@portabletext/plugin-emoji-picker 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@portabletext/plugin-emoji-picker",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Easily configure an Emoji Picker for the Portable Text Editor",
5
5
  "keywords": [
6
6
  "portabletext",
@@ -56,9 +56,9 @@
56
56
  "typescript": "5.9.3",
57
57
  "typescript-eslint": "^8.46.1",
58
58
  "vitest": "^3.2.4",
59
- "@portabletext/editor": "2.15.5",
59
+ "racejar": "1.3.2",
60
60
  "@portabletext/schema": "1.2.0",
61
- "racejar": "1.3.2"
61
+ "@portabletext/editor": "2.15.5"
62
62
  },
63
63
  "peerDependencies": {
64
64
  "@portabletext/editor": "^2.15.5",
@@ -0,0 +1,113 @@
1
+ import {emojis} from './emojis'
2
+ import type {MatchEmojis} from './match-emojis'
3
+
4
+ /**
5
+ * Proposed, but not required type, to represent an emoji match.
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * {
10
+ * type: 'exact',
11
+ * key: '😂-joy',
12
+ * emoji: '😂',
13
+ * keyword: 'joy',
14
+ * }
15
+ * ```
16
+ * @example
17
+ * ```tsx
18
+ * {
19
+ * type: 'partial',
20
+ * key: '😹-joy-_cat',
21
+ * emoji: '😹',
22
+ * keyword: 'joy',
23
+ * startSlice: '',
24
+ * endSlice: '_cat',
25
+ * }
26
+ * ```
27
+ *
28
+ * @beta
29
+ */
30
+ export type EmojiMatch =
31
+ | {
32
+ type: 'exact'
33
+ key: string
34
+ emoji: string
35
+ keyword: string
36
+ }
37
+ | {
38
+ type: 'partial'
39
+ key: string
40
+ emoji: string
41
+ keyword: string
42
+ startSlice: string
43
+ endSlice: string
44
+ }
45
+
46
+ /**
47
+ * Proposed, but not required, default implementation of `MatchEmojis`.
48
+ *
49
+ * @beta
50
+ */
51
+ export const matchEmojis = createMatchEmojis({emojis})
52
+
53
+ /**
54
+ * Proposed, but not required, function to create a `MatchEmojis` function.
55
+ *
56
+ * @example
57
+ * ```ts
58
+ * const matchEmojis = createMatchEmojis({
59
+ * emojis: {
60
+ * '😂': ['joy'],
61
+ * '😹': ['joy_cat'],
62
+ * },
63
+ * })
64
+ * ```
65
+ *
66
+ * @beta
67
+ */
68
+ export function createMatchEmojis(config: {
69
+ emojis: Record<string, ReadonlyArray<string>>
70
+ }): MatchEmojis<EmojiMatch> {
71
+ return ({keyword}: {keyword: string}) => {
72
+ const foundEmojis: Array<EmojiMatch> = []
73
+
74
+ if (keyword.length < 1) {
75
+ return foundEmojis
76
+ }
77
+
78
+ for (const emoji in config.emojis) {
79
+ const emojiKeywords = config.emojis[emoji] ?? []
80
+
81
+ for (const emojiKeyword of emojiKeywords) {
82
+ const keywordIndex = emojiKeyword.indexOf(keyword)
83
+
84
+ if (keywordIndex === -1) {
85
+ continue
86
+ }
87
+
88
+ if (emojiKeyword === keyword) {
89
+ foundEmojis.push({
90
+ type: 'exact',
91
+ key: `${emoji}-${keyword}`,
92
+ emoji,
93
+ keyword,
94
+ })
95
+ } else {
96
+ const start = emojiKeyword.slice(0, keywordIndex)
97
+ const end = emojiKeyword.slice(keywordIndex + keyword.length)
98
+
99
+ foundEmojis.push({
100
+ type: 'partial',
101
+ key: `${emoji}-${start}${keyword}${end}`,
102
+ emoji,
103
+ keyword,
104
+ startSlice: start,
105
+ endSlice: end,
106
+ })
107
+ }
108
+ }
109
+ }
110
+
111
+ return foundEmojis
112
+ }
113
+ }
@@ -28,7 +28,7 @@ import {
28
28
  type AnyEventObject,
29
29
  type CallbackLogicFunction,
30
30
  } from 'xstate'
31
- import type {EmojiMatch, MatchEmojis} from './match-emojis'
31
+ import type {BaseEmojiMatch, MatchEmojis} from './match-emojis'
32
32
 
33
33
  /*******************
34
34
  * Keyboard shortcuts
@@ -175,10 +175,10 @@ function createKeywordFoundEvent(payload: {
175
175
  } as const
176
176
  }
177
177
 
178
- type EmojiPickerContext<TEmojiMatch = EmojiMatch> = {
178
+ type EmojiPickerContext = {
179
179
  editor: Editor
180
- matches: ReadonlyArray<TEmojiMatch>
181
- matchEmojis: MatchEmojis<TEmojiMatch>
180
+ matches: ReadonlyArray<BaseEmojiMatch>
181
+ matchEmojis: MatchEmojis<BaseEmojiMatch>
182
182
  selectedIndex: number
183
183
  keywordAnchor:
184
184
  | {
@@ -9,8 +9,8 @@ import {page, type Locator} from '@vitest/browser/context'
9
9
  import {Before, Then} from 'racejar'
10
10
  import {Feature} from 'racejar/vitest'
11
11
  import {expect, vi} from 'vitest'
12
+ import {createMatchEmojis} from './create-match-emojis'
12
13
  import emojiPickerFeature from './emoji-picker.feature?raw'
13
- import {createMatchEmojis} from './match-emojis'
14
14
  import {useEmojiPicker} from './use-emoji-picker'
15
15
 
16
16
  type EmojiPickerTestContext = Context & {
package/src/emojis.ts CHANGED
@@ -1,6 +1,3 @@
1
- /**
2
- * @beta
3
- */
4
1
  export const emojis: Record<string, Array<string>> = {
5
2
  '😀': [
6
3
  'grinning_face',
package/src/index.ts CHANGED
@@ -1,2 +1,3 @@
1
+ export * from './create-match-emojis'
1
2
  export * from './match-emojis'
2
3
  export * from './use-emoji-picker'
@@ -1,45 +1,16 @@
1
- import {emojis} from './emojis'
2
-
3
1
  /**
4
- * Proposed, but not required type, to represent an emoji match.
5
- *
6
- * @example
7
- * ```tsx
8
- * {
9
- * type: 'exact',
10
- * key: '😂-joy',
11
- * emoji: '😂',
12
- * keyword: 'joy',
13
- * }
14
- * ```
15
- * @example
16
- * ```tsx
17
- * {
18
- * type: 'partial',
19
- * key: '😹-joy-_cat',
20
- * emoji: '😹',
21
- * keyword: 'joy',
22
- * startSlice: '',
23
- * endSlice: '_cat',
24
- * }
25
- * ```
2
+ * The base type representing an emoji match.
26
3
  *
27
4
  * @beta
28
5
  */
29
- export type EmojiMatch =
6
+ export type BaseEmojiMatch =
30
7
  | {
31
8
  type: 'exact'
32
- key: string
33
9
  emoji: string
34
- keyword: string
35
10
  }
36
11
  | {
37
12
  type: 'partial'
38
- key: string
39
13
  emoji: string
40
- keyword: string
41
- startSlice: string
42
- endSlice: string
43
14
  }
44
15
 
45
16
  /**
@@ -47,75 +18,5 @@ export type EmojiMatch =
47
18
  *
48
19
  * @beta
49
20
  */
50
- export type MatchEmojis<TEmojiMatch = EmojiMatch> = (query: {
51
- keyword: string
52
- }) => ReadonlyArray<TEmojiMatch>
53
-
54
- /**
55
- * Proposed, but not required, default implementation of `MatchEmojis`.
56
- *
57
- * @beta
58
- */
59
- export const matchEmojis: MatchEmojis = createMatchEmojis({emojis})
60
-
61
- /**
62
- * Proposed, but not required, function to create a `MatchEmojis` function.
63
- *
64
- * @example
65
- * ```ts
66
- * const matchEmojis = createMatchEmojis({
67
- * emojis: {
68
- * '😂': ['joy'],
69
- * '😹': ['joy_cat'],
70
- * },
71
- * })
72
- * ```
73
- *
74
- * @beta
75
- */
76
- export function createMatchEmojis(config: {
77
- emojis: Record<string, ReadonlyArray<string>>
78
- }): MatchEmojis {
79
- return ({keyword}: {keyword: string}) => {
80
- const foundEmojis: Array<EmojiMatch> = []
81
-
82
- if (keyword.length < 1) {
83
- return foundEmojis
84
- }
85
-
86
- for (const emoji in config.emojis) {
87
- const emojiKeywords = config.emojis[emoji] ?? []
88
-
89
- for (const emojiKeyword of emojiKeywords) {
90
- const keywordIndex = emojiKeyword.indexOf(keyword)
91
-
92
- if (keywordIndex === -1) {
93
- continue
94
- }
95
-
96
- if (emojiKeyword === keyword) {
97
- foundEmojis.push({
98
- type: 'exact',
99
- key: `${emoji}-${keyword}`,
100
- emoji,
101
- keyword,
102
- })
103
- } else {
104
- const start = emojiKeyword.slice(0, keywordIndex)
105
- const end = emojiKeyword.slice(keywordIndex + keyword.length)
106
-
107
- foundEmojis.push({
108
- type: 'partial',
109
- key: `${emoji}-${start}${keyword}${end}`,
110
- emoji,
111
- keyword,
112
- startSlice: start,
113
- endSlice: end,
114
- })
115
- }
116
- }
117
- }
118
-
119
- return foundEmojis
120
- }
121
- }
21
+ export type MatchEmojis<TEmojiMatch extends BaseEmojiMatch = BaseEmojiMatch> =
22
+ (query: {keyword: string}) => ReadonlyArray<TEmojiMatch>
@@ -2,12 +2,12 @@ import {useEditor} from '@portabletext/editor'
2
2
  import {useActorRef, useSelector} from '@xstate/react'
3
3
  import {useCallback} from 'react'
4
4
  import {emojiPickerMachine} from './emoji-picker-machine'
5
- import type {EmojiMatch, MatchEmojis} from './match-emojis'
5
+ import type {BaseEmojiMatch, MatchEmojis} from './match-emojis'
6
6
 
7
7
  /**
8
8
  * @beta
9
9
  */
10
- export type EmojiPicker<TEmojiMatch = EmojiMatch> = {
10
+ export type EmojiPicker<TEmojiMatch extends BaseEmojiMatch = BaseEmojiMatch> = {
11
11
  /**
12
12
  * The matched keyword, including colons.
13
13
  *
@@ -105,7 +105,9 @@ export type EmojiPicker<TEmojiMatch = EmojiMatch> = {
105
105
  /**
106
106
  * @beta
107
107
  */
108
- export type EmojiPickerProps<TEmojiMatch = EmojiMatch> = {
108
+ export type EmojiPickerProps<
109
+ TEmojiMatch extends BaseEmojiMatch = BaseEmojiMatch,
110
+ > = {
109
111
  matchEmojis: MatchEmojis<TEmojiMatch>
110
112
  }
111
113
 
@@ -136,12 +138,12 @@ export type EmojiPickerProps<TEmojiMatch = EmojiMatch> = {
136
138
  *
137
139
  * @beta
138
140
  */
139
- export function useEmojiPicker<TEmojiMatch = EmojiMatch>(
140
- props: EmojiPickerProps<TEmojiMatch>,
141
- ): EmojiPicker<TEmojiMatch> {
141
+ export function useEmojiPicker<
142
+ TEmojiMatch extends BaseEmojiMatch = BaseEmojiMatch,
143
+ >(props: EmojiPickerProps<TEmojiMatch>): EmojiPicker<TEmojiMatch> {
142
144
  const editor = useEditor()
143
145
  const emojiPickerActor = useActorRef(emojiPickerMachine, {
144
- input: {editor, matchEmojis: props.matchEmojis as MatchEmojis<EmojiMatch>},
146
+ input: {editor, matchEmojis: props.matchEmojis},
145
147
  })
146
148
  const keyword = useSelector(
147
149
  emojiPickerActor,