@k2b/ui 0.47.0 → 0.49.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 (95) hide show
  1. package/dist/browser/actions/CopyButton.js +26 -18
  2. package/dist/browser/actions/CopyButton.js.map +1 -1
  3. package/dist/browser/chat/ChatComposer.js +244 -193
  4. package/dist/browser/chat/ChatComposer.js.map +1 -1
  5. package/dist/browser/chat/chat-messages.js +6 -0
  6. package/dist/browser/chat/chat-messages.js.map +1 -1
  7. package/dist/browser/chat/types.js.map +1 -1
  8. package/dist/browser/content/Calendar.js +40 -5
  9. package/dist/browser/content/Calendar.js.map +1 -1
  10. package/dist/browser/content/calendar-event-detail.js +328 -0
  11. package/dist/browser/content/calendar-event-detail.js.map +1 -0
  12. package/dist/browser/content/calendar-messages.js +34 -2
  13. package/dist/browser/content/calendar-messages.js.map +1 -1
  14. package/dist/browser/content/calendar-shared.js +189 -82
  15. package/dist/browser/content/calendar-shared.js.map +1 -1
  16. package/dist/browser/content/calendar-time-view.js +101 -96
  17. package/dist/browser/content/calendar-time-view.js.map +1 -1
  18. package/dist/browser/content/index.js.map +1 -1
  19. package/dist/browser/feedback/prompt-confirm.js +7 -4
  20. package/dist/browser/feedback/prompt-confirm.js.map +1 -1
  21. package/dist/browser/feedback/prompts.js +3 -3
  22. package/dist/browser/feedback/prompts.js.map +1 -1
  23. package/dist/browser/inputs/NumberInput.js +17 -5
  24. package/dist/browser/inputs/NumberInput.js.map +1 -1
  25. package/dist/browser/inputs/dictation/Dictation.js +114 -108
  26. package/dist/browser/inputs/dictation/Dictation.js.map +1 -1
  27. package/dist/browser/inputs/dictation/dictation-messages.js +2 -0
  28. package/dist/browser/inputs/dictation/dictation-messages.js.map +1 -1
  29. package/dist/browser/layout/AppWorkspace.js +574 -522
  30. package/dist/browser/layout/AppWorkspace.js.map +1 -1
  31. package/dist/browser/layout/MobileShell.js +26 -0
  32. package/dist/browser/layout/MobileShell.js.map +1 -1
  33. package/dist/browser/layout/index.js +1 -0
  34. package/dist/browser/layout/index.js.map +1 -1
  35. package/dist/browser/layout/sheet-handle.js +155 -0
  36. package/dist/browser/layout/sheet-handle.js.map +1 -0
  37. package/dist/browser/surfaces/NoticeCard.js +48 -29
  38. package/dist/browser/surfaces/NoticeCard.js.map +1 -1
  39. package/dist/ssr/actions/CopyButton.js +13 -8
  40. package/dist/ssr/actions/CopyButton.js.map +1 -1
  41. package/dist/ssr/chat/ChatComposer.js +53 -30
  42. package/dist/ssr/chat/ChatComposer.js.map +1 -1
  43. package/dist/ssr/chat/chat-messages.js +6 -0
  44. package/dist/ssr/chat/chat-messages.js.map +1 -1
  45. package/dist/ssr/chat/types.js.map +1 -1
  46. package/dist/ssr/content/Calendar.js +36 -4
  47. package/dist/ssr/content/Calendar.js.map +1 -1
  48. package/dist/ssr/content/calendar-event-detail.js +212 -0
  49. package/dist/ssr/content/calendar-event-detail.js.map +1 -0
  50. package/dist/ssr/content/calendar-messages.js +34 -2
  51. package/dist/ssr/content/calendar-messages.js.map +1 -1
  52. package/dist/ssr/content/calendar-shared.js +117 -36
  53. package/dist/ssr/content/calendar-shared.js.map +1 -1
  54. package/dist/ssr/content/calendar-time-view.js +6 -4
  55. package/dist/ssr/content/calendar-time-view.js.map +1 -1
  56. package/dist/ssr/content/index.js.map +1 -1
  57. package/dist/ssr/feedback/prompt-confirm.js +7 -4
  58. package/dist/ssr/feedback/prompt-confirm.js.map +1 -1
  59. package/dist/ssr/feedback/prompts.js +3 -3
  60. package/dist/ssr/feedback/prompts.js.map +1 -1
  61. package/dist/ssr/inputs/NumberInput.js +17 -5
  62. package/dist/ssr/inputs/NumberInput.js.map +1 -1
  63. package/dist/ssr/inputs/dictation/Dictation.js +3 -1
  64. package/dist/ssr/inputs/dictation/Dictation.js.map +1 -1
  65. package/dist/ssr/inputs/dictation/dictation-messages.js +2 -0
  66. package/dist/ssr/inputs/dictation/dictation-messages.js.map +1 -1
  67. package/dist/ssr/layout/AppWorkspace.js +152 -114
  68. package/dist/ssr/layout/AppWorkspace.js.map +1 -1
  69. package/dist/ssr/layout/MobileShell.js +26 -0
  70. package/dist/ssr/layout/MobileShell.js.map +1 -1
  71. package/dist/ssr/layout/index.js +1 -0
  72. package/dist/ssr/layout/index.js.map +1 -1
  73. package/dist/ssr/layout/sheet-handle.js +155 -0
  74. package/dist/ssr/layout/sheet-handle.js.map +1 -0
  75. package/dist/ssr/surfaces/NoticeCard.js +25 -10
  76. package/dist/ssr/surfaces/NoticeCard.js.map +1 -1
  77. package/dist/styles.css +1 -1
  78. package/dist/types/chat/chat-messages.d.ts +3 -0
  79. package/dist/types/chat/types.d.ts +5 -0
  80. package/dist/types/content/Calendar.d.ts +29 -5
  81. package/dist/types/content/calendar-event-detail.d.ts +21 -0
  82. package/dist/types/content/calendar-messages.d.ts +16 -0
  83. package/dist/types/content/calendar-shared.d.ts +16 -1
  84. package/dist/types/content/calendar-time-view.d.ts +1 -1
  85. package/dist/types/content/index.d.ts +1 -1
  86. package/dist/types/feedback/prompt-confirm.d.ts +3 -1
  87. package/dist/types/feedback/prompts.d.ts +2 -2
  88. package/dist/types/inputs/NumberInput.d.ts +1 -1
  89. package/dist/types/inputs/dictation/dictation-messages.d.ts +1 -0
  90. package/dist/types/layout/AppWorkspace.d.ts +16 -1
  91. package/dist/types/layout/MobileShell.d.ts +5 -0
  92. package/dist/types/layout/index.d.ts +2 -1
  93. package/dist/types/layout/sheet-handle.d.ts +21 -0
  94. package/dist/types/surfaces/NoticeCard.d.ts +5 -2
  95. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["surfaces/NoticeCard.tsx"],"sourcesContent":["import { children, For, type JSX, Show, splitProps } from \"solid-js\";\nimport type { IntentTone } from \"../semantics\";\n\nexport type NoticeTone = Extract<IntentTone, \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\">;\n\ntype NoticeCardContentProps =\n | { title: JSX.Element; detail?: JSX.Element; meta?: JSX.Element; children?: JSX.Element }\n | { title?: never; detail?: never; meta?: never; children: JSX.Element };\n\nexport type NoticeCardProps = Omit<JSX.HTMLAttributes<HTMLElement>, \"children\" | \"class\" | \"title\"> &\n NoticeCardContentProps & {\n tone?: NoticeTone;\n /** A Tabler icon class. Turns the notice into a compact status line whose icon and text take the tone colour. */\n icon?: string;\n class?: string;\n bodyClass?: string;\n };\n\nexport const NOTICE_CARD_CLASSES = {\n root: \"k2b-notice-card\",\n icon: \"k2b-notice-card__icon\",\n content: \"k2b-notice-card__content\",\n head: \"k2b-notice-card__head\",\n title: \"k2b-notice-card__title\",\n meta: \"k2b-notice-card__meta\",\n description: \"k2b-notice-card__description\",\n body: \"k2b-notice-card__body\",\n} as const;\n\nfunction NoticeCardComponent(props: NoticeCardProps): JSX.Element {\n const [local, articleProps] = splitProps(props, [\"tone\", \"icon\", \"title\", \"detail\", \"meta\", \"children\", \"class\", \"bodyClass\"]);\n // Children that render nothing, such as a Show whose condition is false, add no body and no gap.\n const body = children(() => local.children);\n const hasBody = () => body.toArray().some((node) => node != null && node !== false && node !== \"\");\n return (\n <article\n {...articleProps}\n class={`${NOTICE_CARD_CLASSES.root} ${local.class ?? \"\"}`}\n data-tone={local.tone ?? \"neutral\"}\n {...(local.icon ? { \"data-icon\": \"\" } : {})}\n >\n <Show when={local.icon}>{(icon) => <i class={`${icon()} ${NOTICE_CARD_CLASSES.icon}`} aria-hidden=\"true\" />}</Show>\n <div class={NOTICE_CARD_CLASSES.content}>\n <Show when={local.title}>\n {(title) => (\n <div class={NOTICE_CARD_CLASSES.head}>\n <p class={NOTICE_CARD_CLASSES.title}>{title()}</p>\n <Show when={local.meta}>{(meta) => <span class={NOTICE_CARD_CLASSES.meta}>{meta()}</span>}</Show>\n </div>\n )}\n </Show>\n <Show when={local.detail}>{(detail) => <p class={NOTICE_CARD_CLASSES.description}>{detail()}</p>}</Show>\n <Show when={hasBody()}>\n <div class={`${NOTICE_CARD_CLASSES.body} ${local.bodyClass ?? \"\"}`}>{body()}</div>\n </Show>\n </div>\n </article>\n );\n}\n\nexport type NoticeGridProps<T> = {\n items: readonly T[];\n children: (item: T) => JSX.Element;\n class?: string;\n};\n\nfunction NoticeGrid<T>(props: NoticeGridProps<T>): JSX.Element {\n const columns = () => (props.items.length <= 1 ? \"one\" : props.items.length === 2 ? \"two\" : \"three\");\n return (\n <Show when={props.items.length > 0}>\n <div class={`k2b-notice-grid ${props.class ?? \"\"}`} data-columns={columns()}>\n <For each={props.items}>{(item) => props.children(item)}</For>\n </div>\n </Show>\n );\n}\n\nexport const NoticeCard = Object.assign(NoticeCardComponent, { Grid: NoticeGrid });\nexport default NoticeCard;\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["surfaces/NoticeCard.tsx"],"sourcesContent":["import { children, For, type JSX, Show, splitProps } from \"solid-js\";\nimport { dialogToneIcon, dialogToneLabel } from \"../feedback/dialog-tone\";\nimport { useUiMessages } from \"../intl/messages\";\nimport type { IntentTone } from \"../semantics\";\n\nexport type NoticeTone = Extract<IntentTone, \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\">;\n\ntype NoticeCardContentProps =\n | { title: JSX.Element; detail?: JSX.Element; meta?: JSX.Element; children?: JSX.Element }\n | { title?: never; detail?: never; meta?: never; children: JSX.Element };\n\nexport type NoticeCardProps = Omit<JSX.HTMLAttributes<HTMLElement>, \"children\" | \"class\" | \"title\"> &\n NoticeCardContentProps & {\n tone?: NoticeTone;\n /**\n * A Tabler icon class. Turns the notice into a compact status line whose icon and text take the tone colour. `true`\n * takes the tone's own icon, the one a toned dialog shows, and names the tone for screen readers.\n */\n icon?: string | true;\n class?: string;\n bodyClass?: string;\n };\n\nexport const NOTICE_CARD_CLASSES = {\n root: \"k2b-notice-card\",\n icon: \"k2b-notice-card__icon\",\n content: \"k2b-notice-card__content\",\n head: \"k2b-notice-card__head\",\n title: \"k2b-notice-card__title\",\n meta: \"k2b-notice-card__meta\",\n description: \"k2b-notice-card__description\",\n body: \"k2b-notice-card__body\",\n} as const;\n\nfunction NoticeCardComponent(props: NoticeCardProps): JSX.Element {\n const [local, articleProps] = splitProps(props, [\"tone\", \"icon\", \"title\", \"detail\", \"meta\", \"children\", \"class\", \"bodyClass\"]);\n // Children that render nothing, such as a Show whose condition is false, add no body and no gap.\n const body = children(() => local.children);\n const hasBody = () => body.toArray().some((node) => node != null && node !== false && node !== \"\");\n const messages = useUiMessages();\n /** The tone a dialog also knows, so `icon` true shows the same icon and word; info and neutral have no word. */\n const dialogTone = () => (local.tone === \"success\" || local.tone === \"warning\" || local.tone === \"danger\" ? local.tone : undefined);\n const icon = () => {\n if (local.icon !== true) return local.icon;\n const tone = dialogTone();\n return tone ? dialogToneIcon(tone) : \"ti ti-info-circle\";\n };\n const toneWord = () => {\n const tone = local.icon === true ? dialogTone() : undefined;\n return tone ? `${dialogToneLabel(messages(), tone)}: ` : undefined;\n };\n return (\n <article\n {...articleProps}\n class={`${NOTICE_CARD_CLASSES.root} ${local.class ?? \"\"}`}\n data-tone={local.tone ?? \"neutral\"}\n {...(local.icon ? { \"data-icon\": \"\" } : {})}\n >\n <Show when={icon()}>\n {(icon) => (\n <>\n <i class={`${icon()} ${NOTICE_CARD_CLASSES.icon}`} aria-hidden=\"true\" />\n {/* Inside the icon's branch, so a notice without one keeps its markup. */}\n {toneWord() ? <span class=\"k2b-sr-only\">{toneWord()}</span> : null}\n </>\n )}\n </Show>\n <div class={NOTICE_CARD_CLASSES.content}>\n <Show when={local.title}>\n {(title) => (\n <div class={NOTICE_CARD_CLASSES.head}>\n <p class={NOTICE_CARD_CLASSES.title}>{title()}</p>\n <Show when={local.meta}>{(meta) => <span class={NOTICE_CARD_CLASSES.meta}>{meta()}</span>}</Show>\n </div>\n )}\n </Show>\n <Show when={local.detail}>{(detail) => <p class={NOTICE_CARD_CLASSES.description}>{detail()}</p>}</Show>\n <Show when={hasBody()}>\n <div class={`${NOTICE_CARD_CLASSES.body} ${local.bodyClass ?? \"\"}`}>{body()}</div>\n </Show>\n </div>\n </article>\n );\n}\n\nexport type NoticeGridProps<T> = {\n items: readonly T[];\n children: (item: T) => JSX.Element;\n class?: string;\n};\n\nfunction NoticeGrid<T>(props: NoticeGridProps<T>): JSX.Element {\n const columns = () => (props.items.length <= 1 ? \"one\" : props.items.length === 2 ? \"two\" : \"three\");\n return (\n <Show when={props.items.length > 0}>\n <div class={`k2b-notice-grid ${props.class ?? \"\"}`} data-columns={columns()}>\n <For each={props.items}>{(item) => props.children(item)}</For>\n </div>\n </Show>\n );\n}\n\nexport const NoticeCard = Object.assign(NoticeCardComponent, { Grid: NoticeGrid });\nexport default NoticeCard;\n"],"mappings":"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","ignoreList":[]}
