@stamcat/craftsman 0.0.23-alpha.26 → 0.0.23-alpha.28

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/AGENTS.md CHANGED
@@ -10,9 +10,12 @@ Use these imports:
10
10
 
11
11
  ```tsx
12
12
  import { Button } from "@stamcat/craftsman/Button";
13
+ import { Checkbox } from "@stamcat/craftsman/Checkbox";
13
14
  import { Input } from "@stamcat/craftsman/Input";
15
+ import { InputPassword } from "@stamcat/craftsman/InputPassword";
14
16
  import { Loader } from "@stamcat/craftsman/Loader";
15
17
  import { Modal } from "@stamcat/craftsman/Modal";
18
+ import { RadioButton } from "@stamcat/craftsman/RadioButton";
16
19
  ```
17
20
 
18
21
  Do not assume a root export like `@stamcat/craftsman` unless that export is explicitly added to package `exports`.
@@ -101,7 +104,19 @@ import { Input } from "@stamcat/craftsman/Input";
101
104
 
102
105
  Props:
103
106
 
104
- - Pure passthrough of native `<input>` props.
107
+ - Inherits native `<input>` props.
108
+ - `label?: string | ReactNode`
109
+ - `labelPosition?: "top" | "left" | "bottom" | "right" | "inside" | "hidden"` (default: `"top"`)
110
+ - `error?: string | boolean | ReactNode`
111
+ - `required?: boolean`
112
+ - `styles?: SerializedStyles` (wrapper override)
113
+ - `type?: TextInputType` (checkbox/radio excluded)
114
+
115
+ Behavior notes:
116
+
117
+ - `id` is preserved; if omitted, a stable React `useId` value is used.
118
+ - Floating-label behavior is supported when `labelPosition="inside"`.
119
+ - `endAdornment` exists as an internal extension point used by `InputPassword`; consumer apps should prefer `InputPassword` rather than wiring password toggles on `Input`.
105
120
 
106
121
  Example:
107
122
 
@@ -109,6 +124,112 @@ Example:
109
124
  <Input type="email" placeholder="you@company.com" required />
