@kitn.ai/ui 0.29.0 → 0.30.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 (243) hide show
  1. package/README.md +11 -7
  2. package/dist/{Icon-DObhsRtm.js → Icon-BzBET3E-.js} +1 -1
  3. package/dist/{action-icons-CcgNN2oT.js → action-icons-DaW2pU6m.js} +1 -1
  4. package/dist/arrow-down-D783iMJj.js +1 -0
  5. package/dist/arrow-left-0VLM5kyg.js +1 -0
  6. package/dist/artifact-DGjzHYUT.js +1 -0
  7. package/dist/{attachments-Qr4kg-2b.js → attachments-YvXHlg88.js} +1 -1
  8. package/dist/{audio-visualizer-DToYdfSc.js → audio-visualizer-9lz5IHsL.js} +1 -1
  9. package/dist/{badge-CdEu_jn2.js → badge-Dh_vp8A5.js} +1 -1
  10. package/dist/{bell-DQAAOpDz.js → bell-CT7_WUwS.js} +1 -1
  11. package/dist/{button-DkuOnGLy.js → button-C_3te6fm.js} +1 -1
  12. package/dist/{card-renderer-Jx70m6_l.js → card-renderer-DZVaGH2e.js} +1 -1
  13. package/dist/check-CiEOVnEN.js +1 -0
  14. package/dist/{checkbox-D7iRB3nL.js → checkbox-Bu2T2e0U.js} +1 -1
  15. package/dist/{checkbox-group-B2_rpoPM.js → checkbox-group-BiryEXPQ.js} +1 -1
  16. package/dist/chevron-down-CSobuZRG.js +1 -0
  17. package/dist/chevron-right-DR9ZAP-2.js +1 -0
  18. package/dist/{choice-card-m0BYqqOK.js → choice-card-CM6IjkmL.js} +1 -1
  19. package/dist/circle-BC66EYF7.js +1 -0
  20. package/dist/circle-check-BqmahW0O.js +1 -0
  21. package/dist/{circle-x-BPG0iPst.js → circle-x-Bk-dA5Wf.js} +1 -1
  22. package/dist/{code-block-ClMLKb7C.js → code-block-B26t-Q7q.js} +1 -1
  23. package/dist/{collapsible-B4DlWicL.js → collapsible-Bhc636Cf.js} +1 -1
  24. package/dist/components/builder-composer-triggers.d.ts +62 -0
  25. package/dist/components/builder-layout.d.ts +54 -0
  26. package/dist/components/builder-message-actions.d.ts +72 -0
  27. package/dist/components/builder-panel.d.ts +189 -0
  28. package/dist/components/builder-preview.d.ts +11 -0
  29. package/dist/components/builder-shell-controls.d.ts +69 -0
  30. package/dist/components/builder-skeleton.d.ts +58 -0
  31. package/dist/components/builder-start.d.ts +75 -0
  32. package/dist/components/builder-workspace-variants.d.ts +23 -0
  33. package/dist/components/captions.d.ts +66 -0
  34. package/dist/{composer-sQ0HcvyG.js → composer-DMI85B6j.js} +1 -1
  35. package/dist/{confirm-card-rQWDQsnC.js → confirm-card-B0YIAwXp.js} +1 -1
  36. package/dist/{context-0kg4ZX1J.js → context-DWgfhqWp.js} +1 -1
  37. package/dist/controllable-BagRpyHv.js +1 -0
  38. package/dist/{conversation-item-BxwQLaFJ.js → conversation-item-BsOsVGmT.js} +1 -1
  39. package/dist/{conversation-list-BCfGN1JU.js → conversation-list-aX3Vtc7L.js} +1 -1
  40. package/dist/{copy-n9u9rqpi.js → copy-BmEwsNhJ.js} +1 -1
  41. package/dist/{create-tween-uPkArjIG.js → create-tween-CNOAU3Fx.js} +1 -1
  42. package/dist/{create-tween-C-q-JCM-.js → create-tween-WfqiENls.js} +1 -1
  43. package/dist/{create-tween-CRrJXxBd.js → create-tween-wlFtW9Kh.js} +1 -1
  44. package/dist/{create-tween-DZ3RRDHD.js → create-tween-zt79ba32.js} +1 -1
  45. package/dist/{default-input-CaMrJkgH.js → default-input-DMV5Eaze.js} +1 -1
  46. package/dist/define-CI0y3eE4.js +1 -0
  47. package/dist/define.js +40 -40
  48. package/dist/define.server.js +45 -45
  49. package/dist/{disclosure-WUImBbDv.js → disclosure-NnACBxsC.js} +1 -1
  50. package/dist/{dropdown-wZVeJOMd.js → dropdown-DT7G0RGR.js} +1 -1
  51. package/dist/elements/agent-card.js +1 -1
  52. package/dist/elements/artifact.js +1 -1
  53. package/dist/elements/attachments.js +1 -1
  54. package/dist/elements/audio-visualizer.js +1 -1
  55. package/dist/elements/avatar.js +1 -1
  56. package/dist/elements/badge.js +1 -1
  57. package/dist/elements/button.js +1 -1
  58. package/dist/elements/card.js +1 -1
  59. package/dist/elements/cards.js +1 -1
  60. package/dist/elements/chain-of-thought.js +1 -1
  61. package/dist/elements/chat-scope-picker.js +1 -1
  62. package/dist/elements/chat-workspace.js +1 -1
  63. package/dist/elements/chat.js +1 -1
  64. package/dist/elements/checkbox-group.js +1 -1
  65. package/dist/elements/checkbox.js +1 -1
  66. package/dist/elements/checkpoint.js +1 -1
  67. package/dist/elements/choice.js +1 -1
  68. package/dist/elements/coachmark.js +1 -1
  69. package/dist/elements/code-block.js +1 -1
  70. package/dist/elements/command.js +1 -1
  71. package/dist/elements/compare.js +1 -1
  72. package/dist/elements/composer.js +1 -1
  73. package/dist/elements/confirm-card.js +1 -1
  74. package/dist/elements/context-meter.js +1 -1
  75. package/dist/elements/conversation-item.js +1 -1
  76. package/dist/elements/conversation-list.js +1 -1
  77. package/dist/elements/dialog.js +1 -1
  78. package/dist/elements/dock.js +1 -1
  79. package/dist/elements/dropdown.js +1 -1
  80. package/dist/elements/editable-label.js +1 -1
  81. package/dist/elements/embed.js +1 -1
  82. package/dist/elements/empty.js +1 -1
  83. package/dist/elements/feedback-bar.js +1 -1
  84. package/dist/elements/file-tree.js +1 -1
  85. package/dist/elements/file-upload.js +1 -1
  86. package/dist/elements/form.js +1 -1
  87. package/dist/elements/hover-card.js +1 -1
  88. package/dist/elements/icon.js +1 -1
  89. package/dist/elements/image.js +1 -1
  90. package/dist/elements/input.js +1 -1
  91. package/dist/elements/kbd.js +1 -1
  92. package/dist/elements/link-preview.js +1 -1
  93. package/dist/elements/loader.js +1 -1
  94. package/dist/elements/markdown.js +1 -1
  95. package/dist/elements/menu.js +1 -1
  96. package/dist/elements/message-skills.js +1 -1
  97. package/dist/elements/message.js +1 -1
  98. package/dist/elements/model-switcher.js +1 -1
  99. package/dist/elements/nav.js +1 -1
  100. package/dist/elements/notice.js +1 -1
  101. package/dist/elements/pane-grid.js +1 -1
  102. package/dist/elements/pane-group.js +1 -1
  103. package/dist/elements/pane.js +1 -1
  104. package/dist/elements/popover.js +1 -1
  105. package/dist/elements/progress-bar.js +1 -1
  106. package/dist/elements/prompt-dock.js +1 -1
  107. package/dist/elements/prompt-input.js +1 -1
  108. package/dist/elements/prompt-suggestions.js +1 -1
  109. package/dist/elements/radio-group.js +1 -1
  110. package/dist/elements/reasoning.js +1 -1
  111. package/dist/elements/remote.js +1 -1
  112. package/dist/elements/resizable.js +1 -1
  113. package/dist/elements/response-stream.js +1 -1
  114. package/dist/elements/screen.js +1 -1
  115. package/dist/elements/scroll-area.js +1 -1
  116. package/dist/elements/scroll-button.js +1 -1
  117. package/dist/elements/search.js +1 -1
  118. package/dist/elements/segmented.js +1 -1
  119. package/dist/elements/select.js +1 -1
  120. package/dist/elements/separator.js +1 -1
  121. package/dist/elements/setting-item.js +1 -1
  122. package/dist/elements/settings-group.js +1 -1
  123. package/dist/elements/skeleton.js +1 -1
  124. package/dist/elements/slider.js +1 -1
  125. package/dist/elements/source.js +1 -1
  126. package/dist/elements/status.js +1 -1
  127. package/dist/elements/switch.js +1 -1
  128. package/dist/elements/tabs.js +1 -1
  129. package/dist/elements/tasks.js +1 -1
  130. package/dist/elements/text-shimmer.js +1 -1
  131. package/dist/elements/thinking-bar.js +1 -1
  132. package/dist/elements/thread.js +1 -1
  133. package/dist/elements/toast.js +1 -1
  134. package/dist/elements/tool.js +1 -1
  135. package/dist/elements/tooltip.js +1 -1
  136. package/dist/elements/voice-input.js +1 -1
  137. package/dist/elements/voice-output.js +1 -1
  138. package/dist/{ellipsis-CbOpJnU3.js → ellipsis-6pJ7SxYT.js} +1 -1
  139. package/dist/{embed-CrfjkbUG.js → embed-BMje-nxj.js} +1 -1
  140. package/dist/{external-link-ByXAwBBQ.js → external-link-Beh9DKeR.js} +1 -1
  141. package/dist/{file-text-DMib2qwt.js → file-text-D1GPfZ8Q.js} +1 -1
  142. package/dist/{file-tree-CJqM2aP7.js → file-tree-Dwj2lqg-.js} +1 -1
  143. package/dist/{folder-_BAb929C.js → folder-b6D8x1DY.js} +1 -1
  144. package/dist/{form-DSZgZQZk.js → form-DWgdxDXu.js} +1 -1
  145. package/dist/{hover-card-BQbul9eq.js → hover-card-CWRkqm40.js} +1 -1
  146. package/dist/{icon-CdcfRhYI.js → icon-CL0jdhsf.js} +1 -1
  147. package/dist/index.js +1741 -1725
  148. package/dist/index.server.js +1582 -1566
  149. package/dist/{info-DsFjGuI_.js → info-0cOUherQ.js} +1 -1
  150. package/dist/{input-DKbmkMos.js → input-BH6Ru91Q.js} +1 -1
  151. package/dist/kai.es.js +1 -1
  152. package/dist/{kbd-PvdGhX4s.js → kbd-DRAnVtNX.js} +1 -1
  153. package/dist/{link-zF8PzWfF.js → link-Dlr0vssB.js} +1 -1
  154. package/dist/{link-preview-DbM1866N.js → link-preview-DODgRyV9.js} +1 -1
  155. package/dist/loader-KvJB6NrT.js +1 -0
  156. package/dist/{markdown-LMvmAyBk.js → markdown-DX9tuJVj.js} +1 -1
  157. package/dist/mcp.es.js +8 -4
  158. package/dist/{message-BYZECyek.js → message-BqQ7Ot5q.js} +1 -1
  159. package/dist/{message-BSsgvHvf.js → message-DkaGfBd8.js} +1 -1
  160. package/dist/message-circle-BPpp5QKv.js +1 -0
  161. package/dist/message-square-BLbsd9BJ.js +1 -0
  162. package/dist/{minimize-2-BQRoBV1V.js → minimize-2-CyOHJwcN.js} +1 -1
  163. package/dist/{model-switcher-CMpCOYcB.js → model-switcher-0hrKDiK2.js} +1 -1
  164. package/dist/{overlay-Cb-MkyDa.js → overlay-DBMFXie6.js} +1 -1
  165. package/dist/{panel-right-i8warFxT.js → panel-right-t8SWJL6e.js} +1 -1
  166. package/dist/{paperclip-ByY3UVO6.js → paperclip-CdzuOjbU.js} +1 -1
  167. package/dist/play-BXy1u7rW.js +1 -0
  168. package/dist/primitives/use-auto-resize.d.ts +11 -0
  169. package/dist/{progress-bar-jVAHvMUf.js → progress-bar-CiBtxMWT.js} +1 -1
  170. package/dist/{prompt-suggestion-CD-qtNgC.js → prompt-suggestion-I_DHP21i.js} +1 -1
  171. package/dist/{radio-BsoBMhkF.js → radio-C_p3n39l.js} +1 -1
  172. package/dist/{reasoning-4kBPtlTx.js → reasoning-BDwy_tIe.js} +1 -1
  173. package/dist/register-impl-DvEnhIxx.js +424 -0
  174. package/dist/{resizable-uPmY9VY-.js → resizable-SYC-fStM.js} +1 -1
  175. package/dist/{rotate-ccw-B2xn93py.js → rotate-ccw-B1nwmwuY.js} +1 -1
  176. package/dist/{rotate-cw-CMVLoCyH.js → rotate-cw-CLAnBcm1.js} +1 -1
  177. package/dist/{scroll-area-BqLUo8ZZ.js → scroll-area-zRyXoLhI.js} +1 -1
  178. package/dist/{scroll-button-DslXiJyL.js → scroll-button-jzrbYCG9.js} +1 -1
  179. package/dist/{select-2cLRtPGT.js → select-DM-0nEe0.js} +1 -1
  180. package/dist/{separator-BWQtNJcM.js → separator-BToOOoOt.js} +1 -1
  181. package/dist/{settings-BBR63jLg.js → settings-PaGo_S4U.js} +1 -1
  182. package/dist/{settings-group-B2ciy-Iw.js → settings-group-BFXGIfXq.js} +1 -1
  183. package/dist/{skeleton-CkHI-HgC.js → skeleton-DYpmFnnm.js} +1 -1
  184. package/dist/{slider-DDR9U-i0.js → slider-ebutAmkQ.js} +1 -1
  185. package/dist/{solid-DruVOXnf.js → solid-15v_3WVL.js} +3563 -3412
  186. package/dist/{solid-BzCFdL25.js → solid-5P-otgdi.js} +4502 -4296
  187. package/dist/solid.d.ts +6 -0
  188. package/dist/solid.js +259 -254
  189. package/dist/solid.server.js +259 -254
  190. package/dist/{source-GEnFF528.js → source-c1gpRl9h.js} +1 -1
  191. package/dist/{star-CilHq8GP.js → star-pcV_3LqF.js} +1 -1
  192. package/dist/{store-Ciyk6eZG.js → store-CSgbFFCg.js} +1 -1
  193. package/dist/{switch-KkeQIbuH.js → switch-Bh2OdLV2.js} +1 -1
  194. package/dist/{tasks-card-BrN4bggJ.js → tasks-card-CbqQAn2S.js} +1 -1
  195. package/dist/text-shimmer-BSzgEnDH.js +1 -0
  196. package/dist/textarea-DrYNt_0z.js +1 -0
  197. package/dist/theme.tokens.css +22 -21
  198. package/dist/{thumbs-up-CsT9Wzb9.js → thumbs-up-BL3-NenK.js} +1 -1
  199. package/dist/{toast-store-tgK6MuMv.js → toast-store-DkOlYczt.js} +1 -1
  200. package/dist/{tool-DzUjIBT8.js → tool-CeIWUVUe.js} +1 -1
  201. package/dist/{tooltip-Bkkg_4t0.js → tooltip-GA-nmg06.js} +1 -1
  202. package/dist/{trash-2-jBKxjGGQ.js → trash-2-CT66QWlm.js} +1 -1
  203. package/dist/{triangle-alert-DlQ68ppf.js → triangle-alert-CeHLWxhD.js} +1 -1
  204. package/dist/ui/color-field.d.ts +48 -0
  205. package/dist/ui/textarea.d.ts +4 -0
  206. package/dist/ui/toggle-chip.d.ts +40 -0
  207. package/dist/{upload-TcAHXv9W.js → upload-9Csb0F0J.js} +1 -1
  208. package/dist/{use-card-resolution-DaZqAdWf.js → use-card-resolution-Zg0a08Z-.js} +1 -1
  209. package/dist/{variant-aurora-DbW_OWL2.js → variant-aurora-4VBQHIKV.js} +1 -1
  210. package/dist/{variant-aurora-CNmfHhcx.js → variant-aurora-DBeCAQNk.js} +2 -2
  211. package/dist/{variant-aurora-D6GsdTPA.js → variant-aurora-FzHVXHby.js} +2 -2
  212. package/dist/{variant-aurora-BhLuYxJR.js → variant-aurora-LE3fqxgw.js} +1 -1
  213. package/dist/{variant-custom-BvYHR62b.js → variant-custom-AFRGcOBS.js} +1 -1
  214. package/dist/{variant-custom-DV2x254s.js → variant-custom-BQkNuPpE.js} +2 -2
  215. package/dist/{variant-custom-BRvaNHSi.js → variant-custom-DI5R0rln.js} +1 -1
  216. package/dist/{variant-custom-DMTrEO5w.js → variant-custom-WWnrrRHS.js} +2 -2
  217. package/dist/{variant-wave-CyBueXj9.js → variant-wave-DUCbH5oI.js} +2 -2
  218. package/dist/{variant-wave-BNMGrDfj.js → variant-wave-DuQV7DhQ.js} +2 -2
  219. package/dist/{variant-wave-BpDd8t3Z.js → variant-wave-nSI2sfII.js} +1 -1
  220. package/dist/{variant-wave-sp-qwsdI.js → variant-wave-wTP5v_jU.js} +1 -1
  221. package/dist/x-eiO9V6J6.js +1 -0
  222. package/kit-base.css +311 -0
  223. package/package.json +17 -2
  224. package/solid.css +33 -0
  225. package/theme.css +39 -23
  226. package/dist/arrow-down-CjRU3JgV.js +0 -1
  227. package/dist/arrow-left-Bnpb1UEW.js +0 -1
  228. package/dist/artifact-Bwt7OgcR.js +0 -1
  229. package/dist/check-njkVdZu2.js +0 -1
  230. package/dist/chevron-down-B72s6PXR.js +0 -1
  231. package/dist/chevron-right-BatuHzUm.js +0 -1
  232. package/dist/circle-check-B62pODB3.js +0 -1
  233. package/dist/circle-zx0ByzY9.js +0 -1
  234. package/dist/controllable-CnGpMF6r.js +0 -1
  235. package/dist/define-By-uL588.js +0 -1
  236. package/dist/loader-BM4CEz4G.js +0 -1
  237. package/dist/message-circle-DruwObfX.js +0 -1
  238. package/dist/message-square-BG6q6mlm.js +0 -1
  239. package/dist/play-BvKKq3fX.js +0 -1
  240. package/dist/register-impl-B1hLkrI8.js +0 -424
  241. package/dist/text-shimmer-Dcj1MHuq.js +0 -1
  242. package/dist/textarea-Dpvbngbg.js +0 -1
  243. package/dist/x-Z5UntkIJ.js +0 -1
