@recursica/mui-adapter 0.6.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 (164) hide show
  1. package/ARCHITECTURE.md +15 -0
  2. package/CHANGELOG.md +6 -0
  3. package/SETUP.md +77 -0
  4. package/USAGE.md +55 -0
  5. package/dist/mui-adapter.cjs +26 -26
  6. package/dist/mui-adapter.cjs.map +1 -1
  7. package/dist/mui-adapter.css +1 -1
  8. package/dist/mui-adapter.js +3721 -3511
  9. package/dist/mui-adapter.js.map +1 -1
  10. package/dist/src/components/Accordion/Accordion.d.ts +9 -29
  11. package/dist/src/components/AssistiveElement/AssistiveElement.d.ts +2 -5
  12. package/dist/src/components/Autocomplete/Autocomplete.d.ts +4 -8
  13. package/dist/src/components/Avatar/Avatar.d.ts +1 -6
  14. package/dist/src/components/Badge/Badge.d.ts +1 -4
  15. package/dist/src/components/Breadcrumb/Breadcrumb.d.ts +2 -3
  16. package/dist/src/components/Button/Button.d.ts +2 -17
  17. package/dist/src/components/Card/Card.d.ts +2 -4
  18. package/dist/src/components/Checkbox/Checkbox.d.ts +4 -6
  19. package/dist/src/components/Checkbox/CheckboxGroup.d.ts +8 -6
  20. package/dist/src/components/Chip/Chip.d.ts +2 -11
  21. package/dist/src/components/Container/Container.d.ts +1 -5
  22. package/dist/src/components/DatePicker/DatePicker.d.ts +2 -1
  23. package/dist/src/components/Dropdown/Dropdown.d.ts +4 -14
  24. package/dist/src/components/Flex/Flex.d.ts +2 -22
  25. package/dist/src/components/FormControlLayout/FormControlLayout.d.ts +2 -7
  26. package/dist/src/components/FormControlWrapper/FormControlWrapper.d.ts +3 -18
  27. package/dist/src/components/Group/Group.d.ts +2 -7
  28. package/dist/src/components/HoverCard/HoverCard.d.ts +13 -39
  29. package/dist/src/components/Label/Label.d.ts +2 -9
  30. package/dist/src/components/Link/Link.d.ts +2 -6
  31. package/dist/src/components/Loader/Loader.d.ts +2 -7
  32. package/dist/src/components/Menu/Menu.d.ts +24 -98
  33. package/dist/src/components/Modal/Modal.d.ts +32 -31
  34. package/dist/src/components/NumberInput/NumberInput.d.ts +3 -5
  35. package/dist/src/components/Pagination/Pagination.d.ts +8 -41
  36. package/dist/src/components/Panel/Panel.d.ts +5 -18
  37. package/dist/src/components/Radio/Radio.d.ts +4 -4
  38. package/dist/src/components/Radio/RadioGroup.d.ts +3 -7
  39. package/dist/src/components/ReadOnlyField/ReadOnlyField.d.ts +2 -5
  40. package/dist/src/components/SegmentedControl/SegmentedControl.d.ts +5 -15
  41. package/dist/src/components/Slider/Slider.d.ts +4 -14
  42. package/dist/src/components/Stack/Stack.d.ts +2 -5
  43. package/dist/src/components/Stepper/Stepper.d.ts +36 -16
  44. package/dist/src/components/Switch/Switch.d.ts +4 -4
  45. package/dist/src/components/Switch/SwitchGroup.d.ts +4 -4
  46. package/dist/src/components/Table/Table.d.ts +2 -1
  47. package/dist/src/components/Tabs/Tabs.d.ts +11 -26
  48. package/dist/src/components/Text/Text.d.ts +2 -16
  49. package/dist/src/components/TextArea/TextArea.d.ts +3 -9
  50. package/dist/src/components/TextField/TextField.d.ts +3 -7
  51. package/dist/src/components/TimePicker/TimePicker.d.ts +2 -1
  52. package/dist/src/components/Timeline/Timeline.d.ts +2 -1
  53. package/dist/src/components/Timeline/TimelineItem.d.ts +2 -13
  54. package/dist/src/components/Title/Title.d.ts +2 -15
  55. package/dist/src/components/Toast/Toast.d.ts +11 -16
  56. package/dist/src/components/Tooltip/Tooltip.d.ts +7 -21
  57. package/dist/src/components/TransferList/TransferList.d.ts +2 -1
  58. package/dist/src/components/Typography/Typography.d.ts +1 -1
  59. package/dist/src/utils/RequireAccessibleLabel.d.ts +1 -18
  60. package/dist/src/utils/filterStylingProps.d.ts +1 -11
  61. package/llms.txt +16 -0
  62. package/package.json +6 -2
  63. package/src/components/Accordion/Accordion.module.css +1 -2
  64. package/src/components/Accordion/Accordion.stories.tsx +0 -18
  65. package/src/components/Accordion/Accordion.tsx +19 -23
  66. package/src/components/AssistiveElement/AssistiveElement.module.css +32 -29
  67. package/src/components/AssistiveElement/AssistiveElement.stories.tsx +10 -27
  68. package/src/components/AssistiveElement/AssistiveElement.tsx +11 -15
  69. package/src/components/Autocomplete/Autocomplete.module.css +17 -18
  70. package/src/components/Autocomplete/Autocomplete.stories.tsx +7 -16
  71. package/src/components/Autocomplete/Autocomplete.tsx +27 -45
  72. package/src/components/Avatar/Avatar.tsx +2 -13
  73. package/src/components/Badge/Badge.tsx +2 -5
  74. package/src/components/Breadcrumb/Breadcrumb.tsx +1 -4
  75. package/src/components/Button/Button.module.css +19 -61
  76. package/src/components/Button/Button.stories.tsx +24 -23
  77. package/src/components/Button/Button.tsx +7 -18
  78. package/src/components/Card/Card.module.css +36 -0
  79. package/src/components/Card/Card.tsx +6 -4
  80. package/src/components/Checkbox/Checkbox.module.css +27 -10
  81. package/src/components/Checkbox/Checkbox.tsx +124 -24
  82. package/src/components/Checkbox/CheckboxGroup.stories.tsx +139 -0
  83. package/src/components/Checkbox/CheckboxGroup.tsx +43 -23
  84. package/src/components/Chip/Chip.module.css +52 -34
  85. package/src/components/Chip/Chip.tsx +45 -47
  86. package/src/components/Container/Container.stories.tsx +103 -20
  87. package/src/components/Container/Container.tsx +1 -13
  88. package/src/components/DatePicker/DatePicker.stories.tsx +125 -19
  89. package/src/components/DatePicker/DatePicker.tsx +3 -1
  90. package/src/components/Dropdown/Dropdown.tsx +7 -9
  91. package/src/components/FileInput/FileInput.stories.tsx +2 -19
  92. package/src/components/FileUpload/FileUpload.stories.tsx +2 -19
  93. package/src/components/Flex/Flex.stories.tsx +113 -20
  94. package/src/components/Flex/Flex.tsx +16 -26
  95. package/src/components/FormControlLayout/FormControlLayout.stories.tsx +0 -8
  96. package/src/components/FormControlLayout/FormControlLayout.tsx +18 -7
  97. package/src/components/FormControlWrapper/FormControlWrapper.module.css +1 -10
  98. package/src/components/FormControlWrapper/FormControlWrapper.stories.tsx +12 -21
  99. package/src/components/FormControlWrapper/FormControlWrapper.tsx +11 -30
  100. package/src/components/Group/Group.stories.tsx +6 -30
  101. package/src/components/Group/Group.tsx +14 -9
  102. package/src/components/HoverCard/HoverCard.tsx +72 -75
  103. package/src/components/Label/Label.module.css +4 -0
  104. package/src/components/Label/Label.stories.tsx +18 -12
  105. package/src/components/Label/Label.tsx +3 -9
  106. package/src/components/Link/Link.module.css +4 -3
  107. package/src/components/Link/Link.stories.tsx +2 -8
  108. package/src/components/Link/Link.tsx +1 -5
  109. package/src/components/Loader/Loader.module.css +1 -2
  110. package/src/components/Loader/Loader.tsx +1 -7
  111. package/src/components/Menu/IMPLEMENTATION_NOTES.md +4 -0
  112. package/src/components/Menu/Menu.stories.tsx +106 -188
  113. package/src/components/Menu/Menu.tsx +34 -280
  114. package/src/components/Modal/Modal.tsx +158 -160
  115. package/src/components/NumberInput/NumberInput.tsx +6 -18
  116. package/src/components/Pagination/IMPLEMENTATION_NOTES.md +3 -0
  117. package/src/components/Pagination/Pagination.module.css +12 -24
  118. package/src/components/Pagination/Pagination.stories.tsx +0 -8
  119. package/src/components/Pagination/Pagination.tsx +20 -140
  120. package/src/components/Panel/Panel.tsx +7 -30
  121. package/src/components/Radio/Radio.module.css +25 -10
  122. package/src/components/Radio/Radio.tsx +51 -19
  123. package/src/components/Radio/RadioGroup.stories.tsx +117 -0
  124. package/src/components/Radio/RadioGroup.tsx +26 -12
  125. package/src/components/ReadOnlyField/ReadOnlyField.module.css +6 -6
  126. package/src/components/ReadOnlyField/ReadOnlyField.stories.tsx +5 -36
  127. package/src/components/ReadOnlyField/ReadOnlyField.tsx +9 -13
  128. package/src/components/SegmentedControl/SegmentedControl.module.css +23 -47
  129. package/src/components/SegmentedControl/SegmentedControl.tsx +44 -14
  130. package/src/components/Slider/Slider.module.css +1 -4
  131. package/src/components/Slider/Slider.stories.tsx +3 -3
  132. package/src/components/Slider/Slider.tsx +26 -25
  133. package/src/components/Stack/Stack.stories.tsx +4 -25
  134. package/src/components/Stack/Stack.tsx +1 -5
  135. package/src/components/Stepper/IMPLEMENTATION_NOTES.md +4 -0
  136. package/src/components/Stepper/Stepper.stories.tsx +56 -43
  137. package/src/components/Stepper/Stepper.tsx +89 -87
  138. package/src/components/Switch/Switch.module.css +21 -0
  139. package/src/components/Switch/Switch.tsx +63 -16
  140. package/src/components/Switch/SwitchGroup.stories.tsx +132 -0
  141. package/src/components/Switch/SwitchGroup.tsx +27 -18
  142. package/src/components/Table/Table.stories.tsx +1 -19
  143. package/src/components/Table/Table.tsx +3 -1
  144. package/src/components/Tabs/IMPLEMENTATION_NOTES.md +4 -0
  145. package/src/components/Tabs/Tabs.stories.tsx +41 -24
  146. package/src/components/Tabs/Tabs.tsx +49 -66
  147. package/src/components/Text/Text.stories.tsx +5 -17
  148. package/src/components/Text/Text.tsx +1 -15
  149. package/src/components/TextArea/TextArea.tsx +7 -17
  150. package/src/components/TextField/TextField.stories.tsx +1 -27
  151. package/src/components/TextField/TextField.tsx +4 -6
  152. package/src/components/TimePicker/TimePicker.stories.tsx +2 -19
  153. package/src/components/TimePicker/TimePicker.tsx +3 -1
  154. package/src/components/Timeline/Timeline.tsx +4 -1
  155. package/src/components/Timeline/TimelineItem.tsx +1 -12
  156. package/src/components/Title/Title.stories.tsx +0 -18
  157. package/src/components/Title/Title.tsx +1 -7
  158. package/src/components/Toast/Toast.stories.tsx +1 -1
  159. package/src/components/Toast/Toast.tsx +62 -28
  160. package/src/components/Tooltip/Tooltip.tsx +11 -37
  161. package/src/components/TransferList/TransferList.stories.tsx +1 -19
  162. package/src/components/TransferList/TransferList.tsx +3 -1
  163. package/src/utils/RequireAccessibleLabel.ts +1 -12
  164. package/src/utils/filterStylingProps.ts +7 -20