110
125
  ```
111
126
 
127
+ ### InputPassword
128
+
129
+ Import:
130
+
131
+ ```tsx
132
+ import { InputPassword } from "@stamcat/craftsman/InputPassword";
133
+ ```
134
+
135
+ Props:
136
+
137
+ - Extends `Input` props, with `type` constrained to password mode.
138
+ - Includes all label, error, required, and wrapper style props from `Input`.
139
+
140
+ Behavior notes:
141
+
142
+ - Built on top of `Input` and adds an internal password visibility state.
143
+ - Renders an in-field show/hide toggle button.
144
+ - Toggle is accessible: real button element, keyboard operable, and updates `aria-label` + `aria-pressed`.
145
+ - Use this component for password fields instead of `Input type="password"`.
146
+
147
+ Example:
148
+
149
+ ```tsx
150
+ <InputPassword
151
+ label="Password"
152
+ placeholder="Enter your password"
153
+ autoComplete="current-password"
154
+ />
155
+ ```
156
+
157
+ ### Checkbox
158
+
159
+ Import:
160
+
161
+ ```tsx
162
+ import { Checkbox } from "@stamcat/craftsman/Checkbox";
163
+ ```
164
+
165
+ Props:
166
+
167
+ - Extends `Input` props.
168
+ - `type?: "checkbox"` (default: `"checkbox"`)
169
+ - `labelPosition?: "left" | "right" | "top" | "bottom"` (default: `"right"`)
170
+
171
+ Behavior notes:
172
+
173
+ - `Checkbox` is a thin wrapper around `Input` with checkbox-specific guardrails.
174
+ - The wrapper enforces checkbox type by default and narrows label position options to common checkbox layouts.
175
+ - Controlled and uncontrolled patterns are both supported (`checked` + `onChange`, or `defaultChecked`).
176
+
177
+ Example:
178
+
179
+ ```tsx
180
+ <Checkbox
181
+ id="accept-terms"
182
+ name="terms"
183
+ value="accepted"
184
+ label="Accept terms"
185
+ checked={accepted}
186
+ onChange={(event) => setAccepted(event.currentTarget.checked)}
187
+ />
188
+ ```
189
+
190
+ ### RadioButton
191
+
192
+ Import:
193
+
194
+ ```tsx
195
+ import { RadioButton } from "@stamcat/craftsman/RadioButton";
196
+ ```
197
+
198
+ Props:
199
+
200
+ - Extends `Input` props.
201
+ - `type?: "radio"` (default: `"radio"`)
202
+ - `labelPosition?: "left" | "right"` (default: `"right"`)
203
+
204
+ Behavior notes:
205
+
206
+ - `RadioButton` is a thin wrapper around `Input` with radio-specific guardrails.
207
+ - Group behavior is native HTML radio behavior: use a shared `name` across options.
208
+ - Controlled and uncontrolled patterns are both supported (`checked` + `onChange`, or `defaultChecked`).
209
+
210
+ Example:
211
+
212
+ ```tsx
213
+ <>
214
+ <RadioButton
215
+ id="captain-kirk"
216
+ name="favorite-captain"
217
+ value="Kirk"
218
+ label="James T. Kirk"
219
+ checked={selected === "Kirk"}
220
+ onChange={(event) => setSelected(event.currentTarget.value)}
221
+ />
222
+ <RadioButton
223
+ id="captain-picard"
224
+ name="favorite-captain"
225
+ value="Picard"
226
+ label="Jean-Luc Picard"
227
+ checked={selected === "Picard"}
228
+ onChange={(event) => setSelected(event.currentTarget.value)}
229
+ />
230
+ </>
231
+ ```
232
+
112
233
  ### Modal
113
234
 
114
235
  Import:
@@ -246,6 +367,6 @@ if (arr.length === 0) { ... }
246
367
 
247
368
  If uncertain about available exports:
248
369
 
249
- 1. Use only `Button`, `Input`, `Loader`, and `Modal` from their component entry points.
370
+ 1. Use only `Button`, `Checkbox`, `Input`, `InputPassword`, `Loader`, `Modal`, and `RadioButton` from their component entry points.
250
371
  2. Do not invent package APIs.
251
372
  3. Prefer native HTML elements for anything not explicitly exported.
package/Components.esm.js CHANGED
@@ -1,14 +1,20 @@
1
1
  import { __exportAll as e } from "./_virtual/_rolldown/runtime.esm.js";
2
2
  import { Button as t } from "./src/components/Button.esm.js";
3
3
  import { Input as n } from "./src/components/Input.esm.js";
4
- import { Loader as r } from "./src/components/Loader.esm.js";
5
- import { Modal as i } from "./src/components/Modal.esm.js";
4
+ import { InputPassword as r } from "./src/components/InputPassword.esm.js";
5
+ import { Loader as i } from "./src/components/Loader.esm.js";
6
+ import { RadioButton as a } from "./src/components/RadioButton.esm.js";
7
+ import { Checkbox as o } from "./src/components/Checkbox.esm.js";
8
+ import { Modal as s } from "./src/components/Modal.esm.js";
6
9
  //#region src/components/index.ts
7
- var a = /* @__PURE__ */ e({
10
+ var c = /* @__PURE__ */ e({
8
11
  Button: () => t,
12
+ Checkbox: () => o,
9
13
  Input: () => n,
10
- Loader: () => r,
11
- Modal: () => i
14
+ InputPassword: () => r,
15
+ Loader: () => i,
16
+ Modal: () => s,
17
+ RadioButton: () => a
12
18
  });
13
19
  //#endregion
14
- export { t as Button, n as Input, r as Loader, i as Modal, a as components_exports };
20
+ export { t as Button, o as Checkbox, n as Input, r as InputPassword, i as Loader, s as Modal, a as RadioButton, c as components_exports };
package/Styles.esm.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { defaultColors as e, defaultWidths as t } from "./src/styles/utilities/constants.esm.js";
2
2
  import { color as n, colors as r, hexToRgba as i } from "./src/styles/utilities/color.esm.js";
3
- import { BaseWidthSchema as a, BreakpointSchema as o, LayoutWidthsSchema as s, MaxScreenWidthSchema as c, ScreenWidthSchema as l, zTextInputExclusions as u } from "./src/styles/utilities/types.esm.js";
4
- import { breakpoint as d, media as f, width as p, widths as m } from "./src/styles/utilities/layout.esm.js";
5
- import { CraftsmanThemeProvider as h, themeBuilder as g } from "./src/styles/theme/theme.esm.js";
6
- import { globalStyles as _ } from "./src/styles/global/globalStyles.esm.js";
7
- import { ClientProvider as v } from "./src/styles/components/ClientProvider.esm.js";
8
- export { a as BaseWidthSchema, o as BreakpointSchema, v as ClientProvider, h as CraftsmanThemeProvider, s as LayoutWidthsSchema, c as MaxScreenWidthSchema, l as ScreenWidthSchema, d as breakpoint, n as color, r as colors, e as defaultColors, t as defaultWidths, _ as globalStyles, i as hexToRgba, f as media, g as themeBuilder, p as width, m as widths, u as zTextInputExclusions };
3
+ import { BaseWidthSchema as a, BreakpointSchema as o, LayoutWidthsSchema as s, MaxScreenWidthSchema as c, ScreenWidthSchema as l, zLabelPosition as u, zTextInputExclusions as d, zTextInputType as f, zTextInputTypes as p } from "./src/styles/utilities/types.esm.js";
4
+ import { breakpoint as m, media as h, width as g, widths as _ } from "./src/styles/utilities/layout.esm.js";
5
+ import { CraftsmanThemeProvider as v, themeBuilder as y } from "./src/styles/theme/theme.esm.js";
6
+ import { globalStyles as b } from "./src/styles/global/globalStyles.esm.js";
7
+ import { ClientProvider as x } from "./src/styles/components/ClientProvider.esm.js";
8
+ export { a as BaseWidthSchema, o as BreakpointSchema, x as ClientProvider, v as CraftsmanThemeProvider, s as LayoutWidthsSchema, c as MaxScreenWidthSchema, l as ScreenWidthSchema, m as breakpoint, n as color, r as colors, e as defaultColors, t as defaultWidths, b as globalStyles, i as hexToRgba, h as media, y as themeBuilder, g as width, _ as widths, u as zLabelPosition, d as zTextInputExclusions, f as zTextInputType, p as zTextInputTypes };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stamcat/craftsman",
3
- "version": "0.0.23-alpha.26",
3
+ "version": "0.0.23-alpha.28",
4
4
  "type": "module",
5
5
  "description": "A powerful, lightweight framework for design systems",
6
6
  "repository": {
@@ -25,7 +25,7 @@
25
25
  "dependencies": {
26
26
  "@emotion/react": "11.14.0",
27
27
  "@emotion/styled": "11.14.1",
28
- "dompurify": "3.4.11",
28
+ "dompurify": "3.4.12",
29
29
  "emotion": "11.0.0",
30
30
  "react": "19.2.7",
31
31
  "react-date-picker": "12.0.2",
@@ -39,7 +39,8 @@
39
39
  },
40
40
  "devDependencies": {},
41
41
  "overrides": {
42
- "postcss": "8.5.20"
42
+ "postcss": "8.5.20",
43
+ "sharp": "0.35.3"
43
44
  },
44
45
  "exports": {
45
46
  ".": {
@@ -66,10 +67,22 @@
66
67
  "types": "./src/components/Input.d.ts",
67
68
  "default": "./src/components/Input.esm.js"
68
69
  },
70
+ "./InputPassword": {
71
+ "types": "./src/components/InputPassword.d.ts",
72
+ "default": "./src/components/InputPassword.esm.js"
73
+ },
69
74
  "./Loader": {
70
75
  "types": "./src/components/Loader.d.ts",
71
76
  "default": "./src/components/Loader.esm.js"
72
77
  },
78
+ "./RadioButton": {
79
+ "types": "./src/components/RadioButton.d.ts",
80
+ "default": "./src/components/RadioButton.esm.js"
81
+ },
82
+ "./Checkbox": {
83
+ "types": "./src/components/Checkbox.d.ts",
84
+ "default": "./src/components/Checkbox.esm.js"
85
+ },
73
86
  "./Modal": {
74
87
  "types": "./src/components/Modal.d.ts",
75
88
  "default": "./src/components/Modal.esm.js"
@@ -6,19 +6,23 @@ import r from "@emotion/styled";
6
6
  import { Fragment as i, jsx as a } from "react/jsx-runtime";
7
7
  //#region src/components/Button.tsx
8
8
  var o = r.button`
