@k2b/ui 0.44.0 → 0.46.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 (206) hide show
  1. package/dist/browser/actions/Dropdown.js +8 -1
  2. package/dist/browser/actions/Dropdown.js.map +1 -1
  3. package/dist/browser/actions/FilterChip.js +11 -5
  4. package/dist/browser/actions/FilterChip.js.map +1 -1
  5. package/dist/browser/actions/Tabs.js +3 -4
  6. package/dist/browser/actions/Tabs.js.map +1 -1
  7. package/dist/browser/actions/ViewTabs.js +225 -93
  8. package/dist/browser/actions/ViewTabs.js.map +1 -1
  9. package/dist/browser/actions/menu-sheet.js +2 -3
  10. package/dist/browser/actions/menu-sheet.js.map +1 -1
  11. package/dist/browser/actions/phone-sheet.js +4 -0
  12. package/dist/browser/actions/phone-sheet.js.map +1 -0
  13. package/dist/browser/content/DataTable.js +47 -51
  14. package/dist/browser/content/DataTable.js.map +1 -1
  15. package/dist/browser/content/FileGrid.js +125 -99
  16. package/dist/browser/content/FileGrid.js.map +1 -1
  17. package/dist/browser/feedback/dialog-core.js +5 -1
  18. package/dist/browser/feedback/dialog-core.js.map +1 -1
  19. package/dist/browser/feedback/dialog-tone.js +26 -0
  20. package/dist/browser/feedback/dialog-tone.js.map +1 -0
  21. package/dist/browser/feedback/index.js.map +1 -1
  22. package/dist/browser/feedback/prompt-confirm.js +223 -0
  23. package/dist/browser/feedback/prompt-confirm.js.map +1 -0
  24. package/dist/browser/feedback/prompts.js +195 -343
  25. package/dist/browser/feedback/prompts.js.map +1 -1
  26. package/dist/browser/inputs/ChoiceList.js +45 -17
  27. package/dist/browser/inputs/ChoiceList.js.map +1 -1
  28. package/dist/browser/inputs/DatePicker.js +1647 -334
  29. package/dist/browser/inputs/DatePicker.js.map +1 -1
  30. package/dist/browser/inputs/TextInput.js +5 -4
  31. package/dist/browser/inputs/TextInput.js.map +1 -1
  32. package/dist/browser/inputs/choice.js +36 -9
  33. package/dist/browser/inputs/choice.js.map +1 -1
  34. package/dist/browser/inputs/date-input-messages.js +128 -0
  35. package/dist/browser/inputs/date-input-messages.js.map +1 -0
  36. package/dist/browser/inputs/date-input-status.js +132 -0
  37. package/dist/browser/inputs/date-input-status.js.map +1 -0
  38. package/dist/browser/inputs/date-input.js +334 -0
  39. package/dist/browser/inputs/date-input.js.map +1 -0
  40. package/dist/browser/inputs/date-sheet.js +49 -0
  41. package/dist/browser/inputs/date-sheet.js.map +1 -0
  42. package/dist/browser/internal/reveal-in-scroller.js +28 -0
  43. package/dist/browser/internal/reveal-in-scroller.js.map +1 -0
  44. package/dist/browser/intl/messages.js +6 -0
  45. package/dist/browser/intl/messages.js.map +1 -1
  46. package/dist/browser/layout/AppWorkspace.js +556 -528
  47. package/dist/browser/layout/AppWorkspace.js.map +1 -1
  48. package/dist/browser/layout/BottomSheet.js +3 -0
  49. package/dist/browser/layout/BottomSheet.js.map +1 -1
  50. package/dist/browser/layout/DetailPanel.js +130 -108
  51. package/dist/browser/layout/DetailPanel.js.map +1 -1
  52. package/dist/browser/layout/DetailSections.js +1019 -0
  53. package/dist/browser/layout/DetailSections.js.map +1 -0
  54. package/dist/browser/layout/DetailsToggle.js +32 -0
  55. package/dist/browser/layout/DetailsToggle.js.map +1 -0
  56. package/dist/browser/layout/Discussion.js +3 -0
  57. package/dist/browser/layout/Discussion.js.map +1 -1
  58. package/dist/browser/layout/MobileShell.js +116 -94
  59. package/dist/browser/layout/MobileShell.js.map +1 -1
  60. package/dist/browser/layout/PageTitle.js +33 -10
  61. package/dist/browser/layout/PageTitle.js.map +1 -1
  62. package/dist/browser/layout/PanelDialog.js +167 -132
  63. package/dist/browser/layout/PanelDialog.js.map +1 -1
  64. package/dist/browser/layout/Settings.js +175 -139
  65. package/dist/browser/layout/Settings.js.map +1 -1
  66. package/dist/browser/layout/SettingsModal.js +2 -4
  67. package/dist/browser/layout/SettingsModal.js.map +1 -1
  68. package/dist/browser/layout/app-workspace-controller.js +12 -0
  69. package/dist/browser/layout/app-workspace-controller.js.map +1 -1
  70. package/dist/browser/layout/detail-sections-messages.js +123 -0
  71. package/dist/browser/layout/detail-sections-messages.js.map +1 -0
  72. package/dist/browser/layout/index.js +2 -0
  73. package/dist/browser/layout/index.js.map +1 -1
  74. package/dist/browser/surfaces/Avatar.js +3 -1
  75. package/dist/browser/surfaces/Avatar.js.map +1 -1
  76. package/dist/browser/surfaces/AvatarStack.js +95 -61
  77. package/dist/browser/surfaces/AvatarStack.js.map +1 -1
  78. package/dist/browser/surfaces/ChangeList.js +77 -0
  79. package/dist/browser/surfaces/ChangeList.js.map +1 -0
  80. package/dist/browser/surfaces/StatusBadge.js +47 -14
  81. package/dist/browser/surfaces/StatusBadge.js.map +1 -1
  82. package/dist/browser/surfaces/index.js +2 -1
  83. package/dist/browser/surfaces/index.js.map +1 -1
  84. package/dist/browser/text-editor/TextEditor.js +26 -8
  85. package/dist/browser/text-editor/TextEditor.js.map +1 -1
  86. package/dist/ssr/actions/Dropdown.js +6 -0
  87. package/dist/ssr/actions/Dropdown.js.map +1 -1
  88. package/dist/ssr/actions/FilterChip.js +1 -1
  89. package/dist/ssr/actions/FilterChip.js.map +1 -1
  90. package/dist/ssr/actions/Tabs.js +3 -4
  91. package/dist/ssr/actions/Tabs.js.map +1 -1
  92. package/dist/ssr/actions/ViewTabs.js +144 -37
  93. package/dist/ssr/actions/ViewTabs.js.map +1 -1
  94. package/dist/ssr/actions/menu-sheet.js +2 -3
  95. package/dist/ssr/actions/menu-sheet.js.map +1 -1
  96. package/dist/ssr/actions/phone-sheet.js +4 -0
  97. package/dist/ssr/actions/phone-sheet.js.map +1 -0
  98. package/dist/ssr/content/DataTable.js +1 -2
  99. package/dist/ssr/content/DataTable.js.map +1 -1
  100. package/dist/ssr/content/FileGrid.js +36 -22
  101. package/dist/ssr/content/FileGrid.js.map +1 -1
  102. package/dist/ssr/feedback/dialog-core.js +5 -1
  103. package/dist/ssr/feedback/dialog-core.js.map +1 -1
  104. package/dist/ssr/feedback/dialog-tone.js +26 -0
  105. package/dist/ssr/feedback/dialog-tone.js.map +1 -0
  106. package/dist/ssr/feedback/index.js.map +1 -1
  107. package/dist/ssr/feedback/prompt-confirm.js +123 -0
  108. package/dist/ssr/feedback/prompt-confirm.js.map +1 -0
  109. package/dist/ssr/feedback/prompts.js +60 -132
  110. package/dist/ssr/feedback/prompts.js.map +1 -1
  111. package/dist/ssr/inputs/ChoiceList.js +29 -9
  112. package/dist/ssr/inputs/ChoiceList.js.map +1 -1
  113. package/dist/ssr/inputs/DatePicker.js +1183 -166
  114. package/dist/ssr/inputs/DatePicker.js.map +1 -1
  115. package/dist/ssr/inputs/TextInput.js +5 -4
  116. package/dist/ssr/inputs/TextInput.js.map +1 -1
  117. package/dist/ssr/inputs/choice.js +36 -9
  118. package/dist/ssr/inputs/choice.js.map +1 -1
  119. package/dist/ssr/inputs/date-input-messages.js +128 -0
  120. package/dist/ssr/inputs/date-input-messages.js.map +1 -0
  121. package/dist/ssr/inputs/date-input-status.js +132 -0
  122. package/dist/ssr/inputs/date-input-status.js.map +1 -0
  123. package/dist/ssr/inputs/date-input.js +334 -0
  124. package/dist/ssr/inputs/date-input.js.map +1 -0
  125. package/dist/ssr/inputs/date-sheet.js +44 -0
  126. package/dist/ssr/inputs/date-sheet.js.map +1 -0
  127. package/dist/ssr/internal/reveal-in-scroller.js +28 -0
  128. package/dist/ssr/internal/reveal-in-scroller.js.map +1 -0
  129. package/dist/ssr/intl/messages.js +6 -0
  130. package/dist/ssr/intl/messages.js.map +1 -1
  131. package/dist/ssr/layout/AppWorkspace.js +71 -50
  132. package/dist/ssr/layout/AppWorkspace.js.map +1 -1
  133. package/dist/ssr/layout/BottomSheet.js +3 -0
  134. package/dist/ssr/layout/BottomSheet.js.map +1 -1
  135. package/dist/ssr/layout/DetailPanel.js +17 -0
  136. package/dist/ssr/layout/DetailPanel.js.map +1 -1
  137. package/dist/ssr/layout/DetailSections.js +762 -0
  138. package/dist/ssr/layout/DetailSections.js.map +1 -0
  139. package/dist/ssr/layout/DetailsToggle.js +29 -0
  140. package/dist/ssr/layout/DetailsToggle.js.map +1 -0
  141. package/dist/ssr/layout/Discussion.js +3 -0
  142. package/dist/ssr/layout/Discussion.js.map +1 -1
  143. package/dist/ssr/layout/MobileShell.js +45 -28
  144. package/dist/ssr/layout/MobileShell.js.map +1 -1
  145. package/dist/ssr/layout/PageTitle.js +29 -6
  146. package/dist/ssr/layout/PageTitle.js.map +1 -1
  147. package/dist/ssr/layout/PanelDialog.js +48 -30
  148. package/dist/ssr/layout/PanelDialog.js.map +1 -1
  149. package/dist/ssr/layout/Settings.js +34 -18
  150. package/dist/ssr/layout/Settings.js.map +1 -1
  151. package/dist/ssr/layout/SettingsModal.js +2 -4
  152. package/dist/ssr/layout/SettingsModal.js.map +1 -1
  153. package/dist/ssr/layout/app-workspace-controller.js +12 -0
  154. package/dist/ssr/layout/app-workspace-controller.js.map +1 -1
  155. package/dist/ssr/layout/detail-sections-messages.js +123 -0
  156. package/dist/ssr/layout/detail-sections-messages.js.map +1 -0
  157. package/dist/ssr/layout/index.js +2 -0
  158. package/dist/ssr/layout/index.js.map +1 -1
  159. package/dist/ssr/surfaces/Avatar.js +3 -1
  160. package/dist/ssr/surfaces/Avatar.js.map +1 -1
  161. package/dist/ssr/surfaces/AvatarStack.js +61 -32
  162. package/dist/ssr/surfaces/AvatarStack.js.map +1 -1
  163. package/dist/ssr/surfaces/ChangeList.js +37 -0
  164. package/dist/ssr/surfaces/ChangeList.js.map +1 -0
  165. package/dist/ssr/surfaces/StatusBadge.js +26 -8
  166. package/dist/ssr/surfaces/StatusBadge.js.map +1 -1
  167. package/dist/ssr/surfaces/index.js +2 -1
  168. package/dist/ssr/surfaces/index.js.map +1 -1
  169. package/dist/ssr/text-editor/TextEditor.js +26 -8
  170. package/dist/ssr/text-editor/TextEditor.js.map +1 -1
  171. package/dist/styles.css +1 -1
  172. package/dist/types/actions/FilterChip.d.ts +4 -0
  173. package/dist/types/actions/ViewTabs.d.ts +11 -1
  174. package/dist/types/actions/menu-sheet.d.ts +1 -3
  175. package/dist/types/actions/phone-sheet.d.ts +3 -0
  176. package/dist/types/content/FileGrid.d.ts +6 -0
  177. package/dist/types/feedback/dialog-tone.d.ts +10 -0
  178. package/dist/types/feedback/index.d.ts +1 -0
  179. package/dist/types/feedback/prompt-confirm.d.ts +19 -0
  180. package/dist/types/feedback/prompts.d.ts +4 -8
  181. package/dist/types/inputs/ChoiceList.d.ts +7 -3
  182. package/dist/types/inputs/DatePicker.d.ts +13 -3
  183. package/dist/types/inputs/TextInput.d.ts +1 -1
  184. package/dist/types/inputs/choice.d.ts +9 -3
  185. package/dist/types/inputs/date-input-messages.d.ts +64 -0
  186. package/dist/types/inputs/date-input-status.d.ts +35 -0
  187. package/dist/types/inputs/date-input.d.ts +90 -0
  188. package/dist/types/inputs/date-sheet.d.ts +14 -0
  189. package/dist/types/internal/reveal-in-scroller.d.ts +6 -0
  190. package/dist/types/intl/messages.d.ts +3 -0
  191. package/dist/types/layout/AppWorkspace.d.ts +14 -0
  192. package/dist/types/layout/BottomSheet.d.ts +3 -0
  193. package/dist/types/layout/DetailPanel.d.ts +9 -0
  194. package/dist/types/layout/DetailSections.d.ts +156 -0
  195. package/dist/types/layout/DetailsToggle.d.ts +13 -0
  196. package/dist/types/layout/PageTitle.d.ts +7 -0
  197. package/dist/types/layout/PanelDialog.d.ts +3 -0
  198. package/dist/types/layout/Settings.d.ts +17 -1
  199. package/dist/types/layout/detail-sections-messages.d.ts +59 -0
  200. package/dist/types/layout/index.d.ts +5 -2
  201. package/dist/types/surfaces/Avatar.d.ts +3 -0
  202. package/dist/types/surfaces/AvatarStack.d.ts +20 -1
  203. package/dist/types/surfaces/ChangeList.d.ts +20 -0
  204. package/dist/types/surfaces/StatusBadge.d.ts +5 -0
  205. package/dist/types/surfaces/index.d.ts +5 -3
  206. package/package.json +3 -3
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["layout/Settings.tsx"],"sourcesContent":["import { children, createMemo, createUniqueId, type JSX, Show } from \"solid-js\";\nimport { Button, type ButtonVariant } from \"../actions/Button\";\nimport { usePromptMessages } from \"../feedback/prompt-messages\";\nimport type { MaybeAccessor } from \"../inputs/field-contract\";\nimport { useSettingsMessages } from \"./settings-messages\";\n\nconst read = <T,>(value: MaybeAccessor<T>): T => (typeof value === \"function\" ? (value as () => T)() : value);\n\nexport type SettingsPageProps = {\n title: JSX.Element;\n /** False when a surrounding head already shows the title, such as a workspace level; the actions move to the footer. */\n header?: boolean;\n subtitle?: JSX.Element;\n icon?: string;\n actions?: JSX.Element;\n children: JSX.Element;\n footer?: JSX.Element;\n scrollPreserveKey?: string;\n class?: string;\n style?: JSX.CSSProperties | string;\n};\n\nexport function SettingsPage(props: SettingsPageProps): JSX.Element {\n return (\n <section\n class={`k2b-settings-page${props.class ? ` ${props.class}` : \"\"}`}\n style={props.style}\n aria-label={props.header === false && typeof props.title === \"string\" ? props.title : undefined}\n >\n <Show when={props.header !== false}>\n <header class=\"k2b-settings-page__header\">\n <Show when={props.icon}>{(icon) => <i class={icon()} aria-hidden=\"true\" />}</Show>\n <div class=\"k2b-settings-page__heading\">\n <h1>{props.title}</h1>\n <Show when={props.subtitle}>\n <p>{props.subtitle}</p>\n </Show>\n </div>\n <Show when={props.actions}>\n <div class=\"k2b-settings-page__actions\">{props.actions}</div>\n </Show>\n </header>\n </Show>\n <div class=\"k2b-settings-page__body\" data-scroll-preserve={props.scrollPreserveKey}>\n {props.children}\n </div>\n <Show when={props.footer}>\n <footer class=\"k2b-settings-page__footer\">{props.footer}</footer>\n </Show>\n </section>\n );\n}\n\nexport type SettingsSectionProps = {\n title: JSX.Element;\n subtitle?: JSX.Element;\n icon?: string;\n actions?: JSX.Element;\n children: JSX.Element;\n class?: string;\n};\n\n/**\n * A full-page settings group: a heading, optional actions and its fields on the\n * page surface without a card. Dialogs keep using PanelDialog.Section.\n */\nexport function SettingsSection(props: SettingsSectionProps): JSX.Element {\n const headingId = `k2b-settings-section-${createUniqueId()}`;\n return (\n <section class={`k2b-settings-section${props.class ? ` ${props.class}` : \"\"}`} aria-labelledby={headingId}>\n <header class=\"k2b-settings-section__header\">\n <Show when={props.icon}>{(icon) => <i class={icon()} aria-hidden=\"true\" />}</Show>\n <div class=\"k2b-settings-section__heading\">\n <h2 id={headingId}>{props.title}</h2>\n <Show when={props.subtitle}>\n <p>{props.subtitle}</p>\n </Show>\n </div>\n <Show when={props.actions}>\n <div class=\"k2b-settings-section__actions\">{props.actions}</div>\n </Show>\n </header>\n <div class=\"k2b-settings-section__body\">{props.children}</div>\n </section>\n );\n}\n\nconst SETTINGS_GROUP_ACTION = Symbol(\"SettingsGroup.Action\");\n\nexport type SettingsGroupProps = {\n title: JSX.Element;\n description?: JSX.Element;\n children: JSX.Element;\n class?: string;\n};\n\nexport type SettingsGroupActionProps = {\n children: JSX.Element;\n};\n\ntype SettingsGroupActionDefinition = {\n readonly kind: typeof SETTINGS_GROUP_ACTION;\n readonly props: SettingsGroupActionProps;\n};\n\ntype SettingsGroupComponent = ((props: SettingsGroupProps) => JSX.Element) & {\n Action: (props: SettingsGroupActionProps) => JSX.Element;\n};\n\nconst SettingsGroupAction = (props: SettingsGroupActionProps): JSX.Element =>\n ({ kind: SETTINGS_GROUP_ACTION, props }) satisfies SettingsGroupActionDefinition as unknown as JSX.Element;\n\nconst collectSettingsGroupActions = (value: unknown): SettingsGroupActionDefinition[] => {\n if (Array.isArray(value)) return value.flatMap(collectSettingsGroupActions);\n return value && typeof value === \"object\" && (value as { kind?: unknown }).kind === SETTINGS_GROUP_ACTION\n ? [value as SettingsGroupActionDefinition]\n : [];\n};\n\nconst collectSettingsGroupContent = (value: unknown): JSX.Element[] => {\n if (Array.isArray(value)) return value.flatMap(collectSettingsGroupContent);\n return value && typeof value === \"object\" && (value as { kind?: unknown }).kind === SETTINGS_GROUP_ACTION ? [] : [value as JSX.Element];\n};\n\nexport const SettingsGroup = ((props: SettingsGroupProps): JSX.Element => {\n const resolved = children(() => props.children);\n const action = createMemo(() => collectSettingsGroupActions(resolved())[0]);\n const content = createMemo(() => collectSettingsGroupContent(resolved()));\n const headingId = `k2b-settings-group-${createUniqueId()}`;\n return (\n <section class={`k2b-settings-group${props.class ? ` ${props.class}` : \"\"}`} aria-labelledby={headingId}>\n <header class=\"k2b-settings-group__header\">\n <div class=\"k2b-settings-group__heading\">\n <h3 id={headingId}>{props.title}</h3>\n <Show when={props.description}>\n <p>{props.description}</p>\n </Show>\n </div>\n <Show when={action()}>{(slot) => <div class=\"k2b-settings-group__action\">{slot().props.children}</div>}</Show>\n </header>\n <div class=\"k2b-settings-group__body\">{content()}</div>\n </section>\n );\n}) as SettingsGroupComponent;\n\nSettingsGroup.Action = SettingsGroupAction;\n\nexport const sameSettingValue = (left: unknown, right: unknown): boolean => JSON.stringify(left) === JSON.stringify(right);\n\nexport const readSettingsError = async (\n response: Pick<Response, \"json\">,\n fallback: string,\n): Promise<{ message: string; fields: Record<string, string> }> => {\n const data = (await response.json().catch(() => null)) as {\n message?: string;\n errors?: Record<string, string>;\n } | null;\n return { message: data?.message ?? fallback, fields: data?.errors ?? {} };\n};\n\nexport type SettingsFieldProps = {\n label: string;\n description: string;\n error: MaybeAccessor<string | undefined>;\n changed?: MaybeAccessor<boolean>;\n children: JSX.Element | ((control: SettingsFieldControlProps) => JSX.Element);\n class?: string;\n};\n\nexport type SettingsFieldControlProps = {\n describedBy: () => string;\n};\n\nexport function SettingsField(props: SettingsFieldProps): JSX.Element {\n const settingsMessages = useSettingsMessages();\n const id = createUniqueId();\n const descriptionId = `k2b-settings-field-${id}-description`;\n const errorId = `k2b-settings-field-${id}-error`;\n const describedBy = () => (read(props.error) ? `${descriptionId} ${errorId}` : descriptionId);\n const control = () =>\n typeof props.children === \"function\"\n ? (props.children as (control: SettingsFieldControlProps) => JSX.Element)({ describedBy })\n : props.children;\n return (\n <div class={`k2b-settings-field ${props.class ?? \"\"}`}>\n <div class=\"k2b-settings-field__copy\">\n <div class=\"k2b-settings-field__heading\">\n <strong>{props.label}</strong>\n <Show when={props.changed !== undefined && read(props.changed)}>\n <span>{settingsMessages().unsaved}</span>\n </Show>\n </div>\n <p id={descriptionId}>{props.description}</p>\n </div>\n {control()}\n <Show when={read(props.error)}>\n {(error) => (\n <p id={errorId} class=\"k2b-settings-field__error\" role=\"alert\">\n <i class=\"ti ti-alert-circle\" aria-hidden=\"true\" /> {error()}\n </p>\n )}\n </Show>\n </div>\n );\n}\n\nexport type SettingsSaveBarProps = {\n changeCount: MaybeAccessor<number>;\n loading: MaybeAccessor<boolean>;\n saveDisabled?: MaybeAccessor<boolean>;\n onDiscard: () => void;\n onSave: () => void;\n saveLabel?: string;\n saveVariant?: ButtonVariant;\n class?: string;\n};\n\nconst SettingsActions = (\n props: SettingsSaveBarProps & {\n disableWithoutChanges?: boolean;\n },\n): JSX.Element => {\n const promptMessages = usePromptMessages();\n const settingsMessages = useSettingsMessages();\n const changeCount = () => read(props.changeCount);\n const loading = () => read(props.loading);\n const disabled = () => loading() || Boolean(props.disableWithoutChanges && changeCount() === 0);\n const saveDisabled = () => disabled() || Boolean(props.saveDisabled !== undefined && read(props.saveDisabled));\n return (\n <div class=\"k2b-settings-actions\">\n <Button variant=\"secondary\" disabled={disabled()} onClick={props.onDiscard}>\n {promptMessages().discard}\n </Button>\n <Button\n variant={props.saveVariant ?? \"primary\"}\n loading={loading()}\n loadingLabel={settingsMessages().saving}\n disabled={saveDisabled()}\n onClick={props.onSave}\n >\n <i class=\"ti ti-device-floppy\" aria-hidden=\"true\" />\n {props.saveLabel ?? settingsMessages().saveChanges}\n </Button>\n </div>\n );\n};\n\nexport function SettingsSaveBar(props: SettingsSaveBarProps): JSX.Element {\n const settingsMessages = useSettingsMessages();\n const changeCount = () => read(props.changeCount);\n return (\n <Show when={changeCount() > 0}>\n <div class={`k2b-settings-save-bar ${props.class ?? \"\"}`}>\n <p role=\"status\" aria-live=\"polite\">\n <strong>{changeCount()}</strong> {settingsMessages().unsavedChangeLabel({ count: changeCount() })}\n </p>\n <SettingsActions {...props} />\n </div>\n </Show>\n );\n}\n\nexport type SettingsPanelFooterProps = SettingsSaveBarProps;\n\nexport function SettingsPanelFooter(props: SettingsPanelFooterProps): JSX.Element {\n const settingsMessages = useSettingsMessages();\n const changeCount = () => read(props.changeCount);\n return (\n <>\n <p class=\"k2b-settings-panel-footer__status\" role=\"status\" aria-live=\"polite\">\n <Show when={changeCount() > 0} fallback={settingsMessages().noUnsavedChanges}>\n <strong>{changeCount()}</strong> {settingsMessages().unsavedChangeLabel({ count: changeCount() })}\n </Show>\n </p>\n <SettingsActions {...props} disableWithoutChanges />\n </>\n );\n}\n\nexport type SaveStatusState = \"saved\" | \"draft\" | \"saving\" | \"failed\" | \"invalid\" | \"unknown\" | \"readonly\";\n\nexport type SaveStatusProps = {\n /** What the person's values are now: saved, a draft with changes, being saved, or a problem that kept them unsaved. */\n state: MaybeAccessor<SaveStatusState>;\n /** Formatted time of the last save, shown with `saved`. */\n savedAt?: MaybeAccessor<string | undefined>;\n /** Fields to check, shown with `invalid`. Default 1. */\n invalidCount?: MaybeAccessor<number>;\n /** With both handlers, Discard and Save follow the status while there is something to save. */\n onDiscard?: () => void;\n onSave?: () => void;\n saveLabel?: string;\n saveDisabled?: MaybeAccessor<boolean>;\n class?: string;\n};\n\nconst SAVE_STATUS_ICON: Record<SaveStatusState, string> = {\n saved: \"ti ti-check\",\n draft: \"ti ti-pencil\",\n saving: \"ti ti-loader-2\",\n failed: \"ti ti-alert-triangle\",\n invalid: \"ti ti-alert-triangle\",\n unknown: \"ti ti-help-circle\",\n readonly: \"ti ti-lock\",\n};\n\n/**\n * The save status of a settings form at one fixed place, usually the head of its column. It reserves its width, so\n * a change of state never moves the title or the buttons beside it. Problems with one field stay at that field.\n */\nexport function SaveStatus(props: SaveStatusProps): JSX.Element {\n const settingsMessages = useSettingsMessages();\n const state = () => read(props.state);\n const text = () => {\n const t = settingsMessages();\n switch (state()) {\n case \"saved\": {\n const at = props.savedAt === undefined ? undefined : read(props.savedAt);\n return at ? t.statusSavedAt({ time: at }) : t.statusSaved;\n }\n case \"draft\":\n return t.statusDraft;\n case \"saving\":\n return t.saving;\n case \"failed\":\n return t.statusFailed;\n case \"invalid\":\n return t.statusInvalid({ count: props.invalidCount === undefined ? 1 : read(props.invalidCount) });\n case \"unknown\":\n return t.statusUnknown;\n case \"readonly\":\n return t.statusReadOnly;\n }\n };\n const hasActions = () => Boolean(props.onSave && props.onDiscard) && state() !== \"readonly\";\n const pending = () => state() === \"draft\" || state() === \"failed\" || state() === \"invalid\" || state() === \"saving\";\n return (\n <div class={`k2b-save-status ${props.class ?? \"\"}`}>\n <span class=\"k2b-save-status__slot\">\n <span class=\"k2b-save-status__state\" data-state={state()} role=\"status\" aria-live=\"polite\">\n <i class={`${SAVE_STATUS_ICON[state()]}${state() === \"saving\" ? \" k2b-spin\" : \"\"}`} aria-hidden=\"true\" />\n {text()}\n </span>\n </span>\n <Show when={hasActions()}>\n <SettingsActions\n changeCount={() => (pending() ? 1 : 0)}\n loading={() => state() === \"saving\"}\n saveDisabled={() => state() === \"invalid\" || Boolean(props.saveDisabled !== undefined && read(props.saveDisabled))}\n onDiscard={props.onDiscard!}\n onSave={props.onSave!}\n saveLabel={props.saveLabel ?? settingsMessages().save}\n disableWithoutChanges\n />\n </Show>\n </div>\n );\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["layout/Settings.tsx"],"sourcesContent":["import { children, createMemo, createUniqueId, type JSX, Show } from \"solid-js\";\nimport { Button, type ButtonVariant } from \"../actions/Button\";\nimport { usePromptMessages } from \"../feedback/prompt-messages\";\nimport type { MaybeAccessor } from \"../inputs/field-contract\";\nimport { useSettingsMessages } from \"./settings-messages\";\n\nconst read = <T,>(value: MaybeAccessor<T>): T => (typeof value === \"function\" ? (value as () => T)() : value);\n\nexport type SettingsPageProps = {\n title: JSX.Element;\n /** False when a surrounding head already shows the title, such as a workspace level; the actions move to the footer. */\n header?: boolean;\n subtitle?: JSX.Element;\n icon?: string;\n actions?: JSX.Element;\n children: JSX.Element;\n footer?: JSX.Element;\n scrollPreserveKey?: string;\n class?: string;\n style?: JSX.CSSProperties | string;\n};\n\nexport function SettingsPage(props: SettingsPageProps): JSX.Element {\n return (\n <section\n class={`k2b-settings-page${props.class ? ` ${props.class}` : \"\"}`}\n style={props.style}\n aria-label={props.header === false && typeof props.title === \"string\" ? props.title : undefined}\n >\n <Show when={props.header !== false}>\n <header class=\"k2b-settings-page__header\">\n <Show when={props.icon}>{(icon) => <i class={icon()} aria-hidden=\"true\" />}</Show>\n <div class=\"k2b-settings-page__heading\">\n <h1>{props.title}</h1>\n <Show when={props.subtitle}>\n <p>{props.subtitle}</p>\n </Show>\n </div>\n <Show when={props.actions}>\n <div class=\"k2b-settings-page__actions\">{props.actions}</div>\n </Show>\n </header>\n </Show>\n <div class=\"k2b-settings-page__body\" data-scroll-preserve={props.scrollPreserveKey}>\n {props.children}\n </div>\n <Show when={props.footer}>\n <footer class=\"k2b-settings-page__footer\">{props.footer}</footer>\n </Show>\n </section>\n );\n}\n\nexport type SettingsSectionProps = {\n title: JSX.Element;\n subtitle?: JSX.Element;\n icon?: string;\n actions?: JSX.Element;\n children: JSX.Element;\n class?: string;\n};\n\n/**\n * A full-page settings group: a heading, optional actions and its fields on the\n * page surface without a card. From 860 px of its own width the heading takes a\n * column beside the fields. Dialogs keep using PanelDialog.Section.\n */\nexport function SettingsSection(props: SettingsSectionProps): JSX.Element {\n const headingId = `k2b-settings-section-${createUniqueId()}`;\n return (\n <section class={`k2b-settings-section${props.class ? ` ${props.class}` : \"\"}`} aria-labelledby={headingId}>\n <div class=\"k2b-settings-section__layout\">\n <header class=\"k2b-settings-section__header\">\n <Show when={props.icon}>{(icon) => <i class={icon()} aria-hidden=\"true\" />}</Show>\n <div class=\"k2b-settings-section__heading\">\n <h2 id={headingId}>{props.title}</h2>\n <Show when={props.subtitle}>\n <p>{props.subtitle}</p>\n </Show>\n </div>\n <Show when={props.actions}>\n <div class=\"k2b-settings-section__actions\">{props.actions}</div>\n </Show>\n </header>\n <div class=\"k2b-settings-section__body\">{props.children}</div>\n </div>\n </section>\n );\n}\n\nconst SETTINGS_GROUP_ACTION = Symbol(\"SettingsGroup.Action\");\n\nexport type SettingsGroupProps = {\n title: JSX.Element;\n description?: JSX.Element;\n children: JSX.Element;\n class?: string;\n};\n\nexport type SettingsGroupActionProps = {\n children: JSX.Element;\n};\n\ntype SettingsGroupActionDefinition = {\n readonly kind: typeof SETTINGS_GROUP_ACTION;\n readonly props: SettingsGroupActionProps;\n};\n\ntype SettingsGroupComponent = ((props: SettingsGroupProps) => JSX.Element) & {\n Action: (props: SettingsGroupActionProps) => JSX.Element;\n};\n\nconst SettingsGroupAction = (props: SettingsGroupActionProps): JSX.Element =>\n ({ kind: SETTINGS_GROUP_ACTION, props }) satisfies SettingsGroupActionDefinition as unknown as JSX.Element;\n\nconst collectSettingsGroupActions = (value: unknown): SettingsGroupActionDefinition[] => {\n if (Array.isArray(value)) return value.flatMap(collectSettingsGroupActions);\n return value && typeof value === \"object\" && (value as { kind?: unknown }).kind === SETTINGS_GROUP_ACTION\n ? [value as SettingsGroupActionDefinition]\n : [];\n};\n\nconst collectSettingsGroupContent = (value: unknown): JSX.Element[] => {\n if (Array.isArray(value)) return value.flatMap(collectSettingsGroupContent);\n return value && typeof value === \"object\" && (value as { kind?: unknown }).kind === SETTINGS_GROUP_ACTION ? [] : [value as JSX.Element];\n};\n\nexport const SettingsGroup = ((props: SettingsGroupProps): JSX.Element => {\n const resolved = children(() => props.children);\n const action = createMemo(() => collectSettingsGroupActions(resolved())[0]);\n const content = createMemo(() => collectSettingsGroupContent(resolved()));\n const headingId = `k2b-settings-group-${createUniqueId()}`;\n return (\n <section class={`k2b-settings-group${props.class ? ` ${props.class}` : \"\"}`} aria-labelledby={headingId}>\n <header class=\"k2b-settings-group__header\">\n <div class=\"k2b-settings-group__heading\">\n <h3 id={headingId}>{props.title}</h3>\n <Show when={props.description}>\n <p>{props.description}</p>\n </Show>\n </div>\n <Show when={action()}>{(slot) => <div class=\"k2b-settings-group__action\">{slot().props.children}</div>}</Show>\n </header>\n <div class=\"k2b-settings-group__body\">{content()}</div>\n </section>\n );\n}) as SettingsGroupComponent;\n\nSettingsGroup.Action = SettingsGroupAction;\n\nexport const sameSettingValue = (left: unknown, right: unknown): boolean => JSON.stringify(left) === JSON.stringify(right);\n\nexport const readSettingsError = async (\n response: Pick<Response, \"json\">,\n fallback: string,\n): Promise<{ message: string; fields: Record<string, string> }> => {\n const data = (await response.json().catch(() => null)) as {\n message?: string;\n errors?: Record<string, string>;\n } | null;\n return { message: data?.message ?? fallback, fields: data?.errors ?? {} };\n};\n\n/**\n * The room a setting's control takes: `short` for a number, `medium` for a choice, `long` for text, and `full` for\n * an editor, which keeps its name above it and takes the whole row.\n */\nexport type SettingsFieldWidth = \"short\" | \"medium\" | \"long\" | \"full\";\n\nexport type SettingsFieldProps = {\n label: string;\n /** One sentence of help; longer guidance belongs in the page's guide. */\n description: string;\n error: MaybeAccessor<string | undefined>;\n changed?: MaybeAccessor<boolean>;\n /**\n * Where the value comes from, at a fixed place after the control: quiet text such as \"Default\", or the one way\n * back to it, such as a Reset button that only a value of its own shows.\n */\n source?: JSX.Element;\n /** The control's width by kind, so a number never stretches like a URL. Defaults to `long`, the full column. */\n width?: SettingsFieldWidth;\n /** The row's id, for a link that leads to this one setting. */\n id?: string;\n children: JSX.Element | ((control: SettingsFieldControlProps) => JSX.Element);\n class?: string;\n};\n\nexport type SettingsFieldControlProps = {\n describedBy: () => string;\n};\n\nexport function SettingsField(props: SettingsFieldProps): JSX.Element {\n const settingsMessages = useSettingsMessages();\n const id = createUniqueId();\n const descriptionId = `k2b-settings-field-${id}-description`;\n const errorId = `k2b-settings-field-${id}-error`;\n const describedBy = () => (read(props.error) ? `${descriptionId} ${errorId}` : descriptionId);\n const control = () =>\n typeof props.children === \"function\"\n ? (props.children as (control: SettingsFieldControlProps) => JSX.Element)({ describedBy })\n : props.children;\n const source = children(() => props.source);\n return (\n <div id={props.id} class={`k2b-settings-field ${props.class ?? \"\"}`} data-width={props.width ?? \"long\"}>\n <div class=\"k2b-settings-field__row\">\n <div class=\"k2b-settings-field__copy\">\n <div class=\"k2b-settings-field__heading\">\n <strong>{props.label}</strong>\n <Show when={props.changed !== undefined && read(props.changed)}>\n <span>{settingsMessages().unsaved}</span>\n </Show>\n </div>\n <p id={descriptionId}>{props.description}</p>\n </div>\n <div class=\"k2b-settings-field__control\">\n {control()}\n <Show when={read(props.error)}>\n {(error) => (\n <p id={errorId} class=\"k2b-settings-field__error\" role=\"alert\">\n <i class=\"ti ti-alert-circle\" aria-hidden=\"true\" /> {error()}\n </p>\n )}\n </Show>\n </div>\n <Show when={source()}>\n <div class=\"k2b-settings-field__source\">{source()}</div>\n </Show>\n </div>\n </div>\n );\n}\n\nexport type SettingsSaveBarProps = {\n changeCount: MaybeAccessor<number>;\n loading: MaybeAccessor<boolean>;\n saveDisabled?: MaybeAccessor<boolean>;\n onDiscard: () => void;\n onSave: () => void;\n saveLabel?: string;\n saveVariant?: ButtonVariant;\n class?: string;\n};\n\nconst SettingsActions = (\n props: SettingsSaveBarProps & {\n disableWithoutChanges?: boolean;\n },\n): JSX.Element => {\n const promptMessages = usePromptMessages();\n const settingsMessages = useSettingsMessages();\n const changeCount = () => read(props.changeCount);\n const loading = () => read(props.loading);\n const disabled = () => loading() || Boolean(props.disableWithoutChanges && changeCount() === 0);\n const saveDisabled = () => disabled() || Boolean(props.saveDisabled !== undefined && read(props.saveDisabled));\n return (\n <div class=\"k2b-settings-actions\">\n <Button variant=\"secondary\" disabled={disabled()} onClick={props.onDiscard}>\n {promptMessages().discard}\n </Button>\n <Button\n variant={props.saveVariant ?? \"primary\"}\n loading={loading()}\n loadingLabel={settingsMessages().saving}\n disabled={saveDisabled()}\n onClick={props.onSave}\n >\n <i class=\"ti ti-device-floppy\" aria-hidden=\"true\" />\n {props.saveLabel ?? settingsMessages().saveChanges}\n </Button>\n </div>\n );\n};\n\nexport function SettingsSaveBar(props: SettingsSaveBarProps): JSX.Element {\n const settingsMessages = useSettingsMessages();\n const changeCount = () => read(props.changeCount);\n return (\n <Show when={changeCount() > 0}>\n <div class={`k2b-settings-save-bar ${props.class ?? \"\"}`}>\n <p role=\"status\" aria-live=\"polite\">\n <strong>{changeCount()}</strong> {settingsMessages().unsavedChangeLabel({ count: changeCount() })}\n </p>\n <SettingsActions {...props} />\n </div>\n </Show>\n );\n}\n\nexport type SettingsPanelFooterProps = SettingsSaveBarProps;\n\nexport function SettingsPanelFooter(props: SettingsPanelFooterProps): JSX.Element {\n const settingsMessages = useSettingsMessages();\n const changeCount = () => read(props.changeCount);\n return (\n <>\n <p class=\"k2b-settings-panel-footer__status\" role=\"status\" aria-live=\"polite\">\n <Show when={changeCount() > 0} fallback={settingsMessages().noUnsavedChanges}>\n <strong>{changeCount()}</strong> {settingsMessages().unsavedChangeLabel({ count: changeCount() })}\n </Show>\n </p>\n <SettingsActions {...props} disableWithoutChanges />\n </>\n );\n}\n\nexport type SaveStatusState = \"saved\" | \"draft\" | \"saving\" | \"failed\" | \"invalid\" | \"unknown\" | \"readonly\";\n\nexport type SaveStatusProps = {\n /** What the person's values are now: saved, a draft with changes, being saved, or a problem that kept them unsaved. */\n state: MaybeAccessor<SaveStatusState>;\n /** Formatted time of the last save, shown with `saved`. */\n savedAt?: MaybeAccessor<string | undefined>;\n /** Fields to check, shown with `invalid`. Default 1. */\n invalidCount?: MaybeAccessor<number>;\n /** With both handlers, Discard and Save follow the status while there is something to save. */\n onDiscard?: () => void;\n onSave?: () => void;\n saveLabel?: string;\n saveDisabled?: MaybeAccessor<boolean>;\n class?: string;\n};\n\nconst SAVE_STATUS_ICON: Record<SaveStatusState, string> = {\n saved: \"ti ti-check\",\n draft: \"ti ti-pencil\",\n saving: \"ti ti-loader-2\",\n failed: \"ti ti-alert-triangle\",\n invalid: \"ti ti-alert-triangle\",\n unknown: \"ti ti-help-circle\",\n readonly: \"ti ti-lock\",\n};\n\n/**\n * The save status of a settings form at one fixed place, usually the head of its column. It reserves its width, so\n * a change of state never moves the title or the buttons beside it. Problems with one field stay at that field.\n */\nexport function SaveStatus(props: SaveStatusProps): JSX.Element {\n const settingsMessages = useSettingsMessages();\n const state = () => read(props.state);\n const text = () => {\n const t = settingsMessages();\n switch (state()) {\n case \"saved\": {\n const at = props.savedAt === undefined ? undefined : read(props.savedAt);\n return at ? t.statusSavedAt({ time: at }) : t.statusSaved;\n }\n case \"draft\":\n return t.statusDraft;\n case \"saving\":\n return t.saving;\n case \"failed\":\n return t.statusFailed;\n case \"invalid\":\n return t.statusInvalid({ count: props.invalidCount === undefined ? 1 : read(props.invalidCount) });\n case \"unknown\":\n return t.statusUnknown;\n case \"readonly\":\n return t.statusReadOnly;\n }\n };\n const hasActions = () => Boolean(props.onSave && props.onDiscard) && state() !== \"readonly\";\n const pending = () => state() === \"draft\" || state() === \"failed\" || state() === \"invalid\" || state() === \"saving\";\n return (\n <div class={`k2b-save-status ${props.class ?? \"\"}`}>\n <span class=\"k2b-save-status__slot\">\n <span class=\"k2b-save-status__state\" data-state={state()} role=\"status\" aria-live=\"polite\">\n <i class={`${SAVE_STATUS_ICON[state()]}${state() === \"saving\" ? \" k2b-spin\" : \"\"}`} aria-hidden=\"true\" />\n {text()}\n </span>\n </span>\n <Show when={hasActions()}>\n <SettingsActions\n changeCount={() => (pending() ? 1 : 0)}\n loading={() => state() === \"saving\"}\n saveDisabled={() => state() === \"invalid\" || Boolean(props.saveDisabled !== undefined && read(props.saveDisabled))}\n onDiscard={props.onDiscard!}\n onSave={props.onSave!}\n saveLabel={props.saveLabel ?? settingsMessages().save}\n disableWithoutChanges\n />\n </Show>\n </div>\n );\n}\n"],"mappings":"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","ignoreList":[]}
@@ -20,6 +20,7 @@ var _tmpl$ = /*#__PURE__*/_$template(`<button type=button role=tab><!$><!/><span
20
20
  _tmpl$8 = /*#__PURE__*/_$template(`<footer class=k2b-settings__footer>`);
21
21
  import { children, createEffect, createMemo, createSignal, createUniqueId, For, Show } from "solid-js";
22
22
  import { IconButton } from "../actions/Button";
23
+ import { revealInScroller } from "../internal/reveal-in-scroller";
23
24
  import { useUiMessages } from "../intl/messages";
24
25
  import { createScrollFade } from "./scroll-fade";
25
26
  import { useSettingsMessages } from "./settings-messages";
@@ -102,10 +103,7 @@ const SettingsModal = props => {
102
103
  // `defaultTab`, `activeTab` and clicks can select a category past the edge of the scrolling row or rail.
103
104
  createEffect(() => {
104
105
  const id = resolvedActiveTabId();
105
- queueMicrotask(() => tabRefs.get(id)?.scrollIntoView?.({
106
- block: "nearest",
107
- inline: "nearest"
108
- }));
106
+ queueMicrotask(() => revealInScroller(tabList, tabRefs.get(id)));
109
107
  });
110
108
  // A memo, so a change elsewhere in the tab list does not create the open panel again.
111
109
  const activeTab = createMemo(() => tabs().find(tab => tab.props.id === resolvedActiveTabId()) ?? null);
@@ -1 +1 @@
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":[]}
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 { revealInScroller } from \"../internal/reveal-in-scroller\";\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(() => revealInScroller(tabList, tabRefs.get(id)));\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":[]}
@@ -47,6 +47,7 @@ const SELECTION_MARK_SELECTOR = '[aria-selected="true"], [aria-current]:not([ari
47
47
  const IGNORED_SELECTION_MARK_SELECTOR = "[data-calendar-day-key]";
48
48
  const clamp = (value, min, max) => Math.round(Math.min(max, Math.max(min, value)));
49
49
  const eventElement = event => event.target instanceof Element ? event.target : null;
50
+ const PREVIEW_FOCUS_SELECTOR = ".k2b-app-workspace__sidebar-preview-trigger:not([data-row-trigger])";
50
51
  const resizeHandle = event => eventElement(event)?.closest(HANDLE_SELECTOR) ?? null;
51
52
  const resizeKind = handle => {
52
53
  const value = handle.dataset.appWorkspaceResize;
@@ -1733,7 +1734,16 @@ export const installAppWorkspaceController = (options = {}) => {
1733
1734
  * arriving at a handle was announced whatever `aria-valuenow`/`valuemax` the
1734
1735
  * last drag left behind.
1735
1736
  */
1737
+ // A keyboard-focused action preview covers the row's last action, so the actions before it say so. CSS cannot ask
1738
+ // this through `:has()` from the actions' buttons without restyling every button of the page on each DOM change.
1739
+ const syncPreviewFocus = event => {
1740
+ const trigger = eventElement(event)?.closest(PREVIEW_FOCUS_SELECTOR);
1741
+ const actions = trigger?.previousElementSibling;
1742
+ if (!trigger || !actions?.matches(".k2b-app-workspace__sidebar-item-actions")) return;
1743
+ if (event.type === "focusin" && trigger.matches(":focus-visible")) actions.setAttribute("data-preview-focus", "");else actions.removeAttribute("data-preview-focus");
1744
+ };
1736
1745
  const onFocusIn = event => {
1746
+ syncPreviewFocus(event);
1737
1747
  const handle = resizeHandle(event);
1738
1748
  const kind = handle ? resizeKind(handle) : null;
1739
1749
  const root = handle ? workspaceRoot(handle) : null;
@@ -1889,6 +1899,7 @@ export const installAppWorkspaceController = (options = {}) => {
1889
1899
  phone?.addEventListener("change", syncPhonePages);
1890
1900
  eventRoot.addEventListener("keydown", onKeyDown);
1891
1901
  eventRoot.addEventListener("focusin", onFocusIn);
1902
+ eventRoot.addEventListener("focusout", syncPreviewFocus);
1892
1903
  window.addEventListener("resize", onResize);
1893
1904
  syncPhonePages();
1894
1905
  syncObservedRoots();
@@ -1966,6 +1977,7 @@ export const installAppWorkspaceController = (options = {}) => {
1966
1977
  phone?.removeEventListener("change", syncHostState);
1967
1978
  eventRoot.removeEventListener("keydown", onKeyDown);
1968
1979
  eventRoot.removeEventListener("focusin", onFocusIn);
1980
+ eventRoot.removeEventListener("focusout", syncPreviewFocus);
1969
1981
  window.removeEventListener("resize", onResize);
1970
1982
  };
1971
1983
  };