@olenbetong/synergi-react 2.4.0 → 2.5.1
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/es/components/AppMenu/AppMenu.css +158 -0
- package/es/components/AppMenu/index.d.ts +12 -0
- package/es/components/AppMenu/index.js +85 -0
- package/es/components/AppShell/index.d.ts +5 -0
- package/es/components/AppShell/index.js +112 -0
- package/es/components/Toolbar/Toolbar.css +124 -0
- package/es/components/Toolbar/index.d.ts +15 -0
- package/es/components/Toolbar/index.js +64 -0
- package/es/index.d.ts +3 -0
- package/es/index.js +3 -0
- package/package.json +9 -7
- package/src/components/AppMenu/AppMenu.css +158 -0
- package/src/components/AppMenu/index.tsx +179 -0
- package/src/components/AppShell/index.tsx +133 -0
- package/src/components/Toolbar/Toolbar.css +124 -0
- package/src/components/Toolbar/index.tsx +132 -0
- package/src/index.ts +10 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import "./Toolbar.css";
|
|
2
|
+
|
|
3
|
+
import { useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
4
|
+
import { createPortal } from "react-dom";
|
|
5
|
+
|
|
6
|
+
export type ToolbarPortalSlot = "breadcrumbs" | "search" | "actions";
|
|
7
|
+
|
|
8
|
+
export type ToolbarPortalProps = {
|
|
9
|
+
slot: ToolbarPortalSlot;
|
|
10
|
+
children: React.ReactNode;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export function ToolbarPortal({ slot, children }: ToolbarPortalProps) {
|
|
14
|
+
// Target element IDs: ob-toolbar-breadcrumbs, ob-toolbar-search, ob-toolbar-actions
|
|
15
|
+
const target = document.getElementById(`ob-toolbar-${slot}`);
|
|
16
|
+
if (!target) return null;
|
|
17
|
+
return createPortal(children, target);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type BreadcrumbItem = {
|
|
21
|
+
label: string;
|
|
22
|
+
href?: string;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export type ToolbarBreadcrumbsProps = {
|
|
26
|
+
items: BreadcrumbItem[];
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
function BreadcrumbsInner({ items }: ToolbarBreadcrumbsProps) {
|
|
30
|
+
let [firstVisible, setFirstVisible] = useState(0);
|
|
31
|
+
let [overflowOpen, setOverflowOpen] = useState(false);
|
|
32
|
+
let navRef = useRef<HTMLElement>(null);
|
|
33
|
+
let listRef = useRef<HTMLOListElement>(null);
|
|
34
|
+
let overflowItemRef = useRef<HTMLLIElement>(null);
|
|
35
|
+
|
|
36
|
+
// Detect overflow: increment firstVisible until the list fits within the nav.
|
|
37
|
+
// Runs after every render so it keeps pushing items into overflow until the
|
|
38
|
+
// list stops overflowing or only the last item (current page) remains.
|
|
39
|
+
useLayoutEffect(() => {
|
|
40
|
+
let nav = navRef.current;
|
|
41
|
+
let list = listRef.current;
|
|
42
|
+
if (!nav || !list) return;
|
|
43
|
+
|
|
44
|
+
if (list.scrollWidth > nav.clientWidth && firstVisible < items.length - 1) {
|
|
45
|
+
setFirstVisible((prev) => prev + 1);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// ResizeObserver resets firstVisible to 0 on container resize so that the
|
|
50
|
+
// overflow calculation starts fresh at the new container width.
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
let nav = navRef.current;
|
|
53
|
+
if (!nav) return;
|
|
54
|
+
|
|
55
|
+
let observer = new ResizeObserver(() => {
|
|
56
|
+
setFirstVisible(0);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
observer.observe(nav);
|
|
60
|
+
return () => observer.disconnect();
|
|
61
|
+
}, []);
|
|
62
|
+
|
|
63
|
+
// Close the overflow dropdown when the user clicks outside of it.
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
if (!overflowOpen) return;
|
|
66
|
+
|
|
67
|
+
function handleClickOutside(event: MouseEvent) {
|
|
68
|
+
if (overflowItemRef.current && !overflowItemRef.current.contains(event.target as Node)) {
|
|
69
|
+
setOverflowOpen(false);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
74
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
75
|
+
}, [overflowOpen]);
|
|
76
|
+
|
|
77
|
+
let hiddenItems = items.slice(0, firstVisible);
|
|
78
|
+
let visibleItems = items.slice(firstVisible);
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<nav className="ob-breadcrumbs" aria-label="Breadcrumb" ref={navRef}>
|
|
82
|
+
<ol className="ob-breadcrumbs__list" ref={listRef}>
|
|
83
|
+
{firstVisible > 0 && (
|
|
84
|
+
<li className="ob-breadcrumbs__item ob-breadcrumbs__overflow" ref={overflowItemRef}>
|
|
85
|
+
<button
|
|
86
|
+
type="button"
|
|
87
|
+
aria-label="Show hidden breadcrumbs"
|
|
88
|
+
aria-expanded={overflowOpen}
|
|
89
|
+
aria-haspopup="true"
|
|
90
|
+
onClick={() => setOverflowOpen((prev) => !prev)}
|
|
91
|
+
>
|
|
92
|
+
…
|
|
93
|
+
</button>
|
|
94
|
+
{overflowOpen && (
|
|
95
|
+
<ul className="ob-breadcrumbs__overflow-menu" role="menu">
|
|
96
|
+
{hiddenItems.map((item, index) => (
|
|
97
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: stable list with no reordering
|
|
98
|
+
<li key={index} role="menuitem">
|
|
99
|
+
{item.href ? <a href={item.href}>{item.label}</a> : <span>{item.label}</span>}
|
|
100
|
+
</li>
|
|
101
|
+
))}
|
|
102
|
+
</ul>
|
|
103
|
+
)}
|
|
104
|
+
</li>
|
|
105
|
+
)}
|
|
106
|
+
{visibleItems.map((item, index) => {
|
|
107
|
+
let actualIndex = firstVisible + index;
|
|
108
|
+
let isCurrent = actualIndex === items.length - 1;
|
|
109
|
+
return (
|
|
110
|
+
<li key={actualIndex} className="ob-breadcrumbs__item">
|
|
111
|
+
{isCurrent ? (
|
|
112
|
+
<span aria-current="page">{item.label}</span>
|
|
113
|
+
) : item.href ? (
|
|
114
|
+
<a href={item.href}>{item.label}</a>
|
|
115
|
+
) : (
|
|
116
|
+
<span>{item.label}</span>
|
|
117
|
+
)}
|
|
118
|
+
</li>
|
|
119
|
+
);
|
|
120
|
+
})}
|
|
121
|
+
</ol>
|
|
122
|
+
</nav>
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export function ToolbarBreadcrumbs({ items }: ToolbarBreadcrumbsProps) {
|
|
127
|
+
return (
|
|
128
|
+
<ToolbarPortal slot="breadcrumbs">
|
|
129
|
+
<BreadcrumbsInner items={items} />
|
|
130
|
+
</ToolbarPortal>
|
|
131
|
+
);
|
|
132
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export { AppMenu, type AppMenuArticle, type AppMenuProps } from "./components/AppMenu/index.js";
|
|
2
|
+
export { AppShell, type AppShellProps } from "./components/AppShell/index.js";
|
|
1
3
|
export { Checkbox, type CheckboxProps } from "./components/Checkbox/index.js";
|
|
2
4
|
export { CardColumn, CardDetail, CardLabel, CardStep, CardStepList, ColorCard } from "./components/ColorCard/index.js";
|
|
3
5
|
export { DateNavigator } from "./components/DateNavigator/index.js";
|
|
@@ -19,6 +21,14 @@ export {
|
|
|
19
21
|
} from "./components/PageBanner/index.js";
|
|
20
22
|
export * from "./components/PdfViewer/index.js";
|
|
21
23
|
export { Portal } from "./components/Portal/index.js";
|
|
24
|
+
export {
|
|
25
|
+
ToolbarBreadcrumbs,
|
|
26
|
+
ToolbarPortal,
|
|
27
|
+
type BreadcrumbItem,
|
|
28
|
+
type ToolbarBreadcrumbsProps,
|
|
29
|
+
type ToolbarPortalProps,
|
|
30
|
+
type ToolbarPortalSlot,
|
|
31
|
+
} from "./components/Toolbar/index.js";
|
|
22
32
|
export { ProgressBar } from "./components/ProgressBar/index.js";
|
|
23
33
|
export { Sidebar, type SidebarProps } from "./components/Sidebar/index.js";
|
|
24
34
|
export { Spinner, type SpinnerProps } from "./components/Spinner/index.js";
|