@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,35 +1,94 @@
1
+ import React from "react";
1
2
  import type { Meta, StoryObj } from "@storybook/react";
2
3
  import { Dropdown } from "./Dropdown";
3
- import { ComingSoon } from "@recursica/storybook-template";
4
+ import { formControlArgTypes } from "../../../.storybook/commonArgTypes";
4
5
 
5
- const meta: Meta<typeof Dropdown> = {
6
- title: "UI-Kit/🚧 Dropdown",
6
+ type DropdownStoryProps = React.ComponentProps<typeof Dropdown>;
7
+
8
+ const meta: Meta<DropdownStoryProps> = {
9
+ title: "UI-Kit/Dropdown",
7
10
  component: Dropdown,
8
11
  tags: ["autodocs"],
9
12
  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
- ],
13
+ docs: {
14
+ description: {
15
+ component:
16
+ "Dropdown provides a selectable list of options, mapping natively over Mantine's Select component encapsulated within the standardized FormControlWrapper.",
17
+ },
18
+ },
19
+ },
20
+ args: {
21
+ label: "Country Selection",
22
+ assistiveText: "Select your country of origin.",
23
+ placeholder: "Pick value",
24
+ data: ["United States", "Canada", "Mexico", "United Kingdom", "France"],
25
+ disabled: false,
26
+ required: false,
27
+ readOnly: false,
28
+ searchable: false,
29
+ clearable: false,
30
+ },
31
+ argTypes: {
32
+ disabled: {
33
+ control: "boolean",
34
+ },
35
+ ...formControlArgTypes,
36
+ readOnly: {
37
+ control: "boolean",
38
+ },
39
+ searchable: {
40
+ control: "boolean",
41
+ },
42
+ clearable: {
43
+ control: "boolean",
44
+ },
45
+ checked: {
46
+ table: { disable: true },
47
+ },
48
+ defaultChecked: {
49
+ table: { disable: true },
50
+ },
51
+ containerWidth: {
52
+ table: { disable: true },
26
53
  },
27
54
  },
28
55
  };
29
56
 
30
57
  export default meta;
31
- type Story = StoryObj<typeof Dropdown>;
58
+
59
+ type Story = StoryObj<DropdownStoryProps>;
32
60
 
33
61
  export const Default: Story = {
34
- render: () => <ComingSoon componentName="Dropdown" />,
62
+ args: {},
63
+ };
64
+
65
+ export const SearchableClearable: Story = {
66
+ args: {
67
+ label: "Search & Clear Options",
68
+ searchable: true,
69
+ clearable: true,
70
+ placeholder: "Start typing...",
71
+ },
72
+ };
73
+
74
+ export const StaticError: Story = {
75
+ args: {
76
+ error: "You must choose a valid destination.",
77
+ value: "Invalid Island",
78
+ },
79
+ };
80
+
81
+ export const StaticDisabled: Story = {
82
+ args: {
83
+ disabled: true,
84
+ value: "United States",
85
+ },
86
+ };
87
+
88
+ export const StaticReadOnly: Story = {
89
+ args: {
90
+ label: "Read Only View",
91
+ readOnly: true,
92
+ value: "Canada",
93
+ },
35
94
  };
