@polderlabs/bizar 6.3.0 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (245) hide show
  1. package/.claude/hooks/sessionend-recall.mjs +3 -3
  2. package/.claude/hooks/worker-suggest.mjs +110 -0
  3. package/.claude/settings.json +9 -0
  4. package/bizar-dash/dist/assets/{EnvVarsSection-B58aiJiE.js → EnvVarsSection-CW6fWKds.js} +3 -3
  5. package/bizar-dash/dist/assets/{EnvVarsSection-B58aiJiE.js.map → EnvVarsSection-CW6fWKds.js.map} +1 -1
  6. package/bizar-dash/dist/assets/MobileChat-D7zRhU9K.js +1 -0
  7. package/bizar-dash/dist/assets/{MobileChat-BJrqwVDd.js.map → MobileChat-D7zRhU9K.js.map} +1 -1
  8. package/bizar-dash/dist/assets/MobileSettings-K-sNsn_r.js +1 -0
  9. package/bizar-dash/dist/assets/{MobileSettings-CEQNJNLJ.js.map → MobileSettings-K-sNsn_r.js.map} +1 -1
  10. package/bizar-dash/dist/assets/{Toast-Cpl6-E63.js → Toast-WTxc3m2g.js} +1 -1
  11. package/bizar-dash/dist/assets/{Toast-Cpl6-E63.js.map → Toast-WTxc3m2g.js.map} +1 -1
  12. package/bizar-dash/dist/assets/flow-BpU0-gK2.js +1 -0
  13. package/bizar-dash/dist/assets/flow-BpU0-gK2.js.map +1 -0
  14. package/bizar-dash/dist/assets/fuzzy-l0sNRNKZ.js +1 -0
  15. package/bizar-dash/dist/assets/fuzzy-l0sNRNKZ.js.map +1 -0
  16. package/bizar-dash/dist/assets/{icons-Do5N2jmX.js → icons-B0AKnYI3.js} +98 -103
  17. package/bizar-dash/dist/assets/icons-B0AKnYI3.js.map +1 -0
  18. package/bizar-dash/dist/assets/main-C-Md3DaY.css +1 -0
  19. package/bizar-dash/dist/assets/main-CO8fIxQK.js +18 -0
  20. package/bizar-dash/dist/assets/main-CO8fIxQK.js.map +1 -0
  21. package/bizar-dash/dist/assets/markdown-w2bDDkAH.js +1 -0
  22. package/bizar-dash/dist/assets/{markdown-tOLaD6nm.js.map → markdown-w2bDDkAH.js.map} +1 -1
  23. package/bizar-dash/dist/assets/mobile-DXYCA0hC.js +1 -0
  24. package/bizar-dash/dist/assets/{mobile-DYCHcUpq.js.map → mobile-DXYCA0hC.js.map} +1 -1
  25. package/bizar-dash/dist/assets/mobile-layout-DSmtNPja.js +2 -0
  26. package/bizar-dash/dist/assets/mobile-layout-DSmtNPja.js.map +1 -0
  27. package/bizar-dash/dist/assets/react-vendor-BnuhLJ6X.css +1 -0
  28. package/bizar-dash/dist/assets/react-vendor-D3pra6w-.js +46 -0
  29. package/bizar-dash/dist/assets/react-vendor-D3pra6w-.js.map +1 -0
  30. package/bizar-dash/dist/assets/useSlashCommands-3DFLOfpk.js +2 -0
  31. package/bizar-dash/dist/assets/useSlashCommands-3DFLOfpk.js.map +1 -0
  32. package/bizar-dash/dist/assets/vendor-Di7Cp-rw.js +45 -0
  33. package/bizar-dash/dist/assets/vendor-Di7Cp-rw.js.map +1 -0
  34. package/bizar-dash/dist/index.html +12 -10
  35. package/bizar-dash/dist/mobile.html +7 -4
  36. package/bizar-dash/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  37. package/bizar-dash/src/server/api.mjs +11 -0
  38. package/bizar-dash/src/server/memory-consolidator.mjs +218 -0
  39. package/bizar-dash/src/server/memory-distillation.mjs +296 -0
  40. package/bizar-dash/src/server/routes/distill.mjs +129 -0
  41. package/bizar-dash/src/server/routes/goal-planner.mjs +236 -0
  42. package/bizar-dash/src/web/App.tsx +4 -0
  43. package/bizar-dash/src/web/components/Tag.tsx +18 -5
  44. package/bizar-dash/src/web/components/Topbar.tsx +3 -0
  45. package/bizar-dash/src/web/components/agents/CommunicationLog.tsx +126 -0
  46. package/bizar-dash/src/web/components/agents/DependencyGraph.tsx +163 -0
  47. package/bizar-dash/src/web/components/agents/QualityGates.tsx +123 -0
  48. package/bizar-dash/src/web/components/agents/RealTimeEventLog.tsx +127 -0
  49. package/bizar-dash/src/web/components/agents/RoutingDecisions.test.tsx +148 -0
  50. package/bizar-dash/src/web/components/agents/RoutingDecisions.tsx +160 -0
  51. package/bizar-dash/src/web/components/goals/GoalInput.tsx +86 -0
  52. package/bizar-dash/src/web/components/goals/PlanVisualization.tsx +111 -0
  53. package/bizar-dash/src/web/lib/goapPlanner.ts +614 -0
  54. package/bizar-dash/src/web/lib/types.ts +25 -0
  55. package/bizar-dash/src/web/styles/agents-redesign.css +311 -0
  56. package/bizar-dash/src/web/styles/main.css +251 -0
  57. package/bizar-dash/src/web/styles/tasks-redesign.css +231 -0
  58. package/bizar-dash/src/web/ui/controls/Button.tsx +77 -0
  59. package/bizar-dash/src/web/ui/controls/Checkbox.tsx +95 -0
  60. package/bizar-dash/src/web/ui/controls/IconButton.tsx +66 -0
  61. package/bizar-dash/src/web/ui/controls/Kbd.tsx +24 -0
  62. package/bizar-dash/src/web/ui/controls/NumberInput.tsx +77 -0
  63. package/bizar-dash/src/web/ui/controls/RadioGroup.tsx +109 -0
  64. package/bizar-dash/src/web/ui/controls/SearchInput.tsx +91 -0
  65. package/bizar-dash/src/web/ui/controls/Select.tsx +92 -0
  66. package/bizar-dash/src/web/ui/controls/Slider.tsx +70 -0
  67. package/bizar-dash/src/web/ui/controls/TextInput.tsx +67 -0
  68. package/bizar-dash/src/web/ui/controls/Toggle.tsx +79 -0
  69. package/bizar-dash/src/web/ui/controls/controls.css +454 -0
  70. package/bizar-dash/src/web/ui/controls/index.ts +33 -0
  71. package/bizar-dash/src/web/ui/data/BarChart.tsx +60 -0
  72. package/bizar-dash/src/web/ui/data/DataTable.tsx +216 -0
  73. package/bizar-dash/src/web/ui/data/EmptyState.tsx +60 -0
  74. package/bizar-dash/src/web/ui/data/ErrorState.tsx +56 -0
  75. package/bizar-dash/src/web/ui/data/KeyValueList.tsx +106 -0
  76. package/bizar-dash/src/web/ui/data/LoadingState.tsx +65 -0
  77. package/bizar-dash/src/web/ui/data/Sparkline.tsx +87 -0
  78. package/bizar-dash/src/web/ui/data/StatTile.tsx +87 -0
  79. package/bizar-dash/src/web/ui/data/data.css +535 -0
  80. package/bizar-dash/src/web/ui/data/index.ts +31 -0
  81. package/bizar-dash/src/web/ui/feedback/Badge.tsx +49 -0
  82. package/bizar-dash/src/web/ui/feedback/Dialog.tsx +209 -0
  83. package/bizar-dash/src/web/ui/feedback/ProgressBar.tsx +69 -0
  84. package/bizar-dash/src/web/ui/feedback/StatusDot.tsx +50 -0
  85. package/bizar-dash/src/web/ui/feedback/Toast.tsx +200 -0
  86. package/bizar-dash/src/web/ui/feedback/Tooltip.tsx +126 -0
  87. package/bizar-dash/src/web/ui/feedback/feedback.css +314 -0
  88. package/bizar-dash/src/web/ui/feedback/index.ts +43 -0
  89. package/bizar-dash/src/web/ui/index.ts +56 -0
  90. package/bizar-dash/src/web/ui/layout/AppShell.tsx +51 -0
  91. package/bizar-dash/src/web/ui/layout/Breadcrumbs.tsx +97 -0
  92. package/bizar-dash/src/web/ui/layout/Panel.tsx +73 -0
  93. package/bizar-dash/src/web/ui/layout/PanelHeader.tsx +39 -0
  94. package/bizar-dash/src/web/ui/layout/Sidebar.tsx +131 -0
  95. package/bizar-dash/src/web/ui/layout/Tabs.tsx +133 -0
  96. package/bizar-dash/src/web/ui/layout/Topbar.tsx +42 -0
  97. package/bizar-dash/src/web/ui/layout/index.ts +33 -0
  98. package/bizar-dash/src/web/ui/layout/layout.css +413 -0
  99. package/bizar-dash/src/web/ui/navigation/CommandPalette.tsx +199 -0
  100. package/bizar-dash/src/web/ui/navigation/NavGroup.tsx +95 -0
  101. package/bizar-dash/src/web/ui/navigation/NavLink.tsx +93 -0
  102. package/bizar-dash/src/web/ui/navigation/index.ts +17 -0
  103. package/bizar-dash/src/web/ui/navigation/navigation.css +343 -0
  104. package/bizar-dash/src/web/ui/primitives/Box.tsx +91 -0
  105. package/bizar-dash/src/web/ui/primitives/Grid.tsx +49 -0
  106. package/bizar-dash/src/web/ui/primitives/Inline.tsx +55 -0
  107. package/bizar-dash/src/web/ui/primitives/Separator.tsx +46 -0
  108. package/bizar-dash/src/web/ui/primitives/Stack.tsx +54 -0
  109. package/bizar-dash/src/web/ui/primitives/VisuallyHidden.tsx +26 -0
  110. package/bizar-dash/src/web/ui/primitives/index.ts +23 -0
  111. package/bizar-dash/src/web/ui/primitives/primitives.css +183 -0
  112. package/bizar-dash/src/web/ui/styles/globals.css +86 -0
  113. package/bizar-dash/src/web/ui/styles/reset.css +125 -0
  114. package/bizar-dash/src/web/ui/styles/tokens.css +195 -0
  115. package/bizar-dash/src/web/ui/theme/ThemeProvider.tsx +142 -0
  116. package/bizar-dash/src/web/ui/theme/tokens.ts +131 -0
  117. package/bizar-dash/src/web/ui/theme/useTheme.ts +22 -0
  118. package/bizar-dash/src/web/ui/utils/cx.ts +42 -0
  119. package/bizar-dash/src/web/views/Agents.tsx +506 -266
  120. package/bizar-dash/src/web/views/GoalPlanner.tsx +158 -0
  121. package/bizar-dash/src/web/views/Overview.tsx +996 -448
  122. package/bizar-dash/src/web/views/Tasks.tsx +277 -273
  123. package/bizar-dash/tests/communication-log.test.tsx +67 -0
  124. package/bizar-dash/tests/dep-graph.test.tsx +40 -0
  125. package/bizar-dash/tests/event-log.test.tsx +61 -0
  126. package/bizar-dash/tests/goal-input.test.tsx +72 -0
  127. package/bizar-dash/tests/goap-planner.test.ts +68 -0
  128. package/bizar-dash/tests/quality-gates.test.tsx +59 -0
  129. package/bizar-dash/tests/setup.ts +31 -1
  130. package/bizar-dash/tests/ui/controls/Button.test.tsx +50 -0
  131. package/bizar-dash/tests/ui/controls/Checkbox.test.tsx +44 -0
  132. package/bizar-dash/tests/ui/controls/IconButton.test.tsx +37 -0
  133. package/bizar-dash/tests/ui/controls/Kbd.test.tsx +39 -0
  134. package/bizar-dash/tests/ui/controls/NumberInput.test.tsx +56 -0
  135. package/bizar-dash/tests/ui/controls/RadioGroup.test.tsx +58 -0
  136. package/bizar-dash/tests/ui/controls/SearchInput.test.tsx +52 -0
  137. package/bizar-dash/tests/ui/controls/Select.test.tsx +66 -0
  138. package/bizar-dash/tests/ui/controls/Slider.test.tsx +41 -0
  139. package/bizar-dash/tests/ui/controls/TextInput.test.tsx +44 -0
  140. package/bizar-dash/tests/ui/controls/Toggle.test.tsx +39 -0
  141. package/bizar-dash/tests/ui/data/BarChart.test.tsx +55 -0
  142. package/bizar-dash/tests/ui/data/DataTable.test.tsx +112 -0
  143. package/bizar-dash/tests/ui/data/EmptyState.test.tsx +57 -0
  144. package/bizar-dash/tests/ui/data/ErrorState.test.tsx +47 -0
  145. package/bizar-dash/tests/ui/data/KeyValueList.test.tsx +59 -0
  146. package/bizar-dash/tests/ui/data/LoadingState.test.tsx +37 -0
  147. package/bizar-dash/tests/ui/data/Sparkline.test.tsx +56 -0
  148. package/bizar-dash/tests/ui/data/StatTile.test.tsx +69 -0
  149. package/bizar-dash/tests/ui/feedback/Badge.test.tsx +41 -0
  150. package/bizar-dash/tests/ui/feedback/Dialog.test.tsx +99 -0
  151. package/bizar-dash/tests/ui/feedback/ProgressBar.test.tsx +66 -0
  152. package/bizar-dash/tests/ui/feedback/StatusDot.test.tsx +41 -0
  153. package/bizar-dash/tests/ui/feedback/Toast.test.tsx +124 -0
  154. package/bizar-dash/tests/ui/feedback/Tooltip.test.tsx +102 -0
  155. package/bizar-dash/tests/ui/layout/AppShell.test.tsx +50 -0
  156. package/bizar-dash/tests/ui/layout/Breadcrumbs.test.tsx +85 -0
  157. package/bizar-dash/tests/ui/layout/Panel.test.tsx +52 -0
  158. package/bizar-dash/tests/ui/layout/PanelHeader.test.tsx +32 -0
  159. package/bizar-dash/tests/ui/layout/Sidebar.test.tsx +95 -0
  160. package/bizar-dash/tests/ui/layout/Tabs.test.tsx +87 -0
  161. package/bizar-dash/tests/ui/layout/Topbar.test.tsx +41 -0
  162. package/bizar-dash/tests/ui/navigation/CommandPalette.test.tsx +105 -0
  163. package/bizar-dash/tests/ui/navigation/NavGroup.test.tsx +55 -0
  164. package/bizar-dash/tests/ui/navigation/NavLink.test.tsx +61 -0
  165. package/bizar-dash/tests/ui/primitives/Box.test.tsx +49 -0
  166. package/bizar-dash/tests/ui/primitives/Grid.test.tsx +37 -0
  167. package/bizar-dash/tests/ui/primitives/Inline.test.tsx +33 -0
  168. package/bizar-dash/tests/ui/primitives/Separator.test.tsx +34 -0
  169. package/bizar-dash/tests/ui/primitives/Stack.test.tsx +45 -0
  170. package/bizar-dash/tests/ui/primitives/VisuallyHidden.test.tsx +27 -0
  171. package/bizar-dash/tests/views/Agents.test.tsx +359 -0
  172. package/bizar-dash/tests/views/Overview.test.tsx +413 -0
  173. package/bizar-dash/tests/views/Tasks.test.tsx +250 -0
  174. package/bizar-dash/vitest.config.ts +3 -1
  175. package/cli/__tests__/cost-gate.test.mjs +301 -0
  176. package/cli/__tests__/feature-list-bridge.test.mjs +371 -0
  177. package/cli/bin.mjs +38 -0
  178. package/cli/commands/claim.mjs +282 -0
  179. package/cli/commands/cost.mjs +279 -0
  180. package/cli/cost-gate.mjs +501 -0
  181. package/cli/feature-list-bridge.mjs +400 -0
  182. package/cli/memory-constants.mjs +17 -0
  183. package/cli/worker-dispatcher.mjs +259 -0
  184. package/cli/worker-dispatcher.test.mjs +204 -0
  185. package/config/trigger-patterns.json +186 -0
  186. package/package.json +2 -2
  187. package/packages/sdk/package.json +1 -1
  188. package/packages/sdk/src/agent-registry.ts +304 -0
  189. package/packages/sdk/src/consensus/byzantine.ts +587 -0
  190. package/packages/sdk/src/consensus/index.ts +147 -0
  191. package/packages/sdk/src/consensus/queen.ts +173 -0
  192. package/packages/sdk/src/consensus/types.ts +199 -0
  193. package/packages/sdk/src/federation/audit.ts +156 -0
  194. package/packages/sdk/src/federation/budget.ts +269 -0
  195. package/packages/sdk/src/federation/envelope.ts +144 -0
  196. package/packages/sdk/src/federation/hmac.ts +160 -0
  197. package/packages/sdk/src/federation/index.ts +443 -0
  198. package/packages/sdk/src/federation/pii.ts +241 -0
  199. package/packages/sdk/src/federation/policy.ts +112 -0
  200. package/packages/sdk/src/federation/trust.ts +146 -0
  201. package/packages/sdk/src/index.ts +67 -0
  202. package/packages/sdk/src/mcp/server.ts +351 -1
  203. package/packages/sdk/src/router/codemod-intent.ts +125 -0
  204. package/packages/sdk/src/router/index.ts +247 -0
  205. package/packages/sdk/src/router/memory-distillation-shim.mjs +18 -0
  206. package/packages/sdk/src/router/memory-distillation.ts +249 -0
  207. package/packages/sdk/src/router/model-router.ts +235 -0
  208. package/packages/sdk/src/router/q-learning-router.ts +304 -0
  209. package/packages/sdk/src/swarm-topology.ts +279 -0
  210. package/packages/sdk/tests/agent-registry.test.ts +285 -0
  211. package/packages/sdk/tests/consensus.test.ts +376 -0
  212. package/packages/sdk/tests/federation/audit.test.ts +164 -0
  213. package/packages/sdk/tests/federation/budget.test.ts +189 -0
  214. package/packages/sdk/tests/federation/envelope.test.ts +120 -0
  215. package/packages/sdk/tests/federation/hmac.test.ts +194 -0
  216. package/packages/sdk/tests/federation/orchestrator.test.ts +176 -0
  217. package/packages/sdk/tests/federation/pii.test.ts +106 -0
  218. package/packages/sdk/tests/federation/policy.test.ts +140 -0
  219. package/packages/sdk/tests/federation/trust.test.ts +124 -0
  220. package/packages/sdk/tests/mcp-tools.test.ts +204 -0
  221. package/packages/sdk/tests/memory-distillation.test.mjs +186 -0
  222. package/packages/sdk/tests/model-router.test.mjs +108 -0
  223. package/packages/sdk/tests/q-learning-router.test.mjs +100 -0
  224. package/packages/sdk/tests/router-orchestrator.test.mjs +172 -0
  225. package/packages/sdk/tests/router.test.mjs +91 -0
  226. package/packages/sdk/tests/sdk.test.mjs +26 -2
  227. package/packages/sdk/tests/swarm-topology.test.ts +258 -0
  228. package/scripts/bh-full-e2e.mjs +11 -15
  229. package/bizar-dash/dist/assets/MobileChat-BJrqwVDd.js +0 -1
  230. package/bizar-dash/dist/assets/MobileSettings-CEQNJNLJ.js +0 -1
  231. package/bizar-dash/dist/assets/icons-Do5N2jmX.js.map +0 -1
  232. package/bizar-dash/dist/assets/main-IvfQAOfy.js +0 -18
  233. package/bizar-dash/dist/assets/main-IvfQAOfy.js.map +0 -1
  234. package/bizar-dash/dist/assets/main-ietCEg_R.css +0 -1
  235. package/bizar-dash/dist/assets/markdown-tOLaD6nm.js +0 -1
  236. package/bizar-dash/dist/assets/mobile-DYCHcUpq.js +0 -1
  237. package/bizar-dash/dist/assets/mobile-layout-CBHjpwsb.js +0 -2
  238. package/bizar-dash/dist/assets/mobile-layout-CBHjpwsb.js.map +0 -1
  239. package/bizar-dash/dist/assets/react-vendor-Dn4wqh4Z.js +0 -40
  240. package/bizar-dash/dist/assets/react-vendor-Dn4wqh4Z.js.map +0 -1
  241. package/bizar-dash/dist/assets/useSlashCommands-Bd7_FA6U.js +0 -2
  242. package/bizar-dash/dist/assets/useSlashCommands-Bd7_FA6U.js.map +0 -1
  243. package/bizar-dash/dist/assets/vendor-C843201K.js +0 -29
  244. package/bizar-dash/dist/assets/vendor-C843201K.js.map +0 -1
  245. package/packages/sdk/package-lock.json +0 -32
