@yuva-devlab/ui 1.0.0 → 1.1.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/README.md CHANGED
@@ -139,22 +139,42 @@ import { Container, Stack, Flex, Box } from "@yuva-devlab/ui";
139
139
  </Container>;
140
140
  ```
141
141
 
142
- ## Styling
142
+ ## Styling & Brand Theming
143
143
 
144
- This library uses Vanilla Extract for type-safe, zero-runtime CSS. All styles
145
- are compiled at build time.
144
+ ### 1. Global Styles Setup
146
145
 
147
- ### Importing Styles
146
+ Import the UI stylesheet in your root layout:
148
147
 
149
148
  ```tsx
150
- // Import global styles once in your app entry point
151
149
  import "@yuva-devlab/ui/styles.css";
152
150
  ```
153
151
 
154
- ### Theming
152
+ Or import specific brand themes directly:
155
153
 
156
- The library includes a natural theme by default. Custom theming support coming
157
- soon.
154
+ ```css
155
+ @import "@yuva-devlab/ui/styles.css";
156
+ @import "@yuva-devlab/ui/themes/finai.css";
157
+ ```
158
+
159
+ ### 2. Brand & Theme Provider (`ConfigProvider`)
160
+
161
+ Wrap your application with `ConfigProvider` (or `ThemeProvider`) and pass your `brand`:
162
+
163
+ ```tsx
164
+ import { ConfigProvider } from "@yuva-devlab/ui";
165
+
166
+ export function RootLayout({ children }: { children: React.ReactNode }) {
167
+ return (
168
+ <ConfigProvider brand="finai" defaultTheme="system">
169
+ {children}
170
+ </ConfigProvider>
171
+ );
172
+ }
173
+ ```
174
+
175
+ The provider sets the appropriate `data-brand` and `data-theme` attributes on `<html>`, instantly activating the scoped design tokens for that brand without loading or exposing styles of other brands!
176
+
177
+ ---
158
178
 
159
179
  ## Development
160
180
 
@@ -169,18 +189,13 @@ pnpm --filter @yuva-devlab/ui build
169
189
  pnpm --filter @yuva-devlab/ui test
170
190
 
171
191
  # Type check
172
- pnpm --filter @yuva-devlab/ui type-check
192
+ pnpm --filter @yuva-devlab/ui typecheck
173
193
  ```
174
194
 
175
195
  ## Documentation
176
196
 
177
197
  - **Storybook**: Run `pnpm dev:docs` to view interactive component documentation
178
198
  - **Playground**: Run `pnpm dev:playground` to test components in a live
179
- environment
180
-
181
- ## Related Packages
182
-
183
- - [@yuva-devlab/tokens](../tokens) - Tailwind CSS 4 preset and design token theme bridge
184
199
 
185
200
  ## License
186
201
 
