@jsenv/navi 0.18.2 → 0.18.5

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.
@@ -667,6 +667,13 @@ const actionRunEffect = (
667
667
  // normalize falsy values to undefined so that any falsy value ends up in the same state of "don't run the action"
668
668
  return undefined;
669
669
  }
670
+ if (params && typeof params.then === "function") {
671
+ {
672
+ console.warn(
673
+ `actionRunEffect second arg is returning a promise. This is not supported, the function should be sync and return params to give to the action`,
674
+ );
675
+ }
676
+ }
670
677
  if (lastTruthyParams === undefined) {
671
678
  lastTruthyParams = params;
672
679
  }
@@ -5248,6 +5255,7 @@ const FLOW_PROPS = {
5248
5255
  box: () => {},
5249
5256
  row: () => {},
5250
5257
  column: () => {},
5258
+ grid: () => {},
5251
5259
  };
5252
5260
  const OUTER_SPACING_PROPS = {
5253
5261
  margin: PASS_THROUGH,
@@ -5575,6 +5583,22 @@ const CONTENT_PROPS = {
5575
5583
  }
5576
5584
  return undefined;
5577
5585
  },
5586
+ spacingX: (value, { boxFlow }) => {
5587
+ if (boxFlow === "grid") {
5588
+ return {
5589
+ columnGap: resolveSpacingSize(value, "columnGap"),
5590
+ };
5591
+ }
5592
+ return undefined;
5593
+ },
5594
+ spacingY: (value, { boxFlow }) => {
5595
+ if (boxFlow === "grid") {
5596
+ return {
5597
+ rowGap: resolveSpacingSize(value, "rowGap"),
5598
+ };
5599
+ }
5600
+ return undefined;
5601
+ },
5578
5602
  };
