@k2b/ui 0.40.0 → 0.42.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 (135) hide show
  1. package/dist/base.css +22 -0
  2. package/dist/browser/actions/Dropdown.js +220 -110
  3. package/dist/browser/actions/Dropdown.js.map +1 -1
  4. package/dist/browser/actions/index.js.map +1 -1
  5. package/dist/browser/actions/menu-search.js +166 -0
  6. package/dist/browser/actions/menu-search.js.map +1 -0
  7. package/dist/browser/actions/menu-sheet.js +107 -13
  8. package/dist/browser/actions/menu-sheet.js.map +1 -1
  9. package/dist/browser/chat/ChatComposer.js +759 -570
  10. package/dist/browser/chat/ChatComposer.js.map +1 -1
  11. package/dist/browser/content/CalendarWeekView.js +13 -1
  12. package/dist/browser/content/CalendarWeekView.js.map +1 -1
  13. package/dist/browser/inputs/ChoiceGroups.js +30 -18
  14. package/dist/browser/inputs/ChoiceGroups.js.map +1 -1
  15. package/dist/browser/inputs/IconChoices.js +121 -0
  16. package/dist/browser/inputs/IconChoices.js.map +1 -0
  17. package/dist/browser/inputs/Select.js +32 -19
  18. package/dist/browser/inputs/Select.js.map +1 -1
  19. package/dist/browser/inputs/SpecialInputs.js +54 -25
  20. package/dist/browser/inputs/SpecialInputs.js.map +1 -1
  21. package/dist/browser/inputs/choice.js +4 -1
  22. package/dist/browser/inputs/choice.js.map +1 -1
  23. package/dist/browser/inputs/dictation/Dictation.js +546 -0
  24. package/dist/browser/inputs/dictation/Dictation.js.map +1 -0
  25. package/dist/browser/inputs/dictation/create-dictation.js +324 -0
  26. package/dist/browser/inputs/dictation/create-dictation.js.map +1 -0
  27. package/dist/browser/inputs/dictation/dictation-messages.js +115 -0
  28. package/dist/browser/inputs/dictation/dictation-messages.js.map +1 -0
  29. package/dist/browser/inputs/dictation/text-dictation.js +152 -0
  30. package/dist/browser/inputs/dictation/text-dictation.js.map +1 -0
  31. package/dist/browser/inputs/dictation/types.js +2 -0
  32. package/dist/browser/inputs/dictation/types.js.map +1 -0
  33. package/dist/browser/inputs/icon-messages.js +29 -2
  34. package/dist/browser/inputs/icon-messages.js.map +1 -1
  35. package/dist/browser/inputs/icon-texts.js +172 -0
  36. package/dist/browser/inputs/icon-texts.js.map +1 -0
  37. package/dist/browser/inputs/index.js +3 -0
  38. package/dist/browser/inputs/index.js.map +1 -1
  39. package/dist/browser/intl/messages.js +6 -0
  40. package/dist/browser/intl/messages.js.map +1 -1
  41. package/dist/browser/layout/AnchoredPopover.js +1 -1
  42. package/dist/browser/layout/AnchoredPopover.js.map +1 -1
  43. package/dist/browser/layout/AppWorkspace.js +118 -93
  44. package/dist/browser/layout/AppWorkspace.js.map +1 -1
  45. package/dist/browser/layout/SettingsModal.js +10 -5
  46. package/dist/browser/layout/SettingsModal.js.map +1 -1
  47. package/dist/browser/text-editor/TextEditor.js +74 -25
  48. package/dist/browser/text-editor/TextEditor.js.map +1 -1
  49. package/dist/browser/text-editor/dictation.js +166 -0
  50. package/dist/browser/text-editor/dictation.js.map +1 -0
  51. package/dist/browser/text-editor/format.js +11 -7
  52. package/dist/browser/text-editor/format.js.map +1 -1
  53. package/dist/browser/text-editor/table.js +39 -11
  54. package/dist/browser/text-editor/table.js.map +1 -1
  55. package/dist/browser/text-editor.js +2 -1
  56. package/dist/browser/text-editor.js.map +1 -1
  57. package/dist/ssr/actions/Dropdown.js +118 -40
  58. package/dist/ssr/actions/Dropdown.js.map +1 -1
  59. package/dist/ssr/actions/index.js.map +1 -1
  60. package/dist/ssr/actions/menu-search.js +113 -0
  61. package/dist/ssr/actions/menu-search.js.map +1 -0
  62. package/dist/ssr/actions/menu-sheet.js +82 -13
  63. package/dist/ssr/actions/menu-sheet.js.map +1 -1
  64. package/dist/ssr/chat/ChatComposer.js +271 -99
  65. package/dist/ssr/chat/ChatComposer.js.map +1 -1
  66. package/dist/ssr/content/CalendarWeekView.js +13 -1
  67. package/dist/ssr/content/CalendarWeekView.js.map +1 -1
  68. package/dist/ssr/inputs/ChoiceGroups.js +12 -3
  69. package/dist/ssr/inputs/ChoiceGroups.js.map +1 -1
  70. package/dist/ssr/inputs/IconChoices.js +59 -0
  71. package/dist/ssr/inputs/IconChoices.js.map +1 -0
  72. package/dist/ssr/inputs/Select.js +8 -2
  73. package/dist/ssr/inputs/Select.js.map +1 -1
  74. package/dist/ssr/inputs/SpecialInputs.js +54 -25
  75. package/dist/ssr/inputs/SpecialInputs.js.map +1 -1
  76. package/dist/ssr/inputs/choice.js +4 -1
  77. package/dist/ssr/inputs/choice.js.map +1 -1
  78. package/dist/ssr/inputs/dictation/Dictation.js +386 -0
  79. package/dist/ssr/inputs/dictation/Dictation.js.map +1 -0
  80. package/dist/ssr/inputs/dictation/create-dictation.js +324 -0
  81. package/dist/ssr/inputs/dictation/create-dictation.js.map +1 -0
  82. package/dist/ssr/inputs/dictation/dictation-messages.js +115 -0
  83. package/dist/ssr/inputs/dictation/dictation-messages.js.map +1 -0
  84. package/dist/ssr/inputs/dictation/text-dictation.js +152 -0
  85. package/dist/ssr/inputs/dictation/text-dictation.js.map +1 -0
  86. package/dist/ssr/inputs/dictation/types.js +2 -0
  87. package/dist/ssr/inputs/dictation/types.js.map +1 -0
  88. package/dist/ssr/inputs/icon-messages.js +29 -2
  89. package/dist/ssr/inputs/icon-messages.js.map +1 -1
  90. package/dist/ssr/inputs/icon-texts.js +172 -0
  91. package/dist/ssr/inputs/icon-texts.js.map +1 -0
  92. package/dist/ssr/inputs/index.js +3 -0
  93. package/dist/ssr/inputs/index.js.map +1 -1
  94. package/dist/ssr/intl/messages.js +6 -0
  95. package/dist/ssr/intl/messages.js.map +1 -1
  96. package/dist/ssr/layout/AnchoredPopover.js +1 -1
  97. package/dist/ssr/layout/AnchoredPopover.js.map +1 -1
  98. package/dist/ssr/layout/AppWorkspace.js +40 -20
  99. package/dist/ssr/layout/AppWorkspace.js.map +1 -1
  100. package/dist/ssr/layout/SettingsModal.js +10 -5
  101. package/dist/ssr/layout/SettingsModal.js.map +1 -1
  102. package/dist/ssr/text-editor/TextEditor.js +74 -25
  103. package/dist/ssr/text-editor/TextEditor.js.map +1 -1
  104. package/dist/ssr/text-editor/dictation.js +166 -0
  105. package/dist/ssr/text-editor/dictation.js.map +1 -0
  106. package/dist/ssr/text-editor/format.js +11 -7
  107. package/dist/ssr/text-editor/format.js.map +1 -1
  108. package/dist/ssr/text-editor/table.js +39 -11
  109. package/dist/ssr/text-editor/table.js.map +1 -1
  110. package/dist/ssr/text-editor.js +2 -1
  111. package/dist/ssr/text-editor.js.map +1 -1
  112. package/dist/styles.css +1 -1
  113. package/dist/types/actions/Dropdown.d.ts +34 -3
  114. package/dist/types/actions/index.d.ts +1 -1
  115. package/dist/types/actions/menu-search.d.ts +27 -0
  116. package/dist/types/actions/menu-sheet.d.ts +5 -1
  117. package/dist/types/chat/ChatComposer.d.ts +9 -0
  118. package/dist/types/inputs/IconChoices.d.ts +19 -0
  119. package/dist/types/inputs/SpecialInputs.d.ts +8 -0
  120. package/dist/types/inputs/dictation/Dictation.d.ts +26 -0
  121. package/dist/types/inputs/dictation/create-dictation.d.ts +77 -0
  122. package/dist/types/inputs/dictation/dictation-messages.d.ts +54 -0
  123. package/dist/types/inputs/dictation/text-dictation.d.ts +36 -0
  124. package/dist/types/inputs/dictation/types.d.ts +74 -0
  125. package/dist/types/inputs/icon-messages.d.ts +14 -0
  126. package/dist/types/inputs/icon-texts.d.ts +13 -0
  127. package/dist/types/inputs/index.d.ts +7 -0
  128. package/dist/types/intl/messages.d.ts +3 -0
  129. package/dist/types/layout/AnchoredPopover.d.ts +5 -0
  130. package/dist/types/layout/AppWorkspace.d.ts +6 -1
  131. package/dist/types/text-editor/TextEditor.d.ts +10 -1
  132. package/dist/types/text-editor/dictation.d.ts +20 -0
  133. package/dist/types/text-editor/table.d.ts +2 -0
  134. package/dist/types/text-editor.d.ts +2 -1
  135. package/package.json +3 -1
