@jsenv/navi 0.29.349 → 0.29.350

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.
@@ -13,8 +13,8 @@
13
13
  "import {\n getVirtualKeyboardOverlayHeight,\n subscribeVisualViewportResizeSettled,\n subscribeWindowResizeSettled,\n} from \"@jsenv/dom\";\nimport { computed, signal } from \"@preact/signals\";\n\nexport const windowWidthSignal = signal(window.innerWidth);\nexport const windowHeightSignal = signal(window.innerHeight);\n\n// Debounced (not a raw \"resize\" listener) — see window_size.js's own\n// module comment: mobile fires a transient \"resize\" when the browser's own\n// UI chrome (address bar, etc.) briefly shows/hides, and this needs to settle\n// on the same tick as Popover/Dialog's own repositioning, or one flickers a\n// moment out of sync with the others.\nsubscribeWindowResizeSettled(() => {\n windowWidthSignal.value = window.innerWidth;\n windowHeightSignal.value = window.innerHeight;\n});\n\n// Visual viewport dimensions — update when the virtual keyboard opens/closes or\n// when the browser UI (address bar) shows/hides.\n// When visualViewport is not available, derived from window signals so they\n// stay live without any extra listeners.\nconst vv = window.visualViewport;\nexport const visualViewportWidthSignal = vv\n ? signal(vv.width)\n : computed(() => windowWidthSignal.value);\nexport const visualViewportHeightSignal = vv\n ? signal(vv.height)\n : computed(() => windowHeightSignal.value);\n\nif (vv) {\n const update = () => {\n visualViewportWidthSignal.value = vv.width;\n visualViewportHeightSignal.value = vv.height;\n };\n // The two directions are not equally trustworthy, and treating them alike is\n // what makes one of the two bugs unavoidable.\n //\n // SMALLER is believed at once. Something now covers the screen, and what is\n // sized against these numbers — the dialog/popover ceilings, through\n // --navi-vvh (navi_css_vars.js) — has to answer the smaller screen in the\n // same frame the placement does. The placement reads the viewport live (see\n // getVisibleViewportRect in @jsenv/dom), so a ceiling arriving a debounce\n // later means a box sized for a screen that is gone, placed in the one that\n // replaced it.\n //\n // BIGGER waits for the resize to settle, because growing back is the reading\n // a mobile browser lies about: going straight from one field to the next\n // fires a blur/focus pair that briefly reports the full height again, with\n // the keyboard never having left. Believed, it flicks every popup back to\n // full height and down again between two taps — the \"two inputs\" case in\n // Dialog's own demo. Nothing is lost by waiting: a keyboard that really left\n // stays gone, and the settled event lands 100ms later.\n vv.addEventListener(\"resize\", () => {\n if (\n vv.width < visualViewportWidthSignal.peek() ||\n vv.height < visualViewportHeightSignal.peek()\n ) {\n update();\n }\n });\n subscribeVisualViewportResizeSettled(update);\n vv.addEventListener(\"scroll\", update);\n}\n\n// The app's own screen — the visual viewport, unless the app declared a\n// narrower one with --navi-app-max-width/--navi-app-height (see\n// navi_css_vars.js, which derives --navi-app-width/--navi-app-height from\n// these in CSS). Anything escaping normal flow is sized against this rather\n// than the viewport: an app that simulates a handheld screen keeps that width\n// even for what paints on top of it.\n//\n// The declaration stays in CSS and is read back from there rather than handed\n// to navi a second time in JS — a JS copy would be the one that goes stale.\n// Read on the spot rather than cached in a signal: the only caller is a popup\n// resolving its own margin as it places itself, which already reads far more\n// of the DOM than this, and nothing then has to be invalidated when the value\n// changes.\nconst unresolvableWarned = new Set();\nconst readAppMax = (propertyName) => {\n const declared = getComputedStyle(document.documentElement)\n .getPropertyValue(propertyName)\n .trim();\n if (!declared) {\n return Infinity;\n }\n // A custom property computes to a token stream, not to a length: \"40rem\"\n // arrives here as the string \"40rem\", and parseFloat would read it as 40\n // pixels. Only px is accepted — an app declaring the screen it simulates has\n // a pixel number to give, and resolving arbitrary lengths would mean laying\n // out a probe element on every read.\n const inPixels = /^([0-9.]+)px$/.exec(declared);\n if (!inPixels) {\n if (!unresolvableWarned.has(propertyName)) {\n unresolvableWarned.add(propertyName);\n // Not silently wrong, just partially applied: CSS still caps the popup's\n // size with the declared length, only the margin it keeps with the edges\n // falls back to a share of the viewport (the pre-token behavior).\n console.warn(\n `${propertyName}=\"${declared}\" must be a length in pixels (\"600px\"). Until then popups keep viewport-sized margins.`,\n );\n }\n return Infinity;\n }\n return parseFloat(inPixels[1]);\n};\nexport const getAppWidth = () =>\n Math.min(visualViewportWidthSignal.value, readAppMax(\"--navi-app-max-width\"));\n// The JS reading of --navi-app-inset-* (see safe_area.js): the centered bands\n// between the window's edges and the app's own rectangle. Handed to\n// @jsenv/dom (setPlacementViewportInsets, wired in navi_css_vars.js) so\n// placement keeps to the same rectangle the CSS size caps describe. The\n// keyboard is deliberately absent, unlike in the CSS twin: the placement\n// viewport already subtracts the keyboard overlay itself (see\n// getVisibleViewportRect in @jsenv/dom's visible_rect.js), so carrying it\n// here too would count it twice.\nexport const getAppInsets = () => {\n const vvWidth = visualViewportWidthSignal.value;\n const vvHeight = visualViewportHeightSignal.value;\n const appMaxWidth = readAppMax(\"--navi-app-max-width\");\n const appMaxHeight = readAppMax(\"--navi-app-max-height\");\n const bandX = appMaxWidth < vvWidth ? (vvWidth - appMaxWidth) / 2 : 0;\n const bandY = appMaxHeight < vvHeight ? (vvHeight - appMaxHeight) / 2 : 0;\n return { left: bandX, top: bandY, right: bandX, bottom: bandY };\n};\n// Minus what the keyboard covers, so this stays the JS reading of the very\n// same rectangle --navi-app-height describes in CSS (see safe_area.js's own\n// --navi-keyboard-inset-bottom). Zero unless the app opted into the keyboard\n// overlaying its content — otherwise the shrinking visual viewport above has\n// already accounted for it, and subtracting again would count it twice.\nexport const getAppHeight = () =>\n Math.max(\n 0,\n Math.min(\n visualViewportHeightSignal.value,\n readAppMax(\"--navi-app-max-height\"),\n ) - getVirtualKeyboardOverlayHeight(),\n );\n\n// Whether the primary input is a finger rather than a mouse. A pointer type is\n// not a size: a narrow desktop window is still a mouse, and a large tablet is\n// still a finger — so anything sized for the on-screen keyboard must key off\n// this, never off windowWidthSignal. Thumb reach needs both, which is what\n// smallTouchScreenSignal below answers.\nconst coarsePointerQuery = window.matchMedia\n ? window.matchMedia(\"(pointer: coarse)\")\n : null;\nexport const coarsePointerSignal = signal(\n coarsePointerQuery ? coarsePointerQuery.matches : false,\n);\nif (coarsePointerQuery) {\n coarsePointerQuery.addEventListener(\"change\", () => {\n coarsePointerSignal.value = coarsePointerQuery.matches;\n });\n}\n\n// Whether the screen is one a bottom sheet actually suits: a finger *and* a\n// screen whose bottom edge stays where the thumb already is. Touch alone is not\n// enough — a tall touch screen (a tablet, a kiosk panel) docks a sheet a whole\n// screen away from where the finger just tapped, which is worse than the\n// centered box it replaced.\n//\n// A phone is recognized by its SHAPE, not by a box of maximum dimensions: what\n// makes the bottom edge reachable is holding a narrow slab, and phones keep\n// growing along their long side (20:9, 21:9) while staying just as narrow. So\n// each orientation is answered on the short side plus the elongation:\n// - upright: narrow enough to be held in one hand, and taller than it is wide.\n// Its height is deliberately unbounded — a very tall narrow screen is the\n// case a bottom sheet is most for, not the case to exclude.\n// - on its side: short enough that the bottom edge is a thumb away whatever the\n// width, and wider than it is tall.\n// A tablet fails both: it is too wide upright, and too tall on its side — the\n// smallest one already starts around 740 CSS px on its short side, and the\n// bound below leaves that gap deliberately wide rather than cutting close to\n// the largest phone.\n//\n// Read off window, not visualViewport: the virtual keyboard shrinks the visual\n// viewport while the user types, and a dialog must not undock mid-interaction\n// because a keyboard opened under it.\nconst HANDHELD_MAX_SHORT_SIDE = 600;\n// Enough elongation to tell a slab from a square-ish panel; a phone is well\n// past it (1.7 and up) in either orientation.\nconst HANDHELD_MIN_RATIO = 1.2;\nexport const smallTouchScreenSignal = computed(() => {\n if (!coarsePointerSignal.value) {\n return false;\n }\n const width = windowWidthSignal.value;\n const height = windowHeightSignal.value;\n if (width <= HANDHELD_MAX_SHORT_SIDE) {\n return height >= width * HANDHELD_MIN_RATIO;\n }\n if (height <= HANDHELD_MAX_SHORT_SIDE) {\n return width >= height * HANDHELD_MIN_RATIO;\n }\n return false;\n});\n",
