@recursica/mui-adapter 0.30.0 → 0.31.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 +11 -0
- package/dist/index.d.ts +8 -1
- package/dist/mui-adapter.cjs +36 -36
- package/dist/mui-adapter.cjs.map +1 -1
- package/dist/mui-adapter.js +2097 -2093
- package/dist/mui-adapter.js.map +1 -1
- package/package.json +2 -2
- package/src/components/Slider/IMPLEMENTATION_NOTES.md +10 -0
- package/src/components/Slider/Slider.stories.tsx +44 -0
- package/src/components/Slider/Slider.tsx +23 -4
- package/src/components/Slider/USAGE.md +6 -0
package/package.json
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"url": "git+https://github.com/borderux/recursica.git",
|
|
14
14
|
"directory": "packages/mui-adapter"
|
|
15
15
|
},
|
|
16
|
-
"version": "0.
|
|
16
|
+
"version": "0.31.0",
|
|
17
17
|
"publishConfig": {
|
|
18
18
|
"access": "public"
|
|
19
19
|
},
|
|
@@ -102,7 +102,7 @@
|
|
|
102
102
|
"vitest": "^3.2.4"
|
|
103
103
|
},
|
|
104
104
|
"dependencies": {
|
|
105
|
-
"@recursica/adapter-common": "^0.
|
|
105
|
+
"@recursica/adapter-common": "^0.22.0",
|
|
106
106
|
"@recursica/official-release": "^2.8.0",
|
|
107
107
|
"dayjs": "^1.11.21"
|
|
108
108
|
},
|
|
@@ -27,3 +27,13 @@ This document contains specific design decisions, architectural constraints, and
|
|
|
27
27
|
## 4. Mark Label Color
|
|
28
28
|
|
|
29
29
|
**Root cause:** MUI's `.sliderMarkLabel` already inherited the container text color using the min-max-label typography tokens. Mantine's equivalent class (`styles.sliderMarkLabel`) was referenced in `Slider.tsx`'s `classNames` map but was never defined in Mantine's `Slider.module.css`, so Mantine silently fell back to its own default theme grey instead of any recursica token. Fixed in `mantine-adapter` by adding the missing `.sliderMarkLabel` rule (same tokens/inherit-color approach as MUI) rather than copying Mantine's undefined behavior into MUI.
|
|
30
|
+
|
|
31
|
+
## 5. Formatted Current Value, Label Overrides, Trailing Icon
|
|
32
|
+
|
|
33
|
+
**Symptom:** `.currentValue` always rendered the raw numeric value, even when `tooltipLabel` was a formatter function (already used for MUI's own `valueLabelFormat`) — a caller mapping values onto custom text got the formatted tooltip while dragging but the raw number next to the track otherwise. Same bug as `mantine-adapter`.
|
|
34
|
+
|
|
35
|
+
**Fix:** `.currentValue` now runs `resolvedValue` through `tooltipLabel` when it's a function, reusing the same formatter passed to `valueLabelFormat`. Added `minLabel`/`maxLabel` (new `adapter-common` props) to override the `.minMaxGuide` text at either end of the track, and `trailingIcon` (new `adapter-common` prop) to render a second icon opposite the existing `icon`, reusing the same `.iconWrapper` styling.
|
|
36
|
+
|
|
37
|
+
## 6. No Dual-Thumb / Range Support
|
|
38
|
+
|
|
39
|
+
**Decision:** Requested (MUI's `Slider` already accepts `number[]` for `value`/`onChange` and renders multiple thumbs natively), declined — no current use case needs it. `Slider` stays single-thumb only; `value`/`onChange` remain typed as `number` and arrays continue to be collapsed to `value[0]`.
|
|
@@ -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
|
|
@@ -48,7 +48,8 @@ const SliderReadOnlyValue: React.FC<{ value: number }> = ({ value }) => {
|
|
|
48
48
|
* Recursica Slider component wrapping Mui's Slider.
|
|
49
49
|
*
|
|
50
50
|
* Implements a bidirectional text input field next to the slider track, responsive layouts,
|
|
51
|
-
* custom typography-bound min/max labels
|
|
51
|
+
* custom typography-bound min/max labels (optionally overridden via `minLabel`/`maxLabel`),
|
|
52
|
+
* optional leading/trailing icons, and an explicit read-only layout.
|
|
52
53
|
*/
|
|
53
54
|
export const Slider = forwardRef<HTMLDivElement, SliderProps>(
|
|
54
55
|
function Slider(props, ref) {
|
|
@@ -82,10 +83,13 @@ export const Slider = forwardRef<HTMLDivElement, SliderProps>(
|
|
|
82
83
|
value,
|
|
83
84
|
defaultValue,
|
|
84
85
|
icon,
|
|
86
|
+
trailingIcon,
|
|
85
87
|
showInput = false,
|
|
86
88
|
showMinMaxLabels = true,
|
|
87
89
|
min = 0,
|
|
88
90
|
max = 100,
|
|
91
|
+
minLabel,
|
|
92
|
+
maxLabel,
|
|
89
93
|
step = 1,
|
|
90
94
|
onChange,
|
|
91
95
|
onChangeEnd,
|
|
@@ -220,6 +224,19 @@ export const Slider = forwardRef<HTMLDivElement, SliderProps>(
|
|
|
220
224
|
</span>
|
|
221
225
|
) : null;
|
|
222
226
|
|
|
227
|
+
const trailingIconEl = trailingIcon ? (
|
|
228
|
+
<span className={styles.iconWrapper} aria-hidden>
|
|
229
|
+
{trailingIcon}
|
|
230
|
+
</span>
|
|
231
|
+
) : null;
|
|
232
|
+
|
|
233
|
+
// Duplicates the raw numeric value next to the track by default; when `tooltipLabel` is a
|
|
234
|
+
// formatter, reuse it here too so both displays agree instead of one showing raw numbers.
|
|
235
|
+
const displayValue =
|
|
236
|
+
typeof tooltipLabel === "function"
|
|
237
|
+
? tooltipLabel(resolvedValue)
|
|
238
|
+
: resolvedValue;
|
|
239
|
+
|
|
223
240
|
return (
|
|
224
241
|
<WithReadOnlyWrapper
|
|
225
242
|
ref={ref}
|
|
@@ -258,7 +275,7 @@ export const Slider = forwardRef<HTMLDivElement, SliderProps>(
|
|
|
258
275
|
{leadingIcon}
|
|
259
276
|
|
|
260
277
|
{showMinMaxLabels && (
|
|
261
|
-
<span className={styles.minMaxGuide}>{min}</span>
|
|
278
|
+
<span className={styles.minMaxGuide}>{minLabel ?? min}</span>
|
|
262
279
|
)}
|
|
263
280
|
|
|
264
281
|
<div className={styles.sliderTrackWrapper}>
|
|
@@ -295,10 +312,10 @@ export const Slider = forwardRef<HTMLDivElement, SliderProps>(
|
|
|
295
312
|
|
|
296
313
|
<div className={styles.rightGuideContainer}>
|
|
297
314
|
{!showInput && (
|
|
298
|
-
<span className={styles.currentValue}>{
|
|
315
|
+
<span className={styles.currentValue}>{displayValue}</span>
|
|
299
316
|
)}
|
|
300
317
|
{showMinMaxLabels && (
|
|
301
|
-
<span className={styles.minMaxGuide}>{max}</span>
|
|
318
|
+
<span className={styles.minMaxGuide}>{maxLabel ?? max}</span>
|
|
302
319
|
)}
|
|
303
320
|
</div>
|
|
304
321
|
|
|
@@ -316,6 +333,8 @@ export const Slider = forwardRef<HTMLDivElement, SliderProps>(
|
|
|
316
333
|
data-error={error ? "true" : undefined}
|
|
317
334
|
/>
|
|
318
335
|
)}
|
|
336
|
+
|
|
337
|
+
{trailingIconEl}
|
|
319
338
|
</div>
|
|
320
339
|
}
|
|
321
340
|
/>
|
|
@@ -34,3 +34,9 @@ All Recursica components in the `@recursica/mui-adapter` package adhere strictly
|
|
|
34
34
|
> - **Anti-override protection**: Rogues style injections (like inline `style` or arbitrary `className`) are automatically blocked by our prop layer unless `overStyled={true}` is explicitly provided.
|
|
35
35
|
> - **No Direct Layers**: Do not pass a `layer` prop to this component. To place it on a specific visual layer, wrap it in a `<Layer layer={0|1|2|3}>` component natively.
|
|
36
36
|
> - **Variables and Theming**: Styling is entirely determined by local CSS variables defined in `recursica_variables_scoped.css` and mapped in the component's CSS module.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 4. Key Integration Features & Constraints
|
|
41
|
+
|
|
42
|
+
The `label` prop is passed through to the surrounding form label rather than MUI'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.
|