@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,12 @@
1
+ import { style } from "@vanilla-extract/css";
2
+
3
+ const spanEntries: Record<number, { gridColumn: string }> = {};
4
+ for (let i = 1; i <= 12; i++) {
5
+ spanEntries[i] = { gridColumn: `span ${i} / span ${i}` };
6
+ }
7
+ export const gridSpanVariants = spanEntries;
8
+
9
+ export const gridItem = style({
10
+ boxSizing: "border-box",
11
+ minWidth: 0,
12
+ });
@@ -0,0 +1,32 @@
1
+ import clsx from "clsx";
2
+ import { Box, type BoxProps } from "../Box/box";
3
+ import { gridSprinkles } from "../../utils/sprinkles.css";
4
+ import { gridSpanVariants, gridItem } from "./grid.css";
5
+ import { applyGridSprinkles } from "../../utils/ve-style.utils";
6
+
7
+ type GridSprinkles = Parameters<typeof gridSprinkles>[0];
8
+
9
+ export type GridProps = Omit<BoxProps, "columns" | "gap" | "align"> & GridSprinkles;
10
+
11
+ export type GridItemProps = BoxProps & {
12
+ span?: keyof typeof gridSpanVariants;
13
+ };
14
+
15
+ function Grid({ className, style, ...props }: GridProps) {
16
+ const [gridStyles, restProps] = applyGridSprinkles(props);
17
+ return (
18
+ <Box display="grid" className={clsx(gridStyles, className)} style={style} {...restProps} />
19
+ );
20
+ }
21
+
22
+ function GridItem({ span: spanProp, className, style, ...props }: GridItemProps) {
23
+ return (
24
+ <Box
25
+ className={clsx(gridItem, spanProp && gridSpanVariants[spanProp], className)}
26
+ style={style}
27
+ {...props}
28
+ />
29
+ );
30
+ }
31
+
32
+ export { Grid, GridItem };
@@ -0,0 +1 @@
1
+ export * from "./grid";
@@ -0,0 +1,10 @@
1
+ import { style } from "@vanilla-extract/css";
2
+
3
+ export const iconWrapper = style({
4
+ display: "inline-flex",
5
+ alignItems: "center",
6
+ justifyContent: "center",
7
+ width: "fit-content",
8
+ height: "fit-content",
9
+ flexShrink: 0,
10
+ });
@@ -0,0 +1,15 @@
1
+ import clsx from "clsx";
2
+ import { iconWrapper } from "./icon.css";
3
+ import { Box, type BoxProps } from "../Box/box";
4
+
5
+ type IconProps = BoxProps;
6
+
7
+ export function Icon({ children, className, style, ...props }: IconProps) {
8
+ return (
9
+ <Box className={clsx(iconWrapper, className)} style={style} {...props}>
10
+ {children}
11
+ </Box>
12
+ );
13
+ }
14
+
15
+ export type { IconProps };
@@ -0,0 +1 @@
1
+ export * from "./icon";
@@ -0,0 +1,6 @@
1
+ import { style } from "@vanilla-extract/css";
2
+
3
+ export const base = style({
4
+ maxWidth: "100px",
5
+ width: "fit-content",
6
+ });
@@ -0,0 +1,11 @@
1
+ import clsx from "clsx";
2
+ import { Button, type ButtonProps } from "../Button/button";
3
+ import { base } from "./icon-button.css";
4
+
5
+ type IconButtonProps = Omit<ButtonProps, "size">;
6
+
7
+ export function IconButton({ className, ...props }: IconButtonProps) {
8
+ return <Button {...props} size="icon" className={clsx(base, className)} />;
9
+ }
10
+
11
+ export type { IconButtonProps };
@@ -0,0 +1,2 @@
1
+ export { IconButton } from "./icon-button";
2
+ export type { IconButtonProps } from "./icon-button";
@@ -0,0 +1 @@
1
+ export * from "./input";
@@ -0,0 +1,72 @@
1
+ import { style } from "@vanilla-extract/css";
2
+ import { semanticVars, tokenVars } from "@blenx-dev/theme/contract";
3
+
4
+ export const label = style({
5
+ fontSize: 14,
6
+ display: "inline-flex",
7
+ gap: 4,
8
+ lineHeight: 1.4,
9
+ fontWeight: 400,
10
+ color: semanticVars.text.secondary,
11
+ });
12
+
13
+ export const input = style({
14
+ width: "100%",
15
+ boxSizing: "border-box",
16
+ paddingTop: tokenVars.spacing.sm,
17
+ paddingBottom: tokenVars.spacing.sm,
18
+ paddingLeft: tokenVars.spacing.md,
19
+ paddingRight: tokenVars.spacing.md,
20
+ fontSize: 16,
21
+ lineHeight: 1.5,
22
+ color: semanticVars.text.primary,
23
+ backgroundColor: semanticVars.surface.default,
24
+ borderWidth: 1,
25
+ borderStyle: "solid",
26
+ borderColor: semanticVars.border.default,
27
+ borderRadius: tokenVars.borderRadius.default,
28
+ outline: "none",
29
+ selectors: {
30
+ "&::placeholder": {
31
+ color: semanticVars.text.disabled,
32
+ },
33
+ "&:disabled": {
34
+ opacity: 0.5,
35
+ cursor: "not-allowed",
36
+ },
37
+ "&:focus-visible": {
38
+ borderColor: semanticVars.border.strong,
39
+ boxShadow: `0 0 0 2px ${semanticVars.border.strong}`,
40
+ },
41
+ "&:focus-visible[aria-invalid='true']": {
42
+ borderColor: semanticVars.status.danger.default,
43
+ boxShadow: `0 0 0 3px ${semanticVars.status.danger}`,
44
+ },
45
+ },
46
+ });
47
+
48
+ export const inputSm = style({
49
+ paddingTop: tokenVars.spacing.xs,
50
+ paddingBottom: tokenVars.spacing.xs,
51
+ paddingLeft: tokenVars.spacing.sm,
52
+ paddingRight: tokenVars.spacing.sm,
53
+ fontSize: 16,
54
+ });
55
+
56
+ export const inputLg = style({
57
+ paddingTop: tokenVars.spacing.md,
58
+ paddingBottom: tokenVars.spacing.md,
59
+ paddingLeft: tokenVars.spacing.lg,
60
+ paddingRight: tokenVars.spacing.lg,
61
+ fontSize: 16,
62
+ });
63
+
64
+ export const inputError = style({
65
+ borderColor: semanticVars.status.danger.default,
66
+ });
67
+
68
+ export const error = style({
69
+ fontSize: 12,
70
+ lineHeight: 1.4,
71
+ color: semanticVars.status.danger.default,
72
+ });
@@ -0,0 +1,50 @@
1
+ import { Input as InputPrimitive } from "@base-ui/react/input";
2
+ import { useRender } from "@base-ui/react/use-render";
3
+ import clsx from "clsx";
4
+ import type * as React from "react";
5
+ import { useId } from "react";
6
+ import { input, inputSm, inputLg, inputError, label } from "./input.css";
7
+
8
+ type InputSize = "sm" | "default" | "lg";
9
+ type _BaseInputProps = Omit<InputPrimitive.Props & React.RefAttributes<HTMLInputElement>, "size">;
10
+ export type InputProps = _BaseInputProps & {
11
+ size?: InputSize;
12
+ error?: string;
13
+ wrapperStyle?: React.CSSProperties;
14
+ className?: string;
15
+ style?: React.CSSProperties;
16
+ };
17
+
18
+ type LabelProps = useRender.ComponentProps<"label"> & {
19
+ className?: string;
20
+ style?: React.CSSProperties;
21
+ };
22
+
23
+ export function Label({ render, className, style, ...props }: LabelProps): React.ReactElement {
24
+ return useRender({
25
+ defaultTagName: "label",
26
+ props: { className: clsx(label, className), style, "data-slot": "label", ...props },
27
+ render,
28
+ });
29
+ }
30
+
31
+ export function Input({ error, className, style, size = "default", ...props }: InputProps) {
32
+ const generatedId = useId();
33
+ const fieldId = props.id ?? generatedId;
34
+
35
+ return (
36
+ <InputPrimitive
37
+ id={fieldId}
38
+ data-slot="input"
39
+ className={clsx(
40
+ input,
41
+ size === "sm" && inputSm,
42
+ size === "lg" && inputLg,
43
+ error ? inputError : null,
44
+ className,
45
+ )}
46
+ style={style}
47
+ {...props}
48
+ />
49
+ );
50
+ }
@@ -0,0 +1 @@
1
+ export * from "./input-group";
@@ -0,0 +1,156 @@
1
+ import { style } from "@vanilla-extract/css";
2
+ import { semanticVars, tokenVars } from "@blenx-dev/theme/contract";
3
+
4
+ export const group = style({
5
+ position: "relative",
6
+ display: "inline-flex",
7
+ width: "100%",
8
+ minWidth: 0,
9
+ alignItems: "center",
10
+ borderRadius: tokenVars.borderRadius.lg,
11
+ borderWidth: 1,
12
+ borderStyle: "solid",
13
+ borderColor: semanticVars.border.default,
14
+ color: semanticVars.text.primary,
15
+ fontSize: tokenVars.fontSize.sm,
16
+ boxSizing: "border-box",
17
+ minHeight: "40px",
18
+ overflow: "hidden",
19
+ transitionProperty: "border-color, box-shadow",
20
+ transitionDuration: "150ms",
21
+ selectors: {
22
+ "&:focus-within": {
23
+ borderColor: semanticVars.border.strong,
24
+ boxShadow: `0 0 0 2px ${semanticVars.border.strong}`,
25
+ },
26
+ "&:has([aria-invalid='true'])": {
27
+ borderColor: semanticVars.status.danger.default,
28
+ },
29
+ "&:has([aria-invalid='true']:focus-visible)": {
30
+ borderColor: semanticVars.status.danger.default,
31
+ boxShadow: `0 0 0 2px ${semanticVars.status.danger}`,
32
+ },
33
+ "&:has(:disabled)": {
34
+ opacity: 0.64,
35
+ cursor: "not-allowed",
36
+ },
37
+ "&:has([data-align='block-start'], [data-align='block-end'])": {
38
+ flexDirection: "column",
39
+ },
40
+ },
41
+ });
42
+
43
+ export const addon = style({
44
+ display: "flex",
45
+ alignItems: "center",
46
+ justifyContent: "center",
47
+ cursor: "text",
48
+ flexShrink: 0,
49
+ color: semanticVars.text.secondary,
50
+ userSelect: "none",
51
+ fontSize: tokenVars.fontSize.sm,
52
+ selectors: {
53
+ "&:has(:last-child[data-slot='badge'])": {
54
+ marginInlineStart: 0,
55
+ },
56
+ },
57
+ });
58
+
59
+ export const addonInlineStart = style({
60
+ paddingTop: 0,
61
+ paddingBottom: 0,
62
+ paddingLeft: "8px",
63
+ paddingRight: "4px",
64
+ alignSelf: "center",
65
+ });
66
+
67
+ export const addonInlineEnd = style({
68
+ order: 1,
69
+ paddingLeft: "4px",
70
+ paddingRight: "4px",
71
+ alignSelf: "stretch",
72
+ display: "flex",
73
+ alignItems: "center",
74
+ });
75
+
76
+ export const addonBlockStart = style({
77
+ order: -1,
78
+ width: "100%",
79
+ justifyContent: "flex-start",
80
+ paddingTop: "4px",
81
+ paddingLeft: "4px",
82
+ paddingRight: "4px",
83
+ });
84
+
85
+ export const addonBlockEnd = style({
86
+ order: 1,
87
+ width: "100%",
88
+ justifyContent: "flex-start",
89
+ paddingBottom: "4px",
90
+ paddingLeft: "4px",
91
+ paddingRight: "4px",
92
+ });
93
+
94
+ export const text = style({
95
+ display: "flex",
96
+ alignItems: "center",
97
+ gap: tokenVars.spacing.sm,
98
+ whiteSpace: "nowrap",
99
+ lineHeight: 1,
100
+ color: semanticVars.text.secondary,
101
+ });
102
+
103
+ export const menu = style({
104
+ display: "flex",
105
+ flexDirection: "column",
106
+ });
107
+
108
+ export const input = style({
109
+ flex: 1,
110
+ minWidth: 0,
111
+ width: "100%",
112
+ height: "100%",
113
+ border: "none",
114
+ outline: "none",
115
+ backgroundColor: "inherit",
116
+ paddingTop: "8px",
117
+ paddingBottom: "6px",
118
+ paddingLeft: "8px",
119
+ paddingRight: "8px",
120
+ borderWidth: 0,
121
+ fontSize: tokenVars.fontSize.sm,
122
+ color: semanticVars.text.primary,
123
+ boxSizing: "border-box",
124
+ lineHeight: 1.5,
125
+ selectors: {
126
+ "&::placeholder": {
127
+ color: semanticVars.text.disabled,
128
+ },
129
+ "&:disabled": {
130
+ opacity: 0.5,
131
+ cursor: "not-allowed",
132
+ },
133
+ },
134
+ });
135
+
136
+ export const textarea = style({
137
+ flex: 1,
138
+ minWidth: 0,
139
+ width: "100%",
140
+ border: "none",
141
+ outline: "none",
142
+ backgroundColor: "transparent",
143
+ paddingTop: "8px",
144
+ paddingBottom: "8px",
145
+ borderWidth: 0,
146
+ paddingLeft: "10px",
147
+ paddingRight: "10px",
148
+ fontSize: tokenVars.fontSize.sm,
149
+ color: semanticVars.text.primary,
150
+ resize: "none",
151
+ selectors: {
152
+ "&::placeholder": {
153
+ color: semanticVars.text.disabled,
154
+ },
155
+ },
156
+ });
@@ -0,0 +1,133 @@
1
+ "use client";
2
+
3
+ import { useRender } from "@base-ui/react";
4
+ import { Checkbox as CheckboxPrimitive } from "@base-ui/react/checkbox";
5
+ import { Input as InputPrimitive } from "@base-ui/react/input";
6
+ import { Radio as RadioPrimitive } from "@base-ui/react/radio";
7
+ import { RadioGroup as RadioGroupPrimitive } from "@base-ui/react/radio-group";
8
+ import clsx from "clsx";
9
+ import type * as React from "react";
10
+ import {
11
+ group,
12
+ addon,
13
+ addonInlineStart,
14
+ addonInlineEnd,
15
+ addonBlockStart,
16
+ addonBlockEnd,
17
+ text as textStyle,
18
+ menu,
19
+ input as inputStyle,
20
+ textarea as textareaStyle,
21
+ } from "./input-group.css";
22
+ import type { _BaseDivProps } from "../../utils/types";
23
+
24
+ type Align = "inline-start" | "inline-end" | "block-start" | "block-end";
25
+
26
+ type InputGroupProps = useRender.ComponentProps<"fieldset">;
27
+
28
+ function InputGroup({ className, ...props }: InputGroupProps): React.ReactElement {
29
+ return <fieldset className={clsx(group, className)} data-slot="input-group" {...props} />;
30
+ }
31
+
32
+ type InputGroupAddonProps = _BaseDivProps & {
33
+ align?: Align;
34
+ };
35
+
36
+ function InputGroupAddon({
37
+ align = "inline-start",
38
+ className,
39
+ ...props
40
+ }: InputGroupAddonProps): React.ReactElement {
41
+ return (
42
+ <div
43
+ className={clsx(
44
+ addon,
45
+ align === "inline-start" && addonInlineStart,
46
+ align === "inline-end" && addonInlineEnd,
47
+ align === "block-start" && addonBlockStart,
48
+ align === "block-end" && addonBlockEnd,
49
+ className,
50
+ )}
51
+ data-align={align}
52
+ data-slot="input-group-addon"
53
+ role="presentation"
54
+ onMouseDown={(e: React.MouseEvent<HTMLDivElement>) => {
55
+ const target = e.target as HTMLElement;
56
+ const isInteractive = target.closest(
57
+ "button, a, input, select, textarea, [role='button'], [role='combobox'], [role='listbox'], [data-slot='select-trigger']",
58
+ );
59
+ if (isInteractive) return;
60
+ e.preventDefault();
61
+ const parent = e.currentTarget.parentElement;
62
+ const input = parent?.querySelector<HTMLInputElement | HTMLTextAreaElement>(
63
+ "input, textarea",
64
+ );
65
+ if (input && !parent?.querySelector("input:focus, textarea:focus")) {
66
+ input.focus();
67
+ }
68
+ }}
69
+ {...props}
70
+ />
71
+ );
72
+ }
73
+
74
+ type InputGroupTextProps = React.ComponentProps<"span">;
75
+
76
+ function InputGroupText({ className, ...props }: InputGroupTextProps): React.ReactElement {
77
+ return <span className={clsx(textStyle, className)} {...props} />;
78
+ }
79
+
80
+ type InputGroupInputProps = Omit<
81
+ InputPrimitive.Props & React.RefAttributes<HTMLInputElement>,
82
+ "style"
83
+ >;
84
+
85
+ function InputGroupInput({ className, ...props }: InputGroupInputProps): React.ReactElement {
86
+ return (
87
+ <InputPrimitive className={clsx(inputStyle, className)} data-slot="input-control" {...props} />
88
+ );
89
+ }
90
+
91
+ type InputGroupTextareaProps = Omit<React.ComponentPropsWithoutRef<"textarea">, "style">;
92
+
93
+ function InputGroupTextarea({ ...props }: InputGroupTextareaProps): React.ReactElement {
94
+ return <textarea className={textareaStyle} rows={4} data-slot="textarea-control" {...props} />;
95
+ }
96
+
97
+ function InputGroupMenu({
98
+ className,
99
+ render,
100
+ ...props
101
+ }: useRender.ComponentProps<"nav">): React.ReactElement {
102
+ return useRender({
103
+ defaultTagName: "nav",
104
+ props: {
105
+ className: clsx(menu, className),
106
+ "data-slot": "input-group-menu",
107
+ ...props,
108
+ } as never,
109
+ render,
110
+ });
111
+ }
112
+
113
+ const InputGroupCheckboxItem = CheckboxPrimitive.Root;
114
+ const InputGroupRadioGroup = RadioGroupPrimitive;
115
+ const InputGroupRadioItem = RadioPrimitive.Root;
116
+
117
+ export type {
118
+ InputGroupAddonProps,
119
+ InputGroupInputProps,
120
+ InputGroupProps,
121
+ InputGroupTextareaProps,
122
+ };
123
+ export {
124
+ InputGroup,
125
+ InputGroupAddon,
126
+ InputGroupCheckboxItem,
127
+ InputGroupInput,
128
+ InputGroupMenu,
129
+ InputGroupRadioGroup,
130
+ InputGroupRadioItem,
131
+ InputGroupText,
132
+ InputGroupTextarea,
133
+ };
@@ -0,0 +1 @@
1
+ export * from "./menu";
@@ -0,0 +1,121 @@
1
+ import { style } from "@vanilla-extract/css";
2
+ import { semanticVars, tokenVars } from "@blenx-dev/theme/contract";
3
+
4
+ export const trigger = style({
5
+ display: "inline-flex",
6
+ alignItems: "center",
7
+ justifyContent: "center",
8
+ cursor: "pointer",
9
+ backgroundColor: "transparent",
10
+ appearance: "none",
11
+ border: "none",
12
+ padding: 0,
13
+ outline: "none",
14
+ borderWidth: 0,
15
+ fontFamily: "inherit",
16
+ fontSize: "inherit",
17
+ color: "inherit",
18
+ borderRadius: tokenVars.borderRadius.md,
19
+ transition: "background-color 0.15s ease, box-shadow 0.15s ease",
20
+ selectors: {
21
+ "&:focus-visible": {
22
+ boxShadow: `0 0 0 2px ${semanticVars.border.strong}`,
23
+ },
24
+ },
25
+ });
26
+
27
+ export const popup = style({
28
+ backgroundColor: semanticVars.surface.default,
29
+ borderWidth: 1,
30
+ borderStyle: "solid",
31
+ borderColor: semanticVars.border.subtle,
32
+ borderRadius: tokenVars.borderRadius.lg,
33
+ boxShadow: tokenVars.shadow.xl,
34
+ zIndex: 1000,
35
+ padding: tokenVars.spacing.xs,
36
+ display: "flex",
37
+ gap: tokenVars.spacing["1"],
38
+ flexDirection: "column",
39
+ minWidth: 224,
40
+ overflow: "hidden",
41
+ outline: "none",
42
+ });
43
+
44
+ export const item = style({
45
+ display: "flex",
46
+ alignItems: "center",
47
+ gap: tokenVars.spacing.sm,
48
+ minHeight: 24,
49
+ padding: `${tokenVars.spacing.xs} ${tokenVars.spacing.sm}`,
50
+ borderRadius: tokenVars.borderRadius.default,
51
+ color: semanticVars.text.primary,
52
+ fontSize: tokenVars.fontSize.sm,
53
+ fontWeight: tokenVars.fontWeight.medium,
54
+ lineHeight: 1.2,
55
+ textDecoration: "none",
56
+ textAlign: "left",
57
+ border: "none",
58
+ backgroundColor: "transparent",
59
+ cursor: "pointer",
60
+ appearance: "none",
61
+ outline: "none",
62
+ transition: "background-color 0.15s ease, color 0.15s ease",
63
+ selectors: {
64
+ "&:hover": {
65
+ backgroundColor: semanticVars.background.subtle,
66
+ color: semanticVars.text.primary,
67
+ },
68
+ "&:focus-visible": {
69
+ backgroundColor: semanticVars.background.subtle,
70
+ color: semanticVars.text.primary,
71
+ boxShadow: `0 0 0 2px ${semanticVars.border.strong} inset`,
72
+ },
73
+ "&:active": {
74
+ backgroundColor: semanticVars.border.subtle,
75
+ },
76
+ },
77
+ });
78
+
79
+ export const itemDestructive = style({
80
+ color: semanticVars.status.danger.default,
81
+ selectors: {
82
+ "&:hover": {
83
+ backgroundColor: semanticVars.status.dangerBg,
84
+ color: semanticVars.status.danger.default,
85
+ },
86
+ "&:focus-visible": {
87
+ backgroundColor: semanticVars.status.dangerBg,
88
+ color: semanticVars.status.danger.default,
89
+ boxShadow: `0 0 0 2px ${semanticVars.status.danger} inset`,
90
+ },
91
+ "&:active": {
92
+ backgroundColor: semanticVars.status.dangerBg,
93
+ },
94
+ },
95
+ });
96
+
97
+ export const separator = style({
98
+ height: 1,
99
+ backgroundColor: semanticVars.border.subtle,
100
+ border: "none",
101
+ });
102
+
103
+ export const groupLabel = style({
104
+ padding: `${tokenVars.spacing.sm} ${tokenVars.spacing.md} ${tokenVars.spacing.xs}`,
105
+ fontSize: tokenVars.fontSize.xs,
106
+ fontWeight: tokenVars.fontWeight.semibold,
107
+ color: semanticVars.text.secondary,
108
+ textTransform: "uppercase",
109
+ letterSpacing: tokenVars.letterSpacing.wide,
110
+ });
111
+
112
+ export const inset = style({
113
+ paddingLeft: 40,
114
+ });
115
+
116
+ export const shortcut = style({
117
+ marginLeft: "auto",
118
+ color: semanticVars.text.disabled,
119
+ fontSize: tokenVars.fontSize.xs,
120
+ fontWeight: tokenVars.fontWeight.medium,
121
+ });