@k2b/ui 0.47.0 → 0.49.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/dist/browser/actions/CopyButton.js +26 -18
  2. package/dist/browser/actions/CopyButton.js.map +1 -1
  3. package/dist/browser/chat/ChatComposer.js +244 -193
  4. package/dist/browser/chat/ChatComposer.js.map +1 -1
  5. package/dist/browser/chat/chat-messages.js +6 -0
  6. package/dist/browser/chat/chat-messages.js.map +1 -1
  7. package/dist/browser/chat/types.js.map +1 -1
  8. package/dist/browser/content/Calendar.js +40 -5
  9. package/dist/browser/content/Calendar.js.map +1 -1
  10. package/dist/browser/content/calendar-event-detail.js +328 -0
  11. package/dist/browser/content/calendar-event-detail.js.map +1 -0
  12. package/dist/browser/content/calendar-messages.js +34 -2
  13. package/dist/browser/content/calendar-messages.js.map +1 -1
  14. package/dist/browser/content/calendar-shared.js +189 -82
  15. package/dist/browser/content/calendar-shared.js.map +1 -1
  16. package/dist/browser/content/calendar-time-view.js +101 -96
  17. package/dist/browser/content/calendar-time-view.js.map +1 -1
  18. package/dist/browser/content/index.js.map +1 -1
  19. package/dist/browser/feedback/prompt-confirm.js +7 -4
  20. package/dist/browser/feedback/prompt-confirm.js.map +1 -1
  21. package/dist/browser/feedback/prompts.js +3 -3
  22. package/dist/browser/feedback/prompts.js.map +1 -1
  23. package/dist/browser/inputs/NumberInput.js +17 -5
  24. package/dist/browser/inputs/NumberInput.js.map +1 -1
  25. package/dist/browser/inputs/dictation/Dictation.js +114 -108
  26. package/dist/browser/inputs/dictation/Dictation.js.map +1 -1
  27. package/dist/browser/inputs/dictation/dictation-messages.js +2 -0
  28. package/dist/browser/inputs/dictation/dictation-messages.js.map +1 -1
  29. package/dist/browser/layout/AppWorkspace.js +574 -522
  30. package/dist/browser/layout/AppWorkspace.js.map +1 -1
  31. package/dist/browser/layout/MobileShell.js +26 -0
  32. package/dist/browser/layout/MobileShell.js.map +1 -1
  33. package/dist/browser/layout/index.js +1 -0
  34. package/dist/browser/layout/index.js.map +1 -1
  35. package/dist/browser/layout/sheet-handle.js +155 -0
  36. package/dist/browser/layout/sheet-handle.js.map +1 -0
  37. package/dist/browser/surfaces/NoticeCard.js +48 -29
  38. package/dist/browser/surfaces/NoticeCard.js.map +1 -1
  39. package/dist/ssr/actions/CopyButton.js +13 -8
  40. package/dist/ssr/actions/CopyButton.js.map +1 -1
  41. package/dist/ssr/chat/ChatComposer.js +53 -30
  42. package/dist/ssr/chat/ChatComposer.js.map +1 -1
  43. package/dist/ssr/chat/chat-messages.js +6 -0
  44. package/dist/ssr/chat/chat-messages.js.map +1 -1
  45. package/dist/ssr/chat/types.js.map +1 -1
  46. package/dist/ssr/content/Calendar.js +36 -4
  47. package/dist/ssr/content/Calendar.js.map +1 -1
  48. package/dist/ssr/content/calendar-event-detail.js +212 -0
  49. package/dist/ssr/content/calendar-event-detail.js.map +1 -0
  50. package/dist/ssr/content/calendar-messages.js +34 -2
  51. package/dist/ssr/content/calendar-messages.js.map +1 -1
  52. package/dist/ssr/content/calendar-shared.js +117 -36
  53. package/dist/ssr/content/calendar-shared.js.map +1 -1
  54. package/dist/ssr/content/calendar-time-view.js +6 -4
  55. package/dist/ssr/content/calendar-time-view.js.map +1 -1
  56. package/dist/ssr/content/index.js.map +1 -1
  57. package/dist/ssr/feedback/prompt-confirm.js +7 -4
  58. package/dist/ssr/feedback/prompt-confirm.js.map +1 -1
  59. package/dist/ssr/feedback/prompts.js +3 -3
  60. package/dist/ssr/feedback/prompts.js.map +1 -1
  61. package/dist/ssr/inputs/NumberInput.js +17 -5
  62. package/dist/ssr/inputs/NumberInput.js.map +1 -1
  63. package/dist/ssr/inputs/dictation/Dictation.js +3 -1
  64. package/dist/ssr/inputs/dictation/Dictation.js.map +1 -1
  65. package/dist/ssr/inputs/dictation/dictation-messages.js +2 -0
  66. package/dist/ssr/inputs/dictation/dictation-messages.js.map +1 -1
  67. package/dist/ssr/layout/AppWorkspace.js +152 -114
  68. package/dist/ssr/layout/AppWorkspace.js.map +1 -1
  69. package/dist/ssr/layout/MobileShell.js +26 -0
  70. package/dist/ssr/layout/MobileShell.js.map +1 -1
  71. package/dist/ssr/layout/index.js +1 -0
  72. package/dist/ssr/layout/index.js.map +1 -1
  73. package/dist/ssr/layout/sheet-handle.js +155 -0
  74. package/dist/ssr/layout/sheet-handle.js.map +1 -0
  75. package/dist/ssr/surfaces/NoticeCard.js +25 -10
  76. package/dist/ssr/surfaces/NoticeCard.js.map +1 -1
  77. package/dist/styles.css +1 -1
  78. package/dist/types/chat/chat-messages.d.ts +3 -0
  79. package/dist/types/chat/types.d.ts +5 -0
  80. package/dist/types/content/Calendar.d.ts +29 -5
  81. package/dist/types/content/calendar-event-detail.d.ts +21 -0
  82. package/dist/types/content/calendar-messages.d.ts +16 -0
  83. package/dist/types/content/calendar-shared.d.ts +16 -1
  84. package/dist/types/content/calendar-time-view.d.ts +1 -1
  85. package/dist/types/content/index.d.ts +1 -1
  86. package/dist/types/feedback/prompt-confirm.d.ts +3 -1
  87. package/dist/types/feedback/prompts.d.ts +2 -2
  88. package/dist/types/inputs/NumberInput.d.ts +1 -1
  89. package/dist/types/inputs/dictation/dictation-messages.d.ts +1 -0
  90. package/dist/types/layout/AppWorkspace.d.ts +16 -1
  91. package/dist/types/layout/MobileShell.d.ts +5 -0
  92. package/dist/types/layout/index.d.ts +2 -1
  93. package/dist/types/layout/sheet-handle.d.ts +21 -0
  94. package/dist/types/surfaces/NoticeCard.d.ts +5 -2
  95. package/package.json +1 -1
@@ -39,6 +39,23 @@ const MODAL_ATTRIBUTE = "data-k2b-mobile-shell-modal";
39
39
  const FOOTER_HEIGHT = "--k2b-mobile-shell-footer-height";
40
40
  /** How much of the scroll area a persistent toast covers; local to the shell. */
41
41
  const TOAST_INSET = "--k2b-mobile-shell-toast-inset";
42
+ /** How far the on-screen keyboard reaches into the shell from the bottom edge; local to the shell. */
43
+ const KEYBOARD_INSET = "--k2b-mobile-shell-keyboard";
44
+ /** On the shell while the on-screen keyboard is up. */
45
+ const KEYBOARD_ATTRIBUTE = "data-k2b-keyboard";
46
+ /** Below this height a change of the visual viewport is browser chrome, such as a hiding address bar, not a keyboard. */
47
+ const KEYBOARD_MIN = 120;
48
+
49
+ /**
50
+ * The height the on-screen keyboard covers at the bottom of the layout viewport, from the visual viewport; zero
51
+ * without a keyboard or without `visualViewport`.
52
+ */
53
+ export const keyboardInset = view => {
54
+ const visual = view.visualViewport;
55
+ if (!visual) return 0;
56
+ const covered = Math.round(view.innerHeight - visual.height - visual.offsetTop);
57
+ return covered >= KEYBOARD_MIN ? covered : 0;
58
+ };
42
59
 
