@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,202 @@
1
- import React from "react";
2
- import "./Switch.module.css";
1
+ import { forwardRef } from "react";
2
+ import {
3
+ Switch as MuiSwitch,
4
+ type SwitchProps as MuiSwitchProps,
5
+ } from "@mui/material";
6
+ import { type ReadOnlyControlProps } from "@recursica/adapter-common";
3
7
 
4
- export type SwitchProps = React.HTMLAttributes<HTMLDivElement>;
8
+ import {
9
+ filterStylingProps,
10
+ type RecursicaOverStyled,
11
+ } from "../../utils/filterStylingProps";
12
+ import {
13
+ type RequireAccessibleLabel,
14
+ type RecursicaSwitchProps,
15
+ } from "@recursica/adapter-common";
16
+ import {
17
+ FormControlLayout,
18
+ type FormControlLayoutProps,
19
+ } from "../FormControlLayout/FormControlLayout";
20
+ import styles from "./Switch.module.css";
5
21
 
6
- export const Switch: React.FC<SwitchProps> = (props) => {
7
- return <div {...props}>Switch</div>;
8
- };
22
+ // Removed unused SwitchGroup import
23
+
24
+ export type SwitchWrapperProps = Omit<
25
+ MuiSwitchProps,
26
+ "size" | "color" | "radius" | "variant"
27
+ > &
28
+ RecursicaSwitchProps &
29
+ ReadOnlyControlProps &
30
+ Pick<
31
+ FormControlLayoutProps,
32
+ "formLayout" | "labelSize" | "controlMaxWidth" | "controlMinWidth"
33
+ >;
34
+
35
+ export type RecursicaSwitchPropsAlias =
36
+ RequireAccessibleLabel<SwitchWrapperProps>;
37
+
38
+ export type SwitchProps = RecursicaOverStyled<RecursicaSwitchPropsAlias>;
39
+
40
+ type SwitchComponent = any;
41
+
42
+ export const Switch = forwardRef<HTMLInputElement, SwitchProps>(
43
+ function Switch(props, ref) {
44
+ const {
45
+ overStyled = false,
46
+ readOnly,
47
+ readOnlyComponent,
48
+ disabled,
49
+ // Removed thumbIcon from destructured props since it's not supported
50
+ formLayout,
51
+ labelSize,
52
+ controlMaxWidth,
53
+ controlMinWidth,
54
+ label,
55
+ description,
56
+ error,
57
+ style,
58
+ ...rest
59
+ } = props;
60
+ const sanitizedProps = filterStylingProps(rest, overStyled);
61
+ const restRecord = sanitizedProps as Record<string, unknown>;
62
+
63
+ // Actively delete dimension bindings that bypass the abstraction
64
+ delete restRecord["size"];
65
+ delete restRecord["color"];
66
+ delete restRecord["radius"];
67
+ delete restRecord["variant"];
68
+
69
+ const mergedClassNames: Partial<Record<string, string>> = {
70
+ root: styles.root,
71
+ body: styles.body,
72
+ track: styles.track,
73
+ thumb: styles.thumb,
74
+ trackLabel: styles.trackLabel,
75
+ labelWrapper: styles.labelWrapper,
76
+ label: styles.label,
77
+ };
78
+
79
+ const classNamesProp = restRecord.classNames;
80
+ if (
81
+ classNamesProp &&
82
+ typeof classNamesProp === "object" &&
83
+ !Array.isArray(classNamesProp)
84
+ ) {
85
+ const o = classNamesProp as Partial<Record<string, string>>;
86
+ mergedClassNames.root = o.root ? `${styles.root} ${o.root}` : styles.root;
87
+ mergedClassNames.body = o.body ? `${styles.body} ${o.body}` : styles.body;
88
+ mergedClassNames.track = o.track
89
+ ? `${styles.track} ${o.track}`
90
+ : styles.track;
91
+ mergedClassNames.thumb = o.thumb
92
+ ? `${styles.thumb} ${o.thumb}`
93
+ : styles.thumb;
94
+ mergedClassNames.trackLabel = o.trackLabel
95
+ ? `${styles.trackLabel} ${o.trackLabel}`
96
+ : styles.trackLabel;
97
+ mergedClassNames.labelWrapper = o.labelWrapper
98
+ ? `${styles.labelWrapper} ${o.labelWrapper}`
99
+ : styles.labelWrapper;
100
+ mergedClassNames.label = o.label
101
+ ? `${styles.label} ${o.label}`
102
+ : styles.label;
103
+ }
104
+
105
+ const classNameProp = restRecord.className as string | undefined;
106
+ const finalClass = classNameProp
107
+ ? `${styles.root} ${classNameProp}`
108
+ : styles.root;
109
+
110
+ if (readOnly && !!readOnlyComponent) {
111
+ const isChecked = !!(restRecord.checked ?? restRecord.defaultChecked);
112
+ const ReadOnlyComp = readOnlyComponent;
113
+ const roNode = (
114
+ <ReadOnlyComp
115
+ {...props}
116
+ checked={isChecked}
117
+ label={restRecord.label as React.ReactNode}
118
+ />
119
+ );
120
+
121
+ if (formLayout) {
122
+ return (
123
+ <FormControlLayout
124
+ formLayout={formLayout}
125
+ labelSize={labelSize}
126
+ controlMaxWidth={controlMaxWidth}
127
+ controlMinWidth={controlMinWidth}
128
+ >
129
+ {roNode}
130
+ </FormControlLayout>
131
+ );
132
+ }
133
+
134
+ return <>{roNode}</>;
135
+ }
136
+
137
+ // We omit Mui's sizing/coloring so we rely strictly on variables from Switch.module.css
138
+ const switchNode = (
139
+ <MuiSwitch
140
+ ref={ref as any}
141
+ className={!label ? `${finalClass} ${styles.inner}` : styles.inner}
142
+ classes={mergedClassNames}
143
+ disabled={readOnly || disabled}
144
+ data-disabled={readOnly || disabled || undefined}
145
+ // thumbIcon={thumbIcon ?? FinalThumbIcon}
146
+ {...(sanitizedProps as unknown as MuiSwitchProps)}
147
+ />
148
+ );
149
+
150
+ const finalNode = label ? (
151
+ <div className={finalClass} style={style as React.CSSProperties}>
152
+ <div className={styles.body}>
153
+ {switchNode}
154
+ <div className={styles.labelWrapper}>
155
+ <label
156
+ className={styles.label}
157
+ htmlFor={restRecord.id as string}
158
+ data-disabled={readOnly || disabled ? true : undefined}
159
+ >
160
+ {label as React.ReactNode}
161
+ </label>
162
+ {description && (
163
+ <div
164
+ className={styles.description}
165
+ data-disabled={readOnly || disabled ? true : undefined}
166
+ >
167
+ {description}
168
+ </div>
169
+ )}
170
+ {error && (
171
+ <div
172
+ className={styles.error}
173
+ data-disabled={readOnly || disabled ? true : undefined}
174
+ >
175
+ {error}
176
+ </div>
177
+ )}
178
+ </div>
179
+ </div>
180
+ </div>
181
+ ) : (
182
+ switchNode
183
+ );
184
+
185
+ if (formLayout) {
186
+ return (
187
+ <FormControlLayout
188
+ formLayout={formLayout}
189
+ labelSize={labelSize}
190
+ controlMaxWidth={controlMaxWidth}
191
+ controlMinWidth={controlMinWidth}
192
+ >
193
+ {finalNode}
194
+ </FormControlLayout>
195
+ );
196
+ }
197
+
198
+ return finalNode;
199
+ },
200
+ ) as SwitchComponent;
201
+
202
+ Switch.displayName = "Switch";
@@ -0,0 +1,132 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { Switch } from "./Switch";
3
+ import { SwitchGroup } from "./SwitchGroup";
4
+ import { useState } from "react";
5
+ import { formControlArgTypes } from "../../../.storybook/commonArgTypes";
6
+
7
+ const meta: Meta<typeof SwitchGroup> = {
8
+ title: "UI-Kit/SwitchGroup",
9
+ component: SwitchGroup,
10
+ tags: ["autodocs"],
11
+ parameters: {
12
+ docs: {
13
+ description: {
14
+ component: `
15
+ The \`SwitchGroup\` component is the mandatory organizational wrapper for orchestrating \`Switch\` primitives into macro form layouts. It inherently leverages the \`FormControlWrapper\`, granting native access to structural alignments, assistive descriptions, and strict flex arrays.
16
+
17
+ ### Supported Layout Vectors
18
+ - **\`formLayout="stacked"\`**: Top-to-bottom layout cascading the Label bounding box down vertically into a standard stacked switch array.
19
+ - **\`formLayout="side-by-side"\`**: Flow architecture pulling the grouping Label dynamically to the left while structurally organizing the internal switches cleanly alongside it horizontally.
20
+
21
+ > [!IMPORTANT]
22
+ > If you require a solitary \`Switch\` field to natively accept an overarching form label, assistive text, or align with other side-by-side components in a form column, you must wrap it inside a \`Switch.Group\` to trigger the \`FormControlWrapper\` mapping.
23
+ `,
24
+ },
25
+ },
26
+ },
27
+ argTypes: {
28
+ ...formControlArgTypes,
29
+ readOnly: {
30
+ control: "boolean",
31
+ description:
32
+ "Passes read-only lock natively down mapping inner switches into explicitly disabled states.",
33
+ },
34
+ },
35
+ };
36
+
37
+ export default meta;
38
+
39
+ type Story = StoryObj<typeof SwitchGroup>;
40
+
41
+ export const Default: Story = {
42
+ args: {
43
+ formLayout: "stacked",
44
+ label: "Standard Group",
45
+ },
46
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
47
+ render: function StoryRender({ withLayer, layer, ...args }: any) {
48
+ const [value, setValue] = useState<string[]>([]);
49
+ return (
50
+ <SwitchGroup {...args} value={value} onChange={setValue}>
51
+ <Switch value="1" label="Option 1" />
52
+ <Switch value="2" label="Option 2" />
53
+ </SwitchGroup>
54
+ );
55
+ },
56
+ };
57
+
58
+ export const StackedLayout: Story = {
59
+ args: {
60
+ formLayout: "stacked",
61
+ label: "Notification Settings",
62
+ description: "Manage your preferences.",
63
+ assistiveText: "We recommend turning these on.",
64
+ error: "",
65
+ required: true,
66
+ },
67
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
68
+ render: function StoryRender({ withLayer, layer, ...args }: any) {
69
+ const [value, setValue] = useState<string[]>(["email"]);
70
+ return (
71
+ <SwitchGroup {...args} value={value} onChange={setValue}>
72
+ <Switch value="email" label="Email Alerts" />
73
+ <Switch value="push" label="Push Notifications" />
74
+ <Switch value="sms" label="SMS Messages" />
75
+ </SwitchGroup>
76
+ );
77
+ },
78
+ };
79
+
80
+ export const SideBySideLayout: Story = {
81
+ args: {
82
+ ...StackedLayout.args,
83
+ formLayout: "side-by-side",
84
+ labelSize: "default",
85
+ labelAlignment: "left",
86
+ },
87
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
88
+ render: function StoryRender({ withLayer, layer, ...args }: any) {
89
+ const [value, setValue] = useState<string[]>([]);
90
+ return (
91
+ <SwitchGroup {...args} value={value} onChange={setValue}>
92
+ <Switch value="weekly" label="Weekly Digest" />
93
+ <Switch value="marketing" label="Marketing Emails" />
94
+ </SwitchGroup>
95
+ );
96
+ },
97
+ };
98
+
99
+ export const SolitaryFormControl: Story = {
100
+ args: {
101
+ formLayout: "side-by-side",
102
+ label: "Enable Backups",
103
+ description: "Automatically back up your data nightly.",
104
+ },
105
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
106
+ render: function StoryRender({ withLayer, layer, ...args }: any) {
107
+ const [value, setValue] = useState<string[]>(["auto"]);
108
+ return (
109
+ <SwitchGroup {...args} value={value} onChange={setValue}>
110
+ <Switch value="auto" label="Auto-backup" />
111
+ </SwitchGroup>
112
+ );
113
+ },
114
+ };
115
+
116
+ export const ReadOnly: Story = {
117
+ args: {
118
+ ...StackedLayout.args,
119
+ readOnly: true,
120
+ },
121
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
122
+ render: function StoryRender({ withLayer, layer, ...args }: any) {
123
+ const [value, setValue] = useState<string[]>(["email", "sms"]);
124
+ return (
125
+ <SwitchGroup {...args} value={value} onChange={setValue}>
126
+ <Switch value="email" label="Email Alerts" />
127
+ <Switch value="push" label="Push Notifications" />
128
+ <Switch value="sms" label="SMS Messages" />
129
+ </SwitchGroup>
130
+ );
131
+ },
132
+ };
@@ -0,0 +1,120 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import React, { forwardRef } from "react";
3
+ import {
4
+ FormGroup as MuiFormGroup,
5
+ type FormGroupProps as MuiFormGroupProps,
6
+ } from "@mui/material";
7
+ import { type ReadOnlyControlProps } from "@recursica/adapter-common";
8
+ import {
9
+ filterStylingProps,
10
+ type RecursicaOverStyled,
11
+ } from "../../utils/filterStylingProps";
12
+ import { type RecursicaFormControlWrapperProps } from "../FormControlWrapper/FormControlWrapper";
13
+ import { WithReadOnlyWrapper } from "../ReadOnlyField/WithReadOnlyWrapper";
14
+ import styles from "./Switch.module.css";
15
+
16
+ import { type RecursicaSwitchGroupProps as BaseRecursicaSwitchGroupProps } from "@recursica/adapter-common";
17
+
18
+ export interface RecursicaSwitchGroupProps
19
+ extends Omit<
20
+ MuiFormGroupProps,
21
+ | "size"
22
+ | "labelProps"
23
+ | "onChange"
24
+ | "classes"
25
+ | "ref"
26
+ | "value"
27
+ | "defaultValue"
28
+ >,
29
+ Omit<
30
+ RecursicaFormControlWrapperProps,
31
+ "controlMaxWidth" | "controlMinWidth" | "classes" | "onChange"
32
+ >,
33
+ ReadOnlyControlProps,
34
+ BaseRecursicaSwitchGroupProps {}
35
+
36
+ export type SwitchGroupProps = RecursicaOverStyled<RecursicaSwitchGroupProps>;
37
+
38
+ export const SwitchGroup = forwardRef<HTMLDivElement, SwitchGroupProps>(
39
+ function SwitchGroup(props, ref) {
40
+ const {
41
+ overStyled = false,
42
+ formLayout = "stacked",
43
+
44
+ // Label Wrappers
45
+ labelSize,
46
+ labelAlignment,
47
+ labelOptionalText,
48
+ labelWithEditIcon,
49
+ onLabelEditClick,
50
+
51
+ // Base Mui Extracted Attributes
52
+ label,
53
+ description,
54
+ assistiveText,
55
+ assistiveWithIcon,
56
+ error,
57
+ required,
58
+ // removed withAsterisk
59
+ id,
60
+ className,
61
+ style,
62
+ children,
63
+ readOnly,
64
+ readOnlyComponent,
65
+ emptyValueComponent,
66
+ value,
67
+ defaultValue,
68
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
69
+ onChange,
70
+ ...rest
71
+ } = props;
72
+ const sanitizedProps = filterStylingProps(rest, overStyled);
73
+ const restRecord = sanitizedProps as Record<string, unknown>;
74
+
75
+ // Delete prohibited sizing hooks from bypassing the variables
76
+ delete restRecord["size"];
77
+
78
+ return (
79
+ <WithReadOnlyWrapper
80
+ className={className}
81
+ style={style as React.CSSProperties}
82
+ controlMaxWidth="var(--recursica_ui-kit_components_switch-item_properties_label-max-width)"
83
+ controlMinWidth={undefined}
84
+ overStyled={overStyled as true}
85
+ // Strictly override. ARIA grouping prohibits interactive switches nested natively inside <label>.
86
+ formLayout={formLayout}
87
+ labelSize={labelSize}
88
+ labelAlignment={labelAlignment}
89
+ labelOptionalText={labelOptionalText}
90
+ labelWithEditIcon={labelWithEditIcon}
91
+ onLabelEditClick={onLabelEditClick}
92
+ label={label}
93
+ description={description}
94
+ assistiveText={assistiveText}
95
+ assistiveWithIcon={assistiveWithIcon}
96
+ error={error}
97
+ required={required}
98
+ id={id}
99
+ readOnly={readOnly && !!readOnlyComponent}
100
+ readOnlyComponent={readOnlyComponent}
101
+ emptyValueComponent={emptyValueComponent}
102
+ readOnlyType="text"
103
+ readOnlyValue={value !== undefined ? value : defaultValue}
104
+ readOnlyNativeProps={props}
105
+ activeComponent={
106
+ <MuiFormGroup
107
+ ref={ref}
108
+ {...(sanitizedProps as unknown as MuiFormGroupProps)}
109
+ className={`${styles.groupRoot} ${(sanitizedProps as any).className || ""}`.trim()}
110
+ data-layout={formLayout}
111
+ >
112
+ {children}
113
+ </MuiFormGroup>
114
+ }
115
+ />
116
+ );
117
+ },
118
+ );
119
+
120
+ SwitchGroup.displayName = "SwitchGroup";
@@ -6,28 +6,10 @@ const meta: Meta<typeof Table> = {
6
6
  title: "UI-Kit/🚧 Table",
7
7
  component: Table,
8
8
  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
- ],
26
- },
27
- },
28
9
  };
