@adea-ai/ui 0.89.1 → 0.93.2

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 (102) hide show
  1. package/README.md +22 -5
  2. package/dist/NOTICE +19 -0
  3. package/dist/components/composites/list-row/index.d.ts +1 -0
  4. package/dist/components/composites/list-row/index.d.ts.map +1 -1
  5. package/dist/components/composites/list-row/index.js +2 -1
  6. package/dist/components/composites/list-row/list-row-control.d.ts +20 -0
  7. package/dist/components/composites/list-row/list-row-control.d.ts.map +1 -0
  8. package/dist/components/composites/list-row/list-row-control.js +96 -0
  9. package/dist/components/composites/list-row/list-row-control.js.map +1 -0
  10. package/dist/components/composites/list-row/list-row.d.ts +15 -35
  11. package/dist/components/composites/list-row/list-row.d.ts.map +1 -1
  12. package/dist/components/composites/list-row/list-row.js +88 -135
  13. package/dist/components/composites/list-row/list-row.js.map +1 -1
  14. package/dist/components/composites/tree/index.d.ts +4 -0
  15. package/dist/components/composites/tree/index.d.ts.map +1 -0
  16. package/dist/components/composites/tree/index.js +2 -0
  17. package/dist/components/composites/tree/tree-navigation.d.ts +46 -0
  18. package/dist/components/composites/tree/tree-navigation.d.ts.map +1 -0
  19. package/dist/components/composites/tree/tree-navigation.js +95 -0
  20. package/dist/components/composites/tree/tree-navigation.js.map +1 -0
  21. package/dist/components/composites/tree/tree.d.ts +64 -0
  22. package/dist/components/composites/tree/tree.d.ts.map +1 -0
  23. package/dist/components/composites/tree/tree.js +311 -0
  24. package/dist/components/composites/tree/tree.js.map +1 -0
  25. package/dist/components/conversation/message-composer.d.ts +18 -3
  26. package/dist/components/conversation/message-composer.d.ts.map +1 -1
  27. package/dist/components/conversation/message-composer.js +93 -27
  28. package/dist/components/conversation/message-composer.js.map +1 -1
  29. package/dist/components/layout/sidebar-nav/index.d.ts +1 -1
  30. package/dist/components/layout/sidebar-nav/index.d.ts.map +1 -1
  31. package/dist/components/layout/sidebar-nav/index.js +2 -2
  32. package/dist/components/layout/sidebar-nav/sidebar-nav.d.ts +19 -1
  33. package/dist/components/layout/sidebar-nav/sidebar-nav.d.ts.map +1 -1
  34. package/dist/components/layout/sidebar-nav/sidebar-nav.js +83 -17
  35. package/dist/components/layout/sidebar-nav/sidebar-nav.js.map +1 -1
  36. package/dist/components/layout/top-bar/top-bar.d.ts +6 -5
  37. package/dist/components/layout/top-bar/top-bar.d.ts.map +1 -1
  38. package/dist/components/layout/top-bar/top-bar.js +30 -7
  39. package/dist/components/layout/top-bar/top-bar.js.map +1 -1
  40. package/dist/components/ui/dialog/dialog.d.ts +2 -0
  41. package/dist/components/ui/dialog/dialog.d.ts.map +1 -1
  42. package/dist/components/ui/dialog/dialog.js +4 -3
  43. package/dist/components/ui/dialog/dialog.js.map +1 -1
  44. package/dist/components/ui/modal-dialog/modal-dialog.d.ts +5 -2
  45. package/dist/components/ui/modal-dialog/modal-dialog.d.ts.map +1 -1
  46. package/dist/components/ui/modal-dialog/modal-dialog.js +33 -24
  47. package/dist/components/ui/modal-dialog/modal-dialog.js.map +1 -1
  48. package/dist/components/ui/textarea/index.d.ts +1 -1
  49. package/dist/components/ui/textarea/index.d.ts.map +1 -1
  50. package/dist/components/ui/textarea/index.js +2 -2
  51. package/dist/components/ui/textarea/textarea.d.ts +15 -2
  52. package/dist/components/ui/textarea/textarea.d.ts.map +1 -1
  53. package/dist/components/ui/textarea/textarea.js +47 -3
  54. package/dist/components/ui/textarea/textarea.js.map +1 -1
  55. package/dist/components/ui/tooltip/tooltip.d.ts.map +1 -1
  56. package/dist/components/ui/tooltip/tooltip.js +239 -17
  57. package/dist/components/ui/tooltip/tooltip.js.map +1 -1
  58. package/dist/index.d.ts +1 -0
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/index.js +5 -3
  61. package/dist/lib/variants.js +2 -2
  62. package/dist/r/conversation.json +1 -0
  63. package/dist/r/list-row.json +5 -0
  64. package/dist/r/registry.json +41 -2
  65. package/dist/r/src/components/composites/list-row/index.ts +1 -0
  66. package/dist/r/src/components/composites/list-row/list-row-control.tsx +108 -0
  67. package/dist/r/src/components/composites/list-row/list-row.tsx +60 -127
  68. package/dist/r/src/components/composites/tree/index.ts +3 -0
  69. package/dist/r/src/components/composites/tree/tree-navigation.ts +114 -0
  70. package/dist/r/src/components/composites/tree/tree.tsx +405 -0
  71. package/dist/r/src/components/conversation/message-composer.tsx +103 -22
  72. package/dist/r/src/components/layout/sidebar-nav/index.ts +3 -0
  73. package/dist/r/src/components/layout/sidebar-nav/sidebar-nav.tsx +75 -6
  74. package/dist/r/src/components/layout/top-bar/top-bar.tsx +34 -11
  75. package/dist/r/src/components/ui/dialog/dialog.tsx +4 -2
  76. package/dist/r/src/components/ui/modal-dialog/modal-dialog.tsx +20 -4
  77. package/dist/r/src/components/ui/textarea/index.ts +1 -1
  78. package/dist/r/src/components/ui/textarea/textarea.tsx +52 -10
  79. package/dist/r/src/components/ui/tooltip/tooltip.tsx +305 -10
  80. package/dist/r/src/styles/base.css +40 -0
  81. package/dist/r/textarea.json +3 -1
  82. package/dist/r/top-bar.json +3 -1
  83. package/dist/r/tree.json +29 -0
  84. package/package.json +4 -1
  85. package/registry.json +41 -2
  86. package/src/components/composites/list-row/index.ts +1 -0
  87. package/src/components/composites/list-row/list-row-control.tsx +108 -0
  88. package/src/components/composites/list-row/list-row.tsx +60 -127
  89. package/src/components/composites/tree/index.ts +3 -0
  90. package/src/components/composites/tree/tree-navigation.ts +114 -0
  91. package/src/components/composites/tree/tree.tsx +405 -0
  92. package/src/components/conversation/message-composer.tsx +103 -22
  93. package/src/components/layout/sidebar-nav/index.ts +3 -0
  94. package/src/components/layout/sidebar-nav/sidebar-nav.tsx +75 -6
  95. package/src/components/layout/top-bar/top-bar.tsx +34 -11
  96. package/src/components/ui/dialog/dialog.tsx +4 -2
  97. package/src/components/ui/modal-dialog/modal-dialog.tsx +20 -4
  98. package/src/components/ui/textarea/index.ts +1 -1
  99. package/src/components/ui/textarea/textarea.tsx +52 -10
  100. package/src/components/ui/tooltip/tooltip.tsx +305 -10
  101. package/src/index.ts +1 -0
  102. package/src/styles/base.css +40 -0
@@ -1,19 +1,26 @@
1
1
  import { cn } from "../../lib/utils.js";
2
- import { Button } from "../ui/button/button.js";
3
2
  import { Spinner } from "../ui/spinner/spinner.js";
3
+ import { ActionButton } from "../composites/action-button/action-button.js";
4
4
  import { Kbd } from "../ui/kbd/kbd.js";
5
5
  import { Textarea } from "../ui/textarea/textarea.js";
6
6
  import { createComposerImeGuard } from "./ime-guard.js";
7
- import { className, createComponent, effect, insert, memo, mergeProps, spread, template } from "solid-js/web";
7
+ import { className, createComponent, delegateEvents, effect, insert, memo, mergeProps, setAttribute, spread, template } from "solid-js/web";
8
8
  import { CornerDownLeft, Paperclip, Send, X } from "lucide-solid";
9
- import { Show, createSignal, splitProps } from "solid-js";
9
+ import { Show, createSignal, createUniqueId, splitProps } from "solid-js";
10
10
  //#region src/components/conversation/message-composer.tsx
11
11
  var _tmpl$ = /*#__PURE__*/ template(`<div>`);
12
12
  var _tmpl$2 = /*#__PURE__*/ template(`<p class="text-muted-foreground flex items-center gap-1.5 text-2xs"> to send<span aria-hidden=true>·</span> <!> for a new line`);
13
- var _tmpl$3 = /*#__PURE__*/ template(`<form data-slot=message-composer><div><div class="flex items-center gap-1"><div class="ms-auto flex items-center gap-1"></div></div></div><div aria-live=polite class=min-h-0>`);
13
+ var _tmpl$3 = /*#__PURE__*/ template(`<form data-slot=message-composer><div><div class="flex items-center gap-1"><div class="ms-auto flex items-center gap-1"></div></div></div><div role=status aria-live=polite class=min-h-0>`);
14
14
  var _tmpl$4 = /*#__PURE__*/ template(`<div class="bg-muted text-muted-foreground flex items-center gap-2 rounded-md px-2.5 py-1.5 text-xs"><span class="min-w-0 flex-1 truncate">Replying to `);