@@ -1,12 +1,12 @@
1
1
  import { createComponent as _$createComponent } from "solid-js/web";
2
2
  import { mergeProps as _$mergeProps } from "solid-js/web";
3
- import { ssr as _$ssr } from "solid-js/web";
4
3
  import { ssrAttribute as _$ssrAttribute } from "solid-js/web";
5
- import { escape as _$escape } from "solid-js/web";
6
4
  import { memo as _$memo } from "solid-js/web";
7
- var _tmpl$ = ["<i", " aria-hidden=\"true\"></i>"],
8
- _tmpl$2 = ["<span>", "</span>"],
9
- _tmpl$3 = ["<span class=\"k2b-sr-only\" aria-live=\"polite\">", "</span>"];
5
+ import { ssr as _$ssr } from "solid-js/web";
6
+ import { escape as _$escape } from "solid-js/web";
7
+ var _tmpl$ = ["<span class=\"k2b-sr-only\" aria-live=\"polite\">", "</span>"],
8
+ _tmpl$2 = ["<i", " aria-hidden=\"true\"></i>"],
9
+ _tmpl$3 = ["<span class=\"k2b-copy-button__label\"", "><span>", "</span></span>"];
10
10
  import { copyToClipboard } from "@k2b/stdlib/browser";
11
11
  import { createSignal, onCleanup, splitProps } from "solid-js";
