@sincpro/mobile-ui 3.0.1 → 3.1.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.
Files changed (308) hide show
  1. package/dist/Actions/Actions.Button.d.ts +6 -6
  2. package/dist/Actions/Actions.Button.js +650 -180
  3. package/dist/Actions/Actions.Dock.d.ts +1 -1
  4. package/dist/Actions/Actions.Dock.js +297 -18
  5. package/dist/Actions/Actions.FAB.js +100 -12
  6. package/dist/Actions/Actions.FilterButton.d.ts +17 -0
  7. package/dist/Actions/Actions.FilterButton.js +263 -33
  8. package/dist/Actions/Actions.IconButton.d.ts +1 -0
  9. package/dist/Actions/Actions.IconButton.js +196 -33
  10. package/dist/Actions/index.js +13 -13
  11. package/dist/Dialog/Confirmation.context.js +82 -16
  12. package/dist/Dialog/Dialog.ActionSheet.js +200 -41
  13. package/dist/Dialog/Dialog.Confirmation.js +168 -31
  14. package/dist/Dialog/Dialog.EditValue.js +449 -61
  15. package/dist/Dialog/Dialog.Sheet.d.ts +7 -3
  16. package/dist/Dialog/Dialog.Sheet.js +231 -15
  17. package/dist/Dialog/OverlayHost.d.ts +23 -0
  18. package/dist/Dialog/OverlayHost.js +196 -0
  19. package/dist/Dialog/SheetSurface.d.ts +24 -0
  20. package/dist/Dialog/SheetSurface.js +441 -0
  21. package/dist/Dialog/dialog-actions.d.ts +17 -0
  22. package/dist/Dialog/dialog-actions.js +59 -0
  23. package/dist/Dialog/index.d.ts +4 -1
  24. package/dist/Dialog/index.js +8 -7
  25. package/dist/Dialog/overlay.store.d.ts +24 -0
  26. package/dist/Dialog/overlay.store.js +59 -0
  27. package/dist/Dialog/requestConfirmation.js +20 -10
  28. package/dist/Display/Display.Accordion.js +185 -13
  29. package/dist/Display/Display.AmountSummary.js +206 -15
  30. package/dist/Display/Display.Avatar.js +93 -31
  31. package/dist/Display/Display.AvatarGroup.js +132 -17
  32. package/dist/Display/Display.Badge.d.ts +18 -2
  33. package/dist/Display/Display.Badge.js +117 -49
  34. package/dist/Display/Display.Card.js +163 -26
  35. package/dist/Display/Display.Carousel.js +459 -105
  36. package/dist/Display/Display.Chip.d.ts +4 -1
  37. package/dist/Display/Display.Chip.js +165 -31
  38. package/dist/Display/Display.CircleButton.d.ts +1 -0
  39. package/dist/Display/Display.CircleButton.js +86 -27
  40. package/dist/Display/Display.CopyableText.js +289 -66
  41. package/dist/Display/Display.CountRecords.js +60 -3
  42. package/dist/Display/Display.DataTable.js +123 -13
  43. package/dist/Display/Display.Date.js +243 -33
  44. package/dist/Display/Display.Divider.d.ts +10 -10
  45. package/dist/Display/Display.Divider.js +67 -20
  46. package/dist/Display/Display.ExpoImage.js +97 -8
  47. package/dist/Display/Display.GradientSurface.d.ts +9 -4
  48. package/dist/Display/Display.GradientSurface.js +196 -46
  49. package/dist/Display/Display.Icon.js +129 -15
  50. package/dist/Display/Display.IconBadge.js +95 -25
  51. package/dist/Display/Display.Image.d.ts +7 -1
  52. package/dist/Display/Display.Image.js +344 -39
  53. package/dist/Display/Display.KeyValue.js +90 -5
  54. package/dist/Display/Display.ListGroup.js +181 -9
  55. package/dist/Display/Display.ListItem.js +324 -28
  56. package/dist/Display/Display.Logo.js +84 -29
  57. package/dist/Display/Display.MediaCard.js +125 -4
  58. package/dist/Display/Display.MediaEmbed.d.ts +0 -5
  59. package/dist/Display/Display.MediaEmbed.js +170 -26
  60. package/dist/Display/Display.MenuButton.d.ts +2 -2
  61. package/dist/Display/Display.MenuButton.js +380 -94
  62. package/dist/Display/Display.MenuCard.js +122 -18
  63. package/dist/Display/Display.MenuGrid.js +43 -3
  64. package/dist/Display/Display.Monetary.js +90 -5
  65. package/dist/Display/Display.Pattern.js +306 -47
  66. package/dist/Display/Display.PriceTag.js +117 -14
  67. package/dist/Display/Display.ProductCard.js +154 -4
  68. package/dist/Display/Display.Rating.js +92 -11
  69. package/dist/Display/Display.SearchHistory.js +132 -6
  70. package/dist/Display/Display.SectionHeader.d.ts +5 -1
  71. package/dist/Display/Display.SectionHeader.js +125 -12
  72. package/dist/Display/Display.Stat.js +62 -3
  73. package/dist/Display/Display.StatCard.js +131 -7
  74. package/dist/Display/Display.StatusBadge.d.ts +29 -0
  75. package/dist/Display/Display.StatusBadge.js +68 -0
  76. package/dist/Display/Display.StatusDot.js +93 -18
  77. package/dist/Display/Display.Story.js +285 -35
  78. package/dist/Display/Display.StoryTray.js +354 -34
  79. package/dist/Display/Display.StoryViewer.js +571 -72
  80. package/dist/Display/Display.SwipeableRow.js +141 -20
  81. package/dist/Display/Display.Tag.d.ts +4 -1
  82. package/dist/Display/Display.Tag.js +66 -4
  83. package/dist/Display/Display.Timeline.js +102 -13
  84. package/dist/Display/Display.Tooltip.js +122 -26
  85. package/dist/Display/chevron.d.ts +6 -0
  86. package/dist/Display/chevron.js +32 -0
  87. package/dist/Display/count-badge.d.ts +21 -0
  88. package/dist/Display/count-badge.js +124 -0
  89. package/dist/Display/group-title.d.ts +10 -0
  90. package/dist/Display/group-title.js +53 -0
  91. package/dist/Display/icon-font.d.ts +3 -0
  92. package/dist/Display/icon-font.ios.d.ts +3 -0
  93. package/dist/Display/icon-font.ios.js +4 -0
  94. package/dist/Display/icon-font.js +7 -0
  95. package/dist/Display/icon-glyphs.d.ts +2 -0
  96. package/dist/Display/icon-glyphs.js +87 -0
  97. package/dist/Display/icon-map.d.ts +5 -1
  98. package/dist/Display/icon-map.js +340 -84
  99. package/dist/Display/icon-registry.d.ts +21 -0
  100. package/dist/Display/icon-registry.js +21 -0
  101. package/dist/Display/index.d.ts +6 -1
  102. package/dist/Display/index.js +53 -48
  103. package/dist/Display/pill.d.ts +16 -0
  104. package/dist/Display/pill.js +47 -0
  105. package/dist/Feedback/ErrorBoundary.js +35 -23
  106. package/dist/Feedback/Feedback.Banner.js +202 -24
  107. package/dist/Feedback/Feedback.DomainSplashScreen.js +246 -70
  108. package/dist/Feedback/Feedback.Empty.js +54 -3
  109. package/dist/Feedback/Feedback.EmptyState.js +114 -5
  110. package/dist/Feedback/Feedback.Error.d.ts +1 -1
  111. package/dist/Feedback/Feedback.Error.js +130 -5
  112. package/dist/Feedback/Feedback.Loading.d.ts +1 -1
  113. package/dist/Feedback/Feedback.Loading.js +70 -3
  114. package/dist/Feedback/Feedback.PermissionCard.js +161 -5
  115. package/dist/Feedback/Feedback.Progress.js +199 -41
  116. package/dist/Feedback/Feedback.ProgressCircle.js +184 -12
  117. package/dist/Feedback/Feedback.Skeleton.js +149 -36
  118. package/dist/Feedback/Feedback.Spinner.js +407 -79
  119. package/dist/Feedback/Feedback.Splash.js +240 -33
  120. package/dist/Feedback/Feedback.State.d.ts +17 -0
  121. package/dist/Feedback/Feedback.State.js +104 -0
  122. package/dist/Feedback/Toast.context.js +883 -167
  123. package/dist/Feedback/index.d.ts +3 -0
  124. package/dist/Feedback/index.js +15 -13
  125. package/dist/Form/Form.Checkbox.js +212 -22
  126. package/dist/Form/Form.ControlledCheckbox.d.ts +1 -1
  127. package/dist/Form/Form.ControlledCheckbox.js +46 -4
  128. package/dist/Form/Form.ControlledDropdown.d.ts +1 -1
  129. package/dist/Form/Form.ControlledDropdown.js +62 -4
  130. package/dist/Form/Form.ControlledInput.d.ts +4 -3
  131. package/dist/Form/Form.ControlledInput.js +72 -4
  132. package/dist/Form/Form.ControlledMonetaryInput.d.ts +6 -3
  133. package/dist/Form/Form.ControlledMonetaryInput.js +50 -4
  134. package/dist/Form/Form.ControlledRadioButton.d.ts +2 -2
  135. package/dist/Form/Form.ControlledRadioButton.js +45 -4
  136. package/dist/Form/Form.DatePicker.js +505 -107
  137. package/dist/Form/Form.Dropdown.js +303 -52
  138. package/dist/Form/Form.ErrorSummary.js +236 -44
  139. package/dist/Form/Form.Field.d.ts +24 -0
  140. package/dist/Form/Form.Field.js +55 -0
  141. package/dist/Form/Form.FractionalQuantityInput.js +508 -96
  142. package/dist/Form/Form.Input.d.ts +17 -3
  143. package/dist/Form/Form.Input.js +478 -29
  144. package/dist/Form/Form.KeyboardForm.d.ts +22 -8
  145. package/dist/Form/Form.KeyboardForm.js +83 -8
  146. package/dist/Form/Form.KeyboardToolbarHost.d.ts +14 -0
  147. package/dist/Form/Form.KeyboardToolbarHost.js +182 -0
  148. package/dist/Form/Form.MonetaryInput.js +164 -17
  149. package/dist/Form/Form.PickerField.d.ts +31 -0
  150. package/dist/Form/Form.PickerField.js +562 -0
  151. package/dist/Form/Form.PinInput.js +150 -15
  152. package/dist/Form/Form.QuantitySelector.js +229 -25
  153. package/dist/Form/Form.RadioButton.js +132 -24
  154. package/dist/Form/Form.Select.js +487 -56
  155. package/dist/Form/Form.Slider.js +133 -10
  156. package/dist/Form/Form.Switch.js +99 -4
  157. package/dist/Form/index.d.ts +11 -6
  158. package/dist/Form/index.js +26 -27
  159. package/dist/Form/input-text.d.ts +7 -0
  160. package/dist/Form/input-text.js +18 -0
  161. package/dist/Navigation/Navigation.AppBar.d.ts +3 -4
  162. package/dist/Navigation/Navigation.AppBar.js +535 -99
  163. package/dist/Navigation/Navigation.BottomNav.js +363 -98
  164. package/dist/Navigation/Navigation.CollapsingHeader.d.ts +28 -13
  165. package/dist/Navigation/Navigation.CollapsingHeader.js +369 -36
  166. package/dist/Navigation/Navigation.FloatingBar.js +71 -11
  167. package/dist/Navigation/Navigation.Menu.js +309 -95
  168. package/dist/Navigation/Navigation.MenuSection.js +80 -11
  169. package/dist/Navigation/Navigation.RowItem.d.ts +4 -2
  170. package/dist/Navigation/Navigation.RowItem.js +93 -8
  171. package/dist/Navigation/Navigation.Search.js +241 -27
  172. package/dist/Navigation/Navigation.SearchBar.d.ts +7 -1
  173. package/dist/Navigation/Navigation.SearchBar.js +218 -29
  174. package/dist/Navigation/Navigation.SearchSuggestions.js +77 -3
  175. package/dist/Navigation/Navigation.SegmentedControl.js +152 -14
  176. package/dist/Navigation/Navigation.Steps.js +105 -11
  177. package/dist/Navigation/Navigation.Tabs.js +449 -41
  178. package/dist/Navigation/index.d.ts +9 -4
  179. package/dist/Navigation/index.js +13 -13
  180. package/dist/Typography/Typography.Heading.js +33 -3
  181. package/dist/Typography/Typography.SelectableText.js +95 -7
  182. package/dist/Typography/Typography.Text.d.ts +4 -2
  183. package/dist/Typography/Typography.Text.js +217 -7
  184. package/dist/Typography/index.js +3 -3
  185. package/dist/branding.js +29 -13
  186. package/dist/icons/AddItemIcon.js +76 -2
  187. package/dist/icons/ArrangeCircle.js +82 -2
  188. package/dist/icons/ArrowDownIcon.js +63 -3
  189. package/dist/icons/ArrowUpIcon.js +63 -3
  190. package/dist/icons/BoxIcon.js +64 -2
  191. package/dist/icons/BoxTimeIcon.js +63 -2
  192. package/dist/icons/CalendarIcon.js +145 -2
  193. package/dist/icons/CardIcon.js +80 -2
  194. package/dist/icons/CashierIcon.js +39 -2
  195. package/dist/icons/CreditIcon.js +76 -3
  196. package/dist/icons/DuoIcon.js +75 -2
  197. package/dist/icons/HomeIcon.js +39 -2
  198. package/dist/icons/HomeIconOutlined.js +53 -2
  199. package/dist/icons/LogoIcon.js +87 -2
  200. package/dist/icons/MoneyReceiveIcon.js +86 -2
  201. package/dist/icons/PinIcon.js +39 -2
  202. package/dist/icons/ProfileIcon.js +47 -2
  203. package/dist/icons/SettingsIcon.js +114 -2
  204. package/dist/icons/SinpeIcon.js +60 -2
  205. package/dist/icons/ToggleOffIcon.js +53 -2
  206. package/dist/icons/WalletMoneyIcon.js +81 -2
  207. package/dist/index.d.ts +1 -0
  208. package/dist/index.js +8 -2
  209. package/dist/layouts/AuthContainer.d.ts +4 -5
  210. package/dist/layouts/AuthContainer.js +231 -7
  211. package/dist/layouts/BottomInset.js +4 -1
  212. package/dist/layouts/Container.d.ts +2 -2
  213. package/dist/layouts/Container.js +45 -3
  214. package/dist/layouts/GradientContainer.js +37 -5
  215. package/dist/layouts/PlainLayout.js +19 -3
  216. package/dist/layouts/ScrollContainer.d.ts +14 -9
  217. package/dist/layouts/ScrollContainer.js +125 -4
  218. package/dist/layouts/edges.d.ts +2 -0
  219. package/dist/layouts/edges.js +1 -0
  220. package/dist/primitives/AspectRatio.js +75 -3
  221. package/dist/primitives/Box.js +45 -3
  222. package/dist/primitives/Pressable.js +95 -5
  223. package/dist/primitives/Row.js +84 -13
  224. package/dist/primitives/Spacer.js +42 -5
  225. package/dist/primitives/Stack.js +66 -7
  226. package/dist/primitives/index.js +1 -1
  227. package/dist/theme/active.js +20 -18
  228. package/dist/theme/build.js +118 -87
  229. package/dist/theme/color.js +87 -87
  230. package/dist/theme/components/ThemedActivityIndicator.d.ts +2 -15
  231. package/dist/theme/components/ThemedActivityIndicator.js +35 -3
  232. package/dist/theme/components/index.js +1 -0
  233. package/dist/theme/contrast.js +32 -33
  234. package/dist/theme/css-vars.js +71 -75
  235. package/dist/theme/dark.js +116 -97
  236. package/dist/theme/default.js +116 -97
  237. package/dist/theme/define.js +16 -12
  238. package/dist/theme/index.d.ts +1 -0
  239. package/dist/theme/index.js +7 -6
  240. package/dist/theme/on-dark-surface.d.ts +12 -0
  241. package/dist/theme/on-dark-surface.js +13 -0
  242. package/dist/theme/theme.js +1 -0
  243. package/dist/theme/tw.js +3 -1
  244. package/dist/theme/types.js +0 -18
  245. package/dist/theme/typography.d.ts +1 -1
  246. package/dist/theme/typography.js +337 -303
  247. package/dist/theme/useTheme.js +12 -3
  248. package/dist/theme/useThemeVars.d.ts +9 -0
  249. package/dist/theme/useThemeVars.js +23 -0
  250. package/dist/theme/validate.js +175 -166
  251. package/dist/tokens/index.js +1 -1
  252. package/dist/tokens/motion.js +30 -13
  253. package/dist/utils/async.d.ts +14 -0
  254. package/dist/utils/async.js +22 -0
  255. package/dist/utils/criteria.js +66 -85
  256. package/dist/utils/date.d.ts +8 -2
  257. package/dist/utils/date.js +63 -50
  258. package/dist/utils/image.js +8 -8
  259. package/dist/utils/intl.d.ts +1 -0
  260. package/dist/utils/intl.js +13 -0
  261. package/dist/utils/keys.js +3 -5
  262. package/dist/utils/monetary.d.ts +1 -0
  263. package/dist/utils/monetary.js +28 -24
  264. package/dist/utils/progress.js +2 -3
  265. package/dist/utils/quantity.js +25 -26
  266. package/dist/utils/reorder.js +11 -20
  267. package/dist/utils/search.d.ts +4 -0
  268. package/dist/utils/search.js +12 -0
  269. package/dist/utils/serializer.js +38 -38
  270. package/dist/utils/useReducedMotion.js +32 -30
  271. package/dist/views/AppSplashView.js +117 -3
  272. package/dist/views/AuthFormView.d.ts +4 -5
  273. package/dist/views/AuthFormView.js +119 -11
  274. package/dist/views/FormViewV2.context.js +75 -23
  275. package/dist/views/FormViewV2.d.ts +4 -5
  276. package/dist/views/FormViewV2.js +658 -92
  277. package/dist/views/ListViewV2.context.js +91 -47
  278. package/dist/views/ListViewV2.d.ts +84 -43
  279. package/dist/views/ListViewV2.js +1350 -200
  280. package/dist/views/Wizard/Wizard.context.js +248 -84
  281. package/dist/views/Wizard/Wizard.js +260 -67
  282. package/dist/views/types/IListView.js +34 -31
  283. package/dist/widgets/CollectionOptions.js +557 -138
  284. package/dist/widgets/FilterBar.js +159 -7
  285. package/dist/widgets/FilterBuilder.js +375 -102
  286. package/dist/widgets/JSONViewer.js +275 -129
  287. package/dist/widgets/PromoBanner.js +336 -42
  288. package/dist/widgets/PromoModal.d.ts +2 -2
  289. package/dist/widgets/PromoModal.js +389 -62
  290. package/dist/widgets/QueryChoice.js +150 -8
  291. package/dist/widgets/QuickActions.js +120 -31
  292. package/dist/widgets/ReorderableList.js +399 -128
  293. package/dist/widgets/TimeZoneSelectorModal.js +458 -51
  294. package/dist/widgets/index.js +3 -3
  295. package/package.json +6 -1
  296. package/tailwind.preset.js +7 -5
  297. package/dist/Form/Form.InputField.d.ts +0 -10
  298. package/dist/Form/Form.InputField.js +0 -38
  299. package/dist/Form/Form.KeyboardToolbar.d.ts +0 -22
  300. package/dist/Form/Form.KeyboardToolbar.js +0 -66
  301. package/dist/Form/Form.PasswordInput.d.ts +0 -9
  302. package/dist/Form/Form.PasswordInput.js +0 -17
  303. package/dist/Form/Form.TextInput.d.ts +0 -8
  304. package/dist/Form/Form.TextInput.js +0 -8
  305. package/dist/primitives/BaseButton.d.ts +0 -150
  306. package/dist/primitives/BaseButton.js +0 -229
  307. package/dist/utils/useSheetTranslation.d.ts +0 -5
  308. package/dist/utils/useSheetTranslation.js +0 -23
