@propeller-commerce/propeller-v2-react-ui 0.10.1 → 0.11.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/CHANGELOG.md +87 -0
- package/dist/index.cjs +178 -251
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +69 -6
- package/dist/index.d.ts +69 -6
- package/dist/index.js +178 -251
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,93 @@ once it reaches 1.0. Until then (the `0.x` line) the public API may change
|
|
|
8
8
|
between minor versions; breaking changes are called out below and in
|
|
9
9
|
[MIGRATION.md](./MIGRATION.md).
|
|
10
10
|
|
|
11
|
+
## [0.11.1] - 2026-07-30
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- **`menuStyle="accordion"` rendered nothing above `md`.** The accordion is the
|
|
16
|
+
mobile drawer for every style, so its `<nav>` carried `md:hidden` and rendered
|
|
17
|
+
unconditionally — while the desktop branches were gated on `menuStyle`.
|
|
18
|
+
Selecting it therefore matched no desktop branch and hid the mobile one,
|
|
19
|
+
leaving an empty panel. It now renders at every breakpoint when chosen
|
|
20
|
+
explicitly, and stays `md:hidden` as the mobile presentation of the others.
|
|
21
|
+
This is what 0.11.0's depth warning already recommended for deep trees.
|
|
22
|
+
- **`menuStyle` values with no renderer failed silently.** An unrecognised
|
|
23
|
+
style matched no branch and produced an empty panel with nothing to indicate
|
|
24
|
+
why. It now falls back to `accordion` — the style that can display any tree —
|
|
25
|
+
and warns in development, pointing at `renderMenu`.
|
|
26
|
+
- **The accordion's expand control didn't look clickable.** Tailwind v4 resets
|
|
27
|
+
buttons to `cursor: default`, so the chevron — the only control that expands a
|
|
28
|
+
branch — gave no affordance. Added `cursor-pointer` plus a hover colour shift,
|
|
29
|
+
and the same to the jumbotron tabs, which had it too.
|
|
30
|
+
- **A deep flyout could run off the viewport with no way to reach it.** The
|
|
31
|
+
columns row now has `max-w-[100vw] overflow-x-auto`, so a tree wider than the
|
|
32
|
+
screen degrades to a scroll instead of being unreachable.
|
|
33
|
+
|
|
34
|
+
### Added
|
|
35
|
+
|
|
36
|
+
- **`renderMenu` — render the menu yourself.** The built-in styles are three
|
|
37
|
+
arrangements of the same tree; this is the escape hatch for a fourth. It
|
|
38
|
+
receives a `MenuRenderContext` carrying the categories, the open-path state
|
|
39
|
+
and the same helpers the built-ins use (`getCategoryUrl` honouring
|
|
40
|
+
`getUrl`/`configuration`, `handleItemClick` firing `onMenuItemClick`,
|
|
41
|
+
`openAt`/`toggleAt`/`isOpenAt`), so a custom menu gets working open/close
|
|
42
|
+
behaviour and URL building without reimplementing them and drifting. Return
|
|
43
|
+
`null` to fall through to the `menuStyle` rendering. `MenuStyle` and
|
|
44
|
+
`MenuRenderContext` are exported.
|
|
45
|
+
- **First tests for `Menu`** (9 cases), covering the failures above: they all
|
|
46
|
+
passed type-checking and rendered *something*, so only a DOM assertion catches
|
|
47
|
+
them.
|
|
48
|
+
|
|
49
|
+
### Changed
|
|
50
|
+
|
|
51
|
+
- **`dropdown-horizontal` removed.** It was referenced only in the depth-cap
|
|
52
|
+
logic and never had a renderer, so it advertised a style that drew nothing.
|
|
53
|
+
Callers using it now hit the unknown-style fallback (accordion + warning); use
|
|
54
|
+
`renderMenu` for a genuinely custom layout.
|
|
55
|
+
- **`dropdown-vertical` caps at 5 levels, up from 4.** Each level is a 256px
|
|
56
|
+
column, so five total 1280px — within a 1440px desktop. Paired with the
|
|
57
|
+
overflow guard above for narrower screens.
|
|
58
|
+
- **`menuStyle` is typed `MenuStyle | (string & {})`** rather than `string`: the
|
|
59
|
+
built-ins autocomplete while a custom value still type-checks for use with
|
|
60
|
+
`renderMenu`.
|
|
61
|
+
|
|
62
|
+
## [0.11.0] - 2026-07-30
|
|
63
|
+
|
|
64
|
+
### Fixed
|
|
65
|
+
|
|
66
|
+
- **`<Menu depth>` was inert past three levels.** `depth` was threaded into
|
|
67
|
+
`useMenu`, which correctly built a recursive query to any depth, but every
|
|
68
|
+
style rendered exactly three hand-coded levels. `depth={4}` and beyond fetched
|
|
69
|
+
data that was never displayed — extra payload for nothing, with no warning
|
|
70
|
+
that the prop was only half-honoured. All styles now render to `depth`.
|
|
71
|
+
- **The expand chevron promised levels that never rendered.** It keyed off "has
|
|
72
|
+
children" alone, so a category at the deepest rendered level showed an
|
|
73
|
+
affordance that did nothing. It is now also gated on the child being within
|
|
74
|
+
`depth`.
|
|
75
|
+
|
|
76
|
+
### Changed
|
|
77
|
+
|
|
78
|
+
- **Per-level menu state replaced with a single open path.** The four
|
|
79
|
+
positional state slots (`hoveredL1Id` / `hoveredL2Id` / `expandedL1` /
|
|
80
|
+
`expandedL2`) are now one `openPath: number[]`. "Opening a shallower item
|
|
81
|
+
closes the deeper ones" is structural (`slice(0, level)`) rather than a
|
|
82
|
+
hand-written reset per level, which grew quadratically and was easy to get
|
|
83
|
+
wrong when adding a level.
|
|
84
|
+
- **`data-level` is emitted to whatever depth renders** instead of a hardcoded
|
|
85
|
+
`1`/`2`/`3`, so consumer CSS can target arbitrary depth.
|
|
86
|
+
- **Flyout styles cap the levels they can lay out** — 4 for
|
|
87
|
+
`dropdown-vertical`, 3 for `dropdown-horizontal`/`jumbotron`, since each level
|
|
88
|
+
is another horizontal column and beyond that they run off-screen. The
|
|
89
|
+
accordion nests vertically and is uncapped. Exceeding a cap logs a
|
|
90
|
+
`console.warn` in development (previously the prop silently did nothing).
|
|
91
|
+
|
|
92
|
+
`depth` still defaults to 3, and all fifteen `propeller-menu__*` class hooks are
|
|
93
|
+
unchanged, so a three-level menu keeps its existing structure and styling. Some
|
|
94
|
+
Tailwind utility classes internal to the component differ where per-level
|
|
95
|
+
values (`pl-8` / `pl-12` indentation) became a computed `padding-left`; styling
|
|
96
|
+
that targets the `propeller-menu__*` hooks is unaffected.
|
|
97
|
+
|
|
11
98
|
## [0.10.1] - 2026-07-30
|
|
12
99
|
|
|
13
100
|
### Fixed
|
package/dist/index.cjs
CHANGED
|
@@ -12845,12 +12845,10 @@ function ItemsOverview(props) {
|
|
|
12845
12845
|
] });
|
|
12846
12846
|
}
|
|
12847
12847
|
var ItemsOverview_default = ItemsOverview;
|
|
12848
|
+
var RENDERED_STYLES = ["dropdown-vertical", "jumbotron", "accordion"];
|
|
12848
12849
|
function Menu(rawProps) {
|
|
12849
12850
|
const props = useInfraProps(rawProps);
|
|
12850
|
-
const [
|
|
12851
|
-
const [hoveredL2Id, setHoveredL2Id] = React6.useState(null);
|
|
12852
|
-
const [expandedL1, setExpandedL1] = React6.useState(null);
|
|
12853
|
-
const [expandedL2, setExpandedL2] = React6.useState(null);
|
|
12851
|
+
const [openPath, setOpenPath] = React6.useState([]);
|
|
12854
12852
|
const userKey = props.user ? "contactId" in props.user ? `c${props.user.contactId}` : `u${props.user.customerId}` : "";
|
|
12855
12853
|
const hasPrefetchedTree = Array.isArray(props.tree);
|
|
12856
12854
|
const { categories: fetchedCategories, loading: fetchedLoading, error: menuError, fetchMenu } = useMenu({
|
|
@@ -12887,21 +12885,178 @@ function Menu(rawProps) {
|
|
|
12887
12885
|
});
|
|
12888
12886
|
}
|
|
12889
12887
|
}
|
|
12890
|
-
function
|
|
12891
|
-
|
|
12892
|
-
|
|
12888
|
+
function openAt(level, categoryId) {
|
|
12889
|
+
setOpenPath((prev) => {
|
|
12890
|
+
const next = prev.slice(0, level);
|
|
12891
|
+
if (categoryId !== null) next.push(categoryId);
|
|
12892
|
+
return next;
|
|
12893
|
+
});
|
|
12893
12894
|
}
|
|
12894
|
-
function
|
|
12895
|
-
|
|
12895
|
+
function toggleAt(level, categoryId) {
|
|
12896
|
+
setOpenPath(
|
|
12897
|
+
(prev) => prev[level] === categoryId ? prev.slice(0, level) : [...prev.slice(0, level), categoryId]
|
|
12898
|
+
);
|
|
12899
|
+
}
|
|
12900
|
+
function isOpenAt(level, categoryId) {
|
|
12901
|
+
return openPath[level] === categoryId;
|
|
12896
12902
|
}
|
|
12897
12903
|
function getMenuStyle() {
|
|
12898
|
-
|
|
12904
|
+
const requested = props.menuStyle || "dropdown-vertical";
|
|
12905
|
+
if (!RENDERED_STYLES.includes(requested)) {
|
|
12906
|
+
if (process.env.NODE_ENV !== "production") {
|
|
12907
|
+
console.warn(
|
|
12908
|
+
`[Menu] menuStyle="${requested}" has no built-in renderer (available: ${RENDERED_STYLES.join(", ")}); falling back to "accordion". Pass \`renderMenu\` to draw a custom style.`
|
|
12909
|
+
);
|
|
12910
|
+
}
|
|
12911
|
+
return "accordion";
|
|
12912
|
+
}
|
|
12913
|
+
return requested;
|
|
12914
|
+
}
|
|
12915
|
+
function getRenderableDepth() {
|
|
12916
|
+
const requested = Math.max(1, props.depth ?? 3);
|
|
12917
|
+
const cap = getMenuStyle() === "accordion" ? Number.POSITIVE_INFINITY : 5;
|
|
12918
|
+
if (process.env.NODE_ENV !== "production" && requested > cap) {
|
|
12919
|
+
console.warn(
|
|
12920
|
+
`[Menu] depth={${requested}} exceeds what menuStyle="${getMenuStyle()}" can lay out (${cap}); rendering ${cap} levels. Use menuStyle="accordion" for deeper trees.`
|
|
12921
|
+
);
|
|
12922
|
+
}
|
|
12923
|
+
return Math.min(requested, cap);
|
|
12924
|
+
}
|
|
12925
|
+
const maxDepth = getRenderableDepth();
|
|
12926
|
+
function renderChevron(cat, level, rotated = false) {
|
|
12927
|
+
if (getSubCategories(cat).length === 0 || level + 1 >= maxDepth) return null;
|
|
12928
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
12929
|
+
"svg",
|
|
12930
|
+
{
|
|
12931
|
+
className: `propeller-menu__chevron w-3.5 h-3.5 flex-shrink-0 transition-transform ${rotated ? "rotate-180" : ""}`,
|
|
12932
|
+
viewBox: "0 0 24 24",
|
|
12933
|
+
fill: "none",
|
|
12934
|
+
stroke: "currentColor",
|
|
12935
|
+
strokeWidth: "2",
|
|
12936
|
+
strokeLinecap: "round",
|
|
12937
|
+
strokeLinejoin: "round",
|
|
12938
|
+
"aria-hidden": "true",
|
|
12939
|
+
children: rotated ? /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "6 9 12 15 18 9" }) : /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "9 18 15 12 9 6" })
|
|
12940
|
+
}
|
|
12941
|
+
);
|
|
12942
|
+
}
|
|
12943
|
+
function renderColumns(items, level) {
|
|
12944
|
+
if (!items.length || level >= maxDepth) return [];
|
|
12945
|
+
const openId = openPath[level];
|
|
12946
|
+
const openCat = items.find((c) => c.categoryId === openId);
|
|
12947
|
+
const column = /* @__PURE__ */ jsxRuntime.jsx(
|
|
12948
|
+
"ul",
|
|
12949
|
+
{
|
|
12950
|
+
className: `propeller-menu__list w-64 py-1 flex-shrink-0 ${level + 1 < maxDepth ? "border-r border-border" : ""}`,
|
|
12951
|
+
"data-level": level + 1,
|
|
12952
|
+
children: items.map((cat, idx) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
12953
|
+
"li",
|
|
12954
|
+
{
|
|
12955
|
+
className: "propeller-menu__item",
|
|
12956
|
+
"data-level": level + 1,
|
|
12957
|
+
"data-active": isOpenAt(level, cat.categoryId) ? "true" : "false",
|
|
12958
|
+
onMouseEnter: () => openAt(level, cat.categoryId),
|
|
12959
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12960
|
+
"a",
|
|
12961
|
+
{
|
|
12962
|
+
href: getCategoryUrl(cat),
|
|
12963
|
+
onClick: (e) => handleItemClick(cat, e),
|
|
12964
|
+
className: `propeller-menu__link flex items-center justify-between px-4 py-2.5 text-sm transition-colors ${isOpenAt(level, cat.categoryId) ? "bg-accent text-accent-foreground" : "text-foreground hover:bg-accent/50"}`,
|
|
12965
|
+
children: [
|
|
12966
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "propeller-menu__label", children: getCategoryName(cat) }),
|
|
12967
|
+
renderChevron(cat, level)
|
|
12968
|
+
]
|
|
12969
|
+
}
|
|
12970
|
+
)
|
|
12971
|
+
},
|
|
12972
|
+
`l${level}-${cat.categoryId}-${idx}`
|
|
12973
|
+
))
|
|
12974
|
+
},
|
|
12975
|
+
`col-${level}`
|
|
12976
|
+
);
|
|
12977
|
+
const deeper = openCat ? renderColumns(getSubCategories(openCat), level + 1) : [];
|
|
12978
|
+
return [column, ...deeper];
|
|
12979
|
+
}
|
|
12980
|
+
function renderAccordion(items, level) {
|
|
12981
|
+
if (!items.length || level >= maxDepth) return null;
|
|
12982
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
12983
|
+
"ul",
|
|
12984
|
+
{
|
|
12985
|
+
className: `propeller-menu__list ${level === 0 ? "divide-y divide-border" : level === 1 ? "bg-accent/30" : "bg-accent/20"}`,
|
|
12986
|
+
"data-level": level + 1,
|
|
12987
|
+
children: items.map((cat, idx) => {
|
|
12988
|
+
const children = getSubCategories(cat);
|
|
12989
|
+
const expanded = isOpenAt(level, cat.categoryId);
|
|
12990
|
+
const canExpand = children.length > 0 && level + 1 < maxDepth;
|
|
12991
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12992
|
+
"li",
|
|
12993
|
+
{
|
|
12994
|
+
className: "propeller-menu__item",
|
|
12995
|
+
"data-level": level + 1,
|
|
12996
|
+
"data-expanded": expanded ? "true" : "false",
|
|
12997
|
+
children: [
|
|
12998
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
12999
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
13000
|
+
"a",
|
|
13001
|
+
{
|
|
13002
|
+
href: getCategoryUrl(cat),
|
|
13003
|
+
onClick: (e) => handleItemClick(cat, e),
|
|
13004
|
+
className: "propeller-menu__link flex-1 px-4 py-3 text-sm text-foreground",
|
|
13005
|
+
style: { paddingLeft: `${1 + level}rem` },
|
|
13006
|
+
children: getCategoryName(cat)
|
|
13007
|
+
}
|
|
13008
|
+
),
|
|
13009
|
+
canExpand ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
13010
|
+
"button",
|
|
13011
|
+
{
|
|
13012
|
+
type: "button",
|
|
13013
|
+
className: "propeller-menu__toggle cursor-pointer px-4 py-3 text-muted-foreground transition-colors hover:text-foreground",
|
|
13014
|
+
"aria-expanded": expanded,
|
|
13015
|
+
"aria-label": getCategoryName(cat),
|
|
13016
|
+
onClick: () => toggleAt(level, cat.categoryId),
|
|
13017
|
+
children: renderChevron(cat, level, expanded)
|
|
13018
|
+
}
|
|
13019
|
+
) : null
|
|
13020
|
+
] }),
|
|
13021
|
+
expanded && canExpand ? renderAccordion(children, level + 1) : null
|
|
13022
|
+
]
|
|
13023
|
+
},
|
|
13024
|
+
`l${level}-${cat.categoryId}-${idx}`
|
|
13025
|
+
);
|
|
13026
|
+
})
|
|
13027
|
+
}
|
|
13028
|
+
);
|
|
12899
13029
|
}
|
|
12900
13030
|
React6.useEffect(() => {
|
|
12901
13031
|
if (hasPrefetchedTree) return;
|
|
12902
13032
|
if (!props.graphqlClient) return;
|
|
12903
13033
|
fetchMenu(props.categoryId, userKey);
|
|
12904
13034
|
}, [hasPrefetchedTree, props.graphqlClient, props.categoryId, props.language, userKey, fetchMenu]);
|
|
13035
|
+
const customMenu = props.renderMenu ? props.renderMenu({
|
|
13036
|
+
categories: menuCategories,
|
|
13037
|
+
isLoading,
|
|
13038
|
+
hasError,
|
|
13039
|
+
maxDepth,
|
|
13040
|
+
getSubCategories,
|
|
13041
|
+
getCategoryName,
|
|
13042
|
+
getCategoryUrl,
|
|
13043
|
+
handleItemClick,
|
|
13044
|
+
openPath,
|
|
13045
|
+
isOpenAt,
|
|
13046
|
+
openAt,
|
|
13047
|
+
toggleAt
|
|
13048
|
+
}) : null;
|
|
13049
|
+
if (customMenu !== null && customMenu !== void 0) {
|
|
13050
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
13051
|
+
"div",
|
|
13052
|
+
{
|
|
13053
|
+
className: `propeller-menu ${props.className || ""}`,
|
|
13054
|
+
"data-variant": props.menuStyle || "custom",
|
|
13055
|
+
"data-loading": isLoading ? "true" : "false",
|
|
13056
|
+
children: customMenu
|
|
13057
|
+
}
|
|
13058
|
+
);
|
|
13059
|
+
}
|
|
12905
13060
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12906
13061
|
"div",
|
|
12907
13062
|
{
|
|
@@ -12919,125 +13074,7 @@ function Menu(rawProps) {
|
|
|
12919
13074
|
"nav",
|
|
12920
13075
|
{
|
|
12921
13076
|
className: `propeller-menu__nav hidden md:block ${props.menuClass || ""}`,
|
|
12922
|
-
children: /* @__PURE__ */ jsxRuntime.
|
|
12923
|
-
/* @__PURE__ */ jsxRuntime.jsx("ul", { className: "propeller-menu__list w-64 py-1 border-r border-border flex-shrink-0", "data-level": "1", children: menuCategories?.map((l1, idx) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
12924
|
-
"li",
|
|
12925
|
-
{
|
|
12926
|
-
className: "propeller-menu__item",
|
|
12927
|
-
"data-level": "1",
|
|
12928
|
-
"data-active": hoveredL1Id === l1.categoryId ? "true" : "false",
|
|
12929
|
-
onMouseEnter: (event) => setHoveredL1(l1.categoryId),
|
|
12930
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12931
|
-
"a",
|
|
12932
|
-
{
|
|
12933
|
-
href: getCategoryUrl(l1),
|
|
12934
|
-
onClick: (e) => handleItemClick(l1, e),
|
|
12935
|
-
className: `propeller-menu__link flex items-center justify-between px-4 py-2.5 text-sm transition-colors ${hoveredL1Id === l1.categoryId ? "bg-accent text-accent-foreground" : "text-foreground hover:bg-accent/50"}`,
|
|
12936
|
-
children: [
|
|
12937
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "propeller-menu__label font-medium truncate", children: getCategoryName(l1) }),
|
|
12938
|
-
getSubCategories(l1).length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
12939
|
-
"svg",
|
|
12940
|
-
{
|
|
12941
|
-
fill: "none",
|
|
12942
|
-
stroke: "currentColor",
|
|
12943
|
-
viewBox: "0 0 24 24",
|
|
12944
|
-
className: "propeller-menu__chevron w-4 h-4 text-muted-foreground",
|
|
12945
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
12946
|
-
"path",
|
|
12947
|
-
{
|
|
12948
|
-
strokeLinecap: "round",
|
|
12949
|
-
strokeLinejoin: "round",
|
|
12950
|
-
d: "M9 5l7 7-7 7",
|
|
12951
|
-
strokeWidth: 2
|
|
12952
|
-
}
|
|
12953
|
-
)
|
|
12954
|
-
}
|
|
12955
|
-
) : null
|
|
12956
|
-
]
|
|
12957
|
-
}
|
|
12958
|
-
)
|
|
12959
|
-
},
|
|
12960
|
-
`l1-${l1.categoryId}-${idx}`
|
|
12961
|
-
)) }),
|
|
12962
|
-
menuCategories?.map(
|
|
12963
|
-
(l1, idx) => hoveredL1Id === l1.categoryId && getSubCategories(l1).length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
12964
|
-
"ul",
|
|
12965
|
-
{
|
|
12966
|
-
className: "propeller-menu__list w-64 py-1 border-r border-border flex-shrink-0",
|
|
12967
|
-
"data-level": "2",
|
|
12968
|
-
children: getSubCategories(l1)?.map((l2, idx2) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
12969
|
-
"li",
|
|
12970
|
-
{
|
|
12971
|
-
className: "propeller-menu__item",
|
|
12972
|
-
"data-level": "2",
|
|
12973
|
-
"data-active": hoveredL2Id === l2.categoryId ? "true" : "false",
|
|
12974
|
-
onMouseEnter: (event) => setHoveredL2(l2.categoryId),
|
|
12975
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12976
|
-
"a",
|
|
12977
|
-
{
|
|
12978
|
-
href: getCategoryUrl(l2),
|
|
12979
|
-
onClick: (e) => handleItemClick(l2, e),
|
|
12980
|
-
className: `propeller-menu__link flex items-center justify-between px-4 py-2.5 text-sm transition-colors ${hoveredL2Id === l2.categoryId ? "bg-accent text-accent-foreground" : "text-foreground hover:bg-accent/50"}`,
|
|
12981
|
-
children: [
|
|
12982
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "propeller-menu__label truncate", children: getCategoryName(l2) }),
|
|
12983
|
-
getSubCategories(l2).length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
12984
|
-
"svg",
|
|
12985
|
-
{
|
|
12986
|
-
fill: "none",
|
|
12987
|
-
stroke: "currentColor",
|
|
12988
|
-
viewBox: "0 0 24 24",
|
|
12989
|
-
className: "propeller-menu__chevron w-4 h-4 text-muted-foreground",
|
|
12990
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
12991
|
-
"path",
|
|
12992
|
-
{
|
|
12993
|
-
strokeLinecap: "round",
|
|
12994
|
-
strokeLinejoin: "round",
|
|
12995
|
-
d: "M9 5l7 7-7 7",
|
|
12996
|
-
strokeWidth: 2
|
|
12997
|
-
}
|
|
12998
|
-
)
|
|
12999
|
-
}
|
|
13000
|
-
) : null
|
|
13001
|
-
]
|
|
13002
|
-
}
|
|
13003
|
-
)
|
|
13004
|
-
},
|
|
13005
|
-
`l2-${l2.categoryId}-${idx2}`
|
|
13006
|
-
))
|
|
13007
|
-
},
|
|
13008
|
-
`l1-sub-${l1.categoryId}-${idx}`
|
|
13009
|
-
) : null
|
|
13010
|
-
),
|
|
13011
|
-
menuCategories?.map(
|
|
13012
|
-
(l1, idx) => hoveredL1Id === l1.categoryId ? /* @__PURE__ */ jsxRuntime.jsx(React6__namespace.Fragment, { children: getSubCategories(l1)?.map(
|
|
13013
|
-
(l2, idx2) => hoveredL2Id === l2.categoryId && getSubCategories(l2).length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
13014
|
-
"ul",
|
|
13015
|
-
{
|
|
13016
|
-
className: "propeller-menu__list w-64 py-1 flex-shrink-0",
|
|
13017
|
-
"data-level": "3",
|
|
13018
|
-
children: getSubCategories(l2)?.map((l3, idx3) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
13019
|
-
"li",
|
|
13020
|
-
{
|
|
13021
|
-
className: "propeller-menu__item",
|
|
13022
|
-
"data-level": "3",
|
|
13023
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
13024
|
-
"a",
|
|
13025
|
-
{
|
|
13026
|
-
className: "propeller-menu__link block px-4 py-2.5 text-sm text-foreground hover:bg-accent/50 transition-colors",
|
|
13027
|
-
href: getCategoryUrl(l3),
|
|
13028
|
-
onClick: (e) => handleItemClick(l3, e),
|
|
13029
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "propeller-menu__label", children: getCategoryName(l3) })
|
|
13030
|
-
}
|
|
13031
|
-
)
|
|
13032
|
-
},
|
|
13033
|
-
`l3-${l3.categoryId}-${idx3}`
|
|
13034
|
-
))
|
|
13035
|
-
},
|
|
13036
|
-
`l3-col-${l2.categoryId}-${idx2}`
|
|
13037
|
-
) : null
|
|
13038
|
-
) }, `l1-l3col-${l1.categoryId}-${idx}`) : null
|
|
13039
|
-
)
|
|
13040
|
-
] })
|
|
13077
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex max-w-[100vw] overflow-x-auto bg-popover border border-border shadow-lg", children: renderColumns(menuCategories, 0) })
|
|
13041
13078
|
}
|
|
13042
13079
|
) : null,
|
|
13043
13080
|
!isLoading && !hasError && menuCategories.length > 0 && getMenuStyle() === "jumbotron" ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -13048,22 +13085,22 @@ function Menu(rawProps) {
|
|
|
13048
13085
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "propeller-menu__tabs flex items-center border-b border-border", children: menuCategories?.map((l1, idx) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
13049
13086
|
"button",
|
|
13050
13087
|
{
|
|
13051
|
-
className: `propeller-menu__tab px-5 py-3 text-sm font-medium transition-colors border-b-2 ${
|
|
13088
|
+
className: `propeller-menu__tab cursor-pointer px-5 py-3 text-sm font-medium transition-colors border-b-2 ${isOpenAt(0, l1.categoryId) ? "border-primary text-primary" : "border-transparent text-foreground hover:text-primary hover:border-primary/50"}`,
|
|
13052
13089
|
"data-level": "1",
|
|
13053
|
-
"data-active":
|
|
13054
|
-
onMouseEnter: (event) =>
|
|
13090
|
+
"data-active": isOpenAt(0, l1.categoryId) ? "true" : "false",
|
|
13091
|
+
onMouseEnter: (event) => openAt(0, l1.categoryId),
|
|
13055
13092
|
onClick: (e) => handleItemClick(l1, e),
|
|
13056
13093
|
children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "propeller-menu__label", children: getCategoryName(l1) })
|
|
13057
13094
|
},
|
|
13058
13095
|
`l1-${l1.categoryId}-${idx}`
|
|
13059
13096
|
)) }),
|
|
13060
13097
|
menuCategories?.map(
|
|
13061
|
-
(l1, idx) =>
|
|
13098
|
+
(l1, idx) => isOpenAt(0, l1.categoryId) && getSubCategories(l1).length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
13062
13099
|
"div",
|
|
13063
13100
|
{
|
|
13064
13101
|
className: "propeller-menu__panel bg-popover border border-border border-t-0 shadow-lg p-6",
|
|
13065
|
-
onMouseEnter: (event) =>
|
|
13066
|
-
onMouseLeave: (event) =>
|
|
13102
|
+
onMouseEnter: (event) => openAt(0, l1.categoryId),
|
|
13103
|
+
onMouseLeave: (event) => openAt(0, null),
|
|
13067
13104
|
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "propeller-menu__panel-grid grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-6", children: getSubCategories(l1)?.map((l2, idx2) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "propeller-menu__group", "data-level": "2", children: [
|
|
13068
13105
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
13069
13106
|
"a",
|
|
@@ -13090,123 +13127,13 @@ function Menu(rawProps) {
|
|
|
13090
13127
|
]
|
|
13091
13128
|
}
|
|
13092
13129
|
) : null,
|
|
13093
|
-
!isLoading && !hasError && menuCategories.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
13094
|
-
"
|
|
13130
|
+
!isLoading && !hasError && menuCategories.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
13131
|
+
"nav",
|
|
13095
13132
|
{
|
|
13096
|
-
className:
|
|
13097
|
-
|
|
13098
|
-
|
|
13099
|
-
|
|
13100
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center", children: [
|
|
13101
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
13102
|
-
"a",
|
|
13103
|
-
{
|
|
13104
|
-
className: "propeller-menu__link flex-1 px-4 py-3 text-sm font-medium text-foreground",
|
|
13105
|
-
href: getCategoryUrl(l1),
|
|
13106
|
-
onClick: (e) => handleItemClick(l1, e),
|
|
13107
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "propeller-menu__label", children: getCategoryName(l1) })
|
|
13108
|
-
}
|
|
13109
|
-
),
|
|
13110
|
-
getSubCategories(l1).length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
13111
|
-
"button",
|
|
13112
|
-
{
|
|
13113
|
-
type: "button",
|
|
13114
|
-
className: "propeller-menu__toggle px-4 py-3 text-muted-foreground",
|
|
13115
|
-
onClick: (event) => {
|
|
13116
|
-
setExpandedL1(expandedL1 === l1.categoryId ? null : l1.categoryId);
|
|
13117
|
-
},
|
|
13118
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
13119
|
-
"svg",
|
|
13120
|
-
{
|
|
13121
|
-
fill: "none",
|
|
13122
|
-
stroke: "currentColor",
|
|
13123
|
-
viewBox: "0 0 24 24",
|
|
13124
|
-
className: `propeller-menu__chevron w-4 h-4 transition-transform ${expandedL1 === l1.categoryId ? "rotate-180" : ""}`,
|
|
13125
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
13126
|
-
"path",
|
|
13127
|
-
{
|
|
13128
|
-
strokeLinecap: "round",
|
|
13129
|
-
strokeLinejoin: "round",
|
|
13130
|
-
d: "m6 9 6 6 6-6",
|
|
13131
|
-
strokeWidth: 2
|
|
13132
|
-
}
|
|
13133
|
-
)
|
|
13134
|
-
}
|
|
13135
|
-
)
|
|
13136
|
-
}
|
|
13137
|
-
) : null
|
|
13138
|
-
] }),
|
|
13139
|
-
expandedL1 === l1.categoryId && getSubCategories(l1).length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "propeller-menu__list bg-accent/30", "data-level": "2", children: getSubCategories(l1)?.map((l2, idx2) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
13140
|
-
"li",
|
|
13141
|
-
{
|
|
13142
|
-
className: "propeller-menu__item",
|
|
13143
|
-
"data-level": "2",
|
|
13144
|
-
"data-expanded": expandedL2 === l2.categoryId ? "true" : "false",
|
|
13145
|
-
children: [
|
|
13146
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center", children: [
|
|
13147
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
13148
|
-
"a",
|
|
13149
|
-
{
|
|
13150
|
-
className: "propeller-menu__link flex-1 pl-8 pr-4 py-2.5 text-sm text-foreground",
|
|
13151
|
-
href: getCategoryUrl(l2),
|
|
13152
|
-
onClick: (e) => handleItemClick(l2, e),
|
|
13153
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "propeller-menu__label", children: getCategoryName(l2) })
|
|
13154
|
-
}
|
|
13155
|
-
),
|
|
13156
|
-
getSubCategories(l2).length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
13157
|
-
"button",
|
|
13158
|
-
{
|
|
13159
|
-
type: "button",
|
|
13160
|
-
className: "propeller-menu__toggle px-4 py-2.5 text-muted-foreground",
|
|
13161
|
-
onClick: (event) => {
|
|
13162
|
-
setExpandedL2(expandedL2 === l2.categoryId ? null : l2.categoryId);
|
|
13163
|
-
},
|
|
13164
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
13165
|
-
"svg",
|
|
13166
|
-
{
|
|
13167
|
-
fill: "none",
|
|
13168
|
-
stroke: "currentColor",
|
|
13169
|
-
viewBox: "0 0 24 24",
|
|
13170
|
-
className: `propeller-menu__chevron w-3.5 h-3.5 transition-transform ${expandedL2 === l2.categoryId ? "rotate-180" : ""}`,
|
|
13171
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
13172
|
-
"path",
|
|
13173
|
-
{
|
|
13174
|
-
strokeLinecap: "round",
|
|
13175
|
-
strokeLinejoin: "round",
|
|
13176
|
-
d: "m6 9 6 6 6-6",
|
|
13177
|
-
strokeWidth: 2
|
|
13178
|
-
}
|
|
13179
|
-
)
|
|
13180
|
-
}
|
|
13181
|
-
)
|
|
13182
|
-
}
|
|
13183
|
-
) : null
|
|
13184
|
-
] }),
|
|
13185
|
-
expandedL2 === l2.categoryId && getSubCategories(l2).length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "propeller-menu__list bg-accent/20", "data-level": "3", children: getSubCategories(l2)?.map((l3, idx3) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
13186
|
-
"li",
|
|
13187
|
-
{
|
|
13188
|
-
className: "propeller-menu__item",
|
|
13189
|
-
"data-level": "3",
|
|
13190
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
13191
|
-
"a",
|
|
13192
|
-
{
|
|
13193
|
-
className: "propeller-menu__link block pl-12 pr-4 py-2 text-sm text-muted-foreground hover:text-foreground transition-colors",
|
|
13194
|
-
href: getCategoryUrl(l3),
|
|
13195
|
-
onClick: (e) => handleItemClick(l3, e),
|
|
13196
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "propeller-menu__label", children: getCategoryName(l3) })
|
|
13197
|
-
}
|
|
13198
|
-
)
|
|
13199
|
-
},
|
|
13200
|
-
`l3-mobile-${l3.categoryId}-${idx3}`
|
|
13201
|
-
)) }) : null
|
|
13202
|
-
]
|
|
13203
|
-
},
|
|
13204
|
-
`l2-mobile-${l2.categoryId}-${idx2}`
|
|
13205
|
-
)) }) : null
|
|
13206
|
-
]
|
|
13207
|
-
},
|
|
13208
|
-
`l1-mobile-${l1.categoryId}-${idx}`
|
|
13209
|
-
)) }) }) : null
|
|
13133
|
+
className: `propeller-menu__nav ${getMenuStyle() === "accordion" ? "block" : "md:hidden"} ${props.menuClass || ""}`,
|
|
13134
|
+
children: renderAccordion(menuCategories, 0)
|
|
13135
|
+
}
|
|
13136
|
+
) : null
|
|
13210
13137
|
]
|
|
13211
13138
|
}
|
|
13212
13139
|
);
|