expo-native-sheet-emojis 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/README.md +95 -18
- package/android/build.gradle +8 -0
- package/android/src/main/assets/translations/.gitkeep +0 -0
- package/ios/EmojiSheetModule.podspec +1 -1
- package/ios/EmojiSheetUIView.swift +29 -21
- package/ios/translations/.gitkeep +0 -0
- package/package.json +5 -2
- package/android/src/main/assets/translations/de.json +0 -1
- package/android/src/main/assets/translations/el.json +0 -1
- package/android/src/main/assets/translations/es.json +0 -1
- package/android/src/main/assets/translations/fr.json +0 -1
- package/ios/translations/de.json +0 -1
- package/ios/translations/el.json +0 -1
- package/ios/translations/es.json +0 -1
- package/ios/translations/fr.json +0 -1
package/README.md
CHANGED
|
@@ -100,9 +100,72 @@ await EmojiSheetModule.present({
|
|
|
100
100
|
});
|
|
101
101
|
```
|
|
102
102
|
|
|
103
|
+
## Custom Hook Pattern
|
|
104
|
+
|
|
105
|
+
For apps that use the emoji picker in multiple places, extract a reusable hook to centralize theme, translations, and configuration:
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
import { EmojiSheetModule } from 'expo-native-sheet-emojis';
|
|
109
|
+
import type { EmojiSheetPresentOptions, EmojiSheetResult } from 'expo-native-sheet-emojis';
|
|
110
|
+
|
|
111
|
+
export function useEmojiPicker() {
|
|
112
|
+
// Pull your theme colors and i18n strings from your app's providers
|
|
113
|
+
const theme = useAppTheme();
|
|
114
|
+
const { t } = useTranslation();
|
|
115
|
+
|
|
116
|
+
const present = async (
|
|
117
|
+
overrides?: Partial<EmojiSheetPresentOptions>
|
|
118
|
+
): Promise<EmojiSheetResult> => {
|
|
119
|
+
return EmojiSheetModule.present({
|
|
120
|
+
theme: {
|
|
121
|
+
accentColor: theme.colors.primary,
|
|
122
|
+
backgroundColor: theme.colors.background,
|
|
123
|
+
searchBarBackgroundColor: theme.colors.surface,
|
|
124
|
+
textColor: theme.colors.text,
|
|
125
|
+
textSecondaryColor: theme.colors.textSecondary,
|
|
126
|
+
dividerColor: theme.colors.border,
|
|
127
|
+
},
|
|
128
|
+
translations: {
|
|
129
|
+
searchPlaceholder: t('Search emoji'),
|
|
130
|
+
noResultsText: t('No emojis found'),
|
|
131
|
+
categoryNames: {
|
|
132
|
+
frequently_used: t('Frequently Used'),
|
|
133
|
+
smileys_emotion: t('Smileys & Emotion'),
|
|
134
|
+
people_body: t('People & Body'),
|
|
135
|
+
animals_nature: t('Animals & Nature'),
|
|
136
|
+
food_drink: t('Food & Drink'),
|
|
137
|
+
travel_places: t('Travel & Places'),
|
|
138
|
+
activities: t('Activities'),
|
|
139
|
+
objects: t('Objects'),
|
|
140
|
+
symbols: t('Symbols'),
|
|
141
|
+
flags: t('Flags'),
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
excludeEmojis: ['pile_of_poo'],
|
|
145
|
+
...overrides,
|
|
146
|
+
});
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
return { present };
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Then use it anywhere with a single line:
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
const emojiPicker = useEmojiPicker();
|
|
157
|
+
|
|
158
|
+
const result = await emojiPicker.present();
|
|
159
|
+
if (!result.cancelled) {
|
|
160
|
+
console.log(result.emoji);
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
103
164
|
## Multilingual Search
|
|
104
165
|
|
|
105
|
-
English search keywords are always included (built into `emojis.json`).
|
|
166
|
+
English search keywords are always included (built into `emojis.json`). No additional setup is needed for English-only apps.
|
|
167
|
+
|
|
168
|
+
To enable search in additional languages, use the Expo config plugin to select which locale files to bundle. **Nothing is bundled by default** -- you opt in to the locales you need.
|
|
106
169
|
|
|
107
170
|
### Expo (managed or prebuild)
|
|
108
171
|
|
|
@@ -116,35 +179,49 @@ Configure the plugin in your `app.json` or `app.config.js`:
|
|
|
116
179
|
}
|
|
117
180
|
```
|
|
118
181
|
|
|
119
|
-
The
|
|
182
|
+
Then run `npx expo prebuild --clean`. The plugin copies only the selected locale files into your native bundles.
|
|
120
183
|
|
|
121
|
-
### Bare React Native
|
|
184
|
+
### Bare React Native
|
|
122
185
|
|
|
123
|
-
|
|
186
|
+
**Android** requires no setup -- the module's Gradle build automatically copies all translation files at build time.
|
|
124
187
|
|
|
125
|
-
**iOS
|
|
188
|
+
**iOS** requires a `pre_install` hook in your `Podfile`. This copies locale files into the module's bundle during `pod install`:
|
|
126
189
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
190
|
+
**All locales:**
|
|
191
|
+
```ruby
|
|
192
|
+
pre_install do |installer|
|
|
193
|
+
emoji_sheet_pod = File.join(__dir__, '..', 'node_modules', 'expo-native-sheet-emojis')
|
|
194
|
+
source = File.join(emoji_sheet_pod, 'translations')
|
|
195
|
+
target = File.join(emoji_sheet_pod, 'ios', 'translations')
|
|
196
|
+
if File.directory?(source)
|
|
197
|
+
FileUtils.mkdir_p(target)
|
|
198
|
+
FileUtils.cp(Dir.glob(File.join(source, '*.json')), target)
|
|
199
|
+
end
|
|
200
|
+
end
|
|
131
201
|
```
|
|
132
202
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
203
|
+
**Selected locales only:**
|
|
204
|
+
```ruby
|
|
205
|
+
pre_install do |installer|
|
|
206
|
+
emoji_locales = ['es', 'fr', 'de', 'ja']
|
|
207
|
+
emoji_sheet_pod = File.join(__dir__, '..', 'node_modules', 'expo-native-sheet-emojis')
|
|
208
|
+
source = File.join(emoji_sheet_pod, 'translations')
|
|
209
|
+
target = File.join(emoji_sheet_pod, 'ios', 'translations')
|
|
210
|
+
if File.directory?(source)
|
|
211
|
+
FileUtils.mkdir_p(target)
|
|
212
|
+
files = emoji_locales.map { |l| File.join(source, "#{l}.json") }.select { |f| File.exist?(f) }
|
|
213
|
+
FileUtils.cp(files, target)
|
|
214
|
+
end
|
|
215
|
+
end
|
|
141
216
|
```
|
|
142
217
|
|
|
218
|
+
If you already have a `pre_install` block, add the emoji translation snippet inside it. Run `pod install` after updating.
|
|
219
|
+
|
|
143
220
|
### Supported Locales
|
|
144
221
|
|
|
145
222
|
`ca`, `cs`, `de`, `el`, `en`, `es`, `fi`, `fr`, `hi`, `hu`, `it`, `ja`, `ko`, `nl`, `pl`, `pt`, `ru`, `sv`, `tr`, `uk`, `zh`
|
|
146
223
|
|
|
147
|
-
|
|
224
|
+
**Bundle size impact:** The base emoji data (`emojis.json`) adds ~300KB to your app. Each locale file adds 64-185KB depending on the language (all 21 locales total ~2.3MB). Only bundle the locales your app actually needs.
|
|
148
225
|
|
|
149
226
|
### Custom Translations
|
|
150
227
|
|
package/android/build.gradle
CHANGED
|
@@ -29,6 +29,14 @@ android {
|
|
|
29
29
|
versionName "1.0.0"
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
// Copy translation files from package root into module assets at build time.
|
|
33
|
+
// This means Android consumers get all translations automatically — no manual setup.
|
|
34
|
+
task copyTranslations(type: Copy) {
|
|
35
|
+
from "${projectDir}/../translations"
|
|
36
|
+
into "${projectDir}/src/main/assets/translations"
|
|
37
|
+
}
|
|
38
|
+
preBuild.dependsOn copyTranslations
|
|
39
|
+
|
|
32
40
|
lintOptions {
|
|
33
41
|
abortOnError false
|
|
34
42
|
}
|
|
File without changes
|
|
@@ -4,7 +4,7 @@ Pod::Spec.new do |s|
|
|
|
4
4
|
s.summary = 'Native emoji picker bottom sheet for React Native'
|
|
5
5
|
s.description = 'A fully native iOS/Android emoji picker presented in a bottom sheet with search, skin tones, and theming support.'
|
|
6
6
|
s.author = ''
|
|
7
|
-
s.homepage = 'https://github.com/
|
|
7
|
+
s.homepage = 'https://github.com/efstathiosntonas/expo-native-sheet-emojis'
|
|
8
8
|
s.license = { type: 'MIT' }
|
|
9
9
|
s.platforms = { ios: '15.1' }
|
|
10
10
|
s.source = { git: '' }
|
|
@@ -327,41 +327,49 @@ class EmojiSheetUIView: UIView,
|
|
|
327
327
|
let bundle = Bundle(for: EmojiSheetUIView.self)
|
|
328
328
|
var merged: [String: [String]] = [:]
|
|
329
329
|
|
|
330
|
-
//
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
330
|
+
// Translation files are copied into ios/translations/ by the config plugin.
|
|
331
|
+
// The podspec bundles translations/*.json into the module's resource bundle.
|
|
332
|
+
// CocoaPods may copy them flat (root level) or preserve the subdirectory.
|
|
333
|
+
// We check both locations.
|
|
334
|
+
|
|
335
|
+
// 1. Check translations/ subdirectory
|
|
336
|
+
if let translationsURL = bundle.url(forResource: "translations", withExtension: nil) {
|
|
334
337
|
if let urls = try? FileManager.default.contentsOfDirectory(at: translationsURL, includingPropertiesForKeys: nil)
|
|
335
338
|
.filter({ $0.pathExtension == "json" }) {
|
|
336
339
|
for url in urls {
|
|
337
|
-
|
|
338
|
-
let dict = try? JSONSerialization.jsonObject(with: data) as? [String: [String]] {
|
|
339
|
-
for (key, value) in dict {
|
|
340
|
-
if var existing = merged[key] {
|
|
341
|
-
existing.append(contentsOf: value)
|
|
342
|
-
merged[key] = existing
|
|
343
|
-
} else {
|
|
344
|
-
merged[key] = value
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
}
|
|
340
|
+
Self.mergeKeywords(from: url, into: &merged)
|
|
348
341
|
}
|
|
349
342
|
}
|
|
350
343
|
}
|
|
351
344
|
|
|
352
|
-
// Fallback:
|
|
345
|
+
// 2. Fallback: check flat bundle root for known locale files
|
|
353
346
|
if merged.isEmpty {
|
|
354
|
-
let
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
347
|
+
let locales = ["ca", "cs", "de", "el", "en", "es", "fi", "fr", "hi", "hu",
|
|
348
|
+
"it", "ja", "ko", "nl", "pl", "pt", "ru", "sv", "tr", "uk", "zh"]
|
|
349
|
+
for locale in locales {
|
|
350
|
+
if let url = bundle.url(forResource: locale, withExtension: "json") {
|
|
351
|
+
Self.mergeKeywords(from: url, into: &merged)
|
|
352
|
+
}
|
|
359
353
|
}
|
|
360
354
|
}
|
|
361
355
|
|
|
362
356
|
return merged
|
|
363
357
|
}
|
|
364
358
|
|
|
359
|
+
private static func mergeKeywords(from url: URL, into merged: inout [String: [String]]) {
|
|
360
|
+
guard let data = try? Data(contentsOf: url),
|
|
361
|
+
let dict = try? JSONSerialization.jsonObject(with: data) as? [String: [String]]
|
|
362
|
+
else { return }
|
|
363
|
+
for (key, value) in dict {
|
|
364
|
+
if var existing = merged[key] {
|
|
365
|
+
existing.append(contentsOf: value)
|
|
366
|
+
merged[key] = existing
|
|
367
|
+
} else {
|
|
368
|
+
merged[key] = value
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
365
373
|
func loadDataAsync() {
|
|
366
374
|
let cached = Self.cacheQueue.sync { (Self.cachedSections, Self.cachedKeywords) }
|
|
367
375
|
if let sections = cached.0, let keywords = cached.1 {
|
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-native-sheet-emojis",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "A fully native emoji picker bottom sheet for React Native. Built with Swift and Kotlin for maximum performance. Features search with multilingual keywords, skin tones, frequently used tracking, theming, and configurable layout.",
|
|
5
5
|
"main": "lib/commonjs/index.js",
|
|
6
6
|
"module": "lib/module/index.js",
|
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
"typecheck": "tsc --noEmit",
|
|
17
17
|
"prepare": "lefthook install && bob build && tsc --project plugin/tsconfig.json",
|
|
18
18
|
"prepublishOnly": "bob build && tsc --project plugin/tsconfig.json",
|
|
19
|
-
"build:plugin": "tsc --project plugin/tsconfig.json"
|
|
19
|
+
"build:plugin": "tsc --project plugin/tsconfig.json",
|
|
20
|
+
"release": "release-it"
|
|
20
21
|
},
|
|
21
22
|
"keywords": [
|
|
22
23
|
"expo",
|
|
@@ -46,6 +47,7 @@
|
|
|
46
47
|
"react-native": ">=0.81.0"
|
|
47
48
|
},
|
|
48
49
|
"devDependencies": {
|
|
50
|
+
"@release-it/conventional-changelog": "^10.0.6",
|
|
49
51
|
"@types/react": "~19.2.14",
|
|
50
52
|
"del-cli": "6.0.0",
|
|
51
53
|
"eslint": "9.0.0",
|
|
@@ -57,6 +59,7 @@
|
|
|
57
59
|
"react": "19.2.4",
|
|
58
60
|
"react-native": "0.83.3",
|
|
59
61
|
"react-native-builder-bob": "0.40.0",
|
|
62
|
+
"release-it": "^19.2.4",
|
|
60
63
|
"typescript": "~5.9.3"
|
|
61
64
|
},
|
|
62
65
|
"files": [
|