@retray-dev/ui-kit 6.2.0 → 9.0.0
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/COMPONENTS.md +997 -20
- package/EXAMPLES.md +250 -2
- package/README.md +21 -14
- package/dist/Accordion.d.mts +28 -0
- package/dist/Accordion.d.ts +28 -0
- package/dist/Accordion.js +392 -0
- package/dist/Accordion.mjs +7 -0
- package/dist/AlertBanner.d.mts +16 -0
- package/dist/AlertBanner.d.ts +16 -0
- package/dist/AlertBanner.js +250 -0
- package/dist/AlertBanner.mjs +6 -0
- package/dist/AppHeader.d.mts +40 -0
- package/dist/AppHeader.d.ts +40 -0
- package/dist/AppHeader.js +515 -0
- package/dist/AppHeader.mjs +10 -0
- package/dist/Avatar.d.mts +20 -0
- package/dist/Avatar.d.ts +20 -0
- package/dist/Avatar.js +244 -0
- package/dist/Avatar.mjs +4 -0
- package/dist/Badge.d.mts +26 -0
- package/dist/Badge.d.ts +26 -0
- package/dist/Badge.js +257 -0
- package/dist/Badge.mjs +5 -0
- package/dist/Button.d.mts +30 -0
- package/dist/Button.d.ts +30 -0
- package/dist/Button.js +432 -0
- package/dist/Button.mjs +9 -0
- package/dist/ButtonGroup.d.mts +26 -0
- package/dist/ButtonGroup.d.ts +26 -0
- package/dist/ButtonGroup.js +52 -0
- package/dist/ButtonGroup.mjs +3 -0
- package/dist/Card.d.mts +39 -0
- package/dist/Card.d.ts +39 -0
- package/dist/Card.js +349 -0
- package/dist/Card.mjs +8 -0
- package/dist/CategoryStrip.d.mts +26 -0
- package/dist/CategoryStrip.d.ts +26 -0
- package/dist/CategoryStrip.js +453 -0
- package/dist/CategoryStrip.mjs +9 -0
- package/dist/Checkbox.d.mts +14 -0
- package/dist/Checkbox.d.ts +14 -0
- package/dist/Checkbox.js +336 -0
- package/dist/Checkbox.mjs +7 -0
- package/dist/Chip.d.mts +31 -0
- package/dist/Chip.d.ts +31 -0
- package/dist/Chip.js +403 -0
- package/dist/Chip.mjs +8 -0
- package/dist/ConfirmDialog.d.mts +15 -0
- package/dist/ConfirmDialog.d.ts +15 -0
- package/dist/ConfirmDialog.js +560 -0
- package/dist/ConfirmDialog.mjs +10 -0
- package/dist/CurrencyDisplay.d.mts +24 -0
- package/dist/CurrencyDisplay.d.ts +24 -0
- package/dist/CurrencyDisplay.js +189 -0
- package/dist/CurrencyDisplay.mjs +4 -0
- package/dist/CurrencyInput.d.mts +26 -0
- package/dist/CurrencyInput.d.ts +26 -0
- package/dist/CurrencyInput.js +408 -0
- package/dist/CurrencyInput.mjs +8 -0
- package/dist/DetailRow.d.mts +32 -0
- package/dist/DetailRow.d.ts +32 -0
- package/dist/DetailRow.js +275 -0
- package/dist/DetailRow.mjs +5 -0
- package/dist/EmptyState.d.mts +27 -0
- package/dist/EmptyState.d.ts +27 -0
- package/dist/EmptyState.js +523 -0
- package/dist/EmptyState.mjs +10 -0
- package/dist/ErrorBoundary.d.mts +42 -0
- package/dist/ErrorBoundary.d.ts +42 -0
- package/dist/ErrorBoundary.js +351 -0
- package/dist/ErrorBoundary.mjs +7 -0
- package/dist/Form.d.mts +52 -0
- package/dist/Form.d.ts +52 -0
- package/dist/Form.js +204 -0
- package/dist/Form.mjs +4 -0
- package/dist/HolographicCard.d.mts +55 -0
- package/dist/HolographicCard.d.ts +55 -0
- package/dist/HolographicCard.js +316 -0
- package/dist/HolographicCard.mjs +191 -0
- package/dist/IconButton.d.mts +27 -0
- package/dist/IconButton.d.ts +27 -0
- package/dist/IconButton.js +400 -0
- package/dist/IconButton.mjs +8 -0
- package/dist/ImageViewer.d.mts +23 -0
- package/dist/ImageViewer.d.ts +23 -0
- package/dist/ImageViewer.js +582 -0
- package/dist/ImageViewer.mjs +8 -0
- package/dist/Input.d.mts +23 -0
- package/dist/Input.d.ts +23 -0
- package/dist/Input.js +351 -0
- package/dist/Input.mjs +7 -0
- package/dist/LabelValue.d.mts +16 -0
- package/dist/LabelValue.d.ts +16 -0
- package/dist/LabelValue.js +225 -0
- package/dist/LabelValue.mjs +5 -0
- package/dist/ListGroup.d.mts +34 -0
- package/dist/ListGroup.d.ts +34 -0
- package/dist/ListGroup.js +217 -0
- package/dist/ListGroup.mjs +5 -0
- package/dist/ListItem.d.mts +64 -0
- package/dist/ListItem.d.ts +64 -0
- package/dist/ListItem.js +444 -0
- package/dist/ListItem.mjs +9 -0
- package/dist/MediaCard.d.mts +39 -0
- package/dist/MediaCard.d.ts +39 -0
- package/dist/MediaCard.js +475 -0
- package/dist/MediaCard.mjs +9 -0
- package/dist/MenuGroup.d.mts +34 -0
- package/dist/MenuGroup.d.ts +34 -0
- package/dist/MenuGroup.js +217 -0
- package/dist/MenuGroup.mjs +5 -0
- package/dist/MenuItem.d.mts +48 -0
- package/dist/MenuItem.d.ts +48 -0
- package/dist/MenuItem.js +415 -0
- package/dist/MenuItem.mjs +9 -0
- package/dist/MonthPicker.d.mts +28 -0
- package/dist/MonthPicker.d.ts +28 -0
- package/dist/MonthPicker.js +297 -0
- package/dist/MonthPicker.mjs +5 -0
- package/dist/PagerDots.d.mts +35 -0
- package/dist/PagerDots.d.ts +35 -0
- package/dist/PagerDots.js +392 -0
- package/dist/PagerDots.mjs +7 -0
- package/dist/Pressable.d.mts +34 -0
- package/dist/Pressable.d.ts +34 -0
- package/dist/Pressable.js +143 -0
- package/dist/Pressable.mjs +5 -0
- package/dist/PricingCard.d.mts +50 -0
- package/dist/PricingCard.d.ts +50 -0
- package/dist/PricingCard.js +636 -0
- package/dist/PricingCard.mjs +11 -0
- package/dist/Progress.d.mts +14 -0
- package/dist/Progress.d.ts +14 -0
- package/dist/Progress.js +191 -0
- package/dist/Progress.mjs +5 -0
- package/dist/RadioGroup.d.mts +19 -0
- package/dist/RadioGroup.d.ts +19 -0
- package/dist/RadioGroup.js +392 -0
- package/dist/RadioGroup.mjs +7 -0
- package/dist/RetrayProvider.d.mts +2 -0
- package/dist/RetrayProvider.d.ts +2 -0
- package/dist/RetrayProvider.js +214 -0
- package/dist/RetrayProvider.mjs +5 -0
- package/dist/Select.d.mts +22 -0
- package/dist/Select.d.ts +22 -0
- package/dist/Select.js +488 -0
- package/dist/Select.mjs +7 -0
- package/dist/SelectableGrid.d.mts +44 -0
- package/dist/SelectableGrid.d.ts +44 -0
- package/dist/SelectableGrid.js +448 -0
- package/dist/SelectableGrid.mjs +9 -0
- package/dist/Separator.d.mts +10 -0
- package/dist/Separator.d.ts +10 -0
- package/dist/Separator.js +156 -0
- package/dist/Separator.mjs +3 -0
- package/dist/Sheet.d.mts +93 -0
- package/dist/Sheet.d.ts +93 -0
- package/dist/Sheet.js +450 -0
- package/dist/Sheet.mjs +6 -0
- package/dist/Skeleton.d.mts +67 -0
- package/dist/Skeleton.d.ts +67 -0
- package/dist/Skeleton.js +266 -0
- package/dist/Skeleton.mjs +6 -0
- package/dist/Slider.d.mts +20 -0
- package/dist/Slider.d.ts +20 -0
- package/dist/Slider.js +279 -0
- package/dist/Slider.mjs +5 -0
- package/dist/Spinner.d.mts +12 -0
- package/dist/Spinner.d.ts +12 -0
- package/dist/Spinner.js +193 -0
- package/dist/Spinner.mjs +4 -0
- package/dist/Switch.d.mts +13 -0
- package/dist/Switch.d.ts +13 -0
- package/dist/Switch.js +311 -0
- package/dist/Switch.mjs +6 -0
- package/dist/TabBar.d.mts +42 -0
- package/dist/TabBar.d.ts +42 -0
- package/dist/TabBar.js +361 -0
- package/dist/TabBar.mjs +6 -0
- package/dist/Tabs.d.mts +27 -0
- package/dist/Tabs.d.ts +27 -0
- package/dist/Tabs.js +419 -0
- package/dist/Tabs.mjs +7 -0
- package/dist/Text.d.mts +12 -0
- package/dist/Text.d.ts +12 -0
- package/dist/Text.js +327 -0
- package/dist/Text.mjs +5 -0
- package/dist/Textarea.d.mts +16 -0
- package/dist/Textarea.d.ts +16 -0
- package/dist/Textarea.js +333 -0
- package/dist/Textarea.mjs +7 -0
- package/dist/Toast.d.mts +47 -0
- package/dist/Toast.d.ts +47 -0
- package/dist/Toast.js +185 -0
- package/dist/Toast.mjs +4 -0
- package/dist/Toggle.d.mts +36 -0
- package/dist/Toggle.d.ts +36 -0
- package/dist/Toggle.js +412 -0
- package/dist/Toggle.mjs +8 -0
- package/dist/VirtualList.d.mts +19 -0
- package/dist/VirtualList.d.ts +19 -0
- package/dist/VirtualList.js +38 -0
- package/dist/VirtualList.mjs +2 -0
- package/dist/chunk-26BCI223.mjs +14 -0
- package/dist/chunk-2CE3TQVY.mjs +11 -0
- package/dist/chunk-2TFTAWVJ.mjs +131 -0
- package/dist/chunk-2UYENBLV.mjs +49 -0
- package/dist/chunk-3BBOZ3OQ.mjs +41 -0
- package/dist/chunk-3DKJ2GIC.mjs +30 -0
- package/dist/chunk-3U4SSNWP.mjs +120 -0
- package/dist/chunk-4I7D47FH.mjs +139 -0
- package/dist/chunk-4K625MVM.mjs +142 -0
- package/dist/chunk-6OAZJ577.mjs +98 -0
- package/dist/chunk-6Q64UFIA.mjs +71 -0
- package/dist/chunk-756RAKE4.mjs +145 -0
- package/dist/chunk-7QHVVCB3.mjs +115 -0
- package/dist/chunk-A3A6KNQN.mjs +245 -0
- package/dist/chunk-A4MDAP7G.mjs +42 -0
- package/dist/chunk-AJ7ZDNBT.mjs +120 -0
- package/dist/chunk-AV4EMIRH.mjs +94 -0
- package/dist/chunk-AZJF2BLK.mjs +115 -0
- package/dist/chunk-BNP626TY.mjs +159 -0
- package/dist/chunk-BRKYVJVV.mjs +60 -0
- package/dist/chunk-DVK4G2GT.mjs +59 -0
- package/dist/chunk-EH745HE5.mjs +127 -0
- package/dist/chunk-EJ7ZPXOH.mjs +163 -0
- package/dist/chunk-GD6KXMG5.mjs +106 -0
- package/dist/chunk-GQYFLP3D.mjs +187 -0
- package/dist/chunk-ID72TK46.mjs +111 -0
- package/dist/chunk-IRRY3CRZ.mjs +82 -0
- package/dist/chunk-JB67UOB5.mjs +92 -0
- package/dist/chunk-JMOZEC77.mjs +90 -0
- package/dist/chunk-JT7HKXRB.mjs +114 -0
- package/dist/chunk-KIHCWCWL.mjs +124 -0
- package/dist/chunk-LXJIIOYQ.mjs +104 -0
- package/dist/chunk-M6ZXVBTK.mjs +64 -0
- package/dist/chunk-MAC465BB.mjs +61 -0
- package/dist/chunk-MBMXYJJV.mjs +36 -0
- package/dist/chunk-MLF3EZFW.mjs +119 -0
- package/dist/chunk-MX6HRKMI.mjs +29 -0
- package/dist/chunk-NA7PARID.mjs +147 -0
- package/dist/chunk-NC5ZTR2Y.mjs +32 -0
- package/dist/chunk-O3HA6TYM.mjs +139 -0
- package/dist/chunk-OB4JUQ3O.mjs +51 -0
- package/dist/chunk-PFZTM6D5.mjs +238 -0
- package/dist/chunk-QKH5ZOD5.mjs +97 -0
- package/dist/chunk-QY3X2UYR.mjs +191 -0
- package/dist/chunk-SOA2Z4RB.mjs +82 -0
- package/dist/chunk-SOYNZDVY.mjs +151 -0
- package/dist/chunk-T7XZ7H7Y.mjs +57 -0
- package/dist/chunk-TERDKCLE.mjs +74 -0
- package/dist/chunk-UREA2GYY.mjs +113 -0
- package/dist/chunk-VGTDN7SW.mjs +164 -0
- package/dist/chunk-VQ57HWPL.mjs +144 -0
- package/dist/chunk-WBOOUHSS.mjs +62 -0
- package/dist/chunk-WJLKJMKR.mjs +78 -0
- package/dist/chunk-X4G6APW6.mjs +134 -0
- package/dist/chunk-Y6FXYEAI.mjs +8 -0
- package/dist/chunk-YFZ3ELX5.mjs +16 -0
- package/dist/chunk-YNROWHQJ.mjs +46 -0
- package/dist/chunk-Z4BVUWW6.mjs +196 -0
- package/dist/chunk-ZJKGQMYH.mjs +131 -0
- package/dist/index-wt-orHUi.d.mts +85 -0
- package/dist/index-wt-orHUi.d.ts +85 -0
- package/dist/index.d.mts +149 -920
- package/dist/index.d.ts +149 -920
- package/dist/index.js +2560 -970
- package/dist/index.mjs +60 -3895
- package/package.json +55 -16
- package/src/assets/fonts/Sohne-Bold.otf +0 -0
- package/src/assets/fonts/Sohne-BoldItalic.otf +0 -0
- package/src/assets/fonts/Sohne-ExtraBold.otf +0 -0
- package/src/assets/fonts/Sohne-ExtraBoldItalic.otf +0 -0
- package/src/assets/fonts/Sohne-ExtraLight.otf +0 -0
- package/src/assets/fonts/Sohne-ExtraLightItalic.otf +0 -0
- package/src/assets/fonts/Sohne-Italic.otf +0 -0
- package/src/assets/fonts/Sohne-Light.otf +0 -0
- package/src/assets/fonts/Sohne-LightItalic.otf +0 -0
- package/src/assets/fonts/Sohne-Medium.otf +0 -0
- package/src/assets/fonts/Sohne-MediumItalic.otf +0 -0
- package/src/assets/fonts/Sohne-Regular.otf +0 -0
- package/src/assets/fonts/Sohne-SemiBold.otf +0 -0
- package/src/assets/fonts/Sohne-SemiBoldItalic.otf +0 -0
- package/src/assets/fonts/SohneMono-Bold.otf +0 -0
- package/src/assets/fonts/SohneMono-BoldItalic.otf +0 -0
- package/src/assets/fonts/SohneMono-ExtraBold.otf +0 -0
- package/src/assets/fonts/SohneMono-ExtraBoldItalic.otf +0 -0
- package/src/assets/fonts/SohneMono-ExtraLight.otf +0 -0
- package/src/assets/fonts/SohneMono-ExtraLightItalic.otf +0 -0
- package/src/assets/fonts/SohneMono-Italic.otf +0 -0
- package/src/assets/fonts/SohneMono-Light.otf +0 -0
- package/src/assets/fonts/SohneMono-LightItalic.otf +0 -0
- package/src/assets/fonts/SohneMono-Medium.otf +0 -0
- package/src/assets/fonts/SohneMono-MediumItalic.otf +0 -0
- package/src/assets/fonts/SohneMono-Regular.otf +0 -0
- package/src/assets/fonts/SohneMono-SemiBold.otf +0 -0
- package/src/assets/fonts/SohneMono-SemiBoldItalic.otf +0 -0
- package/src/components/Accordion/Accordion.tsx +15 -4
- package/src/components/AlertBanner/AlertBanner.tsx +38 -12
- package/src/components/AppHeader/AppHeader.tsx +172 -0
- package/src/components/AppHeader/index.ts +1 -0
- package/src/components/Avatar/Avatar.tsx +14 -4
- package/src/components/Badge/Badge.tsx +12 -3
- package/src/components/Button/Button.tsx +30 -38
- package/src/components/ButtonGroup/ButtonGroup.tsx +13 -10
- package/src/components/Card/Card.tsx +29 -57
- package/src/components/CategoryStrip/CategoryStrip.tsx +41 -42
- package/src/components/Checkbox/Checkbox.tsx +36 -45
- package/src/components/Chip/Chip.tsx +41 -48
- package/src/components/ConfirmDialog/ConfirmDialog.tsx +2 -2
- package/src/components/CurrencyDisplay/CurrencyDisplay.tsx +4 -2
- package/src/components/CurrencyInput/CurrencyInput.tsx +12 -10
- package/src/components/DetailRow/DetailRow.tsx +9 -7
- package/src/components/EmptyState/EmptyState.tsx +4 -3
- package/src/components/ErrorBoundary/ErrorBoundary.tsx +153 -0
- package/src/components/ErrorBoundary/index.ts +1 -0
- package/src/components/Form/Form.tsx +149 -0
- package/src/components/Form/index.ts +1 -0
- package/src/components/HolographicCard/HolographicCard.tsx +315 -0
- package/src/components/HolographicCard/index.ts +1 -0
- package/src/components/IconButton/IconButton.tsx +23 -29
- package/src/components/ImageViewer/ImageViewer.tsx +290 -0
- package/src/components/ImageViewer/index.ts +1 -0
- package/src/components/Input/Input.tsx +27 -31
- package/src/components/LabelValue/LabelValue.tsx +6 -4
- package/src/components/ListGroup/ListGroup.tsx +145 -0
- package/src/components/ListGroup/index.ts +1 -0
- package/src/components/ListItem/ListItem.tsx +78 -76
- package/src/components/MediaCard/MediaCard.tsx +15 -7
- package/src/components/MenuGroup/MenuGroup.tsx +145 -0
- package/src/components/MenuGroup/index.ts +1 -0
- package/src/components/MenuItem/MenuItem.tsx +16 -33
- package/src/components/MonthPicker/MonthPicker.tsx +41 -15
- package/src/components/MonthPicker/index.ts +1 -1
- package/src/components/PagerDots/PagerDots.tsx +200 -0
- package/src/components/PagerDots/index.ts +1 -0
- package/src/components/Pressable/Pressable.tsx +19 -35
- package/src/components/PricingCard/PricingCard.tsx +220 -0
- package/src/components/PricingCard/index.ts +1 -0
- package/src/components/RadioGroup/RadioGroup.tsx +23 -39
- package/src/components/RetrayProvider/RetrayProvider.tsx +59 -0
- package/src/components/RetrayProvider/index.ts +1 -0
- package/src/components/Select/Select.tsx +6 -6
- package/src/components/SelectableGrid/SelectableGrid.tsx +205 -0
- package/src/components/SelectableGrid/index.ts +1 -0
- package/src/components/Separator/Separator.tsx +1 -3
- package/src/components/Sheet/Sheet.tsx +146 -18
- package/src/components/Skeleton/Skeleton.tsx +143 -2
- package/src/components/Slider/Slider.tsx +2 -2
- package/src/components/Spinner/Spinner.tsx +18 -3
- package/src/components/Switch/Switch.tsx +44 -49
- package/src/components/TabBar/TabBar.tsx +169 -0
- package/src/components/TabBar/index.ts +1 -0
- package/src/components/Tabs/Tabs.tsx +45 -44
- package/src/components/Text/Text.tsx +5 -1
- package/src/components/Textarea/Textarea.tsx +18 -14
- package/src/components/Toast/Toast.tsx +6 -6
- package/src/components/Toggle/Toggle.tsx +80 -72
- package/src/components/VirtualList/VirtualList.tsx +60 -0
- package/src/components/VirtualList/index.ts +1 -0
- package/src/fonts.ts +41 -20
- package/src/index.ts +28 -3
- package/src/theme/colors.ts +53 -39
- package/src/theme/types.ts +3 -0
- package/src/tokens.ts +49 -39
- package/src/utils/animations.ts +29 -1
- package/src/utils/fontGuard.ts +34 -0
- package/src/utils/haptics.ts +211 -9
- package/src/utils/icons.ts +47 -20
- package/src/utils/pressable.ts +66 -0
- package/src/utils/usePressScale.ts +2 -0
- package/src/assets/fonts/Poppins-Black.ttf +0 -0
- package/src/assets/fonts/Poppins-BlackItalic.ttf +0 -0
- package/src/assets/fonts/Poppins-Bold.ttf +0 -0
- package/src/assets/fonts/Poppins-BoldItalic.ttf +0 -0
- package/src/assets/fonts/Poppins-ExtraBold.ttf +0 -0
- package/src/assets/fonts/Poppins-ExtraBoldItalic.ttf +0 -0
- package/src/assets/fonts/Poppins-ExtraLight.ttf +0 -0
- package/src/assets/fonts/Poppins-ExtraLightItalic.ttf +0 -0
- package/src/assets/fonts/Poppins-Italic.ttf +0 -0
- package/src/assets/fonts/Poppins-Light.ttf +0 -0
- package/src/assets/fonts/Poppins-LightItalic.ttf +0 -0
- package/src/assets/fonts/Poppins-Medium.ttf +0 -0
- package/src/assets/fonts/Poppins-MediumItalic.ttf +0 -0
- package/src/assets/fonts/Poppins-Regular.ttf +0 -0
- package/src/assets/fonts/Poppins-SemiBold.ttf +0 -0
- package/src/assets/fonts/Poppins-SemiBoldItalic.ttf +0 -0
- package/src/assets/fonts/Poppins-Thin.ttf +0 -0
- package/src/assets/fonts/Poppins-ThinItalic.ttf +0 -0
package/src/tokens.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
// ─── Spacing ─────────────────────────────────────────────────────────────────
|
|
2
|
-
// 8pt grid with 2pt micro-step. `section` for major band separators (Airbnb: 64px).
|
|
3
2
|
export const SPACING = {
|
|
4
3
|
xxs: 2,
|
|
5
4
|
xs: 4,
|
|
@@ -22,8 +21,6 @@ export const ICON_SIZES = {
|
|
|
22
21
|
} as const
|
|
23
22
|
|
|
24
23
|
// ─── Border radius ────────────────────────────────────────────────────────────
|
|
25
|
-
// Airbnb-aligned shape language — soft everywhere, no hard corners on interactive elements.
|
|
26
|
-
// xs: micro chips/tags sm: inputs/forms md: cards lg: sheet corners xl: primary CTAs (pill)
|
|
27
24
|
export const RADIUS = {
|
|
28
25
|
none: 0,
|
|
29
26
|
xs: 4,
|
|
@@ -35,7 +32,6 @@ export const RADIUS = {
|
|
|
35
32
|
} as const
|
|
36
33
|
|
|
37
34
|
// ─── Shadows ──────────────────────────────────────────────────────────────────
|
|
38
|
-
// Multi-tier. Default card usage = sm. Hover float = md. Modals = lg/xl.
|
|
39
35
|
export const SHADOWS = {
|
|
40
36
|
sm: {
|
|
41
37
|
shadowColor: '#000',
|
|
@@ -73,118 +69,132 @@ export const BREAKPOINTS = {
|
|
|
73
69
|
} as const
|
|
74
70
|
|
|
75
71
|
// ─── Typography ───────────────────────────────────────────────────────────────
|
|
76
|
-
//
|
|
77
|
-
//
|
|
78
|
-
//
|
|
72
|
+
// AUDIT FIX: Rationalised display scale — removed weight inversions and size
|
|
73
|
+
// collisions. display-lg/md separated by 4px with matching weights. title-md/sm
|
|
74
|
+
// now actually differ in size. uppercase-tag raised from 10px → 11px for
|
|
75
|
+
// minimum mobile readability (Apple HIG: 11pt floor).
|
|
79
76
|
export const TYPOGRAPHY = {
|
|
80
77
|
'display-hero': {
|
|
81
|
-
fontFamily: '
|
|
78
|
+
fontFamily: 'Sohne-Bold',
|
|
82
79
|
fontSize: 64,
|
|
83
80
|
fontWeight: '700' as const,
|
|
84
81
|
lineHeight: 70,
|
|
85
82
|
letterSpacing: -1,
|
|
86
83
|
},
|
|
87
84
|
'display-xl': {
|
|
88
|
-
fontFamily: '
|
|
85
|
+
fontFamily: 'Sohne-Bold',
|
|
89
86
|
fontSize: 28,
|
|
90
87
|
fontWeight: '700' as const,
|
|
91
88
|
lineHeight: 40,
|
|
92
89
|
letterSpacing: 0,
|
|
93
90
|
},
|
|
91
|
+
// AUDIT FIX: was 22px/500 — raised to 24px/600; removes weight inversion vs display-md
|
|
94
92
|
'display-lg': {
|
|
95
|
-
fontFamily: '
|
|
96
|
-
fontSize:
|
|
97
|
-
fontWeight: '
|
|
98
|
-
lineHeight:
|
|
99
|
-
letterSpacing: -0.
|
|
93
|
+
fontFamily: 'Sohne-SemiBold',
|
|
94
|
+
fontSize: 24,
|
|
95
|
+
fontWeight: '600' as const,
|
|
96
|
+
lineHeight: 32,
|
|
97
|
+
letterSpacing: -0.3,
|
|
100
98
|
},
|
|
99
|
+
// AUDIT FIX: was 21px/700 — lowered to 20px/600; weight normalised, 4px gap preserved
|
|
101
100
|
'display-md': {
|
|
102
|
-
fontFamily: '
|
|
103
|
-
fontSize:
|
|
104
|
-
fontWeight: '
|
|
105
|
-
lineHeight:
|
|
101
|
+
fontFamily: 'Sohne-SemiBold',
|
|
102
|
+
fontSize: 20,
|
|
103
|
+
fontWeight: '600' as const,
|
|
104
|
+
lineHeight: 28,
|
|
106
105
|
letterSpacing: 0,
|
|
107
106
|
},
|
|
108
107
|
'display-sm': {
|
|
109
|
-
fontFamily: '
|
|
110
|
-
fontSize:
|
|
108
|
+
fontFamily: 'Sohne-SemiBold',
|
|
109
|
+
fontSize: 18,
|
|
111
110
|
fontWeight: '600' as const,
|
|
112
111
|
lineHeight: 24,
|
|
113
112
|
letterSpacing: -0.18,
|
|
114
113
|
},
|
|
114
|
+
// AUDIT FIX: was 16px — raised to 17px so title-md > title-sm is size-visible
|
|
115
115
|
'title-md': {
|
|
116
|
-
fontFamily: '
|
|
117
|
-
fontSize:
|
|
116
|
+
fontFamily: 'Sohne-SemiBold',
|
|
117
|
+
fontSize: 17,
|
|
118
118
|
fontWeight: '600' as const,
|
|
119
|
-
lineHeight:
|
|
119
|
+
lineHeight: 22,
|
|
120
120
|
letterSpacing: 0,
|
|
121
121
|
},
|
|
122
|
+
// AUDIT FIX: was 16px — lowered to 15px; now distinct from title-md
|
|
122
123
|
'title-sm': {
|
|
123
|
-
fontFamily: '
|
|
124
|
-
fontSize:
|
|
124
|
+
fontFamily: 'Sohne-Medium',
|
|
125
|
+
fontSize: 15,
|
|
125
126
|
fontWeight: '500' as const,
|
|
126
127
|
lineHeight: 20,
|
|
127
128
|
letterSpacing: 0,
|
|
128
129
|
},
|
|
129
130
|
'body-md': {
|
|
130
|
-
fontFamily: '
|
|
131
|
+
fontFamily: 'Sohne-Regular',
|
|
131
132
|
fontSize: 16,
|
|
132
133
|
fontWeight: '400' as const,
|
|
133
134
|
lineHeight: 24,
|
|
134
135
|
letterSpacing: 0,
|
|
135
136
|
},
|
|
136
137
|
'body-sm': {
|
|
137
|
-
fontFamily: '
|
|
138
|
+
fontFamily: 'Sohne-Regular',
|
|
138
139
|
fontSize: 14,
|
|
139
140
|
fontWeight: '400' as const,
|
|
140
141
|
lineHeight: 20,
|
|
141
142
|
letterSpacing: 0,
|
|
142
143
|
},
|
|
143
|
-
caption: {
|
|
144
|
-
fontFamily: '
|
|
144
|
+
'caption': {
|
|
145
|
+
fontFamily: 'Sohne-Medium',
|
|
145
146
|
fontSize: 14,
|
|
146
147
|
fontWeight: '500' as const,
|
|
147
148
|
lineHeight: 18,
|
|
148
149
|
letterSpacing: 0,
|
|
149
150
|
},
|
|
150
151
|
'caption-sm': {
|
|
151
|
-
fontFamily: '
|
|
152
|
+
fontFamily: 'Sohne-Regular',
|
|
152
153
|
fontSize: 13,
|
|
153
154
|
fontWeight: '400' as const,
|
|
154
155
|
lineHeight: 16,
|
|
155
156
|
letterSpacing: 0,
|
|
156
157
|
},
|
|
157
158
|
'badge-text': {
|
|
158
|
-
fontFamily: '
|
|
159
|
+
fontFamily: 'Sohne-SemiBold',
|
|
159
160
|
fontSize: 11,
|
|
160
161
|
fontWeight: '600' as const,
|
|
161
|
-
lineHeight:
|
|
162
|
+
lineHeight: 14,
|
|
163
|
+
letterSpacing: 0,
|
|
164
|
+
},
|
|
165
|
+
// AUDIT FIX: added badge-text-md so Badge md size has a canonical token
|
|
166
|
+
'badge-text-md': {
|
|
167
|
+
fontFamily: 'Sohne-SemiBold',
|
|
168
|
+
fontSize: 13,
|
|
169
|
+
fontWeight: '600' as const,
|
|
170
|
+
lineHeight: 16,
|
|
162
171
|
letterSpacing: 0,
|
|
163
172
|
},
|
|
164
173
|
'micro-label': {
|
|
165
|
-
fontFamily: '
|
|
174
|
+
fontFamily: 'Sohne-Bold',
|
|
166
175
|
fontSize: 12,
|
|
167
176
|
fontWeight: '700' as const,
|
|
168
177
|
lineHeight: 16,
|
|
169
178
|
letterSpacing: 0,
|
|
170
179
|
},
|
|
180
|
+
// AUDIT FIX: was 10px/0.8 letterSpacing — raised to 11px/0.6; minimum mobile readability
|
|
171
181
|
'uppercase-tag': {
|
|
172
|
-
fontFamily: '
|
|
173
|
-
fontSize:
|
|
182
|
+
fontFamily: 'Sohne-Bold',
|
|
183
|
+
fontSize: 11,
|
|
174
184
|
fontWeight: '700' as const,
|
|
175
|
-
lineHeight:
|
|
176
|
-
letterSpacing: 0.
|
|
185
|
+
lineHeight: 14,
|
|
186
|
+
letterSpacing: 0.6,
|
|
177
187
|
textTransform: 'uppercase' as const,
|
|
178
188
|
},
|
|
179
189
|
'button-lg': {
|
|
180
|
-
fontFamily: '
|
|
190
|
+
fontFamily: 'Sohne-Medium',
|
|
181
191
|
fontSize: 16,
|
|
182
192
|
fontWeight: '500' as const,
|
|
183
193
|
lineHeight: 22,
|
|
184
194
|
letterSpacing: 0,
|
|
185
195
|
},
|
|
186
196
|
'button-sm': {
|
|
187
|
-
fontFamily: '
|
|
197
|
+
fontFamily: 'Sohne-Medium',
|
|
188
198
|
fontSize: 14,
|
|
189
199
|
fontWeight: '500' as const,
|
|
190
200
|
lineHeight: 18,
|
package/src/utils/animations.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Easing } from 'react-native-reanimated'
|
|
2
|
+
import type { SingleTransition } from 'react-native-ease'
|
|
2
3
|
|
|
3
4
|
// ─── Spring presets ──────────────────────────────────────────────────────────
|
|
4
5
|
// Tuned for the "Apple HIG / Airbnb" press-feel: snap inward fast, settle out elastically.
|
|
@@ -17,7 +18,7 @@ export const SPRINGS = {
|
|
|
17
18
|
surfacePressOut: { stiffness: 220, damping: 20, mass: 0.95 },
|
|
18
19
|
|
|
19
20
|
/** Settled transitions for moving indicators — Tabs pill, Switch thumb. */
|
|
20
|
-
glide: { stiffness: 380, damping: 38, mass: 1
|
|
21
|
+
glide: { stiffness: 380, damping: 38, mass: 1 },
|
|
21
22
|
|
|
22
23
|
/** Elastic indicator — Switch thumb, RadioGroup dot. */
|
|
23
24
|
elastic: { stiffness: 320, damping: 22, mass: 0.7 },
|
|
@@ -48,6 +49,33 @@ export const EASINGS = {
|
|
|
48
49
|
collapse: Easing.in(Easing.ease),
|
|
49
50
|
} as const
|
|
50
51
|
|
|
52
|
+
// ─── EaseView transition presets ─────────────────────────────────────────────
|
|
53
|
+
// Equivalents of the reanimated presets above, in `react-native-ease` units.
|
|
54
|
+
// EaseView spring takes raw damping/stiffness/mass (same physical model). EaseView
|
|
55
|
+
// timing takes duration + an easing curve as a cubic-bezier tuple.
|
|
56
|
+
|
|
57
|
+
/** Color/border state transition for Toggle, Checkbox, Chip, CategoryStrip, Switch track. Mirrors TIMINGS.state + EASINGS.standard. */
|
|
58
|
+
export const COLOR_TRANSITION: SingleTransition = {
|
|
59
|
+
type: 'timing',
|
|
60
|
+
duration: TIMINGS.state.duration,
|
|
61
|
+
easing: [0.2, 0, 0, 1],
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Icon/opacity crossfade. Mirrors TIMINGS.state + EASINGS.standard. */
|
|
65
|
+
export const OPACITY_TRANSITION: SingleTransition = {
|
|
66
|
+
type: 'timing',
|
|
67
|
+
duration: TIMINGS.state.duration,
|
|
68
|
+
easing: [0.2, 0, 0, 1],
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Elastic indicator spring — Switch thumb, RadioGroup dot. Mirrors SPRINGS.elastic. */
|
|
72
|
+
export const SPRING_ELASTIC: SingleTransition = {
|
|
73
|
+
type: 'spring',
|
|
74
|
+
stiffness: 320,
|
|
75
|
+
damping: 22,
|
|
76
|
+
mass: 0.7,
|
|
77
|
+
}
|
|
78
|
+
|
|
51
79
|
// ─── Press scale tokens ──────────────────────────────────────────────────────
|
|
52
80
|
// Per-component press intensities — taken from DESIGN.md.
|
|
53
81
|
export const PRESS_SCALE = {
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { isLoaded } from 'expo-font'
|
|
2
|
+
|
|
3
|
+
declare const __DEV__: boolean
|
|
4
|
+
|
|
5
|
+
let warned = false
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Dev-only guard: warns once if the Sohne font family is not loaded.
|
|
9
|
+
*
|
|
10
|
+
* Called lazily from `Text` on first render. Without this, a missing
|
|
11
|
+
* `useFonts(SohneFonts)` call (or a broken font path) produces invisible /
|
|
12
|
+
* system-font text with no signal — a silent failure consumers reported losing
|
|
13
|
+
* hours to. In production (`__DEV__ === false`) this is a no-op.
|
|
14
|
+
*/
|
|
15
|
+
export function warnIfFontsMissing(): void {
|
|
16
|
+
if (warned) return
|
|
17
|
+
if (typeof __DEV__ !== 'undefined' && !__DEV__) return
|
|
18
|
+
warned = true
|
|
19
|
+
try {
|
|
20
|
+
if (!isLoaded('Sohne-Regular')) {
|
|
21
|
+
console.warn(
|
|
22
|
+
'[retray-ui-kit] Sohne fonts are not loaded — text will fall back to the ' +
|
|
23
|
+
'system font. Load them at your app root before rendering any UI kit ' +
|
|
24
|
+
'component:\n\n' +
|
|
25
|
+
" import { useFonts } from 'expo-font'\n" +
|
|
26
|
+
" import { SohneFonts } from '@retray-dev/ui-kit/fonts'\n\n" +
|
|
27
|
+
' const [fontsLoaded] = useFonts(SohneFonts)\n' +
|
|
28
|
+
' if (!fontsLoaded) return null\n',
|
|
29
|
+
)
|
|
30
|
+
}
|
|
31
|
+
} catch {
|
|
32
|
+
// `isLoaded` not available in this expo-font version — skip the guard silently.
|
|
33
|
+
}
|
|
34
|
+
}
|
package/src/utils/haptics.ts
CHANGED
|
@@ -1,38 +1,240 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Haptic feedback utilities using expo-haptics.
|
|
3
|
+
*
|
|
4
|
+
* Uses expo-haptics which works with both Expo Go and development builds.
|
|
5
|
+
* react-native-pulsar support is optional for dev builds with native modules.
|
|
6
|
+
*
|
|
7
|
+
* All functions are web-safe (no-op on web platform).
|
|
8
|
+
*/
|
|
9
|
+
import { Platform, NativeModules } from 'react-native'
|
|
2
10
|
|
|
11
|
+
// ─── expo-haptics (primary) ───────────────────────────────────────────────────
|
|
3
12
|
type HapticsModule = typeof import('expo-haptics')
|
|
4
|
-
|
|
5
13
|
let _haptics: HapticsModule | null = null
|
|
14
|
+
let _hapticsLoaded = false
|
|
6
15
|
|
|
7
16
|
async function getHaptics(): Promise<HapticsModule | null> {
|
|
8
17
|
if (Platform.OS === 'web') return null
|
|
9
|
-
if (!
|
|
10
|
-
|
|
18
|
+
if (!_hapticsLoaded) {
|
|
19
|
+
_hapticsLoaded = true
|
|
20
|
+
try {
|
|
21
|
+
_haptics = await import('expo-haptics')
|
|
22
|
+
} catch {
|
|
23
|
+
_haptics = null
|
|
24
|
+
}
|
|
11
25
|
}
|
|
12
26
|
return _haptics
|
|
13
27
|
}
|
|
14
28
|
|
|
29
|
+
// ─── Pulsar (optional for dev builds) ─────────────────────────────────────────
|
|
30
|
+
// Only available in development builds with native modules installed.
|
|
31
|
+
// Gracefully falls back to expo-haptics if not available.
|
|
32
|
+
type PulsarModule = typeof import('react-native-pulsar')
|
|
33
|
+
let _pulsar: PulsarModule | null = null
|
|
34
|
+
let _pulsarChecked = false
|
|
35
|
+
let _pulsarAvailable = false
|
|
36
|
+
|
|
37
|
+
function isPulsarNativeRegistered(): boolean {
|
|
38
|
+
// react-native-pulsar's NativeRNPulsar.ts calls
|
|
39
|
+
// TurboModuleRegistry.getEnforcing('RNPulsar') at module-eval time. When the
|
|
40
|
+
// native binary is absent (e.g. Expo Go), requiring the package throws during
|
|
41
|
+
// Metro module eval — and that throw is surfaced by RN's global error handler
|
|
42
|
+
// (red screen) even when wrapped in try/catch, because guardedLoadModule
|
|
43
|
+
// reports it before rethrowing. So we must confirm the native module is
|
|
44
|
+
// actually registered BEFORE requiring the JS wrapper.
|
|
45
|
+
//
|
|
46
|
+
// TurboModuleRegistry.get() returns a truthy proxy even for unregistered
|
|
47
|
+
// modules (false positive), so it can't be trusted. Instead we probe the low
|
|
48
|
+
// level: the new-arch turbo proxy returns null for unregistered names, and
|
|
49
|
+
// the old-arch NativeModules map omits them. A direct lookup throws nothing —
|
|
50
|
+
// unlike a top-level import — so any failure is caught safely here.
|
|
51
|
+
try {
|
|
52
|
+
const g = globalThis as {
|
|
53
|
+
__turboModuleProxy?: (name: string) => unknown
|
|
54
|
+
}
|
|
55
|
+
if (typeof g.__turboModuleProxy === 'function') {
|
|
56
|
+
return g.__turboModuleProxy('RNPulsar') != null
|
|
57
|
+
}
|
|
58
|
+
return NativeModules?.RNPulsar != null
|
|
59
|
+
} catch {
|
|
60
|
+
return false
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function getPulsar(): PulsarModule | null {
|
|
65
|
+
if (Platform.OS === 'web') return null
|
|
66
|
+
if (!_pulsarChecked) {
|
|
67
|
+
_pulsarChecked = true
|
|
68
|
+
try {
|
|
69
|
+
// Only require the package when its native module is registered —
|
|
70
|
+
// otherwise the require would red-screen the app (see above).
|
|
71
|
+
if (isPulsarNativeRegistered()) {
|
|
72
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
73
|
+
_pulsar = require('react-native-pulsar') as PulsarModule
|
|
74
|
+
_pulsarAvailable = true
|
|
75
|
+
}
|
|
76
|
+
} catch {
|
|
77
|
+
_pulsar = null
|
|
78
|
+
_pulsarAvailable = false
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return _pulsarAvailable ? _pulsar : null
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// ─── Public API ───────────────────────────────────────────────────────────────
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Light selection feedback — checkboxes, switches, toggles, pickers.
|
|
88
|
+
*/
|
|
15
89
|
export function selectionAsync(): void {
|
|
16
90
|
if (Platform.OS === 'web') return
|
|
17
|
-
|
|
91
|
+
// Try expo-haptics first (always available in Expo Go)
|
|
92
|
+
getHaptics().then((h) => {
|
|
93
|
+
if (h) {
|
|
94
|
+
h.selectionAsync()
|
|
95
|
+
} else {
|
|
96
|
+
// Fallback to Pulsar if available
|
|
97
|
+
getPulsar()?.Presets.System.selection()
|
|
98
|
+
}
|
|
99
|
+
})
|
|
18
100
|
}
|
|
19
101
|
|
|
102
|
+
/**
|
|
103
|
+
* Light impact — cards, surfaces, light interactions.
|
|
104
|
+
*/
|
|
20
105
|
export function impactLight(): void {
|
|
21
106
|
if (Platform.OS === 'web') return
|
|
22
|
-
getHaptics().then(h =>
|
|
107
|
+
getHaptics().then((h) => {
|
|
108
|
+
if (h) {
|
|
109
|
+
h.impactAsync(h.ImpactFeedbackStyle.Light)
|
|
110
|
+
} else {
|
|
111
|
+
getPulsar()?.Presets.System.impactLight()
|
|
112
|
+
}
|
|
113
|
+
})
|
|
23
114
|
}
|
|
24
115
|
|
|
116
|
+
/**
|
|
117
|
+
* Medium impact — buttons, primary actions.
|
|
118
|
+
*/
|
|
25
119
|
export function impactMedium(): void {
|
|
26
120
|
if (Platform.OS === 'web') return
|
|
27
|
-
getHaptics().then(h =>
|
|
121
|
+
getHaptics().then((h) => {
|
|
122
|
+
if (h) {
|
|
123
|
+
h.impactAsync(h.ImpactFeedbackStyle.Medium)
|
|
124
|
+
} else {
|
|
125
|
+
getPulsar()?.Presets.System.impactMedium()
|
|
126
|
+
}
|
|
127
|
+
})
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Heavy impact — confirmations, important actions.
|
|
132
|
+
*/
|
|
133
|
+
export function impactHeavy(): void {
|
|
134
|
+
if (Platform.OS === 'web') return
|
|
135
|
+
getHaptics().then((h) => {
|
|
136
|
+
if (h) {
|
|
137
|
+
h.impactAsync(h.ImpactFeedbackStyle.Heavy)
|
|
138
|
+
} else {
|
|
139
|
+
getPulsar()?.Presets.System.impactHeavy()
|
|
140
|
+
}
|
|
141
|
+
})
|
|
28
142
|
}
|
|
29
143
|
|
|
144
|
+
/**
|
|
145
|
+
* Success notification — confirmations, completed actions.
|
|
146
|
+
*/
|
|
30
147
|
export function notificationSuccess(): void {
|
|
31
148
|
if (Platform.OS === 'web') return
|
|
32
|
-
getHaptics().then(h =>
|
|
149
|
+
getHaptics().then((h) => {
|
|
150
|
+
if (h) {
|
|
151
|
+
h.notificationAsync(h.NotificationFeedbackType.Success)
|
|
152
|
+
} else {
|
|
153
|
+
getPulsar()?.Presets.System.notificationSuccess()
|
|
154
|
+
}
|
|
155
|
+
})
|
|
33
156
|
}
|
|
34
157
|
|
|
158
|
+
/**
|
|
159
|
+
* Error notification — failed actions, errors.
|
|
160
|
+
*/
|
|
35
161
|
export function notificationError(): void {
|
|
36
162
|
if (Platform.OS === 'web') return
|
|
37
|
-
getHaptics().then(h =>
|
|
163
|
+
getHaptics().then((h) => {
|
|
164
|
+
if (h) {
|
|
165
|
+
h.notificationAsync(h.NotificationFeedbackType.Error)
|
|
166
|
+
} else {
|
|
167
|
+
getPulsar()?.Presets.System.notificationError()
|
|
168
|
+
}
|
|
169
|
+
})
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Warning notification — caution states.
|
|
174
|
+
*/
|
|
175
|
+
export function notificationWarning(): void {
|
|
176
|
+
if (Platform.OS === 'web') return
|
|
177
|
+
getHaptics().then((h) => {
|
|
178
|
+
if (h) {
|
|
179
|
+
h.notificationAsync(h.NotificationFeedbackType.Warning)
|
|
180
|
+
} else {
|
|
181
|
+
getPulsar()?.Presets.System.notificationWarning()
|
|
182
|
+
}
|
|
183
|
+
})
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// ─── Rich Pulsar Presets (enhanced feedback) ──────────────────────────────────
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Rich haptic presets from Pulsar — enhanced feedback for special interactions.
|
|
190
|
+
* Falls back to basic expo-haptics on Expo Go or unsupported devices.
|
|
191
|
+
*/
|
|
192
|
+
export const richHaptics = {
|
|
193
|
+
/** Hammer strike — strong confirmation feedback. */
|
|
194
|
+
hammer: (): void => {
|
|
195
|
+
if (Platform.OS === 'web') return
|
|
196
|
+
const p = getPulsar()
|
|
197
|
+
if (p) p.Presets.hammer()
|
|
198
|
+
else impactHeavy()
|
|
199
|
+
},
|
|
200
|
+
|
|
201
|
+
/** Pulse — rhythmic feedback for toggles or state changes. */
|
|
202
|
+
pulse: (): void => {
|
|
203
|
+
if (Platform.OS === 'web') return
|
|
204
|
+
const p = getPulsar()
|
|
205
|
+
if (p) p.Presets.pulse()
|
|
206
|
+
else selectionAsync()
|
|
207
|
+
},
|
|
208
|
+
|
|
209
|
+
/** Buzz — continuous vibration for attention. */
|
|
210
|
+
buzz: (): void => {
|
|
211
|
+
if (Platform.OS === 'web') return
|
|
212
|
+
const p = getPulsar()
|
|
213
|
+
if (p) p.Presets.buzz()
|
|
214
|
+
else impactMedium()
|
|
215
|
+
},
|
|
216
|
+
|
|
217
|
+
/** Flick — crisp click feedback. */
|
|
218
|
+
flick: (): void => {
|
|
219
|
+
if (Platform.OS === 'web') return
|
|
220
|
+
const p = getPulsar()
|
|
221
|
+
if (p) p.Presets.flick()
|
|
222
|
+
else selectionAsync()
|
|
223
|
+
},
|
|
224
|
+
|
|
225
|
+
/** Soft — gentle, subtle feedback. */
|
|
226
|
+
soft: (): void => {
|
|
227
|
+
if (Platform.OS === 'web') return
|
|
228
|
+
const p = getPulsar()
|
|
229
|
+
if (p) p.Presets.System.impactSoft()
|
|
230
|
+
else impactLight()
|
|
231
|
+
},
|
|
232
|
+
|
|
233
|
+
/** Rigid — firm, solid feedback. */
|
|
234
|
+
rigid: (): void => {
|
|
235
|
+
if (Platform.OS === 'web') return
|
|
236
|
+
const p = getPulsar()
|
|
237
|
+
if (p) p.Presets.System.impactRigid()
|
|
238
|
+
else impactMedium()
|
|
239
|
+
},
|
|
38
240
|
}
|
package/src/utils/icons.ts
CHANGED
|
@@ -17,36 +17,63 @@ export interface IconProps {
|
|
|
17
17
|
family?: IconFamily
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
type
|
|
20
|
+
type IconComponentType = React.ComponentType<{ name: string; size: number; color: string }>
|
|
21
|
+
type IconFamilyEntry = {
|
|
21
22
|
name: IconFamily
|
|
22
|
-
component:
|
|
23
|
-
glyphMap
|
|
23
|
+
component: IconComponentType
|
|
24
|
+
/** Deferred — glyphMap is only read when the resolution cache is first built. */
|
|
25
|
+
getGlyphMap: () => Record<string, number>
|
|
24
26
|
}
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
{ name: '
|
|
28
|
+
type WithGlyphMap = { glyphMap?: Record<string, number> }
|
|
29
|
+
|
|
30
|
+
const glyphMapOf = (mod: unknown): Record<string, number> =>
|
|
31
|
+
(mod as WithGlyphMap).glyphMap ?? {}
|
|
32
|
+
|
|
33
|
+
// Priority order: highest-priority family LAST so it overwrites lower-priority entries in the cache.
|
|
34
|
+
const ALL_FAMILIES: IconFamilyEntry[] = [
|
|
35
|
+
{ name: 'Ionicons', component: Ionicons as unknown as IconComponentType, getGlyphMap: () => glyphMapOf(Ionicons) },
|
|
36
|
+
{ name: 'MaterialIcons', component: MaterialIcons as unknown as IconComponentType, getGlyphMap: () => glyphMapOf(MaterialIcons) },
|
|
37
|
+
{ name: 'FontAwesome5', component: FontAwesome5 as unknown as IconComponentType, getGlyphMap: () => glyphMapOf(FontAwesome5) },
|
|
38
|
+
{ name: 'Entypo', component: Entypo as unknown as IconComponentType, getGlyphMap: () => glyphMapOf(Entypo) },
|
|
39
|
+
{ name: 'AntDesign', component: AntDesign as unknown as IconComponentType, getGlyphMap: () => glyphMapOf(AntDesign) },
|
|
40
|
+
{ name: 'Feather', component: Feather as unknown as IconComponentType, getGlyphMap: () => glyphMapOf(Feather) },
|
|
34
41
|
]
|
|
35
42
|
|
|
36
|
-
|
|
43
|
+
// Active families participating in name resolution. Defaults to all six.
|
|
44
|
+
let activeFamilies: IconFamilyEntry[] = ALL_FAMILIES
|
|
45
|
+
let resolvedCache: Map<string, IconFamilyEntry> | null = null
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Restrict which icon families participate in automatic name resolution.
|
|
49
|
+
* Narrowing to the families you actually use shrinks the resolution cache and
|
|
50
|
+
* speeds up the first `renderIcon` call (no scanning thousands of unused glyphs).
|
|
51
|
+
*
|
|
52
|
+
* Note: all six families are still statically imported by this module — Metro
|
|
53
|
+
* bundles them regardless. This controls *resolution scope*, not bundle size.
|
|
54
|
+
*
|
|
55
|
+
* @example configureIconFamilies(['Feather', 'MaterialIcons'])
|
|
56
|
+
*/
|
|
57
|
+
export function configureIconFamilies(families: IconFamily[]): void {
|
|
58
|
+
const order = families
|
|
59
|
+
.map((n) => ALL_FAMILIES.find((f) => f.name === n))
|
|
60
|
+
.filter((f): f is IconFamilyEntry => f !== undefined)
|
|
61
|
+
activeFamilies = order.length > 0 ? order : ALL_FAMILIES
|
|
62
|
+
resolvedCache = null // invalidate — rebuilt lazily on next resolve
|
|
63
|
+
}
|
|
37
64
|
|
|
38
|
-
function buildCache(): Map<string,
|
|
39
|
-
const cache = new Map<string,
|
|
40
|
-
for (const family of
|
|
41
|
-
|
|
42
|
-
for (const iconName of Object.keys(
|
|
65
|
+
function buildCache(): Map<string, IconFamilyEntry> {
|
|
66
|
+
const cache = new Map<string, IconFamilyEntry>()
|
|
67
|
+
for (const family of activeFamilies) {
|
|
68
|
+
const glyphMap = family.getGlyphMap()
|
|
69
|
+
for (const iconName of Object.keys(glyphMap)) {
|
|
43
70
|
cache.set(iconName, family)
|
|
44
71
|
}
|
|
45
72
|
}
|
|
46
73
|
return cache
|
|
47
74
|
}
|
|
48
75
|
|
|
49
|
-
function resolveFamily(name: string):
|
|
76
|
+
function resolveFamily(name: string): IconFamilyEntry | null {
|
|
50
77
|
if (!resolvedCache) {
|
|
51
78
|
resolvedCache = buildCache()
|
|
52
79
|
}
|
|
@@ -54,10 +81,10 @@ function resolveFamily(name: string): ResolvedFamily | null {
|
|
|
54
81
|
}
|
|
55
82
|
|
|
56
83
|
export function Icon({ name, size, color, family }: IconProps): React.ReactElement | null {
|
|
57
|
-
let resolved:
|
|
84
|
+
let resolved: IconFamilyEntry | null = null
|
|
58
85
|
|
|
59
86
|
if (family) {
|
|
60
|
-
resolved =
|
|
87
|
+
resolved = ALL_FAMILIES.find((f) => f.name === family) ?? null
|
|
61
88
|
} else {
|
|
62
89
|
resolved = resolveFamily(name)
|
|
63
90
|
}
|