@recursica/mantine-adapter 0.9.3 → 0.10.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/.storybook/commonArgTypes.ts +148 -0
- package/CHANGELOG.md +88 -0
- package/README.md +48 -332
- package/dist/index.d.ts +2 -0
- package/dist/mantine-adapter.cjs +2 -0
- package/dist/mantine-adapter.cjs.map +1 -0
- package/dist/mantine-adapter.css +1 -0
- package/dist/mantine-adapter.js +1797 -0
- package/dist/mantine-adapter.js.map +1 -0
- package/dist/src/components/Accordion/Accordion.d.ts +42 -0
- package/dist/src/components/Accordion/index.d.ts +1 -0
- package/dist/src/components/AssistiveElement/AssistiveElement.d.ts +10 -0
- package/dist/src/components/Avatar/Avatar.d.ts +9 -0
- package/dist/src/components/Avatar/index.d.ts +1 -0
- package/dist/src/components/Badge/Badge.d.ts +8 -0
- package/dist/src/components/Breadcrumb/Breadcrumb.d.ts +6 -0
- package/dist/src/components/Button/Button.d.ts +10 -0
- package/dist/src/components/Button/index.d.ts +1 -0
- package/dist/src/components/Card/Card.d.ts +38 -0
- package/dist/src/components/Checkbox/Checkbox.d.ts +11 -0
- package/dist/src/components/Checkbox/CheckboxGroup.d.ts +9 -0
- package/dist/src/components/Chip/Chip.d.ts +15 -0
- package/dist/src/components/Container/Container.d.ts +18 -0
- package/dist/src/components/DatePicker/DatePicker.d.ts +3 -0
- package/dist/src/components/Dropdown/Dropdown.d.ts +11 -0
- package/dist/src/components/FileInput/FileInput.d.ts +3 -0
- package/dist/src/components/FileUpload/FileUpload.d.ts +3 -0
- package/dist/src/components/Flex/Flex.d.ts +17 -0
- package/dist/src/components/FormControlWrapper/FormControlWrapper.d.ts +18 -0
- package/dist/src/components/Group/Group.d.ts +17 -0
- package/dist/src/components/HoverCard/HoverCard.d.ts +3 -0
- package/dist/src/components/Label/Label.d.ts +21 -0
- package/dist/src/components/Label/index.d.ts +1 -0
- package/dist/src/components/Link/Link.d.ts +3 -0
- package/dist/src/components/Loader/Loader.d.ts +10 -0
- package/dist/src/components/Menu/Menu.d.ts +3 -0
- package/dist/src/components/Modal/Modal.d.ts +3 -0
- package/dist/src/components/NumberInput/NumberInput.d.ts +3 -0
- package/dist/src/components/Pagination/Pagination.d.ts +3 -0
- package/dist/src/components/Panel/Panel.d.ts +3 -0
- package/dist/src/components/Popover/Popover.d.ts +3 -0
- package/dist/src/components/Radio/Radio.d.ts +11 -0
- package/dist/src/components/Radio/RadioGroup.d.ts +9 -0
- package/dist/src/components/ReadOnlyField/ReadOnlyField.d.ts +20 -0
- package/dist/src/components/ReadOnlyField/ReadOnlyTextField.d.ts +8 -0
- package/dist/src/components/ReadOnlyField/WithReadOnlyWrapper.d.ts +22 -0
- package/dist/src/components/ReadOnlyField/index.d.ts +3 -0
- package/dist/src/components/Search/Search.d.ts +3 -0
- package/dist/src/components/SegmentedControl/SegmentedControl.d.ts +3 -0
- package/dist/src/components/Slider/Slider.d.ts +3 -0
- package/dist/src/components/Stack/Stack.d.ts +15 -0
- package/dist/src/components/Stepper/Stepper.d.ts +3 -0
- package/dist/src/components/Switch/Switch.d.ts +11 -0
- package/dist/src/components/Switch/SwitchGroup.d.ts +9 -0
- package/dist/src/components/Table/Table.d.ts +3 -0
- package/dist/src/components/Tabs/Tabs.d.ts +3 -0
- package/dist/src/components/Text/Text.d.ts +17 -0
- package/dist/src/components/TextArea/TextArea.d.ts +15 -0
- package/dist/src/components/TextField/TextField.d.ts +9 -0
- package/dist/src/components/TimePicker/TimePicker.d.ts +3 -0
- package/dist/src/components/Timeline/Timeline.d.ts +3 -0
- package/dist/src/components/Title/Title.d.ts +13 -0
- package/dist/src/components/Toast/Toast.d.ts +3 -0
- package/dist/src/components/Tooltip/Tooltip.d.ts +3 -0
- package/dist/src/components/TransferList/TransferList.d.ts +3 -0
- package/dist/src/components/index.d.ts +47 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/types/index.d.ts +6 -0
- package/dist/src/utils/ColorSchemeWrapper.d.ts +3 -0
- package/dist/src/utils/copyToClipboard.d.ts +8 -0
- package/dist/src/utils/filterStylingProps.d.ts +36 -0
- package/dist/src/utils/index.d.ts +1 -0
- package/dist/vite.config.d.ts +2 -0
- package/dist/vite.svg +1 -0
- package/dist/vitest.workspace.d.ts +2 -0
- package/package.json +74 -35
- package/src/OverStyling.stories.tsx +174 -0
- package/src/Version.stories.tsx +56 -0
- package/src/components/Accordion/ACCORDION_IMPLEMENTATION_NOTES.md +48 -0
- package/src/components/Accordion/Accordion.module.css +282 -0
- package/src/components/Accordion/Accordion.stories.tsx +145 -0
- package/src/components/Accordion/Accordion.tsx +200 -0
- package/src/components/Accordion/index.ts +1 -0
- package/src/components/AssistiveElement/AssistiveElement.module.css +111 -0
- package/src/components/AssistiveElement/AssistiveElement.stories.tsx +73 -0
- package/src/components/AssistiveElement/AssistiveElement.tsx +91 -0
- package/src/components/Avatar/AVATAR_IMPLEMENTATION_NOTES.md +24 -0
- package/src/components/Avatar/Avatar.module.css +340 -0
- package/src/components/Avatar/Avatar.stories.tsx +102 -0
- package/src/components/Avatar/Avatar.tsx +100 -0
- package/src/components/Avatar/index.ts +1 -0
- package/src/components/Badge/BADGE_IMPLEMENTATION_NOTES.md +18 -0
- package/src/components/Badge/Badge.module.css +124 -0
- package/src/components/Badge/Badge.stories.tsx +77 -0
- package/src/components/Badge/Badge.tsx +66 -0
- package/src/components/Breadcrumb/BREADCRUMB_IMPLEMENTATION_NOTES.md +14 -0
- package/src/components/Breadcrumb/Breadcrumb.module.css +26 -0
- package/src/components/Breadcrumb/Breadcrumb.stories.tsx +77 -0
- package/src/components/Breadcrumb/Breadcrumb.tsx +64 -0
- package/src/components/Button/Button.module.css +275 -0
- package/src/components/Button/Button.stories.tsx +105 -0
- package/src/components/Button/Button.tsx +122 -0
- package/src/components/Button/IMPLEMENTATION_NOTES.md +45 -0
- package/src/components/Button/index.ts +1 -0
- package/src/components/Card/CARD_IMPLEMENTATION_NOTES.md +10 -0
- package/src/components/Card/Card.module.css +60 -0
- package/src/components/Card/Card.stories.tsx +141 -0
- package/src/components/Card/Card.tsx +176 -0
- package/src/components/Checkbox/CHECKBOX_IMPLEMENTATION_NOTES.md +25 -0
- package/src/components/Checkbox/Checkbox.module.css +204 -0
- package/src/components/Checkbox/Checkbox.stories.tsx +73 -0
- package/src/components/Checkbox/Checkbox.tsx +102 -0
- package/src/components/Checkbox/CheckboxGroup.stories.tsx +138 -0
- package/src/components/Checkbox/CheckboxGroup.tsx +140 -0
- package/src/components/Chip/CHIP_IMPLEMENTATION_NOTES.md +35 -0
- package/src/components/Chip/Chip.module.css +218 -0
- package/src/components/Chip/Chip.stories.tsx +115 -0
- package/src/components/Chip/Chip.tsx +143 -0
- package/src/components/Container/CONTAINER_IMPLEMENTATION_NOTES.md +4 -0
- package/src/components/Container/Container.module.css +7 -0
- package/src/components/Container/Container.stories.tsx +115 -0
- package/src/components/Container/Container.tsx +89 -0
- package/src/components/DatePicker/DatePicker.stories.tsx +22 -0
- package/src/components/DatePicker/DatePicker.tsx +7 -0
- package/src/components/Dropdown/DROPDOWN_IMPLEMENTATION_NOTES.md +7 -0
- package/src/components/Dropdown/Dropdown.module.css +272 -0
- package/src/components/Dropdown/Dropdown.stories.tsx +94 -0
- package/src/components/Dropdown/Dropdown.tsx +173 -0
- package/src/components/FileInput/FileInput.stories.tsx +22 -0
- package/src/components/FileInput/FileInput.tsx +7 -0
- package/src/components/FileUpload/FileUpload.stories.tsx +22 -0
- package/src/components/FileUpload/FileUpload.tsx +7 -0
- package/src/components/Flex/FLEX_IMPLEMENTATION_NOTES.md +4 -0
- package/src/components/Flex/Flex.module.css +7 -0
- package/src/components/Flex/Flex.stories.tsx +125 -0
- package/src/components/Flex/Flex.tsx +68 -0
- package/src/components/FormControlWrapper/FORMCONTROLWRAPPER_IMPLEMENTATION_NOTES.md +32 -0
- package/src/components/FormControlWrapper/FormControlWrapper.module.css +46 -0
- package/src/components/FormControlWrapper/FormControlWrapper.stories.tsx +116 -0
- package/src/components/FormControlWrapper/FormControlWrapper.tsx +170 -0
- package/src/components/Group/GROUP_IMPLEMENTATION_NOTES.md +4 -0
- package/src/components/Group/Group.module.css +7 -0
- package/src/components/Group/Group.stories.tsx +117 -0
- package/src/components/Group/Group.tsx +68 -0
- package/src/components/HoverCard/HoverCard.stories.tsx +17 -0
- package/src/components/HoverCard/HoverCard.tsx +7 -0
- package/src/components/Label/LABEL_IMPLEMENTATION_NOTES.md +48 -0
- package/src/components/Label/Label.module.css +177 -0
- package/src/components/Label/Label.stories.tsx +123 -0
- package/src/components/Label/Label.tsx +132 -0
- package/src/components/Label/index.ts +1 -0
- package/src/components/Link/Link.stories.tsx +17 -0
- package/src/components/Link/Link.tsx +7 -0
- package/src/components/Loader/Loader.module.css +60 -0
- package/src/components/Loader/Loader.stories.tsx +98 -0
- package/src/components/Loader/Loader.tsx +76 -0
- package/src/components/Menu/Menu.stories.tsx +17 -0
- package/src/components/Menu/Menu.tsx +7 -0
- package/src/components/Modal/Modal.stories.tsx +17 -0
- package/src/components/Modal/Modal.tsx +7 -0
- package/src/components/NumberInput/NumberInput.stories.tsx +22 -0
- package/src/components/NumberInput/NumberInput.tsx +7 -0
- package/src/components/Pagination/Pagination.stories.tsx +17 -0
- package/src/components/Pagination/Pagination.tsx +7 -0
- package/src/components/Panel/Panel.stories.tsx +17 -0
- package/src/components/Panel/Panel.tsx +7 -0
- package/src/components/Popover/Popover.stories.tsx +17 -0
- package/src/components/Popover/Popover.tsx +7 -0
- package/src/components/Radio/Radio.module.css +207 -0
- package/src/components/Radio/Radio.stories.tsx +76 -0
- package/src/components/Radio/Radio.tsx +115 -0
- package/src/components/Radio/RadioGroup.stories.tsx +98 -0
- package/src/components/Radio/RadioGroup.tsx +138 -0
- package/src/components/ReadOnlyField/READ_ONLY_FIELD_IMPLEMENTATION_NOTES.md +15 -0
- package/src/components/ReadOnlyField/ReadOnlyField.module.css +49 -0
- package/src/components/ReadOnlyField/ReadOnlyField.stories.tsx +120 -0
- package/src/components/ReadOnlyField/ReadOnlyField.tsx +75 -0
- package/src/components/ReadOnlyField/ReadOnlyTextField.tsx +46 -0
- package/src/components/ReadOnlyField/WithReadOnlyWrapper.tsx +85 -0
- package/src/components/ReadOnlyField/index.ts +3 -0
- package/src/components/Search/Search.stories.tsx +17 -0
- package/src/components/Search/Search.tsx +7 -0
- package/src/components/SegmentedControl/SegmentedControl.stories.tsx +22 -0
- package/src/components/SegmentedControl/SegmentedControl.tsx +7 -0
- package/src/components/Slider/Slider.stories.tsx +22 -0
- package/src/components/Slider/Slider.tsx +7 -0
- package/src/components/Stack/STACK_IMPLEMENTATION_NOTES.md +4 -0
- package/src/components/Stack/Stack.module.css +7 -0
- package/src/components/Stack/Stack.stories.tsx +105 -0
- package/src/components/Stack/Stack.tsx +66 -0
- package/src/components/Stepper/Stepper.stories.tsx +17 -0
- package/src/components/Stepper/Stepper.tsx +7 -0
- package/src/components/Switch/SWITCH_IMPLEMENTATION_NOTES.md +28 -0
- package/src/components/Switch/Switch.module.css +207 -0
- package/src/components/Switch/Switch.stories.tsx +96 -0
- package/src/components/Switch/Switch.tsx +119 -0
- package/src/components/Switch/SwitchGroup.stories.tsx +112 -0
- package/src/components/Switch/SwitchGroup.tsx +138 -0
- package/src/components/Table/Table.stories.tsx +17 -0
- package/src/components/Table/Table.tsx +7 -0
- package/src/components/Tabs/Tabs.stories.tsx +17 -0
- package/src/components/Tabs/Tabs.tsx +7 -0
- package/src/components/Text/Text.stories.tsx +88 -0
- package/src/components/Text/Text.tsx +54 -0
- package/src/components/TextArea/TEXTAREA_IMPLEMENTATION_NOTES.md +7 -0
- package/src/components/TextArea/TextArea.module.css +225 -0
- package/src/components/TextArea/TextArea.stories.tsx +94 -0
- package/src/components/TextArea/TextArea.tsx +151 -0
- package/src/components/TextField/TEXTFIELD_IMPLEMENTATION_NOTES.md +19 -0
- package/src/components/TextField/TextField.module.css +225 -0
- package/src/components/TextField/TextField.stories.tsx +162 -0
- package/src/components/TextField/TextField.tsx +138 -0
- package/src/components/TimePicker/TimePicker.stories.tsx +22 -0
- package/src/components/TimePicker/TimePicker.tsx +7 -0
- package/src/components/Timeline/Timeline.stories.tsx +17 -0
- package/src/components/Timeline/Timeline.tsx +7 -0
- package/src/components/Title/Title.stories.tsx +63 -0
- package/src/components/Title/Title.tsx +45 -0
- package/src/components/Toast/Toast.stories.tsx +17 -0
- package/src/components/Toast/Toast.tsx +7 -0
- package/src/components/Tooltip/Tooltip.stories.tsx +17 -0
- package/src/components/Tooltip/Tooltip.tsx +7 -0
- package/src/components/TransferList/TransferList.stories.tsx +17 -0
- package/src/components/TransferList/TransferList.tsx +7 -0
- package/src/components/index.ts +47 -0
- package/src/env.d.ts +7 -0
- package/src/index.ts +3 -0
- package/src/types/index.ts +9 -0
- package/src/types/mantine.d.ts +7 -0
- package/src/types/scss-modules.d.ts +9 -0
- package/src/utils/ColorSchemeWrapper.tsx +27 -0
- package/src/utils/copyToClipboard.ts +36 -0
- package/src/utils/filterStylingProps.ts +141 -0
- package/src/utils/index.ts +1 -0
- package/dist/index.js +0 -917
- package/dist/index.js.map +0 -1
- package/dist/main.cjs +0 -924
- package/dist/main.cjs.map +0 -1
- package/dist/main.js +0 -922
- package/dist/main.js.map +0 -1
- package/dist/webworker.js +0 -787
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { forwardRef } from "react";
|
|
2
|
+
import {
|
|
3
|
+
Radio as MantineRadio,
|
|
4
|
+
type RadioProps as MantineRadioProps,
|
|
5
|
+
} from "@mantine/core";
|
|
6
|
+
import { type ReadOnlyControlProps } from "@recursica/adapter-common";
|
|
7
|
+
import { RadioGroup } from "./RadioGroup";
|
|
8
|
+
import {
|
|
9
|
+
filterStylingProps,
|
|
10
|
+
type RecursicaOverStyled,
|
|
11
|
+
} from "../../utils/filterStylingProps";
|
|
12
|
+
import styles from "./Radio.module.css";
|
|
13
|
+
|
|
14
|
+
const RadioIcon: React.FC<{
|
|
15
|
+
className?: string;
|
|
16
|
+
style?: React.CSSProperties;
|
|
17
|
+
}> = ({ className, style }) => (
|
|
18
|
+
<svg
|
|
19
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
20
|
+
viewBox="0 0 16 16"
|
|
21
|
+
fill="currentColor"
|
|
22
|
+
className={className}
|
|
23
|
+
style={style}
|
|
24
|
+
>
|
|
25
|
+
<circle cx="8" cy="8" r="5" />
|
|
26
|
+
</svg>
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
export type RecursicaRadioProps = Omit<
|
|
30
|
+
MantineRadioProps,
|
|
31
|
+
"size" | "color" | "radius" | "iconColor" | "variant"
|
|
32
|
+
> &
|
|
33
|
+
ReadOnlyControlProps;
|
|
34
|
+
|
|
35
|
+
export type RadioProps = RecursicaOverStyled<RecursicaRadioProps>;
|
|
36
|
+
|
|
37
|
+
type RadioComponent = React.ForwardRefExoticComponent<
|
|
38
|
+
RadioProps & React.RefAttributes<HTMLInputElement>
|
|
39
|
+
> & {
|
|
40
|
+
Group: typeof RadioGroup;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const Radio = forwardRef<HTMLInputElement, RadioProps>(function Radio(
|
|
44
|
+
{ overStyled = false, readOnly, readOnlyComponent, disabled, ...rest },
|
|
45
|
+
ref,
|
|
46
|
+
) {
|
|
47
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
48
|
+
const restRecord = sanitizedProps as Record<string, unknown>;
|
|
49
|
+
|
|
50
|
+
// Actively delete dimension bindings that bypass the abstraction
|
|
51
|
+
delete restRecord["size"];
|
|
52
|
+
delete restRecord["color"];
|
|
53
|
+
delete restRecord["radius"];
|
|
54
|
+
delete restRecord["variant"];
|
|
55
|
+
delete restRecord["iconColor"];
|
|
56
|
+
|
|
57
|
+
if (readOnly && readOnlyComponent) {
|
|
58
|
+
// Safely fallback explicitly returning mapped elements natively without macro wrappers
|
|
59
|
+
return <>{readOnlyComponent}</>;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const mergedClassNames: Partial<Record<string, string>> = {
|
|
63
|
+
root: styles.root,
|
|
64
|
+
body: styles.body,
|
|
65
|
+
inner: styles.inner,
|
|
66
|
+
radio: styles.radio,
|
|
67
|
+
icon: styles.icon,
|
|
68
|
+
labelWrapper: styles.labelWrapper,
|
|
69
|
+
label: styles.label,
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const classNamesProp = restRecord.classNames;
|
|
73
|
+
if (
|
|
74
|
+
classNamesProp &&
|
|
75
|
+
typeof classNamesProp === "object" &&
|
|
76
|
+
!Array.isArray(classNamesProp)
|
|
77
|
+
) {
|
|
78
|
+
const o = classNamesProp as Partial<Record<string, string>>;
|
|
79
|
+
mergedClassNames.root = o.root ? `${styles.root} ${o.root}` : styles.root;
|
|
80
|
+
mergedClassNames.body = o.body ? `${styles.body} ${o.body}` : styles.body;
|
|
81
|
+
mergedClassNames.inner = o.inner
|
|
82
|
+
? `${styles.inner} ${o.inner}`
|
|
83
|
+
: styles.inner;
|
|
84
|
+
mergedClassNames.radio = o.radio
|
|
85
|
+
? `${styles.radio} ${o.radio}`
|
|
86
|
+
: styles.radio;
|
|
87
|
+
mergedClassNames.icon = o.icon ? `${styles.icon} ${o.icon}` : styles.icon;
|
|
88
|
+
mergedClassNames.labelWrapper = o.labelWrapper
|
|
89
|
+
? `${styles.labelWrapper} ${o.labelWrapper}`
|
|
90
|
+
: styles.labelWrapper;
|
|
91
|
+
mergedClassNames.label = o.label
|
|
92
|
+
? `${styles.label} ${o.label}`
|
|
93
|
+
: styles.label;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const classNameProp = restRecord.className as string | undefined;
|
|
97
|
+
const finalClass = classNameProp
|
|
98
|
+
? `${styles.root} ${classNameProp}`
|
|
99
|
+
: styles.root;
|
|
100
|
+
|
|
101
|
+
// We omit Mantine's sizing/coloring so we rely strictly on variables from Radio.module.css
|
|
102
|
+
return (
|
|
103
|
+
<MantineRadio
|
|
104
|
+
ref={ref}
|
|
105
|
+
icon={RadioIcon}
|
|
106
|
+
className={finalClass}
|
|
107
|
+
classNames={mergedClassNames}
|
|
108
|
+
disabled={readOnly || disabled}
|
|
109
|
+
{...(sanitizedProps as unknown as MantineRadioProps)}
|
|
110
|
+
/>
|
|
111
|
+
);
|
|
112
|
+
}) as RadioComponent;
|
|
113
|
+
|
|
114
|
+
Radio.displayName = "Radio";
|
|
115
|
+
Radio.Group = RadioGroup;
|
|
@@ -0,0 +1,98 @@
|
|
|
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 GroupStacked: Story = {
|
|
39
|
+
args: {
|
|
40
|
+
formLayout: "stacked",
|
|
41
|
+
required: true,
|
|
42
|
+
label: "Hosting Provider",
|
|
43
|
+
error: "You must select a deployment provider.",
|
|
44
|
+
},
|
|
45
|
+
render: function GroupStackedRender(args) {
|
|
46
|
+
const [value, setValue] = useState<string>("aws");
|
|
47
|
+
return (
|
|
48
|
+
<RadioGroup {...args} value={value} onChange={setValue}>
|
|
49
|
+
<Radio value="aws" label="Amazon Web Services" />
|
|
50
|
+
<Radio
|
|
51
|
+
value="gcp"
|
|
52
|
+
label="Google Cloud Platform (with completely distributed edge computing environments bridging local runtime boundaries seamlessly.)"
|
|
53
|
+
/>
|
|
54
|
+
<Radio value="azure" label="Microsoft Azure" />
|
|
55
|
+
</RadioGroup>
|
|
56
|
+
);
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export const GroupSideBySide: Story = {
|
|
61
|
+
args: {
|
|
62
|
+
formLayout: "side-by-side",
|
|
63
|
+
labelOptionalText: "Recommended",
|
|
64
|
+
labelWithEditIcon: true,
|
|
65
|
+
label: "Deployment Region",
|
|
66
|
+
assistiveText: "Select the data center closest to your user base.",
|
|
67
|
+
},
|
|
68
|
+
render: function GroupSideBySideRender(args) {
|
|
69
|
+
const [value, setValue] = useState<string>("us-east");
|
|
70
|
+
return (
|
|
71
|
+
<RadioGroup {...args} value={value} onChange={setValue}>
|
|
72
|
+
<Radio value="us-east" label="US East (N. Virginia)" />
|
|
73
|
+
<Radio value="us-west" label="US West (Oregon)" />
|
|
74
|
+
<Radio value="eu-central" label="EU Central (Frankfurt)" />
|
|
75
|
+
</RadioGroup>
|
|
76
|
+
);
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export const StaticReadOnlyGroup: Story = {
|
|
81
|
+
args: {
|
|
82
|
+
readOnly: true,
|
|
83
|
+
formLayout: "stacked",
|
|
84
|
+
required: true,
|
|
85
|
+
label: "Selected Framework",
|
|
86
|
+
assistiveText: "This selection cannot be changed after initialization.",
|
|
87
|
+
readOnlyComponent: <span>React (Standard Build)</span>,
|
|
88
|
+
},
|
|
89
|
+
render: function StaticReadOnlyGroupRender(args) {
|
|
90
|
+
const [value, setValue] = useState<string>("react");
|
|
91
|
+
return (
|
|
92
|
+
<RadioGroup {...args} value={value} onChange={setValue}>
|
|
93
|
+
<Radio value="react" label="React" />
|
|
94
|
+
<Radio value="vue" label="Vue" />
|
|
95
|
+
</RadioGroup>
|
|
96
|
+
);
|
|
97
|
+
},
|
|
98
|
+
};
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import React, { forwardRef } from "react";
|
|
3
|
+
import {
|
|
4
|
+
Radio as MantineRadio,
|
|
5
|
+
type RadioGroupProps as MantineRadioGroupProps,
|
|
6
|
+
} from "@mantine/core";
|
|
7
|
+
import { type ReadOnlyControlProps } from "@recursica/adapter-common";
|
|
8
|
+
import {
|
|
9
|
+
filterStylingProps,
|
|
10
|
+
type RecursicaOverStyled,
|
|
11
|
+
} from "../../utils/filterStylingProps";
|
|
12
|
+
import {
|
|
13
|
+
FormControlWrapper,
|
|
14
|
+
type RecursicaFormControlWrapperProps,
|
|
15
|
+
} from "../FormControlWrapper/FormControlWrapper";
|
|
16
|
+
import styles from "./Radio.module.css";
|
|
17
|
+
|
|
18
|
+
export interface RecursicaRadioGroupProps
|
|
19
|
+
extends Omit<MantineRadioGroupProps, "size" | "labelProps">,
|
|
20
|
+
Omit<
|
|
21
|
+
RecursicaFormControlWrapperProps,
|
|
22
|
+
"controlMaxWidth" | "controlMinWidth"
|
|
23
|
+
>,
|
|
24
|
+
ReadOnlyControlProps {}
|
|
25
|
+
|
|
26
|
+
export type RadioGroupProps = RecursicaOverStyled<RecursicaRadioGroupProps>;
|
|
27
|
+
|
|
28
|
+
export const RadioGroup = forwardRef<HTMLDivElement, RadioGroupProps>(
|
|
29
|
+
function RadioGroup(
|
|
30
|
+
{
|
|
31
|
+
overStyled = false,
|
|
32
|
+
formLayout = "stacked",
|
|
33
|
+
|
|
34
|
+
// Label Wrappers
|
|
35
|
+
labelSize,
|
|
36
|
+
labelAlignment,
|
|
37
|
+
labelOptionalText,
|
|
38
|
+
labelWithEditIcon,
|
|
39
|
+
onLabelEditClick,
|
|
40
|
+
|
|
41
|
+
// Base Mantine Extracted Attributes
|
|
42
|
+
label,
|
|
43
|
+
description,
|
|
44
|
+
assistiveText,
|
|
45
|
+
assistiveWithIcon,
|
|
46
|
+
error,
|
|
47
|
+
required,
|
|
48
|
+
withAsterisk,
|
|
49
|
+
id,
|
|
50
|
+
className,
|
|
51
|
+
style,
|
|
52
|
+
children,
|
|
53
|
+
readOnly,
|
|
54
|
+
readOnlyComponent,
|
|
55
|
+
...rest
|
|
56
|
+
},
|
|
57
|
+
ref,
|
|
58
|
+
) {
|
|
59
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
60
|
+
const restRecord = sanitizedProps as Record<string, unknown>;
|
|
61
|
+
|
|
62
|
+
// Delete prohibited sizing hooks from bypassing the variables
|
|
63
|
+
delete restRecord["size"];
|
|
64
|
+
|
|
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
|
+
return (
|
|
95
|
+
<FormControlWrapper
|
|
96
|
+
className={className}
|
|
97
|
+
style={style as React.CSSProperties}
|
|
98
|
+
controlMaxWidth="var(--recursica_ui-kit_components_radio-button-item_properties_max-width)"
|
|
99
|
+
controlMinWidth={undefined}
|
|
100
|
+
overStyled={overStyled as true}
|
|
101
|
+
labelElement="div" // Strictly override. ARIA grouping prohibits interactive radios nested natively inside <label>.
|
|
102
|
+
formLayout={formLayout}
|
|
103
|
+
labelSize={labelSize}
|
|
104
|
+
labelAlignment={labelAlignment}
|
|
105
|
+
labelOptionalText={labelOptionalText}
|
|
106
|
+
labelWithEditIcon={labelWithEditIcon}
|
|
107
|
+
onLabelEditClick={onLabelEditClick}
|
|
108
|
+
label={label}
|
|
109
|
+
description={description}
|
|
110
|
+
assistiveText={assistiveText}
|
|
111
|
+
assistiveWithIcon={assistiveWithIcon}
|
|
112
|
+
error={error}
|
|
113
|
+
required={required}
|
|
114
|
+
withAsterisk={withAsterisk}
|
|
115
|
+
id={id}
|
|
116
|
+
>
|
|
117
|
+
<MantineRadio.Group
|
|
118
|
+
ref={ref}
|
|
119
|
+
/* Natively bind local disabled lock dynamically */
|
|
120
|
+
{...(sanitizedProps as unknown as MantineRadioGroupProps)}
|
|
121
|
+
>
|
|
122
|
+
<div className={styles.groupRoot} data-layout={formLayout}>
|
|
123
|
+
{React.Children.map(children, (child) => {
|
|
124
|
+
if (React.isValidElement(child)) {
|
|
125
|
+
return React.cloneElement(child as React.ReactElement<any>, {
|
|
126
|
+
disabled: readOnly || (child.props as any).disabled,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
return child;
|
|
130
|
+
})}
|
|
131
|
+
</div>
|
|
132
|
+
</MantineRadio.Group>
|
|
133
|
+
</FormControlWrapper>
|
|
134
|
+
);
|
|
135
|
+
},
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
RadioGroup.displayName = "RadioGroup";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# ReadOnlyField Implementation Notes
|
|
2
|
+
|
|
3
|
+
This document acts as a living record tracking edge cases and architectural choices made specific to the `ReadOnlyField` and its internal blocks (like `ReadOnlyTextField`).
|
|
4
|
+
|
|
5
|
+
## 1. Stripping Mantine Assumptions
|
|
6
|
+
|
|
7
|
+
Unlike standard input variables, standard HTML output `<p>` tags inherently carry margin and spacing assumptions from core browser stylesheets. To correctly map `ReadOnlyTextField` elements gracefully inside the generic `FormControlWrapper` bounded context, we hardcode resets:
|
|
8
|
+
|
|
9
|
+
- `margin: 0` explicitly strips block flow gap so `FormControlWrapper` handles vertical rhythm.
|
|
10
|
+
- `min-height`: Native `Input` boxes typically have baseline padding borders. We map directly to `var(--recursica_ui-kit_components_read-only-field_properties_min-height)` to ensure a side-by-side editable `TextField` and `ReadOnlyField` perfectly share roughly identical visual heights.
|
|
11
|
+
|
|
12
|
+
## 2. Unidirectional Editable Mode
|
|
13
|
+
|
|
14
|
+
The main wrapper intercepts `readOnly` boolean blocks, maintaining its own `isReadOnly` state. Natively, if a user clicks an exposed 'Edit' action (like our legacy SVG or custom `labelActionArea`), the context permanently switches to active.
|
|
15
|
+
There is intentionally no built-in reverse toggle inside typical field bindings (like input "Blur") to revert state. Parents must pass external controls to `readOnly` forcing the internal hooks to reset via standard `useEffect` propagation.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/* HARDCODED VALUES:
|
|
2
|
+
- margin: 0; padding: overrides native paragraph margins mapping back to form element flows.
|
|
3
|
+
*/
|
|
4
|
+
.textField {
|
|
5
|
+
margin: 0; /* HARDCODE: Reset paragraph margin; assume wrapper controls layout */
|
|
6
|
+
display: flex;
|
|
7
|
+
align-items: center;
|
|
8
|
+
word-break: break-word;
|
|
9
|
+
padding: 0; /* HARDCODE: read-only fields have no specific padding defined by tokens, zeroing it. */
|
|
10
|
+
font-family: var(
|
|
11
|
+
--recursica_ui-kit_components_read-only-field_properties_text_font-family,
|
|
12
|
+
inherit
|
|
13
|
+
);
|
|
14
|
+
font-size: var(
|
|
15
|
+
--recursica_ui-kit_components_read-only-field_properties_text_font-size,
|
|
16
|
+
1rem
|
|
17
|
+
);
|
|
18
|
+
font-weight: var(
|
|
19
|
+
--recursica_ui-kit_components_read-only-field_properties_text_font-weight,
|
|
20
|
+
normal
|
|
21
|
+
);
|
|
22
|
+
letter-spacing: var(
|
|
23
|
+
--recursica_ui-kit_components_read-only-field_properties_text_letter-spacing,
|
|
24
|
+
normal
|
|
25
|
+
);
|
|
26
|
+
line-height: var(
|
|
27
|
+
--recursica_ui-kit_components_read-only-field_properties_text_line-height,
|
|
28
|
+
1.5
|
|
29
|
+
);
|
|
30
|
+
font-style: var(
|
|
31
|
+
--recursica_ui-kit_components_read-only-field_properties_text_font-style,
|
|
32
|
+
normal
|
|
33
|
+
);
|
|
34
|
+
text-decoration: var(
|
|
35
|
+
--recursica_ui-kit_components_read-only-field_properties_text_text-decoration,
|
|
36
|
+
none
|
|
37
|
+
);
|
|
38
|
+
text-transform: var(
|
|
39
|
+
--recursica_ui-kit_components_read-only-field_properties_text_text-transform,
|
|
40
|
+
none
|
|
41
|
+
);
|
|
42
|
+
color: var(
|
|
43
|
+
--recursica_ui-kit_components_read-only-field_properties_colors_text
|
|
44
|
+
);
|
|
45
|
+
min-height: var(
|
|
46
|
+
--recursica_ui-kit_components_read-only-field_properties_min-height,
|
|
47
|
+
32px
|
|
48
|
+
);
|
|
49
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
3
|
+
import { ReadOnlyField } from "./ReadOnlyField";
|
|
4
|
+
import { EmptyValueRenderer } from "@recursica/adapter-common";
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof ReadOnlyField> = {
|
|
7
|
+
title: "UI Kit/ReadOnlyField",
|
|
8
|
+
component: ReadOnlyField,
|
|
9
|
+
tags: ["autodocs"],
|
|
10
|
+
parameters: {
|
|
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
|
+
},
|
|
16
|
+
},
|
|
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
|
+
},
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export default meta;
|
|
37
|
+
|
|
38
|
+
type Story = StoryObj<typeof ReadOnlyField>;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Playground story demonstrating standard structural blocks of the ReadOnlyField module dynamically.
|
|
42
|
+
*/
|
|
43
|
+
export const Default: Story = {
|
|
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
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import React, { forwardRef } from "react";
|
|
3
|
+
import {
|
|
4
|
+
ReadOnlyFieldType,
|
|
5
|
+
EmptyValueRenderer,
|
|
6
|
+
} from "@recursica/adapter-common";
|
|
7
|
+
import {
|
|
8
|
+
filterStylingProps,
|
|
9
|
+
type RecursicaOverStyled,
|
|
10
|
+
} from "../../utils/filterStylingProps";
|
|
11
|
+
import {
|
|
12
|
+
type FormControlWrapperProps,
|
|
13
|
+
FormControlWrapper,
|
|
14
|
+
} from "../FormControlWrapper/FormControlWrapper";
|
|
15
|
+
import { ReadOnlyTextField } from "./ReadOnlyTextField";
|
|
16
|
+
|
|
17
|
+
export interface RecursicaReadOnlyFieldProps
|
|
18
|
+
extends Omit<FormControlWrapperProps, "children" | "overStyled"> {
|
|
19
|
+
/** The specific value to be rendered in read-only mode explicitly matching the original field input */
|
|
20
|
+
value?: any;
|
|
21
|
+
/** The data type formatting rules bounding how the string is presented to the user */
|
|
22
|
+
type?: ReadOnlyFieldType;
|
|
23
|
+
/** Custom renderer explicitly responsible for formatting missing/empty value mappings (overriding default 'N/A') */
|
|
24
|
+
emptyValueComponent?: React.ElementType<{ value?: any }>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export type ReadOnlyFieldProps =
|
|
28
|
+
RecursicaOverStyled<RecursicaReadOnlyFieldProps>;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* A native generic form control wrapper exclusively responsible for displaying fixed data.
|
|
32
|
+
* Internally maps to structural ReadOnly primitive blocks bridging standard `FormControlWrapper` layouts natively.
|
|
33
|
+
*/
|
|
34
|
+
export const ReadOnlyField = forwardRef<HTMLDivElement, ReadOnlyFieldProps>(
|
|
35
|
+
function ReadOnlyField(
|
|
36
|
+
{ value, type = "text", emptyValueComponent, overStyled = false, ...rest },
|
|
37
|
+
ref,
|
|
38
|
+
) {
|
|
39
|
+
let content: React.ReactNode = null;
|
|
40
|
+
|
|
41
|
+
// We still pass sanitized properties (like className/style/etc) strictly down.
|
|
42
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
43
|
+
|
|
44
|
+
const Renderer = emptyValueComponent || EmptyValueRenderer;
|
|
45
|
+
const isValueEmpty = (Renderer as any).check
|
|
46
|
+
? (Renderer as any).check(value)
|
|
47
|
+
: EmptyValueRenderer.check(value);
|
|
48
|
+
|
|
49
|
+
const displayValue = isValueEmpty ? <Renderer value={value} /> : value;
|
|
50
|
+
|
|
51
|
+
switch (type) {
|
|
52
|
+
case "text":
|
|
53
|
+
default:
|
|
54
|
+
content = (
|
|
55
|
+
<ReadOnlyTextField
|
|
56
|
+
value={displayValue}
|
|
57
|
+
overStyled={overStyled as true}
|
|
58
|
+
/>
|
|
59
|
+
);
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<FormControlWrapper
|
|
65
|
+
ref={ref}
|
|
66
|
+
overStyled={overStyled as true}
|
|
67
|
+
{...(sanitizedProps as any)}
|
|
68
|
+
>
|
|
69
|
+
{content}
|
|
70
|
+
</FormControlWrapper>
|
|
71
|
+
);
|
|
72
|
+
},
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
ReadOnlyField.displayName = "ReadOnlyField";
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { Box } from "@mantine/core";
|
|
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
|
+
: String(value)
|
|
41
|
+
: ""}
|
|
42
|
+
</Box>
|
|
43
|
+
);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
ReadOnlyTextField.displayName = "ReadOnlyTextField";
|