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

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 (200) hide show
  1. package/AGENTS.md +16 -344
  2. package/Components.esm.js +66 -11
  3. package/README.md +5 -0
  4. package/Styles.esm.js +7 -7
  5. package/Utilities.esm.js +2 -2
  6. package/_virtual/_rolldown/runtime.esm.js +18 -6
  7. package/package.json +62 -6
  8. package/src/components/Button/AGENTS.md +64 -0
  9. package/src/components/{Button.d.ts → Button/Button.d.ts} +1 -1
  10. package/src/components/Button/Button.esm.js +25 -0
  11. package/src/components/Carousel/AGENTS.md +41 -0
  12. package/src/components/Carousel/Carousel.css +1 -0
  13. package/src/components/Carousel/Carousel.d.ts +11 -0
  14. package/src/components/Carousel/Carousel.scss +34 -0
  15. package/src/components/Carousel/Carousel2.esm.js +75 -0
  16. package/src/components/Checkbox/AGENTS.md +32 -0
  17. package/src/components/Checkbox/Checkbox.d.ts +7 -0
  18. package/src/components/{Checkbox.esm.js → Checkbox/Checkbox.esm.js} +2 -2
  19. package/src/components/DatePicker/AGENTS.md +36 -0
  20. package/src/components/DatePicker/DatePicker.css +1 -0
  21. package/src/components/DatePicker/DatePicker.d.ts +8 -0
  22. package/src/components/DatePicker/DatePicker.scss +61 -0
  23. package/src/components/DatePicker/DatePicker2.esm.js +29 -0
  24. package/src/components/DatePicker/ReactCalendar.css +1 -0
  25. package/src/components/DatePicker/ReactCalendar.scss +158 -0
  26. package/src/components/DatePicker/_DatePicker.scss +73 -0
  27. package/src/components/DateRangePicker/AGENTS.md +38 -0
  28. package/src/components/DateRangePicker/DateRangePicker.css +1 -0
  29. package/src/components/DateRangePicker/DateRangePicker.d.ts +8 -0
  30. package/src/components/DateRangePicker/DateRangePicker.scss +62 -0
  31. package/src/components/DateRangePicker/DateRangePicker2.esm.js +29 -0
  32. package/src/components/DateTimePicker/AGENTS.md +41 -0
  33. package/src/components/DateTimePicker/DateTimePicker.css +1 -0
  34. package/src/components/DateTimePicker/DateTimePicker.d.ts +13 -0
  35. package/src/components/DateTimePicker/DateTimePicker.scss +86 -0
  36. package/src/components/DateTimePicker/DateTimePicker2.esm.js +82 -0
  37. package/src/components/Icons/IconAmazonPay.d.ts +2 -0
  38. package/src/components/Icons/IconAmazonPay.esm.js +76 -0
  39. package/src/components/Icons/IconAmex.d.ts +2 -0
  40. package/src/components/Icons/IconAmex.esm.js +87 -0
  41. package/src/components/Icons/IconApplePay.d.ts +2 -0
  42. package/src/components/Icons/IconApplePay.esm.js +26 -0
  43. package/src/components/Icons/IconDiscover.d.ts +2 -0
  44. package/src/components/Icons/IconDiscover.esm.js +129 -0
  45. package/src/components/Icons/IconGooglePay.d.ts +2 -0
  46. package/src/components/Icons/IconGooglePay.esm.js +64 -0
  47. package/src/components/Icons/IconMaestro.d.ts +2 -0
  48. package/src/components/Icons/IconMaestro.esm.js +38 -0
  49. package/src/components/Icons/IconMastercard.d.ts +2 -0
  50. package/src/components/Icons/IconMastercard.esm.js +27 -0
  51. package/src/components/Icons/IconPayPal.d.ts +2 -0
  52. package/src/components/Icons/IconPayPal.esm.js +52 -0
  53. package/src/components/Icons/IconSepa.d.ts +2 -0
  54. package/src/components/Icons/IconSepa.esm.js +272 -0
  55. package/src/components/Icons/IconShopPay.d.ts +2 -0
  56. package/src/components/Icons/IconShopPay.esm.js +35 -0
  57. package/src/components/Icons/IconSquare.d.ts +2 -0
  58. package/src/components/Icons/IconSquare.esm.js +11 -0
  59. package/src/components/Icons/IconStripe.d.ts +2 -0
  60. package/src/components/Icons/IconStripe.esm.js +57 -0
  61. package/src/components/Icons/IconUnionPay.d.ts +2 -0
  62. package/src/components/Icons/IconUnionPay.esm.js +28 -0
  63. package/src/components/Icons/IconVenmo.d.ts +2 -0
  64. package/src/components/Icons/IconVenmo.esm.js +21 -0
  65. package/src/components/Icons/IconVisa.d.ts +2 -0
  66. package/src/components/Icons/IconVisa.esm.js +14 -0
  67. package/src/components/Icons/index.d.ts +15 -0
  68. package/src/components/Icons/index.esm.js +16 -0
  69. package/src/components/Icons/types.d.ts +4 -0
  70. package/src/components/Input/AGENTS.md +30 -0
  71. package/src/components/Input/Input.css +1 -0
  72. package/src/components/Input/Input.d.ts +6 -0
  73. package/src/components/Input/Input.scss +176 -0
  74. package/src/components/Input/Input2.esm.js +42 -0
  75. package/src/components/Input/InputWrapper.d.ts +11 -0
  76. package/src/components/Input/InputWrapper.esm.js +22 -0
  77. package/src/components/InputNumber/AGENTS.md +36 -0
  78. package/src/components/InputNumber/InputNumber.css +1 -0
  79. package/src/components/InputNumber/InputNumber.d.ts +9 -0
  80. package/src/components/InputNumber/InputNumber.scss +29 -0
  81. package/src/components/InputNumber/InputNumber2.esm.js +36 -0
  82. package/src/components/InputPassword/AGENTS.md +29 -0
  83. package/src/components/{InputPassword.d.ts → InputPassword/InputPassword.d.ts} +2 -2
  84. package/src/components/InputPassword/InputPassword.esm.js +30 -0
  85. package/src/components/InputPhone/AGENTS.md +35 -0
  86. package/src/components/InputPhone/InputPhone.css +1 -0
  87. package/src/components/InputPhone/InputPhone.d.ts +7 -0
  88. package/src/components/InputPhone/InputPhone.scss +266 -0
  89. package/src/components/InputPhone/InputPhone2.esm.js +27 -0
  90. package/src/components/Loader/AGENTS.md +31 -0
  91. package/src/components/{Loader.d.ts → Loader/Loader.d.ts} +1 -2
  92. package/src/components/Loader/Loader.esm.js +19 -0
  93. package/src/components/Loader/loaders.module.css +1 -0
  94. package/src/components/Loader/loaders.module.esm.js +21 -0
  95. package/src/{styles/global/components → components/Loader}/loaders.module.scss +2 -1
  96. package/src/components/Modal/AGENTS.md +47 -0
  97. package/src/components/Modal/Modal.css +1 -0
  98. package/src/components/{Modal.d.ts → Modal/Modal.d.ts} +0 -1
  99. package/src/components/Modal/Modal.scss +150 -0
  100. package/src/components/Modal/Modal2.esm.js +53 -0
  101. package/src/components/Pagination/AGENTS.md +38 -0
  102. package/src/components/Pagination/Pagination.css +1 -0
  103. package/src/components/Pagination/Pagination.d.ts +10 -0
  104. package/src/components/Pagination/Pagination.scss +22 -0
  105. package/src/components/Pagination/Pagination2.esm.js +64 -0
  106. package/src/components/RadioButton/AGENTS.md +42 -0
  107. package/src/components/RadioButton/RadioButton.d.ts +8 -0
  108. package/src/components/{RadioButton.esm.js → RadioButton/RadioButton.esm.js} +2 -2
  109. package/src/components/Select/AGENTS.md +36 -0
  110. package/src/components/Select/Select.d.ts +14 -0
  111. package/src/components/Select/Select.esm.js +26 -0
  112. package/src/components/Text/AGENTS.md +32 -0
  113. package/src/components/Text/Text.css +1 -0
  114. package/src/components/Text/Text.d.ts +10 -0
  115. package/src/components/Text/Text.scss +80 -0
  116. package/src/components/Text/Text2.esm.js +23 -0
  117. package/src/components/Textarea/AGENTS.md +32 -0
  118. package/src/components/Textarea/Textarea.d.ts +3 -0
  119. package/src/components/Textarea/Textarea.esm.js +23 -0
  120. package/src/components/TimePicker/AGENTS.md +42 -0
  121. package/src/components/TimePicker/TimePicker.css +1 -0
  122. package/src/components/TimePicker/TimePicker.d.ts +13 -0
  123. package/src/components/TimePicker/TimePicker.scss +226 -0
  124. package/src/components/TimePicker/TimePicker2.esm.js +98 -0
  125. package/src/components/TimePicker/TimePickerDisplay.d.ts +16 -0
  126. package/src/components/TimePicker/TimePickerDisplay.esm.js +54 -0
  127. package/src/components/TimePicker/TimePickerWheel.d.ts +13 -0
  128. package/src/components/TimePicker/TimePickerWheel.esm.js +61 -0
  129. package/src/components/TimePicker/constants.d.ts +7 -0
  130. package/src/components/TimePicker/constants.esm.js +3 -0
  131. package/src/components/TimePicker/utilities.d.ts +15 -0
  132. package/src/components/TimePicker/utilities.esm.js +20 -0
  133. package/src/components/Tooltip/AGENTS.md +41 -0
  134. package/src/components/Tooltip/Tooltip.css +1 -0
  135. package/src/components/Tooltip/Tooltip.d.ts +12 -0
  136. package/src/components/Tooltip/Tooltip.scss +29 -0
  137. package/src/components/Tooltip/Tooltip2.esm.js +65 -0
  138. package/src/components/index.d.ts +20 -7
  139. package/src/stories/assets/Stam.jpg +0 -0
  140. package/src/stories/assets/kaluah.jpg +0 -0
  141. package/src/stories/assets/stam2.jpg +0 -0
  142. package/src/stories/assets/tito.jpg +0 -0
  143. package/src/stories/documentation/AboutUs.mdx +21 -0
  144. package/src/stories/documentation/GettingStarted.mdx +117 -0
  145. package/src/stories/documentation/Introduction.mdx +29 -0
  146. package/src/stories/documentation/Themes.mdx +264 -0
  147. package/src/stories/documentation/ToDo.mdx +17 -0
  148. package/src/stories/molecules/Carousel.scss +21 -0
  149. package/src/stories/utilities/DeviceDetection.mdx +59 -0
  150. package/src/styles/_config.scss +30 -0
  151. package/src/styles/components/ThemeProvider.esm.js +1 -1
  152. package/src/styles/global/components/_button.scss +57 -52
  153. package/src/styles/global/components/_checkbox.scss +63 -59
  154. package/src/styles/global/components/_code.scss +19 -15
  155. package/src/styles/global/components/_input.scss +29 -37
  156. package/src/styles/global/components/_radioButton.scss +29 -26
  157. package/src/styles/global/components/_select.scss +56 -0
  158. package/src/styles/global/components/_typography.scss +92 -6
  159. package/src/styles/global/globalStyles.module.scss +1 -129
  160. package/src/styles/global/globalStyles.scss +85 -1
  161. package/src/styles/index.d.ts +1 -1
  162. package/src/styles/theme/components.esm.js +11 -7
  163. package/src/styles/theme/theme.esm.js +31 -41
  164. package/src/styles/theme/types.d.ts +4 -1
  165. package/src/styles/utilities/_functions.scss +117 -0
  166. package/src/styles/utilities/_mixins.scss +0 -0
  167. package/src/styles/utilities/_placeholders.scss +6 -0
  168. package/src/styles/utilities/color.d.ts +1 -1
  169. package/src/styles/utilities/constants.d.ts +1 -1
  170. package/src/styles/utilities/layout.d.ts +1 -1
  171. package/src/styles/utilities/layout.esm.js +3 -3
  172. package/src/{styles/utilities → utilities}/types.d.ts +53 -3
  173. package/src/utilities/types.esm.js +79 -0
  174. package/src/utilities/validations.d.ts +5 -0
  175. package/src/utilities/validations.esm.js +19 -1
  176. package/src/components/Button.esm.js +0 -28
  177. package/src/components/Button.module.css +0 -1
  178. package/src/components/Button.module.esm.js +0 -9
  179. package/src/components/Button.module.scss +0 -5
  180. package/src/components/Checkbox.d.ts +0 -7
  181. package/src/components/Input.d.ts +0 -11
  182. package/src/components/Input.esm.js +0 -41
  183. package/src/components/Input.module.css +0 -1
  184. package/src/components/Input.module.esm.js +0 -11
  185. package/src/components/Input.module.scss +0 -141
  186. package/src/components/InputPassword.esm.js +0 -33
  187. package/src/components/Loader.esm.js +0 -21
  188. package/src/components/Modal.esm.js +0 -62
  189. package/src/components/Modal.module.css +0 -1
  190. package/src/components/Modal.module.esm.js +0 -13
  191. package/src/components/Modal.module.scss +0 -133
  192. package/src/components/RadioButton.d.ts +0 -7
  193. package/src/styles/global/components/_mixins.scss +0 -2
  194. package/src/styles/global/components/button.d.ts +0 -7
  195. package/src/styles/global/components/loaders.module.css +0 -1
  196. package/src/styles/global/components/loaders.module.esm.js +0 -21
  197. package/src/styles/utilities/types.esm.js +0 -54
  198. package/src/{styles/global/components/loaders.d.ts → components/Loader/types.d.ts} +1 -1
  199. /package/src/{styles/global/components/loaders.esm.js → components/Loader/types.esm.js} +0 -0
  200. /package/src/components/{Progress.d.ts → Progress/Progress.d.ts} +0 -0
