@krizaka/ui 3.2.0 → 3.3.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 (162) hide show
  1. package/dist/{chunk-I5RVM5CW.js → chunk-2FRWNSRO.js} +2 -6
  2. package/dist/chunk-2FRWNSRO.js.map +1 -0
  3. package/dist/chunk-BTMFZ66D.js +135 -0
  4. package/dist/chunk-BTMFZ66D.js.map +1 -0
  5. package/dist/chunk-C2BRIFJG.js +13 -0
  6. package/dist/chunk-C2BRIFJG.js.map +1 -0
  7. package/dist/chunk-KDXRYUD3.js +39 -0
  8. package/dist/chunk-KDXRYUD3.js.map +1 -0
  9. package/dist/{chunk-2PUDI7JS.js → chunk-ZKVQGXLD.js} +5 -3
  10. package/dist/{chunk-2PUDI7JS.js.map → chunk-ZKVQGXLD.js.map} +1 -1
  11. package/dist/command.js +1 -1
  12. package/dist/confirm-button.js +1 -1
  13. package/dist/data-table.js +3 -2
  14. package/dist/data-table.js.map +1 -1
  15. package/dist/date-picker.d.ts +3 -1
  16. package/dist/date-picker.js +13 -13
  17. package/dist/date-picker.js.map +1 -1
  18. package/dist/dropdown-menu.js +1 -1
  19. package/dist/filter-bar.js +3 -2
  20. package/dist/form.d.ts +23 -12
  21. package/dist/form.js +11 -47
  22. package/dist/form.js.map +1 -1
  23. package/dist/glow-card.js +1 -1
  24. package/dist/image-cropper.js +3 -1
  25. package/dist/image-cropper.js.map +1 -1
  26. package/dist/marquee.js +1 -1
  27. package/dist/native/form.d.ts +60 -15
  28. package/dist/native/form.js +103 -42
  29. package/dist/native/form.js.map +1 -1
  30. package/dist/native.d.ts +206 -2
  31. package/dist/native.js +1172 -541
  32. package/dist/native.js.map +1 -1
  33. package/dist/nav-bar.js +1 -1
  34. package/dist/popover.js +1 -1
  35. package/dist/radio-group.d.ts +66 -32
  36. package/dist/radio-group.js +54 -10
  37. package/dist/radio-group.js.map +1 -1
  38. package/dist/slider.d.ts +96 -35
  39. package/dist/slider.js +67 -13
  40. package/dist/slider.js.map +1 -1
  41. package/dist/terminal-replay.js +34 -60
  42. package/dist/terminal-replay.js.map +1 -1
  43. package/dist/toast.js +1 -1
  44. package/dist/tooltip.js +1 -1
  45. package/dist/video-player.js +3 -1
  46. package/dist/video-player.js.map +1 -1
  47. package/package.json +6 -6
  48. package/registry/combobox.json +225 -3
  49. package/registry/date-picker.json +16 -2
  50. package/registry/dialog.json +74 -3
  51. package/registry/examples/combobox/native/multiple.d.ts +4 -0
  52. package/registry/examples/combobox/native/multiple.dark.png +0 -0
  53. package/registry/examples/combobox/native/multiple.js +15 -0
  54. package/registry/examples/combobox/native/multiple.light.png +0 -0
  55. package/registry/examples/combobox/native/multiple.tsx +15 -0
  56. package/registry/examples/combobox/native/search.d.ts +4 -0
  57. package/registry/examples/combobox/native/search.dark.png +0 -0
  58. package/registry/examples/combobox/native/search.js +15 -0
  59. package/registry/examples/combobox/native/search.light.png +0 -0
  60. package/registry/examples/combobox/native/search.tsx +15 -0
  61. package/registry/examples/dialog/native/sheet.d.ts +4 -0
  62. package/registry/examples/dialog/native/sheet.dark.png +0 -0
  63. package/registry/examples/dialog/native/sheet.js +21 -0
  64. package/registry/examples/dialog/native/sheet.light.png +0 -0
  65. package/registry/examples/dialog/native/sheet.tsx +18 -0
  66. package/registry/examples/field/native/select.d.ts +4 -0
  67. package/registry/examples/field/native/select.dark.png +0 -0
  68. package/registry/examples/field/native/select.js +29 -0
  69. package/registry/examples/field/native/select.light.png +0 -0
  70. package/registry/examples/field/native/select.tsx +25 -0
  71. package/registry/examples/form/native/audience.dark.png +0 -0
  72. package/registry/examples/form/native/audience.light.png +0 -0
  73. package/registry/examples/form/native/profile.dark.png +0 -0
  74. package/registry/examples/form/native/profile.light.png +0 -0
  75. package/registry/examples/form/native/settings.dark.png +0 -0
  76. package/registry/examples/form/native/settings.light.png +0 -0
  77. package/registry/examples/form/native/sign-up.dark.png +0 -0
  78. package/registry/examples/form/native/sign-up.light.png +0 -0
  79. package/registry/examples/form/native/upload.dark.png +0 -0
  80. package/registry/examples/form/native/upload.light.png +0 -0
  81. package/registry/examples/radio-group/buttons.d.ts +4 -0
  82. package/registry/examples/radio-group/buttons.js +17 -0
  83. package/registry/examples/radio-group/buttons.tsx +21 -0
  84. package/registry/examples/radio-group/cards.js +1 -1
  85. package/registry/examples/radio-group/cards.tsx +2 -2
  86. package/registry/examples/radio-group/native/buttons.d.ts +4 -0
  87. package/registry/examples/radio-group/native/buttons.dark.png +0 -0
  88. package/registry/examples/radio-group/native/buttons.js +25 -0
  89. package/registry/examples/radio-group/native/buttons.light.png +0 -0
  90. package/registry/examples/radio-group/native/buttons.tsx +21 -0
  91. package/registry/examples/radio-group/native/cards.d.ts +4 -0
  92. package/registry/examples/radio-group/native/cards.dark.png +0 -0
  93. package/registry/examples/radio-group/native/cards.js +23 -0
  94. package/registry/examples/radio-group/native/cards.light.png +0 -0
  95. package/registry/examples/radio-group/native/cards.tsx +19 -0
  96. package/registry/examples/radio-group/native/list.d.ts +4 -0
  97. package/registry/examples/radio-group/native/list.dark.png +0 -0
  98. package/registry/examples/radio-group/native/list.js +24 -0
  99. package/registry/examples/radio-group/native/list.light.png +0 -0
  100. package/registry/examples/radio-group/native/list.tsx +20 -0
  101. package/registry/examples/radio-group/native/segmented.d.ts +4 -0
  102. package/registry/examples/radio-group/native/segmented.dark.png +0 -0
  103. package/registry/examples/radio-group/native/segmented.js +24 -0
  104. package/registry/examples/radio-group/native/segmented.light.png +0 -0
  105. package/registry/examples/radio-group/native/segmented.tsx +20 -0
  106. package/registry/examples/radio-group/segmented.d.ts +4 -0
  107. package/registry/examples/radio-group/segmented.js +15 -0
  108. package/registry/examples/radio-group/segmented.tsx +12 -0
  109. package/registry/examples/slider/floating.d.ts +4 -0
  110. package/registry/examples/slider/floating.js +11 -0
  111. package/registry/examples/slider/floating.tsx +12 -0
  112. package/registry/examples/slider/native/default.d.ts +4 -0
  113. package/registry/examples/slider/native/default.dark.png +0 -0
  114. package/registry/examples/slider/native/default.js +14 -0
  115. package/registry/examples/slider/native/default.light.png +0 -0
  116. package/registry/examples/slider/native/default.tsx +13 -0
  117. package/registry/examples/slider/native/range.d.ts +4 -0
  118. package/registry/examples/slider/native/range.dark.png +0 -0
  119. package/registry/examples/slider/native/range.js +12 -0
  120. package/registry/examples/slider/native/range.light.png +0 -0
  121. package/registry/examples/slider/native/range.tsx +11 -0
  122. package/registry/examples/slider/native/stepped.d.ts +4 -0
  123. package/registry/examples/slider/native/stepped.dark.png +0 -0
  124. package/registry/examples/slider/native/stepped.js +28 -0
  125. package/registry/examples/slider/native/stepped.light.png +0 -0
  126. package/registry/examples/slider/native/stepped.tsx +24 -0
  127. package/registry/examples/slider/native/vertical.d.ts +4 -0
  128. package/registry/examples/slider/native/vertical.dark.png +0 -0
  129. package/registry/examples/slider/native/vertical.js +16 -0
  130. package/registry/examples/slider/native/vertical.light.png +0 -0
  131. package/registry/examples/slider/native/vertical.tsx +13 -0
  132. package/registry/examples/slider/price-range.d.ts +4 -0
  133. package/registry/examples/slider/price-range.js +29 -0
  134. package/registry/examples/slider/price-range.tsx +27 -0
  135. package/registry/examples/slider/stepped.d.ts +4 -0
  136. package/registry/examples/slider/stepped.js +28 -0
  137. package/registry/examples/slider/stepped.tsx +24 -0
  138. package/registry/examples/slider/vertical.d.ts +4 -0
  139. package/registry/examples/slider/vertical.js +15 -0
  140. package/registry/examples/slider/vertical.tsx +14 -0
  141. package/registry/examples/switch/native/default.d.ts +4 -0
  142. package/registry/examples/switch/native/default.dark.png +0 -0
  143. package/registry/examples/switch/native/default.js +16 -0
  144. package/registry/examples/switch/native/default.light.png +0 -0
  145. package/registry/examples/switch/native/default.tsx +13 -0
  146. package/registry/examples/switch/native/settings.d.ts +4 -0
  147. package/registry/examples/switch/native/settings.dark.png +0 -0
  148. package/registry/examples/switch/native/settings.js +20 -0
  149. package/registry/examples/switch/native/settings.light.png +0 -0
  150. package/registry/examples/switch/native/settings.tsx +17 -0
  151. package/registry/field.json +15 -3
  152. package/registry/form.json +250 -42
  153. package/registry/index.json +24 -20
  154. package/registry/radio-group.json +227 -15
  155. package/registry/slider.json +314 -13
  156. package/registry/switch.json +115 -3
  157. package/registry/tabs.json +2 -2
  158. package/skills/choice-controls/SKILL.md +39 -0
  159. package/skills/form/SKILL.md +3 -0
  160. package/dist/chunk-I5RVM5CW.js.map +0 -1
  161. package/dist/chunk-RUPRYJ45.js +0 -82
  162. package/dist/chunk-RUPRYJ45.js.map +0 -1