43
60
  /**
44
61
  * The visible part of the toast rail when it holds a toast without a timer (`duration: 0`, running progress, or a
@@ -213,6 +230,10 @@ export function observeMobileShell(root) {
213
230
  const footer = Math.max(0, rootBottom - main.getBoundingClientRect().bottom, owned);
214
231
  document.body.style.setProperty(FOOTER_HEIGHT, `${footer}px`);
215
232
  root.style.setProperty(TOAST_INSET, `${persistentToastInset(body ?? main)}px`);
233
+ // Content that owns the bottom edge stands above the keyboard, and the footer under it steps aside.
234
+ const keyboard = keyboardInset(window);
235
+ root.style.setProperty(KEYBOARD_INSET, `${keyboard}px`);
236
+ root.toggleAttribute(KEYBOARD_ATTRIBUTE, keyboard > 0);
216
237
  // A modal dialog takes the bottom edge back for its footer; the toast rules read this, not `html:has(dialog:modal)`.
217
238
  documentRoot.toggleAttribute(MODAL_ATTRIBUTE, document.querySelector("dialog:modal") !== null);
218
239
  };
@@ -234,7 +255,12 @@ export function observeMobileShell(root) {
234
255
  attributeFilter: ["data-state", "data-closing", "data-persistent", "open"]
235
256
  });
236
257
  document.addEventListener("transitionend", schedule, true);
258
+ window.visualViewport?.addEventListener("resize", schedule);
259
+ window.visualViewport?.addEventListener("scroll", schedule);
237
260
  return () => {
261
+ window.visualViewport?.removeEventListener("resize", schedule);
262
+ window.visualViewport?.removeEventListener("scroll", schedule);
263
+ root.removeAttribute(KEYBOARD_ATTRIBUTE);
238
264
  if (frame) cancelAnimationFrame(frame);
239
265
  resize.disconnect();
240
266
  mutations.disconnect();
@@ -1 +1 @@
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 /**\n * The content is a screen of its own, such as an open chat on a phone: the footer steps aside, so the content\n * reaches the bottom edge and pads its safe area itself. Content that opens or leaves such a screen in place calls\n * `MobileShell.setScreen`.\n */\n screen?: 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/**\n * On the document element while a shell is the page: `\"sidebar\"` when it shows its sidebar, otherwise empty. A host\n * that renders the shell on the server writes it into its `<html>` too, so the first paint already has it.\n */\nconst SHELL_ATTRIBUTE = \"data-k2b-mobile-shell\";\n/** On the document element while a shell is mounted and a modal dialog is open. */\nconst MODAL_ATTRIBUTE = \"data-k2b-mobile-shell-modal\";\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/** On the root while its content is a screen of its own; the footer steps aside. */\nconst SCREEN = \"data-k2b-screen\";\n\n/**\n * Marks the shell around `from` as showing a screen of its own, or not, after the first paint; the server renders\n * the first state with the `screen` prop. Does nothing outside a shell.\n */\nconst setMobileShellScreen = (from: Element, screen: boolean): void => {\n const root = from.closest(\".k2b-mobile-shell\");\n if (!root) return;\n if (screen) root.setAttribute(SCREEN, \"\");\n else root.removeAttribute(SCREEN);\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 // The document says that a shell is the page, for the controls and toasts portalled outside it. An attribute, not\n // `html:has(.k2b-mobile-shell)`: a `:has()` on the document restyles the whole page on every change inside it.\n const documentRoot = root.ownerDocument.documentElement;\n const previousShell = documentRoot.getAttribute(SHELL_ATTRIBUTE);\n documentRoot.setAttribute(SHELL_ATTRIBUTE, root.querySelector(\":scope > .k2b-mobile-shell__sidebar\") ? \"sidebar\" : \"\");\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 let owner: HTMLElement | null = null;\n let resize: ResizeObserver | undefined;\n const watchOwner = () => {\n const next = root.querySelector<HTMLElement>(\"[data-k2b-shell-bottom]\");\n if (next === owner) return;\n if (owner) resize?.unobserve(owner);\n owner = next;\n if (owner) resize?.observe(owner);\n };\n const measure = () => {\n frame = 0;\n watchOwner();\n const rootBottom = root.getBoundingClientRect().bottom;\n // Content that owns the bottom edge, such as a chat's composer, counts as the footer, so toasts stay above it.\n const owned = owner?.getClientRects().length ? rootBottom - owner.getBoundingClientRect().top : 0;\n const footer = Math.max(0, rootBottom - main.getBoundingClientRect().bottom, owned);\n document.body.style.setProperty(FOOTER_HEIGHT, `${footer}px`);\n root.style.setProperty(TOAST_INSET, `${persistentToastInset(body ?? main)}px`);\n // A modal dialog takes the bottom edge back for its footer; the toast rules read this, not `html:has(dialog:modal)`.\n documentRoot.toggleAttribute(MODAL_ATTRIBUTE, document.querySelector(\"dialog:modal\") !== null);\n };\n const schedule = () => {\n if (!frame) frame = requestAnimationFrame(measure);\n };\n // The footer can appear, disappear, or change height; the main area takes whatever it leaves. Content that owns the\n // bottom edge, such as a composer, grows and shrinks on its own.\n resize = new ResizeObserver(schedule);\n resize.observe(root);\n resize.observe(main);\n measure();\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 documentRoot.removeAttribute(MODAL_ATTRIBUTE);\n if (previousShell === null) documentRoot.removeAttribute(SHELL_ATTRIBUTE);\n else documentRoot.setAttribute(SHELL_ATTRIBUTE, previousShell);\n stopLinkTaps();\n stopScrollFades();\n };\n}\n\nfunction MobileShellRoot(props: MobileShellProps): JSX.Element {\n let root!: HTMLDivElement;\n\n onMount(() => onCleanup(observeMobileShell(root)));\n return (\n <>\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 data-k2b-screen={props.screen ? \"\" : 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 {/* No pinch zoom on the whole page, portalled dialogs and menus included, also before hydration. iOS ignores\n `user-scalable=no`; it honours touch-action. It lives here, not behind `html:has(.k2b-mobile-shell) *`, which\n would restyle the document on every `:has()` change. Zero specificity, so a component's own touch-action,\n such as a drag handle's `none`, still wins. */}\n <style innerHTML=\":where(html *) { touch-action: pan-x pan-y; }\" />\n </>\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 /**\n * A quiet count after the label, such as open tasks: a number (0 shows nothing) or an element that renders one. The\n * item's `badge`, which calls for attention, takes its place.\n */\n count?: number | JSX.Element;\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.badge ?? props.item.count}>{(mark) => <span class=\"k2b-mobile-shell__sidebar-count\">{mark()}</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, {\n Header: MobileShellHeader,\n Sidebar: MobileShellSidebar,\n setScreen: setMobileShellScreen,\n});\n\nexport default MobileShell;\n"],"mappings":"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","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 /**\n * The content is a screen of its own, such as an open chat on a phone: the footer steps aside, so the content\n * reaches the bottom edge and pads its safe area itself. Content that opens or leaves such a screen in place calls\n * `MobileShell.setScreen`.\n */\n screen?: 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/**\n * On the document element while a shell is the page: `\"sidebar\"` when it shows its sidebar, otherwise empty. A host\n * that renders the shell on the server writes it into its `<html>` too, so the first paint already has it.\n */\nconst SHELL_ATTRIBUTE = \"data-k2b-mobile-shell\";\n/** On the document element while a shell is mounted and a modal dialog is open. */\nconst MODAL_ATTRIBUTE = \"data-k2b-mobile-shell-modal\";\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/** How far the on-screen keyboard reaches into the shell from the bottom edge; local to the shell. */\nconst KEYBOARD_INSET = \"--k2b-mobile-shell-keyboard\";\n/** On the shell while the on-screen keyboard is up. */\nconst KEYBOARD_ATTRIBUTE = \"data-k2b-keyboard\";\n/** Below this height a change of the visual viewport is browser chrome, such as a hiding address bar, not a keyboard. */\nconst KEYBOARD_MIN = 120;\n\n/**\n * The height the on-screen keyboard covers at the bottom of the layout viewport, from the visual viewport; zero\n * without a keyboard or without `visualViewport`.\n */\nexport const keyboardInset = (view: Pick<Window, \"innerHeight\" | \"visualViewport\">): number => {\n const visual = view.visualViewport;\n if (!visual) return 0;\n const covered = Math.round(view.innerHeight - visual.height - visual.offsetTop);\n return covered >= KEYBOARD_MIN ? covered : 0;\n};\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/** On the root while its content is a screen of its own; the footer steps aside. */\nconst SCREEN = \"data-k2b-screen\";\n\n/**\n * Marks the shell around `from` as showing a screen of its own, or not, after the first paint; the server renders\n * the first state with the `screen` prop. Does nothing outside a shell.\n */\nconst setMobileShellScreen = (from: Element, screen: boolean): void => {\n const root = from.closest(\".k2b-mobile-shell\");\n if (!root) return;\n if (screen) root.setAttribute(SCREEN, \"\");\n else root.removeAttribute(SCREEN);\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 // The document says that a shell is the page, for the controls and toasts portalled outside it. An attribute, not\n // `html:has(.k2b-mobile-shell)`: a `:has()` on the document restyles the whole page on every change inside it.\n const documentRoot = root.ownerDocument.documentElement;\n const previousShell = documentRoot.getAttribute(SHELL_ATTRIBUTE);\n documentRoot.setAttribute(SHELL_ATTRIBUTE, root.querySelector(\":scope > .k2b-mobile-shell__sidebar\") ? \"sidebar\" : \"\");\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 let owner: HTMLElement | null = null;\n let resize: ResizeObserver | undefined;\n const watchOwner = () => {\n const next = root.querySelector<HTMLElement>(\"[data-k2b-shell-bottom]\");\n if (next === owner) return;\n if (owner) resize?.unobserve(owner);\n owner = next;\n if (owner) resize?.observe(owner);\n };\n const measure = () => {\n frame = 0;\n watchOwner();\n const rootBottom = root.getBoundingClientRect().bottom;\n // Content that owns the bottom edge, such as a chat's composer, counts as the footer, so toasts stay above it.\n const owned = owner?.getClientRects().length ? rootBottom - owner.getBoundingClientRect().top : 0;\n const footer = Math.max(0, rootBottom - main.getBoundingClientRect().bottom, owned);\n document.body.style.setProperty(FOOTER_HEIGHT, `${footer}px`);\n root.style.setProperty(TOAST_INSET, `${persistentToastInset(body ?? main)}px`);\n // Content that owns the bottom edge stands above the keyboard, and the footer under it steps aside.\n const keyboard = keyboardInset(window);\n root.style.setProperty(KEYBOARD_INSET, `${keyboard}px`);\n root.toggleAttribute(KEYBOARD_ATTRIBUTE, keyboard > 0);\n // A modal dialog takes the bottom edge back for its footer; the toast rules read this, not `html:has(dialog:modal)`.\n documentRoot.toggleAttribute(MODAL_ATTRIBUTE, document.querySelector(\"dialog:modal\") !== null);\n };\n const schedule = () => {\n if (!frame) frame = requestAnimationFrame(measure);\n };\n // The footer can appear, disappear, or change height; the main area takes whatever it leaves. Content that owns the\n // bottom edge, such as a composer, grows and shrinks on its own.\n resize = new ResizeObserver(schedule);\n resize.observe(root);\n resize.observe(main);\n measure();\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 window.visualViewport?.addEventListener(\"resize\", schedule);\n window.visualViewport?.addEventListener(\"scroll\", schedule);\n return () => {\n window.visualViewport?.removeEventListener(\"resize\", schedule);\n window.visualViewport?.removeEventListener(\"scroll\", schedule);\n root.removeAttribute(KEYBOARD_ATTRIBUTE);\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 documentRoot.removeAttribute(MODAL_ATTRIBUTE);\n if (previousShell === null) documentRoot.removeAttribute(SHELL_ATTRIBUTE);\n else documentRoot.setAttribute(SHELL_ATTRIBUTE, previousShell);\n stopLinkTaps();\n stopScrollFades();\n };\n}\n\nfunction MobileShellRoot(props: MobileShellProps): JSX.Element {\n let root!: HTMLDivElement;\n\n onMount(() => onCleanup(observeMobileShell(root)));\n return (\n <>\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 data-k2b-screen={props.screen ? \"\" : 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 {/* No pinch zoom on the whole page, portalled dialogs and menus included, also before hydration. iOS ignores\n `user-scalable=no`; it honours touch-action. It lives here, not behind `html:has(.k2b-mobile-shell) *`, which\n would restyle the document on every `:has()` change. Zero specificity, so a component's own touch-action,\n such as a drag handle's `none`, still wins. */}\n <style innerHTML=\":where(html *) { touch-action: pan-x pan-y; }\" />\n </>\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 /**\n * A quiet count after the label, such as open tasks: a number (0 shows nothing) or an element that renders one. The\n * item's `badge`, which calls for attention, takes its place.\n */\n count?: number | JSX.Element;\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.badge ?? props.item.count}>{(mark) => <span class=\"k2b-mobile-shell__sidebar-count\">{mark()}</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, {\n Header: MobileShellHeader,\n Sidebar: MobileShellSidebar,\n setScreen: setMobileShellScreen,\n});\n\nexport default MobileShell;\n"],"mappings":"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","ignoreList":[]}
@@ -30,6 +30,7 @@ export { default as SettingsCollection } from "./SettingsCollection";
30
30
  export { default as SettingsModal } from "./SettingsModal";
