@octanejs/aria 0.0.22 → 0.0.24
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/package.json
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@octanejs/aria",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.24",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
|
+
"sideEffects": [
|
|
7
|
+
"./src/index.ts",
|
|
8
|
+
"./src/interactions/useFocusVisible.ts",
|
|
9
|
+
"./src/utils/runAfterTransition.ts"
|
|
10
|
+
],
|
|
6
11
|
"engines": {
|
|
7
12
|
"node": ">=22.22.2"
|
|
8
13
|
},
|
|
@@ -46,7 +51,7 @@
|
|
|
46
51
|
"clsx": "^2.1.1"
|
|
47
52
|
},
|
|
48
53
|
"peerDependencies": {
|
|
49
|
-
"octane": "0.1.
|
|
54
|
+
"octane": "0.1.30"
|
|
50
55
|
},
|
|
51
56
|
"devDependencies": {
|
|
52
57
|
"@tsrx/react": "^0.2.56",
|
|
@@ -57,7 +62,7 @@
|
|
|
57
62
|
"react-dom": "^19.2.7",
|
|
58
63
|
"react-stately": "3.48.0",
|
|
59
64
|
"vitest": "^4.1.10",
|
|
60
|
-
"octane": "0.1.
|
|
65
|
+
"octane": "0.1.30"
|
|
61
66
|
},
|
|
62
67
|
"scripts": {
|
|
63
68
|
"test": "vitest run"
|
package/src/index.ts
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
// upstream monopackage index (.react-spectrum/packages/react-aria/exports/index.ts) and
|
|
3
3
|
// grow area-by-area with the migration plan (docs/aria-migration-plan.md).
|
|
4
4
|
|
|
5
|
+
// Keep global transition tracking reachable when unused behavior hooks are tree-shaken.
|
|
6
|
+
import './utils/runAfterTransition';
|
|
7
|
+
|
|
5
8
|
// button
|
|
6
9
|
export { useButton } from './button/useButton';
|
|
7
10
|
export { useToggleButton } from './button/useToggleButton';
|
|
@@ -18,7 +18,7 @@ import type {
|
|
|
18
18
|
ValueBase,
|
|
19
19
|
} from '@react-types/shared';
|
|
20
20
|
import { NumberFormatter, NumberParser } from '@internationalized/number';
|
|
21
|
-
import { useCallback, useMemo, useState } from 'octane';
|
|
21
|
+
import { useCallback, useLinkedState, useMemo, useState } from 'octane';
|
|
22
22
|
|
|
23
23
|
import type { FocusableProps } from '../../interactions/useFocusable';
|
|
24
24
|
|
|
@@ -111,6 +111,12 @@ export interface NumberFieldStateOptions extends NumberFieldProps {
|
|
|
111
111
|
locale: string;
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
+
interface NumberFieldInputSource {
|
|
115
|
+
value: number;
|
|
116
|
+
locale: string;
|
|
117
|
+
formatOptions: Intl.NumberFormatOptions | undefined;
|
|
118
|
+
}
|
|
119
|
+
|
|
114
120
|
/**
|
|
115
121
|
* Provides state management for a number field component. Number fields allow users to enter a
|
|
116
122
|
* number, and increment or decrement the value using stepper buttons.
|
|
@@ -169,17 +175,60 @@ export function useNumberFieldState(...args: any[]): NumberFieldState {
|
|
|
169
175
|
subSlot(slot, 'number'),
|
|
170
176
|
);
|
|
171
177
|
let [initialValue] = useState(numberValue, subSlot(slot, 'initial'));
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
178
|
+
const providedFormatOptions = formatOptions;
|
|
179
|
+
// Normalize parser rounding options before linked-source comparison or formatting.
|
|
180
|
+
let [numberParser, normalizedFormatOptions] = useMemo(
|
|
181
|
+
() => {
|
|
182
|
+
let normalizedOptions = formatOptions;
|
|
183
|
+
if (
|
|
184
|
+
normalizedOptions?.roundingIncrement != null &&
|
|
185
|
+
normalizedOptions.roundingIncrement !== 1 &&
|
|
186
|
+
(normalizedOptions.minimumFractionDigits == null ||
|
|
187
|
+
normalizedOptions.maximumFractionDigits == null)
|
|
188
|
+
) {
|
|
189
|
+
const fractionDigits =
|
|
190
|
+
normalizedOptions.minimumFractionDigits ?? normalizedOptions.maximumFractionDigits ?? 0;
|
|
191
|
+
normalizedOptions = {
|
|
192
|
+
...normalizedOptions,
|
|
193
|
+
minimumFractionDigits: normalizedOptions.minimumFractionDigits ?? fractionDigits,
|
|
194
|
+
maximumFractionDigits: normalizedOptions.maximumFractionDigits ?? fractionDigits,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
return [new NumberParser(locale, normalizedOptions), normalizedOptions] as const;
|
|
198
|
+
},
|
|
180
199
|
[locale, formatOptions],
|
|
181
200
|
subSlot(slot, 'parser'),
|
|
182
201
|
);
|
|
202
|
+
formatOptions = normalizedFormatOptions;
|
|
203
|
+
let [inputValue, setInputValue] = useLinkedState<NumberFieldInputSource, string>(
|
|
204
|
+
{ value: numberValue, locale, formatOptions },
|
|
205
|
+
(source, previous) => {
|
|
206
|
+
if (isNaN(source.value)) {
|
|
207
|
+
return '';
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// React formats initial currencies before their parser normalizes rounding digits.
|
|
211
|
+
let options =
|
|
212
|
+
previous === undefined &&
|
|
213
|
+
providedFormatOptions?.style === 'currency' &&
|
|
214
|
+
providedFormatOptions.minimumFractionDigits == null &&
|
|
215
|
+
providedFormatOptions.maximumFractionDigits == null
|
|
216
|
+
? providedFormatOptions
|
|
217
|
+
: source.formatOptions;
|
|
218
|
+
if (previous !== undefined) {
|
|
219
|
+
const numberingSystem = numberParser.getNumberingSystem(previous.value);
|
|
220
|
+
options = { ...source.formatOptions, numberingSystem };
|
|
221
|
+
}
|
|
222
|
+
return new NumberFormatter(source.locale, options).format(source.value);
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
sourceEqual: (previous, next) =>
|
|
226
|
+
Object.is(previous.value, next.value) &&
|
|
227
|
+
previous.locale === next.locale &&
|
|
228
|
+
isEqualFormatOptions(previous.formatOptions, next.formatOptions),
|
|
229
|
+
},
|
|
230
|
+
subSlot(slot, 'input'),
|
|
231
|
+
);
|
|
183
232
|
let numberingSystem = useMemo(
|
|
184
233
|
() => numberParser.getNumberingSystem(inputValue),
|
|
185
234
|
[numberParser, inputValue],
|
|
@@ -210,26 +259,6 @@ export function useNumberFieldState(...args: any[]): NumberFieldState {
|
|
|
210
259
|
clampStep = 0.01;
|
|
211
260
|
}
|
|
212
261
|
|
|
213
|
-
// Update the input value when the number value or format options change. This is done
|
|
214
|
-
// in a useEffect so that the controlled behavior is correct and we only update the
|
|
215
|
-
// textfield after prop changes.
|
|
216
|
-
let [prevValue, setPrevValue] = useState(numberValue, subSlot(slot, 'prevValue'));
|
|
217
|
-
let [prevLocale, setPrevLocale] = useState(locale, subSlot(slot, 'prevLocale'));
|
|
218
|
-
let [prevFormatOptions, setPrevFormatOptions] = useState(
|
|
219
|
-
formatOptions,
|
|
220
|
-
subSlot(slot, 'prevFormat'),
|
|
221
|
-
);
|
|
222
|
-
if (
|
|
223
|
-
!Object.is(numberValue, prevValue) ||
|
|
224
|
-
locale !== prevLocale ||
|
|
225
|
-
!isEqualFormatOptions(formatOptions, prevFormatOptions)
|
|
226
|
-
) {
|
|
227
|
-
setInputValue(format(numberValue));
|
|
228
|
-
setPrevValue(numberValue);
|
|
229
|
-
setPrevLocale(locale);
|
|
230
|
-
setPrevFormatOptions(formatOptions);
|
|
231
|
-
}
|
|
232
|
-
|
|
233
262
|
let parsedValue = useMemo(
|
|
234
263
|
() => numberParser.parse(inputValue),
|
|
235
264
|
[numberParser, inputValue],
|