@jsenv/navi 0.11.5 → 0.11.7

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.
@@ -1,3 +1,4 @@
1
+ import { installImportMetaCss } from "./jsenv_navi_side_effects.js";
1
2
  import { createIterableWeakSet, createPubSub, createValueEffect, createStyleController, getVisuallyVisibleInfo, getFirstVisuallyVisibleAncestor, allowWheelThrough, visibleRectEffect, pickPositionRelativeTo, getBorderSizes, getPaddingSizes, activeElementSignal, canInterceptKeys, initUITransition, getElementSignature, resolveCSSSize, normalizeStyles, appendStyles, findBefore, findAfter, initFocusGroup, elementIsFocusable, pickLightOrDark, dragAfterThreshold, getScrollContainer, stickyAsRelativeCoords, createDragToMoveGestureController, getDropTargetInfo, setStyles, useActiveElement } from "@jsenv/dom";
2
3
  import { prefixFirstAndIndentRemainingLines } from "@jsenv/humanize";
3
4
  import { effect, signal, computed, batch, useSignal } from "@preact/signals";
@@ -6,42 +7,6 @@ import { createContext, createRef, toChildArray, cloneElement } from "preact";
6
7
  import { jsx, jsxs, Fragment } from "preact/jsx-runtime";
7
8
  import { forwardRef, createPortal } from "preact/compat";
8
9
 
9
- const installImportMetaCss = (importMeta) => {
10
- const stylesheet = new CSSStyleSheet({ baseUrl: importMeta.url });
11
-
12
- let called = false;
13
- // eslint-disable-next-line accessor-pairs
14
- Object.defineProperty(importMeta, "css", {
15
- configurable: true,
16
- set(value) {
17
- if (called) {
18
- throw new Error("import.meta.css setter can only be called once");
19
- }
20
- called = true;
21
- stylesheet.replaceSync(value);
22
- document.adoptedStyleSheets = [
23
- ...document.adoptedStyleSheets,
24
- stylesheet,
25
- ];
26
- },
27
- });
28
- };
29
-
30
- installImportMetaCss(import.meta);import.meta.css = /* css */ `
31
- @layer navi {
32
- :root {
33
- --navi-background-color-readonly: #d3d3d3;
34
- --navi-color-readonly: grey;
35
- --navi-background-color-disabled: #d3d3d3;
36
- --navi-color-disabled: #eeeeee;
37
-
38
- --navi-info-color: #2196f3;
39
- --navi-warning-color: #ff9800;
40
- --navi-error-color: #f44336;
41
- }
42
- }
43
- `;
44
-
45
10
  const actionPrivatePropertiesWeakMap = new WeakMap();