package/kit-base.css ADDED
@@ -0,0 +1,311 @@
1
+ /* Shared kit base + component rules. ONE source, TWO consumers, and the
2
+ consumers are different style paths, which is the whole reason this file
3
+ exists:
4
+
5
+ src/elements/styles.css compiled to compiled.css and adopted into every
6
+ kai-* shadow root (the ./elements and ./define
7
+ entries). It also sets the :host rules.
8
+ solid.css Tailwind SOURCE that a light-DOM SolidJS consumer
9
+ @imports into their own Tailwind build (the . and
10
+ ./solid entries ship class names and no CSS).
11
+
12
+ Before this file, everything below lived only in the elements sheet, so the
13
+ Solid path silently shipped without it: .kai-radio / .kai-checkbox / .kai-range
14
+ rendered as raw OS chrome, no inset focus ring, no token-driven focus outline,
15
+ no scrollbars, no ::selection. Nothing in CI rendered that path, so nothing
16
+ noticed. The same defect had already happened once before, one layer up, when
17
+ the Storybook sheet hand-copied a few of these rules and omitted the rest.
18
+
19
+ NEVER copy a rule from here into either consumer, and never add a rule to one
20
+ consumer that both need. Add it here. The one thing that cannot live here is
21
+ :host, which selects nothing in a light DOM; those rules stay in
22
+ src/elements/styles.css, and .storybook/styles.css re-states them on body.
23
+
24
+ This file relies on the --color-* tokens from theme.css and on the classes
25
+ tw-animate-css emits; both consumers import those alongside it. */
26
+
27
+ @layer base {
28
+ /* Code/monospace surfaces use --kai-font-code (named for its ROLE — code — not
29
+ "mono", so any family works). Covers inline code, <pre>, and code blocks. */
30
+ code, kbd, samp, pre {
31
+ font-family: var(--kai-font-code, ui-monospace, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace);
32
+ }
33
+ * { border-color: var(--color-border); }
34
+
35
+ /* Native controls (date/time pickers, <select>, number spinners, the
36
+ checkbox/radio fallbacks, scrollbars) must follow the kit's light/dark
37
+ mode — NOT the OS — so e.g. the native calendar icon never renders black
38
+ on a dark surface. `color-scheme` drives that native rendering; we set it
39
+ from the resolved mode (the `.dark` scope the element factory toggles). */
40
+ .dark { color-scheme: dark; }
41
+
42
+ /* One token-driven focus ring for EVERY focusable element in the shadow root.
43
+ Blue by default (via --color-ring), consistent in light + dark, and
44
+ overridable through --kai-color-ring. Uses `outline` (not a box-shadow
45
+ ring) because it follows the element's radius and — unlike a `ring-*`
46
+ utility — is written in literal values, so it does not depend on any
47
+ `--tw-*` custom property. That matters more than it looks: `@property`
48
+ registration is document-global and is ignored inside a shadow root, so
49
+ every `--tw-*` here is unset and every `ring-*` utility computes to
50
+ nothing. This literal rule is the only reason most of the kit had a focus
51
+ indicator at all. `:focus-visible` so it only appears for keyboard
52
+ navigation, never on a mouse click. Components that render their own ring
53
+ set `focus-visible:outline-none` (a utility in a later cascade layer) and
54
+ win over this — so there's no double ring, just a guaranteed blue fallback
55
+ for the many controls that have no explicit focus style.
56
+
57
+ CAVEAT, learned the hard way: an outline is NOT immune to clipping. It is
58
+ unaffected by the element's OWN overflow, but `outline-offset: 2px` draws
59
+ it entirely outside the border box, where an ANCESTOR with
60
+ `overflow: clip`/`hidden` erases it completely. Controls that sit flush
61
+ inside such a container need `.kai-focus-inset` below. */
62
+ :focus-visible {
63
+ outline: 2px solid var(--color-ring);
64
+ outline-offset: 2px;
65
+ }
66
+
67
+ /* Consistent cross-platform scrollbars for EVERY scroll region inside the
68
+ shadow root (message list, conversation list, menus, hover cards, code
69
+ blocks, the prompt textarea …). Thin + rounded + subtle, themed via tokens
70
+ for light/dark, thumb stronger on hover. Track stays transparent and
71
+ overflow is untouched, so no scrollbar is forced where none is needed.
72
+ Scoped to the shadow root, so it never restyles the host page. */
73
+ * {
74
+ scrollbar-width: thin;
75
+ scrollbar-color: var(--color-scrollbar-thumb) transparent;
76
+ }
77
+ *::-webkit-scrollbar { width: 8px; height: 8px; }
78
+ *::-webkit-scrollbar-track { background: transparent; }
79
+ *::-webkit-scrollbar-thumb {
80
+ background-color: var(--color-scrollbar-thumb);
81
+ border-radius: 9999px;
82
+ border: 2px solid transparent;
83
+ background-clip: padding-box;
84
+ }
85
+ *::-webkit-scrollbar-thumb:hover { background-color: var(--color-scrollbar-thumb-hover); }
86
+ *::-webkit-scrollbar-corner { background: transparent; }
87
+
88
+ /* SELECTED text, kit-owned. Scoped to the shadow root — deliberately, and this
89
+ is the whole design decision, so read it before "simplifying" it into
90
+ theme.css.
91
+
92
+ WHY THE KIT OWNS IT AT ALL: left to the UA, the browser's blue selection was
93
+ visually stronger than the kit's OWN deliberate emphasis (the composer's
94
+ --color-highlight mark), so an incidental drag-select outranked a keyword the
95
+ app had flagged on purpose. How selected text reads is a fact about the
96
+ medium, which is the kit's call.
97
+
98
+ WHY ONLY HERE, AND NOT IN theme.css: theme.css is imported into a CONSUMER's
99
+ Tailwind build, so a bare ::selection there would restyle every paragraph on
100
+ their page — the kit deciding for the app's own content, which is not ours to
101
+ decide. The shadow root IS the kit's DOM, so the same rule is unambiguous
102
+ here. Identical reasoning to the scrollbar and :focus-visible rules above,
103
+ which are scoped the same way and for the same reason. theme.css therefore
104
+ carries the TOKENS only. A Solid-layer consumer rendering our components
105
+ into their own light DOM opts in by importing solid.css, which brings this
106
+ whole file and says so in its header; a consumer who wants the tokens alone
107
+ imports theme.css and writes their own scoped rule:
108
+ `.my-chat ::selection { background-color: var(--color-selection); … }`.
109
+
110
+ WHY THE RULE MUST BE IN THIS SHEET AND NOT INHERITED: ::selection does NOT
111
+ cross the shadow boundary the way ordinary inherited properties do — a
112
+ document-level ::selection leaves shadow content on the UA default. The
113
+ --kai-color-selection TOKEN does pierce (custom properties inherit normally),
114
+ which is what keeps a consumer override working.
115
+
116
+ Both background AND color are set; see the theme.css note for why the
117
+ foreground is load-bearing rather than cosmetic (coloured text falls under
118
+ WCAG AA on this fill if it keeps its own colour). */
119
+ ::selection {
120
+ background-color: var(--color-selection);
121
+ color: var(--color-selection-foreground);
122
+ }
123
+
124
+ /* Respect a user's reduced-motion preference: disable the tw-animate-css
125
+ enter/exit keyframe animations (toasts, overlays, cards) so they appear and
126
+ disappear instantly instead of sliding/fading. Targets the utility classes
127
+ tw-animate-css emits (.animate-in / .animate-out) plus any arbitrary
128
+ `animate-[…]` keyframe utility. */
129
+ @media (prefers-reduced-motion: reduce) {
130
+ .animate-in,
131
+ .animate-out,
132
+ [class*="animate-["] {
133
+ animation: none !important;
134
+ }
135
+ }
136
+ }
137
+
138
+
139
+ @layer components {
140
+ /* Focus ring drawn INSIDE the element's border box, for focusable regions
141
+ that sit flush against a clipping ancestor. The scrollable code-block body
142
+ and the message log are both `overflow-*` regions filling a rounded
143
+ `overflow: clip` container, so the default `outline-offset: 2px` put the
144
+ whole ring outside the clip and it never painted — the outline computed
145
+ correctly, matched `:focus-visible`, and was erased before it reached the
146
+ screen. A negative offset keeps it clear of the boundary. Same token and
147
+ width as the base ring, so it reads identically. */
148
+ .kai-focus-inset:focus-visible {
149
+ outline: 2px solid var(--color-ring);
150
+ outline-offset: -2px;
151
+ }
152
+
153
+ /* Designed radio + checkbox (appearance-none) so the form controls read as
154
+ intentional, theme correctly in light/dark, and have comfortable targets —
155
+ replacing the weak native defaults. Used via `.kai-radio` / `.kai-checkbox`. */
156
+ .kai-radio,
157
+ .kai-checkbox {
158
+ appearance: none;
159
+ -webkit-appearance: none;
160
+ inline-size: 1.125rem;
161
+ block-size: 1.125rem;
162
+ margin: 0;
163
+ flex-shrink: 0;
164
+ cursor: pointer;
165
+ border: 1.5px solid var(--color-input);
166
+ background-color: var(--color-background);
167
+ display: inline-grid;
168
+ place-content: center;
169
+ box-shadow: 0 1px 2px rgb(0 0 0 / 0.04);
170
+ transition: border-color 0.18s ease, background-color 0.18s ease, box-shadow 0.18s ease,
171
+ transform 0.1s ease;
172
+ }
173
+ .kai-radio { border-radius: 9999px; }
174
+ .kai-checkbox { border-radius: 0.3rem; }
175
+ .kai-radio::after {
176
+ content: "";
177
+ inline-size: 0.5rem;
178
+ block-size: 0.5rem;
179
+ border-radius: 9999px;
180
+ background-color: var(--color-primary);
181
+ transform: scale(0);
182
+ transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
183
+ }
184
+ .kai-radio:checked { border-color: var(--color-primary); }
185
+ .kai-radio:checked::after { transform: scale(1); }
186
+ .kai-checkbox:checked {
187
+ background-color: var(--color-primary);
188
+ border-color: var(--color-primary);
189
+ }
190
+ .kai-checkbox::after {
191
+ content: "";
192
+ inline-size: 0.8rem;
193
+ block-size: 0.8rem;
194
+ background-color: var(--color-primary-foreground);
195
+ transform: scale(0);
196
+ transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
197
+ -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E") center / contain no-repeat;
198
+ mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E") center / contain no-repeat;
199
+ }
200
+ .kai-checkbox:checked::after { transform: scale(1); }
201
+ .kai-radio:hover:not(:disabled),
202
+ .kai-checkbox:hover:not(:disabled) {
203
+ border-color: var(--color-primary);
204
+ box-shadow: 0 0 0 4px color-mix(in srgb, var(--color-primary) 9%, transparent);
205
+ }
206
+ .kai-radio:active:not(:disabled),
207
+ .kai-checkbox:active:not(:disabled) { transform: scale(0.92); }
208
+ .kai-checkbox:checked {
209
+ box-shadow: 0 1px 4px color-mix(in srgb, var(--color-primary) 26%, transparent);
210
+ }
211
+ /* The mixed state ("some of the children below are ticked"). `indeterminate` is a
212
+ DOM property with no HTML attribute, so a rule is the ONLY way it can be seen —
213
+ without one a mixed box paints pixel-identically to an unchecked one and lies
214
+ about its state. That was live: `<kai-tasks>` in `select` mode puts an
215
+ indeterminate select-all above a partial selection, and it read as "none
216
+ selected".
217
+
218
+ Same fill and the same masked `::after` as `:checked`, with the tick mask
219
+ swapped for a bar, so the two states are siblings of one technique rather than
220
+ two: the bar is `--color-primary-foreground` on `--color-primary`, exactly the
221
+ pair the tick already uses, so it themes and contrasts identically in both
222
+ themes and stays consumer-themable through the same tokens.
223
+
224
+ Ordered AFTER the `:checked` rules on purpose. `indeterminate` is independent of
225
+ `checked`, so a box can be both; specificity is equal, so source order decides,
226
+ and mixed-wins is what the browser's own native rendering does.
227
+
228
+ Scoped to `.kai-checkbox` on purpose: `:indeterminate` also matches every radio
229
+ in a group with nothing selected, and an empty radio group must go on reading as
230
+ empty rather than sprouting a third state. */
231
+ .kai-checkbox:indeterminate {
232
+ background-color: var(--color-primary);
233
+ border-color: var(--color-primary);
234
+ box-shadow: 0 1px 4px color-mix(in srgb, var(--color-primary) 26%, transparent);
235
+ }
236
+ .kai-checkbox:indeterminate::after {
237
+ transform: scale(1);
238
+ -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14'/%3E%3C/svg%3E") center / contain no-repeat;
239
+ mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14'/%3E%3C/svg%3E") center / contain no-repeat;
240
+ }
241
+ .kai-radio:disabled,
242
+ .kai-checkbox:disabled { opacity: 0.5; cursor: not-allowed; }
243
+
244
+ /* Custom range slider: a filled track (--kai-range-fill set by the widget) and a
245
+ refined thumb that scales on hover/press with a focus halo — no native chrome. */
246
+ .kai-range {
247
+ appearance: none;
248
+ -webkit-appearance: none;
249
+ inline-size: 100%;
250
+ block-size: 1.25rem;
251
+ background: transparent;
252
+ cursor: pointer;
253
+ margin: 0;
254
+ }
255
+ .kai-range::-webkit-slider-runnable-track {
256
+ block-size: 0.375rem;
257
+ border-radius: 9999px;
258
+ border: none;
259
+ box-shadow: none;
260
+ background: linear-gradient(
261
+ to right,
262
+ var(--color-primary) var(--kai-range-fill, 0%),
263
+ var(--color-muted) var(--kai-range-fill, 0%)
264
+ );
265
+ }
266
+ .kai-range::-moz-range-track {
267
+ block-size: 0.375rem;
268
+ border-radius: 9999px;
269
+ border: none;
270
+ box-shadow: none;
271
+ background: var(--color-muted);
272
+ }
273
+ .kai-range::-moz-range-progress {
274
+ block-size: 0.375rem;
275
+ border-radius: 9999px;
276
+ background: var(--color-primary);
277
+ }
278
+ .kai-range::-webkit-slider-thumb {
279
+ appearance: none;
280
+ -webkit-appearance: none;
281
+ inline-size: 1.125rem;
282
+ block-size: 1.125rem;
283
+ border-radius: 9999px;
284
+ background: var(--color-background);
285
+ border: 2px solid var(--color-primary);
286
+ box-shadow: 0 1px 3px rgb(0 0 0 / 0.18);
287
+ margin-block-start: -0.375rem;
288
+ transition: transform 0.12s ease, box-shadow 0.12s ease;
289
+ }
290
+ .kai-range::-moz-range-thumb {
291
+ inline-size: 1.125rem;
292
+ block-size: 1.125rem;
293
+ border-radius: 9999px;
294
+ background: var(--color-background);
295
+ border: 2px solid var(--color-primary);
296
+ box-shadow: 0 1px 3px rgb(0 0 0 / 0.18);
297
+ transition: transform 0.12s ease, box-shadow 0.12s ease;
298
+ }
299
+ .kai-range:hover::-webkit-slider-thumb { transform: scale(1.12); }
300
+ .kai-range:hover::-moz-range-thumb { transform: scale(1.12); }
301
+ .kai-range:focus-visible { outline: none; }
302
+ .kai-range:focus-visible::-webkit-slider-thumb,
303
+ .kai-range:active::-webkit-slider-thumb {
304
+ box-shadow: 0 0 0 6px color-mix(in srgb, var(--color-primary) 14%, transparent);
305
+ }
306
+ .kai-range:focus-visible::-moz-range-thumb,
307
+ .kai-range:active::-moz-range-thumb {
308
+ box-shadow: 0 0 0 6px color-mix(in srgb, var(--color-primary) 14%, transparent);
309
+ }
310
+ .kai-range:disabled { opacity: 0.5; cursor: not-allowed; }
311
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kitn.ai/ui",
3
- "version": "0.29.0",
3
+ "version": "0.30.0",
4
4
  "nx": {
5
5
  "name": "ui",
6
6
  "targets": {
@@ -93,6 +93,7 @@
93
93
  "default": "./dist/elements/autoloader.js"
94
94
  },
95
95
  "./theme.css": "./theme.css",
96
+ "./solid.css": "./solid.css",
96
97
  "./theme.tokens.css": "./dist/theme.tokens.css",
97
98
  "./element-meta.json": "./src/elements/element-meta.json",
98
99
  "./icon-names.json": "./src/elements/icon-names.json",
@@ -162,6 +163,8 @@
162
163
  "!dist/**/*.testlib.*",
163
164
  "frameworks",
164
165
  "theme.css",
166
+ "solid.css",
167
+ "kit-base.css",
165
168
  "llms.txt",
166
169
  "llms-full.txt",
167
170
  "NOTICE"
@@ -303,11 +306,23 @@
303
306
  "vitest": "^4.1.0"
304
307
  },
305
308
  "peerDependencies": {
306
- "react": ">=18"
309
+ "@tailwindcss/typography": "^0.5.19",
310
+ "react": ">=18",
311
+ "tailwindcss": "^4.2.2",
312
+ "tw-animate-css": "^1.4.0"
307
313
  },
308
314
  "peerDependenciesMeta": {
315
+ "@tailwindcss/typography": {
316
+ "optional": true
317
+ },
309
318
  "react": {
310
319
  "optional": true
320
+ },
321
+ "tailwindcss": {
322
+ "optional": true
323
+ },
324
+ "tw-animate-css": {
325
+ "optional": true
311
326
  }
312
327
  }
313
328
  }
