@brut-ui/react 0.2.0 → 0.4.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/dist/index.cjs CHANGED
@@ -21,7 +21,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  Button: () => Button,
24
- Input: () => Input
24
+ Checkbox: () => Checkbox,
25
+ Input: () => Input,
26
+ Textarea: () => Textarea
25
27
  });
26
28
  module.exports = __toCommonJS(index_exports);
27
29
 
@@ -63,18 +65,80 @@ var Button = (0, import_react.forwardRef)(
63
65
  }
64
66
  );
65
67
 
66
- // src/components/input/input.tsx
68
+ // src/components/checkbox/checkbox.tsx
67
69
  var import_react2 = require("react");
68
70
 
71
+ // src/components/checkbox/checkbox.constants.ts
72
+ var CHECKBOX_DEFAULTS = {
73
+ size: "medium"
74
+ };
75
+
76
+ // src/components/checkbox/checkbox.tsx
77
+ var import_jsx_runtime2 = require("react/jsx-runtime");
78
+ var Checkbox = (0, import_react2.forwardRef)(
79
+ function Checkbox2({
80
+ children,
81
+ size = CHECKBOX_DEFAULTS.size,
82
+ checked,
83
+ defaultChecked,
84
+ onCheckedChange,
85
+ error,
86
+ disabled,
87
+ ...rest
88
+ }, ref) {
89
+ const handleChange = (e) => {
90
+ onCheckedChange?.(e.target.checked);
91
+ };
92
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
93
+ "label",
94
+ {
95
+ "data-brut-checkbox-label": "",
96
+ "data-size": size,
97
+ "data-disabled": disabled || void 0,
98
+ children: [
99
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
100
+ "input",
101
+ {
102
+ ref,
103
+ type: "checkbox",
104
+ checked,
105
+ defaultChecked,
106
+ onChange: handleChange,
107
+ disabled,
108
+ "aria-invalid": error || void 0,
109
+ ...rest
110
+ }
111
+ ),
112
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
113
+ "span",
114
+ {
115
+ "data-brut-checkbox": "",
116
+ "data-size": size,
117
+ "data-checked": checked || void 0,
118
+ "data-error": error || void 0,
119
+ "data-disabled": disabled || void 0,
120
+ "aria-hidden": "true"
121
+ }
122
+ ),
123
+ children && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children })
124
+ ]
125
+ }
126
+ );
127
+ }
128
+ );
129
+
130
+ // src/components/input/input.tsx
131
+ var import_react3 = require("react");
132
+
69
133
  // src/components/input/input.constants.ts
70
134
  var INPUT_DEFAULTS = {
71
135
  size: "medium"
72
136
  };
73
137
 
74
138
  // src/components/input/input.tsx