@@ -1,7 +1,14 @@
1
- import React from "react";
1
+ import React, { forwardRef } from "react";
2
2
  import {
3
- Modal as MuiModal,
4
- type ModalProps as MuiModalProps,
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,
5
12
  } from "@mui/material";
6
13
  import {
7
14
  filterStylingProps,
@@ -9,125 +16,128 @@ import {
9
16
  } from "../../utils/filterStylingProps";
10
17
  import styles from "./Modal.module.css";
11
18
 
12
- /**
13
- * Properties for the strictly-tokenized Modal component.
14
- * Native Mui abstract properties like `size`, `radius`, and `shadow` have been stripped out
15
- * because they directly conflict with the non-negotiable pixel boundaries defined in the Recursica UI Kit.
16
- */
19
+ // ============================================================
20
+ // MODAL ROOT (Dialog)
21
+ // ============================================================
22
+
23
+ import { type RecursicaModalProps } from "@recursica/adapter-common";
24
+
17
25
  export type ModalProps = RecursicaOverStyled<
18
- Omit<MuiModalProps, "size" | "radius" | "shadow">
26
+ Omit<MuiDialogProps, "size" | "radius" | "shadow" | "open"> &
27
+ RecursicaModalProps
19
28
  >;
20
29
 
21
- /**
22
- * The `Modal` component displays a window overlaid on the primary viewport.
23
- *
24
- * **Recursica Abstract:**
25
- * This component acts as a strict structural wrapper around Mui's `<Modal>`.
26
- * It automatically enforces Figma UI Kit geometries (`max-width: 960px`, `min-width: 304px`)
27
- * and handles internal body scrolling explicitly via CSS module overrides.
28
- *
29
- * @example
30
- * ```tsx
31
- * <Modal opened={opened} onClose={close} title="Hello World">
32
- * Modal Content
33
- * </Modal>
34
- * ```
35
- */
36
- const ModalInner = React.forwardRef<HTMLDivElement, ModalProps>(function Modal(
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(
37
47
  {
38
48
  overStyled = false,
39
- children,
40
- title,
49
+ opened = false,
41
50
  withCloseButton = true,
42
- overlayProps,
43
- withOverlay = true,
44
- closeButtonProps,
51
+ title,
52
+ children,
53
+ onClose,
54
+ className,
45
55
  ...rest
46
56
  },
47
57
  ref,
48
58
  ) {
49
59
  const sanitizedProps = filterStylingProps(rest, overStyled);
50
60
 
51
- const mergedClassNames: Partial<Record<string, string>> = {
52
- root: styles.root,
53
- inner: styles.inner,
54
- content: styles.content,
55
- header: styles.header,
56
- title: styles.title,
57
- close: styles.close,
58
- };
59
-
60
- const classNamesProp = (sanitizedProps as Record<string, unknown>).classNames;
61
- if (
62
- classNamesProp &&
63
- typeof classNamesProp === "object" &&
64
- !Array.isArray(classNamesProp)
65
- ) {
66
- const o = classNamesProp as Record<string, string>;
67
- Object.keys(o).forEach((key) => {
68
- if (mergedClassNames[key]) {
69
- mergedClassNames[key] = `${mergedClassNames[key]} ${o[key]}`;
70
- } else {
71
- mergedClassNames[key] = o[key];
72
- }
73
- });
74
- }
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
75
 
76
76
  return (
77
- <div
77
+ <MuiDialog
78
78
  ref={ref}
79
- classes={mergedClassNames}
80
- {...(sanitizedProps as unknown as Omit<
81
- MuiModalProps,
82
- "size" | "radius" | "shadow"
83
- >)}
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}
84
86
  >
85
- {withOverlay && <div {...overlayProps} />}
86
- <div>
87
- {(title || withCloseButton) && (
88
- <div>
89
- {title && <div>{title}</div>}
90
- {withCloseButton && <div {...closeButtonProps} />}
91
- </div>
92
- )}
93
- <ModalBody>{children}</ModalBody>
94
- </div>
95
- </div>
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>
96
103
  );
97
104
  });
98
105
 
99
- ModalInner.displayName = "Modal";
100
-
101
- /**
102
- * The `Modal.Footer` provides a perfectly padded container for modal actions.
103
- *
104
- * **Recursica Abstract:**
105
- * By default, this container aligns its children to the right (`justify-content: flex-end`)
106
- * and applies the standard Figma button-gap spacing.
107
- *
108
- * > [!IMPORTANT]
109
- * > **Button Hierarchy:** Recursica design language explicitly requires that the
110
- * > primary action button MUST be the right-most element, with the secondary
111
- * > (outline variant) action placed immediately to the left of it.
112
- */
113
- const ModalFooter = React.forwardRef<
114
- HTMLDivElement,
115
- React.ComponentPropsWithoutRef<"div">
116
- >(function ModalFooter({ className, ...rest }, ref) {
117
- return (
118
- <div
119
- ref={ref}
120
- className={`${styles.footer} ${className || ""}`}
121
- {...rest}
122
- />
123
- );
124
- });
125
- ModalFooter.displayName = "Modal.Footer";
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
+ // ============================================================
126
133
 
127
- const ModalBody = React.forwardRef<
128
- HTMLDivElement,
129
- React.ComponentPropsWithoutRef<typeof MuiModal.Body>
130
- >(function ModalBody({ className, onScroll, children, ...rest }, ref) {
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);
131
141
  const internalRef = React.useRef<HTMLDivElement>(null);
132
142
  const [scrolledTop, setScrolledTop] = React.useState(false);
133
143
  const [scrolledBottom, setScrolledBottom] = React.useState(false);
@@ -140,81 +150,69 @@ const ModalBody = React.forwardRef<
140
150
  }
141
151
  }, []);
