@recursica/mantine-adapter 0.42.0 → 0.43.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 +18 -0
- package/dist/index.d.ts +93 -15
- package/dist/mantine-adapter.cjs +2 -2
- package/dist/mantine-adapter.cjs.map +1 -1
- package/dist/mantine-adapter.css +1 -1
- package/dist/mantine-adapter.js +3546 -3250
- package/dist/mantine-adapter.js.map +1 -1
- package/package.json +1 -1
- package/src/GlobalExemptions.modules.css +0 -6
- package/src/components/Accordion/Accordion.module.css +0 -8
- package/src/components/Accordion/Accordion.tsx +32 -33
- package/src/components/AssistiveElement/AssistiveElement.tsx +1 -1
- package/src/components/AutoComplete/AutoComplete.module.css +0 -7
- package/src/components/AutoComplete/AutoComplete.tsx +26 -38
- package/src/components/Avatar/Avatar.module.css +0 -8
- package/src/components/Avatar/Avatar.tsx +22 -23
- package/src/components/Badge/Badge.tsx +12 -18
- package/src/components/Breadcrumb/Breadcrumb.tsx +10 -18
- package/src/components/Button/Button.tsx +31 -30
- package/src/components/Card/Card.tsx +48 -27
- package/src/components/Checkbox/Checkbox.tsx +29 -42
- package/src/components/Checkbox/CheckboxGroup.tsx +12 -5
- package/src/components/Chip/Chip.module.css +0 -16
- package/src/components/Chip/Chip.tsx +34 -27
- package/src/components/DatePicker/DATEPICKER_IMPLEMENTATION_NOTES.md +14 -1
- package/src/components/DatePicker/DatePicker.icons.tsx +27 -0
- package/src/components/DatePicker/DatePicker.module.css +256 -7
- package/src/components/DatePicker/DatePicker.stories.tsx +0 -7
- package/src/components/DatePicker/DatePicker.tsx +68 -33
- package/src/components/DatePicker/USAGE.md +6 -2
- package/src/components/Dropdown/BareDropdown.tsx +25 -13
- package/src/components/Dropdown/Dropdown.module.css +0 -7
- package/src/components/Dropdown/Dropdown.tsx +25 -38
- package/src/components/FileInput/FileInput.module.css +0 -21
- package/src/components/FileInput/FileInput.tsx +1 -1
- package/src/components/FileUpload/FileUpload.module.css +0 -11
- package/src/components/FileUpload/FileUpload.tsx +1 -1
- package/src/components/HoverCard/HoverCard.module.css +1 -7
- package/src/components/HoverCard/HoverCard.tsx +18 -34
- package/src/components/Label/Label.module.css +0 -6
- package/src/components/Label/Label.tsx +20 -21
- package/src/components/Link/Link.module.css +1 -6
- package/src/components/Link/Link.tsx +6 -14
- package/src/components/Loader/Loader.tsx +8 -16
- package/src/components/Menu/Menu.module.css +0 -6
- package/src/components/Menu/Menu.tsx +55 -48
- package/src/components/Modal/Modal.module.css +0 -11
- package/src/components/Modal/Modal.tsx +134 -96
- package/src/components/NumberInput/NumberInput.module.css +0 -7
- package/src/components/NumberInput/NumberInput.tsx +14 -7
- package/src/components/Pagination/Pagination.module.css +0 -81
- package/src/components/Pagination/Pagination.tsx +25 -34
- package/src/components/Panel/Panel.tsx +19 -26
- package/src/components/Popover/Popover.tsx +19 -31
- package/src/components/Radio/Radio.tsx +32 -43
- package/src/components/Radio/RadioGroup.tsx +11 -4
- package/src/components/ReadOnlyField/ReadOnlyField.tsx +1 -1
- package/src/components/ReadOnlyField/ReadOnlyTextField.tsx +1 -1
- package/src/components/ReadOnlyField/WithReadOnlyWrapper.tsx +1 -1
- package/src/components/SegmentedControl/SegmentedControl.module.css +0 -1
- package/src/components/SegmentedControl/SegmentedControl.tsx +29 -33
- package/src/components/Slider/Slider.tsx +30 -43
- package/src/components/Stepper/Stepper.tsx +20 -13
- package/src/components/Switch/Switch.tsx +45 -45
- package/src/components/Switch/SwitchGroup.tsx +11 -4
- package/src/components/Table/Table.tsx +1 -1
- package/src/components/Tabs/Tabs.tsx +13 -6
- package/src/components/Text/Text.tsx +1 -1
- package/src/components/TextArea/TextArea.module.css +0 -7
- package/src/components/TextArea/TextArea.tsx +21 -25
- package/src/components/TextField/TextField.module.css +0 -7
- package/src/components/TextField/TextField.tsx +23 -30
- package/src/components/TimePicker/TimePicker.module.css +0 -16
- package/src/components/TimePicker/TimePicker.tsx +26 -12
- package/src/components/Timeline/Timeline.module.css +0 -6
- package/src/components/Timeline/Timeline.tsx +7 -21
- package/src/components/Timeline/TimelineItem.tsx +14 -26
- package/src/components/Title/Title.tsx +12 -2
- package/src/components/Toast/Toast.module.css +0 -7
- package/src/components/Toast/Toast.tsx +32 -31
- package/src/components/Tooltip/Tooltip.module.css +0 -9
- package/src/components/Tooltip/Tooltip.tsx +18 -34
- package/src/components/TransferList/TransferList.module.css +0 -8
- package/src/components/TransferList/TransferList.tsx +1 -1
- package/src/components/Tree/Tree.tsx +8 -8
- package/src/utils/filterStylingProps.ts +4 -0
|
@@ -7,6 +7,8 @@ import {
|
|
|
7
7
|
} from "@mantine/core";
|
|
8
8
|
import {
|
|
9
9
|
filterStylingProps,
|
|
10
|
+
omitUnsupportedProps,
|
|
11
|
+
mergeClassNames,
|
|
10
12
|
type RecursicaOverStyled,
|
|
11
13
|
} from "../../utils/filterStylingProps";
|
|
12
14
|
import styles from "./Card.module.css";
|
|
@@ -32,11 +34,23 @@ export type CardProps = RecursicaOverStyled<
|
|
|
32
34
|
/**
|
|
33
35
|
* The root Card elevation box. It establishes the global background color, border radius, nested component gap, and outer shadow governed by the current `Layer` context.
|
|
34
36
|
*/
|
|
37
|
+
// Props this component intentionally doesn't support — deleted at runtime so they can't leak
|
|
38
|
+
// through even if a caller forces them via plain JavaScript. `Card.module.css` unconditionally
|
|
39
|
+
// drives these from Recursica UI Kit tokens on `.root`; the native prop is never consulted.
|
|
40
|
+
const UNSUPPORTED_PROPS = [
|
|
41
|
+
"radius", // Border radius is token-driven (`--recursica_..._borders_border-radius`), not caller-set.
|
|
42
|
+
"withBorder", // Border is always applied via tokens on `.root`; not an optional caller toggle.
|
|
43
|
+
"padding", // Padding is token-driven (`--card-padding`), not Mantine's spacing-scale prop.
|
|
44
|
+
] as const satisfies readonly (keyof MantineCardProps)[];
|
|
45
|
+
|
|
35
46
|
const CardBase = forwardRef<HTMLDivElement, CardProps>(function Card(
|
|
36
47
|
{ overStyled = false, ...rest },
|
|
37
48
|
ref,
|
|
38
49
|
) {
|
|
39
|
-
const sanitizedProps =
|
|
50
|
+
const sanitizedProps = omitUnsupportedProps(
|
|
51
|
+
filterStylingProps(rest, overStyled),
|
|
52
|
+
UNSUPPORTED_PROPS,
|
|
53
|
+
);
|
|
40
54
|
|
|
41
55
|
// Expose outer layout/flexbox properties on Card to allow structuring alongside siblings
|
|
42
56
|
const safeCardLayoutKeys = [
|
|
@@ -56,25 +70,14 @@ const CardBase = forwardRef<HTMLDivElement, CardProps>(function Card(
|
|
|
56
70
|
}
|
|
57
71
|
});
|
|
58
72
|
|
|
59
|
-
const mergedClassNames
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
!Array.isArray(classNamesProp)
|
|
68
|
-
) {
|
|
69
|
-
const o = classNamesProp as Record<string, string>;
|
|
70
|
-
Object.keys(o).forEach((key) => {
|
|
71
|
-
if (mergedClassNames[key]) {
|
|
72
|
-
mergedClassNames[key] = `${mergedClassNames[key]} ${o[key]}`;
|
|
73
|
-
} else {
|
|
74
|
-
mergedClassNames[key] = o[key];
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
}
|
|
73
|
+
const mergedClassNames = mergeClassNames(
|
|
74
|
+
{
|
|
75
|
+
root: styles.root,
|
|
76
|
+
},
|
|
77
|
+
(sanitizedProps as Record<string, unknown>).classNames as
|
|
78
|
+
| Partial<Record<string, string>>
|
|
79
|
+
| undefined,
|
|
80
|
+
);
|
|
78
81
|
|
|
79
82
|
const classNameProp = (sanitizedProps as Record<string, unknown>)
|
|
80
83
|
.className as string | undefined;
|
|
@@ -82,9 +85,9 @@ const CardBase = forwardRef<HTMLDivElement, CardProps>(function Card(
|
|
|
82
85
|
return (
|
|
83
86
|
<MantineCard
|
|
84
87
|
ref={ref}
|
|
88
|
+
{...(sanitizedProps as unknown as MantineCardProps)}
|
|
85
89
|
className={classNameProp}
|
|
86
90
|
classNames={mergedClassNames}
|
|
87
|
-
{...(sanitizedProps as unknown as MantineCardProps)}
|
|
88
91
|
/>
|
|
89
92
|
);
|
|
90
93
|
});
|
|
@@ -106,10 +109,10 @@ export const CardSection = forwardRef<HTMLDivElement, CardSectionProps>(
|
|
|
106
109
|
return (
|
|
107
110
|
<MantineCard.Section
|
|
108
111
|
ref={ref}
|
|
112
|
+
{...(sanitizedProps as unknown as MantineCardSectionProps)}
|
|
109
113
|
className={
|
|
110
114
|
classNameProp ? `${styles.section} ${classNameProp}` : styles.section
|
|
111
115
|
}
|
|
112
|
-
{...(sanitizedProps as unknown as MantineCardSectionProps)}
|
|
113
116
|
/>
|
|
114
117
|
);
|
|
115
118
|
},
|
|
@@ -122,19 +125,32 @@ export type CardHeaderProps = RecursicaOverStyled<RecursicaCardSectionProps>;
|
|
|
122
125
|
/**
|
|
123
126
|
* Replaces standard generic Mantine `<Card.Section>` wrappers by directly injecting the strict Recursica design tokens for header sizing, background drops, and intrinsic padding limits.
|
|
124
127
|
*/
|
|
128
|
+
// Props this component intentionally doesn't support — deleted at runtime so they can't leak
|
|
129
|
+
// through even if a caller forces them via plain JavaScript. `CardHeaderProps` already omits all
|
|
130
|
+
// native Mantine section props from the public type, but that alone doesn't stop a forced-typed
|
|
131
|
+
// caller from smuggling one through `...rest`; `.header` in Card.module.css unconditionally
|
|
132
|
+
// drives background/padding/border from Recursica tokens, so these native toggles are meaningless.
|
|
133
|
+
const HEADER_FOOTER_UNSUPPORTED_PROPS = [
|
|
134
|
+
"withBorder", // The divider border is always applied via tokens on `.header`/`.footer`.
|
|
135
|
+
"inheritPadding", // Padding is fixed by the `.header`/`.footer` token-driven padding, not Mantine's default.
|
|
136
|
+
] as const satisfies readonly (keyof MantineCardSectionProps)[];
|
|
137
|
+
|
|
125
138
|
export const CardHeader = forwardRef<HTMLDivElement, CardHeaderProps>(
|
|
126
139
|
function CardHeader({ overStyled = false, ...rest }, ref) {
|
|
127
|
-
const sanitizedProps =
|
|
140
|
+
const sanitizedProps = omitUnsupportedProps(
|
|
141
|
+
filterStylingProps(rest, overStyled),
|
|
142
|
+
HEADER_FOOTER_UNSUPPORTED_PROPS,
|
|
143
|
+
);
|
|
128
144
|
const classNameProp = (sanitizedProps as Record<string, unknown>)
|
|
129
145
|
.className as string | undefined;
|
|
130
146
|
|
|
131
147
|
return (
|
|
132
148
|
<MantineCard.Section
|
|
133
149
|
ref={ref}
|
|
150
|
+
{...(sanitizedProps as unknown as MantineCardSectionProps)}
|
|
134
151
|
className={
|
|
135
152
|
classNameProp ? `${styles.header} ${classNameProp}` : styles.header
|
|
136
153
|
}
|
|
137
|
-
{...(sanitizedProps as unknown as MantineCardSectionProps)}
|
|
138
154
|
/>
|
|
139
155
|
);
|
|
140
156
|
},
|
|
@@ -149,17 +165,22 @@ export type CardFooterProps = RecursicaOverStyled<RecursicaCardSectionProps>;
|
|
|
149
165
|
*/
|
|
150
166
|
export const CardFooter = forwardRef<HTMLDivElement, CardFooterProps>(
|
|
151
167
|
function CardFooter({ overStyled = false, ...rest }, ref) {
|
|
152
|
-
|
|
168
|
+
// Reuses HEADER_FOOTER_UNSUPPORTED_PROPS (declared above with CardHeader) — same rationale
|
|
169
|
+
// applies: `.footer` in Card.module.css unconditionally drives padding/border from tokens.
|
|
170
|
+
const sanitizedProps = omitUnsupportedProps(
|
|
171
|
+
filterStylingProps(rest, overStyled),
|
|
172
|
+
HEADER_FOOTER_UNSUPPORTED_PROPS,
|
|
173
|
+
);
|
|
153
174
|
const classNameProp = (sanitizedProps as Record<string, unknown>)
|
|
154
175
|
.className as string | undefined;
|
|
155
176
|
|
|
156
177
|
return (
|
|
157
178
|
<MantineCard.Section
|
|
158
179
|
ref={ref}
|
|
180
|
+
{...(sanitizedProps as unknown as MantineCardSectionProps)}
|
|
159
181
|
className={
|
|
160
182
|
classNameProp ? `${styles.footer} ${classNameProp}` : styles.footer
|
|
161
183
|
}
|
|
162
|
-
{...(sanitizedProps as unknown as MantineCardSectionProps)}
|
|
163
184
|
/>
|
|
164
185
|
);
|
|
165
186
|
},
|
|
@@ -183,10 +204,10 @@ export const CardContent = forwardRef<HTMLDivElement, CardContentProps>(
|
|
|
183
204
|
return (
|
|
184
205
|
<div
|
|
185
206
|
ref={ref}
|
|
207
|
+
{...sanitizedProps}
|
|
186
208
|
className={
|
|
187
209
|
classNameProp ? `${styles.content} ${classNameProp}` : styles.content
|
|
188
210
|
}
|
|
189
|
-
{...sanitizedProps}
|
|
190
211
|
/>
|
|
191
212
|
);
|
|
192
213
|
},
|
|
@@ -7,6 +7,8 @@ import { type ReadOnlyControlProps } from "@recursica/adapter-common";
|
|
|
7
7
|
import { CheckboxGroup } from "./CheckboxGroup";
|
|
8
8
|
import {
|
|
9
9
|
filterStylingProps,
|
|
10
|
+
omitUnsupportedProps,
|
|
11
|
+
mergeClassNames,
|
|
10
12
|
type RecursicaOverStyled,
|
|
11
13
|
} from "../../utils/filterStylingProps";
|
|
12
14
|
import {
|
|
@@ -56,49 +58,34 @@ export const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
|
|
|
56
58
|
...rest
|
|
57
59
|
} = props;
|
|
58
60
|
// Checkbox doesn't use Label onLabelEditClick natively since it isn't mapped inside FormControlWrapper intrinsically.
|
|
59
|
-
|
|
61
|
+
// Props this component intentionally doesn't support — deleted at runtime so they can't leak
|
|
62
|
+
// through even if a caller forces them via plain JavaScript, bypassing the `Omit<>` above.
|
|
63
|
+
const UNSUPPORTED_PROPS = [
|
|
64
|
+
"size", // Recursica controls sizing via Checkbox.module.css variables, not Mantine's native size scale.
|
|
65
|
+
"color", // Colors are token-driven via Checkbox.module.css; Mantine's native palette isn't exposed.
|
|
66
|
+
"radius", // Corner radius is fixed by Recursica tokens in Checkbox.module.css, not caller-configurable.
|
|
67
|
+
"variant", // Checkbox has a single Recursica-defined visual treatment; Mantine's variant isn't exposed.
|
|
68
|
+
"iconColor", // Icon color is token-driven via Checkbox.module.css, not a native Mantine override.
|
|
69
|
+
] as const satisfies readonly (keyof MantineCheckboxProps)[];
|
|
70
|
+
|
|
71
|
+
const sanitizedProps = omitUnsupportedProps(
|
|
72
|
+
filterStylingProps(rest, overStyled) as Record<string, unknown>,
|
|
73
|
+
UNSUPPORTED_PROPS,
|
|
74
|
+
) as Partial<typeof rest>;
|
|
60
75
|
const restRecord = sanitizedProps as Record<string, unknown>;
|
|
61
76
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
icon: styles.icon,
|
|
75
|
-
labelWrapper: styles.labelWrapper,
|
|
76
|
-
label: styles.label,
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
const classNamesProp = restRecord.classNames;
|
|
80
|
-
if (
|
|
81
|
-
classNamesProp &&
|
|
82
|
-
typeof classNamesProp === "object" &&
|
|
83
|
-
!Array.isArray(classNamesProp)
|
|
84
|
-
) {
|
|
85
|
-
const o = classNamesProp as Partial<Record<string, string>>;
|
|
86
|
-
mergedClassNames.root = o.root ? `${styles.root} ${o.root}` : styles.root;
|
|
87
|
-
mergedClassNames.body = o.body ? `${styles.body} ${o.body}` : styles.body;
|
|
88
|
-
mergedClassNames.inner = o.inner
|
|
89
|
-
? `${styles.inner} ${o.inner}`
|
|
90
|
-
: styles.inner;
|
|
91
|
-
mergedClassNames.input = o.input
|
|
92
|
-
? `${styles.input} ${o.input}`
|
|
93
|
-
: styles.input;
|
|
94
|
-
mergedClassNames.icon = o.icon ? `${styles.icon} ${o.icon}` : styles.icon;
|
|
95
|
-
mergedClassNames.labelWrapper = o.labelWrapper
|
|
96
|
-
? `${styles.labelWrapper} ${o.labelWrapper}`
|
|
97
|
-
: styles.labelWrapper;
|
|
98
|
-
mergedClassNames.label = o.label
|
|
99
|
-
? `${styles.label} ${o.label}`
|
|
100
|
-
: styles.label;
|
|
101
|
-
}
|
|
77
|
+
const mergedClassNames = mergeClassNames(
|
|
78
|
+
{
|
|
79
|
+
root: styles.root,
|
|
80
|
+
body: styles.body,
|
|
81
|
+
inner: styles.inner,
|
|
82
|
+
input: styles.input,
|
|
83
|
+
icon: styles.icon,
|
|
84
|
+
labelWrapper: styles.labelWrapper,
|
|
85
|
+
label: styles.label,
|
|
86
|
+
},
|
|
87
|
+
restRecord.classNames as Partial<Record<string, string>> | undefined,
|
|
88
|
+
);
|
|
102
89
|
|
|
103
90
|
const classNameProp = restRecord.className as string | undefined;
|
|
104
91
|
const finalClass = classNameProp
|
|
@@ -136,10 +123,10 @@ export const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
|
|
|
136
123
|
const checkboxNode = (
|
|
137
124
|
<MantineCheckbox
|
|
138
125
|
ref={ref}
|
|
126
|
+
{...(sanitizedProps as unknown as MantineCheckboxProps)}
|
|
139
127
|
className={finalClass}
|
|
140
128
|
classNames={mergedClassNames}
|
|
141
129
|
disabled={readOnly || disabled}
|
|
142
|
-
{...(sanitizedProps as unknown as MantineCheckboxProps)}
|
|
143
130
|
/>
|
|
144
131
|
);
|
|
145
132
|
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
import { type ReadOnlyControlProps } from "@recursica/adapter-common";
|
|
8
8
|
import {
|
|
9
9
|
filterStylingProps,
|
|
10
|
+
omitUnsupportedProps,
|
|
10
11
|
type RecursicaOverStyled,
|
|
11
12
|
} from "../../utils/filterStylingProps";
|
|
12
13
|
import { type RecursicaFormControlWrapperProps } from "../FormControlWrapper/FormControlWrapper";
|
|
@@ -62,11 +63,17 @@ export const CheckboxGroup = forwardRef<HTMLDivElement, CheckboxGroupProps>(
|
|
|
62
63
|
defaultValue,
|
|
63
64
|
...rest
|
|
64
65
|
} = props;
|
|
65
|
-
|
|
66
|
-
|
|
66
|
+
// Props this component intentionally doesn't support — deleted at runtime so they can't leak
|
|
67
|
+
// through even if a caller forces them via plain JavaScript, bypassing the `Omit<>` above.
|
|
68
|
+
const UNSUPPORTED_PROPS = [
|
|
69
|
+
"size", // Recursica controls sizing via Checkbox.module.css variables, not Mantine's native size scale.
|
|
70
|
+
] as const satisfies readonly (keyof MantineCheckboxGroupProps)[];
|
|
67
71
|
|
|
68
|
-
|
|
69
|
-
|
|
72
|
+
const sanitizedProps = omitUnsupportedProps(
|
|
73
|
+
filterStylingProps(rest, overStyled) as Record<string, unknown>,
|
|
74
|
+
UNSUPPORTED_PROPS,
|
|
75
|
+
) as Partial<typeof rest>;
|
|
76
|
+
const restRecord = sanitizedProps as Record<string, unknown>;
|
|
70
77
|
|
|
71
78
|
// Mantine's own `Checkbox.Group` always establishes a context whose `value` defaults to
|
|
72
79
|
// `[]` (see @mantine/core's `useUncontrolled({ finalValue: [] })`), and its `Checkbox` spreads
|
|
@@ -123,8 +130,8 @@ export const CheckboxGroup = forwardRef<HTMLDivElement, CheckboxGroupProps>(
|
|
|
123
130
|
) : (
|
|
124
131
|
<div
|
|
125
132
|
ref={ref}
|
|
126
|
-
role="group"
|
|
127
133
|
{...(sanitizedProps as Record<string, unknown>)}
|
|
134
|
+
role="group"
|
|
128
135
|
className={styles.groupRoot}
|
|
129
136
|
data-layout={formLayout}
|
|
130
137
|
>
|
|
@@ -1,19 +1,3 @@
|
|
|
1
|
-
/* EXEMPTIONS:
|
|
2
|
-
- close-icon-color, leading-icon-color, and select-specific state icon variables are ignored because
|
|
3
|
-
Chip uses explicit state color definitions (e.g. unselected, selected, error, error-selected variant colors)
|
|
4
|
-
to drive pixel-perfect hover and click transitions, rather than generic single-color overrides.
|
|
5
|
-
- text-size is ignored since actual chip sizing is dynamically driven by precise vertical padding and line-heights. */
|
|
6
|
-
/* recursica-ignore: --recursica_ui-kit_components_chip_properties_close-icon-color */
|
|
7
|
-
/* recursica-ignore: --recursica_ui-kit_components_chip_properties_leading-icon-color */
|
|
8
|
-
/* recursica-ignore: --recursica_ui-kit_components_chip_properties_text-size */
|
|
9
|
-
/* recursica-ignore: --recursica_ui-kit_components_chip_variants_selection-states_unselected_variants_states_error_properties_colors_leading-icon-color */
|
|
10
|
-
/* recursica-ignore: --recursica_ui-kit_components_chip_variants_selection-states_unselected_variants_states_error_properties_colors_selected-icon-color */
|
|
11
|
-
/* recursica-ignore: --recursica_ui-kit_components_chip_variants_selection-states_unselected_variants_states_error_properties_colors_icon-color */
|
|
12
|
-
/* recursica-ignore: --recursica_ui-kit_components_chip_variants_selection-states_selected_variants_states_error_properties_colors_icon-color */
|
|
13
|
-
/* recursica-ignore: --recursica_ui-kit_components_chip_variants_selection-states_selected_variants_states_error_properties_colors_leading-icon-color */
|
|
14
|
-
/* recursica-ignore: --recursica_ui-kit_components_chip_variants_selection-states_selected_properties_colors_leading-icon-color */
|
|
15
|
-
/* recursica-ignore: --recursica_ui-kit_components_chip_variants_selection-states_unselected_properties_colors_selected-icon-color */
|
|
16
|
-
|
|
17
1
|
/* HARDCODED VALUES
|
|
18
2
|
border-style: solid; (Baseline reset)
|
|
19
3
|
box-sizing: border-box; (Baseline reset)
|
|
@@ -5,6 +5,8 @@ import {
|
|
|
5
5
|
} from "@mantine/core";
|
|
6
6
|
import {
|
|
7
7
|
filterStylingProps,
|
|
8
|
+
mergeClassNames,
|
|
9
|
+
withCallerOverride,
|
|
8
10
|
type RecursicaOverStyled,
|
|
9
11
|
} from "../../utils/filterStylingProps";
|
|
10
12
|
import styles from "./Chip.module.css";
|
|
@@ -45,6 +47,9 @@ export const Chip = forwardRef<HTMLInputElement, ChipProps>(function Chip(
|
|
|
45
47
|
removeIconRef,
|
|
46
48
|
children,
|
|
47
49
|
overStyled = false,
|
|
50
|
+
wrapperProps,
|
|
51
|
+
tabIndex,
|
|
52
|
+
"aria-hidden": ariaHidden,
|
|
48
53
|
...rest
|
|
49
54
|
},
|
|
50
55
|
ref,
|
|
@@ -52,26 +57,16 @@ export const Chip = forwardRef<HTMLInputElement, ChipProps>(function Chip(
|
|
|
52
57
|
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
53
58
|
const restRecord = sanitizedProps as Record<string, unknown>;
|
|
54
59
|
|
|
55
|
-
const mergedClassNames
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
classNamesProp &&
|
|
66
|
-
typeof classNamesProp === "object" &&
|
|
67
|
-
!Array.isArray(classNamesProp)
|
|
68
|
-
) {
|
|
69
|
-
const o = classNamesProp as Partial<Record<string, string>>;
|
|
70
|
-
mergedClassNames.root = o.root ? `${styles.root} ${o.root}` : styles.root;
|
|
71
|
-
mergedClassNames.label = o.label
|
|
72
|
-
? `${styles.label} ${o.label}`
|
|
73
|
-
: styles.label;
|
|
74
|
-
}
|
|
60
|
+
const mergedClassNames = mergeClassNames(
|
|
61
|
+
{
|
|
62
|
+
root: styles.root,
|
|
63
|
+
label: styles.label,
|
|
64
|
+
input: styles.input,
|
|
65
|
+
iconWrapper: styles.mantineIconWrapper,
|
|
66
|
+
checkIcon: styles.checkIcon,
|
|
67
|
+
},
|
|
68
|
+
restRecord.classNames as Partial<Record<string, string>> | undefined,
|
|
69
|
+
);
|
|
75
70
|
|
|
76
71
|
const classNameProp = restRecord.className as string | undefined;
|
|
77
72
|
const finalClass = classNameProp
|
|
@@ -90,18 +85,30 @@ export const Chip = forwardRef<HTMLInputElement, ChipProps>(function Chip(
|
|
|
90
85
|
restRecord.onClick !== undefined ||
|
|
91
86
|
restRecord.onChange !== undefined;
|
|
92
87
|
|
|
88
|
+
// Our own computed default for Mantine's `wrapperProps` — flags the internal error/interactive
|
|
89
|
+
// CSS hooks. This is a real Mantine `ChipProps` slot a caller could legitimately pass their own
|
|
90
|
+
// value for, so it must merge via `withCallerOverride`, not silently clobber theirs.
|
|
91
|
+
const computedWrapperProps = {
|
|
92
|
+
...(dataError !== undefined ? { "data-error": "" } : {}),
|
|
93
|
+
...(isInteractive ? { "data-interactive": "" } : {}),
|
|
94
|
+
} as NonNullable<MantineChipProps["wrapperProps"]>;
|
|
95
|
+
|
|
93
96
|
return (
|
|
94
97
|
<MantineChip
|
|
95
98
|
ref={ref}
|
|
99
|
+
{...sanitizedProps}
|
|
96
100
|
className={finalClass}
|
|
97
101
|
classNames={mergedClassNames}
|
|
98
|
-
wrapperProps={
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
{
|
|
102
|
+
wrapperProps={withCallerOverride(computedWrapperProps, wrapperProps)}
|
|
103
|
+
data-icon-only={isIconOnly ? "" : undefined}
|
|
104
|
+
tabIndex={withCallerOverride<number | undefined>(
|
|
105
|
+
isInteractive ? undefined : -1,
|
|
106
|
+
tabIndex,
|
|
107
|
+
)}
|
|
108
|
+
aria-hidden={withCallerOverride<boolean | "true" | "false" | undefined>(
|
|
109
|
+
isInteractive ? undefined : true,
|
|
110
|
+
ariaHidden,
|
|
111
|
+
)}
|
|
105
112
|
>
|
|
106
113
|
<span className={styles.innerWrapper}>
|
|
107
114
|
{icon && (
|
|
@@ -8,9 +8,22 @@ The `DatePicker` component is a wrapper around the `@mantine/dates` `DatePickerI
|
|
|
8
8
|
|
|
9
9
|
1. **Naked Input Usage**: We intentionally pass `label={undefined}`, `description={undefined}`, and `error={undefined}` to the Mantine `DatePickerInput` component. This suppresses Mantine's internal macro form wrapping and ensures that only our `WithReadOnlyWrapper` > `FormControlWrapper` orchestrates labels, description text, and ARIA state error boundaries.
|
|
10
10
|
2. **Read-Only Implementation**: Since the value type for `DatePickerInput` can be a date object, string, or array, the `WithReadOnlyWrapper` attempts to safely cast the output value using standard `String(value)`. For production apps utilizing heavy date formatting logic, developers can pass a custom `readOnlyComponent` explicitly to bypass this default cast.
|
|
11
|
-
3. **Calendar Portal/Dropdown (Figma Token Issue)**: The Recursica UI Kit's `date-picker` component in Figma fails to export any explicit structural or color properties for the calendar popover itself (e.g. elevation, surface background, selected day colors). To solve this organically within the framework without breaking strict token adherence, we manually
|
|
11
|
+
3. **Calendar Portal/Dropdown (Figma Token Issue)**: The Recursica UI Kit's `date-picker` component in Figma fails to export any explicit structural or color properties for the calendar popover itself (e.g. elevation, surface background, selected day colors, hover, today, in-range). To solve this organically within the framework without breaking strict token adherence, we manually map every calendar state to the closest existing Recursica token instead of leaving any of it on Mantine's own un-tokenized defaults:
|
|
12
|
+
- **Surface** (`.dropdown`) & **selected day** (`.day[data-selected]`): `--recursica_ui-kit_components_hover-card-popover` tokens for elevation/padding/surface, `--recursica_ui-kit_components_button_variants_styles_solid` tokens for the selected day fill (unchanged from before).
|
|
13
|
+
- **Header content, weekday row** (`.calendarHeader`, `.weekday`): the hover-card-popover content-color token — previously unmapped, so these leaked Mantine's own text colors.
|
|
14
|
+
- **Header nav controls & month/year label** (`.calendarHeaderControl`, `.calendarHeaderLevel`, `.calendarHeaderControlIcon`): these are functionally buttons, so they're now styled with `--recursica_ui-kit_components_button_variants_styles_text` tokens (border/background/color/elevation) plus small-size `Button` sizing tokens (height, icon-only vs. label-content border-radius/padding/min-width, icon size, typography) — the same tokens `Button`'s `data-variant="text"` uses. Disabled opacity/elevation and the focus-visible ring also mirror `Button`'s own treatment instead of the generic brand tokens used elsewhere in this file.
|
|
15
|
+
- **Hover** (any day cell, header nav, header level button): the generic `--recursica_brand_states_hover_color`/`_hover_opacity` pair, via the same `::after`-overlay technique used by `Button`/`Menu` — the standard convention for components with no dedicated hover token. Unlike `Button`, the day number is a bare text node with no wrapping span to `z-index` above the overlay, so here the overlay sits at `z-index: -1` instead of the text getting `z-index: 1` — same visual effect, opposite side of the layering. Also unlike `Button` (a plain button with no library-native hover CSS), Mantine's `Day`/`CalendarHeaderControl`/`CalendarHeaderLevel` all ship their own native `:hover { background-color: ... }` rule — an explicit `background-color: transparent` reset on `:hover` was needed first, or the overlay would just layer on top of Mantine's own gray-0/dark-5 fill instead of replacing it. (Caught in review: the first pass added the overlay without this reset, and the visible hover color was indistinguishable from Mantine's plain default — confirmed via computed-style diffing, not just eyeballing the screenshot.)
|
|
16
|
+
- **Disabled / outside-month days**: the generic `--recursica_brand_states_disabled` opacity token — the same one used repo-wide (Button, Chip, Tree, Pagination, Accordion) for elements with no dedicated disabled token. **Disabled header nav/label controls** use `Button`'s own text-variant disabled opacity/elevation tokens instead, since they're now styled as `Button`.
|
|
17
|
+
- **Today marker**: no dedicated token exists, so it reuses the hover-card-popover border-size/color tokens already used for the dropdown surface's own border (previously hardcoded `1px`). `highlightToday` is now defaulted to `true` in `DatePicker.tsx` (Mantine ships it `false`, meaning today was never marked at all before this pass).
|
|
18
|
+
- **Weekend days**: Mantine's default colors these red; the UI Kit has no such concept, so weekend text is explicitly forced back to the same color as any other day rather than left on that unrelated default.
|
|
19
|
+
- **Range selection** (`.day[data-in-range]`/`[data-first-in-range]`/`[data-last-in-range]`): styled with the generic `--recursica_brand_states_overlay_color`/`_overlay_opacity` pair — previously unused anywhere in the codebase, but its name and shape (a translucent tint token) is exactly this use case. **Not currently reachable through our public API**: `RecursicaDatePickerProps` doesn't discriminate on `type`, so `value`/`defaultValue` are typed for single-date selection only — `type="range"` fails typecheck for consumers. This CSS is forward-compatible groundwork, not a demoed feature; proper range-mode typing would be a separate, larger follow-up. Also flagged as a judgment call on the token pairing itself: first usage anywhere, no prior precedent or design-team confirmation.
|
|
12
20
|
|
|
13
21
|
## Styling Quirks
|
|
14
22
|
|
|
15
23
|
- The `DatePickerInput` mimics Mantine's `Input` structure natively (`.input`, `.wrapper`, `.section`). We attach our `styles.input` and `styles.root` classes exactly like `TextField`.
|
|
16
24
|
- The global layout margin override (`.layoutOverride`) utilizes `--form-control-margin-bottom` driven by specific stacked/side-by-side design tokens.
|
|
25
|
+
- **Popover `classNames` gotcha (bug fix)**: `.dropdown` was previously passed via the top-level `classNames` prop alongside `wrapper`/`input`/`section`/`day`/etc., which silently did nothing — the calendar surface is rendered by Mantine's internal `Popover`, whose style API is a separate namespace only reachable via `popoverProps.classNames` (`PickerInputBaseProps.popoverProps: Partial<Omit<PopoverProps, 'children'>>`). The `.dropdown` CSS (background/border/border-radius/box-shadow/padding/font-family, matching `Popover`'s own `.dropdown` rules 1:1) was never actually applied until this was fixed — confirmed via computed styles before/after (`box-shadow: none` → the real elevation token). `DatePicker.tsx` now merges any consumer-supplied `popoverProps`/`popoverProps.classNames` with our default instead of overwriting them.
|
|
26
|
+
- **Default value format**: `valueFormat="MM/DD/YY"` (a `dayjs` format string, Mantine's default is `"MMMM D, YYYY"`), set before the `sanitizedProps` spread so consumers can still override via their own `valueFormat` prop.
|
|
27
|
+
- **Default leading icon**: `leftSection={<CalendarIcon />}` (new `DatePicker.icons.tsx`, following the existing local-inline-SVG convention used by `Pagination.icons.tsx` — no icon library is a dependency of either adapter) is set the same way, overridable via `leftSection`.
|
|
28
|
+
- **Default placeholder**: `placeholder="MM / DD / YY"`, set the same way (before `sanitizedProps`, so consumers can override).
|
|
29
|
+
- **Single-line enforcement (bug fix)**: `DatePickerInput` renders its value/placeholder as a `<button>`'s text content, not a native `<input>` — it wraps like any other block text by default. A long placeholder (e.g. the original story's `"Select a deadline..."`) wrapped to two lines, inflating the field's height well past its `min-height` token and making the field visually look narrower than its actual `width` token value even though the box itself was always the right size. Fixed with `white-space: nowrap`/`text-overflow: ellipsis`/`overflow-x: clip`/`overflow-y: visible` on `.input`, the same convention `FileInput.module.css`'s `.value` uses.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Default leading icon for DatePicker's left section. Consumers can override it by passing
|
|
5
|
+
* their own `leftSection` prop (see DatePicker.tsx). Sized/colored entirely via the generic
|
|
6
|
+
* `.section :global(svg)` rule in DatePicker.module.css, same as the icon in the
|
|
7
|
+
* WithLeadingIcon story — no width/height/color hardcoded here on purpose.
|
|
8
|
+
*/
|
|
9
|
+
export function CalendarIcon(props: React.SVGProps<SVGSVGElement>) {
|
|
10
|
+
return (
|
|
11
|
+
<svg
|
|
12
|
+
viewBox="0 0 24 24"
|
|
13
|
+
fill="none"
|
|
14
|
+
stroke="currentColor"
|
|
15
|
+
strokeWidth="2"
|
|
16
|
+
strokeLinecap="round"
|
|
17
|
+
strokeLinejoin="round"
|
|
18
|
+
aria-hidden
|
|
19
|
+
{...props}
|
|
20
|
+
>
|
|
21
|
+
<rect x="3" y="4" width="18" height="18" rx="2" ry="2" />
|
|
22
|
+
<line x1="16" y1="2" x2="16" y2="6" />
|
|
23
|
+
<line x1="8" y1="2" x2="8" y2="6" />
|
|
24
|
+
<line x1="3" y1="10" x2="21" y2="10" />
|
|
25
|
+
</svg>
|
|
26
|
+
);
|
|
27
|
+
}
|