@k2b/ui 0.26.0 → 0.28.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/README.md +1 -1
- package/dist/base.css +147 -2
- package/dist/browser/actions/ContextMenu.js +30 -4
- package/dist/browser/actions/ContextMenu.js.map +1 -1
- package/dist/browser/actions/Dropdown.js +184 -158
- package/dist/browser/actions/Dropdown.js.map +1 -1
- package/dist/browser/actions/GestureMenu.js +71 -138
- package/dist/browser/actions/GestureMenu.js.map +1 -1
- package/dist/browser/actions/Toolbar.js +379 -48
- package/dist/browser/actions/Toolbar.js.map +1 -1
- package/dist/browser/actions/index.js.map +1 -1
- package/dist/browser/actions/menu-rows.js +15 -0
- package/dist/browser/actions/menu-rows.js.map +1 -0
- package/dist/browser/actions/menu-sheet.js +154 -0
- package/dist/browser/actions/menu-sheet.js.map +1 -0
- package/dist/browser/actions/toolbar-messages.js +20 -0
- package/dist/browser/actions/toolbar-messages.js.map +1 -0
- package/dist/browser/chart-inspection.js +3 -0
- package/dist/browser/chart-inspection.js.map +1 -0
- package/dist/browser/chat/ChatComposer.js +1020 -431
- package/dist/browser/chat/ChatComposer.js.map +1 -1
- package/dist/browser/chat/chat-behavior.js +4 -0
- package/dist/browser/chat/chat-behavior.js.map +1 -1
- package/dist/browser/chat/chat-messages.js +33 -1
- package/dist/browser/chat/chat-messages.js.map +1 -1
- package/dist/browser/chat/command-search.js +173 -0
- package/dist/browser/chat/command-search.js.map +1 -0
- package/dist/browser/chat/composer-document.js +1 -1
- package/dist/browser/chat/composer-document.js.map +1 -1
- package/dist/browser/chat/index.js +2 -0
- package/dist/browser/chat/index.js.map +1 -1
- package/dist/browser/chat/reaction-people.js +15 -0
- package/dist/browser/chat/reaction-people.js.map +1 -0
- package/dist/browser/content/CalendarDayView.js +28 -3
- package/dist/browser/content/CalendarDayView.js.map +1 -1
- package/dist/browser/content/Chart.js +6 -15
- package/dist/browser/content/Chart.js.map +1 -1
- package/dist/browser/content/ChartSnapshotView.js +7 -10
- package/dist/browser/content/ChartSnapshotView.js.map +1 -1
- package/dist/browser/content/MessageRow.js +330 -448
- package/dist/browser/content/MessageRow.js.map +1 -1
- package/dist/browser/content/ReactionBar.js +419 -0
- package/dist/browser/content/ReactionBar.js.map +1 -0
- package/dist/browser/content/chart-inspection-core.js +557 -0
- package/dist/browser/content/chart-inspection-core.js.map +1 -0
- package/dist/browser/content/chart-inspection.js +10 -445
- package/dist/browser/content/chart-inspection.js.map +1 -1
- package/dist/browser/content/chart-line-gaps.js +1 -1
- package/dist/browser/content/chart-line-gaps.js.map +1 -1
- package/dist/browser/content/chart-snapshot.js +1 -1
- package/dist/browser/content/chart-snapshot.js.map +1 -1
- package/dist/browser/content/index.js +1 -0
- package/dist/browser/content/index.js.map +1 -1
- package/dist/browser/feedback/dialog-core.js +135 -23
- package/dist/browser/feedback/dialog-core.js.map +1 -1
- package/dist/browser/index.js +1 -0
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/input-mode.js +40 -0
- package/dist/browser/input-mode.js.map +1 -0
- package/dist/browser/inputs/Combobox.js +4 -2
- package/dist/browser/inputs/Combobox.js.map +1 -1
- package/dist/browser/inputs/FileDropTarget.js +24 -9
- package/dist/browser/inputs/FileDropTarget.js.map +1 -1
- package/dist/browser/inputs/FileInputs.js +2 -2
- package/dist/browser/inputs/FileInputs.js.map +1 -1
- package/dist/browser/inputs/SelectChip.js +52 -12
- package/dist/browser/inputs/SelectChip.js.map +1 -1
- package/dist/browser/inputs/emoji/EmojiPicker.js +13 -0
- package/dist/browser/inputs/emoji/EmojiPicker.js.map +1 -1
- package/dist/browser/inputs/file-drop.js.map +1 -1
- package/dist/browser/layout/AppWorkspace.js +708 -515
- package/dist/browser/layout/AppWorkspace.js.map +1 -1
- package/dist/browser/layout/BottomSheet.js +8 -0
- package/dist/browser/layout/BottomSheet.js.map +1 -1
- package/dist/browser/layout/DetailPanel.js +283 -197
- package/dist/browser/layout/DetailPanel.js.map +1 -1
- package/dist/browser/layout/Discussion.js +233 -185
- package/dist/browser/layout/Discussion.js.map +1 -1
- package/dist/browser/layout/TableOfContents.js +10 -2
- package/dist/browser/layout/TableOfContents.js.map +1 -1
- package/dist/browser/layout/app-workspace-controller.js +155 -23
- package/dist/browser/layout/app-workspace-controller.js.map +1 -1
- package/dist/browser/layout/app-workspace-state.js +5 -1
- package/dist/browser/layout/app-workspace-state.js.map +1 -1
- package/dist/browser/layout/detail-panel-messages.js +35 -0
- package/dist/browser/layout/detail-panel-messages.js.map +1 -0
- package/dist/browser/layout/index.js +1 -1
- package/dist/browser/layout/index.js.map +1 -1
- package/dist/browser/surfaces/Avatar.js +50 -20
- package/dist/browser/surfaces/Avatar.js.map +1 -1
- package/dist/browser/surfaces/AvatarStack.js +406 -0
- package/dist/browser/surfaces/AvatarStack.js.map +1 -0
- package/dist/browser/surfaces/avatar-messages.js +8 -2
- package/dist/browser/surfaces/avatar-messages.js.map +1 -1
- package/dist/browser/surfaces/index.js +1 -0
- package/dist/browser/surfaces/index.js.map +1 -1
- package/dist/ssr/actions/ContextMenu.js +21 -3
- package/dist/ssr/actions/ContextMenu.js.map +1 -1
- package/dist/ssr/actions/Dropdown.js +140 -72
- package/dist/ssr/actions/Dropdown.js.map +1 -1
- package/dist/ssr/actions/GestureMenu.js +52 -106
- package/dist/ssr/actions/GestureMenu.js.map +1 -1
- package/dist/ssr/actions/Toolbar.js +294 -14
- package/dist/ssr/actions/Toolbar.js.map +1 -1
- package/dist/ssr/actions/index.js.map +1 -1
- package/dist/ssr/actions/menu-rows.js +15 -0
- package/dist/ssr/actions/menu-rows.js.map +1 -0
- package/dist/ssr/actions/menu-sheet.js +138 -0
- package/dist/ssr/actions/menu-sheet.js.map +1 -0
- package/dist/ssr/actions/toolbar-messages.js +20 -0
- package/dist/ssr/actions/toolbar-messages.js.map +1 -0
- package/dist/ssr/chart-inspection.js +3 -0
- package/dist/ssr/chart-inspection.js.map +1 -0
- package/dist/ssr/chat/ChatComposer.js +604 -113
- package/dist/ssr/chat/ChatComposer.js.map +1 -1
- package/dist/ssr/chat/chat-behavior.js +4 -0
- package/dist/ssr/chat/chat-behavior.js.map +1 -1
- package/dist/ssr/chat/chat-messages.js +33 -1
- package/dist/ssr/chat/chat-messages.js.map +1 -1
- package/dist/ssr/chat/command-search.js +173 -0
- package/dist/ssr/chat/command-search.js.map +1 -0
- package/dist/ssr/chat/composer-document.js +1 -1
- package/dist/ssr/chat/composer-document.js.map +1 -1
- package/dist/ssr/chat/index.js +2 -0
- package/dist/ssr/chat/index.js.map +1 -1
- package/dist/ssr/chat/reaction-people.js +15 -0
- package/dist/ssr/chat/reaction-people.js.map +1 -0
- package/dist/ssr/content/CalendarDayView.js +28 -3
- package/dist/ssr/content/CalendarDayView.js.map +1 -1
- package/dist/ssr/content/Chart.js +6 -15
- package/dist/ssr/content/Chart.js.map +1 -1
- package/dist/ssr/content/ChartSnapshotView.js +7 -10
- package/dist/ssr/content/ChartSnapshotView.js.map +1 -1
- package/dist/ssr/content/MessageRow.js +98 -152
- package/dist/ssr/content/MessageRow.js.map +1 -1
- package/dist/ssr/content/ReactionBar.js +304 -0
- package/dist/ssr/content/ReactionBar.js.map +1 -0
- package/dist/ssr/content/chart-inspection-core.js +557 -0
- package/dist/ssr/content/chart-inspection-core.js.map +1 -0
- package/dist/ssr/content/chart-inspection.js +10 -445
- package/dist/ssr/content/chart-inspection.js.map +1 -1
- package/dist/ssr/content/chart-line-gaps.js +1 -1
- package/dist/ssr/content/chart-line-gaps.js.map +1 -1
- package/dist/ssr/content/chart-snapshot.js +1 -1
- package/dist/ssr/content/chart-snapshot.js.map +1 -1
- package/dist/ssr/content/index.js +1 -0
- package/dist/ssr/content/index.js.map +1 -1
- package/dist/ssr/feedback/dialog-core.js +135 -23
- package/dist/ssr/feedback/dialog-core.js.map +1 -1
- package/dist/ssr/index.js +1 -0
- package/dist/ssr/index.js.map +1 -1
- package/dist/ssr/input-mode.js +40 -0
- package/dist/ssr/input-mode.js.map +1 -0
- package/dist/ssr/inputs/Combobox.js +4 -2
- package/dist/ssr/inputs/Combobox.js.map +1 -1
- package/dist/ssr/inputs/FileDropTarget.js +17 -5
- package/dist/ssr/inputs/FileDropTarget.js.map +1 -1
- package/dist/ssr/inputs/FileInputs.js +2 -2
- package/dist/ssr/inputs/FileInputs.js.map +1 -1
- package/dist/ssr/inputs/SelectChip.js +44 -11
- package/dist/ssr/inputs/SelectChip.js.map +1 -1
- package/dist/ssr/inputs/emoji/EmojiPicker.js +12 -0
- package/dist/ssr/inputs/emoji/EmojiPicker.js.map +1 -1
- package/dist/ssr/inputs/file-drop.js.map +1 -1
- package/dist/ssr/layout/AppWorkspace.js +242 -105
- package/dist/ssr/layout/AppWorkspace.js.map +1 -1
- package/dist/ssr/layout/BottomSheet.js +8 -0
- package/dist/ssr/layout/BottomSheet.js.map +1 -1
- package/dist/ssr/layout/DetailPanel.js +112 -58
- package/dist/ssr/layout/DetailPanel.js.map +1 -1
- package/dist/ssr/layout/Discussion.js +63 -36
- package/dist/ssr/layout/Discussion.js.map +1 -1
- package/dist/ssr/layout/TableOfContents.js +10 -2
- package/dist/ssr/layout/TableOfContents.js.map +1 -1
- package/dist/ssr/layout/app-workspace-controller.js +155 -23
- package/dist/ssr/layout/app-workspace-controller.js.map +1 -1
- package/dist/ssr/layout/app-workspace-state.js +5 -1
- package/dist/ssr/layout/app-workspace-state.js.map +1 -1
- package/dist/ssr/layout/detail-panel-messages.js +35 -0
- package/dist/ssr/layout/detail-panel-messages.js.map +1 -0
- package/dist/ssr/layout/index.js +1 -1
- package/dist/ssr/layout/index.js.map +1 -1
- package/dist/ssr/surfaces/Avatar.js +20 -2
- package/dist/ssr/surfaces/Avatar.js.map +1 -1
- package/dist/ssr/surfaces/AvatarStack.js +286 -0
- package/dist/ssr/surfaces/AvatarStack.js.map +1 -0
- package/dist/ssr/surfaces/avatar-messages.js +8 -2
- package/dist/ssr/surfaces/avatar-messages.js.map +1 -1
- package/dist/ssr/surfaces/index.js +1 -0
- package/dist/ssr/surfaces/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/types/actions/ContextMenu.d.ts +8 -0
- package/dist/types/actions/Dropdown.d.ts +12 -5
- package/dist/types/actions/GestureMenu.d.ts +6 -4
- package/dist/types/actions/Toolbar.d.ts +20 -0
- package/dist/types/actions/index.d.ts +1 -1
- package/dist/types/actions/menu-rows.d.ts +5 -0
- package/dist/types/actions/menu-sheet.d.ts +22 -0
- package/dist/types/actions/toolbar-messages.d.ts +8 -0
- package/dist/types/chart-inspection.d.ts +2 -0
- package/dist/types/chat/ChatComposer.d.ts +51 -2
- package/dist/types/chat/chat-behavior.d.ts +4 -0
- package/dist/types/chat/chat-messages.d.ts +17 -2
- package/dist/types/chat/command-search.d.ts +41 -0
- package/dist/types/chat/index.d.ts +3 -1
- package/dist/types/chat/reaction-people.d.ts +9 -0
- package/dist/types/content/Chart.d.ts +2 -2
- package/dist/types/content/MessageRow.d.ts +3 -10
- package/dist/types/content/ReactionBar.d.ts +32 -0
- package/dist/types/content/chart-inspection-core.d.ts +61 -0
- package/dist/types/content/chart-inspection.d.ts +4 -20
- package/dist/types/content/chart-snapshot.d.ts +1 -1
- package/dist/types/content/index.d.ts +2 -1
- package/dist/types/feedback/dialog-core.d.ts +16 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/input-mode.d.ts +7 -0
- package/dist/types/inputs/FileDropTarget.d.ts +6 -3
- package/dist/types/inputs/SelectChip.d.ts +6 -0
- package/dist/types/inputs/file-drop.d.ts +2 -0
- package/dist/types/layout/AppWorkspace.d.ts +13 -1
- package/dist/types/layout/BottomSheet.d.ts +8 -0
- package/dist/types/layout/DetailPanel.d.ts +11 -0
- package/dist/types/layout/Discussion.d.ts +8 -0
- package/dist/types/layout/TableOfContents.d.ts +2 -0
- package/dist/types/layout/detail-panel-messages.d.ts +15 -0
- package/dist/types/layout/index.d.ts +1 -1
- package/dist/types/surfaces/Avatar.d.ts +12 -0
- package/dist/types/surfaces/AvatarStack.d.ts +41 -0
- package/dist/types/surfaces/avatar-messages.d.ts +3 -0
- package/dist/types/surfaces/index.d.ts +3 -1
- package/package.json +9 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["layout/Discussion.tsx"],"sourcesContent":["import { createEffect, createSignal, createUniqueId, type JSX, onCleanup, onMount, Show, splitProps } from \"solid-js\";\nimport { Button, IconButton } from \"../actions/Button\";\nimport { useChatMessages } from \"../chat/chat-messages\";\nimport { MarkdownEditor } from \"../inputs/markdown/MarkdownEditor\";\nimport { useUiMessages } from \"../intl/messages\";\n\nexport type DiscussionProps = Omit<JSX.HTMLAttributes<HTMLElement>, \"children\" | \"class\"> & {\n label: JSX.Element;\n children: JSX.Element;\n icon?: string | false;\n count?: number;\n actions?: JSX.Element;\n as?: \"h2\" | \"h3\";\n surface?: \"default\" | \"bare\";\n class?: string;\n};\n\nexport type DiscussionComposerProps = Omit<JSX.FormHTMLAttributes<HTMLFormElement>, \"children\" | \"class\" | \"onSubmit\"> & {\n label: string;\n onSubmit: (message: string) => boolean | void | Promise<boolean | void>;\n initialValue?: string;\n placeholder?: string;\n submitLabel?: string;\n cancelLabel?: string;\n onCancel?: () => void;\n lines?: number;\n class?: string;\n};\n\nexport type DiscussionListProps = {\n children?: JSX.Element;\n loading?: boolean;\n loadingLabel?: string;\n error?: string | null;\n onRetry?: () => void | Promise<void>;\n hasMore?: boolean;\n loadingMore?: boolean;\n loadMoreLabel?: string;\n onLoadMore?: () => boolean | void | Promise<boolean | void>;\n class?: string;\n};\n\nexport type DiscussionItemProps = Omit<JSX.LiHTMLAttributes<HTMLLIElement>, \"children\" | \"class\"> & {\n author: JSX.Element;\n children: JSX.Element;\n avatar?: JSX.Element;\n timestamp?: JSX.Element;\n meta?: JSX.Element;\n replyContext?: JSX.Element;\n actions?: JSX.Element;\n actionVisibility?: \"always\" | \"progressive\";\n class?: string;\n};\n\ntype DiscussionComponent = ((props: DiscussionProps) => JSX.Element) & {\n Composer: (props: DiscussionComposerProps) => JSX.Element;\n List: (props: DiscussionListProps) => JSX.Element;\n Item: (props: DiscussionItemProps) => JSX.Element;\n};\n\nconst classNames = (base: string, extra?: string): string => (extra ? `${base} ${extra}` : base);\n\nconst DiscussionRoot = (props: DiscussionProps): JSX.Element => {\n const headingId = `k2b-discussion-${createUniqueId()}`;\n const [local, sectionProps] = splitProps(props, [\"label\", \"children\", \"icon\", \"count\", \"actions\", \"as\", \"surface\", \"class\"]);\n\n return (\n <section\n {...sectionProps}\n class={classNames(\"k2b-discussion\", local.class)}\n data-surface={local.surface ?? \"default\"}\n aria-labelledby={headingId}\n >\n <header class=\"k2b-discussion__header\">\n <Show when={local.icon !== false && local.icon}>\n {(icon) => (\n <span class=\"k2b-discussion__icon\" aria-hidden=\"true\">\n <i class={icon()} />\n </span>\n )}\n </Show>\n <Show when={local.as === \"h2\"} fallback={<h3 id={headingId}>{local.label}</h3>}>\n <h2 id={headingId}>{local.label}</h2>\n </Show>\n <Show when={local.count !== undefined}>\n <span class=\"k2b-discussion__count\">{local.count}</span>\n </Show>\n <Show when={local.actions !== undefined}>\n <div class=\"k2b-discussion__actions\">{local.actions}</div>\n </Show>\n </header>\n <div class=\"k2b-discussion__body\">{local.children}</div>\n </section>\n );\n};\n\nconst DiscussionComposer = (props: DiscussionComposerProps): JSX.Element => {\n const messages = useUiMessages();\n const chatMessages = useChatMessages();\n const [local, formProps] = splitProps(props, [\n \"label\",\n \"onSubmit\",\n \"initialValue\",\n \"placeholder\",\n \"submitLabel\",\n \"cancelLabel\",\n \"onCancel\",\n \"lines\",\n \"class\",\n ]);\n const [message, setMessage] = createSignal(local.initialValue ?? \"\");\n const [submitting, setSubmitting] = createSignal(false);\n const [submitError, setSubmitError] = createSignal<string | null>(null);\n\n const submit = async () => {\n const normalized = message().trim();\n if (!normalized || submitting()) return;\n setSubmitting(true);\n setSubmitError(null);\n try {\n const accepted = await local.onSubmit(normalized);\n if (accepted !== false) setMessage(\"\");\n } catch (error) {\n setSubmitError(error instanceof Error ? error.message : chatMessages().couldNotPostMessage);\n } finally {\n setSubmitting(false);\n }\n };\n\n return (\n <form\n {...formProps}\n class={classNames(\"k2b-discussion__composer\", local.class)}\n onSubmit={(event) => {\n event.preventDefault();\n void submit();\n }}\n >\n <div class=\"k2b-discussion__composer-field\" data-has-inset-action=\"true\">\n <MarkdownEditor\n aria-label={local.label}\n value={message}\n onValueChange={(value) => {\n // The error belongs to the submitted text; any edit, including clearing it, makes it stale.\n if (value !== message()) setSubmitError(null);\n setMessage(value);\n }}\n placeholder={local.placeholder}\n lines={local.lines ?? 4}\n noToolbar\n showStats={false}\n disabled={submitting()}\n error={submitError() !== null}\n onSubmit={() => void submit()}\n />\n <div class=\"k2b-discussion__composer-inset-action\">\n <IconButton\n type=\"submit\"\n label={local.submitLabel ?? chatMessages().postMessage}\n size=\"sm\"\n variant=\"primary\"\n loading={submitting()}\n disabled={submitting() || !message().trim()}\n >\n <i class=\"ti ti-send\" aria-hidden=\"true\" />\n </IconButton>\n </div>\n </div>\n <Show when={submitError()}>\n {(error) => (\n <p class=\"k2b-discussion__status\" role=\"alert\">\n {error()}\n </p>\n )}\n </Show>\n <Show when={local.onCancel}>\n {(onCancel) => (\n <footer>\n <Button type=\"button\" variant=\"ghost\" size=\"xs\" disabled={submitting()} onClick={onCancel()}>\n {local.cancelLabel ?? messages().cancel}\n </Button>\n </footer>\n )}\n </Show>\n </form>\n );\n};\n\nconst scrollOwner = (element: HTMLElement): HTMLElement | null => {\n let parent = element.parentElement;\n while (parent) {\n const style = getComputedStyle(parent);\n if (style.overflowY === \"auto\" || style.overflowY === \"scroll\" || style.overflow === \"auto\" || style.overflow === \"scroll\")\n return parent;\n parent = parent.parentElement;\n }\n return document.scrollingElement instanceof HTMLElement ? document.scrollingElement : null;\n};\n\nconst DiscussionList = (props: DiscussionListProps): JSX.Element => {\n const messages = useUiMessages();\n const chatMessages = useChatMessages();\n const [loadingMoreInternally, setLoadingMoreInternally] = createSignal(false);\n const [loadMoreError, setLoadMoreError] = createSignal<string | null>(null);\n const [sentinelVisible, setSentinelVisible] = createSignal(false);\n const [automaticLoadAttempted, setAutomaticLoadAttempted] = createSignal(false);\n let listRef: HTMLOListElement | undefined;\n let sentinelRef: HTMLDivElement | undefined;\n let observer: IntersectionObserver | undefined;\n let adjustmentFrame: number | undefined;\n let active = true;\n\n const loadingMore = () => Boolean(props.loadingMore || loadingMoreInternally());\n const canLoadMore = () =>\n Boolean(!props.loading && !props.error && !loadMoreError() && props.hasMore && props.onLoadMore && !loadingMore());\n\n const loadMore = async (retry = false): Promise<boolean> => {\n if (props.loading || props.error || (!retry && loadMoreError()) || !props.onLoadMore || !props.hasMore || loadingMore()) return false;\n const owner = listRef ? scrollOwner(listRef) : null;\n const previousScrollHeight = owner?.scrollHeight ?? 0;\n setLoadMoreError(null);\n setLoadingMoreInternally(true);\n let loaded = false;\n try {\n loaded = (await props.onLoadMore()) !== false;\n } catch (error) {\n if (active) setLoadMoreError(error instanceof Error ? error.message : chatMessages().couldNotLoadEarlierMessages);\n } finally {\n if (active) setLoadingMoreInternally(false);\n }\n if (!active || !loaded || !owner) return false;\n queueMicrotask(() => {\n if (!active) return;\n adjustmentFrame = requestAnimationFrame(() => {\n if (!active) return;\n owner.scrollTop += owner.scrollHeight - previousScrollHeight;\n });\n });\n return true;\n };\n\n createEffect(() => {\n if (!sentinelVisible()) {\n setAutomaticLoadAttempted(false);\n return;\n }\n if (automaticLoadAttempted() || !canLoadMore()) return;\n setAutomaticLoadAttempted(true);\n void loadMore();\n });\n\n onMount(() => {\n if (typeof IntersectionObserver === \"undefined\" || !sentinelRef) return;\n observer = new IntersectionObserver(\n (entries) => {\n setSentinelVisible(entries.some((entry) => entry.isIntersecting));\n },\n { rootMargin: \"160px 0px 0px\" },\n );\n observer.observe(sentinelRef);\n });\n\n onCleanup(() => {\n active = false;\n observer?.disconnect();\n if (adjustmentFrame !== undefined) cancelAnimationFrame(adjustmentFrame);\n });\n\n return (\n <div class={classNames(\"k2b-discussion__list-region\", props.class)} aria-busy={props.loading || loadingMore() ? \"true\" : undefined}>\n <div ref={sentinelRef} class=\"k2b-discussion__sentinel\" aria-hidden=\"true\" />\n <Show when={props.loading}>\n <p class=\"k2b-discussion__status\" role=\"status\">\n <i class=\"ti ti-loader-2 k2b-spin\" aria-hidden=\"true\" /> {props.loadingLabel ?? chatMessages().loadingMessages}\n </p>\n </Show>\n <Show when={props.error}>\n {(error) => (\n <div class=\"k2b-discussion__status\" role=\"alert\">\n <span>{error()}</span>\n <Show when={props.onRetry}>\n <button type=\"button\" onClick={props.onRetry}>\n {messages().retry}\n </button>\n </Show>\n </div>\n )}\n </Show>\n <Show when={loadMoreError()}>\n {(error) => (\n <div class=\"k2b-discussion__status\" role=\"alert\">\n <span>{error()}</span>\n <button type=\"button\" onClick={() => void loadMore(true)}>\n {messages().retry}\n </button>\n </div>\n )}\n </Show>\n <Show when={!props.loading && !props.error && !loadMoreError() && (canLoadMore() || loadingMore())}>\n <button type=\"button\" class=\"k2b-discussion__load-more\" disabled={loadingMore()} onClick={() => void loadMore()}>\n <i class={`ti ${loadingMore() ? \"ti-loader-2 k2b-spin\" : \"ti-history\"}`} aria-hidden=\"true\" />\n {loadingMore() ? (props.loadingLabel ?? chatMessages().loadingMessages) : (props.loadMoreLabel ?? chatMessages().loadEarlier)}\n </button>\n </Show>\n <ol ref={listRef} class=\"k2b-discussion__list\">\n {props.children}\n </ol>\n </div>\n );\n};\n\nconst DiscussionItem = (props: DiscussionItemProps): JSX.Element => {\n const [local, itemProps] = splitProps(props, [\n \"author\",\n \"children\",\n \"avatar\",\n \"timestamp\",\n \"meta\",\n \"replyContext\",\n \"actions\",\n \"actionVisibility\",\n \"class\",\n ]);\n return (\n <li\n {...itemProps}\n class={classNames(\"k2b-discussion__item\", local.class)}\n data-has-avatar={local.avatar !== undefined ? \"true\" : undefined}\n >\n <Show when={local.avatar !== undefined}>\n <div class=\"k2b-discussion__avatar\">{local.avatar}</div>\n </Show>\n <div class=\"k2b-discussion__entry\">\n <header>\n <strong>{local.author}</strong>\n <Show when={local.timestamp !== undefined}>\n <span class=\"k2b-discussion__timestamp\">{local.timestamp}</span>\n </Show>\n <Show when={local.meta !== undefined}>\n <span class=\"k2b-discussion__meta\">{local.meta}</span>\n </Show>\n <Show when={local.actions !== undefined}>\n <div class=\"k2b-discussion__item-actions\" data-visibility={local.actionVisibility ?? \"progressive\"}>\n {local.actions}\n </div>\n </Show>\n </header>\n <Show when={local.replyContext !== undefined}>\n <div class=\"k2b-discussion__reply-context\">{local.replyContext}</div>\n </Show>\n <div class=\"k2b-discussion__content\">{local.children}</div>\n </div>\n </li>\n );\n};\n\nconst Discussion = DiscussionRoot as DiscussionComponent;\nDiscussion.Composer = DiscussionComposer;\nDiscussion.List = DiscussionList;\nDiscussion.Item = DiscussionItem;\n\nexport default Discussion;\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":[],"sources":["layout/Discussion.tsx"],"sourcesContent":["import { children, createEffect, createSignal, createUniqueId, type JSX, onCleanup, onMount, Show, splitProps } from \"solid-js\";\nimport { Button, IconButton } from \"../actions/Button\";\nimport { useChatMessages } from \"../chat/chat-messages\";\nimport { MarkdownEditor } from \"../inputs/markdown/MarkdownEditor\";\nimport { useUiMessages } from \"../intl/messages\";\nimport { DetailPanelCount } from \"./DetailPanel\";\nimport { useDetailPanelMessages } from \"./detail-panel-messages\";\n\nexport type DiscussionProps = Omit<JSX.HTMLAttributes<HTMLElement>, \"children\" | \"class\"> & {\n label: JSX.Element;\n children: JSX.Element;\n icon?: string | false;\n count?: number;\n actions?: JSX.Element;\n as?: \"h2\" | \"h3\";\n surface?: \"default\" | \"bare\";\n class?: string;\n};\n\nexport type DiscussionComposerProps = Omit<JSX.FormHTMLAttributes<HTMLFormElement>, \"children\" | \"class\" | \"onSubmit\"> & {\n label: string;\n onSubmit: (message: string) => boolean | void | Promise<boolean | void>;\n initialValue?: string;\n placeholder?: string;\n submitLabel?: string;\n cancelLabel?: string;\n onCancel?: () => void;\n lines?: number;\n class?: string;\n};\n\nexport type DiscussionListProps = {\n children?: JSX.Element;\n loading?: boolean;\n loadingLabel?: string;\n error?: string | null;\n onRetry?: () => void | Promise<void>;\n hasMore?: boolean;\n loadingMore?: boolean;\n loadMoreLabel?: string;\n onLoadMore?: () => boolean | void | Promise<boolean | void>;\n /**\n * Shows only the newest `fold` entries and a \"Show n older\" toggle above them. Expanded, the toggle reads \"Show less\"\n * and earlier pages load as usual. Omit it to show every loaded entry.\n */\n fold?: number;\n /** Controls the fold, for example to reveal an older entry; `onExpandedChange` requests a change. */\n expanded?: boolean;\n onExpandedChange?: (expanded: boolean) => void;\n class?: string;\n};\n\nexport type DiscussionItemProps = Omit<JSX.LiHTMLAttributes<HTMLLIElement>, \"children\" | \"class\"> & {\n author: JSX.Element;\n children: JSX.Element;\n avatar?: JSX.Element;\n timestamp?: JSX.Element;\n meta?: JSX.Element;\n replyContext?: JSX.Element;\n actions?: JSX.Element;\n actionVisibility?: \"always\" | \"progressive\";\n class?: string;\n};\n\ntype DiscussionComponent = ((props: DiscussionProps) => JSX.Element) & {\n Composer: (props: DiscussionComposerProps) => JSX.Element;\n List: (props: DiscussionListProps) => JSX.Element;\n Item: (props: DiscussionItemProps) => JSX.Element;\n};\n\nconst classNames = (base: string, extra?: string): string => (extra ? `${base} ${extra}` : base);\n\nconst DiscussionRoot = (props: DiscussionProps): JSX.Element => {\n const headingId = `k2b-discussion-${createUniqueId()}`;\n const [local, sectionProps] = splitProps(props, [\"label\", \"children\", \"icon\", \"count\", \"actions\", \"as\", \"surface\", \"class\"]);\n\n return (\n <section\n {...sectionProps}\n class={classNames(\"k2b-discussion\", local.class)}\n data-surface={local.surface ?? \"default\"}\n aria-labelledby={headingId}\n >\n <header class=\"k2b-discussion__header\">\n <Show when={local.icon !== false && local.icon}>\n {(icon) => (\n <span class=\"k2b-discussion__icon\" aria-hidden=\"true\">\n <i class={icon()} />\n </span>\n )}\n </Show>\n <Show when={local.as === \"h2\"} fallback={<h3 id={headingId}>{local.label}</h3>}>\n <h2 id={headingId}>{local.label}</h2>\n </Show>\n <Show when={local.count !== undefined}>\n <DetailPanelCount count={local.count ?? 0} />\n </Show>\n <Show when={local.actions !== undefined}>\n <div class=\"k2b-discussion__actions\">{local.actions}</div>\n </Show>\n </header>\n <div class=\"k2b-discussion__body\">{local.children}</div>\n </section>\n );\n};\n\nconst DiscussionComposer = (props: DiscussionComposerProps): JSX.Element => {\n const messages = useUiMessages();\n const chatMessages = useChatMessages();\n const [local, formProps] = splitProps(props, [\n \"label\",\n \"onSubmit\",\n \"initialValue\",\n \"placeholder\",\n \"submitLabel\",\n \"cancelLabel\",\n \"onCancel\",\n \"lines\",\n \"class\",\n ]);\n const [message, setMessage] = createSignal(local.initialValue ?? \"\");\n const [submitting, setSubmitting] = createSignal(false);\n const [submitError, setSubmitError] = createSignal<string | null>(null);\n\n const submit = async () => {\n const normalized = message().trim();\n if (!normalized || submitting()) return;\n setSubmitting(true);\n setSubmitError(null);\n try {\n const accepted = await local.onSubmit(normalized);\n if (accepted !== false) setMessage(\"\");\n } catch (error) {\n setSubmitError(error instanceof Error ? error.message : chatMessages().couldNotPostMessage);\n } finally {\n setSubmitting(false);\n }\n };\n\n return (\n <form\n {...formProps}\n class={classNames(\"k2b-discussion__composer\", local.class)}\n onSubmit={(event) => {\n event.preventDefault();\n void submit();\n }}\n >\n <div class=\"k2b-discussion__composer-field\" data-has-inset-action=\"true\">\n <MarkdownEditor\n aria-label={local.label}\n value={message}\n onValueChange={(value) => {\n // The error belongs to the submitted text; any edit, including clearing it, makes it stale.\n if (value !== message()) setSubmitError(null);\n setMessage(value);\n }}\n placeholder={local.placeholder}\n lines={local.lines ?? 4}\n noToolbar\n showStats={false}\n disabled={submitting()}\n error={submitError() !== null}\n onSubmit={() => void submit()}\n />\n <div class=\"k2b-discussion__composer-inset-action\">\n <IconButton\n type=\"submit\"\n label={local.submitLabel ?? chatMessages().postMessage}\n size=\"sm\"\n variant=\"primary\"\n loading={submitting()}\n disabled={submitting() || !message().trim()}\n >\n <i class=\"ti ti-send\" aria-hidden=\"true\" />\n </IconButton>\n </div>\n </div>\n <Show when={submitError()}>\n {(error) => (\n <p class=\"k2b-discussion__status\" role=\"alert\">\n {error()}\n </p>\n )}\n </Show>\n <Show when={local.onCancel}>\n {(onCancel) => (\n <footer>\n <Button type=\"button\" variant=\"ghost\" size=\"xs\" disabled={submitting()} onClick={onCancel()}>\n {local.cancelLabel ?? messages().cancel}\n </Button>\n </footer>\n )}\n </Show>\n </form>\n );\n};\n\nconst scrollOwner = (element: HTMLElement): HTMLElement | null => {\n let parent = element.parentElement;\n while (parent) {\n const style = getComputedStyle(parent);\n if (style.overflowY === \"auto\" || style.overflowY === \"scroll\" || style.overflow === \"auto\" || style.overflow === \"scroll\")\n return parent;\n parent = parent.parentElement;\n }\n return document.scrollingElement instanceof HTMLElement ? document.scrollingElement : null;\n};\n\nconst DiscussionList = (props: DiscussionListProps): JSX.Element => {\n const messages = useUiMessages();\n const chatMessages = useChatMessages();\n const foldMessages = useDetailPanelMessages();\n const [internalExpanded, setInternalExpanded] = createSignal(false);\n const expanded = () => props.expanded ?? internalExpanded();\n const setExpanded = (next: boolean) => {\n if (props.expanded === undefined) setInternalExpanded(next);\n props.onExpandedChange?.(next);\n };\n const resolved = children(() => props.children);\n const entries = () => resolved.toArray();\n const hidden = () => (props.fold !== undefined && !expanded() ? Math.max(0, entries().length - props.fold) : 0);\n const folded = () => props.fold !== undefined && entries().length > props.fold;\n const visible = () => (hidden() > 0 ? entries().slice(hidden()) : entries());\n const [loadingMoreInternally, setLoadingMoreInternally] = createSignal(false);\n const [loadMoreError, setLoadMoreError] = createSignal<string | null>(null);\n const [sentinelVisible, setSentinelVisible] = createSignal(false);\n const [automaticLoadAttempted, setAutomaticLoadAttempted] = createSignal(false);\n let listRef: HTMLOListElement | undefined;\n let sentinelRef: HTMLDivElement | undefined;\n let observer: IntersectionObserver | undefined;\n let adjustmentFrame: number | undefined;\n let active = true;\n\n const loadingMore = () => Boolean(props.loadingMore || loadingMoreInternally());\n const canLoadMore = () =>\n Boolean(!props.loading && !props.error && !loadMoreError() && hidden() === 0 && props.hasMore && props.onLoadMore && !loadingMore());\n\n const loadMore = async (retry = false): Promise<boolean> => {\n if (props.loading || props.error || (!retry && loadMoreError()) || hidden() > 0 || !props.onLoadMore || !props.hasMore || loadingMore())\n return false;\n const owner = listRef ? scrollOwner(listRef) : null;\n const previousScrollHeight = owner?.scrollHeight ?? 0;\n setLoadMoreError(null);\n setLoadingMoreInternally(true);\n let loaded = false;\n try {\n loaded = (await props.onLoadMore()) !== false;\n } catch (error) {\n if (active) setLoadMoreError(error instanceof Error ? error.message : chatMessages().couldNotLoadEarlierMessages);\n } finally {\n if (active) setLoadingMoreInternally(false);\n }\n if (!active || !loaded || !owner) return false;\n queueMicrotask(() => {\n if (!active) return;\n adjustmentFrame = requestAnimationFrame(() => {\n if (!active) return;\n owner.scrollTop += owner.scrollHeight - previousScrollHeight;\n });\n });\n return true;\n };\n\n createEffect(() => {\n if (!sentinelVisible()) {\n setAutomaticLoadAttempted(false);\n return;\n }\n if (automaticLoadAttempted() || !canLoadMore()) return;\n setAutomaticLoadAttempted(true);\n void loadMore();\n });\n\n onMount(() => {\n if (typeof IntersectionObserver === \"undefined\" || !sentinelRef) return;\n observer = new IntersectionObserver(\n (entries) => {\n setSentinelVisible(entries.some((entry) => entry.isIntersecting));\n },\n { rootMargin: \"160px 0px 0px\" },\n );\n observer.observe(sentinelRef);\n });\n\n onCleanup(() => {\n active = false;\n observer?.disconnect();\n if (adjustmentFrame !== undefined) cancelAnimationFrame(adjustmentFrame);\n });\n\n return (\n <div class={classNames(\"k2b-discussion__list-region\", props.class)} aria-busy={props.loading || loadingMore() ? \"true\" : undefined}>\n <div ref={sentinelRef} class=\"k2b-discussion__sentinel\" aria-hidden=\"true\" />\n <Show when={props.loading}>\n <p class=\"k2b-discussion__status\" role=\"status\">\n <i class=\"ti ti-loader-2 k2b-spin\" aria-hidden=\"true\" /> {props.loadingLabel ?? chatMessages().loadingMessages}\n </p>\n </Show>\n <Show when={props.error}>\n {(error) => (\n <div class=\"k2b-discussion__status\" role=\"alert\">\n <span>{error()}</span>\n <Show when={props.onRetry}>\n <button type=\"button\" onClick={props.onRetry}>\n {messages().retry}\n </button>\n </Show>\n </div>\n )}\n </Show>\n <Show when={loadMoreError()}>\n {(error) => (\n <div class=\"k2b-discussion__status\" role=\"alert\">\n <span>{error()}</span>\n <button type=\"button\" onClick={() => void loadMore(true)}>\n {messages().retry}\n </button>\n </div>\n )}\n </Show>\n {/* The toggle stays above the entries in both states, so nothing above it moves. A failed refresh keeps it:\n the entries it folds are still there. */}\n <Show when={folded() && !props.loading}>\n <button type=\"button\" class=\"k2b-discussion__fold\" aria-expanded={hidden() === 0} onClick={() => setExpanded(hidden() > 0)}>\n <i class={`ti ${hidden() > 0 ? \"ti-chevron-down\" : \"ti-chevron-up\"}`} aria-hidden=\"true\" />\n {hidden() > 0 ? foldMessages().showOlder({ count: hidden() }) : foldMessages().showLess}\n </button>\n </Show>\n <Show when={!props.loading && !props.error && !loadMoreError() && (canLoadMore() || loadingMore())}>\n <button type=\"button\" class=\"k2b-discussion__load-more\" disabled={loadingMore()} onClick={() => void loadMore()}>\n <i class={`ti ${loadingMore() ? \"ti-loader-2 k2b-spin\" : \"ti-history\"}`} aria-hidden=\"true\" />\n {loadingMore() ? (props.loadingLabel ?? chatMessages().loadingMessages) : (props.loadMoreLabel ?? chatMessages().loadEarlier)}\n </button>\n </Show>\n <ol ref={listRef} class=\"k2b-discussion__list\">\n {visible()}\n </ol>\n </div>\n );\n};\n\nconst DiscussionItem = (props: DiscussionItemProps): JSX.Element => {\n const [local, itemProps] = splitProps(props, [\n \"author\",\n \"children\",\n \"avatar\",\n \"timestamp\",\n \"meta\",\n \"replyContext\",\n \"actions\",\n \"actionVisibility\",\n \"class\",\n ]);\n return (\n <li\n {...itemProps}\n class={classNames(\"k2b-discussion__item\", local.class)}\n data-has-avatar={local.avatar !== undefined ? \"true\" : undefined}\n >\n <Show when={local.avatar !== undefined}>\n <div class=\"k2b-discussion__avatar\">{local.avatar}</div>\n </Show>\n <div class=\"k2b-discussion__entry\">\n <header>\n <strong>{local.author}</strong>\n <Show when={local.meta !== undefined}>\n <span class=\"k2b-discussion__meta\">{local.meta}</span>\n </Show>\n {/* Times end on the panel's trailing edge; item actions sit just before them. */}\n <Show when={local.actions !== undefined}>\n <div class=\"k2b-discussion__item-actions\" data-visibility={local.actionVisibility ?? \"progressive\"}>\n {local.actions}\n </div>\n </Show>\n <Show when={local.timestamp !== undefined}>\n <span class=\"k2b-discussion__timestamp\">{local.timestamp}</span>\n </Show>\n </header>\n <Show when={local.replyContext !== undefined}>\n <div class=\"k2b-discussion__reply-context\">{local.replyContext}</div>\n </Show>\n <div class=\"k2b-discussion__content\">{local.children}</div>\n </div>\n </li>\n );\n};\n\nconst Discussion = DiscussionRoot as DiscussionComponent;\nDiscussion.Composer = DiscussionComposer;\nDiscussion.List = DiscussionList;\nDiscussion.Item = DiscussionItem;\n\nexport default Discussion;\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -24,6 +24,14 @@ export function TableOfContents(props) {
|
|
|
24
24
|
// Reading every id here makes a changed id or a store update recompute the active section.
|
|
25
25
|
const ids = props.items.map(item => item.id);
|
|
26
26
|
const root = resolveMaybeAccessor(props.scrollRoot);
|
|
27
|
+
const content = resolveMaybeAccessor(props.contentRoot);
|
|
28
|
+
const heading = id => {
|
|
29
|
+
const element = document.getElementById(id);
|
|
30
|
+
if (!content || element && content.contains(element)) return element;
|
|
31
|
+
// The same id elsewhere on the page, or a root outside the document tree, needs a lookup within the root.
|
|
32
|
+
for (const candidate of content.querySelectorAll("[id]")) if (candidate.id === id) return candidate;
|
|
33
|
+
return null;
|
|
34
|
+
};
|
|
27
35
|
const target = root ?? window;
|
|
28
36
|
let frame;
|
|
29
37
|
const update = () => {
|
|
@@ -34,7 +42,7 @@ export function TableOfContents(props) {
|
|
|
34
42
|
const line = top + height / 4;
|
|
35
43
|
const headings = ids.map(id => ({
|
|
36
44
|
id,
|
|
37
|
-
box:
|
|
45
|
+
box: heading(id)?.getBoundingClientRect()
|
|
38
46
|
}));
|
|
39
47
|
let next = ids[0];
|
|
40
48
|
for (const heading of headings) if (heading.box && heading.box.top <= line) next = heading.id;
|
|
@@ -55,7 +63,7 @@ export function TableOfContents(props) {
|
|
|
55
63
|
window.addEventListener("resize", schedule);
|
|
56
64
|
const observer = typeof ResizeObserver === "undefined" ? undefined : new ResizeObserver(schedule);
|
|
57
65
|
// No scroll or window resize happens when the root, a block above a heading, or a heading's own section changes size.
|
|
58
|
-
const observed = new Set([root ?? document.documentElement, ...(root?.children ?? [document.body]), ...ids.map(id =>
|
|
66
|
+
const observed = new Set([root ?? document.documentElement, ...(root?.children ?? [document.body]), ...ids.map(id => heading(id)?.parentElement)]);
|
|
59
67
|
for (const element of observed) if (element) observer?.observe(element);
|
|
60
68
|
untrack(update);
|
|
61
69
|
onCleanup(() => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["layout/TableOfContents.tsx"],"sourcesContent":["import { createEffect, createSignal, createUniqueId, For, type JSX, onCleanup, Show, untrack } from \"solid-js\";\nimport type { MaybeAccessor } from \"../inputs/field-contract\";\nimport { resolveMaybeAccessor } from \"../inputs/field-contract\";\nimport { assertStableUiId } from \"./stable-id\";\nimport { useTableOfContentsMessages } from \"./table-of-contents-messages\";\n\nexport type TableOfContentsItem = { id: string; label: string };\nexport type TableOfContentsProps = {\n items: readonly TableOfContentsItem[];\n /** Visible heading and navigation name. Defaults to the localized \"On this page\". */\n title?: string;\n /** Element whose scrolling decides the active section. Defaults to the window. */\n scrollRoot?: MaybeAccessor<HTMLElement | undefined>;\n /** Stay in view inside the caller's layout. */\n sticky?: boolean;\n /** Called when another section becomes active. */\n onActiveChange?: (id: string | undefined) => void;\n class?: string;\n};\n\n/**\n * Native section links with a scroll spy on the window or a content container.\n * @example <TableOfContents items={[{ id: \"sharing\", label: \"Sharing\" }]} sticky />\n */\nexport function TableOfContents(props: TableOfContentsProps): JSX.Element {\n const t = useTableOfContentsMessages();\n const headingId = assertStableUiId(`k2b-toc-${createUniqueId().replace(/[^a-zA-Z0-9_-]/g, \"-\")}`, \"TableOfContents heading id\");\n const [active, setActive] = createSignal(props.items[0]?.id);\n createEffect(() => {\n // Reading every id here makes a changed id or a store update recompute the active section.\n const ids = props.items.map((item) => item.id);\n const root = resolveMaybeAccessor(props.scrollRoot);\n const target = root ?? window;\n let frame: number | undefined;\n const update = () => {\n frame = undefined;\n const box = root?.getBoundingClientRect();\n const top = box ? box.top + (root?.clientTop ?? 0) : 0;\n const height = root?.clientHeight ?? window.innerHeight;\n const line = top + height / 4;\n const headings = ids.map((id) => ({ id, box:
|
|
1
|
+
{"version":3,"names":[],"sources":["layout/TableOfContents.tsx"],"sourcesContent":["import { createEffect, createSignal, createUniqueId, For, type JSX, onCleanup, Show, untrack } from \"solid-js\";\nimport type { MaybeAccessor } from \"../inputs/field-contract\";\nimport { resolveMaybeAccessor } from \"../inputs/field-contract\";\nimport { assertStableUiId } from \"./stable-id\";\nimport { useTableOfContentsMessages } from \"./table-of-contents-messages\";\n\nexport type TableOfContentsItem = { id: string; label: string };\nexport type TableOfContentsProps = {\n items: readonly TableOfContentsItem[];\n /** Visible heading and navigation name. Defaults to the localized \"On this page\". */\n title?: string;\n /** Element whose scrolling decides the active section. Defaults to the window. */\n scrollRoot?: MaybeAccessor<HTMLElement | undefined>;\n /** Element that contains the section headings. Defaults to the document. */\n contentRoot?: MaybeAccessor<HTMLElement | undefined>;\n /** Stay in view inside the caller's layout. */\n sticky?: boolean;\n /** Called when another section becomes active. */\n onActiveChange?: (id: string | undefined) => void;\n class?: string;\n};\n\n/**\n * Native section links with a scroll spy on the window or a content container.\n * @example <TableOfContents items={[{ id: \"sharing\", label: \"Sharing\" }]} sticky />\n */\nexport function TableOfContents(props: TableOfContentsProps): JSX.Element {\n const t = useTableOfContentsMessages();\n const headingId = assertStableUiId(`k2b-toc-${createUniqueId().replace(/[^a-zA-Z0-9_-]/g, \"-\")}`, \"TableOfContents heading id\");\n const [active, setActive] = createSignal(props.items[0]?.id);\n createEffect(() => {\n // Reading every id here makes a changed id or a store update recompute the active section.\n const ids = props.items.map((item) => item.id);\n const root = resolveMaybeAccessor(props.scrollRoot);\n const content = resolveMaybeAccessor(props.contentRoot);\n const heading = (id: string): Element | null => {\n const element = document.getElementById(id);\n if (!content || (element && content.contains(element))) return element;\n // The same id elsewhere on the page, or a root outside the document tree, needs a lookup within the root.\n for (const candidate of content.querySelectorAll(\"[id]\")) if (candidate.id === id) return candidate;\n return null;\n };\n const target = root ?? window;\n let frame: number | undefined;\n const update = () => {\n frame = undefined;\n const box = root?.getBoundingClientRect();\n const top = box ? box.top + (root?.clientTop ?? 0) : 0;\n const height = root?.clientHeight ?? window.innerHeight;\n const line = top + height / 4;\n const headings = ids.map((id) => ({ id, box: heading(id)?.getBoundingClientRect() }));\n let next = ids[0];\n for (const heading of headings) if (heading.box && heading.box.top <= line) next = heading.id;\n const last = headings.at(-1);\n const atEnd = root\n ? root.scrollHeight - root.clientHeight - root.scrollTop <= 4\n : document.documentElement.scrollHeight - window.innerHeight - window.scrollY <= 4;\n if (atEnd && last?.box && last.box.top < top + height && last.box.bottom > top) next = last.id;\n if (next !== active()) {\n setActive(next);\n props.onActiveChange?.(next);\n }\n };\n const schedule = () => {\n if (frame === undefined) frame = requestAnimationFrame(update);\n };\n target.addEventListener(\"scroll\", schedule, { passive: true });\n window.addEventListener(\"resize\", schedule);\n const observer = typeof ResizeObserver === \"undefined\" ? undefined : new ResizeObserver(schedule);\n // No scroll or window resize happens when the root, a block above a heading, or a heading's own section changes size.\n const observed = new Set<Element | null | undefined>([\n root ?? document.documentElement,\n ...(root?.children ?? [document.body]),\n ...ids.map((id) => heading(id)?.parentElement),\n ]);\n for (const element of observed) if (element) observer?.observe(element);\n untrack(update);\n onCleanup(() => {\n target.removeEventListener(\"scroll\", schedule);\n window.removeEventListener(\"resize\", schedule);\n observer?.disconnect();\n if (frame !== undefined) cancelAnimationFrame(frame);\n });\n });\n return (\n <Show when={props.items.length > 0}>\n <nav\n class={`k2b-toc${props.class ? ` ${props.class}` : \"\"}`}\n data-sticky={props.sticky ? \"true\" : undefined}\n aria-labelledby={headingId}\n >\n <p class=\"k2b-toc__title\" id={headingId}>\n {props.title ?? t().title}\n </p>\n <ol class=\"k2b-toc__list\">\n <For each={props.items}>\n {(item) => (\n <li>\n <a class=\"k2b-toc__link\" href={`#${item.id}`} aria-current={active() === item.id ? \"location\" : undefined}>\n {item.label}\n </a>\n </li>\n )}\n </For>\n </ol>\n </nav>\n </Show>\n );\n}\nexport default TableOfContents;\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { suppressTextSelection } from "../internal/text-selection";
|
|
2
2
|
import { prefersReducedMotion } from "../motion";
|
|
3
|
-
import { APP_WORKSPACE_DETAIL_DEFAULT, APP_WORKSPACE_DETAIL_MAX, APP_WORKSPACE_DETAIL_MIN, APP_WORKSPACE_DRAWER_MAX, APP_WORKSPACE_DRAWER_MIN, APP_WORKSPACE_MAIN_MIN, APP_WORKSPACE_PANE_MAX, APP_WORKSPACE_PANE_MIN, APP_WORKSPACE_SIDEBAR_COLLAPSED, APP_WORKSPACE_SIDEBAR_MAX, APP_WORKSPACE_SIDEBAR_MIN, appWorkspacePanelVariable, appWorkspaceResizeLimits, fitAppWorkspacePaneSizes, normalizeAppWorkspaceLayoutState, resolveAppWorkspaceSidebarWidth, safeAppWorkspacePanelId, shouldCollapseAppWorkspaceSidebar } from "./app-workspace-state";
|
|
3
|
+
import { APP_WORKSPACE_DETAIL_DEFAULT, APP_WORKSPACE_DETAIL_MAX, APP_WORKSPACE_DETAIL_MIN, 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_MAX, APP_WORKSPACE_SIDEBAR_MIN, appWorkspacePanelVariable, appWorkspaceResizeLimits, fitAppWorkspacePaneSizes, normalizeAppWorkspaceLayoutState, resolveAppWorkspaceSidebarWidth, safeAppWorkspacePanelId, shouldCollapseAppWorkspaceSidebar } from "./app-workspace-state";
|
|
4
4
|
import { installScrollFades } from "./scroll-fade";
|
|
5
5
|
const HANDLE_SELECTOR = "[data-app-workspace-resize]";
|
|
6
6
|
const ROOT_SELECTOR = "[data-k2b-app-workspace]";
|
|
@@ -57,7 +57,16 @@ const controlledPanel = (root, handle) => {
|
|
|
57
57
|
const panel = document.getElementById(controls);
|
|
58
58
|
return panel?.closest(ROOT_SELECTOR) === root ? panel : null;
|
|
59
59
|
};
|
|
60
|
-
const
|
|
60
|
+
const flexibleLevel = pane => {
|
|
61
|
+
if (!pane.hasAttribute("data-workspace-level")) return false;
|
|
62
|
+
const widthClass = window.matchMedia("(min-width: 80rem)").matches ? "3" : window.matchMedia("(min-width: 48rem)").matches ? "2" : "1";
|
|
63
|
+
return pane.dataset.workspaceLevelLast?.split(" ").includes(widthClass) ?? false;
|
|
64
|
+
};
|
|
65
|
+
const levelsMain = handle => handle.closest(".k2b-app-workspace__main")?.hasAttribute("data-workspace-levels") ?? false;
|
|
66
|
+
const controlsResizableRegion = (root, handle, kind) => {
|
|
67
|
+
const panel = kind === "sidebar" ? sidebarElement(root) : controlledPanel(root, handle);
|
|
68
|
+
return panel?.dataset.workspaceResizable === "true" && (!panel.hasAttribute("data-workspace-level") || isVisible(panel) && isVisible(handle) && !flexibleLevel(panel));
|
|
69
|
+
};
|
|
61
70
|
const panelId = handle => safeAppWorkspacePanelId(handle.dataset.workspacePanelId ?? "primary") || "primary";
|
|
62
71
|
const numberData = (handle, key, fallback) => {
|
|
63
72
|
const value = Number(handle.dataset[key]);
|
|
@@ -66,7 +75,11 @@ const numberData = (handle, key, fallback) => {
|
|
|
66
75
|
const sizeLimits = (root, handle, kind) => {
|
|
67
76
|
const controlled = controlledPanel(root, handle);
|
|
68
77
|
const main = kind === "pane" ? handle.closest(".k2b-app-workspace__main") : mainElement(root);
|
|
69
|
-
const panes = main ? Array.from(main.querySelectorAll(".k2b-app-workspace__main-pane")).filter(pane => pane.closest(".k2b-app-workspace__main") === main && !pane.classList.contains("is-primary") && isVisible(pane)) : [];
|
|
78
|
+
const panes = main ? Array.from(main.querySelectorAll(".k2b-app-workspace__main-pane")).filter(pane => pane.closest(".k2b-app-workspace__main") === main && !pane.classList.contains("is-primary") && !flexibleLevel(pane) && isVisible(pane)) : [];
|
|
79
|
+
const separatorSize = kind === "pane" && main ? Array.from(main.querySelectorAll(`.k2b-app-workspace__resize${HANDLE_SELECTOR}`)).filter(separator => separator.closest(".k2b-app-workspace__main") === main && resizeKind(separator) === "pane" && isVisible(separator)).reduce((total, separator) => {
|
|
80
|
+
const style = getComputedStyle(separator);
|
|
81
|
+
return total + Math.max(0, separator.getBoundingClientRect().width + (Number.parseFloat(style.marginLeft) || 0) + (Number.parseFloat(style.marginRight) || 0));
|
|
82
|
+
}, 0) : 0;
|
|
70
83
|
// Content ends before the detail track, so its width alone would shrink a
|
|
71
84
|
// persisted panel again on every reconciliation. Measure from Content's
|
|
72
85
|
// start to the workspace's inner end: this includes the detail column and
|
|
@@ -77,7 +90,7 @@ const sizeLimits = (root, handle, kind) => {
|
|
|
77
90
|
return appWorkspaceResizeLimits({
|
|
78
91
|
kind,
|
|
79
92
|
workspaceSize: kind === "drawer" ? root.getBoundingClientRect().height : kind === "pane" && main ? main.getBoundingClientRect().width : content ? root.getBoundingClientRect().right - root.clientLeft - content.getBoundingClientRect().left : root.getBoundingClientRect().width,
|
|
80
|
-
reservedSize: kind === "detail" ? 8 : kind === "pane" ? panes.reduce((total, pane) => total + (pane === controlled ? 0 : elementSize(pane, "pane")), 0) : 0,
|
|
93
|
+
reservedSize: kind === "detail" ? 8 : kind === "pane" ? panes.reduce((total, pane) => total + (pane === controlled ? 0 : elementSize(pane, "pane")), 0) + separatorSize : 0,
|
|
81
94
|
min: numberData(handle, "workspaceMinSize", defaultMin),
|
|
82
95
|
max: numberData(handle, "workspaceMaxSize", defaultMax),
|
|
83
96
|
sidebarCollapsible: kind === "sidebar" && sidebarCollapsible(root)
|
|
@@ -140,6 +153,18 @@ const reconcilePanes = (root, layoutState, active = null) => {
|
|
|
140
153
|
if (!main || !isVisible(main)) return;
|
|
141
154
|
const handles = rootElements(root, HANDLE_SELECTOR).filter(handle => resizeKind(handle) === "pane" && controlsResizableRegion(root, handle, "pane"));
|
|
142
155
|
if (!handles.length) return;
|
|
156
|
+
if (main.hasAttribute("data-workspace-levels")) {
|
|
157
|
+
// CSS owns the multi-level fit, including a flexible shown-last pane.
|
|
158
|
+
// Keep preferences intact when the window temporarily has less room.
|
|
159
|
+
for (const handle of handles) {
|
|
160
|
+
const min = numberData(handle, "workspaceMinSize", APP_WORKSPACE_PANE_MIN);
|
|
161
|
+
const max = Math.max(min, numberData(handle, "workspaceMaxSize", APP_WORKSPACE_PANE_MAX));
|
|
162
|
+
const preferred = active?.moved && active.handle === handle ? active.liveSize : layoutState.paneWidths?.[panelId(handle)];
|
|
163
|
+
if (preferred !== undefined) root.style.setProperty(appWorkspacePanelVariable("pane", panelId(handle)), `${clamp(preferred, min, max)}px`);
|
|
164
|
+
updateHandleValue(root, handle, "pane", currentSize(root, handle, "pane"));
|
|
165
|
+
}
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
143
168
|
const controlled = new Set(handles.map(handle => controlledPanel(root, handle)).filter(Boolean));
|
|
144
169
|
const fixedWidth = Array.from(main.querySelectorAll(".k2b-app-workspace__main-pane")).filter(pane => pane.closest(".k2b-app-workspace__main") === main && !pane.classList.contains("is-primary") && isVisible(pane) && !controlled.has(pane)).reduce((total, pane) => total + elementSize(pane, "pane"), 0);
|
|
145
170
|
const fits = handles.flatMap(handle => {
|
|
@@ -268,27 +293,43 @@ export const installAppWorkspaceController = (options = {}) => {
|
|
|
268
293
|
if (control.matches("a[href]") || control.closest(ITEM_SELECTOR)) closeOverlay("kept");
|
|
269
294
|
};
|
|
270
295
|
const onOverlayKeyDown = event => {
|
|
271
|
-
if (
|
|
296
|
+
if (event.defaultPrevented) return;
|
|
272
297
|
const target = eventElement(event);
|
|
273
298
|
if (!target) return;
|
|
274
299
|
// Escape also closes it when a click left focus on nothing, so on the body.
|
|
275
|
-
if (event.key === "Escape" && (overlay.sidebar.contains(target) || target === ownerDocument.body)) {
|
|
300
|
+
if (overlay && event.key === "Escape" && (overlay.sidebar.contains(target) || target === ownerDocument.body)) {
|
|
276
301
|
event.preventDefault();
|
|
277
302
|
closeOverlay("button");
|
|
278
303
|
return;
|
|
279
304
|
}
|
|
280
|
-
|
|
281
|
-
const
|
|
305
|
+
const aside = target.closest(detailSelector);
|
|
306
|
+
const panel = overlay?.sidebar ?? (phone?.matches && aside && !aside.hidden && phonePage(aside) && eventRoot.contains(aside) ? aside : null);
|
|
307
|
+
if (event.key !== "Tab") return;
|
|
308
|
+
if (!panel) {
|
|
309
|
+
// Focus outside an open phone page, on the body after a load or on chrome the page covers, enters the page.
|
|
310
|
+
// Dialogs and popovers keep their own Tab order.
|
|
311
|
+
const page = phone?.matches ? allRoots().flatMap(openDetails).find(phonePage) : undefined;
|
|
312
|
+
if (!page || ownerDocument.querySelector("dialog[open], [aria-modal='true']") || target.closest("[popover]")) return;
|
|
313
|
+
const stops = tabStopsIn(page);
|
|
314
|
+
event.preventDefault();
|
|
315
|
+
(event.shiftKey ? stops.at(-1) : stops[0])?.focus();
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
if (!panel.contains(target)) return;
|
|
319
|
+
const stops = tabStopsIn(panel);
|
|
282
320
|
const first = stops[0];
|
|
283
321
|
const last = stops.at(-1);
|
|
284
322
|
if (!first || !last) {
|
|
285
323
|
event.preventDefault();
|
|
286
324
|
return;
|
|
287
325
|
}
|
|
288
|
-
|
|
326
|
+
// Focus can also rest on an element that is no tab stop, such as a title focused as the panel opened.
|
|
327
|
+
const active = document.activeElement;
|
|
328
|
+
const before = (element, other) => Boolean(element && other && element.compareDocumentPosition(other) & Node.DOCUMENT_POSITION_FOLLOWING);
|
|
329
|
+
if (event.shiftKey && !stops.some(stop => before(stop, active))) {
|
|
289
330
|
event.preventDefault();
|
|
290
331
|
last.focus();
|
|
291
|
-
} else if (!event.shiftKey &&
|
|
332
|
+
} else if (!event.shiftKey && !stops.some(stop => before(active, stop))) {
|
|
292
333
|
event.preventDefault();
|
|
293
334
|
first.focus();
|
|
294
335
|
}
|
|
@@ -445,7 +486,9 @@ export const installAppWorkspaceController = (options = {}) => {
|
|
|
445
486
|
subtree: true
|
|
446
487
|
});
|
|
447
488
|
};
|
|
489
|
+
const phonePage = aside => aside.dataset.workspaceDetailPhone === "page";
|
|
448
490
|
const setDetent = (aside, full) => {
|
|
491
|
+
if (phonePage(aside)) return;
|
|
449
492
|
touchedDetails.add(aside);
|
|
450
493
|
if (full) aside.dataset.workspaceDetailSheet = "full";else delete aside.dataset.workspaceDetailSheet;
|
|
451
494
|
aside.querySelector(grabberSelector)?.setAttribute("aria-pressed", String(full));
|
|
@@ -489,6 +532,7 @@ export const installAppWorkspaceController = (options = {}) => {
|
|
|
489
532
|
root.dataset.workspaceDetailSliding = "";
|
|
490
533
|
};
|
|
491
534
|
const revealItem = (root, aside, snapshot) => {
|
|
535
|
+
if (phone?.matches && phonePage(aside)) return;
|
|
492
536
|
const pending = revealFrames.get(root);
|
|
493
537
|
if (pending !== undefined) cancelAnimationFrame(pending);
|
|
494
538
|
revealFrames.set(root, requestAnimationFrame(() => {
|
|
@@ -734,6 +778,7 @@ export const installAppWorkspaceController = (options = {}) => {
|
|
|
734
778
|
const aside = target?.closest(detailSelector);
|
|
735
779
|
const root = aside?.closest(ROOT_SELECTOR);
|
|
736
780
|
if (!target || !aside || !root || aside.hidden || !observedRoots.has(root) || target.closest(ROOT_SELECTOR) !== root) return;
|
|
781
|
+
if (phonePage(aside)) return;
|
|
737
782
|
const grabber = target.closest(grabberSelector);
|
|
738
783
|
if (!grabber && (!target.closest(".k2b-detail-panel__header") || target.closest("a, button, input, select, textarea, [role='button'], [contenteditable]:not([contenteditable='false'])"))) return;
|
|
739
784
|
claimedDetailGestures.add(event);
|
|
@@ -759,7 +804,7 @@ export const installAppWorkspaceController = (options = {}) => {
|
|
|
759
804
|
const target = eventElement(event);
|
|
760
805
|
const grabber = target?.closest(grabberSelector);
|
|
761
806
|
const aside = grabber?.closest(detailSelector);
|
|
762
|
-
if (!aside || aside.hidden || !phone?.matches || claimedToggleClicks.has(event)) return;
|
|
807
|
+
if (!aside || aside.hidden || phonePage(aside) || !phone?.matches || claimedToggleClicks.has(event)) return;
|
|
763
808
|
claimedToggleClicks.add(event);
|
|
764
809
|
if (suppressedClick === aside && event instanceof MouseEvent && event.detail !== 0) {
|
|
765
810
|
event.preventDefault();
|
|
@@ -789,6 +834,7 @@ export const installAppWorkspaceController = (options = {}) => {
|
|
|
789
834
|
const touch = event.touches[0];
|
|
790
835
|
const root = aside?.closest(ROOT_SELECTOR);
|
|
791
836
|
if (!target || !aside || !root || aside.hidden || !touch || !observedRoots.has(root) || target.closest(ROOT_SELECTOR) !== root) return;
|
|
837
|
+
if (phone?.matches && phonePage(aside)) return;
|
|
792
838
|
if (phone?.matches && (verticalScroller(target, aside) ?? aside).scrollTop <= 0) {
|
|
793
839
|
if (!ownsTouchGesture(target, aside, "sheet")) beginDetailDrag(aside, target, "sheet", touch.clientX, touch.clientY, touch.identifier);
|
|
794
840
|
} else if (touchDrawer?.matches && closable(aside)) {
|
|
@@ -840,22 +886,27 @@ export const installAppWorkspaceController = (options = {}) => {
|
|
|
840
886
|
const onDetailTouchEnd = event => {
|
|
841
887
|
if (detailDrag && detailDrag.source !== "pointer") finishDetailDrag(event.type === "touchcancel");
|
|
842
888
|
};
|
|
843
|
-
const
|
|
889
|
+
const onPanelDoubleClick = event => {
|
|
844
890
|
const handle = resizeHandle(event);
|
|
845
891
|
const root = handle?.closest(ROOT_SELECTOR);
|
|
846
|
-
|
|
892
|
+
const kind = handle ? resizeKind(handle) : null;
|
|
893
|
+
if (!handle || !root || kind !== "detail" && kind !== "pane" || !workspaceResizable(root) || !controlsResizableRegion(root, handle, kind)) return;
|
|
894
|
+
const key = kind === "pane" ? "paneWidths" : "detailWidths";
|
|
847
895
|
const widths = {
|
|
848
|
-
...layoutState
|
|
896
|
+
...layoutState[key]
|
|
849
897
|
};
|
|
850
898
|
delete widths[panelId(handle)];
|
|
851
899
|
layoutState = {
|
|
852
900
|
...layoutState,
|
|
853
|
-
|
|
901
|
+
[key]: widths
|
|
854
902
|
};
|
|
855
|
-
const variable = appWorkspacePanelVariable(
|
|
903
|
+
const variable = appWorkspacePanelVariable(kind, panelId(handle));
|
|
856
904
|
root.style.removeProperty(variable);
|
|
857
|
-
|
|
858
|
-
|
|
905
|
+
// An SSR ancestor may still supply the old preference until the next request.
|
|
906
|
+
if (getComputedStyle(root).getPropertyValue(variable).trim()) root.style.setProperty(variable, `${numberData(handle, "workspaceDefaultSize", kind === "pane" ? APP_WORKSPACE_PANE_DEFAULT : APP_WORKSPACE_DETAIL_DEFAULT)}px`);
|
|
907
|
+
// The siblings fit again around the default width, also in a Main without levels.
|
|
908
|
+
if (kind === "pane") reconcilePanes(root, layoutState);
|
|
909
|
+
updateHandleValue(root, handle, kind, currentSize(root, handle, kind));
|
|
859
910
|
options.writeState?.(layoutState);
|
|
860
911
|
};
|
|
861
912
|
const stopScrollFades = installScrollFades(eventRoot);
|
|
@@ -885,6 +936,40 @@ export const installAppWorkspaceController = (options = {}) => {
|
|
|
885
936
|
}
|
|
886
937
|
options.writeState?.(layoutState);
|
|
887
938
|
};
|
|
939
|
+
|
|
940
|
+
// A level resize starts from what is on screen. When the stored widths do
|
|
941
|
+
// not fit beside the flexible level, CSS shrinks the resizable levels (a
|
|
942
|
+
// level without a separator does not shrink), so a step from a shrunk width
|
|
943
|
+
// would land on a preference that shrinks again and jump. The visible
|
|
944
|
+
// resizable levels therefore take their rendered widths as preferences when
|
|
945
|
+
// a step really moves; then they fit, and the step moves exactly by its
|
|
946
|
+
// size. All widths are measured before any is written, because each write
|
|
947
|
+
// reflows the others.
|
|
948
|
+
const settleLevels = (root, handle) => {
|
|
949
|
+
const main = handle.closest(".k2b-app-workspace__main");
|
|
950
|
+
if (!main?.hasAttribute("data-workspace-levels")) return;
|
|
951
|
+
const widths = Array.from(main.querySelectorAll(HANDLE_SELECTOR)).filter(other => other.closest(".k2b-app-workspace__main") === main && resizeKind(other) === "pane").flatMap(other => {
|
|
952
|
+
const panel = controlledPanel(root, other);
|
|
953
|
+
return isVisible(panel) && !flexibleLevel(panel) && panel.dataset.workspaceResizable === "true" ? [{
|
|
954
|
+
id: panelId(other),
|
|
955
|
+
width: Math.round(elementSize(panel, "pane"))
|
|
956
|
+
}] : [];
|
|
957
|
+
});
|
|
958
|
+
for (const {
|
|
959
|
+
id,
|
|
960
|
+
width
|
|
961
|
+
} of widths) {
|
|
962
|
+
if (layoutState.paneWidths?.[id] === width) continue;
|
|
963
|
+
root.style.setProperty(appWorkspacePanelVariable("pane", id), `${width}px`);
|
|
964
|
+
layoutState = {
|
|
965
|
+
...layoutState,
|
|
966
|
+
paneWidths: {
|
|
967
|
+
...layoutState.paneWidths,
|
|
968
|
+
[id]: width
|
|
969
|
+
}
|
|
970
|
+
};
|
|
971
|
+
}
|
|
972
|
+
};
|
|
888
973
|
const flushPointerMove = () => {
|
|
889
974
|
if (resizeFrame !== null) {
|
|
890
975
|
cancelAnimationFrame(resizeFrame);
|
|
@@ -893,8 +978,18 @@ export const installAppWorkspaceController = (options = {}) => {
|
|
|
893
978
|
if (!active || pendingClient === null) return;
|
|
894
979
|
const client = pendingClient;
|
|
895
980
|
pendingClient = null;
|
|
896
|
-
active.moved ||= client !== active.startClient;
|
|
897
981
|
const requested = active.startSize + (client - active.startClient) * active.direction;
|
|
982
|
+
// A press without movement, or a drag that the limits stop, changes no
|
|
983
|
+
// level preference, also not a sibling's.
|
|
984
|
+
if (!active.moved && client !== active.startClient && active.kind === "pane" && levelsMain(active.handle)) {
|
|
985
|
+
const {
|
|
986
|
+
min,
|
|
987
|
+
max
|
|
988
|
+
} = sizeLimits(active.root, active.handle, "pane");
|
|
989
|
+
if (clamp(requested, min, max) === Math.round(currentSize(active.root, active.handle, "pane"))) return;
|
|
990
|
+
settleLevels(active.root, active.handle);
|
|
991
|
+
}
|
|
992
|
+
active.moved ||= client !== active.startClient;
|
|
898
993
|
// Below half the smallest visible width a hideable sidebar stays at its
|
|
899
994
|
// minimum and previews hiding; dragging back out resumes the live width.
|
|
900
995
|
const hiding = active.kind === "sidebar" && sidebarHideable(active.root) && requested < sizeLimits(active.root, active.handle, active.kind).min / 2;
|
|
@@ -1000,6 +1095,11 @@ export const installAppWorkspaceController = (options = {}) => {
|
|
|
1000
1095
|
else if (kind !== "drawer" && event.key === "ArrowLeft") requested = collapsibleSidebar && current <= APP_WORKSPACE_SIDEBAR_MIN ? APP_WORKSPACE_SIDEBAR_COLLAPSED : current - step * direction;else if (kind !== "drawer" && event.key === "ArrowRight") requested = collapsibleSidebar && current <= APP_WORKSPACE_SIDEBAR_COLLAPSED ? layoutState.sidebarWidth ?? APP_WORKSPACE_SIDEBAR_MIN : current + step * direction;
|
|
1001
1096
|
if (requested === null) return;
|
|
1002
1097
|
event.preventDefault();
|
|
1098
|
+
if (kind === "pane" && levelsMain(handle)) {
|
|
1099
|
+
// A step that the limits stop changes no preference, also not a sibling's.
|
|
1100
|
+
if (clamp(requested, min, max) === Math.round(current)) return;
|
|
1101
|
+
settleLevels(root, handle);
|
|
1102
|
+
}
|
|
1003
1103
|
persistSize(handle, kind, applySize(root, handle, kind, requested));
|
|
1004
1104
|
if (kind === "sidebar" || kind === "detail") reconcilePanes(root, layoutState);
|
|
1005
1105
|
};
|
|
@@ -1007,6 +1107,32 @@ export const installAppWorkspaceController = (options = {}) => {
|
|
|
1007
1107
|
const nested = Array.from(eventRoot.querySelectorAll(ROOT_SELECTOR));
|
|
1008
1108
|
return eventRoot instanceof HTMLElement && eventRoot.matches(ROOT_SELECTOR) ? [eventRoot, ...nested] : nested;
|
|
1009
1109
|
};
|
|
1110
|
+
// Remember only attributes we own; application-set inert survives every transition.
|
|
1111
|
+
const phonePageInerted = new Set();
|
|
1112
|
+
const syncPhonePages = () => {
|
|
1113
|
+
const regions = new Set();
|
|
1114
|
+
if (phone?.matches) {
|
|
1115
|
+
for (const root of allRoots()) {
|
|
1116
|
+
if (!root.isConnected) continue;
|
|
1117
|
+
for (const aside of openDetails(root).filter(phonePage)) {
|
|
1118
|
+
for (let node = aside; node && node !== root; node = node.parentElement) {
|
|
1119
|
+
const parent = node.parentElement;
|
|
1120
|
+
if (parent) overlayRegions(parent, aside).forEach(region => regions.add(region));
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
phonePageInerted.forEach(region => {
|
|
1126
|
+
if (regions.has(region)) return;
|
|
1127
|
+
region.removeAttribute("inert");
|
|
1128
|
+
phonePageInerted.delete(region);
|
|
1129
|
+
});
|
|
1130
|
+
regions.forEach(region => {
|
|
1131
|
+
if (region.hasAttribute("inert")) return;
|
|
1132
|
+
region.setAttribute("inert", "");
|
|
1133
|
+
phonePageInerted.add(region);
|
|
1134
|
+
});
|
|
1135
|
+
};
|
|
1010
1136
|
const roots = () => {
|
|
1011
1137
|
// A hidden or zero-width workspace measures 0, which drives every limit
|
|
1012
1138
|
// down to its minimum — reconciling one would overwrite its variables and
|
|
@@ -1125,12 +1251,13 @@ export const installAppWorkspaceController = (options = {}) => {
|
|
|
1125
1251
|
};
|
|
1126
1252
|
const layoutNode = node => node instanceof Element && (node.matches(LAYOUT_REGION_SELECTOR) || Boolean(node.querySelector(LAYOUT_REGION_SELECTOR)));
|
|
1127
1253
|
const mutationObserver = typeof MutationObserver === "undefined" ? null : new MutationObserver(records => {
|
|
1254
|
+
syncPhonePages();
|
|
1128
1255
|
if (pendingTitle && (pendingTitle.aside.hidden || !pendingTitle.aside.isConnected)) cancelTitle();
|
|
1129
1256
|
// Hiding or removing the sidebar, or its button, ends the overlay.
|
|
1130
1257
|
if (overlay && (overlay.sidebar.hidden || !overlay.sidebar.isConnected || !overlay.toggle.isConnected)) closeOverlay("kept");
|
|
1131
1258
|
const details = new Set();
|
|
1132
1259
|
for (const record of records) {
|
|
1133
|
-
if (record.type === "attributes" && record.target instanceof HTMLElement && record.target.matches(detailSelector) && !details.has(record.target)) {
|
|
1260
|
+
if (record.type === "attributes" && record.attributeName === "hidden" && record.target instanceof HTMLElement && record.target.matches(detailSelector) && !details.has(record.target)) {
|
|
1134
1261
|
details.add(record.target);
|
|
1135
1262
|
detailTransition(record.target, detailHidden.get(record.target) ?? record.oldValue !== null);
|
|
1136
1263
|
}
|
|
@@ -1152,7 +1279,7 @@ export const installAppWorkspaceController = (options = {}) => {
|
|
|
1152
1279
|
eventRoot.addEventListener("focusin", onDetailFocusIn);
|
|
1153
1280
|
eventRoot.addEventListener("pointerdown", onSheetPointerDown);
|
|
1154
1281
|
eventRoot.addEventListener("click", onGrabberClick);
|
|
1155
|
-
eventRoot.addEventListener("dblclick",
|
|
1282
|
+
eventRoot.addEventListener("dblclick", onPanelDoubleClick);
|
|
1156
1283
|
window.addEventListener("pointermove", onSheetPointerMove);
|
|
1157
1284
|
window.addEventListener("pointerup", onSheetPointerEnd);
|
|
1158
1285
|
window.addEventListener("pointercancel", onSheetPointerEnd);
|
|
@@ -1163,19 +1290,24 @@ export const installAppWorkspaceController = (options = {}) => {
|
|
|
1163
1290
|
eventRoot.addEventListener("touchend", onDetailTouchEnd);
|
|
1164
1291
|
eventRoot.addEventListener("touchcancel", onDetailTouchEnd);
|
|
1165
1292
|
compact?.addEventListener("change", onCompactChange);
|
|
1293
|
+
phone?.addEventListener("change", syncPhonePages);
|
|
1166
1294
|
eventRoot.addEventListener("keydown", onKeyDown);
|
|
1167
1295
|
eventRoot.addEventListener("focusin", onFocusIn);
|
|
1168
1296
|
window.addEventListener("resize", onResize);
|
|
1297
|
+
syncPhonePages();
|
|
1169
1298
|
syncObservedRoots();
|
|
1170
1299
|
mutationObserver?.observe(eventRoot, {
|
|
1171
1300
|
attributes: true,
|
|
1172
1301
|
attributeOldValue: true,
|
|
1173
|
-
attributeFilter: ["hidden"],
|
|
1302
|
+
attributeFilter: ["hidden", "data-workspace-level-shown"],
|
|
1174
1303
|
childList: true,
|
|
1175
1304
|
subtree: true
|
|
1176
1305
|
});
|
|
1177
1306
|
scheduleReconcile();
|
|
1178
1307
|
return () => {
|
|
1308
|
+
phonePageInerted.forEach(region => region.removeAttribute("inert"));
|
|
1309
|
+
phonePageInerted.clear();
|
|
1310
|
+
phone?.removeEventListener("change", syncPhonePages);
|
|
1179
1311
|
cancelTitle();
|
|
1180
1312
|
pendingAnchors.forEach(cancel => cancel());
|
|
1181
1313
|
slides.forEach(end => end());
|
|
@@ -1200,7 +1332,7 @@ export const installAppWorkspaceController = (options = {}) => {
|
|
|
1200
1332
|
eventRoot.removeEventListener("focusin", onDetailFocusIn);
|
|
1201
1333
|
eventRoot.removeEventListener("pointerdown", onSheetPointerDown);
|
|
1202
1334
|
eventRoot.removeEventListener("click", onGrabberClick);
|
|
1203
|
-
eventRoot.removeEventListener("dblclick",
|
|
1335
|
+
eventRoot.removeEventListener("dblclick", onPanelDoubleClick);
|
|
1204
1336
|
window.removeEventListener("pointermove", onSheetPointerMove);
|
|
1205
1337
|
window.removeEventListener("pointerup", onSheetPointerEnd);
|
|
1206
1338
|
window.removeEventListener("pointercancel", onSheetPointerEnd);
|