tembro 3.1.14 → 3.1.16

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 (45) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/components/modern/resizable-panel.d.ts +1 -1
  3. package/dist/components/patterns/form-builder.d.ts +9 -4
  4. package/dist/showcase/package-meta.d.ts +2 -2
  5. package/dist/src/components/display/status-legend.cjs +1 -1
  6. package/dist/src/components/display/status-legend.js +4 -4
  7. package/dist/src/components/modern/resizable-panel.cjs +1 -1
  8. package/dist/src/components/modern/resizable-panel.js +4 -4
  9. package/dist/src/components/notifications/notification-center.cjs +1 -1
  10. package/dist/src/components/notifications/notification-center.js +10 -10
  11. package/dist/src/components/patterns/detail-layout.cjs +1 -1
  12. package/dist/src/components/patterns/detail-layout.js +1 -1
  13. package/dist/src/components/patterns/form-builder.cjs +1 -1
  14. package/dist/src/components/patterns/form-builder.js +6 -6
  15. package/dist/src/components/patterns/resource-detail-page.cjs +1 -1
  16. package/dist/src/components/patterns/resource-detail-page.js +1 -1
  17. package/dist/src/components/patterns/resource-page.cjs +1 -1
  18. package/dist/src/components/patterns/resource-page.js +1 -1
  19. package/dist/src/components/ui/card/index.cjs +1 -1
  20. package/dist/src/components/ui/card/index.js +1 -0
  21. package/dist/src/showcase/package-meta.cjs +1 -1
  22. package/dist/src/showcase/package-meta.js +1 -1
  23. package/dist/src/showcase/registry-specific.cjs +1 -1
  24. package/dist/src/showcase/registry-specific.js +281 -233
  25. package/dist/src/showcase/site-data.cjs +1 -1
  26. package/dist/src/showcase/site-data.js +1 -1
  27. package/dist/src/showcase/tembro-registry.json.cjs +1 -1
  28. package/dist/src/showcase/tembro-registry.json.js +1 -1
  29. package/package.json +1 -1
  30. package/packages/cli/dist/index.cjs +1 -1
  31. package/packages/cli/vendor/src/components/display/status-legend.tsx +4 -4
  32. package/packages/cli/vendor/src/components/modern/resizable-panel.tsx +1 -1
  33. package/packages/cli/vendor/src/components/notifications/notification-center.tsx +11 -11
  34. package/packages/cli/vendor/src/components/patterns/detail-layout.tsx +1 -1
  35. package/packages/cli/vendor/src/components/patterns/form-builder.tsx +30 -30
  36. package/packages/cli/vendor/src/components/patterns/resource-detail-page.tsx +1 -1
  37. package/packages/cli/vendor/src/components/patterns/resource-page.tsx +1 -1
  38. package/packages/cli/vendor/src/components/ui/card/index.tsx +1 -0
  39. package/packages/cli/vendor/src/showcase/package-meta.ts +1 -1
  40. package/packages/cli/vendor/src/showcase/registry-specific.tsx +11 -1
  41. package/packages/cli/vendor/src/showcase/tembro-registry.json +1 -1
  42. package/packages/cli/vendor/templates/showcase/src/showcase/layout/HeroSection.tsx +2 -2
  43. package/packages/cli/vendor/templates/showcase/src/showcase/layout/WorkbenchSidebar.tsx +1 -1
  44. package/packages/cli/vendor/templates/styles/globals.css +60 -40
  45. package/registry.json +1 -1
