@kitnai/chat 0.4.0 → 0.6.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 (36) hide show
  1. package/README.md +74 -5
  2. package/dist/custom-elements.json +475 -0
  3. package/dist/kitn-chat.es.js +18 -18
  4. package/dist/llms/llms-full.txt +55 -4
  5. package/dist/llms/llms.txt +3 -3
  6. package/dist/theme.tokens.css +31 -3
  7. package/frameworks/react/index.tsx +54 -0
  8. package/llms-full.txt +55 -4
  9. package/llms.txt +3 -3
  10. package/package.json +20 -2
  11. package/src/components/chat-thread.tsx +217 -0
  12. package/src/components/prompt-input.tsx +5 -0
  13. package/src/elements/chat-workspace.tsx +122 -0
  14. package/src/elements/chat.tsx +30 -271
  15. package/src/elements/compiled.css +1 -1
  16. package/src/elements/define.tsx +1 -1
  17. package/src/elements/element-types.d.ts +40 -0
  18. package/src/elements/kitn-chat-workspace.stories.tsx +195 -0
  19. package/src/elements/register.ts +1 -0
  20. package/src/elements/styles.css +35 -0
  21. package/src/primitives/chat-config.tsx +1 -1
  22. package/src/stories/docs/Installation.mdx +27 -0
  23. package/src/stories/docs/Integrations.mdx +2 -0
  24. package/src/stories/docs/Introduction.mdx +12 -3
  25. package/src/stories/pattern-centered-conversation.stories.tsx +93 -0
  26. package/src/stories/pattern-docked-widget.stories.tsx +93 -0
  27. package/src/stories/pattern-empty-state.stories.tsx +76 -0
  28. package/src/ui/collapsible.stories.tsx +70 -0
  29. package/src/ui/dropdown.stories.tsx +60 -0
  30. package/src/ui/hover-card.stories.tsx +78 -0
  31. package/src/ui/overlay.stories.tsx +115 -0
  32. package/src/ui/overlay.tsx +1 -1
  33. package/src/ui/scroll-area.stories.tsx +51 -0
  34. package/src/ui/scroll-area.tsx +1 -1
  35. package/src/ui/textarea.stories.tsx +77 -0
  36. package/theme.css +31 -3
package/README.md CHANGED
@@ -1,15 +1,15 @@
1
1
  # @kitnai/chat
2
2
 
3
- A SolidJS component kit for building AI chat interfaces — message threads, prompt inputs, streaming responses, markdown + code rendering, reasoning/tool panels, attachments, and a conversation sidebar.
3
+ Framework-agnostic web components for building AI chat interfaces — message threads, prompt inputs, streaming responses, markdown + code rendering, reasoning/tool panels, attachments, and a conversation sidebar. Drop them into any app: React, Vue, Angular, Svelte, or plain HTML.
4
4
 
5
5
  It can be consumed two ways:
6
6
 
7
- 1. **As SolidJS components** — import the components directly into a SolidJS app for full compositional control.
8
- 2. **As framework-agnostic web components** — drop `<kitn-chat>`, `<kitn-conversation-list>`, and `<kitn-prompt-input>` into any project (React, Vue, plain HTML). Each is fully style-isolated via Shadow DOM; SolidJS is bundled in, so the host needs nothing.
7
+ 1. **As framework-agnostic web components** *(primary)* drop `<kitn-chat>`, `<kitn-conversation-list>`, and `<kitn-prompt-input>` into any project (React, Vue, Angular, Svelte, plain HTML). Each is fully style-isolated via Shadow DOM, and the rendering runtime is bundled in, so the host needs nothing.
8
+ 2. **As native SolidJS components** — the kit is authored in SolidJS, so SolidJS apps can import the components directly for full compositional control. (This is a convenience for SolidJS users, not a requirement the web components work everywhere.)
9
9
 
10
10
  ## Highlights
11
11
 
