@nexub/react 8.4.0 → 8.6.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.
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "8.4.0",
2
+ "version": "8.6.0",
3
3
  "standard": "WCAG 2.2 Level AA",
4
4
  "method": {
5
5
  "automated": "axe-core rules tagged wcag2a, wcag2aa, wcag21a, wcag21aa and wcag22aa, run on every Storybook story in light and dark, and on open popups (menus, listboxes, dialogs), on every pull request; a new violation fails the build.",
@@ -10,7 +10,7 @@ import { usePointerSheen } from "../../hooks/usePointerSheen.js";
10
10
  const cardVariants = cva(
11
11
  // In-flow content: tone + a soft alpha hairline, no shadow (shadows are for floating layers).
12
12
  // A CardLink inside stretches over the card; the card then carries its focus ring.
13
- "rounded-[var(--card-radius,var(--shape-container))] bg-[var(--card-bg,var(--color-surface-elevated))] border border-[color:var(--card-border,color-mix(in_srgb,var(--color-outline-variant)_60%,transparent))] text-[var(--card-fg,var(--color-on-surface))] has-[[data-card-link]]:relative has-[[data-card-link]:focus-visible]:outline has-[[data-card-link]:focus-visible]:outline-[3px] has-[[data-card-link]:focus-visible]:outline-offset-2 has-[[data-card-link]:focus-visible]:outline-[var(--color-primary)]",
13
+ "rounded-[var(--card-radius,var(--shape-container))] bg-[var(--card-bg,var(--color-surface-elevated))] border border-[color:var(--card-border,color-mix(in_srgb,var(--color-outline-variant)_60%,transparent))] text-[var(--card-fg,var(--color-on-surface))] has-[[data-card-link]]:relative has-[[data-card-link]:focus-visible]:outline has-[[data-card-link]:focus-visible]:outline-3 has-[[data-card-link]:focus-visible]:outline-offset-2 has-[[data-card-link]:focus-visible]:outline-[var(--color-primary)]",
14
14
  {
15
15
  variants: {
16
16
  variant: {
@@ -35,7 +35,7 @@ const alignJustify = {
35
35
  };
36
36
  const pagerButton = cn(
37
37
  pressable,
38
- "border border-[var(--color-outline-variant)] bg-transparent px-4 py-2 min-h-[44px] text-label-lg text-[var(--color-on-surface)]",
38
+ "border border-[var(--color-outline-variant)] bg-transparent px-4 py-2 min-h-11 text-label-lg text-[var(--color-on-surface)]",
39
39
  disabledContainer
40
40
  );
41
41
  const TableRoot = Table.Root;
@@ -22,6 +22,9 @@ export declare function useCalendarLocale(localeProp?: Locale): {
22
22
  };
23
23
  export interface DatePickerProps {
24
24
  value?: Date;
25
+ /** Called with the new value. */
26
+ onValueChange?: (date: Date | undefined) => void;
27
+ /** @deprecated 8.5: use `onValueChange` (the name every other Nexub input, and React Native, uses). Removed in 9.0. */
25
28
  onChange?: (date: Date | undefined) => void;
26
29
  placeholder?: string;
27
30
  disabled?: boolean;
@@ -88,6 +88,7 @@ const calendarClassNames = {
88
88
  const DatePicker = React.forwardRef(
89
89
  function DatePicker2({
90
90
  value,
91
+ onValueChange,
91
92
  onChange,
92
93
  placeholder: placeholderProp,
93
94
  disabled = false,
@@ -102,6 +103,10 @@ const DatePicker = React.forwardRef(
102
103
  typeable = false
103
104
  }, ref) {
104
105
  const [open, setOpen] = React.useState(false);
106
+ const change = (v) => {
107
+ onValueChange?.(v);
108
+ onChange?.(v);
109
+ };
105
110
  const messages = useNexubMessages();
106
111
  const placeholder = placeholderProp ?? messages.pickDate;
107
112
  const calendar = useCalendarLocale(localeProp);
@@ -112,11 +117,11 @@ const DatePicker = React.forwardRef(
112
117
  const invalid = typed !== void 0 && (!isValid(typed) || minDate !== void 0 && typed < minDate || maxDate !== void 0 && typed > maxDate || disabledDates !== void 0 && dateMatchModifiers(typed, disabledDates));
113
118
  const commit = () => {
114
119
  if (text === null || invalid) return;
115
- onChange?.(typed);
120
+ change(typed);
116
121
  setText(null);
117
122
  };
118
123
  const pick = (date) => {
119
- onChange?.(date);
124
+ change(date);
120
125
  setText(null);
121
126
  setOpen(false);
122
127
  };
@@ -3,6 +3,9 @@ import type { Locale } from 'date-fns';
3
3
  export interface DateTimePickerProps {
4
4
  /** Date and time in the reader's local time. */
5
5
  value?: Date;
6
+ /** Called with the new value. */
7
+ onValueChange?: (value: Date | undefined) => void;
8
+ /** @deprecated 8.5: use `onValueChange` (the name every other Nexub input, and React Native, uses). Removed in 9.0. */
6
9
  onChange?: (value: Date | undefined) => void;
7
10
  /** Time used when a date is picked first. @default '09:00' */
8
11
  defaultTime?: string;
@@ -17,4 +20,4 @@ export interface DateTimePickerProps {
17
20
  locale?: Locale;
18
21
  }
19
22
  /** A DatePicker and a TimePicker that edit one `Date` together. */
20
- export declare function DateTimePicker({ value, onChange, defaultTime, minuteStep, minDate, maxDate, disabled, timeZone, 'aria-label': ariaLabel, className, locale, }: DateTimePickerProps): React.JSX.Element;
23
+ export declare function DateTimePicker({ value, onValueChange, onChange, defaultTime, minuteStep, minDate, maxDate, disabled, timeZone, 'aria-label': ariaLabel, className, locale, }: DateTimePickerProps): React.JSX.Element;
@@ -15,6 +15,7 @@ const withTime = (d, time) => {
15
15
  };
16
16
  function DateTimePicker({
17
17
  value,
18
+ onValueChange,
18
19
  onChange,
19
20
  defaultTime = "09:00",
20
21
  minuteStep,
@@ -26,6 +27,10 @@ function DateTimePicker({
26
27
  className,
27
28
  locale
28
29
  }) {
30
+ const change = (v) => {
31
+ onValueChange?.(v);
32
+ onChange?.(v);
33
+ };
29
34
  const messages = useNexubMessages();
30
35
  const intlLocale = useIntlLocale();
31
36
  const [pendingTime, setPendingTime] = React.useState(defaultTime);
@@ -37,7 +42,7 @@ function DateTimePicker({
37
42
  {
38
43
  "aria-label": messages.dateLabel,
39
44
  value,
40
- onChange: (date) => onChange?.(date ? withTime(date, time) : void 0),
45
+ onValueChange: (date) => change(date ? withTime(date, time) : void 0),
41
46
  minDate,
42
47
  maxDate,
43
48
  disabled,
@@ -54,7 +59,7 @@ function DateTimePicker({
54
59
  disabled,
55
60
  onValueChange: (next) => {
56
61
  if (!next) return;
57
- if (value) onChange?.(withTime(value, next));
62
+ if (value) change(withTime(value, next));
58
63
  else setPendingTime(next);
59
64
  }
60
65
  }
@@ -115,7 +115,7 @@ const Dropzone = React.forwardRef(
115
115
  className: cn(
116
116
  // Hover/press = the state layer.
117
117
  "nx-state-layer rounded-shape-container border-2 border-dashed text-center text-[var(--color-on-surface)] transition-colors",
118
- "has-[input:focus-visible]:outline has-[input:focus-visible]:outline-[3px] has-[input:focus-visible]:outline-offset-2 has-[input:focus-visible]:outline-[var(--color-primary)]",
118
+ "has-[input:focus-visible]:outline has-[input:focus-visible]:outline-3 has-[input:focus-visible]:outline-offset-2 has-[input:focus-visible]:outline-[var(--color-primary)]",
119
119
  isDragging ? "border-[var(--color-primary)] bg-[color-mix(in_srgb,var(--color-primary)_8%,transparent)]" : "border-[var(--color-outline)] hover:border-[var(--color-primary)]",
120
120
  className
121
121
  ),
@@ -20,7 +20,7 @@ const MediaCard = React.forwardRef(
20
20
  ref,
21
21
  className: cn(
22
22
  "group relative grid overflow-hidden rounded-shape-container border border-[color-mix(in_srgb,var(--color-outline-variant)_60%,transparent)] bg-[var(--color-surface-container-high)]",
23
- href && "shadow-elevation-1 transition-[box-shadow,transform] duration-effects-fast ease-effects-fast hover:shadow-elevation-2 hover:duration-spatial-default hover:ease-spatial-default motion-safe:hover:-translate-y-0.5 has-[a:focus-visible]:outline has-[a:focus-visible]:outline-[3px] has-[a:focus-visible]:outline-offset-2 has-[a:focus-visible]:outline-[var(--color-primary)]",
23
+ href && "shadow-elevation-1 transition-[box-shadow,transform] duration-effects-fast ease-effects-fast hover:shadow-elevation-2 hover:duration-spatial-default hover:ease-spatial-default motion-safe:hover:-translate-y-0.5 has-[a:focus-visible]:outline has-[a:focus-visible]:outline-3 has-[a:focus-visible]:outline-offset-2 has-[a:focus-visible]:outline-[var(--color-primary)]",
24
24
  className
25
25
  ),
26
26
  ...props,
@@ -9,6 +9,9 @@ export interface NumberInputProps extends Omit<React.InputHTMLAttributes<HTMLInp
9
9
  showSteppers?: boolean;
10
10
  value?: number;
11
11
  defaultValue?: number;
12
+ /** Called with the new value. */
13
+ onValueChange?: (value: number) => void;
14
+ /** @deprecated 8.5: use `onValueChange` (the name every other Nexub input, and React Native, uses). Removed in 9.0. */
12
15
  onChange?: (value: number) => void;
13
16
  invalid?: boolean;
14
17
  }
@@ -26,19 +26,24 @@ const NumberInput = React.forwardRef(
26
26
  showSteppers = false,
27
27
  value,
28
28
  defaultValue = 0,
29
+ onValueChange,
29
30
  onChange,
30
31
  invalid,
31
32
  disabled,
32
33
  ...props
33
34
  }, ref) => {
34
35
  const [internalValue, setInternalValue] = React.useState(defaultValue);
36
+ const change = (v) => {
37
+ onValueChange?.(v);
38
+ onChange?.(v);
39
+ };
35
40
  const messages = useNexubMessages();
36
41
  const controlled = value !== void 0;
37
42
  const currentValue = controlled ? value : internalValue;
38
43
  const commit = (next) => {
39
44
  const clamped = clampValue(next, min, max);
40
45
  if (!controlled) setInternalValue(clamped);
41
- onChange?.(clamped);
46
+ change(clamped);
42
47
  };
43
48
  const handleChange = (e) => {
44
49
  const parsed = parseFloat(e.target.value);
@@ -17,7 +17,7 @@ const spinnerVariants = cva(
17
17
  xs: "h-3 w-3 border-[1.5px]",
18
18
  sm: "h-4 w-4 border-2",
19
19
  md: "h-6 w-6 border-2",
20
- lg: "h-8 w-8 border-[3px]",
20
+ lg: "h-8 w-8 border-3",
21
21
  xl: "h-10 w-10 border-4"
22
22
  },
23
23
  tone: {
@@ -36,7 +36,7 @@ const StreamingText = React.forwardRef(
36
36
  {
37
37
  "aria-hidden": "true",
38
38
  "data-caret": "",
39
- className: "nx-caret ms-0.5 inline-block h-[1em] w-[2px] align-text-bottom rounded-full bg-[var(--color-primary)] motion-reduce:animate-none"
39
+ className: "nx-caret ms-0.5 inline-block h-[1em] w-0-5 align-text-bottom rounded-full bg-[var(--color-primary)] motion-reduce:animate-none"
40
40
  }
41
41
  )
42
42
  ]
@@ -93,7 +93,7 @@ const Head = React.forwardRef(
93
93
  {
94
94
  ref,
95
95
  className: cn(
96
- "h-10 px-4 text-start align-middle font-medium text-[var(--color-on-surface-muted)] [&:has([role=checkbox])]:pe-0 [&>[role=checkbox]]:translate-y-[2px]",
96
+ "h-10 px-4 text-start align-middle font-medium text-[var(--color-on-surface-muted)] [&:has([role=checkbox])]:pe-0 [&>[role=checkbox]]:translate-y-0-5",
97
97
  className
98
98
  ),
99
99
  ...props
@@ -107,7 +107,7 @@ const Cell = React.forwardRef(
107
107
  {
108
108
  ref,
109
109
  className: cn(
110
- "p-4 align-middle [&:has([role=checkbox])]:pe-0 [&>[role=checkbox]]:translate-y-[2px]",
110
+ "p-4 align-middle [&:has([role=checkbox])]:pe-0 [&>[role=checkbox]]:translate-y-0-5",
111
111
  className
112
112
  ),
113
113
  ...props
@@ -15,9 +15,9 @@ const textareaVariants = cva(
15
15
  {
16
16
  variants: {
17
17
  size: {
18
- sm: "px-3 py-1.5 text-body-sm min-h-[64px]",
19
- md: "px-3.5 py-2 text-body-md min-h-[80px]",
20
- lg: "px-4 py-2.5 text-body-md min-h-[96px]"
18
+ sm: "px-3 py-1.5 text-body-sm min-h-16",
19
+ md: "px-3.5 py-2 text-body-md min-h-20",
20
+ lg: "px-4 py-2.5 text-body-md min-h-24"
21
21
  },
22
22
  invalid: {
23
23
  true: fieldInvalid
@@ -64,7 +64,7 @@ const Action = React.forwardRef(
64
64
  {
65
65
  ref,
66
66
  className: cn(
67
- "nx-state-layer relative inline-flex min-h-[44px] min-w-[44px] shrink-0 items-center justify-center rounded-shape-control px-3 text-label-lg text-[var(--color-inverse-primary)]",
67
+ "nx-state-layer relative inline-flex min-h-11 min-w-11 shrink-0 items-center justify-center rounded-shape-control px-3 text-label-lg text-[var(--color-inverse-primary)]",
68
68
  className
69
69
  ),
70
70
  ...props
@@ -198,7 +198,7 @@ function Toaster({ expand = false, visibleToasts = 3, position = "top-end" }) {
198
198
  {
199
199
  altText: action.label,
200
200
  onClick: action.onClick,
201
- className: "nx-state-layer relative inline-flex min-h-[44px] min-w-[44px] shrink-0 items-center justify-center rounded-shape-control px-3 text-label-lg text-[var(--color-inverse-primary)]",
201
+ className: "nx-state-layer relative inline-flex min-h-11 min-w-11 shrink-0 items-center justify-center rounded-shape-control px-3 text-label-lg text-[var(--color-inverse-primary)]",
202
202
  children: action.label
203
203
  }
204
204
  ),
@@ -220,7 +220,7 @@ function TreeView({
220
220
  {
221
221
  "aria-hidden": "true",
222
222
  className: cn(
223
- "inline-flex size-4 shrink-0 items-center justify-center rounded-[4px] border-2",
223
+ "inline-flex size-4 shrink-0 items-center justify-center rounded-shape-min border-2",
224
224
  isChecked || mixed ? "border-[var(--color-primary)] bg-[var(--color-primary)] text-[var(--color-on-primary)]" : "border-[var(--color-outline)]"
225
225
  ),
226
226
  children: isChecked ? /* @__PURE__ */ jsx(Check, { size: "xs" }) : mixed ? /* @__PURE__ */ jsx(Minus, { size: "xs" }) : null