12
12
  import { useUiMessages } from "../intl/messages";
@@ -42,9 +42,14 @@ export function CopyButton(props) {
42
42
  if (resetTimer) clearTimeout(resetTimer);
43
43
  resetTimer = setTimeout(() => setCopied(false), local.resetAfter ?? 2000);
44
44
  };
45
- const visibleLabel = () => copied() ? local.copiedLabel ?? messages().copied : local.label ?? messages().copy;
45
+ const copyLabel = () => local.label ?? messages().copy;
46
+ const copiedLabel = () => local.copiedLabel ?? messages().copied;
47
+ const visibleLabel = () => copied() ? copiedLabel() : copyLabel();
46
48
  const icon = () => copied() ? "ti ti-check" : "ti ti-copy";
47
49
  const iconOnly = () => local.iconOnly ?? local.label === undefined;
50
+ // Copied often flashes into a row next to a field; the other label, drawn hidden by CSS, keeps the button's width.
51
+ const hiddenLabel = () => copied() ? copyLabel() : copiedLabel();
52
+ const announcement = () => _$ssr(_tmpl$, copied() ? _$escape(visibleLabel()) : "");
48
53
  const button = tooltip => _$createComponent(Button, _$mergeProps(rest, {
49
54
  tooltip: tooltip,
50
55
  get disabled() {
@@ -73,10 +78,10 @@ export function CopyButton(props) {
73
78
  },
74
79
  onClick: copy,
75
80
  get children() {
76
- return [_$ssr(_tmpl$, _$ssrAttribute("class", _$escape(icon(), true), false)), !iconOnly() && _$ssr(_tmpl$2, _$escape(visibleLabel()))];
81
+ return [_$ssr(_tmpl$2, _$ssrAttribute("class", _$escape(icon(), true), false)), !iconOnly() && _$ssr(_tmpl$3, _$ssrAttribute("data-reserve", _$escape(hiddenLabel(), true), false), _$escape(visibleLabel()))];
77
82
  }
78
83
  }));
79
- return iconOnly() ? [button(visibleLabel()), _$ssr(_tmpl$3, copied() ? _$escape(visibleLabel()) : "")] : button(undefined);
84
+ return [button(iconOnly() ? visibleLabel() : undefined), announcement()];
80
85
  }
