@recursica/mui-adapter 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (212) hide show
  1. package/ARCHITECTURE.md +15 -0
  2. package/CHANGELOG.md +15 -0
  3. package/SETUP.md +77 -0
  4. package/USAGE.md +55 -0
  5. package/dist/mui-adapter.cjs +74 -1
  6. package/dist/mui-adapter.cjs.map +1 -1
  7. package/dist/mui-adapter.css +1 -1
  8. package/dist/mui-adapter.js +6863 -205
  9. package/dist/mui-adapter.js.map +1 -1
  10. package/dist/src/components/Accordion/Accordion.d.ts +43 -2
  11. package/dist/src/components/AssistiveElement/AssistiveElement.d.ts +6 -2
  12. package/dist/src/components/Autocomplete/Autocomplete.d.ts +12 -2
  13. package/dist/src/components/Avatar/Avatar.d.ts +10 -3
  14. package/dist/src/components/Badge/Badge.d.ts +10 -3
  15. package/dist/src/components/Breadcrumb/Breadcrumb.d.ts +9 -3
  16. package/dist/src/components/Button/Button.d.ts +2 -17
  17. package/dist/src/components/Card/Card.d.ts +38 -3
  18. package/dist/src/components/Checkbox/Checkbox.d.ts +13 -2
  19. package/dist/src/components/Checkbox/CheckboxGroup.d.ts +18 -0
  20. package/dist/src/components/Checkbox/index.d.ts +5 -1
  21. package/dist/src/components/Chip/Chip.d.ts +9 -2
  22. package/dist/src/components/Container/Container.d.ts +1 -5
  23. package/dist/src/components/DatePicker/DatePicker.d.ts +2 -1
  24. package/dist/src/components/Dropdown/Dropdown.d.ts +12 -2
  25. package/dist/src/components/Flex/Flex.d.ts +2 -22
  26. package/dist/src/components/FormControlLayout/FormControlLayout.d.ts +5 -2
  27. package/dist/src/components/FormControlWrapper/FormControlWrapper.d.ts +9 -2
  28. package/dist/src/components/Group/Group.d.ts +2 -7
  29. package/dist/src/components/HoverCard/HoverCard.d.ts +28 -2
  30. package/dist/src/components/Label/Label.d.ts +6 -2
  31. package/dist/src/components/Link/Link.d.ts +2 -6
  32. package/dist/src/components/Loader/Loader.d.ts +2 -7
  33. package/dist/src/components/Menu/Menu.d.ts +25 -3
  34. package/dist/src/components/Modal/Modal.d.ts +37 -2
  35. package/dist/src/components/NumberInput/NumberInput.d.ts +12 -2
  36. package/dist/src/components/Pagination/Pagination.d.ts +12 -3
  37. package/dist/src/components/Pagination/Pagination.icons.d.ts +8 -0
  38. package/dist/src/components/Panel/Panel.d.ts +52 -3
  39. package/dist/src/components/Radio/Radio.d.ts +13 -3
  40. package/dist/src/components/Radio/RadioGroup.d.ts +9 -0
  41. package/dist/src/components/ReadOnlyField/ReadOnlyBooleanField.d.ts +5 -0
  42. package/dist/src/components/ReadOnlyField/ReadOnlyField.d.ts +4 -2
  43. package/dist/src/components/ReadOnlyField/ReadOnlySwitchField.d.ts +5 -0
  44. package/dist/src/components/ReadOnlyField/ReadOnlyTextField.d.ts +8 -0
  45. package/dist/src/components/ReadOnlyField/WithReadOnlyWrapper.d.ts +28 -0
  46. package/dist/src/components/ReadOnlyField/index.d.ts +1 -0
  47. package/dist/src/components/SegmentedControl/SegmentedControl.d.ts +21 -3
  48. package/dist/src/components/Slider/Slider.d.ts +18 -2
  49. package/dist/src/components/Stack/Stack.d.ts +2 -5
  50. package/dist/src/components/Stepper/Stepper.d.ts +41 -2
  51. package/dist/src/components/Switch/Switch.d.ts +10 -3
  52. package/dist/src/components/Switch/SwitchGroup.d.ts +13 -0
  53. package/dist/src/components/Table/Table.d.ts +2 -1
  54. package/dist/src/components/Tabs/Tabs.d.ts +20 -3
  55. package/dist/src/components/Text/Text.d.ts +2 -16
  56. package/dist/src/components/TextArea/TextArea.d.ts +12 -2
  57. package/dist/src/components/TextField/TextField.d.ts +12 -2
  58. package/dist/src/components/TimePicker/TimePicker.d.ts +2 -1
  59. package/dist/src/components/Timeline/Timeline.d.ts +15 -2
  60. package/dist/src/components/Timeline/TimelineItem.d.ts +18 -0
  61. package/dist/src/components/Title/Title.d.ts +2 -15
  62. package/dist/src/components/Toast/Toast.d.ts +20 -2
  63. package/dist/src/components/Tooltip/Tooltip.d.ts +28 -3
  64. package/dist/src/components/TransferList/TransferList.d.ts +2 -1
  65. package/dist/src/components/Typography/Typography.d.ts +1 -1
  66. package/dist/src/utils/RequireAccessibleLabel.d.ts +1 -18
  67. package/dist/src/utils/filterStylingProps.d.ts +1 -11
  68. package/llms.txt +16 -0
  69. package/package.json +14 -3
  70. package/src/components/Accordion/Accordion.module.css +294 -56
  71. package/src/components/Accordion/Accordion.stories.tsx +131 -21
  72. package/src/components/Accordion/Accordion.tsx +260 -5
  73. package/src/components/AssistiveElement/AssistiveElement.module.css +114 -20
  74. package/src/components/AssistiveElement/AssistiveElement.stories.tsx +60 -20
  75. package/src/components/AssistiveElement/AssistiveElement.tsx +81 -5
  76. package/src/components/Autocomplete/Autocomplete.module.css +319 -42
  77. package/src/components/Autocomplete/Autocomplete.stories.tsx +175 -23
  78. package/src/components/Autocomplete/Autocomplete.tsx +181 -6
  79. package/src/components/Avatar/Avatar.module.css +343 -73
  80. package/src/components/Avatar/Avatar.stories.tsx +94 -22
  81. package/src/components/Avatar/Avatar.tsx +99 -6
  82. package/src/components/Badge/Badge.module.css +127 -29
  83. package/src/components/Badge/Badge.stories.tsx +65 -22
  84. package/src/components/Badge/Badge.tsx +67 -6
  85. package/src/components/Breadcrumb/Breadcrumb.module.css +25 -5
  86. package/src/components/Breadcrumb/Breadcrumb.stories.tsx +57 -22
  87. package/src/components/Breadcrumb/Breadcrumb.tsx +59 -6
  88. package/src/components/Button/Button.module.css +19 -61
  89. package/src/components/Button/Button.stories.tsx +24 -23
  90. package/src/components/Button/Button.tsx +7 -18
  91. package/src/components/Card/Card.module.css +154 -38
  92. package/src/components/Card/Card.stories.tsx +117 -19
  93. package/src/components/Card/Card.tsx +181 -5
  94. package/src/components/Checkbox/Checkbox.module.css +249 -39
  95. package/src/components/Checkbox/Checkbox.stories.tsx +81 -19
  96. package/src/components/Checkbox/Checkbox.tsx +246 -5
  97. package/src/components/Checkbox/CheckboxGroup.stories.tsx +139 -0
  98. package/src/components/Checkbox/CheckboxGroup.tsx +137 -0
  99. package/src/components/Checkbox/index.ts +6 -1
  100. package/src/components/Chip/Chip.module.css +246 -43
  101. package/src/components/Chip/Chip.stories.tsx +101 -21
  102. package/src/components/Chip/Chip.tsx +136 -6
  103. package/src/components/Container/Container.stories.tsx +103 -20
  104. package/src/components/Container/Container.tsx +1 -13
  105. package/src/components/DatePicker/DatePicker.stories.tsx +125 -19
  106. package/src/components/DatePicker/DatePicker.tsx +3 -1
  107. package/src/components/Dropdown/Dropdown.module.css +291 -41
  108. package/src/components/Dropdown/Dropdown.stories.tsx +80 -21
  109. package/src/components/Dropdown/Dropdown.tsx +180 -6
  110. package/src/components/FileInput/FileInput.stories.tsx +2 -19
  111. package/src/components/FileUpload/FileUpload.stories.tsx +2 -19
  112. package/src/components/Flex/Flex.stories.tsx +113 -20
  113. package/src/components/Flex/Flex.tsx +16 -26
  114. package/src/components/FormControlLayout/FormControlLayout.module.css +92 -0
  115. package/src/components/FormControlLayout/FormControlLayout.stories.tsx +67 -20
  116. package/src/components/FormControlLayout/FormControlLayout.tsx +69 -4
  117. package/src/components/FormControlWrapper/FormControlWrapper.module.css +87 -0
  118. package/src/components/FormControlWrapper/FormControlWrapper.stories.tsx +116 -22
  119. package/src/components/FormControlWrapper/FormControlWrapper.tsx +126 -6
  120. package/src/components/Group/Group.stories.tsx +6 -30
  121. package/src/components/Group/Group.tsx +14 -9
  122. package/src/components/HoverCard/HoverCard.module.css +90 -22
  123. package/src/components/HoverCard/HoverCard.stories.tsx +158 -21
  124. package/src/components/HoverCard/HoverCard.tsx +147 -5
  125. package/src/components/Label/Label.module.css +140 -35
  126. package/src/components/Label/Label.stories.tsx +108 -21
  127. package/src/components/Label/Label.tsx +82 -5
  128. package/src/components/Link/Link.module.css +4 -3
  129. package/src/components/Link/Link.stories.tsx +2 -8
  130. package/src/components/Link/Link.tsx +1 -5
  131. package/src/components/Loader/Loader.module.css +1 -2
  132. package/src/components/Loader/Loader.tsx +1 -7
  133. package/src/components/Menu/IMPLEMENTATION_NOTES.md +4 -0
  134. package/src/components/Menu/Menu.module.css +285 -51
  135. package/src/components/Menu/Menu.stories.tsx +229 -25
  136. package/src/components/Menu/Menu.tsx +73 -6
  137. package/src/components/Modal/Modal.module.css +171 -35
  138. package/src/components/Modal/Modal.stories.tsx +66 -22
  139. package/src/components/Modal/Modal.tsx +215 -5
  140. package/src/components/NumberInput/NumberInput.module.css +276 -42
  141. package/src/components/NumberInput/NumberInput.stories.tsx +83 -20
  142. package/src/components/NumberInput/NumberInput.tsx +136 -6
  143. package/src/components/Pagination/IMPLEMENTATION_NOTES.md +3 -0
  144. package/src/components/Pagination/Pagination.icons.tsx +66 -0
  145. package/src/components/Pagination/Pagination.module.css +234 -20
  146. package/src/components/Pagination/Pagination.stories.tsx +34 -21
  147. package/src/components/Pagination/Pagination.tsx +74 -6
  148. package/src/components/Panel/Panel.module.css +206 -38
  149. package/src/components/Panel/Panel.stories.tsx +214 -22
  150. package/src/components/Panel/Panel.tsx +130 -5
  151. package/src/components/Radio/Radio.module.css +235 -37
  152. package/src/components/Radio/Radio.stories.tsx +77 -19
  153. package/src/components/Radio/Radio.tsx +210 -5
  154. package/src/components/Radio/RadioGroup.stories.tsx +117 -0
  155. package/src/components/Radio/RadioGroup.tsx +125 -0
  156. package/src/components/ReadOnlyField/ReadOnlyBooleanField.tsx +21 -0
  157. package/src/components/ReadOnlyField/ReadOnlyField.module.css +53 -15
  158. package/src/components/ReadOnlyField/ReadOnlyField.stories.tsx +147 -19
  159. package/src/components/ReadOnlyField/ReadOnlyField.tsx +105 -5
  160. package/src/components/ReadOnlyField/ReadOnlySwitchField.tsx +21 -0
  161. package/src/components/ReadOnlyField/ReadOnlyTextField.tsx +48 -0
  162. package/src/components/ReadOnlyField/WithReadOnlyWrapper.tsx +93 -0
  163. package/src/components/ReadOnlyField/index.ts +1 -0
  164. package/src/components/SegmentedControl/SegmentedControl.module.css +179 -47
  165. package/src/components/SegmentedControl/SegmentedControl.stories.tsx +102 -20
  166. package/src/components/SegmentedControl/SegmentedControl.tsx +140 -6
  167. package/src/components/Slider/Slider.module.css +539 -86
  168. package/src/components/Slider/Slider.stories.tsx +157 -19
  169. package/src/components/Slider/Slider.tsx +283 -5
  170. package/src/components/Stack/Stack.stories.tsx +4 -25
  171. package/src/components/Stack/Stack.tsx +1 -5
  172. package/src/components/Stepper/IMPLEMENTATION_NOTES.md +4 -0
  173. package/src/components/Stepper/Stepper.module.css +410 -71
  174. package/src/components/Stepper/Stepper.stories.tsx +146 -20
  175. package/src/components/Stepper/Stepper.tsx +147 -6
  176. package/src/components/Switch/Switch.module.css +259 -39
  177. package/src/components/Switch/Switch.stories.tsx +98 -19
  178. package/src/components/Switch/Switch.tsx +200 -6
  179. package/src/components/Switch/SwitchGroup.stories.tsx +132 -0
  180. package/src/components/Switch/SwitchGroup.tsx +120 -0
  181. package/src/components/Table/Table.stories.tsx +1 -19
  182. package/src/components/Table/Table.tsx +3 -1
  183. package/src/components/Tabs/IMPLEMENTATION_NOTES.md +4 -0
  184. package/src/components/Tabs/Tabs.module.css +422 -79
  185. package/src/components/Tabs/Tabs.stories.tsx +156 -20
  186. package/src/components/Tabs/Tabs.tsx +86 -6
  187. package/src/components/Text/Text.stories.tsx +5 -17
  188. package/src/components/Text/Text.tsx +1 -15
  189. package/src/components/TextArea/TextArea.module.css +155 -32
  190. package/src/components/TextArea/TextArea.stories.tsx +80 -21
  191. package/src/components/TextArea/TextArea.tsx +146 -6
  192. package/src/components/TextField/TextField.module.css +261 -42
  193. package/src/components/TextField/TextField.stories.tsx +147 -20
  194. package/src/components/TextField/TextField.tsx +169 -6
  195. package/src/components/TimePicker/TimePicker.stories.tsx +2 -19
  196. package/src/components/TimePicker/TimePicker.tsx +3 -1
  197. package/src/components/Timeline/Timeline.module.css +365 -76
  198. package/src/components/Timeline/Timeline.stories.tsx +114 -21
  199. package/src/components/Timeline/Timeline.tsx +83 -5
  200. package/src/components/Timeline/TimelineItem.tsx +90 -0
  201. package/src/components/Title/Title.stories.tsx +0 -18
  202. package/src/components/Title/Title.tsx +1 -7
  203. package/src/components/Toast/Toast.module.css +166 -28
  204. package/src/components/Toast/Toast.stories.tsx +54 -22
  205. package/src/components/Toast/Toast.tsx +124 -5
  206. package/src/components/Tooltip/Tooltip.module.css +89 -24
  207. package/src/components/Tooltip/Tooltip.stories.tsx +152 -22
  208. package/src/components/Tooltip/Tooltip.tsx +88 -5
  209. package/src/components/TransferList/TransferList.stories.tsx +1 -19
  210. package/src/components/TransferList/TransferList.tsx +3 -1
  211. package/src/utils/RequireAccessibleLabel.ts +1 -12
  212. package/src/utils/filterStylingProps.ts +7 -20
