@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.
Files changed (58) hide show
  1. package/README.md +14 -0
  2. package/package.json +45 -24
  3. package/src/animations.css +92 -15
  4. package/src/components/data-display/accordion.tsx +15 -6
  5. package/src/components/data-display/filter-chip.stories.tsx +38 -0
  6. package/src/components/data-display/filter-chip.tsx +9 -3
  7. package/src/components/data-display/sort-controls.tsx +1 -1
  8. package/src/components/data-display/table.tsx +3 -7
  9. package/src/components/feedback/empty-state.tsx +16 -6
  10. package/src/components/feedback/file-upload-status-badge.tsx +1 -1
  11. package/src/components/feedback/progress.tsx +2 -2
  12. package/src/components/feedback/update-guard.tsx +1 -1
  13. package/src/components/forms/calendar.tsx +6 -3
  14. package/src/components/forms/field.tsx +3 -3
  15. package/src/components/forms/input.tsx +1 -1
  16. package/src/components/forms/passkey-management.tsx +2 -2
  17. package/src/components/forms/radio-group.tsx +1 -1
  18. package/src/components/forms/select.tsx +11 -4
  19. package/src/components/forms/slider.tsx +16 -4
  20. package/src/components/forms/stepper.tsx +1 -1
  21. package/src/components/forms/textarea.tsx +1 -1
  22. package/src/components/layout/section-intro.tsx +1 -1
  23. package/src/components/navigation/app-navigation.tsx +4 -4
  24. package/src/components/navigation/pagination-controls.tsx +2 -2
  25. package/src/components/navigation/tabs.tsx +1 -1
  26. package/src/components/overlays/alert-dialog.tsx +30 -8
  27. package/src/components/overlays/command.tsx +123 -20
  28. package/src/components/overlays/dialog.tsx +4 -4
  29. package/src/components/overlays/dropdown-menu.tsx +137 -21
  30. package/src/components/overlays/popover.tsx +14 -3
  31. package/src/components/overlays/sheet.tsx +24 -8
  32. package/src/components/primitives/avatar.tsx +6 -2
  33. package/src/components/primitives/badge.tsx +5 -2
  34. package/src/components/primitives/button.tsx +16 -18
  35. package/src/components/primitives/card.stories.tsx +2 -2
  36. package/src/components/primitives/card.tsx +2 -5
  37. package/src/constants/chart-colors.ts +2 -2
  38. package/src/index.ts +1 -1
  39. package/src/native/index.ts +11 -0
  40. package/src/native/make-styles.ts +32 -0
  41. package/src/native/shadows.ts +38 -0
  42. package/src/native/use-theme-colors.ts +19 -0
  43. package/src/styles.css +154 -66
  44. package/src/tokens/chart-colors.stories.tsx +189 -0
  45. package/src/tokens/color-systems.stories.tsx +21 -3
  46. package/src/tokens/css-vars.ts +15 -0
  47. package/src/tokens/foundations.stories.tsx +66 -16
  48. package/src/tokens/generated/dark.colors.generated.ts +24 -50
  49. package/src/tokens/generated/dark.css +24 -48
  50. package/src/tokens/generated/foundations.css +2 -2
  51. package/src/tokens/generated/foundations.generated.ts +14 -6
  52. package/src/tokens/generated/light.colors.generated.ts +24 -50
  53. package/src/tokens/generated/light.css +24 -48
  54. package/src/tokens/index.ts +12 -15
  55. package/src/tokens/layout.stories.tsx +40 -3
  56. package/src/tokens.css +3 -0
  57. package/dist/index.js +0 -2508
  58. package/dist/index.js.map +0 -1
@@ -12,11 +12,17 @@ function DropdownMenuPortal(props: React.ComponentProps<typeof DropdownMenuPrimi
12
12
  return <DropdownMenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />;
13
13
  }
14
14
 