@@ -0,0 +1,91 @@
1
+ /*
2
+ * SearchInput.tsx — text field with search affordances (Wave 2A).
3
+ *
4
+ * Composes TextInput: bakes in a left Search icon and a conditional
5
+ * Clear button on the right when `value` is non-empty. `onClear` fires
6
+ * only when the user activates the explicit Clear button — not on
7
+ * backspace keystrokes, which are reported through the regular
8
+ * `onChange` callback. `aria-label` should be supplied by the caller
9
+ * (visual label is optional).
10
+ */
11
+
12
+ import {
13
+ forwardRef,
14
+ useCallback,
15
+ type ChangeEvent,
16
+ } from 'react';
17
+ import { Search, X } from 'lucide-react';
18
+ import { cx } from '../utils/cx';
19
+ import { TextInput } from './TextInput';
20
+
21
+ export type SearchInputSize = 'sm' | 'md' | 'lg';
22
+
23
+ export type SearchInputProps = Omit<
24
+ React.InputHTMLAttributes<HTMLInputElement>,
25
+ 'size' | 'children' | 'type'
26
+ > & {
27
+ inputSize?: SearchInputSize;
28
+ value: string;
29
+ onChange: (next: string) => void;
30
+ onClear?: () => void;
31
+ placeholder?: string;
32
+ disabled?: boolean;
33
+ 'aria-label'?: string;
34
+ };
35
+
36
+ export const SearchInput = forwardRef<HTMLInputElement, SearchInputProps>(
37
+ function SearchInput(
38
+ {
39
+ inputSize = 'md',
40
+ value,
41
+ onChange,
42
+ onClear,
43
+ placeholder = 'Search…',
44
+ disabled,
45
+ className,
46
+ ...rest
47
+ },
48
+ ref,
49
+ ) {
50
+ const handleClear = useCallback(() => {
51
+ onChange('');
52
+ onClear?.();
53
+ }, [onChange, onClear]);
54
+ const handleChange = useCallback(
55
+ (e: ChangeEvent<HTMLInputElement>) => {
56
+ onChange(e.target.value);
57
+ },
58
+ [onChange],
59
+ );
60
+ return (
61
+ <span className={cx('field', className)}>
62
+ <Search
63
+ size={14}
64
+ className="field-icon-left"
65
+ aria-hidden
66
+ />
67
+ <input
68
+ ref={ref}
69
+ type="search"
70
+ value={value}
71
+ onChange={handleChange}
72
+ placeholder={placeholder}
73
+ disabled={disabled}
74
+ className="field-input field-has-left"
75
+ {...rest}
76
+ />
77
+ {value !== '' && !disabled && (
78
+ <button
79
+ type="button"
80
+ onClick={handleClear}
81
+ className="field-clear"
82
+ aria-label="Clear search"
83
+ tabIndex={-1}
84
+ >
85
+ <X size={12} aria-hidden />
86
+ </button>
87
+ )}
88
+ </span>
89
+ );
90
+ },
91
+ );
@@ -0,0 +1,92 @@
1
+ /*
2
+ * Select.tsx — native select dropdown (Wave 2A).
3
+ *
4
+ * Built on the native <select> for keyboard nav, mobile picker, and
5
+ * free accessibility. The native control is wrapped in a span that
6
+ * owns sizing + caret positioning. CSS paints a chevron via the
7
+ * `select-caret` sibling. Wrapper-level props (data-testid, id, className)
8
+ * land on the outer span; form-related props (name, form, required) go
9
+ * to the inner <select>.
10
+ */
11
+
12
+ import {
13
+ forwardRef,
14
+ type HTMLAttributes,
15
+ } from 'react';
16
+ import { ChevronDown } from 'lucide-react';
17
+ import { cx } from '../utils/cx';
18
+
19
+ export type SelectOption = {
20
+ value: string;
21
+ label: string;
22
+ disabled?: boolean;
23
+ };
24
+
25
+ export type SelectSize = 'sm' | 'md' | 'lg';
26
+
27
+ export type SelectProps = Omit<
28
+ HTMLAttributes<HTMLSpanElement>,
29
+ 'children'
30
+ > & {
31
+ inputSize?: SelectSize;
32
+ options: SelectOption[];
33
+ placeholder?: string;
34
+ error?: string | null;
35
+ value?: string;
36
+ defaultValue?: string;
37
+ disabled?: boolean;
38
+ name?: string;
39
+ required?: boolean;
40
+ onChange?: (e: React.ChangeEvent<HTMLSelectElement>) => void;
41
+ };
42
+
43
+ export const Select = forwardRef<HTMLSelectElement, SelectProps>(
44
+ function Select(
45
+ {
46
+ inputSize = 'md',
47
+ options,
48
+ placeholder,
49
+ error,
50
+ value,
51
+ defaultValue,
52
+ disabled,
53
+ name,
54
+ required,
55
+ onChange,
56
+ className,
57
+ ...wrapperProps
58
+ },
59
+ ref,
60
+ ) {
61
+ return (
62
+ <span
63
+ {...wrapperProps}
64
+ className={cx('select', `select-size-${inputSize}`, className)}
65
+ >
66
+ <select
67
+ ref={ref}
68
+ disabled={disabled}
69
+ name={name}
70
+ required={required}
71
+ value={value}
72
+ defaultValue={defaultValue ?? (placeholder !== undefined ? '' : undefined)}
73
+ onChange={onChange}
74
+ aria-invalid={error ? true : undefined}
75
+ className={cx('select-native', error && 'select-error')}
76
+ >
77
+ {placeholder !== undefined && (
78
+ <option value="" disabled>
79
+ {placeholder}
80
+ </option>
81
+ )}
82
+ {options.map((opt) => (
83
+ <option key={opt.value} value={opt.value} disabled={opt.disabled}>
84
+ {opt.label}
85
+ </option>
86
+ ))}
87
+ </select>
88
+ <ChevronDown className="select-caret" size={14} aria-hidden />
89
+ </span>
90
+ );
91
+ },
92
+ );
@@ -0,0 +1,70 @@
1
+ /*
2
+ * Slider.tsx — range input (Wave 2A).
3
+ *
4
+ * Thin wrapper around <input type="range"> that adds a labelled header
5
+ * row and an optional value badge. The native range control delivers
6
+ * keyboard arrow-keys / page-up / home / end for free. `showValue` adds
7
+ * a tabular-numeric readout to the right of the label.
8
+ */
9
+
10
+ import { forwardRef, type InputHTMLAttributes } from 'react';
11
+ import { cx } from '../utils/cx';
12
+
13
+ export type SliderProps = Omit<
14
+ InputHTMLAttributes<HTMLInputElement>,
15
+ 'type' | 'value' | 'onChange' | 'children'
16
+ > & {
17
+ value: number;
18
+ onChange: (next: number) => void;
19
+ min?: number;
20
+ max?: number;
21
+ step?: number;
22
+ label?: string;
23
+ showValue?: boolean;
24
+ disabled?: boolean;
25
+ };
26
+
27
+ export const Slider = forwardRef<HTMLInputElement, SliderProps>(
28
+ function Slider(
29
+ {
30
+ value,
31
+ onChange,
32
+ min = 0,
33
+ max = 100,
34
+ step = 1,
35
+ label,
36
+ showValue = false,
37
+ disabled,
38
+ className,
39
+ ...rest
40
+ },
41
+ ref,
42
+ ) {
43
+ return (
44
+ <div className={cx('slider', className)}>
45
+ {(label !== undefined || showValue) && (
46
+ <div className="slider-header">
47
+ {label !== undefined && (
48
+ <span className="slider-label">{label}</span>
49
+ )}
50
+ {showValue && (
51
+ <span className="slider-value">{String(value)}</span>
52
+ )}
53
+ </div>
54
+ )}
55
+ <input
56
+ ref={ref}
57
+ type="range"
58
+ min={min}
59
+ max={max}
60
+ step={step}
61
+ value={value}
62
+ disabled={disabled}
63
+ onChange={(e) => onChange(Number(e.target.value))}
64
+ className="slider-input"
65
+ {...rest}
66
+ />
67
+ </div>
68
+ );
69
+ },
70
+ );
@@ -0,0 +1,67 @@
1
+ /*
2
+ * TextInput.tsx — single-line text field (Wave 2A).
3
+ *
4
+ * Wraps the native <input type="text"> to keep autofocus / selection /
5
+ * spellcheck / mobile keyboard behavior free of customization. Sizes sm/md/lg
6
+ * match the rest of the controls' vertical rhythm. `error` paints the border
7
+ * danger and shifts the focus ring to the danger-subtle tone. `leftIcon` and
8
+ * `rightIcon` are ReactNode (typically a lucide-react icon) absolutely
9
+ * positioned inside the field padding well.
10
+ */
11
+
12
+ import {
13
+ forwardRef,
14
+ type InputHTMLAttributes,
15
+ type ReactNode,
16
+ } from 'react';
17
+ import { cx } from '../utils/cx';
18
+
19
+ export type TextInputSize = 'sm' | 'md' | 'lg';
20
+
21
+ export type TextInputProps = Omit<
22
+ InputHTMLAttributes<HTMLInputElement>,
23
+ 'size' | 'children'
24
+ > & {
25
+ inputSize?: TextInputSize;
26
+ error?: string | null;
27
+ leftIcon?: ReactNode;
28
+ rightIcon?: ReactNode;
29
+ };
30
+
31
+ export const TextInput = forwardRef<HTMLInputElement, TextInputProps>(
32
+ function TextInput(
33
+ {
34
+ inputSize = 'md',
35
+ error,
36
+ leftIcon,
37
+ rightIcon,
38
+ disabled,
39
+ className,
40
+ ...rest
41
+ },
42
+ ref,
43
+ ) {
44
+ return (
45
+ <span
46
+ className={cx(
47
+ 'field',
48
+ `field-size-${inputSize}`,
49
+ leftIcon && 'field-has-left',
50
+ rightIcon && 'field-has-right',
51
+ className,
52
+ )}
53
+ >
54
+ {leftIcon && <span className="field-icon-left">{leftIcon}</span>}
55
+ <input
56
+ ref={ref}
57
+ type="text"
58
+ disabled={disabled}
59
+ aria-invalid={error ? true : undefined}
60
+ className={cx('field-input', error && 'field-error')}
61
+ {...rest}
62
+ />
63
+ {rightIcon && <span className="field-icon-right">{rightIcon}</span>}
64
+ </span>
65
+ );
66
+ },
67
+ );
@@ -0,0 +1,79 @@
1
+ /*
2
+ * Toggle.tsx — boolean switch (Wave 2A).
3
+ *
4
+ * Built as a label-wrapping-input pattern (visually hidden checkbox) so
5
+ * screen readers announce role=switch without extra ARIA. The CSS track +
6
+ * thumb are absolutely positioned inside the label; checked/disabled states
7
+ * toggle classes on the wrapping label. `size` sm/md governs the track.
8
+ *
9
+ * Wrapper-level props (data-testid, id, aria-*, className) flow to the
10
+ * <label>; the inner <input> only takes its own concerns (name, form,
11
+ * autoFocus, etc).
12
+ */
13
+
14
+ import {
15
+ forwardRef,
16
+ type HTMLAttributes,
17
+ type ReactNode,
18
+ } from 'react';
19
+ import { cx } from '../utils/cx';
20
+
21
+ export type ToggleSize = 'sm' | 'md';
22
+
23
+ export type ToggleProps = Omit<
24
+ HTMLAttributes<HTMLLabelElement>,
25
+ 'onChange' | 'children'
26
+ > & {
27
+ checked: boolean;
28
+ onChange: (checked: boolean) => void;
29
+ label?: ReactNode;
30
+ size?: ToggleSize;
31
+ name?: string;
32
+ disabled?: boolean;
33
+ autoFocus?: boolean;
34
+ };
35
+
36
+ export const Toggle = forwardRef<HTMLInputElement, ToggleProps>(
37
+ function Toggle(
38
+ {
39
+ checked,
40
+ onChange,
41
+ label,
42
+ disabled,
43
+ size = 'md',
44
+ name,
45
+ autoFocus,
46
+ className,
47
+ ...labelProps
48
+ },
49
+ ref,
50
+ ) {
51
+ return (
52
+ <label
53
+ {...labelProps}
54
+ className={cx(
55
+ 'toggle',
56
+ size === 'sm' && 'toggle-sm',
57
+ checked && 'toggle-checked',
58
+ className,
59
+ )}
60
+ >
61
+ <input
62
+ ref={ref}
63
+ type="checkbox"
64
+ role="switch"
65
+ name={name}
66
+ checked={checked}
67
+ disabled={disabled}
68
+ autoFocus={autoFocus}
69
+ onChange={(e) => onChange(e.target.checked)}
70
+ className="toggle-input"
71
+ />
72
+ <span className="toggle-track" aria-hidden>
73
+ <span className="toggle-thumb" />
74
+ </span>
75
+ {label !== undefined && <span className="toggle-label">{label}</span>}
76
+ </label>
77
+ );
78
+ },
79
+ );