@jsenv/navi 0.29.172 → 0.29.174

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.
@@ -1489,6 +1489,11 @@ naviI18n.addAll({
1489
1489
  fr: "Cette action attend une modification.",
1490
1490
  en: "This action is waiting for a change.",
1491
1491
  },
1492
+ // parallelGuard: the surface already has as many runs in flight as it allows
1493
+ "constraint.readonly.parallel_guard": {
1494
+ fr: "[max] action[s] déjà en cours, attendez qu'une se termine.",
1495
+ en: "[max] action[s] already in progress, wait for one to finish.",
1496
+ },
1492
1497
  "constraint.readonly.network_policy": {
1493
1498
  fr: "Hors ligne : ça ne peut pas partir.",
1494
1499
  en: "Offline: this cannot be sent.",
@@ -8365,7 +8370,16 @@ const createCalloutManager = (
8365
8370
  // Resolved as the token is added, and kept with it: a token shown later
8366
8371
  // (when the one covering it goes) must be drawn where it was pointing at
8367
8372
  // the time, and the control itself is where a token pointing nowhere goes.
8368
- anchorElement: anchorElement || controller.ref.current,
8373
+ //
8374
+ // Unless the control has somewhere better to send it, which is why it is
8375
+ // given the event: a control drawn by something else — a list row whose
8376
+ // selection is a visually hidden checkbox — answers for a whole box, and
8377
+ // the sentence belongs where the press landed inside it rather than in
8378
+ // its middle (see getCalloutAnchorElement in list_selectable.jsx).
8379
+ anchorElement:
8380
+ anchorElement ||
8381
+ controller.getCalloutAnchorElement?.(event) ||
8382
+ controller.ref.current,
8369
8383
  };
8370
8384
  tokens.set(token, tokenData);
8371
8385
  showToken(tokenData, event);
@@ -8981,8 +8995,13 @@ const formatSecondDuration = (
8981
8995
  * are preserved as-is and non-numeric mid-edit values (e.g. "2a") are rendered
8982
8996
  * with their unit symbol rather than being stringified.
8983
8997
  *
8984
- * @param {{ years?: any, months?: any, weeks?: any, days?: any,
8985
- * hours?: any, minutes?: any, seconds?: any, milliseconds?: any }} duration
8998
+ * @param {string|number|{ years?: any, months?: any, weeks?: any, days?: any,
8999
+ * hours?: any, minutes?: any, seconds?: any, milliseconds?: any }} duration -
9000
+ * A string goes through {@link parseDuration} ("PT1H30M", "1h30"), a number
9001
+ * is read as seconds. Each unit is written with the value it carries: 90
9002
+ * minutes reads "90 minutes", never "1 heure 30" — the variants that
9003
+ * promote a count into bigger units are {@link formatMinuteDuration},
9004
+ * {@link formatHourDuration} and {@link formatSecondDuration}.
8986
9005
  * @param {{ lang?: string, format?: "long"|"short"|"narrow"|"compact" }} [options]
8987
9006
  *
8988
9007
  * @example
@@ -10227,6 +10246,15 @@ const readOnlyMessage = (field) => {
10227
10246
  if (reason === "network-policy") {
10228
10247
  return getNetworkPolicyReadOnlyMessage();
10229
10248
  }
10249
+ // As many runs as the surface allows are already out (see parallel_guard.js):
10250
+ // what stops the press is the queue, and it says how long it is.
10251
+ if (reason === "parallel-guard") {
10252
+ const { max } = field.parallelGuard;
10253
+ return naviI18n("constraint.readonly.parallel_guard", {
10254
+ max,
10255
+ s: max > 1 ? "s" : "",
10256
+ });
10257
+ }
10230
10258
  // A send button held back by the form above it, which holds nothing new (see
10231
10259
  // Button's own `readOnlyWhileFormUnchanged`) — what stops the press is not the
10232
10260
  // button, it is the form still waiting for a change, so that is what it says.
@@ -33522,6 +33550,70 @@ document.body.addEventListener(
33522
33550
  { capture: true },
33523
33551
  );
33524
33552
 
33553
+ /**
33554
+ * How many runs a surface lets happen at once.
33555
+ *
33556
+ * A list whose rows each carry their own action is a place to act, row by row,
33557
+ * and nothing about it stops someone from starting a run on every row before
33558
+ * any of them comes back: a dozen requests in flight, a dozen rows waiting, and
33559
+ * a server asked to do a dozen things at once because a list happened to be
33560
+ * long. The guard is what makes the surface say "not yet" instead — the rows
33561
+ * that are not running go read-only and say what they are waiting for, and the
33562
+ * next press is possible again the moment one of the runs comes back.
33563
+ *
33564
+ * It counts runs, not values — which is what separates it from
33565
+ * `maxLengthGuard`, the one that says how many things a selection may HOLD.
33566
+ * Both refuse a gesture; they refuse it for unrelated reasons and a surface can
33567
+ * carry either, or both.
33568
+ */
33569
+ const ParallelGuardContext = createContext(null);
33570
+
33571
+ /**
33572
+ * @param {number} max - how many runs may be in flight at once. `Infinity`
33573
+ * lifts the guard without taking it out of the tree.
33574
+ */
33575
+ const useParallelGuard = (max) => {
33576
+ const guardRef = useRef(null);
33577
+ if (!guardRef.current) {
33578
+ // A Set rather than a counter: a control asks about ITSELF (its own run is
33579
+ // never what blocks it), and a start that arrives twice for one run must
33580
+ // not be counted twice.
33581
+ const runningSet = new Set();
33582
+ const runningCountSignal = signal(0);
33583
+ const guard = {
33584
+ max,
33585
+ runningCountSignal,
33586
+ claim: (controller) => {
33587
+ if (runningSet.has(controller)) {
33588
+ return;
33589
+ }
33590
+ runningSet.add(controller);
33591
+ runningCountSignal.value = runningSet.size;
33592
+ },
33593
+ release: (controller) => {
33594
+ if (!runningSet.delete(controller)) {
33595
+ return;
33596
+ }
33597
+ runningCountSignal.value = runningSet.size;
33598
+ },
33599
+ blocks: (controller) => {
33600
+ if (guard.max === Infinity) {
33601
+ return false;
33602
+ }
33603
+ if (runningSet.has(controller)) {
33604
+ return false;
33605
+ }
33606
+ // Read through the signal so a control held back re-renders — and
33607
+ // becomes pressable again — the moment one of the runs comes back.
33608
+ return runningCountSignal.value >= guard.max;
33609
+ },
33610
+ };
33611
+ guardRef.current = guard;
33612
+ }
33613
+ guardRef.current.max = max;
33614
+ return guardRef.current;
33615
+ };
33616
+
33525
33617
  /**
33526
33618
  * How a control tells the labels pointing at it what it is (disabled, readOnly,
33527
33619
  * required) and when it goes away.
@@ -34437,6 +34529,9 @@ const useUIStateController = (
34437
34529
  resetUIState: (e) => {
34438
34530
  controller.setUIState(controller.state, e);
34439
34531
  },
34532
+ // Read by the callout manager when it has nowhere else to point.
34533
+ getCalloutAnchorElement: (event) =>
34534
+ resolveCalloutAnchorElement(controller.ref.current, event),
34440
34535
  // What the control shows becomes what is acknowledged: the outside said
34441
34536
  // yes to it, so it is where a rollback goes back to. Left alone for a
34442
34537
  // control whose value is GIVEN — the prop is already its truth — and
@@ -34660,6 +34755,44 @@ const firstDefinedChildUIState = (children) => {
34660
34755
  return undefined;
34661
34756
  };
34662
34757
 
34758
+ // Where a control that cannot point at itself puts what it has to say.
34759
+ //
34760
+ // A control drawn by something ELSE answers for a box bigger than itself: a
34761
+ // list row's selection is a visually hidden checkbox inside a whole pressable
34762
+ // row, so a callout anchored on the control lands in the middle of that row,
34763
+ // pointing at nothing. What the press landed on is what the sentence is about
34764
+ // — another control in the same box takes it (the button that invites, the
34765
+ // picker that opens), and the box itself takes what was aimed at the box.
34766
+ //
34767
+ // Answering null leaves the callout where it would have gone, which is also
34768
+ // what a box asks for once and for all with `data-callout-anchor="item"`.
34769
+ const resolveCalloutAnchorElement = (element, event) => {
34770
+ if (!element || !element.closest("[navi-visually-hidden]")) {
34771
+ return null;
34772
+ }
34773
+ const target = event?.target;
34774
+ if (!target || !target.closest) {
34775
+ return null;
34776
+ }
34777
+ const controlRoot = findControlRoot(element);
34778
+ if (
34779
+ !controlRoot ||
34780
+ controlRoot.getAttribute("data-callout-anchor") === "item"
34781
+ ) {
34782
+ return null;
34783
+ }
34784
+ const controlHost = target.closest("[navi-control-host]");
34785
+ if (
34786
+ !controlHost ||
34787
+ controlHost === element ||
34788
+ !controlRoot.contains(controlHost) ||
34789
+ controlHost.closest("[navi-visually-hidden]")
34790
+ ) {
34791
+ return null;
34792
+ }
34793
+ return controlHost;
34794
+ };
34795
+
34663
34796
  // A run that came back with a yes settles what the control is worth — but only
34664
34797
  // for the control the run BELONGS to. Anything with a `command` still fires its
34665
34798
  // own navi_action_* events (it is given a placeholder action so they exist),
@@ -37495,6 +37628,7 @@ const useInteractiveProps = (props, {
37495
37628
  const controlRequired = useContext(RequiredContext);
37496
37629
  const controlLoadingFromAbove = useContext(LoadingContext$1);
37497
37630
  const parentActionRequester = useContext(ActionRequesterContext);
37631
+ const parallelGuard = useContext(ParallelGuardContext);
37498
37632
  const parentAction = useContext(ActionContext);
37499
37633
  const actionStatus = useActionStatus(boundAction);
37500
37634
  const networkPolicyReason = useNetworkPolicyReason();
@@ -37532,7 +37666,12 @@ const useInteractiveProps = (props, {
37532
37666
  // why (see network_policy.js): a press that looks accepted and fails after
37533
37667
  // is what the policy exists to avoid.
37534
37668
  const heldByNetworkPolicy = networkPolicyReason !== null && (isWriteAction(boundAction) || Boolean(zoneStateApplies && parentAction && isWriteAction(parentAction)));
37535
- const readOnlyBase = readOnly || controlReadOnly || loadingBase || readOnlyFromParentMaxLengthGuard || controlInfo.readOnlyUncontrolled || heldByNetworkPolicy;
37669
+ // Held back because the surface above already has as many runs in flight as
37670
+ // it allows (see parallel_guard.js). Only a control that would START one:
37671
+ // anything without an action of its own runs nothing and has nothing to
37672
+ // wait its turn for.
37673
+ const heldByParallelGuard = Boolean(zoneStateApplies && parallelGuard && props.action && parallelGuard.blocks(uiStateController));
37674
+ const readOnlyBase = readOnly || controlReadOnly || loadingBase || readOnlyFromParentMaxLengthGuard || heldByParallelGuard || controlInfo.readOnlyUncontrolled || heldByNetworkPolicy;
37536
37675
  // An optimistic control trusts its action to succeed: the state the user
37537
37676
  // just set stays visible and interactive while the action runs — no
37538
37677
  // loading, no readonly. On failure resetOnError rolls the state back and
@@ -37577,6 +37716,13 @@ const useInteractiveProps = (props, {
37577
37716
  } else {
37578
37717
  controlHostProps["aria-readonly"] = readOnlyResolved ? "true" : "false";
37579
37718
  }
37719
+ // Read by READONLY_CONSTRAINT to say how many runs are already out, and by
37720
+ // the action handlers below, which are where a run joins and leaves the
37721
+ // count (a labelled block away, hence through the controller).
37722
+ uiStateController.parallelGuard = parallelGuard;
37723
+ if (heldByParallelGuard) {
37724
+ controlHostProps["data-readonly-reason"] = "parallel-guard";
37725
+ }
37580
37726
  if (heldByNetworkPolicy) {
37581
37727
  // Read by READONLY_CONSTRAINT; wins over any other reason the control
37582
37728
  // carries — nothing leaves, whatever else was holding it.
@@ -37820,6 +37966,7 @@ const useInteractiveProps = (props, {
37820
37966
  // carried by every navi_action_* event of that run).
37821
37967
  uiStateController.pendingActionEvent = e.detail.event;
37822
37968
  uiStateController.actionInFlight = true;
37969
+ uiStateController.parallelGuard?.claim(uiStateController);
37823
37970
  // The very instance this run uses, resolved now — while the UI state
37824
37971
  // still holds the value the run was made for. detail.action may be a
37825
37972
  // proxy following that state, and by the time anyone wants to abort
@@ -37834,6 +37981,7 @@ const useInteractiveProps = (props, {
37834
37981
  e.detail.addSideEffect(outcome => {
37835
37982
  uiStateController.actionInFlight = false;
37836
37983
  uiStateController.runningAction = null;
37984
+ uiStateController.parallelGuard?.release(uiStateController);
37837
37985
  const queuedEvent = uiStateController.queuedActionAllowedEvent;
37838
37986
  if (!queuedEvent) {
37839
37987
  return;
@@ -57108,6 +57256,7 @@ const translateOf = (axis, distance) =>
57108
57256
 
57109
57257
  const PopupClose = ({
57110
57258
  label,
57259
+ iconSize,
57111
57260
  ...rest
57112
57261
  }) => {
57113
57262
  return jsx(Button, {
@@ -57131,6 +57280,7 @@ const PopupClose = ({
57131
57280
  "aria-label": label === undefined ? naviI18n("button.close") : label,
57132
57281
  ...rest,
57133
57282
  children: jsx(Icon, {
57283
+ size: iconSize,
57134
57284
  children: jsx(CloseSvg, {})
57135
57285
  })
57136
57286
  });
@@ -64007,6 +64157,11 @@ const ListUI = props => {
64007
64157
  })
64008
64158
  });
64009
64159
  };
64160
+ // How many of a list's own rows may be acting at once, when the rows are what
64161
+ // carry the action. Four rather than none: a list is a place where the same
64162
+ // gesture is available many times over, and nothing else stops a long one from
64163
+ // putting a request out for every row it draws.
64164
+ const PARALLEL_GUARD_DEFAULT = 4;
64010
64165
  const ListFirstResolver = props => {
64011
64166
  const Next = useNextResolver();
64012
64167
  const refDefault = useRef(null);
@@ -64018,8 +64173,13 @@ const ListFirstResolver = props => {
64018
64173
  virtualRef.current = createListVirtual();
64019
64174
  }
64020
64175
  props.virtual = virtualRef.current;
64021
- return jsx(Next, {
64022
- ...props
64176
+ const parallelGuard = useParallelGuard(props.parallelGuard ?? PARALLEL_GUARD_DEFAULT);
64177
+ return jsx(ParallelGuardContext.Provider, {
64178
+ value: parallelGuard,
64179
+ children: jsx(Next, {
64180
+ ...props,
64181
+ parallelGuard: undefined
64182
+ })
64023
64183
  });
64024
64184
  };
64025
64185
 
@@ -64033,6 +64193,7 @@ const ListFirstResolver = props => {
64033
64193
  * deselectable?: boolean,
64034
64194
  * maxLength?: number,
64035
64195
  * maxLengthGuard?: number,
64196
+ * parallelGuard?: number,
64036
64197
  * standalone?: boolean,
64037
64198
  * action?: (value: any) => void,
64038
64199
  * uiAction?: (value: any) => void,
@@ -64209,6 +64370,13 @@ const ListFirstResolver = props => {
64209
64370
  * taking — and `uiAction` is not called. The selected ones stay takeable
64210
64371
  * back, so a selection that arrived too long can always be brought back
64211
64372
  * under the limit. Implies `maxLength` for validity.
64373
+ * @param {number} [props.parallelGuard=4]
64374
+ * How many runs the rows may have in flight at once, for a list whose rows
64375
+ * carry their own `action` (a button per row). While that many are out, every
64376
+ * row that is not running goes read-only and says how many it is waiting on;
64377
+ * the next press is possible again as soon as one comes back. `Infinity`
64378
+ * lifts it. Counts runs, not values — `maxLengthGuard` above is the one that
64379
+ * says how many things the selection may hold.
64212
64380
  * @param {boolean} [props.standalone]
64213
64381
  * This list answers for itself: it does not register with the control group
64214
64382
  * or picker around it, so its selection stays out of that value and nothing
@@ -82195,5 +82363,5 @@ const UserSvg = () => jsx("svg", {
82195
82363
  })
82196
82364
  });
82197
82365
 
82198
- export { ActionRenderer, ActiveKeyboardShortcuts, Address, Badge, BadgeCount, BadgeList, Binder, Box, Button, ButtonCopyToClipboard, CalloutStatusIcon, Caption, CardLayout, CheckSvg, CheckboxGroup, CloseSvg, Code, Col, Colgroup, Color, ConstructionSvg, ControlGroup, ControlSwap, DaySpin, Details, Dialog, Editable, ErrorBoundary, ErrorBoundaryContext, ExclamationSvg, Expandable, EyeClosedSvg, EyeSvg, Field, FixedBar, Form, Group, Head, HeartSvg, HomeSvg, Icon, Image, InfoSvg, Input, InputDuration, Interpolate, Label, Link, LinkAnchorSvg, LinkBlankTargetSvg, LinkCurrentSvg, List, ListItem, ListItemGroup, ListItems, Loading, LoadingDotsSvg, LoadingIndicator, LoadingIndicatorFluid, LoadingOutline, MessageBox, Meter, Nav, NaviDebug, NumberSpin, OfflineError, Paragraph, Picker, Popover, Popup, Quantity, RadioGroup, Route, RouteTransitionArea, RouteTravel, RowNumberCol, RowNumberTableCell, SVGMaskOverlay, SearchSvg, Select, SelectableInput, SelectionContext, Separator, SettingsSvg, SidePanel, Slide, SlideContainer, Spin, SpinGroup, SplitButton, StarSvg, Step, StepList, SummaryMarker, Svg, Table, TableCell, Tbody, Text, TextBox, Textarea, TextareaCharCount, Thead, Time, TimeRange, TimeRangeSpin, TimeRangeWheel, TimeSpin, TimeWheel, Title, Tr, UITransition, Unit, UserSvg, ViewportLayout, Wheel, WheelGroup, WheelItem, actionRunEffect, anyMatchingRouteSignal, applySearch, arraySignalMembership, canNavBackSignal, canNavForwardSignal, coarsePointerSignal, compareTwoJsValues, constraintFromValidityRule, createAction, createAvailableConstraint, createI18n, createRequestCanceller, createSearch, createSelectionKeyboardShortcuts, createSlot, defineInteractionDetector, defineRouteDefaultTransition, defineRouteTransition, detectHorizontalOverflow, enableDebugActions, enableDebugOnDocumentLoading, ensureDocumentStartViewTransition, errorIsDisplayed, filterTableSelection, formatDatetime, formatDay, formatDayRelative, formatMonth, formatNumber, formatTime, formatTimeRelative, getNowHours, getNowHoursRoundedToStep, interpolateText, isCellSelected, isColumnSelected, isOfflineError, isRowSelected, isScrolling, isToday, languagesSignal, localStorageSignal, markErrorAsDisplayedBy, moveArrayItemByIndex, moveFocusTo, navBack, navForward, navIntegratedVia, navTo, naviI18n, openCallout, rawUrlPart, registerGlobalConstraint, reload, rerunActions, resource, route, routeAction, scrollActivitySignal, setBaseUrl, setNetworkPolicy, setPreferredLanguage, setSupportedLanguages, setUrlTargetOptions, setupRoutes, smallTouchScreenSignal, stateSignal, stopLoad, stringifyTableSelectionValue, swapArrayItemByIndex, syncOwnedResourceToSignals, syncResourceToSignals, triggerNaviCommand, updateActions, useActionStatus, useArraySignalMembership, useAsyncData, useCalloutElement, useCalloutRequestClose, useCanNavBack, useCanNavForward, useCancelPrevious, useCellGridFromRows, useConstraintValidityState, useDependenciesDiff, useDisplayedLayoutEffect, useDocumentResource, useDocumentState, useDocumentUrl, useEditionController, useFocusGroup, useInputGroup, useKeyboardShortcuts, useNavState, useNetworkPolicyReason, useOrderedColumns, usePopupMode, useRouteStatus, useSearchText, useSelectableElement, useSelectionController, useSignalSync, useSlideContainer, useSlideValue, useStateArray, useTitleLevel, useTransitionCover, useUrlSearchParam, useUrlTargetId, valueInLocalStorage, windowWidthSignal };
82366
+ export { ActionRenderer, ActiveKeyboardShortcuts, Address, Badge, BadgeCount, BadgeList, Binder, Box, Button, ButtonCopyToClipboard, CalloutStatusIcon, Caption, CardLayout, CheckSvg, CheckboxGroup, CloseSvg, Code, Col, Colgroup, Color, ConstructionSvg, ControlGroup, ControlSwap, DaySpin, Details, Dialog, Editable, ErrorBoundary, ErrorBoundaryContext, ExclamationSvg, Expandable, EyeClosedSvg, EyeSvg, Field, FixedBar, Form, Group, Head, HeartSvg, HomeSvg, Icon, Image, InfoSvg, Input, InputDuration, Interpolate, Label, Link, LinkAnchorSvg, LinkBlankTargetSvg, LinkCurrentSvg, List, ListItem, ListItemGroup, ListItems, Loading, LoadingDotsSvg, LoadingIndicator, LoadingIndicatorFluid, LoadingOutline, MessageBox, Meter, Nav, NaviDebug, NumberSpin, OfflineError, Paragraph, Picker, Popover, Popup, Quantity, RadioGroup, Route, RouteTransitionArea, RouteTravel, RowNumberCol, RowNumberTableCell, SVGMaskOverlay, SearchSvg, Select, SelectableInput, SelectionContext, Separator, SettingsSvg, SidePanel, Slide, SlideContainer, Spin, SpinGroup, SplitButton, StarSvg, Step, StepList, SummaryMarker, Svg, Table, TableCell, Tbody, Text, TextBox, Textarea, TextareaCharCount, Thead, Time, TimeRange, TimeRangeSpin, TimeRangeWheel, TimeSpin, TimeWheel, Title, Tr, UITransition, Unit, UserSvg, ViewportLayout, Wheel, WheelGroup, WheelItem, actionRunEffect, anyMatchingRouteSignal, applySearch, arraySignalMembership, canNavBackSignal, canNavForwardSignal, coarsePointerSignal, compareTwoJsValues, constraintFromValidityRule, createAction, createAvailableConstraint, createI18n, createRequestCanceller, createSearch, createSelectionKeyboardShortcuts, createSlot, defineInteractionDetector, defineRouteDefaultTransition, defineRouteTransition, detectHorizontalOverflow, enableDebugActions, enableDebugOnDocumentLoading, ensureDocumentStartViewTransition, errorIsDisplayed, filterTableSelection, formatDatetime, formatDay, formatDayRelative, formatDuration, formatHourDuration, formatMinuteDuration, formatMonth, formatNumber, formatSecondDuration, formatTime, formatTimeRelative, getNowHours, getNowHoursRoundedToStep, interpolateText, isCellSelected, isColumnSelected, isOfflineError, isRowSelected, isScrolling, isToday, languagesSignal, localStorageSignal, markErrorAsDisplayedBy, moveArrayItemByIndex, moveFocusTo, navBack, navForward, navIntegratedVia, navTo, naviI18n, openCallout, rawUrlPart, registerGlobalConstraint, reload, rerunActions, resource, route, routeAction, scrollActivitySignal, setBaseUrl, setNetworkPolicy, setPreferredLanguage, setSupportedLanguages, setUrlTargetOptions, setupRoutes, smallTouchScreenSignal, stateSignal, stopLoad, stringifyTableSelectionValue, swapArrayItemByIndex, syncOwnedResourceToSignals, syncResourceToSignals, triggerNaviCommand, updateActions, useActionStatus, useArraySignalMembership, useAsyncData, useCalloutElement, useCalloutRequestClose, useCanNavBack, useCanNavForward, useCancelPrevious, useCellGridFromRows, useConstraintValidityState, useDependenciesDiff, useDisplayedLayoutEffect, useDocumentResource, useDocumentState, useDocumentUrl, useEditionController, useFocusGroup, useInputGroup, useKeyboardShortcuts, useNavState, useNetworkPolicyReason, useOrderedColumns, usePopupMode, useRouteStatus, useSearchText, useSelectableElement, useSelectionController, useSignalSync, useSlideContainer, useSlideValue, useStateArray, useTitleLevel, useTransitionCover, useUrlSearchParam, useUrlTargetId, valueInLocalStorage, windowWidthSignal };
82199
82367
  //# sourceMappingURL=jsenv_navi.js.map