@ponti-studios/ui 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -0
- package/package.json +45 -24
- package/src/animations.css +92 -15
- package/src/components/data-display/accordion.tsx +15 -6
- package/src/components/data-display/filter-chip.stories.tsx +38 -0
- package/src/components/data-display/filter-chip.tsx +9 -3
- package/src/components/data-display/sort-controls.tsx +1 -1
- package/src/components/data-display/table.tsx +3 -7
- package/src/components/feedback/empty-state.tsx +16 -6
- package/src/components/feedback/file-upload-status-badge.tsx +1 -1
- package/src/components/feedback/progress.tsx +2 -2
- package/src/components/feedback/update-guard.tsx +1 -1
- package/src/components/forms/calendar.tsx +6 -3
- package/src/components/forms/field.tsx +3 -3
- package/src/components/forms/input.tsx +1 -1
- package/src/components/forms/passkey-management.tsx +2 -2
- package/src/components/forms/radio-group.tsx +1 -1
- package/src/components/forms/select.tsx +11 -4
- package/src/components/forms/slider.tsx +16 -4
- package/src/components/forms/stepper.tsx +1 -1
- package/src/components/forms/textarea.tsx +1 -1
- package/src/components/layout/section-intro.tsx +1 -1
- package/src/components/navigation/app-navigation.tsx +4 -4
- package/src/components/navigation/pagination-controls.tsx +2 -2
- package/src/components/navigation/tabs.tsx +1 -1
- package/src/components/overlays/alert-dialog.tsx +30 -8
- package/src/components/overlays/command.tsx +123 -20
- package/src/components/overlays/dialog.tsx +4 -4
- package/src/components/overlays/dropdown-menu.tsx +137 -21
- package/src/components/overlays/popover.tsx +14 -3
- package/src/components/overlays/sheet.tsx +24 -8
- package/src/components/primitives/avatar.tsx +6 -2
- package/src/components/primitives/badge.tsx +5 -2
- package/src/components/primitives/button.tsx +16 -18
- package/src/components/primitives/card.stories.tsx +2 -2
- package/src/components/primitives/card.tsx +2 -5
- package/src/constants/chart-colors.ts +2 -2
- package/src/index.ts +1 -1
- package/src/native/index.ts +11 -0
- package/src/native/make-styles.ts +32 -0
- package/src/native/shadows.ts +38 -0
- package/src/native/use-theme-colors.ts +19 -0
- package/src/styles.css +154 -66
- package/src/tokens/chart-colors.stories.tsx +189 -0
- package/src/tokens/color-systems.stories.tsx +21 -3
- package/src/tokens/css-vars.ts +15 -0
- package/src/tokens/foundations.stories.tsx +66 -16
- package/src/tokens/generated/dark.colors.generated.ts +24 -50
- package/src/tokens/generated/dark.css +24 -48
- package/src/tokens/generated/foundations.css +2 -2
- package/src/tokens/generated/foundations.generated.ts +14 -6
- package/src/tokens/generated/light.colors.generated.ts +24 -50
- package/src/tokens/generated/light.css +24 -48
- package/src/tokens/index.ts +12 -15
- package/src/tokens/layout.stories.tsx +40 -3
- package/src/tokens.css +3 -0
- package/dist/index.js +0 -2508
- package/dist/index.js.map +0 -1
package/README.md
CHANGED
|
@@ -25,3 +25,17 @@ pnpm config set --location=user //registry.npmjs.org/:_authToken "$NODE_AUTH_TOK
|
|
|
25
25
|
```
|
|
26
26
|
|
|
27
27
|
CI consumers should use a secret-backed npm token with read access.
|
|
28
|
+
|
|
29
|
+
### Ships TypeScript source, not a bundle
|
|
30
|
+
|
|
31
|
+
This package has no build output — every `exports` entry resolves to a file under `src/`. Consumers are expected to transpile the package themselves (Vite, Metro, Next, etc. all do this for workspace/npm packages by default). This is deliberate: Tailwind v4 class detection for consumers of `./styles.css` or `./tokens.css` requires an `@source` directive pointing at the installed package's `src/`, e.g.
|
|
32
|
+
|
|
33
|
+
```css
|
|
34
|
+
@source "../../../node_modules/@ponti-studios/ui/src";
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Bundling the package would break that detection, since Tailwind can't scan generated/minified output for class names. `pnpm run build` only type-checks; it does not emit JS.
|
|
38
|
+
|
|
39
|
+
### `./native` subpath
|
|
40
|
+
|
|
41
|
+
`@ponti-studios/ui/native` is the only part of the package that imports `react-native`. Web consumers never pull it in; native consumers get `createMakeStyles`, `nativeShadows`, `useColorMode`, and `useThemeColors`. `react-native` is an optional peer dependency — only declare it in your own `package.json` if you actually import from this subpath.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ponti-studios/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Shared UI component library for ponti-studios labs",
|
|
6
6
|
"license": "MIT",
|
|
@@ -14,13 +14,13 @@
|
|
|
14
14
|
"access": "public"
|
|
15
15
|
},
|
|
16
16
|
"files": [
|
|
17
|
-
"dist",
|
|
18
17
|
"src",
|
|
19
18
|
"THIRD_PARTY_NOTICES.md"
|
|
20
19
|
],
|
|
21
20
|
"type": "module",
|
|
22
21
|
"sideEffects": [
|
|
23
22
|
"./src/styles.css",
|
|
23
|
+
"./src/tokens.css",
|
|
24
24
|
"./src/animations.css"
|
|
25
25
|
],
|
|
26
26
|
"exports": {
|
|
@@ -64,19 +64,41 @@
|
|
|
64
64
|
"types": "./src/tokens/index.ts",
|
|
65
65
|
"import": "./src/tokens/index.ts"
|
|
66
66
|
},
|
|
67
|
+
"./tokens/css-vars": {
|
|
68
|
+
"types": "./src/tokens/css-vars.ts",
|
|
69
|
+
"import": "./src/tokens/css-vars.ts"
|
|
70
|
+
},
|
|
71
|
+
"./native": {
|
|
72
|
+
"types": "./src/native/index.ts",
|
|
73
|
+
"import": "./src/native/index.ts"
|
|
74
|
+
},
|
|
67
75
|
"./hooks": {
|
|
68
76
|
"types": "./src/hooks/index.ts",
|
|
69
77
|
"import": "./src/hooks/index.ts"
|
|
70
78
|
},
|
|
71
79
|
"./styles.css": "./src/styles.css",
|
|
80
|
+
"./tokens.css": "./src/tokens.css",
|
|
72
81
|
"./animations.css": "./src/animations.css"
|
|
73
82
|
},
|
|
83
|
+
"scripts": {
|
|
84
|
+
"build": "tsc --noEmit",
|
|
85
|
+
"dev": "vite",
|
|
86
|
+
"storybook": "style-dictionary build --config style-dictionary.dark-storybook.json && storybook dev -p 6006",
|
|
87
|
+
"check:source": "node tokens/check-source.mjs",
|
|
88
|
+
"test:a11y": "vitest --run --config vitest.config.ts",
|
|
89
|
+
"tokens:build": "style-dictionary build --config style-dictionary.foundations.json && style-dictionary build --config style-dictionary.light.json && style-dictionary build --config style-dictionary.dark.json && style-dictionary build --config style-dictionary.dark-storybook.json",
|
|
90
|
+
"tokens:check": "pnpm run tokens:build && node tokens/check-foundations.mjs && git diff --exit-code -- src/tokens/generated",
|
|
91
|
+
"typecheck": "tsc --noEmit",
|
|
92
|
+
"lint": "oxlint src --fix",
|
|
93
|
+
"format": "oxfmt src --write",
|
|
94
|
+
"prepack": "pnpm run tokens:check && pnpm run check:source && pnpm run typecheck"
|
|
95
|
+
},
|
|
74
96
|
"dependencies": {
|
|
75
97
|
"@base-ui/react": "^1.6.0",
|
|
98
|
+
"@radix-ui/colors": "^3.0.0",
|
|
76
99
|
"class-variance-authority": "^0.7.1",
|
|
77
100
|
"clsx": "^2.1.1",
|
|
78
101
|
"date-fns": "^4.1.0",
|
|
79
|
-
"framer-motion": "^12.42.2",
|
|
80
102
|
"lucide-react": "^1.24.0",
|
|
81
103
|
"react-day-picker": "^10.0.1",
|
|
82
104
|
"tailwind-merge": "^3.6.0"
|
|
@@ -90,39 +112,38 @@
|
|
|
90
112
|
"@storybook/addon-themes": "10.5.3",
|
|
91
113
|
"@storybook/addon-vitest": "10.5.3",
|
|
92
114
|
"@storybook/react-vite": "^10.5.3",
|
|
93
|
-
"@tailwindcss/vite": "
|
|
94
|
-
"@types/node": "
|
|
115
|
+
"@tailwindcss/vite": "catalog:",
|
|
116
|
+
"@types/node": "catalog:",
|
|
95
117
|
"@types/react": "^19.2.17",
|
|
96
118
|
"@types/react-dom": "^19.2.3",
|
|
97
119
|
"@vitejs/plugin-react": "^6.0.3",
|
|
98
120
|
"@vitest/browser": "4.1.10",
|
|
99
121
|
"@vitest/browser-playwright": "4.1.10",
|
|
100
|
-
"oxfmt": "
|
|
101
|
-
"oxlint": "
|
|
102
|
-
"playwright": "
|
|
122
|
+
"oxfmt": "catalog:shared",
|
|
123
|
+
"oxlint": "catalog:shared",
|
|
124
|
+
"playwright": "catalog:",
|
|
103
125
|
"react": "^19.2.7",
|
|
104
126
|
"react-dom": "^19.2.7",
|
|
127
|
+
"react-native": "0.86.0",
|
|
105
128
|
"storybook": "^10.5.3",
|
|
106
129
|
"style-dictionary": "5.5.0",
|
|
107
|
-
"tailwindcss": "
|
|
130
|
+
"tailwindcss": "catalog:",
|
|
108
131
|
"typescript": "6.0.3",
|
|
109
|
-
"vite": "
|
|
110
|
-
"vitest": "
|
|
132
|
+
"vite": "catalog:",
|
|
133
|
+
"vitest": "catalog:"
|
|
111
134
|
},
|
|
112
135
|
"peerDependencies": {
|
|
113
136
|
"react": "^18.2.0 || ^19.0.0",
|
|
114
|
-
"react-dom": "^18.2.0 || ^19.0.0"
|
|
137
|
+
"react-dom": "^18.2.0 || ^19.0.0",
|
|
138
|
+
"react-native": ">=0.74"
|
|
115
139
|
},
|
|
116
|
-
"
|
|
117
|
-
|
|
118
|
-
"
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
"
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
"typecheck": "tsc --noEmit",
|
|
125
|
-
"lint": "oxlint src --fix",
|
|
126
|
-
"format": "oxfmt src --write"
|
|
140
|
+
"packageManager": "pnpm@10.30.3",
|
|
141
|
+
"peerDependenciesMeta": {
|
|
142
|
+
"react-dom": {
|
|
143
|
+
"optional": true
|
|
144
|
+
},
|
|
145
|
+
"react-native": {
|
|
146
|
+
"optional": true
|
|
147
|
+
}
|
|
127
148
|
}
|
|
128
|
-
}
|
|
149
|
+
}
|
package/src/animations.css
CHANGED
|
@@ -1,19 +1,96 @@
|
|
|
1
|
-
@keyframes accordion-down {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
@keyframes accordion-down {
|
|
2
|
+
from {
|
|
3
|
+
height: 0;
|
|
4
|
+
}
|
|
5
|
+
to {
|
|
6
|
+
height: var(--accordion-content-height);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
@keyframes accordion-up {
|
|
10
|
+
from {
|
|
11
|
+
height: var(--accordion-content-height);
|
|
12
|
+
}
|
|
13
|
+
to {
|
|
14
|
+
height: 0;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
@keyframes fade-in {
|
|
18
|
+
from {
|
|
19
|
+
opacity: 0;
|
|
20
|
+
}
|
|
21
|
+
to {
|
|
22
|
+
opacity: 1;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
@keyframes fade-out {
|
|
26
|
+
from {
|
|
27
|
+
opacity: 1;
|
|
28
|
+
}
|
|
29
|
+
to {
|
|
30
|
+
opacity: 0;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
@keyframes zoom-in {
|
|
34
|
+
from {
|
|
35
|
+
opacity: 0;
|
|
36
|
+
transform: scale(0.95);
|
|
37
|
+
}
|
|
38
|
+
to {
|
|
39
|
+
opacity: 1;
|
|
40
|
+
transform: scale(1);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
@keyframes zoom-out {
|
|
44
|
+
from {
|
|
45
|
+
opacity: 1;
|
|
46
|
+
transform: scale(1);
|
|
47
|
+
}
|
|
48
|
+
to {
|
|
49
|
+
opacity: 0;
|
|
50
|
+
transform: scale(0.95);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
7
53
|
|
|
8
|
-
.animate-in {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
.
|
|
14
|
-
|
|
15
|
-
|
|
54
|
+
.animate-in {
|
|
55
|
+
animation:
|
|
56
|
+
fade-in 150ms ease-out,
|
|
57
|
+
zoom-in 150ms ease-out;
|
|
58
|
+
}
|
|
59
|
+
.animate-out {
|
|
60
|
+
animation:
|
|
61
|
+
fade-out 120ms ease-in,
|
|
62
|
+
zoom-out 120ms ease-in;
|
|
63
|
+
}
|
|
64
|
+
.fade-in-0 {
|
|
65
|
+
animation-name: fade-in;
|
|
66
|
+
}
|
|
67
|
+
.fade-out-0 {
|
|
68
|
+
animation-name: fade-out;
|
|
69
|
+
}
|
|
70
|
+
.zoom-in-95 {
|
|
71
|
+
animation-name: zoom-in;
|
|
72
|
+
}
|
|
73
|
+
.zoom-out-95 {
|
|
74
|
+
animation-name: zoom-out;
|
|
75
|
+
}
|
|
76
|
+
.data-open\:animate-in[data-open],
|
|
77
|
+
.data-open\:animate-in[data-state="open"] {
|
|
78
|
+
animation:
|
|
79
|
+
fade-in 150ms ease-out,
|
|
80
|
+
zoom-in 150ms ease-out;
|
|
81
|
+
}
|
|
82
|
+
.data-closed\:animate-out[data-closed],
|
|
83
|
+
.data-closed\:animate-out[data-state="closed"] {
|
|
84
|
+
animation:
|
|
85
|
+
fade-out 120ms ease-in,
|
|
86
|
+
zoom-out 120ms ease-in;
|
|
87
|
+
}
|
|
16
88
|
|
|
17
89
|
@media (prefers-reduced-motion: reduce) {
|
|
18
|
-
.animate-in,
|
|
90
|
+
.animate-in,
|
|
91
|
+
.animate-out,
|
|
92
|
+
[data-open],
|
|
93
|
+
[data-closed] {
|
|
94
|
+
animation: none !important;
|
|
95
|
+
}
|
|
19
96
|
}
|
|
@@ -4,11 +4,23 @@ import * as React from "react";
|
|
|
4
4
|
|
|
5
5
|
import { cn } from "../../lib/utils";
|
|
6
6
|
|
|
7
|
-
function Accordion({
|
|
7
|
+
function Accordion({
|
|
8
|
+
type,
|
|
9
|
+
collapsible: _collapsible,
|
|
10
|
+
className,
|
|
11
|
+
...props
|
|
12
|
+
}: React.ComponentProps<typeof AccordionPrimitive.Root> & {
|
|
8
13
|
type?: "single" | "multiple";
|
|
9
14
|
collapsible?: boolean;
|
|
10
15
|
}) {
|
|
11
|
-
return
|
|
16
|
+
return (
|
|
17
|
+
<AccordionPrimitive.Root
|
|
18
|
+
data-slot="accordion"
|
|
19
|
+
multiple={type === "multiple"}
|
|
20
|
+
{...props}
|
|
21
|
+
className={cn("w-full", className)}
|
|
22
|
+
/>
|
|
23
|
+
);
|
|
12
24
|
}
|
|
13
25
|
|
|
14
26
|
function AccordionItem({
|
|
@@ -18,10 +30,7 @@ function AccordionItem({
|
|
|
18
30
|
return (
|
|
19
31
|
<AccordionPrimitive.Item
|
|
20
32
|
data-slot="accordion-item"
|
|
21
|
-
className={cn(
|
|
22
|
-
"mb-2 overflow-hidden rounded-md border last:mb-0",
|
|
23
|
-
className,
|
|
24
|
-
)}
|
|
33
|
+
className={cn("mb-2 overflow-hidden rounded-md border last:mb-0", className)}
|
|
25
34
|
{...props}
|
|
26
35
|
/>
|
|
27
36
|
);
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
|
|
3
|
+
import { FilterChip } from "./filter-chip";
|
|
4
|
+
|
|
5
|
+
const meta = {
|
|
6
|
+
title: "DataDisplay/FilterChip",
|
|
7
|
+
component: FilterChip,
|
|
8
|
+
tags: ["autodocs"],
|
|
9
|
+
args: {
|
|
10
|
+
onRemove: () => {},
|
|
11
|
+
},
|
|
12
|
+
} satisfies Meta<typeof FilterChip>;
|
|
13
|
+
|
|
14
|
+
export default meta;
|
|
15
|
+
type Story = StoryObj<typeof meta>;
|
|
16
|
+
|
|
17
|
+
export const Default: Story = {
|
|
18
|
+
args: { label: "Status: Active" },
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const Editable: Story = {
|
|
22
|
+
args: { label: "Status: Active", onClick: () => {} },
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const LongLabel: Story = {
|
|
26
|
+
args: { label: "Created between Jan 1, 2026 and Jul 24, 2026" },
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export const Group: Story = {
|
|
30
|
+
args: { label: "Filters" },
|
|
31
|
+
render: () => (
|
|
32
|
+
<div className="flex flex-wrap gap-2">
|
|
33
|
+
<FilterChip label="Status: Active" onRemove={() => {}} onClick={() => {}} />
|
|
34
|
+
<FilterChip label="Team: Design" onRemove={() => {}} onClick={() => {}} />
|
|
35
|
+
<FilterChip label="Archived" onRemove={() => {}} />
|
|
36
|
+
</div>
|
|
37
|
+
),
|
|
38
|
+
};
|
|
@@ -13,15 +13,21 @@ export interface FilterChipProps {
|
|
|
13
13
|
/** An applied filter with an optional edit action and an explicit remove action. */
|
|
14
14
|
export function FilterChip({ label, onRemove, onClick, className }: FilterChipProps) {
|
|
15
15
|
const labelContent = onClick ? (
|
|
16
|
-
<button
|
|
16
|
+
<button
|
|
17
|
+
type="button"
|
|
18
|
+
className="focus-visible:ring-ring min-h-9 rounded-full px-3 text-left transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none"
|
|
19
|
+
onClick={onClick}
|
|
20
|
+
>
|
|
17
21
|
{label}
|
|
18
22
|
</button>
|
|
19
23
|
) : (
|
|
20
|
-
<span className="flex min-h-
|
|
24
|
+
<span className="flex min-h-9 items-center px-3">{label}</span>
|
|
21
25
|
);
|
|
22
26
|
|
|
23
27
|
return (
|
|
24
28
|
<span
|
|
29
|
+
role="group"
|
|
30
|
+
aria-label={typeof label === "string" ? `${label} filter` : "filter"}
|
|
25
31
|
className={cn(
|
|
26
32
|
"border-border bg-secondary text-secondary-foreground inline-flex items-center rounded-full border text-sm font-medium",
|
|
27
33
|
className,
|
|
@@ -30,7 +36,7 @@ export function FilterChip({ label, onRemove, onClick, className }: FilterChipPr
|
|
|
30
36
|
{labelContent}
|
|
31
37
|
<button
|
|
32
38
|
type="button"
|
|
33
|
-
className="text-muted-foreground hover:text-foreground mr-1 flex size-
|
|
39
|
+
className="text-muted-foreground hover:text-foreground focus-visible:ring-ring mr-1 flex size-9 items-center justify-center rounded-full transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none"
|
|
34
40
|
onClick={onRemove}
|
|
35
41
|
aria-label={`Remove filter: ${typeof label === "string" ? label : "selected filter"}`}
|
|
36
42
|
>
|
|
@@ -60,7 +60,7 @@ export function SortControls({
|
|
|
60
60
|
<DropdownMenuItem
|
|
61
61
|
key={sort.field}
|
|
62
62
|
onSelect={(e) => e.preventDefault()}
|
|
63
|
-
className={`p-0 focus:bg-transparent ${index === focusedSortIndex ? "bg-
|
|
63
|
+
className={`p-0 focus:bg-transparent ${index === focusedSortIndex ? "bg-muted" : ""}`}
|
|
64
64
|
>
|
|
65
65
|
<SortRow
|
|
66
66
|
sortOption={sort}
|
|
@@ -37,11 +37,7 @@ TableFooter.displayName = "TableFooter";
|
|
|
37
37
|
|
|
38
38
|
const TableRow = React.forwardRef<HTMLTableRowElement, React.HTMLAttributes<HTMLTableRowElement>>(
|
|
39
39
|
({ className, ...props }, ref) => (
|
|
40
|
-
<tr
|
|
41
|
-
ref={ref}
|
|
42
|
-
className={cn("data-[state=selected]:bg-muted border-b", className)}
|
|
43
|
-
{...props}
|
|
44
|
-
/>
|
|
40
|
+
<tr ref={ref} className={cn("data-[state=selected]:bg-muted border-b", className)} {...props} />
|
|
45
41
|
),
|
|
46
42
|
);
|
|
47
43
|
TableRow.displayName = "TableRow";
|
|
@@ -53,7 +49,7 @@ const TableHead = React.forwardRef<
|
|
|
53
49
|
<th
|
|
54
50
|
ref={ref}
|
|
55
51
|
className={cn(
|
|
56
|
-
"h-9 px-3 text-left align-middle text-xs font-medium
|
|
52
|
+
"text-muted-foreground h-9 px-3 text-left align-middle text-xs font-medium [&:has([role=checkbox])]:pr-0",
|
|
57
53
|
className,
|
|
58
54
|
)}
|
|
59
55
|
{...props}
|
|
@@ -77,7 +73,7 @@ const TableCaption = React.forwardRef<
|
|
|
77
73
|
HTMLTableCaptionElement,
|
|
78
74
|
React.HTMLAttributes<HTMLTableCaptionElement>
|
|
79
75
|
>(({ className, ...props }, ref) => (
|
|
80
|
-
<caption ref={ref} className={cn("mt-4 text-sm
|
|
76
|
+
<caption ref={ref} className={cn("text-muted-foreground mt-4 text-sm", className)} {...props} />
|
|
81
77
|
));
|
|
82
78
|
TableCaption.displayName = "TableCaption";
|
|
83
79
|
|
|
@@ -37,9 +37,9 @@ export function EmptyState({
|
|
|
37
37
|
<section
|
|
38
38
|
className={cn(
|
|
39
39
|
"rounded-lg px-5 py-8",
|
|
40
|
-
variant === "default" && "
|
|
41
|
-
variant === "dashed" && "
|
|
42
|
-
variant === "search" && "
|
|
40
|
+
variant === "default" && "bg-card border",
|
|
41
|
+
variant === "dashed" && "bg-card border border-dashed",
|
|
42
|
+
variant === "search" && "bg-muted border border-dashed",
|
|
43
43
|
variant === "quiet" && "bg-surface",
|
|
44
44
|
centered
|
|
45
45
|
? cn(
|
|
@@ -51,13 +51,23 @@ export function EmptyState({
|
|
|
51
51
|
)}
|
|
52
52
|
>
|
|
53
53
|
{icon ? (
|
|
54
|
-
<div
|
|
54
|
+
<div
|
|
55
|
+
className="text-muted-foreground mb-3 flex size-11 items-center justify-center"
|
|
56
|
+
aria-hidden
|
|
57
|
+
>
|
|
55
58
|
{icon}
|
|
56
59
|
</div>
|
|
57
60
|
) : null}
|
|
58
61
|
<div className={cn("space-y-2", centered && "max-w-[34ch]")}>
|
|
59
|
-
<h2
|
|
60
|
-
|
|
62
|
+
<h2
|
|
63
|
+
className={cn(
|
|
64
|
+
"text-foreground font-semibold tracking-tight",
|
|
65
|
+
large ? "text-lg" : "text-base",
|
|
66
|
+
)}
|
|
67
|
+
>
|
|
68
|
+
{title}
|
|
69
|
+
</h2>
|
|
70
|
+
{description ? <p className="text-muted-foreground text-sm">{description}</p> : null}
|
|
61
71
|
</div>
|
|
62
72
|
{children ? <div className="mt-3">{children}</div> : null}
|
|
63
73
|
{action ? <div className="mt-4">{action}</div> : null}
|
|
@@ -8,7 +8,7 @@ const STATUS_CONFIG: Record<FileUploadStatusValue, { bg: string; text: string; l
|
|
|
8
8
|
uploading: { bg: "bg-muted", text: "text-foreground", label: "Uploading" },
|
|
9
9
|
processing: { bg: "bg-muted", text: "text-foreground", label: "Processing" },
|
|
10
10
|
queued: { bg: "bg-secondary", text: "text-secondary-foreground", label: "Queued" },
|
|
11
|
-
done: { bg: "bg-
|
|
11
|
+
done: { bg: "bg-muted", text: "text-muted-foreground", label: "Complete" },
|
|
12
12
|
error: { bg: "bg-destructive/10", text: "text-destructive", label: "Error" },
|
|
13
13
|
};
|
|
14
14
|
|
|
@@ -14,13 +14,13 @@ function Progress({
|
|
|
14
14
|
return (
|
|
15
15
|
<ProgressPrimitive.Root
|
|
16
16
|
data-slot="progress"
|
|
17
|
-
className={cn("bg-
|
|
17
|
+
className={cn("bg-primary/20 relative h-2 w-full overflow-hidden rounded-full", className)}
|
|
18
18
|
value={value}
|
|
19
19
|
{...props}
|
|
20
20
|
>
|
|
21
21
|
<ProgressPrimitive.Indicator
|
|
22
22
|
data-slot="progress-indicator"
|
|
23
|
-
className={cn("bg-
|
|
23
|
+
className={cn("bg-primary h-full w-full flex-1 transition-all", indicatorClassName)}
|
|
24
24
|
style={{ transform: `translateX(-${100 - (value ?? 0)}%)` }}
|
|
25
25
|
/>
|
|
26
26
|
</ProgressPrimitive.Root>
|
|
@@ -240,7 +240,7 @@ function UpdateGuardClient({
|
|
|
240
240
|
{copy?.refreshButton ?? "Refresh"}
|
|
241
241
|
</button>
|
|
242
242
|
) : null}
|
|
243
|
-
|
|
243
|
+
<button type="button" onClick={closePrompt} className="text-muted-foreground text-sm">
|
|
244
244
|
{copy?.closeButton ?? "Close"}
|
|
245
245
|
</button>
|
|
246
246
|
</div>
|
|
@@ -24,7 +24,8 @@ function Calendar({ className, classNames, showOutsideDays = true, ...props }: C
|
|
|
24
24
|
"inline-flex size-8 p-2 items-center justify-center rounded-full border bg-background text-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50",
|
|
25
25
|
month_grid: "w-full border-collapse",
|
|
26
26
|
weekdays: "flex",
|
|
27
|
-
weekday:
|
|
27
|
+
weekday:
|
|
28
|
+
"flex size-8 items-center justify-center text-[0.8rem] font-normal text-muted-foreground",
|
|
28
29
|
week: "mt-1 flex w-full",
|
|
29
30
|
day: "relative size-8 p-0 text-center text-lg focus-within:z-20",
|
|
30
31
|
day_button:
|
|
@@ -34,9 +35,11 @@ function Calendar({ className, classNames, showOutsideDays = true, ...props }: C
|
|
|
34
35
|
today: "[&>button]:bg-primary [&>button]:text-primary-foreground",
|
|
35
36
|
outside: "text-muted-foreground [&>button]:text-muted-foreground",
|
|
36
37
|
disabled: "text-muted-foreground opacity-50",
|
|
37
|
-
range_start:
|
|
38
|
+
range_start:
|
|
39
|
+
"rounded-l-md bg-primary [&>button]:bg-primary [&>button]:text-primary-foreground",
|
|
38
40
|
range_middle: "bg-primary [&>button]:rounded-none [&>button]:text-primary-foreground",
|
|
39
|
-
range_end:
|
|
41
|
+
range_end:
|
|
42
|
+
"rounded-r-md bg-primary [&>button]:bg-primary [&>button]:text-primary-foreground",
|
|
40
43
|
hidden: "invisible",
|
|
41
44
|
...classNames,
|
|
42
45
|
}}
|
|
@@ -29,7 +29,7 @@ function Field({ label, helpText, error, required, children, id: externalId }: F
|
|
|
29
29
|
<label
|
|
30
30
|
htmlFor={id}
|
|
31
31
|
className={cn(
|
|
32
|
-
"text-
|
|
32
|
+
"text-foreground text-sm font-medium",
|
|
33
33
|
required && "after:text-destructive after:ml-0.5 after:content-['*']",
|
|
34
34
|
)}
|
|
35
35
|
>
|
|
@@ -50,11 +50,11 @@ function Field({ label, helpText, error, required, children, id: externalId }: F
|
|
|
50
50
|
: children}
|
|
51
51
|
|
|
52
52
|
{error ? (
|
|
53
|
-
<p id={errorId} role="alert" className="text-
|
|
53
|
+
<p id={errorId} role="alert" className="text-destructive text-sm">
|
|
54
54
|
{error}
|
|
55
55
|
</p>
|
|
56
56
|
) : helpText ? (
|
|
57
|
-
<p id={descId} className="text-
|
|
57
|
+
<p id={descId} className="text-muted-foreground text-sm">
|
|
58
58
|
{helpText}
|
|
59
59
|
</p>
|
|
60
60
|
) : null}
|
|
@@ -8,7 +8,7 @@ function Input({ className, type, ...props }: React.ComponentProps<"input">) {
|
|
|
8
8
|
type={type}
|
|
9
9
|
data-slot="input"
|
|
10
10
|
className={cn(
|
|
11
|
-
"file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground bg-background focus-visible:ring-ring h-9 w-full min-w-0 rounded-md border
|
|
11
|
+
"file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground bg-background focus-visible:ring-ring border-input h-9 w-full min-w-0 rounded-md border px-3 py-1 text-base transition-colors file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
|
12
12
|
"aria-invalid:ring-destructive/20 aria-invalid:border-destructive",
|
|
13
13
|
className,
|
|
14
14
|
)}
|
|
@@ -69,10 +69,10 @@ export function PasskeyManagement({
|
|
|
69
69
|
<section aria-labelledby="passkey-heading" className="space-y-4">
|
|
70
70
|
<div className="flex items-center justify-between">
|
|
71
71
|
<div>
|
|
72
|
-
<h2 id="passkey-heading" className="text-sm font-medium
|
|
72
|
+
<h2 id="passkey-heading" className="text-foreground text-sm font-medium">
|
|
73
73
|
Passkeys
|
|
74
74
|
</h2>
|
|
75
|
-
<p className="text-
|
|
75
|
+
<p className="text-muted-foreground text-sm">
|
|
76
76
|
Sign in without a password using biometrics or a security key.
|
|
77
77
|
</p>
|
|
78
78
|
</div>
|
|
@@ -23,7 +23,7 @@ const RadioGroupItem = React.forwardRef<
|
|
|
23
23
|
<RadioPrimitive.Root
|
|
24
24
|
ref={ref}
|
|
25
25
|
className={cn(
|
|
26
|
-
"border-primary bg-background text-foreground focus-visible:border-ring focus-visible:bg-
|
|
26
|
+
"border-primary bg-background text-foreground focus-visible:border-ring focus-visible:bg-muted/25 focus-visible:ring-ring aspect-square h-6 w-6 rounded-full border focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50",
|
|
27
27
|
className,
|
|
28
28
|
)}
|
|
29
29
|
{...props}
|
|
@@ -4,7 +4,10 @@ import * as React from "react";
|
|
|
4
4
|
|
|
5
5
|
import { cn } from "../../lib/utils";
|
|
6
6
|
|
|
7
|
-
type SelectProps = Omit<
|
|
7
|
+
type SelectProps = Omit<
|
|
8
|
+
React.ComponentProps<typeof SelectPrimitive.Root<string>>,
|
|
9
|
+
"onValueChange" | "value" | "defaultValue"
|
|
10
|
+
> & {
|
|
8
11
|
value?: string;
|
|
9
12
|
defaultValue?: string;
|
|
10
13
|
onValueChange?: (value: string) => void;
|
|
@@ -41,7 +44,7 @@ function SelectTrigger({
|
|
|
41
44
|
data-slot="select-trigger"
|
|
42
45
|
data-size={size}
|
|
43
46
|
className={cn(
|
|
44
|
-
"data-placeholder:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 aria-invalid:border-destructive flex w-fit items-center justify-between gap-2 rounded-md border
|
|
47
|
+
"data-placeholder:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 aria-invalid:border-destructive border-input flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:ring-inset disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
45
48
|
className,
|
|
46
49
|
)}
|
|
47
50
|
{...props}
|
|
@@ -92,12 +95,16 @@ function SelectLabel({ className, ...props }: React.ComponentProps<typeof Select
|
|
|
92
95
|
);
|
|
93
96
|
}
|
|
94
97
|
|
|
95
|
-
function SelectItem({
|
|
98
|
+
function SelectItem({
|
|
99
|
+
className,
|
|
100
|
+
children,
|
|
101
|
+
...props
|
|
102
|
+
}: React.ComponentProps<typeof SelectPrimitive.Item>) {
|
|
96
103
|
return (
|
|
97
104
|
<SelectPrimitive.Item
|
|
98
105
|
data-slot="select-item"
|
|
99
106
|
className={cn(
|
|
100
|
-
"data-highlighted:bg-
|
|
107
|
+
"data-highlighted:bg-muted data-highlighted:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-md py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50",
|
|
101
108
|
className,
|
|
102
109
|
)}
|
|
103
110
|
{...props}
|