@stamcat/craftsman 0.0.27-alpha.9 → 0.0.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (180) hide show
  1. package/AGENTS.md +21 -403
  2. package/Components.esm.js +62 -11
  3. package/README.md +63 -12
  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 +51 -3
  8. package/src/components/Button/AGENTS.md +65 -0
  9. package/src/components/Button/Button.d.ts +1 -1
  10. package/src/components/Button/Button.esm.js +11 -17
  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 +34 -0
  17. package/src/components/Checkbox/Checkbox.d.ts +8 -0
  18. package/src/components/Checkbox/Checkbox.esm.js +18 -0
  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 -1
  72. package/src/components/Input/Input.scss +108 -95
  73. package/src/components/Input/Input2.esm.js +27 -18
  74. package/src/components/Input/InputWrapper.d.ts +1 -0
  75. package/src/components/InputNumber/AGENTS.md +37 -0
  76. package/src/components/InputNumber/InputNumber.css +1 -0
  77. package/src/components/InputNumber/InputNumber.d.ts +10 -0
  78. package/src/components/InputNumber/InputNumber.scss +29 -0
  79. package/src/components/InputNumber/InputNumber2.esm.js +36 -0
  80. package/src/components/InputPassword/AGENTS.md +29 -0
  81. package/src/components/{Input → InputPassword}/InputPassword.d.ts +1 -1
  82. package/src/components/InputPassword/InputPassword.esm.js +30 -0
  83. package/src/components/InputPhone/AGENTS.md +35 -0
  84. package/src/components/InputPhone/InputPhone.css +1 -0
  85. package/src/components/{Input → InputPhone}/InputPhone.d.ts +1 -1
  86. package/src/components/InputPhone/InputPhone.scss +266 -0
  87. package/src/components/{Input/InputPhone.esm.js → InputPhone/InputPhone2.esm.js} +4 -4
  88. package/src/components/Loader/AGENTS.md +31 -0
  89. package/src/components/Loader/Loader.esm.js +1 -1
  90. package/src/components/Loader/types.d.ts +1 -1
  91. package/src/components/Modal/AGENTS.md +47 -0
  92. package/src/components/Modal/Modal.css +1 -0
  93. package/src/components/Modal/Modal.scss +150 -0
  94. package/src/components/Modal/Modal2.esm.js +53 -0
  95. package/src/components/Notice/AGENTS.md +42 -0
  96. package/src/components/Notice/Notice.css +1 -0
  97. package/src/components/Notice/Notice.d.ts +13 -0
  98. package/src/components/Notice/Notice.scss +76 -0
  99. package/src/components/Notice/Notice2.esm.js +56 -0
  100. package/src/components/Pagination/AGENTS.md +38 -0
  101. package/src/components/Pagination/Pagination.css +1 -0
  102. package/src/components/Pagination/Pagination.d.ts +10 -0
  103. package/src/components/Pagination/Pagination.scss +22 -0
  104. package/src/components/Pagination/Pagination2.esm.js +64 -0
  105. package/src/components/RadioButton/AGENTS.md +44 -0
  106. package/src/components/RadioButton/RadioButton.d.ts +9 -0
  107. package/src/components/RadioButton/RadioButton.esm.js +18 -0
  108. package/src/components/Select/AGENTS.md +36 -0
  109. package/src/components/SortableList/AGENTS.md +45 -0
  110. package/src/components/SortableList/ListItem.d.ts +10 -0
  111. package/src/components/SortableList/ListItem.esm.js +67 -0
  112. package/src/components/SortableList/SortableList.css +1 -0
  113. package/src/components/SortableList/SortableList.d.ts +23 -0
  114. package/src/components/SortableList/SortableList.scss +41 -0
  115. package/src/components/SortableList/SortableList2.esm.js +54 -0
  116. package/src/components/SortableList/utilities.d.ts +7 -0
  117. package/src/components/SortableList/utilities.esm.js +4 -0
  118. package/src/components/Text/AGENTS.md +32 -0
  119. package/src/components/Text/Text.css +1 -1
  120. package/src/components/Text/Text.scss +2 -2
  121. package/src/components/Textarea/AGENTS.md +32 -0
  122. package/src/components/{Input → Textarea}/Textarea.d.ts +1 -1
  123. package/src/components/Textarea/Textarea.esm.js +23 -0
  124. package/src/components/TimePicker/AGENTS.md +42 -0
  125. package/src/components/TimePicker/TimePicker.css +1 -0
  126. package/src/components/TimePicker/TimePicker.d.ts +13 -0
  127. package/src/components/TimePicker/TimePicker.scss +226 -0
  128. package/src/components/TimePicker/TimePicker2.esm.js +98 -0
  129. package/src/components/TimePicker/TimePickerDisplay.d.ts +16 -0
  130. package/src/components/TimePicker/TimePickerDisplay.esm.js +54 -0
  131. package/src/components/TimePicker/TimePickerWheel.d.ts +13 -0
  132. package/src/components/TimePicker/TimePickerWheel.esm.js +61 -0
  133. package/src/components/TimePicker/constants.d.ts +7 -0
  134. package/src/components/TimePicker/constants.esm.js +3 -0
  135. package/src/components/TimePicker/utilities.d.ts +15 -0
  136. package/src/components/TimePicker/utilities.esm.js +20 -0
  137. package/src/components/Toggle/AGENTS.md +33 -0
  138. package/src/components/Toggle/Toggle.css +1 -0
  139. package/src/components/Toggle/Toggle.d.ts +5 -0
  140. package/src/components/Toggle/Toggle.scss +64 -0
  141. package/src/components/Toggle/Toggle2.esm.js +19 -0
  142. package/src/components/Tooltip/AGENTS.md +41 -0
  143. package/src/components/Tooltip/Tooltip.css +1 -0
  144. package/src/components/Tooltip/Tooltip.d.ts +12 -0
  145. package/src/components/Tooltip/Tooltip.scss +29 -0
  146. package/src/components/Tooltip/Tooltip2.esm.js +65 -0
  147. package/src/components/index.d.ts +17 -6
  148. package/src/styles/global/components/_button.scss +24 -21
  149. package/src/styles/global/components/_checkbox.scss +5 -4
  150. package/src/styles/global/components/_input.scss +1 -1
  151. package/src/styles/global/components/_radioButton.scss +5 -4
  152. package/src/styles/global/components/_typography.scss +6 -1
  153. package/src/styles/global/globalStyles.scss +9 -5
  154. package/src/styles/theme/components.esm.js +5 -6
  155. package/src/styles/utilities/_functions.scss +2 -2
  156. package/src/styles/utilities/_placeholders.scss +6 -0
  157. package/src/styles/utilities/layout.esm.js +3 -3
  158. package/src/utilities/types.d.ts +28 -3
  159. package/src/utilities/types.esm.js +11 -5
  160. package/src/utilities/validations.d.ts +5 -0
  161. package/src/utilities/validations.esm.js +19 -1
  162. package/src/components/Input/Checkbox.d.ts +0 -7
  163. package/src/components/Input/Checkbox.esm.js +0 -11
  164. package/src/components/Input/DatePicker.d.ts +0 -8
  165. package/src/components/Input/DatePicker.esm.js +0 -24
  166. package/src/components/Input/InputPassword.esm.js +0 -28
  167. package/src/components/Input/RadioButton.d.ts +0 -7
  168. package/src/components/Input/RadioButton.esm.js +0 -11
  169. package/src/components/Input/Textarea.esm.js +0 -24
  170. package/src/components/Modal/Modal.esm.js +0 -53
  171. package/src/components/Modal/Modal.module.css +0 -1
  172. package/src/components/Modal/Modal.module.esm.js +0 -16
  173. package/src/components/Modal/Modal.module.scss +0 -147
  174. package/src/styles/global/components/_reactCalendar.css +0 -1
  175. package/src/styles/global/components/_reactCalendar.scss +0 -237
  176. package/src/styles/global/components/_reactDatePicker.css +0 -1
  177. package/src/styles/global/components/_reactDatePicker.scss +0 -152
  178. package/src/styles/global/components/_reactPhone.css +0 -1
  179. package/src/styles/global/components/_reactPhone.scss +0 -265
  180. /package/src/components/{Progress.d.ts → Progress/Progress.d.ts} +0 -0