@@ -3,7 +3,7 @@ import { ssr as _$ssr } from "solid-js/web";
3
3
  import { createComponent as _$createComponent } from "solid-js/web";
4
4
  import { ssrAttribute as _$ssrAttribute } from "solid-js/web";
5
5
  import { escape as _$escape } from "solid-js/web";
6
- var _tmpl$ = ["<button", " type=\"button\" role=\"tab\"", ">", "<span class=\"k2b-truncate-fade\">", "</span></button>"],
6
+ var _tmpl$ = ["<button", " type=\"button\" role=\"tab\"", ">", "<span class=\"k2b-truncate-fade-lines\">", "</span></button>"],
7
7
  _tmpl$2 = ["<i", " aria-hidden=\"true\"></i>"],
8
8
  _tmpl$3 = "<i class=\"ti ti-x\" aria-hidden=\"true\"></i>",
9
9
  _tmpl$4 = ["<div class=\"", "\" role=\"region\"", ">", "<aside class=\"k2b-settings__rail\"><nav class=\"k2b-settings__tabs\"", " role=\"tablist\" data-scroll-fade-mode=\"both\" data-scroll-fade-axis=\"horizontal\">", "</nav></aside><div class=\"k2b-settings__content\">", "", "</div></div>"],
@@ -25,7 +25,7 @@ const isGroupDefinition = value => !!value && typeof value === "object" && value
25
25
  const isFooterDefinition = value => !!value && typeof value === "object" && value.kind === SETTINGS_MODAL_FOOTER;
26
26
  const collectTabs = value => {
27
27
  if (Array.isArray(value)) return value.flatMap(collectTabs);
28
- if (isGroupDefinition(value)) return collectTabs(value.props.children);
28
+ if (isGroupDefinition(value)) return collectTabs(value.resolved());
29
29
  return isTabDefinition(value) ? [value] : [];
30
30
  };
31
31
  const collectRailEntries = value => {
@@ -58,9 +58,13 @@ function SettingsModalTab(props) {
58
58
  };
59
59
  }
60
60
  function SettingsModalGroup(props) {
61
+ // The modal's own `children()` does not reach into a group. Resolving here keeps the other tabs of a group the same
62
+ // objects when a conditional tab comes or goes, so the open panel and its unsaved input stay in place.
63
+ const resolved = children(() => props.children);
61
64
  return {
62
65
  kind: SETTINGS_MODAL_GROUP,
63
- props
66
+ props,
67
+ resolved
64
68
  };
65
69
  }
66
70
  function SettingsModalFooter(props) {
@@ -96,7 +100,8 @@ const SettingsModal = props => {
96
100
  inline: "nearest"
97
101
  }));
98
102
  });
99
- const activeTab = () => tabs().find(tab => tab.props.id === resolvedActiveTabId()) ?? null;
103
+ // A memo, so a change elsewhere in the tab list does not create the open panel again.
104
+ const activeTab = createMemo(() => tabs().find(tab => tab.props.id === resolvedActiveTabId()) ?? null);
100
105
  const resolvedPanelChildren = children(() => activeTab()?.props.children);
101
106
  const panelChildren = createMemo(() => splitPanelChildren(resolvedPanelChildren()));
