@jirawatpyk/aura-react 4.8.0 → 4.9.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/README.md +2 -2
- package/dist/aura.bundle.js +644 -236
- package/dist/cjs/index.cjs +643 -235
- package/dist/esm/Combobox.js +310 -235
- package/dist/esm/NumberField.js +175 -0
- package/dist/esm/SegmentedControl.js +104 -0
- package/dist/esm/Stepper.js +54 -0
- package/dist/esm/index.js +6 -0
- package/dist/esm/locale.js +12 -0
- package/dist/index.d.ts +101 -2
- package/dist/styles.css +107 -0
- package/package.json +1 -1
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { Field, describedBy } from "./Field.js";
|
|
4
|
+
import { Icon } from "./Icon.js";
|
|
5
|
+
import { cx, uid, useMaybeControlled } from "./internal.js";
|
|
6
|
+
import { useStrings } from "./locale.js";
|
|
7
|
+
function decimalsOf(n) {
|
|
8
|
+
const s = String(n);
|
|
9
|
+
const i = s.indexOf(".");
|
|
10
|
+
return i < 0 ? 0 : s.length - i - 1;
|
|
11
|
+
}
|
|
12
|
+
function parse(text) {
|
|
13
|
+
const s = text.replace(/[,\s ]/g, "");
|
|
14
|
+
if (!/^-?(\d+\.?\d*|\.\d+)$/.test(s)) return NaN;
|
|
15
|
+
return Number(s);
|
|
16
|
+
}
|
|
17
|
+
const NumberField = React.forwardRef(function NumberField2(props, ref) {
|
|
18
|
+
const t = useStrings();
|
|
19
|
+
const auto = uid(), id = props.id || auto;
|
|
20
|
+
const step = props.step || 1;
|
|
21
|
+
const decimals = props.decimals != null ? props.decimals : decimalsOf(step);
|
|
22
|
+
const st = useMaybeControlled(
|
|
23
|
+
props.value,
|
|
24
|
+
props.defaultValue == null ? null : props.defaultValue,
|
|
25
|
+
props.onChange
|
|
26
|
+
);
|
|
27
|
+
const value = st[0], setValue = st[1];
|
|
28
|
+
const draftState = React.useState(null), draft = draftState[0], setDraft = draftState[1];
|
|
29
|
+
function fmt(n) {
|
|
30
|
+
if (n == null || isNaN(n)) return "";
|
|
31
|
+
return n.toLocaleString("en", { minimumFractionDigits: decimals, maximumFractionDigits: decimals });
|
|
32
|
+
}
|
|
33
|
+
function fit(n) {
|
|
34
|
+
let v = n;
|
|
35
|
+
if (props.min != null && v < props.min) v = props.min;
|
|
36
|
+
if (props.max != null && v > props.max) v = props.max;
|
|
37
|
+
const f = Math.pow(10, decimals);
|
|
38
|
+
return Math.round(v * f) / f;
|
|
39
|
+
}
|
|
40
|
+
function nudge(by) {
|
|
41
|
+
if (props.disabled || props.readOnly) return;
|
|
42
|
+
const base = value == null ? props.min != null && props.min > 0 ? props.min - by : 0 : value;
|
|
43
|
+
const next = fit(base + by);
|
|
44
|
+
setValue(next);
|
|
45
|
+
setDraft(null);
|
|
46
|
+
}
|
|
47
|
+
function onKeyDown(e) {
|
|
48
|
+
const k = e.key;
|
|
49
|
+
let by = 0;
|
|
50
|
+
if (k === "ArrowUp") by = step;
|
|
51
|
+
else if (k === "ArrowDown") by = -step;
|
|
52
|
+
else if (k === "PageUp") by = step * 10;
|
|
53
|
+
else if (k === "PageDown") by = -step * 10;
|
|
54
|
+
else if (k === "Home" && props.min != null) {
|
|
55
|
+
e.preventDefault();
|
|
56
|
+
setValue(props.min);
|
|
57
|
+
setDraft(null);
|
|
58
|
+
return;
|
|
59
|
+
} else if (k === "End" && props.max != null) {
|
|
60
|
+
e.preventDefault();
|
|
61
|
+
setValue(props.max);
|
|
62
|
+
setDraft(null);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (by) {
|
|
66
|
+
e.preventDefault();
|
|
67
|
+
nudge(by);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const atMin = value != null && props.min != null && value <= props.min;
|
|
71
|
+
const atMax = value != null && props.max != null && value >= props.max;
|
|
72
|
+
const affixText = function(x) {
|
|
73
|
+
return typeof x === "string" || typeof x === "number" ? String(x) : "";
|
|
74
|
+
};
|
|
75
|
+
const valueText = value == null ? void 0 : [affixText(props.prefix), fmt(value), affixText(props.suffix)].join(" ").trim();
|
|
76
|
+
const stepper = props.stepper !== false && !props.readOnly;
|
|
77
|
+
return /* @__PURE__ */ React.createElement(
|
|
78
|
+
Field,
|
|
79
|
+
{
|
|
80
|
+
id,
|
|
81
|
+
label: props.label,
|
|
82
|
+
hint: props.hint,
|
|
83
|
+
error: props.error,
|
|
84
|
+
required: props.required,
|
|
85
|
+
optional: props.optional,
|
|
86
|
+
disabled: props.disabled,
|
|
87
|
+
className: props.className
|
|
88
|
+
},
|
|
89
|
+
/* @__PURE__ */ React.createElement("div", { className: cx("aura-input aura-number", stepper && "has-stepper") }, props.prefix != null ? /* @__PURE__ */ React.createElement("span", { className: "aura-number__affix", "aria-hidden": true }, props.prefix) : null, /* @__PURE__ */ React.createElement(
|
|
90
|
+
"input",
|
|
91
|
+
{
|
|
92
|
+
ref,
|
|
93
|
+
id,
|
|
94
|
+
type: "text",
|
|
95
|
+
role: "spinbutton",
|
|
96
|
+
inputMode: decimals > 0 || props.min != null && props.min < 0 ? "decimal" : "numeric",
|
|
97
|
+
autoComplete: "off",
|
|
98
|
+
className: "aura-input__control",
|
|
99
|
+
name: props.name,
|
|
100
|
+
placeholder: props.placeholder,
|
|
101
|
+
disabled: props.disabled,
|
|
102
|
+
readOnly: props.readOnly,
|
|
103
|
+
required: props.required,
|
|
104
|
+
"aria-valuenow": value == null ? void 0 : value,
|
|
105
|
+
"aria-valuemin": props.min,
|
|
106
|
+
"aria-valuemax": props.max,
|
|
107
|
+
"aria-valuetext": valueText,
|
|
108
|
+
"aria-invalid": props.error ? true : void 0,
|
|
109
|
+
"aria-describedby": describedBy(id, props),
|
|
110
|
+
value: draft != null ? draft : fmt(value),
|
|
111
|
+
onFocus: function() {
|
|
112
|
+
setDraft(fmt(value));
|
|
113
|
+
},
|
|
114
|
+
onChange: function(e) {
|
|
115
|
+
const text = e.target.value;
|
|
116
|
+
setDraft(text);
|
|
117
|
+
if (!text.trim()) setValue(null);
|
|
118
|
+
else {
|
|
119
|
+
const n = parse(text);
|
|
120
|
+
if (!isNaN(n)) setValue(n);
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
onBlur: function(e) {
|
|
124
|
+
const n = draft == null ? value : !draft.trim() ? null : parse(draft);
|
|
125
|
+
if (n == null) {
|
|
126
|
+
if (value != null) setValue(null);
|
|
127
|
+
} else if (!isNaN(n)) {
|
|
128
|
+
const f = fit(n);
|
|
129
|
+
if (f !== value) setValue(f);
|
|
130
|
+
}
|
|
131
|
+
setDraft(null);
|
|
132
|
+
if (props.onBlur) props.onBlur(e);
|
|
133
|
+
},
|
|
134
|
+
onKeyDown
|
|
135
|
+
}
|
|
136
|
+
), props.suffix != null ? /* @__PURE__ */ React.createElement("span", { className: "aura-number__affix", "aria-hidden": true }, props.suffix) : null, stepper ? /* @__PURE__ */ React.createElement("span", { className: "aura-number__steps" }, /* @__PURE__ */ React.createElement(
|
|
137
|
+
"button",
|
|
138
|
+
{
|
|
139
|
+
type: "button",
|
|
140
|
+
tabIndex: -1,
|
|
141
|
+
className: "aura-number__step",
|
|
142
|
+
"aria-label": t.decrease,
|
|
143
|
+
"aria-controls": id,
|
|
144
|
+
disabled: props.disabled || atMin,
|
|
145
|
+
onPointerDown: function(e) {
|
|
146
|
+
e.preventDefault();
|
|
147
|
+
},
|
|
148
|
+
onClick: function() {
|
|
149
|
+
nudge(-step);
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
/* @__PURE__ */ React.createElement(Icon, { name: "minus" })
|
|
153
|
+
), /* @__PURE__ */ React.createElement(
|
|
154
|
+
"button",
|
|
155
|
+
{
|
|
156
|
+
type: "button",
|
|
157
|
+
tabIndex: -1,
|
|
158
|
+
className: "aura-number__step",
|
|
159
|
+
"aria-label": t.increase,
|
|
160
|
+
"aria-controls": id,
|
|
161
|
+
disabled: props.disabled || atMax,
|
|
162
|
+
onPointerDown: function(e) {
|
|
163
|
+
e.preventDefault();
|
|
164
|
+
},
|
|
165
|
+
onClick: function() {
|
|
166
|
+
nudge(step);
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
/* @__PURE__ */ React.createElement(Icon, { name: "plus" })
|
|
170
|
+
)) : null)
|
|
171
|
+
);
|
|
172
|
+
});
|
|
173
|
+
export {
|
|
174
|
+
NumberField
|
|
175
|
+
};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { Icon } from "./Icon.js";
|
|
4
|
+
import { cx, uid, useMaybeControlled } from "./internal.js";
|
|
5
|
+
function toOpt(o) {
|
|
6
|
+
return typeof o === "object" ? o : { value: o, label: o };
|
|
7
|
+
}
|
|
8
|
+
const SegmentedControl = React.forwardRef(
|
|
9
|
+
function SegmentedControl2(props, ref) {
|
|
10
|
+
const options = (props.options || []).map(toOpt);
|
|
11
|
+
const firstEnabled = options.filter(function(o) {
|
|
12
|
+
return !o.disabled;
|
|
13
|
+
})[0];
|
|
14
|
+
const st = useMaybeControlled(
|
|
15
|
+
props.value,
|
|
16
|
+
props.defaultValue != null ? props.defaultValue : firstEnabled ? firstEnabled.value : void 0,
|
|
17
|
+
props.onChange
|
|
18
|
+
);
|
|
19
|
+
const value = st[0], setValue = st[1];
|
|
20
|
+
const auto = uid(), id = props.id || auto;
|
|
21
|
+
const refs = React.useRef([]);
|
|
22
|
+
const selIdx = options.findIndex(function(o) {
|
|
23
|
+
return o.value === value;
|
|
24
|
+
});
|
|
25
|
+
const tabIdx = selIdx >= 0 && !options[selIdx].disabled ? selIdx : options.indexOf(firstEnabled);
|
|
26
|
+
function move(from, dir) {
|
|
27
|
+
const n = options.length;
|
|
28
|
+
for (let k = 1; k <= n; k++) {
|
|
29
|
+
const i = ((from + dir * k) % n + n) % n;
|
|
30
|
+
if (!options[i].disabled) {
|
|
31
|
+
setValue(options[i].value);
|
|
32
|
+
const el = refs.current[i];
|
|
33
|
+
if (el) el.focus();
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function onKeyDown(e, i) {
|
|
39
|
+
const k = e.key;
|
|
40
|
+
if (k === "ArrowRight" || k === "ArrowDown") {
|
|
41
|
+
e.preventDefault();
|
|
42
|
+
move(i, 1);
|
|
43
|
+
} else if (k === "ArrowLeft" || k === "ArrowUp") {
|
|
44
|
+
e.preventDefault();
|
|
45
|
+
move(i, -1);
|
|
46
|
+
} else if (k === "Home") {
|
|
47
|
+
e.preventDefault();
|
|
48
|
+
move(-1, 1);
|
|
49
|
+
} else if (k === "End") {
|
|
50
|
+
e.preventDefault();
|
|
51
|
+
move(options.length, -1);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return /* @__PURE__ */ React.createElement(
|
|
55
|
+
"div",
|
|
56
|
+
{
|
|
57
|
+
ref,
|
|
58
|
+
id,
|
|
59
|
+
role: "radiogroup",
|
|
60
|
+
"aria-label": props.label,
|
|
61
|
+
"aria-disabled": props.disabled || void 0,
|
|
62
|
+
className: cx(
|
|
63
|
+
"aura-segmented",
|
|
64
|
+
props.size === "sm" && "aura-segmented--sm",
|
|
65
|
+
props.fullWidth && "is-full",
|
|
66
|
+
props.disabled && "is-disabled",
|
|
67
|
+
props.className
|
|
68
|
+
)
|
|
69
|
+
},
|
|
70
|
+
options.map(function(o, i) {
|
|
71
|
+
const on = o.value === value;
|
|
72
|
+
const off = props.disabled || o.disabled;
|
|
73
|
+
return /* @__PURE__ */ React.createElement(
|
|
74
|
+
"button",
|
|
75
|
+
{
|
|
76
|
+
key: o.value,
|
|
77
|
+
ref: function(el) {
|
|
78
|
+
refs.current[i] = el;
|
|
79
|
+
},
|
|
80
|
+
type: "button",
|
|
81
|
+
role: "radio",
|
|
82
|
+
"aria-checked": on,
|
|
83
|
+
"aria-label": o.iconOnly ? o.label : void 0,
|
|
84
|
+
title: o.iconOnly ? o.label : void 0,
|
|
85
|
+
tabIndex: i === tabIdx && !props.disabled ? 0 : -1,
|
|
86
|
+
disabled: off,
|
|
87
|
+
className: cx("aura-segmented__option", on && "is-selected", o.iconOnly && "is-icon"),
|
|
88
|
+
onClick: function() {
|
|
89
|
+
setValue(o.value);
|
|
90
|
+
},
|
|
91
|
+
onKeyDown: function(e) {
|
|
92
|
+
onKeyDown(e, i);
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
o.icon ? /* @__PURE__ */ React.createElement(Icon, { name: o.icon }) : null,
|
|
96
|
+
o.iconOnly ? null : /* @__PURE__ */ React.createElement("span", null, o.label)
|
|
97
|
+
);
|
|
98
|
+
})
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
);
|
|
102
|
+
export {
|
|
103
|
+
SegmentedControl
|
|
104
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { Icon } from "./Icon.js";
|
|
4
|
+
import { cx } from "./internal.js";
|
|
5
|
+
import { useStrings } from "./locale.js";
|
|
6
|
+
const Stepper = React.forwardRef(function Stepper2(props, ref) {
|
|
7
|
+
const t = useStrings();
|
|
8
|
+
const steps = props.steps || [];
|
|
9
|
+
let at = -1;
|
|
10
|
+
steps.forEach(function(s, i) {
|
|
11
|
+
if (s.id === props.current) at = i;
|
|
12
|
+
});
|
|
13
|
+
if (at < 0) at = 0;
|
|
14
|
+
const vertical = props.orientation === "vertical";
|
|
15
|
+
const cur = steps[at];
|
|
16
|
+
return /* @__PURE__ */ React.createElement(
|
|
17
|
+
"nav",
|
|
18
|
+
{
|
|
19
|
+
ref,
|
|
20
|
+
"aria-label": props.label,
|
|
21
|
+
className: cx("aura-stepper", vertical ? "aura-stepper--vertical" : "aura-stepper--horizontal", props.className)
|
|
22
|
+
},
|
|
23
|
+
/* @__PURE__ */ React.createElement("ol", { className: "aura-stepper__list" }, steps.map(function(s, i) {
|
|
24
|
+
const state = i < at ? "done" : i === at ? "current" : "upcoming";
|
|
25
|
+
const marker = /* @__PURE__ */ React.createElement("span", { className: "aura-stepper__marker", "aria-hidden": true }, state === "done" ? /* @__PURE__ */ React.createElement(Icon, { name: "check" }) : i + 1);
|
|
26
|
+
const text = /* @__PURE__ */ React.createElement("span", { className: "aura-stepper__text" }, /* @__PURE__ */ React.createElement("span", { className: "aura-stepper__label" }, s.label, state === "done" ? /* @__PURE__ */ React.createElement("span", { className: "aura-sr-only" }, ", " + t.stepDone) : null), s.description ? /* @__PURE__ */ React.createElement("span", { className: "aura-stepper__desc" }, s.description) : null);
|
|
27
|
+
const clickable = state === "done" && !!props.onStepClick;
|
|
28
|
+
return /* @__PURE__ */ React.createElement(
|
|
29
|
+
"li",
|
|
30
|
+
{
|
|
31
|
+
key: s.id,
|
|
32
|
+
className: cx("aura-stepper__item", "is-" + state),
|
|
33
|
+
"aria-current": state === "current" ? "step" : void 0
|
|
34
|
+
},
|
|
35
|
+
clickable ? /* @__PURE__ */ React.createElement(
|
|
36
|
+
"button",
|
|
37
|
+
{
|
|
38
|
+
type: "button",
|
|
39
|
+
className: "aura-stepper__step aura-focusable",
|
|
40
|
+
onClick: function() {
|
|
41
|
+
props.onStepClick(s.id);
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
marker,
|
|
45
|
+
text
|
|
46
|
+
) : /* @__PURE__ */ React.createElement("span", { className: "aura-stepper__step" }, marker, text)
|
|
47
|
+
);
|
|
48
|
+
})),
|
|
49
|
+
!vertical && cur ? /* @__PURE__ */ React.createElement("p", { className: "aura-stepper__compact", "aria-hidden": true }, /* @__PURE__ */ React.createElement("span", { className: "aura-stepper__count" }, t.stepOf(at + 1, steps.length)), /* @__PURE__ */ React.createElement("span", { className: "aura-stepper__compact-label" }, cur.label)) : null
|
|
50
|
+
);
|
|
51
|
+
});
|
|
52
|
+
export {
|
|
53
|
+
Stepper
|
|
54
|
+
};
|
package/dist/esm/index.js
CHANGED
|
@@ -45,6 +45,9 @@ import { EmptyState } from "./EmptyState.js";
|
|
|
45
45
|
import { Pagination } from "./Pagination.js";
|
|
46
46
|
import { Accordion } from "./Accordion.js";
|
|
47
47
|
import { Popover } from "./Popover.js";
|
|
48
|
+
import { NumberField } from "./NumberField.js";
|
|
49
|
+
import { Stepper } from "./Stepper.js";
|
|
50
|
+
import { SegmentedControl } from "./SegmentedControl.js";
|
|
48
51
|
export {
|
|
49
52
|
Accordion,
|
|
50
53
|
Alert,
|
|
@@ -75,17 +78,20 @@ export {
|
|
|
75
78
|
Icon,
|
|
76
79
|
IconButton,
|
|
77
80
|
Menu,
|
|
81
|
+
NumberField,
|
|
78
82
|
Pagination,
|
|
79
83
|
Popover,
|
|
80
84
|
Progress,
|
|
81
85
|
RadioGroup,
|
|
82
86
|
STRINGS,
|
|
87
|
+
SegmentedControl,
|
|
83
88
|
Select,
|
|
84
89
|
SideNav,
|
|
85
90
|
Skeleton,
|
|
86
91
|
Stack,
|
|
87
92
|
Stat,
|
|
88
93
|
StatusPill,
|
|
94
|
+
Stepper,
|
|
89
95
|
Surface,
|
|
90
96
|
Switch,
|
|
91
97
|
Tabs,
|
package/dist/esm/locale.js
CHANGED
|
@@ -83,6 +83,12 @@ const STRINGS = {
|
|
|
83
83
|
return "Up to " + n2 + " files";
|
|
84
84
|
},
|
|
85
85
|
colorScheme: "Colour scheme",
|
|
86
|
+
increase: "Increase",
|
|
87
|
+
decrease: "Decrease",
|
|
88
|
+
stepDone: "completed",
|
|
89
|
+
stepOf: function(i, total) {
|
|
90
|
+
return "Step " + i + " of " + total;
|
|
91
|
+
},
|
|
86
92
|
schemeLight: "Light",
|
|
87
93
|
schemeDark: "Dark",
|
|
88
94
|
schemeSystem: "System",
|
|
@@ -175,6 +181,12 @@ const STRINGS = {
|
|
|
175
181
|
return "\u0E41\u0E19\u0E1A\u0E44\u0E14\u0E49\u0E44\u0E21\u0E48\u0E40\u0E01\u0E34\u0E19 " + n2 + " \u0E44\u0E1F\u0E25\u0E4C";
|
|
176
182
|
},
|
|
177
183
|
colorScheme: "\u0E42\u0E2B\u0E21\u0E14\u0E2A\u0E35",
|
|
184
|
+
increase: "\u0E40\u0E1E\u0E34\u0E48\u0E21",
|
|
185
|
+
decrease: "\u0E25\u0E14",
|
|
186
|
+
stepDone: "\u0E40\u0E2A\u0E23\u0E47\u0E08\u0E41\u0E25\u0E49\u0E27",
|
|
187
|
+
stepOf: function(i, total) {
|
|
188
|
+
return "\u0E02\u0E31\u0E49\u0E19\u0E17\u0E35\u0E48 " + i + " \u0E08\u0E32\u0E01 " + total;
|
|
189
|
+
},
|
|
178
190
|
schemeLight: "\u0E2A\u0E27\u0E48\u0E32\u0E07",
|
|
179
191
|
schemeDark: "\u0E21\u0E37\u0E14",
|
|
180
192
|
schemeSystem: "\u0E15\u0E32\u0E21\u0E23\u0E30\u0E1A\u0E1A",
|
package/dist/index.d.ts
CHANGED
|
@@ -437,6 +437,18 @@ export interface ComboboxOption {
|
|
|
437
437
|
/** Leading icon in the list. */
|
|
438
438
|
icon?: IconName;
|
|
439
439
|
}
|
|
440
|
+
/** Combobox with `multiple`: pick any number; the picks show as removable chips in the field. */
|
|
441
|
+
export interface ComboboxMultipleProps extends Omit<ComboboxProps, "value" | "defaultValue" | "onChange" | "clearable"> {
|
|
442
|
+
multiple: true;
|
|
443
|
+
/** Selected option values, in the order they were picked (controlled). */
|
|
444
|
+
value?: string[];
|
|
445
|
+
defaultValue?: string[];
|
|
446
|
+
onChange?: (value: string[]) => void;
|
|
447
|
+
/** Clear-all button while anything is selected. Default true. */
|
|
448
|
+
clearable?: boolean;
|
|
449
|
+
/** Most picks allowed; further options are disabled. */
|
|
450
|
+
max?: number;
|
|
451
|
+
}
|
|
440
452
|
export interface ComboboxProps extends FieldProps {
|
|
441
453
|
options: Array<ComboboxOption | string>;
|
|
442
454
|
/** Selected option value (controlled). */
|
|
@@ -463,6 +475,77 @@ export interface ComboboxProps extends FieldProps {
|
|
|
463
475
|
filter?: (option: ComboboxOption, query: string) => boolean;
|
|
464
476
|
className?: string;
|
|
465
477
|
}
|
|
478
|
+
/** Number input: thousands separators, +/− buttons, arrow keys, min/max/step, prefix/suffix (฿, %). */
|
|
479
|
+
export interface NumberFieldProps extends FieldProps {
|
|
480
|
+
/** The number (controlled). `null` = empty. */
|
|
481
|
+
value?: number | null;
|
|
482
|
+
defaultValue?: number | null;
|
|
483
|
+
/** Called with the parsed number (or null when emptied) as the person types, and with the clamped value on blur. */
|
|
484
|
+
onChange?: (value: number | null) => void;
|
|
485
|
+
min?: number;
|
|
486
|
+
max?: number;
|
|
487
|
+
/** Arrow keys and buttons move by this. Default 1. PageUp/PageDown move 10×. */
|
|
488
|
+
step?: number;
|
|
489
|
+
/** Decimal places shown and kept. Default: 0 when step is whole, else step's decimals. */
|
|
490
|
+
decimals?: number;
|
|
491
|
+
/** Text before the number, e.g. `฿`. */
|
|
492
|
+
prefix?: React$1.ReactNode;
|
|
493
|
+
/** Text after the number, e.g. `%` or `ชิ้น`. */
|
|
494
|
+
suffix?: React$1.ReactNode;
|
|
495
|
+
/** +/− buttons beside the number. Default true. */
|
|
496
|
+
stepper?: boolean;
|
|
497
|
+
id?: string;
|
|
498
|
+
name?: string;
|
|
499
|
+
placeholder?: string;
|
|
500
|
+
disabled?: boolean;
|
|
501
|
+
readOnly?: boolean;
|
|
502
|
+
className?: string;
|
|
503
|
+
onBlur?: React$1.FocusEventHandler<HTMLInputElement>;
|
|
504
|
+
}
|
|
505
|
+
/** One step of a Stepper. */
|
|
506
|
+
export interface StepItem {
|
|
507
|
+
id: string;
|
|
508
|
+
label: React$1.ReactNode;
|
|
509
|
+
/** Short line under the label, e.g. what the step asks for. */
|
|
510
|
+
description?: React$1.ReactNode;
|
|
511
|
+
}
|
|
512
|
+
/** Progress through a multi-step flow (wizard, checkout, booking). */
|
|
513
|
+
export interface StepperProps {
|
|
514
|
+
steps: StepItem[];
|
|
515
|
+
/** id of the step the person is on. Steps before it are completed. */
|
|
516
|
+
current: string;
|
|
517
|
+
/** Accessible name of the list. Default: none (give one when the page has several). */
|
|
518
|
+
label?: string;
|
|
519
|
+
/** Makes completed steps buttons that go back to them. Upcoming steps never are. */
|
|
520
|
+
onStepClick?: (id: string) => void;
|
|
521
|
+
/** Default `horizontal`. Below `sm` a horizontal stepper shows only the current step ("Step 2 of 4"). */
|
|
522
|
+
orientation?: "horizontal" | "vertical";
|
|
523
|
+
className?: string;
|
|
524
|
+
}
|
|
525
|
+
export interface SegmentedOption {
|
|
526
|
+
value: string;
|
|
527
|
+
label: string;
|
|
528
|
+
icon?: IconName;
|
|
529
|
+
/** Show only the icon; `label` becomes its accessible name and tooltip. */
|
|
530
|
+
iconOnly?: boolean;
|
|
531
|
+
disabled?: boolean;
|
|
532
|
+
}
|
|
533
|
+
/** A row of 2–5 mutually exclusive choices that apply at once (view, period, unit). A radio group underneath. */
|
|
534
|
+
export interface SegmentedControlProps {
|
|
535
|
+
/** Accessible name of the group, e.g. "View". Required. */
|
|
536
|
+
label: string;
|
|
537
|
+
options: Array<SegmentedOption | string>;
|
|
538
|
+
value?: string;
|
|
539
|
+
defaultValue?: string;
|
|
540
|
+
onChange?: (value: string) => void;
|
|
541
|
+
/** `md` (default, 36px) or `sm` (28px) for toolbars. */
|
|
542
|
+
size?: "sm" | "md";
|
|
543
|
+
/** Stretch across the container, segments equal width. */
|
|
544
|
+
fullWidth?: boolean;
|
|
545
|
+
disabled?: boolean;
|
|
546
|
+
id?: string;
|
|
547
|
+
className?: string;
|
|
548
|
+
}
|
|
466
549
|
/** ISO date string, `YYYY-MM-DD` (Gregorian — the era is display only). */
|
|
467
550
|
export type ISODate = string;
|
|
468
551
|
export interface DateDisplayOptions {
|
|
@@ -832,10 +915,16 @@ export declare const Textarea: React$1.ForwardRefExoticComponent<TextareaProps &
|
|
|
832
915
|
export declare const Select: React$1.ForwardRefExoticComponent<SelectProps & React$1.RefAttributes<HTMLSelectElement>>;
|
|
833
916
|
export declare const RadioGroup: React$1.ForwardRefExoticComponent<RadioGroupProps & React$1.RefAttributes<HTMLFieldSetElement>>;
|
|
834
917
|
export declare const Switch: React$1.ForwardRefExoticComponent<SwitchProps & React$1.RefAttributes<HTMLButtonElement>>;
|
|
918
|
+
/** One value, or with `multiple` any number (chips). Two call signatures so value/onChange are typed for each. */
|
|
919
|
+
export interface ComboboxComponent {
|
|
920
|
+
(props: ComboboxMultipleProps & React$1.RefAttributes<HTMLInputElement>): React$1.ReactElement | null;
|
|
921
|
+
(props: ComboboxProps & React$1.RefAttributes<HTMLInputElement>): React$1.ReactElement | null;
|
|
922
|
+
displayName?: string;
|
|
923
|
+
}
|
|
835
924
|
/** The Thai-aware default filter: label, description and keywords contain the query. */
|
|
836
925
|
declare function defaultFilter(option: ComboboxOption, query: string): boolean;
|
|
837
|
-
/** Text field that filters a list as you type (ARIA 1.2 combobox). One value
|
|
838
|
-
export declare const Combobox:
|
|
926
|
+
/** Text field that filters a list as you type (ARIA 1.2 combobox). One value, or any number with `multiple`. */
|
|
927
|
+
export declare const Combobox: ComboboxComponent;
|
|
839
928
|
/** Options for formatDate: locale/calendar plus a preset or any Intl.DateTimeFormat options. */
|
|
840
929
|
export type FormatDateOptions = DateDisplayOptions & {
|
|
841
930
|
format?: "short" | "long" | "numeric" | Intl.DateTimeFormatOptions;
|
|
@@ -953,6 +1042,10 @@ export interface AuraStrings {
|
|
|
953
1042
|
fileWrongType: string;
|
|
954
1043
|
tooManyFiles: (n: number | string) => string;
|
|
955
1044
|
colorScheme: string;
|
|
1045
|
+
increase: string;
|
|
1046
|
+
decrease: string;
|
|
1047
|
+
stepDone: string;
|
|
1048
|
+
stepOf: (i: number, total: number) => string;
|
|
956
1049
|
schemeLight: string;
|
|
957
1050
|
schemeDark: string;
|
|
958
1051
|
schemeSystem: string;
|
|
@@ -1031,6 +1124,12 @@ export declare const EmptyState: React$1.ForwardRefExoticComponent<EmptyStatePro
|
|
|
1031
1124
|
export declare const Pagination: React$1.ForwardRefExoticComponent<PaginationProps & React$1.RefAttributes<HTMLElement>>;
|
|
1032
1125
|
export declare const Accordion: React$1.ForwardRefExoticComponent<AccordionProps & React$1.RefAttributes<HTMLDivElement>>;
|
|
1033
1126
|
export declare const Popover: React$1.ForwardRefExoticComponent<PopoverProps & React$1.RefAttributes<HTMLDivElement>>;
|
|
1127
|
+
/** Number input with thousands separators, +/− buttons and arrow keys (ARIA spinbutton). */
|
|
1128
|
+
export declare const NumberField: React$1.ForwardRefExoticComponent<NumberFieldProps & React$1.RefAttributes<HTMLInputElement>>;
|
|
1129
|
+
/** Progress through a multi-step flow. Completed steps can link back; the current one has aria-current="step". */
|
|
1130
|
+
export declare const Stepper: React$1.ForwardRefExoticComponent<StepperProps & React$1.RefAttributes<HTMLElement>>;
|
|
1131
|
+
/** A row of mutually exclusive choices that apply at once. A radio group: one Tab stop, arrow keys move and select. */
|
|
1132
|
+
export declare const SegmentedControl: React$1.ForwardRefExoticComponent<SegmentedControlProps & React$1.RefAttributes<HTMLDivElement>>;
|
|
1034
1133
|
|
|
1035
1134
|
export {
|
|
1036
1135
|
defaultFilter as comboboxFilter,
|
package/dist/styles.css
CHANGED
|
@@ -944,6 +944,107 @@ button.aura-stat { font: inherit; width: 100%; cursor: pointer; }
|
|
|
944
944
|
.aura-popover__head + .aura-popover__body { padding-top: var(--aura-space-2); }
|
|
945
945
|
@media (prefers-reduced-motion: reduce) { .aura-popover { animation: none; } }
|
|
946
946
|
|
|
947
|
+
/* ---------- Combobox, multiple: picks as chips in the field ---------- */
|
|
948
|
+
.aura-combo.is-multi { flex-wrap: wrap; align-items: center; gap: var(--aura-space-1); padding: 5px calc(var(--aura-space-2) + 2 * var(--aura-control-sm)) 5px calc(var(--aura-space-3) + var(--aura-icon-sm) + var(--aura-space-2)); }
|
|
949
|
+
.aura-combo.is-multi .aura-input__icon { top: calc(var(--aura-input-height) / 2 - var(--aura-icon-sm) / 2 - 1px); }
|
|
950
|
+
.aura-combo.is-multi .aura-input__control { flex: 1 0 4ch; height: 32px; padding: 0 var(--aura-space-1); }
|
|
951
|
+
/* Wrapped chips grow the field: keep the icon and buttons on the first line. */
|
|
952
|
+
.aura-combo.is-multi .aura-combo__clear, .aura-combo.is-multi .aura-combo__toggle { top: calc((var(--aura-input-height) - 2px - var(--aura-control-sm)) / 2); }
|
|
953
|
+
.aura-combo__chips { display: contents; }
|
|
954
|
+
.aura-combo__chip {
|
|
955
|
+
display: inline-flex; align-items: center; gap: 2px; max-width: 100%; height: 28px; box-sizing: border-box;
|
|
956
|
+
padding: 0 2px 0 var(--aura-space-2); border-radius: var(--aura-radius-full);
|
|
957
|
+
background: var(--aura-bg-selected); color: var(--aura-fg-primary); font-size: 13px; font-weight: 500;
|
|
958
|
+
}
|
|
959
|
+
.aura-combo__chip-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 24ch; }
|
|
960
|
+
.aura-combo__chip-remove {
|
|
961
|
+
display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; padding: 0;
|
|
962
|
+
border: 0; border-radius: var(--aura-radius-full); background: transparent; color: var(--aura-fg-secondary); cursor: pointer;
|
|
963
|
+
}
|
|
964
|
+
.aura-combo__chip-remove:hover { background: var(--aura-bg-surface-hover); color: var(--aura-fg-primary); }
|
|
965
|
+
.aura-combo__chip-remove .aura-icon { width: 14px; height: 14px; }
|
|
966
|
+
|
|
967
|
+
/* ---------- NumberField ---------- */
|
|
968
|
+
.aura-number .aura-input__control { font-variant-numeric: tabular-nums; }
|
|
969
|
+
.aura-number__affix { padding-left: var(--aura-space-3); color: var(--aura-fg-secondary); font-size: 14px; white-space: nowrap; }
|
|
970
|
+
.aura-number__affix + .aura-input__control { padding-left: var(--aura-space-2); }
|
|
971
|
+
.aura-input__control + .aura-number__affix { padding: 0 var(--aura-space-2) 0 0; }
|
|
972
|
+
.aura-number__steps { display: flex; align-self: stretch; border-left: 1px solid var(--aura-border-default); }
|
|
973
|
+
.aura-number__step {
|
|
974
|
+
display: inline-flex; align-items: center; justify-content: center; width: 36px; padding: 0;
|
|
975
|
+
border: 0; background: transparent; color: var(--aura-fg-secondary); cursor: pointer;
|
|
976
|
+
transition: background-color var(--aura-duration-fast) var(--aura-ease), color var(--aura-duration-fast) var(--aura-ease);
|
|
977
|
+
}
|
|
978
|
+
.aura-number__step + .aura-number__step { border-left: 1px solid var(--aura-border-default); }
|
|
979
|
+
.aura-number__step:last-child { border-radius: 0 calc(var(--aura-radius-md) - 1px) calc(var(--aura-radius-md) - 1px) 0; }
|
|
980
|
+
.aura-number__step:hover:not(:disabled) { background: var(--aura-bg-surface-hover); color: var(--aura-fg-primary); }
|
|
981
|
+
.aura-number__step:disabled { opacity: var(--aura-disabled-opacity); cursor: default; }
|
|
982
|
+
|
|
983
|
+
/* ---------- Stepper ---------- */
|
|
984
|
+
.aura-stepper { font-family: var(--font-sans); }
|
|
985
|
+
.aura-stepper__list { display: flex; list-style: none; margin: 0; padding: 0; }
|
|
986
|
+
.aura-stepper--vertical .aura-stepper__list { flex-direction: column; }
|
|
987
|
+
.aura-stepper__item { position: relative; flex: 1 1 0; min-width: 0; }
|
|
988
|
+
.aura-stepper__step {
|
|
989
|
+
display: flex; align-items: flex-start; gap: var(--aura-space-3); width: 100%; box-sizing: border-box; padding: 0 var(--aura-space-3) 0 0;
|
|
990
|
+
border: 0; background: none; color: inherit; font: inherit; text-align: left; border-radius: var(--aura-radius-md);
|
|
991
|
+
}
|
|
992
|
+
button.aura-stepper__step { cursor: pointer; }
|
|
993
|
+
button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underline; }
|
|
994
|
+
.aura-stepper__marker {
|
|
995
|
+
position: relative; z-index: 1; flex: none; display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; box-sizing: border-box;
|
|
996
|
+
border-radius: var(--aura-radius-full); border: 1px solid var(--aura-border-control); background: var(--aura-bg-surface);
|
|
997
|
+
color: var(--aura-fg-secondary); font-size: 13px; font-weight: 600; font-variant-numeric: tabular-nums;
|
|
998
|
+
}
|
|
999
|
+
.aura-stepper__marker .aura-icon { width: 16px; height: 16px; }
|
|
1000
|
+
.aura-stepper__item.is-done .aura-stepper__marker { background: var(--aura-button-primary-bg); border-color: var(--aura-button-primary-bg); color: var(--aura-button-primary-fg); }
|
|
1001
|
+
.aura-stepper__item.is-current .aura-stepper__marker { border: 2px solid var(--aura-fg-accent); color: var(--aura-fg-accent); }
|
|
1002
|
+
.aura-stepper__text { display: flex; flex-direction: column; min-width: 0; padding-top: 4px; }
|
|
1003
|
+
.aura-stepper__label { font-size: 13px; font-weight: 500; line-height: 1.4; color: var(--aura-fg-secondary); }
|
|
1004
|
+
.aura-stepper__item.is-current .aura-stepper__label, .aura-stepper__item.is-done .aura-stepper__label { color: var(--aura-fg-primary); }
|
|
1005
|
+
.aura-stepper__item.is-current .aura-stepper__label { font-weight: 600; }
|
|
1006
|
+
.aura-stepper__desc { font-size: 12px; line-height: 1.5; color: var(--aura-fg-secondary); }
|
|
1007
|
+
/* Connector: a line from each marker to the next (labels sit under the markers), or down the left when vertical. */
|
|
1008
|
+
.aura-stepper--horizontal .aura-stepper__item:not(:last-child)::after {
|
|
1009
|
+
content: ""; position: absolute; top: 14px; left: 36px; right: var(--aura-space-2); height: 1px; background: var(--aura-border-control); pointer-events: none;
|
|
1010
|
+
}
|
|
1011
|
+
.aura-stepper--horizontal .aura-stepper__step { flex-direction: column; gap: var(--aura-space-2); }
|
|
1012
|
+
.aura-stepper--horizontal .aura-stepper__text { padding-top: 0; }
|
|
1013
|
+
.aura-stepper--horizontal .aura-stepper__item.is-done::after { background: var(--aura-button-primary-bg); }
|
|
1014
|
+
.aura-stepper--vertical .aura-stepper__item { flex: none; padding-bottom: var(--aura-space-5); }
|
|
1015
|
+
.aura-stepper--vertical .aura-stepper__item:not(:last-child)::after {
|
|
1016
|
+
content: ""; position: absolute; left: 14px; top: 32px; bottom: 4px; width: 1px; background: var(--aura-border-control);
|
|
1017
|
+
}
|
|
1018
|
+
.aura-stepper--vertical .aura-stepper__item.is-done::after { background: var(--aura-button-primary-bg); }
|
|
1019
|
+
.aura-stepper__compact { display: none; margin: var(--aura-space-2) 0 0; font-size: 13px; }
|
|
1020
|
+
.aura-stepper__count { color: var(--aura-fg-secondary); margin-right: var(--aura-space-2); }
|
|
1021
|
+
.aura-stepper__compact-label { font-weight: 600; }
|
|
1022
|
+
|
|
1023
|
+
/* ---------- SegmentedControl ---------- */
|
|
1024
|
+
.aura-segmented {
|
|
1025
|
+
display: inline-flex; gap: 2px; padding: 2px; box-sizing: border-box; max-width: 100%;
|
|
1026
|
+
border: 1px solid var(--aura-border-default); border-radius: var(--aura-radius-full); background: var(--aura-bg-surface-hover);
|
|
1027
|
+
font-family: var(--font-sans);
|
|
1028
|
+
}
|
|
1029
|
+
.aura-segmented:not(.is-full) { width: fit-content; justify-self: start; align-self: flex-start; }
|
|
1030
|
+
.aura-segmented.is-full { display: flex; width: 100%; }
|
|
1031
|
+
.aura-segmented__option {
|
|
1032
|
+
flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; gap: 6px;
|
|
1033
|
+
height: 32px; padding: 0 var(--aura-space-4); box-sizing: border-box;
|
|
1034
|
+
border: 0; border-radius: var(--aura-radius-full); background: transparent; color: var(--aura-fg-secondary);
|
|
1035
|
+
font: inherit; font-size: 13px; font-weight: 500; white-space: nowrap; cursor: pointer;
|
|
1036
|
+
transition: background-color var(--aura-duration-fast) var(--aura-ease), color var(--aura-duration-fast) var(--aura-ease), box-shadow var(--aura-duration-fast) var(--aura-ease);
|
|
1037
|
+
}
|
|
1038
|
+
.aura-segmented.is-full .aura-segmented__option { flex: 1 1 0; min-width: 0; }
|
|
1039
|
+
.aura-segmented__option.is-icon { padding: 0; width: 36px; }
|
|
1040
|
+
.aura-segmented__option:hover:not(:disabled):not(.is-selected) { color: var(--aura-fg-primary); }
|
|
1041
|
+
.aura-segmented__option.is-selected { background: var(--aura-bg-surface); color: var(--aura-fg-primary); box-shadow: var(--aura-shadow-enterprise); }
|
|
1042
|
+
.aura-segmented__option:focus-visible { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: 1px; }
|
|
1043
|
+
.aura-segmented__option:disabled { opacity: var(--aura-disabled-opacity); cursor: default; }
|
|
1044
|
+
.aura-segmented--sm .aura-segmented__option { height: 24px; padding: 0 var(--aura-space-3); font-size: 12px; }
|
|
1045
|
+
.aura-segmented--sm .aura-segmented__option.is-icon { width: 28px; padding: 0; }
|
|
1046
|
+
.aura-segmented.is-disabled { opacity: var(--aura-disabled-opacity); }
|
|
1047
|
+
|
|
947
1048
|
/* A field inside a row Stack takes the remaining width (a search box beside its button). */
|
|
948
1049
|
.aura-stack > .aura-field { flex: 1 1 auto; min-width: 0; }
|
|
949
1050
|
|
|
@@ -951,10 +1052,16 @@ button.aura-stat { font: inherit; width: 100%; cursor: pointer; }
|
|
|
951
1052
|
@media (pointer: coarse) {
|
|
952
1053
|
.aura-cal { --aura-cal-cell: 40px; }
|
|
953
1054
|
.aura-combo__option { min-height: 44px; }
|
|
1055
|
+
.aura-segmented__option, .aura-segmented--sm .aura-segmented__option { height: 40px; }
|
|
1056
|
+
.aura-number__step { width: 44px; }
|
|
954
1057
|
}
|
|
955
1058
|
|
|
956
1059
|
/* ---------- Small screens (< 640px) ---------- */
|
|
957
1060
|
@media (max-width: 639.98px) {
|
|
1061
|
+
/* Horizontal stepper on phones: markers only (names kept for screen readers), the current step named underneath. */
|
|
1062
|
+
.aura-stepper--horizontal .aura-stepper__text { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; padding: 0; }
|
|
1063
|
+
.aura-stepper--horizontal .aura-stepper__item:not(:last-child)::after { right: 8px; }
|
|
1064
|
+
.aura-stepper--horizontal .aura-stepper__compact { display: block; }
|
|
958
1065
|
.aura-dialog-layer:not(.aura-drawer-layer) { align-items: flex-end; padding: 0; }
|
|
959
1066
|
.aura-dialog { max-width: none !important; max-height: 92vh; border-radius: var(--aura-radius-2xl) var(--aura-radius-2xl) 0 0; border-bottom: 0;
|
|
960
1067
|
padding-bottom: calc(var(--aura-space-6) + env(safe-area-inset-bottom)); animation-name: aura-sheet-in; }
|
package/package.json
CHANGED