@@ -0,0 +1,38 @@
1
+ # Pagination — Agent Usage Notes
2
+
3
+ Import:
4
+
5
+ ```tsx
6
+ import { Pagination } from "@stamcat/craftsman/Pagination";
7
+ ```
8
+
9
+ Props:
10
+
11
+ - `total: number`
12
+ - `current: number`
13
+ - `showPages?: number` (default: `5`)
14
+ - `onChange: (e: React.MouseEvent<HTMLButtonElement>) => void`
15
+ - `className?: string`
16
+ - `style?: React.CSSProperties`
17
+
18
+ Behavior notes:
19
+
20
+ - Pagination is zero-based internally. Pass `current={0}` for the first page.
21
+ - `total` is the total number of pages, not the last page index.
22
+ - The component renders first/last buttons and jump-by-window buttons when needed.
23
+ - `showPages` controls both the visible window size and the jump step for `‹‹` / `››`.
24
+ - `onChange` receives the clicked button event. Read the next page from `event.currentTarget.value`.
25
+ - The active page button is disabled and marked with `aria-current="page"`.
26
+
27
+ Example:
28
+
29
+ ```tsx
30
+ const [current, setCurrent] = useState(0);
31
+
32
+ <Pagination
33
+ total={50}
34
+ current={current}
35
+ showPages={5}
36
+ onChange={(event) => setCurrent(parseInt(event.currentTarget.value, 10) || 0)}
37
+ />
38
+ ```
@@ -0,0 +1 @@
1
+ @layer craftsman-component{.pagination{align-items:center;gap:calc(var(--w-gutter) * .25);display:inline-flex}.pagination .active{color:var(--gray700);border:1px solid;border-radius:50%;justify-content:center;align-items:center;width:20px;height:20px;display:inline-flex}}
@@ -0,0 +1,10 @@
1
+ import { default as React } from 'react';
2
+ export type PaginationProps = {
3
+ total: number;
4
+ current: number;
5
+ showPages?: number;
6
+ onChange: (e: React.MouseEvent<HTMLButtonElement>) => void;
7
+ className?: string;
8
+ style?: React.CSSProperties;
9
+ };
10
+ export declare const Pagination: React.FC<PaginationProps>;
@@ -0,0 +1,22 @@
1
+
2
+ @use "../../styles/utilities/_functions" as u;
3
+
4
+ @layer craftsman-component {
5
+ .pagination {
6
+ display: inline-flex;
7
+ align-items: center;
8
+ gap: #{u.width("gutter", 0.25)};
9
+
10
+ .active {
11
+ color: #{u.color("gray700")};
12
+ border: 1px solid;
13
+ border-radius: 50%;
14
+ width: 20px;
15
+ height: 20px;
16
+ display: inline-flex;
17
+ align-items: center;
18
+ justify-content: center;
19
+
20
+ }
21
+ }
22
+ }
@@ -0,0 +1,64 @@
1
+ "use client";
2
+ import './Pagination.css';/* empty css */
3
+ import e from "clsx";
4
+ import { jsx as t, jsxs as n } from "react/jsx-runtime";
5
+ import "react";
6
+ //#region src/components/Pagination/Pagination.tsx
7
+ var r = ({ total: r, current: i, onChange: a, className: o, style: s, showPages: c = 5 }) => {
8
+ function l(e, t) {
9
+ let n = Math.floor(c / 2), r = Math.max(0, e - n), i = Math.min(t - 1, r + c - 1);
10
+ r = Math.max(0, i - c + 1);
11
+ let a = [];
12
+ for (let e = r; e <= i; e++) a.push(e);
13
+ return a;
14
+ }
15
+ let u = l(i, r), d = Math.floor(i / c), f = d > 0, p = (d + 1) * c < r, m = (d - 1) * c, h = (d + 1) * c;
16
+ return /* @__PURE__ */ n("nav", {
17
+ className: e("pagination", o),
18
+ style: s,
19
+ "aria-label": "Pagination",
20
+ children: [
21
+ /* @__PURE__ */ t("button", {
22
+ className: "text",
23
+ value: 0,
24
+ onClick: a,
25
+ disabled: i === 0,
26
+ "aria-label": "First page",
27
+ children: "«"
28
+ }),
29
+ f && /* @__PURE__ */ t("button", {
30
+ className: "text",
31
+ value: m,
32
+ onClick: a,
33
+ "aria-label": `Back ${c} pages`,
34
+ children: "‹‹"
35
+ }),
36
+ u.map((n) => /* @__PURE__ */ t("button", {
37
+ value: n,
38
+ onClick: a,
39
+ disabled: n === i,
40
+ "aria-label": `Page ${n + 1}`,
41
+ "aria-current": n === i ? "page" : void 0,
42
+ className: e("text", n === i ? "active" : void 0),
43
+ children: n + 1
44
+ }, n)),
45
+ p && /* @__PURE__ */ t("button", {
46
+ className: "text",
47
+ value: h,
48
+ onClick: a,
49
+ "aria-label": `Forward ${c} pages`,
50
+ children: "››"
51
+ }),
52
+ /* @__PURE__ */ t("button", {
53
+ className: "text",
54
+ value: r - 1,
55
+ onClick: a,
56
+ disabled: i === r - 1,
57
+ "aria-label": "Last page",
58
+ children: "»"
59
+ })
60
+ ]
61
+ });
62
+ };
63
+ //#endregion
64
+ export { r as Pagination };
@@ -0,0 +1,42 @@
1
+ # RadioButton — Agent Usage Notes
2
+
3
+ Import:
4
+
5
+ ```tsx
6
+ import { RadioButton } from "@stamcat/craftsman/RadioButton";
7
+ ```
8
+
9
+ Props:
10
+
11
+ - Extends `Input` props.
12
+ - `type?: "radio"` (default: `"radio"`)
13
+ - `labelPosition?: "left" | "right"` (default: `"right"`)
14
+
15
+ Behavior notes:
16
+
17
+ - `RadioButton` is a thin wrapper around `Input` with radio-specific guardrails.
18
+ - Group behavior is native HTML radio behavior: use a shared `name` across options.
19
+ - Controlled and uncontrolled patterns are both supported (`checked` + `onChange`, or `defaultChecked`).
20
+
21
+ Example:
22
+
23
+ ```tsx
24
+ <>
25
+ <RadioButton
26
+ id="captain-kirk"
27
+ name="favorite-captain"
28
+ value="Kirk"
29
+ label="James T. Kirk"
30
+ checked={selected === "Kirk"}
31
+ onChange={(event) => setSelected(event.currentTarget.value)}
32
+ />
33
+ <RadioButton
34
+ id="captain-picard"
35
+ name="favorite-captain"
36
+ value="Picard"
37
+ label="Jean-Luc Picard"
38
+ checked={selected === "Picard"}
39
+ onChange={(event) => setSelected(event.currentTarget.value)}
40
+ />
41
+ </>
42
+ ```
@@ -0,0 +1,8 @@
1
+ import { RadioLabelPosition } from '../../styles';
2
+ import { InputProps } from '../Input/Input';
3
+ type RadioButtonProps = InputProps & {
4
+ type?: "radio";
5
+ labelPosition?: RadioLabelPosition;
6
+ };
7
+ export declare const RadioButton: React.FC<RadioButtonProps>;
8
+ export {};
@@ -1,7 +1,7 @@
1
1
  "use client";
