@blenx-dev/core 0.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.
Files changed (172) hide show
  1. package/CHANGELOG.md +77 -0
  2. package/LICENSE +21 -0
  3. package/package.json +49 -0
  4. package/src/DataTable/data-table-column-toggle.tsx +73 -0
  5. package/src/DataTable/data-table-empty.tsx +27 -0
  6. package/src/DataTable/data-table-error.tsx +25 -0
  7. package/src/DataTable/data-table-infinite-loader.tsx +73 -0
  8. package/src/DataTable/data-table-loading.tsx +67 -0
  9. package/src/DataTable/data-table-pagination.tsx +80 -0
  10. package/src/DataTable/data-table-toolbar.tsx +62 -0
  11. package/src/DataTable/data-table.css.ts +420 -0
  12. package/src/DataTable/data-table.tsx +507 -0
  13. package/src/DataTable/index.ts +24 -0
  14. package/src/DataTable/types.ts +169 -0
  15. package/src/DataTable/use-infinite-scroll.ts +67 -0
  16. package/src/components/Accordion/accordion.css.ts +84 -0
  17. package/src/components/Accordion/accordion.tsx +87 -0
  18. package/src/components/Accordion/index.ts +8 -0
  19. package/src/components/Alert/alert.css.ts +29 -0
  20. package/src/components/Alert/alert.tsx +40 -0
  21. package/src/components/Alert/index.ts +1 -0
  22. package/src/components/AlertDialog/alert-dialog.css.ts +62 -0
  23. package/src/components/AlertDialog/alert-dialog.tsx +199 -0
  24. package/src/components/AlertDialog/index.ts +1 -0
  25. package/src/components/AspectRatio/aspect-ratio.css.ts +7 -0
  26. package/src/components/AspectRatio/aspect-ratio.tsx +20 -0
  27. package/src/components/AspectRatio/index.ts +1 -0
  28. package/src/components/Autocomplete/autocomplete.css.ts +167 -0
  29. package/src/components/Autocomplete/autocomplete.tsx +226 -0
  30. package/src/components/Autocomplete/index.ts +1 -0
  31. package/src/components/Avatar/avatar.css.ts +65 -0
  32. package/src/components/Avatar/avatar.tsx +44 -0
  33. package/src/components/Avatar/index.ts +1 -0
  34. package/src/components/Badge/badge.css.ts +180 -0
  35. package/src/components/Badge/badge.tsx +47 -0
  36. package/src/components/Badge/index.ts +1 -0
  37. package/src/components/Box/box.css.ts +5 -0
  38. package/src/components/Box/box.tsx +21 -0
  39. package/src/components/Box/index.ts +1 -0
  40. package/src/components/Breadcrumbs/breadcrumbs.css.ts +72 -0
  41. package/src/components/Breadcrumbs/breadcrumbs.tsx +79 -0
  42. package/src/components/Breadcrumbs/index.ts +9 -0
  43. package/src/components/Button/button.css.ts +200 -0
  44. package/src/components/Button/button.tsx +55 -0
  45. package/src/components/Button/index.ts +1 -0
  46. package/src/components/Calendar/calendar.css.ts +187 -0
  47. package/src/components/Calendar/calendar.tsx +143 -0
  48. package/src/components/Calendar/index.ts +1 -0
  49. package/src/components/Card/card.tsx +32 -0
  50. package/src/components/Card/index.ts +1 -0
  51. package/src/components/Checkbox/checkbox.css.ts +76 -0
  52. package/src/components/Checkbox/checkbox.tsx +94 -0
  53. package/src/components/Checkbox/index.ts +1 -0
  54. package/src/components/CloseButton/close-button.css.ts +11 -0
  55. package/src/components/CloseButton/close-button.tsx +15 -0
  56. package/src/components/CloseButton/index.ts +2 -0
  57. package/src/components/ColorPicker/color-picker.tsx +123 -0
  58. package/src/components/ColorPicker/index.ts +1 -0
  59. package/src/components/ColorSwatch/color-swatch.tsx +21 -0
  60. package/src/components/ColorSwatch/index.ts +1 -0
  61. package/src/components/Combobox/combobox.css.ts +333 -0
  62. package/src/components/Combobox/combobox.tsx +350 -0
  63. package/src/components/Combobox/index.ts +1 -0
  64. package/src/components/Command/command.css.ts +130 -0
  65. package/src/components/Command/command.tsx +413 -0
  66. package/src/components/Command/index.ts +7 -0
  67. package/src/components/Container/container.css.ts +41 -0
  68. package/src/components/Container/container.tsx +25 -0
  69. package/src/components/Container/index.ts +1 -0
  70. package/src/components/CopyButton/copy-button.css.ts +11 -0
  71. package/src/components/CopyButton/copy-button.tsx +45 -0
  72. package/src/components/CopyButton/index.ts +2 -0
  73. package/src/components/DatePicker/date-picker.tsx +75 -0
  74. package/src/components/DatePicker/index.ts +1 -0
  75. package/src/components/Dialog/dialog.css.ts +57 -0
  76. package/src/components/Dialog/dialog.tsx +181 -0
  77. package/src/components/Dialog/index.ts +1 -0
  78. package/src/components/Drawer/drawer.css.ts +404 -0
  79. package/src/components/Drawer/drawer.tsx +573 -0
  80. package/src/components/Drawer/index.ts +1 -0
  81. package/src/components/Field/field.css.ts +35 -0
  82. package/src/components/Field/field.tsx +101 -0
  83. package/src/components/Field/index.ts +1 -0
  84. package/src/components/Grid/grid.css.ts +12 -0
  85. package/src/components/Grid/grid.tsx +32 -0
  86. package/src/components/Grid/index.ts +1 -0
  87. package/src/components/Icon/icon.css.ts +10 -0
  88. package/src/components/Icon/icon.tsx +15 -0
  89. package/src/components/Icon/index.ts +1 -0
  90. package/src/components/IconButton/icon-button.css.ts +6 -0
  91. package/src/components/IconButton/icon-button.tsx +11 -0
  92. package/src/components/IconButton/index.ts +2 -0
  93. package/src/components/Input/index.ts +1 -0
  94. package/src/components/Input/input.css.ts +72 -0
  95. package/src/components/Input/input.tsx +50 -0
  96. package/src/components/InputGroup/index.ts +1 -0
  97. package/src/components/InputGroup/input-group.css.ts +156 -0
  98. package/src/components/InputGroup/input-group.tsx +133 -0
  99. package/src/components/Menu/index.ts +1 -0
  100. package/src/components/Menu/menu.css.ts +121 -0
  101. package/src/components/Menu/menu.tsx +115 -0
  102. package/src/components/OTPField/index.ts +1 -0
  103. package/src/components/OTPField/otp-field.css.ts +54 -0
  104. package/src/components/OTPField/otp-field.tsx +46 -0
  105. package/src/components/Popover/index.ts +1 -0
  106. package/src/components/Popover/popover.css.ts +81 -0
  107. package/src/components/Popover/popover.tsx +113 -0
  108. package/src/components/Progress/index.ts +7 -0
  109. package/src/components/Progress/progress.css.ts +37 -0
  110. package/src/components/Progress/progress.tsx +62 -0
  111. package/src/components/Radio/index.ts +1 -0
  112. package/src/components/Radio/radio.css.ts +72 -0
  113. package/src/components/Radio/radio.tsx +49 -0
  114. package/src/components/ScrollArea/index.ts +1 -0
  115. package/src/components/ScrollArea/scroll-area.css.ts +79 -0
  116. package/src/components/ScrollArea/scroll-area.tsx +96 -0
  117. package/src/components/SegmentedControl/index.ts +1 -0
  118. package/src/components/SegmentedControl/segmented-control.tsx +42 -0
  119. package/src/components/Select/index.ts +1 -0
  120. package/src/components/Select/select.css.ts +182 -0
  121. package/src/components/Select/select.tsx +165 -0
  122. package/src/components/Separator/index.ts +1 -0
  123. package/src/components/Separator/separator.css.ts +59 -0
  124. package/src/components/Separator/separator.tsx +34 -0
  125. package/src/components/Sheet/index.ts +1 -0
  126. package/src/components/Sheet/sheet.css.ts +184 -0
  127. package/src/components/Sheet/sheet.tsx +215 -0
  128. package/src/components/Slider/index.ts +1 -0
  129. package/src/components/Slider/slider.css.ts +81 -0
  130. package/src/components/Slider/slider.tsx +100 -0
  131. package/src/components/Spinner/index.ts +1 -0
  132. package/src/components/Spinner/spinner.css.ts +17 -0
  133. package/src/components/Spinner/spinner.tsx +15 -0
  134. package/src/components/Splitter/index.ts +1 -0
  135. package/src/components/Splitter/splitter.css.ts +69 -0
  136. package/src/components/Splitter/splitter.tsx +521 -0
  137. package/src/components/Stack/index.ts +1 -0
  138. package/src/components/Stack/stack.css.ts +42 -0
  139. package/src/components/Stack/stack.tsx +32 -0
  140. package/src/components/Surface/index.ts +1 -0
  141. package/src/components/Surface/surface.css.ts +40 -0
  142. package/src/components/Surface/surface.tsx +19 -0
  143. package/src/components/Switch/index.ts +1 -0
  144. package/src/components/Switch/switch.css.ts +46 -0
  145. package/src/components/Switch/switch.tsx +25 -0
  146. package/src/components/Table/index.ts +2 -0
  147. package/src/components/Table/table.css.ts +71 -0
  148. package/src/components/Table/table.tsx +117 -0
  149. package/src/components/Tabs/index.ts +1 -0
  150. package/src/components/Tabs/tabs.css.ts +250 -0
  151. package/src/components/Tabs/tabs.tsx +119 -0
  152. package/src/components/Text/index.ts +2 -0
  153. package/src/components/Text/text.css.ts +118 -0
  154. package/src/components/Text/text.tsx +66 -0
  155. package/src/components/Textarea/index.ts +1 -0
  156. package/src/components/Textarea/textarea.css.ts +66 -0
  157. package/src/components/Textarea/textarea.tsx +48 -0
  158. package/src/components/Toggle/index.ts +1 -0
  159. package/src/components/Toggle/toggle.css.ts +91 -0
  160. package/src/components/Toggle/toggle.tsx +44 -0
  161. package/src/components/ToggleGroup/index.ts +1 -0
  162. package/src/components/ToggleGroup/toggle-group.css.ts +77 -0
  163. package/src/components/ToggleGroup/toggle-group.tsx +131 -0
  164. package/src/components/index.ts +54 -0
  165. package/src/index.ts +3 -0
  166. package/src/utils/drawer-styles.css.ts +85 -0
  167. package/src/utils/heights.ts +16 -0
  168. package/src/utils/sprinkles.css.ts +197 -0
  169. package/src/utils/sprinkles.tokens.ts +74 -0
  170. package/src/utils/types.ts +10 -0
  171. package/src/utils/ve-style.utils.ts +51 -0
  172. package/tsconfig.json +10 -0
