@pnkx-lib/ui 1.9.450 → 1.9.451

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.
@@ -54,30 +54,41 @@ function validateAbsolutePaths(menu, nearestAncestorPath) {
54
54
  }
55
55
  }
56
56
 
57
- function compilePattern(pattern) {
57
+ function compilePatternStrict(pattern) {
58
58
  const pat = normalize(pattern);
59
59
  const keys = [];
60
60
  const escaped = pat.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
61
- const withCaptures = escaped.replace(/:([^/]+)/g, (_m, key) => {
61
+ const withCaptures = escaped.replace(/:([^/]+)/g, (_m, raw) => {
62
+ const key = raw.replace(/[\\'"]/g, "");
62
63
  keys.push(key);
63
64
  return "([^/]+)";
64
65
  });
65
- const regex = new RegExp(`^${withCaptures}/?$`);
66
- return { regex, keys };
66
+ return { regex: new RegExp(`^${withCaptures}/?$`), keys };
67
67
  }
68
- function matchPath(pattern, pathname) {
69
- const { regex } = compilePattern(pattern);
68
+ function matchPathStrict(pattern, pathname) {
69
+ const { regex } = compilePatternStrict(pattern);
70
70
  return regex.test(normalize(pathname));
71
71
  }
72
- function extractParams(pattern, pathname) {
73
- const { regex, keys } = compilePattern(pattern);
72
+ function compilePatternLoose(pattern) {
73
+ const pat = normalize(pattern);
74
+ const keys = [];
75
+ const escaped = pat.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
76
+ const withCaptures = escaped.replace(/:([^/]+)/g, (_m, raw) => {
77
+ const key = raw.replace(/[\\'"]/g, "");
78
+ keys.push(key);
79
+ return "([^/]+)";
80
+ });
81
+ return { regex: new RegExp(`^${withCaptures}(?:/.*)?$`), keys };
82
+ }
83
+ function extractParamsLoose(pattern, pathname) {
84
+ const { regex, keys } = compilePatternLoose(pattern);
74
85
  const m = regex.exec(normalize(pathname));
75
86
  if (!m) return {};
76
87
  const out = {};
77
88
  for (let i = 0; i < keys.length; i++) out[keys[i]] = m[i + 1];
78
89
  return out;
79
90
  }
80
- const hasParams = (p) => !!p && /:([^/]+)/.test(p ?? "");
91
+ const hasParams = (p) => !!p && /:([^/]+)/.test(p);
81
92
  const full = (itemPath) => normalize(itemPath ?? "/");
82
93
  function findTrail(menu, pathUrl) {
83
94
  const trail = [];
@@ -85,7 +96,7 @@ function findTrail(menu, pathUrl) {
85
96
  for (const item of items) {
86
97
  const fullPath = full(item.path);
87
98
  trail.push({ ...item, fullPath });
88
- if (item.path && matchPath(fullPath, pathUrl)) return true;
99
+ if (item.path && matchPathStrict(fullPath, pathUrl)) return true;
89
100
  if (item.children?.length && walk(item.children)) return true;
90
101
  trail.pop();
91
102
  }
@@ -94,6 +105,20 @@ function findTrail(menu, pathUrl) {
94
105
  walk(menu);
95
106
  return trail;
96
107
  }
108
+ function pickParamsFromNearestAncestor(trail, fromIndex, pathname, patternKeys) {
109
+ for (let j = fromIndex; j >= 0; j--) {
110
+ const p = trail[j].path;
111
+ if (p && /:([^/]+)/.test(p)) {
112
+ const all = extractParamsLoose(p, pathname);
113
+ const picked = {};
114
+ for (const k of patternKeys) {
115
+ if (all[k]) picked[k] = all[k];
116
+ }
117
+ if (Object.keys(picked).length) return picked;
118
+ }
119
+ }
120
+ return {};
121
+ }
97
122
  function useBreadcrumb(menuRouter, customBreadcrumb) {
98
123
  const { pathname } = useLocation();
99
124
  const normalizedPath = React.useMemo(() => normalize(pathname), [pathname]);
@@ -105,10 +130,6 @@ function useBreadcrumb(menuRouter, customBreadcrumb) {
105
130
  () => trail.length ? trail[trail.length - 1] : void 0,
106
131
  [trail]
107
132
  );
108
- const paramsFromLeaf = React.useMemo(
109
- () => leaf?.path ? extractParams(leaf.path, normalizedPath) : {},
110
- [leaf?.path, normalizedPath]
111
- );
112
133
  const filteredTrail = React.useMemo(() => {
113
134
  if (!trail.length || leaf?.isShowBreadcrumb !== true) return [];
114
135
  return trail.filter(
@@ -122,16 +143,37 @@ function useBreadcrumb(menuRouter, customBreadcrumb) {
122
143
  const pattern = node.path ?? node.fullPath;
123
144
  let href;
124
145
  if (pattern) {
125
- href = hasParams(pattern) ? (() => {
146
+ if (hasParams(pattern)) {
147
+ const { keys: requiredKeys } = compilePatternLoose(pattern);
148
+ const extracted = extractParamsLoose(pattern, normalizedPath);
149
+ let paramsForNode = requiredKeys.reduce(
150
+ (acc, k) => {
151
+ if (extracted[k]) acc[k] = extracted[k];
152
+ return acc;
153
+ },
154
+ {}
155
+ );
156
+ if (Object.keys(paramsForNode).length < requiredKeys.length) {
157
+ const fromAncestor = pickParamsFromNearestAncestor(
158
+ filteredTrail,
159
+ i,
160
+ normalizedPath,
161
+ requiredKeys
162
+ );
163
+ paramsForNode = { ...fromAncestor, ...paramsForNode };
164
+ }
126
165
  try {
127
- return generatePath(pattern, paramsFromLeaf);
166
+ href = Object.keys(paramsForNode).length === requiredKeys.length ? generatePath(pattern, paramsForNode) : void 0;
128
167
  } catch {
129
- return void 0;
168
+ href = void 0;
130
169
  }
131
- })() : pattern;
170
+ } else {
171
+ href = pattern;
172
+ }
132
173
  }
133
- const titleNode = isLast ? /* @__PURE__ */ jsx("span", { children: node.name }) : href ? /* @__PURE__ */ jsx(Link, { to: href, children: node.name }) : /* @__PURE__ */ jsx("span", { children: node.name });
134
- return { title: titleNode };
174
+ return {
175
+ title: isLast ? /* @__PURE__ */ jsx("span", { children: node.name }) : href ? /* @__PURE__ */ jsx(Link, { to: href, children: node.name }) : /* @__PURE__ */ jsx("span", { children: node.name })
176
+ };
135
177
  });
136
178
  return [
137
179
  ...items,
package/es/index.js CHANGED
@@ -84,7 +84,7 @@ export { Cascader } from './fields/CascaderField.js';
84
84
  export { InputRangePicker } from './fields/InputRangePicker.js';
85
85
  export { useToast } from './hooks/useToast.js';
86
86
  export { useMessage } from './hooks/useMessage.js';
87
- export { c as createComponentWithProps, e as extractRoutesFromMenu, n as normalize, v as validateAbsolutePaths } from './chunks/useBreadcrumb-DtXCsh1h.js';
87
+ export { c as createComponentWithProps, e as extractRoutesFromMenu, n as normalize, v as validateAbsolutePaths } from './chunks/useBreadcrumb-DEKhv1-Z.js';
88
88
 
89
89
  const generateId = (name, path) => {
90
90
  const source = `${name}-${path || ""}`;
@@ -1,7 +1,7 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
2
  import { r } from '../chunks/index-t0ynpS_n.js';
3
3
  import { Breadcrumb } from './Breadcrumb.js';
4
- import { u as useBreadcrumb } from '../chunks/useBreadcrumb-DtXCsh1h.js';
4
+ import { u as useBreadcrumb } from '../chunks/useBreadcrumb-DEKhv1-Z.js';
5
5
 
6
6
  const BreadcrumbHeading = (props) => {
7
7
  const { menu, customBreadcum } = props;
@@ -1,5 +1,5 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
- import { u as useBreadcrumb } from '../chunks/useBreadcrumb-DtXCsh1h.js';
2
+ import { u as useBreadcrumb } from '../chunks/useBreadcrumb-DEKhv1-Z.js';
3
3
  import { Breadcrumb } from './Breadcrumb.js';
4
4
 
5
5
  const WrapperBreadcrumb = ({ menu }) => {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pnkx-lib/ui",
3
3
  "private": false,
4
- "version": "1.9.450",
4
+ "version": "1.9.451",
5
5
  "type": "module",
6
6
  "main": "./es/index.js",
7
7
  "module": "./es/index.js",