package/solid.css ADDED
@@ -0,0 +1,33 @@
1
+ /* @kitn.ai/ui for light-DOM SolidJS apps. Tailwind v4 SOURCE: import it from a
2
+ stylesheet that Tailwind processes, after `@import "tailwindcss"`, and keep
3
+ your `@source` line pointing at the kit so its class names survive:
4
+
5
+ @import "tailwindcss";
6
+ @import "@kitn.ai/ui/solid.css";
7
+ @source "../node_modules/@kitn.ai/ui";
8
+
9
+ Why this file and not theme.css alone: the Solid entry (`.` / `./solid`) ships
10
+ class-name strings and NO CSS, so everything the kai-* elements get from their
11
+ compiled shadow-root sheet has to reach your Tailwind build some other way.
12
+ theme.css carries only the tokens. This file adds the rest:
13
+
14
+ tw-animate-css the animate-in/out, fade-*, zoom-*, slide-* classes
15
+ every overlay uses; without it they compile to
16
+ nothing and the animations are silently dead
17
+ @tailwindcss/typography the prose-sm / prose-lg classes proseClass() emits
18
+ kit-base.css the focus ring, scrollbars, ::selection, and the
19
+ .kai-radio / .kai-checkbox / .kai-range /
20
+ .kai-focus-inset component rules
21
+
22
+ tw-animate-css, @tailwindcss/typography and tailwindcss are optional peer
23
+ dependencies: install them next to the kit.
24
+
25
+ The base rules here are global by design: they style your whole page the way
26
+ the kit styles its own shadow roots. If you only want the tokens, import
27
+ theme.css instead and opt into the rest yourself.
28
+
29
+ Guarded by tests/styles/solid-css-contract.test.ts. */
30
+ @import "tw-animate-css";
31
+ @plugin "@tailwindcss/typography";
32
+ @import "./theme.css";
33
+ @import "./kit-base.css";
package/theme.css CHANGED
@@ -1,12 +1,27 @@
1
1
  /* @kitn.ai/ui design system — import after `@import "tailwindcss"`.
2
- Defines ONLY namespaced (--color-*) tokens, component keyframes, animation
2
+ Defines the shadcn-style (--color-*) tokens, component keyframes, animation
3
3
  utilities, and the .chat-markdown styles. Contains NO global base/reset rules,
4
4
  so importing it restyles nothing on its own — a host opts in via the kit's
5
5
  components + classes. Rebrand by overriding the --color-* values (optionally
6
6
  scoped to a subtree).
7
7
  NOTE: This file is Tailwind-v4 source (requires tailwindcss as a peer). For
8
8
  bundler-based apps that don't use Tailwind, import @kitn.ai/ui/theme.tokens.css
9
- instead — it is plain compiled CSS with no toolchain requirements. */
9
+ instead — it is plain compiled CSS with no toolchain requirements.
10
+
11
+ THIS FILE IS MERGED INTO THE CONSUMER'S TAILWIND BUILD when they @import it,
12
+ so everything at global scope here lands in THEIR namespace. What it changes
13
+ for them (documented in apps/docs/.../guides/theming.mdx, keep the two in sync):
14
+ - `@custom-variant dark` below switches their `dark:` utilities from
15
+ prefers-color-scheme to the `.dark` class.
16
+ - the `--color-*` names merge into their @theme (last import wins).
17
+ - `--radius-sm/md/lg/xl` re-point Tailwind's stock radius scale at --radius.
18
+ - `--text-xs/sm/base/lg` are aliased onto the kit's type scale (defaults
19
+ equal stock Tailwind, so nothing moves until a --kai-text-* token is set).
20
+ Everything else global carries a `kai-` prefix so it cannot clash by name:
21
+ every @keyframes is `kai-<name>`, the scrollbar utility is `.kai-scrollbar-thin`.
22
+ The one unprefixed global class is `.chat-markdown` (public; renaming it is a
23
+ breaking change). tests/elements/theme-globals.test.ts pins the prefix rule
24
+ and that every animation reference in src/ resolves to a keyframe here. */
10
25
 
