@kitn.ai/ui 0.28.0 → 0.29.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 (376) hide show
  1. package/README.md +1 -1
  2. package/dist/agent-tooling/construct/public.d.ts +15 -0
  3. package/dist/agent-tooling/construct/schema.d.ts +111 -0
  4. package/dist/construct-cli.es.js +3 -3
  5. package/dist/construct.d.ts +5 -0
  6. package/dist/construct.js +327 -0
  7. package/dist/core-C8fzo39E.js +1 -12
  8. package/dist/engine-javascript-C1x7zo1_.js +1 -141
  9. package/dist/mcp.es.js +1 -1
  10. package/package.json +16 -16
  11. package/bin/route.test.js +0 -58
  12. package/src/agent-tooling/README.md +0 -192
  13. package/src/agent-tooling/archetypes.ts +0 -205
  14. package/src/agent-tooling/catalog/README.md +0 -676
  15. package/src/agent-tooling/catalog/catalog-types.ts +0 -231
  16. package/src/agent-tooling/catalog/fabrications.ts +0 -96
  17. package/src/agent-tooling/catalog/invariants.ts +0 -284
  18. package/src/agent-tooling/catalog/labs-titles.ts +0 -114
  19. package/src/agent-tooling/catalog/scenarios.ts +0 -87
  20. package/src/agent-tooling/catalog/surfaces.ts +0 -347
  21. package/src/agent-tooling/construct/cli-entry.ts +0 -8
  22. package/src/agent-tooling/construct/cli.ts +0 -147
  23. package/src/agent-tooling/construct/codegen.ts +0 -1635
  24. package/src/agent-tooling/construct/construct.v1.schema.json +0 -319
  25. package/src/agent-tooling/construct/dev.ts +0 -148
  26. package/src/agent-tooling/construct/fixtures/demo-widget.construct.json +0 -7
  27. package/src/agent-tooling/construct/fixtures/ops-console.construct.json +0 -44
  28. package/src/agent-tooling/construct/fixtures/owner-widget.construct.json +0 -32
  29. package/src/agent-tooling/construct/schema.ts +0 -452
  30. package/src/agent-tooling/integrations/anthropic.ts +0 -442
  31. package/src/agent-tooling/integrations/cloudflare.ts +0 -218
  32. package/src/agent-tooling/integrations/langgraph.ts +0 -133
  33. package/src/agent-tooling/integrations/mastra.ts +0 -182
  34. package/src/agent-tooling/integrations/mock.ts +0 -148
  35. package/src/agent-tooling/integrations/ollama.ts +0 -97
  36. package/src/agent-tooling/integrations/openai.ts +0 -95
  37. package/src/agent-tooling/integrations/openrouter.ts +0 -82
  38. package/src/agent-tooling/integrations/pi.ts +0 -176
  39. package/src/agent-tooling/integrations/pydantic-ai.ts +0 -108
  40. package/src/agent-tooling/integrations/vercel-ai-sdk.ts +0 -398
  41. package/src/agent-tooling/mcp/css-raw.d.ts +0 -12
  42. package/src/agent-tooling/mcp/manifest.ts +0 -422
  43. package/src/agent-tooling/mcp/server.ts +0 -116
  44. package/src/agent-tooling/mcp/stdio.ts +0 -18
  45. package/src/agent-tooling/mcp/tools/construct.ts +0 -130
  46. package/src/agent-tooling/mcp/tools/debug.ts +0 -621
  47. package/src/agent-tooling/mcp/tools/reference.ts +0 -980
  48. package/src/agent-tooling/mcp/tools/scaffold.ts +0 -6708
  49. package/src/agent-tooling/mcp/tools/theme.ts +0 -456
  50. package/src/agent-tooling/mcp/tools/types.ts +0 -14
  51. package/src/agent-tooling/mcp/validate-args.ts +0 -141
  52. package/src/agent-tooling/recipes/composed-thread.ts +0 -714
  53. package/src/agent-tooling/recipes/index.ts +0 -22
  54. package/src/agent-tooling/recipes/types.ts +0 -32
  55. package/src/agent-tooling/registry.ts +0 -132
  56. package/src/agent-tooling/route-emit.ts +0 -305
  57. package/src/agent-tooling/types.ts +0 -390
  58. package/src/components/artifact-card.tsx +0 -120
  59. package/src/components/artifact.tsx +0 -914
  60. package/src/components/attachment-types.ts +0 -66
  61. package/src/components/attachments.tsx +0 -536
  62. package/src/components/audio-visualizer/audio-visualizer.voice-fixture.ts +0 -257
  63. package/src/components/audio-visualizer/aurora.glsl.ts +0 -330
  64. package/src/components/audio-visualizer/fit-scale.ts +0 -112
  65. package/src/components/audio-visualizer/index.tsx +0 -528
  66. package/src/components/audio-visualizer/labs/lab-choreography.ts +0 -187
  67. package/src/components/audio-visualizer/labs/lab-shaders.ts +0 -363
  68. package/src/components/audio-visualizer/labs/lab-visualizer.tsx +0 -102
  69. package/src/components/audio-visualizer/shader-canvas.tsx +0 -876
  70. package/src/components/audio-visualizer/sizes.ts +0 -54
  71. package/src/components/audio-visualizer/variant-aurora.tsx +0 -305
  72. package/src/components/audio-visualizer/variant-bar.tsx +0 -175
  73. package/src/components/audio-visualizer/variant-custom.tsx +0 -344
  74. package/src/components/audio-visualizer/variant-grid.tsx +0 -175
  75. package/src/components/audio-visualizer/variant-radial.tsx +0 -163
  76. package/src/components/audio-visualizer/variant-wave.tsx +0 -130
  77. package/src/components/audio-visualizer/wave.glsl.ts +0 -130
  78. package/src/components/card-fallback.tsx +0 -60
  79. package/src/components/card-renderer.tsx +0 -220
  80. package/src/components/card.tsx +0 -212
  81. package/src/components/chain-of-thought.tsx +0 -348
  82. package/src/components/chat-container.tsx +0 -89
  83. package/src/components/chat-scope-picker.tsx +0 -57
  84. package/src/components/chat-thread.tsx +0 -1014
  85. package/src/components/checkpoint.tsx +0 -88
  86. package/src/components/choice-card.tsx +0 -743
  87. package/src/components/coachmark.tsx +0 -249
  88. package/src/components/code-block.tsx +0 -181
  89. package/src/components/composer-dom.ts +0 -159
  90. package/src/components/composer-highlight.ts +0 -242
  91. package/src/components/composer-history.ts +0 -82
  92. package/src/components/composer.tsx +0 -1075
  93. package/src/components/confirm-card.tsx +0 -402
  94. package/src/components/context.tsx +0 -377
  95. package/src/components/conversation-item.tsx +0 -241
  96. package/src/components/conversation-list.tsx +0 -429
  97. package/src/components/conversation-panel.tsx +0 -118
  98. package/src/components/dismissed-stub.tsx +0 -80
  99. package/src/components/embed.tsx +0 -200
  100. package/src/components/empty.tsx +0 -177
  101. package/src/components/feedback-bar.tsx +0 -166
  102. package/src/components/file-tree.tsx +0 -530
  103. package/src/components/file-upload.tsx +0 -167
  104. package/src/components/form-widgets.tsx +0 -525
  105. package/src/components/form.tsx +0 -1296
  106. package/src/components/home-panel.tsx +0 -159
  107. package/src/components/image.tsx +0 -65
  108. package/src/components/link-preview.tsx +0 -195
  109. package/src/components/loader.tsx +0 -367
  110. package/src/components/markdown.tsx +0 -162
  111. package/src/components/message-skills.tsx +0 -40
  112. package/src/components/message.tsx +0 -765
  113. package/src/components/model-switcher.tsx +0 -132
  114. package/src/components/prompt-input.tsx +0 -188
  115. package/src/components/prompt-suggestion.tsx +0 -150
  116. package/src/components/reasoning.tsx +0 -293
  117. package/src/components/response-compare-types.ts +0 -152
  118. package/src/components/response-compare.tsx +0 -455
  119. package/src/components/response-stream.tsx +0 -109
  120. package/src/components/screen.tsx +0 -181
  121. package/src/components/scroll-button.tsx +0 -93
  122. package/src/components/source.tsx +0 -192
  123. package/src/components/tasks-card.tsx +0 -801
  124. package/src/components/text-shimmer.tsx +0 -37
  125. package/src/components/thinking-bar.tsx +0 -50
  126. package/src/components/thread.tsx +0 -228
  127. package/src/components/toast.tsx +0 -503
  128. package/src/components/tool-classify.ts +0 -26
  129. package/src/components/tool-types.ts +0 -49
  130. package/src/components/tool.tsx +0 -190
  131. package/src/components/use-card-resolution.ts +0 -44
  132. package/src/components/voice-input.tsx +0 -222
  133. package/src/components/voice-output.tsx +0 -242
  134. package/src/components/widget-tab-bar.tsx +0 -73
  135. package/src/components/workspace-shell.tsx +0 -285
  136. package/src/diagnostics/hook.ts +0 -352
  137. package/src/diagnostics/index.ts +0 -82
  138. package/src/diagnostics/report-request.ts +0 -296
  139. package/src/elements/agent-card.tsx +0 -67
  140. package/src/elements/artifact.tsx +0 -194
  141. package/src/elements/attachments.tsx +0 -140
  142. package/src/elements/audio-visualizer.tsx +0 -227
  143. package/src/elements/autoloader.ts +0 -89
  144. package/src/elements/avatar.tsx +0 -33
  145. package/src/elements/badge.tsx +0 -32
  146. package/src/elements/button.tsx +0 -149
  147. package/src/elements/card.tsx +0 -133
  148. package/src/elements/cards.tsx +0 -266
  149. package/src/elements/chain-of-thought.tsx +0 -141
  150. package/src/elements/chat-scope-picker.tsx +0 -65
  151. package/src/elements/chat-types.ts +0 -102
  152. package/src/elements/chat-workspace.tsx +0 -188
  153. package/src/elements/chat.tsx +0 -304
  154. package/src/elements/checkbox-group.tsx +0 -164
  155. package/src/elements/checkbox.tsx +0 -134
  156. package/src/elements/checkpoint.tsx +0 -47
  157. package/src/elements/choice.tsx +0 -100
  158. package/src/elements/coachmark.tsx +0 -90
  159. package/src/elements/code-block.tsx +0 -60
  160. package/src/elements/command.tsx +0 -197
  161. package/src/elements/compare.tsx +0 -111
  162. package/src/elements/compiled.css +0 -2
  163. package/src/elements/composer.tsx +0 -162
  164. package/src/elements/confirm-card.tsx +0 -76
  165. package/src/elements/context-meter.tsx +0 -107
  166. package/src/elements/conversation-item.tsx +0 -120
  167. package/src/elements/conversation-list.tsx +0 -203
  168. package/src/elements/css.ts +0 -5
  169. package/src/elements/default-input.tsx +0 -392
  170. package/src/elements/define-entry.ts +0 -12
  171. package/src/elements/define.tsx +0 -563
  172. package/src/elements/diagnostic-events.ts +0 -114
  173. package/src/elements/dialog.tsx +0 -145
  174. package/src/elements/disclosure.ts +0 -95
  175. package/src/elements/dock.tsx +0 -215
  176. package/src/elements/dropdown.tsx +0 -123
  177. package/src/elements/editable-label.tsx +0 -140
  178. package/src/elements/element-data-types.ts +0 -152
  179. package/src/elements/element-diagnostics.ts +0 -392
  180. package/src/elements/element-manifest.json +0 -354
  181. package/src/elements/element-nonscalar.json +0 -187
  182. package/src/elements/element-types.d.ts +0 -4353
  183. package/src/elements/embed.tsx +0 -35
  184. package/src/elements/empty.tsx +0 -29
  185. package/src/elements/feedback-bar.tsx +0 -66
  186. package/src/elements/file-tree.tsx +0 -62
  187. package/src/elements/file-upload.tsx +0 -44
  188. package/src/elements/form.tsx +0 -94
  189. package/src/elements/hover-card.tsx +0 -80
  190. package/src/elements/icon.tsx +0 -41
  191. package/src/elements/image.tsx +0 -32
  192. package/src/elements/input.tsx +0 -492
  193. package/src/elements/kbd.tsx +0 -45
  194. package/src/elements/link-preview.tsx +0 -34
  195. package/src/elements/loader.tsx +0 -25
  196. package/src/elements/markdown.tsx +0 -38
  197. package/src/elements/menu.tsx +0 -241
  198. package/src/elements/message-skills.tsx +0 -83
  199. package/src/elements/message.tsx +0 -361
  200. package/src/elements/model-switcher.tsx +0 -121
  201. package/src/elements/nav.tsx +0 -87
  202. package/src/elements/notice.tsx +0 -53
  203. package/src/elements/pane-grid.tsx +0 -111
  204. package/src/elements/pane-group.tsx +0 -119
  205. package/src/elements/pane.tsx +0 -129
  206. package/src/elements/popover.tsx +0 -81
  207. package/src/elements/progress-bar.tsx +0 -39
  208. package/src/elements/prompt-dock.tsx +0 -82
  209. package/src/elements/prompt-input.tsx +0 -240
  210. package/src/elements/prompt-suggestions.tsx +0 -113
  211. package/src/elements/radio-group.tsx +0 -129
  212. package/src/elements/reasoning.tsx +0 -71
  213. package/src/elements/register-impl.ts +0 -148
  214. package/src/elements/register.ts +0 -76
  215. package/src/elements/remote.tsx +0 -225
  216. package/src/elements/resizable.globals.d.ts +0 -36
  217. package/src/elements/resizable.tsx +0 -704
  218. package/src/elements/response-stream.tsx +0 -40
  219. package/src/elements/screen.tsx +0 -90
  220. package/src/elements/scroll-area.tsx +0 -33
  221. package/src/elements/scroll-button.tsx +0 -179
  222. package/src/elements/search.tsx +0 -185
  223. package/src/elements/segmented.tsx +0 -129
  224. package/src/elements/select.tsx +0 -165
  225. package/src/elements/separator.tsx +0 -36
  226. package/src/elements/setting-item.tsx +0 -50
  227. package/src/elements/settings-group.tsx +0 -37
  228. package/src/elements/skeleton.tsx +0 -45
  229. package/src/elements/slider.tsx +0 -171
  230. package/src/elements/slot-text.ts +0 -73
  231. package/src/elements/slots.ts +0 -787
  232. package/src/elements/source.tsx +0 -126
  233. package/src/elements/status.tsx +0 -42
  234. package/src/elements/styles.css +0 -328
  235. package/src/elements/switch.tsx +0 -118
  236. package/src/elements/tabs.tsx +0 -95
  237. package/src/elements/tasks.tsx +0 -103
  238. package/src/elements/text-shimmer.tsx +0 -28
  239. package/src/elements/thinking-bar.tsx +0 -43
  240. package/src/elements/thread.tsx +0 -139
  241. package/src/elements/toast.tsx +0 -106
  242. package/src/elements/tool.tsx +0 -78
  243. package/src/elements/tooltip.tsx +0 -85
  244. package/src/elements/validate-messages.ts +0 -76
  245. package/src/elements/voice-input.tsx +0 -100
  246. package/src/elements/voice-output.tsx +0 -82
  247. package/src/index.ts +0 -430
  248. package/src/primitives/audio-bands.ts +0 -174
  249. package/src/primitives/card-component-types.ts +0 -63
  250. package/src/primitives/card-contract.ts +0 -80
  251. package/src/primitives/card-data-types.ts +0 -361
  252. package/src/primitives/card-host.tsx +0 -37
  253. package/src/primitives/card-recovery.ts +0 -160
  254. package/src/primitives/card-registry.tsx +0 -78
  255. package/src/primitives/card-resolution.ts +0 -36
  256. package/src/primitives/card-routing.ts +0 -85
  257. package/src/primitives/card-schemas/artifact.schema.json +0 -92
  258. package/src/primitives/card-schemas/card-envelope.schema.json +0 -14
  259. package/src/primitives/card-schemas/card-event.schema.json +0 -12
  260. package/src/primitives/card-schemas/choice.schema.json +0 -75
  261. package/src/primitives/card-schemas/confirm.schema.json +0 -65
  262. package/src/primitives/card-schemas/embed.schema.json +0 -63
  263. package/src/primitives/card-schemas/form.result.schema.json +0 -7
  264. package/src/primitives/card-schemas/form.schema.json +0 -53
  265. package/src/primitives/card-schemas/link.schema.json +0 -54
  266. package/src/primitives/card-schemas/tasks.result.schema.json +0 -16
  267. package/src/primitives/card-schemas/tasks.schema.json +0 -83
  268. package/src/primitives/card-tags.ts +0 -61
  269. package/src/primitives/card-validate-cards.ts +0 -255
  270. package/src/primitives/card-validate-schemas.ts +0 -58
  271. package/src/primitives/card-validate.ts +0 -131
  272. package/src/primitives/chat-config.tsx +0 -103
  273. package/src/primitives/composer-model.ts +0 -49
  274. package/src/primitives/composer-triggers.ts +0 -35
  275. package/src/primitives/controllable.ts +0 -21
  276. package/src/primitives/conversation-store.ts +0 -248
  277. package/src/primitives/create-kai-chat.ts +0 -66
  278. package/src/primitives/create-tween.ts +0 -266
  279. package/src/primitives/embed-providers.ts +0 -254
  280. package/src/primitives/field-mask.ts +0 -256
  281. package/src/primitives/field-semantics.ts +0 -115
  282. package/src/primitives/highlighter.ts +0 -157
  283. package/src/primitives/input-mask.ts +0 -853
  284. package/src/primitives/link-preview.ts +0 -87
  285. package/src/primitives/message-feedback.ts +0 -124
  286. package/src/primitives/pdf-preview.ts +0 -121
  287. package/src/primitives/toast-store.ts +0 -338
  288. package/src/primitives/url-scheme-policy.ts +0 -70
  289. package/src/primitives/use-audio-analysis.ts +0 -340
  290. package/src/primitives/use-auto-resize.ts +0 -31
  291. package/src/primitives/use-resize-observer.ts +0 -45
  292. package/src/primitives/use-sequencer.ts +0 -72
  293. package/src/primitives/use-speech-recognition.ts +0 -146
  294. package/src/primitives/use-stick-to-bottom.ts +0 -75
  295. package/src/primitives/use-text-stream.ts +0 -143
  296. package/src/primitives/use-voice-recorder.ts +0 -62
  297. package/src/primitives/visualizer-sequences.ts +0 -350
  298. package/src/remote/host-embed.ts +0 -345
  299. package/src/remote/index.ts +0 -2
  300. package/src/remote/origin.ts +0 -30
  301. package/src/remote/provider-runtime.ts +0 -262
  302. package/src/remote/provider.ts +0 -2
  303. package/src/remote/validate.ts +0 -22
  304. package/src/remote/version.ts +0 -12
  305. package/src/remote/wire.ts +0 -48
  306. package/src/schemas/from-tool-call.ts +0 -151
  307. package/src/schemas/index.ts +0 -341
  308. package/src/schemas/provider-subsets.ts +0 -538
  309. package/src/schemas/registry.ts +0 -355
  310. package/src/schemas/tool-defs.ts +0 -793
  311. package/src/solid.ts +0 -173
  312. package/src/state/index.ts +0 -44
  313. package/src/state/messages.ts +0 -53
  314. package/src/state/mock.ts +0 -297
  315. package/src/state/parts.ts +0 -295
  316. package/src/state/persistence.ts +0 -180
  317. package/src/state/stream.ts +0 -246
  318. package/src/state/suggestions.ts +0 -9
  319. package/src/state/threads.ts +0 -142
  320. package/src/test-utils/fake-clock.ts +0 -88
  321. package/src/types.ts +0 -95
  322. package/src/ui/action-icons.ts +0 -53
  323. package/src/ui/agent-card.tsx +0 -218
  324. package/src/ui/avatar.tsx +0 -23
  325. package/src/ui/badge.tsx +0 -21
  326. package/src/ui/button.tsx +0 -49
  327. package/src/ui/card.tsx +0 -245
  328. package/src/ui/checkbox-group.tsx +0 -153
  329. package/src/ui/checkbox.tsx +0 -63
  330. package/src/ui/collapsible.tsx +0 -163
  331. package/src/ui/command.tsx +0 -103
  332. package/src/ui/dialog.tsx +0 -223
  333. package/src/ui/dock.tsx +0 -630
  334. package/src/ui/dropdown.tsx +0 -636
  335. package/src/ui/editable-label.tsx +0 -112
  336. package/src/ui/hover-card.tsx +0 -345
  337. package/src/ui/icon.tsx +0 -167
  338. package/src/ui/input.tsx +0 -391
  339. package/src/ui/kbd.tsx +0 -118
  340. package/src/ui/nav.tsx +0 -282
  341. package/src/ui/notice.tsx +0 -84
  342. package/src/ui/overlay.tsx +0 -277
  343. package/src/ui/pane-grid.tsx +0 -117
  344. package/src/ui/pane-group.tsx +0 -291
  345. package/src/ui/pane.tsx +0 -193
  346. package/src/ui/popover.tsx +0 -106
  347. package/src/ui/progress-bar.tsx +0 -83
  348. package/src/ui/prompt-dock.tsx +0 -145
  349. package/src/ui/radio.tsx +0 -150
  350. package/src/ui/resizable.tsx +0 -693
  351. package/src/ui/scroll-area.tsx +0 -26
  352. package/src/ui/segmented.tsx +0 -109
  353. package/src/ui/select.tsx +0 -168
  354. package/src/ui/separator.tsx +0 -10
  355. package/src/ui/settings-group.tsx +0 -67
  356. package/src/ui/skeleton.tsx +0 -73
  357. package/src/ui/slider.tsx +0 -178
  358. package/src/ui/status.tsx +0 -48
  359. package/src/ui/switch.tsx +0 -119
  360. package/src/ui/tabs.tsx +0 -168
  361. package/src/ui/textarea.tsx +0 -21
  362. package/src/ui/tooltip.tsx +0 -118
  363. package/src/utils/cn.ts +0 -30
  364. package/src/wire/chunk.ts +0 -248
  365. package/src/wire/consume.ts +0 -599
  366. package/src/wire/diagnostics.ts +0 -727
  367. package/src/wire/encode-probe.ts +0 -214
  368. package/src/wire/encode.ts +0 -947
  369. package/src/wire/files.ts +0 -342
  370. package/src/wire/formats/anthropic.ts +0 -274
  371. package/src/wire/formats/openai.ts +0 -228
  372. package/src/wire/index.ts +0 -95
  373. package/src/wire/media-types.ts +0 -344
  374. package/src/wire/read.ts +0 -396
  375. package/src/wire/sink-helpers.ts +0 -50
  376. package/src/wire/sse.ts +0 -153