15
- function DropdownMenuTrigger({ asChild, children, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger> & { asChild?: boolean }) {
15
+ function DropdownMenuTrigger({
16
+ asChild,
17
+ children,
18
+ ...props
19
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger> & { asChild?: boolean }) {
16
20
  return (
17
21
  <DropdownMenuPrimitive.Trigger
18
22
  data-slot="dropdown-menu-trigger"
19
- {...(asChild && React.isValidElement(children) ? { render: children as React.ReactElement } : {})}
23
+ {...(asChild && React.isValidElement(children)
24
+ ? { render: children as React.ReactElement }
25
+ : {})}
20
26
  {...props}
21
27
  >
22
28
  {!asChild && children}
@@ -24,7 +30,12 @@ function DropdownMenuTrigger({ asChild, children, ...props }: React.ComponentPro
24
30
  );
25
31
  }
26
32
 
27
- function DropdownMenuContent({ className, sideOffset = 4, children, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Popup> & { sideOffset?: number }) {
33
+ function DropdownMenuContent({
34
+ className,
35
+ sideOffset = 4,
36
+ children,
37
+ ...props
38
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Popup> & { sideOffset?: number }) {
28
39
  return (
29
40
  <DropdownMenuPrimitive.Portal>
30
41
  <DropdownMenuPrimitive.Positioner sideOffset={sideOffset}>
@@ -47,54 +58,159 @@ function DropdownMenuGroup(props: React.ComponentProps<typeof DropdownMenuPrimit
47
58
  return <DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />;
48
59
  }
49
60
 
50
- function DropdownMenuLabel({ className, inset, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.GroupLabel> & { inset?: boolean }) {
51
- return <DropdownMenuPrimitive.GroupLabel data-slot="dropdown-menu-label" data-inset={inset} className={cn("px-2 py-1.5 text-sm font-medium data-[inset]:pl-8", className)} {...props} />;
61
+ function DropdownMenuLabel({
62
+ className,
63
+ inset,
64
+ ...props
65
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.GroupLabel> & { inset?: boolean }) {
66
+ return (
67
+ <DropdownMenuPrimitive.GroupLabel
68
+ data-slot="dropdown-menu-label"
69
+ data-inset={inset}
70
+ className={cn("px-2 py-1.5 text-sm font-medium data-[inset]:pl-8", className)}
71
+ {...props}
72
+ />
73
+ );
52
74
  }
53
75
 
54
- function DropdownMenuItem({ className, inset, variant = "default", ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & { inset?: boolean; variant?: "default" | "destructive" }) {
55
- return <DropdownMenuPrimitive.Item data-slot="dropdown-menu-item" data-inset={inset} data-variant={variant} className={cn("data-highlighted:bg-accent data-highlighted:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:data-highlighted:bg-destructive/10 relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none select-none data-disabled:pointer-events-none data-disabled:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", className)} {...props} />;
76
+ function DropdownMenuItem({
77
+ className,
78
+ inset,
79
+ variant = "default",
80
+ ...props
81
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
82
+ inset?: boolean;
83
+ variant?: "default" | "destructive";
84
+ }) {
85
+ return (
86
+ <DropdownMenuPrimitive.Item
87
+ data-slot="dropdown-menu-item"
88
+ data-inset={inset}
89
+ data-variant={variant}
90
+ className={cn(
91
+ "data-highlighted:bg-muted data-highlighted:text-muted-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:data-highlighted:bg-destructive/10 relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none select-none data-disabled:pointer-events-none data-disabled:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
92
+ className,
93
+ )}
94
+ {...props}
95
+ />
96
+ );
56
97
  }
57
98
 
58
- function DropdownMenuCheckboxItem({ className, children, checked, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>) {
99
+ function DropdownMenuCheckboxItem({
100
+ className,
101
+ children,
102
+ checked,
103
+ ...props
104
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>) {
59
105
  return (
60
- <DropdownMenuPrimitive.CheckboxItem data-slot="dropdown-menu-checkbox-item" className={cn("data-highlighted:bg-accent data-highlighted:text-accent-foreground relative flex cursor-default items-center rounded-sm py-1.5 pr-2 pl-8 text-sm outline-none select-none data-disabled:pointer-events-none data-disabled:opacity-50", className)} checked={checked} {...props}>
61
- <span className="absolute left-2 flex size-3.5 items-center justify-center"><DropdownMenuPrimitive.CheckboxItemIndicator><CheckIcon className="size-4" /></DropdownMenuPrimitive.CheckboxItemIndicator></span>
106
+ <DropdownMenuPrimitive.CheckboxItem
107
+ data-slot="dropdown-menu-checkbox-item"
108
+ className={cn(
109
+ "data-highlighted:bg-muted data-highlighted:text-muted-foreground relative flex cursor-default items-center rounded-sm py-1.5 pr-2 pl-8 text-sm outline-none select-none data-disabled:pointer-events-none data-disabled:opacity-50",
110
+ className,
111
+ )}
112
+ checked={checked}
113
+ {...props}
114
+ >
115
+ <span className="absolute left-2 flex size-3.5 items-center justify-center">
116
+ <DropdownMenuPrimitive.CheckboxItemIndicator>
117
+ <CheckIcon className="size-4" />
118
+ </DropdownMenuPrimitive.CheckboxItemIndicator>
119
+ </span>
62
120
  {children}
63
121
  </DropdownMenuPrimitive.CheckboxItem>
64
122
  );
65
123
  }
66
124
 
67
- function DropdownMenuRadioGroup(props: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {
125
+ function DropdownMenuRadioGroup(
126
+ props: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>,
127
+ ) {
68
128
  return <DropdownMenuPrimitive.RadioGroup data-slot="dropdown-menu-radio-group" {...props} />;
69
129
  }
70
130
 
71
- function DropdownMenuRadioItem({ className, children, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>) {
131
+ function DropdownMenuRadioItem({
132
+ className,
133
+ children,
134
+ ...props
135
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>) {
72
136
  return (
73
- <DropdownMenuPrimitive.RadioItem data-slot="dropdown-menu-radio-item" className={cn("data-highlighted:bg-accent data-highlighted:text-accent-foreground relative flex cursor-default items-center rounded-sm py-1.5 pr-2 pl-8 text-sm outline-none select-none data-disabled:pointer-events-none data-disabled:opacity-50", className)} {...props}>
74
- <span className="absolute left-2 flex size-3.5 items-center justify-center"><DropdownMenuPrimitive.RadioItemIndicator><CircleIcon className="size-2 fill-current" /></DropdownMenuPrimitive.RadioItemIndicator></span>
137
+ <DropdownMenuPrimitive.RadioItem
138
+ data-slot="dropdown-menu-radio-item"
139
+ className={cn(
140
+ "data-highlighted:bg-muted data-highlighted:text-muted-foreground relative flex cursor-default items-center rounded-sm py-1.5 pr-2 pl-8 text-sm outline-none select-none data-disabled:pointer-events-none data-disabled:opacity-50",
141
+ className,
142
+ )}
143
+ {...props}
144
+ >
145
+ <span className="absolute left-2 flex size-3.5 items-center justify-center">
146
+ <DropdownMenuPrimitive.RadioItemIndicator>
147
+ <CircleIcon className="size-2 fill-current" />
148
+ </DropdownMenuPrimitive.RadioItemIndicator>
149
+ </span>
75
150
  {children}
76
151
  </DropdownMenuPrimitive.RadioItem>
77
152
  );
78
153
  }
79
154
 
80
- function DropdownMenuSeparator({ className, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {
81
- return <DropdownMenuPrimitive.Separator data-slot="dropdown-menu-separator" className={cn("bg-border -mx-1 my-1 h-px", className)} {...props} />;
155
+ function DropdownMenuSeparator({
156
+ className,
157
+ ...props
158
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {
159
+ return (
160
+ <DropdownMenuPrimitive.Separator
161
+ data-slot="dropdown-menu-separator"
162
+ className={cn("bg-border -mx-1 my-1 h-px", className)}
163
+ {...props}
164
+ />
165
+ );
82
166
  }
83
167
 
84
168
  function DropdownMenuShortcut({ className, ...props }: React.ComponentProps<"span">) {
85
- return <span className={cn("ml-auto text-xs tracking-widest opacity-60", className)} {...props} />;
169
+ return (
170
+ <span className={cn("ml-auto text-xs tracking-widest opacity-60", className)} {...props} />
171
+ );
86
172
  }
87
173
 
88
174
  function DropdownMenuSub(props: React.ComponentProps<typeof DropdownMenuPrimitive.SubmenuRoot>) {
89
175
  return <DropdownMenuPrimitive.SubmenuRoot data-slot="dropdown-menu-sub" {...props} />;
90
176
  }
91
177
 
92
- function DropdownMenuSubTrigger({ className, inset, children, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.SubmenuTrigger> & { inset?: boolean }) {
93
- return <DropdownMenuPrimitive.SubmenuTrigger data-slot="dropdown-menu-sub-trigger" data-inset={inset} className={cn("data-highlighted:bg-accent data-highlighted:text-accent-foreground data-open:bg-accent data-open:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-none select-none data-[inset]:pl-8", className)} {...props}>{children}<ChevronRightIcon className="ml-auto size-4" /></DropdownMenuPrimitive.SubmenuTrigger>;
178
+ function DropdownMenuSubTrigger({
179
+ className,
180
+ inset,
181
+ children,
182
+ ...props
183
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.SubmenuTrigger> & { inset?: boolean }) {
184
+ return (
185
+ <DropdownMenuPrimitive.SubmenuTrigger
186
+ data-slot="dropdown-menu-sub-trigger"
187
+ data-inset={inset}
188
+ className={cn(
189
+ "data-highlighted:bg-muted data-highlighted:text-muted-foreground data-open:bg-muted data-open:text-muted-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-none select-none data-[inset]:pl-8",
190
+ className,
191
+ )}
192
+ {...props}
193
+ >
194
+ {children}
195
+ <ChevronRightIcon className="ml-auto size-4" />
196
+ </DropdownMenuPrimitive.SubmenuTrigger>
197
+ );
94
198
  }
95
199
 
96
- function DropdownMenuSubContent({ className, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Popup>) {
97
- return <DropdownMenuPrimitive.Popup data-slot="dropdown-menu-sub-content" className={cn("bg-popover text-popover-foreground data-open:animate-in data-closed:animate-out z-50 min-w-[8rem] overflow-hidden rounded-md border p-1 shadow-lg outline-none", className)} {...props} />;
200
+ function DropdownMenuSubContent({
201
+ className,
202
+ ...props
203
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Popup>) {
204
+ return (
205
+ <DropdownMenuPrimitive.Popup
206
+ data-slot="dropdown-menu-sub-content"
207
+ className={cn(
208
+ "bg-popover text-popover-foreground data-open:animate-in data-closed:animate-out z-50 min-w-[8rem] overflow-hidden rounded-md border p-1 shadow-lg outline-none",
209
+ className,
210
+ )}
211
+ {...props}
212
+ />
213
+ );
98
214
  }
99
215
 
100
216
  export {
@@ -7,11 +7,17 @@ function Popover({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Root
7
7
  return <PopoverPrimitive.Root data-slot="popover" {...props} />;
8
8
  }
9
9
 
10
- function PopoverTrigger({ asChild, children, ...props }: React.ComponentProps<typeof PopoverPrimitive.Trigger> & { asChild?: boolean }) {
10
+ function PopoverTrigger({
11
+ asChild,
12
+ children,
13
+ ...props
14
+ }: React.ComponentProps<typeof PopoverPrimitive.Trigger> & { asChild?: boolean }) {
11
15
  return (
12
16
  <PopoverPrimitive.Trigger
13
17
  data-slot="popover-trigger"
14
- {...(asChild && React.isValidElement(children) ? { render: children as React.ReactElement } : {})}
18
+ {...(asChild && React.isValidElement(children)
19
+ ? { render: children as React.ReactElement }
20
+ : {})}
15
21
  {...props}
16
22
  >
17
23
  {!asChild && children}
@@ -35,7 +41,12 @@ function PopoverContent({
35
41
  }) {
36
42
  return (
37
43
  <PopoverPrimitive.Portal>
38
- <PopoverPrimitive.Positioner align={align} side={side} sideOffset={sideOffset} collisionAvoidance={avoidCollisions ? undefined : { side: "none", align: "none" }}>
44
+ <PopoverPrimitive.Positioner
45
+ align={align}
46
+ side={side}
47
+ sideOffset={sideOffset}
48
+ collisionAvoidance={avoidCollisions ? undefined : { side: "none", align: "none" }}
49
+ >
39
50
  <PopoverPrimitive.Popup
40
51
  data-slot="popover-content"
41
52
  className={cn(
@@ -8,10 +8,16 @@ import { cn } from "../../lib/utils";
8
8
 
9
9
  const Sheet = SheetPrimitive.Root;
10
10
 
11
- function SheetTrigger({ asChild, children, ...props }: React.ComponentProps<typeof SheetPrimitive.Trigger> & { asChild?: boolean }) {
11
+ function SheetTrigger({
12
+ asChild,
13
+ children,
14
+ ...props
15
+ }: React.ComponentProps<typeof SheetPrimitive.Trigger> & { asChild?: boolean }) {
12
16
  return (
13
17
  <SheetPrimitive.Trigger
14
- {...(asChild && React.isValidElement(children) ? { render: children as React.ReactElement } : {})}
18
+ {...(asChild && React.isValidElement(children)
19
+ ? { render: children as React.ReactElement }
20
+ : {})}
15
21
  {...props}
16
22
  >
17
23
  {!asChild && children}
@@ -19,10 +25,16 @@ function SheetTrigger({ asChild, children, ...props }: React.ComponentProps<type
19
25
  );
20
26
  }
21
27
 
22
- function SheetClose({ asChild, children, ...props }: React.ComponentProps<typeof SheetPrimitive.Close> & { asChild?: boolean }) {
28
+ function SheetClose({
29
+ asChild,
30
+ children,
31
+ ...props
32
+ }: React.ComponentProps<typeof SheetPrimitive.Close> & { asChild?: boolean }) {
23
33
  return (
24
34
  <SheetPrimitive.Close
25
- {...(asChild && React.isValidElement(children) ? { render: children as React.ReactElement } : {})}
35
+ {...(asChild && React.isValidElement(children)
36
+ ? { render: children as React.ReactElement }
37
+ : {})}
26
38
  {...props}
27
39
  >
28
40
  {!asChild && children}
@@ -38,7 +50,7 @@ const SheetOverlay = React.forwardRef<
38
50
  >(({ className, ...props }, ref) => (
39
51
  <SheetPrimitive.Backdrop
40
52
  className={cn(
41
- "bg-black/80 data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 fixed inset-0 z-50 transition-opacity",
53
+ "data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 fixed inset-0 z-50 bg-black/80 transition-opacity",
42
54
  className,
43
55
  )}
44
56
  {...props}
@@ -59,7 +71,7 @@ const SheetContent = React.forwardRef<
59
71
  <SheetPortal>
60
72
  <SheetOverlay />
61
73
  <SheetPrimitive.Popup ref={ref} className={cn(sheetClassName, className)} {...props}>
62
- <SheetPrimitive.Close className="text-muted-foreground hover:bg-accent hover:text-accent-foreground focus-visible:outline-ring absolute top-3 right-3 inline-flex size-11 items-center justify-center rounded-md border border-transparent transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 disabled:pointer-events-none md:top-4 md:right-4">
74
+ <SheetPrimitive.Close className="text-muted-foreground hover:bg-muted hover:text-muted-foreground focus-visible:outline-ring absolute top-3 right-3 inline-flex size-9 items-center justify-center rounded-md border border-transparent transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 disabled:pointer-events-none md:top-4 md:right-4">
63
75
  <X className="size-4.5" />
64
76
  <span className="sr-only">Close</span>
65
77
  </SheetPrimitive.Close>
@@ -86,7 +98,11 @@ const SheetTitle = React.forwardRef<
86
98
  React.ComponentRef<typeof SheetPrimitive.Title>,
87
99
  React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>
88
100
  >(({ className, ...props }, ref) => (
89
- <SheetPrimitive.Title ref={ref} className={cn("text-lg font-semibold tracking-tight", className)} {...props} />
101
+ <SheetPrimitive.Title
102
+ ref={ref}
103
+ className={cn("text-lg font-semibold tracking-tight", className)}
104
+ {...props}
105
+ />
90
106
  ));
91
107
  SheetTitle.displayName = SheetPrimitive.Title.displayName;
92
108
 
@@ -96,7 +112,7 @@ const SheetDescription = React.forwardRef<
96
112
  >(({ className, ...props }, ref) => (
97
113
  <SheetPrimitive.Description
98
114
  ref={ref}
99
- className={cn("max-w-prose text-sm text-muted-foreground", className)}
115
+ className={cn("text-muted-foreground max-w-prose text-sm", className)}
100
116
  {...props}
101
117
  />
102
118
  ));
@@ -46,7 +46,11 @@ function Avatar({
46
46
  <AvatarContext.Provider value={{ size }}>
47
47
  <AvatarPrimitive.Root
48
48
  data-slot="avatar"
49
- className={cn("relative shrink-0 rounded-full select-none", avatarSize[size], className)}
49
+ className={cn(
50
+ "relative inline-flex shrink-0 rounded-full select-none",
51
+ avatarSize[size],
52
+ className,
53
+ )}
50
54
  {...props}
51
55
  >
52
56
  {children}
@@ -54,7 +58,7 @@ function Avatar({
54
58
  <span
55
59
  data-slot="avatar-badge"
56
60
  className={cn(
57
- "bg-accent ring-background absolute right-0 bottom-0 z-10 rounded-full ring-2",
61
+ "bg-primary ring-background absolute right-0 bottom-0 z-10 rounded-full ring-2",
58
62
  badgeDotSize[size],
59
63
  )}
60
64
  />
@@ -4,16 +4,19 @@ import * as React from "react";
4
4
  import { cn } from "../../lib/utils";
5
5
 
6
6
  const badgeVariants = cva(
7
- "inline-flex w-fit shrink-0 items-center justify-center gap-1 overflow-hidden whitespace-nowrap rounded border border-transparent px-1.5 py-px text-xs font-medium [&>svg]:size-3 [&>svg]:pointer-events-none aria-invalid:border-destructive aria-invalid:ring-destructive/20",
7
+ "state-settle inline-flex w-fit shrink-0 items-center justify-center gap-1 overflow-hidden whitespace-nowrap rounded border border-transparent px-1.5 py-px text-xs font-medium [&>svg]:size-3 [&>svg]:pointer-events-none aria-invalid:border-destructive aria-invalid:ring-destructive/20",
8
8
  {
9
9
  variants: {
10
10
  variant: {
11
11
  default: "bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
12
12
  secondary: "bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/80",
13
13
  destructive: "bg-destructive text-destructive-foreground [a&]:hover:bg-destructive/90",
14
- outline: "border-border text-foreground [a&]:hover:bg-accent",
14
+ outline: "border-border text-foreground [a&]:hover:bg-muted",
15
15
  ghost: "[a&]:[a&]: [a&]: [a&]:",
16
16
  link: "text-foreground underline-offset-4 [a&]:hover:underline",
17
+ /** Quiet metadata marker for real reference IDs (case/appointment/feed
18
+ * numbers) — never for decorative sequence markers. */
19
+ ref: "ref-tag border-transparent bg-transparent px-0 py-0 font-normal",
17
20
  },
18
21
  },
19
22
  defaultVariants: {
@@ -6,28 +6,22 @@ import { cn } from "../../lib/utils";
6
6
  import { Spinner } from "../feedback/spinner";
7
7
 
8
8
  const buttonVariants = cva(
9
- "inline-flex min-h-9 cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-md border border-transparent px-4 py-2 text-sm font-medium transition-colors outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
9
+ "inline-flex cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-md border border-transparent font-medium transition-colors outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
10
10
  {
11
11
  variants: {
12
12
  variant: {
13
- default:
14
- "bg-primary text-primary-foreground hover:bg-primary/90",
15
- destructive:
16
- "bg-destructive text-destructive-foreground hover:bg-destructive/90",
17
- outline:
18
- "border-input bg-background hover:bg-accent hover:text-accent-foreground",
19
- secondary:
20
- "border-input bg-secondary text-secondary-foreground hover:bg-secondary/80",
21
- ghost:
22
- "border-transparent bg-transparent hover:bg-accent hover:text-accent-foreground",
13
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
14
+ destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
15
+ outline: "border-input bg-background hover:bg-muted hover:text-muted-foreground",
16
+ secondary: "border-input bg-secondary text-secondary-foreground hover:bg-secondary/80",
17
+ ghost: "border-transparent bg-transparent hover:bg-muted hover:text-muted-foreground",
23
18
  link: "border-transparent bg-transparent px-0 text-primary underline-offset-4 hover:underline",
24
19
  },
25
20
  size: {
26
- sm: "min-h-11 px-2.5 text-sm",
27
- md: "min-h-11 px-3 text-sm",
28
- lg: "min-h-12 px-4 text-base",
29
- default: "",
30
- icon: "size-11 rounded-md p-0",
21
+ sm: "min-h-8 px-2.5 text-xs",
22
+ md: "min-h-9 px-3 text-sm",
23
+ lg: "min-h-10 px-4 text-base",
24
+ icon: "size-9 rounded-md p-0",
31
25
  },
32
26
  },
33
27
  defaultVariants: {
@@ -65,7 +59,9 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
65
59
  const renderedChild = React.cloneElement(child, {
66
60
  children: isLoading ? (
67
61
  <>
68
- <span className="opacity-0" aria-hidden="true">{child.props.children}</span>
62
+ <span className="opacity-0" aria-hidden="true">
63
+ {child.props.children}
64
+ </span>
69
65
  <span className="absolute inset-0 inline-flex items-center justify-center">
70
66
  <Spinner size="sm" aria-hidden="true" />
71
67
  </span>
@@ -105,7 +101,9 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
105
101
  >
106
102
  {isLoading ? (
107
103
  <>
108
- <span className="opacity-0" aria-hidden="true">{children}</span>
104
+ <span className="opacity-0" aria-hidden="true">
105
+ {children}
106
+ </span>
109
107
  <span className="absolute inset-0 inline-flex items-center justify-center">
110
108
  <Spinner size="sm" aria-hidden="true" />
111
109
  </span>
@@ -21,7 +21,7 @@ export const Default: Story = {
21
21
  <CardDescription>A short description of the card's content.</CardDescription>
22
22
  </CardHeader>
23
23
  <CardContent>
24
- <p className="text-sm text-muted-foreground">
24
+ <p className="text-muted-foreground text-sm">
25
25
  Card body content goes here. It can be any React node.
26
26
  </p>
27
27
  </CardContent>
@@ -47,7 +47,7 @@ export const Minimal: Story = {
47
47
  render: () => (
48
48
  <Card className="w-80">
49
49
  <CardContent>
50
- <p className="text-sm text-muted-foreground">Minimal card with only content.</p>
50
+ <p className="text-muted-foreground text-sm">Minimal card with only content.</p>
51
51
  </CardContent>
52
52
  </Card>
53
53
  ),
@@ -6,10 +6,7 @@ function Card({ className, ...props }: React.ComponentProps<"div">) {
6
6
  return (
7
7
  <div
8
8
  data-slot="card"
9
- className={cn(
10
- "bg-card text-card-foreground flex flex-col rounded-xl border",
11
- className,
12
- )}
9
+ className={cn("bg-card text-card-foreground flex flex-col rounded-xl border", className)}
13
10
  {...props}
14
11
  />
15
12
  );
@@ -36,7 +33,7 @@ function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
36
33
  return (
37
34
  <div
38
35
  data-slot="card-description"
39
- className={cn("text-sm text-muted-foreground", className)}
36
+ className={cn("text-muted-foreground text-sm", className)}
40
37
  {...props}
41
38
  />
42
39
  );
@@ -14,14 +14,14 @@ export const CHART_COLORS = {
14
14
  negative: "var(--color-chart-negative)",
15
15
  neutral: "var(--color-chart-neutral)",
16
16
 
17
- background: "var(--color-surface-canvas)",
17
+ background: "var(--color-background)",
18
18
  grid: "var(--color-border)",
19
19
 
20
20
  axis: "var(--color-muted-foreground)",
21
21
  label: "var(--color-muted-foreground)",
22
22
 
23
23
  tooltip: {
24
- background: "var(--color-surface-panel)",
24
+ background: "var(--color-card)",
25
25
  text: "var(--color-foreground)",
26
26
  border: "var(--color-border)",
27
27
  },
package/src/index.ts CHANGED
@@ -9,9 +9,9 @@ export { normalizeOtp, OTP_LENGTH } from "./lib/auth";
9
9
  export { copyToClipboard } from "./lib/clipboard";
10
10
  export { createMemoryStorage } from "./lib/create-memory-storage";
11
11
  export { cn } from "./lib/utils";
12
+ export { colors } from "./tokens/css-vars";
12
13
  export {
13
14
  animations,
14
- colors,
15
15
  colorThemes,
16
16
  colorTokenNames,
17
17
  containers,
@@ -0,0 +1,11 @@
1
+ /**
2
+ * React Native entry point.
3
+ *
4
+ * Kept as its own subpath (`@ponti-studios/ui/native`) because it is the only
5
+ * part of the package that imports `react-native`. Nothing here may import web
6
+ * code, so web consumers never pull React Native into their graph and native
7
+ * consumers never pull in react-dom.
8
+ */
9
+ export { createMakeStyles, type NamedStyles } from "./make-styles";
10
+ export { nativeShadows, type NativeShadowLayer } from "./shadows";
11
+ export { useColorMode, useThemeColors } from "./use-theme-colors";
@@ -0,0 +1,32 @@
1
+ import type { ImageStyle, TextStyle, ViewStyle } from "react-native";
2
+
3
+ export type NamedStyles = Record<string, ViewStyle | TextStyle | ImageStyle>;
4
+
5
+ /**
6
+ * Builds a `makeStyles` helper bound to a consuming app's own theme hook.
7
+ *
8
+ * The theme *shape* stays owned by the app — this package supplies only the
9
+ * mechanism — so `Theme` is a type parameter rather than a type exported from
10
+ * here. An app calls this once with its `useTheme` and uses the result
11
+ * everywhere:
12
+ *
13
+ * ```ts
14
+ * export const makeStyles = createMakeStyles(useTheme);
15
+ *
16
+ * const useStyles = makeStyles((theme) => ({
17
+ * card: { backgroundColor: theme.colors.card },
18
+ * }));
19
+ * ```
20
+ *
21
+ * The returned `useStyles` is a hook: it calls `useTheme` on every render, so
22
+ * styles re-resolve when the color mode changes. Styles are returned as plain
23
+ * objects rather than passed through `StyleSheet.create`, since they are
24
+ * rebuilt per render and React Native accepts plain style objects directly.
25
+ */
26
+ export function createMakeStyles<Theme>(useTheme: () => Theme) {
27
+ return function makeStyles<T extends NamedStyles>(factory: (theme: Theme) => T & NamedStyles) {
28
+ return function useStyles(): T {
29
+ return factory(useTheme());
30
+ };
31
+ };
32
+ }
@@ -0,0 +1,38 @@
1
+ import { shadows, type ShadowToken } from "../tokens";
2
+
3
+ /**
4
+ * One layer of a shadow in the shape React Native's `boxShadow` expects.
5
+ *
6
+ * The shared shadow tokens are authored for CSS, where each dimension carries
7
+ * its own unit. React Native takes bare numbers (density-independent pixels),
8
+ * so the unit is dropped here rather than at every call site.
9
+ */
10
+ export interface NativeShadowLayer {
11
+ color: string;
12
+ offsetX: number;
13
+ offsetY: number;
14
+ blurRadius: number;
15
+ spreadDistance: number;
16
+ inset: boolean;
17
+ }
18
+
19
+ /**
20
+ * The shared shadow scale translated to React Native's `boxShadow` shape.
21
+ *
22
+ * Every token maps to an array of layers, including `none`, which is a single
23
+ * fully transparent layer rather than an empty array — that keeps the value
24
+ * assignable wherever a real shadow is expected.
25
+ */
26
+ export const nativeShadows = Object.fromEntries(
27
+ Object.entries(shadows).map(([name, layers]) => [
28
+ name,
29
+ layers.map((layer) => ({
30
+ color: layer.color,
31
+ offsetX: layer.offsetX.value,
32
+ offsetY: layer.offsetY.value,
33
+ blurRadius: layer.blur.value,
34
+ spreadDistance: layer.spread.value,
35
+ inset: false,
36
+ })),
37
+ ]),
38
+ ) as Record<ShadowToken, NativeShadowLayer[]>;
@@ -0,0 +1,19 @@
1
+ import { useColorScheme } from "react-native";
2
+
3
+ import { colorThemes, type ColorMode, type ColorTheme } from "../tokens";
4
+
5
+ /**
6
+ * Resolves the active color mode from the OS appearance setting.
7
+ *
8
+ * React Native's `useColorScheme` reports `null` before the appearance module
9
+ * has settled, so anything that isn't explicitly "dark" resolves to light —
10
+ * callers always receive a concrete mode rather than having to handle null.
11
+ */
12
+ export function useColorMode(): ColorMode {
13
+ return useColorScheme() === "dark" ? "dark" : "light";
14
+ }
15
+
16
+ /** The full color token set for the active OS appearance. */
17
+ export function useThemeColors(): ColorTheme {
18
+ return colorThemes[useColorMode()];
19
+ }