9
- ${(e) => e.styles}
10
9
  ${((e) => e.size && n`
11
10
  border-radius: calc(var(--btn-border-radius) * ${e.size});
12
11
  padding: calc(var(--btn-pad-y) * ${e.size}) calc(var(--btn-pad-x) * ${e.size});
13
12
  font-size: max(10px, calc(${t("text")} * ${e.size}));
14
13
  `)}
14
+ ${(e) => e.styles && n`
15
+ && {
16
+ ${e.styles}
17
+ }
18
+ `}
15
19
  `, s = (t) => {
16
- let { type: n = "button", variant: r = "default", className: s, size: c, ...l } = t, u = typeof c == "number" ? Math.min(10, Math.max(.1, c)) : void 0, d = [r === "default" ? void 0 : r, s].filter(Boolean).join(" ") || void 0;
20
+ let { type: n = "button", variant: r = "default", size: s, ...c } = t, l = typeof s == "number" ? Math.min(10, Math.max(.1, s)) : void 0;
17
21
  return e(t.children) ? /* @__PURE__ */ a(i, {}) : /* @__PURE__ */ a(o, {
18
22
  type: n,
19
- size: u,
20
- className: d,
21
- ...l
23
+ size: l,
24
+ "data-variant": r,
25
+ ...c
22
26
  });
23
27
  };
24
28
  //#endregion
@@ -0,0 +1,7 @@
1
+ import { InputProps } from './Input';
2
+ type CheckboxProps = InputProps & {
3
+ type?: "checkbox";
4
+ labelPosition?: "left" | "right" | "top" | "bottom";
5
+ };
6
+ export declare const Checkbox: React.FC<CheckboxProps>;
7
+ export {};
@@ -0,0 +1,10 @@
1
+ import { Input as e } from "./Input.esm.js";
2
+ import { jsx as t } from "react/jsx-runtime";
3
+ //#region src/components/Checkbox.tsx
4
+ var n = ({ type: n = "checkbox", labelPosition: r = "right", ...i }) => /* @__PURE__ */ t(e, {
5
+ type: n,
6
+ labelPosition: r,
7
+ ...i
8
+ });
9
+ //#endregion
10
+ export { n as Checkbox };
@@ -1,12 +1,12 @@
1
1
  import { SerializedStyles } from '@emotion/react';
2
- import { TextInputExclusions } from '../styles';
3
- export type LabelPosition = "top" | "left" | "bottom" | "right" | "inside" | "hidden";
2
+ import { LabelPosition, TextInputType } from '../styles/utilities/types';
4
3
  export type InputProps = React.ComponentProps<"input"> & {
5
4
  label?: string | React.ReactNode;
6
5
  labelPosition?: LabelPosition;
7
6
  error?: string | boolean | React.ReactNode;
8
7
  required?: boolean;
9
8
  styles?: SerializedStyles;
10
- type?: Exclude<React.HTMLInputTypeAttribute, TextInputExclusions>;
9
+ endAdornment?: React.ReactNode;
10
+ type?: TextInputType;
11
11
  };
12
12
  export declare const Input: React.FC<InputProps>;
@@ -1,136 +1,86 @@
1
1
  import { isEmpty as e } from "../utilities/validations.esm.js";
2
2
  import { color as t } from "../styles/utilities/color.esm.js";
3
3
  import { width as n } from "../styles/utilities/layout.esm.js";
4
- import "../../Styles.esm.js";
5
- import { css as r } from "@emotion/react";
6
- import i from "@emotion/styled";
7
- import { jsx as a, jsxs as o } from "react/jsx-runtime";
4
+ import { inputErrorStyles as r, inputFieldAdornmentStyles as i, insideLabelStyles as a } from "../styles/global/components/input.esm.js";
5
+ import { css as o } from "@emotion/react";
6
+ import s from "@emotion/styled";
7
+ import { useId as c } from "react";
8
+ import { jsx as l, jsxs as u } from "react/jsx-runtime";
8
9
  //#region src/components/Input.tsx
9
- var s = r`
10
- .input-label {
11
- top: -0.5rem;
12
- left: ${n("gutter", .25)};
13
- font-size: ${n("text", .75)};
14
- }
15
- `, c = (e) => r`
16
- --react-international-phone-height: 50px;
17
- --react-international-phone-border-radius: 8px;
18
- --react-international-phone-border-color: #c0c0c0ff;
19
- position: relative;
20
-
21
- .input-label {
22
- position: absolute;
23
- background-color: white;
24
- z-index: 1;
25
- width: fit-content;
26
- padding: 0 5px;
27
- top: ${n("gutter", .25)};
28
- left: ${n("gutter", .25)};
29
- pointer-events: none;
30
- transition: top 150ms ease, left 150ms ease, font-size 150ms ease, color 150ms ease;
31
- }
32
-
33
- > label > input,
34
- > input {
35
- transition: border-color 200ms ease;
36
- }
37
- &:focus-within {
38
- ${s}
39
- .input-label {
40
- color: ${t("blue500")};
41
- }
42
- input {
43
- border-color: ${t("blue500")};
44
- }
45
- }
46
-
47
- &:has(input:not(:placeholder-shown)) {
48
- ${s}
49
- }
50
-
51
- &:has(input:-webkit-autofill) {
52
- ${s}
53
- }
54
-
55
- ${e ? s : ""}
56
- input[type="tel"] {
57
- width: 100%;
58
- }
59
-
60
- input::placeholder {
61
- opacity: 0;
62
- transition: opacity 200ms ease;
63
- }
64
-
65
- &:focus-within input::placeholder {
66
- opacity: 1;
67
- }
68
- `, l = i.div`
10
+ var d = (e, r) => o`
69
11
  label {
70
12
  .input-label {
71
13
  margin-bottom: ${n("gutter", .25)};
72
- ${(e) => e.required && r`
14
+ ${r && o`
73
15
  ::after {
74
16
  content: "*";
75
17
  color: ${t("red700")};
76
18
  }
77
19
  `}
