@k2b/ui 0.43.0 → 0.45.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 (128) hide show
  1. package/dist/browser/actions/Tabs.js +3 -4
  2. package/dist/browser/actions/Tabs.js.map +1 -1
  3. package/dist/browser/actions/menu-sheet.js +2 -3
  4. package/dist/browser/actions/menu-sheet.js.map +1 -1
  5. package/dist/browser/actions/phone-sheet.js +4 -0
  6. package/dist/browser/actions/phone-sheet.js.map +1 -0
  7. package/dist/browser/content/DataTable.js +47 -51
  8. package/dist/browser/content/DataTable.js.map +1 -1
  9. package/dist/browser/feedback/dialog-core.js +5 -1
  10. package/dist/browser/feedback/dialog-core.js.map +1 -1
  11. package/dist/browser/feedback/dialog-tone.js +26 -0
  12. package/dist/browser/feedback/dialog-tone.js.map +1 -0
  13. package/dist/browser/feedback/index.js.map +1 -1
  14. package/dist/browser/feedback/prompt-confirm.js +223 -0
  15. package/dist/browser/feedback/prompt-confirm.js.map +1 -0
  16. package/dist/browser/feedback/prompts.js +195 -343
  17. package/dist/browser/feedback/prompts.js.map +1 -1
  18. package/dist/browser/inputs/ChoiceList.js +45 -17
  19. package/dist/browser/inputs/ChoiceList.js.map +1 -1
  20. package/dist/browser/inputs/DatePicker.js +1647 -334
  21. package/dist/browser/inputs/DatePicker.js.map +1 -1
  22. package/dist/browser/inputs/TextInput.js +5 -4
  23. package/dist/browser/inputs/TextInput.js.map +1 -1
  24. package/dist/browser/inputs/date-input-messages.js +128 -0
  25. package/dist/browser/inputs/date-input-messages.js.map +1 -0
  26. package/dist/browser/inputs/date-input-status.js +132 -0
  27. package/dist/browser/inputs/date-input-status.js.map +1 -0
  28. package/dist/browser/inputs/date-input.js +334 -0
  29. package/dist/browser/inputs/date-input.js.map +1 -0
  30. package/dist/browser/inputs/date-sheet.js +49 -0
  31. package/dist/browser/inputs/date-sheet.js.map +1 -0
  32. package/dist/browser/internal/reveal-in-scroller.js +28 -0
  33. package/dist/browser/internal/reveal-in-scroller.js.map +1 -0
  34. package/dist/browser/intl/messages.js +6 -0
  35. package/dist/browser/intl/messages.js.map +1 -1
  36. package/dist/browser/layout/AppWorkspace.js +536 -512
  37. package/dist/browser/layout/AppWorkspace.js.map +1 -1
  38. package/dist/browser/layout/BottomSheet.js +3 -0
  39. package/dist/browser/layout/BottomSheet.js.map +1 -1
  40. package/dist/browser/layout/PanelDialog.js +167 -132
  41. package/dist/browser/layout/PanelDialog.js.map +1 -1
  42. package/dist/browser/layout/Settings.js +175 -139
  43. package/dist/browser/layout/Settings.js.map +1 -1
  44. package/dist/browser/layout/SettingsModal.js +2 -4
  45. package/dist/browser/layout/SettingsModal.js.map +1 -1
  46. package/dist/browser/layout/index.js.map +1 -1
  47. package/dist/browser/layout/navigation-model.js +12 -2
  48. package/dist/browser/layout/navigation-model.js.map +1 -1
  49. package/dist/browser/surfaces/StatusBadge.js +47 -14
  50. package/dist/browser/surfaces/StatusBadge.js.map +1 -1
  51. package/dist/browser/text-editor/TextEditor.js +7 -0
  52. package/dist/browser/text-editor/TextEditor.js.map +1 -1
  53. package/dist/ssr/actions/Tabs.js +3 -4
  54. package/dist/ssr/actions/Tabs.js.map +1 -1
  55. package/dist/ssr/actions/menu-sheet.js +2 -3
  56. package/dist/ssr/actions/menu-sheet.js.map +1 -1
  57. package/dist/ssr/actions/phone-sheet.js +4 -0
  58. package/dist/ssr/actions/phone-sheet.js.map +1 -0
  59. package/dist/ssr/content/DataTable.js +1 -2
  60. package/dist/ssr/content/DataTable.js.map +1 -1
  61. package/dist/ssr/feedback/dialog-core.js +5 -1
  62. package/dist/ssr/feedback/dialog-core.js.map +1 -1
  63. package/dist/ssr/feedback/dialog-tone.js +26 -0
  64. package/dist/ssr/feedback/dialog-tone.js.map +1 -0
  65. package/dist/ssr/feedback/index.js.map +1 -1
  66. package/dist/ssr/feedback/prompt-confirm.js +123 -0
  67. package/dist/ssr/feedback/prompt-confirm.js.map +1 -0
  68. package/dist/ssr/feedback/prompts.js +60 -132
  69. package/dist/ssr/feedback/prompts.js.map +1 -1
  70. package/dist/ssr/inputs/ChoiceList.js +29 -9
  71. package/dist/ssr/inputs/ChoiceList.js.map +1 -1
  72. package/dist/ssr/inputs/DatePicker.js +1183 -166
  73. package/dist/ssr/inputs/DatePicker.js.map +1 -1
  74. package/dist/ssr/inputs/TextInput.js +5 -4
  75. package/dist/ssr/inputs/TextInput.js.map +1 -1
  76. package/dist/ssr/inputs/date-input-messages.js +128 -0
  77. package/dist/ssr/inputs/date-input-messages.js.map +1 -0
  78. package/dist/ssr/inputs/date-input-status.js +132 -0
  79. package/dist/ssr/inputs/date-input-status.js.map +1 -0
  80. package/dist/ssr/inputs/date-input.js +334 -0
  81. package/dist/ssr/inputs/date-input.js.map +1 -0
  82. package/dist/ssr/inputs/date-sheet.js +44 -0
  83. package/dist/ssr/inputs/date-sheet.js.map +1 -0
  84. package/dist/ssr/internal/reveal-in-scroller.js +28 -0
  85. package/dist/ssr/internal/reveal-in-scroller.js.map +1 -0
  86. package/dist/ssr/intl/messages.js +6 -0
  87. package/dist/ssr/intl/messages.js.map +1 -1
  88. package/dist/ssr/layout/AppWorkspace.js +44 -23
  89. package/dist/ssr/layout/AppWorkspace.js.map +1 -1
  90. package/dist/ssr/layout/BottomSheet.js +3 -0
  91. package/dist/ssr/layout/BottomSheet.js.map +1 -1
  92. package/dist/ssr/layout/PanelDialog.js +48 -30
  93. package/dist/ssr/layout/PanelDialog.js.map +1 -1
  94. package/dist/ssr/layout/Settings.js +34 -18
  95. package/dist/ssr/layout/Settings.js.map +1 -1
  96. package/dist/ssr/layout/SettingsModal.js +2 -4
  97. package/dist/ssr/layout/SettingsModal.js.map +1 -1
  98. package/dist/ssr/layout/index.js.map +1 -1
  99. package/dist/ssr/layout/navigation-model.js +12 -2
  100. package/dist/ssr/layout/navigation-model.js.map +1 -1
  101. package/dist/ssr/surfaces/StatusBadge.js +26 -8
  102. package/dist/ssr/surfaces/StatusBadge.js.map +1 -1
  103. package/dist/ssr/text-editor/TextEditor.js +7 -0
  104. package/dist/ssr/text-editor/TextEditor.js.map +1 -1
  105. package/dist/styles.css +1 -1
  106. package/dist/types/actions/menu-sheet.d.ts +1 -3
  107. package/dist/types/actions/phone-sheet.d.ts +3 -0
  108. package/dist/types/feedback/dialog-tone.d.ts +10 -0
  109. package/dist/types/feedback/index.d.ts +1 -0
  110. package/dist/types/feedback/prompt-confirm.d.ts +19 -0
  111. package/dist/types/feedback/prompts.d.ts +4 -8
  112. package/dist/types/inputs/ChoiceList.d.ts +7 -3
  113. package/dist/types/inputs/DatePicker.d.ts +13 -3
  114. package/dist/types/inputs/TextInput.d.ts +1 -1
  115. package/dist/types/inputs/date-input-messages.d.ts +64 -0
  116. package/dist/types/inputs/date-input-status.d.ts +35 -0
  117. package/dist/types/inputs/date-input.d.ts +90 -0
  118. package/dist/types/inputs/date-sheet.d.ts +14 -0
  119. package/dist/types/internal/reveal-in-scroller.d.ts +6 -0
  120. package/dist/types/intl/messages.d.ts +3 -0
  121. package/dist/types/layout/AppWorkspace.d.ts +14 -0
  122. package/dist/types/layout/BottomSheet.d.ts +3 -0
  123. package/dist/types/layout/PanelDialog.d.ts +3 -0
  124. package/dist/types/layout/Settings.d.ts +17 -1
  125. package/dist/types/layout/index.d.ts +1 -1
  126. package/dist/types/layout/navigation-model.d.ts +1 -1
  127. package/dist/types/surfaces/StatusBadge.d.ts +5 -0
  128. package/package.json +1 -1
@@ -39,6 +39,9 @@ function BottomSheetRoot(props) {
39
39
  if (!props.dismissDisabled) void props.onDismiss();
40
40
  };
