@jsenv/navi 0.29.470 → 0.29.471

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.
@@ -39055,8 +39055,29 @@ const resolveFirstChildControl = (el) => {
39055
39055
  }
39056
39056
  return startEl.querySelector("[navi-control-host]");
39057
39057
  };
39058
+ // The element a popup command is about: the closest one keeping an open state.
39058
39059
  const resolveClosestExpandable = (el) => {
39059
- return el.closest("[aria-expanded]");
39060
+ const expandable = el.closest("[aria-expanded]");
39061
+ if (!expandable) {
39062
+ return null;
39063
+ }
39064
+ return expandableRepeatedBy(expandable) || expandable;
39065
+ };
39066
+ // A control's host repeats the aria-expanded of its root, beside its role, for
39067
+ // assistive tech to read (a picker's <input>, a combobox or a button). The root
39068
+ // is the expandable: the host is a leaf the walk lands on only when it is the
39069
+ // source itself, and it carries the control's own `command`/`commandfor`, which
39070
+ // a command resolved again from it (a close after a clear) would follow.
39071
+ const expandableRepeatedBy = (el) => {
39072
+ const controlRoot = findControlRoot(el);
39073
+ if (
39074
+ controlRoot &&
39075
+ controlRoot !== el &&
39076
+ controlRoot.hasAttribute("aria-expanded")
39077
+ ) {
39078
+ return controlRoot;
39079
+ }
39080
+ return null;
39060
39081
  };
39061
39082
  // The surface a send is decided on: the expandable holding the CONTROL that
39062
39083
  // sends, never one that control is itself. A picker's own root carries