@@ -1,8 +1,182 @@
1
- import React from "react";
2
- import "./Dropdown.module.css";
1
+ import React, { forwardRef, ReactNode } from "react";
2
+ import {
3
+ Select as MuiSelect,
4
+ SelectProps as MuiSelectProps,
5
+ MenuItem,
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 "./Dropdown.module.css";
3
15
 
4
- export type DropdownProps = React.HTMLAttributes<HTMLDivElement>;
16
+ import { type RecursicaDropdownProps as BaseRecursicaDropdownProps } from "@recursica/adapter-common";
5
17
 
6
- export const Dropdown: React.FC<DropdownProps> = (props) => {
7
- return <div {...props}>Dropdown</div>;
8
- };
18
+ export interface RecursicaDropdownProps
19
+ extends Omit<
20
+ MuiSelectProps,
21
+ "size" | "variant" | "classes" | "inputProps" | "SelectDisplayProps"
22
+ >,
23
+ Pick<
24
+ RecursicaFormControlWrapperProps,
25
+ | "assistiveText"
26
+ | "assistiveWithIcon"
27
+ | "formLayout"
28
+ | "labelSize"
29
+ | "labelAlignment"
30
+ | "labelOptionalText"
31
+ | "labelWithEditIcon"
32
+ | "onLabelEditClick"
33
+ >,
34
+ ReadOnlyControlProps,
35
+ BaseRecursicaDropdownProps {}
36
+
37
+ export type DropdownProps = RecursicaOverStyled<RecursicaDropdownProps>;
38
+
39
+ export const Dropdown = forwardRef<HTMLInputElement, DropdownProps>(
40
+ function Dropdown(props, ref) {
41
+ const {
42
+ overStyled = false,
43
+ formLayout = "stacked",
44
+ containerWidth,
45
+
46
+ // Label & Wrapper Maps
47
+ labelSize,
48
+ labelAlignment,
49
+ labelOptionalText,
50
+ labelWithEditIcon,
51
+ onLabelEditClick,
52
+
53
+ label,
54
+ assistiveText,
55
+ assistiveWithIcon,
56
+ error,
57
+ required,
58
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
59
+ withAsterisk,
60
+ id,
61
+ className,
62
+ style,
63
+ disabled,
64
+ readOnly,
65
+ readOnlyComponent,
66
+ emptyValueComponent,
67
+ value,
68
+ defaultValue,
69
+ data,
70
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
71
+ searchable, // Not natively supported by basic MUI Select, stubbed
72
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
73
+ clearable, // Not natively supported by basic MUI Select, stubbed
74
+ ...rest
75
+ } = props;
76
+ const sanitizedProps = filterStylingProps(rest, overStyled);
77
+ const restRecord = sanitizedProps as Record<string, unknown>;
78
+
79
+ // Delete prohibited sizing hooks
80
+ delete restRecord["size"];
81
+ delete restRecord["variant"];
82
+
83
+ const injectedStyles = {
84
+ ...((style as React.CSSProperties) || {}),
85
+ width: containerWidth || "100%",
86
+ };
87
+
88
+ const wrapperClass = className
89
+ ? `${styles.layoutOverride} ${className}`
90
+ : styles.layoutOverride;
91
+
92
+ const renderOptions = () => {
93
+ if (!data) return null;
94
+ return data.map((item, index) => {
95
+ if (typeof item === "string") {
96
+ return (
97
+ <MenuItem
98
+ key={`${item}-${index}`}
99
+ value={item}
100
+ className={styles.option}
101
+ >
102
+ {item}
103
+ </MenuItem>
104
+ );
105
+ }
106
+ return (
107
+ <MenuItem
108
+ key={`${item.value}-${index}`}
109
+ value={item.value}
110
+ disabled={item.disabled}
111
+ className={styles.option}
112
+ >
113
+ {item.label}
114
+ </MenuItem>
115
+ );
116
+ });
117
+ };
118
+
119
+ return (
120
+ <WithReadOnlyWrapper
121
+ className={wrapperClass}
122
+ style={injectedStyles}
123
+ controlMaxWidth="var(--recursica_ui-kit_components_dropdown_properties_max-width)"
124
+ controlMinWidth="var(--recursica_ui-kit_components_dropdown_properties_min-width)"
125
+ overStyled={overStyled as true}
126
+ formLayout={formLayout}
127
+ labelSize={labelSize}
128
+ labelAlignment={labelAlignment}
129
+ labelOptionalText={labelOptionalText}
130
+ labelWithEditIcon={labelWithEditIcon}
131
+ onLabelEditClick={onLabelEditClick}
132
+ label={label as ReactNode}
133
+ assistiveText={assistiveText}
134
+ assistiveWithIcon={assistiveWithIcon}
135
+ error={!!error}
136
+ required={required}
137
+ id={id}
138
+ readOnly={readOnly}
139
+ readOnlyComponent={readOnlyComponent}
140
+ emptyValueComponent={emptyValueComponent}
141
+ readOnlyType="text"
142
+ readOnlyValue={
143
+ value !== undefined
144
+ ? String(value)
145
+ : defaultValue
146
+ ? String(defaultValue)
147
+ : undefined
148
+ }
149
+ readOnlyNativeProps={props}
150
+ activeComponent={
151
+ <MuiSelect
152
+ ref={ref}
153
+ disabled={disabled}
154
+ value={value}
155
+ defaultValue={defaultValue}
156
+ error={!!error}
157
+ required={required}
158
+ displayEmpty
159
+ className={styles.root}
160
+ classes={{
161
+ select: styles.input,
162
+ icon: styles.icon,
163
+ }}
164
+ MenuProps={{
165
+ classes: { paper: styles.dropdown },
166
+ }}
167
+ inputProps={{
168
+ "data-disabled": disabled ? "true" : undefined,
169
+ "data-error": error ? "true" : undefined,
170
+ ...(restRecord.inputProps as any),
171
+ }}
172
+ {...(sanitizedProps as unknown as MuiSelectProps)}
173
+ >
174
+ {renderOptions()}
175
+ </MuiSelect>
176
+ }
177
+ />
178
+ );
179
+ },
180
+ );
181
+
182
+ Dropdown.displayName = "Dropdown";
@@ -6,28 +6,11 @@ const meta: Meta<typeof FileInput> = {
6
6
  title: "UI-Kit/🚧 FileInput",
7
7
  component: FileInput,
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
- },
9
+ argTypes: {},
28
10
  };
