@jsenv/navi 0.29.224 → 0.29.225

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.
@@ -17066,6 +17066,17 @@ const useAsyncData = (promiseOrAction, {
17066
17066
  run,
17067
17067
  onLoad
17068
17068
  } = {}) => {
17069
+ // The request this component owns, as a function: one action per instance,
17070
+ // made on the first render and kept — the function's identity changes on
17071
+ // every render when it is written inline, the action's does not.
17072
+ const ownActionRef = useRef(null);
17073
+ if (typeof promiseOrAction === "function" && !promiseOrAction.isAction) {
17074
+ if (!ownActionRef.current) {
17075
+ ownActionRef.current = createAction(promiseOrAction);
17076
+ }
17077
+ promiseOrAction = ownActionRef.current;
17078
+ run = true;
17079
+ }
17069
17080
  const isAction = Boolean(promiseOrAction && promiseOrAction.isAction);
17070
17081
  if (loading === true) {
17071
17082
  loading = "use";
@@ -17502,86 +17513,6 @@ const ErrorBoundary = ({
17502
17513
  return children;
17503
17514
  };
17504
17515
 
17505
- /**
17506
- * A component whose code is fetched on demand, the way its data is.
17507
- *
17508
- * The import is an action: it starts from the first render that needs it (or
17509
- * from `preload()`), waits in the nearest `<Loading>`, fails in the nearest
17510
- * `<ErrorBoundary>` with a `rerun` as the way back, and is counted by the
17511
- * document busy signal like any other run. A page under `<Route>` therefore
17512
- * fetches its code and its route action's data side by side, and shows one
17513
- * wait for the two. See docs/dynamic_import.md.
17514
- */
17515
-
17516
-
17517
- /**
17518
- * @param {() => Promise<Function | object>} load - what fetches the code,
17519
- * typically `() => import("./page.jsx")`. May resolve to the component
17520
- * itself or to the module: its `default` export, or its only exported
17521
- * function.
17522
- * @returns {Function & { preload: () => void, action: object }} the component,
17523
- * rendering the loaded one with its props. `preload()` starts the fetch ahead
17524
- * of the render — on a link hovered, on an idle moment; a prefetch that fails
17525
- * is forgotten, the visit asks again.
17526
- */
17527
- const lazy = load => {
17528
- const loadAction = createAction(async () => {
17529
- const loaded = await load();
17530
- return resolveComponent(loaded);
17531
- }, {
17532
- name: nameFromLoader(load)
17533
- });
17534
- const Lazy = props => {
17535
- const [Component] = useAsyncData(loadAction, {
17536
- run: true
17537
- });
17538
- return h(Component, props);
17539
- };
17540
- Lazy.displayName = `Lazy(${loadAction.name})`;
17541
- Lazy.action = loadAction;
17542
- // A prefetch is a prerun: nothing on screen asked for it. One that fails is
17543
- // forgotten rather than reported — the visit that needs the code asks again
17544
- // and shows its own failure; a boundary already showing this one keeps it
17545
- // until the retry runs.
17546
- Lazy.preload = () => {
17547
- const prerunResult = loadAction.prerun({
17548
- reason: "preload"
17549
- });
17550
- // A run already in flight or done answers with nothing to wait for.
17551
- if (prerunResult && typeof prerunResult.catch === "function") {
17552
- prerunResult.catch(() => {
17553
- loadAction.reset({
17554
- reason: "preload failed"
17555
- });
17556
- });
17557
- }
17558
- };
17559
- return Lazy;
17560
- };
17561
- const resolveComponent = loaded => {
17562
- if (typeof loaded === "function") {
17563
- return loaded;
17564
- }
17565
- if (loaded && typeof loaded === "object") {
17566
- if (typeof loaded.default === "function") {
17567
- return loaded.default;
17568
- }
17569
- const functionExportNames = Object.keys(loaded).filter(key => typeof loaded[key] === "function");
17570
- if (functionExportNames.length === 1) {
17571
- return loaded[functionExportNames[0]];
17572
- }
17573
- throw new Error(`lazy(): the module must export one component, found ${functionExportNames.length} (${functionExportNames.join(", ") || "none"}). Return the component from the loader to say which.`);
17574
- }
17575
- throw new Error(`lazy(): expected a component or a module, got ${loaded}`);
17576
- };
17577
-
17578
- // The specifier read off the loader's source, so the action (and the busy
17579
- // signal, and the debug output) says which page is being fetched.
17580
- const nameFromLoader = load => {
17581
- const match = /import\(\s*["']([^"']+)["']/.exec(String(load));
17582
- return match ? `import ${match[1]}` : "lazy";
17583
- };
17584
-
17585
17516
  /**
17586
17517
  * Creates a function that generates abort signals, automatically cancelling previous requests.
17587
17518
  *
@@ -24740,11 +24671,9 @@ const route = (
24740
24671
  return `route "${cleanPattern}"`;
24741
24672
  },
24742
24673
  };
24743
- // What fetches the code of this route ahead of the render — the lazy
24744
- // elements the routers on screen have registered for it (see
24745
- // registerRoutePreload). Code only: the data is the route action's, asked
24746
- // for on arrival with the params the address holds, and a prefetch has no
24747
- // address yet.
24674
+ // Asks ahead of the arrival for what this route's actions ask without the
24675
+ // address — a page's code, a read without params (see routeAction). An
24676
+ // action keyed by a param waits for the arrival: a prefetch has no address.
24748
24677
  route.preload = () => {
24749
24678
  const preloadSet = routePreloadMap.get(route);
24750
24679
  if (!preloadSet) {
@@ -25224,10 +25153,10 @@ const registerRoutePreload = (route, preload) => {
25224
25153
  preloadSet.add(preload);
25225
25154
  };
25226
25155
  /**
25227
- * Fetches the code of every route the url leads to, a section and the page
25228
- * inside it alike. What a link does when the pointer or the focus reaches it
25229
- * (see use_preload_on_intent.js), available to anything else that knows where
25230
- * it is about to go.
25156
+ * Preloads every route the url leads to, a section and the page inside it
25157
+ * alike. What a link does when the pointer or the focus reaches it (see
25158
+ * use_preload_on_intent.js), available to anything else that knows where it
25159
+ * is about to go.
25231
25160
  */
25232
25161
  const preloadUrl = (url) => {
25233
25162
  if (!activeRouteSet) {
@@ -27209,12 +27138,8 @@ const collectBranches = children => {
27209
27138
  children: nodeChildren,
27210
27139
  fallback,
27211
27140
  route,
27212
- routeParams,
27213
- element
27141
+ routeParams
27214
27142
  } = child.props;
27215
- if (route) {
27216
- registerElementPreload(route, element);
27217
- }
27218
27143
  if (nodeChildren) {
27219
27144
  const {
27220
27145
  matchingBranch: matchingChild
@@ -27264,17 +27189,6 @@ const collectBranches = children => {
27264
27189
  activeBranch
27265
27190
  };
27266
27191
  };
27267
- // A branch whose element fetches its code on demand (see lazy.jsx) tells its
27268
- // route, so that intent on a link to that route — or `route.preload()` — can
27269
- // fetch it ahead of the render. Read off the vnode the container walks, which
27270
- // is why a router on screen is what knows: a section's sub-pages register when
27271
- // the section renders its own router.
27272
- const registerElementPreload = (route, element) => {
27273
- const type = element && element.type ? element.type : element;
27274
- if (type && typeof type.preload === "function") {
27275
- registerRoutePreload(route, type.preload);
27276
- }
27277
- };
27278
27192
  const wrapBranch = (branch, wrapper) => {
27279
27193
  return {
27280
27194
  ...branch,
@@ -30859,20 +30773,55 @@ const writeCover = (edge, element, size) => {
30859
30773
  style.setProperty(property, value);
30860
30774
  };
30861
30775
 
30776
+ /**
30777
+ * Binds an action to a route: it runs when the route matches, with the params
30778
+ * the effect reads off the address, and is aborted when the route is left.
30779
+ * Its data, its wait and its failure are read by the page through
30780
+ * `useAsyncData`.
30781
+ *
30782
+ * A page's CODE is declared the same way — the import is one more thing the
30783
+ * address asks for, started with the data rather than after it:
30784
+ *
30785
+ * ```js
30786
+ * const GAME_PAGE_CODE = routeAction(GAME_ROUTE, () =>
30787
+ * import("./game_page.jsx").then((m) => m.GamePage),
30788
+ * );
30789
+ * ```
30790
+ *
30791
+ * @param {object | object[]} routeOrRoutes - the route, or the routes, this
30792
+ * action belongs to.
30793
+ * @param {object | Function} action - an action, or a function made into one.
30794
+ * @param {() => any} [paramsEffect] - what the action runs with, read off
30795
+ * signals (the route's params, a search param): re-read when they change.
30796
+ * Return a falsy value to run nothing. Without it the action asks nothing of
30797
+ * the address, which is also what makes it worth fetching AHEAD of the
30798
+ * arrival: a link to the route preruns it when the pointer or the focus
30799
+ * reaches the link (see docs/dynamic_import.md). An action whose params
30800
+ * come from the address is never prefetched — a prefetch has no address.
30801
+ * @param {object} [options]
30802
+ * @param {boolean} [options.prefetch=true] - `false` keeps a param-less action
30803
+ * from being prerun on intent, when the read is not worth a hover.
30804
+ */
30862
30805
  const routeAction = (
30863
30806
  routeOrRoutes,
30864
30807
  action,
30865
- paramsEffect = () => true,
30866
- options = {},
30808
+ paramsEffect,
30809
+ { prefetch = true, ...options } = {},
30867
30810
  ) => {
30868
- const routeMatchingSignal = Array.isArray(routeOrRoutes)
30869
- ? anyMatchingRouteSignal(routeOrRoutes)
30870
- : routeOrRoutes.matchingSignal;
30811
+ if (typeof action === "function") {
30812
+ action = createAction(action);
30813
+ }
30814
+ const routes = Array.isArray(routeOrRoutes) ? routeOrRoutes : [routeOrRoutes];
30815
+ const routeMatchingSignal =
30816
+ routes.length === 1
30817
+ ? routes[0].matchingSignal
30818
+ : anyMatchingRouteSignal(routes);
30819
+ const readParams = paramsEffect || (() => true);
30871
30820
  const actionBoundToRoute = actionRunEffect(
30872
30821
  action,
30873
30822
  () => {
30874
30823
  const matching = routeMatchingSignal.value;
30875
- const params = paramsEffect();
30824
+ const params = readParams();
30876
30825
  if (!matching) {
30877
30826
  return null;
30878
30827
  }
@@ -30880,10 +30829,37 @@ const routeAction = (
30880
30829
  },
30881
30830
  options,
30882
30831
  );
30883
-
30832
+ if (!paramsEffect && prefetch) {
30833
+ for (const route of routes) {
30834
+ registerRoutePreload(route, () => {
30835
+ prefetchParamless(action);
30836
+ });
30837
+ }
30838
+ }
30884
30839
  return actionBoundToRoute;
30885
30840
  };
30886
30841
 
30842
+ // The instance the effect above runs on the match is the one bound to `true`
30843
+ // (the default params), so a prerun here is what the arrival promotes to a
30844
+ // run. A prefetch that fails is forgotten rather than reported: nothing on
30845
+ // screen asked for it, and the arrival asks again and shows its own failure.
30846
+ const prefetchParamless = (action) => {
30847
+ const instance = action.bindParams(true);
30848
+ const forget = () => {
30849
+ instance.reset({ reason: "prefetch failed" });
30850
+ };
30851
+ let result;
30852
+ try {
30853
+ result = instance.prerun({ reason: "intent" });
30854
+ } catch {
30855
+ forget();
30856
+ return;
30857
+ }
30858
+ if (result && typeof result.catch === "function") {
30859
+ result.catch(forget);
30860
+ }
30861
+ };
30862
+
30887
30863
  // I delibrately prefer the term "any" and avoid "some" so dev are not tempted to think
30888
30864
  // "well I could just use array.some" and bypass this helper entirely, which would be incorrect:
30889
30865
  // This helper does return if some/any route is matching but ensure all route matching signals are read (subscribed to)
@@ -40748,10 +40724,11 @@ const Icon = ({
40748
40724
  };
40749
40725
 
40750
40726
  /**
40751
- * The code of where a link leads, fetched when the pointer or the focus
40752
- * arrives on it: the moment the user signals a destination, before the press.
40753
- * Only code is fetched (see route.preload), so a link whose address is not the
40754
- * final one — an id still to be chosen — loses nothing by asking.
40727
+ * Where a link leads, asked for when the pointer or the focus arrives on it:
40728
+ * the moment the user signals a destination, before the press. Only what the
40729
+ * route's actions ask without the address is fetched (see route.preload), so
40730
+ * a link whose address is not the final one — an id still to be chosen —
40731
+ * loses nothing by asking.
40755
40732
  */
40756
40733
  const usePreloadOnIntent = (ref, href, prefetch = true) => {
40757
40734
  useEffect(() => {
@@ -41285,8 +41262,10 @@ Object.assign(PSEUDO_CLASSES, {
41285
41262
  * button leaves by where the reader came in.
41286
41263
  * @param {boolean} [props.prefetch=true] Fetch the code of where this leads when the
41287
41264
  * pointer or the focus arrives, ahead of the press (see
41288
- * docs/dynamic_import.md). Code only: the data stays the route action's.
41289
- * `false` for a destination not worth fetching on a hover.
41265
+ * docs/dynamic_import.md): the route actions that ask nothing of the
41266
+ * address — a page's code, a read without params — are prerun; one keyed by
41267
+ * a param waits for the arrival. `false` for a destination not worth
41268
+ * fetching on a hover.
41290
41269
  * @param {string} [props.command] - What the press asks of a control around
41291
41270
  * the link — `"--navi-close"` on a link that leaves the sheet it is in.
41292
41271
  * Triggered on the press, before the navigation.
@@ -47748,8 +47727,10 @@ const COMMAND_DEFAULT_PROPS_FACTORIES = {
47748
47727
  * as a button.
47749
47728
  * @param {boolean} [prefetch=true] Fetch the code of where this leads when the
47750
47729
  * pointer or the focus arrives, ahead of the press (see
47751
- * docs/dynamic_import.md). Code only: the data stays the route action's.
47752
- * `false` for a destination not worth fetching on a hover.
47730
+ * docs/dynamic_import.md): the route actions that ask nothing of the
47731
+ * address — a page's code, a read without params — are prerun; one keyed by
47732
+ * a param waits for the arrival. `false` for a destination not worth
47733
+ * fetching on a hover.
47753
47734
  * @param {boolean} [pressableDuringRouteTransition] Keep answering presses
47754
47735
  * while a route transition plays: what a movement photographs goes deaf to
47755
47736
  * the pointer for its whole length, and the door that opened the page — a
@@ -82673,5 +82654,5 @@ const UserSvg = () => jsx("svg", {
82673
82654
  })
82674
82655
  });
82675
82656
 
82676
- 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, createRequestCanceller, createSearch, createSelectionKeyboardShortcuts, createSlot, defineInteractionDetector, defineRouteDefaultTransition, defineRouteTransition, detectHorizontalOverflow, dispatchRequestSetUIState, enableDebugActions, enableDebugOnDocumentLoading, ensureDocumentStartViewTransition, errorIsDisplayed, filterTableSelection, getNowHours, getNowHoursRoundedToStep, isCellSelected, isColumnSelected, isOfflineError, isRowSelected, isScrolling, isToday, languagesSignal, lazy, localStorageSignal, markAsOutsideTextFlow, markErrorAsDisplayedBy, moveArrayItemByIndex, moveFocusTo, navBack, navForward, navIntegratedVia, navTo, naviI18n, openCallout, preloadUrl, 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 };
82657
+ 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, createRequestCanceller, createSearch, createSelectionKeyboardShortcuts, createSlot, defineInteractionDetector, defineRouteDefaultTransition, defineRouteTransition, detectHorizontalOverflow, dispatchRequestSetUIState, enableDebugActions, enableDebugOnDocumentLoading, ensureDocumentStartViewTransition, errorIsDisplayed, filterTableSelection, getNowHours, getNowHoursRoundedToStep, isCellSelected, isColumnSelected, isOfflineError, isRowSelected, isScrolling, isToday, languagesSignal, localStorageSignal, markAsOutsideTextFlow, markErrorAsDisplayedBy, moveArrayItemByIndex, moveFocusTo, navBack, navForward, navIntegratedVia, navTo, naviI18n, openCallout, preloadUrl, 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 };
82677
82658
  //# sourceMappingURL=jsenv_navi.js.map