package/dist/index.cjs CHANGED
@@ -94,6 +94,7 @@ __export(index_exports, {
94
94
  CommandList: () => CommandList,
95
95
  CommandSeparator: () => CommandSeparator,
96
96
  CommandShortcut: () => CommandShortcut,
97
+ ConfigProvider: () => ConfigProvider,
97
98
  ConfirmDialog: () => ConfirmDialog,
98
99
  ContextMenu: () => ContextMenu,
99
100
  ContextMenuCheckboxItem: () => ContextMenuCheckboxItem,
@@ -284,6 +285,7 @@ __export(index_exports, {
284
285
  navigationMenuTriggerStyle: () => navigationMenuTriggerStyle,
285
286
  toast: () => import_sonner.toast,
286
287
  toggleVariants: () => toggleVariants,
288
+ useConfig: () => useConfig,
287
289
  useFormField: () => useFormField,
288
290
  useIsMobile: () => useIsMobile,
289
291
  useSidebar: () => useSidebar,
@@ -303,15 +305,20 @@ var import_react = require("react");
303
305
  var import_jsx_runtime = require("react/jsx-runtime");
304
306
  var initialState = {
305
307
  theme: "system",
308
+ brand: "finai",
306
309
  setTheme: () => null,
310
+ setBrand: () => null,
307
311
  resolvedTheme: "dark"
308
312
  };
309
313
  var ThemeProviderContext = (0, import_react.createContext)(initialState);
310
314
  function ThemeProvider({
311
315
  children,
316
+ brand: initialBrand = "finai",
312
317
  defaultTheme = "system",
313
318
  storageKey = "yd-theme",
319
+ brandStorageKey = "yd-brand",
314
320
  attribute = "data-theme",
321
+ brandAttribute = "data-brand",
315
322
  enableSystem = true,
316
323
  ...props
317
324
  }) {
@@ -322,6 +329,13 @@ function ThemeProvider({
322
329
  }
323
330
  return defaultTheme;
324
331
  });
332
+ const [brand, setBrandState] = (0, import_react.useState)(() => {
333
+ if (typeof window !== "undefined") {
334
+ const stored = localStorage.getItem(brandStorageKey);
335
+ if (stored) return stored;
336
+ }
337
+ return initialBrand;
338
+ });
325
339
  const [resolvedTheme, setResolvedTheme] = (0, import_react.useState)("dark");
326
340
  (0, import_react.useEffect)(() => {
327
341
  const root = window.document.documentElement;
@@ -331,20 +345,33 @@ function ThemeProvider({
331
345
  const systemTheme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
332
346
  activeTheme = systemTheme;
333
347
  }
334
- const isDark = activeTheme.includes("dark") || activeTheme === "orchestrai";
348
+ const isDark = activeTheme.includes("dark") || activeTheme === "orchestrai" || brand === "orchestrai" && activeTheme !== "light";
335
349
  const resolved = isDark ? "dark" : "light";
336
350
  setResolvedTheme(resolved);
337
351
  root.classList.add(resolved);
352
+ if (brandAttribute && brand) {
353
+ root.setAttribute(brandAttribute, brand);
354
+ }
338
355
  if (attribute) {
339
- root.setAttribute(attribute, theme);
356
+ const combinedTheme = theme === "system" ? `${brand}-${resolved}` : theme.startsWith(brand) ? theme : `${brand}-${theme}`;
357
+ root.setAttribute(attribute, combinedTheme);
340
358
  }
341
- }, [theme, enableSystem, attribute]);
359
+ }, [theme, brand, enableSystem, attribute, brandAttribute]);
342
360
  const value = {
343
361
  theme,
362
+ brand,
344
363
  setTheme: (newTheme) => {
345
- localStorage.setItem(storageKey, newTheme);
364
+ if (typeof window !== "undefined") {
365
+ localStorage.setItem(storageKey, newTheme);
366
+ }
346
367
  setThemeState(newTheme);
347
368
  },
369
+ setBrand: (newBrand) => {
370
+ if (typeof window !== "undefined") {
371
+ localStorage.setItem(brandStorageKey, newBrand);
372
+ }
373
+ setBrandState(newBrand);
374
+ },
348
375
  resolvedTheme
349
376
  };
350
377
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemeProviderContext.Provider, { ...props, value, children });
@@ -356,6 +383,8 @@ var useTheme = () => {
356
383
  }
357
384
  return context;
358
385
  };
386
+ var ConfigProvider = ThemeProvider;
387
+ var useConfig = useTheme;
359
388
 
360
389
  // src/hooks/use-mobile.ts
361
390
  var React2 = __toESM(require("react"), 1);
@@ -428,7 +457,7 @@ var import_react_slot = require("@radix-ui/react-slot");
428
457
  var import_class_variance_authority = require("class-variance-authority");
429
458
  var import_jsx_runtime3 = require("react/jsx-runtime");
430
459
  var buttonVariants = (0, import_class_variance_authority.cva)(
431
- "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium cursor-pointer transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 disabled:cursor-not-allowed [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
460
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium cursor-pointer transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 disabled:cursor-not-allowed [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
432
461
  {
433
462
  variants: {
434
463
  variant: {
@@ -714,7 +743,10 @@ var BreadcrumbLink = React8.forwardRef(({ asChild, className, ...props }, ref) =
714
743
  Comp,
715
744
  {
716
745
  ref,
717
- className: cn("transition-colors hover:text-foreground", className),
746
+ className: cn(
747
+ "cursor-pointer transition-colors hover:text-foreground",
748
+ className
749
+ ),
718
750
  ...props
719
751
  }
720
752
  );
@@ -1430,7 +1462,7 @@ var Checkbox = React13.forwardRef(({ className, ...props }, ref) => /* @__PURE__
1430
1462
  {
1431
1463
  ref,
1432
1464
  className: cn(
1433
- "grid place-content-center peer shrink-0 rounded-sm border border-primary shadow cursor-pointer focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground size-4",
1465
+ "grid place-content-center peer shrink-0 rounded-sm border border-primary shadow cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground size-4",
1434
1466
  className
1435
1467
  ),
1436
1468
  ...props,
@@ -1490,7 +1522,7 @@ var DialogContent = React14.forwardRef(({ className, children, ...props }, ref)
1490
1522
  ...props,
1491
1523
  children: [
1492
1524
  children,
1493
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(DialogPrimitive.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background cursor-pointer transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground", children: [
1525
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(DialogPrimitive.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background cursor-pointer transition-opacity hover:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground", children: [
1494
1526
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react6.X, { className: "size-4" }),
1495
1527
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "sr-only", children: "Close" })
1496
1528
  ] })
@@ -1891,7 +1923,7 @@ var DropdownMenuSubTrigger = React18.forwardRef(({ className, inset, children, .
1891
1923
  {
1892
1924
  ref,
1893
1925
  className: cn(
1894
- "flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
1926
+ "flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
1895
1927
  inset && "pl-8",
1896
1928
  className
1897
1929
  ),
@@ -1934,7 +1966,7 @@ var DropdownMenuItem = React18.forwardRef(({ className, inset, ...props }, ref)
1934
1966
  {
1935
1967
  ref,
1936
1968
  className: cn(
1937
- "relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0",
1969
+ "relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0",
1938
1970
  inset && "pl-8",
1939
1971
  className
1940
1972
  ),
@@ -1947,7 +1979,7 @@ var DropdownMenuCheckboxItem = React18.forwardRef(({ className, children, ...pro
1947
1979
  {
1948
1980
  ref,
1949
1981
  className: cn(
1950
- "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50",
1982
+ "relative flex cursor-pointer select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50",
1951
1983
  className
1952
1984
  ),
1953
1985
  ...props,
@@ -1963,7 +1995,7 @@ var DropdownMenuRadioItem = React18.forwardRef(({ className, children, ...props
1963
1995
  {
1964
1996
  ref,
1965
1997
  className: cn(
1966
- "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50",
1998
+ "relative flex cursor-pointer select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50",
1967
1999
  className
1968
2000
  ),
1969
2001
  ...props,
@@ -2209,7 +2241,7 @@ var Input = React23.forwardRef(
2209
2241
  {
2210
2242
  type,
2211
2243
  className: cn(
2212
- "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
2244
+ "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:font-medium file:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
2213
2245
  className
2214
2246
  ),
2215
2247
  ref,
@@ -2757,7 +2789,7 @@ var SelectTrigger = React31.forwardRef(({ className, children, ...props }, ref)
2757
2789
  {
2758
2790
  ref,
2759
2791
  className: cn(
2760
- "flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background cursor-pointer data-placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
2792
+ "flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background cursor-pointer data-placeholder:text-muted-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 disabled:opacity-50 [&>span]:line-clamp-1",
2761
2793
  className
2762
2794
  ),
2763
2795
  ...props,
@@ -2800,7 +2832,7 @@ var SelectContent = React31.forwardRef(({ className, children, position = "poppe
2800
2832
  ref,
2801
2833
  className: cn(
2802
2834
  "relative z-50 max-h-(--radix-select-content-available-height) min-w-32 overflow-y-auto overflow-x-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-(--radix-select-content-transform-origin)",
2803
- position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
2835
+ position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1",
2804
2836
  className
2805
2837
  ),
2806
2838
  position,
@@ -2836,7 +2868,7 @@ var SelectItem = React31.forwardRef(({ className, children, ...props }, ref) =>
2836
2868
  {
2837
2869
  ref,
2838
2870
  className: cn(
2839
- "relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50",
2871
+ "relative flex w-full cursor-pointer select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50",
2840
2872
  className
2841
2873
  ),
2842
2874
  ...props,
@@ -3771,7 +3803,7 @@ var TabsTrigger = React39.forwardRef(({ className, ...props }, ref) => /* @__PUR
3771
3803
  {
3772
3804
  ref,
3773
3805
  className: cn(
3774
- "inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background cursor-pointer transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 disabled:cursor-not-allowed data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow",
3806
+ "inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background cursor-pointer transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow",
3775
3807
  className
3776
3808
  ),
3777
3809
  ...props
@@ -3783,7 +3815,7 @@ var TabsContent = React39.forwardRef(({ className, ...props }, ref) => /* @__PUR
3783
3815
  {
3784
3816
  ref,
3785
3817
  className: cn(
3786
- "mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
3818
+ "mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2",
3787
3819
  className
3788
3820
  ),
3789
3821
  ...props
@@ -3799,7 +3831,7 @@ var Textarea = React40.forwardRef(({ className, ...props }, ref) => {
3799
3831
  "textarea",
3800
3832
  {
3801
3833
  className: cn(
3802
- "flex min-h-15 w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
3834
+ "flex min-h-15 w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
3803
3835
  className
3804
3836
  ),
3805
3837
  ref,
@@ -4320,6 +4352,7 @@ function LoadingState({
4320
4352
  CommandList,
4321
4353
  CommandSeparator,
4322
4354
  CommandShortcut,
4355
+ ConfigProvider,
4323
4356
  ConfirmDialog,
4324
4357
  ContextMenu,
4325
4358
  ContextMenuCheckboxItem,
@@ -4510,6 +4543,7 @@ function LoadingState({
4510
4543
  navigationMenuTriggerStyle,
4511
4544
  toast,
4512
4545
  toggleVariants,
4546
+ useConfig,
4513
4547
  useFormField,
4514
4548
  useIsMobile,
4515
4549
  useSidebar,