@astryxdesign/core 0.7.1 → 0.7.2-canary.07f97c6
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/dist/Button/Button.d.ts.map +1 -1
- package/dist/Button/Button.js +38 -14
- package/dist/Drawer/Drawer.d.ts +191 -0
- package/dist/Drawer/Drawer.d.ts.map +1 -0
- package/dist/Drawer/Drawer.js +382 -0
- package/dist/Drawer/DrawerHeader.d.ts +85 -0
- package/dist/Drawer/DrawerHeader.d.ts.map +1 -0
- package/dist/Drawer/DrawerHeader.js +134 -0
- package/dist/Drawer/index.d.ts +11 -0
- package/dist/Drawer/index.d.ts.map +1 -0
- package/dist/Drawer/index.js +11 -0
- package/dist/Drawer/useDrawerDialogPresence.d.ts +42 -0
- package/dist/Drawer/useDrawerDialogPresence.d.ts.map +1 -0
- package/dist/Drawer/useDrawerDialogPresence.js +236 -0
- package/dist/DropdownMenu/DropdownMenu.js +1 -1
- package/dist/DropdownMenu/DropdownMenuSubMenu.js +4 -4
- package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
- package/dist/HoverCard/useHoverCard.js +10 -2
- package/dist/Layer/layerViewportInset.stylex.d.ts +6 -2
- package/dist/Layer/layerViewportInset.stylex.d.ts.map +1 -1
- package/dist/Layer/layerViewportInset.stylex.js +6 -2
- package/dist/Layer/useLayer.d.ts.map +1 -1
- package/dist/Layer/useLayer.js +13 -7
- package/dist/Layer/useLayerDismissal.d.ts +1 -1
- package/dist/Layer/useLayerDismissal.js +1 -1
- package/dist/Layout/container.stylex.d.ts +5 -5
- package/dist/Layout/container.stylex.js +4 -4
- package/dist/Markdown/plugins/frontmatter.d.ts.map +1 -1
- package/dist/Markdown/plugins/frontmatter.js +7 -3
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +22 -8
- package/dist/MultiSelector/OptionActions.a11y.chromium.spec.js +100 -2
- package/dist/MultiSelector/hooks.d.ts.map +1 -1
- package/dist/MultiSelector/hooks.js +3 -1
- package/dist/Pagination/Pagination.d.ts +8 -5
- package/dist/Pagination/Pagination.d.ts.map +1 -1
- package/dist/Pagination/Pagination.js +21 -8
- package/dist/Popover/Popover.js +2 -2
- package/dist/PowerSearch/PowerSearch.js +1 -1
- package/dist/Selector/hooks.d.ts.map +1 -1
- package/dist/Selector/hooks.js +6 -2
- package/dist/Switch/Switch.d.ts +1 -1
- package/dist/Switch/Switch.d.ts.map +1 -1
- package/dist/Switch/Switch.js +13 -1
- package/dist/TabList/TabMenu.d.ts +2 -2
- package/dist/TabList/TabMenu.d.ts.map +1 -1
- package/dist/TabList/TabMenu.js +6 -3
- package/dist/Text/useTruncation.d.ts +7 -5
- package/dist/Text/useTruncation.d.ts.map +1 -1
- package/dist/Text/useTruncation.js +16 -5
- package/dist/Tooltip/useTooltip.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.js +11 -0
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +26 -0
- package/dist/astryx.css +21 -10
- package/dist/hooks/useEntryAnimation.d.ts +2 -1
- package/dist/hooks/useEntryAnimation.d.ts.map +1 -1
- package/dist/hooks/useEntryAnimation.js +14 -12
- package/dist/hooks/useIsHydrating.d.ts +6 -0
- package/dist/hooks/useIsHydrating.d.ts.map +1 -0
- package/dist/hooks/useIsHydrating.js +30 -0
- package/dist/i18n/generated-locales/en.generated.d.ts.map +1 -1
- package/dist/i18n/generated-locales/en.generated.js +112 -1
- package/dist/i18n/generated-locales/pseudo.generated.d.ts.map +1 -1
- package/dist/i18n/generated-locales/pseudo.generated.js +112 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
- package/dist/theme/derivedVarRegistry.js +0 -3
- package/dist/utils/focusOutline.stylex.d.ts +4 -0
- package/dist/utils/focusOutline.stylex.d.ts.map +1 -1
- package/dist/utils/focusOutline.stylex.js +4 -0
- package/dist/utils/sharedMutationObserver.d.ts +21 -0
- package/dist/utils/sharedMutationObserver.d.ts.map +1 -0
- package/dist/utils/sharedMutationObserver.js +69 -0
- package/locales/en.json +444 -0
- package/locales/pseudo.json +333 -0
- package/package.json +9 -4
- package/src/Button/Button.doc.mjs +2 -2
- package/src/Button/Button.test.tsx +155 -9
- package/src/Button/Button.tsx +39 -16
- package/src/Button/__tests__/Button.a11y.known-failures.ts +1 -62
- package/src/Button/__tests__/Button.a11y.states.ts +0 -10
- package/src/Drawer/Drawer.doc.mjs +472 -0
- package/src/Drawer/Drawer.spec.md +357 -0
- package/src/Drawer/Drawer.test.tsx +1300 -0
- package/src/Drawer/Drawer.tsx +613 -0
- package/src/Drawer/DrawerDirection.test.tsx +127 -0
- package/src/Drawer/DrawerHeader.doc.mjs +293 -0
- package/src/Drawer/DrawerHeader.test.tsx +102 -0
- package/src/Drawer/DrawerHeader.tsx +235 -0
- package/src/Drawer/__tests__/DrawerAudit.a11y.chromium.spec.ts +401 -0
- package/src/Drawer/__tests__/DrawerHeaderAudit.a11y.chromium.spec.ts +297 -0
- package/src/Drawer/index.ts +13 -0
- package/src/Drawer/useDrawerDialogPresence.ts +284 -0
- package/src/DropdownMenu/DropdownMenu.tsx +2 -2
- package/src/DropdownMenu/DropdownMenuSubMenu.tsx +2 -2
- package/src/HoverCard/HoverCard.test.tsx +58 -0
- package/src/HoverCard/useHoverCard.tsx +10 -2
- package/src/IconButton/IconButton.doc.mjs +2 -2
- package/src/IconButton/IconButton.test.tsx +3 -1
- package/src/Layer/layerViewportInset.source-build.test.mjs +90 -0
- package/src/Layer/layerViewportInset.stylex.ts +6 -2
- package/src/Layer/layerViewportInset.test.ts +1 -0
- package/src/Layer/useLayer.tsx +24 -13
- package/src/Layer/useLayerDismissal.ts +1 -1
- package/src/Layout/container.stylex.ts +6 -6
- package/src/List/ListItem.doc.mjs +8 -5
- package/src/Markdown/plugins/frontmatter.test.tsx +25 -0
- package/src/Markdown/plugins/frontmatter.ts +7 -3
- package/src/MultiSelector/MultiSelector.test.tsx +159 -0
- package/src/MultiSelector/MultiSelector.tsx +40 -7
- package/src/MultiSelector/OptionActions.a11y.chromium.spec.ts +112 -2
- package/src/MultiSelector/hooks.ts +3 -1
- package/src/MultiSelector/useMultiCombobox.doc.mjs +267 -0
- package/src/Pagination/Pagination.doc.mjs +7 -7
- package/src/Pagination/Pagination.spec.md +9 -9
- package/src/Pagination/Pagination.test.tsx +242 -0
- package/src/Pagination/Pagination.tsx +27 -11
- package/src/Popover/Popover.test.tsx +2 -2
- package/src/Popover/Popover.tsx +4 -4
- package/src/PowerSearch/PowerSearch.test.tsx +85 -0
- package/src/PowerSearch/PowerSearch.tsx +2 -2
- package/src/Selector/hooks.ts +6 -2
- package/src/Selector/useCombobox.doc.mjs +237 -0
- package/src/Switch/Switch.test.tsx +49 -0
- package/src/Switch/Switch.tsx +11 -0
- package/src/TabList/TabList.test.tsx +67 -0
- package/src/TabList/TabMenu.doc.mjs +4 -3
- package/src/TabList/TabMenu.tsx +7 -4
- package/src/Text/useTruncation.test.tsx +69 -0
- package/src/Text/useTruncation.ts +16 -5
- package/src/Tokenizer/Tokenizer.test.tsx +54 -1
- package/src/Tooltip/Tooltip.test.tsx +31 -0
- package/src/Tooltip/useTooltip.test.tsx +13 -0
- package/src/Tooltip/useTooltip.tsx +11 -0
- package/src/Typeahead/BaseTypeahead.tsx +26 -0
- package/src/Typeahead/Typeahead.test.tsx +260 -2
- package/src/hooks/useEntryAnimation.doc.mjs +4 -4
- package/src/hooks/useEntryAnimation.ssr.test.tsx +143 -0
- package/src/hooks/useEntryAnimation.ts +15 -16
- package/src/hooks/useIsHydrating.test.tsx +70 -0
- package/src/hooks/useIsHydrating.ts +31 -0
- package/src/i18n/InternationalizationProvider.doc.mjs +8 -0
- package/src/i18n/InternationalizationProvider.spec.md +252 -0
- package/src/i18n/__tests__/InternationalizationProvider.test.tsx +128 -0
- package/src/i18n/generated-locales/en.generated.ts +121 -0
- package/src/i18n/generated-locales/pseudo.generated.ts +121 -0
- package/src/i18n/useTranslator.test.tsx +37 -0
- package/src/index.ts +1 -0
- package/src/theme/derivedVarRegistry.test.ts +0 -3
- package/src/theme/derivedVarRegistry.ts +0 -3
- package/src/utils/focusOutline.stylex.ts +4 -0
- package/src/utils/sharedMutationObserver.test.ts +53 -0
- package/src/utils/sharedMutationObserver.ts +78 -0
package/locales/pseudo.json
CHANGED
|
@@ -395,6 +395,63 @@
|
|
|
395
395
|
"@astryx.listInput.announceAlreadyAtBoundary": {
|
|
396
396
|
"defaultMessage": "⟦Ţĥíš {itemName} íš àłřéàðý {boundary, select, first {first} last {last} other {}}.⟧"
|
|
397
397
|
},
|
|
398
|
+
"@astryx.diffViewer.label": {
|
|
399
|
+
"defaultMessage": "⟦Ð탃⟧"
|
|
400
|
+
},
|
|
401
|
+
"@astryx.diffViewer.renamedPath": {
|
|
402
|
+
"defaultMessage": "⟦{oldPath} → {newPath}⟧"
|
|
403
|
+
},
|
|
404
|
+
"@astryx.diffViewer.statusAdded": {
|
|
405
|
+
"defaultMessage": "⟦Àððéð⟧"
|
|
406
|
+
},
|
|
407
|
+
"@astryx.diffViewer.statusDeleted": {
|
|
408
|
+
"defaultMessage": "⟦Ðéłéţéð⟧"
|
|
409
|
+
},
|
|
410
|
+
"@astryx.diffViewer.statusRenamed": {
|
|
411
|
+
"defaultMessage": "⟦Řéñàɱéð⟧"
|
|
412
|
+
},
|
|
413
|
+
"@astryx.diffViewer.addedCount": {
|
|
414
|
+
"defaultMessage": "⟦+{count, number}⟧"
|
|
415
|
+
},
|
|
416
|
+
"@astryx.diffViewer.removedCount": {
|
|
417
|
+
"defaultMessage": "⟦−{count, number}⟧"
|
|
418
|
+
},
|
|
419
|
+
"@astryx.diffViewer.stats": {
|
|
420
|
+
"defaultMessage": "⟦{added, plural, one {# line added} other {# lines added}}, {removed, plural, one {# line removed} other {# lines removed}}⟧"
|
|
421
|
+
},
|
|
422
|
+
"@astryx.diffViewer.added": {
|
|
423
|
+
"defaultMessage": "⟦Àððéð⟧"
|
|
424
|
+
},
|
|
425
|
+
"@astryx.diffViewer.removed": {
|
|
426
|
+
"defaultMessage": "⟦Řéɱóṽéð⟧"
|
|
427
|
+
},
|
|
428
|
+
"@astryx.diffViewer.lineNumberButton": {
|
|
429
|
+
"defaultMessage": "⟦{side, select, old {Original line {line, number}} other {Changed line {line, number}}}⟧"
|
|
430
|
+
},
|
|
431
|
+
"@astryx.diffViewer.columnOldLine": {
|
|
432
|
+
"defaultMessage": "⟦Óříĝíñàł łíñé ñúɱƀéř⟧"
|
|
433
|
+
},
|
|
434
|
+
"@astryx.diffViewer.columnNewLine": {
|
|
435
|
+
"defaultMessage": "⟦Çĥàñĝéð łíñé ñúɱƀéř⟧"
|
|
436
|
+
},
|
|
437
|
+
"@astryx.diffViewer.columnChange": {
|
|
438
|
+
"defaultMessage": "⟦Çĥàñĝé⟧"
|
|
439
|
+
},
|
|
440
|
+
"@astryx.diffViewer.columnCode": {
|
|
441
|
+
"defaultMessage": "⟦Çóðé⟧"
|
|
442
|
+
},
|
|
443
|
+
"@astryx.diffViewer.columnOldCode": {
|
|
444
|
+
"defaultMessage": "⟦Óříĝíñàł çóðé⟧"
|
|
445
|
+
},
|
|
446
|
+
"@astryx.diffViewer.columnNewCode": {
|
|
447
|
+
"defaultMessage": "⟦Çĥàñĝéð çóðé⟧"
|
|
448
|
+
},
|
|
449
|
+
"@astryx.diffViewer.binary": {
|
|
450
|
+
"defaultMessage": "⟦Ɓíñàřý ƒíłé ñóţ šĥóŵñ⟧"
|
|
451
|
+
},
|
|
452
|
+
"@astryx.diffViewer.noChanges": {
|
|
453
|
+
"defaultMessage": "⟦Ñó çóñţéñţ çĥàñĝéš⟧"
|
|
454
|
+
},
|
|
398
455
|
"@astryx.markdownHeadingLinks.copied": {
|
|
399
456
|
"defaultMessage": "⟦Łíñķ çóþíéð⟧"
|
|
400
457
|
},
|
|
@@ -1231,5 +1288,281 @@
|
|
|
1231
1288
|
},
|
|
1232
1289
|
"@astryx.transferListSelector.triggerLabel": {
|
|
1233
1290
|
"defaultMessage": "⟦{count, number} šéłéçţéð⟧"
|
|
1291
|
+
},
|
|
1292
|
+
"@astryx.emojiPicker.label": {
|
|
1293
|
+
"defaultMessage": "⟦Éɱóĵí⟧"
|
|
1294
|
+
},
|
|
1295
|
+
"@astryx.emojiPicker.searchLabel": {
|
|
1296
|
+
"defaultMessage": "⟦Šéàřçĥ éɱóĵí⟧"
|
|
1297
|
+
},
|
|
1298
|
+
"@astryx.emojiPicker.frequentlyUsed": {
|
|
1299
|
+
"defaultMessage": "⟦Ƒřéɋúéñţłý úšéð⟧"
|
|
1300
|
+
},
|
|
1301
|
+
"@astryx.emojiPicker.searchResults": {
|
|
1302
|
+
"defaultMessage": "⟦Šéàřçĥ řéšúłţš⟧"
|
|
1303
|
+
},
|
|
1304
|
+
"@astryx.emojiPicker.noResults": {
|
|
1305
|
+
"defaultMessage": "⟦Ñó éɱóĵí ɱàţçĥ “{query}”⟧"
|
|
1306
|
+
},
|
|
1307
|
+
"@astryx.emojiPicker.loading": {
|
|
1308
|
+
"defaultMessage": "⟦Łóàðíñĝ éɱóĵí⟧"
|
|
1309
|
+
},
|
|
1310
|
+
"@astryx.emojiPicker.loadFailed": {
|
|
1311
|
+
"defaultMessage": "⟦Ṁóřé éɱóĵí çóúłðñ'ţ ƀé łóàðéð.⟧"
|
|
1312
|
+
},
|
|
1313
|
+
"@astryx.emojiPicker.groupSmileysEmotion": {
|
|
1314
|
+
"defaultMessage": "⟦Šɱíłéýš & éɱóţíóñ⟧"
|
|
1315
|
+
},
|
|
1316
|
+
"@astryx.emojiPicker.groupPeopleBody": {
|
|
1317
|
+
"defaultMessage": "⟦Þéóþłé & ƀóðý⟧"
|
|
1318
|
+
},
|
|
1319
|
+
"@astryx.emojiPicker.groupAnimalsNature": {
|
|
1320
|
+
"defaultMessage": "⟦Àñíɱàłš & ñàţúřé⟧"
|
|
1321
|
+
},
|
|
1322
|
+
"@astryx.emojiPicker.groupFoodDrink": {
|
|
1323
|
+
"defaultMessage": "⟦Ƒóóð & ðříñķ⟧"
|
|
1324
|
+
},
|
|
1325
|
+
"@astryx.emojiPicker.groupTravelPlaces": {
|
|
1326
|
+
"defaultMessage": "⟦Ţřàṽéł & þłàçéš⟧"
|
|
1327
|
+
},
|
|
1328
|
+
"@astryx.emojiPicker.groupActivities": {
|
|
1329
|
+
"defaultMessage": "⟦Àçţíṽíţíéš⟧"
|
|
1330
|
+
},
|
|
1331
|
+
"@astryx.emojiPicker.groupObjects": {
|
|
1332
|
+
"defaultMessage": "⟦Óƀĵéçţš⟧"
|
|
1333
|
+
},
|
|
1334
|
+
"@astryx.emojiPicker.groupSymbols": {
|
|
1335
|
+
"defaultMessage": "⟦Šýɱƀółš⟧"
|
|
1336
|
+
},
|
|
1337
|
+
"@astryx.emojiPicker.groupFlags": {
|
|
1338
|
+
"defaultMessage": "⟦Ƒłàĝš⟧"
|
|
1339
|
+
},
|
|
1340
|
+
"@astryx.comments.retry": {
|
|
1341
|
+
"defaultMessage": "⟦Řéţřý⟧"
|
|
1342
|
+
},
|
|
1343
|
+
"@astryx.commentComposer.placeholder": {
|
|
1344
|
+
"defaultMessage": "⟦Ŵříţé à çóɱɱéñţ…⟧"
|
|
1345
|
+
},
|
|
1346
|
+
"@astryx.commentComposer.noAgents": {
|
|
1347
|
+
"defaultMessage": "⟦Ñó àĝéñţš⟧"
|
|
1348
|
+
},
|
|
1349
|
+
"@astryx.commentComposer.agents": {
|
|
1350
|
+
"defaultMessage": "⟦Àĝéñţš⟧"
|
|
1351
|
+
},
|
|
1352
|
+
"@astryx.commentComposer.uploadFailed": {
|
|
1353
|
+
"defaultMessage": "⟦Íɱàĝéš çóúłðñ'ţ ƀé àððéð⟧"
|
|
1354
|
+
},
|
|
1355
|
+
"@astryx.commentComposer.imagesOnly": {
|
|
1356
|
+
"defaultMessage": "⟦Óñłý íɱàĝé ƒíłéš çàñ ƀé àððéð⟧"
|
|
1357
|
+
},
|
|
1358
|
+
"@astryx.commentComposer.chooseImages": {
|
|
1359
|
+
"defaultMessage": "⟦Çĥóóšé íɱàĝéš⟧"
|
|
1360
|
+
},
|
|
1361
|
+
"@astryx.commentComposer.imageAlt": {
|
|
1362
|
+
"defaultMessage": "⟦Íɱàĝé àţţàçĥɱéñţ⟧"
|
|
1363
|
+
},
|
|
1364
|
+
"@astryx.commentComposer.removeQuote": {
|
|
1365
|
+
"defaultMessage": "⟦Řéɱóṽé ɋúóţéð ţéẋţ⟧"
|
|
1366
|
+
},
|
|
1367
|
+
"@astryx.commentComposer.attachImages": {
|
|
1368
|
+
"defaultMessage": "⟦Àţţàçĥ íɱàĝéš⟧"
|
|
1369
|
+
},
|
|
1370
|
+
"@astryx.commentComposer.addEmoji": {
|
|
1371
|
+
"defaultMessage": "⟦Àðð éɱóĵí⟧"
|
|
1372
|
+
},
|
|
1373
|
+
"@astryx.commentComposer.cancel": {
|
|
1374
|
+
"defaultMessage": "⟦Çàñçéł⟧"
|
|
1375
|
+
},
|
|
1376
|
+
"@astryx.comments.actionsLabel": {
|
|
1377
|
+
"defaultMessage": "⟦Àçţíóñš ƒóř {name}'š çóɱɱéñţ⟧"
|
|
1378
|
+
},
|
|
1379
|
+
"@astryx.comments.addReaction": {
|
|
1380
|
+
"defaultMessage": "⟦Àðð řéàçţíóñ⟧"
|
|
1381
|
+
},
|
|
1382
|
+
"@astryx.comments.agentBadge": {
|
|
1383
|
+
"defaultMessage": "⟦Àĝéñţ⟧"
|
|
1384
|
+
},
|
|
1385
|
+
"@astryx.comments.agentLogo": {
|
|
1386
|
+
"defaultMessage": "⟦{name} łóĝó⟧"
|
|
1387
|
+
},
|
|
1388
|
+
"@astryx.comments.chooseReaction": {
|
|
1389
|
+
"defaultMessage": "⟦Çĥóóšé à řéàçţíóñ⟧"
|
|
1390
|
+
},
|
|
1391
|
+
"@astryx.comments.copyLink": {
|
|
1392
|
+
"defaultMessage": "⟦Çóþý çóɱɱéñţ łíñķ⟧"
|
|
1393
|
+
},
|
|
1394
|
+
"@astryx.comments.currentVersion": {
|
|
1395
|
+
"defaultMessage": "⟦Çúřřéñţ ṽéřšíóñ⟧"
|
|
1396
|
+
},
|
|
1397
|
+
"@astryx.comments.delete": {
|
|
1398
|
+
"defaultMessage": "⟦Ðéłéţé⟧"
|
|
1399
|
+
},
|
|
1400
|
+
"@astryx.comments.deleteDescription": {
|
|
1401
|
+
"defaultMessage": "⟦Ðéłéţé {name}'š çóɱɱéñţ? Ţĥíš àçţíóñ çàññóţ ƀé úñðóñé.⟧"
|
|
1402
|
+
},
|
|
1403
|
+
"@astryx.comments.deleteFailed": {
|
|
1404
|
+
"defaultMessage": "⟦Ţĥíš çóɱɱéñţ çóúłðñ'ţ ƀé ðéłéţéð.⟧"
|
|
1405
|
+
},
|
|
1406
|
+
"@astryx.comments.deleteFailedRetry": {
|
|
1407
|
+
"defaultMessage": "⟦Ţĥíš çóɱɱéñţ çóúłðñ'ţ ƀé ðéłéţéð. Ţřý àĝàíñ.⟧"
|
|
1408
|
+
},
|
|
1409
|
+
"@astryx.comments.deleteTitle": {
|
|
1410
|
+
"defaultMessage": "⟦Ðéłéţé çóɱɱéñţ?⟧"
|
|
1411
|
+
},
|
|
1412
|
+
"@astryx.comments.edit": {
|
|
1413
|
+
"defaultMessage": "⟦Éðíţ⟧"
|
|
1414
|
+
},
|
|
1415
|
+
"@astryx.comments.editFailed": {
|
|
1416
|
+
"defaultMessage": "⟦Ýóúř éðíţ çóúłðñ'ţ ƀé šàṽéð.⟧"
|
|
1417
|
+
},
|
|
1418
|
+
"@astryx.comments.editPlaceholder": {
|
|
1419
|
+
"defaultMessage": "⟦Éðíţ çóɱɱéñţ⟧"
|
|
1420
|
+
},
|
|
1421
|
+
"@astryx.comments.edited": {
|
|
1422
|
+
"defaultMessage": "⟦Éðíţéð⟧"
|
|
1423
|
+
},
|
|
1424
|
+
"@astryx.comments.editingContext": {
|
|
1425
|
+
"defaultMessage": "⟦Éðíţíñĝ çóɱɱéñţ⟧"
|
|
1426
|
+
},
|
|
1427
|
+
"@astryx.comments.hideReplies": {
|
|
1428
|
+
"defaultMessage": "⟦Ĥíðé řéþłíéš⟧"
|
|
1429
|
+
},
|
|
1430
|
+
"@astryx.comments.historyEmptyDescription": {
|
|
1431
|
+
"defaultMessage": "⟦Ţĥíš çóɱɱéñţ ĥàš ñó éàřłíéř ṽéřšíóñš.⟧"
|
|
1432
|
+
},
|
|
1433
|
+
"@astryx.comments.historyEmptyTitle": {
|
|
1434
|
+
"defaultMessage": "⟦Ñó éðíţ ĥíšţóřý⟧"
|
|
1435
|
+
},
|
|
1436
|
+
"@astryx.comments.historyFailed": {
|
|
1437
|
+
"defaultMessage": "⟦Éðíţ ĥíšţóřý çóúłðñ'ţ łóàð⟧"
|
|
1438
|
+
},
|
|
1439
|
+
"@astryx.comments.historyLoadFailed": {
|
|
1440
|
+
"defaultMessage": "⟦Ţĥé çóɱɱéñţ'š éðíţ ĥíšţóřý çóúłðñ'ţ ƀé łóàðéð. Ţřý àĝàíñ.⟧"
|
|
1441
|
+
},
|
|
1442
|
+
"@astryx.comments.historyLoading": {
|
|
1443
|
+
"defaultMessage": "⟦Łóàðíñĝ éðíţ ĥíšţóřý⟧"
|
|
1444
|
+
},
|
|
1445
|
+
"@astryx.comments.historySubtitle": {
|
|
1446
|
+
"defaultMessage": "⟦Çóɱɱéñţ ƀý {name}⟧"
|
|
1447
|
+
},
|
|
1448
|
+
"@astryx.comments.historyTitle": {
|
|
1449
|
+
"defaultMessage": "⟦Éðíţ ĥíšţóřý⟧"
|
|
1450
|
+
},
|
|
1451
|
+
"@astryx.comments.linkCopied": {
|
|
1452
|
+
"defaultMessage": "⟦Çóɱɱéñţ łíñķ çóþíéð⟧"
|
|
1453
|
+
},
|
|
1454
|
+
"@astryx.comments.otherReactors": {
|
|
1455
|
+
"defaultMessage": "⟦{count, plural, one {# other} other {# others}}⟧"
|
|
1456
|
+
},
|
|
1457
|
+
"@astryx.comments.outdated": {
|
|
1458
|
+
"defaultMessage": "⟦Óúţðàţéð⟧"
|
|
1459
|
+
},
|
|
1460
|
+
"@astryx.comments.reactionCelebrate": {
|
|
1461
|
+
"defaultMessage": "⟦Çéłéƀřàţé⟧"
|
|
1462
|
+
},
|
|
1463
|
+
"@astryx.comments.reactionCount": {
|
|
1464
|
+
"defaultMessage": "⟦{reaction}: {count, number}⟧"
|
|
1465
|
+
},
|
|
1466
|
+
"@astryx.comments.reactionFailed": {
|
|
1467
|
+
"defaultMessage": "⟦Ýóúř řéàçţíóñ çóúłðñ'ţ ƀé šàṽéð.⟧"
|
|
1468
|
+
},
|
|
1469
|
+
"@astryx.comments.reactionLaugh": {
|
|
1470
|
+
"defaultMessage": "⟦Ĥàĥà⟧"
|
|
1471
|
+
},
|
|
1472
|
+
"@astryx.comments.reactionLike": {
|
|
1473
|
+
"defaultMessage": "⟦Łíķé⟧"
|
|
1474
|
+
},
|
|
1475
|
+
"@astryx.comments.reactionLove": {
|
|
1476
|
+
"defaultMessage": "⟦Łóṽé⟧"
|
|
1477
|
+
},
|
|
1478
|
+
"@astryx.comments.reactionSad": {
|
|
1479
|
+
"defaultMessage": "⟦Šàð⟧"
|
|
1480
|
+
},
|
|
1481
|
+
"@astryx.comments.reactionWow": {
|
|
1482
|
+
"defaultMessage": "⟦Ŵóŵ⟧"
|
|
1483
|
+
},
|
|
1484
|
+
"@astryx.comments.reopen": {
|
|
1485
|
+
"defaultMessage": "⟦Řéóþéñ⟧"
|
|
1486
|
+
},
|
|
1487
|
+
"@astryx.comments.reopenFailed": {
|
|
1488
|
+
"defaultMessage": "⟦Ţĥíš ţĥřéàð çóúłðñ'ţ ƀé řéóþéñéð.⟧"
|
|
1489
|
+
},
|
|
1490
|
+
"@astryx.comments.reply": {
|
|
1491
|
+
"defaultMessage": "⟦Řéþłý⟧"
|
|
1492
|
+
},
|
|
1493
|
+
"@astryx.comments.replyFailed": {
|
|
1494
|
+
"defaultMessage": "⟦Ýóúř řéþłý çóúłðñ'ţ ƀé þóšţéð.⟧"
|
|
1495
|
+
},
|
|
1496
|
+
"@astryx.comments.replyPlaceholder": {
|
|
1497
|
+
"defaultMessage": "⟦Řéþłý ţó {name}…⟧"
|
|
1498
|
+
},
|
|
1499
|
+
"@astryx.comments.replyingContext": {
|
|
1500
|
+
"defaultMessage": "⟦Řéþłýíñĝ ţó {name}⟧"
|
|
1501
|
+
},
|
|
1502
|
+
"@astryx.comments.resolve": {
|
|
1503
|
+
"defaultMessage": "⟦Ṁàřķ àš řéšółṽéð⟧"
|
|
1504
|
+
},
|
|
1505
|
+
"@astryx.comments.resolveFailed": {
|
|
1506
|
+
"defaultMessage": "⟦Ţĥíš ţĥřéàð çóúłðñ'ţ ƀé řéšółṽéð.⟧"
|
|
1507
|
+
},
|
|
1508
|
+
"@astryx.comments.resolved": {
|
|
1509
|
+
"defaultMessage": "⟦Řéšółṽéð⟧"
|
|
1510
|
+
},
|
|
1511
|
+
"@astryx.comments.resolvedBy": {
|
|
1512
|
+
"defaultMessage": "⟦Řéšółṽéð ƀý {name}⟧"
|
|
1513
|
+
},
|
|
1514
|
+
"@astryx.comments.retryFailed": {
|
|
1515
|
+
"defaultMessage": "⟦Řéţřýíñĝ ðíðñ'ţ ŵóřķ.⟧"
|
|
1516
|
+
},
|
|
1517
|
+
"@astryx.comments.sendFailed": {
|
|
1518
|
+
"defaultMessage": "⟦Çóúłðñ'ţ šéñð ţĥíš çóɱɱéñţ.⟧"
|
|
1519
|
+
},
|
|
1520
|
+
"@astryx.comments.threadLabel": {
|
|
1521
|
+
"defaultMessage": "⟦Ţĥřéàð ƀý {name}⟧"
|
|
1522
|
+
},
|
|
1523
|
+
"@astryx.comments.unread": {
|
|
1524
|
+
"defaultMessage": "⟦Ñéŵ⟧"
|
|
1525
|
+
},
|
|
1526
|
+
"@astryx.comments.unsavedDraft": {
|
|
1527
|
+
"defaultMessage": "⟦Úñšàṽéð ðřàƒţ. Ðíšɱíšš àĝàíñ ţó ðíšçàřð íţ.⟧"
|
|
1528
|
+
},
|
|
1529
|
+
"@astryx.comments.versionAuthor": {
|
|
1530
|
+
"defaultMessage": "⟦ƀý {name}⟧"
|
|
1531
|
+
},
|
|
1532
|
+
"@astryx.comments.viewHistory": {
|
|
1533
|
+
"defaultMessage": "⟦Ṽíéŵ éðíţ ĥíšţóřý⟧"
|
|
1534
|
+
},
|
|
1535
|
+
"@astryx.comments.viewReplies": {
|
|
1536
|
+
"defaultMessage": "⟦Ṽíéŵ {count, plural, one {# reply} other {# replies}}⟧"
|
|
1537
|
+
},
|
|
1538
|
+
"@astryx.comments.commentsLabel": {
|
|
1539
|
+
"defaultMessage": "⟦Ţĥřéàðš íñ {label}⟧"
|
|
1540
|
+
},
|
|
1541
|
+
"@astryx.comments.emptyDescription": {
|
|
1542
|
+
"defaultMessage": "⟦Šţàřţ ţĥé ðíšçúššíóñ ŵíţĥ à çóɱɱéñţ.⟧"
|
|
1543
|
+
},
|
|
1544
|
+
"@astryx.comments.emptyReadOnlyDescription": {
|
|
1545
|
+
"defaultMessage": "⟦Ţĥéřé íš ñó ðíšçúššíóñ óñ ţĥíš íţéɱ.⟧"
|
|
1546
|
+
},
|
|
1547
|
+
"@astryx.comments.emptyTitle": {
|
|
1548
|
+
"defaultMessage": "⟦Ñó çóɱɱéñţš ýéţ⟧"
|
|
1549
|
+
},
|
|
1550
|
+
"@astryx.comments.label": {
|
|
1551
|
+
"defaultMessage": "⟦Çóɱɱéñţš⟧"
|
|
1552
|
+
},
|
|
1553
|
+
"@astryx.comments.loadFailed": {
|
|
1554
|
+
"defaultMessage": "⟦Çóɱɱéñţš çóúłðñ'ţ łóàð⟧"
|
|
1555
|
+
},
|
|
1556
|
+
"@astryx.comments.loadOlder": {
|
|
1557
|
+
"defaultMessage": "⟦Łóàð éàřłíéř çóɱɱéñţš⟧"
|
|
1558
|
+
},
|
|
1559
|
+
"@astryx.comments.loading": {
|
|
1560
|
+
"defaultMessage": "⟦Łóàðíñĝ çóɱɱéñţš⟧"
|
|
1561
|
+
},
|
|
1562
|
+
"@astryx.comments.olderFailed": {
|
|
1563
|
+
"defaultMessage": "⟦Éàřłíéř çóɱɱéñţš çóúłðñ'ţ łóàð⟧"
|
|
1564
|
+
},
|
|
1565
|
+
"@astryx.comments.postFailed": {
|
|
1566
|
+
"defaultMessage": "⟦Ýóúř çóɱɱéñţ çóúłðñ'ţ ƀé þóšţéð.⟧"
|
|
1234
1567
|
}
|
|
1235
1568
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astryxdesign/core",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.2-canary.07f97c6",
|
|
4
4
|
"displayName": "Astryx Core",
|
|
5
5
|
"description": "The component library. Accessible, themeable React components with built-in spacing, dark mode, and StyleX styling.",
|
|
6
6
|
"author": "Meta Open Source",
|
|
@@ -329,6 +329,11 @@
|
|
|
329
329
|
"types": "./dist/Divider/index.d.ts",
|
|
330
330
|
"default": "./dist/Divider/index.js"
|
|
331
331
|
},
|
|
332
|
+
"./Drawer": {
|
|
333
|
+
"source": "./src/Drawer/index.ts",
|
|
334
|
+
"types": "./dist/Drawer/index.d.ts",
|
|
335
|
+
"default": "./dist/Drawer/index.js"
|
|
336
|
+
},
|
|
332
337
|
"./DropdownMenu": {
|
|
333
338
|
"source": "./src/DropdownMenu/index.ts",
|
|
334
339
|
"types": "./dist/DropdownMenu/index.d.ts",
|
|
@@ -787,6 +792,8 @@
|
|
|
787
792
|
"react-dom": ">=19.0.0"
|
|
788
793
|
},
|
|
789
794
|
"devDependencies": {
|
|
795
|
+
"@astryxdesign/a11y-spec": "0.7.2-canary.07f97c6",
|
|
796
|
+
"@astryxdesign/cli": "0.7.2-canary.07f97c6",
|
|
790
797
|
"@babel/cli": "^7.29.7",
|
|
791
798
|
"@babel/core": "^7.29.7",
|
|
792
799
|
"@babel/preset-react": "^7.29.7",
|
|
@@ -797,9 +804,7 @@
|
|
|
797
804
|
"@testing-library/jest-dom": "^6.6.0",
|
|
798
805
|
"@testing-library/react": "^16.3.2",
|
|
799
806
|
"@types/babel__core": "^7.20.5",
|
|
800
|
-
"tailwindcss": "^4.3.2"
|
|
801
|
-
"@astryxdesign/a11y-spec": "0.0.0",
|
|
802
|
-
"@astryxdesign/cli": "0.7.1"
|
|
807
|
+
"tailwindcss": "^4.3.2"
|
|
803
808
|
},
|
|
804
809
|
"dependencies": {
|
|
805
810
|
"intl-messageformat": "^11.2.9"
|
|
@@ -138,7 +138,7 @@ export const docs = {
|
|
|
138
138
|
{
|
|
139
139
|
name: 'isLoading',
|
|
140
140
|
type: 'boolean',
|
|
141
|
-
description: 'Shows a loading spinner and
|
|
141
|
+
description: 'Shows a loading spinner and blocks re-activation while staying focusable (aria-busy + aria-disabled, not native disabled, so keyboard focus is never dropped mid-action). Announces "Loading" via a live region.',
|
|
142
142
|
default: 'false',
|
|
143
143
|
},
|
|
144
144
|
{
|
|
@@ -419,7 +419,7 @@ export const docsDense = {
|
|
|
419
419
|
displayName: 'HTML name for form submission',
|
|
420
420
|
value: 'HTML value for form submission',
|
|
421
421
|
form: 'associates button with form element by ID',
|
|
422
|
-
isLoading: 'shows spinner
|
|
422
|
+
isLoading: 'shows spinner, blocks re-activation but stays focusable (aria-disabled, not native disabled); announces via live region',
|
|
423
423
|
icon: 'icon element rendered before label text; unsized Astryx Icon defaults to sm for sm/md buttons and md for lg',
|
|
424
424
|
isIconOnly: 'when true, renders square icon-only button; label becomes aria-label',
|
|
425
425
|
width: "Width of button. Numbers=pixels, strings=as-is (e.g. '100%' for full-width). Default: content width, capped at the container; label truncates w/ ellipsis in a narrow row; icon-only stays square.",
|
|
@@ -11,7 +11,13 @@
|
|
|
11
11
|
|
|
12
12
|
import {readFileSync} from 'node:fs';
|
|
13
13
|
import {describe, it, expect, vi} from 'vitest';
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
render,
|
|
16
|
+
screen,
|
|
17
|
+
fireEvent,
|
|
18
|
+
createEvent,
|
|
19
|
+
act,
|
|
20
|
+
} from '@testing-library/react';
|
|
15
21
|
import userEvent from '@testing-library/user-event';
|
|
16
22
|
import {Button} from './Button';
|
|
17
23
|
import * as stylex from '@stylexjs/stylex';
|
|
@@ -127,8 +133,9 @@ describe('Button', () => {
|
|
|
127
133
|
it('shows isLoading state with spinner', () => {
|
|
128
134
|
render(<Button label="Submit" isLoading />);
|
|
129
135
|
const button = screen.getByRole('button');
|
|
130
|
-
//
|
|
131
|
-
expect(button).toBeDisabled();
|
|
136
|
+
// Busy is aria-disabled (focusable), not native disabled — see #4871.
|
|
137
|
+
expect(button).not.toBeDisabled();
|
|
138
|
+
expect(button).toHaveAttribute('aria-disabled', 'true');
|
|
132
139
|
expect(button.className).toContain('styles.inactive');
|
|
133
140
|
expect(button.className).not.toContain('styles.disabled');
|
|
134
141
|
});
|
|
@@ -143,7 +150,7 @@ describe('Button', () => {
|
|
|
143
150
|
|
|
144
151
|
it('sets aria-busy synchronously while clickAction is pending', async () => {
|
|
145
152
|
// The spinner reveal is visually delayed (CSS animation-delay), but the
|
|
146
|
-
// loading DOM state — aria-busy and disabled — must not be delayed.
|
|
153
|
+
// loading DOM state — aria-busy and aria-disabled — must not be delayed.
|
|
147
154
|
const user = userEvent.setup();
|
|
148
155
|
let resolveAction: (() => void) | undefined;
|
|
149
156
|
const clickAction = vi.fn(
|
|
@@ -157,7 +164,9 @@ describe('Button', () => {
|
|
|
157
164
|
|
|
158
165
|
await user.click(button);
|
|
159
166
|
expect(button).toHaveAttribute('aria-busy', 'true');
|
|
160
|
-
|
|
167
|
+
// Busy is aria-disabled (focusable), not native disabled — see #4871.
|
|
168
|
+
expect(button).not.toBeDisabled();
|
|
169
|
+
expect(button).toHaveAttribute('aria-disabled', 'true');
|
|
161
170
|
|
|
162
171
|
await act(async () => {
|
|
163
172
|
resolveAction?.();
|
|
@@ -165,6 +174,7 @@ describe('Button', () => {
|
|
|
165
174
|
});
|
|
166
175
|
expect(button).not.toHaveAttribute('aria-busy', 'true');
|
|
167
176
|
expect(button).not.toBeDisabled();
|
|
177
|
+
expect(button).not.toHaveAttribute('aria-disabled');
|
|
168
178
|
});
|
|
169
179
|
|
|
170
180
|
it('renders the loading spinner with the inherit shade for every variant (#2717)', () => {
|
|
@@ -310,9 +320,10 @@ describe('Button', () => {
|
|
|
310
320
|
);
|
|
311
321
|
// endContent should still be in the DOM
|
|
312
322
|
expect(screen.getByTestId('end')).toBeInTheDocument();
|
|
313
|
-
//
|
|
323
|
+
// Busy is aria-disabled (focusable), not native disabled — see #4871.
|
|
314
324
|
const button = screen.getByRole('button');
|
|
315
|
-
expect(button).toBeDisabled();
|
|
325
|
+
expect(button).not.toBeDisabled();
|
|
326
|
+
expect(button).toHaveAttribute('aria-disabled', 'true');
|
|
316
327
|
expect(button).toHaveAttribute('aria-busy', 'true');
|
|
317
328
|
});
|
|
318
329
|
|
|
@@ -516,6 +527,111 @@ describe('Button', () => {
|
|
|
516
527
|
expect(handleKeyDown).toHaveBeenCalledTimes(1);
|
|
517
528
|
});
|
|
518
529
|
|
|
530
|
+
it('uses aria-disabled instead of disabled while isLoading, so the button stays focusable (#4871)', () => {
|
|
531
|
+
render(<Button label="Save" isLoading />);
|
|
532
|
+
const button = screen.getByRole('button');
|
|
533
|
+
// Native disabled would move focus to <body> the moment the action
|
|
534
|
+
// starts, losing the keyboard user's place — busy must stay
|
|
535
|
+
// aria-disabled + focusable per the "Disabled vs Busy" convention.
|
|
536
|
+
expect(button).not.toHaveAttribute('disabled');
|
|
537
|
+
expect(button).toHaveAttribute('aria-disabled', 'true');
|
|
538
|
+
expect(button).toHaveAttribute('aria-busy', 'true');
|
|
539
|
+
button.focus();
|
|
540
|
+
expect(button).toHaveFocus();
|
|
541
|
+
});
|
|
542
|
+
|
|
543
|
+
it('does not fire onClick while aria-disabled via isLoading', async () => {
|
|
544
|
+
const user = userEvent.setup();
|
|
545
|
+
const handleClick = vi.fn();
|
|
546
|
+
render(<Button label="Save" isLoading onClick={handleClick} />);
|
|
547
|
+
await user.click(screen.getByRole('button'));
|
|
548
|
+
expect(handleClick).not.toHaveBeenCalled();
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
it('does not let a click on a busy button reach a wrapping ancestor handler', async () => {
|
|
552
|
+
// A native `disabled` element never dispatches a click, so it never
|
|
553
|
+
// reaches an ancestor either. aria-disabled (busy-only) is a real,
|
|
554
|
+
// interactive element that still dispatches one — preventDefault alone
|
|
555
|
+
// only cancels the button's own default action, not propagation, so
|
|
556
|
+
// an unrelated wrapper (a clickable row/card/backdrop) would otherwise
|
|
557
|
+
// still fire.
|
|
558
|
+
const user = userEvent.setup();
|
|
559
|
+
const ancestorClick = vi.fn();
|
|
560
|
+
render(
|
|
561
|
+
<div onClick={ancestorClick}>
|
|
562
|
+
<Button label="Save" isLoading />
|
|
563
|
+
</div>,
|
|
564
|
+
);
|
|
565
|
+
await user.click(screen.getByRole('button'));
|
|
566
|
+
expect(ancestorClick).not.toHaveBeenCalled();
|
|
567
|
+
});
|
|
568
|
+
|
|
569
|
+
it('does not let a click on a busy-only anchor Button reach a wrapping ancestor handler', async () => {
|
|
570
|
+
const user = userEvent.setup();
|
|
571
|
+
const ancestorClick = vi.fn();
|
|
572
|
+
render(
|
|
573
|
+
<div onClick={ancestorClick}>
|
|
574
|
+
<Button label="Docs" href="https://example.com" isLoading />
|
|
575
|
+
</div>,
|
|
576
|
+
);
|
|
577
|
+
await user.click(screen.getByRole('link'));
|
|
578
|
+
expect(ancestorClick).not.toHaveBeenCalled();
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
it('suppresses activation keys but passes other keys while aria-disabled via isLoading', async () => {
|
|
582
|
+
const user = userEvent.setup();
|
|
583
|
+
const handleKeyDown = vi.fn();
|
|
584
|
+
render(<Button label="Save" isLoading onKeyDown={handleKeyDown} />);
|
|
585
|
+
const button = screen.getByRole('button');
|
|
586
|
+
button.focus();
|
|
587
|
+
await user.keyboard('{Enter}');
|
|
588
|
+
expect(handleKeyDown).not.toHaveBeenCalled();
|
|
589
|
+
|
|
590
|
+
await user.keyboard('{Escape}');
|
|
591
|
+
expect(handleKeyDown).toHaveBeenCalledTimes(1);
|
|
592
|
+
});
|
|
593
|
+
|
|
594
|
+
it('suppresses activation keys but passes other keys on a busy-only anchor Button', async () => {
|
|
595
|
+
// The button-rendered path suppresses Enter/Space while aria-disabled;
|
|
596
|
+
// the anchor-rendered path (href set, busy-only) shares the same
|
|
597
|
+
// handleKeyDown but only wires onClick, so a consumer onKeyDown still
|
|
598
|
+
// received Enter/Space on a busy link.
|
|
599
|
+
const user = userEvent.setup();
|
|
600
|
+
const handleKeyDown = vi.fn();
|
|
601
|
+
render(
|
|
602
|
+
<Button
|
|
603
|
+
label="Docs"
|
|
604
|
+
href="https://example.com"
|
|
605
|
+
isLoading
|
|
606
|
+
onKeyDown={handleKeyDown}
|
|
607
|
+
/>,
|
|
608
|
+
);
|
|
609
|
+
const link = screen.getByRole('link');
|
|
610
|
+
link.focus();
|
|
611
|
+
await user.keyboard('{Enter}');
|
|
612
|
+
expect(handleKeyDown).not.toHaveBeenCalled();
|
|
613
|
+
|
|
614
|
+
await user.keyboard('{Escape}');
|
|
615
|
+
expect(handleKeyDown).toHaveBeenCalledTimes(1);
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
it('keeps native disabled (not aria-disabled) when isDisabled and not busy, even without a tooltip', () => {
|
|
619
|
+
render(<Button label="Save" isDisabled />);
|
|
620
|
+
const button = screen.getByRole('button');
|
|
621
|
+
expect(button).toHaveAttribute('disabled');
|
|
622
|
+
expect(button).not.toHaveAttribute('aria-disabled');
|
|
623
|
+
});
|
|
624
|
+
|
|
625
|
+
it('keeps native disabled when isDisabled and isLoading are both true (isDisabled wins)', () => {
|
|
626
|
+
render(<Button label="Save" isDisabled isLoading />);
|
|
627
|
+
const button = screen.getByRole('button');
|
|
628
|
+
// "isDisabled behavior unchanged: that stays native disabled" — busy-only
|
|
629
|
+
// aria-disabled is only for the case where busy is the SOLE reason the
|
|
630
|
+
// button can't be clicked, not when it's also genuinely isDisabled.
|
|
631
|
+
expect(button).toHaveAttribute('disabled');
|
|
632
|
+
expect(button).not.toHaveAttribute('aria-disabled');
|
|
633
|
+
});
|
|
634
|
+
|
|
519
635
|
it('has a live region that announces loading state', () => {
|
|
520
636
|
const {rerender} = render(<Button label="Submit" />);
|
|
521
637
|
const button = screen.getByRole('button');
|
|
@@ -663,8 +779,6 @@ describe('Button', () => {
|
|
|
663
779
|
});
|
|
664
780
|
|
|
665
781
|
it('exposes aria-busy on the link-rendered button while loading', () => {
|
|
666
|
-
// Non-interruptible loading disables the button, which falls back to
|
|
667
|
-
// <button> rendering — so an anchor only shows loading when interruptible.
|
|
668
782
|
render(
|
|
669
783
|
<Button
|
|
670
784
|
label="Docs"
|
|
@@ -682,6 +796,38 @@ describe('Button', () => {
|
|
|
682
796
|
const link = screen.getByRole('link');
|
|
683
797
|
expect(link).not.toHaveAttribute('aria-busy');
|
|
684
798
|
});
|
|
799
|
+
|
|
800
|
+
it('stays an anchor while busy-only, not a disabled <button> fallback (#4871)', () => {
|
|
801
|
+
// Non-interruptible busy is exactly the isBusyOnlyDisabled case: not
|
|
802
|
+
// isDisabled, blocked only because a fire-once action is in flight.
|
|
803
|
+
// Swapping the element to <button disabled> here would drop focus the
|
|
804
|
+
// same way the native disabled attribute did (credit @AKnassa, #4879).
|
|
805
|
+
render(<Button label="Docs" href="https://example.com" isLoading />);
|
|
806
|
+
const link = screen.getByRole('link', {name: 'Docs'});
|
|
807
|
+
expect(link.tagName).toBe('A');
|
|
808
|
+
expect(link).toHaveAttribute('href', 'https://example.com');
|
|
809
|
+
expect(link).toHaveAttribute('aria-busy', 'true');
|
|
810
|
+
expect(link).toHaveAttribute('aria-disabled', 'true');
|
|
811
|
+
expect(link).not.toHaveAttribute('disabled');
|
|
812
|
+
});
|
|
813
|
+
|
|
814
|
+
it('keeps a busy-only anchor focusable and guards its navigation', () => {
|
|
815
|
+
render(<Button label="Docs" href="https://example.com" isLoading />);
|
|
816
|
+
const link = screen.getByRole('link', {name: 'Docs'});
|
|
817
|
+
link.focus();
|
|
818
|
+
expect(link).toHaveFocus();
|
|
819
|
+
|
|
820
|
+
const event = createEvent.click(link);
|
|
821
|
+
fireEvent(link, event);
|
|
822
|
+
expect(event.defaultPrevented).toBe(true);
|
|
823
|
+
});
|
|
824
|
+
|
|
825
|
+
it('falls back to <button disabled> for a truly disabled href Button', () => {
|
|
826
|
+
render(<Button label="Docs" href="https://example.com" isDisabled />);
|
|
827
|
+
expect(screen.queryByRole('link')).not.toBeInTheDocument();
|
|
828
|
+
const button = screen.getByRole('button', {name: 'Docs'});
|
|
829
|
+
expect(button).toBeDisabled();
|
|
830
|
+
});
|
|
685
831
|
});
|
|
686
832
|
|
|
687
833
|
describe('Button pressed state (touch)', () => {
|