78
-
79
20
  }
80
21
  }
81
- &.left label {
22
+
23
+ &[data-label-position="left"] label {
24
+ display: inline-flex;
25
+ align-items: center;
82
26
  .input-label {
83
27
  width: fit-content;
84
28
  margin-right: ${n("gutter", .75)};
85
29
  }
86
- display: inline-flex;
87
- align-items: center;
88
30
  }
89
- &.bottom label {
31
+
32
+ &[data-label-position="bottom"] label {
90
33
  display: inline-flex;
91
34
  flex-direction: column-reverse;
92
35
  align-items: flex-start;
93
36
  .input-label {
94
- display: block;
95
37
  margin-bottom: 0;
96
38
  margin-top: ${n("gutter", .25)};
97
39
  }
98
40
  }
99
- &.right label {
41
+
42
+ &[data-label-position="right"] label {
100
43
  display: inline-flex;
101
44
  flex-direction: row-reverse;
102
45
  align-items: center;
103
46
  .input-label {
104
- display: block;
105
47
  margin-left: ${n("gutter", .75)};
106
48
  }
107
49
  }
108
- &.inside {
109
- ${(e) => c(e.hasInput)}
50
+
51
+ &[data-label-position="inside"] {
52
+ ${a(e)}
110
53
  }
54
+ `, f = s.div`
55
+ ${(e) => d(e.hasInput, e.required)}
56
+ ${(e) => e.hasEndAdornment && i}
111
57
  ${(e) => e.styles}
112
- `, u = i.div`
113
- margin-top: ${n("gutter", .25)};
114
- font-size: ${n("text", .75)};
115
- color: ${t("red700")};
116
- `, d = ({ label: t, id: n, labelPosition: r = "top", required: i = !1, error: s, styles: c, ...d }) => {
117
- let f = n || crypto.randomUUID(), p = !e(d.value) || !e(d.defaultValue), m = !e(s);
118
- return /* @__PURE__ */ o(l, {
119
- className: r,
58
+ `, p = s.div`
59
+ ${r}
60
+ `, m = ({ label: t, id: n, labelPosition: r = "top", required: i = !1, type: a = "text", error: o, styles: s, endAdornment: d, ...m }) => {
61
+ let h = c(), g = n || h, _ = !e(m.value) || !e(m.defaultValue), v = /* @__PURE__ */ u("span", {
62
+ className: "input-field",
63
+ "data-has-end-adornment": !e(d),
64
+ children: [/* @__PURE__ */ l("input", {
65
+ id: g,
66
+ type: a,
67
+ ...m
68
+ }), !e(d) && /* @__PURE__ */ l("span", {
69
+ className: "input-adornment",
70
+ children: d
71
+ })]
72
+ });
73
+ return /* @__PURE__ */ u(f, {
74
+ "data-label-position": r,
75
+ hasEndAdornment: !e(d),
120
76
  required: i,
121
- hasInput: p,
122
- styles: c,
123
- children: [e(t) ? /* @__PURE__ */ a("input", {
124
- id: f,
125
- ...d
126
- }) : /* @__PURE__ */ o("label", { children: [r !== "hidden" && /* @__PURE__ */ a("div", {
77
+ hasInput: _,
78
+ styles: s,
79
+ children: [e(t) ? v : /* @__PURE__ */ u("label", { children: [r !== "hidden" && /* @__PURE__ */ l("div", {
127
80
  className: "input-label",
128
81
  children: t
129
- }), /* @__PURE__ */ a("input", {
130
- id: f,
131
- ...d
132
- })] }), m && /* @__PURE__ */ a(u, { children: s })]
82
+ }), v] }), !e(o) && /* @__PURE__ */ l(p, { children: o })]
133
83
  });
134
84
  };
135
85
  //#endregion
136
- export { d as Input };
86
+ export { m as Input };
@@ -0,0 +1,6 @@
1
+ import { TextInputType } from '../styles/utilities/types';
2
+ import { InputProps } from './Input';
3
+ export type InputPasswordProps = React.ComponentProps<"input"> & {} & Omit<InputProps, "type" | "endAdornment"> & {
4
+ type?: Extract<TextInputType, "password">;
5
+ };
6
+ export declare const InputPassword: React.FC<InputPasswordProps>;
@@ -0,0 +1,33 @@
1
+ import { Button as e } from "./Button.esm.js";
2
+ import { Input as t } from "./Input.esm.js";
3
+ import { css as n } from "@emotion/react";
4
+ import { useState as r } from "react";
5
+ import { jsx as i } from "react/jsx-runtime";
6
+ import { ImEye as a, ImEyeBlocked as o } from "react-icons/im";
7
+ //#region src/components/InputPassword.tsx
8
+ var s = n`
9
+ padding: 0;
10
+ display: inline-flex;
11
+ align-items: center;
12
+ line-height: 1;
13
+ `, c = ({ visible: t, onToggle: n }) => /* @__PURE__ */ i(e, {
14
+ type: "button",
15
+ variant: "text",
16
+ onClick: n,
17
+ "aria-label": t ? "Hide password" : "Show password",
18
+ "aria-pressed": t,
19
+ styles: s,
20
+ children: i(t ? a : o, { size: 16 })
21
+ }), l = ({ type: e = "password", ...n }) => {
22
+ let [a, o] = r(!1), s = a ? "text" : e;
23
+ return /* @__PURE__ */ i(t, {
24
+ ...n,
25
+ type: s,
26
+ endAdornment: /* @__PURE__ */ i(c, {
27
+ visible: a,
28
+ onToggle: () => o((e) => !e)
29
+ })
30
+ });
31
+ };
32
+ //#endregion
33
+ export { l as InputPassword };
@@ -0,0 +1,7 @@
1
+ import { InputProps } from './Input';
2
+ type RadioButtonProps = InputProps & {
3
+ type?: "radio";
4
+ labelPosition?: "left" | "right";
5
+ };
6
+ export declare const RadioButton: React.FC<RadioButtonProps>;
7
+ export {};
@@ -0,0 +1,10 @@
1
+ import { Input as e } from "./Input.esm.js";
2
+ import { jsx as t } from "react/jsx-runtime";
3
+ //#region src/components/RadioButton.tsx
4
+ var n = ({ type: n = "radio", labelPosition: r = "right", ...i }) => /* @__PURE__ */ t(e, {
5
+ type: n,
6
+ labelPosition: r,
7
+ ...i
8
+ });
9
+ //#endregion
10
+ export { n as RadioButton };
@@ -1,4 +1,7 @@
1
1
  export { Button } from './Button';
2
2
  export { Input } from './Input';
3
+ export { InputPassword } from './InputPassword';
3
4
  export { Loader } from './Loader';
5
+ export { RadioButton } from './RadioButton';
6
+ export { Checkbox } from './Checkbox';
4
7
  export { Modal } from './Modal';
@@ -38,7 +38,8 @@ var a = r`
38
38
  &:not(:disabled):not(.disabled):hover {
39
39
  background-color: ${e("teal200")};
40
40
  }
41
- &.text {
41
+ &.text,
42
+ &[data-variant="text"] {
42
43
  ${a}
43
44
  }
44
45
  &:disabled,
@@ -46,13 +47,15 @@ var a = r`
46
47
  cursor: not-allowed;
47
48
  border-color: ${e("gray200")};
48
49
  color: ${e("gray400")};
49
- &.primary {
50
+ &.primary,
51
+ &[data-variant="primary"] {
50
52
  border-color: ${e("gray200")};
51
53
  background-color: ${e("gray400")};
52
54
  color: ${e("gray200")};
53
55
  }
54
56
  }
55
- &.primary {
57
+ &.primary,
58
+ &[data-variant="primary"] {
56
59
  color: ${e("white")};
57
60
  background-color: ${e("blue500")};
58
61
  &:not(:disabled):not(.disabled):hover {
@@ -0,0 +1 @@
1
+ export declare const checkboxStyles: import('@emotion/utils').SerializedStyles;
@@ -0,0 +1,78 @@
1
+ import { color as e } from "../../utilities/color.esm.js";
2
+ import { css as t } from "@emotion/react";
3
+ //#region src/styles/global/components/checkbox.ts
4
+ var n = t`
5
+ &[type="checkbox"] {
6
+ appearance: none;
7
+ box-sizing: border-box;
8
+ position: relative;
9
+ display: inline-block;
10
+ vertical-align: baseline;
11
+ top: 0.08em;
12
+ margin: 0;
13
+ padding: 0;
14
+ height: 16px;
15
+ width: 16px;
16
+ border-radius: 4px;
17
+ border: 1px solid ${e("blue500")};
18
+ background: #fff;
19
+
20
+ &::before {
21
+ content: "";
22
+ position: absolute;
23
+ inset: 0;
24
+ border-radius: 4px;
25
+ background: transparent;
26
+ transition: background-color 0.15s ease;
27
+ }
28
+
29
+ &::after {
30
+ position: absolute;
31
+ left: 50%;
32
+ top: 45%;
33
+ width: 5px;
34
+ height: 8px;
35
+ content: "";
36
+ display: block;
37
+ border: solid white;
38
+ border-width: 0 2px 2px 0;
39
+ transform: translate(-50%, -58%) rotate(45deg) scale(0);
40
+ transform-origin: center;
41
+ transition: transform 0.15s ease;
42
+ }
43
+
44
+ &:checked {
45
+ border-color: ${e("blue500")};
46
+ &::before {
47
+ background-color: ${e("blue500")};
48
+ }
49
+ &::after {
50
+ transform: translate(-50%, -58%) rotate(45deg) scale(1);
51
+ }
52
+ }
53
+
54
+ &:disabled {
55
+ border-color: ${e("gray500")};
56
+ &::before {
57
+ background-color: ${e("gray200")};
58
+ }
59
+ &::after {
60
+ border-color: ${e("gray200")};
61
+ transform: translate(-50%, -58%) rotate(45deg) scale(1);
62
+ }
63
+ }
64
+
65
+ &:checked:disabled {
66
+ border-color: ${e("gray400")};
67
+ &::before {
68
+ background: ${e("gray400")};
69
+ }
70
+ &::after {
71
+ border-color: ${e("white")};
72
+ transform: translate(-50%, -58%) rotate(45deg) scale(1);
73
+ }
74
+ }
75
+ }
76
+ `;
77
+ //#endregion
78
+ export { n as checkboxStyles };
@@ -1 +1,5 @@
1
1
  export declare const input: import('@emotion/utils').SerializedStyles;
2
+ export declare const inputErrorStyles: import('@emotion/utils').SerializedStyles;
3
+ export declare const inputFieldAdornmentStyles: import('@emotion/utils').SerializedStyles;
4
+ export declare const tinyLabelStyles: import('@emotion/utils').SerializedStyles;
5
+ export declare const insideLabelStyles: (hasInput: boolean) => import('@emotion/utils').SerializedStyles;
@@ -3,30 +3,119 @@ import { width as t } from "../../utilities/layout.esm.js";
3
3
  import { css as n } from "@emotion/react";
4
4
  //#region src/styles/global/components/input.ts
5
5
  var r = n`
6
- color: ${e("text")};
7
- border-radius: 3px;
8
- border: 1px solid ${e("gray400")};
9
- padding: ${t("gutter", .5)};
10
- background-color: ${e("white")};
11
-
12
- &[type="number"]::-webkit-outer-spin-button,
13
- &[type="number"]::-webkit-inner-spin-button {
14
- -webkit-appearance: none;
15
- margin: 0;
6
+ color: ${e("text")};
7
+ border-radius: 3px;
8
+ border: 1px solid ${e("gray400")};
9
+ padding: ${t("gutter", .5)};
10
+ background-color: ${e("white")};
11
+
12
+ &[type="number"]::-webkit-outer-spin-button,
13
+ &[type="number"]::-webkit-inner-spin-button {
14
+ -webkit-appearance: none;
15
+ margin: 0;
16
+ }
17
+ &[type="number"] {
18
+ -moz-appearance: textfield;
19
+ appearance: textfield;
20
+ }
21
+ &:disabled,
22
+ &.disabled {
23
+ border-color: ${e("gray200")};
24
+ background-color: ${e("gray100")};
25
+ }
26
+ &:focus {
27
+ outline: 0;
28
+ box-shadow: none;
29
+ }
30
+ `, i = n`
31
+ margin-top: ${t("gutter", .25)};
32
+ font-size: ${t("text", .75)};
33
+ color: ${e("red600")};
34
+ `, a = n`
35
+ .input-field {
36
+ position: relative;
37
+ display: inline-flex;
38
+ width: 100%;
39
+ align-items: center;
40
+
41
+ > input {
42
+ width: 100%;
43
+ padding-right: calc(${t("gutter", .5)} + 24px + ${t("gutter", .5)});
16
44
  }
17
- &[type="number"] {
18
- -moz-appearance: textfield;
19
- appearance: textfield;
45
+
46
+ > .input-adornment {
47
+ position: absolute;
48
+ right: ${t("gutter", .5)};
49
+ top: 50%;
50
+ transform: translateY(-50%);
51
+ margin-top: 0;
52
+ z-index: 1;
53
+ display: inline-flex;
54
+ align-items: center;
20
55
  }
21
- &:disabled, &.disabled {
22
- border-color: ${e("gray200")};
23
- background-color: ${e("gray100")};
56
+ }
57
+ `, o = n`
58
+ .input-label {
59
+ top: -0.5rem;
60
+ left: ${t("gutter", .25)};
61
+ font-size: ${t("text", .75)};
62
+ }
63
+ `, s = (r) => n`
64
+ --react-international-phone-height: 50px;
65
+ --react-international-phone-border-radius: 8px;
66
+ --react-international-phone-border-color: #c0c0c0ff;
67
+ position: relative;
68
+
69
+ .input-label {
70
+ position: absolute;
71
+ background-color: white;
72
+ z-index: 1;
73
+ width: fit-content;
74
+ padding: 0 5px;
75
+ top: ${t("gutter", .25)};
76
+ left: ${t("gutter", .25)};
77
+ pointer-events: none;
78
+ transition:
79
+ top 150ms ease,
80
+ left 150ms ease,
81
+ font-size 150ms ease,
82
+ color 150ms ease;
83
+ }
84
+
85
+ > label > input,
86
+ > input {
87
+ transition: border-color 200ms ease;
88
+ }
89
+
90
+ &:focus-within {
91
+ ${o}
92
+ .input-label {
93
+ color: ${e("blue500")};
24
94
  }
25
- &:focus {
26
- outline: 0;
27
- box-shadow: none;
95
+ input {
96
+ border-color: ${e("blue500")};
28
97
  }
98
+ }
99
+
100
+ &:has(input:not(:placeholder-shown)),
101
+ &:has(input:-webkit-autofill) {
102
+ ${o}
103
+ }
104
+
105
+ ${r && o}
106
+
107
+ input[type="tel"] {
108
+ width: 100%;
109
+ }
110
+
111
+ input::placeholder {
112
+ opacity: 0;
113
+ transition: opacity 200ms ease;
114
+ }
29
115
 
116
+ &:focus-within input::placeholder {
117
+ opacity: 1;
118
+ }
30
119
  `;
31
120
  //#endregion
32
- export { r as input };
121
+ export { r as input, i as inputErrorStyles, a as inputFieldAdornmentStyles, s as insideLabelStyles, o as tinyLabelStyles };
@@ -0,0 +1 @@
1
+ export declare const radioBtnStyles: import('@emotion/utils').SerializedStyles;
@@ -0,0 +1,39 @@
1
+ import { color as e } from "../../utilities/color.esm.js";
2
+ import { css as t } from "@emotion/react";
3
+ //#region src/styles/global/components/radioButton.tsx
4
+ var n = t`
5
+ --radio-btn-size: 16px;
6
+
7
+ transition: border-color 0.2s ease;
8
+ appearance: none;
9
+ cursor: pointer;
10
+ position: relative;
11
+ display: inline-grid;
12
+ place-content: center;
13
+ margin: 0;
14
+ padding: 0;
15
+ width: var(--radio-btn-size);
16
+ height: var(--radio-btn-size);
17
+ border: 1px solid ${e("blue600")};
18
+ border-radius: 50%;
19
+ box-sizing: border-box;
20
+
21
+ &::before {
22
+ content: "";
23
+ width: calc(var(--radio-btn-size) * 0.5);
24
+ height: calc(var(--radio-btn-size) * 0.5);
25
+ border-radius: 50%;
26
+ transform: scale(0);
27
+ transition: transform 0.2s ease;
28
+ background-color: ${e("blue600")};
29
+ }
30
+
31
+ &:checked {
32
+ border-color: ${e("gray500")};
33
+ &::before {
34
+ transform: scale(1);
35
+ }
36
+ }
37
+ `;
38
+ //#endregion
39
+ export { n as radioBtnStyles };
@@ -3,9 +3,11 @@ import { typographyStyles as n } from "./components/typography.esm.js";
3
3
  import { button as r, textLinkStyles as i } from "./components/button.esm.js";
4
4
  import { code as a } from "./components/code.esm.js";
5
5
  import { input as o } from "./components/input.esm.js";
6
- import { css as s } from "@emotion/react";
6
+ import { checkboxStyles as s } from "./components/checkbox.esm.js";
7
+ import { radioBtnStyles as c } from "./components/radioButton.esm.js";
8
+ import { css as l } from "@emotion/react";
7
9
  //#region src/styles/global/globalStyles.ts
8
- var c = s`
10
+ var u = l`
9
11
  :root {
10
12
  ${t}
11
13
  ${e}
@@ -57,6 +59,12 @@ var c = s`
57
59
  }
58
60
  input {
59
61
  ${o}
62
+ &[type="radio"] {
63
+ ${c}
64
+ }
65
+ &[type="checkbox"] {
66
+ ${s}
67
+ }
60
68
  }
61
69
  a {
62
70
  ${i}
@@ -68,4 +76,4 @@ var c = s`
68
76
  ${n}
69
77
  `;
70
78
  //#endregion
71
- export { c as globalStyles };
79
+ export { u as globalStyles };
@@ -49,3 +49,37 @@ export declare const zTextInputExclusions: z.ZodEnum<{
49
49
  radio: "radio";
50
50
  }>;
51
51
  export type TextInputExclusions = z.infer<typeof zTextInputExclusions>;
52
+ export declare const zTextInputTypes: readonly ["color", "date", "datetime-local", "email", "file", "hidden", "image", "month", "number", "password", "range", "reset", "search", "submit", "tel", "text", "time", "url", "week", "radio", "checkbox"];
53
+ export declare const zTextInputType: z.ZodEnum<{
54
+ number: "number";
55
+ text: "text";
56
+ checkbox: "checkbox";
57
+ radio: "radio";
58
+ color: "color";
59
+ date: "date";
60
+ "datetime-local": "datetime-local";
61
+ email: "email";
62
+ file: "file";
63
+ hidden: "hidden";
64
+ image: "image";
65
+ month: "month";
66
+ password: "password";
67
+ range: "range";
68
+ reset: "reset";
69
+ search: "search";
70
+ submit: "submit";
71
+ tel: "tel";
72
+ time: "time";
73
+ url: "url";
74
+ week: "week";
75
+ }>;
76
+ export type TextInputType = z.infer<typeof zTextInputType>;
77
+ export declare const zLabelPosition: z.ZodEnum<{
78
+ hidden: "hidden";
79
+ top: "top";
80
+ left: "left";
81
+ bottom: "bottom";
82
+ right: "right";
83
+ inside: "inside";
84
+ }>;
85
+ export type LabelPosition = z.infer<typeof zLabelPosition>;
@@ -20,6 +20,35 @@ var t = e.enum(["gutter", "column"]), n = e.enum([
20
20
  ...n.options,
21
21
  ...r.options,
22
22
  "text"
23
- ]), o = e.enum(["checkbox", "radio"]);
23
+ ]), o = e.enum(["checkbox", "radio"]), s = [
24
+ "color",
25
+ "date",
26
+ "datetime-local",
27
+ "email",
28
+ "file",
29
+ "hidden",
30
+ "image",
31
+ "month",
32
+ "number",
33
+ "password",
34
+ "range",
35
+ "reset",
36
+ "search",
37
+ "submit",
38
+ "tel",
39
+ "text",
40
+ "time",
41
+ "url",
42
+ "week",
43
+ "radio",
44
+ "checkbox"
45
+ ], c = e.enum(s), l = e.enum([
46
+ "top",
47
+ "left",
48
+ "bottom",
49
+ "right",
50
+ "inside",
51
+ "hidden"
52
+ ]);
24
53
  //#endregion
25
- export { t as BaseWidthSchema, i as BreakpointSchema, a as LayoutWidthsSchema, r as MaxScreenWidthSchema, n as ScreenWidthSchema, o as zTextInputExclusions };
54
+ export { t as BaseWidthSchema, i as BreakpointSchema, a as LayoutWidthsSchema, r as MaxScreenWidthSchema, n as ScreenWidthSchema, l as zLabelPosition, o as zTextInputExclusions, c as zTextInputType, s as zTextInputTypes };