12
- - **~50 composable components** across three layers: headless primitives → UI primitives (built on [Kobalte](https://kobalte.dev)) → AI feature components.
12
+ - **~50 composable components** across three layers: headless primitives → accessible UI primitives (built in-house, WCAG 2.1 AA — no third-party UI dependency) → AI feature components.
13
13
  - **Shadow-DOM web components** — zero CSS conflicts in any host. The host's styles can't leak in; the kit's Tailwind can't leak out.
14
14
  - **Lightweight by design** — a markdown-only `<kitn-chat>` is **~61 KB gzip** (one file). Syntax highlighting (Shiki) is loaded **on demand, per-language, with no WASM** — and never loads at all if you don't render code.
15
15
  - **Tailwind v4** design tokens — rebrand by overriding `--color-*` custom properties.
@@ -60,6 +60,25 @@ npm run build # emits dist/kitn-chat.es.js
60
60
 
61
61
  The element bundle is **ES-module only** and loads via `<script type="module">` in every modern browser. See **[docs/web-components.md](docs/web-components.md)** for the full element API (every property, event, and the `ChatMessage` schema).
62
62
 
63
+ #### Or load from a CDN (no build, no npm)
64
+
65
+ The element bundle is a self-contained ES module — load it directly from [jsDelivr](https://www.jsdelivr.com/package/npm/@kitnai/chat) or [unpkg](https://unpkg.com/browse/@kitnai/chat/), no install or bundler required:
66
+
67
+ ```html
68
+ <script type="module">
69
+ import 'https://cdn.jsdelivr.net/npm/@kitnai/chat/dist/kitn-chat.es.js';
70
+ // …or unpkg: import 'https://unpkg.com/@kitnai/chat/dist/kitn-chat.es.js';
71
+ </script>
72
+
73
+ <kitn-chat></kitn-chat>
74
+ ```
75
+
76
+ The URLs above track the **latest** release — handy for trying things out. **For production, pin an exact version** (e.g. `@kitnai/chat@0.4.0/dist/kitn-chat.es.js`): pinned URLs are immutable and cached far more aggressively, and — since this package is pre-1.0 — pinning shields you from breaking changes in a future minor release. SolidJS and the kit's CSS are bundled in, and the lazy code-highlighting chunks load from the same CDN on demand. To override design tokens, also include `theme.css`:
77
+
78
+ ```html
79
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@kitnai/chat/theme.css">
80
+ ```
81
+
63
82
  ### Option B — SolidJS components
64
83
 
65
84
  ```tsx
@@ -303,7 +322,7 @@ Storybook is the primary way to explore and develop components in isolation.
303
322
  ```
304
323
  src/
305
324
  primitives/ Headless logic hooks + ChatConfig + on-demand highlighter
306
- ui/ UI primitives (Button, Dialog, Tooltip, … built on Kobalte)
325
+ ui/ Accessible UI primitives (Button, Dropdown, Tooltip, HoverCard, … built in-house, no third-party UI deps)
307
326
  components/ AI feature components (Message, PromptInput, Markdown, Tool, …)
308
327
  elements/ Web-component facades + defineKitnElement wrapper + Vite lib entry
309
328
  stories/ Composed example stories (full chat app, layouts)
@@ -314,6 +333,56 @@ docs/
314
333
 
315
334
  The web-component layer wraps a few coarse facades over the SolidJS components; the SolidJS API stays the source of truth and is unchanged by it.
316
335
 
336
+ ## Examples
337
+
338
+ A set of runnable examples and a hosted component playground are included in the repo. See [`examples/README.md`](examples/README.md) for full details.
339
+
340
+ ### Composable showcase
341
+
342
+ The composable showcase demonstrates every individual element in one page. Build the package first, then serve from the repo root:
343
+
344
+ ```bash
345
+ npm run build # produces dist/kitn-chat.es.js
346
+ npm run examples # static server at http://localhost:8000
347
+ ```
348
+
349
+ Then open: **http://localhost:8000/examples/composable/index.html**
350
+
351
+ ### Storybook
352
+
353
+ Storybook is the primary component playground for development:
354
+
355
+ ```bash
356
+ npm run dev # dev server at http://localhost:6006
357
+ ```
358
+
359
+ The published docs are deployed to GitHub Pages:
360
+ **https://kitn-ai.github.io/chat/**
361
+
362
+ ### Framework example apps
363
+
364
+ The `examples/react`, `examples/solid`, `examples/angular`, and `examples/vue` directories are full Vite apps — install their dependencies and run the local dev server:
365
+
366
+ ```bash
367
+ cd examples/react && npm install && npm run dev
368
+ # or
369
+ cd examples/solid && npm install && npm run dev
370
+ # or
371
+ cd examples/angular && npm install && npm run dev
372
+ # or
373
+ cd examples/vue && npm install && npm run dev
374
+ ```
375
+
376
+ - `examples/react` — uses the generated React wrappers from `@kitnai/chat/react`
377
+ - `examples/solid` — uses the raw SolidJS component API
378
+ - `examples/angular` — uses the web components natively via Angular's `[prop]` / `(event)` bindings with `CUSTOM_ELEMENTS_SCHEMA` (no wrappers needed)
379
+ - `examples/vue` — uses the web components natively via Vue's `:prop.prop` modifier and `@event` bindings; `isCustomElement` in `vite.config.ts` prevents Vue treating `kitn-*` tags as Vue components
380
+
381
+ ### Docs and reference
382
+
383
+ - **[docs/web-components.md](docs/web-components.md)** — full element API: every property, event, and the `ChatMessage` schema.
384
+ - **[llms.txt](llms.txt)** / **[llms-full.txt](llms-full.txt)** — dense machine-readable references for AI coding agents.
385
+
317
386
  ## Bundle size
318
387
 
319
388
  | Scenario | Loaded |
@@ -568,6 +568,481 @@
568
568
  }
569
569
  ]
570
570
  },