2
- import { Input as e } from "./Input.esm.js";
2
+ import { Input as e } from "../Input/Input2.esm.js";
3
3
  import { jsx as t } from "react/jsx-runtime";
4
- //#region src/components/RadioButton.tsx
4
+ //#region src/components/RadioButton/RadioButton.tsx
5
5
  var n = ({ type: n = "radio", labelPosition: r = "right", ...i }) => /* @__PURE__ */ t(e, {
6
6
  type: n,
7
7
  labelPosition: r,
@@ -0,0 +1,36 @@
1
+ # Select — Agent Usage Notes
2
+
3
+ Import:
4
+
5
+ ```tsx
6
+ import { Select } from "@stamcat/craftsman/Select";
7
+ ```
8
+
9
+ Props:
10
+
11
+ - Inherits all native `<select>` props.
12
+ - `label?: string | ReactNode`
13
+ - `labelPosition?: "top" | "left" | "bottom" | "right" | "inside" | "hidden"` (default: `"top"`)
14
+ - `error?: string | boolean | ReactNode`
15
+ - `required?: boolean`
16
+ - `options?: Array<{ label: string; value: string }>`
17
+
18
+ Behavior notes:
19
+
20
+ - Built on the native `<select>` element via `InputWrapper`.
21
+ - Pass options as a plain array — do not render `<option>` children manually.
22
+ - `id` is auto-generated via `useId` if not provided.
23
+
24
+ Example:
25
+
26
+ ```tsx
27
+ <Select
28
+ label="Favorite Fruit"
29
+ required
30
+ options={[
31
+ { value: "", label: "Select one..." },
32
+ { value: "apple", label: "Apple" },
33
+ { value: "banana", label: "Banana" },
34
+ ]}
35
+ />
36
+ ```
@@ -0,0 +1,14 @@
1
+ import { LabeledInput } from '../Input/InputWrapper';
2
+ export type SelectOption = {
3
+ value: string;
4
+ selected?: boolean;
5
+ disabled?: boolean;
6
+ label: string;
7
+ };
8
+ export type SelectProps = React.ComponentProps<"select"> & LabeledInput & {
9
+ options?: {
10
+ label: string;
11
+ value: string;
12
+ }[];
13
+ };
14
+ export declare const Select: React.FC<SelectProps>;
@@ -0,0 +1,26 @@
1
+ "use client";
2
+ import { InputWrapper as e } from "../Input/InputWrapper.esm.js";
3
+ import { jsx as t } from "react/jsx-runtime";
4
+ import { useId as n } from "react";
5
+ //#region src/components/Select/Select.tsx
6
+ var r = ({ label: r, id: i, labelPosition: a = "top", required: o = !1, error: s, options: c = [], className: l, style: u, ...d }) => {
7
+ let f = n(), p = i || f;
8
+ return /* @__PURE__ */ t(e, {
9
+ label: r,
10
+ labelPosition: a,
11
+ error: s,
12
+ required: o,
13
+ className: l,
14
+ style: u,
15
+ children: /* @__PURE__ */ t("select", {
16
+ id: p,
17
+ ...d,
18
+ children: c.map((e, n) => /* @__PURE__ */ t("option", {
19
+ value: e.value,
20
+ children: e.label
21
+ }, `${p}-opt-${n}`))
22
+ })
23
+ });
24
+ };
25
+ //#endregion
26
+ export { r as Select };
@@ -0,0 +1,32 @@
1
+ # Text — Agent Usage Notes
2
+
3
+ Import:
4
+
5
+ ```tsx
6
+ import { Text } from "@stamcat/craftsman/Text";
7
+ ```
8
+
9
+ Props:
10
+
11
+ - Inherits all native HTML element props.
12
+ - `as?: TextTags` — HTML tag to render (default: `"div"`)
13
+ - `richText?: boolean` — when `true`, renders sanitized HTML from a string `children` value (always renders as `<div>`)
14
+ - `type?: TextType` — overrides base type styling (e.g. `"display"`, `"heading"`)
15
+ - `size?: TextSize` — overrides base size styling
16
+ - `alignment?: "center" | "left" | "right"` — legacy text-align shorthand
17
+
18
+ Behavior notes:
19
+
20
+ - Uses global HTML5 tag declarations by default; `type` and `size` override base styling.
21
+ - `richText` mode sanitizes HTML via DOMPurify. Always pass a string as `children` in this mode.
22
+ - Prefer semantic HTML5 tags via `as` over using `type`/`size` overrides.
23
+
24
+ Example:
25
+
26
+ ```tsx
27
+ // Semantic heading
28
+ <Text as="h2">Section Title</Text>
29
+
30
+ // Sanitized rich text from a CMS
31
+ <Text richText>{'<p><strong>Hello</strong> world</p>'}</Text>
32
+ ```
@@ -0,0 +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}}
@@ -0,0 +1,10 @@
1
+ import { TextSize } from 'storybook/theming';
2
+ import { TextTags, TextType } from '../../utilities/types';
3
+ export type TextProps = React.HTMLAttributes<HTMLElement> & {
4
+ as?: TextTags;
5
+ richText?: boolean;
6
+ type?: TextType;
7
+ size?: TextSize;
8
+ alignment?: "center" | "left" | "right";
9
+ };
10
+ export declare const Text: React.FC<TextProps>;
@@ -0,0 +1,80 @@
1
+ @use "../../styles/utilities/_functions" as u;
2
+ @use "../../styles/global/components/typography" as t;
3
+ @layer craftsman-component {
4
+ .text {
5
+ // --- display ---
6
+ &.display {
7
+ @include t.h3;
8
+ }
9
+ &.display.xlarge {
10
+ @include t.h1;
11
+ }
12
+ &.display.large {
13
+ @include t.h2;
14
+ }
15
+ &.display.small {
16
+ @include t.h4;
17
+ }
18
+
19
+ // --- heading ---
20
+ &.heading {
21
+ @include t.h3;
22
+ }
23
+ &.heading.xlarge {
24
+ @include t.h1;
25
+ }
26
+ &.heading.large,
27
+ &.xlarge {
28
+ @include t.h2;
29
+ }
30
+ &.heading.medium {
31
+ @include t.h3;
32
+ }
33
+ &.heading.small {
34
+ @include t.h4;
35
+ }
36
+ &.heading.xsmall {
37
+ @include t.h5;
38
+ }
39
+
40
+ // --- paragraph ---
41
+ &.paragraph {
42
+ @include t.p;
43
+ }
44
+ &.paragraph.xlarge,
45
+ &.large {
46
+ @include t.h3;
47
+ }
48
+ &.paragraph.large {
49
+ @include t.h4;
50
+ }
51
+ &.paragraph.medium,
52
+ &.medium {
53
+ @include t.p;
54
+ }
55
+ &.paragraph.small,
56
+ &.small {
57
+ @include t.small;
58
+ }
59
+ &.paragraph.xsmall,
60
+ &.xsmall {
61
+ @include t.xsmall;
62
+ }
63
+
64
+ // --- caption ---
65
+ &.caption {
66
+ @include t.small;
67
+ }
68
+
69
+ // --- alignment ---
70
+ &.center {
71
+ text-align: center;
72
+ }
73
+ &.left {
74
+ text-align: left;
75
+ }
76
+ &.right {
77
+ text-align: right;
78
+ }
79
+ }
80
+ }
@@ -0,0 +1,23 @@
1
+ import './Text.css';/* empty css */
2
+ import e from "clsx";
3
+ import { jsx as t } from "react/jsx-runtime";
4
+ import n from "dompurify";
5
+ //#region src/components/Text/Text.tsx
6
+ var r = ({ as: r = "div", children: i, type: a, size: o, className: s, alignment: c, richText: l, ...u }) => {
7
+ let d = e(a && a, o && o, c && c, "text", s);
8
+ if (l) {
9
+ let e = typeof i == "string" ? n.sanitize(i, { ADD_ATTR: ["target"] }) : i;
10
+ return /* @__PURE__ */ t("div", {
11
+ ...u,
12
+ className: d,
13
+ dangerouslySetInnerHTML: { __html: e || "" }
14
+ });
15
+ }
16
+ return /* @__PURE__ */ t(r, {
17
+ ...u,
18
+ className: d,
19
+ children: i
20
+ });
21
+ };
22
+ //#endregion
23
+ export { r as Text };
@@ -0,0 +1,32 @@
1
+ # Textarea — Agent Usage Notes
2
+
3
+ Import:
4
+
5
+ ```tsx
6
+ import { Textarea } from "@stamcat/craftsman/Textarea";
7
+ ```
8
+
9
+ Props:
10
+
11
+ - Inherits all native `<textarea>` props.
12
+ - `label?: string | ReactNode`
13
+ - `labelPosition?: "top" | "left" | "bottom" | "right" | "inside" | "hidden"` (default: `"top"`)
14
+ - `error?: string | boolean | ReactNode`
15
+ - `required?: boolean`
16
+ - `rows?: number`
17
+
18
+ Behavior notes:
19
+
20
+ - Shares the same `InputWrapper` as `Input` — label, error, and required behavior is identical.
21
+ - `id` is auto-generated via `useId` if not provided.
22
+
23
+ Example:
24
+
25
+ ```tsx
26
+ <Textarea
27
+ label="Your Message"
28
+ placeholder="Type here"
29
+ rows={4}
30
+ required
31
+ />
32
+ ```
@@ -0,0 +1,3 @@
1
+ import { LabeledInput } from '../Input/InputWrapper';
2
+ export type TextareaProps = React.ComponentProps<"textarea"> & LabeledInput;
3
+ export declare const Textarea: React.FC<TextareaProps>;
@@ -0,0 +1,23 @@
1
+ "use client";
2
+ import { InputWrapper as e } from "../Input/InputWrapper.esm.js";
3
+ import { jsx as t } from "react/jsx-runtime";
4
+ import { useId as n } from "react";
5
+ //#region src/components/Textarea/Textarea.tsx
6
+ var r = ({ labelPosition: r = "top", id: i, label: a, error: o, required: s, className: c, style: l, ...u }) => {
7
+ let d = n();
8
+ return /* @__PURE__ */ t(e, {
9
+ label: a,
10
+ className: c,
11
+ labelPosition: r,
12
+ error: o,
13
+ required: s,
14
+ style: l,
15
+ children: /* @__PURE__ */ t("textarea", {
16
+ id: i || d,
17
+ className: "input",
18
+ ...u
19
+ })
20
+ });
21
+ };
22
+ //#endregion
23
+ export { r as Textarea };
@@ -0,0 +1,42 @@
1
+ # TimePicker — Agent Usage Notes
2
+
3
+ Import:
4
+
5
+ ```tsx
6
+ import { TimePicker } from "@stamcat/craftsman/TimePicker";
7
+ ```
8
+
9
+ Props:
10
+
11
+ - Extends `TimePickerProps` from `react-time-picker`, excluding its `locale` and `format` props.
12
+ - `label?: string | ReactNode`
13
+ - `labelPosition?: "top" | "left" | "bottom" | "right" | "inside" | "hidden"` (default: `"top"`)
14
+ - `error?: string | boolean | ReactNode`
15
+ - `required?: boolean`
16
+ - `locale?: Intl.LocalesArgument`
17
+ - `format?: 24 | 12`
18
+ - `labels?: { hour?: string; minute?: string }`
19
+
20
+ Behavior notes:
21
+
22
+ - The component uses a custom wheel UI instead of the stock `react-time-picker` clock popup.
23
+ - `value` is typically a time string such as `"09:30"`; pair it with `onChange` for interactive controlled usage.
24
+ - If a `value` is provided without `onChange`, treat the picker as effectively read-only.
25
+ - Focusing the input opens the wheel, and the trailing toggle button shows or hides it explicitly.
26
+ - The trailing toggle button mirrors the field's `disabled` prop — when `disabled` is set, the toggle is disabled too.
27
+ - Clicking outside the field and wheel closes the wheel.
28
+ - `locale` defaults to the browser locale when omitted and affects time formatting and wheel labels.
29
+ - When `name` is provided, the component renders a hidden input so forms can submit the selected string value.
30
+
31
+ Example:
32
+
33
+ ```tsx
34
+ const [time, setTime] = useState("09:30");
35
+
36
+ <TimePicker
37
+ label="Appointment Time"
38
+ value={time}
39
+ onChange={(value) => setTime(value ?? "")}
40
+ format={24}
41
+ />
42
+ ```
@@ -0,0 +1 @@
1
+ @layer craftsman-base{.react-time-picker__wrapper:focus{box-shadow:none;outline:0}.react-time-picker__wrapper{color:var(--text);border:1px solid var(--gray400);padding:calc(var(--w-gutter) * .5);background-color:var(--white);border-radius:6px}[type=number].react-time-picker__wrapper::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}[type=number].react-time-picker__wrapper::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}[type=number].react-time-picker__wrapper{appearance:textfield}.react-time-picker__wrapper:disabled,.disabled.react-time-picker__wrapper{border-color:var(--gray200);background-color:var(--gray100)}}.react-time-picker,.react-time-picker *,.react-time-picker :before,.react-time-picker :after{box-sizing:border-box}@layer craftsman-component{.react-time-picker{display:inline-flex;position:relative}.react-time-picker--disabled{color:#6d6d6d;background-color:#f0f0f0}.react-time-picker__wrapper{flex-grow:1;flex-shrink:0;padding:6px 8px;display:flex}.react-time-picker__inputGroup{box-sizing:content-box;flex-grow:1;padding:0 2px}.react-time-picker__inputGroup__divider{white-space:pre;padding:1px 0}.react-time-picker__inputGroup__divider,.react-time-picker__inputGroup__leadingZero{font:inherit;display:inline-block}.react-time-picker__inputGroup__input{text-align:center;color:currentColor;min-width:calc(2ch + 1px);height:calc(100% - 2px);font:inherit;box-sizing:content-box;appearance:textfield;background:0 0;border:0;padding:1px;position:relative}[name=year].react-time-picker__inputGroup__input{min-width:calc(4ch + 2px)}.react-time-picker__inputGroup__input:disabled{background-color:unset}.react-time-picker__inputGroup__input::-webkit-outer-spin-button{appearance:none;margin:0}.react-time-picker__inputGroup__input::-webkit-inner-spin-button{appearance:none;margin:0}.react-time-picker__inputGroup__input--hasLeadingZero{margin-left:-.54em;padding-left:calc(1px + .54em)}.react-time-picker__button{border:0;padding:4px 4px 4px 7px}.react-time-picker__button:hover{background:0 0}.react-time-picker__wrapper{padding:6px 24px 6px 8px}.react-time-picker__inputGroup__input:invalid{background:#ff00001a}.react-time-picker__inputGroup__amPm{font:inherit;appearance:menulist}.react-time-picker__button:enabled{cursor:pointer}.react-time-picker__button:enabled:hover .react-time-picker__button__icon,.react-time-picker__button:enabled:focus .react-time-picker__button__icon{stroke:#0078d7}.react-time-picker__button:disabled .react-time-picker__button__icon{stroke:#6d6d6d}.react-time-picker__button svg{display:inherit}.react-time-picker__clock{z-index:1;background-color:#fff;border:thin solid #a0a096;width:200px;max-width:100vw;height:200px;padding:25px}.react-time-picker__clock--closed,.timePicker .react-time-picker__clock{display:none}.timePicker .timePicker__field{position:relative}.timePicker .timePicker__field .input-view-toggle{padding:4px;line-height:1;position:absolute;top:50%;right:4px;transform:translateY(-50%)}.timePicker__display{background-color:var(--white);border:1px solid var(--gray400);z-index:1;border-radius:8px;height:160px;display:inline-flex;position:relative}.timePicker__display:before,.timePicker__display:after{content:"";z-index:1;pointer-events:none;height:calc(50% - 16px);display:block;position:absolute;left:0;right:0}.timePicker__display:before{border-bottom:.5px solid rgba(var(--text-high-contrast-rgb-value), .3);background:linear-gradient(to top, rgba(var(--background-site-rgb-value), .65) 0%, rgba(var(--background-site-rgb-value), 1) 100%);top:-.5px}.timePicker__display:after{border-top:.5px solid rgba(var(--text-high-contrast-rgb-value), .3);background:linear-gradient(to bottom, rgba(var(--background-site-rgb-value), .65) 0%, rgba(var(--background-site-rgb-value), 1) 100%);bottom:-.5px}.timePicker__display .ios-picker{flex-direction:row;align-items:center;gap:6px;height:100%;padding:0 12px;font-size:16px;line-height:1;display:flex}.timePicker__display .ios-picker--disabled{pointer-events:none;opacity:.5}.timePicker__display .ios-picker__scene{touch-action:pan-x;align-items:center;min-width:30px;height:100%;display:flex;overflow:hidden}.timePicker__display .ios-picker__viewport{perspective:1000px;-webkit-user-select:none;user-select:none;-webkit-touch-callout:none;-khtml-user-select:none;-webkit-tap-highlight-color:transparent;width:100%;height:32px}.timePicker__display .ios-picker__viewport--perspective-left{perspective-origin:calc(50% + 130px);transform:translate(27px)}.timePicker__display .ios-picker__viewport--perspective-right{perspective-origin:calc(50% - 130px);transform:translate(-27px)}.timePicker__display .ios-picker__viewport--perspective-center{perspective-origin:50%}.timePicker__display .ios-picker__container{width:100%;height:100%;transform-style:preserve-3d;will-change:transform}.timePicker__display .ios-picker__slide{text-align:center;backface-visibility:hidden;opacity:0;justify-content:center;align-items:center;width:100%;height:100%;display:flex}.timePicker__display .ios-picker__label{white-space:nowrap;pointer-events:none;font-weight:700}}
@@ -0,0 +1,13 @@
1
+ import { default as React } from 'react';
2
+ import { TimePickerProps as ReactTimePickerProps } from 'react-time-picker';
3
+ import { LabeledInput } from '../Input/InputWrapper';
4
+ type TimePickerProps = Omit<ReactTimePickerProps, "locale" | "format"> & LabeledInput & {
5
+ locale?: Intl.LocalesArgument;
6
+ format?: 24 | 12;
7
+ labels?: {
8
+ hour?: string;
9
+ minute?: string;
10
+ };
11
+ };
12
+ export declare const TimePicker: React.FC<TimePickerProps>;
13
+ export {};