@k2b/ui 0.44.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.
- package/dist/browser/actions/Tabs.js +3 -4
- package/dist/browser/actions/Tabs.js.map +1 -1
- package/dist/browser/actions/menu-sheet.js +2 -3
- package/dist/browser/actions/menu-sheet.js.map +1 -1
- package/dist/browser/actions/phone-sheet.js +4 -0
- package/dist/browser/actions/phone-sheet.js.map +1 -0
- package/dist/browser/content/DataTable.js +47 -51
- package/dist/browser/content/DataTable.js.map +1 -1
- package/dist/browser/feedback/dialog-core.js +5 -1
- package/dist/browser/feedback/dialog-core.js.map +1 -1
- package/dist/browser/feedback/dialog-tone.js +26 -0
- package/dist/browser/feedback/dialog-tone.js.map +1 -0
- package/dist/browser/feedback/index.js.map +1 -1
- package/dist/browser/feedback/prompt-confirm.js +223 -0
- package/dist/browser/feedback/prompt-confirm.js.map +1 -0
- package/dist/browser/feedback/prompts.js +195 -343
- package/dist/browser/feedback/prompts.js.map +1 -1
- package/dist/browser/inputs/ChoiceList.js +45 -17
- package/dist/browser/inputs/ChoiceList.js.map +1 -1
- package/dist/browser/inputs/DatePicker.js +1647 -334
- package/dist/browser/inputs/DatePicker.js.map +1 -1
- package/dist/browser/inputs/TextInput.js +5 -4
- package/dist/browser/inputs/TextInput.js.map +1 -1
- package/dist/browser/inputs/date-input-messages.js +128 -0
- package/dist/browser/inputs/date-input-messages.js.map +1 -0
- package/dist/browser/inputs/date-input-status.js +132 -0
- package/dist/browser/inputs/date-input-status.js.map +1 -0
- package/dist/browser/inputs/date-input.js +334 -0
- package/dist/browser/inputs/date-input.js.map +1 -0
- package/dist/browser/inputs/date-sheet.js +49 -0
- package/dist/browser/inputs/date-sheet.js.map +1 -0
- package/dist/browser/internal/reveal-in-scroller.js +28 -0
- package/dist/browser/internal/reveal-in-scroller.js.map +1 -0
- package/dist/browser/intl/messages.js +6 -0
- package/dist/browser/intl/messages.js.map +1 -1
- package/dist/browser/layout/AppWorkspace.js +536 -512
- package/dist/browser/layout/AppWorkspace.js.map +1 -1
- package/dist/browser/layout/BottomSheet.js +3 -0
- package/dist/browser/layout/BottomSheet.js.map +1 -1
- package/dist/browser/layout/PanelDialog.js +167 -132
- package/dist/browser/layout/PanelDialog.js.map +1 -1
- package/dist/browser/layout/Settings.js +175 -139
- package/dist/browser/layout/Settings.js.map +1 -1
- package/dist/browser/layout/SettingsModal.js +2 -4
- package/dist/browser/layout/SettingsModal.js.map +1 -1
- package/dist/browser/layout/index.js.map +1 -1
- package/dist/browser/surfaces/StatusBadge.js +47 -14
- package/dist/browser/surfaces/StatusBadge.js.map +1 -1
- package/dist/browser/text-editor/TextEditor.js +7 -0
- package/dist/browser/text-editor/TextEditor.js.map +1 -1
- package/dist/ssr/actions/Tabs.js +3 -4
- package/dist/ssr/actions/Tabs.js.map +1 -1
- package/dist/ssr/actions/menu-sheet.js +2 -3
- package/dist/ssr/actions/menu-sheet.js.map +1 -1
- package/dist/ssr/actions/phone-sheet.js +4 -0
- package/dist/ssr/actions/phone-sheet.js.map +1 -0
- package/dist/ssr/content/DataTable.js +1 -2
- package/dist/ssr/content/DataTable.js.map +1 -1
- package/dist/ssr/feedback/dialog-core.js +5 -1
- package/dist/ssr/feedback/dialog-core.js.map +1 -1
- package/dist/ssr/feedback/dialog-tone.js +26 -0
- package/dist/ssr/feedback/dialog-tone.js.map +1 -0
- package/dist/ssr/feedback/index.js.map +1 -1
- package/dist/ssr/feedback/prompt-confirm.js +123 -0
- package/dist/ssr/feedback/prompt-confirm.js.map +1 -0
- package/dist/ssr/feedback/prompts.js +60 -132
- package/dist/ssr/feedback/prompts.js.map +1 -1
- package/dist/ssr/inputs/ChoiceList.js +29 -9
- package/dist/ssr/inputs/ChoiceList.js.map +1 -1
- package/dist/ssr/inputs/DatePicker.js +1183 -166
- package/dist/ssr/inputs/DatePicker.js.map +1 -1
- package/dist/ssr/inputs/TextInput.js +5 -4
- package/dist/ssr/inputs/TextInput.js.map +1 -1
- package/dist/ssr/inputs/date-input-messages.js +128 -0
- package/dist/ssr/inputs/date-input-messages.js.map +1 -0
- package/dist/ssr/inputs/date-input-status.js +132 -0
- package/dist/ssr/inputs/date-input-status.js.map +1 -0
- package/dist/ssr/inputs/date-input.js +334 -0
- package/dist/ssr/inputs/date-input.js.map +1 -0
- package/dist/ssr/inputs/date-sheet.js +44 -0
- package/dist/ssr/inputs/date-sheet.js.map +1 -0
- package/dist/ssr/internal/reveal-in-scroller.js +28 -0
- package/dist/ssr/internal/reveal-in-scroller.js.map +1 -0
- package/dist/ssr/intl/messages.js +6 -0
- package/dist/ssr/intl/messages.js.map +1 -1
- package/dist/ssr/layout/AppWorkspace.js +44 -23
- package/dist/ssr/layout/AppWorkspace.js.map +1 -1
- package/dist/ssr/layout/BottomSheet.js +3 -0
- package/dist/ssr/layout/BottomSheet.js.map +1 -1
- package/dist/ssr/layout/PanelDialog.js +48 -30
- package/dist/ssr/layout/PanelDialog.js.map +1 -1
- package/dist/ssr/layout/Settings.js +34 -18
- package/dist/ssr/layout/Settings.js.map +1 -1
- package/dist/ssr/layout/SettingsModal.js +2 -4
- package/dist/ssr/layout/SettingsModal.js.map +1 -1
- package/dist/ssr/layout/index.js.map +1 -1
- package/dist/ssr/surfaces/StatusBadge.js +26 -8
- package/dist/ssr/surfaces/StatusBadge.js.map +1 -1
- package/dist/ssr/text-editor/TextEditor.js +7 -0
- package/dist/ssr/text-editor/TextEditor.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/types/actions/menu-sheet.d.ts +1 -3
- package/dist/types/actions/phone-sheet.d.ts +3 -0
- package/dist/types/feedback/dialog-tone.d.ts +10 -0
- package/dist/types/feedback/index.d.ts +1 -0
- package/dist/types/feedback/prompt-confirm.d.ts +19 -0
- package/dist/types/feedback/prompts.d.ts +4 -8
- package/dist/types/inputs/ChoiceList.d.ts +7 -3
- package/dist/types/inputs/DatePicker.d.ts +13 -3
- package/dist/types/inputs/TextInput.d.ts +1 -1
- package/dist/types/inputs/date-input-messages.d.ts +64 -0
- package/dist/types/inputs/date-input-status.d.ts +35 -0
- package/dist/types/inputs/date-input.d.ts +90 -0
- package/dist/types/inputs/date-sheet.d.ts +14 -0
- package/dist/types/internal/reveal-in-scroller.d.ts +6 -0
- package/dist/types/intl/messages.d.ts +3 -0
- package/dist/types/layout/AppWorkspace.d.ts +14 -0
- package/dist/types/layout/BottomSheet.d.ts +3 -0
- package/dist/types/layout/PanelDialog.d.ts +3 -0
- package/dist/types/layout/Settings.d.ts +17 -1
- package/dist/types/layout/index.d.ts +1 -1
- package/dist/types/surfaces/StatusBadge.d.ts +5 -0
- package/package.json +1 -1
|
@@ -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;
|
|
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\"
|
|
10
|
-
_tmpl$5 = ["<span class=\"k2b-panel-dialog__icon k2b-icon-tile\" aria-hidden=\"true\"><i", "></i></span>"],
|
|
11
|
-
_tmpl$6 = ["<
|
|
12
|
-
_tmpl$7 = ["<
|
|
13
|
-
_tmpl$8 = ["<
|
|
14
|
-
_tmpl$9 = ["<span class=\"k2b-panel-dialog__section-
|
|
15
|
-
_tmpl$0 = "<
|
|
16
|
-
_tmpl$1 =
|
|
17
|
-
_tmpl$10 = ["<
|
|
18
|
-
_tmpl$11 = "<
|
|
19
|
-
_tmpl$12 =
|
|
20
|
-
_tmpl$13 = ["<
|
|
21
|
-
_tmpl$14 = ["<
|
|
22
|
-
_tmpl$15 = ["<
|
|
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
|
|
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
|
|
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:
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
141
|
-
}), _$ssr(_tmpl$
|
|
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$
|
|
159
|
+
return _$ssr(_tmpl$9, _$escape(props.subtitle));
|
|
147
160
|
}
|
|
148
|
-
}))), _$ssr(_tmpl$
|
|
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$
|
|
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$
|
|
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$
|
|
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 _$
|
|
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=\"
|
|
20
|
-
_tmpl$11 = ["<
|
|
21
|
-
_tmpl$12 = "<i class=\"ti ti-
|
|
22
|
-
_tmpl$13 =
|
|
23
|
-
_tmpl$14 = ["<div class=\"
|
|
24
|
-
_tmpl$15 = ["<strong>", "</strong>"],
|
|
25
|
-
_tmpl$16 = ["<
|
|
26
|
-
_tmpl$17 = ["<
|
|
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.
|
|
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
|
-
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":[],"sources":["layout/Settings.tsx"],"sourcesContent":["import { children, createMemo, createUniqueId, type JSX, Show } from \"solid-js\";\nimport { Button, type ButtonVariant } from \"../actions/Button\";\nimport { usePromptMessages } from \"../feedback/prompt-messages\";\nimport type { MaybeAccessor } from \"../inputs/field-contract\";\nimport { useSettingsMessages } from \"./settings-messages\";\n\nconst read = <T,>(value: MaybeAccessor<T>): T => (typeof value === \"function\" ? (value as () => T)() : value);\n\nexport type SettingsPageProps = {\n title: JSX.Element;\n /** False when a surrounding head already shows the title, such as a workspace level; the actions move to the footer. */\n header?: boolean;\n subtitle?: JSX.Element;\n icon?: string;\n actions?: JSX.Element;\n children: JSX.Element;\n footer?: JSX.Element;\n scrollPreserveKey?: string;\n class?: string;\n style?: JSX.CSSProperties | string;\n};\n\nexport function SettingsPage(props: SettingsPageProps): JSX.Element {\n return (\n <section\n class={`k2b-settings-page${props.class ? ` ${props.class}` : \"\"}`}\n style={props.style}\n aria-label={props.header === false && typeof props.title === \"string\" ? props.title : undefined}\n >\n <Show when={props.header !== false}>\n <header class=\"k2b-settings-page__header\">\n <Show when={props.icon}>{(icon) => <i class={icon()} aria-hidden=\"true\" />}</Show>\n <div class=\"k2b-settings-page__heading\">\n <h1>{props.title}</h1>\n <Show when={props.subtitle}>\n <p>{props.subtitle}</p>\n </Show>\n </div>\n <Show when={props.actions}>\n <div class=\"k2b-settings-page__actions\">{props.actions}</div>\n </Show>\n </header>\n </Show>\n <div class=\"k2b-settings-page__body\" data-scroll-preserve={props.scrollPreserveKey}>\n {props.children}\n </div>\n <Show when={props.footer}>\n <footer class=\"k2b-settings-page__footer\">{props.footer}</footer>\n </Show>\n </section>\n );\n}\n\nexport type SettingsSectionProps = {\n title: JSX.Element;\n subtitle?: JSX.Element;\n icon?: string;\n actions?: JSX.Element;\n children: JSX.Element;\n class?: string;\n};\n\n/**\n * A full-page settings group: a heading, optional actions and its fields on the\n * page surface without a card. From 860 px of its own width the heading takes a\n * column beside the fields. Dialogs keep using PanelDialog.Section.\n */\nexport function SettingsSection(props: SettingsSectionProps): JSX.Element {\n const headingId = `k2b-settings-section-${createUniqueId()}`;\n return (\n <section class={`k2b-settings-section${props.class ? ` ${props.class}` : \"\"}`} aria-labelledby={headingId}>\n <div class=\"k2b-settings-section__layout\">\n <header class=\"k2b-settings-section__header\">\n <Show when={props.icon}>{(icon) => <i class={icon()} aria-hidden=\"true\" />}</Show>\n <div class=\"k2b-settings-section__heading\">\n <h2 id={headingId}>{props.title}</h2>\n <Show when={props.subtitle}>\n <p>{props.subtitle}</p>\n </Show>\n </div>\n <Show when={props.actions}>\n <div class=\"k2b-settings-section__actions\">{props.actions}</div>\n </Show>\n </header>\n <div class=\"k2b-settings-section__body\">{props.children}</div>\n </div>\n </section>\n );\n}\n\nconst SETTINGS_GROUP_ACTION = Symbol(\"SettingsGroup.Action\");\n\nexport type SettingsGroupProps = {\n title: JSX.Element;\n description?: JSX.Element;\n children: JSX.Element;\n class?: string;\n};\n\nexport type SettingsGroupActionProps = {\n children: JSX.Element;\n};\n\ntype SettingsGroupActionDefinition = {\n readonly kind: typeof SETTINGS_GROUP_ACTION;\n readonly props: SettingsGroupActionProps;\n};\n\ntype SettingsGroupComponent = ((props: SettingsGroupProps) => JSX.Element) & {\n Action: (props: SettingsGroupActionProps) => JSX.Element;\n};\n\nconst SettingsGroupAction = (props: SettingsGroupActionProps): JSX.Element =>\n ({ kind: SETTINGS_GROUP_ACTION, props }) satisfies SettingsGroupActionDefinition as unknown as JSX.Element;\n\nconst collectSettingsGroupActions = (value: unknown): SettingsGroupActionDefinition[] => {\n if (Array.isArray(value)) return value.flatMap(collectSettingsGroupActions);\n return value && typeof value === \"object\" && (value as { kind?: unknown }).kind === SETTINGS_GROUP_ACTION\n ? [value as SettingsGroupActionDefinition]\n : [];\n};\n\nconst collectSettingsGroupContent = (value: unknown): JSX.Element[] => {\n if (Array.isArray(value)) return value.flatMap(collectSettingsGroupContent);\n return value && typeof value === \"object\" && (value as { kind?: unknown }).kind === SETTINGS_GROUP_ACTION ? [] : [value as JSX.Element];\n};\n\nexport const SettingsGroup = ((props: SettingsGroupProps): JSX.Element => {\n const resolved = children(() => props.children);\n const action = createMemo(() => collectSettingsGroupActions(resolved())[0]);\n const content = createMemo(() => collectSettingsGroupContent(resolved()));\n const headingId = `k2b-settings-group-${createUniqueId()}`;\n return (\n <section class={`k2b-settings-group${props.class ? ` ${props.class}` : \"\"}`} aria-labelledby={headingId}>\n <header class=\"k2b-settings-group__header\">\n <div class=\"k2b-settings-group__heading\">\n <h3 id={headingId}>{props.title}</h3>\n <Show when={props.description}>\n <p>{props.description}</p>\n </Show>\n </div>\n <Show when={action()}>{(slot) => <div class=\"k2b-settings-group__action\">{slot().props.children}</div>}</Show>\n </header>\n <div class=\"k2b-settings-group__body\">{content()}</div>\n </section>\n );\n}) as SettingsGroupComponent;\n\nSettingsGroup.Action = SettingsGroupAction;\n\nexport const sameSettingValue = (left: unknown, right: unknown): boolean => JSON.stringify(left) === JSON.stringify(right);\n\nexport const readSettingsError = async (\n response: Pick<Response, \"json\">,\n fallback: string,\n): Promise<{ message: string; fields: Record<string, string> }> => {\n const data = (await response.json().catch(() => null)) as {\n message?: string;\n errors?: Record<string, string>;\n } | null;\n return { message: data?.message ?? fallback, fields: data?.errors ?? {} };\n};\n\n/**\n * The room a setting's control takes: `short` for a number, `medium` for a choice, `long` for text, and `full` for\n * an editor, which keeps its name above it and takes the whole row.\n */\nexport type SettingsFieldWidth = \"short\" | \"medium\" | \"long\" | \"full\";\n\nexport type SettingsFieldProps = {\n label: string;\n /** One sentence of help; longer guidance belongs in the page's guide. */\n description: string;\n error: MaybeAccessor<string | undefined>;\n changed?: MaybeAccessor<boolean>;\n /**\n * Where the value comes from, at a fixed place after the control: quiet text such as \"Default\", or the one way\n * back to it, such as a Reset button that only a value of its own shows.\n */\n source?: JSX.Element;\n /** The control's width by kind, so a number never stretches like a URL. Defaults to `long`, the full column. */\n width?: SettingsFieldWidth;\n /** The row's id, for a link that leads to this one setting. */\n id?: string;\n children: JSX.Element | ((control: SettingsFieldControlProps) => JSX.Element);\n class?: string;\n};\n\nexport type SettingsFieldControlProps = {\n describedBy: () => string;\n};\n\nexport function SettingsField(props: SettingsFieldProps): JSX.Element {\n const settingsMessages = useSettingsMessages();\n const id = createUniqueId();\n const descriptionId = `k2b-settings-field-${id}-description`;\n const errorId = `k2b-settings-field-${id}-error`;\n const describedBy = () => (read(props.error) ? `${descriptionId} ${errorId}` : descriptionId);\n const control = () =>\n typeof props.children === \"function\"\n ? (props.children as (control: SettingsFieldControlProps) => JSX.Element)({ describedBy })\n : props.children;\n const source = children(() => props.source);\n return (\n <div id={props.id} class={`k2b-settings-field ${props.class ?? \"\"}`} data-width={props.width ?? \"long\"}>\n <div class=\"k2b-settings-field__row\">\n <div class=\"k2b-settings-field__copy\">\n <div class=\"k2b-settings-field__heading\">\n <strong>{props.label}</strong>\n <Show when={props.changed !== undefined && read(props.changed)}>\n <span>{settingsMessages().unsaved}</span>\n </Show>\n </div>\n <p id={descriptionId}>{props.description}</p>\n </div>\n <div class=\"k2b-settings-field__control\">\n {control()}\n <Show when={read(props.error)}>\n {(error) => (\n <p id={errorId} class=\"k2b-settings-field__error\" role=\"alert\">\n <i class=\"ti ti-alert-circle\" aria-hidden=\"true\" /> {error()}\n </p>\n )}\n </Show>\n </div>\n <Show when={source()}>\n <div class=\"k2b-settings-field__source\">{source()}</div>\n </Show>\n </div>\n </div>\n );\n}\n\nexport type SettingsSaveBarProps = {\n changeCount: MaybeAccessor<number>;\n loading: MaybeAccessor<boolean>;\n saveDisabled?: MaybeAccessor<boolean>;\n onDiscard: () => void;\n onSave: () => void;\n saveLabel?: string;\n saveVariant?: ButtonVariant;\n class?: string;\n};\n\nconst SettingsActions = (\n props: SettingsSaveBarProps & {\n disableWithoutChanges?: boolean;\n },\n): JSX.Element => {\n const promptMessages = usePromptMessages();\n const settingsMessages = useSettingsMessages();\n const changeCount = () => read(props.changeCount);\n const loading = () => read(props.loading);\n const disabled = () => loading() || Boolean(props.disableWithoutChanges && changeCount() === 0);\n const saveDisabled = () => disabled() || Boolean(props.saveDisabled !== undefined && read(props.saveDisabled));\n return (\n <div class=\"k2b-settings-actions\">\n <Button variant=\"secondary\" disabled={disabled()} onClick={props.onDiscard}>\n {promptMessages().discard}\n </Button>\n <Button\n variant={props.saveVariant ?? \"primary\"}\n loading={loading()}\n loadingLabel={settingsMessages().saving}\n disabled={saveDisabled()}\n onClick={props.onSave}\n >\n <i class=\"ti ti-device-floppy\" aria-hidden=\"true\" />\n {props.saveLabel ?? settingsMessages().saveChanges}\n </Button>\n </div>\n );\n};\n\nexport function SettingsSaveBar(props: SettingsSaveBarProps): JSX.Element {\n const settingsMessages = useSettingsMessages();\n const changeCount = () => read(props.changeCount);\n return (\n <Show when={changeCount() > 0}>\n <div class={`k2b-settings-save-bar ${props.class ?? \"\"}`}>\n <p role=\"status\" aria-live=\"polite\">\n <strong>{changeCount()}</strong> {settingsMessages().unsavedChangeLabel({ count: changeCount() })}\n </p>\n <SettingsActions {...props} />\n </div>\n </Show>\n );\n}\n\nexport type SettingsPanelFooterProps = SettingsSaveBarProps;\n\nexport function SettingsPanelFooter(props: SettingsPanelFooterProps): JSX.Element {\n const settingsMessages = useSettingsMessages();\n const changeCount = () => read(props.changeCount);\n return (\n <>\n <p class=\"k2b-settings-panel-footer__status\" role=\"status\" aria-live=\"polite\">\n <Show when={changeCount() > 0} fallback={settingsMessages().noUnsavedChanges}>\n <strong>{changeCount()}</strong> {settingsMessages().unsavedChangeLabel({ count: changeCount() })}\n </Show>\n </p>\n <SettingsActions {...props} disableWithoutChanges />\n </>\n );\n}\n\nexport type SaveStatusState = \"saved\" | \"draft\" | \"saving\" | \"failed\" | \"invalid\" | \"unknown\" | \"readonly\";\n\nexport type SaveStatusProps = {\n /** What the person's values are now: saved, a draft with changes, being saved, or a problem that kept them unsaved. */\n state: MaybeAccessor<SaveStatusState>;\n /** Formatted time of the last save, shown with `saved`. */\n savedAt?: MaybeAccessor<string | undefined>;\n /** Fields to check, shown with `invalid`. Default 1. */\n invalidCount?: MaybeAccessor<number>;\n /** With both handlers, Discard and Save follow the status while there is something to save. */\n onDiscard?: () => void;\n onSave?: () => void;\n saveLabel?: string;\n saveDisabled?: MaybeAccessor<boolean>;\n class?: string;\n};\n\nconst SAVE_STATUS_ICON: Record<SaveStatusState, string> = {\n saved: \"ti ti-check\",\n draft: \"ti ti-pencil\",\n saving: \"ti ti-loader-2\",\n failed: \"ti ti-alert-triangle\",\n invalid: \"ti ti-alert-triangle\",\n unknown: \"ti ti-help-circle\",\n readonly: \"ti ti-lock\",\n};\n\n/**\n * The save status of a settings form at one fixed place, usually the head of its column. It reserves its width, so\n * a change of state never moves the title or the buttons beside it. Problems with one field stay at that field.\n */\nexport function SaveStatus(props: SaveStatusProps): JSX.Element {\n const settingsMessages = useSettingsMessages();\n const state = () => read(props.state);\n const text = () => {\n const t = settingsMessages();\n switch (state()) {\n case \"saved\": {\n const at = props.savedAt === undefined ? undefined : read(props.savedAt);\n return at ? t.statusSavedAt({ time: at }) : t.statusSaved;\n }\n case \"draft\":\n return t.statusDraft;\n case \"saving\":\n return t.saving;\n case \"failed\":\n return t.statusFailed;\n case \"invalid\":\n return t.statusInvalid({ count: props.invalidCount === undefined ? 1 : read(props.invalidCount) });\n case \"unknown\":\n return t.statusUnknown;\n case \"readonly\":\n return t.statusReadOnly;\n }\n };\n const hasActions = () => Boolean(props.onSave && props.onDiscard) && state() !== \"readonly\";\n const pending = () => state() === \"draft\" || state() === \"failed\" || state() === \"invalid\" || state() === \"saving\";\n return (\n <div class={`k2b-save-status ${props.class ?? \"\"}`}>\n <span class=\"k2b-save-status__slot\">\n <span class=\"k2b-save-status__state\" data-state={state()} role=\"status\" aria-live=\"polite\">\n <i class={`${SAVE_STATUS_ICON[state()]}${state() === \"saving\" ? \" k2b-spin\" : \"\"}`} aria-hidden=\"true\" />\n {text()}\n </span>\n </span>\n <Show when={hasActions()}>\n <SettingsActions\n changeCount={() => (pending() ? 1 : 0)}\n loading={() => state() === \"saving\"}\n saveDisabled={() => state() === \"invalid\" || Boolean(props.saveDisabled !== undefined && read(props.saveDisabled))}\n onDiscard={props.onDiscard!}\n onSave={props.onSave!}\n saveLabel={props.saveLabel ?? settingsMessages().save}\n disableWithoutChanges\n />\n </Show>\n </div>\n );\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -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)
|
|
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);
|