41
41
  return _$createComponent(PanelDialog, {
42
+ get tone() {
43
+ return props.tone;
44
+ },
42
45
  get children() {
43
46
  return [_$createComponent(Show, {
44
47
  get when() {
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["layout/BottomSheet.tsx"],"sourcesContent":["import { type JSX, Show } from \"solid-js\";\nimport type { OpenDialogOptions } from \"../feedback/dialog-core\";\nimport { suppressTextSelection } from \"../internal/text-selection\";\nimport { useUiMessages } from \"../intl/messages\";\nimport PanelDialog from \"./PanelDialog\";\n\n/** Initial focus goes to the first input of the top sheet, otherwise to the\n * dialog element itself. Native `showModal()` focuses the first focusable\n * descendant, which is the drag handle; iOS shows a ring for that programmatic\n * focus, so the sheet moves it to the ring-less dialog before the next paint. */\nconst sheetInitialFocus = (dialog: HTMLDialogElement): HTMLElement => {\n const input = dialog.lastElementChild?.querySelector<HTMLElement>(\n \"input:not([type='hidden']):not([disabled]), textarea:not([disabled]), select:not([disabled]), [role='combobox']:not([disabled]):not([aria-disabled='true'])\",\n );\n if (input) return input;\n dialog.tabIndex = -1;\n return dialog;\n};\n\nexport const bottomSheetOptions = {\n panelClassName: \"k2b-dialog k2b-bottom-sheet-frame\",\n contentClassName: \"k2b-panel-dialog-viewport k2b-bottom-sheet-viewport\",\n initialFocus: sheetInitialFocus,\n} satisfies OpenDialogOptions;\n\n/** A sheet on phones and a centered dialog from 48rem up, for decisions and forms; menus keep\n * `bottomSheetOptions`. The stylesheet picks the mode with the phone media query, so the first\n * frame is already right and a rotation or resize switches it in place, without a remount. */\nexport const bottomSheetAdaptiveOptions = {\n ...bottomSheetOptions,\n panelClassName: `${bottomSheetOptions.panelClassName} is-adaptive`,\n} satisfies OpenDialogOptions;\n\nexport type BottomSheetProps = {\n children: JSX.Element;\n /** Pass dialogCore's render context requestDismiss, never the completion callback. */\n onDismiss: () => void | Promise<void>;\n dismissDisabled?: boolean;\n dismissLabel?: string;\n handle?: boolean;\n};\n\nfunction BottomSheetRoot(props: BottomSheetProps) {\n const messages = useUiMessages();\n let pointer: { id: number; y: number; releaseTextSelection: () => void } | undefined;\n let suppressClick = false;\n const dismiss = () => {\n if (!props.dismissDisabled) void props.onDismiss();\n };\n return (\n <PanelDialog>\n <Show when={props.handle !== false}>\n <button\n type=\"button\"\n class=\"k2b-bottom-sheet__handle\"\n aria-label={props.dismissLabel ?? messages().close}\n disabled={props.dismissDisabled}\n onPointerDown={(event) => {\n if (!event.isPrimary || event.button !== 0 || props.dismissDisabled) return;\n suppressClick = false;\n pointer = { id: event.pointerId, y: event.clientY, releaseTextSelection: suppressTextSelection(event.pointerId) };\n event.currentTarget.setPointerCapture(event.pointerId);\n }}\n onPointerUp={(event) => {\n if (pointer?.id !== event.pointerId) return;\n const distance = event.clientY - pointer.y;\n pointer.releaseTextSelection();\n pointer = undefined;\n // A drag must not turn into a second dismiss request through click.\n suppressClick = Math.abs(distance) > 8;\n if (distance > 60) dismiss();\n }}\n onPointerCancel={() => {\n pointer?.releaseTextSelection();\n pointer = undefined;\n suppressClick = true;\n }}\n onLostPointerCapture={() => {\n if (pointer) {\n pointer.releaseTextSelection();\n pointer = undefined;\n suppressClick = true;\n }\n }}\n onClick={(event) => {\n if (event.detail !== 0 && suppressClick) {\n suppressClick = false;\n return;\n }\n dismiss();\n }}\n >\n <span aria-hidden=\"true\" />\n </button>\n </Show>\n {props.children}\n </PanelDialog>\n );\n}\n\n/** Bottom-edge presentation; dialogCore continues to own all modal state. */\nconst BottomSheet = Object.assign(BottomSheetRoot, {\n Header: PanelDialog.Header,\n Body: PanelDialog.Body,\n Footer: PanelDialog.Footer,\n Section: PanelDialog.Section,\n Tabs: PanelDialog.Tabs,\n});\nexport default BottomSheet;\n"],"mappings":";;;;;AAAA,SAAmB,IAAI,QAAQ,UAAU;AAEzC,SAAS,qBAAqB,QAAQ,4BAA4B;AAClE,SAAS,aAAa,QAAQ,kBAAkB;AAChD,OAAO,WAAW,MAAM,eAAe;;AAEvC;AACA;AACA;AACA;AACA,MAAM,iBAAiB,GAAI,MAAyB,IAAkB;EACpE,MAAM,KAAK,GAAG,MAAM,CAAC,gBAAgB,EAAE,aAAa,CAClD,6JACF,CAAC;EACD,IAAI,KAAK,EAAE,OAAO,KAAK;EACvB,MAAM,CAAC,QAAQ,GAAG,CAAC,CAAC;EACpB,OAAO,MAAM;AACf,CAAC;AAED,OAAO,MAAM,kBAAkB,GAAG;EAChC,cAAc,EAAE,mCAAmC;EACnD,gBAAgB,EAAE,qDAAqD;EACvE,YAAY,EAAE;AAChB,CAA6B;;AAE7B;AACA;AACA;AACA,OAAO,MAAM,0BAA0B,GAAG;EACxC,GAAG,kBAAkB;EACrB,cAAc,EAAE,GAAG,kBAAkB,CAAC,cAAc;AACtD,CAA6B;AAW7B,SAAS,eAAe,CAAC,KAAuB,EAAE;EAChD,MAAM,QAAQ,GAAG,aAAa,CAAC,CAAC;EAChC,IAAI,OAAgF;EACpF,IAAI,aAAa,GAAG,KAAK;EACzB,MAAM,OAAO,GAAG,MAAM;IACpB,IAAI,CAAC,KAAK,CAAC,eAAe,EAAE,KAAK,KAAK,CAAC,SAAS,CAAC,CAAC;EACpD,CAAC;EACD,yBACG,WAAW;IAAA;MAAA,0BACT,IAAI;QAAA,IAAC,IAAI;UAAA,OAAE,KAAK,CAAC,MAAM,KAAK,KAAK;QAAA;QAAA;UAAA,2DAIlB,KAAK,CAAC,YAAY,IAAI,QAAQ,CAAC,CAAC,CAAC,KAAK,4CACxC,KAAK,CAAC,eAAe;QAAA;MAAA,IAuClC,KAAK,CAAC,QAAQ;IAAA;EAAA;AAGrB;;AAEA;AACA,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC,eAAe,EAAE;EACjD,MAAM,EAAE,WAAW,CAAC,MAAM;EAC1B,IAAI,EAAE,WAAW,CAAC,IAAI;EACtB,MAAM,EAAE,WAAW,CAAC,MAAM;EAC1B,OAAO,EAAE,WAAW,CAAC,OAAO;EAC5B,IAAI,EAAE,WAAW,CAAC;AACpB,CAAC,CAAC;AACF,eAAe,WAAW","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["layout/BottomSheet.tsx"],"sourcesContent":["import { type JSX, Show } from \"solid-js\";\nimport type { OpenDialogOptions } from \"../feedback/dialog-core\";\nimport type { DialogTone } from \"../feedback/dialog-tone\";\nimport { suppressTextSelection } from \"../internal/text-selection\";\nimport { useUiMessages } from \"../intl/messages\";\nimport PanelDialog from \"./PanelDialog\";\n\n/** Initial focus goes to the first input of the top sheet, otherwise to the\n * dialog element itself. Native `showModal()` focuses the first focusable\n * descendant, which is the drag handle; iOS shows a ring for that programmatic\n * focus, so the sheet moves it to the ring-less dialog before the next paint. */\nconst sheetInitialFocus = (dialog: HTMLDialogElement): HTMLElement => {\n const input = dialog.lastElementChild?.querySelector<HTMLElement>(\n \"input:not([type='hidden']):not([disabled]), textarea:not([disabled]), select:not([disabled]), [role='combobox']:not([disabled]):not([aria-disabled='true'])\",\n );\n if (input) return input;\n dialog.tabIndex = -1;\n return dialog;\n};\n\nexport const bottomSheetOptions = {\n panelClassName: \"k2b-dialog k2b-bottom-sheet-frame\",\n contentClassName: \"k2b-panel-dialog-viewport k2b-bottom-sheet-viewport\",\n initialFocus: sheetInitialFocus,\n} satisfies OpenDialogOptions;\n\n/** A sheet on phones and a centered dialog from 48rem up, for decisions and forms; menus keep\n * `bottomSheetOptions`. The stylesheet picks the mode with the phone media query, so the first\n * frame is already right and a rotation or resize switches it in place, without a remount. */\nexport const bottomSheetAdaptiveOptions = {\n ...bottomSheetOptions,\n panelClassName: `${bottomSheetOptions.panelClassName} is-adaptive`,\n} satisfies OpenDialogOptions;\n\nexport type BottomSheetProps = {\n children: JSX.Element;\n /** Pass dialogCore's render context requestDismiss, never the completion callback. */\n onDismiss: () => void | Promise<void>;\n dismissDisabled?: boolean;\n dismissLabel?: string;\n handle?: boolean;\n /** See `PanelDialog`'s `tone`. */\n tone?: DialogTone;\n};\n\nfunction BottomSheetRoot(props: BottomSheetProps) {\n const messages = useUiMessages();\n let pointer: { id: number; y: number; releaseTextSelection: () => void } | undefined;\n let suppressClick = false;\n const dismiss = () => {\n if (!props.dismissDisabled) void props.onDismiss();\n };\n return (\n <PanelDialog tone={props.tone}>\n <Show when={props.handle !== false}>\n <button\n type=\"button\"\n class=\"k2b-bottom-sheet__handle\"\n aria-label={props.dismissLabel ?? messages().close}\n disabled={props.dismissDisabled}\n onPointerDown={(event) => {\n if (!event.isPrimary || event.button !== 0 || props.dismissDisabled) return;\n suppressClick = false;\n pointer = { id: event.pointerId, y: event.clientY, releaseTextSelection: suppressTextSelection(event.pointerId) };\n event.currentTarget.setPointerCapture(event.pointerId);\n }}\n onPointerUp={(event) => {\n if (pointer?.id !== event.pointerId) return;\n const distance = event.clientY - pointer.y;\n pointer.releaseTextSelection();\n pointer = undefined;\n // A drag must not turn into a second dismiss request through click.\n suppressClick = Math.abs(distance) > 8;\n if (distance > 60) dismiss();\n }}\n onPointerCancel={() => {\n pointer?.releaseTextSelection();\n pointer = undefined;\n suppressClick = true;\n }}\n onLostPointerCapture={() => {\n if (pointer) {\n pointer.releaseTextSelection();\n pointer = undefined;\n suppressClick = true;\n }\n }}\n onClick={(event) => {\n if (event.detail !== 0 && suppressClick) {\n suppressClick = false;\n return;\n }\n dismiss();\n }}\n >\n <span aria-hidden=\"true\" />\n </button>\n </Show>\n {props.children}\n </PanelDialog>\n );\n}\n\n/** Bottom-edge presentation; dialogCore continues to own all modal state. */\nconst BottomSheet = Object.assign(BottomSheetRoot, {\n Header: PanelDialog.Header,\n Body: PanelDialog.Body,\n Footer: PanelDialog.Footer,\n Section: PanelDialog.Section,\n Tabs: PanelDialog.Tabs,\n});\nexport default BottomSheet;\n"],"mappings":";;;;;AAAA,SAAmB,IAAI,QAAQ,UAAU;AAGzC,SAAS,qBAAqB,QAAQ,4BAA4B;AAClE,SAAS,aAAa,QAAQ,kBAAkB;AAChD,OAAO,WAAW,MAAM,eAAe;;AAEvC;AACA;AACA;AACA;AACA,MAAM,iBAAiB,GAAI,MAAyB,IAAkB;EACpE,MAAM,KAAK,GAAG,MAAM,CAAC,gBAAgB,EAAE,aAAa,CAClD,6JACF,CAAC;EACD,IAAI,KAAK,EAAE,OAAO,KAAK;EACvB,MAAM,CAAC,QAAQ,GAAG,CAAC,CAAC;EACpB,OAAO,MAAM;AACf,CAAC;AAED,OAAO,MAAM,kBAAkB,GAAG;EAChC,cAAc,EAAE,mCAAmC;EACnD,gBAAgB,EAAE,qDAAqD;EACvE,YAAY,EAAE;AAChB,CAA6B;;AAE7B;AACA;AACA;AACA,OAAO,MAAM,0BAA0B,GAAG;EACxC,GAAG,kBAAkB;EACrB,cAAc,EAAE,GAAG,kBAAkB,CAAC,cAAc;AACtD,CAA6B;AAa7B,SAAS,eAAe,CAAC,KAAuB,EAAE;EAChD,MAAM,QAAQ,GAAG,aAAa,CAAC,CAAC;EAChC,IAAI,OAAgF;EACpF,IAAI,aAAa,GAAG,KAAK;EACzB,MAAM,OAAO,GAAG,MAAM;IACpB,IAAI,CAAC,KAAK,CAAC,eAAe,EAAE,KAAK,KAAK,CAAC,SAAS,CAAC,CAAC;EACpD,CAAC;EACD,yBACG,WAAW;IAAA,IAAC,IAAI;MAAA,OAAE,KAAK,CAAC,IAAI;IAAA;IAAA;MAAA,0BAC1B,IAAI;QAAA,IAAC,IAAI;UAAA,OAAE,KAAK,CAAC,MAAM,KAAK,KAAK;QAAA;QAAA;UAAA,2DAIlB,KAAK,CAAC,YAAY,IAAI,QAAQ,CAAC,CAAC,CAAC,KAAK,4CACxC,KAAK,CAAC,eAAe;QAAA;MAAA,IAuClC,KAAK,CAAC,QAAQ;IAAA;EAAA;AAGrB;;AAEA;AACA,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC,eAAe,EAAE;EACjD,MAAM,EAAE,WAAW,CAAC,MAAM;EAC1B,IAAI,EAAE,WAAW,CAAC,IAAI;EACtB,MAAM,EAAE,WAAW,CAAC,MAAM;EAC1B,OAAO,EAAE,WAAW,CAAC,OAAO;EAC5B,IAAI,EAAE,WAAW,CAAC;AACpB,CAAC,CAAC;AACF,eAAe,WAAW","ignoreList":[]}
@@ -6,30 +6,33 @@ import { escape as _$escape } from "solid-js/web";
6
6
  var _tmpl$ = ["<p>", "</p>"],
7
7
  _tmpl$2 = ["<div class=\"k2b-panel-dialog__actions\">", "</div>"],
8
8
  _tmpl$3 = ["<button type=\"button\" class=\"k2b-dialog__close\"", "", "><i class=\"ti ti-x\" aria-hidden=\"true\"></i></button>"],
9
- _tmpl$4 = ["<header class=\"k2b-panel-dialog__header\"", ">", "<div class=\"k2b-panel-dialog__heading\"><h2>", "</h2>", "</div>", "", "</header>"],
10
- _tmpl$5 = ["<span class=\"k2b-panel-dialog__icon k2b-icon-tile\" aria-hidden=\"true\"><i", "></i></span>"],
11
- _tmpl$6 = ["<div class=\"k2b-panel-dialog__body\"", ">", "</div>"],
12
- _tmpl$7 = ["<footer class=\"k2b-panel-dialog__footer\"", ">", "</footer>"],
13
- _tmpl$8 = ["<span class=\"k2b-panel-dialog__section-subtitle\">", "</span>"],
14
- _tmpl$9 = ["<span class=\"k2b-panel-dialog__section-copy\"><span id=\"", "\" class=\"k2b-panel-dialog__section-title\">", "</span>", "</span>"],
15
- _tmpl$0 = "<i class=\"ti ti-eye\" aria-hidden=\"true\"></i>",
16
- _tmpl$1 = ["<div", ">", "</div>"],
17
- _tmpl$10 = ["<p class=\"k2b-panel-dialog__section-subtitle\">", "</p>"],
18
- _tmpl$11 = "<i class=\"ti ti-eye-off\" aria-hidden=\"true\"></i>",
19
- _tmpl$12 = ["<section class=\"k2b-panel-dialog__section\"", ">", "<header", ">", "<div><h3", ">", "</h3>", "</div>", "", "</header><div id=\"", "\" class=\"k2b-panel-dialog__section-body\"", ">", "</div></section>"],
20
- _tmpl$13 = ["<i", " aria-hidden=\"true\"></i>"],
21
- _tmpl$14 = ["<span class=\"k2b-panel-dialog__section-icon\"><i", " aria-hidden=\"true\"></i></span>"],
22
- _tmpl$15 = ["<div class=\"k2b-panel-dialog\"", ">", "</div>"];
9
+ _tmpl$4 = ["<header class=\"k2b-panel-dialog__header\"", ">", "<div class=\"k2b-panel-dialog__heading\">", "<h2>", "</h2>", "</div>", "", "</header>"],
10
+ _tmpl$5 = ["<span class=\"k2b-panel-dialog__icon k2b-icon-tile\"", " aria-hidden=\"true\"><i", "></i></span>"],
11
+ _tmpl$6 = ["<span class=\"k2b-sr-only\" data-dialog-tone-label>", "</span>"],
12
+ _tmpl$7 = ["<div class=\"k2b-panel-dialog__body\"", ">", "</div>"],
13
+ _tmpl$8 = ["<footer class=\"k2b-panel-dialog__footer\"", ">", "</footer>"],
14
+ _tmpl$9 = ["<span class=\"k2b-panel-dialog__section-subtitle\">", "</span>"],
15
+ _tmpl$0 = ["<span class=\"k2b-panel-dialog__section-copy\"><span id=\"", "\" class=\"k2b-panel-dialog__section-title\">", "</span>", "</span>"],
16
+ _tmpl$1 = "<i class=\"ti ti-eye\" aria-hidden=\"true\"></i>",
17
+ _tmpl$10 = ["<div", ">", "</div>"],
18
+ _tmpl$11 = ["<p class=\"k2b-panel-dialog__section-subtitle\">", "</p>"],
19
+ _tmpl$12 = "<i class=\"ti ti-eye-off\" aria-hidden=\"true\"></i>",
20
+ _tmpl$13 = ["<section class=\"k2b-panel-dialog__section\"", ">", "<header", ">", "<div><h3", ">", "</h3>", "</div>", "", "</header><div id=\"", "\" class=\"k2b-panel-dialog__section-body\"", ">", "</div></section>"],
21
+ _tmpl$14 = ["<i", " aria-hidden=\"true\"></i>"],
22
+ _tmpl$15 = ["<span class=\"k2b-panel-dialog__section-icon\"><i", " aria-hidden=\"true\"></i></span>"],
23
+ _tmpl$16 = ["<div class=\"k2b-panel-dialog\"", ">", "</div>"];
23
24
  import { createContext, createEffect, createSignal, createUniqueId, Show, useContext } from "solid-js";
24
25
  import { Button } from "../actions/Button";
25
26
  import { Tabs } from "../actions/Tabs";
27
+ import { dialogToneIcon, dialogToneLabel } from "../feedback/dialog-tone";
28
+ import { sharedPrompts } from "../feedback/prompt-confirm";
26
29
  import { resolvePromptMessages } from "../feedback/prompt-messages";
27
- import { prompts } from "../feedback/prompts";
28
30
  import { useUiMessages } from "../intl/messages";
29
31
  import { usePanelDialogMessages } from "./panel-dialog-messages";
30
32
  import { createScrollFade } from "./scroll-fade";
31
33
  const PanelDialogSurfaceContext = createContext("contained");
32
34
  const usePanelDialogSurface = () => useContext(PanelDialogSurfaceContext);
35
+ const PanelDialogToneContext = createContext(() => undefined);
33
36
  const panelDialogBasePanelClass = "k2b-dialog k2b-panel-dialog-frame";
34
37
  export const panelDialogPanelClass = `${panelDialogBasePanelClass} is-standard`;
35
38
  export const panelDialogOptions = {
@@ -54,7 +57,7 @@ export const panelDialogWorkspaceOptions = {
54
57
  export const confirmDiscardIfDirty = async dirty => {
55
58
  const hasChanges = typeof dirty === "function" ? dirty() : dirty;
56
59
  if (!hasChanges) return true;
57
- return Boolean(await prompts.confirm(resolvePromptMessages().discardUnsavedChanges, {
60
+ return Boolean(await sharedPrompts.confirm(resolvePromptMessages().discardUnsavedChanges, {
58
61
  title: resolvePromptMessages().unsavedChangesTitle,
59
62
  variant: "danger",
60
63
  confirmText: resolvePromptMessages().discard
@@ -62,11 +65,21 @@ export const confirmDiscardIfDirty = async dirty => {
62
65
  };
63
66
  const PanelDialogHeader = props => {
64
67
  const messages = useUiMessages();
68
+ const tone = useContext(PanelDialogToneContext);
69
+ const icon = () => {
70
+ const value = tone();
71
+ return value ? dialogToneIcon(value) : props.icon;
72
+ };
65
73
  return _$ssr(_tmpl$4, _$ssrAttribute("data-surface", _$escape(usePanelDialogSurface(), true), false) + _$ssrAttribute("data-has-subtitle", _$escape(Boolean(props.subtitle), true), false), _$escape(_$createComponent(Show, {
66
74
  get when() {
67
- return props.icon;
75
+ return icon();
76
+ },
77
+ children: icon => _$ssr(_tmpl$5, _$ssrAttribute("data-tone", _$escape(tone(), true), false), _$ssrAttribute("class", _$escape(icon(), true), false))
78
+ })), _$escape(_$createComponent(Show, {
79
+ get when() {
80
+ return tone();
68
81
  },
69
- children: icon => _$ssr(_tmpl$5, _$ssrAttribute("class", _$escape(icon(), true), false))
82
+ children: value => _$ssr(_tmpl$6, _$escape(dialogToneLabel(messages(), value())))
70
83
  })), _$escape(props.title), _$escape(_$createComponent(Show, {
71
84
  get when() {
72
85
  return props.subtitle;
@@ -93,9 +106,9 @@ const PanelDialogHeader = props => {
93
106
  const PanelDialogBody = props => {
94
107
  let body;
95
108
  createScrollFade(() => body, () => props.scrollFade !== false);
96
- return _$ssr(_tmpl$6, _$ssrAttribute("data-scroll-preserve", _$escape(props.scrollPreserveKey, true), false) + _$ssrAttribute("data-surface", _$escape(usePanelDialogSurface(), true), false) + _$ssrAttribute("data-scroll-fade-mode", props.scrollFade !== false ? "both" : _$escape(undefined, true), false), _$escape(props.children));
109
+ return _$ssr(_tmpl$7, _$ssrAttribute("data-scroll-preserve", _$escape(props.scrollPreserveKey, true), false) + _$ssrAttribute("data-surface", _$escape(usePanelDialogSurface(), true), false) + _$ssrAttribute("data-scroll-fade-mode", props.scrollFade !== false ? "both" : _$escape(undefined, true), false), _$escape(props.children));
97
110
  };
98
- const PanelDialogFooter = props => _$ssr(_tmpl$7, _$ssrAttribute("data-surface", _$escape(usePanelDialogSurface(), true), false), _$escape(props.children));
111
+ const PanelDialogFooter = props => _$ssr(_tmpl$8, _$ssrAttribute("data-surface", _$escape(usePanelDialogSurface(), true), false), _$escape(props.children));
99
112
  const PanelDialogSection = props => {
100
113
  const id = `k2b-panel-dialog-section-${createUniqueId()}`;
101
114
  const [internalOpen, setInternalOpen] = createSignal(props.defaultOpen ?? false);
@@ -118,12 +131,12 @@ const PanelDialogSection = props => {
118
131
  if (!expanded && active && active !== expand && section?.contains(active)) expand?.focus();
119
132
  });
120
133
  });
121
- return _$ssr(_tmpl$12, _$ssrAttribute("data-surface", _$escape(usePanelDialogSurface(), true), false) + _$ssrAttribute("data-hideable", _$escape(props.hideable || undefined, true), false) + _$ssrAttribute("data-open", props.hideable ? _$escape(open(), true) : _$escape(undefined, true), false) + _$ssrAttribute("aria-labelledby", open() ? _$escape(id, true) : `${_$escape(id, true)}-closed`, false), _$escape(_$createComponent(Show, {
134
+ return _$ssr(_tmpl$13, _$ssrAttribute("data-surface", _$escape(usePanelDialogSurface(), true), false) + _$ssrAttribute("data-hideable", _$escape(props.hideable || undefined, true), false) + _$ssrAttribute("data-open", props.hideable ? _$escape(open(), true) : _$escape(undefined, true), false) + _$ssrAttribute("aria-labelledby", open() ? _$escape(id, true) : `${_$escape(id, true)}-closed`, false), _$escape(_$createComponent(Show, {
122
135
  get when() {
123
136
  return props.hideable;
124
137
  },
125
138
  get children() {
126
- return _$ssr(_tmpl$1, _$ssrAttribute("hidden", open(), true), _$escape(_$createComponent(Button, {
139
+ return _$ssr(_tmpl$10, _$ssrAttribute("hidden", open(), true), _$escape(_$createComponent(Button, {
127
140
  variant: "ghost",
128
141
  "class": "k2b-panel-dialog__section-summary",
129
142
  get disabled() {
@@ -137,15 +150,15 @@ const PanelDialogSection = props => {
137
150
  get when() {
138
151
  return props.icon;
139
152
  },
140
- children: icon => _$ssr(_tmpl$13, _$ssrAttribute("class", _$escape(icon(), true), false))
141
- }), _$ssr(_tmpl$9, `${_$escape(id, true)}-closed`, _$escape(props.title), _$escape(_$createComponent(Show, {
153
+ children: icon => _$ssr(_tmpl$14, _$ssrAttribute("class", _$escape(icon(), true), false))
154
+ }), _$ssr(_tmpl$0, `${_$escape(id, true)}-closed`, _$escape(props.title), _$escape(_$createComponent(Show, {
142
155
  get when() {
143
156
  return props.subtitle;
144
157
  },
145
158
  get children() {
146
- return _$ssr(_tmpl$8, _$escape(props.subtitle));
159
+ return _$ssr(_tmpl$9, _$escape(props.subtitle));
147
160
  }
148
- }))), _$ssr(_tmpl$0)];
161
+ }))), _$ssr(_tmpl$1)];
149
162
  }
150
163
  })));
151
164
  }
@@ -153,13 +166,13 @@ const PanelDialogSection = props => {
153
166
  get when() {
154
167
  return props.icon;
155
168
  },
156
- children: icon => _$ssr(_tmpl$14, _$ssrAttribute("class", _$escape(icon(), true), false))
169
+ children: icon => _$ssr(_tmpl$15, _$ssrAttribute("class", _$escape(icon(), true), false))
157
170
  })), _$ssrAttribute("id", _$escape(id, true), false), _$escape(props.title), _$escape(_$createComponent(Show, {
158
171
  get when() {
159
172
  return props.subtitle;
160
173
  },
161
174
  get children() {
162
- return _$ssr(_tmpl$10, _$escape(props.subtitle));
175
+ return _$ssr(_tmpl$11, _$escape(props.subtitle));
163
176
  }
164
177
  })), _$escape(_$createComponent(Show, {
165
178
  get when() {
@@ -185,7 +198,7 @@ const PanelDialogSection = props => {
185
198
  "aria-controls": `${id}-body`,
186
199
  onClick: () => toggle(false),
187
200
  get children() {
188
- return _$ssr(_tmpl$11);
201
+ return _$ssr(_tmpl$12);
189
202
  }
190
203
  });
191
204
  }
@@ -214,7 +227,12 @@ const PanelDialog = props => {
214
227
  return _$createComponent(PanelDialogSurfaceContext.Provider, {
215
228
  value: surface,
216
229
  get children() {
217
- return _$ssr(_tmpl$15, _$ssrAttribute("data-surface", _$escape(surface, true), false), _$escape(props.children));
230
+ return _$createComponent(PanelDialogToneContext.Provider, {
231
+ value: () => props.tone,
232
+ get children() {
233
+ return _$ssr(_tmpl$16, _$ssrAttribute("data-surface", _$escape(surface, true), false) + _$ssrAttribute("data-tone", _$escape(props.tone, true), false), _$escape(props.children));
234
+ }
235
+ });
218
236
  }
219
237
  });
220
238
  };
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["layout/PanelDialog.tsx"],"sourcesContent":["import { createContext, createEffect, createSignal, createUniqueId, type JSX, Show, useContext } from \"solid-js\";\nimport { Button } from \"../actions/Button\";\nimport { Tabs } from \"../actions/Tabs\";\nimport type { OpenDialogOptions } from \"../feedback/dialog-core\";\nimport { resolvePromptMessages } from \"../feedback/prompt-messages\";\nimport { prompts } from \"../feedback/prompts\";\nimport { useUiMessages } from \"../intl/messages\";\nimport { usePanelDialogMessages } from \"./panel-dialog-messages\";\nimport { createScrollFade } from \"./scroll-fade\";\n\nexport type PanelDialogSurface = \"contained\" | \"floating\";\n\nexport type PanelDialogProps = {\n children: JSX.Element;\n surface?: PanelDialogSurface;\n};\n\nexport type PanelDialogHeaderProps = {\n title: JSX.Element;\n subtitle?: JSX.Element;\n icon?: string;\n actions?: JSX.Element;\n close?: () => void;\n closeDisabled?: boolean;\n closeLabel?: string;\n};\n\nexport type PanelDialogBodyProps = {\n children: JSX.Element;\n scrollPreserveKey?: string;\n scrollFade?: boolean;\n};\n\nexport type PanelDialogFooterProps = {\n children: JSX.Element;\n};\n\nexport type PanelDialogSectionProps = {\n title: JSX.Element;\n subtitle?: JSX.Element;\n icon?: string;\n actions?: JSX.Element;\n children: JSX.Element;\n} & (\n | { hideable?: false; open?: never; defaultOpen?: never; onOpenChange?: never; disabled?: never }\n | { hideable: true; open?: boolean; defaultOpen?: boolean; onOpenChange?: (open: boolean) => void; disabled?: boolean }\n);\n\nexport type PanelDialogTabOption<T extends string = string> = {\n value: T;\n label: JSX.Element;\n icon?: string;\n disabled?: boolean;\n};\n\nexport type PanelDialogTabsProps<T extends string = string> = {\n options: readonly PanelDialogTabOption<T>[];\n value: T | (() => T);\n onValueChange: (value: T) => void;\n ariaLabel?: string;\n label?: string;\n};\n\ntype PanelDialogComponent = ((props: PanelDialogProps) => JSX.Element) & {\n Header: (props: PanelDialogHeaderProps) => JSX.Element;\n Body: (props: PanelDialogBodyProps) => JSX.Element;\n Footer: (props: PanelDialogFooterProps) => JSX.Element;\n Section: (props: PanelDialogSectionProps) => JSX.Element;\n Tabs: <T extends string>(props: PanelDialogTabsProps<T>) => JSX.Element;\n};\n\nconst PanelDialogSurfaceContext = createContext<PanelDialogSurface>(\"contained\");\nconst usePanelDialogSurface = () => useContext(PanelDialogSurfaceContext);\n\nconst panelDialogBasePanelClass = \"k2b-dialog k2b-panel-dialog-frame\";\n\nexport const panelDialogPanelClass = `${panelDialogBasePanelClass} is-standard`;\nexport const panelDialogOptions = {\n panelClassName: panelDialogPanelClass,\n contentClassName: \"k2b-panel-dialog-viewport\",\n} satisfies OpenDialogOptions;\n\nexport const panelDialogWidePanelClass = `${panelDialogBasePanelClass} is-wide`;\nexport const panelDialogWideOptions = {\n panelClassName: panelDialogWidePanelClass,\n contentClassName: \"k2b-panel-dialog-viewport\",\n} satisfies OpenDialogOptions;\n\nexport const panelDialogFixedPanelClass = `${panelDialogBasePanelClass} is-fixed`;\nexport const panelDialogFixedOptions = {\n panelClassName: panelDialogFixedPanelClass,\n contentClassName: \"k2b-panel-dialog-viewport is-fixed\",\n} satisfies OpenDialogOptions;\n\nexport const panelDialogWorkspacePanelClass = `${panelDialogBasePanelClass} is-workspace`;\nexport const panelDialogWorkspaceOptions = {\n panelClassName: panelDialogWorkspacePanelClass,\n contentClassName: \"k2b-panel-dialog-viewport is-workspace\",\n} satisfies OpenDialogOptions;\n\nexport const confirmDiscardIfDirty = async (dirty: boolean | (() => boolean)): Promise<boolean> => {\n const hasChanges = typeof dirty === \"function\" ? dirty() : dirty;\n if (!hasChanges) return true;\n return Boolean(\n await prompts.confirm(resolvePromptMessages().discardUnsavedChanges, {\n title: resolvePromptMessages().unsavedChangesTitle,\n variant: \"danger\",\n confirmText: resolvePromptMessages().discard,\n }),\n );\n};\n\nconst PanelDialogHeader = (props: PanelDialogHeaderProps): JSX.Element => {\n const messages = useUiMessages();\n return (\n <header class=\"k2b-panel-dialog__header\" data-surface={usePanelDialogSurface()} data-has-subtitle={Boolean(props.subtitle)}>\n <Show when={props.icon}>\n {(icon) => (\n <span class=\"k2b-panel-dialog__icon k2b-icon-tile\" aria-hidden=\"true\">\n <i class={icon()} />\n </span>\n )}\n </Show>\n <div class=\"k2b-panel-dialog__heading\">\n <h2>{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-panel-dialog__actions\">{props.actions}</div>\n </Show>\n <Show when={props.close}>\n <button\n type=\"button\"\n class=\"k2b-dialog__close\"\n aria-label={props.closeLabel ?? messages().closeDialog}\n disabled={props.closeDisabled}\n onClick={props.close}\n >\n <i class=\"ti ti-x\" aria-hidden=\"true\" />\n </button>\n </Show>\n </header>\n );\n};\n\nconst PanelDialogBody = (props: PanelDialogBodyProps): JSX.Element => {\n let body: HTMLDivElement | undefined;\n createScrollFade(\n () => body,\n () => props.scrollFade !== false,\n );\n return (\n <div\n ref={body}\n class=\"k2b-panel-dialog__body\"\n data-scroll-preserve={props.scrollPreserveKey}\n data-surface={usePanelDialogSurface()}\n data-scroll-fade-mode={props.scrollFade !== false ? \"both\" : undefined}\n >\n {props.children}\n </div>\n );\n};\n\nconst PanelDialogFooter = (props: PanelDialogFooterProps): JSX.Element => (\n <footer class=\"k2b-panel-dialog__footer\" data-surface={usePanelDialogSurface()}>\n {props.children}\n </footer>\n);\n\nconst PanelDialogSection = (props: PanelDialogSectionProps): JSX.Element => {\n const id = `k2b-panel-dialog-section-${createUniqueId()}`;\n const [internalOpen, setInternalOpen] = createSignal(props.defaultOpen ?? false);\n const open = () => !props.hideable || (props.open ?? internalOpen());\n let section: HTMLElement | undefined;\n let expand: HTMLButtonElement | undefined;\n let collapse: HTMLButtonElement | undefined;\n const toggle = (next: boolean) => {\n if (props.disabled) return;\n if (props.open === undefined) setInternalOpen(next);\n props.onOpenChange?.(next);\n };\n createEffect(() => {\n if (!props.hideable) return;\n const expanded = open();\n queueMicrotask(() => {\n if (expanded !== open()) return;\n const active = section?.ownerDocument.activeElement;\n if (expanded && active === expand) collapse?.focus();\n if (!expanded && active && active !== expand && section?.contains(active)) expand?.focus();\n });\n });\n\n return (\n <section\n ref={section}\n class=\"k2b-panel-dialog__section\"\n data-surface={usePanelDialogSurface()}\n data-hideable={props.hideable || undefined}\n data-open={props.hideable ? open() : undefined}\n aria-labelledby={open() ? id : `${id}-closed`}\n >\n <Show when={props.hideable}>\n <div hidden={open()}>\n <Button\n ref={expand}\n variant=\"ghost\"\n class=\"k2b-panel-dialog__section-summary\"\n disabled={props.disabled}\n aria-expanded={false}\n aria-controls={`${id}-body`}\n onClick={() => toggle(true)}\n >\n <Show when={props.icon}>{(icon) => <i class={icon()} aria-hidden=\"true\" />}</Show>\n <span class=\"k2b-panel-dialog__section-copy\">\n <span id={`${id}-closed`} class=\"k2b-panel-dialog__section-title\">\n {props.title}\n </span>\n <Show when={props.subtitle}>\n <span class=\"k2b-panel-dialog__section-subtitle\">{props.subtitle}</span>\n </Show>\n </span>\n <i class=\"ti ti-eye\" aria-hidden=\"true\" />\n </Button>\n </div>\n </Show>\n <header hidden={!open()}>\n <Show when={props.icon}>\n {(icon) => (\n <span class=\"k2b-panel-dialog__section-icon\">\n <i class={icon()} aria-hidden=\"true\" />\n </span>\n )}\n </Show>\n <div>\n <h3 id={id}>{props.title}</h3>\n <Show when={props.subtitle}>\n <p class=\"k2b-panel-dialog__section-subtitle\">{props.subtitle}</p>\n </Show>\n </div>\n <Show when={props.actions}>\n <div class=\"k2b-panel-dialog__actions\">{props.actions}</div>\n </Show>\n <Show when={props.hideable}>\n <Button\n ref={collapse}\n variant=\"ghost\"\n size=\"sm\"\n class=\"k2b-icon-button\"\n disabled={props.disabled}\n aria-labelledby={id}\n aria-expanded={true}\n aria-controls={`${id}-body`}\n onClick={() => toggle(false)}\n >\n <i class=\"ti ti-eye-off\" aria-hidden=\"true\" />\n </Button>\n </Show>\n </header>\n <div id={`${id}-body`} class=\"k2b-panel-dialog__section-body\" hidden={!open()}>\n {props.children}\n </div>\n </section>\n );\n};\n\nconst PanelDialogTabs = <T extends string>(props: PanelDialogTabsProps<T>): JSX.Element => {\n const panelDialogMessages = usePanelDialogMessages();\n return (\n <Tabs\n class=\"k2b-panel-dialog__tabs\"\n value={props.value}\n onValueChange={props.onValueChange}\n ariaLabel={props.ariaLabel ?? props.label ?? panelDialogMessages().dialogTabs}\n options={props.options}\n />\n );\n};\n\nconst PanelDialog = ((props: PanelDialogProps): JSX.Element => {\n const surface = props.surface ?? \"contained\";\n return (\n <PanelDialogSurfaceContext.Provider value={surface}>\n <div class=\"k2b-panel-dialog\" data-surface={surface}>\n {props.children}\n </div>\n </PanelDialogSurfaceContext.Provider>\n );\n}) as PanelDialogComponent;\n\nPanelDialog.Header = PanelDialogHeader;\nPanelDialog.Body = PanelDialogBody;\nPanelDialog.Footer = PanelDialogFooter;\nPanelDialog.Section = PanelDialogSection;\nPanelDialog.Tabs = PanelDialogTabs;\n\nexport default PanelDialog;\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["layout/PanelDialog.tsx"],"sourcesContent":["import { createContext, createEffect, createSignal, createUniqueId, type JSX, Show, useContext } from \"solid-js\";\nimport { Button } from \"../actions/Button\";\nimport { Tabs } from \"../actions/Tabs\";\nimport type { OpenDialogOptions } from \"../feedback/dialog-core\";\nimport { type DialogTone, dialogToneIcon, dialogToneLabel } from \"../feedback/dialog-tone\";\nimport { sharedPrompts } from \"../feedback/prompt-confirm\";\nimport { resolvePromptMessages } from \"../feedback/prompt-messages\";\nimport { useUiMessages } from \"../intl/messages\";\nimport { usePanelDialogMessages } from \"./panel-dialog-messages\";\nimport { createScrollFade } from \"./scroll-fade\";\n\nexport type PanelDialogSurface = \"contained\" | \"floating\";\n\nexport type PanelDialogProps = {\n children: JSX.Element;\n surface?: PanelDialogSurface;\n /** A 2 px edge in the tone's colour inside the dialog frame; the header shows the tone's icon instead of its own. */\n tone?: DialogTone;\n};\n\nexport type PanelDialogHeaderProps = {\n title: JSX.Element;\n subtitle?: JSX.Element;\n icon?: string;\n actions?: JSX.Element;\n close?: () => void;\n closeDisabled?: boolean;\n closeLabel?: string;\n};\n\nexport type PanelDialogBodyProps = {\n children: JSX.Element;\n scrollPreserveKey?: string;\n scrollFade?: boolean;\n};\n\nexport type PanelDialogFooterProps = {\n children: JSX.Element;\n};\n\nexport type PanelDialogSectionProps = {\n title: JSX.Element;\n subtitle?: JSX.Element;\n icon?: string;\n actions?: JSX.Element;\n children: JSX.Element;\n} & (\n | { hideable?: false; open?: never; defaultOpen?: never; onOpenChange?: never; disabled?: never }\n | { hideable: true; open?: boolean; defaultOpen?: boolean; onOpenChange?: (open: boolean) => void; disabled?: boolean }\n);\n\nexport type PanelDialogTabOption<T extends string = string> = {\n value: T;\n label: JSX.Element;\n icon?: string;\n disabled?: boolean;\n};\n\nexport type PanelDialogTabsProps<T extends string = string> = {\n options: readonly PanelDialogTabOption<T>[];\n value: T | (() => T);\n onValueChange: (value: T) => void;\n ariaLabel?: string;\n label?: string;\n};\n\ntype PanelDialogComponent = ((props: PanelDialogProps) => JSX.Element) & {\n Header: (props: PanelDialogHeaderProps) => JSX.Element;\n Body: (props: PanelDialogBodyProps) => JSX.Element;\n Footer: (props: PanelDialogFooterProps) => JSX.Element;\n Section: (props: PanelDialogSectionProps) => JSX.Element;\n Tabs: <T extends string>(props: PanelDialogTabsProps<T>) => JSX.Element;\n};\n\nconst PanelDialogSurfaceContext = createContext<PanelDialogSurface>(\"contained\");\nconst usePanelDialogSurface = () => useContext(PanelDialogSurfaceContext);\nconst PanelDialogToneContext = createContext<() => DialogTone | undefined>(() => undefined);\n\nconst panelDialogBasePanelClass = \"k2b-dialog k2b-panel-dialog-frame\";\n\nexport const panelDialogPanelClass = `${panelDialogBasePanelClass} is-standard`;\nexport const panelDialogOptions = {\n panelClassName: panelDialogPanelClass,\n contentClassName: \"k2b-panel-dialog-viewport\",\n} satisfies OpenDialogOptions;\n\nexport const panelDialogWidePanelClass = `${panelDialogBasePanelClass} is-wide`;\nexport const panelDialogWideOptions = {\n panelClassName: panelDialogWidePanelClass,\n contentClassName: \"k2b-panel-dialog-viewport\",\n} satisfies OpenDialogOptions;\n\nexport const panelDialogFixedPanelClass = `${panelDialogBasePanelClass} is-fixed`;\nexport const panelDialogFixedOptions = {\n panelClassName: panelDialogFixedPanelClass,\n contentClassName: \"k2b-panel-dialog-viewport is-fixed\",\n} satisfies OpenDialogOptions;\n\nexport const panelDialogWorkspacePanelClass = `${panelDialogBasePanelClass} is-workspace`;\nexport const panelDialogWorkspaceOptions = {\n panelClassName: panelDialogWorkspacePanelClass,\n contentClassName: \"k2b-panel-dialog-viewport is-workspace\",\n} satisfies OpenDialogOptions;\n\nexport const confirmDiscardIfDirty = async (dirty: boolean | (() => boolean)): Promise<boolean> => {\n const hasChanges = typeof dirty === \"function\" ? dirty() : dirty;\n if (!hasChanges) return true;\n return Boolean(\n await sharedPrompts.confirm(resolvePromptMessages().discardUnsavedChanges, {\n title: resolvePromptMessages().unsavedChangesTitle,\n variant: \"danger\",\n confirmText: resolvePromptMessages().discard,\n }),\n );\n};\n\nconst PanelDialogHeader = (props: PanelDialogHeaderProps): JSX.Element => {\n const messages = useUiMessages();\n const tone = useContext(PanelDialogToneContext);\n const icon = () => {\n const value = tone();\n return value ? dialogToneIcon(value) : props.icon;\n };\n return (\n <header class=\"k2b-panel-dialog__header\" data-surface={usePanelDialogSurface()} data-has-subtitle={Boolean(props.subtitle)}>\n <Show when={icon()}>\n {(icon) => (\n <span class=\"k2b-panel-dialog__icon k2b-icon-tile\" data-tone={tone()} aria-hidden=\"true\">\n <i class={icon()} />\n </span>\n )}\n </Show>\n <div class=\"k2b-panel-dialog__heading\">\n <Show when={tone()}>\n {(value) => (\n <span class=\"k2b-sr-only\" data-dialog-tone-label>\n {dialogToneLabel(messages(), value())}\n </span>\n )}\n </Show>\n <h2>{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-panel-dialog__actions\">{props.actions}</div>\n </Show>\n <Show when={props.close}>\n <button\n type=\"button\"\n class=\"k2b-dialog__close\"\n aria-label={props.closeLabel ?? messages().closeDialog}\n disabled={props.closeDisabled}\n onClick={props.close}\n >\n <i class=\"ti ti-x\" aria-hidden=\"true\" />\n </button>\n </Show>\n </header>\n );\n};\n\nconst PanelDialogBody = (props: PanelDialogBodyProps): JSX.Element => {\n let body: HTMLDivElement | undefined;\n createScrollFade(\n () => body,\n () => props.scrollFade !== false,\n );\n return (\n <div\n ref={body}\n class=\"k2b-panel-dialog__body\"\n data-scroll-preserve={props.scrollPreserveKey}\n data-surface={usePanelDialogSurface()}\n data-scroll-fade-mode={props.scrollFade !== false ? \"both\" : undefined}\n >\n {props.children}\n </div>\n );\n};\n\nconst PanelDialogFooter = (props: PanelDialogFooterProps): JSX.Element => (\n <footer class=\"k2b-panel-dialog__footer\" data-surface={usePanelDialogSurface()}>\n {props.children}\n </footer>\n);\n\nconst PanelDialogSection = (props: PanelDialogSectionProps): JSX.Element => {\n const id = `k2b-panel-dialog-section-${createUniqueId()}`;\n const [internalOpen, setInternalOpen] = createSignal(props.defaultOpen ?? false);\n const open = () => !props.hideable || (props.open ?? internalOpen());\n let section: HTMLElement | undefined;\n let expand: HTMLButtonElement | undefined;\n let collapse: HTMLButtonElement | undefined;\n const toggle = (next: boolean) => {\n if (props.disabled) return;\n if (props.open === undefined) setInternalOpen(next);\n props.onOpenChange?.(next);\n };\n createEffect(() => {\n if (!props.hideable) return;\n const expanded = open();\n queueMicrotask(() => {\n if (expanded !== open()) return;\n const active = section?.ownerDocument.activeElement;\n if (expanded && active === expand) collapse?.focus();\n if (!expanded && active && active !== expand && section?.contains(active)) expand?.focus();\n });\n });\n\n return (\n <section\n ref={section}\n class=\"k2b-panel-dialog__section\"\n data-surface={usePanelDialogSurface()}\n data-hideable={props.hideable || undefined}\n data-open={props.hideable ? open() : undefined}\n aria-labelledby={open() ? id : `${id}-closed`}\n >\n <Show when={props.hideable}>\n <div hidden={open()}>\n <Button\n ref={expand}\n variant=\"ghost\"\n class=\"k2b-panel-dialog__section-summary\"\n disabled={props.disabled}\n aria-expanded={false}\n aria-controls={`${id}-body`}\n onClick={() => toggle(true)}\n >\n <Show when={props.icon}>{(icon) => <i class={icon()} aria-hidden=\"true\" />}</Show>\n <span class=\"k2b-panel-dialog__section-copy\">\n <span id={`${id}-closed`} class=\"k2b-panel-dialog__section-title\">\n {props.title}\n </span>\n <Show when={props.subtitle}>\n <span class=\"k2b-panel-dialog__section-subtitle\">{props.subtitle}</span>\n </Show>\n </span>\n <i class=\"ti ti-eye\" aria-hidden=\"true\" />\n </Button>\n </div>\n </Show>\n <header hidden={!open()}>\n <Show when={props.icon}>\n {(icon) => (\n <span class=\"k2b-panel-dialog__section-icon\">\n <i class={icon()} aria-hidden=\"true\" />\n </span>\n )}\n </Show>\n <div>\n <h3 id={id}>{props.title}</h3>\n <Show when={props.subtitle}>\n <p class=\"k2b-panel-dialog__section-subtitle\">{props.subtitle}</p>\n </Show>\n </div>\n <Show when={props.actions}>\n <div class=\"k2b-panel-dialog__actions\">{props.actions}</div>\n </Show>\n <Show when={props.hideable}>\n <Button\n ref={collapse}\n variant=\"ghost\"\n size=\"sm\"\n class=\"k2b-icon-button\"\n disabled={props.disabled}\n aria-labelledby={id}\n aria-expanded={true}\n aria-controls={`${id}-body`}\n onClick={() => toggle(false)}\n >\n <i class=\"ti ti-eye-off\" aria-hidden=\"true\" />\n </Button>\n </Show>\n </header>\n <div id={`${id}-body`} class=\"k2b-panel-dialog__section-body\" hidden={!open()}>\n {props.children}\n </div>\n </section>\n );\n};\n\nconst PanelDialogTabs = <T extends string>(props: PanelDialogTabsProps<T>): JSX.Element => {\n const panelDialogMessages = usePanelDialogMessages();\n return (\n <Tabs\n class=\"k2b-panel-dialog__tabs\"\n value={props.value}\n onValueChange={props.onValueChange}\n ariaLabel={props.ariaLabel ?? props.label ?? panelDialogMessages().dialogTabs}\n options={props.options}\n />\n );\n};\n\nconst PanelDialog = ((props: PanelDialogProps): JSX.Element => {\n const surface = props.surface ?? \"contained\";\n return (\n <PanelDialogSurfaceContext.Provider value={surface}>\n <PanelDialogToneContext.Provider value={() => props.tone}>\n <div class=\"k2b-panel-dialog\" data-surface={surface} data-tone={props.tone}>\n {props.children}\n </div>\n </PanelDialogToneContext.Provider>\n </PanelDialogSurfaceContext.Provider>\n );\n}) as PanelDialogComponent;\n\nPanelDialog.Header = PanelDialogHeader;\nPanelDialog.Body = PanelDialogBody;\nPanelDialog.Footer = PanelDialogFooter;\nPanelDialog.Section = PanelDialogSection;\nPanelDialog.Tabs = PanelDialogTabs;\n\nexport default PanelDialog;\n"],"mappings":"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","ignoreList":[]}
@@ -12,18 +12,19 @@ var _tmpl$ = ["<p>", "</p>"],
12
12
  _tmpl$5 = ["<section class=\"", "\" style=\"", "\"", ">", "<div class=\"k2b-settings-page__body\"", ">", "</div>", "</section>"],
13
13
  _tmpl$6 = ["<i", " aria-hidden=\"true\"></i>"],
14
14
  _tmpl$7 = ["<div class=\"k2b-settings-section__actions\">", "</div>"],
15
- _tmpl$8 = ["<section class=\"", "\"", "><header class=\"k2b-settings-section__header\">", "<div class=\"k2b-settings-section__heading\"><h2", ">", "</h2>", "</div>", "</header><div class=\"k2b-settings-section__body\">", "</div></section>"],
15
+ _tmpl$8 = ["<section class=\"", "\"", "><div class=\"k2b-settings-section__layout\"><header class=\"k2b-settings-section__header\">", "<div class=\"k2b-settings-section__heading\"><h2", ">", "</h2>", "</div>", "</header><div class=\"k2b-settings-section__body\">", "</div></div></section>"],
16
16
  _tmpl$9 = ["<section class=\"", "\"", "><header class=\"k2b-settings-group__header\"><div class=\"k2b-settings-group__heading\"><h3", ">", "</h3>", "</div>", "</header><div class=\"k2b-settings-group__body\">", "</div></section>"],
17
17
  _tmpl$0 = ["<div class=\"k2b-settings-group__action\">", "</div>"],
18
18
  _tmpl$1 = ["<span>", "</span>"],
19
- _tmpl$10 = ["<div class=\"", "\"><div class=\"k2b-settings-field__copy\"><div class=\"k2b-settings-field__heading\"><strong>", "</strong>", "</div><p", ">", "</p></div>", "", "</div>"],
20
- _tmpl$11 = ["<p", " class=\"k2b-settings-field__error\" role=\"alert\"><i class=\"ti ti-alert-circle\" aria-hidden=\"true\"></i> ", "</p>"],
21
- _tmpl$12 = "<i class=\"ti ti-device-floppy\" aria-hidden=\"true\"></i>",
22
- _tmpl$13 = ["<div class=\"k2b-settings-actions\">", "", "</div>"],
23
- _tmpl$14 = ["<div class=\"", "\"><p role=\"status\" aria-live=\"polite\"><strong>", "</strong> ", "</p>", "</div>"],
24
- _tmpl$15 = ["<strong>", "</strong>"],
25
- _tmpl$16 = ["<p class=\"k2b-settings-panel-footer__status\" role=\"status\" aria-live=\"polite\">", "</p>"],
26
- _tmpl$17 = ["<div class=\"", "\"><span class=\"k2b-save-status__slot\"><span class=\"k2b-save-status__state\"", " role=\"status\" aria-live=\"polite\"><i class=\"", "\" aria-hidden=\"true\"></i>", "</span></span>", "</div>"];
19
+ _tmpl$10 = ["<div class=\"k2b-settings-field__source\">", "</div>"],
20
+ _tmpl$11 = ["<div", " class=\"", "\"", "><div class=\"k2b-settings-field__row\"><div class=\"k2b-settings-field__copy\"><div class=\"k2b-settings-field__heading\"><strong>", "</strong>", "</div><p", ">", "</p></div><div class=\"k2b-settings-field__control\">", "", "</div>", "</div></div>"],
21
+ _tmpl$12 = ["<p", " class=\"k2b-settings-field__error\" role=\"alert\"><i class=\"ti ti-alert-circle\" aria-hidden=\"true\"></i> ", "</p>"],
22
+ _tmpl$13 = "<i class=\"ti ti-device-floppy\" aria-hidden=\"true\"></i>",
23
+ _tmpl$14 = ["<div class=\"k2b-settings-actions\">", "", "</div>"],
24
+ _tmpl$15 = ["<div class=\"", "\"><p role=\"status\" aria-live=\"polite\"><strong>", "</strong> ", "</p>", "</div>"],
25
+ _tmpl$16 = ["<strong>", "</strong>"],
26
+ _tmpl$17 = ["<p class=\"k2b-settings-panel-footer__status\" role=\"status\" aria-live=\"polite\">", "</p>"],
27
+ _tmpl$18 = ["<div class=\"", "\"><span class=\"k2b-save-status__slot\"><span class=\"k2b-save-status__state\"", " role=\"status\" aria-live=\"polite\"><i class=\"", "\" aria-hidden=\"true\"></i>", "</span></span>", "</div>"];
27
28
  import { children, createMemo, createUniqueId, Show } from "solid-js";
28
29
  import { Button } from "../actions/Button";
29
30
  import { usePromptMessages } from "../feedback/prompt-messages";
@@ -67,7 +68,8 @@ export function SettingsPage(props) {
67
68
  }
68
69
  /**
69
70
  * A full-page settings group: a heading, optional actions and its fields on the
70
- * page surface without a card. Dialogs keep using PanelDialog.Section.
71
+ * page surface without a card. From 860 px of its own width the heading takes a
72
+ * column beside the fields. Dialogs keep using PanelDialog.Section.
71
73
  */
72
74
  export function SettingsSection(props) {
73
75
  const headingId = `k2b-settings-section-${createUniqueId()}`;
@@ -133,6 +135,12 @@ export const readSettingsError = async (response, fallback) => {
133
135
  fields: data?.errors ?? {}
134
136
  };
135
137
  };
138
+
139
+ /**
140
+ * The room a setting's control takes: `short` for a number, `medium` for a choice, `long` for text, and `full` for
141
+ * an editor, which keeps its name above it and takes the whole row.
142
+ */
143
+
136
144
  export function SettingsField(props) {
137
145
  const settingsMessages = useSettingsMessages();
138
146
  const id = createUniqueId();
@@ -142,7 +150,8 @@ export function SettingsField(props) {
142
150
  const control = () => typeof props.children === "function" ? props.children({
143
151
  describedBy
144
152
  }) : props.children;
145
- return _$ssr(_tmpl$10, `k2b-settings-field ${_$escape(props.class ?? "", true)}`, _$escape(props.label), _$escape(_$createComponent(Show, {
153
+ const source = children(() => props.source);
154
+ return _$ssr(_tmpl$11, _$ssrAttribute("id", _$escape(props.id, true), false), `k2b-settings-field ${_$escape(props.class ?? "", true)}`, _$ssrAttribute("data-width", _$escape(props.width ?? "long", true), false), _$escape(props.label), _$escape(_$createComponent(Show, {
146
155
  get when() {
147
156
  return _$memo(() => props.changed !== undefined)() && read(props.changed);
148
157
  },
@@ -153,7 +162,14 @@ export function SettingsField(props) {
153
162
  get when() {
154
163
  return read(props.error);
155
164
  },
156
- children: error => _$ssr(_tmpl$11, _$ssrAttribute("id", _$escape(errorId, true), false), _$escape(error()))
165
+ children: error => _$ssr(_tmpl$12, _$ssrAttribute("id", _$escape(errorId, true), false), _$escape(error()))
166
+ })), _$escape(_$createComponent(Show, {
167
+ get when() {
168
+ return source();
169
+ },
170
+ get children() {
171
+ return _$ssr(_tmpl$10, _$escape(source()));
172
+ }
157
173
  })));
158
174
  }
159
175
  const SettingsActions = props => {
@@ -163,7 +179,7 @@ const SettingsActions = props => {
163
179
  const loading = () => read(props.loading);
164
180
  const disabled = () => loading() || Boolean(props.disableWithoutChanges && changeCount() === 0);
165
181
  const saveDisabled = () => disabled() || Boolean(props.saveDisabled !== undefined && read(props.saveDisabled));
166
- return _$ssr(_tmpl$13, _$escape(_$createComponent(Button, {
182
+ return _$ssr(_tmpl$14, _$escape(_$createComponent(Button, {
167
183
  variant: "secondary",
168
184
  get disabled() {
169
185
  return disabled();
@@ -191,7 +207,7 @@ const SettingsActions = props => {
191
207
  return props.onSave;
192
208
  },
193
209
  get children() {
194
- return [_$ssr(_tmpl$12), props.saveLabel ?? settingsMessages().saveChanges];
210
+ return [_$ssr(_tmpl$13), props.saveLabel ?? settingsMessages().saveChanges];
195
211
  }
196
212
  })));
197
213
  };
@@ -203,7 +219,7 @@ export function SettingsSaveBar(props) {
203
219
  return changeCount() > 0;
204
220
  },
205
221
  get children() {
206
- return _$ssr(_tmpl$14, `k2b-settings-save-bar ${_$escape(props.class ?? "", true)}`, _$escape(changeCount()), _$escape(settingsMessages().unsavedChangeLabel({
222
+ return _$ssr(_tmpl$15, `k2b-settings-save-bar ${_$escape(props.class ?? "", true)}`, _$escape(changeCount()), _$escape(settingsMessages().unsavedChangeLabel({
207
223
  count: changeCount()
208
224
  })), _$escape(_$createComponent(SettingsActions, props)));
209
225
  }
@@ -212,7 +228,7 @@ export function SettingsSaveBar(props) {
212
228
  export function SettingsPanelFooter(props) {
213
229
  const settingsMessages = useSettingsMessages();
214
230
  const changeCount = () => read(props.changeCount);
215
- return [_$ssr(_tmpl$16, _$escape(_$createComponent(Show, {
231
+ return [_$ssr(_tmpl$17, _$escape(_$createComponent(Show, {
216
232
  get when() {
217
233
  return changeCount() > 0;
218
234
  },
@@ -220,7 +236,7 @@ export function SettingsPanelFooter(props) {
220
236
  return settingsMessages().noUnsavedChanges;
221
237
  },
222
238
  get children() {
223
- return [_$ssr(_tmpl$15, _$escape(changeCount())), " ", settingsMessages().unsavedChangeLabel({
239
+ return [_$ssr(_tmpl$16, _$escape(changeCount())), " ", settingsMessages().unsavedChangeLabel({
224
240
  count: changeCount()
225
241
  })];
226
242
  }
@@ -273,7 +289,7 @@ export function SaveStatus(props) {
273
289
  };
274
290
  const hasActions = () => Boolean(props.onSave && props.onDiscard) && state() !== "readonly";
275
291
  const pending = () => state() === "draft" || state() === "failed" || state() === "invalid" || state() === "saving";
276
- return _$ssr(_tmpl$17, `k2b-save-status ${_$escape(props.class ?? "", true)}`, _$ssrAttribute("data-state", _$escape(state(), true), false), `${_$escape(SAVE_STATUS_ICON[state()], true)}${state() === "saving" ? " k2b-spin" : ""}`, _$escape(text()), _$escape(_$createComponent(Show, {
292
+ return _$ssr(_tmpl$18, `k2b-save-status ${_$escape(props.class ?? "", true)}`, _$ssrAttribute("data-state", _$escape(state(), true), false), `${_$escape(SAVE_STATUS_ICON[state()], true)}${state() === "saving" ? " k2b-spin" : ""}`, _$escape(text()), _$escape(_$createComponent(Show, {
277
293
  get when() {
278
294
  return hasActions();
279
295
  },
@@ -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":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,QAAQ,EAAE,UAAU,EAAE,cAAc,EAAY,IAAI,QAAQ,UAAU;AAC/E,SAAS,MAAM,QAA4B,mBAAmB;AAC9D,SAAS,iBAAiB,QAAQ,6BAA6B;AAE/D,SAAS,mBAAmB,QAAQ,qBAAqB;AAEzD,MAAM,IAAI,GAAQ,KAAuB,IAAS,OAAO,KAAK,KAAK,UAAU,GAAI,KAAK,CAAa,CAAC,GAAG,KAAM;AAgB7G,OAAO,SAAS,YAAY,CAAC,KAAwB,EAAe;EAClE,sBAEW,oBAAoB,KAAK,CAAC,KAAK,GAAG,aAAI,KAAK,CAAC,KAAK,SAAE,GAAG,EAAE,EAAE,aAC1D,KAAK,CAAC,KAAK,gCACN,KAAK,CAAC,MAAM,KAAK,KAAK,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ,YAAG,KAAK,CAAC,KAAK,mBAAG,SAAS,4CAE9F,IAAI;IAAA,IAAC,IAAI;MAAA,OAAE,KAAK,CAAC,MAAM,KAAK,KAAK;IAAA;IAAA;MAAA,iDAE7B,IAAI;QAAA,IAAC,IAAI;UAAA,OAAE,KAAK,CAAC,IAAI;QAAA;QAAA,UAAI,IAAI,oDAAe,IAAI,CAAC,CAAC;MAAuB,cAEnE,KAAK,CAAC,KAAK,8BACf,IAAI;QAAA,IAAC,IAAI;UAAA,OAAE,KAAK,CAAC,QAAQ;QAAA;QAAA;UAAA,8BACpB,KAAK,CAAC,QAAQ;QAAA;MAAA,gCAGrB,IAAI;QAAA,IAAC,IAAI;UAAA,OAAE,KAAK,CAAC,OAAO;QAAA;QAAA;UAAA,+BACkB,KAAK,CAAC,OAAO;QAAA;MAAA;IAAA;EAAA,qDAID,KAAK,CAAC,iBAAiB,0BAC/E,KAAK,CAAC,QAAQ,8BAEhB,IAAI;IAAA,IAAC,IAAI;MAAA,OAAE,KAAK,CAAC,MAAM;IAAA;IAAA;MAAA,+BACqB,KAAK,CAAC,MAAM;IAAA;EAAA;AAI/D;AAWA;AACA;AACA;AACA;AACA,OAAO,SAAS,eAAe,CAAC,KAA2B,EAAe;EACxE,MAAM,SAAS,GAAG,wBAAwB,cAAc,CAAC,CAAC,EAAE;EAC5D,sBACkB,uBAAuB,KAAK,CAAC,KAAK,GAAG,aAAI,KAAK,CAAC,KAAK,SAAE,GAAG,EAAE,EAAE,6CAAmB,SAAS,4CAEpG,IAAI;IAAA,IAAC,IAAI;MAAA,OAAE,KAAK,CAAC,IAAI;IAAA;IAAA,UAAI,IAAI,oDAAe,IAAI,CAAC,CAAC;EAAuB,mCAEhE,SAAS,0BAAG,KAAK,CAAC,KAAK,8BAC9B,IAAI;IAAA,IAAC,IAAI;MAAA,OAAE,KAAK,CAAC,QAAQ;IAAA;IAAA;MAAA,8BACpB,KAAK,CAAC,QAAQ;IAAA;EAAA,gCAGrB,IAAI;IAAA,IAAC,IAAI;MAAA,OAAE,KAAK,CAAC,OAAO;IAAA;IAAA;MAAA,+BACqB,KAAK,CAAC,OAAO;IAAA;EAAA,cAGpB,KAAK,CAAC,QAAQ;AAG7D;AAEA,MAAM,qBAAqB,GAAG,MAAM,CAAC,sBAAsB,CAAC;AAsB5D,MAAM,mBAAmB,GAAI,KAA+B,KACzD;EAAE,IAAI,EAAE,qBAAqB;EAAE;AAAM,CAAC,CAAmE;AAE5G,MAAM,2BAA2B,GAAI,KAAc,IAAsC;EACvF,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC,OAAO,CAAC,2BAA2B,CAAC;EAC3E,OAAO,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAK,KAAK,CAAwB,IAAI,KAAK,qBAAqB,GACrG,CAAC,KAAK,CAAkC,GACxC,EAAE;AACR,CAAC;AAED,MAAM,2BAA2B,GAAI,KAAc,IAAoB;EACrE,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC,OAAO,CAAC,2BAA2B,CAAC;EAC3E,OAAO,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAK,KAAK,CAAwB,IAAI,KAAK,qBAAqB,GAAG,EAAE,GAAG,CAAC,KAAK,CAAgB;AACzI,CAAC;AAED,OAAO,MAAM,aAAa,GAAK,KAAyB,IAAkB;EACxE,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,KAAK,CAAC,QAAQ,CAAC;EAC/C,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,2BAA2B,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;EAC3E,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,2BAA2B,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;EACzE,MAAM,SAAS,GAAG,sBAAsB,cAAc,CAAC,CAAC,EAAE;EAC1D,sBACkB,qBAAqB,KAAK,CAAC,KAAK,GAAG,aAAI,KAAK,CAAC,KAAK,SAAE,GAAG,EAAE,EAAE,6CAAmB,SAAS,+CAGzF,SAAS,0BAAG,KAAK,CAAC,KAAK,8BAC9B,IAAI;IAAA,IAAC,IAAI;MAAA,OAAE,KAAK,CAAC,WAAW;IAAA;IAAA;MAAA,8BACvB,KAAK,CAAC,WAAW;IAAA;EAAA,gCAGxB,IAAI;IAAA,IAAC,IAAI;MAAA,OAAE,MAAM,CAAC,CAAC;IAAA;IAAA,UAAI,IAAI,4BAA8C,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ;EAAO,cAEjE,OAAO,CAAC,CAAC;AAGtD,CAA4B;AAE5B,aAAa,CAAC,MAAM,GAAG,mBAAmB;AAE1C,OAAO,MAAM,gBAAgB,GAAG,CAAC,IAAa,EAAE,KAAc,KAAc,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;AAE1H,OAAO,MAAM,iBAAiB,GAAG,OAC/B,QAAgC,EAChC,QAAgB,KACiD;EACjE,MAAM,IAAI,GAAI,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,IAAI,CAG5C;EACR,OAAO;IAAE,OAAO,EAAE,IAAI,EAAE,OAAO,IAAI,QAAQ;IAAE,MAAM,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;EAAE,CAAC;AAC3E,CAAC;AAeD,OAAO,SAAS,aAAa,CAAC,KAAyB,EAAe;EACpE,MAAM,gBAAgB,GAAG,mBAAmB,CAAC,CAAC;EAC9C,MAAM,EAAE,GAAG,cAAc,CAAC,CAAC;EAC3B,MAAM,aAAa,GAAG,sBAAsB,EAAE,cAAc;EAC5D,MAAM,OAAO,GAAG,sBAAsB,EAAE,QAAQ;EAChD,MAAM,WAAW,GAAG,MAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,GAAG,aAAa,IAAI,OAAO,EAAE,GAAG,aAAc;EAC7F,MAAM,OAAO,GAAG,MACd,OAAO,KAAK,CAAC,QAAQ,KAAK,UAAU,GAC/B,KAAK,CAAC,QAAQ,CAAyD;IAAE;EAAY,CAAC,CAAC,GACxF,KAAK,CAAC,QAAQ;EACpB,uBACc,+BAAsB,KAAK,CAAC,KAAK,IAAI,EAAE,SAAE,WAGtC,KAAK,CAAC,KAAK,8BACnB,IAAI;IAAA,IAAC,IAAI;MAAA,OAAE,kBAAK,CAAC,OAAO,KAAK,SAAS,OAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;IAAA;IAAA;MAAA,+BACrD,gBAAgB,CAAC,CAAC,CAAC,OAAO;IAAA;EAAA,mCAG9B,aAAa,0BAAG,KAAK,CAAC,WAAW,YAEzC,OAAO,CAAC,CAAC,8BACT,IAAI;IAAA,IAAC,IAAI;MAAA,OAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;IAAA;IAAA,UACzB,KAAK,kDACE,OAAO,0BACyC,KAAK,CAAC,CAAC;EAE/D;AAIT;AAaA,MAAM,eAAe,GACnB,KAEC,IACe;EAChB,MAAM,cAAc,GAAG,iBAAiB,CAAC,CAAC;EAC1C,MAAM,gBAAgB,GAAG,mBAAmB,CAAC,CAAC;EAC9C,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC;EACjD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;EACzC,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,qBAAqB,IAAI,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC;EAC/F,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,YAAY,KAAK,SAAS,IAAI,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;EAC9G,kDAEK,MAAM;IAAC,OAAO;IAAA,IAAa,QAAQ;MAAA,OAAE,QAAQ,CAAC,CAAC;IAAA;IAAA,IAAE,OAAO;MAAA,OAAE,KAAK,CAAC,SAAS;IAAA;IAAA;MAAA,OACvE,cAAc,CAAC,CAAC,CAAC,OAAO;IAAA;EAAA,gCAE1B,MAAM;IAAA,IACL,OAAO;MAAA,OAAE,KAAK,CAAC,WAAW,IAAI,SAAS;IAAA;IAAA,IACvC,OAAO;MAAA,OAAE,OAAO,CAAC,CAAC;IAAA;IAAA,IAClB,YAAY;MAAA,OAAE,gBAAgB,CAAC,CAAC,CAAC,MAAM;IAAA;IAAA,IACvC,QAAQ;MAAA,OAAE,YAAY,CAAC,CAAC;IAAA;IAAA,IACxB,OAAO;MAAA,OAAE,KAAK,CAAC,MAAM;IAAA;IAAA;MAAA,yBAGpB,KAAK,CAAC,SAAS,IAAI,gBAAgB,CAAC,CAAC,CAAC,WAAW;IAAA;EAAA;AAI1D,CAAC;AAED,OAAO,SAAS,eAAe,CAAC,KAA2B,EAAe;EACxE,MAAM,gBAAgB,GAAG,mBAAmB,CAAC,CAAC;EAC9C,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC;EACjD,yBACG,IAAI;IAAA,IAAC,IAAI;MAAA,OAAE,WAAW,CAAC,CAAC,GAAG,CAAC;IAAA;IAAA;MAAA,uBACf,kCAAyB,KAAK,CAAC,KAAK,IAAI,EAAE,SAAE,WAE3C,WAAW,CAAC,CAAC,YAAY,gBAAgB,CAAC,CAAC,CAAC,kBAAkB,CAAC;QAAE,KAAK,EAAE,WAAW,CAAC;MAAE,CAAC,CAAC,8BAElG,eAAe,EAAK,KAAK;IAAA;EAAA;AAIlC;AAIA,OAAO,SAAS,mBAAmB,CAAC,KAA+B,EAAe;EAChF,MAAM,gBAAgB,GAAG,mBAAmB,CAAC,CAAC;EAC9C,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC;EACjD,mDAGO,IAAI;IAAA,IAAC,IAAI;MAAA,OAAE,WAAW,CAAC,CAAC,GAAG,CAAC;IAAA;IAAA,IAAE,QAAQ;MAAA,OAAE,gBAAgB,CAAC,CAAC,CAAC,gBAAgB;IAAA;IAAA;MAAA,iCACjE,WAAW,CAAC,CAAC,SAAY,gBAAgB,CAAC,CAAC,CAAC,kBAAkB,CAAC;QAAE,KAAK,EAAE,WAAW,CAAC;MAAE,CAAC,CAAC;IAAA;EAAA,wBAGpG,eAAe,eAAK,KAAK;IAAE,qBAAqB;EAAA;AAGvD;AAmBA,MAAM,gBAAiD,GAAG;EACxD,KAAK,EAAE,aAAa;EACpB,KAAK,EAAE,cAAc;EACrB,MAAM,EAAE,gBAAgB;EACxB,MAAM,EAAE,sBAAsB;EAC9B,OAAO,EAAE,sBAAsB;EAC/B,OAAO,EAAE,mBAAmB;EAC5B,QAAQ,EAAE;AACZ,CAAC;;AAED;AACA;AACA;AACA;AACA,OAAO,SAAS,UAAU,CAAC,KAAsB,EAAe;EAC9D,MAAM,gBAAgB,GAAG,mBAAmB,CAAC,CAAC;EAC9C,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;EACrC,MAAM,IAAI,GAAG,MAAM;IACjB,MAAM,CAAC,GAAG,gBAAgB,CAAC,CAAC;IAC5B,QAAQ,KAAK,CAAC,CAAC;MACb,KAAK,OAAO;QAAE;UACZ,MAAM,EAAE,GAAG,KAAK,CAAC,OAAO,KAAK,SAAS,GAAG,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;UACxE,OAAO,EAAE,GAAG,CAAC,CAAC,aAAa,CAAC;YAAE,IAAI,EAAE;UAAG,CAAC,CAAC,GAAG,CAAC,CAAC,WAAW;QAC3D;MACA,KAAK,OAAO;QACV,OAAO,CAAC,CAAC,WAAW;MACtB,KAAK,QAAQ;QACX,OAAO,CAAC,CAAC,MAAM;MACjB,KAAK,QAAQ;QACX,OAAO,CAAC,CAAC,YAAY;MACvB,KAAK,SAAS;QACZ,OAAO,CAAC,CAAC,aAAa,CAAC;UAAE,KAAK,EAAE,KAAK,CAAC,YAAY,KAAK,SAAS,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY;QAAE,CAAC,CAAC;MACpG,KAAK,SAAS;QACZ,OAAO,CAAC,CAAC,aAAa;MACxB,KAAK,UAAU;QACb,OAAO,CAAC,CAAC,cAAc;IAC3B;EACF,CAAC;EACD,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,CAAC,KAAK,UAAU;EAC3F,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,CAAC,KAAK,OAAO,IAAI,KAAK,CAAC,CAAC,KAAK,QAAQ,IAAI,KAAK,CAAC,CAAC,KAAK,SAAS,IAAI,KAAK,CAAC,CAAC,KAAK,QAAQ;EAClH,uBACc,4BAAmB,KAAK,CAAC,KAAK,IAAI,EAAE,SAAE,wCAEG,KAAK,CAAC,CAAC,iBAC5C,YAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC,UAAG,KAAK,CAAC,CAAC,KAAK,QAAQ,GAAG,WAAW,GAAG,EAAE,EAAE,WACjF,IAAI,CAAC,CAAC,8BAGV,IAAI;IAAA,IAAC,IAAI;MAAA,OAAE,UAAU,CAAC,CAAC;IAAA;IAAA;MAAA,yBACrB,eAAe;QACd,WAAW,EAAE,MAAO,OAAO,CAAC,CAAC,GAAG,CAAC,GAAG,CAAE;QACtC,OAAO,EAAE,MAAM,KAAK,CAAC,CAAC,KAAK,QAAQ;QACnC,YAAY,EAAE,MAAM,KAAK,CAAC,CAAC,KAAK,SAAS,IAAI,OAAO,CAAC,KAAK,CAAC,YAAY,KAAK,SAAS,IAAI,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QAAA,IAClH,SAAS;UAAA,OAAE,KAAK,CAAC,SAAS;QAAA;QAAA,IAC1B,MAAM;UAAA,OAAE,KAAK,CAAC,MAAM;QAAA;QAAA,IACpB,SAAS;UAAA,OAAE,KAAK,CAAC,SAAS,IAAI,gBAAgB,CAAC,CAAC,CAAC,IAAI;QAAA;QACrD,qBAAqB;MAAA;IAAA;EAAA;AAK/B","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":[]}
@@ -13,6 +13,7 @@ var _tmpl$ = ["<button", " type=\"button\" role=\"tab\"", ">", "<span class=\"k2
13
13
  _tmpl$8 = ["<footer class=\"k2b-settings__footer\">", "</footer>"];
14
14
  import { children, createEffect, createMemo, createSignal, createUniqueId, For, Show } from "solid-js";
15
15
  import { IconButton } from "../actions/Button";
16
+ import { revealInScroller } from "../internal/reveal-in-scroller";
16
17
  import { useUiMessages } from "../intl/messages";
17
18
  import { createScrollFade } from "./scroll-fade";
18
19
  import { useSettingsMessages } from "./settings-messages";
@@ -95,10 +96,7 @@ const SettingsModal = props => {
95
96
  // `defaultTab`, `activeTab` and clicks can select a category past the edge of the scrolling row or rail.
96
97
  createEffect(() => {
97
98
  const id = resolvedActiveTabId();
98
- queueMicrotask(() => tabRefs.get(id)?.scrollIntoView?.({
99
- block: "nearest",
100
- inline: "nearest"
101
- }));
99
+ queueMicrotask(() => revealInScroller(tabList, tabRefs.get(id)));
102
100
  });
103
101
  // A memo, so a change elsewhere in the tab list does not create the open panel again.
104
102
  const activeTab = createMemo(() => tabs().find(tab => tab.props.id === resolvedActiveTabId()) ?? null);