31
31
  export { APP_WORKSPACE_SWITCHER_SEARCH_FROM } from "./SidebarSwitcher";
32
32
  export { measureScrollFade } from "./scroll-fade";
33
+ export { attachSheetHandle } from "./sheet-handle";
33
34
  export { default as TabBar } from "./TabBar";
34
35
  export { TableOfContents } from "./TableOfContents";
35
36
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["layout/index.ts"],"sourcesContent":["export { AnchoredPopover, type AnchoredPopoverProps } from \"./AnchoredPopover\";\nexport type {\n AppOverviewCardsProps,\n AppOverviewEmptyStateProps,\n AppOverviewPanelProps,\n AppOverviewProps,\n} from \"./AppOverview\";\nexport { default as AppOverview } from \"./AppOverview\";\nexport type {\n AppWorkspaceBottomDrawerHeight,\n AppWorkspaceBottomDrawerProps,\n AppWorkspaceContentProps,\n AppWorkspaceDetailProps,\n AppWorkspaceDetailWidth,\n AppWorkspaceHeadProps,\n AppWorkspaceMainPaneProps,\n AppWorkspaceMainProps,\n AppWorkspaceNavTreeItemProps,\n AppWorkspaceNavTreeMove,\n AppWorkspaceNavTreeProps,\n AppWorkspaceProps,\n AppWorkspaceSidebarAccessoryVisibility,\n AppWorkspaceSidebarBodyProps,\n AppWorkspaceSidebarIconActionProps,\n AppWorkspaceSidebarIconActionTone,\n AppWorkspaceSidebarIconGridProps,\n AppWorkspaceSidebarItemActionProps,\n AppWorkspaceSidebarItemActionsProps,\n AppWorkspaceSidebarItemIconProps,\n AppWorkspaceSidebarItemLabelProps,\n AppWorkspaceSidebarItemMetaProps,\n AppWorkspaceSidebarItemProps,\n AppWorkspaceSidebarItemStatusProps,\n AppWorkspaceSidebarItemTone,\n AppWorkspaceSidebarProps,\n AppWorkspaceSidebarSectionProps,\n AppWorkspaceSidebarVisibility,\n AppWorkspaceWidthShare,\n} from \"./AppWorkspace\";\nexport { appWorkspaceDetailElementId, default as AppWorkspace } from \"./AppWorkspace\";\nexport { AppWorkspaceSidebarItemStatus } from \"./AppWorkspaceSidebarItemStatus\";\nexport { watchAppHostWidth } from \"./app-host-width\";\nexport type { AppWorkspaceControllerOptions } from \"./app-workspace-controller\";\nexport { installAppWorkspaceController, parkWorkspaceDetailDrawers } from \"./app-workspace-controller\";\nexport type {\n AppWorkspaceLayoutState,\n AppWorkspaceResizeKind,\n} from \"./app-workspace-state\";\nexport {\n APP_WORKSPACE_DETAIL_DEFAULT,\n APP_WORKSPACE_DETAIL_MAX,\n APP_WORKSPACE_DETAIL_MIN,\n APP_WORKSPACE_DRAWER_DEFAULT,\n APP_WORKSPACE_DRAWER_MAX,\n APP_WORKSPACE_DRAWER_MIN,\n APP_WORKSPACE_MAIN_MIN,\n APP_WORKSPACE_MAIN_MIN_HEIGHT,\n APP_WORKSPACE_PANE_DEFAULT,\n APP_WORKSPACE_PANE_MAX,\n APP_WORKSPACE_PANE_MIN,\n APP_WORKSPACE_SIDEBAR_COLLAPSE_THRESHOLD,\n APP_WORKSPACE_SIDEBAR_COLLAPSED,\n APP_WORKSPACE_SIDEBAR_DEFAULT,\n APP_WORKSPACE_SIDEBAR_MAX,\n APP_WORKSPACE_SIDEBAR_MIN,\n appWorkspaceLayoutStyle,\n appWorkspacePanelVariable,\n appWorkspaceResizeLimits,\n normalizeAppWorkspaceLayoutState,\n parseAppWorkspaceLayoutState,\n resolveAppWorkspaceSidebarWidth,\n safeAppWorkspacePanelId,\n serializeAppWorkspaceLayoutState,\n shouldCollapseAppWorkspaceSidebar,\n} from \"./app-workspace-state\";\nexport { type BottomSheetProps, bottomSheetAdaptiveOptions, bottomSheetOptions, default as BottomSheet } from \"./BottomSheet\";\nexport type { DataPanelProps } from \"./DataPanel\";\nexport { DataPanel } from \"./DataPanel\";\nexport type {\n DetailPanelActionButtonProps,\n DetailPanelActionLinkProps,\n DetailPanelActionProps,\n DetailPanelActionSecondary,\n DetailPanelBodyProps,\n DetailPanelGroupProps,\n DetailPanelHeaderProps,\n DetailPanelProps,\n DetailPanelRowProps,\n DetailPanelSectionProps,\n DetailPanelSummaryProps,\n DetailPanelTone,\n} from \"./DetailPanel\";\nexport { default as DetailPanel } from \"./DetailPanel\";\nexport type {\n DetailAccessEntry,\n DetailAccessProps,\n DetailLinkItem,\n DetailLinksProps,\n DetailPresencePerson,\n DetailPresenceProps,\n DetailPresenceState,\n DetailPropertiesProps,\n DetailProperty,\n DetailTag,\n DetailTagsProps,\n} from \"./DetailSections\";\nexport { DetailAccess, DetailLinks, DetailPresence, DetailPresenceSlot, DetailProperties, DetailTags } from \"./DetailSections\";\nexport { DETAILS_ICON, DetailsToggle, type DetailsToggleProps } from \"./DetailsToggle\";\nexport type { DiscussionComposerProps, DiscussionItemProps, DiscussionListProps, DiscussionProps } from \"./Discussion\";\nexport { default as Discussion } from \"./Discussion\";\nexport type {\n FloatingWindowClose,\n FloatingWindowProps,\n OpenFloatingWindowOptions,\n} from \"./FloatingWindow\";\nexport {\n default as FloatingWindow,\n type FloatingWindowRect,\n fitFloatingWindowRect,\n openFloatingWindow,\n} from \"./FloatingWindow\";\nexport type { MobileShellHeaderProps, MobileShellProps, MobileShellSidebarItem, MobileShellSidebarProps } from \"./MobileShell\";\nexport { default as MobileShell, observeMobileShell } from \"./MobileShell\";\nexport { default as Navigation, type NavigationProps } from \"./Navigation\";\nexport {\n createNavigation,\n findNavigationItem,\n type NavigationController,\n type NavigationItem,\n type NavigationOptions,\n type NavigationStatus,\n} from \"./navigation-model\";\nexport type { PageTitleProps, PageTrailLink, PageTrailState } from \"./PageTitle\";\nexport { followPageTrail, PAGE_TRAIL_EVENT, PageTitle, PageTrailProvider, readPageTrail, setPageTrail, usePageTrail } from \"./PageTitle\";\nexport type {\n PanelDialogBodyProps,\n PanelDialogFooterProps,\n PanelDialogHeaderProps,\n PanelDialogProps,\n PanelDialogSectionProps,\n PanelDialogSurface,\n PanelDialogTabOption,\n PanelDialogTabsProps,\n} from \"./PanelDialog\";\nexport {\n confirmDiscardIfDirty,\n default as PanelDialog,\n panelDialogFixedOptions,\n panelDialogFixedPanelClass,\n panelDialogOptions,\n panelDialogPanelClass,\n panelDialogWideOptions,\n panelDialogWidePanelClass,\n panelDialogWorkspaceOptions,\n panelDialogWorkspacePanelClass,\n} from \"./PanelDialog\";\nexport type { PanelHeaderProps } from \"./PanelHeader\";\nexport { PanelHeader } from \"./PanelHeader\";\nexport type { PanesItem, PanesProps } from \"./Panes\";\nexport { default as Panes } from \"./Panes\";\nexport type { PullToRefreshProps, PullToRefreshState } from \"./PullToRefresh\";\nexport { default as PullToRefresh } from \"./PullToRefresh\";\nexport { installPageTitleController } from \"./page-title-controller\";\nexport type {\n AddPanesItemOptions,\n PanesDirection,\n PanesGroup,\n PanesIntent,\n PanesLayout,\n PanesNode,\n PanesPath,\n PanesPathSegment,\n PanesSide,\n PanesSplit,\n} from \"./panes-layout\";\nexport {\n activatePanesItem,\n addPanesItem,\n applyPanesIntent,\n createPanesLayout,\n isPanesItemVisible,\n PANES_LAYOUT_VERSION,\n parsePanesLayout,\n reconcilePanesLayout,\n removePanesItem,\n resizePanesSplit,\n} from \"./panes-layout\";\nexport { default as ResizeSeparator, type ResizeSeparatorProps } from \"./ResizeSeparator\";\nexport { attachResizeSeparator, type ResizeSeparatorOptions } from \"./resize-separator\";\nexport type { ScrollAreaProps } from \"./ScrollArea\";\nexport { default as ScrollArea } from \"./ScrollArea\";\nexport type {\n SaveStatusProps,\n SaveStatusState,\n SettingsFieldControlProps,\n SettingsFieldProps,\n SettingsFieldWidth,\n SettingsGroupActionProps,\n SettingsGroupProps,\n SettingsPageProps,\n SettingsPanelFooterProps,\n SettingsSaveBarProps,\n SettingsSectionProps,\n} from \"./Settings\";\nexport {\n readSettingsError,\n SaveStatus,\n SettingsField,\n SettingsGroup,\n SettingsPage,\n SettingsPanelFooter,\n SettingsSaveBar,\n SettingsSection,\n sameSettingValue,\n} from \"./Settings\";\nexport type {\n SettingsCollectionActionProps,\n SettingsCollectionItemActionsProps,\n SettingsCollectionItemProps,\n SettingsCollectionItemReorderProps,\n SettingsCollectionItemStatusProps,\n SettingsCollectionProps,\n} from \"./SettingsCollection\";\nexport { default as SettingsCollection } from \"./SettingsCollection\";\nexport type {\n SettingsModalFooterProps,\n SettingsModalGroupProps,\n SettingsModalProps,\n SettingsModalTabProps,\n SettingsModalTabTone,\n} from \"./SettingsModal\";\nexport { default as SettingsModal } from \"./SettingsModal\";\nexport {\n APP_WORKSPACE_SWITCHER_SEARCH_FROM,\n type AppWorkspaceSidebarSwitcherProps,\n type AppWorkspaceSwitcherAction,\n type AppWorkspaceSwitcherOption,\n} from \"./SidebarSwitcher\";\nexport { measureScrollFade } from \"./scroll-fade\";\nexport type { TabBarItem, TabBarProps } from \"./TabBar\";\nexport { default as TabBar } from \"./TabBar\";\nexport type { TableOfContentsItem, TableOfContentsProps } from \"./TableOfContents\";\nexport { TableOfContents } from \"./TableOfContents\";\n"],"mappings":"AAAA,SAAS,eAAe,QAAmC,mBAAmB;AAO9E,SAAS,OAAO,IAAI,WAAW,QAAQ,eAAe;AAgCtD,SAAS,2BAA2B,EAAE,OAAO,IAAI,YAAY,QAAQ,gBAAgB;AACrF,SAAS,6BAA6B,QAAQ,iCAAiC;AAC/E,SAAS,iBAAiB,QAAQ,kBAAkB;AAEpD,SAAS,6BAA6B,EAAE,0BAA0B,QAAQ,4BAA4B;AAKtG,SACE,4BAA4B,EAC5B,wBAAwB,EACxB,wBAAwB,EACxB,4BAA4B,EAC5B,wBAAwB,EACxB,wBAAwB,EACxB,sBAAsB,EACtB,6BAA6B,EAC7B,0BAA0B,EAC1B,sBAAsB,EACtB,sBAAsB,EACtB,wCAAwC,EACxC,+BAA+B,EAC/B,6BAA6B,EAC7B,yBAAyB,EACzB,yBAAyB,EACzB,uBAAuB,EACvB,yBAAyB,EACzB,wBAAwB,EACxB,gCAAgC,EAChC,4BAA4B,EAC5B,+BAA+B,EAC/B,uBAAuB,EACvB,gCAAgC,EAChC,iCAAiC,QAC5B,uBAAuB;AAC9B,SAAgC,0BAA0B,EAAE,kBAAkB,EAAE,OAAO,IAAI,WAAW,QAAQ,eAAe;AAE7H,SAAS,SAAS,QAAQ,aAAa;AAevC,SAAS,OAAO,IAAI,WAAW,QAAQ,eAAe;AActD,SAAS,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,UAAU,QAAQ,kBAAkB;AAC9H,SAAS,YAAY,EAAE,aAAa,QAAiC,iBAAiB;AAEtF,SAAS,OAAO,IAAI,UAAU,QAAQ,cAAc;AAMpD,SACE,OAAO,IAAI,cAAc,EAEzB,qBAAqB,EACrB,kBAAkB,QACb,kBAAkB;AAEzB,SAAS,OAAO,IAAI,WAAW,EAAE,kBAAkB,QAAQ,eAAe;AAC1E,SAAS,OAAO,IAAI,UAAU,QAA8B,cAAc;AAC1E,SACE,gBAAgB,EAChB,kBAAkB,QAKb,oBAAoB;AAE3B,SAAS,eAAe,EAAE,gBAAgB,EAAE,SAAS,EAAE,iBAAiB,EAAE,aAAa,EAAE,YAAY,EAAE,YAAY,QAAQ,aAAa;AAWxI,SACE,qBAAqB,EACrB,OAAO,IAAI,WAAW,EACtB,uBAAuB,EACvB,0BAA0B,EAC1B,kBAAkB,EAClB,qBAAqB,EACrB,sBAAsB,EACtB,yBAAyB,EACzB,2BAA2B,EAC3B,8BAA8B,QACzB,eAAe;AAEtB,SAAS,WAAW,QAAQ,eAAe;AAE3C,SAAS,OAAO,IAAI,KAAK,QAAQ,SAAS;AAE1C,SAAS,OAAO,IAAI,aAAa,QAAQ,iBAAiB;AAC1D,SAAS,0BAA0B,QAAQ,yBAAyB;AAapE,SACE,iBAAiB,EACjB,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,gBAAgB,EAChB,oBAAoB,EACpB,eAAe,EACf,gBAAgB,QACX,gBAAgB;AACvB,SAAS,OAAO,IAAI,eAAe,QAAmC,mBAAmB;AACzF,SAAS,qBAAqB,QAAqC,oBAAoB;AAEvF,SAAS,OAAO,IAAI,UAAU,QAAQ,cAAc;AAcpD,SACE,iBAAiB,EACjB,UAAU,EACV,aAAa,EACb,aAAa,EACb,YAAY,EACZ,mBAAmB,EACnB,eAAe,EACf,eAAe,EACf,gBAAgB,QACX,YAAY;AASnB,SAAS,OAAO,IAAI,kBAAkB,QAAQ,sBAAsB;AAQpE,SAAS,OAAO,IAAI,aAAa,QAAQ,iBAAiB;AAC1D,SACE,kCAAkC,QAI7B,mBAAmB;AAC1B,SAAS,iBAAiB,QAAQ,eAAe;AAEjD,SAAS,OAAO,IAAI,MAAM,QAAQ,UAAU;AAE5C,SAAS,eAAe,QAAQ,mBAAmB","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["layout/index.ts"],"sourcesContent":["export { AnchoredPopover, type AnchoredPopoverProps } from \"./AnchoredPopover\";\nexport type {\n AppOverviewCardsProps,\n AppOverviewEmptyStateProps,\n AppOverviewPanelProps,\n AppOverviewProps,\n} from \"./AppOverview\";\nexport { default as AppOverview } from \"./AppOverview\";\nexport type {\n AppWorkspaceBottomDrawerHeight,\n AppWorkspaceBottomDrawerProps,\n AppWorkspaceContentProps,\n AppWorkspaceDetailProps,\n AppWorkspaceDetailWidth,\n AppWorkspaceHeadProps,\n AppWorkspaceLevelSwitcher,\n AppWorkspaceMainPaneProps,\n AppWorkspaceMainProps,\n AppWorkspaceNavTreeItemProps,\n AppWorkspaceNavTreeMove,\n AppWorkspaceNavTreeProps,\n AppWorkspaceProps,\n AppWorkspaceSidebarAccessoryVisibility,\n AppWorkspaceSidebarBodyProps,\n AppWorkspaceSidebarIconActionProps,\n AppWorkspaceSidebarIconActionTone,\n AppWorkspaceSidebarIconGridProps,\n AppWorkspaceSidebarItemActionProps,\n AppWorkspaceSidebarItemActionsProps,\n AppWorkspaceSidebarItemIconProps,\n AppWorkspaceSidebarItemLabelProps,\n AppWorkspaceSidebarItemMetaProps,\n AppWorkspaceSidebarItemProps,\n AppWorkspaceSidebarItemStatusProps,\n AppWorkspaceSidebarItemTone,\n AppWorkspaceSidebarProps,\n AppWorkspaceSidebarSectionProps,\n AppWorkspaceSidebarVisibility,\n AppWorkspaceWidthShare,\n} from \"./AppWorkspace\";\nexport { appWorkspaceDetailElementId, default as AppWorkspace } from \"./AppWorkspace\";\nexport { AppWorkspaceSidebarItemStatus } from \"./AppWorkspaceSidebarItemStatus\";\nexport { watchAppHostWidth } from \"./app-host-width\";\nexport type { AppWorkspaceControllerOptions } from \"./app-workspace-controller\";\nexport { installAppWorkspaceController, parkWorkspaceDetailDrawers } from \"./app-workspace-controller\";\nexport type {\n AppWorkspaceLayoutState,\n AppWorkspaceResizeKind,\n} from \"./app-workspace-state\";\nexport {\n APP_WORKSPACE_DETAIL_DEFAULT,\n APP_WORKSPACE_DETAIL_MAX,\n APP_WORKSPACE_DETAIL_MIN,\n APP_WORKSPACE_DRAWER_DEFAULT,\n APP_WORKSPACE_DRAWER_MAX,\n APP_WORKSPACE_DRAWER_MIN,\n APP_WORKSPACE_MAIN_MIN,\n APP_WORKSPACE_MAIN_MIN_HEIGHT,\n APP_WORKSPACE_PANE_DEFAULT,\n APP_WORKSPACE_PANE_MAX,\n APP_WORKSPACE_PANE_MIN,\n APP_WORKSPACE_SIDEBAR_COLLAPSE_THRESHOLD,\n APP_WORKSPACE_SIDEBAR_COLLAPSED,\n APP_WORKSPACE_SIDEBAR_DEFAULT,\n APP_WORKSPACE_SIDEBAR_MAX,\n APP_WORKSPACE_SIDEBAR_MIN,\n appWorkspaceLayoutStyle,\n appWorkspacePanelVariable,\n appWorkspaceResizeLimits,\n normalizeAppWorkspaceLayoutState,\n parseAppWorkspaceLayoutState,\n resolveAppWorkspaceSidebarWidth,\n safeAppWorkspacePanelId,\n serializeAppWorkspaceLayoutState,\n shouldCollapseAppWorkspaceSidebar,\n} from \"./app-workspace-state\";\nexport { type BottomSheetProps, bottomSheetAdaptiveOptions, bottomSheetOptions, default as BottomSheet } from \"./BottomSheet\";\nexport type { DataPanelProps } from \"./DataPanel\";\nexport { DataPanel } from \"./DataPanel\";\nexport type {\n DetailPanelActionButtonProps,\n DetailPanelActionLinkProps,\n DetailPanelActionProps,\n DetailPanelActionSecondary,\n DetailPanelBodyProps,\n DetailPanelGroupProps,\n DetailPanelHeaderProps,\n DetailPanelProps,\n DetailPanelRowProps,\n DetailPanelSectionProps,\n DetailPanelSummaryProps,\n DetailPanelTone,\n} from \"./DetailPanel\";\nexport { default as DetailPanel } from \"./DetailPanel\";\nexport type {\n DetailAccessEntry,\n DetailAccessProps,\n DetailLinkItem,\n DetailLinksProps,\n DetailPresencePerson,\n DetailPresenceProps,\n DetailPresenceState,\n DetailPropertiesProps,\n DetailProperty,\n DetailTag,\n DetailTagsProps,\n} from \"./DetailSections\";\nexport { DetailAccess, DetailLinks, DetailPresence, DetailPresenceSlot, DetailProperties, DetailTags } from \"./DetailSections\";\nexport { DETAILS_ICON, DetailsToggle, type DetailsToggleProps } from \"./DetailsToggle\";\nexport type { DiscussionComposerProps, DiscussionItemProps, DiscussionListProps, DiscussionProps } from \"./Discussion\";\nexport { default as Discussion } from \"./Discussion\";\nexport type {\n FloatingWindowClose,\n FloatingWindowProps,\n OpenFloatingWindowOptions,\n} from \"./FloatingWindow\";\nexport {\n default as FloatingWindow,\n type FloatingWindowRect,\n fitFloatingWindowRect,\n openFloatingWindow,\n} from \"./FloatingWindow\";\nexport type { MobileShellHeaderProps, MobileShellProps, MobileShellSidebarItem, MobileShellSidebarProps } from \"./MobileShell\";\nexport { default as MobileShell, observeMobileShell } from \"./MobileShell\";\nexport { default as Navigation, type NavigationProps } from \"./Navigation\";\nexport {\n createNavigation,\n findNavigationItem,\n type NavigationController,\n type NavigationItem,\n type NavigationOptions,\n type NavigationStatus,\n} from \"./navigation-model\";\nexport type { PageTitleProps, PageTrailLink, PageTrailState } from \"./PageTitle\";\nexport { followPageTrail, PAGE_TRAIL_EVENT, PageTitle, PageTrailProvider, readPageTrail, setPageTrail, usePageTrail } from \"./PageTitle\";\nexport type {\n PanelDialogBodyProps,\n PanelDialogFooterProps,\n PanelDialogHeaderProps,\n PanelDialogProps,\n PanelDialogSectionProps,\n PanelDialogSurface,\n PanelDialogTabOption,\n PanelDialogTabsProps,\n} from \"./PanelDialog\";\nexport {\n confirmDiscardIfDirty,\n default as PanelDialog,\n panelDialogFixedOptions,\n panelDialogFixedPanelClass,\n panelDialogOptions,\n panelDialogPanelClass,\n panelDialogWideOptions,\n panelDialogWidePanelClass,\n panelDialogWorkspaceOptions,\n panelDialogWorkspacePanelClass,\n} from \"./PanelDialog\";\nexport type { PanelHeaderProps } from \"./PanelHeader\";\nexport { PanelHeader } from \"./PanelHeader\";\nexport type { PanesItem, PanesProps } from \"./Panes\";\nexport { default as Panes } from \"./Panes\";\nexport type { PullToRefreshProps, PullToRefreshState } from \"./PullToRefresh\";\nexport { default as PullToRefresh } from \"./PullToRefresh\";\nexport { installPageTitleController } from \"./page-title-controller\";\nexport type {\n AddPanesItemOptions,\n PanesDirection,\n PanesGroup,\n PanesIntent,\n PanesLayout,\n PanesNode,\n PanesPath,\n PanesPathSegment,\n PanesSide,\n PanesSplit,\n} from \"./panes-layout\";\nexport {\n activatePanesItem,\n addPanesItem,\n applyPanesIntent,\n createPanesLayout,\n isPanesItemVisible,\n PANES_LAYOUT_VERSION,\n parsePanesLayout,\n reconcilePanesLayout,\n removePanesItem,\n resizePanesSplit,\n} from \"./panes-layout\";\nexport { default as ResizeSeparator, type ResizeSeparatorProps } from \"./ResizeSeparator\";\nexport { attachResizeSeparator, type ResizeSeparatorOptions } from \"./resize-separator\";\nexport type { ScrollAreaProps } from \"./ScrollArea\";\nexport { default as ScrollArea } from \"./ScrollArea\";\nexport type {\n SaveStatusProps,\n SaveStatusState,\n SettingsFieldControlProps,\n SettingsFieldProps,\n SettingsFieldWidth,\n SettingsGroupActionProps,\n SettingsGroupProps,\n SettingsPageProps,\n SettingsPanelFooterProps,\n SettingsSaveBarProps,\n SettingsSectionProps,\n} from \"./Settings\";\nexport {\n readSettingsError,\n SaveStatus,\n SettingsField,\n SettingsGroup,\n SettingsPage,\n SettingsPanelFooter,\n SettingsSaveBar,\n SettingsSection,\n sameSettingValue,\n} from \"./Settings\";\nexport type {\n SettingsCollectionActionProps,\n SettingsCollectionItemActionsProps,\n SettingsCollectionItemProps,\n SettingsCollectionItemReorderProps,\n SettingsCollectionItemStatusProps,\n SettingsCollectionProps,\n} from \"./SettingsCollection\";\nexport { default as SettingsCollection } from \"./SettingsCollection\";\nexport type {\n SettingsModalFooterProps,\n SettingsModalGroupProps,\n SettingsModalProps,\n SettingsModalTabProps,\n SettingsModalTabTone,\n} from \"./SettingsModal\";\nexport { default as SettingsModal } from \"./SettingsModal\";\nexport {\n APP_WORKSPACE_SWITCHER_SEARCH_FROM,\n type AppWorkspaceSidebarSwitcherProps,\n type AppWorkspaceSwitcherAction,\n type AppWorkspaceSwitcherOption,\n} from \"./SidebarSwitcher\";\nexport { measureScrollFade } from \"./scroll-fade\";\nexport { attachSheetHandle, type SheetHandleOptions } from \"./sheet-handle\";\nexport type { TabBarItem, TabBarProps } from \"./TabBar\";\nexport { default as TabBar } from \"./TabBar\";\nexport type { TableOfContentsItem, TableOfContentsProps } from \"./TableOfContents\";\nexport { TableOfContents } from \"./TableOfContents\";\n"],"mappings":"AAAA,SAAS,eAAe,QAAmC,mBAAmB;AAO9E,SAAS,OAAO,IAAI,WAAW,QAAQ,eAAe;AAiCtD,SAAS,2BAA2B,EAAE,OAAO,IAAI,YAAY,QAAQ,gBAAgB;AACrF,SAAS,6BAA6B,QAAQ,iCAAiC;AAC/E,SAAS,iBAAiB,QAAQ,kBAAkB;AAEpD,SAAS,6BAA6B,EAAE,0BAA0B,QAAQ,4BAA4B;AAKtG,SACE,4BAA4B,EAC5B,wBAAwB,EACxB,wBAAwB,EACxB,4BAA4B,EAC5B,wBAAwB,EACxB,wBAAwB,EACxB,sBAAsB,EACtB,6BAA6B,EAC7B,0BAA0B,EAC1B,sBAAsB,EACtB,sBAAsB,EACtB,wCAAwC,EACxC,+BAA+B,EAC/B,6BAA6B,EAC7B,yBAAyB,EACzB,yBAAyB,EACzB,uBAAuB,EACvB,yBAAyB,EACzB,wBAAwB,EACxB,gCAAgC,EAChC,4BAA4B,EAC5B,+BAA+B,EAC/B,uBAAuB,EACvB,gCAAgC,EAChC,iCAAiC,QAC5B,uBAAuB;AAC9B,SAAgC,0BAA0B,EAAE,kBAAkB,EAAE,OAAO,IAAI,WAAW,QAAQ,eAAe;AAE7H,SAAS,SAAS,QAAQ,aAAa;AAevC,SAAS,OAAO,IAAI,WAAW,QAAQ,eAAe;AActD,SAAS,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,UAAU,QAAQ,kBAAkB;AAC9H,SAAS,YAAY,EAAE,aAAa,QAAiC,iBAAiB;AAEtF,SAAS,OAAO,IAAI,UAAU,QAAQ,cAAc;AAMpD,SACE,OAAO,IAAI,cAAc,EAEzB,qBAAqB,EACrB,kBAAkB,QACb,kBAAkB;AAEzB,SAAS,OAAO,IAAI,WAAW,EAAE,kBAAkB,QAAQ,eAAe;AAC1E,SAAS,OAAO,IAAI,UAAU,QAA8B,cAAc;AAC1E,SACE,gBAAgB,EAChB,kBAAkB,QAKb,oBAAoB;AAE3B,SAAS,eAAe,EAAE,gBAAgB,EAAE,SAAS,EAAE,iBAAiB,EAAE,aAAa,EAAE,YAAY,EAAE,YAAY,QAAQ,aAAa;AAWxI,SACE,qBAAqB,EACrB,OAAO,IAAI,WAAW,EACtB,uBAAuB,EACvB,0BAA0B,EAC1B,kBAAkB,EAClB,qBAAqB,EACrB,sBAAsB,EACtB,yBAAyB,EACzB,2BAA2B,EAC3B,8BAA8B,QACzB,eAAe;AAEtB,SAAS,WAAW,QAAQ,eAAe;AAE3C,SAAS,OAAO,IAAI,KAAK,QAAQ,SAAS;AAE1C,SAAS,OAAO,IAAI,aAAa,QAAQ,iBAAiB;AAC1D,SAAS,0BAA0B,QAAQ,yBAAyB;AAapE,SACE,iBAAiB,EACjB,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,gBAAgB,EAChB,oBAAoB,EACpB,eAAe,EACf,gBAAgB,QACX,gBAAgB;AACvB,SAAS,OAAO,IAAI,eAAe,QAAmC,mBAAmB;AACzF,SAAS,qBAAqB,QAAqC,oBAAoB;AAEvF,SAAS,OAAO,IAAI,UAAU,QAAQ,cAAc;AAcpD,SACE,iBAAiB,EACjB,UAAU,EACV,aAAa,EACb,aAAa,EACb,YAAY,EACZ,mBAAmB,EACnB,eAAe,EACf,eAAe,EACf,gBAAgB,QACX,YAAY;AASnB,SAAS,OAAO,IAAI,kBAAkB,QAAQ,sBAAsB;AAQpE,SAAS,OAAO,IAAI,aAAa,QAAQ,iBAAiB;AAC1D,SACE,kCAAkC,QAI7B,mBAAmB;AAC1B,SAAS,iBAAiB,QAAQ,eAAe;AACjD,SAAS,iBAAiB,QAAiC,gBAAgB;AAE3E,SAAS,OAAO,IAAI,MAAM,QAAQ,UAAU;AAE5C,SAAS,eAAe,QAAQ,mBAAmB","ignoreList":[]}
@@ -0,0 +1,155 @@
1
+ import { suppressTextSelection } from "../internal/text-selection";
2
+ /** Below this distance a press stays a press and the click after it moves the sheet. */
3
+ const DRAG_THRESHOLD = 6;
4
+ /** How far ahead the release projects the pointer's speed, so a short flick reaches the next detent. */
5
+ const PROJECTION_MS = 120;
6
+ /** A pointer that rested this long before it lifted carries no speed into the snap. */
7
+ const REST_MS = 80;
8
+ /** A release below this share of the lowest detent dismisses, when the sheet may be dismissed. */
9
+ const DISMISS_SHARE = 0.6;
10
+
11
+ /**
12
+ * Lets a sheet's handle drag it between detents. The handle stays a button: a press, by pointer, Enter or Space,
13
+ * moves the sheet to the next detent up, and from the highest back to the lowest. A drag follows the pointer with an
14
+ * inline height and, on release, snaps to the detent nearest to where the pointer's speed would carry it. The snap
15
+ * animates with the sheet's own height transition, so reduced motion makes it instant. The stylesheet owns every
16
+ * resting height, which keeps the server's first frame and a rotation correct without script; the handle measures
17
+ * them when a drag starts.
18
+ */
19
+ export function attachSheetHandle(handle, options) {
20
+ const {
21
+ sheet,
22
+ detents
23
+ } = options;
24
+ const current = () => {
25
+ const detent = sheet.dataset.sheetDetent;
26
+ return detent && detents.includes(detent) ? detent : options.initial;
27
+ };
28
+ const set = detent => {
29
+ const changed = detent !== current();
30
+ sheet.dataset.sheetDetent = detent;
31
+ if (changed) options.onChange?.(detent);
32
+ };
33
+ // Each detent's height as the stylesheet draws it now; the caller has turned the transition off.
34
+ const measure = () => {
35
+ const shown = sheet.dataset.sheetDetent;
36
+ const heights = detents.map(detent => {
37
+ sheet.dataset.sheetDetent = detent;
38
+ return sheet.getBoundingClientRect().height;
39
+ });
40
+ if (shown === undefined) delete sheet.dataset.sheetDetent;else sheet.dataset.sheetDetent = shown;
41
+ return heights;
42
+ };
43
+ let drag;
44
+ let suppressClick = false;
45
+ // Dropping the inline height and transition together lets the stylesheet's transition carry the sheet to its detent.
46
+ const release = () => {
47
+ sheet.style.removeProperty("height");
48
+ sheet.style.removeProperty("transition");
49
+ delete sheet.dataset.sheetDragging;
50
+ };
51
+ const finish = (commit, time) => {
52
+ const ended = drag;
53
+ if (!ended) return;
54
+ drag = undefined;
55
+ ended.releaseSelection();
56
+ if (handle.hasPointerCapture?.(ended.id)) handle.releasePointerCapture(ended.id);
57
+ // A cancelled gesture sends no click; only a finished drag's click must not move the sheet again.
58
+ if (!ended.moved || !commit) {
59
+ release();
60
+ return;
61
+ }
62
+ suppressClick = true;
63
+ const speed = time !== undefined && time - ended.time > REST_MS ? 0 : ended.speed;
64
+ const target = ended.height - speed * PROJECTION_MS;
65
+ const lowest = ended.heights[0] ?? 0;
66
+ if (options.onDismiss && ended.height < lowest && target < lowest * DISMISS_SHARE) {
67
+ release();
68
+ options.onDismiss();
69
+ return;
70
+ }
71
+ let nearest = 0;
72
+ for (const [index, height] of ended.heights.entries()) if (Math.abs(height - target) < Math.abs((ended.heights[nearest] ?? 0) - target)) nearest = index;
73
+ release();
74
+ set(detents[nearest] ?? options.initial);
75
+ };
76
+ const down = event => {
77
+ if (event.button !== 0 || event.isPrimary === false || drag) return;
78
+ suppressClick = false;
79
+ // A press during a snap starts from where the sheet is now.
80
+ const startHeight = sheet.getBoundingClientRect().height;
81
+ sheet.style.transition = "none";
82
+ const heights = measure();
83
+ sheet.style.height = `${startHeight}px`;
84
+ handle.setPointerCapture?.(event.pointerId);
85
+ drag = {
86
+ id: event.pointerId,
87
+ startY: event.clientY,
88
+ startHeight,
89
+ heights,
90
+ height: startHeight,
91
+ moved: false,
92
+ y: event.clientY,
93
+ time: event.timeStamp,
94
+ speed: 0,
95
+ releaseSelection: suppressTextSelection(event.pointerId)
96
+ };
97
+ };
98
+ const move = event => {
99
+ if (!drag || event.pointerId !== drag.id) return;
100
+ // A move without a change of height, such as one a release sends first, is no speed.
101
+ if (event.clientY === drag.y) return;
102
+ const distance = event.clientY - drag.startY;
103
+ if (!drag.moved && Math.abs(distance) < DRAG_THRESHOLD) return;
104
+ if (!drag.moved) {
105
+ drag.moved = true;
106
+ sheet.dataset.sheetDragging = "";
107
+ }
108
+ const elapsed = event.timeStamp - drag.time;
109
+ if (elapsed > 0) drag.speed = drag.speed * 0.4 + (event.clientY - drag.y) / elapsed * 0.6;
110
+ drag.y = event.clientY;
111
+ drag.time = event.timeStamp;
112
+ const highest = Math.max(...drag.heights);
113
+ const lowest = options.onDismiss ? 0 : Math.min(...drag.heights);
114
+ drag.height = Math.min(highest, Math.max(lowest, drag.startHeight - distance));
115
+ sheet.style.height = `${drag.height}px`;
116
+ };
117
+ const up = event => {
118
+ if (drag && event.pointerId === drag.id) finish(true, event.timeStamp);
119
+ };
120
+ const cancel = event => {
121
+ if (drag && event.pointerId === drag.id) finish(false);
122
+ };
123
+ const click = event => {
124
+ // The click a drag's release produces does not move the sheet again; a keyboard click has no detail.
125
+ if (suppressClick && event.detail !== 0) {
126
+ suppressClick = false;
127
+ event.preventDefault();
128
+ event.stopImmediatePropagation();
129
+ return;
130
+ }
131
+ suppressClick = false;
132
+ const index = detents.indexOf(current());
133
+ set(detents[index + 1 < detents.length ? index + 1 : 0] ?? options.initial);
134
+ };
135
+ const touchAction = handle.style.touchAction;
136
+ // The browser must not take the drag for a scroll or a page swipe.
137
+ handle.style.touchAction = "none";
138
+ handle.addEventListener("pointerdown", down);
139
+ handle.addEventListener("pointermove", move);
140
+ handle.addEventListener("pointerup", up);
141
+ handle.addEventListener("pointercancel", cancel);
142
+ handle.addEventListener("lostpointercapture", cancel);
143
+ handle.addEventListener("click", click);
144
+ return () => {
145
+ finish(false);
146
+ handle.style.touchAction = touchAction;
147
+ handle.removeEventListener("pointerdown", down);
148
+ handle.removeEventListener("pointermove", move);
149
+ handle.removeEventListener("pointerup", up);
150
+ handle.removeEventListener("pointercancel", cancel);
151
+ handle.removeEventListener("lostpointercapture", cancel);
152
+ handle.removeEventListener("click", click);
153
+ };
154
+ }
155
+ //# sourceMappingURL=sheet-handle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sources":["layout/sheet-handle.ts"],"sourcesContent":["import { suppressTextSelection } from \"../internal/text-selection\";\n\nexport type SheetHandleOptions = {\n /** The sheet the handle sits on. It carries the current detent in `data-sheet-detent`. */\n sheet: HTMLElement;\n /** The detents' names, lowest first. The stylesheet gives each `[data-sheet-detent=\"…\"]` its height. */\n detents: readonly string[];\n /** The detent the stylesheet draws while the sheet has no `data-sheet-detent`, such as in the server's markup. */\n initial: string;\n /** After a drag or a press moved the sheet to another detent, for example to rename the handle. */\n onChange?: (detent: string) => void;\n /** Without it, a drag stops at the lowest detent; with it, a drag well below that detent asks to close. */\n onDismiss?: () => void;\n};\n\n/** Below this distance a press stays a press and the click after it moves the sheet. */\nconst DRAG_THRESHOLD = 6;\n/** How far ahead the release projects the pointer's speed, so a short flick reaches the next detent. */\nconst PROJECTION_MS = 120;\n/** A pointer that rested this long before it lifted carries no speed into the snap. */\nconst REST_MS = 80;\n/** A release below this share of the lowest detent dismisses, when the sheet may be dismissed. */\nconst DISMISS_SHARE = 0.6;\n\n/**\n * Lets a sheet's handle drag it between detents. The handle stays a button: a press, by pointer, Enter or Space,\n * moves the sheet to the next detent up, and from the highest back to the lowest. A drag follows the pointer with an\n * inline height and, on release, snaps to the detent nearest to where the pointer's speed would carry it. The snap\n * animates with the sheet's own height transition, so reduced motion makes it instant. The stylesheet owns every\n * resting height, which keeps the server's first frame and a rotation correct without script; the handle measures\n * them when a drag starts.\n */\nexport function attachSheetHandle(handle: HTMLElement, options: SheetHandleOptions): () => void {\n const { sheet, detents } = options;\n const current = () => {\n const detent = sheet.dataset.sheetDetent;\n return detent && detents.includes(detent) ? detent : options.initial;\n };\n const set = (detent: string) => {\n const changed = detent !== current();\n sheet.dataset.sheetDetent = detent;\n if (changed) options.onChange?.(detent);\n };\n // Each detent's height as the stylesheet draws it now; the caller has turned the transition off.\n const measure = () => {\n const shown = sheet.dataset.sheetDetent;\n const heights = detents.map((detent) => {\n sheet.dataset.sheetDetent = detent;\n return sheet.getBoundingClientRect().height;\n });\n if (shown === undefined) delete sheet.dataset.sheetDetent;\n else sheet.dataset.sheetDetent = shown;\n return heights;\n };\n let drag:\n | {\n id: number;\n startY: number;\n startHeight: number;\n heights: number[];\n height: number;\n moved: boolean;\n y: number;\n time: number;\n /** Downward speed in px per ms. */\n speed: number;\n releaseSelection: () => void;\n }\n | undefined;\n let suppressClick = false;\n // Dropping the inline height and transition together lets the stylesheet's transition carry the sheet to its detent.\n const release = () => {\n sheet.style.removeProperty(\"height\");\n sheet.style.removeProperty(\"transition\");\n delete sheet.dataset.sheetDragging;\n };\n const finish = (commit: boolean, time?: number) => {\n const ended = drag;\n if (!ended) return;\n drag = undefined;\n ended.releaseSelection();\n if (handle.hasPointerCapture?.(ended.id)) handle.releasePointerCapture(ended.id);\n // A cancelled gesture sends no click; only a finished drag's click must not move the sheet again.\n if (!ended.moved || !commit) {\n release();\n return;\n }\n suppressClick = true;\n const speed = time !== undefined && time - ended.time > REST_MS ? 0 : ended.speed;\n const target = ended.height - speed * PROJECTION_MS;\n const lowest = ended.heights[0] ?? 0;\n if (options.onDismiss && ended.height < lowest && target < lowest * DISMISS_SHARE) {\n release();\n options.onDismiss();\n return;\n }\n let nearest = 0;\n for (const [index, height] of ended.heights.entries())\n if (Math.abs(height - target) < Math.abs((ended.heights[nearest] ?? 0) - target)) nearest = index;\n release();\n set(detents[nearest] ?? options.initial);\n };\n const down = (event: PointerEvent) => {\n if (event.button !== 0 || event.isPrimary === false || drag) return;\n suppressClick = false;\n // A press during a snap starts from where the sheet is now.\n const startHeight = sheet.getBoundingClientRect().height;\n sheet.style.transition = \"none\";\n const heights = measure();\n sheet.style.height = `${startHeight}px`;\n handle.setPointerCapture?.(event.pointerId);\n drag = {\n id: event.pointerId,\n startY: event.clientY,\n startHeight,\n heights,\n height: startHeight,\n moved: false,\n y: event.clientY,\n time: event.timeStamp,\n speed: 0,\n releaseSelection: suppressTextSelection(event.pointerId),\n };\n };\n const move = (event: PointerEvent) => {\n if (!drag || event.pointerId !== drag.id) return;\n // A move without a change of height, such as one a release sends first, is no speed.\n if (event.clientY === drag.y) return;\n const distance = event.clientY - drag.startY;\n if (!drag.moved && Math.abs(distance) < DRAG_THRESHOLD) return;\n if (!drag.moved) {\n drag.moved = true;\n sheet.dataset.sheetDragging = \"\";\n }\n const elapsed = event.timeStamp - drag.time;\n if (elapsed > 0) drag.speed = drag.speed * 0.4 + ((event.clientY - drag.y) / elapsed) * 0.6;\n drag.y = event.clientY;\n drag.time = event.timeStamp;\n const highest = Math.max(...drag.heights);\n const lowest = options.onDismiss ? 0 : Math.min(...drag.heights);\n drag.height = Math.min(highest, Math.max(lowest, drag.startHeight - distance));\n sheet.style.height = `${drag.height}px`;\n };\n const up = (event: PointerEvent) => {\n if (drag && event.pointerId === drag.id) finish(true, event.timeStamp);\n };\n const cancel = (event: PointerEvent) => {\n if (drag && event.pointerId === drag.id) finish(false);\n };\n const click = (event: MouseEvent) => {\n // The click a drag's release produces does not move the sheet again; a keyboard click has no detail.\n if (suppressClick && event.detail !== 0) {\n suppressClick = false;\n event.preventDefault();\n event.stopImmediatePropagation();\n return;\n }\n suppressClick = false;\n const index = detents.indexOf(current());\n set(detents[index + 1 < detents.length ? index + 1 : 0] ?? options.initial);\n };\n const touchAction = handle.style.touchAction;\n // The browser must not take the drag for a scroll or a page swipe.\n handle.style.touchAction = \"none\";\n handle.addEventListener(\"pointerdown\", down);\n handle.addEventListener(\"pointermove\", move);\n handle.addEventListener(\"pointerup\", up);\n handle.addEventListener(\"pointercancel\", cancel);\n handle.addEventListener(\"lostpointercapture\", cancel);\n handle.addEventListener(\"click\", click);\n return () => {\n finish(false);\n handle.style.touchAction = touchAction;\n handle.removeEventListener(\"pointerdown\", down);\n handle.removeEventListener(\"pointermove\", move);\n handle.removeEventListener(\"pointerup\", up);\n handle.removeEventListener(\"pointercancel\", cancel);\n handle.removeEventListener(\"lostpointercapture\", cancel);\n handle.removeEventListener(\"click\", click);\n };\n}\n"],"mappings":"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","ignoreList":[]}
@@ -13,10 +13,13 @@ import { memo as _$memo } from "solid-js/web";
13
13
  var _tmpl$ = /*#__PURE__*/_$template(`<div>`),
