@nsaa/core 0.1.0-alpha.3 → 0.1.0-alpha.5
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/LICENSE +1 -1
- package/NOTICE +27 -0
- package/dist/alert/alert.d.ts +27 -3
- package/dist/alert/alert.js +198 -17
- package/dist/alert/index.d.ts +2 -2
- package/dist/badge/badge.d.ts +2 -2
- package/dist/badge/badge.js +1 -1
- package/dist/button/button.d.ts +2 -2
- package/dist/button/button.js +2 -1
- package/dist/date-range-picker/date-range-picker.d.ts +55 -0
- package/dist/date-range-picker/date-range-picker.js +359 -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/empty/empty.d.ts +1 -1
- package/dist/empty/empty.js +2 -2
- package/dist/index.d.ts +17 -4
- package/dist/index.js +12 -5
- package/dist/input-group/input-group.d.ts +1 -1
- package/dist/input-otp/input-otp.js +1 -1
- 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/alert.css +20 -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 +2 -2
- package/package.json +5 -2
- package/src/feel.css +131 -3
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../lib/cn.js";
|
|
3
|
+
import { Skeleton } from "../skeleton/skeleton.js";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import { mergeProps } from "@base-ui/react/merge-props";
|
|
6
|
+
import { useRender } from "@base-ui/react/use-render";
|
|
7
|
+
import * as React from "react";
|
|
8
|
+
// src/stat/stat.tsx
|
|
9
|
+
const StatContext = React.createContext({
|
|
10
|
+
loading: false,
|
|
11
|
+
size: "default"
|
|
12
|
+
});
|
|
13
|
+
/** While loading, a part keeps its own line box and shows a Skeleton in it, so the tile does not
|
|
14
|
+
change height when the data arrives. */
|
|
15
|
+
function Slot({ width, height = "h-[1lh]", children }) {
|
|
16
|
+
const { loading } = React.useContext(StatContext);
|
|
17
|
+
return loading ? /* @__PURE__ */ jsx(Skeleton, { className: cn("inline-block align-top", height, width) }) : children;
|
|
18
|
+
}
|
|
19
|
+
function Stat({ className, size = "default", variant = "card", loading = false, children, ...props }) {
|
|
20
|
+
return /* @__PURE__ */ jsx(StatContext.Provider, {
|
|
21
|
+
value: {
|
|
22
|
+
loading,
|
|
23
|
+
size
|
|
24
|
+
},
|
|
25
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
26
|
+
"data-slot": "stat",
|
|
27
|
+
"data-size": size,
|
|
28
|
+
"data-variant": variant,
|
|
29
|
+
"aria-busy": loading || void 0,
|
|
30
|
+
className: cn("group/stat @container/stat relative flex min-w-0 flex-col gap-1 text-sm text-card-foreground", variant === "card" && "rounded-xl bg-card ring-1 ring-foreground/10", variant === "card" && (size === "sm" ? "p-3" : "p-4"), className),
|
|
31
|
+
...props,
|
|
32
|
+
children
|
|
33
|
+
})
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function StatLabel({ className, children, ...props }) {
|
|
37
|
+
return /* @__PURE__ */ jsx("div", {
|
|
38
|
+
"data-slot": "stat-label",
|
|
39
|
+
className: cn("pe-8 font-medium text-muted-foreground", className),
|
|
40
|
+
...props,
|
|
41
|
+
children: /* @__PURE__ */ jsx(Slot, {
|
|
42
|
+
width: "w-24",
|
|
43
|
+
children
|
|
44
|
+
})
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
/** Tabular figures; a long value drops one type step in a narrow tile instead of truncating. */
|
|
48
|
+
function StatValue({ className, children, ...props }) {
|
|
49
|
+
const { size } = React.useContext(StatContext);
|
|
50
|
+
return /* @__PURE__ */ jsx("div", {
|
|
51
|
+
"data-slot": "stat-value",
|
|
52
|
+
className: cn("font-semibold tracking-tight tabular-nums", size === "sm" ? "text-xl @max-[12rem]/stat:text-lg" : "text-2xl @max-[14rem]/stat:text-xl", className),
|
|
53
|
+
...props,
|
|
54
|
+
children: /* @__PURE__ */ jsx(Slot, {
|
|
55
|
+
width: "w-32",
|
|
56
|
+
children
|
|
57
|
+
})
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
const ARROW = {
|
|
61
|
+
up: "M12 19V5m-6 6 6-6 6 6",
|
|
62
|
+
down: "M12 5v14m6-6-6 6-6-6",
|
|
63
|
+
flat: "M5 12h14"
|
|
64
|
+
};
|
|
65
|
+
const TONE = {
|
|
66
|
+
positive: "bg-positive-subtle text-on-positive-subtle-foreground",
|
|
67
|
+
negative: "bg-danger-subtle text-on-danger-subtle-foreground",
|
|
68
|
+
neutral: "bg-muted text-muted-foreground"
|
|
69
|
+
};
|
|
70
|
+
function StatChange({ className, direction, tone, value, label, labels, ...props }) {
|
|
71
|
+
const resolved = tone ?? (direction === "up" ? "positive" : direction === "down" ? "negative" : "neutral");
|
|
72
|
+
const words = {
|
|
73
|
+
up: "up",
|
|
74
|
+
down: "down",
|
|
75
|
+
flat: "unchanged",
|
|
76
|
+
...labels
|
|
77
|
+
};
|
|
78
|
+
return /* @__PURE__ */ jsx("div", {
|
|
79
|
+
"data-slot": "stat-change",
|
|
80
|
+
"data-direction": direction,
|
|
81
|
+
"data-tone": resolved,
|
|
82
|
+
className: cn("flex flex-wrap items-center gap-x-1.5 gap-y-0.5 text-xs", className),
|
|
83
|
+
...props,
|
|
84
|
+
children: /* @__PURE__ */ jsxs(Slot, {
|
|
85
|
+
width: "w-28",
|
|
86
|
+
height: "h-5",
|
|
87
|
+
children: [/* @__PURE__ */ jsxs("span", {
|
|
88
|
+
className: cn("inline-flex items-center gap-0.5 rounded-md px-1.5 py-0.5 font-medium tabular-nums", TONE[resolved]),
|
|
89
|
+
children: [
|
|
90
|
+
/* @__PURE__ */ jsx("svg", {
|
|
91
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
92
|
+
viewBox: "0 0 24 24",
|
|
93
|
+
fill: "none",
|
|
94
|
+
stroke: "currentColor",
|
|
95
|
+
strokeWidth: "2",
|
|
96
|
+
strokeLinecap: "round",
|
|
97
|
+
strokeLinejoin: "round",
|
|
98
|
+
"aria-hidden": "true",
|
|
99
|
+
className: "size-3",
|
|
100
|
+
children: /* @__PURE__ */ jsx("path", { d: ARROW[direction] })
|
|
101
|
+
}),
|
|
102
|
+
/* @__PURE__ */ jsxs("span", {
|
|
103
|
+
className: "sr-only",
|
|
104
|
+
children: [words[direction], " "]
|
|
105
|
+
}),
|
|
106
|
+
value
|
|
107
|
+
]
|
|
108
|
+
}), label && /* @__PURE__ */ jsx("span", {
|
|
109
|
+
className: "text-muted-foreground",
|
|
110
|
+
children: label
|
|
111
|
+
})]
|
|
112
|
+
})
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
function StatDescription({ className, children, ...props }) {
|
|
116
|
+
return /* @__PURE__ */ jsx("div", {
|
|
117
|
+
"data-slot": "stat-description",
|
|
118
|
+
className: cn("text-muted-foreground", className),
|
|
119
|
+
...props,
|
|
120
|
+
children: /* @__PURE__ */ jsx(Slot, {
|
|
121
|
+
width: "w-40",
|
|
122
|
+
children
|
|
123
|
+
})
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
function StatIcon({ className, ...props }) {
|
|
127
|
+
return /* @__PURE__ */ jsx("div", {
|
|
128
|
+
"data-slot": "stat-icon",
|
|
129
|
+
"aria-hidden": "true",
|
|
130
|
+
className: cn("absolute end-4 top-4 text-muted-foreground group-data-[size=sm]/stat:end-3 group-data-[size=sm]/stat:top-3 [&_svg:not([class*='size-'])]:size-4", className),
|
|
131
|
+
...props
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
/** A link or button at the foot of the tile. Pass `render={<a href="…" />}` for a link. */
|
|
135
|
+
function StatAction({ className, render, cover = false, ...props }) {
|
|
136
|
+
const { loading } = React.useContext(StatContext);
|
|
137
|
+
const element = useRender({
|
|
138
|
+
defaultTagName: "button",
|
|
139
|
+
props: mergeProps({ className: cn("mt-1 w-fit rounded-sm text-sm font-medium underline-offset-4 outline-none hover:underline focus-visible:ring-3 focus-visible:ring-ring/50", cover && "after:absolute after:inset-0 after:rounded-xl", className) }, render ? props : {
|
|
140
|
+
type: "button",
|
|
141
|
+
...props
|
|
142
|
+
}),
|
|
143
|
+
render,
|
|
144
|
+
state: { slot: "stat-action" }
|
|
145
|
+
});
|
|
146
|
+
if (loading) return /* @__PURE__ */ jsx(Skeleton, { className: "mt-1 h-[1lh] w-12 text-sm" });
|
|
147
|
+
return element;
|
|
148
|
+
}
|
|
149
|
+
/** Lays tiles out by its own width (1 to 4 columns), so a sidebar never breaks the grid. */
|
|
150
|
+
function StatGroup({ className, dividers = false, children, ...props }) {
|
|
151
|
+
return /* @__PURE__ */ jsx("div", {
|
|
152
|
+
"data-slot": "stat-group",
|
|
153
|
+
className: cn("@container/stat-group", className),
|
|
154
|
+
...props,
|
|
155
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
156
|
+
className: cn("grid grid-cols-1 @lg/stat-group:grid-cols-2 @3xl/stat-group:grid-cols-3 @5xl/stat-group:grid-cols-4", dividers ? "gap-px overflow-hidden rounded-xl bg-border ring-1 ring-foreground/10 *:data-[slot=stat]:bg-card *:data-[slot=stat]:p-4" : "gap-4"),
|
|
157
|
+
children
|
|
158
|
+
})
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
export { Stat, StatAction, StatChange, StatDescription, StatGroup, StatIcon, StatLabel, StatValue };
|
|
@@ -36,6 +36,24 @@ const spring = {
|
|
|
36
36
|
"bounce": 0
|
|
37
37
|
}
|
|
38
38
|
};
|
|
39
|
+
const duration = {
|
|
40
|
+
"instant": 0,
|
|
41
|
+
"press": 150,
|
|
42
|
+
"tooltip": 125,
|
|
43
|
+
"tooltip-exit": 100,
|
|
44
|
+
"exit": 100,
|
|
45
|
+
"char": 120,
|
|
46
|
+
"fast": 150,
|
|
47
|
+
"base": 200,
|
|
48
|
+
"slow": 250,
|
|
49
|
+
"drawer": 300,
|
|
50
|
+
"chunk": 300,
|
|
51
|
+
"marketing": 400,
|
|
52
|
+
"marketing-slow": 500,
|
|
53
|
+
"spin": 800,
|
|
54
|
+
"caret": 1250,
|
|
55
|
+
"feedback-hold": 1500
|
|
56
|
+
};
|
|
39
57
|
const scale = {
|
|
40
58
|
"press": .97,
|
|
41
59
|
"enter": .95,
|
|
@@ -123,4 +141,4 @@ const sound = {
|
|
|
123
141
|
"progress.loop": "loading"
|
|
124
142
|
}
|
|
125
143
|
};
|
|
126
|
-
export { blur, loader, scale, sound, spring };
|
|
144
|
+
export { blur, duration, loader, scale, sound, spring };
|
|
@@ -3,8 +3,8 @@ import { cn } from "../lib/cn.js";
|
|
|
3
3
|
import { useControlDefaults } from "../lib/control-defaults.js";
|
|
4
4
|
import { Button } from "../button/button.js";
|
|
5
5
|
import { Kbd } from "../kbd/kbd.js";
|
|
6
|
-
import { ariaShortcut, formatShortcut } from "../lib/shortcut.js";
|
|
7
6
|
import { Tooltip, TooltipContent, TooltipTrigger } from "../tooltip/tooltip.js";
|
|
7
|
+
import { ariaShortcut, formatShortcut } from "../lib/shortcut.js";
|
|
8
8
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
9
9
|
import { Toggle } from "@base-ui/react/toggle";
|
|
10
10
|
// src/toolbar/toolbar-item.tsx
|
package/dist/toolbar/toolbar.js
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
import { cn } from "../lib/cn.js";
|
|
3
3
|
import { ControlDefaultsContext, useControlDefaults } from "../lib/control-defaults.js";
|
|
4
4
|
import { buttonVariants } from "../button/button.js";
|
|
5
|
+
import { mergeRefs } from "../lib/merge-refs.js";
|
|
5
6
|
import { Input } from "../input/input.js";
|
|
6
7
|
import { DropdownMenuCheckboxItem, DropdownMenuItem, DropdownMenuShortcut } from "../dropdown-menu/dropdown-menu.js";
|
|
8
|
+
import { TooltipProvider } from "../tooltip/tooltip.js";
|
|
7
9
|
import { tv } from "../lib/tv.js";
|
|
8
10
|
import { ariaShortcut, formatShortcut } from "../lib/shortcut.js";
|
|
9
|
-
import { TooltipProvider } from "../tooltip/tooltip.js";
|
|
10
11
|
import { ToolbarItem } from "./toolbar-item.js";
|
|
11
12
|
import { OverflowContext, OverflowMore, OverflowStore, useOverflowUnit } from "./overflow.js";
|
|
12
|
-
import { mergeRefs } from "../lib/merge-refs.js";
|
|
13
13
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
14
14
|
import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
15
15
|
import { Toolbar } from "@base-ui/react/toolbar";
|
package/package.json
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nsaa/core",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.5",
|
|
4
4
|
"description": "Nsaa core components: accessible, token-driven, animated to the Nsaa feel spec.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"sideEffects": [
|
|
8
8
|
"**/*.css",
|
|
9
|
+
"./dist/index.js",
|
|
10
|
+
"./src/index.ts",
|
|
9
11
|
"./dist/lib/track-input-modality.js",
|
|
12
|
+
"./src/lib/track-input-modality.ts",
|
|
10
13
|
"./dist/spinner/spinner.js"
|
|
11
14
|
],
|
|
12
15
|
"files": [
|
|
@@ -50,7 +53,7 @@
|
|
|
50
53
|
"tailwind-merge": "^3.7.0",
|
|
51
54
|
"tailwind-variants": "^3.3.1",
|
|
52
55
|
"uisfx": "0.4.0",
|
|
53
|
-
"@nsaa/tokens": "^0.1.0-alpha.
|
|
56
|
+
"@nsaa/tokens": "^0.1.0-alpha.5"
|
|
54
57
|
},
|
|
55
58
|
"devDependencies": {
|
|
56
59
|
"@testing-library/jest-dom": "^7.0.1",
|
package/src/feel.css
CHANGED
|
@@ -19,6 +19,29 @@
|
|
|
19
19
|
* own unlayered CSS still wins.
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
+
/* ------------------------------------------------------------------ controls set their text colour (#155)
|
|
23
|
+
shadcn leaves these inherited, so a page with a hard-coded text colour made Input and the outline
|
|
24
|
+
Button unreadable in dark mode (Corvta). Every form control, and every Button / Toggle variant that
|
|
25
|
+
paints a surface, takes its paired foreground at rest. Tailwind's components layer, below
|
|
26
|
+
utilities: a variant's own text-* class, hover and placeholder colours, and an app's className
|
|
27
|
+
still win. Ghost and link stay inherited by design (they sit on someone else's surface). */
|
|
28
|
+
@layer components {
|
|
29
|
+
:is(
|
|
30
|
+
[data-slot="input"],
|
|
31
|
+
[data-slot="textarea"],
|
|
32
|
+
[data-slot="select-trigger"],
|
|
33
|
+
[data-slot="native-select"],
|
|
34
|
+
[data-slot="input-group"],
|
|
35
|
+
[data-slot="input-group-control"],
|
|
36
|
+
[data-slot="input-otp-slot"],
|
|
37
|
+
[data-slot="combobox-chips"],
|
|
38
|
+
[data-slot="button"][data-variant="outline"],
|
|
39
|
+
[data-slot="toggle-group"][data-variant="outline"]
|
|
40
|
+
) {
|
|
41
|
+
color: var(--foreground);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
22
45
|
/* ------------------------------------------------------------------ coarse-pointer hit areas (#144)
|
|
23
46
|
DESIGN.md: 44 px targets on coarse pointers. An invisible ::before, centred, at least 44 × 44 and
|
|
24
47
|
never smaller than the control; layout is unchanged. ::before because base-nova already uses
|
|
@@ -53,6 +76,17 @@
|
|
|
53
76
|
}
|
|
54
77
|
}
|
|
55
78
|
|
|
79
|
+
/* Alert links (#148): 44 px tall, their own width (the AlertLinks gap keeps them apart);
|
|
80
|
+
::after, as ::before draws the separator. */
|
|
81
|
+
[data-slot="alert-link"]::after {
|
|
82
|
+
content: "";
|
|
83
|
+
position: absolute;
|
|
84
|
+
inset-inline: 0;
|
|
85
|
+
top: 50%;
|
|
86
|
+
height: calc(var(--spacing) * 11);
|
|
87
|
+
translate: 0 -50%;
|
|
88
|
+
}
|
|
89
|
+
|
|
56
90
|
:is([data-slot="input"], [data-slot="input-group"]) {
|
|
57
91
|
min-height: calc(var(--spacing) * 11);
|
|
58
92
|
}
|
|
@@ -142,6 +176,25 @@
|
|
|
142
176
|
}
|
|
143
177
|
}
|
|
144
178
|
|
|
179
|
+
/* ---------------------------------------------------------------- Sidebar (#153)
|
|
180
|
+
Collapse and expand: shadcn's 200 ms linear -> duration.base, ease.inOut (an on-screen move).
|
|
181
|
+
base-nova animates the width and the container's left / right (layout exception, #153); the
|
|
182
|
+
rail's transition-all narrows to its translate and background. */
|
|
183
|
+
:is(
|
|
184
|
+
[data-slot="sidebar-gap"],
|
|
185
|
+
[data-slot="sidebar-container"],
|
|
186
|
+
[data-slot="sidebar-group-label"],
|
|
187
|
+
[data-slot="sidebar-menu-button"],
|
|
188
|
+
[data-slot="sidebar-rail"]
|
|
189
|
+
) {
|
|
190
|
+
transition-duration: calc(var(--nsaa-duration-base) * var(--nsaa-time-scale));
|
|
191
|
+
transition-timing-function: var(--nsaa-ease-in-out);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
[data-slot="sidebar-rail"] {
|
|
195
|
+
transition-property: translate, background-color;
|
|
196
|
+
}
|
|
197
|
+
|
|
145
198
|
/* ---------------------------------------------------------------- Drawer
|
|
146
199
|
shadcn's 450 ms → ease.drawer, drawer 300 in, base out; a swipe-dismiss releases on
|
|
147
200
|
spring.sheet, scaled by Base UI's release strength. Stacking and swipe variables untouched. */
|
|
@@ -461,6 +514,13 @@
|
|
|
461
514
|
}
|
|
462
515
|
}
|
|
463
516
|
|
|
517
|
+
/* Dismiss (#148): opacity only, duration.fast, then it unmounts. No height animation (not a
|
|
518
|
+
named layout exception); instant under reduced motion and after keyboard input. */
|
|
519
|
+
[data-slot="alert"][data-ending-style] {
|
|
520
|
+
opacity: 0;
|
|
521
|
+
transition-duration: calc(var(--nsaa-duration-fast) * var(--nsaa-time-scale));
|
|
522
|
+
}
|
|
523
|
+
|
|
464
524
|
/* ---------------------------------------------------------------- Avatar, Skeleton, Spinner
|
|
465
525
|
A loaded image fades in 150; Skeleton keeps its pulse; Spinner turns at duration.spin. */
|
|
466
526
|
/* SkeletonContent: what replaces a Skeleton fades in the same way (#128). */
|
|
@@ -474,6 +534,30 @@
|
|
|
474
534
|
}
|
|
475
535
|
}
|
|
476
536
|
|
|
537
|
+
/* ---------------------------------------------------------------- Progress and Meter (#153)
|
|
538
|
+
A Meter grows from its start once on first paint (scale, ease-out); later value changes ease
|
|
539
|
+
the width. Progress narrows shadcn's transition-all to the width. None under reduced motion. */
|
|
540
|
+
:is(
|
|
541
|
+
[data-slot="progress-indicator"],
|
|
542
|
+
[data-slot="meter-indicator"],
|
|
543
|
+
[data-slot="meter-segment"]
|
|
544
|
+
) {
|
|
545
|
+
transition-property: width, flex-basis, scale;
|
|
546
|
+
transition-duration: calc(var(--nsaa-duration-chunk) * var(--nsaa-time-scale));
|
|
547
|
+
transition-timing-function: var(--nsaa-ease-out);
|
|
548
|
+
transform-origin: left center;
|
|
549
|
+
|
|
550
|
+
&:dir(rtl) {
|
|
551
|
+
transform-origin: right center;
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
:is([data-slot="meter-indicator"], [data-slot="meter-segment"]) {
|
|
556
|
+
@starting-style {
|
|
557
|
+
scale: 0 1;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
|
|
477
561
|
/* Spinner (Phase 5, #113): loaders bring their own keyframes; the "lucide" glyph turns at
|
|
478
562
|
duration.spin and follows the cascading speed and play state like the loaders do. */
|
|
479
563
|
/* Pausing: data-loader-paused on any ancestor (LoaderProvider paused, a Spinner offscreen or in a
|
|
@@ -601,6 +685,18 @@
|
|
|
601
685
|
transition-duration: 0s;
|
|
602
686
|
}
|
|
603
687
|
|
|
688
|
+
/* Sidebar: collapse and expand snap. */
|
|
689
|
+
&
|
|
690
|
+
:is(
|
|
691
|
+
[data-slot="sidebar-gap"],
|
|
692
|
+
[data-slot="sidebar-container"],
|
|
693
|
+
[data-slot="sidebar-group-label"],
|
|
694
|
+
[data-slot="sidebar-menu-button"],
|
|
695
|
+
[data-slot="sidebar-rail"]
|
|
696
|
+
) {
|
|
697
|
+
transition-duration: 0s;
|
|
698
|
+
}
|
|
699
|
+
|
|
604
700
|
/* Drawer: a fade. Dragging still works 1:1 and a release that closes keeps its path, but
|
|
605
701
|
the stack, snap points and height don't slide; nothing is a spring. */
|
|
606
702
|
& :is([data-slot="drawer-popup"], [data-slot="drawer-overlay"]) {
|
|
@@ -673,7 +769,10 @@
|
|
|
673
769
|
[data-slot="input-otp-char"],
|
|
674
770
|
[data-slot="avatar-image"],
|
|
675
771
|
[data-slot="skeleton-content"],
|
|
676
|
-
[data-slot="accordion-trigger-icon"]
|
|
772
|
+
[data-slot="accordion-trigger-icon"],
|
|
773
|
+
[data-slot="progress-indicator"],
|
|
774
|
+
[data-slot="meter-indicator"],
|
|
775
|
+
[data-slot="meter-segment"]
|
|
677
776
|
) {
|
|
678
777
|
transition-property: none;
|
|
679
778
|
}
|
|
@@ -710,6 +809,10 @@
|
|
|
710
809
|
}
|
|
711
810
|
}
|
|
712
811
|
|
|
812
|
+
& [data-slot="alert"][data-ending-style] {
|
|
813
|
+
transition-duration: 0s;
|
|
814
|
+
}
|
|
815
|
+
|
|
713
816
|
& :is([data-slot="skeleton"], [data-loader="lucide"]) {
|
|
714
817
|
animation: none;
|
|
715
818
|
}
|
|
@@ -765,6 +868,18 @@
|
|
|
765
868
|
transition-duration: 0s;
|
|
766
869
|
}
|
|
767
870
|
|
|
871
|
+
/* Sidebar: collapse and expand snap. */
|
|
872
|
+
&
|
|
873
|
+
:is(
|
|
874
|
+
[data-slot="sidebar-gap"],
|
|
875
|
+
[data-slot="sidebar-container"],
|
|
876
|
+
[data-slot="sidebar-group-label"],
|
|
877
|
+
[data-slot="sidebar-menu-button"],
|
|
878
|
+
[data-slot="sidebar-rail"]
|
|
879
|
+
) {
|
|
880
|
+
transition-duration: 0s;
|
|
881
|
+
}
|
|
882
|
+
|
|
768
883
|
/* Drawer: a fade. Dragging still works 1:1 and a release that closes keeps its path, but
|
|
769
884
|
the stack, snap points and height don't slide; nothing is a spring. */
|
|
770
885
|
& :is([data-slot="drawer-popup"], [data-slot="drawer-overlay"]) {
|
|
@@ -837,7 +952,10 @@
|
|
|
837
952
|
[data-slot="input-otp-char"],
|
|
838
953
|
[data-slot="avatar-image"],
|
|
839
954
|
[data-slot="skeleton-content"],
|
|
840
|
-
[data-slot="accordion-trigger-icon"]
|
|
955
|
+
[data-slot="accordion-trigger-icon"],
|
|
956
|
+
[data-slot="progress-indicator"],
|
|
957
|
+
[data-slot="meter-indicator"],
|
|
958
|
+
[data-slot="meter-segment"]
|
|
841
959
|
) {
|
|
842
960
|
transition-property: none;
|
|
843
961
|
}
|
|
@@ -874,6 +992,10 @@
|
|
|
874
992
|
}
|
|
875
993
|
}
|
|
876
994
|
|
|
995
|
+
& [data-slot="alert"][data-ending-style] {
|
|
996
|
+
transition-duration: 0s;
|
|
997
|
+
}
|
|
998
|
+
|
|
877
999
|
& :is([data-slot="skeleton"], [data-loader="lucide"]) {
|
|
878
1000
|
animation: none;
|
|
879
1001
|
}
|
|
@@ -933,7 +1055,13 @@
|
|
|
933
1055
|
[data-slot="drawer-overlay"],
|
|
934
1056
|
[data-slot="accordion-content"],
|
|
935
1057
|
[data-slot="collapsible-content"],
|
|
936
|
-
[data-slot="skeleton-content"]
|
|
1058
|
+
[data-slot="skeleton-content"],
|
|
1059
|
+
[data-slot="alert"][data-ending-style],
|
|
1060
|
+
[data-slot="sidebar-gap"],
|
|
1061
|
+
[data-slot="sidebar-container"],
|
|
1062
|
+
[data-slot="sidebar-group-label"],
|
|
1063
|
+
[data-slot="sidebar-menu-button"],
|
|
1064
|
+
[data-slot="sidebar-rail"]
|
|
937
1065
|
) {
|
|
938
1066
|
transition-duration: 0s;
|
|
939
1067
|
}
|