@@ -0,0 +1,118 @@
1
+ import { recipe } from "@vanilla-extract/recipes";
2
+ import { semanticVars, tokenVars } from "@blenx-dev/theme/contract";
3
+
4
+ export const textVariants = recipe({
5
+ base: {
6
+ margin: 0,
7
+ textDecoration: "none",
8
+ lineHeight: tokenVars.lineHeight.normal,
9
+ },
10
+ variants: {
11
+ variant: {
12
+ h1: {
13
+ fontSize: tokenVars.fontSize.displayLg,
14
+ fontWeight: tokenVars.fontWeight.bold,
15
+ letterSpacing: tokenVars.letterSpacing.tight,
16
+ margin: 0,
17
+ scrollMarginTop: "80px",
18
+ },
19
+ h2: {
20
+ fontSize: tokenVars.fontSize.xxxl,
21
+ fontWeight: tokenVars.fontWeight.bold,
22
+ letterSpacing: tokenVars.letterSpacing.tight,
23
+ margin: 0,
24
+ scrollMarginTop: "80px",
25
+ },
26
+ h3: {
27
+ fontSize: tokenVars.fontSize.xl,
28
+ fontWeight: tokenVars.fontWeight.semibold,
29
+ letterSpacing: tokenVars.letterSpacing.snug,
30
+ margin: 0,
31
+ scrollMarginTop: "80px",
32
+ },
33
+ h4: {
34
+ fontSize: tokenVars.fontSize.lg,
35
+ fontWeight: tokenVars.fontWeight.semibold,
36
+ margin: 0,
37
+ scrollMarginTop: "80px",
38
+ },
39
+ h5: {
40
+ fontSize: tokenVars.fontSize.md,
41
+ fontWeight: tokenVars.fontWeight.semibold,
42
+ margin: 0,
43
+ scrollMarginTop: "80px",
44
+ },
45
+ h6: {
46
+ fontSize: tokenVars.fontSize.sm,
47
+ fontWeight: tokenVars.fontWeight.semibold,
48
+ margin: 0,
49
+ scrollMarginTop: "80px",
50
+ },
51
+ body1: {
52
+ fontWeight: tokenVars.fontWeight.regular,
53
+ margin: 0,
54
+ },
55
+ body2: {
56
+ fontSize: tokenVars.fontSize.sm,
57
+ fontWeight: tokenVars.fontWeight.regular,
58
+ margin: 0,
59
+ },
60
+ body3: {
61
+ fontSize: tokenVars.fontSize.xs,
62
+ fontWeight: tokenVars.fontWeight.regular,
63
+ margin: 0,
64
+ },
65
+ body4: {
66
+ fontSize: tokenVars.fontSize.xxs,
67
+ fontWeight: tokenVars.fontWeight.medium,
68
+ letterSpacing: tokenVars.letterSpacing.wide,
69
+ margin: 0,
70
+ },
71
+ caption: {
72
+ fontSize: tokenVars.fontSize.xs,
73
+ fontWeight: tokenVars.fontWeight.medium,
74
+ letterSpacing: tokenVars.letterSpacing.wide,
75
+ margin: 0,
76
+ },
77
+ creatorNote: {
78
+ fontSize: tokenVars.fontSize.lg,
79
+ lineHeight: "28px",
80
+ fontWeight: tokenVars.fontWeight.regular,
81
+ fontStyle: "italic",
82
+ margin: 0,
83
+ },
84
+ p: {
85
+ fontSize: tokenVars.fontSize.md,
86
+ fontWeight: tokenVars.fontWeight.regular,
87
+ margin: 0,
88
+ },
89
+ div: {
90
+ fontSize: tokenVars.fontSize.md,
91
+ fontWeight: tokenVars.fontWeight.regular,
92
+ margin: 0,
93
+ },
94
+ code: {
95
+ margin: 0,
96
+ backgroundColor: semanticVars.background.subtle,
97
+ borderRadius: tokenVars.borderRadius.sm,
98
+ },
99
+ },
100
+ textAlign: {
101
+ left: { textAlign: "left" },
102
+ center: { textAlign: "center" },
103
+ right: { textAlign: "right" },
104
+ },
105
+ weight: {
106
+ regular: { fontWeight: tokenVars.fontWeight.regular },
107
+ medium: { fontWeight: tokenVars.fontWeight.medium },
108
+ semibold: { fontWeight: tokenVars.fontWeight.semibold },
109
+ bold: { fontWeight: tokenVars.fontWeight.bold },
110
+ },
111
+ transform: {
112
+ uppercase: { textTransform: "uppercase" },
113
+ capitalize: { textTransform: "capitalize" },
114
+ none: { textTransform: "none" },
115
+ lowercase: { textTransform: "lowercase" },
116
+ },
117
+ },
118
+ });
@@ -0,0 +1,66 @@
1
+ import { useRender } from "@base-ui/react/use-render";
2
+ import clsx from "clsx";
3
+ import type React from "react";
4
+ import { textVariants } from "./text.css";
5
+ import type { RecipeVariants } from "@vanilla-extract/recipes";
6
+ import type { BaseSprinkles } from "../../utils/sprinkles.css";
7
+ import { applyBaseSprinkles } from "../../utils/ve-style.utils";
8
+ const variantTag = {
9
+ h1: "h1",
10
+ h2: "h2",
11
+ h3: "h3",
12
+ h4: "h4",
13
+ h5: "h5",
14
+ h6: "h6",
15
+
16
+ body1: "p",
17
+ body2: "p",
18
+ body3: "p",
19
+ body4: "p",
20
+ p: "p",
21
+
22
+ caption: "span",
23
+ creatorNote: "aside",
24
+ code: "code",
25
+ div: "div",
26
+ } as const satisfies Record<string, keyof React.JSX.IntrinsicElements>;
27
+
28
+ export type TextProps = useRender.ComponentProps<"div"> &
29
+ BaseSprinkles &
30
+ RecipeVariants<typeof textVariants> & { span?: boolean } & {
31
+ size?: BaseSprinkles["fontSize"];
32
+ };
33
+
34
+ export function Text({
35
+ variant = "body1",
36
+ textAlign,
37
+ weight,
38
+ className,
39
+ color = "primary",
40
+ style,
41
+ size,
42
+ render,
43
+ span,
44
+ transform = "none",
45
+ ...props
46
+ }: TextProps): React.ReactElement {
47
+ const [baseStyles, htmlProps] = applyBaseSprinkles({ ...props, color, fontSize: size });
48
+ const rootCls = clsx(
49
+ baseStyles,
50
+ textVariants({ variant, textAlign, weight, transform }),
51
+ className,
52
+ );
53
+ const mergedProps = { className: rootCls, style, ...htmlProps };
54
+ if (span) {
55
+ return useRender({
56
+ defaultTagName: "span",
57
+ props: mergedProps,
58
+ render,
59
+ });
60
+ }
61
+ return useRender({
62
+ defaultTagName: variantTag[variant],
63
+ props: mergedProps,
64
+ render,
65
+ });
66
+ }
@@ -0,0 +1 @@
1
+ export * from "./textarea";
@@ -0,0 +1,66 @@
1
+ import { style } from "@vanilla-extract/css";
2
+ import { semanticVars, tokenVars } from "@blenx-dev/theme/contract";
3
+
4
+ export const shell = style({
5
+ display: "inline-flex",
6
+ width: "100%",
7
+ position: "relative",
8
+ borderStyle: "solid",
9
+ borderWidth: 1,
10
+ borderColor: semanticVars.border.default,
11
+ borderRadius: tokenVars.borderRadius.default,
12
+ backgroundColor: semanticVars.surface.default,
13
+ color: semanticVars.text.primary,
14
+ boxShadow: "0 1px 2px rgba(0,0,0,0.04)",
15
+ boxSizing: "border-box",
16
+ outline: "none",
17
+ transitionProperty: "box-shadow, border-color",
18
+ transitionDuration: "150ms",
19
+ selectors: {
20
+ "&:has(:focus-visible)": {
21
+ borderColor: semanticVars.border.strong,
22
+ boxShadow: `0 0 0 3px ${semanticVars.border.strong}`,
23
+ },
24
+ "&:has([aria-invalid])": {
25
+ borderColor: semanticVars.status.danger.default,
26
+ },
27
+ "&:has([aria-invalid]:focus-visible)": {
28
+ boxShadow: `0 0 0 3px ${semanticVars.status.danger.default}`,
29
+ },
30
+ "&:has(:disabled)": {
31
+ opacity: 0.64,
32
+ },
33
+ },
34
+ });
35
+
36
+ export const textarea = style({
37
+ fieldSizing: "content",
38
+ minHeight: "70px",
39
+ width: "100%",
40
+ borderRadius: "inherit",
41
+ borderWidth: 0,
42
+ paddingTop: "calc(12px - 1px)",
43
+ paddingBottom: "calc(12px - 1px)",
44
+ paddingLeft: "calc(12px - 1px)",
45
+ paddingRight: "calc(12px - 1px)",
46
+ fontSize: "16px",
47
+ lineHeight: 1.5,
48
+ outline: "none",
49
+ resize: "none",
50
+ color: semanticVars.text.primary,
51
+ backgroundColor: "transparent",
52
+ });
53
+
54
+ export const textareaSm = style({
55
+ minHeight: "66px",
56
+ paddingTop: "calc(8px - 1px)",
57
+ paddingBottom: "calc(8px - 1px)",
58
+ paddingLeft: "calc(10px - 1px)",
59
+ paddingRight: "calc(10px - 1px)",
60
+ });
61
+
62
+ export const textareaLg = style({
63
+ minHeight: "74px",
64
+ paddingTop: "calc(16px - 1px)",
65
+ paddingBottom: "calc(16px - 1px)",
66
+ });
@@ -0,0 +1,48 @@
1
+ "use client";
2
+
3
+ import { Field as FieldPrimitive } from "@base-ui/react/field";
4
+ import clsx from "clsx";
5
+ import type * as React from "react";
6
+ import { shell, textarea, textareaLg, textareaSm } from "./textarea.css";
7
+
8
+ export type TextareaProps = React.ComponentPropsWithoutRef<"textarea"> &
9
+ React.RefAttributes<HTMLTextAreaElement> & {
10
+ size?: "sm" | "default" | "lg" | number;
11
+ className?: string;
12
+ style?: React.CSSProperties;
13
+ };
14
+
15
+ export function Textarea({
16
+ size = "default",
17
+ className,
18
+ style,
19
+ ref,
20
+ ...props
21
+ }: TextareaProps): React.ReactElement {
22
+ return (
23
+ <span className={shell} data-size={size} data-slot="textarea-control" style={style}>
24
+ <FieldPrimitive.Control
25
+ ref={ref}
26
+ value={props.value}
27
+ defaultValue={props.defaultValue}
28
+ disabled={props.disabled}
29
+ id={props.id}
30
+ name={props.name}
31
+ render={(defaultProps: React.ComponentProps<"textarea">) => (
32
+ <textarea
33
+ ref={ref}
34
+ className={clsx(
35
+ textarea,
36
+ size === "sm" && textareaSm,
37
+ size === "lg" && textareaLg,
38
+ className,
39
+ )}
40
+ data-slot="textarea"
41
+ {...defaultProps}
42
+ {...props}
43
+ />
44
+ )}
45
+ />
46
+ </span>
47
+ );
48
+ }
@@ -0,0 +1 @@
1
+ export * from "./toggle";
@@ -0,0 +1,91 @@
1
+ import { style } from "@vanilla-extract/css";
2
+ import { recipe } from "@vanilla-extract/recipes";
3
+ import { semanticVars, tokenVars } from "@blenx-dev/theme/contract";
4
+
5
+ export const base = style({
6
+ position: "relative",
7
+ display: "inline-flex",
8
+ flexShrink: 0,
9
+ alignItems: "center",
10
+ justifyContent: "center",
11
+ gap: tokenVars.spacing.sm,
12
+ whiteSpace: "nowrap",
13
+ borderStyle: "solid",
14
+ borderWidth: 1,
15
+ borderRadius: tokenVars.borderRadius.default,
16
+ fontWeight: tokenVars.fontWeight.medium,
17
+ fontSize: tokenVars.fontSize.sm,
18
+ lineHeight: 1.4,
19
+ cursor: "pointer",
20
+ userSelect: "none",
21
+ outline: "none",
22
+ backgroundColor: "transparent",
23
+ transition: "box-shadow 0.15s ease",
24
+ selectors: {
25
+ "&:focus-visible": {
26
+ boxShadow: `0 0 0 2px ${semanticVars.focus.ring}`,
27
+ },
28
+ "&:disabled": {
29
+ pointerEvents: "none",
30
+ opacity: 0.64,
31
+ },
32
+ },
33
+ });
34
+
35
+ export const toggleRecipes = recipe({
36
+ variants: {
37
+ size: {
38
+ sm: {
39
+ height: tokenVars.spacing.lg,
40
+ minWidth: tokenVars.spacing.lg,
41
+ paddingLeft: tokenVars.spacing.sm,
42
+ paddingRight: tokenVars.spacing.sm,
43
+ },
44
+ default: {
45
+ height: tokenVars.spacing.lg,
46
+ minWidth: 36,
47
+ paddingLeft: tokenVars.spacing.sm,
48
+ paddingRight: tokenVars.spacing.sm,
49
+ },
50
+ lg: {
51
+ height: tokenVars.spacing.xl,
52
+ paddingLeft: tokenVars.spacing.md,
53
+ paddingRight: tokenVars.spacing.md,
54
+ },
55
+ },
56
+ radius: {
57
+ default: { borderRadius: tokenVars.borderRadius.default },
58
+ none: { borderRadius: 0 },
59
+ xs: { borderRadius: tokenVars.borderRadius.xs },
60
+ sm: { borderRadius: tokenVars.borderRadius.sm },
61
+ md: { borderRadius: tokenVars.borderRadius.md },
62
+ lg: { borderRadius: tokenVars.borderRadius.lg },
63
+ xl: { borderRadius: tokenVars.borderRadius.xl },
64
+ xxl: { borderRadius: tokenVars.borderRadius.xxl },
65
+ full: { borderRadius: tokenVars.borderRadius.full },
66
+ },
67
+ variant: {
68
+ default: {
69
+ borderColor: "transparent",
70
+ color: semanticVars.text.primary,
71
+ backgroundColor: semanticVars.surface.default,
72
+ },
73
+ outline: {
74
+ borderColor: semanticVars.border.default,
75
+ color: semanticVars.text.primary,
76
+ backgroundColor: semanticVars.background.subtle,
77
+ },
78
+ },
79
+ },
80
+ });
81
+
82
+ export const pressed = {
83
+ default: style({
84
+ backgroundColor: semanticVars.surface.raised,
85
+ }),
86
+ outline: style({
87
+ outlineWidth: tokenVars.borderWidth.thin,
88
+ backgroundColor: semanticVars.surface.overlay,
89
+ borderColor: semanticVars.border.strong,
90
+ }),
91
+ };
@@ -0,0 +1,44 @@
1
+ "use client";
2
+
3
+ import { Toggle as TogglePrimitive } from "@base-ui/react/toggle";
4
+ import clsx from "clsx";
5
+ import { base, pressed, toggleRecipes } from "./toggle.css";
6
+ import type { RecipeVariants } from "@vanilla-extract/recipes";
7
+ export type ToggleSize = "default" | "sm" | "lg";
8
+ export type ToggleVariants = RecipeVariants<typeof toggleRecipes>;
9
+
10
+ export type ToggleProps = TogglePrimitive.Props &
11
+ ToggleVariants & {
12
+ size?: ToggleSize;
13
+ };
14
+
15
+ export function Toggle({
16
+ children,
17
+ className,
18
+ variant = "default",
19
+ radius = "default",
20
+ size = "default",
21
+ ...props
22
+ }: ToggleProps) {
23
+ return (
24
+ <TogglePrimitive
25
+ data-slot="toggle"
26
+ {...props}
27
+ render={(renderProps, state) => {
28
+ return (
29
+ <button
30
+ {...renderProps}
31
+ className={clsx(
32
+ base,
33
+ toggleRecipes({ size, variant, radius }),
34
+ state.pressed && pressed[variant],
35
+ className,
36
+ )}
37
+ >
38
+ {children}
39
+ </button>
40
+ );
41
+ }}
42
+ />
43
+ );
44
+ }
@@ -0,0 +1 @@
1
+ export * from "./toggle-group";
@@ -0,0 +1,77 @@
1
+ import { style } from "@vanilla-extract/css";
2
+ import { tokenVars } from "@blenx-dev/theme/contract";
3
+
4
+ export const groupBase = style({
5
+ display: "inline-flex",
6
+ position: "relative",
7
+ });
8
+
9
+ export const groupHorizontal = style({
10
+ flexDirection: "row",
11
+ alignItems: "center",
12
+ });
13
+
14
+ export const groupVertical = style({
15
+ flexDirection: "column",
16
+ alignItems: "center",
17
+ });
18
+
19
+ export const groupDefault = style({
20
+ gap: tokenVars.spacing.xxs,
21
+ });
22
+
23
+ export const groupOutline = style({
24
+ gap: 0,
25
+ });
26
+
27
+ export const outlineItemHorizontal = style({
28
+ selectors: {
29
+ "&:first-child": {
30
+ borderStartStartRadius: tokenVars.borderRadius.md,
31
+ borderEndStartRadius: tokenVars.borderRadius.md,
32
+ },
33
+ "&:last-child": {
34
+ borderStartEndRadius: tokenVars.borderRadius.md,
35
+ borderEndEndRadius: tokenVars.borderRadius.md,
36
+ },
37
+ "&:not(:first-child)": {
38
+ borderInlineStartWidth: 0,
39
+ borderStartStartRadius: 0,
40
+ borderEndStartRadius: 0,
41
+ },
42
+ "&:not(:last-child)": {
43
+ borderInlineEndWidth: 0,
44
+ borderStartEndRadius: 0,
45
+ borderEndEndRadius: 0,
46
+ },
47
+ "&:focus-visible": {
48
+ zIndex: 10,
49
+ },
50
+ },
51
+ });
52
+
53
+ export const outlineItemVertical = style({
54
+ selectors: {
55
+ "&:first-child": {
56
+ borderStartStartRadius: tokenVars.borderRadius.md,
57
+ borderStartEndRadius: tokenVars.borderRadius.md,
58
+ },
59
+ "&:last-child": {
60
+ borderEndStartRadius: tokenVars.borderRadius.md,
61
+ borderEndEndRadius: tokenVars.borderRadius.md,
62
+ },
63
+ "&:not(:first-child)": {
64
+ borderBlockStartWidth: 0,
65
+ borderStartStartRadius: 0,
66
+ borderStartEndRadius: 0,
67
+ },
68
+ "&:not(:last-child)": {
69
+ borderBlockEndWidth: 0,
70
+ borderEndStartRadius: 0,
71
+ borderEndEndRadius: 0,
72
+ },
73
+ "&:focus-visible": {
74
+ zIndex: 10,
75
+ },
76
+ },
77
+ });
@@ -0,0 +1,131 @@
1
+ "use client";
2
+
3
+ import { ToggleGroup as ToggleGroupPrimitive } from "@base-ui/react/toggle-group";
4
+ import clsx from "clsx";
5
+ import * as React from "react";
6
+ import type { SeparatorProps } from "../Separator/separator";
7
+ import { Separator } from "../Separator/separator";
8
+ import {
9
+ Toggle as ToggleComponent,
10
+ type ToggleProps as ToggleComponentProps,
11
+ type ToggleProps,
12
+ type ToggleSize,
13
+ } from "../Toggle/toggle";
14
+ import {
15
+ groupBase,
16
+ groupHorizontal,
17
+ groupVertical,
18
+ groupDefault,
19
+ groupOutline,
20
+ outlineItemHorizontal,
21
+ outlineItemVertical,
22
+ } from "./toggle-group.css";
23
+
24
+ type ToggleGroupVariant = ToggleProps["variant"];
25
+ type ToggleGroupSize = ToggleSize;
26
+
27
+ type ToggleGroupContextValue = {
28
+ variant: ToggleGroupVariant;
29
+ size: ToggleGroupSize;
30
+ orientation: "horizontal" | "vertical";
31
+ };
32
+
33
+ export const ToggleGroupContext = React.createContext<ToggleGroupContextValue | null>(null);
34
+
35
+ export type ToggleGroupProps = ToggleGroupPrimitive.Props & {
36
+ variant?: ToggleGroupVariant;
37
+ size?: ToggleGroupSize;
38
+ orientation?: "horizontal" | "vertical";
39
+ className?: string;
40
+ style?: React.CSSProperties;
41
+ };
42
+
43
+ export function ToggleGroup({
44
+ className,
45
+ style,
46
+ variant = "default",
47
+ size = "default",
48
+ orientation = "horizontal",
49
+ children,
50
+ ...props
51
+ }: ToggleGroupProps): React.ReactElement {
52
+ const isHorizontal = orientation === "horizontal";
53
+ const isOutline = variant === "outline";
54
+
55
+ const contextValue = React.useMemo(
56
+ () => ({ variant, size, orientation }),
57
+ [variant, size, orientation],
58
+ );
59
+
60
+ return (
61
+ <ToggleGroupPrimitive
62
+ className={clsx(
63
+ groupBase,
64
+ isHorizontal ? groupHorizontal : groupVertical,
65
+ isOutline ? groupOutline : groupDefault,
66
+ className,
67
+ )}
68
+ style={style}
69
+ data-slot="toggle-group"
70
+ data-variant={variant}
71
+ data-size={size}
72
+ orientation={orientation}
73
+ {...props}
74
+ >
75
+ <ToggleGroupContext.Provider value={contextValue}>{children}</ToggleGroupContext.Provider>
76
+ </ToggleGroupPrimitive>
77
+ );
78
+ }
79
+
80
+ export function ToggleGroupItem({
81
+ className,
82
+ style,
83
+ children,
84
+ variant,
85
+ size,
86
+ ...props
87
+ }: ToggleComponentProps & {
88
+ variant?: ToggleGroupVariant;
89
+ size?: ToggleGroupSize;
90
+ className?: string;
91
+ style?: React.CSSProperties;
92
+ }): React.ReactElement {
93
+ const context = React.useContext(ToggleGroupContext);
94
+
95
+ const resolvedVariant = variant ?? context?.variant ?? "default";
96
+ const resolvedSize = size ?? context?.size ?? "default";
97
+ const orientation = context?.orientation ?? "horizontal";
98
+ const isOutline = resolvedVariant === "outline";
99
+
100
+ return (
101
+ <ToggleComponent
102
+ className={clsx(
103
+ isOutline && (orientation === "horizontal" ? outlineItemHorizontal : outlineItemVertical),
104
+ className,
105
+ )}
106
+ style={style}
107
+ data-size={resolvedSize}
108
+ data-variant={resolvedVariant}
109
+ size={resolvedSize}
110
+ variant={resolvedVariant}
111
+ {...props}
112
+ >
113
+ {children}
114
+ </ToggleComponent>
115
+ );
116
+ }
117
+
118
+ export function ToggleGroupSeparator({
119
+ className,
120
+ orientation,
121
+ ...props
122
+ }: {
123
+ className?: string;
124
+ orientation?: "horizontal" | "vertical";
125
+ } & SeparatorProps): React.ReactElement {
126
+ const context = React.useContext(ToggleGroupContext);
127
+ const resolvedOrientation =
128
+ orientation ?? (context?.orientation === "vertical" ? "horizontal" : "vertical");
129
+
130
+ return <Separator className={clsx(className)} orientation={resolvedOrientation} {...props} />;
131
+ }