11
26
  @custom-variant dark (&:is(.dark *));
12
27
 
@@ -205,20 +220,18 @@
205
220
  --text-base: var(--kai-text-title, 1rem); --text-base--line-height: calc(1.5 / 1); /* ≡ text-title */
206
221
  --text-lg: var(--kai-text-lg, 1.125rem); --text-lg--line-height: calc(1.75 / 1.125); /* 18px — section headings, lg prose */
207
222
 
208
- @keyframes typing { 0%,100% { transform: translateY(0); opacity: .5 } 50% { transform: translateY(-2px); opacity: 1 } }
209
- @keyframes loading-dots { 0%,100% { opacity: 0 } 50% { opacity: 1 } }
210
- @keyframes wave { 0%,100% { transform: scaleY(1) } 50% { transform: scaleY(.6) } }
211
- @keyframes blink { 0%,100% { opacity: 1 } 50% { opacity: 0 } }
212
- @keyframes text-blink { 0%,100% { color: var(--color-primary) } 50% { color: var(--color-muted-foreground) } }
213
- @keyframes bounce-dots { 0%,100% { transform: scale(.8); opacity: .5 } 50% { transform: scale(1.2); opacity: 1 } }
214
- @keyframes thin-pulse { 0%,100% { transform: scale(.95); opacity: .8 } 50% { transform: scale(1.05); opacity: .4 } }
215
- @keyframes pulse-dot { 0%,100% { transform: scale(1); opacity: .8 } 50% { transform: scale(1.5); opacity: 1 } }
216
- @keyframes shimmer-text { 0% { background-position: 150% center } 100% { background-position: -150% center } }
217
- @keyframes wave-bars { 0%,100% { transform: scaleY(1); opacity: .5 } 50% { transform: scaleY(.6); opacity: 1 } }
218
- @keyframes shimmer { 0% { background-position: 200% 50% } 100% { background-position: -200% 50% } }
219
- @keyframes spinner-fade { 0% { opacity: 0 } 100% { opacity: 1 } }
220
- @keyframes collapsible-down { from { height: 0; opacity: 0 } to { height: var(--kb-collapsible-content-height); opacity: 1 } }
221
- @keyframes collapsible-up { from { height: var(--kb-collapsible-content-height); opacity: 1 } to { height: 0; opacity: 0 } }
223
+ @keyframes kai-typing { 0%,100% { transform: translateY(0); opacity: .5 } 50% { transform: translateY(-2px); opacity: 1 } }
224
+ @keyframes kai-loading-dots { 0%,100% { opacity: 0 } 50% { opacity: 1 } }
225
+ @keyframes kai-wave { 0%,100% { transform: scaleY(1) } 50% { transform: scaleY(.6) } }
226
+ @keyframes kai-blink { 0%,100% { opacity: 1 } 50% { opacity: 0 } }
227
+ @keyframes kai-text-blink { 0%,100% { color: var(--color-primary) } 50% { color: var(--color-muted-foreground) } }
228
+ @keyframes kai-bounce-dots { 0%,100% { transform: scale(.8); opacity: .5 } 50% { transform: scale(1.2); opacity: 1 } }
229
+ @keyframes kai-thin-pulse { 0%,100% { transform: scale(.95); opacity: .8 } 50% { transform: scale(1.05); opacity: .4 } }
230
+ @keyframes kai-pulse-dot { 0%,100% { transform: scale(1); opacity: .8 } 50% { transform: scale(1.5); opacity: 1 } }
231
+ @keyframes kai-shimmer-text { 0% { background-position: 150% center } 100% { background-position: -150% center } }
232
+ @keyframes kai-wave-bars { 0%,100% { transform: scaleY(1); opacity: .5 } 50% { transform: scaleY(.6); opacity: 1 } }
233
+ @keyframes kai-shimmer { 0% { background-position: 200% 50% } 100% { background-position: -200% 50% } }
234
+ @keyframes kai-spinner-fade { 0% { opacity: 0 } 100% { opacity: 1 } }
222
235
  }