81
86
  export default CopyButton;
82
87
  //# sourceMappingURL=CopyButton.js.map
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["actions/CopyButton.tsx"],"sourcesContent":["import { copyToClipboard } from \"@k2b/stdlib/browser\";\nimport { createSignal, type JSX, onCleanup, splitProps } from \"solid-js\";\nimport { useUiMessages } from \"../intl/messages\";\nimport { Button, type ButtonProps } from \"./Button\";\n\nexport type CopyButtonValue = { text: string; value?: string } | { text?: string; value: string };\n\nexport type CopyButtonProps = CopyButtonValue &\n Omit<ButtonProps, \"children\" | \"onClick\"> & {\n label?: string;\n copiedLabel?: string;\n iconOnly?: boolean;\n onCopied?: () => void;\n onCopyError?: (error: unknown) => void;\n resetAfter?: number;\n };\n\nexport async function copyText(\n text: string,\n onCopyError?: (error: unknown) => void,\n copy: (text: string) => Promise<void> = copyToClipboard,\n): Promise<void> {\n try {\n await copy(text);\n } catch (error) {\n onCopyError?.(error);\n throw error;\n }\n}\n\nexport function CopyButton(props: CopyButtonProps): JSX.Element {\n const messages = useUiMessages();\n const [local, rest] = splitProps(props, [\n \"class\",\n \"copiedLabel\",\n \"disabled\",\n \"iconOnly\",\n \"label\",\n \"loading\",\n \"loadingLabel\",\n \"onCopied\",\n \"onCopyError\",\n \"resetAfter\",\n \"size\",\n \"text\",\n \"type\",\n \"value\",\n \"variant\",\n ]);\n const [copied, setCopied] = createSignal(false);\n let resetTimer: ReturnType<typeof setTimeout> | undefined;\n\n onCleanup(() => {\n if (resetTimer) clearTimeout(resetTimer);\n });\n\n const copy = async () => {\n // `copyText` reports through `onCopyError` and then rethrows so direct\n // callers can await it. The click handler is not awaited by anyone, so it\n // has to absorb the rejection here — otherwise a denied clipboard\n // permission surfaces as an unhandled rejection despite `onCopyError`.\n try {\n await copyText(local.text ?? local.value ?? \"\", local.onCopyError);\n } catch {\n return;\n }\n setCopied(true);\n local.onCopied?.();\n if (resetTimer) clearTimeout(resetTimer);\n resetTimer = setTimeout(() => setCopied(false), local.resetAfter ?? 2000);\n };\n\n const visibleLabel = () => (copied() ? (local.copiedLabel ?? messages().copied) : (local.label ?? messages().copy));\n const icon = () => (copied() ? \"ti ti-check\" : \"ti ti-copy\");\n const iconOnly = () => local.iconOnly ?? local.label === undefined;\n const button = (tooltip?: string) => (\n <Button\n {...rest}\n tooltip={tooltip}\n disabled={local.disabled}\n loading={local.loading}\n loadingLabel={local.loadingLabel}\n type={local.type ?? \"button\"}\n class={`k2b-copy-button ${local.class ?? \"\"}`}\n size={local.size ?? \"sm\"}\n variant={local.variant ?? \"ghost\"}\n aria-label={iconOnly() ? visibleLabel() : undefined}\n onClick={copy}\n >\n <i class={icon()} aria-hidden=\"true\" />\n {!iconOnly() && <span>{visibleLabel()}</span>}\n </Button>\n );\n\n return iconOnly() ? (\n <>\n {button(visibleLabel())}\n <span class=\"k2b-sr-only\" aria-live=\"polite\">\n {copied() ? visibleLabel() : \"\"}\n </span>\n </>\n ) : (\n button(undefined)\n );\n}\n\nexport default CopyButton;\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["actions/CopyButton.tsx"],"sourcesContent":["import { copyToClipboard } from \"@k2b/stdlib/browser\";\nimport { createSignal, type JSX, onCleanup, splitProps } from \"solid-js\";\nimport { useUiMessages } from \"../intl/messages\";\nimport { Button, type ButtonProps } from \"./Button\";\n\nexport type CopyButtonValue = { text: string; value?: string } | { text?: string; value: string };\n\nexport type CopyButtonProps = CopyButtonValue &\n Omit<ButtonProps, \"children\" | \"onClick\"> & {\n label?: string;\n copiedLabel?: string;\n iconOnly?: boolean;\n onCopied?: () => void;\n onCopyError?: (error: unknown) => void;\n resetAfter?: number;\n };\n\nexport async function copyText(\n text: string,\n onCopyError?: (error: unknown) => void,\n copy: (text: string) => Promise<void> = copyToClipboard,\n): Promise<void> {\n try {\n await copy(text);\n } catch (error) {\n onCopyError?.(error);\n throw error;\n }\n}\n\nexport function CopyButton(props: CopyButtonProps): JSX.Element {\n const messages = useUiMessages();\n const [local, rest] = splitProps(props, [\n \"class\",\n \"copiedLabel\",\n \"disabled\",\n \"iconOnly\",\n \"label\",\n \"loading\",\n \"loadingLabel\",\n \"onCopied\",\n \"onCopyError\",\n \"resetAfter\",\n \"size\",\n \"text\",\n \"type\",\n \"value\",\n \"variant\",\n ]);\n const [copied, setCopied] = createSignal(false);\n let resetTimer: ReturnType<typeof setTimeout> | undefined;\n\n onCleanup(() => {\n if (resetTimer) clearTimeout(resetTimer);\n });\n\n const copy = async () => {\n // `copyText` reports through `onCopyError` and then rethrows so direct\n // callers can await it. The click handler is not awaited by anyone, so it\n // has to absorb the rejection here — otherwise a denied clipboard\n // permission surfaces as an unhandled rejection despite `onCopyError`.\n try {\n await copyText(local.text ?? local.value ?? \"\", local.onCopyError);\n } catch {\n return;\n }\n setCopied(true);\n local.onCopied?.();\n if (resetTimer) clearTimeout(resetTimer);\n resetTimer = setTimeout(() => setCopied(false), local.resetAfter ?? 2000);\n };\n\n const copyLabel = () => local.label ?? messages().copy;\n const copiedLabel = () => local.copiedLabel ?? messages().copied;\n const visibleLabel = () => (copied() ? copiedLabel() : copyLabel());\n const icon = () => (copied() ? \"ti ti-check\" : \"ti ti-copy\");\n const iconOnly = () => local.iconOnly ?? local.label === undefined;\n // Copied often flashes into a row next to a field; the other label, drawn hidden by CSS, keeps the button's width.\n const hiddenLabel = () => (copied() ? copyLabel() : copiedLabel());\n const announcement = () => (\n <span class=\"k2b-sr-only\" aria-live=\"polite\">\n {copied() ? visibleLabel() : \"\"}\n </span>\n );\n const button = (tooltip?: string) => (\n <Button\n {...rest}\n tooltip={tooltip}\n disabled={local.disabled}\n loading={local.loading}\n loadingLabel={local.loadingLabel}\n type={local.type ?? \"button\"}\n class={`k2b-copy-button ${local.class ?? \"\"}`}\n size={local.size ?? \"sm\"}\n variant={local.variant ?? \"ghost\"}\n aria-label={iconOnly() ? visibleLabel() : undefined}\n onClick={copy}\n >\n <i class={icon()} aria-hidden=\"true\" />\n {!iconOnly() && (\n <span class=\"k2b-copy-button__label\" data-reserve={hiddenLabel()}>\n <span>{visibleLabel()}</span>\n </span>\n )}\n </Button>\n );\n\n return (\n <>\n {button(iconOnly() ? visibleLabel() : undefined)}\n {announcement()}\n </>\n );\n}\n\nexport default CopyButton;\n"],"mappings":"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","ignoreList":[]}
@@ -51,18 +51,19 @@ var _tmpl$ = ["<span><strong", ">", "</strong></span>"],
51
51
  _tmpl$42 = ["<div class=\"k2b-chat-composer__reply\">", "<button type=\"button\" class=\"k2b-chat-composer__icon-action k2b-chat-composer__reply-cancel\"", "><i class=\"ti ti-x\" aria-hidden=\"true\"></i></button></div>"],