@@ -0,0 +1,15 @@
1
+ export { IconAmazonPay } from './IconAmazonPay';
2
+ export { IconAmex } from './IconAmex';
3
+ export { IconApplePay } from './IconApplePay';
4
+ export { IconDiscover } from './IconDiscover';
5
+ export { IconGooglePay } from './IconGooglePay';
6
+ export { IconMaestro } from './IconMaestro';
7
+ export { IconMastercard } from './IconMastercard';
8
+ export { IconPayPal } from './IconPayPal';
9
+ export { IconSepa } from './IconSepa';
10
+ export { IconShopPay } from './IconShopPay';
11
+ export { IconSquare } from './IconSquare';
12
+ export { IconStripe } from './IconStripe';
13
+ export { IconUnionPay } from './IconUnionPay';
14
+ export { IconVenmo } from './IconVenmo';
15
+ export { IconVisa } from './IconVisa';
@@ -0,0 +1,16 @@
1
+ import { IconAmazonPay as e } from "./IconAmazonPay.esm.js";
2
+ import { IconAmex as t } from "./IconAmex.esm.js";
3
+ import { IconApplePay as n } from "./IconApplePay.esm.js";
4
+ import { IconDiscover as r } from "./IconDiscover.esm.js";
5
+ import { IconGooglePay as i } from "./IconGooglePay.esm.js";
6
+ import { IconMaestro as a } from "./IconMaestro.esm.js";
7
+ import { IconMastercard as o } from "./IconMastercard.esm.js";
8
+ import { IconPayPal as s } from "./IconPayPal.esm.js";
9
+ import { IconSepa as c } from "./IconSepa.esm.js";
10
+ import { IconShopPay as l } from "./IconShopPay.esm.js";
11
+ import { IconSquare as u } from "./IconSquare.esm.js";
12
+ import { IconStripe as d } from "./IconStripe.esm.js";
13
+ import { IconUnionPay as f } from "./IconUnionPay.esm.js";
14
+ import { IconVenmo as p } from "./IconVenmo.esm.js";
15
+ import { IconVisa as m } from "./IconVisa.esm.js";
16
+ export { e as IconAmazonPay, t as IconAmex, n as IconApplePay, r as IconDiscover, i as IconGooglePay, a as IconMaestro, o as IconMastercard, s as IconPayPal, c as IconSepa, l as IconShopPay, u as IconSquare, d as IconStripe, f as IconUnionPay, p as IconVenmo, m as IconVisa };
@@ -0,0 +1,4 @@
1
+ import { SVGProps } from 'react';
2
+ export type SVGIconProps = Omit<SVGProps<SVGSVGElement>, 'width'> & {
3
+ width?: number;
4
+ };
@@ -0,0 +1,30 @@
1
+ # Input — Agent Usage Notes
2
+
3
+ Import:
4
+
5
+ ```tsx
6
+ import { Input } from "@stamcat/craftsman/Input";
7
+ ```
8
+
9
+ Props:
10
+
11
+ - Inherits native `<input>` props.
12
+ - `label?: string | ReactNode`
13
+ - `labelPosition?: "top" | "left" | "bottom" | "right" | "inside" | "hidden"` (default: `"top"`)
14
+ - `error?: string | boolean | ReactNode`
15
+ - `required?: boolean`
16
+ - `styles?: React.CSSProperties` (wrapper override)
17
+ - `type?: TextInputType` (checkbox/radio excluded)
18
+
19
+ Behavior notes:
20
+
21
+ - `id` is preserved; if omitted, a stable React `useId` value is used.
22
+ - Floating-label behavior is supported when `labelPosition="inside"`.
23
+ - `endAdornment` exists as an internal extension point used by `InputPassword`; consumer apps should prefer `InputPassword` rather than wiring password toggles on `Input`.
24
+ - `preAdornment` is an internal extension point used by `InputNumber` for its decrement button; consumer apps should prefer `InputNumber` rather than wiring stepper buttons on `Input` directly.
25
+
26
+ Example:
27
+
28
+ ```tsx
29
+ <Input type="email" placeholder="you@company.com" required />
30
+ ```
@@ -1 +1 @@
1
- @layer craftsman-base;.input-wrapper label .input-label{margin-bottom:calc(var(--w-gutter) * .25)}.input-wrapper[data-required=true] label .input-label:after{content:"*";color:var(--red700)}.input-wrapper[data-label-position=left] label{align-items:center;display:inline-flex}.input-wrapper[data-label-position=left] label .input-label{width:fit-content;margin-right:calc(var(--w-gutter) * .75)}.input-wrapper[data-label-position=left].textarea label{align-items:flex-start}.input-wrapper[data-label-position=bottom] label{flex-direction:column-reverse;align-items:flex-start;display:inline-flex}.input-wrapper[data-label-position=bottom] label .input-label{margin-bottom:0;margin-top:calc(var(--w-gutter) * .25)}.input-wrapper[data-label-position=right] label{flex-direction:row-reverse;align-items:baseline;display:inline-flex}.input-wrapper[data-label-position=right] label .input-label{margin-left:calc(var(--w-gutter) * .25);margin-bottom:0}.input-wrapper[data-label-position=inside]{--react-international-phone-height:50px;--react-international-phone-border-radius:8px;--react-international-phone-border-color:silver;position:relative}.input-wrapper[data-label-position=inside] .input-label{background-color:var(--white);z-index:1;width:fit-content;top:calc(var(--w-gutter) * .25);left:calc(var(--w-gutter) * .25);pointer-events:none;padding:0 5px;transition:top .15s,left .15s,font-size .15s,color .15s;position:absolute}.input-wrapper[data-label-position=inside]>label>.input-field>.input,.input-wrapper[data-label-position=inside]>.input{transition:border-color .2s}.input-wrapper[data-label-position=inside]:focus-within .input-label{top:-.5rem;left:calc(var(--w-gutter) * .125);font-size:calc(var(--w-text) * .75);color:var(--blue500)}.input-wrapper[data-label-position=inside]:focus-within .input{border-color:var(--blue500)}.input-wrapper[data-label-position=inside]:focus-within .input::placeholder{opacity:1}.input-wrapper[data-label-position=inside][data-has-input=true] .input-label{top:-.5rem;left:calc(var(--w-gutter) * .125);font-size:calc(var(--w-text) * .75)}.input-wrapper[data-label-position=inside] .input[type=tel]{width:100%}.input-wrapper[data-label-position=inside] .input::placeholder{opacity:0;transition:opacity .2s}.input-wrapper .input-field{align-items:center;display:inline-flex;position:relative}.input-wrapper .input-field[data-has-end-adornment=true]>.input{width:100%;padding-right:calc(var(--w-gutter) * 1.5)}.input-wrapper .input-adornment{right:calc(var(--w-gutter) * .5);z-index:1;align-items:center;margin-top:0;display:inline-flex;position:absolute;top:50%;transform:translateY(-50%)}.input-wrapper .input-error{margin-top:calc(var(--w-gutter) * .25);font-size:calc(var(--w-text) * .75);color:var(--red600)}.input-wrapper .input-view-toggle{align-items:"center";padding:0;line-height:1;display:inline-flex}
1
+ @layer craftsman-base{.input-pre-adornment,.input-end-adornment{z-index:1;align-items:center;margin-top:0;display:inline-flex;position:absolute;top:50%;transform:translateY(-50%)}.input-wrapper label .input-label{margin-bottom:calc(var(--w-gutter) * .25)}.input-wrapper[data-required=true] label .input-label:after{content:"*";color:var(--red700)}.input-wrapper[data-label-position=left] label{align-items:center;display:inline-flex}.input-wrapper[data-label-position=left] label .input-label{width:fit-content;margin-right:calc(var(--w-gutter) * .75)}.input-wrapper[data-label-position=left].textarea label{align-items:flex-start}.input-wrapper[data-label-position=bottom] label{flex-direction:column-reverse;align-items:flex-start;display:inline-flex}.input-wrapper[data-label-position=bottom] label .input-label{margin-bottom:0;margin-top:calc(var(--w-gutter) * .25)}.input-wrapper[data-label-position=right] label{flex-direction:row-reverse;align-items:baseline;display:inline-flex}.input-wrapper[data-label-position=right] label .input-label{margin-left:calc(var(--w-gutter) * .25);margin-bottom:0}.input-wrapper[data-label-position=inside]{--react-international-phone-height:50px;--react-international-phone-border-radius:8px;--react-international-phone-border-color:silver;position:relative}.input-wrapper[data-label-position=inside] .input-label{background-color:var(--white);z-index:1;width:fit-content;top:calc(var(--w-gutter) * .45);left:calc(var(--w-gutter) * .25);pointer-events:none;padding:0 5px;transition:top .15s,left .15s,font-size .15s,color .15s;position:absolute}.input-wrapper[data-label-position=inside]>label>.input-field>.input,.input-wrapper[data-label-position=inside]>.input{transition:border-color .2s}.input-wrapper[data-label-position=inside]:focus-within .input-label{top:-.5rem;left:calc(var(--w-gutter) * .125);font-size:calc(var(--w-text) * .75);color:var(--blue500)}.input-wrapper[data-label-position=inside]:focus-within .input{border-color:var(--blue500)}.input-wrapper[data-label-position=inside]:focus-within .input::placeholder{opacity:1}.input-wrapper[data-label-position=inside][data-has-input=true] .input-label{top:-.5rem;left:calc(var(--w-gutter) * .125);font-size:calc(var(--w-text) * .75)}.input-wrapper[data-label-position=inside] .input[type=tel]{width:100%}.input-wrapper[data-label-position=inside] .input::placeholder{opacity:0;transition:opacity .2s}.input-field{align-items:center;display:inline-flex;position:relative}.input-field[data-has-end-adornment=true]>.input{padding-right:calc(var(--w-gutter) * 1.5)}.input-field[data-has-pre-adornment=true]>.input{padding-left:calc(var(--w-gutter) * 2.25)}.input-end-adornment{right:calc(var(--w-gutter) * .5)}.input-pre-adornment{left:calc(var(--w-gutter) * .5)}.input-error{margin-top:calc(var(--w-gutter) * .25);font-size:calc(var(--w-text) * .75);color:var(--red600)}.input-view-toggle{align-items:"center";padding:0;line-height:1;display:inline-flex}}
@@ -1,152 +1,165 @@
1
1
  @use "../../styles/global/components/input";
