@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.
- package/ARCHITECTURE.md +15 -0
- package/CHANGELOG.md +15 -0
- package/SETUP.md +77 -0
- package/USAGE.md +55 -0
- package/dist/mui-adapter.cjs +74 -1
- package/dist/mui-adapter.cjs.map +1 -1
- package/dist/mui-adapter.css +1 -1
- package/dist/mui-adapter.js +6863 -205
- package/dist/mui-adapter.js.map +1 -1
- package/dist/src/components/Accordion/Accordion.d.ts +43 -2
- package/dist/src/components/AssistiveElement/AssistiveElement.d.ts +6 -2
- package/dist/src/components/Autocomplete/Autocomplete.d.ts +12 -2
- package/dist/src/components/Avatar/Avatar.d.ts +10 -3
- package/dist/src/components/Badge/Badge.d.ts +10 -3
- package/dist/src/components/Breadcrumb/Breadcrumb.d.ts +9 -3
- package/dist/src/components/Button/Button.d.ts +2 -17
- package/dist/src/components/Card/Card.d.ts +38 -3
- package/dist/src/components/Checkbox/Checkbox.d.ts +13 -2
- package/dist/src/components/Checkbox/CheckboxGroup.d.ts +18 -0
- package/dist/src/components/Checkbox/index.d.ts +5 -1
- package/dist/src/components/Chip/Chip.d.ts +9 -2
- package/dist/src/components/Container/Container.d.ts +1 -5
- package/dist/src/components/DatePicker/DatePicker.d.ts +2 -1
- package/dist/src/components/Dropdown/Dropdown.d.ts +12 -2
- package/dist/src/components/Flex/Flex.d.ts +2 -22
- package/dist/src/components/FormControlLayout/FormControlLayout.d.ts +5 -2
- package/dist/src/components/FormControlWrapper/FormControlWrapper.d.ts +9 -2
- package/dist/src/components/Group/Group.d.ts +2 -7
- package/dist/src/components/HoverCard/HoverCard.d.ts +28 -2
- package/dist/src/components/Label/Label.d.ts +6 -2
- package/dist/src/components/Link/Link.d.ts +2 -6
- package/dist/src/components/Loader/Loader.d.ts +2 -7
- package/dist/src/components/Menu/Menu.d.ts +25 -3
- package/dist/src/components/Modal/Modal.d.ts +37 -2
- package/dist/src/components/NumberInput/NumberInput.d.ts +12 -2
- package/dist/src/components/Pagination/Pagination.d.ts +12 -3
- package/dist/src/components/Pagination/Pagination.icons.d.ts +8 -0
- package/dist/src/components/Panel/Panel.d.ts +52 -3
- package/dist/src/components/Radio/Radio.d.ts +13 -3
- package/dist/src/components/Radio/RadioGroup.d.ts +9 -0
- package/dist/src/components/ReadOnlyField/ReadOnlyBooleanField.d.ts +5 -0
- package/dist/src/components/ReadOnlyField/ReadOnlyField.d.ts +4 -2
- package/dist/src/components/ReadOnlyField/ReadOnlySwitchField.d.ts +5 -0
- package/dist/src/components/ReadOnlyField/ReadOnlyTextField.d.ts +8 -0
- package/dist/src/components/ReadOnlyField/WithReadOnlyWrapper.d.ts +28 -0
- package/dist/src/components/ReadOnlyField/index.d.ts +1 -0
- package/dist/src/components/SegmentedControl/SegmentedControl.d.ts +21 -3
- package/dist/src/components/Slider/Slider.d.ts +18 -2
- package/dist/src/components/Stack/Stack.d.ts +2 -5
- package/dist/src/components/Stepper/Stepper.d.ts +41 -2
- package/dist/src/components/Switch/Switch.d.ts +10 -3
- package/dist/src/components/Switch/SwitchGroup.d.ts +13 -0
- package/dist/src/components/Table/Table.d.ts +2 -1
- package/dist/src/components/Tabs/Tabs.d.ts +20 -3
- package/dist/src/components/Text/Text.d.ts +2 -16
- package/dist/src/components/TextArea/TextArea.d.ts +12 -2
- package/dist/src/components/TextField/TextField.d.ts +12 -2
- package/dist/src/components/TimePicker/TimePicker.d.ts +2 -1
- package/dist/src/components/Timeline/Timeline.d.ts +15 -2
- package/dist/src/components/Timeline/TimelineItem.d.ts +18 -0
- package/dist/src/components/Title/Title.d.ts +2 -15
- package/dist/src/components/Toast/Toast.d.ts +20 -2
- package/dist/src/components/Tooltip/Tooltip.d.ts +28 -3
- package/dist/src/components/TransferList/TransferList.d.ts +2 -1
- package/dist/src/components/Typography/Typography.d.ts +1 -1
- package/dist/src/utils/RequireAccessibleLabel.d.ts +1 -18
- package/dist/src/utils/filterStylingProps.d.ts +1 -11
- package/llms.txt +16 -0
- package/package.json +14 -3
- package/src/components/Accordion/Accordion.module.css +294 -56
- package/src/components/Accordion/Accordion.stories.tsx +131 -21
- package/src/components/Accordion/Accordion.tsx +260 -5
- package/src/components/AssistiveElement/AssistiveElement.module.css +114 -20
- package/src/components/AssistiveElement/AssistiveElement.stories.tsx +60 -20
- package/src/components/AssistiveElement/AssistiveElement.tsx +81 -5
- package/src/components/Autocomplete/Autocomplete.module.css +319 -42
- package/src/components/Autocomplete/Autocomplete.stories.tsx +175 -23
- package/src/components/Autocomplete/Autocomplete.tsx +181 -6
- package/src/components/Avatar/Avatar.module.css +343 -73
- package/src/components/Avatar/Avatar.stories.tsx +94 -22
- package/src/components/Avatar/Avatar.tsx +99 -6
- package/src/components/Badge/Badge.module.css +127 -29
- package/src/components/Badge/Badge.stories.tsx +65 -22
- package/src/components/Badge/Badge.tsx +67 -6
- package/src/components/Breadcrumb/Breadcrumb.module.css +25 -5
- package/src/components/Breadcrumb/Breadcrumb.stories.tsx +57 -22
- package/src/components/Breadcrumb/Breadcrumb.tsx +59 -6
- package/src/components/Button/Button.module.css +19 -61
- package/src/components/Button/Button.stories.tsx +24 -23
- package/src/components/Button/Button.tsx +7 -18
- package/src/components/Card/Card.module.css +154 -38
- package/src/components/Card/Card.stories.tsx +117 -19
- package/src/components/Card/Card.tsx +181 -5
- package/src/components/Checkbox/Checkbox.module.css +249 -39
- package/src/components/Checkbox/Checkbox.stories.tsx +81 -19
- package/src/components/Checkbox/Checkbox.tsx +246 -5
- package/src/components/Checkbox/CheckboxGroup.stories.tsx +139 -0
- package/src/components/Checkbox/CheckboxGroup.tsx +137 -0
- package/src/components/Checkbox/index.ts +6 -1
- package/src/components/Chip/Chip.module.css +246 -43
- package/src/components/Chip/Chip.stories.tsx +101 -21
- package/src/components/Chip/Chip.tsx +136 -6
- package/src/components/Container/Container.stories.tsx +103 -20
- package/src/components/Container/Container.tsx +1 -13
- package/src/components/DatePicker/DatePicker.stories.tsx +125 -19
- package/src/components/DatePicker/DatePicker.tsx +3 -1
- package/src/components/Dropdown/Dropdown.module.css +291 -41
- package/src/components/Dropdown/Dropdown.stories.tsx +80 -21
- package/src/components/Dropdown/Dropdown.tsx +180 -6
- package/src/components/FileInput/FileInput.stories.tsx +2 -19
- package/src/components/FileUpload/FileUpload.stories.tsx +2 -19
- package/src/components/Flex/Flex.stories.tsx +113 -20
- package/src/components/Flex/Flex.tsx +16 -26
- package/src/components/FormControlLayout/FormControlLayout.module.css +92 -0
- package/src/components/FormControlLayout/FormControlLayout.stories.tsx +67 -20
- package/src/components/FormControlLayout/FormControlLayout.tsx +69 -4
- package/src/components/FormControlWrapper/FormControlWrapper.module.css +87 -0
- package/src/components/FormControlWrapper/FormControlWrapper.stories.tsx +116 -22
- package/src/components/FormControlWrapper/FormControlWrapper.tsx +126 -6
- package/src/components/Group/Group.stories.tsx +6 -30
- package/src/components/Group/Group.tsx +14 -9
- package/src/components/HoverCard/HoverCard.module.css +90 -22
- package/src/components/HoverCard/HoverCard.stories.tsx +158 -21
- package/src/components/HoverCard/HoverCard.tsx +147 -5
- package/src/components/Label/Label.module.css +140 -35
- package/src/components/Label/Label.stories.tsx +108 -21
- package/src/components/Label/Label.tsx +82 -5
- package/src/components/Link/Link.module.css +4 -3
- package/src/components/Link/Link.stories.tsx +2 -8
- package/src/components/Link/Link.tsx +1 -5
- package/src/components/Loader/Loader.module.css +1 -2
- package/src/components/Loader/Loader.tsx +1 -7
- package/src/components/Menu/IMPLEMENTATION_NOTES.md +4 -0
- package/src/components/Menu/Menu.module.css +285 -51
- package/src/components/Menu/Menu.stories.tsx +229 -25
- package/src/components/Menu/Menu.tsx +73 -6
- package/src/components/Modal/Modal.module.css +171 -35
- package/src/components/Modal/Modal.stories.tsx +66 -22
- package/src/components/Modal/Modal.tsx +215 -5
- package/src/components/NumberInput/NumberInput.module.css +276 -42
- package/src/components/NumberInput/NumberInput.stories.tsx +83 -20
- package/src/components/NumberInput/NumberInput.tsx +136 -6
- package/src/components/Pagination/IMPLEMENTATION_NOTES.md +3 -0
- package/src/components/Pagination/Pagination.icons.tsx +66 -0
- package/src/components/Pagination/Pagination.module.css +234 -20
- package/src/components/Pagination/Pagination.stories.tsx +34 -21
- package/src/components/Pagination/Pagination.tsx +74 -6
- package/src/components/Panel/Panel.module.css +206 -38
- package/src/components/Panel/Panel.stories.tsx +214 -22
- package/src/components/Panel/Panel.tsx +130 -5
- package/src/components/Radio/Radio.module.css +235 -37
- package/src/components/Radio/Radio.stories.tsx +77 -19
- package/src/components/Radio/Radio.tsx +210 -5
- package/src/components/Radio/RadioGroup.stories.tsx +117 -0
- package/src/components/Radio/RadioGroup.tsx +125 -0
- package/src/components/ReadOnlyField/ReadOnlyBooleanField.tsx +21 -0
- package/src/components/ReadOnlyField/ReadOnlyField.module.css +53 -15
- package/src/components/ReadOnlyField/ReadOnlyField.stories.tsx +147 -19
- package/src/components/ReadOnlyField/ReadOnlyField.tsx +105 -5
- package/src/components/ReadOnlyField/ReadOnlySwitchField.tsx +21 -0
- package/src/components/ReadOnlyField/ReadOnlyTextField.tsx +48 -0
- package/src/components/ReadOnlyField/WithReadOnlyWrapper.tsx +93 -0
- package/src/components/ReadOnlyField/index.ts +1 -0
- package/src/components/SegmentedControl/SegmentedControl.module.css +179 -47
- package/src/components/SegmentedControl/SegmentedControl.stories.tsx +102 -20
- package/src/components/SegmentedControl/SegmentedControl.tsx +140 -6
- package/src/components/Slider/Slider.module.css +539 -86
- package/src/components/Slider/Slider.stories.tsx +157 -19
- package/src/components/Slider/Slider.tsx +283 -5
- package/src/components/Stack/Stack.stories.tsx +4 -25
- package/src/components/Stack/Stack.tsx +1 -5
- package/src/components/Stepper/IMPLEMENTATION_NOTES.md +4 -0
- package/src/components/Stepper/Stepper.module.css +410 -71
- package/src/components/Stepper/Stepper.stories.tsx +146 -20
- package/src/components/Stepper/Stepper.tsx +147 -6
- package/src/components/Switch/Switch.module.css +259 -39
- package/src/components/Switch/Switch.stories.tsx +98 -19
- package/src/components/Switch/Switch.tsx +200 -6
- package/src/components/Switch/SwitchGroup.stories.tsx +132 -0
- package/src/components/Switch/SwitchGroup.tsx +120 -0
- package/src/components/Table/Table.stories.tsx +1 -19
- package/src/components/Table/Table.tsx +3 -1
- package/src/components/Tabs/IMPLEMENTATION_NOTES.md +4 -0
- package/src/components/Tabs/Tabs.module.css +422 -79
- package/src/components/Tabs/Tabs.stories.tsx +156 -20
- package/src/components/Tabs/Tabs.tsx +86 -6
- package/src/components/Text/Text.stories.tsx +5 -17
- package/src/components/Text/Text.tsx +1 -15
- package/src/components/TextArea/TextArea.module.css +155 -32
- package/src/components/TextArea/TextArea.stories.tsx +80 -21
- package/src/components/TextArea/TextArea.tsx +146 -6
- package/src/components/TextField/TextField.module.css +261 -42
- package/src/components/TextField/TextField.stories.tsx +147 -20
- package/src/components/TextField/TextField.tsx +169 -6
- package/src/components/TimePicker/TimePicker.stories.tsx +2 -19
- package/src/components/TimePicker/TimePicker.tsx +3 -1
- package/src/components/Timeline/Timeline.module.css +365 -76
- package/src/components/Timeline/Timeline.stories.tsx +114 -21
- package/src/components/Timeline/Timeline.tsx +83 -5
- package/src/components/Timeline/TimelineItem.tsx +90 -0
- package/src/components/Title/Title.stories.tsx +0 -18
- package/src/components/Title/Title.tsx +1 -7
- package/src/components/Toast/Toast.module.css +166 -28
- package/src/components/Toast/Toast.stories.tsx +54 -22
- package/src/components/Toast/Toast.tsx +124 -5
- package/src/components/Tooltip/Tooltip.module.css +89 -24
- package/src/components/Tooltip/Tooltip.stories.tsx +152 -22
- package/src/components/Tooltip/Tooltip.tsx +88 -5
- package/src/components/TransferList/TransferList.stories.tsx +1 -19
- package/src/components/TransferList/TransferList.tsx +3 -1
- package/src/utils/RequireAccessibleLabel.ts +1 -12
- package/src/utils/filterStylingProps.ts +7 -20
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import { Radio } from "./Radio";
|
|
3
|
+
import { RadioGroup } from "./RadioGroup";
|
|
4
|
+
import { useState } from "react";
|
|
5
|
+
import { formControlArgTypes } from "../../../.storybook/commonArgTypes";
|
|
6
|
+
|
|
7
|
+
const meta: Meta<typeof RadioGroup> = {
|
|
8
|
+
title: "UI-Kit/RadioGroup",
|
|
9
|
+
component: RadioGroup,
|
|
10
|
+
tags: ["autodocs"],
|
|
11
|
+
parameters: {
|
|
12
|
+
docs: {
|
|
13
|
+
description: {
|
|
14
|
+
component: `
|
|
15
|
+
The \`RadioGroup\` component is the mandatory organizational wrapper aggregating multiple \`Radio\` primitives into structurally bound unified selection arrays. It inherently leverages the \`FormControlWrapper\` granting native access to macroscopic layout structuring, assistive descriptions, and strict flex arrays.
|
|
16
|
+
|
|
17
|
+
We exclusively utilize the \`formLayout\` parameter to control macro-level form flow:
|
|
18
|
+
- **\`formLayout="stacked"\`**: Top-to-bottom layout cascading the Label bounding box down vertically into a standard stacked radio column array.
|
|
19
|
+
- **\`formLayout="side-by-side"\`**: Flow architecture pulling the grouping Label dynamically to the left while structurally organizing the internal radios cleanly alongside it horizontally.
|
|
20
|
+
`,
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
argTypes: {
|
|
25
|
+
...formControlArgTypes,
|
|
26
|
+
readOnly: {
|
|
27
|
+
control: "boolean",
|
|
28
|
+
description:
|
|
29
|
+
"Toggles structural read-only data presentation bypassing interaction boundaries completely.",
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export default meta;
|
|
35
|
+
|
|
36
|
+
type Story = StoryObj<typeof RadioGroup>;
|
|
37
|
+
|
|
38
|
+
export const Default: Story = {
|
|
39
|
+
args: {
|
|
40
|
+
formLayout: "stacked",
|
|
41
|
+
label: "Standard Group",
|
|
42
|
+
},
|
|
43
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
44
|
+
render: function StoryRender({ withLayer, layer, ...args }: any) {
|
|
45
|
+
const [value, setValue] = useState<string>("");
|
|
46
|
+
return (
|
|
47
|
+
<RadioGroup {...args} value={value} onChange={setValue}>
|
|
48
|
+
<Radio value="1" label="Option 1" />
|
|
49
|
+
<Radio value="2" label="Option 2" />
|
|
50
|
+
</RadioGroup>
|
|
51
|
+
);
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const StackedLayout: Story = {
|
|
56
|
+
args: {
|
|
57
|
+
formLayout: "stacked",
|
|
58
|
+
required: true,
|
|
59
|
+
label: "Hosting Provider",
|
|
60
|
+
error: "You must select a deployment provider.",
|
|
61
|
+
},
|
|
62
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
63
|
+
render: function StoryRender({ withLayer, layer, ...args }: any) {
|
|
64
|
+
const [value, setValue] = useState<string>("aws");
|
|
65
|
+
return (
|
|
66
|
+
<RadioGroup {...args} value={value} onChange={setValue}>
|
|
67
|
+
<Radio value="aws" label="Amazon Web Services" />
|
|
68
|
+
<Radio
|
|
69
|
+
value="gcp"
|
|
70
|
+
label="Google Cloud Platform (with completely distributed edge computing environments bridging local runtime boundaries seamlessly.)"
|
|
71
|
+
/>
|
|
72
|
+
<Radio value="azure" label="Microsoft Azure" />
|
|
73
|
+
</RadioGroup>
|
|
74
|
+
);
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export const SideBySideLayout: Story = {
|
|
79
|
+
args: {
|
|
80
|
+
formLayout: "side-by-side",
|
|
81
|
+
labelOptionalText: "Recommended",
|
|
82
|
+
labelWithEditIcon: true,
|
|
83
|
+
label: "Deployment Region",
|
|
84
|
+
assistiveText: "Select the data center closest to your user base.",
|
|
85
|
+
},
|
|
86
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
87
|
+
render: function StoryRender({ withLayer, layer, ...args }: any) {
|
|
88
|
+
const [value, setValue] = useState<string>("us-east");
|
|
89
|
+
return (
|
|
90
|
+
<RadioGroup {...args} value={value} onChange={setValue}>
|
|
91
|
+
<Radio value="us-east" label="US East (N. Virginia)" />
|
|
92
|
+
<Radio value="us-west" label="US West (Oregon)" />
|
|
93
|
+
<Radio value="eu-central" label="EU Central (Frankfurt)" />
|
|
94
|
+
</RadioGroup>
|
|
95
|
+
);
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
export const ReadOnly: Story = {
|
|
100
|
+
args: {
|
|
101
|
+
readOnly: true,
|
|
102
|
+
formLayout: "stacked",
|
|
103
|
+
required: true,
|
|
104
|
+
label: "Selected Framework",
|
|
105
|
+
assistiveText: "This selection cannot be changed after initialization.",
|
|
106
|
+
},
|
|
107
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
108
|
+
render: function StoryRender({ withLayer, layer, ...args }: any) {
|
|
109
|
+
const [value, setValue] = useState<string>("react");
|
|
110
|
+
return (
|
|
111
|
+
<RadioGroup {...args} value={value} onChange={setValue}>
|
|
112
|
+
<Radio value="react" label="React" />
|
|
113
|
+
<Radio value="vue" label="Vue" />
|
|
114
|
+
</RadioGroup>
|
|
115
|
+
);
|
|
116
|
+
},
|
|
117
|
+
};
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import React, { forwardRef } from "react";
|
|
2
|
+
import {
|
|
3
|
+
// Removed unused Radio import
|
|
4
|
+
RadioGroup as MuiRadioGroup,
|
|
5
|
+
type RadioGroupProps as MuiRadioGroupProps,
|
|
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 "./Radio.module.css";
|
|
15
|
+
|
|
16
|
+
import { type RecursicaRadioGroupProps as BaseRecursicaRadioGroupProps } from "@recursica/adapter-common";
|
|
17
|
+
|
|
18
|
+
export interface RecursicaRadioGroupProps
|
|
19
|
+
extends Omit<
|
|
20
|
+
MuiRadioGroupProps,
|
|
21
|
+
| "size"
|
|
22
|
+
| "labelProps"
|
|
23
|
+
| "classes"
|
|
24
|
+
| "ref"
|
|
25
|
+
| "onChange"
|
|
26
|
+
| "value"
|
|
27
|
+
| "defaultValue"
|
|
28
|
+
>,
|
|
29
|
+
Omit<
|
|
30
|
+
RecursicaFormControlWrapperProps,
|
|
31
|
+
| "controlMaxWidth"
|
|
32
|
+
| "controlMinWidth"
|
|
33
|
+
| "classes"
|
|
34
|
+
| "onChange"
|
|
35
|
+
| keyof MuiRadioGroupProps
|
|
36
|
+
>,
|
|
37
|
+
ReadOnlyControlProps,
|
|
38
|
+
BaseRecursicaRadioGroupProps {}
|
|
39
|
+
|
|
40
|
+
export type RadioGroupProps = RecursicaOverStyled<RecursicaRadioGroupProps>;
|
|
41
|
+
|
|
42
|
+
export const RadioGroup = forwardRef<HTMLDivElement, RadioGroupProps>(
|
|
43
|
+
function RadioGroup(props, ref) {
|
|
44
|
+
const {
|
|
45
|
+
overStyled = false,
|
|
46
|
+
formLayout = "stacked",
|
|
47
|
+
|
|
48
|
+
// Label Wrappers
|
|
49
|
+
labelSize,
|
|
50
|
+
labelAlignment,
|
|
51
|
+
labelOptionalText,
|
|
52
|
+
labelWithEditIcon,
|
|
53
|
+
onLabelEditClick,
|
|
54
|
+
|
|
55
|
+
// Base Mui Extracted Attributes
|
|
56
|
+
label,
|
|
57
|
+
description,
|
|
58
|
+
assistiveText,
|
|
59
|
+
assistiveWithIcon,
|
|
60
|
+
error,
|
|
61
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
62
|
+
required,
|
|
63
|
+
// Removed withAsterisk as it is not supported natively in this interface
|
|
64
|
+
id,
|
|
65
|
+
className,
|
|
66
|
+
style,
|
|
67
|
+
children,
|
|
68
|
+
readOnly,
|
|
69
|
+
readOnlyComponent,
|
|
70
|
+
emptyValueComponent,
|
|
71
|
+
value,
|
|
72
|
+
defaultValue,
|
|
73
|
+
...rest
|
|
74
|
+
} = props;
|
|
75
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
76
|
+
const restRecord = sanitizedProps as Record<string, unknown>;
|
|
77
|
+
|
|
78
|
+
// Delete prohibited sizing hooks from bypassing the variables
|
|
79
|
+
delete restRecord["size"];
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<WithReadOnlyWrapper
|
|
83
|
+
className={className}
|
|
84
|
+
style={style as React.CSSProperties}
|
|
85
|
+
controlMaxWidth="var(--recursica_ui-kit_components_radio-button-item_properties_max-width)"
|
|
86
|
+
controlMinWidth={undefined}
|
|
87
|
+
overStyled={overStyled as true}
|
|
88
|
+
// Strictly override. ARIA grouping prohibits interactive radios nested natively inside <label>.
|
|
89
|
+
formLayout={formLayout}
|
|
90
|
+
labelSize={labelSize}
|
|
91
|
+
labelAlignment={labelAlignment}
|
|
92
|
+
labelOptionalText={labelOptionalText}
|
|
93
|
+
labelWithEditIcon={labelWithEditIcon}
|
|
94
|
+
onLabelEditClick={onLabelEditClick}
|
|
95
|
+
label={label}
|
|
96
|
+
description={description}
|
|
97
|
+
assistiveText={assistiveText}
|
|
98
|
+
assistiveWithIcon={assistiveWithIcon}
|
|
99
|
+
error={error}
|
|
100
|
+
id={id}
|
|
101
|
+
readOnly={readOnly && !!readOnlyComponent}
|
|
102
|
+
readOnlyComponent={readOnlyComponent}
|
|
103
|
+
emptyValueComponent={emptyValueComponent}
|
|
104
|
+
readOnlyType="text"
|
|
105
|
+
readOnlyValue={value !== undefined ? value : defaultValue}
|
|
106
|
+
readOnlyNativeProps={props}
|
|
107
|
+
activeComponent={
|
|
108
|
+
<MuiRadioGroup
|
|
109
|
+
ref={ref}
|
|
110
|
+
/* Natively bind local disabled lock dynamically */
|
|
111
|
+
{...(sanitizedProps as unknown as MuiRadioGroupProps)}
|
|
112
|
+
value={value}
|
|
113
|
+
defaultValue={defaultValue}
|
|
114
|
+
className={styles.groupRoot}
|
|
115
|
+
data-layout={formLayout}
|
|
116
|
+
>
|
|
117
|
+
{children}
|
|
118
|
+
</MuiRadioGroup>
|
|
119
|
+
}
|
|
120
|
+
/>
|
|
121
|
+
);
|
|
122
|
+
},
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
RadioGroup.displayName = "RadioGroup";
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Box } from "@mui/material";
|
|
3
|
+
import styles from "./ReadOnlyField.module.css";
|
|
4
|
+
|
|
5
|
+
export const ReadOnlyBooleanField: React.FC<{
|
|
6
|
+
checked: boolean;
|
|
7
|
+
label?: React.ReactNode;
|
|
8
|
+
}> = ({ checked, label }) => {
|
|
9
|
+
return (
|
|
10
|
+
<Box
|
|
11
|
+
component="span"
|
|
12
|
+
className={styles.textField}
|
|
13
|
+
style={{ display: "inline-flex", gap: "8px", alignItems: "baseline" }}
|
|
14
|
+
>
|
|
15
|
+
{label && <span style={{ fontWeight: 500 }}>{label}:</span>}
|
|
16
|
+
<span>{checked ? "True" : "False"}</span>
|
|
17
|
+
</Box>
|
|
18
|
+
);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
ReadOnlyBooleanField.displayName = "ReadOnlyBooleanField";
|
|
@@ -1,16 +1,54 @@
|
|
|
1
|
-
/*
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
/* LAYOUT SPACING OVERRIDES:
|
|
2
|
+
- Sets the --form-control-margin-bottom spacing hook to map component-specific layout tokens. */
|
|
3
|
+
.root {
|
|
4
|
+
width: 100%;
|
|
5
|
+
--form-control-margin-bottom: var(
|
|
6
|
+
--recursica_ui-kit_components_read-only-field_variants_layouts_stacked_properties_top-bottom-margin
|
|
7
|
+
);
|
|
8
|
+
}
|
|
4
9
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
.root[data-form-layout="side-by-side"] {
|
|
11
|
+
--form-control-margin-bottom: var(
|
|
12
|
+
--recursica_ui-kit_components_read-only-field_variants_layouts_side-by-side_properties_top-bottom-margin
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.text {
|
|
17
|
+
margin: 0;
|
|
18
|
+
padding: 0;
|
|
19
|
+
display: flex;
|
|
20
|
+
align-items: center;
|
|
21
|
+
word-break: break-word;
|
|
22
|
+
|
|
23
|
+
font-family: var(
|
|
24
|
+
--recursica_ui-kit_components_read-only-field_properties_text_font-family
|
|
25
|
+
);
|
|
26
|
+
font-size: var(
|
|
27
|
+
--recursica_ui-kit_components_read-only-field_properties_text_font-size
|
|
28
|
+
);
|
|
29
|
+
font-style: var(
|
|
30
|
+
--recursica_ui-kit_components_read-only-field_properties_text_font-style
|
|
31
|
+
);
|
|
32
|
+
font-weight: var(
|
|
33
|
+
--recursica_ui-kit_components_read-only-field_properties_text_font-weight
|
|
34
|
+
);
|
|
35
|
+
letter-spacing: var(
|
|
36
|
+
--recursica_ui-kit_components_read-only-field_properties_text_letter-spacing
|
|
37
|
+
);
|
|
38
|
+
line-height: var(
|
|
39
|
+
--recursica_ui-kit_components_read-only-field_properties_text_line-height
|
|
40
|
+
);
|
|
41
|
+
text-decoration: var(
|
|
42
|
+
--recursica_ui-kit_components_read-only-field_properties_text_text-decoration
|
|
43
|
+
);
|
|
44
|
+
text-transform: var(
|
|
45
|
+
--recursica_ui-kit_components_read-only-field_properties_text_text-transform
|
|
46
|
+
);
|
|
47
|
+
color: var(
|
|
48
|
+
--recursica_ui-kit_components_read-only-field_properties_colors_text
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
min-height: var(
|
|
52
|
+
--recursica_ui-kit_components_read-only-field_properties_min-height
|
|
53
|
+
);
|
|
54
|
+
}
|
|
@@ -1,35 +1,163 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
1
2
|
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
3
|
import { ReadOnlyField } from "./ReadOnlyField";
|
|
3
|
-
import {
|
|
4
|
+
import { EmptyValueRenderer } from "@recursica/adapter-common";
|
|
4
5
|
|
|
5
6
|
const meta: Meta<typeof ReadOnlyField> = {
|
|
6
|
-
title: "UI
|
|
7
|
+
title: "UI Kit/ReadOnlyField",
|
|
7
8
|
component: ReadOnlyField,
|
|
8
9
|
tags: ["autodocs"],
|
|
9
10
|
parameters: {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
"component",
|
|
16
|
-
"variant",
|
|
17
|
-
"size",
|
|
18
|
-
"icon",
|
|
19
|
-
"disabled",
|
|
20
|
-
"href",
|
|
21
|
-
"onClick",
|
|
22
|
-
"onChange",
|
|
23
|
-
"value",
|
|
24
|
-
"checked",
|
|
25
|
-
],
|
|
11
|
+
docs: {
|
|
12
|
+
description: {
|
|
13
|
+
component:
|
|
14
|
+
"The ReadOnlyField safely natively wraps data sets bypassing active HTML interaction hooks while natively retaining exact bounding visual layouts defined by internal Design System Tokens. Useful for creating strict data-review profiles or conditional form read-overs.",
|
|
15
|
+
},
|
|
26
16
|
},
|
|
27
17
|
},
|
|
18
|
+
args: {
|
|
19
|
+
label: "Read Only Label",
|
|
20
|
+
value: "Fixed Data Set Value",
|
|
21
|
+
assistiveText: "Helper description text beneath the node.",
|
|
22
|
+
type: "text",
|
|
23
|
+
},
|
|
24
|
+
argTypes: {
|
|
25
|
+
type: {
|
|
26
|
+
control: "select",
|
|
27
|
+
options: ["text", "number"], // Add more as we support them
|
|
28
|
+
},
|
|
29
|
+
labelWithEditIcon: {
|
|
30
|
+
control: "boolean",
|
|
31
|
+
},
|
|
32
|
+
// We cannot natively control a React.ElementType through standard primitive storybook panels.
|
|
33
|
+
},
|
|
28
34
|
};
|
|
29
35
|
|
|
30
36
|
export default meta;
|
|
37
|
+
|
|
31
38
|
type Story = StoryObj<typeof ReadOnlyField>;
|
|
32
39
|
|
|
40
|
+
/**
|
|
41
|
+
* Playground story demonstrating standard structural blocks of the ReadOnlyField module dynamically.
|
|
42
|
+
*/
|
|
33
43
|
export const Default: Story = {
|
|
34
|
-
|
|
44
|
+
args: {},
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Shows the default handler replacing missing mapping data directly with 'N/A'.
|
|
49
|
+
*/
|
|
50
|
+
export const EmptyValue: Story = {
|
|
51
|
+
args: {
|
|
52
|
+
value: "",
|
|
53
|
+
label: "Empty String Evaluated Automatically (Default 'N/A')",
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const CustomEmptyTextRenderer: React.FC<{ value?: any }> & {
|
|
58
|
+
check?: (v: any) => boolean;
|
|
59
|
+
} = (props) => <EmptyValueRenderer {...props} emptyText="No Data Found" />;
|
|
60
|
+
CustomEmptyTextRenderer.check = EmptyValueRenderer.check;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Demonstrates overriding the baseline verbiage internally utilizing the exported `EmptyValueRenderer` while inheriting default evaluation checks.
|
|
64
|
+
*/
|
|
65
|
+
export const CustomEmptyText: Story = {
|
|
66
|
+
args: {
|
|
67
|
+
value: null,
|
|
68
|
+
label: "Custom Empty Text Default",
|
|
69
|
+
emptyValueComponent: CustomEmptyTextRenderer,
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const CustomEmptyCheckRenderer: React.FC<{ value?: any }> & {
|
|
74
|
+
check?: (v: any) => boolean;
|
|
75
|
+
} = () => {
|
|
76
|
+
return <i>Custom HTML Markup Provided</i>;
|
|
77
|
+
};
|
|
78
|
+
CustomEmptyCheckRenderer.check = (val) => val === "EMPTY_MOCK";
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Validates a fully overridden emptyValueComponent injecting custom rendering boundaries alongside explicitly tailored validation rules evaluating datasets dynamically.
|
|
82
|
+
*/
|
|
83
|
+
export const CustomEmptyRenderer: Story = {
|
|
84
|
+
args: {
|
|
85
|
+
value: "EMPTY_MOCK",
|
|
86
|
+
label: "Custom Logic Evaluation Binding",
|
|
87
|
+
emptyValueComponent: CustomEmptyCheckRenderer,
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Validates the core read-only label execution and base default spacing bindings globally.
|
|
93
|
+
*/
|
|
94
|
+
export const StackedDefault: Story = {
|
|
95
|
+
args: {
|
|
96
|
+
formLayout: "stacked",
|
|
97
|
+
value: "Some fixed readable text",
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Binds side-by-side structures globally maintaining correct inline gutter layouts.
|
|
103
|
+
*/
|
|
104
|
+
export const SideBySide: Story = {
|
|
105
|
+
args: {
|
|
106
|
+
formLayout: "side-by-side",
|
|
107
|
+
value: "Some fixed readable text mapping horizontally",
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Tests the fallback structural logic when Edit icon natively overrides required bindings.
|
|
113
|
+
*/
|
|
114
|
+
export const WithEditIcon: Story = {
|
|
115
|
+
args: {
|
|
116
|
+
labelWithEditIcon: true,
|
|
117
|
+
required: true,
|
|
118
|
+
value: "Editable fixed structure",
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Demonstrates how the generic ReadOnlyField handles mapping different internal data types.
|
|
124
|
+
* Currently, all types safely default to string extraction mapping into the text renderer natively.
|
|
125
|
+
*/
|
|
126
|
+
export const DataTypes: Story = {
|
|
127
|
+
args: {},
|
|
128
|
+
render: () => (
|
|
129
|
+
<div style={{ display: "flex", flexDirection: "column", gap: "24px" }}>
|
|
130
|
+
<ReadOnlyField
|
|
131
|
+
label="Text Mapping"
|
|
132
|
+
type="text"
|
|
133
|
+
value="Standard string output"
|
|
134
|
+
/>
|
|
135
|
+
<ReadOnlyField label="Number Mapping" type="number" value={1234567.89} />
|
|
136
|
+
<ReadOnlyField
|
|
137
|
+
label="Date Mapping"
|
|
138
|
+
type="date"
|
|
139
|
+
value={new Date("2026-04-28T12:00:00Z").toLocaleDateString()}
|
|
140
|
+
/>
|
|
141
|
+
<ReadOnlyField
|
|
142
|
+
label="Boolean Mapping (True)"
|
|
143
|
+
type="boolean"
|
|
144
|
+
value={true}
|
|
145
|
+
/>
|
|
146
|
+
<ReadOnlyField
|
|
147
|
+
label="Boolean Mapping (False)"
|
|
148
|
+
type="boolean"
|
|
149
|
+
value={false}
|
|
150
|
+
/>
|
|
151
|
+
<ReadOnlyField
|
|
152
|
+
label="Switch Mapping (True -> On)"
|
|
153
|
+
type="switch"
|
|
154
|
+
value={true}
|
|
155
|
+
/>
|
|
156
|
+
<ReadOnlyField
|
|
157
|
+
label="Switch Mapping (False -> Off)"
|
|
158
|
+
type="switch"
|
|
159
|
+
value={false}
|
|
160
|
+
/>
|
|
161
|
+
</div>
|
|
162
|
+
),
|
|
35
163
|
};
|
|
@@ -1,8 +1,108 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
1
2
|
import React from "react";
|
|
2
|
-
import "
|
|
3
|
+
import { type ReadOnlyControlProps } from "@recursica/adapter-common";
|
|
4
|
+
import {
|
|
5
|
+
FormControlWrapper,
|
|
6
|
+
type RecursicaFormControlWrapperProps,
|
|
7
|
+
} from "../FormControlWrapper/FormControlWrapper";
|
|
8
|
+
import styles from "./ReadOnlyField.module.css";
|
|
3
9
|
|
|
4
|
-
|
|
10
|
+
import { type RecursicaReadOnlyFieldProps as BaseRecursicaReadOnlyFieldProps } from "@recursica/adapter-common";
|
|
5
11
|
|
|
6
|
-
export
|
|
7
|
-
|
|
8
|
-
|
|
12
|
+
export type ReadOnlyFieldProps = Omit<
|
|
13
|
+
RecursicaFormControlWrapperProps,
|
|
14
|
+
"error" | "focused" | "controlMaxWidth" | "controlMinWidth"
|
|
15
|
+
> &
|
|
16
|
+
ReadOnlyControlProps &
|
|
17
|
+
BaseRecursicaReadOnlyFieldProps;
|
|
18
|
+
|
|
19
|
+
export const ReadOnlyField = React.forwardRef<
|
|
20
|
+
HTMLDivElement,
|
|
21
|
+
ReadOnlyFieldProps
|
|
22
|
+
>(function ReadOnlyField(props, ref) {
|
|
23
|
+
const {
|
|
24
|
+
value,
|
|
25
|
+
type = "text",
|
|
26
|
+
readOnlyComponent,
|
|
27
|
+
emptyValueComponent,
|
|
28
|
+
className,
|
|
29
|
+
...wrapperProps
|
|
30
|
+
} = props;
|
|
31
|
+
|
|
32
|
+
// Custom empty component bypass map handling dynamically explicitly
|
|
33
|
+
if (emptyValueComponent && typeof emptyValueComponent !== "string") {
|
|
34
|
+
const CustomEmptyRenderer = emptyValueComponent as React.FC<any> & {
|
|
35
|
+
check?: (val: any) => boolean;
|
|
36
|
+
};
|
|
37
|
+
if (CustomEmptyRenderer.check && CustomEmptyRenderer.check(value)) {
|
|
38
|
+
return (
|
|
39
|
+
<FormControlWrapper
|
|
40
|
+
ref={ref}
|
|
41
|
+
className={`${styles.root} ${className || ""}`}
|
|
42
|
+
{...wrapperProps}
|
|
43
|
+
>
|
|
44
|
+
<CustomEmptyRenderer value={value} />
|
|
45
|
+
</FormControlWrapper>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Value missing check mapping Default 'N/A' behavior mapping natively
|
|
51
|
+
const isMissing =
|
|
52
|
+
value === undefined ||
|
|
53
|
+
value === null ||
|
|
54
|
+
value === "" ||
|
|
55
|
+
(Array.isArray(value) && value.length === 0);
|
|
56
|
+
|
|
57
|
+
if (isMissing) {
|
|
58
|
+
return (
|
|
59
|
+
<FormControlWrapper
|
|
60
|
+
ref={ref}
|
|
61
|
+
className={`${styles.root} ${className || ""}`}
|
|
62
|
+
{...wrapperProps}
|
|
63
|
+
>
|
|
64
|
+
<p className={styles.text}>N/A</p>
|
|
65
|
+
</FormControlWrapper>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Override execution mapping securely
|
|
70
|
+
if (readOnlyComponent) {
|
|
71
|
+
const CustomReadOnlyRenderer = readOnlyComponent as React.ElementType;
|
|
72
|
+
return (
|
|
73
|
+
<FormControlWrapper
|
|
74
|
+
ref={ref}
|
|
75
|
+
className={`${styles.root} ${className || ""}`}
|
|
76
|
+
{...wrapperProps}
|
|
77
|
+
>
|
|
78
|
+
<CustomReadOnlyRenderer value={value as any} />
|
|
79
|
+
</FormControlWrapper>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Type coercions securely bounding the output values cleanly explicitly.
|
|
84
|
+
let displayValue: React.ReactNode = value;
|
|
85
|
+
|
|
86
|
+
if (type === "boolean" || type === "switch") {
|
|
87
|
+
displayValue = value ? "True" : "False";
|
|
88
|
+
if (type === "switch") {
|
|
89
|
+
displayValue = value ? "On" : "Off";
|
|
90
|
+
}
|
|
91
|
+
} else if (Array.isArray(value)) {
|
|
92
|
+
displayValue = value.join(", ");
|
|
93
|
+
} else {
|
|
94
|
+
displayValue = String(value);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return (
|
|
98
|
+
<FormControlWrapper
|
|
99
|
+
ref={ref}
|
|
100
|
+
className={`${styles.root} ${className || ""}`}
|
|
101
|
+
{...wrapperProps}
|
|
102
|
+
>
|
|
103
|
+
<p className={styles.text}>{displayValue}</p>
|
|
104
|
+
</FormControlWrapper>
|
|
105
|
+
);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
ReadOnlyField.displayName = "ReadOnlyField";
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Box } from "@mui/material";
|
|
3
|
+
import styles from "./ReadOnlyField.module.css";
|
|
4
|
+
|
|
5
|
+
export const ReadOnlySwitchField: React.FC<{
|
|
6
|
+
checked: boolean;
|
|
7
|
+
label?: React.ReactNode;
|
|
8
|
+
}> = ({ checked, label }) => {
|
|
9
|
+
return (
|
|
10
|
+
<Box
|
|
11
|
+
component="span"
|
|
12
|
+
className={styles.textField}
|
|
13
|
+
style={{ display: "inline-flex", gap: "8px", alignItems: "baseline" }}
|
|
14
|
+
>
|
|
15
|
+
{label && <span style={{ fontWeight: 500 }}>{label}:</span>}
|
|
16
|
+
<span>{checked ? "On" : "Off"}</span>
|
|
17
|
+
</Box>
|
|
18
|
+
);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
ReadOnlySwitchField.displayName = "ReadOnlySwitchField";
|