52
52
  _tmpl$43 = ["<div class=\"k2b-message-row__quote\">", "</div>"],
53
53
  _tmpl$44 = ["<button type=\"button\" class=\"k2b-message-row__quote\">", "</button>"],
54
- _tmpl$45 = ["<button type=\"button\" class=\"k2b-chat-composer__attachment-remove\"", "", "><i class=\"ti ti-x\" aria-hidden=\"true\"></i></button>"],
55
- _tmpl$46 = ["<div class=\"k2b-chat-composer__attachment\" role=\"listitem\"><div class=\"", "\">", "", "</div>", "</div>"],
56
- _tmpl$47 = ["<img", ">"],
57
- _tmpl$48 = ["<div class=\"k2b-chat-composer__attachment-identity\">", "", "</div>"],
58
- _tmpl$49 = ["<a class=\"k2b-chat-composer__attachment-link\"", " target=\"_blank\" rel=\"noopener noreferrer\"", ">", "", "</a>"],
59
- _tmpl$50 = ["<button type=\"button\" class=\"k2b-chat-composer__attachment-action\"", ">", "", "</button>"],
60
- _tmpl$51 = ["<footer class=\"k2b-chat-composer__footer\">", "</footer>"],
61
- _tmpl$52 = ["<div class=\"k2b-chat-composer__tools\">", "", "", "", "", "", "", "</div>"],
62
- _tmpl$53 = ["<div class=\"k2b-chat-composer__submit\">", "", "", "", "", "", "</div>"],
63
- _tmpl$54 = ["<span>", "</span>"],
64
- _tmpl$55 = ["<div class=\"k2b-chat-composer__status-line\"", "><i aria-hidden=\"true\"", "></i><span>", "</span></div>"],
65
- _tmpl$56 = ["<span class=\"k2b-sr-only\">", "</span>"];
54
+ _tmpl$45 = ["<span class=\"k2b-chat-composer__attachment-action k2b-chat-composer__attachment-progress\">", "", "</span>"],
55
+ _tmpl$46 = ["<button type=\"button\" class=\"k2b-chat-composer__attachment-remove\"", "", "><i class=\"ti ti-x\" aria-hidden=\"true\"></i></button>"],
56
+ _tmpl$47 = ["<div class=\"k2b-chat-composer__attachment\" role=\"listitem\"><div class=\"", "\">", "", "", "</div>", "</div>"],
57
+ _tmpl$48 = ["<img", ">"],
58
+ _tmpl$49 = ["<div class=\"k2b-chat-composer__attachment-identity\">", "", "</div>"],
59
+ _tmpl$50 = ["<a class=\"k2b-chat-composer__attachment-link\"", " target=\"_blank\" rel=\"noopener noreferrer\"", ">", "", "</a>"],
60
+ _tmpl$51 = ["<button type=\"button\" class=\"k2b-chat-composer__attachment-action\"", "", ">", "", "</button>"],
61
+ _tmpl$52 = ["<footer class=\"k2b-chat-composer__footer\">", "</footer>"],
62
+ _tmpl$53 = ["<div class=\"k2b-chat-composer__tools\">", "", "", "", "", "", "", "</div>"],
63
+ _tmpl$54 = ["<div class=\"k2b-chat-composer__submit\">", "", "", "", "", "", "</div>"],
64
+ _tmpl$55 = ["<span>", "</span>"],
65
+ _tmpl$56 = ["<div class=\"k2b-chat-composer__status-line\"", "><i aria-hidden=\"true\"", "></i><span>", "</span></div>"],
66
+ _tmpl$57 = ["<span class=\"k2b-sr-only\">", "</span>"];
66
67
  import { batch, children, createEffect, createMemo, createSignal, createUniqueId, For, Index, on, onCleanup, onMount, Show, untrack } from "solid-js";
