@cueplusplus/ui 0.1.0 → 0.2.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/CHANGELOG.md +684 -0
- package/dist/brand/_chassis.d.ts +54 -0
- package/dist/brand/_chassis.js +81 -0
- package/dist/brand/_geometry.js +41 -0
- package/dist/brand/cue-logotype.d.ts +29 -0
- package/dist/brand/cue-logotype.js +60 -0
- package/dist/brand/cue-mark.d.ts +30 -0
- package/dist/brand/cue-mark.js +61 -0
- package/dist/brand/index.d.ts +5 -0
- package/dist/brand/plussie.d.ts +67 -0
- package/dist/brand/plussie.js +125 -0
- package/dist/chat/agent-pile.js +1 -1
- package/dist/chat/ask-box.js +2 -2
- package/dist/chat/delegation-card.js +1 -1
- package/dist/chat/message.js +2 -2
- package/dist/chrome/_edge-scroller.d.ts +45 -0
- package/dist/chrome/_edge-scroller.js +138 -0
- package/dist/chrome/_glyphs.js +19 -1
- package/dist/chrome/_tabs-scroll.d.ts +12 -7
- package/dist/chrome/_tabs-scroll.js +12 -7
- package/dist/chrome/app-bar.d.ts +103 -0
- package/dist/chrome/app-bar.js +175 -0
- package/dist/chrome/app-shell.d.ts +125 -0
- package/dist/chrome/app-shell.js +167 -0
- package/dist/chrome/footer.d.ts +75 -0
- package/dist/chrome/footer.js +68 -0
- package/dist/chrome/index.d.ts +5 -1
- package/dist/chrome/index.js +4 -1
- package/dist/chrome/navigation-menu.js +1 -1
- package/dist/chrome/page-shell.d.ts +1 -1
- package/dist/chrome/page-shell.js +15 -5
- package/dist/chrome/segmented-control.d.ts +19 -0
- package/dist/chrome/segmented-control.js +40 -21
- package/dist/chrome/tabs.js +21 -65
- package/dist/chrome/toolbar.d.ts +22 -0
- package/dist/chrome/toolbar.js +26 -5
- package/dist/configurator/_overrides.js +4 -2
- package/dist/configurator/configurator.js +1 -1
- package/dist/configurator/panel-sections.js +10 -4
- package/dist/dmx/channel-matrix.js +1 -1
- package/dist/forms/otp-field.js +1 -1
- package/dist/index.d.ts +15 -6
- package/dist/index.js +15 -9
- package/dist/instruments/data-table.js +1 -1
- package/dist/layout/carousel.js +1 -1
- package/dist/layout/container.d.ts +1 -1
- package/dist/layout/container.js +6 -3
- package/dist/layout/index.d.ts +3 -3
- package/dist/layout/index.js +3 -3
- package/dist/layout/pagination.js +1 -1
- package/dist/layout/sidebar.d.ts +23 -3
- package/dist/layout/sidebar.js +18 -7
- package/dist/midi/spectrum-visualizer.js +1 -1
- package/dist/midi/timeline-ruler.js +1 -1
- package/dist/overlays/command-palette.js +1 -1
- package/dist/overlays/dialog.js +1 -1
- package/dist/overlays/dropdown-menu.js +2 -2
- package/dist/overlays/hover-card.js +1 -1
- package/dist/overlays/index.js +1 -1
- package/dist/overlays/popover.js +1 -1
- package/dist/overlays/sheet.js +1 -1
- package/dist/overlays/toast.js +1 -1
- package/dist/primitives/index.d.ts +1 -1
- package/dist/primitives/index.js +1 -1
- package/dist/primitives/status-dot.d.ts +7 -0
- package/dist/primitives/status-dot.js +8 -1
- package/dist/styles.css +47 -1
- package/dist/system/density.d.ts +4 -1
- package/dist/system/density.js +12 -4
- package/dist/system/index.d.ts +2 -2
- package/dist/system/portal.d.ts +5 -5
- package/dist/system/portal.js +11 -6
- package/dist/system/prepaint.d.ts +15 -8
- package/dist/system/prepaint.js +26 -9
- package/dist/system/theme-provider.d.ts +36 -10
- package/dist/system/theme-provider.js +56 -18
- package/dist/system/use-density.d.ts +3 -3
- package/dist/system/use-density.js +16 -6
- package/dist/system/use-theme.d.ts +4 -2
- package/dist/system/use-theme.js +4 -2
- package/dist/theming/_presets.js +80 -5
- package/dist/theming/create-theme.js +13 -4
- package/package.json +4 -3
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../lib/cn.js";
|
|
3
|
+
import { MenuGlyph } from "./_glyphs.js";
|
|
4
|
+
import { Sidebar } from "../layout/sidebar.js";
|
|
5
|
+
import { CrossGlyph } from "../overlays/_glyphs.js";
|
|
6
|
+
import { Drawer } from "../overlays/drawer.js";
|
|
7
|
+
import { IconButton } from "../primitives/icon-button.js";
|
|
8
|
+
import * as React from "react";
|
|
9
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
+
//#region src/chrome/app-shell.tsx
|
|
11
|
+
const AppShellContext = React.createContext({
|
|
12
|
+
navOpen: false,
|
|
13
|
+
setNavOpen: () => {}
|
|
14
|
+
});
|
|
15
|
+
/**
|
|
16
|
+
* The console frame: title bar, navigation, work area, status bar — one
|
|
17
|
+
* viewport tall, with exactly one thing scrolling.
|
|
18
|
+
*
|
|
19
|
+
* Every console screen in this system is the same five parts in the same
|
|
20
|
+
* arrangement, and the value here is not the parts (they already exist as
|
|
21
|
+
* `TitleBar`, `Sidebar`, `Toolbar` and `StatusBar`) but the arithmetic between
|
|
22
|
+
* them: `h-dvh` on the frame rather than `min-h-dvh`, an unbroken `min-h-0`
|
|
23
|
+
* chain from the frame down to the scroller, `min-w-0` on the content column,
|
|
24
|
+
* and a scroller that is not the document. Get one of those wrong and the
|
|
25
|
+
* status bar leaves the screen or the navigation column gets shoved off the
|
|
26
|
+
* side; the shell exists so no page has to get them right again.
|
|
27
|
+
*
|
|
28
|
+
* The bars are ordinary children — `TitleBar` and `StatusBar` are already
|
|
29
|
+
* `shrink-0` and need no wrapper — so a shell reads as the page's outline.
|
|
30
|
+
*
|
|
31
|
+
* This is also the only component in the library with a viewport breakpoint:
|
|
32
|
+
* below `md` the navigation column becomes a drawer and a trigger appears in
|
|
33
|
+
* the bar. See {@link AppShellSidebar} for the ruling.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* <AppShell.Root>
|
|
37
|
+
* <TitleBar center="main-stage.cue" actions={<Chip tone="ok">live</Chip>}>
|
|
38
|
+
* <AppShell.NavTrigger />
|
|
39
|
+
* <Eyebrow>CUE++</Eyebrow>
|
|
40
|
+
* </TitleBar>
|
|
41
|
+
* <AppShell.Body>
|
|
42
|
+
* <AppShell.Sidebar aria-label="Console" drawerTitle="Console">
|
|
43
|
+
* <Sidebar.Section label="Show">
|
|
44
|
+
* <Sidebar.Item icon={List} active>Cues</Sidebar.Item>
|
|
45
|
+
* </Sidebar.Section>
|
|
46
|
+
* </AppShell.Sidebar>
|
|
47
|
+
* <AppShell.Content>
|
|
48
|
+
* <Toolbar.Root aria-label="Playback"><Toolbar.Button icon={Play}>Go</Toolbar.Button></Toolbar.Root>
|
|
49
|
+
* <AppShell.Scroller><Panel>…</Panel></AppShell.Scroller>
|
|
50
|
+
* </AppShell.Content>
|
|
51
|
+
* <AppShell.Aside aria-label="Inspector">…</AppShell.Aside>
|
|
52
|
+
* </AppShell.Body>
|
|
53
|
+
* <StatusBar><StatusBar.Item tone="ok">Art-Net</StatusBar.Item></StatusBar>
|
|
54
|
+
* </AppShell.Root>
|
|
55
|
+
*/
|
|
56
|
+
const AppShell = {
|
|
57
|
+
Root: React.forwardRef(function AppShellRoot({ className, navOpen: navOpenProp, defaultNavOpen = false, onNavOpenChange, ...elementProps }, ref) {
|
|
58
|
+
const [uncontrolled, setUncontrolled] = React.useState(defaultNavOpen);
|
|
59
|
+
const navOpen = navOpenProp ?? uncontrolled;
|
|
60
|
+
const setNavOpen = React.useCallback((open) => {
|
|
61
|
+
if (navOpenProp === void 0) setUncontrolled(open);
|
|
62
|
+
onNavOpenChange?.(open);
|
|
63
|
+
}, [navOpenProp, onNavOpenChange]);
|
|
64
|
+
const context = React.useMemo(() => ({
|
|
65
|
+
navOpen,
|
|
66
|
+
setNavOpen
|
|
67
|
+
}), [navOpen, setNavOpen]);
|
|
68
|
+
return /* @__PURE__ */ jsx(AppShellContext.Provider, {
|
|
69
|
+
value: context,
|
|
70
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
71
|
+
ref,
|
|
72
|
+
"data-slot": "app-shell",
|
|
73
|
+
className: cn("relative flex h-dvh flex-col overflow-clip bg-bg text-fg", className),
|
|
74
|
+
...elementProps
|
|
75
|
+
})
|
|
76
|
+
});
|
|
77
|
+
}),
|
|
78
|
+
Body: React.forwardRef(function AppShellBody({ className, ...elementProps }, ref) {
|
|
79
|
+
return /* @__PURE__ */ jsx("div", {
|
|
80
|
+
ref,
|
|
81
|
+
"data-slot": "app-shell-body",
|
|
82
|
+
className: cn("flex min-h-0 min-w-0 flex-1", className),
|
|
83
|
+
...elementProps
|
|
84
|
+
});
|
|
85
|
+
}),
|
|
86
|
+
Sidebar: React.forwardRef(function AppShellSidebar({ className, drawerClassName, drawerTitle = "Navigation", closeLabel = "Close navigation", collapsible = true, landmark = "navigation", "aria-label": ariaLabel = "Navigation", children, ...sidebarProps }, ref) {
|
|
87
|
+
const { navOpen, setNavOpen } = React.useContext(AppShellContext);
|
|
88
|
+
const DrawerLandmark = landmark === "complementary" ? "aside" : "nav";
|
|
89
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs(Sidebar.Root, {
|
|
90
|
+
ref,
|
|
91
|
+
"data-slot": "app-shell-sidebar",
|
|
92
|
+
"aria-label": ariaLabel,
|
|
93
|
+
landmark,
|
|
94
|
+
className: cn("hidden md:flex", className),
|
|
95
|
+
...sidebarProps,
|
|
96
|
+
children: [children, collapsible ? /* @__PURE__ */ jsx(Sidebar.Rail, {}) : null]
|
|
97
|
+
}), /* @__PURE__ */ jsx(Drawer.Root, {
|
|
98
|
+
swipeDirection: "left",
|
|
99
|
+
open: navOpen,
|
|
100
|
+
onOpenChange: setNavOpen,
|
|
101
|
+
children: /* @__PURE__ */ jsxs(Drawer.Content, {
|
|
102
|
+
grabHandle: false,
|
|
103
|
+
className: cn("w-[min(18rem,calc(100vw-3rem))]", drawerClassName),
|
|
104
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
105
|
+
className: "flex shrink-0 items-center justify-between gap-(--cue-space-3)",
|
|
106
|
+
children: [/* @__PURE__ */ jsx(Drawer.Title, { children: drawerTitle }), /* @__PURE__ */ jsx(Drawer.Close, { render: /* @__PURE__ */ jsx(IconButton, {
|
|
107
|
+
"aria-label": closeLabel,
|
|
108
|
+
icon: CrossGlyph,
|
|
109
|
+
size: "sm"
|
|
110
|
+
}) })]
|
|
111
|
+
}), /* @__PURE__ */ jsx(DrawerLandmark, {
|
|
112
|
+
"data-slot": "app-shell-nav-drawer",
|
|
113
|
+
"aria-label": ariaLabel,
|
|
114
|
+
className: "flex min-h-0 flex-1 flex-col gap-(--cue-space-4) overflow-y-auto",
|
|
115
|
+
children
|
|
116
|
+
})]
|
|
117
|
+
})
|
|
118
|
+
})] });
|
|
119
|
+
}),
|
|
120
|
+
NavTrigger: React.forwardRef(function AppShellNavTrigger({ className, label = "Open navigation", icon = MenuGlyph, size = "md", onClick, ...elementProps }, ref) {
|
|
121
|
+
const { navOpen, setNavOpen } = React.useContext(AppShellContext);
|
|
122
|
+
return /* @__PURE__ */ jsx(IconButton, {
|
|
123
|
+
ref,
|
|
124
|
+
"data-slot": "app-shell-nav-trigger",
|
|
125
|
+
"aria-label": label,
|
|
126
|
+
"aria-expanded": navOpen,
|
|
127
|
+
icon,
|
|
128
|
+
size,
|
|
129
|
+
className: cn("shrink-0 md:hidden", className),
|
|
130
|
+
onClick: (event) => {
|
|
131
|
+
onClick?.(event);
|
|
132
|
+
if (!event.defaultPrevented) setNavOpen(true);
|
|
133
|
+
},
|
|
134
|
+
...elementProps
|
|
135
|
+
});
|
|
136
|
+
}),
|
|
137
|
+
Content: React.forwardRef(function AppShellContent({ className, main = true, ...elementProps }, ref) {
|
|
138
|
+
return /* @__PURE__ */ jsx(main ? "main" : "div", {
|
|
139
|
+
ref,
|
|
140
|
+
"data-slot": "app-shell-content",
|
|
141
|
+
className: cn("flex min-h-0 min-w-0 flex-1 flex-col", className),
|
|
142
|
+
...elementProps
|
|
143
|
+
});
|
|
144
|
+
}),
|
|
145
|
+
Scroller: React.forwardRef(function AppShellScroller({ className, padded = true, ...elementProps }, ref) {
|
|
146
|
+
return /* @__PURE__ */ jsx("div", {
|
|
147
|
+
ref,
|
|
148
|
+
"data-slot": "app-shell-scroller",
|
|
149
|
+
className: cn("min-h-0 min-w-0 flex-1 overflow-y-auto", padded ? "p-(--cue-space-5)" : null, className),
|
|
150
|
+
...elementProps
|
|
151
|
+
});
|
|
152
|
+
}),
|
|
153
|
+
Aside: React.forwardRef(function AppShellAside({ className, width = "18rem", style, ...elementProps }, ref) {
|
|
154
|
+
return /* @__PURE__ */ jsx("aside", {
|
|
155
|
+
ref,
|
|
156
|
+
"data-slot": "app-shell-aside",
|
|
157
|
+
className: cn("flex shrink-0 flex-col gap-(--cue-space-4) overflow-y-auto border-l border-border bg-surface-1 p-(--cue-space-4)", className),
|
|
158
|
+
style: {
|
|
159
|
+
width,
|
|
160
|
+
...style
|
|
161
|
+
},
|
|
162
|
+
...elementProps
|
|
163
|
+
});
|
|
164
|
+
})
|
|
165
|
+
};
|
|
166
|
+
//#endregion
|
|
167
|
+
export { AppShell };
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { ContainerWidth } from "../layout/container.js";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
//#region src/chrome/footer.d.ts
|
|
4
|
+
interface FooterProps extends React.ComponentPropsWithoutRef<"footer"> {
|
|
5
|
+
/**
|
|
6
|
+
* Which measure the footer's column takes. Defaults to `"broad"`.
|
|
7
|
+
*
|
|
8
|
+
* The same four rungs `Container` and `PageShell` offer, so a footer lines up
|
|
9
|
+
* with the page above it by naming the same width — `broad` rather than
|
|
10
|
+
* `narrow` by default because a footer is usually the widest thing on a page,
|
|
11
|
+
* and a row of columns inside a 42rem reading measure is four squeezed lists.
|
|
12
|
+
*/
|
|
13
|
+
width?: ContainerWidth;
|
|
14
|
+
/**
|
|
15
|
+
* The fine print, under a hairline of its own: copyright, a licence, a build
|
|
16
|
+
* number.
|
|
17
|
+
*
|
|
18
|
+
* A slot rather than a component, because that row is a sentence and a couple
|
|
19
|
+
* of links — but it is a *separated* sentence, and hand-rolling the rule and
|
|
20
|
+
* the space above it in every app is exactly the kind of repetition this
|
|
21
|
+
* component exists to end.
|
|
22
|
+
*/
|
|
23
|
+
meta?: React.ReactNode;
|
|
24
|
+
/** Extra classes for the centred column inside the landmark. */
|
|
25
|
+
columnClassName?: string;
|
|
26
|
+
/** The footer's body — normally a `Grid` of `Stack`s of `Link`s. */
|
|
27
|
+
children?: React.ReactNode;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The `contentinfo` landmark at the bottom of a document: a hairline, a
|
|
31
|
+
* measure, and room for whatever a page ends with.
|
|
32
|
+
*
|
|
33
|
+
* Deliberately **not** a link-list component. A "complex footer" in this system
|
|
34
|
+
* is `Grid` + `Stack` + `Link` inside this one — components that already exist
|
|
35
|
+
* and already carry the density ladder — and a `Grid` with `minItemWidth` fills
|
|
36
|
+
* the row with as many columns as fit, so the footer is responsive without a
|
|
37
|
+
* breakpoint and without a prop for how many columns to draw. What is left over
|
|
38
|
+
* is what a footer actually needs and nothing else has: the landmark, the rule
|
|
39
|
+
* that separates it from the page, the measure that lines it up with the page,
|
|
40
|
+
* and the second rule above the fine print.
|
|
41
|
+
*
|
|
42
|
+
* The band is full-bleed and the column inside it is centred, which is why the
|
|
43
|
+
* hairline runs edge to edge while the links stop at the measure. The column is
|
|
44
|
+
* set in the bar's register — mono, at the UI size — because a footer is
|
|
45
|
+
* furniture. It paints no ground of its own: a footer is the end of the page,
|
|
46
|
+
* not a bar, and the seam is the hairline. Give it `className="bg-surface-1"`
|
|
47
|
+
* where a distinct band is wanted.
|
|
48
|
+
*
|
|
49
|
+
* Inside `AppShell` this is a child of `AppShell.Scroller`, at the end of the
|
|
50
|
+
* content column — so it scrolls with the page and its full bleed is the
|
|
51
|
+
* content column's width, not the window's. A footer placed *beside* the
|
|
52
|
+
* navigation column instead (after `AppShell.Body`) runs under the navigation
|
|
53
|
+
* and reads as chrome it is not. It coexists with `StatusBar`, which is the
|
|
54
|
+
* opposite object: a strip of the frame, always on screen, never scrolled.
|
|
55
|
+
*
|
|
56
|
+
* Static markup — no `"use client"`.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* <Footer meta={<><span>© 2026 CUE++</span><Link href="/legal">Legal</Link></>}>
|
|
60
|
+
* <Grid minItemWidth="12rem" gap={5}>
|
|
61
|
+
* <Stack gap={2}>
|
|
62
|
+
* <Eyebrow>Docs</Eyebrow>
|
|
63
|
+
* <Link href="/docs">Getting started</Link>
|
|
64
|
+
* <Link href="/docs/theming">Theming</Link>
|
|
65
|
+
* </Stack>
|
|
66
|
+
* <Stack gap={2}>
|
|
67
|
+
* <Eyebrow>Surfaces</Eyebrow>
|
|
68
|
+
* <Link href="/kitchen-sink">Kitchen sink</Link>
|
|
69
|
+
* </Stack>
|
|
70
|
+
* </Grid>
|
|
71
|
+
* </Footer>
|
|
72
|
+
*/
|
|
73
|
+
declare const Footer: React.ForwardRefExoticComponent<FooterProps & React.RefAttributes<HTMLElement>>;
|
|
74
|
+
//#endregion
|
|
75
|
+
export { Footer, FooterProps };
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { cn } from "../lib/cn.js";
|
|
2
|
+
import { Container } from "../layout/container.js";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
//#region src/chrome/footer.tsx
|
|
6
|
+
/**
|
|
7
|
+
* The `contentinfo` landmark at the bottom of a document: a hairline, a
|
|
8
|
+
* measure, and room for whatever a page ends with.
|
|
9
|
+
*
|
|
10
|
+
* Deliberately **not** a link-list component. A "complex footer" in this system
|
|
11
|
+
* is `Grid` + `Stack` + `Link` inside this one — components that already exist
|
|
12
|
+
* and already carry the density ladder — and a `Grid` with `minItemWidth` fills
|
|
13
|
+
* the row with as many columns as fit, so the footer is responsive without a
|
|
14
|
+
* breakpoint and without a prop for how many columns to draw. What is left over
|
|
15
|
+
* is what a footer actually needs and nothing else has: the landmark, the rule
|
|
16
|
+
* that separates it from the page, the measure that lines it up with the page,
|
|
17
|
+
* and the second rule above the fine print.
|
|
18
|
+
*
|
|
19
|
+
* The band is full-bleed and the column inside it is centred, which is why the
|
|
20
|
+
* hairline runs edge to edge while the links stop at the measure. The column is
|
|
21
|
+
* set in the bar's register — mono, at the UI size — because a footer is
|
|
22
|
+
* furniture. It paints no ground of its own: a footer is the end of the page,
|
|
23
|
+
* not a bar, and the seam is the hairline. Give it `className="bg-surface-1"`
|
|
24
|
+
* where a distinct band is wanted.
|
|
25
|
+
*
|
|
26
|
+
* Inside `AppShell` this is a child of `AppShell.Scroller`, at the end of the
|
|
27
|
+
* content column — so it scrolls with the page and its full bleed is the
|
|
28
|
+
* content column's width, not the window's. A footer placed *beside* the
|
|
29
|
+
* navigation column instead (after `AppShell.Body`) runs under the navigation
|
|
30
|
+
* and reads as chrome it is not. It coexists with `StatusBar`, which is the
|
|
31
|
+
* opposite object: a strip of the frame, always on screen, never scrolled.
|
|
32
|
+
*
|
|
33
|
+
* Static markup — no `"use client"`.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* <Footer meta={<><span>© 2026 CUE++</span><Link href="/legal">Legal</Link></>}>
|
|
37
|
+
* <Grid minItemWidth="12rem" gap={5}>
|
|
38
|
+
* <Stack gap={2}>
|
|
39
|
+
* <Eyebrow>Docs</Eyebrow>
|
|
40
|
+
* <Link href="/docs">Getting started</Link>
|
|
41
|
+
* <Link href="/docs/theming">Theming</Link>
|
|
42
|
+
* </Stack>
|
|
43
|
+
* <Stack gap={2}>
|
|
44
|
+
* <Eyebrow>Surfaces</Eyebrow>
|
|
45
|
+
* <Link href="/kitchen-sink">Kitchen sink</Link>
|
|
46
|
+
* </Stack>
|
|
47
|
+
* </Grid>
|
|
48
|
+
* </Footer>
|
|
49
|
+
*/
|
|
50
|
+
const Footer = React.forwardRef(function Footer({ className, columnClassName, width = "broad", meta, children, ...elementProps }, ref) {
|
|
51
|
+
return /* @__PURE__ */ jsx("footer", {
|
|
52
|
+
ref,
|
|
53
|
+
"data-slot": "footer",
|
|
54
|
+
className: cn("w-full border-t border-border", className),
|
|
55
|
+
...elementProps,
|
|
56
|
+
children: /* @__PURE__ */ jsxs(Container, {
|
|
57
|
+
width,
|
|
58
|
+
className: cn("flex flex-col gap-(--cue-space-6) py-(--cue-space-7) font-mono text-(length:--cue-text-ui)", columnClassName),
|
|
59
|
+
children: [children, meta === void 0 ? null : /* @__PURE__ */ jsx("div", {
|
|
60
|
+
"data-slot": "footer-meta",
|
|
61
|
+
className: "flex flex-wrap items-center justify-between gap-(--cue-space-3) border-t border-border pt-(--cue-space-5) font-mono text-(length:--cue-text-label) text-fg-subtle",
|
|
62
|
+
children: meta
|
|
63
|
+
})]
|
|
64
|
+
})
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
//#endregion
|
|
68
|
+
export { Footer };
|
package/dist/chrome/index.d.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { ScrollEdges, TAB_FADE_PX, computeScrollEdges, edgeFadeMask } from "./_tabs-scroll.js";
|
|
2
|
+
import { BarOverflow } from "./_edge-scroller.js";
|
|
2
3
|
import { TREE_GUIDE_GLYPHS, TreeGuide, TreeItem, TreeRow, flattenTree } from "./_tree.js";
|
|
4
|
+
import { AppBar, AppBarActionsProps, AppBarBrandProps, AppBarLinkProps, AppBarNavProps, AppBarRegister, AppBarRootProps, AppBarSeparatorProps } from "./app-bar.js";
|
|
5
|
+
import { AppShell, AppShellAsideProps, AppShellBodyProps, AppShellContentProps, AppShellNavTriggerProps, AppShellRootProps, AppShellScrollerProps, AppShellSidebarProps } from "./app-shell.js";
|
|
3
6
|
import { EmptyState, EmptyStateProps } from "./empty-state.js";
|
|
4
7
|
import { Eyebrow, EyebrowProps } from "./eyebrow.js";
|
|
8
|
+
import { Footer, FooterProps } from "./footer.js";
|
|
5
9
|
import { NavigationMenu, NavigationMenuContentProps, NavigationMenuItemProps, NavigationMenuLinkProps, NavigationMenuListProps, NavigationMenuRootProps, NavigationMenuTriggerProps, NavigationMenuViewportProps } from "./navigation-menu.js";
|
|
6
10
|
import { PageShell, PageShellProps, PageWidth } from "./page-shell.js";
|
|
7
11
|
import { Panel, PanelHeader, PanelHeaderProps, PanelProps } from "./panel.js";
|
|
@@ -14,4 +18,4 @@ import { ScrollableTabsList, ScrollableTabsListProps, Tabs, TabsListProps, TabsP
|
|
|
14
18
|
import { TitleBar, TitleBarProps } from "./title-bar.js";
|
|
15
19
|
import { Tree, TreeProps, TreeVisibility, TreeVisibilityToggle, TreeVisibilityToggleProps } from "./tree.js";
|
|
16
20
|
import { Toolbar, ToolbarButtonProps, ToolbarGroupProps, ToolbarRootProps, ToolbarSeparatorProps } from "./toolbar.js";
|
|
17
|
-
export { EmptyState, type EmptyStateProps, Eyebrow, type EyebrowProps, NavigationMenu, type NavigationMenuContentProps, type NavigationMenuItemProps, type NavigationMenuLinkProps, type NavigationMenuListProps, type NavigationMenuRootProps, type NavigationMenuTriggerProps, type NavigationMenuViewportProps, PageShell, type PageShellProps, type PageWidth, Panel, PanelHeader, type PanelHeaderProps, type PanelProps, Row, type RowProps, ScrollArea, type ScrollAreaOrientation, type ScrollAreaProps, type ScrollEdges, ScrollableTabsList, type ScrollableTabsListProps, SeamList, type SeamListProps, SectionHeader, type SectionHeaderProps, SegmentedControl, type SegmentedControlItem, type SegmentedControlProps, type SegmentedControlSize, StatusBar, type StatusBarItemProps, type StatusBarProps, type StatusBarTone, TAB_FADE_PX, TREE_GUIDE_GLYPHS, Tabs, type TabsListProps, type TabsPanelProps, type TabsRootProps, type TabsTabProps, TitleBar, type TitleBarProps, Toolbar, type ToolbarButtonProps, type ToolbarGroupProps, type ToolbarRootProps, type ToolbarSeparatorProps, Tree, type TreeGuide, type TreeItem, type TreeProps, type TreeRow, type TreeVisibility, TreeVisibilityToggle, type TreeVisibilityToggleProps, computeScrollEdges, edgeFadeMask, flattenTree, rowVariants };
|
|
21
|
+
export { AppBar, type AppBarActionsProps, type AppBarBrandProps, type AppBarLinkProps, type AppBarNavProps, type AppBarRegister, type AppBarRootProps, type AppBarSeparatorProps, AppShell, type AppShellAsideProps, type AppShellBodyProps, type AppShellContentProps, type AppShellNavTriggerProps, type AppShellRootProps, type AppShellScrollerProps, type AppShellSidebarProps, type BarOverflow, EmptyState, type EmptyStateProps, Eyebrow, type EyebrowProps, Footer, type FooterProps, NavigationMenu, type NavigationMenuContentProps, type NavigationMenuItemProps, type NavigationMenuLinkProps, type NavigationMenuListProps, type NavigationMenuRootProps, type NavigationMenuTriggerProps, type NavigationMenuViewportProps, PageShell, type PageShellProps, type PageWidth, Panel, PanelHeader, type PanelHeaderProps, type PanelProps, Row, type RowProps, ScrollArea, type ScrollAreaOrientation, type ScrollAreaProps, type ScrollEdges, ScrollableTabsList, type ScrollableTabsListProps, SeamList, type SeamListProps, SectionHeader, type SectionHeaderProps, SegmentedControl, type SegmentedControlItem, type SegmentedControlProps, type SegmentedControlSize, StatusBar, type StatusBarItemProps, type StatusBarProps, type StatusBarTone, TAB_FADE_PX, TREE_GUIDE_GLYPHS, Tabs, type TabsListProps, type TabsPanelProps, type TabsRootProps, type TabsTabProps, TitleBar, type TitleBarProps, Toolbar, type ToolbarButtonProps, type ToolbarGroupProps, type ToolbarRootProps, type ToolbarSeparatorProps, Tree, type TreeGuide, type TreeItem, type TreeProps, type TreeRow, type TreeVisibility, TreeVisibilityToggle, type TreeVisibilityToggleProps, computeScrollEdges, edgeFadeMask, flattenTree, rowVariants };
|
package/dist/chrome/index.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { TAB_FADE_PX, computeScrollEdges, edgeFadeMask } from "./_tabs-scroll.js";
|
|
2
2
|
import { TREE_GUIDE_GLYPHS, flattenTree } from "./_tree.js";
|
|
3
|
+
import { AppBar } from "./app-bar.js";
|
|
4
|
+
import { AppShell } from "./app-shell.js";
|
|
3
5
|
import { EmptyState } from "./empty-state.js";
|
|
4
6
|
import { Eyebrow } from "./eyebrow.js";
|
|
7
|
+
import { Footer } from "./footer.js";
|
|
5
8
|
import { NavigationMenu } from "./navigation-menu.js";
|
|
6
9
|
import { PageShell } from "./page-shell.js";
|
|
7
10
|
import { Panel, PanelHeader } from "./panel.js";
|
|
@@ -14,4 +17,4 @@ import { ScrollableTabsList, Tabs } from "./tabs.js";
|
|
|
14
17
|
import { TitleBar } from "./title-bar.js";
|
|
15
18
|
import { Tree, TreeVisibilityToggle } from "./tree.js";
|
|
16
19
|
import { Toolbar } from "./toolbar.js";
|
|
17
|
-
export { EmptyState, Eyebrow, NavigationMenu, PageShell, Panel, PanelHeader, Row, ScrollArea, ScrollableTabsList, SeamList, SectionHeader, SegmentedControl, StatusBar, TAB_FADE_PX, TREE_GUIDE_GLYPHS, Tabs, TitleBar, Toolbar, Tree, TreeVisibilityToggle, computeScrollEdges, edgeFadeMask, flattenTree, rowVariants };
|
|
20
|
+
export { AppBar, AppShell, EmptyState, Eyebrow, Footer, NavigationMenu, PageShell, Panel, PanelHeader, Row, ScrollArea, ScrollableTabsList, SeamList, SectionHeader, SegmentedControl, StatusBar, TAB_FADE_PX, TREE_GUIDE_GLYPHS, Tabs, TitleBar, Toolbar, Tree, TreeVisibilityToggle, computeScrollEdges, edgeFadeMask, flattenTree, rowVariants };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn } from "../lib/cn.js";
|
|
3
|
+
import { CaretDownGlyph } from "./_glyphs.js";
|
|
3
4
|
import { useCuePortalProps } from "../system/portal.js";
|
|
4
5
|
import { overlayPopupTransitionClasses, overlayPositionerClasses, overlaySurfaceClasses } from "../overlays/_surface.js";
|
|
5
|
-
import { CaretDownGlyph } from "./_glyphs.js";
|
|
6
6
|
import * as React from "react";
|
|
7
7
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
8
|
import { NavigationMenu } from "@base-ui/react/navigation-menu";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
//#region src/chrome/page-shell.d.ts
|
|
3
3
|
/** How wide the content column is allowed to get. */
|
|
4
|
-
type PageWidth = "narrow" | "wide";
|
|
4
|
+
type PageWidth = "narrow" | "wide" | "broad" | "full";
|
|
5
5
|
interface PageShellProps extends Omit<React.ComponentPropsWithoutRef<"div">, "title"> {
|
|
6
6
|
/** Which measure the content column takes. Defaults to `"narrow"`. */
|
|
7
7
|
width?: PageWidth;
|
|
@@ -3,14 +3,24 @@ import * as React from "react";
|
|
|
3
3
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
4
|
//#region src/chrome/page-shell.tsx
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* Four measures, not a scale — and the same four `Container` offers.
|
|
7
|
+
*
|
|
8
|
+
* `narrow` (42rem) is a reading column: settings, forms, prose. `wide` (54rem)
|
|
9
|
+
* is a working column: tables and panel grids. `broad` (84rem) is the
|
|
10
|
+
* application measure — a two-column documentation page, a page whose body is a
|
|
11
|
+
* device frame — and it exists because both of this repo's own hard-coded
|
|
12
|
+
* `max-w-[84rem]` overrides were asking for it. `full` caps nothing, for a page
|
|
13
|
+
* whose body sets its own width.
|
|
14
|
+
*
|
|
15
|
+
* `full` is still a page shell, not a console layout: it keeps the gutters and
|
|
16
|
+
* the standard page header. A screen that wants the *viewport* — one frame tall,
|
|
17
|
+
* with its own scroller — is `AppShell`, not this.
|
|
10
18
|
*/
|
|
11
19
|
const WIDTHS = {
|
|
12
20
|
narrow: "max-w-[42rem]",
|
|
13
|
-
wide: "max-w-[54rem]"
|
|
21
|
+
wide: "max-w-[54rem]",
|
|
22
|
+
broad: "max-w-[84rem]",
|
|
23
|
+
full: ""
|
|
14
24
|
};
|
|
15
25
|
/**
|
|
16
26
|
* A centred content column with a standard page header.
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { BarOverflow } from "./_edge-scroller.js";
|
|
1
2
|
import * as React from "react";
|
|
2
3
|
import { ToggleGroup } from "@base-ui/react/toggle-group";
|
|
3
4
|
//#region src/chrome/segmented-control.d.ts
|
|
@@ -29,6 +30,24 @@ interface SegmentedControlProps extends Omit<ToggleGroup.Props<string>, "value"
|
|
|
29
30
|
className?: string;
|
|
30
31
|
/** Extra classes for every segment. */
|
|
31
32
|
itemClassName?: string;
|
|
33
|
+
/**
|
|
34
|
+
* What the control does when its segments do not fit. Defaults to `"scroll"`.
|
|
35
|
+
*
|
|
36
|
+
* The same behaviour `Toolbar` has, from the same module, for the same
|
|
37
|
+
* reason: a switcher with five segments in a page header's actions slot runs
|
|
38
|
+
* off a phone-width screen, and wrapping it would turn a one-rung control
|
|
39
|
+
* into a two-row block that no longer reads as one switch. `"scroll"` keeps
|
|
40
|
+
* the rim and the height, scrolls the segments inside them, fades the
|
|
41
|
+
* overflowing edge and offers a pager chevron there.
|
|
42
|
+
*
|
|
43
|
+
* `"clip"` is the old behaviour, for a control already inside something that
|
|
44
|
+
* scrolls.
|
|
45
|
+
*/
|
|
46
|
+
overflow?: BarOverflow;
|
|
47
|
+
/** Accessible name for the chevron that reveals segments off the leading edge. */
|
|
48
|
+
previousLabel?: string;
|
|
49
|
+
/** Accessible name for the chevron that reveals segments off the trailing edge. */
|
|
50
|
+
nextLabel?: string;
|
|
32
51
|
}
|
|
33
52
|
/**
|
|
34
53
|
* A one-of-N switch drawn as a row of segments: the console's view picker.
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn } from "../lib/cn.js";
|
|
3
|
+
import { useComposedRefs } from "../lib/compose.js";
|
|
4
|
+
import { EDGE_SCROLLER_CLASSES, EdgeChevrons, useEdgeScroll } from "./_edge-scroller.js";
|
|
3
5
|
import * as React from "react";
|
|
4
6
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
7
|
import { Toggle } from "@base-ui/react/toggle";
|
|
@@ -40,9 +42,12 @@ const ITEM_CLASSES = "inline-flex shrink-0 cursor-pointer select-none items-cent
|
|
|
40
42
|
* items={[{ value: "beams", label: "Beams" }, { value: "patch", label: "Patch" }]}
|
|
41
43
|
* />
|
|
42
44
|
*/
|
|
43
|
-
const SegmentedControl = React.forwardRef(function SegmentedControl({ items, value: valueProp, defaultValue, onValueChange, size = "md", className, itemClassName, ...groupProps }, ref) {
|
|
45
|
+
const SegmentedControl = React.forwardRef(function SegmentedControl({ items, value: valueProp, defaultValue, onValueChange, size = "md", className, itemClassName, overflow = "scroll", previousLabel = "Show earlier segments", nextLabel = "Show later segments", ...groupProps }, ref) {
|
|
44
46
|
const [uncontrolledValue, setUncontrolledValue] = React.useState(defaultValue);
|
|
45
47
|
const value = valueProp ?? uncontrolledValue;
|
|
48
|
+
const scrolls = overflow === "scroll";
|
|
49
|
+
const scroll = useEdgeScroll(scrolls);
|
|
50
|
+
const groupRef = useComposedRefs(ref, scroll.ref);
|
|
46
51
|
const handleValueChange = (groupValue) => {
|
|
47
52
|
const next = groupValue[0];
|
|
48
53
|
if (next === void 0 || next === value) return;
|
|
@@ -50,26 +55,40 @@ const SegmentedControl = React.forwardRef(function SegmentedControl({ items, val
|
|
|
50
55
|
onValueChange?.(next);
|
|
51
56
|
};
|
|
52
57
|
const iconSize = size === "sm" ? "size-icon-sm" : "size-icon-md";
|
|
53
|
-
return /* @__PURE__ */
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
58
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
59
|
+
"data-slot": "segmented-control-frame",
|
|
60
|
+
className: cn("relative inline-flex max-w-full min-w-0 shrink-0 items-center rounded-(--radius-control) border border-border bg-surface-1 p-(--cue-space-1)", className),
|
|
61
|
+
children: [/* @__PURE__ */ jsx(ToggleGroup, {
|
|
62
|
+
ref: groupRef,
|
|
63
|
+
value: value === void 0 ? [] : [value],
|
|
64
|
+
onValueChange: handleValueChange,
|
|
65
|
+
"data-slot": "segmented-control",
|
|
66
|
+
className: cn("inline-flex min-w-0 items-center gap-(--cue-space-1)", scrolls ? EDGE_SCROLLER_CLASSES : null),
|
|
67
|
+
...groupProps,
|
|
68
|
+
style: {
|
|
69
|
+
...groupProps.style,
|
|
70
|
+
...scroll.style
|
|
71
|
+
},
|
|
72
|
+
children: items.map((item) => {
|
|
73
|
+
const Icon = item.icon;
|
|
74
|
+
return /* @__PURE__ */ jsxs(Toggle, {
|
|
75
|
+
value: item.value,
|
|
76
|
+
disabled: item.disabled,
|
|
77
|
+
"data-slot": "segmented-control-item",
|
|
78
|
+
className: cn(ITEM_CLASSES, ITEM_SIZES[size], itemClassName),
|
|
79
|
+
children: [Icon === void 0 ? null : /* @__PURE__ */ jsx(Icon, {
|
|
80
|
+
"aria-hidden": "true",
|
|
81
|
+
className: cn("shrink-0", iconSize)
|
|
82
|
+
}), item.label]
|
|
83
|
+
}, item.value);
|
|
84
|
+
})
|
|
85
|
+
}), /* @__PURE__ */ jsx(EdgeChevrons, {
|
|
86
|
+
edges: scroll.edges,
|
|
87
|
+
onNudge: scroll.nudge,
|
|
88
|
+
previousLabel,
|
|
89
|
+
nextLabel,
|
|
90
|
+
className: "rounded-(--radius-control) bg-surface-1"
|
|
91
|
+
})]
|
|
73
92
|
});
|
|
74
93
|
});
|
|
75
94
|
//#endregion
|
package/dist/chrome/tabs.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn } from "../lib/cn.js";
|
|
3
|
-
import {
|
|
4
|
-
import { ChevronLeftGlyph, ChevronRightGlyph } from "./_glyphs.js";
|
|
3
|
+
import { EDGE_SCROLLER_CLASSES, EdgeChevrons, useEdgeScroll } from "./_edge-scroller.js";
|
|
5
4
|
import * as React from "react";
|
|
6
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
6
|
import { Tabs } from "@base-ui/react/tabs";
|
|
@@ -52,8 +51,6 @@ const TabsPanel = React.forwardRef(function TabsPanel({ className, ...elementPro
|
|
|
52
51
|
...elementProps
|
|
53
52
|
});
|
|
54
53
|
});
|
|
55
|
-
/** Page the strip by most of a screenful, keeping a sliver of context. */
|
|
56
|
-
const NUDGE_FRACTION = .7;
|
|
57
54
|
/**
|
|
58
55
|
* A {@link TabsList} that scrolls when its tabs do not fit, and says so.
|
|
59
56
|
*
|
|
@@ -75,75 +72,34 @@ const NUDGE_FRACTION = .7;
|
|
|
75
72
|
* </Tabs.Root>
|
|
76
73
|
*/
|
|
77
74
|
const ScrollableTabsList = React.forwardRef(function ScrollableTabsList({ className, containerClassName, activeValue, children, ...listProps }, ref) {
|
|
78
|
-
const
|
|
79
|
-
const [edges, setEdges] = React.useState({
|
|
80
|
-
start: false,
|
|
81
|
-
end: false
|
|
82
|
-
});
|
|
83
|
-
const sync = React.useCallback(() => {
|
|
84
|
-
const el = scrollerRef.current;
|
|
85
|
-
if (el === null) return;
|
|
86
|
-
setEdges(computeScrollEdges(el.scrollLeft, el.scrollWidth, el.clientWidth));
|
|
87
|
-
}, []);
|
|
88
|
-
React.useEffect(() => {
|
|
89
|
-
const el = scrollerRef.current;
|
|
90
|
-
if (el === null) return;
|
|
91
|
-
sync();
|
|
92
|
-
el.addEventListener("scroll", sync, { passive: true });
|
|
93
|
-
const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(() => sync());
|
|
94
|
-
observer?.observe(el);
|
|
95
|
-
if (el.firstElementChild !== null) observer?.observe(el.firstElementChild);
|
|
96
|
-
return () => {
|
|
97
|
-
el.removeEventListener("scroll", sync);
|
|
98
|
-
observer?.disconnect();
|
|
99
|
-
};
|
|
100
|
-
}, [sync]);
|
|
75
|
+
const scroll = useEdgeScroll();
|
|
101
76
|
React.useEffect(() => {
|
|
102
|
-
|
|
77
|
+
scroll.ref.current?.querySelector("[data-slot='tabs-tab'][data-active]")?.scrollIntoView?.({
|
|
103
78
|
block: "nearest",
|
|
104
79
|
inline: "nearest"
|
|
105
80
|
});
|
|
106
81
|
}, [activeValue]);
|
|
107
|
-
const nudge = (direction) => {
|
|
108
|
-
const el = scrollerRef.current;
|
|
109
|
-
el?.scrollBy?.({
|
|
110
|
-
left: direction * el.clientWidth * NUDGE_FRACTION,
|
|
111
|
-
behavior: "smooth"
|
|
112
|
-
});
|
|
113
|
-
};
|
|
114
|
-
const mask = edgeFadeMask(edges);
|
|
115
|
-
const chevronClasses = "absolute inset-y-0 z-10 flex w-(--cue-space-5) cursor-pointer items-center justify-center bg-surface-2 text-fg-muted outline-none hover:text-fg focus-visible:outline-2 focus-visible:outline-solid focus-visible:-outline-offset-2 focus-visible:outline-accent";
|
|
116
82
|
return /* @__PURE__ */ jsxs("div", {
|
|
117
83
|
"data-slot": "tabs-scroll-frame",
|
|
118
84
|
className: cn("relative min-w-0", containerClassName),
|
|
119
|
-
children: [
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
children: /* @__PURE__ */ jsx(ChevronLeftGlyph, { className: "size-icon-sm" })
|
|
138
|
-
}) : null,
|
|
139
|
-
edges.end ? /* @__PURE__ */ jsx("button", {
|
|
140
|
-
type: "button",
|
|
141
|
-
"aria-label": "Show later tabs",
|
|
142
|
-
onClick: () => nudge(1),
|
|
143
|
-
className: cn(chevronClasses, "right-0"),
|
|
144
|
-
children: /* @__PURE__ */ jsx(ChevronRightGlyph, { className: "size-icon-sm" })
|
|
145
|
-
}) : null
|
|
146
|
-
]
|
|
85
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
86
|
+
ref: scroll.ref,
|
|
87
|
+
"data-slot": "tabs-scroller",
|
|
88
|
+
className: EDGE_SCROLLER_CLASSES,
|
|
89
|
+
style: scroll.style,
|
|
90
|
+
children: /* @__PURE__ */ jsx(TabsList, {
|
|
91
|
+
ref,
|
|
92
|
+
className: cn("w-max", className),
|
|
93
|
+
...listProps,
|
|
94
|
+
children
|
|
95
|
+
})
|
|
96
|
+
}), /* @__PURE__ */ jsx(EdgeChevrons, {
|
|
97
|
+
edges: scroll.edges,
|
|
98
|
+
onNudge: scroll.nudge,
|
|
99
|
+
previousLabel: "Show earlier tabs",
|
|
100
|
+
nextLabel: "Show later tabs",
|
|
101
|
+
className: "bg-surface-2"
|
|
102
|
+
})]
|
|
147
103
|
});
|
|
148
104
|
});
|
|
149
105
|
/**
|