46
11
  const getActionPrivateProperties = (action) => {
47
12
  const actionPrivateProperties = actionPrivatePropertiesWeakMap.get(action);
@@ -7682,7 +7647,11 @@ const createRoute = (urlPatternInput) => {
7682
7647
  let relativeUrl = urlPatternInput;
7683
7648
  let hasRawUrlPartWithInvalidChars = false;
7684
7649
 
7685
- const encode = (value) => {
7650
+ // Encode parameter values for URL usage, with special handling for raw URL parts.
7651
+ // When a parameter is wrapped with rawUrlPart(), it bypasses encoding and is
7652
+ // inserted as-is into the URL. This allows including pre-encoded values or
7653
+ // special characters that should not be percent-encoded.
7654
+ const encodeParamValue = (value) => {
7686
7655
  if (value && value[rawUrlPartSymbol]) {
7687
7656
  const rawValue = value.value;
7688
7657
  // Check if raw value contains invalid URL characters
@@ -7700,7 +7669,7 @@ const createRoute = (urlPatternInput) => {
7700
7669
  // Replace named parameters (:param and {param})
7701
7670
  for (const key of keys) {
7702
7671
  const value = params[key];
7703
- const encodedValue = encode(value);
7672
+ const encodedValue = encodeParamValue(value);
7704
7673
  const beforeReplace = relativeUrl;
7705
7674
  relativeUrl = relativeUrl.replace(`:${key}`, encodedValue);
7706
7675
  relativeUrl = relativeUrl.replace(`{${key}}`, encodedValue);
@@ -7724,7 +7693,7 @@ const createRoute = (urlPatternInput) => {
7724
7693
  if (paramValue) {
7725
7694
  extraParamSet.delete(paramKey);
7726
7695
  }
7727
- const replacement = paramValue ? encode(paramValue) : "*";
7696
+ const replacement = paramValue ? encodeParamValue(paramValue) : "*";
7728
7697
  wildcardIndex++;
7729
7698
  return replacement;
7730
7699
  });
@@ -7733,15 +7702,17 @@ const createRoute = (urlPatternInput) => {
7733
7702
  // Add remaining parameters as search params
7734
7703
  if (extraParamSet.size > 0) {
7735
7704
  if (extraParamEffect === "inject_as_search_param") {
7736
- const searchParams = new URLSearchParams();
7705
+ const searchParamPairs = [];
7737
7706
  for (const key of extraParamSet) {
7738
7707
  const value = params[key];
7739
7708
  if (value !== undefined && value !== null) {
7740
- searchParams.append(key, value);
7709
+ const encodedKey = encodeURIComponent(key);
7710
+ const encodedValue = encodeParamValue(value);
7711
+ searchParamPairs.push(`${encodedKey}=${encodedValue}`);
7741
7712
  }
7742
7713
  }
7743
- const searchString = searchParams.toString();
7744
- if (searchString) {
7714
+ if (searchParamPairs.length > 0) {
7715
+ const searchString = searchParamPairs.join("&");
7745
7716
  relativeUrl += (relativeUrl.includes("?") ? "&" : "?") + searchString;
7746
7717
  }
7747
7718
  } else if (extraParamEffect === "warn") {
@@ -7757,6 +7728,25 @@ const createRoute = (urlPatternInput) => {
7757
7728
  hasRawUrlPartWithInvalidChars,
7758
7729
  };
7759
7730
  };
7731
+
7732
+ /**
7733
+ * Builds a complete URL for this route with the given parameters.
7734
+ *
7735
+ * Takes parameters and substitutes them into the route's URL pattern,
7736
+ * automatically URL-encoding values unless wrapped with rawUrlPart().
7737
+ * Extra parameters not in the pattern are added as search parameters.
7738
+ *
7739
+ * @param {Object} params - Parameters to substitute into the URL pattern
7740
+ * @returns {string} Complete URL with base URL and encoded parameters
7741
+ *
7742
+ * @example
7743
+ * // For a route with pattern "/items/:id"
7744
+ * // Normal parameter encoding
7745
+ * route.buildUrl({ id: "hello world" }) // → "https://example.com/items/hello%20world"
7746
+ * // Raw parameter (no encoding)
7747
+ * route.buildUrl({ id: rawUrlPart("hello world") }) // → "https://example.com/items/hello world"
7748
+ *
7749
+ */
7760
7750
  const buildUrl = (params = {}) => {
7761
7751
  const { relativeUrl, hasRawUrlPartWithInvalidChars } =
7762
7752
  buildRelativeUrl(params);
@@ -8806,18 +8796,23 @@ const initRouteObserver = ({
8806
8796
  isComposite: true,
8807
8797
  active: false,
8808
8798
  subscribeStatus: subscribeCompositeStatus,
8809
- toString: () => `composite(${candidateSet.size} candidates)`
8799
+ toString: () => `composite(${candidateSet.size} candidates)`,
8800
+ routeFromProps: route,
8801
+ elementFromProps: element
8810
8802
  };
8811
8803
  const findActiveChildInfo = () => {
8812
8804
  let fallbackInfo = null;
8813
8805
  for (const candidate of candidateSet) {
8814
- if (candidate.route.active) {
8806
+ if (candidate.route?.active) {
8815
8807
  return {
8816
8808
  ChildActiveElement: candidate.ActiveElement,
8817
8809
  route: candidate.route
8818
8810
  };
8819
8811
  }
8820
- if (candidate.fallback) {
8812
+ // fallback without route can match when no other route matches.
8813
+ // This is useful solely for "catch all" fallback used on the <Routes>
8814
+ // otherwise a fallback would always match and make the parent route always active
8815
+ if (candidate.fallback && !candidate.route.routeFromProps) {
8821
8816
  fallbackInfo = {
8822
8817
  ChildActiveElement: candidate.ActiveElement,
8823
8818
  route: candidate.route
@@ -8852,7 +8847,8 @@ const initRouteObserver = ({
8852
8847
  const activeRouteSignal = signal();
8853
8848
  const SlotActiveElementSignal = signal();
8854
8849
  const ActiveElement = () => {
8855
- useContentKey(activeRouteSignal.value.urlPattern);
8850
+ const activeRoute = activeRouteSignal.value;
8851
+ useContentKey(activeRoute?.urlPattern);
8856
8852
  const SlotActiveElement = SlotActiveElementSignal.value;
8857
8853
  if (typeof element === "function") {
8858
8854
  const Element = element;
@@ -9372,6 +9368,7 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
9372
9368
  display: inline-flex;
9373
9369
  width: fit-content;
9374
9370
  height: fit-content;
9371
+ flex-direction: inherit;
9375
9372
  /* min-width: 100%; */
9376
9373
  /* min-height: 100%; */
9377
9374
  border-radius: inherit;
@@ -14756,7 +14753,7 @@ const FormBasic = forwardRef((props, ref) => {
14756
14753
  loading
14757
14754
  };
14758
14755
  }, [loading]);
14759
- const [innerStyle, remainingProps] = withPropsStyle(rest, {
14756
+ const [remainingProps, innerStyle] = withPropsStyle(rest, {
14760
14757
  layout: true
14761
14758
  });
14762
14759
  return jsx("form", {