75
- var import_jsx_runtime2 = require("react/jsx-runtime");
76
- var Input = (0, import_react2.forwardRef)(function Input2({ size = INPUT_DEFAULTS.size, error, disabled, ...rest }, ref) {
77
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
139
+ var import_jsx_runtime3 = require("react/jsx-runtime");
140
+ var Input = (0, import_react3.forwardRef)(function Input2({ size = INPUT_DEFAULTS.size, error, disabled, ...rest }, ref) {
141
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
78
142
  "input",
79
143
  {
80
144
  ref,
@@ -88,8 +152,46 @@ var Input = (0, import_react2.forwardRef)(function Input2({ size = INPUT_DEFAULT
88
152
  }
89
153
  );
90
154
  });
155
+
156
+ // src/components/textarea/textarea.tsx
157
+ var import_react4 = require("react");
158
+
159
+ // src/components/textarea/textarea.constants.ts
160
+ var TEXTAREA_DEFAULTS = {
161
+ size: "medium",
162
+ rows: 4
163
+ };
164
+
165
+ // src/components/textarea/textarea.tsx
166
+ var import_jsx_runtime4 = require("react/jsx-runtime");
167
+ var Textarea = (0, import_react4.forwardRef)(
168
+ function Textarea2({
169
+ size = TEXTAREA_DEFAULTS.size,
170
+ rows = TEXTAREA_DEFAULTS.rows,
171
+ error,
172
+ disabled,
173
+ ...rest
174
+ }, ref) {
175
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
176
+ "textarea",
177
+ {
178
+ ref,
179
+ "data-brut-textarea": "",
180
+ "data-size": size,
181
+ "data-error": error || void 0,
182
+ "data-disabled": disabled || void 0,
183
+ disabled,
184
+ "aria-invalid": error || void 0,
185
+ rows,
186
+ ...rest
187
+ }
188
+ );
189
+ }
190
+ );
91
191
  // Annotate the CommonJS export names for ESM import in node:
92
192
  0 && (module.exports = {
93
193
  Button,
94
- Input
194
+ Checkbox,
195
+ Input,
196
+ Textarea
95
197
  });
package/dist/index.css CHANGED
@@ -58,6 +58,84 @@
58
58
  cursor: not-allowed;
59
59
  }
60
60
 
61
+ /* src/components/checkbox/checkbox.css */
62
+ [data-brut-checkbox-label] {
63
+ display: inline-flex;
64
+ align-items: center;
65
+ gap: var(--brut-space-sm);
66
+ cursor: pointer;
67
+ font-family: var(--brut-font-mono);
68
+ color: var(--brut-black);
69
+ }
70
+ [data-brut-checkbox-label][data-disabled] {
71
+ opacity: 0.4;
72
+ cursor: not-allowed;
73
+ }
74
+ [data-brut-checkbox-label] > input {
75
+ position: absolute;
76
+ width: 1px;
77
+ height: 1px;
78
+ margin: -1px;
79
+ padding: 0;
80
+ border: 0;
81
+ clip: rect(0, 0, 0, 0);
82
+ overflow: hidden;
83
+ white-space: nowrap;
84
+ }
85
+ [data-brut-checkbox] {
86
+ display: inline-flex;
87
+ align-items: center;
88
+ justify-content: center;
89
+ flex-shrink: 0;
90
+ box-sizing: border-box;
91
+ border: var(--brut-border);
92
+ border-radius: var(--brut-radius);
93
+ background: var(--brut-white);
94
+ }
95
+ [data-brut-checkbox][data-size=small] {
96
+ width: 14px;
97
+ height: 14px;
98
+ }
99
+ [data-brut-checkbox][data-size=medium] {
100
+ width: 18px;
101
+ height: 18px;
102
+ }
103
+ [data-brut-checkbox][data-size=large] {
104
+ width: 22px;
105
+ height: 22px;
106
+ }
107
+ [data-brut-checkbox-label][data-size=small] {
108
+ font-size: 0.75rem;
109
+ }
110
+ [data-brut-checkbox-label][data-size=medium] {
111
+ font-size: 0.875rem;
112
+ }
113
+ [data-brut-checkbox-label][data-size=large] {
114
+ font-size: 1.125rem;
115
+ }
116
+ [data-brut-checkbox]::after {
117
+ content: "";
118
+ display: none;
119
+ width: 30%;
120
+ height: 55%;
121
+ border-right: 2px solid var(--brut-black);
122
+ border-bottom: 2px solid var(--brut-black);
123
+ transform: rotate(45deg) translate(-5%, -5%);
124
+ }
125
+ [data-brut-checkbox][data-checked]::after {
126
+ display: block;
127
+ }
128
+ [data-brut-checkbox-label] > input:checked + [data-brut-checkbox]::after {
129
+ display: block;
130
+ }
131
+ [data-brut-checkbox][data-error] {
132
+ border-color: var(--brut-error);
133
+ }
134
+ [data-brut-checkbox-label] > input:focus-visible + [data-brut-checkbox] {
135
+ outline: var(--brut-focus-outline);
136
+ outline-offset: var(--brut-focus-offset);
137
+ }
138
+
61
139
  /* src/components/input/input.css */
62
140
  [data-brut-input] {
63
141
  display: block;
@@ -98,3 +176,45 @@
98
176
  opacity: 0.4;
99
177
  cursor: not-allowed;
100
178
  }
179
+
180
+ /* src/components/textarea/textarea.css */
181
+ [data-brut-textarea] {
182
+ display: block;
183
+ box-sizing: border-box;
184
+ width: 100%;
185
+ font-family: var(--brut-font-mono);
186
+ font-weight: 400;
187
+ border: var(--brut-border);
188
+ border-radius: var(--brut-radius);
189
+ background: var(--brut-white);
190
+ color: var(--brut-black);
191
+ padding: var(--brut-space-sm) var(--brut-space-md);
192
+ line-height: 1.4;
193
+ resize: vertical;
194
+ }
195
+ [data-brut-textarea]::placeholder {
196
+ color: var(--brut-gray);
197
+ opacity: 1;
198
+ }
199
+ [data-brut-textarea][data-size=small] {
200
+ font-size: 0.75rem;
201
+ padding: var(--brut-space-xs) var(--brut-space-sm);
202
+ }
203
+ [data-brut-textarea][data-size=medium] {
204
+ font-size: 0.875rem;
205
+ }
206
+ [data-brut-textarea][data-size=large] {
207
+ font-size: 1.125rem;
208
+ padding: var(--brut-space-sm) var(--brut-space-lg);
209
+ }
210
+ [data-brut-textarea][data-error] {
211
+ border-color: var(--brut-error);
212
+ }
213
+ [data-brut-textarea]:focus-visible {
214
+ outline: var(--brut-focus-outline);
215
+ outline-offset: var(--brut-focus-offset);
216
+ }
217
+ [data-brut-textarea][data-disabled] {
218
+ opacity: 0.4;
219
+ cursor: not-allowed;
220
+ }
package/dist/index.d.cts CHANGED
@@ -37,6 +37,38 @@ interface ButtonProps<T extends ElementType = "button"> {
37
37
  type PolymorphicButtonProps<T extends ElementType = "button"> = ButtonProps<T> & Omit<ComponentPropsWithRef<T>, keyof ButtonProps<T>>;
38
38
  declare const Button: <T extends ElementType = "button">(props: PolymorphicButtonProps<T>) => ReactNode;
39
39
 
40
+ /** Available size presets for Checkbox. */
41
+ declare const CHECKBOX_SIZES: readonly ["small", "medium", "large"];
42
+ type CheckboxSize = (typeof CHECKBOX_SIZES)[number];
43
+
44
+ /**
45
+ * Checkbox — a brutalist checkbox with built-in label.
46
+ *
47
+ * Renders an accessible checkbox with a thick square indicator
48
+ * and monospace label. Supports `small`, `medium`, and `large` sizes.
49
+ *
50
+ * Error state sets `aria-invalid` and `data-error` for styling hooks.
51
+ *
52
+ * @example
53
+ * ```tsx
54
+ * <Checkbox>Accept terms</Checkbox>
55
+ * <Checkbox size="large" error>Must accept</Checkbox>
56
+ * ```
57
+ */
58
+ interface CheckboxProps extends Omit<ComponentPropsWithRef<"input">, "size" | "type" | "onChange"> {
59
+ /** Label content. */
60
+ children?: ReactNode;
61
+ /** Size preset. @default "medium" */
62
+ size?: CheckboxSize;
63
+ /** Controlled checked state. */
64
+ checked?: boolean;
65
+ /** Callback fired when the checked state changes. */
66
+ onCheckedChange?: (checked: boolean) => void;
67
+ /** Error state — sets `data-error` and `aria-invalid`. */
68
+ error?: boolean;
69
+ }
70
+ declare const Checkbox: (props: CheckboxProps) => ReactNode;
71
+
40
72
  /** Available size presets for Input. */
41
73
  declare const INPUT_SIZES: readonly ["small", "medium", "large"];
42
74
  type InputSize = (typeof INPUT_SIZES)[number];
@@ -63,4 +95,30 @@ interface InputProps extends Omit<ComponentPropsWithRef<"input">, "size"> {
63
95
  }
64
96
  declare const Input: (props: InputProps) => ReactNode;
65
97
 
66
- export { Button, type ButtonProps, type ButtonSize, type ButtonVariant, Input, type InputProps, type InputSize };
98
+ /** Available size presets for Textarea. */
99
+ declare const TEXTAREA_SIZES: readonly ["small", "medium", "large"];
100
+ type TextareaSize = (typeof TEXTAREA_SIZES)[number];
101
+
102
+ /**
103
+ * Textarea — a brutalist multiline text input.
104
+ *
105
+ * Renders an accessible textarea with thick square borders
106
+ * and monospace typography. Supports `small`, `medium`, and `large` sizes.
107
+ *
108
+ * Error state sets `aria-invalid` and `data-error` for styling hooks.
109
+ *
110
+ * @example
111
+ * ```tsx
112
+ * <Textarea placeholder="Write something..." />
113
+ * <Textarea size="large" error rows={6} />
114
+ * ```
115
+ */
116
+ interface TextareaProps extends Omit<ComponentPropsWithRef<"textarea">, "size"> {
117
+ /** Size preset. @default "medium" */
118
+ size?: TextareaSize;
119
+ /** Error state — sets `data-error` and `aria-invalid`. */
120
+ error?: boolean;
121
+ }
122
+ declare const Textarea: (props: TextareaProps) => ReactNode;
123
+
124
+ export { Button, type ButtonProps, type ButtonSize, type ButtonVariant, Checkbox, type CheckboxProps, type CheckboxSize, Input, type InputProps, type InputSize, Textarea, type TextareaProps, type TextareaSize };
package/dist/index.d.ts CHANGED
@@ -37,6 +37,38 @@ interface ButtonProps<T extends ElementType = "button"> {
37
37
  type PolymorphicButtonProps<T extends ElementType = "button"> = ButtonProps<T> & Omit<ComponentPropsWithRef<T>, keyof ButtonProps<T>>;
38
38
  declare const Button: <T extends ElementType = "button">(props: PolymorphicButtonProps<T>) => ReactNode;
39
39
 
40
+ /** Available size presets for Checkbox. */
41
+ declare const CHECKBOX_SIZES: readonly ["small", "medium", "large"];
42
+ type CheckboxSize = (typeof CHECKBOX_SIZES)[number];
43
+
44
+ /**
45
+ * Checkbox — a brutalist checkbox with built-in label.
46
+ *
47
+ * Renders an accessible checkbox with a thick square indicator
48
+ * and monospace label. Supports `small`, `medium`, and `large` sizes.
49
+ *
50
+ * Error state sets `aria-invalid` and `data-error` for styling hooks.
51
+ *
52
+ * @example
53
+ * ```tsx
54
+ * <Checkbox>Accept terms</Checkbox>
55
+ * <Checkbox size="large" error>Must accept</Checkbox>
56
+ * ```
57
+ */
58
+ interface CheckboxProps extends Omit<ComponentPropsWithRef<"input">, "size" | "type" | "onChange"> {
59
+ /** Label content. */
60
+ children?: ReactNode;
61
+ /** Size preset. @default "medium" */
62
+ size?: CheckboxSize;
63
+ /** Controlled checked state. */
64
+ checked?: boolean;
65
+ /** Callback fired when the checked state changes. */
66
+ onCheckedChange?: (checked: boolean) => void;
67
+ /** Error state — sets `data-error` and `aria-invalid`. */
68
+ error?: boolean;
69
+ }
70
+ declare const Checkbox: (props: CheckboxProps) => ReactNode;
71
+
40
72
  /** Available size presets for Input. */
41
73
  declare const INPUT_SIZES: readonly ["small", "medium", "large"];
42
74
  type InputSize = (typeof INPUT_SIZES)[number];
@@ -63,4 +95,30 @@ interface InputProps extends Omit<ComponentPropsWithRef<"input">, "size"> {
63
95
  }
64
96
  declare const Input: (props: InputProps) => ReactNode;
65
97
 
66
- export { Button, type ButtonProps, type ButtonSize, type ButtonVariant, Input, type InputProps, type InputSize };
98
+ /** Available size presets for Textarea. */
99
+ declare const TEXTAREA_SIZES: readonly ["small", "medium", "large"];
100
+ type TextareaSize = (typeof TEXTAREA_SIZES)[number];
101
+
102
+ /**
103
+ * Textarea — a brutalist multiline text input.
104
+ *
105
+ * Renders an accessible textarea with thick square borders
106
+ * and monospace typography. Supports `small`, `medium`, and `large` sizes.
107
+ *
108
+ * Error state sets `aria-invalid` and `data-error` for styling hooks.
109
+ *
110
+ * @example
111
+ * ```tsx
112
+ * <Textarea placeholder="Write something..." />
113
+ * <Textarea size="large" error rows={6} />
114
+ * ```
115
+ */
116
+ interface TextareaProps extends Omit<ComponentPropsWithRef<"textarea">, "size"> {
117
+ /** Size preset. @default "medium" */
118
+ size?: TextareaSize;
119
+ /** Error state — sets `data-error` and `aria-invalid`. */
120
+ error?: boolean;
121
+ }
122
+ declare const Textarea: (props: TextareaProps) => ReactNode;
123
+
124
+ export { Button, type ButtonProps, type ButtonSize, type ButtonVariant, Checkbox, type CheckboxProps, type CheckboxSize, Input, type InputProps, type InputSize, Textarea, type TextareaProps, type TextareaSize };
package/dist/index.js CHANGED
@@ -36,18 +36,80 @@ var Button = forwardRef(
36
36
  }
37
37
  );
38
38
 
39
- // src/components/input/input.tsx
39
+ // src/components/checkbox/checkbox.tsx
40
40
  import { forwardRef as forwardRef2 } from "react";
41
41
 
42
+ // src/components/checkbox/checkbox.constants.ts
43
+ var CHECKBOX_DEFAULTS = {
44
+ size: "medium"
45
+ };
46
+
47
+ // src/components/checkbox/checkbox.tsx
48
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
49
+ var Checkbox = forwardRef2(
50
+ function Checkbox2({
51
+ children,
52
+ size = CHECKBOX_DEFAULTS.size,
53
+ checked,
54
+ defaultChecked,
55
+ onCheckedChange,
56
+ error,
57
+ disabled,
58
+ ...rest
59
+ }, ref) {
60
+ const handleChange = (e) => {
61
+ onCheckedChange?.(e.target.checked);
62
+ };
63
+ return /* @__PURE__ */ jsxs(
64
+ "label",
65
+ {
66
+ "data-brut-checkbox-label": "",
67
+ "data-size": size,
68
+ "data-disabled": disabled || void 0,
69
+ children: [
70
+ /* @__PURE__ */ jsx2(
71
+ "input",
72
+ {
73
+ ref,
74
+ type: "checkbox",
75
+ checked,
76
+ defaultChecked,
77
+ onChange: handleChange,
78
+ disabled,
79
+ "aria-invalid": error || void 0,
80
+ ...rest
81
+ }
82
+ ),
83
+ /* @__PURE__ */ jsx2(
84
+ "span",
85
+ {
86
+ "data-brut-checkbox": "",
87
+ "data-size": size,
88
+ "data-checked": checked || void 0,
89
+ "data-error": error || void 0,
90
+ "data-disabled": disabled || void 0,
91
+ "aria-hidden": "true"
92
+ }
93
+ ),
94
+ children && /* @__PURE__ */ jsx2("span", { children })
95
+ ]
96
+ }
97
+ );
98
+ }
99
+ );
100
+
101
+ // src/components/input/input.tsx
102
+ import { forwardRef as forwardRef3 } from "react";
103
+
42
104
  // src/components/input/input.constants.ts
43
105
  var INPUT_DEFAULTS = {
44
106
  size: "medium"
45
107
  };
46
108
 
47
109
  // src/components/input/input.tsx
48
- import { jsx as jsx2 } from "react/jsx-runtime";
49
- var Input = forwardRef2(function Input2({ size = INPUT_DEFAULTS.size, error, disabled, ...rest }, ref) {
50
- return /* @__PURE__ */ jsx2(
110
+ import { jsx as jsx3 } from "react/jsx-runtime";
111
+ var Input = forwardRef3(function Input2({ size = INPUT_DEFAULTS.size, error, disabled, ...rest }, ref) {
112
+ return /* @__PURE__ */ jsx3(
51
113
  "input",
52
114
  {
53
115
  ref,
@@ -61,7 +123,45 @@ var Input = forwardRef2(function Input2({ size = INPUT_DEFAULTS.size, error, dis
61
123
  }
62
124
  );
63
125
  });
126
+
127
+ // src/components/textarea/textarea.tsx
128
+ import { forwardRef as forwardRef4 } from "react";
129
+
130
+ // src/components/textarea/textarea.constants.ts
131
+ var TEXTAREA_DEFAULTS = {
132
+ size: "medium",
133
+ rows: 4
134
+ };
135
+
136
+ // src/components/textarea/textarea.tsx
137
+ import { jsx as jsx4 } from "react/jsx-runtime";
138
+ var Textarea = forwardRef4(
139
+ function Textarea2({
140
+ size = TEXTAREA_DEFAULTS.size,
141
+ rows = TEXTAREA_DEFAULTS.rows,
142
+ error,
143
+ disabled,
144
+ ...rest
145
+ }, ref) {
146
+ return /* @__PURE__ */ jsx4(
147
+ "textarea",
148
+ {
149
+ ref,
150
+ "data-brut-textarea": "",
151
+ "data-size": size,
152
+ "data-error": error || void 0,
153
+ "data-disabled": disabled || void 0,
154
+ disabled,
155
+ "aria-invalid": error || void 0,
156
+ rows,
157
+ ...rest
158
+ }
159
+ );
160
+ }
161
+ );
64
162
  export {
65
163
  Button,
66
- Input
164
+ Checkbox,
165
+ Input,
166
+ Textarea
67
167
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brut-ui/react",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Ultra-light brutalist React component library",
5
5
  "keywords": [
6
6
  "react",