14
14
  "/**\n * The part of the window an app actually has, in two levels.\n *\n * Two, and not one, for a reason worth stating up front: a fixed bar is one of\n * the things that reduce the free region, so it cannot ALSO be placed against\n * that region — it would push itself off the edge it is pinned to. What is\n * anchored and what is anchored-inside are two different rectangles.\n *\n * 1. `--navi-app-inset-{top,right,bottom,left}` — from the window's edges to\n * the app's own rectangle. Whatever is pinned to an edge (a fixed bar, a\n * side panel, a popup aimed at a corner) is pinned to THAT, so an app\n * pretending to be a 600px handheld inside a 1500px window stays one\n * rectangle instead of a column with its furniture spread across the glass.\n *\n * 2. `--navi-safe-area-inset-{top,right,bottom,left}` — from the window's edges\n * to the band left free INSIDE that rectangle. Whatever flows, scrolls, or\n * gets painted keeps to it.\n *\n * Level 2 is a sum, and the contract for taking part in it is only \"publish\n * what you take on one edge\": the device's own notch (`env(safe-area-inset-*)`,\n * which is the browser's version of this very idea), the fixed bars\n * (fixed_bar_space.js), and anything an app adds. That is the point of naming\n * it at all — a component that must stay clear of what covers the screen reads\n * ONE set of numbers, and never has to learn what is covering it.\n *\n * `max()` between the notch and the bars rather than a sum: a bar pinned to an\n * edge already reaches under the notch and counts it in its own size (see\n * fixed_bar.jsx), so adding both would reserve it twice.\n *\n * JS placement answers to the level-1 rectangle too: getAppInsets\n * (layout/responsive.js) is its reading of these same bands, handed to\n * pickPositionRelativeTo via setPlacementViewportInsets (see\n * navi_css_vars.js).\n */\n\nconst SAFE_AREA_CSS = /* css */ `\n /* Declared as lengths so that they COMPUTE to one: an unregistered custom\n property keeps the calc() it was written as, and the sum below is then a\n string no one can read back. Reading it off the computed style — which a\n route transition does, to keep the band the page being left had (see\n nav/transition_window.js) — only works for a registered property. */\n @property --navi-safe-area-inset-top {\n syntax: \"<length>\";\n inherits: true;\n initial-value: 0px;\n }\n @property --navi-safe-area-inset-right {\n syntax: \"<length>\";\n inherits: true;\n initial-value: 0px;\n }\n @property --navi-safe-area-inset-bottom {\n syntax: \"<length>\";\n inherits: true;\n initial-value: 0px;\n }\n @property --navi-safe-area-inset-left {\n syntax: \"<length>\";\n inherits: true;\n initial-value: 0px;\n }\n\n @layer navi {\n /* Layered whole, rules included: the two rules below are offers, not\n structure. [data-navi-safe-area] is an attribute the app puts on its own\n scroller, so the app's own padding on that element has to win over what\n navi suggests for it. */\n :root {\n /* The room each kind of furniture takes, declared here at zero and\n written by whoever takes it. A slot rather than a value: the sum below\n has to be readable whether or not the app ever mounts a fixed bar. */\n --navi-fixed-bar-space-top: 0px;\n --navi-fixed-bar-space-right: 0px;\n --navi-fixed-bar-space-bottom: 0px;\n --navi-fixed-bar-space-left: 0px;\n\n /* What the on-screen keyboard covers — and ONLY where it overlays the\n content rather than shrinking the viewport, which is navi's default\n wherever the browser has the VirtualKeyboard API (see\n layout/virtual_keyboard.js). Zero on Firefox/Safari, which have no\n such API, and zero for an app that called\n disableVirtualKeyboardOverlay(): both get a keyboard that shrinks the\n visual viewport instead, which --navi-vvh already tracks. Reading\n env() rather than a JS-written value keeps it live: the keyboard\n slides in over several frames and this follows it without a\n listener. */\n --navi-keyboard-inset-bottom: env(keyboard-inset-height, 0px);\n\n /* Level 1. Centered bands, so that declaring one ceiling\n (--navi-app-max-width) is all an app has to do to be a narrow screen in\n a wide window; an app that wants them uneven writes these directly. */\n --navi-app-inset-top: max(\n 0px,\n (var(--navi-vvh) - var(--navi-app-max-height, var(--navi-vvh))) / 2\n );\n /* The keyboard on top of the band, and on this edge only: it eats into\n the app's own rectangle exactly like a viewport that shrank, which is\n what makes both paths end up at the same --navi-app-height (and so at\n the same dialog/popover ceiling). Not part of the centering, hence\n added here rather than folded into --navi-app-inset-top: a keyboard\n takes the bottom, it doesn't re-center anything. */\n --navi-app-inset-bottom: calc(\n var(--navi-app-inset-top) + var(--navi-keyboard-inset-bottom)\n );\n --navi-app-inset-left: max(\n 0px,\n (var(--navi-vvw) - var(--navi-app-max-width, var(--navi-vvw))) / 2\n );\n --navi-app-inset-right: var(--navi-app-inset-left);\n\n /* Level 2. */\n --navi-safe-area-inset-top: calc(\n var(--navi-app-inset-top) +\n max(env(safe-area-inset-top), var(--navi-fixed-bar-space-top))\n );\n --navi-safe-area-inset-right: calc(\n var(--navi-app-inset-right) +\n max(env(safe-area-inset-right), var(--navi-fixed-bar-space-right))\n );\n --navi-safe-area-inset-bottom: calc(\n var(--navi-app-inset-bottom) +\n max(env(safe-area-inset-bottom), var(--navi-fixed-bar-space-bottom))\n );\n --navi-safe-area-inset-left: calc(\n var(--navi-app-inset-left) +\n max(env(safe-area-inset-left), var(--navi-fixed-bar-space-left))\n );\n\n /* The document is the scrollport in the common case, and something the\n browser scrolls to — an anchor, a focused field, a restored position —\n landing under a bar is never what anyone wants. */\n scroll-padding-top: var(--navi-safe-area-inset-top);\n scroll-padding-right: var(--navi-safe-area-inset-right);\n scroll-padding-bottom: var(--navi-safe-area-inset-bottom);\n scroll-padding-left: var(--navi-safe-area-inset-left);\n }\n\n /* Put this on whatever scrolls under the furniture.\n\n There are TWO rooms to give back, and forgetting the second one is the\n classic bug:\n\n - padding, so the end of the content can be scrolled out from under it.\n Without it the last screenful stays covered, unreachable.\n - scroll-padding, so anything the browser scrolls TO lands in front of it\n rather than under. The padding above does not help here: it moves the\n content, not the place the browser scrolls the target to.\n\n Marked by the app rather than picked by navi: which element scrolls is\n the app's business, and an app with more than one would have to fight a\n component that chose for it. An app is free to read the variables itself\n instead. */\n [data-navi-safe-area] {\n padding-top: var(--navi-safe-area-inset-top);\n padding-right: var(--navi-safe-area-inset-right);\n padding-bottom: var(--navi-safe-area-inset-bottom);\n padding-left: var(--navi-safe-area-inset-left);\n\n scroll-padding-top: var(--navi-safe-area-inset-top);\n scroll-padding-right: var(--navi-safe-area-inset-right);\n scroll-padding-bottom: var(--navi-safe-area-inset-bottom);\n scroll-padding-left: var(--navi-safe-area-inset-left);\n }\n }\n`;\nimport.meta.css = SAFE_AREA_CSS;\n",
