@monimesl/dot-renderer-react 0.1.0-alpha.4 → 0.1.0-alpha.41

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 (267) hide show
  1. package/README.md +43 -1
  2. package/dist/LICENSE-PHOSPHOR +21 -0
  3. package/dist/_virtual/_rolldown/runtime.js +14 -0
  4. package/dist/_virtual/builtin_esm-external-require-react.js +9 -0
  5. package/dist/color.js +94 -0
  6. package/dist/components/amount-input.d.ts +6 -0
  7. package/dist/components/amount-input.js +111 -0
  8. package/dist/components/avatar.d.ts +6 -0
  9. package/dist/components/avatar.js +68 -0
  10. package/dist/components/box.js +56 -0
  11. package/dist/components/button.d.ts +6 -0
  12. package/dist/components/button.js +42 -0
  13. package/dist/components/carousel.d.ts +6 -0
  14. package/dist/components/carousel.js +258 -0
  15. package/dist/components/chip.d.ts +6 -0
  16. package/dist/components/chip.js +41 -0
  17. package/dist/components/code-input.d.ts +6 -0
  18. package/dist/components/code-input.js +96 -0
  19. package/dist/components/detail-row.d.ts +6 -0
  20. package/dist/components/detail-row.js +40 -0
  21. package/dist/components/disclosure.d.ts +6 -0
  22. package/dist/components/disclosure.js +76 -0
  23. package/dist/components/divider.d.ts +6 -0
  24. package/dist/components/divider.js +18 -0
  25. package/dist/components/empty-state.d.ts +6 -0
  26. package/dist/components/empty-state.js +64 -0
  27. package/dist/components/feedback.d.ts +8 -0
  28. package/dist/components/feedback.js +101 -0
  29. package/dist/components/field-box.js +44 -0
  30. package/dist/components/field.js +43 -0
  31. package/dist/components/footer.d.ts +6 -0
  32. package/dist/components/footer.js +25 -0
  33. package/dist/components/grid.d.ts +7 -0
  34. package/dist/components/grid.js +97 -0
  35. package/dist/components/https.js +11 -0
  36. package/dist/components/icon-artwork.js +143 -0
  37. package/dist/components/icon-button.js +28 -0
  38. package/dist/components/icon-svg.js +27 -0
  39. package/dist/components/icon.d.ts +6 -0
  40. package/dist/components/icon.js +25 -0
  41. package/dist/components/image.d.ts +6 -0
  42. package/dist/components/image.js +40 -0
  43. package/dist/components/index.d.ts +38 -0
  44. package/dist/components/index.js +92 -0
  45. package/dist/components/input.d.ts +6 -0
  46. package/dist/components/input.js +108 -0
  47. package/dist/components/link.d.ts +6 -0
  48. package/dist/components/link.js +32 -0
  49. package/dist/components/list.d.ts +7 -0
  50. package/dist/components/list.js +143 -0
  51. package/dist/components/numbers.js +9 -0
  52. package/dist/components/option-place.js +9 -0
  53. package/dist/components/option.d.ts +6 -0
  54. package/dist/components/option.js +44 -0
  55. package/dist/components/padding.d.ts +2 -0
  56. package/dist/components/padding.js +38 -0
  57. package/dist/components/pressable.js +17 -0
  58. package/dist/components/prose-context.js +5 -0
  59. package/dist/components/prose.d.ts +9 -0
  60. package/dist/components/prose.js +67 -0
  61. package/dist/components/qr-code.d.ts +6 -0
  62. package/dist/components/qr-code.js +58 -0
  63. package/dist/components/rich-text.d.ts +6 -0
  64. package/dist/components/rich-text.js +73 -0
  65. package/dist/components/scroll.d.ts +6 -0
  66. package/dist/components/scroll.js +57 -0
  67. package/dist/components/select.d.ts +6 -0
  68. package/dist/components/select.js +93 -0
  69. package/dist/components/sheet.d.ts +8 -0
  70. package/dist/components/sheet.js +106 -0
  71. package/dist/components/skeleton.d.ts +6 -0
  72. package/dist/components/skeleton.js +55 -0
  73. package/dist/components/slider.d.ts +6 -0
  74. package/dist/components/slider.js +57 -0
  75. package/dist/components/spinner.d.ts +6 -0
  76. package/dist/components/spinner.js +48 -0
  77. package/dist/components/stack.d.ts +6 -0
  78. package/dist/components/stack.js +25 -0
  79. package/dist/components/stepper.d.ts +6 -0
  80. package/dist/components/stepper.js +92 -0
  81. package/dist/components/steps.d.ts +7 -0
  82. package/dist/components/steps.js +110 -0
  83. package/dist/components/tabs.d.ts +7 -0
  84. package/dist/components/tabs.js +95 -0
  85. package/dist/components/text-area.d.ts +6 -0
  86. package/dist/components/text-area.js +42 -0
  87. package/dist/components/text.d.ts +6 -0
  88. package/dist/components/text.js +107 -0
  89. package/dist/components/toast.d.ts +6 -0
  90. package/dist/components/toast.js +56 -0
  91. package/dist/components/toggles.d.ts +9 -0
  92. package/dist/components/toggles.js +148 -0
  93. package/dist/components/tokens.js +49 -0
  94. package/dist/components/tones.js +30 -0
  95. package/dist/components/typed-text.js +28 -0
  96. package/dist/components/view.d.ts +6 -0
  97. package/dist/components/view.js +61 -0
  98. package/dist/index.d.ts +43 -48
  99. package/dist/index.js +40 -2086
  100. package/dist/markdown.js +255 -0
  101. package/dist/page-root.d.ts +2 -0
  102. package/dist/page-root.js +20 -0
  103. package/dist/portal.js +8 -0
  104. package/dist/pull-to-refresh.js +120 -0
  105. package/dist/react-host/19.3.0/react-dom.js +3 -0
  106. package/dist/react-host/19.3.0/react-host.js +6 -6
  107. package/dist/renderer.d.ts +17 -0
  108. package/dist/renderer.js +33 -0
  109. package/dist/root.d.ts +10 -0
  110. package/dist/root.js +71 -0
  111. package/dist/styles.css +1 -0
  112. package/dist/theme.d.ts +26 -0
  113. package/dist/theme.js +129 -0
  114. package/dist/types.d.ts +7 -0
  115. package/dist/vendor/@base-ui/react/checkbox/indicator/CheckboxIndicator.js +51 -0
  116. package/dist/vendor/@base-ui/react/checkbox/root/CheckboxRoot.js +265 -0
  117. package/dist/vendor/@base-ui/react/checkbox/root/CheckboxRootContext.js +13 -0
  118. package/dist/vendor/@base-ui/react/checkbox/root/CheckboxRootDataAttributes.js +11 -0
  119. package/dist/vendor/@base-ui/react/checkbox/utils/getCheckboxStateAttributesMapping.js +15 -0
  120. package/dist/vendor/@base-ui/react/checkbox-group/CheckboxGroupContext.js +10 -0
  121. package/dist/vendor/@base-ui/react/dialog/backdrop/DialogBackdrop.js +40 -0
  122. package/dist/vendor/@base-ui/react/dialog/close/DialogClose.js +39 -0
  123. package/dist/vendor/@base-ui/react/dialog/popup/DialogPopup.js +92 -0
  124. package/dist/vendor/@base-ui/react/dialog/popup/DialogPopupCssVars.js +8 -0
  125. package/dist/vendor/@base-ui/react/dialog/popup/DialogPopupDataAttributes.js +7 -0
  126. package/dist/vendor/@base-ui/react/dialog/portal/DialogPortal.js +38 -0
  127. package/dist/vendor/@base-ui/react/dialog/portal/DialogPortalContext.js +13 -0
  128. package/dist/vendor/@base-ui/react/dialog/root/DialogRoot.js +16 -0
  129. package/dist/vendor/@base-ui/react/dialog/root/DialogRootContext.js +13 -0
  130. package/dist/vendor/@base-ui/react/dialog/root/useDialogRoot.js +77 -0
  131. package/dist/vendor/@base-ui/react/dialog/root/useRenderDialogRoot.js +65 -0
  132. package/dist/vendor/@base-ui/react/dialog/store/DialogStore.js +70 -0
  133. package/dist/vendor/@base-ui/react/dialog/title/DialogTitle.js +25 -0
  134. package/dist/vendor/@base-ui/react/dialog/utils/stateAttributesMapping.js +17 -0
  135. package/dist/vendor/@base-ui/react/field/control/FieldControlDataAttributes.js +11 -0
  136. package/dist/vendor/@base-ui/react/field/item/FieldItemContext.js +10 -0
  137. package/dist/vendor/@base-ui/react/field/root/useFieldValidation.js +18 -0
  138. package/dist/vendor/@base-ui/react/fieldset/root/FieldsetRootContext.js +13 -0
  139. package/dist/vendor/@base-ui/react/floating-ui-react/components/FloatingFocusManager.js +477 -0
  140. package/dist/vendor/@base-ui/react/floating-ui-react/components/FloatingPortal.js +165 -0
  141. package/dist/vendor/@base-ui/react/floating-ui-react/components/FloatingRootStore.js +65 -0
  142. package/dist/vendor/@base-ui/react/floating-ui-react/components/FloatingTree.js +22 -0
  143. package/dist/vendor/@base-ui/react/floating-ui-react/hooks/useDismiss.js +373 -0
  144. package/dist/vendor/@base-ui/react/floating-ui-react/hooks/useSyncedFloatingRootContext.js +58 -0
  145. package/dist/vendor/@base-ui/react/floating-ui-react/utils/composite.js +40 -0
  146. package/dist/vendor/@base-ui/react/floating-ui-react/utils/constants.js +5 -0
  147. package/dist/vendor/@base-ui/react/floating-ui-react/utils/createAttribute.js +6 -0
  148. package/dist/vendor/@base-ui/react/floating-ui-react/utils/createEventEmitter.js +18 -0
  149. package/dist/vendor/@base-ui/react/floating-ui-react/utils/element.js +26 -0
  150. package/dist/vendor/@base-ui/react/floating-ui-react/utils/enqueueFocus.js +25 -0
  151. package/dist/vendor/@base-ui/react/floating-ui-react/utils/event.js +25 -0
  152. package/dist/vendor/@base-ui/react/floating-ui-react/utils/markOthers.js +116 -0
  153. package/dist/vendor/@base-ui/react/floating-ui-react/utils/nodes.js +16 -0
  154. package/dist/vendor/@base-ui/react/floating-ui-react/utils/tabbable.js +135 -0
  155. package/dist/vendor/@base-ui/react/internals/TransitionStatusDataAttributes.js +11 -0
  156. package/dist/vendor/@base-ui/react/internals/composite/composite.js +89 -0
  157. package/dist/vendor/@base-ui/react/internals/composite/constants.js +4 -0
  158. package/dist/vendor/@base-ui/react/internals/composite/item/CompositeItem.js +21 -0
  159. package/dist/vendor/@base-ui/react/internals/composite/item/useCompositeItem.js +31 -0
  160. package/dist/vendor/@base-ui/react/internals/composite/list/CompositeList.js +180 -0
  161. package/dist/vendor/@base-ui/react/internals/composite/list/CompositeListContext.js +15 -0
  162. package/dist/vendor/@base-ui/react/internals/composite/list/useCompositeListItem.js +54 -0
  163. package/dist/vendor/@base-ui/react/internals/composite/root/CompositeRoot.js +62 -0
  164. package/dist/vendor/@base-ui/react/internals/composite/root/CompositeRootContext.js +13 -0
  165. package/dist/vendor/@base-ui/react/internals/composite/root/useCompositeRoot.js +170 -0
  166. package/dist/vendor/@base-ui/react/internals/constants.js +18 -0
  167. package/dist/vendor/@base-ui/react/internals/createBaseUIEventDetails.js +40 -0
  168. package/dist/vendor/@base-ui/react/internals/direction-context/DirectionContext.js +10 -0
  169. package/dist/vendor/@base-ui/react/internals/field-constants/constants.js +33 -0
  170. package/dist/vendor/@base-ui/react/internals/field-register-control/useRegisterFieldControl.js +40 -0
  171. package/dist/vendor/@base-ui/react/internals/field-root-context/FieldRootContext.js +45 -0
  172. package/dist/vendor/@base-ui/react/internals/form-context/FormContext.js +18 -0
  173. package/dist/vendor/@base-ui/react/internals/getStateAttributesProps.js +17 -0
  174. package/dist/vendor/@base-ui/react/internals/labelable-provider/LabelableContext.js +24 -0
  175. package/dist/vendor/@base-ui/react/internals/labelable-provider/useAriaLabelledBy.js +35 -0
  176. package/dist/vendor/@base-ui/react/internals/labelable-provider/useLabelableId.js +57 -0
  177. package/dist/vendor/@base-ui/react/internals/reason-parts.js +14 -0
  178. package/dist/vendor/@base-ui/react/internals/serializeValue.js +12 -0
  179. package/dist/vendor/@base-ui/react/internals/stateAttributesMapping.js +11 -0
  180. package/dist/vendor/@base-ui/react/internals/use-button/useButton.js +137 -0
  181. package/dist/vendor/@base-ui/react/internals/useAnimationsFinished.js +94 -0
  182. package/dist/vendor/@base-ui/react/internals/useBaseUiId.js +13 -0
  183. package/dist/vendor/@base-ui/react/internals/useOpenChangeComplete.js +28 -0
  184. package/dist/vendor/@base-ui/react/internals/useRenderElement.js +109 -0
  185. package/dist/vendor/@base-ui/react/internals/useTransitionStatus.js +70 -0
  186. package/dist/vendor/@base-ui/react/internals/useValueChanged.js +15 -0
  187. package/dist/vendor/@base-ui/react/merge-props/mergeProps.js +153 -0
  188. package/dist/vendor/@base-ui/react/radio/indicator/RadioIndicator.js +46 -0
  189. package/dist/vendor/@base-ui/react/radio/root/RadioRoot.js +179 -0
  190. package/dist/vendor/@base-ui/react/radio/root/RadioRootContext.js +13 -0
  191. package/dist/vendor/@base-ui/react/radio/root/RadioRootDataAttributes.js +11 -0
  192. package/dist/vendor/@base-ui/react/radio/utils/stateAttributesMapping.js +14 -0
  193. package/dist/vendor/@base-ui/react/radio-group/RadioGroup.js +170 -0
  194. package/dist/vendor/@base-ui/react/radio-group/RadioGroupContext.js +10 -0
  195. package/dist/vendor/@base-ui/react/switch/root/SwitchRoot.js +170 -0
  196. package/dist/vendor/@base-ui/react/switch/root/SwitchRootContext.js +13 -0
  197. package/dist/vendor/@base-ui/react/switch/root/SwitchRootDataAttributes.js +11 -0
  198. package/dist/vendor/@base-ui/react/switch/stateAttributesMapping.js +12 -0
  199. package/dist/vendor/@base-ui/react/switch/thumb/SwitchThumb.js +25 -0
  200. package/dist/vendor/@base-ui/react/tabs/list/TabsList.js +98 -0
  201. package/dist/vendor/@base-ui/react/tabs/list/TabsListContext.js +13 -0
  202. package/dist/vendor/@base-ui/react/tabs/root/TabsRoot.js +213 -0
  203. package/dist/vendor/@base-ui/react/tabs/root/TabsRootContext.js +16 -0
  204. package/dist/vendor/@base-ui/react/tabs/root/TabsRootDataAttributes.js +8 -0
  205. package/dist/vendor/@base-ui/react/tabs/root/stateAttributesMapping.js +5 -0
  206. package/dist/vendor/@base-ui/react/tabs/tab/TabsTab.js +137 -0
  207. package/dist/vendor/@base-ui/react/utils/CommonPopupDataAttributes.js +24 -0
  208. package/dist/vendor/@base-ui/react/utils/CommonTriggerDataAttributes.js +11 -0
  209. package/dist/vendor/@base-ui/react/utils/FocusGuard.js +32 -0
  210. package/dist/vendor/@base-ui/react/utils/InternalBackdrop.js +30 -0
  211. package/dist/vendor/@base-ui/react/utils/dispatchClickWithModifiers.js +25 -0
  212. package/dist/vendor/@base-ui/react/utils/popupStateMapping.js +22 -0
  213. package/dist/vendor/@base-ui/react/utils/popups/popupStoreUtils.js +247 -0
  214. package/dist/vendor/@base-ui/react/utils/popups/popupTriggerMap.js +96 -0
  215. package/dist/vendor/@base-ui/react/utils/popups/store.js +94 -0
  216. package/dist/vendor/@base-ui/react/utils/resolveClassName.js +13 -0
  217. package/dist/vendor/@base-ui/react/utils/resolveRef.js +11 -0
  218. package/dist/vendor/@base-ui/react/utils/resolveStyle.js +13 -0
  219. package/dist/vendor/@base-ui/react/utils/useFocusableWhenDisabled.js +30 -0
  220. package/dist/vendor/@base-ui/utils/addEventListener.js +12 -0
  221. package/dist/vendor/@base-ui/utils/createLogOnce.js +20 -0
  222. package/dist/vendor/@base-ui/utils/empty.js +6 -0
  223. package/dist/vendor/@base-ui/utils/error.js +5 -0
  224. package/dist/vendor/@base-ui/utils/fastHooks.js +68 -0
  225. package/dist/vendor/@base-ui/utils/formatErrorMessage.js +27 -0
  226. package/dist/vendor/@base-ui/utils/getDefaultFormSubmitter.js +25 -0
  227. package/dist/vendor/@base-ui/utils/getReactElementRef.js +14 -0
  228. package/dist/vendor/@base-ui/utils/inertValue.js +8 -0
  229. package/dist/vendor/@base-ui/utils/isElementDisabled.js +6 -0
  230. package/dist/vendor/@base-ui/utils/mergeCleanups.js +14 -0
  231. package/dist/vendor/@base-ui/utils/mergeObjects.js +11 -0
  232. package/dist/vendor/@base-ui/utils/owner.js +7 -0
  233. package/dist/vendor/@base-ui/utils/platform/engine.js +8 -0
  234. package/dist/vendor/@base-ui/utils/platform/env.js +6 -0
  235. package/dist/vendor/@base-ui/utils/platform/os.js +15 -0
  236. package/dist/vendor/@base-ui/utils/platform/screen-reader.js +9 -0
  237. package/dist/vendor/@base-ui/utils/platform/shared.js +36 -0
  238. package/dist/vendor/@base-ui/utils/reactVersion.js +8 -0
  239. package/dist/vendor/@base-ui/utils/safeReact.js +13 -0
  240. package/dist/vendor/@base-ui/utils/shadowDom.js +26 -0
  241. package/dist/vendor/@base-ui/utils/store/ReactStore.js +181 -0
  242. package/dist/vendor/@base-ui/utils/store/Store.js +102 -0
  243. package/dist/vendor/@base-ui/utils/store/useStore.js +97 -0
  244. package/dist/vendor/@base-ui/utils/useAnimationFrame.js +87 -0
  245. package/dist/vendor/@base-ui/utils/useControlled.js +52 -0
  246. package/dist/vendor/@base-ui/utils/useId.js +32 -0
  247. package/dist/vendor/@base-ui/utils/useIsoLayoutEffect.js +7 -0
  248. package/dist/vendor/@base-ui/utils/useMergedRefs.js +87 -0
  249. package/dist/vendor/@base-ui/utils/useOnMount.js +12 -0
  250. package/dist/vendor/@base-ui/utils/useRefWithInit.js +18 -0
  251. package/dist/vendor/@base-ui/utils/useScrollLock.js +206 -0
  252. package/dist/vendor/@base-ui/utils/useStableCallback.js +38 -0
  253. package/dist/vendor/@base-ui/utils/useTimeout.js +43 -0
  254. package/dist/vendor/@base-ui/utils/useValueAsRef.js +27 -0
  255. package/dist/vendor/@base-ui/utils/visuallyHidden.js +23 -0
  256. package/dist/vendor/@base-ui/utils/warn.js +5 -0
  257. package/dist/vendor/@floating-ui/utils/dist/floating-ui.utils.dom.js +49 -0
  258. package/dist/vendor/uqr/dist/index.js +858 -0
  259. package/dist/vendor/use-sync-external-store/cjs/use-sync-external-store-shim/with-selector.development.js +74 -0
  260. package/dist/vendor/use-sync-external-store/cjs/use-sync-external-store-shim/with-selector.production.js +77 -0
  261. package/dist/vendor/use-sync-external-store/cjs/use-sync-external-store-shim.development.js +69 -0
  262. package/dist/vendor/use-sync-external-store/cjs/use-sync-external-store-shim.production.js +64 -0
  263. package/dist/vendor/use-sync-external-store/shim/index.js +11 -0
  264. package/dist/vendor/use-sync-external-store/shim/with-selector.js +11 -0
  265. package/package.json +14 -9
  266. package/dist/index.d.ts.map +0 -1
  267. package/dist/index.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,2089 +1,43 @@