67
68
  import { Dropdown } from "../actions/Dropdown";
68
69
  import { dialogHistorySettled, holdDialogHistory } from "../feedback/dialog-core";
@@ -80,6 +81,7 @@ import { SelectChip } from "../inputs/SelectChip";
80
81
  import { useSelectMessages } from "../inputs/select-messages";
81
82
  import { useLocale } from "../intl/locale";
82
83
  import { useUiMessages } from "../intl/messages";
84
+ import { ProgressRing } from "../surfaces/ProgressRing";
83
85
  import { ChatContextUsage as ContextUsage } from "./ChatPrimitives";
84
86
  import { chatCommandKey, conversationEnterAction, executeChatAction, nextChatCommandIndex, reportChatFailure, runChatSubmission } from "./chat-behavior";
85
87
  import { useChatMessages } from "./chat-messages";
@@ -240,7 +242,10 @@ export function ChatComposer(props) {
240
242
  const [microphoneMenuOpen, setMicrophoneMenuOpen] = createSignal(false);
241
243
  const dictation = () => props.microphone?.dictation ?? null;
242
244
  const showHint = () => conversation() || dictation() !== null || hasContent(hint.toArray());
243
- const state = () => props.state ?? "idle";
245
+
246
+ // Handlers such as sending read these outside any owner. A host's conditional prop is a getter that creates a
247
+ // computation on each read, which would never be disposed there; memos read it inside the composer's owner.
248
+ const state = createMemo(() => props.state ?? "idle");
244
249
  const running = () => state() === "running";
245
250
  const stopping = () => state() === "stopping";
246
251
  const runningSubmitIntent = () => props.runningSubmitIntent ?? "steer";
@@ -927,7 +932,7 @@ export function ChatComposer(props) {
927
932
  selectedCommandKey();
928
933
  setAnnouncement(undefined);
929
934
  });