15
15
  "/**\n * navi's stance on the on-screen keyboard: it overlays the app rather than\n * resizing the viewport, wherever the browser can be told so (the\n * VirtualKeyboard API — Chromium only). See virtual_keyboard.js in @jsenv/dom\n * for what that trades away and what it gives back.\n *\n * Turned on rather than offered, because navi already sizes everything that\n * escapes normal flow against the app's own rectangle rather than against the\n * window (--navi-app-width/height, see navi_css_vars.js), and\n * --navi-keyboard-inset-bottom (safe_area.js) puts the keyboard into exactly\n * that rectangle. So the two mechanisms reach the same numbers here, and the\n * overlay reaches them without reflowing the page underneath — a resizing\n * viewport is a resize of everything, fired transiently every time focus goes\n * from one input to the next.\n *\n * An app that built its own layout around the viewport shrinking can say so\n * with disableVirtualKeyboardOverlay(), and gets the behavior Firefox and\n * Safari give it anyway.\n *\n * The one thing it hands back to the app: scrolling the focused field into\n * view. A viewport that shrinks makes the browser do it; a keyboard that\n * merely paints over the page leaves whatever is under it under it. navi\n * answers that for what it places itself — a popup is sized and positioned\n * against the app rectangle the keyboard was just subtracted from — and for\n * anything marked [data-navi-safe-area], whose scroll-padding-bottom counts\n * the keyboard in (safe_area.js). A field in a scroller the app never marked\n * is the app's own to handle.\n */\n\nimport { setVirtualKeyboardOverlaysContent } from \"@jsenv/dom\";\n\nsetVirtualKeyboardOverlaysContent(true);\n\nexport const disableVirtualKeyboardOverlay = () => {\n setVirtualKeyboardOverlaysContent(false);\n};\n",