@@ -1,7 +1,16 @@
1
- import { getActiveTheme, getThemeVersion, subscribeTheme, } from "./active.js";
1
+ import { c as _c } from "react/compiler-runtime";
2
+ import { getActiveTheme, getThemeVersion, subscribeTheme } from "./active.js";
2
3
  import { useSyncExternalStore } from "react";
3
4
  export function useTheme() {
4
- useSyncExternalStore(subscribeTheme, getThemeVersion, getThemeVersion);
5
- return getActiveTheme();
5
+ const $ = _c(1);
6
+ useSyncExternalStore(subscribeTheme, getThemeVersion, getThemeVersion);
7
+ let t0;
8
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
9
+ t0 = getActiveTheme();
10
+ $[0] = t0;
11
+ } else {
12
+ t0 = $[0];
13
+ }
14
+ return t0;
6
15
  }
7
16
  export const theme = getActiveTheme();
@@ -0,0 +1,9 @@
1
+ import { vars } from "nativewind";
2
+ type ThemeVars = ReturnType<typeof vars>;
3
+ /**
4
+ * NativeWind CSS variables for the active theme, as one stable object per
5
+ * theme version. A new object on every render would make every `className`
6
+ * consumer below re-resolve its styles.
7
+ */
8
+ export declare function useThemeVars(): ThemeVars;
9
+ export {};
@@ -0,0 +1,23 @@
1
+ import { getActiveTheme, getThemeVersion, subscribeTheme } from "./active.js";
2
+ import { themeToVars } from "./css-vars.js";
3
+ import { vars } from "nativewind";
4
+ import { useSyncExternalStore } from "react";
5
+ let cachedVersion = -1;
6
+ let cachedVars;
7
+ function currentVars() {
8
+ const version = getThemeVersion();
9
+ if (!cachedVars || cachedVersion !== version) {
10
+ cachedVersion = version;
11
+ cachedVars = vars(themeToVars(getActiveTheme()));
12
+ }
13
+ return cachedVars;
14
+ }
15
+
16
+ /**
17
+ * NativeWind CSS variables for the active theme, as one stable object per
18
+ * theme version. A new object on every render would make every `className`
19
+ * consumer below re-resolve its styles.
20
+ */
21
+ export function useThemeVars() {
22
+ return useSyncExternalStore(subscribeTheme, currentVars, currentVars);
23
+ }
@@ -9,61 +9,77 @@ import { contrastRatio, resolveOnColor } from "./contrast.js";
9
9
  * tests intentionally pass partial themes). Can also be called directly.