142
152
 
143
- // Re-check scroll on mount and window resize
144
153
  React.useEffect(() => {
145
154
  checkScroll();
146
155
  window.addEventListener("resize", checkScroll);
147
156
  return () => window.removeEventListener("resize", checkScroll);
148
157
  }, [checkScroll, children]);
149
158
 
150
- const handleScroll = (e: React.UIEvent<HTMLDivElement>) => {
151
- checkScroll();
152
- onScroll?.(e);
153
- };
154
-
155
- // Intercept children to pull Modal.Footer out of the scrolling container
156
- let footer: React.ReactNode = null;
157
- const bodyChildren: React.ReactNode[] = [];
158
-
159
- React.Children.forEach(children, (child) => {
160
- if (
161
- React.isValidElement(child) &&
162
- (child.type === ModalFooter ||
163
- (child.type as React.ComponentType)?.displayName === "Modal.Footer")
164
- ) {
165
- footer = child;
166
- } else {
167
- bodyChildren.push(child);
168
- }
169
- });
170
-
171
159
  return (
172
- <div
173
- {...rest}
160
+ <MuiDialogContent
174
161
  ref={(node) => {
175
- if (typeof ref === "function") ref(node);
162
+ if (typeof ref === "function") ref(node as any);
176
163
  else if (ref)
177
- (ref as React.MutableRefObject<HTMLDivElement | null>).current = node;
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;
178
170
  }}
179
- className={`${styles.bodyWrapper} ${className || ""}`}
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)}
180
176
  >