102
107
  const selectTab = id => {
@@ -155,7 +160,7 @@ const SettingsModal = props => {
155
160
  },
156
161
  children: entry => isGroupDefinition(entry) ? _$ssr(_tmpl$5, _$escape(entry.props.title), _$escape(_$createComponent(For, {
157
162
  get each() {
158
- return collectTabs(entry.props.children);
163
+ return collectTabs(entry.resolved());
159
164
  },
160
165
  children: tab => TabButton(tab)
161
166
  }))) : TabButton(entry)
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["layout/SettingsModal.tsx"],"sourcesContent":["import { children, createEffect, createMemo, createSignal, createUniqueId, For, type JSX, Show } from \"solid-js\";\nimport { IconButton } from \"../actions/Button\";\nimport { useUiMessages } from \"../intl/messages\";\nimport { createScrollFade } from \"./scroll-fade\";\nimport { useSettingsMessages } from \"./settings-messages\";\nimport { assertUniqueStableUiIds } from \"./stable-id\";\n\nconst SETTINGS_MODAL_TAB = Symbol(\"SettingsModal.Tab\");\nconst SETTINGS_MODAL_GROUP = Symbol(\"SettingsModal.Group\");\nconst SETTINGS_MODAL_FOOTER = Symbol(\"SettingsModal.Footer\");\n\nexport type SettingsModalTabTone = \"default\" | \"danger\";\n\nexport type SettingsModalTabProps = {\n id: string;\n title: string;\n description?: string;\n icon?: string;\n tone?: SettingsModalTabTone;\n children: JSX.Element;\n};\n\nexport type SettingsModalGroupProps = {\n title: string;\n children: JSX.Element;\n};\n\nexport type SettingsModalFooterProps = {\n children: JSX.Element;\n};\n\ntype SettingsModalTabDefinition = {\n readonly kind: typeof SETTINGS_MODAL_TAB;\n readonly props: SettingsModalTabProps;\n};\n\ntype SettingsModalGroupDefinition = {\n readonly kind: typeof SETTINGS_MODAL_GROUP;\n readonly props: SettingsModalGroupProps;\n};\n\ntype SettingsModalFooterDefinition = {\n readonly kind: typeof SETTINGS_MODAL_FOOTER;\n readonly props: SettingsModalFooterProps;\n};\n\nexport type SettingsModalProps = {\n /** Accessible name for the settings surface. */\n title: string;\n /** @deprecated Retained for source compatibility; tab descriptions carry the visible context. */\n subtitle?: string;\n /** @deprecated Retained for source compatibility; tab icons identify the rail entries. */\n icon?: string;\n defaultTab?: string;\n activeTab?: string;\n onTabChange?: (id: string) => void;\n onClose?: () => void;\n closeLabel?: string;\n class?: string;\n children: JSX.Element;\n};\n\ntype SettingsModalComponent = ((props: SettingsModalProps) => JSX.Element) & {\n Tab: (props: SettingsModalTabProps) => JSX.Element;\n Group: (props: SettingsModalGroupProps) => JSX.Element;\n Footer: (props: SettingsModalFooterProps) => JSX.Element;\n};\n\nconst isTabDefinition = (value: unknown): value is SettingsModalTabDefinition =>\n !!value && typeof value === \"object\" && (value as { kind?: unknown }).kind === SETTINGS_MODAL_TAB;\n\nconst isGroupDefinition = (value: unknown): value is SettingsModalGroupDefinition =>\n !!value && typeof value === \"object\" && (value as { kind?: unknown }).kind === SETTINGS_MODAL_GROUP;\n\nconst isFooterDefinition = (value: unknown): value is SettingsModalFooterDefinition =>\n !!value && typeof value === \"object\" && (value as { kind?: unknown }).kind === SETTINGS_MODAL_FOOTER;\n\nconst collectTabs = (value: unknown): SettingsModalTabDefinition[] => {\n if (Array.isArray(value)) return value.flatMap(collectTabs);\n if (isGroupDefinition(value)) return collectTabs(value.props.children);\n return isTabDefinition(value) ? [value] : [];\n};\n\nconst collectRailEntries = (value: unknown): (SettingsModalGroupDefinition | SettingsModalTabDefinition)[] => {\n if (Array.isArray(value)) return value.flatMap(collectRailEntries);\n if (isGroupDefinition(value) || isTabDefinition(value)) return [value];\n return [];\n};\n\nconst splitPanelChildren = (value: unknown): { content: JSX.Element[]; footer?: SettingsModalFooterDefinition } => {\n if (Array.isArray(value)) {\n return value.reduce<{ content: JSX.Element[]; footer?: SettingsModalFooterDefinition }>(\n (result, entry) => {\n const next = splitPanelChildren(entry);\n result.content.push(...next.content);\n if (next.footer) result.footer = next.footer;\n return result;\n },\n { content: [] },\n );\n }\n return isFooterDefinition(value) ? { content: [], footer: value } : { content: [value as JSX.Element] };\n};\n\nfunction SettingsModalTab(props: SettingsModalTabProps): JSX.Element {\n return { kind: SETTINGS_MODAL_TAB, props } satisfies SettingsModalTabDefinition as unknown as JSX.Element;\n}\n\nfunction SettingsModalGroup(props: SettingsModalGroupProps): JSX.Element {\n return { kind: SETTINGS_MODAL_GROUP, props } satisfies SettingsModalGroupDefinition as unknown as JSX.Element;\n}\n\nfunction SettingsModalFooter(props: SettingsModalFooterProps): JSX.Element {\n return { kind: SETTINGS_MODAL_FOOTER, props } satisfies SettingsModalFooterDefinition as unknown as JSX.Element;\n}\n\nconst SettingsModal = ((props: SettingsModalProps): JSX.Element => {\n const messages = useUiMessages();\n const settingsMessages = useSettingsMessages();\n const resolved = children(() => props.children);\n const railEntries = createMemo(() => collectRailEntries(resolved()));\n const tabs = createMemo(() => {\n const collected = collectTabs(resolved());\n assertUniqueStableUiIds(\n collected.map((tab) => tab.props.id),\n \"SettingsModal.Tab id\",\n );\n return collected;\n });\n const instanceId = `k2b-settings-${createUniqueId()}`;\n const tabRefs = new Map<string, HTMLButtonElement>();\n let tabList: HTMLElement | undefined;\n // Narrow surfaces show the categories as one scrolling row; the fade tells that more follow.\n createScrollFade(\n () => tabList,\n () => true,\n );\n const firstTabId = () => tabs()[0]?.props.id ?? \"\";\n const [localActiveTab, setLocalActiveTab] = createSignal(props.defaultTab ?? firstTabId());\n const requestedActiveTabId = () => props.activeTab ?? (localActiveTab() || firstTabId());\n const resolvedActiveTabId = createMemo(() =>\n tabs().some((tab) => tab.props.id === requestedActiveTabId()) ? requestedActiveTabId() : firstTabId(),\n );\n // `defaultTab`, `activeTab` and clicks can select a category past the edge of the scrolling row or rail.\n createEffect(() => {\n const id = resolvedActiveTabId();\n queueMicrotask(() => tabRefs.get(id)?.scrollIntoView?.({ block: \"nearest\", inline: \"nearest\" }));\n });\n const activeTab = () => tabs().find((tab) => tab.props.id === resolvedActiveTabId()) ?? null;\n const resolvedPanelChildren = children(() => activeTab()?.props.children);\n const panelChildren = createMemo(() => splitPanelChildren(resolvedPanelChildren()));\n\n const selectTab = (id: string) => {\n if (props.activeTab === undefined) setLocalActiveTab(id);\n props.onTabChange?.(id);\n };\n\n const moveTabFocus = (event: KeyboardEvent, currentId: string) => {\n const currentIndex = tabs().findIndex((tab) => tab.props.id === currentId);\n if (currentIndex < 0 || tabs().length === 0) return;\n let nextIndex: number | null = null;\n if (event.key === \"ArrowRight\" || event.key === \"ArrowDown\") nextIndex = (currentIndex + 1) % tabs().length;\n if (event.key === \"ArrowLeft\" || event.key === \"ArrowUp\") nextIndex = (currentIndex - 1 + tabs().length) % tabs().length;\n if (event.key === \"Home\") nextIndex = 0;\n if (event.key === \"End\") nextIndex = tabs().length - 1;\n if (nextIndex === null) return;\n event.preventDefault();\n const nextTab = tabs()[nextIndex];\n if (!nextTab) return;\n selectTab(nextTab.props.id);\n tabRefs.get(nextTab.props.id)?.focus();\n };\n\n const tabId = (id: string) => `${instanceId}-tab-${id}`;\n const panelId = (id: string) => `${instanceId}-panel-${id}`;\n\n const TabButton = (tab: SettingsModalTabDefinition): JSX.Element => {\n const active = () => resolvedActiveTabId() === tab.props.id;\n return (\n <button\n ref={(element) => tabRefs.set(tab.props.id, element)}\n id={tabId(tab.props.id)}\n type=\"button\"\n role=\"tab\"\n aria-selected={active()}\n aria-controls={active() ? panelId(tab.props.id) : undefined}\n tabIndex={active() ? 0 : -1}\n data-state={active() ? \"active\" : \"idle\"}\n data-active={active() ? \"true\" : undefined}\n data-tone={tab.props.tone ?? \"default\"}\n onClick={() => selectTab(tab.props.id)}\n onKeyDown={(event) => moveTabFocus(event, tab.props.id)}\n >\n <Show when={tab.props.icon}>{(icon) => <i class={icon()} aria-hidden=\"true\" />}</Show>\n <span class=\"k2b-truncate-fade\">{tab.props.title}</span>\n </button>\n );\n };\n\n return (\n <div class={`k2b-settings ${props.class ?? \"\"}`} role=\"region\" aria-label={props.title}>\n <Show when={props.onClose}>\n <IconButton class=\"k2b-settings__close\" label={props.closeLabel ?? messages().close} onClick={props.onClose}>\n <i class=\"ti ti-x\" aria-hidden=\"true\" />\n </IconButton>\n </Show>\n <aside class=\"k2b-settings__rail\">\n <nav\n ref={tabList}\n class=\"k2b-settings__tabs\"\n aria-label={settingsMessages().sectionsLabel({ title: props.title })}\n role=\"tablist\"\n data-scroll-fade-mode=\"both\"\n data-scroll-fade-axis=\"horizontal\"\n >\n <For each={railEntries()}>\n {(entry) =>\n isGroupDefinition(entry) ? (\n <div class=\"k2b-settings__tab-group\" role=\"presentation\">\n <span class=\"k2b-settings__tab-group-label k2b-truncate-fade\" aria-hidden=\"true\">\n {entry.props.title}\n </span>\n <For each={collectTabs(entry.props.children)}>{(tab) => TabButton(tab)}</For>\n </div>\n ) : (\n TabButton(entry)\n )\n }\n </For>\n </nav>\n </aside>\n <div class=\"k2b-settings__content\">\n <Show when={activeTab()}>\n {(tab) => (\n <section\n id={panelId(tab().props.id)}\n class=\"k2b-settings__body\"\n role=\"tabpanel\"\n aria-labelledby={tabId(tab().props.id)}\n tabIndex={0}\n data-tone={tab().props.tone ?? \"default\"}\n >\n <div class=\"k2b-settings__section\">\n <div class=\"k2b-settings__section-heading\">\n <h2>{tab().props.title}</h2>\n <Show when={tab().props.description}>{(description) => <p>{description()}</p>}</Show>\n </div>\n {panelChildren().content}\n </div>\n </section>\n )}\n </Show>\n <Show when={panelChildren().footer}>{(footer) => <footer class=\"k2b-settings__footer\">{footer().props.children}</footer>}</Show>\n </div>\n </div>\n );\n}) as SettingsModalComponent;\n\nSettingsModal.Tab = SettingsModalTab;\nSettingsModal.Group = SettingsModalGroup;\nSettingsModal.Footer = SettingsModalFooter;\n\nexport default SettingsModal;\n"],"mappings":";;;;;;;;;;;;;AAAA,SAAS,QAAQ,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,GAAG,EAAY,IAAI,QAAQ,UAAU;AAChH,SAAS,UAAU,QAAQ,mBAAmB;AAC9C,SAAS,aAAa,QAAQ,kBAAkB;AAChD,SAAS,gBAAgB,QAAQ,eAAe;AAChD,SAAS,mBAAmB,QAAQ,qBAAqB;AACzD,SAAS,uBAAuB,QAAQ,aAAa;AAErD,MAAM,kBAAkB,GAAG,MAAM,CAAC,mBAAmB,CAAC;AACtD,MAAM,oBAAoB,GAAG,MAAM,CAAC,qBAAqB,CAAC;AAC1D,MAAM,qBAAqB,GAAG,MAAM,CAAC,sBAAsB,CAAC;AA2D5D,MAAM,eAAe,GAAI,KAAc,IACrC,CAAC,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAK,KAAK,CAAwB,IAAI,KAAK,kBAAkB;AAEnG,MAAM,iBAAiB,GAAI,KAAc,IACvC,CAAC,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAK,KAAK,CAAwB,IAAI,KAAK,oBAAoB;AAErG,MAAM,kBAAkB,GAAI,KAAc,IACxC,CAAC,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAK,KAAK,CAAwB,IAAI,KAAK,qBAAqB;AAEtG,MAAM,WAAW,GAAI,KAAc,IAAmC;EACpE,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC;EAC3D,IAAI,iBAAiB,CAAC,KAAK,CAAC,EAAE,OAAO,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC;EACtE,OAAO,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE;AAC9C,CAAC;AAED,MAAM,kBAAkB,GAAI,KAAc,IAAoE;EAC5G,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC,OAAO,CAAC,kBAAkB,CAAC;EAClE,IAAI,iBAAiB,CAAC,KAAK,CAAC,IAAI,eAAe,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC;EACtE,OAAO,EAAE;AACX,CAAC;AAED,MAAM,kBAAkB,GAAI,KAAc,IAAyE;EACjH,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;IACxB,OAAO,KAAK,CAAC,MAAM,CACjB,CAAC,MAAM,EAAE,KAAK,KAAK;MACjB,MAAM,IAAI,GAAG,kBAAkB,CAAC,KAAK,CAAC;MACtC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC;MACpC,IAAI,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM;MAC5C,OAAO,MAAM;IACf,CAAC,EACD;MAAE,OAAO,EAAE;IAAG,CAChB,CAAC;EACH;EACA,OAAO,kBAAkB,CAAC,KAAK,CAAC,GAAG;IAAE,OAAO,EAAE,EAAE;IAAE,MAAM,EAAE;EAAM,CAAC,GAAG;IAAE,OAAO,EAAE,CAAC,KAAK;EAAiB,CAAC;AACzG,CAAC;AAED,SAAS,gBAAgB,CAAC,KAA4B,EAAe;EACnE,OAAO;IAAE,IAAI,EAAE,kBAAkB;IAAE;EAAM,CAAC;AAC5C;AAEA,SAAS,kBAAkB,CAAC,KAA8B,EAAe;EACvE,OAAO;IAAE,IAAI,EAAE,oBAAoB;IAAE;EAAM,CAAC;AAC9C;AAEA,SAAS,mBAAmB,CAAC,KAA+B,EAAe;EACzE,OAAO;IAAE,IAAI,EAAE,qBAAqB;IAAE;EAAM,CAAC;AAC/C;AAEA,MAAM,aAAa,GAAK,KAAyB,IAAkB;EACjE,MAAM,QAAQ,GAAG,aAAa,CAAC,CAAC;EAChC,MAAM,gBAAgB,GAAG,mBAAmB,CAAC,CAAC;EAC9C,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,KAAK,CAAC,QAAQ,CAAC;EAC/C,MAAM,WAAW,GAAG,UAAU,CAAC,MAAM,kBAAkB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;EACpE,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM;IAC5B,MAAM,SAAS,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC;IACzC,uBAAuB,CACrB,SAAS,CAAC,GAAG,CAAE,GAAG,IAAK,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,EACpC,sBACF,CAAC;IACD,OAAO,SAAS;EAClB,CAAC,CAAC;EACF,MAAM,UAAU,GAAG,gBAAgB,cAAc,CAAC,CAAC,EAAE;EACrD,MAAM,OAAO,GAAG,IAAI,GAAG,CAA4B,CAAC;EACpD,IAAI,OAAgC;EACpC;EACA,gBAAgB,CACd,MAAM,OAAO,EACb,MAAM,IACR,CAAC;EACD,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,IAAI,EAAE;EAClD,MAAM,CAAC,cAAc,EAAE,iBAAiB,CAAC,GAAG,YAAY,CAAC,KAAK,CAAC,UAAU,IAAI,UAAU,CAAC,CAAC,CAAC;EAC1F,MAAM,oBAAoB,GAAG,MAAM,KAAK,CAAC,SAAS,KAAK,cAAc,CAAC,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC;EACxF,MAAM,mBAAmB,GAAG,UAAU,CAAC,MACrC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAE,GAAG,IAAK,GAAG,CAAC,KAAK,CAAC,EAAE,KAAK,oBAAoB,CAAC,CAAC,CAAC,GAAG,oBAAoB,CAAC,CAAC,GAAG,UAAU,CAAC,CACtG,CAAC;EACD;EACA,YAAY,CAAC,MAAM;IACjB,MAAM,EAAE,GAAG,mBAAmB,CAAC,CAAC;IAChC,cAAc,CAAC,MAAM,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,cAAc,GAAG;MAAE,KAAK,EAAE,SAAS;MAAE,MAAM,EAAE;IAAU,CAAC,CAAC,CAAC;EAClG,CAAC,CAAC;EACF,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,CAAC,CAAC,IAAI,CAAE,GAAG,IAAK,GAAG,CAAC,KAAK,CAAC,EAAE,KAAK,mBAAmB,CAAC,CAAC,CAAC,IAAI,IAAI;EAC5F,MAAM,qBAAqB,GAAG,QAAQ,CAAC,MAAM,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,QAAQ,CAAC;EACzE,MAAM,aAAa,GAAG,UAAU,CAAC,MAAM,kBAAkB,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;EAEnF,MAAM,SAAS,GAAI,EAAU,IAAK;IAChC,IAAI,KAAK,CAAC,SAAS,KAAK,SAAS,EAAE,iBAAiB,CAAC,EAAE,CAAC;IACxD,KAAK,CAAC,WAAW,GAAG,EAAE,CAAC;EACzB,CAAC;EAED,MAAM,YAAY,GAAG,CAAC,KAAoB,EAAE,SAAiB,KAAK;IAChE,MAAM,YAAY,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,CAAE,GAAG,IAAK,GAAG,CAAC,KAAK,CAAC,EAAE,KAAK,SAAS,CAAC;IAC1E,IAAI,YAAY,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE;IAC7C,IAAI,SAAwB,GAAG,IAAI;IACnC,IAAI,KAAK,CAAC,GAAG,KAAK,YAAY,IAAI,KAAK,CAAC,GAAG,KAAK,WAAW,EAAE,SAAS,GAAG,CAAC,YAAY,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM;IAC3G,IAAI,KAAK,CAAC,GAAG,KAAK,WAAW,IAAI,KAAK,CAAC,GAAG,KAAK,SAAS,EAAE,SAAS,GAAG,CAAC,YAAY,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM;IACxH,IAAI,KAAK,CAAC,GAAG,KAAK,MAAM,EAAE,SAAS,GAAG,CAAC;IACvC,IAAI,KAAK,CAAC,GAAG,KAAK,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC;IACtD,IAAI,SAAS,KAAK,IAAI,EAAE;IACxB,KAAK,CAAC,cAAc,CAAC,CAAC;IACtB,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;IACjC,IAAI,CAAC,OAAO,EAAE;IACd,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;IAC3B,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;EACxC,CAAC;EAED,MAAM,KAAK,GAAI,EAAU,IAAK,GAAG,UAAU,QAAQ,EAAE,EAAE;EACvD,MAAM,OAAO,GAAI,EAAU,IAAK,GAAG,UAAU,UAAU,EAAE,EAAE;EAE3D,MAAM,SAAS,GAAI,GAA+B,IAAkB;IAClE,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,CAAC,KAAK,GAAG,CAAC,KAAK,CAAC,EAAE;IAC3D,mDAGQ,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,0DAGR,MAAM,CAAC,CAAC,kDACR,MAAM,CAAC,CAAC,YAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,mBAAG,SAAS,6CACjD,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,wCACf,MAAM,CAAC,CAAC,GAAG,QAAQ,GAAG,MAAM,yCAC3B,MAAM,CAAC,CAAC,GAAG,MAAM,YAAG,SAAS,uDAC/B,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,SAAS,4CAIrC,IAAI;MAAA,IAAC,IAAI;QAAA,OAAE,GAAG,CAAC,KAAK,CAAC,IAAI;MAAA;MAAA,UAAI,IAAI,oDAAe,IAAI,CAAC,CAAC;IAAuB,cAC7C,GAAG,CAAC,KAAK,CAAC,KAAK;EAGtD,CAAC;EAED,sBACc,yBAAgB,KAAK,CAAC,KAAK,IAAI,EAAE,SAAE,wCAA4B,KAAK,CAAC,KAAK,4CACnF,IAAI;IAAA,IAAC,IAAI;MAAA,OAAE,KAAK,CAAC,OAAO;IAAA;IAAA;MAAA,yBACtB,UAAU;QAAA;QAAA,IAA6B,KAAK;UAAA,OAAE,KAAK,CAAC,UAAU,IAAI,QAAQ,CAAC,CAAC,CAAC,KAAK;QAAA;QAAA,IAAE,OAAO;UAAA,OAAE,KAAK,CAAC,OAAO;QAAA;QAAA;UAAA;QAAA;MAAA;IAAA;EAAA,2CAQ7F,gBAAgB,CAAC,CAAC,CAAC,aAAa,CAAC;IAAE,KAAK,EAAE,KAAK,CAAC;EAAM,CAAC,CAAC,4CAKnE,GAAG;IAAA,IAAC,IAAI;MAAA,OAAE,WAAW,CAAC,CAAC;IAAA;IAAA,UACpB,KAAK,IACL,iBAAiB,CAAC,KAAK,CAAC,2BAGjB,KAAK,CAAC,KAAK,CAAC,KAAK,8BAEnB,GAAG;MAAA,IAAC,IAAI;QAAA,OAAE,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC;MAAA;MAAA,UAAI,GAAG,IAAK,SAAS,CAAC,GAAG;IAAC,OAGxE,SAAS,CAAC,KAAK;EAChB,gCAMN,IAAI;IAAA,IAAC,IAAI;MAAA,OAAE,SAAS,CAAC,CAAC;IAAA;IAAA,UACnB,GAAG,iDAEG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,4DAGV,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,sDAE3B,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,IAAI,SAAS,0BAI/B,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,8BACrB,IAAI;MAAA,IAAC,IAAI;QAAA,OAAE,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW;MAAA;MAAA,UAAI,WAAW,4BAAS,WAAW,CAAC,CAAC;IAAK,cAE9E,aAAa,CAAC,CAAC,CAAC,OAAO;EAG7B,gCAEF,IAAI;IAAA,IAAC,IAAI;MAAA,OAAE,aAAa,CAAC,CAAC,CAAC,MAAM;IAAA;IAAA,UAAI,MAAM,4BAA2C,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ;EAAU;AAIhI,CAA4B;AAE5B,aAAa,CAAC,GAAG,GAAG,gBAAgB;AACpC,aAAa,CAAC,KAAK,GAAG,kBAAkB;AACxC,aAAa,CAAC,MAAM,GAAG,mBAAmB;AAE1C,eAAe,aAAa","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["layout/SettingsModal.tsx"],"sourcesContent":["import { type Accessor, children, createEffect, createMemo, createSignal, createUniqueId, For, type JSX, Show } from \"solid-js\";\nimport { IconButton } from \"../actions/Button\";\nimport { useUiMessages } from \"../intl/messages\";\nimport { createScrollFade } from \"./scroll-fade\";\nimport { useSettingsMessages } from \"./settings-messages\";\nimport { assertUniqueStableUiIds } from \"./stable-id\";\n\nconst SETTINGS_MODAL_TAB = Symbol(\"SettingsModal.Tab\");\nconst SETTINGS_MODAL_GROUP = Symbol(\"SettingsModal.Group\");\nconst SETTINGS_MODAL_FOOTER = Symbol(\"SettingsModal.Footer\");\n\nexport type SettingsModalTabTone = \"default\" | \"danger\";\n\nexport type SettingsModalTabProps = {\n id: string;\n title: string;\n description?: string;\n icon?: string;\n tone?: SettingsModalTabTone;\n children: JSX.Element;\n};\n\nexport type SettingsModalGroupProps = {\n title: string;\n children: JSX.Element;\n};\n\nexport type SettingsModalFooterProps = {\n children: JSX.Element;\n};\n\ntype SettingsModalTabDefinition = {\n readonly kind: typeof SETTINGS_MODAL_TAB;\n readonly props: SettingsModalTabProps;\n};\n\ntype SettingsModalGroupDefinition = {\n readonly kind: typeof SETTINGS_MODAL_GROUP;\n readonly props: SettingsModalGroupProps;\n /** The group's children, created once and resolved like `children()`, so a `<Show>` tab follows its condition. */\n readonly resolved: Accessor<unknown>;\n};\n\ntype SettingsModalFooterDefinition = {\n readonly kind: typeof SETTINGS_MODAL_FOOTER;\n readonly props: SettingsModalFooterProps;\n};\n\nexport type SettingsModalProps = {\n /** Accessible name for the settings surface. */\n title: string;\n /** @deprecated Retained for source compatibility; tab descriptions carry the visible context. */\n subtitle?: string;\n /** @deprecated Retained for source compatibility; tab icons identify the rail entries. */\n icon?: string;\n defaultTab?: string;\n activeTab?: string;\n onTabChange?: (id: string) => void;\n onClose?: () => void;\n closeLabel?: string;\n class?: string;\n children: JSX.Element;\n};\n\ntype SettingsModalComponent = ((props: SettingsModalProps) => JSX.Element) & {\n Tab: (props: SettingsModalTabProps) => JSX.Element;\n Group: (props: SettingsModalGroupProps) => JSX.Element;\n Footer: (props: SettingsModalFooterProps) => JSX.Element;\n};\n\nconst isTabDefinition = (value: unknown): value is SettingsModalTabDefinition =>\n !!value && typeof value === \"object\" && (value as { kind?: unknown }).kind === SETTINGS_MODAL_TAB;\n\nconst isGroupDefinition = (value: unknown): value is SettingsModalGroupDefinition =>\n !!value && typeof value === \"object\" && (value as { kind?: unknown }).kind === SETTINGS_MODAL_GROUP;\n\nconst isFooterDefinition = (value: unknown): value is SettingsModalFooterDefinition =>\n !!value && typeof value === \"object\" && (value as { kind?: unknown }).kind === SETTINGS_MODAL_FOOTER;\n\nconst collectTabs = (value: unknown): SettingsModalTabDefinition[] => {\n if (Array.isArray(value)) return value.flatMap(collectTabs);\n if (isGroupDefinition(value)) return collectTabs(value.resolved());\n return isTabDefinition(value) ? [value] : [];\n};\n\nconst collectRailEntries = (value: unknown): (SettingsModalGroupDefinition | SettingsModalTabDefinition)[] => {\n if (Array.isArray(value)) return value.flatMap(collectRailEntries);\n if (isGroupDefinition(value) || isTabDefinition(value)) return [value];\n return [];\n};\n\nconst splitPanelChildren = (value: unknown): { content: JSX.Element[]; footer?: SettingsModalFooterDefinition } => {\n if (Array.isArray(value)) {\n return value.reduce<{ content: JSX.Element[]; footer?: SettingsModalFooterDefinition }>(\n (result, entry) => {\n const next = splitPanelChildren(entry);\n result.content.push(...next.content);\n if (next.footer) result.footer = next.footer;\n return result;\n },\n { content: [] },\n );\n }\n return isFooterDefinition(value) ? { content: [], footer: value } : { content: [value as JSX.Element] };\n};\n\nfunction SettingsModalTab(props: SettingsModalTabProps): JSX.Element {\n return { kind: SETTINGS_MODAL_TAB, props } satisfies SettingsModalTabDefinition as unknown as JSX.Element;\n}\n\nfunction SettingsModalGroup(props: SettingsModalGroupProps): JSX.Element {\n // The modal's own `children()` does not reach into a group. Resolving here keeps the other tabs of a group the same\n // objects when a conditional tab comes or goes, so the open panel and its unsaved input stay in place.\n const resolved = children(() => props.children);\n return { kind: SETTINGS_MODAL_GROUP, props, resolved } satisfies SettingsModalGroupDefinition as unknown as JSX.Element;\n}\n\nfunction SettingsModalFooter(props: SettingsModalFooterProps): JSX.Element {\n return { kind: SETTINGS_MODAL_FOOTER, props } satisfies SettingsModalFooterDefinition as unknown as JSX.Element;\n}\n\nconst SettingsModal = ((props: SettingsModalProps): JSX.Element => {\n const messages = useUiMessages();\n const settingsMessages = useSettingsMessages();\n const resolved = children(() => props.children);\n const railEntries = createMemo(() => collectRailEntries(resolved()));\n const tabs = createMemo(() => {\n const collected = collectTabs(resolved());\n assertUniqueStableUiIds(\n collected.map((tab) => tab.props.id),\n \"SettingsModal.Tab id\",\n );\n return collected;\n });\n const instanceId = `k2b-settings-${createUniqueId()}`;\n const tabRefs = new Map<string, HTMLButtonElement>();\n let tabList: HTMLElement | undefined;\n // Narrow surfaces show the categories as one scrolling row; the fade tells that more follow.\n createScrollFade(\n () => tabList,\n () => true,\n );\n const firstTabId = () => tabs()[0]?.props.id ?? \"\";\n const [localActiveTab, setLocalActiveTab] = createSignal(props.defaultTab ?? firstTabId());\n const requestedActiveTabId = () => props.activeTab ?? (localActiveTab() || firstTabId());\n const resolvedActiveTabId = createMemo(() =>\n tabs().some((tab) => tab.props.id === requestedActiveTabId()) ? requestedActiveTabId() : firstTabId(),\n );\n // `defaultTab`, `activeTab` and clicks can select a category past the edge of the scrolling row or rail.\n createEffect(() => {\n const id = resolvedActiveTabId();\n queueMicrotask(() => tabRefs.get(id)?.scrollIntoView?.({ block: \"nearest\", inline: \"nearest\" }));\n });\n // A memo, so a change elsewhere in the tab list does not create the open panel again.\n const activeTab = createMemo(() => tabs().find((tab) => tab.props.id === resolvedActiveTabId()) ?? null);\n const resolvedPanelChildren = children(() => activeTab()?.props.children);\n const panelChildren = createMemo(() => splitPanelChildren(resolvedPanelChildren()));\n\n const selectTab = (id: string) => {\n if (props.activeTab === undefined) setLocalActiveTab(id);\n props.onTabChange?.(id);\n };\n\n const moveTabFocus = (event: KeyboardEvent, currentId: string) => {\n const currentIndex = tabs().findIndex((tab) => tab.props.id === currentId);\n if (currentIndex < 0 || tabs().length === 0) return;\n let nextIndex: number | null = null;\n if (event.key === \"ArrowRight\" || event.key === \"ArrowDown\") nextIndex = (currentIndex + 1) % tabs().length;\n if (event.key === \"ArrowLeft\" || event.key === \"ArrowUp\") nextIndex = (currentIndex - 1 + tabs().length) % tabs().length;\n if (event.key === \"Home\") nextIndex = 0;\n if (event.key === \"End\") nextIndex = tabs().length - 1;\n if (nextIndex === null) return;\n event.preventDefault();\n const nextTab = tabs()[nextIndex];\n if (!nextTab) return;\n selectTab(nextTab.props.id);\n tabRefs.get(nextTab.props.id)?.focus();\n };\n\n const tabId = (id: string) => `${instanceId}-tab-${id}`;\n const panelId = (id: string) => `${instanceId}-panel-${id}`;\n\n const TabButton = (tab: SettingsModalTabDefinition): JSX.Element => {\n const active = () => resolvedActiveTabId() === tab.props.id;\n return (\n <button\n ref={(element) => tabRefs.set(tab.props.id, element)}\n id={tabId(tab.props.id)}\n type=\"button\"\n role=\"tab\"\n aria-selected={active()}\n aria-controls={active() ? panelId(tab.props.id) : undefined}\n tabIndex={active() ? 0 : -1}\n data-state={active() ? \"active\" : \"idle\"}\n data-active={active() ? \"true\" : undefined}\n data-tone={tab.props.tone ?? \"default\"}\n onClick={() => selectTab(tab.props.id)}\n onKeyDown={(event) => moveTabFocus(event, tab.props.id)}\n >\n <Show when={tab.props.icon}>{(icon) => <i class={icon()} aria-hidden=\"true\" />}</Show>\n <span class=\"k2b-truncate-fade-lines\">{tab.props.title}</span>\n </button>\n );\n };\n\n return (\n <div class={`k2b-settings ${props.class ?? \"\"}`} role=\"region\" aria-label={props.title}>\n <Show when={props.onClose}>\n <IconButton class=\"k2b-settings__close\" label={props.closeLabel ?? messages().close} onClick={props.onClose}>\n <i class=\"ti ti-x\" aria-hidden=\"true\" />\n </IconButton>\n </Show>\n <aside class=\"k2b-settings__rail\">\n <nav\n ref={tabList}\n class=\"k2b-settings__tabs\"\n aria-label={settingsMessages().sectionsLabel({ title: props.title })}\n role=\"tablist\"\n data-scroll-fade-mode=\"both\"\n data-scroll-fade-axis=\"horizontal\"\n >\n <For each={railEntries()}>\n {(entry) =>\n isGroupDefinition(entry) ? (\n <div class=\"k2b-settings__tab-group\" role=\"presentation\">\n <span class=\"k2b-settings__tab-group-label k2b-truncate-fade\" aria-hidden=\"true\">\n {entry.props.title}\n </span>\n <For each={collectTabs(entry.resolved())}>{(tab) => TabButton(tab)}</For>\n </div>\n ) : (\n TabButton(entry)\n )\n }\n </For>\n </nav>\n </aside>\n <div class=\"k2b-settings__content\">\n <Show when={activeTab()}>\n {(tab) => (\n <section\n id={panelId(tab().props.id)}\n class=\"k2b-settings__body\"\n role=\"tabpanel\"\n aria-labelledby={tabId(tab().props.id)}\n tabIndex={0}\n data-tone={tab().props.tone ?? \"default\"}\n >\n <div class=\"k2b-settings__section\">\n <div class=\"k2b-settings__section-heading\">\n <h2>{tab().props.title}</h2>\n <Show when={tab().props.description}>{(description) => <p>{description()}</p>}</Show>\n </div>\n {panelChildren().content}\n </div>\n </section>\n )}\n </Show>\n <Show when={panelChildren().footer}>{(footer) => <footer class=\"k2b-settings__footer\">{footer().props.children}</footer>}</Show>\n </div>\n </div>\n );\n}) as SettingsModalComponent;\n\nSettingsModal.Tab = SettingsModalTab;\nSettingsModal.Group = SettingsModalGroup;\nSettingsModal.Footer = SettingsModalFooter;\n\nexport default SettingsModal;\n"],"mappings":"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","ignoreList":[]}
@@ -27,17 +27,20 @@ var _tmpl$ = ["<div class=\"k2b-ste-size-picker\">", "", "</div>"],
27
27
  import { history, historyKeymap, redo, undo } from "@codemirror/commands";
