Skip to content

Commit

Permalink
Add dynamicWidth props to Picker
Browse files Browse the repository at this point in the history
  • Loading branch information
EtienneLem committed Nov 27, 2022
1 parent 07c0380 commit 03960bd
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 10 deletions.
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -95,6 +95,7 @@ function App() {
| **onAddCustomEmoji** | `null` | | Callback when the *Add custom emoji* button is clicked. The button will only be displayed if this callback is provided. It is displayed when search returns no results. |
| **autoFocus** | `false` | | Whether the picker should automatically focus on the search input |
| **categoryIcons** | `{}` | | [Custom category icons](#custom-category-icons) |
| **dynamicWidth** | `false` | | Whether the picker should calculate `perLine` dynamically based on the width of `<em-emoji-picker>`. When enabled, `perLine` is ignored |
| **emojiButtonColors** | `[]` | i.e. `#f00`, `pink`, `rgba(155,223,88,.7)` | An array of color that affects the hover background color |
| **emojiButtonRadius** | `100%` | i.e. `6px`, `1em`, `100%` | The radius of the emoji buttons |
| **emojiButtonSize** | `36` | | The size of the emoji buttons |
Expand Down
74 changes: 64 additions & 10 deletions packages/emoji-mart/src/components/Picker/Picker.tsx
Expand Up @@ -18,8 +18,11 @@ export default class Picker extends Component {
constructor(props) {
super()

this.observers = []

this.state = {
pos: [-1, -1],
perLine: this.initDynamicPerLine(props),
visibleRows: { 0: true },
...this.getInitialState(props),
}
Expand All @@ -33,7 +36,6 @@ export default class Picker extends Component {
}

componentWillMount() {
this.observers = []
this.dir = I18n.rtl ? 'rtl' : 'ltr'
this.refs = {
menu: createRef(),
Expand Down Expand Up @@ -133,10 +135,17 @@ export default class Picker extends Component {
this.observeRows()
}

unobserve() {
unobserve({ except = [] } = {}) {
if (!Array.isArray(except)) {
except = [except]
}

for (const observer of this.observers) {
if (except.includes(observer)) continue
observer.disconnect()
}

this.observers = [].concat(except)
}

initGrid() {
Expand Down Expand Up @@ -173,7 +182,7 @@ export default class Picker extends Component {
let row = addRow(rows, category)

for (let emoji of category.emojis) {
if (row.length == this.props.perLine) {
if (row.length == this.getPerLine()) {
row = addRow(rows, category)
}

Expand Down Expand Up @@ -235,6 +244,36 @@ export default class Picker extends Component {
}
}

initDynamicPerLine(props = this.props) {
if (!props.dynamicWidth) return
const { element, emojiButtonSize } = props

const calculatePerLine = () => {
const { width } = element.getBoundingClientRect()
return Math.floor(width / emojiButtonSize)
}

const observer = new ResizeObserver(() => {
this.unobserve({ except: observer })
this.setState({ perLine: calculatePerLine() }, () => {
this.initGrid()
this.forceUpdate(() => {
this.observeCategories()
this.observeRows()
})
})
})

observer.observe(element)
this.observers.push(observer)

return calculatePerLine()
}

getPerLine() {
return this.state.perLine || this.props.perLine
}

getEmojiByPos([p1, p2]) {
const grid = this.state.searchResults || this.grid
const emoji = grid[p1] && grid[p1][p2]
Expand Down Expand Up @@ -349,7 +388,7 @@ export default class Picker extends Component {
let row = null

for (let emoji of searchResults) {
if (!grid.length || row.length == this.props.perLine) {
if (!grid.length || row.length == this.getPerLine()) {
row = []
row.__categoryId = 'search'
row.__index = grid.length
Expand Down Expand Up @@ -852,6 +891,7 @@ export default class Picker extends Component {
renderCategories() {
const { categories } = Data
const hidden = !!this.state.searchResults
const perLine = this.getPerLine()

return (
<div
Expand Down Expand Up @@ -889,10 +929,14 @@ export default class Picker extends Component {
return null
}

const start = i * this.props.perLine
const end = start + this.props.perLine
const start = i * perLine
const end = start + perLine
const emojiIds = category.emojis.slice(start, end)

if (emojiIds.length < perLine) {
emojiIds.push(...new Array(perLine - emojiIds.length))
}

return (
<div
key={row.index}
Expand All @@ -903,6 +947,17 @@ export default class Picker extends Component {
>
{visible &&
emojiIds.map((emojiId, ii) => {
if (!emojiId) {
return (
<div
style={{
width: this.props.emojiButtonSize,
height: this.props.emojiButtonSize,
}}
></div>
)
}

const emoji = SearchIndex.get(emojiId)

return this.renderEmojiButton(emoji, {
Expand Down Expand Up @@ -1048,9 +1103,6 @@ export default class Picker extends Component {
<section
id="root"
class="flex flex-column"
style={{
width: this.props.perLine * this.props.emojiButtonSize + (12 + 16),
}}
data-emoji-set={this.props.set}
data-theme={this.state.theme}
data-menu={this.state.showSkins ? '' : undefined}
Expand All @@ -1064,7 +1116,9 @@ export default class Picker extends Component {
<div ref={this.refs.scroll} class="scroll flex-grow padding-lr">
<div
style={{
width: this.props.perLine * this.props.emojiButtonSize,
width: this.props.dynamicWidth
? '100%'
: this.props.perLine * this.props.emojiButtonSize,
height: '100%',
}}
>
Expand Down
3 changes: 3 additions & 0 deletions packages/emoji-mart/src/components/Picker/PickerProps.ts
Expand Up @@ -2,6 +2,9 @@ export default {
autoFocus: {
value: false,
},
dynamicWidth: {
value: false,
},
emojiButtonColors: {
value: null,
},
Expand Down
4 changes: 4 additions & 0 deletions packages/emoji-mart/src/components/Picker/PickerStyles.scss
Expand Up @@ -451,6 +451,10 @@ button {
.skin-tone-5 { background-color: #a46134 }
.skin-tone-6 { background-color: #5d4437 }

[data-index] {
justify-content: space-between;
}

[data-emoji-set="twitter"] {
.skin-tone:after {
border-color: rgba(0,0,0, .5);
Expand Down

0 comments on commit 03960bd

Please sign in to comment.