181
- <div
182
- ref={internalRef}
183
- onScroll={handleScroll}
184
- data-scrolled-top={scrolledTop || undefined}
185
- data-scrolled-bottom={scrolledBottom || undefined}
186
- className={styles.scrollArea}
187
- >
188
- {bodyChildren}
189
- </div>
190
- {footer}
191
- </div>
177
+ {children}
178
+ </MuiDialogContent>
192
179
  );
193
180
  });
181
+
194
182
  ModalBody.displayName = "Modal.Body";
195
183
 
196
- interface ModalComponent
197
- extends React.ForwardRefExoticComponent<
198
- ModalProps & React.RefAttributes<HTMLDivElement>
199
- > {
200
- Root: typeof MuiModal.Root;
201
- Overlay: typeof MuiModal.Overlay;
202
- Content: typeof MuiModal.Content;
203
- Header: typeof MuiModal.Header;
204
- Title: typeof MuiModal.Title;
205
- CloseButton: typeof MuiModal.CloseButton;
206
- Body: typeof ModalBody;
207
- Footer: typeof ModalFooter;
208
- }
184
+ // ============================================================
185
+ // MODAL FOOTER (DialogActions)
186
+ // ============================================================
187
+
188
+ export type ModalFooterProps = RecursicaOverStyled<MuiDialogActionsProps>;
209
189
 
