Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Add full typescript support #789

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/emoji-mart-react/react.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// @ts-nocheck
import React, { useEffect, useRef } from 'react'
import { Picker } from 'emoji-mart'
import { Picker, PickerProps } from 'emoji-mart'

export default function EmojiPicker(props) {
export default function EmojiPicker(props: PickerProps) {
const ref = useRef(null)
const instance = useRef(null)

Expand Down
6 changes: 3 additions & 3 deletions packages/emoji-mart/src/components/Emoji/EmojiProps.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import PickerProps from '../Picker/PickerProps'
import { defaultPickerProps } from '../Picker/PickerProps'

export default {
fallback: '',
Expand All @@ -18,6 +18,6 @@ export default {
},

// Shared
set: PickerProps.set,
skin: PickerProps.skin,
set: defaultPickerProps.set,
skin: defaultPickerProps.skin,
}
22 changes: 17 additions & 5 deletions packages/emoji-mart/src/components/Picker/Picker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,24 @@ import Icons from '../../icons'
import { Emoji } from '../Emoji'
import { Navigation } from '../Navigation'
import { PureInlineComponent } from '../HOCs'
import { PickerProps, PickerTheme } from './PickerProps'

const Performance = {
rowsPerRender: 10,
}

export default class Picker extends Component {
type EmojiGrid = EmojiRow[]

type EmojiRow = EmojiDataItem[] & {
__categoryId: string
__index: number
}

interface PickerState {
searchResults: EmojiGrid
}

export default class Picker extends Component<PickerProps, PickerState> {
constructor(props) {
super()

Expand Down Expand Up @@ -194,7 +206,7 @@ export default class Picker extends Component {
}
}

initTheme(theme) {
initTheme(theme: PickerTheme) {
if (theme != 'auto') return theme

if (!this.darkMedia) {
Expand All @@ -210,7 +222,7 @@ export default class Picker extends Component {
return this.darkMedia.matches ? 'dark' : 'light'
}

handleClickOutside = (e) => {
handleClickOutside = (e: MouseEvent) => {
const { element } = this.props

if (e.target != element) {
Expand Down Expand Up @@ -383,9 +395,9 @@ export default class Picker extends Component {
}

const pos = input.selectionStart == input.value.length ? [0, 0] : [-1, -1]
const grid = []
const grid: EmojiGrid = []
grid.setsize = searchResults.length
let row = null
let row: EmojiRow = null

for (let emoji of searchResults) {
if (!grid.length || row.length == this.getPerLine()) {
Expand Down
8 changes: 4 additions & 4 deletions packages/emoji-mart/src/components/Picker/PickerElement.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@ import { render } from 'preact'
import { init, getProps } from '../../config'
import { ShadowElement } from '../HTMLElement'
import { Picker, PickerStyles } from '.'
import PickerProps from './PickerProps'
import { defaultPickerProps, PickerProps } from './PickerProps'

export default class PickerElement extends ShadowElement {
static Props = PickerProps
static Props = defaultPickerProps

constructor(props) {
constructor(props: PickerProps) {
super(props, { styles: PickerStyles })
}

async connectedCallback() {
const props = getProps(this.props, PickerProps, this)
const props: PickerProps = getProps(this.props, defaultPickerProps, this)
props.element = this
props.ref = (component) => {
this.component = component
Expand Down
172 changes: 171 additions & 1 deletion packages/emoji-mart/src/components/Picker/PickerProps.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,174 @@
export default {
export type PickerCategory =
| 'frequent'
| 'people'
| 'nature'
| 'foods'
| 'activity'
| 'places'
| 'objects'
| 'symbols'
| 'flags'

export type PickerTheme = 'auto' | 'light' | 'dark'

export interface PickerProps {
/**
* Data to use for the picker
*/
data?: any

/**
* Localization data to use for the picker
*/
i18n?: any

/**
* Categories to show in the picker. Order is respected.
*/
categories?: PickerCategory[]

/**
* Custom emojis
*/
custom?: any[]

/**
* Callback when an emoji is selected
*/
onEmojiSelect?: (emojiData, e: MouseEvent) => void

/**
* Callback when a click outside of the picker happens
*/
onClickOutside?: (e: MouseEvent) => void

/**
* 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.
*/
onAddCustomEmoji?: (e: MouseEvent) => void

/**
* Whether the picker should automatically focus on the search input
*/
autoFocus?: boolean

/**
* Custom category icons
*/
categoryIcons?: any

/**
* Whether the picker should calculate perLine dynamically based on the width of <em-emoji-picker>. When enabled, perLine is ignored
*/
dynamicWidth?: boolean

/**
* An array of color that affects the hover background color
*/
emojiButtonColors?: string[]

/**
* The radius of the emoji buttons
*/
emojiButtonRadius?: string

/**
* The size of the emoji buttons
*/
emojiButtonSize?: number

/**
* The size of the emojis (inside the buttons)
*/
emojiSize?: number

/**
* The version of the emoji data to use. Latest version supported in @emoji-mart/data is currently 14
*/
emojiVersion?: string

/**
* List of emoji IDs that will be excluded from the picker
*/
exceptEmojis?: string[]

/**
* The type of icons to use for the picker. outline with light theme and solid with dark theme.
*/
icons?: 'auto' | 'outline' | 'solid'

/**
* The locale to use for the picker
*/
locale?: string

/**
* The maximum number of frequent rows to show. 0 will disable frequent category
*/
maxFrequentRows?: number

/**
* The position of the navigation bar
*/
navPosition?: 'top' | 'bottom' | 'none'

/**
* Whether to show country flags or not. If not provided, tbhis is handled automatically (Windows doesn’t support country flags)
*/
noCountryFlags?: boolean

/**
* The id of the emoji to use for the no results emoji
*/
noResultsEmoji?: string

/**
* The number of emojis to show per line
*/
perLine?: number

/**
* The id of the emoji to use for the preview when not hovering any emoji. point_up when preview position is bottom and point_down when preview position is top.
*/
previewEmoji?: string

/**
* The position of the preview
*/
previewPosition?: 'top' | 'bottom' | 'none'

/**
* The position of the search input
*/
searchPosition?: 'sticky' | 'static' | 'none'

/**
* The set of emojis to use for the picker. native being the most performant, others rely on spritesheets.
*/
set?: 'native' | 'apple' | 'facebook' | 'google' | 'twitter'

/**
* The emojis skin tone
*/
skin?: 1 | 2 | 3 | 4 | 5 | 6

/**
* The position of the skin tone selector
*/
skinTonePosition?: 'preview' | 'search' | 'none'

/**
* The color theme of the picker
*/
theme?: PickerTheme

/**
* A function that returns the URL of the spritesheet to use for the picker. It should be compatible with the data provided.
*/
getSpritesheetURL?: (set: string) => string
}

export const defaultPickerProps = {
autoFocus: {
value: false,
},
Expand Down
25 changes: 16 additions & 9 deletions packages/emoji-mart/src/config.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
// @ts-nocheck
import i18n_en from '@emoji-mart/data/i18n/en.json'
import PickerProps from './components/Picker/PickerProps'
import { defaultPickerProps } from './components/Picker/PickerProps'
import {
FrequentlyUsed,
NativeSupport,
SafeFlags,
SearchIndex,
} from './helpers'
import type { EmojiData } from './types'

export let I18n = null
export let Data = null
export let Data: EmojiData | null = null

const fetchCache = {}
async function fetchJSON(src) {
Expand All @@ -29,7 +30,13 @@ let initiated = false
let initCallback = null
let initialized = false

export function init(options, { caller } = {}) {
interface InitOptions {
emojiVersion?: number
set?: string
locale?: string
}

export function init(options: InitOptions, { caller } = {}): Promise<void> {
promise ||
(promise = new Promise((resolve) => {
initCallback = resolve
Expand All @@ -46,13 +53,13 @@ export function init(options, { caller } = {}) {
return promise
}

async function _init(props) {
async function _init(props: InitOptions) {
initialized = true

let { emojiVersion, set, locale } = props
emojiVersion || (emojiVersion = PickerProps.emojiVersion.value)
set || (set = PickerProps.set.value)
locale || (locale = PickerProps.locale.value)
emojiVersion || (emojiVersion = defaultPickerProps.emojiVersion.value)
set || (set = defaultPickerProps.set.value)
locale || (locale = defaultPickerProps.locale.value)

if (!Data) {
Data =
Expand Down Expand Up @@ -150,8 +157,8 @@ async function _init(props) {
maxFrequentRows =
maxFrequentRows >= 0
? maxFrequentRows
: PickerProps.maxFrequentRows.value
perLine || (perLine = PickerProps.perLine.value)
: defaultPickerProps.maxFrequentRows.value
perLine || (perLine = defaultPickerProps.perLine.value)

category.emojis = FrequentlyUsed.get({ maxFrequentRows, perLine })
}
Expand Down
11 changes: 8 additions & 3 deletions packages/emoji-mart/src/helpers/search-index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
// @ts-nocheck
import { init, Data } from '../config'
import type { EmojiDataItem } from '../types'

const SHORTCODES_REGEX = /^(?:\:([^\:]+)\:)(?:\:skin-tone-(\d)\:)?$/
let Pool = null
let Pool: EmojiDataItem[] = null

function get(emojiId) {
if (emojiId.id) {
Expand All @@ -20,7 +21,10 @@ function reset() {
Pool = null
}

async function search(value, { maxResults, caller } = {}) {
async function search(
value: string,
{ maxResults, caller }: { maxResults: number; caller: string } = {},
): Promise<EmojiDataItem[]> {
if (!value || !value.trim().length) return null
maxResults || (maxResults = 90)

Expand All @@ -37,7 +41,8 @@ async function search(value, { maxResults, caller } = {}) {
if (!values.length) return

let pool = Pool || (Pool = Object.values(Data.emojis))
let results, scores
let results: EmojiDataItem[]
let scores: Record<string, number>

for (const value of values) {
if (!pool.length) break
Expand Down
3 changes: 3 additions & 0 deletions packages/emoji-mart/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
export { PickerElement as Picker } from './components/Picker'
export { EmojiElement as Emoji } from './components/Emoji'
export type { PickerProps } from './components/Picker/PickerProps'

export { FrequentlyUsed, SafeFlags, SearchIndex, Store } from './helpers'

export { init, Data, I18n } from './config'

export { getEmojiDataFromNative } from './utils'

export * from './types'
Loading