@recursica/mui-adapter 0.4.0 → 0.6.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 +15 -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 +6651 -201
- package/dist/mui-adapter.js.map +1 -1
- package/dist/src/components/Accordion/Accordion.d.ts +63 -2
- package/dist/src/components/AssistiveElement/AssistiveElement.d.ts +9 -2
- package/dist/src/components/Autocomplete/Autocomplete.d.ts +17 -0
- package/dist/src/components/Autocomplete/index.d.ts +1 -0
- package/dist/src/components/Avatar/Avatar.d.ts +14 -2
- package/dist/src/components/Badge/Badge.d.ts +13 -3
- package/dist/src/components/Breadcrumb/Breadcrumb.d.ts +10 -3
- package/dist/src/components/Button/Button.d.ts +1 -1
- package/dist/src/components/Card/Card.d.ts +40 -3
- package/dist/src/components/Checkbox/Checkbox.d.ts +15 -2
- package/dist/src/components/Checkbox/CheckboxGroup.d.ts +16 -0
- package/dist/src/components/Checkbox/index.d.ts +5 -1
- package/dist/src/components/Chip/Chip.d.ts +18 -2
- package/dist/src/components/Dropdown/Dropdown.d.ts +23 -3
- package/dist/src/components/FormControlLayout/FormControlLayout.d.ts +10 -2
- package/dist/src/components/FormControlWrapper/FormControlWrapper.d.ts +24 -2
- package/dist/src/components/HoverCard/HoverCard.d.ts +55 -3
- package/dist/src/components/Label/Label.d.ts +13 -2
- package/dist/src/components/Link/Link.d.ts +1 -1
- package/dist/src/components/Menu/Menu.d.ts +99 -3
- package/dist/src/components/Modal/Modal.d.ts +36 -2
- package/dist/src/components/NumberInput/NumberInput.d.ts +14 -2
- package/dist/src/components/Pagination/Pagination.d.ts +44 -2
- package/dist/src/components/Pagination/Pagination.icons.d.ts +8 -0
- package/dist/src/components/Panel/Panel.d.ts +65 -3
- package/dist/src/components/Radio/Radio.d.ts +13 -3
- package/dist/src/components/Radio/RadioGroup.d.ts +13 -0
- package/dist/src/components/ReadOnlyField/ReadOnlyBooleanField.d.ts +5 -0
- package/dist/src/components/ReadOnlyField/ReadOnlyField.d.ts +7 -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 +31 -3
- package/dist/src/components/Slider/Slider.d.ts +28 -2
- package/dist/src/components/Stepper/Stepper.d.ts +21 -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/Tabs/Tabs.d.ts +35 -3
- package/dist/src/components/Text/Text.d.ts +1 -1
- package/dist/src/components/TextArea/TextArea.d.ts +18 -2
- package/dist/src/components/TextField/TextField.d.ts +16 -2
- package/dist/src/components/Timeline/Timeline.d.ts +14 -2
- package/dist/src/components/Timeline/TimelineItem.d.ts +29 -0
- package/dist/src/components/Title/Title.d.ts +1 -1
- package/dist/src/components/Toast/Toast.d.ts +25 -2
- package/dist/src/components/Tooltip/Tooltip.d.ts +42 -3
- package/dist/src/components/Typography/Typography.d.ts +1 -1
- package/dist/src/components/index.d.ts +1 -0
- package/package.json +12 -2
- package/src/GlobalExemptions.modules.css +13 -0
- package/src/components/Accordion/Accordion.module.css +295 -0
- package/src/components/Accordion/Accordion.stories.tsx +149 -21
- package/src/components/Accordion/Accordion.tsx +264 -4
- package/src/components/AssistiveElement/AssistiveElement.module.css +111 -0
- package/src/components/AssistiveElement/AssistiveElement.stories.tsx +76 -19
- package/src/components/AssistiveElement/AssistiveElement.tsx +85 -4
- package/src/components/Autocomplete/Autocomplete.module.css +325 -0
- package/src/components/Autocomplete/Autocomplete.stories.tsx +196 -0
- package/src/components/Autocomplete/Autocomplete.tsx +201 -0
- package/src/components/Autocomplete/index.ts +1 -0
- package/src/components/Avatar/Avatar.module.css +344 -0
- package/src/components/Avatar/Avatar.stories.tsx +94 -22
- package/src/components/Avatar/Avatar.tsx +110 -5
- package/src/components/Badge/Badge.module.css +127 -0
- package/src/components/Badge/Badge.stories.tsx +65 -22
- package/src/components/Badge/Badge.tsx +70 -5
- package/src/components/Breadcrumb/Breadcrumb.module.css +26 -0
- package/src/components/Breadcrumb/Breadcrumb.stories.tsx +57 -22
- package/src/components/Breadcrumb/Breadcrumb.tsx +62 -5
- package/src/components/Button/Button.module.css +113 -20
- package/src/components/Button/Button.stories.tsx +3 -0
- package/src/components/Button/Button.tsx +10 -3
- package/src/components/Card/Card.module.css +118 -0
- package/src/components/Card/Card.stories.tsx +117 -19
- package/src/components/Card/Card.tsx +179 -4
- package/src/components/Checkbox/Checkbox.module.css +232 -0
- package/src/components/Checkbox/Checkbox.stories.tsx +81 -19
- package/src/components/Checkbox/Checkbox.tsx +146 -4
- package/src/components/Checkbox/CheckboxGroup.tsx +117 -0
- package/src/components/Checkbox/index.ts +6 -1
- package/src/components/Chip/Chip.module.css +236 -0
- package/src/components/Chip/Chip.stories.tsx +101 -21
- package/src/components/Chip/Chip.tsx +138 -5
- package/src/components/DatePicker/DatePicker.module.css +42 -0
- package/src/components/DatePicker/DatePicker.tsx +1 -0
- package/src/components/Dropdown/Dropdown.module.css +296 -0
- package/src/components/Dropdown/Dropdown.stories.tsx +80 -21
- package/src/components/Dropdown/Dropdown.tsx +182 -5
- package/src/components/FileInput/FileInput.module.css +47 -0
- package/src/components/FileInput/FileInput.tsx +1 -0
- package/src/components/FileUpload/FileUpload.module.css +40 -0
- package/src/components/FileUpload/FileUpload.tsx +1 -0
- package/src/components/FormControlLayout/FormControlLayout.module.css +92 -0
- package/src/components/FormControlLayout/FormControlLayout.stories.tsx +74 -19
- package/src/components/FormControlLayout/FormControlLayout.tsx +58 -4
- package/src/components/FormControlWrapper/FormControlWrapper.module.css +96 -0
- package/src/components/FormControlWrapper/FormControlWrapper.stories.tsx +122 -19
- package/src/components/FormControlWrapper/FormControlWrapper.tsx +145 -6
- package/src/components/HoverCard/HoverCard.module.css +91 -0
- package/src/components/HoverCard/HoverCard.stories.tsx +158 -21
- package/src/components/HoverCard/HoverCard.tsx +150 -4
- package/src/components/Label/Label.module.css +136 -0
- package/src/components/Label/Label.stories.tsx +98 -17
- package/src/components/Label/Label.tsx +88 -4
- package/src/components/Link/Link.module.css +8 -0
- package/src/components/Menu/Menu.module.css +287 -0
- package/src/components/Menu/Menu.stories.tsx +307 -21
- package/src/components/Menu/Menu.tsx +318 -4
- package/src/components/Modal/Modal.module.css +172 -0
- package/src/components/Modal/Modal.stories.tsx +66 -22
- package/src/components/Modal/Modal.tsx +216 -3
- package/src/components/NumberInput/NumberInput.module.css +281 -0
- package/src/components/NumberInput/NumberInput.stories.tsx +83 -20
- package/src/components/NumberInput/NumberInput.tsx +148 -5
- package/src/components/Pagination/Pagination.icons.tsx +66 -0
- package/src/components/Pagination/Pagination.module.css +307 -0
- package/src/components/Pagination/Pagination.stories.tsx +42 -21
- package/src/components/Pagination/Pagination.tsx +193 -4
- package/src/components/Panel/Panel.module.css +206 -0
- package/src/components/Panel/Panel.stories.tsx +214 -22
- package/src/components/Panel/Panel.tsx +153 -4
- package/src/components/Radio/Radio.module.css +220 -0
- package/src/components/Radio/Radio.stories.tsx +77 -19
- package/src/components/Radio/Radio.tsx +178 -4
- package/src/components/Radio/RadioGroup.tsx +111 -0
- package/src/components/ReadOnlyField/ReadOnlyBooleanField.tsx +21 -0
- package/src/components/ReadOnlyField/ReadOnlyField.module.css +54 -0
- package/src/components/ReadOnlyField/ReadOnlyField.stories.tsx +175 -16
- package/src/components/ReadOnlyField/ReadOnlyField.tsx +109 -4
- 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 +203 -0
- package/src/components/SegmentedControl/SegmentedControl.stories.tsx +102 -20
- package/src/components/SegmentedControl/SegmentedControl.tsx +110 -5
- package/src/components/Slider/Slider.module.css +542 -0
- package/src/components/Slider/Slider.stories.tsx +157 -19
- package/src/components/Slider/Slider.tsx +282 -4
- package/src/components/Stepper/Stepper.module.css +410 -0
- package/src/components/Stepper/Stepper.stories.tsx +132 -19
- package/src/components/Stepper/Stepper.tsx +145 -5
- package/src/components/Switch/Switch.module.css +238 -0
- package/src/components/Switch/Switch.stories.tsx +98 -19
- package/src/components/Switch/Switch.tsx +153 -5
- package/src/components/Switch/SwitchGroup.tsx +111 -0
- package/src/components/Tabs/Tabs.module.css +422 -0
- package/src/components/Tabs/Tabs.stories.tsx +138 -19
- package/src/components/Tabs/Tabs.tsx +103 -5
- package/src/components/TextArea/TextArea.module.css +160 -0
- package/src/components/TextArea/TextArea.stories.tsx +80 -21
- package/src/components/TextArea/TextArea.tsx +156 -5
- package/src/components/TextField/TextField.module.css +266 -0
- package/src/components/TextField/TextField.stories.tsx +168 -15
- package/src/components/TextField/TextField.tsx +171 -5
- package/src/components/TimePicker/TimePicker.module.css +41 -0
- package/src/components/TimePicker/TimePicker.tsx +1 -0
- package/src/components/Timeline/Timeline.module.css +367 -0
- package/src/components/Timeline/Timeline.stories.tsx +114 -21
- package/src/components/Timeline/Timeline.tsx +80 -4
- package/src/components/Timeline/TimelineItem.tsx +101 -0
- package/src/components/Toast/Toast.module.css +170 -0
- package/src/components/Toast/Toast.stories.tsx +54 -22
- package/src/components/Toast/Toast.tsx +90 -4
- package/src/components/Tooltip/Tooltip.module.css +90 -0
- package/src/components/Tooltip/Tooltip.stories.tsx +152 -22
- package/src/components/Tooltip/Tooltip.tsx +114 -4
- package/src/components/TransferList/TransferList.module.css +38 -0
- package/src/components/TransferList/TransferList.tsx +1 -0
- package/src/components/index.ts +1 -0
|
@@ -1,35 +1,194 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import React from "react";
|
|
1
3
|
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
4
|
import { ReadOnlyField } from "./ReadOnlyField";
|
|
3
|
-
import {
|
|
5
|
+
import { EmptyValueRenderer } from "@recursica/adapter-common";
|
|
6
|
+
import { formControlArgTypes } from "../../../.storybook/commonArgTypes";
|
|
4
7
|
|
|
5
8
|
const meta: Meta<typeof ReadOnlyField> = {
|
|
6
|
-
title: "UI-Kit
|
|
9
|
+
title: "UI-Kit/ReadOnlyField",
|
|
7
10
|
component: ReadOnlyField,
|
|
8
11
|
tags: ["autodocs"],
|
|
9
12
|
parameters: {
|
|
13
|
+
docs: {
|
|
14
|
+
description: {
|
|
15
|
+
component:
|
|
16
|
+
"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.",
|
|
17
|
+
},
|
|
18
|
+
},
|
|
10
19
|
controls: {
|
|
11
20
|
include: [
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"disabled",
|
|
20
|
-
"href",
|
|
21
|
-
"onClick",
|
|
22
|
-
"onChange",
|
|
23
|
-
"value",
|
|
24
|
-
"checked",
|
|
21
|
+
"type",
|
|
22
|
+
"labelWithEditIcon",
|
|
23
|
+
"formLayout",
|
|
24
|
+
"labelSize",
|
|
25
|
+
"labelAlignment",
|
|
26
|
+
"labelOptionalText",
|
|
27
|
+
"required",
|
|
25
28
|
],
|
|
26
29
|
},
|
|
27
30
|
},
|
|
31
|
+
args: {
|
|
32
|
+
label: "Read Only Label",
|
|
33
|
+
value: "Fixed Data Set Value",
|
|
34
|
+
assistiveText: "Helper description text beneath the node.",
|
|
35
|
+
type: "text",
|
|
36
|
+
},
|
|
37
|
+
argTypes: {
|
|
38
|
+
...formControlArgTypes,
|
|
39
|
+
type: {
|
|
40
|
+
control: "select",
|
|
41
|
+
options: ["text", "number", "boolean", "switch", "date"], // Add more as we support them
|
|
42
|
+
},
|
|
43
|
+
labelWithEditIcon: {
|
|
44
|
+
control: "boolean",
|
|
45
|
+
},
|
|
46
|
+
},
|
|
28
47
|
};
|
|
29
48
|
|
|
30
49
|
export default meta;
|
|
50
|
+
|
|
31
51
|
type Story = StoryObj<typeof ReadOnlyField>;
|
|
32
52
|
|
|
53
|
+
/**
|
|
54
|
+
* Playground story demonstrating standard structural blocks of the ReadOnlyField module dynamically.
|
|
55
|
+
*/
|
|
33
56
|
export const Default: Story = {
|
|
34
|
-
|
|
57
|
+
args: {},
|
|
58
|
+
render: ({ ...args }: any) => <ReadOnlyField {...args} />,
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Shows the default handler replacing missing mapping data directly with 'N/A'.
|
|
63
|
+
*/
|
|
64
|
+
export const EmptyValue: Story = {
|
|
65
|
+
args: {
|
|
66
|
+
value: "",
|
|
67
|
+
label: "Empty String Evaluated Automatically (Default 'N/A')",
|
|
68
|
+
},
|
|
69
|
+
render: ({ ...args }: any) => <ReadOnlyField {...args} />,
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const CustomEmptyTextRenderer: React.FC<{ value?: any }> & {
|
|
73
|
+
check?: (v: any) => boolean;
|
|
74
|
+
} = (props) => <EmptyValueRenderer {...props} emptyText="No Data Found" />;
|
|
75
|
+
CustomEmptyTextRenderer.check = EmptyValueRenderer.check;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Demonstrates overriding the baseline verbiage internally utilizing the exported `EmptyValueRenderer` while inheriting default evaluation checks.
|
|
79
|
+
*/
|
|
80
|
+
export const CustomEmptyText: Story = {
|
|
81
|
+
args: {
|
|
82
|
+
value: null,
|
|
83
|
+
label: "Custom Empty Text Default",
|
|
84
|
+
emptyValueComponent: CustomEmptyTextRenderer,
|
|
85
|
+
},
|
|
86
|
+
render: ({ ...args }: any) => <ReadOnlyField {...args} />,
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const CustomEmptyCheckRenderer: React.FC<{ value?: any }> & {
|
|
90
|
+
check?: (v: any) => boolean;
|
|
91
|
+
} = () => {
|
|
92
|
+
return <i>Custom HTML Markup Provided</i>;
|
|
93
|
+
};
|
|
94
|
+
CustomEmptyCheckRenderer.check = (val) => val === "EMPTY_MOCK";
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Validates a fully overridden emptyValueComponent injecting custom rendering boundaries alongside explicitly tailored validation rules evaluating datasets dynamically.
|
|
98
|
+
*/
|
|
99
|
+
export const CustomEmptyRenderer: Story = {
|
|
100
|
+
args: {
|
|
101
|
+
value: "EMPTY_MOCK",
|
|
102
|
+
label: "Custom Logic Evaluation Binding",
|
|
103
|
+
emptyValueComponent: CustomEmptyCheckRenderer,
|
|
104
|
+
},
|
|
105
|
+
render: ({ ...args }: any) => <ReadOnlyField {...args} />,
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Validates the core read-only label execution and base default spacing bindings globally.
|
|
110
|
+
*/
|
|
111
|
+
export const StackedDefault: Story = {
|
|
112
|
+
args: {
|
|
113
|
+
formLayout: "stacked",
|
|
114
|
+
value: "Some fixed readable text",
|
|
115
|
+
},
|
|
116
|
+
render: ({ ...args }: any) => <ReadOnlyField {...args} />,
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Binds side-by-side structures globally maintaining correct inline gutter layouts.
|
|
121
|
+
*/
|
|
122
|
+
export const SideBySide: Story = {
|
|
123
|
+
args: {
|
|
124
|
+
formLayout: "side-by-side",
|
|
125
|
+
value: "Some fixed readable text mapping horizontally",
|
|
126
|
+
},
|
|
127
|
+
render: ({ ...args }: any) => <ReadOnlyField {...args} />,
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Tests the fallback structural logic when Edit icon natively overrides required bindings.
|
|
132
|
+
*/
|
|
133
|
+
export const WithEditIcon: Story = {
|
|
134
|
+
args: {
|
|
135
|
+
labelWithEditIcon: true,
|
|
136
|
+
required: true,
|
|
137
|
+
value: "Editable fixed structure",
|
|
138
|
+
},
|
|
139
|
+
render: ({ ...args }: any) => <ReadOnlyField {...args} />,
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Demonstrates how the generic ReadOnlyField handles mapping different internal data types.
|
|
144
|
+
* Currently, all types safely default to string extraction mapping into the text renderer natively.
|
|
145
|
+
*/
|
|
146
|
+
export const DataTypes: Story = {
|
|
147
|
+
args: {},
|
|
148
|
+
render: ({ ...args }: any) => (
|
|
149
|
+
<div style={{ display: "flex", flexDirection: "column", gap: "24px" }}>
|
|
150
|
+
<ReadOnlyField
|
|
151
|
+
{...args}
|
|
152
|
+
label="Text Mapping"
|
|
153
|
+
type="text"
|
|
154
|
+
value="Standard string output"
|
|
155
|
+
/>
|
|
156
|
+
<ReadOnlyField
|
|
157
|
+
{...args}
|
|
158
|
+
label="Number Mapping"
|
|
159
|
+
type="number"
|
|
160
|
+
value={1234567.89}
|
|
161
|
+
/>
|
|
162
|
+
<ReadOnlyField
|
|
163
|
+
{...args}
|
|
164
|
+
label="Date Mapping"
|
|
165
|
+
type="date"
|
|
166
|
+
value={new Date("2026-04-28T12:00:00Z").toLocaleDateString()}
|
|
167
|
+
/>
|
|
168
|
+
<ReadOnlyField
|
|
169
|
+
{...args}
|
|
170
|
+
label="Boolean Mapping (True)"
|
|
171
|
+
type="boolean"
|
|
172
|
+
value={true}
|
|
173
|
+
/>
|
|
174
|
+
<ReadOnlyField
|
|
175
|
+
{...args}
|
|
176
|
+
label="Boolean Mapping (False)"
|
|
177
|
+
type="boolean"
|
|
178
|
+
value={false}
|
|
179
|
+
/>
|
|
180
|
+
<ReadOnlyField
|
|
181
|
+
{...args}
|
|
182
|
+
label="Switch Mapping (True -> On)"
|
|
183
|
+
type="switch"
|
|
184
|
+
value={true}
|
|
185
|
+
/>
|
|
186
|
+
<ReadOnlyField
|
|
187
|
+
{...args}
|
|
188
|
+
label="Switch Mapping (False -> Off)"
|
|
189
|
+
type="switch"
|
|
190
|
+
value={false}
|
|
191
|
+
/>
|
|
192
|
+
</div>
|
|
193
|
+
),
|
|
35
194
|
};
|
|
@@ -1,7 +1,112 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
1
2
|
import React from "react";
|
|
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";
|
|
2
9
|
|
|
3
|
-
export type ReadOnlyFieldProps =
|
|
10
|
+
export type ReadOnlyFieldProps = Omit<
|
|
11
|
+
RecursicaFormControlWrapperProps,
|
|
12
|
+
"error" | "focused"
|
|
13
|
+
> &
|
|
14
|
+
ReadOnlyControlProps & {
|
|
15
|
+
value?: any;
|
|
16
|
+
type?: "text" | "boolean" | "number" | "switch" | "date";
|
|
17
|
+
};
|
|
4
18
|
|
|
5
|
-
export const ReadOnlyField
|
|
6
|
-
|
|
7
|
-
|
|
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
|
+
<span className={styles.text}>N/A</span>
|
|
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 (typeof value === "object") {
|
|
92
|
+
try {
|
|
93
|
+
displayValue = JSON.stringify(value);
|
|
94
|
+
} catch {
|
|
95
|
+
displayValue = String(value);
|
|
96
|
+
}
|
|
97
|
+
} else {
|
|
98
|
+
displayValue = String(value);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return (
|
|
102
|
+
<FormControlWrapper
|
|
103
|
+
ref={ref}
|
|
104
|
+
className={`${styles.root} ${className || ""}`}
|
|
105
|
+
{...wrapperProps}
|
|
106
|
+
>
|
|
107
|
+
<span className={styles.text}>{displayValue}</span>
|
|
108
|
+
</FormControlWrapper>
|
|
109
|
+
);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
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";
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { Box } from "@mui/material";
|
|
4
|
+
import {
|
|
5
|
+
filterStylingProps,
|
|
6
|
+
type RecursicaOverStyled,
|
|
7
|
+
} from "../../utils/filterStylingProps";
|
|
8
|
+
import styles from "./ReadOnlyField.module.css";
|
|
9
|
+
|
|
10
|
+
export interface RecursicaReadOnlyTextFieldProps {
|
|
11
|
+
/** The value strictly rendered as text output */
|
|
12
|
+
value?: any;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type ReadOnlyTextFieldProps =
|
|
16
|
+
RecursicaOverStyled<RecursicaReadOnlyTextFieldProps>;
|
|
17
|
+
|
|
18
|
+
export const ReadOnlyTextField: React.FC<ReadOnlyTextFieldProps> = ({
|
|
19
|
+
value,
|
|
20
|
+
overStyled = false,
|
|
21
|
+
...rest
|
|
22
|
+
}) => {
|
|
23
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
24
|
+
const classNameProp = (sanitizedProps as Record<string, unknown>)
|
|
25
|
+
.className as string | undefined;
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<Box
|
|
29
|
+
component="p"
|
|
30
|
+
className={
|
|
31
|
+
classNameProp
|
|
32
|
+
? `${styles.textField} ${classNameProp}`
|
|
33
|
+
: styles.textField
|
|
34
|
+
}
|
|
35
|
+
{...sanitizedProps}
|
|
36
|
+
>
|
|
37
|
+
{value != null
|
|
38
|
+
? React.isValidElement(value)
|
|
39
|
+
? value
|
|
40
|
+
: Array.isArray(value)
|
|
41
|
+
? value.join(", ")
|
|
42
|
+
: String(value)
|
|
43
|
+
: ""}
|
|
44
|
+
</Box>
|
|
45
|
+
);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
ReadOnlyTextField.displayName = "ReadOnlyTextField";
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import React, { forwardRef } from "react";
|
|
3
|
+
import { type ReadOnlyFieldType } from "@recursica/adapter-common";
|
|
4
|
+
import {
|
|
5
|
+
FormControlWrapper,
|
|
6
|
+
type FormControlWrapperProps,
|
|
7
|
+
} from "../FormControlWrapper/FormControlWrapper";
|
|
8
|
+
import { ReadOnlyField } from "./ReadOnlyField";
|
|
9
|
+
|
|
10
|
+
export interface WithReadOnlyWrapperProps
|
|
11
|
+
extends Omit<FormControlWrapperProps, "children" | "overStyled"> {
|
|
12
|
+
/** Injects whether the field defaults to reading mode natively */
|
|
13
|
+
readOnly?: boolean;
|
|
14
|
+
/** Explicit React component directly overtaking the baseline text renderer when read-only mode is active */
|
|
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;
|
|
20
|
+
/** Instructs the underlying generic ReadOnlyField which raw visual structure to bridge automatically */
|
|
21
|
+
readOnlyType?: ReadOnlyFieldType;
|
|
22
|
+
/** The isolated raw data value intercepted explicitly into the ReadOnly formatters */
|
|
23
|
+
readOnlyValue?: any;
|
|
24
|
+
/** Safely enables deep overrides transparently bypassing block filters */
|
|
25
|
+
overStyled?: boolean;
|
|
26
|
+
/** The nested active node dynamically exposed exclusively when read-only bounds are disabled */
|
|
27
|
+
activeComponent: React.ReactNode;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Universal execution barrier trapping readOnly states globally.
|
|
32
|
+
* Natively delegates active logic down avoiding duplicative internal component bindings dynamically.
|
|
33
|
+
*/
|
|
34
|
+
export const WithReadOnlyWrapper = forwardRef<
|
|
35
|
+
HTMLDivElement,
|
|
36
|
+
WithReadOnlyWrapperProps
|
|
37
|
+
>(function WithReadOnlyWrapper(
|
|
38
|
+
{
|
|
39
|
+
readOnly,
|
|
40
|
+
readOnlyComponent,
|
|
41
|
+
readOnlyType = "text",
|
|
42
|
+
readOnlyValue,
|
|
43
|
+
readOnlyNativeProps,
|
|
44
|
+
emptyValueComponent,
|
|
45
|
+
activeComponent,
|
|
46
|
+
overStyled,
|
|
47
|
+
onLabelEditClick,
|
|
48
|
+
...wrapperProps
|
|
49
|
+
},
|
|
50
|
+
ref,
|
|
51
|
+
) {
|
|
52
|
+
if (readOnly) {
|
|
53
|
+
if (readOnlyComponent) {
|
|
54
|
+
const ReadOnlyComponent = readOnlyComponent;
|
|
55
|
+
return (
|
|
56
|
+
<FormControlWrapper
|
|
57
|
+
ref={ref}
|
|
58
|
+
{...wrapperProps}
|
|
59
|
+
onLabelEditClick={onLabelEditClick}
|
|
60
|
+
overStyled={overStyled as true}
|
|
61
|
+
>
|
|
62
|
+
<ReadOnlyComponent {...readOnlyNativeProps} />
|
|
63
|
+
</FormControlWrapper>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
<ReadOnlyField
|
|
69
|
+
ref={ref}
|
|
70
|
+
type={readOnlyType}
|
|
71
|
+
value={readOnlyValue}
|
|
72
|
+
emptyValueComponent={emptyValueComponent}
|
|
73
|
+
onLabelEditClick={onLabelEditClick}
|
|
74
|
+
overStyled={overStyled as true}
|
|
75
|
+
{...wrapperProps}
|
|
76
|
+
/>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Active Standard Execution natively forwarding bound children implicitly
|
|
81
|
+
return (
|
|
82
|
+
<FormControlWrapper
|
|
83
|
+
ref={ref}
|
|
84
|
+
{...wrapperProps}
|
|
85
|
+
onLabelEditClick={onLabelEditClick}
|
|
86
|
+
overStyled={overStyled as true}
|
|
87
|
+
>
|
|
88
|
+
{activeComponent}
|
|
89
|
+
</FormControlWrapper>
|
|
90
|
+
);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
WithReadOnlyWrapper.displayName = "WithReadOnlyWrapper";
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/* HARDCODED VALUES:
|
|
2
|
+
- border-style: solid; on container and indicator
|
|
3
|
+
- background-color: transparent; on label hover (overriding Mantine)
|
|
4
|
+
- Scope prefix .root to enforce Figma tokens over Mantine's inline calculation without using !important
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
.root {
|
|
8
|
+
background-color: var(
|
|
9
|
+
--recursica_ui-kit_components_segmented-control_properties_colors_background
|
|
10
|
+
);
|
|
11
|
+
border: var(
|
|
12
|
+
--recursica_ui-kit_components_segmented-control_properties_border-size
|
|
13
|
+
)
|
|
14
|
+
solid
|
|
15
|
+
var(
|
|
16
|
+
--recursica_ui-kit_components_segmented-control_properties_colors_border-color
|
|
17
|
+
);
|
|
18
|
+
border-radius: var(
|
|
19
|
+
--recursica_ui-kit_components_segmented-control_properties_border-radius
|
|
20
|
+
);
|
|
21
|
+
padding: var(
|
|
22
|
+
--recursica_ui-kit_components_segmented-control_properties_padding-vertical
|
|
23
|
+
)
|
|
24
|
+
var(
|
|
25
|
+
--recursica_ui-kit_components_segmented-control_properties_padding-horizontal
|
|
26
|
+
);
|
|
27
|
+
box-shadow: var(
|
|
28
|
+
--recursica_ui-kit_components_segmented-control_properties_elevation,
|
|
29
|
+
none
|
|
30
|
+
);
|
|
31
|
+
gap: var(--recursica_ui-kit_components_segmented-control_properties_item-gap);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.root .label {
|
|
35
|
+
padding-left: var(
|
|
36
|
+
--recursica_ui-kit_components_segmented-control-item_properties_item_padding-horizontal
|
|
37
|
+
);
|
|
38
|
+
padding-right: var(
|
|
39
|
+
--recursica_ui-kit_components_segmented-control-item_properties_item_padding-horizontal
|
|
40
|
+
);
|
|
41
|
+
height: var(
|
|
42
|
+
--recursica_ui-kit_components_segmented-control-item_properties_item_height
|
|
43
|
+
);
|
|
44
|
+
border-radius: var(
|
|
45
|
+
--recursica_ui-kit_components_segmented-control-item_properties_unselected_border-radius,
|
|
46
|
+
var(
|
|
47
|
+
--recursica_ui-kit_components_segmented-control-item_properties_item_border-radius
|
|
48
|
+
)
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
border: var(
|
|
52
|
+
--recursica_ui-kit_components_segmented-control-item_properties_unselected_border-size
|
|
53
|
+
)
|
|
54
|
+
solid
|
|
55
|
+
var(
|
|
56
|
+
--recursica_ui-kit_components_segmented-control-item_properties_unselected_colors_border-color
|
|
57
|
+
);
|
|
58
|
+
background-color: var(
|
|
59
|
+
--recursica_ui-kit_components_segmented-control-item_properties_unselected_colors_background
|
|
60
|
+
);
|
|
61
|
+
box-shadow: var(
|
|
62
|
+
--recursica_ui-kit_components_segmented-control-item_properties_unselected_elevation
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
font-family: var(
|
|
66
|
+
--recursica_ui-kit_components_segmented-control-item_properties_unselected-text_font-family,
|
|
67
|
+
inherit
|
|
68
|
+
);
|
|
69
|
+
font-size: var(
|
|
70
|
+
--recursica_ui-kit_components_segmented-control-item_properties_unselected-text_font-size,
|
|
71
|
+
inherit
|
|
72
|
+
);
|
|
73
|
+
font-style: var(
|
|
74
|
+
--recursica_ui-kit_components_segmented-control-item_properties_unselected-text_font-style,
|
|
75
|
+
inherit
|
|
76
|
+
);
|
|
77
|
+
font-weight: var(
|
|
78
|
+
--recursica_ui-kit_components_segmented-control-item_properties_unselected-text_font-weight,
|
|
79
|
+
inherit
|
|
80
|
+
);
|
|
81
|
+
letter-spacing: var(
|
|
82
|
+
--recursica_ui-kit_components_segmented-control-item_properties_unselected-text_letter-spacing,
|
|
83
|
+
inherit
|
|
84
|
+
);
|
|
85
|
+
line-height: var(
|
|
86
|
+
--recursica_ui-kit_components_segmented-control-item_properties_unselected-text_line-height,
|
|
87
|
+
inherit
|
|
88
|
+
);
|
|
89
|
+
text-decoration: var(
|
|
90
|
+
--recursica_ui-kit_components_segmented-control-item_properties_unselected-text_text-decoration,
|
|
91
|
+
inherit
|
|
92
|
+
);
|
|
93
|
+
text-transform: var(
|
|
94
|
+
--recursica_ui-kit_components_segmented-control-item_properties_unselected-text_text-transform,
|
|
95
|
+
inherit
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
color: var(
|
|
99
|
+
--recursica_ui-kit_components_segmented-control-item_properties_unselected_colors_text-color,
|
|
100
|
+
inherit
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
display: flex;
|
|
104
|
+
align-items: center;
|
|
105
|
+
justify-content: center;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/* Mantine natively wraps label contents in an innerLabel span */
|
|
109
|
+
.root .label :global(.mantine-SegmentedControl-innerLabel) {
|
|
110
|
+
display: flex;
|
|
111
|
+
align-items: center;
|
|
112
|
+
justify-content: center;
|
|
113
|
+
gap: var(
|
|
114
|
+
--recursica_ui-kit_components_segmented-control-item_properties_item_icon-text-gap
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.root .label svg {
|
|
119
|
+
width: var(
|
|
120
|
+
--recursica_ui-kit_components_segmented-control-item_properties_item_icon-size
|
|
121
|
+
);
|
|
122
|
+
height: var(
|
|
123
|
+
--recursica_ui-kit_components_segmented-control-item_properties_item_icon-size
|
|
124
|
+
);
|
|
125
|
+
flex-shrink: 0;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/* Mantine adds a background on hover, we must strictly strip it */
|
|
129
|
+
.root .label:hover {
|
|
130
|
+
background-color: transparent;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/* Mantine adds separators via ::before on the .control */
|
|
134
|
+
.root .control::before {
|
|
135
|
+
background-color: var(
|
|
136
|
+
--recursica_ui-kit_components_segmented-control_properties_colors_divider-color
|
|
137
|
+
);
|
|
138
|
+
width: var(
|
|
139
|
+
--recursica_ui-kit_components_segmented-control_properties_divider-size
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/* Indicator (the moving selected block) */
|
|
144
|
+
.root .indicator {
|
|
145
|
+
background-color: var(
|
|
146
|
+
--recursica_ui-kit_components_segmented-control-item_properties_selected_colors_background
|
|
147
|
+
);
|
|
148
|
+
border: var(
|
|
149
|
+
--recursica_ui-kit_components_segmented-control-item_properties_selected_border-size
|
|
150
|
+
)
|
|
151
|
+
solid
|
|
152
|
+
var(
|
|
153
|
+
--recursica_ui-kit_components_segmented-control-item_properties_selected_colors_border-color
|
|
154
|
+
);
|
|
155
|
+
box-shadow: var(
|
|
156
|
+
--recursica_ui-kit_components_segmented-control-item_properties_selected_elevation
|
|
157
|
+
);
|
|
158
|
+
border-radius: var(
|
|
159
|
+
--recursica_ui-kit_components_segmented-control-item_properties_selected_border-radius,
|
|
160
|
+
var(
|
|
161
|
+
--recursica_ui-kit_components_segmented-control-item_properties_item_border-radius
|
|
162
|
+
)
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/* Selected label text color override */
|
|
167
|
+
.root .control[data-active] .label {
|
|
168
|
+
color: var(
|
|
169
|
+
--recursica_ui-kit_components_segmented-control-item_properties_selected_colors_text-color
|
|
170
|
+
);
|
|
171
|
+
font-family: var(
|
|
172
|
+
--recursica_ui-kit_components_segmented-control-item_properties_selected-text_font-family,
|
|
173
|
+
inherit
|
|
174
|
+
);
|
|
175
|
+
font-size: var(
|
|
176
|
+
--recursica_ui-kit_components_segmented-control-item_properties_selected-text_font-size,
|
|
177
|
+
inherit
|
|
178
|
+
);
|
|
179
|
+
font-style: var(
|
|
180
|
+
--recursica_ui-kit_components_segmented-control-item_properties_selected-text_font-style,
|
|
181
|
+
inherit
|
|
182
|
+
);
|
|
183
|
+
font-weight: var(
|
|
184
|
+
--recursica_ui-kit_components_segmented-control-item_properties_selected-text_font-weight,
|
|
185
|
+
inherit
|
|
186
|
+
);
|
|
187
|
+
letter-spacing: var(
|
|
188
|
+
--recursica_ui-kit_components_segmented-control-item_properties_selected-text_letter-spacing,
|
|
189
|
+
inherit
|
|
190
|
+
);
|
|
191
|
+
line-height: var(
|
|
192
|
+
--recursica_ui-kit_components_segmented-control-item_properties_selected-text_line-height,
|
|
193
|
+
inherit
|
|
194
|
+
);
|
|
195
|
+
text-decoration: var(
|
|
196
|
+
--recursica_ui-kit_components_segmented-control-item_properties_selected-text_text-decoration,
|
|
197
|
+
inherit
|
|
198
|
+
);
|
|
199
|
+
text-transform: var(
|
|
200
|
+
--recursica_ui-kit_components_segmented-control-item_properties_selected-text_text-transform,
|
|
201
|
+
inherit
|
|
202
|
+
);
|
|
203
|
+
}
|