930
- const busy = () => Boolean(props.disabled || stopping() || state() === "submitting" || executing() || addingFiles());
935
+ const busy = createMemo(() => Boolean(props.disabled || stopping() || state() === "submitting" || executing() || addingFiles()));
931
936
  const blocked = () => busy() || submitting();
932
937
  /** The conversation field stays editable while a message is sent, so it keeps the focus and a phone its keyboard. */
933
938
  const editBlocked = () => conversation() ? busy() : blocked();
@@ -941,7 +946,7 @@ export function ChatComposer(props) {
941
946
  }));
942
947
  const hasDraft = () => Boolean(props.value.trim() || !running() && attachments().length > 0);
943
948
  /** The draft may go out now, apart from a submission that is already on its way. */
944
- const submittable = () => !busy() && !props.submitDisabled && hasDraft() && !(props.dictation && liveDictation.active()) && !(running() && runningSubmitIntent() === "steer" && mentions().length);
949
+ const submittable = createMemo(() => !busy() && !props.submitDisabled && hasDraft() && !(props.dictation && liveDictation.active()) && !(running() && runningSubmitIntent() === "steer" && mentions().length));
945
950
  const canSubmit = () => !submitting() && submittable();
946
951
  const canSelectFiles = () => Boolean(props.fileSelection && !props.fileSelection.disabled && !running() && !blocked());
947
952
  const hasAddMenu = () => Boolean(props.fileSelection || props.menuActions?.length);
@@ -2266,7 +2271,7 @@ export function ChatComposer(props) {
2266
2271
  }
2267
2272
  })));
2268
2273
  }
