@stasho/ds 0.11.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stasho/ds",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "stasho design system",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
"./pagination": "./src/components/pagination/pagination.tsx",
|
|
49
49
|
"./copyable-text": "./src/components/copyable-text/copyable-text.tsx",
|
|
50
50
|
"./dialog": "./src/components/dialog/dialog.tsx",
|
|
51
|
+
"./drawer": "./src/components/drawer/drawer.tsx",
|
|
51
52
|
"./logo": "./src/components/logo/logo.tsx",
|
|
52
53
|
"./progress-bar": "./src/components/progress-bar/progress-bar.tsx",
|
|
53
54
|
"./stepper": "./src/components/stepper/stepper.tsx",
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
forwardRef,
|
|
5
|
+
type ComponentPropsWithoutRef,
|
|
6
|
+
} from "react";
|
|
7
|
+
import { Dialog as DialogPrimitive } from "radix-ui";
|
|
8
|
+
import { X } from "@phosphor-icons/react";
|
|
9
|
+
import { cn } from "@ac/lib/cn";
|
|
10
|
+
|
|
11
|
+
/* ── Direct re-exports ─────────────────────────── */
|
|
12
|
+
|
|
13
|
+
const Drawer = DialogPrimitive.Root;
|
|
14
|
+
const DrawerTrigger = DialogPrimitive.Trigger;
|
|
15
|
+
const DrawerClose = DialogPrimitive.Close;
|
|
16
|
+
|
|
17
|
+
/* ── DrawerContent (Portal + Overlay + Content) ── */
|
|
18
|
+
|
|
19
|
+
type DrawerSide = "bottom" | "left" | "right";
|
|
20
|
+
|
|
21
|
+
const sideClasses: Record<DrawerSide, string> = {
|
|
22
|
+
bottom: cn(
|
|
23
|
+
"inset-x-0 bottom-0 max-h-[85dvh] w-full rounded-t-xl border-t",
|
|
24
|
+
"motion-safe:data-[state=open]:animate-drawer-in-bottom",
|
|
25
|
+
"motion-safe:data-[state=closed]:animate-drawer-out-bottom",
|
|
26
|
+
),
|
|
27
|
+
left: cn(
|
|
28
|
+
"inset-y-0 left-0 h-dvh w-80 max-w-[85vw] border-r",
|
|
29
|
+
"motion-safe:data-[state=open]:animate-drawer-in-left",
|
|
30
|
+
"motion-safe:data-[state=closed]:animate-drawer-out-left",
|
|
31
|
+
),
|
|
32
|
+
right: cn(
|
|
33
|
+
"inset-y-0 right-0 h-dvh w-80 max-w-[85vw] border-l",
|
|
34
|
+
"motion-safe:data-[state=open]:animate-drawer-in-right",
|
|
35
|
+
"motion-safe:data-[state=closed]:animate-drawer-out-right",
|
|
36
|
+
),
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
type DrawerContentProps = ComponentPropsWithoutRef<
|
|
40
|
+
typeof DialogPrimitive.Content
|
|
41
|
+
> & {
|
|
42
|
+
side?: DrawerSide;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const DrawerContent = forwardRef<HTMLDivElement, DrawerContentProps>(
|
|
46
|
+
({ className, children, side = "bottom", ...rest }, ref) => (
|
|
47
|
+
<DialogPrimitive.Portal>
|
|
48
|
+
<DialogPrimitive.Overlay
|
|
49
|
+
className={cn(
|
|
50
|
+
"fixed inset-0 z-50 bg-black/60 backdrop-blur-sm",
|
|
51
|
+
"data-[state=open]:animate-in data-[state=open]:fade-in-0",
|
|
52
|
+
"data-[state=closed]:animate-out data-[state=closed]:fade-out-0",
|
|
53
|
+
"motion-reduce:animate-none",
|
|
54
|
+
)}
|
|
55
|
+
/>
|
|
56
|
+
<DialogPrimitive.Content
|
|
57
|
+
ref={ref}
|
|
58
|
+
className={cn(
|
|
59
|
+
"fixed z-50 border-edge bg-surface p-6",
|
|
60
|
+
"overflow-y-auto overscroll-contain",
|
|
61
|
+
sideClasses[side],
|
|
62
|
+
className,
|
|
63
|
+
)}
|
|
64
|
+
{...rest}
|
|
65
|
+
>
|
|
66
|
+
{children}
|
|
67
|
+
<DialogPrimitive.Close
|
|
68
|
+
className={cn(
|
|
69
|
+
"absolute top-4 right-4 rounded-sm",
|
|
70
|
+
"text-muted-foreground transition-colors hover:text-foreground",
|
|
71
|
+
"focus-visible:outline-2 focus-visible:outline-accent focus-visible:outline-offset-2",
|
|
72
|
+
)}
|
|
73
|
+
aria-label="Close"
|
|
74
|
+
>
|
|
75
|
+
<X weight="bold" className="size-4" />
|
|
76
|
+
</DialogPrimitive.Close>
|
|
77
|
+
</DialogPrimitive.Content>
|
|
78
|
+
</DialogPrimitive.Portal>
|
|
79
|
+
),
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
DrawerContent.displayName = "DrawerContent";
|
|
83
|
+
|
|
84
|
+
/* ── DrawerTitle ───────────────────────────────── */
|
|
85
|
+
|
|
86
|
+
const DrawerTitle = forwardRef<
|
|
87
|
+
HTMLHeadingElement,
|
|
88
|
+
ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
|
|
89
|
+
>(({ className, ...rest }, ref) => (
|
|
90
|
+
<DialogPrimitive.Title
|
|
91
|
+
ref={ref}
|
|
92
|
+
className={cn(
|
|
93
|
+
"font-heading font-bold text-lg text-foreground",
|
|
94
|
+
className,
|
|
95
|
+
)}
|
|
96
|
+
{...rest}
|
|
97
|
+
/>
|
|
98
|
+
));
|
|
99
|
+
|
|
100
|
+
DrawerTitle.displayName = "DrawerTitle";
|
|
101
|
+
|
|
102
|
+
/* ── DrawerDescription ─────────────────────────── */
|
|
103
|
+
|
|
104
|
+
const DrawerDescription = forwardRef<
|
|
105
|
+
HTMLParagraphElement,
|
|
106
|
+
ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
|
|
107
|
+
>(({ className, ...rest }, ref) => (
|
|
108
|
+
<DialogPrimitive.Description
|
|
109
|
+
ref={ref}
|
|
110
|
+
className={cn("text-sm text-muted-foreground", className)}
|
|
111
|
+
{...rest}
|
|
112
|
+
/>
|
|
113
|
+
));
|
|
114
|
+
|
|
115
|
+
DrawerDescription.displayName = "DrawerDescription";
|
|
116
|
+
|
|
117
|
+
/* ── Exports ───────────────────────────────────── */
|
|
118
|
+
|
|
119
|
+
export {
|
|
120
|
+
Drawer,
|
|
121
|
+
DrawerClose,
|
|
122
|
+
DrawerContent,
|
|
123
|
+
DrawerDescription,
|
|
124
|
+
DrawerTitle,
|
|
125
|
+
DrawerTrigger,
|
|
126
|
+
type DrawerContentProps,
|
|
127
|
+
};
|
|
@@ -64,5 +64,71 @@ const LogoFull = forwardRef<SVGSVGElement, LogoProps>(
|
|
|
64
64
|
|
|
65
65
|
LogoFull.displayName = "LogoFull";
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
/**
|
|
68
|
+
* stasho wordmark only, no icon (placeholder logotype, rebrand still deferred).
|
|
69
|
+
* Set in Anybody 800 italic to match the brand headings; the consuming app must
|
|
70
|
+
* load Anybody or it falls back to sans-serif. viewBox is fitted to "stasho" at
|
|
71
|
+
* that cut. Inherits color from parent via `currentColor`.
|
|
72
|
+
*/
|
|
73
|
+
const LogoWordmark = forwardRef<SVGSVGElement, LogoProps>(
|
|
74
|
+
({ className, ...rest }, ref) => (
|
|
75
|
+
<svg
|
|
76
|
+
ref={ref}
|
|
77
|
+
viewBox="0 0 654 229"
|
|
78
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
79
|
+
fill="currentColor"
|
|
80
|
+
className={cn("shrink-0", className)}
|
|
81
|
+
{...rest}
|
|
82
|
+
>
|
|
83
|
+
<text
|
|
84
|
+
x="0"
|
|
85
|
+
y="180"
|
|
86
|
+
fill="currentColor"
|
|
87
|
+
fontFamily="Anybody, sans-serif"
|
|
88
|
+
fontSize="200"
|
|
89
|
+
fontWeight="800"
|
|
90
|
+
fontStyle="italic"
|
|
91
|
+
>
|
|
92
|
+
stasho
|
|
93
|
+
</text>
|
|
94
|
+
</svg>
|
|
95
|
+
),
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
LogoWordmark.displayName = "LogoWordmark";
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* stasho letter mark "s", for collapsed / compact placements (placeholder
|
|
102
|
+
* logotype, rebrand still deferred). Set in Anybody 800 italic to match the
|
|
103
|
+
* brand headings; the consuming app must load Anybody or it falls back to
|
|
104
|
+
* sans-serif. Inherits color from parent via `currentColor`.
|
|
105
|
+
*/
|
|
106
|
+
const LogoLetter = forwardRef<SVGSVGElement, LogoProps>(
|
|
107
|
+
({ className, ...rest }, ref) => (
|
|
108
|
+
<svg
|
|
109
|
+
ref={ref}
|
|
110
|
+
viewBox="0 0 119 229"
|
|
111
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
112
|
+
fill="currentColor"
|
|
113
|
+
className={cn("shrink-0", className)}
|
|
114
|
+
{...rest}
|
|
115
|
+
>
|
|
116
|
+
<text
|
|
117
|
+
x="0"
|
|
118
|
+
y="180"
|
|
119
|
+
fill="currentColor"
|
|
120
|
+
fontFamily="Anybody, sans-serif"
|
|
121
|
+
fontSize="200"
|
|
122
|
+
fontWeight="800"
|
|
123
|
+
fontStyle="italic"
|
|
124
|
+
>
|
|
125
|
+
s
|
|
126
|
+
</text>
|
|
127
|
+
</svg>
|
|
128
|
+
),
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
LogoLetter.displayName = "LogoLetter";
|
|
132
|
+
|
|
133
|
+
export { Logo, LogoFull, LogoWordmark, LogoLetter };
|
|
68
134
|
export type { LogoProps };
|
package/src/styles/tokens.css
CHANGED
|
@@ -398,4 +398,49 @@
|
|
|
398
398
|
@keyframes accordion-up {
|
|
399
399
|
from { height: var(--radix-accordion-content-height); }
|
|
400
400
|
to { height: 0; }
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/* ── Drawer slide in/out (per side) ────────────── */
|
|
404
|
+
|
|
405
|
+
/* Same mechanism as the Accordion utilities above: registered in @theme so
|
|
406
|
+
the `data-[state=...]:` variant composes, and applied in the component as
|
|
407
|
+
`motion-safe:data-[state=…]:animate-drawer-*` so reduced motion is honored
|
|
408
|
+
by gating the animation INTO motion-safe. */
|
|
409
|
+
@theme {
|
|
410
|
+
--animate-drawer-in-bottom: drawer-in-bottom 300ms ease-out;
|
|
411
|
+
--animate-drawer-out-bottom: drawer-out-bottom 300ms ease-in;
|
|
412
|
+
--animate-drawer-in-left: drawer-in-left 300ms ease-out;
|
|
413
|
+
--animate-drawer-out-left: drawer-out-left 300ms ease-in;
|
|
414
|
+
--animate-drawer-in-right: drawer-in-right 300ms ease-out;
|
|
415
|
+
--animate-drawer-out-right: drawer-out-right 300ms ease-in;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
@keyframes drawer-in-bottom {
|
|
419
|
+
from { transform: translateY(100%); }
|
|
420
|
+
to { transform: translateY(0); }
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
@keyframes drawer-out-bottom {
|
|
424
|
+
from { transform: translateY(0); }
|
|
425
|
+
to { transform: translateY(100%); }
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
@keyframes drawer-in-left {
|
|
429
|
+
from { transform: translateX(-100%); }
|
|
430
|
+
to { transform: translateX(0); }
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
@keyframes drawer-out-left {
|
|
434
|
+
from { transform: translateX(0); }
|
|
435
|
+
to { transform: translateX(-100%); }
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
@keyframes drawer-in-right {
|
|
439
|
+
from { transform: translateX(100%); }
|
|
440
|
+
to { transform: translateX(0); }
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
@keyframes drawer-out-right {
|
|
444
|
+
from { transform: translateX(0); }
|
|
445
|
+
to { transform: translateX(100%); }
|
|
401
446
|
}
|