@mario_hahn/jumpy-ui 0.11.0 → 0.13.0
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/README.md +11 -1
- package/dist/{chunk-V3XYXQPA.js → chunk-2I6OOQNV.js} +40 -0
- package/dist/index.js +125 -21
- package/dist/theme.js +1 -1
- package/index.d.ts +5 -3
- package/package.json +1 -1
- package/tokens/android/tokens/src/main/kotlin/com/mariohahn/jumpy/tokens/defaultDark/Tokens.kt +1197 -1
- package/tokens/android/tokens/src/main/kotlin/com/mariohahn/jumpy/tokens/defaultLight/Tokens.kt +1197 -1
- package/tokens/android/tokens/src/main/kotlin/com/mariohahn/jumpy/tokens/jumpyDark/Tokens.kt +1197 -1
- package/tokens/android/tokens/src/main/kotlin/com/mariohahn/jumpy/tokens/jumpyLight/Tokens.kt +1197 -1
package/README.md
CHANGED
|
@@ -211,7 +211,7 @@ Jumpy Components als ein gemeinsames UI-Paket.
|
|
|
211
211
|
Starting with 0.5.0, Jumpy UI uses the public npmjs registry. No package token is required to install:
|
|
212
212
|
|
|
213
213
|
```bash
|
|
214
|
-
npm install @mario_hahn/jumpy-ui@^0.
|
|
214
|
+
npm install @mario_hahn/jumpy-ui@^0.13.0
|
|
215
215
|
```
|
|
216
216
|
|
|
217
217
|
The public npm package uses the `@mario_hahn` scope. Older GitHub Packages releases
|
|
@@ -328,6 +328,16 @@ import { JumpAppShell, JumpSideMenu, JumpSideMenuItem, JumpTabBar, JumpTabBarIte
|
|
|
328
328
|
mobile the bar stays empty and blends into the page until that heading scrolls under
|
|
329
329
|
it, then shows a compact centered title. Set `--jumpy-app-shell-gutter` to match your
|
|
330
330
|
content padding. Do not render a second page heading yourself.
|
|
331
|
+
- `topBar.actions` (0.12.0+): `[{ label, icon, onClick | href, variant }]`. Mobile shows
|
|
332
|
+
icon-only buttons (`label` becomes the accessible name); with three or more, the first
|
|
333
|
+
stays visible and the rest go into a "More actions" menu. Desktop shows labelled
|
|
334
|
+
buttons beside the large title, otherwise in the top bar. Prefer it over `trailing`
|
|
335
|
+
for ordinary actions; keep `trailing` for custom content such as an avatar.
|
|
336
|
+
- `topBar.back` (0.13.0+): `{ label, href, as: Link }` for detail pages ("up" to the
|
|
337
|
+
parent). Mobile: "‹ label" replaces the menu button; desktop: link above the large
|
|
338
|
+
title or in the top bar. Returns through history when the previous entry is that
|
|
339
|
+
parent, otherwise follows `href` (deep links stay in the app). Keep the browser's own
|
|
340
|
+
back (button, Safari edge swipe) working: every page change needs a history entry.
|
|
331
341
|
- `JumpTopBar` and `JumpTabBar` also work standalone. Both are sticky and include
|
|
332
342
|
safe-area insets. `JumpTabBarItem` accepts `as` (e.g. Next `Link`), `href`, `icon`,
|
|
333
343
|
numeric or custom `badge` and `selected` (`aria-current="page"`).
|
|
@@ -11853,6 +11853,27 @@ var providerStyles = `
|
|
|
11853
11853
|
flex: 0 0 auto;
|
|
11854
11854
|
}
|
|
11855
11855
|
|
|
11856
|
+
/* Centered title (iOS navigation bar): equal side columns keep the title centered however many buttons sit left or right.
|
|
11857
|
+
Explicit columns so a hidden menu button does not shift the title. */
|
|
11858
|
+
[data-jumpy-theme='true'] [data-jumpy-component='top-bar'][data-title-align='center'] {
|
|
11859
|
+
display: grid;
|
|
11860
|
+
grid-template-columns: minmax(0, 1fr) minmax(0, max-content) minmax(0, 1fr);
|
|
11861
|
+
}
|
|
11862
|
+
|
|
11863
|
+
[data-jumpy-theme='true'] [data-jumpy-component='top-bar'][data-title-align='center'] > [data-jumpy-slot='top-bar-leading'] {
|
|
11864
|
+
grid-column: 1;
|
|
11865
|
+
justify-self: start;
|
|
11866
|
+
}
|
|
11867
|
+
|
|
11868
|
+
[data-jumpy-theme='true'] [data-jumpy-component='top-bar'][data-title-align='center'] > [data-jumpy-slot='top-bar-title'] {
|
|
11869
|
+
grid-column: 2;
|
|
11870
|
+
}
|
|
11871
|
+
|
|
11872
|
+
[data-jumpy-theme='true'] [data-jumpy-component='top-bar'][data-title-align='center'] > [data-jumpy-slot='top-bar-trailing'] {
|
|
11873
|
+
grid-column: 3;
|
|
11874
|
+
justify-self: end;
|
|
11875
|
+
}
|
|
11876
|
+
|
|
11856
11877
|
[data-jumpy-theme='true'] [data-jumpy-component='tab-bar'] [data-jumpy-slot='tab-bar-surface'] {
|
|
11857
11878
|
background-color: var(--jumpy-color-surface-card);
|
|
11858
11879
|
}
|
|
@@ -11883,6 +11904,25 @@ var providerStyles = `
|
|
|
11883
11904
|
backdrop-filter: none;
|
|
11884
11905
|
}
|
|
11885
11906
|
|
|
11907
|
+
[data-jumpy-theme='true'] [data-jumpy-slot='app-shell-back'] {
|
|
11908
|
+
display: inline-flex;
|
|
11909
|
+
-webkit-tap-highlight-color: transparent;
|
|
11910
|
+
}
|
|
11911
|
+
|
|
11912
|
+
/* Only the label truncates; the chevron keeps its size. */
|
|
11913
|
+
[data-jumpy-theme='true'] [data-jumpy-slot='app-shell-back'] > svg {
|
|
11914
|
+
flex: none;
|
|
11915
|
+
}
|
|
11916
|
+
|
|
11917
|
+
[data-jumpy-theme='true'] [data-jumpy-slot='app-shell-back']:hover {
|
|
11918
|
+
color: var(--jumpy-interactive-active-regular-hover-text);
|
|
11919
|
+
}
|
|
11920
|
+
|
|
11921
|
+
[data-jumpy-theme='true'] [data-jumpy-slot='app-shell-back']:focus-visible {
|
|
11922
|
+
outline: var(--jumpy-spacing-outline-medium) solid var(--jumpy-interactive-inactive-regular-focus-focus-ring);
|
|
11923
|
+
outline-offset: var(--jumpy-spacing-outline-small);
|
|
11924
|
+
}
|
|
11925
|
+
|
|
11886
11926
|
[data-jumpy-theme='true'] [data-jumpy-component='tab-bar-item'] {
|
|
11887
11927
|
transition: background-color var(--jumpy-animation-duration-xsmall) var(--jumpy-animation-easing-drift), color var(--jumpy-animation-duration-xsmall) var(--jumpy-animation-easing-drift);
|
|
11888
11928
|
-webkit-tap-highlight-color: transparent;
|
package/dist/index.js
CHANGED
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
textStyleValue,
|
|
29
29
|
themeToCSSVariables,
|
|
30
30
|
useJumpyTheme
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-2I6OOQNV.js";
|
|
32
32
|
import {
|
|
33
33
|
cn
|
|
34
34
|
} from "./chunk-3DBKYKP2.js";
|
|
@@ -1642,7 +1642,7 @@ function JumpPopover({ open, defaultOpen = false, onOpenChange, trigger, childre
|
|
|
1642
1642
|
visible ? /* @__PURE__ */ jsx2("div", { role: "dialog", "data-jumpy-component": "popover", style: { position: "absolute", top: `calc(100% + ${spacingValue(theme, JumpySpacing.smallXS)}px)`, left: 0, zIndex: 30, minWidth: 220, borderRadius: radiusValue(theme, JumpyRadius.large), border: `${borderWidthValue(theme, JumpyBorderWidth.small)}px solid ${theme.color.borderSubtle}`, backgroundColor: theme.color.surfaceCard, color: theme.color.textPrimary, boxShadow: theme.shadow.positiveMedium, padding: spacingValue(theme, JumpySpacing.large) }, children }) : null
|
|
1643
1643
|
] });
|
|
1644
1644
|
}
|
|
1645
|
-
function JumpMenu({ trigger, open, defaultOpen = false, onOpenChange, header, footer, children, className = "", placement = "bottom-start", closeOnSelect = true, ...props }) {
|
|
1645
|
+
function JumpMenu({ trigger, triggerProps = {}, open, defaultOpen = false, onOpenChange, header, footer, children, className = "", placement = "bottom-start", closeOnSelect = true, ...props }) {
|
|
1646
1646
|
const theme = useJumpyTheme();
|
|
1647
1647
|
const [internalOpen, setInternalOpen] = useState2(defaultOpen);
|
|
1648
1648
|
const isOpen = open ?? internalOpen;
|
|
@@ -1748,7 +1748,7 @@ function JumpMenu({ trigger, open, defaultOpen = false, onOpenChange, header, fo
|
|
|
1748
1748
|
refs.domReference.current?.focus?.();
|
|
1749
1749
|
}
|
|
1750
1750
|
return /* @__PURE__ */ jsxs2("span", { "data-jumpy-component": "menu-root", className: cn(className), onPointerDown: markInteractionInside, onFocus: markInteractionInside, style: { display: "inline-flex", ...props.style || {} }, children: [
|
|
1751
|
-
/* @__PURE__ */ jsx2("span", { ref: refs.setReference, "aria-haspopup": "menu", "aria-expanded": isOpen, tabIndex: 0, onClick: () => setOpen(!isOpen), onKeyDown: handleTriggerKeyDown, children: trigger }),
|
|
1751
|
+
/* @__PURE__ */ jsx2("span", { ...triggerProps, ref: refs.setReference, "aria-haspopup": "menu", "aria-expanded": isOpen, tabIndex: 0, onClick: () => setOpen(!isOpen), onKeyDown: handleTriggerKeyDown, children: trigger }),
|
|
1752
1752
|
isOpen ? /* @__PURE__ */ jsx2(JumpyPortal, { children: /* @__PURE__ */ jsxs2(
|
|
1753
1753
|
"div",
|
|
1754
1754
|
{
|
|
@@ -2408,13 +2408,14 @@ function JumpSheet({ visible = false, onVisibleChange, position = "right", title
|
|
|
2408
2408
|
footer ? /* @__PURE__ */ jsx2("div", { style: { padding: spacingValue(theme, JumpySpacing.large), borderTop: `${borderWidthValue(theme, JumpyBorderWidth.small)}px solid ${theme.color.borderSubtle}` }, children: footer }) : null
|
|
2409
2409
|
] }) });
|
|
2410
2410
|
}
|
|
2411
|
-
function JumpyNavigationIcon({ type }) {
|
|
2411
|
+
function JumpyNavigationIcon({ type, size: size2 = 24 }) {
|
|
2412
2412
|
const paths = {
|
|
2413
2413
|
menu: "M4 6h16M4 12h16M4 18h16",
|
|
2414
2414
|
close: "M6 6l12 12M18 6 6 18",
|
|
2415
|
-
back: "M15 18l-6-6 6-6"
|
|
2415
|
+
back: "M15 18l-6-6 6-6",
|
|
2416
|
+
more: "M5 12h.01M12 12h.01M19 12h.01"
|
|
2416
2417
|
};
|
|
2417
|
-
return /* @__PURE__ */ jsx2("svg", { width:
|
|
2418
|
+
return /* @__PURE__ */ jsx2("svg", { width: size2, height: size2, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: type === "more" ? 3 : 2, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", focusable: "false", "data-jumpy-stroke-icon": "true", style: { display: "block" }, children: /* @__PURE__ */ jsx2("path", { d: paths[type] }) });
|
|
2418
2419
|
}
|
|
2419
2420
|
function JumpTopBar({ leading, onMenu, onBack, menuOpen = false, title, subtitle, trailing, sticky = true, titleAlign = "start", titleHidden = false, ariaLabels = {}, className = "", ...props }) {
|
|
2420
2421
|
const theme = useJumpyTheme();
|
|
@@ -2454,20 +2455,13 @@ function JumpTopBar({ leading, onMenu, onBack, menuOpen = false, title, subtitle
|
|
|
2454
2455
|
...props.style || {}
|
|
2455
2456
|
},
|
|
2456
2457
|
children: [
|
|
2457
|
-
leadingNode ? /* @__PURE__ */ jsx2("span", { "data-jumpy-slot": "top-bar-leading", "data-leading": leadingType, style: { marginLeft: -spacingValue(theme, JumpySpacing.smallXS) }, children: leadingNode }) : null,
|
|
2458
|
+
leadingNode ? /* @__PURE__ */ jsx2("span", { "data-jumpy-slot": "top-bar-leading", "data-leading": leadingType, style: { minWidth: 0, maxWidth: "100%", marginLeft: -spacingValue(theme, JumpySpacing.smallXS) }, children: leadingNode }) : null,
|
|
2458
2459
|
/* @__PURE__ */ jsxs2("span", { "data-jumpy-slot": "top-bar-title", "aria-hidden": titleHidden || void 0, style: titleAlign === "center" ? {
|
|
2459
|
-
position: "absolute",
|
|
2460
|
-
left: `calc(${sizeValue(theme, JumpySize.largeXL) + spacingValue(theme, JumpySpacing.large)}px + env(safe-area-inset-left, 0px))`,
|
|
2461
|
-
right: `calc(${sizeValue(theme, JumpySize.largeXL) + spacingValue(theme, JumpySpacing.large)}px + env(safe-area-inset-right, 0px))`,
|
|
2462
|
-
top: "env(safe-area-inset-top, 0px)",
|
|
2463
|
-
bottom: 0,
|
|
2464
2460
|
display: "flex",
|
|
2465
2461
|
flexDirection: "column",
|
|
2466
2462
|
alignItems: "center",
|
|
2467
|
-
justifyContent: "center",
|
|
2468
2463
|
textAlign: "center",
|
|
2469
2464
|
minWidth: 0,
|
|
2470
|
-
pointerEvents: "none",
|
|
2471
2465
|
opacity: titleHidden ? 0 : 1
|
|
2472
2466
|
} : { display: "flex", flexDirection: "column", flex: "1 1 auto", minWidth: 0, opacity: titleHidden ? 0 : 1 }, children: [
|
|
2473
2467
|
title ? /* @__PURE__ */ jsx2("span", { style: { maxWidth: "100%", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", fontSize: titleStyle.fontSize, lineHeight: titleStyle.lineHeight, fontWeight: titleStyle.fontWeight }, children: title }) : null,
|
|
@@ -2564,6 +2558,93 @@ function JumpTabBarItem({ as, icon, badge, selected = false, children, className
|
|
|
2564
2558
|
}
|
|
2565
2559
|
);
|
|
2566
2560
|
}
|
|
2561
|
+
var jumpyLocations = { current: null, previous: null };
|
|
2562
|
+
function jumpyNormalizeUrl(url) {
|
|
2563
|
+
const resolved = new URL(url, window.location.href);
|
|
2564
|
+
const path = resolved.pathname.length > 1 ? resolved.pathname.replace(/\/+$/, "") : resolved.pathname;
|
|
2565
|
+
return `${resolved.origin}${path}${resolved.search === "?" ? "" : resolved.search}`;
|
|
2566
|
+
}
|
|
2567
|
+
function jumpyPreviousEntryIs(href) {
|
|
2568
|
+
const target = jumpyNormalizeUrl(href);
|
|
2569
|
+
const navigation = window.navigation;
|
|
2570
|
+
if (navigation && typeof navigation.entries === "function" && navigation.currentEntry) {
|
|
2571
|
+
if (!navigation.canGoBack) return false;
|
|
2572
|
+
const previous = navigation.entries()[navigation.currentEntry.index - 1];
|
|
2573
|
+
return Boolean(previous?.url) && jumpyNormalizeUrl(previous.url) === target;
|
|
2574
|
+
}
|
|
2575
|
+
return Boolean(jumpyLocations.previous) && jumpyNormalizeUrl(jumpyLocations.previous) === target && window.history.length > 1;
|
|
2576
|
+
}
|
|
2577
|
+
function JumpyAppShellBack({ back, variant, ariaLabels }) {
|
|
2578
|
+
const theme = useJumpyTheme();
|
|
2579
|
+
const Component = back.as || (back.href ? "a" : "button");
|
|
2580
|
+
const textStyle = textStyleValue(theme, variant === "inline" ? JumpyTextStyle.bodySmallEmphasized : JumpyTextStyle.bodyMedium);
|
|
2581
|
+
const accessibleName = ariaLabels.backTo ? ariaLabels.backTo(back.label) : `Back to ${back.label}`;
|
|
2582
|
+
function handleClick(event) {
|
|
2583
|
+
back.onClick?.(event);
|
|
2584
|
+
if (event.defaultPrevented || !back.href || back.history === false) return;
|
|
2585
|
+
if (event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
|
|
2586
|
+
if (!jumpyPreviousEntryIs(back.href)) return;
|
|
2587
|
+
event.preventDefault();
|
|
2588
|
+
window.history.back();
|
|
2589
|
+
}
|
|
2590
|
+
return /* @__PURE__ */ jsxs2(
|
|
2591
|
+
Component,
|
|
2592
|
+
{
|
|
2593
|
+
href: back.href,
|
|
2594
|
+
type: Component === "button" ? "button" : void 0,
|
|
2595
|
+
"aria-label": accessibleName,
|
|
2596
|
+
"data-jumpy-slot": "app-shell-back",
|
|
2597
|
+
"data-variant": variant,
|
|
2598
|
+
onClick: handleClick,
|
|
2599
|
+
style: {
|
|
2600
|
+
boxSizing: "border-box",
|
|
2601
|
+
alignItems: "center",
|
|
2602
|
+
gap: spacingValue(theme, JumpySpacing.small4XS),
|
|
2603
|
+
maxWidth: "100%",
|
|
2604
|
+
minWidth: 0,
|
|
2605
|
+
minHeight: variant === "inline" ? void 0 : sizeValue(theme, JumpySize.largeXL),
|
|
2606
|
+
margin: variant === "inline" ? `0 0 ${spacingValue(theme, JumpySpacing.small3XS)}px ${-spacingValue(theme, JumpySpacing.small3XS)}px` : 0,
|
|
2607
|
+
padding: variant === "inline" ? 0 : `0 ${spacingValue(theme, JumpySpacing.smallXS)}px 0 0`,
|
|
2608
|
+
border: 0,
|
|
2609
|
+
borderRadius: radiusValue(theme, JumpyRadius.small),
|
|
2610
|
+
background: "transparent",
|
|
2611
|
+
color: "var(--jumpy-interactive-active-regular-default-text)",
|
|
2612
|
+
textDecoration: "none",
|
|
2613
|
+
cursor: "pointer",
|
|
2614
|
+
fontFamily: theme.fontFamily.familyBase,
|
|
2615
|
+
fontSize: textStyle.fontSize,
|
|
2616
|
+
lineHeight: textStyle.lineHeight,
|
|
2617
|
+
fontWeight: textStyle.fontWeight
|
|
2618
|
+
},
|
|
2619
|
+
children: [
|
|
2620
|
+
/* @__PURE__ */ jsx2(JumpyNavigationIcon, { type: "back", size: variant === "inline" ? 18 : 24 }),
|
|
2621
|
+
/* @__PURE__ */ jsx2("span", { style: { minWidth: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: back.label })
|
|
2622
|
+
]
|
|
2623
|
+
}
|
|
2624
|
+
);
|
|
2625
|
+
}
|
|
2626
|
+
function JumpyAppShellActions({ actions, variant, ariaLabels }) {
|
|
2627
|
+
const theme = useJumpyTheme();
|
|
2628
|
+
if (!actions.length) return null;
|
|
2629
|
+
const gap = spacingValue(theme, JumpySpacing.smallXS);
|
|
2630
|
+
if (variant === "full") {
|
|
2631
|
+
return /* @__PURE__ */ jsx2("span", { "data-jumpy-slot": "app-shell-actions", "data-variant": "full", style: { alignItems: "center", gap, flexWrap: "wrap", justifyContent: "flex-end" }, children: actions.map((action, index) => /* @__PURE__ */ jsx2(JumpButton, { as: action.href ? "a" : void 0, href: action.href, variant: action.variant || "secondary", leadingIcon: action.icon, disabled: action.disabled, onClick: action.onClick, children: action.label }, action.id ?? index)) });
|
|
2632
|
+
}
|
|
2633
|
+
const visible = actions.length > 2 ? actions.slice(0, 1) : actions;
|
|
2634
|
+
const overflow = actions.length > 2 ? actions.slice(1) : [];
|
|
2635
|
+
return /* @__PURE__ */ jsxs2("span", { "data-jumpy-slot": "app-shell-actions", "data-variant": "compact", style: { alignItems: "center", gap }, children: [
|
|
2636
|
+
visible.map((action, index) => /* @__PURE__ */ jsx2(JumpIconButton, { as: action.href ? "a" : void 0, href: action.href, variant: action.variant === "primary" ? "primary" : "borderless", "aria-label": action.label, disabled: action.disabled, onClick: action.onClick, children: action.icon }, action.id ?? index)),
|
|
2637
|
+
overflow.length ? /* @__PURE__ */ jsx2(
|
|
2638
|
+
JumpMenu,
|
|
2639
|
+
{
|
|
2640
|
+
placement: "bottom-end",
|
|
2641
|
+
triggerProps: { role: "button", "aria-label": ariaLabels.moreActions || "More actions", "data-jumpy-slot": "app-shell-actions-more" },
|
|
2642
|
+
trigger: /* @__PURE__ */ jsx2(JumpIconButton, { as: "span", variant: "borderless", tabIndex: -1, "aria-hidden": "true", children: /* @__PURE__ */ jsx2(JumpyNavigationIcon, { type: "more" }) }),
|
|
2643
|
+
children: overflow.map((action, index) => /* @__PURE__ */ jsx2(JumpMenuItem, { as: action.href ? "a" : void 0, href: action.href, leading: action.icon, disabled: action.disabled, onClick: action.onClick, children: action.label }, action.id ?? index))
|
|
2644
|
+
}
|
|
2645
|
+
) : null
|
|
2646
|
+
] });
|
|
2647
|
+
}
|
|
2567
2648
|
function JumpAppShell({ brand, navigation, sidebarFooter, topBar, tabBar, hideTabBar = false, breakpoint = 1024, sidebarWidth = 256, navigationOpen, defaultNavigationOpen = false, onNavigationOpenChange, ariaLabels = {}, children, className = "", ...props }) {
|
|
2568
2649
|
const theme = useJumpyTheme();
|
|
2569
2650
|
const shellId = useId();
|
|
@@ -2575,11 +2656,19 @@ function JumpAppShell({ brand, navigation, sidebarFooter, topBar, tabBar, hideTa
|
|
|
2575
2656
|
const showDrawer = isOpen || drawerMounted;
|
|
2576
2657
|
const closing = drawerMounted && !isOpen;
|
|
2577
2658
|
const wasShown = useRef2(showDrawer);
|
|
2578
|
-
const { desktop:
|
|
2659
|
+
const { desktop: topBarDesktop = false, leading, largeTitle = false, actions = [], back, ...topBarProps } = topBar || {};
|
|
2579
2660
|
const showLargeTitle = largeTitle && Boolean(topBarProps.title);
|
|
2661
|
+
const hasBack = Boolean(back?.label);
|
|
2662
|
+
const topBarOnDesktop = topBarDesktop || !showLargeTitle && (actions.length > 0 || hasBack);
|
|
2580
2663
|
const largeTitleRef = useRef2(null);
|
|
2581
2664
|
const [largeTitleCovered, setLargeTitleCovered] = useState2(false);
|
|
2582
|
-
const resolvedLeading = leading ?? (navigation ? "menu" : void 0);
|
|
2665
|
+
const resolvedLeading = hasBack ? /* @__PURE__ */ jsx2(JumpyAppShellBack, { back, variant: "bar", ariaLabels }) : leading ?? (navigation ? "menu" : void 0);
|
|
2666
|
+
useEffect2(() => {
|
|
2667
|
+
const href = window.location.href;
|
|
2668
|
+
if (jumpyLocations.current === href) return;
|
|
2669
|
+
jumpyLocations.previous = jumpyLocations.current;
|
|
2670
|
+
jumpyLocations.current = href;
|
|
2671
|
+
});
|
|
2583
2672
|
const shell = `[data-jumpy-app-shell="${shellId}"]`;
|
|
2584
2673
|
const width = typeof sidebarWidth === "number" ? `${sidebarWidth}px` : sidebarWidth;
|
|
2585
2674
|
function setOpen(next) {
|
|
@@ -2636,9 +2725,15 @@ function JumpAppShell({ brand, navigation, sidebarFooter, topBar, tabBar, hideTa
|
|
|
2636
2725
|
const shellStyles = `
|
|
2637
2726
|
${shell} { grid-template-columns: minmax(0, 1fr); }
|
|
2638
2727
|
${shell} > [data-jumpy-slot='app-shell-sidebar'] { display: none; }
|
|
2728
|
+
${shell} [data-jumpy-slot='app-shell-actions'][data-variant='compact'] { display: inline-flex; }
|
|
2729
|
+
${shell} [data-jumpy-slot='app-shell-actions'][data-variant='full'] { display: none; }
|
|
2730
|
+
${shell} [data-jumpy-slot='app-shell-back'][data-variant='inline'] { display: none; }
|
|
2639
2731
|
@media (min-width: ${breakpoint}px) {
|
|
2640
2732
|
${shell} { grid-template-columns: ${width} minmax(0, 1fr); }
|
|
2641
2733
|
${shell} > [data-jumpy-slot='app-shell-sidebar'] { display: flex; }
|
|
2734
|
+
${shell} [data-jumpy-slot='app-shell-actions'][data-variant='compact'] { display: none; }
|
|
2735
|
+
${shell} [data-jumpy-slot='app-shell-actions'][data-variant='full'] { display: inline-flex; }
|
|
2736
|
+
${shell} [data-jumpy-slot='app-shell-back'][data-variant='inline'] { display: flex; width: fit-content; }
|
|
2642
2737
|
${shell} > [data-jumpy-slot='app-shell-body'] > [data-jumpy-component='tab-bar'] { display: none; }
|
|
2643
2738
|
${shell} > [data-jumpy-slot='app-shell-body'] > [data-jumpy-component='top-bar'][data-mobile-only='true'] { display: none; }
|
|
2644
2739
|
${shell} > [data-jumpy-slot='app-shell-body'] > [data-jumpy-component='top-bar'] > [data-leading='menu'] { display: none; }
|
|
@@ -2653,9 +2748,14 @@ ${shell} > [data-jumpy-slot='app-shell-sidebar'] { display: none; }
|
|
|
2653
2748
|
onMenu: () => setOpen(true),
|
|
2654
2749
|
title: topBarProps.title ?? brand,
|
|
2655
2750
|
subtitle: showLargeTitle ? void 0 : topBarProps.subtitle,
|
|
2656
|
-
titleAlign: showLargeTitle ? "center" : topBarProps.titleAlign,
|
|
2751
|
+
titleAlign: showLargeTitle || hasBack ? "center" : topBarProps.titleAlign,
|
|
2657
2752
|
titleHidden: showLargeTitle ? !largeTitleCovered : topBarProps.titleHidden,
|
|
2658
2753
|
"data-large-title": showLargeTitle ? "true" : void 0,
|
|
2754
|
+
trailing: actions.length || topBarProps.trailing ? /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
2755
|
+
/* @__PURE__ */ jsx2(JumpyAppShellActions, { actions, variant: "compact", ariaLabels }),
|
|
2756
|
+
showLargeTitle ? null : /* @__PURE__ */ jsx2(JumpyAppShellActions, { actions, variant: "full", ariaLabels }),
|
|
2757
|
+
topBarProps.trailing
|
|
2758
|
+
] }) : void 0,
|
|
2659
2759
|
ariaLabels: { menu: ariaLabels.openNavigation, back: ariaLabels.back, ...topBarProps.ariaLabels || {} }
|
|
2660
2760
|
}
|
|
2661
2761
|
);
|
|
@@ -2703,10 +2803,14 @@ ${shell} > [data-jumpy-slot='app-shell-sidebar'] { display: none; }
|
|
|
2703
2803
|
/* @__PURE__ */ jsxs2("div", { "data-jumpy-slot": "app-shell-body", style: { display: "flex", flexDirection: "column", minWidth: 0, minHeight: "100dvh" }, children: [
|
|
2704
2804
|
topBar !== null ? topBarNode : null,
|
|
2705
2805
|
/* @__PURE__ */ jsxs2("main", { "data-jumpy-slot": "app-shell-content", style: { flex: 1, minWidth: 0 }, children: [
|
|
2706
|
-
showLargeTitle ? /* @__PURE__ */
|
|
2707
|
-
/* @__PURE__ */
|
|
2708
|
-
|
|
2709
|
-
|
|
2806
|
+
showLargeTitle ? /* @__PURE__ */ jsx2("div", { "data-jumpy-slot": "app-shell-large-title", style: { padding: `${spacingValue(theme, JumpySpacing.smallXS)}px calc(var(--jumpy-app-shell-gutter, ${spacingValue(theme, JumpySpacing.large)}px) + env(safe-area-inset-right, 0px)) 0 calc(var(--jumpy-app-shell-gutter, ${spacingValue(theme, JumpySpacing.large)}px) + env(safe-area-inset-left, 0px))` }, children: /* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "flex-end", justifyContent: "space-between", gap: spacingValue(theme, JumpySpacing.large), flexWrap: "wrap" }, children: [
|
|
2807
|
+
/* @__PURE__ */ jsxs2("div", { style: { minWidth: 0 }, children: [
|
|
2808
|
+
hasBack ? /* @__PURE__ */ jsx2(JumpyAppShellBack, { back, variant: "inline", ariaLabels }) : null,
|
|
2809
|
+
/* @__PURE__ */ jsx2("h1", { ref: largeTitleRef, style: { margin: 0, ...textStyleValue(theme, JumpyTextStyle.displaySmallEmphasized), overflowWrap: "anywhere" }, children: topBarProps.title }),
|
|
2810
|
+
topBarProps.subtitle ? /* @__PURE__ */ jsx2("p", { style: { margin: `${spacingValue(theme, JumpySpacing.small4XS)}px 0 0`, color: "var(--jumpy-color-text-secondary)", ...textStyleValue(theme, JumpyTextStyle.bodyMedium) }, children: topBarProps.subtitle }) : null
|
|
2811
|
+
] }),
|
|
2812
|
+
/* @__PURE__ */ jsx2(JumpyAppShellActions, { actions, variant: "full", ariaLabels })
|
|
2813
|
+
] }) }) : null,
|
|
2710
2814
|
children
|
|
2711
2815
|
] }),
|
|
2712
2816
|
tabBar && !hideTabBar ? tabBar : null
|
package/dist/theme.js
CHANGED
package/index.d.ts
CHANGED
|
@@ -71,7 +71,7 @@ export declare function JumpSkeletonLoader(props: HTMLAttributes<HTMLElement> &
|
|
|
71
71
|
export declare const JumpSearchField: import('react').ForwardRefExoticComponent<Omit<InputHTMLAttributes<HTMLInputElement>, 'type'> & { label?: string } & import('react').RefAttributes<HTMLInputElement>>
|
|
72
72
|
export declare function JumpTooltip(props: HTMLAttributes<HTMLSpanElement> & { content: ReactNode; children: ReactNode }): ReactNode
|
|
73
73
|
export declare function JumpPopover(props: HTMLAttributes<HTMLSpanElement> & { open?: boolean; defaultOpen?: boolean; onOpenChange?: (open: boolean) => void; trigger: ReactNode; children: ReactNode }): ReactNode
|
|
74
|
-
export declare function JumpMenu(props: HTMLAttributes<HTMLDivElement> & { trigger: ReactNode; open?: boolean; defaultOpen?: boolean; onOpenChange?: (open: boolean) => void; closeOnSelect?: boolean; header?: ReactNode; footer?: ReactNode; placement?: 'top' | 'top-start' | 'top-end' | 'right' | 'right-start' | 'right-end' | 'bottom' | 'bottom-start' | 'bottom-end' | 'left' | 'left-start' | 'left-end'; children: ReactNode }): ReactNode
|
|
74
|
+
export declare function JumpMenu(props: HTMLAttributes<HTMLDivElement> & { trigger: ReactNode; triggerProps?: HTMLAttributes<HTMLSpanElement> & Record<string, unknown>; open?: boolean; defaultOpen?: boolean; onOpenChange?: (open: boolean) => void; closeOnSelect?: boolean; header?: ReactNode; footer?: ReactNode; placement?: 'top' | 'top-start' | 'top-end' | 'right' | 'right-start' | 'right-end' | 'bottom' | 'bottom-start' | 'bottom-end' | 'left' | 'left-start' | 'left-end'; children: ReactNode }): ReactNode
|
|
75
75
|
export declare function JumpMenuItem(props: HTMLAttributes<HTMLElement> & { as?: ElementTag; children: ReactNode; selected?: boolean; disabled?: boolean; readOnly?: boolean; focusedView?: boolean; leading?: ReactNode; trailing?: ReactNode; metadata?: ReactNode; description?: ReactNode; slots?: JumpListItemSlots; nestedMenu?: ReactNode }): ReactNode
|
|
76
76
|
export type JumpToggleButtonValue = string | number
|
|
77
77
|
export declare function JumpToggleButton(props: Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'onChange'> & { as?: ElementTag; selected?: boolean; value?: JumpToggleButtonValue; onChange?: (selected: boolean) => void; leading?: ReactNode | ((state: { selected: boolean }) => ReactNode); children?: ReactNode }): ReactNode
|
|
@@ -116,8 +116,10 @@ export declare function JumpTopBar(props: JumpTopBarProps): ReactNode
|
|
|
116
116
|
export declare function JumpTabBar(props: HTMLAttributes<HTMLElement> & { children: ReactNode }): ReactNode
|
|
117
117
|
export type JumpTabBarItemProps = { as?: ElementType; href?: string; icon?: ReactNode; badge?: ReactNode | number; selected?: boolean; children: ReactNode; className?: string; style?: CSSProperties } & Record<string, unknown>
|
|
118
118
|
export declare function JumpTabBarItem(props: JumpTabBarItemProps): ReactNode
|
|
119
|
-
export type
|
|
120
|
-
export
|
|
119
|
+
export type JumpAppShellAction = { id?: string; label: string; icon: ReactNode; onClick?: (event: import('react').MouseEvent<HTMLElement>) => void; href?: string; variant?: 'primary' | 'secondary' | 'tertiary' | 'borderless'; disabled?: boolean }
|
|
120
|
+
export type JumpAppShellBack = { label: string; href?: string; as?: ElementType; onClick?: (event: import('react').MouseEvent<HTMLElement>) => void; history?: boolean }
|
|
121
|
+
export type JumpAppShellTopBar = Omit<JumpTopBarProps, 'onMenu' | 'menuOpen'> & { desktop?: boolean; largeTitle?: boolean; actions?: JumpAppShellAction[]; back?: JumpAppShellBack }
|
|
122
|
+
export declare function JumpAppShell(props: HTMLAttributes<HTMLDivElement> & { brand?: ReactNode; navigation?: ReactNode; sidebarFooter?: ReactNode; topBar?: JumpAppShellTopBar | null; tabBar?: ReactNode; hideTabBar?: boolean; breakpoint?: number; sidebarWidth?: number | string; navigationOpen?: boolean; defaultNavigationOpen?: boolean; onNavigationOpenChange?: (open: boolean) => void; ariaLabels?: { navigation?: string; openNavigation?: string; closeNavigation?: string; back?: string; backTo?: (label: string) => string; moreActions?: string }; children?: ReactNode }): ReactNode
|
|
121
123
|
export declare function JumpSectionHeader(props: HTMLAttributes<HTMLElement> & { as?: ElementTag; variant?: 'regular' | 'prominent'; description?: ReactNode; children: ReactNode }): ReactNode
|
|
122
124
|
export declare function JumpSectionFooter(props: HTMLAttributes<HTMLElement> & { as?: ElementTag; children: ReactNode }): ReactNode
|
|
123
125
|
export declare function JumpTag(props: HTMLAttributes<HTMLSpanElement> & { size?: 'small' | 'medium'; status?: 'regular' | 'positive' | 'warning' | 'alarm'; disabled?: boolean; children: ReactNode }): ReactNode
|