29
11
 
30
12
  export default meta;
13
+
31
14
  type Story = StoryObj<typeof FileInput>;
32
15
 
33
16
  export const Default: Story = {
@@ -6,28 +6,11 @@ const meta: Meta<typeof FileUpload> = {
6
6
  title: "UI-Kit/🚧 FileUpload",
7
7
  component: FileUpload,
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
- },
9
+ argTypes: {},
28
10
  };
29
11
 
30
12
  export default meta;
13
+
31
14
  type Story = StoryObj<typeof FileUpload>;
32
15
 
33
16
  export const Default: Story = {
@@ -1,35 +1,128 @@
1
+ import React from "react";
1
2
  import type { Meta, StoryObj } from "@storybook/react";
2
3
  import { Flex } from "./Flex";
3
- import { ComingSoon } from "@recursica/storybook-template";
4
+ import { Button } from "../Button";
5
+ import { Text } from "../Text/Text";
4
6
 
5
- const meta: Meta<typeof Flex> = {
6
- title: "UI-Kit/🚧 Flex",
7
+ type FlexStoryProps = React.ComponentProps<typeof Flex>;
8
+
9
+ const meta: Meta<FlexStoryProps> = {
10
+ title: "UI-Kit/Flex",
7
11
  component: Flex,
8
12
  tags: ["autodocs"],
9
13
  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",
14
+ docs: {
15
+ description: {
16
+ component:
17
+ "Flex is a bare-metal flex container that maps directly to Mantine's Flex component, providing unopinionated control over direction, alignment, and wrapping.",
18
+ },
19
+ },
20
+ },
21
+ args: {
22
+ gap: "rec-default",
23
+ align: "center",
24
+ justify: "flex-start",
25
+ direction: "row",
26
+ wrap: "wrap",
27
+ },
28
+ argTypes: {
29
+ gap: {
30
+ control: "select",
31
+ options: [
32
+ "rec-none",
33
+ "rec-sm",
34
+ "rec-default",
35
+ "rec-md",
36
+ "rec-lg",
37
+ "rec-xl",
38
+ "rec-2xl",
39
+ "xs",
40
+ "sm",
41
+ "md",
42
+ "lg",
43
+ "xl",
44
+ ],
45
+ description: "Gap between elements",
46
+ },
47
+ direction: {
48
+ control: "select",
49
+ options: ["row", "column", "row-reverse", "column-reverse"],
50
+ description: "Flex-direction property",
51
+ },
52
+ align: {
53
+ control: "select",
54
+ options: ["flex-start", "center", "flex-end", "stretch"],
55
+ description: "Align-items property",
56
+ },
57
+ justify: {
58
+ control: "select",
59
+ options: [
60
+ "flex-start",
61
+ "center",
62
+ "flex-end",
63
+ "space-between",
64
+ "space-around",
25
65
  ],
66
+ description: "Justify-content property",
67
+ },
68
+ wrap: {
69
+ control: "select",
70
+ options: ["wrap", "nowrap", "wrap-reverse"],
71
+ description: "Flex-wrap property",
72
+ },
73
+ defaultChecked: {
74
+ table: { disable: true },
75
+ },
76
+ rowGap: {
77
+ table: { disable: true },
78
+ },
79
+ columnGap: {
80
+ table: { disable: true },
26
81
  },
27
82
  },
28
83
  };
29
84
 
30
85
  export default meta;
31
- type Story = StoryObj<typeof Flex>;
86
+
87
+ type Story = StoryObj<FlexStoryProps>;
32
88
 
33
89
  export const Default: Story = {
34
- render: () => <ComingSoon componentName="Flex" />,
90
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
91
+ render: ({ withLayer, layer, ...args }: any) => (
92
+ <Flex {...args}>
93
+ <Button variant="solid">Block A</Button>
94
+ <Button variant="outline">Block B</Button>
95
+ <Text>Text inside Flex</Text>
96
+ </Flex>
97
+ ),
98
+ };
99
+
100
+ export const StaticGapSmallColumn: Story = {
101
+ args: {
102
+ gap: "rec-sm",
103
+ direction: "column",
104
+ },
105
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
106
+ render: ({ withLayer, layer, ...args }: any) => (
107
+ <Flex {...args}>
108
+ <Button variant="solid">Item 1</Button>
109
+ <Button variant="solid">Item 2</Button>
110
+ <Button variant="solid">Item 3</Button>
111
+ </Flex>
112
+ ),
113
+ };
114
+
115
+ export const StaticGapLargeRow: Story = {
116
+ args: {
117
+ gap: "rec-xl",
118
+ direction: "row",
119
+ },
120
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
121
+ render: ({ withLayer, layer, ...args }: any) => (
122
+ <Flex {...args}>
123
+ <Button variant="solid">Item 1</Button>
124
+ <Button variant="solid">Item 2</Button>
125
+ <Button variant="solid">Item 3</Button>
126
+ </Flex>
127
+ ),
35
128
  };
@@ -11,41 +11,27 @@
11
11
  import React, { forwardRef } from "react";
12
12
  import { Box as MUIBox, type BoxProps as MUIBoxProps } from "@mui/material";
13
13
  import {
14
- type RecursicaSpacing,
15
14
  SPACING_MAP,
16
15
  type OmitSx,
17
16
  filterSxProp,
18
17
  } from "../../utils/filterStylingProps";
19
18
 
20
- export interface RecursicaFlexProps {
21
- /**
22
- * Content to render inside the flex container.
23
- */
24
- children?: React.ReactNode;
25
-
26
- /**
27
- * The gap between flex items. Accepts standard MUI spacing or Recursica gap tokens
28
- * (e.g. "rec-md").
29
- */
30
- gap?: string | number | RecursicaSpacing;
31
-
32
- /**
33
- * The vertical gap between flex items when wrapping. Accepts standard MUI spacing
34
- * or Recursica gap tokens.
35
- */
36
- rowGap?: string | number | RecursicaSpacing;
37
-
38
- /**
39
- * The horizontal gap between flex items when wrapping. Accepts standard MUI spacing
40
- * or Recursica gap tokens.
41
- */
42
- columnGap?: string | number | RecursicaSpacing;
43
- }
19
+ import { type RecursicaFlexProps } from "@recursica/adapter-common";
44
20
 
45
21
  export type FlexProps = OmitSx<MUIBoxProps & RecursicaFlexProps>;
46
22
 
47
23
  export const Flex = forwardRef<HTMLDivElement, FlexProps>(function Flex(
48
- { children, gap = "rec-default", rowGap, columnGap, ...rest },
24
+ {
25
+ children,
26
+ gap = "rec-default",
27
+ rowGap,
28
+ columnGap,
29
+ direction,
30
+ align,
31
+ justify,
32
+ wrap,
33
+ ...rest
34
+ },
49
35
  ref,
50
36
  ) {
51
37
  const safeProps = filterSxProp(rest as Record<string, unknown>);
@@ -70,6 +56,10 @@ export const Flex = forwardRef<HTMLDivElement, FlexProps>(function Flex(
70
56
  gap={resolvedGap}
71
57
  rowGap={resolvedRowGap}
72
58
  columnGap={resolvedColumnGap}
59
+ flexDirection={direction}
60
+ alignItems={align}
61
+ justifyContent={justify}
62
+ flexWrap={wrap}
73
63
  >
74
64
  {children}
75
65
  </MUIBox>
@@ -0,0 +1,92 @@
1
+ .root {
2
+ /* Recursica Reset Boundary */
3
+ box-sizing: border-box;
4
+ display: flex;
5
+ margin: 0; /* Hardcoded structural reset */
6
+ width: 100%;
7
+
8
+ /* Recursica Layout Overrides mapped down dynamically from components */
9
+ padding: 0; /* Hardcoded structural reset */
10
+ max-width: var(--form-control-max-width);
11
+ min-width: var(--form-control-min-width);
12
+ }
13
+
14
+ /* =========================================
15
+ LAYOUT MODES
16
+ ========================================= */
17
+
18
+ .root[data-form-layout="stacked"] {
19
+ flex-direction: column;
20
+ }
21
+
22
+ .root[data-form-layout="side-by-side"] {
23
+ /* Aligns the Input/Component identically horizontally beside the label mapping */
24
+ flex-direction: row;
25
+ align-items: flex-start;
26
+ flex-wrap: wrap; /* Allows collapse if screen is too thin, though standard flex width should hold */
27
+ }
28
+
29
+ /* =========================================
30
+ GRID SECTIONS
31
+ ========================================= */
32
+
33
+ .leftSection {
34
+ flex-shrink: 0;
35
+ display: flex;
36
+ flex-direction: column;
37
+ }
38
+
39
+ /*
40
+ Stacked margins natively apply spacing *below* the label
41
+ */
42
+ .root[data-form-layout="stacked"] .leftSection {
43
+ margin-bottom: var(
44
+ --recursica_ui-kit_globals_form_properties_label-field-gap-vertical
45
+ );
46
+ }
47
+
48
+ /*
49
+ Side-by-side margins natively apply spacing *right* of the label
50
+ and forces vertical padding to align the label perfectly with 1st line of input text
51
+ */
52
+ .root[data-form-layout="side-by-side"] .leftSection {
53
+ margin-right: var(
54
+ --recursica_ui-kit_components_label_variants_layouts_side-by-side_properties_gutter
55
+ );
56
+ padding-top: var(
57
+ --recursica_ui-kit_components_label_variants_layouts_side-by-side_properties_vertical-padding
58
+ );
59
+ min-height: var(
60
+ --recursica_ui-kit_components_label_variants_layouts_side-by-side_properties_min-height
61
+ );
62
+ }
63
+
64
+ /* Label column sizing hooks (Only applies functionally in side-by-side mode) */
65
+ .root[data-form-layout="side-by-side"] .leftSection[data-label-size="small"] {
66
+ width: var(
67
+ --recursica_ui-kit_components_label_variants_layouts_side-by-side_variants_sizes_small_properties_width
68
+ );
69
+ }
70
+
71
+ .root[data-form-layout="side-by-side"] .leftSection[data-label-size="default"] {
72
+ width: var(
73
+ --recursica_ui-kit_components_label_variants_layouts_side-by-side_variants_sizes_default_properties_width
74
+ );
75
+ }
76
+
77
+ .root[data-form-layout="side-by-side"] .leftSection[data-label-size="md"] {
78
+ /* No 'medium' defined explicitly in generated token scope, mapped fallback to default */
79
+ width: var(
80
+ --recursica_ui-kit_components_label_variants_layouts_side-by-side_variants_sizes_default_properties_width
81
+ );
82
+ }
83
+
84
+ /*
85
+ Right Section dynamically wraps the input element natively
86
+ */
87
+ .rightSection {
88
+ display: flex; /* Groups internal field alongside subsequent errors/descriptions */
89
+ flex-direction: column;
90
+ flex: 1; /* Consumes the remaining x-axis in grid columns natively */
91
+ min-width: 0; /* Break boundary preventing internal flex explosion */
92
+ }