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 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`). To enable search in additional languages, you need to bundle the corresponding locale files.
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 config plugin copies only the selected locale files into your native bundles at prebuild time.
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 (without Expo config plugins)
184
+ ### Bare React Native
122
185
 
123
- Manually copy the locale files you need from the package's `translations/` directory into your native projects:
186
+ **Android** requires no setup -- the module's Gradle build automatically copies all translation files at build time.
124
187
 
125
- **iOS:** Copy the desired `.json` files into your Xcode project, placing them alongside the module's `emojis.json`. The native code loads all `.json` files found in the `translations/` bundle directory.
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
- ```bash
128
- # From your project root
129
- cp node_modules/expo-native-sheet-emojis/translations/es.json ios/translations/
130
- cp node_modules/expo-native-sheet-emojis/translations/fr.json ios/translations/
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
- Make sure the `translations/` folder is added to your Xcode project as a folder reference and included in the "Copy Bundle Resources" build phase.
134
-
135
- **Android:** Copy the files into your app's assets:
136
-
137
- ```bash
138
- mkdir -p android/app/src/main/assets/translations
139
- cp node_modules/expo-native-sheet-emojis/translations/es.json android/app/src/main/assets/translations/
140
- cp node_modules/expo-native-sheet-emojis/translations/fr.json android/app/src/main/assets/translations/
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
- Each locale file adds roughly 60-190KB to your app bundle depending on the language.
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
 
@@ -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/user/expo-native-sheet-emojis'
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
- // Try translations directory (per-locale files from config plugin)
331
- if let translationsURL = bundle.url(forResource: "translations", withExtension: nil) ??
332
- bundle.urls(forResourcesWithExtension: "json", subdirectory: "translations")?.first.map({ $0.deletingLastPathComponent() }) {
333
- // Load all .json files in translations/
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
- if let data = try? Data(contentsOf: url),
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: try flat "all.json" (legacy format)
345
+ // 2. Fallback: check flat bundle root for known locale files
353
346
  if merged.isEmpty {
354
- let url = bundle.url(forResource: "all", withExtension: "json")
355
- ?? bundle.url(forResource: "all", withExtension: "json", subdirectory: "translations")
356
- if let url, let data = try? Data(contentsOf: url),
357
- let dict = try? JSONSerialization.jsonObject(with: data) as? [String: [String]] {
358
- return dict
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.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": [