@papernote/ui 1.7.0 → 1.7.2
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/components/Breadcrumbs.d.ts +66 -0
- package/dist/components/Breadcrumbs.d.ts.map +1 -1
- package/dist/components/index.d.ts +2 -2
- package/dist/components/index.d.ts.map +1 -1
- package/dist/index.d.ts +68 -2
- package/dist/index.esm.js +106 -9
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +105 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/Breadcrumbs.tsx +166 -21
- package/src/components/index.ts +2 -2
package/dist/index.js
CHANGED
|
@@ -7279,16 +7279,113 @@ function Hide({ children, above, below, only, className = '' }) {
|
|
|
7279
7279
|
return (jsxRuntime.jsx("div", { className: `${visibilityClasses} ${className}`, children: children }));
|
|
7280
7280
|
}
|
|
7281
7281
|
|
|
7282
|
+
/**
|
|
7283
|
+
* Hook to detect breadcrumb navigation and trigger callbacks.
|
|
7284
|
+
* Use this in host components to reset state when a breadcrumb is clicked.
|
|
7285
|
+
*
|
|
7286
|
+
* @param onReset - Callback fired when breadcrumb navigation is detected
|
|
7287
|
+
*
|
|
7288
|
+
* @example
|
|
7289
|
+
* function ProductsPage() {
|
|
7290
|
+
* const [viewMode, setViewMode] = useState<'list' | 'detail'>('list');
|
|
7291
|
+
*
|
|
7292
|
+
* // Automatically reset to list view when breadcrumb is clicked
|
|
7293
|
+
* useBreadcrumbReset(() => setViewMode('list'));
|
|
7294
|
+
*
|
|
7295
|
+
* // ... rest of component
|
|
7296
|
+
* }
|
|
7297
|
+
*/
|
|
7298
|
+
function useBreadcrumbReset(onReset) {
|
|
7299
|
+
const location = reactRouterDom.useLocation();
|
|
7300
|
+
const lastResetRef = React.useRef(null);
|
|
7301
|
+
React.useEffect(() => {
|
|
7302
|
+
const state = location.state;
|
|
7303
|
+
if (state?.breadcrumbReset && state.breadcrumbReset !== lastResetRef.current) {
|
|
7304
|
+
lastResetRef.current = state.breadcrumbReset;
|
|
7305
|
+
onReset();
|
|
7306
|
+
}
|
|
7307
|
+
}, [location.state, onReset]);
|
|
7308
|
+
}
|
|
7309
|
+
/**
|
|
7310
|
+
* Breadcrumbs navigation component.
|
|
7311
|
+
*
|
|
7312
|
+
* When a breadcrumb with href is clicked:
|
|
7313
|
+
* - If navigating to a different route: standard navigation occurs
|
|
7314
|
+
* - If navigating to the same route: navigation state is updated with a unique key,
|
|
7315
|
+
* which can be used by host apps to detect "reset" navigation via useLocation().state
|
|
7316
|
+
*
|
|
7317
|
+
* @example
|
|
7318
|
+
* // Basic usage
|
|
7319
|
+
* <Breadcrumbs items={[
|
|
7320
|
+
* { label: 'Home', href: '/' },
|
|
7321
|
+
* { label: 'Products', href: '/products' },
|
|
7322
|
+
* { label: 'Widget' } // Current page (no href)
|
|
7323
|
+
* ]} />
|
|
7324
|
+
*
|
|
7325
|
+
* @example
|
|
7326
|
+
* // Host app detecting breadcrumb navigation for state reset
|
|
7327
|
+
* function ProductsPage() {
|
|
7328
|
+
* const location = useLocation();
|
|
7329
|
+
* const [viewMode, setViewMode] = useState<'list' | 'detail'>('list');
|
|
7330
|
+
*
|
|
7331
|
+
* // Reset to list view when breadcrumb navigation occurs
|
|
7332
|
+
* useEffect(() => {
|
|
7333
|
+
* if (location.state?.breadcrumbReset) {
|
|
7334
|
+
* setViewMode('list');
|
|
7335
|
+
* }
|
|
7336
|
+
* }, [location.state?.breadcrumbReset]);
|
|
7337
|
+
*
|
|
7338
|
+
* // ... rest of component
|
|
7339
|
+
* }
|
|
7340
|
+
*/
|
|
7282
7341
|
function Breadcrumbs({ items, showHome = true }) {
|
|
7283
|
-
|
|
7342
|
+
const navigate = reactRouterDom.useNavigate();
|
|
7343
|
+
const location = reactRouterDom.useLocation();
|
|
7344
|
+
/**
|
|
7345
|
+
* Handle breadcrumb click with same-route detection.
|
|
7346
|
+
* When clicking a breadcrumb that points to the current route,
|
|
7347
|
+
* we navigate with state to trigger a reset in the host component.
|
|
7348
|
+
*/
|
|
7349
|
+
const handleBreadcrumbClick = (e, href, onClick) => {
|
|
7350
|
+
// Always call onClick if provided (for custom actions)
|
|
7351
|
+
onClick?.();
|
|
7352
|
+
// Check if we're navigating to the same base path
|
|
7353
|
+
const targetPath = href.split('?')[0].split('#')[0];
|
|
7354
|
+
const currentPath = location.pathname;
|
|
7355
|
+
if (targetPath === currentPath) {
|
|
7356
|
+
// Same route - prevent default Link behavior and use navigate with state
|
|
7357
|
+
e.preventDefault();
|
|
7358
|
+
navigate(href, {
|
|
7359
|
+
state: {
|
|
7360
|
+
breadcrumbReset: Date.now(),
|
|
7361
|
+
from: 'breadcrumb'
|
|
7362
|
+
},
|
|
7363
|
+
replace: true
|
|
7364
|
+
});
|
|
7365
|
+
}
|
|
7366
|
+
// Different route - let the Link handle it normally
|
|
7367
|
+
};
|
|
7368
|
+
return (jsxRuntime.jsxs("nav", { "aria-label": "Breadcrumb", className: "flex items-center space-x-2 text-sm", children: [showHome && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(reactRouterDom.Link, { to: "/", className: "text-ink-500 hover:text-ink-900 transition-colors", "aria-label": "Home", onClick: (e) => handleBreadcrumbClick(e, '/'), children: jsxRuntime.jsx(lucideReact.Home, { className: "h-4 w-4" }) }), items.length > 0 && jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-4 w-4 text-ink-400" })] })), items.map((item, index) => {
|
|
7284
7369
|
const isLast = index === items.length - 1;
|
|
7285
7370
|
const isActive = isLast;
|
|
7286
|
-
|
|
7287
|
-
|
|
7288
|
-
|
|
7289
|
-
|
|
7290
|
-
|
|
7291
|
-
|
|
7371
|
+
const content = (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [item.icon && jsxRuntime.jsx("span", { className: "flex-shrink-0", children: item.icon }), jsxRuntime.jsx("span", { children: item.label })] }));
|
|
7372
|
+
const renderBreadcrumb = () => {
|
|
7373
|
+
// Active item (last item) - always render as non-clickable span
|
|
7374
|
+
if (isActive) {
|
|
7375
|
+
return (jsxRuntime.jsx("span", { className: "flex items-center gap-2 px-2 py-1 rounded-md bg-accent-50 text-accent-900 font-semibold transition-colors", "aria-current": "page", children: content }));
|
|
7376
|
+
}
|
|
7377
|
+
// Has href - render as Link with same-route detection
|
|
7378
|
+
if (item.href) {
|
|
7379
|
+
return (jsxRuntime.jsx(reactRouterDom.Link, { to: item.href, onClick: (e) => handleBreadcrumbClick(e, item.href, item.onClick), className: "flex items-center gap-2 text-ink-500 hover:text-ink-900 hover:underline transition-colors", children: content }));
|
|
7380
|
+
}
|
|
7381
|
+
// Only onClick (no href) - render as button
|
|
7382
|
+
if (item.onClick) {
|
|
7383
|
+
return (jsxRuntime.jsx("button", { type: "button", onClick: item.onClick, className: "flex items-center gap-2 text-ink-500 hover:text-ink-900 hover:underline transition-colors bg-transparent border-none cursor-pointer p-0", children: content }));
|
|
7384
|
+
}
|
|
7385
|
+
// Neither href nor onClick - render as non-clickable span
|
|
7386
|
+
return (jsxRuntime.jsx("span", { className: "flex items-center gap-2 text-ink-700 font-medium", children: content }));
|
|
7387
|
+
};
|
|
7388
|
+
return (jsxRuntime.jsxs(React.Fragment, { children: [renderBreadcrumb(), !isLast && jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-4 w-4 text-ink-400" })] }, index));
|
|
7292
7389
|
})] }));
|
|
7293
7390
|
}
|
|
7294
7391
|
|
|
@@ -56986,6 +57083,7 @@ exports.saveColumnOrder = saveColumnOrder;
|
|
|
56986
57083
|
exports.saveColumnWidths = saveColumnWidths;
|
|
56987
57084
|
exports.searchFormulas = searchFormulas;
|
|
56988
57085
|
exports.statusManager = statusManager;
|
|
57086
|
+
exports.useBreadcrumbReset = useBreadcrumbReset;
|
|
56989
57087
|
exports.useBreakpoint = useBreakpoint;
|
|
56990
57088
|
exports.useBreakpointValue = useBreakpointValue;
|
|
56991
57089
|
exports.useColumnReorder = useColumnReorder;
|