571
+ {
572
+ "kind": "class",
573
+ "customElement": true,
574
+ "tagName": "kitn-chat-workspace",
575
+ "name": "KitnChatWorkspaceElement",
576
+ "description": "",
577
+ "members": [
578
+ {
579
+ "kind": "field",
580
+ "name": "groups",
581
+ "type": {
582
+ "text": "{ id: string; userId?: undefined | string; teamId?: undefined | string; name: string; sortOrder: number; createdAt: string }[]"
583
+ },
584
+ "description": "Pre-bucketed conversation groups for the sidebar. Set as a JS property.",
585
+ "privacy": "public"
586
+ },
587
+ {
588
+ "kind": "field",
589
+ "name": "conversations",
590
+ "type": {
591
+ "text": "{ id: string; title: string; groupId?: undefined | string; scope: { type: \"document\" | \"collection\"; documentId?: undefined | string; filters?: undefined | { tags?: undefined | string[]; authors?: undefined | string[]; contentType?: undefined | \"transcript\" | \"markdown\"; dateRange?: undefined | { from: string; to: string } } }; messageCount: number; lastMessageAt: string; updatedAt: string }[]"
592
+ },
593
+ "description": "Flat conversation list (auto-bucketed if `groups` is empty). Set as a JS property.",
594
+ "privacy": "public"
595
+ },
596
+ {
597
+ "kind": "field",
598
+ "name": "activeId",
599
+ "type": {
600
+ "text": "undefined | string"
601
+ },
602
+ "description": "Id of the open conversation, highlighted in the sidebar.",
603
+ "privacy": "public"
604
+ },
605
+ {
606
+ "kind": "field",
607
+ "name": "messages",
608
+ "type": {
609
+ "text": "{ 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\")[] }[]"
610
+ },
611
+ "description": "The active conversation's message thread, newest last. Set as a JS property.",
612
+ "privacy": "public"
613
+ },
614
+ {
615
+ "kind": "field",
616
+ "name": "value",
617
+ "type": {
618
+ "text": "undefined | string"
619
+ },
620
+ "description": "",
621
+ "privacy": "public"
622
+ },
623
+ {
624
+ "kind": "field",
625
+ "name": "placeholder",
626
+ "type": {
627
+ "text": "undefined | string"
628
+ },
629
+ "description": "",
630
+ "privacy": "public"
631
+ },
632
+ {
633
+ "kind": "field",
634
+ "name": "loading",
635
+ "type": {
636
+ "text": "undefined | false | true"
637
+ },
638
+ "description": "",
639
+ "privacy": "public"
640
+ },
641
+ {
642
+ "kind": "field",
643
+ "name": "suggestions",
644
+ "type": {
645
+ "text": "undefined | string[]"
646
+ },
647
+ "description": "",
648
+ "privacy": "public"
649
+ },
650
+ {
651
+ "kind": "field",
652
+ "name": "suggestionMode",
653
+ "type": {
654
+ "text": "undefined | \"submit\" | \"fill\""
655
+ },
656
+ "description": "",
657
+ "privacy": "public"
658
+ },
659
+ {
660
+ "kind": "field",
661
+ "name": "proseSize",
662
+ "type": {
663
+ "text": "undefined | \"xs\" | \"sm\" | \"base\" | \"lg\""
664
+ },
665
+ "description": "",
666
+ "privacy": "public"
667
+ },
668
+ {
669
+ "kind": "field",
670
+ "name": "codeTheme",
671
+ "type": {
672
+ "text": "undefined | string"
673
+ },
674
+ "description": "",
675
+ "privacy": "public"
676
+ },
677
+ {
678
+ "kind": "field",
679
+ "name": "codeHighlight",
680
+ "type": {
681
+ "text": "undefined | false | true"
682
+ },
683
+ "description": "",
684
+ "privacy": "public"
685
+ },
686
+ {
687
+ "kind": "field",
688
+ "name": "chatTitle",
689
+ "type": {
690
+ "text": "undefined | string"
691
+ },
692
+ "description": "",
693
+ "privacy": "public"
694
+ },
695
+ {
696
+ "kind": "field",
697
+ "name": "models",
698
+ "type": {
699
+ "text": "undefined | { id: string; name: string; provider?: undefined | string }[]"
700
+ },
701
+ "description": "",
702
+ "privacy": "public"
703
+ },
704
+ {
705
+ "kind": "field",
706
+ "name": "currentModel",
707
+ "type": {
708
+ "text": "undefined | string"
709
+ },
710
+ "description": "",
711
+ "privacy": "public"
712
+ },
713
+ {
714
+ "kind": "field",
715
+ "name": "context",
716
+ "type": {
717
+ "text": "undefined | { usedTokens: number; maxTokens: number; inputTokens?: undefined | number; outputTokens?: undefined | number; estimatedCost?: undefined | number }"
718
+ },
719
+ "description": "",
720
+ "privacy": "public"
721
+ },
722
+ {
723
+ "kind": "field",
724
+ "name": "scrollButton",
725
+ "type": {
726
+ "text": "undefined | false | true"
727
+ },
728
+ "description": "",
729
+ "privacy": "public"
730
+ },
731
+ {
732
+ "kind": "field",
733
+ "name": "search",
734
+ "type": {
735
+ "text": "undefined | false | true"
736
+ },
737
+ "description": "",
738
+ "privacy": "public"
739
+ },
740
+ {
741
+ "kind": "field",
742
+ "name": "voice",
743
+ "type": {
744
+ "text": "undefined | false | true"
745
+ },
746
+ "description": "",
747
+ "privacy": "public"
748
+ },
749
+ {
750
+ "kind": "field",
751
+ "name": "slashCommands",
752
+ "type": {
753
+ "text": "undefined | { id: string; label: string; description?: undefined | string; category?: undefined | string }[]"
754
+ },
755
+ "description": "",
756
+ "privacy": "public"
757
+ },
758
+ {
759
+ "kind": "field",
760
+ "name": "slashActiveIds",
761
+ "type": {
762
+ "text": "undefined | string[]"
763
+ },
764
+ "description": "",
765
+ "privacy": "public"
766
+ },
767
+ {
768
+ "kind": "field",
769
+ "name": "slashCompact",
770
+ "type": {
771
+ "text": "undefined | false | true"
772
+ },
773
+ "description": "",
774
+ "privacy": "public"
775
+ },
776
+ {
777
+ "kind": "field",
778
+ "name": "sidebarWidth",
779
+ "type": {
780
+ "text": "undefined | number"
781
+ },
782
+ "description": "Sidebar default width as a percent of the workspace (default 22).",
783
+ "privacy": "public"
784
+ },
785
+ {
786
+ "kind": "field",
787
+ "name": "sidebarMinWidth",
788
+ "type": {
789
+ "text": "undefined | number"
790
+ },
791
+ "description": "Sidebar min width in px (default 200).",
792
+ "privacy": "public"
793
+ },
794
+ {
795
+ "kind": "field",
796
+ "name": "sidebarMaxWidth",
797
+ "type": {
798
+ "text": "undefined | number"
799
+ },
800
+ "description": "Sidebar max width in px (default 420).",
801
+ "privacy": "public"
802
+ },
803
+ {
804
+ "kind": "field",
805
+ "name": "sidebarCollapsed",
806
+ "type": {
807
+ "text": "undefined | false | true"
808
+ },
809
+ "description": "Initial collapsed state of the sidebar (default false).",
810
+ "privacy": "public"
811
+ }
812
+ ],
813
+ "attributes": [
814
+ {
815
+ "name": "theme",
816
+ "type": {
817
+ "text": "'light' | 'dark' | 'auto'"
818
+ },
819
+ "description": "Color mode (auto follows prefers-color-scheme)."
820
+ },
821
+ {
822
+ "name": "active-id",
823
+ "fieldName": "activeId",
824
+ "type": {
825
+ "text": "undefined | string"
826
+ },
827
+ "description": "Id of the open conversation, highlighted in the sidebar."
828
+ },
829
+ {
830
+ "name": "value",
831
+ "fieldName": "value",
832
+ "type": {
833
+ "text": "undefined | string"
834
+ },
835
+ "description": ""
836
+ },
837
+ {
838
+ "name": "placeholder",
839
+ "fieldName": "placeholder",
840
+ "type": {
841
+ "text": "undefined | string"
842
+ },
843
+ "description": ""
844
+ },
845
+ {
846
+ "name": "loading",
847
+ "fieldName": "loading",
848
+ "type": {
849
+ "text": "undefined | false | true"
850
+ },
851
+ "description": ""
852
+ },
853
+ {
854
+ "name": "suggestion-mode",
855
+ "fieldName": "suggestionMode",
856
+ "type": {
857
+ "text": "undefined | \"submit\" | \"fill\""
858
+ },
859
+ "description": ""
860
+ },
861
+ {
862
+ "name": "prose-size",
863
+ "fieldName": "proseSize",
864
+ "type": {
865
+ "text": "undefined | \"xs\" | \"sm\" | \"base\" | \"lg\""
866
+ },
867
+ "description": ""
868
+ },
869
+ {
870
+ "name": "code-theme",
871
+ "fieldName": "codeTheme",
872
+ "type": {
873
+ "text": "undefined | string"
874
+ },
875
+ "description": ""
876
+ },
877
+ {
878
+ "name": "code-highlight",
879
+ "fieldName": "codeHighlight",
880
+ "type": {
881
+ "text": "undefined | false | true"
882
+ },
883
+ "description": ""
884
+ },
885
+ {
886
+ "name": "chat-title",
887
+ "fieldName": "chatTitle",
888
+ "type": {
889
+ "text": "undefined | string"
890
+ },
891
+ "description": ""
892
+ },
893
+ {
894
+ "name": "current-model",
895
+ "fieldName": "currentModel",
896
+ "type": {
897
+ "text": "undefined | string"
898
+ },
899
+ "description": ""
900
+ },
901
+ {
902
+ "name": "scroll-button",
903
+ "fieldName": "scrollButton",
904
+ "type": {
905
+ "text": "undefined | false | true"
906
+ },
907
+ "description": ""
908
+ },
909
+ {
910
+ "name": "search",
911
+ "fieldName": "search",
912
+ "type": {
913
+ "text": "undefined | false | true"
914
+ },
915
+ "description": ""
916
+ },
917
+ {
918
+ "name": "voice",
919
+ "fieldName": "voice",
920
+ "type": {
921
+ "text": "undefined | false | true"
922
+ },
923
+ "description": ""
924
+ },
925
+ {
926
+ "name": "slash-compact",
927
+ "fieldName": "slashCompact",
928
+ "type": {
929
+ "text": "undefined | false | true"
930
+ },
931
+ "description": ""
932
+ },
933
+ {
934
+ "name": "sidebar-width",
935
+ "fieldName": "sidebarWidth",
936
+ "type": {
937
+ "text": "undefined | number"
938
+ },
939
+ "description": "Sidebar default width as a percent of the workspace (default 22)."
940
+ },
941
+ {
942
+ "name": "sidebar-min-width",
943
+ "fieldName": "sidebarMinWidth",
944
+ "type": {
945
+ "text": "undefined | number"
946
+ },
947
+ "description": "Sidebar min width in px (default 200)."
948
+ },
949
+ {
950
+ "name": "sidebar-max-width",
951
+ "fieldName": "sidebarMaxWidth",
952
+ "type": {
953
+ "text": "undefined | number"
954
+ },
955
+ "description": "Sidebar max width in px (default 420)."
956
+ },
957
+ {
958
+ "name": "sidebar-collapsed",
959
+ "fieldName": "sidebarCollapsed",
960
+ "type": {
961
+ "text": "undefined | false | true"
962
+ },
963
+ "description": "Initial collapsed state of the sidebar (default false)."
964
+ }
965
+ ],
966
+ "events": [
967
+ {
968
+ "name": "conversationselect",
969
+ "type": {
970
+ "text": "CustomEvent<unknown>"
971
+ },
972
+ "description": ""
973
+ },
974
+ {
975
+ "name": "messageaction",
976
+ "type": {
977
+ "text": "CustomEvent<unknown>"
978
+ },
979
+ "description": ""
980
+ },
981
+ {
982
+ "name": "modelchange",
983
+ "type": {
984
+ "text": "CustomEvent<unknown>"
985
+ },
986
+ "description": ""
987
+ },
988
+ {
989
+ "name": "newchat",
990
+ "type": {
991
+ "text": "CustomEvent<unknown>"
992
+ },
993
+ "description": ""
994
+ },
995
+ {
996
+ "name": "search",
997
+ "type": {
998
+ "text": "CustomEvent<unknown>"
999
+ },
1000
+ "description": ""
1001
+ },
1002
+ {
1003
+ "name": "sidebartoggle",
1004
+ "type": {
1005
+ "text": "CustomEvent<unknown>"
1006
+ },
1007
+ "description": ""
1008
+ },
1009
+ {
1010
+ "name": "slashselect",
1011
+ "type": {
1012
+ "text": "CustomEvent<unknown>"
1013
+ },
1014
+ "description": ""
1015
+ },
1016
+ {
1017
+ "name": "submit",
1018
+ "type": {
1019
+ "text": "CustomEvent<unknown>"
1020
+ },
1021
+ "description": ""
1022
+ },
1023
+ {
1024
+ "name": "suggestionclick",
1025
+ "type": {
1026
+ "text": "CustomEvent<unknown>"
1027
+ },
1028
+ "description": ""
1029
+ },
1030
+ {
1031
+ "name": "valuechange",
1032
+ "type": {
1033
+ "text": "CustomEvent<unknown>"
1034
+ },
1035
+ "description": ""
1036
+ },
1037
+ {
1038
+ "name": "voice",
1039
+ "type": {
1040
+ "text": "CustomEvent<unknown>"
1041
+ },
1042
+ "description": ""
1043
+ }
1044
+ ]
1045
+ },
571
1046
  {
572
1047
  "kind": "class",
573
1048
  "customElement": true,