@recursica/mantine-adapter 0.10.0 → 0.12.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/CHANGELOG.md +16 -0
- package/README.md +6 -28
- package/dist/mantine-adapter.cjs +1 -1
- package/dist/mantine-adapter.cjs.map +1 -1
- package/dist/mantine-adapter.css +1 -1
- package/dist/mantine-adapter.js +1650 -1344
- package/dist/mantine-adapter.js.map +1 -1
- package/dist/src/components/Checkbox/Checkbox.d.ts +3 -1
- package/dist/src/components/FormControlLayout/FormControlLayout.d.ts +21 -0
- package/dist/src/components/FormControlWrapper/FormControlWrapper.d.ts +2 -0
- package/dist/src/components/Label/Label.d.ts +1 -3
- package/dist/src/components/Menu/Menu.d.ts +85 -3
- package/dist/src/components/Radio/Radio.d.ts +3 -1
- package/dist/src/components/ReadOnlyField/ReadOnlyBooleanField.d.ts +5 -0
- package/dist/src/components/ReadOnlyField/ReadOnlyField.d.ts +6 -6
- package/dist/src/components/ReadOnlyField/ReadOnlySwitchField.d.ts +5 -0
- package/dist/src/components/ReadOnlyField/WithReadOnlyWrapper.d.ts +7 -1
- package/dist/src/components/ReadOnlyField/index.d.ts +2 -0
- package/dist/src/components/Switch/Switch.d.ts +3 -1
- package/dist/src/components/index.d.ts +1 -0
- package/dist/src/utils/RequireAccessibleLabel.d.ts +18 -0
- package/package.json +1 -1
- package/src/components/AssistiveElement/AssistiveElement.stories.tsx +6 -4
- package/src/components/Avatar/Avatar.stories.tsx +10 -5
- package/src/components/Badge/Badge.stories.tsx +2 -1
- package/src/components/Button/Button.stories.tsx +2 -4
- package/src/components/Checkbox/Checkbox.module.css +1 -1
- package/src/components/Checkbox/Checkbox.stories.tsx +24 -3
- package/src/components/Checkbox/Checkbox.tsx +72 -15
- package/src/components/Checkbox/CheckboxGroup.stories.tsx +26 -25
- package/src/components/Checkbox/CheckboxGroup.tsx +38 -58
- package/src/components/Container/Container.stories.tsx +6 -3
- package/src/components/DatePicker/DatePicker.stories.tsx +1 -5
- package/src/components/Dropdown/Dropdown.stories.tsx +0 -3
- package/src/components/Dropdown/Dropdown.tsx +6 -5
- package/src/components/FileInput/FileInput.stories.tsx +1 -5
- package/src/components/FileUpload/FileUpload.stories.tsx +1 -5
- package/src/components/Flex/Flex.stories.tsx +6 -3
- package/src/components/FormControlLayout/FormControlLayout.module.css +80 -0
- package/src/components/FormControlLayout/FormControlLayout.stories.tsx +82 -0
- package/src/components/FormControlLayout/FormControlLayout.tsx +78 -0
- package/src/components/FormControlWrapper/FormControlWrapper.module.css +3 -41
- package/src/components/FormControlWrapper/FormControlWrapper.stories.tsx +18 -5
- package/src/components/FormControlWrapper/FormControlWrapper.tsx +28 -41
- package/src/components/Group/Group.stories.tsx +6 -3
- package/src/components/Label/Label.module.css +0 -37
- package/src/components/Label/Label.stories.tsx +8 -9
- package/src/components/Label/Label.tsx +2 -7
- package/src/components/Loader/Loader.stories.tsx +10 -5
- package/src/components/Menu/MENU_IMPLEMENTATION_NOTES.md +78 -0
- package/src/components/Menu/Menu.module.css +244 -0
- package/src/components/Menu/Menu.stories.tsx +309 -5
- package/src/components/Menu/Menu.tsx +317 -4
- package/src/components/NumberInput/NumberInput.stories.tsx +1 -5
- package/src/components/Radio/Radio.stories.tsx +22 -8
- package/src/components/Radio/Radio.tsx +134 -75
- package/src/components/Radio/RadioGroup.stories.tsx +26 -7
- package/src/components/Radio/RadioGroup.tsx +37 -57
- package/src/components/ReadOnlyField/ReadOnlyBooleanField.tsx +21 -0
- package/src/components/ReadOnlyField/ReadOnlyField.stories.tsx +43 -0
- package/src/components/ReadOnlyField/ReadOnlyField.tsx +30 -3
- package/src/components/ReadOnlyField/ReadOnlySwitchField.tsx +21 -0
- package/src/components/ReadOnlyField/ReadOnlyTextField.tsx +3 -1
- package/src/components/ReadOnlyField/WithReadOnlyWrapper.tsx +10 -2
- package/src/components/ReadOnlyField/index.ts +2 -0
- package/src/components/SegmentedControl/SegmentedControl.stories.tsx +1 -5
- package/src/components/Slider/Slider.stories.tsx +1 -5
- package/src/components/Stack/Stack.stories.tsx +6 -3
- package/src/components/Switch/Switch.module.css +2 -10
- package/src/components/Switch/Switch.stories.tsx +42 -27
- package/src/components/Switch/Switch.tsx +138 -89
- package/src/components/Switch/SwitchGroup.stories.tsx +28 -8
- package/src/components/Switch/SwitchGroup.tsx +37 -57
- package/src/components/TextArea/TextArea.stories.tsx +0 -3
- package/src/components/TextArea/TextArea.tsx +6 -5
- package/src/components/TextField/TextField.tsx +6 -5
- package/src/components/TimePicker/TimePicker.stories.tsx +1 -5
- package/src/components/index.ts +1 -0
- package/src/utils/RequireAccessibleLabel.ts +12 -0
|
@@ -35,14 +35,32 @@ export default meta;
|
|
|
35
35
|
|
|
36
36
|
type Story = StoryObj<typeof RadioGroup>;
|
|
37
37
|
|
|
38
|
-
export const
|
|
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 = {
|
|
39
56
|
args: {
|
|
40
57
|
formLayout: "stacked",
|
|
41
58
|
required: true,
|
|
42
59
|
label: "Hosting Provider",
|
|
43
60
|
error: "You must select a deployment provider.",
|
|
44
61
|
},
|
|
45
|
-
|
|
62
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
63
|
+
render: function StoryRender({ withLayer, layer, ...args }: any) {
|
|
46
64
|
const [value, setValue] = useState<string>("aws");
|
|
47
65
|
return (
|
|
48
66
|
<RadioGroup {...args} value={value} onChange={setValue}>
|
|
@@ -57,7 +75,7 @@ export const GroupStacked: Story = {
|
|
|
57
75
|
},
|
|
58
76
|
};
|
|
59
77
|
|
|
60
|
-
export const
|
|
78
|
+
export const SideBySideLayout: Story = {
|
|
61
79
|
args: {
|
|
62
80
|
formLayout: "side-by-side",
|
|
63
81
|
labelOptionalText: "Recommended",
|
|
@@ -65,7 +83,8 @@ export const GroupSideBySide: Story = {
|
|
|
65
83
|
label: "Deployment Region",
|
|
66
84
|
assistiveText: "Select the data center closest to your user base.",
|
|
67
85
|
},
|
|
68
|
-
|
|
86
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
87
|
+
render: function StoryRender({ withLayer, layer, ...args }: any) {
|
|
69
88
|
const [value, setValue] = useState<string>("us-east");
|
|
70
89
|
return (
|
|
71
90
|
<RadioGroup {...args} value={value} onChange={setValue}>
|
|
@@ -77,16 +96,16 @@ export const GroupSideBySide: Story = {
|
|
|
77
96
|
},
|
|
78
97
|
};
|
|
79
98
|
|
|
80
|
-
export const
|
|
99
|
+
export const ReadOnly: Story = {
|
|
81
100
|
args: {
|
|
82
101
|
readOnly: true,
|
|
83
102
|
formLayout: "stacked",
|
|
84
103
|
required: true,
|
|
85
104
|
label: "Selected Framework",
|
|
86
105
|
assistiveText: "This selection cannot be changed after initialization.",
|
|
87
|
-
readOnlyComponent: <span>React (Standard Build)</span>,
|
|
88
106
|
},
|
|
89
|
-
|
|
107
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
108
|
+
render: function StoryRender({ withLayer, layer, ...args }: any) {
|
|
90
109
|
const [value, setValue] = useState<string>("react");
|
|
91
110
|
return (
|
|
92
111
|
<RadioGroup {...args} value={value} onChange={setValue}>
|
|
@@ -9,10 +9,8 @@ import {
|
|
|
9
9
|
filterStylingProps,
|
|
10
10
|
type RecursicaOverStyled,
|
|
11
11
|
} from "../../utils/filterStylingProps";
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
type RecursicaFormControlWrapperProps,
|
|
15
|
-
} from "../FormControlWrapper/FormControlWrapper";
|
|
12
|
+
import { type RecursicaFormControlWrapperProps } from "../FormControlWrapper/FormControlWrapper";
|
|
13
|
+
import { WithReadOnlyWrapper } from "../ReadOnlyField/WithReadOnlyWrapper";
|
|
16
14
|
import styles from "./Radio.module.css";
|
|
17
15
|
|
|
18
16
|
export interface RecursicaRadioGroupProps
|
|
@@ -26,8 +24,8 @@ export interface RecursicaRadioGroupProps
|
|
|
26
24
|
export type RadioGroupProps = RecursicaOverStyled<RecursicaRadioGroupProps>;
|
|
27
25
|
|
|
28
26
|
export const RadioGroup = forwardRef<HTMLDivElement, RadioGroupProps>(
|
|
29
|
-
function RadioGroup(
|
|
30
|
-
{
|
|
27
|
+
function RadioGroup(props, ref) {
|
|
28
|
+
const {
|
|
31
29
|
overStyled = false,
|
|
32
30
|
formLayout = "stacked",
|
|
33
31
|
|
|
@@ -52,47 +50,19 @@ export const RadioGroup = forwardRef<HTMLDivElement, RadioGroupProps>(
|
|
|
52
50
|
children,
|
|
53
51
|
readOnly,
|
|
54
52
|
readOnlyComponent,
|
|
53
|
+
emptyValueComponent,
|
|
54
|
+
value,
|
|
55
|
+
defaultValue,
|
|
55
56
|
...rest
|
|
56
|
-
}
|
|
57
|
-
ref,
|
|
58
|
-
) {
|
|
57
|
+
} = props;
|
|
59
58
|
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
60
59
|
const restRecord = sanitizedProps as Record<string, unknown>;
|
|
61
60
|
|
|
62
61
|
// Delete prohibited sizing hooks from bypassing the variables
|
|
63
62
|
delete restRecord["size"];
|
|
64
63
|
|
|
65
|
-
if (readOnly && readOnlyComponent) {
|
|
66
|
-
return (
|
|
67
|
-
<FormControlWrapper
|
|
68
|
-
className={className}
|
|
69
|
-
style={style as React.CSSProperties}
|
|
70
|
-
controlMaxWidth="var(--recursica_ui-kit_components_radio-button-item_properties_max-width)"
|
|
71
|
-
controlMinWidth={undefined}
|
|
72
|
-
overStyled={overStyled as true}
|
|
73
|
-
labelElement="div"
|
|
74
|
-
formLayout={formLayout}
|
|
75
|
-
labelSize={labelSize}
|
|
76
|
-
labelAlignment={labelAlignment}
|
|
77
|
-
labelOptionalText={labelOptionalText}
|
|
78
|
-
labelWithEditIcon={labelWithEditIcon}
|
|
79
|
-
onLabelEditClick={onLabelEditClick}
|
|
80
|
-
label={label}
|
|
81
|
-
description={description}
|
|
82
|
-
assistiveText={assistiveText}
|
|
83
|
-
assistiveWithIcon={assistiveWithIcon}
|
|
84
|
-
error={error}
|
|
85
|
-
required={required}
|
|
86
|
-
withAsterisk={withAsterisk}
|
|
87
|
-
id={id}
|
|
88
|
-
>
|
|
89
|
-
{readOnlyComponent}
|
|
90
|
-
</FormControlWrapper>
|
|
91
|
-
);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
64
|
return (
|
|
95
|
-
<
|
|
65
|
+
<WithReadOnlyWrapper
|
|
96
66
|
className={className}
|
|
97
67
|
style={style as React.CSSProperties}
|
|
98
68
|
controlMaxWidth="var(--recursica_ui-kit_components_radio-button-item_properties_max-width)"
|
|
@@ -113,24 +83,34 @@ export const RadioGroup = forwardRef<HTMLDivElement, RadioGroupProps>(
|
|
|
113
83
|
required={required}
|
|
114
84
|
withAsterisk={withAsterisk}
|
|
115
85
|
id={id}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
86
|
+
readOnly={readOnly && !!readOnlyComponent}
|
|
87
|
+
readOnlyComponent={readOnlyComponent}
|
|
88
|
+
emptyValueComponent={emptyValueComponent}
|
|
89
|
+
readOnlyType="text"
|
|
90
|
+
readOnlyValue={value !== undefined ? value : defaultValue}
|
|
91
|
+
readOnlyNativeProps={props}
|
|
92
|
+
activeComponent={
|
|
93
|
+
<MantineRadio.Group
|
|
94
|
+
ref={ref}
|
|
95
|
+
/* Natively bind local disabled lock dynamically */
|
|
96
|
+
{...(sanitizedProps as unknown as MantineRadioGroupProps)}
|
|
97
|
+
disabled={readOnly || (restRecord as any).disabled}
|
|
98
|
+
value={value}
|
|
99
|
+
defaultValue={defaultValue}
|
|
100
|
+
>
|
|
101
|
+
<div className={styles.groupRoot} data-layout={formLayout}>
|
|
102
|
+
{React.Children.map(children, (child) => {
|
|
103
|
+
if (React.isValidElement(child)) {
|
|
104
|
+
return React.cloneElement(child as React.ReactElement<any>, {
|
|
105
|
+
disabled: readOnly || (child.props as any).disabled,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
return child;
|
|
109
|
+
})}
|
|
110
|
+
</div>
|
|
111
|
+
</MantineRadio.Group>
|
|
112
|
+
}
|
|
113
|
+
/>
|
|
134
114
|
);
|
|
135
115
|
},
|
|
136
116
|
);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Box } from "@mantine/core";
|
|
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";
|
|
@@ -118,3 +118,46 @@ export const WithEditIcon: Story = {
|
|
|
118
118
|
value: "Editable fixed structure",
|
|
119
119
|
},
|
|
120
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
|
+
),
|
|
163
|
+
};
|
|
@@ -3,6 +3,7 @@ import React, { forwardRef } from "react";
|
|
|
3
3
|
import {
|
|
4
4
|
ReadOnlyFieldType,
|
|
5
5
|
EmptyValueRenderer,
|
|
6
|
+
type ReadOnlyControlProps,
|
|
6
7
|
} from "@recursica/adapter-common";
|
|
7
8
|
import {
|
|
8
9
|
filterStylingProps,
|
|
@@ -15,13 +16,19 @@ import {
|
|
|
15
16
|
import { ReadOnlyTextField } from "./ReadOnlyTextField";
|
|
16
17
|
|
|
17
18
|
export interface RecursicaReadOnlyFieldProps
|
|
18
|
-
extends Omit<
|
|
19
|
+
extends Omit<
|
|
20
|
+
FormControlWrapperProps,
|
|
21
|
+
"children" | "overStyled" | "controlMaxWidth" | "controlMinWidth"
|
|
22
|
+
>,
|
|
23
|
+
Pick<ReadOnlyControlProps, "emptyValueComponent"> {
|
|
19
24
|
/** The specific value to be rendered in read-only mode explicitly matching the original field input */
|
|
20
25
|
value?: any;
|
|
21
26
|
/** The data type formatting rules bounding how the string is presented to the user */
|
|
22
27
|
type?: ReadOnlyFieldType;
|
|
23
|
-
/**
|
|
24
|
-
|
|
28
|
+
/** Pass the native maximum width design variable dynamically bounding the specific wrapper width exclusively. */
|
|
29
|
+
controlMaxWidth?: string | undefined;
|
|
30
|
+
/** Pass the native minimum width design variable dynamically bounding the specific wrapper width exclusively. */
|
|
31
|
+
controlMinWidth?: string | undefined;
|
|
25
32
|
}
|
|
26
33
|
|
|
27
34
|
export type ReadOnlyFieldProps =
|
|
@@ -49,6 +56,26 @@ export const ReadOnlyField = forwardRef<HTMLDivElement, ReadOnlyFieldProps>(
|
|
|
49
56
|
const displayValue = isValueEmpty ? <Renderer value={value} /> : value;
|
|
50
57
|
|
|
51
58
|
switch (type) {
|
|
59
|
+
case "boolean":
|
|
60
|
+
content = (
|
|
61
|
+
<ReadOnlyTextField
|
|
62
|
+
value={
|
|
63
|
+
value === true ? "True" : value === false ? "False" : displayValue
|
|
64
|
+
}
|
|
65
|
+
overStyled={overStyled as true}
|
|
66
|
+
/>
|
|
67
|
+
);
|
|
68
|
+
break;
|
|
69
|
+
case "switch":
|
|
70
|
+
content = (
|
|
71
|
+
<ReadOnlyTextField
|
|
72
|
+
value={
|
|
73
|
+
value === true ? "On" : value === false ? "Off" : displayValue
|
|
74
|
+
}
|
|
75
|
+
overStyled={overStyled as true}
|
|
76
|
+
/>
|
|
77
|
+
);
|
|
78
|
+
break;
|
|
52
79
|
case "text":
|
|
53
80
|
default:
|
|
54
81
|
content = (
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Box } from "@mantine/core";
|
|
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";
|
|
@@ -12,7 +12,11 @@ export interface WithReadOnlyWrapperProps
|
|
|
12
12
|
/** Injects whether the field defaults to reading mode natively */
|
|
13
13
|
readOnly?: boolean;
|
|
14
14
|
/** Explicit React component directly overtaking the baseline text renderer when read-only mode is active */
|
|
15
|
-
readOnlyComponent?: React.
|
|
15
|
+
readOnlyComponent?: React.ElementType<any>;
|
|
16
|
+
/** Custom renderer explicitly responsible for formatting missing/empty value mappings (overriding default 'N/A') */
|
|
17
|
+
emptyValueComponent?: React.ElementType<{ value?: any }>;
|
|
18
|
+
/** The full native props dictionary securely forwarded into the custom readOnlyComponent if active */
|
|
19
|
+
readOnlyNativeProps?: any;
|
|
16
20
|
/** Instructs the underlying generic ReadOnlyField which raw visual structure to bridge automatically */
|
|
17
21
|
readOnlyType?: ReadOnlyFieldType;
|
|
18
22
|
/** The isolated raw data value intercepted explicitly into the ReadOnly formatters */
|
|
@@ -36,6 +40,8 @@ export const WithReadOnlyWrapper = forwardRef<
|
|
|
36
40
|
readOnlyComponent,
|
|
37
41
|
readOnlyType = "text",
|
|
38
42
|
readOnlyValue,
|
|
43
|
+
readOnlyNativeProps,
|
|
44
|
+
emptyValueComponent,
|
|
39
45
|
activeComponent,
|
|
40
46
|
overStyled,
|
|
41
47
|
onLabelEditClick,
|
|
@@ -45,6 +51,7 @@ export const WithReadOnlyWrapper = forwardRef<
|
|
|
45
51
|
) {
|
|
46
52
|
if (readOnly) {
|
|
47
53
|
if (readOnlyComponent) {
|
|
54
|
+
const ReadOnlyComponent = readOnlyComponent;
|
|
48
55
|
return (
|
|
49
56
|
<FormControlWrapper
|
|
50
57
|
ref={ref}
|
|
@@ -52,7 +59,7 @@ export const WithReadOnlyWrapper = forwardRef<
|
|
|
52
59
|
onLabelEditClick={onLabelEditClick}
|
|
53
60
|
overStyled={overStyled as true}
|
|
54
61
|
>
|
|
55
|
-
{
|
|
62
|
+
<ReadOnlyComponent {...readOnlyNativeProps} />
|
|
56
63
|
</FormControlWrapper>
|
|
57
64
|
);
|
|
58
65
|
}
|
|
@@ -62,6 +69,7 @@ export const WithReadOnlyWrapper = forwardRef<
|
|
|
62
69
|
ref={ref}
|
|
63
70
|
type={readOnlyType}
|
|
64
71
|
value={readOnlyValue}
|
|
72
|
+
emptyValueComponent={emptyValueComponent}
|
|
65
73
|
onLabelEditClick={onLabelEditClick}
|
|
66
74
|
overStyled={overStyled as true}
|
|
67
75
|
{...wrapperProps}
|
|
@@ -69,7 +69,8 @@ export default meta;
|
|
|
69
69
|
type Story = StoryObj<StackStoryProps>;
|
|
70
70
|
|
|
71
71
|
export const Default: Story = {
|
|
72
|
-
|
|
72
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
73
|
+
render: ({ withLayer, layer, ...args }: any) => (
|
|
73
74
|
<Stack {...args}>
|
|
74
75
|
<Button variant="solid">Primary Block</Button>
|
|
75
76
|
<Button variant="outline">Secondary Block</Button>
|
|
@@ -82,7 +83,8 @@ export const StaticGapSmall: Story = {
|
|
|
82
83
|
args: {
|
|
83
84
|
gap: "rec-sm",
|
|
84
85
|
},
|
|
85
|
-
|
|
86
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
87
|
+
render: ({ withLayer, layer, ...args }: any) => (
|
|
86
88
|
<Stack {...args}>
|
|
87
89
|
<Button variant="solid">Item 1</Button>
|
|
88
90
|
<Button variant="solid">Item 2</Button>
|
|
@@ -95,7 +97,8 @@ export const StaticGapLarge: Story = {
|
|
|
95
97
|
args: {
|
|
96
98
|
gap: "rec-xl",
|
|
97
99
|
},
|
|
98
|
-
|
|
100
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
101
|
+
render: ({ withLayer, layer, ...args }: any) => (
|
|
99
102
|
<Stack {...args}>
|
|
100
103
|
<Button variant="solid">Item 1</Button>
|
|
101
104
|
<Button variant="solid">Item 2</Button>
|
|
@@ -190,18 +190,10 @@
|
|
|
190
190
|
|
|
191
191
|
.groupRoot {
|
|
192
192
|
display: flex;
|
|
193
|
+
flex-direction: column;
|
|
194
|
+
align-items: flex-start;
|
|
193
195
|
gap: var(
|
|
194
196
|
--recursica_ui-kit_components_switch_properties_label-switch-gap,
|
|
195
197
|
16px
|
|
196
198
|
);
|
|
197
199
|
}
|
|
198
|
-
|
|
199
|
-
.groupRoot[data-layout="stacked"] {
|
|
200
|
-
flex-direction: column;
|
|
201
|
-
align-items: flex-start;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
.groupRoot[data-layout="side-by-side"] {
|
|
205
|
-
flex-direction: row;
|
|
206
|
-
align-items: center;
|
|
207
|
-
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
2
|
import { Switch } from "./Switch";
|
|
3
|
+
import { Stack } from "../Stack/Stack";
|
|
3
4
|
|
|
4
5
|
const meta: Meta<typeof Switch> = {
|
|
5
6
|
title: "UI-Kit/Switch",
|
|
@@ -24,9 +25,6 @@ To render a standard switch:
|
|
|
24
25
|
},
|
|
25
26
|
},
|
|
26
27
|
argTypes: {
|
|
27
|
-
disabled: {
|
|
28
|
-
control: "boolean",
|
|
29
|
-
},
|
|
30
28
|
checked: {
|
|
31
29
|
control: "boolean",
|
|
32
30
|
},
|
|
@@ -44,6 +42,9 @@ To render a standard switch:
|
|
|
44
42
|
description:
|
|
45
43
|
"Toggles structural read-only data presentation bypassing interaction boundaries completely.",
|
|
46
44
|
},
|
|
45
|
+
controlMaxWidth: { table: { disable: true } },
|
|
46
|
+
controlMinWidth: { table: { disable: true } },
|
|
47
|
+
emptyValueComponent: { table: { disable: true } },
|
|
47
48
|
},
|
|
48
49
|
};
|
|
49
50
|
|
|
@@ -56,41 +57,55 @@ export const Default: Story = {
|
|
|
56
57
|
disabled: false,
|
|
57
58
|
label: "Standard Switch",
|
|
58
59
|
},
|
|
60
|
+
// We explicitly destructure global Storybook injected arguments so they do not leak into the DOM natively.
|
|
61
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
62
|
+
render: ({ withLayer, layer, ...args }: any) => <Switch {...args} />,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const SideBySideLayout: Story = {
|
|
66
|
+
args: {
|
|
67
|
+
label: "Opt-in form alignment",
|
|
68
|
+
formLayout: "side-by-side",
|
|
69
|
+
},
|
|
70
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
71
|
+
render: ({ withLayer, layer, ...args }: any) => <Switch {...args} />,
|
|
59
72
|
};
|
|
60
73
|
|
|
61
74
|
export const StaticVariations: Story = {
|
|
62
75
|
args: {},
|
|
63
76
|
render: () => (
|
|
64
|
-
<
|
|
65
|
-
style={{
|
|
66
|
-
display: "flex",
|
|
67
|
-
flexDirection: "column",
|
|
68
|
-
gap: "24px",
|
|
69
|
-
}}
|
|
70
|
-
>
|
|
77
|
+
<Stack gap="xl">
|
|
71
78
|
<Switch label="Default Unchecked State" />
|
|
72
79
|
<Switch label="Checked State" defaultChecked />
|
|
73
80
|
<Switch label="Disabled Unchecked" disabled />
|
|
74
81
|
<Switch label="Disabled Checked" defaultChecked disabled />
|
|
75
|
-
</
|
|
82
|
+
</Stack>
|
|
76
83
|
),
|
|
77
84
|
};
|
|
78
85
|
|
|
79
|
-
export const
|
|
80
|
-
args: {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
86
|
+
export const ReadOnly: Story = {
|
|
87
|
+
args: {
|
|
88
|
+
...Default.args,
|
|
89
|
+
readOnly: true,
|
|
90
|
+
},
|
|
91
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
92
|
+
render: ({ withLayer, layer, ...args }: any) => <Switch {...args} />,
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export const CustomReadOnly: Story = {
|
|
96
|
+
args: {
|
|
97
|
+
...Default.args,
|
|
98
|
+
readOnly: true,
|
|
99
|
+
},
|
|
100
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
101
|
+
render: ({ withLayer, layer, ...args }: any) => (
|
|
102
|
+
<Switch
|
|
103
|
+
{...args}
|
|
104
|
+
readOnlyComponent={({ checked, label }) => (
|
|
105
|
+
<span style={{ fontWeight: "bold", color: checked ? "green" : "red" }}>
|
|
106
|
+
{label} {checked ? "ENABLED" : "DISABLED"}
|
|
107
|
+
</span>
|
|
108
|
+
)}
|
|
109
|
+
/>
|
|
95
110
|
),
|
|
96
111
|
};
|