@webstacks/ui 0.4.3 → 0.4.5

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
@@ -27,17 +27,20 @@ This package includes:
27
27
 
28
28
  ## Usage
29
29
 
30
- Import components directly from the package:
30
+ ### 1. Add the theme to your CSS
31
31
 
32
- ```tsx
33
- import { Button } from "@webstacks/ui";
32
+ In your app's main CSS file (e.g. `index.css`), import Tailwind and the `@webstacks/ui` theme:
34
33
 
35
- function App() {
36
- return <Button>Hello world</Button>;
37
- }
34
+ ```css
35
+ @import "tailwindcss";
36
+ @import "@webstacks/ui/theme";
38
37
  ```
39
38
 
40
- At the root of your application, wrap your content with the `BaseStyles` component. This injects all design tokens, fonts, color primitives, and base styles:
39
+ This registers all design tokens, fonts, colors, and component classes with Tailwind v4 at build time. No other CSS imports are needed.
40
+
41
+ ### 2. Wrap your app with BaseStyles
42
+
43
+ At the root of your application, wrap your content with `BaseStyles` to activate the design tokens at runtime:
41
44
 
42
45
  ```tsx
43
46
  import { BaseStyles } from "@webstacks/ui";
@@ -47,6 +50,21 @@ function RootLayout({ children }) {
47
50
  }
48
51
  ```
49
52
 
53
+ ### 3. Use components
54
+
55
+ ```tsx
56
+ import { Button, Heading, Section } from "@webstacks/ui";
57
+
58
+ function App() {
59
+ return (
60
+ <Section paddingBlockStart="spacious" paddingBlockEnd="spacious">
61
+ <Heading as="h1" size="display">Hello world</Heading>
62
+ <Button>Get Started</Button>
63
+ </Section>
64
+ );
65
+ }
66
+ ```
67
+
50
68
  ### Color mode
51
69
 
52
70
  `BaseStyles` accepts a `colorMode` prop to control light/dark theming:
@@ -62,14 +80,6 @@ function RootLayout({ children }) {
62
80
  <BaseStyles colorMode="auto">
63
81
  ```
64
82
 
65
- ### Alternative: manual CSS import
66
-
67
- If you prefer not to use `BaseStyles`, you can import the styles directly in your entry point:
68
-
69
- ```tsx
70
- import "@webstacks/ui/styles.css";
71
- ```
72
-
73
83
  ## Components
74
84
 
75
85
  ### Layout
package/dist/index.cjs CHANGED
@@ -582,37 +582,148 @@ var import_react_slot = require("@radix-ui/react-slot");
582
582
  var import_class_variance_authority2 = require("class-variance-authority");
583
583
  var import_jsx_runtime4 = require("react/jsx-runtime");
