@stamcat/craftsman 0.0.27-alpha.20 → 0.0.27-alpha.21

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 (45) hide show
  1. package/AGENTS.md +3 -0
  2. package/Components.esm.js +48 -42
  3. package/Styles.esm.js +7 -7
  4. package/package.json +14 -1
  5. package/src/components/Button/AGENTS.md +5 -4
  6. package/src/components/Button/Button.esm.js +11 -16
  7. package/src/components/Checkbox/AGENTS.md +2 -0
  8. package/src/components/Checkbox/Checkbox.d.ts +1 -0
  9. package/src/components/Checkbox/Checkbox.esm.js +12 -5
  10. package/src/components/Input/Input2.esm.js +1 -1
  11. package/src/components/InputNumber/AGENTS.md +2 -1
  12. package/src/components/InputNumber/InputNumber.d.ts +1 -0
  13. package/src/components/InputNumber/InputNumber2.esm.js +9 -9
  14. package/src/components/Notice/AGENTS.md +42 -0
  15. package/src/components/Notice/Notice.css +1 -0
  16. package/src/components/Notice/Notice.d.ts +13 -0
  17. package/src/components/Notice/Notice.scss +76 -0
  18. package/src/components/Notice/Notice2.esm.js +56 -0
  19. package/src/components/RadioButton/AGENTS.md +2 -0
  20. package/src/components/RadioButton/RadioButton.d.ts +1 -0
  21. package/src/components/RadioButton/RadioButton.esm.js +12 -5
  22. package/src/components/SortableList/AGENTS.md +45 -0
  23. package/src/components/SortableList/ListItem.d.ts +10 -0
  24. package/src/components/SortableList/ListItem.esm.js +67 -0
  25. package/src/components/SortableList/SortableList.css +1 -0
  26. package/src/components/SortableList/SortableList.d.ts +23 -0
  27. package/src/components/SortableList/SortableList.scss +41 -0
  28. package/src/components/SortableList/SortableList2.esm.js +54 -0
  29. package/src/components/SortableList/utilities.d.ts +7 -0
  30. package/src/components/SortableList/utilities.esm.js +4 -0
  31. package/src/components/Text/Text.css +1 -1
  32. package/src/components/Toggle/AGENTS.md +33 -0
  33. package/src/components/Toggle/Toggle.css +1 -0
  34. package/src/components/Toggle/Toggle.d.ts +5 -0
  35. package/src/components/Toggle/Toggle.scss +64 -0
  36. package/src/components/Toggle/Toggle2.esm.js +19 -0
  37. package/src/components/index.d.ts +3 -0
  38. package/src/stories/documentation/ToDo.mdx +1 -3
  39. package/src/styles/global/components/_button.scss +4 -5
  40. package/src/styles/global/components/_checkbox.scss +5 -4
  41. package/src/styles/global/components/_radioButton.scss +5 -4
  42. package/src/styles/global/components/_typography.scss +6 -1
  43. package/src/styles/global/globalStyles.scss +3 -1
  44. package/src/utilities/types.d.ts +8 -0
  45. package/src/utilities/types.esm.js +8 -2
package/AGENTS.md CHANGED
@@ -30,6 +30,9 @@ import { Select } from "@stamcat/craftsman/Select";
30
30
  import { Text } from "@stamcat/craftsman/Text";
31
31
  import { Textarea } from "@stamcat/craftsman/Textarea";
32
32
  import { TimePicker } from "@stamcat/craftsman/TimePicker";