16
- "/**\n * Regroup CSS vars that makes sense to share across all navi components.\n */\nimport { setPlacementViewportInsets } from \"@jsenv/dom\";\nimport { effect } from \"@preact/signals\";\n\nimport {\n getAppInsets,\n visualViewportHeightSignal,\n visualViewportWidthSignal,\n} from \"./layout/responsive.js\";\nimport \"./layout/safe_area.js\";\n// Side-effect import: turns the on-screen keyboard into something that\n// overlays the app instead of resizing the viewport, which is navi's default\n// (see that module for why, and safe_area.js's own\n// --navi-keyboard-inset-bottom for what then reads the geometry). Here rather\n// than in each component: it is one decision about the whole window, and this\n// is the module that already makes those.\nimport \"./layout/virtual_keyboard.js\";\n\nconst button = document.createElement(\"button\");\nbutton.style.display = \"none\";\ndocument.body.appendChild(button);\nconst computedStyle = getComputedStyle(button);\nconst controlDefaultFontFamily = computedStyle.fontFamily;\nconst controlDefaultFontSize = computedStyle.fontSize;\ndocument.body.removeChild(button);\n\nconst css = /* css */ `\n @layer navi {\n :root {\n /* Overridden at runtime with precise VisualViewport pixel values so that dvw/dvh \n (which don't track the virtual keyboard dimensions) are never used in practice on supported browsers. */\n --navi-vvw: 100dvw;\n --navi-vvh: 100dvh;\n\n /* What navi treats as \"the screen\" when it sizes something that escapes\n normal flow (a dialog in the top layer, a popover, anything built on\n them): the app's own rectangle, which is the visual viewport minus the\n bands an app asks for. An app that never spans the whole window says so\n ONCE, without ever naming a component:\n\n :root {\n --navi-app-max-width: 600px;\n }\n\n In pixels — see readAppMax in layout/responsive.js for why.\n\n Typically an app simulating a handheld screen: a column centered in a\n wide window with bands on the sides. A dialog is in the top layer, so\n it answers to the viewport, not to that column — left alone it would\n paint 1500px of modal over a 600px app. Declaring the ceiling here is\n what makes the app's own width apply everywhere, including on top.\n\n It stays a ceiling and nothing else: on a screen narrower than the app\n it never binds, so popups keep shrinking with the phone, and the gap\n each popup keeps with the edges (marginWithContainer) is subtracted\n from it as before. A single popup that genuinely needs more can still\n raise its own maxWidth/maxHeight prop.\n\n Read from the insets rather than as a min() of its own so that the\n width and the placement come from ONE description of where the app is\n (see layout/safe_area.js). Placement follows the same rectangle: see\n setPlacementViewportInsets at the bottom of this file. */\n --navi-app-width: calc(\n var(--navi-vvw) - var(--navi-app-inset-left) - var(\n --navi-app-inset-right\n )\n );\n --navi-app-height: calc(\n var(--navi-vvh) - var(--navi-app-inset-top) - var(\n --navi-app-inset-bottom\n )\n );\n\n --navi-focus-outline-width: 2px;\n --navi-focus-outline-color: light-dark(#4476ff, #3b82f6);\n --navi-loader-color: light-dark(#355fcc, #3b82f6);\n /* The grey rectangle a mobile browser flashes under a finger: we draw\n what a press does ourselves (background, ring, chevron), and the\n browser's rectangle is a square painted over rounded corners.\n Declared here alone because the property is inherited: :root covers\n every element, in and out of navi, so nothing has to remember it.\n Set the token to a color to get the flash back, on the whole app or\n on one subtree. */\n -webkit-tap-highlight-color: var(--navi-tap-highlight-color);\n --navi-tap-highlight-color: transparent;\n\n /* A face of their own for the controls, and nothing else on the page.\n Undeclared here on purpose: controls write in inherit, so what a\n container says reaches the button, the field and the picker inside it,\n and a value on :root would resolve here and wall that off again. Set\n it to give the controls their own face, on the whole app or on one\n subtree:\n\n :root {\n --navi-control-font-family: system-ui;\n }\n */\n --navi-control-font-size: ${controlDefaultFontSize};\n --navi-control-border-radius: 2px;\n /* A checkbox is only ~1em wide: applying a control radius meant for\n buttons/inputs (say 8px) would turn it into a circle and make it read\n as a radio. So it follows the control radius but capped at a quarter\n of its own size. Override this token alone to opt out of the cap. */\n --navi-checkbox-border-radius: min(\n var(--navi-control-border-radius),\n 0.25em\n );\n /* The color a control uses to say \"this one is on\": a checked checkbox,\n a checked radio, an enabled switch. Kept apart from --navi-accent-color\n (the brand color for CTA and selection) because a control that is on\n must stay readable as a control, which usually means a brighter, more\n saturated color than a brand accent.\n The light value matches the browser's own accent so a navi control and\n a native one can sit side by side without reading as two blues. */\n --navi-control-accent-color: light-dark(rgb(24, 117, 255), #3b82f6);\n --navi-control-border-width: 1px;\n --navi-control-border-color: light-dark(#767676, #8e8e93);\n --navi-control-padding-x-default: 2px;\n --navi-control-padding-y-default: 1px;\n /* Global padding defaults — override these to change all button paddings. */\n /* Use --button-padding, --button-padding-x, --button-padding-y for per-button overrides. */\n --navi-button-padding-x-default: 6px;\n --navi-button-padding-y-default: 1px;\n /* Read by Button, and by whatever is drawn as one (a picker under\n variant=\"button\"), so the two keep the same surface. */\n --navi-button-background-color: light-dark(#f3f4f6, #2d3748);\n\n /* What a callout says about its message, as a color — and what draws\n as one outside the callout too (the icon a picker in callout mode\n presses, see CalloutStatusIcon). */\n --navi-callout-success-color: #4caf50;\n --navi-callout-info-color: #2196f3;\n --navi-callout-warning-color: #ff9800;\n --navi-callout-error-color: #f44336;\n /* No status: the message is an aside, said without an icon and framed\n like a control rather than like a warning. */\n --navi-callout-neutral-color: var(--navi-control-border-color);\n /* For list item we need slightly more padding to be able to see radio/checkbox outline */\n --navi-list-item-padding-x-default: 4px;\n --navi-list-item-padding-y-default: 1px;\n /* default */\n --navi-picker-padding-x-default: var(--navi-control-padding-x-default);\n --navi-picker-padding-y-default: var(--navi-control-padding-y-default);\n\n --navi-popup-border-radius: 8px;\n --navi-popup-border-color: light-dark(#d0d0d0, #3b3b3b);\n --navi-popup-box-shadow:\n 0 4px 8px rgba(0, 0, 0, 0.08), 0 12px 40px rgba(0, 0, 0, 0.22);\n /* A popup's paper is the same paper as everything else's: derived from\n the surface token so one override themes fields, layouts and popups\n together. Still its own token, so popups alone can be re-papered. */\n --navi-popup-background-color: var(--navi-surface-color);\n /* The ink written on that paper. A popup declares both on itself (see\n dialog.jsx / popover.jsx): it is a new surface, so it does not write\n in whatever the container it was declared in writes in. */\n --navi-popup-color: var(--navi-surface-text-color);\n /* A backdrop's paint is a colour AND a filter, one pair per kind of\n backdrop: how much the page behind must stop competing for the eye is\n a different question from what an outside click does, so a backdrop\n that closes on that click can blur too. Only \"capture\" blurs by\n default. */\n --navi-backdrop-close-background: rgba(0, 0, 0, 0.08);\n --navi-backdrop-close-backdrop-filter: none;\n /* backdropVariant=\"discrete\": the popup still catches every outside\n click, it just stops announcing that it did. For an affordance one\n reaches past rather than through — the dim is there to mark the layer,\n not to push the page behind it away. */\n --navi-backdrop-discrete-background: rgba(0, 0, 0, 0.02);\n --navi-backdrop-discrete-backdrop-filter: none;\n /* \"capture\" means the rest of the page is fully non-interactive —\n blurred, not just dimmed, so it reads as clearly secondary and\n pulls visual focus onto the popover's own content. */\n --navi-backdrop-capture-background: rgb(255 255 255 / 0.08);\n --navi-backdrop-capture-backdrop-filter: blur(30px) saturate(180%);\n /* animation=\"lifting\": the popup is what the anchor became, so the page\n it came out of is not a context to keep readable — it is the thing the\n movement leaves. A card, a plan, a picture lifted to be looked at wants\n nothing legible competing with it, and a document still crisp behind a\n box that is still travelling reads as two movements at once. Dark in\n both schemes on purpose: what withdraws here is the page itself, the\n way it does around a photo, not a surface tinted to match a theme. */\n --navi-backdrop-lift-background: rgb(6 10 20 / 88%);\n --navi-backdrop-lift-backdrop-filter: blur(4px);\n\n /* Link colors. They live here rather than only on .navi_link because a\n var declared on the element itself always beats the same var inherited\n from an ancestor: a page setting --link-color-pressed on :root would\n never reach a link. These :root tokens are the theme-level surface;\n --link-color-* stays the per-link (or per-subtree) override. */\n --navi-link-color: rgb(0, 0, 238);\n /* --navi-link-color-visited is intentionally left undefined: by default a\n visited link is derived from whatever --link-color ended up being on\n the link itself (see link.jsx), which a :root token cannot see. Set it\n here from an app to pin one visited color for every link. */\n --navi-link-color-pressed: red;\n --navi-link-current-indicator-color: rgb(205, 52, 37);\n\n --navi-selection-border-color: #0078d4;\n --navi-selection-background-color: #eaf1fd;\n /* Accent color — used for call-to-action buttons and selected list items.\n Override this single variable to apply a consistent brand color across\n all components that need to stand out. */\n --navi-accent-color: rgb(3, 30, 60);\n /* The surface a control's content sits on — the \"paper\" behind the text.\n Fields use it whenever they need a solid background (their default\n background, a transparent field being edited, …). */\n --navi-surface-color: light-dark(#ffffff, #1c1c1e);\n /* What is written on that paper. The browser's own text color rather\n than a literal, so it follows color-scheme the way the paper does. */\n --navi-surface-text-color: CanvasText;\n /* The plane the app's own frame is painted on — a top bar, a side menu, a\n toolbar: everything that surrounds a screen rather than being in it.\n A step away from the paper, because a bar painted in the paper's own\n color on a page of that color is not a bar, it is a line. Derived from\n the paper rather than written as a literal so it follows the theme by\n construction: a step toward the dark on a light page, toward the light\n on a dark one. Reached as background=\"chrome\" on a Box. */\n --navi-chrome-color: color-mix(\n in srgb,\n var(--navi-surface-color) 94%,\n var(--navi-color-dark)\n );\n /* The line that separates two regions of one surface — a scrolling area's\n header from what scrolls under it, for instance. Not a border: the\n separation belongs to the layout, not to the box that draws it. */\n --navi-separator-color-default: #d1d9e0;\n --navi-color-white: white;\n --navi-color-dark: rgb(55, 60, 69);\n\n --navi-info-color-light: #eaf6fc;\n --navi-info-color: #376cc2;\n --navi-success-color-light: #ecf9ef;\n --navi-success-color: #50c464;\n --navi-warning-color-light: #fdf6e3;\n --navi-warning-color: #f19c05;\n --navi-error-color-light: #fcebed;\n --navi-error-color: #eb364b;\n\n --navi-xxs: 0.125em; /* = 2px at 16px base */\n --navi-xs: 0.25em; /* = 4px at 16px base */\n --navi-s: 0.5em; /* = 8px at 16px base */\n --navi-m: 1em; /* = 16px at 16px base (base font size) */\n --navi-l: 1.5em; /* = 24px at 16px base */\n --navi-xl: 2em; /* = 32px at 16px base */\n --navi-xxl: 3em; /* 48px at 16px base */\n\n --navi-typo-xxs: 0.625rem; /* 10px at 16px base */\n --navi-typo-xs: 0.75rem; /* 12px at 16px base */\n --navi-typo-s: 0.875rem; /* 14px at 16px base */\n --navi-typo-m: 1rem; /* 16px at 16px base (base font size) */\n --navi-typo-l: 1.125rem; /* 18px at 16px base */\n --navi-typo-xl: 1.25rem; /* 20px at 16px base */\n --navi-typo-xxl: 1.5rem; /* 24px at 16px base */\n\n /* The line every text is written on, controls included. A number\n rather than \"normal\", because of the emoji: its box is taller than a\n letter's, so under \"normal\" the one line carrying one stands taller\n than the lines around it, and under a tighter line its top is cut.\n 1.25 is where neither happens — 1 clips the glyph, 1.5 spaces the rows\n out more than reading them asks for — which also makes it the floor\n for an app that displays what people typed.\n The document is written on it; the components that come with a line of\n their own from the browser (Button, Input, Textarea, Select) are handed\n it by name. One number everywhere is what keeps a value on the same\n line whether it is typed in a field or drawn in the page.\n See docs/typography.md. */\n --navi-line-height: 1.25;\n /* The face everything is written in, controls included — they inherit\n it rather than carrying one of their own, so an app names its typeface\n once, wherever it wants it to start: on the document, on a section, on\n a popup opened with font=\"…\". The browser's own control face rather\n than the document's default, so that a page saying nothing gets its\n text and its buttons in one face instead of two.\n Layered like the line above, so the app's own rule wins. */\n font-family: ${controlDefaultFontFamily};\n /* Layered: the document's line is what navi writes on when the app says\n nothing, so the app's own body rule wins. */\n line-height: var(--navi-line-height);\n /* The same line for a control, snapped to the pixel. The browser lays a\n line out at its exact height but paints the glyph on a pixel row: at\n the default control size (13.333px) the line is 16.666px, and the\n two-thirds that do not fit go entirely under the glyph, which then\n sits a pixel above the middle of its field. A whole number of pixels\n has no remainder to put anywhere. Written with em so it resolves on\n the control that uses it, at that control's own size. */\n --navi-control-line-height: round(\n calc(var(--navi-line-height) * 1em),\n 1px\n );\n\n /* Color keywords.\n primary: the ink of the paper, at full strength. An absolute\n rather than currentColor: it is what brings a run back\n to plain text inside a muted one (a value in a secondary\n label). Themed through --navi-surface-text-color.\n secondary: supporting text, captions, less important labels\n emphasis: reinforce meaning, make content stand out more\n discrete: unobtrusive elements that shouldn't compete for attention\n hint: barely-there color, watermarks, ghost placeholders\n The last four mix currentColor toward transparent or black, so they\n follow whatever ink a container writes in: a dark card sets color and\n nothing else. The share of ink in each is the theme's knob, a -mix\n token read wherever the formulas are declared — here and on each\n surface that re-declares them (rules below) — so a ratio set on :root\n reaches the page and its popups alike. Set on a container it reaches\n none of that container's own text, a var() resolving where its custom\n property is declared; a container that wants one keyword otherwise\n for ITS paper (a white at 88% where 80% of white reads too faint on a\n colored resin) pins the keyword itself, and that value stops at the\n next surface. */\n --navi-color-secondary-mix: 80%;\n --navi-color-emphasis-mix: 50%;\n --navi-color-discrete-mix: 60%;\n --navi-color-hint-mix: 25%;\n --navi-color-primary: var(--navi-surface-text-color);\n\n /* What a control shows while it holds nothing: the ::placeholder of an\n input, the empty value slot of a picker. One place for the whole app:\n\n :root {\n --navi-placeholder-color: #8a94a6;\n --navi-placeholder-font-style: italic;\n }\n */\n --navi-placeholder-color: var(--navi-color-discrete);\n --navi-placeholder-font-style: normal;\n }\n\n /* A surface is a new paper: it writes in an ink of its own, and the\n keywords below are computed against that ink rather than the\n container's. A popup writes in --navi-popup-color. */\n .navi_popover,\n .navi_dialog {\n --navi-color-primary: var(--navi-popup-color);\n }\n /* A callout writes in the UA's own ink: callout.js sets color: revert on\n a [popover] element, which the UA styles CanvasText. */\n .navi_callout {\n --navi-color-primary: CanvasText;\n }\n\n /* The keywords derived from the ink, declared on every paper — :root, and\n each surface that is a new one — so what a container pinned for its own\n paper stops at the surface. The -mix ratios (see :root) are read where\n this is declared, and each paper resolves currentColor as its own. On\n the element itself, so a surface beats the container's value whatever\n the layer; an app that wants a surface to keep its container's ink says\n so on the surface, unlayered, and wins in turn. */\n :root,\n .navi_popover,\n .navi_dialog,\n .navi_callout {\n --navi-color-secondary: color-mix(\n in srgb,\n currentColor var(--navi-color-secondary-mix),\n transparent\n );\n --navi-color-emphasis: color-mix(\n in srgb,\n currentColor var(--navi-color-emphasis-mix),\n black\n );\n --navi-color-discrete: color-mix(\n in srgb,\n currentColor var(--navi-color-discrete-mix),\n transparent\n );\n --navi-color-hint: color-mix(\n in srgb,\n currentColor var(--navi-color-hint-mix),\n transparent\n );\n }\n }\n\n /* Hidden appearance */\n input[navi-visually-hidden],\n button[navi-visually-hidden],\n div[navi-visually-hidden] {\n position: absolute;\n top: 0;\n left: 0;\n z-index: -1;\n /* Important to take full size so that scrollIntoView work as expected */\n width: 100%;\n height: 100%;\n margin: 0;\n padding: 0;\n white-space: nowrap;\n border: 0;\n clip-path: inset(50%);\n appearance: none;\n overflow: hidden;\n\n &[navi-debug] {\n position: static;\n width: auto;\n height: auto;\n margin: 0;\n clip-path: none;\n appearance: auto;\n }\n }\n`;\nimport.meta.css = css;\n\neffect(() => {\n document.documentElement.style.setProperty(\n \"--navi-vvw\",\n `${visualViewportWidthSignal.value}px`,\n );\n document.documentElement.style.setProperty(\n \"--navi-vvh\",\n `${visualViewportHeightSignal.value}px`,\n );\n});\n\n// Placement follows the same rectangle the size caps above describe: the JS\n// that positions popups (pickPositionRelativeTo in @jsenv/dom) computes\n// against the visual viewport narrowed by the app's own bands, so a dialog\n// centers on the app column and a side panel docks flush against the app's\n// edge rather than the window's. Here rather than in each component, for the\n// same reason as virtual_keyboard.js above: one decision about the whole\n// window.\nsetPlacementViewportInsets(getAppInsets);\n"
16
+ "/**\n * Regroup CSS vars that makes sense to share across all navi components.\n */\nimport { setPlacementViewportInsets } from \"@jsenv/dom\";\nimport { effect } from \"@preact/signals\";\n\nimport {\n getAppInsets,\n visualViewportHeightSignal,\n visualViewportWidthSignal,\n} from \"./layout/responsive.js\";\nimport \"./layout/safe_area.js\";\n// Side-effect import: turns the on-screen keyboard into something that\n// overlays the app instead of resizing the viewport, which is navi's default\n// (see that module for why, and safe_area.js's own\n// --navi-keyboard-inset-bottom for what then reads the geometry). Here rather\n// than in each component: it is one decision about the whole window, and this\n// is the module that already makes those.\nimport \"./layout/virtual_keyboard.js\";\n\nconst button = document.createElement(\"button\");\nbutton.style.display = \"none\";\ndocument.body.appendChild(button);\nconst computedStyle = getComputedStyle(button);\nconst controlDefaultFontFamily = computedStyle.fontFamily;\nconst controlDefaultFontSize = computedStyle.fontSize;\ndocument.body.removeChild(button);\n\nconst css = /* css */ `\n @layer navi {\n :root {\n /* Overridden at runtime with precise VisualViewport pixel values so that dvw/dvh \n (which don't track the virtual keyboard dimensions) are never used in practice on supported browsers. */\n --navi-vvw: 100dvw;\n --navi-vvh: 100dvh;\n\n /* What navi treats as \"the screen\" when it sizes something that escapes\n normal flow (a dialog in the top layer, a popover, anything built on\n them): the app's own rectangle, which is the visual viewport minus the\n bands an app asks for. An app that never spans the whole window says so\n ONCE, without ever naming a component:\n\n :root {\n --navi-app-max-width: 600px;\n }\n\n In pixels — see readAppMax in layout/responsive.js for why.\n\n Typically an app simulating a handheld screen: a column centered in a\n wide window with bands on the sides. A dialog is in the top layer, so\n it answers to the viewport, not to that column — left alone it would\n paint 1500px of modal over a 600px app. Declaring the ceiling here is\n what makes the app's own width apply everywhere, including on top.\n\n It stays a ceiling and nothing else: on a screen narrower than the app\n it never binds, so popups keep shrinking with the phone, and the gap\n each popup keeps with the edges (marginWithContainer) is subtracted\n from it as before. A single popup that genuinely needs more can still\n raise its own maxWidth/maxHeight prop.\n\n Read from the insets rather than as a min() of its own so that the\n width and the placement come from ONE description of where the app is\n (see layout/safe_area.js). Placement follows the same rectangle: see\n setPlacementViewportInsets at the bottom of this file. */\n --navi-app-width: calc(\n var(--navi-vvw) - var(--navi-app-inset-left) - var(\n --navi-app-inset-right\n )\n );\n --navi-app-height: calc(\n var(--navi-vvh) - var(--navi-app-inset-top) - var(\n --navi-app-inset-bottom\n )\n );\n\n --navi-focus-outline-width: 2px;\n --navi-focus-outline-color: light-dark(#4476ff, #3b82f6);\n --navi-loader-color: light-dark(#355fcc, #3b82f6);\n /* The grey rectangle a mobile browser flashes under a finger: we draw\n what a press does ourselves (background, ring, chevron), and the\n browser's rectangle is a square painted over rounded corners.\n Declared here alone because the property is inherited: :root covers\n every element, in and out of navi, so nothing has to remember it.\n Set the token to a color to get the flash back, on the whole app or\n on one subtree. */\n -webkit-tap-highlight-color: var(--navi-tap-highlight-color);\n --navi-tap-highlight-color: transparent;\n\n /* A face of their own for the controls, and nothing else on the page.\n Undeclared here on purpose: controls write in inherit, so what a\n container says reaches the button, the field and the picker inside it,\n and a value on :root would resolve here and wall that off again. Set\n it to give the controls their own face, on the whole app or on one\n subtree:\n\n :root {\n --navi-control-font-family: system-ui;\n }\n */\n --navi-control-font-size: ${controlDefaultFontSize};\n --navi-control-border-radius: 2px;\n /* A checkbox is only ~1em wide: applying a control radius meant for\n buttons/inputs (say 8px) would turn it into a circle and make it read\n as a radio. So it follows the control radius but capped at a quarter\n of its own size. Override this token alone to opt out of the cap. */\n --navi-checkbox-border-radius: min(\n var(--navi-control-border-radius),\n 0.25em\n );\n /* The color a control uses to say \"this one is on\": a checked checkbox,\n a checked radio, an enabled switch. Kept apart from --navi-accent-color\n (the brand color for CTA and selection) because a control that is on\n must stay readable as a control, which usually means a brighter, more\n saturated color than a brand accent.\n The light value matches the browser's own accent so a navi control and\n a native one can sit side by side without reading as two blues. */\n --navi-control-accent-color: light-dark(rgb(24, 117, 255), #3b82f6);\n --navi-control-border-width: 1px;\n --navi-control-border-color: light-dark(#767676, #8e8e93);\n --navi-control-padding-x-default: 2px;\n --navi-control-padding-y-default: 1px;\n /* Global padding defaults — override these to change all button paddings. */\n /* Use --button-padding, --button-padding-x, --button-padding-y for per-button overrides. */\n --navi-button-padding-x-default: 6px;\n --navi-button-padding-y-default: 1px;\n /* Read by Button, and by whatever is drawn as one (a picker under\n variant=\"button\"), so the two keep the same surface. */\n --navi-button-background-color: light-dark(#f3f4f6, #2d3748);\n\n /* What a callout says about its message, as a color — and what draws\n as one outside the callout too (the icon a picker in callout mode\n presses, see CalloutStatusIcon). */\n --navi-callout-success-color: #4caf50;\n --navi-callout-info-color: #2196f3;\n --navi-callout-warning-color: #ff9800;\n --navi-callout-error-color: #f44336;\n /* No status: the message is an aside, said without an icon and framed\n like a control rather than like a warning. */\n --navi-callout-neutral-color: var(--navi-control-border-color);\n /* For list item we need slightly more padding to be able to see radio/checkbox outline */\n --navi-list-item-padding-x-default: 4px;\n --navi-list-item-padding-y-default: 1px;\n /* default */\n --navi-picker-padding-x-default: var(--navi-control-padding-x-default);\n --navi-picker-padding-y-default: var(--navi-control-padding-y-default);\n\n --navi-popup-border-radius: 8px;\n --navi-popup-border-color: light-dark(#d0d0d0, #3b3b3b);\n --navi-popup-box-shadow:\n 0 4px 8px rgba(0, 0, 0, 0.08), 0 12px 40px rgba(0, 0, 0, 0.22);\n /* A popup's paper is the same paper as everything else's: derived from\n the surface token so one override themes fields, layouts and popups\n together. Still its own token, so popups alone can be re-papered. */\n --navi-popup-background-color: var(--navi-surface-color);\n /* The ink written on that paper. A popup declares both on itself (see\n dialog.jsx / popover.jsx): it is a new surface, so it does not write\n in whatever the container it was declared in writes in. */\n --navi-popup-color: var(--navi-surface-text-color);\n /* A backdrop's paint is a colour AND a filter, one pair per kind of\n backdrop: how much the page behind must stop competing for the eye is\n a different question from what an outside click does, so a backdrop\n that closes on that click can blur too. Only \"capture\" blurs by\n default. */\n --navi-backdrop-close-background: rgba(0, 0, 0, 0.08);\n --navi-backdrop-close-backdrop-filter: none;\n /* backdropVariant=\"discrete\": the popup still catches every outside\n click, it just stops announcing that it did. For an affordance one\n reaches past rather than through — the dim is there to mark the layer,\n not to push the page behind it away. */\n --navi-backdrop-discrete-background: rgba(0, 0, 0, 0.02);\n --navi-backdrop-discrete-backdrop-filter: none;\n /* \"capture\" means the rest of the page is fully non-interactive —\n blurred, not just dimmed, so it reads as clearly secondary and\n pulls visual focus onto the popover's own content. */\n --navi-backdrop-capture-background: rgb(255 255 255 / 0.08);\n --navi-backdrop-capture-backdrop-filter: blur(30px) saturate(180%);\n /* animation=\"lifting\", and backdropVariant=\"lift\" asking for the same\n wall without the movement: the popup is what the anchor became, so the page\n it came out of is not a context to keep readable — it is the thing the\n movement leaves. A card, a plan, a picture lifted to be looked at wants\n nothing legible competing with it, and a document still crisp behind a\n box that is still travelling reads as two movements at once. Dark in\n both schemes on purpose: what withdraws here is the page itself, the\n way it does around a photo, not a surface tinted to match a theme. */\n --navi-backdrop-lift-background: rgb(6 10 20 / 88%);\n --navi-backdrop-lift-backdrop-filter: blur(4px);\n\n /* Link colors. They live here rather than only on .navi_link because a\n var declared on the element itself always beats the same var inherited\n from an ancestor: a page setting --link-color-pressed on :root would\n never reach a link. These :root tokens are the theme-level surface;\n --link-color-* stays the per-link (or per-subtree) override. */\n --navi-link-color: rgb(0, 0, 238);\n /* --navi-link-color-visited is intentionally left undefined: by default a\n visited link is derived from whatever --link-color ended up being on\n the link itself (see link.jsx), which a :root token cannot see. Set it\n here from an app to pin one visited color for every link. */\n --navi-link-color-pressed: red;\n --navi-link-current-indicator-color: rgb(205, 52, 37);\n\n --navi-selection-border-color: #0078d4;\n --navi-selection-background-color: #eaf1fd;\n /* Accent color — used for call-to-action buttons and selected list items.\n Override this single variable to apply a consistent brand color across\n all components that need to stand out. */\n --navi-accent-color: rgb(3, 30, 60);\n /* The surface a control's content sits on — the \"paper\" behind the text.\n Fields use it whenever they need a solid background (their default\n background, a transparent field being edited, …). */\n --navi-surface-color: light-dark(#ffffff, #1c1c1e);\n /* What is written on that paper. The browser's own text color rather\n than a literal, so it follows color-scheme the way the paper does. */\n --navi-surface-text-color: CanvasText;\n /* The plane the app's own frame is painted on — a top bar, a side menu, a\n toolbar: everything that surrounds a screen rather than being in it.\n A step away from the paper, because a bar painted in the paper's own\n color on a page of that color is not a bar, it is a line. Derived from\n the paper rather than written as a literal so it follows the theme by\n construction: a step toward the dark on a light page, toward the light\n on a dark one. Reached as background=\"chrome\" on a Box. */\n --navi-chrome-color: color-mix(\n in srgb,\n var(--navi-surface-color) 94%,\n var(--navi-color-dark)\n );\n /* The line that separates two regions of one surface — a scrolling area's\n header from what scrolls under it, for instance. Not a border: the\n separation belongs to the layout, not to the box that draws it. */\n --navi-separator-color-default: #d1d9e0;\n --navi-color-white: white;\n --navi-color-dark: rgb(55, 60, 69);\n\n --navi-info-color-light: #eaf6fc;\n --navi-info-color: #376cc2;\n --navi-success-color-light: #ecf9ef;\n --navi-success-color: #50c464;\n --navi-warning-color-light: #fdf6e3;\n --navi-warning-color: #f19c05;\n --navi-error-color-light: #fcebed;\n --navi-error-color: #eb364b;\n\n --navi-xxs: 0.125em; /* = 2px at 16px base */\n --navi-xs: 0.25em; /* = 4px at 16px base */\n --navi-s: 0.5em; /* = 8px at 16px base */\n --navi-m: 1em; /* = 16px at 16px base (base font size) */\n --navi-l: 1.5em; /* = 24px at 16px base */\n --navi-xl: 2em; /* = 32px at 16px base */\n --navi-xxl: 3em; /* 48px at 16px base */\n\n --navi-typo-xxs: 0.625rem; /* 10px at 16px base */\n --navi-typo-xs: 0.75rem; /* 12px at 16px base */\n --navi-typo-s: 0.875rem; /* 14px at 16px base */\n --navi-typo-m: 1rem; /* 16px at 16px base (base font size) */\n --navi-typo-l: 1.125rem; /* 18px at 16px base */\n --navi-typo-xl: 1.25rem; /* 20px at 16px base */\n --navi-typo-xxl: 1.5rem; /* 24px at 16px base */\n\n /* The line every text is written on, controls included. A number\n rather than \"normal\", because of the emoji: its box is taller than a\n letter's, so under \"normal\" the one line carrying one stands taller\n than the lines around it, and under a tighter line its top is cut.\n 1.25 is where neither happens — 1 clips the glyph, 1.5 spaces the rows\n out more than reading them asks for — which also makes it the floor\n for an app that displays what people typed.\n The document is written on it; the components that come with a line of\n their own from the browser (Button, Input, Textarea, Select) are handed\n it by name. One number everywhere is what keeps a value on the same\n line whether it is typed in a field or drawn in the page.\n See docs/typography.md. */\n --navi-line-height: 1.25;\n /* The face everything is written in, controls included — they inherit\n it rather than carrying one of their own, so an app names its typeface\n once, wherever it wants it to start: on the document, on a section, on\n a popup opened with font=\"…\". The browser's own control face rather\n than the document's default, so that a page saying nothing gets its\n text and its buttons in one face instead of two.\n Layered like the line above, so the app's own rule wins. */\n font-family: ${controlDefaultFontFamily};\n /* Layered: the document's line is what navi writes on when the app says\n nothing, so the app's own body rule wins. */\n line-height: var(--navi-line-height);\n /* The same line for a control, snapped to the pixel. The browser lays a\n line out at its exact height but paints the glyph on a pixel row: at\n the default control size (13.333px) the line is 16.666px, and the\n two-thirds that do not fit go entirely under the glyph, which then\n sits a pixel above the middle of its field. A whole number of pixels\n has no remainder to put anywhere. Written with em so it resolves on\n the control that uses it, at that control's own size. */\n --navi-control-line-height: round(\n calc(var(--navi-line-height) * 1em),\n 1px\n );\n\n /* Color keywords.\n primary: the ink of the paper, at full strength. An absolute\n rather than currentColor: it is what brings a run back\n to plain text inside a muted one (a value in a secondary\n label). Themed through --navi-surface-text-color.\n secondary: supporting text, captions, less important labels\n emphasis: reinforce meaning, make content stand out more\n discrete: unobtrusive elements that shouldn't compete for attention\n hint: barely-there color, watermarks, ghost placeholders\n The last four mix currentColor toward transparent or black, so they\n follow whatever ink a container writes in: a dark card sets color and\n nothing else. The share of ink in each is the theme's knob, a -mix\n token read wherever the formulas are declared — here and on each\n surface that re-declares them (rules below) — so a ratio set on :root\n reaches the page and its popups alike. Set on a container it reaches\n none of that container's own text, a var() resolving where its custom\n property is declared; a container that wants one keyword otherwise\n for ITS paper (a white at 88% where 80% of white reads too faint on a\n colored resin) pins the keyword itself, and that value stops at the\n next surface. */\n --navi-color-secondary-mix: 80%;\n --navi-color-emphasis-mix: 50%;\n --navi-color-discrete-mix: 60%;\n --navi-color-hint-mix: 25%;\n --navi-color-primary: var(--navi-surface-text-color);\n\n /* What a control shows while it holds nothing: the ::placeholder of an\n input, the empty value slot of a picker. One place for the whole app:\n\n :root {\n --navi-placeholder-color: #8a94a6;\n --navi-placeholder-font-style: italic;\n }\n */\n --navi-placeholder-color: var(--navi-color-discrete);\n --navi-placeholder-font-style: normal;\n }\n\n /* A surface is a new paper: it writes in an ink of its own, and the\n keywords below are computed against that ink rather than the\n container's. A popup writes in --navi-popup-color. */\n .navi_popover,\n .navi_dialog {\n --navi-color-primary: var(--navi-popup-color);\n }\n /* A callout writes in the UA's own ink: callout.js sets color: revert on\n a [popover] element, which the UA styles CanvasText. */\n .navi_callout {\n --navi-color-primary: CanvasText;\n }\n\n /* The keywords derived from the ink, declared on every paper — :root, and\n each surface that is a new one — so what a container pinned for its own\n paper stops at the surface. The -mix ratios (see :root) are read where\n this is declared, and each paper resolves currentColor as its own. On\n the element itself, so a surface beats the container's value whatever\n the layer; an app that wants a surface to keep its container's ink says\n so on the surface, unlayered, and wins in turn. */\n :root,\n .navi_popover,\n .navi_dialog,\n .navi_callout {\n --navi-color-secondary: color-mix(\n in srgb,\n currentColor var(--navi-color-secondary-mix),\n transparent\n );\n --navi-color-emphasis: color-mix(\n in srgb,\n currentColor var(--navi-color-emphasis-mix),\n black\n );\n --navi-color-discrete: color-mix(\n in srgb,\n currentColor var(--navi-color-discrete-mix),\n transparent\n );\n --navi-color-hint: color-mix(\n in srgb,\n currentColor var(--navi-color-hint-mix),\n transparent\n );\n }\n }\n\n /* Hidden appearance */\n input[navi-visually-hidden],\n button[navi-visually-hidden],\n div[navi-visually-hidden] {\n position: absolute;\n top: 0;\n left: 0;\n z-index: -1;\n /* Important to take full size so that scrollIntoView work as expected */\n width: 100%;\n height: 100%;\n margin: 0;\n padding: 0;\n white-space: nowrap;\n border: 0;\n clip-path: inset(50%);\n appearance: none;\n overflow: hidden;\n\n &[navi-debug] {\n position: static;\n width: auto;\n height: auto;\n margin: 0;\n clip-path: none;\n appearance: auto;\n }\n }\n`;\nimport.meta.css = css;\n\neffect(() => {\n document.documentElement.style.setProperty(\n \"--navi-vvw\",\n `${visualViewportWidthSignal.value}px`,\n );\n document.documentElement.style.setProperty(\n \"--navi-vvh\",\n `${visualViewportHeightSignal.value}px`,\n );\n});\n\n// Placement follows the same rectangle the size caps above describe: the JS\n// that positions popups (pickPositionRelativeTo in @jsenv/dom) computes\n// against the visual viewport narrowed by the app's own bands, so a dialog\n// centers on the app column and a side panel docks flush against the app's\n// edge rather than the window's. Here rather than in each component, for the\n// same reason as virtual_keyboard.js above: one decision about the whole\n// window.\nsetPlacementViewportInsets(getAppInsets);\n"
17
17
  ],