210
- export const Modal = ModalInner as ModalComponent & {
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;
211
213
  Footer: typeof ModalFooter;
212
214
  };
213
- Modal.Root = MuiModal.Root;
214
- Modal.Overlay = MuiModal.Overlay;
215
- Modal.Content = MuiModal.Content;
216
- Modal.Header = MuiModal.Header;
217
- Modal.Title = MuiModal.Title;
218
- Modal.CloseButton = MuiModal.CloseButton;
215
+
216
+ Modal.Title = ModalTitle;
219
217
  Modal.Body = ModalBody;
220
218
  Modal.Footer = ModalFooter;
@@ -12,6 +12,8 @@ import { type RecursicaFormControlWrapperProps } from "../FormControlWrapper/For
12
12
  import { WithReadOnlyWrapper } from "../ReadOnlyField/WithReadOnlyWrapper";
13
13
  import styles from "./NumberInput.module.css";
14
14
 
15
+ import { type RecursicaNumberInputProps as BaseRecursicaNumberInputProps } from "@recursica/adapter-common";
16
+
15
17
  export interface RecursicaNumberInputProps
16
18
  extends Omit<
17
19
  MuiNumberInputProps,
@@ -28,10 +30,8 @@ export interface RecursicaNumberInputProps
28
30
  | "labelWithEditIcon"