33
+ import { Toggle } from "@stamcat/craftsman/Toggle";
34
+ import { Notice } from "@stamcat/craftsman/Notice";
35
+ import { SortableList } from "@stamcat/craftsman/SortableList";
33
36
  ```
34
37
 
35
38
  Do not assume a root export like `@stamcat/craftsman` unless that export is explicitly added to package `exports`.
package/Components.esm.js CHANGED
@@ -13,63 +13,69 @@ import { DatePicker as d } from "./src/components/DatePicker/DatePicker2.esm.js"
13
13
  import { DateRangePicker as f } from "./src/components/DateRangePicker/DateRangePicker2.esm.js";
14
14
  import { InputPhone as p } from "./src/components/InputPhone/InputPhone2.esm.js";
15
15
  import { InputNumber as m } from "./src/components/InputNumber/InputNumber2.esm.js";
16
- import { Pagination as h } from "./src/components/Pagination/Pagination2.esm.js";
17
- import { Carousel as g } from "./src/components/Carousel/Carousel2.esm.js";
18
- import { TimePicker as _ } from "./src/components/TimePicker/TimePicker2.esm.js";
19
- import { DateTimePicker as v } from "./src/components/DateTimePicker/DateTimePicker2.esm.js";
20
- import { Tooltip as y } from "./src/components/Tooltip/Tooltip2.esm.js";
21
- import { IconAmazonPay as b } from "./src/components/Icons/IconAmazonPay.esm.js";
22
- import { IconAmex as x } from "./src/components/Icons/IconAmex.esm.js";
23
- import { IconApplePay as S } from "./src/components/Icons/IconApplePay.esm.js";
24
- import { IconDiscover as C } from "./src/components/Icons/IconDiscover.esm.js";
25
- import { IconGooglePay as w } from "./src/components/Icons/IconGooglePay.esm.js";
26
- import { IconMaestro as T } from "./src/components/Icons/IconMaestro.esm.js";
27
- import { IconMastercard as E } from "./src/components/Icons/IconMastercard.esm.js";
28
- import { IconPayPal as D } from "./src/components/Icons/IconPayPal.esm.js";
29
- import { IconSepa as O } from "./src/components/Icons/IconSepa.esm.js";
30
- import { IconShopPay as k } from "./src/components/Icons/IconShopPay.esm.js";
31
- import { IconSquare as A } from "./src/components/Icons/IconSquare.esm.js";
32
- import { IconStripe as j } from "./src/components/Icons/IconStripe.esm.js";
33
- import { IconUnionPay as M } from "./src/components/Icons/IconUnionPay.esm.js";
34
- import { IconVenmo as N } from "./src/components/Icons/IconVenmo.esm.js";
35
- import { IconVisa as P } from "./src/components/Icons/IconVisa.esm.js";
16
+ import { Toggle as h } from "./src/components/Toggle/Toggle2.esm.js";
17
+ import { Pagination as g } from "./src/components/Pagination/Pagination2.esm.js";
18
+ import { Carousel as _ } from "./src/components/Carousel/Carousel2.esm.js";
19
+ import { TimePicker as v } from "./src/components/TimePicker/TimePicker2.esm.js";
20
+ import { DateTimePicker as y } from "./src/components/DateTimePicker/DateTimePicker2.esm.js";
21
+ import { Tooltip as b } from "./src/components/Tooltip/Tooltip2.esm.js";
22
+ import { Notice as x } from "./src/components/Notice/Notice2.esm.js";
23
+ import { SortableList as S } from "./src/components/SortableList/SortableList2.esm.js";
24
+ import { IconAmazonPay as C } from "./src/components/Icons/IconAmazonPay.esm.js";
25
+ import { IconAmex as w } from "./src/components/Icons/IconAmex.esm.js";
26
+ import { IconApplePay as T } from "./src/components/Icons/IconApplePay.esm.js";
27
+ import { IconDiscover as E } from "./src/components/Icons/IconDiscover.esm.js";
28
+ import { IconGooglePay as D } from "./src/components/Icons/IconGooglePay.esm.js";
29
+ import { IconMaestro as O } from "./src/components/Icons/IconMaestro.esm.js";
30
+ import { IconMastercard as k } from "./src/components/Icons/IconMastercard.esm.js";
31
+ import { IconPayPal as A } from "./src/components/Icons/IconPayPal.esm.js";
32
+ import { IconSepa as j } from "./src/components/Icons/IconSepa.esm.js";
33
+ import { IconShopPay as M } from "./src/components/Icons/IconShopPay.esm.js";
34
+ import { IconSquare as N } from "./src/components/Icons/IconSquare.esm.js";
35
+ import { IconStripe as P } from "./src/components/Icons/IconStripe.esm.js";
36
+ import { IconUnionPay as F } from "./src/components/Icons/IconUnionPay.esm.js";
37
+ import { IconVenmo as I } from "./src/components/Icons/IconVenmo.esm.js";
38
+ import { IconVisa as L } from "./src/components/Icons/IconVisa.esm.js";
36
39
  import "./src/components/Icons/index.esm.js";
37
40
  //#region src/components/index.ts
38
- var F = /* @__PURE__ */ e({
41
+ var R = /* @__PURE__ */ e({
39
42
  Button: () => t,
40
- Carousel: () => g,
43
+ Carousel: () => _,
41
44
  Checkbox: () => o,
42
45
  DatePicker: () => d,
43
46
  DateRangePicker: () => f,
44
- DateTimePicker: () => v,
45
- IconAmazonPay: () => b,
46
- IconAmex: () => x,
47
- IconApplePay: () => S,
48
- IconDiscover: () => C,
49
- IconGooglePay: () => w,
50
- IconMaestro: () => T,
51
- IconMastercard: () => E,
52
- IconPayPal: () => D,
53
- IconSepa: () => O,
54
- IconShopPay: () => k,
55
- IconSquare: () => A,
56
- IconStripe: () => j,
57
- IconUnionPay: () => M,
58
- IconVenmo: () => N,
59
- IconVisa: () => P,
47
+ DateTimePicker: () => y,
48
+ IconAmazonPay: () => C,
49
+ IconAmex: () => w,
50
+ IconApplePay: () => T,
51
+ IconDiscover: () => E,
52
+ IconGooglePay: () => D,
53
+ IconMaestro: () => O,
54
+ IconMastercard: () => k,
55
+ IconPayPal: () => A,
56
+ IconSepa: () => j,
57
+ IconShopPay: () => M,
58
+ IconSquare: () => N,
59
+ IconStripe: () => P,
60
+ IconUnionPay: () => F,
61
+ IconVenmo: () => I,
62
+ IconVisa: () => L,
60
63
  Input: () => n,
61
64
  InputNumber: () => m,
62
65
  InputPassword: () => r,
63
66
  InputPhone: () => p,
64
67
  Loader: () => i,
65
68
  Modal: () => l,
66
- Pagination: () => h,
69
+ Notice: () => x,
70
+ Pagination: () => g,
67
71
  RadioButton: () => a,
68
72
  Select: () => u,
73
+ SortableList: () => S,
69
74
  Text: () => c,
70
75
  Textarea: () => s,
71
- TimePicker: () => _,
72
- Tooltip: () => y
76
+ TimePicker: () => v,
77
+ Toggle: () => h,
78
+ Tooltip: () => b
73
79
  });
74
80
  //#endregion
75
- export { t as Button, g as Carousel, o as Checkbox, d as DatePicker, f as DateRangePicker, v as DateTimePicker, b as IconAmazonPay, x as IconAmex, S as IconApplePay, C as IconDiscover, w as IconGooglePay, T as IconMaestro, E as IconMastercard, D as IconPayPal, O as IconSepa, k as IconShopPay, A as IconSquare, j as IconStripe, M as IconUnionPay, N as IconVenmo, P as IconVisa, n as Input, m as InputNumber, r as InputPassword, p as InputPhone, i as Loader, l as Modal, h as Pagination, a as RadioButton, u as Select, c as Text, s as Textarea, _ as TimePicker, y as Tooltip, F as components_exports };
81
+ export { t as Button, _ as Carousel, o as Checkbox, d as DatePicker, f as DateRangePicker, y as DateTimePicker, C as IconAmazonPay, w as IconAmex, T as IconApplePay, E as IconDiscover, D as IconGooglePay, O as IconMaestro, k as IconMastercard, A as IconPayPal, j as IconSepa, M as IconShopPay, N as IconSquare, P as IconStripe, F as IconUnionPay, I as IconVenmo, L as IconVisa, n as Input, m as InputNumber, r as InputPassword, p as InputPhone, i as Loader, l as Modal, x as Notice, g as Pagination, a as RadioButton, u as Select, S as SortableList, c as Text, s as Textarea, v as TimePicker, h as Toggle, b as Tooltip, R as components_exports };
package/Styles.esm.js CHANGED
@@ -1,7 +1,7 @@
1
- import { BaseWidthSchema as e, BreakpointSchema as t, ButtonType as n, CarouselPageType as r, LayoutWidthsSchema as i, MaxScreenWidthSchema as a, ScreenWidthSchema as o, TextSize as s, TextTags as c, TextType as l, zCheckboxLabelPosition as u, zLabelPosition as d, zRadioLabelPosition as f, zTextInputExclusions as p, zTextInputType as m, zTextInputTypes as h } from "./src/utilities/types.esm.js";
2
- import { defaultColors as g, defaultWidths as _ } from "./src/styles/utilities/constants.esm.js";
3
- import { breakpoint as v, media as y, width as b, widths as x } from "./src/styles/utilities/layout.esm.js";
4
- import { color as S, colors as C, hexToRgba as w } from "./src/styles/utilities/color.esm.js";
5
- import { themeBuilder as T } from "./src/styles/theme/theme.esm.js";
6
- import { ThemeProvider as E } from "./src/styles/components/ThemeProvider.esm.js";
7
- export { e as BaseWidthSchema, t as BreakpointSchema, n as ButtonType, r as CarouselPageType, i as LayoutWidthsSchema, a as MaxScreenWidthSchema, o as ScreenWidthSchema, s as TextSize, c as TextTags, l as TextType, E as ThemeProvider, v as breakpoint, S as color, C as colors, g as defaultColors, _ as defaultWidths, w as hexToRgba, y as media, T as themeBuilder, b as width, x as widths, u as zCheckboxLabelPosition, d as zLabelPosition, f as zRadioLabelPosition, p as zTextInputExclusions, m as zTextInputType, h as zTextInputTypes };
1
+ import { BaseWidthSchema as e, BreakpointSchema as t, ButtonType as n, CarouselPageType as r, LayoutWidthsSchema as i, MaxScreenWidthSchema as a, NoticeType as o, ScreenWidthSchema as s, TextSize as c, TextTags as l, TextType as u, zCheckboxLabelPosition as d, zLabelPosition as f, zRadioLabelPosition as p, zTextInputExclusions as m, zTextInputType as h, zTextInputTypes as g } from "./src/utilities/types.esm.js";
2
+ import { defaultColors as _, defaultWidths as v } from "./src/styles/utilities/constants.esm.js";
3
+ import { color as y, colors as b, hexToRgba as x } from "./src/styles/utilities/color.esm.js";
4
+ import { breakpoint as S, media as C, width as w, widths as T } from "./src/styles/utilities/layout.esm.js";
5
+ import { themeBuilder as E } from "./src/styles/theme/theme.esm.js";
6
+ import { ThemeProvider as D } from "./src/styles/components/ThemeProvider.esm.js";
7
+ export { e as BaseWidthSchema, t as BreakpointSchema, n as ButtonType, r as CarouselPageType, i as LayoutWidthsSchema, a as MaxScreenWidthSchema, o as NoticeType, s as ScreenWidthSchema, c as TextSize, l as TextTags, u as TextType, D as ThemeProvider, S as breakpoint, y as color, b as colors, _ as defaultColors, v as defaultWidths, x as hexToRgba, C as media, E as themeBuilder, w as width, T as widths, d as zCheckboxLabelPosition, f as zLabelPosition, p as zRadioLabelPosition, m as zTextInputExclusions, h as zTextInputType, g as zTextInputTypes };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stamcat/craftsman",
3
- "version": "0.0.27-alpha.20",
3
+ "version": "0.0.27-alpha.21",
4
4
  "type": "module",
5
5
  "description": "A powerful, lightweight framework for design systems",
6
6
  "repository": {
@@ -23,6 +23,7 @@
23
23
  "prepublishOnly": "node ./scripts/prepublishCheck.js"
24
24
  },
25
25
  "dependencies": {
26
+ "@atlaskit/pragmatic-drag-and-drop": "3.0.0",
26
27
  "@floating-ui/react-dom": "2.1.9",
27
28
  "@wojtekmaj/react-daterange-picker": "7.1.0",
28
29
  "clsx": "2.1.1",
@@ -124,6 +125,10 @@
124
125
  "types": "./src/components/InputNumber.d.ts",
125
126
  "default": "./src/components/InputNumber.esm.js"
126
127
  },
128
+ "./Toggle": {
129
+ "types": "./src/components/Toggle.d.ts",
130
+ "default": "./src/components/Toggle.esm.js"
131
+ },
127
132
  "./Pagination": {
128
133
  "types": "./src/components/Pagination.d.ts",
129
134
  "default": "./src/components/Pagination.esm.js"
@@ -143,6 +148,14 @@
143
148
  "./Tooltip": {
144
149
  "types": "./src/components/Tooltip.d.ts",
145
150
  "default": "./src/components/Tooltip.esm.js"
151
+ },
152
+ "./Notice": {
153
+ "types": "./src/components/Notice.d.ts",
154
+ "default": "./src/components/Notice.esm.js"
155
+ },
156
+ "./SortableList": {
157
+ "types": "./src/components/SortableList.d.ts",
158
+ "default": "./src/components/SortableList.esm.js"
146
159
  }
147
160
  }
148
161
  }
@@ -21,10 +21,11 @@ Behavior notes:
21
21
  - Theme component overrides are selector-based CSS emitted by `ThemeProvider`; `theme.components.*` accepts JS style objects or raw CSS/Sass strings for the target selector.
22
22
  - If `children` is empty (per `isEmpty`), the component renders nothing.
23
23
  - `size` is clamped to `[0.1, 10]` before styling is applied.
24
- - When `size` is provided, Button scales:
25
- - `border-radius: calc(var(--btn-border-radius) * size)`
26
- - `padding: calc(var(--btn-pad-y) * size) calc(var(--btn-pad-x) * size)`
27
- - `font-size: max(10px, calc(var(--w-text) * size))`
24
+ - When `size` is provided, Button sets a single `--btn-size` CSS variable inline; all scaling math lives in SCSS:
25
+ - `border-radius: calc(var(--w-gutter) * 0.75 * var(--btn-size))`
26
+ - `padding: calc(var(--w-gutter) * 0.5 * var(--btn-size)) calc(var(--w-gutter) * 0.75 * var(--btn-size))`
27
+ - `font-size: max(10px, calc(var(--w-text) * var(--btn-size)))`
28
+ - This is the standard sizing pattern used across the library (see `Toggle`'s `--toggle-width`): components expose one scale/size CSS variable, and SCSS does all the `calc()` work.
28
29
  - There is no dedicated icon/loading prop. Icons, loaders, and mixed content are passed as `children`.
29
30
  - Supports both real disable (`disabled={true}`) and style-only disable (`className="disabled"`).
30
31
  - Native button modes are supported (`type="button" | "submit" | "reset"`).
@@ -1,25 +1,20 @@
1
1
  "use client";
2
2
  import { isEmpty as e } from "../../utilities/validations.esm.js";
3
- import { width as t } from "../../styles/utilities/layout.esm.js";
4
- import n from "clsx";
5
- import { Fragment as r, jsx as i } from "react/jsx-runtime";
3
+ import t from "clsx";
4
+ import { Fragment as n, jsx as r } from "react/jsx-runtime";
6
5
  //#region src/components/Button/Button.tsx
7
- var a = (a) => {
8
- let { type: o = "button", variant: s = "default", size: c, styles: l, className: u, style: d, ...f } = a, p = typeof c == "number" ? Math.min(10, Math.max(.1, c)) : void 0, m = e(l) ? void 0 : l, h = p ? {
9
- borderRadius: `calc(var(--btn-border-radius) * ${p})`,
10
- padding: `calc(var(--btn-pad-y) * ${p}) calc(var(--btn-pad-x) * ${p})`,
11
- fontSize: `max(10px, calc(${t("text")} * ${p}))`
12
- } : {};
13
- return e(a.children) ? /* @__PURE__ */ i(r, {}) : /* @__PURE__ */ i("button", {
14
- type: o,
15
- className: n("button", s, u),
6
+ var i = (i) => {
7
+ let { type: a = "button", variant: o = "default", size: s, styles: c, className: l, style: u, ...d } = i, f = typeof s == "number" ? Math.min(10, Math.max(.1, s)) : void 0, p = e(c) ? void 0 : c, m = f ? { "--btn-size": f } : void 0;
8
+ return e(i.children) ? /* @__PURE__ */ r(n, {}) : /* @__PURE__ */ r("button", {
9
+ type: a,
10
+ className: t("button", o, l),
16
11
  style: {
17
- ...h,
18
12
  ...m,
19
- ...d
13
+ ...p,
14
+ ...u
20
15
  },
21
- ...f
16
+ ...d
22
17
  });
23
18
  };
24
19
  //#endregion
25
- export { a as Button };
20
+ export { i as Button };
@@ -11,12 +11,14 @@ Props:
11
11
  - Extends `Input` props.
12
12
  - `type?: "checkbox"` (default: `"checkbox"`)
13
13
  - `labelPosition?: "left" | "right" | "top" | "bottom"` (default: `"right"`)
14
+ - `size?: number` (default visual scale is `1`, clamped to `[0.1, 10]`)
14
15
 
15
16
  Behavior notes:
16
17
 
17
18
  - `Checkbox` is a thin wrapper around `Input` with checkbox-specific guardrails.
18
19
  - The wrapper enforces checkbox type by default and narrows label position options to common checkbox layouts.
19
20
  - Controlled and uncontrolled patterns are both supported (`checked` + `onChange`, or `defaultChecked`).
21
+ - When `size` is provided, Checkbox sets a single `--checkbox-size` CSS variable inline; the checkbox box and checkmark scale via SCSS `calc()` from that variable (same pattern as `Button`'s `--btn-size` and `Toggle`'s `--toggle-width`).
20
22
 
21
23
  Example:
22
24
 
@@ -3,5 +3,6 @@ import { CheckboxLabelPosition } from '../../utilities/types';
3
3
  export type CheckboxProps = InputProps & {
4
4
  type?: "checkbox";
5
5
  labelPosition?: CheckboxLabelPosition;
6
+ size?: number;
6
7
  };
7
8
  export declare const Checkbox: React.FC<CheckboxProps>;
@@ -2,10 +2,17 @@
2
2
  import { Input as e } from "../Input/Input2.esm.js";
3
3
  import { jsx as t } from "react/jsx-runtime";
4
4
  //#region src/components/Checkbox/Checkbox.tsx
5
- var n = ({ type: n = "checkbox", labelPosition: r = "right", ...i }) => /* @__PURE__ */ t(e, {
6
- type: n,
7
- labelPosition: r,
8
- ...i
9
- });
5
+ var n = ({ type: n = "checkbox", labelPosition: r = "right", size: i, style: a, ...o }) => {
6
+ let s = typeof i == "number" ? Math.min(10, Math.max(.1, i)) : void 0;
7
+ return /* @__PURE__ */ t(e, {
8
+ type: n,
9
+ labelPosition: r,
10
+ style: {
11
+ ...s ? { "--checkbox-size": s } : void 0,
12
+ ...a
13
+ },
14
+ ...o
15
+ });
16
+ };
10
17
  //#endregion
11
18
  export { n as Checkbox };
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { isEmpty as e } from "../../utilities/validations.esm.js";
3
- import "../../utilities/types.esm.js";
4
3
  import { InputWrapper as t } from "./InputWrapper.esm.js";
4
+ import "../../utilities/types.esm.js";
5
5
  import n from "clsx";
6
6
  import { jsx as r, jsxs as i } from "react/jsx-runtime";
7
7
  import { useId as a } from "react";
@@ -12,7 +12,8 @@ Props:
12
12
  - `type?: "number"` (fixed, default: `"number"`)
13
13
  - `onDecrement?: (e: React.MouseEvent<HTMLButtonElement>) => void`
14
14
  - `onIncrement?: (e: React.MouseEvent<HTMLButtonElement>) => void`
15
- - `iconIncrement?: React.ReactNode` — overrides the icon rendered in **both** the decrement and increment buttons (there is no separate `iconDecrement` prop yet).
15
+ - `iconIncrement?: React.ReactNode` — overrides the icon rendered in the increment button.
16
+ - `iconDecrement?: React.ReactNode` — overrides the icon rendered in the decrement button.
16
17
 
17
18
  Behavior notes:
18
19
 
@@ -5,5 +5,6 @@ export type InputNumberProps = React.ComponentProps<"input"> & {} & Omit<InputPr
5
5
  onDecrement?: (e: React.MouseEvent<HTMLButtonElement>) => void;
6
6
  onIncrement?: (e: React.MouseEvent<HTMLButtonElement>) => void;
7
7
  iconIncrement?: React.ReactNode;
8
+ iconDecrement?: React.ReactNode;
8
9
  };
9
10
  export declare const InputNumber: React.FC<InputNumberProps>;
@@ -7,28 +7,28 @@ import { jsx as r } from "react/jsx-runtime";
7
7
  import { useRef as i } from "react";
8
8
  import { IoAddCircleOutline as a, IoRemoveCircleOutline as o } from "react-icons/io5";
9
9
  //#region src/components/InputNumber/InputNumber.tsx
10
- var s = ({ type: s = "number", className: c, iconIncrement: l, onDecrement: u, onIncrement: d, ...f }) => {
11
- let p = i(null);
10
+ var s = ({ type: s = "number", className: c, iconIncrement: l, iconDecrement: u, onDecrement: d, onIncrement: f, ...p }) => {
11
+ let m = i(null);
12
12
  return /* @__PURE__ */ r(t, {
13
- ref: p,
13
+ ref: m,
14
14
  className: n("inputNumber", c),
15
15
  preAdornment: /* @__PURE__ */ r(e, {
16
16
  variant: "text",
17
17
  onClick: (e) => {
18
- let t = p.current;
19
- t && (t.stepDown(), t.dispatchEvent(new Event("input", { bubbles: !0 }))), u?.(e);
18
+ let t = m.current;
19
+ t && (t.stepDown(), t.dispatchEvent(new Event("input", { bubbles: !0 }))), d?.(e);
20
20
  },
21
21
  children: l || /* @__PURE__ */ r(o, { size: "26" })
22
22
  }),
23
23
  endAdornment: /* @__PURE__ */ r(e, {
24
24
  variant: "text",
25
25
  onClick: (e) => {
26
- let t = p.current;
27
- t && (t.stepUp(), t.dispatchEvent(new Event("input", { bubbles: !0 }))), d?.(e);
26
+ let t = m.current;
27
+ t && (t.stepUp(), t.dispatchEvent(new Event("input", { bubbles: !0 }))), f?.(e);
28
28
  },
29
- children: l || /* @__PURE__ */ r(a, { size: "26" })
29
+ children: u || /* @__PURE__ */ r(a, { size: "26" })
30
30
  }),
31
- ...f,
31
+ ...p,
32
32
  type: s
33
33
  });
34
34
  };
@@ -0,0 +1,42 @@
1
+ # Notice — Agent Usage Notes
2
+
3
+ Import:
4
+
5
+ ```tsx
6
+ import { Notice } from "@stamcat/craftsman/Notice";
7
+ ```
8
+
9
+ Props:
10
+
11
+ - Inherits all native `<div>` props.
12
+ - `type?: "help" | "info" | "success" | "error" | "none"` (default: `"info"`; `"none"` hides the leading status icon container)
13
+ - `icon?: React.ReactNode` (overrides the default status icon for the given `type`)
14
+ - `title?: string | React.ReactNode`
15
+ - `message?: string | React.ReactNode`
16
+ - `children?: React.ReactNode` (rendered alongside `title`/`message`)
17
+ - `buttons?: React.ReactNode` (rendered in a footer action row)
18
+ - `dismissible?: boolean` (shows a close ("x") button)
19
+ - `visible?: boolean` (default: `true`; renders nothing when `false`)
20
+ - `onDismiss?: (id?: string) => void`
21
+ - `id?: string` (passed back to `onDismiss`)
22
+
23
+ Behavior notes:
24
+
25
+ - Notice is an inline, persistent alert banner — not a popup toast. For transient popup notifications use the existing `react-toastify` integration (see the "Molecules/Toast" story), not this component.
26
+ - Notice is not self-dismissing — the dismiss button only calls `onDismiss`; the parent owns visibility and must flip `visible` to `false` (or unmount) in response.
27
+ - `title` is wrapped in `<Text as="h5">` and `message` in `<Text as="span">` when passed as a string; `React.ReactNode` values are rendered as-is.
28
+ - The leading icon inherits its color via CSS (`currentColor`) from the `.notice.<type>` class — don't pass an explicit `fill`/`color` prop to override it, use `icon` to swap the element instead.
29
+
30
+ Example:
31
+
32
+ ```tsx
33
+ <Notice
34
+ type="error"
35
+ title="Something went wrong"
36
+ message="Please check the highlighted fields and try again."
37
+ dismissible
38
+ visible={visible}
39
+ onDismiss={() => setVisible(false)}
40
+ buttons={<Button variant="text" onClick={retry}>Retry</Button>}
41
+ />
42
+ ```
@@ -0,0 +1 @@
1
+ @layer craftsman-component{.notice{gap:calc(var(--w-gutter) * .5);padding:var(--w-gutter);border:1px solid var(--gray400);background-color:var(--white);border-left-width:3px;border-radius:4px;flex-direction:column;transition:opacity .5s ease-in-out;display:flex}.notice.info{border-color:var(--blue500);background-color:var(--blue50);color:var(--blue600)}.notice.success{border-color:var(--green500);background-color:var(--green50);border-color:var(--green500)}.notice.error{border-color:var(--red500);background-color:var(--red50);color:var(--red600)}.notice.help{border-color:var(--gray500);background-color:var(--gray50)}.notice button.text{color:inherit}.notice-contents{align-items:flex-start;gap:calc(var(--w-gutter) * .5);flex-flow:row;width:100%;display:flex}.notice-icon{flex:none;font-size:24px;display:flex}.notice-text{margin-top:calc(var(--w-gutter) * .25);flex-grow:1}.notice-text span{display:block}.notice-dismiss{flex:none;padding:0}.notice-buttons{justify-content:flex-end;gap:calc(var(--w-gutter) * .5);width:100%;display:flex}}
@@ -0,0 +1,13 @@
1
+ import { NoticeType } from '../../utilities/types';
2
+ export type NoticeProps = React.ComponentPropsWithoutRef<"div"> & {
3
+ type?: NoticeType;
4
+ icon?: React.ReactNode;
5
+ title?: string | React.ReactNode;
6
+ message?: string | React.ReactNode;
7
+ buttons?: React.ReactNode;
8
+ visible?: boolean;
9
+ dismissible?: boolean;
10
+ onDismiss?: (id?: string) => void;
11
+ id?: string;
12
+ };
13
+ export declare const Notice: React.FC<NoticeProps>;
@@ -0,0 +1,76 @@
1
+ @use "../../styles/utilities/_functions" as u;
2
+
3
+ @layer craftsman-component {
4
+ .notice {
5
+ transition: opacity 500ms ease-in-out;
6
+ display: flex;
7
+ flex-direction: column;
8
+ gap: #{u.width("gutter", 0.5)};
9
+ padding: #{u.width("gutter")};
10
+ border: 1px solid var(--gray400);
11
+ border-left-width: 3px;
12
+ background-color: var(--white);
13
+ border-radius: 4px;
14
+
15
+ &.info {
16
+ border-color: var(--blue500);
17
+ background-color: var(--blue50);
18
+ color: var(--blue600);
19
+ }
20
+
21
+ &.success {
22
+ border-color: var(--green500);
23
+ background-color: var(--green50);
24
+ border-color: var(--green500);
25
+ }
26
+
27
+ &.error {
28
+ border-color: var(--red500);
29
+ background-color: var(--red50);
30
+ color: var(--red600);
31
+ }
32
+
33
+ &.help {
34
+ border-color: var(--gray500);
35
+ background-color: var(--gray50);
36
+ }
37
+ button.text {
38
+ color: inherit;
39
+ }
40
+ }
41
+
42
+ .notice-contents {
43
+ display: flex;
44
+ flex-flow: row nowrap;
45
+ align-items: flex-start;
46
+ gap: #{u.width("gutter", 0.5)};
47
+ width: 100%;
48
+ }
49
+
50
+ .notice-icon {
51
+ display: flex;
52
+ flex: 0 0 auto;
53
+ font-size: 24px;
54
+ }
55
+
56
+ .notice-text {
57
+ flex-grow: 1;
58
+ margin-top: #{u.width("gutter", 0.25)};
59
+ span {
60
+ display: block;
61
+ }
62
+ }
63
+
64
+ .notice-dismiss {
65
+ flex: 0 0 auto;
66
+ padding: 0;
67
+ }
68
+
69
+ .notice-buttons {
70
+ width: 100%;
71
+ display: flex;
72
+ justify-content: flex-end;
73
+ gap: #{u.width("gutter", 0.5)};
74
+
75
+ }
76
+ }
@@ -0,0 +1,56 @@
1
+ "use client";
2
+ import { Button as e } from "../Button/Button.esm.js";
3
+ import { Text as t } from "../Text/Text2.esm.js";
4
+ import './Notice.css';/* empty css */
5
+ import n from "clsx";
6
+ import { Fragment as r, jsx as i, jsxs as a } from "react/jsx-runtime";
7
+ import { IoAlertCircleOutline as o, IoCheckmarkCircleOutline as s, IoCloseOutline as c, IoHelpCircleOutline as l, IoInformationCircleOutline as u } from "react-icons/io5";
8
+ //#region src/components/Notice/Notice.tsx
9
+ var d = {
10
+ info: /* @__PURE__ */ i(u, {}),
11
+ success: /* @__PURE__ */ i(s, {}),
12
+ error: /* @__PURE__ */ i(o, {}),
13
+ help: /* @__PURE__ */ i(l, {}),
14
+ none: /* @__PURE__ */ i(r, {})
15
+ }, f = (e, n) => typeof e == "string" ? /* @__PURE__ */ i(t, {
16
+ as: n,
17
+ children: e
18
+ }) : e, p = ({ type: t = "info", title: r, message: o, buttons: s, id: l, className: u, style: p, icon: m, children: h, dismissible: g, onDismiss: _, ...v }) => {
19
+ let y = () => {
20
+ _?.(l);
21
+ };
22
+ return /* @__PURE__ */ a("div", {
23
+ id: l,
24
+ className: n("notice", t, u),
25
+ style: p,
26
+ ...v,
27
+ children: [/* @__PURE__ */ a("div", {
28
+ className: "notice-contents",
29
+ children: [
30
+ t !== "none" && /* @__PURE__ */ i("div", {
31
+ className: "notice-icon",
32
+ children: m || d[t]
33
+ }),
34
+ /* @__PURE__ */ a("div", {
35
+ className: "notice-text",
36
+ children: [
37
+ r && f(r, "h5"),
38
+ o && f(o, "span"),
39
+ h
40
+ ]
41
+ }),
42
+ g && /* @__PURE__ */ i(e, {
43
+ variant: "text",
44
+ className: "notice-dismiss",
45
+ onClick: y,
46
+ children: /* @__PURE__ */ i(c, { size: 16 })
47
+ })
48
+ ]
49
+ }), s && /* @__PURE__ */ i("footer", {
50
+ className: "notice-buttons",
51
+ children: s
52
+ })]
53
+ });
54
+ };
55
+ //#endregion
56
+ export { p as Notice };
@@ -11,12 +11,14 @@ Props:
11
11
  - Extends `Input` props.
12
12
  - `type?: "radio"` (default: `"radio"`)
13
13
  - `labelPosition?: "left" | "right"` (default: `"right"`)
14
+ - `size?: number` (default visual scale is `1`, clamped to `[0.1, 10]`)
14
15
 
15
16
  Behavior notes:
16
17
 
17
18
  - `RadioButton` is a thin wrapper around `Input` with radio-specific guardrails.
18
19
  - Group behavior is native HTML radio behavior: use a shared `name` across options.
19
20
  - Controlled and uncontrolled patterns are both supported (`checked` + `onChange`, or `defaultChecked`).
21
+ - When `size` is provided, RadioButton sets a single `--radio-size` CSS variable inline; the radio circle and dot scale via SCSS `calc()` from that variable (same pattern as `Button`'s `--btn-size` and `Toggle`'s `--toggle-width`).
20
22
 
21
23
  Example:
22
24
 
@@ -3,6 +3,7 @@ import { InputProps } from '../Input/Input';
3
3
  type RadioButtonProps = InputProps & {
4
4
  type?: "radio";
5
5
  labelPosition?: RadioLabelPosition;
6
+ size?: number;
6
7
  };
7
8
  export declare const RadioButton: React.FC<RadioButtonProps>;
8
9
  export {};
@@ -2,10 +2,17 @@
2
2
  import { Input as e } from "../Input/Input2.esm.js";
3
3
  import { jsx as t } from "react/jsx-runtime";
4
4
  //#region src/components/RadioButton/RadioButton.tsx
5
- var n = ({ type: n = "radio", labelPosition: r = "right", ...i }) => /* @__PURE__ */ t(e, {
6
- type: n,
7
- labelPosition: r,
8
- ...i
9
- });
5
+ var n = ({ type: n = "radio", labelPosition: r = "right", size: i, style: a, ...o }) => {
6
+ let s = typeof i == "number" ? Math.min(10, Math.max(.1, i)) : void 0;
7
+ return /* @__PURE__ */ t(e, {
8
+ type: n,
9
+ labelPosition: r,
10
+ style: {
11
+ ...s ? { "--radio-size": s } : void 0,
12
+ ...a
13
+ },
14
+ ...o
15
+ });
16
+ };
10
17
  //#endregion
11
18
  export { n as RadioButton };
@@ -0,0 +1,45 @@
1
+ # SortableList — Agent Usage Notes
2
+
3
+ Import:
4
+
5
+ ```tsx
6
+ import { SortableList } from "@stamcat/craftsman/SortableList";
7
+ ```
8
+
9
+ Props:
10
+
11
+ - `items: T[]`
12
+ - `getKey: (item: T, index: number) => string`
13
+ - `renderItem: (args: SortableListRenderArgs<T>) => React.ReactNode`
14
+ - `onReorder: (items: T[]) => void`
15
+ - `disabled?: boolean`
16
+ - `className?: string`
17
+ - `style?: React.CSSProperties`
18
+
19
+ Behavior notes:
20
+
21
+ - Built on `@atlaskit/pragmatic-drag-and-drop`. The list only owns drag/drop wiring and reordering — all item markup comes from `renderItem`.
22
+ - `renderItem` receives `{ item, index, isDragging, dropEdge, dragHandleRef }`.
23
+ - By default the whole rendered item is the drag source.
24
+ - To restrict dragging to a handle, attach `dragHandleRef` to the handle element's `ref`.
25
+ - `dropEdge` is `"top" | "bottom" | null` while another item is dragged over this one — use it to render a drop indicator, or rely on the built-in `.drop-top` / `.drop-bottom` styles.
26
+ - `onReorder` is called with the full reordered array on drop; the component does not mutate `items` itself — update your own state in the callback.
27
+ - Set `disabled` to suspend all drag/drop wiring (for example while a related request is in flight).
28
+
29
+ Example:
30
+
31
+ ```tsx
32
+ const [items, setItems] = useState(["Alpha", "Beta", "Gamma"]);
33
+
34
+ <SortableList
35
+ items={items}
36
+ getKey={(item) => item}
37
+ onReorder={setItems}
38
+ renderItem={({ item, isDragging, dropEdge, dragHandleRef }) => (
39
+ <div className={isDragging ? "dragging" : undefined} data-drop-edge={dropEdge ?? undefined}>
40
+ <span ref={dragHandleRef}>⠿</span>
41
+ {item}
42
+ </div>
43
+ )}
44
+ />
45
+ ```
@@ -0,0 +1,10 @@
1
+ import { SortableListRenderArgs } from './SortableList';
2
+ export type DropEdge = "top" | "bottom";
3
+ export declare function SortableListItem<T>({ item, index, getKey, renderItem, disabled, listId, }: {
4
+ item: T;
5
+ index: number;
6
+ getKey: (item: T, index: number) => string;
7
+ renderItem: (args: SortableListRenderArgs<T>) => React.ReactNode;
8
+ disabled?: boolean;
9
+ listId: string;
10
+ }): import("react").JSX.Element;
@@ -0,0 +1,67 @@
1
+ "use client";
2
+ import { combine as e } from "../../../node_modules/@atlaskit/pragmatic-drag-and-drop/dist/esm/public-utils/combine.esm.js";
3
+ import { draggable as t, dropTargetForElements as n } from "../../../node_modules/@atlaskit/pragmatic-drag-and-drop/dist/esm/adapter/element-adapter.esm.js";
4
+ import { isItemData as r } from "./utilities.esm.js";
5
+ import i from "clsx";
6
+ import { jsx as a } from "react/jsx-runtime";
7
+ import { useEffect as o, useLayoutEffect as s, useRef as c, useState as l } from "react";
8
+ //#region src/components/SortableList/ListItem.tsx
9
+ function u({ item: u, index: d, getKey: f, renderItem: p, disabled: m, listId: h }) {
10
+ let [g, _] = l(null), [v, y] = l(null), [b, x] = l(!1), [S, C] = l(null), w = c(null), T = c(null), E = f(u, d);
11
+ return s(() => {
12
+ w.current = g;
13
+ let e = w.current;
14
+ if (!e) return;
15
+ let t = T.current, n = e.getBoundingClientRect();
16
+ T.current = n;
17
+ let r = t ? t.top - n.top : 0;
18
+ !r || window.matchMedia("(prefers-reduced-motion: reduce)").matches || (e.style.transition = "none", e.style.transform = `translateY(${r}px)`, requestAnimationFrame(() => {
19
+ e.style.transition = "", e.style.transform = "";
20
+ }));
21
+ }, [g, d]), o(() => {
22
+ if (!g || m) return;
23
+ let i = {
24
+ key: E,
25
+ index: d,
26
+ listId: h,
27
+ item: u
28
+ };
29
+ return e(t({
30
+ element: g,
31
+ dragHandle: v ?? void 0,
32
+ getInitialData: () => i,
33
+ onDragStart: () => x(!0),
34
+ onDrop: () => x(!1)
35
+ }), n({
36
+ element: g,
37
+ getData: () => i,
38
+ canDrop: ({ source: e }) => r(e.data) && e.data.key !== E,
39
+ onDrag: ({ location: e }) => {
40
+ let t = g.getBoundingClientRect(), n = e.current.input.clientY > t.top + t.height / 2;
41
+ C(n ? "bottom" : "top");
42
+ },
43
+ onDragLeave: () => C(null),
44
+ onDrop: () => C(null)
45
+ }));
46
+ }, [
47
+ g,
48
+ v,
49
+ E,
50
+ d,
51
+ m,
52
+ h,
53
+ u
54
+ ]), /* @__PURE__ */ a("li", {
55
+ ref: _,
56
+ className: i("sortable-list-item", b && "dragging", S && `drop-${S}`),
57
+ children: p({
58
+ item: u,
59
+ index: d,
60
+ isDragging: b,
61
+ dropEdge: S,
62
+ dragHandleRef: y
63
+ })
64
+ }, E);
65
+ }
66
+ //#endregion
67
+ export { u as SortableListItem };
@@ -0,0 +1 @@
1
+ @layer craftsman-component{.sortable-list{gap:calc(var(--w-gutter) * .25);flex-direction:column;margin:0;padding:0;list-style:none;display:flex}.sortable-list-item{cursor:grab;transition:transform .2s,opacity .15s;position:relative}.sortable-list-item.dragging{opacity:.4}.sortable-list-item.drop-top:before,.sortable-list-item.drop-bottom:after{content:"";background-color:var(--blue500);border-radius:1px;height:2px;position:absolute;left:0;right:0}.sortable-list-item.drop-top:before{top:-1px}.sortable-list-item.drop-bottom:after{bottom:-1px}}
@@ -0,0 +1,23 @@
1
+ import { default as React } from 'react';
2
+ import { DropEdge } from './ListItem';
3
+ export type SortableListItemState = {
4
+ isDragging: boolean;
5
+ dropEdge: DropEdge | null;
6
+ };
7
+ export type SortableListRenderArgs<T> = SortableListItemState & {
8
+ dragHandleRef: (element: HTMLElement | null) => void;
9
+ item: T;
10
+ index: number;
11
+ };
12
+ export type SortableListProps<T> = {
13
+ items: T[];
14
+ getKey: (item: T, index: number) => string;
15
+ renderItem: (args: SortableListRenderArgs<T>) => React.ReactNode;
16
+ onReorder: (items: T[]) => void;
17
+ disabled?: boolean;
18
+ className?: string;
19
+ style?: React.CSSProperties;
20
+ listId?: string;
21
+ onReceive?: (item: T, atIndex: number) => void;
22
+ };
23
+ export declare const SortableList: <T>({ items, getKey, renderItem, onReorder, disabled, className, style, listId, onReceive }: SortableListProps<T>) => React.JSX.Element;
@@ -0,0 +1,41 @@
1
+ @use "../../styles/utilities/_functions" as u;
2
+
3
+ @layer craftsman-component {
4
+ .sortable-list {
5
+ display: flex;
6
+ flex-direction: column;
7
+ gap: #{u.width("gutter", 0.25)};
8
+ margin: 0;
9
+ padding: 0;
10
+ list-style: none;
11
+ }
12
+
13
+ .sortable-list-item {
14
+ position: relative;
15
+ cursor: grab;
16
+ transition: transform 200ms ease, opacity 150ms ease;
17
+
18
+ &.dragging {
19
+ opacity: 0.4;
20
+ }
21
+
22
+ &.drop-top::before,
23
+ &.drop-bottom::after {
24
+ content: "";
25
+ position: absolute;
26
+ left: 0;
27
+ right: 0;
28
+ height: 2px;
29
+ border-radius: 1px;
30
+ background-color: #{u.color("blue500")};
31
+ }
32
+
33
+ &.drop-top::before {
34
+ top: -1px;
35
+ }
36
+
37
+ &.drop-bottom::after {
38
+ bottom: -1px;
39
+ }
40
+ }
41
+ }
@@ -0,0 +1,54 @@
1
+ "use client";
2
+ import { monitorForElements as e } from "../../../node_modules/@atlaskit/pragmatic-drag-and-drop/dist/esm/adapter/element-adapter.esm.js";
3
+ import { reorder as t } from "../../../node_modules/@atlaskit/pragmatic-drag-and-drop/dist/esm/public-utils/reorder.esm.js";
4
+ import './SortableList.css';/* empty css */
5
+ import { isItemData as n } from "./utilities.esm.js";
6
+ import { SortableListItem as r } from "./ListItem.esm.js";
7
+ import i from "clsx";
8
+ import { jsx as a } from "react/jsx-runtime";
9
+ import { useEffect as o, useId as s } from "react";
10
+ //#region src/components/SortableList/SortableList.tsx
11
+ var c = ({ items: c, getKey: l, renderItem: u, onReorder: d, disabled: f, className: p, style: m, listId: h, onReceive: g }) => {
12
+ let _ = s(), v = h ?? _, y = (e, n) => {
13
+ let r = c.findIndex((t, n) => l(t, n) === e), i = c.findIndex((e, t) => l(e, t) === n);
14
+ r === -1 || i === -1 || r === i || d(t({
15
+ list: c,
16
+ startIndex: r,
17
+ finishIndex: i
18
+ }));
19
+ }, b = (e) => {
20
+ let t = c.findIndex((t, n) => l(t, n) === e);
21
+ t !== -1 && d(c.filter((e, n) => n !== t));
22
+ }, x = (e, t) => {
23
+ let n = c.findIndex((e, n) => l(e, n) === t);
24
+ g?.(e, n === -1 ? c.length : n);
25
+ };
26
+ return o(() => {
27
+ if (!f) return e({ onDrop: ({ source: e, location: t }) => {
28
+ let r = t.current.dropTargets[0];
29
+ if (!r || !n(e.data) || !n(r.data)) return;
30
+ let i = e.data.listId, a = r.data.listId, o = i === v, s = a === v;
31
+ o && s ? y(e.data.key, r.data.key) : o ? b(e.data.key) : s && g && x(e.data.item, r.data.key);
32
+ } });
33
+ }, [
34
+ c,
35
+ l,
36
+ d,
37
+ f,
38
+ v,
39
+ g
40
+ ]), /* @__PURE__ */ a("ul", {
41
+ className: i("sortable-list", p),
42
+ style: m,
43
+ children: c.map((e, t) => /* @__PURE__ */ a(r, {
44
+ item: e,
45
+ index: t,
46
+ getKey: l,
47
+ renderItem: u,
48
+ disabled: f,
49
+ listId: v
50
+ }, l(e, t)))
51
+ });
52
+ };
53
+ //#endregion
54
+ export { c as SortableList };
@@ -0,0 +1,7 @@
1
+ export type ItemData = {
2
+ key: string;
3
+ index: number;
4
+ listId: string;
5
+ item: unknown;
6
+ };
7
+ export declare const isItemData: (data: Record<string | symbol, unknown>) => data is ItemData;
@@ -0,0 +1,4 @@
1
+ //#region src/components/SortableList/utilities.ts
2
+ var e = (e) => typeof e.key == "string" && typeof e.index == "number" && typeof e.listId == "string";
3
+ //#endregion
4
+ export { e as isItemData };
@@ -1 +1 @@
1
- @layer craftsman-base{h1{font-size:calc(var(--w-text) * 3.125);line-height:1.2}h2{font-size:calc(var(--w-text) * 2.625);font-weight:625;line-height:1.1}h3{font-size:calc(var(--w-text) * 1.625);line-height:1.1}h4{font-size:calc(var(--w-text) * 1.25);margin:calc(var(--w-gutter) * .5) 0;line-height:1.1}h5{font-size:var(--w-text);line-height:1.2}h6{font-size:calc(var(--w-text) * .875);font-weight:600;line-height:1.2}p{font-style:normal;font-size:var(--w-text);margin:0;line-height:1.5}small{font-size:calc(var(--w-text) * .75)}@media (width<=660px){h4{font-size:var(--w-text,14px)}p{font-size:calc(var(--w-text,14px) * .875)}}}@layer craftsman-component{.text.display{font-size:calc(var(--w-text) * 1.625);line-height:1.1}.text.display.xlarge{font-size:calc(var(--w-text) * 3.125);line-height:1.2}.text.display.large{font-size:calc(var(--w-text) * 2.625);font-weight:625;line-height:1.1}.text.display.small{font-size:calc(var(--w-text) * 1.25);margin:calc(var(--w-gutter) * .5) 0;line-height:1.1}.text.heading{font-size:calc(var(--w-text) * 1.625);line-height:1.1}.text.heading.xlarge{font-size:calc(var(--w-text) * 3.125);line-height:1.2}.text.heading.large,.text.xlarge{font-size:calc(var(--w-text) * 2.625);font-weight:625;line-height:1.1}.text.heading.medium{font-size:calc(var(--w-text) * 1.625);line-height:1.1}.text.heading.small{font-size:calc(var(--w-text) * 1.25);margin:calc(var(--w-gutter) * .5) 0;line-height:1.1}.text.heading.xsmall{font-size:var(--w-text);line-height:1.2}.text.paragraph{font-style:normal;font-size:var(--w-text);margin:0;line-height:1.5}.text.paragraph.xlarge,.text.large{font-size:calc(var(--w-text) * 1.625);line-height:1.1}.text.paragraph.large{font-size:calc(var(--w-text) * 1.25);margin:calc(var(--w-gutter) * .5) 0;line-height:1.1}.text.paragraph.medium,.text.medium{font-style:normal;font-size:var(--w-text);margin:0;line-height:1.5}.text.paragraph.small,.text.small{font-size:calc(var(--w-text) * .75)}.text.paragraph.xsmall,.text.xsmall{font-size:calc(var(--w-text) * .5)}.text.caption{font-size:calc(var(--w-text) * .75)}.text.center{text-align:center}.text.left{text-align:left}.text.right{text-align:right}}
1
+ @layer craftsman-base{h1{font-size:calc(var(--w-text) * 3.125);margin:0 0 var(--w-gutter) 0;line-height:1.2}h2{font-size:calc(var(--w-text) * 2.625);margin:0 0 var(--w-gutter) 0;font-weight:625;line-height:1.1}h3{font-size:calc(var(--w-text) * 1.625);margin:0 0 calc(var(--w-gutter) * .75) 0;line-height:1.1}h4{font-size:calc(var(--w-text) * 1.25);margin:0 0 calc(var(--w-gutter) * .5) 0;line-height:1.1}h5{font-size:var(--w-text);margin:0 0 calc(var(--w-gutter) * .5) 0;line-height:1.2}h6{font-size:calc(var(--w-text) * .875);margin:0;font-weight:600;line-height:1.2}p{font-style:normal;font-size:var(--w-text);margin:0;line-height:1.5}small{font-size:calc(var(--w-text) * .75)}@media (width<=660px){h4{font-size:var(--w-text,14px)}p{font-size:calc(var(--w-text,14px) * .875)}}}@layer craftsman-component{.text.display{font-size:calc(var(--w-text) * 1.625);margin:0 0 calc(var(--w-gutter) * .75) 0;line-height:1.1}.text.display.xlarge{font-size:calc(var(--w-text) * 3.125);margin:0 0 var(--w-gutter) 0;line-height:1.2}.text.display.large{font-size:calc(var(--w-text) * 2.625);margin:0 0 var(--w-gutter) 0;font-weight:625;line-height:1.1}.text.display.small{font-size:calc(var(--w-text) * 1.25);margin:0 0 calc(var(--w-gutter) * .5) 0;line-height:1.1}.text.heading{font-size:calc(var(--w-text) * 1.625);margin:0 0 calc(var(--w-gutter) * .75) 0;line-height:1.1}.text.heading.xlarge{font-size:calc(var(--w-text) * 3.125);margin:0 0 var(--w-gutter) 0;line-height:1.2}.text.heading.large,.text.xlarge{font-size:calc(var(--w-text) * 2.625);margin:0 0 var(--w-gutter) 0;font-weight:625;line-height:1.1}.text.heading.medium{font-size:calc(var(--w-text) * 1.625);margin:0 0 calc(var(--w-gutter) * .75) 0;line-height:1.1}.text.heading.small{font-size:calc(var(--w-text) * 1.25);margin:0 0 calc(var(--w-gutter) * .5) 0;line-height:1.1}.text.heading.xsmall{font-size:var(--w-text);margin:0 0 calc(var(--w-gutter) * .5) 0;line-height:1.2}.text.paragraph{font-style:normal;font-size:var(--w-text);margin:0;line-height:1.5}.text.paragraph.xlarge,.text.large{font-size:calc(var(--w-text) * 1.625);margin:0 0 calc(var(--w-gutter) * .75) 0;line-height:1.1}.text.paragraph.large{font-size:calc(var(--w-text) * 1.25);margin:0 0 calc(var(--w-gutter) * .5) 0;line-height:1.1}.text.paragraph.medium,.text.medium{font-style:normal;font-size:var(--w-text);margin:0;line-height:1.5}.text.paragraph.small,.text.small{font-size:calc(var(--w-text) * .75)}.text.paragraph.xsmall,.text.xsmall{font-size:calc(var(--w-text) * .5)}.text.caption{font-size:calc(var(--w-text) * .75)}.text.center{text-align:center}.text.left{text-align:left}.text.right{text-align:right}}
@@ -0,0 +1,33 @@
1
+ # Toggle — Agent Usage Notes
2
+
3
+ Import:
4
+
5
+ ```tsx
6
+ import { Toggle } from "@stamcat/craftsman/Toggle";
7
+ ```
8
+
9
+ Props:
10
+
11
+ - Extends `Input` props, excluding `type`, `preAdornment`, and `endAdornment` (all internally managed).
12
+ - `width?: number` — pixel width of the switch track (default: `40`). Track height, thumb size, and thumb travel all derive from this via `calc()`.
13
+ - `label?: string | ReactNode`, `labelPosition?: "top" | "left" | "bottom" | "right" | "inside" | "hidden"` (default: `"right"`), `error?`, `required?` — same as `Input`.
14
+
15
+ Behavior notes:
16
+
17
+ - `Toggle` is `<Input type="checkbox">` under the hood — it is a real, keyboard-accessible checkbox styled as a switch, not a custom widget.
18
+ - `width` sets a single `--toggle-width` CSS variable inline; the track, thumb, and checked-state translation are all `calc()`-derived from it in `Toggle.scss` (the same sizing pattern used by `Button`'s `--btn-size`, `Checkbox`'s `--checkbox-size`, and `RadioButton`'s `--radio-size`).
19
+ - The underlying checkbox input is stretched invisibly over the full switch (`opacity: 0`) so it stays the real click/keyboard target; the visual slider is rendered via `endAdornment` with `pointer-events: none`.
20
+ - Controlled and uncontrolled patterns are both supported (`checked` + `onChange`, or `defaultChecked`).
21
+
22
+ Example:
23
+
24
+ ```tsx
25
+ const [enabled, setEnabled] = useState(false);
26
+
27
+ <Toggle
28
+ label="Enable notifications"
29
+ width={48}
30
+ checked={enabled}
31
+ onChange={(event) => setEnabled(event.currentTarget.checked)}
32
+ />
33
+ ```
@@ -0,0 +1 @@
1
+ @layer craftsman-component{.input-wrapper.toggle>label{align-items:center;gap:calc(var(--w-gutter) * .5);display:inline-flex}.input-wrapper.toggle .input-field{width:var(--toggle-width,60px);height:calc(var(--toggle-width,60px) * .56);position:relative}.input-wrapper.toggle .input.checkbox{opacity:0;cursor:pointer;z-index:1;width:100%;height:100%;margin:0;position:absolute;inset:0}.input-wrapper.toggle .input-end-adornment{position:absolute;inset:0;transform:none}.input-wrapper.toggle .toggle-slider{pointer-events:none;background-color:var(--gray400);border-radius:calc(var(--toggle-width,60px) * .56);transition:background-color .2s;position:absolute;inset:0}.input-wrapper.toggle .toggle-slider:before{content:"";left:calc(var(--toggle-width,60px) * .065);bottom:calc(var(--toggle-width,60px) * .065);height:calc(var(--toggle-width,60px) * .43);width:calc(var(--toggle-width,60px) * .43);background-color:var(--white);border-radius:50%;transition:transform .2s;position:absolute}.input-wrapper.toggle .input.checkbox:checked+.input-end-adornment .toggle-slider{background-color:var(--blue500)}.input-wrapper.toggle .input.checkbox:checked+.input-end-adornment .toggle-slider:before{transform:translateX(calc(var(--toggle-width,60px) * .43))}}
@@ -0,0 +1,5 @@
1
+ import { InputProps } from '../Input/Input';
2
+ export type ToggleProps = Omit<InputProps, "type" | "preAdornment" | "endAdornment"> & {
3
+ width?: number;
4
+ };
5
+ export declare const Toggle: React.FC<ToggleProps>;
@@ -0,0 +1,64 @@
1
+ @use "../../styles/utilities/_functions" as u;
2
+
3
+ @layer craftsman-component {
4
+ .input-wrapper.toggle {
5
+ > label {
6
+ display: inline-flex;
7
+ align-items: center;
8
+ gap: #{u.width("gutter", 0.5)};
9
+ }
10
+
11
+ .input-field {
12
+ position: relative;
13
+ width: var(--toggle-width, 60px);
14
+ height: calc(var(--toggle-width, 60px) * 0.56);
15
+ }
16
+
17
+ .input.checkbox {
18
+ position: absolute;
19
+ inset: 0;
20
+ width: 100%;
21
+ height: 100%;
22
+ margin: 0;
23
+ opacity: 0;
24
+ cursor: pointer;
25
+ z-index: 1;
26
+ }
27
+
28
+ .input-end-adornment {
29
+ position: absolute;
30
+ inset: 0;
31
+ top: 0;
32
+ transform: none;
33
+ }
34
+
35
+ .toggle-slider {
36
+ position: absolute;
37
+ inset: 0;
38
+ pointer-events: none;
39
+ background-color: var(--gray400);
40
+ border-radius: calc(var(--toggle-width, 60px) * 0.56);
41
+ transition: background-color 0.2s ease;
42
+
43
+ &::before {
44
+ position: absolute;
45
+ content: "";
46
+ left: calc(var(--toggle-width, 60px) * 0.065);
47
+ bottom: calc(var(--toggle-width, 60px) * 0.065);
48
+ height: calc(var(--toggle-width, 60px) * 0.43);
49
+ width: calc(var(--toggle-width, 60px) * 0.43);
50
+ border-radius: 50%;
51
+ background-color: var(--white);
52
+ transition: transform 0.2s ease;
53
+ }
54
+ }
55
+
56
+ .input.checkbox:checked + .input-end-adornment .toggle-slider {
57
+ background-color: var(--blue500);
58
+
59
+ &::before {
60
+ transform: translateX(calc(var(--toggle-width, 60px) * 0.43));
61
+ }
62
+ }
63
+ }
64
+ }
@@ -0,0 +1,19 @@
1
+ "use client";
2
+ import { Input as e } from "../Input/Input2.esm.js";
3
+ import './Toggle.css';/* empty css */
4
+ import t from "clsx";
5
+ import { jsx as n } from "react/jsx-runtime";
6
+ //#region src/components/Toggle/Toggle.tsx
7
+ var r = ({ labelPosition: r = "right", className: i, style: a, width: o = 40, ...s }) => /* @__PURE__ */ n(e, {
8
+ type: "checkbox",
9
+ labelPosition: r,
10
+ className: t("toggle", i),
11
+ endAdornment: /* @__PURE__ */ n("span", { className: "toggle-slider" }),
12
+ style: {
13
+ ...a,
14
+ "--toggle-width": `${o}px`
15
+ },
16
+ ...s
17
+ });
18
+ //#endregion
19
+ export { r as Toggle };
@@ -12,9 +12,12 @@ export { DatePicker } from './DatePicker/DatePicker';
12
12
  export { DateRangePicker } from './DateRangePicker/DateRangePicker';
13
13
  export { InputPhone } from './InputPhone/InputPhone';
14
14
  export { InputNumber } from './InputNumber/InputNumber';
15
+ export { Toggle } from './Toggle/Toggle';
15
16
  export { Pagination } from './Pagination/Pagination';
16
17
  export { Carousel } from './Carousel/Carousel';
17
18
  export { TimePicker } from './TimePicker/TimePicker';
18
19
  export { DateTimePicker } from './DateTimePicker/DateTimePicker';
19
20
  export { Tooltip } from './Tooltip/Tooltip';
21
+ export { Notice } from './Notice/Notice';
22
+ export { SortableList } from './SortableList/SortableList';
20
23
  export * from './Icons';
@@ -5,13 +5,11 @@ import { Meta } from "@storybook/addon-docs/blocks";
5
5
  # Global Styles
6
6
  - video
7
7
  - image
8
- - Input - toggle (boolean)
9
8
  - radio button alignment to baseline
10
9
  - implement dark mode @media (prefers-color-scheme: dark)
11
10
  - Accordion
12
- - Notification
13
11
  - Progress
14
12
  - Skeleton
15
13
  - Toast - enhance to show pile vs stacking
16
14
  - Tabs
17
- - InputCreditCard - should have CC checksum validations
15
+ - sortable list
@@ -20,9 +20,7 @@
20
20
  }
21
21
 
22
22
  %button-styles {
23
- --btn-pad-y: #{u.width(gutter, 0.5)};
24
- --btn-pad-x: #{u.width(gutter, 0.75)};
25
- --btn-border-radius: #{u.width(gutter, 0.75)};
23
+ --btn-size: 1;
26
24
  color: var(--blue600);
27
25
  border: none;
28
26
  cursor: pointer;
@@ -31,8 +29,9 @@
31
29
  align-items: center;
32
30
  font-weight: 500;
33
31
  transition: 0.125s;
34
- padding: var(--btn-pad-y) var(--btn-pad-x);
35
- border-radius: var(--btn-border-radius);
32
+ padding: calc(#{u.width(gutter, 0.5)} * var(--btn-size)) calc(#{u.width(gutter, 0.75)} * var(--btn-size));
33
+ border-radius: calc(#{u.width(gutter, 0.75)} * var(--btn-size));
34
+ font-size: max(10px, calc(#{u.width(text)} * var(--btn-size)));
36
35
  border: 1px solid var(--blue500);
37
36
  background-color: var(--white);
38
37
 
@@ -10,8 +10,9 @@
10
10
  top: 0.08em;
11
11
  margin: 0;
12
12
  padding: 0;
13
- height: #{u.width("gutter")};
14
- width: #{u.width("gutter")};
13
+ --checkbox-size: 1;
14
+ height: calc(#{u.width("gutter")} * var(--checkbox-size));
15
+ width: calc(#{u.width("gutter")} * var(--checkbox-size));
15
16
  border-radius: 4px;
16
17
  border: 1px solid var(--blue500);
17
18
  background: #fff;
@@ -29,8 +30,8 @@
29
30
  position: absolute;
30
31
  left: 50%;
31
32
  top: 45%;
32
- width: 5px;
33
- height: 8px;
33
+ width: calc(5px * var(--checkbox-size));
34
+ height: calc(8px * var(--checkbox-size));
34
35
  content: "";
35
36
  display: block;
36
37
  border: solid white;
@@ -9,16 +9,17 @@
9
9
  display: inline-grid;
10
10
  place-content: center;
11
11
  padding: 0;
12
- width: #{u.width("gutter")};
13
- height: #{u.width("gutter")};
12
+ --radio-size: 1;
13
+ width: calc(#{u.width("gutter")} * var(--radio-size));
14
+ height: calc(#{u.width("gutter")} * var(--radio-size));
14
15
  border: 1px solid var(--blue600);
15
16
  border-radius: 50%;
16
17
  box-sizing: border-box;
17
18
 
18
19
  &::before {
19
20
  content: "";
20
- width: #{u.width("gutter", 0.5)};
21
- height: #{u.width("gutter", 0.5)};
21
+ width: calc(#{u.width("gutter", 0.5)} * var(--radio-size));
22
+ height: calc(#{u.width("gutter", 0.5)} * var(--radio-size));
22
23
  border-radius: 50%;
23
24
  transform: scale(0);
24
25
  transition: transform 0.2s ease;
@@ -11,29 +11,34 @@
11
11
  @mixin h1 {
12
12
  font-size: #{u.width(text, 3.125)};
13
13
  line-height: 1.2;
14
+ margin: 0 0 #{u.width(gutter)} 0;
14
15
  }
15
16
  @mixin h2 {
16
17
  font-size: #{u.width(text, 2.625)};
17
18
  font-weight: 625;
18
19
  line-height: 1.1;
20
+ margin: 0 0 #{u.width(gutter)} 0;
19
21
  }
20
22
  @mixin h3 {
21
23
  font-size: #{u.width(text, 1.625)};
22
24
  line-height: 1.1;
25
+ margin: 0 0 #{u.width(gutter, 0.75)} 0;
23
26
  }
24
27
  @mixin h4 {
25
28
  font-size: #{u.width(text, 1.25)};
26
29
  line-height: 1.1;
27
- margin: #{u.width(gutter, 0.5)} 0;
30
+ margin: 0 0 #{u.width(gutter, 0.5)} 0;
28
31
  }
29
32
  @mixin h5 {
30
33
  font-size: var(--w-text);
31
34
  line-height: 1.2;
35
+ margin: 0 0 #{u.width(gutter, 0.5)} 0;
32
36
  }
33
37
  @mixin h6 {
34
38
  font-size: #{u.width(text, 0.875)};
35
39
  line-height: 1.2;
36
40
  font-weight: 600;
41
+ margin: 0;
37
42
  }
38
43
  @mixin p {
39
44
  font-style: normal;
@@ -39,7 +39,9 @@
39
39
  margin: 0;
40
40
  padding: 0;
41
41
  }
42
-
42
+ ul {
43
+ list-style: none;
44
+ }
43
45
  body {
44
46
  @include t.body-typography;
45
47
  background-color: #fff;
@@ -133,3 +133,11 @@ export declare const CarouselPageType: z.ZodEnum<{
133
133
  numbers: "numbers";
134
134
  }>;
135
135
  export type CarouselPageType = z.infer<typeof CarouselPageType>;
136
+ export declare const NoticeType: z.ZodEnum<{
137
+ help: "help";
138
+ info: "info";
139
+ success: "success";
140
+ error: "error";
141
+ none: "none";
142
+ }>;
143
+ export type NoticeType = z.infer<typeof NoticeType>;
@@ -74,6 +74,12 @@ var t = e.enum(["gutter", "column"]), n = e.enum([
74
74
  "medium",
75
75
  "small",
76
76
  "xsmall"
77
- ]), g = e.enum(["dots", "numbers"]);
77
+ ]), g = e.enum(["dots", "numbers"]), _ = e.enum([
78
+ "help",
79
+ "info",
80
+ "success",
81
+ "error",
82
+ "none"
83
+ ]);
78
84
  //#endregion
79
- export { t as BaseWidthSchema, i as BreakpointSchema, f as ButtonType, g as CarouselPageType, a as LayoutWidthsSchema, r as MaxScreenWidthSchema, n as ScreenWidthSchema, h as TextSize, p as TextTags, m as TextType, u as zCheckboxLabelPosition, l as zLabelPosition, d as zRadioLabelPosition, o as zTextInputExclusions, c as zTextInputType, s as zTextInputTypes };
85
+ export { t as BaseWidthSchema, i as BreakpointSchema, f as ButtonType, g as CarouselPageType, a as LayoutWidthsSchema, r as MaxScreenWidthSchema, _ as NoticeType, n as ScreenWidthSchema, h as TextSize, p as TextTags, m as TextType, u as zCheckboxLabelPosition, l as zLabelPosition, d as zRadioLabelPosition, o as zTextInputExclusions, c as zTextInputType, s as zTextInputTypes };