28
28
  import { EditorView, keymap } from "@codemirror/view";
29
29
  import { clipboard } from "@k2b/stdlib/solid";
30
- import { createEffect, createSignal, createUniqueId, For, onCleanup, onMount, Show, untrack } from "solid-js";
30
+ import { children, createEffect, createMemo, createSignal, createUniqueId, For, on, onCleanup, onMount, Show, untrack } from "solid-js";
31
31
  import { Button, IconButton } from "../actions/Button";
32
32
  import { Dropdown } from "../actions/Dropdown";
33
33
  import { SegmentedControl } from "../actions/SegmentedControl";
34
34
  import { Toolbar } from "../actions/Toolbar";
35
35
  import { Kbd } from "../content/Kbd";
36
36
  import { dialogCore } from "../feedback/dialog-core";
37
+ import { createDictation } from "../inputs/dictation/create-dictation";
38
+ import { DictationBar, DictationButton, dictationBarShown } from "../inputs/dictation/Dictation";
37
39
  import { NumberInput } from "../inputs/NumberInput";
38
40
  import { LocaleProvider, useLocale } from "../intl/locale";
39
41
  import { formatShortcut, keyboardPlatform } from "../intl/shortcut";
40
42
  import BottomSheet, { bottomSheetAdaptiveOptions } from "../layout/BottomSheet";