15
- var _tmpl$5 = /*#__PURE__*/ template(`<p class="text-foreground border-s-2 border-destructive ps-2 text-xs">`);
16
- var _tmpl$6 = /*#__PURE__*/ template(`<p>`);
15
+ var _tmpl$5 = /*#__PURE__*/ template(`<span class=sr-only>`);
16
+ var _tmpl$6 = /*#__PURE__*/ template(`<p class="text-foreground border-s-2 border-destructive ps-2 text-xs">`);
17
+ var _tmpl$7 = /*#__PURE__*/ template(`<p>`);
18
+ function invokeEventHandler(handler, event) {
19
+ if (Array.isArray(handler)) {
20
+ const [callback, data] = handler;
21
+ callback(data, event);
22
+ } else if (typeof handler === "function") handler(event);
23
+ }
17
24
  function MessageComposer(props) {
18
25
  const [local, rest] = splitProps(props, [
19
26
  "class",
@@ -27,11 +34,23 @@ function MessageComposer(props) {
27
34
  "leading",
28
35
  "trailing",
29
36
  "menu",
30
- "replyTo"
37
+ "replyTo",
38
+ "inputRef",
39
+ "inputId",
40
+ "inputLabel",
41
+ "inputDescription",
42
+ "inputDescribedBy",
43
+ "inputSize",
44
+ "inputResize",
45
+ "onKeyDown"
31
46
  ]);
32
47
  const [sending, setSending] = createSignal(false);
33
48
  const [error, setError] = createSignal(null);
34
49
  const ime = createComposerImeGuard();
50
+ const descriptionId = `message-composer-help-${createUniqueId()}`;
51
+ const describedBy = () => [local.inputDescribedBy, local.inputDescription ? descriptionId : void 0].filter(Boolean).join(" ") || void 0;
52
+ const actionLabel = () => local.submitLabel ?? "Send message";
53
+ const pendingLabel = () => `Sending ${local.submitLabel ? local.submitLabel.toLowerCase() : "message"}`;
35
54
  const canSend = () => local.value.trim().length > 0 && !local.disabled && !sending();
36
55
  const send = async () => {
37
56
  if (!canSend()) return;
@@ -47,17 +66,21 @@ function MessageComposer(props) {
47
66
  };
48
67
  const onKeyDown = (event) => {
49
68
  if (event.defaultPrevented) return;
50
- if (event.key === "Escape" && error()) {
51
- setError(null);
52
- return;
53
- }
54
69
  if (event.key !== "Enter") return;
55
70
  if (event.shiftKey && !event.metaKey && !event.ctrlKey) return;
56
71
  if (!ime.claimEnter(event)) return;
57
72
  send();
58
73
  };
74
+ const onFormKeyDown = (event) => {
75
+ invokeEventHandler(local.onKeyDown, event);
76
+ if (event.defaultPrevented || event.key !== "Escape" || !error() || event.isComposing || event.keyCode === 229) return;
77
+ setError(null);
78
+ event.preventDefault();
79
+ event.stopPropagation();
80
+ };
59
81
  return (() => {
60
82
  var _el$ = _tmpl$3(), _el$3 = _el$.firstChild, _el$4 = _el$3.firstChild, _el$5 = _el$4.firstChild, _el$10 = _el$3.nextSibling;
83
+ _el$.$$keydown = onFormKeyDown;
61
84
  _el$.addEventListener("submit", (event) => {
62
85
  event.preventDefault();
63
86
  send();
@@ -83,11 +106,12 @@ function MessageComposer(props) {
83
106
  var _el$11 = _tmpl$4(), _el$12 = _el$11.firstChild;
84
107
  _el$12.firstChild;
85
108
  insert(_el$12, () => reply().label, null);
86
- insert(_el$11, createComponent(Button, {
109
+ insert(_el$11, createComponent(ActionButton, {
87
110
  type: "button",
88
111
  variant: "ghost",
89
112
  size: "icon-2xs",
90
113
  "aria-label": "Cancel reply",
114
+ tooltip: "Cancel reply",
91
115
  onClick: () => reply().onDismiss(),
92
116
  get children() {
93
117
  return createComponent(X, {});
@@ -97,6 +121,13 @@ function MessageComposer(props) {
97
121
  })()
98
122
  }), _el$3);
99
123
  insert(_el$3, createComponent(Textarea, {
124
+ ref(r$) {
125
+ var _ref$ = local.inputRef;
126
+ typeof _ref$ === "function" ? _ref$(r$) : local.inputRef = r$;
127
+ },
128
+ get id() {
129
+ return local.inputId;
130
+ },
100
131
  get onCompositionStart() {
101
132
  return ime.onCompositionStart;
102
133
  },
@@ -122,9 +153,29 @@ function MessageComposer(props) {
122
153
  },
123
154
  rows: 1,
124
155
  get ["aria-label"]() {
125
- return memo(() => !!local.submitLabel)() ? `${local.submitLabel} message` : "Message";
156
+ return local.inputLabel ?? (local.submitLabel ? `${local.submitLabel} message` : "Message");
157
+ },
158
+ get ["aria-describedby"]() {
159
+ return describedBy();
126
160
  },
127
- "class": "min-h-9 resize-none border-0 bg-transparent p-0 text-sm shadow-none focus-visible:ring-0"
161
+ variant: "composer",
162
+ get size() {
163
+ return local.inputSize ?? "comfortable";
164
+ },
165
+ get resize() {
166
+ return local.inputResize ?? "vertical";
167
+ }
168
+ }), _el$4);
169
+ insert(_el$3, createComponent(Show, {
170
+ get when() {
171
+ return local.inputDescription;
172
+ },
173
+ children: (description) => (() => {
174
+ var _el$14 = _tmpl$5();
175
+ setAttribute(_el$14, "id", descriptionId);
176
+ insert(_el$14, description);
177
+ return _el$14;
178
+ })()
128
179
  }), _el$4);
129
180
  insert(_el$4, createComponent(Show, {
130
181
  get when() {
@@ -142,14 +193,17 @@ function MessageComposer(props) {
142
193
  return local.trailing;
143
194
  }
144
195
  }), null);
145
- insert(_el$5, createComponent(Button, {
196
+ insert(_el$5, createComponent(ActionButton, {
146
197
  type: "submit",
147
198
  size: "icon-sm",
148
199
  get disabled() {
149
200
  return !canSend();
150
201
  },
151
202
  get ["aria-label"]() {
152
- return sending() ? "Sending message" : "Send message";
203
+ return memo(() => !!sending())() ? pendingLabel() : actionLabel();
204
+ },
205
+ get tooltip() {
206
+ return actionLabel();
153
207
  },
154
208
  get children() {
155
209
  return createComponent(Show, {
@@ -184,13 +238,23 @@ function MessageComposer(props) {
184
238
  }), _el$10);
185
239
  insert(_el$10, createComponent(Show, {
186
240
  get when() {
187
- return error();
241
+ return sending();
188
242
  },
189
- children: (message) => (() => {
190
- var _el$14 = _tmpl$5();
191
- insert(_el$14, message);
192
- return _el$14;
193
- })()
243
+ get fallback() {
244
+ return createComponent(Show, {
245
+ get when() {
246
+ return error();
247
+ },
248
+ children: (message) => (() => {
249
+ var _el$15 = _tmpl$6();
250
+ insert(_el$15, message);
251
+ return _el$15;
252
+ })()
253
+ });
254
+ },
255
+ get children() {
256
+ return [memo(() => pendingLabel()), "…"];
257
+ }
194
258
  }));
195
259
  effect(() => className(_el$3, cn("border-input bg-card flex flex-col gap-1 rounded-lg border p-2", "transition-[color,box-shadow,border-color] ease-out", "focus-within:border-ring focus-within:ring-3 focus-within:ring-primary-subtle", local.disabled && "opacity-50")));
196
260
  return _el$;
@@ -210,7 +274,7 @@ function ComposerAttachmentButton(props) {
210
274
  "open",
211
275
  "children"
212
276
  ]);
213
- return createComponent(Button, mergeProps({
277
+ return createComponent(ActionButton, mergeProps({
214
278
  type: "button",
215
279
  variant: "ghost",
216
280
  size: "icon-sm",
@@ -220,6 +284,7 @@ function ComposerAttachmentButton(props) {
220
284
  get ["aria-expanded"]() {
221
285
  return local.open;
222
286
  },
287
+ tooltip: "Add an attachment",
223
288
  "class": "text-muted-foreground"
224
289
  }, rest, { get children() {
225
290
  return local.children ?? createComponent(Paperclip, {});
@@ -229,11 +294,11 @@ function ComposerAttachmentButton(props) {
229
294
  function ComposerHint(props) {
230
295
  const [local, rest] = splitProps(props, ["class", "children"]);
231
296
  return (() => {
232
- var _el$15 = _tmpl$6();
233
- spread(_el$15, mergeProps({ get ["class"]() {
297
+ var _el$16 = _tmpl$7();
298
+ spread(_el$16, mergeProps({ get ["class"]() {
234
299
  return cn("text-muted-foreground flex items-center gap-1.5 text-2xs", local.class);
235
300
  } }, rest), false, true);
236
- insert(_el$15, () => local.children ?? [
301
+ insert(_el$16, () => local.children ?? [
237
302
  createComponent(CornerDownLeft, {
238
303
  "aria-hidden": "true",
239
304
  "class": "size-3"
@@ -241,9 +306,10 @@ function ComposerHint(props) {
241
306
  createComponent(Kbd, { children: "Enter" }),
242
307
  " to send"
243
308
  ]);
244
- return _el$15;
309
+ return _el$16;
245
310
  })();
246
311
  }
312
+ delegateEvents(["keydown"]);
247
313
  //#endregion
248
314
  export { ComposerAttachmentButton, ComposerHint, MessageComposer };
249
315
 
@@ -1 +1 @@
1
- {"version":3,"file":"message-composer.js","names":["CornerDownLeft","Paperclip","Send","X","ComponentProps","JSX","Show","createSignal","splitProps","cn","Button","Kbd","Spinner","Textarea","createComposerImeGuard","MessageComposerProps","Omit","value","onValueChange","onSubmit","Promise","placeholder","disabled","submitLabel","showHint","leading","Element","trailing","menu","replyTo","label","onDismiss","MessageComposer","props","local","rest","sending","setSending","error","setError","ime","canSend","trim","length","send","onKeyDown","EventHandlerUnion","HTMLTextAreaElement","KeyboardEvent","event","defaultPrevented","key","shiftKey","metaKey","ctrlKey","claimEnter","_el$","_tmpl$3","_el$3","firstChild","_el$4","_el$5","_el$10","nextSibling","addEventListener","preventDefault","_$spread","_$mergeProps","class","_$insert","_$createComponent","when","children","_el$2","_tmpl$","reply","_el$11","_tmpl$4","_el$12","_el$13","type","variant","size","onClick","onCompositionStart","onCompositionEnd","onFocus","onBlur","onInput","currentTarget","rows","aria-label","_$memo","fallback","_el$6","_tmpl$2","_el$7","_el$8","_el$9","_el$1","_el$0","message","_el$14","_tmpl$5","_$effect","_$className","ComposerAttachmentButton","count","open","aria-expanded","ComposerHint","_el$15","_tmpl$6","_$mergeProps","_$createComponent","_$memo","_$className"],"sources":["../../../src/components/conversation/message-composer.tsx"],"sourcesContent":["import { CornerDownLeft, Paperclip, Send, X } from 'lucide-solid'\nimport type { ComponentProps, JSX } from 'solid-js'\nimport { Show, createSignal, splitProps } from 'solid-js'\nimport { cn } from '#lib/utils'\nimport { Button } from '../ui/button/button'\nimport { Kbd } from '../ui/kbd/kbd'\nimport { Spinner } from '../ui/spinner/spinner'\nimport { Textarea } from '../ui/textarea/textarea'\nimport { createComposerImeGuard } from './ime-guard'\n\n/**\n * MessageComposer.\n *\n * The field a message is written in. It is a form, and it behaves like one: Enter\n * sends, Shift+Enter breaks the line, Escape clears the error.\n *\n * ## What it does not know\n *\n * No mention model, no attachment model, no dictation, no idempotency keys. The\n * first version of this composer was written against adea's agent and artifact\n * types, which meant it could only ever be used by adea. Here the attachment control\n * is a *slot*, the mention menu is a slot, and a caller that has an agent model\n * renders one; a caller that does not gets a composer without it.\n *\n * ## The three things it does own\n *\n * **Enter sends, Shift+Enter breaks the line.** That is the convention every chat\n * application shares, and getting it wrong is the single most irritating thing a\n * composer can do. `⌘`/`Ctrl`+Enter is accepted too, because someone arriving from an\n * editor will try it.\n *\n * **The send button is disabled when there is nothing to send.** A control that\n * accepts a press and does nothing is worse than one that says it cannot.\n *\n * **The status region is `aria-live`.** \"Sending…\" and a failure both land there, so\n * a screen reader hears the outcome without the composer stealing focus.\n *\n * Enter ownership follows KiroCrew's pinned IME latch: candidate commits keep\n * their native default action, and the post-composition Enter cannot send or\n * insert an accidental newline. Composition abandoned by focus/blur recovers;\n * the Solid owner's cleanup settles its timer. See ime-guard.ts for provenance.\n */\nexport type MessageComposerProps = Omit<ComponentProps<'form'>, 'onSubmit'> & {\n /** The draft. Controlled: the caller owns the text, because it usually persists. */\n value: string\n onValueChange: (value: string) => void\n /** Called on send. A rejection is surfaced as an error and the draft is kept. */\n onSubmit: () => void | Promise<void>\n placeholder?: string\n /** Disable the whole composer, e.g. while the channel is read-only. */\n disabled?: boolean\n /** Label the send action for a context other than a message, e.g. a reply. */\n submitLabel?: string\n /** Show the keyboard hint under the field. */\n showHint?: boolean\n /** A leading control group, e.g. an attach button. */\n leading?: JSX.Element\n /** A trailing group before the send button, e.g. a dictation toggle. */\n trailing?: JSX.Element\n /** A menu rendered above the field, e.g. mention suggestions. */\n menu?: JSX.Element\n /** The reply target, drawn as a strip above the field. */\n replyTo?: { label: string; onDismiss: () => void }\n}\n\nexport function MessageComposer(props: MessageComposerProps) {\n const [local, rest] = splitProps(props, [\n 'class',\n 'value',\n 'onValueChange',\n 'onSubmit',\n 'placeholder',\n 'disabled',\n 'submitLabel',\n 'showHint',\n 'leading',\n 'trailing',\n 'menu',\n 'replyTo',\n ])\n\n const [sending, setSending] = createSignal(false)\n const [error, setError] = createSignal<string | null>(null)\n const ime = createComposerImeGuard()\n\n const canSend = () => local.value.trim().length > 0 && !local.disabled && !sending()\n\n const send = async () => {\n if (!canSend()) return\n setSending(true)\n setError(null)\n try {\n await local.onSubmit()\n } catch {\n // The draft is deliberately left in place. A send that fails and clears the\n // field loses the user's work, which is the worst outcome available here.\n setError('Message not sent. Your draft is still here; retry when the connection recovers.')\n } finally {\n setSending(false)\n }\n }\n\n const onKeyDown: JSX.EventHandlerUnion<HTMLTextAreaElement, KeyboardEvent> = (event) => {\n if (event.defaultPrevented) return\n if (event.key === 'Escape' && error()) {\n setError(null)\n return\n }\n if (event.key !== 'Enter') return\n // Shift breaks the line; a bare Enter, or a modified one, sends.\n if (event.shiftKey && !event.metaKey && !event.ctrlKey) return\n if (!ime.claimEnter(event)) return\n void send()\n }\n\n return (\n <form\n data-slot=\"message-composer\"\n class={cn('flex flex-col gap-2', local.class)}\n onSubmit={(event) => {\n event.preventDefault()\n void send()\n }}\n {...rest}\n >\n <Show when={local.menu}>\n <div>{local.menu}</div>\n </Show>\n\n <Show when={local.replyTo}>\n {(reply) => (\n <div class=\"bg-muted text-muted-foreground flex items-center gap-2 rounded-md px-2.5 py-1.5 text-xs\">\n <span class=\"min-w-0 flex-1 truncate\">Replying to {reply().label}</span>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-2xs\"\n aria-label=\"Cancel reply\"\n onClick={() => reply().onDismiss()}\n >\n <X />\n </Button>\n </div>\n )}\n </Show>\n\n <div\n class={cn(\n 'border-input bg-card flex flex-col gap-1 rounded-lg border p-2',\n 'transition-[color,box-shadow,border-color] ease-out',\n 'focus-within:border-ring focus-within:ring-3 focus-within:ring-primary-subtle',\n local.disabled && 'opacity-50'\n )}\n >\n <Textarea\n onCompositionStart={ime.onCompositionStart}\n onCompositionEnd={ime.onCompositionEnd}\n onFocus={ime.onFocus}\n onBlur={ime.onBlur}\n value={local.value}\n onInput={(event) => local.onValueChange(event.currentTarget.value)}\n onKeyDown={onKeyDown}\n placeholder={local.placeholder ?? 'Write a message…'}\n disabled={local.disabled}\n rows={1}\n aria-label={local.submitLabel ? `${local.submitLabel} message` : 'Message'}\n class=\"min-h-9 resize-none border-0 bg-transparent p-0 text-sm shadow-none focus-visible:ring-0\"\n />\n\n <div class=\"flex items-center gap-1\">\n <Show when={local.leading}>{local.leading}</Show>\n <div class=\"ms-auto flex items-center gap-1\">\n <Show when={local.trailing}>{local.trailing}</Show>\n <Button\n type=\"submit\"\n size=\"icon-sm\"\n disabled={!canSend()}\n aria-label={sending() ? 'Sending message' : 'Send message'}\n >\n <Show when={sending()} fallback={<Send />}>\n <Spinner size=\"sm\" label={false} class=\"text-primary-foreground\" />\n </Show>\n </Button>\n </div>\n </div>\n </div>\n\n <Show when={local.showHint}>\n <p class=\"text-muted-foreground flex items-center gap-1.5 text-2xs\">\n <Kbd>Enter</Kbd> to send\n <span aria-hidden=\"true\">·</span>\n <Kbd>Shift</Kbd> <Kbd>Enter</Kbd> for a new line\n </p>\n </Show>\n\n {/* A live region, so the outcome is announced without moving focus out of the\n field the user is typing in. */}\n <div aria-live=\"polite\" class=\"min-h-0\">\n <Show when={error()}>\n {(message) => (\n <p class=\"text-foreground border-s-2 border-destructive ps-2 text-xs\">{message()}</p>\n )}\n </Show>\n </div>\n </form>\n )\n}\n\n/**\n * The attachment control.\n *\n * A slot rather than a built-in, because what can be attached is the application's\n * business — but the *button* is shared, so it looks and behaves the same in both.\n * The count is announced, since a paperclip alone does not say whether anything is\n * attached.\n */\nexport function ComposerAttachmentButton(\n props: ComponentProps<typeof Button> & { count?: number; open?: boolean }\n) {\n const [local, rest] = splitProps(props, ['count', 'open', 'children'])\n\n return (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-label={local.count ? `${local.count} attached, add an attachment` : 'Add an attachment'}\n aria-expanded={local.open}\n class=\"text-muted-foreground\"\n {...rest}\n >\n {local.children ?? <Paperclip />}\n </Button>\n )\n}\n\n/** The hint a composer shows when the field is empty, as a one-line prompt. */\nexport function ComposerHint(props: ComponentProps<'p'>) {\n const [local, rest] = splitProps(props, ['class', 'children'])\n return (\n <p\n class={cn('text-muted-foreground flex items-center gap-1.5 text-2xs', local.class)}\n {...rest}\n >\n {local.children ?? (\n <>\n <CornerDownLeft aria-hidden=\"true\" class=\"size-3\" />\n <Kbd>Enter</Kbd> to send\n </>\n )}\n </p>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"message-composer.js","names":["CornerDownLeft","Paperclip","Send","X","ComponentProps","JSX","Ref","Show","createSignal","createUniqueId","splitProps","cn","ActionButton","Button","Kbd","Spinner","Textarea","createComposerImeGuard","invokeEventHandler","handler","event","Event","Array","isArray","callback","data","MessageComposerProps","Omit","value","onValueChange","onSubmit","Promise","placeholder","disabled","submitLabel","showHint","leading","Element","trailing","menu","replyTo","label","onDismiss","inputRef","HTMLTextAreaElement","inputId","inputLabel","inputDescription","inputDescribedBy","inputSize","inputResize","MessageComposer","props","local","rest","sending","setSending","error","setError","ime","descriptionId","describedBy","undefined","filter","Boolean","join","actionLabel","pendingLabel","toLowerCase","canSend","trim","length","send","onKeyDown","EventHandlerUnion","KeyboardEvent","defaultPrevented","key","shiftKey","metaKey","ctrlKey","claimEnter","onFormKeyDown","HTMLFormElement","isComposing","keyCode","preventDefault","stopPropagation","_el$","_tmpl$3","_el$3","firstChild","_el$4","_el$5","_el$10","nextSibling","$$keydown","addEventListener","_$spread","_$mergeProps","class","_$insert","_$createComponent","when","children","_el$2","_tmpl$","reply","_el$11","_tmpl$4","_el$12","_el$13","type","variant","size","tooltip","onClick","ref","r$","_ref$","id","onCompositionStart","onCompositionEnd","onFocus","onBlur","onInput","currentTarget","rows","aria-label","aria-describedby","resize","description","_el$14","_tmpl$5","_$setAttribute","_$memo","fallback","_el$6","_tmpl$2","_el$7","_el$8","_el$9","_el$1","_el$0","message","_el$15","_tmpl$6","_$effect","_$className","ComposerAttachmentButton","count","open","aria-expanded","ComposerHint","_el$16","_tmpl$7","_$delegateEvents","_$mergeProps","_$createComponent","_$memo","_$className","_$delegateEvents"],"sources":["../../../src/components/conversation/message-composer.tsx"],"sourcesContent":["import { CornerDownLeft, Paperclip, Send, X } from 'lucide-solid'\nimport type { ComponentProps, JSX, Ref } from 'solid-js'\nimport { Show, createSignal, createUniqueId, splitProps } from 'solid-js'\nimport { cn } from '#lib/utils'\nimport { ActionButton } from '../composites/action-button/action-button'\nimport { Button } from '../ui/button/button'\nimport { Kbd } from '../ui/kbd/kbd'\nimport { Spinner } from '../ui/spinner/spinner'\nimport { Textarea } from '../ui/textarea/textarea'\nimport { createComposerImeGuard } from './ime-guard'\n\nfunction invokeEventHandler(handler: unknown, event: Event) {\n if (Array.isArray(handler)) {\n const [callback, data] = handler as [(data: unknown, event: Event) => void, unknown]\n callback(data, event)\n } else if (typeof handler === 'function') {\n const callback = handler as (event: Event) => void\n callback(event)\n }\n}\n\n/**\n * MessageComposer.\n *\n * The field a message is written in. It is a form, and it behaves like one: Enter\n * sends, Shift+Enter breaks the line, Escape clears the error from anywhere in\n * the composer unless a nested control or an active IME already owns the key.\n *\n * ## What it does not know\n *\n * No mention model, no attachment model, no dictation, no idempotency keys. The\n * first version of this composer was written against adea's agent and artifact\n * types, which meant it could only ever be used by adea. Here the attachment control\n * is a *slot*, the mention menu is a slot, and a caller that has an agent model\n * renders one; a caller that does not gets a composer without it.\n *\n * ## The three things it does own\n *\n * **Enter sends, Shift+Enter breaks the line.** That is the convention every chat\n * application shares, and getting it wrong is the single most irritating thing a\n * composer can do. `⌘`/`Ctrl`+Enter is accepted too, because someone arriving from an\n * editor will try it.\n *\n * **The send button is disabled when there is nothing to send.** A control that\n * accepts a press and does nothing is worse than one that says it cannot.\n *\n * **The status region is `aria-live`.** \"Sending…\" and a failure both land there, so\n * a screen reader hears the outcome without the composer stealing focus.\n *\n * Enter ownership follows KiroCrew's pinned IME latch: candidate commits keep\n * their native default action, and the post-composition Enter cannot send or\n * insert an accidental newline. Composition abandoned by focus/blur recovers;\n * the Solid owner's cleanup settles its timer. See ime-guard.ts for provenance.\n */\nexport type MessageComposerProps = Omit<ComponentProps<'form'>, 'onSubmit'> & {\n /** The draft. Controlled: the caller owns the text, because it usually persists. */\n value: string\n onValueChange: (value: string) => void\n /** Called on send. A rejection is surfaced as an error and the draft is kept. */\n onSubmit: () => void | Promise<void>\n placeholder?: string\n /** Disable the whole composer, e.g. while the channel is read-only. */\n disabled?: boolean\n /** Accessible name and tooltip for the action, e.g. \"Reply\". */\n submitLabel?: string\n /** Show the keyboard hint under the field. */\n showHint?: boolean\n /** A leading control group, e.g. an attach button. */\n leading?: JSX.Element\n /** A trailing group before the send button, e.g. a dictation toggle. */\n trailing?: JSX.Element\n /** A menu rendered above the field, e.g. mention suggestions. */\n menu?: JSX.Element\n /** The reply target, drawn as a strip above the field. */\n replyTo?: { label: string; onDismiss: () => void }\n /** Ref to the actual message textarea, for host focus and selection behavior. */\n inputRef?: Ref<HTMLTextAreaElement>\n /** Stable host-owned id for the actual textarea. */\n inputId?: string\n /** Accessible name for the actual textarea. Defaults to \"Message\" or \"Reply message\". */\n inputLabel?: string\n /** Additional help text associated with the actual textarea. */\n inputDescription?: string\n /** Existing host description id, combined with `inputDescription` when supplied. */\n inputDescribedBy?: string\n /** Comfortable uses the shared 4rem minimum and 12rem maximum field heights. */\n inputSize?: 'default' | 'comfortable'\n /** The shared resize behavior for the actual textarea. */\n inputResize?: 'vertical' | 'none' | 'both'\n}\n\nexport function MessageComposer(props: MessageComposerProps) {\n const [local, rest] = splitProps(props, [\n 'class',\n 'value',\n 'onValueChange',\n 'onSubmit',\n 'placeholder',\n 'disabled',\n 'submitLabel',\n 'showHint',\n 'leading',\n 'trailing',\n 'menu',\n 'replyTo',\n 'inputRef',\n 'inputId',\n 'inputLabel',\n 'inputDescription',\n 'inputDescribedBy',\n 'inputSize',\n 'inputResize',\n 'onKeyDown',\n ])\n\n const [sending, setSending] = createSignal(false)\n const [error, setError] = createSignal<string | null>(null)\n const ime = createComposerImeGuard()\n const descriptionId = `message-composer-help-${createUniqueId()}`\n const describedBy = () =>\n [local.inputDescribedBy, local.inputDescription ? descriptionId : undefined]\n .filter(Boolean)\n .join(' ') || undefined\n const actionLabel = () => local.submitLabel ?? 'Send message'\n const pendingLabel = () =>\n `Sending ${local.submitLabel ? local.submitLabel.toLowerCase() : 'message'}`\n\n const canSend = () => local.value.trim().length > 0 && !local.disabled && !sending()\n\n const send = async () => {\n if (!canSend()) return\n setSending(true)\n setError(null)\n try {\n await local.onSubmit()\n } catch {\n // The draft is deliberately left in place. A send that fails and clears the\n // field loses the user's work, which is the worst outcome available here.\n setError('Message not sent. Your draft is still here; retry when the connection recovers.')\n } finally {\n setSending(false)\n }\n }\n\n const onKeyDown: JSX.EventHandlerUnion<HTMLTextAreaElement, KeyboardEvent> = (event) => {\n if (event.defaultPrevented) return\n if (event.key !== 'Enter') return\n // Shift breaks the line; a bare Enter, or a modified one, sends.\n if (event.shiftKey && !event.metaKey && !event.ctrlKey) return\n if (!ime.claimEnter(event)) return\n void send()\n }\n\n const onFormKeyDown: JSX.EventHandlerUnion<HTMLFormElement, KeyboardEvent> = (event) => {\n invokeEventHandler(local.onKeyDown, event)\n if (\n event.defaultPrevented ||\n event.key !== 'Escape' ||\n !error() ||\n event.isComposing ||\n event.keyCode === 229\n ) {\n return\n }\n setError(null)\n event.preventDefault()\n event.stopPropagation()\n }\n\n return (\n <form\n data-slot=\"message-composer\"\n class={cn('flex flex-col gap-2', local.class)}\n onSubmit={(event) => {\n event.preventDefault()\n void send()\n }}\n onKeyDown={onFormKeyDown}\n {...rest}\n >\n <Show when={local.menu}>\n <div>{local.menu}</div>\n </Show>\n\n <Show when={local.replyTo}>\n {(reply) => (\n <div class=\"bg-muted text-muted-foreground flex items-center gap-2 rounded-md px-2.5 py-1.5 text-xs\">\n <span class=\"min-w-0 flex-1 truncate\">Replying to {reply().label}</span>\n <ActionButton\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-2xs\"\n aria-label=\"Cancel reply\"\n tooltip=\"Cancel reply\"\n onClick={() => reply().onDismiss()}\n >\n <X />\n </ActionButton>\n </div>\n )}\n </Show>\n\n <div\n class={cn(\n 'border-input bg-card flex flex-col gap-1 rounded-lg border p-2',\n 'transition-[color,box-shadow,border-color] ease-out',\n 'focus-within:border-ring focus-within:ring-3 focus-within:ring-primary-subtle',\n local.disabled && 'opacity-50'\n )}\n >\n <Textarea\n ref={local.inputRef}\n id={local.inputId}\n onCompositionStart={ime.onCompositionStart}\n onCompositionEnd={ime.onCompositionEnd}\n onFocus={ime.onFocus}\n onBlur={ime.onBlur}\n value={local.value}\n onInput={(event) => local.onValueChange(event.currentTarget.value)}\n onKeyDown={onKeyDown}\n placeholder={local.placeholder ?? 'Write a message…'}\n disabled={local.disabled}\n rows={1}\n aria-label={\n local.inputLabel ?? (local.submitLabel ? `${local.submitLabel} message` : 'Message')\n }\n aria-describedby={describedBy()}\n variant=\"composer\"\n size={local.inputSize ?? 'comfortable'}\n resize={local.inputResize ?? 'vertical'}\n />\n <Show when={local.inputDescription}>\n {(description) => (\n <span id={descriptionId} class=\"sr-only\">\n {description()}\n </span>\n )}\n </Show>\n\n <div class=\"flex items-center gap-1\">\n <Show when={local.leading}>{local.leading}</Show>\n <div class=\"ms-auto flex items-center gap-1\">\n <Show when={local.trailing}>{local.trailing}</Show>\n <ActionButton\n type=\"submit\"\n size=\"icon-sm\"\n disabled={!canSend()}\n aria-label={sending() ? pendingLabel() : actionLabel()}\n tooltip={actionLabel()}\n >\n <Show when={sending()} fallback={<Send />}>\n <Spinner size=\"sm\" label={false} class=\"text-primary-foreground\" />\n </Show>\n </ActionButton>\n </div>\n </div>\n </div>\n\n <Show when={local.showHint}>\n <p class=\"text-muted-foreground flex items-center gap-1.5 text-2xs\">\n <Kbd>Enter</Kbd> to send\n <span aria-hidden=\"true\">·</span>\n <Kbd>Shift</Kbd> <Kbd>Enter</Kbd> for a new line\n </p>\n </Show>\n\n {/* A live region, so the outcome is announced without moving focus out of the\n field the user is typing in. */}\n <div role=\"status\" aria-live=\"polite\" class=\"min-h-0\">\n <Show\n when={sending()}\n fallback={\n <Show when={error()}>\n {(message) => (\n <p class=\"text-foreground border-s-2 border-destructive ps-2 text-xs\">\n {message()}\n </p>\n )}\n </Show>\n }\n >\n {pendingLabel()}…\n </Show>\n </div>\n </form>\n )\n}\n\n/**\n * The attachment control.\n *\n * A slot rather than a built-in, because what can be attached is the application's\n * business — but the *button* is shared, so it looks and behaves the same in both.\n * The count is announced, since a paperclip alone does not say whether anything is\n * attached.\n */\nexport function ComposerAttachmentButton(\n props: ComponentProps<typeof Button> & { count?: number; open?: boolean }\n) {\n const [local, rest] = splitProps(props, ['count', 'open', 'children'])\n\n return (\n <ActionButton\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-label={local.count ? `${local.count} attached, add an attachment` : 'Add an attachment'}\n aria-expanded={local.open}\n tooltip=\"Add an attachment\"\n class=\"text-muted-foreground\"\n {...rest}\n >\n {local.children ?? <Paperclip />}\n </ActionButton>\n )\n}\n\n/** The hint a composer shows when the field is empty, as a one-line prompt. */\nexport function ComposerHint(props: ComponentProps<'p'>) {\n const [local, rest] = splitProps(props, ['class', 'children'])\n return (\n <p\n class={cn('text-muted-foreground flex items-center gap-1.5 text-2xs', local.class)}\n {...rest}\n >\n {local.children ?? (\n <>\n <CornerDownLeft aria-hidden=\"true\" class=\"size-3\" />\n <Kbd>Enter</Kbd> to send\n </>\n )}\n </p>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAWA,SAASkB,mBAAmBC,SAAkBC,OAAc;CAC1D,IAAIE,MAAMC,QAAQJ,OAAO,GAAG;EAC1B,MAAM,CAACK,UAAUC,QAAQN;EACzBK,SAASC,MAAML,KAAK;CACtB,OAAO,IAAI,OAAOD,YAAY,YAE5BK,QAASJ,KAAK;AAElB;AAwEA,SAAgB+B,gBAAgBC,OAA6B;CAC3D,MAAM,CAACC,OAAOC,QAAQ5C,WAAW0C,OAAO;EACtC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CAAW,CACZ;CAED,MAAM,CAACG,SAASC,cAAchD,aAAa,KAAK;CAChD,MAAM,CAACiD,OAAOC,YAAYlD,aAA4B,IAAI;CAC1D,MAAMmD,MAAM1C,uBAAuB;CACnC,MAAM2C,gBAAgB,yBAAyBnD,eAAe;CAC9D,MAAMoD,oBACJ,CAACR,MAAML,kBAAkBK,MAAMN,mBAAmBa,gBAAgBE,KAAAA,CAAS,CAAC,CACzEC,OAAOC,OAAO,CAAC,CACfC,KAAK,GAAG,KAAKH,KAAAA;CAClB,MAAMI,oBAAoBb,MAAMnB,eAAe;CAC/C,MAAMiC,qBACJ,WAAWd,MAAMnB,cAAcmB,MAAMnB,YAAYkC,YAAY,IAAI;CAEnE,MAAMC,gBAAgBhB,MAAMzB,MAAM0C,KAAK,CAAC,CAACC,SAAS,KAAK,CAAClB,MAAMpB,YAAY,CAACsB,QAAQ;CAEnF,MAAMiB,OAAO,YAAY;EACvB,IAAI,CAACH,QAAQ,GAAG;EAChBb,WAAW,IAAI;EACfE,SAAS,IAAI;EACb,IAAI;GACF,MAAML,MAAMvB,SAAS;EACvB,QAAQ;GAGN4B,SAAS,iFAAiF;EAC5F,UAAU;GACRF,WAAW,KAAK;EAClB;CACF;CAEA,MAAMiB,aAAwErD,UAAU;EACtF,IAAIA,MAAMwD,kBAAkB;EAC5B,IAAIxD,MAAMyD,QAAQ,SAAS;EAE3B,IAAIzD,MAAM0D,YAAY,CAAC1D,MAAM2D,WAAW,CAAC3D,MAAM4D,SAAS;EACxD,IAAI,CAACrB,IAAIsB,WAAW7D,KAAK,GAAG;EAC5B,KAAU;CACZ;CAEA,MAAM8D,iBAAwE9D,UAAU;EACtFF,mBAAmBmC,MAAMoB,WAAWrD,KAAK;EACzC,IACEA,MAAMwD,oBACNxD,MAAMyD,QAAQ,YACd,CAACpB,MAAM,KACPrC,MAAMgE,eACNhE,MAAMiE,YAAY,KAElB;EAEF3B,SAAS,IAAI;EACbtC,MAAMkE,eAAe;EACrBlE,MAAMmE,gBAAgB;CACxB;CAEA,cAAA;EAAA,IAAAC,OAAAC,QAAA,GAAAC,QAAAF,KAAAG,YAAAC,QAAAF,MAAAC,YAAAE,QAAAD,MAAAD,YAAAG,SAAAJ,MAAAK;EAAAP,KAAAQ,YAQed;EAAaM,KAAAS,iBAAA,WAJb7E,UAAU;GACnBA,MAAMkE,eAAe;GACrB,KAAU;EACZ,CAAC;EAAAY,OAAAV,MAAAW,WAAA,EAAA,KAAA,WAAA;GAAA,OAJMxF,GAAG,uBAAuB0C,MAAM+C,KAAK;EAAC,EAAA,GAMzC9C,IAAI,GAAA,OAAA,IAAA;EAAA+C,OAAAb,MAAAc,gBAEP/F,MAAI;GAAA,IAACgG,OAAI;IAAA,OAAElD,MAAMd;GAAI;GAAA,IAAAiE,WAAA;IAAA,IAAAC,QAAAC,OAAA;IAAAL,OAAAI,aACdpD,MAAMd,IAAI;IAAA,OAAAkE;GAAA;EAAA,CAAA,GAAAf,KAAA;EAAAW,OAAAb,MAAAc,gBAGjB/F,MAAI;GAAA,IAACgG,OAAI;IAAA,OAAElD,MAAMb;GAAO;GAAAgE,WACrBG,iBAAK;IAAA,IAAAC,SAAAC,QAAA,GAAAC,SAAAF,OAAAjB;IAAAmB,OAAAnB;IAAAU,OAAAS,cAEgDH,MAAM,CAAC,CAAClE,OAAK,IAAA;IAAA4D,OAAAO,QAAAN,gBAC/D1F,cAAY;KACXoG,MAAI;KACJC,SAAO;KACPC,MAAI;KAAA,cAAA;KAEJC,SAAO;KACPC,eAAeT,MAAM,CAAC,CAACjE,UAAU;KAAC,IAAA8D,WAAA;MAAA,OAAAF,gBAEjCnG,GAAC,CAAA,CAAA;KAAA;IAAA,CAAA,GAAA,IAAA;IAAA,OAAAyG;GAAA,EAAA,CAAA;EAGP,CAAA,GAAAlB,KAAA;EAAAW,OAAAX,OAAAY,gBAWAtF,UAAQ;GAAAqG,IAAAC,IAAA;IAAA,IAAAC,QACFlE,MAAMV;IAAQ,OAAA4E,UAAA,aAAAA,MAAAD,EAAA,IAAdjE,MAAMV,WAAQ2E;GAAA;GAAA,IACnBE,KAAE;IAAA,OAAEnE,MAAMR;GAAO;GAAA,IACjB4E,qBAAkB;IAAA,OAAE9D,IAAI8D;GAAkB;GAAA,IAC1CC,mBAAgB;IAAA,OAAE/D,IAAI+D;GAAgB;GAAA,IACtCC,UAAO;IAAA,OAAEhE,IAAIgE;GAAO;GAAA,IACpBC,SAAM;IAAA,OAAEjE,IAAIiE;GAAM;GAAA,IAClBhG,QAAK;IAAA,OAAEyB,MAAMzB;GAAK;GAClBiG,UAAUzG,UAAUiC,MAAMxB,cAAcT,MAAM0G,cAAclG,KAAK;GACtD6C;GAAS,IACpBzC,cAAW;IAAA,OAAEqB,MAAMrB,eAAe;GAAkB;GAAA,IACpDC,WAAQ;IAAA,OAAEoB,MAAMpB;GAAQ;GACxB8F,MAAM;GAAC,KAAA,gBAAA;IAAA,OAEL1E,MAAMP,eAAeO,MAAMnB,cAAc,GAAGmB,MAAMnB,YAAW,YAAa;GAAU;GAAA,KAAA,sBAAA;IAAA,OAEpE2B,YAAY;GAAC;GAC/BoD,SAAO;GAAA,IACPC,OAAI;IAAA,OAAE7D,MAAMJ,aAAa;GAAa;GAAA,IACtCiF,SAAM;IAAA,OAAE7E,MAAMH,eAAe;GAAU;EAAA,CAAA,GAAA0C,KAAA;EAAAS,OAAAX,OAAAY,gBAExC/F,MAAI;GAAA,IAACgG,OAAI;IAAA,OAAElD,MAAMN;GAAgB;GAAAyD,WAC9B2B,uBAAW;IAAA,IAAAC,SAAAC,QAAA;IAAAC,aAAAF,QAAA,MACDxE,aAAa;IAAAyC,OAAA+B,QACpBD,WAAW;IAAA,OAAAC;GAAA,EAAA,CAAA;EAEf,CAAA,GAAAxC,KAAA;EAAAS,OAAAT,OAAAU,gBAIA/F,MAAI;GAAA,IAACgG,OAAI;IAAA,OAAElD,MAAMjB;GAAO;GAAA,IAAAoE,WAAA;IAAA,OAAGnD,MAAMjB;GAAO;EAAA,CAAA,GAAAyD,KAAA;EAAAQ,OAAAR,OAAAS,gBAEtC/F,MAAI;GAAA,IAACgG,OAAI;IAAA,OAAElD,MAAMf;GAAQ;GAAA,IAAAkE,WAAA;IAAA,OAAGnD,MAAMf;GAAQ;EAAA,CAAA,GAAA,IAAA;EAAA+D,OAAAR,OAAAS,gBAC1C1F,cAAY;GACXoG,MAAI;GACJE,MAAI;GAAA,IACJjF,WAAQ;IAAA,OAAE,CAACoC,QAAQ;GAAC;GAAA,KAAA,gBAAA;IAAA,OACRkE,WAAA,CAAA,CAAAhF,QAAQ,CAAC,CAAA,CAAA,IAAGY,aAAa,IAAID,YAAY;GAAC;GAAA,IACtDiD,UAAO;IAAA,OAAEjD,YAAY;GAAC;GAAA,IAAAsC,WAAA;IAAA,OAAAF,gBAErB/F,MAAI;KAAA,IAACgG,OAAI;MAAA,OAAEhD,QAAQ;KAAC;KAAA,IAAEiF,WAAQ;MAAA,OAAAlC,gBAAGpG,MAAI,CAAA,CAAA;KAAA;KAAA,IAAAsG,WAAA;MAAA,OAAAF,gBACnCvF,SAAO;OAACmG,MAAI;OAAMzE,OAAO;OAAK,SAAA;MAAA,CAAA;KAAA;IAAA,CAAA;GAAA;EAAA,CAAA,GAAA,IAAA;EAAA4D,OAAAb,MAAAc,gBAOxC/F,MAAI;GAAA,IAACgG,OAAI;IAAA,OAAElD,MAAMlB;GAAQ;GAAA,IAAAqE,WAAA;IAAA,IAAAiC,QAAAC,QAAA,GAAAC,QAAAF,MAAA9C,YAAAkD,QAAAF,MAAA5C,YAAAA,aAAA+C,QAAAD,MAAA9C;IAAA+C,MAAA/C;IAAAM,OAAAoC,OAAAnC,gBAErBxF,KAAG,EAAA0F,UAAA,QAAA,CAAA,GAAAmC,KAAA;IAAAtC,OAAAoC,OAAAnC,gBAEHxF,KAAG,EAAA0F,UAAA,QAAA,CAAA,GAAAqC,KAAA;IAAAxC,OAAAoC,OAAAnC,gBAAcxF,KAAG,EAAA0F,UAAA,QAAA,CAAA,GAAAsC,KAAA;IAAA,OAAAL;GAAA;EAAA,CAAA,GAAA3C,MAAA;EAAAO,OAAAP,QAAAQ,gBAOtB/F,MAAI;GAAA,IACHgG,OAAI;IAAA,OAAEhD,QAAQ;GAAC;GAAA,IACfiF,WAAQ;IAAA,OAAAlC,gBACL/F,MAAI;KAAA,IAACgG,OAAI;MAAA,OAAE9C,MAAM;KAAC;KAAA+C,WACfwC,mBAAO;MAAA,IAAAC,SAAAC,QAAA;MAAA7C,OAAA4C,QAEJD,OAAO;MAAA,OAAAC;KAAA,EAAA,CAAA;IAEX,CAAA;GAAA;GAAA,IAAAzC,WAAA;IAAA,OAAA,CAAA+B,WAIJpE,aAAa,CAAC,GAAA,GAAA;GAAA;EAAA,CAAA,CAAA;EAAAgF,aAAAC,UAAA1D,OA9EV/E,GACL,kEACA,uDACA,iFACA0C,MAAMpB,YAAY,YACpB,CAAC,CAAA;EAAA,OAAAuD;CAAA,EAAA,CAAA;AA8ET;;;;;;;;;AAUA,SAAgB6D,yBACdjG,OACA;CACA,MAAM,CAACC,OAAOC,QAAQ5C,WAAW0C,OAAO;EAAC;EAAS;EAAQ;CAAU,CAAC;CAErE,OAAAkD,gBACG1F,cAAYuF,WAAA;EACXa,MAAI;EACJC,SAAO;EACPC,MAAI;EAAA,KAAA,gBAAA;GAAA,OACQqB,WAAA,CAAA,CAAAlF,MAAMiG,KAAK,CAAA,CAAA,IAAG,GAAGjG,MAAMiG,MAAK,gCAAiC;EAAmB;EAAA,KAAA,mBAAA;GAAA,OAC7EjG,MAAMkG;EAAI;EACzBpC,SAAO;EAAA,SAAA;CAAA,GAEH7D,MAAI,EAAA,IAAAkD,WAAA;EAAA,OAEPnD,MAAMmD,YAAQF,gBAAKrG,WAAS,CAAA,CAAA;CAAG,EAAA,CAAA,CAAA;AAGtC;;AAGA,SAAgBwJ,aAAarG,OAA4B;CACvD,MAAM,CAACC,OAAOC,QAAQ5C,WAAW0C,OAAO,CAAC,SAAS,UAAU,CAAC;CAC7D,cAAA;EAAA,IAAAsG,SAAAC,QAAA;EAAAzD,OAAAwD,QAAAvD,WAAA,EAAA,KAAA,WAAA;GAAA,OAEWxF,GAAG,4DAA4D0C,MAAM+C,KAAK;EAAC,EAAA,GAC9E9C,IAAI,GAAA,OAAA,IAAA;EAAA+C,OAAAqD,cAEPrG,MAAMmD,YAAQ;GAAAF,gBAEVtG,gBAAc;IAAA,eAAA;IAAA,SAAA;GAAA,CAAA;GAAAsG,gBACdxF,KAAG,EAAA0F,UAAA,QAAA,CAAA;GAAA;EAAA,CAEP;EAAA,OAAAkD;CAAA,EAAA,CAAA;AAGP;AAACE,eAAA,CAAA,SAAA,CAAA"}
@@ -1,3 +1,3 @@
1
- export { SidebarNav, SidebarNavButton, SidebarNavContent, SidebarNavFooter, SidebarNavHeader, SidebarNavItem, SidebarNavSection, SidebarNavTitle, sidebarNavItemClass, sidebarNavItemStateClass, type SidebarNavItemProps, type SidebarNavProps, type SidebarNavSectionProps, type SidebarNavSectionTriggerProps, type SidebarNavTitleProps, } from './sidebar-nav';
1
+ export { SidebarNav, SidebarNavButton, SidebarNavContent, SidebarNavFooter, SidebarNavHeader, SidebarNavItem, SidebarNavLabel, SidebarNavRow, SidebarNavSection, SidebarNavTitle, sidebarNavItemClass, sidebarNavItemStateClass, type SidebarNavItemProps, type SidebarNavProps, type SidebarNavRowProps, type SidebarNavSectionProps, type SidebarNavSectionTriggerProps, type SidebarNavTitleProps, } from './sidebar-nav';
2
2
  export { SidebarNavResizeHandle, type SidebarNavResizeHandleProps, } from './sidebar-nav-resize-handle';
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/layout/sidebar-nav/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,iBAAiB,EACjB,eAAe,EACf,mBAAmB,EACnB,wBAAwB,EACxB,KAAK,mBAAmB,EACxB,KAAK,eAAe,EACpB,KAAK,sBAAsB,EAC3B,KAAK,6BAA6B,EAClC,KAAK,oBAAoB,GAC1B,MAAM,eAAe,CAAA;AACtB,OAAO,EACL,sBAAsB,EACtB,KAAK,2BAA2B,GACjC,MAAM,6BAA6B,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/layout/sidebar-nav/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,mBAAmB,EACnB,wBAAwB,EACxB,KAAK,mBAAmB,EACxB,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAC3B,KAAK,6BAA6B,EAClC,KAAK,oBAAoB,GAC1B,MAAM,eAAe,CAAA;AACtB,OAAO,EACL,sBAAsB,EACtB,KAAK,2BAA2B,GACjC,MAAM,6BAA6B,CAAA"}
@@ -1,3 +1,3 @@
1
- import { SidebarNav, SidebarNavButton, SidebarNavContent, SidebarNavFooter, SidebarNavHeader, SidebarNavItem, SidebarNavSection, SidebarNavTitle, sidebarNavItemClass, sidebarNavItemStateClass } from "./sidebar-nav.js";
1
+ import { SidebarNav, SidebarNavButton, SidebarNavContent, SidebarNavFooter, SidebarNavHeader, SidebarNavItem, SidebarNavLabel, SidebarNavRow, SidebarNavSection, SidebarNavTitle, sidebarNavItemClass, sidebarNavItemStateClass } from "./sidebar-nav.js";
2
2
  import { SidebarNavResizeHandle } from "./sidebar-nav-resize-handle.js";
3
- export { SidebarNav, SidebarNavButton, SidebarNavContent, SidebarNavFooter, SidebarNavHeader, SidebarNavItem, SidebarNavResizeHandle, SidebarNavSection, SidebarNavTitle, sidebarNavItemClass, sidebarNavItemStateClass };
3
+ export { SidebarNav, SidebarNavButton, SidebarNavContent, SidebarNavFooter, SidebarNavHeader, SidebarNavItem, SidebarNavLabel, SidebarNavResizeHandle, SidebarNavRow, SidebarNavSection, SidebarNavTitle, sidebarNavItemClass, sidebarNavItemStateClass };
@@ -49,6 +49,8 @@ export type SidebarNavSectionProps = ComponentProps<'div'> & {
49
49
  /** Render a disclosure control instead of a plain heading. */
50
50
  collapsible?: boolean;
51
51
  defaultOpen?: boolean;
52
+ /** Mark the current project/group without changing its disclosure state. */
53
+ active?: boolean;
52
54
  /** Controlled disclosure state. When supplied, the host owns changes. */
53
55
  open?: boolean;
54
56
  /** Called for user-initiated disclosure changes. */
@@ -63,6 +65,19 @@ export type SidebarNavSectionProps = ComponentProps<'div'> & {
63
65
  headingAs?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
64
66
  };
65
67
  export declare function SidebarNavSection(props: SidebarNavSectionProps): JSX.Element;
68
+ export type SidebarNavRowProps = ComponentProps<'div'> & {
69
+ /** Adjacent controls, outside the navigation item's interactive element. */
70
+ actions?: JSX.Element;
71
+ };
72
+ /**
73
+ * A navigation item and its adjacent controls. Actions stay outside the item
74
+ * to avoid nested buttons; touch, keyboard focus, and expanded menus expose
75
+ * them without requiring a pointer hover. A narrow lane or enlarged text
76
+ * may move actions onto a second line rather than clipping the label or controls.
77
+ */
78
+ export declare function SidebarNavRow(props: SidebarNavRowProps): JSX.Element;
79
+ /** Row text may truncate visually; its complete content remains the accessible name. */
80
+ export declare function SidebarNavLabel(props: ComponentProps<'span'>): JSX.Element;
66
81
  export type SidebarNavItemProps<T extends ValidComponent = 'a'> = PolymorphicProps<T, {
67
82
  class?: string;
68
83
  active?: boolean;
@@ -71,7 +86,10 @@ export type SidebarNavItemProps<T extends ValidComponent = 'a'> = PolymorphicPro
71
86
  /** Trailing slot: a count, a status dot, a hover action. */
72
87
  trailing?: JSX.Element;
73
88
  }>;
74
- /** A sidebar row. Exported classes, so a caller's own element can match it. */
89
+ /**
90
+ * A sidebar row. Exported classes, so a caller's own element can match it.
91
+ * Coarse pointers get a 44px target without changing Kiro's desktop density.
92
+ */
75
93
  export declare const sidebarNavItemClass: string;
76
94
  export declare const sidebarNavItemStateClass: {
77
95
  active: string;
@@ -1 +1 @@
1
- {"version":3,"file":"sidebar-nav.d.ts","sourceRoot":"","sources":["../../../../src/components/layout/sidebar-nav/sidebar-nav.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sidebar-nav.d.ts","sourceRoot":"","sources":["../../../../src/components/layout/sidebar-nav/sidebar-nav.tsx"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { cn } from "../../../lib/utils.js";
2
- import { createComponent, insert, memo, mergeProps, spread, template } from "solid-js/web";
2
+ import { className, createComponent, effect, insert, memo, mergeProps, setAttribute, spread, template } from "solid-js/web";
3
3
  import { ChevronRight } from "lucide-solid";
4
4
  import { Show, createSignal, splitProps } from "solid-js";
5
5
  import { Polymorphic } from "@kobalte/core/polymorphic";
@@ -12,9 +12,12 @@ var _tmpl$5 = /*#__PURE__*/ template(`<span class="shrink-0 tabular-nums text-mu
12
12
  var _tmpl$6 = /*#__PURE__*/ template(`<button>`);
13
13
  var _tmpl$7 = /*#__PURE__*/ template(`<span class="shrink-0 opacity-0 transition-opacity ease-out group-hover/section-header:opacity-100 focus-within:opacity-100 [@media(hover:none)]:opacity-100">`);
14
14
  var _tmpl$8 = /*#__PURE__*/ template(`<div class="flex flex-col gap-0.5">`);
15
- var _tmpl$9 = /*#__PURE__*/ template(`<div data-slot=sidebar-nav-section><div class="group/section-header flex items-center gap-1 rounded-md px-2 py-1.5 hover:bg-sidebar-accent/60">`);
16
- var _tmpl$0 = /*#__PURE__*/ template(`<span class="ms-auto flex shrink-0 items-center gap-1">`);
17
- var _tmpl$1 = /*#__PURE__*/ template(`<button type=button>`);
15
+ var _tmpl$9 = /*#__PURE__*/ template(`<div data-slot=sidebar-nav-section><div data-slot=sidebar-nav-section-header>`);
16
+ var _tmpl$0 = /*#__PURE__*/ template(`<span data-slot=sidebar-nav-row-actions class="ms-auto flex shrink-0 items-center gap-0.5 opacity-0 transition-opacity ease-out group-hover/sidebar-nav-row:opacity-100 group-focus-within/sidebar-nav-row:opacity-100 has-[[aria-haspopup=menu][aria-expanded=true]]:opacity-100 has-[[aria-haspopup=true][aria-expanded=true]]:opacity-100 [@media(hover:none)]:opacity-100">`);
17
+ var _tmpl$1 = /*#__PURE__*/ template(`<div data-slot=sidebar-nav-row>`);
18
+ var _tmpl$10 = /*#__PURE__*/ template(`<span data-slot=sidebar-nav-label>`);
19
+ var _tmpl$11 = /*#__PURE__*/ template(`<span class="ms-auto flex shrink-0 items-center gap-1">`);
20
+ var _tmpl$12 = /*#__PURE__*/ template(`<button type=button>`);
18
21
  function invokeEventHandler(handler, event) {
19
22
  if (Array.isArray(handler)) {
20
23
  const [callback, data] = handler;
@@ -33,7 +36,7 @@ function SidebarNav(props) {
33
36
  return local["aria-label"] ?? "Section";
34
37
  },
35
38
  get ["class"]() {
36
- return cn("bg-sidebar text-sidebar-foreground flex h-full w-sidebar shrink-0 flex-col border-e border-sidebar-border", local.class);
39
+ return cn("bg-sidebar text-sidebar-foreground flex h-full w-sidebar min-w-0 max-w-full shrink-0 flex-col border-e border-sidebar-border", local.class);
37
40
  }
38
41
  }, rest, { get children() {
39
42
  return local.children;
@@ -86,6 +89,7 @@ function SidebarNavSection(props) {
86
89
  "label",
87
90
  "collapsible",
88
91
  "defaultOpen",
92
+ "active",
89
93
  "open",
90
94
  "onOpenChange",
91
95
  "triggerProps",
@@ -147,7 +151,9 @@ function SidebarNavSection(props) {
147
151
  get ["aria-label"]() {
148
152
  return memo(() => !!local.headingAs)() ? local.label : void 0;
149
153
  },
150
- "class": "flex min-w-0 flex-1 items-center gap-1.5 text-2xs font-medium tracking-wide text-sidebar-muted-foreground uppercase",
154
+ get ["class"]() {
155
+ return cn("flex min-w-0 flex-1 items-center gap-1.5 text-2xs font-medium tracking-wide uppercase", local.active ? "text-foreground" : "text-sidebar-muted-foreground");
156
+ },
151
157
  get children() {
152
158
  return createComponent(Show, {
153
159
  get when() {
@@ -161,6 +167,9 @@ function SidebarNavSection(props) {
161
167
  get ["aria-expanded"]() {
162
168
  return open();
163
169
  },
170
+ get ["aria-current"]() {
171
+ return memo(() => !!local.active)() ? "page" : triggerRest["aria-current"];
172
+ },
164
173
  "onClick": (event) => {
165
174
  invokeEventHandler(trigger.onClick, event);
166
175
  if (event.defaultPrevented) return;
@@ -174,7 +183,9 @@ function SidebarNavSection(props) {
174
183
  event.stopPropagation();
175
184
  trigger.onReorder?.(event.key === "ArrowUp" ? "up" : "down");
176
185
  },
177
- "class": "flex min-w-0 flex-1 items-center gap-1.5 rounded-sm text-2xs font-medium tracking-wide text-sidebar-muted-foreground uppercase outline-none transition-colors ease-out hover:text-sidebar-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle"
186
+ get ["class"]() {
187
+ return cn("flex min-w-0 flex-1 items-center gap-1.5 rounded-sm text-2xs font-medium tracking-wide uppercase outline-none transition-colors ease-out hover:text-sidebar-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle [@media(pointer:coarse)]:min-h-11", local.active ? "text-foreground" : "text-sidebar-muted-foreground");
188
+ }
178
189
  }), false, true);
179
190
  insert(_el$8, heading);
180
191
  return _el$8;
@@ -202,13 +213,67 @@ function SidebarNavSection(props) {
202
213
  return _el$0;
203
214
  }
204
215
  }), null);
216
+ effect((_p$) => {
217
+ var _v$ = local.active ? "" : void 0, _v$2 = cn("group/section-header flex items-center gap-1 rounded-md px-2 py-1.5", { "[@media(pointer:coarse)]:py-0": local.collapsible }, local.active ? "bg-primary-subtle text-foreground" : "hover:bg-sidebar-accent/60");
218
+ _v$ !== _p$.e && setAttribute(_el$7, "data-active", _p$.e = _v$);
219
+ _v$2 !== _p$.t && className(_el$7, _p$.t = _v$2);
220
+ return _p$;
221
+ }, {
222
+ e: void 0,
223
+ t: void 0
224
+ });
205
225
  return _el$6;
206
226
  })();
207
227
  }
208
- /** A sidebar row. Exported classes, so a caller's own element can match it. */
228
+ /**
229
+ * A navigation item and its adjacent controls. Actions stay outside the item
230
+ * to avoid nested buttons; touch, keyboard focus, and expanded menus expose
231
+ * them without requiring a pointer hover. A narrow lane or enlarged text
232
+ * may move actions onto a second line rather than clipping the label or controls.
233
+ */
234
+ function SidebarNavRow(props) {
235
+ const [local, rest] = splitProps(props, [
236
+ "class",
237
+ "children",
238
+ "actions"
239
+ ]);
240
+ return (() => {
241
+ var _el$1 = _tmpl$1();
242
+ spread(_el$1, mergeProps({ get ["class"]() {
243
+ return cn("group/sidebar-nav-row flex min-w-0 flex-wrap items-center gap-0.5 [&>[data-slot=sidebar-nav-item]]:flex-1 [&>[data-slot=sidebar-nav-item]]:basis-36", local.class);
244
+ } }, rest), false, true);
245
+ insert(_el$1, () => local.children, null);
246
+ insert(_el$1, createComponent(Show, {
247
+ get when() {
248
+ return local.actions;
249
+ },
250
+ get children() {
251
+ var _el$10 = _tmpl$0();
252
+ insert(_el$10, () => local.actions);
253
+ return _el$10;
254
+ }
255
+ }), null);
256
+ return _el$1;
257
+ })();
258
+ }
259
+ /** Row text may truncate visually; its complete content remains the accessible name. */
260
+ function SidebarNavLabel(props) {
261
+ const [local, rest] = splitProps(props, ["class"]);
262
+ return (() => {
263
+ var _el$11 = _tmpl$10();
264
+ spread(_el$11, mergeProps({ get ["class"]() {
265
+ return cn("min-w-0 flex-1 truncate", local.class);
266
+ } }, rest), false, false);
267
+ return _el$11;
268
+ })();
269
+ }
270
+ /**
271
+ * A sidebar row. Exported classes, so a caller's own element can match it.
272
+ * Coarse pointers get a 44px target without changing Kiro's desktop density.
273
+ */
209
274
  var sidebarNavItemClass = [
210
275
  "group/nav-item relative flex min-w-0 items-center gap-2.5 rounded-md px-3 py-2 text-sm font-medium",
211
- "whitespace-nowrap transition-colors ease-out outline-none select-none",
276
+ "whitespace-nowrap transition-colors ease-out outline-none select-none [@media(pointer:coarse)]:min-h-11",
212
277
  "focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle",
213
278
  "[&_svg]:size-4 [&_svg]:shrink-0"
214
279
  ].join(" ");
@@ -226,6 +291,7 @@ function SidebarNavItem(props) {
226
291
  ]);
227
292
  return createComponent(Polymorphic, mergeProps({
228
293
  as: "a",
294
+ "data-slot": "sidebar-nav-item",
229
295
  get ["aria-current"]() {
230
296
  return local.active ? "page" : void 0;
231
297
  },
@@ -241,9 +307,9 @@ function SidebarNavItem(props) {
241
307
  return local.trailing;
242
308
  },
243
309
  get children() {
244
- var _el$1 = _tmpl$0();
245
- insert(_el$1, () => local.trailing);
246
- return _el$1;
310
+ var _el$12 = _tmpl$11();
311
+ insert(_el$12, () => local.trailing);
312
+ return _el$12;
247
313
  }
248
314
  })];
249
315
  } }));
@@ -252,15 +318,15 @@ function SidebarNavItem(props) {
252
318
  function SidebarNavButton(props) {
253
319
  const [local, rest] = splitProps(props, ["class", "children"]);
254
320
  return (() => {
255
- var _el$10 = _tmpl$1();
256
- spread(_el$10, mergeProps({ get ["class"]() {
321
+ var _el$13 = _tmpl$12();
322
+ spread(_el$13, mergeProps({ get ["class"]() {
257
323
  return cn(sidebarNavItemClass, sidebarNavItemStateClass.idle, "w-full disabled:pointer-events-none disabled:opacity-50", local.class);
258
324
  } }, rest), false, true);
259
- insert(_el$10, () => local.children);
260
- return _el$10;
325
+ insert(_el$13, () => local.children);
326
+ return _el$13;
261
327
  })();
262
328
  }
263
329
  //#endregion
264
- export { SidebarNav, SidebarNavButton, SidebarNavContent, SidebarNavFooter, SidebarNavHeader, SidebarNavItem, SidebarNavSection, SidebarNavTitle, sidebarNavItemClass, sidebarNavItemStateClass };
330
+ export { SidebarNav, SidebarNavButton, SidebarNavContent, SidebarNavFooter, SidebarNavHeader, SidebarNavItem, SidebarNavLabel, SidebarNavRow, SidebarNavSection, SidebarNavTitle, sidebarNavItemClass, sidebarNavItemStateClass };
265
331
 
266
332
  //# sourceMappingURL=sidebar-nav.js.map