@fluid-app/portal-sdk 0.1.245 → 0.1.246
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.
- package/dist/index.cjs +73 -57
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +73 -57
- package/dist/index.mjs.map +1 -1
- package/package.json +15 -15
package/dist/index.mjs
CHANGED
|
@@ -1865,6 +1865,68 @@ function SdkCompanySwitcher() {
|
|
|
1865
1865
|
});
|
|
1866
1866
|
}
|
|
1867
1867
|
//#endregion
|
|
1868
|
+
//#region ../core/src/navigation/slug-utils.ts
|
|
1869
|
+
/**
|
|
1870
|
+
* Extract all slugs from a navigation tree, sorted by segment count descending.
|
|
1871
|
+
* Longest slugs first enables greedy prefix matching (e.g. "share/playlists"
|
|
1872
|
+
* is checked before "share").
|
|
1873
|
+
*/
|
|
1874
|
+
function collectNavSlugs(items) {
|
|
1875
|
+
const slugs = [];
|
|
1876
|
+
for (const item of items) {
|
|
1877
|
+
if (item.slug) slugs.push(normalizeSlug(item.slug));
|
|
1878
|
+
for (const child of item.children ?? []) if (child.slug) slugs.push(normalizeSlug(child.slug));
|
|
1879
|
+
}
|
|
1880
|
+
return [...slugs].sort((a, b) => b.split("/").length - a.split("/").length);
|
|
1881
|
+
}
|
|
1882
|
+
/**
|
|
1883
|
+
* Find the longest registered nav slug that is a prefix of `fullSlug`.
|
|
1884
|
+
* Uses segment-boundary checking to prevent "shop" from matching "shopping".
|
|
1885
|
+
*/
|
|
1886
|
+
function matchSlugPrefix(fullSlug, navSlugs) {
|
|
1887
|
+
const normalized = normalizeSlug(fullSlug);
|
|
1888
|
+
if (!normalized) return void 0;
|
|
1889
|
+
for (const navSlug of navSlugs) {
|
|
1890
|
+
if (normalized === navSlug) return {
|
|
1891
|
+
matchedSlug: navSlug,
|
|
1892
|
+
rest: ""
|
|
1893
|
+
};
|
|
1894
|
+
if (normalized.startsWith(navSlug + "/")) return {
|
|
1895
|
+
matchedSlug: navSlug,
|
|
1896
|
+
rest: normalized.slice(navSlug.length + 1)
|
|
1897
|
+
};
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1900
|
+
/**
|
|
1901
|
+
* Extract the slug portion from a full pathname by stripping the basePath prefix.
|
|
1902
|
+
* Returns an empty string when the pathname equals the basePath exactly.
|
|
1903
|
+
*
|
|
1904
|
+
* Examples:
|
|
1905
|
+
* extractSlugFromPathname("/contacts/123", "/") → "contacts/123"
|
|
1906
|
+
* extractSlugFromPathname("/portal/contacts", "/portal") → "contacts"
|
|
1907
|
+
* extractSlugFromPathname("/portal", "/portal") → ""
|
|
1908
|
+
* extractSlugFromPathname("/", "/") → ""
|
|
1909
|
+
*/
|
|
1910
|
+
function extractSlugFromPathname(pathname, basePath) {
|
|
1911
|
+
if (basePath === "/") return pathname.replace(/^\//, "");
|
|
1912
|
+
if (pathname.startsWith(basePath)) return pathname.slice(basePath.length).replace(/^\//, "");
|
|
1913
|
+
return pathname.replace(/^\//, "");
|
|
1914
|
+
}
|
|
1915
|
+
/**
|
|
1916
|
+
* Generate a URL-safe slug from a human-readable name. Mirrors the admin
|
|
1917
|
+
* builder's `generateSlugFromName` so a navigation item authored as
|
|
1918
|
+
* `slugifyName(screen.name)` can be matched back to the screen at runtime
|
|
1919
|
+
* even when the screen's own `slug` is opaque (e.g. `screen-{uuid}`).
|
|
1920
|
+
*/
|
|
1921
|
+
function slugifyName(name) {
|
|
1922
|
+
return name.toLowerCase().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "");
|
|
1923
|
+
}
|
|
1924
|
+
function isSlugInSection(item, currentSlug, navSlugs) {
|
|
1925
|
+
const baseSlug = matchSlugPrefix(currentSlug, navSlugs)?.matchedSlug ?? normalizeSlug(currentSlug);
|
|
1926
|
+
if (normalizeSlug(item.slug) === baseSlug) return true;
|
|
1927
|
+
return item.children?.some((child) => normalizeSlug(child.slug) === baseSlug) ?? false;
|
|
1928
|
+
}
|
|
1929
|
+
//#endregion
|
|
1868
1930
|
//#region src/shell/go-back-or-home.ts
|
|
1869
1931
|
/**
|
|
1870
1932
|
* Navigate one step back in the browser history if anything is on the stack;
|
|
@@ -2080,7 +2142,14 @@ function PageRouter({ currentSlug, currentNavItem, customPages, screens, baseSlu
|
|
|
2080
2142
|
}, [screens]);
|
|
2081
2143
|
const screenBySlug = useMemo(() => {
|
|
2082
2144
|
if (!screens || screens.length === 0) return void 0;
|
|
2083
|
-
|
|
2145
|
+
const map = /* @__PURE__ */ new Map();
|
|
2146
|
+
for (const s of screens) if (s.slug) map.set(s.slug, s);
|
|
2147
|
+
for (const s of screens) {
|
|
2148
|
+
if (!s.name) continue;
|
|
2149
|
+
const nameSlug = slugifyName(s.name);
|
|
2150
|
+
if (nameSlug && !map.has(nameSlug)) map.set(nameSlug, s);
|
|
2151
|
+
}
|
|
2152
|
+
return map;
|
|
2084
2153
|
}, [screens]);
|
|
2085
2154
|
const builderScreen = useMemo(() => {
|
|
2086
2155
|
if (currentNavItem?.screen_id && screenById) {
|
|
@@ -2122,59 +2191,6 @@ function PageRouter({ currentSlug, currentNavItem, customPages, screens, baseSlu
|
|
|
2122
2191
|
return /* @__PURE__ */ jsx(ScreenNotFound, { name: currentNavItem?.label ?? currentSlug });
|
|
2123
2192
|
}
|
|
2124
2193
|
//#endregion
|
|
2125
|
-
//#region ../core/src/navigation/slug-utils.ts
|
|
2126
|
-
/**
|
|
2127
|
-
* Extract all slugs from a navigation tree, sorted by segment count descending.
|
|
2128
|
-
* Longest slugs first enables greedy prefix matching (e.g. "share/playlists"
|
|
2129
|
-
* is checked before "share").
|
|
2130
|
-
*/
|
|
2131
|
-
function collectNavSlugs(items) {
|
|
2132
|
-
const slugs = [];
|
|
2133
|
-
for (const item of items) {
|
|
2134
|
-
if (item.slug) slugs.push(normalizeSlug(item.slug));
|
|
2135
|
-
for (const child of item.children ?? []) if (child.slug) slugs.push(normalizeSlug(child.slug));
|
|
2136
|
-
}
|
|
2137
|
-
return [...slugs].sort((a, b) => b.split("/").length - a.split("/").length);
|
|
2138
|
-
}
|
|
2139
|
-
/**
|
|
2140
|
-
* Find the longest registered nav slug that is a prefix of `fullSlug`.
|
|
2141
|
-
* Uses segment-boundary checking to prevent "shop" from matching "shopping".
|
|
2142
|
-
*/
|
|
2143
|
-
function matchSlugPrefix(fullSlug, navSlugs) {
|
|
2144
|
-
const normalized = normalizeSlug(fullSlug);
|
|
2145
|
-
if (!normalized) return void 0;
|
|
2146
|
-
for (const navSlug of navSlugs) {
|
|
2147
|
-
if (normalized === navSlug) return {
|
|
2148
|
-
matchedSlug: navSlug,
|
|
2149
|
-
rest: ""
|
|
2150
|
-
};
|
|
2151
|
-
if (normalized.startsWith(navSlug + "/")) return {
|
|
2152
|
-
matchedSlug: navSlug,
|
|
2153
|
-
rest: normalized.slice(navSlug.length + 1)
|
|
2154
|
-
};
|
|
2155
|
-
}
|
|
2156
|
-
}
|
|
2157
|
-
/**
|
|
2158
|
-
* Extract the slug portion from a full pathname by stripping the basePath prefix.
|
|
2159
|
-
* Returns an empty string when the pathname equals the basePath exactly.
|
|
2160
|
-
*
|
|
2161
|
-
* Examples:
|
|
2162
|
-
* extractSlugFromPathname("/contacts/123", "/") → "contacts/123"
|
|
2163
|
-
* extractSlugFromPathname("/portal/contacts", "/portal") → "contacts"
|
|
2164
|
-
* extractSlugFromPathname("/portal", "/portal") → ""
|
|
2165
|
-
* extractSlugFromPathname("/", "/") → ""
|
|
2166
|
-
*/
|
|
2167
|
-
function extractSlugFromPathname(pathname, basePath) {
|
|
2168
|
-
if (basePath === "/") return pathname.replace(/^\//, "");
|
|
2169
|
-
if (pathname.startsWith(basePath)) return pathname.slice(basePath.length).replace(/^\//, "");
|
|
2170
|
-
return pathname.replace(/^\//, "");
|
|
2171
|
-
}
|
|
2172
|
-
function isSlugInSection(item, currentSlug, navSlugs) {
|
|
2173
|
-
const baseSlug = matchSlugPrefix(currentSlug, navSlugs)?.matchedSlug ?? normalizeSlug(currentSlug);
|
|
2174
|
-
if (normalizeSlug(item.slug) === baseSlug) return true;
|
|
2175
|
-
return item.children?.some((child) => normalizeSlug(child.slug) === baseSlug) ?? false;
|
|
2176
|
-
}
|
|
2177
|
-
//#endregion
|
|
2178
2194
|
//#region src/shell/AppShellErrorBoundary.tsx
|
|
2179
2195
|
var AppShellErrorBoundary = class extends Component {
|
|
2180
2196
|
state = { error: null };
|
|
@@ -2428,7 +2444,7 @@ function AppShell({ appData: appDataProp, navigation: navigationProp, customPage
|
|
|
2428
2444
|
const navSlugs = useMemo(() => collectNavSlugs(filteredNavItems), [filteredNavItems]);
|
|
2429
2445
|
const allNavSlugs = useMemo(() => {
|
|
2430
2446
|
const mobileSlugs = collectNavSlugs(filteredMobileNavItems);
|
|
2431
|
-
return Array.from(new Set([...navSlugs, ...mobileSlugs]));
|
|
2447
|
+
return Array.from(new Set([...navSlugs, ...mobileSlugs])).sort((a, b) => b.split("/").length - a.split("/").length);
|
|
2432
2448
|
}, [navSlugs, filteredMobileNavItems]);
|
|
2433
2449
|
const [themeMode, setThemeMode] = useState(getInitialThemeMode);
|
|
2434
2450
|
const handleThemeModeChange = useCallback((mode) => {
|
|
@@ -2534,11 +2550,11 @@ function AppShell({ appData: appDataProp, navigation: navigationProp, customPage
|
|
|
2534
2550
|
if (typeof orderToken === "string" && orderToken) handleNavigate(`orders/${orderToken}`);
|
|
2535
2551
|
}, [handleNavigate]);
|
|
2536
2552
|
const resolvedSidebarFooter = useMemo(() => sidebarFooter !== void 0 ? sidebarFooter : /* @__PURE__ */ jsx(SdkLogoutButton, { onLogout: logout }), [sidebarFooter, logout]);
|
|
2537
|
-
const slugMatch = useMemo(() => matchSlugPrefix(activeSlug,
|
|
2553
|
+
const slugMatch = useMemo(() => matchSlugPrefix(activeSlug, allNavSlugs), [activeSlug, allNavSlugs]);
|
|
2538
2554
|
const baseSlug = slugMatch?.matchedSlug ?? normalizeSlug(activeSlug);
|
|
2539
2555
|
const restParams = slugMatch?.rest ?? "";
|
|
2540
2556
|
const mobileSecondLevelTabs = findCurrentSection(filteredMobileNavItems, baseSlug)?.children ?? [];
|
|
2541
|
-
const currentNavItem = findNavItem(filteredNavItems, baseSlug);
|
|
2557
|
+
const currentNavItem = findNavItem(filteredNavItems, baseSlug) ?? findNavItem(filteredMobileNavItems, baseSlug);
|
|
2542
2558
|
const screenTitle = currentNavItem?.label || screens?.find((s) => s.id === currentNavItem?.screen_id)?.name || void 0;
|
|
2543
2559
|
const content = /* @__PURE__ */ jsx(AppShellErrorBoundary, { children: typeof children === "function" ? children({
|
|
2544
2560
|
currentSlug: activeSlug,
|