43
+ import { codeMirrorDictationTarget, dictationExtension } from "./dictation";
41
44
  import { createTextEditor } from "./engine";
42
45
  import { commands, formatLabels } from "./format";
43
46
  import { findTables, inspectTableStructure } from "./markdown-table";
@@ -266,6 +269,7 @@ export function TextEditor(props) {
266
269
  const locale = useLocale();
267
270
  const t = () => textEditorMessages.resolve([locale()]).t;
268
271
  const [mode, setMode] = createSignal(props.mode ?? "formatted");
272
+ const status = children(() => props.status);
269
273
  const [ready, setReady] = createSignal(false);
270
274
  const [recovery, setRecovery] = createSignal();
271
275
  const [notice, setNotice] = createSignal();
@@ -372,6 +376,26 @@ export function TextEditor(props) {
372
376
  let root;
373
377
  let mount;
374
378
  let editor;
379
+ // The view is read-only while it loads or recovers, too; dictation only runs where words can land.
380
+ const dictationWritable = () => !props.readOnly && !props.loading && ready() && recovery() === undefined && mode() !== "plain";
381
+ const dictation = createDictation({
382
+ source: {
383
+ start: options => props.dictation.source.start(options),
384
+ devices: () => props.dictation?.source.devices() ?? Promise.resolve([])
385
+ },
386
+ get alternative() {
387
+ return props.dictation?.alternative;
388
+ },
389
+ target: codeMirrorDictationTarget(() => editor?.view),
390
+ disabled: () => !props.dictation || !dictationWritable()
391
+ });
392
+ // A field that turns read-only or plain hides the toolbar; dictation then ends and the words so far stay.
393
+ // A memo compares the value, so ordinary edits never end it.
394
+ const dictationScope = createMemo(() => `${Boolean(props.dictation)}:${dictationWritable()}`);
395
+ createEffect(on(dictationScope, () => dictation.end(), {
396
+ defer: true
397
+ }));
398
+ const dictating = () => Boolean(props.dictation) && dictationBarShown(dictation);
375
399
  const menuBlocked = () => !!props.loading || !ready() || recovery() !== undefined;
376
400
  const blocked = () => !!props.readOnly || menuBlocked();
377
401
  const updateCheck = () => {
@@ -847,7 +871,8 @@ export function TextEditor(props) {
847
871
  }
848
872
  });
849
873
  const selectMode = next => {
850
- const restoreEditorFocus = !!editor?.view.contentDOM.contains(document.activeElement);
874
+ // Returning from the source view removes its switch; keyboard focus then moves into the text.
875
+ const restoreEditorFocus = !!editor?.view.contentDOM.contains(document.activeElement) || !!root.querySelector(".k2b-ste-views")?.contains(document.activeElement);
851
876
  menuOpen = false;
852
877
  setCell(undefined);
853
878
  setMode(next);
@@ -879,7 +904,7 @@ export function TextEditor(props) {
879
904
  }), EditorView.updateListener.of(update => {
880
905
  schedulePosition();
881
906
  if (update.docChanged) queueMicrotask(() => setDocumentRevision(revision => revision + 1));
882
- }), props.extensions ?? []],
907
+ }), props.extensions ?? [], props.dictation ? dictationExtension() : []],
883
908
  host: {
884
909
  ...props.host,
885
910
  undo: props.host?.undo ?? (() => editor && undo(editor.view)),
@@ -1083,10 +1108,10 @@ export function TextEditor(props) {
1083
1108
  });