@@ -39067,7 +39088,7 @@ const resolveClosestExpandable = (el) => {
39067
39088
  const resolveExpandableAround = (source) => {
39068
39089
  const sender = findControlRoot(source) || source;
39069
39090
  const parent = sender.parentElement;
39070
- return parent ? parent.closest("[aria-expanded]") : null;
39091
+ return parent ? resolveClosestExpandable(parent) : null;
39071
39092
  };
39072
39093
  // An element carrying navi-command-proxy-for="anchorId" stands in for that
39073
39094
  // other element as the command's source when the source is forwarded to
@@ -39368,8 +39389,12 @@ const sendCommand = (source, event, { requester }) => {
39368
39389
  // looking at, and a decision just taken there is a reason to leave it. The
39369
39390
  // NEAREST surface answers, and only that one — a form inside a slide inside a
39370
39391
  // dialog goes back a slide, it does not also close the dialog.
39371
- // send inside expandable
39372
- if (target.getAttribute("aria-expanded") === "true") {
39392
+ // send inside expandable — the control itself when it sends from its host,
39393
+ // whose aria-expanded is its root's (see expandableRepeatedBy)
39394
+ if (
39395
+ target.getAttribute("aria-expanded") === "true" &&
39396
+ !expandableRepeatedBy(target)
39397
+ ) {
39373
39398
  return {
39374
39399
  target,
39375
39400
  implementation: () => {
@@ -39804,7 +39829,7 @@ const requestCloseUpward = (target, detail) => {
39804
39829
  return false;
39805
39830
  }
39806
39831
  const parent = expandable.parentElement;
39807
- expandable = parent ? parent.closest("[aria-expanded]") : null;
39832
+ expandable = parent ? resolveClosestExpandable(parent) : null;
39808
39833
  }
39809
39834
  return true;
39810
39835
  };
@@ -58184,6 +58209,10 @@ const Label = props => {
58184
58209
  requiredIndicator
58185
58210
  } = props;
58186
58211
  const controlId = useContext(ControlIdContext);
58212
+ // What a popup opened from the control is named by (see getTriggerLabelIds
58213
+ // in picker_custom.jsx): aria-labelledby can only point at an id.
58214
+ const idDefault = useId();
58215
+ props.id = props.id || `label_${idDefault}`;
58187
58216
  const [disabled, setDisabled] = useState(false);
58188
58217
  const [readOnly, setReadOnly] = useState(false);
58189
58218
  const [required, setRequired] = useState(false);
@@ -67877,9 +67906,297 @@ const PopupClose = ({
67877
67906
  });
67878
67907
  };
67879
67908
 
67909
+ const SuccessSvg = () => {
67910
+ return jsx("svg", {
67911
+ viewBox: "0 0 16 16",
67912
+ fill: "currentColor",
67913
+ children: jsx("path", {
67914
+ d: "M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm1.5 0a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Zm10.28-1.72-4.5 4.5a.75.75 0 0 1-1.06 0l-2-2a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018l1.47 1.47 3.97-3.97a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Z"
67915
+ })
67916
+ });
67917
+ };
67918
+ const ErrorSvg = () => {
67919
+ return jsx("svg", {
67920
+ viewBox: "0 0 16 16",
67921
+ fill: "currentColor",
67922
+ children: jsx("path", {
67923
+ d: "M4.47.22A.749.749 0 0 1 5 0h6c.199 0 .389.079.53.22l4.25 4.25c.141.14.22.331.22.53v6a.749.749 0 0 1-.22.53l-4.25 4.25A.749.749 0 0 1 11 16H5a.749.749 0 0 1-.53-.22L.22 11.53A.749.749 0 0 1 0 11V5c0-.199.079-.389.22-.53Zm.84 1.28L1.5 5.31v5.38l3.81 3.81h5.38l3.81-3.81V5.31L10.69 1.5ZM8 4a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 8 4Zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"
67924
+ })
67925
+ });
67926
+ };
67927
+ const InfoSvg$1 = () => {
67928
+ return jsx("svg", {
67929
+ viewBox: "0 0 16 16",
67930
+ fill: "currentColor",
67931
+ children: jsx("path", {
67932
+ d: "M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"
67933
+ })
67934
+ });
67935
+ };
67936
+ const WarningSvg = () => {
67937
+ return jsx("svg", {
67938
+ viewBox: "0 0 16 16",
67939
+ fill: "currentColor",
67940
+ children: jsx("path", {
67941
+ d: "M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"
67942
+ })
67943
+ });
67944
+ };
67945
+
67946
+ installImportMetaCssBuild(import.meta);
67947
+ const css$E = /* css */`@layer navi {
67948
+ .navi_message_box {
67949
+ --background-color-info: var(--navi-info-color-light);
67950
+ --color-info: var(--navi-info-color);
67951
+ --background-color-success: var(--navi-success-color-light);
67952
+ --color-success: var(--navi-success-color);
67953
+ --background-color-warning: var(--navi-warning-color-light);
67954
+ --color-warning: var(--navi-warning-color);
67955
+ --background-color-error: var(--navi-error-color-light);
67956
+ --color-error: var(--navi-error-color);
67957
+ }
67958
+ }
67959
+
67960
+ .navi_message_box {
67961
+ --x-message-background-color: var(--background-color-info);
67962
+ --x-message-color: var(--color-info);
67963
+ background-color: var(--x-message-background-color);
67964
+
67965
+ & > .navi_icon {
67966
+ flex-shrink: 0;
67967
+ }
67968
+ }
67969
+
67970
+ .navi_message_box[data-status-info] {
67971
+ --x-message-background-color: var(--background-color-info);
67972
+ --x-message-color: var(--color-info);
67973
+ }
67974
+
67975
+ .navi_message_box[data-status-success] {
67976
+ --x-message-background-color: var(--background-color-success);
67977
+ --x-message-color: var(--color-success);
67978
+ }
67979
+
67980
+ .navi_message_box[data-status-warning] {
67981
+ --x-message-background-color: var(--background-color-warning);
67982
+ --x-message-color: var(--color-warning);
67983
+ }
67984
+
67985
+ .navi_message_box[data-status-error] {
67986
+ --x-message-background-color: var(--background-color-error);
67987
+ --x-message-color: var(--color-error);
67988
+ }
67989
+
67990
+ .navi_message_box[data-left-stripe] {
67991
+ border-left: 6px solid var(--x-message-color);
67992
+ border-top-left-radius: 6px;
67993
+ border-bottom-left-radius: 6px;
67994
+ }
67995
+ `;
67996
+ const MessageBox = ({
67997
+ status = "info",
67998
+ padding = "sm",
67999
+ icon,
68000
+ leftStripe,
68001
+ children,
68002
+ onClose,
68003
+ ...rest
68004
+ }) => {
68005
+ import.meta.css = [css$E, "@jsenv/navi/src/text/message_box.jsx"];
68006
+ const [hasTitleChild, setHasTitleChild] = useState(false);
68007
+ const innerLeftStripe = leftStripe === undefined ? hasTitleChild : leftStripe;
68008
+ if (icon === true) {
68009
+ icon = status === "info" ? jsx(InfoSvg$1, {}) : status === "success" ? jsx(SuccessSvg, {}) : status === "warning" ? jsx(WarningSvg, {}) : status === "error" ? jsx(ErrorSvg, {}) : null;
68010
+ } else if (typeof icon === "function") {
68011
+ const Comp = icon;
68012
+ icon = jsx(Comp, {});
68013
+ }
68014
+ return jsx(Box, {
68015
+ as: "div",
68016
+ role: status === "info" ? "status" : "alert",
68017
+ "data-left-stripe": innerLeftStripe ? "" : undefined,
68018
+ inline: true,
68019
+ column: true,
68020
+ alignY: "center",
68021
+ spacing: "s",
68022
+ ...rest,
68023
+ className: withPropsClassName("navi_message_box", rest.className),
68024
+ padding: padding,
68025
+ pseudoClasses: MessageBoxPseudoClasses,
68026
+ basePseudoState: {
68027
+ ":-navi-status-info": status === "info",
68028
+ ":-navi-status-success": status === "success",
68029
+ ":-navi-status-warning": status === "warning",
68030
+ ":-navi-status-error": status === "error"
68031
+ },
68032
+ children: jsx(MessageBoxStatusContext.Provider, {
68033
+ value: status,
68034
+ children: jsxs(MessageBoxReportTitleChildContext.Provider, {
68035
+ value: setHasTitleChild,
68036
+ children: [icon && jsx(Icon, {
68037
+ color: "var(--x-message-color)",
68038
+ height: "1lh",
68039
+ maxHeight: "auto",
68040
+ selfAlignY: "start",
68041
+ aspectRatio: "auto",
68042
+ children: icon
68043
+ }), jsx(Text, {
68044
+ children: children
68045
+ }), onClose &&
68046
+ // A column as tall as the first line of the message, pinned to the
68047
+ // top, the button centered in it: the close button stays level
68048
+ // with the first line however many lines the message takes (same
68049
+ // layout as Callout).
68050
+ jsx(Box, {
68051
+ flex: true,
68052
+ alignY: "center",
68053
+ height: "1lh",
68054
+ selfAlignY: "start",
68055
+ shrink: false,
68056
+ children: jsx(Button, {
68057
+ action: onClose,
68058
+ icon: true,
68059
+ border: "none",
68060
+ style: {
68061
+ ":hover": {
68062
+ backgroundColor: "rgba(0, 0, 0, 0.1)"
68063
+ }
68064
+ },
68065
+ children: jsx(Icon, {
68066
+ children: jsx(CloseSvg, {})
68067
+ })
68068
+ })
68069
+ })]
68070
+ })
68071
+ })
68072
+ });
68073
+ };
68074
+ const MessageBoxPseudoClasses = [":-navi-status-info", ":-navi-status-success", ":-navi-status-warning", ":-navi-status-error"];
68075
+ const MessageBoxStatusContext = createContext();
68076
+ const MessageBoxReportTitleChildContext = createContext();
68077
+
68078
+ installImportMetaCssBuild(import.meta);
68079
+ const css$D = /* css */`.navi_message_box {
68080
+ & .navi_title {
68081
+ margin-top: 0;
68082
+ margin-bottom: var(--navi-s);
68083
+ color: var(--x-message-color);
68084
+ }
68085
+ }
68086
+ `;
68087
+ const Title = props => {
68088
+ import.meta.css = [css$D, "@jsenv/navi/src/text/title.jsx"];
68089
+ const messageBoxStatus = useContext(MessageBoxStatusContext);
68090
+ const innerAs = props.as || (messageBoxStatus ? "h4" : "h1");
68091
+ const titleLevel = parseInt(innerAs.slice(1));
68092
+ const reportTitleToMessageBox = useContext(MessageBoxReportTitleChildContext);
68093
+ reportTitleToMessageBox?.(true);
68094
+ return jsx(TitleLevelContext.Provider, {
68095
+ value: titleLevel,
68096
+ children: jsx(Text, {
68097
+ bold: true,
68098
+ className: withPropsClassName("navi_title"),
68099
+ as: messageBoxStatus ? "h4" : "h1",
68100
+ ...props,
68101
+ pseudoClasses: TitlePseudoClasses,
68102
+ children: props.children
68103
+ })
68104
+ });
68105
+ };
68106
+ const TitleLevelContext = createContext();
68107
+ const useTitleLevel = () => {
68108
+ return useContext(TitleLevelContext);
68109
+ };
68110
+ const TitlePseudoClasses = [":hover"];
68111
+
68112
+ /**
68113
+ * What a popup is called, decided by Dialog and Popover alike: the name the
68114
+ * caller writes on it (aria-label/aria-labelledby), else the title it holds
68115
+ * (`<Popup.Title>`), else the name of what opened it (`openerAriaLabelledBy` /
68116
+ * `openerAriaLabel`, which a Picker fills with its trigger's). A popup no one
68117
+ * names is announced as "dialog" and nothing else.
68118
+ *
68119
+ * The title tells the popup it exists rather than the popup looking for it:
68120
+ * the content is built after the popup and thrown away before it (see
68121
+ * popup_content_mount.js), and a title may sit anywhere in it — a header, a
68122
+ * step of a form — so only the title knows when it is there.
68123
+ */
68124
+
68125
+ const PopupTitleContext = createContext(null);
68126
+
68127
+ /**
68128
+ * The title of the popup it sits in — reached as `<Popup.Title>`,
68129
+ * `<Dialog.Title>` or `<Popover.Title>`. A heading (`h2` unless `as` says
68130
+ * otherwise) that is also the popup's accessible name: a screen reader
68131
+ * announces the popup by it, and `getByRole("dialog", { name })` finds it.
68132
+ * An `aria-label`/`aria-labelledby` written on the popup itself wins over it.
68133
+ *
68134
+ * @type {import("ignore:preact").FunctionComponent<{
68135
+ * as?: "h1" | "h2" | "h3" | "h4" | "h5" | "h6",
68136
+ * id?: string,
68137
+ * children?: import("ignore:preact").ComponentChildren,
68138
+ * } & Record<string, any>>}
68139
+ */
68140
+ const PopupTitle = props => {
68141
+ const registerTitle = useContext(PopupTitleContext);
68142
+ const idDefault = useId();
68143
+ const id = props.id || `popup_title_${idDefault}`;
68144
+ useLayoutEffect(() => {
68145
+ if (!registerTitle) {
68146
+ return undefined;
68147
+ }
68148
+ return registerTitle(id);
68149
+ }, [registerTitle, id]);
68150
+ return jsx(Title, {
68151
+ as: "h2",
68152
+ ...props,
68153
+ id: id
68154
+ });
68155
+ };
68156
+
68157
+ /**
68158
+ * The name props of a popup element, and what its titles register with —
68159
+ * handed to its children through PopupTitleContext.
68160
+ */
68161
+ const usePopupName = ({
68162
+ ariaLabel,
68163
+ ariaLabelledBy,
68164
+ openerAriaLabel,
68165
+ openerAriaLabelledBy
68166
+ }) => {
68167
+ // Several titles is a content of the caller's own making (two steps both
68168
+ // mounted): the first one registered names the popup.
68169
+ const [titleIds, setTitleIds] = useState(NO_TITLE);
68170
+ const registerTitle = useMemo(() => {
68171
+ return id => {
68172
+ setTitleIds(ids => [...ids, id]);
68173
+ return () => {
68174
+ setTitleIds(ids => ids.filter(each => each !== id));
68175
+ };
68176
+ };
68177
+ }, []);
68178
+ let labelledBy;
68179
+ let label;
68180
+ if (ariaLabelledBy !== undefined || ariaLabel !== undefined) {
68181
+ labelledBy = ariaLabelledBy;
68182
+ label = ariaLabel;
68183
+ } else if (titleIds.length > 0) {
68184
+ labelledBy = titleIds[0];
68185
+ } else if (openerAriaLabelledBy !== undefined) {
68186
+ labelledBy = openerAriaLabelledBy;
68187
+ } else {
68188
+ label = openerAriaLabel;
68189
+ }
68190
+ return [{
68191
+ "aria-labelledby": labelledBy,
68192
+ "aria-label": label
68193
+ }, registerTitle];
68194
+ };
68195
+ const NO_TITLE = [];
68196
+
67880
68197
  installImportMetaCssBuild(import.meta);
67881
68198
  let openLocalDialogCount = 0;
67882
- const css$E = /* css */`
68199
+ const css$C = /* css */`
67883
68200
  /* jsenv-css-opaque: popupCss overlaps these rules, own sheet = cascade
67884
68201
  order depending on which popup renders first. */
67885
68202
 
@@ -68948,10 +69265,14 @@ const css$E = /* css */`
68948
69265
  * under `"while-opened"`, only a press on what opens the popup does (a
68949
69266
  * `--navi-open` button, a picker's trigger), never with an `onOpen`, and a
68950
69267
  * press that does not open the popup throws it away.
69268
+ * @param {string} [props.openerAriaLabelledBy] - The id(s) naming what opened
69269
+ * the dialog: its accessible name when neither `aria-label`/`aria-labelledby`
69270
+ * nor a `<Dialog.Title>` names it. A Picker passes its trigger's.
69271
+ * @param {string} [props.openerAriaLabel] - The same, as a string.
68951
69272
  * @param {import("ignore:preact").ComponentChildren} props.children
68952
69273
  */
68953
69274
  const Dialog = props => {
68954
- import.meta.css = [css$E, "@jsenv/navi/src/layout/dialog.jsx"];
69275
+ import.meta.css = [css$C, "@jsenv/navi/src/layout/dialog.jsx"];
68955
69276
  if (props.openController) {
68956
69277
  return jsx(ControlledDialog, {
68957
69278
  ...props
@@ -69325,6 +69646,9 @@ const useDialogProps = props => {
69325
69646
  onOpen,
69326
69647
  children: childrenProp,
69327
69648
  mount,
69649
+ // Read by usePopupName below, never written on the element.
69650
+ openerAriaLabel,
69651
+ openerAriaLabelledBy,
69328
69652
  ...rest
69329
69653
  } = props;
69330
69654
  // Assigned on every render, like openEffect below, so it always closes over
@@ -69335,7 +69659,16 @@ const useDialogProps = props => {
69335
69659
  mount,
69336
69660
  anchor
69337
69661
  });
69338
- const children = contentMounted ? childrenProp : null;
69662
+ const [nameProps, registerTitle] = usePopupName({
69663
+ ariaLabel: rest["aria-label"],
69664
+ ariaLabelledBy: rest["aria-labelledby"],
69665
+ openerAriaLabel,
69666
+ openerAriaLabelledBy
69667
+ });
69668
+ const children = contentMounted ? jsx(PopupTitleContext.Provider, {
69669
+ value: registerTitle,
69670
+ children: childrenProp
69671
+ }) : null;
69339
69672
  // Where it is placed, and whether there is a wall — the two questions that
69340
69673
  // pick the show call (see this file's top comment).
69341
69674
  const isTopLayer = layer === "top";
@@ -70125,6 +70458,7 @@ const useDialogProps = props => {
70125
70458
  "backdropFilter": backdrop ? backdropFilter : undefined,
70126
70459
  "styleCSSVars": DIALOG_STYLE_CSS_VARS,
70127
70460
  ...rest,
70461
+ ...nameProps,
70128
70462
  ...autoFocusProps,
70129
70463
  "as": "dialog",
70130
70464
  ref,
@@ -70298,10 +70632,11 @@ const DIALOG_STYLE_CSS_VARS = {
70298
70632
  maxHeight: "--dialog-max-height"
70299
70633
  };
70300
70634
  Dialog.Close = PopupClose;
70635
+ Dialog.Title = PopupTitle;
70301
70636
 
70302
70637
  installImportMetaCssBuild(import.meta);
70303
70638
  let openLocalPopoverCount = 0;
70304
- const css$D = /* css */`
70639
+ const css$B = /* css */`
70305
70640
  /* jsenv-css-opaque: popupCss overlaps these rules, own sheet = cascade
70306
70641
  order depending on which popup renders first. */
70307
70642
 
@@ -70900,10 +71235,17 @@ const css$D = /* css */`
70900
71235
  * under `"while-opened"`, only a press on what opens the popup does (a
70901
71236
  * `--navi-open` button, a picker's trigger), never with an `onOpen`, and a
70902
71237
  * press that does not open the popup throws it away.
71238
+ * @param {string} [props.openerAriaLabelledBy] - The id(s) naming what opened
71239
+ * the popover: its accessible name when neither `aria-label`/`aria-labelledby`
71240
+ * nor a `<Popover.Title>` names it. A Picker passes its trigger's.
71241
+ * @param {string} [props.openerAriaLabel] - The same, as a string. A popover
71242
+ * something names — these, `aria-label`/`aria-labelledby`, a
71243
+ * `<Popover.Title>` — is a `dialog`, unless given another `role`: a name on
71244
+ * an element with no role is read by nobody.
70903
71245
  * @param {import("ignore:preact").ComponentChildren} props.children
70904
71246
  */
70905
71247
  const Popover = props => {
70906
- import.meta.css = [css$D, "@jsenv/navi/src/layout/popover.jsx"];
71248
+ import.meta.css = [css$B, "@jsenv/navi/src/layout/popover.jsx"];
70907
71249
  if (props.openController) {
70908
71250
  return jsx(ControlledPopover, {
70909
71251
  ...props
@@ -71140,6 +71482,9 @@ const usePopoverProps = props => {
71140
71482
  onOpen,
71141
71483
  children: childrenProp,
71142
71484
  mount,
71485
+ // Read by usePopupName below, never written on the element.
71486
+ openerAriaLabel,
71487
+ openerAriaLabelledBy,
71143
71488
  ...rest
71144
71489
  } = props;
71145
71490
  // Assigned on every render, like openEffect below, so it always closes over
@@ -71150,7 +71495,16 @@ const usePopoverProps = props => {
71150
71495
  mount,
71151
71496
  anchor
71152
71497
  });
71153
- const children = contentMounted ? childrenProp : null;
71498
+ const [nameProps, registerTitle] = usePopupName({
71499
+ ariaLabel: rest["aria-label"],
71500
+ ariaLabelledBy: rest["aria-labelledby"],
71501
+ openerAriaLabel,
71502
+ openerAriaLabelledBy
71503
+ });
71504
+ const children = contentMounted ? jsx(PopupTitleContext.Provider, {
71505
+ value: registerTitle,
71506
+ children: childrenProp
71507
+ }) : null;
71154
71508
  const isTopLayer = layer === "top";
71155
71509
  const ref = props.ref;
71156
71510
  const backdropRef = useRef();
@@ -71955,6 +72309,10 @@ const usePopoverProps = props => {
71955
72309
  "navi-hidden": openController.openedInDom ? undefined : "",
71956
72310
  "styleCSSVars": POPUP_STYLE_CSS_VARS,
71957
72311
  ...rest,
72312
+ ...nameProps,
72313
+ // A <div> has no role, and a name on an element without one is read by
72314
+ // nobody: a popover something names is a dialog, unless told what else.
72315
+ "role": rest.role ?? (nameProps["aria-labelledby"] === undefined && nameProps["aria-label"] === undefined ? undefined : "dialog"),
71958
72316
  ...autoFocusProps,
71959
72317
  ref,
71960
72318
  // Not a control, but still something the rest of navi has to be able to
@@ -72070,9 +72428,10 @@ const resolvePositionAreaAndAnimationKind = ({
72070
72428
  };
72071
72429
  };
72072
72430
  Popover.Close = PopupClose;
72431
+ Popover.Title = PopupTitle;
72073
72432
 
72074
72433
  installImportMetaCssBuild(import.meta);
72075
- const css$C = /* css */`@layer navi {
72434
+ const css$A = /* css */`@layer navi {
72076
72435
  .navi_popup {
72077
72436
  --popup-border-radius: var(--navi-popup-border-radius);
72078
72437
  --popup-border-width: 1px;
@@ -72213,6 +72572,10 @@ const css$C = /* css */`@layer navi {
72213
72572
  * @param {string} [props.className] - Merged with the shared
72214
72573
  * `"navi_popup"` class (see this file's own CSS) rather than replacing
72215
72574
  * it.
72575
+ * @param {string} [props.openerAriaLabelledBy] - Forwarded as-is: the name the
72576
+ * popup takes when neither `aria-label`/`aria-labelledby` nor a
72577
+ * `<Popup.Title>` in `children` names it (see `Dialog`/`Popover`).
72578
+ * @param {string} [props.openerAriaLabel] - Forwarded as-is, same.
72216
72579
  * @param {"always"|"idle"|"from-first-open"|"while-opened"} [props.mount] - When
72217
72580
  * `children` are built and thrown away (see popup_content_mount.js).
72218
72581
  * `"from-first-open"` (the default) builds them on the first open and keeps
@@ -72228,7 +72591,7 @@ const css$C = /* css */`@layer navi {
72228
72591
  * @param {import("ignore:preact").ComponentChildren} props.children
72229
72592
  */
72230
72593
  const Popup = props => {
72231
- import.meta.css = [css$C, "@jsenv/navi/src/layout/popup.jsx"];
72594
+ import.meta.css = [css$A, "@jsenv/navi/src/layout/popup.jsx"];
72232
72595
  const {
72233
72596
  mode: modeProp,
72234
72597
  maxWidth,
@@ -72311,6 +72674,7 @@ const Popup = props => {
72311
72674
  });
72312
72675
  };
72313
72676
  Popup.Close = PopupClose;
72677
+ Popup.Title = PopupTitle;
72314
72678
 
72315
72679
  // What Dialog's own animation values mean to a popover, which has no lift
72316
72680
  // (see the `animation` doc above).
@@ -72359,6 +72723,54 @@ const pickerUIIsNaviOwn = ui => {
72359
72723
  return Boolean(ui) && typeof ui === "object" && Boolean(ui.type?.isPickerOwnUI);
72360
72724
  };
72361
72725
 
72726
+ /*
72727
+ * What the picker really is, said on the element that holds the name and takes
72728
+ * the focus (the host input in picker.jsx), which is both what a screen reader
72729
+ * announces and what getByRole(role, { name }) finds:
72730
+ * - a picker that picks nothing is a door — its popup is a question
72731
+ * (type="confirm") or something to read (mode="callout", which says it for
72732
+ * itself) — and a door is pressed: "button";
72733
+ * - a picker holding a value and opening a popup of navi's is a select-only
72734
+ * combobox: it shows a value the user does not type, and opens what changes
72735
+ * it. A textbox could not say the rest — aria-expanded is not allowed on one,
72736
+ * so "open" and "closed" would never be announced;
72737
+ * - a picker showing the browser's own picker (no popup of navi's) stays the
72738
+ * textbox its <input> is.
72739
+ */
72740
+ const getPickerHostRole = props => {
72741
+ if (props.role !== undefined) {
72742
+ return props.role;
72743
+ }
72744
+ if (props.picksNothing) {
72745
+ return "button";
72746
+ }
72747
+ if (props["aria-haspopup"] !== undefined) {
72748
+ return "combobox";
72749
+ }
72750
+ return undefined;
72751
+ };
72752
+
72753
+ /*
72754
+ * And what that button is called, when the caller wrote it as a drawing rather
72755
+ * than as a word: a door draws no value, so what sits in its value slot IS its
72756
+ * label — the `ui` a caller gave it, or its placeholder. Undefined the moment
72757
+ * the caller names it themselves (aria-label/aria-labelledby), which is the
72758
+ * only way to name a door drawn as an icon. Read by the popup too: what the
72759
+ * user pressed is a fair name for what it opened.
72760
+ */
72761
+ const getPickerHostLabelId = (id, props) => {
72762
+ if (getPickerHostRole(props) !== "button") {
72763
+ return undefined;
72764
+ }
72765
+ if (props["aria-label"] !== undefined || props["aria-labelledby"] !== undefined) {
72766
+ return undefined;
72767
+ }
72768
+ if (props.variant === "headless" || props.ui === "default") {
72769
+ return undefined;
72770
+ }
72771
+ return `${id}_picker_label`;
72772
+ };
72773
+
72362
72774
  /**
72363
72775
  * What the picker holds, read from inside its `ui` — for a drawing given as
72364
72776
  * an element (`ui={<MyCard game={game} />}`), which the picker cannot hand
@@ -72388,7 +72800,7 @@ const usePickerState = () => {
72388
72800
  };
72389
72801
 
72390
72802
  installImportMetaCssBuild(import.meta);
72391
- const css$B = /* css */`.navi_picker_callout_dock > [data-picker-content] {
72803
+ const css$z = /* css */`.navi_picker_callout_dock > [data-picker-content] {
72392
72804
  display: none;
72393
72805
  }
72394
72806
 
@@ -72417,7 +72829,7 @@ const css$B = /* css */`.navi_picker_callout_dock > [data-picker-content] {
72417
72829
  }
72418
72830
  }
72419
72831
 
72420
- .navi_picker[aria-haspopup="listbox"][aria-expanded="true"][navi-popover-mode="overlay"] {
72832
+ .navi_picker[navi-popover-mode="overlay"][aria-expanded="true"] {
72421
72833
  border-color: #0000;
72422
72834
  }
72423
72835
 
@@ -72445,7 +72857,7 @@ const css$B = /* css */`.navi_picker_callout_dock > [data-picker-content] {
72445
72857
  }
72446
72858
  `;
72447
72859
  const PickerCustomResolver = props => {
72448
- import.meta.css = [css$B, "@jsenv/navi/src/control/picker/picker_custom.jsx"];
72860
+ import.meta.css = [css$z, "@jsenv/navi/src/control/picker/picker_custom.jsx"];
72449
72861
  if (props.children === undefined) {
72450
72862
  return renderResolver(PickerNative, props);
72451
72863
  }
@@ -73254,6 +73666,24 @@ const isPressDisputedByHold = pickerEl => Boolean(pickerEl?.parentElement?.close
73254
73666
  const getPickerInput = pickerEl => {
73255
73667
  return pickerEl.querySelector(".navi_picker_input");
73256
73668
  };
73669
+
73670
+ // The <label>s naming a picker's trigger, by id. Read off the document: it is
73671
+ // the one place a label[for] and its control meet (navi's own Label carries an
73672
+ // id for this). A label wrapping the picker is left out — it holds the trigger
73673
+ // and the popup with it, and the popup would be named after its own content.
73674
+ const getTriggerLabelIds = pickerEl => {
73675
+ const labels = pickerEl && getPickerInput(pickerEl)?.labels;
73676
+ if (!labels) {
73677
+ return undefined;
73678
+ }
73679
+ const ids = [];
73680
+ for (const label of labels) {
73681
+ if (label.id && !label.contains(pickerEl)) {
73682
+ ids.push(label.id);
73683
+ }
73684
+ }
73685
+ return ids.length === 0 ? undefined : ids.join(" ");
73686
+ };
73257
73687
  const getPickerInputUIState = pickerEl => {
73258
73688
  const pickerInput = getPickerInput(pickerEl);
73259
73689
  return getUIStateFromElement(pickerInput);
@@ -73276,6 +73706,11 @@ const PickerContentInsidePopup = props => {
73276
73706
  // Same reason: a `data-testid` on the picker names the trigger (see
73277
73707
  // docs/testid.md) — this one names the popup.
73278
73708
  popupTestId,
73709
+ // Same again for the accessible name: aria-label/aria-labelledby on the
73710
+ // picker name the trigger (see control_context.js), these the popup.
73711
+ popupAriaLabel,
73712
+ popupAriaLabelledBy,
73713
+ popupAriaDescribedBy,
73279
73714
  positionArea,
73280
73715
  popoverMode = "nearby",
73281
73716
  popoverSpacing = popoverMode === "nearby" ? 5 : 0,
@@ -73337,8 +73772,25 @@ const PickerContentInsidePopup = props => {
73337
73772
  } = props;
73338
73773
  const isPopover = mode === "popover";
73339
73774
  const isCallout = mode === "callout";
73340
- return jsx(Next, {
73341
- "aria-haspopup": isPopover ? "listbox" : "dialog",
73775
+ // The trigger's name, in the order the browser reads it, for the popup to
73776
+ // take when neither the caller nor a <Popup.Title> names it: "Report this
73777
+ // book" is a fair name for the sheet it opens, "Start date" for a calendar.
73778
+ let openerAriaLabelledBy = rest["aria-labelledby"] ?? getPickerHostLabelId(props.id, props);
73779
+ let openerAriaLabel;
73780
+ if (openerAriaLabelledBy === undefined) {
73781
+ openerAriaLabel = rest["aria-label"];
73782
+ // Read only while open: the labels are a question for the document, and
73783
+ // a closed popup has nobody to announce it.
73784
+ if (openerAriaLabel === undefined && rest["aria-expanded"]) {
73785
+ openerAriaLabelledBy = getTriggerLabelIds(props.ref.current);
73786
+ }
73787
+ }
73788
+ return jsx(Next
73789
+ // A dialog in either mode: what a picker opens is content of the
73790
+ // caller's, never a listbox (a selectable List is a group of radios or
73791
+ // checkboxes). The popover says so with its role, below.
73792
+ , {
73793
+ "aria-haspopup": "dialog",
73342
73794
  "navi-popover-mode": isPopover ? popoverMode : undefined,
73343
73795
  ...rest,
73344
73796
  // On popupProps already (see the picker's popup assembly); they mean
@@ -73383,11 +73835,23 @@ const PickerContentInsidePopup = props => {
73383
73835
  pressOutside: pressOutside,
73384
73836
  children: jsx(PopupModeContext.Provider, {
73385
73837
  value: mode,
73386
- children: children
73838
+ children: jsx(PopupTitleContext.Provider, {
73839
+ value: null,
73840
+ children: children
73841
+ })
73387
73842
  })
73388
73843
  }) : jsx(Popup, {
73389
73844
  ...popupProps,
73390
73845
  "data-testid": popupTestId
73846
+ // What the trigger's aria-haspopup announces; a <dialog> says it
73847
+ // for itself.
73848
+ ,
73849
+ role: isPopover ? "dialog" : undefined,
73850
+ "aria-label": popupAriaLabel,
73851
+ "aria-labelledby": popupAriaLabelledBy,
73852
+ "aria-describedby": popupAriaDescribedBy,
73853
+ openerAriaLabel: openerAriaLabel,
73854
+ openerAriaLabelledBy: openerAriaLabelledBy
73391
73855
  // What the CSS above keys on: this picker's own popup, and no other
73392
73856
  // popup below the picker.
73393
73857
  ,
@@ -73657,7 +74121,7 @@ const showNativePicker = (pickerInput, event) => {
73657
74121
  };
73658
74122
 
73659
74123
  installImportMetaCssBuild(import.meta);
73660
- const css$A = /* css */`.navi_picker_confirm_body {
74124
+ const css$y = /* css */`.navi_picker_confirm_body {
73661
74125
  min-width: 180px;
73662
74126
  max-width: 320px;
73663
74127
  padding: var(--navi-m);
@@ -73673,7 +74137,7 @@ const css$A = /* css */`.navi_picker_confirm_body {
73673
74137
  }
73674
74138
  `;
73675
74139
  const PickerConfirmResolver = props => {
73676
- import.meta.css = [css$A, "@jsenv/navi/src/control/picker/picker_confirm.jsx"];
74140
+ import.meta.css = [css$y, "@jsenv/navi/src/control/picker/picker_confirm.jsx"];
73677
74141
  const Next = useNextResolver();
73678
74142
  if (props.type !== "confirm") {
73679
74143
  return jsx(Next, {
@@ -74199,7 +74663,7 @@ const LoadingIndicator = ({
74199
74663
  };
74200
74664
 
74201
74665
  installImportMetaCssBuild(import.meta);
74202
- const css$z = /* css */`@layer navi {
74666
+ const css$x = /* css */`@layer navi {
74203
74667
  .navi_separator {
74204
74668
  --size: 1px;
74205
74669
  --color: var(--navi-separator-color-default);
@@ -74273,7 +74737,7 @@ const Separator = ({
74273
74737
  style,
74274
74738
  ...props
74275
74739
  }) => {
74276
- import.meta.css = [css$z, "@jsenv/navi/src/layout/separator.jsx"];
74740
+ import.meta.css = [css$x, "@jsenv/navi/src/layout/separator.jsx"];
74277
74741
  return jsx(Box, {
74278
74742
  as: vertical ? "span" : "hr",
74279
74743
  ...props,
@@ -75067,7 +75531,7 @@ const listItemBlockedMessage = (loading, props) => {
75067
75531
  };
75068
75532
 
75069
75533
  installImportMetaCssBuild(import.meta);
75070
- const css$y = /* css */`@layer navi {
75534
+ const css$w = /* css */`@layer navi {
75071
75535
  .navi_list_container[navi-selectable] {
75072
75536
  --list-item-outline-width: var(--navi-focus-outline-width);
75073
75537
  --list-item-outline-offset: calc(-1 * var(--list-item-outline-width));
@@ -75240,7 +75704,7 @@ const ListSelectableResolver = props => {
75240
75704
  };
75241
75705
  const ListSelectable = props => {
75242
75706
  const Next = useNextResolver();
75243
- import.meta.css = [css$y, "@jsenv/navi/src/control/list/list_selectable.jsx"];
75707
+ import.meta.css = [css$w, "@jsenv/navi/src/control/list/list_selectable.jsx"];
75244
75708
  // we allow ourselves to auto-generate a name
75245
75709
  const defaultName = useId();
75246
75710
  props.name = props.name || `listbox_${defaultName}`;
@@ -75909,7 +76373,7 @@ const ListRunItemContext = createContext(null);
75909
76373
  // item takes its place in the collection by slot: the place is then the list's
75910
76374
  // to move, and the item's to follow — see list_items.js.
75911
76375
  const ListSlotContext = createContext(null);
75912
- const css$x = /* css */`@property --list-group-label-height {
76376
+ const css$v = /* css */`@property --list-group-label-height {
75913
76377
  syntax: "<length>";
75914
76378
  inherits: false;
75915
76379
  initial-value: 0;
@@ -76437,7 +76901,7 @@ const resolveRenderBudget = renderBudget => {
76437
76901
  };
76438
76902
  };
76439
76903
  const ListUI = props => {
76440
- import.meta.css = [css$x, "@jsenv/navi/src/control/list/list.jsx"];
76904
+ import.meta.css = [css$v, "@jsenv/navi/src/control/list/list.jsx"];
76441
76905
  const {
76442
76906
  ref,
76443
76907
  renderBudget: renderBudgetProp,
@@ -82552,7 +83016,7 @@ const createBadgeRegistry = () => {
82552
83016
  };
82553
83017
 
82554
83018
  installImportMetaCssBuild(import.meta);
82555
- const css$w = /* css */`@layer navi;
83019
+ const css$u = /* css */`@layer navi;
82556
83020
 
82557
83021
  .navi_badge {
82558
83022
  --font-size: .7em;
@@ -82655,7 +83119,7 @@ const BadgeUI = ({
82655
83119
  className,
82656
83120
  ...props
82657
83121
  }) => {
82658
- import.meta.css = [css$w, "@jsenv/navi/src/text/badge.jsx"];
83122
+ import.meta.css = [css$u, "@jsenv/navi/src/text/badge.jsx"];
82659
83123
  const defaultRef = useRef();
82660
83124
  props.ref = props.ref || defaultRef;
82661
83125
  const {
@@ -82763,7 +83227,7 @@ const wrapLabels = childArray => {
82763
83227
  };
82764
83228
 
82765
83229
  installImportMetaCssBuild(import.meta);
82766
- const css$v = /* css */`@layer navi;
83230
+ const css$t = /* css */`@layer navi;
82767
83231
 
82768
83232
  .navi_badge_list {
82769
83233
  flex-wrap: wrap;
@@ -82898,7 +83362,7 @@ const useBadgeRegistry = (children, enabled) => {
82898
83362
  * component grants (a <Picker>, see max_lines_context.js).
82899
83363
  */
82900
83364
  const BadgeList = props => {
82901
- import.meta.css = [css$v, "@jsenv/navi/src/text/badge_list.jsx"];
83365
+ import.meta.css = [css$t, "@jsenv/navi/src/text/badge_list.jsx"];
82902
83366
  const {
82903
83367
  maxLines,
82904
83368
  max,
@@ -83242,7 +83706,7 @@ const BadgeListContent = ({
83242
83706
  };
83243
83707
 
83244
83708
  installImportMetaCssBuild(import.meta);
83245
- const css$u = /* css */`.navi_color {
83709
+ const css$s = /* css */`.navi_color {
83246
83710
  aspect-ratio: 1;
83247
83711
  background-color: currentColor;
83248
83712
  border: 1px solid #0003;
@@ -83262,7 +83726,7 @@ const Color = ({
83262
83726
  children,
83263
83727
  ...rest
83264
83728
  }) => {
83265
- import.meta.css = [css$u, "@jsenv/navi/src/text/color.jsx"];
83729
+ import.meta.css = [css$s, "@jsenv/navi/src/text/color.jsx"];
83266
83730
  const color = children || undefined;
83267
83731
  return jsx(Box, {
83268
83732
  as: "span",
@@ -83749,7 +84213,7 @@ const PickerFileUI = /*#__PURE__*/asPickerOwnUI(() => {
83749
84213
  });
83750
84214
 
83751
84215
  installImportMetaCssBuild(import.meta);
83752
- const css$t = /* css */`@layer navi {
84216
+ const css$r = /* css */`@layer navi {
83753
84217
  .navi_picker {
83754
84218
  --picker-border-radius: var(--navi-control-border-radius);
83755
84219
  --picker-border-width: var(--navi-control-border-width);
@@ -84218,7 +84682,7 @@ const css$t = /* css */`@layer navi {
84218
84682
  }
84219
84683
  `;
84220
84684
  const PickerButton = props => {
84221
- import.meta.css = [css$t, "@jsenv/navi/src/control/picker/picker.jsx"];
84685
+ import.meta.css = [css$r, "@jsenv/navi/src/control/picker/picker.jsx"];
84222
84686
  if (typeof props.maxLines === "string") {
84223
84687
  props.maxLines = parseInt(props.maxLines);
84224
84688
  }
@@ -84259,11 +84723,6 @@ const PickerButton = props => {
84259
84723
  // confirm resolver (see picker_confirm.jsx), which is the picker that is
84260
84724
  // one — a caller whose popup is a menu of actions says it for themselves.
84261
84725
  picksNothing,
84262
- // Where the caller's own role goes: onto the host, beside the name (see
84263
- // control_context.js) — a role and a name on two different elements name
84264
- // nothing at all. Left unsaid, a picker that picks nothing takes "button"
84265
- // (see PickerInput below).
84266
- role,
84267
84726
  readOnly,
84268
84727
  error,
84269
84728
  // Who draws the loading outline. Left unsaid, the picker does, around its
@@ -84344,21 +84803,8 @@ const PickerButton = props => {
84344
84803
  // clearing being a modification like any other.
84345
84804
  const interactive = !basePseudoState[":disabled"] && !basePseudoState[":read-only"] && !loading;
84346
84805
  usePickerErrorCallout(uiStateController, error);
84347
- // What the picker really is, said on the element that holds the name and
84348
- // takes the focus (the host input below): a picker that picks nothing is a
84349
- // door — its popup is a question (type="confirm") or something to read
84350
- // (mode="callout", which says it for itself) — and a door is pressed. So it
84351
- // answers to "button" rather than to the "textbox" its <input> would
84352
- // otherwise be, which is both what a screen reader announces and what
84353
- // getByRole("button", { name }) finds. A picker holding a value stays a
84354
- // textbox: it does hold text.
84355
- const hostRole = role ?? (picksNothing ? "button" : undefined);
84356
- // And what that button is called, when the caller wrote it as a drawing
84357
- // rather than as a word: a door draws no value, so what sits in its value
84358
- // slot IS its label — the `ui` a caller gave it, or its placeholder. Skipped
84359
- // the moment the caller names it themselves (aria-label/aria-labelledby),
84360
- // which is the only way to name a door drawn as an icon.
84361
- const hostLabelId = hostRole === "button" && inputProps["aria-label"] === undefined && inputProps["aria-labelledby"] === undefined && variant !== "headless" && ui !== "default" ? `${inputProps.id}_picker_label` : undefined;
84806
+ const hostRole = getPickerHostRole(props);
84807
+ const hostLabelId = getPickerHostLabelId(inputProps.id, props);
84362
84808
  // What the picker knows about itself, for the pieces it does not place: the
84363
84809
  // drawings of its value (Picker.UI.*), and the affordances a caller may put
84364
84810
  // in their own `ui` (Picker.Clear) as much as the ones it puts in its slot.
@@ -84427,8 +84873,16 @@ const PickerButton = props => {
84427
84873
  basePseudoState: basePseudoState,
84428
84874
  styleCSSVars: PickerStyleCSSVars,
84429
84875
  variant: undefined,
84430
- icon: undefined,
84876
+ icon: undefined
84877
+ // The caller's own role goes onto the host, beside the name (see
84878
+ // control_context.js): a role and a name on two different elements
84879
+ // name nothing at all. What the trigger opens is said there too, and
84880
+ // aria-haspopup with it. aria-expanded stays here as well: commands.js
84881
+ // and the CSS read the open state off the root (see
84882
+ // expandableRepeatedBy in commands.js).
84883
+ ,
84431
84884
  role: undefined,
84885
+ "aria-haspopup": undefined,
84432
84886
  rightSlotIcon: undefined,
84433
84887
  rightSlotIconSize: undefined,
84434
84888
  rightSlot: undefined,
@@ -84468,6 +84922,8 @@ const PickerButton = props => {
84468
84922
  inset: loadingOutlineInset
84469
84923
  }), jsx(PickerInput, {
84470
84924
  role: hostRole,
84925
+ "aria-haspopup": props["aria-haspopup"],
84926
+ "aria-expanded": props["aria-expanded"],
84471
84927
  "aria-labelledby": hostLabelId,
84472
84928
  tabIndex: variant === "headless" ? -1 : undefined,
84473
84929
  "aria-hidden": variant === "headless" ? "true" : undefined,
@@ -84993,7 +85449,7 @@ const Picker = /*#__PURE__*/Object.assign(PickerResolved, {
84993
85449
  });
84994
85450
 
84995
85451
  installImportMetaCssBuild(import.meta);
84996
- const css$s = /* css */`@layer navi {
85452
+ const css$q = /* css */`@layer navi {
84997
85453
  .navi_picker_spin {
84998
85454
  --picker-spin-padding-x-default: var(--navi-picker-padding-x-default);
84999
85455
  --picker-spin-padding-y-default: var(--navi-picker-padding-y-default);
@@ -85343,7 +85799,7 @@ const Spin = ({
85343
85799
  nextLabel,
85344
85800
  ...rest
85345
85801
  }) => {
85346
- import.meta.css = [css$s, "@jsenv/navi/src/control/picker/picker_spin.jsx"];
85802
+ import.meta.css = [css$q, "@jsenv/navi/src/control/picker/picker_spin.jsx"];
85347
85803
  const id = useId();
85348
85804
  // What the group around it says, when there is one: how big the whole thing
85349
85805
  // is written is said once, on the group, and every spin in it follows.
@@ -86054,7 +86510,7 @@ const renderValueDefault = value => String(value ?? "");
86054
86510
  * are passed on to the spins sitting in them.
86055
86511
  */
86056
86512
  const SpinGroup = props => {
86057
- import.meta.css = [css$s, "@jsenv/navi/src/control/picker/picker_spin.jsx"];
86513
+ import.meta.css = [css$q, "@jsenv/navi/src/control/picker/picker_spin.jsx"];
86058
86514
  const {
86059
86515
  size
86060
86516
  } = props;
@@ -86563,7 +87019,7 @@ const TimeRangeSpin = ({
86563
87019
  };
86564
87020
 
86565
87021
  installImportMetaCssBuild(import.meta);
86566
- const css$r = /* css */`.navi_checkbox_group {
87022
+ const css$p = /* css */`.navi_checkbox_group {
86567
87023
  border-style: solid;
86568
87024
 
86569
87025
  &[data-callout] {
@@ -86623,7 +87079,7 @@ const CheckboxGroup = props => {
86623
87079
  return checkboxGroup;
86624
87080
  };
86625
87081
  const CheckboxGroupInterface = props => {
86626
- import.meta.css = [css$r, "@jsenv/navi/src/control/input/checkbox_group.jsx"];
87082
+ import.meta.css = [css$p, "@jsenv/navi/src/control/input/checkbox_group.jsx"];
86627
87083
  const {
86628
87084
  ref
86629
87085
  } = props;
@@ -86741,7 +87197,7 @@ const formatIntlUnit = (unit, {
86741
87197
  };
86742
87198
 
86743
87199
  installImportMetaCssBuild(import.meta);
86744
- const css$q = /* css */`.navi_input_duration {
87200
+ const css$o = /* css */`.navi_input_duration {
86745
87201
  --duration-separator-spacing: 4px;
86746
87202
  --loader-color: var(--navi-loader-color);
86747
87203
  position: relative;
@@ -86806,7 +87262,7 @@ const css$q = /* css */`.navi_input_duration {
86806
87262
  * "auto" aligns each field toward its neighbouring separator (first→right, last→left, middle/solo→center).
86807
87263
  */
86808
87264
  const InputDuration = props => {
86809
- import.meta.css = [css$q, "@jsenv/navi/src/control/input/input_duration.jsx"];
87265
+ import.meta.css = [css$o, "@jsenv/navi/src/control/input/input_duration.jsx"];
86810
87266
  const defaultRef = useRef();
86811
87267
  props.ref = props.ref || defaultRef;
86812
87268
  props.max = props.max || "23h59";
@@ -87307,7 +87763,7 @@ const InputDurationPart = ({
87307
87763
  };
87308
87764
 
87309
87765
  installImportMetaCssBuild(import.meta);
87310
- const css$p = /* css */`.navi_radio_group {
87766
+ const css$n = /* css */`.navi_radio_group {
87311
87767
  border-style: solid;
87312
87768
 
87313
87769
  &[data-callout] {
@@ -87347,7 +87803,7 @@ const RadioGroup = props => {
87347
87803
  return radioGroup;
87348
87804
  };
87349
87805
  const RadioGroupInterface = props => {
87350
- import.meta.css = [css$p, "@jsenv/navi/src/control/input/radio_group.jsx"];
87806
+ import.meta.css = [css$n, "@jsenv/navi/src/control/input/radio_group.jsx"];
87351
87807
  const {
87352
87808
  ref
87353
87809
  } = props;
@@ -87377,7 +87833,7 @@ const RadioGroupInterface = props => {
87377
87833
  };
87378
87834
 
87379
87835
  installImportMetaCssBuild(import.meta);
87380
- const css$o = /* css */`.navi_input.navi_select {
87836
+ const css$m = /* css */`.navi_input.navi_select {
87381
87837
  & .navi_control_input {
87382
87838
  padding-right: calc(var(--x-padding-right) + 1em);
87383
87839
  line-height: var(--navi-control-line-height);
@@ -87424,7 +87880,7 @@ const Select = ({
87424
87880
  ...props
87425
87881
  }) => {
87426
87882
  installInputCss();
87427
- import.meta.css = [css$o, "@jsenv/navi/src/control/input/select.jsx"];
87883
+ import.meta.css = [css$m, "@jsenv/navi/src/control/input/select.jsx"];
87428
87884
  const defaultRef = useRef(null);
87429
87885
  props.ref = props.ref || defaultRef;
87430
87886
  seedDefaultValueFromSignal(props);
@@ -87474,7 +87930,7 @@ const Select = ({
87474
87930
  };
87475
87931
 
87476
87932
  installImportMetaCssBuild(import.meta);
87477
- const css$n = /* css */`.navi_split_button {
87933
+ const css$l = /* css */`.navi_split_button {
87478
87934
  border-radius: var(--navi-control-border-radius);
87479
87935
  display: inline-flex;
87480
87936
  position: relative;
@@ -87596,7 +88052,7 @@ const css$n = /* css */`.navi_split_button {
87596
88052
  * on the split button's own box.
87597
88053
  */
87598
88054
  const SplitButton = props => {
87599
- import.meta.css = [css$n, "@jsenv/navi/src/control/input/split_button.jsx"];
88055
+ import.meta.css = [css$l, "@jsenv/navi/src/control/input/split_button.jsx"];
87600
88056
  const {
87601
88057
  options = [],
87602
88058
  value,
@@ -88615,7 +89071,7 @@ const createItemTracker = (onChange) => {
88615
89071
  };
88616
89072
 
88617
89073
  installImportMetaCssBuild(import.meta);
88618
- const css$m = /* css */`.navi_wheel_container {
89074
+ const css$k = /* css */`.navi_wheel_container {
88619
89075
  --wheel-item-height: round(1.8em, 1px);
88620
89076
  --wheel-emphasis-size: round(1.5em, 1px);
88621
89077
  --wheel-item-width: 3.5ch;
@@ -89563,7 +90019,7 @@ const useWheelKeyboard = ({
89563
90019
  }, [isHorizontal, interactive, isLoop]);
89564
90020
  };
89565
90021
  function WheelUI(props) {
89566
- import.meta.css = [css$m, "@jsenv/navi/src/control/wheel/wheel.jsx"];
90022
+ import.meta.css = [css$k, "@jsenv/navi/src/control/wheel/wheel.jsx"];
89567
90023
  const {
89568
90024
  ref,
89569
90025
  visibleCount = 3,
@@ -90553,7 +91009,7 @@ Wheel.Item = WheelItem;
90553
91009
  * @param {boolean|number} [props.zoom] - Enlarge the centered value of every wheel (see Wheel's zoom prop) with one prop for the whole group.
90554
91010
  */
90555
91011
  const WheelGroup = props => {
90556
- import.meta.css = [css$m, "@jsenv/navi/src/control/wheel/wheel.jsx"];
91012
+ import.meta.css = [css$k, "@jsenv/navi/src/control/wheel/wheel.jsx"];
90557
91013
  // WheelGroup IS a control group: it aggregates its named wheels ("hours",
90558
91014
  // "minutes"…) into one object value, so it can sit directly inside a Form or a
90559
91015
  // Picker with no extra <ControlGroup> wrapper. The wheel-specific presentation
@@ -90726,7 +91182,7 @@ const WheelColon = props => {
90726
91182
  Wheel.Colon = WheelColon;
90727
91183
 
90728
91184
  installImportMetaCssBuild(import.meta);
90729
- const css$l = /* css */`.navi_time_range_label {
91185
+ const css$j = /* css */`.navi_time_range_label {
90730
91186
  --wheel-item-height: round(1.8em, 1px);
90731
91187
  color: var(--wheel-color, light-dark(#111, #eee));
90732
91188
  line-height: var(--wheel-item-height);
@@ -90950,7 +91406,7 @@ const TimeRangeWheel = ({
90950
91406
  endTimeProps,
90951
91407
  ...rest
90952
91408
  }) => {
90953
- import.meta.css = [css$l, "@jsenv/navi/src/control/wheel/wheel_time.jsx"];
91409
+ import.meta.css = [css$j, "@jsenv/navi/src/control/wheel/wheel_time.jsx"];
90954
91410
  const startId = useId();
90955
91411
  const startRef = useRef(null);
90956
91412
  const endRef = useRef(null);
@@ -91538,7 +91994,7 @@ const Z_INDEX_DROP_PREVIEW = Z_INDEX_STICKY_CORNER + 1;
91538
91994
  const Z_INDEX_TABLE_UI = Z_INDEX_STICKY_CORNER + 1;
91539
91995
 
91540
91996
  installImportMetaCssBuild(import.meta);
91541
- const css$k = /* css */`.navi_table_drag_clone_container {
91997
+ const css$i = /* css */`.navi_table_drag_clone_container {
91542
91998
  top: var(--table-visual-top);
91543
91999
  left: var(--table-visual-left);
91544
92000
  width: var(--table-visual-width);
@@ -91693,7 +92149,7 @@ const useTableDragContextValue = ({
91693
92149
  }, [grabTarget, canChangeColumnOrder]);
91694
92150
  };
91695
92151
  const TableDragCloneContainer = /*#__PURE__*/forwardRef((props, ref) => {
91696
- import.meta.css = [css$k, "@jsenv/navi/src/control/table/drag/table_drag.jsx"];
92152
+ import.meta.css = [css$i, "@jsenv/navi/src/control/table/drag/table_drag.jsx"];
91697
92153
  const {
91698
92154
  tableId
91699
92155
  } = props;
@@ -91992,7 +92448,7 @@ const ROW_MIN_HEIGHT = 30;
91992
92448
  const ROW_MAX_HEIGHT = 100;
91993
92449
  const COLUMN_MIN_WIDTH = 50;
91994
92450
  const COLUMN_MAX_WIDTH = 500;
91995
- const css$j = /* css */`@layer navi {
92451
+ const css$h = /* css */`@layer navi {
91996
92452
  .navi_table {
91997
92453
  --table-resizer-handle-color: #063b7c;
91998
92454
  --table-resizer-color: #387ec9;
@@ -92161,7 +92617,7 @@ const css$j = /* css */`@layer navi {
92161
92617
 
92162
92618
  // Column resize components
92163
92619
  const TableColumnResizer = props => {
92164
- import.meta.css = [css$j, "@jsenv/navi/src/control/table/resize/table_resize.jsx"];
92620
+ import.meta.css = [css$h, "@jsenv/navi/src/control/table/resize/table_resize.jsx"];
92165
92621
  const defaultRef = useRef();
92166
92622
  const ref = props.ref || defaultRef;
92167
92623
  return jsxs("div", {
@@ -92633,7 +93089,7 @@ const findPreviousTableRow = currentRow => {
92633
93089
  };
92634
93090
 
92635
93091
  installImportMetaCssBuild(import.meta);
92636
- const css$i = /* css */`@layer navi {
93092
+ const css$g = /* css */`@layer navi {
92637
93093
  .navi_table {
92638
93094
  --selection-border-color: var(--navi-selection-border-color, #0078d4);
92639
93095
  --selection-background-color: var(--navi-selection-background-color, #eaf1fd);
@@ -92727,7 +93183,7 @@ const useTableSelectionController = ({
92727
93183
  onSelectionChange,
92728
93184
  selectionColor
92729
93185
  }) => {
92730
- import.meta.css = [css$i, "@jsenv/navi/src/control/table/selection/table_selection.jsx"];
93186
+ import.meta.css = [css$g, "@jsenv/navi/src/control/table/selection/table_selection.jsx"];
92731
93187
  const selectionController = useSelectionController({
92732
93188
  elementRef: tableRef,
92733
93189
  layout: "grid",
@@ -93198,7 +93654,7 @@ const useTableStickyContextValue = ({
93198
93654
  };
93199
93655
 
93200
93656
  installImportMetaCssBuild(import.meta);
93201
- const css$h = /* css */`@layer navi {
93657
+ const css$f = /* css */`@layer navi {
93202
93658
  .navi_table {
93203
93659
  --sticky-frontier-color: silver;
93204
93660
  --sticky-frontier-size: 12px;
@@ -93371,7 +93827,7 @@ const css$h = /* css */`@layer navi {
93371
93827
  const TableStickyFrontier = ({
93372
93828
  tableRef
93373
93829
  }) => {
93374
- import.meta.css = [css$h, "@jsenv/navi/src/control/table/sticky/table_sticky.jsx"];
93830
+ import.meta.css = [css$f, "@jsenv/navi/src/control/table/sticky/table_sticky.jsx"];
93375
93831
  const stickyLeftFrontierGhostRef = useRef();
93376
93832
  const stickyLeftFrontierPreviewRef = useRef();
93377
93833
  const stickyTopFrontierGhostRef = useRef();
@@ -93602,7 +94058,7 @@ installImportMetaCssBuild(import.meta);
93602
94058
  * inset 0 -1px 0 0 color; // Bottom border
93603
94059
  */
93604
94060
 
93605
- const css$g = /* css */ `.navi_table_root {
94061
+ const css$e = /* css */ `.navi_table_root {
93606
94062
  max-width: var(--table-max-width, none);
93607
94063
  max-height: var(--table-max-height, none);
93608
94064
  position: relative;
@@ -93787,11 +94243,11 @@ const css$g = /* css */ `.navi_table_root {
93787
94243
  // table must not carry this sheet, and a build that sees no caller drops the
93788
94244
  // css with the function.
93789
94245
  const installTableCss = () => {
93790
- import.meta.css = [css$g, "@jsenv/navi/src/control/table/table_css.js"];
94246
+ import.meta.css = [css$e, "@jsenv/navi/src/control/table/table_css.js"];
93791
94247
  };
93792
94248
 
93793
94249
  installImportMetaCssBuild(import.meta);
93794
- const css$f = /* css */`.navi_table_ui {
94250
+ const css$d = /* css */`.navi_table_ui {
93795
94251
  z-index: ${Z_INDEX_TABLE_UI};
93796
94252
  pointer-events: none;
93797
94253
  position: fixed;
@@ -93800,7 +94256,7 @@ const css$f = /* css */`.navi_table_ui {
93800
94256
  }
93801
94257
  `;
93802
94258
  const TableUI = /*#__PURE__*/forwardRef((props, ref) => {
93803
- import.meta.css = [css$f, "@jsenv/navi/src/control/table/table_ui.jsx"];
94259
+ import.meta.css = [css$d, "@jsenv/navi/src/control/table/table_ui.jsx"];
93804
94260
  const {
93805
94261
  tableRef,
93806
94262
  tableId,
@@ -94722,7 +95178,7 @@ const normalizeKey = (key) => {
94722
95178
  };
94723
95179
 
94724
95180
  installImportMetaCssBuild(import.meta);
94725
- const css$e = /* css */`.navi_shortcut_container[data-visually-hidden], .navi_shortcut_button[data-visually-hidden] {
95181
+ const css$c = /* css */`.navi_shortcut_container[data-visually-hidden], .navi_shortcut_button[data-visually-hidden] {
94726
95182
  clip: rect(0, 0, 0, 0);
94727
95183
  white-space: nowrap;
94728
95184
  opacity: 0;
@@ -94739,7 +95195,7 @@ const css$e = /* css */`.navi_shortcut_container[data-visually-hidden], .navi_sh
94739
95195
  const ActiveKeyboardShortcuts = ({
94740
95196
  visible
94741
95197
  }) => {
94742
- import.meta.css = [css$e, "@jsenv/navi/src/keyboard/active_keyboard_shortcuts.jsx"];
95198
+ import.meta.css = [css$c, "@jsenv/navi/src/keyboard/active_keyboard_shortcuts.jsx"];
94743
95199
  const activeShortcuts = activeShortcutsSignal.value;
94744
95200
  return jsx("div", {
94745
95201
  className: "navi_shortcut_container",
@@ -94779,7 +95235,7 @@ const KeyboardShortcutAriaElement = ({
94779
95235
  };
94780
95236
 
94781
95237
  installImportMetaCssBuild(import.meta);
94782
- const css$d = /* css */`@layer navi {
95238
+ const css$b = /* css */`@layer navi {
94783
95239
  .navi_clipboard_container {
94784
95240
  --height: 1.5em;
94785
95241
  --notif-spacing: .5em;
@@ -94810,7 +95266,7 @@ const ButtonCopyToClipboard = ({
94810
95266
  children,
94811
95267
  ...props
94812
95268
  }) => {
94813
- import.meta.css = [css$d, "@jsenv/navi/src/control/input/button_copy_to_clipboard.jsx"];
95269
+ import.meta.css = [css$b, "@jsenv/navi/src/control/input/button_copy_to_clipboard.jsx"];
94814
95270
  const [copied, setCopied] = useState(false);
94815
95271
  const renderedRef = useRef();
94816
95272
  useEffect(() => {
@@ -94890,7 +95346,7 @@ const Address = ({
94890
95346
  };
94891
95347
 
94892
95348
  installImportMetaCssBuild(import.meta);
94893
- const css$c = /* css */`@layer navi;
95349
+ const css$a = /* css */`@layer navi;
94894
95350
 
94895
95351
  .navi_text.navi_badge_count {
94896
95352
  white-space: nowrap;
@@ -95019,7 +95475,7 @@ const BadgeCount = ({
95019
95475
  lineLayout,
95020
95476
  ...props
95021
95477
  }) => {
95022
- import.meta.css = [css$c, "@jsenv/navi/src/text/badge_count.jsx"];
95478
+ import.meta.css = [css$a, "@jsenv/navi/src/text/badge_count.jsx"];
95023
95479
  const defaultRef = useRef();
95024
95480
  props.ref = props.ref || defaultRef;
95025
95481
  const {
@@ -95162,7 +95618,7 @@ const BadgeCountCircle = ({
95162
95618
  };
95163
95619
 
95164
95620
  installImportMetaCssBuild(import.meta);
95165
- const css$b = /* css */`@layer navi {
95621
+ const css$9 = /* css */`@layer navi {
95166
95622
  .navi_caption {
95167
95623
  --color: #6b7280;
95168
95624
  }
@@ -95182,7 +95638,7 @@ const Caption = ({
95182
95638
  className,
95183
95639
  ...rest
95184
95640
  }) => {
95185
- import.meta.css = [css$b, "@jsenv/navi/src/text/caption.jsx"];
95641
+ import.meta.css = [css$9, "@jsenv/navi/src/text/caption.jsx"];
95186
95642
  return jsx(Text, {
95187
95643
  as: "small",
95188
95644
  size: "0.8em" // We use em to be relative to the parent (we want to be smaller than the surrounding text)
@@ -95578,177 +96034,8 @@ const Interpolate = ({
95578
96034
  });
95579
96035
  };
95580
96036
 
95581
- const SuccessSvg = () => {
95582
- return jsx("svg", {
95583
- viewBox: "0 0 16 16",
95584
- fill: "currentColor",
95585
- children: jsx("path", {
95586
- d: "M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm1.5 0a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Zm10.28-1.72-4.5 4.5a.75.75 0 0 1-1.06 0l-2-2a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018l1.47 1.47 3.97-3.97a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Z"
95587
- })
95588
- });
95589
- };
95590
- const ErrorSvg = () => {
95591
- return jsx("svg", {
95592
- viewBox: "0 0 16 16",
95593
- fill: "currentColor",
95594
- children: jsx("path", {
95595
- d: "M4.47.22A.749.749 0 0 1 5 0h6c.199 0 .389.079.53.22l4.25 4.25c.141.14.22.331.22.53v6a.749.749 0 0 1-.22.53l-4.25 4.25A.749.749 0 0 1 11 16H5a.749.749 0 0 1-.53-.22L.22 11.53A.749.749 0 0 1 0 11V5c0-.199.079-.389.22-.53Zm.84 1.28L1.5 5.31v5.38l3.81 3.81h5.38l3.81-3.81V5.31L10.69 1.5ZM8 4a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 8 4Zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"
95596
- })
95597
- });
95598
- };
95599
- const InfoSvg$1 = () => {
95600
- return jsx("svg", {
95601
- viewBox: "0 0 16 16",
95602
- fill: "currentColor",
95603
- children: jsx("path", {
95604
- d: "M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"
95605
- })
95606
- });
95607
- };
95608
- const WarningSvg = () => {
95609
- return jsx("svg", {
95610
- viewBox: "0 0 16 16",
95611
- fill: "currentColor",
95612
- children: jsx("path", {
95613
- d: "M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"
95614
- })
95615
- });
95616
- };
95617
-
95618
96037
  installImportMetaCssBuild(import.meta);
95619
- const css$a = /* css */`@layer navi {
95620
- .navi_message_box {
95621
- --background-color-info: var(--navi-info-color-light);
95622
- --color-info: var(--navi-info-color);
95623
- --background-color-success: var(--navi-success-color-light);
95624
- --color-success: var(--navi-success-color);
95625
- --background-color-warning: var(--navi-warning-color-light);
95626
- --color-warning: var(--navi-warning-color);
95627
- --background-color-error: var(--navi-error-color-light);
95628
- --color-error: var(--navi-error-color);
95629
- }
95630
- }
95631
-
95632
- .navi_message_box {
95633
- --x-message-background-color: var(--background-color-info);
95634
- --x-message-color: var(--color-info);
95635
- background-color: var(--x-message-background-color);
95636
-
95637
- & > .navi_icon {
95638
- flex-shrink: 0;
95639
- }
95640
- }
95641
-
95642
- .navi_message_box[data-status-info] {
95643
- --x-message-background-color: var(--background-color-info);
95644
- --x-message-color: var(--color-info);
95645
- }
95646
-
95647
- .navi_message_box[data-status-success] {
95648
- --x-message-background-color: var(--background-color-success);
95649
- --x-message-color: var(--color-success);
95650
- }
95651
-
95652
- .navi_message_box[data-status-warning] {
95653
- --x-message-background-color: var(--background-color-warning);
95654
- --x-message-color: var(--color-warning);
95655
- }
95656
-
95657
- .navi_message_box[data-status-error] {
95658
- --x-message-background-color: var(--background-color-error);
95659
- --x-message-color: var(--color-error);
95660
- }
95661
-
95662
- .navi_message_box[data-left-stripe] {
95663
- border-left: 6px solid var(--x-message-color);
95664
- border-top-left-radius: 6px;
95665
- border-bottom-left-radius: 6px;
95666
- }
95667
- `;
95668
- const MessageBox = ({
95669
- status = "info",
95670
- padding = "sm",
95671
- icon,
95672
- leftStripe,
95673
- children,
95674
- onClose,
95675
- ...rest
95676
- }) => {
95677
- import.meta.css = [css$a, "@jsenv/navi/src/text/message_box.jsx"];
95678
- const [hasTitleChild, setHasTitleChild] = useState(false);
95679
- const innerLeftStripe = leftStripe === undefined ? hasTitleChild : leftStripe;
95680
- if (icon === true) {
95681
- icon = status === "info" ? jsx(InfoSvg$1, {}) : status === "success" ? jsx(SuccessSvg, {}) : status === "warning" ? jsx(WarningSvg, {}) : status === "error" ? jsx(ErrorSvg, {}) : null;
95682
- } else if (typeof icon === "function") {
95683
- const Comp = icon;
95684
- icon = jsx(Comp, {});
95685
- }
95686
- return jsx(Box, {
95687
- as: "div",
95688
- role: status === "info" ? "status" : "alert",
95689
- "data-left-stripe": innerLeftStripe ? "" : undefined,
95690
- inline: true,
95691
- column: true,
95692
- alignY: "center",
95693
- spacing: "s",
95694
- ...rest,
95695
- className: withPropsClassName("navi_message_box", rest.className),
95696
- padding: padding,
95697
- pseudoClasses: MessageBoxPseudoClasses,
95698
- basePseudoState: {
95699
- ":-navi-status-info": status === "info",
95700
- ":-navi-status-success": status === "success",
95701
- ":-navi-status-warning": status === "warning",
95702
- ":-navi-status-error": status === "error"
95703
- },
95704
- children: jsx(MessageBoxStatusContext.Provider, {
95705
- value: status,
95706
- children: jsxs(MessageBoxReportTitleChildContext.Provider, {
95707
- value: setHasTitleChild,
95708
- children: [icon && jsx(Icon, {
95709
- color: "var(--x-message-color)",
95710
- height: "1lh",
95711
- maxHeight: "auto",
95712
- selfAlignY: "start",
95713
- aspectRatio: "auto",
95714
- children: icon
95715
- }), jsx(Text, {
95716
- children: children
95717
- }), onClose &&
95718
- // A column as tall as the first line of the message, pinned to the
95719
- // top, the button centered in it: the close button stays level
95720
- // with the first line however many lines the message takes (same
95721
- // layout as Callout).
95722
- jsx(Box, {
95723
- flex: true,
95724
- alignY: "center",
95725
- height: "1lh",
95726
- selfAlignY: "start",
95727
- shrink: false,
95728
- children: jsx(Button, {
95729
- action: onClose,
95730
- icon: true,
95731
- border: "none",
95732
- style: {
95733
- ":hover": {
95734
- backgroundColor: "rgba(0, 0, 0, 0.1)"
95735
- }
95736
- },
95737
- children: jsx(Icon, {
95738
- children: jsx(CloseSvg, {})
95739
- })
95740
- })
95741
- })]
95742
- })
95743
- })
95744
- });
95745
- };
95746
- const MessageBoxPseudoClasses = [":-navi-status-info", ":-navi-status-success", ":-navi-status-warning", ":-navi-status-error"];
95747
- const MessageBoxStatusContext = createContext();
95748
- const MessageBoxReportTitleChildContext = createContext();
95749
-
95750
- installImportMetaCssBuild(import.meta);
95751
- const css$9 = /* css */`@layer navi;
96038
+ const css$8 = /* css */`@layer navi;
95752
96039
 
95753
96040
  .navi_quantity {
95754
96041
  flex-direction: column;
@@ -95849,7 +96136,7 @@ const Quantity = ({
95849
96136
  bold = true,
95850
96137
  ...props
95851
96138
  }) => {
95852
- import.meta.css = [css$9, "@jsenv/navi/src/text/quantity.jsx"];
96139
+ import.meta.css = [css$8, "@jsenv/navi/src/text/quantity.jsx"];
95853
96140
  const value = parseQuantityValue(children);
95854
96141
  const valueRounded = integer && typeof value === "number" ? Math.round(value) : value;
95855
96142
  const valueFormatted = typeof valueRounded === "number" ? formatNumber(valueRounded, {
@@ -95908,7 +96195,7 @@ const parseQuantityValue = children => {
95908
96195
  };
95909
96196
 
95910
96197
  installImportMetaCssBuild(import.meta);
95911
- const css$8 = /* css */`@layer navi {
96198
+ const css$7 = /* css */`@layer navi {
95912
96199
  .navi_meter {
95913
96200
  --loader-color: var(--navi-loader-color);
95914
96201
  --track-color: #efefef;
@@ -96047,7 +96334,7 @@ const Meter = ({
96047
96334
  style,
96048
96335
  ...rest
96049
96336
  }) => {
96050
- import.meta.css = [css$8, "@jsenv/navi/src/text/meter.jsx"];
96337
+ import.meta.css = [css$7, "@jsenv/navi/src/text/meter.jsx"];
96051
96338
  const defaultRef = useRef();
96052
96339
  const ref = rest.ref || defaultRef;
96053
96340
  value = Number(value);
@@ -96162,7 +96449,7 @@ const Paragraph = props => {
96162
96449
  };
96163
96450
 
96164
96451
  installImportMetaCssBuild(import.meta);
96165
- const css$7 = /* css */`.navi_text_box {
96452
+ const css$6 = /* css */`.navi_text_box {
96166
96453
  align-items: flex-start;
96167
96454
  min-width: 0;
96168
96455
  }
@@ -96204,7 +96491,7 @@ const TextBox = ({
96204
96491
  children,
96205
96492
  ...rest
96206
96493
  }) => {
96207
- import.meta.css = [css$7, "@jsenv/navi/src/text/text_box.jsx"];
96494
+ import.meta.css = [css$6, "@jsenv/navi/src/text/text_box.jsx"];
96208
96495
  const boxRef = useRef(null);
96209
96496
  const contentRef = useRef(null);
96210
96497
  useLayoutEffect(() => {
@@ -96250,40 +96537,6 @@ const adjustWidth = (boxEl, contentEl) => {
96250
96537
  contentEl.style.width = `${Math.ceil(optimalWidth)}px`;
96251
96538
  };
96252
96539
 
96253
- installImportMetaCssBuild(import.meta);
96254
- const css$6 = /* css */`.navi_message_box {
96255
- & .navi_title {
96256
- margin-top: 0;
96257
- margin-bottom: var(--navi-s);
96258
- color: var(--x-message-color);
96259
- }
96260
- }
96261
- `;
96262
- const Title = props => {
96263
- import.meta.css = [css$6, "@jsenv/navi/src/text/title.jsx"];
96264
- const messageBoxStatus = useContext(MessageBoxStatusContext);
96265
- const innerAs = props.as || (messageBoxStatus ? "h4" : "h1");
96266
- const titleLevel = parseInt(innerAs.slice(1));
96267
- const reportTitleToMessageBox = useContext(MessageBoxReportTitleChildContext);
96268
- reportTitleToMessageBox?.(true);
96269
- return jsx(TitleLevelContext.Provider, {
96270
- value: titleLevel,
96271
- children: jsx(Text, {
96272
- bold: true,
96273
- className: withPropsClassName("navi_title"),
96274
- as: messageBoxStatus ? "h4" : "h1",
96275
- ...props,
96276
- pseudoClasses: TitlePseudoClasses,
96277
- children: props.children
96278
- })
96279
- });
96280
- };
96281
- const TitleLevelContext = createContext();
96282
- const useTitleLevel = () => {
96283
- return useContext(TitleLevelContext);
96284
- };
96285
- const TitlePseudoClasses = [":hover"];
96286
-
96287
96540
  installImportMetaCssBuild(import.meta);
96288
96541
  const css$5 = /* css */`@keyframes navi_image_shimmer {
96289
96542
  0% {