18
18
  "names": [],
19
- "mappings": "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"
19
+ "mappings": "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"
20
20
  }
@@ -59538,8 +59538,15 @@ const css$E = /* css */`
59538
59538
  --backdrop-filter: var(--navi-backdrop-capture-backdrop-filter);
59539
59539
  }
59540
59540
  /* backdropVariant, after the rules it overrides: same specificity, so
59541
- order is what decides. The wall is still there either way only the
59542
- paint goes away. */
59541
+ order is what decides. The wall is still there whichever one is asked
59542
+ for — only its paint changes. */
59543
+ /* "lift": the wall a lifted popup brings, asked for on its own. A popup
59544
+ whose content is what must be looked at wants the page gone behind it
59545
+ whether or not it got there by moving. */
59546
+ &[data-backdrop-variant="lift"] {
59547
+ --backdrop-background: var(--navi-backdrop-lift-background);
59548
+ --backdrop-filter: var(--navi-backdrop-lift-backdrop-filter);
59549
+ }
59543
59550
  &[data-backdrop-variant="discrete"] {
59544
59551
  --backdrop-background: var(--navi-backdrop-discrete-background);
59545
59552
  --backdrop-filter: var(--navi-backdrop-discrete-backdrop-filter);
@@ -59737,6 +59744,10 @@ const css$E = /* css */`
59737
59744
  --backdrop-background: var(--navi-backdrop-capture-background);