@@ -1,8 +1,218 @@
1
- import React from "react";
2
- import "./Modal.module.css";
1
+ import React, { forwardRef } from "react";
2
+ import {
3
+ Dialog as MuiDialog,
4
+ type DialogProps as MuiDialogProps,
5
+ DialogTitle as MuiDialogTitle,
6
+ type DialogTitleProps as MuiDialogTitleProps,
7
+ DialogContent as MuiDialogContent,
8
+ type DialogContentProps as MuiDialogContentProps,
9
+ DialogActions as MuiDialogActions,
10
+ type DialogActionsProps as MuiDialogActionsProps,
11
+ IconButton as MuiIconButton,
12
+ } from "@mui/material";
13
+ import {
14
+ filterStylingProps,
15
+ type RecursicaOverStyled,
16
+ } from "../../utils/filterStylingProps";
17
+ import styles from "./Modal.module.css";
3
18
 
4
- export type ModalProps = React.HTMLAttributes<HTMLDivElement>;
19
+ // ============================================================
20
+ // MODAL ROOT (Dialog)
21
+ // ============================================================
5
22
 
6
- export const Modal: React.FC<ModalProps> = (props) => {
7
- return <div {...props}>Modal</div>;
23
+ import { type RecursicaModalProps } from "@recursica/adapter-common";
24
+
25
+ export type ModalProps = RecursicaOverStyled<
26
+ Omit<MuiDialogProps, "size" | "radius" | "shadow" | "open"> &
27
+ RecursicaModalProps
28
+ >;
29
+
30
+ const CloseIcon = () => (
31
+ <svg
32
+ xmlns="http://www.w3.org/2000/svg"
33
+ width="20"
34
+ height="20"
35
+ viewBox="0 0 24 24"
36
+ fill="none"
37
+ stroke="currentColor"
38
+ strokeWidth="2"
39
+ strokeLinecap="round"
40
+ strokeLinejoin="round"
41
+ >
42
+ <path d="M18 6L6 18M6 6l12 12" />
43
+ </svg>
44
+ );
45
+
46
+ const ModalRoot = forwardRef<HTMLDivElement, ModalProps>(function ModalRoot(
47
+ {
48
+ overStyled = false,
49
+ opened = false,
50
+ withCloseButton = true,
51
+ title,
52
+ children,
53
+ onClose,
54
+ className,
55
+ ...rest
56
+ },
57
+ ref,
58
+ ) {
59
+ const sanitizedProps = filterStylingProps(rest, overStyled);
60
+
61
+ let footer: React.ReactNode = null;
62
+ const bodyChildren: React.ReactNode[] = [];
63
+
64
+ React.Children.forEach(children, (child) => {
65
+ if (
66
+ React.isValidElement(child) &&
67
+ (child.type === ModalFooter ||
68
+ (child.type as any)?.displayName === "Modal.Footer")
69
+ ) {
70
+ footer = child;
71
+ } else {
72
+ bodyChildren.push(child);
73
+ }
74
+ });
75
+
76
+ return (
77
+ <MuiDialog
78
+ ref={ref}
79
+ className={`${styles.root} ${className || ""}`}
80
+ classes={{
81
+ paper: styles.inner,
82
+ }}
83
+ {...(sanitizedProps as MuiDialogProps)}
84
+ open={opened || (sanitizedProps as any).open}
85
+ onClose={onClose}
86
+ >
87
+ {(title || withCloseButton) && (
88
+ <div className={styles.header}>
89
+ {title && <div className={styles.title}>{title}</div>}
90
+ {withCloseButton && (
91
+ <MuiIconButton
92
+ onClick={(e) => onClose?.(e, "backdropClick")}
93
+ className={styles.close}
94
+ >
95
+ <CloseIcon />
96
+ </MuiIconButton>
97
+ )}
98
+ </div>
99
+ )}
100
+ <ModalBody>{bodyChildren}</ModalBody>
101
+ {footer}
102
+ </MuiDialog>
103
+ );
104
+ });
105
+
106
+ ModalRoot.displayName = "Modal";
107
+
108
+ // ============================================================
109
+ // MODAL TITLE (DialogTitle)
110
+ // ============================================================
111
+
112
+ export type ModalTitleProps = RecursicaOverStyled<MuiDialogTitleProps>;
113
+
114
+ const ModalTitle = forwardRef<HTMLDivElement, ModalTitleProps>(
115
+ function ModalTitle({ overStyled = false, className, ...rest }, ref) {
116
+ const sanitizedProps = filterStylingProps(rest, overStyled);
117
+
118
+ return (
119
+ <MuiDialogTitle
120
+ ref={ref as any}
121
+ className={`${styles.title} ${className || ""}`}
122
+ {...(sanitizedProps as MuiDialogTitleProps)}
123
+ />
124
+ );
125
+ },
126
+ );
127
+
128
+ ModalTitle.displayName = "Modal.Title";
129
+
130
+ // ============================================================
131
+ // MODAL BODY (DialogContent)
132
+ // ============================================================
133
+
134
+ export type ModalBodyProps = RecursicaOverStyled<MuiDialogContentProps>;
135
+
136
+ const ModalBody = forwardRef<HTMLDivElement, ModalBodyProps>(function ModalBody(
137
+ { overStyled = false, className, children, ...rest },
138
+ ref,
139
+ ) {
140
+ const sanitizedProps = filterStylingProps(rest, overStyled);
141
+ const internalRef = React.useRef<HTMLDivElement>(null);
142
+ const [scrolledTop, setScrolledTop] = React.useState(false);
143
+ const [scrolledBottom, setScrolledBottom] = React.useState(false);
144
+
145
+ const checkScroll = React.useCallback(() => {
146
+ if (internalRef.current) {
147
+ const { scrollTop, scrollHeight, clientHeight } = internalRef.current;
148
+ setScrolledTop(scrollTop > 0);
149
+ setScrolledBottom(Math.ceil(scrollTop + clientHeight) < scrollHeight);
150
+ }
151
+ }, []);
152
+
153
+ React.useEffect(() => {
154
+ checkScroll();
155
+ window.addEventListener("resize", checkScroll);
156
+ return () => window.removeEventListener("resize", checkScroll);
157
+ }, [checkScroll, children]);
158
+
159
+ return (
160
+ <MuiDialogContent
161
+ ref={(node) => {
162
+ if (typeof ref === "function") ref(node as any);
163
+ else if (ref)
164
+ (ref as React.MutableRefObject<HTMLDivElement | null>).current =
165
+ node as any;
166
+ if (internalRef)
167
+ (
168
+ internalRef as React.MutableRefObject<HTMLDivElement | null>
169
+ ).current = node as HTMLDivElement;
170
+ }}
171
+ onScroll={() => checkScroll()}
172
+ data-scrolled-top={scrolledTop || undefined}
173
+ data-scrolled-bottom={scrolledBottom || undefined}
174
+ className={`${styles.content} ${styles.scrollArea} ${className || ""}`}
175
+ {...(sanitizedProps as MuiDialogContentProps)}
176
+ >
177
+ {children}
178
+ </MuiDialogContent>
179
+ );
180
+ });
181
+
182
+ ModalBody.displayName = "Modal.Body";
183
+
184
+ // ============================================================
185
+ // MODAL FOOTER (DialogActions)
186
+ // ============================================================
187
+
188
+ export type ModalFooterProps = RecursicaOverStyled<MuiDialogActionsProps>;
189
+
190
+ const ModalFooter = forwardRef<HTMLDivElement, ModalFooterProps>(
191
+ function ModalFooter({ overStyled = false, className, ...rest }, ref) {
192
+ const sanitizedProps = filterStylingProps(rest, overStyled);
193
+
194
+ return (
195
+ <MuiDialogActions
196
+ ref={ref as any}
197
+ className={`${styles.footer} ${className || ""}`}
198
+ {...(sanitizedProps as MuiDialogActionsProps)}
199
+ />
200
+ );
201
+ },
202
+ );
203
+
204
+ ModalFooter.displayName = "Modal.Footer";
205
+
206
+ // ============================================================
207
+ // EXPORT COMPOSITION
208
+ // ============================================================
209
+
210
+ export const Modal = ModalRoot as typeof ModalRoot & {
211
+ Title: typeof ModalTitle;
212
+ Body: typeof ModalBody;
213
+ Footer: typeof ModalFooter;
8
214
  };
215
+
216
+ Modal.Title = ModalTitle;
217
+ Modal.Body = ModalBody;
218
+ Modal.Footer = ModalFooter;
@@ -1,47 +1,281 @@
1
1
  /* EXEMPTIONS:
2
- This component is a placeholder stub. Once fully implemented, its specific
3
- tokens will be fully wired up to direct styles. */
4
-
5
- /* recursica-ignore: --recursica_ui-kit_components_number-input_properties_border-radius */
6
- /* recursica-ignore: --recursica_ui-kit_components_number-input_properties_horizontal-padding */
7
- /* recursica-ignore: --recursica_ui-kit_components_number-input_properties_icon-size */
8
- /* recursica-ignore: --recursica_ui-kit_components_number-input_properties_icon-text-gap */
9
- /* recursica-ignore: --recursica_ui-kit_components_number-input_properties_max-width */
10
- /* recursica-ignore: --recursica_ui-kit_components_number-input_properties_min-height */
11
- /* recursica-ignore: --recursica_ui-kit_components_number-input_properties_min-width */
12
- /* recursica-ignore: --recursica_ui-kit_components_number-input_properties_placeholder-opacity */
13
- /* recursica-ignore: --recursica_ui-kit_components_number-input_properties_text_font-family */
14
- /* recursica-ignore: --recursica_ui-kit_components_number-input_properties_text_font-size */
15
- /* recursica-ignore: --recursica_ui-kit_components_number-input_properties_text_font-style */
16
- /* recursica-ignore: --recursica_ui-kit_components_number-input_properties_text_font-weight */
17
- /* recursica-ignore: --recursica_ui-kit_components_number-input_properties_text_letter-spacing */
18
- /* recursica-ignore: --recursica_ui-kit_components_number-input_properties_text_line-height */
19
- /* recursica-ignore: --recursica_ui-kit_components_number-input_properties_text_text-decoration */
20
- /* recursica-ignore: --recursica_ui-kit_components_number-input_properties_text_text-transform */
21
- /* recursica-ignore: --recursica_ui-kit_components_number-input_properties_vertical-padding */
22
- /* recursica-ignore: --recursica_ui-kit_components_number-input_variants_layouts_side-by-side_properties_top-bottom-margin */
23
- /* recursica-ignore: --recursica_ui-kit_components_number-input_variants_layouts_stacked_properties_top-bottom-margin */
2
+ - state-specific border-size variables are ignored because the input box uses a uniform static boundary to prevent
3
+ unexpected layout shifts or flickering when switching between active, focused, or error states. */
24
4
  /* recursica-ignore: --recursica_ui-kit_components_number-input_variants_states_default_properties_border-size */
25
- /* recursica-ignore: --recursica_ui-kit_components_number-input_variants_states_default_properties_colors_background */
26
- /* recursica-ignore: --recursica_ui-kit_components_number-input_variants_states_default_properties_colors_border-color */
27
- /* recursica-ignore: --recursica_ui-kit_components_number-input_variants_states_default_properties_colors_leading-icon */
28
- /* recursica-ignore: --recursica_ui-kit_components_number-input_variants_states_default_properties_colors_text */
29
- /* recursica-ignore: --recursica_ui-kit_components_number-input_variants_states_default_properties_colors_trailing-icon */
30
5
  /* recursica-ignore: --recursica_ui-kit_components_number-input_variants_states_disabled_properties_border-size */
31
- /* recursica-ignore: --recursica_ui-kit_components_number-input_variants_states_disabled_properties_colors_background */
32
- /* recursica-ignore: --recursica_ui-kit_components_number-input_variants_states_disabled_properties_colors_border-color */
33
- /* recursica-ignore: --recursica_ui-kit_components_number-input_variants_states_disabled_properties_colors_leading-icon */
34
- /* recursica-ignore: --recursica_ui-kit_components_number-input_variants_states_disabled_properties_colors_text */
35
- /* recursica-ignore: --recursica_ui-kit_components_number-input_variants_states_disabled_properties_colors_trailing-icon */
36
6
  /* recursica-ignore: --recursica_ui-kit_components_number-input_variants_states_error_properties_border-size */
37
- /* recursica-ignore: --recursica_ui-kit_components_number-input_variants_states_error_properties_colors_background */
38
- /* recursica-ignore: --recursica_ui-kit_components_number-input_variants_states_error_properties_colors_border-color */
39
- /* recursica-ignore: --recursica_ui-kit_components_number-input_variants_states_error_properties_colors_leading-icon */
40
- /* recursica-ignore: --recursica_ui-kit_components_number-input_variants_states_error_properties_colors_text */
41
- /* recursica-ignore: --recursica_ui-kit_components_number-input_variants_states_error_properties_colors_trailing-icon */
42
7
  /* recursica-ignore: --recursica_ui-kit_components_number-input_variants_states_focus_properties_border-size */
43
- /* recursica-ignore: --recursica_ui-kit_components_number-input_variants_states_focus_properties_colors_background */
44
- /* recursica-ignore: --recursica_ui-kit_components_number-input_variants_states_focus_properties_colors_border-color */
45
- /* recursica-ignore: --recursica_ui-kit_components_number-input_variants_states_focus_properties_colors_leading-icon */
46
- /* recursica-ignore: --recursica_ui-kit_components_number-input_variants_states_focus_properties_colors_text */
47
- /* recursica-ignore: --recursica_ui-kit_components_number-input_variants_states_focus_properties_colors_trailing-icon */
8
+
9
+ /* LAYOUT SPACING OVERRIDES:
10
+ - Sets the --form-control-margin-bottom spacing hook to map component-specific layout tokens. */
11
+ .layoutOverride {
12
+ --form-control-margin-bottom: var(
13
+ --recursica_ui-kit_components_number-input_variants_layouts_stacked_properties_top-bottom-margin
14
+ );
15
+ }
16
+
17
+ .layoutOverride[data-form-layout="side-by-side"] {
18
+ --form-control-margin-bottom: var(
19
+ --recursica_ui-kit_components_number-input_variants_layouts_side-by-side_properties_top-bottom-margin
20
+ );
21
+ }
22
+
23
+ /* HARDCODED VALUES:
24
+ - border-width: 1px. Native geometric boundary for the input box.
25
+ - border-style: solid. Native structural rendering rule.
26
+ - outline: none. Bypassing browser focus rings to rely strictly on Recursica focus states natively.
27
+ - flex/layout: display: flex on the root wrapper safely encapsulating internal section rendering.
28
+ - Controls: Hardcoded to bypass Mantine's default borders and backgrounds on the increment/decrement arrows.
29
+ */
30
+
31
+ .root {
32
+ display: flex;
33
+ position: relative;
34
+ width: 100%;
35
+ min-height: var(
36
+ --recursica_ui-kit_components_number-input_properties_min-height
37
+ );
38
+
39
+ /* Override Mantine native Input variables governing section spacing padding mathematics safely */
40
+ --input-left-section-size: calc(
41
+ var(
42
+ --recursica_ui-kit_components_number-input_properties_horizontal-padding
43
+ ) +
44
+ var(--recursica_ui-kit_components_number-input_properties_icon-size) +
45
+ var(--recursica_ui-kit_components_number-input_properties_icon-text-gap)
46
+ );
47
+ --input-right-section-size: calc(
48
+ var(
49
+ --recursica_ui-kit_components_number-input_properties_horizontal-padding
50
+ ) +
51
+ var(--recursica_ui-kit_components_number-input_properties_icon-size) +
52
+ var(--recursica_ui-kit_components_number-input_properties_icon-text-gap)
53
+ );
54
+ }
55
+
56
+ .input {
57
+ /* Structural Overrides */
58
+ width: 100%;
59
+ box-sizing: border-box;
60
+ margin: 0;
61
+
62
+ /* Box Geometry */
63
+ min-height: var(
64
+ --recursica_ui-kit_components_number-input_properties_min-height
65
+ );
66
+ padding-top: var(
67
+ --recursica_ui-kit_components_number-input_properties_vertical-padding
68
+ );
69
+ padding-bottom: var(
70
+ --recursica_ui-kit_components_number-input_properties_vertical-padding
71
+ );
72
+ padding-left: var(
73
+ --recursica_ui-kit_components_number-input_properties_horizontal-padding
74
+ );
75
+ padding-right: var(
76
+ --recursica_ui-kit_components_number-input_properties_horizontal-padding
77
+ );
78
+ border-radius: var(
79
+ --recursica_ui-kit_components_number-input_properties_border-radius
80
+ );
81
+ border-width: 1px;
82
+ border-style: solid;
83
+
84
+ /* Strict Typography Unification */
85
+ font-family: var(
86
+ --recursica_ui-kit_components_number-input_properties_text_font-family
87
+ );
88
+ font-size: var(
89
+ --recursica_ui-kit_components_number-input_properties_text_font-size
90
+ );
91
+ font-style: var(
92
+ --recursica_ui-kit_components_number-input_properties_text_font-style
93
+ );
94
+ font-weight: var(
95
+ --recursica_ui-kit_components_number-input_properties_text_font-weight
96
+ );
97
+ letter-spacing: var(
98
+ --recursica_ui-kit_components_number-input_properties_text_letter-spacing
99
+ );
100
+ line-height: var(
101
+ --recursica_ui-kit_components_number-input_properties_text_line-height
102
+ );
103
+ text-decoration: var(
104
+ --recursica_ui-kit_components_number-input_properties_text_text-decoration
105
+ );
106
+ text-transform: var(
107
+ --recursica_ui-kit_components_number-input_properties_text_text-transform
108
+ );
109
+
110
+ /* Base State Default Execution */
111
+ background-color: var(
112
+ --recursica_ui-kit_components_number-input_variants_states_default_properties_colors_background
113
+ );
114
+ border-color: var(
115
+ --recursica_ui-kit_components_number-input_variants_states_default_properties_colors_border-color
116
+ );
117
+ color: var(
118
+ --recursica_ui-kit_components_number-input_variants_states_default_properties_colors_text
119
+ );
120
+
121
+ outline: none;
122
+ }
123
+
124
+ .input::placeholder {
125
+ opacity: var(
126
+ --recursica_ui-kit_components_number-input_properties_placeholder-opacity
127
+ );
128
+ color: inherit;
129
+ }
130
+
131
+ /* Dynamic Padding Overrides */
132
+ .root[data-with-left-section] .input {
133
+ padding-left: var(--input-left-section-size);
134
+ }
135
+
136
+ .root[data-with-right-section] .input {
137
+ padding-right: var(--input-right-section-size);
138
+ }
139
+
140
+ /* Flexible End-Caps (Icons, actions) */
141
+ .section {
142
+ display: flex;
143
+ align-items: center;
144
+ height: 100%;
145
+ }
146
+
147
+ .section[data-position="left"] {
148
+ justify-content: flex-start;
149
+ padding-left: var(
150
+ --recursica_ui-kit_components_number-input_properties_horizontal-padding
151
+ );
152
+ }
153
+
154
+ .section[data-position="right"] {
155
+ justify-content: flex-end;
156
+ padding-right: var(
157
+ --recursica_ui-kit_components_number-input_properties_horizontal-padding
158
+ );
159
+ }
160
+
161
+ .section :global(svg) {
162
+ width: var(--recursica_ui-kit_components_number-input_properties_icon-size);
163
+ height: var(--recursica_ui-kit_components_number-input_properties_icon-size);
164
+ color: var(
165
+ --recursica_ui-kit_components_number-input_variants_states_default_properties_colors_leading-icon
166
+ );
167
+ }
168
+
169
+ .section[data-position="right"] :global(svg) {
170
+ color: var(
171
+ --recursica_ui-kit_components_number-input_variants_states_default_properties_colors_trailing-icon
172
+ );
173
+ }
174
+
175
+ /* -------------------------------------
176
+ CONTROLS (Mantine Specific Up/Down Arrows)
177
+ -------------------------------------- */
178
+
179
+ .controls {
180
+ /* Adjust right padding so controls do not overlap borders */
181
+ padding-right: var(
182
+ --recursica_ui-kit_components_number-input_properties_horizontal-padding
183
+ );
184
+ }
185
+
186
+ .control {
187
+ /* Override Mantine borders for the inner controls */
188
+ border: none;
189
+ background: transparent;
190
+ color: var(
191
+ --recursica_ui-kit_components_number-input_variants_states_default_properties_colors_trailing-icon
192
+ );
193
+ }
194
+
195
+ .control:hover {
196
+ background: transparent;
197
+ }
198
+
199
+ /* -------------------------------------
200
+ STATE CASCADE ARCHITECTURE
201
+ -------------------------------------- */
202
+
203
+ /* Focus State Mapping (Triggered internally via browser pseudo-pseudo-class) */
204
+ .input:focus-within,
205
+ .input:focus {
206
+ border-color: var(
207
+ --recursica_ui-kit_components_number-input_variants_states_focus_properties_colors_border-color
208
+ );
209
+ background-color: var(
210
+ --recursica_ui-kit_components_number-input_variants_states_focus_properties_colors_background
211
+ );
212
+ color: var(
213
+ --recursica_ui-kit_components_number-input_variants_states_focus_properties_colors_text
214
+ );
215
+ }
216
+
217
+ .root:focus-within .section[data-position="left"] :global(svg) {
218
+ color: var(
219
+ --recursica_ui-kit_components_number-input_variants_states_focus_properties_colors_leading-icon
220
+ );
221
+ }
222
+
223
+ .root:focus-within .section[data-position="right"] :global(svg),
224
+ .root:focus-within .control {
225
+ color: var(
226
+ --recursica_ui-kit_components_number-input_variants_states_focus_properties_colors_trailing-icon
227
+ );
228
+ }
229
+
230
+ /* Error State Mapping (Propagated strictly down from the wrapper DOM context) */
231
+ .root[data-error] .input {
232
+ border-color: var(
233
+ --recursica_ui-kit_components_number-input_variants_states_error_properties_colors_border-color
234
+ ) !important;
235
+ background-color: var(
236
+ --recursica_ui-kit_components_number-input_variants_states_error_properties_colors_background
237
+ ) !important;
238
+ color: var(
239
+ --recursica_ui-kit_components_number-input_variants_states_error_properties_colors_text
240
+ ) !important;
241
+ }
242
+
243
+ .root[data-error] .section[data-position="left"] :global(svg) {
244
+ color: var(
245
+ --recursica_ui-kit_components_number-input_variants_states_error_properties_colors_leading-icon
246
+ ) !important;
247
+ }
248
+
249
+ .root[data-error] .section[data-position="right"] :global(svg),
250
+ .root[data-error] .control {
251
+ color: var(
252
+ --recursica_ui-kit_components_number-input_variants_states_error_properties_colors_trailing-icon
253
+ ) !important;
254
+ }
255
+
256
+ /* Disabled State Mapping (Propagated strictly down from the wrapper DOM context) */
257
+ .root[data-disabled] .input {
258
+ border-color: var(
259
+ --recursica_ui-kit_components_number-input_variants_states_disabled_properties_colors_border-color
260
+ ) !important;
261
+ background-color: var(
262
+ --recursica_ui-kit_components_number-input_variants_states_disabled_properties_colors_background
263
+ ) !important;
264
+ color: var(
265
+ --recursica_ui-kit_components_number-input_variants_states_disabled_properties_colors_text
266
+ ) !important;
267
+ cursor: not-allowed;
268
+ }
269
+
270
+ .root[data-disabled] .section[data-position="left"] :global(svg) {
271
+ color: var(
272
+ --recursica_ui-kit_components_number-input_variants_states_disabled_properties_colors_leading-icon
273
+ ) !important;
274
+ }
275
+
276
+ .root[data-disabled] .section[data-position="right"] :global(svg),
277
+ .root[data-disabled] .control {
278
+ color: var(
279
+ --recursica_ui-kit_components_number-input_variants_states_disabled_properties_colors_trailing-icon
280
+ ) !important;
281
+ }
@@ -1,35 +1,98 @@
1
1
  import type { Meta, StoryObj } from "@storybook/react";
2
2
  import { NumberInput } from "./NumberInput";
3
- import { ComingSoon } from "@recursica/storybook-template";
4
3
 
5
4
  const meta: Meta<typeof NumberInput> = {
6
- title: "UI-Kit/🚧 NumberInput",
5
+ title: "UI-Kit/NumberInput",
7
6
  component: NumberInput,
8
7
  tags: ["autodocs"],
9
- parameters: {
10
- controls: {
11
- include: [
12
- "layer",
13
- "withLayer",
14
- "children",
15
- "component",
16
- "variant",
17
- "size",
18
- "icon",
19
- "disabled",
20
- "href",
21
- "onClick",
22
- "onChange",
23
- "value",
24
- "checked",
25
- ],
8
+ argTypes: {
9
+ label: { control: "text" },
10
+ assistiveText: { control: "text" },
11
+ disabled: { control: "boolean" },
12
+ error: { control: "boolean" },
13
+ readOnly: { control: "boolean" },
14
+ required: { control: "boolean" },
15
+ hideControls: { control: "boolean" },
16
+ formLayout: {
17
+ control: "select",
18
+ options: ["stacked", "side-by-side"],
26
19
  },
20
+ labelSize: {
21
+ control: "select",
22
+ options: ["small", "default", "large"],
23
+ },
24
+ checked: { table: { disable: true } },
25
+ defaultChecked: { table: { disable: true } },
26
+ assistiveWithIcon: { table: { disable: true } },
27
+ labelOptionalText: { table: { disable: true } },
28
+ labelWithEditIcon: { table: { disable: true } },
29
+ onLabelEditClick: { table: { disable: true } },
30
+ emptyValueComponent: { table: { disable: true } },
27
31
  },
28
32
  };
29
33
 
30
34
  export default meta;
35
+
31
36
  type Story = StoryObj<typeof NumberInput>;
32
37
 
33
38
  export const Default: Story = {
34
- render: () => <ComingSoon componentName="NumberInput" />,
39
+ args: {
40
+ label: "Amount",
41
+ placeholder: "Enter an amount",
42
+ assistiveText: "Must be greater than 0",
43
+ defaultValue: 10,
44
+ min: 0,
45
+ max: 100,
46
+ },
47
+ };
48
+
49
+ export const SideBySideLayout: Story = {
50
+ args: {
51
+ ...Default.args,
52
+ formLayout: "side-by-side",
53
+ },
54
+ };
55
+
56
+ export const States: Story = {
57
+ render: () => (
58
+ <div
59
+ style={{
60
+ display: "flex",
61
+ flexDirection: "column",
62
+ gap: "1rem",
63
+ maxWidth: 400,
64
+ }}
65
+ >
66
+ <NumberInput label="Default" placeholder="Enter a number" />
67
+ <NumberInput label="Disabled" placeholder="Disabled input" disabled />
68
+ <NumberInput label="Error" placeholder="Error state" error />
69
+ <NumberInput label="Read Only" value={42} readOnly />
70
+ <NumberInput label="Required" required />
71
+ </div>
72
+ ),
73
+ };
74
+
75
+ export const WithLeftIcon: Story = {
76
+ args: {
77
+ label: "Price",
78
+ placeholder: "0.00",
79
+ leftSection: <span>$</span>,
80
+ },
81
+ };
82
+
83
+ export const WithRightIcon: Story = {
84
+ args: {
85
+ label: "Percentage",
86
+ placeholder: "0",
87
+ rightSection: <span>%</span>,
88
+ hideControls: true, // Typically hiding controls if rightSection is occupied
89
+ },
90
+ };
91
+
92
+ export const HiddenControls: Story = {
93
+ args: {
94
+ label: "Zip Code",
95
+ placeholder: "Enter zip code",
96
+ hideControls: true,
97
+ },
35
98
  };