@jsenv/navi 0.27.53 → 0.27.54

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.
@@ -8891,11 +8891,35 @@ import.meta.css = [/* css */`
8891
8891
  const PSEUDO_CLASSES_DEFAULT = [];
8892
8892
  const PSEUDO_ELEMENTS_DEFAULT = [];
8893
8893
  const STYLE_CSS_VARS_DEFAULT = {};
8894
- const PROPS_CSS_VARS_DEFAULT = {};
8895
8894
  // When only pseudoStateSelector is set (no visualSelector), the box owns its
8896
8895
  // visual identity. Only event handlers and these explicit props are forwarded
8897
8896
  // to the inner semantic/interactive child element.
8898
8897
  const PSEUDO_STATE_CHILD_PROP_SET = new Set(["tabIndex", "tabindex"]);
8898
+
8899
+ /**
8900
+ * @type {import("ignore:preact").FunctionComponent<{
8901
+ * as?: string,
8902
+ * className?: string,
8903
+ * style?: import("ignore:preact").JSX.CSSProperties & { [pseudo: string]: import("ignore:preact").JSX.CSSProperties },
8904
+ * styleCSSVars?: { [stylePropName: string]: string },
8905
+ * inline?: boolean,
8906
+ * block?: boolean,
8907
+ * flex?: "x" | "y" | boolean,
8908
+ * grid?: boolean,
8909
+ * display?: "inherit",
8910
+ * pseudoState?: { [stateName: string]: boolean },
8911
+ * pseudoClasses?: string[],
8912
+ * pseudoElements?: string[],
8913
+ * visualSelector?: string,
8914
+ * pseudoStateSelector?: string,
8915
+ * hasChildUsingForwardedProps?: boolean,
8916
+ * childPropSet?: Set<string>,
8917
+ * preventInitialTransition?: boolean,
8918
+ * separator?: import("ignore:preact").ComponentChildren | ((index: number) => import("ignore:preact").ComponentChildren),
8919
+ * children?: import("ignore:preact").ComponentChildren,
8920
+ * [key: string]: any,
8921
+ * }>}
8922
+ */
8899
8923
  const Box = props => {
8900
8924
  const {
8901
8925
  ref,
@@ -8906,7 +8930,6 @@ const Box = props => {
8906
8930
  // style management
8907
8931
  style,
8908
8932
  styleCSSVars = STYLE_CSS_VARS_DEFAULT,
8909
- propsCSSVars = PROPS_CSS_VARS_DEFAULT,
8910
8933
  basePseudoState,
8911
8934
  pseudoState,
8912
8935
  // for demo purposes it's possible to control pseudo state from props
@@ -9165,13 +9188,6 @@ const Box = props => {
9165
9188
  addStyle(value, name, styleContext, boxStylesTarget, context);
9166
9189
  return;
9167
9190
  }
9168
- const propCssVar = propsCSSVars[name];
9169
- if (propCssVar) {
9170
- if (value !== undefined) {
9171
- addCSSVar(value, propCssVar, boxStylesTarget);
9172
- }
9173
- return;
9174
- }
9175
9191
  const isPseudoStyle = styleOrigin === "pseudo_style";
9176
9192
  if (isStyleProp(name)) {
9177
9193
  // it's a style prop, we need first to check if we have css var to handle them
@@ -9205,6 +9221,13 @@ const Box = props => {
9205
9221
  }
9206
9222
  return;
9207
9223
  }
9224
+ const cssVarName = styleCSSVars[name];
9225
+ if (cssVarName) {
9226
+ if (value !== undefined) {
9227
+ addCSSVar(value, cssVarName, boxStylesTarget);
9228
+ }
9229
+ return;
9230
+ }
9208
9231
  // not a style prop what do we do with it?
9209
9232
  // When pseudoStateSelector is set, the child element is the semantic/interactive one
9210
9233
  // When both selectors are set the child IS the component (e.g. Button with scale
@@ -17601,11 +17624,32 @@ const createI18n = ({
17601
17624
  return interpolateText(template, values);
17602
17625
  };
17603
17626
 
17627
+ const has = (key, { lang = activeLang } = {}) => {
17628
+ const resolvedLang = lang ? matchLang(lang, languageMap) : null;
17629
+ if (resolvedLang) {
17630
+ const translations = languageMap.get(resolvedLang);
17631
+ if (translations && key in translations) {
17632
+ return true;
17633
+ }
17634
+ }
17635
+ if (fallbackLang) {
17636
+ const resolvedFallbackLang = matchLang(fallbackLang, languageMap);
17637
+ if (resolvedFallbackLang) {
17638
+ const fallbackTranslations = languageMap.get(resolvedFallbackLang);
17639
+ if (fallbackTranslations && key in fallbackTranslations) {
17640
+ return true;
17641
+ }
17642
+ }
17643
+ }
17644
+ return false;
17645
+ };
17646
+
17604
17647
  // The i18n instance is itself a callable function
17605
17648
  const i18n = (key, values, opts) => format(key, values, opts);
17606
17649
  i18n.add = add;
17607
17650
  i18n.addAll = addAll;
17608
17651
  i18n.addLangKeys = addLangKeys;
17652
+ i18n.has = has;
17609
17653
  i18n.format = format;
17610
17654
  i18n.languageMap = languageMap;
17611
17655
 
@@ -27347,57 +27391,74 @@ const shouldInjectSpacingBetween = (left, right) => {
27347
27391
  };
27348
27392
 
27349
27393
  /**
27350
- * Text component for rendering inline or block text with layout-stable style changes.
27351
- *
27352
- * Most props are forwarded to the underlying `Box` component (as, style, bold, noWrap, …).
27353
- * The props listed below are specific to Text.
27354
- *
27355
- * @param {object} props
27356
- *
27357
- * @param {number} [props.maxLines]
27358
- * Truncates overflowing text with an ellipsis after at most N lines.
27359
- * `maxLines={1}` truncates after one line (single-line ellipsis).
27360
- * `maxLines={n}` (n > 1) truncates after n lines (multi-line clamp).
27361
- *
27362
- * @param {string} [props.spacing]
27363
- * Controls the separator injected between child nodes.
27364
- * Accepts a size/spacing scale key, a CSS length, or `"pre"` / `0` to disable.
27365
- * Defaults to a regular space character (or a padding-based fake space when
27366
- * `preventSpaceUnderlines` is active).
27394
+ * @type {import("ignore:preact").FunctionComponent<{
27395
+ * children?: import("ignore:preact").ComponentChildren,
27396
+ * as?: string,
27397
+ * className?: string,
27398
+ * style?: import("ignore:preact").JSX.CSSProperties,
27399
+ * bold?: boolean,
27400
+ * noWrap?: boolean,
27401
+ * maxLines?: number,
27402
+ * spacing?: string | number | import("ignore:preact").ComponentChildren,
27403
+ * loading?: boolean,
27404
+ * skeleton?: boolean,
27405
+ * preventSpaceUnderlines?: boolean,
27406
+ * holdSpaceForStyle?: import("ignore:preact").JSX.CSSProperties,
27407
+ * boldStable?: boolean,
27408
+ * shrinkWrap?: boolean,
27409
+ * capitalize?: boolean,
27410
+ * selectRange?: string | [number, number],
27411
+ * childrenOutsideFlow?: import("ignore:preact").ComponentChildren,
27412
+ * [key: string]: any,
27413
+ * }>}
27367
27414
  *
27368
- * @param {boolean} [props.loading]
27369
- * Renders a shimmer skeleton in place of the text.
27370
- *
27371
- * @param {boolean} [props.skeleton]
27372
- * Same as `loading` but without the shimmer animation.
27373
- *
27374
- * @param {boolean} [props.preventSpaceUnderlines]
27375
- * Replaces real space characters between children with padding-based spaces
27376
- * to avoid the underline browsers draw under spaces inside links.
27377
- *
27378
- * @param {object} [props.holdSpaceForStyle]
27379
- * Prevents layout shifts when text styles change (font-weight, font-size, …).
27380
- * Pass an object of CSS-in-JS style properties representing the "maximum" state of the text.
27381
- * An invisible placeholder is rendered with those styles to reserve the space,
27382
- * and the real visible text is layered on top via `position: absolute`.
27383
- * Only works reliably with single-line (`noWrap`) text.
27384
- * Example: `holdSpaceForStyle={{ fontWeight: "bold", fontSize: "1.5rem" }}`
27385
- *
27386
- * @param {boolean} [props.boldStable]
27387
- * Alternative to `holdSpaceForStyle` for multi-line text.
27388
- * Keeps a consistent visual width regardless of font-weight by painting normal-weight
27389
- * text on top of a bold background using `background-clip: text`.
27390
- * Does not support font-size changes.
27391
- *
27392
- * @param {boolean} [props.capitalize]
27393
- * Applies `text-transform: uppercase` to the first letter via CSS.
27394
- *
27395
- * @param {string|Array} [props.selectRange]
27396
- * Selects a portion of the text on mount. Forwarded to `useInitialTextSelection`.
27397
- *
27398
- * @param {*} [props.childrenOutsideFlow]
27399
- * Rendered after children but outside the text flow (useful for overlays
27400
- * like the skeleton container).
27415
+ * @param {number} [maxLines]
27416
+ * Truncates overflowing text with an ellipsis. `maxLines={1}` produces a
27417
+ * single-line truncation; `maxLines={n}` (n > 1) uses `-webkit-line-clamp`
27418
+ * to allow up to n lines before clipping.
27419
+ *
27420
+ * @param {string|number} [spacing]
27421
+ * Separator injected between child nodes. Accepts a size token (`"s"`, `"m"`, …),
27422
+ * a CSS length string, a number (interpreted as px), or `"pre"` / `0` to
27423
+ * disable spacing entirely. Defaults to a regular space character.
27424
+ *
27425
+ * @param {boolean} [loading]
27426
+ * Renders a shimmer skeleton animation in place of the text content.
27427
+ *
27428
+ * @param {boolean} [skeleton]
27429
+ * Same as `loading` but without the shimmer animation a static grey bar.
27430
+ *
27431
+ * @param {boolean} [preventSpaceUnderlines]
27432
+ * Replaces real space characters between children with padding-based spaces.
27433
+ * Useful inside `<a>` elements where browsers draw an underline under spaces.
27434
+ *
27435
+ * @param {import("ignore:preact").JSX.CSSProperties} [holdSpaceForStyle]
27436
+ * Prevents layout shifts when text styles change (e.g. font-weight, font-size).
27437
+ * Pass the CSS properties representing the "largest" visual state of the text.
27438
+ * An invisible placeholder rendered with those styles reserves the space; the
27439
+ * real visible text is layered on top via `position: absolute`.
27440
+ * Best combined with `noWrap` does not work reliably on multi-line text.
27441
+ *
27442
+ * @param {boolean} [boldStable]
27443
+ * Alternative to `holdSpaceForStyle` for multi-line text. Keeps a consistent
27444
+ * visual width across bold/normal transitions by painting normal-weight text
27445
+ * over a bold background using `background-clip: text`. Does not handle
27446
+ * font-size changes.
27447
+ *
27448
+ * @param {boolean} [shrinkWrap]
27449
+ * Forces the element width to match its longest visual line, preventing the
27450
+ * text block from being wider than its content when inside a flex/grid container.
27451
+ *
27452
+ * @param {boolean} [capitalize]
27453
+ * Uppercases the first letter of the text content via CSS.
27454
+ *
27455
+ * @param {string|[number,number]} [selectRange]
27456
+ * Selects a portion of the text on mount. Pass a substring to search for, or
27457
+ * a `[start, end]` character-offset tuple.
27458
+ *
27459
+ * @param {import("ignore:preact").ComponentChildren} [childrenOutsideFlow]
27460
+ * Rendered after children but outside the text spacing/flow logic. Used
27461
+ * internally for overlays such as the skeleton container.
27401
27462
  */
27402
27463
  const Text = props => {
27403
27464
  const defaultRef = useRef();
@@ -34374,21 +34435,13 @@ const Unit = ({
34374
34435
  let unitText = unit;
34375
34436
  if (label) {
34376
34437
  unitText = label;
34377
- } else {
34438
+ } else if (naviI18n.has(unit, {
34439
+ lang
34440
+ })) {
34378
34441
  const singularText = naviI18n(unit, undefined, {
34379
34442
  lang
34380
34443
  });
34381
- if (singularText === unit) {
34382
- // naviI18n has no translation — try Intl.NumberFormat with style:"unit"
34383
- const intlText = formatIntlUnit(unit, {
34384
- plural,
34385
- lang,
34386
- format
34387
- });
34388
- if (intlText !== null) {
34389
- unitText = intlText;
34390
- }
34391
- } else if (format === "short" || format === "narrow") {
34444
+ if (format === "short" || format === "narrow") {
34392
34445
  const shortKey = `${unit}__short`;
34393
34446
  const shortText = naviI18n(shortKey, undefined, {
34394
34447
  lang
@@ -34404,6 +34457,18 @@ const Unit = ({
34404
34457
  } else {
34405
34458
  unitText = singularText;
34406
34459
  }
34460
+ } else {
34461
+ // naviI18n has no translation — try Intl.NumberFormat with style:"unit"
34462
+ const intlText = formatIntlUnit(unit, {
34463
+ plural,
34464
+ lang,
34465
+ format
34466
+ });
34467
+ if (intlText === null) {
34468
+ unitText = unit;
34469
+ } else {
34470
+ unitText = intlText;
34471
+ }
34407
34472
  }
34408
34473
  return jsx(Text, {
34409
34474
  baseClassName: "navi_unit",
@@ -35834,6 +35899,15 @@ const POPOVER_PSEUDO_CLASSES = [":hover", ":active", ":focus", ":focus-visible",
35834
35899
 
35835
35900
  installImportMetaCssBuild(import.meta);const css$p = /* css */`
35836
35901
  .navi_picker {
35902
+ /* Shared by popover and dialog */
35903
+ --picker-popup-background-color: var(--picker-background-color);
35904
+ --picker-popup-border-radius: var(--picker-border-radius);
35905
+ /* Popover */
35906
+ --picker-popover-max-height: 300px;
35907
+ /* Dialog */
35908
+ --picker-dialog-max-width: 95dvw;
35909
+ --picker-dialog-max-height: 95dvh;
35910
+
35837
35911
  /* popover */
35838
35912
  &[aria-haspopup="listbox"] {
35839
35913
  .navi_picker_popover {
@@ -35842,14 +35916,17 @@ installImportMetaCssBuild(import.meta);const css$p = /* css */`
35842
35916
  min-width: var(--anchor-width, 0px);
35843
35917
  max-width: 95vw;
35844
35918
  /* max-height covers the placeholder + list; the list scrolls internally */
35845
- max-height: min(var(--picker-popup-max-height, 300px), var(--space-available, 95dvh));
35919
+ max-height: min(
35920
+ var(--picker-popover-max-height),
35921
+ var(--space-available, 95dvh)
35922
+ );
35846
35923
  margin: 0;
35847
35924
  padding: 0;
35848
- background: var(--picker-background-color);
35925
+ background: var(--picker-popup-background-color);
35849
35926
  border-width: var(--picker-border-width);
35850
35927
  border-style: solid;
35851
35928
  border-color: var(--x-picker-border-color);
35852
- border-radius: var(--picker-border-radius);
35929
+ border-radius: var(--picker-popup-border-radius);
35853
35930
  outline-width: var(--picker-outline-width);
35854
35931
  outline-color: var(--picker-outline-color);
35855
35932
  outline-offset: 0px;
@@ -35857,7 +35934,7 @@ installImportMetaCssBuild(import.meta);const css$p = /* css */`
35857
35934
  0 4px 8px rgba(0, 0, 0, 0.08),
35858
35935
  0 12px 40px rgba(0, 0, 0, 0.22);
35859
35936
  cursor: default; /* Reset pointer cursor within the select */
35860
- overflow: hidden;
35937
+ overflow: auto;
35861
35938
  overscroll-behavior: none;
35862
35939
 
35863
35940
  /* The anchor placeholder is a non-interactive visual clone of the
@@ -35905,7 +35982,7 @@ installImportMetaCssBuild(import.meta);const css$p = /* css */`
35905
35982
  width: 100%;
35906
35983
  border-radius: max(
35907
35984
  0px,
35908
- var(--picker-border-radius) - var(--picker-border-width)
35985
+ var(--picker-popup-border-radius) - var(--picker-border-width)
35909
35986
  );
35910
35987
  overflow: auto;
35911
35988
  overscroll-behavior: none;
@@ -35934,16 +36011,13 @@ installImportMetaCssBuild(import.meta);const css$p = /* css */`
35934
36011
  /* dialog */
35935
36012
  &[aria-haspopup="dialog"] {
35936
36013
  .navi_picker_dialog {
35937
- --dialog-max-width: 95dvw;
35938
- --dialog-max-height: 95dvh;
35939
-
35940
36014
  min-width: var(--anchor-width, 0px);
35941
- max-width: var(--dialog-max-width);
35942
- max-height: var(--dialog-max-height);
36015
+ max-width: var(--picker-dialog-max-width);
36016
+ max-height: var(--picker-dialog-max-height);
35943
36017
  padding: 0;
35944
- background: var(--picker-background-color);
36018
+ background: var(--picker-popup-background-color);
35945
36019
  border: var(--picker-border-width) solid var(--x-picker-border-color);
35946
- border-radius: var(--picker-border-radius);
36020
+ border-radius: var(--picker-popup-border-radius);
35947
36021
  outline-width: var(--picker-outline-width);
35948
36022
  outline-color: var(--picker-outline-color);
35949
36023
  outline-offset: 0;
@@ -35954,10 +36028,10 @@ installImportMetaCssBuild(import.meta);const css$p = /* css */`
35954
36028
  /* overscroll-behavior: contain; */
35955
36029
 
35956
36030
  &[data-expand-x] {
35957
- width: var(--dialog-max-width);
36031
+ width: var(--picker-dialog-max-width);
35958
36032
  }
35959
36033
  &[data-expand-y] {
35960
- height: var(--dialog-max-height);
36034
+ height: var(--picker-dialog-max-height);
35961
36035
  }
35962
36036
 
35963
36037
  &[open] {
@@ -35978,7 +36052,7 @@ installImportMetaCssBuild(import.meta);const css$p = /* css */`
35978
36052
  width: 100%;
35979
36053
  border-radius: max(
35980
36054
  0px,
35981
- var(--picker-border-radius) - var(--picker-border-width)
36055
+ var(--picker-popup-border-radius) - var(--picker-border-width)
35982
36056
  );
35983
36057
  overflow: auto;
35984
36058
  overscroll-behavior: none;
@@ -40902,6 +40976,9 @@ const PickerStyleCSSVars = {
40902
40976
  "outlineWidth": "--picker-outline-width",
40903
40977
  "borderWidth": "--picker-border-width",
40904
40978
  "borderRadius": "--picker-border-radius",
40979
+ "popoverMaxHeight": "--picker-popover-max-height",
40980
+ "popupBackgroundColor": "--picker-popup-background-color",
40981
+ "popupBorderRadius": "--picker-popup-border-radius",
40905
40982
  "padding": "--picker-padding",
40906
40983
  "paddingX": "--picker-padding-x",
40907
40984
  "paddingY": "--picker-padding-y",
@@ -40976,6 +41053,9 @@ const PickerFirstResolver = props => {
40976
41053
  * variant?: "icon" | "headless",
40977
41054
  * icon?: import("ignore:preact").ComponentChildren,
40978
41055
  * maxLines?: number,
41056
+ * popoverMaxHeight?: number | string,
41057
+ * popupBackgroundColor?: string,
41058
+ * popupBorderRadius?: number | string,
40979
41059
  * dialogExpand?: boolean,
40980
41060
  * dialogExpandX?: boolean,
40981
41061
  * dialogExpandY?: boolean,
@@ -45854,6 +45934,26 @@ installImportMetaCssBuild(import.meta);const css$7 = /* css */`
45854
45934
  }
45855
45935
  }
45856
45936
  `;
45937
+
45938
+ /**
45939
+ * @type {import("ignore:preact").FunctionComponent<{
45940
+ * children?: number | string,
45941
+ * unit?: string,
45942
+ * unitPosition?: "right" | "bottom",
45943
+ * unitSize?: string,
45944
+ * unitSizeRatio?: number,
45945
+ * unitColor?: string,
45946
+ * label?: string,
45947
+ * size?: string,
45948
+ * lang?: string,
45949
+ * integer?: boolean,
45950
+ * loading?: boolean,
45951
+ * readOnly?: boolean,
45952
+ * disabled?: boolean,
45953
+ * bold?: boolean,
45954
+ * [key: string]: any,
45955
+ * }>}
45956
+ */
45857
45957
  const Quantity = ({
45858
45958
  children,
45859
45959
  unit,
@@ -45881,7 +45981,7 @@ const Quantity = ({
45881
45981
  return jsxs(Text, {
45882
45982
  baseClassName: "navi_quantity",
45883
45983
  "data-unit-bottom": unitBottom ? "" : undefined,
45884
- propsCSSVars: QuantityPropsCSSVars,
45984
+ styleCSSVars: QuantityStyleCSSVars,
45885
45985
  basePseudoState: {
45886
45986
  ":read-only": readOnly,
45887
45987
  ":disabled": disabled,
@@ -45915,7 +46015,7 @@ const Quantity = ({
45915
46015
  })]
45916
46016
  });
45917
46017
  };
45918
- const QuantityPropsCSSVars = {
46018
+ const QuantityStyleCSSVars = {
45919
46019
  unitColor: "--unit-color"
45920
46020
  };
45921
46021
  const QuantityPseudoClasses = [":hover", ":active", ":read-only", ":disabled", ":-navi-loading"];
@@ -46795,7 +46895,7 @@ const SidePanel = ({
46795
46895
  value: onClose,
46796
46896
  children: jsxs(Box, {
46797
46897
  baseClassName: "navi_side_panel",
46798
- propsCSSVars: SidePanelStyleCSSVars,
46898
+ styleCSSVars: SidePanelStyleCSSVars,
46799
46899
  width: width,
46800
46900
  "data-opening": phase === "opening" ? "" : undefined,
46801
46901
  "data-closing": phase === "closing" ? "" : undefined,