29
10
 
30
11
  export default meta;
12
+
31
13
  type Story = StoryObj<typeof Table>;
32
14
 
33
15
  export const Default: Story = {
@@ -1,6 +1,8 @@
1
1
  import React from "react";
2
+ import { type RecursicaTableProps } from "@recursica/adapter-common";
2
3
 
3
- export type TableProps = React.HTMLAttributes<HTMLDivElement>;
4
+ export type TableProps = React.HTMLAttributes<HTMLDivElement> &
5
+ RecursicaTableProps;
4
6
 
5
7
  export const Table: React.FC<TableProps> = (props) => {
6
8
  return <div {...props}>Table</div>;
@@ -0,0 +1,4 @@
1
+ # Tabs Implementation Notes
2
+
3
+ - **Compositional API Dropped:** Mantine uses `<Tabs.List>`, `<Tabs.Tab>`, and `<Tabs.Panel>` natively with implicit context from `<Tabs>`. MUI relies on `@mui/lab/TabContext` and separates `Tabs` and `TabPanel`.
4
+ - **Monolithic API Adopted:** Following architectural review, we have opted to drop the broken dot-notation wrappers for `mui-adapter`. We now natively export `Tabs` (MUI List), `Tab` (MUI Item), and `TabPanel` (from `@mui/lab`). Developers must use `TabContext` (from `@mui/lab`) to manage state, just like native MUI. Storybook and visual regression tests have been updated to reflect this divergence while retaining core property mapping compatibility.