@@ -6,7 +6,7 @@
6
6
  "description": "An on/off setting that applies at once.",
7
7
  "status": "beta",
8
8
  "category": "forms",
9
- "platforms": "web",
9
+ "platforms": "both",
10
10
  "whenToUse": [
11
11
  "For a setting that takes effect immediately: autoplay, notifications, a weekly digest."
12
12
  ],
@@ -120,7 +120,119 @@
120
120
  }
121
121
  ]
122
122
  },
123
- "native": null,
123
+ "native": {
124
+ "entry": "@krizaka/ui/native",
125
+ "import": "import { Switch } from \"@krizaka/ui/native\";",
126
+ "differences": [
127
+ "Drawn by the theme, not the system's: the same switch on iOS and Android, the accent when on, a `selection` haptic when it flips (the app's `haptics`).",
128
+ "`showLabel` makes it a settings row: the label and its `description` beside the switch, the whole row pressable, the description read as the hint.",
129
+ "`error` shows under the row and is announced."
130
+ ],
131
+ "props": [
132
+ {
133
+ "component": "Switch",
134
+ "description": "An on/off switch for React Native — the web `Switch`, drawn by the theme (the accent when on, the material's knob),\nnot the system's: the same look on iOS and Android, a `selection` haptic when it flips. `showLabel` makes it a\nsettings row (the label and its description beside it, all pressable).",
135
+ "props": [
136
+ {
137
+ "name": "label",
138
+ "type": "string",
139
+ "default": null,
140
+ "description": "The accessible name (\"Push notifications\"), passed translated — also the visible words when `children` is not given and `showLabel` is set.",
141
+ "required": true
142
+ },
143
+ {
144
+ "name": "checked",
145
+ "type": "boolean",
146
+ "default": null,
147
+ "description": "On (controlled).",
148
+ "required": false
149
+ },
150
+ {
151
+ "name": "defaultChecked",
152
+ "type": "boolean",
153
+ "default": "false",
154
+ "description": "On at first, uncontrolled.",
155
+ "required": false
156
+ },
157
+ {
158
+ "name": "description",
159
+ "type": "string",
160
+ "default": null,
161
+ "description": "A line under the label, read with the switch (\"Auctions you follow, new messages\"). Shown with `showLabel`.",
162
+ "required": false
163
+ },
164
+ {
165
+ "name": "disabled",
166
+ "type": "boolean",
167
+ "default": null,
168
+ "description": "Not available.",
169
+ "required": false
170
+ },
171
+ {
172
+ "name": "error",
173
+ "type": "string",
174
+ "default": null,
175
+ "description": "An error under the row, read and announced.",
176
+ "required": false
177
+ },
178
+ {
179
+ "name": "onCheckedChange",
180
+ "type": "((checked: boolean) => void)",
181
+ "default": null,
182
+ "description": "Called with the new state.",
183
+ "required": false
184
+ },
185
+ {
186
+ "name": "showLabel",
187
+ "type": "boolean",
188
+ "default": null,
189
+ "description": "Draws the label (and the description) beside the switch, the whole row pressable: a settings row.",
190
+ "required": false
191
+ },
192
+ {
193
+ "name": "size",
194
+ "type": "\"sm\" | \"md\"",
195
+ "default": "md",
196
+ "description": "sm · md (default).",
197
+ "required": false
198
+ },
199
+ {
200
+ "name": "style",
201
+ "type": "StyleProp<ViewStyle>",
202
+ "default": null,
203
+ "description": "Styles merged last.",
204
+ "required": false
205
+ }
206
+ ]
207
+ }
208
+ ],
209
+ "examples": [
210
+ {
211
+ "name": "settings",
212
+ "title": "Settings rows",
213
+ "description": "Notification preferences: rows with a description, one disabled while push is off.",
214
+ "path": "examples/switch/native/settings.tsx",
215
+ "module": "@krizaka/ui/registry/examples/switch/native/settings",
216
+ "code": "import { Switch } from \"@krizaka/ui/native\";\nimport * as React from \"react\";\nimport { View } from \"react-native\";\n\n// Notification preferences: settings rows, the whole row pressable, a selection haptic as each one flips.\nexport default function NativeSwitchSettings() {\n const [push, setPush] = React.useState(true);\n const [auctions, setAuctions] = React.useState(true);\n const [digest, setDigest] = React.useState(false);\n return (\n <View style={{ width: 320, gap: 4 }}>\n <Switch label=\"Push notifications\" description=\"On this phone, even when the app is closed.\" showLabel checked={push} onCheckedChange={setPush} />\n <Switch label=\"Auctions you follow\" description=\"Outbid, ending soon, won.\" showLabel checked={auctions} onCheckedChange={setAuctions} disabled={!push} />\n <Switch label=\"Weekly digest\" description=\"One e-mail on Monday morning.\" showLabel checked={digest} onCheckedChange={setDigest} />\n </View>\n );\n}\n",
217
+ "screenshots": {
218
+ "dark": "examples/switch/native/settings.dark.png",
219
+ "light": "examples/switch/native/settings.light.png"
220
+ }
221
+ },
222
+ {
223
+ "name": "default",
224
+ "title": "Alone",
225
+ "description": "Named by `label`; md and sm.",
226
+ "path": "examples/switch/native/default.tsx",
227
+ "module": "@krizaka/ui/registry/examples/switch/native/default",
228
+ "code": "import { Switch } from \"@krizaka/ui/native\";\nimport { View } from \"react-native\";\n\n// The switch alone, named by `label`: md and sm, on and off.\nexport default function NativeSwitchDefault() {\n return (\n <View style={{ flexDirection: \"row\", gap: 16, alignItems: \"center\" }}>\n <Switch label=\"Dark mode\" defaultChecked />\n <Switch label=\"Sounds\" />\n <Switch label=\"Compact\" size=\"sm\" defaultChecked />\n </View>\n );\n}\n",
229
+ "screenshots": {
230
+ "dark": "examples/switch/native/default.dark.png",
231
+ "light": "examples/switch/native/default.light.png"
232
+ }
233
+ }
234
+ ]
235
+ },
124
236
  "files": [
125
237
  {
126
238
  "path": "meta.ts",
@@ -132,7 +244,7 @@
132
244
  },
133
245
  {
134
246
  "path": "switch/meta.ts",
135
- "content": "import type { ComponentMeta } from \"../meta\";\n\nexport const meta = {\n title: \"Switch\",\n summary: \"An on/off setting that applies at once.\",\n status: \"beta\",\n category: \"forms\",\n platforms: \"web\",\n whenToUse: [\"For a setting that takes effect immediately: autoplay, notifications, a weekly digest.\"],\n whenNotToUse: [\n { when: \"For a choice submitted with a form, or an agreement.\", use: \"checkbox\" },\n { when: \"For more than two states.\", use: \"radio-group\" },\n { when: \"To run an action.\", use: \"button\" },\n ],\n bestPractices: [\n \"Name the setting, not the state: “Autoplay”, not “Turn autoplay on”.\",\n \"Put the label first and the switch at the end of the line (`Field.Label htmlFor`), with a hint when it helps.\",\n ],\n accessibility: {\n keyboard: [{ keys: \"Space\", action: \"Toggles the switch.\" }],\n notes: [\n \"Radix Switch: `role=\\\"switch\\\"` with `aria-checked`.\",\n \"`label` names it when no visible label does; otherwise use `Field.Label htmlFor` and `aria-describedby` for the hint.\",\n ],\n },\n related: [\"checkbox\", \"field\", \"radio-group\"],\n web: {\n imports: [\"Switch\"],\n examples: [\n { name: \"off\", title: \"Off\", description: \"Named by `label`.\" },\n { name: \"on\", title: \"On\", description: \"`defaultChecked` (or `checked` + `onCheckedChange`).\" },\n { name: \"disabled\", title: \"Disabled\", description: \"Off and on.\" },\n { name: \"small\", title: \"Small\", description: \"`size=\\\"sm\\\"`.\" },\n { name: \"with-label\", title: \"With a visible label\", description: \"A label and a hint on the same line.\" },\n ],\n },\n} satisfies ComponentMeta;\n"
247
+ "content": "import type { ComponentMeta } from \"../meta\";\n\nexport const meta = {\n title: \"Switch\",\n summary: \"An on/off setting that applies at once.\",\n status: \"beta\",\n category: \"forms\",\n platforms: \"both\",\n whenToUse: [\"For a setting that takes effect immediately: autoplay, notifications, a weekly digest.\"],\n whenNotToUse: [\n { when: \"For a choice submitted with a form, or an agreement.\", use: \"checkbox\" },\n { when: \"For more than two states.\", use: \"radio-group\" },\n { when: \"To run an action.\", use: \"button\" },\n ],\n bestPractices: [\n \"Name the setting, not the state: “Autoplay”, not “Turn autoplay on”.\",\n \"Put the label first and the switch at the end of the line (`Field.Label htmlFor`), with a hint when it helps.\",\n ],\n accessibility: {\n keyboard: [{ keys: \"Space\", action: \"Toggles the switch.\" }],\n notes: [\n \"Radix Switch: `role=\\\"switch\\\"` with `aria-checked`.\",\n \"`label` names it when no visible label does; otherwise use `Field.Label htmlFor` and `aria-describedby` for the hint.\",\n ],\n },\n related: [\"checkbox\", \"field\", \"radio-group\"],\n web: {\n imports: [\"Switch\"],\n examples: [\n { name: \"off\", title: \"Off\", description: \"Named by `label`.\" },\n { name: \"on\", title: \"On\", description: \"`defaultChecked` (or `checked` + `onCheckedChange`).\" },\n { name: \"disabled\", title: \"Disabled\", description: \"Off and on.\" },\n { name: \"small\", title: \"Small\", description: \"`size=\\\"sm\\\"`.\" },\n { name: \"with-label\", title: \"With a visible label\", description: \"A label and a hint on the same line.\" },\n ],\n },\n native: {\n imports: [\"Switch\"],\n differences: [\n \"Drawn by the theme, not the system's: the same switch on iOS and Android, the accent when on, a `selection` haptic when it flips (the app's `haptics`).\",\n \"`showLabel` makes it a settings row: the label and its `description` beside the switch, the whole row pressable, the description read as the hint.\",\n \"`error` shows under the row and is announced.\",\n ],\n examples: [\n { name: \"settings\", title: \"Settings rows\", description: \"Notification preferences: rows with a description, one disabled while push is off.\" },\n { name: \"default\", title: \"Alone\", description: \"Named by `label`; md and sm.\" },\n ],\n },\n} satisfies ComponentMeta;\n"
136
248
  },
137
249
  {
138
250
  "path": "switch/switch.tsx",
@@ -59,7 +59,7 @@
59
59
  "props": [
60
60
  {
61
61
  "name": "variant",
62
- "type": "\"underline\" | \"segmented\" | \"pills\"",
62
+ "type": "\"segmented\" | \"underline\" | \"pills\"",
63
63
  "default": "underline",
64
64
  "description": "underline (the sections of a page) · segmented (a view switch) · pills (a feed's sections).",
65
65
  "required": false
@@ -146,7 +146,7 @@
146
146
  "props": [
147
147
  {
148
148
  "name": "variant",
149
- "type": "\"underline\" | \"segmented\" | \"pills\"",
149
+ "type": "\"segmented\" | \"underline\" | \"pills\"",
150
150
  "default": "underline",
151
151
  "description": "underline (the sections of a page) · segmented (a view switch) · pills (a feed's sections).",
152
152
  "required": false
@@ -0,0 +1,39 @@
1
+ ---
2
+ name: krizaka-choice-controls
3
+ description: Choices and settings in a Krizaka app (Next.js or Expo) with @krizaka/ui — RadioGroup (dots, cards, tactile keys that press in, segmented), Slider (range, steps and marks, floating value, brand gradient, vertical), Switch, and on React Native Select / Combobox in a Sheet, with haptics through the ThemeProvider. Use it instead of React Native's Switch, a picker module, a hand-made segmented control or a slider library.
4
+ ---
5
+
6
+ # RadioGroup · Slider · Switch · Select · Combobox · Sheet
7
+
8
+ ## Rules
9
+
10
+ 1. Pick by the choice:
11
+ - two to five options seen at once → `RadioGroup` — `list` (settings), `cards` (an amount, a plan: a line under
12
+ each), `buttons` (a size, a tip, a level: tactile keys), `segmented` (two to four short words on one line);
13
+ - many options → web `Select` of `@krizaka/ui/field` (the platform's menu) or `Combobox` (searched); native `Select`
14
+ / `Combobox` (a field that opens a `Sheet`);
15
+ - a value by feel within bounds → `Slider` (`ticks` when the steps are few, `marks` to name the ends,
16
+ `floatingValue` while touched, `orientation="vertical"` for faders); an exact number → a text field;
17
+ - on / off, applied at once → `Switch` (native: `showLabel` + `description` makes the settings row).
18
+ 2. Never React Native's `Switch`, `@react-native-community/slider` or a picker module: the platform's controls are
19
+ drawn by the theme, the same on iOS and Android, and wear the product's accent.
20
+ 3. A segmented control that **switches views** is `Tabs variant="segmented"` (web) / `Segmented` (native); one that is a
21
+ **form's value** is `RadioGroup variant="segmented"`.
22
+ 4. Haptics: `<ThemeProvider haptics={(k) => k === "selection" ? Haptics.selectionAsync() : Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light)}>`
23
+ once at the root (expo-haptics). Wheels, slider steps, radios and switches play `selection`; a tactile key `impact`.
24
+ 5. Words are props (`label`, `thumbLabels`, `formatValue`, `hint`, `labels`), passed translated. In a form, use the
25
+ form's fields (`form.RadioGroup variant=…`, `form.Slider`, `form.Switch`, `form.Select`, `form.Combobox`).
26
+
27
+ ## Recipes
28
+
29
+ ```tsx
30
+ <RadioGroup.Root label={t("tip")} variant="buttons" value={tip} onValueChange={setTip}>
31
+ {TIPS.map((p) => <RadioGroup.Button key={p} value={p} hint={formatMoney(total * p / 100)}>{`${p} %`}</RadioGroup.Button>)}
32
+ </RadioGroup.Root>
33
+ <Slider<[number, number]> label={t("price")} thumbLabels={[t("min"), t("max")]} value={range} onValueChange={setRange}
34
+ max={250} step={10} floatingValue marks={[{ value: 0, label: "$0" }, { value: 250, label: "$250+" }]} />
35
+ // React Native
36
+ <Switch label={t("push")} description={t("push.hint")} showLabel checked={push} onCheckedChange={setPush} />
37
+ <Select label={t("language")} options={LANGUAGES} value={lang} onValueChange={setLang} />
38
+ <Combobox label={t("city")} onSearch={(q, signal) => searchCities(q, signal)} value={city} onValueChange={setCity} />
39
+ ```
@@ -40,5 +40,8 @@ const form = signUp.useForm({ i18n: { t }, codeFields: { USERNAME_RESERVED: "use
40
40
  - Amounts: `form.Money name="amount" currency="EUR"` stores integer cents (`z.number().int()`).
41
41
  - Lists: `<form.FieldArray name="links">{(a) => a.items.map((_, i) => <form.TextField name={`links[${i}].url`} … />)}</form.FieldArray>`.
42
42
  - Conditional parts: `<form.Watch name="audience">{(v) => v === "subscribers" ? <form.Money name="price" … /> : null}</form.Watch>`.
43
+ - Controls (DS5): `form.RadioGroup variant="buttons" | "segmented" | "cards"`, `form.DateField entry="wheel" max={latestBirthDate(18)}`,
44
+ `form.Slider ticks marks={…}` (the value floats while touched). Native: `DateField` is wheels by default, `Select` /
45
+ `Combobox` open a sheet, `Switch` is a settings row; pass `haptics` to the native `ThemeProvider` for the haptics.
43
46
  - Native: `<form.Form scroll>` makes the form the screen's scrolling content above the keyboard; the return key walks the
44
47
  text fields and the last one sends; `<form.Submit label=… brand="orochia" />` turns the product's mark while sending.
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cn.ts","../src/floating.ts"],"sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { cnMerge, type TWMergeConfig } from \"tailwind-variants\";\n\nexport type { ClassValue };\n\n/**\n * The preset's own utilities, told to the merge engine: the material (BRAND.md §6: `bg-sheen`, `bg-fill-shade`,\n * `bg-halo` are background images; `shadow-raised` · `-floating` · `-overlay` · `-glow` are shadows; `inset-shadow-edge`\n * · `-edge-fill` · `-well` are inset shadows). Unknown, tailwind-merge would take `bg-sheen` for a colour and drop the\n * `bg-surface-2` it lies on.\n */\nexport const twMergeConfig: TWMergeConfig = {\n extend: {\n classGroups: {\n \"bg-image\": [\"bg-sheen\", \"bg-fill-shade\", \"bg-halo\"],\n shadow: [\"shadow-raised\", \"shadow-floating\", \"shadow-overlay\", \"shadow-glow\", \"shadow-glow-lg\"],\n \"inset-shadow\": [\"inset-shadow-edge\", \"inset-shadow-edge-fill\", \"inset-shadow-well\"],\n },\n },\n};\n\n/**\n * Merges Tailwind classes: the last one wins — a product's `className` overrides the primitive's. The merge engine is\n * tailwind-merge as tailwind-variants ships it (the one `tv` uses), so the platform carries a single copy of it.\n * tailwind-variants bundles that engine since 3.3 (it never imports the `tailwind-merge` package, an optional peer):\n * hence `tailwind-variants ^3.3.1` and no `tailwind-merge` dependency — `scripts/consumer.mjs` checks it on a clean\n * install of the packed package.\n */\nexport function cn(...inputs: ClassValue[]): string {\n return cnMerge(clsx(inputs))({ twMergeConfig }) ?? \"\";\n}\n","// The one surface of everything that floats next to its trigger (popover, menu, tooltip): a raised surface, a border,\n// the large shadow and the `kz-pop` entrance from the side Radix measured (`--radix-*-transform-origin`).\nexport const floating =\n \"kz-pop z-50 rounded-lg border border-border-default bg-surface-2 text-fg shadow-lg outline-hidden\";\n"],"mappings":";;;AAAA,SAA0B,YAAY;AACtC,SAAS,eAAmC;AAUrC,IAAM,gBAA+B;AAAA,EAC1C,QAAQ;AAAA,IACN,aAAa;AAAA,MACX,YAAY,CAAC,YAAY,iBAAiB,SAAS;AAAA,MACnD,QAAQ,CAAC,iBAAiB,mBAAmB,kBAAkB,eAAe,gBAAgB;AAAA,MAC9F,gBAAgB,CAAC,qBAAqB,0BAA0B,mBAAmB;AAAA,IACrF;AAAA,EACF;AACF;AASO,SAAS,MAAM,QAA8B;AAClD,SAAO,QAAQ,KAAK,MAAM,CAAC,EAAE,EAAE,cAAc,CAAC,KAAK;AACrD;;;AC5BO,IAAM,WACX;","names":[]}
@@ -1,82 +0,0 @@
1
- "use client";
2
-
3
- // src/slider/slider.tsx
4
- import { Slider as SliderPrimitive } from "radix-ui";
5
- import * as React from "react";
6
- import { tv } from "tailwind-variants";
7
- import { jsx, jsxs } from "react/jsx-runtime";
8
- var slider = tv({
9
- slots: {
10
- root: "flex flex-col gap-2",
11
- header: "flex items-baseline justify-between gap-3 text-xs font-semibold text-fg-secondary",
12
- value: "font-mono text-[11px] tabular-nums text-fg-secondary",
13
- control: "relative flex h-6 w-full touch-none select-none items-center data-disabled:cursor-not-allowed data-disabled:opacity-40",
14
- track: "relative h-1.5 w-full grow overflow-hidden rounded-full bg-surface-3",
15
- range: "absolute h-full rounded-full bg-linear-to-r from-accent to-accent-2",
16
- thumb: "block h-5 w-5 cursor-grab rounded-full border border-border-strong bg-fg-on-media shadow-md transition-[box-shadow] focus-visible:outline-hidden focus-visible:ring-4 focus-visible:ring-ring/50 active:cursor-grabbing"
17
- }
18
- });
19
- var toArray = (v) => v === void 0 ? void 0 : typeof v === "number" ? [v] : v;
20
- function Slider({
21
- value,
22
- defaultValue,
23
- onValueChange,
24
- onValueCommit,
25
- label,
26
- thumbLabels,
27
- formatValue = String,
28
- showLabel,
29
- origin,
30
- min = 0,
31
- max = 100,
32
- className,
33
- ...props
34
- }) {
35
- const s = slider();
36
- const range = Array.isArray(value ?? defaultValue);
37
- const [inner, setInner] = React.useState(() => toArray(defaultValue) ?? [min]);
38
- const current = toArray(value) ?? inner;
39
- const out = (next) => range ? next : next[0];
40
- const pct = (v) => (v - min) / (max - min || 1) * 100;
41
- const fill = origin !== void 0 && !range ? { left: `${Math.min(pct(origin), pct(current[0]))}%`, right: `${100 - Math.max(pct(origin), pct(current[0]))}%` } : void 0;
42
- const id = React.useId();
43
- return /* @__PURE__ */ jsxs("div", { className: s.root({ className }), "data-range": range ? "" : void 0, children: [
44
- showLabel && /* @__PURE__ */ jsxs("div", { className: s.header(), children: [
45
- /* @__PURE__ */ jsx("span", { id: `${id}-label`, children: label }),
46
- /* @__PURE__ */ jsx("span", { className: s.value(), "aria-hidden": true, children: current.map(formatValue).join(" \u2013 ") })
47
- ] }),
48
- /* @__PURE__ */ jsxs(
49
- SliderPrimitive.Root,
50
- {
51
- min,
52
- max,
53
- value: current,
54
- onValueChange: (next) => {
55
- if (value === void 0) setInner(next);
56
- onValueChange?.(out(next));
57
- },
58
- onValueCommit: onValueCommit && ((next) => onValueCommit(out(next))),
59
- className: s.control(),
60
- ...props,
61
- children: [
62
- /* @__PURE__ */ jsx(SliderPrimitive.Track, { className: s.track(), children: fill ? /* @__PURE__ */ jsx("span", { "data-origin": "", className: s.range(), style: fill }) : /* @__PURE__ */ jsx(SliderPrimitive.Range, { className: s.range() }) }),
63
- current.map((v, i) => /* @__PURE__ */ jsx(
64
- SliderPrimitive.Thumb,
65
- {
66
- "aria-label": range ? thumbLabels?.[i] ?? label : showLabel ? void 0 : label,
67
- "aria-labelledby": !range && showLabel ? `${id}-label` : void 0,
68
- "aria-valuetext": formatValue(v),
69
- className: s.thumb()
70
- },
71
- i
72
- ))
73
- ]
74
- }
75
- )
76
- ] });
77
- }
78
-
79
- export {
80
- Slider
81
- };
82
- //# sourceMappingURL=chunk-RUPRYJ45.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/slider/slider.tsx"],"sourcesContent":["// Client. Radix Slider: role=\"slider\" on each thumb, arrows / Page Up / Page Down / Home / End, a range with two\n// thumbs. The words arrive as props: `label` names the thumb(s), `formatValue` gives the aria-valuetext and the value\n// shown next to a visible label.\nimport { Slider as SliderPrimitive } from \"radix-ui\";\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nexport const slider = tv({\n slots: {\n root: \"flex flex-col gap-2\",\n header: \"flex items-baseline justify-between gap-3 text-xs font-semibold text-fg-secondary\",\n value: \"font-mono text-[11px] tabular-nums text-fg-secondary\",\n control:\n \"relative flex h-6 w-full touch-none select-none items-center data-disabled:cursor-not-allowed data-disabled:opacity-40\",\n track: \"relative h-1.5 w-full grow overflow-hidden rounded-full bg-surface-3\",\n range: \"absolute h-full rounded-full bg-linear-to-r from-accent to-accent-2\",\n thumb:\n \"block h-5 w-5 cursor-grab rounded-full border border-border-strong bg-fg-on-media shadow-md transition-[box-shadow] \" +\n \"focus-visible:outline-hidden focus-visible:ring-4 focus-visible:ring-ring/50 active:cursor-grabbing\",\n },\n});\n\nexport type SliderValue = number | [number, number];\n\nexport type SliderProps<V extends SliderValue = number> = Omit<\n React.ComponentProps<typeof SliderPrimitive.Root>,\n \"value\" | \"defaultValue\" | \"onValueChange\" | \"onValueCommit\" | \"children\"\n> & {\n /** One number (a thumb) or two (a range). Controlled with `onValueChange`. */\n value?: V;\n /** The value at first, uncontrolled: one number, or two for a range. */\n defaultValue?: V;\n /** Called on every move, with one number or two. */\n onValueChange?: (value: V) => void;\n /** Called once the drag or the key press ends. */\n onValueCommit?: (value: V) => void;\n /** The accessible name — of the thumb, or of both thumbs of a range — passed translated. */\n label: string;\n /** For a range: each thumb's own name ([\"Minimum\", \"Maximum\"]), passed translated. */\n thumbLabels?: [string, string];\n /** The value as words (aria-valuetext) and as shown: \"1.5×\", \"−12 %\", \"3 min\". */\n formatValue?: (value: number) => string;\n /** Shows the label and the value above the track. Without it, `label` only names the thumb. */\n showLabel?: boolean;\n /** Fills from this value instead of the minimum (a ±range from 0: brightness, balance). One thumb only. */\n origin?: number;\n};\n\nconst toArray = (v: SliderValue | undefined) => (v === undefined ? undefined : typeof v === \"number\" ? [v] : v);\n\n/** A slider on one value or a range: `value`/`defaultValue` + `onValueChange`, `min`, `max`, `step`. */\nexport function Slider<V extends SliderValue = number>({\n value,\n defaultValue,\n onValueChange,\n onValueCommit,\n label,\n thumbLabels,\n formatValue = String,\n showLabel,\n origin,\n min = 0,\n max = 100,\n className,\n ...props\n}: SliderProps<V>) {\n const s = slider();\n const range = Array.isArray(value ?? defaultValue);\n const [inner, setInner] = React.useState(() => toArray(defaultValue) ?? [min]);\n const current = toArray(value) ?? inner;\n const out = (next: number[]) => (range ? next : next[0]) as V;\n const pct = (v: number) => ((v - min) / (max - min || 1)) * 100;\n const fill =\n origin !== undefined && !range\n ? { left: `${Math.min(pct(origin), pct(current[0]))}%`, right: `${100 - Math.max(pct(origin), pct(current[0]))}%` }\n : undefined;\n const id = React.useId();\n return (\n <div className={s.root({ className })} data-range={range ? \"\" : undefined}>\n {showLabel && (\n <div className={s.header()}>\n <span id={`${id}-label`}>{label}</span>\n <span className={s.value()} aria-hidden>\n {current.map(formatValue).join(\" – \")}\n </span>\n </div>\n )}\n <SliderPrimitive.Root\n min={min}\n max={max}\n value={current}\n onValueChange={(next) => {\n if (value === undefined) setInner(next);\n onValueChange?.(out(next));\n }}\n onValueCommit={onValueCommit && ((next) => onValueCommit(out(next)))}\n className={s.control()}\n {...props}\n >\n <SliderPrimitive.Track className={s.track()}>\n {fill ? <span data-origin=\"\" className={s.range()} style={fill} /> : <SliderPrimitive.Range className={s.range()} />}\n </SliderPrimitive.Track>\n {current.map((v, i) => (\n <SliderPrimitive.Thumb\n key={i}\n aria-label={range ? (thumbLabels?.[i] ?? label) : showLabel ? undefined : label}\n aria-labelledby={!range && showLabel ? `${id}-label` : undefined}\n aria-valuetext={formatValue(v)}\n className={s.thumb()}\n />\n ))}\n </SliderPrimitive.Root>\n </div>\n );\n}\n"],"mappings":";;;AAGA,SAAS,UAAU,uBAAuB;AAC1C,YAAY,WAAW;AACvB,SAAS,UAAU;AA2EX,SACE,KADF;AAzED,IAAM,SAAS,GAAG;AAAA,EACvB,OAAO;AAAA,IACL,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,SACE;AAAA,IACF,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OACE;AAAA,EAEJ;AACF,CAAC;AA4BD,IAAM,UAAU,CAAC,MAAgC,MAAM,SAAY,SAAY,OAAO,MAAM,WAAW,CAAC,CAAC,IAAI;AAGtG,SAAS,OAAuC;AAAA,EACrD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA,MAAM;AAAA,EACN,MAAM;AAAA,EACN;AAAA,EACA,GAAG;AACL,GAAmB;AACjB,QAAM,IAAI,OAAO;AACjB,QAAM,QAAQ,MAAM,QAAQ,SAAS,YAAY;AACjD,QAAM,CAAC,OAAO,QAAQ,IAAU,eAAS,MAAM,QAAQ,YAAY,KAAK,CAAC,GAAG,CAAC;AAC7E,QAAM,UAAU,QAAQ,KAAK,KAAK;AAClC,QAAM,MAAM,CAAC,SAAoB,QAAQ,OAAO,KAAK,CAAC;AACtD,QAAM,MAAM,CAAC,OAAgB,IAAI,QAAQ,MAAM,OAAO,KAAM;AAC5D,QAAM,OACJ,WAAW,UAAa,CAAC,QACrB,EAAE,MAAM,GAAG,KAAK,IAAI,IAAI,MAAM,GAAG,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,OAAO,GAAG,MAAM,KAAK,IAAI,IAAI,MAAM,GAAG,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,IAChH;AACN,QAAM,KAAW,YAAM;AACvB,SACE,qBAAC,SAAI,WAAW,EAAE,KAAK,EAAE,UAAU,CAAC,GAAG,cAAY,QAAQ,KAAK,QAC7D;AAAA,iBACC,qBAAC,SAAI,WAAW,EAAE,OAAO,GACvB;AAAA,0BAAC,UAAK,IAAI,GAAG,EAAE,UAAW,iBAAM;AAAA,MAChC,oBAAC,UAAK,WAAW,EAAE,MAAM,GAAG,eAAW,MACpC,kBAAQ,IAAI,WAAW,EAAE,KAAK,UAAK,GACtC;AAAA,OACF;AAAA,IAEF;AAAA,MAAC,gBAAgB;AAAA,MAAhB;AAAA,QACC;AAAA,QACA;AAAA,QACA,OAAO;AAAA,QACP,eAAe,CAAC,SAAS;AACvB,cAAI,UAAU,OAAW,UAAS,IAAI;AACtC,0BAAgB,IAAI,IAAI,CAAC;AAAA,QAC3B;AAAA,QACA,eAAe,kBAAkB,CAAC,SAAS,cAAc,IAAI,IAAI,CAAC;AAAA,QAClE,WAAW,EAAE,QAAQ;AAAA,QACpB,GAAG;AAAA,QAEJ;AAAA,8BAAC,gBAAgB,OAAhB,EAAsB,WAAW,EAAE,MAAM,GACvC,iBAAO,oBAAC,UAAK,eAAY,IAAG,WAAW,EAAE,MAAM,GAAG,OAAO,MAAM,IAAK,oBAAC,gBAAgB,OAAhB,EAAsB,WAAW,EAAE,MAAM,GAAG,GACpH;AAAA,UACC,QAAQ,IAAI,CAAC,GAAG,MACf;AAAA,YAAC,gBAAgB;AAAA,YAAhB;AAAA,cAEC,cAAY,QAAS,cAAc,CAAC,KAAK,QAAS,YAAY,SAAY;AAAA,cAC1E,mBAAiB,CAAC,SAAS,YAAY,GAAG,EAAE,WAAW;AAAA,cACvD,kBAAgB,YAAY,CAAC;AAAA,cAC7B,WAAW,EAAE,MAAM;AAAA;AAAA,YAJd;AAAA,UAKP,CACD;AAAA;AAAA;AAAA,IACH;AAAA,KACF;AAEJ;","names":[]}