1
- import { createEvent, toList, toText } from "@monimesl/dot-core";
2
- import { Children, Fragment, createContext, createElement, isValidElement, useContext, useEffect, useEffectEvent, useMemo, useRef, useState, useSyncExternalStore } from "react";
3
- import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
4
- import { ArrowDown, ArrowLeft, ArrowRight, ArrowUp, Banknote, Bell, Calendar, Check, ChevronDown, ChevronLeft, ChevronRight, ChevronUp, CircleAlert, CircleCheck, CircleHelp, Clock, Copy, CreditCard, Download, Droplet, Ellipsis, Eye, EyeOff, File, Gift, Heart, History, House, Image, Info, Landmark, LayoutGrid, List, Lock, LogOut, Mail, MapPin, Minus, Pencil, Phone, Plus, QrCode, Receipt, RefreshCw, Search, Send, Settings, Share2, ShoppingCart, Smartphone, Star, Trash2, TriangleAlert, Upload, User, Users, Wallet, Wifi, X, Zap } from "lucide";
5
- import { encode } from "uqr";
6
- import { createRoot } from "react-dom/client";
7
- //#region src/theme.ts
8
- const FONT_FAMILY = "system-ui, sans-serif";
9
- const DEFAULT_RADIUS = 12;
10
- const DEFAULT_COLORS = {
11
- light: {
12
- primary: "#1c1c1e",
13
- background: "#f2f2f2",
14
- surface: "#ffffff",
15
- text: "#111111",
16
- subtle: "#8e8e93",
17
- muted: "#e9e9eb",
18
- border: "#e9e9eb",
19
- info: "#0a64d6",
20
- success: "#1a8a4a",
21
- warning: "#b25e00",
22
- danger: "#d0312d"
23
- },
24
- dark: {
25
- primary: "#f5f5f5",
26
- background: "#121212",
27
- surface: "#1e1e1e",
28
- text: "#f5f5f5",
29
- subtle: "#8e8e93",
30
- muted: "#2c2c2e",
31
- border: "#2a2a2c",
32
- info: "#4c9dff",
33
- success: "#3ecf72",
34
- warning: "#ffb340",
35
- danger: "#ff6961"
36
- }
37
- };
38
- function resolveTheme(theme, systemScheme) {
39
- const scheme = !theme.scheme || theme.scheme === "system" ? systemScheme : theme.scheme;
40
- const defaults = DEFAULT_COLORS[scheme];
41
- const colors = theme.colors ?? {};
42
- const pick = (color, fallback) => color?.[scheme] ?? fallback;
43
- return {
44
- scheme,
45
- colors: {
46
- primary: pick(colors.primary, defaults.primary),
47
- background: pick(colors.background, defaults.background),
48
- surface: pick(colors.surface, defaults.surface),
49
- text: pick(colors.text, defaults.text),
50
- subtle: defaults.subtle,
51
- muted: defaults.muted,
52
- border: defaults.border,
53
- info: defaults.info,
54
- success: defaults.success,
55
- warning: defaults.warning,
56
- danger: defaults.danger
57
- },
58
- radius: theme.radius ?? DEFAULT_RADIUS
59
- };
60
- }
61
- const ThemeContext = createContext(resolveTheme({}, "light"));
62
- function useTheme() {
63
- return useContext(ThemeContext);
64
- }
65
- //#endregion
66
- //#region src/components/tokens.ts
67
- const SPACE = {
68
- none: 0,
69
- small: 4,
70
- medium: 8,
71
- large: 16
72
- };
73
- const FONT_SIZE = {
74
- caption: 13,
75
- body: 15,
76
- title: 20
77
- };
78
- const CARD_RADIUS_SCALE = 1.5;
79
- const DISABLED_OPACITY = .6;
80
- const ICON_SIZE = {
81
- small: 16,
82
- medium: 20,
83
- large: 28
84
- };
85
- //#endregion
86
- //#region src/components/field.tsx
87
- function Field({ label, hint, error, children }) {
88
- const { colors } = useTheme();
89
- const note = error || hint;
90
- return /* @__PURE__ */ jsxs("label", {
91
- className: "dot-field",
92
- style: {
93
- display: "flex",
94
- flexDirection: "column",
95
- gap: SPACE.small
96
- },
97
- children: [
98
- label ? /* @__PURE__ */ jsx(FieldLabel, { children: label }) : null,
99
- children,
100
- note ? /* @__PURE__ */ jsx("span", {
101
- style: {
102
- fontSize: FONT_SIZE.caption,
103
- color: error ? colors.danger : colors.subtle
104
- },
105
- children: note
106
- }) : null
107
- ]
108
- });
109
- }
110
- function FieldLabel({ children }) {
111
- return /* @__PURE__ */ jsx("span", {
112
- style: {
113
- fontSize: FONT_SIZE.caption,
114
- fontWeight: 500
115
- },
116
- children
117
- });
118
- }
119
- //#endregion
120
- //#region src/components/field-box.ts
121
- function useFieldBox(error, disabled) {
122
- const { colors, radius } = useTheme();
123
- const [focused, setFocused] = useState(false);
124
- let borderColor = colors.border;
125
- if (error) borderColor = colors.danger;
126
- else if (focused) borderColor = colors.primary;
127
- return {
128
- style: {
129
- border: `1px solid ${borderColor}`,
130
- borderRadius: radius,
131
- background: colors.surface,
132
- color: colors.text,
133
- fontSize: 16,
134
- opacity: disabled ? DISABLED_OPACITY : 1
135
- },
136
- onFocus: () => setFocused(true),
137
- onBlur: () => setFocused(false)
138
- };
139
- }
140
- //#endregion
141
- //#region src/components/typed-text.ts
142
- function useTypedText(value, sendsChanges, show = (text) => text) {
143
- const [text, setText] = useState(() => show(value ?? ""));
144
- const [awaitingEcho, setAwaitingEcho] = useState([]);
145
- const [previousValue, setPreviousValue] = useState(value);
146
- if (value !== previousValue) {
147
- setPreviousValue(value);
148
- const echo = awaitingEcho.indexOf(value ?? "");
149
- if (echo >= 0) setAwaitingEcho(awaitingEcho.slice(echo + 1));
150
- else {
151
- setAwaitingEcho([]);
152
- setText(show(value ?? ""));
153
- }
154
- }
155
- const type = (next, sent = next) => {
156
- setText(next);
157
- if (sendsChanges && value !== void 0) setAwaitingEcho([...awaitingEcho, sent]);
158
- };
159
- return [text, type];
160
- }
161
- //#endregion
162
- //#region src/components/amount-input.tsx
163
- const AMOUNT_FONT_SIZE = 28;
164
- const AmountInput = ({ value, currency, decimals = 0, label, placeholder = "0", hint, error, disabled, onChange }) => {
165
- const { colors } = useTheme();
166
- const places = Math.max(0, Math.round(decimals));
167
- const [text, typeText] = useTypedText(amountText(value), onChange !== void 0, (sent) => sent === "" ? "" : formatAmount(Number(sent), places));
168
- const box = useFieldBox(error, disabled);
169
- return /* @__PURE__ */ jsx(Field, {
170
- label,
171
- hint,
172
- error,
173
- children: /* @__PURE__ */ jsxs("span", {
174
- className: "dot-amount-input",
175
- style: {
176
- ...box.style,
177
- display: "flex",
178
- alignItems: "baseline",
179
- gap: SPACE.medium,
180
- padding: "10px 14px"
181
- },
182
- children: [currency ? /* @__PURE__ */ jsx("span", {
183
- style: {
184
- color: colors.subtle,
185
- fontSize: 20,
186
- fontWeight: 500
187
- },
188
- children: currency
189
- }) : null, /* @__PURE__ */ jsx("input", {
190
- value: text,
191
- placeholder,
192
- inputMode: places > 0 ? "decimal" : "numeric",
193
- disabled,
194
- "aria-invalid": error ? true : void 0,
195
- onFocus: box.onFocus,
196
- onBlur: box.onBlur,
197
- onChange: (event) => {
198
- const typed = cleanAmount(event.currentTarget.value, places);
199
- const amount = parseAmount(typed);
200
- typeText(typed, amount === null ? "" : String(amount));
201
- onChange?.(createEvent("change", { value: amount }));
202
- },
203
- style: {
204
- flexGrow: 1,
205
- minWidth: 0,
206
- padding: 0,
207
- border: "none",
208
- outline: "none",
209
- background: "transparent",
210
- color: "inherit",
211
- font: "inherit",
212
- fontSize: AMOUNT_FONT_SIZE,
213
- fontWeight: 600
214
- }
215
- })]
216
- })
217
- });
218
- };
219
- function amountText(value) {
220
- if (value === void 0) return;
221
- return Number.isFinite(value) ? String(value) : "";
222
- }
223
- function cleanAmount(typed, places) {
224
- const [whole = "", ...fractions] = typed.replace(/[^\d.]/g, "").split(".");
225
- const digits = whole.replace(/^0+/, "") || whole.slice(0, 1);
226
- if (places === 0 || fractions.length === 0) return groupThousands(digits);
227
- const fraction = fractions.join("").slice(0, places);
228
- return `${groupThousands(digits) || "0"}.${fraction}`;
229
- }
230
- function parseAmount(text) {
231
- const plain = text.replaceAll(",", "");
232
- return plain === "" ? null : Number(plain);
233
- }
234
- function formatAmount(amount, places) {
235
- const [whole = "", fraction] = Math.abs(amount).toFixed(places).split(".");
236
- const grouped = groupThousands(whole);
237
- return fraction === void 0 ? grouped : `${grouped}.${fraction}`;
238
- }
239
- function groupThousands(digits) {
240
- const groups = [];
241
- for (let end = digits.length; end > 0; end -= 3) groups.unshift(digits.slice(Math.max(0, end - 3), end));
242
- return groups.join(",");
243
- }
244
- //#endregion
245
- //#region src/components/spinner.tsx
246
- function LoadingIcon({ size }) {
247
- return /* @__PURE__ */ jsxs("svg", {
248
- className: "dot-spinner",
249
- width: size,
250
- height: size,
251
- viewBox: "0 0 24 24",
252
- fill: "none",
253
- stroke: "currentColor",
254
- strokeWidth: 3,
255
- role: "progressbar",
256
- "aria-label": "Loading",
257
- style: { flexShrink: 0 },
258
- children: [/* @__PURE__ */ jsx("circle", {
259
- cx: "12",
260
- cy: "12",
261
- r: "9",
262
- strokeOpacity: .25
263
- }), /* @__PURE__ */ jsx("path", {
264
- d: "M21 12a9 9 0 0 0-9-9",
265
- strokeLinecap: "round",
266
- children: /* @__PURE__ */ jsx("animateTransform", {
267
- attributeName: "transform",
268
- type: "rotate",
269
- from: "0 12 12",
270
- to: "360 12 12",
271
- dur: "0.8s",
272
- repeatCount: "indefinite"
273
- })
274
- })]
275
- });
276
- }
277
- const Spinner = ({ size = "medium" }) => {
278
- const { colors } = useTheme();
279
- return /* @__PURE__ */ jsx("span", {
280
- style: {
281
- display: "inline-flex",
282
- alignSelf: "center",
283
- color: colors.subtle
284
- },
285
- children: /* @__PURE__ */ jsx(LoadingIcon, { size: ICON_SIZE[size] })
286
- });
287
- };
288
- //#endregion
289
- //#region src/components/button.tsx
290
- const Button = ({ variant = "primary", disabled, loading, onClick, children }) => {
291
- const { colors, radius } = useTheme();
292
- const filled = variant === "primary" && !disabled;
293
- let color = colors.text;
294
- if (filled) color = colors.surface;
295
- else if (disabled) color = colors.subtle;
296
- return /* @__PURE__ */ jsxs("button", {
297
- type: "button",
298
- className: "dot-button",
299
- "data-variant": variant,
300
- disabled,
301
- "aria-busy": loading,
302
- onClick: onClick && !loading ? () => onClick(createEvent("click")) : void 0,
303
- style: {
304
- display: "inline-flex",
305
- alignItems: "center",
306
- justifyContent: "center",
307
- gap: SPACE.medium,
308
- minHeight: 48,
309
- padding: "12px 20px",
310
- border: "none",
311
- borderRadius: radius,
312
- background: filled ? colors.primary : colors.muted,
313
- color,
314
- font: "inherit",
315
- fontSize: FONT_SIZE.body,
316
- fontWeight: 600,
317
- opacity: disabled ? DISABLED_OPACITY : 1,
318
- cursor: disabled || loading ? "default" : "pointer"
319
- },
320
- children: [loading ? /* @__PURE__ */ jsx(LoadingIcon, { size: ICON_SIZE.small }) : null, children]
321
- });
322
- };
323
- //#endregion
324
- //#region src/components/carousel.tsx
325
- const SLIDE_DURATION = 350;
326
- const SLIDE_EASING = "cubic-bezier(0.22, 0.61, 0.36, 1)";
327
- const SWIPE_DISTANCE = .2;
328
- const SWIPE_SPEED = .4;
329
- const EDGE_RESISTANCE = .3;
330
- const TAP_SLOP = 6;
331
- const Carousel = ({ autoplay = false, interval = 4e3, loop = false, indicator = "dots", gap = "none", effect = "slide", index, onChange, children }) => {
332
- const { colors } = useTheme();
333
- const slides = slidesOf(children);
334
- const count = slides.length;
335
- const looping = loop && count > 1;
336
- const first = looping ? 1 : 0;
337
- const last = looping ? count + 1 : count - 1;
338
- const [position, setPosition] = useState(() => first + slideIndex(index ?? 0, count));
339
- const [animated, setAnimated] = useState(true);
340
- const [drag, setDrag] = useState(0);
341
- const [dragging, setDragging] = useState(false);
342
- const [width, setWidth] = useState(0);
343
- const [previousIndex, setPreviousIndex] = useState(index);
344
- const viewport = useRef(null);
345
- const gesture = useRef(null);
346
- const swiped = useRef(false);
347
- if (index !== previousIndex) {
348
- setPreviousIndex(index);
349
- if (index !== void 0) {
350
- setAnimated(true);
351
- setPosition(first + slideIndex(index, count));
352
- }
353
- }
354
- const shown = clamp(position, 0, last);
355
- const current = count === 0 ? 0 : wrap(shown - first, count);
356
- const moveTo = (target) => {
357
- const next = clamp(target, 0, last);
358
- setAnimated(true);
359
- setPosition(next);
360
- const nextIndex = wrap(next - first, count);
361
- if (nextIndex !== current) onChange?.(createEvent("change", { index: nextIndex }));
362
- };
363
- const step = (direction) => {
364
- const beyondEnd = current + direction < 0 || current + direction >= count;
365
- moveTo(!looping && beyondEnd ? shown : shown + direction);
366
- };
367
- const advance = useEffectEvent(() => {
368
- if (!looping && current === count - 1) moveTo(first);
369
- else moveTo(shown + 1);
370
- });
371
- useEffect(() => {
372
- if (!autoplay || count < 2 || dragging) return;
373
- const timer = setTimeout(advance, interval);
374
- return () => clearTimeout(timer);
375
- }, [
376
- autoplay,
377
- count,
378
- dragging,
379
- interval,
380
- current
381
- ]);
382
- useEffect(() => {
383
- if (!looping || position !== 0 && position !== count + 1) return;
384
- const timer = setTimeout(() => {
385
- setAnimated(false);
386
- setPosition(position === 0 ? count : 1);
387
- }, SLIDE_DURATION);
388
- return () => clearTimeout(timer);
389
- }, [
390
- looping,
391
- position,
392
- count
393
- ]);
394
- const gestureOf = (event) => {
395
- const touch = gesture.current;
396
- return touch?.pointerId === event.pointerId ? touch : null;
397
- };
398
- const endGesture = () => {
399
- gesture.current = null;
400
- setDragging(false);
401
- setDrag(0);
402
- setAnimated(true);
403
- };
404
- const onPointerDown = (event) => {
405
- if (count < 2 || !event.isPrimary) return;
406
- gesture.current = {
407
- pointerId: event.pointerId,
408
- startX: event.clientX,
409
- startY: event.clientY,
410
- startTime: event.timeStamp,
411
- swiping: false
412
- };
413
- swiped.current = false;
414
- setDragging(true);
415
- setWidth(viewport.current?.clientWidth ?? 0);
416
- };
417
- const onPointerMove = (event) => {
418
- const touch = gestureOf(event);
419
- if (!touch) return;
420
- const dx = event.clientX - touch.startX;
421
- const dy = event.clientY - touch.startY;
422
- if (!touch.swiping) {
423
- if (Math.abs(dx) < TAP_SLOP && Math.abs(dy) < TAP_SLOP) return;
424
- if (Math.abs(dy) > Math.abs(dx)) {
425
- endGesture();
426
- return;
427
- }
428
- touch.swiping = true;
429
- swiped.current = true;
430
- event.currentTarget.setPointerCapture?.(event.pointerId);
431
- setAnimated(false);
432
- }
433
- const pastEnd = !looping && (current === 0 && dx > 0 || current === count - 1 && dx < 0);
434
- setDrag(pastEnd ? dx * EDGE_RESISTANCE : dx);
435
- };
436
- const onPointerUp = (event) => {
437
- const touch = gestureOf(event);
438
- if (!touch) return;
439
- endGesture();
440
- if (!touch.swiping) return;
441
- const dx = event.clientX - touch.startX;
442
- const speed = Math.abs(dx) / Math.max(1, event.timeStamp - touch.startTime);
443
- if (Math.abs(dx) > width * SWIPE_DISTANCE || speed > SWIPE_SPEED) step(dx < 0 ? 1 : -1);
444
- else moveTo(shown);
445
- };
446
- const gapWidth = SPACE[gap];
447
- const transition = animated ? `transform ${SLIDE_DURATION}ms ${SLIDE_EASING}` : "none";
448
- const swipedSlides = width > 0 ? drag / (width + gapWidth) : 0;
449
- const track = looping ? [
450
- {
451
- ...slides[count - 1],
452
- key: "copy-of-last"
453
- },
454
- ...slides,
455
- {
456
- ...slides[0],
457
- key: "copy-of-first"
458
- }
459
- ] : slides;
460
- return /* @__PURE__ */ jsxs("div", {
461
- className: "dot-carousel",
462
- role: "region",
463
- "aria-roledescription": "carousel",
464
- style: {
465
- display: "flex",
466
- flexDirection: "column",
467
- gap: SPACE.medium,
468
- minWidth: 0
469
- },
470
- children: [/* @__PURE__ */ jsx("div", {
471
- ref: viewport,
472
- onPointerDown,
473
- onPointerMove,
474
- onPointerUp,
475
- onPointerCancel: endGesture,
476
- onDragStart: (event) => event.preventDefault(),
477
- onClickCapture: (event) => {
478
- if (swiped.current) {
479
- swiped.current = false;
480
- event.stopPropagation();
481
- }
482
- },
483
- style: {
484
- overflow: "hidden",
485
- touchAction: "pan-y",
486
- userSelect: dragging ? "none" : void 0
487
- },
488
- children: /* @__PURE__ */ jsx("div", {
489
- style: {
490
- display: "flex",
491
- gap: gapWidth,
492
- transform: `translateX(calc(${-shown} * (100% + ${gapWidth}px) + ${drag}px))`,
493
- transition
494
- },
495
- children: track.map((slide, trackPosition) => {
496
- const visible = trackPosition === shown;
497
- const distance = Math.abs(trackPosition - shown + swipedSlides);
498
- const scale = 1 - Math.min(distance, 1) * .15000000000000002;
499
- return /* @__PURE__ */ jsx("div", {
500
- role: "group",
501
- "aria-roledescription": "slide",
502
- "aria-label": `${wrap(trackPosition - first, count) + 1} of ${count}`,
503
- "aria-hidden": !visible,
504
- inert: !visible,
505
- style: {
506
- display: "grid",
507
- flex: "0 0 100%",
508
- minWidth: 0,
509
- transform: effect === "scale" ? `scale(${scale})` : void 0,
510
- transition: effect === "scale" ? transition : void 0
511
- },
512
- children: slide.node
513
- }, slide.key);
514
- })
515
- })
516
- }), indicator === "dots" && count > 1 ? /* @__PURE__ */ jsx("div", {
517
- style: {
518
- display: "flex",
519
- justifyContent: "center"
520
- },
521
- children: slides.map((slide, slideIndex) => {
522
- const active = slideIndex === current;
523
- return /* @__PURE__ */ jsx("button", {
524
- type: "button",
525
- "aria-label": `Slide ${slideIndex + 1} of ${count}`,
526
- "aria-current": active,
527
- onClick: () => moveTo(first + slideIndex),
528
- style: {
529
- padding: "6px 3px",
530
- border: "none",
531
- background: "none",
532
- cursor: "pointer"
533
- },
534
- children: /* @__PURE__ */ jsx("span", { style: {
535
- display: "block",
536
- width: active ? 18 : 6,
537
- height: 6,
538
- borderRadius: 3,
539
- background: active ? colors.primary : colors.subtle,
540
- transition: "width 0.3s, background 0.3s"
541
- } })
542
- }, slide.key);
543
- })
544
- }) : null]
545
- });
546
- };
547
- function slidesOf(children, keyPrefix = "") {
548
- const slides = [];
549
- for (const child of Children.toArray(children)) {
550
- if (!isValidElement(child)) continue;
551
- const key = `${keyPrefix}${String(child.key)}`;
552
- if (child.type === Fragment) slides.push(...slidesOf(child.props.children, `${key}/`));
553
- else slides.push({
554
- key,
555
- node: child
556
- });
557
- }
558
- return slides;
559
- }
560
- function clamp(value, min, max) {
561
- return Math.max(min, Math.min(value, max));
562
- }
563
- function slideIndex(index, count) {
564
- return clamp(Math.round(index), 0, count - 1);
565
- }
566
- function wrap(value, count) {
567
- return (value % count + count) % count;
568
- }
569
- //#endregion
570
- //#region src/components/tones.ts
571
- const STATUS_ICONS = {
572
- default: "info",
573
- info: "info",
574
- success: "success",
575
- warning: "warning",
576
- danger: "error"
577
- };
578
- function toneColor(colors, tone) {
579
- switch (tone) {
580
- case "default": return colors.text;
581
- case "muted": return colors.subtle;
582
- default: return colors[tone];
583
- }
584
- }
585
- function toneBackground(colors, tone) {
586
- if (tone === "default" || tone === "muted") return colors.muted;
587
- return withOpacity(colors[tone], .14);
588
- }
589
- function withOpacity(color, opacity) {
590
- return `${color}${Math.round(opacity * 255).toString(16).padStart(2, "0")}`;
591
- }
592
- //#endregion
593
- //#region src/components/icon.tsx
594
- const ICONS = {
595
- "arrow-down": ArrowDown,
596
- "arrow-left": ArrowLeft,
597
- "arrow-right": ArrowRight,
598
- "arrow-up": ArrowUp,
599
- bank: Landmark,
600
- bell: Bell,
601
- bolt: Zap,
602
- calendar: Calendar,
603
- card: CreditCard,
604
- cart: ShoppingCart,
605
- cash: Banknote,
606
- check: Check,
607
- "chevron-down": ChevronDown,
608
- "chevron-left": ChevronLeft,
609
- "chevron-right": ChevronRight,
610
- "chevron-up": ChevronUp,
611
- clock: Clock,
612
- close: X,
613
- copy: Copy,
614
- download: Download,
615
- edit: Pencil,
616
- error: CircleAlert,
617
- eye: Eye,
618
- "eye-off": EyeOff,
619
- file: File,
620
- gift: Gift,
621
- grid: LayoutGrid,
622
- heart: Heart,
623
- help: CircleHelp,
624
- history: History,
625
- home: House,
626
- image: Image,
627
- info: Info,
628
- list: List,
629
- location: MapPin,
630
- lock: Lock,
631
- logout: LogOut,
632
- mail: Mail,
633
- minus: Minus,
634
- mobile: Smartphone,
635
- more: Ellipsis,
636
- phone: Phone,
637
- plus: Plus,
638
- "qr-code": QrCode,
639
- receipt: Receipt,
640
- refresh: RefreshCw,
641
- search: Search,
642
- send: Send,
643
- settings: Settings,
644
- share: Share2,
645
- star: Star,
646
- success: CircleCheck,
647
- trash: Trash2,
648
- upload: Upload,
649
- user: User,
650
- users: Users,
651
- wallet: Wallet,
652
- warning: TriangleAlert,
653
- water: Droplet,
654
- wifi: Wifi
655
- };
656
- function IconGraphic({ name, size, color }) {
657
- return /* @__PURE__ */ jsx("svg", {
658
- className: "dot-icon",
659
- width: size,
660
- height: size,
661
- viewBox: "0 0 24 24",
662
- fill: "none",
663
- stroke: color,
664
- strokeWidth: 2,
665
- strokeLinecap: "round",
666
- strokeLinejoin: "round",
667
- "aria-hidden": "true",
668
- style: {
669
- display: "inline-block",
670
- verticalAlign: "middle",
671
- flexShrink: 0
672
- },
673
- children: ICONS[name].map(([tag, attributes], index) => createElement(tag, {
674
- key: index,
675
- ...attributes
676
- }))
677
- });
678
- }
679
- const Icon = ({ name, size = "medium", tone = "default" }) => {
680
- const { colors } = useTheme();
681
- if (!name) return null;
682
- return /* @__PURE__ */ jsx(IconGraphic, {
683
- name,
684
- size: ICON_SIZE[size],
685
- color: toneColor(colors, tone)
686
- });
687
- };
688
- //#endregion
689
- //#region src/components/chip.tsx
690
- const Chip = ({ label, icon, selected = false, disabled, onTap }) => {
691
- const { colors } = useTheme();
692
- const color = selected ? colors.surface : colors.text;
693
- return /* @__PURE__ */ jsxs("button", {
694
- type: "button",
695
- className: "dot-chip",
696
- "aria-pressed": selected,
697
- disabled,
698
- onClick: onTap ? () => onTap(createEvent("tap")) : void 0,
699
- style: {
700
- display: "inline-flex",
701
- alignItems: "center",
702
- gap: 6,
703
- flexShrink: 0,
704
- minHeight: 34,
705
- padding: "0 14px",
706
- borderRadius: 17,
707
- border: `1px solid ${selected ? colors.primary : colors.border}`,
708
- background: selected ? colors.primary : colors.surface,
709
- color,
710
- font: "inherit",
711
- fontSize: FONT_SIZE.caption,
712
- fontWeight: 500,
713
- whiteSpace: "nowrap",
714
- opacity: disabled ? DISABLED_OPACITY : 1,
715
- cursor: disabled ? "default" : "pointer"
716
- },
717
- children: [icon ? /* @__PURE__ */ jsx(IconGraphic, {
718
- name: icon,
719
- size: ICON_SIZE.small,
720
- color
721
- }) : null, label]
722
- });
723
- };
724
- //#endregion
725
- //#region src/components/code-input.tsx
726
- const CodeInput = ({ value, length = 6, label, hint, error, secure, disabled, onChange, onComplete }) => {
727
- const { colors, radius } = useTheme();
728
- const [text, typeText] = useTypedText(value, onChange !== void 0);
729
- const [focused, setFocused] = useState(false);
730
- const count = Math.max(1, Math.round(length));
731
- const digits = text.slice(0, count);
732
- const next = Math.min(digits.length, count - 1);
733
- const boxes = Array.from({ length: count }, (_, index) => {
734
- const digit = digits[index];
735
- let borderColor = colors.border;
736
- if (error) borderColor = colors.danger;
737
- else if (focused && index === next) borderColor = colors.primary;
738
- return /* @__PURE__ */ jsx("span", {
739
- style: {
740
- display: "flex",
741
- alignItems: "center",
742
- justifyContent: "center",
743
- flex: "1 1 0",
744
- maxWidth: 52,
745
- height: 52,
746
- border: `1.5px solid ${borderColor}`,
747
- borderRadius: radius,
748
- background: colors.surface,
749
- fontSize: 22,
750
- fontWeight: 600
751
- },
752
- children: digit !== void 0 && secure ? /* @__PURE__ */ jsx("span", {
753
- "aria-hidden": "true",
754
- style: {
755
- width: 12,
756
- height: 12,
757
- borderRadius: "50%",
758
- background: colors.text
759
- }
760
- }) : digit
761
- }, index);
762
- });
763
- return /* @__PURE__ */ jsx(Field, {
764
- label,
765
- hint,
766
- error,
767
- children: /* @__PURE__ */ jsxs("span", {
768
- className: "dot-code-input",
769
- style: {
770
- position: "relative",
771
- display: "flex",
772
- gap: SPACE.medium,
773
- color: colors.text,
774
- opacity: disabled ? DISABLED_OPACITY : 1
775
- },
776
- children: [boxes, /* @__PURE__ */ jsx("input", {
777
- value: digits,
778
- inputMode: "numeric",
779
- autoComplete: "one-time-code",
780
- maxLength: count,
781
- disabled,
782
- "aria-invalid": error ? true : void 0,
783
- onFocus: () => setFocused(true),
784
- onBlur: () => setFocused(false),
785
- onSelect: (event) => {
786
- const input = event.currentTarget;
787
- const end = input.value.length;
788
- if (input.selectionStart !== end || input.selectionEnd !== end) input.setSelectionRange(end, end);
789
- },
790
- onChange: (event) => {
791
- const typed = event.currentTarget.value.replace(/\D/g, "").slice(0, count);
792
- if (typed === digits) return;
793
- typeText(typed);
794
- onChange?.(createEvent("change", { value: typed }));
795
- if (typed.length === count) onComplete?.(createEvent("complete", { value: typed }));
796
- },
797
- style: {
798
- position: "absolute",
799
- inset: 0,
800
- width: "100%",
801
- height: "100%",
802
- padding: 0,
803
- border: "none",
804
- opacity: 0,
805
- fontSize: 16,
806
- cursor: disabled ? "default" : "text"
807
- }
808
- })]
809
- })
810
- });
811
- };
812
- //#endregion
813
- //#region src/components/divider.tsx
814
- const Divider = () => {
815
- const { colors } = useTheme();
816
- return /* @__PURE__ */ jsx("div", {
817
- className: "dot-divider",
818
- role: "separator",
819
- style: {
820
- height: 1,
821
- alignSelf: "stretch",
822
- flexShrink: 0,
823
- background: colors.border
824
- }
825
- });
826
- };
827
- //#endregion
828
- //#region src/components/empty-state.tsx
829
- const EmptyState = ({ icon, title, text, children }) => {
830
- const { colors } = useTheme();
831
- return /* @__PURE__ */ jsxs("div", {
832
- className: "dot-empty-state",
833
- style: {
834
- display: "flex",
835
- flexDirection: "column",
836
- alignItems: "center",
837
- gap: SPACE.medium,
838
- padding: "32px 16px",
839
- textAlign: "center",
840
- color: colors.text
841
- },
842
- children: [
843
- icon ? /* @__PURE__ */ jsx("span", {
844
- style: {
845
- display: "flex",
846
- alignItems: "center",
847
- justifyContent: "center",
848
- width: 64,
849
- height: 64,
850
- borderRadius: "50%",
851
- background: colors.muted
852
- },
853
- children: /* @__PURE__ */ jsx(IconGraphic, {
854
- name: icon,
855
- size: ICON_SIZE.large,
856
- color: colors.subtle
857
- })
858
- }) : null,
859
- title ? /* @__PURE__ */ jsx("span", {
860
- style: {
861
- fontSize: 17,
862
- fontWeight: 600
863
- },
864
- children: title
865
- }) : null,
866
- text ? /* @__PURE__ */ jsx("span", {
867
- style: {
868
- maxWidth: 300,
869
- fontSize: FONT_SIZE.body,
870
- color: colors.subtle
871
- },
872
- children: text
873
- }) : null,
874
- children ? /* @__PURE__ */ jsx("div", {
875
- style: {
876
- display: "flex",
877
- gap: SPACE.medium,
878
- paddingTop: SPACE.small
879
- },
880
- children
881
- }) : null
882
- ]
883
- });
884
- };
885
- //#endregion
886
- //#region src/components/feedback.tsx
887
- const ProgressBar = ({ value = 0 }) => {
888
- const { colors } = useTheme();
889
- const percent = Math.min(100, Math.max(0, value));
890
- return /* @__PURE__ */ jsx("div", {
891
- className: "dot-progress-bar",
892
- role: "progressbar",
893
- "aria-valuemin": 0,
894
- "aria-valuemax": 100,
895
- "aria-valuenow": percent,
896
- style: {
897
- height: 6,
898
- borderRadius: 3,
899
- background: colors.muted,
900
- overflow: "hidden"
901
- },
902
- children: /* @__PURE__ */ jsx("div", { style: {
903
- width: `${percent}%`,
904
- height: "100%",
905
- background: colors.primary,
906
- transition: "width 0.2s"
907
- } })
908
- });
909
- };
910
- const Notice = ({ tone = "default", title, children }) => {
911
- const { colors, radius } = useTheme();
912
- return /* @__PURE__ */ jsxs("div", {
913
- className: "dot-notice",
914
- role: tone === "danger" ? "alert" : "status",
915
- style: {
916
- display: "flex",
917
- gap: SPACE.medium,
918
- padding: "12px 14px",
919
- borderRadius: radius,
920
- background: toneBackground(colors, tone),
921
- color: colors.text,
922
- fontSize: FONT_SIZE.body
923
- },
924
- children: [/* @__PURE__ */ jsx(IconGraphic, {
925
- name: STATUS_ICONS[tone],
926
- size: ICON_SIZE.medium,
927
- color: toneColor(colors, tone)
928
- }), /* @__PURE__ */ jsxs("div", {
929
- style: {
930
- display: "flex",
931
- flexDirection: "column",
932
- gap: 2
933
- },
934
- children: [title ? /* @__PURE__ */ jsx("span", {
935
- style: { fontWeight: 600 },
936
- children: title
937
- }) : null, children ? /* @__PURE__ */ jsx("span", { children }) : null]
938
- })]
939
- });
940
- };
941
- const Badge = ({ tone = "default", children }) => {
942
- const { colors } = useTheme();
943
- return /* @__PURE__ */ jsx("span", {
944
- className: "dot-badge",
945
- style: {
946
- display: "inline-flex",
947
- alignItems: "center",
948
- width: "fit-content",
949
- padding: "2px 8px",
950
- borderRadius: 999,
951
- background: toneBackground(colors, tone),
952
- color: toneColor(colors, tone),
953
- fontSize: FONT_SIZE.caption,
954
- fontWeight: 600,
955
- whiteSpace: "nowrap"
956
- },
957
- children
958
- });
959
- };
960
- //#endregion
961
- //#region src/components/footer.tsx
962
- const Footer = ({ children }) => {
963
- const { colors } = useTheme();
964
- return /* @__PURE__ */ jsx("div", {
965
- className: "dot-footer",
966
- style: {
967
- position: "sticky",
968
- bottom: 0,
969
- marginTop: "auto",
970
- display: "flex",
971
- flexDirection: "column",
972
- gap: SPACE.medium,
973
- paddingTop: SPACE.medium,
974
- paddingBottom: SPACE.medium,
975
- background: colors.background
976
- },
977
- children
978
- });
979
- };
980
- //#endregion
981
- //#region src/components/pill.tsx
982
- function Pill({ background, color, children }) {
983
- return /* @__PURE__ */ jsx("span", {
984
- style: {
985
- minWidth: 18,
986
- padding: "1px 6px",
987
- borderRadius: 9,
988
- background,
989
- color,
990
- fontSize: 11,
991
- fontWeight: 600,
992
- lineHeight: "16px",
993
- textAlign: "center",
994
- whiteSpace: "nowrap"
995
- },
996
- children
997
- });
998
- }
999
- //#endregion
1000
- //#region src/components/grid.tsx
1001
- const TILE_SIZE = 52;
1002
- const Grid = ({ columns = 4, gap = "medium", children }) => /* @__PURE__ */ jsx("div", {
1003
- className: "dot-grid",
1004
- style: {
1005
- display: "grid",
1006
- gridTemplateColumns: `repeat(${Math.max(1, Math.round(columns))}, minmax(0, 1fr))`,
1007
- gap: SPACE[gap]
1008
- },
1009
- children
1010
- });
1011
- const GridItem = ({ label, icon, image, badge, onTap }) => {
1012
- const { colors, radius } = useTheme();
1013
- const tileRadius = radius * CARD_RADIUS_SCALE;
1014
- let picture = null;
1015
- if (image) picture = /* @__PURE__ */ jsx("img", {
1016
- src: image,
1017
- alt: "",
1018
- width: TILE_SIZE,
1019
- height: TILE_SIZE,
1020
- style: {
1021
- display: "block",
1022
- borderRadius: tileRadius,
1023
- objectFit: "cover"
1024
- }
1025
- });
1026
- else if (icon) picture = /* @__PURE__ */ jsx(IconGraphic, {
1027
- name: icon,
1028
- size: 24,
1029
- color: colors.primary
1030
- });
1031
- return /* @__PURE__ */ jsxs("div", {
1032
- className: "dot-grid-item",
1033
- role: onTap ? "button" : void 0,
1034
- onClick: onTap ? () => onTap(createEvent("tap")) : void 0,
1035
- style: {
1036
- display: "flex",
1037
- flexDirection: "column",
1038
- alignItems: "center",
1039
- gap: 6,
1040
- padding: `${SPACE.small}px 0`,
1041
- cursor: onTap ? "pointer" : void 0
1042
- },
1043
- children: [/* @__PURE__ */ jsxs("span", {
1044
- style: {
1045
- position: "relative",
1046
- display: "flex",
1047
- alignItems: "center",
1048
- justifyContent: "center",
1049
- width: TILE_SIZE,
1050
- height: TILE_SIZE,
1051
- borderRadius: tileRadius,
1052
- background: colors.muted
1053
- },
1054
- children: [picture, badge ? /* @__PURE__ */ jsx("span", {
1055
- style: {
1056
- position: "absolute",
1057
- top: -6,
1058
- right: -10
1059
- },
1060
- children: /* @__PURE__ */ jsx(Pill, {
1061
- background: colors.danger,
1062
- color: "#ffffff",
1063
- children: badge
1064
- })
1065
- }) : null]
1066
- }), label ? /* @__PURE__ */ jsx("span", {
1067
- style: {
1068
- display: "-webkit-box",
1069
- WebkitLineClamp: 2,
1070
- WebkitBoxOrient: "vertical",
1071
- overflow: "hidden",
1072
- width: "100%",
1073
- textAlign: "center",
1074
- fontSize: FONT_SIZE.caption,
1075
- color: colors.text
1076
- },
1077
- children: label
1078
- }) : null]
1079
- });
1080
- };
1081
- //#endregion
1082
- //#region src/components/image.tsx
1083
- const Image$1 = ({ src, alt, width, height, fit = "cover", shape = "rounded", onLoad, onError }) => {
1084
- const { radius } = useTheme();
1085
- const corners = {
1086
- rounded: radius,
1087
- square: 0,
1088
- circle: "50%"
1089
- }[shape];
1090
- return /* @__PURE__ */ jsx("img", {
1091
- className: "dot-image",
1092
- src,
1093
- alt: alt ?? "",
1094
- width,
1095
- height,
1096
- style: {
1097
- borderRadius: corners,
1098
- objectFit: fit
1099
- },
1100
- onLoad: onLoad ? (event) => {
1101
- const { naturalWidth, naturalHeight } = event.currentTarget;
1102
- onLoad(createEvent("load", {
1103
- width: naturalWidth,
1104
- height: naturalHeight
1105
- }));
1106
- } : void 0,
1107
- onError: onError ? () => onError(createEvent("error", { message: `Failed to load ${src}` })) : void 0
1108
- });
1109
- };
1110
- //#endregion
1111
- //#region src/components/input.tsx
1112
- const HTML_TYPES = {
1113
- text: {
1114
- type: "text",
1115
- inputMode: "text"
1116
- },
1117
- number: {
1118
- type: "text",
1119
- inputMode: "decimal"
1120
- },
1121
- email: {
1122
- type: "email",
1123
- inputMode: "email"
1124
- },
1125
- phone: {
1126
- type: "tel",
1127
- inputMode: "tel"
1128
- },
1129
- password: {
1130
- type: "password",
1131
- inputMode: "text"
1132
- }
1133
- };
1134
- const Input = ({ value, placeholder, label, hint, error, prefix, suffix, type = "text", maxLength, disabled, onChange, onSubmit }) => {
1135
- const { colors } = useTheme();
1136
- const [text, typeText] = useTypedText(value, onChange !== void 0);
1137
- const box = useFieldBox(error, disabled);
1138
- return /* @__PURE__ */ jsx(Field, {
1139
- label,
1140
- hint,
1141
- error,
1142
- children: /* @__PURE__ */ jsxs("span", {
1143
- className: "dot-input",
1144
- style: {
1145
- ...box.style,
1146
- display: "flex",
1147
- alignItems: "center",
1148
- gap: SPACE.medium,
1149
- padding: "0 14px"
1150
- },
1151
- children: [
1152
- prefix ? /* @__PURE__ */ jsx("span", {
1153
- style: { color: colors.subtle },
1154
- children: prefix
1155
- }) : null,
1156
- /* @__PURE__ */ jsx("input", {
1157
- ...HTML_TYPES[type],
1158
- value: text,
1159
- placeholder,
1160
- maxLength,
1161
- disabled,
1162
- "aria-invalid": error ? true : void 0,
1163
- onFocus: box.onFocus,
1164
- onBlur: box.onBlur,
1165
- onChange: (event) => {
1166
- const next = event.currentTarget.value;
1167
- typeText(next);
1168
- onChange?.(createEvent("change", { value: next }));
1169
- },
1170
- onKeyDown: (event) => {
1171
- if (event.key === "Enter" && onSubmit) onSubmit(createEvent("submit", { value: text }));
1172
- },
1173
- style: {
1174
- flexGrow: 1,
1175
- minWidth: 0,
1176
- padding: "12px 0",
1177
- border: "none",
1178
- outline: "none",
1179
- background: "transparent",
1180
- color: "inherit",
1181
- font: "inherit"
1182
- }
1183
- }),
1184
- suffix ? /* @__PURE__ */ jsx("span", {
1185
- style: { color: colors.subtle },
1186
- children: suffix
1187
- }) : null
1188
- ]
1189
- })
1190
- });
1191
- };
1192
- //#endregion
1193
- //#region src/components/list.tsx
1194
- const List$1 = ({ children }) => {
1195
- const { colors, radius } = useTheme();
1196
- return /* @__PURE__ */ jsx("div", {
1197
- className: "dot-list",
1198
- style: {
1199
- display: "flex",
1200
- flexDirection: "column",
1201
- gap: 1,
1202
- overflow: "hidden",
1203
- borderRadius: radius * CARD_RADIUS_SCALE,
1204
- border: `1px solid ${colors.border}`,
1205
- background: colors.border
1206
- },
1207
- children
1208
- });
1209
- };
1210
- const ListItem = ({ title, subtitle, value, icon, image, onTap, children }) => {
1211
- const { colors, radius } = useTheme();
1212
- let leading = null;
1213
- if (image) leading = /* @__PURE__ */ jsx("img", {
1214
- src: image,
1215
- alt: "",
1216
- width: 40,
1217
- height: 40,
1218
- style: {
1219
- borderRadius: radius,
1220
- objectFit: "cover",
1221
- flexShrink: 0
1222
- }
1223
- });
1224
- else if (icon) leading = /* @__PURE__ */ jsx("span", {
1225
- style: {
1226
- display: "flex",
1227
- alignItems: "center",
1228
- justifyContent: "center",
1229
- width: 36,
1230
- height: 36,
1231
- borderRadius: "50%",
1232
- background: colors.muted,
1233
- flexShrink: 0
1234
- },
1235
- children: /* @__PURE__ */ jsx(IconGraphic, {
1236
- name: icon,
1237
- size: ICON_SIZE.medium,
1238
- color: colors.text
1239
- })
1240
- });
1241
- let trailing = children;
1242
- if (!trailing && value) trailing = /* @__PURE__ */ jsx("span", {
1243
- style: { color: colors.subtle },
1244
- children: value
1245
- });
1246
- return /* @__PURE__ */ jsxs("div", {
1247
- className: "dot-list-item",
1248
- role: onTap ? "button" : void 0,
1249
- onClick: onTap ? () => onTap(createEvent("tap")) : void 0,
1250
- style: {
1251
- display: "flex",
1252
- alignItems: "center",
1253
- gap: 12,
1254
- padding: "12px 16px",
1255
- background: colors.surface,
1256
- fontSize: FONT_SIZE.body,
1257
- cursor: onTap ? "pointer" : void 0
1258
- },
1259
- children: [
1260
- leading,
1261
- /* @__PURE__ */ jsxs("span", {
1262
- style: {
1263
- display: "flex",
1264
- flexDirection: "column",
1265
- flexGrow: 1,
1266
- minWidth: 0
1267
- },
1268
- children: [title ? /* @__PURE__ */ jsx("span", {
1269
- style: { fontWeight: 500 },
1270
- children: title
1271
- }) : null, subtitle ? /* @__PURE__ */ jsx("span", {
1272
- style: {
1273
- fontSize: FONT_SIZE.caption,
1274
- color: colors.subtle
1275
- },
1276
- children: subtitle
1277
- }) : null]
1278
- }),
1279
- trailing ? /* @__PURE__ */ jsx("span", {
1280
- style: {
1281
- display: "flex",
1282
- alignItems: "center",
1283
- gap: SPACE.small,
1284
- flexShrink: 0
1285
- },
1286
- children: trailing
1287
- }) : null,
1288
- onTap ? /* @__PURE__ */ jsx(IconGraphic, {
1289
- name: "chevron-right",
1290
- size: ICON_SIZE.small,
1291
- color: colors.subtle
1292
- }) : null
1293
- ]
1294
- });
1295
- };
1296
- //#endregion
1297
- //#region src/components/qr-code.tsx
1298
- const DARK = "#000000";
1299
- const LIGHT = "#ffffff";
1300
- const QUIET_ZONE = 2;
1301
- const QRCode = ({ value, size = 200, label }) => {
1302
- const { radius } = useTheme();
1303
- const drawing = useMemo(() => value ? drawCode(value) : null, [value]);
1304
- return /* @__PURE__ */ jsx("svg", {
1305
- className: "dot-qr-code",
1306
- role: "img",
1307
- "aria-label": label ?? value,
1308
- width: size,
1309
- height: size,
1310
- viewBox: drawing ? `0 0 ${drawing.size} ${drawing.size}` : "0 0 1 1",
1311
- shapeRendering: "crispEdges",
1312
- style: {
1313
- display: "block",
1314
- flexShrink: 0,
1315
- borderRadius: radius,
1316
- background: LIGHT
1317
- },
1318
- children: drawing ? /* @__PURE__ */ jsx("path", {
1319
- d: drawing.path,
1320
- fill: DARK
1321
- }) : null
1322
- });
1323
- };
1324
- function drawCode(value) {
1325
- let modules;
1326
- try {
1327
- modules = encode(value, {
1328
- ecc: "M",
1329
- border: QUIET_ZONE
1330
- }).data;
1331
- } catch {
1332
- return null;
1333
- }
1334
- const squares = [];
1335
- modules.forEach((row, y) => {
1336
- row.forEach((dark, x) => {
1337
- if (dark) squares.push(`M${x} ${y}h1v1h-1z`);
1338
- });
1339
- });
1340
- return {
1341
- size: modules.length,
1342
- path: squares.join("")
1343
- };
1344
- }
1345
- //#endregion
1346
- //#region src/components/animate.ts
1347
- function animate(element, keyframes, options) {
1348
- if (!element || typeof element.animate !== "function") return;
1349
- return element.animate(keyframes, options);
1350
- }
1351
- //#endregion
1352
- //#region src/components/sheet.tsx
1353
- const SLIDE_UP = [{ transform: "translateY(100%)" }, { transform: "translateY(0)" }];
1354
- function SheetPanel({ open, title, onClose, children }) {
1355
- const { colors, radius } = useTheme();
1356
- const panel = useRef(null);
1357
- useEffect(() => {
1358
- if (open) animate(panel.current, SLIDE_UP, {
1359
- duration: 200,
1360
- easing: "ease-out"
1361
- });
1362
- }, [open]);
1363
- if (!open) return null;
1364
- const corner = radius * CARD_RADIUS_SCALE;
1365
- return /* @__PURE__ */ jsx("div", {
1366
- className: "dot-sheet",
1367
- onClick: onClose,
1368
- style: {
1369
- position: "fixed",
1370
- inset: 0,
1371
- zIndex: 100,
1372
- display: "flex",
1373
- flexDirection: "column",
1374
- justifyContent: "flex-end",
1375
- background: "rgba(0, 0, 0, 0.4)"
1376
- },
1377
- children: /* @__PURE__ */ jsxs("div", {
1378
- ref: panel,
1379
- role: "dialog",
1380
- "aria-modal": "true",
1381
- "aria-label": title,
1382
- onClick: (event) => event.stopPropagation(),
1383
- style: {
1384
- display: "flex",
1385
- flexDirection: "column",
1386
- gap: SPACE.medium,
1387
- maxHeight: "85vh",
1388
- overflowY: "auto",
1389
- padding: `${SPACE.large}px ${SPACE.large}px 24px`,
1390
- borderTopLeftRadius: corner,
1391
- borderTopRightRadius: corner,
1392
- background: colors.surface,
1393
- color: colors.text
1394
- },
1395
- children: [title ? /* @__PURE__ */ jsx("span", {
1396
- style: {
1397
- fontSize: FONT_SIZE.body,
1398
- fontWeight: 600,
1399
- textAlign: "center"
1400
- },
1401
- children: title
1402
- }) : null, children]
1403
- })
1404
- });
1405
- }
1406
- const Sheet = ({ open = false, title, onClose, children }) => /* @__PURE__ */ jsx(SheetPanel, {
1407
- open,
1408
- title,
1409
- onClose: () => onClose?.(createEvent("close")),
1410
- children
1411
- });
1412
- //#endregion
1413
- //#region src/components/select.tsx
1414
- const OptionPlaceContext = createContext({
1415
- inField: false,
1416
- value: void 0,
1417
- choose: void 0
1418
- });
1419
- const Select = ({ value, label, placeholder, hint, error, disabled, onChange, children }) => {
1420
- const { colors } = useTheme();
1421
- const [open, setOpen] = useState(false);
1422
- const box = useFieldBox(error, disabled);
1423
- const choose = (next) => {
1424
- setOpen(false);
1425
- onChange?.(createEvent("change", { value: next }));
1426
- };
1427
- return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Field, {
1428
- label,
1429
- hint,
1430
- error,
1431
- children: /* @__PURE__ */ jsxs("button", {
1432
- type: "button",
1433
- className: "dot-select",
1434
- disabled,
1435
- onClick: () => setOpen(true),
1436
- onFocus: box.onFocus,
1437
- onBlur: box.onBlur,
1438
- style: {
1439
- font: "inherit",
1440
- ...box.style,
1441
- display: "flex",
1442
- alignItems: "center",
1443
- gap: SPACE.medium,
1444
- width: "100%",
1445
- padding: "12px 14px",
1446
- textAlign: "start",
1447
- cursor: disabled ? "default" : "pointer"
1448
- },
1449
- children: [/* @__PURE__ */ jsx("span", {
1450
- style: { flexGrow: 1 },
1451
- children: value ? /* @__PURE__ */ jsx(OptionPlaceContext.Provider, {
1452
- value: {
1453
- inField: true,
1454
- value,
1455
- choose: void 0
1456
- },
1457
- children
1458
- }) : /* @__PURE__ */ jsx("span", {
1459
- style: { color: colors.subtle },
1460
- children: placeholder
1461
- })
1462
- }), /* @__PURE__ */ jsx(IconGraphic, {
1463
- name: "chevron-down",
1464
- size: ICON_SIZE.small,
1465
- color: colors.subtle
1466
- })]
1467
- })
1468
- }), /* @__PURE__ */ jsx(SheetPanel, {
1469
- open,
1470
- title: label,
1471
- onClose: () => setOpen(false),
1472
- children: /* @__PURE__ */ jsx("div", {
1473
- role: "listbox",
1474
- style: {
1475
- display: "flex",
1476
- flexDirection: "column"
1477
- },
1478
- children: /* @__PURE__ */ jsx(OptionPlaceContext.Provider, {
1479
- value: {
1480
- inField: false,
1481
- value,
1482
- choose
1483
- },
1484
- children
1485
- })
1486
- })
1487
- })] });
1488
- };
1489
- const Option = ({ value, label }) => {
1490
- const { colors } = useTheme();
1491
- const place = useContext(OptionPlaceContext);
1492
- const chosen = value !== void 0 && value === place.value;
1493
- if (place.inField) return chosen ? /* @__PURE__ */ jsx(Fragment$1, { children: label }) : null;
1494
- const { choose } = place;
1495
- return /* @__PURE__ */ jsxs("button", {
1496
- type: "button",
1497
- className: "dot-option",
1498
- role: "option",
1499
- "aria-selected": chosen,
1500
- onClick: choose && value !== void 0 ? () => choose(value) : void 0,
1501
- style: {
1502
- display: "flex",
1503
- alignItems: "center",
1504
- justifyContent: "space-between",
1505
- padding: "14px 4px",
1506
- border: "none",
1507
- borderBottom: `1px solid ${colors.border}`,
1508
- background: "transparent",
1509
- color: colors.text,
1510
- font: "inherit",
1511
- fontSize: FONT_SIZE.body,
1512
- fontWeight: chosen ? 600 : 400,
1513
- textAlign: "start",
1514
- cursor: "pointer"
1515
- },
1516
- children: [/* @__PURE__ */ jsx("span", { children: label }), chosen ? /* @__PURE__ */ jsx(IconGraphic, {
1517
- name: "check",
1518
- size: ICON_SIZE.medium,
1519
- color: colors.primary
1520
- }) : null]
1521
- });
1522
- };
1523
- //#endregion
1524
- //#region src/components/skeleton.tsx
1525
- const PULSE = [
1526
- { opacity: 1 },
1527
- { opacity: .4 },
1528
- { opacity: 1 }
1529
- ];
1530
- const LINE_HEIGHT = 12;
1531
- const Skeleton = ({ shape = "text", lines = 1, height }) => {
1532
- const { colors, radius } = useTheme();
1533
- const placeholder = useRef(null);
1534
- useEffect(() => {
1535
- const pulse = animate(placeholder.current, PULSE, {
1536
- duration: 1200,
1537
- iterations: Infinity
1538
- });
1539
- return () => pulse?.cancel();
1540
- }, []);
1541
- let content;
1542
- if (shape === "circle") {
1543
- const size = height ?? 40;
1544
- content = /* @__PURE__ */ jsx("div", { style: {
1545
- width: size,
1546
- height: size,
1547
- borderRadius: "50%",
1548
- background: colors.muted
1549
- } });
1550
- } else if (shape === "box") content = /* @__PURE__ */ jsx("div", { style: {
1551
- height: height ?? 80,
1552
- borderRadius: radius,
1553
- background: colors.muted
1554
- } });
1555
- else {
1556
- const count = Math.max(1, lines);
1557
- content = Array.from({ length: count }, (_, index) => {
1558
- const last = count > 1 && index === count - 1;
1559
- return /* @__PURE__ */ jsx("div", { style: {
1560
- width: last ? "60%" : "100%",
1561
- height: LINE_HEIGHT,
1562
- borderRadius: LINE_HEIGHT / 2,
1563
- background: colors.muted
1564
- } }, index);
1565
- });
1566
- }
1567
- return /* @__PURE__ */ jsx("div", {
1568
- ref: placeholder,
1569
- className: "dot-skeleton",
1570
- "aria-busy": "true",
1571
- style: {
1572
- display: "flex",
1573
- flexDirection: "column",
1574
- gap: SPACE.medium,
1575
- width: shape === "circle" ? void 0 : "100%",
1576
- flexShrink: shape === "circle" ? 0 : 1
1577
- },
1578
- children: content
1579
- });
1580
- };
1581
- //#endregion
1582
- //#region src/components/tabs.tsx
1583
- const TabsContext = createContext({
1584
- value: void 0,
1585
- segmented: false,
1586
- choose: void 0
1587
- });
1588
- const Tabs = ({ value, variant = "underline", onChange, children }) => {
1589
- const { colors, radius } = useTheme();
1590
- const segmented = variant === "segmented";
1591
- const choose = onChange ? (next) => {
1592
- if (next !== value) onChange(createEvent("change", { value: next }));
1593
- } : void 0;
1594
- return /* @__PURE__ */ jsx("div", {
1595
- className: "dot-tabs",
1596
- role: "tablist",
1597
- style: {
1598
- display: "flex",
1599
- overflowX: "auto",
1600
- ...segmented ? {
1601
- gap: 2,
1602
- padding: 3,
1603
- borderRadius: radius,
1604
- background: colors.muted
1605
- } : { borderBottom: `1px solid ${colors.border}` }
1606
- },
1607
- children: /* @__PURE__ */ jsx(TabsContext.Provider, {
1608
- value: {
1609
- value,
1610
- segmented,
1611
- choose
1612
- },
1613
- children
1614
- })
1615
- });
1616
- };
1617
- const Tab = ({ value, label, badge }) => {
1618
- const { colors, radius } = useTheme();
1619
- const { value: chosen, segmented, choose } = useContext(TabsContext);
1620
- const selected = value !== void 0 && value === chosen;
1621
- let color = colors.subtle;
1622
- if (selected) color = segmented ? colors.text : colors.primary;
1623
- return /* @__PURE__ */ jsxs("button", {
1624
- type: "button",
1625
- role: "tab",
1626
- "aria-selected": selected,
1627
- onClick: choose && value !== void 0 ? () => choose(value) : void 0,
1628
- style: {
1629
- display: "flex",
1630
- alignItems: "center",
1631
- justifyContent: "center",
1632
- gap: 6,
1633
- flex: "1 0 auto",
1634
- minHeight: segmented ? 36 : 44,
1635
- padding: "0 12px",
1636
- border: "none",
1637
- font: "inherit",
1638
- fontSize: FONT_SIZE.body,
1639
- fontWeight: selected ? 600 : 500,
1640
- whiteSpace: "nowrap",
1641
- color,
1642
- cursor: "pointer",
1643
- ...segmented ? {
1644
- borderRadius: radius - 2,
1645
- background: selected ? colors.surface : "transparent",
1646
- boxShadow: selected ? "0 1px 3px rgba(0, 0, 0, 0.15)" : "none"
1647
- } : {
1648
- marginBottom: -1,
1649
- background: "transparent",
1650
- borderBottom: `2px solid ${selected ? colors.primary : "transparent"}`
1651
- }
1652
- },
1653
- children: [label, badge ? /* @__PURE__ */ jsx(Pill, {
1654
- background: colors.primary,
1655
- color: colors.surface,
1656
- children: badge
1657
- }) : null]
1658
- });
1659
- };
1660
- //#endregion
1661
- //#region src/components/text.tsx
1662
- const VARIANTS = {
1663
- body: { fontSize: FONT_SIZE.body },
1664
- caption: { fontSize: FONT_SIZE.caption },
1665
- title: {
1666
- fontSize: FONT_SIZE.title,
1667
- fontWeight: 600
1668
- }
1669
- };
1670
- const WEIGHTS = {
1671
- regular: 400,
1672
- medium: 500,
1673
- bold: 600
1674
- };
1675
- const Text = ({ variant = "body", tone, weight, align, maxLines, children }) => {
1676
- const { colors } = useTheme();
1677
- const style = {
1678
- ...VARIANTS[variant],
1679
- textAlign: align
1680
- };
1681
- if (tone) style.color = toneColor(colors, tone);
1682
- if (weight) style.fontWeight = WEIGHTS[weight];
1683
- if (maxLines) Object.assign(style, {
1684
- display: "-webkit-box",
1685
- WebkitLineClamp: maxLines,
1686
- WebkitBoxOrient: "vertical",
1687
- overflow: "hidden"
1688
- });
1689
- return /* @__PURE__ */ jsx("span", {
1690
- className: "dot-text",
1691
- style,
1692
- children
1693
- });
1694
- };
1695
- //#endregion
1696
- //#region src/components/text-area.tsx
1697
- const TextArea = ({ value, placeholder, label, hint, error, rows = 3, maxLength, disabled, onChange }) => {
1698
- const [text, typeText] = useTypedText(value, onChange !== void 0);
1699
- const box = useFieldBox(error, disabled);
1700
- return /* @__PURE__ */ jsx(Field, {
1701
- label,
1702
- hint,
1703
- error,
1704
- children: /* @__PURE__ */ jsx("textarea", {
1705
- className: "dot-text-area",
1706
- value: text,
1707
- placeholder,
1708
- rows,
1709
- maxLength,
1710
- disabled,
1711
- "aria-invalid": error ? true : void 0,
1712
- onFocus: box.onFocus,
1713
- onBlur: box.onBlur,
1714
- onChange: (event) => {
1715
- const next = event.currentTarget.value;
1716
- typeText(next);
1717
- onChange?.(createEvent("change", { value: next }));
1718
- },
1719
- style: {
1720
- font: "inherit",
1721
- ...box.style,
1722
- boxSizing: "border-box",
1723
- width: "100%",
1724
- padding: "12px 14px",
1725
- outline: "none",
1726
- resize: "none"
1727
- }
1728
- })
1729
- });
1730
- };
1731
- //#endregion
1732
- //#region src/components/toast.tsx
1733
- const Toast = ({ message, tone = "default", duration = 2500, onHide }) => {
1734
- const { colors, radius } = useTheme();
1735
- const [hidden, setHidden] = useState(false);
1736
- const [previousMessage, setPreviousMessage] = useState(message);
1737
- if (message !== previousMessage) {
1738
- setPreviousMessage(message);
1739
- setHidden(false);
1740
- }
1741
- const hide = useEffectEvent(() => {
1742
- setHidden(true);
1743
- onHide?.(createEvent("hide"));
1744
- });
1745
- useEffect(() => {
1746
- if (!message) return;
1747
- const timer = setTimeout(hide, duration);
1748
- return () => clearTimeout(timer);
1749
- }, [message, duration]);
1750
- if (!message || hidden) return null;
1751
- return /* @__PURE__ */ jsxs("div", {
1752
- className: "dot-toast",
1753
- role: "status",
1754
- style: {
1755
- position: "fixed",
1756
- top: SPACE.large,
1757
- left: "50%",
1758
- transform: "translateX(-50%)",
1759
- zIndex: 110,
1760
- display: "flex",
1761
- alignItems: "center",
1762
- gap: SPACE.medium,
1763
- maxWidth: "calc(100% - 32px)",
1764
- width: "max-content",
1765
- padding: "10px 16px",
1766
- borderRadius: radius,
1767
- background: colors.primary,
1768
- color: colors.surface,
1769
- fontSize: FONT_SIZE.body,
1770
- boxShadow: "0 4px 16px rgba(0, 0, 0, 0.2)"
1771
- },
1772
- children: [tone === "default" ? null : /* @__PURE__ */ jsx(IconGraphic, {
1773
- name: STATUS_ICONS[tone],
1774
- size: ICON_SIZE.medium,
1775
- color: toneColor(colors, tone)
1776
- }), /* @__PURE__ */ jsx("span", { children: message })]
1777
- });
1778
- };
1779
- //#endregion
1780
- //#region src/components/toggles.tsx
1781
- function rowStyle(colors, disabled) {
1782
- return {
1783
- display: "flex",
1784
- alignItems: "center",
1785
- gap: 12,
1786
- width: "100%",
1787
- padding: "6px 0",
1788
- border: "none",
1789
- background: "transparent",
1790
- color: colors.text,
1791
- font: "inherit",
1792
- fontSize: FONT_SIZE.body,
1793
- textAlign: "start",
1794
- opacity: disabled ? DISABLED_OPACITY : 1,
1795
- cursor: disabled ? "default" : "pointer"
1796
- };
1797
- }
1798
- function changeTo(checked, onChange) {
1799
- return onChange ? () => onChange(createEvent("change", { checked })) : void 0;
1800
- }
1801
- function ChoiceMark({ round, checked, children }) {
1802
- const { colors } = useTheme();
1803
- const filled = checked && !round;
1804
- return /* @__PURE__ */ jsx("span", {
1805
- style: {
1806
- display: "flex",
1807
- alignItems: "center",
1808
- justifyContent: "center",
1809
- flexShrink: 0,
1810
- width: 22,
1811
- height: 22,
1812
- boxSizing: "border-box",
1813
- borderRadius: round ? "50%" : 6,
1814
- border: `2px solid ${checked ? colors.primary : colors.subtle}`,
1815
- background: filled ? colors.primary : "transparent"
1816
- },
1817
- children
1818
- });
1819
- }
1820
- const Switch = ({ checked = false, label, disabled, onChange }) => {
1821
- const { colors } = useTheme();
1822
- return /* @__PURE__ */ jsxs("button", {
1823
- type: "button",
1824
- className: "dot-switch",
1825
- role: "switch",
1826
- "aria-checked": checked,
1827
- disabled,
1828
- onClick: changeTo(!checked, onChange),
1829
- style: {
1830
- ...rowStyle(colors, disabled),
1831
- justifyContent: "space-between"
1832
- },
1833
- children: [label ? /* @__PURE__ */ jsx("span", { children: label }) : null, /* @__PURE__ */ jsx("span", {
1834
- style: {
1835
- position: "relative",
1836
- flexShrink: 0,
1837
- width: 44,
1838
- height: 26,
1839
- borderRadius: 13,
1840
- background: checked ? colors.primary : colors.subtle,
1841
- transition: "background 0.2s"
1842
- },
1843
- children: /* @__PURE__ */ jsx("span", { style: {
1844
- position: "absolute",
1845
- top: 2,
1846
- left: checked ? 20 : 2,
1847
- width: 22,
1848
- height: 22,
1849
- borderRadius: "50%",
1850
- background: colors.surface,
1851
- transition: "left 0.2s"
1852
- } })
1853
- })]
1854
- });
1855
- };
1856
- const Checkbox = ({ checked = false, label, disabled, onChange }) => {
1857
- const { colors } = useTheme();
1858
- return /* @__PURE__ */ jsxs("button", {
1859
- type: "button",
1860
- className: "dot-checkbox",
1861
- role: "checkbox",
1862
- "aria-checked": checked,
1863
- disabled,
1864
- onClick: changeTo(!checked, onChange),
1865
- style: rowStyle(colors, disabled),
1866
- children: [/* @__PURE__ */ jsx(ChoiceMark, {
1867
- round: false,
1868
- checked,
1869
- children: checked ? /* @__PURE__ */ jsx(IconGraphic, {
1870
- name: "check",
1871
- size: ICON_SIZE.small,
1872
- color: colors.surface
1873
- }) : null
1874
- }), label ? /* @__PURE__ */ jsx("span", { children: label }) : null]
1875
- });
1876
- };
1877
- const RadioGroupContext = createContext({
1878
- value: void 0,
1879
- disabled: true,
1880
- choose: void 0
1881
- });
1882
- const RadioGroup = ({ value, label, disabled = false, onChange, children }) => {
1883
- const choose = onChange ? (next) => onChange(createEvent("change", { value: next })) : void 0;
1884
- return /* @__PURE__ */ jsxs("div", {
1885
- className: "dot-radio-group",
1886
- role: "radiogroup",
1887
- "aria-label": label,
1888
- style: {
1889
- display: "flex",
1890
- flexDirection: "column",
1891
- gap: SPACE.small
1892
- },
1893
- children: [label ? /* @__PURE__ */ jsx(FieldLabel, { children: label }) : null, /* @__PURE__ */ jsx(RadioGroupContext.Provider, {
1894
- value: {
1895
- value,
1896
- disabled,
1897
- choose
1898
- },
1899
- children
1900
- })]
1901
- });
1902
- };
1903
- const Radio = ({ value, label, disabled }) => {
1904
- const { colors } = useTheme();
1905
- const group = useContext(RadioGroupContext);
1906
- const selected = value !== void 0 && value === group.value;
1907
- const inactive = disabled || group.disabled;
1908
- const { choose } = group;
1909
- return /* @__PURE__ */ jsxs("button", {
1910
- type: "button",
1911
- className: "dot-radio",
1912
- role: "radio",
1913
- "aria-checked": selected,
1914
- disabled: inactive,
1915
- onClick: choose && value !== void 0 ? () => choose(value) : void 0,
1916
- style: rowStyle(colors, inactive),
1917
- children: [/* @__PURE__ */ jsx(ChoiceMark, {
1918
- round: true,
1919
- checked: selected,
1920
- children: selected ? /* @__PURE__ */ jsx("span", { style: {
1921
- width: 10,
1922
- height: 10,
1923
- borderRadius: "50%",
1924
- background: colors.primary
1925
- } }) : null
1926
- }), label ? /* @__PURE__ */ jsx("span", { children: label }) : null]
1927
- });
1928
- };
1929
- //#endregion
1930
- //#region src/components/view.tsx
1931
- const ALIGN = {
1932
- stretch: "stretch",
1933
- start: "flex-start",
1934
- center: "center",
1935
- end: "flex-end"
1936
- };
1937
- const JUSTIFY = {
1938
- start: "flex-start",
1939
- center: "center",
1940
- end: "flex-end",
1941
- between: "space-between"
1942
- };
1943
- const View = ({ direction = "column", gap = "medium", align = "stretch", justify = "start", wrap = false, grow = false, padding, paddingTop, paddingStart, paddingEnd, paddingBottom, variant = "plain", onTap, children }) => {
1944
- const { colors, radius } = useTheme();
1945
- const card = variant === "card";
1946
- const allSides = padding ?? (card ? "large" : "none");
1947
- return /* @__PURE__ */ jsx("div", {
1948
- className: "dot-view",
1949
- onClick: onTap ? () => onTap(createEvent("tap")) : void 0,
1950
- style: {
1951
- display: "flex",
1952
- flexDirection: direction,
1953
- gap: SPACE[gap],
1954
- alignItems: ALIGN[align],
1955
- justifyContent: JUSTIFY[justify],
1956
- flexWrap: wrap ? "wrap" : void 0,
1957
- flexGrow: grow ? 1 : void 0,
1958
- minWidth: grow ? 0 : void 0,
1959
- paddingTop: SPACE[paddingTop ?? allSides],
1960
- paddingInlineStart: SPACE[paddingStart ?? allSides],
1961
- paddingInlineEnd: SPACE[paddingEnd ?? allSides],
1962
- paddingBottom: SPACE[paddingBottom ?? allSides],
1963
- borderRadius: card ? radius * CARD_RADIUS_SCALE : void 0,
1964
- background: card ? colors.surface : void 0,
1965
- border: card ? `1px solid ${colors.border}` : void 0,
1966
- cursor: onTap ? "pointer" : void 0
1967
- },
1968
- children
1969
- });
1970
- };
1971
- //#endregion
1972
- //#region src/components/index.ts
1973
- const builtins = {
1974
- AmountInput,
1975
- Badge,
1976
- Button,
1977
- Carousel,
1978
- Checkbox,
1979
- Chip,
1980
- CodeInput,
1981
- Divider,
1982
- EmptyState,
1983
- Footer,
1984
- Grid,
1985
- GridItem,
1986
- Icon,
1987
- Image: Image$1,
1988
- Input,
1989
- List: List$1,
1990
- ListItem,
1991
- Notice,
1992
- Option,
1993
- ProgressBar,
1994
- QRCode,
1995
- Radio,
1996
- RadioGroup,
1997
- Select,
1998
- Sheet,
1999
- Skeleton,
2000
- Spinner,
2001
- Switch,
2002
- Tab,
2003
- Tabs,
2004
- Text,
2005
- TextArea,
2006
- Toast,
2007
- View
2008
- };
2009
- //#endregion
2010
- //#region src/page-root.tsx
2011
- function PageRoot({ page, components }) {
2012
- const state = useSyncExternalStore(page.subscribe, page.getState);
2013
- const context = useMemo(() => ({
2014
- h(type, props, ...children) {
2015
- const component = components[type];
2016
- if (!component) throw new Error(`The renderer has no component registered for tag '<${type}>'`);
2017
- return createElement(component, props, ...children);
2018
- },
2019
- text: toText,
2020
- on: (handler, data) => page.on(handler, data),
2021
- each: (items, render, key) => createElement(Fragment, null, toList(items).map((item, index) => createElement(Fragment, { key: key ? String(key(item, index)) : index }, ...render(item, index))))
2022
- }), [page, components]);
2023
- if (!state) return null;
2024
- return page.viewRenderer(state, context);
2025
- }
2026
- //#endregion
2027
- //#region src/root.tsx
2028
- function Root({ page, dotContext, components, wrapper: Wrapper }) {
2029
- const theme = useSyncExternalStore(dotContext.theme.subscribe, dotContext.theme.get);
2030
- const systemContext = useSyncExternalStore(dotContext.systemContext.subscribe, dotContext.systemContext.get);
2031
- const resolved = useMemo(() => resolveTheme(theme, systemContext.scheme), [theme, systemContext.scheme]);
2032
- const content = /* @__PURE__ */ jsx(PageRoot, {
2033
- page,
2034
- components
2035
- });
2036
- return /* @__PURE__ */ jsx(ThemeContext.Provider, {
2037
- value: resolved,
2038
- children: Wrapper ? /* @__PURE__ */ jsx(Wrapper, {
2039
- theme: {
2040
- ...theme,
2041
- scheme: resolved.scheme
2042
- },
2043
- children: content
2044
- }) : /* @__PURE__ */ jsx(DefaultSurface, { children: content })
2045
- });
2046
- }
2047
- function DefaultSurface({ children }) {
2048
- const { colors } = useTheme();
2049
- return /* @__PURE__ */ jsx("div", {
2050
- className: "dot-surface",
2051
- style: {
2052
- minHeight: "100vh",
2053
- display: "flex",
2054
- flexDirection: "column",
2055
- background: colors.background,
2056
- color: colors.text,
2057
- fontFamily: FONT_FAMILY
2058
- },
2059
- children
2060
- });
2061
- }
2062
- //#endregion
2063
- //#region src/renderer.tsx
2064
- function reactRenderer({ components = {}, wrapper } = {}) {
2065
- const registry = {
2066
- ...builtins,
2067
- ...components
2068
- };
2069
- return {
2070
- name: "react",
2071
- mount(container, page, dotContext) {
2072
- const root = createRoot(container);
2073
- root.render(/* @__PURE__ */ jsx(Root, {
2074
- page,
2075
- dotContext,
2076
- components: registry,
2077
- wrapper
2078
- }));
2079
- return () => root.unmount();
2080
- }
2081
- };
2082
- }
2083
- //#endregion
1
+ import { resolveTheme, useTheme } from "./theme.js";
2
+ import { AmountInput } from "./components/amount-input.js";
3
+ import { Avatar } from "./components/avatar.js";
4
+ import { Spinner } from "./components/spinner.js";
5
+ import { Button } from "./components/button.js";
6
+ import { Carousel } from "./components/carousel.js";
7
+ import { Icon } from "./components/icon.js";
8
+ import { Chip } from "./components/chip.js";
9
+ import { CodeInput } from "./components/code-input.js";
10
+ import { DetailRow } from "./components/detail-row.js";
11
+ import { Disclosure } from "./components/disclosure.js";
12
+ import { Divider } from "./components/divider.js";
13
+ import { EmptyState } from "./components/empty-state.js";
14
+ import { Badge, Notice, ProgressBar } from "./components/feedback.js";
15
+ import { Footer } from "./components/footer.js";
16
+ import { Grid, GridItem } from "./components/grid.js";
17
+ import { Image } from "./components/image.js";
18
+ import { Input } from "./components/input.js";
19
+ import { Link } from "./components/link.js";
20
+ import { List, ListItem } from "./components/list.js";
21
+ import { Option } from "./components/option.js";
22
+ import { Bullet, BulletList, Prose, Quote } from "./components/prose.js";
23
+ import { QRCode } from "./components/qr-code.js";
24
+ import { Text } from "./components/text.js";
25
+ import { RichText } from "./components/rich-text.js";
26
+ import { Scroll } from "./components/scroll.js";
27
+ import { Sheet } from "./components/sheet.js";
28
+ import { Select } from "./components/select.js";
29
+ import { Skeleton } from "./components/skeleton.js";
30
+ import { Slider } from "./components/slider.js";
31
+ import { Stack } from "./components/stack.js";
32
+ import { Step, Steps } from "./components/steps.js";
33
+ import { Stepper } from "./components/stepper.js";
34
+ import { Tab, Tabs } from "./components/tabs.js";
35
+ import { TextArea } from "./components/text-area.js";
36
+ import { Toast } from "./components/toast.js";
37
+ import { Checkbox, Radio, RadioGroup, Switch } from "./components/toggles.js";
38
+ import { View } from "./components/view.js";
39
+ import { createReactRenderer, reactRenderer } from "./renderer.js";
2084
40
  //#region src/index.ts
2085
41
  var src_default = reactRenderer;
2086
42
  //#endregion
2087
- export { builtins, src_default as default, resolveTheme, useTheme };
2088
-
2089
- //# sourceMappingURL=index.js.map
43
+ export { AmountInput, Avatar, Badge, Bullet, BulletList, Button, Carousel, Checkbox, Chip, CodeInput, DetailRow, Disclosure, Divider, EmptyState, Footer, Grid, GridItem, Icon, Image, Input, Link, List, ListItem, Notice, Option, ProgressBar, Prose, QRCode, Quote, Radio, RadioGroup, RichText, Scroll, Select, Sheet, Skeleton, Slider, Spinner, Stack, Step, Stepper, Steps, Switch, Tab, Tabs, Text, TextArea, Toast, View, createReactRenderer, src_default as default, resolveTheme, useTheme };