@recursica/mantine-adapter 0.45.0 → 0.47.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 +24 -0
- package/dist/index.d.ts +72 -52
- 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 +1945 -1934
- package/dist/mantine-adapter.js.map +1 -1
- package/package.json +2 -2
- package/src/components/Accordion/Accordion.tsx +1 -1
- package/src/components/Checkbox/CheckboxGroup.tsx +1 -1
- package/src/components/Chip/CHIP_IMPLEMENTATION_NOTES.md +8 -8
- package/src/components/Chip/Chip.module.css +5 -5
- package/src/components/Chip/Chip.stories.tsx +2 -2
- package/src/components/Chip/Chip.tsx +13 -13
- package/src/components/Chip/USAGE.md +2 -2
- package/src/components/Dropdown/Dropdown.module.css +1 -1
- package/src/components/FileInput/FILEINPUT_IMPLEMENTATION_NOTES.md +6 -4
- package/src/components/FileInput/FileInput.stories.tsx +3 -0
- package/src/components/FileInput/FileInput.tsx +11 -10
- package/src/components/FileInput/USAGE.md +1 -0
- package/src/components/FileUpload/FILEUPLOAD_IMPLEMENTATION_NOTES.md +12 -12
- package/src/components/FileUpload/FileUpload.tsx +9 -9
- package/src/components/Radio/RadioGroup.tsx +1 -1
- package/src/components/SegmentedControl/IMPLEMENTATION_NOTES.md +8 -0
- package/src/components/SegmentedControl/SegmentedControl.stories.tsx +17 -28
- package/src/components/SegmentedControl/SegmentedControl.tsx +29 -17
- package/src/components/SegmentedControl/USAGE.md +13 -0
- package/src/components/Slider/IMPLEMENTATION_NOTES.md +13 -0
- package/src/components/Slider/Slider.stories.tsx +44 -0
- package/src/components/Slider/Slider.tsx +23 -4
- package/src/components/Slider/USAGE.md +1 -1
- package/src/components/Switch/SwitchGroup.tsx +1 -1
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
} from "@mantine/core";
|
|
6
6
|
import {
|
|
7
7
|
filterStylingProps,
|
|
8
|
-
omitUnsupportedProps,
|
|
9
8
|
mergeClassNames,
|
|
10
9
|
type RecursicaOverStyled,
|
|
11
10
|
} from "../../utils/filterStylingProps";
|
|
@@ -22,7 +21,7 @@ export type SegmentedControlProps = RecursicaOverStyled<
|
|
|
22
21
|
| "color"
|
|
23
22
|
| "classNames"
|
|
24
23
|
| "className"
|
|
25
|
-
| "
|
|
24
|
+
| "data"
|
|
26
25
|
> & {
|
|
27
26
|
className?: string;
|
|
28
27
|
classNames?: Partial<Record<string, string>>;
|
|
@@ -53,27 +52,39 @@ function useSegmentedControlClassNames(restRecord: Record<string, unknown>): {
|
|
|
53
52
|
|
|
54
53
|
const _SegmentedControl = forwardRef<HTMLDivElement, SegmentedControlProps>(
|
|
55
54
|
function SegmentedControl(
|
|
56
|
-
{
|
|
55
|
+
{
|
|
56
|
+
overStyled = false,
|
|
57
|
+
orientation = "horizontal",
|
|
58
|
+
fullWidth,
|
|
59
|
+
data = [],
|
|
60
|
+
...rest
|
|
61
|
+
},
|
|
57
62
|
ref,
|
|
58
63
|
) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
// SegmentedControl only supports per-item disabling via the `data` array (each item may set
|
|
63
|
-
// its own `disabled`); a top-level `disabled` is intentionally unsupported (typed as `never`
|
|
64
|
-
// in RecursicaSegmentedControlProps) because Mantine's top-level `disabled` would disable
|
|
65
|
-
// the whole control uniformly instead of per-item.
|
|
66
|
-
"disabled",
|
|
67
|
-
] as const satisfies readonly (keyof MantineSegmentedControlProps)[];
|
|
68
|
-
|
|
69
|
-
const sanitizedProps = omitUnsupportedProps(
|
|
70
|
-
filterStylingProps(rest, overStyled) as Record<string, unknown>,
|
|
71
|
-
UNSUPPORTED_PROPS,
|
|
72
|
-
) as Partial<typeof rest>;
|
|
64
|
+
const sanitizedProps = filterStylingProps(rest, overStyled) as Partial<
|
|
65
|
+
typeof rest
|
|
66
|
+
>;
|
|
73
67
|
const restRecord = sanitizedProps as Record<string, unknown>;
|
|
74
68
|
|
|
75
69
|
const stylingParams = useSegmentedControlClassNames(restRecord);
|
|
76
70
|
|
|
71
|
+
// Mantine's own data item has no icon slot; compose one into `label` (already a ReactNode)
|
|
72
|
+
// so Mantine's native innerLabel wrapper lays it out using the icon-size/gap tokens already
|
|
73
|
+
// wired in SegmentedControl.module.css.
|
|
74
|
+
const mappedData = data.map((item) =>
|
|
75
|
+
typeof item === "string" || !item.icon
|
|
76
|
+
? item
|
|
77
|
+
: {
|
|
78
|
+
...item,
|
|
79
|
+
label: (
|
|
80
|
+
<>
|
|
81
|
+
{item.icon}
|
|
82
|
+
{item.label}
|
|
83
|
+
</>
|
|
84
|
+
),
|
|
85
|
+
},
|
|
86
|
+
);
|
|
87
|
+
|
|
77
88
|
return (
|
|
78
89
|
<MantineSegmentedControl
|
|
79
90
|
ref={ref}
|
|
@@ -86,6 +97,7 @@ const _SegmentedControl = forwardRef<HTMLDivElement, SegmentedControlProps>(
|
|
|
86
97
|
orientation={orientation}
|
|
87
98
|
fullWidth={fullWidth}
|
|
88
99
|
data-orientation={orientation}
|
|
100
|
+
data={mappedData}
|
|
89
101
|
/>
|
|
90
102
|
);
|
|
91
103
|
},
|
|
@@ -23,6 +23,17 @@ export default function Demo() {
|
|
|
23
23
|
}
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
+
Each `data` item may also be an object with an optional `icon`, rendered ahead of the label:
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
<SegmentedControl
|
|
30
|
+
data={[
|
|
31
|
+
{ value: "daily", label: "Daily", icon: <CheckIcon /> },
|
|
32
|
+
{ value: "weekly", label: "Weekly" },
|
|
33
|
+
]}
|
|
34
|
+
/>
|
|
35
|
+
```
|
|
36
|
+
|
|
26
37
|
---
|
|
27
38
|
|
|
28
39
|
## 3. Design System Integration
|
|
@@ -40,3 +51,5 @@ All Recursica components in the `@recursica/mantine-adapter` package adhere stri
|
|
|
40
51
|
## 4. Key Integration Features & Constraints
|
|
41
52
|
|
|
42
53
|
The `variant`, `size`, `radius`, and `color` props are not available on this component, since appearance is fully controlled by the design system tokens. The active segment is shown as a floating indicator that moves behind the selected label, with a divider rendered between adjacent segments.
|
|
54
|
+
|
|
55
|
+
A top-level `disabled` disables every item at once; an individual item can still be disabled on its own via `data[].disabled`.
|
|
@@ -57,3 +57,16 @@ This document contains specific design decisions, architectural constraints, and
|
|
|
57
57
|
- The thumb's focus box-shadow layers the ring on top of its existing `thumb-elevation` shadow rather than replacing it.
|
|
58
58
|
- `.sliderMark[data-filled]` has no default-state "-active" step-indicator token anymore (only `disabled`/`error` define one); it reuses `colors_track-active` so filled marks stay visually tied to the filled portion of the track. Worth a design review if a distinct filled-mark color is expected.
|
|
59
59
|
- `markLabel` was already mapped in the `classNames` prop but had no matching `.sliderMarkLabel` rule in this file, so Mantine silently fell back to its own default theme grey instead of any recursica token. Added a `.sliderMarkLabel` rule reusing the min-max-label typography tokens with `color: inherit`, matching the mui-adapter's equivalent.
|
|
60
|
+
|
|
61
|
+
## 7. Formatted Current Value, Label Overrides, Trailing Icon
|
|
62
|
+
|
|
63
|
+
**Decision:** The floating `.currentValue` display (see §5) always rendered the raw numeric value, even when `tooltipLabel` was a formatter function — a caller mapping values onto custom text (e.g. 0-4 → XS/S/M/L/XL) got the formatted tooltip while dragging but the raw number next to the track otherwise.
|
|
64
|
+
**Implementation:**
|
|
65
|
+
|
|
66
|
+
- `.currentValue` now runs `resolvedValue` through `tooltipLabel` when it's a function, so both displays agree. No change when `tooltipLabel` is absent or a static node — still the raw number.
|
|
67
|
+
- `minLabel`/`maxLabel` (new `adapter-common` props) override the `.minMaxGuide` text at either end of the track, falling back to the numeric `min`/`max`.
|
|
68
|
+
- `trailingIcon` (new `adapter-common` prop) renders a second icon on the opposite side of the track from the existing `icon`, reusing the same `.iconWrapper` styling (disabled/error/focus states already target `.iconWrapper` generically, so no new CSS was needed).
|
|
69
|
+
|
|
70
|
+
## 8. No Dual-Thumb / Range Support
|
|
71
|
+
|
|
72
|
+
**Decision:** Requested (a caller passing `[number, number]` for `value`/`onChange`, backed by Mantine's separate `RangeSlider` component), declined — no current use case needs it. `Slider` stays single-thumb only; `value`/`onChange` remain typed as `number`.
|
|
@@ -146,6 +146,50 @@ export const WithMarks: Story = {
|
|
|
146
146
|
},
|
|
147
147
|
};
|
|
148
148
|
|
|
149
|
+
export const WithIconsAndLabels: Story = {
|
|
150
|
+
args: {
|
|
151
|
+
label: "Volume",
|
|
152
|
+
assistiveText:
|
|
153
|
+
"Icons flank the track; min/max labels replace the raw bounds.",
|
|
154
|
+
defaultValue: 60,
|
|
155
|
+
minLabel: "Quiet",
|
|
156
|
+
maxLabel: "Loud",
|
|
157
|
+
tooltipLabel: (value: number) => `${value}%`,
|
|
158
|
+
icon: (
|
|
159
|
+
<svg
|
|
160
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
161
|
+
width="16"
|
|
162
|
+
height="16"
|
|
163
|
+
viewBox="0 0 24 24"
|
|
164
|
+
fill="none"
|
|
165
|
+
stroke="currentColor"
|
|
166
|
+
strokeWidth="2"
|
|
167
|
+
strokeLinecap="round"
|
|
168
|
+
strokeLinejoin="round"
|
|
169
|
+
>
|
|
170
|
+
<polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"></polygon>
|
|
171
|
+
</svg>
|
|
172
|
+
),
|
|
173
|
+
trailingIcon: (
|
|
174
|
+
<svg
|
|
175
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
176
|
+
width="16"
|
|
177
|
+
height="16"
|
|
178
|
+
viewBox="0 0 24 24"
|
|
179
|
+
fill="none"
|
|
180
|
+
stroke="currentColor"
|
|
181
|
+
strokeWidth="2"
|
|
182
|
+
strokeLinecap="round"
|
|
183
|
+
strokeLinejoin="round"
|
|
184
|
+
>
|
|
185
|
+
<polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"></polygon>
|
|
186
|
+
<path d="M15.54 8.46a5 5 0 0 1 0 7.07"></path>
|
|
187
|
+
<path d="M19.07 4.93a10 10 0 0 1 0 14.14"></path>
|
|
188
|
+
</svg>
|
|
189
|
+
),
|
|
190
|
+
},
|
|
191
|
+
};
|
|
192
|
+
|
|
149
193
|
export const FormLayouts: Story = {
|
|
150
194
|
render: () => (
|
|
151
195
|
<div
|
|
@@ -51,7 +51,8 @@ const SliderReadOnlyValue: React.FC<{ value: number }> = ({ value }) => {
|
|
|
51
51
|
* Recursica Slider component wrapping Mantine's Slider.
|
|
52
52
|
*
|
|
53
53
|
* Implements a bidirectional text input field next to the slider track, responsive layouts,
|
|
54
|
-
* custom typography-bound min/max labels
|
|
54
|
+
* custom typography-bound min/max labels (optionally overridden via `minLabel`/`maxLabel`),
|
|
55
|
+
* optional leading/trailing icons, and an explicit read-only layout.
|
|
55
56
|
*/
|
|
56
57
|
export const Slider = forwardRef<HTMLDivElement, SliderProps>(
|
|
57
58
|
function Slider(props, ref) {
|
|
@@ -84,10 +85,13 @@ export const Slider = forwardRef<HTMLDivElement, SliderProps>(
|
|
|
84
85
|
value,
|
|
85
86
|
defaultValue,
|
|
86
87
|
icon,
|
|
88
|
+
trailingIcon,
|
|
87
89
|
showInput = false,
|
|
88
90
|
showMinMaxLabels = true,
|
|
89
91
|
min = 0,
|
|
90
92
|
max = 100,
|
|
93
|
+
minLabel,
|
|
94
|
+
maxLabel,
|
|
91
95
|
step = 1,
|
|
92
96
|
onChange,
|
|
93
97
|
onChangeEnd,
|
|
@@ -176,6 +180,19 @@ export const Slider = forwardRef<HTMLDivElement, SliderProps>(
|
|
|
176
180
|
</span>
|
|
177
181
|
) : null;
|
|
178
182
|
|
|
183
|
+
const trailingIconEl = trailingIcon ? (
|
|
184
|
+
<span className={styles.iconWrapper} aria-hidden>
|
|
185
|
+
{trailingIcon}
|
|
186
|
+
</span>
|
|
187
|
+
) : null;
|
|
188
|
+
|
|
189
|
+
// Duplicates the raw numeric value next to the track by default; when `tooltipLabel` is a
|
|
190
|
+
// formatter, reuse it here too so both displays agree instead of one showing raw numbers.
|
|
191
|
+
const displayValue =
|
|
192
|
+
typeof tooltipLabel === "function"
|
|
193
|
+
? tooltipLabel(resolvedValue)
|
|
194
|
+
: resolvedValue;
|
|
195
|
+
|
|
179
196
|
return (
|
|
180
197
|
<WithReadOnlyWrapper
|
|
181
198
|
ref={ref}
|
|
@@ -214,7 +231,7 @@ export const Slider = forwardRef<HTMLDivElement, SliderProps>(
|
|
|
214
231
|
{leadingIcon}
|
|
215
232
|
|
|
216
233
|
{showMinMaxLabels && (
|
|
217
|
-
<span className={styles.minMaxGuide}>{min}</span>
|
|
234
|
+
<span className={styles.minMaxGuide}>{minLabel ?? min}</span>
|
|
218
235
|
)}
|
|
219
236
|
|
|
220
237
|
<div className={styles.sliderTrackWrapper}>
|
|
@@ -234,10 +251,10 @@ export const Slider = forwardRef<HTMLDivElement, SliderProps>(
|
|
|
234
251
|
|
|
235
252
|
<div className={styles.rightGuideContainer}>
|
|
236
253
|
{!showInput && (
|
|
237
|
-
<span className={styles.currentValue}>{
|
|
254
|
+
<span className={styles.currentValue}>{displayValue}</span>
|
|
238
255
|
)}
|
|
239
256
|
{showMinMaxLabels && (
|
|
240
|
-
<span className={styles.minMaxGuide}>{max}</span>
|
|
257
|
+
<span className={styles.minMaxGuide}>{maxLabel ?? max}</span>
|
|
241
258
|
)}
|
|
242
259
|
</div>
|
|
243
260
|
|
|
@@ -255,6 +272,8 @@ export const Slider = forwardRef<HTMLDivElement, SliderProps>(
|
|
|
255
272
|
data-error={error ? "true" : undefined}
|
|
256
273
|
/>
|
|
257
274
|
)}
|
|
275
|
+
|
|
276
|
+
{trailingIconEl}
|
|
258
277
|
</div>
|
|
259
278
|
}
|
|
260
279
|
/>
|
|
@@ -39,4 +39,4 @@ All Recursica components in the `@recursica/mantine-adapter` package adhere stri
|
|
|
39
39
|
|
|
40
40
|
## 4. Key Integration Features & Constraints
|
|
41
41
|
|
|
42
|
-
The `label` prop is passed through to the surrounding form label rather than Mantine's dragging tooltip; use `tooltipLabel` to set the label shown while dragging. When `showInput` is enabled, a numeric text input is rendered alongside the track and stays in sync with the slider's value. Set `showMinMaxLabels` to `false` to hide the min/max guides shown at either end of the track. Otherwise, the current value is displayed near the track instead.
|
|
42
|
+
The `label` prop is passed through to the surrounding form label rather than Mantine's dragging tooltip; use `tooltipLabel` to set the label shown while dragging. When `showInput` is enabled, a numeric text input is rendered alongside the track and stays in sync with the slider's value. Set `showMinMaxLabels` to `false` to hide the min/max guides shown at either end of the track. Otherwise, the current value is displayed near the track instead — pass `tooltipLabel` as a formatter function (`(value) => ReactNode`) and that same formatter is reused for this display, instead of always showing the raw number. `minLabel`/`maxLabel` override the text shown at either end of the track (defaults to the numeric `min`/`max`). `icon` renders a leading icon next to the track; `trailingIcon` renders one on the opposite side.
|
|
@@ -19,7 +19,7 @@ import { type RecursicaSwitchGroupProps as BaseRecursicaSwitchGroupProps } from
|
|
|
19
19
|
export interface RecursicaSwitchGroupProps
|
|
20
20
|
extends Omit<
|
|
21
21
|
MantineSwitchGroupProps,
|
|
22
|
-
"size" | "labelProps" | "defaultValue" | "value"
|
|
22
|
+
"size" | "labelProps" | "defaultValue" | "value"
|
|
23
23
|
>,
|
|
24
24
|
Omit<
|
|
25
25
|
RecursicaFormControlWrapperProps,
|