@k2b/ui 0.31.0 → 0.33.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/base.css +2 -0
- package/dist/browser/actions/Dropdown.js +159 -99
- package/dist/browser/actions/Dropdown.js.map +1 -1
- package/dist/browser/actions/FilterChip.js +113 -56
- package/dist/browser/actions/FilterChip.js.map +1 -1
- package/dist/browser/actions/ViewTabs.js +8 -0
- package/dist/browser/actions/ViewTabs.js.map +1 -1
- package/dist/browser/actions/filter-messages.js +26 -2
- package/dist/browser/actions/filter-messages.js.map +1 -1
- package/dist/browser/actions/menu-rows.js +23 -3
- package/dist/browser/actions/menu-rows.js.map +1 -1
- package/dist/browser/actions/menu-sheet.js +2 -7
- package/dist/browser/actions/menu-sheet.js.map +1 -1
- package/dist/browser/chat/ChatComposer.js +480 -403
- package/dist/browser/chat/ChatComposer.js.map +1 -1
- package/dist/browser/chat/chat-messages.js +14 -0
- package/dist/browser/chat/chat-messages.js.map +1 -1
- package/dist/browser/chat/index.js.map +1 -1
- package/dist/browser/content/Calendar.js +39 -29
- package/dist/browser/content/Calendar.js.map +1 -1
- package/dist/browser/content/CalendarDayView.js +159 -165
- package/dist/browser/content/CalendarDayView.js.map +1 -1
- package/dist/browser/content/Chart.js +104 -55
- package/dist/browser/content/Chart.js.map +1 -1
- package/dist/browser/content/ChartExplorer.js +5 -3
- package/dist/browser/content/ChartExplorer.js.map +1 -1
- package/dist/browser/content/MapView.js +4 -4
- package/dist/browser/content/MapView.js.map +1 -1
- package/dist/browser/content/MessageRow.js +607 -343
- package/dist/browser/content/MessageRow.js.map +1 -1
- package/dist/browser/content/ReactionBar.js +17 -0
- package/dist/browser/content/ReactionBar.js.map +1 -1
- package/dist/browser/content/chart-inspection-core.js +4 -1
- package/dist/browser/content/chart-inspection-core.js.map +1 -1
- package/dist/browser/content/code-highlight.js +66 -0
- package/dist/browser/content/code-highlight.js.map +1 -1
- package/dist/browser/content/index.js +2 -1
- package/dist/browser/content/index.js.map +1 -1
- package/dist/browser/content/map-view-live.js +47 -10
- package/dist/browser/content/map-view-live.js.map +1 -1
- package/dist/browser/content/map-view-types.js.map +1 -1
- package/dist/browser/feedback/dialog-core.js +6 -0
- package/dist/browser/feedback/dialog-core.js.map +1 -1
- package/dist/browser/inputs/AutocompleteEditor.js +167 -104
- package/dist/browser/inputs/AutocompleteEditor.js.map +1 -1
- package/dist/browser/inputs/RichSelect.js +1474 -0
- package/dist/browser/inputs/RichSelect.js.map +1 -0
- package/dist/browser/inputs/TextInput.js +99 -61
- package/dist/browser/inputs/TextInput.js.map +1 -1
- package/dist/browser/inputs/choice.js +19 -8
- package/dist/browser/inputs/choice.js.map +1 -1
- package/dist/browser/inputs/index.js +1 -0
- package/dist/browser/inputs/index.js.map +1 -1
- package/dist/browser/inputs/rich-select-messages.js +46 -0
- package/dist/browser/inputs/rich-select-messages.js.map +1 -0
- package/dist/browser/intl/shortcut-messages.js +4 -0
- package/dist/browser/intl/shortcut-messages.js.map +1 -1
- package/dist/browser/intl/shortcut.js +4 -0
- package/dist/browser/intl/shortcut.js.map +1 -1
- package/dist/browser/layout/AppWorkspace.js +624 -565
- package/dist/browser/layout/AppWorkspace.js.map +1 -1
- package/dist/browser/layout/DetailPanel.js +10 -1
- package/dist/browser/layout/DetailPanel.js.map +1 -1
- package/dist/browser/layout/MobileShell.js +213 -38
- package/dist/browser/layout/MobileShell.js.map +1 -1
- package/dist/browser/layout/Navigation.js +14 -5
- package/dist/browser/layout/Navigation.js.map +1 -1
- package/dist/browser/layout/PageTitle.js +9 -3
- package/dist/browser/layout/PageTitle.js.map +1 -1
- package/dist/browser/layout/ResizeSeparator.js +8 -2
- package/dist/browser/layout/ResizeSeparator.js.map +1 -1
- package/dist/browser/layout/app-workspace-controller.js +192 -31
- package/dist/browser/layout/app-workspace-controller.js.map +1 -1
- package/dist/browser/layout/index.js +1 -0
- package/dist/browser/layout/index.js.map +1 -1
- package/dist/browser/layout/navigation-model.js.map +1 -1
- package/dist/browser/layout/resize-separator.js +25 -1
- package/dist/browser/layout/resize-separator.js.map +1 -1
- package/dist/browser/layout/scroll-fade.js +32 -5
- package/dist/browser/layout/scroll-fade.js.map +1 -1
- package/dist/browser/surfaces/NoticeCard.js +46 -30
- package/dist/browser/surfaces/NoticeCard.js.map +1 -1
- package/dist/browser/surfaces/Skeleton.js +14 -0
- package/dist/browser/surfaces/Skeleton.js.map +1 -0
- package/dist/browser/surfaces/index.js +1 -0
- package/dist/browser/surfaces/index.js.map +1 -1
- package/dist/browser/surfaces/resource-messages.js +2 -2
- package/dist/browser/surfaces/resource-messages.js.map +1 -1
- package/dist/ssr/actions/Dropdown.js +51 -27
- package/dist/ssr/actions/Dropdown.js.map +1 -1
- package/dist/ssr/actions/FilterChip.js +67 -16
- package/dist/ssr/actions/FilterChip.js.map +1 -1
- package/dist/ssr/actions/ViewTabs.js +8 -0
- package/dist/ssr/actions/ViewTabs.js.map +1 -1
- package/dist/ssr/actions/filter-messages.js +26 -2
- package/dist/ssr/actions/filter-messages.js.map +1 -1
- package/dist/ssr/actions/menu-rows.js +23 -3
- package/dist/ssr/actions/menu-rows.js.map +1 -1
- package/dist/ssr/actions/menu-sheet.js +2 -7
- package/dist/ssr/actions/menu-sheet.js.map +1 -1
- package/dist/ssr/chat/ChatComposer.js +96 -67
- package/dist/ssr/chat/ChatComposer.js.map +1 -1
- package/dist/ssr/chat/chat-messages.js +14 -0
- package/dist/ssr/chat/chat-messages.js.map +1 -1
- package/dist/ssr/chat/index.js.map +1 -1
- package/dist/ssr/content/Calendar.js +40 -31
- package/dist/ssr/content/Calendar.js.map +1 -1
- package/dist/ssr/content/CalendarDayView.js +40 -48
- package/dist/ssr/content/CalendarDayView.js.map +1 -1
- package/dist/ssr/content/Chart.js +27 -7
- package/dist/ssr/content/Chart.js.map +1 -1
- package/dist/ssr/content/ChartExplorer.js +5 -3
- package/dist/ssr/content/ChartExplorer.js.map +1 -1
- package/dist/ssr/content/MapView.js +4 -4
- package/dist/ssr/content/MapView.js.map +1 -1
- package/dist/ssr/content/MessageRow.js +264 -91
- package/dist/ssr/content/MessageRow.js.map +1 -1
- package/dist/ssr/content/ReactionBar.js +17 -0
- package/dist/ssr/content/ReactionBar.js.map +1 -1
- package/dist/ssr/content/chart-inspection-core.js +4 -1
- package/dist/ssr/content/chart-inspection-core.js.map +1 -1
- package/dist/ssr/content/code-highlight.js +66 -0
- package/dist/ssr/content/code-highlight.js.map +1 -1
- package/dist/ssr/content/index.js +2 -1
- package/dist/ssr/content/index.js.map +1 -1
- package/dist/ssr/content/map-view-types.js.map +1 -1
- package/dist/ssr/feedback/dialog-core.js +6 -0
- package/dist/ssr/feedback/dialog-core.js.map +1 -1
- package/dist/ssr/inputs/AutocompleteEditor.js +64 -24
- package/dist/ssr/inputs/AutocompleteEditor.js.map +1 -1
- package/dist/ssr/inputs/RichSelect.js +950 -0
- package/dist/ssr/inputs/RichSelect.js.map +1 -0
- package/dist/ssr/inputs/TextInput.js +44 -17
- package/dist/ssr/inputs/TextInput.js.map +1 -1
- package/dist/ssr/inputs/choice.js +19 -8
- package/dist/ssr/inputs/choice.js.map +1 -1
- package/dist/ssr/inputs/index.js +1 -0
- package/dist/ssr/inputs/index.js.map +1 -1
- package/dist/ssr/inputs/rich-select-messages.js +46 -0
- package/dist/ssr/inputs/rich-select-messages.js.map +1 -0
- package/dist/ssr/intl/shortcut-messages.js +4 -0
- package/dist/ssr/intl/shortcut-messages.js.map +1 -1
- package/dist/ssr/intl/shortcut.js +4 -0
- package/dist/ssr/intl/shortcut.js.map +1 -1
- package/dist/ssr/layout/AppWorkspace.js +166 -125
- package/dist/ssr/layout/AppWorkspace.js.map +1 -1
- package/dist/ssr/layout/DetailPanel.js +1 -1
- package/dist/ssr/layout/DetailPanel.js.map +1 -1
- package/dist/ssr/layout/MobileShell.js +100 -20
- package/dist/ssr/layout/MobileShell.js.map +1 -1
- package/dist/ssr/layout/Navigation.js +1 -1
- package/dist/ssr/layout/Navigation.js.map +1 -1
- package/dist/ssr/layout/PageTitle.js +9 -3
- package/dist/ssr/layout/PageTitle.js.map +1 -1
- package/dist/ssr/layout/ResizeSeparator.js +4 -1
- package/dist/ssr/layout/ResizeSeparator.js.map +1 -1
- package/dist/ssr/layout/app-workspace-controller.js +192 -31
- package/dist/ssr/layout/app-workspace-controller.js.map +1 -1
- package/dist/ssr/layout/index.js +1 -0
- package/dist/ssr/layout/index.js.map +1 -1
- package/dist/ssr/layout/navigation-model.js.map +1 -1
- package/dist/ssr/layout/resize-separator.js +25 -1
- package/dist/ssr/layout/resize-separator.js.map +1 -1
- package/dist/ssr/layout/scroll-fade.js +32 -5
- package/dist/ssr/layout/scroll-fade.js.map +1 -1
- package/dist/ssr/surfaces/NoticeCard.js +21 -12
- package/dist/ssr/surfaces/NoticeCard.js.map +1 -1
- package/dist/ssr/surfaces/Skeleton.js +8 -0
- package/dist/ssr/surfaces/Skeleton.js.map +1 -0
- package/dist/ssr/surfaces/index.js +1 -0
- package/dist/ssr/surfaces/index.js.map +1 -1
- package/dist/ssr/surfaces/resource-messages.js +2 -2
- package/dist/ssr/surfaces/resource-messages.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/types/actions/Dropdown.d.ts +14 -0
- package/dist/types/actions/FilterChip.d.ts +11 -0
- package/dist/types/actions/filter-messages.d.ts +12 -0
- package/dist/types/actions/menu-rows.d.ts +7 -2
- package/dist/types/chat/ChatComposer.d.ts +13 -0
- package/dist/types/chat/chat-messages.d.ts +7 -0
- package/dist/types/chat/index.d.ts +1 -1
- package/dist/types/content/Calendar.d.ts +7 -0
- package/dist/types/content/Chart.d.ts +4 -2
- package/dist/types/content/ChartExplorer.d.ts +0 -1
- package/dist/types/content/MessageRow.d.ts +64 -2
- package/dist/types/content/code-highlight.d.ts +3 -1
- package/dist/types/content/index.d.ts +3 -2
- package/dist/types/content/map-view-live.d.ts +1 -1
- package/dist/types/content/map-view-types.d.ts +2 -0
- package/dist/types/feedback/dialog-core.d.ts +3 -0
- package/dist/types/inputs/AutocompleteEditor.d.ts +6 -1
- package/dist/types/inputs/RichSelect.d.ts +93 -0
- package/dist/types/inputs/TextInput.d.ts +5 -2
- package/dist/types/inputs/choice.d.ts +24 -4
- package/dist/types/inputs/index.d.ts +2 -0
- package/dist/types/inputs/rich-select-messages.d.ts +21 -0
- package/dist/types/intl/shortcut-messages.d.ts +2 -0
- package/dist/types/layout/AppWorkspace.d.ts +9 -0
- package/dist/types/layout/DetailPanel.d.ts +2 -0
- package/dist/types/layout/MobileShell.d.ts +52 -5
- package/dist/types/layout/app-workspace-controller.d.ts +2 -0
- package/dist/types/layout/index.d.ts +2 -1
- package/dist/types/layout/navigation-model.d.ts +2 -0
- package/dist/types/layout/resize-separator.d.ts +1 -0
- package/dist/types/layout/scroll-fade.d.ts +5 -0
- package/dist/types/surfaces/NoticeCard.d.ts +3 -0
- package/dist/types/surfaces/Skeleton.d.ts +6 -0
- package/dist/types/surfaces/index.d.ts +1 -0
- package/package.json +4 -4
|
@@ -438,7 +438,7 @@ const DetailPanelSection = props => {
|
|
|
438
438
|
}
|
|
439
439
|
});
|
|
440
440
|
};
|
|
441
|
-
const DetailPanel = props => _$ssr(_tmpl$9, _$ssrAttribute("class", _$escape(classNames("k2b-detail-panel", props.class), true), false), _$escape(props.children));
|
|
441
|
+
const DetailPanel = props => _$ssr(_tmpl$9, _$ssrAttribute("class", _$escape(classNames("k2b-detail-panel", props.class), true), false) + _$ssrAttribute("data-surface", _$escape(props.surface, true), false), _$escape(props.children));
|
|
442
442
|
DetailPanel.Header = DetailPanelHeader;
|
|
443
443
|
DetailPanel.Body = DetailPanelBody;
|
|
444
444
|
DetailPanel.Summary = DetailPanelSummary;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["layout/DetailPanel.tsx"],"sourcesContent":["import { children, createEffect, createSignal, createUniqueId, type JSX, Show, splitProps } from \"solid-js\";\nimport { Button, ButtonLink, type ButtonLinkProps, type ButtonProps, IconButton } from \"../actions/Button\";\nimport { Dropdown, type DropdownItem } from \"../actions/Dropdown\";\nimport { useDetailPanelMessages } from \"./detail-panel-messages\";\nimport { createScrollFade } from \"./scroll-fade\";\n\nexport type DetailPanelProps = {\n children: JSX.Element;\n class?: string;\n};\n\ntype DetailPanelHeaderBaseProps = {\n title: JSX.Element;\n subtitle?: JSX.Element;\n meta?: JSX.Element;\n actions?: JSX.Element;\n primaryActions?: JSX.Element;\n class?: string;\n};\n\nexport type DetailPanelHeaderProps = DetailPanelHeaderBaseProps &\n (\n | {\n leading?: JSX.Element;\n icon?: never;\n }\n | {\n leading?: never;\n icon?: string;\n }\n );\n\nexport type DetailPanelBodyProps = {\n scrollFade?: boolean;\n children: JSX.Element;\n scrollPreserveKey?: string;\n class?: string;\n};\n\nexport type DetailPanelSummaryProps = {\n title: JSX.Element;\n children: JSX.Element;\n actions?: JSX.Element;\n class?: string;\n};\n\nexport type DetailPanelGroupProps = {\n children: JSX.Element;\n label?: string;\n class?: string;\n};\n\nexport type DetailPanelTone = \"accent\" | \"neutral\" | \"success\" | \"warning\" | \"danger\";\n\ntype DetailPanelSectionBaseProps = {\n title: JSX.Element;\n icon?: string;\n tone?: DetailPanelTone;\n description?: JSX.Element;\n /** How many things the section lists, as a chip after the title; `0` reads \"None yet\". */\n count?: number;\n /** Short state after the title, such as \"2 of 4 done\". */\n meta?: JSX.Element;\n class?: string;\n};\n\n/** One direct secondary command, rendered as a sibling icon button at the end of the row. */\nexport type DetailPanelActionSecondary = {\n /** Icon class, for example `ti ti-trash`. */\n icon: string;\n /** Accessible name and tooltip of the icon button. */\n label: string;\n onClick: () => void;\n variant?: \"danger\";\n};\n\ntype DetailPanelActionBaseProps = {\n title: JSX.Element;\n description?: JSX.Element;\n leading?: JSX.Element;\n trailing?: JSX.Element;\n secondaryAction?: DetailPanelActionSecondary;\n /** Marks the row of the current place, such as the section in view, in the panel's accent. */\n current?: boolean;\n /** Lets the title wrap to two lines instead of ending with an ellipsis. */\n wrap?: boolean;\n class?: string;\n};\n\ntype DetailPanelActionMenuProps =\n | {\n menuItems?: never;\n menuLabel?: never;\n }\n | {\n menuItems: readonly DropdownItem[];\n menuLabel: string;\n };\n\nexport type DetailPanelActionLinkProps = DetailPanelActionBaseProps &\n DetailPanelActionMenuProps &\n Omit<ButtonLinkProps, \"children\" | \"class\" | \"size\" | \"title\" | \"variant\"> & {\n href: string;\n };\n\nexport type DetailPanelActionButtonProps = DetailPanelActionBaseProps &\n DetailPanelActionMenuProps &\n Omit<ButtonProps, \"children\" | \"class\" | \"size\" | \"title\" | \"variant\"> & {\n href?: never;\n };\n\nexport type DetailPanelActionProps = DetailPanelActionLinkProps | DetailPanelActionButtonProps;\n\nexport type DetailPanelSectionProps = DetailPanelSectionBaseProps &\n (\n | {\n children?: JSX.Element;\n actions?: JSX.Element;\n collapsible?: false;\n defaultOpen?: never;\n open?: never;\n onOpenChange?: never;\n disabled?: never;\n }\n | {\n children: JSX.Element;\n actions?: never;\n collapsible: true;\n defaultOpen?: boolean;\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n disabled?: boolean;\n }\n );\n\ntype DetailPanelComponent = ((props: DetailPanelProps) => JSX.Element) & {\n Header: (props: DetailPanelHeaderProps) => JSX.Element;\n Body: (props: DetailPanelBodyProps) => JSX.Element;\n Summary: (props: DetailPanelSummaryProps) => JSX.Element;\n Group: (props: DetailPanelGroupProps) => JSX.Element;\n Section: (props: DetailPanelSectionProps) => JSX.Element;\n Action: (props: DetailPanelActionProps) => JSX.Element;\n};\n\nconst classNames = (base: string, extra?: string): string => (extra ? `${base} ${extra}` : base);\n\nconst showTruncatedTitle = (event: PointerEvent & { currentTarget: HTMLHeadingElement }) => {\n const heading = event.currentTarget;\n if (heading.scrollHeight > heading.clientHeight + 1) heading.title = heading.textContent ?? \"\";\n else heading.removeAttribute(\"title\");\n};\n\nconst DetailPanelHeader = (props: DetailPanelHeaderProps): JSX.Element => (\n <header class={classNames(\"k2b-detail-panel__header\", props.class)}>\n <div class=\"k2b-detail-panel__header-main\" data-identity={props.icon || props.leading ? \"true\" : undefined}>\n <Show when={props.icon}>\n {(icon) => (\n <span class=\"k2b-detail-panel__header-icon\" aria-hidden=\"true\">\n <i class={icon()} />\n </span>\n )}\n </Show>\n <Show when={props.leading}>\n <div class=\"k2b-detail-panel__header-leading\">{props.leading}</div>\n </Show>\n <div class=\"k2b-detail-panel__heading\">\n {/* A long title wraps to two lines and ends with an ellipsis; then the native hint shows all of it. */}\n <h2 onPointerEnter={showTruncatedTitle}>{props.title}</h2>\n <Show when={props.subtitle || props.meta}>\n <div class=\"k2b-detail-panel__supporting\">\n <Show when={props.subtitle}>\n <p>{props.subtitle}</p>\n </Show>\n <Show when={props.meta}>\n <div class=\"k2b-detail-panel__meta\">{props.meta}</div>\n </Show>\n </div>\n </Show>\n </div>\n <Show when={props.actions}>\n <div class=\"k2b-detail-panel__actions\">{props.actions}</div>\n </Show>\n </div>\n <Show when={props.primaryActions}>\n <div class=\"k2b-detail-panel__primary-actions\">{props.primaryActions}</div>\n </Show>\n </header>\n);\n\nconst DetailPanelBody = (props: DetailPanelBodyProps): JSX.Element => {\n let body!: HTMLDivElement;\n createScrollFade(\n () => body,\n () => props.scrollFade !== false,\n );\n return (\n <div\n ref={body}\n class={classNames(\"k2b-detail-panel__body\", props.class)}\n data-scroll-fade-mode={props.scrollFade !== false ? \"both\" : undefined}\n data-scroll-preserve={props.scrollPreserveKey}\n >\n {props.children}\n </div>\n );\n};\n\nconst DetailPanelSummary = (props: DetailPanelSummaryProps): JSX.Element => {\n const headingId = `k2b-detail-panel-summary-${createUniqueId()}`;\n\n return (\n <section class={classNames(\"k2b-detail-panel__summary\", props.class)} aria-labelledby={headingId}>\n <header class=\"k2b-detail-panel__summary-header\">\n <h3 id={headingId}>{props.title}</h3>\n <Show when={props.actions}>\n <div class=\"k2b-detail-panel__summary-actions\">{props.actions}</div>\n </Show>\n </header>\n <div class=\"k2b-detail-panel__summary-body\">{props.children}</div>\n </section>\n );\n};\n\nconst DetailPanelGroup = (props: DetailPanelGroupProps): JSX.Element => (\n <div class={classNames(\"k2b-detail-panel__group\", props.class)} role=\"group\" aria-label={props.label}>\n {props.children}\n </div>\n);\n\nconst DetailPanelSectionIcon = (props: Pick<DetailPanelSectionBaseProps, \"icon\" | \"tone\">): JSX.Element => (\n <Show when={props.icon}>\n {(icon) => (\n <span class=\"k2b-detail-panel__section-icon\" data-tone={props.tone ?? \"neutral\"} aria-hidden=\"true\">\n <i class={icon()} />\n </span>\n )}\n </Show>\n);\n\n/** A count chip, or \"None yet\" for zero; shared by sections and discussions. */\nexport const DetailPanelCount = (props: { count: number }): JSX.Element => {\n const messages = useDetailPanelMessages();\n return (\n <Show when={props.count > 0} fallback={<span class=\"k2b-detail-panel__none\">{messages().noneYet}</span>}>\n <span class=\"k2b-count-chip\">{props.count}</span>\n </Show>\n );\n};\n\n/** Title, then its count and state right after it, so every section reads the same way. */\nconst SectionTitleMeta = (props: Pick<DetailPanelSectionBaseProps, \"count\" | \"meta\">): JSX.Element => (\n <>\n <Show when={props.count !== undefined}>\n <DetailPanelCount count={props.count ?? 0} />\n </Show>\n <Show when={props.meta}>\n <span class=\"k2b-detail-panel__section-meta\">{props.meta}</span>\n </Show>\n </>\n);\n\nconst DetailPanelActionContent = (props: DetailPanelActionBaseProps): JSX.Element => (\n <>\n {/* Always present, so every row's text starts on the section's text edge. */}\n <span class=\"k2b-detail-panel__action-leading\">{props.leading}</span>\n <span class=\"k2b-detail-panel__action-copy\">\n <span class=\"k2b-detail-panel__action-title\">{props.title}</span>\n <Show when={props.description}>\n <span class=\"k2b-detail-panel__action-description\">{props.description}</span>\n </Show>\n </span>\n <Show when={props.trailing}>\n <span class=\"k2b-detail-panel__action-trailing\">{props.trailing}</span>\n </Show>\n </>\n);\n\nconst DetailPanelAction = (props: DetailPanelActionProps): JSX.Element => {\n const [local, rest] = splitProps(props, [\n \"class\",\n \"current\",\n \"description\",\n \"href\",\n \"leading\",\n \"menuItems\",\n \"menuLabel\",\n \"secondaryAction\",\n \"title\",\n \"trailing\",\n \"wrap\",\n ]);\n const className = classNames(\"k2b-detail-panel__action\", local.class);\n const content = () => (\n <DetailPanelActionContent title={local.title} description={local.description} leading={local.leading} trailing={local.trailing} />\n );\n\n const action = () => (\n <Show\n when={local.href !== undefined}\n fallback={\n <Button\n {...(rest as Omit<DetailPanelActionButtonProps, keyof DetailPanelActionBaseProps>)}\n class={className}\n aria-current={local.current ? \"true\" : undefined}\n data-current={local.current ? \"true\" : undefined}\n data-wrap={local.wrap ? \"true\" : undefined}\n variant=\"ghost\"\n size=\"sm\"\n >\n {content()}\n </Button>\n }\n >\n <ButtonLink\n {...(rest as Omit<DetailPanelActionLinkProps, keyof DetailPanelActionBaseProps | \"href\">)}\n href={local.href as string}\n class={className}\n aria-current={local.current ? \"location\" : undefined}\n data-current={local.current ? \"true\" : undefined}\n data-wrap={local.wrap ? \"true\" : undefined}\n variant=\"ghost\"\n size=\"sm\"\n >\n {content()}\n </ButtonLink>\n </Show>\n );\n\n return (\n <Show when={local.secondaryAction || local.menuItems?.length} fallback={action()}>\n <div class=\"k2b-detail-panel__action-row\">\n {action()}\n <Show when={local.secondaryAction}>\n {(secondary) => (\n <IconButton\n size=\"sm\"\n variant=\"ghost\"\n label={secondary().label}\n class=\"k2b-detail-panel__action-secondary\"\n data-tone={secondary().variant}\n onClick={() => secondary().onClick()}\n >\n <i class={secondary().icon} aria-hidden=\"true\" />\n </IconButton>\n )}\n </Show>\n <Show when={local.menuItems?.length}>\n <Dropdown.Root items={local.menuItems ?? []} align=\"end\" label={local.menuLabel} class=\"k2b-detail-panel__action-menu\">\n <Dropdown.Trigger iconOnly size=\"sm\" variant=\"ghost\" label={local.menuLabel} class=\"k2b-detail-panel__action-menu-trigger\">\n <i class=\"ti ti-dots\" aria-hidden=\"true\" />\n </Dropdown.Trigger>\n </Dropdown.Root>\n </Show>\n </div>\n </Show>\n );\n};\n\nconst DetailPanelSection = (props: DetailPanelSectionProps): JSX.Element => {\n const headingId = `k2b-detail-panel-section-${createUniqueId()}`;\n const bodyId = `${headingId}-body`;\n const [internalOpen, setInternalOpen] = createSignal(props.defaultOpen ?? false);\n const open = () => props.open ?? internalOpen();\n let expand: HTMLButtonElement | undefined;\n let collapse: HTMLButtonElement | undefined;\n let body: HTMLDivElement | undefined;\n const toggle = (next: boolean) => {\n if (props.disabled) return;\n if (props.open === undefined) setInternalOpen(next);\n props.onOpenChange?.(next);\n };\n createEffect(() => {\n const expanded = open();\n // Restore focus only when its current control becomes hidden, including\n // a parent-controlled collapse while focus is inside an editor.\n queueMicrotask(() => {\n if (expanded !== open()) return;\n const active = expand?.ownerDocument.activeElement;\n if (expanded && active === expand) collapse?.focus();\n if (!expanded && (active === collapse || (active && body?.contains(active)))) expand?.focus();\n });\n });\n const className = () => classNames(\"k2b-detail-panel__section\", props.class);\n // Resolve once: reading `props.children` twice would instantiate the section body twice.\n const resolved = children(() => props.children);\n\n return (\n <Show\n when={props.collapsible}\n fallback={\n <section class={className()} aria-labelledby={headingId} data-icon={props.icon ? \"true\" : undefined}>\n <header class=\"k2b-detail-panel__section-header\">\n <DetailPanelSectionIcon icon={props.icon} tone={props.tone} />\n <div class=\"k2b-detail-panel__section-copy\">\n <div class=\"k2b-detail-panel__section-heading\">\n <h3 id={headingId}>{props.title}</h3>\n <SectionTitleMeta count={props.count} meta={props.meta} />\n </div>\n <Show when={props.description}>\n <p class=\"k2b-detail-panel__section-description\">{props.description}</p>\n </Show>\n </div>\n <Show when={props.actions}>\n <div class=\"k2b-detail-panel__section-actions\">{props.actions}</div>\n </Show>\n </header>\n <Show when={resolved()}>\n <div class=\"k2b-detail-panel__section-body\">{resolved()}</div>\n </Show>\n </section>\n }\n >\n <section\n class={className()}\n aria-labelledby={open() ? headingId : `${headingId}-closed`}\n data-open={open()}\n data-icon={props.icon ? \"true\" : undefined}\n >\n <div hidden={open()}>\n <Button\n ref={expand}\n variant=\"ghost\"\n class=\"k2b-detail-panel__section-summary\"\n disabled={props.disabled}\n aria-expanded={false}\n aria-controls={bodyId}\n onClick={() => toggle(true)}\n >\n <DetailPanelSectionIcon icon={props.icon} tone={props.tone} />\n <span class=\"k2b-detail-panel__section-copy\">\n <span class=\"k2b-detail-panel__section-heading\">\n <span id={`${headingId}-closed`} class=\"k2b-detail-panel__section-title\">\n {props.title}\n </span>\n <SectionTitleMeta count={props.count} meta={props.meta} />\n </span>\n <Show when={props.description}>\n <span class=\"k2b-detail-panel__section-description\">{props.description}</span>\n </Show>\n </span>\n {/* Same column as the open header's collapse button, so nothing moves between the states. */}\n <span class=\"k2b-detail-panel__section-toggle\" aria-hidden=\"true\">\n <i class=\"ti ti-chevron-down\" />\n </span>\n </Button>\n </div>\n <div hidden={!open()}>\n <header class=\"k2b-detail-panel__section-header\">\n <DetailPanelSectionIcon icon={props.icon} tone={props.tone} />\n <div class=\"k2b-detail-panel__section-copy\">\n <div class=\"k2b-detail-panel__section-heading\">\n <h3 id={headingId}>{props.title}</h3>\n <SectionTitleMeta count={props.count} meta={props.meta} />\n </div>\n <Show when={props.description}>\n <p class=\"k2b-detail-panel__section-description\">{props.description}</p>\n </Show>\n </div>\n <Button\n ref={collapse}\n variant=\"ghost\"\n size=\"sm\"\n class=\"k2b-detail-panel__section-toggle\"\n disabled={props.disabled}\n aria-labelledby={headingId}\n aria-expanded={true}\n aria-controls={bodyId}\n onClick={() => toggle(false)}\n >\n <i class=\"ti ti-chevron-up\" aria-hidden=\"true\" />\n </Button>\n </header>\n </div>\n <div ref={body} id={bodyId} hidden={!open()} class=\"k2b-detail-panel__section-body\">\n {props.children}\n </div>\n </section>\n </Show>\n );\n};\n\nconst DetailPanel = ((props: DetailPanelProps): JSX.Element => (\n <div class={classNames(\"k2b-detail-panel\", props.class)}>{props.children}</div>\n)) as DetailPanelComponent;\n\nDetailPanel.Header = DetailPanelHeader;\nDetailPanel.Body = DetailPanelBody;\nDetailPanel.Summary = DetailPanelSummary;\nDetailPanel.Group = DetailPanelGroup;\nDetailPanel.Section = DetailPanelSection;\nDetailPanel.Action = DetailPanelAction;\n\nexport default DetailPanel;\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":[],"sources":["layout/DetailPanel.tsx"],"sourcesContent":["import { children, createEffect, createSignal, createUniqueId, type JSX, Show, splitProps } from \"solid-js\";\nimport { Button, ButtonLink, type ButtonLinkProps, type ButtonProps, IconButton } from \"../actions/Button\";\nimport { Dropdown, type DropdownItem } from \"../actions/Dropdown\";\nimport { useDetailPanelMessages } from \"./detail-panel-messages\";\nimport { createScrollFade } from \"./scroll-fade\";\n\nexport type DetailPanelProps = {\n /** Plain sections share their host surface, as in AppWorkspace.Detail. */\n surface?: \"default\" | \"plain\";\n children: JSX.Element;\n class?: string;\n};\n\ntype DetailPanelHeaderBaseProps = {\n title: JSX.Element;\n subtitle?: JSX.Element;\n meta?: JSX.Element;\n actions?: JSX.Element;\n primaryActions?: JSX.Element;\n class?: string;\n};\n\nexport type DetailPanelHeaderProps = DetailPanelHeaderBaseProps &\n (\n | {\n leading?: JSX.Element;\n icon?: never;\n }\n | {\n leading?: never;\n icon?: string;\n }\n );\n\nexport type DetailPanelBodyProps = {\n scrollFade?: boolean;\n children: JSX.Element;\n scrollPreserveKey?: string;\n class?: string;\n};\n\nexport type DetailPanelSummaryProps = {\n title: JSX.Element;\n children: JSX.Element;\n actions?: JSX.Element;\n class?: string;\n};\n\nexport type DetailPanelGroupProps = {\n children: JSX.Element;\n label?: string;\n class?: string;\n};\n\nexport type DetailPanelTone = \"accent\" | \"neutral\" | \"success\" | \"warning\" | \"danger\";\n\ntype DetailPanelSectionBaseProps = {\n title: JSX.Element;\n icon?: string;\n tone?: DetailPanelTone;\n description?: JSX.Element;\n /** How many things the section lists, as a chip after the title; `0` reads \"None yet\". */\n count?: number;\n /** Short state after the title, such as \"2 of 4 done\". */\n meta?: JSX.Element;\n class?: string;\n};\n\n/** One direct secondary command, rendered as a sibling icon button at the end of the row. */\nexport type DetailPanelActionSecondary = {\n /** Icon class, for example `ti ti-trash`. */\n icon: string;\n /** Accessible name and tooltip of the icon button. */\n label: string;\n onClick: () => void;\n variant?: \"danger\";\n};\n\ntype DetailPanelActionBaseProps = {\n title: JSX.Element;\n description?: JSX.Element;\n leading?: JSX.Element;\n trailing?: JSX.Element;\n secondaryAction?: DetailPanelActionSecondary;\n /** Marks the row of the current place, such as the section in view, in the panel's accent. */\n current?: boolean;\n /** Lets the title wrap to two lines instead of ending with an ellipsis. */\n wrap?: boolean;\n class?: string;\n};\n\ntype DetailPanelActionMenuProps =\n | {\n menuItems?: never;\n menuLabel?: never;\n }\n | {\n menuItems: readonly DropdownItem[];\n menuLabel: string;\n };\n\nexport type DetailPanelActionLinkProps = DetailPanelActionBaseProps &\n DetailPanelActionMenuProps &\n Omit<ButtonLinkProps, \"children\" | \"class\" | \"size\" | \"title\" | \"variant\"> & {\n href: string;\n };\n\nexport type DetailPanelActionButtonProps = DetailPanelActionBaseProps &\n DetailPanelActionMenuProps &\n Omit<ButtonProps, \"children\" | \"class\" | \"size\" | \"title\" | \"variant\"> & {\n href?: never;\n };\n\nexport type DetailPanelActionProps = DetailPanelActionLinkProps | DetailPanelActionButtonProps;\n\nexport type DetailPanelSectionProps = DetailPanelSectionBaseProps &\n (\n | {\n children?: JSX.Element;\n actions?: JSX.Element;\n collapsible?: false;\n defaultOpen?: never;\n open?: never;\n onOpenChange?: never;\n disabled?: never;\n }\n | {\n children: JSX.Element;\n actions?: never;\n collapsible: true;\n defaultOpen?: boolean;\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n disabled?: boolean;\n }\n );\n\ntype DetailPanelComponent = ((props: DetailPanelProps) => JSX.Element) & {\n Header: (props: DetailPanelHeaderProps) => JSX.Element;\n Body: (props: DetailPanelBodyProps) => JSX.Element;\n Summary: (props: DetailPanelSummaryProps) => JSX.Element;\n Group: (props: DetailPanelGroupProps) => JSX.Element;\n Section: (props: DetailPanelSectionProps) => JSX.Element;\n Action: (props: DetailPanelActionProps) => JSX.Element;\n};\n\nconst classNames = (base: string, extra?: string): string => (extra ? `${base} ${extra}` : base);\n\nconst showTruncatedTitle = (event: PointerEvent & { currentTarget: HTMLHeadingElement }) => {\n const heading = event.currentTarget;\n if (heading.scrollHeight > heading.clientHeight + 1) heading.title = heading.textContent ?? \"\";\n else heading.removeAttribute(\"title\");\n};\n\nconst DetailPanelHeader = (props: DetailPanelHeaderProps): JSX.Element => (\n <header class={classNames(\"k2b-detail-panel__header\", props.class)}>\n <div class=\"k2b-detail-panel__header-main\" data-identity={props.icon || props.leading ? \"true\" : undefined}>\n <Show when={props.icon}>\n {(icon) => (\n <span class=\"k2b-detail-panel__header-icon\" aria-hidden=\"true\">\n <i class={icon()} />\n </span>\n )}\n </Show>\n <Show when={props.leading}>\n <div class=\"k2b-detail-panel__header-leading\">{props.leading}</div>\n </Show>\n <div class=\"k2b-detail-panel__heading\">\n {/* A long title wraps to two lines and ends with an ellipsis; then the native hint shows all of it. */}\n <h2 onPointerEnter={showTruncatedTitle}>{props.title}</h2>\n <Show when={props.subtitle || props.meta}>\n <div class=\"k2b-detail-panel__supporting\">\n <Show when={props.subtitle}>\n <p>{props.subtitle}</p>\n </Show>\n <Show when={props.meta}>\n <div class=\"k2b-detail-panel__meta\">{props.meta}</div>\n </Show>\n </div>\n </Show>\n </div>\n <Show when={props.actions}>\n <div class=\"k2b-detail-panel__actions\">{props.actions}</div>\n </Show>\n </div>\n <Show when={props.primaryActions}>\n <div class=\"k2b-detail-panel__primary-actions\">{props.primaryActions}</div>\n </Show>\n </header>\n);\n\nconst DetailPanelBody = (props: DetailPanelBodyProps): JSX.Element => {\n let body!: HTMLDivElement;\n createScrollFade(\n () => body,\n () => props.scrollFade !== false,\n );\n return (\n <div\n ref={body}\n class={classNames(\"k2b-detail-panel__body\", props.class)}\n data-scroll-fade-mode={props.scrollFade !== false ? \"both\" : undefined}\n data-scroll-preserve={props.scrollPreserveKey}\n >\n {props.children}\n </div>\n );\n};\n\nconst DetailPanelSummary = (props: DetailPanelSummaryProps): JSX.Element => {\n const headingId = `k2b-detail-panel-summary-${createUniqueId()}`;\n\n return (\n <section class={classNames(\"k2b-detail-panel__summary\", props.class)} aria-labelledby={headingId}>\n <header class=\"k2b-detail-panel__summary-header\">\n <h3 id={headingId}>{props.title}</h3>\n <Show when={props.actions}>\n <div class=\"k2b-detail-panel__summary-actions\">{props.actions}</div>\n </Show>\n </header>\n <div class=\"k2b-detail-panel__summary-body\">{props.children}</div>\n </section>\n );\n};\n\nconst DetailPanelGroup = (props: DetailPanelGroupProps): JSX.Element => (\n <div class={classNames(\"k2b-detail-panel__group\", props.class)} role=\"group\" aria-label={props.label}>\n {props.children}\n </div>\n);\n\nconst DetailPanelSectionIcon = (props: Pick<DetailPanelSectionBaseProps, \"icon\" | \"tone\">): JSX.Element => (\n <Show when={props.icon}>\n {(icon) => (\n <span class=\"k2b-detail-panel__section-icon\" data-tone={props.tone ?? \"neutral\"} aria-hidden=\"true\">\n <i class={icon()} />\n </span>\n )}\n </Show>\n);\n\n/** A count chip, or \"None yet\" for zero; shared by sections and discussions. */\nexport const DetailPanelCount = (props: { count: number }): JSX.Element => {\n const messages = useDetailPanelMessages();\n return (\n <Show when={props.count > 0} fallback={<span class=\"k2b-detail-panel__none\">{messages().noneYet}</span>}>\n <span class=\"k2b-count-chip\">{props.count}</span>\n </Show>\n );\n};\n\n/** Title, then its count and state right after it, so every section reads the same way. */\nconst SectionTitleMeta = (props: Pick<DetailPanelSectionBaseProps, \"count\" | \"meta\">): JSX.Element => (\n <>\n <Show when={props.count !== undefined}>\n <DetailPanelCount count={props.count ?? 0} />\n </Show>\n <Show when={props.meta}>\n <span class=\"k2b-detail-panel__section-meta\">{props.meta}</span>\n </Show>\n </>\n);\n\nconst DetailPanelActionContent = (props: DetailPanelActionBaseProps): JSX.Element => (\n <>\n {/* Always present, so every row's text starts on the section's text edge. */}\n <span class=\"k2b-detail-panel__action-leading\">{props.leading}</span>\n <span class=\"k2b-detail-panel__action-copy\">\n <span class=\"k2b-detail-panel__action-title\">{props.title}</span>\n <Show when={props.description}>\n <span class=\"k2b-detail-panel__action-description\">{props.description}</span>\n </Show>\n </span>\n <Show when={props.trailing}>\n <span class=\"k2b-detail-panel__action-trailing\">{props.trailing}</span>\n </Show>\n </>\n);\n\nconst DetailPanelAction = (props: DetailPanelActionProps): JSX.Element => {\n const [local, rest] = splitProps(props, [\n \"class\",\n \"current\",\n \"description\",\n \"href\",\n \"leading\",\n \"menuItems\",\n \"menuLabel\",\n \"secondaryAction\",\n \"title\",\n \"trailing\",\n \"wrap\",\n ]);\n const className = classNames(\"k2b-detail-panel__action\", local.class);\n const content = () => (\n <DetailPanelActionContent title={local.title} description={local.description} leading={local.leading} trailing={local.trailing} />\n );\n\n const action = () => (\n <Show\n when={local.href !== undefined}\n fallback={\n <Button\n {...(rest as Omit<DetailPanelActionButtonProps, keyof DetailPanelActionBaseProps>)}\n class={className}\n aria-current={local.current ? \"true\" : undefined}\n data-current={local.current ? \"true\" : undefined}\n data-wrap={local.wrap ? \"true\" : undefined}\n variant=\"ghost\"\n size=\"sm\"\n >\n {content()}\n </Button>\n }\n >\n <ButtonLink\n {...(rest as Omit<DetailPanelActionLinkProps, keyof DetailPanelActionBaseProps | \"href\">)}\n href={local.href as string}\n class={className}\n aria-current={local.current ? \"location\" : undefined}\n data-current={local.current ? \"true\" : undefined}\n data-wrap={local.wrap ? \"true\" : undefined}\n variant=\"ghost\"\n size=\"sm\"\n >\n {content()}\n </ButtonLink>\n </Show>\n );\n\n return (\n <Show when={local.secondaryAction || local.menuItems?.length} fallback={action()}>\n <div class=\"k2b-detail-panel__action-row\">\n {action()}\n <Show when={local.secondaryAction}>\n {(secondary) => (\n <IconButton\n size=\"sm\"\n variant=\"ghost\"\n label={secondary().label}\n class=\"k2b-detail-panel__action-secondary\"\n data-tone={secondary().variant}\n onClick={() => secondary().onClick()}\n >\n <i class={secondary().icon} aria-hidden=\"true\" />\n </IconButton>\n )}\n </Show>\n <Show when={local.menuItems?.length}>\n <Dropdown.Root items={local.menuItems ?? []} align=\"end\" label={local.menuLabel} class=\"k2b-detail-panel__action-menu\">\n <Dropdown.Trigger iconOnly size=\"sm\" variant=\"ghost\" label={local.menuLabel} class=\"k2b-detail-panel__action-menu-trigger\">\n <i class=\"ti ti-dots\" aria-hidden=\"true\" />\n </Dropdown.Trigger>\n </Dropdown.Root>\n </Show>\n </div>\n </Show>\n );\n};\n\nconst DetailPanelSection = (props: DetailPanelSectionProps): JSX.Element => {\n const headingId = `k2b-detail-panel-section-${createUniqueId()}`;\n const bodyId = `${headingId}-body`;\n const [internalOpen, setInternalOpen] = createSignal(props.defaultOpen ?? false);\n const open = () => props.open ?? internalOpen();\n let expand: HTMLButtonElement | undefined;\n let collapse: HTMLButtonElement | undefined;\n let body: HTMLDivElement | undefined;\n const toggle = (next: boolean) => {\n if (props.disabled) return;\n if (props.open === undefined) setInternalOpen(next);\n props.onOpenChange?.(next);\n };\n createEffect(() => {\n const expanded = open();\n // Restore focus only when its current control becomes hidden, including\n // a parent-controlled collapse while focus is inside an editor.\n queueMicrotask(() => {\n if (expanded !== open()) return;\n const active = expand?.ownerDocument.activeElement;\n if (expanded && active === expand) collapse?.focus();\n if (!expanded && (active === collapse || (active && body?.contains(active)))) expand?.focus();\n });\n });\n const className = () => classNames(\"k2b-detail-panel__section\", props.class);\n // Resolve once: reading `props.children` twice would instantiate the section body twice.\n const resolved = children(() => props.children);\n\n return (\n <Show\n when={props.collapsible}\n fallback={\n <section class={className()} aria-labelledby={headingId} data-icon={props.icon ? \"true\" : undefined}>\n <header class=\"k2b-detail-panel__section-header\">\n <DetailPanelSectionIcon icon={props.icon} tone={props.tone} />\n <div class=\"k2b-detail-panel__section-copy\">\n <div class=\"k2b-detail-panel__section-heading\">\n <h3 id={headingId}>{props.title}</h3>\n <SectionTitleMeta count={props.count} meta={props.meta} />\n </div>\n <Show when={props.description}>\n <p class=\"k2b-detail-panel__section-description\">{props.description}</p>\n </Show>\n </div>\n <Show when={props.actions}>\n <div class=\"k2b-detail-panel__section-actions\">{props.actions}</div>\n </Show>\n </header>\n <Show when={resolved()}>\n <div class=\"k2b-detail-panel__section-body\">{resolved()}</div>\n </Show>\n </section>\n }\n >\n <section\n class={className()}\n aria-labelledby={open() ? headingId : `${headingId}-closed`}\n data-open={open()}\n data-icon={props.icon ? \"true\" : undefined}\n >\n <div hidden={open()}>\n <Button\n ref={expand}\n variant=\"ghost\"\n class=\"k2b-detail-panel__section-summary\"\n disabled={props.disabled}\n aria-expanded={false}\n aria-controls={bodyId}\n onClick={() => toggle(true)}\n >\n <DetailPanelSectionIcon icon={props.icon} tone={props.tone} />\n <span class=\"k2b-detail-panel__section-copy\">\n <span class=\"k2b-detail-panel__section-heading\">\n <span id={`${headingId}-closed`} class=\"k2b-detail-panel__section-title\">\n {props.title}\n </span>\n <SectionTitleMeta count={props.count} meta={props.meta} />\n </span>\n <Show when={props.description}>\n <span class=\"k2b-detail-panel__section-description\">{props.description}</span>\n </Show>\n </span>\n {/* Same column as the open header's collapse button, so nothing moves between the states. */}\n <span class=\"k2b-detail-panel__section-toggle\" aria-hidden=\"true\">\n <i class=\"ti ti-chevron-down\" />\n </span>\n </Button>\n </div>\n <div hidden={!open()}>\n <header class=\"k2b-detail-panel__section-header\">\n <DetailPanelSectionIcon icon={props.icon} tone={props.tone} />\n <div class=\"k2b-detail-panel__section-copy\">\n <div class=\"k2b-detail-panel__section-heading\">\n <h3 id={headingId}>{props.title}</h3>\n <SectionTitleMeta count={props.count} meta={props.meta} />\n </div>\n <Show when={props.description}>\n <p class=\"k2b-detail-panel__section-description\">{props.description}</p>\n </Show>\n </div>\n <Button\n ref={collapse}\n variant=\"ghost\"\n size=\"sm\"\n class=\"k2b-detail-panel__section-toggle\"\n disabled={props.disabled}\n aria-labelledby={headingId}\n aria-expanded={true}\n aria-controls={bodyId}\n onClick={() => toggle(false)}\n >\n <i class=\"ti ti-chevron-up\" aria-hidden=\"true\" />\n </Button>\n </header>\n </div>\n <div ref={body} id={bodyId} hidden={!open()} class=\"k2b-detail-panel__section-body\">\n {props.children}\n </div>\n </section>\n </Show>\n );\n};\n\nconst DetailPanel = ((props: DetailPanelProps): JSX.Element => (\n <div class={classNames(\"k2b-detail-panel\", props.class)} data-surface={props.surface}>\n {props.children}\n </div>\n)) as DetailPanelComponent;\n\nDetailPanel.Header = DetailPanelHeader;\nDetailPanel.Body = DetailPanelBody;\nDetailPanel.Summary = DetailPanelSummary;\nDetailPanel.Group = DetailPanelGroup;\nDetailPanel.Section = DetailPanelSection;\nDetailPanel.Action = DetailPanelAction;\n\nexport default DetailPanel;\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1,12 +1,23 @@
|
|
|
1
|
+
import { memo as _$memo } from "solid-js/web";
|
|
1
2
|
import { ssr as _$ssr } from "solid-js/web";
|
|
2
3
|
import { createComponent as _$createComponent } from "solid-js/web";
|
|
3
4
|
import { ssrAttribute as _$ssrAttribute } from "solid-js/web";
|
|
4
5
|
import { escape as _$escape } from "solid-js/web";
|
|
5
|
-
var _tmpl$ = ["<div", ">", "<main class=\"k2b-mobile-shell__main\">", "</main>", "</div>"],
|
|
6
|
-
_tmpl$2 = ["<
|
|
7
|
-
_tmpl$3 = ["<
|
|
8
|
-
_tmpl$4 = "<
|
|
9
|
-
|
|
6
|
+
var _tmpl$ = ["<div", ">", "", "<main class=\"k2b-mobile-shell__main\">", "</main>", "</div>"],
|
|
7
|
+
_tmpl$2 = ["<span class=\"k2b-mobile-shell__title-narrow\">", "</span>"],
|
|
8
|
+
_tmpl$3 = ["<span class=\"k2b-mobile-shell__title-wide\">", "</span>"],
|
|
9
|
+
_tmpl$4 = ["<div class=\"k2b-mobile-shell__actions\">", "</div>"],
|
|
10
|
+
_tmpl$5 = ["<header class=\"k2b-mobile-shell__header\">", "<h1 class=\"k2b-mobile-shell__title\">", "</h1>", "</header>"],
|
|
11
|
+
_tmpl$6 = "<i class=\"ti ti-chevron-left\" aria-hidden=\"true\"></i>",
|
|
12
|
+
_tmpl$7 = ["<a", "><i", " aria-hidden=\"true\"></i><span class=\"k2b-truncate-fade\">", "</span>", "</a>"],
|
|
13
|
+
_tmpl$8 = ["<span class=\"k2b-mobile-shell__sidebar-count\">", "</span>"],
|
|
14
|
+
_tmpl$9 = ["<ul>", "</ul>"],
|
|
15
|
+
_tmpl$0 = ["<li>", "</li>"],
|
|
16
|
+
_tmpl$1 = ["<div class=\"k2b-mobile-shell__sidebar-foot\">", "</div>"],
|
|
17
|
+
_tmpl$10 = ["<nav class=\"k2b-mobile-shell__sidebar\"", "><div class=\"k2b-mobile-shell__sidebar-head\">", "<span class=\"k2b-truncate-fade\">", "</span></div><div class=\"k2b-mobile-shell__sidebar-body\">", "", "</div>", "</nav>"],
|
|
18
|
+
_tmpl$11 = ["<img", " alt width=\"32\" height=\"32\">"],
|
|
19
|
+
_tmpl$12 = ["<section><h2>", "</h2>", "</section>"];
|
|
20
|
+
import { For, onCleanup, onMount, Show } from "solid-js";
|
|
10
21
|
import { IconButton, IconButtonLink } from "../actions/Button";
|
|
11
22
|
import ScrollArea from "./ScrollArea";
|
|
12
23
|
import { installScrollFades } from "./scroll-fade";
|
|
@@ -147,15 +158,16 @@ const observeLinkTaps = root => {
|
|
|
147
158
|
export function observeMobileShell(root) {
|
|
148
159
|
const main = root.querySelector(":scope > .k2b-mobile-shell__main");
|
|
149
160
|
const body = main?.querySelector(":scope > .k2b-mobile-shell__body");
|
|
150
|
-
if (!main
|
|
161
|
+
if (!main) return () => {};
|
|
151
162
|
const stopLinkTaps = observeLinkTaps(root);
|
|
152
|
-
|
|
163
|
+
// Content with its own scroll areas keeps its own fades; the room a toast takes applies to the whole main area.
|
|
164
|
+
const stopScrollFades = body ? installScrollFades(body) : () => {};
|
|
153
165
|
let frame = 0;
|
|
154
166
|
const measure = () => {
|
|
155
167
|
frame = 0;
|
|
156
168
|
const footer = Math.max(0, root.getBoundingClientRect().bottom - main.getBoundingClientRect().bottom);
|
|
157
169
|
document.body.style.setProperty(FOOTER_HEIGHT, `${footer}px`);
|
|
158
|
-
root.style.setProperty(TOAST_INSET, `${persistentToastInset(body)}px`);
|
|
170
|
+
root.style.setProperty(TOAST_INSET, `${persistentToastInset(body ?? main)}px`);
|
|
159
171
|
};
|
|
160
172
|
const schedule = () => {
|
|
161
173
|
if (!frame) frame = requestAnimationFrame(measure);
|
|
@@ -187,15 +199,25 @@ export function observeMobileShell(root) {
|
|
|
187
199
|
function MobileShellRoot(props) {
|
|
188
200
|
let root;
|
|
189
201
|
onMount(() => onCleanup(observeMobileShell(root)));
|
|
190
|
-
return _$ssr(_tmpl$, _$ssrAttribute("class", props.class ? `k2b-mobile-shell ${_$escape(props.class, true)}` : "k2b-mobile-shell", false), _$escape(props.header), _$escape(_$createComponent(
|
|
191
|
-
|
|
192
|
-
|
|
202
|
+
return _$ssr(_tmpl$, _$ssrAttribute("class", props.class ? `k2b-mobile-shell ${_$escape(props.class, true)}` : "k2b-mobile-shell", false) + _$ssrAttribute("data-k2b-content-heads", props.scroll === false ? "" : _$escape(undefined, true), false), _$escape(props.sidebar), _$escape(props.header), _$escape(_$createComponent(Show, {
|
|
203
|
+
get when() {
|
|
204
|
+
return props.scroll !== false;
|
|
205
|
+
},
|
|
206
|
+
get fallback() {
|
|
193
207
|
return props.children;
|
|
208
|
+
},
|
|
209
|
+
get children() {
|
|
210
|
+
return _$createComponent(ScrollArea, {
|
|
211
|
+
"class": "k2b-mobile-shell__body",
|
|
212
|
+
get children() {
|
|
213
|
+
return props.children;
|
|
214
|
+
}
|
|
215
|
+
});
|
|
194
216
|
}
|
|
195
217
|
})), _$escape(props.footer));
|
|
196
218
|
}
|
|
197
219
|
function MobileShellHeader(props) {
|
|
198
|
-
return _$ssr(_tmpl$
|
|
220
|
+
return _$ssr(_tmpl$5, _$escape(_$createComponent(Show, {
|
|
199
221
|
get when() {
|
|
200
222
|
return props.back;
|
|
201
223
|
},
|
|
@@ -206,18 +228,24 @@ function MobileShellHeader(props) {
|
|
|
206
228
|
get fallback() {
|
|
207
229
|
return _$createComponent(IconButton, {
|
|
208
230
|
"class": "k2b-mobile-shell__back",
|
|
231
|
+
get ["data-with-sidebar"]() {
|
|
232
|
+
return back().withSidebar === false ? "false" : undefined;
|
|
233
|
+
},
|
|
209
234
|
get label() {
|
|
210
235
|
return back().label;
|
|
211
236
|
},
|
|
212
237
|
tooltip: false,
|
|
213
238
|
onClick: () => back().onClick?.(),
|
|
214
239
|
get children() {
|
|
215
|
-
return _$ssr(_tmpl$
|
|
240
|
+
return _$ssr(_tmpl$6);
|
|
216
241
|
}
|
|
217
242
|
});
|
|
218
243
|
},
|
|
219
244
|
children: href => _$createComponent(IconButtonLink, {
|
|
220
245
|
"class": "k2b-mobile-shell__back",
|
|
246
|
+
get ["data-with-sidebar"]() {
|
|
247
|
+
return back().withSidebar === false ? "false" : undefined;
|
|
248
|
+
},
|
|
221
249
|
get href() {
|
|
222
250
|
return href();
|
|
223
251
|
},
|
|
@@ -227,27 +255,79 @@ function MobileShellHeader(props) {
|
|
|
227
255
|
tooltip: false,
|
|
228
256
|
onClick: () => back().onClick?.(),
|
|
229
257
|
get children() {
|
|
230
|
-
return _$ssr(_tmpl$
|
|
258
|
+
return _$ssr(_tmpl$6);
|
|
231
259
|
}
|
|
232
260
|
})
|
|
233
261
|
})
|
|
234
|
-
})), _$escape(
|
|
262
|
+
})), _$escape(_$createComponent(Show, {
|
|
263
|
+
get when() {
|
|
264
|
+
return _$memo(() => props.sidebarTitle !== undefined)() && props.sidebarTitle !== props.title;
|
|
265
|
+
},
|
|
266
|
+
get fallback() {
|
|
267
|
+
return props.title;
|
|
268
|
+
},
|
|
269
|
+
get children() {
|
|
270
|
+
return [_$ssr(_tmpl$2, _$escape(props.title)), _$ssr(_tmpl$3, _$escape(props.sidebarTitle))];
|
|
271
|
+
}
|
|
272
|
+
})), _$escape(_$createComponent(Show, {
|
|
235
273
|
get when() {
|
|
236
274
|
return props.actions;
|
|
237
275
|
},
|
|
238
276
|
get children() {
|
|
239
|
-
return _$ssr(_tmpl$
|
|
277
|
+
return _$ssr(_tmpl$4, _$escape(props.actions));
|
|
278
|
+
}
|
|
279
|
+
})));
|
|
280
|
+
}
|
|
281
|
+
function SidebarLink(props) {
|
|
282
|
+
return _$ssr(_tmpl$7, _$ssrAttribute("href", _$escape(props.item.href, true), false) + _$ssrAttribute("aria-current", props.item.current ? "page" : _$escape(undefined, true), false) + _$ssrAttribute("data-tab", _$escape(props.item.id, true), false) + _$ssrAttribute("data-k2b-title", _$escape(props.item.title ?? props.item.label, true), false), _$ssrAttribute("class", _$escape(props.item.icon, true), false), _$escape(props.item.label), _$escape(_$createComponent(Show, {
|
|
283
|
+
get when() {
|
|
284
|
+
return props.item.count;
|
|
285
|
+
},
|
|
286
|
+
children: count => _$ssr(_tmpl$8, _$escape(count()))
|
|
287
|
+
})));
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* The navigation of a touch app on a wide screen, in `MobileShell`'s `sidebar`: the app's name, then its destinations
|
|
292
|
+
* as 44 px rows with icon and label, the open one in the action colour. A press shows the item's page frame at once,
|
|
293
|
+
* as on a tab, and the row of a loading page pulses.
|
|
294
|
+
*/
|
|
295
|
+
function MobileShellSidebar(props) {
|
|
296
|
+
const list = items => _$ssr(_tmpl$9, _$escape(_$createComponent(For, {
|
|
297
|
+
each: items,
|
|
298
|
+
children: item => _$ssr(_tmpl$0, _$escape(_$createComponent(SidebarLink, {
|
|
299
|
+
item: item
|
|
300
|
+
})))
|
|
301
|
+
})));
|
|
302
|
+
return _$ssr(_tmpl$10, _$ssrAttribute("aria-label", _$escape(props.label, true), false), _$escape(_$createComponent(Show, {
|
|
303
|
+
get when() {
|
|
304
|
+
return props.logo;
|
|
305
|
+
},
|
|
306
|
+
children: logo => _$ssr(_tmpl$11, _$ssrAttribute("src", _$escape(logo(), true), false))
|
|
307
|
+
})), _$escape(props.title), _$escape(list(props.items)), _$escape(_$createComponent(For, {
|
|
308
|
+
get each() {
|
|
309
|
+
return (props.sections ?? []).filter(section => section.items.length > 0);
|
|
310
|
+
},
|
|
311
|
+
children: section => _$ssr(_tmpl$12, _$escape(section.title), _$escape(list(section.items)))
|
|
312
|
+
})), _$escape(_$createComponent(Show, {
|
|
313
|
+
get when() {
|
|
314
|
+
return props.footer?.length;
|
|
315
|
+
},
|
|
316
|
+
get children() {
|
|
317
|
+
return _$ssr(_tmpl$1, _$escape(list(props.footer ?? [])));
|
|
240
318
|
}
|
|
241
319
|
})));
|
|
242
320
|
}
|
|
243
321
|
|
|
244
322
|
/**
|
|
245
|
-
* The full-screen frame of a phone app: a header, one scroll area, and an optional footer such as a `TabBar`.
|
|
246
|
-
*
|
|
247
|
-
*
|
|
323
|
+
* The full-screen frame of a phone app: a header, one scroll area, and an optional footer such as a `TabBar`. With a
|
|
324
|
+
* `sidebar`, a window of 48rem and wider shows the sidebar at the start edge instead of the footer, and the toast rail
|
|
325
|
+
* stays in the area beside it. While it is mounted, the document itself never scrolls, pinch zoom and rubber-banding
|
|
326
|
+
* are off, and the toast rail sits above the footer. Mount one per page, as the page's layout.
|
|
248
327
|
*/
|
|
249
328
|
export const MobileShell = Object.assign(MobileShellRoot, {
|
|
250
|
-
Header: MobileShellHeader
|
|
329
|
+
Header: MobileShellHeader,
|
|
330
|
+
Sidebar: MobileShellSidebar
|
|
251
331
|
});
|
|
252
332
|
export default MobileShell;
|
|
253
333
|
//# sourceMappingURL=MobileShell.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["layout/MobileShell.tsx"],"sourcesContent":["import { type JSX, onCleanup, onMount, Show } from \"solid-js\";\nimport { IconButton, IconButtonLink } from \"../actions/Button\";\nimport ScrollArea from \"./ScrollArea\";\nimport { installScrollFades } from \"./scroll-fade\";\n\nexport type MobileShellProps = {\n /** Usually `MobileShell.Header`; it sits above the scroll area and pads the top safe area. */\n header: JSX.Element;\n /** Usually a `TabBar`; it sits below the scroll area and pads the bottom safe area itself. */\n footer?: JSX.Element;\n /** The page content, inside the shell's only scroll area. */\n children: JSX.Element;\n class?: string;\n};\n\nexport type MobileShellHeaderProps = {\n title: string;\n /** A Back control before the title: a link with `href`, otherwise a button. */\n back?: { href?: string; onClick?: () => void; label: string };\n /** Controls after the title, such as a menu. */\n actions?: JSX.Element;\n};\n\n/** Read by the toast rail, which is portalled outside the shell, so it lives on the body. */\nconst FOOTER_HEIGHT = \"--k2b-mobile-shell-footer-height\";\n/** How much of the scroll area a persistent toast covers; local to the shell. */\nconst TOAST_INSET = \"--k2b-mobile-shell-toast-inset\";\n\n/**\n * The visible part of the toast rail when it holds a toast without a timer (`duration: 0`, running progress, or a\n * custom slot), so the last row of the scroll area can still scroll above it. A rail that sits elsewhere, such as\n * above a dialog, covers nothing.\n */\nconst persistentToastInset = (body: HTMLElement): number => {\n if (document.querySelector(\"dialog:modal\")) return 0;\n const cards = [...document.querySelectorAll<HTMLElement>(\"[data-k2b-toast-container] [data-k2b-toast]:not([data-closing])\")];\n if (!cards.some((card) => card.dataset.persistent === \"true\")) return 0;\n const area = body.getBoundingClientRect();\n const top = Math.min(...cards.map((card) => card.getBoundingClientRect().top));\n return Math.max(0, Math.min(area.height, area.bottom - top));\n};\n\n/** Marks the link whose page is loading; the tab bar shows it as selected. */\nconst PENDING = \"data-k2b-pending\";\n/** On a link: the title of the page it opens. Such a link switches the shell to that page's frame at the first touch. */\nconst PAGE_TITLE = \"data-k2b-title\";\n/** On the root while the shell shows the frame of the page that is loading. */\nconst SWITCHING = \"data-k2b-switching\";\n/** On the header title while the shell switches: the loading page's title, which the title shows instead. */\nconst NEXT_TITLE = \"data-k2b-next-title\";\n\n/** The link a click or press follows as a page load of this origin, or null when it does something else. */\nconst pageLink = (root: HTMLElement, event: MouseEvent): HTMLAnchorElement | null => {\n if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return null;\n const link = event.target instanceof Element ? event.target.closest<HTMLAnchorElement>(\"a[href]\") : null;\n if (!link || !root.contains(link) || link.hasAttribute(\"download\") || (link.target && link.target !== \"_self\")) return null;\n const url = new URL(link.href);\n if (url.origin !== location.origin) return null;\n // A jump inside the page loads nothing.\n if (url.hash && url.pathname === location.pathname && url.search === location.search) return null;\n return link;\n};\n\n/**\n * Taps on the shell's links. iOS shows `:active` only while the page listens to touches, so a tap gets its pressed\n * state at once. A link's page keeps loading while the old page stays visible; a second tap on it would cancel that\n * load and start it over, so it is ignored. A link that names its page's title, such as a tab, shows that page's\n * frame at the first touch instead of at the end of the tap: its title and an empty content area, until the page\n * arrives. Returns the cleanup.\n */\nconst observeLinkTaps = (root: HTMLElement): (() => void) => {\n /** The link marked as the next page. */\n let pending: string | undefined;\n /** Whether its page is loading; a pressed tab waits for its click. */\n let loading = false;\n const clear = () => {\n pending = undefined;\n loading = false;\n for (const link of root.querySelectorAll(`[${PENDING}]`)) link.removeAttribute(PENDING);\n root.removeAttribute(SWITCHING);\n root.querySelector(\".k2b-mobile-shell__title\")?.removeAttribute(NEXT_TITLE);\n };\n const mark = (link: HTMLAnchorElement) => {\n clear();\n pending = link.href;\n link.setAttribute(PENDING, \"\");\n const title = link.getAttribute(PAGE_TITLE);\n const heading = root.querySelector(\".k2b-mobile-shell__title\");\n if (title === null || !heading) return;\n heading.setAttribute(NEXT_TITLE, title);\n root.setAttribute(SWITCHING, \"\");\n };\n const touch = () => {};\n // A press on a tab shows its page's frame while the finger is still down. The page itself loads with the click\n // that ends the tap, as for any link: only the end of a touch counts as the person's action, and a load that\n // started before it could let the browser's Back skip this page.\n const press = (event: PointerEvent) => {\n if (!event.isPrimary) return;\n const link = pageLink(root, event);\n if (!link?.hasAttribute(PAGE_TITLE) || (link.href === pending && loading)) return;\n mark(link);\n };\n // A press that the browser takes over, such as one that turns into a scroll, ends without a click and takes its\n // frame back.\n const cancel = (event: PointerEvent) => {\n if (event.isPrimary && !loading) clear();\n };\n // On the window, so it runs after every handler of the click, including delegated ones that prevent it.\n const click = (event: MouseEvent) => {\n const link = pageLink(root, event);\n if (link && link.href === pending && loading) {\n event.preventDefault();\n return;\n }\n // Any other tap ends the wait, also for a link that answered with a download instead of a page.\n clear();\n if (!link) return;\n mark(link);\n loading = true;\n };\n // iOS sends no click for a tap on content without an action, so the end of a tap anywhere else ends the wait as\n // well. A touch that scrolls ends without a pointerup and keeps a load's wait.\n const release = (event: PointerEvent) => {\n if (pending === undefined) return;\n const link = event.target instanceof Element ? event.target.closest<HTMLAnchorElement>(\"a[href]\") : null;\n if (link?.href !== pending) clear();\n };\n // A page restored from the back/forward cache shows the state it was left in.\n const show = (event: PageTransitionEvent) => {\n if (event.persisted) clear();\n };\n document.addEventListener(\"touchstart\", touch, { passive: true });\n window.addEventListener(\"pointerdown\", press);\n window.addEventListener(\"pointercancel\", cancel);\n window.addEventListener(\"pointerup\", release);\n window.addEventListener(\"click\", click);\n window.addEventListener(\"pageshow\", show);\n return () => {\n document.removeEventListener(\"touchstart\", touch);\n window.removeEventListener(\"pointerdown\", press);\n window.removeEventListener(\"pointercancel\", cancel);\n window.removeEventListener(\"pointerup\", release);\n window.removeEventListener(\"click\", click);\n window.removeEventListener(\"pageshow\", show);\n clear();\n };\n};\n\n/**\n * Keeps a mounted shell working: the footer height on the body, which the portalled toast rail reads, the room a\n * persistent toast takes from the scroll area, the scroll area's edge fade, and immediate feedback for link taps.\n * The fade is the only cue at the footer's edge, which has no rule. `MobileShell` calls it itself;\n * a page that renders the shell on the server without hydrating it calls it once in the browser. Returns the\n * cleanup.\n */\nexport function observeMobileShell(root: HTMLElement): () => void {\n const main = root.querySelector<HTMLElement>(\":scope > .k2b-mobile-shell__main\");\n const body = main?.querySelector<HTMLElement>(\":scope > .k2b-mobile-shell__body\");\n if (!main || !body) return () => {};\n const stopLinkTaps = observeLinkTaps(root);\n const stopScrollFades = installScrollFades(body);\n let frame = 0;\n const measure = () => {\n frame = 0;\n const footer = Math.max(0, root.getBoundingClientRect().bottom - main.getBoundingClientRect().bottom);\n document.body.style.setProperty(FOOTER_HEIGHT, `${footer}px`);\n root.style.setProperty(TOAST_INSET, `${persistentToastInset(body)}px`);\n };\n const schedule = () => {\n if (!frame) frame = requestAnimationFrame(measure);\n };\n measure();\n // The footer can appear, disappear, or change height; the main area takes whatever it leaves.\n const resize = new ResizeObserver(schedule);\n resize.observe(root);\n resize.observe(main);\n // Toasts arrive and leave anywhere in the document, and their slots grow and collapse in a transition.\n const mutations = new MutationObserver(schedule);\n mutations.observe(document.body, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: [\"data-state\", \"data-closing\", \"data-persistent\", \"open\"],\n });\n document.addEventListener(\"transitionend\", schedule, true);\n return () => {\n if (frame) cancelAnimationFrame(frame);\n resize.disconnect();\n mutations.disconnect();\n document.removeEventListener(\"transitionend\", schedule, true);\n document.body.style.removeProperty(FOOTER_HEIGHT);\n stopLinkTaps();\n stopScrollFades();\n };\n}\n\nfunction MobileShellRoot(props: MobileShellProps): JSX.Element {\n let root!: HTMLDivElement;\n\n onMount(() => onCleanup(observeMobileShell(root)));\n\n return (\n <div ref={root} class={props.class ? `k2b-mobile-shell ${props.class}` : \"k2b-mobile-shell\"}>\n {props.header}\n <main class=\"k2b-mobile-shell__main\">\n <ScrollArea class=\"k2b-mobile-shell__body\">{props.children}</ScrollArea>\n </main>\n {props.footer}\n </div>\n );\n}\n\nfunction MobileShellHeader(props: MobileShellHeaderProps): JSX.Element {\n return (\n <header class=\"k2b-mobile-shell__header\">\n <Show when={props.back}>\n {(back) => (\n <Show\n when={back().href}\n fallback={\n <IconButton class=\"k2b-mobile-shell__back\" label={back().label} tooltip={false} onClick={() => back().onClick?.()}>\n <i class=\"ti ti-chevron-left\" aria-hidden=\"true\" />\n </IconButton>\n }\n >\n {(href) => (\n <IconButtonLink\n class=\"k2b-mobile-shell__back\"\n href={href()}\n label={back().label}\n tooltip={false}\n onClick={() => back().onClick?.()}\n >\n <i class=\"ti ti-chevron-left\" aria-hidden=\"true\" />\n </IconButtonLink>\n )}\n </Show>\n )}\n </Show>\n <h1 class=\"k2b-mobile-shell__title\">{props.title}</h1>\n <Show when={props.actions}>\n <div class=\"k2b-mobile-shell__actions\">{props.actions}</div>\n </Show>\n </header>\n );\n}\n\n/**\n * The full-screen frame of a phone app: a header, one scroll area, and an optional footer such as a `TabBar`. While\n * it is mounted, the document itself never scrolls, pinch zoom and rubber-banding are off, and the toast rail sits\n * above the footer. Mount one per page, as the page's layout.\n */\nexport const MobileShell = Object.assign(MobileShellRoot, { Header: MobileShellHeader });\n\nexport default MobileShell;\n"],"mappings":";;;;;;;;AAAA,SAAmB,SAAS,EAAE,OAAO,EAAE,IAAI,QAAQ,UAAU;AAC7D,SAAS,UAAU,EAAE,cAAc,QAAQ,mBAAmB;AAC9D,OAAO,UAAU,MAAM,cAAc;AACrC,SAAS,kBAAkB,QAAQ,eAAe;AAoBlD;AACA,MAAM,aAAa,GAAG,kCAAkC;AACxD;AACA,MAAM,WAAW,GAAG,gCAAgC;;AAEpD;AACA;AACA;AACA;AACA;AACA,MAAM,oBAAoB,GAAI,IAAiB,IAAa;EAC1D,IAAI,QAAQ,CAAC,aAAa,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;EACpD,MAAM,KAAK,GAAG,CAAC,GAAG,QAAQ,CAAC,gBAAgB,CAAc,iEAAiE,CAAC,CAAC;EAC5H,IAAI,CAAC,KAAK,CAAC,IAAI,CAAE,IAAI,IAAK,IAAI,CAAC,OAAO,CAAC,UAAU,KAAK,MAAM,CAAC,EAAE,OAAO,CAAC;EACvE,MAAM,IAAI,GAAG,IAAI,CAAC,qBAAqB,CAAC,CAAC;EACzC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAE,IAAI,IAAK,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;EAC9E,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC;AAC9D,CAAC;;AAED;AACA,MAAM,OAAO,GAAG,kBAAkB;AAClC;AACA,MAAM,UAAU,GAAG,gBAAgB;AACnC;AACA,MAAM,SAAS,GAAG,oBAAoB;AACtC;AACA,MAAM,UAAU,GAAG,qBAAqB;;AAExC;AACA,MAAM,QAAQ,GAAG,CAAC,IAAiB,EAAE,KAAiB,KAA+B;EACnF,IAAI,KAAK,CAAC,gBAAgB,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,MAAM,EAAE,OAAO,IAAI;EACjI,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,YAAY,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,OAAO,CAAoB,SAAS,CAAC,GAAG,IAAI;EACxG,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,IAAK,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,KAAK,OAAQ,EAAE,OAAO,IAAI;EAC3H,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;EAC9B,IAAI,GAAG,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM,EAAE,OAAO,IAAI;EAC/C;EACA,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC,QAAQ,IAAI,GAAG,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM,EAAE,OAAO,IAAI;EACjG,OAAO,IAAI;AACb,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,eAAe,GAAI,IAAiB,IAAmB;EAC3D;EACA,IAAI,OAA2B;EAC/B;EACA,IAAI,OAAO,GAAG,KAAK;EACnB,MAAM,KAAK,GAAG,MAAM;IAClB,OAAO,GAAG,SAAS;IACnB,OAAO,GAAG,KAAK;IACf,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,gBAAgB,CAAC,IAAI,OAAO,GAAG,CAAC,EAAE,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC;IACvF,IAAI,CAAC,eAAe,CAAC,SAAS,CAAC;IAC/B,IAAI,CAAC,aAAa,CAAC,0BAA0B,CAAC,EAAE,eAAe,CAAC,UAAU,CAAC;EAC7E,CAAC;EACD,MAAM,IAAI,GAAI,IAAuB,IAAK;IACxC,KAAK,CAAC,CAAC;IACP,OAAO,GAAG,IAAI,CAAC,IAAI;IACnB,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,EAAE,CAAC;IAC9B,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC;IAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,0BAA0B,CAAC;IAC9D,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,OAAO,EAAE;IAChC,OAAO,CAAC,YAAY,CAAC,UAAU,EAAE,KAAK,CAAC;IACvC,IAAI,CAAC,YAAY,CAAC,SAAS,EAAE,EAAE,CAAC;EAClC,CAAC;EACD,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC;EACtB;EACA;EACA;EACA,MAAM,KAAK,GAAI,KAAmB,IAAK;IACrC,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE;IACtB,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IAClC,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,UAAU,CAAC,IAAK,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,OAAQ,EAAE;IAC3E,IAAI,CAAC,IAAI,CAAC;EACZ,CAAC;EACD;EACA;EACA,MAAM,MAAM,GAAI,KAAmB,IAAK;IACtC,IAAI,KAAK,CAAC,SAAS,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;EAC1C,CAAC;EACD;EACA,MAAM,KAAK,GAAI,KAAiB,IAAK;IACnC,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IAClC,IAAI,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,OAAO,EAAE;MAC5C,KAAK,CAAC,cAAc,CAAC,CAAC;MACtB;IACF;IACA;IACA,KAAK,CAAC,CAAC;IACP,IAAI,CAAC,IAAI,EAAE;IACX,IAAI,CAAC,IAAI,CAAC;IACV,OAAO,GAAG,IAAI;EAChB,CAAC;EACD;EACA;EACA,MAAM,OAAO,GAAI,KAAmB,IAAK;IACvC,IAAI,OAAO,KAAK,SAAS,EAAE;IAC3B,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,YAAY,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,OAAO,CAAoB,SAAS,CAAC,GAAG,IAAI;IACxG,IAAI,IAAI,EAAE,IAAI,KAAK,OAAO,EAAE,KAAK,CAAC,CAAC;EACrC,CAAC;EACD;EACA,MAAM,IAAI,GAAI,KAA0B,IAAK;IAC3C,IAAI,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;EAC9B,CAAC;EACD,QAAQ,CAAC,gBAAgB,CAAC,YAAY,EAAE,KAAK,EAAE;IAAE,OAAO,EAAE;EAAK,CAAC,CAAC;EACjE,MAAM,CAAC,gBAAgB,CAAC,aAAa,EAAE,KAAK,CAAC;EAC7C,MAAM,CAAC,gBAAgB,CAAC,eAAe,EAAE,MAAM,CAAC;EAChD,MAAM,CAAC,gBAAgB,CAAC,WAAW,EAAE,OAAO,CAAC;EAC7C,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC;EACvC,MAAM,CAAC,gBAAgB,CAAC,UAAU,EAAE,IAAI,CAAC;EACzC,OAAO,MAAM;IACX,QAAQ,CAAC,mBAAmB,CAAC,YAAY,EAAE,KAAK,CAAC;IACjD,MAAM,CAAC,mBAAmB,CAAC,aAAa,EAAE,KAAK,CAAC;IAChD,MAAM,CAAC,mBAAmB,CAAC,eAAe,EAAE,MAAM,CAAC;IACnD,MAAM,CAAC,mBAAmB,CAAC,WAAW,EAAE,OAAO,CAAC;IAChD,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC;IAC1C,MAAM,CAAC,mBAAmB,CAAC,UAAU,EAAE,IAAI,CAAC;IAC5C,KAAK,CAAC,CAAC;EACT,CAAC;AACH,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAAS,kBAAkB,CAAC,IAAiB,EAAc;EAChE,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,CAAc,kCAAkC,CAAC;EAChF,MAAM,IAAI,GAAG,IAAI,EAAE,aAAa,CAAc,kCAAkC,CAAC;EACjF,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,OAAO,MAAM,CAAC,CAAC;EACnC,MAAM,YAAY,GAAG,eAAe,CAAC,IAAI,CAAC;EAC1C,MAAM,eAAe,GAAG,kBAAkB,CAAC,IAAI,CAAC;EAChD,IAAI,KAAK,GAAG,CAAC;EACb,MAAM,OAAO,GAAG,MAAM;IACpB,KAAK,GAAG,CAAC;IACT,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC,MAAM,GAAG,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC,MAAM,CAAC;IACrG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,aAAa,EAAE,GAAG,MAAM,IAAI,CAAC;IAC7D,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,WAAW,EAAE,GAAG,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC;EACxE,CAAC;EACD,MAAM,QAAQ,GAAG,MAAM;IACrB,IAAI,CAAC,KAAK,EAAE,KAAK,GAAG,qBAAqB,CAAC,OAAO,CAAC;EACpD,CAAC;EACD,OAAO,CAAC,CAAC;EACT;EACA,MAAM,MAAM,GAAG,IAAI,cAAc,CAAC,QAAQ,CAAC;EAC3C,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;EACpB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;EACpB;EACA,MAAM,SAAS,GAAG,IAAI,gBAAgB,CAAC,QAAQ,CAAC;EAChD,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE;IAC/B,SAAS,EAAE,IAAI;IACf,OAAO,EAAE,IAAI;IACb,UAAU,EAAE,IAAI;IAChB,eAAe,EAAE,CAAC,YAAY,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM;EAC3E,CAAC,CAAC;EACF,QAAQ,CAAC,gBAAgB,CAAC,eAAe,EAAE,QAAQ,EAAE,IAAI,CAAC;EAC1D,OAAO,MAAM;IACX,IAAI,KAAK,EAAE,oBAAoB,CAAC,KAAK,CAAC;IACtC,MAAM,CAAC,UAAU,CAAC,CAAC;IACnB,SAAS,CAAC,UAAU,CAAC,CAAC;IACtB,QAAQ,CAAC,mBAAmB,CAAC,eAAe,EAAE,QAAQ,EAAE,IAAI,CAAC;IAC7D,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,aAAa,CAAC;IACjD,YAAY,CAAC,CAAC;IACd,eAAe,CAAC,CAAC;EACnB,CAAC;AACH;AAEA,SAAS,eAAe,CAAC,KAAuB,EAAe;EAC7D,IAAI,IAAqB;EAEzB,OAAO,CAAC,MAAM,SAAS,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC;EAElD,6CACyB,KAAK,CAAC,KAAK,GAAG,6BAAoB,KAAK,CAAC,KAAK,SAAE,GAAG,kBAAkB,mBACxF,KAAK,CAAC,MAAM,8BAEV,UAAU;IAAA;IAAA;MAAA,OAAiC,KAAK,CAAC,QAAQ;IAAA;EAAA,cAE3D,KAAK,CAAC,MAAM;AAGnB;AAEA,SAAS,iBAAiB,CAAC,KAA6B,EAAe;EACrE,iDAEK,IAAI;IAAA,IAAC,IAAI;MAAA,OAAE,KAAK,CAAC,IAAI;IAAA;IAAA,UAClB,IAAI,sBACH,IAAI;MAAA,IACH,IAAI;QAAA,OAAE,IAAI,CAAC,CAAC,CAAC,IAAI;MAAA;MAAA,IACjB,QAAQ;QAAA,yBACL,UAAU;UAAA;UAAA,IAAgC,KAAK;YAAA,OAAE,IAAI,CAAC,CAAC,CAAC,KAAK;UAAA;UAAE,OAAO,EAAE,KAAK;UAAE,OAAO,EAAE,MAAM,IAAI,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC;UAAA;YAAA;UAAA;QAAA;MAAA;MAAA,UAKjH,IAAI,sBACH,cAAc;QAAA;QAAA,IAEb,IAAI;UAAA,OAAE,IAAI,CAAC,CAAC;QAAA;QAAA,IACZ,KAAK;UAAA,OAAE,IAAI,CAAC,CAAC,CAAC,KAAK;QAAA;QACnB,OAAO,EAAE,KAAK;QACd,OAAO,EAAE,MAAM,IAAI,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC;QAAA;UAAA;QAAA;MAAA;IAIpC;EAEJ,cAEkC,KAAK,CAAC,KAAK,8BAC/C,IAAI;IAAA,IAAC,IAAI;MAAA,OAAE,KAAK,CAAC,OAAO;IAAA;IAAA;MAAA,+BACiB,KAAK,CAAC,OAAO;IAAA;EAAA;AAI7D;;AAEA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC,eAAe,EAAE;EAAE,MAAM,EAAE;AAAkB,CAAC,CAAC;AAExF,eAAe,WAAW","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":[],"sources":["layout/MobileShell.tsx"],"sourcesContent":["import { For, type JSX, onCleanup, onMount, Show } from \"solid-js\";\nimport { IconButton, IconButtonLink } from \"../actions/Button\";\nimport ScrollArea from \"./ScrollArea\";\nimport { installScrollFades } from \"./scroll-fade\";\nimport type { TabBarItem } from \"./TabBar\";\n\nexport type MobileShellProps = {\n /** Usually `MobileShell.Header`; it sits above the scroll area and pads the top safe area. */\n header?: JSX.Element;\n /** Usually a `TabBar`; it sits below the scroll area and pads the bottom safe area itself. */\n footer?: JSX.Element;\n /**\n * Usually `MobileShell.Sidebar` with the footer's destinations and more. From 48rem of window width it stands at\n * the start edge and the footer goes; below, it is not shown. The server renders both, so CSS alone decides.\n */\n sidebar?: JSX.Element;\n /** The page content, inside the shell's only scroll area. */\n children: JSX.Element;\n /**\n * `false` for content that brings its own heads and scroll areas, such as `AppWorkspace.Main` levels: it fills the\n * main area without the shell's scroll area, and the header shows only as the frame of the next page while a tapped\n * tab's page loads.\n */\n scroll?: boolean;\n class?: string;\n};\n\nexport type MobileShellHeaderProps = {\n title: string;\n /** The title while the shell shows its sidebar, which already names the app; `title` by default. */\n sidebarTitle?: string;\n /**\n * A Back control before the title: a link with `href`, otherwise a button. `withSidebar: false` hides it while the\n * shell shows its sidebar, for a way back to a destination the sidebar lists.\n */\n back?: { href?: string; onClick?: () => void; label: string; withSidebar?: boolean };\n /** Controls after the title, such as a menu. */\n actions?: JSX.Element;\n};\n\n/** Read by the toast rail, which is portalled outside the shell, so it lives on the body. */\nconst FOOTER_HEIGHT = \"--k2b-mobile-shell-footer-height\";\n/** How much of the scroll area a persistent toast covers; local to the shell. */\nconst TOAST_INSET = \"--k2b-mobile-shell-toast-inset\";\n\n/**\n * The visible part of the toast rail when it holds a toast without a timer (`duration: 0`, running progress, or a\n * custom slot), so the last row of the scroll area can still scroll above it. A rail that sits elsewhere, such as\n * above a dialog, covers nothing.\n */\nconst persistentToastInset = (body: HTMLElement): number => {\n if (document.querySelector(\"dialog:modal\")) return 0;\n const cards = [...document.querySelectorAll<HTMLElement>(\"[data-k2b-toast-container] [data-k2b-toast]:not([data-closing])\")];\n if (!cards.some((card) => card.dataset.persistent === \"true\")) return 0;\n const area = body.getBoundingClientRect();\n const top = Math.min(...cards.map((card) => card.getBoundingClientRect().top));\n return Math.max(0, Math.min(area.height, area.bottom - top));\n};\n\n/** Marks the link whose page is loading; the tab bar shows it as selected. */\nconst PENDING = \"data-k2b-pending\";\n/** On a link: the title of the page it opens. Such a link switches the shell to that page's frame at the first touch. */\nconst PAGE_TITLE = \"data-k2b-title\";\n/** On the root while the shell shows the frame of the page that is loading. */\nconst SWITCHING = \"data-k2b-switching\";\n/** On the header title while the shell switches: the loading page's title, which the title shows instead. */\nconst NEXT_TITLE = \"data-k2b-next-title\";\n\n/** The link a click or press follows as a page load of this origin, or null when it does something else. */\nconst pageLink = (root: HTMLElement, event: MouseEvent): HTMLAnchorElement | null => {\n if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return null;\n const link = event.target instanceof Element ? event.target.closest<HTMLAnchorElement>(\"a[href]\") : null;\n if (!link || !root.contains(link) || link.hasAttribute(\"download\") || (link.target && link.target !== \"_self\")) return null;\n const url = new URL(link.href);\n if (url.origin !== location.origin) return null;\n // A jump inside the page loads nothing.\n if (url.hash && url.pathname === location.pathname && url.search === location.search) return null;\n return link;\n};\n\n/**\n * Taps on the shell's links. iOS shows `:active` only while the page listens to touches, so a tap gets its pressed\n * state at once. A link's page keeps loading while the old page stays visible; a second tap on it would cancel that\n * load and start it over, so it is ignored. A link that names its page's title, such as a tab, shows that page's\n * frame at the first touch instead of at the end of the tap: its title and an empty content area, until the page\n * arrives. Returns the cleanup.\n */\nconst observeLinkTaps = (root: HTMLElement): (() => void) => {\n /** The link marked as the next page. */\n let pending: string | undefined;\n /** Whether its page is loading; a pressed tab waits for its click. */\n let loading = false;\n const clear = () => {\n pending = undefined;\n loading = false;\n for (const link of root.querySelectorAll(`[${PENDING}]`)) link.removeAttribute(PENDING);\n root.removeAttribute(SWITCHING);\n root.querySelector(\".k2b-mobile-shell__title\")?.removeAttribute(NEXT_TITLE);\n };\n const mark = (link: HTMLAnchorElement) => {\n clear();\n pending = link.href;\n link.setAttribute(PENDING, \"\");\n const title = link.getAttribute(PAGE_TITLE);\n const heading = root.querySelector(\".k2b-mobile-shell__title\");\n if (title === null || !heading) return;\n heading.setAttribute(NEXT_TITLE, title);\n root.setAttribute(SWITCHING, \"\");\n };\n const touch = () => {};\n // A press on a tab shows its page's frame while the finger is still down. The page itself loads with the click\n // that ends the tap, as for any link: only the end of a touch counts as the person's action, and a load that\n // started before it could let the browser's Back skip this page.\n const press = (event: PointerEvent) => {\n if (!event.isPrimary) return;\n const link = pageLink(root, event);\n if (!link?.hasAttribute(PAGE_TITLE) || (link.href === pending && loading)) return;\n mark(link);\n };\n // A press that the browser takes over, such as one that turns into a scroll, ends without a click and takes its\n // frame back.\n const cancel = (event: PointerEvent) => {\n if (event.isPrimary && !loading) clear();\n };\n // On the window, so it runs after every handler of the click, including delegated ones that prevent it.\n const click = (event: MouseEvent) => {\n const link = pageLink(root, event);\n if (link && link.href === pending && loading) {\n event.preventDefault();\n return;\n }\n // Any other tap ends the wait, also for a link that answered with a download instead of a page.\n clear();\n if (!link) return;\n mark(link);\n loading = true;\n };\n // iOS sends no click for a tap on content without an action, so the end of a tap anywhere else ends the wait as\n // well. A touch that scrolls ends without a pointerup and keeps a load's wait.\n const release = (event: PointerEvent) => {\n if (pending === undefined) return;\n const link = event.target instanceof Element ? event.target.closest<HTMLAnchorElement>(\"a[href]\") : null;\n if (link?.href !== pending) clear();\n };\n // A page restored from the back/forward cache shows the state it was left in.\n const show = (event: PageTransitionEvent) => {\n if (event.persisted) clear();\n };\n document.addEventListener(\"touchstart\", touch, { passive: true });\n window.addEventListener(\"pointerdown\", press);\n window.addEventListener(\"pointercancel\", cancel);\n window.addEventListener(\"pointerup\", release);\n window.addEventListener(\"click\", click);\n window.addEventListener(\"pageshow\", show);\n return () => {\n document.removeEventListener(\"touchstart\", touch);\n window.removeEventListener(\"pointerdown\", press);\n window.removeEventListener(\"pointercancel\", cancel);\n window.removeEventListener(\"pointerup\", release);\n window.removeEventListener(\"click\", click);\n window.removeEventListener(\"pageshow\", show);\n clear();\n };\n};\n\n/**\n * Keeps a mounted shell working: the footer height on the body, which the portalled toast rail reads, the room a\n * persistent toast takes from the scroll area, the scroll area's edge fade, and immediate feedback for link taps.\n * The fade is the only cue at the footer's edge, which has no rule. `MobileShell` calls it itself;\n * a page that renders the shell on the server without hydrating it calls it once in the browser. Returns the\n * cleanup.\n */\nexport function observeMobileShell(root: HTMLElement): () => void {\n const main = root.querySelector<HTMLElement>(\":scope > .k2b-mobile-shell__main\");\n const body = main?.querySelector<HTMLElement>(\":scope > .k2b-mobile-shell__body\");\n if (!main) return () => {};\n const stopLinkTaps = observeLinkTaps(root);\n // Content with its own scroll areas keeps its own fades; the room a toast takes applies to the whole main area.\n const stopScrollFades = body ? installScrollFades(body) : () => {};\n let frame = 0;\n const measure = () => {\n frame = 0;\n const footer = Math.max(0, root.getBoundingClientRect().bottom - main.getBoundingClientRect().bottom);\n document.body.style.setProperty(FOOTER_HEIGHT, `${footer}px`);\n root.style.setProperty(TOAST_INSET, `${persistentToastInset(body ?? main)}px`);\n };\n const schedule = () => {\n if (!frame) frame = requestAnimationFrame(measure);\n };\n measure();\n // The footer can appear, disappear, or change height; the main area takes whatever it leaves.\n const resize = new ResizeObserver(schedule);\n resize.observe(root);\n resize.observe(main);\n // Toasts arrive and leave anywhere in the document, and their slots grow and collapse in a transition.\n const mutations = new MutationObserver(schedule);\n mutations.observe(document.body, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: [\"data-state\", \"data-closing\", \"data-persistent\", \"open\"],\n });\n document.addEventListener(\"transitionend\", schedule, true);\n return () => {\n if (frame) cancelAnimationFrame(frame);\n resize.disconnect();\n mutations.disconnect();\n document.removeEventListener(\"transitionend\", schedule, true);\n document.body.style.removeProperty(FOOTER_HEIGHT);\n stopLinkTaps();\n stopScrollFades();\n };\n}\n\nfunction MobileShellRoot(props: MobileShellProps): JSX.Element {\n let root!: HTMLDivElement;\n\n onMount(() => onCleanup(observeMobileShell(root)));\n\n return (\n <div\n ref={root}\n class={props.class ? `k2b-mobile-shell ${props.class}` : \"k2b-mobile-shell\"}\n data-k2b-content-heads={props.scroll === false ? \"\" : undefined}\n >\n {props.sidebar}\n {props.header}\n <main class=\"k2b-mobile-shell__main\">\n <Show when={props.scroll !== false} fallback={props.children}>\n <ScrollArea class=\"k2b-mobile-shell__body\">{props.children}</ScrollArea>\n </Show>\n </main>\n {props.footer}\n </div>\n );\n}\n\nfunction MobileShellHeader(props: MobileShellHeaderProps): JSX.Element {\n return (\n <header class=\"k2b-mobile-shell__header\">\n <Show when={props.back}>\n {(back) => (\n <Show\n when={back().href}\n fallback={\n <IconButton\n class=\"k2b-mobile-shell__back\"\n data-with-sidebar={back().withSidebar === false ? \"false\" : undefined}\n label={back().label}\n tooltip={false}\n onClick={() => back().onClick?.()}\n >\n <i class=\"ti ti-chevron-left\" aria-hidden=\"true\" />\n </IconButton>\n }\n >\n {(href) => (\n <IconButtonLink\n class=\"k2b-mobile-shell__back\"\n data-with-sidebar={back().withSidebar === false ? \"false\" : undefined}\n href={href()}\n label={back().label}\n tooltip={false}\n onClick={() => back().onClick?.()}\n >\n <i class=\"ti ti-chevron-left\" aria-hidden=\"true\" />\n </IconButtonLink>\n )}\n </Show>\n )}\n </Show>\n <h1 class=\"k2b-mobile-shell__title\">\n <Show when={props.sidebarTitle !== undefined && props.sidebarTitle !== props.title} fallback={props.title}>\n <span class=\"k2b-mobile-shell__title-narrow\">{props.title}</span>\n <span class=\"k2b-mobile-shell__title-wide\">{props.sidebarTitle}</span>\n </Show>\n </h1>\n <Show when={props.actions}>\n <div class=\"k2b-mobile-shell__actions\">{props.actions}</div>\n </Show>\n </header>\n );\n}\n\nexport type MobileShellSidebarItem = TabBarItem & {\n /** A count after the label, such as unread messages; 0 shows nothing. */\n count?: number;\n};\n\nexport type MobileShellSidebarProps = {\n /** Accessible name of the navigation landmark; usually the tab bar's. */\n label: string;\n /** The app's name in the sidebar's head. */\n title: string;\n /** Address of the app's logo before the name; decorative, the name says it. */\n logo?: string;\n /** Destinations at the top, such as Start. */\n items: readonly MobileShellSidebarItem[];\n /** Named groups below them, such as the apps; a group without items is left out. */\n sections?: readonly { title: string; items: readonly MobileShellSidebarItem[] }[];\n /** Destinations at the bottom edge, such as Settings. */\n footer?: readonly MobileShellSidebarItem[];\n};\n\nfunction SidebarLink(props: { item: MobileShellSidebarItem }): JSX.Element {\n return (\n <a\n href={props.item.href}\n aria-current={props.item.current ? \"page\" : undefined}\n data-tab={props.item.id}\n data-k2b-title={props.item.title ?? props.item.label}\n >\n <i class={props.item.icon} aria-hidden=\"true\" />\n <span class=\"k2b-truncate-fade\">{props.item.label}</span>\n <Show when={props.item.count}>{(count) => <span class=\"k2b-mobile-shell__sidebar-count\">{count()}</span>}</Show>\n </a>\n );\n}\n\n/**\n * The navigation of a touch app on a wide screen, in `MobileShell`'s `sidebar`: the app's name, then its destinations\n * as 44 px rows with icon and label, the open one in the action colour. A press shows the item's page frame at once,\n * as on a tab, and the row of a loading page pulses.\n */\nfunction MobileShellSidebar(props: MobileShellSidebarProps): JSX.Element {\n const list = (items: readonly MobileShellSidebarItem[]) => (\n <ul>\n <For each={items}>\n {(item) => (\n <li>\n <SidebarLink item={item} />\n </li>\n )}\n </For>\n </ul>\n );\n return (\n <nav class=\"k2b-mobile-shell__sidebar\" aria-label={props.label}>\n <div class=\"k2b-mobile-shell__sidebar-head\">\n <Show when={props.logo}>{(logo) => <img src={logo()} alt=\"\" width=\"32\" height=\"32\" />}</Show>\n <span class=\"k2b-truncate-fade\">{props.title}</span>\n </div>\n <div class=\"k2b-mobile-shell__sidebar-body\">\n {list(props.items)}\n <For each={(props.sections ?? []).filter((section) => section.items.length > 0)}>\n {(section) => (\n <section>\n <h2>{section.title}</h2>\n {list(section.items)}\n </section>\n )}\n </For>\n </div>\n <Show when={props.footer?.length}>\n <div class=\"k2b-mobile-shell__sidebar-foot\">{list(props.footer ?? [])}</div>\n </Show>\n </nav>\n );\n}\n\n/**\n * The full-screen frame of a phone app: a header, one scroll area, and an optional footer such as a `TabBar`. With a\n * `sidebar`, a window of 48rem and wider shows the sidebar at the start edge instead of the footer, and the toast rail\n * stays in the area beside it. While it is mounted, the document itself never scrolls, pinch zoom and rubber-banding\n * are off, and the toast rail sits above the footer. Mount one per page, as the page's layout.\n */\nexport const MobileShell = Object.assign(MobileShellRoot, { Header: MobileShellHeader, Sidebar: MobileShellSidebar });\n\nexport default MobileShell;\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -108,7 +108,7 @@ export default function Navigation(props) {
|
|
|
108
108
|
return item().section;
|
|
109
109
|
},
|
|
110
110
|
get fallback() {
|
|
111
|
-
return _$ssr(_tmpl$11, _$ssrAttribute("data-active", _$escape(item().active || undefined, true), false), _$escape(_$createComponent(Show, {
|
|
111
|
+
return _$ssr(_tmpl$11, _$ssrAttribute("data-active", _$escape(item().active || undefined, true), false) + _$ssrAttribute("data-context", item().context === undefined ? _$escape(undefined, true) : _$escape(String(item().context), true), false), _$escape(_$createComponent(Show, {
|
|
112
112
|
get when() {
|
|
113
113
|
return item().href;
|
|
114
114
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["layout/Navigation.tsx"],"sourcesContent":["import { documentNavigate, Link } from \"@k2b/ssr/nav\";\nimport { createSignal, createUniqueId, For, Show } from \"solid-js\";\nimport { IconButton } from \"../actions/Button\";\nimport { Dropdown } from \"../actions/Dropdown\";\nimport type { NavigationController, NavigationItem } from \"./navigation-model\";\nimport { AppWorkspaceSidebarSwitcher } from \"./SidebarSwitcher\";\nimport { useWorkspaceMessages } from \"./workspace-messages\";\n\nexport type NavigationProps = {\n navigation: NavigationController;\n label: string;\n /** A host can finish dismissing its menu before the selected operation runs. */\n beforeSelect?: () => boolean | void | Promise<boolean | void>;\n};\n\n/** A named icon is an image screen readers announce; any other icon is decoration. */\nconst iconAccessibility = (label: string | undefined) => (label ? { role: \"img\" as const, \"aria-label\": label } : { \"aria-hidden\": true });\n\nexport default function Navigation(props: NavigationProps) {\n const workspaceMessages = useWorkspaceMessages();\n const [expanded, setExpanded] = createSignal<Record<string, boolean>>({});\n const ready = async () => (await props.beforeSelect?.()) !== false;\n /** `keepOpen` changes only what the menu shows, so the host does not dismiss it first. */\n const activate = async (id: string, keepOpen = false) => {\n if (keepOpen || (await ready())) await props.navigation.activate(id);\n };\n const Rows = (rows: { items: readonly NavigationItem[]; disabled?: boolean; labelledBy?: string }) => (\n <ul class=\"k2b-navigation__list\" aria-labelledby={rows.labelledBy}>\n <For each={rows.items.map((item) => item.id)}>\n {(id) => {\n const item = () => rows.items.find((entry) => entry.id === id)!;\n const disabled = () => rows.disabled || item().disabled;\n const headingId = `k2b-navigation-section-${createUniqueId()}`;\n // `expanded` hands disclosure to the item's owner; every other toggle stays local to this renderer.\n const open = () => item().expanded ?? expanded()[id] ?? item().defaultExpanded ?? true;\n const toggle = () => {\n if (item().expanded !== undefined) props.navigation.onExpandedChange?.(id, !open());\n else setExpanded((current) => ({ ...current, [id]: !open() }));\n };\n const content = () => (\n <>\n <Show when={item().icon}>\n <i class={item().icon} {...iconAccessibility(item().iconLabel)} />\n </Show>\n <span class=\"k2b-navigation__copy\">\n <span>{item().label}</span>\n <Show when={item().description}>\n <small>{item().description}</small>\n </Show>\n </span>\n <Show when={item().color}>\n <span class=\"k2b-navigation__color\" style={{ \"background-color\": item().color }} />\n </Show>\n <Show when={item().badge !== undefined}>\n <span class=\"k2b-navigation__badge\">{item().badge}</span>\n </Show>\n {/* `null` keeps the empty slot, so a status that appears later takes no width from the label. */}\n <Show when={item().status !== undefined}>\n <span class=\"k2b-navigation__status\" data-tone={item().status?.tone} title={item().status?.label}>\n <Show when={item().status}>\n {(status) => (\n <>\n <i class={status().icon} aria-hidden=\"true\" />\n <span class=\"k2b-sr-only\">{status().label}</span>\n </>\n )}\n </Show>\n </span>\n </Show>\n </>\n );\n return (\n <Show\n when={item().section}\n fallback={\n <li>\n <div class=\"k2b-navigation__row\" data-active={item().active || undefined}>\n <Show\n when={item().href}\n fallback={\n <button\n type=\"button\"\n class=\"k2b-navigation__control\"\n disabled={disabled()}\n aria-expanded={!item().action ? open() : undefined}\n onClick={() => (item().action ? void activate(id, item().keepOpen) : toggle())}\n >\n {content()}\n <Show when={!item().action && item().children?.length}>\n <i class={open() ? \"ti ti-chevron-down\" : \"ti ti-chevron-right\"} aria-hidden=\"true\" />\n </Show>\n </button>\n }\n >\n {(href) => (\n <Link\n class=\"k2b-navigation__control\"\n href={href()}\n aria-current={item().active ? \"page\" : undefined}\n aria-disabled={disabled() || undefined}\n tabIndex={disabled() ? -1 : undefined}\n scroll={item().scroll}\n onNavigate={async (event) => {\n if (!(await ready())) return;\n if (item().navigation === \"enhanced\" && props.navigation.onNavigate) await props.navigation.onNavigate(event);\n else event.fallback();\n }}\n onClick={(event) => {\n if (disabled()) {\n event.preventDefault();\n return;\n }\n if (!item().action || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey)\n return;\n // Local opening can fetch before committing navigation, outside a view transition.\n event.preventDefault();\n void activate(id);\n }}\n >\n {content()}\n </Link>\n )}\n </Show>\n <Show when={(item().href || item().action) && item().children?.length}>\n <button\n type=\"button\"\n class=\"k2b-navigation__disclosure\"\n aria-label={item().label}\n aria-expanded={open()}\n disabled={disabled()}\n onClick={toggle}\n >\n <i class={open() ? \"ti ti-chevron-down\" : \"ti ti-chevron-right\"} aria-hidden=\"true\" />\n </button>\n </Show>\n {/* Keyed by id like the rows, so a button keeps its identity and focus when the model updates. */}\n <For each={(item().inlineActions ?? []).map((action) => action.id)}>\n {(actionId) => {\n const action = () => item().inlineActions?.find((entry) => entry.id === actionId);\n return (\n <Show when={action()}>\n {(current) => (\n <IconButton\n class=\"k2b-navigation__inline-action\"\n label={current().label}\n disabled={disabled() || current().disabled}\n onClick={() => void activate(actionId)}\n >\n <i class={current().icon} aria-hidden=\"true\" />\n </IconButton>\n )}\n </Show>\n );\n }}\n </For>\n <Show when={item().actions?.length}>\n <Dropdown.Root\n items={(item().actions ?? []).map((action) => ({\n label: action.label,\n icon: action.icon,\n description: action.description,\n disabled: disabled() || action.disabled,\n action: () => {\n if (action.href)\n void ready().then((allowed) => {\n if (allowed) documentNavigate(action.href!);\n });\n else void activate(action.id);\n },\n }))}\n >\n <Dropdown.Trigger iconOnly label={`${item().label}: ${workspaceMessages().rowAction}`} variant=\"ghost\">\n <i class=\"ti ti-dots\" aria-hidden=\"true\" />\n </Dropdown.Trigger>\n </Dropdown.Root>\n </Show>\n </div>\n <Show when={item().children?.length}>\n <div hidden={!open()}>\n <Rows items={item().children ?? []} disabled={disabled()} />\n </div>\n </Show>\n </li>\n }\n >\n <li class=\"k2b-navigation__section\">\n <div class=\"k2b-navigation__heading\" id={headingId}>\n {item().label}\n </div>\n <Rows items={item().children ?? []} disabled={disabled()} labelledBy={headingId} />\n </li>\n </Show>\n );\n }}\n </For>\n </ul>\n );\n return (\n <nav class=\"k2b-navigation\" aria-label={props.label}>\n <Show when={props.navigation.switcher?.()}>\n {(switcher) => <AppWorkspaceSidebarSwitcher {...switcher()} beforeSelect={props.beforeSelect} />}\n </Show>\n <Rows items={props.navigation.items()} />\n </nav>\n );\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":[],"sources":["layout/Navigation.tsx"],"sourcesContent":["import { documentNavigate, Link } from \"@k2b/ssr/nav\";\nimport { createSignal, createUniqueId, For, Show } from \"solid-js\";\nimport { IconButton } from \"../actions/Button\";\nimport { Dropdown } from \"../actions/Dropdown\";\nimport type { NavigationController, NavigationItem } from \"./navigation-model\";\nimport { AppWorkspaceSidebarSwitcher } from \"./SidebarSwitcher\";\nimport { useWorkspaceMessages } from \"./workspace-messages\";\n\nexport type NavigationProps = {\n navigation: NavigationController;\n label: string;\n /** A host can finish dismissing its menu before the selected operation runs. */\n beforeSelect?: () => boolean | void | Promise<boolean | void>;\n};\n\n/** A named icon is an image screen readers announce; any other icon is decoration. */\nconst iconAccessibility = (label: string | undefined) => (label ? { role: \"img\" as const, \"aria-label\": label } : { \"aria-hidden\": true });\n\nexport default function Navigation(props: NavigationProps) {\n const workspaceMessages = useWorkspaceMessages();\n const [expanded, setExpanded] = createSignal<Record<string, boolean>>({});\n const ready = async () => (await props.beforeSelect?.()) !== false;\n /** `keepOpen` changes only what the menu shows, so the host does not dismiss it first. */\n const activate = async (id: string, keepOpen = false) => {\n if (keepOpen || (await ready())) await props.navigation.activate(id);\n };\n const Rows = (rows: { items: readonly NavigationItem[]; disabled?: boolean; labelledBy?: string }) => (\n <ul class=\"k2b-navigation__list\" aria-labelledby={rows.labelledBy}>\n <For each={rows.items.map((item) => item.id)}>\n {(id) => {\n const item = () => rows.items.find((entry) => entry.id === id)!;\n const disabled = () => rows.disabled || item().disabled;\n const headingId = `k2b-navigation-section-${createUniqueId()}`;\n // `expanded` hands disclosure to the item's owner; every other toggle stays local to this renderer.\n const open = () => item().expanded ?? expanded()[id] ?? item().defaultExpanded ?? true;\n const toggle = () => {\n if (item().expanded !== undefined) props.navigation.onExpandedChange?.(id, !open());\n else setExpanded((current) => ({ ...current, [id]: !open() }));\n };\n const content = () => (\n <>\n <Show when={item().icon}>\n <i class={item().icon} {...iconAccessibility(item().iconLabel)} />\n </Show>\n <span class=\"k2b-navigation__copy\">\n <span>{item().label}</span>\n <Show when={item().description}>\n <small>{item().description}</small>\n </Show>\n </span>\n <Show when={item().color}>\n <span class=\"k2b-navigation__color\" style={{ \"background-color\": item().color }} />\n </Show>\n <Show when={item().badge !== undefined}>\n <span class=\"k2b-navigation__badge\">{item().badge}</span>\n </Show>\n {/* `null` keeps the empty slot, so a status that appears later takes no width from the label. */}\n <Show when={item().status !== undefined}>\n <span class=\"k2b-navigation__status\" data-tone={item().status?.tone} title={item().status?.label}>\n <Show when={item().status}>\n {(status) => (\n <>\n <i class={status().icon} aria-hidden=\"true\" />\n <span class=\"k2b-sr-only\">{status().label}</span>\n </>\n )}\n </Show>\n </span>\n </Show>\n </>\n );\n return (\n <Show\n when={item().section}\n fallback={\n <li>\n <div\n class=\"k2b-navigation__row\"\n data-active={item().active || undefined}\n data-context={item().context === undefined ? undefined : String(item().context)}\n >\n <Show\n when={item().href}\n fallback={\n <button\n type=\"button\"\n class=\"k2b-navigation__control\"\n disabled={disabled()}\n aria-expanded={!item().action ? open() : undefined}\n onClick={() => (item().action ? void activate(id, item().keepOpen) : toggle())}\n >\n {content()}\n <Show when={!item().action && item().children?.length}>\n <i class={open() ? \"ti ti-chevron-down\" : \"ti ti-chevron-right\"} aria-hidden=\"true\" />\n </Show>\n </button>\n }\n >\n {(href) => (\n <Link\n class=\"k2b-navigation__control\"\n href={href()}\n aria-current={item().active ? \"page\" : undefined}\n aria-disabled={disabled() || undefined}\n tabIndex={disabled() ? -1 : undefined}\n scroll={item().scroll}\n onNavigate={async (event) => {\n if (!(await ready())) return;\n if (item().navigation === \"enhanced\" && props.navigation.onNavigate) await props.navigation.onNavigate(event);\n else event.fallback();\n }}\n onClick={(event) => {\n if (disabled()) {\n event.preventDefault();\n return;\n }\n if (!item().action || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey)\n return;\n // Local opening can fetch before committing navigation, outside a view transition.\n event.preventDefault();\n void activate(id);\n }}\n >\n {content()}\n </Link>\n )}\n </Show>\n <Show when={(item().href || item().action) && item().children?.length}>\n <button\n type=\"button\"\n class=\"k2b-navigation__disclosure\"\n aria-label={item().label}\n aria-expanded={open()}\n disabled={disabled()}\n onClick={toggle}\n >\n <i class={open() ? \"ti ti-chevron-down\" : \"ti ti-chevron-right\"} aria-hidden=\"true\" />\n </button>\n </Show>\n {/* Keyed by id like the rows, so a button keeps its identity and focus when the model updates. */}\n <For each={(item().inlineActions ?? []).map((action) => action.id)}>\n {(actionId) => {\n const action = () => item().inlineActions?.find((entry) => entry.id === actionId);\n return (\n <Show when={action()}>\n {(current) => (\n <IconButton\n class=\"k2b-navigation__inline-action\"\n label={current().label}\n disabled={disabled() || current().disabled}\n onClick={() => void activate(actionId)}\n >\n <i class={current().icon} aria-hidden=\"true\" />\n </IconButton>\n )}\n </Show>\n );\n }}\n </For>\n <Show when={item().actions?.length}>\n <Dropdown.Root\n items={(item().actions ?? []).map((action) => ({\n label: action.label,\n icon: action.icon,\n description: action.description,\n disabled: disabled() || action.disabled,\n action: () => {\n if (action.href)\n void ready().then((allowed) => {\n if (allowed) documentNavigate(action.href!);\n });\n else void activate(action.id);\n },\n }))}\n >\n <Dropdown.Trigger iconOnly label={`${item().label}: ${workspaceMessages().rowAction}`} variant=\"ghost\">\n <i class=\"ti ti-dots\" aria-hidden=\"true\" />\n </Dropdown.Trigger>\n </Dropdown.Root>\n </Show>\n </div>\n <Show when={item().children?.length}>\n <div hidden={!open()}>\n <Rows items={item().children ?? []} disabled={disabled()} />\n </div>\n </Show>\n </li>\n }\n >\n <li class=\"k2b-navigation__section\">\n <div class=\"k2b-navigation__heading\" id={headingId}>\n {item().label}\n </div>\n <Rows items={item().children ?? []} disabled={disabled()} labelledBy={headingId} />\n </li>\n </Show>\n );\n }}\n </For>\n </ul>\n );\n return (\n <nav class=\"k2b-navigation\" aria-label={props.label}>\n <Show when={props.navigation.switcher?.()}>\n {(switcher) => <AppWorkspaceSidebarSwitcher {...switcher()} beforeSelect={props.beforeSelect} />}\n </Show>\n <Rows items={props.navigation.items()} />\n </nav>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,gBAAgB,EAAE,IAAI,QAAQ,cAAc;AACrD,SAAS,YAAY,EAAE,cAAc,EAAE,GAAG,EAAE,IAAI,QAAQ,UAAU;AAClE,SAAS,UAAU,QAAQ,mBAAmB;AAC9C,SAAS,QAAQ,QAAQ,qBAAqB;AAE9C,SAAS,2BAA2B,QAAQ,mBAAmB;AAC/D,SAAS,oBAAoB,QAAQ,sBAAsB;AAS3D;AACA,MAAM,iBAAiB,GAAI,KAAyB,IAAM,KAAK,GAAG;EAAE,IAAI,EAAE,KAAc;EAAE,YAAY,EAAE;AAAM,CAAC,GAAG;EAAE,aAAa,EAAE;AAAK,CAAE;AAE1I,eAAe,SAAS,UAAU,CAAC,KAAsB,EAAE;EACzD,MAAM,iBAAiB,GAAG,oBAAoB,CAAC,CAAC;EAChD,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,YAAY,CAA0B,CAAC,CAAC,CAAC;EACzE,MAAM,KAAK,GAAG,YAAY,CAAC,MAAM,KAAK,CAAC,YAAY,GAAG,CAAC,MAAM,KAAK;EAClE;EACA,MAAM,QAAQ,GAAG,OAAO,EAAU,EAAE,QAAQ,GAAG,KAAK,KAAK;IACvD,IAAI,QAAQ,KAAK,MAAM,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;EACtE,CAAC;EACD,MAAM,IAAI,GAAI,IAAmF,6DAC7C,IAAI,CAAC,UAAU,4CAC9D,GAAG;IAAA,IAAC,IAAI;MAAA,OAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAE,IAAI,IAAK,IAAI,CAAC,EAAE,CAAC;IAAA;IAAA,UACxC,EAAE,IAAK;MACP,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAE,KAAK,IAAK,KAAK,CAAC,EAAE,KAAK,EAAE,CAAE;MAC/D,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,QAAQ;MACvD,MAAM,SAAS,GAAG,0BAA0B,cAAc,CAAC,CAAC,EAAE;MAC9D;MACA,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,CAAC,CAAC,QAAQ,IAAI,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,eAAe,IAAI,IAAI;MACtF,MAAM,MAAM,GAAG,MAAM;QACnB,IAAI,IAAI,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,EAAE,KAAK,CAAC,UAAU,CAAC,gBAAgB,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAC/E,WAAW,CAAE,OAAO,KAAM;UAAE,GAAG,OAAO;UAAE,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC;QAAE,CAAC,CAAC,CAAC;MAChE,CAAC;MACD,MAAM,OAAO,GAAG,yBAEX,IAAI;QAAA,IAAC,IAAI;UAAA,OAAE,IAAI,CAAC,CAAC,CAAC,IAAI;QAAA;QAAA;UAAA;YAAA;cAAA,OACX,IAAI,CAAC,CAAC,CAAC,IAAI;YAAA;UAAA,SAAM,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;QAAA;MAAA,4BAGvD,IAAI,CAAC,CAAC,CAAC,KAAK,8BAClB,IAAI;QAAA,IAAC,IAAI;UAAA,OAAE,IAAI,CAAC,CAAC,CAAC,WAAW;QAAA;QAAA;UAAA,+BACpB,IAAI,CAAC,CAAC,CAAC,WAAW;QAAA;MAAA,wBAG7B,IAAI;QAAA,IAAC,IAAI;UAAA,OAAE,IAAI,CAAC,CAAC,CAAC,KAAK;QAAA;QAAA;UAAA,uEAC2C,IAAI,CAAC,CAAC,CAAC,KAAK;QAAA;MAAA,sBAE9E,IAAI;QAAA,IAAC,IAAI;UAAA,OAAE,IAAI,CAAC,CAAC,CAAC,KAAK,KAAK,SAAS;QAAA;QAAA;UAAA,+BACC,IAAI,CAAC,CAAC,CAAC,KAAK;QAAA;MAAA,sBAGlD,IAAI;QAAA,IAAC,IAAI;UAAA,OAAE,IAAI,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS;QAAA;QAAA;UAAA,2DACW,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,mDAAS,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,KAAK,4CAC7F,IAAI;YAAA,IAAC,IAAI;cAAA,OAAE,IAAI,CAAC,CAAC,CAAC,MAAM;YAAA;YAAA,UACrB,MAAM,qDAEM,MAAM,CAAC,CAAC,CAAC,IAAI,0CACI,MAAM,CAAC,CAAC,CAAC,KAAK;UAE5C;QAAA;MAAA,GAKV;MACD,yBACG,IAAI;QAAA,IACH,IAAI;UAAA,OAAE,IAAI,CAAC,CAAC,CAAC,OAAO;QAAA;QAAA,IACpB,QAAQ;UAAA,8DAIW,IAAI,CAAC,CAAC,CAAC,MAAM,IAAI,SAAS,iDACzB,IAAI,CAAC,CAAC,CAAC,OAAO,KAAK,SAAS,YAAG,SAAS,mBAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,4CAE9E,IAAI;YAAA,IACH,IAAI;cAAA,OAAE,IAAI,CAAC,CAAC,CAAC,IAAI;YAAA;YAAA,IACjB,QAAQ;cAAA,kDAIM,QAAQ,CAAC,CAAC,0CACL,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,YAAG,IAAI,CAAC,CAAC,mBAAG,SAAS,0BAGjD,OAAO,CAAC,CAAC,8BACT,IAAI;gBAAA,IAAC,IAAI;kBAAA,OAAE,gBAAC,IAAI,CAAC,CAAC,CAAC,MAAM,OAAI,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,MAAM;gBAAA;gBAAA;kBAAA,8CACzC,IAAI,CAAC,CAAC,GAAG,oBAAoB,GAAG,qBAAqB;gBAAA;cAAA;YAAA;YAAA,UAKnE,IAAI,sBACH,IAAI;cAAA;cAAA,IAEH,IAAI;gBAAA,OAAE,IAAI,CAAC,CAAC;cAAA;cAAA;gBAAA,OACE,IAAI,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,GAAG,SAAS;cAAA;cAAA;gBAAA,OACjC,QAAQ,CAAC,CAAC,IAAI,SAAS;cAAA;cAAA,IACtC,QAAQ;gBAAA,OAAE,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,SAAS;cAAA;cAAA,IACrC,MAAM;gBAAA,OAAE,IAAI,CAAC,CAAC,CAAC,MAAM;cAAA;cACrB,UAAU,EAAE,MAAO,KAAK,IAAK;gBAC3B,IAAI,EAAE,MAAM,KAAK,CAAC,CAAC,CAAC,EAAE;gBACtB,IAAI,IAAI,CAAC,CAAC,CAAC,UAAU,KAAK,UAAU,IAAI,KAAK,CAAC,UAAU,CAAC,UAAU,EAAE,MAAM,KAAK,CAAC,UAAU,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,KACzG,KAAK,CAAC,QAAQ,CAAC,CAAC;cACvB,CAAC;cACD,OAAO,EAAG,KAAK,IAAK;gBAClB,IAAI,QAAQ,CAAC,CAAC,EAAE;kBACd,KAAK,CAAC,cAAc,CAAC,CAAC;kBACtB;gBACF;gBACA,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,MAAM,EAC1G;gBACF;gBACA,KAAK,CAAC,cAAc,CAAC,CAAC;gBACtB,KAAK,QAAQ,CAAC,EAAE,CAAC;cACnB,CAAC;cAAA;gBAAA,OAEA,OAAO,CAAC,CAAC;cAAA;YAAA;UAEb,gCAEF,IAAI;YAAA,IAAC,IAAI;cAAA,OAAE,gBAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,QAAK,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,MAAM;YAAA;YAAA;cAAA,4DAIrD,IAAI,CAAC,CAAC,CAAC,KAAK,2DACT,IAAI,CAAC,CAAC,4CACX,QAAQ,CAAC,CAAC,iCAGV,IAAI,CAAC,CAAC,GAAG,oBAAoB,GAAG,qBAAqB;YAAA;UAAA,gCAIlE,GAAG;YAAA,IAAC,IAAI;cAAA,OAAE,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,IAAI,EAAE,EAAE,GAAG,CAAE,MAAM,IAAK,MAAM,CAAC,EAAE,CAAC;YAAA;YAAA,UAC9D,QAAQ,IAAK;cACb,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,CAAC,CAAC,aAAa,EAAE,IAAI,CAAE,KAAK,IAAK,KAAK,CAAC,EAAE,KAAK,QAAQ,CAAC;cACjF,yBACG,IAAI;gBAAA,IAAC,IAAI;kBAAA,OAAE,MAAM,CAAC,CAAC;gBAAA;gBAAA,UAChB,OAAO,sBACN,UAAU;kBAAA;kBAAA,IAET,KAAK;oBAAA,OAAE,OAAO,CAAC,CAAC,CAAC,KAAK;kBAAA;kBAAA,IACtB,QAAQ;oBAAA,OAAE,QAAQ,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,QAAQ;kBAAA;kBAC1C,OAAO,EAAE,MAAM,KAAK,QAAQ,CAAC,QAAQ,CAAC;kBAAA;oBAAA,uDAE5B,OAAO,CAAC,CAAC,CAAC,IAAI;kBAAA;gBAAA;cAE3B;YAGP;UAAC,gCAEF,IAAI;YAAA,IAAC,IAAI;cAAA,OAAE,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,MAAM;YAAA;YAAA;cAAA,yBAC/B,QAAQ,CAAC,IAAI;gBAAA,IACZ,KAAK;kBAAA,OAAE,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,EAAE,GAAG,CAAE,MAAM,KAAM;oBAC7C,KAAK,EAAE,MAAM,CAAC,KAAK;oBACnB,IAAI,EAAE,MAAM,CAAC,IAAI;oBACjB,WAAW,EAAE,MAAM,CAAC,WAAW;oBAC/B,QAAQ,EAAE,QAAQ,CAAC,CAAC,IAAI,MAAM,CAAC,QAAQ;oBACvC,MAAM,EAAE,MAAM;sBACZ,IAAI,MAAM,CAAC,IAAI,EACb,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI,CAAE,OAAO,IAAK;wBAC7B,IAAI,OAAO,EAAE,gBAAgB,CAAC,MAAM,CAAC,IAAK,CAAC;sBAC7C,CAAC,CAAC,CAAC,KACA,KAAK,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;oBAC/B;kBACF,CAAC,CAAC,CAAC;gBAAA;gBAAA;kBAAA,yBAEF,QAAQ,CAAC,OAAO;oBAAC,QAAQ;oBAAA,IAAC,KAAK;sBAAA,OAAE,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,KAAK,iBAAiB,CAAC,CAAC,CAAC,SAAS,EAAE;oBAAA;oBAAE,OAAO;oBAAA;sBAAA;oBAAA;kBAAA;gBAAA;cAAA;YAAA;UAAA,gCAMnG,IAAI;YAAA,IAAC,IAAI;cAAA,OAAE,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,MAAM;YAAA;YAAA;cAAA,gDACpB,CAAC,IAAI,CAAC,CAAC,oCACjB,IAAI;gBAAA,IAAC,KAAK;kBAAA,OAAE,IAAI,CAAC,CAAC,CAAC,QAAQ,IAAI,EAAE;gBAAA;gBAAA,IAAE,QAAQ;kBAAA,OAAE,QAAQ,CAAC,CAAC;gBAAA;cAAA;YAAA;UAAA;QAAA;QAAA;UAAA,oDAOrB,SAAS,0BAC/C,IAAI,CAAC,CAAC,CAAC,KAAK,8BAEd,IAAI;YAAA,IAAC,KAAK;cAAA,OAAE,IAAI,CAAC,CAAC,CAAC,QAAQ,IAAI,EAAE;YAAA;YAAA,IAAE,QAAQ;cAAA,OAAE,QAAQ,CAAC,CAAC;YAAA;YAAE,UAAU,EAAE;UAAS;QAAA;MAAA;IAIvF;EAAC,IAGN;EACD,6DAC0C,KAAK,CAAC,KAAK,4CAChD,IAAI;IAAA,IAAC,IAAI;MAAA,OAAE,KAAK,CAAC,UAAU,CAAC,QAAQ,GAAG,CAAC;IAAA;IAAA,UACrC,QAAQ,sBAAM,2BAA2B,eAAK,QAAQ;MAAA,IAAI,YAAY;QAAA,OAAE,KAAK,CAAC,YAAY;MAAA;IAAA;EAAI,gCAEjG,IAAI;IAAA,IAAC,KAAK;MAAA,OAAE,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IAAA;EAAA;AAG3C","ignoreList":[]}
|
|
@@ -207,8 +207,13 @@ export function PageTitle(props) {
|
|
|
207
207
|
* Titles inside islands render in the browser anyway. Returns the disposer.
|
|
208
208
|
*/
|
|
209
209
|
export const followPageTrail = (root = document) => {
|
|
210
|
-
const disposers =
|
|
210
|
+
const disposers = new Map();
|
|
211
211
|
const upgrade = () => {
|
|
212
|
+
for (const [place, dispose] of disposers) {
|
|
213
|
+
if (place.isConnected) continue;
|
|
214
|
+
dispose();
|
|
215
|
+
disposers.delete(place);
|
|
216
|
+
}
|
|
212
217
|
const trail = readPageTrail();
|
|
213
218
|
for (const element of root.querySelectorAll(".k2b-page-title[data-k2b-server]")) {
|
|
214
219
|
const row = element.parentElement;
|
|
@@ -229,7 +234,7 @@ export const followPageTrail = (root = document) => {
|
|
|
229
234
|
const place = document.createTextNode("");
|
|
230
235
|
row.insertBefore(place, element);
|
|
231
236
|
element.remove();
|
|
232
|
-
disposers.
|
|
237
|
+
disposers.set(place, createRoot(dispose => {
|
|
233
238
|
const live = usePageTrail();
|
|
234
239
|
insert(row, () => _$createComponent(Show, {
|
|
235
240
|
get when() {
|
|
@@ -265,7 +270,8 @@ export const followPageTrail = (root = document) => {
|
|
|
265
270
|
window.addEventListener(PAGE_TRAIL_EVENT, upgrade);
|
|
266
271
|
return () => {
|
|
267
272
|
window.removeEventListener(PAGE_TRAIL_EVENT, upgrade);
|
|
268
|
-
for (const dispose of disposers.
|
|
273
|
+
for (const dispose of disposers.values()) dispose();
|
|
274
|
+
disposers.clear();
|
|
269
275
|
};
|
|
270
276
|
};
|
|
271
277
|
//# sourceMappingURL=PageTitle.js.map
|