@k2b/ui 0.45.0 → 0.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/actions/Dropdown.js +8 -1
- package/dist/browser/actions/Dropdown.js.map +1 -1
- package/dist/browser/actions/FilterChip.js +11 -5
- package/dist/browser/actions/FilterChip.js.map +1 -1
- package/dist/browser/actions/ViewTabs.js +225 -93
- package/dist/browser/actions/ViewTabs.js.map +1 -1
- package/dist/browser/content/FileGrid.js +125 -99
- package/dist/browser/content/FileGrid.js.map +1 -1
- package/dist/browser/inputs/choice.js +36 -9
- package/dist/browser/inputs/choice.js.map +1 -1
- package/dist/browser/layout/AppWorkspace.js +30 -26
- package/dist/browser/layout/AppWorkspace.js.map +1 -1
- package/dist/browser/layout/DetailPanel.js +130 -108
- package/dist/browser/layout/DetailPanel.js.map +1 -1
- package/dist/browser/layout/DetailSections.js +1019 -0
- package/dist/browser/layout/DetailSections.js.map +1 -0
- package/dist/browser/layout/DetailsToggle.js +32 -0
- package/dist/browser/layout/DetailsToggle.js.map +1 -0
- package/dist/browser/layout/Discussion.js +3 -0
- package/dist/browser/layout/Discussion.js.map +1 -1
- package/dist/browser/layout/MobileShell.js +116 -94
- package/dist/browser/layout/MobileShell.js.map +1 -1
- package/dist/browser/layout/PageTitle.js +33 -10
- package/dist/browser/layout/PageTitle.js.map +1 -1
- package/dist/browser/layout/app-workspace-controller.js +12 -0
- package/dist/browser/layout/app-workspace-controller.js.map +1 -1
- package/dist/browser/layout/detail-sections-messages.js +123 -0
- package/dist/browser/layout/detail-sections-messages.js.map +1 -0
- package/dist/browser/layout/index.js +2 -0
- package/dist/browser/layout/index.js.map +1 -1
- package/dist/browser/surfaces/Avatar.js +3 -1
- package/dist/browser/surfaces/Avatar.js.map +1 -1
- package/dist/browser/surfaces/AvatarStack.js +95 -61
- package/dist/browser/surfaces/AvatarStack.js.map +1 -1
- package/dist/browser/surfaces/ChangeList.js +77 -0
- package/dist/browser/surfaces/ChangeList.js.map +1 -0
- package/dist/browser/surfaces/index.js +2 -1
- package/dist/browser/surfaces/index.js.map +1 -1
- package/dist/browser/text-editor/TextEditor.js +19 -8
- package/dist/browser/text-editor/TextEditor.js.map +1 -1
- package/dist/ssr/actions/Dropdown.js +6 -0
- package/dist/ssr/actions/Dropdown.js.map +1 -1
- package/dist/ssr/actions/FilterChip.js +1 -1
- package/dist/ssr/actions/FilterChip.js.map +1 -1
- package/dist/ssr/actions/ViewTabs.js +144 -37
- package/dist/ssr/actions/ViewTabs.js.map +1 -1
- package/dist/ssr/content/FileGrid.js +36 -22
- package/dist/ssr/content/FileGrid.js.map +1 -1
- package/dist/ssr/inputs/choice.js +36 -9
- package/dist/ssr/inputs/choice.js.map +1 -1
- package/dist/ssr/layout/AppWorkspace.js +27 -27
- package/dist/ssr/layout/AppWorkspace.js.map +1 -1
- package/dist/ssr/layout/DetailPanel.js +17 -0
- package/dist/ssr/layout/DetailPanel.js.map +1 -1
- package/dist/ssr/layout/DetailSections.js +762 -0
- package/dist/ssr/layout/DetailSections.js.map +1 -0
- package/dist/ssr/layout/DetailsToggle.js +29 -0
- package/dist/ssr/layout/DetailsToggle.js.map +1 -0
- package/dist/ssr/layout/Discussion.js +3 -0
- package/dist/ssr/layout/Discussion.js.map +1 -1
- package/dist/ssr/layout/MobileShell.js +45 -28
- package/dist/ssr/layout/MobileShell.js.map +1 -1
- package/dist/ssr/layout/PageTitle.js +29 -6
- package/dist/ssr/layout/PageTitle.js.map +1 -1
- package/dist/ssr/layout/app-workspace-controller.js +12 -0
- package/dist/ssr/layout/app-workspace-controller.js.map +1 -1
- package/dist/ssr/layout/detail-sections-messages.js +123 -0
- package/dist/ssr/layout/detail-sections-messages.js.map +1 -0
- package/dist/ssr/layout/index.js +2 -0
- package/dist/ssr/layout/index.js.map +1 -1
- package/dist/ssr/surfaces/Avatar.js +3 -1
- package/dist/ssr/surfaces/Avatar.js.map +1 -1
- package/dist/ssr/surfaces/AvatarStack.js +61 -32
- package/dist/ssr/surfaces/AvatarStack.js.map +1 -1
- package/dist/ssr/surfaces/ChangeList.js +37 -0
- package/dist/ssr/surfaces/ChangeList.js.map +1 -0
- package/dist/ssr/surfaces/index.js +2 -1
- package/dist/ssr/surfaces/index.js.map +1 -1
- package/dist/ssr/text-editor/TextEditor.js +19 -8
- package/dist/ssr/text-editor/TextEditor.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/types/actions/FilterChip.d.ts +4 -0
- package/dist/types/actions/ViewTabs.d.ts +11 -1
- package/dist/types/content/FileGrid.d.ts +6 -0
- package/dist/types/inputs/choice.d.ts +9 -3
- package/dist/types/layout/DetailPanel.d.ts +9 -0
- package/dist/types/layout/DetailSections.d.ts +156 -0
- package/dist/types/layout/DetailsToggle.d.ts +13 -0
- package/dist/types/layout/PageTitle.d.ts +7 -0
- package/dist/types/layout/detail-sections-messages.d.ts +59 -0
- package/dist/types/layout/index.d.ts +4 -1
- package/dist/types/surfaces/Avatar.d.ts +3 -0
- package/dist/types/surfaces/AvatarStack.d.ts +20 -1
- package/dist/types/surfaces/ChangeList.d.ts +20 -0
- package/dist/types/surfaces/index.d.ts +5 -3
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["content/FileGrid.tsx"],"sourcesContent":["import { createEffect, createMemo, createSignal, createUniqueId, For, Index, type JSX, on, Show } from \"solid-js\";\nimport type { CollectionSelection } from \"./collection-selection\";\nimport { useFileListMessages } from \"./file-list-messages\";\n\n/** One part of an open file list, such as its files as rows and its images as tiles. */\nexport type FileGridGroup<T> = {\n id: string;\n label: JSX.Element;\n rows: readonly T[];\n /** `tiles` fills each item with its preview and lays the name over it. Defaults to `list`. */\n layout?: \"list\" | \"tiles\";\n};\n\ntype FileGridBaseProps<T> = {\n rows: readonly T[];\n getRowId: (row: T) => string;\n label: string;\n size?: \"sm\" | \"md\" | \"lg\";\n /** `list` shows one compact row per item: preview, name, and meta beside each other. Defaults to `grid`. */\n layout?: \"grid\" | \"list\";\n renderPreview: (row: T) => JSX.Element;\n renderLabel: (row: T) => JSX.Element;\n renderMeta?: (row: T) => JSX.Element;\n renderActions?: (row: T) => JSX.Element;\n /**\n * `progressive` shows the actions on hover, keyboard focus, or an open menu with a mouse or trackpad, and always\n * on touch. Their slot is reserved in both states, so nothing moves. Defaults to `always`.\n */\n actionVisibility?: \"always\" | \"progressive\";\n onOpen: (row: T) => void;\n onContextMenu?: (row: T) => void;\n /** Extra attributes for one tile, for example drag-and-drop handlers or data attributes the host styles. */\n itemProps?: (row: T) => JSX.HTMLAttributes<HTMLDivElement>;\n class?: string;\n};\n\n/** A browser or picker: items are selected, and Enter or a double click opens them. */\nexport type FileGridSelectableProps<T> = FileGridBaseProps<T> & {\n selection: CollectionSelection;\n onRowClick?: (row: T) => void;\n limit?: never;\n expanded?: never;\n onExpandedChange?: never;\n moreMeta?: never;\n toolbar?: never;\n groups?: never;\n};\n\n/** A list without selection, as in a details panel: one click on an item opens it. */\nexport type FileGridOpenProps<T> = FileGridBaseProps<T> & {\n selection?: never;\n onRowClick?: never;\n /** Shows the first `limit` items, then \"Show all N\", which opens the full list in place. Without it, the list is always full. */\n limit?: number;\n /** Controls whether the full list is open. Without it, the list keeps its own state. */\n expanded?: boolean;\n onExpandedChange?: (expanded: boolean) => void;\n /** A quiet note at the end of \"Show all N\", such as how many duplicates were merged. */\n moreMeta?: JSX.Element;\n /** Shown above the full list, such as a count, an arrangement switch, or \"Download all\"; not in the short list. */\n toolbar?: JSX.Element;\n /** How the full list arranges its items, such as files as rows, then images as tiles; the short list stays one list. */\n groups?: (rows: readonly T[]) => readonly FileGridGroup<T>[];\n};\n\nexport type FileGridProps<T> = FileGridSelectableProps<T> | FileGridOpenProps<T>;\n\n/**\n * File presentation only; the host owns data, menus, leases and permissions. Items the selection marks with\n * `isDisabled` stay reachable by keyboard but cannot be selected or opened; say why in `renderMeta`.\n */\nexport function FileGrid<T>(props: FileGridProps<T>) {\n return (\n <Show when={props.selection} fallback={<OpenFileGrid {...(props as FileGridOpenProps<T>)} />}>\n {(selection) => <SelectableFileGrid {...(props as FileGridSelectableProps<T>)} selection={selection()} />}\n </Show>\n );\n}\n\nfunction SelectableFileGrid<T>(props: FileGridSelectableProps<T>) {\n let grid: HTMLDivElement | undefined;\n // Both clicks of a double-click belong to the item that took the first one. When that click replaced the rows,\n // for example by opening a folder, the item now under the pointer ignores the rest of the gesture.\n let pressed: EventTarget | null | undefined;\n const ownsClick = (event: MouseEvent) => {\n if (event.detail > 1 && pressed !== event.currentTarget) pressed = null;\n else pressed = event.currentTarget;\n return pressed !== null;\n };\n const columns = () => (grid ? Math.max(1, getComputedStyle(grid).gridTemplateColumns.split(\" \").length) : 1);\n const nested = (event: Event) =>\n event.target instanceof Element &&\n !!event.target.closest(\"button,a,input,label,select,textarea,summary,[contenteditable],[role=button],[role=menu]\");\n return (\n <div\n ref={grid}\n class={`k2b-file-grid ${props.class ?? \"\"}`}\n data-size={props.size ?? \"md\"}\n data-layout={props.layout ?? \"grid\"}\n data-action-visibility={props.actionVisibility ?? \"always\"}\n role=\"grid\"\n aria-label={props.label}\n aria-multiselectable={props.selection.multiple}\n >\n <For each={props.rows}>\n {(row) => {\n const id = () => props.getRowId(row);\n const disabled = () => props.selection.isDisabled(id());\n return (\n <div role=\"row\" class=\"k2b-file-grid__row\">\n <div\n {...props.itemProps?.(row)}\n role=\"gridcell\"\n class=\"k2b-file-grid__item\"\n aria-selected={props.selection.selected().has(id())}\n aria-disabled={disabled() || undefined}\n ref={(element) => props.selection.register(id(), element)}\n tabIndex={props.selection.focused() === id() ? 0 : -1}\n onFocus={() => props.selection.markFocused(id())}\n onClick={(event) => {\n if (!nested(event) && ownsClick(event) && !disabled()) {\n props.selection.select(id(), event);\n props.onRowClick?.(row);\n }\n }}\n onDblClick={(event) => {\n if (!nested(event) && pressed !== null && !disabled()) props.onOpen(row);\n }}\n onContextMenu={() => props.onContextMenu?.(row)}\n onKeyDown={(event) => {\n if (nested(event)) return;\n if (props.selection.keyDown(event, id(), columns())) return;\n if (event.key === \"Enter\") {\n event.preventDefault();\n if (!disabled()) props.onOpen(row);\n }\n }}\n >\n <div class=\"k2b-file-grid__preview\">{props.renderPreview(row)}</div>\n <div class=\"k2b-file-grid__name\">{props.renderLabel(row)}</div>\n <div class=\"k2b-file-grid__meta\">{props.renderMeta?.(row)}</div>\n <div class=\"k2b-file-grid__actions\">{props.renderActions?.(row)}</div>\n </div>\n </div>\n );\n }}\n </For>\n </div>\n );\n}\n\nfunction OpenFileGrid<T>(props: FileGridOpenProps<T>) {\n const messages = useFileListMessages();\n const [ownExpanded, setOwnExpanded] = createSignal(false);\n const limited = () => props.limit !== undefined && props.rows.length > props.limit;\n // Without a limit the list is always complete, so its toolbar and groups always apply.\n const full = () => props.limit === undefined || (limited() && (props.expanded ?? ownExpanded()));\n let more: HTMLButtonElement | undefined;\n let less: HTMLButtonElement | undefined;\n let moveFocus = false;\n const toggle = (next: boolean) => {\n moveFocus = true;\n if (props.expanded === undefined) setOwnExpanded(next);\n props.onExpandedChange?.(next);\n };\n // The pressed button leaves with the state it showed; once the new state is there, focus moves to its\n // counterpart, also when a controlling host applies it later.\n createEffect(\n on(\n full,\n (open) => {\n if (!moveFocus) return;\n moveFocus = false;\n queueMicrotask(() => (open ? less : more)?.focus());\n },\n { defer: true },\n ),\n );\n const groups = createMemo((): readonly FileGridGroup<T>[] =>\n full() && props.groups\n ? props.groups(props.rows).filter((group) => group.rows.length > 0)\n : [{ id: \"rows\", label: undefined, rows: full() || !limited() ? props.rows : props.rows.slice(0, props.limit) }],\n );\n\n const list = (group: () => FileGridGroup<T>, labelId?: string) => (\n <div\n class={`k2b-file-grid ${props.class ?? \"\"}`}\n data-size={props.size ?? \"md\"}\n data-layout={group().layout === \"tiles\" ? \"tiles\" : (props.layout ?? \"grid\")}\n data-action-visibility={props.actionVisibility ?? \"always\"}\n data-open-items=\"true\"\n role=\"list\"\n aria-label={labelId ? undefined : props.label}\n aria-labelledby={labelId}\n >\n {/* Keyed by the row itself: new data keeps every existing item, its focus, and its state. */}\n <For each={group().rows}>\n {(row) => {\n const id = `k2b-file-grid-${createUniqueId()}`;\n return (\n <div role=\"listitem\" class=\"k2b-file-grid__row\">\n <div {...props.itemProps?.(row)} class=\"k2b-file-grid__item\">\n {/* The whole item opens the file; its actions lie above this layer in their own slot. */}\n <button\n type=\"button\"\n class=\"k2b-file-grid__open\"\n aria-labelledby={`${id}-name`}\n aria-describedby={props.renderMeta ? `${id}-meta` : undefined}\n onClick={() => props.onOpen(row)}\n onContextMenu={() => props.onContextMenu?.(row)}\n />\n <div class=\"k2b-file-grid__preview\">{props.renderPreview(row)}</div>\n <div class=\"k2b-file-grid__name\" id={`${id}-name`}>\n {props.renderLabel(row)}\n </div>\n <div class=\"k2b-file-grid__meta\" id={`${id}-meta`}>\n {props.renderMeta?.(row)}\n </div>\n <div class=\"k2b-file-grid__actions\">{props.renderActions?.(row)}</div>\n </div>\n </div>\n );\n }}\n </For>\n </div>\n );\n\n return (\n <div class=\"k2b-file-grid-stack\" data-expanded={full() ? \"true\" : undefined}>\n <Show when={full() && props.toolbar}>\n <div class=\"k2b-file-grid-stack__toolbar\">{props.toolbar}</div>\n </Show>\n {/* By position: a group that only changes its rows keeps its list, so new data remounts nothing. */}\n <Index each={groups()}>\n {(group) => {\n const labelId = `k2b-file-grid-group-${createUniqueId()}`;\n return (\n <Show when={group().label !== undefined} fallback={list(group)}>\n <div class=\"k2b-file-grid-stack__group\">\n <div class=\"k2b-file-grid-stack__label\" id={labelId}>\n {group().label}\n <span class=\"k2b-file-grid-stack__count\">{group().rows.length}</span>\n </div>\n {list(group, labelId)}\n </div>\n </Show>\n );\n }}\n </Index>\n <Show when={limited()}>\n <Show\n when={full()}\n fallback={\n <button ref={more} type=\"button\" class=\"k2b-file-grid-stack__more\" aria-expanded=\"false\" onClick={() => toggle(true)}>\n <span>{messages().showAll({ count: props.rows.length })}</span>\n <i class=\"ti ti-chevron-down\" aria-hidden=\"true\" />\n <Show when={props.moreMeta}>\n <span class=\"k2b-file-grid-stack__more-meta\">{props.moreMeta}</span>\n </Show>\n </button>\n }\n >\n <button ref={less} type=\"button\" class=\"k2b-file-grid-stack__more\" aria-expanded=\"true\" onClick={() => toggle(false)}>\n <span>{messages().showLess}</span>\n <i class=\"ti ti-chevron-up\" aria-hidden=\"true\" />\n </button>\n </Show>\n </Show>\n </div>\n );\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":[],"sources":["content/FileGrid.tsx"],"sourcesContent":["import { createEffect, createMemo, createSignal, createUniqueId, For, Index, type JSX, on, Show } from \"solid-js\";\nimport type { CollectionSelection } from \"./collection-selection\";\nimport { useFileListMessages } from \"./file-list-messages\";\n\n/** One part of an open file list, such as its files as rows and its images as tiles. */\nexport type FileGridGroup<T> = {\n id: string;\n label: JSX.Element;\n rows: readonly T[];\n /** `tiles` fills each item with its preview and lays the name over it. Defaults to `list`. */\n layout?: \"list\" | \"tiles\";\n};\n\ntype FileGridBaseProps<T> = {\n rows: readonly T[];\n getRowId: (row: T) => string;\n label: string;\n size?: \"sm\" | \"md\" | \"lg\";\n /** `list` shows one compact row per item: preview, name, and meta beside each other. Defaults to `grid`. */\n layout?: \"grid\" | \"list\";\n renderPreview: (row: T) => JSX.Element;\n renderLabel: (row: T) => JSX.Element;\n renderMeta?: (row: T) => JSX.Element;\n renderActions?: (row: T) => JSX.Element;\n /**\n * `progressive` shows the actions on hover, keyboard focus, or an open menu with a mouse or trackpad, and always\n * on touch. Their slot is reserved in both states, so nothing moves. Defaults to `always`.\n */\n actionVisibility?: \"always\" | \"progressive\";\n onOpen: (row: T) => void;\n onContextMenu?: (row: T) => void;\n /** Extra attributes for one tile, for example drag-and-drop handlers or data attributes the host styles. */\n itemProps?: (row: T) => JSX.HTMLAttributes<HTMLDivElement>;\n class?: string;\n};\n\n/** A browser or picker: items are selected, and Enter or a double click opens them. */\nexport type FileGridSelectableProps<T> = FileGridBaseProps<T> & {\n selection: CollectionSelection;\n onRowClick?: (row: T) => void;\n /**\n * Shows a check box before each item that `checks` returns `true` for, or a circle when only one item may be\n * selected. The check only mirrors the selection; items without one keep its slot, so names stay in line.\n */\n checks?: (row: T) => boolean;\n limit?: never;\n expanded?: never;\n onExpandedChange?: never;\n moreMeta?: never;\n toolbar?: never;\n groups?: never;\n};\n\n/** A list without selection, as in a details panel: one click on an item opens it. */\nexport type FileGridOpenProps<T> = FileGridBaseProps<T> & {\n selection?: never;\n onRowClick?: never;\n checks?: never;\n /** Shows the first `limit` items, then \"Show all N\", which opens the full list in place. Without it, the list is always full. */\n limit?: number;\n /** Controls whether the full list is open. Without it, the list keeps its own state. */\n expanded?: boolean;\n onExpandedChange?: (expanded: boolean) => void;\n /** A quiet note at the end of \"Show all N\", such as how many duplicates were merged. */\n moreMeta?: JSX.Element;\n /** Shown above the full list, such as a count, an arrangement switch, or \"Download all\"; not in the short list. */\n toolbar?: JSX.Element;\n /** How the full list arranges its items, such as files as rows, then images as tiles; the short list stays one list. */\n groups?: (rows: readonly T[]) => readonly FileGridGroup<T>[];\n};\n\nexport type FileGridProps<T> = FileGridSelectableProps<T> | FileGridOpenProps<T>;\n\n/**\n * File presentation only; the host owns data, menus, leases and permissions. Items the selection marks with\n * `isDisabled` stay reachable by keyboard but cannot be selected or opened; say why in `renderMeta`.\n */\nexport function FileGrid<T>(props: FileGridProps<T>) {\n return (\n <Show when={props.selection} fallback={<OpenFileGrid {...(props as FileGridOpenProps<T>)} />}>\n {(selection) => <SelectableFileGrid {...(props as FileGridSelectableProps<T>)} selection={selection()} />}\n </Show>\n );\n}\n\nfunction SelectableFileGrid<T>(props: FileGridSelectableProps<T>) {\n let grid: HTMLDivElement | undefined;\n // Both clicks of a double-click belong to the item that took the first one. When that click replaced the rows,\n // for example by opening a folder, the item now under the pointer ignores the rest of the gesture.\n let pressed: EventTarget | null | undefined;\n const ownsClick = (event: MouseEvent) => {\n if (event.detail > 1 && pressed !== event.currentTarget) pressed = null;\n else pressed = event.currentTarget;\n return pressed !== null;\n };\n const columns = () => (grid ? Math.max(1, getComputedStyle(grid).gridTemplateColumns.split(\" \").length) : 1);\n const nested = (event: Event) =>\n event.target instanceof Element &&\n !!event.target.closest(\"button,a,input,label,select,textarea,summary,[contenteditable],[role=button],[role=menu]\");\n return (\n <div\n ref={grid}\n class={`k2b-file-grid ${props.class ?? \"\"}`}\n data-size={props.size ?? \"md\"}\n data-layout={props.layout ?? \"grid\"}\n data-action-visibility={props.actionVisibility ?? \"always\"}\n data-checks={props.checks ? \"true\" : undefined}\n role=\"grid\"\n aria-label={props.label}\n aria-multiselectable={props.selection.multiple}\n >\n <For each={props.rows}>\n {(row) => {\n const id = () => props.getRowId(row);\n const disabled = () => props.selection.isDisabled(id());\n return (\n <div role=\"row\" class=\"k2b-file-grid__row\">\n <div\n {...props.itemProps?.(row)}\n role=\"gridcell\"\n class=\"k2b-file-grid__item\"\n aria-selected={props.selection.selected().has(id())}\n aria-disabled={disabled() || undefined}\n ref={(element) => props.selection.register(id(), element)}\n tabIndex={props.selection.focused() === id() ? 0 : -1}\n onFocus={() => props.selection.markFocused(id())}\n onClick={(event) => {\n if (!nested(event) && ownsClick(event) && !disabled()) {\n props.selection.select(id(), event);\n props.onRowClick?.(row);\n }\n }}\n onDblClick={(event) => {\n if (!nested(event) && pressed !== null && !disabled()) props.onOpen(row);\n }}\n onContextMenu={() => props.onContextMenu?.(row)}\n onKeyDown={(event) => {\n if (nested(event)) return;\n if (props.selection.keyDown(event, id(), columns())) return;\n if (event.key === \"Enter\") {\n event.preventDefault();\n if (!disabled()) props.onOpen(row);\n }\n }}\n >\n <Show when={props.checks}>\n {(checks) => (\n <span class=\"k2b-file-grid__check\" aria-hidden=\"true\">\n <Show when={checks()(row)}>\n <span class=\"k2b-file-grid__check-box\" data-shape={props.selection.multiple ? \"box\" : \"circle\"}>\n <i class=\"ti ti-check\" />\n </span>\n </Show>\n </span>\n )}\n </Show>\n <div class=\"k2b-file-grid__preview\">{props.renderPreview(row)}</div>\n <div class=\"k2b-file-grid__name\">{props.renderLabel(row)}</div>\n <div class=\"k2b-file-grid__meta\">{props.renderMeta?.(row)}</div>\n <div class=\"k2b-file-grid__actions\">{props.renderActions?.(row)}</div>\n </div>\n </div>\n );\n }}\n </For>\n </div>\n );\n}\n\nfunction OpenFileGrid<T>(props: FileGridOpenProps<T>) {\n const messages = useFileListMessages();\n const [ownExpanded, setOwnExpanded] = createSignal(false);\n const limited = () => props.limit !== undefined && props.rows.length > props.limit;\n // Without a limit the list is always complete, so its toolbar and groups always apply.\n const full = () => props.limit === undefined || (limited() && (props.expanded ?? ownExpanded()));\n let more: HTMLButtonElement | undefined;\n let less: HTMLButtonElement | undefined;\n let moveFocus = false;\n const toggle = (next: boolean) => {\n moveFocus = true;\n if (props.expanded === undefined) setOwnExpanded(next);\n props.onExpandedChange?.(next);\n };\n // The pressed button leaves with the state it showed; once the new state is there, focus moves to its\n // counterpart, also when a controlling host applies it later.\n createEffect(\n on(\n full,\n (open) => {\n if (!moveFocus) return;\n moveFocus = false;\n queueMicrotask(() => (open ? less : more)?.focus());\n },\n { defer: true },\n ),\n );\n const groups = createMemo((): readonly FileGridGroup<T>[] =>\n full() && props.groups\n ? props.groups(props.rows).filter((group) => group.rows.length > 0)\n : [{ id: \"rows\", label: undefined, rows: full() || !limited() ? props.rows : props.rows.slice(0, props.limit) }],\n );\n\n const list = (group: () => FileGridGroup<T>, labelId?: string) => (\n <div\n class={`k2b-file-grid ${props.class ?? \"\"}`}\n data-size={props.size ?? \"md\"}\n data-layout={group().layout === \"tiles\" ? \"tiles\" : (props.layout ?? \"grid\")}\n data-action-visibility={props.actionVisibility ?? \"always\"}\n data-open-items=\"true\"\n role=\"list\"\n aria-label={labelId ? undefined : props.label}\n aria-labelledby={labelId}\n >\n {/* Keyed by the row itself: new data keeps every existing item, its focus, and its state. */}\n <For each={group().rows}>\n {(row) => {\n const id = `k2b-file-grid-${createUniqueId()}`;\n return (\n <div role=\"listitem\" class=\"k2b-file-grid__row\">\n <div {...props.itemProps?.(row)} class=\"k2b-file-grid__item\">\n {/* The whole item opens the file; its actions lie above this layer in their own slot. */}\n <button\n type=\"button\"\n class=\"k2b-file-grid__open\"\n aria-labelledby={`${id}-name`}\n aria-describedby={props.renderMeta ? `${id}-meta` : undefined}\n onClick={() => props.onOpen(row)}\n onContextMenu={() => props.onContextMenu?.(row)}\n />\n <div class=\"k2b-file-grid__preview\">{props.renderPreview(row)}</div>\n <div class=\"k2b-file-grid__name\" id={`${id}-name`}>\n {props.renderLabel(row)}\n </div>\n <div class=\"k2b-file-grid__meta\" id={`${id}-meta`}>\n {props.renderMeta?.(row)}\n </div>\n <div class=\"k2b-file-grid__actions\">{props.renderActions?.(row)}</div>\n </div>\n </div>\n );\n }}\n </For>\n </div>\n );\n\n return (\n <div class=\"k2b-file-grid-stack\" data-expanded={full() ? \"true\" : undefined}>\n <Show when={full() && props.toolbar}>\n <div class=\"k2b-file-grid-stack__toolbar\">{props.toolbar}</div>\n </Show>\n {/* By position: a group that only changes its rows keeps its list, so new data remounts nothing. */}\n <Index each={groups()}>\n {(group) => {\n const labelId = `k2b-file-grid-group-${createUniqueId()}`;\n return (\n <Show when={group().label !== undefined} fallback={list(group)}>\n <div class=\"k2b-file-grid-stack__group\">\n <div class=\"k2b-file-grid-stack__label\" id={labelId}>\n {group().label}\n <span class=\"k2b-file-grid-stack__count\">{group().rows.length}</span>\n </div>\n {list(group, labelId)}\n </div>\n </Show>\n );\n }}\n </Index>\n <Show when={limited()}>\n <Show\n when={full()}\n fallback={\n <button ref={more} type=\"button\" class=\"k2b-file-grid-stack__more\" aria-expanded=\"false\" onClick={() => toggle(true)}>\n <span>{messages().showAll({ count: props.rows.length })}</span>\n <i class=\"ti ti-chevron-down\" aria-hidden=\"true\" />\n <Show when={props.moreMeta}>\n <span class=\"k2b-file-grid-stack__more-meta\">{props.moreMeta}</span>\n </Show>\n </button>\n }\n >\n <button ref={less} type=\"button\" class=\"k2b-file-grid-stack__more\" aria-expanded=\"true\" onClick={() => toggle(false)}>\n <span>{messages().showLess}</span>\n <i class=\"ti ti-chevron-up\" aria-hidden=\"true\" />\n </button>\n </Show>\n </Show>\n </div>\n );\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -62,10 +62,16 @@ export function createChoiceLoader(loader, debounceMs) {
|
|
|
62
62
|
timer = undefined;
|
|
63
63
|
controller?.abort();
|
|
64
64
|
controller = undefined;
|
|
65
|
+
request++;
|
|
66
|
+
setLoading(false);
|
|
65
67
|
};
|
|
66
68
|
const run = async query => {
|
|
67
69
|
const loadOptions = loader();
|
|
68
|
-
if (!loadOptions)
|
|
70
|
+
if (!loadOptions) {
|
|
71
|
+
// The source went away while its search waited out the debounce.
|
|
72
|
+
setLoading(false);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
69
75
|
controller?.abort();
|
|
70
76
|
controller = new AbortController();
|
|
71
77
|
const currentController = controller;
|
|
@@ -81,13 +87,16 @@ export function createChoiceLoader(loader, debounceMs) {
|
|
|
81
87
|
setError(errorMessage(reason));
|
|
82
88
|
}
|
|
83
89
|
} finally {
|
|
84
|
-
if (currentRequest === request) setLoading(false);
|
|
90
|
+
if (currentRequest === request && !timer) setLoading(false);
|
|
85
91
|
}
|
|
86
92
|
};
|
|
87
93
|
const load = (query, immediate = false) => {
|
|
88
94
|
lastQuery = query;
|
|
89
95
|
if (timer) clearTimeout(timer);
|
|
90
96
|
timer = undefined;
|
|
97
|
+
// A search waiting out its debounce is already loading: the list shows its
|
|
98
|
+
// loading rows, not "no results" for a request that has not run yet.
|
|
99
|
+
if (loader()) setLoading(true);
|
|
91
100
|
if (immediate || debounceMs() <= 0) {
|
|
92
101
|
void run(query);
|
|
93
102
|
return;
|
|
@@ -115,15 +124,23 @@ const popoverIsOpen = popover => {
|
|
|
115
124
|
return false;
|
|
116
125
|
}
|
|
117
126
|
};
|
|
118
|
-
|
|
127
|
+
/**
|
|
128
|
+
* Places the popover under (or above) its trigger. `floor` is the narrowest
|
|
129
|
+
* width it may take, such as the width it already had while open, so filtering
|
|
130
|
+
* the options never makes it narrower.
|
|
131
|
+
*/
|
|
132
|
+
export const placeChoicePopover = (trigger, popover, placement = {}, floor = 0) => {
|
|
119
133
|
const margin = 8;
|
|
120
134
|
const gap = 4;
|
|
121
135
|
const triggerRect = trigger.getBoundingClientRect();
|
|
122
|
-
//
|
|
123
|
-
//
|
|
124
|
-
//
|
|
125
|
-
|
|
126
|
-
|
|
136
|
+
// The popover starts at the trigger's left edge and is never narrower than
|
|
137
|
+
// the trigger. Its stylesheet lets it grow to its longest name, as a menu
|
|
138
|
+
// does, so a name stays on one line beside a narrow trigger.
|
|
139
|
+
if (placement.width !== "own") {
|
|
140
|
+
popover.dataset.width = "fit";
|
|
141
|
+
const minWidth = Math.min(Math.max(triggerRect.width, floor), window.innerWidth - margin * 2);
|
|
142
|
+
popover.style.setProperty("--k2b-choice-min-width", `${minWidth}px`);
|
|
143
|
+
}
|
|
127
144
|
|
|
128
145
|
// A stylesheet minimum, such as a popover with filter chips, can make it
|
|
129
146
|
// wider than the trigger, so the clamp below uses the rendered width.
|
|
@@ -142,14 +159,24 @@ export function createChoicePopover(disabled, placement = () => ({})) {
|
|
|
142
159
|
const [trigger, setTrigger] = createSignal();
|
|
143
160
|
const [popover, setPopover] = createSignal();
|
|
144
161
|
let triggerRing = true;
|
|
162
|
+
// The widest the open popover has been: typing a filter never narrows it.
|
|
163
|
+
let widest = 0;
|
|
145
164
|
const place = () => {
|
|
146
165
|
const triggerElement = trigger();
|
|
147
166
|
const popoverElement = popover();
|
|
148
|
-
if (triggerElement
|
|
167
|
+
if (!triggerElement || !popoverElement || !open()) return;
|
|
168
|
+
placeChoicePopover(triggerElement, popoverElement, placement(), widest);
|
|
169
|
+
widest = popoverElement.getBoundingClientRect().width;
|
|
170
|
+
// Hold the width now, while it is the one on screen. Shorter results then
|
|
171
|
+
// keep it without a resize, so the observer below never has to widen the
|
|
172
|
+
// popover again during its own delivery, which WebKit reports as a
|
|
173
|
+
// "ResizeObserver loop" error.
|
|
174
|
+
if (placement().width !== "own") popoverElement.style.setProperty("--k2b-choice-min-width", `${widest}px`);
|
|
149
175
|
};
|
|
150
176
|
const show = () => {
|
|
151
177
|
const popoverElement = popover();
|
|
152
178
|
if (disabled() || !popoverElement || popoverIsOpen(popoverElement)) return;
|
|
179
|
+
widest = 0;
|
|
153
180
|
triggerRing = ringOnReturn(trigger());
|
|
154
181
|
popoverElement.showPopover();
|
|
155
182
|
setOpen(true);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["inputs/choice.ts"],"sourcesContent":["import { createEffect, createSignal, onCleanup, type Setter } from \"solid-js\";\nimport { returnFocus, ringOnReturn } from \"../internal/focus-return\";\n\nexport type ChoiceOption<T extends string = string> = {\n value: T;\n label: string;\n description?: string;\n icon?: string;\n color?: string;\n disabled?: boolean;\n /** Optional overlapping groups used by choice controls that expose group filtering. */\n groups?: readonly string[];\n};\n\nexport type ChoiceOptionsLoader<T extends string = string> = (query: string, signal: AbortSignal) => Promise<readonly ChoiceOption<T>[]>;\n\n/** Matches label, description, value, and optional extra keywords. */\nexport const filterChoiceOptions = <\n O extends Pick<ChoiceOption<string>, \"label\" | \"description\" | \"value\"> & { keywords?: readonly string[] },\n>(\n options: readonly O[],\n query: string,\n): readonly O[] => {\n const normalized = query.trim().toLocaleLowerCase();\n if (!normalized) return options;\n return options.filter((option) =>\n [option.label, option.description, option.value, ...(option.keywords ?? [])].some((part) =>\n part?.toLocaleLowerCase().includes(normalized),\n ),\n );\n};\n\n/**\n * Moves through the options and wraps at the ends, skipping `disabled` ones. A\n * RichSelect row that cannot be chosen carries a `disabledReason` instead, so\n * the arrow keys still reach it and its reason can be read.\n */\nexport const nextEnabledChoiceIndex = <O extends { label: string; disabled?: boolean }>(\n options: readonly O[],\n current: number,\n direction: 1 | -1,\n): number => {\n if (options.length === 0 || options.every((option) => option.disabled)) return -1;\n\n let index = current;\n for (let visited = 0; visited < options.length; visited += 1) {\n index = (index + direction + options.length) % options.length;\n if (!options[index]?.disabled) return index;\n }\n return -1;\n};\n\n/**\n * Counts the leading pills that fit into `available` pixels and measures the\n * whole row. When not all of them fit, the rest collapse into a summary pill\n * of width `more`; the first pill always stays and truncates when even it does\n * not fit. Without a measured width (no layout yet) every pill stays. Half a\n * pixel of slack absorbs layout rounding, so a row given exactly its own\n * `rowWidth` always fits.\n */\nexport const fitChoicePills = (\n available: number,\n widths: readonly number[],\n gap: number,\n more: number,\n): { visible: number; rowWidth: number } => {\n const rowWidth = widths.reduce((sum, width) => sum + width, 0) + gap * Math.max(0, widths.length - 1);\n if (available <= 0 || rowWidth <= available + 0.5) return { visible: widths.length, rowWidth };\n let used = more;\n let visible = 0;\n for (const width of widths) {\n used += gap + width;\n if (used > available) break;\n visible += 1;\n }\n return { visible: Math.max(1, visible), rowWidth };\n};\n\nconst errorMessage = (error: unknown): string => (error instanceof Error ? error.message : \"Failed to load options\");\n\nexport function createChoiceLoader<T extends string>(\n loader: () => ChoiceOptionsLoader<T> | undefined,\n debounceMs: () => number,\n): {\n options: () => readonly ChoiceOption<T>[];\n loading: () => boolean;\n error: () => string | undefined;\n load: (query: string, immediate?: boolean) => void;\n retry: () => void;\n cancel: () => void;\n} {\n const [options, setOptions] = createSignal<readonly ChoiceOption<T>[]>([]);\n const [loading, setLoading] = createSignal(false);\n const [error, setError] = createSignal<string>();\n let controller: AbortController | undefined;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let request = 0;\n let lastQuery = \"\";\n\n const cancel = () => {\n if (timer) clearTimeout(timer);\n timer = undefined;\n controller?.abort();\n controller = undefined;\n };\n\n const run = async (query: string) => {\n const loadOptions = loader();\n if (!loadOptions) return;\n\n controller?.abort();\n controller = new AbortController();\n const currentController = controller;\n const currentRequest = ++request;\n setLoading(true);\n setError(undefined);\n\n try {\n const next = await loadOptions(query, currentController.signal);\n if (currentRequest === request && !currentController.signal.aborted) setOptions(next);\n } catch (reason) {\n if (currentRequest === request && !currentController.signal.aborted) {\n setOptions([]);\n setError(errorMessage(reason));\n }\n } finally {\n if (currentRequest === request) setLoading(false);\n }\n };\n\n const load = (query: string, immediate = false) => {\n lastQuery = query;\n if (timer) clearTimeout(timer);\n timer = undefined;\n if (immediate || debounceMs() <= 0) {\n void run(query);\n return;\n }\n timer = setTimeout(() => {\n timer = undefined;\n void run(query);\n }, debounceMs());\n };\n\n onCleanup(cancel);\n return { options, loading, error, load, retry: () => load(lastQuery, true), cancel };\n}\n\nconst popoverIsOpen = (popover: HTMLElement | undefined): boolean => {\n if (!popover) return false;\n try {\n return popover.matches(\":popover-open\");\n } catch {\n return false;\n }\n};\n\nexport type ChoicePopoverPlacement = {\n /**\n * `trigger` (default) gives the popover the trigger's width; `own` keeps the\n * width its stylesheet sets, such as a RichSelect with a preview.\n */\n width?: \"trigger\" | \"own\";\n /** The side tried first. The popover flips when the other side has more room. */\n side?: \"below\" | \"above\";\n};\n\nexport const placeChoicePopover = (trigger: HTMLElement, popover: HTMLElement, placement: ChoicePopoverPlacement = {}): void => {\n const margin = 8;\n const gap = 4;\n const triggerRect = trigger.getBoundingClientRect();\n // Cloud sizes its dropdowns to the trigger exactly (`dialog.style.width =\n // rect.width`). Keep that so a narrow toolbar select does not open a wide\n // panel that no longer lines up with the control it belongs to.\n const triggerWidth = Math.min(triggerRect.width, window.innerWidth - margin * 2);\n if (placement.width !== \"own\") popover.style.width = `${triggerWidth}px`;\n\n // A stylesheet minimum, such as a popover with filter chips, can make it\n // wider than the trigger, so the clamp below uses the rendered width.\n const popoverRect = popover.getBoundingClientRect();\n const width = popoverRect.width;\n const left = Math.max(margin, Math.min(triggerRect.left, window.innerWidth - width - margin));\n const roomBelow = window.innerHeight - triggerRect.bottom - gap - margin;\n const roomAbove = triggerRect.top - gap - margin;\n const opensAbove =\n placement.side === \"above\"\n ? popoverRect.height <= roomAbove || roomAbove > roomBelow\n : popoverRect.height > roomBelow && roomAbove > roomBelow;\n const top = opensAbove\n ? Math.max(margin, triggerRect.top - popoverRect.height - gap)\n : Math.min(triggerRect.bottom + gap, window.innerHeight - popoverRect.height - margin);\n\n popover.style.left = `${left}px`;\n popover.style.top = `${Math.max(margin, top)}px`;\n};\n\nexport function createChoicePopover(\n disabled: () => boolean,\n placement: () => ChoicePopoverPlacement = () => ({}),\n): {\n open: () => boolean;\n setTrigger: Setter<HTMLElement | undefined>;\n setPopover: Setter<HTMLElement | undefined>;\n show: () => void;\n hide: (restoreFocus?: boolean) => void;\n toggle: () => void;\n trigger: () => HTMLElement | undefined;\n} {\n const [open, setOpen] = createSignal(false);\n const [trigger, setTrigger] = createSignal<HTMLElement>();\n const [popover, setPopover] = createSignal<HTMLElement>();\n let triggerRing = true;\n\n const place = () => {\n const triggerElement = trigger();\n const popoverElement = popover();\n if (triggerElement && popoverElement && open()) placeChoicePopover(triggerElement, popoverElement, placement());\n };\n\n const show = () => {\n const popoverElement = popover();\n if (disabled() || !popoverElement || popoverIsOpen(popoverElement)) return;\n triggerRing = ringOnReturn(trigger());\n popoverElement.showPopover();\n setOpen(true);\n queueMicrotask(place);\n };\n\n const hide = (restoreFocus = false) => {\n const popoverElement = popover();\n // Before hiding, so the popover does not return focus on its own.\n if (restoreFocus) returnFocus(trigger(), triggerRing);\n if (popoverIsOpen(popoverElement)) popoverElement?.hidePopover();\n setOpen(false);\n };\n\n createEffect(() => {\n const popoverElement = popover();\n if (!popoverElement) return;\n const syncOpenState = () => setOpen(popoverIsOpen(popoverElement));\n const containWheel = (event: WheelEvent) => {\n if (event.ctrlKey) return;\n event.preventDefault();\n\n const target = event.target instanceof Element ? event.target : undefined;\n const groups = target?.closest<HTMLElement>(\".k2b-choice-groups\");\n const horizontalDelta = event.shiftKey && event.deltaX === 0 ? event.deltaY : event.deltaX;\n if (groups && (event.shiftKey || Math.abs(event.deltaX) > Math.abs(event.deltaY)) && groups.scrollWidth > groups.clientWidth) {\n const unit = event.deltaMode === 1 ? 16 : event.deltaMode === 2 ? groups.clientWidth : 1;\n groups.scrollLeft += horizontalDelta * unit;\n return;\n }\n\n // A popover with more than one scrolling region, such as a list beside a\n // preview, marks them; the wheel scrolls the one under the pointer.\n const options =\n target?.closest<HTMLElement>(\"[data-choice-scroll]\") ?? popoverElement.querySelector<HTMLElement>(\".k2b-choice-options\");\n if (!options || options.scrollHeight <= options.clientHeight) return;\n const unit = event.deltaMode === 1 ? 16 : event.deltaMode === 2 ? options.clientHeight : 1;\n options.scrollTop += event.deltaY * unit;\n };\n popoverElement.addEventListener(\"toggle\", syncOpenState);\n popoverElement.addEventListener(\"wheel\", containWheel, { passive: false });\n onCleanup(() => {\n popoverElement.removeEventListener(\"toggle\", syncOpenState);\n popoverElement.removeEventListener(\"wheel\", containWheel);\n });\n });\n\n createEffect(() => {\n if (!open()) return;\n\n const dismiss = (event: PointerEvent) => {\n const target = event.target;\n if (!(target instanceof Node) || trigger()?.contains(target) || popover()?.contains(target)) return;\n hide();\n };\n const reposition = () => place();\n\n // Async option lists arrive after the popover is already open, so the first\n // placement measures an empty panel. Re-place whenever the panel resizes,\n // otherwise a dropdown that grows past the viewport bottom stays clipped.\n const popoverElement = popover();\n const observer = popoverElement && typeof ResizeObserver !== \"undefined\" ? new ResizeObserver(reposition) : undefined;\n if (popoverElement) observer?.observe(popoverElement);\n\n document.addEventListener(\"pointerdown\", dismiss, true);\n window.addEventListener(\"resize\", reposition);\n window.addEventListener(\"scroll\", reposition, true);\n onCleanup(() => {\n observer?.disconnect();\n document.removeEventListener(\"pointerdown\", dismiss, true);\n window.removeEventListener(\"resize\", reposition);\n window.removeEventListener(\"scroll\", reposition, true);\n });\n });\n\n onCleanup(() => hide());\n return {\n open,\n setTrigger,\n setPopover,\n show,\n hide,\n toggle: () => (open() ? hide() : show()),\n trigger,\n };\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":[],"sources":["inputs/choice.ts"],"sourcesContent":["import { createEffect, createSignal, onCleanup, type Setter } from \"solid-js\";\nimport { returnFocus, ringOnReturn } from \"../internal/focus-return\";\n\nexport type ChoiceOption<T extends string = string> = {\n value: T;\n label: string;\n description?: string;\n icon?: string;\n color?: string;\n disabled?: boolean;\n /** Optional overlapping groups used by choice controls that expose group filtering. */\n groups?: readonly string[];\n};\n\nexport type ChoiceOptionsLoader<T extends string = string> = (query: string, signal: AbortSignal) => Promise<readonly ChoiceOption<T>[]>;\n\n/** Matches label, description, value, and optional extra keywords. */\nexport const filterChoiceOptions = <\n O extends Pick<ChoiceOption<string>, \"label\" | \"description\" | \"value\"> & { keywords?: readonly string[] },\n>(\n options: readonly O[],\n query: string,\n): readonly O[] => {\n const normalized = query.trim().toLocaleLowerCase();\n if (!normalized) return options;\n return options.filter((option) =>\n [option.label, option.description, option.value, ...(option.keywords ?? [])].some((part) =>\n part?.toLocaleLowerCase().includes(normalized),\n ),\n );\n};\n\n/**\n * Moves through the options and wraps at the ends, skipping `disabled` ones. A\n * RichSelect row that cannot be chosen carries a `disabledReason` instead, so\n * the arrow keys still reach it and its reason can be read.\n */\nexport const nextEnabledChoiceIndex = <O extends { label: string; disabled?: boolean }>(\n options: readonly O[],\n current: number,\n direction: 1 | -1,\n): number => {\n if (options.length === 0 || options.every((option) => option.disabled)) return -1;\n\n let index = current;\n for (let visited = 0; visited < options.length; visited += 1) {\n index = (index + direction + options.length) % options.length;\n if (!options[index]?.disabled) return index;\n }\n return -1;\n};\n\n/**\n * Counts the leading pills that fit into `available` pixels and measures the\n * whole row. When not all of them fit, the rest collapse into a summary pill\n * of width `more`; the first pill always stays and truncates when even it does\n * not fit. Without a measured width (no layout yet) every pill stays. Half a\n * pixel of slack absorbs layout rounding, so a row given exactly its own\n * `rowWidth` always fits.\n */\nexport const fitChoicePills = (\n available: number,\n widths: readonly number[],\n gap: number,\n more: number,\n): { visible: number; rowWidth: number } => {\n const rowWidth = widths.reduce((sum, width) => sum + width, 0) + gap * Math.max(0, widths.length - 1);\n if (available <= 0 || rowWidth <= available + 0.5) return { visible: widths.length, rowWidth };\n let used = more;\n let visible = 0;\n for (const width of widths) {\n used += gap + width;\n if (used > available) break;\n visible += 1;\n }\n return { visible: Math.max(1, visible), rowWidth };\n};\n\nconst errorMessage = (error: unknown): string => (error instanceof Error ? error.message : \"Failed to load options\");\n\nexport function createChoiceLoader<T extends string>(\n loader: () => ChoiceOptionsLoader<T> | undefined,\n debounceMs: () => number,\n): {\n options: () => readonly ChoiceOption<T>[];\n loading: () => boolean;\n error: () => string | undefined;\n load: (query: string, immediate?: boolean) => void;\n retry: () => void;\n cancel: () => void;\n} {\n const [options, setOptions] = createSignal<readonly ChoiceOption<T>[]>([]);\n const [loading, setLoading] = createSignal(false);\n const [error, setError] = createSignal<string>();\n let controller: AbortController | undefined;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let request = 0;\n let lastQuery = \"\";\n\n const cancel = () => {\n if (timer) clearTimeout(timer);\n timer = undefined;\n controller?.abort();\n controller = undefined;\n request++;\n setLoading(false);\n };\n\n const run = async (query: string) => {\n const loadOptions = loader();\n if (!loadOptions) {\n // The source went away while its search waited out the debounce.\n setLoading(false);\n return;\n }\n\n controller?.abort();\n controller = new AbortController();\n const currentController = controller;\n const currentRequest = ++request;\n setLoading(true);\n setError(undefined);\n\n try {\n const next = await loadOptions(query, currentController.signal);\n if (currentRequest === request && !currentController.signal.aborted) setOptions(next);\n } catch (reason) {\n if (currentRequest === request && !currentController.signal.aborted) {\n setOptions([]);\n setError(errorMessage(reason));\n }\n } finally {\n if (currentRequest === request && !timer) setLoading(false);\n }\n };\n\n const load = (query: string, immediate = false) => {\n lastQuery = query;\n if (timer) clearTimeout(timer);\n timer = undefined;\n // A search waiting out its debounce is already loading: the list shows its\n // loading rows, not \"no results\" for a request that has not run yet.\n if (loader()) setLoading(true);\n if (immediate || debounceMs() <= 0) {\n void run(query);\n return;\n }\n timer = setTimeout(() => {\n timer = undefined;\n void run(query);\n }, debounceMs());\n };\n\n onCleanup(cancel);\n return { options, loading, error, load, retry: () => load(lastQuery, true), cancel };\n}\n\nconst popoverIsOpen = (popover: HTMLElement | undefined): boolean => {\n if (!popover) return false;\n try {\n return popover.matches(\":popover-open\");\n } catch {\n return false;\n }\n};\n\nexport type ChoicePopoverPlacement = {\n /**\n * `trigger` (default) makes the popover at least as wide as the trigger and\n * as wide as its longest name, so names stay on one line; `own` keeps\n * the width its stylesheet sets, such as a RichSelect with a preview.\n */\n width?: \"trigger\" | \"own\";\n /** The side tried first. The popover flips when the other side has more room. */\n side?: \"below\" | \"above\";\n};\n\n/**\n * Places the popover under (or above) its trigger. `floor` is the narrowest\n * width it may take, such as the width it already had while open, so filtering\n * the options never makes it narrower.\n */\nexport const placeChoicePopover = (trigger: HTMLElement, popover: HTMLElement, placement: ChoicePopoverPlacement = {}, floor = 0): void => {\n const margin = 8;\n const gap = 4;\n const triggerRect = trigger.getBoundingClientRect();\n // The popover starts at the trigger's left edge and is never narrower than\n // the trigger. Its stylesheet lets it grow to its longest name, as a menu\n // does, so a name stays on one line beside a narrow trigger.\n if (placement.width !== \"own\") {\n popover.dataset.width = \"fit\";\n const minWidth = Math.min(Math.max(triggerRect.width, floor), window.innerWidth - margin * 2);\n popover.style.setProperty(\"--k2b-choice-min-width\", `${minWidth}px`);\n }\n\n // A stylesheet minimum, such as a popover with filter chips, can make it\n // wider than the trigger, so the clamp below uses the rendered width.\n const popoverRect = popover.getBoundingClientRect();\n const width = popoverRect.width;\n const left = Math.max(margin, Math.min(triggerRect.left, window.innerWidth - width - margin));\n const roomBelow = window.innerHeight - triggerRect.bottom - gap - margin;\n const roomAbove = triggerRect.top - gap - margin;\n const opensAbove =\n placement.side === \"above\"\n ? popoverRect.height <= roomAbove || roomAbove > roomBelow\n : popoverRect.height > roomBelow && roomAbove > roomBelow;\n const top = opensAbove\n ? Math.max(margin, triggerRect.top - popoverRect.height - gap)\n : Math.min(triggerRect.bottom + gap, window.innerHeight - popoverRect.height - margin);\n\n popover.style.left = `${left}px`;\n popover.style.top = `${Math.max(margin, top)}px`;\n};\n\nexport function createChoicePopover(\n disabled: () => boolean,\n placement: () => ChoicePopoverPlacement = () => ({}),\n): {\n open: () => boolean;\n setTrigger: Setter<HTMLElement | undefined>;\n setPopover: Setter<HTMLElement | undefined>;\n show: () => void;\n hide: (restoreFocus?: boolean) => void;\n toggle: () => void;\n trigger: () => HTMLElement | undefined;\n} {\n const [open, setOpen] = createSignal(false);\n const [trigger, setTrigger] = createSignal<HTMLElement>();\n const [popover, setPopover] = createSignal<HTMLElement>();\n let triggerRing = true;\n // The widest the open popover has been: typing a filter never narrows it.\n let widest = 0;\n\n const place = () => {\n const triggerElement = trigger();\n const popoverElement = popover();\n if (!triggerElement || !popoverElement || !open()) return;\n placeChoicePopover(triggerElement, popoverElement, placement(), widest);\n widest = popoverElement.getBoundingClientRect().width;\n // Hold the width now, while it is the one on screen. Shorter results then\n // keep it without a resize, so the observer below never has to widen the\n // popover again during its own delivery, which WebKit reports as a\n // \"ResizeObserver loop\" error.\n if (placement().width !== \"own\") popoverElement.style.setProperty(\"--k2b-choice-min-width\", `${widest}px`);\n };\n\n const show = () => {\n const popoverElement = popover();\n if (disabled() || !popoverElement || popoverIsOpen(popoverElement)) return;\n widest = 0;\n triggerRing = ringOnReturn(trigger());\n popoverElement.showPopover();\n setOpen(true);\n queueMicrotask(place);\n };\n\n const hide = (restoreFocus = false) => {\n const popoverElement = popover();\n // Before hiding, so the popover does not return focus on its own.\n if (restoreFocus) returnFocus(trigger(), triggerRing);\n if (popoverIsOpen(popoverElement)) popoverElement?.hidePopover();\n setOpen(false);\n };\n\n createEffect(() => {\n const popoverElement = popover();\n if (!popoverElement) return;\n const syncOpenState = () => setOpen(popoverIsOpen(popoverElement));\n const containWheel = (event: WheelEvent) => {\n if (event.ctrlKey) return;\n event.preventDefault();\n\n const target = event.target instanceof Element ? event.target : undefined;\n const groups = target?.closest<HTMLElement>(\".k2b-choice-groups\");\n const horizontalDelta = event.shiftKey && event.deltaX === 0 ? event.deltaY : event.deltaX;\n if (groups && (event.shiftKey || Math.abs(event.deltaX) > Math.abs(event.deltaY)) && groups.scrollWidth > groups.clientWidth) {\n const unit = event.deltaMode === 1 ? 16 : event.deltaMode === 2 ? groups.clientWidth : 1;\n groups.scrollLeft += horizontalDelta * unit;\n return;\n }\n\n // A popover with more than one scrolling region, such as a list beside a\n // preview, marks them; the wheel scrolls the one under the pointer.\n const options =\n target?.closest<HTMLElement>(\"[data-choice-scroll]\") ?? popoverElement.querySelector<HTMLElement>(\".k2b-choice-options\");\n if (!options || options.scrollHeight <= options.clientHeight) return;\n const unit = event.deltaMode === 1 ? 16 : event.deltaMode === 2 ? options.clientHeight : 1;\n options.scrollTop += event.deltaY * unit;\n };\n popoverElement.addEventListener(\"toggle\", syncOpenState);\n popoverElement.addEventListener(\"wheel\", containWheel, { passive: false });\n onCleanup(() => {\n popoverElement.removeEventListener(\"toggle\", syncOpenState);\n popoverElement.removeEventListener(\"wheel\", containWheel);\n });\n });\n\n createEffect(() => {\n if (!open()) return;\n\n const dismiss = (event: PointerEvent) => {\n const target = event.target;\n if (!(target instanceof Node) || trigger()?.contains(target) || popover()?.contains(target)) return;\n hide();\n };\n const reposition = () => place();\n\n // Async option lists arrive after the popover is already open, so the first\n // placement measures an empty panel. Re-place whenever the panel resizes,\n // otherwise a dropdown that grows past the viewport bottom stays clipped.\n const popoverElement = popover();\n const observer = popoverElement && typeof ResizeObserver !== \"undefined\" ? new ResizeObserver(reposition) : undefined;\n if (popoverElement) observer?.observe(popoverElement);\n\n document.addEventListener(\"pointerdown\", dismiss, true);\n window.addEventListener(\"resize\", reposition);\n window.addEventListener(\"scroll\", reposition, true);\n onCleanup(() => {\n observer?.disconnect();\n document.removeEventListener(\"pointerdown\", dismiss, true);\n window.removeEventListener(\"resize\", reposition);\n window.removeEventListener(\"scroll\", reposition, true);\n });\n });\n\n onCleanup(() => hide());\n return {\n open,\n setTrigger,\n setPopover,\n show,\n hide,\n toggle: () => (open() ? hide() : show()),\n trigger,\n };\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -17,7 +17,7 @@ var _tmpl$ = ["<button type=\"button\" class=\"k2b-app-workspace__resize\" role=
|
|
|
17
17
|
_tmpl$8 = ["<section", " class=\"", "\"", " style=\"", "\">", "</section>"],
|
|
18
18
|
_tmpl$9 = ["<div class=\"k2b-app-workspace__level-body\"", ">", "</div>"],
|
|
19
19
|
_tmpl$0 = "<i class=\"ti ti-chevron-left\" aria-hidden=\"true\"></i>",
|
|
20
|
-
_tmpl$1 = "<i
|
|
20
|
+
_tmpl$1 = ["<i", " aria-hidden=\"true\"></i>"],
|
|
21
21
|
_tmpl$10 = ["<aside", " class=\"", "\"", "", " style=\"", "\"><button type=\"button\" class=\"k2b-app-workspace__detail-grabber\"", " aria-pressed=\"false\"><span aria-hidden=\"true\"></span></button>", "</aside>"],
|
|
22
22
|
_tmpl$11 = ["<aside", " class=\"", "\"", "", " style=\"", "\">", "</aside>"],
|
|
23
23
|
_tmpl$12 = ["<nav class=\"k2b-app-workspace__sidebar-sheet\"", " style=\"", "\">", "</nav>"],
|
|
@@ -57,18 +57,17 @@ var _tmpl$ = ["<button type=\"button\" class=\"k2b-app-workspace__resize\" role=
|
|
|
57
57
|
_tmpl$46 = ["<div class=\"k2b-app-workspace__nav-tree-node\" role=\"treeitem\"", " style=\"", "\">", "", "</div>"],
|
|
58
58
|
_tmpl$47 = ["<div class=\"", "\" role=\"tree\"", ">", "</div>"],
|
|
59
59
|
_tmpl$48 = ["<div class=\"k2b-app-workspace__sidebar-icon-grid\"", ">", "</div>"],
|
|
60
|
-
_tmpl$49 =
|
|
61
|
-
_tmpl$50 = "<
|
|
62
|
-
_tmpl$51 =
|
|
63
|
-
_tmpl$52 = "<
|
|
64
|
-
_tmpl$53 = ["<div class=\"k2b-app-workspace__head-
|
|
65
|
-
_tmpl$54 = ["<
|
|
66
|
-
_tmpl$55 = ["<
|
|
67
|
-
_tmpl$56 = ["<div class=\"k2b-app-workspace__head-
|
|
68
|
-
_tmpl$57 = ["<
|
|
69
|
-
_tmpl$58 = ["<
|
|
70
|
-
_tmpl$59 = ["<div class=\"", "\"
|
|
71
|
-
_tmpl$60 = ["<div class=\"", "\">", "</div>"];
|
|
60
|
+
_tmpl$49 = "<i class=\"ti ti-chevron-down k2b-app-workspace__head-primary-chevron\" aria-hidden=\"true\"></i>",
|
|
61
|
+
_tmpl$50 = ["<span class=\"k2b-app-workspace__head-primary-label\">", "", "</span>"],
|
|
62
|
+
_tmpl$51 = "<i class=\"ti ti-layout-sidebar\" aria-hidden=\"true\"></i>",
|
|
63
|
+
_tmpl$52 = ["<div class=\"k2b-app-workspace__head-views\">", "</div>"],
|
|
64
|
+
_tmpl$53 = ["<div class=\"k2b-app-workspace__head-filters\" role=\"group\"", ">", "", "</div>"],
|
|
65
|
+
_tmpl$54 = ["<span class=\"k2b-app-workspace__head-count\"><span>", "</span></span>"],
|
|
66
|
+
_tmpl$55 = ["<div class=\"k2b-app-workspace__head-actions\">", "", "</div>"],
|
|
67
|
+
_tmpl$56 = ["<div class=\"k2b-app-workspace__head\"", ">", "<div class=\"k2b-app-workspace__head-lead\">", "", "", "", "", "</div>", "</div>"],
|
|
68
|
+
_tmpl$57 = ["<h1 class=\"k2b-app-workspace__head-heading\" data-k2b-page-trail-title", ">", "</h1>"],
|
|
69
|
+
_tmpl$58 = ["<div class=\"", "\" data-k2b-app-workspace", " style=\"", "\">", "</div>"],
|
|
70
|
+
_tmpl$59 = ["<div class=\"", "\">", "</div>"];
|
|
72
71
|
import { Link } from "@k2b/ssr/nav";
|
|
73
72
|
import { children, createContext, createEffect, createMemo, createRoot, createSignal, createUniqueId, For, getOwner, mergeProps, on, onCleanup, onMount, Show, useContext } from "solid-js";
|
|
74
73
|
import { Dynamic, isServer } from "solid-js/web";
|
|
@@ -81,6 +80,7 @@ import { APP_WORKSPACE_DETAIL_CLOSE_EVENT, APP_WORKSPACE_DETAIL_OPEN_EVENT, APP_
|
|
|
81
80
|
import { APP_WORKSPACE_DETAIL_DEFAULT, APP_WORKSPACE_DETAIL_MAX, APP_WORKSPACE_DETAIL_MIN, APP_WORKSPACE_DRAWER_DEFAULT, APP_WORKSPACE_DRAWER_MAX, APP_WORKSPACE_DRAWER_MIN, APP_WORKSPACE_MAIN_MIN, APP_WORKSPACE_PANE_DEFAULT, APP_WORKSPACE_PANE_MAX, APP_WORKSPACE_PANE_MIN, APP_WORKSPACE_SIDEBAR_COLLAPSED, APP_WORKSPACE_SIDEBAR_DEFAULT, APP_WORKSPACE_SIDEBAR_MAX, APP_WORKSPACE_SIDEBAR_MIN, appWorkspaceLayoutStyle, appWorkspacePanelVariable } from "./app-workspace-state";
|
|
82
81
|
import { appWorkspaceInverseWidthCss, appWorkspaceWidthCss, appWorkspaceWidthToken, isAppWorkspaceWidthShare } from "./app-workspace-width";
|
|
83
82
|
import BottomSheet, { bottomSheetAdaptiveOptions } from "./BottomSheet";
|
|
83
|
+
import { DETAILS_ICON } from "./DetailsToggle";
|
|
84
84
|
import { PageTitle, usePageTrail } from "./PageTitle";
|
|
85
85
|
import { SidebarItemPreview } from "./SidebarItemPreview";
|
|
86
86
|
import { inSidebarRail, SidebarRailHint } from "./SidebarRailHint";
|
|
@@ -590,9 +590,9 @@ function AppWorkspaceDetail(props) {
|
|
|
590
590
|
get disabled() {
|
|
591
591
|
return props.available === false;
|
|
592
592
|
},
|
|
593
|
-
"class": "k2b-app-workspace__detail-toggle",
|
|
593
|
+
"class": "k2b-app-workspace__detail-toggle k2b-details-toggle",
|
|
594
594
|
get children() {
|
|
595
|
-
return [_$ssr(_tmpl$1), workspaceMessages().details];
|
|
595
|
+
return [_$ssr(_tmpl$1, _$ssrAttribute("class", _$escape(DETAILS_ICON, true), false)), workspaceMessages().details];
|
|
596
596
|
}
|
|
597
597
|
});
|
|
598
598
|
}
|
|
@@ -1828,7 +1828,7 @@ const AppWorkspaceSidebarIconGrid = props => _$ssrElement("section", _$mergeProp
|
|
|
1828
1828
|
})), _$ssr(_tmpl$48, _$ssrAttribute("data-columns", _$escape(props.columns ?? 2, true), false), _$escape(props.children))], false);
|
|
1829
1829
|
const AppWorkspaceSidebarIconAction = props => {
|
|
1830
1830
|
let target;
|
|
1831
|
-
const content = _$ssr(_tmpl$
|
|
1831
|
+
const content = _$ssr(_tmpl$1, _$ssrAttribute("class", _$escape(iconClass(props.icon), true), false));
|
|
1832
1832
|
const attrs = () => ({
|
|
1833
1833
|
ref: element => target = element,
|
|
1834
1834
|
class: `k2b-app-workspace__sidebar-icon-action ${props.active ? "is-active" : ""}`,
|
|
@@ -1918,15 +1918,15 @@ function AppWorkspaceHead(props) {
|
|
|
1918
1918
|
return `@media not all and (min-width:48rem){${host} > .k2b-app-workspace__head,${host} > .k2b-app-workspace__content > .k2b-app-workspace__detail-toggle,${host} > .k2b-app-workspace__content > :is(solid-island, solid-client) > .k2b-app-workspace__detail-toggle{display:none}}`;
|
|
1919
1919
|
};
|
|
1920
1920
|
const resetContent = () => filters().reset;
|
|
1921
|
-
const primaryContent = () => [_$ssr(_tmpl$
|
|
1921
|
+
const primaryContent = () => [_$ssr(_tmpl$1, _$ssrAttribute("class", _$escape(props.head?.primary?.icon, true), false)), _$ssr(_tmpl$50, _$escape(props.head?.primary?.label), _$escape(_$createComponent(Show, {
|
|
1922
1922
|
get when() {
|
|
1923
1923
|
return props.head?.primary?.popup;
|
|
1924
1924
|
},
|
|
1925
1925
|
get children() {
|
|
1926
|
-
return _$ssr(_tmpl$
|
|
1926
|
+
return _$ssr(_tmpl$49);
|
|
1927
1927
|
}
|
|
1928
1928
|
})))];
|
|
1929
|
-
return _$ssr(_tmpl$
|
|
1929
|
+
return _$ssr(_tmpl$56, _$ssrAttribute("data-trail", trail()?.ancestors.length ? "up" : trail() ? "title" : _$escape(undefined, true), false) + _$ssrAttribute("data-row", props.head ? "" : _$escape(undefined, true), false) + _$ssrAttribute("data-workspace-head-pane", _$escape(mobilePane(), true), false), _$escape(_$createComponent(Show, {
|
|
1930
1930
|
get when() {
|
|
1931
1931
|
return mobilePane();
|
|
1932
1932
|
},
|
|
@@ -1942,7 +1942,7 @@ function AppWorkspaceHead(props) {
|
|
|
1942
1942
|
"aria-expanded": "false",
|
|
1943
1943
|
"data-app-workspace-sidebar-toggle": "",
|
|
1944
1944
|
get children() {
|
|
1945
|
-
return _$ssr(_tmpl$
|
|
1945
|
+
return _$ssr(_tmpl$51);
|
|
1946
1946
|
}
|
|
1947
1947
|
})), _$escape(_$createComponent(Show, {
|
|
1948
1948
|
get when() {
|
|
@@ -1954,20 +1954,20 @@ function AppWorkspaceHead(props) {
|
|
|
1954
1954
|
},
|
|
1955
1955
|
as: "p",
|
|
1956
1956
|
fallback: true
|
|
1957
|
-
}), _$ssr(_tmpl$
|
|
1957
|
+
}), _$ssr(_tmpl$57, _$ssrAttribute("data-k2b-server", isServer ? "" : _$escape(undefined, true), false), _$escape(current().title))]
|
|
1958
1958
|
})), _$escape(_$createComponent(Show, {
|
|
1959
1959
|
get when() {
|
|
1960
1960
|
return resolvedViews.toArray().some(Boolean);
|
|
1961
1961
|
},
|
|
1962
1962
|
get children() {
|
|
1963
|
-
return _$ssr(_tmpl$
|
|
1963
|
+
return _$ssr(_tmpl$52, _$escape(resolvedViews()));
|
|
1964
1964
|
}
|
|
1965
1965
|
})), _$escape(_$createComponent(Show, {
|
|
1966
1966
|
get when() {
|
|
1967
1967
|
return resolvedFilters.toArray().some(Boolean) || props.head?.filtered;
|
|
1968
1968
|
},
|
|
1969
1969
|
get children() {
|
|
1970
|
-
return _$ssr(_tmpl$
|
|
1970
|
+
return _$ssr(_tmpl$53, _$ssrAttribute("aria-label", _$escape(filters().filters, true), false), _$escape(resolvedFilters()), _$escape(_$createComponent(Show, {
|
|
1971
1971
|
get when() {
|
|
1972
1972
|
return props.head?.filtered;
|
|
1973
1973
|
},
|
|
@@ -2014,14 +2014,14 @@ function AppWorkspaceHead(props) {
|
|
|
2014
2014
|
return _$memo(() => !!props.head?.filtered)() && resolvedCount.toArray().some(value => value !== undefined && value !== null && value !== false);
|
|
2015
2015
|
},
|
|
2016
2016
|
get children() {
|
|
2017
|
-
return _$ssr(_tmpl$
|
|
2017
|
+
return _$ssr(_tmpl$54, _$escape(resolvedCount()));
|
|
2018
2018
|
}
|
|
2019
2019
|
})), _$escape(_$createComponent(Show, {
|
|
2020
2020
|
get when() {
|
|
2021
2021
|
return resolvedActions.toArray().some(Boolean) || props.head?.primary;
|
|
2022
2022
|
},
|
|
2023
2023
|
get children() {
|
|
2024
|
-
return _$ssr(_tmpl$
|
|
2024
|
+
return _$ssr(_tmpl$55, _$escape(resolvedActions()), _$escape(_$createComponent(Show, {
|
|
2025
2025
|
get when() {
|
|
2026
2026
|
return props.head?.primary;
|
|
2027
2027
|
},
|
|
@@ -2127,7 +2127,7 @@ const AppWorkspace = props => {
|
|
|
2127
2127
|
return _$createComponent(WorkspaceContext.Provider, {
|
|
2128
2128
|
value: workspace,
|
|
2129
2129
|
get children() {
|
|
2130
|
-
return _$ssr(_tmpl$
|
|
2130
|
+
return _$ssr(_tmpl$58, `k2b-app-workspace ${_$escape(props.class ?? "", true)}`, _$ssrAttribute("data-mobile-surface", _$escape(props.mobileSurface, true), false) + _$ssrAttribute("data-flat", props.flat ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-sidebar-collapsed", initialLayoutState()?.sidebarCollapsed === undefined ? _$escape(undefined, true) : _$escape(String(initialLayoutState()?.sidebarCollapsed), true), false) + _$ssrAttribute("data-workspace-resizable", props.resizable === false ? "false" : "true", false), _$ssrStyle(appWorkspaceLayoutStyle(initialLayoutState())), _$escape(contents()));
|
|
2131
2131
|
}
|
|
2132
2132
|
});
|
|
2133
2133
|
}
|
|
@@ -2142,7 +2142,7 @@ AppWorkspace.LayoutStateProvider = props => _$createComponent(LayoutStateContext
|
|
|
2142
2142
|
}
|
|
2143
2143
|
});
|
|
2144
2144
|
AppWorkspace.Head = AppWorkspaceHeadSlot;
|
|
2145
|
-
AppWorkspace.Content = props => _$ssr(_tmpl$
|
|
2145
|
+
AppWorkspace.Content = props => _$ssr(_tmpl$59, `k2b-app-workspace__content ${_$escape(props.class ?? "", true)}`, _$escape(props.children));
|
|
2146
2146
|
AppWorkspace.Main = AppWorkspaceMain;
|
|
2147
2147
|
AppWorkspace.MainPane = AppWorkspaceMainPane;
|
|
2148
2148
|
AppWorkspace.Detail = AppWorkspaceDetail;
|