@recursica/mantine-adapter 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.storybook/commonArgTypes.ts +148 -0
- package/CHANGELOG.md +69 -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 +660 -586
- package/dist/mantine-adapter.js.map +1 -1
- package/dist/src/components/Checkbox/CheckboxGroup.d.ts +1 -1
- package/dist/src/components/Chip/Chip.d.ts +14 -2
- package/package.json +5 -2
- 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 +261 -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 +111 -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/DatePicker/DatePicker.stories.tsx +22 -0
- package/src/components/DatePicker/DatePicker.tsx +7 -0
- package/src/components/Dropdown/Dropdown.stories.tsx +22 -0
- package/src/components/Dropdown/Dropdown.tsx +7 -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/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/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.stories.tsx +17 -0
- package/src/components/Loader/Loader.tsx +7 -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.stories.tsx +22 -0
- package/src/components/Radio/Radio.tsx +7 -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/Stepper/Stepper.stories.tsx +17 -0
- package/src/components/Stepper/Stepper.tsx +7 -0
- package/src/components/Switch/Switch.stories.tsx +22 -0
- package/src/components/Switch/Switch.tsx +7 -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.stories.tsx +22 -0
- package/src/components/TextArea/TextArea.tsx +7 -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 +39 -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 +139 -0
- package/src/utils/index.ts +1 -0
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import React, { forwardRef } from "react";
|
|
2
|
+
import {
|
|
3
|
+
Accordion as MantineAccordion,
|
|
4
|
+
type AccordionProps as MantineAccordionProps,
|
|
5
|
+
type AccordionItemProps,
|
|
6
|
+
type AccordionControlProps,
|
|
7
|
+
type AccordionPanelProps,
|
|
8
|
+
} from "@mantine/core";
|
|
9
|
+
import {
|
|
10
|
+
filterStylingProps,
|
|
11
|
+
type RecursicaOverStyled,
|
|
12
|
+
} from "../../utils/filterStylingProps";
|
|
13
|
+
import styles from "./Accordion.module.css";
|
|
14
|
+
|
|
15
|
+
// ==== ACCORDION CONTAINER ====
|
|
16
|
+
export type AccordionProps = RecursicaOverStyled<MantineAccordionProps>;
|
|
17
|
+
|
|
18
|
+
const AccordionBase = function Accordion({
|
|
19
|
+
variant = "unstyled",
|
|
20
|
+
overStyled = false,
|
|
21
|
+
...rest
|
|
22
|
+
}: AccordionProps) {
|
|
23
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
24
|
+
|
|
25
|
+
// Bind all deep CSS module references natively into the global class mapping schema
|
|
26
|
+
const mergedClassNames: Partial<Record<string, string>> = {
|
|
27
|
+
root: styles.root,
|
|
28
|
+
item: styles.item,
|
|
29
|
+
control: styles.control,
|
|
30
|
+
label: styles.label,
|
|
31
|
+
chevron: styles.chevron,
|
|
32
|
+
panel: styles.panel,
|
|
33
|
+
content: styles.content,
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const classNamesProp = (sanitizedProps as Record<string, unknown>).classNames;
|
|
37
|
+
if (
|
|
38
|
+
classNamesProp &&
|
|
39
|
+
typeof classNamesProp === "object" &&
|
|
40
|
+
!Array.isArray(classNamesProp)
|
|
41
|
+
) {
|
|
42
|
+
const o = classNamesProp as Record<string, string>;
|
|
43
|
+
Object.keys(o).forEach((key) => {
|
|
44
|
+
if (mergedClassNames[key]) {
|
|
45
|
+
mergedClassNames[key] = `${mergedClassNames[key]} ${o[key]}`;
|
|
46
|
+
} else {
|
|
47
|
+
mergedClassNames[key] = o[key];
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const classNameProp = (sanitizedProps as Record<string, unknown>)
|
|
53
|
+
.className as string | undefined;
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<MantineAccordion
|
|
57
|
+
variant={variant}
|
|
58
|
+
className={classNameProp}
|
|
59
|
+
classNames={mergedClassNames}
|
|
60
|
+
{...(sanitizedProps as unknown as MantineAccordionProps)}
|
|
61
|
+
/>
|
|
62
|
+
);
|
|
63
|
+
};
|
|
64
|
+
AccordionBase.displayName = "Accordion";
|
|
65
|
+
|
|
66
|
+
// ==== ACCORDION ITEM ====
|
|
67
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
68
|
+
export interface RecursicaAccordionItemProps
|
|
69
|
+
extends Omit<AccordionItemProps, "className"> {}
|
|
70
|
+
// We need to omit and re-merge native props like in Badge
|
|
71
|
+
export type AccordionItemWrapperProps = RecursicaOverStyled<
|
|
72
|
+
AccordionItemProps & {
|
|
73
|
+
/**
|
|
74
|
+
* When provided alongside `leftIcon` or independently, this auto-generates the Accordion Control and Panel DOM layers natively.
|
|
75
|
+
*/
|
|
76
|
+
title?: React.ReactNode;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Leading icon explicitly mapped into the Mantine `Accordion.Control` leftSection boundary natively.
|
|
80
|
+
*/
|
|
81
|
+
leftIcon?: React.ReactNode;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Toggles the presence of the bottom trailing divider native to AccordionItems.
|
|
85
|
+
* @default true
|
|
86
|
+
*/
|
|
87
|
+
divider?: boolean;
|
|
88
|
+
}
|
|
89
|
+
>;
|
|
90
|
+
|
|
91
|
+
export const AccordionItem = forwardRef<
|
|
92
|
+
HTMLDivElement,
|
|
93
|
+
AccordionItemWrapperProps
|
|
94
|
+
>(function AccordionItem(
|
|
95
|
+
{ title, leftIcon, divider = true, children, overStyled = false, ...rest },
|
|
96
|
+
ref,
|
|
97
|
+
) {
|
|
98
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
99
|
+
const classNameProp = (sanitizedProps as Record<string, unknown>)
|
|
100
|
+
.className as string | undefined;
|
|
101
|
+
|
|
102
|
+
const finalClass =
|
|
103
|
+
[divider ? undefined : styles.noDivider, classNameProp]
|
|
104
|
+
.filter(Boolean)
|
|
105
|
+
.join(" ") || undefined;
|
|
106
|
+
|
|
107
|
+
// If the user utilizes the explicit 'title' prop from Recursica, we securely auto-construct the Mantine sub-hierarchy natively!
|
|
108
|
+
// If not, we defer to raw composable children (meaning the integrator maps `<Accordion.Control>` manually).
|
|
109
|
+
return (
|
|
110
|
+
<MantineAccordion.Item
|
|
111
|
+
ref={ref}
|
|
112
|
+
className={finalClass}
|
|
113
|
+
{...(sanitizedProps as unknown as AccordionItemProps)}
|
|
114
|
+
>
|
|
115
|
+
{title ? (
|
|
116
|
+
<>
|
|
117
|
+
<AccordionControl leftIcon={leftIcon}>{title}</AccordionControl>
|
|
118
|
+
<AccordionPanel>{children}</AccordionPanel>
|
|
119
|
+
</>
|
|
120
|
+
) : (
|
|
121
|
+
children
|
|
122
|
+
)}
|
|
123
|
+
</MantineAccordion.Item>
|
|
124
|
+
);
|
|
125
|
+
});
|
|
126
|
+
AccordionItem.displayName = "AccordionItem";
|
|
127
|
+
|
|
128
|
+
// ==== ACCORDION CONTROL ====
|
|
129
|
+
export type AccordionControlWrapperProps = RecursicaOverStyled<
|
|
130
|
+
AccordionControlProps & {
|
|
131
|
+
/**
|
|
132
|
+
* Leading icon explicitly mapped into the Mantine `Accordion.Control` leftSection boundary natively.
|
|
133
|
+
*/
|
|
134
|
+
leftIcon?: React.ReactNode;
|
|
135
|
+
}
|
|
136
|
+
>;
|
|
137
|
+
|
|
138
|
+
export const AccordionControl = forwardRef<
|
|
139
|
+
HTMLButtonElement,
|
|
140
|
+
AccordionControlWrapperProps
|
|
141
|
+
>(function AccordionControl(
|
|
142
|
+
{ leftIcon, children, overStyled = false, ...rest },
|
|
143
|
+
ref,
|
|
144
|
+
) {
|
|
145
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
146
|
+
const classNameProp = (sanitizedProps as Record<string, unknown>)
|
|
147
|
+
.className as string | undefined;
|
|
148
|
+
|
|
149
|
+
return (
|
|
150
|
+
<MantineAccordion.Control
|
|
151
|
+
ref={ref}
|
|
152
|
+
className={classNameProp}
|
|
153
|
+
icon={
|
|
154
|
+
leftIcon ? (
|
|
155
|
+
<span className={styles.iconLeftWrapper} aria-hidden>
|
|
156
|
+
{leftIcon}
|
|
157
|
+
</span>
|
|
158
|
+
) : undefined
|
|
159
|
+
}
|
|
160
|
+
{...(sanitizedProps as unknown as AccordionControlProps)}
|
|
161
|
+
>
|
|
162
|
+
{children}
|
|
163
|
+
</MantineAccordion.Control>
|
|
164
|
+
);
|
|
165
|
+
});
|
|
166
|
+
AccordionControl.displayName = "AccordionControl";
|
|
167
|
+
|
|
168
|
+
// ==== ACCORDION PANEL ====
|
|
169
|
+
export type AccordionPanelWrapperProps =
|
|
170
|
+
RecursicaOverStyled<AccordionPanelProps>;
|
|
171
|
+
|
|
172
|
+
export const AccordionPanel = forwardRef<
|
|
173
|
+
HTMLDivElement,
|
|
174
|
+
AccordionPanelWrapperProps
|
|
175
|
+
>(function AccordionPanel({ overStyled = false, ...rest }, ref) {
|
|
176
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
177
|
+
const classNameProp = (sanitizedProps as Record<string, unknown>)
|
|
178
|
+
.className as string | undefined;
|
|
179
|
+
|
|
180
|
+
return (
|
|
181
|
+
<MantineAccordion.Panel
|
|
182
|
+
ref={ref}
|
|
183
|
+
className={classNameProp}
|
|
184
|
+
{...(sanitizedProps as unknown as AccordionPanelProps)}
|
|
185
|
+
/>
|
|
186
|
+
);
|
|
187
|
+
});
|
|
188
|
+
AccordionPanel.displayName = "AccordionPanel";
|
|
189
|
+
|
|
190
|
+
// ==== DOT NOTATION EXPORT ====
|
|
191
|
+
type AccordionComponent = typeof AccordionBase & {
|
|
192
|
+
Item: typeof AccordionItem;
|
|
193
|
+
Control: typeof AccordionControl;
|
|
194
|
+
Panel: typeof AccordionPanel;
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
export const Accordion = AccordionBase as AccordionComponent;
|
|
198
|
+
Accordion.Item = AccordionItem;
|
|
199
|
+
Accordion.Control = AccordionControl;
|
|
200
|
+
Accordion.Panel = AccordionPanel;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./Accordion";
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AssistiveElement.module.css
|
|
3
|
+
*
|
|
4
|
+
* HARDCODED VALUES:
|
|
5
|
+
* - margin / padding: 0 — Structural resets.
|
|
6
|
+
* - display: flex / align-items: flex-start — layout alignment.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
.root {
|
|
10
|
+
display: flex !important;
|
|
11
|
+
align-items: flex-start !important; /* Forces the icon to align with the first line of text */
|
|
12
|
+
margin: 0 !important; /* HARDCODE: structural reset */
|
|
13
|
+
padding: 0 !important; /* HARDCODE: structural reset */
|
|
14
|
+
|
|
15
|
+
gap: var(
|
|
16
|
+
--recursica_ui-kit_components_assistive-element_properties_icon-text-gap
|
|
17
|
+
);
|
|
18
|
+
margin-top: var(
|
|
19
|
+
--recursica_ui-kit_components_assistive-element_properties_top-margin
|
|
20
|
+
) !important;
|
|
21
|
+
max-width: var(
|
|
22
|
+
--recursica_ui-kit_components_assistive-element_properties_max-width
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.textWrapper {
|
|
27
|
+
/* Text properties securely governed via layout mappings */
|
|
28
|
+
font-family: var(
|
|
29
|
+
--recursica_ui-kit_components_assistive-element_properties_text_font-family
|
|
30
|
+
);
|
|
31
|
+
font-size: var(
|
|
32
|
+
--recursica_ui-kit_components_assistive-element_properties_text_font-size
|
|
33
|
+
);
|
|
34
|
+
font-style: var(
|
|
35
|
+
--recursica_ui-kit_components_assistive-element_properties_text_font-style
|
|
36
|
+
);
|
|
37
|
+
font-weight: var(
|
|
38
|
+
--recursica_ui-kit_components_assistive-element_properties_text_font-weight
|
|
39
|
+
);
|
|
40
|
+
letter-spacing: var(
|
|
41
|
+
--recursica_ui-kit_components_assistive-element_properties_text_letter-spacing
|
|
42
|
+
);
|
|
43
|
+
line-height: var(
|
|
44
|
+
--recursica_ui-kit_components_assistive-element_properties_text_line-height
|
|
45
|
+
);
|
|
46
|
+
text-decoration: var(
|
|
47
|
+
--recursica_ui-kit_components_assistive-element_properties_text_text-decoration
|
|
48
|
+
);
|
|
49
|
+
text-transform: var(
|
|
50
|
+
--recursica_ui-kit_components_assistive-element_properties_text_text-transform
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
/* Fallback text wrap structures */
|
|
54
|
+
overflow-wrap: break-word;
|
|
55
|
+
white-space: normal;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.iconWrapper {
|
|
59
|
+
flex-shrink: 0 !important; /* Prevent squishing */
|
|
60
|
+
display: flex !important;
|
|
61
|
+
align-items: center !important;
|
|
62
|
+
justify-content: center !important;
|
|
63
|
+
|
|
64
|
+
width: var(
|
|
65
|
+
--recursica_ui-kit_components_assistive-element_properties_icon-size
|
|
66
|
+
) !important;
|
|
67
|
+
height: calc(
|
|
68
|
+
var(
|
|
69
|
+
--recursica_ui-kit_components_assistive-element_properties_text_line-height
|
|
70
|
+
) *
|
|
71
|
+
var(
|
|
72
|
+
--recursica_ui-kit_components_assistive-element_properties_text_font-size
|
|
73
|
+
)
|
|
74
|
+
) !important; /* Forces exact centering bounds within the first text line vertically */
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.iconWrapper svg {
|
|
78
|
+
width: var(
|
|
79
|
+
--recursica_ui-kit_components_assistive-element_properties_icon-size
|
|
80
|
+
) !important;
|
|
81
|
+
height: var(
|
|
82
|
+
--recursica_ui-kit_components_assistive-element_properties_icon-size
|
|
83
|
+
) !important;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/*
|
|
87
|
+
* VARIANT MAPPINGS
|
|
88
|
+
* Inherits colors natively mapped per variant.
|
|
89
|
+
*/
|
|
90
|
+
|
|
91
|
+
.root[data-variant="help"] .textWrapper {
|
|
92
|
+
color: var(
|
|
93
|
+
--recursica_ui-kit_components_assistive-element_variants_types_help_properties_colors_text-color
|
|
94
|
+
) !important;
|
|
95
|
+
}
|
|
96
|
+
.root[data-variant="help"] .iconWrapper svg {
|
|
97
|
+
color: var(
|
|
98
|
+
--recursica_ui-kit_components_assistive-element_variants_types_help_properties_colors_icon-color
|
|
99
|
+
) !important;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.root[data-variant="error"] .textWrapper {
|
|
103
|
+
color: var(
|
|
104
|
+
--recursica_ui-kit_components_assistive-element_variants_types_error_properties_colors_text-color
|
|
105
|
+
) !important;
|
|
106
|
+
}
|
|
107
|
+
.root[data-variant="error"] .iconWrapper svg {
|
|
108
|
+
color: var(
|
|
109
|
+
--recursica_ui-kit_components_assistive-element_variants_types_error_properties_colors_icon-color
|
|
110
|
+
) !important;
|
|
111
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import { AssistiveElement } from "./AssistiveElement";
|
|
3
|
+
import { Layer } from "@recursica/adapter-common";
|
|
4
|
+
import React from "react";
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof AssistiveElement> = {
|
|
7
|
+
title: "UI-Kit/AssistiveElement",
|
|
8
|
+
component: AssistiveElement,
|
|
9
|
+
tags: ["autodocs"],
|
|
10
|
+
parameters: {
|
|
11
|
+
docs: {
|
|
12
|
+
description: {
|
|
13
|
+
component:
|
|
14
|
+
"The `AssistiveElement` is a semantic structural primitive designed to standardize Helper and Error descriptive blocks natively beneath form components globally. By explicitly wiring to the `--recursica_ui-kit_components_assistive-element` layout tokens, this component safely injects custom SVGs (Alerts vs Info circles) alongside constrained flex-wrapping typography strings, preserving flawless line-height and alignment logic entirely decoupled from underlying input engine frameworks.",
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
argTypes: {
|
|
19
|
+
assistiveVariant: {
|
|
20
|
+
control: "radio",
|
|
21
|
+
options: ["help", "error"],
|
|
22
|
+
},
|
|
23
|
+
assistiveWithIcon: {
|
|
24
|
+
control: "boolean",
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export default meta;
|
|
30
|
+
|
|
31
|
+
type Story = StoryObj<typeof AssistiveElement>;
|
|
32
|
+
|
|
33
|
+
export const DefaultHelp: Story = {
|
|
34
|
+
args: {
|
|
35
|
+
children:
|
|
36
|
+
"This is a standard assistive layout explaining specific configurations.",
|
|
37
|
+
assistiveVariant: "help",
|
|
38
|
+
assistiveWithIcon: true,
|
|
39
|
+
},
|
|
40
|
+
render: (args) => (
|
|
41
|
+
<Layer layer={0} style={{ padding: "48px" }}>
|
|
42
|
+
<AssistiveElement {...args} />
|
|
43
|
+
</Layer>
|
|
44
|
+
),
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const ErrorState: Story = {
|
|
48
|
+
args: {
|
|
49
|
+
children:
|
|
50
|
+
"Invalid property. You must satisfy the constraints outlined above.",
|
|
51
|
+
assistiveVariant: "error",
|
|
52
|
+
assistiveWithIcon: true,
|
|
53
|
+
},
|
|
54
|
+
render: (args) => (
|
|
55
|
+
<Layer layer={0} style={{ padding: "48px" }}>
|
|
56
|
+
<AssistiveElement {...args} />
|
|
57
|
+
</Layer>
|
|
58
|
+
),
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export const NoIconHelp: Story = {
|
|
62
|
+
args: {
|
|
63
|
+
children:
|
|
64
|
+
"Fallback textual representation without visual injection targets.",
|
|
65
|
+
assistiveVariant: "help",
|
|
66
|
+
assistiveWithIcon: false,
|
|
67
|
+
},
|
|
68
|
+
render: (args) => (
|
|
69
|
+
<Layer layer={0} style={{ padding: "48px" }}>
|
|
70
|
+
<AssistiveElement {...args} />
|
|
71
|
+
</Layer>
|
|
72
|
+
),
|
|
73
|
+
};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import React, { forwardRef } from "react";
|
|
2
|
+
import {
|
|
3
|
+
filterStylingProps,
|
|
4
|
+
type RecursicaOverStyled,
|
|
5
|
+
} from "../../utils/filterStylingProps";
|
|
6
|
+
import styles from "./AssistiveElement.module.css";
|
|
7
|
+
|
|
8
|
+
export interface RecursicaAssistiveElementProps {
|
|
9
|
+
/** The semantic variant driving the icon and text colors natively mapped across the UI Kit tokens. */
|
|
10
|
+
assistiveVariant?: "help" | "error";
|
|
11
|
+
/** Explicitly toggle the rendering of the variant-specific SVG bounding box. */
|
|
12
|
+
assistiveWithIcon?: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type AssistiveElementProps = RecursicaOverStyled<
|
|
16
|
+
React.HTMLAttributes<HTMLDivElement> & RecursicaAssistiveElementProps
|
|
17
|
+
>;
|
|
18
|
+
|
|
19
|
+
const InfoIcon = () => (
|
|
20
|
+
<svg
|
|
21
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
22
|
+
viewBox="0 0 24 24"
|
|
23
|
+
fill="none"
|
|
24
|
+
stroke="currentColor"
|
|
25
|
+
strokeWidth="2"
|
|
26
|
+
strokeLinecap="round"
|
|
27
|
+
strokeLinejoin="round"
|
|
28
|
+
>
|
|
29
|
+
<circle cx="12" cy="12" r="10" />
|
|
30
|
+
<path d="M12 16v-4" />
|
|
31
|
+
<path d="M12 8h.01" />
|
|
32
|
+
</svg>
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
const AlertIcon = () => (
|
|
36
|
+
<svg
|
|
37
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
38
|
+
viewBox="0 0 24 24"
|
|
39
|
+
fill="none"
|
|
40
|
+
stroke="currentColor"
|
|
41
|
+
strokeWidth="2"
|
|
42
|
+
strokeLinecap="round"
|
|
43
|
+
strokeLinejoin="round"
|
|
44
|
+
>
|
|
45
|
+
<path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z" />
|
|
46
|
+
<path d="M12 9v4" />
|
|
47
|
+
<path d="M12 17h.01" />
|
|
48
|
+
</svg>
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
export const AssistiveElement = forwardRef<
|
|
52
|
+
HTMLDivElement,
|
|
53
|
+
AssistiveElementProps
|
|
54
|
+
>(function AssistiveElement(
|
|
55
|
+
{
|
|
56
|
+
assistiveVariant = "help",
|
|
57
|
+
assistiveWithIcon = true,
|
|
58
|
+
children,
|
|
59
|
+
className,
|
|
60
|
+
overStyled = false,
|
|
61
|
+
...rest
|
|
62
|
+
},
|
|
63
|
+
ref,
|
|
64
|
+
) {
|
|
65
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
66
|
+
const restRecord = sanitizedProps as Record<string, unknown>;
|
|
67
|
+
|
|
68
|
+
const rootClass = styles.root;
|
|
69
|
+
const finalClass = className ? `${rootClass} ${className}` : rootClass;
|
|
70
|
+
|
|
71
|
+
const IconComponent = assistiveVariant === "error" ? AlertIcon : InfoIcon;
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
<div
|
|
75
|
+
ref={ref}
|
|
76
|
+
className={finalClass}
|
|
77
|
+
data-variant={assistiveVariant}
|
|
78
|
+
style={restRecord.style as React.CSSProperties}
|
|
79
|
+
{...restRecord} // Spread standard HTML attributes (like id, aria-*, role) natively.
|
|
80
|
+
>
|
|
81
|
+
{assistiveWithIcon && (
|
|
82
|
+
<span className={styles.iconWrapper}>
|
|
83
|
+
<IconComponent />
|
|
84
|
+
</span>
|
|
85
|
+
)}
|
|
86
|
+
<span className={styles.textWrapper}>{children}</span>
|
|
87
|
+
</div>
|
|
88
|
+
);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
AssistiveElement.displayName = "AssistiveElement";
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Avatar Component Implementation Notes
|
|
2
|
+
|
|
3
|
+
## Architecture Decisions
|
|
4
|
+
|
|
5
|
+
The `Avatar` component is an adapter over Mantine's `Avatar`. To ensure adherence to the `COMPONENT_GUIDE_WALKTHROUGH.md`:
|
|
6
|
+
|
|
7
|
+
- We do not wrap `MantineAvatar` in any custom standard `div` elements, preserving DOM structure.
|
|
8
|
+
- All styles strictly pull from explicit `--recursica_ui-kit_components_avatar_*` CSS tokens.
|
|
9
|
+
|
|
10
|
+
## Structural Workarounds
|
|
11
|
+
|
|
12
|
+
### Implicit `data-style`
|
|
13
|
+
|
|
14
|
+
Mantine's Avatar implicitly renders an image, an icon, or a text node based on the properties passed (`src`, `var`, `children`).
|
|
15
|
+
Recursica Tokens split Avatar styling distinctly across three separate categories: `image`, `icon`, and `text`.
|
|
16
|
+
To correctly map these variables, our React component observes standard prop states and manually injects a `data-style="image|icon|text"` onto the root. The `Avatar.module.css` explicitly gates padding and generic sizing modifiers under these `data-style` attributes.
|
|
17
|
+
|
|
18
|
+
### Flex Layout & Internal Spans
|
|
19
|
+
|
|
20
|
+
Since Avatar children (icons or initials) require robust centering that might differ heavily across Recursica size mappings, all child content defaults to being wrapped in `span` elements (either `.textWrapper` or `.iconWrapper`). These spans enforce 100% height and flex formatting independent of the Mantine container constraints.
|
|
21
|
+
|
|
22
|
+
### CSS Reset Hacks
|
|
23
|
+
|
|
24
|
+
Noticeable `/* HARDCODE: ... */` hacks are deployed within `.root` to completely zero-out Mantine's `--avatar-bg` and internal variables statically since Recursica handles background-colors inherently via the CSS variants cascade.
|