@astryxdesign/core 0.5.1 → 0.5.2-canary.1917581
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/CHANGELOG.md +19 -0
- package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheet.js +1 -1
- package/dist/BottomSheet/BottomSheetEdgeTint.d.ts +2 -2
- package/dist/BottomSheet/BottomSheetEdgeTint.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheetEdgeTint.js +7 -10
- package/dist/BottomSheet/BottomSheetSwitcher.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheetSwitcher.js +1 -1
- package/dist/Button/Button.d.ts +2 -1
- package/dist/Button/Button.d.ts.map +1 -1
- package/dist/Button/Button.js +11 -4
- package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
- package/dist/Chat/ChatToolCalls.js +34 -17
- package/dist/Popover/Popover.d.ts +10 -6
- package/dist/Popover/Popover.d.ts.map +1 -1
- package/dist/Popover/Popover.js +141 -16
- package/dist/Popover/usePopover.d.ts +4 -0
- package/dist/Popover/usePopover.d.ts.map +1 -1
- package/dist/Popover/usePopover.js +52 -5
- package/dist/Toast/useToastGesture.d.ts.map +1 -1
- package/dist/Toast/useToastGesture.js +46 -9
- package/dist/astryx.css +10 -0
- package/dist/hooks/useFocusTrap.d.ts.map +1 -1
- package/dist/hooks/useFocusTrap.js +12 -0
- package/dist/i18n/InternationalizationContext.d.ts +2 -0
- package/dist/i18n/InternationalizationContext.d.ts.map +1 -1
- package/dist/i18n/InternationalizationContext.js +3 -1
- package/dist/i18n/InternationalizationProvider.d.ts.map +1 -1
- package/dist/i18n/InternationalizationProvider.js +3 -1
- package/dist/i18n/resolve.d.ts +1 -1
- package/dist/i18n/resolve.d.ts.map +1 -1
- package/dist/i18n/resolve.js +37 -38
- package/dist/i18n/useTranslator.d.ts.map +1 -1
- package/dist/i18n/useTranslator.js +2 -3
- package/locales/af-ZA.json +0 -4
- package/locales/ar-SA.json +0 -4
- package/locales/ca-ES.json +0 -4
- package/locales/cs-CZ.json +0 -4
- package/locales/da-DK.json +0 -4
- package/locales/de-DE.json +0 -4
- package/locales/el-GR.json +0 -4
- package/locales/en.json +16 -0
- package/locales/es-ES.json +0 -4
- package/locales/fi-FI.json +0 -4
- package/locales/fr-FR.json +0 -4
- package/locales/he-IL.json +0 -4
- package/locales/hu-HU.json +0 -4
- package/locales/it-IT.json +0 -4
- package/locales/ja-JP.json +0 -4
- package/locales/ko-KR.json +0 -4
- package/locales/nl-NL.json +0 -4
- package/locales/no-NO.json +0 -4
- package/locales/pl-PL.json +0 -4
- package/locales/pseudo.json +12 -0
- package/locales/pt-BR.json +0 -4
- package/locales/pt-PT.json +0 -4
- package/locales/ro-RO.json +0 -4
- package/locales/ru-RU.json +0 -4
- package/locales/sr-SP.json +0 -4
- package/locales/sv-SE.json +0 -4
- package/locales/tr-TR.json +0 -4
- package/locales/uk-UA.json +0 -4
- package/locales/vi-VN.json +0 -4
- package/locales/zh-CN.json +0 -4
- package/locales/zh-TW.json +0 -4
- package/package.json +3 -3
- package/src/BottomSheet/BottomSheet.tsx +1 -2
- package/src/BottomSheet/BottomSheetEdgeTint.test.tsx +4 -6
- package/src/BottomSheet/BottomSheetEdgeTint.tsx +7 -10
- package/src/BottomSheet/BottomSheetSwitcher.tsx +1 -2
- package/src/Button/Button.test.tsx +10 -0
- package/src/Button/Button.tsx +13 -5
- package/src/Calendar/Calendar.doc.mjs +1 -1
- package/src/Chat/ChatToolCalls.test.tsx +44 -0
- package/src/Chat/ChatToolCalls.tsx +36 -15
- package/src/CheckboxInput/CheckboxInput.doc.mjs +1 -1
- package/src/CheckboxList/CheckboxList.doc.mjs +1 -1
- package/src/ComplexSelector/ComplexSelector.doc.mjs +2 -2
- package/src/DateInput/DateInput.doc.mjs +1 -1
- package/src/DateRangeInput/DateRangeInput.doc.mjs +1 -1
- package/src/DateTimeInput/DateTimeInput.doc.mjs +1 -1
- package/src/Field/Field.doc.mjs +1 -1
- package/src/FieldStatus/FieldStatus.doc.mjs +1 -1
- package/src/FileInput/FileInput.doc.mjs +1 -1
- package/src/Indicator/Indicator.doc.mjs +1 -1
- package/src/InputGroup/InputGroup.doc.mjs +1 -1
- package/src/MultiSelector/MultiSelector.doc.mjs +1 -1
- package/src/NumberInput/NumberInput.doc.mjs +1 -1
- package/src/Popover/Popover.doc.mjs +11 -11
- package/src/Popover/Popover.test.tsx +397 -2
- package/src/Popover/Popover.tsx +228 -21
- package/src/Popover/usePopover.tsx +92 -15
- package/src/PowerSearch/PowerSearch.doc.mjs +1 -1
- package/src/RadioList/RadioList.doc.mjs +1 -1
- package/src/Selector/Selector.doc.mjs +1 -1
- package/src/Slider/Slider.doc.mjs +2 -2
- package/src/Switch/Switch.doc.mjs +1 -1
- package/src/TextArea/TextArea.doc.mjs +1 -1
- package/src/TextInput/TextInput.doc.mjs +1 -1
- package/src/TimeInput/TimeInput.doc.mjs +1 -1
- package/src/Toast/ToastViewport.test.tsx +118 -4
- package/src/Toast/useToastGesture.ts +61 -8
- package/src/Tokenizer/Tokenizer.doc.mjs +1 -1
- package/src/Typeahead/Typeahead.doc.mjs +1 -1
- package/src/hooks/useFocusTrap.test.tsx +40 -0
- package/src/hooks/useFocusTrap.ts +13 -0
- package/src/i18n/InternationalizationContext.ts +3 -0
- package/src/i18n/InternationalizationProvider.tsx +8 -1
- package/src/i18n/__tests__/resolve.test.ts +23 -1
- package/src/i18n/resolve.ts +46 -49
- package/src/i18n/useTranslator.ts +2 -7
|
@@ -22,6 +22,7 @@ import { LayerDepthProvider } from "../Layer/LayerDepthContext.js";
|
|
|
22
22
|
import "../theme/tokens.stylex.js";
|
|
23
23
|
import { colorVars, spacingVars, radiusVars, shadowVars } from "../theme/tokens.stylex.js";
|
|
24
24
|
import { Button } from "../Button/index.js";
|
|
25
|
+
import { FOCUSABLE_SELECTOR } from "../hooks/focusableSelector.js";
|
|
25
26
|
import { rtlStyles } from "../utils/index.js";
|
|
26
27
|
import { useTranslator } from "../i18n/index.js";
|
|
27
28
|
import { useDevWarning } from "../hooks/useDevWarning.js";
|
|
@@ -29,6 +30,24 @@ import { mergeProps } from "../utils/mergeProps.js";
|
|
|
29
30
|
import { themeProps } from "../utils/themeProps.js";
|
|
30
31
|
import { stableClassName } from "../naming.js";
|
|
31
32
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
33
|
+
const FALLBACK_CLOSE_SELECTOR = '[data-astryx-popover-fallback-close]';
|
|
34
|
+
function attemptFocus(element) {
|
|
35
|
+
try {
|
|
36
|
+
element.focus();
|
|
37
|
+
} catch {
|
|
38
|
+
// Ignore non-focusable elements; the caller will try the next target.
|
|
39
|
+
}
|
|
40
|
+
return document.activeElement === element;
|
|
41
|
+
}
|
|
42
|
+
function focusFirstContentControl(container) {
|
|
43
|
+
const focusable = Array.from(container.querySelectorAll(FOCUSABLE_SELECTOR)).filter(element => element.closest(FALLBACK_CLOSE_SELECTOR) == null);
|
|
44
|
+
for (const element of focusable) {
|
|
45
|
+
if (attemptFocus(element)) {
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
32
51
|
const styles = {
|
|
33
52
|
surface: {
|
|
34
53
|
kWkggS: "x1prclbq",
|
|
@@ -39,6 +58,7 @@ const styles = {
|
|
|
39
58
|
},
|
|
40
59
|
contentWrapper: {
|
|
41
60
|
kVAEAm: "x1n2onr6",
|
|
61
|
+
kI3sdo: "x1a2a7pz",
|
|
42
62
|
$$css: true
|
|
43
63
|
},
|
|
44
64
|
closeButtonWrapper: {
|
|
@@ -129,6 +149,7 @@ function usePopoverImplementation(options = {}) {
|
|
|
129
149
|
|
|
130
150
|
// Track whether to skip auto-focus for the current open event
|
|
131
151
|
const skipAutoFocusRef = useRef(false);
|
|
152
|
+
const focusTargetRef = useRef('first');
|
|
132
153
|
|
|
133
154
|
// Core layer for popover positioning
|
|
134
155
|
const layer = useLayerInternal({
|
|
@@ -148,20 +169,40 @@ function usePopoverImplementation(options = {}) {
|
|
|
148
169
|
isActive: layer.isOpen,
|
|
149
170
|
onEscape: hasEscapeDismiss || hasLightDismiss ? layer.hide : undefined
|
|
150
171
|
});
|
|
172
|
+
const focusInitialTarget = useCallback(() => {
|
|
173
|
+
const container = contentRef.current;
|
|
174
|
+
if (!container) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
if (focusFirstContentControl(container)) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
if (role === 'dialog') {
|
|
181
|
+
attemptFocus(container);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
focusFirst();
|
|
185
|
+
}, [contentRef, focusFirst, role]);
|
|
151
186
|
|
|
152
187
|
// Auto-focus first element when popover opens (unless skipped)
|
|
153
188
|
useEffect(() => {
|
|
154
189
|
if (layer.isOpen && hasAutoFocus && !skipAutoFocusRef.current) {
|
|
155
190
|
// Use requestAnimationFrame to ensure DOM is ready
|
|
156
191
|
requestAnimationFrame(() => {
|
|
157
|
-
|
|
192
|
+
const container = contentRef.current;
|
|
193
|
+
if (focusTargetRef.current === 'container' && role === 'dialog' && container) {
|
|
194
|
+
attemptFocus(container);
|
|
195
|
+
} else {
|
|
196
|
+
focusInitialTarget();
|
|
197
|
+
}
|
|
158
198
|
});
|
|
159
199
|
}
|
|
160
|
-
// Reset
|
|
200
|
+
// Reset per-open focus preferences after the popover closes.
|
|
161
201
|
if (!layer.isOpen) {
|
|
162
202
|
skipAutoFocusRef.current = false;
|
|
203
|
+
focusTargetRef.current = 'first';
|
|
163
204
|
}
|
|
164
|
-
}, [layer.isOpen, hasAutoFocus,
|
|
205
|
+
}, [contentRef, layer.isOpen, hasAutoFocus, focusInitialTarget, role]);
|
|
165
206
|
|
|
166
207
|
// Combined ref for trigger element (layer anchor + our ref)
|
|
167
208
|
const triggerRef = useCallback(el => {
|
|
@@ -172,20 +213,22 @@ function usePopoverImplementation(options = {}) {
|
|
|
172
213
|
// Show function with optional skipAutoFocus
|
|
173
214
|
const show = useCallback(showOptions => {
|
|
174
215
|
skipAutoFocusRef.current = showOptions?.skipAutoFocus ?? false;
|
|
216
|
+
focusTargetRef.current = showOptions?.focusTarget ?? 'first';
|
|
175
217
|
layer.show();
|
|
176
218
|
}, [layer]);
|
|
177
219
|
|
|
178
220
|
// Toggle function
|
|
179
|
-
const
|
|
221
|
+
const toggleWithOptions = useCallback(showOptions => {
|
|
180
222
|
if (layer.wasJustDismissed()) {
|
|
181
223
|
return;
|
|
182
224
|
}
|
|
183
225
|
if (layer.isOpen) {
|
|
184
226
|
layer.hide();
|
|
185
227
|
} else {
|
|
186
|
-
show();
|
|
228
|
+
show(showOptions);
|
|
187
229
|
}
|
|
188
230
|
}, [layer, show]);
|
|
231
|
+
const toggle = useCallback(() => toggleWithOptions(), [toggleWithOptions]);
|
|
189
232
|
|
|
190
233
|
// ARIA attributes for the trigger
|
|
191
234
|
const triggerProps = {
|
|
@@ -210,11 +253,13 @@ function usePopoverImplementation(options = {}) {
|
|
|
210
253
|
role: role === 'dialog' ? 'dialog' : undefined,
|
|
211
254
|
"aria-modal": role === 'dialog' && isModal ? true : undefined,
|
|
212
255
|
"aria-label": role === 'dialog' ? dialogLabel : undefined,
|
|
256
|
+
tabIndex: role === 'dialog' ? -1 : undefined,
|
|
213
257
|
...mergeProps({
|
|
214
258
|
...surfaceProps,
|
|
215
259
|
className: surfaceClassName
|
|
216
260
|
}, stylex.props(styles.contentWrapper, hasSurface && styles.surface, xstyle), className, style),
|
|
217
261
|
children: [children, hasCloseButton && /*#__PURE__*/_jsx("div", {
|
|
262
|
+
"data-astryx-popover-fallback-close": "",
|
|
218
263
|
...stylex.props(styles.closeButtonWrapper, rtlStyles.centerInline('100%')),
|
|
219
264
|
children: /*#__PURE__*/_jsx(Button, {
|
|
220
265
|
variant: "secondary",
|
|
@@ -235,6 +280,7 @@ function usePopoverImplementation(options = {}) {
|
|
|
235
280
|
show,
|
|
236
281
|
hide: layer.hide,
|
|
237
282
|
toggle,
|
|
283
|
+
toggleWithOptions,
|
|
238
284
|
wasJustDismissed: layer.wasJustDismissed,
|
|
239
285
|
isOpen: layer.isOpen,
|
|
240
286
|
id: layer.id,
|
|
@@ -245,6 +291,7 @@ function usePopoverImplementation(options = {}) {
|
|
|
245
291
|
export function usePopover(options = {}) {
|
|
246
292
|
const {
|
|
247
293
|
wasJustDismissed: _,
|
|
294
|
+
toggleWithOptions: __,
|
|
248
295
|
...popover
|
|
249
296
|
} = usePopoverImplementation(options);
|
|
250
297
|
return popover;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useToastGesture.d.ts","sourceRoot":"","sources":["../../src/Toast/useToastGesture.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAC,YAAY,IAAI,iBAAiB,EAAE,SAAS,EAAC,MAAM,OAAO,CAAC;AAWxE,MAAM,MAAM,qBAAqB,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"useToastGesture.d.ts","sourceRoot":"","sources":["../../src/Toast/useToastGesture.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAC,YAAY,IAAI,iBAAiB,EAAE,SAAS,EAAC,MAAM,OAAO,CAAC;AAWxE,MAAM,MAAM,qBAAqB,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;AAsB3C,UAAU,sBAAsB;IAC9B,SAAS,EAAE,qBAAqB,CAAC;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,MAAM,OAAO,CAAC;IAC7B,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,kBAAkB,EAAE,CAClB,MAAM,EAAE,WAAW,GAAG,IAAI,EAC1B,IAAI,EAAE,WAAW,KACd,OAAO,CAAC;CACd;AAED,UAAU,oBAAoB;IAC5B,aAAa,EAAE,CAAC,KAAK,EAAE,iBAAiB,CAAC,cAAc,CAAC,KAAK,IAAI,CAAC;IAClE,aAAa,EAAE,CAAC,KAAK,EAAE,iBAAiB,CAAC,cAAc,CAAC,KAAK,IAAI,CAAC;IAClE,WAAW,EAAE,CAAC,KAAK,EAAE,iBAAiB,CAAC,cAAc,CAAC,KAAK,IAAI,CAAC;IAChE,eAAe,EAAE,CAAC,KAAK,EAAE,iBAAiB,CAAC,cAAc,CAAC,KAAK,IAAI,CAAC;IACpE,oBAAoB,EAAE,CAAC,KAAK,EAAE,iBAAiB,CAAC,cAAc,CAAC,KAAK,IAAI,CAAC;CAC1E;AAED,UAAU,qBAAqB;IAC7B,OAAO,EAAE,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IAC1C,QAAQ,EAAE,oBAAoB,CAAC;CAChC;AAcD,wBAAgB,eAAe,CAAC,EAC9B,SAAS,EACT,OAAO,EACP,aAAa,EACb,aAAa,EACb,UAAU,EACV,WAAW,EACX,OAAO,EACP,kBAAkB,GACnB,EAAE,sBAAsB,GAAG,qBAAqB,CA+ThD"}
|
|
@@ -62,6 +62,7 @@ export function useToastGesture({
|
|
|
62
62
|
}
|
|
63
63
|
const surfaceSize = Math.max(root.getBoundingClientRect().height, 1);
|
|
64
64
|
gestureRef.current = {
|
|
65
|
+
source: point.source,
|
|
65
66
|
pointerId: point.pointerId,
|
|
66
67
|
startX: point.clientX,
|
|
67
68
|
startY: point.clientY,
|
|
@@ -77,7 +78,7 @@ export function useToastGesture({
|
|
|
77
78
|
const moveGesture = useCallback((point, preventDefault, releaseCapture) => {
|
|
78
79
|
const state = gestureRef.current;
|
|
79
80
|
const root = rootRef.current;
|
|
80
|
-
if (!state || !root || point.pointerId !== state.pointerId) {
|
|
81
|
+
if (!state || !root || point.source !== state.source || point.pointerId !== state.pointerId) {
|
|
81
82
|
return;
|
|
82
83
|
}
|
|
83
84
|
const deltaX = point.clientX - state.startX;
|
|
@@ -111,7 +112,7 @@ export function useToastGesture({
|
|
|
111
112
|
const endGesture = useCallback(point => {
|
|
112
113
|
const state = gestureRef.current;
|
|
113
114
|
const root = rootRef.current;
|
|
114
|
-
if (!state || !root || point.pointerId !== state.pointerId) {
|
|
115
|
+
if (!state || !root || point.source !== state.source || point.pointerId !== state.pointerId) {
|
|
115
116
|
return;
|
|
116
117
|
}
|
|
117
118
|
const travel = Math.max(0, (point.clientY - state.startY) * state.direction);
|
|
@@ -120,6 +121,10 @@ export function useToastGesture({
|
|
|
120
121
|
gestureRef.current = null;
|
|
121
122
|
root.style.removeProperty('transition-duration');
|
|
122
123
|
if (isDismissed) {
|
|
124
|
+
// The exit animation owns the final translation. Clear the live-drag
|
|
125
|
+
// transform/fade/scale first so a standalone Toast does not remain
|
|
126
|
+
// partially translated or faded after its dismiss callback fires.
|
|
127
|
+
clearTransientStyles(root);
|
|
123
128
|
root.style.setProperty('--_toast-swipe-exit-y', state.direction === 1 ? SWIPE_EXIT_DISTANCE : `calc(-1 * ${SWIPE_EXIT_DISTANCE})`);
|
|
124
129
|
dismiss();
|
|
125
130
|
return;
|
|
@@ -130,7 +135,12 @@ export function useToastGesture({
|
|
|
130
135
|
}
|
|
131
136
|
}, [dismiss, resumeTimer]);
|
|
132
137
|
const handlePointerDown = useCallback(event => {
|
|
133
|
-
if (event.pointerType === 'pen' && (event.button == null || event.button === 0) && beginGesture(
|
|
138
|
+
if (event.pointerType === 'pen' && (event.button == null || event.button === 0) && beginGesture({
|
|
139
|
+
source: 'pen',
|
|
140
|
+
pointerId: event.pointerId,
|
|
141
|
+
clientX: event.clientX,
|
|
142
|
+
clientY: event.clientY
|
|
143
|
+
}, event.target)) {
|
|
134
144
|
rootRef.current?.setPointerCapture?.(event.pointerId);
|
|
135
145
|
}
|
|
136
146
|
}, [beginGesture]);
|
|
@@ -138,17 +148,27 @@ export function useToastGesture({
|
|
|
138
148
|
if (event.pointerType !== 'pen') {
|
|
139
149
|
return;
|
|
140
150
|
}
|
|
141
|
-
moveGesture(
|
|
151
|
+
moveGesture({
|
|
152
|
+
source: 'pen',
|
|
153
|
+
pointerId: event.pointerId,
|
|
154
|
+
clientX: event.clientX,
|
|
155
|
+
clientY: event.clientY
|
|
156
|
+
}, () => event.preventDefault(), () => rootRef.current?.releasePointerCapture?.(event.pointerId));
|
|
142
157
|
}, [moveGesture]);
|
|
143
158
|
const handlePointerUp = useCallback(event => {
|
|
144
159
|
if (event.pointerType !== 'pen') {
|
|
145
160
|
return;
|
|
146
161
|
}
|
|
147
162
|
rootRef.current?.releasePointerCapture?.(event.pointerId);
|
|
148
|
-
endGesture(
|
|
163
|
+
endGesture({
|
|
164
|
+
source: 'pen',
|
|
165
|
+
pointerId: event.pointerId,
|
|
166
|
+
clientX: event.clientX,
|
|
167
|
+
clientY: event.clientY
|
|
168
|
+
});
|
|
149
169
|
}, [endGesture]);
|
|
150
170
|
const handlePointerCancel = useCallback(event => {
|
|
151
|
-
if (event.pointerType === 'pen' && gestureRef.current?.pointerId === event.pointerId) {
|
|
171
|
+
if (event.pointerType === 'pen' && gestureRef.current?.source === 'pen' && gestureRef.current?.pointerId === event.pointerId) {
|
|
152
172
|
resetGesture(true);
|
|
153
173
|
}
|
|
154
174
|
}, [resetGesture]);
|
|
@@ -158,21 +178,34 @@ export function useToastGesture({
|
|
|
158
178
|
return;
|
|
159
179
|
}
|
|
160
180
|
const point = touch => ({
|
|
181
|
+
source: 'touch',
|
|
161
182
|
pointerId: touch.identifier,
|
|
162
183
|
clientX: touch.clientX,
|
|
163
184
|
clientY: touch.clientY
|
|
164
185
|
});
|
|
165
186
|
const changedTouch = event => {
|
|
166
|
-
const
|
|
187
|
+
const state = gestureRef.current;
|
|
188
|
+
const pointerId = state?.source === 'touch' ? state.pointerId : null;
|
|
167
189
|
return pointerId == null ? undefined : [...event.changedTouches].find(touch => touch.identifier === pointerId);
|
|
168
190
|
};
|
|
169
191
|
const handleTouchStart = event => {
|
|
170
|
-
|
|
171
|
-
|
|
192
|
+
if (event.touches?.length !== 1) {
|
|
193
|
+
// A second contact means the browser may be handling pinch zoom or
|
|
194
|
+
// two-finger scrolling. Abandon any accepted one-finger swipe before
|
|
195
|
+
// touchmove can suppress that native gesture.
|
|
196
|
+
resetGesture(true);
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
const touch = event.changedTouches[0];
|
|
200
|
+
if (touch != null) {
|
|
172
201
|
beginGesture(point(touch), event.target);
|
|
173
202
|
}
|
|
174
203
|
};
|
|
175
204
|
const handleTouchMove = event => {
|
|
205
|
+
if (event.touches?.length !== 1) {
|
|
206
|
+
resetGesture(true);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
176
209
|
const touch = changedTouch(event);
|
|
177
210
|
if (touch) {
|
|
178
211
|
moveGesture(point(touch), () => {
|
|
@@ -183,6 +216,10 @@ export function useToastGesture({
|
|
|
183
216
|
}
|
|
184
217
|
};
|
|
185
218
|
const handleTouchEnd = event => {
|
|
219
|
+
if (event.touches.length > 0) {
|
|
220
|
+
resetGesture(true);
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
186
223
|
const touch = changedTouch(event);
|
|
187
224
|
if (touch) {
|
|
188
225
|
endGesture(point(touch));
|
package/dist/astryx.css
CHANGED
|
@@ -1012,6 +1012,7 @@
|
|
|
1012
1012
|
.xkd40ry:not(#\#):not(#\#):not(#\#){margin-inline-end:calc(-1 * var(--spacing-1))}
|
|
1013
1013
|
.x3kzqx6:not(#\#):not(#\#):not(#\#){margin-inline-end:calc(-1 * var(--spacing-2))}
|
|
1014
1014
|
.xmequkd:not(#\#):not(#\#):not(#\#){margin-inline-end:calc(var(--spacing-1) * -1)}
|
|
1015
|
+
.xxeicf8:not(#\#):not(#\#):not(#\#){margin-inline-end:max(var(--spacing-4),env(safe-area-inset-left,0px),env(safe-area-inset-right,0px))}
|
|
1015
1016
|
.xnur1sd:not(#\#):not(#\#):not(#\#){margin-inline-end:var(--spacing-1)}
|
|
1016
1017
|
.x1c9tiao:not(#\#):not(#\#):not(#\#){margin-inline-end:var(--x-marginInlineEnd)}
|
|
1017
1018
|
.x1qfufaz:not(#\#):not(#\#):not(#\#){margin-inline-start:-8px}
|
|
@@ -1022,6 +1023,7 @@
|
|
|
1022
1023
|
.x1wim8z0:not(#\#):not(#\#):not(#\#){margin-inline-start:calc(-1 * var(--layout-padding-inner-x,var(--spacing-4)))}
|
|
1023
1024
|
.x1s1akpx:not(#\#):not(#\#):not(#\#){margin-inline-start:calc(-1 * var(--spacing-2))}
|
|
1024
1025
|
.x1xrm450:not(#\#):not(#\#):not(#\#){margin-inline-start:calc(var(--spacing-2) - var(--spacing-1) + 1px)}
|
|
1026
|
+
.x47fqr9:not(#\#):not(#\#):not(#\#){margin-inline-start:max(var(--spacing-4),env(safe-area-inset-left,0px),env(safe-area-inset-right,0px))}
|
|
1025
1027
|
.x12vn87o:not(#\#):not(#\#):not(#\#){margin-inline-start:var(--_tree-indent,0px)}
|
|
1026
1028
|
.xladpz9:not(#\#):not(#\#):not(#\#){margin-inline-start:var(--spacing-0-5)}
|
|
1027
1029
|
.x11g1kdw:not(#\#):not(#\#):not(#\#){margin-inline-start:var(--spacing-1)}
|
|
@@ -1331,6 +1333,7 @@
|
|
|
1331
1333
|
.xbt4iw:focus-within:not(#\#):not(#\#):not(#\#){pointer-events:auto}
|
|
1332
1334
|
.xo74pv5:focus-within:not(#\#):not(#\#):not(#\#){position:static}
|
|
1333
1335
|
.x1mqgsch:is([data-astryx-scrolling]):not(#\#):not(#\#):not(#\#){scrollbar-width:none}
|
|
1336
|
+
.x8ppqj.x8ppqj:active:where(:not(:disabled,[aria-disabled="true"])):not(#\#):not(#\#):not(#\#){transform:scale(.98)}
|
|
1334
1337
|
.xaafvuh:is([dir="rtl"] *):not(#\#):not(#\#):not(#\#){transform:scaleX(-1) rotate(0deg)}
|
|
1335
1338
|
.x1nxqau:is([dir="rtl"] *):not(#\#):not(#\#):not(#\#){transform:scaleX(-1) rotate(90deg)}
|
|
1336
1339
|
.xgtlewx:is([dir="rtl"] *):not(#\#):not(#\#):not(#\#){transform:scaleX(-1)}
|
|
@@ -1555,6 +1558,7 @@
|
|
|
1555
1558
|
.x6h7pi7:not(#\#):not(#\#):not(#\#):not(#\#){margin-bottom:calc(-1 * var(--container-padding-block-end,0px))}
|
|
1556
1559
|
.x1cdrix3:not(#\#):not(#\#):not(#\#):not(#\#){margin-bottom:calc(-1 * var(--radius-chat))}
|
|
1557
1560
|
.xdrfirk:not(#\#):not(#\#):not(#\#):not(#\#){margin-bottom:calc(-1 * var(--spacing-1-5))}
|
|
1561
|
+
.x1kps3mo:not(#\#):not(#\#):not(#\#):not(#\#){margin-bottom:max(var(--spacing-4),env(safe-area-inset-bottom,0px))}
|
|
1558
1562
|
.xlstkdb:not(#\#):not(#\#):not(#\#):not(#\#){margin-bottom:var(--spacing-0-5)}
|
|
1559
1563
|
.x14cgwvg:not(#\#):not(#\#):not(#\#):not(#\#){margin-bottom:var(--spacing-1)}
|
|
1560
1564
|
.x1p37lm5:not(#\#):not(#\#):not(#\#):not(#\#){margin-bottom:var(--spacing-2)}
|
|
@@ -1572,6 +1576,7 @@
|
|
|
1572
1576
|
.x1c40v9y:not(#\#):not(#\#):not(#\#):not(#\#){margin-top:calc(-1 * var(--spacing-1-5))}
|
|
1573
1577
|
.x1ajqlyv:not(#\#):not(#\#):not(#\#):not(#\#){margin-top:calc(-1 * var(--spacing-2))}
|
|
1574
1578
|
.x1233pnv:not(#\#):not(#\#):not(#\#):not(#\#){margin-top:calc((1em * var(--text-body-leading) - 6px) / 2)}
|
|
1579
|
+
.xsoubt3:not(#\#):not(#\#):not(#\#):not(#\#){margin-top:max(var(--spacing-4),env(safe-area-inset-top,0px))}
|
|
1575
1580
|
.xjc2qm6:not(#\#):not(#\#):not(#\#):not(#\#){margin-top:var(--spacing-0-5)}
|
|
1576
1581
|
.xcsaf9d:not(#\#):not(#\#):not(#\#):not(#\#){margin-top:var(--spacing-1)}
|
|
1577
1582
|
.xtbrsbv:not(#\#):not(#\#):not(#\#):not(#\#){margin-top:var(--spacing-2)}
|
|
@@ -1585,6 +1590,7 @@
|
|
|
1585
1590
|
.x1xiyphd:not(#\#):not(#\#):not(#\#):not(#\#){max-height:240px}
|
|
1586
1591
|
.xuyqlj2:not(#\#):not(#\#):not(#\#):not(#\#){max-height:300px}
|
|
1587
1592
|
.xbhvqqn:not(#\#):not(#\#):not(#\#):not(#\#){max-height:calc(100% - var(--spacing-3))}
|
|
1593
|
+
.xtm2925:not(#\#):not(#\#):not(#\#):not(#\#){max-height:calc(100vh - var(--spacing-4) - var(--spacing-4));max-height:calc(100dvb - max(var(--spacing-4),env(safe-area-inset-top,0px)) - max(var(--spacing-4),env(safe-area-inset-bottom,0px)))}
|
|
1588
1594
|
.x14bu9tk:not(#\#):not(#\#):not(#\#):not(#\#){max-height:calc(92dvh + 48px)}
|
|
1589
1595
|
.xpnbb6b:not(#\#):not(#\#):not(#\#):not(#\#){max-height:min(480px,calc(100vh - 32px))}
|
|
1590
1596
|
.x7ab17h:not(#\#):not(#\#):not(#\#):not(#\#){max-height:none}
|
|
@@ -1604,6 +1610,8 @@
|
|
|
1604
1610
|
.x11gisft:not(#\#):not(#\#):not(#\#):not(#\#){max-width:640px}
|
|
1605
1611
|
.x1ap80js:not(#\#):not(#\#):not(#\#):not(#\#){max-width:800px}
|
|
1606
1612
|
.xq8v1hd:not(#\#):not(#\#):not(#\#):not(#\#){max-width:90%}
|
|
1613
|
+
.xbd96yr:not(#\#):not(#\#):not(#\#):not(#\#){max-width:calc(100% - var(--spacing-4));max-width:calc(100% - max(var(--spacing-4),env(safe-area-inset-left,0px),env(safe-area-inset-right,0px)))}
|
|
1614
|
+
.xs2v1xk:not(#\#):not(#\#):not(#\#):not(#\#){max-width:calc(100vw - var(--spacing-4) - var(--spacing-4));max-width:calc(100vi - max(var(--spacing-4),env(safe-area-inset-left,0px)) - max(var(--spacing-4),env(safe-area-inset-right,0px)))}
|
|
1607
1615
|
.xl6temz:not(#\#):not(#\#):not(#\#):not(#\#){max-width:max(80%,280px)}
|
|
1608
1616
|
.x1m1aaou:not(#\#):not(#\#):not(#\#):not(#\#){max-width:min(960px,calc(100dvw - var(--spacing-4)))}
|
|
1609
1617
|
.x1x1rfll:not(#\#):not(#\#):not(#\#):not(#\#){max-width:none}
|
|
@@ -1641,6 +1649,8 @@
|
|
|
1641
1649
|
.x900493:not(#\#):not(#\#):not(#\#):not(#\#){min-width:48px}
|
|
1642
1650
|
.x13n9wmd:not(#\#):not(#\#):not(#\#):not(#\#){min-width:4ch}
|
|
1643
1651
|
.xfvyar9:not(#\#):not(#\#):not(#\#):not(#\#){min-width:60px}
|
|
1652
|
+
.x1ks9poc:not(#\#):not(#\#):not(#\#):not(#\#){min-width:anchor-size(width);min-width:min(anchor-size(width),calc(100% - var(--spacing-4)));min-width:min(anchor-size(width),calc(100% - max(var(--spacing-4),env(safe-area-inset-left,0px),env(safe-area-inset-right,0px))))}
|
|
1653
|
+
.xagy28z:not(#\#):not(#\#):not(#\#):not(#\#){min-width:anchor-size(width);min-width:min(anchor-size(width),calc(100vw - var(--spacing-4) - var(--spacing-4)));min-width:min(anchor-size(width),calc(100vi - max(var(--spacing-4),env(safe-area-inset-left,0px)) - max(var(--spacing-4),env(safe-area-inset-right,0px))))}
|
|
1644
1654
|
.xrzjruh:not(#\#):not(#\#):not(#\#):not(#\#){min-width:anchor-size(width)}
|
|
1645
1655
|
.x8wyhu6:not(#\#):not(#\#):not(#\#):not(#\#){min-width:calc(anchor-size(width) + 16px)}
|
|
1646
1656
|
.x1pshirs:not(#\#):not(#\#):not(#\#):not(#\#){min-width:fit-content}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useFocusTrap.d.ts","sourceRoot":"","sources":["../../src/hooks/useFocusTrap.ts"],"names":[],"mappings":"AA8BA;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,IAAI,OAAO,CAElD;AAgFD;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;OAEG;IACH,QAAQ,EAAE,OAAO,CAAC;IAElB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW;IACrE;;OAEG;IACH,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAExC;;OAEG;IACH,UAAU,EAAE,MAAM,IAAI,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,EAC9D,OAAO,EAAE,mBAAmB,GAC3B,kBAAkB,CAAC,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"useFocusTrap.d.ts","sourceRoot":"","sources":["../../src/hooks/useFocusTrap.ts"],"names":[],"mappings":"AA8BA;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,IAAI,OAAO,CAElD;AAgFD;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;OAEG;IACH,QAAQ,EAAE,OAAO,CAAC;IAElB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW;IACrE;;OAEG;IACH,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAExC;;OAEG;IACH,UAAU,EAAE,MAAM,IAAI,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,EAC9D,OAAO,EAAE,mBAAmB,GAC3B,kBAAkB,CAAC,CAAC,CAAC,CA0OvB"}
|
|
@@ -321,6 +321,18 @@ export function useFocusTrap(options) {
|
|
|
321
321
|
}
|
|
322
322
|
const first = focusable[0];
|
|
323
323
|
const last = focusable[focusable.length - 1];
|
|
324
|
+
if (document.activeElement === container) {
|
|
325
|
+
// Programmatic initial focus can sit on the trap container itself
|
|
326
|
+
// (for example a dialog panel with no content controls). Move into
|
|
327
|
+
// the tabbable cycle instead of letting Tab escape to the page.
|
|
328
|
+
event.preventDefault();
|
|
329
|
+
if (event.shiftKey) {
|
|
330
|
+
last.focus();
|
|
331
|
+
} else {
|
|
332
|
+
first.focus();
|
|
333
|
+
}
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
324
336
|
if (event.shiftKey) {
|
|
325
337
|
// Shift+Tab: if on first element, wrap to last
|
|
326
338
|
if (document.activeElement === first) {
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import { getResolve } from './resolve';
|
|
1
2
|
import type { Locale, MessagesByLocale, Overrides } from './types';
|
|
2
3
|
export interface InternationalizationContextValue {
|
|
3
4
|
locale: Locale;
|
|
4
5
|
direction: 'ltr' | 'rtl';
|
|
5
6
|
messages: MessagesByLocale;
|
|
6
7
|
overrides?: Overrides;
|
|
8
|
+
translate: ReturnType<typeof getResolve>;
|
|
7
9
|
}
|
|
8
10
|
/**
|
|
9
11
|
* Default value falls through to the shipped en catalog in resolve().
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InternationalizationContext.d.ts","sourceRoot":"","sources":["../../src/i18n/InternationalizationContext.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAC,MAAM,EAAE,gBAAgB,EAAE,SAAS,EAAC,MAAM,SAAS,CAAC;AAEjE,MAAM,WAAW,gCAAgC;IAC/C,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,KAAK,GAAG,KAAK,CAAC;IACzB,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,SAAS,CAAC,EAAE,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"InternationalizationContext.d.ts","sourceRoot":"","sources":["../../src/i18n/InternationalizationContext.ts"],"names":[],"mappings":"AAyBA,OAAO,EAAC,UAAU,EAAC,MAAM,WAAW,CAAC;AACrC,OAAO,KAAK,EAAC,MAAM,EAAE,gBAAgB,EAAE,SAAS,EAAC,MAAM,SAAS,CAAC;AAEjE,MAAM,WAAW,gCAAgC;IAC/C,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,KAAK,GAAG,KAAK,CAAC;IACzB,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,SAAS,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;CAC1C;AAED;;;GAGG;AACH,eAAO,MAAM,2BAA2B,2DAMpC,CAAC"}
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
* - /packages/core/src/i18n/index.ts
|
|
23
23
|
*/
|
|
24
24
|
import { createContext } from 'react';
|
|
25
|
+
import { getResolve } from "./resolve.js";
|
|
25
26
|
/**
|
|
26
27
|
* Default value falls through to the shipped en catalog in resolve().
|
|
27
28
|
* A consumer that doesn't render a provider still gets English defaults.
|
|
@@ -29,6 +30,7 @@ import { createContext } from 'react';
|
|
|
29
30
|
export const InternationalizationContext = /*#__PURE__*/createContext({
|
|
30
31
|
locale: 'en',
|
|
31
32
|
direction: 'ltr',
|
|
32
|
-
messages: {}
|
|
33
|
+
messages: {},
|
|
34
|
+
translate: getResolve('en', {})
|
|
33
35
|
});
|
|
34
36
|
InternationalizationContext.displayName = 'InternationalizationContext';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InternationalizationProvider.d.ts","sourceRoot":"","sources":["../../src/i18n/InternationalizationProvider.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAU,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAG9C,OAAO,KAAK,EAAC,MAAM,EAAE,gBAAgB,EAAE,SAAS,EAAC,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"InternationalizationProvider.d.ts","sourceRoot":"","sources":["../../src/i18n/InternationalizationProvider.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAU,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAG9C,OAAO,KAAK,EAAC,MAAM,EAAE,gBAAgB,EAAE,SAAS,EAAC,MAAM,SAAS,CAAC;AAGjE,MAAM,WAAW,iCAAiC;IAChD;;;;;;OAMG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;;;;OASG;IACH,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B;;;;;;;;;;OAUG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB;;;;;;;;;;;OAWG;IACH,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC;IACpB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,EAC3C,MAAM,EACN,QAAQ,EACR,SAAS,EACT,GAAG,EACH,QAAQ,GACT,EAAE,iCAAiC,+BAiBnC;yBAvBe,4BAA4B"}
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
import { useMemo } from 'react';
|
|
22
22
|
import { InternationalizationContext } from "./InternationalizationContext.js";
|
|
23
23
|
import { getLocaleDirection } from "./getLocaleDirection.js";
|
|
24
|
+
import { getResolve } from "./resolve.js";
|
|
24
25
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
25
26
|
/**
|
|
26
27
|
* Provides locale + additional messages + overrides to all astryx
|
|
@@ -38,7 +39,8 @@ export function InternationalizationProvider({
|
|
|
38
39
|
locale,
|
|
39
40
|
direction,
|
|
40
41
|
messages: messages ?? {},
|
|
41
|
-
overrides
|
|
42
|
+
overrides,
|
|
43
|
+
translate: getResolve(locale, messages ?? {}, overrides)
|
|
42
44
|
}), [locale, direction, messages, overrides]);
|
|
43
45
|
return /*#__PURE__*/_jsx(InternationalizationContext, {
|
|
44
46
|
value: value,
|
package/dist/i18n/resolve.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ import type { Locale, MessagesByLocale, Overrides } from './types';
|
|
|
13
13
|
* shipped en catalog separately as the final source-of-truth.
|
|
14
14
|
*/
|
|
15
15
|
export declare function resolveLocaleChain(locale: Locale): Locale[];
|
|
16
|
-
export declare function
|
|
16
|
+
export declare function getResolve(locale: Locale, messages: MessagesByLocale, overrides?: Overrides): (key: string, values: Record<string, unknown> | undefined) => string;
|
|
17
17
|
/**
|
|
18
18
|
* Reset internal caches. Test-only.
|
|
19
19
|
* @internal
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/i18n/resolve.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAU,MAAM,EAAE,gBAAgB,EAAE,SAAS,EAAC,MAAM,SAAS,CAAC;AAwB1E;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAc3D;
|
|
1
|
+
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/i18n/resolve.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAU,MAAM,EAAE,gBAAgB,EAAE,SAAS,EAAC,MAAM,SAAS,CAAC;AAwB1E;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAc3D;AAkCD,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,gBAAgB,EAC1B,SAAS,CAAC,EAAE,SAAS,IAIb,KAAK,MAAM,EAAE,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,YA0BjE;AAED;;;GAGG;AACH,wBAAgB,eAAe,IAAI,IAAI,CAGtC"}
|
package/dist/i18n/resolve.js
CHANGED
|
@@ -69,55 +69,54 @@ export function resolveLocaleChain(locale) {
|
|
|
69
69
|
}
|
|
70
70
|
return chain;
|
|
71
71
|
}
|
|
72
|
-
function
|
|
72
|
+
function getLookup(locale, messages, overrides) {
|
|
73
|
+
const lookup = {};
|
|
73
74
|
const chain = resolveLocaleChain(locale);
|
|
74
|
-
|
|
75
75
|
// 1 + 2. Overrides (most specific to least specific in the chain)
|
|
76
76
|
if (overrides !== undefined) {
|
|
77
77
|
for (const tag of chain) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
78
|
+
if (overrides[tag]) {
|
|
79
|
+
for (const [key, value] of Object.entries(overrides[tag])) {
|
|
80
|
+
if (lookup[key] === undefined && value !== null) {
|
|
81
|
+
lookup[key] = value;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
81
84
|
}
|
|
82
85
|
}
|
|
83
86
|
}
|
|
84
|
-
|
|
85
|
-
// 3 + 4. Shipped catalogs (most specific to least specific)
|
|
86
87
|
for (const tag of chain) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
if (messages[tag]) {
|
|
89
|
+
for (const [key, value] of Object.entries(messages[tag])) {
|
|
90
|
+
if (lookup[key] === undefined && value?.defaultMessage !== null) {
|
|
91
|
+
lookup[key] = value?.defaultMessage;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
90
94
|
}
|
|
91
95
|
}
|
|
92
|
-
|
|
93
|
-
// 5. Shipped en catalog — always present
|
|
94
|
-
const enEntry = EN_CATALOG[key];
|
|
95
|
-
if (enEntry !== undefined) {
|
|
96
|
-
return enEntry.defaultMessage;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// 6. Nothing found
|
|
100
|
-
return null;
|
|
96
|
+
return lookup;
|
|
101
97
|
}
|
|
102
|
-
export function
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
98
|
+
export function getResolve(locale, messages, overrides) {
|
|
99
|
+
const lookup = getLookup(locale, messages, overrides);
|
|
100
|
+
return (key, values) => {
|
|
101
|
+
const result = lookup[key] ?? EN_CATALOG[key]?.defaultMessage;
|
|
102
|
+
if (result === undefined) {
|
|
103
|
+
// Fires ONLY when a key is missing from every source including the
|
|
104
|
+
// shipped `en` catalog — a real bug (typo, stale catalog, deleted key).
|
|
105
|
+
// Fallback to `en` from a non-en locale is expected and stays silent,
|
|
106
|
+
// matching the FormatJS / i18next default.
|
|
107
|
+
warnOnce(`astryx-i18n:${locale}::${key}`, 'astryx-i18n', `missing key: ${key} (locale: ${locale})`);
|
|
108
|
+
return key;
|
|
109
|
+
}
|
|
110
|
+
if (values === undefined) {
|
|
111
|
+
// Static string — skip the parser entirely for the common case
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
114
|
+
const formatted = getFormatter(result, locale).format(values);
|
|
115
|
+
// IntlMessageFormat.format returns string | (string | React elements) — we
|
|
116
|
+
// only ever pass string values so it will be a string; assert for the type
|
|
117
|
+
// system.
|
|
118
|
+
return formatted;
|
|
119
|
+
};
|
|
121
120
|
}
|
|
122
121
|
|
|
123
122
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useTranslator.d.ts","sourceRoot":"","sources":["../../src/i18n/useTranslator.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useTranslator.d.ts","sourceRoot":"","sources":["../../src/i18n/useTranslator.ts"],"names":[],"mappings":"AAwBA,MAAM,MAAM,YAAY,GAAG,CACzB,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC7B,MAAM,CAAC;AAEZ;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,IAAI,YAAY,CAG5C"}
|
|
@@ -18,9 +18,8 @@
|
|
|
18
18
|
* - /packages/core/src/i18n/index.ts
|
|
19
19
|
* - /packages/core/src/i18n/t.client.ts
|
|
20
20
|
*/
|
|
21
|
-
import { use
|
|
21
|
+
import { use } from 'react';
|
|
22
22
|
import { InternationalizationContext } from "./InternationalizationContext.js";
|
|
23
|
-
import { resolve } from "./resolve.js";
|
|
24
23
|
/**
|
|
25
24
|
* Returns a translator function bound to the current provider's locale.
|
|
26
25
|
* Safe to call from event handlers and effects.
|
|
@@ -35,5 +34,5 @@ import { resolve } from "./resolve.js";
|
|
|
35
34
|
*/
|
|
36
35
|
export function useTranslator() {
|
|
37
36
|
const ctx = use(InternationalizationContext);
|
|
38
|
-
return
|
|
37
|
+
return ctx.translate;
|
|
39
38
|
}
|
package/locales/af-ZA.json
CHANGED
|
@@ -623,10 +623,6 @@
|
|
|
623
623
|
"defaultMessage": "Kies 'n datum",
|
|
624
624
|
"description": "Grey placeholder inside an empty DateTimeInput field. Note: the English says only \"date\" though the field is date+time — do not add \"and time\" unless natural."
|
|
625
625
|
},
|
|
626
|
-
"@astryx.dateTimeInput.dialogLabel": {
|
|
627
|
-
"defaultMessage": "Kies datum",
|
|
628
|
-
"description": "Screen-reader-only accessible name for the DateTimeInput picker dialog. Same English-only \"date\" phrasing as the placeholder — don't add \"and time\" unless natural."
|
|
629
|
-
},
|
|
630
626
|
"@astryx.link.newTab": {
|
|
631
627
|
"defaultMessage": "(maak in nuwe oortjie oop)",
|
|
632
628
|
"description": "Visually-hidden (screen-reader-only) suffix appended to a Link's accessible name when it opens in a new tab. Example: `Documentation (opens in new tab)`."
|
package/locales/ar-SA.json
CHANGED
|
@@ -651,10 +651,6 @@
|
|
|
651
651
|
"defaultMessage": "حدّد تاريخًا",
|
|
652
652
|
"description": "Grey placeholder inside an empty DateTimeInput field. Note: the English says only \"date\" though the field is date+time — do not add \"and time\" unless natural."
|
|
653
653
|
},
|
|
654
|
-
"@astryx.dateTimeInput.dialogLabel": {
|
|
655
|
-
"defaultMessage": "اختر التاريخ",
|
|
656
|
-
"description": "Screen-reader-only accessible name for the DateTimeInput picker dialog. Same English-only \"date\" phrasing as the placeholder — don't add \"and time\" unless natural."
|
|
657
|
-
},
|
|
658
654
|
"@astryx.link.newTab": {
|
|
659
655
|
"defaultMessage": "(يُفتح في علامة تبويب جديدة)",
|
|
660
656
|
"description": "Visually-hidden (screen-reader-only) suffix appended to a Link's accessible name when it opens in a new tab. Example: `Documentation (opens in new tab)`."
|
package/locales/ca-ES.json
CHANGED
|
@@ -643,10 +643,6 @@
|
|
|
643
643
|
"defaultMessage": "Selecciona una data",
|
|
644
644
|
"description": "Grey placeholder inside an empty DateTimeInput field. Note: the English says only \"date\" though the field is date+time — do not add \"and time\" unless natural."
|
|
645
645
|
},
|
|
646
|
-
"@astryx.dateTimeInput.dialogLabel": {
|
|
647
|
-
"defaultMessage": "Tria una data",
|
|
648
|
-
"description": "Screen-reader-only accessible name for the DateTimeInput picker dialog. Same English-only \"date\" phrasing as the placeholder — don't add \"and time\" unless natural."
|
|
649
|
-
},
|
|
650
646
|
"@astryx.link.newTab": {
|
|
651
647
|
"defaultMessage": "(s’obre en una pestanya nova)",
|
|
652
648
|
"description": "Visually-hidden (screen-reader-only) suffix appended to a Link's accessible name when it opens in a new tab. Example: `Documentation (opens in new tab)`."
|
package/locales/cs-CZ.json
CHANGED
|
@@ -647,10 +647,6 @@
|
|
|
647
647
|
"defaultMessage": "Vyberte datum",
|
|
648
648
|
"description": "Grey placeholder inside an empty DateTimeInput field. Note: the English says only \"date\" though the field is date+time — do not add \"and time\" unless natural."
|
|
649
649
|
},
|
|
650
|
-
"@astryx.dateTimeInput.dialogLabel": {
|
|
651
|
-
"defaultMessage": "Zvolit datum",
|
|
652
|
-
"description": "Screen-reader-only accessible name for the DateTimeInput picker dialog. Same English-only \"date\" phrasing as the placeholder — don't add \"and time\" unless natural."
|
|
653
|
-
},
|
|
654
650
|
"@astryx.link.newTab": {
|
|
655
651
|
"defaultMessage": "(otevře se na nové kartě)",
|
|
656
652
|
"description": "Visually-hidden (screen-reader-only) suffix appended to a Link's accessible name when it opens in a new tab. Example: `Documentation (opens in new tab)`."
|
package/locales/da-DK.json
CHANGED
|
@@ -639,10 +639,6 @@
|
|
|
639
639
|
"defaultMessage": "Vælg en dato",
|
|
640
640
|
"description": "Grey placeholder inside an empty DateTimeInput field. Note: the English says only \"date\" though the field is date+time — do not add \"and time\" unless natural."
|
|
641
641
|
},
|
|
642
|
-
"@astryx.dateTimeInput.dialogLabel": {
|
|
643
|
-
"defaultMessage": "Vælg dato",
|
|
644
|
-
"description": "Screen-reader-only accessible name for the DateTimeInput picker dialog. Same English-only \"date\" phrasing as the placeholder — don't add \"and time\" unless natural."
|
|
645
|
-
},
|
|
646
642
|
"@astryx.link.newTab": {
|
|
647
643
|
"defaultMessage": "(åbner i ny fane)",
|
|
648
644
|
"description": "Visually-hidden (screen-reader-only) suffix appended to a Link's accessible name when it opens in a new tab. Example: `Documentation (opens in new tab)`."
|