@yuva-devlab/ui 1.0.1 → 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);
@@ -4323,6 +4352,7 @@ function LoadingState({
4323
4352
  CommandList,
4324
4353
  CommandSeparator,
4325
4354
  CommandShortcut,
4355
+ ConfigProvider,
4326
4356
  ConfirmDialog,
4327
4357
  ContextMenu,
4328
4358
  ContextMenuCheckboxItem,
@@ -4513,6 +4543,7 @@ function LoadingState({
4513
4543
  navigationMenuTriggerStyle,
4514
4544
  toast,
4515
4545
  toggleVariants,
4546
+ useConfig,
4516
4547
  useFormField,
4517
4548
  useIsMobile,
4518
4549
  useSidebar,