5579
5603
  const All_PROPS = {
5580
5604
  ...FLOW_PROPS,
@@ -6407,6 +6431,9 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
6407
6431
  [data-flow-inline][data-flow-column] {
6408
6432
  display: inline-flex;
6409
6433
  }
6434
+ [data-flow-grid] {
6435
+ display: grid;
6436
+ }
6410
6437
  `;
6411
6438
  const PSEUDO_CLASSES_DEFAULT = [];
6412
6439
  const PSEUDO_ELEMENTS_DEFAULT = [];
@@ -6452,7 +6479,8 @@ const Box = props => {
6452
6479
  box,
6453
6480
  inline,
6454
6481
  row,
6455
- column
6482
+ column,
6483
+ grid
6456
6484
  } = rest;
6457
6485
  if (box === "auto" || inline || defaultDisplay === "inline") {
6458
6486
  if (rest.width !== undefined || rest.height !== undefined) {
@@ -6463,7 +6491,7 @@ const Box = props => {
6463
6491
  if (inline === undefined) {
6464
6492
  inline = true;
6465
6493
  }
6466
- if (column === undefined && !row) {
6494
+ if (column === undefined && !row && !grid) {
6467
6495
  column = true;
6468
6496
  }
6469
6497
  }
@@ -6480,6 +6508,8 @@ const Box = props => {
6480
6508
  boxFlow = "row";
6481
6509
  } else if (column) {
6482
6510
  boxFlow = "column";
6511
+ } else if (grid) {
6512
+ boxFlow = "grid";
6483
6513
  } else {
6484
6514
  boxFlow = defaultDisplay;
6485
6515
  }
@@ -6779,6 +6809,7 @@ const Box = props => {
6779
6809
  "data-flow-inline": inline ? "" : undefined,
6780
6810
  "data-flow-row": row ? "" : undefined,
6781
6811
  "data-flow-column": column ? "" : undefined,
6812
+ "data-flow-grid": boxFlow === "grid" ? "" : undefined,
6782
6813
  "data-visual-selector": visualSelector,
6783
6814
  ...selfForwardedProps,
6784
6815
  children: jsx(BoxFlowContext.Provider, {
@@ -12173,6 +12204,11 @@ const applyRouting = (
12173
12204
  reason,
12174
12205
  },
12175
12206
  ) => {
12207
+ if (!updateRoutes) {
12208
+ // .init() not called yet
12209
+ // likely because code does not uses routing at all
12210
+ return {};
12211
+ }
12176
12212
  const {
12177
12213
  loadSet,
12178
12214
  reloadSet,
@@ -22031,18 +22067,33 @@ const useConstraintValidityState = (ref) => {
22031
22067
  installImportMetaCss(import.meta);import.meta.css = /* css */`
22032
22068
  @layer navi {
22033
22069
  label {
22034
- cursor: pointer;
22035
- }
22070
+ &[data-interactive] {
22071
+ cursor: pointer;
22072
+ }
22036
22073
 
22037
- label[data-readonly],
22038
- label[data-disabled] {
22039
- color: rgba(0, 0, 0, 0.5);
22040
- cursor: default;
22074
+ &[data-read-only],
22075
+ &[data-disabled] {
22076
+ color: rgba(0, 0, 0, 0.5);
22077
+ cursor: default;
22078
+ }
22041
22079
  }
22042
22080
  }
22043
22081
  `;
22044
22082
  const ReportReadOnlyOnLabelContext = createContext();
22045
22083
  const ReportDisabledOnLabelContext = createContext();
22084
+ const ReportInteractiveOnLabelContext = createContext();
22085
+ const reportReadOnlyToLabel = value => {
22086
+ const reportReadOnly = useContext(ReportReadOnlyOnLabelContext);
22087
+ reportReadOnly?.(value);
22088
+ };
22089
+ const reportInteractiveToLabel = value => {
22090
+ const reportInteractive = useContext(ReportInteractiveOnLabelContext);
22091
+ reportInteractive?.(value);
22092
+ };
22093
+ const reportDisabledToLabel = value => {
22094
+ const reportDisabled = useContext(ReportDisabledOnLabelContext);
22095
+ reportDisabled?.(value);
22096
+ };
22046
22097
  const LabelPseudoClasses = [":hover", ":active", ":focus", ":focus-visible", ":read-only", ":disabled", ":-navi-loading"];
22047
22098
  const Label = props => {
22048
22099
  const {
@@ -22051,6 +22102,7 @@ const Label = props => {
22051
22102
  children,
22052
22103
  ...rest
22053
22104
  } = props;
22105
+ const [interactive, setInteractive] = useState(false);
22054
22106
  const [inputReadOnly, setInputReadOnly] = useState(false);
22055
22107
  const innerReadOnly = readOnly || inputReadOnly;
22056
22108
  const [inputDisabled, setInputDisabled] = useState(false);
@@ -22063,11 +22115,15 @@ const Label = props => {
22063
22115
  ":read-only": innerReadOnly,
22064
22116
  ":disabled": innerDisabled
22065
22117
  },
22066
- children: jsx(ReportReadOnlyOnLabelContext.Provider, {
22067
- value: setInputReadOnly,
22068
- children: jsx(ReportDisabledOnLabelContext.Provider, {
22069
- value: setInputDisabled,
22070
- children: children
22118
+ "data-interactive": interactive ? "" : undefined,
22119
+ children: jsx(ReportInteractiveOnLabelContext.Provider, {
22120
+ value: setInteractive,
22121
+ children: jsx(ReportReadOnlyOnLabelContext.Provider, {
22122
+ value: setInputReadOnly,
22123
+ children: jsx(ReportDisabledOnLabelContext.Provider, {
22124
+ value: setInputDisabled,
22125
+ children: children
22126
+ })
22071
22127
  })
22072
22128
  })
22073
22129
  });
@@ -22479,8 +22535,6 @@ const InputCheckboxBasic = props => {
22479
22535
  const loadingElement = useContext(LoadingElementContext);
22480
22536
  const uiStateController = useContext(UIStateControllerContext);
22481
22537
  const uiState = useContext(UIStateContext);
22482
- const reportReadOnlyOnLabel = useContext(ReportReadOnlyOnLabelContext);
22483
- const reportDisabledOnLabel = useContext(ReportDisabledOnLabelContext);
22484
22538
  const {
22485
22539
  /* eslint-disable no-unused-vars */
22486
22540
  type,
@@ -22509,8 +22563,9 @@ const InputCheckboxBasic = props => {
22509
22563
  const innerRequired = required || contextRequired;
22510
22564
  const innerLoading = loading || contextLoading && loadingElement === ref.current;
22511
22565
  const innerReadOnly = readOnly || contextReadOnly || innerLoading || uiStateController.readOnly;
22512
- reportReadOnlyOnLabel?.(innerReadOnly);
22513
- reportDisabledOnLabel?.(innerDisabled);
22566
+ reportReadOnlyToLabel(innerReadOnly);
22567
+ reportDisabledToLabel(innerDisabled);
22568
+ reportInteractiveToLabel(true);
22514
22569
  useAutoFocus(ref, autoFocus);
22515
22570
  const remainingProps = useConstraints(ref, rest);
22516
22571
  const checked = Boolean(uiState);
@@ -23204,8 +23259,6 @@ const InputRadioBasic = props => {
23204
23259
  const contextLoadingElement = useContext(LoadingElementContext);
23205
23260
  const uiStateController = useContext(UIStateControllerContext);
23206
23261
  const uiState = useContext(UIStateContext);
23207
- const reportReadOnlyOnLabel = useContext(ReportReadOnlyOnLabelContext);
23208
- const reportDisabledOnLabel = useContext(ReportDisabledOnLabelContext);
23209
23262
  const {
23210
23263
  /* eslint-disable no-unused-vars */
23211
23264
  type,
@@ -23231,8 +23284,9 @@ const InputRadioBasic = props => {
23231
23284
  const innerRequired = required || contextRequired;
23232
23285
  const innerLoading = loading || contextLoading && contextLoadingElement === ref.current;
23233
23286
  const innerReadOnly = readOnly || contextReadOnly || innerLoading || uiStateController.readOnly;
23234
- reportReadOnlyOnLabel?.(innerReadOnly);
23235
- reportDisabledOnLabel?.(innerDisabled);
23287
+ reportReadOnlyToLabel(innerReadOnly);
23288
+ reportDisabledToLabel(innerDisabled);
23289
+ reportInteractiveToLabel(true);
23236
23290
  useAutoFocus(ref, autoFocus);
23237
23291
  const remainingProps = useConstraints(ref, rest);
23238
23292
  const checked = Boolean(uiState);
@@ -23624,7 +23678,6 @@ const InputRangeBasic = props => {
23624
23678
  const contextDisabled = useContext(DisabledContext);
23625
23679
  const contextLoading = useContext(LoadingContext);
23626
23680
  const contextLoadingElement = useContext(LoadingElementContext);
23627
- const reportReadOnlyOnLabel = useContext(ReportReadOnlyOnLabelContext);
23628
23681
  const uiStateController = useContext(UIStateControllerContext);
23629
23682
  const uiState = useContext(UIStateContext);
23630
23683
  const {
@@ -23644,7 +23697,9 @@ const InputRangeBasic = props => {
23644
23697
  const innerReadOnly = readOnly || contextReadOnly || innerLoading || uiStateController.readOnly;
23645
23698
  const innerDisabled = disabled || contextDisabled;
23646
23699
  // infom any <label> parent of our readOnly state
23647
- reportReadOnlyOnLabel?.(innerReadOnly);
23700
+ reportReadOnlyToLabel(innerReadOnly);
23701
+ reportDisabledToLabel(innerDisabled);
23702
+ reportInteractiveToLabel(true);
23648
23703
  useAutoFocus(ref, autoFocus, {
23649
23704
  autoFocusVisible,
23650
23705
  autoSelect
@@ -24123,7 +24178,6 @@ const InputTextualBasic = props => {
24123
24178
  const contextDisabled = useContext(DisabledContext);
24124
24179
  const contextLoading = useContext(LoadingContext);
24125
24180
  const contextLoadingElement = useContext(LoadingElementContext);
24126
- const reportReadOnlyOnLabel = useContext(ReportReadOnlyOnLabelContext);
24127
24181
  const uiStateController = useContext(UIStateControllerContext);
24128
24182
  const uiState = useContext(UIStateContext);
24129
24183
  const {
@@ -24145,8 +24199,10 @@ const InputTextualBasic = props => {
24145
24199
  const innerLoading = loading || contextLoading && contextLoadingElement === ref.current;
24146
24200
  const innerReadOnly = readOnly || contextReadOnly || innerLoading || uiStateController.readOnly;
24147
24201
  const innerDisabled = disabled || contextDisabled;
24148
- // infom any <label> parent of our readOnly state
24149
- reportReadOnlyOnLabel?.(innerReadOnly);
24202
+ // infom any <label> parent of our readOnly state + that we are interactive
24203
+ reportReadOnlyToLabel(innerReadOnly);
24204
+ reportDisabledToLabel(innerDisabled);
24205
+ reportInteractiveToLabel(true);
24150
24206
  useAutoFocus(ref, autoFocus, {
24151
24207
  autoFocusVisible,
24152
24208
  autoSelect
@@ -28824,6 +28880,10 @@ const LoadingDots = ({
28824
28880
  });
28825
28881
  };
28826
28882
 
28883
+ const formatNumber = (value, { lang } = {}) => {
28884
+ return new Intl.NumberFormat(lang).format(value);
28885
+ };
28886
+
28827
28887
  const CSS_VAR_NAME = "--x-color-contrasting";
28828
28888
 
28829
28889
  const useContrastingColor = (ref, backgroundElementSelector) => {
@@ -28953,12 +29013,21 @@ const BadgeCount = ({
28953
29013
  // so that visually the interface do not suddently switch from circle to ellipse depending on the count
28954
29014
  circle,
28955
29015
  max = circle ? MAX_FOR_CIRCLE : Infinity,
29016
+ integer,
29017
+ lang,
28956
29018
  ...props
28957
29019
  }) => {
28958
29020
  const defaultRef = useRef();
28959
29021
  const ref = props.ref || defaultRef;
28960
29022
  useContrastingColor(ref, ".navi_badge_count_visual");
28961
- const valueRequested = typeof children === "string" ? parseInt(children, 10) : children;
29023
+ let valueRequested = (() => {
29024
+ if (typeof children !== "string") return children;
29025
+ const parsed = Number(children);
29026
+ return Number.isNaN(parsed) ? children : parsed;
29027
+ })();
29028
+ if (integer && typeof valueRequested === "number") {
29029
+ valueRequested = Math.round(valueRequested);
29030
+ }
28962
29031
  const valueDisplayed = applyMaxToValue(max, valueRequested);
28963
29032
  const hasOverflow = valueDisplayed !== valueRequested;
28964
29033
  const valueCharCount = String(valueDisplayed).length;
@@ -28975,11 +29044,14 @@ const BadgeCount = ({
28975
29044
  children: [valueDisplayed, hasOverflow && maxElement]
28976
29045
  });
28977
29046
  }
29047
+ const valueFormatted = typeof valueDisplayed === "number" ? formatNumber(valueDisplayed, {
29048
+ lang
29049
+ }) : valueDisplayed;
28978
29050
  return jsxs(BadgeCountEllipse, {
28979
29051
  ...props,
28980
29052
  ref: ref,
28981
29053
  hasOverflow: hasOverflow,
28982
- children: [valueDisplayed, hasOverflow && maxElement]
29054
+ children: [valueFormatted, hasOverflow && maxElement]
28983
29055
  });
28984
29056
  };
28985
29057
  const applyMaxToValue = (max, value) => {
@@ -29374,6 +29446,355 @@ const CodeBox = ({
29374
29446
  });
29375
29447
  };
29376
29448
 
29449
+ installImportMetaCss(import.meta);import.meta.css = /* css */`
29450
+ @layer navi {
29451
+ .navi_stat {
29452
+ --unit-color: color-mix(in srgb, currentColor 50%, white);
29453
+ --unit-ratio: 0.7;
29454
+ }
29455
+ }
29456
+
29457
+ .navi_stat {
29458
+ display: inline-flex;
29459
+ flex-direction: column;
29460
+ align-items: flex-start;
29461
+ gap: 0.3em;
29462
+ line-height: 1;
29463
+
29464
+ .navi_stat_label {
29465
+ font-weight: 600;
29466
+ font-size: 0.75em;
29467
+ text-transform: uppercase;
29468
+ line-height: 1;
29469
+ letter-spacing: 0.06em;
29470
+ }
29471
+ .navi_stat_body {
29472
+ .navi_stat_value {
29473
+ font-weight: bold;
29474
+ }
29475
+ .navi_stat_unit {
29476
+ color: var(--unit-color);
29477
+ font-weight: normal;
29478
+ font-size: calc(var(--unit-ratio) * 1em);
29479
+ }
29480
+ }
29481
+
29482
+ &[data-readonly] {
29483
+ opacity: 0.7;
29484
+ cursor: default;
29485
+ }
29486
+
29487
+ &[data-disabled] {
29488
+ opacity: 0.4;
29489
+ cursor: not-allowed;
29490
+ user-select: none;
29491
+ }
29492
+
29493
+ &[data-unit-bottom] {
29494
+ .navi_stat_value {
29495
+ display: inline-block;
29496
+ width: 100%;
29497
+ text-align: center;
29498
+ }
29499
+ .navi_stat_body {
29500
+ .navi_stat_unit {
29501
+ display: inline-block;
29502
+ width: 100%;
29503
+ text-align: center;
29504
+ }
29505
+ }
29506
+ }
29507
+ }
29508
+ `;
29509
+ const StatPseudoClasses = [":hover", ":active", ":read-only", ":disabled", ":-navi-loading"];
29510
+ const Stat = ({
29511
+ children,
29512
+ unit,
29513
+ unitPosition = "right",
29514
+ unitRatio,
29515
+ label,
29516
+ size,
29517
+ lang,
29518
+ integer,
29519
+ loading,
29520
+ readOnly,
29521
+ disabled,
29522
+ ...props
29523
+ }) => {
29524
+ const value = parseStatValue(children);
29525
+ const valueRounded = integer && typeof value === "number" ? Math.round(value) : value;
29526
+ const valueFormatted = typeof valueRounded === "number" ? formatNumber(valueRounded, {
29527
+ lang
29528
+ }) : valueRounded;
29529
+ const unitBottom = unitPosition === "bottom";
29530
+ return jsxs(Text, {
29531
+ baseClassName: "navi_stat",
29532
+ "data-unit-bottom": unitBottom ? "" : undefined,
29533
+ basePseudoState: {
29534
+ ":read-only": readOnly,
29535
+ ":disabled": disabled,
29536
+ ":-navi-loading": loading
29537
+ },
29538
+ pseudoClasses: StatPseudoClasses,
29539
+ spacing: "pre",
29540
+ ...props,
29541
+ children: [label && jsx("span", {
29542
+ className: "navi_stat_label",
29543
+ children: label
29544
+ }), jsxs(Text, {
29545
+ className: "navi_stat_body",
29546
+ size: size,
29547
+ spacing: unitBottom ? jsx("br", {}) : undefined,
29548
+ children: [jsx("span", {
29549
+ className: "navi_stat_value",
29550
+ children: loading ? jsx(Icon, {
29551
+ flowInline: true,
29552
+ children: jsx(LoadingDots, {})
29553
+ }) : valueFormatted
29554
+ }), unit && jsx("span", {
29555
+ className: "navi_stat_unit",
29556
+ style: {
29557
+ ...(unitRatio === undefined ? {} : {
29558
+ "--unit-ratio": unitRatio
29559
+ })
29560
+ },
29561
+ children: unit
29562
+ })]
29563
+ })]
29564
+ });
29565
+ };
29566
+ const parseStatValue = children => {
29567
+ if (typeof children !== "string") {
29568
+ return children;
29569
+ }
29570
+ const parsed = Number(children);
29571
+ return Number.isNaN(parsed) ? children : parsed;
29572
+ };
29573
+
29574
+ installImportMetaCss(import.meta);import.meta.css = /* css */`
29575
+ @layer navi {
29576
+ .navi_meter {
29577
+ --loader-color: var(--navi-loader-color);
29578
+ --track-color: #efefef;
29579
+ --border-color: #cbcbcb;
29580
+ --border-width: 1px;
29581
+ --border-radius: 5px;
29582
+ --height: 1em;
29583
+ --width: 5em;
29584
+
29585
+ /* Semantic fill colors, matching native meter on Chrome/macOS */
29586
+ --fill-color-optimum: light-dark(#0f7c0f, #4caf50);
29587
+ --fill-color-suboptimum: light-dark(#fdb900, #ffc107);
29588
+ --fill-color-subsuboptimum: light-dark(#d83b01, #f44336);
29589
+ }
29590
+ }
29591
+
29592
+ .navi_meter {
29593
+ position: relative;
29594
+ display: inline-flex;
29595
+ box-sizing: border-box;
29596
+ width: var(--width);
29597
+ height: var(--height);
29598
+ align-items: center;
29599
+ vertical-align: middle;
29600
+
29601
+ .navi_meter_track_container {
29602
+ position: relative;
29603
+ width: 100%;
29604
+ height: calc(var(--height) * 0.5);
29605
+ border-radius: var(--border-radius);
29606
+
29607
+ .navi_meter_track {
29608
+ position: absolute;
29609
+ inset: 0;
29610
+ background-color: var(--track-color);
29611
+ border: var(--border-width) solid var(--border-color);
29612
+ border-radius: inherit;
29613
+ }
29614
+
29615
+ .navi_meter_fill {
29616
+ position: absolute;
29617
+ inset: 0;
29618
+ background-clip: content-box;
29619
+ background-color: var(--x-fill-color);
29620
+ border-width: var(--border-width);
29621
+ border-style: solid;
29622
+ border-color: transparent;
29623
+ border-radius: inherit;
29624
+ clip-path: inset(0 calc((1 - var(--x-fill-ratio, 0)) * 100%) 0 0);
29625
+ }
29626
+
29627
+ .navi_meter_caption {
29628
+ position: absolute;
29629
+ inset: 0;
29630
+ z-index: 1;
29631
+ display: flex;
29632
+ align-items: center;
29633
+ justify-content: center;
29634
+ color: var(--x-caption-color, white);
29635
+ font-size: calc(var(--height) * 0.55);
29636
+ text-shadow:
29637
+ 0 0 4px var(--x-caption-shadow-color, black),
29638
+ 0 0 2px var(--x-caption-shadow-color, black);
29639
+ white-space: nowrap;
29640
+ pointer-events: none;
29641
+ user-select: none;
29642
+ }
29643
+ }
29644
+
29645
+ &[data-disabled] {
29646
+ opacity: 0.4;
29647
+ }
29648
+
29649
+ /* When caption is shown, the track takes the full height */
29650
+ &[data-has-caption] {
29651
+ .navi_meter_track_container {
29652
+ height: var(--height);
29653
+ }
29654
+ }
29655
+ /* fillOnly: hide the empty track background */
29656
+ &[data-fill-only] {
29657
+ .navi_meter_track {
29658
+ background-color: transparent;
29659
+ border-color: transparent;
29660
+ }
29661
+ }
29662
+ &[data-fill-round] {
29663
+ .navi_meter_fill {
29664
+ width: calc(var(--x-fill-ratio) * 100%);
29665
+ clip-path: unset;
29666
+ }
29667
+ }
29668
+ /* borderless: remove border */
29669
+ &[data-borderless] {
29670
+ .navi_meter_track {
29671
+ border-color: transparent;
29672
+ }
29673
+ }
29674
+ }
29675
+ `;
29676
+ const MeterStyleCSSVars = {
29677
+ trackColor: "--track-color",
29678
+ borderColor: "--border-color",
29679
+ borderRadius: "--border-radius",
29680
+ height: "--height",
29681
+ width: "--width"
29682
+ };
29683
+ const MeterPseudoClasses = [":hover", ":active", ":focus", ":focus-visible", ":read-only", ":disabled", ":-navi-loading"];
29684
+ const Meter = ({
29685
+ value = 0,
29686
+ min = 0,
29687
+ max = 1,
29688
+ low,
29689
+ high,
29690
+ optimum,
29691
+ loading,
29692
+ readOnly,
29693
+ disabled,
29694
+ children,
29695
+ percentage,
29696
+ fillOnly,
29697
+ fillRound = fillOnly,
29698
+ borderless,
29699
+ style,
29700
+ ...props
29701
+ }) => {
29702
+ const clampedValue = value < min ? min : value > max ? max : value;
29703
+ const fillRatio = max === min ? 0 : (clampedValue - min) / (max - min);
29704
+ if (children === undefined && percentage) {
29705
+ children = jsx(Stat, {
29706
+ unit: "%",
29707
+ unitRatio: "1",
29708
+ children: Math.round(fillRatio * 100)
29709
+ });
29710
+ }
29711
+ const level = getMeterLevel(clampedValue, min, max, low, high, optimum);
29712
+ const fillColorVar = level === "optimum" ? "var(--fill-color-optimum)" : level === "suboptimum" ? "var(--fill-color-suboptimum)" : "var(--fill-color-subsuboptimum)";
29713
+ reportDisabledToLabel(disabled);
29714
+ reportReadOnlyToLabel(readOnly);
29715
+ const trackContainerRef = useRef();
29716
+ useLayoutEffect(() => {
29717
+ if (!children) {
29718
+ return;
29719
+ }
29720
+ const trackContainer = trackContainerRef.current;
29721
+ if (!trackContainer) {
29722
+ return;
29723
+ }
29724
+ const fillEl = trackContainer.querySelector(".navi_meter_fill");
29725
+ if (!fillEl) {
29726
+ return;
29727
+ }
29728
+ const fillBgColor = getComputedStyle(fillEl).backgroundColor;
29729
+ const textColor = pickLightOrDark(fillBgColor, "white", "black", fillEl);
29730
+ const shadowColor = textColor === "white" ? "black" : "white";
29731
+ trackContainer.style.setProperty("--x-caption-color", textColor);
29732
+ trackContainer.style.setProperty("--x-caption-shadow-color", shadowColor);
29733
+ }, [children, level]);
29734
+ return jsx(Box, {
29735
+ role: "meter",
29736
+ "aria-valuenow": clampedValue,
29737
+ "aria-valuemin": min,
29738
+ "aria-valuemax": max,
29739
+ "aria-label": typeof children === "string" ? children : undefined,
29740
+ baseClassName: "navi_meter",
29741
+ styleCSSVars: MeterStyleCSSVars,
29742
+ basePseudoState: {
29743
+ ":read-only": readOnly,
29744
+ ":disabled": disabled,
29745
+ ":-navi-loading": loading
29746
+ },
29747
+ pseudoClasses: MeterPseudoClasses,
29748
+ "data-has-caption": children !== undefined ? "" : undefined,
29749
+ "data-fill-only": fillOnly ? "" : undefined,
29750
+ "data-fill-round": fillRound ? "" : undefined,
29751
+ "data-borderless": borderless ? "" : undefined,
29752
+ style: {
29753
+ "--x-fill-ratio": fillRatio,
29754
+ "--x-fill-color": fillColorVar,
29755
+ ...style
29756
+ },
29757
+ ...props,
29758
+ children: jsxs("span", {
29759
+ className: "navi_meter_track_container",
29760
+ ref: trackContainerRef,
29761
+ children: [jsx(LoaderBackground, {
29762
+ loading: loading,
29763
+ color: "var(--loader-color)",
29764
+ inset: -1
29765
+ }), jsx("span", {
29766
+ className: "navi_meter_track"
29767
+ }), jsx("span", {
29768
+ className: "navi_meter_fill"
29769
+ }), children && jsx("span", {
29770
+ className: "navi_meter_caption",
29771
+ "aria-hidden": "true",
29772
+ children: children
29773
+ })]
29774
+ })
29775
+ });
29776
+ };
29777
+ const getMeterLevel = (value, min, max, low, high, optimum) => {
29778
+ // Without low/high thresholds the whole range is one region → always optimum
29779
+ if (low === undefined && high === undefined) {
29780
+ return "optimum";
29781
+ }
29782
+ const effectiveLow = low !== undefined ? low : min;
29783
+ const effectiveHigh = high !== undefined ? high : max;
29784
+ const effectiveOptimum = optimum !== undefined ? optimum : (min + max) / 2;
29785
+ const getRegion = v => {
29786
+ if (v < effectiveLow) return 1; // below-low region
29787
+ if (v > effectiveHigh) return 3; // above-high region
29788
+ return 2; // middle region
29789
+ };
29790
+ const optimumRegion = getRegion(effectiveOptimum);
29791
+ const valueRegion = getRegion(value);
29792
+ const distance = Math.abs(optimumRegion - valueRegion);
29793
+ if (distance === 0) return "optimum";
29794
+ if (distance === 1) return "suboptimum";
29795
+ return "subsuboptimum";
29796
+ };
29797
+
29377
29798
  const Paragraph = props => {
29378
29799
  return jsx(Text, {
29379
29800
  marginTop: "md",
@@ -29797,5 +30218,5 @@ const UserSvg = () => jsx("svg", {
29797
30218
  })
29798
30219
  });
29799
30220
 
29800
- export { ActionRenderer, ActiveKeyboardShortcuts, Address, BadgeCount, Box, Button, ButtonCopyToClipboard, Caption, CheckSvg, Checkbox, CheckboxList, Code, Col, Colgroup, ConstructionSvg, Details, DialogLayout, Editable, ErrorBoundaryContext, ExclamationSvg, EyeClosedSvg, EyeSvg, Form, Group, HeartSvg, HomeSvg, Icon, Image, Input, Label, Link, LinkAnchorSvg, LinkBlankTargetSvg, MessageBox, Paragraph, Radio, RadioList, Route, RouteLink, Routes, RowNumberCol, RowNumberTableCell, SINGLE_SPACE_CONSTRAINT, SVGMaskOverlay, SearchSvg, Select, SelectionContext, Separator, SettingsSvg, StarSvg, SummaryMarker, Svg, Tab, TabList, Table, TableCell, Tbody, Text, Thead, Title, Tr, UITransition, UserSvg, ViewportLayout, actionIntegratedVia, actionRunEffect, addCustomMessage, compareTwoJsValues, createAction, createAvailableConstraint, createRequestCanceller, createSelectionKeyboardShortcuts, enableDebugActions, enableDebugOnDocumentLoading, forwardActionRequested, installCustomConstraintValidation, isCellSelected, isColumnSelected, isRowSelected, localStorageSignal, navBack, navForward, navTo, openCallout, rawUrlPart, reload, removeCustomMessage, requestAction, rerunActions, resource, route, routeAction, setBaseUrl, setupRoutes, stateSignal, stopLoad, stringifyTableSelectionValue, updateActions, useActionData, useActionStatus, useArraySignalMembership, useCalloutClose, useCancelPrevious, useCellsAndColumns, useConstraintValidityState, useDependenciesDiff, useDocumentResource, useDocumentState, useDocumentUrl, useEditionController, useFocusGroup, useKeyboardShortcuts, useMatchingRouteInfo, useNavState$1 as useNavState, useRouteStatus, useRunOnMount, useSelectableElement, useSelectionController, useSignalSync, useStateArray, useTitleLevel, useUrlSearchParam, valueInLocalStorage };
30221
+ export { ActionRenderer, ActiveKeyboardShortcuts, Address, BadgeCount, Box, Button, ButtonCopyToClipboard, Caption, CheckSvg, Checkbox, CheckboxList, Code, Col, Colgroup, ConstructionSvg, Details, DialogLayout, Editable, ErrorBoundaryContext, ExclamationSvg, EyeClosedSvg, EyeSvg, Form, Group, HeartSvg, HomeSvg, Icon, Image, Input, Label, Link, LinkAnchorSvg, LinkBlankTargetSvg, MessageBox, Meter, Paragraph, Radio, RadioList, Route, RouteLink, Routes, RowNumberCol, RowNumberTableCell, SINGLE_SPACE_CONSTRAINT, SVGMaskOverlay, SearchSvg, Select, SelectionContext, Separator, SettingsSvg, StarSvg, Stat, SummaryMarker, Svg, Tab, TabList, Table, TableCell, Tbody, Text, Thead, Title, Tr, UITransition, UserSvg, ViewportLayout, actionIntegratedVia, actionRunEffect, addCustomMessage, compareTwoJsValues, createAction, createAvailableConstraint, createRequestCanceller, createSelectionKeyboardShortcuts, enableDebugActions, enableDebugOnDocumentLoading, forwardActionRequested, installCustomConstraintValidation, isCellSelected, isColumnSelected, isRowSelected, localStorageSignal, navBack, navForward, navTo, openCallout, rawUrlPart, reload, removeCustomMessage, requestAction, rerunActions, resource, route, routeAction, setBaseUrl, setupRoutes, stateSignal, stopLoad, stringifyTableSelectionValue, updateActions, useActionData, useActionStatus, useArraySignalMembership, useCalloutClose, useCancelPrevious, useCellsAndColumns, useConstraintValidityState, useDependenciesDiff, useDocumentResource, useDocumentState, useDocumentUrl, useEditionController, useFocusGroup, useKeyboardShortcuts, useMatchingRouteInfo, useNavState$1 as useNavState, useRouteStatus, useRunOnMount, useSelectableElement, useSelectionController, useSignalSync, useStateArray, useTitleLevel, useUrlSearchParam, valueInLocalStorage };
29801
30222
  //# sourceMappingURL=jsenv_navi.js.map