1084
1109
  return _$ssr(_tmpl$15, `k2b-text-editor ${_$escape(props.class ?? "", true)}`, _$ssrAttribute("data-mode", _$escape(mode(), true), false) + _$ssrAttribute("data-readonly", props.readOnly ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-active", active() ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("aria-busy", _$escape(props.loading || !ready(), true), false), _$escape(announcement()), _$escape(_$createComponent(Show, {
1085
1110
  get when() {
1086
- return !props.presentation || "status" in props || check();
1111
+ return _$memo(() => !!(status() !== undefined && status() !== null))() && status() !== false || check();
1087
1112
  },
1088
1113
  get children() {
1089
- return _$ssr(_tmpl$10, _$escape(props.status), _$escape(_$createComponent(Show, {
1114
+ return _$ssr(_tmpl$10, _$escape(status()), _$escape(_$createComponent(Show, {
1090
1115
  get when() {
1091
1116
  return check();
1092
1117
  },
@@ -1132,9 +1157,18 @@ export function TextEditor(props) {
1132
1157
  return t().formatting;
1133
1158
  },
1134
1159
  get children() {
1135
- return [_$createComponent(For, {
1160
+ return [_$createComponent(Show, {
1161
+ get when() {
1162
+ return dictating();
1163
+ },
1164
+ get children() {
1165
+ return _$createComponent(DictationBar, {
1166
+ dictation: dictation
1167
+ });
1168
+ }
1169
+ }), _$createComponent(For, {
1136
1170
  get each() {
1137
- return [toolbar.slice(0, 3), toolbar.slice(3, 6), toolbar.slice(6)];
1171
+ return _$memo(() => !!dictating())() ? [] : [toolbar.slice(0, 3), toolbar.slice(3, 6), toolbar.slice(6)];
1138
1172
  },
1139
1173
  children: group => _$createComponent(Toolbar.Group, {
1140
1174
  "class": "k2b-ste-tool-group",
@@ -1176,27 +1210,42 @@ export function TextEditor(props) {
1176
1210
  });
1177
1211
  }
1178
1212
  })
1179
- }), _$createComponent(SegmentedControl, {
1180
- "class": "k2b-ste-views",
1181
- size: "sm",
1182
- get ariaLabel() {
1183
- return t().view;
1184
- },
1185
- get value() {
1186
- return mode() === "source" ? "source" : "formatted";
1213
+ }), _$createComponent(Show, {
1214
+ get when() {
1215
+ return _$memo(() => mode() === "source")() && !dictating();
1187
1216
  },
1188
- get options() {
1189
- return [{
1190
- value: "formatted",
1191
- label: t().formatted,
1192
- icon: "ti ti-typography"
1193
- }, {
1217
+ get children() {
1218
+ return _$createComponent(SegmentedControl, {
1219
+ "class": "k2b-ste-views",
1220
+ size: "sm",
1221
+ get ariaLabel() {
1222
+ return t().view;
1223
+ },
1194
1224
  value: "source",
1195
- label: t().source,
1196
- icon: "ti ti-markdown"
1197
- }];
1225
+ get options() {
1226
+ return [{
1227
+ value: "formatted",
1228
+ label: t().formatted,
1229
+ icon: "ti ti-typography"
1230
+ }, {
1231
+ value: "source",
1232
+ label: t().source,
1233
+ icon: "ti ti-markdown"
1234
+ }];
1235
+ },
1236
+ onValueChange: selectMode
1237
+ });
1238
+ }
1239
+ }), _$createComponent(Show, {
1240
+ get when() {
1241
+ return _$memo(() => !!props.dictation)() && !dictating();
1198
1242
  },
1199
- onValueChange: selectMode
1243
+ get children() {
1244
+ return _$createComponent(DictationButton, {
1245
+ dictation: dictation,
1246
+ "class": "k2b-ste-tool k2b-ste-dictate"
1247
+ });
1248
+ }
1200
1249
  })];
1201
1250
  }
1202
1251
  })));