14
14
  _tmpl$2 = /*#__PURE__*/_$template(`<article><!$><!/><div><!$><!/><!$><!/><!$><!/>`),
15
15
  _tmpl$3 = /*#__PURE__*/_$template(`<i aria-hidden=true>`),
16
- _tmpl$4 = /*#__PURE__*/_$template(`<div><p></p><!$><!/>`),
17
- _tmpl$5 = /*#__PURE__*/_$template(`<span>`),
18
- _tmpl$6 = /*#__PURE__*/_$template(`<p>`);
16
+ _tmpl$4 = /*#__PURE__*/_$template(`<span class=k2b-sr-only>`),
17
+ _tmpl$5 = /*#__PURE__*/_$template(`<div><p></p><!$><!/>`),
18
+ _tmpl$6 = /*#__PURE__*/_$template(`<span>`),
19
+ _tmpl$7 = /*#__PURE__*/_$template(`<p>`);
19
20
  import { children, For, Show, splitProps } from "solid-js";
21
+ import { dialogToneIcon, dialogToneLabel } from "../feedback/dialog-tone";
22
+ import { useUiMessages } from "../intl/messages";
20
23
  export const NOTICE_CARD_CLASSES = {
21
24
  root: "k2b-notice-card",
22
25
  icon: "k2b-notice-card__icon",
@@ -32,6 +35,18 @@ function NoticeCardComponent(props) {
32
35
  // Children that render nothing, such as a Show whose condition is false, add no body and no gap.
33
36
  const body = children(() => local.children);
34
37
  const hasBody = () => body.toArray().some(node => node != null && node !== false && node !== "");
38
+ const messages = useUiMessages();
39
+ /** The tone a dialog also knows, so `icon` true shows the same icon and word; info and neutral have no word. */
40
+ const dialogTone = () => local.tone === "success" || local.tone === "warning" || local.tone === "danger" ? local.tone : undefined;
41
+ const icon = () => {
42
+ if (local.icon !== true) return local.icon;
43
+ const tone = dialogTone();
44
+ return tone ? dialogToneIcon(tone) : "ti ti-info-circle";
45
+ };
46
+ const toneWord = () => {
47
+ const tone = local.icon === true ? dialogTone() : undefined;
48
+ return tone ? `${dialogToneLabel(messages(), tone)}: ` : undefined;
49
+ };
35
50
  return (() => {
36
51
  var _el$ = _$getNextElement(_tmpl$2),
37
52
  _el$0 = _el$.firstChild,
@@ -55,46 +70,50 @@ function NoticeCardComponent(props) {
55
70
  } : {}), false, true);
56
71
  _$insert(_el$, _$createComponent(Show, {
57
72
  get when() {
58
- return local.icon;
73
+ return icon();
59
74
  },
60
- children: icon => (() => {
75
+ children: icon => [(() => {
61
76
  var _el$10 = _$getNextElement(_tmpl$3);
62
77
  _$effect(() => _$className(_el$10, `${icon()} ${NOTICE_CARD_CLASSES.icon}`));
63
78
  return _el$10;
64
- })()
79
+ })(), _$memo(() => _$memo(() => !!toneWord())() ? (() => {
80
+ var _el$11 = _$getNextElement(_tmpl$4);
81
+ _$insert(_el$11, toneWord);
82
+ return _el$11;
83
+ })() : null)]
65
84
  }), _el$1, _co$4);
66
85
  _$insert(_el$2, _$createComponent(Show, {
67
86
  get when() {
68
87
  return local.title;
69
88
  },
70
89
  children: title => (() => {
71
- var _el$11 = _$getNextElement(_tmpl$4),
72
- _el$12 = _el$11.firstChild,
73
- _el$13 = _el$12.nextSibling,
74
- [_el$14, _co$5] = _$getNextMarker(_el$13.nextSibling);
75
- _$insert(_el$12, title);
76
- _$insert(_el$11, _$createComponent(Show, {
90
+ var _el$12 = _$getNextElement(_tmpl$5),
91
+ _el$13 = _el$12.firstChild,
92
+ _el$14 = _el$13.nextSibling,
93
+ [_el$15, _co$5] = _$getNextMarker(_el$14.nextSibling);
94
+ _$insert(_el$13, title);
95
+ _$insert(_el$12, _$createComponent(Show, {
77
96
  get when() {
78
97
  return local.meta;
79
98
  },
80
99
  children: meta => (() => {
81
- var _el$15 = _$getNextElement(_tmpl$5);
82
- _$insert(_el$15, meta);
83
- _$effect(() => _$className(_el$15, NOTICE_CARD_CLASSES.meta));
84
- return _el$15;
100
+ var _el$16 = _$getNextElement(_tmpl$6);
101
+ _$insert(_el$16, meta);
102
+ _$effect(() => _$className(_el$16, NOTICE_CARD_CLASSES.meta));
103
+ return _el$16;
85
104
  })()
86
- }), _el$14, _co$5);
105
+ }), _el$15, _co$5);
87
106
  _$effect(_p$ => {
88
107
  var _v$ = NOTICE_CARD_CLASSES.head,
89
108
  _v$2 = NOTICE_CARD_CLASSES.title;
90
- _v$ !== _p$.e && _$className(_el$11, _p$.e = _v$);
91
- _v$2 !== _p$.t && _$className(_el$12, _p$.t = _v$2);
109
+ _v$ !== _p$.e && _$className(_el$12, _p$.e = _v$);
110
+ _v$2 !== _p$.t && _$className(_el$13, _p$.t = _v$2);
92
111
  return _p$;
93
112
  }, {
94
113
  e: undefined,
95
114
  t: undefined
96
115
  });
97
- return _el$11;
116
+ return _el$12;
98
117
  })()
99
118
  }), _el$5, _co$);
100
119
  _$insert(_el$2, _$createComponent(Show, {
@@ -102,10 +121,10 @@ function NoticeCardComponent(props) {
102
121
  return local.detail;
103
122
  },
104
123
  children: detail => (() => {
105
- var _el$16 = _$getNextElement(_tmpl$6);
106
- _$insert(_el$16, detail);
107
- _$effect(() => _$className(_el$16, NOTICE_CARD_CLASSES.description));
108
- return _el$16;
124
+ var _el$17 = _$getNextElement(_tmpl$7);
125
+ _$insert(_el$17, detail);
126
+ _$effect(() => _$className(_el$17, NOTICE_CARD_CLASSES.description));
127
+ return _el$17;
109
128
  })()
110
129
  }), _el$7, _co$2);
111
130
  _$insert(_el$2, _$createComponent(Show, {
@@ -131,8 +150,8 @@ function NoticeGrid(props) {
131
150
  return props.items.length > 0;
132
151
  },
133
152
  get children() {
134
- var _el$17 = _$getNextElement(_tmpl$);
135
- _$insert(_el$17, _$createComponent(For, {
153
+ var _el$18 = _$getNextElement(_tmpl$);
154
+ _$insert(_el$18, _$createComponent(For, {
136
155
  get each() {
137
156
  return props.items;
138
157
  },
@@ -141,14 +160,14 @@ function NoticeGrid(props) {
141
160
  _$effect(_p$ => {
142
161
  var _v$3 = `k2b-notice-grid ${props.class ?? ""}`,
143
162
  _v$4 = columns();
144
- _v$3 !== _p$.e && _$className(_el$17, _p$.e = _v$3);
145
- _v$4 !== _p$.t && _$setAttribute(_el$17, "data-columns", _p$.t = _v$4);
163
+ _v$3 !== _p$.e && _$className(_el$18, _p$.e = _v$3);
164
+ _v$4 !== _p$.t && _$setAttribute(_el$18, "data-columns", _p$.t = _v$4);
146
165
  return _p$;
147
166
  }, {
148
167
  e: undefined,
149
168
  t: undefined
150
169
  });
151
- return _el$17;
170
+ return _el$18;
152
171
  }
153
172
  });
154
173
  }