@workday/canvas-kit-docs 7.0.0-alpha.89-next.16 → 7.0.0-alpha.92-next.19
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/commonjs/lib/specs.js +131 -0
- package/dist/es6/lib/specs.js +131 -0
- package/dist/mdx/7.0-MIGRATION-GUIDE.mdx +311 -1
- package/dist/mdx/changelog.stories.mdx +1 -0
- package/dist/mdx/preview-react/form-field/examples/Custom.tsx +3 -4
- package/dist/mdx/preview-react/menu/Menu.mdx +1 -1
- package/dist/mdx/preview-react/menu/examples/Icons.tsx +0 -1
- package/dist/mdx/react/button/button/Button.mdx +3 -3
- package/dist/mdx/react/collection/Collection.mdx +136 -0
- package/dist/mdx/react/collection/examples/Basic.tsx +12 -0
- package/dist/mdx/react/collection/examples/BasicVirtual.tsx +24 -0
- package/dist/mdx/react/collection/examples/DynamicItems.tsx +20 -0
- package/dist/mdx/react/collection/examples/IdentifiedItems.tsx +12 -0
- package/dist/mdx/react/collection/examples/MultiSelection.tsx +56 -0
- package/dist/mdx/react/collection/examples/RovingFocus.tsx +39 -0
- package/dist/mdx/react/collection/examples/Selection.tsx +58 -0
- package/dist/mdx/react/color-picker/color-input/ColorInput.mdx +2 -2
- package/dist/mdx/react/color-picker/color-preview/ColorPreview.mdx +2 -2
- package/dist/mdx/react/layout/Flex.mdx +22 -22
- package/dist/mdx/react/layout/Stack.mdx +98 -139
- package/dist/mdx/react/menu/Menu.mdx +123 -0
- package/dist/mdx/react/menu/examples/Basic.tsx +26 -0
- package/dist/mdx/react/menu/examples/ContextMenu.tsx +25 -0
- package/dist/mdx/react/menu/examples/Icons.tsx +41 -0
- package/dist/mdx/react/modal/examples/ReturnFocus.tsx +1 -1
- package/dist/mdx/react/popup/examples/InitialFocus.tsx +4 -2
- package/dist/mdx/react/popup/examples/NestedPopups.tsx +17 -17
- package/dist/mdx/react/popup/examples/RTL.tsx +6 -3
- package/dist/mdx/react/tabs/Tabs.mdx +4 -8
- package/dist/mdx/react/tabs/examples/DynamicTabs.tsx +4 -7
- package/dist/mdx/react/tabs/examples/HoistedModel.tsx +8 -8
- package/dist/mdx/react/tabs/examples/Icons.tsx +4 -4
- package/dist/mdx/react/tabs/examples/NamedTabs.tsx +10 -10
- package/dist/mdx/react/tabs/examples/OverflowTabs.tsx +2 -2
- package/dist/mdx/react/text-input/examples/Basic.tsx +3 -0
- package/package.json +7 -16
- package/ts3.5/dist/commonjs/index.d.ts +0 -4
- package/ts3.5/dist/commonjs/lib/Specifications.d.ts +0 -6
- package/ts3.5/dist/commonjs/lib/docs.d.ts +0 -5
- package/ts3.5/dist/commonjs/lib/specs.d.ts +0 -16
- package/ts3.5/dist/es6/index.d.ts +0 -4
- package/ts3.5/dist/es6/lib/Specifications.d.ts +0 -6
- package/ts3.5/dist/es6/lib/docs.d.ts +0 -5
- package/ts3.5/dist/es6/lib/specs.d.ts +0 -16
|
@@ -1302,6 +1302,137 @@ module.exports = {specifications: [
|
|
|
1302
1302
|
{
|
|
1303
1303
|
"type": "file",
|
|
1304
1304
|
"name": "Menu.spec.ts",
|
|
1305
|
+
"children": [
|
|
1306
|
+
{
|
|
1307
|
+
"type": "describe",
|
|
1308
|
+
"name": "Menu",
|
|
1309
|
+
"children": [
|
|
1310
|
+
{
|
|
1311
|
+
"type": "describe",
|
|
1312
|
+
"name": "given the [Components/Popups/Menu/React, Basic] story is rendered",
|
|
1313
|
+
"children": [
|
|
1314
|
+
{
|
|
1315
|
+
"type": "it",
|
|
1316
|
+
"name": "should pass axe checks"
|
|
1317
|
+
},
|
|
1318
|
+
{
|
|
1319
|
+
"type": "it",
|
|
1320
|
+
"name": "should have aria-haspopup set to true"
|
|
1321
|
+
},
|
|
1322
|
+
{
|
|
1323
|
+
"type": "it",
|
|
1324
|
+
"name": "should have aria-expanded set to false"
|
|
1325
|
+
},
|
|
1326
|
+
{
|
|
1327
|
+
"type": "it",
|
|
1328
|
+
"name": "should not show a menu"
|
|
1329
|
+
},
|
|
1330
|
+
{
|
|
1331
|
+
"type": "describe",
|
|
1332
|
+
"name": "when the \"Open Menu\" button is clicked",
|
|
1333
|
+
"children": [
|
|
1334
|
+
{
|
|
1335
|
+
"type": "it",
|
|
1336
|
+
"name": "should set aria-expanded to true"
|
|
1337
|
+
},
|
|
1338
|
+
{
|
|
1339
|
+
"type": "it",
|
|
1340
|
+
"name": "should show menu"
|
|
1341
|
+
},
|
|
1342
|
+
{
|
|
1343
|
+
"type": "it",
|
|
1344
|
+
"name": "should transfer focus to the first menu item"
|
|
1345
|
+
},
|
|
1346
|
+
{
|
|
1347
|
+
"type": "describe",
|
|
1348
|
+
"name": "when escape key is pressed",
|
|
1349
|
+
"children": [
|
|
1350
|
+
{
|
|
1351
|
+
"type": "it",
|
|
1352
|
+
"name": "should have aria-expanded set to false"
|
|
1353
|
+
},
|
|
1354
|
+
{
|
|
1355
|
+
"type": "it",
|
|
1356
|
+
"name": "should not show a menu"
|
|
1357
|
+
},
|
|
1358
|
+
{
|
|
1359
|
+
"type": "it",
|
|
1360
|
+
"name": "return focus to the \"Open Menu\" button"
|
|
1361
|
+
}
|
|
1362
|
+
]
|
|
1363
|
+
},
|
|
1364
|
+
{
|
|
1365
|
+
"type": "describe",
|
|
1366
|
+
"name": "when down arrow key is pressed",
|
|
1367
|
+
"children": [
|
|
1368
|
+
{
|
|
1369
|
+
"type": "it",
|
|
1370
|
+
"name": "should transfer focus to the second item"
|
|
1371
|
+
},
|
|
1372
|
+
{
|
|
1373
|
+
"type": "describe",
|
|
1374
|
+
"name": "when the enter key is pressed",
|
|
1375
|
+
"children": [
|
|
1376
|
+
{
|
|
1377
|
+
"type": "it",
|
|
1378
|
+
"name": "should have aria-expanded set to false"
|
|
1379
|
+
},
|
|
1380
|
+
{
|
|
1381
|
+
"type": "it",
|
|
1382
|
+
"name": "should not show a menu"
|
|
1383
|
+
},
|
|
1384
|
+
{
|
|
1385
|
+
"type": "it",
|
|
1386
|
+
"name": "should select the second item"
|
|
1387
|
+
}
|
|
1388
|
+
]
|
|
1389
|
+
}
|
|
1390
|
+
]
|
|
1391
|
+
},
|
|
1392
|
+
{
|
|
1393
|
+
"type": "describe",
|
|
1394
|
+
"name": "when the second item is clicked",
|
|
1395
|
+
"children": [
|
|
1396
|
+
{
|
|
1397
|
+
"type": "it",
|
|
1398
|
+
"name": "should have aria-expanded set to false"
|
|
1399
|
+
},
|
|
1400
|
+
{
|
|
1401
|
+
"type": "it",
|
|
1402
|
+
"name": "should not show a menu"
|
|
1403
|
+
},
|
|
1404
|
+
{
|
|
1405
|
+
"type": "it",
|
|
1406
|
+
"name": "should select the second item"
|
|
1407
|
+
}
|
|
1408
|
+
]
|
|
1409
|
+
},
|
|
1410
|
+
{
|
|
1411
|
+
"type": "describe",
|
|
1412
|
+
"name": "when the user types a printable character \"t\"",
|
|
1413
|
+
"children": []
|
|
1414
|
+
},
|
|
1415
|
+
{
|
|
1416
|
+
"type": "describe",
|
|
1417
|
+
"name": "when up arrow key is pressed",
|
|
1418
|
+
"children": [
|
|
1419
|
+
{
|
|
1420
|
+
"type": "it",
|
|
1421
|
+
"name": "should focus on the last option"
|
|
1422
|
+
}
|
|
1423
|
+
]
|
|
1424
|
+
}
|
|
1425
|
+
]
|
|
1426
|
+
}
|
|
1427
|
+
]
|
|
1428
|
+
}
|
|
1429
|
+
]
|
|
1430
|
+
}
|
|
1431
|
+
]
|
|
1432
|
+
},
|
|
1433
|
+
{
|
|
1434
|
+
"type": "file",
|
|
1435
|
+
"name": "MenuPreview.spec.ts",
|
|
1305
1436
|
"children": [
|
|
1306
1437
|
{
|
|
1307
1438
|
"type": "describe",
|
package/dist/es6/lib/specs.js
CHANGED
|
@@ -1302,6 +1302,137 @@ module.exports = {specifications: [
|
|
|
1302
1302
|
{
|
|
1303
1303
|
"type": "file",
|
|
1304
1304
|
"name": "Menu.spec.ts",
|
|
1305
|
+
"children": [
|
|
1306
|
+
{
|
|
1307
|
+
"type": "describe",
|
|
1308
|
+
"name": "Menu",
|
|
1309
|
+
"children": [
|
|
1310
|
+
{
|
|
1311
|
+
"type": "describe",
|
|
1312
|
+
"name": "given the [Components/Popups/Menu/React, Basic] story is rendered",
|
|
1313
|
+
"children": [
|
|
1314
|
+
{
|
|
1315
|
+
"type": "it",
|
|
1316
|
+
"name": "should pass axe checks"
|
|
1317
|
+
},
|
|
1318
|
+
{
|
|
1319
|
+
"type": "it",
|
|
1320
|
+
"name": "should have aria-haspopup set to true"
|
|
1321
|
+
},
|
|
1322
|
+
{
|
|
1323
|
+
"type": "it",
|
|
1324
|
+
"name": "should have aria-expanded set to false"
|
|
1325
|
+
},
|
|
1326
|
+
{
|
|
1327
|
+
"type": "it",
|
|
1328
|
+
"name": "should not show a menu"
|
|
1329
|
+
},
|
|
1330
|
+
{
|
|
1331
|
+
"type": "describe",
|
|
1332
|
+
"name": "when the \"Open Menu\" button is clicked",
|
|
1333
|
+
"children": [
|
|
1334
|
+
{
|
|
1335
|
+
"type": "it",
|
|
1336
|
+
"name": "should set aria-expanded to true"
|
|
1337
|
+
},
|
|
1338
|
+
{
|
|
1339
|
+
"type": "it",
|
|
1340
|
+
"name": "should show menu"
|
|
1341
|
+
},
|
|
1342
|
+
{
|
|
1343
|
+
"type": "it",
|
|
1344
|
+
"name": "should transfer focus to the first menu item"
|
|
1345
|
+
},
|
|
1346
|
+
{
|
|
1347
|
+
"type": "describe",
|
|
1348
|
+
"name": "when escape key is pressed",
|
|
1349
|
+
"children": [
|
|
1350
|
+
{
|
|
1351
|
+
"type": "it",
|
|
1352
|
+
"name": "should have aria-expanded set to false"
|
|
1353
|
+
},
|
|
1354
|
+
{
|
|
1355
|
+
"type": "it",
|
|
1356
|
+
"name": "should not show a menu"
|
|
1357
|
+
},
|
|
1358
|
+
{
|
|
1359
|
+
"type": "it",
|
|
1360
|
+
"name": "return focus to the \"Open Menu\" button"
|
|
1361
|
+
}
|
|
1362
|
+
]
|
|
1363
|
+
},
|
|
1364
|
+
{
|
|
1365
|
+
"type": "describe",
|
|
1366
|
+
"name": "when down arrow key is pressed",
|
|
1367
|
+
"children": [
|
|
1368
|
+
{
|
|
1369
|
+
"type": "it",
|
|
1370
|
+
"name": "should transfer focus to the second item"
|
|
1371
|
+
},
|
|
1372
|
+
{
|
|
1373
|
+
"type": "describe",
|
|
1374
|
+
"name": "when the enter key is pressed",
|
|
1375
|
+
"children": [
|
|
1376
|
+
{
|
|
1377
|
+
"type": "it",
|
|
1378
|
+
"name": "should have aria-expanded set to false"
|
|
1379
|
+
},
|
|
1380
|
+
{
|
|
1381
|
+
"type": "it",
|
|
1382
|
+
"name": "should not show a menu"
|
|
1383
|
+
},
|
|
1384
|
+
{
|
|
1385
|
+
"type": "it",
|
|
1386
|
+
"name": "should select the second item"
|
|
1387
|
+
}
|
|
1388
|
+
]
|
|
1389
|
+
}
|
|
1390
|
+
]
|
|
1391
|
+
},
|
|
1392
|
+
{
|
|
1393
|
+
"type": "describe",
|
|
1394
|
+
"name": "when the second item is clicked",
|
|
1395
|
+
"children": [
|
|
1396
|
+
{
|
|
1397
|
+
"type": "it",
|
|
1398
|
+
"name": "should have aria-expanded set to false"
|
|
1399
|
+
},
|
|
1400
|
+
{
|
|
1401
|
+
"type": "it",
|
|
1402
|
+
"name": "should not show a menu"
|
|
1403
|
+
},
|
|
1404
|
+
{
|
|
1405
|
+
"type": "it",
|
|
1406
|
+
"name": "should select the second item"
|
|
1407
|
+
}
|
|
1408
|
+
]
|
|
1409
|
+
},
|
|
1410
|
+
{
|
|
1411
|
+
"type": "describe",
|
|
1412
|
+
"name": "when the user types a printable character \"t\"",
|
|
1413
|
+
"children": []
|
|
1414
|
+
},
|
|
1415
|
+
{
|
|
1416
|
+
"type": "describe",
|
|
1417
|
+
"name": "when up arrow key is pressed",
|
|
1418
|
+
"children": [
|
|
1419
|
+
{
|
|
1420
|
+
"type": "it",
|
|
1421
|
+
"name": "should focus on the last option"
|
|
1422
|
+
}
|
|
1423
|
+
]
|
|
1424
|
+
}
|
|
1425
|
+
]
|
|
1426
|
+
}
|
|
1427
|
+
]
|
|
1428
|
+
}
|
|
1429
|
+
]
|
|
1430
|
+
}
|
|
1431
|
+
]
|
|
1432
|
+
},
|
|
1433
|
+
{
|
|
1434
|
+
"type": "file",
|
|
1435
|
+
"name": "MenuPreview.spec.ts",
|
|
1305
1436
|
"children": [
|
|
1306
1437
|
{
|
|
1307
1438
|
"type": "describe",
|
|
@@ -5,6 +5,7 @@ Below are the breaking changes made in Canvas Kit v7. Please
|
|
|
5
5
|
any questions about the update.
|
|
6
6
|
|
|
7
7
|
- [Codemod](#codemod)
|
|
8
|
+
- [Infrastructure](#infrastructure)
|
|
8
9
|
- [Component Deprecations](#component-deprecations)
|
|
9
10
|
- [Component Promotions](#component-promotion)
|
|
10
11
|
- [Buttons](#buttons)
|
|
@@ -16,6 +17,7 @@ any questions about the update.
|
|
|
16
17
|
- [Popup Cards](#popup-cards)
|
|
17
18
|
- [Popper Props Update](#popper-props-update)
|
|
18
19
|
- [Component Promotions](#component-promotion)
|
|
20
|
+
- [Model Changes](#model-changes)
|
|
19
21
|
- [Token Updates](#token-updates)
|
|
20
22
|
- [Depth Tokens](#depth-tokens)
|
|
21
23
|
|
|
@@ -45,6 +47,19 @@ rollback more easily if necessary.**
|
|
|
45
47
|
encounter any issues or use cases that we've missed. The `@workday/canvas-kit-codemod` package will
|
|
46
48
|
help us maintain additional codemod transforms to make future migrations easier.
|
|
47
49
|
|
|
50
|
+
## Infrastructure
|
|
51
|
+
|
|
52
|
+
## Infrastructure Upgrades
|
|
53
|
+
|
|
54
|
+
Breaking:
|
|
55
|
+
|
|
56
|
+
- v7 now requires Typescript 4.1 and has dropped support for Typescript 3.5-3.9. Previously we used
|
|
57
|
+
`downlevel-dts` to support Typescript 3.5+ while using Typescript 3.8 features, but
|
|
58
|
+
`downlevel-dts` does not support the Typescript 4.1 features we use. Typescript 4.1 was release in
|
|
59
|
+
November, 2020 and we feel it is time to move forward. Reach out if you experience issues
|
|
60
|
+
upgrading your Typescript version. In our experience, Typescript 4.1 found a few more errors that
|
|
61
|
+
Typescript 3.8 did not, but the upgrade was manageable.
|
|
62
|
+
|
|
48
63
|
## Component Deprecations
|
|
49
64
|
|
|
50
65
|
### Deprecation Types
|
|
@@ -330,7 +345,7 @@ system.
|
|
|
330
345
|
|
|
331
346
|
## Segmented Control
|
|
332
347
|
|
|
333
|
-
|
|
348
|
+
Segmented Control use to work when rendering `IconButton` as children. This has now moved to a
|
|
334
349
|
compound component and removed the use of `IconButton`.
|
|
335
350
|
|
|
336
351
|
### Breaking Change
|
|
@@ -463,6 +478,44 @@ If your code contains any hacks to make a `Modal` overflow, these hacks should n
|
|
|
463
478
|
`max-height` of the `Modal.Body` element using calculations. These should be removed. The
|
|
464
479
|
`Popup.Card` now has a max height and the `Popup.Body` height is automatically calculated.
|
|
465
480
|
|
|
481
|
+
### Popup.Body
|
|
482
|
+
|
|
483
|
+
The `Popup.Body` is now an overflow container. This means 2 things:
|
|
484
|
+
|
|
485
|
+
- `Popup.Body` will scroll if the contents are too big to fit in the page
|
|
486
|
+
- `Popup.Body` will hide focus rings that render outside the overflow container
|
|
487
|
+
|
|
488
|
+
Our examples contained some buttons inside the `Body` element and had focus rings cut off. The
|
|
489
|
+
adjustment is to move the buttons outside the `Body` element. This is most likely the desired
|
|
490
|
+
structure anyways since the buttons will not scroll with the overflowed `Body` content.
|
|
491
|
+
|
|
492
|
+
Before:
|
|
493
|
+
|
|
494
|
+
```tsx
|
|
495
|
+
<Modal.Card>
|
|
496
|
+
<Modal.Body>
|
|
497
|
+
Body Contents
|
|
498
|
+
<HStack spacing="s">
|
|
499
|
+
{/*will scroll with the body*/}
|
|
500
|
+
<Modal.CloseButton as={PrimaryButton}>Delete</Modal.CloseButton>
|
|
501
|
+
<Modal.CloseButton>Cancel</Modal.CloseButton>
|
|
502
|
+
</HStack>
|
|
503
|
+
</Modal.Body>
|
|
504
|
+
</Modal.Card>
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
After:
|
|
508
|
+
|
|
509
|
+
```tsx
|
|
510
|
+
<Modal.Card>
|
|
511
|
+
<Modal.Body>Body Contents</Modal.Body>
|
|
512
|
+
<HStack spacing="s">
|
|
513
|
+
<Modal.CloseButton as={PrimaryButton}>Delete</Modal.CloseButton>
|
|
514
|
+
<Modal.CloseButton>Cancel</Modal.CloseButton>
|
|
515
|
+
</HStack>
|
|
516
|
+
</Modal.Card>
|
|
517
|
+
```
|
|
518
|
+
|
|
466
519
|
## Popper Props Update
|
|
467
520
|
|
|
468
521
|
We removed the `containerElement` prop from Popper component because it's no longer needed with
|
|
@@ -482,6 +535,263 @@ main `react` package.
|
|
|
482
535
|
- `Flex` was promoted from `@workday/canvas-kit-labs/layout` to `@workday/canvas-kit-react/layout`
|
|
483
536
|
- `Stack` was promoted from `@workday/canvas-kit-labs/layout` to `@workday/canvas-kit-react/layout`
|
|
484
537
|
|
|
538
|
+
## Model Changes
|
|
539
|
+
|
|
540
|
+
### Guards and Callbacks
|
|
541
|
+
|
|
542
|
+
We changed the signature of model event guards and callbacks. In v6, the parameters were in an
|
|
543
|
+
object. This has a less than ideal developer experience as intellisense isn't engaged immediately
|
|
544
|
+
and we don't plan on adding any additional parameters to guard and callback functions. We've removed
|
|
545
|
+
the object wrapper.
|
|
546
|
+
|
|
547
|
+
🤖 The codemod handles these changes automatically.
|
|
548
|
+
|
|
549
|
+
Before:
|
|
550
|
+
|
|
551
|
+
```tsx
|
|
552
|
+
const model = useTabsModel({
|
|
553
|
+
onSelect({data: {id}, prevState}) {
|
|
554
|
+
console.log(id, prevState);
|
|
555
|
+
},
|
|
556
|
+
});
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
After:
|
|
560
|
+
|
|
561
|
+
```tsx
|
|
562
|
+
const model = useTabsModel({
|
|
563
|
+
onSelect({id}, prevState) {
|
|
564
|
+
console.log(id, prevState);
|
|
565
|
+
},
|
|
566
|
+
});
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
### Model Implementation
|
|
570
|
+
|
|
571
|
+
If you don't extend models, you can skip this section.
|
|
572
|
+
|
|
573
|
+
In v6 we supported Typescript 3.8 which limited the way types could be inferred and defined. Canvas
|
|
574
|
+
Kit v7 now requires Typescript 4.1 which introduced
|
|
575
|
+
[Template Literal Types](https://www.typescriptlang.org/docs/handbook/2/template-literal-types.html).
|
|
576
|
+
This means that the guards and callbacks no longer need to be manually defined via an `eventMap`.
|
|
577
|
+
Event maps were a stopgap, were manual, and prone to errors in defining them. Not all events had
|
|
578
|
+
guards or callbacks there's no check other than manual review to ensure the existence of an event
|
|
579
|
+
callback or guard. Template Literal Types allow us to properly type guards and callbacks without
|
|
580
|
+
event maps. The previous types forced `data` to be an object. We've since dropped that restriction.
|
|
581
|
+
You can still only pass a single argument to events. If you need additional information, use an
|
|
582
|
+
object.
|
|
583
|
+
|
|
584
|
+
This change also allowed us to remove a lot of boilerplate associated with models without
|
|
585
|
+
sacrificing type safety. This change doesn't effect most use cases, but will effect those whole
|
|
586
|
+
extended a model. We created a new utility function called `createModelHook` that helps set up
|
|
587
|
+
types.
|
|
588
|
+
|
|
589
|
+
Before:
|
|
590
|
+
|
|
591
|
+
```ts
|
|
592
|
+
export type MyState = {
|
|
593
|
+
value: string;
|
|
594
|
+
};
|
|
595
|
+
|
|
596
|
+
export type MyEvents = {
|
|
597
|
+
updateValue(data: {value: string}): void; // enforced that `data` is an object even if we only need to pass a string
|
|
598
|
+
};
|
|
599
|
+
|
|
600
|
+
export type MyModel = Model<MyState, MyEvents>;
|
|
601
|
+
|
|
602
|
+
export const myEventMap = createEventMap<MyEvents>()({
|
|
603
|
+
guards: {
|
|
604
|
+
shouldUpdateValue: 'updateValue', // easy to forget or make a mistake on guard name
|
|
605
|
+
},
|
|
606
|
+
callbacks: {
|
|
607
|
+
onUpdateValue: 'updateValue',
|
|
608
|
+
},
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
export type MyBaseConfig = {
|
|
612
|
+
initialValue?: string;
|
|
613
|
+
};
|
|
614
|
+
|
|
615
|
+
export type MyConfig = MyBaseConfig & Partial<ToModelConfig<MyState, MyEvents, typeof myEventMap>>;
|
|
616
|
+
|
|
617
|
+
const useMyModel = (config: MyConfig = {}): MyModel => {
|
|
618
|
+
const [value, setValue] = React.useState(config.initialValue || '');
|
|
619
|
+
|
|
620
|
+
const state = {value};
|
|
621
|
+
|
|
622
|
+
// useEventMap is used to wrap the event object with guards and callbacks according to the event map
|
|
623
|
+
const events = useEventMap(myEventMap, state, config, {
|
|
624
|
+
updateValue(data) {
|
|
625
|
+
setValue(data.value);
|
|
626
|
+
},
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
return {state, events};
|
|
630
|
+
};
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
After:
|
|
634
|
+
|
|
635
|
+
```tsx
|
|
636
|
+
const useMyModel = createModelHook({
|
|
637
|
+
defaultConfig: {
|
|
638
|
+
initialValue: '',
|
|
639
|
+
},
|
|
640
|
+
})(config => {
|
|
641
|
+
const [value, setValue] = React.useState(config.initialValue); // default is already handled
|
|
642
|
+
|
|
643
|
+
const state = {value};
|
|
644
|
+
|
|
645
|
+
const events = {
|
|
646
|
+
updateValue(value: string) {
|
|
647
|
+
// doesn't need to be an object anymore
|
|
648
|
+
setValue(value);
|
|
649
|
+
},
|
|
650
|
+
};
|
|
651
|
+
|
|
652
|
+
return {state, events};
|
|
653
|
+
});
|
|
654
|
+
```
|
|
655
|
+
|
|
656
|
+
Notice the large reduction in Typescript type boilerplate. In this example, the only place that
|
|
657
|
+
Typescript syntax exists is in the `updateValue` function definition. This allows better collocating
|
|
658
|
+
of types and values. Also notice that `useEventMap` doesn't need to be used anymore. The
|
|
659
|
+
`createModelHook` will automatically wrap the `events` returned to call guards and callbacks when
|
|
660
|
+
appropriate. Today this is done via creating a new events object. Once we drop IE11 support, this
|
|
661
|
+
can be done via a proxy instead. The `createModelHook` handles all type inference so we don't have
|
|
662
|
+
to explicitly type everything. Also `createModelHook` attaches React Context directly to the hook
|
|
663
|
+
along with `defaultConfig` and `requiredConfig` for model extension.
|
|
664
|
+
|
|
665
|
+
If you extended a model, you'll notice all those types are no longer being exported. You'll have to
|
|
666
|
+
use this new utility function. Here's an example we found in the wild:
|
|
667
|
+
|
|
668
|
+
```tsx
|
|
669
|
+
import {
|
|
670
|
+
BasePopupModelConfig,
|
|
671
|
+
createEventMap,
|
|
672
|
+
Model,
|
|
673
|
+
popupEventMap,
|
|
674
|
+
PopupEvents,
|
|
675
|
+
PopupModelConfig,
|
|
676
|
+
PopupState,
|
|
677
|
+
ToModelConfig,
|
|
678
|
+
useCloseOnEscape,
|
|
679
|
+
useEventMap,
|
|
680
|
+
useFocusTrap,
|
|
681
|
+
useInitialFocus,
|
|
682
|
+
usePopupModel,
|
|
683
|
+
useReturnFocus,
|
|
684
|
+
} from '@workday/canvas-kit-react';
|
|
685
|
+
|
|
686
|
+
type MyModalState = PopupState & {
|
|
687
|
+
showOverlay: boolean;
|
|
688
|
+
};
|
|
689
|
+
|
|
690
|
+
type MyModalEvents = PopupEvents;
|
|
691
|
+
|
|
692
|
+
const myModalEventMap = createEventMap<MyModalEvents>()({
|
|
693
|
+
guards: {
|
|
694
|
+
...popupEventMap.guards,
|
|
695
|
+
},
|
|
696
|
+
callbacks: {
|
|
697
|
+
...popupEventMap.callbacks,
|
|
698
|
+
},
|
|
699
|
+
});
|
|
700
|
+
|
|
701
|
+
type MyBaseModalConfig = BasePopupModelConfig & {
|
|
702
|
+
showOverlay?: boolean;
|
|
703
|
+
};
|
|
704
|
+
|
|
705
|
+
type MyModalModel = Model<MyModalState, MyModalEvents>;
|
|
706
|
+
|
|
707
|
+
type MyConfig = MyBaseConfig &
|
|
708
|
+
Partial<ToModelConfig<MyModalState, MyModalEvents, typeof myModalEventMap>>;
|
|
709
|
+
|
|
710
|
+
export const useMyModalModel = (config: MyConfig = {}): MyModalModel => {
|
|
711
|
+
const [showOverlay] = React.useState(config.showOverlay ?? true);
|
|
712
|
+
|
|
713
|
+
const model = usePopupModel({
|
|
714
|
+
...config,
|
|
715
|
+
// hook up to a redux store
|
|
716
|
+
onShow(...params) {
|
|
717
|
+
dispatch(setIsModalOpen(true));
|
|
718
|
+
config?.onShow?.(...params);
|
|
719
|
+
},
|
|
720
|
+
onHide(...params) {
|
|
721
|
+
dispatch(setIsModalOpen(false));
|
|
722
|
+
config?.onShow?.(...params);
|
|
723
|
+
},
|
|
724
|
+
});
|
|
725
|
+
|
|
726
|
+
useInitialFocus(model);
|
|
727
|
+
useReturnFocus(model);
|
|
728
|
+
useFocusTrap(model);
|
|
729
|
+
useCloseOnEscape(model);
|
|
730
|
+
|
|
731
|
+
const state = {
|
|
732
|
+
...model.state,
|
|
733
|
+
showOverlay,
|
|
734
|
+
};
|
|
735
|
+
|
|
736
|
+
const events = useEventMap(myEventMap, state, config, {
|
|
737
|
+
...model.events,
|
|
738
|
+
});
|
|
739
|
+
|
|
740
|
+
return {state, events};
|
|
741
|
+
};
|
|
742
|
+
```
|
|
743
|
+
|
|
744
|
+
After:
|
|
745
|
+
|
|
746
|
+
```ts
|
|
747
|
+
import {
|
|
748
|
+
useCloseOnEscape,
|
|
749
|
+
useEventMap,
|
|
750
|
+
useFocusTrap,
|
|
751
|
+
useInitialFocus,
|
|
752
|
+
usePopupModel,
|
|
753
|
+
useReturnFocus,
|
|
754
|
+
} from '@workday/canvas-kit-react';
|
|
755
|
+
|
|
756
|
+
const useMyModalModel = createModelHook({
|
|
757
|
+
defaultConfig: {
|
|
758
|
+
...usePopupModel.defaultConfig,
|
|
759
|
+
showOverlay: true,
|
|
760
|
+
},
|
|
761
|
+
requiredConfig: usePopupModel.requiredConfig,
|
|
762
|
+
contextOverride: usePopupModel.Context, // needed to make sure this model uses the same context as the popup model, otherwise it will create a new one
|
|
763
|
+
})(config => {
|
|
764
|
+
// `mergeConfig` takes care of the manual merging we were doing earlier
|
|
765
|
+
const model = usePopupModel(
|
|
766
|
+
usePopupModel.mergeConfig(config, {
|
|
767
|
+
// hook up to a redux store
|
|
768
|
+
onShow() {
|
|
769
|
+
dispatch(setIsModalOpen(true));
|
|
770
|
+
},
|
|
771
|
+
onHide() {
|
|
772
|
+
dispatch(setIsModalOpen(false));
|
|
773
|
+
},
|
|
774
|
+
})
|
|
775
|
+
);
|
|
776
|
+
|
|
777
|
+
useInitialFocus(model);
|
|
778
|
+
useReturnFocus(model);
|
|
779
|
+
useFocusTrap(model);
|
|
780
|
+
useCloseOnEscape(model);
|
|
781
|
+
|
|
782
|
+
const state = {
|
|
783
|
+
...model.state,
|
|
784
|
+
showOverlay,
|
|
785
|
+
};
|
|
786
|
+
|
|
787
|
+
return {...model, state};
|
|
788
|
+
});
|
|
789
|
+
```
|
|
790
|
+
|
|
791
|
+
All the cumbersome type boilerplate went away. Also all the type imports went away. The code is more
|
|
792
|
+
focused on your unique logic and less on boilerplate. Unfortunately, this change doesn't have a
|
|
793
|
+
codemod. While possible, this code isn't very common and the codemod would be very complex.
|
|
794
|
+
|
|
485
795
|
## Token Updates
|
|
486
796
|
|
|
487
797
|
### Depth Tokens
|
|
@@ -5,13 +5,12 @@ import {
|
|
|
5
5
|
useFormFieldLabel,
|
|
6
6
|
useFormFieldModel,
|
|
7
7
|
useFormFieldOrientation,
|
|
8
|
-
FormFieldModelContext,
|
|
9
8
|
} from '@workday/canvas-kit-preview-react/form-field';
|
|
10
9
|
import {useModelContext} from '@workday/canvas-kit-react/common';
|
|
11
10
|
import {Stack} from '@workday/canvas-kit-react/layout';
|
|
12
11
|
|
|
13
12
|
const Label = ({model, children}) => {
|
|
14
|
-
const localModel = useModelContext(
|
|
13
|
+
const localModel = useModelContext(useFormFieldModel.Context, model);
|
|
15
14
|
const props = useFormFieldLabel(localModel);
|
|
16
15
|
|
|
17
16
|
return (
|
|
@@ -23,14 +22,14 @@ const Label = ({model, children}) => {
|
|
|
23
22
|
};
|
|
24
23
|
|
|
25
24
|
const Hint = ({model, children}) => {
|
|
26
|
-
const localModel = useModelContext(
|
|
25
|
+
const localModel = useModelContext(useFormFieldModel.Context, model);
|
|
27
26
|
const props = useFormFieldHint(localModel);
|
|
28
27
|
|
|
29
28
|
return <span {...props}>{children}</span>;
|
|
30
29
|
};
|
|
31
30
|
|
|
32
31
|
const Input = ({model, ...elementProps}) => {
|
|
33
|
-
const localModel = useModelContext(
|
|
32
|
+
const localModel = useModelContext(useFormFieldModel.Context, model);
|
|
34
33
|
const props = useFormFieldInput(localModel, elementProps);
|
|
35
34
|
|
|
36
35
|
return <input type="text" required={model.state.isRequired ? true : false} {...props} />;
|