@kitn.ai/ui 0.18.2 → 0.19.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.
- package/dist/components/thread.d.ts +54 -0
- package/dist/custom-elements.json +195 -0
- package/dist/elements/agent-card.js +1 -1
- package/dist/elements/artifact.js +1 -1
- package/dist/elements/attachments.js +1 -1
- package/dist/elements/autoloader.js +1 -1
- package/dist/elements/avatar.js +1 -1
- package/dist/elements/badge.js +1 -1
- package/dist/elements/button.js +1 -1
- package/dist/elements/card.js +1 -1
- package/dist/elements/cards.js +1 -1
- package/dist/elements/chain-of-thought.js +1 -1
- package/dist/elements/chat-scope-picker.js +1 -1
- package/dist/elements/chat-workspace.js +1 -1
- package/dist/elements/chat.js +1 -1
- package/dist/elements/checkpoint.js +1 -1
- package/dist/elements/choice.js +1 -1
- package/dist/elements/chunks/{Icon-C2LTALdM.js → Icon-11SRdjJ4.js} +1 -1
- package/dist/elements/chunks/action-icons-CtRg17uX.js +1 -0
- package/dist/elements/chunks/arrow-left-CifsGq8x.js +1 -0
- package/dist/elements/chunks/{attachments-DLJcWCDV.js → attachments-CBqQRh60.js} +1 -1
- package/dist/elements/chunks/{badge-BTNZTODL.js → badge-CxklEXQm.js} +1 -1
- package/dist/elements/chunks/{button-DBDZebGr.js → button-BD7lUvVB.js} +1 -1
- package/dist/elements/chunks/{card-YfCyI4fH.js → card-B-PRGXdj.js} +1 -1
- package/dist/elements/chunks/chat-thread-DIZbRIKG.js +1 -0
- package/dist/elements/chunks/check-CUKS495w.js +1 -0
- package/dist/elements/chunks/chevron-down-AELmYT1j.js +1 -0
- package/dist/elements/chunks/chevron-right-C8g26oKh.js +1 -0
- package/dist/elements/chunks/circle-DGcI8Cft.js +1 -0
- package/dist/elements/chunks/circle-check-DuU0IcBQ.js +1 -0
- package/dist/elements/chunks/{circle-x-pDtzlghQ.js → circle-x-mtjCO_Ok.js} +1 -1
- package/dist/elements/chunks/{code-block-DZ6mz6vs.js → code-block-BeWVttmU.js} +1 -1
- package/dist/elements/chunks/{collapsible-CWUAShMC.js → collapsible-DGjADCN6.js} +1 -1
- package/dist/elements/chunks/{composer-BZyPU6gD.js → composer-CavJww3d.js} +7 -3
- package/dist/elements/chunks/{context-Cx6eQA_G.js → context-CnlsNJSJ.js} +1 -1
- package/dist/elements/chunks/{conversation-list-C4xTQSpT.js → conversation-list-5O_KdI_I.js} +1 -1
- package/dist/elements/chunks/{default-input-BZcwyKcP.js → default-input-CB46cJJ1.js} +1 -1
- package/dist/elements/chunks/{define-CNSKFZCd.js → define-DfTe4zwZ.js} +1 -1
- package/dist/elements/chunks/{disclosure-BcBs--Jf.js → disclosure-BtFK3a-M.js} +1 -1
- package/dist/elements/chunks/{download-BDQwcFav.js → download-qJv1dS3M.js} +1 -1
- package/dist/elements/chunks/{dropdown-wgs8xCJZ.js → dropdown-UhtAueYR.js} +1 -1
- package/dist/elements/chunks/{ellipsis-CUiEJ6R1.js → ellipsis-B1sOOqiJ.js} +1 -1
- package/dist/elements/chunks/{external-link-DJUmC7g2.js → external-link-DToP_VKE.js} +1 -1
- package/dist/elements/chunks/{file-text-DOYfYvrh.js → file-text-BwUs_Pj4.js} +1 -1
- package/dist/elements/chunks/{file-tree-DQzNQrbr.js → file-tree-C6RhmSnX.js} +1 -1
- package/dist/elements/chunks/{folder-DBDUBANz.js → folder-H_Xp0GYP.js} +1 -1
- package/dist/elements/chunks/hover-card-Dn3yrk1l.js +1 -0
- package/dist/elements/chunks/icon-BrxJQXzC.js +1 -0
- package/dist/elements/chunks/{info-DBQl-m6e.js → info-11eT2q5H.js} +1 -1
- package/dist/elements/chunks/{input-DZD67EvW.js → input-B9oZKDfb.js} +1 -1
- package/dist/elements/chunks/{kbd-DbyVrlnU.js → kbd-D2fx3rWh.js} +1 -1
- package/dist/elements/chunks/{link-vko7AttA.js → link-B-RNYWNw.js} +1 -1
- package/dist/elements/chunks/{loader-Cg6rO8tQ.js → loader-BJh_aRlp.js} +1 -1
- package/dist/elements/chunks/{markdown-n3Xbj3PR.js → markdown-BIpjrDFv.js} +1 -1
- package/dist/elements/chunks/{message-CgKytiSB.js → message-CPfqj8Gi.js} +1 -1
- package/dist/elements/chunks/{message-feedback-Ds3-US0e.js → message-feedback-8uj0aVYh.js} +1 -1
- package/dist/elements/chunks/message-square-CCSQ4M9g.js +1 -0
- package/dist/elements/chunks/{minimize-2-3kCdE0q3.js → minimize-2-C9qkiTJg.js} +1 -1
- package/dist/elements/chunks/{model-switcher-BMtXGwLU.js → model-switcher-DRrMcRXH.js} +1 -1
- package/dist/elements/chunks/{overlay-B1-MBI6h.js → overlay-C8_FUL8q.js} +1 -1
- package/dist/elements/chunks/{paperclip-DDEfmkHc.js → paperclip-MA9hxLhW.js} +1 -1
- package/dist/elements/chunks/{progress-bar-Dwbiyv3s.js → progress-bar-y5G6HDjg.js} +1 -1
- package/dist/elements/chunks/{prompt-suggestion-9lvgFcEa.js → prompt-suggestion-LalWvCJy.js} +1 -1
- package/dist/elements/chunks/reasoning-CW3SDdb4.js +1 -0
- package/dist/elements/chunks/resizable-xhYF5lCQ.js +1 -0
- package/dist/elements/chunks/{rotate-cw-jpisOdOV.js → rotate-cw-2ndEXjgS.js} +1 -1
- package/dist/elements/chunks/{scroll-area-g5Ze3K6f.js → scroll-area-BzOPDXrZ.js} +1 -1
- package/dist/elements/chunks/scroll-button-B1x4cYqM.js +1 -0
- package/dist/elements/chunks/{separator-Bmjc5XyX.js → separator-CPvL5Xdl.js} +1 -1
- package/dist/elements/chunks/{settings-group-9imY3kRA.js → settings-group-BiIym17O.js} +1 -1
- package/dist/elements/chunks/{settings-Cz1bMJP9.js → settings-hmzIuNXD.js} +1 -1
- package/dist/elements/chunks/{share-BdenF0wQ.js → share-BbziTAzn.js} +1 -1
- package/dist/elements/chunks/skeleton-Bxhs1thL.js +1 -0
- package/dist/elements/chunks/{slots-DkZ-Cmha.js → slots--V19HwUb.js} +1 -1
- package/dist/elements/chunks/{star-DY6z1UUH.js → star-BHL3Va5p.js} +1 -1
- package/dist/elements/chunks/{store-th4VyJXM.js → store-tpnnWlxY.js} +1 -1
- package/dist/elements/chunks/{text-shimmer-CEi-tlXr.js → text-shimmer-1DCKivKx.js} +1 -1
- package/dist/elements/chunks/textarea-Czaowo9F.js +1 -0
- package/dist/elements/chunks/{thumbs-up-BR33KLfA.js → thumbs-up-CdLqA13R.js} +1 -1
- package/dist/elements/chunks/{toast-store-BEMda0fv.js → toast-store-BvBquUFA.js} +1 -1
- package/dist/elements/chunks/{tool-TMued3WO.js → tool-4P_ne8Go.js} +1 -1
- package/dist/elements/chunks/{tooltip-Cft_Rxiw.js → tooltip-CBeFqJKk.js} +1 -1
- package/dist/elements/chunks/{triangle-alert-B07fX3Q8.js → triangle-alert-BllqxXq8.js} +1 -1
- package/dist/elements/chunks/{use-card-resolution-M36zVciB.js → use-card-resolution-73xiddIW.js} +1 -1
- package/dist/elements/chunks/{video-MKp3LmNT.js → video-O9rA6k7S.js} +1 -1
- package/dist/elements/chunks/x-DeS3rQhx.js +1 -0
- package/dist/elements/coachmark.js +1 -1
- package/dist/elements/code-block.js +1 -1
- package/dist/elements/command.js +1 -1
- package/dist/elements/compare.js +1 -1
- package/dist/elements/composer.js +1 -1
- package/dist/elements/confirm-card.js +1 -1
- package/dist/elements/context-meter.js +1 -1
- package/dist/elements/conversation-list.js +1 -1
- package/dist/elements/dialog.js +1 -1
- package/dist/elements/editable-label.js +1 -1
- package/dist/elements/embed.js +1 -1
- package/dist/elements/empty.js +1 -1
- package/dist/elements/feedback-bar.js +1 -1
- package/dist/elements/file-tree.js +1 -1
- package/dist/elements/file-upload.js +1 -1
- package/dist/elements/form.js +1 -1
- package/dist/elements/hover-card.js +1 -1
- package/dist/elements/icon.js +1 -1
- package/dist/elements/image.js +1 -1
- package/dist/elements/input.js +1 -1
- package/dist/elements/kbd.js +1 -1
- package/dist/elements/link-preview.js +1 -1
- package/dist/elements/loader.js +1 -1
- package/dist/elements/markdown.js +1 -1
- package/dist/elements/menu.js +1 -1
- package/dist/elements/message-skills.js +1 -1
- package/dist/elements/message.js +1 -1
- package/dist/elements/model-switcher.js +1 -1
- package/dist/elements/nav.js +1 -1
- package/dist/elements/notice.js +1 -1
- package/dist/elements/pane-group.js +1 -1
- package/dist/elements/pane.js +1 -1
- package/dist/elements/popover.js +1 -1
- package/dist/elements/progress-bar.js +1 -1
- package/dist/elements/prompt-dock.js +1 -1
- package/dist/elements/prompt-input.js +1 -1
- package/dist/elements/prompt-suggestions.js +1 -1
- package/dist/elements/reasoning.js +1 -1
- package/dist/elements/remote.js +1 -1
- package/dist/elements/resizable.js +1 -1
- package/dist/elements/response-stream.js +1 -1
- package/dist/elements/screen.js +1 -1
- package/dist/elements/scroll-area.js +1 -1
- package/dist/elements/scroll-button.js +1 -1
- package/dist/elements/search.js +1 -1
- package/dist/elements/segmented.js +1 -1
- package/dist/elements/separator.js +1 -1
- package/dist/elements/setting-item.js +1 -1
- package/dist/elements/settings-group.js +1 -1
- package/dist/elements/skeleton.js +1 -1
- package/dist/elements/slots.d.ts +3 -0
- package/dist/elements/source.js +1 -1
- package/dist/elements/status.js +1 -1
- package/dist/elements/switch.js +1 -1
- package/dist/elements/tabs.js +1 -1
- package/dist/elements/tasks.js +1 -1
- package/dist/elements/text-shimmer.js +1 -1
- package/dist/elements/thinking-bar.js +1 -1
- package/dist/elements/thread.d.ts +1 -0
- package/dist/elements/thread.js +1 -0
- package/dist/elements/toast.js +1 -1
- package/dist/elements/tool.js +1 -1
- package/dist/elements/tooltip.js +1 -1
- package/dist/elements/voice-input.js +1 -1
- package/dist/elements/voice-output.js +1 -1
- package/dist/elements.d.ts +24 -0
- package/dist/index.js +3393 -3311
- package/dist/kai.es.js +1 -1
- package/dist/llms/llms-full.txt +34 -4
- package/dist/llms/llms.txt +3 -3
- package/dist/react/index.d.ts +64 -0
- package/dist/react/use-voice-input.d.ts +15 -0
- package/dist/react.js +263 -240
- package/dist/register-impl-CaaHJcea.js +145 -0
- package/dist/ui/resizable.d.ts +9 -3
- package/frameworks/react/index.tsx +32 -1
- package/frameworks/react/use-voice-input.tsx +59 -0
- package/llms-full.txt +34 -4
- package/llms.txt +3 -3
- package/package.json +27 -5
- package/src/components/component-meta.json +30 -28
- package/src/components/composer.tsx +5 -0
- package/src/components/thread.tsx +177 -0
- package/src/elements/chat-workspace.tsx +1 -1
- package/src/elements/compiled.css +1 -1
- package/src/elements/element-manifest.json +4 -0
- package/src/elements/element-meta.json +117 -0
- package/src/elements/element-types.d.ts +24 -0
- package/src/elements/icon-names.json +2 -0
- package/src/elements/menu.tsx +7 -4
- package/src/elements/register-impl.ts +2 -0
- package/src/elements/resizable.tsx +78 -2
- package/src/elements/slots.ts +7 -0
- package/src/elements/thread.tsx +105 -0
- package/src/ui/action-icons.ts +2 -1
- package/src/ui/icon.tsx +4 -0
- package/src/ui/overlay.tsx +8 -1
- package/src/ui/resizable.tsx +47 -9
- package/dist/elements/chunks/action-icons-Dtl8Ox5D.js +0 -1
- package/dist/elements/chunks/arrow-left-GbBceGBE.js +0 -1
- package/dist/elements/chunks/chat-thread-Dz2qbzvI.js +0 -1
- package/dist/elements/chunks/check-fhmRksq_.js +0 -1
- package/dist/elements/chunks/chevron-down-DcRg1aRU.js +0 -1
- package/dist/elements/chunks/chevron-right-ChzBcNJ-.js +0 -1
- package/dist/elements/chunks/circle-B4fTe9v6.js +0 -1
- package/dist/elements/chunks/circle-check-CJV-3Rem.js +0 -1
- package/dist/elements/chunks/hover-card-BQGdGAQ3.js +0 -1
- package/dist/elements/chunks/icon-CAyRqVrg.js +0 -1
- package/dist/elements/chunks/message-square-MmRkvc-M.js +0 -1
- package/dist/elements/chunks/reasoning-DzHWsdAJ.js +0 -1
- package/dist/elements/chunks/resizable-Bq_eHxUm.js +0 -1
- package/dist/elements/chunks/skeleton-Pjc5jiaY.js +0 -1
- package/dist/elements/chunks/textarea-CboigarR.js +0 -1
- package/dist/elements/chunks/x-Ckwicf6g.js +0 -1
- package/dist/register-impl-DcjZDELj.js +0 -141
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
"kai-prompt-input": "prompt-input",
|
|
5
5
|
"kai-chat": "chat",
|
|
6
6
|
"kai-workspace": "chat-workspace",
|
|
7
|
+
"kai-thread": "thread",
|
|
7
8
|
"kai-thinking-bar": "thinking-bar",
|
|
8
9
|
"kai-model-switcher": "model-switcher",
|
|
9
10
|
"kai-attachments": "attachments",
|
|
@@ -91,6 +92,9 @@
|
|
|
91
92
|
"chat-workspace": [
|
|
92
93
|
"kai-workspace"
|
|
93
94
|
],
|
|
95
|
+
"thread": [
|
|
96
|
+
"kai-thread"
|
|
97
|
+
],
|
|
94
98
|
"thinking-bar": [
|
|
95
99
|
"kai-thinking-bar"
|
|
96
100
|
],
|
|
@@ -5200,6 +5200,15 @@
|
|
|
5200
5200
|
"description": "Which item index is maximized (null = none). Declarative source of truth.",
|
|
5201
5201
|
"default": "null",
|
|
5202
5202
|
"displayType": "undefined | null | number"
|
|
5203
|
+
},
|
|
5204
|
+
{
|
|
5205
|
+
"name": "handle",
|
|
5206
|
+
"type": "undefined | \"none\" | \"line\" | \"grip\"",
|
|
5207
|
+
"optional": true,
|
|
5208
|
+
"scalar": true,
|
|
5209
|
+
"description": "Divider affordance drawn inside each draggable handle's 8px grab zone: - `line` (default) — a 1px hairline, transparent at rest, tinting on hover/drag. - `grip` — a dotted grip handle. - `none` — no visible divider, just the invisible hit-area. The full grab zone and keyboard/ARIA behavior are identical for all three.",
|
|
5210
|
+
"default": "'line'",
|
|
5211
|
+
"displayType": "undefined | \"none\" | \"line\" | \"grip\""
|
|
5203
5212
|
}
|
|
5204
5213
|
],
|
|
5205
5214
|
"events": [
|
|
@@ -6768,6 +6777,114 @@
|
|
|
6768
6777
|
],
|
|
6769
6778
|
"tokens": []
|
|
6770
6779
|
},
|
|
6780
|
+
{
|
|
6781
|
+
"tag": "kai-thread",
|
|
6782
|
+
"className": "KaiThreadElement",
|
|
6783
|
+
"displayName": "Thread",
|
|
6784
|
+
"props": [
|
|
6785
|
+
{
|
|
6786
|
+
"name": "messages",
|
|
6787
|
+
"type": "undefined | { id: string; role: \"user\" | \"assistant\"; content: string; reasoning?: undefined | { text: string; label?: undefined | string }; tools?: undefined | { type: string; state: \"input-streaming\" | \"input-available\" | \"output-available\" | \"output-error\"; input?: undefined | Record<string, unknown>; output?: undefined | Record<string, unknown>; toolCallId?: undefined | string; errorText?: undefined | string }[]; attachments?: undefined | { id: string; type: \"file\" | \"source-document\"; filename?: undefined | string; mediaType?: undefined | string; url?: undefined | string; title?: undefined | string }[]; actions?: undefined | (\"copy\" | \"like\" | \"dislike\" | \"regenerate\" | \"edit\" | { id: string; label: string; icon?: undefined | string; tooltip?: undefined | string })[]; avatar?: undefined | { src?: undefined | string; fallback?: undefined | string; alt?: undefined | string }; feedback?: undefined | \"like\" | \"dislike\" }[]",
|
|
6788
|
+
"optional": true,
|
|
6789
|
+
"scalar": false,
|
|
6790
|
+
"description": "The full message thread to render, newest last. Each entry carries its role, content, and optional reasoning/tools/attachments/actions/avatar. Set as a JS property (`el.messages = [...]`); a NEW array reference per streaming chunk re-renders (mutating in place does not).",
|
|
6791
|
+
"displayType": "undefined | { id: string; role: \"user\" | \"assistant\"; content: string; reasoning?: undefined | { text: string; label?: undefined | string }; tools?: undefined | { type: string; state: \"input-streaming\" | \"input-available\" | \"output-available\" | \"output-error\"; input?: undefined | Record<string, unknown>; output?: undefined | Record<string, unknown>; toolCallId?: undefined | string; errorText?: undefined | string }[]; attachments?: undefined | { id: string; type: \"file\" | \"source-document\"; filename?: undefined | string; mediaType?: undefined | string; url?: undefined | string; title?: undefined | string }[]; actions?: undefined | (\"copy\" | \"like\" | \"dislike\" | \"regenerate\" | \"edit\" | { id: string; label: string; icon?: undefined | string; tooltip?: undefined | string })[]; avatar?: undefined | { src?: undefined | string; fallback?: undefined | string; alt?: undefined | string }; feedback?: undefined | \"like\" | \"dislike\" }[]"
|
|
6792
|
+
},
|
|
6793
|
+
{
|
|
6794
|
+
"name": "loading",
|
|
6795
|
+
"type": "undefined | false | true",
|
|
6796
|
+
"optional": true,
|
|
6797
|
+
"scalar": true,
|
|
6798
|
+
"description": "Show a typing indicator on the pending assistant turn — set while awaiting the assistant's reply.",
|
|
6799
|
+
"default": "false",
|
|
6800
|
+
"displayType": "undefined | false | true"
|
|
6801
|
+
},
|
|
6802
|
+
{
|
|
6803
|
+
"name": "proseSize",
|
|
6804
|
+
"type": "undefined | \"sm\" | \"lg\" | \"xs\" | \"base\"",
|
|
6805
|
+
"optional": true,
|
|
6806
|
+
"scalar": true,
|
|
6807
|
+
"description": "Body/prose font scale for rendered markdown (`'xs' | 'sm' | 'base' | 'lg'`). Defaults to `'sm'`.",
|
|
6808
|
+
"default": "'sm'",
|
|
6809
|
+
"displayType": "undefined | \"sm\" | \"lg\" | \"xs\" | \"base\""
|
|
6810
|
+
},
|
|
6811
|
+
{
|
|
6812
|
+
"name": "codeTheme",
|
|
6813
|
+
"type": "undefined | string",
|
|
6814
|
+
"optional": true,
|
|
6815
|
+
"scalar": true,
|
|
6816
|
+
"description": "Shiki theme name for syntax-highlighted code blocks (e.g. `'github-dark-dimmed'`).",
|
|
6817
|
+
"default": "'github-dark-dimmed'",
|
|
6818
|
+
"displayType": "undefined | string"
|
|
6819
|
+
},
|
|
6820
|
+
{
|
|
6821
|
+
"name": "codeHighlight",
|
|
6822
|
+
"type": "undefined | false | true",
|
|
6823
|
+
"optional": true,
|
|
6824
|
+
"scalar": true,
|
|
6825
|
+
"description": "Enable Shiki syntax highlighting in code blocks. Turn off to render plain `<pre>` blocks (lighter, no highlighter load). Default true.",
|
|
6826
|
+
"default": "true",
|
|
6827
|
+
"displayType": "undefined | false | true"
|
|
6828
|
+
},
|
|
6829
|
+
{
|
|
6830
|
+
"name": "actionsReveal",
|
|
6831
|
+
"type": "undefined | \"always\" | \"hover\"",
|
|
6832
|
+
"optional": true,
|
|
6833
|
+
"scalar": true,
|
|
6834
|
+
"description": "Whether each message's action bar is always visible (`'always'`, default) or only revealed on hover of that message row (`'hover'`).",
|
|
6835
|
+
"default": "'always'",
|
|
6836
|
+
"displayType": "undefined | \"always\" | \"hover\""
|
|
6837
|
+
},
|
|
6838
|
+
{
|
|
6839
|
+
"name": "scrollButton",
|
|
6840
|
+
"type": "undefined | false | true",
|
|
6841
|
+
"optional": true,
|
|
6842
|
+
"scalar": true,
|
|
6843
|
+
"description": "Show the scroll-to-bottom button inside the scroll area. Default true.",
|
|
6844
|
+
"default": "true",
|
|
6845
|
+
"displayType": "undefined | false | true"
|
|
6846
|
+
},
|
|
6847
|
+
{
|
|
6848
|
+
"name": "class",
|
|
6849
|
+
"type": "undefined | string",
|
|
6850
|
+
"optional": true,
|
|
6851
|
+
"scalar": true,
|
|
6852
|
+
"description": "Extra classes applied to the thread's inner root.",
|
|
6853
|
+
"displayType": "undefined | string"
|
|
6854
|
+
}
|
|
6855
|
+
],
|
|
6856
|
+
"events": [
|
|
6857
|
+
{
|
|
6858
|
+
"name": "kai-message-action",
|
|
6859
|
+
"detail": "{ messageId: string; action: string; state?: undefined | \"on\" | \"off\" }",
|
|
6860
|
+
"description": "A message's action button was clicked. `action` is the built-in name (`copy` / `like` / `dislike` / `regenerate` / `edit`) or a custom id. `state` is present only for the toggleable feedback votes: `'on'` when a like/dislike is set, `'off'` when re-tapped to clear.",
|
|
6861
|
+
"displayDetail": "{ messageId: string; action: string; state?: undefined | \"on\" | \"off\" }"
|
|
6862
|
+
}
|
|
6863
|
+
],
|
|
6864
|
+
"methods": [
|
|
6865
|
+
{
|
|
6866
|
+
"name": "scrollToBottom",
|
|
6867
|
+
"params": "behavior?: ScrollBehavior",
|
|
6868
|
+
"returns": "void",
|
|
6869
|
+
"description": "Scroll the message list to the bottom (default `'smooth'`)."
|
|
6870
|
+
}
|
|
6871
|
+
],
|
|
6872
|
+
"composedFrom": [
|
|
6873
|
+
{
|
|
6874
|
+
"name": "Thread",
|
|
6875
|
+
"group": "Components",
|
|
6876
|
+
"storyId": "solid-advanced-elements-thread--docs"
|
|
6877
|
+
}
|
|
6878
|
+
],
|
|
6879
|
+
"tokens": [],
|
|
6880
|
+
"slots": [
|
|
6881
|
+
{
|
|
6882
|
+
"name": "empty",
|
|
6883
|
+
"mode": "replace",
|
|
6884
|
+
"doc": "Custom zero-state rendered in the message area while the thread is empty; replaces the built-in default."
|
|
6885
|
+
}
|
|
6886
|
+
]
|
|
6887
|
+
},
|
|
6771
6888
|
{
|
|
6772
6889
|
"tag": "kai-toast-region",
|
|
6773
6890
|
"className": "KaiToastRegionElement",
|
|
@@ -923,6 +923,8 @@ export interface KaiResizableElement extends HTMLElement {
|
|
|
923
923
|
orientation?: "vertical" | "horizontal";
|
|
924
924
|
/** Which item index is maximized (null = none). Declarative source of truth. */
|
|
925
925
|
maximizedIndex?: null | number;
|
|
926
|
+
/** Divider affordance drawn inside each draggable handle's 8px grab zone: - `line` (default) — a 1px hairline, transparent at rest, tinting on hover/drag. - `grip` — a dotted grip handle. - `none` — no visible divider, just the invisible hit-area. The full grab zone and keyboard/ARIA behavior are identical for all three. */
|
|
927
|
+
handle?: "none" | "line" | "grip";
|
|
926
928
|
}
|
|
927
929
|
|
|
928
930
|
export interface KaiResizableItemElement extends HTMLElement {
|
|
@@ -1213,6 +1215,27 @@ export interface KaiThinkingBarElement extends HTMLElement {
|
|
|
1213
1215
|
stopLabel?: string;
|
|
1214
1216
|
}
|
|
1215
1217
|
|
|
1218
|
+
export interface KaiThreadElement extends HTMLElement {
|
|
1219
|
+
/** Color mode (`auto` follows prefers-color-scheme). */
|
|
1220
|
+
theme?: 'light' | 'dark' | 'auto';
|
|
1221
|
+
/** The full message thread to render, newest last. Each entry carries its role, content, and optional reasoning/tools/attachments/actions/avatar. Set as a JS property (`el.messages = [...]`); a NEW array reference per streaming chunk re-renders (mutating in place does not). */
|
|
1222
|
+
messages?: { id: string; role: "user" | "assistant"; content: string; reasoning?: { text: string; label?: string }; tools?: { type: string; state: "input-streaming" | "input-available" | "output-available" | "output-error"; input?: Record<string, unknown>; output?: Record<string, unknown>; toolCallId?: string; errorText?: string }[]; attachments?: { id: string; type: "file" | "source-document"; filename?: string; mediaType?: string; url?: string; title?: string }[]; actions?: ("copy" | "like" | "dislike" | "regenerate" | "edit" | { id: string; label: string; icon?: string; tooltip?: string })[]; avatar?: { src?: string; fallback?: string; alt?: string }; feedback?: "like" | "dislike" }[];
|
|
1223
|
+
/** Show a typing indicator on the pending assistant turn — set while awaiting the assistant's reply. */
|
|
1224
|
+
loading?: boolean;
|
|
1225
|
+
/** Body/prose font scale for rendered markdown (`'xs' | 'sm' | 'base' | 'lg'`). Defaults to `'sm'`. */
|
|
1226
|
+
proseSize?: "sm" | "lg" | "xs" | "base";
|
|
1227
|
+
/** Shiki theme name for syntax-highlighted code blocks (e.g. `'github-dark-dimmed'`). */
|
|
1228
|
+
codeTheme?: string;
|
|
1229
|
+
/** Enable Shiki syntax highlighting in code blocks. Turn off to render plain `<pre>` blocks (lighter, no highlighter load). Default true. */
|
|
1230
|
+
codeHighlight?: boolean;
|
|
1231
|
+
/** Whether each message's action bar is always visible (`'always'`, default) or only revealed on hover of that message row (`'hover'`). */
|
|
1232
|
+
actionsReveal?: "always" | "hover";
|
|
1233
|
+
/** Show the scroll-to-bottom button inside the scroll area. Default true. */
|
|
1234
|
+
scrollButton?: boolean;
|
|
1235
|
+
/** Extra classes applied to the thread's inner root. */
|
|
1236
|
+
class?: string;
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1216
1239
|
export interface KaiToastRegionElement extends HTMLElement {
|
|
1217
1240
|
/** Color mode (`auto` follows prefers-color-scheme). */
|
|
1218
1241
|
theme?: 'light' | 'dark' | 'auto';
|
|
@@ -1412,6 +1435,7 @@ declare global {
|
|
|
1412
1435
|
'kai-tasks': KaiTasksElement;
|
|
1413
1436
|
'kai-text-shimmer': KaiTextShimmerElement;
|
|
1414
1437
|
'kai-thinking-bar': KaiThinkingBarElement;
|
|
1438
|
+
'kai-thread': KaiThreadElement;
|
|
1415
1439
|
'kai-toast-region': KaiToastRegionElement;
|
|
1416
1440
|
'kai-tool': KaiToolElement;
|
|
1417
1441
|
'kai-tooltip': KaiTooltipElement;
|
package/src/elements/menu.tsx
CHANGED
|
@@ -79,12 +79,15 @@ interface Events {
|
|
|
79
79
|
/**
|
|
80
80
|
* `<kai-menu>` — a cascading action menu driven by a JSON items-tree.
|
|
81
81
|
*
|
|
82
|
-
* Set the `items` property in JavaScript (array, not attribute). The
|
|
83
|
-
*
|
|
82
|
+
* Set the `items` property in JavaScript (array, not attribute). The menu
|
|
83
|
+
* provides its own trigger button (accessible + keyboard-wired); slot only the
|
|
84
|
+
* VISUAL content into `slot="trigger"` (an icon, text, an `<svg>`) — never your
|
|
85
|
+
* own `<button>`/`<a>`, which would nest interactive elements. Set the
|
|
86
|
+
* accessible name with the `label` attribute (for an icon-only trigger):
|
|
84
87
|
*
|
|
85
88
|
* ```html
|
|
86
|
-
* <kai-menu>
|
|
87
|
-
* <
|
|
89
|
+
* <kai-menu label="Open menu">
|
|
90
|
+
* <span slot="trigger">+</span>
|
|
88
91
|
* </kai-menu>
|
|
89
92
|
* <script type="module">
|
|
90
93
|
* import '@kitn.ai/ui/elements';
|
|
@@ -7,6 +7,8 @@ import './conversation-list';
|
|
|
7
7
|
import './prompt-input';
|
|
8
8
|
import './chat';
|
|
9
9
|
import './chat-workspace';
|
|
10
|
+
// Message-list composable (the scrolling thread slice, sans composer/header)
|
|
11
|
+
import './thread';
|
|
10
12
|
// Composable leaf elements (spike — see docs/handoff + examples/composable)
|
|
11
13
|
import './thinking-bar';
|
|
12
14
|
import './model-switcher';
|
|
@@ -55,6 +55,14 @@ interface GroupProps extends Record<string, unknown> {
|
|
|
55
55
|
orientation?: Orientation;
|
|
56
56
|
/** Which item index is maximized (null = none). Declarative source of truth. */
|
|
57
57
|
maximizedIndex?: number | null;
|
|
58
|
+
/**
|
|
59
|
+
* Divider affordance drawn inside each draggable handle's 8px grab zone:
|
|
60
|
+
* - `line` (default) — a 1px hairline, transparent at rest, tinting on hover/drag.
|
|
61
|
+
* - `grip` — a dotted grip handle.
|
|
62
|
+
* - `none` — no visible divider, just the invisible hit-area.
|
|
63
|
+
* The full grab zone and keyboard/ARIA behavior are identical for all three.
|
|
64
|
+
*/
|
|
65
|
+
handle?: 'line' | 'grip' | 'none';
|
|
58
66
|
}
|
|
59
67
|
|
|
60
68
|
interface GroupEvents extends Record<string, unknown> {
|
|
@@ -75,6 +83,7 @@ interface GroupEvents extends Record<string, unknown> {
|
|
|
75
83
|
defineWebComponent<GroupProps, GroupEvents>('kai-resizable', {
|
|
76
84
|
orientation: 'horizontal',
|
|
77
85
|
maximizedIndex: null,
|
|
86
|
+
handle: 'line',
|
|
78
87
|
}, (props, { element, dispatch }) => {
|
|
79
88
|
const [items, setItems] = createSignal<ItemInfo[]>([]);
|
|
80
89
|
const orientation = (): Orientation => (props.orientation === 'vertical' ? 'vertical' : 'horizontal');
|
|
@@ -452,7 +461,7 @@ defineWebComponent<GroupProps, GroupEvents>('kai-resizable', {
|
|
|
452
461
|
<>
|
|
453
462
|
<Show when={i() > 0}>
|
|
454
463
|
<ResizableHandle
|
|
455
|
-
|
|
464
|
+
handle={props.handle ?? 'line'}
|
|
456
465
|
orientation={orientation()}
|
|
457
466
|
static={isStatic()}
|
|
458
467
|
onPanelResize={() => {
|
|
@@ -516,6 +525,68 @@ defineWebComponent<GroupProps, GroupEvents>('kai-resizable', {
|
|
|
516
525
|
);
|
|
517
526
|
});
|
|
518
527
|
|
|
528
|
+
/**
|
|
529
|
+
* Reflect a `<kai-resizable-item>`'s reactive CONFIG props to the ATTRIBUTES the
|
|
530
|
+
* parent `<kai-resizable>` reads (`readItems()` + its `size`/`min`/`max`/`locked`
|
|
531
|
+
* MutationObserver). Framework runtimes (React et al.) assign these as DOM
|
|
532
|
+
* *properties* — `el.size = "280px"` — but component-register only mirrors
|
|
533
|
+
* attribute→property, never the reverse, so a property-set size never becomes an
|
|
534
|
+
* attribute and the parent silently falls back to a flexible split. This is the
|
|
535
|
+
* exact class of bug the `collapsed` reflection already fixed; extended here to
|
|
536
|
+
* `size`/`min`/`max` (strings) and `locked` (boolean). `hidden` is deliberately
|
|
537
|
+
* NOT reflected — native `el.hidden` reflects to the attribute on its own and the
|
|
538
|
+
* parent honours the `hidden` property directly (and maximize drives `hidden`).
|
|
539
|
+
*
|
|
540
|
+
* Durability (don't fight drags): the parent WRITES `size` back to the live percent
|
|
541
|
+
* during a drag (`persistSizes` → `setAttribute('size', …)`), and that attribute
|
|
542
|
+
* write back-propagates into this prop's signal (component-register's
|
|
543
|
+
* attributeChangedCallback → property → the solid-element prop signal). A naive
|
|
544
|
+
* "reflect on every signal change" effect would therefore re-stomp the dragged size
|
|
545
|
+
* the next time a framework re-render re-asserts the ORIGINAL declared `size`
|
|
546
|
+
* (e.g. React re-runs `el.size = "280px"` on every render). So each string reflect
|
|
547
|
+
* only writes when the value the CONSUMER declared actually changes: a signal value
|
|
548
|
+
* that already equals the current attribute came FROM an attribute write (a drag),
|
|
549
|
+
* not the consumer, so it is left untouched and is not adopted as the new baseline.
|
|
550
|
+
* Net effect: a dragged size survives re-renders, while an explicit `size` change
|
|
551
|
+
* still applies. `size` prop signals use Solid's DEFAULT (same-value-skipping)
|
|
552
|
+
* equality — this guard is needed on top of that only because of the drag-write
|
|
553
|
+
* back-propagation, which same-value-skip alone can't see.
|
|
554
|
+
*
|
|
555
|
+
* Exported for unit testing (the live Shadow-DOM element is not jsdom-friendly).
|
|
556
|
+
*/
|
|
557
|
+
export function reflectItemConfig(
|
|
558
|
+
element: HTMLElement,
|
|
559
|
+
props: { readonly size?: string; readonly min?: string; readonly max?: string },
|
|
560
|
+
flag: (name: string) => boolean,
|
|
561
|
+
) {
|
|
562
|
+
const norm = (v: unknown): string | null => (v == null || v === '' ? null : String(v));
|
|
563
|
+
const reflectString = (name: 'size' | 'min' | 'max') => {
|
|
564
|
+
// Last value the CONSUMER declared (distinct from a value the parent wrote to
|
|
565
|
+
// the attribute mid-drag). Starts `undefined`, which `norm` never returns, so
|
|
566
|
+
// the first genuine value always reflects.
|
|
567
|
+
let lastConsumer: string | null | undefined;
|
|
568
|
+
createEffect(() => {
|
|
569
|
+
const desired = norm(props[name]); // reactive read
|
|
570
|
+
if (desired === lastConsumer) return; // consumer intent unchanged → leave the attr (the drag owns it)
|
|
571
|
+
const current = element.getAttribute(name);
|
|
572
|
+
// Already matches — either untouched or the parent wrote it (drag). Don't
|
|
573
|
+
// adopt it as the consumer baseline and don't fight it.
|
|
574
|
+
if (desired === current) return;
|
|
575
|
+
lastConsumer = desired;
|
|
576
|
+
if (desired === null) element.removeAttribute(name);
|
|
577
|
+
else element.setAttribute(name, desired);
|
|
578
|
+
});
|
|
579
|
+
};
|
|
580
|
+
reflectString('size');
|
|
581
|
+
reflectString('min');
|
|
582
|
+
reflectString('max');
|
|
583
|
+
// Boolean: mirror the `collapsed`/`loading` precedent — a bare `locked` attribute
|
|
584
|
+
// and the IDL property are both honoured via `flag`. The parent also writes
|
|
585
|
+
// `locked` during maximize/restore; because `flag` re-derives from that same
|
|
586
|
+
// attribute state, the reflection stays self-consistent (no fight).
|
|
587
|
+
createEffect(() => { element.toggleAttribute('locked', flag('locked')); });
|
|
588
|
+
}
|
|
589
|
+
|
|
519
590
|
interface ItemProps extends Record<string, unknown> {
|
|
520
591
|
/** Initial main-axis size: `"280px"` (fixed) or `"25%"`/`25` (percent). Omitted → flexible. */
|
|
521
592
|
size?: string;
|
|
@@ -551,7 +622,7 @@ defineWebComponent<ItemProps>('kai-resizable-item', {
|
|
|
551
622
|
locked: false,
|
|
552
623
|
hidden: false,
|
|
553
624
|
collapsed: false,
|
|
554
|
-
}, (
|
|
625
|
+
}, (props, { element, flag }) => {
|
|
555
626
|
// Reflect the reactive `collapsed` prop to the `collapsed` ATTRIBUTE the parent
|
|
556
627
|
// <kai-resizable> reads (and observes). This is what makes a bare JSX boolean
|
|
557
628
|
// collapse the panel at INITIAL render from any framework: component-register
|
|
@@ -563,6 +634,11 @@ defineWebComponent<ItemProps>('kai-resizable-item', {
|
|
|
563
634
|
// `hidden`, so the back-compat hidden path and maximize (which drive `hidden`)
|
|
564
635
|
// are untouched.
|
|
565
636
|
createEffect(() => { element.toggleAttribute('collapsed', flag('collapsed')); });
|
|
637
|
+
// Reflect the other config props (`size`/`min`/`max`/`locked`) property→attribute
|
|
638
|
+
// for the SAME reason — a framework that sets them as DOM properties (React et al.)
|
|
639
|
+
// would otherwise be invisible to the parent. See reflectItemConfig for the
|
|
640
|
+
// drag-durability guard on `size`.
|
|
641
|
+
reflectItemConfig(element, props, flag);
|
|
566
642
|
return (
|
|
567
643
|
<>
|
|
568
644
|
{/* The item host fills the panel's single grid cell (the panel stretches it on
|
package/src/elements/slots.ts
CHANGED
|
@@ -552,11 +552,18 @@ export const MENU_PARTS: PartDef[] = [
|
|
|
552
552
|
{ name: 'shortcut', doc: 'The right-aligned per-item keyboard shortcut, rendered as kai-kbd key caps. Shown only when an item carries a `shortcut`.', recipe: 'kai-menu::part(shortcut) { opacity: 0.8 }' },
|
|
553
553
|
];
|
|
554
554
|
|
|
555
|
+
/** Slots of `<kai-thread>` (the standalone scrolling message list; messages come
|
|
556
|
+
* from the `messages` prop). */
|
|
557
|
+
export const THREAD_SLOTS: SlotDef[] = [
|
|
558
|
+
{ name: 'empty', mode: 'replace', doc: 'Custom zero-state rendered in the message area while the thread is empty; replaces the built-in default.' },
|
|
559
|
+
];
|
|
560
|
+
|
|
555
561
|
export const ELEMENT_COMPOSITION: Record<string, ElementComposition> = {
|
|
556
562
|
'kai-chat': { slots: CHAT_SLOTS, parts: CHAT_PARTS },
|
|
557
563
|
'kai-command': { parts: COMMAND_PARTS },
|
|
558
564
|
'kai-conversations': { slots: CONVERSATIONS_SLOTS, parts: CONVERSATIONS_PARTS },
|
|
559
565
|
'kai-message': { slots: MESSAGE_SLOTS, parts: MESSAGE_PARTS },
|
|
566
|
+
'kai-thread': { slots: THREAD_SLOTS },
|
|
560
567
|
'kai-prompt-input': { slots: PROMPT_INPUT_SLOTS, parts: PROMPT_INPUT_PARTS },
|
|
561
568
|
'kai-button': { slots: BUTTON_SLOTS, parts: BUTTON_PARTS },
|
|
562
569
|
'kai-badge': { parts: BADGE_PARTS },
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { createSignal, onMount, onCleanup } from 'solid-js';
|
|
2
|
+
import { defineWebComponent } from './define';
|
|
3
|
+
import { readSlots, THREAD_SLOTS } from './slots';
|
|
4
|
+
import { Thread, type ThreadController } from '../components/thread';
|
|
5
|
+
import type { ChatMessage } from './chat-types';
|
|
6
|
+
import type { ProseSize } from '../primitives/chat-config';
|
|
7
|
+
|
|
8
|
+
interface Props extends Record<string, unknown> {
|
|
9
|
+
/** The full message thread to render, newest last. Each entry carries its role,
|
|
10
|
+
* content, and optional reasoning/tools/attachments/actions/avatar. Set as a JS
|
|
11
|
+
* property (`el.messages = [...]`); a NEW array reference per streaming chunk
|
|
12
|
+
* re-renders (mutating in place does not). */
|
|
13
|
+
messages?: ChatMessage[];
|
|
14
|
+
/** Show a typing indicator on the pending assistant turn — set while awaiting
|
|
15
|
+
* the assistant's reply. */
|
|
16
|
+
loading?: boolean;
|
|
17
|
+
/** Body/prose font scale for rendered markdown (`'xs' | 'sm' | 'base' | 'lg'`).
|
|
18
|
+
* Defaults to `'sm'`. */
|
|
19
|
+
proseSize?: ProseSize;
|
|
20
|
+
/** Shiki theme name for syntax-highlighted code blocks (e.g.
|
|
21
|
+
* `'github-dark-dimmed'`). */
|
|
22
|
+
codeTheme?: string;
|
|
23
|
+
/** Enable Shiki syntax highlighting in code blocks. Turn off to render plain
|
|
24
|
+
* `<pre>` blocks (lighter, no highlighter load). Default true. */
|
|
25
|
+
codeHighlight?: boolean;
|
|
26
|
+
/** Whether each message's action bar is always visible (`'always'`, default) or
|
|
27
|
+
* only revealed on hover of that message row (`'hover'`). */
|
|
28
|
+
actionsReveal?: 'always' | 'hover';
|
|
29
|
+
/** Show the scroll-to-bottom button inside the scroll area. Default true. */
|
|
30
|
+
scrollButton?: boolean;
|
|
31
|
+
/** Extra classes applied to the thread's inner root. */
|
|
32
|
+
class?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Events fired by `<kai-thread>`. */
|
|
36
|
+
interface Events extends Record<string, unknown> {
|
|
37
|
+
/** A message's action button was clicked. `action` is the built-in name (`copy`
|
|
38
|
+
* / `like` / `dislike` / `regenerate` / `edit`) or a custom id. `state` is
|
|
39
|
+
* present only for the toggleable feedback votes: `'on'` when a like/dislike is
|
|
40
|
+
* set, `'off'` when re-tapped to clear. */
|
|
41
|
+
'kai-message-action': { messageId: string; action: string; state?: 'on' | 'off' };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* `<kai-thread>` — the scrolling message list of a chat, as a standalone
|
|
46
|
+
* composable element: one message row per `messages` entry with markdown / code
|
|
47
|
+
* highlight / reasoning + tool panels / avatars / action row, stick-to-bottom
|
|
48
|
+
* scroll with a scroll-to-bottom button, an optional typing indicator, and an
|
|
49
|
+
* `empty` slot. It fills the height its parent gives it and scrolls internally
|
|
50
|
+
* (`:host { display:block; height:100% }`). No composer, header, suggestions, or
|
|
51
|
+
* sidebar — pair it with `<kai-prompt-input>` and your own layout, or reach for
|
|
52
|
+
* the batteries-included `<kai-chat>`. Emits `kai-message-action`; exposes
|
|
53
|
+
* `scrollToBottom()`.
|
|
54
|
+
*/
|
|
55
|
+
defineWebComponent<Props, Events>('kai-thread', {
|
|
56
|
+
messages: undefined,
|
|
57
|
+
loading: false,
|
|
58
|
+
proseSize: 'sm',
|
|
59
|
+
codeTheme: 'github-dark-dimmed',
|
|
60
|
+
codeHighlight: true,
|
|
61
|
+
actionsReveal: 'always',
|
|
62
|
+
scrollButton: true,
|
|
63
|
+
class: undefined,
|
|
64
|
+
}, (props, { element, dispatch, flag, expose }) => {
|
|
65
|
+
let controller: ThreadController | undefined;
|
|
66
|
+
|
|
67
|
+
// Detect whether the consumer projected `slot="empty"` content, so the built-in
|
|
68
|
+
// default only renders when they did NOT.
|
|
69
|
+
const [slots, setSlots] = createSignal<Record<string, boolean>>({});
|
|
70
|
+
onMount(() => {
|
|
71
|
+
const read = () => setSlots(readSlots(element, THREAD_SLOTS));
|
|
72
|
+
read();
|
|
73
|
+
const observer = new MutationObserver(read);
|
|
74
|
+
observer.observe(element, { childList: true });
|
|
75
|
+
onCleanup(() => observer.disconnect());
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// Imperative method API — forward the thread's scroll control onto the host.
|
|
79
|
+
expose({
|
|
80
|
+
/** Scroll the message list to the bottom (default `'smooth'`). */
|
|
81
|
+
scrollToBottom: (behavior?: ScrollBehavior) => controller?.scrollToBottom(behavior),
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<>
|
|
86
|
+
{/* Fill the height the parent gives us and scroll internally, like
|
|
87
|
+
<kai-resizable>. Consumers only need to give a parent (or the element) a
|
|
88
|
+
height. */}
|
|
89
|
+
<style>{':host{display:block;height:100%}'}</style>
|
|
90
|
+
<Thread
|
|
91
|
+
class={props.class as string | undefined}
|
|
92
|
+
messages={(props.messages as ChatMessage[] | undefined) ?? []}
|
|
93
|
+
loading={flag('loading')}
|
|
94
|
+
proseSize={props.proseSize as ProseSize}
|
|
95
|
+
codeTheme={props.codeTheme as string}
|
|
96
|
+
codeHighlight={flag('codeHighlight')}
|
|
97
|
+
actionsReveal={props.actionsReveal as 'always' | 'hover'}
|
|
98
|
+
scrollButton={props.scrollButton !== false}
|
|
99
|
+
empty={slots()['empty'] ? <slot name="empty" /> : undefined}
|
|
100
|
+
onMessageAction={(detail) => dispatch('kai-message-action', detail)}
|
|
101
|
+
controllerRef={(c) => (controller = c)}
|
|
102
|
+
/>
|
|
103
|
+
</>
|
|
104
|
+
);
|
|
105
|
+
});
|
package/src/ui/action-icons.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Component } from 'solid-js';
|
|
2
2
|
import {
|
|
3
3
|
Copy, ThumbsUp, ThumbsDown, RefreshCw, Pencil,
|
|
4
|
-
Share, Bookmark, Download, Link, Trash2, Check, X, Star, Flag, Reply, MoreHorizontal,
|
|
4
|
+
Share, Bookmark, Download, Link, Trash2, Check, X, Star, Flag, Reply, MoreHorizontal, Volume2,
|
|
5
5
|
} from 'lucide-solid';
|
|
6
6
|
import type { ChatMessageAction } from '../elements/chat-types';
|
|
7
7
|
|
|
@@ -33,6 +33,7 @@ const ICONS: Record<string, IconComponent> = {
|
|
|
33
33
|
flag: Flag,
|
|
34
34
|
reply: Reply,
|
|
35
35
|
more: MoreHorizontal,
|
|
36
|
+
'volume-2': Volume2,
|
|
36
37
|
};
|
|
37
38
|
|
|
38
39
|
/** Resolve a curated icon name to its component, or `undefined` when unknown
|
package/src/ui/icon.tsx
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
House, Clock, Lock, Box, Briefcase, PanelLeft, Circle, SlidersHorizontal, Workflow, SquarePen,
|
|
9
9
|
Archive, ArrowUp, Bookmark, Copy, Ellipsis, ExternalLink, Flag,
|
|
10
10
|
GitBranch, GitPullRequest, ListFilter, RotateCw,
|
|
11
|
+
Moon, Sun,
|
|
11
12
|
} from 'lucide-solid';
|
|
12
13
|
|
|
13
14
|
type IconComponent = Component<{ class?: string }>;
|
|
@@ -64,6 +65,9 @@ const NAMED_ICONS: Record<string, IconComponent> = {
|
|
|
64
65
|
'git-pull-request': GitPullRequest,
|
|
65
66
|
'list-filter': ListFilter,
|
|
66
67
|
'rotate-cw': RotateCw,
|
|
68
|
+
// Theme / appearance glyphs.
|
|
69
|
+
moon: Moon,
|
|
70
|
+
sun: Sun,
|
|
67
71
|
};
|
|
68
72
|
|
|
69
73
|
/** Render an item icon.
|
package/src/ui/overlay.tsx
CHANGED
|
@@ -206,7 +206,14 @@ export function usePosition(
|
|
|
206
206
|
// on unmount via onCleanup.
|
|
207
207
|
const cleanup = autoUpdate(ref, float, update);
|
|
208
208
|
let ro: ResizeObserver | undefined;
|
|
209
|
-
|
|
209
|
+
// Only a REAL element can be observed. The composer's trigger menu anchors to a
|
|
210
|
+
// VIRTUAL reference (a caret-rect object exposing just getBoundingClientRect, no
|
|
211
|
+
// DOM node); ResizeObserver.observe() throws "parameter 1 is not of type 'Element'"
|
|
212
|
+
// on it, and that uncaught throw aborts this effect before onCleanup registers,
|
|
213
|
+
// which corrupted the menu's reactive scope so it never re-opened after the first
|
|
214
|
+
// time. autoUpdate already tracks the virtual anchor; this ResizeObserver is a
|
|
215
|
+
// real-element-only add-on for ancestor/element resizes.
|
|
216
|
+
if (typeof ResizeObserver === 'function' && ref instanceof Element) {
|
|
210
217
|
ro = new ResizeObserver(update);
|
|
211
218
|
ro.observe(ref);
|
|
212
219
|
for (const ancestor of getOverflowAncestors(ref)) {
|