@recursica/mantine-adapter 0.10.0 → 0.11.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 +6 -0
- 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 +1482 -1316
- 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/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/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
|
@@ -2,7 +2,9 @@ import { CheckboxProps as MantineCheckboxProps } from '@mantine/core';
|
|
|
2
2
|
import { ReadOnlyControlProps } from '@recursica/adapter-common';
|
|
3
3
|
import { CheckboxGroup } from './CheckboxGroup';
|
|
4
4
|
import { RecursicaOverStyled } from '../../utils/filterStylingProps';
|
|
5
|
-
|
|
5
|
+
import { RequireAccessibleLabel } from '../../utils/RequireAccessibleLabel';
|
|
6
|
+
import { FormControlLayoutProps } from '../FormControlLayout/FormControlLayout';
|
|
7
|
+
export type RecursicaCheckboxProps = RequireAccessibleLabel<Omit<MantineCheckboxProps, "size" | "color" | "radius" | "iconColor" | "variant"> & ReadOnlyControlProps & Pick<FormControlLayoutProps, "formLayout" | "labelSize" | "controlMaxWidth" | "controlMinWidth">>;
|
|
6
8
|
export type CheckboxProps = RecursicaOverStyled<RecursicaCheckboxProps>;
|
|
7
9
|
type CheckboxComponent = React.ForwardRefExoticComponent<CheckboxProps & React.RefAttributes<HTMLInputElement>> & {
|
|
8
10
|
Group: typeof CheckboxGroup;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
export interface FormControlLayoutProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
3
|
+
formLayout?: "stacked" | "side-by-side";
|
|
4
|
+
labelSize?: "default" | "small" | "md";
|
|
5
|
+
controlMaxWidth?: string;
|
|
6
|
+
controlMinWidth?: string;
|
|
7
|
+
leftSection?: React.ReactNode;
|
|
8
|
+
children?: React.ReactNode;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* A layout component used to correctly position form inputs alongside their labels.
|
|
12
|
+
*
|
|
13
|
+
* **When to use this:**
|
|
14
|
+
* Typically, you should use `FormControlWrapper` instead, which uses this component
|
|
15
|
+
* under the hood to handle layout automatically.
|
|
16
|
+
*
|
|
17
|
+
* However, this component is useful when you need to align standalone inputs
|
|
18
|
+
* (like a `Switch` or `Checkbox` without a label) so they perfectly match the spacing
|
|
19
|
+
* and alignment of your other form fields in a `side-by-side` layout.
|
|
20
|
+
*/
|
|
21
|
+
export declare const FormControlLayout: React.ForwardRefExoticComponent<FormControlLayoutProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -3,6 +3,8 @@ import { InputWrapperProps } from '@mantine/core';
|
|
|
3
3
|
import { RecursicaOverStyled } from '../../utils/filterStylingProps';
|
|
4
4
|
import { RecursicaLabelProps } from '../Label/Label';
|
|
5
5
|
export interface RecursicaFormControlWrapperProps extends RecursicaLabelProps {
|
|
6
|
+
/** Overall structural flow mapping the Form Control natively cascading down to Label and Input logic. */
|
|
7
|
+
formLayout?: "stacked" | "side-by-side";
|
|
6
8
|
/** Securely replaces standard Mantine descriptions safely providing standard Assistive properties. */
|
|
7
9
|
assistiveText?: React.ReactNode;
|
|
8
10
|
/** Explicit toggle to suppress the Info icon rendering natively alongside the assistiveText. Defaults to true. */
|
|
@@ -2,10 +2,8 @@ import { default as React } from 'react';
|
|
|
2
2
|
import { InputLabelProps } from '@mantine/core';
|
|
3
3
|
import { RecursicaOverStyled } from '../../utils/filterStylingProps';
|
|
4
4
|
export interface RecursicaLabelProps {
|
|
5
|
-
/** Overall structural flow mapping the Form Control natively cascading down to Label and Input logic. */
|
|
6
|
-
formLayout?: "stacked" | "side-by-side";
|
|
7
5
|
/** Specifies the sizing metrics natively mapping the Label boundaries. */
|
|
8
|
-
labelSize?: "default" | "small";
|
|
6
|
+
labelSize?: "default" | "small" | "md";
|
|
9
7
|
/** Overall alignment directive for the label strings natively forcing Left/Right justification. */
|
|
10
8
|
labelAlignment?: "left" | "right";
|
|
11
9
|
/** Injects an indicator text block alongside the label. Can be boolean (`true` maps to '(Optional)') or custom React nodes. */
|
|
@@ -2,7 +2,9 @@ import { RadioProps as MantineRadioProps } from '@mantine/core';
|
|
|
2
2
|
import { ReadOnlyControlProps } from '@recursica/adapter-common';
|
|
3
3
|
import { RadioGroup } from './RadioGroup';
|
|
4
4
|
import { RecursicaOverStyled } from '../../utils/filterStylingProps';
|
|
5
|
-
|
|
5
|
+
import { RequireAccessibleLabel } from '../../utils/RequireAccessibleLabel';
|
|
6
|
+
import { FormControlLayoutProps } from '../FormControlLayout/FormControlLayout';
|
|
7
|
+
export type RecursicaRadioProps = RequireAccessibleLabel<Omit<MantineRadioProps, "size" | "color" | "radius" | "iconColor" | "variant"> & ReadOnlyControlProps & Pick<FormControlLayoutProps, "formLayout" | "labelSize" | "controlMaxWidth" | "controlMinWidth">>;
|
|
6
8
|
export type RadioProps = RecursicaOverStyled<RecursicaRadioProps>;
|
|
7
9
|
type RadioComponent = React.ForwardRefExoticComponent<RadioProps & React.RefAttributes<HTMLInputElement>> & {
|
|
8
10
|
Group: typeof RadioGroup;
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
-
import { ReadOnlyFieldType } from '@recursica/adapter-common';
|
|
2
|
+
import { ReadOnlyFieldType, ReadOnlyControlProps } from '@recursica/adapter-common';
|
|
3
3
|
import { RecursicaOverStyled } from '../../utils/filterStylingProps';
|
|
4
4
|
import { FormControlWrapperProps } from '../FormControlWrapper/FormControlWrapper';
|
|
5
|
-
export interface RecursicaReadOnlyFieldProps extends Omit<FormControlWrapperProps, "children" | "overStyled"> {
|
|
5
|
+
export interface RecursicaReadOnlyFieldProps extends Omit<FormControlWrapperProps, "children" | "overStyled" | "controlMaxWidth" | "controlMinWidth">, Pick<ReadOnlyControlProps, "emptyValueComponent"> {
|
|
6
6
|
/** The specific value to be rendered in read-only mode explicitly matching the original field input */
|
|
7
7
|
value?: any;
|
|
8
8
|
/** The data type formatting rules bounding how the string is presented to the user */
|
|
9
9
|
type?: ReadOnlyFieldType;
|
|
10
|
-
/**
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
/** Pass the native maximum width design variable dynamically bounding the specific wrapper width exclusively. */
|
|
11
|
+
controlMaxWidth?: string | undefined;
|
|
12
|
+
/** Pass the native minimum width design variable dynamically bounding the specific wrapper width exclusively. */
|
|
13
|
+
controlMinWidth?: string | undefined;
|
|
14
14
|
}
|
|
15
15
|
export type ReadOnlyFieldProps = RecursicaOverStyled<RecursicaReadOnlyFieldProps>;
|
|
16
16
|
/**
|
|
@@ -5,7 +5,13 @@ export interface WithReadOnlyWrapperProps extends Omit<FormControlWrapperProps,
|
|
|
5
5
|
/** Injects whether the field defaults to reading mode natively */
|
|
6
6
|
readOnly?: boolean;
|
|
7
7
|
/** Explicit React component directly overtaking the baseline text renderer when read-only mode is active */
|
|
8
|
-
readOnlyComponent?: React.
|
|
8
|
+
readOnlyComponent?: React.ElementType<any>;
|
|
9
|
+
/** Custom renderer explicitly responsible for formatting missing/empty value mappings (overriding default 'N/A') */
|
|
10
|
+
emptyValueComponent?: React.ElementType<{
|
|
11
|
+
value?: any;
|
|
12
|
+
}>;
|
|
13
|
+
/** The full native props dictionary securely forwarded into the custom readOnlyComponent if active */
|
|
14
|
+
readOnlyNativeProps?: any;
|
|
9
15
|
/** Instructs the underlying generic ReadOnlyField which raw visual structure to bridge automatically */
|
|
10
16
|
readOnlyType?: ReadOnlyFieldType;
|
|
11
17
|
/** The isolated raw data value intercepted explicitly into the ReadOnly formatters */
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { SwitchProps as MantineSwitchProps } from '@mantine/core';
|
|
2
2
|
import { ReadOnlyControlProps } from '@recursica/adapter-common';
|
|
3
3
|
import { RecursicaOverStyled } from '../../utils/filterStylingProps';
|
|
4
|
+
import { RequireAccessibleLabel } from '../../utils/RequireAccessibleLabel';
|
|
5
|
+
import { FormControlLayoutProps } from '../FormControlLayout/FormControlLayout';
|
|
4
6
|
import { SwitchGroup } from './SwitchGroup';
|
|
5
|
-
export type RecursicaSwitchProps = Omit<MantineSwitchProps, "size" | "color" | "radius" | "variant"> & ReadOnlyControlProps
|
|
7
|
+
export type RecursicaSwitchProps = RequireAccessibleLabel<Omit<MantineSwitchProps, "size" | "color" | "radius" | "variant"> & ReadOnlyControlProps & Pick<FormControlLayoutProps, "formLayout" | "labelSize" | "controlMaxWidth" | "controlMinWidth">>;
|
|
6
8
|
export type SwitchProps = RecursicaOverStyled<RecursicaSwitchProps>;
|
|
7
9
|
type SwitchComponent = React.ForwardRefExoticComponent<SwitchProps & React.RefAttributes<HTMLInputElement>> & {
|
|
8
10
|
Group: typeof SwitchGroup;
|
|
@@ -13,6 +13,7 @@ export * from './Dropdown/Dropdown';
|
|
|
13
13
|
export * from './FileInput/FileInput';
|
|
14
14
|
export * from './FileUpload/FileUpload';
|
|
15
15
|
export * from './Flex/Flex';
|
|
16
|
+
export * from './FormControlLayout/FormControlLayout';
|
|
16
17
|
export * from './Group/Group';
|
|
17
18
|
export * from './HoverCard/HoverCard';
|
|
18
19
|
export * from './Link/Link';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Enforces accessibility by strictly requiring at least one form of labeling:
|
|
4
|
+
* either a visual \`label\`, an \`aria-label\`, or an \`aria-labelledby\`.
|
|
5
|
+
*/
|
|
6
|
+
export type RequireAccessibleLabel<T> = T & ({
|
|
7
|
+
label: ReactNode;
|
|
8
|
+
"aria-label"?: string;
|
|
9
|
+
"aria-labelledby"?: string;
|
|
10
|
+
} | {
|
|
11
|
+
label?: ReactNode;
|
|
12
|
+
"aria-label": string;
|
|
13
|
+
"aria-labelledby"?: string;
|
|
14
|
+
} | {
|
|
15
|
+
label?: ReactNode;
|
|
16
|
+
"aria-label"?: string;
|
|
17
|
+
"aria-labelledby": string;
|
|
18
|
+
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
2
|
import { AssistiveElement } from "./AssistiveElement";
|
|
3
3
|
import { Layer } from "@recursica/adapter-common";
|
|
4
|
-
import React from "react";
|
|
5
4
|
|
|
6
5
|
const meta: Meta<typeof AssistiveElement> = {
|
|
7
6
|
title: "UI-Kit/AssistiveElement",
|
|
@@ -37,7 +36,8 @@ export const DefaultHelp: Story = {
|
|
|
37
36
|
assistiveVariant: "help",
|
|
38
37
|
assistiveWithIcon: true,
|
|
39
38
|
},
|
|
40
|
-
|
|
39
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
40
|
+
render: ({ withLayer, layer, ...args }: any) => (
|
|
41
41
|
<Layer layer={0} style={{ padding: "48px" }}>
|
|
42
42
|
<AssistiveElement {...args} />
|
|
43
43
|
</Layer>
|
|
@@ -51,7 +51,8 @@ export const ErrorState: Story = {
|
|
|
51
51
|
assistiveVariant: "error",
|
|
52
52
|
assistiveWithIcon: true,
|
|
53
53
|
},
|
|
54
|
-
|
|
54
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
55
|
+
render: ({ withLayer, layer, ...args }: any) => (
|
|
55
56
|
<Layer layer={0} style={{ padding: "48px" }}>
|
|
56
57
|
<AssistiveElement {...args} />
|
|
57
58
|
</Layer>
|
|
@@ -65,7 +66,8 @@ export const NoIconHelp: Story = {
|
|
|
65
66
|
assistiveVariant: "help",
|
|
66
67
|
assistiveWithIcon: false,
|
|
67
68
|
},
|
|
68
|
-
|
|
69
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
70
|
+
render: ({ withLayer, layer, ...args }: any) => (
|
|
69
71
|
<Layer layer={0} style={{ padding: "48px" }}>
|
|
70
72
|
<AssistiveElement {...args} />
|
|
71
73
|
</Layer>
|
|
@@ -42,7 +42,8 @@ export const Default: Story = {
|
|
|
42
42
|
size: "default",
|
|
43
43
|
variant: "solid",
|
|
44
44
|
},
|
|
45
|
-
|
|
45
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
46
|
+
render: ({ withLayer, layer, ...args }: any) => {
|
|
46
47
|
return <Avatar {...args} />;
|
|
47
48
|
},
|
|
48
49
|
};
|
|
@@ -53,7 +54,8 @@ export const TextSolidDefault: Story = {
|
|
|
53
54
|
variant: "solid",
|
|
54
55
|
size: "default",
|
|
55
56
|
},
|
|
56
|
-
|
|
57
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
58
|
+
render: ({ withLayer, layer, ...args }: any) => <Avatar {...args} />,
|
|
57
59
|
};
|
|
58
60
|
|
|
59
61
|
export const ImageLarge: Story = {
|
|
@@ -61,7 +63,8 @@ export const ImageLarge: Story = {
|
|
|
61
63
|
src: "https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=250&q=80",
|
|
62
64
|
size: "large",
|
|
63
65
|
},
|
|
64
|
-
|
|
66
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
67
|
+
render: ({ withLayer, layer, ...args }: any) => <Avatar {...args} />,
|
|
65
68
|
};
|
|
66
69
|
|
|
67
70
|
export const IconSmallGhost: Story = {
|
|
@@ -85,7 +88,8 @@ export const IconSmallGhost: Story = {
|
|
|
85
88
|
</svg>
|
|
86
89
|
),
|
|
87
90
|
},
|
|
88
|
-
|
|
91
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
92
|
+
render: ({ withLayer, layer, ...args }: any) => <Avatar {...args} />,
|
|
89
93
|
};
|
|
90
94
|
|
|
91
95
|
export const LayerOneOutline: Story = {
|
|
@@ -94,7 +98,8 @@ export const LayerOneOutline: Story = {
|
|
|
94
98
|
variant: "outline",
|
|
95
99
|
size: "default",
|
|
96
100
|
},
|
|
97
|
-
|
|
101
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
102
|
+
render: ({ withLayer, layer, ...args }: any) => (
|
|
98
103
|
<Layer layer={1} style={{ padding: "24px", display: "inline-block" }}>
|
|
99
104
|
<Avatar {...args} />
|
|
100
105
|
</Layer>
|
|
@@ -27,7 +27,8 @@ export const Default: Story = {
|
|
|
27
27
|
children: "Badge Label",
|
|
28
28
|
variant: "primary-color",
|
|
29
29
|
},
|
|
30
|
-
|
|
30
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
31
|
+
render: ({ withLayer, layer, ...args }: any) => {
|
|
31
32
|
return <Badge {...args} />;
|
|
32
33
|
},
|
|
33
34
|
};
|
|
@@ -20,9 +20,6 @@ const meta: Meta<ButtonStoryProps> = {
|
|
|
20
20
|
options: ["default", "small"],
|
|
21
21
|
description: "The size of the button",
|
|
22
22
|
},
|
|
23
|
-
disabled: {
|
|
24
|
-
control: "boolean",
|
|
25
|
-
},
|
|
26
23
|
},
|
|
27
24
|
};
|
|
28
25
|
|
|
@@ -37,7 +34,8 @@ export const Default: Story = {
|
|
|
37
34
|
size: "default",
|
|
38
35
|
disabled: false,
|
|
39
36
|
},
|
|
40
|
-
|
|
37
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
38
|
+
render: ({ withLayer, layer, ...args }: any) => {
|
|
41
39
|
return <Button {...args} />;
|
|
42
40
|
},
|
|
43
41
|
};
|
|
@@ -161,7 +161,7 @@
|
|
|
161
161
|
--recursica_ui-kit_components_checkbox_properties_colors_icon-color
|
|
162
162
|
) !important;
|
|
163
163
|
}
|
|
164
|
-
.input:disabled + .
|
|
164
|
+
.input:disabled + .icon {
|
|
165
165
|
color: var(
|
|
166
166
|
--recursica_ui-kit_components_checkbox_properties_colors_disabled-icon
|
|
167
167
|
) !important;
|
|
@@ -24,14 +24,13 @@ To render a solitary component natively:
|
|
|
24
24
|
},
|
|
25
25
|
},
|
|
26
26
|
argTypes: {
|
|
27
|
-
disabled: {
|
|
28
|
-
control: "boolean",
|
|
29
|
-
},
|
|
30
27
|
readOnly: {
|
|
31
28
|
control: "boolean",
|
|
32
29
|
description:
|
|
33
30
|
"Toggles structural read-only data presentation bypassing interaction boundaries completely.",
|
|
34
31
|
},
|
|
32
|
+
controlMaxWidth: { table: { disable: true } },
|
|
33
|
+
controlMinWidth: { table: { disable: true } },
|
|
35
34
|
},
|
|
36
35
|
};
|
|
37
36
|
|
|
@@ -46,6 +45,13 @@ export const Default: Story = {
|
|
|
46
45
|
},
|
|
47
46
|
};
|
|
48
47
|
|
|
48
|
+
export const SideBySideLayout: Story = {
|
|
49
|
+
args: {
|
|
50
|
+
label: "Opt-in form alignment",
|
|
51
|
+
formLayout: "side-by-side",
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
|
|
49
55
|
export const LongLabelWrap: Story = {
|
|
50
56
|
args: {
|
|
51
57
|
label:
|
|
@@ -71,3 +77,18 @@ export const StaticVariations: Story = {
|
|
|
71
77
|
</div>
|
|
72
78
|
),
|
|
73
79
|
};
|
|
80
|
+
|
|
81
|
+
export const ReadOnly: Story = {
|
|
82
|
+
args: {},
|
|
83
|
+
render: () => (
|
|
84
|
+
<div
|
|
85
|
+
style={{
|
|
86
|
+
display: "flex",
|
|
87
|
+
flexDirection: "column",
|
|
88
|
+
gap: "24px",
|
|
89
|
+
}}
|
|
90
|
+
>
|
|
91
|
+
<Checkbox label="Accept Terms & Conditions" defaultChecked readOnly />
|
|
92
|
+
</div>
|
|
93
|
+
),
|
|
94
|
+
};
|
|
@@ -9,13 +9,25 @@ import {
|
|
|
9
9
|
filterStylingProps,
|
|
10
10
|
type RecursicaOverStyled,
|
|
11
11
|
} from "../../utils/filterStylingProps";
|
|
12
|
+
import { type RequireAccessibleLabel } from "../../utils/RequireAccessibleLabel";
|
|
13
|
+
import {
|
|
14
|
+
FormControlLayout,
|
|
15
|
+
type FormControlLayoutProps,
|
|
16
|
+
} from "../FormControlLayout/FormControlLayout";
|
|
17
|
+
|
|
12
18
|
import styles from "./Checkbox.module.css";
|
|
13
19
|
|
|
14
|
-
export type RecursicaCheckboxProps =
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
export type RecursicaCheckboxProps = RequireAccessibleLabel<
|
|
21
|
+
Omit<
|
|
22
|
+
MantineCheckboxProps,
|
|
23
|
+
"size" | "color" | "radius" | "iconColor" | "variant"
|
|
24
|
+
> &
|
|
25
|
+
ReadOnlyControlProps &
|
|
26
|
+
Pick<
|
|
27
|
+
FormControlLayoutProps,
|
|
28
|
+
"formLayout" | "labelSize" | "controlMaxWidth" | "controlMinWidth"
|
|
29
|
+
>
|
|
30
|
+
>;
|
|
19
31
|
|
|
20
32
|
export type CheckboxProps = RecursicaOverStyled<RecursicaCheckboxProps>;
|
|
21
33
|
|
|
@@ -26,10 +38,18 @@ type CheckboxComponent = React.ForwardRefExoticComponent<
|
|
|
26
38
|
};
|
|
27
39
|
|
|
28
40
|
export const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
|
|
29
|
-
function Checkbox(
|
|
30
|
-
{
|
|
31
|
-
|
|
32
|
-
|
|
41
|
+
function Checkbox(props, ref) {
|
|
42
|
+
const {
|
|
43
|
+
overStyled = false,
|
|
44
|
+
readOnly,
|
|
45
|
+
readOnlyComponent,
|
|
46
|
+
disabled,
|
|
47
|
+
formLayout,
|
|
48
|
+
labelSize,
|
|
49
|
+
controlMaxWidth,
|
|
50
|
+
controlMinWidth,
|
|
51
|
+
...rest
|
|
52
|
+
} = props;
|
|
33
53
|
// Checkbox doesn't use Label onLabelEditClick natively since it isn't mapped inside FormControlWrapper intrinsically.
|
|
34
54
|
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
35
55
|
const restRecord = sanitizedProps as Record<string, unknown>;
|
|
@@ -41,11 +61,6 @@ export const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
|
|
|
41
61
|
delete restRecord["variant"];
|
|
42
62
|
delete restRecord["iconColor"];
|
|
43
63
|
|
|
44
|
-
if (readOnly && readOnlyComponent) {
|
|
45
|
-
// Safely fallback explicitly returning mapped elements natively without macro wrappers
|
|
46
|
-
return <>{readOnlyComponent}</>;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
64
|
const mergedClassNames: Partial<Record<string, string>> = {
|
|
50
65
|
root: styles.root,
|
|
51
66
|
body: styles.body,
|
|
@@ -85,8 +100,35 @@ export const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
|
|
|
85
100
|
? `${styles.root} ${classNameProp}`
|
|
86
101
|
: styles.root;
|
|
87
102
|
|
|
103
|
+
if (readOnly && !!readOnlyComponent) {
|
|
104
|
+
const isChecked = !!(restRecord.checked ?? restRecord.defaultChecked);
|
|
105
|
+
const ReadOnlyComp = readOnlyComponent;
|
|
106
|
+
const roNode = (
|
|
107
|
+
<ReadOnlyComp
|
|
108
|
+
{...props}
|
|
109
|
+
checked={isChecked}
|
|
110
|
+
label={restRecord.label as React.ReactNode}
|
|
111
|
+
/>
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
if (formLayout) {
|
|
115
|
+
return (
|
|
116
|
+
<FormControlLayout
|
|
117
|
+
formLayout={formLayout}
|
|
118
|
+
labelSize={labelSize}
|
|
119
|
+
controlMaxWidth={controlMaxWidth}
|
|
120
|
+
controlMinWidth={controlMinWidth}
|
|
121
|
+
>
|
|
122
|
+
{roNode}
|
|
123
|
+
</FormControlLayout>
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return <>{roNode}</>;
|
|
128
|
+
}
|
|
129
|
+
|
|
88
130
|
// We omit Mantine's sizing/coloring so we rely strictly on variables from Checkbox.module.css
|
|
89
|
-
|
|
131
|
+
const checkboxNode = (
|
|
90
132
|
<MantineCheckbox
|
|
91
133
|
ref={ref}
|
|
92
134
|
className={finalClass}
|
|
@@ -95,6 +137,21 @@ export const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
|
|
|
95
137
|
{...(sanitizedProps as unknown as MantineCheckboxProps)}
|
|
96
138
|
/>
|
|
97
139
|
);
|
|
140
|
+
|
|
141
|
+
if (formLayout) {
|
|
142
|
+
return (
|
|
143
|
+
<FormControlLayout
|
|
144
|
+
formLayout={formLayout}
|
|
145
|
+
labelSize={labelSize}
|
|
146
|
+
controlMaxWidth={controlMaxWidth}
|
|
147
|
+
controlMinWidth={controlMinWidth}
|
|
148
|
+
>
|
|
149
|
+
{checkboxNode}
|
|
150
|
+
</FormControlLayout>
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return checkboxNode;
|
|
98
155
|
},
|
|
99
156
|
) as CheckboxComponent;
|
|
100
157
|
|
|
@@ -46,7 +46,24 @@ export default meta;
|
|
|
46
46
|
|
|
47
47
|
type Story = StoryObj<typeof CheckboxGroup>;
|
|
48
48
|
|
|
49
|
-
export const
|
|
49
|
+
export const Default: Story = {
|
|
50
|
+
args: {
|
|
51
|
+
formLayout: "stacked",
|
|
52
|
+
label: "Standard Group",
|
|
53
|
+
},
|
|
54
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
55
|
+
render: function StoryRender({ withLayer, layer, ...args }: any) {
|
|
56
|
+
const [value, setValue] = useState<string[]>([]);
|
|
57
|
+
return (
|
|
58
|
+
<Checkbox.Group {...args} value={value} onChange={setValue}>
|
|
59
|
+
<Checkbox value="1" label="Option 1" />
|
|
60
|
+
<Checkbox value="2" label="Option 2" />
|
|
61
|
+
</Checkbox.Group>
|
|
62
|
+
);
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export const SideBySideLayout: Story = {
|
|
50
67
|
args: {
|
|
51
68
|
formLayout: "side-by-side",
|
|
52
69
|
labelOptionalText: "Recommended",
|
|
@@ -55,7 +72,8 @@ export const GroupSideBySide: Story = {
|
|
|
55
72
|
assistiveText:
|
|
56
73
|
"Select all libraries currently in use for this specific workspace configuration.",
|
|
57
74
|
},
|
|
58
|
-
|
|
75
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
76
|
+
render: function StoryRender({ withLayer, layer, ...args }: any) {
|
|
59
77
|
const [value, setValue] = useState<string[]>(["react"]);
|
|
60
78
|
return (
|
|
61
79
|
<Checkbox.Group {...args} value={value} onChange={setValue}>
|
|
@@ -70,14 +88,15 @@ export const GroupSideBySide: Story = {
|
|
|
70
88
|
},
|
|
71
89
|
};
|
|
72
90
|
|
|
73
|
-
export const
|
|
91
|
+
export const StackedLayout: Story = {
|
|
74
92
|
args: {
|
|
75
93
|
formLayout: "stacked",
|
|
76
94
|
required: true,
|
|
77
95
|
label: "Execution Targets",
|
|
78
96
|
error: "You must select at least one deployment target to compile.",
|
|
79
97
|
},
|
|
80
|
-
|
|
98
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
99
|
+
render: function StoryRender({ withLayer, layer, ...args }: any) {
|
|
81
100
|
const [value, setValue] = useState<string[]>(["react"]);
|
|
82
101
|
return (
|
|
83
102
|
<Checkbox.Group {...args} value={value} onChange={setValue}>
|
|
@@ -92,7 +111,7 @@ export const GroupStacked: Story = {
|
|
|
92
111
|
},
|
|
93
112
|
};
|
|
94
113
|
|
|
95
|
-
export const
|
|
114
|
+
export const ReadOnly: Story = {
|
|
96
115
|
args: {
|
|
97
116
|
readOnly: true,
|
|
98
117
|
formLayout: "stacked",
|
|
@@ -101,7 +120,8 @@ export const StaticReadOnlyGroup: Story = {
|
|
|
101
120
|
assistiveText:
|
|
102
121
|
"This structure explicitly validates native component-level DOM preservation natively mapping lock bounds safely over interaction.",
|
|
103
122
|
},
|
|
104
|
-
|
|
123
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
124
|
+
render: function StoryRender({ withLayer, layer, ...args }: any) {
|
|
105
125
|
const [value, setValue] = useState<string[]>(["disabledNode"]);
|
|
106
126
|
return (
|
|
107
127
|
<Checkbox.Group {...args} value={value} onChange={setValue}>
|
|
@@ -117,22 +137,3 @@ export const StaticReadOnlyGroup: Story = {
|
|
|
117
137
|
);
|
|
118
138
|
},
|
|
119
139
|
};
|
|
120
|
-
|
|
121
|
-
export const EditableReadOnlyGroup: Story = {
|
|
122
|
-
args: {
|
|
123
|
-
readOnly: true,
|
|
124
|
-
formLayout: "side-by-side",
|
|
125
|
-
labelWithEditIcon: true,
|
|
126
|
-
label: "Interactively Editable ReadOnly Group",
|
|
127
|
-
assistiveText: "Users explicitly unlock DOM structures dynamically.",
|
|
128
|
-
},
|
|
129
|
-
render: function EditableReadOnlyGroupRender(args) {
|
|
130
|
-
const [value, setValue] = useState<string[]>(["activeState"]);
|
|
131
|
-
return (
|
|
132
|
-
<Checkbox.Group {...args} value={value} onChange={setValue}>
|
|
133
|
-
<Checkbox value="activeState" label="Locked active state" />
|
|
134
|
-
<Checkbox value="unlockedNode" label="Locked inactive map" />
|
|
135
|
-
</Checkbox.Group>
|
|
136
|
-
);
|
|
137
|
-
},
|
|
138
|
-
};
|