59738
59745
  --backdrop-filter: var(--navi-backdrop-capture-backdrop-filter);
59739
59746
  }
59747
+ &[data-backdrop-variant="lift"] {
59748
+ --backdrop-background: var(--navi-backdrop-lift-background);
59749
+ --backdrop-filter: var(--navi-backdrop-lift-backdrop-filter);
59750
+ }
59740
59751
  &[data-backdrop-variant="discrete"] {
59741
59752
  --backdrop-background: var(--navi-backdrop-discrete-background);
59742
59753
  --backdrop-filter: var(--navi-backdrop-discrete-backdrop-filter);
@@ -59999,15 +60010,18 @@ const css$E = /* css */`
59999
60010
  * "Outside" is the dialog's own border box; a see-through dialog whose box is
60000
60011
  * bigger than what it paints marks the difference with
60001
60012
  * `data-navi-popup-outside` (see docs/popup_backdrop.md).
60002
- * @param {"auto"|"discrete"|"invisible"} [props.backdropVariant="auto"] - How
60003
- * visible the backdrop is, independently of what it does. `"auto"`: the
60004
- * paint `pointerInteractionOutsideEffect` implies (dimmed for
60013
+ * @param {"auto"|"lift"|"discrete"|"invisible"} [props.backdropVariant="auto"]
60014
+ * - How visible the backdrop is, independently of what it does. `"auto"`:
60015
+ * the paint `pointerInteractionOutsideEffect` implies (dimmed for
60005
60016
  * `"close"`/`"cancel"`, blurred glass for `"capture"`), or the opaque wall
60006
- * `animation="lifting"` asks for. `"discrete"`: a
60007
- * barely-there dim. `"invisible"`: fully transparent a wall that is not
60008
- * seen, still catching every press. This only changes how much the dialog
60009
- * insists visually, never what an outside click does; whether there is a
60010
- * wall to paint at all is `backdrop` above.
60017
+ * `animation="lifting"` asks for. `"lift"`: that same opaque, blurred wall
60018
+ * (`--navi-backdrop-lift-*`) asked for on its own, for a dialog whose
60019
+ * content is the thing to look at a picture, a plan, a card opened full
60020
+ * without the morph. `"discrete"`: a barely-there dim. `"invisible"`:
60021
+ * fully transparent a wall that is not seen, still catching every press.
60022
+ * This only changes how much the dialog insists visually, never what an
60023
+ * outside click does; whether there is a wall to paint at all is `backdrop`
60024
+ * above.
60011
60025
  * @param {string} [props.backdropColor] - The wash painted over what is
60012
60026
  * behind, for this popup alone: any CSS color (`"rgb(6 10 20 / 88%)"`).
60013
60027
  * Wins over `backdropVariant` and over the theme tokens
@@ -60389,9 +60403,10 @@ const useDialogProps = props => {
60389
60403
  // the dialog goes to the same top layer through the Popover API instead.
60390
60404
  backdrop = true,
60391
60405
  // How loudly the backdrop says it is there — independent of what it
60392
- // *does* (that's pointerInteractionOutsideEffect above). "invisible" is a
60393
- // wall that is not seen, not the absence of one: it only stops the dim
60394
- // from being drawn.
60406
+ // *does* (that's pointerInteractionOutsideEffect above). "lift" is the
60407
+ // opaque wall at one end, "invisible" a wall that is not seen at the
60408
+ // other — not the absence of one, it only stops the dim from being
60409
+ // drawn.
60395
60410
  backdropVariant = "auto",
60396
60411
  // The paint itself, when the tokens behind backdropVariant are not what
60397
60412
  // this one dialog wants. Named/forwarded rather than left in ...rest:
@@ -61600,6 +61615,13 @@ const css$D = /* css */`
61600
61615
  them to win. Only the paint changes: the element is still rendered
61601
61616
  and still pointer-events: auto, so an outside click keeps doing
61602
61617
  exactly what pointerInteractionOutsideEffect says. */
61618
+ /* "lift": the wall a lifted popup brings (see navi_css_vars.js), asked
61619
+ for on its own — a popover whose own content is what must be looked at
61620
+ wants the page gone behind it, without moving out of anything. */
61621
+ &[data-backdrop-variant="lift"] {
61622
+ --backdrop-background: var(--navi-backdrop-lift-background);
61623
+ --backdrop-filter: var(--navi-backdrop-lift-backdrop-filter);
61624
+ }
61603
61625
  &[data-backdrop-variant="discrete"] {
61604
61626
  --backdrop-background: var(--navi-backdrop-discrete-background);
61605
61627
  --backdrop-filter: var(--navi-backdrop-discrete-backdrop-filter);
@@ -61691,12 +61713,15 @@ const css$D = /* css */`
61691
61713
  * own border box; a see-through popover whose box is bigger than what it
61692
61714
  * paints marks the difference with `data-navi-popup-outside` (see
61693
61715
  * docs/popup_backdrop.md).
61694
- * @param {"auto"|"discrete"|"invisible"} [props.backdropVariant="auto"] - How
61695
- * visible the backdrop is, independently of what it does. `"auto"`: the
61696
- * paint `pointerInteractionOutsideEffect` implies (dimmed for
61697
- * `"close"`/`"cancel"`, blurred glass for `"capture"`). `"discrete"`: a
61698
- * barely-there dim. `"invisible"`: fully transparent — a wall that is not
61699
- * seen, still rendered and still catching every outside click. This only
61716
+ * @param {"auto"|"lift"|"discrete"|"invisible"} [props.backdropVariant="auto"]
61717
+ * - How visible the backdrop is, independently of what it does. `"auto"`:
61718
+ * the paint `pointerInteractionOutsideEffect` implies (dimmed for
61719
+ * `"close"`/`"cancel"`, blurred glass for `"capture"`). `"lift"`: the
61720
+ * opaque, blurred wall (`--navi-backdrop-lift-*`) a lifted popup brings,
61721
+ * for content that is the thing to look at rather than a surface shown over
61722
+ * a page still being read. `"discrete"`: a barely-there dim. `"invisible"`:
61723
+ * fully transparent — a wall that is not seen, still rendered and still
61724
+ * catching every outside click. This only
61700
61725
  * changes how much the popover insists on being the thing you deal with;
61701
61726
  * whether there is a wall to paint at all is `backdrop` above. Ignored when
61702
61727
  * there is none (`pointerInteractionOutsideEffect="none"`, or
@@ -62031,9 +62056,10 @@ const usePopoverProps = props => {
62031
62056
  backdrop = true,
62032
62057
  // How loudly the backdrop says it is there — independent of what it
62033
62058
  // *does* (that's pointerInteractionOutsideEffect above). "auto" keeps
62034
- // the paint the effect implies; "discrete"/"invisible" tone it down or
62035
- // stop drawing it, without giving up the outside click a wall that is
62036
- // not seen is still a wall (that is `backdrop` above).
62059
+ // the paint the effect implies; "lift" asks for the opaque wall, and
62060
+ // "discrete"/"invisible" tone it down or stop drawing itnone of them
62061
+ // gives up the outside click, a wall that is not seen is still a wall
62062
+ // (that is `backdrop` above).
62037
62063
  backdropVariant = "auto",
62038
62064
  // The paint itself, when the tokens behind backdropVariant are not what
62039
62065
  // this one popover wants. Named/forwarded rather than left in ...rest:
@@ -63033,7 +63059,7 @@ const css$C = /* css */`@layer navi {
63033
63059
  * resolution picks says nothing about whether the page behind stays live.
63034
63060
  * It is also what makes a sheet docked to an edge of a phone's screen
63035
63061
  * (`dockedOnSmallTouchScreen`) non-modal.
63036
- * @param {"auto"|"discrete"|"invisible"} [props.backdropVariant] - Forwarded
63062
+ * @param {"auto"|"lift"|"discrete"|"invisible"} [props.backdropVariant] - Forwarded
63037
63063
  * as-is to whichever component renders (both understand it identically):
63038
63064
  * how visible the backdrop is, independently of what an outside click
63039
63065
  * does — a wall that is not seen is still a wall (that is `backdrop`
@@ -75799,7 +75825,7 @@ const css$n = /* css */`.navi_split_button {
75799
75825
  * dockedOnSmallTouchScreen?: boolean | "top" | "bottom",
75800
75826
  * marginWithContainer?: number | string,
75801
75827
  * backdrop?: boolean,
75802
- * backdropVariant?: "auto" | "discrete" | "invisible",
75828
+ * backdropVariant?: "auto" | "lift" | "discrete" | "invisible",
75803
75829
  * backdropColor?: string,
75804
75830
  * backdropFilter?: string,
75805
75831
  * pointerInteractionOutsideEffect?: "close" | "cancel" | "capture",