UNPKG

react-native-emojis-picker

Version:

A simple emoji picker for React Native and Expo. It's built with TypeScript and uses Reanimated 2 for smooth animations.

383 lines (372 loc) 11.9 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var src_exports = {}; __export(src_exports, { EmojiModal: () => Modal, EmojiProvider: () => Provider }); module.exports = __toCommonJS(src_exports); // src/components/modal/modal.tsx var import_non_secure = require("nanoid/non-secure"); var import_react = require("react"); var import_portal = require("@gorhom/portal"); var import_react_native5 = require("react-native"); var import_expo_blur = require("expo-blur"); // src/components/modal/filterBar.tsx var import_react_native2 = require("react-native"); // src/helper.ts var import_emoji_datasource = __toESM(require("emoji-datasource")); var emojis = import_emoji_datasource.default; var Categories = [ { symbol: "\u{1F600}", key: "Smileys & Emotion" }, { symbol: "\u{1F9D1}", key: "People & Body" }, { symbol: "\u{1F984}", key: "Animals & Nature" }, { symbol: "\u{1F354}", key: "Food & Drink" }, { symbol: "\u26BE\uFE0F", key: "Activities" }, { symbol: "\u2708\uFE0F", key: "Travel & Places" }, { symbol: "\u{1F4A1}", key: "Objects" }, { symbol: "\u{1F523}", key: "Symbols" }, { symbol: "\u{1F1F8}\u{1F1E6}", key: "Flags" } ]; function charFromUtf16(utf16) { return String.fromCodePoint( ...utf16.split("-").map((u) => "0x" + u) ); } function charFromEmojiObject(obj) { return charFromUtf16(obj.unified); } var filteredEmojis = emojis.filter((e2) => !e2["obsoleted_by"]); // src/constants.ts var import_react_native = require("react-native"); var { width: screenWidth, height: screenHeight } = import_react_native.Dimensions.get("window"); // src/components/modal/filterBar.tsx var import_jsx_runtime = require("react/jsx-runtime"); function FilterBar({ onPress, selectedCategory, categories, darkMode }) { const result = Categories.filter( (item) => categories.find((el) => el === item.key) ); const size = Math.floor((screenWidth - 80) / 9); return /* @__PURE__ */ (0, import_jsx_runtime.jsx)( import_react_native2.View, { style: [ styles.wrapper, { borderColor: darkMode ? "#5C5470" : "#f2f2f2" } ], children: result.map((category, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)( import_react_native2.TouchableOpacity, { onPress: () => onPress(category.key), style: { opacity: selectedCategory === category.key ? 1 : 0.3, width: size, height: size }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.icon, children: category.symbol }) }, index )) } ); } var styles = import_react_native2.StyleSheet.create({ wrapper: { flexDirection: "row", alignItems: "center", paddingHorizontal: 20, paddingBottom: 10, borderBottomWidth: 2 }, icon: { fontSize: screenHeight * 0.025 } }); // src/components/modal/search.tsx var import_react_native3 = require("react-native"); var import_jsx_runtime2 = require("react/jsx-runtime"); function Search({ darkMode, ...props }) { return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)( import_react_native3.TextInput, { style: [styles2.search, darkMode && { backgroundColor: "#5C5470" }], placeholderTextColor: "#8E8E93", ...props } ); } var styles2 = import_react_native3.StyleSheet.create({ search: { paddingHorizontal: 10, paddingVertical: 15, marginHorizontal: 20, marginVertical: 10, borderRadius: 10, backgroundColor: "#f2f2f2" } }); // src/components/modal/emojiCell.tsx var import_react_native4 = require("react-native"); var import_jsx_runtime3 = require("react/jsx-runtime"); function EmojiCell({ emoji, onPress, colSize }) { return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)( import_react_native4.TouchableOpacity, { style: { ...styles3.wrapper, width: colSize, height: colSize }, onPress: () => onPress(emoji), children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native4.Text, { style: { fontSize: colSize - 5 }, children: charFromEmojiObject(emoji) }) } ); } var styles3 = import_react_native4.StyleSheet.create({ wrapper: { borderRadius: 10, justifyContent: "center", alignItems: "center" } }); // src/components/modal/modal.tsx var import_react_native_reanimated = __toESM(require("react-native-reanimated")); var import_jsx_runtime4 = require("react/jsx-runtime"); var AnimatedBlurView = import_react_native_reanimated.default.createAnimatedComponent(import_expo_blur.BlurView); function Modal({ intensityBlur = 20, columns = 10, onEmojiSelected, onPressOutside, categories = [ "Smileys & Emotion", "Activities", "Animals & Nature", "Flags", "Food & Drink", "Objects", "People & Body", "Symbols", "Travel & Places" ], position = "center", darkMode = false, autoFocusSearch = false }) { const [search, setSearch] = (0, import_react.useState)(""); const [selectedCategory, setSelectedCategory] = (0, import_react.useState)(categories[0]); const key = (0, import_react.useMemo)(() => `modal-${(0, import_non_secure.nanoid)()}`, []); const colSize = Math.floor((screenWidth - 80) / columns); const positionStyle = (0, import_react.useMemo)(() => { switch (position) { case "top": return "flex-start"; case "bottom": return "flex-end"; default: return "center"; } }, [position]); return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_portal.Portal, { name: key, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native5.SafeAreaView, { style: styles4.safeArea, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)( import_react_native5.KeyboardAvoidingView, { keyboardVerticalOffset: import_react_native5.Platform.OS === "ios" ? 10 : 0, style: [styles4.container, { justifyContent: positionStyle }], behavior: import_react_native5.Platform.OS === "ios" ? "padding" : "height", children: [ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)( AnimatedBlurView, { entering: import_react_native_reanimated.FadeIn, exiting: import_react_native_reanimated.FadeOut, onTouchStart: onPressOutside, style: styles4.blur, intensity: intensityBlur } ), /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)( import_react_native_reanimated.default.View, { entering: import_react_native_reanimated.FadeInDown.springify(), exiting: import_react_native_reanimated.FadeOutDown, style: [styles4.modal, darkMode && { backgroundColor: "#352F44" }], children: [ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)( FilterBar, { darkMode, categories, onPress: (key2) => setSelectedCategory(key2), selectedCategory } ), /* @__PURE__ */ (0, import_jsx_runtime4.jsx)( Search, { darkMode, autoFocus: autoFocusSearch, placeholder: "Search..", value: search, onChangeText: (value) => setSearch(value) } ), !search && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)( import_react_native5.Text, { style: [styles4.title, { color: darkMode ? "white" : "black" }], children: selectedCategory } ), /* @__PURE__ */ (0, import_jsx_runtime4.jsx)( import_react_native5.FlatList, { numColumns: columns, showsVerticalScrollIndicator: false, ListEmptyComponent: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native5.View, { style: styles4.noResultWrapper, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native5.Text, { style: styles4.noResultText, children: "No Results" }) }), contentContainerStyle: styles4.flatlistContainer, data: emojis.filter((item) => { if (search === "") { return item.category === selectedCategory; } else { return item.name.includes(search.toLocaleUpperCase()); } }), keyExtractor: (_, index) => index.toString(), renderItem: ({ item }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)( EmojiCell, { colSize, emoji: item, onPress: (emoji) => onEmojiSelected(charFromEmojiObject(emoji)) } ) } ) ] } ) ] } ) }) }, key); } var styles4 = import_react_native5.StyleSheet.create({ safeArea: { height: screenHeight, width: screenWidth, position: "absolute" }, container: { zIndex: 1e3, alignItems: "center", height: "100%", width: "100%" }, blur: { position: "absolute", zIndex: 1, height: screenHeight, width: screenWidth }, modal: { zIndex: 10, paddingVertical: 20, height: "auto", maxHeight: screenHeight / 2, width: screenWidth - 40, borderRadius: 20, backgroundColor: "white", // shadow shadowColor: "#000", shadowOffset: { width: 2, height: 2 }, shadowOpacity: 0.3, shadowRadius: 30 }, title: { marginLeft: 20, fontSize: 20, marginVertical: 10 }, flatlistContainer: { marginHorizontal: 20 }, noResultWrapper: { marginVertical: 10, flex: 1, justifyContent: "center", alignItems: "center" }, noResultText: { fontSize: 16, color: "#666" } }); // src/components/provider/provider.tsx var import_portal2 = require("@gorhom/portal"); var import_jsx_runtime5 = require("react/jsx-runtime"); function Provider({ children }) { return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_portal2.PortalProvider, { children }); } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { EmojiModal, EmojiProvider });