10
10
  */
11
11
  export function validateTheme(theme) {
12
- const issues = [];
13
- if (typeof theme.name !== "string" || theme.name.trim() === "") {
14
- issues.push({ path: "name", message: "Theme must have a non-empty `name`." });
12
+ const issues = [];
13
+ if (typeof theme.name !== "string" || theme.name.trim() === "") {
14
+ issues.push({
15
+ path: "name",
16
+ message: "Theme must have a non-empty `name`."
17
+ });
18
+ }
19
+ if (!isHex(theme.primary)) {
20
+ issues.push({
21
+ path: "primary",
22
+ message: `Invalid hex color: ${String(theme.primary)}`
23
+ });
24
+ }
25
+ if (!isHex(theme.accent)) {
26
+ issues.push({
27
+ path: "accent",
28
+ message: `Invalid hex color: ${String(theme.accent)}`
29
+ });
30
+ }
31
+ if (!isHex(theme.bg?.page)) {
32
+ issues.push({
33
+ path: "bg.page",
34
+ message: `Invalid hex color: ${String(theme.bg?.page)}`
35
+ });
36
+ }
37
+ if (!isHex(theme.text?.primary)) {
38
+ issues.push({
39
+ path: "text.primary",
40
+ message: `Invalid hex color: ${String(theme.text?.primary)}`
41
+ });
42
+ }
43
+ if (theme.pattern) {
44
+ if (!isFiniteSize(theme.pattern.size)) {
45
+ issues.push({
46
+ path: "pattern.size",
47
+ message: `Tile size must be > 0 (got ${String(theme.pattern.size)}).`
48
+ });
15
49
  }
16
- if (!isHex(theme.primary)) {
17
- issues.push({ path: "primary", message: `Invalid hex color: ${String(theme.primary)}` });
18
- }
19
- if (!isHex(theme.accent)) {
20
- issues.push({ path: "accent", message: `Invalid hex color: ${String(theme.accent)}` });
21
- }
22
- if (!isHex(theme.bg?.page)) {
23
- issues.push({ path: "bg.page", message: `Invalid hex color: ${String(theme.bg?.page)}` });
24
- }
25
- if (!isHex(theme.text?.primary)) {
26
- issues.push({
27
- path: "text.primary",
28
- message: `Invalid hex color: ${String(theme.text?.primary)}`,
29
- });
30
- }
31
- if (theme.pattern) {
32
- if (!isFiniteSize(theme.pattern.size)) {
33
- issues.push({
34
- path: "pattern.size",
35
- message: `Tile size must be > 0 (got ${String(theme.pattern.size)}).`,
36
- });
37
- }
38
- }
39
- if (theme.shadow) {
40
- issues.push(...validateShadow("shadow.sm", theme.shadow.sm));
41
- issues.push(...validateShadow("shadow.md", theme.shadow.md));
42
- issues.push(...validateShadow("shadow.lg", theme.shadow.lg));
43
- }
44
- issues.push(...validateContrast(theme));
45
- issues.push(...validateSemanticDistinct(theme));
46
- return issues;
50
+ }
51
+ if (theme.shadow) {
52
+ issues.push(...validateShadow("shadow.sm", theme.shadow.sm));
53
+ issues.push(...validateShadow("shadow.md", theme.shadow.md));
54
+ issues.push(...validateShadow("shadow.lg", theme.shadow.lg));
55
+ }
56
+ issues.push(...validateContrast(theme));
57
+ issues.push(...validateSemanticDistinct(theme));
58
+ return issues;
47
59
  }
48
60
  function isHex(value) {
49
- return typeof value === "string" && /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(value.trim());
61
+ return typeof value === "string" && /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(value.trim());
50
62
  }
51
63
  function isFiniteSize(n) {
52
- return typeof n === "number" && Number.isFinite(n) && n > 0;
64
+ return typeof n === "number" && Number.isFinite(n) && n > 0;
53
65
  }
54
66
  function validateShadow(path, s) {
55
- const out = [];
56
- if (typeof s.shadowColor !== "string" || s.shadowColor.trim() === "") {
57
- out.push({ path: `${path}.shadowColor`, message: "shadowColor must be a string." });
58
- }
59
- if (typeof s.shadowOpacity !== "number" || s.shadowOpacity < 0 || s.shadowOpacity > 1) {
60
- out.push({
61
- path: `${path}.shadowOpacity`,
62
- message: `shadowOpacity must be in [0, 1] (got ${s.shadowOpacity}).`,
63
- });
64
- }
65
- return out;
67
+ const out = [];
68
+ if (typeof s.shadowColor !== "string" || s.shadowColor.trim() === "") {
69
+ out.push({
70
+ path: `${path}.shadowColor`,
71
+ message: "shadowColor must be a string."
72
+ });
73
+ }
74
+ if (typeof s.shadowOpacity !== "number" || s.shadowOpacity < 0 || s.shadowOpacity > 1) {
75
+ out.push({
76
+ path: `${path}.shadowOpacity`,
77
+ message: `shadowOpacity must be in [0, 1] (got ${s.shadowOpacity}).`
78
+ });
79
+ }
80
+ return out;
66
81
  }
82
+
67
83
  /**
68
84
  * WCAG 2.1 contrast validation. Checks the P0 on-color pairs that every consumer
69
85
  * relies on (CTA text/bg, focus ring, body text on surfaces). Flags any pair below the
@@ -71,130 +87,123 @@ function validateShadow(path, s) {
71
87
  * entries — never throws — so the dev-mode warning stays non-fatal.
72
88
  */
73
89
  function validateContrast(theme) {
74
- const issues = [];
75
- const checks = [
76
- {
77
- fg: theme.text?.onPrimary,
78
- bg: theme.primary,
79
- min: 4.5,
80
- label: "text.onPrimary on primary (CTA)",
81
- },
82
- {
83
- fg: theme.text?.onSecondary,
84
- bg: theme.secondary,
85
- min: 4.5,
86
- label: "text.onSecondary on secondary",
87
- },
88
- {
89
- fg: theme.text?.onAccent,
90
- bg: theme.accent,
91
- min: 4.5,
92
- label: "text.onAccent on accent",
93
- },
94
- { fg: theme.border?.focus, bg: theme.bg?.page, min: 3, label: "border.focus on bg.page" },
95
- { fg: theme.border?.focus, bg: theme.bg?.card, min: 3, label: "border.focus on bg.card" },
96
- {
97
- fg: theme.text?.onDanger,
98
- bg: theme.danger,
99
- min: 4.5,
100
- label: "text.onDanger on danger",
101
- },
102
- {
103
- fg: theme.text?.onSuccess,
104
- bg: theme.success,
105
- min: 4.5,
106
- label: "text.onSuccess on success",
107
- },
108
- {
109
- fg: theme.text?.accent,
110
- bg: theme.bg?.card,
111
- min: 4.5,
112
- label: "text.accent on bg.card (brand text)",
113
- },
114
- {
115
- fg: theme.text?.accent,
116
- bg: theme.bg?.page,
117
- min: 4.5,
118
- label: "text.accent on bg.page (brand text)",
119
- },
120
- {
121
- fg: theme.container?.onPrimary,
122
- bg: theme.container?.primary,
123
- min: 4.5,
124
- label: "container.onPrimary on container.primary",
125
- },
126
- {
127
- fg: theme.container?.onSuccess,
128
- bg: theme.container?.success,
129
- min: 4.5,
130
- label: "container.onSuccess on container.success",
131
- },
132
- {
133
- fg: theme.container?.onDanger,
134
- bg: theme.container?.danger,
135
- min: 4.5,
136
- label: "container.onDanger on container.danger",
137
- },
138
- ];
139
- for (const c of checks) {
140
- if (!isHex(c.fg) || !isHex(c.bg))
141
- continue;
142
- const ratio = contrastRatio(c.fg, c.bg);
143
- if (ratio < c.min) {
144
- let message = `Contrast ratio ${ratio.toFixed(2)}:1 is below WCAG AA minimum ${c.min}:1 for body/UI text.`;
145
- if (c.label.includes("onPrimary") && isHex(theme.primary)) {
146
- const suggested = resolveOnColor(theme.primary);
147
- message += ` Use resolveOnColor(primary) → ${suggested}.`;
148
- }
149
- issues.push({ path: c.label, message });
150
- }
90
+ const issues = [];
91
+ const checks = [{
92
+ fg: theme.text?.onPrimary,
93
+ bg: theme.primary,
94
+ min: 4.5,
95
+ label: "text.onPrimary on primary (CTA)"
96
+ }, {
97
+ fg: theme.text?.onSecondary,
98
+ bg: theme.secondary,
99
+ min: 4.5,
100
+ label: "text.onSecondary on secondary"
101
+ }, {
102
+ fg: theme.text?.onAccent,
103
+ bg: theme.accent,
104
+ min: 4.5,
105
+ label: "text.onAccent on accent"
106
+ }, {
107
+ fg: theme.border?.focus,
108
+ bg: theme.bg?.page,
109
+ min: 3,
110
+ label: "border.focus on bg.page"
111
+ }, {
112
+ fg: theme.border?.focus,
113
+ bg: theme.bg?.card,
114
+ min: 3,
115
+ label: "border.focus on bg.card"
116
+ }, {
117
+ fg: theme.text?.onDanger,
118
+ bg: theme.danger,
119
+ min: 4.5,
120
+ label: "text.onDanger on danger"
121
+ }, {
122
+ fg: theme.text?.onSuccess,
123
+ bg: theme.success,
124
+ min: 4.5,
125
+ label: "text.onSuccess on success"
126
+ }, {
127
+ fg: theme.text?.accent,
128
+ bg: theme.bg?.card,
129
+ min: 4.5,
130
+ label: "text.accent on bg.card (brand text)"
131
+ }, {
132
+ fg: theme.text?.accent,
133
+ bg: theme.bg?.page,
134
+ min: 4.5,
135
+ label: "text.accent on bg.page (brand text)"
136
+ }, {
137
+ fg: theme.container?.onPrimary,
138
+ bg: theme.container?.primary,
139
+ min: 4.5,
140
+ label: "container.onPrimary on container.primary"
141
+ }, {
142
+ fg: theme.container?.onSuccess,
143
+ bg: theme.container?.success,
144
+ min: 4.5,
145
+ label: "container.onSuccess on container.success"
146
+ }, {
147
+ fg: theme.container?.onDanger,
148
+ bg: theme.container?.danger,
149
+ min: 4.5,
150
+ label: "container.onDanger on container.danger"
151
+ }];
152
+ for (const c of checks) {
153
+ if (!isHex(c.fg) || !isHex(c.bg)) continue;
154
+ const ratio = contrastRatio(c.fg, c.bg);
155
+ if (ratio < c.min) {
156
+ let message = `Contrast ratio ${ratio.toFixed(2)}:1 is below WCAG AA minimum ${c.min}:1 for body/UI text.`;
157
+ if (c.label.includes("onPrimary") && isHex(theme.primary)) {
158
+ const suggested = resolveOnColor(theme.primary);
159
+ message += ` Use resolveOnColor(primary) → ${suggested}.`;
160
+ }
161
+ issues.push({
162
+ path: c.label,
163
+ message
164
+ });
151
165
  }
152
- return issues;
166
+ }
167
+ return issues;
153
168
  }
169
+
154
170
  /** Roles that must stay visually distinct for maintainable state semantics. */
155
171
  function validateSemanticDistinct(theme) {
156
- const issues = [];
157
- const pairs = [
158
- ["bg.disabled vs bg.muted", theme.bg?.disabled, theme.bg?.muted],
159
- ["text.disabled vs text.muted", theme.text?.disabled, theme.text?.muted],
160
- ["icon.disabled vs icon.secondary", theme.icon?.disabled, theme.icon?.secondary],
161
- ];
162
- for (const [label, a, b] of pairs) {
163
- if (!isHex(a) || !isHex(b))
164
- continue;
165
- if (a.trim().toLowerCase() === b.trim().toLowerCase()) {
166
- issues.push({
167
- path: label,
168
- message: `Tokens share the same hex (${a}). Keep roles distinct so disabled/muted states stay maintainable.`,
169
- });
170
- }
172
+ const issues = [];
173
+ const pairs = [["bg.disabled vs bg.muted", theme.bg?.disabled, theme.bg?.muted], ["text.disabled vs text.muted", theme.text?.disabled, theme.text?.muted], ["icon.disabled vs icon.secondary", theme.icon?.disabled, theme.icon?.secondary]];
174
+ for (const [label, a, b] of pairs) {
175
+ if (!isHex(a) || !isHex(b)) continue;
176
+ if (a.trim().toLowerCase() === b.trim().toLowerCase()) {
177
+ issues.push({
178
+ path: label,
179
+ message: `Tokens share the same hex (${a}). Keep roles distinct so disabled/muted states stay maintainable.`
180
+ });
181
+ }
182
+ }
183
+ if (theme.state) {
184
+ for (const key of ["hover", "press", "focus", "drag"]) {
185
+ const v = theme.state[key];
186
+ if (typeof v !== "number" || v < 0 || v > 1) {
187
+ issues.push({
188
+ path: `state.${key}`,
189
+ message: `State layer opacity must be in [0, 1] (got ${String(v)}).`
190
+ });
191
+ }
171
192
  }
172
- if (theme.state) {
173
- for (const key of ["hover", "press", "focus", "drag"]) {
174
- const v = theme.state[key];
175
- if (typeof v !== "number" || v < 0 || v > 1) {
176
- issues.push({
177
- path: `state.${key}`,
178
- message: `State layer opacity must be in [0, 1] (got ${String(v)}).`,
179
- });
180
- }
181
- }
193
+ }
194
+ if (theme.material) {
195
+ if (typeof theme.material.opacity === "number" && (theme.material.opacity < 0 || theme.material.opacity > 1)) {
196
+ issues.push({
197
+ path: "material.opacity",
198
+ message: `material.opacity must be in [0, 1] (got ${theme.material.opacity}).`
199
+ });
182
200
  }
183
- if (theme.material) {
184
- if (typeof theme.material.opacity === "number" &&
185
- (theme.material.opacity < 0 || theme.material.opacity > 1)) {
186
- issues.push({
187
- path: "material.opacity",
188
- message: `material.opacity must be in [0, 1] (got ${theme.material.opacity}).`,
189
- });
190
- }
191
- if (typeof theme.material.blur === "number" &&
192
- (!Number.isFinite(theme.material.blur) || theme.material.blur < 0)) {
193
- issues.push({
194
- path: "material.blur",
195
- message: `material.blur must be ≥ 0 (got ${theme.material.blur}).`,
196
- });
197
- }
201
+ if (typeof theme.material.blur === "number" && (!Number.isFinite(theme.material.blur) || theme.material.blur < 0)) {
202
+ issues.push({
203
+ path: "material.blur",
204
+ message: `material.blur must be ≥ 0 (got ${theme.material.blur}).`
205
+ });
198
206
  }
199
- return issues;
207
+ }
208
+ return issues;
200
209
  }
@@ -1,2 +1,2 @@
1
1
  export { motion } from "./motion.js";
2
- export { duration, easing, spring, } from "./motion.js";
2
+ export { duration, easing, spring } from "./motion.js";
@@ -2,24 +2,41 @@
2
2
  * Motion tokens — durations and curves for consistent animations (reanimated, LayoutAnimation).
3
3
  * Single source of the DS "rhythm": enter/exit, press, theme transitions, sheets, skeletons.
4
4
  */
5
+
5
6
  export const duration = {
6
- instant: 0,
7
- fast: 120,
8
- normal: 200,
9
- slow: 320,
10
- slower: 480,
7
+ instant: 0,
8
+ fast: 120,
9
+ normal: 200,
10
+ slow: 320,
11
+ slower: 480
11
12
  };
12
13
  /** Bezier curves (x1,y1,x2,y2) for Easing.bezier / CSS-like. */
13
14
  export const easing = {
14
- standard: [0.2, 0, 0, 1],
15
- decelerate: [0, 0, 0, 1],
16
- accelerate: [0.3, 0, 1, 1],
17
- emphasized: [0.2, 0, 0, 1],
15
+ standard: [0.2, 0, 0, 1],
16
+ decelerate: [0, 0, 0, 1],
17
+ accelerate: [0.3, 0, 1, 1],
18
+ emphasized: [0.2, 0, 0, 1]
18
19
  };
19
20
  /** Config for reanimated withSpring (spring presets). */
20
21
  export const spring = {
21
- default: { damping: 20, stiffness: 200, mass: 1 },
22
- gentle: { damping: 24, stiffness: 120, mass: 1 },
23
- snappy: { damping: 18, stiffness: 300, mass: 1 },
22
+ default: {
23
+ damping: 20,
24
+ stiffness: 200,
25
+ mass: 1
26
+ },
27
+ gentle: {
28
+ damping: 24,
29
+ stiffness: 120,
30
+ mass: 1
31
+ },
32
+ snappy: {
33
+ damping: 18,
34
+ stiffness: 300,
35
+ mass: 1
36
+ }
37
+ };
38
+ export const motion = {
39
+ duration,
40
+ easing,
41
+ spring
24
42
  };
25
- export const motion = { duration, easing, spring };
@@ -0,0 +1,14 @@
1
+ export type Attempt<T> = {
2
+ ok: true;
3
+ value: T;
4
+ } | {
5
+ ok: false;
6
+ error: unknown;
7
+ };
8
+ /**
9
+ * Runs `task` and reports how it ended instead of throwing. Component handlers use it
10
+ * so they need no `try/finally`: React Compiler skips any component whose body has one.
11
+ */
12
+ export declare function attempt<T>(task: () => T | Promise<T>): Promise<Attempt<T>>;
13
+ /** The error's own message when it has one, else the fallback shown to the user. */
14
+ export declare function errorMessage(cause: unknown, fallback: string): string;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Runs `task` and reports how it ended instead of throwing. Component handlers use it
3
+ * so they need no `try/finally`: React Compiler skips any component whose body has one.
4
+ */
5
+ export async function attempt(task) {
6
+ try {
7
+ return {
8
+ ok: true,
9
+ value: await task()
10
+ };
11
+ } catch (error) {
12
+ return {
13
+ ok: false,
14
+ error
15
+ };
16
+ }
17
+ }
18
+
19
+ /** The error's own message when it has one, else the fallback shown to the user. */
20
+ export function errorMessage(cause, fallback) {
21
+ return cause instanceof Error && cause.message.trim() ? cause.message : fallback;
22
+ }