@tangible/ui 0.0.6 → 0.0.8
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/components/Accordion/Accordion.js +11 -3
- package/components/Avatar/Avatar.js +4 -3
- package/components/Avatar/AvatarGroup.js +7 -5
- package/components/Avatar/index.d.ts +2 -2
- package/components/Avatar/index.js +1 -1
- package/components/Avatar/types.d.ts +27 -0
- package/components/Avatar/types.js +8 -0
- package/components/Button/Button.js +4 -2
- package/components/Button/index.d.ts +2 -1
- package/components/Button/index.js +1 -0
- package/components/Button/types.d.ts +10 -0
- package/components/Button/types.js +3 -1
- package/components/Checkbox/Checkbox.js +46 -11
- package/components/Checkbox/types.d.ts +9 -0
- package/components/Combobox/Combobox.d.ts +1 -1
- package/components/Combobox/Combobox.js +28 -7
- package/components/Combobox/index.d.ts +2 -1
- package/components/Combobox/index.js +1 -0
- package/components/Combobox/types.d.ts +14 -0
- package/components/Combobox/types.js +3 -1
- package/components/Dropdown/Dropdown.js +16 -4
- package/components/Field/Field.d.ts +4 -1
- package/components/Field/Field.js +38 -7
- package/components/Field/FieldContext.d.ts +18 -0
- package/components/Field/FieldContext.js +3 -0
- package/components/Field/index.d.ts +2 -1
- package/components/Field/index.js +1 -0
- package/components/MoveHandle/MoveHandle.js +1 -1
- package/components/MoveHandle/types.d.ts +1 -1
- package/components/MultiSelect/MultiSelect.d.ts +1 -1
- package/components/MultiSelect/MultiSelect.js +37 -19
- package/components/MultiSelect/index.d.ts +2 -1
- package/components/MultiSelect/index.js +1 -0
- package/components/MultiSelect/types.d.ts +34 -0
- package/components/MultiSelect/types.js +10 -0
- package/components/Pager/Pager.d.ts +7 -1
- package/components/Pager/Pager.js +7 -5
- package/components/Pager/index.d.ts +2 -0
- package/components/Pager/index.js +1 -0
- package/components/Pager/types.d.ts +37 -0
- package/components/Pager/types.js +12 -0
- package/components/Radio/Radio.d.ts +4 -0
- package/components/Radio/Radio.js +15 -5
- package/components/Radio/RadioGroup.d.ts +1 -1
- package/components/Radio/RadioGroup.js +2 -2
- package/components/Radio/types.d.ts +10 -0
- package/components/Rating/Rating.d.ts +2 -32
- package/components/Rating/Rating.js +5 -3
- package/components/Rating/index.d.ts +2 -1
- package/components/Rating/index.js +1 -0
- package/components/Rating/types.d.ts +41 -0
- package/components/Rating/types.js +4 -0
- package/components/SegmentedControl/SegmentedControl.js +6 -5
- package/components/SegmentedControl/types.d.ts +17 -5
- package/components/Select/Select.d.ts +1 -0
- package/components/Select/Select.js +109 -77
- package/components/Select/SelectContext.d.ts +4 -16
- package/components/Select/SelectContext.js +5 -35
- package/components/Select/types.d.ts +19 -19
- package/components/Sidebar/Sidebar.js +25 -20
- package/components/StepIndicator/StepIndicator.js +11 -8
- package/components/StepIndicator/index.d.ts +2 -1
- package/components/StepIndicator/index.js +1 -0
- package/components/StepIndicator/types.d.ts +18 -0
- package/components/StepIndicator/types.js +7 -1
- package/components/Switch/Switch.js +28 -14
- package/components/Table/BulkActionsBar.d.ts +4 -1
- package/components/Table/BulkActionsBar.js +5 -4
- package/components/Table/DataTable.d.ts +4 -1
- package/components/Table/DataTable.js +10 -8
- package/components/Table/index.d.ts +3 -0
- package/components/Table/index.js +2 -0
- package/components/Table/types.d.ts +20 -0
- package/components/Table/types.js +11 -0
- package/components/Tabs/Tabs.js +11 -4
- package/components/TextInput/TextInput.js +2 -1
- package/components/TextInput/types.d.ts +7 -1
- package/components/Textarea/Textarea.js +3 -2
- package/components/Textarea/types.d.ts +6 -1
- package/icons/icons.svg +29 -15
- package/icons/lms/index.d.ts +8 -0
- package/icons/lms/index.js +48 -4
- package/icons/manifest.json +112 -0
- package/icons/player/index.js +9 -9
- package/icons/registry.d.ts +28 -0
- package/icons/registry.js +14 -0
- package/icons/system/index.d.ts +20 -0
- package/icons/system/index.js +112 -2
- package/package.json +1 -1
- package/styles/all.css +1 -1
- package/styles/all.expanded.css +426 -136
- package/styles/all.expanded.unlayered.css +426 -136
- package/styles/all.unlayered.css +1 -1
- package/styles/components/input/index.scss +29 -7
- package/styles/system/_constants.scss +1 -1
- package/styles/system/_tokens.scss +1 -0
- package/styles/utilities/_index.scss +14 -4
- package/tui-manifest.json +102 -46
- package/utils/use-roving-group.js +9 -6
|
@@ -10,14 +10,24 @@ export type RadioGroupProps = {
|
|
|
10
10
|
loop?: boolean;
|
|
11
11
|
'aria-label'?: string;
|
|
12
12
|
'aria-labelledby'?: string;
|
|
13
|
+
'aria-describedby'?: string;
|
|
14
|
+
'aria-invalid'?: boolean | 'true' | 'false';
|
|
15
|
+
'aria-required'?: boolean | 'true' | 'false';
|
|
13
16
|
className?: string;
|
|
14
17
|
children: ReactNode;
|
|
15
18
|
};
|
|
16
19
|
export type RadioProps = {
|
|
17
20
|
value: OptionValue;
|
|
18
21
|
label?: ReactNode;
|
|
22
|
+
/**
|
|
23
|
+
* Description text displayed below the label.
|
|
24
|
+
*/
|
|
25
|
+
description?: string;
|
|
19
26
|
disabled?: boolean;
|
|
27
|
+
'aria-label'?: string;
|
|
28
|
+
'aria-labelledby'?: string;
|
|
20
29
|
className?: string;
|
|
30
|
+
children?: ReactNode;
|
|
21
31
|
};
|
|
22
32
|
export type RadioItemRecord = RovingItemRecord;
|
|
23
33
|
export type RadioGroupContextValue = {
|
|
@@ -1,32 +1,2 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
type Theme = ThemeFull;
|
|
4
|
-
export type RatingProps = {
|
|
5
|
-
/** Controlled value (1..max). Use with onValueChange */
|
|
6
|
-
value?: number;
|
|
7
|
-
/** Uncontrolled initial value */
|
|
8
|
-
defaultValue?: number;
|
|
9
|
-
/** Maximum icons shown */
|
|
10
|
-
max?: number;
|
|
11
|
-
/** Disable interaction (keeps semantics) */
|
|
12
|
-
disabled?: boolean;
|
|
13
|
-
/** Presentational readOnly (no form semantics) */
|
|
14
|
-
readOnly?: boolean;
|
|
15
|
-
/** Name for the radio group (if you care about form posts) */
|
|
16
|
-
name?: string;
|
|
17
|
-
/** Size maps to icon + spacing */
|
|
18
|
-
size?: Size;
|
|
19
|
-
/** Theme feeds foreground color tokens */
|
|
20
|
-
theme?: Theme;
|
|
21
|
-
/** Called when the value changes */
|
|
22
|
-
onValueChange?: (value: number) => void;
|
|
23
|
-
/** Allow clicking the current selection to clear back to 0 */
|
|
24
|
-
allowClear?: boolean;
|
|
25
|
-
className?: string;
|
|
26
|
-
/** Gap override (e.g. '0.25rem') – otherwise uses density utilities */
|
|
27
|
-
gap?: string;
|
|
28
|
-
/** Accessible label for the rating group. Defaults to "Rating: X of Y" */
|
|
29
|
-
'aria-label'?: string;
|
|
30
|
-
};
|
|
31
|
-
export declare function Rating({ value, defaultValue, max, disabled, readOnly, name, size, theme, onValueChange, allowClear, className, gap, 'aria-label': ariaLabel, }: RatingProps): import("react/jsx-runtime").JSX.Element;
|
|
32
|
-
export {};
|
|
1
|
+
import type { RatingProps } from './types';
|
|
2
|
+
export declare function Rating({ value, defaultValue, max, disabled, readOnly, name, size, theme, onValueChange, allowClear, className, gap, 'aria-label': ariaLabel, labels: labelsProp, }: RatingProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -2,10 +2,12 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { cx } from '../../utils/cx.js';
|
|
4
4
|
import { Icon } from '../Icon/index.js';
|
|
5
|
-
|
|
5
|
+
import { defaultRatingLabels } from './types.js';
|
|
6
|
+
export function Rating({ value, defaultValue = 0, max = 5, disabled, readOnly, name, size = 'lg', theme = 'secondary', onValueChange, allowClear, className, gap, 'aria-label': ariaLabel, labels: labelsProp, }) {
|
|
6
7
|
const isControlled = value != null;
|
|
7
8
|
const [internal, setInternal] = React.useState(defaultValue);
|
|
8
9
|
const current = isControlled ? value : internal;
|
|
10
|
+
const labels = { ...defaultRatingLabels, ...labelsProp };
|
|
9
11
|
const generatedId = React.useId();
|
|
10
12
|
const groupName = name ?? generatedId;
|
|
11
13
|
const setValue = (v) => {
|
|
@@ -62,13 +64,13 @@ export function Rating({ value, defaultValue = 0, max = 5, disabled, readOnly, n
|
|
|
62
64
|
return;
|
|
63
65
|
}
|
|
64
66
|
};
|
|
65
|
-
const defaultAriaLabel =
|
|
67
|
+
const defaultAriaLabel = labels.rating(current, max);
|
|
66
68
|
// Roving tabindex: only the selected radio (or first if none) is in tab order
|
|
67
69
|
const focusableIndex = current > 0 ? current : 1;
|
|
68
70
|
return (_jsx("div", { className: cx('tui-rating', `is-size-${size}`, `is-theme-${theme}`, disabled && 'is-disabled', className), style: { gap }, role: readOnly ? 'img' : 'radiogroup', "aria-label": ariaLabel ?? defaultAriaLabel, onKeyDown: readOnly ? undefined : onKeyDown, children: Array.from({ length: max }).map((_, i) => {
|
|
69
71
|
const n = i + 1;
|
|
70
72
|
const checked = current >= n;
|
|
71
73
|
const id = `${groupName}__star-${n}`;
|
|
72
|
-
return (_jsxs("div", { className: "tui-rating__item", children: [!readOnly && (_jsx("input", { className: "tui-visually-hidden", type: "radio", id: id, name: groupName, value: n, checked: current === n, "aria-checked": current === n, tabIndex: n === focusableIndex ? 0 : -1, onChange: () => handleSelect(n), disabled: disabled })), readOnly ? (_jsx("span", { className: cx('tui-rating__star', checked && 'is-active'), children: _jsx(Icon, { name: checked ? 'system/star-fill' : 'system/star-outline' }) })) : (_jsxs("label", { className: cx('tui-rating__star', checked && 'is-active'), htmlFor: id, tabIndex: -1, children: [_jsx(Icon, { name: checked ? 'system/star-fill' : 'system/star-outline' }), _jsx("span", { className: "tui-visually-hidden", children:
|
|
74
|
+
return (_jsxs("div", { className: "tui-rating__item", children: [!readOnly && (_jsx("input", { className: "tui-visually-hidden", type: "radio", id: id, name: groupName, value: n, checked: current === n, "aria-checked": current === n, tabIndex: n === focusableIndex ? 0 : -1, onChange: () => handleSelect(n), disabled: disabled })), readOnly ? (_jsx("span", { className: cx('tui-rating__star', checked && 'is-active'), children: _jsx(Icon, { name: checked ? 'system/star-fill' : 'system/star-outline' }) })) : (_jsxs("label", { className: cx('tui-rating__star', checked && 'is-active'), htmlFor: id, tabIndex: -1, children: [_jsx(Icon, { name: checked ? 'system/star-fill' : 'system/star-outline' }), _jsx("span", { className: "tui-visually-hidden", children: labels.value(n, max) })] }))] }, n));
|
|
73
75
|
}) }));
|
|
74
76
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { SizeStandard, Theme as ThemeFull } from '../../types';
|
|
2
|
+
export type Size = SizeStandard;
|
|
3
|
+
export type Theme = ThemeFull;
|
|
4
|
+
export type RatingLabels = {
|
|
5
|
+
/** Group label for the radiogroup/img. Receives current value and max. */
|
|
6
|
+
rating?: (value: number, max: number) => string;
|
|
7
|
+
/** Visually-hidden label for each star. Receives star number and max. */
|
|
8
|
+
value?: (n: number, max: number) => string;
|
|
9
|
+
};
|
|
10
|
+
export declare const defaultRatingLabels: Required<RatingLabels>;
|
|
11
|
+
export type RatingProps = {
|
|
12
|
+
/** Controlled value (1..max). Use with onValueChange */
|
|
13
|
+
value?: number;
|
|
14
|
+
/** Uncontrolled initial value */
|
|
15
|
+
defaultValue?: number;
|
|
16
|
+
/** Maximum icons shown */
|
|
17
|
+
max?: number;
|
|
18
|
+
/** Disable interaction (keeps semantics) */
|
|
19
|
+
disabled?: boolean;
|
|
20
|
+
/** Presentational readOnly (no form semantics) */
|
|
21
|
+
readOnly?: boolean;
|
|
22
|
+
/** Name for the radio group (if you care about form posts) */
|
|
23
|
+
name?: string;
|
|
24
|
+
/** Size maps to icon + spacing */
|
|
25
|
+
size?: Size;
|
|
26
|
+
/** Theme feeds foreground color tokens */
|
|
27
|
+
theme?: Theme;
|
|
28
|
+
/** Called when the value changes */
|
|
29
|
+
onValueChange?: (value: number) => void;
|
|
30
|
+
/** Allow clicking the current selection to clear back to 0 */
|
|
31
|
+
allowClear?: boolean;
|
|
32
|
+
className?: string;
|
|
33
|
+
/** Gap override (e.g. '0.25rem') – otherwise uses density utilities */
|
|
34
|
+
gap?: string;
|
|
35
|
+
/** Accessible label for the rating group. Defaults to "Rating: X of Y" */
|
|
36
|
+
'aria-label'?: string;
|
|
37
|
+
/**
|
|
38
|
+
* Override default English strings for i18n.
|
|
39
|
+
*/
|
|
40
|
+
labels?: RatingLabels;
|
|
41
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
2
|
+
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
3
3
|
import { cx } from '../../utils/cx.js';
|
|
4
4
|
import { isDev } from '../../utils/is-dev.js';
|
|
5
5
|
import { toKey } from '../../utils/value-key.js';
|
|
@@ -8,9 +8,10 @@ import { SegmentedControlContext, useSegmentedControlContext } from './Segmented
|
|
|
8
8
|
// =============================================================================
|
|
9
9
|
// SegmentedControl Root
|
|
10
10
|
// =============================================================================
|
|
11
|
-
function SegmentedControlRoot({ value: controlledValue, defaultValue, onValueChange, variant = 'pill', size = 'md', orientation = 'horizontal', loop = true, disabled = false, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, className, children, }) {
|
|
11
|
+
function SegmentedControlRoot({ value: controlledValue, defaultValue, onValueChange, variant = 'pill', size = 'md', orientation = 'horizontal', loop = true, wrap = false, disabled = false, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, className, children, }) {
|
|
12
12
|
const [internalValue, setInternalValue] = useState(defaultValue);
|
|
13
|
-
|
|
13
|
+
// Lock controlled/uncontrolled decision at mount to prevent mode switching
|
|
14
|
+
const isControlled = useRef(controlledValue !== undefined).current;
|
|
14
15
|
const selectedValue = isControlled ? controlledValue : internalValue;
|
|
15
16
|
// Selection handler
|
|
16
17
|
const onSelect = useCallback((newValue) => {
|
|
@@ -28,7 +29,7 @@ function SegmentedControlRoot({ value: controlledValue, defaultValue, onValueCha
|
|
|
28
29
|
disabled,
|
|
29
30
|
loop,
|
|
30
31
|
orientation,
|
|
31
|
-
orientationKeyboard:
|
|
32
|
+
orientationKeyboard: false,
|
|
32
33
|
});
|
|
33
34
|
// Dev-only: Warn if missing accessible name
|
|
34
35
|
useEffect(() => {
|
|
@@ -60,7 +61,7 @@ function SegmentedControlRoot({ value: controlledValue, defaultValue, onValueCha
|
|
|
60
61
|
unregisterItem,
|
|
61
62
|
onSelect,
|
|
62
63
|
]);
|
|
63
|
-
return (_jsx(SegmentedControlContext.Provider, { value: contextValue, children: _jsx("div", { role: "radiogroup", className: cx('tui-segmented', `is-variant-${variant}`, `is-size-${size}`, orientation === 'vertical' && 'is-vertical', className), "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-disabled": disabled || undefined, "aria-orientation": orientation, onKeyDown: handleKeyDown, children: children }) }));
|
|
64
|
+
return (_jsx(SegmentedControlContext.Provider, { value: contextValue, children: _jsx("div", { role: "radiogroup", className: cx('tui-segmented', `is-variant-${variant}`, `is-size-${size}`, orientation === 'vertical' && 'is-vertical', wrap && 'is-wrap', className), "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-disabled": disabled || undefined, "aria-orientation": orientation, onKeyDown: handleKeyDown, children: children }) }));
|
|
64
65
|
}
|
|
65
66
|
// =============================================================================
|
|
66
67
|
// SegmentedControl.Item
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
2
|
import type { RovingItemRecord } from '../../utils/use-roving-group';
|
|
3
|
+
import type { SizeStandard } from '../../types/sizes';
|
|
3
4
|
export type SegmentedControlValue = string | number;
|
|
4
5
|
export type SegmentedControlVariant = 'pill' | 'outline' | 'underline';
|
|
5
|
-
export type SegmentedControlSize =
|
|
6
|
+
export type SegmentedControlSize = SizeStandard;
|
|
6
7
|
export type SegmentedControlOrientation = 'horizontal' | 'vertical';
|
|
7
8
|
export type SegmentedControlProps = {
|
|
8
9
|
/** Controlled selected value */
|
|
@@ -19,11 +20,19 @@ export type SegmentedControlProps = {
|
|
|
19
20
|
orientation?: SegmentedControlOrientation;
|
|
20
21
|
/** Whether arrow keys wrap around */
|
|
21
22
|
loop?: boolean;
|
|
23
|
+
/** Allow items to wrap to multiple lines (default: false) */
|
|
24
|
+
wrap?: boolean;
|
|
22
25
|
/** Disable all items */
|
|
23
26
|
disabled?: boolean;
|
|
24
|
-
/**
|
|
27
|
+
/**
|
|
28
|
+
* Accessible label for the radiogroup.
|
|
29
|
+
* At least one of `aria-label` or `aria-labelledby` is required.
|
|
30
|
+
*/
|
|
25
31
|
'aria-label'?: string;
|
|
26
|
-
/**
|
|
32
|
+
/**
|
|
33
|
+
* ID of element that labels this control.
|
|
34
|
+
* At least one of `aria-label` or `aria-labelledby` is required.
|
|
35
|
+
*/
|
|
27
36
|
'aria-labelledby'?: string;
|
|
28
37
|
/** Additional classes */
|
|
29
38
|
className?: string;
|
|
@@ -34,9 +43,12 @@ export type SegmentedControlItemProps = {
|
|
|
34
43
|
value: SegmentedControlValue;
|
|
35
44
|
/** Disable this item */
|
|
36
45
|
disabled?: boolean;
|
|
37
|
-
/**
|
|
46
|
+
/**
|
|
47
|
+
* Icon element rendered before the label.
|
|
48
|
+
* @remarks Icon-only items (no `children`) must provide `aria-label`.
|
|
49
|
+
*/
|
|
38
50
|
icon?: ReactNode;
|
|
39
|
-
/** Accessible label for icon-only items */
|
|
51
|
+
/** Accessible label — required for icon-only items */
|
|
40
52
|
'aria-label'?: string;
|
|
41
53
|
/** Additional classes */
|
|
42
54
|
className?: string;
|
|
@@ -37,3 +37,4 @@ export declare const SelectOption: typeof SelectOptionComponent;
|
|
|
37
37
|
export declare const SelectGroup: typeof SelectGroupComponent;
|
|
38
38
|
export declare const SelectLabel: typeof SelectLabelComponent;
|
|
39
39
|
export { useSelectContext as useSelect } from './SelectContext';
|
|
40
|
+
export type { SelectContextValue } from './types';
|