2
- @use "../../styles/utilities/functions" as u;
2
+ @use "../../styles/utilities/_functions" as u;
3
3
 
4
4
  @mixin inside-input-label-floating {
5
5
  top: -0.5rem;
6
6
  left: #{u.width("gutter", 0.125)};
7
7
  font-size: #{u.width("text", 0.75)};
8
8
  }
9
-
10
- .input-wrapper {
11
- label {
12
- .input-label {
13
- margin-bottom: #{u.width("gutter", 0.25)};
14
- }
9
+ // This is in base layer because many components implement it.
10
+ @layer craftsman-base {
11
+ %input-adornment {
12
+ position: absolute;
13
+ top: 50%;
14
+ transform: translateY(-50%);
15
+ margin-top: 0;
16
+ z-index: 1;
17
+ display: inline-flex;
18
+ align-items: center;
15
19
  }
16
-
17
- &[data-required="true"] {
20
+ .input-wrapper {
18
21
  label {
19
22
  .input-label {
20
- &::after {
21
- content: "*";
22
- color: var(--red700);
23
+ margin-bottom: #{u.width("gutter", 0.25)};
24
+ }
25
+ }
26
+
27
+ &[data-required="true"] {
28
+ label {
29
+ .input-label {
30
+ &::after {
31
+ content: "*";
32
+ color: var(--red700);
33
+ }
23
34
  }
24
35
  }
25
36
  }
26
- }
27
37
 
28
- &[data-label-position="left"] {
29
- label {
30
- display: inline-flex;
31
- align-items: center;
38
+ &[data-label-position="left"] {
39
+ label {
40
+ display: inline-flex;
41
+ align-items: center;
32
42
 
33
- .input-label {
34
- width: fit-content;
35
- margin-right: #{u.width("gutter", 0.75)};
43
+ .input-label {
44
+ width: fit-content;
45
+ margin-right: #{u.width("gutter", 0.75)};
46
+ }
47
+ }
48
+ &.textarea {
49
+ label {
50
+ align-items: flex-start;
51
+ }
36
52
  }
37
53
  }
38
- &.textarea {
54
+
55
+ &[data-label-position="bottom"] {
39
56
  label {
57
+ display: inline-flex;
58
+ flex-direction: column-reverse;
40
59
  align-items: flex-start;
60
+
61
+ .input-label {
62
+ margin-bottom: 0;
63
+ margin-top: #{u.width("gutter", 0.25)};
64
+ }
41
65
  }
42
66
  }
43
- }
44
67
 
45
- &[data-label-position="bottom"] {
46
- label {
47
- display: inline-flex;
48
- flex-direction: column-reverse;
49
- align-items: flex-start;
68
+ &[data-label-position="right"] {
69
+ label {
70
+ display: inline-flex;
71
+ flex-direction: row-reverse;
72
+ align-items: baseline;
50
73
 
51
- .input-label {
52
- margin-bottom: 0;
53
- margin-top: #{u.width("gutter", 0.25)};
74
+ .input-label {
75
+ margin-left: #{u.width("gutter", 0.25)};
76
+ margin-bottom: 0;
77
+ }
54
78
  }
55
79
  }
56
- }
57
80
 
58
- &[data-label-position="right"] {
59
- label {
60
- display: inline-flex;
61
- flex-direction: row-reverse;
62
- align-items: baseline;
81
+ &[data-label-position="inside"] {
82
+ --react-international-phone-height: 50px;
83
+ --react-international-phone-border-radius: 8px;
84
+ --react-international-phone-border-color: #c0c0c0ff;
85
+ position: relative;
63
86
 
64
87
  .input-label {
65
- margin-left: #{u.width("gutter", 0.25)};
66
- margin-bottom: 0;
88
+ position: absolute;
89
+ background-color: var(--white);
90
+ z-index: 1;
91
+ width: fit-content;
92
+ padding: 0 5px;
93
+ top: #{u.width(gutter, 0.45)};
94
+ left: #{u.width(gutter, 0.25)};
95
+ pointer-events: none;
96
+ transition:
97
+ top 150ms ease,
98
+ left 150ms ease,
99
+ font-size 150ms ease,
100
+ color 150ms ease;
67
101
  }
68
- }
69
- }
70
102
 
71
- &[data-label-position="inside"] {
72
- --react-international-phone-height: 50px;
73
- --react-international-phone-border-radius: 8px;
74
- --react-international-phone-border-color: #c0c0c0ff;
75
- position: relative;
103
+ > label > .input-field > .input,
104
+ > .input {
105
+ transition: border-color 200ms ease;
106
+ }
76
107
 
77
- .input-label {
78
- position: absolute;
79
- background-color: var(--white);
80
- z-index: 1;
81
- width: fit-content;
82
- padding: 0 5px;
83
- top: #{u.width(gutter, 0.25)};
84
- left: #{u.width(gutter, 0.25)};
85
- pointer-events: none;
86
- transition:
87
- top 150ms ease,
88
- left 150ms ease,
89
- font-size 150ms ease,
90
- color 150ms ease;
91
- }
108
+ &:focus-within {
109
+ .input-label {
110
+ @include inside-input-label-floating;
111
+ color: var(--blue500);
112
+ }
92
113
 
93
- > label > .input-field > .input,
94
- > .input {
95
- transition: border-color 200ms ease;
96
- }
114
+ .input {
115
+ border-color: var(--blue500);
116
+ }
97
117
 
98
- &:focus-within {
99
- .input-label {
100
- @include inside-input-label-floating;
101
- color: var(--blue500);
118
+ .input::placeholder {
119
+ opacity: 1;
120
+ }
102
121
  }
103
122
 
104
- .input {
105
- border-color: var(--blue500);
123
+ &[data-has-input="true"] {
124
+ .input-label {
125
+ @include inside-input-label-floating;
126
+ }
106
127
  }
107
128
 
108
- .input::placeholder {
109
- opacity: 1;
129
+ .input[type="tel"] {
130
+ width: 100%;
110
131
  }
111
- }
112
132
 
113
- &[data-has-input="true"] {
114
- .input-label {
115
- @include inside-input-label-floating;
133
+ .input::placeholder {
134
+ opacity: 0;
135
+ transition: opacity 200ms ease;
116
136
  }
117
137
  }
118
-
119
- .input[type="tel"] {
120
- width: 100%;
121
- }
122
-
123
- .input::placeholder {
124
- opacity: 0;
125
- transition: opacity 200ms ease;
126
- }
127
138
  }
128
139
  .input-field {
129
140
  position: relative;
130
141
  display: inline-flex;
131
142
  align-items: center;
132
-
133
143
  &[data-has-end-adornment="true"] {
134
144
  > .input {
135
- width: 100%;
136
145
  padding-right: #{u.width("gutter", 1.5)};
137
146
  }
138
147
  }
148
+ &[data-has-pre-adornment="true"] {
149
+ > .input {
150
+ padding-left: #{u.width("gutter", 2.25)};
151
+ }
152
+ }
139
153
  }
140
154
 
141
- .input-adornment {
142
- position: absolute;
155
+
156
+ .input-end-adornment {
157
+ @extend %input-adornment;
143
158
  right: #{u.width("gutter", 0.5)};
144
- top: 50%;
145
- transform: translateY(-50%);
146
- margin-top: 0;
147
- z-index: 1;
148
- display: inline-flex;
149
- align-items: center;
159
+ }
160
+ .input-pre-adornment {
161
+ @extend %input-adornment;
162
+ left: #{u.width("gutter", 0.5)};
150
163
  }
151
164
 
152
165
  .input-error {
@@ -1,31 +1,40 @@
1
1
  "use client";
2
2
  import { isEmpty as e } from "../../utilities/validations.esm.js";
3
3
  import { InputWrapper as t } from "./InputWrapper.esm.js";
4
+ import "../../utilities/types.esm.js";
4
5
  import n from "clsx";
5
6
  import { jsx as r, jsxs as i } from "react/jsx-runtime";
6
7
  import { useId as a } from "react";
7
8
  //#region src/components/Input/Input.tsx
8
- var o = ({ label: o, id: s, labelPosition: c = "top", required: l = !1, type: u = "text", error: d, endAdornment: f, style: p, className: m, ...h }) => {
9
- let g = a(), _ = s || g;
9
+ var o = (o) => {
10
+ let { label: s, id: c, labelPosition: l = "top", required: u = !1, type: d = "text", error: f, endAdornment: p, preAdornment: m, style: h, className: g, ..._ } = o, v = a(), y = c || v;
10
11
  return /* @__PURE__ */ r(t, {
11
- className: m,
12
- label: o,
13
- labelPosition: c,
14
- error: d,
15
- required: l,
16
- style: p,
12
+ className: g,
13
+ label: s,
14
+ labelPosition: l,
15
+ error: f,
16
+ required: u,
17
+ style: h,
17
18
  children: /* @__PURE__ */ i("span", {
18
19
  className: "input-field",
19
- "data-has-end-adornment": !e(f),
20
- children: [/* @__PURE__ */ r("input", {
21
- id: _,
22
- type: u,
23
- className: n("input", u),
24
- ...h
25
- }), !e(f) && /* @__PURE__ */ r("span", {
26
- className: "input-adornment",
27
- children: f
28
- })]
20
+ "data-has-end-adornment": !e(p),
21
+ "data-has-pre-adornment": !e(m),
22
+ children: [
23
+ !e(m) && /* @__PURE__ */ r("span", {
24
+ className: "input-pre-adornment",
25
+ children: m
26
+ }),
27
+ /* @__PURE__ */ r("input", {
28
+ id: y,
29
+ type: d,
30
+ className: n("input", d),
31
+ ..._
32
+ }),
33
+ !e(p) && /* @__PURE__ */ r("span", {
34
+ className: "input-end-adornment",
35
+ children: p
36
+ })
37
+ ]
29
38
  })
30
39
  });
31
40
  };
@@ -5,6 +5,7 @@ export type LabeledInput = {
5
5
  error?: string | boolean | React.ReactNode;
6
6
  required?: boolean;
7
7
  endAdornment?: React.ReactNode;
8
+ preAdornment?: React.ReactNode;
8
9
  };
9
10
  export type InputWrapperProps = React.ComponentProps<"input" | "textarea" | "select"> & LabeledInput;
10
11
  export declare const InputWrapper: React.FC<InputWrapperProps>;
@@ -0,0 +1,37 @@
1
+ # InputNumber — Agent Usage Notes
2
+
3
+ Import:
4
+
5
+ ```tsx
6
+ import { InputNumber } from "@stamcat/craftsman/InputNumber";
7
+ ```
8
+
9
+ Props:
10
+
11
+ - Extends `Input` props (`Omit<InputProps, "type" | "endAdornment">`).
12
+ - `type?: "number"` (fixed, default: `"number"`)
13
+ - `onDecrement?: (e: React.MouseEvent<HTMLButtonElement>) => void`
14
+ - `onIncrement?: (e: React.MouseEvent<HTMLButtonElement>) => void`
15
+ - `iconIncrement?: React.ReactNode` — overrides the icon rendered in the increment button.
16
+ - `iconDecrement?: React.ReactNode` — overrides the icon rendered in the decrement button.
17
+
18
+ Behavior notes:
19
+
20
+ - Renders an `Input` with a decrement button as `preAdornment` and an increment button as `endAdornment`.
21
+ - Clicking a button calls the native `stepDown()` / `stepUp()` on the underlying `<input type="number">` (honoring `min`, `max`, and `step`), then dispatches a native `input` event so a controlled `onChange` fires exactly like a real number input's spinner.
22
+ - `onDecrement` / `onIncrement` are optional callbacks invoked after the native step — they do not replace `value`/`onChange` control.
23
+ - Use standard controlled `<input type="number">` patterns (`value` + `onChange`) to own the number's state.
24
+
25
+ Example:
26
+
27
+ ```tsx
28
+ const [count, setCount] = useState(0);
29
+
30
+ <InputNumber
31
+ label="Quantity"
32
+ value={count}
33
+ min={0}
34
+ max={10}
35
+ onChange={(e) => setCount(Number(e.currentTarget.value))}
36
+ />
37
+ ```
@@ -0,0 +1 @@
1
+ @layer craftsman-base;@layer craftsman-component{.inputNumber.input-wrapper[data-label-position=inside] .input-label{left:40px}.inputNumber .input-field{gap:calc(var(--w-gutter) * .5)}.inputNumber .input-field[data-has-end-adornment=true]>.input{padding-right:calc(var(--w-gutter) * .75)}.inputNumber .input-field[data-has-pre-adornment=true]>.input{padding-left:calc(var(--w-gutter) * .75)}.inputNumber .input-end-adornment,.inputNumber .input-pre-adornment{position:unset;transform:unset;top:unset}}
@@ -0,0 +1,10 @@
1
+ import { TextInputType } from '../../utilities/types';
2
+ import { InputProps } from '../Input/Input';
3
+ export type InputNumberProps = React.ComponentProps<"input"> & {} & Omit<InputProps, "type" | "endAdornment"> & {
4
+ type?: Extract<TextInputType, "number">;
5
+ onDecrement?: (e: React.MouseEvent<HTMLButtonElement>) => void;
6
+ onIncrement?: (e: React.MouseEvent<HTMLButtonElement>) => void;
7
+ iconIncrement?: React.ReactNode;
8
+ iconDecrement?: React.ReactNode;
9
+ };
10
+ export declare const InputNumber: React.FC<InputNumberProps>;
@@ -0,0 +1,29 @@
1
+ @use "../../styles/global/components/input";
2
+ @use "../../styles/utilities/_functions" as u;
3
+ @use "../../styles/utilities/_placeholders";
4
+
5
+ @layer craftsman-component {
6
+ .inputNumber {
7
+ &.input-wrapper[data-label-position=inside] .input-label {
8
+ left: 40px;
9
+ }
10
+ .input-field {
11
+ gap: #{u.width("gutter", 0.5)};
12
+ }
13
+ .input-field[data-has-end-adornment=true] {
14
+ & > .input {
15
+ padding-right: #{u.width("gutter", 0.75)};
16
+ }
17
+ }
18
+ .input-field[data-has-pre-adornment=true] {
19
+ & > .input {
20
+ padding-left: #{u.width("gutter", 0.75)};
21
+ }
22
+ }
23
+ .input-end-adornment, .input-pre-adornment {
24
+ position: unset;
25
+ transform: unset;
26
+ top: unset;
27
+ }
28
+ }
29
+ }
@@ -0,0 +1,36 @@
1
+ "use client";
2
+ import { Button as e } from "../Button/Button.esm.js";
3
+ import { Input as t } from "../Input/Input2.esm.js";
4
+ import './InputNumber.css';/* empty css */
5
+ import n from "clsx";
6
+ import { jsx as r } from "react/jsx-runtime";
7
+ import { useRef as i } from "react";
8
+ import { IoAddCircleOutline as a, IoRemoveCircleOutline as o } from "react-icons/io5";
9
+ //#region src/components/InputNumber/InputNumber.tsx
10
+ var s = ({ type: s = "number", className: c, iconIncrement: l, iconDecrement: u, onDecrement: d, onIncrement: f, ...p }) => {
11
+ let m = i(null);
12
+ return /* @__PURE__ */ r(t, {
13
+ ref: m,
14
+ className: n("inputNumber", c),
15
+ preAdornment: /* @__PURE__ */ r(e, {
16
+ variant: "text",
17
+ onClick: (e) => {
18
+ let t = m.current;
19
+ t && (t.stepDown(), t.dispatchEvent(new Event("input", { bubbles: !0 }))), d?.(e);
20
+ },
21
+ children: l || /* @__PURE__ */ r(o, { size: "26" })
22
+ }),
23
+ endAdornment: /* @__PURE__ */ r(e, {
24
+ variant: "text",
25
+ onClick: (e) => {
26
+ let t = m.current;
27
+ t && (t.stepUp(), t.dispatchEvent(new Event("input", { bubbles: !0 }))), f?.(e);
28
+ },
29
+ children: u || /* @__PURE__ */ r(a, { size: "26" })
30
+ }),
31
+ ...p,
32
+ type: s
33
+ });
34
+ };
35
+ //#endregion
36
+ export { s as InputNumber };
@@ -0,0 +1,29 @@
1
+ # InputPassword — Agent Usage Notes
2
+
3
+ Import:
4
+
5
+ ```tsx
6
+ import { InputPassword } from "@stamcat/craftsman/InputPassword";
7
+ ```
8
+
9
+ Props:
10
+
11
+ - Extends `Input` props, with `type` constrained to password mode.
12
+ - Includes all label, error, required, and wrapper style props from `Input`.
13
+
14
+ Behavior notes:
15
+
16
+ - Built on top of `Input` and adds an internal password visibility state.
17
+ - Renders an in-field show/hide toggle button.
18
+ - Toggle is accessible: real button element, keyboard operable, and updates `aria-label` + `aria-pressed`.
19
+ - Use this component for password fields instead of `Input type="password"`.
20
+
21
+ Example:
22
+
23
+ ```tsx
24
+ <InputPassword
25
+ label="Password"
26
+ placeholder="Enter your password"
27
+ autoComplete="current-password"
28
+ />
29
+ ```
@@ -1,5 +1,5 @@
1
1
  import { TextInputType } from '../../utilities/types';
2
- import { InputProps } from './Input';
2
+ import { InputProps } from '../Input/Input';
3
3
  export type InputPasswordProps = React.ComponentProps<"input"> & {} & Omit<InputProps, "type" | "endAdornment"> & {
4
4
  type?: Extract<TextInputType, "password">;
5
5
  };
@@ -0,0 +1,30 @@
1
+ "use client";
2
+ import { Button as e } from "../Button/Button.esm.js";
3
+ import { Input as t } from "../Input/Input2.esm.js";
4
+ import n from "clsx";
5
+ import { jsx as r } from "react/jsx-runtime";
6
+ import { useState as i } from "react";
7
+ import { ImEye as a, ImEyeBlocked as o } from "react-icons/im";
8
+ //#region src/components/InputPassword/InputPassword.tsx
9
+ var s = ({ visible: t, onToggle: n }) => /* @__PURE__ */ r(e, {
10
+ type: "button",
11
+ variant: "text",
12
+ onClick: n,
13
+ "aria-label": t ? "Hide password" : "Show password",
14
+ "aria-pressed": t,
15
+ className: "input-view-toggle",
16
+ children: r(t ? a : o, { size: 16 })
17
+ }), c = ({ type: e = "password", className: a, ...o }) => {
18
+ let [c, l] = i(!1), u = c ? "text" : e;
19
+ return /* @__PURE__ */ r(t, {
20
+ className: n("inputPassword", a),
21
+ ...o,
22
+ type: u,
23
+ endAdornment: /* @__PURE__ */ r(s, {
24
+ visible: c,
25
+ onToggle: () => l((e) => !e)
26
+ })
27
+ });
28
+ };
29
+ //#endregion
30
+ export { c as InputPassword };
@@ -0,0 +1,35 @@
1
+ # InputPhone — Agent Usage Notes
2
+
3
+ Import:
4
+
5
+ ```tsx
6
+ import { InputPhone } from "@stamcat/craftsman/InputPhone";
7
+ ```
8
+
9
+ Props:
10
+
11
+ - Extends `PhoneInputProps` from `react-international-phone`.
12
+ - `label?: string | ReactNode`
13
+ - `labelPosition?: "top" | "left" | "bottom" | "right" | "inside" | "hidden"` (default: `"top"`)
14
+ - `error?: string | boolean | ReactNode`
15
+ - `required?: boolean`
16
+ - `defaultCountry?: string` (default: `"us"`)
17
+ - `preferredCountries?: string[]`
18
+ - `endAdornment?: ReactNode`
19
+
20
+ Behavior notes:
21
+
22
+ - Powered by `react-international-phone` for i18n-aware phone number formatting.
23
+ - Country selector dropdown opens below the field; ensure the container has at least 350px of vertical space.
24
+ - Use `preferredCountries` to surface commonly used countries at the top of the dropdown.
25
+
26
+ Example:
27
+
28
+ ```tsx
29
+ <InputPhone
30
+ label="Phone Number"
31
+ defaultCountry="us"
32
+ preferredCountries={["us", "gb", "ca"]}
33
+ required
34
+ />
35
+ ```