2269
- })), `k2b-chat-composer ${_$escape(props.class ?? "", true)}`, _$ssrAttribute("data-running", running() ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-variant", conversation() ? "conversation" : _$escape(undefined, true), false), _$ssrAttribute("aria-label", _$escape(props.label ?? chatMessages().messageComposer, true), false), _$escape(_$createComponent(Show, {
2274
+ })), `k2b-chat-composer ${_$escape(props.class ?? "", true)}`, _$ssrAttribute("data-running", running() ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-variant", conversation() ? "conversation" : _$escape(undefined, true), false) + _$ssrAttribute("data-invalid", props.error ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-disabled", props.disabled ? "true" : _$escape(undefined, true), false), _$ssrAttribute("aria-label", _$escape(props.label ?? chatMessages().messageComposer, true), false), _$escape(_$createComponent(Show, {
2270
2275
  get when() {
2271
2276
  return showHint();
2272
2277
  },
@@ -2308,12 +2313,12 @@ export function ChatComposer(props) {
2308
2313
  get each() {
2309
2314
  return attachments();
2310
2315
  },
2311
- children: attachment => _$ssr(_tmpl$46, `k2b-chat-composer__attachment-content ${Boolean(attachment.action) ? "k2b-chat-composer__attachment-content--action" : ""}`, _$escape(_$createComponent(Show, {
2316
+ children: attachment => _$ssr(_tmpl$47, `k2b-chat-composer__attachment-content ${Boolean(attachment.action) || attachment.progress !== undefined ? "k2b-chat-composer__attachment-content--action" : ""}`, _$escape(_$createComponent(Show, {
2312
2317
  get when() {
2313
2318
  return attachment.href;
2314
2319
  },
2315
2320
  get fallback() {
2316
- return _$ssr(_tmpl$48, _$escape(_$createComponent(Show, {
2321
+ return _$ssr(_tmpl$49, _$escape(_$createComponent(Show, {
2317
2322
  get when() {
2318
2323
  return _$memo(() => attachment.kind === "image")() && attachment.previewUrl;
2319
2324
  },
@@ -2321,11 +2326,11 @@ export function ChatComposer(props) {
2321
2326
  return _$ssr(_tmpl$3, _$ssrAttribute("class", _$escape(attachmentIcon(attachment), true), false));
2322
2327
  },
2323
2328
  get children() {
2324
- return _$ssr(_tmpl$47, _$ssrAttribute("src", _$escape(attachment.previewUrl, true), false) + _$ssrAttribute("alt", _$escape(attachment.alt ?? "", true), false));
2329
+ return _$ssr(_tmpl$48, _$ssrAttribute("src", _$escape(attachment.previewUrl, true), false) + _$ssrAttribute("alt", _$escape(attachment.alt ?? "", true), false));
2325
2330
  }
2326
2331
  })), _$escape(renderAttachmentCopy(attachment)));
2327
2332
  },
2328
- children: href => _$ssr(_tmpl$49, _$ssrAttribute("href", _$escape(href(), true), false), _$ssrAttribute("aria-label", _$escape(chatMessages().openInNewTab({
2333
+ children: href => _$ssr(_tmpl$50, _$ssrAttribute("href", _$escape(href(), true), false), _$ssrAttribute("aria-label", _$escape(chatMessages().openInNewTab({
2329
2334
  name: attachment.name
2330
2335
  }), true), false), _$escape(_$createComponent(Show, {
2331
2336
  get when() {
@@ -2335,14 +2340,32 @@ export function ChatComposer(props) {
2335
2340
  return _$ssr(_tmpl$3, _$ssrAttribute("class", _$escape(attachmentIcon(attachment), true), false));
2336
2341
  },
2337
2342
  get children() {
2338
- return _$ssr(_tmpl$47, _$ssrAttribute("src", _$escape(attachment.previewUrl, true), false) + _$ssrAttribute("alt", _$escape(attachment.alt ?? "", true), false));
2343
+ return _$ssr(_tmpl$48, _$ssrAttribute("src", _$escape(attachment.previewUrl, true), false) + _$ssrAttribute("alt", _$escape(attachment.alt ?? "", true), false));
2339
2344
  }
2340
2345
  })), _$escape(renderAttachmentCopy(attachment)))
2341
2346
  })), _$escape(_$createComponent(Show, {
2342
2347
  get when() {
2343
- return attachment.action;
2348
+ return attachment.progress !== undefined;
2349
+ },
2350
+ get children() {
2351
+ return _$ssr(_tmpl$45, _$escape(_$createComponent(ProgressRing, {
2352
+ get value() {
2353
+ return attachment.progress ?? 0;
2354
+ },
2355
+ get label() {
2356
+ return chatMessages().uploading({
2357
+ name: attachment.name
2358
+ });
2359
+ }
2360
+ })), _$escape(new Intl.NumberFormat(locale(), {
2361
+ style: "percent"
2362
+ }).format(Math.round(attachment.progress ?? 0) / 100)));
2363
+ }
2364
+ })), _$escape(_$createComponent(Show, {
2365
+ get when() {
2366
+ return _$memo(() => attachment.progress === undefined)() && attachment.action;
2344
2367
  },
2345
- children: action => _$ssr(_tmpl$50, _$ssrAttribute("disabled", blocked() || action().disabled, true), _$escape(_$createComponent(Show, {
2368
+ children: action => _$ssr(_tmpl$51, _$ssrAttribute("data-tone", action().variant === "danger" ? "danger" : _$escape(undefined, true), false) + _$ssrAttribute("data-waiting", action().disabled ? "" : _$escape(undefined, true), false), _$ssrAttribute("disabled", blocked() || action().disabled, true), _$escape(_$createComponent(Show, {
2346
2369
  get when() {
2347
2370
  return action().icon;
2348
2371
  },
@@ -2353,7 +2376,7 @@ export function ChatComposer(props) {
2353
2376
  return props.onAttachmentsChange;
2354
2377
  },
2355
2378
  get children() {
2356
- return _$ssr(_tmpl$45, _$ssrAttribute("aria-label", _$escape(selectMessages().removeNamed({
2379
+ return _$ssr(_tmpl$46, _$ssrAttribute("aria-label", _$escape(selectMessages().removeNamed({
2357
2380
  name: attachment.name
2358
2381
  }), true), false), _$ssrAttribute("disabled", blocked(), true));
2359
2382
  }
@@ -2372,12 +2395,12 @@ export function ChatComposer(props) {
2372
2395
  get children() {
2373
2396
  return _$ssr(_tmpl$28, _$escape(props.error));
2374
2397
  }
2375
- }), formatRow(), _$ssr(_tmpl$51, _$escape(_$createComponent(Show, {
2398
+ }), formatRow(), _$ssr(_tmpl$52, _$escape(_$createComponent(Show, {
2376
2399
  get when() {
2377
2400
  return dictating() || footer();
2378
2401
  },
2379
2402
  get fallback() {
2380
- return [_$ssr(_tmpl$52, _$escape(props.footerTools), _$escape(_$createComponent(Show, {
2403
+ return [_$ssr(_tmpl$53, _$escape(props.footerTools), _$escape(_$createComponent(Show, {
2381
2404
  get when() {
2382
2405
  return addOpensCommands();
2383
2406
  },
@@ -2440,7 +2463,7 @@ export function ChatComposer(props) {
2440
2463
  }
2441
2464
  });
2442
2465
  }
2443
- })), _$escape(props.modelDetails)), _$ssr(_tmpl$53, _$escape(_$createComponent(For, {
2466
+ })), _$escape(props.modelDetails)), _$ssr(_tmpl$54, _$escape(_$createComponent(For, {
2444
2467
  get each() {
2445
2468
  return props.contextActions;
2446
2469
  },
@@ -2566,18 +2589,18 @@ export function ChatComposer(props) {
2566
2589
  return suggestionAnnouncement();
2567
2590
  },
2568
2591
  keyed: true,
2569
- children: announced => _$ssr(_tmpl$54, _$escape(announced.text))
2592
+ children: announced => _$ssr(_tmpl$55, _$escape(announced.text))
2570
2593
  })), _$escape(_$createComponent(Show, {
2571
2594
  get when() {
2572
2595
  return _$memo(() => !!!suggestionsOpen())() && commandStatus();
2573
2596
  },
2574
- children: status => _$ssr(_tmpl$55, _$ssrAttribute("data-tone", _$escape(status().tone, true), false), _$ssrAttribute("class", status().tone === "busy" ? "ti ti-loader-2 k2b-spin" : status().tone === "done" ? "ti ti-check" : "ti ti-alert-circle", false), _$escape(status().text))
2597
+ children: status => _$ssr(_tmpl$56, _$ssrAttribute("data-tone", _$escape(status().tone, true), false), _$ssrAttribute("class", status().tone === "busy" ? "ti ti-loader-2 k2b-spin" : status().tone === "done" ? "ti ti-check" : "ti ti-alert-circle", false), _$escape(status().text))
2575
2598
  })), _$escape(_$createComponent(Show, {
2576
2599
  get when() {
2577
2600
  return _$memo(() => !!suggestionsOpen())() && announcement();
2578
2601
  },
2579
2602
  keyed: true,
2580
- children: announced => _$ssr(_tmpl$56, _$escape(announced.text))
2603
+ children: announced => _$ssr(_tmpl$57, _$escape(announced.text))
2581
2604
  })));
2582
2605
  }
2583
2606
  //# sourceMappingURL=ChatComposer.js.map