@@ -47,21 +47,21 @@ function NotificationCenter({
47
47
  render={<PopoverTrigger />}
48
48
  variant="ghost"
49
49
  size="icon"
50
- className="relative rounded-full border border-[color:var(--aui-surface-border)] bg-[color:var(--aui-control-bg)] text-foreground shadow-sm hover:bg-[color:color-mix(in_srgb,var(--aui-control-bg)_82%,white_18%)]"
50
+ className="relative rounded-full border bg-white text-foreground shadow-sm hover:bg-muted dark:bg-neutral-950"
51
51
  >
52
52
  <BellIcon className="size-5" />
53
53
  {unreadCount > 0 && (
54
- <span className="absolute -right-1 -top-1 inline-flex min-w-5 items-center justify-center rounded-full bg-[color:var(--aui-brand-strong)] px-1.5 py-0.5 text-[10px] font-bold leading-none text-white shadow-[0_8px_20px_rgba(16,185,129,0.35)]">
54
+ <span className="absolute -right-1 -top-1 inline-flex min-w-5 items-center justify-center rounded-full bg-primary px-1.5 py-0.5 text-[10px] font-bold leading-none text-primary-foreground shadow-[0_8px_20px_rgba(16,185,129,0.24)]">
55
55
  {unreadCount}
56
56
  <span className="sr-only">{unreadCount} unread notifications</span>
57
57
  </span>
58
58
  )}
59
59
  </Button>
60
60
  <PopoverContent
61
- className="w-[24rem] overflow-hidden rounded-3xl border border-[color:var(--aui-surface-border)] bg-[color:var(--aui-page-bg)] p-0 shadow-[0_24px_60px_rgba(15,23,42,0.18)]"
61
+ className="isolate w-[24rem] overflow-hidden rounded-3xl border bg-white p-0 text-popover-foreground opacity-100 shadow-[0_24px_60px_rgba(15,23,42,0.18)] dark:bg-neutral-950"
62
62
  align="end"
63
63
  >
64
- <div className="flex items-center justify-between border-b border-[color:var(--aui-surface-border)] bg-[color:var(--aui-control-bg)] px-5 py-4">
64
+ <div className="flex items-center justify-between border-b bg-white px-5 py-4 dark:bg-neutral-950">
65
65
  <div className="grid gap-0.5">
66
66
  <h4 className="font-semibold tracking-tight text-foreground">{title}</h4>
67
67
  <span className="text-xs text-muted-foreground">
@@ -73,7 +73,7 @@ function NotificationCenter({
73
73
  <Button
74
74
  variant="ghost"
75
75
  size="sm"
76
- className="h-8 rounded-full border border-[color:var(--aui-surface-border)] px-3 text-xs font-semibold text-muted-foreground hover:bg-[color:var(--aui-page-bg)] hover:text-foreground"
76
+ className="h-8 rounded-full border px-3 text-xs font-semibold text-muted-foreground hover:bg-background hover:text-foreground"
77
77
  onClick={onMarkAllRead}
78
78
  >
79
79
  Mark all read
@@ -83,7 +83,7 @@ function NotificationCenter({
83
83
  <Button
84
84
  variant="ghost"
85
85
  size="sm"
86
- className="h-8 rounded-full border border-[color:var(--aui-surface-border)] px-3 text-xs font-semibold text-muted-foreground hover:bg-[color:var(--aui-page-bg)] hover:text-foreground"
86
+ className="h-8 rounded-full border px-3 text-xs font-semibold text-muted-foreground hover:bg-background hover:text-foreground"
87
87
  onClick={onClearAll}
88
88
  >
89
89
  Clear all
@@ -91,9 +91,9 @@ function NotificationCenter({
91
91
  ) : null}
92
92
  </div>
93
93
  </div>
94
- <div className="max-h-[400px] overflow-y-auto bg-[color:var(--aui-page-bg)] p-2">
94
+ <div className="max-h-[400px] overflow-y-auto bg-white p-2 dark:bg-neutral-950">
95
95
  {notifications.length === 0 ? (
96
- <div className="rounded-2xl border border-dashed border-[color:var(--aui-surface-border)] px-6 py-10 text-center text-sm text-muted-foreground">
96
+ <div className="rounded-2xl border border-dashed px-6 py-10 text-center text-sm text-muted-foreground">
97
97
  {emptyLabel}
98
98
  </div>
99
99
  ) : (
@@ -105,8 +105,8 @@ function NotificationCenter({
105
105
  <button
106
106
  key={notification.id}
107
107
  className={cn(
108
- "flex flex-col gap-1 rounded-2xl border border-transparent px-4 py-3 text-left transition hover:border-[color:var(--aui-surface-border)] hover:bg-[color:var(--aui-control-bg)]",
109
- !notification.read && "border-[color:color-mix(in_srgb,var(--aui-brand-strong)_16%,var(--aui-surface-border))] bg-[color:color-mix(in_srgb,var(--aui-brand-strong)_8%,var(--aui-control-bg))]"
108
+ "flex flex-col gap-1 rounded-2xl border border-transparent bg-white px-4 py-3 text-left transition hover:border-border hover:bg-muted dark:bg-neutral-950 dark:hover:bg-neutral-900",
109
+ !notification.read && "border-primary/20 bg-slate-50 dark:bg-neutral-900"
110
110
  )}
111
111
  onClick={() => onNotificationClick?.(notification)}
112
112
  >
@@ -115,7 +115,7 @@ function NotificationCenter({
115
115
  {notification.title}
116
116
  </span>
117
117
  {!notification.read && (
118
- <span className="mt-1 flex size-2 shrink-0 rounded-full bg-[color:var(--aui-brand-strong)] shadow-[0_0_0_4px_color-mix(in_srgb,var(--aui-brand-strong)_14%,transparent)]" />
118
+ <span className="mt-1 flex size-2 shrink-0 rounded-full bg-primary shadow-[0_0_0_4px_color-mix(in_srgb,var(--primary)_14%,transparent)]" />
119
119
  )}
120
120
  </div>
121
121
  {notification.description && (
@@ -55,7 +55,7 @@ function DetailLayout({
55
55
  {hasContent && (
56
56
  <div
57
57
  data-slot="detail-layout-content"
58
- className={cn("grid min-w-0 gap-4 xl:grid-cols-[minmax(0,1fr)_20rem]", contentClassName)}
58
+ className={cn("grid min-w-0 gap-4", aside && "xl:grid-cols-[minmax(0,1fr)_20rem]", contentClassName)}
59
59
  >
60
60
  <main data-slot="detail-layout-main" className="min-w-0">
61
61
  {children}
@@ -22,8 +22,10 @@ import {
22
22
  } from "@/components/form/form-date-range-input"
23
23
  import { cn } from "@/lib/utils"
24
24
 
25
- export type FormBuilderLayout = "grid" | "stack"
26
- export type FormBuilderDensity = "compact" | "default" | "comfortable"
25
+ export type FormBuilderLayout = "grid" | "stack"
26
+ export type FormBuilderDensity = "compact" | "default" | "comfortable"
27
+
28
+ type DistributiveOmit<T, TKey extends PropertyKey> = T extends unknown ? Omit<T, TKey> : never
27
29
 
28
30
  export type FormBuilderFieldRenderContext<TFieldValues extends FieldValues> = {
29
31
  control: Control<TFieldValues>
@@ -48,7 +50,7 @@ export type FormBuilderInputField<
48
50
  TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
49
51
  > = BaseFormBuilderField & {
50
52
  type: "input"
51
- props: Omit<FormInputProps<TFieldValues, TName>, "control">
53
+ props: DistributiveOmit<FormInputProps<TFieldValues, TName>, "control">
52
54
  }
53
55
 
54
56
  export type FormBuilderTextareaField<
@@ -64,7 +66,7 @@ export type FormBuilderSelectField<
64
66
  TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
65
67
  > = BaseFormBuilderField & {
66
68
  type: "select"
67
- props: Omit<FormSelectProps<TFieldValues, TName>, "control">
69
+ props: DistributiveOmit<FormSelectProps<TFieldValues, TName>, "control">
68
70
  }
69
71
 
70
72
  export type FormBuilderAsyncSelectField<
@@ -116,17 +118,14 @@ export type FormBuilderDateRangeField<
116
118
  props: Omit<FormDateRangeInputProps<TFieldValues, TFromName, TToName>, "control">
117
119
  }
118
120
 
119
- export type FormBuilderField<TFieldValues extends FieldValues> =
120
- | FormBuilderCustomField<TFieldValues>
121
- | FormBuilderInputField<TFieldValues>
122
- | FormBuilderTextareaField<TFieldValues>
123
- | FormBuilderSelectField<TFieldValues>
124
- | FormBuilderAsyncSelectField<TFieldValues>
125
- | FormBuilderSwitchField<TFieldValues>
126
- | FormBuilderNumberField<TFieldValues>
127
- | FormBuilderPhoneField<TFieldValues>
128
- | FormBuilderDateField<TFieldValues>
129
- | FormBuilderDateRangeField<TFieldValues>
121
+ type FormBuilderStoredField = BaseFormBuilderField & {
122
+ type: "input" | "textarea" | "select" | "async-select" | "switch" | "number" | "phone" | "date" | "date-range"
123
+ props: object
124
+ }
125
+
126
+ export type FormBuilderField<TFieldValues extends FieldValues> =
127
+ | FormBuilderCustomField<TFieldValues>
128
+ | FormBuilderStoredField
130
129
 
131
130
  export type FormBuilderSection<TFieldValues extends FieldValues> = {
132
131
  id: string
@@ -280,8 +279,11 @@ function renderFormBuilderField<TFieldValues extends FieldValues>(
280
279
  field: FormBuilderField<TFieldValues>,
281
280
  context: FormBuilderFieldRenderContext<TFieldValues>
282
281
  ) {
283
- const FormInputComponent = FormInput as unknown as React.ComponentType<Record<string, unknown>>
284
- const FormSelectComponent = FormSelect as unknown as React.ComponentType<Record<string, unknown>>
282
+ const FormInputComponent = FormInput as unknown as React.ComponentType<Record<string, unknown>>
283
+ const FormSelectComponent = FormSelect as unknown as React.ComponentType<Record<string, unknown>>
284
+ const FormTextareaComponent = FormTextarea as unknown as React.ComponentType<Record<string, unknown>>
285
+ const FormSwitchComponent = FormSwitch as unknown as React.ComponentType<Record<string, unknown>>
286
+ const FormDateRangeInputComponent = FormDateRangeInput as unknown as React.ComponentType<Record<string, unknown>>
285
287
 
286
288
  switch (field.type) {
287
289
  case "custom":
@@ -293,8 +295,8 @@ function renderFormBuilderField<TFieldValues extends FieldValues>(
293
295
  readOnly: context.readOnly,
294
296
  ...(field.props as Omit<FormInputProps<TFieldValues, FieldPath<TFieldValues>>, "control">),
295
297
  })
296
- case "textarea":
297
- return <FormTextarea control={context.control} disabled={context.disabled} readOnly={context.readOnly} {...field.props} />
298
+ case "textarea":
299
+ return React.createElement(FormTextareaComponent, { control: context.control, disabled: context.disabled, readOnly: context.readOnly, ...field.props })
298
300
  case "select":
299
301
  return React.createElement(FormSelectComponent, {
300
302
  control: context.control,
@@ -308,8 +310,8 @@ function renderFormBuilderField<TFieldValues extends FieldValues>(
308
310
  kind: "async",
309
311
  ...field.props,
310
312
  })
311
- case "switch":
312
- return <FormSwitch control={context.control} disabled={context.disabled} {...field.props} />
313
+ case "switch":
314
+ return React.createElement(FormSwitchComponent, { control: context.control, disabled: context.disabled, ...field.props })
313
315
  case "number":
314
316
  return React.createElement(FormInputComponent, {
315
317
  control: context.control,
@@ -334,15 +336,13 @@ function renderFormBuilderField<TFieldValues extends FieldValues>(
334
336
  kind: "date",
335
337
  ...field.props,
336
338
  })
337
- case "date-range":
338
- return (
339
- <FormDateRangeInput
340
- control={context.control}
341
- fromInputProps={{ disabled: context.disabled, readOnly: context.readOnly }}
342
- toInputProps={{ disabled: context.disabled, readOnly: context.readOnly }}
343
- {...field.props}
344
- />
345
- )
339
+ case "date-range":
340
+ return React.createElement(FormDateRangeInputComponent, {
341
+ control: context.control,
342
+ fromInputProps: { disabled: context.disabled, readOnly: context.readOnly },
343
+ toInputProps: { disabled: context.disabled, readOnly: context.readOnly },
344
+ ...field.props,
345
+ })
346
346
  default:
347
347
  return null
348
348
  }
@@ -120,7 +120,7 @@ function ResourceDetailPage({
120
120
  {(hasMainContent || aside) && (
121
121
  <div
122
122
  data-slot="resource-detail-page-content"
123
- className={cn("grid min-w-0 gap-4 xl:grid-cols-[minmax(0,1fr)_20rem]", contentClassName)}
123
+ className={cn("grid min-w-0 gap-4", aside && "xl:grid-cols-[minmax(0,1fr)_20rem]", contentClassName)}
124
124
  >
125
125
  <div data-slot="resource-detail-page-main" className="grid min-w-0 gap-4">
126
126
  {children}
@@ -136,7 +136,7 @@ function ResourcePage<TData, TValue = unknown>({
136
136
  {(hasMainContent || aside) && (
137
137
  <div
138
138
  data-slot="resource-page-content"
139
- className={cn("grid min-w-0 gap-4 xl:grid-cols-[minmax(0,1fr)_20rem]", contentClassName)}
139
+ className={cn("grid min-w-0 gap-4", aside && "xl:grid-cols-[minmax(0,1fr)_20rem]", contentClassName)}
140
140
  >
141
141
  <div data-slot="resource-page-main" className="grid min-w-0 gap-4">
142
142
  {children}
@@ -181,6 +181,7 @@ function Card({
181
181
  return (
182
182
  <div
183
183
  data-slot="card"
184
+ data-card=""
184
185
  data-surface={surfaceMode || undefined}
185
186
  data-size={size ?? "default"}
186
187
  data-variant={variant ?? "default"}
@@ -1,4 +1,4 @@
1
- export const PACKAGE_LATEST_VERSION = "3.1.14"
1
+ export const PACKAGE_LATEST_VERSION = "3.1.16"
2
2
  export const PACKAGE_LATEST_RELEASE_DATE = "July 15, 2026"
3
3
  export const PACKAGE_DEPENDENCY_RANGE = PACKAGE_LATEST_VERSION
4
4
 
@@ -48,7 +48,7 @@ import {
48
48
  Avatar,
49
49
  } from "@/index"
50
50
  import { PreviewFileDropzone as FileDropzone, PreviewStatCard as StatCard } from "@/showcase/preview-compositions"
51
- import { FormBuilder, customField, formSection } from "@/components/patterns/form-builder"
51
+ import { FormBuilder, customField, formSection, inputField, selectField, switchField, textareaField } from "@/components/patterns/form-builder"
52
52
  import { ResourceDetailPage } from "@/components/patterns/resource-detail-page"
53
53
  import { ResourcePage, ResourcePageSection } from "@/components/patterns/resource-page"
54
54
  import { useForm } from "react-hook-form"
@@ -750,6 +750,7 @@ function FormBuilderPreview() {
750
750
  email: string
751
751
  notes: string
752
752
  marketing: boolean
753
+ role: string
753
754
  }
754
755
 
755
756
  const form = useForm<FormBuilderDemoValues>({
@@ -758,6 +759,7 @@ function FormBuilderPreview() {
758
759
  email: "azamat@example.com",
759
760
  notes: "Release gate is ready.",
760
761
  marketing: true,
762
+ role: "admin",
761
763
  },
762
764
  })
763
765
 
@@ -779,6 +781,14 @@ function FormBuilderPreview() {
779
781
  </div>
780
782
  ),
781
783
  }),
784
+ inputField<FormBuilderDemoValues, "name">({ id: "name", props: { name: "name", label: "Name", required: true } }),
785
+ inputField<FormBuilderDemoValues, "email">({ id: "email", props: { name: "email", label: "Email", type: "email" } }),
786
+ selectField<FormBuilderDemoValues, "role">({ id: "role", props: { name: "role", label: "Role", options: [
787
+ { value: "admin", label: "Administrator" },
788
+ { value: "member", label: "Member" },
789
+ ] } }),
790
+ switchField<FormBuilderDemoValues, "marketing">({ id: "marketing", props: { name: "marketing", label: "Product updates" } }),
791
+ textareaField<FormBuilderDemoValues, "notes">({ id: "notes", colSpan: "full", props: { name: "notes", label: "Release notes" } }),
782
792
  ],
783
793
  }),
784
794
  ]
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://tembro.dev/registry.schema.json",
3
3
  "name": "tembro",
4
- "version": "3.1.14",
4
+ "version": "3.1.16",
5
5
  "description": "Reusable React + TypeScript UI kit registry",
6
6
  "groups": {
7
7
  "ui": [
@@ -25,7 +25,7 @@ export function HeroSection() {
25
25
  <div className="flex flex-wrap gap-2">
26
26
  <Button leftIcon={<PlusIcon className="size-4" />}>Create</Button>
27
27
  <Button variant="outline" leftIcon={<SettingsIcon className="size-4" />}>Settings</Button>
28
- <CopyButton value="npx tembro@3.1.14 list --json">Copy list command</CopyButton>
28
+ <CopyButton value="npx tembro@3.1.16 list --json">Copy list command</CopyButton>
29
29
  </div>
30
30
  </div>
31
31
 
@@ -33,7 +33,7 @@ export function HeroSection() {
33
33
  <StatisticCard label="Registry components" value={moduleCount} change="visible below" trend="up" description="tembro add <name>" />
34
34
  <StatisticCard label="Local source files" value="152" change="with hooks/lib" trend="up" description="installed by CLI" />
35
35
  <StatisticCard label="Categories" value={registryGroups.length} change="all shown" trend="up" description="actions to wizard" />
36
- <StatisticCard label="Build" value="Pass" change="doctor pass" trend="up" description="tembro@3.1.14" />
36
+ <StatisticCard label="Build" value="Pass" change="doctor pass" trend="up" description="tembro@3.1.16" />
37
37
  </StatisticGrid>
38
38
  </div>
39
39
  </section>
@@ -72,7 +72,7 @@ export function WorkbenchSidebar({ selectedKey, onSelect }: WorkbenchSidebarProp
72
72
  }),
73
73
  ]}
74
74
  footerAccount={{
75
- label: "tembro@3.1.14",
75
+ label: "tembro@3.1.16",
76
76
  description: `${moduleCount} registry components`,
77
77
  }}
78
78
  activeIndicator="bar"
@@ -95,6 +95,27 @@
95
95
  --aui-danger: var(--destructive);
96
96
  --aui-danger-foreground: oklch(0.985 0.004 95);
97
97
 
98
+ /* Compatibility aliases for components authored against the earlier theme contract. */
99
+ --aui-brand-strong: var(--primary);
100
+ --aui-control-bg: var(--aui-control-surface);
101
+ --aui-control-border: var(--input);
102
+ --aui-control-fg: var(--foreground);
103
+ --aui-divider: var(--border);
104
+ --aui-input-bg: var(--aui-control-surface);
105
+ --aui-input-border: var(--input);
106
+ --aui-input-border-hover: var(--aui-control-hover-border);
107
+ --aui-input-fg: var(--foreground);
108
+ --aui-page-bg: var(--background);
109
+ --aui-page-bg-alt: var(--muted);
110
+ --aui-page-foreground: var(--foreground);
111
+ --aui-popover-bg: var(--popover);
112
+ --aui-popover-fg: var(--popover-foreground);
113
+ --aui-ring: var(--ring);
114
+ --aui-shadow-card: var(--aui-card-shadow);
115
+ --aui-surface: var(--card);
116
+ --aui-surface-border: var(--aui-card-border);
117
+ --aui-text-muted: var(--muted-foreground);
118
+
98
119
  --aui-radius-control: var(--radius-md);
99
120
  --aui-radius-surface: var(--radius-lg);
100
121
  --aui-radius-overlay: var(--radius-xl);
@@ -133,9 +154,9 @@
133
154
  --aui-control-panel-bg: var(--aui-surface-raised);
134
155
  --aui-control-panel-shadow: var(--aui-shadow-md);
135
156
  --aui-card-radius: var(--aui-radius-surface);
136
- --aui-card-border: color-mix(in oklch, var(--border), white 8%);
137
- --aui-card-shadow: var(--aui-shadow-md);
138
- --aui-card-shadow-hover: var(--aui-shadow-lg);
157
+ --aui-card-border: var(--border);
158
+ --aui-card-shadow: var(--aui-shadow-xs);
159
+ --aui-card-shadow-hover: var(--aui-shadow-md);
139
160
  --aui-card-soft-bg: color-mix(in oklch, var(--muted), var(--background) 34%);
140
161
  --aui-card-outline-bg: var(--aui-surface-raised);
141
162
  --aui-popover-shadow: var(--aui-shadow-lg);
@@ -860,106 +881,105 @@
860
881
  box-shadow: var(--aui-control-shadow), 0 0 0 1px var(--aui-focus-ring), 0 0 0 5px var(--aui-focus-ring-soft);
861
882
  }
862
883
 
863
- [data-slot="card"][data-slot="card"],
864
- [data-slot="stat-card"][data-slot="stat-card"] {
884
+ :is([data-slot="card"], [data-card]) {
865
885
  border: 1px solid var(--aui-card-border);
866
886
  border-radius: var(--aui-card-radius);
867
887
  background: linear-gradient(180deg, color-mix(in oklch, var(--card), white 8%), var(--card));
868
888
  box-shadow: var(--aui-card-shadow);
869
889
  }
870
890
 
871
- [data-slot="card"] {
891
+ :is([data-slot="card"], [data-card]) {
872
892
  --card-spacing: 1.25rem;
873
893
  color: var(--card-foreground);
874
894
  font-size: 0.875rem;
875
895
  transition: background-color var(--aui-motion-normal) var(--aui-ease-standard), border-color var(--aui-motion-normal) var(--aui-ease-standard), box-shadow var(--aui-motion-normal) var(--aui-ease-standard), transform var(--aui-motion-normal) var(--aui-ease-standard), opacity var(--aui-motion-normal) var(--aui-ease-standard);
876
896
  }
877
897
 
878
- [data-slot="card"][data-size="sm"] { --card-spacing: 1rem; }
879
- [data-slot="card"][data-size="lg"] { --card-spacing: 1.5rem; }
880
- [data-slot="card"][data-density="compact"] { font-size: 0.75rem; }
881
- [data-slot="card"][data-density="comfortable"] { font-size: 1rem; }
882
- [data-slot="card"][data-variant="ghost"] { border-color: transparent; background: transparent; box-shadow: none; }
883
- [data-slot="card"] > img:first-child { border-radius: var(--aui-card-radius) var(--aui-card-radius) 0 0; }
884
- [data-slot="card"] > img:last-child { border-radius: 0 0 var(--aui-card-radius) var(--aui-card-radius); }
898
+ :is([data-slot="card"], [data-card])[data-size="sm"] { --card-spacing: 1rem; }
899
+ :is([data-slot="card"], [data-card])[data-size="lg"] { --card-spacing: 1.5rem; }
900
+ :is([data-slot="card"], [data-card])[data-density="compact"] { font-size: 0.75rem; }
901
+ :is([data-slot="card"], [data-card])[data-density="comfortable"] { font-size: 1rem; }
902
+ :is([data-slot="card"], [data-card])[data-variant="ghost"] { border-color: transparent; background: transparent; box-shadow: none; }
903
+ :is([data-slot="card"], [data-card]) > img:first-child { border-radius: var(--aui-card-radius) var(--aui-card-radius) 0 0; }
904
+ :is([data-slot="card"], [data-card]) > img:last-child { border-radius: 0 0 var(--aui-card-radius) var(--aui-card-radius); }
885
905
 
886
906
  [data-slot="card-header"] { border-radius: var(--aui-card-radius) var(--aui-card-radius) 0 0; }
887
907
  [data-slot="card-eyebrow"] { color: color-mix(in oklch, var(--muted-foreground), transparent 20%); font-size: 0.6875rem; font-weight: 650; letter-spacing: 0.18em; text-transform: uppercase; }
888
908
  [data-slot="card-title"] { font-family: var(--font-heading); font-size: 1.05rem; font-weight: 650; line-height: 1.35; letter-spacing: -0.02em; }
889
- [data-slot="card"][data-size="sm"] [data-slot="card-title"] { font-size: 0.875rem; }
890
- [data-slot="card"][data-size="lg"] [data-slot="card-title"] { font-size: 1.25rem; }
909
+ :is([data-slot="card"], [data-card])[data-size="sm"] [data-slot="card-title"] { font-size: 0.875rem; }
910
+ :is([data-slot="card"], [data-card])[data-size="lg"] [data-slot="card-title"] { font-size: 1.25rem; }
891
911
  [data-slot="card-description"] { color: var(--muted-foreground); font-size: 0.875rem; line-height: 1.5rem; }
892
912
  [data-slot="card-footer"] { border-top: 1px solid color-mix(in oklch, var(--border), transparent 40%); border-radius: 0 0 var(--aui-card-radius) var(--aui-card-radius); background: color-mix(in oklch, var(--muted), transparent 78%); }
893
913
 
894
- [data-slot="card"][data-variant="elevated"] {
914
+ :is([data-slot="card"], [data-card])[data-variant="elevated"] {
895
915
  box-shadow: 0 1px 0 oklch(1 0 0 / 76%), 0 24px 58px oklch(0.24 0.02 255 / 10%);
896
916
  }
897
917
 
898
- [data-slot="card"][data-variant="outline"] {
918
+ :is([data-slot="card"], [data-card])[data-variant="outline"] {
899
919
  background: var(--aui-card-outline-bg);
900
920
  box-shadow: none;
901
921
  }
902
922
 
903
- [data-slot="card"][data-variant="soft"] {
923
+ :is([data-slot="card"], [data-card])[data-variant="soft"] {
904
924
  border-color: color-mix(in oklch, var(--border), transparent 28%);
905
925
  background: var(--aui-card-soft-bg);
906
926
  box-shadow: none;
907
927
  }
908
928
 
909
- [data-slot="card"][data-tone="info"] {
929
+ :is([data-slot="card"], [data-card])[data-tone="info"] {
910
930
  background: linear-gradient(180deg, color-mix(in oklch, var(--card), var(--aui-info) 14%), var(--card));
911
931
  }
912
932
 
913
- [data-slot="card"][data-tone="success"] {
933
+ :is([data-slot="card"], [data-card])[data-tone="success"] {
914
934
  background: linear-gradient(180deg, color-mix(in oklch, var(--card), var(--aui-success) 14%), var(--card));
915
935
  }
916
936
 
917
- [data-slot="card"][data-tone="warning"] {
937
+ :is([data-slot="card"], [data-card])[data-tone="warning"] {
918
938
  background: linear-gradient(180deg, color-mix(in oklch, var(--card), var(--aui-warning) 14%), var(--card));
919
939
  }
920
940
 
921
- [data-slot="card"][data-tone="danger"] {
941
+ :is([data-slot="card"], [data-card])[data-tone="danger"] {
922
942
  background: linear-gradient(180deg, color-mix(in oklch, var(--card), var(--destructive) 10%), var(--card));
923
943
  }
924
944
 
925
- [data-slot="card"][data-interactive="true"]:hover {
945
+ :is([data-slot="card"], [data-card])[data-interactive="true"]:hover {
926
946
  border-color: var(--aui-control-hover-border);
927
947
  box-shadow: var(--aui-card-shadow-hover);
928
948
  }
929
949
 
930
- [data-slot="card"][data-interactive="true"]:focus-visible {
950
+ :is([data-slot="card"], [data-card])[data-interactive="true"]:focus-visible {
931
951
  box-shadow: var(--aui-card-shadow), 0 0 0 1px var(--aui-focus-ring), 0 0 0 5px var(--aui-focus-ring-soft);
932
952
  }
933
953
 
934
- [data-slot="card"][data-selected="true"] {
954
+ :is([data-slot="card"], [data-card])[data-selected="true"] {
935
955
  border-color: color-mix(in oklch, var(--primary), transparent 44%);
936
956
  box-shadow: var(--aui-card-shadow), 0 0 0 1px color-mix(in oklch, var(--primary), transparent 64%), 0 0 0 6px color-mix(in oklch, var(--primary), transparent 88%);
937
957
  }
938
958
 
939
- [data-slot="card"][data-disabled="true"] {
959
+ :is([data-slot="card"], [data-card])[data-disabled="true"] {
940
960
  box-shadow: none;
941
961
  opacity: 0.76;
942
962
  }
943
963
 
944
- [data-slot="card"][data-size="sm"] {
964
+ :is([data-slot="card"], [data-card])[data-size="sm"] {
945
965
  border-radius: var(--radius-xl);
946
966
  }
947
967
 
948
- [data-slot="card"][data-size="lg"] {
968
+ :is([data-slot="card"], [data-card])[data-size="lg"] {
949
969
  border-radius: var(--radius-3xl);
950
970
  }
951
971
 
952
- [data-slot="card"][data-density="compact"] [data-slot="card-description"] {
972
+ :is([data-slot="card"], [data-card])[data-density="compact"] [data-slot="card-description"] {
953
973
  font-size: 0.8125rem;
954
974
  line-height: 1.35;
955
975
  }
956
976
 
957
- [data-slot="card"][data-density="comfortable"] [data-slot="card-description"] {
977
+ :is([data-slot="card"], [data-card])[data-density="comfortable"] [data-slot="card-description"] {
958
978
  font-size: 0.975rem;
959
979
  line-height: 1.7;
960
980
  }
961
981
 
962
- [data-slot="card"] [data-slot="card"][data-slot="card"] {
982
+ :is([data-slot="card"], [data-card]) :is([data-slot="card"], [data-card]) {
963
983
  box-shadow: none;
964
984
  border-color: color-mix(in oklch, var(--border), transparent 18%);
965
985
  background: color-mix(in oklch, var(--muted), transparent 74%);
@@ -1724,9 +1744,9 @@
1724
1744
  }
1725
1745
 
1726
1746
  [data-slot="statistic-card"] {
1727
- border-color: var(--aui-surface-border);
1728
- background: var(--aui-surface);
1729
- box-shadow: var(--aui-shadow-card);
1747
+ border-color: var(--aui-card-border, var(--border));
1748
+ background: var(--card);
1749
+ box-shadow: var(--aui-card-shadow, var(--aui-shadow-xs));
1730
1750
  }
1731
1751
 
1732
1752
  [data-slot="statistic-label"],
@@ -1740,10 +1760,10 @@
1740
1760
  [data-slot="statistic-change"][data-trend="down"] { color: var(--destructive); background: color-mix(in oklch, var(--destructive), transparent 90%); }
1741
1761
 
1742
1762
  [data-slot="page-state"] {
1743
- border-color: var(--aui-surface-border);
1763
+ border-color: var(--aui-card-border, var(--border));
1744
1764
  border-radius: var(--aui-radius-panel);
1745
- background: var(--aui-surface);
1746
- box-shadow: var(--aui-shadow-card);
1765
+ background: var(--card);
1766
+ box-shadow: var(--aui-card-shadow, var(--aui-shadow-xs));
1747
1767
  }
1748
1768
 
1749
1769
  [data-slot="page-state-icon"] { color: var(--muted-foreground); background: var(--aui-surface-muted); }
@@ -1753,9 +1773,9 @@
1753
1773
 
1754
1774
  [data-slot="file-upload-dropzone"],
1755
1775
  [data-slot="file-upload-item"] {
1756
- border-color: var(--aui-surface-border);
1757
- background: var(--aui-surface);
1758
- box-shadow: var(--aui-shadow-card);
1776
+ border-color: var(--aui-card-border, var(--border));
1777
+ background: var(--card);
1778
+ box-shadow: var(--aui-card-shadow, var(--aui-shadow-xs));
1759
1779
  }
1760
1780
 
1761
1781
  [data-slot="file-upload-file-status"][data-status="success"] { color: var(--aui-success-fg); background: var(--aui-success-bg); }
package/registry.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://tembro.dev/registry.schema.json",
3
3
  "name": "tembro",
4
- "version": "3.1.14",
4
+ "version": "3.1.16",
5
5
  "description": "Reusable React + TypeScript UI kit registry",
6
6
  "groups": {
7
7
  "ui": [