@@ -1,165 +0,0 @@
1
- import { createEffect, createSignal, untrack } from 'solid-js';
2
- import { defineWebComponent } from './define';
3
- import { Select } from '../ui/select';
4
- // Public shape of the `options` prop; lives in ./element-data-types so the ROOT
5
- // entry can re-export it (see that file's header).
6
- import type { KaiSelectOption } from './element-data-types';
7
-
8
- interface Props extends Record<string, unknown> {
9
- /** The choices, in display order. Set as a JS PROPERTY (array), never an attribute.
10
- * Rendered in full: the kit never truncates, re-orders or de-duplicates them. */
11
- options: KaiSelectOption[];
12
- /** Controlled selected value. Settable and reflected to the `value` attribute.
13
- * `el.value = 'high'` drives it; choosing an option updates it and fires
14
- * `kai-change`. Read `el.value` for live state; for a `multiple` select read
15
- * `el.values` instead. */
16
- value?: string;
17
- /** Text for a leading, disabled, empty option: the "nothing chosen yet" row.
18
- * Omitted means no such row at all; there is no default wording, because inventing
19
- * one would put words in your UI. */
20
- placeholder?: string;
21
- /** Allow more than one selection. Turns the control into the platform's list box, so
22
- * the kit's chevron is not drawn. */
23
- multiple?: boolean;
24
- /** Force the invalid (destructive-border) state. */
25
- invalid?: boolean;
26
- /** Disable interaction. */
27
- disabled?: boolean;
28
- /** Set the native `required` attribute, and nothing more. Whether an empty select is
29
- * an error is the application's rule, not the kit's. */
30
- required?: boolean;
31
- /** Accessible label for the control. */
32
- label?: string;
33
- /** Form-control name, for a native form submit. */
34
- name?: string;
35
- }
36
-
37
- /** Events fired by `<kai-select>`. */
38
- interface Events {
39
- /** A choice was made. `value` is the first selected option (empty when nothing is
40
- * selected); `values` is every selected option, which is what a `multiple` select
41
- * needs. Both are always present, so neither shape silently loses the other. */
42
- 'kai-change': { value: string; values: string[] };
43
- }
44
-
45
- /**
46
- * `<kai-select>` — a select over a REAL native `<select>`, in the kit's field box with
47
- * the kit's own chevron. Native, not a hand-built listbox: that is what keeps the
48
- * platform picker on mobile, type-ahead on desktop, form participation and the OS
49
- * accessibility tree.
50
- *
51
- * The dropdown list itself stays OS chrome — it renders outside the page and no
52
- * stylesheet reaches it. What the element does do is make it follow the kit's
53
- * light/dark mode rather than the OS's.
54
- *
55
- * Feed it `options` (a JS-property array of `{ value, label?, disabled? }`), drive and
56
- * read the selection with the `value` property (settable + reflected to the `value`
57
- * attribute, so `:host([value])` and `el.value` see live state), and listen for
58
- * `kai-change`.
59
- *
60
- * Re-rendering follows the kit's reactivity contract: hand it a NEW array reference,
61
- * and a new object for any option whose content changed — the list is
62
- * reference-keyed, so mutating an option in place changes nothing on screen.
63
- *
64
- * ```html
65
- * <kai-select value="high" placeholder="Choose a severity…" label="Severity"></kai-select>
66
- * <script type="module">
67
- * import '@kitn.ai/ui/elements';
68
- * const select = document.querySelector('kai-select');
69
- * // ARRAY prop — a JS property, never an attribute.
70
- * select.options = [
71
- * { value: 'low', label: 'Low' },
72
- * { value: 'high', label: 'High priority' },
73
- * { value: 'legacy', label: 'Legacy', disabled: true },
74
- * ];
75
- * select.addEventListener('kai-change', (e) => console.log(e.detail.value, e.detail.values));
76
- * select.value = 'low'; // drive it (no kai-change — the host already knows)
77
- * </script>
78
- * ```
79
- */
80
- defineWebComponent<Props, Events>('kai-select', {
81
- options: [],
82
- value: undefined,
83
- placeholder: undefined,
84
- multiple: undefined,
85
- invalid: undefined,
86
- disabled: undefined,
87
- required: undefined,
88
- label: undefined,
89
- name: undefined,
90
- }, (props, ctx) => {
91
- const { element, dispatch, flag, expose } = ctx;
92
-
93
- // Lift the selection into the facade and drive Select CONTROLLED so the host can read
94
- // it (`el.value` / `:host([value])`) and set it after mount. Seed from the `value`
95
- // property/attribute present on mount; nothing is auto-selected, because `options`
96
- // normally arrives as a property AFTER upgrade (kai-radio-group's structure).
97
- const seed = (props.value as string | undefined) ?? element.getAttribute('value') ?? '';
98
- const [values, setValues] = createSignal<string[]>(seed ? [seed] : []);
99
- const first = () => values()[0] ?? '';
100
-
101
- // Coerce anything arriving through the `value` setter (a JS assignment, or the
102
- // attributeChangedCallback write-back the reflect effect below triggers) to a string,
103
- // falling back to the live attribute when nullish so the write-back equals the signal
104
- // and the guards absorb it — no attr⇄prop feedback loop.
105
- const coerce = (v: unknown): string =>
106
- v == null ? (element.getAttribute('value') ?? '') : String(v);
107
-
108
- // Apply a new selection and fire kai-change once (the user-choice path).
109
- const apply = (next: string[]) => {
110
- const prev = untrack(values);
111
- if (prev.length === next.length && prev.every((v, i) => v === next[i])) return;
112
- setValues(next);
113
- dispatch('kai-change', { value: next[0] ?? '', values: next });
114
- };
115
-
116
- Object.defineProperty(element, 'value', {
117
- get: () => first(),
118
- set: (v: unknown) => {
119
- const next = coerce(v);
120
- if (untrack(first) !== next) setValues(next ? [next] : []);
121
- },
122
- configurable: true,
123
- enumerable: true,
124
- });
125
-
126
- // The multi-selection read/write side. `value` alone cannot represent it, and
127
- // returning only the first option from a `multiple` select would be a silent drop.
128
- Object.defineProperty(element, 'values', {
129
- get: () => values(),
130
- set: (v: unknown) => setValues(Array.isArray(v) ? v.map(String) : []),
131
- configurable: true,
132
- enumerable: true,
133
- });
134
-
135
- // Reflect the primary value → the `[value]` host attribute (for `:host([value])`).
136
- createEffect(() => {
137
- const v = first();
138
- if (v) {
139
- if (element.getAttribute('value') !== v) element.setAttribute('value', v);
140
- } else if (element.hasAttribute('value')) {
141
- element.removeAttribute('value');
142
- }
143
- });
144
-
145
- expose({
146
- /** Focus the inner select (the host element can't reach it). */
147
- focus: (options?: FocusOptions) =>
148
- element.shadowRoot?.querySelector<HTMLSelectElement>('select')?.focus(options),
149
- });
150
-
151
- return (
152
- <Select
153
- options={(props.options ?? []) as KaiSelectOption[]}
154
- value={values()}
155
- placeholder={props.placeholder as string | undefined}
156
- multiple={flag('multiple')}
157
- invalid={flag('invalid')}
158
- disabled={flag('disabled')}
159
- required={flag('required')}
160
- aria-label={props.label as string | undefined}
161
- name={props.name as string | undefined}
162
- onChange={(e) => apply([...e.currentTarget.selectedOptions].map((o) => o.value))}
163
- />
164
- );
165
- });
@@ -1,36 +0,0 @@
1
- import { Separator } from '../ui/separator';
2
- import { defineWebComponent } from './define';
3
-
4
- interface Props extends Record<string, unknown> {
5
- /** `horizontal` (default, block + full-width) or `vertical` (a rule inside a
6
- * flex/grid row, stretching to the row height). */
7
- orientation?: 'horizontal' | 'vertical';
8
- }
9
-
10
- /**
11
- * `<kai-separator>` — a themed divider between groups of content (toolbar
12
- * sections, menu groups, header/sidebar splits). Carries `role="separator"`.
13
- * Restyle via `::part(separator)`.
14
- *
15
- * ```html
16
- * <kai-separator></kai-separator>
17
- * <div style="display:flex; gap:.5rem">
18
- * <span>A</span><kai-separator orientation="vertical"></kai-separator><span>B</span>
19
- * </div>
20
- * ```
21
- */
22
- defineWebComponent<Props>('kai-separator', {
23
- orientation: 'horizontal',
24
- }, (props) => {
25
- const vertical = () => props.orientation === 'vertical';
26
- return (
27
- <>
28
- {/* The host owns its layout box: a horizontal rule is block + full-width;
29
- a vertical rule is an inline-block flex item that stretches to the row. */}
30
- <style>{vertical()
31
- ? ':host{display:inline-block;align-self:stretch}'
32
- : ':host{display:block}'}</style>
33
- <Separator orientation={vertical() ? 'vertical' : 'horizontal'} part="separator" />
34
- </>
35
- );
36
- });
@@ -1,50 +0,0 @@
1
- import { createSignal, onCleanup, onMount } from 'solid-js';
2
- import { SettingItem } from '../ui/settings-group';
3
- import { defineWebComponent } from './define';
4
-
5
- interface Props extends Record<string, unknown> {
6
- /** Row label (primary text). Attribute: `label`. */
7
- label?: string;
8
- /** Optional secondary description under the label. Attribute: `description`. */
9
- description?: string;
10
- }
11
-
12
- /**
13
- * `<kai-setting-item>` — one row inside a `<kai-settings-group>`: a left
14
- * label/description block and an optional right-aligned control. Slot the control
15
- * (a `<kai-switch>`, segmented control, select, …) into `slot="control"`; omit it
16
- * for a plain label row.
17
- *
18
- * Themeable `::part`s: `label` (the label/description block) and `control`.
19
- *
20
- * ```html
21
- * <kai-setting-item label="Reduce motion" description="Minimize animations.">
22
- * <kai-switch slot="control"></kai-switch>
23
- * </kai-setting-item>
24
- * ```
25
- */
26
- defineWebComponent<Props>('kai-setting-item', {
27
- label: '',
28
- description: undefined,
29
- }, (props, { element }) => {
30
- // The control region only renders when `slot="control"` is actually filled, so
31
- // a plain label row has no stray right-side wrapper. An empty `<slot>` is always
32
- // a truthy node, so we track occupancy and gate on it (the kai-card approach).
33
- // Re-read on child/attribute mutations so a late-slotted control lights up.
34
- const [hasControl, setHasControl] = createSignal(false);
35
- onMount(() => {
36
- const read = () => setHasControl(!!element.querySelector(':scope > [slot="control"]'));
37
- read();
38
- const observer = new MutationObserver(read);
39
- observer.observe(element, { childList: true, attributes: true, subtree: true });
40
- onCleanup(() => observer.disconnect());
41
- });
42
-
43
- return (
44
- <SettingItem
45
- label={props.label ?? ''}
46
- description={props.description}
47
- control={hasControl() ? <slot name="control" /> : undefined}
48
- />
49
- );
50
- });
@@ -1,37 +0,0 @@
1
- import { SettingsGroup } from '../ui/settings-group';
2
- import { defineWebComponent } from './define';
3
-
4
- interface Props extends Record<string, unknown> {
5
- /** Small section heading shown above the card. Attribute: `heading`. */
6
- heading?: string;
7
- /** Optional muted description under the heading. Attribute: `description`. */
8
- description?: string;
9
- }
10
-
11
- /**
12
- * `<kai-settings-group>` — a settings section: a small heading + optional muted
13
- * description over a bordered, rounded card that stacks `<kai-setting-item>` rows
14
- * with hairline dividers. Put the rows as light-DOM children (the default slot).
15
- *
16
- * Host-agnostic chrome: the SAME group drops into a modal or a full settings
17
- * page; only the rows change per app.
18
- *
19
- * Themeable `::part`s: `header` (the heading/description block) and `body` (the
20
- * rows card).
21
- *
22
- * ```html
23
- * <kai-settings-group heading="Appearance" description="How the app looks.">
24
- * <kai-setting-item label="Theme">
25
- * <kai-switch slot="control"></kai-switch>
26
- * </kai-setting-item>
27
- * </kai-settings-group>
28
- * ```
29
- */
30
- defineWebComponent<Props>('kai-settings-group', {
31
- heading: '',
32
- description: undefined,
33
- }, (props) => (
34
- <SettingsGroup heading={props.heading ?? ''} description={props.description}>
35
- <slot />
36
- </SettingsGroup>
37
- ));
@@ -1,45 +0,0 @@
1
- import { Skeleton, type SkeletonVariant } from '../ui/skeleton';
2
- import { defineWebComponent } from './define';
3
-
4
- interface Props extends Record<string, unknown> {
5
- /** `text` (one or more lines), `rect` (a block), or `circle` (round).
6
- * Defaults to `text`. */
7
- variant?: SkeletonVariant;
8
- /** CSS width (e.g. `'12rem'`, `'60%'`). Defaults to full width (responsive);
9
- * for `circle` it is the diameter. */
10
- width?: string;
11
- /** CSS height. Defaults per variant (a text line height; circle = width). */
12
- height?: string;
13
- /** `text` only: number of lines; the last is shorter. Defaults to 1. */
14
- lines?: number;
15
- }
16
-
17
- /**
18
- * `<kai-skeleton>` — a pulsing loading placeholder that preserves layout while
19
- * content arrives. Responsive by default (fills its container's width). It is
20
- * prop-driven because utility classes can't cross the shadow boundary: pick a
21
- * `variant` and optionally set `width` / `height` / `lines`.
22
- *
23
- * ```html
24
- * <kai-skeleton variant="text" lines="3"></kai-skeleton>
25
- * <kai-skeleton variant="circle" width="2.5rem"></kai-skeleton>
26
- * <kai-skeleton variant="rect" height="10rem"></kai-skeleton>
27
- * ```
28
- * Recolor by overriding the `--color-muted` token.
29
- */
30
- defineWebComponent<Props>('kai-skeleton', {
31
- variant: 'text',
32
- width: undefined,
33
- height: undefined,
34
- lines: undefined,
35
- }, (props) => (
36
- <>
37
- <style>{':host{display:block}'}</style>
38
- <Skeleton
39
- variant={props.variant ?? 'text'}
40
- width={props.width}
41
- height={props.height}
42
- lines={props.lines != null ? Number(props.lines) : undefined}
43
- />
44
- </>
45
- ));
@@ -1,171 +0,0 @@
1
- import { createEffect, createSignal, untrack } from 'solid-js';
2
- import { defineWebComponent } from './define';
3
- import { Slider } from '../ui/slider';
4
-
5
- interface Props extends Record<string, unknown> {
6
- /** Lowest selectable value. Required: a range with no bounds is a guess, and the
7
- * guess belongs to whoever knows what the number means. */
8
- min?: number;
9
- /** Highest selectable value. Required, for the same reason as `min`. */
10
- max?: number;
11
- /** Granularity. Omitted means the native default of 1; `any` means continuous. */
12
- step?: number | 'any';
13
- /** Controlled value. Settable and reflected to the `value` attribute. `el.value = 40`
14
- * drives it; dragging updates it and fires `kai-input` per step, `kai-change` on
15
- * release. Read `el.value` for live state. */
16
- value?: number;
17
- /** Disable interaction. */
18
- disabled?: boolean;
19
- /** Accessible label for the slider. */
20
- label?: string;
21
- /** Form-control name, for a native form submit. */
22
- name?: string;
23
- /** Show the current value beside the track. Off by default.
24
- *
25
- * Two ways in, because one of them is not a scalar. As a bare ATTRIBUTE
26
- * (`<kai-slider value-label>`) it renders the raw number. As a JS PROPERTY it also
27
- * accepts a formatter function (`el.valueLabel = (v) => v + '%'`), for a slider that
28
- * is not counting bare numbers. A function cannot survive an attribute, so that half
29
- * is property-only.
30
- *
31
- * The readout is hidden from assistive tech: the slider already reports the same
32
- * number, and an exposed copy would be announced twice. */
33
- valueLabel?: boolean | ((value: number) => string);
34
- }
35
-
36
- /** Events fired by `<kai-slider>`. */
37
- interface Events {
38
- /** The thumb moved. Fires per step during a drag or a key press. */
39
- 'kai-input': { value: number };
40
- /** The value was committed: pointer released, or a key press finished. */
41
- 'kai-change': { value: number };
42
- }
43
-
44
- /**
45
- * `<kai-slider>` — a slider over a real `<input type="range">`, with the kit's filled
46
- * track and thumb. Arrows, Home, End and PageUp/PageDown all work because the control
47
- * underneath is the browser's, not a reimplementation.
48
- *
49
- * Give it `min` and `max` (there are no defaults on purpose), drive and read the
50
- * position with the `value` property, and listen for `kai-input` while dragging or
51
- * `kai-change` on release.
52
- *
53
- * ```html
54
- * <kai-slider min="0" max="100" step="5" value="40" label="Temperature"></kai-slider>
55
- * <script type="module">
56
- * import '@kitn.ai/ui/elements';
57
- * const slider = document.querySelector('kai-slider');
58
- * slider.addEventListener('kai-input', (e) => console.log(e.detail.value));
59
- * slider.value = 70; // drive it (no event — the host already knows)
60
- * </script>
61
- * ```
62
- */
63
- defineWebComponent<Props, Events>('kai-slider', {
64
- min: undefined,
65
- max: undefined,
66
- step: undefined,
67
- value: undefined,
68
- disabled: undefined,
69
- label: undefined,
70
- name: undefined,
71
- valueLabel: undefined,
72
- }, (props, ctx) => {
73
- const { element, dispatch, flag, expose } = ctx;
74
-
75
- // `Number(null)` is 0 and `Number('')` is 0, both FINITE, so a naive
76
- // `Number.isFinite(Number(v))` treats a missing attribute as a real zero and the
77
- // fallbacks below never fire. Reject the empty cases before coercing.
78
- const num = (v: unknown, fallback: number): number => {
79
- if (v == null || (typeof v === 'string' && v.trim() === '')) return fallback;
80
- const n = Number(v);
81
- return Number.isFinite(n) ? n : fallback;
82
- };
83
- // No invented bounds: these mirror the native `<input type="range">` defaults, which
84
- // is what an author who wrote neither attribute is already going to get.
85
- const min = () => num(props.min, 0);
86
- const max = () => num(props.max, 100);
87
-
88
- // Lift the position into the facade and drive Slider CONTROLLED so the host can read
89
- // it (`el.value` / `:host([value])`) and set it after mount. Seed from the `value`
90
- // property/attribute present on mount, falling back to the midpoint — HTML's own rule
91
- // for a range with no value. kai-checkbox / kai-radio-group's structure, deliberately.
92
- const [value, setValue] = createSignal(
93
- props.value != null
94
- ? num(props.value, (min() + max()) / 2)
95
- : num(element.getAttribute('value'), (min() + max()) / 2),
96
- );
97
-
98
- // Coerce anything arriving through the `value` setter (a JS assignment, or the
99
- // write-back `attributeChangedCallback` fires when the reflect effect below writes the
100
- // attribute) to a number, falling back to the live attribute when nullish so the
101
- // write-back equals the signal and the guard absorbs it — no attr⇄prop feedback loop.
102
- const coerce = (v: unknown): number =>
103
- v == null ? num(element.getAttribute('value'), untrack(value)) : num(v, untrack(value));
104
-
105
- // Apply a new value and fire once (the user path). No-op while disabled.
106
- const apply = (next: number, type: 'kai-input' | 'kai-change') => {
107
- if (flag('disabled')) return;
108
- // kai-change fires on commit EVEN IF the value equals the last one this element
109
- // reported, because "you let go here" is information the host cannot derive; the
110
- // equality guard applies to the per-step stream only.
111
- if (type === 'kai-input' && untrack(value) === next) return;
112
- setValue(next);
113
- dispatch(type, { value: next });
114
- };
115
-
116
- // Reads return LIVE state; host writes drive it WITHOUT firing an event — the host
117
- // already knows what it set. The equality guard kills the reflect write-back.
118
- Object.defineProperty(element, 'value', {
119
- get: () => value(),
120
- set: (v: unknown) => { const next = coerce(v); if (untrack(value) !== next) setValue(next); },
121
- configurable: true,
122
- enumerable: true,
123
- });
124
-
125
- // Reflect internal value → the `[value]` host attribute (for `:host([value])`).
126
- createEffect(() => {
127
- const v = String(value());
128
- if (element.getAttribute('value') !== v) element.setAttribute('value', v);
129
- });
130
-
131
- expose({
132
- /** Focus the inner range input (the host element can't reach it). */
133
- focus: (options?: FocusOptions) =>
134
- element.shadowRoot?.querySelector<HTMLInputElement>('input[type="range"]')?.focus(options),
135
- });
136
-
137
- // `step` arrives as a string when it came from an attribute. Resolve the one literal
138
- // the spec allows (`any`, continuous) and treat everything else as a number.
139
- const step = (): number | 'any' | undefined => {
140
- const raw = props.step;
141
- if (raw == null) return undefined;
142
- if (String(raw) === 'any') return 'any';
143
- const n = Number(raw);
144
- return Number.isFinite(n) ? n : undefined;
145
- };
146
-
147
- // `valueLabel` arrives either as a bare attribute (the boolean half) or as a property
148
- // holding a formatter (the half an attribute cannot carry). `flag` handles the first,
149
- // a typeof check the second.
150
- const valueLabel = (): boolean | ((v: number) => string) => {
151
- const raw = props.valueLabel;
152
- if (typeof raw === 'function') return raw as (v: number) => string;
153
- return flag('valueLabel');
154
- };
155
-
156
- // Base sets `:host{display:block}`, which is right for a full-width track.
157
- return (
158
- <Slider
159
- min={min()}
160
- max={max()}
161
- step={step()}
162
- value={value()}
163
- disabled={flag('disabled')}
164
- aria-label={props.label as string | undefined}
165
- name={props.name as string | undefined}
166
- valueLabel={valueLabel()}
167
- onInput={(e) => apply(e.currentTarget.valueAsNumber, 'kai-input')}
168
- onChange={(e) => apply(e.currentTarget.valueAsNumber, 'kai-change')}
169
- />
170
- );
171
- });
@@ -1,73 +0,0 @@
1
- import { createSignal, type Accessor } from 'solid-js';
2
-
3
- /**
4
- * Track whether a `<slot>` is projecting VISIBLE TEXT, so a facade can tell
5
- * "this control shows its own name" from "this control is icon-only and needs
6
- * one".
7
- *
8
- * WHY IT EXISTS. Slotted light-DOM text is part of the flattened tree, so it
9
- * names the shadow `<button>` all by itself — measured, not assumed:
10
- * `scripts/probe-button-accessible-name.mjs` reads chromium's AX tree and
11
- * `<kai-button>Save</kai-button>` computes the name "Save" from `contents`,
12
- * with no `aria-label` anywhere. An `aria-label` on top of that does not add a
13
- * name, it REPLACES one, and a replacement that disagrees with the visible text
14
- * is a WCAG 2.5.3 (Label in Name) failure: speech-input users say what they
15
- * see, so a button reading "Save" whose accessible name is "Submit" cannot be
16
- * activated by voice at all. `kai-checkpoint` already resolved this the same
17
- * way; this is the reusable form of that decision.
18
- *
19
- * WHY A SIGNAL AND NOT A ONE-OFF READ. The facade renders while the HTML parser
20
- * is still inside the element's own tag, so the light DOM is usually EMPTY at
21
- * that moment and any synchronous read of `element.childNodes` reports "no text"
22
- * for the most common case there is. `slotchange` is the event that tells the
23
- * truth, and it fires on the initial assignment too.
24
- *
25
- * The initial value is therefore `false`, meaning "assume icon-only", which
26
- * makes the pre-`slotchange` frame emit the `aria-label`. That direction is
27
- * deliberate: an overridden name is a defect, an ABSENT name is a worse one, so
28
- * the transient state is the named one. `slotchange` is queued as a mutation
29
- * observer microtask, so it lands before paint and no assistive technology
30
- * observes the transient.
31
- */
32
- export function createSlotText(options: {
33
- /**
34
- * Follow `assignedNodes({ flatten: true })`, which descends into nested
35
- * light-DOM `<slot>` elements (a consumer wrapping the element in their OWN
36
- * component and forwarding a slot) — and, when nothing is assigned, returns
37
- * the slot's FALLBACK content.
38
- *
39
- * Only safe on a slot whose fallback is exactly the visible label. Do NOT set
40
- * it on a slot whose fallback can render a non-name (an icon that happens to
41
- * be plain text, say): the fallback would count as visible text and suppress
42
- * the very `aria-label` that names the control. `kai-button`'s default slot
43
- * has no fallback at all, so flatten there only buys the nested case;
44
- * `kai-menu`'s trigger slot falls back to an icon, so it must not use it.
45
- */
46
- flatten?: boolean;
47
- } = {}): {
48
- /** Whether the slot is currently showing text. */
49
- hasText: Accessor<boolean>;
50
- /** `ref` for the `<slot>`. Re-reads on every `slotchange`. */
51
- ref: (slot: HTMLSlotElement) => void;
52
- } {
53
- const [hasText, setHasText] = createSignal(false);
54
-
55
- const read = (slot: HTMLSlotElement) => {
56
- const nodes = slot.assignedNodes({ flatten: options.flatten ?? false });
57
- setHasText(nodes.some((node) => (node.textContent ?? '').trim() !== ''));
58
- };
59
-
60
- return {
61
- hasText,
62
- ref: (slot: HTMLSlotElement) => {
63
- // A slot outside a shadow root assigns nothing, and this ref runs before
64
- // solid inserts it — so this first read is normally `false` and the
65
- // slotchange below is what carries the answer. It is here for the case
66
- // where the element is created with its children already in place
67
- // (`el.textContent = 'Save'` then appended), where no assignment CHANGE
68
- // happens after insertion and slotchange may never fire.
69
- read(slot);
70
- slot.addEventListener('slotchange', () => read(slot));
71
- },
72
- };
73
- }