584
584
  var buttonVariants = (0, import_class_variance_authority2.cva)(
585
- "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-full text-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
585
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-full transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:cursor-not-allowed [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
586
586
  {
587
587
  variants: {
588
- variant: {
589
- default: "bg-primary text-primary-foreground hover:bg-primary/90",
590
- destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
591
- outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
592
- secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
593
- ghost: "hover:bg-accent hover:text-accent-foreground",
594
- link: "text-primary underline-offset-4 hover:underline"
588
+ mode: {
589
+ filled: "",
590
+ stroke: "bg-transparent border",
591
+ bleed: "!bg-transparent border-0 !rounded hover:!bg-foreground/5 disabled:opacity-50",
592
+ link: "disabled:opacity-50"
593
+ },
594
+ tone: {
595
+ primary: "",
596
+ secondary: "",
597
+ tertiary: ""
595
598
  },
596
599
  size: {
597
- default: "h-9 px-4 py-2",
598
- sm: "h-8 px-3 text-xs",
599
- lg: "h-10 px-8",
600
+ xs: "",
601
+ sm: "px-4 py-2 text-xs",
602
+ md: "px-6 py-3 text-sm",
603
+ lg: "px-8 py-4 text-base",
600
604
  icon: "h-9 w-9"
605
+ },
606
+ fullWidth: {
607
+ true: "w-full",
608
+ false: ""
601
609
  }
602
610
  },
603
611
  defaultVariants: {
604
- variant: "default",
605
- size: "default"
606
- }
612
+ mode: "filled",
613
+ tone: "primary",
614
+ size: "md"
615
+ },
616
+ compoundVariants: [
617
+ /* ── Filled ── */
618
+ {
619
+ mode: "filled",
620
+ tone: "primary",
621
+ className: "bg-primary text-primary-foreground hover:bg-primary/90 disabled:opacity-50"
622
+ },
623
+ {
624
+ mode: "filled",
625
+ tone: "secondary",
626
+ className: "bg-foreground text-background hover:bg-foreground/90 dark:bg-background dark:text-foreground dark:hover:bg-background/90 dark:border dark:border-border disabled:opacity-50"
627
+ },
628
+ {
629
+ mode: "filled",
630
+ tone: "tertiary",
631
+ className: "bg-muted text-foreground hover:bg-muted/80 disabled:opacity-50"
632
+ },
633
+ /* ── Stroke ── */
634
+ {
635
+ mode: "stroke",
636
+ tone: "primary",
637
+ className: "border-primary text-primary hover:bg-primary hover:text-primary-foreground disabled:opacity-50"
638
+ },
639
+ {
640
+ mode: "stroke",
641
+ tone: "secondary",
642
+ className: "border-border text-foreground hover:bg-primary hover:text-primary-foreground hover:border-primary disabled:opacity-50"
643
+ },
644
+ {
645
+ mode: "stroke",
646
+ tone: "tertiary",
647
+ className: "border-border text-foreground hover:bg-accent disabled:opacity-50"
648
+ },
649
+ /* ── Bleed ── */
650
+ {
651
+ mode: "bleed",
652
+ tone: "primary",
653
+ className: "text-foreground"
654
+ },
655
+ {
656
+ mode: "bleed",
657
+ tone: "secondary",
658
+ className: "text-foreground"
659
+ },
660
+ {
661
+ mode: "bleed",
662
+ tone: "tertiary",
663
+ className: "text-muted-foreground"
664
+ },
665
+ /* ── Link ── */
666
+ {
667
+ mode: "link",
668
+ tone: "primary",
669
+ className: "text-primary underline-offset-4 hover:underline"
670
+ },
671
+ {
672
+ mode: "link",
673
+ tone: "secondary",
674
+ className: "text-foreground underline-offset-4 hover:underline"
675
+ },
676
+ {
677
+ mode: "link",
678
+ tone: "tertiary",
679
+ className: "text-muted-foreground underline-offset-4 hover:underline"
680
+ },
681
+ /* ── Link + Bleed size overrides ── */
682
+ {
683
+ mode: "link",
684
+ size: "xs",
685
+ className: "text-xs"
686
+ },
687
+ {
688
+ mode: "link",
689
+ size: "sm",
690
+ className: "px-0 py-0 text-sm"
691
+ },
692
+ {
693
+ mode: "link",
694
+ size: "md",
695
+ className: "px-0 py-0 text-sm"
696
+ },
697
+ {
698
+ mode: "link",
699
+ size: "lg",
700
+ className: "px-0 py-0 text-base"
701
+ },
702
+ {
703
+ mode: "bleed",
704
+ size: "sm",
705
+ className: "px-2 py-1 text-sm"
706
+ },
707
+ {
708
+ mode: "bleed",
709
+ size: "md",
710
+ className: "px-3 py-2 text-sm"
711
+ },
712
+ {
713
+ mode: "bleed",
714
+ size: "lg",
715
+ className: "px-3 py-2 text-base"
716
+ }
717
+ ]
607
718
  }
608
719
  );
609
720
  var Button = React6.forwardRef(
610
- ({ className, variant, size, asChild = false, ...props }, ref) => {
721
+ ({ className, mode, tone, size, fullWidth, asChild = false, ...props }, ref) => {
611
722
  const Comp = asChild ? import_react_slot.Slot : "button";
612
723
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
613
724
  Comp,
614
725
  {
615
- className: cn(buttonVariants({ variant, size, className })),
726
+ className: cn(buttonVariants({ mode, tone, size, fullWidth, className })),
616
727
  ref,
617
728
  ...props
618
729
  }
@@ -713,7 +824,7 @@ var AlertDialogCancel = React7.forwardRef(({ className, ...props }, ref) => /* @
713
824
  {
714
825
  ref,
715
826
  className: cn(
716
- buttonVariants({ variant: "outline" }),
827
+ buttonVariants({ mode: "stroke", tone: "secondary" }),
717
828
  "mt-2 sm:mt-0",
718
829
  className
719
830
  ),
@@ -1175,6 +1286,34 @@ var columnMap = {
1175
1286
  11: "grid-cols-11",
1176
1287
  12: "grid-cols-12"
1177
1288
  };
1289
+ var mdColumnMap = {
1290
+ 1: "md:grid-cols-1",
1291
+ 2: "md:grid-cols-2",
1292
+ 3: "md:grid-cols-3",
1293
+ 4: "md:grid-cols-4",
1294
+ 5: "md:grid-cols-5",
1295
+ 6: "md:grid-cols-6",
1296
+ 7: "md:grid-cols-7",
1297
+ 8: "md:grid-cols-8",
1298
+ 9: "md:grid-cols-9",
1299
+ 10: "md:grid-cols-10",
1300
+ 11: "md:grid-cols-11",
1301
+ 12: "md:grid-cols-12"
1302
+ };
1303
+ var lgColumnMap = {
1304
+ 1: "lg:grid-cols-1",
1305
+ 2: "lg:grid-cols-2",
1306
+ 3: "lg:grid-cols-3",
1307
+ 4: "lg:grid-cols-4",
1308
+ 5: "lg:grid-cols-5",
1309
+ 6: "lg:grid-cols-6",
1310
+ 7: "lg:grid-cols-7",
1311
+ 8: "lg:grid-cols-8",
1312
+ 9: "lg:grid-cols-9",
1313
+ 10: "lg:grid-cols-10",
1314
+ 11: "lg:grid-cols-11",
1315
+ 12: "lg:grid-cols-12"
1316
+ };
1178
1317
  var Grid = React11.forwardRef(
1179
1318
  ({ as: Comp = "div", className, columns = 12, gap, gapX, gapY, align, justify, ...props }, ref) => {
1180
1319
  let columnClasses;
@@ -1183,8 +1322,8 @@ var Grid = React11.forwardRef(
1183
1322
  } else {
1184
1323
  const classes = [];
1185
1324
  if (columns.narrow) classes.push(columnMap[columns.narrow]);
1186
- if (columns.regular) classes.push(`md:${columnMap[columns.regular]}`);
1187
- if (columns.wide) classes.push(`lg:${columnMap[columns.wide]}`);
1325
+ if (columns.regular) classes.push(mdColumnMap[columns.regular]);
1326
+ if (columns.wide) classes.push(lgColumnMap[columns.wide]);
1188
1327
  columnClasses = classes.join(" ");
1189
1328
  }
1190
1329
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
@@ -1249,6 +1388,34 @@ var spanMap = {
1249
1388
  11: "col-span-11",
1250
1389
  12: "col-span-12"
1251
1390
  };
1391
+ var mdSpanMap = {
1392
+ 1: "md:col-span-1",
1393
+ 2: "md:col-span-2",
1394
+ 3: "md:col-span-3",
1395
+ 4: "md:col-span-4",
1396
+ 5: "md:col-span-5",
1397
+ 6: "md:col-span-6",
1398
+ 7: "md:col-span-7",
1399
+ 8: "md:col-span-8",
1400
+ 9: "md:col-span-9",
1401
+ 10: "md:col-span-10",
1402
+ 11: "md:col-span-11",
1403
+ 12: "md:col-span-12"
1404
+ };
1405
+ var lgSpanMap = {
1406
+ 1: "lg:col-span-1",
1407
+ 2: "lg:col-span-2",
1408
+ 3: "lg:col-span-3",
1409
+ 4: "lg:col-span-4",
1410
+ 5: "lg:col-span-5",
1411
+ 6: "lg:col-span-6",
1412
+ 7: "lg:col-span-7",
1413
+ 8: "lg:col-span-8",
1414
+ 9: "lg:col-span-9",
1415
+ 10: "lg:col-span-10",
1416
+ 11: "lg:col-span-11",
1417
+ 12: "lg:col-span-12"
1418
+ };
1252
1419
  var GridColumn = React11.forwardRef(
1253
1420
  ({ as: Comp = "div", className, span, start, ...props }, ref) => {
1254
1421
  let spanClasses;
@@ -1257,8 +1424,8 @@ var GridColumn = React11.forwardRef(
1257
1424
  } else if (span) {
1258
1425
  const classes = [];
1259
1426
  if (span.narrow) classes.push(spanMap[span.narrow]);
1260
- if (span.regular) classes.push(`md:${spanMap[span.regular]}`);
1261
- if (span.wide) classes.push(`lg:${spanMap[span.wide]}`);
1427
+ if (span.regular) classes.push(mdSpanMap[span.regular]);
1428
+ if (span.wide) classes.push(lgSpanMap[span.wide]);
1262
1429
  spanClasses = classes.join(" ");
1263
1430
  } else {
1264
1431
  spanClasses = "";
@@ -1707,6 +1874,14 @@ var directionMap = {
1707
1874
  horizontal: "flex-row",
1708
1875
  vertical: "flex-col"
1709
1876
  };
1877
+ var mdDirectionMap = {
1878
+ horizontal: "md:flex-row",
1879
+ vertical: "md:flex-col"
1880
+ };
1881
+ var lgDirectionMap = {
1882
+ horizontal: "lg:flex-row",
1883
+ vertical: "lg:flex-col"
1884
+ };
1710
1885
  var gapMap = {
1711
1886
  none: "gap-0",
1712
1887
  condensed: "gap-2",
@@ -1714,6 +1889,20 @@ var gapMap = {
1714
1889
  spacious: "gap-6",
1715
1890
  "extra-spacious": "gap-8"
1716
1891
  };
1892
+ var mdGapMap = {
1893
+ none: "md:gap-0",
1894
+ condensed: "md:gap-2",
1895
+ normal: "md:gap-4",
1896
+ spacious: "md:gap-6",
1897
+ "extra-spacious": "md:gap-8"
1898
+ };
1899
+ var lgGapMap = {
1900
+ none: "lg:gap-0",
1901
+ condensed: "lg:gap-2",
1902
+ normal: "lg:gap-4",
1903
+ spacious: "lg:gap-6",
1904
+ "extra-spacious": "lg:gap-8"
1905
+ };
1717
1906
  var alignMap = {
1718
1907
  start: "items-start",
1719
1908
  center: "items-center",
@@ -1721,6 +1910,20 @@ var alignMap = {
1721
1910
  stretch: "items-stretch",
1722
1911
  baseline: "items-baseline"
1723
1912
  };
1913
+ var mdAlignMap = {
1914
+ start: "md:items-start",
1915
+ center: "md:items-center",
1916
+ end: "md:items-end",
1917
+ stretch: "md:items-stretch",
1918
+ baseline: "md:items-baseline"
1919
+ };
1920
+ var lgAlignMap = {
1921
+ start: "lg:items-start",
1922
+ center: "lg:items-center",
1923
+ end: "lg:items-end",
1924
+ stretch: "lg:items-stretch",
1925
+ baseline: "lg:items-baseline"
1926
+ };
1724
1927
  var justifyMap = {
1725
1928
  start: "justify-start",
1726
1929
  center: "justify-center",
@@ -1729,16 +1932,37 @@ var justifyMap = {
1729
1932
  "space-around": "justify-around",
1730
1933
  "space-evenly": "justify-evenly"
1731
1934
  };
1732
- function resolveResponsive3(value, map) {
1935
+ var mdJustifyMap = {
1936
+ start: "md:justify-start",
1937
+ center: "md:justify-center",
1938
+ end: "md:justify-end",
1939
+ "space-between": "md:justify-between",
1940
+ "space-around": "md:justify-around",
1941
+ "space-evenly": "md:justify-evenly"
1942
+ };
1943
+ var lgJustifyMap = {
1944
+ start: "lg:justify-start",
1945
+ center: "lg:justify-center",
1946
+ end: "lg:justify-end",
1947
+ "space-between": "lg:justify-between",
1948
+ "space-around": "lg:justify-around",
1949
+ "space-evenly": "lg:justify-evenly"
1950
+ };
1951
+ function resolveResponsive3(value, maps) {
1733
1952
  if (!value) return [];
1734
- if (typeof value === "string") return [map[value]].filter(Boolean);
1953
+ if (typeof value === "string") return [maps.narrow[value]].filter(Boolean);
1735
1954
  const classes = [];
1736
- const prefixes = { narrow: "", regular: "md:", wide: "lg:" };
1737
- for (const [bp, val] of Object.entries(value)) {
1738
- if (val && map[val]) {
1739
- const prefix = prefixes[bp] || "";
1740
- classes.push(`${prefix}${map[val]}`);
1741
- }
1955
+ if (value.narrow) {
1956
+ const cls = maps.narrow[value.narrow];
1957
+ if (cls) classes.push(cls);
1958
+ }
1959
+ if (value.regular) {
1960
+ const cls = maps.regular[value.regular];
1961
+ if (cls) classes.push(cls);
1962
+ }
1963
+ if (value.wide) {
1964
+ const cls = maps.wide[value.wide];
1965
+ if (cls) classes.push(cls);
1742
1966
  }
1743
1967
  return classes;
1744
1968
  }
@@ -1755,10 +1979,10 @@ var Stack = React15.forwardRef(
1755
1979
  ...props
1756
1980
  }, ref) => {
1757
1981
  const responsiveClasses = [
1758
- ...resolveResponsive3(direction, directionMap),
1759
- ...resolveResponsive3(gap, gapMap),
1760
- ...resolveResponsive3(align, alignMap),
1761
- ...resolveResponsive3(justify, justifyMap)
1982
+ ...resolveResponsive3(direction, { narrow: directionMap, regular: mdDirectionMap, wide: lgDirectionMap }),
1983
+ ...resolveResponsive3(gap, { narrow: gapMap, regular: mdGapMap, wide: lgGapMap }),
1984
+ ...resolveResponsive3(align, { narrow: alignMap, regular: mdAlignMap, wide: lgAlignMap }),
1985
+ ...resolveResponsive3(justify, { narrow: justifyMap, regular: mdJustifyMap, wide: lgJustifyMap })
1762
1986
  ];
1763
1987
  const isResponsiveDirection = typeof direction === "object";
1764
1988
  const isResponsiveGap = typeof gap === "object";
@@ -1800,7 +2024,8 @@ function Calendar({
1800
2024
  classNames,
1801
2025
  showOutsideDays = true,
1802
2026
  captionLayout = "label",
1803
- buttonVariant = "ghost",
2027
+ buttonMode = "bleed",
2028
+ buttonTone = "primary",
1804
2029
  formatters,
1805
2030
  components,
1806
2031
  ...props
@@ -1833,12 +2058,12 @@ function Calendar({
1833
2058
  defaultClassNames.nav
1834
2059
  ),
1835
2060
  button_previous: cn(
1836
- buttonVariants({ variant: buttonVariant }),
2061
+ buttonVariants({ mode: buttonMode, tone: buttonTone }),
1837
2062
  "h-[--cell-size] w-[--cell-size] select-none p-0 aria-disabled:opacity-50",
1838
2063
  defaultClassNames.button_previous
1839
2064
  ),
1840
2065
  button_next: cn(
1841
- buttonVariants({ variant: buttonVariant }),
2066
+ buttonVariants({ mode: buttonMode, tone: buttonTone }),
1842
2067
  "h-[--cell-size] w-[--cell-size] select-none p-0 aria-disabled:opacity-50",
1843
2068
  defaultClassNames.button_next
1844
2069
  ),
@@ -1955,7 +2180,7 @@ function CalendarDayButton({
1955
2180
  Button,
1956
2181
  {
1957
2182
  ref,
1958
- variant: "ghost",
2183
+ mode: "bleed",
1959
2184
  size: "icon",
1960
2185
  "data-day": day.date.toLocaleDateString(),
1961
2186
  "data-selected-single": modifiers.selected && !modifiers.range_start && !modifiers.range_end && !modifiers.range_middle,
@@ -2164,13 +2389,14 @@ var CarouselItem = React18.forwardRef(({ className, ...props }, ref) => {
2164
2389
  );
2165
2390
  });
2166
2391
  CarouselItem.displayName = "CarouselItem";
2167
- var CarouselPrevious = React18.forwardRef(({ className, variant = "outline", size = "icon", ...props }, ref) => {
2392
+ var CarouselPrevious = React18.forwardRef(({ className, mode = "stroke", tone = "secondary", size = "icon", ...props }, ref) => {
2168
2393
  const { orientation, scrollPrev, canScrollPrev } = useCarousel();
2169
2394
  return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
2170
2395
  Button,
2171
2396
  {
2172
2397
  ref,
2173
- variant,
2398
+ mode,
2399
+ tone,
2174
2400
  size,
2175
2401
  className: cn(
2176
2402
  "absolute h-8 w-8 rounded-full",
@@ -2188,13 +2414,14 @@ var CarouselPrevious = React18.forwardRef(({ className, variant = "outline", siz
2188
2414
  );
2189
2415
  });
2190
2416
  CarouselPrevious.displayName = "CarouselPrevious";
2191
- var CarouselNext = React18.forwardRef(({ className, variant = "outline", size = "icon", ...props }, ref) => {
2417
+ var CarouselNext = React18.forwardRef(({ className, mode = "stroke", tone = "secondary", size = "icon", ...props }, ref) => {
2192
2418
  const { orientation, scrollNext, canScrollNext } = useCarousel();
2193
2419
  return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
2194
2420
  Button,
2195
2421
  {
2196
2422
  ref,
2197
- variant,
2423
+ mode,
2424
+ tone,
2198
2425
  size,
2199
2426
  className: cn(
2200
2427
  "absolute h-8 w-8 rounded-full",
@@ -3559,7 +3786,8 @@ var PaginationLink = ({
3559
3786
  "aria-current": isActive ? "page" : void 0,
3560
3787
  className: cn(
3561
3788
  buttonVariants({
3562
- variant: isActive ? "outline" : "ghost",
3789
+ mode: isActive ? "stroke" : "bleed",
3790
+ tone: "secondary",
3563
3791
  size
3564
3792
  }),
3565
3793
  className
@@ -3575,7 +3803,7 @@ var PaginationPrevious = ({
3575
3803
  PaginationLink,
3576
3804
  {
3577
3805
  "aria-label": "Go to previous page",
3578
- size: "default",
3806
+ size: "md",
3579
3807
  className: cn("gap-1 pl-2.5", className),
3580
3808
  ...props,
3581
3809
  children: [
@@ -3592,7 +3820,7 @@ var PaginationNext = ({
3592
3820
  PaginationLink,
3593
3821
  {
3594
3822
  "aria-label": "Go to next page",
3595
- size: "default",
3823
+ size: "md",
3596
3824
  className: cn("gap-1 pr-2.5", className),
3597
3825
  ...props,
3598
3826
  children: [
@@ -4235,7 +4463,7 @@ var SidebarTrigger = React42.forwardRef(({ className, onClick, ...props }, ref)
4235
4463
  {
4236
4464
  ref,
4237
4465
  "data-sidebar": "trigger",
4238
- variant: "ghost",
4466
+ mode: "bleed",
4239
4467
  size: "icon",
4240
4468
  className: cn("h-7 w-7", className),
4241
4469
  onClick: (event) => {