@juwel-development/design-system 3.9.0 → 3.9.1

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.
@@ -1119,24 +1119,34 @@ var g = (e) => typeof e == "boolean" ? `${e}` : e === 0 ? "0" : e, _ = h, v = (e
1119
1119
  if (e.min >= e.max) throw new X(`\`min\` (${e.min}) must be below \`max\` (${e.max})`);
1120
1120
  if (e.step <= 0) throw new X(`\`step\` (${e.step}) must be positive`);
1121
1121
  if (e.value < e.min || e.value > e.max) throw new X(`\`value\` (${e.value}) must lie within [${e.min}, ${e.max}]`);
1122
- }, ft = ({ min: t, max: n, step: r = 1, value: i, onInput$: a, label: o, valueText: s, disabled: c, testId: l }) => (dt({
1123
- min: t,
1124
- max: n,
1125
- step: r,
1126
- value: i
1127
- }), /* @__PURE__ */ e("input", {
1128
- type: "range",
1129
- className: ut(),
1130
- min: t,
1131
- max: n,
1132
- step: r,
1133
- value: i,
1134
- disabled: c,
1135
- "aria-label": o,
1136
- "aria-valuetext": s,
1137
- "data-testid": l,
1138
- onChange: (e) => a.next(e.currentTarget.valueAsNumber)
1139
- })), pt = class extends Error {
1122
+ }, ft = ({ min: n, max: r, step: i = 1, value: a, onInput$: o, label: s, valueText: c, disabled: u, testId: d }) => {
1123
+ let f = `${l()}-control`;
1124
+ return dt({
1125
+ min: n,
1126
+ max: r,
1127
+ step: i,
1128
+ value: a
1129
+ }), /* @__PURE__ */ t("div", {
1130
+ className: "flex flex-col gap-[var(--space-stack)]",
1131
+ children: [/* @__PURE__ */ e("label", {
1132
+ htmlFor: f,
1133
+ className: "font-secondary font-medium text-body text-foreground",
1134
+ children: s
1135
+ }), /* @__PURE__ */ e("input", {
1136
+ id: f,
1137
+ type: "range",
1138
+ className: ut(),
1139
+ min: n,
1140
+ max: r,
1141
+ step: i,
1142
+ value: a,
1143
+ disabled: u,
1144
+ "aria-valuetext": c,
1145
+ "data-testid": d,
1146
+ onChange: (e) => o.next(e.currentTarget.valueAsNumber)
1147
+ })]
1148
+ });
1149
+ }, pt = class extends Error {
1140
1150
  constructor(e) {
1141
1151
  super(`Tabs.${e} must be composed inside Tabs.Root`), this.name = "TabsCompositionError";
1142
1152
  }
@@ -1,4 +1,4 @@
1
- import type { FunctionComponent } from 'react';
1
+ import { type FunctionComponent } from 'react';
2
2
  import type { Subject } from 'rxjs';
3
3
  export interface ISliderProps {
4
4
  /** The operating range's lower bound - interaction geometry, not a content rule (ADR 0009). */
@@ -20,7 +20,10 @@ export interface ISliderProps {
20
20
  * could never read a value at all.
21
21
  */
22
22
  onInput$: Subject<number>;
23
- /** The control's accessible name. */
23
+ /**
24
+ * Always rendered as a visible label associated with the control, the way `Input`'s is (#112);
25
+ * it doubles as the accessible name.
26
+ */
24
27
  label: string;
25
28
  /**
26
29
  * How the value is announced, in the consumer's wording ("$60 a week"). Left out, assistive
@@ -35,7 +38,9 @@ export interface ISliderProps {
35
38
  * A control that sets one numeric value by moving one thumb along a fixed, visible operating
36
39
  * range. Controlled: the consumer holds the value and passes it back in, and a value it does not
37
40
  * pass back is never adopted. It renders the value nowhere - the consumer sets any figures beside
38
- * it with typography - and it fills its container's width the way `Input` does. `disabled` is the
39
- * explicit non-operable state.
41
+ * it with typography - and it fills its container's width the way `Input` does. Its label follows
42
+ * `Input` too: visible, associated, and the only text the component renders (#112). It is still
43
+ * a live control and not a form field, so none of Input's annotations - hint, error, optional
44
+ * marker - come with it. `disabled` is the explicit non-operable state.
40
45
  */
41
46
  export declare const Slider: FunctionComponent<ISliderProps>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juwel-development/design-system",
3
- "version": "3.9.0",
3
+ "version": "3.9.1",
4
4
  "type": "module",
5
5
  "description": "Shared design system: tokens and components.",
6
6
  "license": "MIT",
@@ -1,5 +1,5 @@
1
1
  import { cva } from 'class-variance-authority';
2
- import type { FunctionComponent } from 'react';
2
+ import { type FunctionComponent, useId } from 'react';
3
3
  import type { Subject } from 'rxjs';
4
4
  import { SliderConfigurationError } from './SliderConfigurationError';
5
5
 
@@ -45,7 +45,10 @@ export interface ISliderProps {
45
45
  * could never read a value at all.
46
46
  */
47
47
  onInput$: Subject<number>;
48
- /** The control's accessible name. */
48
+ /**
49
+ * Always rendered as a visible label associated with the control, the way `Input`'s is (#112);
50
+ * it doubles as the accessible name.
51
+ */
49
52
  label: string;
50
53
  /**
51
54
  * How the value is announced, in the consumer's wording ("$60 a week"). Left out, assistive
@@ -91,8 +94,10 @@ const assertOperatingRange = (
91
94
  * A control that sets one numeric value by moving one thumb along a fixed, visible operating
92
95
  * range. Controlled: the consumer holds the value and passes it back in, and a value it does not
93
96
  * pass back is never adopted. It renders the value nowhere - the consumer sets any figures beside
94
- * it with typography - and it fills its container's width the way `Input` does. `disabled` is the
95
- * explicit non-operable state.
97
+ * it with typography - and it fills its container's width the way `Input` does. Its label follows
98
+ * `Input` too: visible, associated, and the only text the component renders (#112). It is still
99
+ * a live control and not a form field, so none of Input's annotations - hint, error, optional
100
+ * marker - come with it. `disabled` is the explicit non-operable state.
96
101
  */
97
102
  export const Slider: FunctionComponent<ISliderProps> = ({
98
103
  min,
@@ -105,21 +110,32 @@ export const Slider: FunctionComponent<ISliderProps> = ({
105
110
  disabled,
106
111
  testId,
107
112
  }) => {
113
+ const controlId = `${useId()}-control`;
108
114
  assertOperatingRange({ min, max, step, value });
109
115
  return (
110
- <input
111
- type={'range'}
112
- className={slider()}
113
- min={min}
114
- max={max}
115
- step={step}
116
- value={value}
117
- disabled={disabled}
118
- aria-label={label}
119
- aria-valuetext={valueText}
120
- data-testid={testId}
121
- // React's onChange rides the native input event, so every movement emits through here.
122
- onChange={(event) => onInput$.next(event.currentTarget.valueAsNumber)}
123
- />
116
+ <div className={'flex flex-col gap-[var(--space-stack)]'}>
117
+ {/* The label declares its face and size on itself, never on the wrapper, which would hand
118
+ them to the control too; `body` is the control's own role (docs/adr/0004, #90, #92). */}
119
+ <label
120
+ htmlFor={controlId}
121
+ className={'font-secondary font-medium text-body text-foreground'}
122
+ >
123
+ {label}
124
+ </label>
125
+ <input
126
+ id={controlId}
127
+ type={'range'}
128
+ className={slider()}
129
+ min={min}
130
+ max={max}
131
+ step={step}
132
+ value={value}
133
+ disabled={disabled}
134
+ aria-valuetext={valueText}
135
+ data-testid={testId}
136
+ // React's onChange rides the native input event, so every movement emits through here.
137
+ onChange={(event) => onInput$.next(event.currentTarget.valueAsNumber)}
138
+ />
139
+ </div>
124
140
  );
125
141
  };