223
236
 
224
237
  .dark {
@@ -344,21 +357,24 @@
344
357
 
345
358
  /* Cross-platform thin scrollbar utility (Firefox + WebKit). Used by ScrollArea
346
359
  and any scroll region in the SolidJS-component build (web components also get
347
- this globally inside their shadow root — see src/elements/styles.css). */
348
- .scrollbar-thin {
360
+ this globally inside their shadow root — see src/elements/styles.css).
361
+ `kai-` prefixed because this file is merged into a consumer's Tailwind build
362
+ and `.scrollbar-thin` is a name they may well own (no consumer-facing doc ever
363
+ named the old unprefixed class, so no alias is kept). */
364
+ .kai-scrollbar-thin {
349
365
  scrollbar-width: thin;
350
366
  scrollbar-color: var(--color-scrollbar-thumb) transparent;
351
367
  }
352
- .scrollbar-thin::-webkit-scrollbar { width: 8px; height: 8px; }
353
- .scrollbar-thin::-webkit-scrollbar-track { background: transparent; }
354
- .scrollbar-thin::-webkit-scrollbar-thumb {
368
+ .kai-scrollbar-thin::-webkit-scrollbar { width: 8px; height: 8px; }
369
+ .kai-scrollbar-thin::-webkit-scrollbar-track { background: transparent; }
370
+ .kai-scrollbar-thin::-webkit-scrollbar-thumb {
355
371
  background-color: var(--color-scrollbar-thumb);
356
372
  border-radius: 9999px;
357
373
  border: 2px solid transparent;
358
374
  background-clip: padding-box;
359
375
  }
360
- .scrollbar-thin::-webkit-scrollbar-thumb:hover { background-color: var(--color-scrollbar-thumb-hover); }
361
- .scrollbar-thin::-webkit-scrollbar-corner { background: transparent; }
376
+ .kai-scrollbar-thin::-webkit-scrollbar-thumb:hover { background-color: var(--color-scrollbar-thumb-hover); }
377
+ .kai-scrollbar-thin::-webkit-scrollbar-corner { background: transparent; }
362
378
 
363
379
  /* Surface utilities — `bg-surface` / `bg-surface-strong` paint the opaque,
364
380
  theme-derived surface tokens (see --color-surface above). Defined explicitly
@@ -1 +0,0 @@
1
- import{I as o}from"./Icon-DObhsRtm.js";import{c as r,q as e}from"./define-By-uL588.js";var m=[["path",{d:"M12 5v14",key:"s699le"}],["path",{d:"m19 12-7 7-7-7",key:"1idqje"}]],p=a=>r(o,e(a,{name:"ArrowDown",iconNode:m})),t=p;export{t as a};
@@ -1 +0,0 @@
1
- import{I as o}from"./Icon-DObhsRtm.js";import{c as r,q as e}from"./define-By-uL588.js";var m=[["path",{d:"m12 19-7-7 7-7",key:"1l729n"}],["path",{d:"M19 12H5",key:"x3x0zl"}]],t=a=>r(o,e(a,{name:"ArrowLeft",iconNode:m})),p=t;export{p as a};
@@ -1 +0,0 @@
1
- import{q as J,s as he,g as k,k as y,j as F,x as Q,o as X,p as fe,i as c,c as a,S as g,t as v,d as p,a as z,b as Y,u as Z,m as ge,h as be,e as ve}from"./define-By-uL588.js";import{c as H}from"./cn-DN5AWfiS.js";import{B as C}from"./button-DkuOnGLy.js";import{C as me,a as pe}from"./code-block-ClMLKb7C.js";import{F as we}from"./file-tree-CJqM2aP7.js";import{L as xe}from"./loader-BM4CEz4G.js";import{a as ke,i as ee}from"./url-scheme-policy-DR5DgvkM.js";import{a as ye}from"./arrow-left-Bnpb1UEW.js";import{a as ze,r as Ce,h as Te,e as Fe,c as Pe,d as Se}from"./rotate-cw-CMVLoCyH.js";import{e as re}from"./external-link-ByXAwBBQ.js";import{f as Oe}from"./file-text-DMib2qwt.js";import{m as Re,a as je}from"./minimize-2-BQRoBV1V.js";const Ie="6.0.227",ne=`https://cdn.jsdelivr.net/npm/pdfjs-dist@${Ie}/build`,He=()=>import(/*@vite-ignore*/`${ne}/pdf.min.mjs`),Ne=`${ne}/pdf.worker.min.mjs`;let Ee=He,Me=Ne,N=null;function $e(){if(!N){const r=Ee;N=(async()=>{const t=await r(),e=t.default??t;return e.GlobalWorkerOptions.workerSrc=Me,e})()}return N}async function Be(r,t,e){const i=await(await $e()).getDocument({url:r}).promise;t.replaceChildren();const o=typeof window<"u"&&window.devicePixelRatio?window.devicePixelRatio:1;for(let s=1;s<=i.numPages;s++){const d=await i.getPage(s),u=d.getViewport({scale:1}),h=u.width>0?e/u.width:1,f=d.getViewport({scale:h*o}),b=document.createElement("canvas");b.width=Math.max(1,Math.floor(f.width)),b.height=Math.max(1,Math.floor(f.height)),b.setAttribute("role","img"),b.setAttribute("aria-label",`Page ${s}`),b.style.width="100%",b.style.height="auto",b.style.display="block";const w=b.getContext("2d");t.appendChild(b),await d.render({canvasContext:w,viewport:f}).promise}return{pages:i.numPages}}var Le=v('<div><div class="relative min-h-0 flex-1">'),Ue=v('<form class="min-w-0 flex-1"><label class=sr-only for=kai-artifact-path>Address</label><input id=kai-artifact-path name=kai-artifact-path type=text autocomplete=off placeholder="Enter a path or URL\u2026">'),De=v("<div class=flex-1 aria-hidden=true>"),Ae=v('<div role=tablist aria-label=View class="flex shrink-0 items-center gap-0.5 rounded-md bg-muted p-0.5">'),Ve=v('<div data-artifact-toolbar class="flex shrink-0 items-center gap-1.5 border-b border-border bg-surface px-2 py-1.5">'),We=v("<button type=button role=tab>"),Ke=v('<iframe class="absolute inset-0 h-full w-full border-0 bg-white">'),_e=v('<div class="absolute inset-0 flex"><div class="w-56 shrink-0 overflow-auto border-r border-border bg-surface-sunken py-1.5 scrollbar-thin"></div><div class="min-w-0 flex-1 overflow-auto scrollbar-thin">'),qe=v('<div class="flex h-full items-center justify-center p-6 text-sm text-muted-foreground">Select a file to view its source.'),Ge=v('<div class="flex h-full items-center justify-center p-6 text-sm text-muted-foreground">No source \u2014 this file (<!>) has no code view.'),Je=v('<div class="flex flex-wrap items-center justify-center gap-2"><a class="inline-flex h-8 items-center gap-1.5 rounded-md border border-border bg-background px-3 text-xs font-medium text-foreground transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"target=_blank rel="noopener noreferrer">Open in new tab</a><a class="inline-flex h-8 items-center gap-1.5 rounded-md border border-border bg-background px-3 text-xs font-medium text-foreground transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"download>Download'),Qe=v(`<div role=region aria-label="PDF preview unavailable"class="absolute inset-0 flex flex-col items-center justify-center gap-3 bg-card p-6 text-center"><div class="text-sm font-medium text-foreground"></div><div class="text-xs text-muted-foreground">Can't preview this PDF inline.`),Xe=v(`<div class="text-xs text-muted-foreground">Blocked: that address uses a scheme this viewer won't open.`),Ye=v('<div class="pointer-events-none absolute inset-0 flex items-center justify-center">'),Ze=v('<div class="absolute inset-0"><div role=region aria-label="PDF preview"tabindex=0 class="absolute inset-0 flex flex-col items-center gap-3 overflow-auto bg-surface-sunken p-3 scrollbar-thin focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset">');const er="allow-scripts allow-forms";function E(r,t){console.warn(`[kai-artifact] blocked unsafe url in ${r}: ${t}`)}function rr(r,t){if(r.url)return r.url;if(!t)return r.path;try{return new URL(r.path,t).href}catch{return r.path}}function nr(r,t){if(!r)return!1;const e=t.find(o=>o.url===r||o.path===r);if(e?.type==="pdf")return!0;const i=r.split(/[?#]/)[0];return/\.pdf$/i.test(i)}function tr(r){const t=J({files:[],defaultTab:"preview",sandbox:er,showNav:!0,showReload:!0,showHome:!0,showPathField:!0,showTabs:!0,expandable:!1,openInTab:!1,standalone:!1,readonlyPath:!1,maximized:!1},r),[e,i]=he(t,["src","files","tab","defaultTab","activeFile","sandbox","iframeTitle","onNavigate","onTabChange","onFileSelect","maximized","onMaximizeChange","showNav","showReload","showHome","showPathField","showTabs","expandable","openInTab","standalone","readonlyPath","displayUrl","controllerRef","class"]),[o,s]=k(e.src?[e.src]:[]),[d,u]=k(e.src?0:-1),h=()=>o()[d()]??"",f=()=>d()>0,b=()=>d()<o().length-1,w=y(()=>{const n=h();return n&&ke(n)?(E("preview",n),""):n}),[P,M]=k(e.tab??e.defaultTab),[$,B]=k(e.activeFile),[ae,ie]=k(0),[S,O]=k(e.maximized??!1);F(()=>O(e.maximized??!1));const le=()=>{var n;const l=!S();O(l),(n=e.onMaximizeChange)==null||n.call(e,l)},L=y(()=>{const n=h();return!!n&&n!=="about:blank"&&ee(n)}),U=()=>{const n=h();if(!L()){n&&n!=="about:blank"&&E("openExternal",n);return}window.open(n,"_blank","noopener,noreferrer")},D=y(()=>e.expandable&&!e.standalone),oe=y(()=>e.showNav||e.showReload||e.showHome||e.showPathField||e.showTabs||D()||e.openInTab);let x;F(()=>{e.tab!==void 0&&M(e.tab)}),F(()=>B(e.activeFile)),F(Q(()=>e.src,n=>{n&&n!==h()&&T(n)},{defer:!0}));const A=n=>n===void 0?void 0:e.files.find(l=>l.path===n),V=y(()=>A($())),se=y(()=>{const n=V();return!!n&&n.type!=="image"&&n.type!=="pdf"&&typeof n.code=="string"});function T(n){if(n===h()){j();return}s(l=>[...l.slice(0,d()+1),n]),u(l=>l+1),R()}function R(){var n;x&&(x.src=w()||"about:blank"),(n=e.onNavigate)==null||n.call(e,h())}function de(n){var l;n!==P()&&(M(n),(l=e.onTabChange)==null||l.call(e,n))}function W(n,l){var m;B(n),(m=e.onFileSelect)==null||m.call(e,n),T(rr(l,e.src))}const K=()=>{f()&&(u(n=>n-1),R())},_=()=>{b()&&(u(n=>n+1),R())};function j(){var n;x&&(x.src="about:blank",x.src=w()||"about:blank"),ie(l=>l+1),(n=e.onNavigate)==null||n.call(e,h())}const q=()=>{e.src&&T(e.src)},G=n=>{var l;S()!==n&&(O(n),(l=e.onMaximizeChange)==null||l.call(e,n))};X(()=>{var n;(n=e.controllerRef)==null||n.call(e,{back:()=>K(),forward:()=>_(),reload:()=>j(),home:()=>q(),navigate:l=>T(l),selectFile:l=>{const m=A(l);m&&W(l,m)},openExternal:()=>U(),maximize:()=>G(!0),restore:()=>G(!1)})});const ue=()=>{var n,l;try{const m=(n=x?.contentWindow)==null?void 0:n.location.href;m&&m!=="about:blank"&&m!==h()&&(s(I=>[...I.slice(0,d()+1),m]),u(I=>I+1),(l=e.onNavigate)==null||l.call(e,m))}catch{}},ce=n=>{n.preventDefault();const l=n.currentTarget.elements.namedItem("kai-artifact-path");if(e.readonlyPath||e.displayUrl!=null){l&&(l.value=e.displayUrl??h());return}l&&l.value&&T(l.value)};return(()=>{var n=Le(),l=n.firstChild;return fe(n,J({get class(){return H("flex h-full w-full flex-col overflow-hidden bg-card text-card-foreground",e.standalone&&"rounded-xl border border-border",e.class)}},i),!1,!0),c(n,a(g,{get when(){return oe()},get children(){return a(ar,{url:()=>e.displayUrl??h(),tab:P,canBack:f,canForward:b,canHome:()=>!!e.src,onBack:K,onForward:_,onReload:j,onHome:q,onSubmitPath:ce,onTab:de,showNav:()=>e.showNav,showReload:()=>e.showReload,showHome:()=>e.showHome,showPathField:()=>e.showPathField,showTabs:()=>e.showTabs,showExpand:D,showOpenInTab:()=>e.openInTab,maximized:S,onToggleMaximize:le,canOpenInTab:L,onOpenInTab:U,readonlyPath:()=>e.readonlyPath||e.displayUrl!=null})}}),l),c(l,a(g,{get when(){return P()==="preview"},get fallback(){return a(lr,{get files(){return e.files},activeFile:$,activeFileObj:V,hasSource:se,onSelect:W})},get children(){return a(g,{get when(){return nr(h(),e.files)},get fallback(){return a(ir,{ref:m=>x=m,src:w,get sandbox(){return e.sandbox},get title(){return e.iframeTitle??"Artifact preview"},onLoad:ue})},get children(){return a(sr,{get url(){return h()},get reloadKey(){return ae()}})}})}})),n})()}function ar(r){return(()=>{var t=Ve();return c(t,a(g,{get when(){return r.showNav()},get children(){return[a(C,{variant:"ghost",size:"icon-sm","aria-label":"Back",get disabled(){return!r.canBack()},onClick:()=>r.onBack(),get children(){return a(ye,{size:16,"aria-hidden":"true"})}}),a(C,{variant:"ghost",size:"icon-sm","aria-label":"Forward",get disabled(){return!r.canForward()},onClick:()=>r.onForward(),get children(){return a(ze,{size:16,"aria-hidden":"true"})}})]}}),null),c(t,a(g,{get when(){return r.showReload()},get children(){return a(C,{variant:"ghost",size:"icon-sm","aria-label":"Reload",onClick:()=>r.onReload(),get children(){return a(Ce,{size:15,"aria-hidden":"true"})}})}}),null),c(t,a(g,{get when(){return r.showHome()},get children(){return a(C,{variant:"ghost",size:"icon-sm","aria-label":"Home",get disabled(){return!r.canHome()},onClick:()=>r.onHome(),get children(){return a(Te,{size:15,"aria-hidden":"true"})}})}}),null),c(t,a(g,{get when(){return r.showPathField()},get children(){var e=Ue(),i=e.firstChild,o=i.nextSibling;return e.addEventListener("submit",s=>r.onSubmitPath(s)),p(o,"spellcheck",!1),z(s=>{var d=r.readonlyPath()||void 0,u=r.readonlyPath()?"true":void 0,h=H("h-7 w-full rounded-md border border-border px-2.5 text-xs text-foreground font-mono outline-none",r.readonlyPath()?"bg-muted/40 cursor-default":"bg-background focus-visible:ring-2 focus-visible:ring-ring");return d!==s.e&&(o.readOnly=s.e=d),u!==s.t&&p(o,"aria-readonly",s.t=u),h!==s.a&&Y(o,s.a=h),s},{e:void 0,t:void 0,a:void 0}),z(()=>o.value=r.url()),e}}),null),c(t,a(g,{get when(){return!r.showPathField()},get children(){return De()}}),null),c(t,a(g,{get when(){return r.showExpand()},get children(){return a(C,{variant:"ghost",size:"icon-sm",get"aria-label"(){return r.maximized()?"Collapse":"Expand"},get"aria-expanded"(){return r.maximized()},onClick:()=>r.onToggleMaximize(),get children(){return a(g,{get when(){return r.maximized()},get fallback(){return a(je,{size:15,"aria-hidden":"true"})},get children(){return a(Re,{size:15,"aria-hidden":"true"})}})}})}}),null),c(t,a(g,{get when(){return r.showOpenInTab()},get children(){return a(C,{variant:"ghost",size:"icon-sm","aria-label":"Open in new tab",get disabled(){return!r.canOpenInTab()},onClick:()=>r.onOpenInTab(),get children(){return a(re,{size:15,"aria-hidden":"true"})}})}}),null),c(t,a(g,{get when(){return r.showTabs()},get children(){var e=Ae();return c(e,a(te,{label:"Preview",get icon(){return a(Fe,{size:14,"aria-hidden":"true"})},get selected(){return r.tab()==="preview"},onClick:()=>r.onTab("preview")}),null),c(e,a(te,{label:"Code",get icon(){return a(Pe,{size:14,"aria-hidden":"true"})},get selected(){return r.tab()==="code"},onClick:()=>r.onTab("code")}),null),e}}),null),t})()}function te(r){return(()=>{var t=We();return t.$$click=()=>r.onClick(),c(t,()=>r.icon,null),c(t,()=>r.label,null),z(e=>{var i=r.selected,o=H("inline-flex h-6 items-center gap-1.5 rounded px-2 text-xs font-medium transition-colors outline-none","focus-visible:ring-2 focus-visible:ring-ring",r.selected?"bg-background text-foreground shadow-sm":"text-muted-foreground hover:text-foreground");return i!==e.e&&p(t,"aria-selected",e.e=i),o!==e.t&&Y(t,e.t=o),e},{e:void 0,t:void 0}),t})()}function ir(r){return(()=>{var t=Ke();t.addEventListener("load",()=>r.onLoad());var e=r.ref;return typeof e=="function"?Z(e,t):r.ref=t,z(i=>{var o=r.src()||"about:blank",s=r.sandbox,d=r.title;return o!==i.e&&p(t,"src",i.e=o),s!==i.t&&p(t,"sandbox",i.t=s),d!==i.a&&p(t,"title",i.a=d),i},{e:void 0,t:void 0,a:void 0}),t})()}function lr(r){return(()=>{var t=_e(),e=t.firstChild,i=e.nextSibling;return c(e,a(we,{get files(){return r.files},get activeFile(){return r.activeFile()},onSelect:(o,s)=>r.onSelect(o,s)})),c(i,a(g,{get when(){return r.activeFileObj()},get fallback(){return qe()},get children(){return a(g,{get when(){return r.hasSource()},get fallback(){return(()=>{var o=Ge(),s=o.firstChild,d=s.nextSibling;return d.nextSibling,c(o,()=>r.activeFileObj().type??"binary",d),o})()},get children(){return a(me,{class:"h-full rounded-none border-0",get children(){return a(pe,{get code(){return r.activeFileObj().code??""},get language(){return r.activeFileObj().language}})}})}})}})),t})()}function or(r){const t=()=>{const i=r.url.split(/[?#]/)[0];return i.slice(i.lastIndexOf("/")+1)||"document.pdf"},e=y(()=>{if(r.url){if(ee(r.url))return r.url;E("pdf fallback",r.url)}});return(()=>{var i=Qe(),o=i.firstChild;return o.nextSibling,c(i,a(Oe,{size:40,class:"text-muted-foreground","aria-hidden":"true"}),o),c(o,t),c(i,a(g,{get when(){return e()},get fallback(){return Xe()},get children(){var s=Je(),d=s.firstChild;d.firstChild;var u=d.nextSibling,h=u.firstChild;return c(d,a(re,{size:13,"aria-hidden":"true"}),null),c(u,a(Se,{size:13,"aria-hidden":"true"}),h),z(f=>{var b=e(),w=e();return b!==f.e&&p(d,"href",f.e=b),w!==f.t&&p(u,"href",f.t=w),f},{e:void 0,t:void 0}),s}}),null),i})()}function sr(r){const[t,e]=k("loading");let i,o=0,s;const d=async()=>{if(!i){e("error");return}const u=++o;e("loading");try{const h=i.clientWidth||600;await Be(r.url,i,h),u===o&&e("success")}catch{u===o&&e("error")}};return F(Q(()=>[r.url,r.reloadKey],()=>{d()})),X(()=>{if(!i||typeof ResizeObserver>"u")return;const u=new ResizeObserver(()=>{t()==="success"&&(clearTimeout(s),s=setTimeout(()=>{d()},200))});u.observe(i),be(()=>{u.disconnect(),clearTimeout(s),o++})}),(()=>{var u=Ze(),h=u.firstChild;return Z(f=>i=f,h),c(u,a(g,{get when(){return ge(()=>!0)()&&t()==="loading"},get children(){var f=Ye();return c(f,a(xe,{variant:"circular",size:"md"})),f}}),null),c(u,a(g,{get when(){return t()==="error"},get children(){return a(or,{get url(){return r.url}})}}),null),z(()=>p(h,"aria-busy",t()==="loading")),u})()}ve(["click"]);export{tr as A};
@@ -1 +0,0 @@
1
- import{I as o}from"./Icon-DObhsRtm.js";import{c as m,q as r}from"./define-By-uL588.js";var c=[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]],e=a=>m(o,r(a,{name:"Check",iconNode:c})),f=e;export{f as c};
@@ -1 +0,0 @@
1
- import{I as r}from"./Icon-DObhsRtm.js";import{c as a,q as m}from"./define-By-uL588.js";var e=[["path",{d:"m6 9 6 6 6-6",key:"qrunsl"}]],n=o=>a(r,m(o,{name:"ChevronDown",iconNode:e})),p=n;export{p as c};
@@ -1 +0,0 @@
1
- import{I as a}from"./Icon-DObhsRtm.js";import{c as m,q as r}from"./define-By-uL588.js";var t=[["path",{d:"m9 18 6-6-6-6",key:"mthhwq"}]],e=o=>m(a,r(o,{name:"ChevronRight",iconNode:t})),h=e;export{h as c};
@@ -1 +0,0 @@
1
- import{I as m}from"./Icon-DObhsRtm.js";import{c as r,q as a}from"./define-By-uL588.js";var e=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]],o=c=>r(m,a(c,{name:"CircleCheck",iconNode:e})),i=o;export{i as c};
@@ -1 +0,0 @@
1
- import{I as c}from"./Icon-DObhsRtm.js";import{c as o,q as a}from"./define-By-uL588.js";var e=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}]],m=r=>o(c,a(r,{name:"Circle",iconNode:e})),i=m;export{i as c};
@@ -1 +0,0 @@
1
- import{g as c}from"./define-By-uL588.js";function i(t,o){const[r,n]=c(o);return[()=>t()??r(),a=>n(a)]}export{i as c};