29
31
  | "onLabelEditClick"
30
32
  >,
31
- ReadOnlyControlProps {
32
- /** Enables/disables the controls to increment and decrement the value */
33
- hideControls?: boolean;
34
- }
33
+ ReadOnlyControlProps,
34
+ BaseRecursicaNumberInputProps {}
35
35
 
36
36
  export type NumberInputProps = RecursicaOverStyled<RecursicaNumberInputProps>;
37
37
 
@@ -53,7 +53,7 @@ export const NumberInput = forwardRef<HTMLInputElement, NumberInputProps>(
53
53
  assistiveWithIcon,
54
54
  error,
55
55
  required,
56
- withAsterisk,
56
+ // removed withAsterisk
57
57
  id,
58
58
  className,
59
59
  style,
@@ -63,6 +63,7 @@ export const NumberInput = forwardRef<HTMLInputElement, NumberInputProps>(
63
63
  emptyValueComponent,
64
64
  value,
65
65
  defaultValue,
66
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
66
67
  hideControls = false,
67
68
  ...rest
68
69
  } = props;
@@ -106,7 +107,6 @@ export const NumberInput = forwardRef<HTMLInputElement, NumberInputProps>(
106
107
  assistiveWithIcon={assistiveWithIcon}
107
108
  error={error}
108
109
  required={required}
109
- withAsterisk={withAsterisk}
110
110
  id={id}
111
111
  readOnly={readOnly}
112
112
  readOnlyComponent={readOnlyComponent}
@@ -124,21 +124,9 @@ export const NumberInput = forwardRef<HTMLInputElement, NumberInputProps>(
124
124
  disabled={disabled}
125
125
  value={value}
126
126
  defaultValue={defaultValue}
127
- hideControls={hideControls}
128
127
  label={undefined}
129
- description={undefined}
130
128
  error={undefined}
131
129
  required={undefined}
132
- withAsterisk={undefined}
133
- wrapperProps={{
134
- "data-disabled": disabled ? "true" : undefined,
135
- "data-error": error ? "true" : undefined,
136
- "data-with-left-section": restRecord.leftSection
137
- ? "true"
138
- : undefined,
139
- "data-with-right-section":
140
- restRecord.rightSection || !hideControls ? "true" : undefined,
141
- }}
142
130
  {...(sanitizedProps as unknown as MuiNumberInputProps)}
143
131
  />
144
132
  }
@@ -0,0 +1,3 @@
1
+ # Pagination Implementation Notes
2
+
3
+ - **Compositional API Dropped:** Mantine's original `Pagination` component relies heavily on dot-notation sub-components (`Pagination.Root`, `Pagination.Items`, `Pagination.Control`, etc.). MUI's `<Pagination>` is fundamentally monolithic. Following architectural review, we have decided to drop the dot-notation wrappers for `mui-adapter` and rely strictly on MUI's monolithic API. Storybook and visual regression tests have been updated to reflect this divergence while retaining core property mapping compatibility.
@@ -98,42 +98,33 @@
98
98
 
99
99
  /* Typography */
100
100
  font-family: var(
101
- --recursica_ui-kit_components_button_variants_sizes_default_properties_text_font-family,
102
- var(--recursica_brand_fonts_primary)
101
+ --recursica_ui-kit_components_button_variants_sizes_default_properties_text_font-family
103
102
  );
104
103
  font-size: var(
105
- --recursica_ui-kit_components_button_variants_sizes_default_properties_text_font-size,
106
- var(--recursica_brand_dimensions_text-size_default)
104
+ --recursica_ui-kit_components_button_variants_sizes_default_properties_text_font-size
107
105
  );
108
106
  font-style: var(
109
- --recursica_ui-kit_components_button_variants_sizes_default_properties_text_font-style,
110
- normal
107
+ --recursica_ui-kit_components_button_variants_sizes_default_properties_text_font-style
111
108
  );
112
109
  font-weight: var(
113
- --recursica_ui-kit_components_button_variants_sizes_default_properties_text_font-weight,
114
- 500
110
+ --recursica_ui-kit_components_button_variants_sizes_default_properties_text_font-weight
115
111
  );
116
112
  letter-spacing: var(
117
- --recursica_ui-kit_components_button_variants_sizes_default_properties_text_letter-spacing,
118
- 0
113
+ --recursica_ui-kit_components_button_variants_sizes_default_properties_text_letter-spacing
119
114
  );
120
115
  line-height: var(
121
- --recursica_ui-kit_components_button_variants_sizes_default_properties_text_line-height,
122
- 1.5
116
+ --recursica_ui-kit_components_button_variants_sizes_default_properties_text_line-height
123
117
  );
124
118
  text-decoration: var(
125
- --recursica_ui-kit_components_button_variants_sizes_default_properties_text_text-decoration,
126
- none
119
+ --recursica_ui-kit_components_button_variants_sizes_default_properties_text_text-decoration
127
120
  );
128
121
  text-transform: var(
129
- --recursica_ui-kit_components_button_variants_sizes_default_properties_text_text-transform,
130
- none
122
+ --recursica_ui-kit_components_button_variants_sizes_default_properties_text_text-transform
131
123
  );
132
124
 
133
125
  /* Dimensions */
134
126
  border-radius: var(
135
- --recursica_ui-kit_components_button_variants_content_icon-only_variants_sizes_default_properties_border-radius,
136
- 4px
127
+ --recursica_ui-kit_components_button_variants_content_icon-only_variants_sizes_default_properties_border-radius
137
128
  );
138
129
  height: var(
139
130
  --recursica_ui-kit_components_button_variants_sizes_default_properties_height
@@ -192,8 +183,7 @@
192
183
 
193
184
  .control:hover:not(:disabled)::after {
194
185
  opacity: var(
195
- --recursica_ui-kit_components_button_variants_sizes_default_properties_hover-opacity,
196
- 0.1
186
+ --recursica_ui-kit_components_button_variants_sizes_default_properties_hover-opacity
197
187
  );
198
188
  }
199
189
 
@@ -270,8 +260,7 @@
270
260
  }
271
261
  .control[data-variant="text"]:hover:not(:disabled)::after {
272
262
  opacity: var(
273
- --recursica_ui-kit_components_button_variants_sizes_default_properties_hover-opacity,
274
- 0.1
263
+ --recursica_ui-kit_components_button_variants_sizes_default_properties_hover-opacity
275
264
  );
276
265
  }
277
266
 
@@ -296,8 +285,7 @@
296
285
  display: flex;
297
286
  align-items: center;
298
287
  gap: var(
299
- --recursica_ui-kit_components_button_variants_sizes_default_properties_icon-text-gap,
300
- 4px
288
+ --recursica_ui-kit_components_button_variants_sizes_default_properties_icon-text-gap
301
289
  );
302
290
  }
303
291
 
@@ -40,14 +40,6 @@ export const WithEdges: Story = {
40
40
  },
41
41
  };
42
42
 
43
- export const Compositional: Story = {
44
- render: () => (
45
- <Pagination.Root total={10}>
46
- <Pagination.Items />
47
- </Pagination.Root>
48
- ),
49
- };
50
-
51
43
  export const WithTextLabels: Story = {
52
44
  args: {
53
45
  withEdges: true,