@nsaa/core 0.1.0-alpha.4 → 0.1.0-alpha.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/button/button.js +1 -0
- package/dist/date-range-picker/date-range-picker.d.ts +55 -0
- package/dist/date-range-picker/date-range-picker.js +346 -0
- package/dist/date-range-picker/index.d.ts +4 -0
- package/dist/date-range-picker/presets.d.ts +25 -0
- package/dist/date-range-picker/presets.js +115 -0
- package/dist/index.d.ts +15 -2
- package/dist/index.js +11 -4
- package/dist/lib/dev.js +14 -0
- package/dist/meter/index.d.ts +3 -0
- package/dist/meter/meter.d.ts +33 -0
- package/dist/meter/meter.js +145 -0
- package/dist/money/index.d.ts +3 -0
- package/dist/money/money.d.ts +28 -0
- package/dist/money/money.js +77 -0
- package/dist/progress/index.d.ts +3 -0
- package/dist/progress/progress.d.ts +8 -0
- package/dist/progress/progress.js +43 -0
- package/dist/sidebar/index.d.ts +3 -0
- package/dist/sidebar/sidebar.d.ts +66 -0
- package/dist/sidebar/sidebar.js +449 -0
- package/dist/sidebar/use-mobile.js +13 -0
- package/dist/sources/date-range-picker.css +29 -0
- package/dist/sources/meter.css +3 -0
- package/dist/sources/money.css +3 -0
- package/dist/sources/progress.css +3 -0
- package/dist/sources/sidebar.css +32 -0
- package/dist/sources/stat.css +4 -0
- package/dist/stat/index.d.ts +3 -0
- package/dist/stat/stat.d.ts +47 -0
- package/dist/stat/stat.js +161 -0
- package/dist/tokens/dist/motion.js +19 -1
- package/dist/toolbar/toolbar-item.js +1 -1
- package/dist/toolbar/toolbar.js +1 -1
- package/package.json +2 -2
- package/src/feel.css +104 -3
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use client";
|
|
3
|
+
import { cn } from "../lib/cn.js";
|
|
4
|
+
import { Button } from "../button/button.js";
|
|
5
|
+
import { Input } from "../input/input.js";
|
|
6
|
+
import { Drawer, DrawerContent, DrawerDescription, DrawerHeader, DrawerTitle } from "../drawer/drawer.js";
|
|
7
|
+
import { Separator } from "../separator/separator.js";
|
|
8
|
+
import { isDev } from "../lib/dev.js";
|
|
9
|
+
import { Skeleton } from "../skeleton/skeleton.js";
|
|
10
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from "../tooltip/tooltip.js";
|
|
11
|
+
import { useIsMobile } from "./use-mobile.js";
|
|
12
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
13
|
+
import { mergeProps } from "@base-ui/react/merge-props";
|
|
14
|
+
import { useRender } from "@base-ui/react/use-render";
|
|
15
|
+
import { cva } from "class-variance-authority";
|
|
16
|
+
import * as React from "react";
|
|
17
|
+
import { useDirection } from "@base-ui/react/direction-provider";
|
|
18
|
+
// src/sidebar/sidebar.tsx
|
|
19
|
+
const SIDEBAR_COOKIE_NAME = "sidebar_state";
|
|
20
|
+
const SIDEBAR_COOKIE_MAX_AGE = 604800;
|
|
21
|
+
const SIDEBAR_WIDTH = "16rem";
|
|
22
|
+
const SIDEBAR_WIDTH_MOBILE = "18rem";
|
|
23
|
+
const SIDEBAR_WIDTH_ICON = "3rem";
|
|
24
|
+
const SIDEBAR_KEYBOARD_SHORTCUT = "b";
|
|
25
|
+
const SidebarContext = React.createContext(null);
|
|
26
|
+
function useSidebar() {
|
|
27
|
+
const context = React.useContext(SidebarContext);
|
|
28
|
+
if (!context) throw new Error("useSidebar must be used within a SidebarProvider.");
|
|
29
|
+
return context;
|
|
30
|
+
}
|
|
31
|
+
function SidebarProvider({ defaultOpen = true, open: openProp, onOpenChange: setOpenProp, className, style, children, ...props }) {
|
|
32
|
+
const isMobile = useIsMobile();
|
|
33
|
+
const [openMobile, setOpenMobile] = React.useState(false);
|
|
34
|
+
const [_open, _setOpen] = React.useState(defaultOpen);
|
|
35
|
+
const open = openProp ?? _open;
|
|
36
|
+
const setOpen = React.useCallback((value) => {
|
|
37
|
+
const openState = typeof value === "function" ? value(open) : value;
|
|
38
|
+
if (setOpenProp) setOpenProp(openState);
|
|
39
|
+
else _setOpen(openState);
|
|
40
|
+
document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
|
|
41
|
+
}, [setOpenProp, open]);
|
|
42
|
+
const toggleSidebar = React.useCallback(() => {
|
|
43
|
+
return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open);
|
|
44
|
+
}, [
|
|
45
|
+
isMobile,
|
|
46
|
+
setOpen,
|
|
47
|
+
setOpenMobile
|
|
48
|
+
]);
|
|
49
|
+
React.useEffect(() => {
|
|
50
|
+
const handleKeyDown = (event) => {
|
|
51
|
+
if (event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey)) {
|
|
52
|
+
event.preventDefault();
|
|
53
|
+
toggleSidebar();
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
57
|
+
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
58
|
+
}, [toggleSidebar]);
|
|
59
|
+
const state = open ? "expanded" : "collapsed";
|
|
60
|
+
const contextValue = React.useMemo(() => ({
|
|
61
|
+
state,
|
|
62
|
+
open,
|
|
63
|
+
setOpen,
|
|
64
|
+
isMobile,
|
|
65
|
+
openMobile,
|
|
66
|
+
setOpenMobile,
|
|
67
|
+
toggleSidebar
|
|
68
|
+
}), [
|
|
69
|
+
state,
|
|
70
|
+
open,
|
|
71
|
+
setOpen,
|
|
72
|
+
isMobile,
|
|
73
|
+
openMobile,
|
|
74
|
+
setOpenMobile,
|
|
75
|
+
toggleSidebar
|
|
76
|
+
]);
|
|
77
|
+
return /* @__PURE__ */ jsx(SidebarContext.Provider, {
|
|
78
|
+
value: contextValue,
|
|
79
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
80
|
+
"data-slot": "sidebar-wrapper",
|
|
81
|
+
style: {
|
|
82
|
+
"--sidebar-width": SIDEBAR_WIDTH,
|
|
83
|
+
"--sidebar-width-icon": SIDEBAR_WIDTH_ICON,
|
|
84
|
+
...style
|
|
85
|
+
},
|
|
86
|
+
className: cn("group/sidebar-wrapper flex min-h-svh w-full has-data-[variant=inset]:bg-sidebar", className),
|
|
87
|
+
...props,
|
|
88
|
+
children
|
|
89
|
+
})
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
function Sidebar({ side = "left", variant = "sidebar", collapsible = "offcanvas", className, children, dir, "aria-label": ariaLabel = "Sidebar", ...props }) {
|
|
93
|
+
const { isMobile, state, openMobile, setOpenMobile } = useSidebar();
|
|
94
|
+
const direction = useDirection();
|
|
95
|
+
const edge = (dir ?? direction) === "rtl" ? side === "left" ? "right" : "left" : side;
|
|
96
|
+
if (collapsible === "none") return /* @__PURE__ */ jsx("nav", {
|
|
97
|
+
"data-slot": "sidebar",
|
|
98
|
+
"aria-label": ariaLabel,
|
|
99
|
+
className: cn("flex h-full w-(--sidebar-width) flex-col bg-sidebar text-sidebar-foreground", className),
|
|
100
|
+
...props,
|
|
101
|
+
children
|
|
102
|
+
});
|
|
103
|
+
if (isMobile) return /* @__PURE__ */ jsx(Drawer, {
|
|
104
|
+
open: openMobile,
|
|
105
|
+
onOpenChange: (open) => setOpenMobile(open),
|
|
106
|
+
swipeDirection: edge,
|
|
107
|
+
children: /* @__PURE__ */ jsxs(DrawerContent, {
|
|
108
|
+
dir,
|
|
109
|
+
"data-sidebar": "sidebar",
|
|
110
|
+
"data-mobile": "true",
|
|
111
|
+
className: "w-(--sidebar-width) bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden",
|
|
112
|
+
style: {
|
|
113
|
+
"--sidebar-width": SIDEBAR_WIDTH_MOBILE,
|
|
114
|
+
"--drawer-bleed-background": "var(--color-sidebar)"
|
|
115
|
+
},
|
|
116
|
+
children: [/* @__PURE__ */ jsxs(DrawerHeader, {
|
|
117
|
+
className: "sr-only",
|
|
118
|
+
children: [/* @__PURE__ */ jsx(DrawerTitle, { children: "Sidebar" }), /* @__PURE__ */ jsx(DrawerDescription, { children: "Displays the mobile sidebar." })]
|
|
119
|
+
}), /* @__PURE__ */ jsx("nav", {
|
|
120
|
+
"data-slot": "sidebar",
|
|
121
|
+
"aria-label": ariaLabel,
|
|
122
|
+
className: "flex h-full w-full flex-col",
|
|
123
|
+
children
|
|
124
|
+
})]
|
|
125
|
+
})
|
|
126
|
+
});
|
|
127
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
128
|
+
className: "group peer hidden text-sidebar-foreground md:block",
|
|
129
|
+
"data-state": state,
|
|
130
|
+
"data-collapsible": state === "collapsed" ? collapsible : "",
|
|
131
|
+
"data-variant": variant,
|
|
132
|
+
"data-side": edge,
|
|
133
|
+
"data-slot": "sidebar",
|
|
134
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
135
|
+
"data-slot": "sidebar-gap",
|
|
136
|
+
className: cn("relative w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear", "group-data-[collapsible=offcanvas]:w-0", "group-data-[side=right]:rotate-180", variant === "floating" || variant === "inset" ? "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]" : "group-data-[collapsible=icon]:w-(--sidebar-width-icon)")
|
|
137
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
138
|
+
"data-slot": "sidebar-container",
|
|
139
|
+
"data-side": edge,
|
|
140
|
+
inert: state === "collapsed" && collapsible === "offcanvas",
|
|
141
|
+
className: cn("fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear data-[side=left]:left-0 data-[side=left]:group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)] data-[side=right]:right-0 data-[side=right]:group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)] md:flex", variant === "floating" || variant === "inset" ? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]" : "group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l", className),
|
|
142
|
+
...props,
|
|
143
|
+
children: /* @__PURE__ */ jsx("nav", {
|
|
144
|
+
"data-sidebar": "sidebar",
|
|
145
|
+
"data-slot": "sidebar-inner",
|
|
146
|
+
"aria-label": ariaLabel,
|
|
147
|
+
className: "flex size-full flex-col bg-sidebar group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:shadow-sm group-data-[variant=floating]:ring-1 group-data-[variant=floating]:ring-sidebar-border",
|
|
148
|
+
children
|
|
149
|
+
})
|
|
150
|
+
})]
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
function SidebarTrigger({ className, onClick, ...props }) {
|
|
154
|
+
const { toggleSidebar } = useSidebar();
|
|
155
|
+
return /* @__PURE__ */ jsxs(Button, {
|
|
156
|
+
"data-sidebar": "trigger",
|
|
157
|
+
"data-slot": "sidebar-trigger",
|
|
158
|
+
variant: "ghost",
|
|
159
|
+
size: "icon-sm",
|
|
160
|
+
className: cn(className),
|
|
161
|
+
onClick: (event) => {
|
|
162
|
+
onClick?.(event);
|
|
163
|
+
toggleSidebar();
|
|
164
|
+
},
|
|
165
|
+
...props,
|
|
166
|
+
children: [/* @__PURE__ */ jsxs("svg", {
|
|
167
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
168
|
+
viewBox: "0 0 24 24",
|
|
169
|
+
fill: "none",
|
|
170
|
+
stroke: "currentColor",
|
|
171
|
+
strokeWidth: "2",
|
|
172
|
+
strokeLinecap: "round",
|
|
173
|
+
strokeLinejoin: "round",
|
|
174
|
+
"aria-hidden": "true",
|
|
175
|
+
className: "cn-rtl-flip",
|
|
176
|
+
children: [/* @__PURE__ */ jsx("rect", {
|
|
177
|
+
width: "18",
|
|
178
|
+
height: "18",
|
|
179
|
+
x: "3",
|
|
180
|
+
y: "3",
|
|
181
|
+
rx: "2"
|
|
182
|
+
}), /* @__PURE__ */ jsx("path", { d: "M9 3v18" })]
|
|
183
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
184
|
+
className: "sr-only",
|
|
185
|
+
children: "Toggle Sidebar"
|
|
186
|
+
})]
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
function SidebarRail({ className, ...props }) {
|
|
190
|
+
const { toggleSidebar } = useSidebar();
|
|
191
|
+
return /* @__PURE__ */ jsx("button", {
|
|
192
|
+
"data-sidebar": "rail",
|
|
193
|
+
"data-slot": "sidebar-rail",
|
|
194
|
+
"aria-label": "Toggle Sidebar",
|
|
195
|
+
tabIndex: -1,
|
|
196
|
+
onClick: toggleSidebar,
|
|
197
|
+
title: "Toggle Sidebar",
|
|
198
|
+
className: cn("absolute inset-y-0 z-20 hidden w-4 transition-all ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:start-1/2 after:w-[2px] hover:after:bg-sidebar-border sm:flex ltr:-translate-x-1/2 rtl:-translate-x-1/2", "in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize", "[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize", "group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full hover:group-data-[collapsible=offcanvas]:bg-sidebar", "[[data-side=left][data-collapsible=offcanvas]_&]:-right-2", "[[data-side=right][data-collapsible=offcanvas]_&]:-left-2", className),
|
|
199
|
+
...props
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
/** The page beside the sidebar: a `main` landmark. Pass `render={<div />}` when the page already has
|
|
203
|
+
one (a demo, or a sidebar inside a page section). */
|
|
204
|
+
function SidebarInset({ className, render, ...props }) {
|
|
205
|
+
return useRender({
|
|
206
|
+
defaultTagName: "main",
|
|
207
|
+
render,
|
|
208
|
+
props: mergeProps({ className: cn("relative flex w-full flex-1 flex-col bg-background md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ms-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow-sm md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ms-2", className) }, props),
|
|
209
|
+
state: { slot: "sidebar-inset" }
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
function SidebarInput({ className, ...props }) {
|
|
213
|
+
return /* @__PURE__ */ jsx(Input, {
|
|
214
|
+
"data-slot": "sidebar-input",
|
|
215
|
+
"data-sidebar": "input",
|
|
216
|
+
className: cn("h-8 w-full bg-background shadow-none", className),
|
|
217
|
+
...props
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
function SidebarHeader({ className, ...props }) {
|
|
221
|
+
return /* @__PURE__ */ jsx("div", {
|
|
222
|
+
"data-slot": "sidebar-header",
|
|
223
|
+
"data-sidebar": "header",
|
|
224
|
+
className: cn("flex flex-col gap-2 p-2", className),
|
|
225
|
+
...props
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
function SidebarFooter({ className, ...props }) {
|
|
229
|
+
return /* @__PURE__ */ jsx("div", {
|
|
230
|
+
"data-slot": "sidebar-footer",
|
|
231
|
+
"data-sidebar": "footer",
|
|
232
|
+
className: cn("flex flex-col gap-2 p-2", className),
|
|
233
|
+
...props
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
function SidebarSeparator({ className, ...props }) {
|
|
237
|
+
return /* @__PURE__ */ jsx(Separator, {
|
|
238
|
+
"data-slot": "sidebar-separator",
|
|
239
|
+
"data-sidebar": "separator",
|
|
240
|
+
className: cn("mx-2 w-auto bg-sidebar-border", className),
|
|
241
|
+
...props
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
function SidebarContent({ className, ...props }) {
|
|
245
|
+
return /* @__PURE__ */ jsx("div", {
|
|
246
|
+
"data-slot": "sidebar-content",
|
|
247
|
+
"data-sidebar": "content",
|
|
248
|
+
className: cn("no-scrollbar flex min-h-0 flex-1 flex-col gap-0 overflow-auto group-data-[collapsible=icon]:overflow-hidden", className),
|
|
249
|
+
...props
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
const SidebarGroupContext = React.createContext(null);
|
|
253
|
+
function SidebarGroup({ className, ...props }) {
|
|
254
|
+
const [labelId, setLabelId] = React.useState();
|
|
255
|
+
return /* @__PURE__ */ jsx(SidebarGroupContext.Provider, {
|
|
256
|
+
value: setLabelId,
|
|
257
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
258
|
+
"data-slot": "sidebar-group",
|
|
259
|
+
"data-sidebar": "group",
|
|
260
|
+
role: "group",
|
|
261
|
+
"aria-labelledby": labelId,
|
|
262
|
+
className: cn("relative flex w-full min-w-0 flex-col p-2", className),
|
|
263
|
+
...props
|
|
264
|
+
})
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
function SidebarGroupLabel({ className, render, id: idProp, ...props }) {
|
|
268
|
+
const generatedId = React.useId();
|
|
269
|
+
const id = idProp ?? generatedId;
|
|
270
|
+
const setLabelId = React.useContext(SidebarGroupContext);
|
|
271
|
+
React.useEffect(() => {
|
|
272
|
+
setLabelId?.(id);
|
|
273
|
+
return () => setLabelId?.(void 0);
|
|
274
|
+
}, [setLabelId, id]);
|
|
275
|
+
return useRender({
|
|
276
|
+
defaultTagName: "div",
|
|
277
|
+
props: mergeProps({
|
|
278
|
+
id,
|
|
279
|
+
className: cn("flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium text-sidebar-foreground/70 ring-sidebar-ring outline-hidden transition-[margin,opacity] duration-200 ease-linear group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0 focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0", className)
|
|
280
|
+
}, props),
|
|
281
|
+
render,
|
|
282
|
+
state: {
|
|
283
|
+
slot: "sidebar-group-label",
|
|
284
|
+
sidebar: "group-label"
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
function SidebarGroupAction({ className, render, ...props }) {
|
|
289
|
+
return useRender({
|
|
290
|
+
defaultTagName: "button",
|
|
291
|
+
props: mergeProps({ className: cn("absolute top-3.5 end-3 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground ring-sidebar-ring outline-hidden transition-transform group-data-[collapsible=icon]:hidden after:absolute after:-inset-2 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 md:after:hidden [&>svg]:size-4 [&>svg]:shrink-0", className) }, props),
|
|
292
|
+
render,
|
|
293
|
+
state: {
|
|
294
|
+
slot: "sidebar-group-action",
|
|
295
|
+
sidebar: "group-action"
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
function SidebarGroupContent({ className, ...props }) {
|
|
300
|
+
return /* @__PURE__ */ jsx("div", {
|
|
301
|
+
"data-slot": "sidebar-group-content",
|
|
302
|
+
"data-sidebar": "group-content",
|
|
303
|
+
className: cn("w-full text-sm", className),
|
|
304
|
+
...props
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
function SidebarMenu({ className, ...props }) {
|
|
308
|
+
return /* @__PURE__ */ jsx("ul", {
|
|
309
|
+
"data-slot": "sidebar-menu",
|
|
310
|
+
"data-sidebar": "menu",
|
|
311
|
+
className: cn("flex w-full min-w-0 flex-col gap-0", className),
|
|
312
|
+
...props
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
function SidebarMenuItem({ className, ...props }) {
|
|
316
|
+
return /* @__PURE__ */ jsx("li", {
|
|
317
|
+
"data-slot": "sidebar-menu-item",
|
|
318
|
+
"data-sidebar": "menu-item",
|
|
319
|
+
className: cn("group/menu-item relative", className),
|
|
320
|
+
...props
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
const sidebarMenuButtonVariants = cva("peer/menu-button group/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-start text-sm ring-sidebar-ring outline-hidden transition-[width,height,padding] group-has-data-[sidebar=menu-action]/menu-item:pe-8 group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-open:hover:bg-sidebar-accent data-open:hover:text-sidebar-accent-foreground data-active:bg-sidebar-accent data-active:font-medium data-active:text-sidebar-accent-foreground pointer-coarse:min-h-11 [&_svg]:size-4 [&_svg]:shrink-0 [&>span:last-child]:truncate", {
|
|
324
|
+
variants: {
|
|
325
|
+
variant: {
|
|
326
|
+
default: "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
|
|
327
|
+
outline: "bg-background shadow-[0_0_0_1px_var(--sidebar-border)] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_var(--sidebar-accent)]"
|
|
328
|
+
},
|
|
329
|
+
size: {
|
|
330
|
+
default: "h-8 text-sm",
|
|
331
|
+
sm: "h-7 text-xs",
|
|
332
|
+
lg: "h-12 text-sm group-data-[collapsible=icon]:p-0!"
|
|
333
|
+
}
|
|
334
|
+
},
|
|
335
|
+
defaultVariants: {
|
|
336
|
+
variant: "default",
|
|
337
|
+
size: "default"
|
|
338
|
+
}
|
|
339
|
+
});
|
|
340
|
+
function SidebarMenuButton({ render, isActive = false, variant = "default", size = "default", tooltip, className, ref, ...props }) {
|
|
341
|
+
const { isMobile, state } = useSidebar();
|
|
342
|
+
const own = React.useRef(null);
|
|
343
|
+
React.useEffect(() => {
|
|
344
|
+
if (!isDev() || tooltip || isMobile || state !== "collapsed") return;
|
|
345
|
+
const el = own.current;
|
|
346
|
+
if (!el?.closest("[data-collapsible=\"icon\"]")) return;
|
|
347
|
+
if (!(el.getAttribute("aria-label")?.trim() || el.getAttribute("aria-labelledby") || el.textContent?.trim())) console.warn("SidebarMenuButton: collapsed to icons with no `tooltip` and no accessible name. Pass `tooltip` and a text label (or `aria-label`).");
|
|
348
|
+
}, [
|
|
349
|
+
tooltip,
|
|
350
|
+
isMobile,
|
|
351
|
+
state
|
|
352
|
+
]);
|
|
353
|
+
const comp = useRender({
|
|
354
|
+
defaultTagName: "button",
|
|
355
|
+
ref: [own, ref ?? null],
|
|
356
|
+
props: mergeProps({
|
|
357
|
+
"aria-current": isActive ? "page" : void 0,
|
|
358
|
+
className: cn(sidebarMenuButtonVariants({
|
|
359
|
+
variant,
|
|
360
|
+
size
|
|
361
|
+
}), className)
|
|
362
|
+
}, props),
|
|
363
|
+
render: !tooltip ? render : /* @__PURE__ */ jsx(TooltipTrigger, { render }),
|
|
364
|
+
state: {
|
|
365
|
+
slot: "sidebar-menu-button",
|
|
366
|
+
sidebar: "menu-button",
|
|
367
|
+
size,
|
|
368
|
+
active: isActive
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
if (!tooltip) return comp;
|
|
372
|
+
return /* @__PURE__ */ jsxs(Tooltip, { children: [comp, /* @__PURE__ */ jsx(TooltipContent, {
|
|
373
|
+
side: "right",
|
|
374
|
+
align: "center",
|
|
375
|
+
hidden: state !== "collapsed" || isMobile,
|
|
376
|
+
...typeof tooltip === "string" ? { children: tooltip } : tooltip
|
|
377
|
+
})] });
|
|
378
|
+
}
|
|
379
|
+
function SidebarMenuAction({ className, render, showOnHover = false, ...props }) {
|
|
380
|
+
return useRender({
|
|
381
|
+
defaultTagName: "button",
|
|
382
|
+
props: mergeProps({ className: cn("absolute top-1.5 end-1 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground ring-sidebar-ring outline-hidden transition-transform group-data-[collapsible=icon]:hidden peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[size=default]/menu-button:top-1.5 peer-data-[size=lg]/menu-button:top-2.5 peer-data-[size=sm]/menu-button:top-1 pointer-coarse:peer-data-[size=default]/menu-button:top-3 pointer-coarse:peer-data-[size=sm]/menu-button:top-3 after:absolute after:-inset-2 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 md:after:hidden [&>svg]:size-4 [&>svg]:shrink-0", showOnHover && "group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 peer-data-active/menu-button:text-sidebar-accent-foreground aria-expanded:opacity-100 md:opacity-0", className) }, props),
|
|
383
|
+
render,
|
|
384
|
+
state: {
|
|
385
|
+
slot: "sidebar-menu-action",
|
|
386
|
+
sidebar: "menu-action"
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
function SidebarMenuBadge({ className, ...props }) {
|
|
391
|
+
return /* @__PURE__ */ jsx("div", {
|
|
392
|
+
"data-slot": "sidebar-menu-badge",
|
|
393
|
+
"data-sidebar": "menu-badge",
|
|
394
|
+
className: cn("pointer-events-none absolute end-1 flex h-5 min-w-5 items-center justify-center rounded-md px-1 text-xs font-medium text-sidebar-foreground tabular-nums select-none group-data-[collapsible=icon]:hidden peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[size=default]/menu-button:top-1.5 peer-data-[size=lg]/menu-button:top-2.5 peer-data-[size=sm]/menu-button:top-1 pointer-coarse:peer-data-[size=default]/menu-button:top-3 pointer-coarse:peer-data-[size=sm]/menu-button:top-3 peer-data-active/menu-button:text-sidebar-accent-foreground", className),
|
|
395
|
+
...props
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
function SidebarMenuSkeleton({ className, showIcon = false, ...props }) {
|
|
399
|
+
const [width] = React.useState(() => {
|
|
400
|
+
return `${Math.floor(Math.random() * 40) + 50}%`;
|
|
401
|
+
});
|
|
402
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
403
|
+
"data-slot": "sidebar-menu-skeleton",
|
|
404
|
+
"data-sidebar": "menu-skeleton",
|
|
405
|
+
className: cn("flex h-8 items-center gap-2 rounded-md px-2", className),
|
|
406
|
+
...props,
|
|
407
|
+
children: [showIcon && /* @__PURE__ */ jsx(Skeleton, {
|
|
408
|
+
className: "size-4 rounded-md",
|
|
409
|
+
"data-sidebar": "menu-skeleton-icon"
|
|
410
|
+
}), /* @__PURE__ */ jsx(Skeleton, {
|
|
411
|
+
className: "h-4 max-w-(--skeleton-width) flex-1",
|
|
412
|
+
"data-sidebar": "menu-skeleton-text",
|
|
413
|
+
style: { "--skeleton-width": width }
|
|
414
|
+
})]
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
function SidebarMenuSub({ className, ...props }) {
|
|
418
|
+
return /* @__PURE__ */ jsx("ul", {
|
|
419
|
+
"data-slot": "sidebar-menu-sub",
|
|
420
|
+
"data-sidebar": "menu-sub",
|
|
421
|
+
className: cn("mx-3.5 flex min-w-0 ltr:translate-x-px rtl:-translate-x-px flex-col gap-1 border-s border-sidebar-border px-2.5 py-0.5 group-data-[collapsible=icon]:hidden", className),
|
|
422
|
+
...props
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
function SidebarMenuSubItem({ className, ...props }) {
|
|
426
|
+
return /* @__PURE__ */ jsx("li", {
|
|
427
|
+
"data-slot": "sidebar-menu-sub-item",
|
|
428
|
+
"data-sidebar": "menu-sub-item",
|
|
429
|
+
className: cn("group/menu-sub-item relative", className),
|
|
430
|
+
...props
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
function SidebarMenuSubButton({ render, size = "md", isActive = false, className, ...props }) {
|
|
434
|
+
return useRender({
|
|
435
|
+
defaultTagName: "a",
|
|
436
|
+
props: mergeProps({
|
|
437
|
+
"aria-current": isActive ? "page" : void 0,
|
|
438
|
+
className: cn("flex h-7 min-w-0 ltr:-translate-x-px rtl:translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 text-sidebar-foreground ring-sidebar-ring outline-hidden group-data-[collapsible=icon]:hidden hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[size=md]:text-sm data-[size=sm]:text-xs data-active:bg-sidebar-accent data-active:text-sidebar-accent-foreground pointer-coarse:min-h-11 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0 [&>svg]:text-sidebar-accent-foreground", className)
|
|
439
|
+
}, props),
|
|
440
|
+
render,
|
|
441
|
+
state: {
|
|
442
|
+
slot: "sidebar-menu-sub-button",
|
|
443
|
+
sidebar: "menu-sub-button",
|
|
444
|
+
size,
|
|
445
|
+
active: isActive
|
|
446
|
+
}
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
export { Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, useSidebar };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
// src/sidebar/use-mobile.ts
|
|
4
|
+
const MOBILE_BREAKPOINT = 768;
|
|
5
|
+
function subscribe(onChange) {
|
|
6
|
+
const mql = window.matchMedia(`(max-width: 767px)`);
|
|
7
|
+
mql.addEventListener("change", onChange);
|
|
8
|
+
return () => mql.removeEventListener("change", onChange);
|
|
9
|
+
}
|
|
10
|
+
function useIsMobile() {
|
|
11
|
+
return React.useSyncExternalStore(subscribe, () => window.innerWidth < MOBILE_BREAKPOINT, () => false);
|
|
12
|
+
}
|
|
13
|
+
export { useIsMobile };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/* @nsaa/core: Tailwind sources for date-range-picker (generated). */
|
|
2
|
+
@source "../button/button.js";
|
|
3
|
+
@source "../calendar/calendar.js";
|
|
4
|
+
@source "../date-range-picker/date-range-picker.js";
|
|
5
|
+
@source "../date-range-picker/presets.js";
|
|
6
|
+
@source "../drawer/drawer.js";
|
|
7
|
+
@source "../lib/cn.js";
|
|
8
|
+
@source "../lib/control-defaults.js";
|
|
9
|
+
@source "../lib/use-press.js";
|
|
10
|
+
@source "../loaders/arc.js";
|
|
11
|
+
@source "../loaders/bouncing-dots.js";
|
|
12
|
+
@source "../loaders/cap.js";
|
|
13
|
+
@source "../loaders/circular-dots.js";
|
|
14
|
+
@source "../loaders/classic.js";
|
|
15
|
+
@source "../loaders/easing.js";
|
|
16
|
+
@source "../loaders/fade.js";
|
|
17
|
+
@source "../loaders/frame.js";
|
|
18
|
+
@source "../loaders/motion.js";
|
|
19
|
+
@source "../loaders/orbit.js";
|
|
20
|
+
@source "../loaders/pulse.js";
|
|
21
|
+
@source "../loaders/ring.js";
|
|
22
|
+
@source "../loaders/wave.js";
|
|
23
|
+
@source "../popover/popover.js";
|
|
24
|
+
@source "../sound/sound-map.js";
|
|
25
|
+
@source "../sound/sound.js";
|
|
26
|
+
@source "../spinner/loader-provider.js";
|
|
27
|
+
@source "../spinner/registry.js";
|
|
28
|
+
@source "../spinner/spinner.js";
|
|
29
|
+
@source "../tokens/dist/motion.js";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/* @nsaa/core: Tailwind sources for sidebar (generated). */
|
|
2
|
+
@source "../button/button.js";
|
|
3
|
+
@source "../drawer/drawer.js";
|
|
4
|
+
@source "../input/input.js";
|
|
5
|
+
@source "../lib/cn.js";
|
|
6
|
+
@source "../lib/control-defaults.js";
|
|
7
|
+
@source "../lib/dev.js";
|
|
8
|
+
@source "../lib/use-press.js";
|
|
9
|
+
@source "../loaders/arc.js";
|
|
10
|
+
@source "../loaders/bouncing-dots.js";
|
|
11
|
+
@source "../loaders/cap.js";
|
|
12
|
+
@source "../loaders/circular-dots.js";
|
|
13
|
+
@source "../loaders/classic.js";
|
|
14
|
+
@source "../loaders/easing.js";
|
|
15
|
+
@source "../loaders/fade.js";
|
|
16
|
+
@source "../loaders/frame.js";
|
|
17
|
+
@source "../loaders/motion.js";
|
|
18
|
+
@source "../loaders/orbit.js";
|
|
19
|
+
@source "../loaders/pulse.js";
|
|
20
|
+
@source "../loaders/ring.js";
|
|
21
|
+
@source "../loaders/wave.js";
|
|
22
|
+
@source "../separator/separator.js";
|
|
23
|
+
@source "../sidebar/sidebar.js";
|
|
24
|
+
@source "../sidebar/use-mobile.js";
|
|
25
|
+
@source "../skeleton/skeleton.js";
|
|
26
|
+
@source "../sound/sound-map.js";
|
|
27
|
+
@source "../sound/sound.js";
|
|
28
|
+
@source "../spinner/loader-provider.js";
|
|
29
|
+
@source "../spinner/registry.js";
|
|
30
|
+
@source "../spinner/spinner.js";
|
|
31
|
+
@source "../tokens/dist/motion.js";
|
|
32
|
+
@source "../tooltip/tooltip.js";
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
|
|
2
|
+
import { Stat, StatAction, StatActionProps, StatChange, StatChangeProps, StatDescription, StatGroup, StatGroupProps, StatIcon, StatLabel, StatProps, StatValue } from "./stat.js";
|
|
3
|
+
export { Stat, StatAction, type StatActionProps, StatChange, type StatChangeProps, StatDescription, StatGroup, type StatGroupProps, StatIcon, StatLabel, type StatProps, StatValue };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
|
|
2
|
+
import { useRender } from "@base-ui/react/use-render";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
type StatProps = React.ComponentProps<"div"> & {
|
|
5
|
+
/** `default` or `sm` (tighter padding, one type step smaller). */
|
|
6
|
+
size?: "default" | "sm";
|
|
7
|
+
/** `card` (default): its own bordered surface. `plain`: no surface, for use inside another Card. */
|
|
8
|
+
variant?: "card" | "plain";
|
|
9
|
+
/** Shows Skeletons in place of each part, at the same height, and sets `aria-busy`. */
|
|
10
|
+
loading?: boolean;
|
|
11
|
+
};
|
|
12
|
+
declare function Stat({ className, size, variant, loading, children, ...props }: StatProps): React.JSX.Element;
|
|
13
|
+
declare function StatLabel({ className, children, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
14
|
+
/** Tabular figures; a long value drops one type step in a narrow tile instead of truncating. */
|
|
15
|
+
declare function StatValue({ className, children, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
16
|
+
type StatChangeProps = Omit<React.ComponentProps<"div">, "children"> & {
|
|
17
|
+
/** Sets the arrow. */
|
|
18
|
+
direction: "up" | "down" | "flat";
|
|
19
|
+
/** Sets the colour, separately from the direction, because a rise can be bad. Defaults: up positive, down negative, flat neutral. */
|
|
20
|
+
tone?: "positive" | "negative" | "neutral";
|
|
21
|
+
/** The change, already formatted ("12%", "GH₵400"). */
|
|
22
|
+
value: React.ReactNode;
|
|
23
|
+
/** What it is compared with ("vs last month"). */
|
|
24
|
+
label?: React.ReactNode;
|
|
25
|
+
/** The words screen readers hear for each direction. */
|
|
26
|
+
labels?: {
|
|
27
|
+
up?: string;
|
|
28
|
+
down?: string;
|
|
29
|
+
flat?: string;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
declare function StatChange({ className, direction, tone, value, label, labels, ...props }: StatChangeProps): React.JSX.Element;
|
|
33
|
+
declare function StatDescription({ className, children, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
34
|
+
declare function StatIcon({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
35
|
+
type StatActionProps = useRender.ComponentProps<"button"> & {
|
|
36
|
+
/** Stretches the action over the whole tile, so the tile is one link (keep it the only interactive element). */
|
|
37
|
+
cover?: boolean;
|
|
38
|
+
};
|
|
39
|
+
/** A link or button at the foot of the tile. Pass `render={<a href="…" />}` for a link. */
|
|
40
|
+
declare function StatAction({ className, render, cover, ...props }: StatActionProps): React.JSX.Element;
|
|
41
|
+
type StatGroupProps = React.ComponentProps<"div"> & {
|
|
42
|
+
/** One surface with hairlines between tiles; put `variant="plain"` Stats inside. */
|
|
43
|
+
dividers?: boolean;
|
|
44
|
+
};
|
|
45
|
+
/** Lays tiles out by its own width (1 to 4 columns), so a sidebar never breaks the grid. */
|
|
46
|
+
declare function StatGroup({ className, dividers, children, ...props }: StatGroupProps): React.JSX.Element;
|
|
47
|
+
export { Stat, StatAction, type StatActionProps, StatChange, type StatChangeProps, StatDescription, StatGroup, type StatGroupProps, StatIcon, StatLabel, type StatProps, StatValue };
|