From 32446b85162d5e926b9bda78e7dfa8a051e1c00d Mon Sep 17 00:00:00 2001 From: Jane Chu <7559015+janechu@users.noreply.github.com> Date: Wed, 26 Jun 2024 10:47:50 -0700 Subject: [PATCH] Remove @microsoft/fast-foundation and @microsoft/fast-web-utilities (#6996) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Pull Request ## 📖 Description This change removes: - `@microsoft/fast-foundation` - the most recent version can be found on branch `archives/fast-foundation-3` - `@microsoft/fast-web-utilities` ### 🎫 Issues Closes #6951 and closes #6954 ## ✅ Checklist ### General - [ ] I have included a change request file using `$ yarn change` - [ ] I have added tests for my changes. - [x] I have tested my changes. - [ ] I have updated the project documentation to reflect my changes. - [x] I have read the [CONTRIBUTING](https://github.com/microsoft/fast/blob/master/CONTRIBUTING.md) documentation and followed the [standards](https://github.com/microsoft/fast/blob/master/CODE_OF_CONDUCT.md#our-standards) for this project. ## ⏭ Next Steps - File an issue to remove dependency on `@microsoft/fast-foundation` in `@microsoft/fast-ssr` for testing. --- .github/CODEOWNERS | 4 - CONTRIBUTING.md | 6 +- package.json | 1 - .../fast-web-utilities/.eslintignore | 11 - .../fast-web-utilities/.eslintrc.json | 9 - .../fast-web-utilities/.mocharc.json | 9 - .../utilities/fast-web-utilities/.npmignore | 12 - packages/utilities/fast-web-utilities/.npmrc | 1 - .../fast-web-utilities/.prettierignore | 3 - .../fast-web-utilities/CHANGELOG.json | 358 -- .../utilities/fast-web-utilities/CHANGELOG.md | 520 -- .../utilities/fast-web-utilities/README.md | 173 - .../fast-web-utilities/karma.conf.cjs | 160 - .../utilities/fast-web-utilities/package.json | 75 - .../src/__test__/setup-browser.cts | 6 - .../src/__test__/setup-node.ts | 12 - .../fast-web-utilities/src/aria.spec.ts | 9 - .../utilities/fast-web-utilities/src/aria.ts | 12 - .../fast-web-utilities/src/array.spec.ts | 30 - .../utilities/fast-web-utilities/src/array.ts | 21 - .../src/class-names.spec.ts | 72 - .../fast-web-utilities/src/class-names.ts | 17 - .../fast-web-utilities/src/dom.spec.ts | 147 - .../utilities/fast-web-utilities/src/dom.ts | 111 - .../fast-web-utilities/src/events.ts | 142 - .../fast-web-utilities/src/html.spec.ts | 96 - .../utilities/fast-web-utilities/src/html.ts | 53 - .../utilities/fast-web-utilities/src/index.ts | 13 - .../fast-web-utilities/src/key-codes.ts | 49 - .../fast-web-utilities/src/localization.ts | 7 - .../fast-web-utilities/src/numbers.spec.ts | 120 - .../fast-web-utilities/src/numbers.ts | 34 - .../fast-web-utilities/src/query.spec.ts | 48 - .../utilities/fast-web-utilities/src/query.ts | 28 - .../src/rtl-scroll-converter.spec.ts | 341 -- .../src/rtl-scroll-converter.ts | 233 - .../fast-web-utilities/src/strings.spec.ts | 147 - .../fast-web-utilities/src/strings.ts | 108 - .../fast-web-utilities/src/system-colors.ts | 19 - .../fast-web-utilities/tsconfig.build.json | 9 - .../fast-web-utilities/tsconfig.json | 13 - packages/web-components/README.md | 9 - .../fast-foundation/.eslintignore | 6 - .../fast-foundation/.eslintrc.cjs | 66 - .../web-components/fast-foundation/.gitignore | 4 - .../web-components/fast-foundation/.npmignore | 25 - .../web-components/fast-foundation/.npmrc | 1 - .../fast-foundation/.prettierignore | 3 - .../.storybook/debug.stories.ts | 13 - .../fast-foundation/.storybook/main.ts | 23 - .../.storybook/manager-head.html | 6 - .../.storybook/preview-body.html | 46 - .../.storybook/preview-head.html | 178 - .../fast-foundation/.storybook/preview.ts | 19 - .../fast-foundation/ACKNOWLEDGEMENTS.md | 4 - .../fast-foundation/CEMToMarkdown.mjs | 217 - .../fast-foundation/CHANGELOG.json | 4537 ----------------- .../fast-foundation/CHANGELOG.md | 2030 -------- .../web-components/fast-foundation/README.md | 58 - .../fast-foundation/api-extractor.json | 21 - .../custom-elements-manifest-plugins.mjs | 140 - .../custom-elements-manifest.config.mjs | 24 - .../fast-foundation/docs/api-report.md | 2929 ----------- .../docs/integrations/angular.md | 155 - .../docs/integrations/aspnet.md | 107 - .../docs/integrations/aurelia.md | 312 -- .../docs/integrations/blazor.md | 291 -- .../docs/integrations/ember.md | 124 - .../docs/integrations/introduction.md | 13 - .../docs/integrations/react.md | 313 -- .../docs/integrations/rollup.md | 260 - .../docs/integrations/svelte.md | 132 - .../fast-foundation/docs/integrations/vite.md | 154 - .../fast-foundation/docs/integrations/vue.md | 111 - .../docs/integrations/webpack.md | 419 -- .../docs/tools/component-explorer.md | 9 - .../docs/tools/hot-module-reload.md | 15 - .../fast-foundation/docs/tools/vscode.md | 15 - .../fast-foundation/package.json | 282 - .../fast-foundation/playwright.config.ts | 26 - .../fast-foundation/rollup.config.js | 63 - .../fast-foundation/src/__test__/custom.d.ts | 1 - .../fast-foundation/src/__test__/global.d.ts | 10 - .../fast-foundation/src/__test__/helpers.ts | 100 - .../accordion-item/accordion-item.pw.spec.ts | 111 - .../accordion-item/accordion-item.template.ts | 56 - .../src/accordion-item/accordion-item.ts | 104 - .../src/accordion-item/index.ts | 3 - .../stories/accordion-item.register.ts | 125 - .../stories/accordion-item.stories.ts | 49 - .../fast-foundation/src/accordion/README.md | 219 - .../src/accordion/accordion.options.ts | 23 - .../src/accordion/accordion.pw.spec.ts | 387 -- .../src/accordion/accordion.spec.md | 203 - .../src/accordion/accordion.template.ts | 15 - .../src/accordion/accordion.ts | 276 - .../fast-foundation/src/accordion/index.ts | 3 - .../accordion/stories/accordion.register.ts | 18 - .../accordion/stories/accordion.stories.ts | 137 - .../fast-foundation/src/anchor/README.md | 143 - .../src/anchor/anchor.options.ts | 20 - .../src/anchor/anchor.pw.spec.ts | 59 - .../src/anchor/anchor.template.ts | 54 - .../fast-foundation/src/anchor/anchor.ts | 148 - .../fast-foundation/src/anchor/index.ts | 4 - .../src/anchor/stories/anchor.register.ts | 94 - .../src/anchor/stories/anchor.stories.ts | 101 - .../src/anchored-region/README.md | 190 - .../anchored-region/anchored-region-config.ts | 184 - .../anchored-region.options.ts | 124 - .../anchored-region.pw.spec.ts | 83 - .../anchored-region/anchored-region.spec.md | 270 - .../anchored-region.template.ts | 22 - .../src/anchored-region/anchored-region.ts | 1279 ----- .../images/adjacent-adjacent.png | Bin 23256 -> 0 bytes .../anchored-region/images/adjacent-inset.png | Bin 21570 -> 0 bytes .../anchored-region/images/inset-adjacent.png | Bin 21937 -> 0 bytes .../anchored-region/images/inset-inset.png | Bin 18325 -> 0 bytes .../src/anchored-region/index.ts | 20 - .../stories/anchored-region.register.ts | 15 - .../stories/anchored-region.stories.ts | 123 - .../fast-foundation/src/avatar/README.md | 130 - .../fast-foundation/src/avatar/avatar.spec.md | 87 - .../src/avatar/avatar.template.ts | 20 - .../fast-foundation/src/avatar/avatar.ts | 23 - .../fast-foundation/src/avatar/index.ts | 3 - .../src/avatar/stories/avatar.register.ts | 85 - .../src/avatar/stories/avatar.stories.ts | 57 - .../fast-foundation/src/badge/README.md | 77 - .../fast-foundation/src/badge/badge.spec.md | 68 - .../src/badge/badge.template.ts | 20 - .../fast-foundation/src/badge/badge.ts | 30 - .../fast-foundation/src/badge/index.ts | 3 - .../src/badge/stories/badge.register.ts | 35 - .../src/badge/stories/badge.stories.ts | 29 - .../breadcrumb-item.pw.spec.ts | 137 - .../breadcrumb-item.template.ts | 29 - .../src/breadcrumb-item/breadcrumb-item.ts | 44 - .../src/breadcrumb-item/index.ts | 3 - .../stories/breadcrumb-item.register.ts | 111 - .../stories/breadcrumb-item.stories.ts | 120 - .../fast-foundation/src/breadcrumb/README.md | 196 - .../src/breadcrumb/breadcrumb.pw.spec.ts | 105 - .../src/breadcrumb/breadcrumb.spec.md | 130 - .../src/breadcrumb/breadcrumb.template.ts | 24 - .../src/breadcrumb/breadcrumb.ts | 90 - .../fast-foundation/src/breadcrumb/index.ts | 3 - .../breadcrumb/stories/breadcrumb.register.ts | 33 - .../breadcrumb/stories/breadcrumb.stories.ts | 62 - .../fast-foundation/src/button/README.md | 186 - .../src/button/button.form-associated.ts | 14 - .../src/button/button.options.ts | 19 - .../src/button/button.pw.spec.ts | 236 - .../fast-foundation/src/button/button.spec.md | 80 - .../src/button/button.template.ts | 58 - .../fast-foundation/src/button/button.ts | 245 - .../fast-foundation/src/button/index.ts | 4 - .../src/button/stories/button.register.ts | 99 - .../src/button/stories/button.stories.ts | 130 - .../src/calendar/calendar.options.ts | 65 - .../src/calendar/calendar.pw.spec.ts | 653 --- .../src/calendar/calendar.spec.md | 211 - .../src/calendar/calendar.template.ts | 250 - .../fast-foundation/src/calendar/calendar.ts | 372 -- .../src/calendar/date-formatter.ts | 197 - .../fast-foundation/src/calendar/index.ts | 19 - .../src/calendar/stories/calendar.register.ts | 104 - .../src/calendar/stories/calendar.stories.ts | 61 - .../fast-foundation/src/card/README.md | 76 - .../fast-foundation/src/card/card.spec.md | 71 - .../fast-foundation/src/card/card.template.ts | 13 - .../fast-foundation/src/card/card.ts | 10 - .../src/card/images/content-card-dark.png | Bin 284574 -> 0 bytes .../src/card/images/content-card.png | Bin 283050 -> 0 bytes .../src/card/images/favorites-card-dark.png | Bin 10211 -> 0 bytes .../src/card/images/favorites-card.png | Bin 10968 -> 0 bytes .../src/card/images/money-card-dark.png | Bin 60266 -> 0 bytes .../src/card/images/money-card.png | Bin 65332 -> 0 bytes .../src/card/images/shopping-card-dark.png | Bin 133623 -> 0 bytes .../src/card/images/shopping-card.png | Bin 133661 -> 0 bytes .../fast-foundation/src/card/index.ts | 2 - .../src/card/stories/card.register.ts | 22 - .../src/card/stories/card.stories.ts | 53 - .../fast-foundation/src/checkbox/README.md | 148 - .../src/checkbox/checkbox.form-associated.ts | 14 - .../src/checkbox/checkbox.pw.spec.ts | 421 -- .../src/checkbox/checkbox.spec.md | 125 - .../src/checkbox/checkbox.template.ts | 42 - .../fast-foundation/src/checkbox/checkbox.ts | 85 - .../fast-foundation/src/checkbox/index.ts | 3 - .../src/checkbox/stories/checkbox.register.ts | 155 - .../src/checkbox/stories/checkbox.stories.ts | 107 - .../fast-foundation/src/combobox/README.md | 238 - .../src/combobox/combobox.form-associated.ts | 14 - .../src/combobox/combobox.options.ts | 18 - .../src/combobox/combobox.pw.spec.ts | 681 --- .../src/combobox/combobox.spec.md | 146 - .../src/combobox/combobox.template.ts | 74 - .../fast-foundation/src/combobox/combobox.ts | 763 --- .../fast-foundation/src/combobox/index.ts | 4 - .../src/combobox/stories/combobox.register.ts | 211 - .../src/combobox/stories/combobox.stories.ts | 120 - .../fast-foundation/src/data-grid/README.md | 329 -- .../src/data-grid/data-grid-cell.pw.spec.ts | 229 - .../src/data-grid/data-grid-cell.template.ts | 22 - .../src/data-grid/data-grid-cell.ts | 332 -- .../src/data-grid/data-grid-row.pw.spec.ts | 241 - .../src/data-grid/data-grid-row.template.ts | 68 - .../src/data-grid/data-grid-row.ts | 358 -- .../src/data-grid/data-grid.options.ts | 144 - .../src/data-grid/data-grid.pw.spec.ts | 777 --- .../src/data-grid/data-grid.spec.md | 443 -- .../src/data-grid/data-grid.template.ts | 52 - .../src/data-grid/data-grid.ts | 1033 ---- .../src/data-grid/images/ex1.png | Bin 5419 -> 0 bytes .../src/data-grid/images/ex2.png | Bin 6335 -> 0 bytes .../src/data-grid/images/grid.png | Bin 123529 -> 0 bytes .../fast-foundation/src/data-grid/index.ts | 19 - .../stories/data-grid-cell.register.ts | 32 - .../stories/data-grid-cell.stories.ts | 40 - .../stories/data-grid-row.register.ts | 32 - .../stories/data-grid-row.stories.ts | 34 - .../data-grid/stories/data-grid.register.ts | 24 - .../data-grid/stories/data-grid.stories.ts | 160 - .../stories/examples/complex-cell.ts | 67 - .../core/design-token-node.pw.spec.ts | 1246 ----- .../design-token/core/design-token-node.ts | 724 --- .../src/design-token/core/design-token.ts | 7 - .../src/design-token/core/exports.ts | 9 - .../core/test/fast-element-dom-shim.ts | 9 - .../design-token/custom-property-manager.ts | 229 - .../design-token/design-token-style-target.ts | 41 - .../src/design-token/event-strategy.spec.ts | 91 - .../src/design-token/event-strategy.ts | 61 - .../src/design-token/exports.ts | 16 - .../design-token/fast-design-token.pw.spec.ts | 1590 ------ .../src/design-token/fast-design-token.ts | 459 -- .../stories/design-token.stories.ts | 115 - .../fast-foundation/src/dialog/README.md | 122 - .../src/dialog/dialog.pw.spec.ts | 245 - .../fast-foundation/src/dialog/dialog.spec.md | 137 - .../src/dialog/dialog.template.ts | 38 - .../fast-foundation/src/dialog/dialog.ts | 341 -- .../src/dialog/images/dialog-dark.png | Bin 122102 -> 0 bytes .../src/dialog/images/dialog.png | Bin 137536 -> 0 bytes .../fast-foundation/src/dialog/index.ts | 2 - .../src/dialog/stories/dialog.register.ts | 58 - .../src/dialog/stories/dialog.stories.ts | 83 - .../src/directives/reflect-attributes.spec.ts | 122 - .../src/directives/reflect-attributes.ts | 147 - .../fast-foundation/src/disclosure/README.md | 112 - .../src/disclosure/disclosure.pw.spec.ts | 108 - .../src/disclosure/disclosure.spec.md | 110 - .../src/disclosure/disclosure.template.ts | 28 - .../src/disclosure/disclosure.ts | 110 - .../fast-foundation/src/disclosure/index.ts | 3 - .../disclosure/stories/disclosure.register.ts | 79 - .../disclosure/stories/disclosure.stories.ts | 48 - .../fast-foundation/src/divider/README.md | 87 - .../src/divider/divider.options.ts | 36 - .../src/divider/divider.pw.spec.ts | 101 - .../src/divider/divider.spec.md | 60 - .../src/divider/divider.template.ts | 20 - .../fast-foundation/src/divider/divider.ts | 31 - .../fast-foundation/src/divider/index.ts | 3 - .../src/divider/stories/divider.register.ts | 28 - .../src/divider/stories/divider.stories.ts | 23 - .../fast-foundation/src/flipper/README.md | 147 - .../src/flipper/flipper.options.ts | 16 - .../src/flipper/flipper.pw.spec.ts | 152 - .../src/flipper/flipper.spec.md | 101 - .../src/flipper/flipper.template.ts | 45 - .../fast-foundation/src/flipper/flipper.ts | 80 - .../src/flipper/images/next-hover.png | Bin 6195 -> 0 bytes .../src/flipper/images/next.png | Bin 5967 -> 0 bytes .../flipper/images/previous-dark-hover.png | Bin 6201 -> 0 bytes .../src/flipper/images/previous-dark.png | Bin 5956 -> 0 bytes .../src/flipper/images/previous-hover.png | Bin 6214 -> 0 bytes .../src/flipper/images/previous.png | Bin 6013 -> 0 bytes .../fast-foundation/src/flipper/index.ts | 3 - .../src/flipper/stories/flipper.register.ts | 94 - .../src/flipper/stories/flipper.stories.ts | 28 - .../src/form-associated/README.md | 28 - .../form-associated-custom-element.spec.md | 116 - .../form-associated.pw.spec.ts | 555 -- .../src/form-associated/form-associated.ts | 811 --- .../src/form-associated/index.ts | 12 - .../stories/form-associated.register.ts | 56 - .../src/horizontal-scroll/README.md | 217 - .../horizontal-scroll.options.ts | 44 - .../horizontal-scroll.pw.spec.ts | 330 -- .../horizontal-scroll.template.ts | 68 - .../horizontal-scroll/horizontal-scroll.ts | 565 -- .../src/horizontal-scroll/index.ts | 4 - .../stories/horizontal-scroll.register.ts | 131 - .../stories/horizontal-scroll.stories.ts | 69 - .../fast-foundation/src/index.rollup.debug.ts | 8 - .../fast-foundation/src/index.rollup.ts | 7 - .../fast-foundation/src/index.ts | 51 - .../src/listbox-option/README.md | 137 - .../src/listbox-option/index.ts | 7 - .../listbox-option/listbox-option.pw.spec.ts | 147 - .../src/listbox-option/listbox-option.spec.md | 72 - .../listbox-option/listbox-option.template.ts | 29 - .../src/listbox-option/listbox-option.ts | 321 -- .../stories/listbox-option.register.ts | 118 - .../stories/listbox-option.stories.ts | 50 - .../fast-foundation/src/listbox/README.md | 166 - .../fast-foundation/src/listbox/index.ts | 3 - .../src/listbox/listbox.element.ts | 527 -- .../src/listbox/listbox.pw.spec.ts | 264 - .../src/listbox/listbox.spec.md | 84 - .../src/listbox/listbox.template.ts | 30 - .../fast-foundation/src/listbox/listbox.ts | 656 --- .../src/listbox/stories/listbox.register.ts | 74 - .../src/listbox/stories/listbox.stories.ts | 57 - .../fast-foundation/src/menu-item/index.ts | 3 - .../src/menu-item/menu-item.options.ts | 39 - .../src/menu-item/menu-item.pw.spec.ts | 204 - .../src/menu-item/menu-item.template.ts | 88 - .../src/menu-item/menu-item.ts | 375 -- .../menu-item/stories/menu-item.register.ts | 238 - .../menu-item/stories/menu-item.stories.ts | 155 - .../fast-foundation/src/menu/README.md | 260 - .../src/menu/images/menu-glyph.png | Bin 22411 -> 0 bytes .../src/menu/images/menu-item-disabled.png | Bin 8592 -> 0 bytes .../src/menu/images/menu-item-glyph-focus.png | Bin 11127 -> 0 bytes .../src/menu/images/menu-item-glyph-hover.png | Bin 10917 -> 0 bytes .../src/menu/images/menu-item-glyph.png | Bin 10746 -> 0 bytes .../menu/images/menu-item-no-glyph-focus.png | Bin 10189 -> 0 bytes .../menu/images/menu-item-no-glyph-hover.png | Bin 10051 -> 0 bytes .../src/menu/images/menu-item.png | Bin 9802 -> 0 bytes .../fast-foundation/src/menu/images/menu.png | Bin 24091 -> 0 bytes .../fast-foundation/src/menu/index.ts | 2 - .../fast-foundation/src/menu/menu.pw.spec.ts | 459 -- .../fast-foundation/src/menu/menu.spec.md | 195 - .../fast-foundation/src/menu/menu.template.ts | 20 - .../fast-foundation/src/menu/menu.ts | 333 -- .../src/menu/stories/menu.register.ts | 403 -- .../src/menu/stories/menu.stories.ts | 237 - .../src/number-field/README.md | 189 - .../fast-foundation/src/number-field/index.ts | 3 - .../number-field.form-associated.ts | 14 - .../src/number-field/number-field.pw.spec.ts | 714 --- .../src/number-field/number-field.spec.md | 112 - .../src/number-field/number-field.template.ts | 94 - .../src/number-field/number-field.ts | 404 -- .../stories/number-field.register.ts | 154 - .../stories/number-field.stories.ts | 115 - .../src/patterns/aria-global.ts | 253 - .../fast-foundation/src/patterns/index.ts | 5 - .../fast-foundation/src/patterns/start-end.ts | 68 - .../fast-foundation/src/patterns/tag-for.ts | 33 - .../fast-foundation/src/picker/README.md | 284 -- .../fast-foundation/src/picker/index.ts | 12 - .../src/picker/picker-context.ts | 18 - .../src/picker/picker-list-item.template.ts | 23 - .../src/picker/picker-list-item.ts | 98 - .../src/picker/picker-list.template.ts | 16 - .../fast-foundation/src/picker/picker-list.ts | 8 - .../src/picker/picker-menu-option.template.ts | 21 - .../src/picker/picker-menu-option.ts | 76 - .../src/picker/picker-menu.template.ts | 32 - .../fast-foundation/src/picker/picker-menu.ts | 79 - .../src/picker/picker.form-associated.ts | 14 - .../src/picker/picker.options.ts | 20 - .../fast-foundation/src/picker/picker.spec.md | 117 - .../fast-foundation/src/picker/picker.spec.ts | 498 -- .../src/picker/picker.template.ts | 130 - .../fast-foundation/src/picker/picker.ts | 1091 ---- .../src/picker/stories/picker.register.ts | 240 - .../src/picker/stories/picker.stories.ts | 67 - .../src/progress-ring/index.ts | 3 - .../progress-ring/progress-ring.options.ts | 10 - .../progress-ring/progress-ring.pw.spec.ts | 77 - .../progress-ring/progress-ring.template.ts | 59 - .../src/progress-ring/progress-ring.ts | 15 - .../stories/progress-ring.register.ts | 87 - .../stories/progress-ring.stories.ts | 29 - .../fast-foundation/src/progress/README.md | 197 - .../src/progress/base-progress.ts | 77 - .../fast-foundation/src/progress/index.ts | 4 - .../src/progress/progress.options.ts | 11 - .../src/progress/progress.pw.spec.ts | 128 - .../src/progress/progress.spec.md | 152 - .../src/progress/progress.template.ts | 43 - .../fast-foundation/src/progress/progress.ts | 14 - .../src/progress/stories/progress.register.ts | 117 - .../src/progress/stories/progress.stories.ts | 27 - .../fast-foundation/src/radio-group/README.md | 133 - .../fast-foundation/src/radio-group/index.ts | 3 - .../src/radio-group/radio-group.options.ts | 14 - .../src/radio-group/radio-group.pw.spec.ts | 481 -- .../src/radio-group/radio-group.spec.md | 88 - .../src/radio-group/radio-group.template.ts | 40 - .../src/radio-group/radio-group.ts | 440 -- .../stories/radio-group.register.ts | 35 - .../stories/radio-group.stories.ts | 67 - .../fast-foundation/src/radio/README.md | 155 - .../fast-foundation/src/radio/index.ts | 3 - .../src/radio/radio.form-associated.ts | 14 - .../src/radio/radio.pw.spec.ts | 312 -- .../fast-foundation/src/radio/radio.spec.md | 99 - .../src/radio/radio.template.ts | 43 - .../fast-foundation/src/radio/radio.ts | 132 - .../src/radio/stories/radio.register.ts | 143 - .../src/radio/stories/radio.stories.ts | 46 - .../fast-foundation/src/search/README.md | 168 - .../fast-foundation/src/search/index.ts | 3 - .../src/search/search.form-associated.ts | 14 - .../src/search/search.pw.spec.ts | 331 -- .../fast-foundation/src/search/search.spec.md | 124 - .../src/search/search.template.ts | 86 - .../fast-foundation/src/search/search.ts | 263 - .../src/search/stories/search.register.ts | 180 - .../src/search/stories/search.stories.ts | 108 - .../fast-foundation/src/select/README.md | 220 - .../fast-foundation/src/select/index.ts | 3 - .../src/select/select.form-associated.ts | 14 - .../src/select/select.pw.spec.ts | 516 -- .../fast-foundation/src/select/select.spec.md | 151 - .../src/select/select.template.ts | 75 - .../fast-foundation/src/select/select.ts | 619 --- .../src/select/stories/select.register.ts | 213 - .../src/select/stories/select.stories.ts | 88 - .../fast-foundation/src/skeleton/README.md | 189 - .../fast-foundation/src/skeleton/index.ts | 2 - .../src/skeleton/skeleton.spec.md | 113 - .../src/skeleton/skeleton.template.ts | 24 - .../fast-foundation/src/skeleton/skeleton.ts | 65 - .../src/skeleton/stories/skeleton.register.ts | 90 - .../src/skeleton/stories/skeleton.stories.ts | 103 - .../fast-foundation/src/slider-label/index.ts | 2 - .../src/slider-label/slider-label.pw.spec.ts | 53 - .../src/slider-label/slider-label.template.ts | 30 - .../src/slider-label/slider-label.ts | 206 - .../stories/slider-label.register.ts | 108 - .../stories/slider-label.stories.ts | 40 - .../fast-foundation/src/slider/README.md | 286 -- .../src/slider/images/slider-rtl.png | Bin 5274 -> 0 bytes .../fast-foundation/src/slider/index.ts | 4 - .../src/slider/slider-utilities.ts | 17 - .../src/slider/slider.form-associated.ts | 14 - .../src/slider/slider.options.ts | 50 - .../src/slider/slider.pw.spec.ts | 568 --- .../fast-foundation/src/slider/slider.spec.md | 192 - .../src/slider/slider.template.ts | 50 - .../fast-foundation/src/slider/slider.ts | 528 -- .../src/slider/stories/slider.register.ts | 136 - .../src/slider/stories/slider.stories.ts | 102 - .../fast-foundation/src/switch/README.md | 155 - .../fast-foundation/src/switch/index.ts | 3 - .../src/switch/stories/switch.register.ts | 132 - .../src/switch/stories/switch.stories.ts | 52 - .../src/switch/switch.form-associated.ts | 14 - .../src/switch/switch.pw.spec.ts | 420 -- .../fast-foundation/src/switch/switch.spec.md | 114 - .../src/switch/switch.template.ts | 39 - .../fast-foundation/src/switch/switch.ts | 87 - .../fast-foundation/src/tab-panel/index.ts | 2 - .../tab-panel/stories/tab-panel.register.ts | 22 - .../tab-panel/stories/tab-panel.stories.ts | 21 - .../src/tab-panel/tab-panel.pw.spec.ts | 45 - .../src/tab-panel/tab-panel.template.ts | 15 - .../src/tab-panel/tab-panel.ts | 10 - .../fast-foundation/src/tab/index.ts | 3 - .../src/tab/stories/tab.register.ts | 95 - .../src/tab/stories/tab.stories.ts | 32 - .../fast-foundation/src/tab/tab.pw.spec.ts | 49 - .../fast-foundation/src/tab/tab.template.ts | 20 - .../fast-foundation/src/tab/tab.ts | 40 - .../fast-foundation/src/tabs/README.md | 206 - .../fast-foundation/src/tabs/index.ts | 4 - .../src/tabs/stories/tabs.register.ts | 72 - .../src/tabs/stories/tabs.stories.ts | 97 - .../fast-foundation/src/tabs/tabs.options.ts | 22 - .../fast-foundation/src/tabs/tabs.pw.spec.ts | 458 -- .../fast-foundation/src/tabs/tabs.spec.md | 150 - .../fast-foundation/src/tabs/tabs.template.ts | 24 - .../fast-foundation/src/tabs/tabs.ts | 373 -- .../fast-foundation/src/text-area/README.md | 176 - .../src/text-area/images/text-area-focus.png | Bin 8416 -> 0 bytes .../src/text-area/images/text-area-label.png | Bin 7844 -> 0 bytes .../images/text-area-placeholder.png | Bin 8418 -> 0 bytes .../src/text-area/images/text-area.png | Bin 5607 -> 0 bytes .../fast-foundation/src/text-area/index.ts | 3 - .../text-area/stories/text-area.register.ts | 134 - .../text-area/stories/text-area.stories.ts | 116 - .../text-area/text-area.form-associated.ts | 14 - .../src/text-area/text-area.options.ts | 33 - .../src/text-area/text-area.pw.spec.ts | 261 - .../src/text-area/text-area.spec.md | 134 - .../src/text-area/text-area.template.ts | 70 - .../src/text-area/text-area.ts | 237 - .../fast-foundation/src/text-field/README.md | 187 - .../text-field/images/text-field-disabled.png | Bin 6927 -> 0 bytes .../text-field/images/text-field-filled.png | Bin 7668 -> 0 bytes .../text-field/images/text-field-focus.png | Bin 4831 -> 0 bytes .../text-field/images/text-field-password.png | Bin 5626 -> 0 bytes .../images/text-field-placeholder.png | Bin 7789 -> 0 bytes .../src/text-field/images/text-field.png | Bin 4829 -> 0 bytes .../fast-foundation/src/text-field/index.ts | 3 - .../text-field/stories/text-field.register.ts | 122 - .../text-field/stories/text-field.stories.ts | 115 - .../text-field/text-field.form-associated.ts | 14 - .../src/text-field/text-field.options.ts | 38 - .../src/text-field/text-field.pw.spec.ts | 740 --- .../src/text-field/text-field.spec.md | 139 - .../src/text-field/text-field.template.ts | 77 - .../src/text-field/text-field.ts | 308 -- .../fast-foundation/src/toolbar/README.md | 165 - .../fast-foundation/src/toolbar/index.ts | 4 - .../src/toolbar/stories/toolbar.register.ts | 52 - .../src/toolbar/stories/toolbar.stories.ts | 90 - .../src/toolbar/toolbar.options.ts | 22 - .../src/toolbar/toolbar.pw.spec.ts | 571 --- .../src/toolbar/toolbar.spec.md | 123 - .../src/toolbar/toolbar.template.ts | 45 - .../fast-foundation/src/toolbar/toolbar.ts | 351 -- .../fast-foundation/src/tooltip/README.md | 117 - .../fast-foundation/src/tooltip/index.ts | 3 - .../src/tooltip/stories/tooltip.register.ts | 52 - .../src/tooltip/stories/tooltip.stories.ts | 61 - .../src/tooltip/tooltip.options.ts | 28 - .../src/tooltip/tooltip.pw.spec.ts | 171 - .../src/tooltip/tooltip.spec.md | 93 - .../src/tooltip/tooltip.template.ts | 15 - .../fast-foundation/src/tooltip/tooltip.ts | 451 -- .../fast-foundation/src/tree-item/README.md | 112 - .../fast-foundation/src/tree-item/index.ts | 3 - .../tree-item/stories/tree-item.register.ts | 214 - .../tree-item/stories/tree-item.stories.ts | 57 - .../src/tree-item/tree-item.pw.spec.ts | 368 -- .../src/tree-item/tree-item.template.ts | 66 - .../src/tree-item/tree-item.ts | 211 - .../fast-foundation/src/tree-view/README.md | 133 - .../tree-view/images/tree-item-collapsed.png | Bin 11915 -> 0 bytes .../tree-view/images/tree-item-expanded.png | Bin 11827 -> 0 bytes .../images/tree-item-selected-collapsed.png | Bin 12642 -> 0 bytes .../images/tree-item-selected-expanded.png | Bin 12558 -> 0 bytes .../tree-view/images/tree-item-selected.png | Bin 13893 -> 0 bytes .../src/tree-view/images/tree-item.png | Bin 13449 -> 0 bytes .../src/tree-view/images/tree-view-rtl.png | Bin 32536 -> 0 bytes .../src/tree-view/images/tree-view.png | Bin 40754 -> 0 bytes .../fast-foundation/src/tree-view/index.ts | 2 - .../tree-view/stories/tree-view.register.ts | 26 - .../tree-view/stories/tree-view.stories.ts | 78 - .../src/tree-view/tree-view.pw.spec.ts | 182 - .../src/tree-view/tree-view.spec.md | 204 - .../src/tree-view/tree-view.template.ts | 23 - .../src/tree-view/tree-view.ts | 331 -- .../src/utilities/apply-mixins.ts | 26 - .../src/utilities/direction.ts | 15 - .../fast-foundation/src/utilities/index.ts | 19 - .../src/utilities/intersection-service.ts | 104 - .../match-media-stylesheet-behavior.ts | 198 - .../utilities/property-stylesheet-behavior.ts | 62 - .../src/utilities/resize-observer.ts | 47 - .../src/utilities/root-active-element.ts | 10 - .../src/utilities/style/disabled.ts | 6 - .../src/utilities/style/display.ts | 44 - .../src/utilities/style/focus.ts | 6 - .../src/utilities/style/index.ts | 4 - .../src/utilities/template-helpers.ts | 42 - .../fast-foundation/src/utilities/typings.ts | 6 - .../src/utilities/utilities.pw.spec.ts | 138 - .../src/utilities/whitespace-filter.ts | 14 - .../statics/svg/chevron_down_12_regular.svg | 1 - .../statics/svg/chevron_left_16_regular.svg | 1 - .../statics/svg/chevron_right_12_regular.svg | 1 - .../statics/svg/chevron_right_16_regular.svg | 1 - .../statics/svg/chevron_up_12_regular.svg | 1 - .../statics/svg/dismiss_12_regular.svg | 1 - .../fast-foundation/tsconfig.build.json | 4 - .../fast-foundation/tsconfig.json | 19 - .../web-components/fast-foundation/tsdoc.json | 44 - sites/site-utilities/build/badges.js | 2 +- sites/site-utilities/package.json | 4 +- .../src/docs/resources/browser-support.md | 2 +- yarn.lock | 3267 +----------- 580 files changed, 115 insertions(+), 78894 deletions(-) delete mode 100644 packages/utilities/fast-web-utilities/.eslintignore delete mode 100644 packages/utilities/fast-web-utilities/.eslintrc.json delete mode 100644 packages/utilities/fast-web-utilities/.mocharc.json delete mode 100644 packages/utilities/fast-web-utilities/.npmignore delete mode 100644 packages/utilities/fast-web-utilities/.npmrc delete mode 100644 packages/utilities/fast-web-utilities/.prettierignore delete mode 100644 packages/utilities/fast-web-utilities/CHANGELOG.json delete mode 100644 packages/utilities/fast-web-utilities/CHANGELOG.md delete mode 100644 packages/utilities/fast-web-utilities/README.md delete mode 100644 packages/utilities/fast-web-utilities/karma.conf.cjs delete mode 100644 packages/utilities/fast-web-utilities/package.json delete mode 100644 packages/utilities/fast-web-utilities/src/__test__/setup-browser.cts delete mode 100644 packages/utilities/fast-web-utilities/src/__test__/setup-node.ts delete mode 100644 packages/utilities/fast-web-utilities/src/aria.spec.ts delete mode 100644 packages/utilities/fast-web-utilities/src/aria.ts delete mode 100644 packages/utilities/fast-web-utilities/src/array.spec.ts delete mode 100644 packages/utilities/fast-web-utilities/src/array.ts delete mode 100644 packages/utilities/fast-web-utilities/src/class-names.spec.ts delete mode 100644 packages/utilities/fast-web-utilities/src/class-names.ts delete mode 100644 packages/utilities/fast-web-utilities/src/dom.spec.ts delete mode 100644 packages/utilities/fast-web-utilities/src/dom.ts delete mode 100644 packages/utilities/fast-web-utilities/src/events.ts delete mode 100644 packages/utilities/fast-web-utilities/src/html.spec.ts delete mode 100644 packages/utilities/fast-web-utilities/src/html.ts delete mode 100644 packages/utilities/fast-web-utilities/src/index.ts delete mode 100644 packages/utilities/fast-web-utilities/src/key-codes.ts delete mode 100644 packages/utilities/fast-web-utilities/src/localization.ts delete mode 100644 packages/utilities/fast-web-utilities/src/numbers.spec.ts delete mode 100644 packages/utilities/fast-web-utilities/src/numbers.ts delete mode 100644 packages/utilities/fast-web-utilities/src/query.spec.ts delete mode 100644 packages/utilities/fast-web-utilities/src/query.ts delete mode 100644 packages/utilities/fast-web-utilities/src/rtl-scroll-converter.spec.ts delete mode 100644 packages/utilities/fast-web-utilities/src/rtl-scroll-converter.ts delete mode 100644 packages/utilities/fast-web-utilities/src/strings.spec.ts delete mode 100644 packages/utilities/fast-web-utilities/src/strings.ts delete mode 100644 packages/utilities/fast-web-utilities/src/system-colors.ts delete mode 100644 packages/utilities/fast-web-utilities/tsconfig.build.json delete mode 100644 packages/utilities/fast-web-utilities/tsconfig.json delete mode 100644 packages/web-components/fast-foundation/.eslintignore delete mode 100644 packages/web-components/fast-foundation/.eslintrc.cjs delete mode 100644 packages/web-components/fast-foundation/.gitignore delete mode 100644 packages/web-components/fast-foundation/.npmignore delete mode 100644 packages/web-components/fast-foundation/.npmrc delete mode 100644 packages/web-components/fast-foundation/.prettierignore delete mode 100644 packages/web-components/fast-foundation/.storybook/debug.stories.ts delete mode 100644 packages/web-components/fast-foundation/.storybook/main.ts delete mode 100644 packages/web-components/fast-foundation/.storybook/manager-head.html delete mode 100644 packages/web-components/fast-foundation/.storybook/preview-body.html delete mode 100644 packages/web-components/fast-foundation/.storybook/preview-head.html delete mode 100644 packages/web-components/fast-foundation/.storybook/preview.ts delete mode 100644 packages/web-components/fast-foundation/ACKNOWLEDGEMENTS.md delete mode 100644 packages/web-components/fast-foundation/CEMToMarkdown.mjs delete mode 100644 packages/web-components/fast-foundation/CHANGELOG.json delete mode 100644 packages/web-components/fast-foundation/CHANGELOG.md delete mode 100644 packages/web-components/fast-foundation/README.md delete mode 100644 packages/web-components/fast-foundation/api-extractor.json delete mode 100644 packages/web-components/fast-foundation/custom-elements-manifest-plugins.mjs delete mode 100644 packages/web-components/fast-foundation/custom-elements-manifest.config.mjs delete mode 100644 packages/web-components/fast-foundation/docs/api-report.md delete mode 100644 packages/web-components/fast-foundation/docs/integrations/angular.md delete mode 100644 packages/web-components/fast-foundation/docs/integrations/aspnet.md delete mode 100644 packages/web-components/fast-foundation/docs/integrations/aurelia.md delete mode 100644 packages/web-components/fast-foundation/docs/integrations/blazor.md delete mode 100644 packages/web-components/fast-foundation/docs/integrations/ember.md delete mode 100644 packages/web-components/fast-foundation/docs/integrations/introduction.md delete mode 100644 packages/web-components/fast-foundation/docs/integrations/react.md delete mode 100644 packages/web-components/fast-foundation/docs/integrations/rollup.md delete mode 100644 packages/web-components/fast-foundation/docs/integrations/svelte.md delete mode 100644 packages/web-components/fast-foundation/docs/integrations/vite.md delete mode 100644 packages/web-components/fast-foundation/docs/integrations/vue.md delete mode 100644 packages/web-components/fast-foundation/docs/integrations/webpack.md delete mode 100644 packages/web-components/fast-foundation/docs/tools/component-explorer.md delete mode 100644 packages/web-components/fast-foundation/docs/tools/hot-module-reload.md delete mode 100644 packages/web-components/fast-foundation/docs/tools/vscode.md delete mode 100644 packages/web-components/fast-foundation/package.json delete mode 100644 packages/web-components/fast-foundation/playwright.config.ts delete mode 100644 packages/web-components/fast-foundation/rollup.config.js delete mode 100644 packages/web-components/fast-foundation/src/__test__/custom.d.ts delete mode 100644 packages/web-components/fast-foundation/src/__test__/global.d.ts delete mode 100644 packages/web-components/fast-foundation/src/__test__/helpers.ts delete mode 100644 packages/web-components/fast-foundation/src/accordion-item/accordion-item.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/accordion-item/accordion-item.template.ts delete mode 100644 packages/web-components/fast-foundation/src/accordion-item/accordion-item.ts delete mode 100644 packages/web-components/fast-foundation/src/accordion-item/index.ts delete mode 100644 packages/web-components/fast-foundation/src/accordion-item/stories/accordion-item.register.ts delete mode 100644 packages/web-components/fast-foundation/src/accordion-item/stories/accordion-item.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/accordion/README.md delete mode 100644 packages/web-components/fast-foundation/src/accordion/accordion.options.ts delete mode 100644 packages/web-components/fast-foundation/src/accordion/accordion.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/accordion/accordion.spec.md delete mode 100644 packages/web-components/fast-foundation/src/accordion/accordion.template.ts delete mode 100644 packages/web-components/fast-foundation/src/accordion/accordion.ts delete mode 100644 packages/web-components/fast-foundation/src/accordion/index.ts delete mode 100644 packages/web-components/fast-foundation/src/accordion/stories/accordion.register.ts delete mode 100644 packages/web-components/fast-foundation/src/accordion/stories/accordion.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/anchor/README.md delete mode 100644 packages/web-components/fast-foundation/src/anchor/anchor.options.ts delete mode 100644 packages/web-components/fast-foundation/src/anchor/anchor.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/anchor/anchor.template.ts delete mode 100644 packages/web-components/fast-foundation/src/anchor/anchor.ts delete mode 100644 packages/web-components/fast-foundation/src/anchor/index.ts delete mode 100644 packages/web-components/fast-foundation/src/anchor/stories/anchor.register.ts delete mode 100644 packages/web-components/fast-foundation/src/anchor/stories/anchor.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/anchored-region/README.md delete mode 100644 packages/web-components/fast-foundation/src/anchored-region/anchored-region-config.ts delete mode 100644 packages/web-components/fast-foundation/src/anchored-region/anchored-region.options.ts delete mode 100644 packages/web-components/fast-foundation/src/anchored-region/anchored-region.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/anchored-region/anchored-region.spec.md delete mode 100644 packages/web-components/fast-foundation/src/anchored-region/anchored-region.template.ts delete mode 100644 packages/web-components/fast-foundation/src/anchored-region/anchored-region.ts delete mode 100644 packages/web-components/fast-foundation/src/anchored-region/images/adjacent-adjacent.png delete mode 100644 packages/web-components/fast-foundation/src/anchored-region/images/adjacent-inset.png delete mode 100644 packages/web-components/fast-foundation/src/anchored-region/images/inset-adjacent.png delete mode 100644 packages/web-components/fast-foundation/src/anchored-region/images/inset-inset.png delete mode 100644 packages/web-components/fast-foundation/src/anchored-region/index.ts delete mode 100644 packages/web-components/fast-foundation/src/anchored-region/stories/anchored-region.register.ts delete mode 100644 packages/web-components/fast-foundation/src/anchored-region/stories/anchored-region.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/avatar/README.md delete mode 100644 packages/web-components/fast-foundation/src/avatar/avatar.spec.md delete mode 100644 packages/web-components/fast-foundation/src/avatar/avatar.template.ts delete mode 100644 packages/web-components/fast-foundation/src/avatar/avatar.ts delete mode 100644 packages/web-components/fast-foundation/src/avatar/index.ts delete mode 100644 packages/web-components/fast-foundation/src/avatar/stories/avatar.register.ts delete mode 100644 packages/web-components/fast-foundation/src/avatar/stories/avatar.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/badge/README.md delete mode 100644 packages/web-components/fast-foundation/src/badge/badge.spec.md delete mode 100644 packages/web-components/fast-foundation/src/badge/badge.template.ts delete mode 100644 packages/web-components/fast-foundation/src/badge/badge.ts delete mode 100644 packages/web-components/fast-foundation/src/badge/index.ts delete mode 100644 packages/web-components/fast-foundation/src/badge/stories/badge.register.ts delete mode 100644 packages/web-components/fast-foundation/src/badge/stories/badge.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/breadcrumb-item/breadcrumb-item.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/breadcrumb-item/breadcrumb-item.template.ts delete mode 100644 packages/web-components/fast-foundation/src/breadcrumb-item/breadcrumb-item.ts delete mode 100644 packages/web-components/fast-foundation/src/breadcrumb-item/index.ts delete mode 100644 packages/web-components/fast-foundation/src/breadcrumb-item/stories/breadcrumb-item.register.ts delete mode 100644 packages/web-components/fast-foundation/src/breadcrumb-item/stories/breadcrumb-item.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/breadcrumb/README.md delete mode 100644 packages/web-components/fast-foundation/src/breadcrumb/breadcrumb.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/breadcrumb/breadcrumb.spec.md delete mode 100644 packages/web-components/fast-foundation/src/breadcrumb/breadcrumb.template.ts delete mode 100644 packages/web-components/fast-foundation/src/breadcrumb/breadcrumb.ts delete mode 100644 packages/web-components/fast-foundation/src/breadcrumb/index.ts delete mode 100644 packages/web-components/fast-foundation/src/breadcrumb/stories/breadcrumb.register.ts delete mode 100644 packages/web-components/fast-foundation/src/breadcrumb/stories/breadcrumb.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/button/README.md delete mode 100644 packages/web-components/fast-foundation/src/button/button.form-associated.ts delete mode 100644 packages/web-components/fast-foundation/src/button/button.options.ts delete mode 100644 packages/web-components/fast-foundation/src/button/button.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/button/button.spec.md delete mode 100644 packages/web-components/fast-foundation/src/button/button.template.ts delete mode 100644 packages/web-components/fast-foundation/src/button/button.ts delete mode 100644 packages/web-components/fast-foundation/src/button/index.ts delete mode 100644 packages/web-components/fast-foundation/src/button/stories/button.register.ts delete mode 100644 packages/web-components/fast-foundation/src/button/stories/button.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/calendar/calendar.options.ts delete mode 100644 packages/web-components/fast-foundation/src/calendar/calendar.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/calendar/calendar.spec.md delete mode 100644 packages/web-components/fast-foundation/src/calendar/calendar.template.ts delete mode 100644 packages/web-components/fast-foundation/src/calendar/calendar.ts delete mode 100644 packages/web-components/fast-foundation/src/calendar/date-formatter.ts delete mode 100644 packages/web-components/fast-foundation/src/calendar/index.ts delete mode 100644 packages/web-components/fast-foundation/src/calendar/stories/calendar.register.ts delete mode 100644 packages/web-components/fast-foundation/src/calendar/stories/calendar.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/card/README.md delete mode 100644 packages/web-components/fast-foundation/src/card/card.spec.md delete mode 100644 packages/web-components/fast-foundation/src/card/card.template.ts delete mode 100644 packages/web-components/fast-foundation/src/card/card.ts delete mode 100644 packages/web-components/fast-foundation/src/card/images/content-card-dark.png delete mode 100644 packages/web-components/fast-foundation/src/card/images/content-card.png delete mode 100644 packages/web-components/fast-foundation/src/card/images/favorites-card-dark.png delete mode 100644 packages/web-components/fast-foundation/src/card/images/favorites-card.png delete mode 100644 packages/web-components/fast-foundation/src/card/images/money-card-dark.png delete mode 100644 packages/web-components/fast-foundation/src/card/images/money-card.png delete mode 100644 packages/web-components/fast-foundation/src/card/images/shopping-card-dark.png delete mode 100644 packages/web-components/fast-foundation/src/card/images/shopping-card.png delete mode 100644 packages/web-components/fast-foundation/src/card/index.ts delete mode 100644 packages/web-components/fast-foundation/src/card/stories/card.register.ts delete mode 100644 packages/web-components/fast-foundation/src/card/stories/card.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/checkbox/README.md delete mode 100644 packages/web-components/fast-foundation/src/checkbox/checkbox.form-associated.ts delete mode 100644 packages/web-components/fast-foundation/src/checkbox/checkbox.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/checkbox/checkbox.spec.md delete mode 100644 packages/web-components/fast-foundation/src/checkbox/checkbox.template.ts delete mode 100644 packages/web-components/fast-foundation/src/checkbox/checkbox.ts delete mode 100644 packages/web-components/fast-foundation/src/checkbox/index.ts delete mode 100644 packages/web-components/fast-foundation/src/checkbox/stories/checkbox.register.ts delete mode 100644 packages/web-components/fast-foundation/src/checkbox/stories/checkbox.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/combobox/README.md delete mode 100644 packages/web-components/fast-foundation/src/combobox/combobox.form-associated.ts delete mode 100644 packages/web-components/fast-foundation/src/combobox/combobox.options.ts delete mode 100644 packages/web-components/fast-foundation/src/combobox/combobox.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/combobox/combobox.spec.md delete mode 100644 packages/web-components/fast-foundation/src/combobox/combobox.template.ts delete mode 100644 packages/web-components/fast-foundation/src/combobox/combobox.ts delete mode 100644 packages/web-components/fast-foundation/src/combobox/index.ts delete mode 100644 packages/web-components/fast-foundation/src/combobox/stories/combobox.register.ts delete mode 100644 packages/web-components/fast-foundation/src/combobox/stories/combobox.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/data-grid/README.md delete mode 100644 packages/web-components/fast-foundation/src/data-grid/data-grid-cell.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/data-grid/data-grid-cell.template.ts delete mode 100644 packages/web-components/fast-foundation/src/data-grid/data-grid-cell.ts delete mode 100644 packages/web-components/fast-foundation/src/data-grid/data-grid-row.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/data-grid/data-grid-row.template.ts delete mode 100644 packages/web-components/fast-foundation/src/data-grid/data-grid-row.ts delete mode 100644 packages/web-components/fast-foundation/src/data-grid/data-grid.options.ts delete mode 100644 packages/web-components/fast-foundation/src/data-grid/data-grid.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/data-grid/data-grid.spec.md delete mode 100644 packages/web-components/fast-foundation/src/data-grid/data-grid.template.ts delete mode 100644 packages/web-components/fast-foundation/src/data-grid/data-grid.ts delete mode 100644 packages/web-components/fast-foundation/src/data-grid/images/ex1.png delete mode 100644 packages/web-components/fast-foundation/src/data-grid/images/ex2.png delete mode 100644 packages/web-components/fast-foundation/src/data-grid/images/grid.png delete mode 100644 packages/web-components/fast-foundation/src/data-grid/index.ts delete mode 100644 packages/web-components/fast-foundation/src/data-grid/stories/data-grid-cell.register.ts delete mode 100644 packages/web-components/fast-foundation/src/data-grid/stories/data-grid-cell.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/data-grid/stories/data-grid-row.register.ts delete mode 100644 packages/web-components/fast-foundation/src/data-grid/stories/data-grid-row.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/data-grid/stories/data-grid.register.ts delete mode 100644 packages/web-components/fast-foundation/src/data-grid/stories/data-grid.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/data-grid/stories/examples/complex-cell.ts delete mode 100644 packages/web-components/fast-foundation/src/design-token/core/design-token-node.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/design-token/core/design-token-node.ts delete mode 100644 packages/web-components/fast-foundation/src/design-token/core/design-token.ts delete mode 100644 packages/web-components/fast-foundation/src/design-token/core/exports.ts delete mode 100644 packages/web-components/fast-foundation/src/design-token/core/test/fast-element-dom-shim.ts delete mode 100644 packages/web-components/fast-foundation/src/design-token/custom-property-manager.ts delete mode 100644 packages/web-components/fast-foundation/src/design-token/design-token-style-target.ts delete mode 100644 packages/web-components/fast-foundation/src/design-token/event-strategy.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/design-token/event-strategy.ts delete mode 100644 packages/web-components/fast-foundation/src/design-token/exports.ts delete mode 100644 packages/web-components/fast-foundation/src/design-token/fast-design-token.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/design-token/fast-design-token.ts delete mode 100644 packages/web-components/fast-foundation/src/design-token/stories/design-token.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/dialog/README.md delete mode 100644 packages/web-components/fast-foundation/src/dialog/dialog.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/dialog/dialog.spec.md delete mode 100644 packages/web-components/fast-foundation/src/dialog/dialog.template.ts delete mode 100644 packages/web-components/fast-foundation/src/dialog/dialog.ts delete mode 100644 packages/web-components/fast-foundation/src/dialog/images/dialog-dark.png delete mode 100644 packages/web-components/fast-foundation/src/dialog/images/dialog.png delete mode 100644 packages/web-components/fast-foundation/src/dialog/index.ts delete mode 100644 packages/web-components/fast-foundation/src/dialog/stories/dialog.register.ts delete mode 100644 packages/web-components/fast-foundation/src/dialog/stories/dialog.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/directives/reflect-attributes.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/directives/reflect-attributes.ts delete mode 100644 packages/web-components/fast-foundation/src/disclosure/README.md delete mode 100644 packages/web-components/fast-foundation/src/disclosure/disclosure.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/disclosure/disclosure.spec.md delete mode 100644 packages/web-components/fast-foundation/src/disclosure/disclosure.template.ts delete mode 100644 packages/web-components/fast-foundation/src/disclosure/disclosure.ts delete mode 100644 packages/web-components/fast-foundation/src/disclosure/index.ts delete mode 100644 packages/web-components/fast-foundation/src/disclosure/stories/disclosure.register.ts delete mode 100644 packages/web-components/fast-foundation/src/disclosure/stories/disclosure.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/divider/README.md delete mode 100644 packages/web-components/fast-foundation/src/divider/divider.options.ts delete mode 100644 packages/web-components/fast-foundation/src/divider/divider.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/divider/divider.spec.md delete mode 100644 packages/web-components/fast-foundation/src/divider/divider.template.ts delete mode 100644 packages/web-components/fast-foundation/src/divider/divider.ts delete mode 100644 packages/web-components/fast-foundation/src/divider/index.ts delete mode 100644 packages/web-components/fast-foundation/src/divider/stories/divider.register.ts delete mode 100644 packages/web-components/fast-foundation/src/divider/stories/divider.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/flipper/README.md delete mode 100644 packages/web-components/fast-foundation/src/flipper/flipper.options.ts delete mode 100644 packages/web-components/fast-foundation/src/flipper/flipper.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/flipper/flipper.spec.md delete mode 100644 packages/web-components/fast-foundation/src/flipper/flipper.template.ts delete mode 100644 packages/web-components/fast-foundation/src/flipper/flipper.ts delete mode 100644 packages/web-components/fast-foundation/src/flipper/images/next-hover.png delete mode 100644 packages/web-components/fast-foundation/src/flipper/images/next.png delete mode 100644 packages/web-components/fast-foundation/src/flipper/images/previous-dark-hover.png delete mode 100644 packages/web-components/fast-foundation/src/flipper/images/previous-dark.png delete mode 100644 packages/web-components/fast-foundation/src/flipper/images/previous-hover.png delete mode 100644 packages/web-components/fast-foundation/src/flipper/images/previous.png delete mode 100644 packages/web-components/fast-foundation/src/flipper/index.ts delete mode 100644 packages/web-components/fast-foundation/src/flipper/stories/flipper.register.ts delete mode 100644 packages/web-components/fast-foundation/src/flipper/stories/flipper.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/form-associated/README.md delete mode 100644 packages/web-components/fast-foundation/src/form-associated/form-associated-custom-element.spec.md delete mode 100644 packages/web-components/fast-foundation/src/form-associated/form-associated.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/form-associated/form-associated.ts delete mode 100644 packages/web-components/fast-foundation/src/form-associated/index.ts delete mode 100644 packages/web-components/fast-foundation/src/form-associated/stories/form-associated.register.ts delete mode 100644 packages/web-components/fast-foundation/src/horizontal-scroll/README.md delete mode 100644 packages/web-components/fast-foundation/src/horizontal-scroll/horizontal-scroll.options.ts delete mode 100644 packages/web-components/fast-foundation/src/horizontal-scroll/horizontal-scroll.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/horizontal-scroll/horizontal-scroll.template.ts delete mode 100644 packages/web-components/fast-foundation/src/horizontal-scroll/horizontal-scroll.ts delete mode 100644 packages/web-components/fast-foundation/src/horizontal-scroll/index.ts delete mode 100644 packages/web-components/fast-foundation/src/horizontal-scroll/stories/horizontal-scroll.register.ts delete mode 100644 packages/web-components/fast-foundation/src/horizontal-scroll/stories/horizontal-scroll.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/index.rollup.debug.ts delete mode 100644 packages/web-components/fast-foundation/src/index.rollup.ts delete mode 100644 packages/web-components/fast-foundation/src/index.ts delete mode 100644 packages/web-components/fast-foundation/src/listbox-option/README.md delete mode 100644 packages/web-components/fast-foundation/src/listbox-option/index.ts delete mode 100644 packages/web-components/fast-foundation/src/listbox-option/listbox-option.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/listbox-option/listbox-option.spec.md delete mode 100644 packages/web-components/fast-foundation/src/listbox-option/listbox-option.template.ts delete mode 100644 packages/web-components/fast-foundation/src/listbox-option/listbox-option.ts delete mode 100644 packages/web-components/fast-foundation/src/listbox-option/stories/listbox-option.register.ts delete mode 100644 packages/web-components/fast-foundation/src/listbox-option/stories/listbox-option.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/listbox/README.md delete mode 100644 packages/web-components/fast-foundation/src/listbox/index.ts delete mode 100644 packages/web-components/fast-foundation/src/listbox/listbox.element.ts delete mode 100644 packages/web-components/fast-foundation/src/listbox/listbox.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/listbox/listbox.spec.md delete mode 100644 packages/web-components/fast-foundation/src/listbox/listbox.template.ts delete mode 100644 packages/web-components/fast-foundation/src/listbox/listbox.ts delete mode 100644 packages/web-components/fast-foundation/src/listbox/stories/listbox.register.ts delete mode 100644 packages/web-components/fast-foundation/src/listbox/stories/listbox.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/menu-item/index.ts delete mode 100644 packages/web-components/fast-foundation/src/menu-item/menu-item.options.ts delete mode 100644 packages/web-components/fast-foundation/src/menu-item/menu-item.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/menu-item/menu-item.template.ts delete mode 100644 packages/web-components/fast-foundation/src/menu-item/menu-item.ts delete mode 100644 packages/web-components/fast-foundation/src/menu-item/stories/menu-item.register.ts delete mode 100644 packages/web-components/fast-foundation/src/menu-item/stories/menu-item.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/menu/README.md delete mode 100644 packages/web-components/fast-foundation/src/menu/images/menu-glyph.png delete mode 100644 packages/web-components/fast-foundation/src/menu/images/menu-item-disabled.png delete mode 100644 packages/web-components/fast-foundation/src/menu/images/menu-item-glyph-focus.png delete mode 100644 packages/web-components/fast-foundation/src/menu/images/menu-item-glyph-hover.png delete mode 100644 packages/web-components/fast-foundation/src/menu/images/menu-item-glyph.png delete mode 100644 packages/web-components/fast-foundation/src/menu/images/menu-item-no-glyph-focus.png delete mode 100644 packages/web-components/fast-foundation/src/menu/images/menu-item-no-glyph-hover.png delete mode 100644 packages/web-components/fast-foundation/src/menu/images/menu-item.png delete mode 100644 packages/web-components/fast-foundation/src/menu/images/menu.png delete mode 100644 packages/web-components/fast-foundation/src/menu/index.ts delete mode 100644 packages/web-components/fast-foundation/src/menu/menu.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/menu/menu.spec.md delete mode 100644 packages/web-components/fast-foundation/src/menu/menu.template.ts delete mode 100644 packages/web-components/fast-foundation/src/menu/menu.ts delete mode 100644 packages/web-components/fast-foundation/src/menu/stories/menu.register.ts delete mode 100644 packages/web-components/fast-foundation/src/menu/stories/menu.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/number-field/README.md delete mode 100644 packages/web-components/fast-foundation/src/number-field/index.ts delete mode 100644 packages/web-components/fast-foundation/src/number-field/number-field.form-associated.ts delete mode 100644 packages/web-components/fast-foundation/src/number-field/number-field.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/number-field/number-field.spec.md delete mode 100644 packages/web-components/fast-foundation/src/number-field/number-field.template.ts delete mode 100644 packages/web-components/fast-foundation/src/number-field/number-field.ts delete mode 100644 packages/web-components/fast-foundation/src/number-field/stories/number-field.register.ts delete mode 100644 packages/web-components/fast-foundation/src/number-field/stories/number-field.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/patterns/aria-global.ts delete mode 100644 packages/web-components/fast-foundation/src/patterns/index.ts delete mode 100644 packages/web-components/fast-foundation/src/patterns/start-end.ts delete mode 100644 packages/web-components/fast-foundation/src/patterns/tag-for.ts delete mode 100644 packages/web-components/fast-foundation/src/picker/README.md delete mode 100644 packages/web-components/fast-foundation/src/picker/index.ts delete mode 100644 packages/web-components/fast-foundation/src/picker/picker-context.ts delete mode 100644 packages/web-components/fast-foundation/src/picker/picker-list-item.template.ts delete mode 100644 packages/web-components/fast-foundation/src/picker/picker-list-item.ts delete mode 100644 packages/web-components/fast-foundation/src/picker/picker-list.template.ts delete mode 100644 packages/web-components/fast-foundation/src/picker/picker-list.ts delete mode 100644 packages/web-components/fast-foundation/src/picker/picker-menu-option.template.ts delete mode 100644 packages/web-components/fast-foundation/src/picker/picker-menu-option.ts delete mode 100644 packages/web-components/fast-foundation/src/picker/picker-menu.template.ts delete mode 100644 packages/web-components/fast-foundation/src/picker/picker-menu.ts delete mode 100644 packages/web-components/fast-foundation/src/picker/picker.form-associated.ts delete mode 100644 packages/web-components/fast-foundation/src/picker/picker.options.ts delete mode 100644 packages/web-components/fast-foundation/src/picker/picker.spec.md delete mode 100644 packages/web-components/fast-foundation/src/picker/picker.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/picker/picker.template.ts delete mode 100644 packages/web-components/fast-foundation/src/picker/picker.ts delete mode 100644 packages/web-components/fast-foundation/src/picker/stories/picker.register.ts delete mode 100644 packages/web-components/fast-foundation/src/picker/stories/picker.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/progress-ring/index.ts delete mode 100644 packages/web-components/fast-foundation/src/progress-ring/progress-ring.options.ts delete mode 100644 packages/web-components/fast-foundation/src/progress-ring/progress-ring.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/progress-ring/progress-ring.template.ts delete mode 100644 packages/web-components/fast-foundation/src/progress-ring/progress-ring.ts delete mode 100644 packages/web-components/fast-foundation/src/progress-ring/stories/progress-ring.register.ts delete mode 100644 packages/web-components/fast-foundation/src/progress-ring/stories/progress-ring.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/progress/README.md delete mode 100644 packages/web-components/fast-foundation/src/progress/base-progress.ts delete mode 100644 packages/web-components/fast-foundation/src/progress/index.ts delete mode 100644 packages/web-components/fast-foundation/src/progress/progress.options.ts delete mode 100644 packages/web-components/fast-foundation/src/progress/progress.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/progress/progress.spec.md delete mode 100644 packages/web-components/fast-foundation/src/progress/progress.template.ts delete mode 100644 packages/web-components/fast-foundation/src/progress/progress.ts delete mode 100644 packages/web-components/fast-foundation/src/progress/stories/progress.register.ts delete mode 100644 packages/web-components/fast-foundation/src/progress/stories/progress.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/radio-group/README.md delete mode 100644 packages/web-components/fast-foundation/src/radio-group/index.ts delete mode 100644 packages/web-components/fast-foundation/src/radio-group/radio-group.options.ts delete mode 100644 packages/web-components/fast-foundation/src/radio-group/radio-group.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/radio-group/radio-group.spec.md delete mode 100644 packages/web-components/fast-foundation/src/radio-group/radio-group.template.ts delete mode 100644 packages/web-components/fast-foundation/src/radio-group/radio-group.ts delete mode 100644 packages/web-components/fast-foundation/src/radio-group/stories/radio-group.register.ts delete mode 100644 packages/web-components/fast-foundation/src/radio-group/stories/radio-group.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/radio/README.md delete mode 100644 packages/web-components/fast-foundation/src/radio/index.ts delete mode 100644 packages/web-components/fast-foundation/src/radio/radio.form-associated.ts delete mode 100644 packages/web-components/fast-foundation/src/radio/radio.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/radio/radio.spec.md delete mode 100644 packages/web-components/fast-foundation/src/radio/radio.template.ts delete mode 100644 packages/web-components/fast-foundation/src/radio/radio.ts delete mode 100644 packages/web-components/fast-foundation/src/radio/stories/radio.register.ts delete mode 100644 packages/web-components/fast-foundation/src/radio/stories/radio.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/search/README.md delete mode 100644 packages/web-components/fast-foundation/src/search/index.ts delete mode 100644 packages/web-components/fast-foundation/src/search/search.form-associated.ts delete mode 100644 packages/web-components/fast-foundation/src/search/search.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/search/search.spec.md delete mode 100644 packages/web-components/fast-foundation/src/search/search.template.ts delete mode 100644 packages/web-components/fast-foundation/src/search/search.ts delete mode 100644 packages/web-components/fast-foundation/src/search/stories/search.register.ts delete mode 100644 packages/web-components/fast-foundation/src/search/stories/search.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/select/README.md delete mode 100644 packages/web-components/fast-foundation/src/select/index.ts delete mode 100644 packages/web-components/fast-foundation/src/select/select.form-associated.ts delete mode 100644 packages/web-components/fast-foundation/src/select/select.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/select/select.spec.md delete mode 100644 packages/web-components/fast-foundation/src/select/select.template.ts delete mode 100644 packages/web-components/fast-foundation/src/select/select.ts delete mode 100644 packages/web-components/fast-foundation/src/select/stories/select.register.ts delete mode 100644 packages/web-components/fast-foundation/src/select/stories/select.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/skeleton/README.md delete mode 100644 packages/web-components/fast-foundation/src/skeleton/index.ts delete mode 100644 packages/web-components/fast-foundation/src/skeleton/skeleton.spec.md delete mode 100644 packages/web-components/fast-foundation/src/skeleton/skeleton.template.ts delete mode 100644 packages/web-components/fast-foundation/src/skeleton/skeleton.ts delete mode 100644 packages/web-components/fast-foundation/src/skeleton/stories/skeleton.register.ts delete mode 100644 packages/web-components/fast-foundation/src/skeleton/stories/skeleton.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/slider-label/index.ts delete mode 100644 packages/web-components/fast-foundation/src/slider-label/slider-label.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/slider-label/slider-label.template.ts delete mode 100644 packages/web-components/fast-foundation/src/slider-label/slider-label.ts delete mode 100644 packages/web-components/fast-foundation/src/slider-label/stories/slider-label.register.ts delete mode 100644 packages/web-components/fast-foundation/src/slider-label/stories/slider-label.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/slider/README.md delete mode 100644 packages/web-components/fast-foundation/src/slider/images/slider-rtl.png delete mode 100644 packages/web-components/fast-foundation/src/slider/index.ts delete mode 100644 packages/web-components/fast-foundation/src/slider/slider-utilities.ts delete mode 100644 packages/web-components/fast-foundation/src/slider/slider.form-associated.ts delete mode 100644 packages/web-components/fast-foundation/src/slider/slider.options.ts delete mode 100644 packages/web-components/fast-foundation/src/slider/slider.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/slider/slider.spec.md delete mode 100644 packages/web-components/fast-foundation/src/slider/slider.template.ts delete mode 100644 packages/web-components/fast-foundation/src/slider/slider.ts delete mode 100644 packages/web-components/fast-foundation/src/slider/stories/slider.register.ts delete mode 100644 packages/web-components/fast-foundation/src/slider/stories/slider.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/switch/README.md delete mode 100644 packages/web-components/fast-foundation/src/switch/index.ts delete mode 100644 packages/web-components/fast-foundation/src/switch/stories/switch.register.ts delete mode 100644 packages/web-components/fast-foundation/src/switch/stories/switch.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/switch/switch.form-associated.ts delete mode 100644 packages/web-components/fast-foundation/src/switch/switch.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/switch/switch.spec.md delete mode 100644 packages/web-components/fast-foundation/src/switch/switch.template.ts delete mode 100644 packages/web-components/fast-foundation/src/switch/switch.ts delete mode 100644 packages/web-components/fast-foundation/src/tab-panel/index.ts delete mode 100644 packages/web-components/fast-foundation/src/tab-panel/stories/tab-panel.register.ts delete mode 100644 packages/web-components/fast-foundation/src/tab-panel/stories/tab-panel.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/tab-panel/tab-panel.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/tab-panel/tab-panel.template.ts delete mode 100644 packages/web-components/fast-foundation/src/tab-panel/tab-panel.ts delete mode 100644 packages/web-components/fast-foundation/src/tab/index.ts delete mode 100644 packages/web-components/fast-foundation/src/tab/stories/tab.register.ts delete mode 100644 packages/web-components/fast-foundation/src/tab/stories/tab.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/tab/tab.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/tab/tab.template.ts delete mode 100644 packages/web-components/fast-foundation/src/tab/tab.ts delete mode 100644 packages/web-components/fast-foundation/src/tabs/README.md delete mode 100644 packages/web-components/fast-foundation/src/tabs/index.ts delete mode 100644 packages/web-components/fast-foundation/src/tabs/stories/tabs.register.ts delete mode 100644 packages/web-components/fast-foundation/src/tabs/stories/tabs.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/tabs/tabs.options.ts delete mode 100644 packages/web-components/fast-foundation/src/tabs/tabs.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/tabs/tabs.spec.md delete mode 100644 packages/web-components/fast-foundation/src/tabs/tabs.template.ts delete mode 100644 packages/web-components/fast-foundation/src/tabs/tabs.ts delete mode 100644 packages/web-components/fast-foundation/src/text-area/README.md delete mode 100644 packages/web-components/fast-foundation/src/text-area/images/text-area-focus.png delete mode 100644 packages/web-components/fast-foundation/src/text-area/images/text-area-label.png delete mode 100644 packages/web-components/fast-foundation/src/text-area/images/text-area-placeholder.png delete mode 100644 packages/web-components/fast-foundation/src/text-area/images/text-area.png delete mode 100644 packages/web-components/fast-foundation/src/text-area/index.ts delete mode 100644 packages/web-components/fast-foundation/src/text-area/stories/text-area.register.ts delete mode 100644 packages/web-components/fast-foundation/src/text-area/stories/text-area.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/text-area/text-area.form-associated.ts delete mode 100644 packages/web-components/fast-foundation/src/text-area/text-area.options.ts delete mode 100644 packages/web-components/fast-foundation/src/text-area/text-area.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/text-area/text-area.spec.md delete mode 100644 packages/web-components/fast-foundation/src/text-area/text-area.template.ts delete mode 100644 packages/web-components/fast-foundation/src/text-area/text-area.ts delete mode 100644 packages/web-components/fast-foundation/src/text-field/README.md delete mode 100644 packages/web-components/fast-foundation/src/text-field/images/text-field-disabled.png delete mode 100644 packages/web-components/fast-foundation/src/text-field/images/text-field-filled.png delete mode 100644 packages/web-components/fast-foundation/src/text-field/images/text-field-focus.png delete mode 100644 packages/web-components/fast-foundation/src/text-field/images/text-field-password.png delete mode 100644 packages/web-components/fast-foundation/src/text-field/images/text-field-placeholder.png delete mode 100644 packages/web-components/fast-foundation/src/text-field/images/text-field.png delete mode 100644 packages/web-components/fast-foundation/src/text-field/index.ts delete mode 100644 packages/web-components/fast-foundation/src/text-field/stories/text-field.register.ts delete mode 100644 packages/web-components/fast-foundation/src/text-field/stories/text-field.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/text-field/text-field.form-associated.ts delete mode 100644 packages/web-components/fast-foundation/src/text-field/text-field.options.ts delete mode 100644 packages/web-components/fast-foundation/src/text-field/text-field.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/text-field/text-field.spec.md delete mode 100644 packages/web-components/fast-foundation/src/text-field/text-field.template.ts delete mode 100644 packages/web-components/fast-foundation/src/text-field/text-field.ts delete mode 100644 packages/web-components/fast-foundation/src/toolbar/README.md delete mode 100644 packages/web-components/fast-foundation/src/toolbar/index.ts delete mode 100644 packages/web-components/fast-foundation/src/toolbar/stories/toolbar.register.ts delete mode 100644 packages/web-components/fast-foundation/src/toolbar/stories/toolbar.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/toolbar/toolbar.options.ts delete mode 100644 packages/web-components/fast-foundation/src/toolbar/toolbar.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/toolbar/toolbar.spec.md delete mode 100644 packages/web-components/fast-foundation/src/toolbar/toolbar.template.ts delete mode 100644 packages/web-components/fast-foundation/src/toolbar/toolbar.ts delete mode 100644 packages/web-components/fast-foundation/src/tooltip/README.md delete mode 100644 packages/web-components/fast-foundation/src/tooltip/index.ts delete mode 100644 packages/web-components/fast-foundation/src/tooltip/stories/tooltip.register.ts delete mode 100644 packages/web-components/fast-foundation/src/tooltip/stories/tooltip.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/tooltip/tooltip.options.ts delete mode 100644 packages/web-components/fast-foundation/src/tooltip/tooltip.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/tooltip/tooltip.spec.md delete mode 100644 packages/web-components/fast-foundation/src/tooltip/tooltip.template.ts delete mode 100644 packages/web-components/fast-foundation/src/tooltip/tooltip.ts delete mode 100644 packages/web-components/fast-foundation/src/tree-item/README.md delete mode 100644 packages/web-components/fast-foundation/src/tree-item/index.ts delete mode 100644 packages/web-components/fast-foundation/src/tree-item/stories/tree-item.register.ts delete mode 100644 packages/web-components/fast-foundation/src/tree-item/stories/tree-item.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/tree-item/tree-item.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/tree-item/tree-item.template.ts delete mode 100644 packages/web-components/fast-foundation/src/tree-item/tree-item.ts delete mode 100644 packages/web-components/fast-foundation/src/tree-view/README.md delete mode 100644 packages/web-components/fast-foundation/src/tree-view/images/tree-item-collapsed.png delete mode 100644 packages/web-components/fast-foundation/src/tree-view/images/tree-item-expanded.png delete mode 100644 packages/web-components/fast-foundation/src/tree-view/images/tree-item-selected-collapsed.png delete mode 100644 packages/web-components/fast-foundation/src/tree-view/images/tree-item-selected-expanded.png delete mode 100644 packages/web-components/fast-foundation/src/tree-view/images/tree-item-selected.png delete mode 100644 packages/web-components/fast-foundation/src/tree-view/images/tree-item.png delete mode 100644 packages/web-components/fast-foundation/src/tree-view/images/tree-view-rtl.png delete mode 100644 packages/web-components/fast-foundation/src/tree-view/images/tree-view.png delete mode 100644 packages/web-components/fast-foundation/src/tree-view/index.ts delete mode 100644 packages/web-components/fast-foundation/src/tree-view/stories/tree-view.register.ts delete mode 100644 packages/web-components/fast-foundation/src/tree-view/stories/tree-view.stories.ts delete mode 100644 packages/web-components/fast-foundation/src/tree-view/tree-view.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/tree-view/tree-view.spec.md delete mode 100644 packages/web-components/fast-foundation/src/tree-view/tree-view.template.ts delete mode 100644 packages/web-components/fast-foundation/src/tree-view/tree-view.ts delete mode 100644 packages/web-components/fast-foundation/src/utilities/apply-mixins.ts delete mode 100644 packages/web-components/fast-foundation/src/utilities/direction.ts delete mode 100644 packages/web-components/fast-foundation/src/utilities/index.ts delete mode 100644 packages/web-components/fast-foundation/src/utilities/intersection-service.ts delete mode 100644 packages/web-components/fast-foundation/src/utilities/match-media-stylesheet-behavior.ts delete mode 100644 packages/web-components/fast-foundation/src/utilities/property-stylesheet-behavior.ts delete mode 100644 packages/web-components/fast-foundation/src/utilities/resize-observer.ts delete mode 100644 packages/web-components/fast-foundation/src/utilities/root-active-element.ts delete mode 100644 packages/web-components/fast-foundation/src/utilities/style/disabled.ts delete mode 100644 packages/web-components/fast-foundation/src/utilities/style/display.ts delete mode 100644 packages/web-components/fast-foundation/src/utilities/style/focus.ts delete mode 100644 packages/web-components/fast-foundation/src/utilities/style/index.ts delete mode 100644 packages/web-components/fast-foundation/src/utilities/template-helpers.ts delete mode 100644 packages/web-components/fast-foundation/src/utilities/typings.ts delete mode 100644 packages/web-components/fast-foundation/src/utilities/utilities.pw.spec.ts delete mode 100644 packages/web-components/fast-foundation/src/utilities/whitespace-filter.ts delete mode 100644 packages/web-components/fast-foundation/statics/svg/chevron_down_12_regular.svg delete mode 100644 packages/web-components/fast-foundation/statics/svg/chevron_left_16_regular.svg delete mode 100644 packages/web-components/fast-foundation/statics/svg/chevron_right_12_regular.svg delete mode 100644 packages/web-components/fast-foundation/statics/svg/chevron_right_16_regular.svg delete mode 100644 packages/web-components/fast-foundation/statics/svg/chevron_up_12_regular.svg delete mode 100644 packages/web-components/fast-foundation/statics/svg/dismiss_12_regular.svg delete mode 100644 packages/web-components/fast-foundation/tsconfig.build.json delete mode 100644 packages/web-components/fast-foundation/tsconfig.json delete mode 100644 packages/web-components/fast-foundation/tsdoc.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 5fe33757b6e..739551d6791 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -28,12 +28,8 @@ build/ @janechu @nicholasrice @chrisdholt @awentzel # Package specific owners -# Utilities -/packages/utilities/fast-web-utilities/ @janechu @chrisdholt @nicholasrice - # Web components /packages/web-components/fast-element/ @chrisdholt @janechu @nicholasrice -/packages/web-components/fast-foundation/ @chrisdholt @bheston @scomea @radium-v @kingoftac # the change directory has no owners /change/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 81d9a3563e8..1105688c497 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -96,8 +96,8 @@ When working across feature branches, you'll need to target the branch using the ```json { "type": "minor", - "comment": "add fancy new feature for foundation", - "packageName": "@microsoft/fast-foundation", + "comment": "add fancy new feature to FASTElement", + "packageName": "@microsoft/fast-element", "email": "name@example.com", "dependentChangeType": "minor", "date": "2021-03-01T19:10:06.323Z" @@ -122,7 +122,7 @@ If you are merging a pull request, be sure to use the pull request title as the ### Documenting breaking changes -Make sure to document the migration strategy in a `MIGRATION.md` file in the package(s) that has breaking changes, eg. `packages/web-components/fast-foundation/MIGRATION.md`. +Make sure to document the migration strategy in a `MIGRATION.md` file in the package(s) that has breaking changes, eg. `packages/web-components/fast-element/MIGRATION.md`. Example of how to format `MIGRATION.md`: diff --git a/package.json b/package.json index ee2cffefddc..6ab946f2420 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,6 @@ "private": true, "workspaces": { "packages": [ - "packages/utilities/*", "packages/web-components/*", "sites/*", "examples/todo-app", diff --git a/packages/utilities/fast-web-utilities/.eslintignore b/packages/utilities/fast-web-utilities/.eslintignore deleted file mode 100644 index 0d3f63047a4..00000000000 --- a/packages/utilities/fast-web-utilities/.eslintignore +++ /dev/null @@ -1,11 +0,0 @@ -# don't ever lint node_modules -node_modules -# don't lint build output (make sure it's set to your correct build folder name) -dist -# don't lint coverage output -coverage -# Don't lint test files -**/*.spec.ts - -# Ignore karma config -karma.conf.ts diff --git a/packages/utilities/fast-web-utilities/.eslintrc.json b/packages/utilities/fast-web-utilities/.eslintrc.json deleted file mode 100644 index ed277537a6e..00000000000 --- a/packages/utilities/fast-web-utilities/.eslintrc.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": ["../../../.eslintrc.js"], - "rules": { - "import/extensions": [ - "error", - "always" - ] - } -} diff --git a/packages/utilities/fast-web-utilities/.mocharc.json b/packages/utilities/fast-web-utilities/.mocharc.json deleted file mode 100644 index 622f83dfc22..00000000000 --- a/packages/utilities/fast-web-utilities/.mocharc.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "colors": true, - "recursive": true, - "timeout": 5000, - "require": [ - "esm", - "jsdom-global/register" - ] -} \ No newline at end of file diff --git a/packages/utilities/fast-web-utilities/.npmignore b/packages/utilities/fast-web-utilities/.npmignore deleted file mode 100644 index 570b98b54a0..00000000000 --- a/packages/utilities/fast-web-utilities/.npmignore +++ /dev/null @@ -1,12 +0,0 @@ -# Tests -__test__/ -*.spec.* -*.test.* - -# Source files -coverage/ -src/ - -# config -babel.config.js -tsconfig.json \ No newline at end of file diff --git a/packages/utilities/fast-web-utilities/.npmrc b/packages/utilities/fast-web-utilities/.npmrc deleted file mode 100644 index 43c97e719a5..00000000000 --- a/packages/utilities/fast-web-utilities/.npmrc +++ /dev/null @@ -1 +0,0 @@ -package-lock=false diff --git a/packages/utilities/fast-web-utilities/.prettierignore b/packages/utilities/fast-web-utilities/.prettierignore deleted file mode 100644 index 521e20e203d..00000000000 --- a/packages/utilities/fast-web-utilities/.prettierignore +++ /dev/null @@ -1,3 +0,0 @@ -coverage/* -dist/* -www/* \ No newline at end of file diff --git a/packages/utilities/fast-web-utilities/CHANGELOG.json b/packages/utilities/fast-web-utilities/CHANGELOG.json deleted file mode 100644 index 1d9752b02bd..00000000000 --- a/packages/utilities/fast-web-utilities/CHANGELOG.json +++ /dev/null @@ -1,358 +0,0 @@ -{ - "name": "@microsoft/fast-web-utilities", - "entries": [ - { - "date": "Thu, 20 Jun 2024 17:00:57 GMT", - "version": "6.0.0", - "tag": "@microsoft/fast-web-utilities_v6.0.0", - "comments": { - "none": [ - { - "author": "7559015+janechu@users.noreply.github.com", - "package": "@microsoft/fast-web-utilities", - "commit": "4b23b5caa76c172d3ea6c6559699d632a278442c", - "comment": "Convert karma configuration to cjs" - }, - { - "author": "7559015+janechu@users.noreply.github.com", - "package": "@microsoft/fast-web-utilities", - "commit": "00bccd7812ca072fc2efdf39af7762bbfdc90846", - "comment": "Remove eslint config package" - } - ] - } - }, - { - "date": "Wed, 20 Dec 2023 19:03:47 GMT", - "tag": "@microsoft/fast-web-utilities_v6.0.0", - "version": "6.0.0", - "comments": { - "none": [ - { - "author": "863023+radium-v@users.noreply.github.com", - "package": "@microsoft/fast-web-utilities", - "commit": "fd65254531ac3a593b32528d81b44ebf82c8e4ab", - "comment": "fix RtlScrollConverter test" - } - ] - } - }, - { - "date": "Fri, 16 Jun 2023 18:17:13 GMT", - "tag": "@microsoft/fast-web-utilities_v6.0.0", - "version": "6.0.0", - "comments": { - "none": [ - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-web-utilities", - "commit": "ca0e62ee8d05f72d1d8c1ad66bd6eea8e3f0a4eb", - "comment": "update prettier and eslint-config-prettier versions" - } - ] - } - }, - { - "date": "Sat, 11 Mar 2023 00:09:48 GMT", - "tag": "@microsoft/fast-web-utilities_v6.0.0", - "version": "6.0.0", - "comments": { - "none": [ - { - "author": "nonusethi1272@gmail.com", - "package": "@microsoft/fast-web-utilities", - "commit": "2e47102bbf16415a4d2ec27bfbf27f619dd649a8", - "comment": "Turned on strictNullChecks, strictPropertyInitialization for fast-web-utilities" - } - ] - } - }, - { - "date": "Thu, 06 Oct 2022 23:21:20 GMT", - "tag": "@microsoft/fast-web-utilities_v6.0.0", - "version": "6.0.0", - "comments": { - "none": [ - { - "author": "863023+radium-v@users.noreply.github.com", - "package": "@microsoft/fast-web-utilities", - "commit": "c06e32d72d518bf5c3152efe4e666f233190b445", - "comment": "upgrade karma to ^6.4.1" - } - ] - } - }, - { - "date": "Thu, 18 Aug 2022 20:46:10 GMT", - "tag": "@microsoft/fast-web-utilities_v6.0.0", - "version": "6.0.0", - "comments": { - "none": [ - { - "author": "nicholasrice@users.noreply.github.com", - "package": "@microsoft/fast-web-utilities", - "commit": "0b57f1bc812e8e6371b7d27bb625f99a25bfaa66", - "comment": "Reverts PR #6253" - } - ] - } - }, - { - "date": "Wed, 15 Jun 2022 17:41:10 GMT", - "tag": "@microsoft/fast-web-utilities_v6.0.0", - "version": "6.0.0", - "comments": { - "none": [ - { - "comment": "Updated README for usage of keyboard event keys", - "author": "7559015+janechu@users.noreply.github.com", - "commit": "a6b2a570c1cb592bc92b4c9d8366d197658819ae", - "package": "@microsoft/fast-web-utilities" - } - ] - } - }, - { - "date": "Wed, 01 Jun 2022 17:53:14 GMT", - "tag": "@microsoft/fast-web-utilities_v6.0.0", - "version": "6.0.0", - "comments": { - "none": [ - { - "comment": "chore: update package.json metadata", - "author": "roeisenb@microsoft.com", - "commit": "4699e77715068f8610aae908ede6356a249574b6", - "package": "@microsoft/fast-web-utilities" - }, - { - "comment": "update api extractor and typescript to use the latest versions", - "author": "chhol@microsoft.com", - "commit": "4699e77715068f8610aae908ede6356a249574b6", - "package": "@microsoft/fast-web-utilities" - }, - { - "comment": "Bump @microsoft/eslint-config-fast-dna to v2.1.0", - "author": "roeisenb@microsoft.com", - "commit": "4699e77715068f8610aae908ede6356a249574b6", - "package": "@microsoft/fast-web-utilities" - } - ], - "patch": [ - { - "comment": "chore: fix broken build", - "author": "roeisenb@microsoft.com", - "commit": "4699e77715068f8610aae908ede6356a249574b6", - "package": "@microsoft/fast-web-utilities" - }, - { - "comment": "Upgrade TypeScript", - "author": "nicholasrice@users.noreply.github.com", - "commit": "4699e77715068f8610aae908ede6356a249574b6", - "package": "@microsoft/fast-web-utilities" - } - ], - "major": [ - { - "comment": "remove deprecated keycodes and add additional keys", - "author": "chhol@microsoft.com", - "commit": "4699e77715068f8610aae908ede6356a249574b6", - "package": "@microsoft/fast-web-utilities" - } - ] - } - }, - { - "date": "Wed, 04 May 2022 07:14:00 GMT", - "tag": "@microsoft/fast-web-utilities_v5.4.1", - "version": "5.4.1", - "comments": { - "patch": [ - { - "comment": "convert orientation enum to const object with corresponding type", - "author": "chhol@microsoft.com", - "commit": "d39284193f6d476b5b40b0fad75d3dbd836d55da", - "package": "@microsoft/fast-web-utilities" - } - ] - } - }, - { - "date": "Wed, 27 Apr 2022 07:21:09 GMT", - "tag": "@microsoft/fast-web-utilities_v5.4.0", - "version": "5.4.0", - "comments": { - "minor": [ - { - "comment": "update to typescript 4.6.2 and update ARIAMixin typings", - "author": "chhol@microsoft.com", - "commit": "35bdab45550b5d8b8762041110eccb06de78add5", - "package": "@microsoft/fast-web-utilities" - } - ], - "patch": [ - { - "comment": "Bump @microsoft/eslint-config-fast-dna to v2.1.0", - "author": "chhol@microsoft.com", - "commit": "35bdab45550b5d8b8762041110eccb06de78add5", - "package": "@microsoft/fast-web-utilities" - } - ] - } - }, - { - "date": "Sun, 17 Apr 2022 07:11:18 GMT", - "tag": "@microsoft/fast-web-utilities_v5.3.0", - "version": "5.3.0", - "comments": { - "minor": [ - { - "comment": "Instead of matchAll, used regex replace for pascalCase and added number to add to spinalCase", - "author": "74849806+wannieman98@users.noreply.github.com", - "commit": "14bc5d5f2ae608328eb16ad7e619bab00415f60a", - "package": "@microsoft/fast-web-utilities" - } - ] - } - }, - { - "date": "Sun, 03 Apr 2022 07:12:01 GMT", - "tag": "@microsoft/fast-web-utilities_v5.2.0", - "version": "5.2.0", - "comments": { - "minor": [ - { - "comment": "Declare package as using ES modules", - "author": "nicholasrice@users.noreply.github.com", - "commit": "f6107c448ab6446667f4d9e86d9f9c11fff075aa", - "package": "@microsoft/fast-web-utilities" - } - ], - "patch": [ - { - "comment": "update exenv-es6 to 1.1.0 to ensure we lock to es module support", - "author": "chhol@microsoft.com", - "commit": "077a14b2e63332384349d2be205b4afa7246b13c", - "package": "@microsoft/fast-web-utilities" - } - ] - } - }, - { - "date": "Tue, 25 Jan 2022 07:11:53 GMT", - "tag": "@microsoft/fast-web-utilities_v5.1.0", - "version": "5.1.0", - "comments": { - "minor": [ - { - "comment": "add findLastIndex and inRange functions to fast-web-utilities", - "author": "john.kreitlow@microsoft.com", - "commit": "97f653f8ee62c74d47df9b60024ff8eef05c79d1", - "package": "@microsoft/fast-web-utilities" - } - ] - } - }, - { - "date": "Sun, 31 Oct 2021 07:17:45 GMT", - "tag": "@microsoft/fast-web-utilities_v5.0.2", - "version": "5.0.2", - "comments": { - "patch": [ - { - "comment": "update fast eslint package version", - "author": "chhol@microsoft.com", - "commit": "a150068ee196e73fe7a4f7b538a38752e0e506ba", - "package": "@microsoft/fast-web-utilities" - } - ] - } - }, - { - "date": "Wed, 13 Oct 2021 01:53:37 GMT", - "tag": "@microsoft/fast-web-utilities_v5.0.1", - "version": "5.0.1", - "comments": { - "patch": [ - { - "comment": "remove prefix from uniqueId function", - "author": "john.kreitlow@microsoft.com", - "commit": "d609cffb4657e8447fb65d3b52899f48b8bb87cb", - "package": "@microsoft/fast-web-utilities" - }, - { - "comment": "remove throttle function", - "author": "john.kreitlow@microsoft.com", - "commit": "696d66c1382aebedc9410b83362c4dbda131a638", - "package": "@microsoft/fast-web-utilities" - }, - { - "comment": "refactor: remove lodash-es as a dependency", - "author": "connor@peet.io", - "commit": "4ef4b325f8259dd0f648b5fe1b393ef8839e643e", - "package": "@microsoft/fast-web-utilities" - } - ] - } - }, - { - "date": "Sun, 19 Sep 2021 07:17:17 GMT", - "tag": "@microsoft/fast-web-utilities_v5.0.0", - "version": "5.0.0", - "comments": { - "major": [ - { - "comment": "add picker component", - "author": "scomea@microsoft.com", - "commit": "395775ca58b6529861aae2e2ab1a628e2d8db081", - "package": "@microsoft/fast-web-utilities" - } - ] - } - }, - { - "date": "Sun, 12 Sep 2021 07:17:43 GMT", - "tag": "@microsoft/fast-web-utilities_v4.8.1", - "version": "4.8.1", - "comments": { - "patch": [ - { - "comment": "remove dependencies on keycode", - "author": "scomea@microsoft.com", - "commit": "e8602a247065b0c916bdc8e55314f2d3e3403fd1", - "package": "@microsoft/fast-web-utilities" - } - ] - } - }, - { - "date": "Thu, 20 May 2021 07:24:10 GMT", - "tag": "@microsoft/fast-web-utilities_v4.8.0", - "version": "4.8.0", - "comments": { - "minor": [ - { - "comment": "add key string constants", - "author": "john.kreitlow@microsoft.com", - "commit": "c7db517ac34ee6f0e5454bbf395711f464b438a0", - "package": "@microsoft/fast-web-utilities" - } - ] - } - }, - { - "date": "Fri, 16 Apr 2021 01:19:08 GMT", - "tag": "@microsoft/fast-web-utilities_v4.7.3", - "version": "4.7.3", - "comments": { - "none": [ - { - "comment": "chore: convert Jest tests to Karma/Mocha/Chai", - "author": "7559015+janechu@users.noreply.github.com", - "commit": "832c1086c05099de4f7c9261dd85b7b32605538c", - "package": "@microsoft/fast-web-utilities" - } - ] - } - } - ] -} diff --git a/packages/utilities/fast-web-utilities/CHANGELOG.md b/packages/utilities/fast-web-utilities/CHANGELOG.md deleted file mode 100644 index 4b62a597fd1..00000000000 --- a/packages/utilities/fast-web-utilities/CHANGELOG.md +++ /dev/null @@ -1,520 +0,0 @@ -# Change Log - @microsoft/fast-web-utilities - -This log was last generated on Wed, 01 Jun 2022 17:53:14 GMT and should not be manually modified. - - - -## 6.0.0 - -Wed, 01 Jun 2022 17:53:14 GMT - -### Major changes - -- remove deprecated keycodes and add additional keys (chhol@microsoft.com) - -### Patches - -- chore: fix broken build (roeisenb@microsoft.com) -- Upgrade TypeScript (nicholasrice@users.noreply.github.com) - -## 5.4.1 - -Wed, 04 May 2022 07:14:00 GMT - -### Patches - -- convert orientation enum to const object with corresponding type (chhol@microsoft.com) - -## 5.4.0 - -Wed, 27 Apr 2022 07:21:09 GMT - -### Minor changes - -- update to typescript 4.6.2 and update ARIAMixin typings (chhol@microsoft.com) - -### Patches - -- Bump @microsoft/eslint-config-fast-dna to v2.1.0 (chhol@microsoft.com) - -## 5.3.0 - -Sun, 17 Apr 2022 07:11:18 GMT - -### Minor changes - -- Instead of matchAll, used regex replace for pascalCase and added number to add to spinalCase (74849806+wannieman98@users.noreply.github.com) - -## 5.2.0 - -Sun, 03 Apr 2022 07:12:01 GMT - -### Minor changes - -- Declare package as using ES modules (nicholasrice@users.noreply.github.com) - -### Patches - -- update exenv-es6 to 1.1.0 to ensure we lock to es module support (chhol@microsoft.com) - -## 5.1.0 - -Tue, 25 Jan 2022 07:11:53 GMT - -### Minor changes - -- add findLastIndex and inRange functions to fast-web-utilities (john.kreitlow@microsoft.com) - -## 5.0.2 - -Sun, 31 Oct 2021 07:17:45 GMT - -### Patches - -- update fast eslint package version (chhol@microsoft.com) - -## 5.0.1 - -Wed, 13 Oct 2021 01:53:37 GMT - -### Patches - -- remove prefix from uniqueId function (john.kreitlow@microsoft.com) -- remove throttle function (john.kreitlow@microsoft.com) -- refactor: remove lodash-es as a dependency (connor@peet.io) - -## 5.0.0 - -Sun, 19 Sep 2021 07:17:17 GMT - -### Major changes - -- add picker component (scomea@microsoft.com) - -## 4.8.1 - -Sun, 12 Sep 2021 07:17:43 GMT - -### Patches - -- remove dependencies on keycode (scomea@microsoft.com) - -## 4.8.0 - -Thu, 20 May 2021 07:24:10 GMT - -### Minor changes - -- add key string constants (john.kreitlow@microsoft.com) - -## [4.7.3](https://github.com/Microsoft/fast/compare/@microsoft/fast-web-utilities@4.7.1...@microsoft/fast-web-utilities@4.7.3) (2021-02-08) - -**Note:** Version bump only for package @microsoft/fast-web-utilities - - - - - -## [4.7.2](https://github.com/Microsoft/fast/compare/@microsoft/fast-web-utilities@4.7.1...@microsoft/fast-web-utilities@4.7.2) (2021-02-08) - -**Note:** Version bump only for package @microsoft/fast-web-utilities - - - - - -## [4.7.1](https://github.com/Microsoft/fast/compare/@microsoft/fast-web-utilities@4.7.0...@microsoft/fast-web-utilities@4.7.1) (2021-01-30) - - -### Bug Fixes - -* allow nonce usage in canUseFocusVisible ([#4243](https://github.com/Microsoft/fast/issues/4243)) ([6e8b917](https://github.com/Microsoft/fast/commit/6e8b917dcbff8c5c0452e2dccc92020070ae3e3c)) - - - - - -# [4.7.0](https://github.com/Microsoft/fast/compare/@microsoft/fast-web-utilities@4.6.1...@microsoft/fast-web-utilities@4.7.0) (2020-12-16) - - -### Features - -* add standard event types as exported strings ([#4161](https://github.com/Microsoft/fast/issues/4161)) ([f2d9087](https://github.com/Microsoft/fast/commit/f2d9087296401d613ff4aa85d8eb4c0d54e73be0)) - - - - - -## [4.6.1](https://github.com/Microsoft/fast/compare/@microsoft/fast-web-utilities@4.6.0...@microsoft/fast-web-utilities@4.6.1) (2020-10-14) - -**Note:** Version bump only for package @microsoft/fast-web-utilities - - - - - -# [4.6.0](https://github.com/Microsoft/fast/compare/@microsoft/fast-web-utilities@4.5.2...@microsoft/fast-web-utilities@4.6.0) (2020-07-14) - - -### Features - -* update typescript version and remove utility types dependencies for react packages ([#3422](https://github.com/Microsoft/fast/issues/3422)) ([09d07b5](https://github.com/Microsoft/fast/commit/09d07b580cda3bcc5d28f83d3568521f710c9576)) - - - - - -## [4.5.2](https://github.com/Microsoft/fast/compare/@microsoft/fast-web-utilities@4.5.1...@microsoft/fast-web-utilities@4.5.2) (2020-06-26) - -**Note:** Version bump only for package @microsoft/fast-web-utilities - - - - - -# [4.5.0](https://github.com/Microsoft/fast/compare/@microsoft/fast-web-utilities@4.4.5...@microsoft/fast-web-utilities@4.5.0) (2020-05-18) - - -### Features - -* add system-colors to fast-web-utilities ([#3137](https://github.com/Microsoft/fast/issues/3137)) ([ee37b3f](https://github.com/Microsoft/fast/commit/ee37b3f51336a040b64fc0f00d73c57185cafaa7)) - - - - - -## [4.4.5](https://github.com/Microsoft/fast/compare/@microsoft/fast-web-utilities@4.4.4...@microsoft/fast-web-utilities@4.4.5) (2020-04-29) - -**Note:** Version bump only for package @microsoft/fast-web-utilities - - - - - -## [4.4.4](https://github.com/Microsoft/fast/compare/@microsoft/fast-web-utilities@4.4.3...@microsoft/fast-web-utilities@4.4.4) (2020-04-27) - -**Note:** Version bump only for package @microsoft/fast-web-utilities - - - - - -## [4.4.3](https://github.com/Microsoft/fast/compare/@microsoft/fast-web-utilities@4.4.2...@microsoft/fast-web-utilities@4.4.3) (2020-04-22) - -**Note:** Version bump only for package @microsoft/fast-web-utilities - - - - - -## [4.4.2](https://github.com/Microsoft/fast/compare/@microsoft/fast-web-utilities@4.4.1...@microsoft/fast-web-utilities@4.4.2) (2020-04-10) - -**Note:** Version bump only for package @microsoft/fast-web-utilities - - - - - -## [4.4.1](https://github.com/Microsoft/fast/compare/@microsoft/fast-web-utilities@4.4.0...@microsoft/fast-web-utilities@4.4.1) (2020-03-13) - -**Note:** Version bump only for package @microsoft/fast-web-utilities - - - - - -# [4.4.0](https://github.com/Microsoft/fast/compare/@microsoft/fast-web-utilities@4.3.7...@microsoft/fast-web-utilities@4.4.0) (2019-12-05) - - -### Bug Fixes - -* horizontal overflow rtl scroll behavior and add rtl scrollLeft utility ([#2462](https://github.com/Microsoft/fast/issues/2462)) ([0cc2da5](https://github.com/Microsoft/fast/commit/0cc2da5fde2abe23da987c216e03d73370cd4ad3)) - - -### Features - -* add new utilities for checking HTML elements ([#2481](https://github.com/Microsoft/fast/issues/2481)) ([15de67e](https://github.com/Microsoft/fast/commit/15de67e207796c0b799827f33cdb47a8e32432e3)) - - - - - -## [4.3.7](https://github.com/Microsoft/fast/compare/@microsoft/fast-web-utilities@4.3.6...@microsoft/fast-web-utilities@4.3.7) (2019-11-19) - -**Note:** Version bump only for package @microsoft/fast-web-utilities - - - - - -## [4.3.6](https://github.com/Microsoft/fast/compare/@microsoft/fast-web-utilities@4.3.5...@microsoft/fast-web-utilities@4.3.6) (2019-11-07) - - -### Bug Fixes - -* canUsedForcedColors should be called canUseForcedColors ([#2403](https://github.com/Microsoft/fast/issues/2403)) ([8904df4](https://github.com/Microsoft/fast/commit/8904df4d8af78d917a3aa6104f34ad45e12bfda5)) - - - - - -## [4.3.5](https://github.com/Microsoft/fast/compare/@microsoft/fast-web-utilities@4.3.4...@microsoft/fast-web-utilities@4.3.5) (2019-10-25) - -**Note:** Version bump only for package @microsoft/fast-web-utilities - - - - - -## [4.3.4](https://github.com/Microsoft/fast/compare/@microsoft/fast-web-utilities@4.3.3...@microsoft/fast-web-utilities@4.3.4) (2019-10-24) - - -### Bug Fixes - -* canUsedForcedColors function is not isomorphic ([#2378](https://github.com/Microsoft/fast/issues/2378)) ([0c929c8](https://github.com/Microsoft/fast/commit/0c929c8a333f810d95d43b09d171e71e55276f16)) - - - - - -## [4.3.3](https://github.com/Microsoft/fast/compare/@microsoft/fast-web-utilities@4.3.2...@microsoft/fast-web-utilities@4.3.3) (2019-10-17) - - -### Bug Fixes - -* components are not showing correct high contrast colors in Edge chromium, removed hard code value, and add more examples ([#2327](https://github.com/Microsoft/fast/issues/2327)) ([125a85c](https://github.com/Microsoft/fast/commit/125a85c)) - - - - - -## [4.3.2](https://github.com/Microsoft/fast/compare/@microsoft/fast-web-utilities@4.3.1...@microsoft/fast-web-utilities@4.3.2) (2019-09-17) - - -### Bug Fixes - -* improve render performance of page, grid, and column components ([#2241](https://github.com/Microsoft/fast/issues/2241)) ([7936adc](https://github.com/Microsoft/fast/commit/7936adc)) - - - - - -## [4.3.1](https://github.com/Microsoft/fast/compare/@microsoft/fast-web-utilities@4.3.0...@microsoft/fast-web-utilities@4.3.1) (2019-09-09) - - -### Bug Fixes - -* exit focus visible utility immediately with false value if DOM is unavailable ([#2223](https://github.com/Microsoft/fast/issues/2223)) ([3fbd6c2](https://github.com/Microsoft/fast/commit/3fbd6c2)) - - - - - -# [4.3.0](https://github.com/Microsoft/fast/compare/@microsoft/fast-web-utilities@4.2.1...@microsoft/fast-web-utilities@4.3.0) (2019-08-22) - - -### Features - -* adds classNames utility ([#2163](https://github.com/Microsoft/fast/issues/2163)) ([d6a872d](https://github.com/Microsoft/fast/commit/d6a872d)) -* export individual keycodes as named exports and unreference KeyCodes ([327d806](https://github.com/Microsoft/fast/commit/327d806)) - - - - - -## [4.2.1](https://github.com/Microsoft/fast/compare/@microsoft/fast-web-utilities@4.2.0...@microsoft/fast-web-utilities@4.2.1) (2019-08-09) - - -### Bug Fixes - -* establish no side effects in fast-web-utilities ([a97741a](https://github.com/Microsoft/fast/commit/a97741a)) - - - - - -# [4.2.0](https://github.com/Microsoft/fast/compare/@microsoft/fast-web-utilities@4.1.0...@microsoft/fast-web-utilities@4.2.0) (2019-05-31) - - -### Features - -* add query string parser ([#1784](https://github.com/Microsoft/fast/issues/1784)) ([de20112](https://github.com/Microsoft/fast/commit/de20112)) -* show values as dash separated and send camelCase values in the CSS property editor callback ([#1772](https://github.com/Microsoft/fast/issues/1772)) ([93d6223](https://github.com/Microsoft/fast/commit/93d6223)) - - - - - -# [4.1.0](https://github.com/Microsoft/fast/compare/@microsoft/fast-web-utilities@4.0.1...@microsoft/fast-web-utilities@4.1.0) (2019-04-23) - - -### Features - -* reduce dependency on peer dependencies ([#1669](https://github.com/Microsoft/fast/issues/1669)) ([cc06b10](https://github.com/Microsoft/fast/commit/cc06b10)) - - - - - -## [4.0.1](https://github.com/Microsoft/fast/compare/@microsoft/fast-web-utilities@4.0.0...@microsoft/fast-web-utilities@4.0.1) (2019-04-09) - -**Note:** Version bump only for package @microsoft/fast-web-utilities - - - - - -# [4.0.0](https://github.com/Microsoft/fast/compare/@microsoft/fast-web-utilities@3.1.3...@microsoft/fast-web-utilities@4.0.0) (2019-03-25) - - -### Bug Fixes - -* update to use esModuleInterop in the TypeScript configuration files ([#1211](https://github.com/Microsoft/fast/issues/1211)) ([2ec0644](https://github.com/Microsoft/fast/commit/2ec0644)) - - -### Features - -* remove fast-application-utilities package ([#1455](https://github.com/Microsoft/fast/issues/1455)) ([7ee34fa](https://github.com/Microsoft/fast/commit/7ee34fa)) - - -### BREAKING CHANGES - -* removal of fast-application-utilities-package -* This will affect how imports will be handled by -consumers - - - - - -## [3.1.3](https://github.com/Microsoft/fast/compare/@microsoft/fast-web-utilities@3.1.2...@microsoft/fast-web-utilities@3.1.3) (2019-03-19) - - -### Bug Fixes - -* update jest to fix build break ([#1531](https://github.com/Microsoft/fast/issues/1531)) ([73ae6de](https://github.com/Microsoft/fast/commit/73ae6de)) - - - - - -## [3.1.2](https://github.com/Microsoft/fast/compare/@microsoft/fast-web-utilities@3.1.1...@microsoft/fast-web-utilities@3.1.2) (2019-02-21) - -**Note:** Version bump only for package @microsoft/fast-web-utilities - - - - - -## [3.1.1](https://github.com/Microsoft/fast/compare/@microsoft/fast-web-utilities@3.1.0...@microsoft/fast-web-utilities@3.1.1) (2019-02-07) - -**Note:** Version bump only for package @microsoft/fast-web-utilities - - - - - - -# [3.1.0](https://github.com/Microsoft/fast/compare/@microsoft/fast-web-utilities@3.0.4...@microsoft/fast-web-utilities@3.1.0) (2019-01-26) - - -### Features - -* add direction and localization helpers to fast-web-utilities ([#1330](https://github.com/Microsoft/fast/issues/1330)) ([be0f603](https://github.com/Microsoft/fast/commit/be0f603)) - - - - - - -## [3.0.4](https://github.com/Microsoft/fast/compare/@microsoft/fast-web-utilities@3.0.3...@microsoft/fast-web-utilities@3.0.4) (2018-12-21) - - -### Bug Fixes - -* style cleanup and consolidation ([#1198](https://github.com/Microsoft/fast/issues/1198)) ([4151f39](https://github.com/Microsoft/fast/commit/4151f39)) - - - - - - -# 2.2.0 (2018-09-11) - - -### Features - -* add contrast based color system ([#810](https://github.com/Microsoft/fast/issues/810)) ([5ec457c](https://github.com/Microsoft/fast/commit/5ec457c)) - - - - -# 2.1.0 (2018-08-29) - - -### Bug Fixes - -* **fast-web-utilities:** fix an issue where getClientRectWithMargin threw an error in EDGE and IE strict modes due to readonly properties ([#767](https://github.com/Microsoft/fast/issues/767)) ([d3fa002](https://github.com/Microsoft/fast/commit/d3fa002)) - - -### Features - -* update Lerna to ^3.0.0 ([#795](https://github.com/Microsoft/fast/issues/795)) ([9ce9a56](https://github.com/Microsoft/fast/commit/9ce9a56)) -* upgrade to TypeScript 3.0.0 ([#793](https://github.com/Microsoft/fast/issues/793)) ([e203e86](https://github.com/Microsoft/fast/commit/e203e86)) -* **fast-components-react-base:** add callback to horizontal overflow to return and object that informs scroll start and end ([#797](https://github.com/Microsoft/fast/issues/797)) ([37975f3](https://github.com/Microsoft/fast/commit/37975f3)) -* **fast-components-react-base:** add tabs component ([#761](https://github.com/Microsoft/fast/issues/761)) ([24a5bb3](https://github.com/Microsoft/fast/commit/24a5bb3)) -* **paragraph:** adds paragraph as a new MSFT component ([#805](https://github.com/Microsoft/fast/issues/805)) ([8325d3f](https://github.com/Microsoft/fast/commit/8325d3f)) - - - - -# 2.0.0-corrected (2018-08-03) - - -### Features - -* **utilities:** add fast-web-utilities as a new package ([#686](https://github.com/Microsoft/fast/issues/686)) ([a31a581](https://github.com/Microsoft/fast/commit/a31a581)) - - - - - - -# [2.1.0](https://github.com/Microsoft/fast/compare/v2.0.0-corrected...v2.1.0) (2018-08-29) - - -### Bug Fixes - -* **fast-web-utilities:** fix an issue where getClientRectWithMargin threw an error in EDGE and IE strict modes due to readonly properties ([#767](https://github.com/Microsoft/fast/issues/767)) ([d3fa002](https://github.com/Microsoft/fast/commit/d3fa002)) - - -### Features - -* update Lerna to ^3.0.0 ([#795](https://github.com/Microsoft/fast/issues/795)) ([9ce9a56](https://github.com/Microsoft/fast/commit/9ce9a56)) -* upgrade to TypeScript 3.0.0 ([#793](https://github.com/Microsoft/fast/issues/793)) ([e203e86](https://github.com/Microsoft/fast/commit/e203e86)) -* **fast-components-react-base:** add callback to horizontal overflow to return and object that informs scroll start and end ([#797](https://github.com/Microsoft/fast/issues/797)) ([37975f3](https://github.com/Microsoft/fast/commit/37975f3)) -* **fast-components-react-base:** add tabs component ([#761](https://github.com/Microsoft/fast/issues/761)) ([24a5bb3](https://github.com/Microsoft/fast/commit/24a5bb3)) -* **paragraph:** adds paragraph as a new MSFT component ([#805](https://github.com/Microsoft/fast/issues/805)) ([8325d3f](https://github.com/Microsoft/fast/commit/8325d3f)) - - - - - - -# [2.0.0](https://github.com/Microsoft/fast/compare/v1.6.0...v2.0.0) (2018-08-02) - - -### Features - -* **utilities:** add fast-web-utilities as a new package ([#686](https://github.com/Microsoft/fast/issues/686)) ([a31a581](https://github.com/Microsoft/fast/commit/a31a581)) - - - - - -# [1.9.0](https://github.com/Microsoft/fast/compare/v1.6.0...v1.9.0) (2018-07-14) - - -### Features - -* **utilities:** add fast-web-utilities as a new package ([#686](https://github.com/Microsoft/fast/issues/686)) ([a31a581](https://github.com/Microsoft/fast/commit/a31a581)) diff --git a/packages/utilities/fast-web-utilities/README.md b/packages/utilities/fast-web-utilities/README.md deleted file mode 100644 index 7478e8ebd9c..00000000000 --- a/packages/utilities/fast-web-utilities/README.md +++ /dev/null @@ -1,173 +0,0 @@ -# FAST Web utilities - -This package is a collection of utilities intended to be used for web projects. - -## Installation - -`npm i --save @microsoft/fast-web-utilities` - -## Usage - -### DOM utilities - -#### Keys - -Various keys are available to use with keyboard events. - -```js -import { keyEnter } from "@microsoft/fast-web-utilities"; - -handleKeyPress = (e) => { - if (e.key === keyEnter) { - // Do something when the Enter key has been pressed - } -} -``` - -View our [available keys](https://github.com/microsoft/fast/blob/master/packages/utilities/fast-web-utilities/src/key-codes.ts) file for details. - -### HTML utilities - -#### getClientRectWithMargin - -The `getClientRectWithMargin` function gets the client bounding rectangle including any margins of an element. - -```js -import { getClientRectWithMargin } from "@microsoft/fast-web-utilities"; - -const itemWidth = getClientRectWithMargin(item).width; -const itemHeight = getClientRectWithMargin(item).height; -``` - -#### convertStylePropertyPixelsToNumber - -The `convertStylePropertyPixelsToNumber` function will convert a property value from an elements computed style from pixels to a number value. - -```js -import { convertStylePropertyPixelsToNumber } from "@microsoft/fast-web-utilities"; - -const elementTopMargin = convertStylePropertyPixelsToNumber(style, "margin-top"); -``` - -### Key utilities - -#### Key strings - -Commonly used `event.key` values are available as individual exports. Additional `key` values will be added as needed. - -```js -import { keyEnter, keySpace } from "@microsoft/fast-web-utilities"; - -handleKeyPress = (e) => { - switch (e.key) { - case keySpace: - case keyEnter: - // Do something if key matches - break; - } -} -``` - -#### KeyCodes (enum) - -Keycodes are deprecated and their use should be avoided. Use the individual string `key` values instead. - -### Localization utilities - -#### Typescript enum - -The `Direction` enum contains the `ltr` and `rtl` enum for use in a Typescript project. - -```typescript -import { Direction } from "@microsoft/fast-web-utilities"; - -let direction: Direction = Direction.ltr; -``` - -### Number utilities - -#### Limit - -The `limit` function ensures that a value is between a min and max value. If the value is lower than min, min will be returned. If the value is greater than max, max will be retured. - -```js -import { limit } from "@microsoft/fast-web-utilities"; -const incomingNumber; // 11 -const setNumberByLimit = limit(0, 10, incomingNumber); // returns 10 -``` - -#### wrapInBounds - -The `wrapInBounds` function keeps a given value within the bounds of a min and max value. If the value is larger than the max, the minimum value will be returned. If the value is smaller than the minimum, the maximum will be returned. Otherwise, the value is returned un-changed. - -```js -import { wrapInBounds } from "@microsoft/fast-web-utilities"; -const slides; // 5 -const index; // 5 -const activeIndex = wrapInBounds(0, this.slides.length - 1, index) // returns 0 -``` - -### String utilities - -#### Format - -The `format` function builds a string from a format specifier and replacement parameters. - -```js -import { format } from "@microsoft/fast-web-utilities"; - -const formatterString = "View {0} {1}"; - -const newString = format(formatterString, "page", "4")); // "View page 4" -``` - -#### startsWith - -The `startsWith` function checks to see if one string starts with another. The function is case sensitive. - -```js -import { startsWith } from "@microsoft/fast-web-utilities"; - -const matchIsFalse = startsWith("HelloWorld", "World"); // false -const matchIsTrue = startsWith("HelloWorld", "Hello"); // true -``` - -#### isNullOrWhiteSpace - -The `isNullOrWhiteSpace` function determines if the specified string is undefined, null, empty, or whitespace. The function returns true if the value is undefined, null, empty, or whitespace, otherwise false. - -```js -import { isNullOrWhiteSpace } from "@microsoft/fast-web-utilities"; - -const myAnchor = document.querySelector("#id"); -const checkWhitespace = isNullOrWhiteSpace(myAnchor.href); -``` - -#### pascalCase - -The `pascalCase` function converts a string to Pascal Case - -```js -import { pascalCase } from "@microsoft/fast-web-utilities"; - -const hyphenatedToPascal = pascalCase("my-string"); -const uppercaseToPascal = pascalCase("MY STRING"); -const whitespaceToPascal = pascalCase(" my string "); -``` - -#### classNames -A utility for merging class names into a single string conditionally. Accepts any number of strings, functions that return strings and two index arrays where the first index is a string or function that returns a string, and the second index is a boolean. - -```js -import { classNames } from "@microsoft/fast-web-utilities"; - -// evaluates to "classOne classTwo classThree classFive" -const myJoinedClassNames = classNames( - "classOne", - () => "classTwo", - ["classThree", true], - ["classFour", false] - [() => "classFive", true], - [() => "classSix", false] -) -``` diff --git a/packages/utilities/fast-web-utilities/karma.conf.cjs b/packages/utilities/fast-web-utilities/karma.conf.cjs deleted file mode 100644 index 0eb4cf97564..00000000000 --- a/packages/utilities/fast-web-utilities/karma.conf.cjs +++ /dev/null @@ -1,160 +0,0 @@ -const path = require("path"); - -const basePath = path.resolve(__dirname); - -const commonChromeFlags = [ - "--no-default-browser-check", - "--no-first-run", - "--no-sandbox", - "--no-managed-user-acknowledgment-check", - "--disable-background-timer-throttling", - "--disable-backing-store-limit", - "--disable-boot-animation", - "--disable-cloud-import", - "--disable-contextual-search", - "--disable-default-apps", - "--disable-extensions", - "--disable-infobars", - "--disable-translate", - "--force-device-scale-factor=1", -]; - -module.exports = function (config) { - let browsers; - if (process.env.BROWSERS) { - browsers = [process.env.BROWSERS]; - } else if (config.browsers) { - browsers = config.browsers; - } else { - browsers = ["Chrome"]; - } - - const setup = "setup-browser" + (config.package ? "-" + config.package : ""); - const options = { - basePath, - browserDisconnectTimeout: 10000, - processKillTimeout: 10000, - frameworks: ["source-map-support", "mocha"], - plugins: [ - require("karma-mocha"), - require("karma-mocha-reporter"), - require("karma-webpack"), - require("karma-source-map-support"), - require("karma-sourcemap-loader"), - require("karma-coverage-istanbul-reporter"), - require("karma-chrome-launcher"), - require("karma-firefox-launcher"), - ], - files: [`dist/__test__/${setup}.cjs`], - preprocessors: { - [`dist/__test__/${setup}.cjs`]: ["webpack", "sourcemap"], - }, - webpackMiddleware: { - // webpack-dev-middleware configuration - // i. e. - stats: "errors-only", - }, - webpack: { - mode: "none", - resolve: { - extensions: [".js"], - modules: ["node_modules"], - mainFields: ["module", "main"], - }, - devtool: "inline-source-map", - performance: { - hints: false, - }, - optimization: { - nodeEnv: false, - usedExports: true, - flagIncludedChunks: false, - sideEffects: true, - concatenateModules: true, - splitChunks: { - name: false, - }, - runtimeChunk: false, - noEmitOnErrors: false, - checkWasmTypes: false, - minimize: false, - }, - module: { - rules: [ - { - test: /\.js\.map$/, - use: ["ignore-loader"], - }, - { - test: /\.js$/, - use: [ - { - loader: "source-map-loader", - options: { - enforce: "pre", - }, - }, - ], - }, - ], - }, - }, - mime: { - "text/x-typescript": ["ts"], - }, - reporters: [config.reporter || (process.env.CI ? "min" : "progress")], - browsers: browsers, - customLaunchers: { - ChromeDebugging: { - base: "Chrome", - flags: [...commonChromeFlags, "--remote-debugging-port=9333"], - debug: true, - }, - ChromeHeadlessOpt: { - base: "ChromeHeadless", - flags: [...commonChromeFlags], - }, - }, - client: { - captureConsole: true, - mocha: { - bail: config["bail"], - ui: "bdd", - timeout: 5000, - }, - }, - logLevel: config.LOG_ERROR, // to disable the WARN 404 for image requests - }; - - if (config.coverage) { - options.webpack.module.rules.push({ - enforce: "post", - exclude: /(__tests__|testing|node_modules|\.spec\.[tj]s$)/, - loader: "istanbul-instrumenter-loader", - options: { esModules: true }, - test: /\.[tj]s$/, - }); - options.reporters = ["coverage-istanbul", ...options.reporters]; - options.coverageIstanbulReporter = { - reports: ["html", "text-summary", "json", "lcovonly", "cobertura"], - dir: "coverage", - verbose: true, - thresholds: { - emitWarning: false, - global: { - statements: 90, - lines: 90, - branches: 90, - functions: 90, - }, - }, - }; - options.junitReporter = { - outputDir: "coverage", - outputFile: "test-results.xml", - useBrowserName: false, - }; - } - - config.set(options); -}; diff --git a/packages/utilities/fast-web-utilities/package.json b/packages/utilities/fast-web-utilities/package.json deleted file mode 100644 index 9012d539f57..00000000000 --- a/packages/utilities/fast-web-utilities/package.json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "name": "@microsoft/fast-web-utilities", - "description": "FAST web utilities", - "version": "6.0.0", - "sideEffects": false, - "author": { - "name": "Microsoft", - "url": "https://discord.gg/FcSNfg4" - }, - "homepage": "https://www.fast.design/", - "license": "MIT", - "repository": { - "type": "git", - "url": "git+https://github.com/Microsoft/fast.git", - "directory": "packages/utilities/fast-web-utilities" - }, - "bugs": { - "url": "https://github.com/Microsoft/fast/issues/new/choose" - }, - "main": "dist/index.js", - "types": "dist/index.d.ts", - "type": "module", - "scripts": { - "build": "tsc -p ./tsconfig.build.json", - "clean:dist": "node ../../../build/clean.js dist", - "prepare": "yarn clean:dist && yarn build", - "prettier": "prettier --config ../../../.prettierrc --write \"**/*.ts\"", - "prettier:diff": "prettier --config ../../../.prettierrc \"**/*.ts\" --list-different", - "test": "yarn eslint && yarn build && yarn test-chrome:verbose", - "test-node": "mocha --reporter min --exit dist/esm/__test__/setup-node.js './dist/esm/**/*.spec.js'", - "test-node:verbose": "mocha --reporter spec --exit dist/esm/__test__/setup-node.js './dist/esm/**/*.spec.js'", - "test-chrome": "karma start karma.conf.cjs --browsers=ChromeHeadlessOpt --single-run --coverage", - "test-chrome:verbose": "karma start karma.conf.cjs --browsers=ChromeHeadlessOpt --single-run --coverage --reporter=mocha", - "test-chrome:watch": "karma start karma.conf.cjs --browsers=ChromeHeadlessOpt --coverage --watch-extensions js", - "test-chrome:debugger": "karma start karma.conf.cjs --browsers=ChromeDebugging", - "test-chrome:verbose:watch": "karma start karma.conf.cjs --browsers=ChromeHeadlessOpt --coverage --watch-extensions js --reporter=mocha", - "test-chrome:verbose:debugger": "karma start karma.conf.cjs --browsers=ChromeDebugging --reporter=mocha", - "test-firefox": "karma start karma.conf.cjs --browsers=FirefoxHeadless --single-run --coverage", - "test-firefox:verbose": "karma start karma.conf.cjs --browsers=FirefoxHeadless --single-run --coverage --reporter=mocha", - "test-firefox:watch": "karma start karma.conf.cjs --browsers=FirefoxHeadless --coverage --watch-extensions js", - "eslint": "eslint . --ext .ts,.tsx", - "eslint:fix": "eslint . --ext .ts,.tsx --fix", - "watch": "yarn build -- -w --preserveWatchOutput" - }, - "devDependencies": { - "@types/chai": "^4.2.11", - "@types/karma": "^6.3.3", - "@types/mocha": "^7.0.2", - "chai": "^4.2.0", - "chai-spies": "^1.0.0", - "eslint-config-prettier": "^8.8.0", - "eslint-loader": "^4.0.0", - "istanbul": "^0.4.5", - "istanbul-instrumenter-loader": "^3.0.1", - "jsdom": "^16.2.2", - "jsdom-global": "3.0.2", - "karma": "^6.4.1", - "karma-chrome-launcher": "^3.1.0", - "karma-coverage": "^2.0.2", - "karma-coverage-istanbul-reporter": "^3.0.0", - "karma-firefox-launcher": "^2.1.0", - "karma-mocha": "^2.0.1", - "karma-mocha-reporter": "^2.2.5", - "karma-source-map-support": "^1.4.0", - "karma-sourcemap-loader": "^0.3.7", - "karma-webpack": "^5.0.0", - "mocha": "^7.1.2", - "prettier": "2.8.8", - "ts-loader": "^4.0.1", - "typescript": "^4.7.0" - }, - "dependencies": { - "exenv-es6": "^1.1.1" - } -} diff --git a/packages/utilities/fast-web-utilities/src/__test__/setup-browser.cts b/packages/utilities/fast-web-utilities/src/__test__/setup-browser.cts deleted file mode 100644 index 55b02eb60f5..00000000000 --- a/packages/utilities/fast-web-utilities/src/__test__/setup-browser.cts +++ /dev/null @@ -1,6 +0,0 @@ -function importAll(r: __WebpackModuleApi.RequireContext): void { - r.keys().forEach(r); -} - -// Explicitly add to browser test -importAll(require.context("../", true, /\.spec\.js$/)); diff --git a/packages/utilities/fast-web-utilities/src/__test__/setup-node.ts b/packages/utilities/fast-web-utilities/src/__test__/setup-node.ts deleted file mode 100644 index be4102c41a9..00000000000 --- a/packages/utilities/fast-web-utilities/src/__test__/setup-node.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* eslint-disable */ -if (window.document && !window.document.createRange) { - window.document.createRange = () => ({ - setStart: () => {}, - setEnd: () => {}, - // @ts-ignore - commonAncestorContainer: { - nodeName: "BODY", - ownerDocument: document, - }, - }); -} diff --git a/packages/utilities/fast-web-utilities/src/aria.spec.ts b/packages/utilities/fast-web-utilities/src/aria.spec.ts deleted file mode 100644 index b56cdd26eb1..00000000000 --- a/packages/utilities/fast-web-utilities/src/aria.spec.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { expect } from "chai"; -import { Orientation } from "./aria.js"; - -describe("aria-orientation", () => { - it("should correctly return orientation values", () => { - expect(Orientation.horizontal).to.equal("horizontal"); - expect(Orientation.vertical).to.equal("vertical"); - }); -}); diff --git a/packages/utilities/fast-web-utilities/src/aria.ts b/packages/utilities/fast-web-utilities/src/aria.ts deleted file mode 100644 index adb6ed15df9..00000000000 --- a/packages/utilities/fast-web-utilities/src/aria.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Standard orientation values - */ -export const Orientation = { - horizontal: "horizontal", - vertical: "vertical", -} as const; - -/** - * The orientation type - */ -export type Orientation = (typeof Orientation)[keyof typeof Orientation]; diff --git a/packages/utilities/fast-web-utilities/src/array.spec.ts b/packages/utilities/fast-web-utilities/src/array.spec.ts deleted file mode 100644 index fec29dee7b8..00000000000 --- a/packages/utilities/fast-web-utilities/src/array.spec.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { expect } from "chai"; -import { findLastIndex } from "./array.js"; - -describe("findLastIndex", (): void => { - it("should return -1 when array is empty", (): void => { - expect(findLastIndex([], () => true)).to.equal(-1); - }); - - it("should return the last valid item that matches the predicate", (): void => { - const array = [ - { value: true }, - { value: false }, - { value: true }, - { value: false }, - ]; - - expect(findLastIndex(array, v => v.value)).to.equal(2); - }); - - it("should return -1 when no items match the predicate", (): void => { - const array = [ - { value: false }, - { value: false }, - { value: false }, - { value: false }, - ]; - - expect(findLastIndex(array, v => v.value)).to.equal(-1); - }); -}); diff --git a/packages/utilities/fast-web-utilities/src/array.ts b/packages/utilities/fast-web-utilities/src/array.ts deleted file mode 100644 index 00572ba24cf..00000000000 --- a/packages/utilities/fast-web-utilities/src/array.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Returns the index of the last element in the array where predicate is true, and -1 otherwise. - * - * @param array - the array to test - * @param predicate - find calls predicate once for each element of the array, in descending order, - * until it finds one where predicate returns true. If such an element is found, findLastIndex immediately returns that element index. - * Otherwise, findIndex returns -1. - */ -export function findLastIndex( - array: Array, - predicate: (value: T, index: number, obj: T[]) => unknown -): number { - let k = array.length; - while (k--) { - if (predicate(array[k], k, array)) { - return k; - } - } - - return -1; -} diff --git a/packages/utilities/fast-web-utilities/src/class-names.spec.ts b/packages/utilities/fast-web-utilities/src/class-names.spec.ts deleted file mode 100644 index 3a5e5f20469..00000000000 --- a/packages/utilities/fast-web-utilities/src/class-names.spec.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { expect } from "chai"; -import { classNames } from "./class-names.js"; - -describe("classNames", (): void => { - it("should return a string when invalid values are provided", (): void => { - expect(classNames()).to.equal(""); - expect(classNames(undefined as any)).to.equal(""); - expect(classNames(null as any)).to.equal(""); - expect(classNames(NaN as any)).to.equal(""); - expect(classNames(Infinity as any)).to.equal(""); - expect(classNames(new Date() as any)).to.equal(""); - expect(classNames(1 as any)).to.equal(""); - expect(classNames([undefined as any, true])).to.equal(""); - expect(classNames([null as any, true])).to.equal(""); - expect(classNames([NaN as any, true])).to.equal(""); - expect(classNames([Infinity as any, true])).to.equal(""); - expect(classNames([new Date() as any, true])).to.equal(""); - expect(classNames([1 as any, true])).to.equal(""); - }); - - it("should return a single string argument unmodified", (): void => { - expect(classNames("hello")).to.equal("hello"); - }); - - it("should join multiple string arguments together", (): void => { - expect(classNames("hello", "world")).to.equal("hello world"); - }); - - it("should return the return value of a single function", (): void => { - expect(classNames(() => "hello")).to.equal("hello"); - }); - - it("should join the return value of a multiple functions", (): void => { - expect( - classNames( - () => "hello", - () => "world" - ) - ).to.equal("hello world"); - }); - - it("should return a the first index of an array arg when the second index is truthy", (): void => { - expect(classNames(["foo", true])).to.equal("foo"); - }); - - it("should return a single function return value of an array arg when the second index is truthy", (): void => { - expect(classNames([(): string => "foo", true])).to.equal("foo"); - }); - - it("should join multiple array index when all second indexes are true", (): void => { - expect(classNames(["foo", true], ["bar", true])).to.equal("foo bar"); - }); - - it("should omit first indexes of an array argument when the second index is falsey", (): void => { - expect(classNames(["foo", true], ["bar", false], ["bat", true])).to.equal( - "foo bat" - ); - }); - - it("should join string, function, and object arguments", (): void => { - expect( - classNames( - "hello", - ["foo", true], - ["bar", false], - [(): string => "bat", true], - "world", - () => "earth" - ) - ).to.equal("hello foo bat world earth"); - }); -}); diff --git a/packages/utilities/fast-web-utilities/src/class-names.ts b/packages/utilities/fast-web-utilities/src/class-names.ts deleted file mode 100644 index 0e6c899dc88..00000000000 --- a/packages/utilities/fast-web-utilities/src/class-names.ts +++ /dev/null @@ -1,17 +0,0 @@ -type ClassNamesArg = string | (() => string) | [string | (() => string), boolean]; - -export function classNames(...args: ClassNamesArg[]): string { - return args.reduce((accum: string, value: ClassNamesArg): string => { - const leadingChar: string = accum.length ? " " : ""; - const normalizedValue: string = - Array.isArray(value) && value[1] - ? classNames.call(null, value[0]) - : typeof value === "function" - ? value() - : typeof value === "string" - ? value - : ""; - - return !normalizedValue.length ? accum : accum + leadingChar + normalizedValue; - }, ""); -} diff --git a/packages/utilities/fast-web-utilities/src/dom.spec.ts b/packages/utilities/fast-web-utilities/src/dom.spec.ts deleted file mode 100644 index 251ed29a23f..00000000000 --- a/packages/utilities/fast-web-utilities/src/dom.spec.ts +++ /dev/null @@ -1,147 +0,0 @@ -import chai, { expect } from "chai"; -import spies from "chai-spies"; -import { - canUseCssGrid, - canUseFocusVisible, - canUseForcedColors, - getDisplayedNodes, - isHTMLElement, - resetDocumentCache, -} from "./dom.js"; - -chai.use(spies); - -describe("isHTMLElement", () => { - document.body.innerHTML = ` -
- Child -
- `; - - it("should not throw", () => { - expect(() => { - isHTMLElement(); - }).not.to.throw(); - }); - it("should return true if all arguments are HTML elements", () => { - expect(isHTMLElement(document.getElementById("element"))).to.equal(true); - }); - it("should return false if all arguments are NOT HTML elements", () => { - /* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */ - expect(isHTMLElement(document.getElementById("element")!.childNodes)).to.equal( - false - ); - }); -}); - -describe("getDisplayedNodes", () => { - it("should not throw if both arguments are null or undefined", () => { - expect(() => { - getDisplayedNodes(null, null); - getDisplayedNodes(undefined, undefined); - }).not.to.throw(); - }); -}); - -describe("canUseFocusVisible", () => { - beforeEach(() => { - resetDocumentCache(); - }); - it("should not throw", () => { - expect(() => { - canUseFocusVisible(); - }).not.to.throw(); - }); - it("should return true if the environment supports focus-visible selectors", () => { - expect(canUseFocusVisible()).to.equal(true); - }); - it("should use a nonce if once is present on the page", () => { - const nonce: string = "foo-nonce"; - const metaEl: HTMLMetaElement = document.createElement("meta"); - metaEl.setAttribute("property", "csp-nonce"); - metaEl.setAttribute("content", nonce); - document.head.appendChild(metaEl); - - // Run the function and intercept its appendChild call - const realAppendChild = document.head.appendChild; - const mockAppendChild = chai.spy(realAppendChild); - Object.defineProperty(document.head, "appendChild", { - value: mockAppendChild, - configurable: true, - }); - const mutationObserverCallback = (mutationsList: MutationRecord[]): void => { - expect(mutationsList).to.have.length.greaterThan(0); - expect(mutationsList[0].addedNodes).to.have.length.greaterThan(0); - expect(mutationsList[0].addedNodes.item(0)).not.to.equal(undefined); - expect( - (mutationsList[0].addedNodes.item(0) as HTMLStyleElement).nonce - ).to.equal(nonce); - }; - const mutationObserver = new MutationObserver(mutationObserverCallback); - mutationObserver.observe(document.head, { childList: true, subtree: true }); - canUseFocusVisible(); - - expect(mockAppendChild).to.have.been.called.exactly(1); - Object.defineProperty(document.head, "appendChild", { - value: realAppendChild, - configurable: true, - }); - }); - it("should cache the result for subsequent calls", () => { - const realAppendChild = document.head.appendChild; - const mockAppendChild = chai.spy(realAppendChild); - Object.defineProperty(document.head, "appendChild", { - value: mockAppendChild, - configurable: true, - }); - canUseFocusVisible(); - - expect(mockAppendChild).to.have.been.called.exactly(1); - - canUseFocusVisible(); - expect(mockAppendChild).to.have.been.called.exactly(1); - Object.defineProperty(document.head, "appendChild", { - value: realAppendChild, - configurable: true, - }); - }); -}); - -describe("canUseCssGrid", () => { - beforeEach(() => { - resetDocumentCache(); - }); - it("should not throw", () => { - expect(() => { - canUseCssGrid(); - }).not.to.throw(); - }); -}); - -describe("canUseForcedColors", () => { - beforeEach(() => { - window.matchMedia = (query: any): any => { - return { - matches: true, - media: query, - }; - }; - }); - it("should return true if forced color is enabled", () => { - expect(canUseForcedColors()).to.equal(true); - }); -}); - -describe("canUseForcedColors", () => { - beforeEach(() => { - window.matchMedia = (query: any): any => { - return { - matches: false, - media: query, - }; - }; - }); - it("should return false if forced color is not enabled", () => { - expect(canUseForcedColors()).to.equal(false); - }); -}); diff --git a/packages/utilities/fast-web-utilities/src/dom.ts b/packages/utilities/fast-web-utilities/src/dom.ts deleted file mode 100644 index eac4af8f5d8..00000000000 --- a/packages/utilities/fast-web-utilities/src/dom.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { canUseDOM } from "exenv-es6"; - -/** - * A test that ensures that all arguments are HTML Elements - */ -export function isHTMLElement(...args: any[]): boolean { - return args.every((arg: any) => arg instanceof HTMLElement); -} - -/** - * Returns all displayed elements inside of a root node that match a provided selector - */ -export function getDisplayedNodes( - rootNode: HTMLElement | null | undefined, - selector: string | null | undefined -): HTMLElement[] | void { - if (!rootNode || !selector || !isHTMLElement(rootNode)) { - return; - } - - const nodes: HTMLElement[] = Array.from(rootNode.querySelectorAll(selector)); - - // offsetParent will be null if the element isn't currently displayed, - // so this will allow us to operate only on visible nodes - return nodes.filter((node: HTMLElement) => node.offsetParent !== null); -} - -/** - * Returns the nonce used in the page, if any. - * - * Based on https://github.com/cssinjs/jss/blob/master/packages/jss/src/DomRenderer.js - */ -function getNonce(): string | null { - const node = document.querySelector('meta[property="csp-nonce"]'); - if (node) { - return node.getAttribute("content"); - } else { - return null; - } -} - -/** - * Test if the document supports :focus-visible - */ -let _canUseFocusVisible: boolean | undefined; -export function canUseFocusVisible(): boolean { - if (typeof _canUseFocusVisible === "boolean") { - return _canUseFocusVisible; - } - - if (!canUseDOM()) { - _canUseFocusVisible = false; - - return _canUseFocusVisible; - } - - // Check to see if the document supports the focus-visible element - const styleElement: HTMLStyleElement = document.createElement("style"); - - // If nonces are present on the page, use it when creating the style element - // to test focus-visible support. - const styleNonce = getNonce(); - if (styleNonce !== null) { - styleElement.setAttribute("nonce", styleNonce); - } - document.head.appendChild(styleElement); - - try { - (styleElement.sheet as any).insertRule("foo:focus-visible {color:inherit}", 0); - _canUseFocusVisible = true; - } catch (e) { - _canUseFocusVisible = false; - } finally { - document.head.removeChild(styleElement); - } - - return _canUseFocusVisible as boolean; -} - -let _canUseCssGrid: boolean | undefined; -export function canUseCssGrid(): boolean { - if (typeof _canUseCssGrid === "boolean") { - return _canUseCssGrid; - } - - try { - _canUseCssGrid = CSS.supports("display", "grid"); - } catch { - _canUseCssGrid = false; - } - - return _canUseCssGrid; -} - -export function canUseForcedColors(): boolean { - return ( - canUseDOM() && - (window.matchMedia("(forced-colors: none)").matches || - window.matchMedia("(forced-colors: active)").matches) - ); -} - -export function resetDocumentCache(): void { - _canUseCssGrid = undefined; - _canUseFocusVisible = undefined; -} - -/** - * @deprecated Use 'canUseForcedColors' instead - */ -export const canUsedForcedColors: typeof canUseForcedColors = canUseForcedColors; diff --git a/packages/utilities/fast-web-utilities/src/events.ts b/packages/utilities/fast-web-utilities/src/events.ts deleted file mode 100644 index 14055bc8fbf..00000000000 --- a/packages/utilities/fast-web-utilities/src/events.ts +++ /dev/null @@ -1,142 +0,0 @@ -/** - * This set of exported strings reference https://developer.mozilla.org/en-US/docs/Web/Events - * and should include all non-deprecated and non-experimental Standard events - */ - -export const eventAbort: string = "abort"; -export const eventAfterPrint: string = "afterprint"; -export const eventAnimationCancel: string = "animationcancel"; -export const eventAnimationEnd: string = "animationend"; -export const eventAnimationIteration: string = "animationiteration"; -export const eventAnimationStart: string = "animationstart"; -export const eventAppInstalled: string = "appinstalled"; -export const eventBeforePrint: string = "beforeprint"; -export const eventBeforeUnload: string = "beforeunload"; -export const eventBeginEvent: string = "beginEvent"; -export const eventBlocked: string = "blocked"; -export const eventBlur: string = "blur"; -export const eventCanPlay: string = "canplay"; -export const eventCanPlayThrough: string = "canplaythrough"; -export const eventChange: string = "change"; -export const eventChargingChange: string = "chargingchange"; -export const eventChargingTimeChange: string = "chargingtimechange"; -export const eventClick: string = "click"; -export const eventClose: string = "close"; -export const eventComplete: string = "complete"; -export const eventCompositionEnd: string = "compositionend"; -export const eventCompositionStart: string = "compositionstart"; -export const eventCompositionUpdate: string = "compositionupdate"; -export const eventContextMenu: string = "contextmenu"; -export const eventCopy: string = "copy"; -export const eventCut: string = "cut"; -export const eventDblClick: string = "dblclick"; -export const eventDeviceChange: string = "devicechange"; -export const eventDeviceMotion: string = "devicemotion"; -export const eventDeviceOrientation: string = "deviceorientation"; -export const eventDischargingTimeChange: string = "dischargingtimechange"; -export const eventDrag: string = "drag"; -export const eventDragEnd: string = "dragend"; -export const eventDragEnter: string = "dragenter"; -export const eventDragLeave: string = "dragleave"; -export const eventDragOver: string = "dragover"; -export const eventDragStart: string = "dragstart"; -export const eventDrop: string = "drop"; -export const eventDurationChange: string = "durationchange"; -export const eventEmptied: string = "emptied"; -export const eventEnded: string = "ended"; -export const eventEndEvent: string = "endevent"; -export const eventError: string = "error"; -export const eventFocus: string = "focus"; -export const eventFocusIn: string = "focusin"; -export const eventFocusOut: string = "focusout"; -export const eventFullScreenChange: string = "fullscreenchange"; -export const eventFullScreenError: string = "fullscreenerror"; -export const eventGamePadConnected: string = "gamepadconnected"; -export const eventGamePadDisconnected: string = "gamepaddisconnected"; -export const eventGotPointerCapture: string = "gotpointercapture"; -export const eventHashChange: string = "hashchange"; -export const eventLostPointerCapture: string = "lostpointercapture"; -export const eventInput: string = "input"; -export const eventInvalid: string = "invalid"; -export const eventKeyDown: string = "keydown"; -export const eventKeyUp: string = "keyup"; -export const eventLevelChange: string = "levelchange"; -export const eventLoad: string = "load"; -export const eventLoadedData: string = "loadeddata"; -export const eventLoadedMetaData: string = "loadedmetadata"; -export const eventLoadEnd: string = "loadend"; -export const eventLoadStart: string = "loadstart"; -export const eventMessage: string = "message"; -export const eventMessageError: string = "messageerror"; -export const eventMouseDown: string = "mousedown"; -export const eventMouseEnter: string = "mouseenter"; -export const eventMouseLeave: string = "mouseleave"; -export const eventMouseMove: string = "mousemove"; -export const eventMouseOut: string = "mouseout"; -export const eventMouseOver: string = "mouseover"; -export const eventMouseUp: string = "mouseup"; -export const eventNotificationClick: string = "notificationclick"; -export const eventOffline: string = "offline"; -export const eventOnline: string = "online"; -export const eventOpen: string = "open"; -export const eventOrientationChange: string = "orientationchange"; -export const eventPageHide: string = "pagehide"; -export const eventPageShow: string = "pageshow"; -export const eventPaste: string = "paste"; -export const eventPause: string = "pause"; -export const eventPointerCancel: string = "pointercancel"; -export const eventPointerDown: string = "pointerdown"; -export const eventPointerEnter: string = "pointerenter"; -export const eventPointerLeave: string = "pointerleave"; -export const eventPointerLockChange: string = "pointerlockchange"; -export const eventPointerLockError: string = "pointerlockerror"; -export const eventPointerMove: string = "pointermove"; -export const eventPointerOut: string = "pointerout"; -export const eventPointerOver: string = "pointerover"; -export const eventPointerUp: string = "pointerup"; -export const eventPlay: string = "play"; -export const eventPlaying: string = "playing"; -export const eventPopState: string = "popstate"; -export const eventProgress: string = "progress"; -export const eventPush: string = "push"; -export const eventPushSubscriptionChange: string = "pushsubscriptionchange"; -export const eventRateChange: string = "ratechange"; -export const eventReadyStateChange: string = "readystatechange"; -export const eventRepeatEvent: string = "repeatevent"; -export const eventReset: string = "reset"; -export const eventResize: string = "resize"; -export const eventResourceTimingBufferFull: string = "resourcetimingbufferfull"; -export const eventScroll: string = "scroll"; -export const eventSeeked: string = "seeked"; -export const eventSeeking: string = "seeking"; -export const eventSelect: string = "select"; -export const eventShow: string = "show"; -export const eventSlotChange: string = "slotchange"; -export const eventStalled: string = "stalled"; -export const eventStart: string = "start"; -export const eventStorage: string = "storage"; -export const eventSubmit: string = "submit"; -export const eventSuccess: string = "success"; -export const eventSuspend: string = "suspend"; -export const eventSVGAbort: string = "SVGAbort"; -export const eventSVGError: string = "SVGError"; -export const eventSVGLoad: string = "SVGLoad"; -export const eventSVGResize: string = "SVGResize"; -export const eventSVGScroll: string = "SVGScroll"; -export const eventSVGUnload: string = "SVGUnload"; -export const eventSVGZoom: string = "SVGZoom"; -export const eventTimeOut: string = "timeout"; -export const eventTimeUpdate: string = "timeupdate"; -export const eventTouchCancel: string = "touchcancel"; -export const eventTouchEnd: string = "touchend"; -export const eventTouchMove: string = "touchmove"; -export const eventTouchStart: string = "touchstart"; -export const eventTransitionEnd: string = "transitionend"; -export const eventUnload: string = "unload"; -export const eventUpgradeNeeded: string = "upgradeneeded"; -export const eventUserProximity: string = "userproximity"; -export const eventVersionChange: string = "versionchange"; -export const eventVisibilityChange: string = "visibilitychange"; -export const eventVolumeChange: string = "volumechange"; -export const eventWaiting: string = "waiting"; -export const eventWheel: string = "wheel"; diff --git a/packages/utilities/fast-web-utilities/src/html.spec.ts b/packages/utilities/fast-web-utilities/src/html.spec.ts deleted file mode 100644 index 08325ec9208..00000000000 --- a/packages/utilities/fast-web-utilities/src/html.spec.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { expect } from "chai"; -import { convertStylePropertyPixelsToNumber, getClientRectWithMargin } from "./html.js"; - -describe("getClientRectWithMargin", () => { - const mockWidth: number = 120; - const mockHeight: number = 120; - const mockRect: DOMRect = { - width: mockWidth, - height: mockHeight, - top: 0, - left: 0, - bottom: 0, - right: 0, - x: undefined!, - y: undefined!, - toJSON: undefined!, - }; - - beforeEach(() => { - Element.prototype.getBoundingClientRect = (): any => { - return mockRect; - }; - }); - - it("should correctly manage undefined and null values", () => { - expect(() => getClientRectWithMargin(null)).not.to.throw(); - expect(() => getClientRectWithMargin(undefined)).not.to.throw(); - }); - - it("should correctly return computed client rect with margin values", () => { - document.body.innerHTML = ` -
- `; - - const element: HTMLElement | undefined | null = - document.getElementById("element"); - const expectedWidth: number = mockWidth + 40; - const expectedHeight: number = mockHeight + 20; - - const expectedRect: DOMRect = Object.assign({}, mockRect, { - width: expectedWidth, - height: expectedHeight, - }); - /* eslint-disable @typescript-eslint/no-non-null-assertion */ - expect(getClientRectWithMargin(element)!.bottom).to.equal(expectedRect.bottom); - expect(getClientRectWithMargin(element)!.height).to.equal(expectedRect.height); - expect(getClientRectWithMargin(element)!.left).to.equal(expectedRect.left); - expect(getClientRectWithMargin(element)!.right).to.equal(expectedRect.right); - expect(getClientRectWithMargin(element)!.top).to.equal(expectedRect.top); - expect(getClientRectWithMargin(element)!.width).to.equal(expectedRect.width); - /* eslint-enable @typescript-eslint/no-non-null-assertion */ - }); -}); - -describe("convertStylePropertyPixelsToNumber", () => { - it("should correctly manage undefined and null values", () => { - expect(() => convertStylePropertyPixelsToNumber(null, null)).not.to.throw(); - expect(() => convertStylePropertyPixelsToNumber(undefined, null)).not.to.throw(); - expect(() => - convertStylePropertyPixelsToNumber(undefined, undefined) - ).not.to.throw(); - }); - - it("should correctly convert an element's computed style property pixel value and return a number", () => { - document.body.innerHTML = ` -
- `; - /* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */ - const element: HTMLElement = document.getElementById("element")!; - - expect( - convertStylePropertyPixelsToNumber( - window.getComputedStyle(element), - "margin-top" - ) - ).to.equal(20); - expect( - convertStylePropertyPixelsToNumber( - window.getComputedStyle(element), - "margin-bottom" - ) - ).to.equal(12); - expect( - convertStylePropertyPixelsToNumber( - window.getComputedStyle(element), - "margin-left" - ) - ).to.equal(8); - expect( - convertStylePropertyPixelsToNumber( - window.getComputedStyle(element), - "margin-right" - ) - ).to.equal(5); - }); -}); diff --git a/packages/utilities/fast-web-utilities/src/html.ts b/packages/utilities/fast-web-utilities/src/html.ts deleted file mode 100644 index 7506563c864..00000000000 --- a/packages/utilities/fast-web-utilities/src/html.ts +++ /dev/null @@ -1,53 +0,0 @@ -export interface ClientRectWithMargin { - width: number; - height: number; - top: number; - bottom: number; - left: number; - right: number; -} - -export function convertStylePropertyPixelsToNumber( - computedStyle: CSSStyleDeclaration | null | undefined, - property: string | null | undefined -): number | void { - if (!computedStyle || !property) { - return; - } - - return parseInt( - computedStyle - .getPropertyValue(property) - .substring(0, computedStyle.getPropertyValue(property).length - 2), - 10 - ); -} - -/** - * Gets the client bounding rectangle including any margins of an element. - */ -export function getClientRectWithMargin( - element: HTMLElement | null | undefined -): ClientRectWithMargin | undefined { - if (!element) { - return; - } - - const rect: DOMRect = element.getBoundingClientRect(); - const style: CSSStyleDeclaration = window.getComputedStyle(element, null); - const clone: ClientRectWithMargin = { - width: rect.width, - height: rect.height, - top: rect.top, - bottom: rect.bottom, - left: rect.left, - right: rect.right, - }; - - clone.width += convertStylePropertyPixelsToNumber(style, "margin-left") as number; - clone.width += convertStylePropertyPixelsToNumber(style, "margin-right") as number; - clone.height += convertStylePropertyPixelsToNumber(style, "margin-top") as number; - clone.height += convertStylePropertyPixelsToNumber(style, "margin-bottom") as number; - - return clone; -} diff --git a/packages/utilities/fast-web-utilities/src/index.ts b/packages/utilities/fast-web-utilities/src/index.ts deleted file mode 100644 index ae024caa7d4..00000000000 --- a/packages/utilities/fast-web-utilities/src/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -export * from "./aria.js"; -export * from "./array.js"; -export * from "./class-names.js"; -export * from "./dom.js"; -export * from "./events.js"; -export * from "./html.js"; -export * from "./key-codes.js"; -export * from "./localization.js"; -export * from "./numbers.js"; -export * from "./strings.js"; -export * from "./query.js"; -export * from "./rtl-scroll-converter.js"; -export * from "./system-colors.js"; diff --git a/packages/utilities/fast-web-utilities/src/key-codes.ts b/packages/utilities/fast-web-utilities/src/key-codes.ts deleted file mode 100644 index 21ccbf8a417..00000000000 --- a/packages/utilities/fast-web-utilities/src/key-codes.ts +++ /dev/null @@ -1,49 +0,0 @@ -/** - * String values for use with KeyboardEvent.key - */ -export const keyAlt: "Alt" = "Alt" as const; -export const keyAltGraph: "AltGraph" = "AltGraph" as const; -export const keyCapsLock: "CapsLock" = "CapsLock" as const; -export const keyControl: "Control" = "Control" as const; -export const keyArrowDown: "ArrowDown" = "ArrowDown" as const; -export const keyArrowLeft: "ArrowLeft" = "ArrowLeft" as const; -export const keyArrowRight: "ArrowRight" = "ArrowRight" as const; -export const keyArrowUp: "ArrowUp" = "ArrowUp" as const; -export const keyBackspace: "Backspace" = "Backspace" as const; -export const keyDelete: "Delete" = "Delete" as const; -export const keyEnd: "End" = "End" as const; -export const keyEnter: "Enter" = "Enter" as const; -export const keyEscape: "Escape" = "Escape" as const; -export const keyHome: "Home" = "Home" as const; -export const keyFunction: "Fn" = "Fn" as const; -export const keyFunctionLock: "FnLock" = "FnLock" as const; -export const keyFunction2: "F2" = "F2" as const; -export const keyFunction3: "F3" = "F3" as const; -export const keyFunction4: "F4" = "F4" as const; -export const keyFunction5: "F5" = "F5" as const; -export const keyFunction6: "F6" = "F6" as const; -export const keyFunction7: "F7" = "F7" as const; -export const keyFunction8: "F8" = "F8" as const; -export const keyFunction9: "F9" = "F9" as const; -export const keyFunction10: "F10" = "F10" as const; -export const keyFunction11: "F11" = "F11" as const; -export const keyFunction12: "F12" = "F12" as const; -export const keyFunction13: "F13" = "F13" as const; -export const keyFunction14: "F14" = "F14" as const; -export const keyFunction15: "F15" = "F15" as const; -export const keyNumLock: "NumLock" = "NumLock" as const; -export const keyPageDown: "PageDown" = "PageDown" as const; -export const keyPageUp: "PageUp" = "PageUp" as const; -export const keyScrollLock: "ScrollLock" = "ScrollLock" as const; -export const keyShift: "Shift" = "Shift" as const; -export const keySpace: " " = " " as const; -export const keyTab: "Tab" = "Tab" as const; - -export const ArrowKeys = { - ArrowDown: keyArrowDown, - ArrowLeft: keyArrowLeft, - ArrowRight: keyArrowRight, - ArrowUp: keyArrowUp, -} as const; - -export type ArrowKeys = (typeof ArrowKeys)[keyof typeof ArrowKeys]; diff --git a/packages/utilities/fast-web-utilities/src/localization.ts b/packages/utilities/fast-web-utilities/src/localization.ts deleted file mode 100644 index 50ac142e038..00000000000 --- a/packages/utilities/fast-web-utilities/src/localization.ts +++ /dev/null @@ -1,7 +0,0 @@ -/** - * Expose ltr and rtl strings - */ -export enum Direction { - ltr = "ltr", - rtl = "rtl", -} diff --git a/packages/utilities/fast-web-utilities/src/numbers.spec.ts b/packages/utilities/fast-web-utilities/src/numbers.spec.ts deleted file mode 100644 index ff58089d621..00000000000 --- a/packages/utilities/fast-web-utilities/src/numbers.spec.ts +++ /dev/null @@ -1,120 +0,0 @@ -import { expect } from "chai"; -import { inRange, limit, wrapInBounds } from "./numbers.js"; - -describe("wrapInBounds", () => { - it("should not throw if any parameters are null", () => { - expect(() => { - wrapInBounds(null!, null!, null!); - }).not.to.throw(); - expect(() => { - wrapInBounds(1, null!, null!); - }).not.to.throw(); - expect(() => { - wrapInBounds(1, 2, 3); - }).not.to.throw(); - expect(() => { - wrapInBounds(1, null!, 3); - }).not.to.throw(); - expect(() => { - wrapInBounds(1, 2, null!); - }).not.to.throw(); - }); - - it("should return `min` if `value` is greater than `max`", () => { - expect(wrapInBounds(0, 10, 11)).to.equal(0); - expect(wrapInBounds(-10, 0, 1)).to.equal(-10); - expect(wrapInBounds(-10, 10, 11)).to.equal(-10); - expect(wrapInBounds(10, 20, 30)).to.equal(10); - }); - - it("should return `max` if `value` is less than `min`", () => { - expect(wrapInBounds(0, 10, -10)).to.equal(10); - expect(wrapInBounds(-10, 0, -11)).to.equal(0); - expect(wrapInBounds(-20, -10, -30)).to.equal(-10); - expect(wrapInBounds(-10, 10, -11)).to.equal(10); - }); - - it("should return the correct value if both min and max are the same", () => { - expect(wrapInBounds(0, 0, -1)).to.equal(0); - expect(wrapInBounds(0, 0, 1)).to.equal(0); - }); -}); - -describe("limit", () => { - it("should not throw if any parameters are null", () => { - expect(() => { - limit(null!, null!, null!); - }).not.to.throw(); - expect(() => { - limit(0, null!, null!); - }).not.to.throw(); - expect(() => { - limit(0, null!, 1); - }).not.to.throw(); - expect(() => { - limit(0, 10, null!); - }).not.to.throw(); - }); - - it("should return `min` if `value` is equal to `min`", () => { - expect(limit(0, 10, 0)).to.equal(0); - }); - - it("should return `min` if `value` is greater than `min`", () => { - expect(limit(10, 15, -1)).to.equal(10); - }); - - it("should return `max` if `value` is equal to `max`", () => { - expect(limit(0, 10, 10)).to.equal(10); - }); - - it("should return `max` if `value` is greater than `max`", () => { - expect(limit(0, 10, 11)).to.equal(10); - }); - - it("should return the value if `value` is not less min or greater than max", () => { - expect(limit(0, 10, 5)).to.equal(5); - }); -}); - -describe("inRange", () => { - it("should not throw if any parameters are null", () => { - expect(() => { - inRange(null!, null!, null!); - }).not.to.throw(); - expect(() => { - inRange(0, null!, null!); - }).not.to.throw(); - expect(() => { - inRange(0, null!, 1); - }).not.to.throw(); - expect(() => { - inRange(0, 10, null!); - }).not.to.throw(); - }); - - it("should return `true` if `value` is within range of `min` and `max`", () => { - expect(inRange(10, 0, 20)).to.be.true; - expect(inRange(10, 20)).to.be.true; - }); - - it("should return `false` when `value` is less than `min` and `max`", () => { - expect(inRange(10, 20, 30)).to.be.false; - }); - - it("should return `false` when `value` is greater than `min` and `max`", () => { - expect(inRange(10, 0, 5)).to.be.false; - }); - - it("should return `false` when `value` is equal to `max`", () => { - expect(inRange(10, 0, 10)).to.be.false; - }); - - it("should return `true` when `value` is less than `min` and `max` is omitted", () => { - expect(inRange(10, 20)).to.be.true; - }); - - it("should return `false` when `value` is less than 0 and `max` is omitted", () => { - expect(inRange(-10, 20)).to.be.false; - }); -}); diff --git a/packages/utilities/fast-web-utilities/src/numbers.ts b/packages/utilities/fast-web-utilities/src/numbers.ts deleted file mode 100644 index 3f62b1b16e9..00000000000 --- a/packages/utilities/fast-web-utilities/src/numbers.ts +++ /dev/null @@ -1,34 +0,0 @@ -/** - * This method keeps a given value within the bounds of a min and max value. If the value - * is larger than the max, the minimum value will be returned. If the value is smaller than the minimum, - * the maximum will be returned. Otherwise, the value is returned un-changed. - */ -export function wrapInBounds(min: number, max: number, value: number): number { - if (value < min) { - return max; - } else if (value > max) { - return min; - } - - return value; -} - -/** - * Ensures that a value is between a min and max value. If value is lower than min, min will be returned. - * If value is greater than max, max will be returned. - */ -export function limit(min: number, max: number, value: number): number { - return Math.min(Math.max(value, min), max); -} - -/** - * Determines if a number value is within a specified range. - * - * @param value - the value to check - * @param min - the range start - * @param max - the range end - */ -export function inRange(value: number, min: number, max: number = 0): boolean { - [min, max] = [min, max].sort((a, b) => a - b); - return min <= value && value < max; -} diff --git a/packages/utilities/fast-web-utilities/src/query.spec.ts b/packages/utilities/fast-web-utilities/src/query.spec.ts deleted file mode 100644 index 0a2c38dcd23..00000000000 --- a/packages/utilities/fast-web-utilities/src/query.spec.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { expect } from "chai"; -import { parseQueryStringParams } from "./query.js"; - -describe("parseQueryStringParams", (): void => { - it("basic query string", (): void => { - const params: Map = parseQueryStringParams( - "www.microsoft.com?a=12345&b=qwerty" - ); - - expect(params.size).to.equal(2); - expect(params.get("a")).to.equal("12345"); - expect(params.get("b")).to.equal("qwerty"); - }); - - it("query string not part of a full url", (): void => { - const params: Map = parseQueryStringParams("a=12345&b=qwerty"); - - expect(params.size).to.equal(2); - expect(params.get("a")).to.equal("12345"); - expect(params.get("b")).to.equal("qwerty"); - }); - - it("query string with encoding", (): void => { - const params: Map = parseQueryStringParams( - "www.microsoft.com?a=CHAPTER%201.%20Loomings.%20Call%20me%20Ishmael.%20Some%20years%20ago%E2%80%94never%20mind%20how%20long%20precisely%E2%80%94having%20little%20or%20no%20money%20in%20my%20purse%2C%20and%20nothing%20particular%20to%20interest%20me%20on%20shore%2C%20I%20thought%20I%20would%20sail%20about%20a%20little%20and%20see%20the%20watery%20part%20of%20the%20world.%20It%20is%20a%20way%20I%20have%20of%20driving%20off%20the%20spleen%20and%20regulating%20the%20circulation.%20Whenever%20I%20find%20myself%20growing%20grim%20about%20the%20mouth%3B%20whenever%20it%20is%20a%20damp%2C%20drizzly%20November%20in%20my%20soul%3B%20whenever%20I%20find%20myself%20involuntarily%20pausing%20before%20coffin%20warehouses%2C%20and%20bringing%20up%20the%20rear%20of%20every%20funeral%20I%20meet%3B%20and%20especially%20whenever%20my%20hypos%20get%20such%20an%20upper%20hand%20of%20me%2C%20that%20it%20requires%20a%20strong%20moral%20principle%20to%20prevent%20me%20from%20deliberately%20stepping%20into%20the%20street%2C%20and%20methodically%20knocking%20people%E2%80%99s%20hats%20off%E2%80%94then%2C%20I%20account%20it%20high%20time%20to%20get%20to%20sea%20as%20soon%20as%20I%20can.%20This%20is%20my%20substitute%20for%20pistol%20and%20ball.%20With%20a%20philosophical%20flourish%20Cato%20throws%20himself%20upon%20his%20sword%3B%20I%20quietly%20take%20to%20the%20ship.%20There%20is%20nothing%20surprising%20in%20this.%20If%20they%20but%20knew%20it%2C%20almost%20all%20men%20in%20their%20degree%2C%20some%20time%20or%20other%2C%20cherish%20very%20nearly%20the%20same%20feelings%20towards%20the%20ocean%20with%20me." - ); - - expect(params.size).to.equal(1); - expect(params.get("a")).to.equal( - "CHAPTER 1. Loomings. Call me Ishmael. Some years ago—never mind how long precisely—having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world. It is a way I have of driving off the spleen and regulating the circulation. Whenever I find myself growing grim about the mouth; whenever it is a damp, drizzly November in my soul; whenever I find myself involuntarily pausing before coffin warehouses, and bringing up the rear of every funeral I meet; and especially whenever my hypos get such an upper hand of me, that it requires a strong moral principle to prevent me from deliberately stepping into the street, and methodically knocking people’s hats off—then, I account it high time to get to sea as soon as I can. This is my substitute for pistol and ball. With a philosophical flourish Cato throws himself upon his sword; I quietly take to the ship. There is nothing surprising in this. If they but knew it, almost all men in their degree, some time or other, cherish very nearly the same feelings towards the ocean with me." - ); - }); - - it("undefined or empty input should return an empty Map", (): void => { - const params1: Map = parseQueryStringParams(""); - expect(params1.size).to.equal(0); - const params2: Map = parseQueryStringParams(undefined!); - expect(params2.size).to.equal(0); - }); - - it("gibberish input should return an empty Map", (): void => { - const params: Map = parseQueryStringParams( - "qwertyuiopasdfghjklzxcvbnm" - ); - - expect(params.size).to.equal(0); - }); -}); diff --git a/packages/utilities/fast-web-utilities/src/query.ts b/packages/utilities/fast-web-utilities/src/query.ts deleted file mode 100644 index d1e99ac5ba5..00000000000 --- a/packages/utilities/fast-web-utilities/src/query.ts +++ /dev/null @@ -1,28 +0,0 @@ -/** - * @param input Can be in the form ANYTHING?a=1&b=2&c=3 ... or just a=1&b=2&c=3 ... - * all query string keys and values will be run through decodeURIComponent - */ -export function parseQueryStringParams(input: string): Map { - const retVal: Map = new Map(); - if (typeof input !== "string" || input.length <= 0) { - return retVal; - } - const splitLocation: string[] = input.split("?"); - let rawQuery: string; - if (splitLocation.length === 1) { - rawQuery = splitLocation[0]; - } else { - rawQuery = splitLocation[1]; - } - const querySegments: string[] = rawQuery.split("&"); - for (const querySegment of querySegments) { - const paramSegments: string[] = querySegment.split("="); - if (paramSegments.length === 2) { - retVal.set( - decodeURIComponent(paramSegments[0]), - decodeURIComponent(paramSegments[1]) - ); - } - } - return retVal; -} diff --git a/packages/utilities/fast-web-utilities/src/rtl-scroll-converter.spec.ts b/packages/utilities/fast-web-utilities/src/rtl-scroll-converter.spec.ts deleted file mode 100644 index 3402e0bd9a9..00000000000 --- a/packages/utilities/fast-web-utilities/src/rtl-scroll-converter.spec.ts +++ /dev/null @@ -1,341 +0,0 @@ -import { expect } from "chai"; -import { RtlScrollConverter } from "./rtl-scroll-converter.js"; -import { Direction } from "./localization.js"; - -function getDummyDiv(): HTMLDivElement { - const dummy: HTMLDivElement = document.createElement("div"); - dummy.appendChild(document.createTextNode("ABCD")); - dummy.dir = "rtl"; - dummy.style.fontSize = "14px"; - dummy.style.width = "4px"; - dummy.style.height = "1px"; - dummy.style.position = "absolute"; - dummy.style.top = "-1000px"; - dummy.style.overflow = "scroll"; - return dummy; -} - -describe("RtlScrollConverter", (): void => { - it("should not throw on getter", () => { - const testElement: HTMLDivElement = getDummyDiv(); - - expect(() => { - RtlScrollConverter.getScrollLeft(testElement, Direction.ltr); - }).not.to.throw(); - }); - - it("should not throw on setter", () => { - const testElement: HTMLDivElement = getDummyDiv(); - - expect(() => { - RtlScrollConverter.setScrollLeft(testElement, 0, Direction.ltr); - }).not.to.throw(); - }); - - // note: this test must happen before any rtl calls to getScrollLeft/setScrollLeft in this test suite - it("getter and setter start as referencing initial function", () => { - expect(RtlScrollConverter["getRtlScrollLeftConverter"]).to.equal( - RtlScrollConverter["initialGetRtlScrollConverter"] - ); - expect(RtlScrollConverter["setRtlScrollLeftConverter"]).to.equal( - RtlScrollConverter["initialSetRtlScrollConverter"] - ); - }); - - it("calling getter with inital function set applies converters", () => { - const testElement: HTMLDivElement = getDummyDiv(); - - RtlScrollConverter["getRtlScrollLeftConverter"] = - RtlScrollConverter["initialGetRtlScrollConverter"]; - RtlScrollConverter["setRtlScrollLeftConverter"] = - RtlScrollConverter["initialSetRtlScrollConverter"]; - - expect(RtlScrollConverter["getRtlScrollLeftConverter"]).to.equal( - RtlScrollConverter["initialGetRtlScrollConverter"] - ); - expect(RtlScrollConverter["setRtlScrollLeftConverter"]).to.equal( - RtlScrollConverter["initialSetRtlScrollConverter"] - ); - - RtlScrollConverter.getScrollLeft(testElement, Direction.rtl); - - expect(RtlScrollConverter["getRtlScrollLeftConverter"]).to.equal( - RtlScrollConverter["directGetRtlScrollConverter"] - ); - expect(RtlScrollConverter["setRtlScrollLeftConverter"]).to.equal( - RtlScrollConverter["directSetRtlScrollConverter"] - ); - }); - - it("calling setter with inital function set applies converters", () => { - const testElement: HTMLDivElement = getDummyDiv(); - - RtlScrollConverter["getRtlScrollLeftConverter"] = - RtlScrollConverter["initialGetRtlScrollConverter"]; - RtlScrollConverter["setRtlScrollLeftConverter"] = - RtlScrollConverter["initialSetRtlScrollConverter"]; - - expect(RtlScrollConverter["getRtlScrollLeftConverter"]).to.equal( - RtlScrollConverter["initialGetRtlScrollConverter"] - ); - expect(RtlScrollConverter["setRtlScrollLeftConverter"]).to.equal( - RtlScrollConverter["initialSetRtlScrollConverter"] - ); - - RtlScrollConverter.setScrollLeft(testElement, -1, Direction.rtl); - - expect(RtlScrollConverter["getRtlScrollLeftConverter"]).to.equal( - RtlScrollConverter["directGetRtlScrollConverter"] - ); - expect(RtlScrollConverter["setRtlScrollLeftConverter"]).to.equal( - RtlScrollConverter["directSetRtlScrollConverter"] - ); - }); - - it("directGetRtlScrollConverter returns correct value", () => { - const testElement: HTMLDivElement = getDummyDiv(); - document.body.appendChild(testElement); - testElement.scrollLeft = -1; - - expect(RtlScrollConverter["directGetRtlScrollConverter"](testElement)).to.equal( - -1 - ); - }); - - it("invertedGetRtlScrollConverter returns a value <= 0", () => { - const testElement: HTMLDivElement = getDummyDiv(); - document.body.appendChild(testElement); - testElement.scrollLeft = 1; - - expect( - RtlScrollConverter["invertedGetRtlScrollConverter"](testElement) - ).to.be.lessThanOrEqual(0); - }); - - it("reverseGetRtlScrollConverter returns correct value", () => { - const testElement: HTMLDivElement = getDummyDiv(); - testElement.scrollLeft = 0; - document.body.appendChild(testElement); - - expect(RtlScrollConverter["reverseGetRtlScrollConverter"](testElement)).to.equal( - testElement.scrollLeft - (testElement.scrollWidth - testElement.clientWidth) - ); - - testElement.scrollLeft = -1; - - expect(RtlScrollConverter["reverseGetRtlScrollConverter"](testElement)).to.equal( - -1 - (testElement.scrollWidth - testElement.clientWidth) - ); - }); - - it("directSetRtlScrollConverter applies correct value", () => { - const testElement: HTMLDivElement = { scrollLeft: 0 } as HTMLDivElement; - RtlScrollConverter["directSetRtlScrollConverter"](testElement, -100); - expect(testElement.scrollLeft).to.equal(-100); - }); - - it("invertedSetRtlScrollConverter applies correct value", () => { - const testElement: HTMLDivElement = { scrollLeft: 0 } as HTMLDivElement; - RtlScrollConverter["invertedSetRtlScrollConverter"](testElement, -100); - expect(testElement.scrollLeft).to.equal(100); - }); - - it("reverseSetRtlScrollConverter applies correct value", () => { - const testElement: HTMLDivElement = { - scrollLeft: 0, - clientWidth: 100, - scrollWidth: 200, - } as HTMLDivElement; - RtlScrollConverter["reverseSetRtlScrollConverter"](testElement, -100); - expect(testElement.scrollLeft).to.equal(0); - }); - - it("getter should not adjust value in ltr mode", () => { - const testElement: HTMLDivElement = { - scrollLeft: -200, - } as HTMLDivElement; - - expect(RtlScrollConverter.getScrollLeft(testElement, Direction.ltr)).to.equal( - -200 - ); - }); - - it("setter should not adjust value in ltr mode", () => { - const testElement: HTMLDivElement = { - scrollLeft: 0, - } as HTMLDivElement; - - RtlScrollConverter.setScrollLeft(testElement, -200, Direction.ltr); - expect(testElement.scrollLeft).to.equal(-200); - }); - - it("generated test element has correct attributes", () => { - const testElement: HTMLDivElement = RtlScrollConverter["getTestElement"](); - - expect(testElement.dir).to.equal("rtl"); - expect(testElement.style.fontSize).to.equal("14px"); - expect(testElement.style.width).to.equal("4px"); - expect(testElement.style.height).to.equal("1px"); - expect(testElement.style.position).to.equal("absolute"); - expect(testElement.style.top).to.equal("-1000px"); - expect(testElement.style.overflow).to.equal("scroll"); - }); - - it("applyDirectScrollConverters applies correct converters", () => { - RtlScrollConverter["getRtlScrollLeftConverter"] = null!; - RtlScrollConverter["setRtlScrollLeftConverter"] = null!; - - expect(RtlScrollConverter["getRtlScrollLeftConverter"]).not.to.equal( - RtlScrollConverter["directGetRtlScrollConverter"] - ); - expect(RtlScrollConverter["setRtlScrollLeftConverter"]).not.to.equal( - RtlScrollConverter["directSetRtlScrollConverter"] - ); - - RtlScrollConverter["applyDirectScrollConverters"](); - - expect(RtlScrollConverter["getRtlScrollLeftConverter"]).to.equal( - RtlScrollConverter["directGetRtlScrollConverter"] - ); - expect(RtlScrollConverter["setRtlScrollLeftConverter"]).to.equal( - RtlScrollConverter["directSetRtlScrollConverter"] - ); - }); - - it("applyInvertedScrollConverters applies correct converters", () => { - RtlScrollConverter["getRtlScrollLeftConverter"] = null!; - RtlScrollConverter["setRtlScrollLeftConverter"] = null!; - - expect(RtlScrollConverter["getRtlScrollLeftConverter"]).not.to.equal( - RtlScrollConverter["invertedGetRtlScrollConverter"] - ); - expect(RtlScrollConverter["setRtlScrollLeftConverter"]).not.to.equal( - RtlScrollConverter["invertedSetRtlScrollConverter"] - ); - - RtlScrollConverter["applyInvertedScrollConverters"](); - - expect(RtlScrollConverter["getRtlScrollLeftConverter"]).to.equal( - RtlScrollConverter["invertedGetRtlScrollConverter"] - ); - expect(RtlScrollConverter["setRtlScrollLeftConverter"]).to.equal( - RtlScrollConverter["invertedSetRtlScrollConverter"] - ); - }); - - it("applyReverseScrollConverters applies correct converters", () => { - RtlScrollConverter["getRtlScrollLeftConverter"] = null!; - RtlScrollConverter["setRtlScrollLeftConverter"] = null!; - - expect(RtlScrollConverter["getRtlScrollLeftConverter"]).not.to.equal( - RtlScrollConverter["reverseGetRtlScrollConverter"] - ); - expect(RtlScrollConverter["setRtlScrollLeftConverter"]).not.to.equal( - RtlScrollConverter["reverseSetRtlScrollConverter"] - ); - - RtlScrollConverter["applyReverseScrollConverters"](); - - expect(RtlScrollConverter["getRtlScrollLeftConverter"]).to.equal( - RtlScrollConverter["reverseGetRtlScrollConverter"] - ); - expect(RtlScrollConverter["setRtlScrollLeftConverter"]).to.equal( - RtlScrollConverter["reverseSetRtlScrollConverter"] - ); - }); - - it("isReverse returns true if provided with an element with a positive scroll value", () => { - const testElement: HTMLDivElement = { - scrollLeft: 1, - } as HTMLDivElement; - - expect(RtlScrollConverter["isReverse"](testElement)).to.equal(true); - }); - - it("isReverse returns false if provided with an element with a 0 scroll value", () => { - const testElement: HTMLDivElement = { - scrollLeft: 0, - } as HTMLDivElement; - - expect(RtlScrollConverter["isReverse"](testElement)).to.equal(false); - }); - - it("isReverse returns false if provided with an element with a negative scroll value", () => { - const testElement: HTMLDivElement = { - scrollLeft: -1, - } as HTMLDivElement; - - expect(RtlScrollConverter["isReverse"](testElement)).to.equal(false); - }); - - it("isDirect returns true if provided with an element that accepts a negative scroll value", () => { - const testElement: HTMLDivElement = { - scrollLeft: 0, - } as HTMLDivElement; - - expect(RtlScrollConverter["isDirect"](testElement)).to.equal(true); - }); - - it("checkForScrollType applies reverse converters if provided with an element with a positive scroll value", () => { - const testElement: HTMLDivElement = { - scrollLeft: 1, - } as HTMLDivElement; - - RtlScrollConverter["getRtlScrollLeftConverter"] = null!; - RtlScrollConverter["setRtlScrollLeftConverter"] = null!; - - RtlScrollConverter["checkForScrollType"](testElement); - - expect(RtlScrollConverter["getRtlScrollLeftConverter"]).to.equal( - RtlScrollConverter["reverseGetRtlScrollConverter"] - ); - expect(RtlScrollConverter["setRtlScrollLeftConverter"]).to.equal( - RtlScrollConverter["reverseSetRtlScrollConverter"] - ); - }); - - it("checkForScrollType applies direct converters if provided with an element with a scroll value of 0 that uses negative values", () => { - const testElement: HTMLDivElement = { - scrollLeft: 0, - } as HTMLDivElement; - - RtlScrollConverter["getRtlScrollLeftConverter"] = null!; - RtlScrollConverter["setRtlScrollLeftConverter"] = null!; - - RtlScrollConverter["checkForScrollType"](testElement); - - expect(RtlScrollConverter["getRtlScrollLeftConverter"]).to.equal( - RtlScrollConverter["directGetRtlScrollConverter"] - ); - expect(RtlScrollConverter["setRtlScrollLeftConverter"]).to.equal( - RtlScrollConverter["directSetRtlScrollConverter"] - ); - }); - - it("checkForScrollType applies inverted converters if provided with a scroll value of 0 that uses positive values", () => { - const testElement: HTMLDivElement = { - scrollLeft: 0, - } as HTMLDivElement; - - Object.defineProperty(testElement, "scrollLeft", { - get(): number { - return this._value; - }, - set(newValue: number): void { - this._value = Math.abs(newValue); - }, - }); - - RtlScrollConverter["getRtlScrollLeftConverter"] = null!; - RtlScrollConverter["setRtlScrollLeftConverter"] = null!; - - RtlScrollConverter["checkForScrollType"](testElement); - - expect(RtlScrollConverter["getRtlScrollLeftConverter"]).to.equal( - RtlScrollConverter["invertedGetRtlScrollConverter"] - ); - expect(RtlScrollConverter["setRtlScrollLeftConverter"]).to.equal( - RtlScrollConverter["invertedSetRtlScrollConverter"] - ); - }); -}); diff --git a/packages/utilities/fast-web-utilities/src/rtl-scroll-converter.ts b/packages/utilities/fast-web-utilities/src/rtl-scroll-converter.ts deleted file mode 100644 index 00add61f2ba..00000000000 --- a/packages/utilities/fast-web-utilities/src/rtl-scroll-converter.ts +++ /dev/null @@ -1,233 +0,0 @@ -import { canUseDOM } from "exenv-es6"; -import { Direction } from "./localization.js"; - -/** - * Standardize left scroll conversion when direction is rtl - * inspired by - * https://github.com/alitaheri/normalize-scroll-left - */ -export class RtlScrollConverter { - /** - * Gets the scrollLeft value of the provided element - */ - public static getScrollLeft(scrolledElement: Element, direction: Direction): number { - if (direction === Direction.rtl) { - return RtlScrollConverter.getRtlScrollLeftConverter(scrolledElement); - } - return scrolledElement.scrollLeft; - } - - /** - * Sets the scrollLeft value of the provided element - */ - public static setScrollLeft( - scrolledElement: Element, - scrollValue: number, - direction: Direction - ): void { - if (direction === Direction.rtl) { - RtlScrollConverter.setRtlScrollLeftConverter(scrolledElement, scrollValue); - return; - } - scrolledElement.scrollLeft = scrollValue; - } - - /** - * This variable holds the appropriate converter function to get the scrollLeft value - * The functions initially assigned triggers a browser check when called which sets - * the correct converter based on browser and then invokes it - */ - private static getRtlScrollLeftConverter: (scrolledElement: Element) => number = - RtlScrollConverter.initialGetRtlScrollConverter; - - /** - * This variable holds the appropriate converter function to set the scrollLeft value - * The functions initially assigned triggers a browser check when called which sets - * the correct function based on browser and then invokes it - */ - private static setRtlScrollLeftConverter: ( - scrolledElement: Element, - scrollValue: number - ) => void = RtlScrollConverter.initialSetRtlScrollConverter; - - /** - * The initial rtl scroll converter getter function, it calls the browser test to set the correct converter - * functions and then invokes the getter - */ - private static initialGetRtlScrollConverter(scrolledElement: Element): number { - RtlScrollConverter.initializeRtlScrollConverters(); - return RtlScrollConverter.getRtlScrollLeftConverter(scrolledElement); - } - - /** - * The "direct" rtl get scroll converter does not need to tamper with the scrollLeft - * values as the browser is already doing the right thing. Content start = 0 and - * scrolling left goes negative. - */ - private static directGetRtlScrollConverter(scrolledElement: Element): number { - return scrolledElement.scrollLeft; - } - - /** - * The "inverted" get scroll converter is used when the browser reports scroll left - * as a positive maximum scroll value at content start and then goes to zero as content - * is scrolled left - */ - private static invertedGetRtlScrollConverter(scrolledElement: Element): number { - return -Math.abs(scrolledElement.scrollLeft); - } - - /** - * The "reverse" get scroll converter is used when the browser reports scroll left - * as 0 at content start and then goes positive as content is scrolled left - */ - private static reverseGetRtlScrollConverter(scrolledElement: Element): number { - return ( - scrolledElement.scrollLeft - - (scrolledElement.scrollWidth - scrolledElement.clientWidth) - ); - } - - /** - * The initial rtl scroll converter setter function, it calls the browser test to set the correct converter - * functions and then invokes the setter - */ - private static initialSetRtlScrollConverter( - scrolledElement: Element, - newScrollValue: number - ): void { - RtlScrollConverter.initializeRtlScrollConverters(); - RtlScrollConverter.setRtlScrollLeftConverter(scrolledElement, newScrollValue); - } - - /** - * The "direct" rtl set scroll converter does not need to tamper with the scrollLeft - * values as the browser is already doing the right thing. Content start = 0 and - * scrolling left goes negative. - */ - private static directSetRtlScrollConverter( - scrolledElement: Element, - newScrollValue: number - ): void { - scrolledElement.scrollLeft = newScrollValue; - } - - /** - * The "inverted" set scroll converter is used when the browser reports scroll left - * as a positive maximum scroll value at content start and then goes to zero as content - * is scrolled left - */ - private static invertedSetRtlScrollConverter( - scrolledElement: Element, - newScrollValue: number - ): void { - scrolledElement.scrollLeft = Math.abs(newScrollValue); - } - - /** - * The "reverse" set scroll converter is used when the browser reports scroll left - * as 0 at content start and then goes positive as content is scrolled left - */ - private static reverseSetRtlScrollConverter( - scrolledElement: Element, - newScrollValue: number - ): void { - const maxScroll: number = - scrolledElement.scrollWidth - scrolledElement.clientWidth; - scrolledElement.scrollLeft = maxScroll + newScrollValue; - } - - /** - * detects the appropriate rtl scroll converter functions and assigns them - * should only run once - */ - private static initializeRtlScrollConverters(): void { - if (!canUseDOM()) { - RtlScrollConverter.applyDirectScrollConverters(); - return; - } - const testElement: HTMLDivElement = RtlScrollConverter.getTestElement(); - document.body.appendChild(testElement); - - RtlScrollConverter.checkForScrollType(testElement); - - document.body.removeChild(testElement); - } - - /** - * checks the provided test element to determine scroll type - * and apply appropriate converters - */ - private static checkForScrollType(testElement: HTMLDivElement): void { - if (RtlScrollConverter.isReverse(testElement)) { - RtlScrollConverter.applyReverseScrollConverters(); - } else { - if (RtlScrollConverter.isDirect(testElement)) { - RtlScrollConverter.applyDirectScrollConverters(); - } else { - RtlScrollConverter.applyInvertedScrollConverters(); - } - } - } - - /** - * checks test element initial state for rtl "reverse" mode - */ - private static isReverse(testElement: HTMLDivElement): boolean { - return testElement.scrollLeft > 0; - } - - /** - * checks test element for rtl "direct" mode - */ - private static isDirect(testElement: HTMLDivElement): boolean { - testElement.scrollLeft = -1; - return testElement.scrollLeft < 0; - } - - /** - * apply direct scroll conververters - */ - private static applyDirectScrollConverters(): void { - RtlScrollConverter.setRtlScrollLeftConverter = - RtlScrollConverter.directSetRtlScrollConverter; - RtlScrollConverter.getRtlScrollLeftConverter = - RtlScrollConverter.directGetRtlScrollConverter; - } - - /** - * apply inverted scroll conververters - */ - private static applyInvertedScrollConverters(): void { - RtlScrollConverter.setRtlScrollLeftConverter = - RtlScrollConverter.invertedSetRtlScrollConverter; - RtlScrollConverter.getRtlScrollLeftConverter = - RtlScrollConverter.invertedGetRtlScrollConverter; - } - - /** - * apply reverse scroll conververters - */ - private static applyReverseScrollConverters(): void { - RtlScrollConverter.setRtlScrollLeftConverter = - RtlScrollConverter.reverseSetRtlScrollConverter; - RtlScrollConverter.getRtlScrollLeftConverter = - RtlScrollConverter.reverseGetRtlScrollConverter; - } - - /** - * generate a test element for rtl testing - */ - private static getTestElement(): HTMLDivElement { - const testElement: HTMLDivElement = document.createElement("div"); - testElement.appendChild(document.createTextNode("ABCD")); - testElement.dir = "rtl"; - testElement.style.fontSize = "14px"; - testElement.style.width = "4px"; - testElement.style.height = "1px"; - testElement.style.position = "absolute"; - testElement.style.top = "-1000px"; - testElement.style.overflow = "scroll"; - return testElement; - } -} diff --git a/packages/utilities/fast-web-utilities/src/strings.spec.ts b/packages/utilities/fast-web-utilities/src/strings.spec.ts deleted file mode 100644 index f5e80405059..00000000000 --- a/packages/utilities/fast-web-utilities/src/strings.spec.ts +++ /dev/null @@ -1,147 +0,0 @@ -import { expect } from "chai"; -import { - format, - isNullOrWhiteSpace, - pascalCase, - spinalCase, - startsWith, -} from "./strings.js"; - -describe("format", (): void => { - it("should correctly manage undefined by returning an unformatted string", (): void => { - const formatterString: string = "Hello {0} world"; - - expect(format(formatterString, undefined!)).to.equal("Hello world"); - }); - - it("should correctly manage null by returning an unformatted string", (): void => { - const formatterString: string = "Hello {0} world"; - - expect(format(formatterString, null!)).to.equal("Hello world"); - }); - - it("should correctly manage having too many parameters", (): void => { - const formatterString: string = "View {0} {1}"; - - expect(format(formatterString, "page", "five", "now")).to.equal("View page five"); - }); - - it("should correctly manage a formatter with not enough parameters", (): void => { - const formatterString: string = "View {0} {1}"; - - expect(format(formatterString, "page")).to.equal("View page {1}"); - }); - - it("should correctly manage empty strings by returning a formatted string with white space", (): void => { - const formatterString: string = "Hello {0} world"; - - expect(format(formatterString, "")).to.equal("Hello world"); - }); - - it("should correctly manage strings by returning a formatted string", (): void => { - const formatterString: string = "Hello {0} world"; - - expect(format(formatterString, "foo")).to.equal("Hello foo world"); - }); - - it("should correctly manage multiple strings parameters", (): void => { - const formatterString: string = "View {0} {1}"; - - expect(format(formatterString, "page", "five")).to.equal("View page five"); - }); - - it("should correctly manage non-formatted strings by returning the initial string", (): void => { - const formatterString: string = "Hello"; - - expect(format(formatterString, "world")).to.equal("Hello"); - }); - - it("should correctly manage non-formatted strings by returning the initial string", (): void => { - const formatterString: string = "Hello"; - - expect(format(formatterString, "world")).to.equal("Hello"); - }); -}); - -describe("isNullOrWhiteSpace", (): void => { - it("should correctly manage undefined", () => { - expect(isNullOrWhiteSpace(undefined!)).to.equal(true); - }); - it("should correctly manage null", () => { - expect(isNullOrWhiteSpace(null!)).to.equal(true); - }); - it("should correctly manage a value with only white space", () => { - expect(isNullOrWhiteSpace("\t\n ")).to.equal(true); - }); - it("should correctly manage a value without white space", () => { - expect(isNullOrWhiteSpace("foobar")).to.equal(false); - }); -}); - -describe("pascalCase", (): void => { - it("should correctly manage hyphenated strings", (): void => { - expect(pascalCase("string-extensions")).to.equal("StringExtensions"); - }); - - it("should correctly manage strings with whitespace", (): void => { - expect(pascalCase(" foo bar ")).to.equal("FooBar"); - }); - - it("should correctly manage all caps strings", (): void => { - expect(pascalCase("STRING EXTENSIONS")).to.equal("StringExtensions"); - }); - - it("should no-op on existing pascal case", (): void => { - expect(pascalCase("StringExtensions")).to.equal("StringExtensions"); - }); - - it("should correctly manage one capital case with no whitespace", (): void => { - expect(pascalCase("thinkIAm")).to.equal("ThinkIAm"); - }); - - it("should correctly manage strings with dashes", (): void => { - expect(pascalCase("--foo bar--")).to.equal("FooBar"); - }); - - it("should correctly manage strings with underscores", (): void => { - expect(pascalCase("__foo bar__")).to.equal("FooBar"); - }); -}); - -describe("spinalCase", () => { - it("should convert pascalCase strings", (): void => { - expect(spinalCase("stringExtensions")).to.equal("string-extensions"); - }); - it("should convert CamelCase strings", (): void => { - expect(spinalCase("StringExtensions")).to.equal("string-extensions"); - }); - it("should convert CamelCase with numbers", (): void => { - expect(spinalCase("typeRampMinus1FontSize")).to.equal( - "type-ramp-minus-1-font-size" - ); - }); -}); - -describe("startsWith", (): void => { - it("should correctly manage undefined", () => { - expect(startsWith(undefined!, undefined!)).to.equal(false); - expect(startsWith("Hello", undefined!)).to.equal(false); - }); - it("should correctly manage null", () => { - expect(startsWith(null!, null!)).to.equal(false); - expect(startsWith("Hello", null!)).to.equal(false); - }); - it("should correctly manage searching for an empty string", () => { - expect(startsWith("Helloworld", "")).to.equal(false); - }); - it("should correctly manage a string which includes a match but does not start with it", () => { - expect(startsWith("HelloWorld", "World")).to.equal(false); - }); - it("should correctly manage finding a valid string that starts with a match", () => { - expect(startsWith("start", "start")).to.equal(true); - expect(startsWith("start", "star")).to.equal(true); - }); - it("should correctly manage incorrect casing as an invalid match", () => { - expect(startsWith("start", "START")).to.equal(false); - }); -}); diff --git a/packages/utilities/fast-web-utilities/src/strings.ts b/packages/utilities/fast-web-utilities/src/strings.ts deleted file mode 100644 index f6a4fea655f..00000000000 --- a/packages/utilities/fast-web-utilities/src/strings.ts +++ /dev/null @@ -1,108 +0,0 @@ -let uniqueIdCounter: number = 0; - -/** - * Generates a unique ID based on incrementing a counter. - */ -export function uniqueId(prefix: string = ""): string { - return `${prefix}${uniqueIdCounter++}`; -} - -/** - * Builds a string from a format specifier and replacement parameters. - */ -export function format(formatSpecifier: string, ...parameters: string[]): string { - return formatSpecifier.replace( - /{(\d+)}/g, - function (match: string, index: number): any { - if (index >= parameters.length) { - return match; - } - - const value: string = parameters[index]; - - if (typeof value !== "number" && !value) { - return ""; - } - - return value; - } - ); -} - -/** - * Check to see if one string starts with another - */ -export function startsWith( - stringToSearch: string, - searchFor: string, - position: number = 0 -): boolean { - if (!stringToSearch || !searchFor) { - return false; - } - - return stringToSearch.substr(position, searchFor.length) === searchFor; -} - -/** - * Determines if the specified string is undefined, null, empty, or whitespace. - * True if the value is undefined, null, empty, or whitespace, otherwise false. - */ -export function isNullOrWhiteSpace(value: string): boolean { - return !value || !value.trim(); -} - -/** - * Converts a string to Pascal Case - * where the first letter of each compound word is capitalized. - */ -export function pascalCase(value: string): string { - let newValue: string = `${value}` - .replace(new RegExp(/[-_]+/, "g"), " ") - .replace(new RegExp(/[^\w\s]/, "g"), "") - .replace(/^\s+|\s+$|\s+(?=\s)/g, "") - .replace( - new RegExp(/\s+(.)(\w*)/, "g"), - ($1, $2, $3) => `${$2.toUpperCase() + $3.toLowerCase()}` - ) - .replace(new RegExp(/\w/), s => s.toUpperCase()); - - let firstLowerIdx: number = 0; - - for (let i = 0; i < newValue.length; i++) { - const currChar: string = newValue.charAt(i); - - if (currChar == currChar.toLowerCase()) { - firstLowerIdx = i; - break; - } - } - - if (firstLowerIdx > 1) { - newValue = - `${newValue.charAt(0).toUpperCase()}${newValue - .slice(1, firstLowerIdx - 1) - .toLowerCase()}` + newValue.slice(firstLowerIdx - 1); - } - - return newValue; -} - -/** - * converts a string from camelCase or pascalCase to spinal-case - * which is an lowercase dash separated naming style. - * - * An example of spinal case: foo-bar-bat - */ -export function spinalCase(value: string): string { - const valueWithLowerCaseFirstLetter: string = `${value - .charAt(0) - .toLowerCase()}${value.slice(1)}`; - - return valueWithLowerCaseFirstLetter.replace( - /([A-Z]|[0-9])/g, - function (match: string, group1: string): string { - return `-${group1.toLowerCase()}`; - } - ); -} diff --git a/packages/utilities/fast-web-utilities/src/system-colors.ts b/packages/utilities/fast-web-utilities/src/system-colors.ts deleted file mode 100644 index c107a9fe53c..00000000000 --- a/packages/utilities/fast-web-utilities/src/system-colors.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Define system colors for use in CSS stylesheets. - * - * https://drafts.csswg.org/css-color/#css-system-colors - */ -export enum SystemColors { - Canvas = "Canvas", - CanvasText = "CanvasText", - LinkText = "LinkText", - VisitedText = "VisitedText", - ActiveText = "ActiveText", - ButtonFace = "ButtonFace", - ButtonText = "ButtonText", - Field = "Field", - FieldText = "FieldText", - Highlight = "Highlight", - HighlightText = "HighlightText", - GrayText = "GrayText", -} diff --git a/packages/utilities/fast-web-utilities/tsconfig.build.json b/packages/utilities/fast-web-utilities/tsconfig.build.json deleted file mode 100644 index a808868a800..00000000000 --- a/packages/utilities/fast-web-utilities/tsconfig.build.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "./tsconfig.json", - "include": [ - "src/**/*" - ], - "exclude": [ - "node_modules" - ] -} diff --git a/packages/utilities/fast-web-utilities/tsconfig.json b/packages/utilities/fast-web-utilities/tsconfig.json deleted file mode 100644 index df0729d1645..00000000000 --- a/packages/utilities/fast-web-utilities/tsconfig.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "extends": "../../../tsconfig.json", - "compilerOptions": { - "baseUrl": ".", - "outDir": "./dist", - "module": "Node16", - "moduleResolution": "Node16", - "strictNullChecks": true, - "strictPropertyInitialization": true, - "allowJs": true, - "types": ["mocha", "webpack-env", "node"] - } -} diff --git a/packages/web-components/README.md b/packages/web-components/README.md index 3713906e648..82cba271ed8 100644 --- a/packages/web-components/README.md +++ b/packages/web-components/README.md @@ -9,15 +9,6 @@ Our web component packages. The `@microsoft/fast-element` library is a lightweight means to easily build performant, memory-efficient, standards-compliant Web Components. FAST Elements work in every major browser and can be used in combination with any front-end framework or even without a framework. To get up and running with `@microsoft/fast-element` see [the Getting Started guide](https://fast.design/docs/fast-element/getting-started). -## `@microsoft/fast-foundation` - -[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) -[![npm version](https://badge.fury.io/js/%40microsoft%2Ffast-foundation.svg)](https://badge.fury.io/js/%40microsoft%2Ffast-foundation) - -The `@microsoft/fast-foundation` package is a library of Web Component classes, templates, and other utilities intended to be composed into registered Web Components by design systems (e.g. Fluent Design, Material Design, etc.). The exports of this package can generally be thought of as un-styled base components that implement semantic and accessible markup and behavior. - -This package does not export Web Components registered as [custom elements](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements) - it exports parts and pieces intended to be *composed* into Web Components, allowing you to implement your own design language by simply applying CSS styles and behaviors without having to write all the JavaScript that's involved in building production-quality component implementations. - ## `@microsoft/fast-ssr` [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) diff --git a/packages/web-components/fast-foundation/.eslintignore b/packages/web-components/fast-foundation/.eslintignore deleted file mode 100644 index 62c6d3c918b..00000000000 --- a/packages/web-components/fast-foundation/.eslintignore +++ /dev/null @@ -1,6 +0,0 @@ -coverage -dist -node_modules -*.spec.ts -!*.pw.spec.ts -.eslintrc.* diff --git a/packages/web-components/fast-foundation/.eslintrc.cjs b/packages/web-components/fast-foundation/.eslintrc.cjs deleted file mode 100644 index 77390791df3..00000000000 --- a/packages/web-components/fast-foundation/.eslintrc.cjs +++ /dev/null @@ -1,66 +0,0 @@ -const path = require("path"); - -module.exports = { - extends: [ - "../../../.eslintrc.js", - "plugin:storybook/recommended", - ], - rules: { - "@typescript-eslint/naming-convention": [ - "error", - { - selector: "typeLike", - format: ["UPPER_CASE", "camelCase", "PascalCase"], - leadingUnderscore: "allow", - }, - ], - "@typescript-eslint/ban-types": [ - "error", - { - types: { - "{}": false, - Function: false, - Object: false, - }, - extendDefaults: true, - }, - ], - }, - overrides: [ - { - files: ["**/*.cjs"], - env: { - commonjs: true, - node: true, - }, - rules: { - "@typescript-eslint/no-var-requires": "off", - }, - }, - { - files: ["**/*.ts"], - excludedFiles: ["playwright.config.ts"], - parserOptions: { - parser: "@typescript-eslint/parser", - project: path.resolve(__dirname, "./tsconfig.json"), - }, - rules: { - "@typescript-eslint/consistent-type-imports": "error", - "@typescript-eslint/consistent-type-exports": [ - "error", - { fixMixedExportsWithInlineTypeSpecifier: false }, - ], - }, - }, - { - files: ["**/*.ts"], - excludedFiles: ["**/*.stories.ts"], - rules: { - "no-restricted-imports": [ - "error", - { patterns: ["**/stories/**", "**/*.pw.spec.ts"] }, - ], - }, - }, - ], -}; diff --git a/packages/web-components/fast-foundation/.gitignore b/packages/web-components/fast-foundation/.gitignore deleted file mode 100644 index 1360a95303d..00000000000 --- a/packages/web-components/fast-foundation/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -.rollupcache -coverage -tsdoc-metadata.json -temp \ No newline at end of file diff --git a/packages/web-components/fast-foundation/.npmignore b/packages/web-components/fast-foundation/.npmignore deleted file mode 100644 index 9284e0b71bc..00000000000 --- a/packages/web-components/fast-foundation/.npmignore +++ /dev/null @@ -1,25 +0,0 @@ -# Tests -dist/dts/__test__/ -dist/esm/__test__/ -*.spec.* -coverage/ - -# Source files -src/ - -# images -images/ - -# config files -.eslintignore -.eslintrc.js -.mocharc.json -.prettierignore -api-extractor.json -karma.conf.js -rollup.config.js -tsconfig.json - -# cache -.rollupcache -temp \ No newline at end of file diff --git a/packages/web-components/fast-foundation/.npmrc b/packages/web-components/fast-foundation/.npmrc deleted file mode 100644 index 43c97e719a5..00000000000 --- a/packages/web-components/fast-foundation/.npmrc +++ /dev/null @@ -1 +0,0 @@ -package-lock=false diff --git a/packages/web-components/fast-foundation/.prettierignore b/packages/web-components/fast-foundation/.prettierignore deleted file mode 100644 index 8c383faa550..00000000000 --- a/packages/web-components/fast-foundation/.prettierignore +++ /dev/null @@ -1,3 +0,0 @@ -coverage/* -dist/* -*.spec.ts \ No newline at end of file diff --git a/packages/web-components/fast-foundation/.storybook/debug.stories.ts b/packages/web-components/fast-foundation/.storybook/debug.stories.ts deleted file mode 100644 index 05352662f9a..00000000000 --- a/packages/web-components/fast-foundation/.storybook/debug.stories.ts +++ /dev/null @@ -1,13 +0,0 @@ -/** - * This is a special story that allows us to load a blank preview page for - * playwright tests which need to generate elements and insert them directly, - * rather than start with a pre-determined element. - */ - -import type { Meta } from "@storybook/html"; - -export default { - title: "Debug", -} as Meta; - -export const Blank = () => ""; diff --git a/packages/web-components/fast-foundation/.storybook/main.ts b/packages/web-components/fast-foundation/.storybook/main.ts deleted file mode 100644 index fcb6a8d1fb1..00000000000 --- a/packages/web-components/fast-foundation/.storybook/main.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { StorybookConfig } from "@storybook/html-vite"; - -const config: StorybookConfig = { - stories: ["../src/**/stories/*.stories.ts", "debug.stories.ts"], - framework: "@storybook/html-vite", - addons: ["@storybook/addon-essentials"], - core: { - disableTelemetry: true, - disableWhatsNewNotifications: true, - }, - async viteFinal(config) { - const { mergeConfig } = await import("vite"); - - return mergeConfig(config, { - build: { chunkSizeWarningLimit: 1000 }, - resolve: { - alias: [{ find: /^(.*\.svg)$/, replacement: "$1?raw" }], - }, - }); - }, -}; - -export default config; diff --git a/packages/web-components/fast-foundation/.storybook/manager-head.html b/packages/web-components/fast-foundation/.storybook/manager-head.html deleted file mode 100644 index 3baaa1af068..00000000000 --- a/packages/web-components/fast-foundation/.storybook/manager-head.html +++ /dev/null @@ -1,6 +0,0 @@ - diff --git a/packages/web-components/fast-foundation/.storybook/preview-body.html b/packages/web-components/fast-foundation/.storybook/preview-body.html deleted file mode 100644 index d87a8e39307..00000000000 --- a/packages/web-components/fast-foundation/.storybook/preview-body.html +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - - diff --git a/packages/web-components/fast-foundation/.storybook/preview-head.html b/packages/web-components/fast-foundation/.storybook/preview-head.html deleted file mode 100644 index 8aa4d735223..00000000000 --- a/packages/web-components/fast-foundation/.storybook/preview-head.html +++ /dev/null @@ -1,178 +0,0 @@ - diff --git a/packages/web-components/fast-foundation/.storybook/preview.ts b/packages/web-components/fast-foundation/.storybook/preview.ts deleted file mode 100644 index 0633ba9e228..00000000000 --- a/packages/web-components/fast-foundation/.storybook/preview.ts +++ /dev/null @@ -1,19 +0,0 @@ -/// - -// Import all component definitions. This is a vite-specific feature: -// https://vitejs.dev/guide/features.html#glob-import -const modules = import.meta.glob("../src/**/*.register.ts"); - -for (const path in modules) { - modules[path](); -} - -// Provide the `html` tag function as a global. This is needed for some tests. -(async () => { - const { html } = await import("@microsoft/fast-element"); - - Object.defineProperty(globalThis, "html", { - value: html, - writable: false, - }); -})(); diff --git a/packages/web-components/fast-foundation/ACKNOWLEDGEMENTS.md b/packages/web-components/fast-foundation/ACKNOWLEDGEMENTS.md deleted file mode 100644 index 0d48a417d86..00000000000 --- a/packages/web-components/fast-foundation/ACKNOWLEDGEMENTS.md +++ /dev/null @@ -1,4 +0,0 @@ -# Acknowledgements - -* A huge thank-you to [TypeScript](www.typescriptlang.org/) for providing an amazing language, build tools, and at least one [code sample](./src/utilities/apply-mixins.ts) we've shamelessly stolen. -* Big thanks to https://github.com/fkleuver and the https://github.com/aurelia/aurelia project for [Dependency Injection](./src/di/di.ts) code and core tests. \ No newline at end of file diff --git a/packages/web-components/fast-foundation/CEMToMarkdown.mjs b/packages/web-components/fast-foundation/CEMToMarkdown.mjs deleted file mode 100644 index b7c79da52c1..00000000000 --- a/packages/web-components/fast-foundation/CEMToMarkdown.mjs +++ /dev/null @@ -1,217 +0,0 @@ -import fs from "fs"; -import { default as os } from "os"; -import { customElementsManifestToMarkdown } from "@custom-elements-manifest/to-markdown"; - -// new line and double new line shorthands -const LF = os.EOL; -const LF2 = LF + LF; - -// Read the custom-elements.json file and parse the JSON -const fullManifest = JSON.parse(fs.readFileSync("dist/custom-elements.json", "utf-8")); - -// Filter out template modules and ensure that they are in alphabetical order -const modules = fullManifest.modules - .filter(module => module.path.indexOf("template.ts") === -1) - .sort((a, b) => - getComponentNameFromPath(a.path).localeCompare(getComponentNameFromPath(b.path)) - ); - -// Loop through the manifest grouping modules from the same folder in order to produce one markdown file per component. -for (var i = 0, modulesLength = modules.length; i < modulesLength; i++) { - // We only care about javascript-modules. - if (modules[i].kind === "javascript-module") { - // Create a new manifest object just for this component. - let componentManifest = {}; - componentManifest.schemaVersion = fullManifest.schemaVersion; - componentManifest.readme = fullManifest.readme; - componentManifest.modules = []; - - // Determine the component name from the path. This name will be used to group following modules. - const currName = getComponentNameFromPath(modules[i].path); - const componentIndex = i; - - componentManifest.modules.push(modules[i]); - - // Continue looping through the main manifest, adding modules to the small manifest until we find a module with a different name. - // Include modules with names like "component-item" so components like Accordion and Accordion-item are included in the same file. - // Include modules with names like "component-label" so components like Slider and Slider-label are included in the same file. - while ( - i < modules.length - 1 && - (currName === getComponentNameFromPath(modules[i + 1].path) || - currName + "-item" === getComponentNameFromPath(modules[i + 1].path) || - currName + "-label" === getComponentNameFromPath(modules[i + 1].path)) - ) { - componentManifest.modules.push(modules[i + 1]); - i++; - } - - // Special logic for the "tab" components. - // If the current module is "tabs" include the previous two modules which should be "tab" and "tab-panel". - if (currName === "tabs") { - componentManifest.modules.push(modules[i - 1]); - componentManifest.modules.push(modules[i - 2]); - } - - // enclose html tags in `` to prevent tags in comments from confusing docusaurus - // and remove new line characters from descriptions - componentManifest.modules.forEach(module => { - module.declarations?.forEach(dec => { - if (dec.description) { - dec.description = replaceJSDOCLinksWithMDLinks( - fixTagsInText(dec.description.replaceAll(LF, " ")) - ); - } - if (dec.default) { - dec.default = replaceJSDOCLinksWithMDLinks( - fixTagsInText(dec.default.replaceAll(LF, " ")) - ); - } - if (dec.type) { - dec.type.text = cleanUpVariableTypes(dec.type.text); - } - dec.members?.forEach(member => { - if (member.description) { - member.description = replaceJSDOCLinksWithMDLinks( - fixTagsInText(member.description.replaceAll(LF, " ")) - ); - } - if (member.default) { - member.default = replaceJSDOCLinksWithMDLinks( - fixTagsInText(member.default.replaceAll(LF, " ")) - ); - } - if (member.return?.type?.text) { - // these are already rendered inside of back-ticks so we only need to remove new lines - member.return.type.text = member.return.type.text.replaceAll( - LF, - " " - ); - } - }); - dec.attributes?.forEach(attr => { - if (attr.description) { - attr.description = replaceJSDOCLinksWithMDLinks( - fixTagsInText(attr.description.replaceAll(LF, " ")) - ); - } - }); - }); - }); - - // Convert the single component manifest into a markdown string. - let markdown = customElementsManifestToMarkdown(componentManifest, { - headingOffset: 1, - private: "hidden", - omitDeclarations: ["exports"], - omitSections: ["static-methods"], - }); - - // Replace our < and > markers with backticks and < > - // This is necessary because customElementsManifestToMarkdown escapes the backticks during the conversion - // and we don't want that because then docusaurus will see the tags as real tags instead of just text. - markdown = markdown.replaceAll("REPLACELT", "`<").replaceAll("REPLACEGT", ">`"); - - // Clean up some additional formatting issues - // Remove the file source header - markdown = markdown.replaceAll(/## `src.*`:/g, ""); - // Fix escape of colon in urls - markdown = markdown.replaceAll("https\\:", "https:"); - // Fix escape of . in some urls - markdown = markdown.replaceAll("www\\.w3", "www.w3"); - // Fix escape of open bracket on links - markdown = markdown.replaceAll("\\[", "["); - // Fix escape of open paren on links - markdown = markdown.replaceAll("\\(", "("); - - // Replace \| with 'or' - markdown = markdown.replaceAll("\\|", "or"); - - // Get the README.md file - let path = modules[componentIndex].path.split("/"); - path[path.length - 1] = "README.md"; - path = path.join("/"); - - // If a README.md file exists - if (fs.existsSync(path)) { - // Read the contents of the file - let readMe = fs.readFileSync(path, "utf-8"); - - // Find the location of the "## API" section - let apiLoc = readMe.indexOf("## API"); - - // Find the location of the "## Additional resources" section - let resourcesLoc = readMe.indexOf("## Additional resources"); - - // If the API section does not exist then create it either just - // above the Additional Resources section or at the end of the file. - if (apiLoc === -1) { - // no API section yet so add it - if (resourcesLoc > 0) { - // add API section above Additional Resources - readMe = readMe.replace( - "## Additional resources", - "## API" + LF2 + "## Additional resources" - ); - } else { - // add API to the end - readMe += LF2 + "## API"; - } - - // Get the updated locations - apiLoc = readMe.indexOf("## API"); - resourcesLoc = readMe.indexOf("## Additional resources"); - } - - // customElementsManifestToMarkdown() hard codes line endings as '/n'. This causes GIT to detect changes - // to the file on windows environments even if nothing but the line endings change. If the os.EOL is '\r\n' - // then replace all '\n' in the markdown with '\r\n'. - if (LF === "\r\n") { - markdown = markdown.replaceAll("\n", "\r\n"); - } - - // Replace everything in between the API and Additional Resources sections with the - // updated markdown. - const startIndex = apiLoc; - const endIndex = resourcesLoc >= 0 ? resourcesLoc : readMe.length; - readMe = readMe.replace( - readMe.slice(startIndex, endIndex), - "## API" + LF2 + markdown + LF2 - ); - - // Replace the README.md file with the new content. - fs.writeFileSync(path, readMe); - } - } -} - -function getComponentNameFromPath(path) { - return path.split("/")[1]; -} - -function fixTagsInText(text) { - // replace < and > characters in text with something that can be easily replaced later. - return text.replaceAll(/<.*>/gi, match => { - return match.replace("<", "REPLACELT").replace(">", "REPLACEGT"); - }); -} - -function replaceJSDOCLinksWithMDLinks(text) { - // Replace jsdoc links with markdown links - // [TEXT]{@link URL} => [TEXT](URL) - // {@link URL} => URL - // {@link URL TEXT} => [TEXT](URL) - // {@link URL | TEXT} => [TEXT](URL) - return text - .replace(/\[(.*)\]\{@link (\S*)\}/gm, "[$1]($2)") - .replace(/\{@link (\S*)\}/gm, "$1") - .replace(/\{@link (\S*)\s*\|?\s*([^}]+?)\s*\}/gm, "[$2]($1)"); -} - -function cleanUpVariableTypes(text) { - // Remove block comments - text = text.replace(/\/\*(.|\s)*?\*\//gm, ""); - // Remove inline comments, line breaks, and extra spaces - return text - .replace(/\/\/.*$/gm, "") - .replace(/\s+/gm, " "); -} diff --git a/packages/web-components/fast-foundation/CHANGELOG.json b/packages/web-components/fast-foundation/CHANGELOG.json deleted file mode 100644 index 54fd5e225be..00000000000 --- a/packages/web-components/fast-foundation/CHANGELOG.json +++ /dev/null @@ -1,4537 +0,0 @@ -{ - "name": "@microsoft/fast-foundation", - "entries": [ - { - "date": "Thu, 20 Jun 2024 17:00:56 GMT", - "version": "3.0.0-alpha.33", - "tag": "@microsoft/fast-foundation_v3.0.0-alpha.33", - "comments": { - "prerelease": [ - { - "author": "145117767+JiginJayaprakash@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "e70cdb0fa0ad2c79e6d26ee8670a60761165999a", - "comment": "update picker component roles" - }, - { - "author": "stephcomeau@msn.com", - "package": "@microsoft/fast-foundation", - "commit": "33164280e20c93d9ff6395a77994348260d72ce0", - "comment": "add picker disabled state" - }, - { - "author": "stephcomeau@msn.com", - "package": "@microsoft/fast-foundation", - "commit": "e499c035e15dbe1337867a27b9d221279202886b", - "comment": "no options missing" - }, - { - "author": "26874831+atmgrifter00@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "f8071fb913310eb35dc19da017b554c2608b7f12", - "comment": "Various Combobox fixes with tests." - }, - { - "author": "7559015+janechu@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "6a0c57ae410e0c64cb3be2311ba081de894aa2a2", - "comment": "Remove unmatched closing div" - }, - { - "author": "olaf-k@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "731fcb18123a005a9d94abb2fe96af0c4fdc5d7d", - "comment": "removing readonly for Slider" - }, - { - "author": "nicholasrice@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "94b51bc0e52673ec80e39ba4eecf9ccb31bf8831", - "comment": "Adds token name to token resolution error when the name exists for a token" - }, - { - "author": "7559015+janechu@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "c4e4422f28bab5a5da74f1e8cf9337922a1b20c9", - "comment": "fix(foundation): textfield proxy enterkeyhint" - }, - { - "author": "43081j@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "d1685dea3029c7aa3d3cc5b29d62510dc41a7cd8", - "comment": "feat(text-field): reset value on type change" - }, - { - "author": "zoepeterson@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "543a69ce71ea79322a86dcbb5adbfe1f451a880a", - "comment": "fix(combobox): close the combobox even if there's no selection" - }, - { - "author": "863023+radium-v@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "5dac26f674ca755476b5a38bda5506947b42de93", - "comment": "upgrade to Storybook 8" - }, - { - "author": "47367562+bheston@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "2ba8729473156176840521f1332e98032b3114b0", - "comment": "Foundation: Update Slider templates (https://github.com/microsoft/fast/pull/6800)" - }, - { - "author": "fcollonval@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "5b2b801208a86c1d342feff49961f5c490ad247e", - "comment": "Fix toolbar stealing focus" - }, - { - "author": "47367562+bheston@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "0d592e266e81acec6188961d7d17326a4ad9ad72", - "comment": "Foundation: Update Number field, Search, Switch, Text area, and Text field templates (https://github.com/microsoft/fast/pull/6798)" - }, - { - "author": "47367562+bheston@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "daff330978c2bbc961e729ee7f285ab426bf0beb", - "comment": "Update Badge and Breadcrumb templates (https://github.com/microsoft/fast/pull/6797)" - }, - { - "author": "quic_scomeau@qualcomm.com", - "package": "@microsoft/fast-foundation", - "commit": "8023f7ee8458ac147dee4dadb9b72ce45a142a1f", - "comment": "fix: allow tabs `setTabs` method to be extended" - }, - { - "author": "stephcomeau@msn.com", - "package": "@microsoft/fast-foundation", - "commit": "df2ca503b1e2e060b3ddc32af0765505c65bb7f5", - "comment": "comparisons to document.activeElement consider shadowRoot" - }, - { - "author": "47367562+bheston@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "9d7b36d38ed1e3b3c847df718f5aea97c811e946", - "comment": "Foundation: Update Accordion template element naming (https://github.com/microsoft/fast/pull/6796)" - } - ], - "none": [ - { - "author": "7559015+janechu@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "4b23b5caa76c172d3ea6c6559699d632a278442c", - "comment": "Added missing types" - }, - { - "author": "7559015+janechu@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "00bccd7812ca072fc2efdf39af7762bbfdc90846", - "comment": "Remove eslint config package" - }, - { - "author": "863023+radium-v@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "97ef4d7a3880212bbb4f895459a047429a113472", - "comment": "upgrade playwright to 1.41" - }, - { - "author": "7282195+m-akinc@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "9af1b251df57244d61524bf5af757839373249a0", - "comment": "Additional design token test cases" - } - ] - } - }, - { - "date": "Wed, 20 Dec 2023 19:03:48 GMT", - "tag": "@microsoft/fast-foundation_v3.0.0-alpha.32", - "version": "3.0.0-alpha.32", - "comments": { - "prerelease": [ - { - "author": "20542556+mollykreis@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "a7144c63191e4412d6441cce81cd04cc03152510", - "comment": "Fix focus issue when clicking on an element in the toolbar" - }, - { - "author": "20542556+mollykreis@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "b78c921ec4e49ec9d7ec980f079ec114045df42e", - "comment": "Fix bug in toolbar click handler when a slotted element has child elements" - } - ] - } - }, - { - "date": "Fri, 18 Aug 2023 22:48:12 GMT", - "tag": "@microsoft/fast-foundation_v3.0.0-alpha.31", - "version": "3.0.0-alpha.31", - "comments": { - "prerelease": [ - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "d4d8c961b3ad5262924120070057ad6554dfdcb9", - "comment": "export patterns from foundation as package export" - } - ] - } - }, - { - "date": "Fri, 18 Aug 2023 00:04:39 GMT", - "tag": "@microsoft/fast-foundation_v3.0.0-alpha.30", - "version": "3.0.0-alpha.30", - "comments": { - "prerelease": [ - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "2dab94c0eda05bee7c4b497e68951d79d6fcbe46", - "comment": "update fast-element export paths to include extensions" - }, - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "98a726cdb9d1b0dd5deaa7cb61ef2c23f4758585", - "comment": "add export paths with extensions for each fast-foundation component and utilities" - }, - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "4f0377849de66bd69ac69c1cc7c0ff5bbe7ebbfd", - "comment": "fix: change public static methods for listbox and data grid to not be fat arrow fns" - }, - { - "author": "beachball", - "package": "@microsoft/fast-foundation", - "comment": "Bump @microsoft/fast-element to v2.0.0-beta.26", - "commit": "2dab94c0eda05bee7c4b497e68951d79d6fcbe46" - } - ] - } - }, - { - "date": "Sat, 12 Aug 2023 00:26:35 GMT", - "tag": "@microsoft/fast-foundation_v3.0.0-alpha.29", - "version": "3.0.0-alpha.29", - "comments": { - "prerelease": [ - { - "author": "stephcomeau@msn.com", - "package": "@microsoft/fast-foundation", - "commit": "a38e6b166765bb5290b0e6cf55feffdb16a8cbb4", - "comment": "block cell nav events" - }, - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "b5f23eb6c537a2659da4666f3c993c360d523153", - "comment": "fix: add aria-orientation to divider only when role equals separator" - }, - { - "author": "nicholasrice@noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "57f3c22c6341d8a21d48b1ffb7fcbfab1ffd02d8", - "comment": "Removed the 'applyMixins' function from exported features." - }, - { - "author": "7282195+m-akinc@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "50dba9c58b1bc6ac0c8b948f68dd0cfb6485460b", - "comment": "Prevent keyboard navigation to hidden tab" - }, - { - "author": "stephcomeau@msn.com", - "package": "@microsoft/fast-foundation", - "commit": "e0d4cb42ef8ff28452a744867bde7f095a263297", - "comment": "picker zero items" - }, - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "adaaeb653a37c0eec6ce5fbc57b73c24ca09f347", - "comment": "fix: toolbar should not throw if start or end is undefined" - }, - { - "author": "beachball", - "package": "@microsoft/fast-foundation", - "comment": "Bump @microsoft/fast-element to v2.0.0-beta.25", - "commit": "2297004e14386b5a689ba96361f8d8eebee69cd8" - } - ] - } - }, - { - "date": "Fri, 16 Jun 2023 18:17:12 GMT", - "tag": "@microsoft/fast-foundation_v3.0.0-alpha.28", - "version": "3.0.0-alpha.28", - "comments": { - "prerelease": [ - { - "author": "saicharan0124@gmail.com", - "package": "@microsoft/fast-foundation", - "commit": "50e3fcd207adca50c5e666b12fc7c72b3cc0ba07", - "comment": "remove keyboard ability to change value for readonly state in fast-number-field" - }, - { - "author": "stephcomeau@msn.com", - "package": "@microsoft/fast-foundation", - "commit": "2f944b3d72a65743cbba9da44471b70ac0c9fe27", - "comment": "open picker menu on delete" - }, - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "f994643b29c179fe2cced616dedcff5dbb26af64", - "comment": "set activeid when setting active tab" - }, - { - "author": "47367562+bheston@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "bc731b8291bc0de4ada910ccb37225b227706861", - "comment": "Fix api-extractor doc warnings" - }, - { - "author": "nicholasrice@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "e678a782dd06a1c9ca79726da4a5765244858d21", - "comment": "Updates when directive instances to use 'else' template option" - }, - { - "author": "stephcomeau@msn.com", - "package": "@microsoft/fast-foundation", - "commit": "00140c2a3462bf73b5173f8f18a37d547df3b1e0", - "comment": "picker show no options" - }, - { - "author": "stephcomeau@msn.com", - "package": "@microsoft/fast-foundation", - "commit": "864303b923a10fd8b1d88444efb05e3f64c9524d", - "comment": "fix picker scroll into view" - }, - { - "author": "stephcomeau@msn.com", - "package": "@microsoft/fast-foundation", - "commit": "f05058084183576b641d33b18e0cdd205814ffdf", - "comment": "picker filter ignores case" - }, - { - "author": "beachball", - "package": "@microsoft/fast-foundation", - "comment": "Bump @microsoft/fast-element to v2.0.0-beta.24", - "commit": "8250aa8352940584ff443b550ee756d49f01c478" - } - ], - "none": [ - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "ca0e62ee8d05f72d1d8c1ad66bd6eea8e3f0a4eb", - "comment": "update prettier and eslint-config-prettier versions" - } - ] - } - }, - { - "date": "Tue, 28 Mar 2023 22:14:10 GMT", - "tag": "@microsoft/fast-foundation_v3.0.0-alpha.27", - "version": "3.0.0-alpha.27", - "comments": { - "prerelease": [ - { - "author": "tebin.raouf@gmail.com", - "package": "@microsoft/fast-foundation", - "commit": "24a23de4c342988c162552aeeab9dc83d10cf501", - "comment": "update @microsoft/fast-element to be fixed for foundation package" - }, - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "ae07a0142cf35ae1c6b246140f1ebc419cbaf0e0", - "comment": "update slider changed methods to protected" - }, - { - "author": "scomea@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "27070ef2fc7aa5cdaeb827f1266eb3c5a0ad2c3e", - "comment": "support row selection in data grid" - }, - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "6f37a826129ea14d6e69d0f916bb9561c5c09566", - "comment": "remove activeindicator from tabs component" - }, - { - "author": "beachball", - "package": "@microsoft/fast-foundation", - "comment": "Bump @microsoft/fast-element to v2.0.0-beta.23", - "commit": "032285c2bf0311f9f44cbc875b40696fc8f62857" - } - ] - } - }, - { - "date": "Sat, 11 Mar 2023 00:09:48 GMT", - "tag": "@microsoft/fast-foundation_v3.0.0-alpha.26", - "version": "3.0.0-alpha.26", - "comments": { - "prerelease": [ - { - "author": "yinon@hotmail.com", - "package": "@microsoft/fast-foundation", - "commit": "dcf64d0383f613fd0c79b6f4f5ef010fccdbc11f", - "comment": "remove readonly support from fast radio" - }, - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "f9a97566884c338cd83ce96ac2996aacf8b360f9", - "comment": "update slider to increment and decrement without a default value for the step attribute" - }, - { - "author": "stephcomeau@msn.com", - "package": "@microsoft/fast-foundation", - "commit": "e57f033cfb538e22a2c38182c863912a68d985fa", - "comment": "picker should work in shadow dom" - }, - { - "author": "stephcomeau@msn.com", - "package": "@microsoft/fast-foundation", - "commit": "c766483f75ac05292d54f91bc6119dbeb6059633", - "comment": "data grid header fix" - }, - { - "author": "rob@bluespire.com", - "package": "@microsoft/fast-foundation", - "commit": "70eb15bc13d9f4d849bc5b1fe4d591a23e57c935", - "comment": "fix: update components to new binding APIs" - }, - { - "author": "jes@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "4ce7cdb80bedf8115d3994f56e93f50b6d9f181a", - "comment": "fix: remove focus management from slider" - }, - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "1e89f8ea00d14fac3d3794782c3eef94ccb3ae67", - "comment": "remove className logic from switch checkedChanged" - }, - { - "author": "ryan@ryanmerrill.net", - "package": "@microsoft/fast-foundation", - "commit": "0535a97f2712fc25e68910518890e00d7c1e9c2b", - "comment": "Fixes Slider vertical orientation so adjusting the slider increases the value when the thumb is moved upwards and corrects keyboard handling" - }, - { - "author": "beachball", - "package": "@microsoft/fast-foundation", - "comment": "Bump @microsoft/fast-element to v2.0.0-beta.22", - "commit": "dcf64d0383f613fd0c79b6f4f5ef010fccdbc11f" - } - ] - } - }, - { - "date": "Tue, 14 Feb 2023 04:02:34 GMT", - "tag": "@microsoft/fast-foundation_v3.0.0-alpha.25", - "version": "3.0.0-alpha.25", - "comments": { - "prerelease": [ - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "e504d092f81623e6332fa8cdf72ce9114e6c842e", - "comment": "fix radio group disabled handling" - }, - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "a85467bdbf2241628dc3007610cb017017da04d0", - "comment": "remove readonly classname from switch" - }, - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "4a616b4a3b1c3c3b060756c74ec8802e09e6600e", - "comment": "add explicit exports for component orientations" - }, - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "48a29ca6d68093fb2b70abfd99e888f75085ade2", - "comment": "ensure single expand mode accordions support explicitly expanded items" - }, - { - "author": "47367562+bheston@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "5a27a1cebf1ada23f41863e3ec909f5229d7888e", - "comment": "Cleaned up `start` and `end` definitions" - }, - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "f8dde59eee21a1152263447d22a76593ee5ed9e5", - "comment": "add default slot to divider" - }, - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "26a07b9c59e9a6bdc94c35577eb96cd934523ced", - "comment": "observe accordion children to accommodate single expand scenarios with programmatic changes" - }, - { - "author": "47367562+bheston@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "92c0d0da33ff43ed0c520dbd84bfb959384985ee", - "comment": "Fix Picker template missing quote and dependent tag names" - }, - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "0ae312ee9be8f451519187c0925a6c6ac6071f22", - "comment": "remove paused attribute from progress" - }, - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "91beb0e43a390692240e62e085c2f49256500852", - "comment": "remove status messages from switch template" - }, - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "2a2fe957ccb823a40a8eebdc25fd2c3f8e444070", - "comment": "fixes an issue where accordion expand-mode changes were not reflected in the component" - }, - { - "author": "47367562+bheston@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "21c210f2164c5cf285cade1a328460c67e4b97e6", - "comment": "Remove link from Avatar" - }, - { - "author": "beachball", - "package": "@microsoft/fast-foundation", - "comment": "Bump @microsoft/fast-element to v2.0.0-beta.21", - "commit": "e504d092f81623e6332fa8cdf72ce9114e6c842e" - } - ], - "none": [ - { - "author": "47367562+bheston@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "2f8c3d3b2176571dc2cf4038af33a0dc22d1932e", - "comment": "Import icons for fast-foundation stories" - } - ] - } - }, - { - "date": "Wed, 11 Jan 2023 22:07:43 GMT", - "tag": "@microsoft/fast-foundation_v3.0.0-alpha.24", - "version": "3.0.0-alpha.24", - "comments": { - "prerelease": [ - { - "author": "Mathieu.Salois@goto.com", - "package": "@microsoft/fast-foundation", - "commit": "dfab11aed93627f28d0985a376f6fd461b27cdb6", - "comment": "fix(Calendar): add fix for the timezones from #5539" - }, - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "4e39f28dfca811ef5b977c0ab706669fca732ed7", - "comment": "export staticallyCompose function" - }, - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "2bb85c931a84d4de3a8b61d6f26f89f2d9a525f6", - "comment": "remove deprecation notice from display helpers" - }, - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "d003ef9f7980a7e3697592f28a14ec01fad6aaed", - "comment": "add disabled attribute support to accordion item" - }, - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "02ae46b6bc91f73f0d77fa4c1a2517925f4295d5", - "comment": "add ValuesOf helper for mapping types from a const object" - }, - { - "author": "32497422+KingOfTac@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "b28b297e014939aba1810fe8d22ff35b2ad86efb", - "comment": "Removed legacy unsupported delegates focus from Anchor and Button now that `delgatesFocus` is supported in firefox since version 94." - }, - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "52cd5171c3e9061af8066443023782bca2b0e59b", - "comment": "updates types for default slotted content to remove string and support DangerousHTMLDirective" - }, - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "d29b0a0c840cc9a5dedd5f3c79508cc7d6355986", - "comment": "update default value of menu item checked attribute to false" - }, - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "3a3bd3ab29344c8b98bf88d8528cbfa4e07958f9", - "comment": "add missing part attribute for tabpanel in tabs" - }, - { - "author": "stephcomeau@msn.com", - "package": "@microsoft/fast-foundation", - "commit": "a3d8260e210a2ed94d76b89226c2ed15e12ac229", - "comment": "clean up header on disconnect" - }, - { - "author": "nicholasrice@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "d33b910a8fabe927e0afb63bba843c20cf67f2f4", - "comment": "Fixed bug in DesignTokenNode reparenting" - }, - { - "author": "stephcomeau@msn.com", - "package": "@microsoft/fast-foundation", - "commit": "03ec71cfce57046ee857088f44362910050cc0f8", - "comment": "rework scroll into view" - }, - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "3c5495be5875ac01527d99855ab912fa0298d3cf", - "comment": "ensure submenu items are navigable after parent menu item has been clicked" - }, - { - "author": "roeisenb@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "5c3b2f0431ae8f840d3dc778ff93be73b585c6e2", - "comment": "refactor(fast-foundation): template inline options and html.partial" - }, - { - "author": "863023+radium-v@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "555f1b2cd614a1d5a9bc3985fb892d040c110cb3", - "comment": "rewrite tooltip to use floating-ui" - }, - { - "author": "beachball", - "package": "@microsoft/fast-foundation", - "comment": "Bump @microsoft/fast-element to v2.0.0-beta.20", - "commit": "2bb85c931a84d4de3a8b61d6f26f89f2d9a525f6" - } - ], - "none": [ - { - "author": "863023+radium-v@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "fedf41e5222c14cf27be1886161d6acad0fcbfab", - "comment": "convert form-associated tests to playwright" - }, - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "7d3b7f3741523c27adce82ef4e1eca202954dee4", - "comment": "fix FancyMenu example class issues" - }, - { - "author": "rina.oksman@vonage.com", - "package": "@microsoft/fast-foundation", - "commit": "2f51c838340d27b7b73a253f6e0a87f8de333728", - "comment": "add user-select to button" - } - ] - } - }, - { - "date": "Fri, 02 Dec 2022 01:18:22 GMT", - "tag": "@microsoft/fast-foundation_v3.0.0-alpha.23", - "version": "3.0.0-alpha.23", - "comments": { - "prerelease": [ - { - "author": "yinon@hotmail.com", - "package": "@microsoft/fast-foundation", - "commit": "802443ffb2b19a078f9b48f62e6d1a35e3276fb5", - "comment": "checkbox remove irrelevant read-only property" - }, - { - "author": "beachball", - "package": "@microsoft/fast-foundation", - "comment": "Bump @microsoft/fast-element to v2.0.0-beta.19", - "commit": "040867e9a2a9e0ae25b78dfb3265fbe8f60fe023" - } - ] - } - }, - { - "date": "Tue, 15 Nov 2022 02:40:34 GMT", - "tag": "@microsoft/fast-foundation_v3.0.0-alpha.22", - "version": "3.0.0-alpha.22", - "comments": { - "prerelease": [ - { - "author": "olaf-k@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "416dc9167e9d41e6ffe11d87ed79b2f455357923", - "comment": "add aria-orientation to radio-group" - }, - { - "author": "nicholasrice@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "e4a2bfccc07e65f9cfd1db9a943d93a84fb13ae4", - "comment": "Fixing bug in DesignToken causing RangeError" - }, - { - "author": "roeisenb@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "1a1fc0b9e85f1e65c605e32f6724402291ffbcaa", - "comment": "chore: move ViewBehaviorOrchestrator to utilities" - }, - { - "author": "roeisenb@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "3c14603089495a7af8ed5b55122c418b47c45fd5", - "comment": "feat: add new DOM Policy protection throughout" - }, - { - "author": "beachball", - "package": "@microsoft/fast-foundation", - "comment": "Bump @microsoft/fast-element to v2.0.0-beta.18", - "commit": "416dc9167e9d41e6ffe11d87ed79b2f455357923" - } - ], - "none": [ - { - "author": "steph@huynhicode.dev", - "package": "@microsoft/fast-foundation", - "commit": "c35569f91f83e3c776461624d80dc32c8fa50823", - "comment": "update links for svelte and vite integration guides - current and legacy doc versions" - } - ] - } - }, - { - "date": "Fri, 04 Nov 2022 22:28:49 GMT", - "tag": "@microsoft/fast-foundation_v3.0.0-alpha.21", - "version": "3.0.0-alpha.21", - "comments": { - "prerelease": [ - { - "author": "roeisenb@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "9c594ef006d5189b3660de0e4d61dd6c5bb16496", - "comment": "feat: enable using design tokens in html" - } - ] - } - }, - { - "date": "Tue, 01 Nov 2022 23:26:26 GMT", - "tag": "@microsoft/fast-foundation_v3.0.0-alpha.20", - "version": "3.0.0-alpha.20", - "comments": { - "prerelease": [ - { - "author": "beachball", - "package": "@microsoft/fast-foundation", - "comment": "Bump @microsoft/fast-element to v2.0.0-beta.17", - "commit": "32d18d0900047899d1dadfe94f7923b6164b0cf3" - } - ] - } - }, - { - "date": "Fri, 28 Oct 2022 20:44:44 GMT", - "tag": "@microsoft/fast-foundation_v3.0.0-alpha.19", - "version": "3.0.0-alpha.19", - "comments": { - "prerelease": [ - { - "author": "863023+radium-v@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "7aaf156483ac6f5922a529b5b54e04e87445d882", - "comment": "use floating-ui for menu-item submenus" - }, - { - "author": "863023+radium-v@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "45b9c12961ea49694276b6a6d4d1f932ee9f83e8", - "comment": "use floating-ui for select and combobox" - }, - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "a614cb8270fe4b1d389cc3775c96913424dfc71b", - "comment": "remove indent logic from foundation menu and menu item, move to example" - }, - { - "author": "tebin.raouf@thomsonreuters.com", - "package": "@microsoft/fast-foundation", - "commit": "f7186f122613e3cc66f9cf3700138c2b41175ed4", - "comment": "remove unnecessary composedParent & composedContains exports from Foundation" - }, - { - "author": "beachball", - "package": "@microsoft/fast-foundation", - "comment": "Bump @microsoft/fast-element to v2.0.0-beta.16", - "commit": "5b745b1fb3bf249a7a2d172b7fb69cb08694aadd" - } - ] - } - }, - { - "date": "Tue, 25 Oct 2022 20:24:32 GMT", - "tag": "@microsoft/fast-foundation_v3.0.0-alpha.18", - "version": "3.0.0-alpha.18", - "comments": { - "prerelease": [ - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "2455b606ad905219af52f15e35a74e20921e2eb4", - "comment": "add readonly property to identify tree items and udpate isTreeItemElement check" - }, - { - "author": "32497422+KingOfTac@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "e2604dd734275f78cfb577527c48b9c014f0929e", - "comment": "remove unnecessary click handler from legacy button span implementation" - }, - { - "author": "beachball", - "package": "@microsoft/fast-foundation", - "comment": "Bump @microsoft/fast-element to v2.0.0-beta.15", - "commit": "220cc7e0e0de490e51cc8b6f42ff46b03228beaa" - } - ], - "none": [ - { - "author": "nicholasrice@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "016cbf86b111923d2424f9d44e707efb80750cde", - "comment": "Migrate DesignToken tests to Playwright" - } - ] - } - }, - { - "date": "Fri, 14 Oct 2022 18:26:11 GMT", - "tag": "@microsoft/fast-foundation_v3.0.0-alpha.17", - "version": "3.0.0-alpha.17", - "comments": { - "prerelease": [ - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "bcfbcb5be4433fb1fb0fab1697f13d345980db87", - "comment": "indeterminate checkboxes should set an aria-checked state of mixed" - }, - { - "author": "robarb@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "dbe2989d20201028d3e4b25ae37172bbfcc7439d", - "comment": "feat: calendar attr to adjust weekday start" - }, - { - "author": "beachball", - "package": "@microsoft/fast-foundation", - "comment": "Bump @microsoft/fast-element to v2.0.0-beta.14", - "commit": "bcfbcb5be4433fb1fb0fab1697f13d345980db87" - } - ] - } - }, - { - "date": "Mon, 10 Oct 2022 20:28:02 GMT", - "tag": "@microsoft/fast-foundation_v3.0.0-alpha.16", - "version": "3.0.0-alpha.16", - "comments": { - "prerelease": [ - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "ed2977ef6556964e68ea3ab0e4951320a1527baf", - "comment": "revert tree item changes from playwright migration" - }, - { - "author": "beachball", - "package": "@microsoft/fast-foundation", - "comment": "Bump @microsoft/fast-element to v2.0.0-beta.13", - "commit": "ed2977ef6556964e68ea3ab0e4951320a1527baf" - } - ] - } - }, - { - "date": "Thu, 06 Oct 2022 23:21:20 GMT", - "tag": "@microsoft/fast-foundation_v3.0.0-alpha.15", - "version": "3.0.0-alpha.15", - "comments": { - "prerelease": [ - { - "author": "ryan@ryanmerrill.net", - "package": "@microsoft/fast-foundation", - "commit": "30a9e92c29e4613217bee0588f0c0935777032c8", - "comment": "Adds ability to close menu with Escape key" - }, - { - "author": "beachball", - "package": "@microsoft/fast-foundation", - "comment": "Bump @microsoft/fast-element to v2.0.0-beta.12", - "commit": "a69c2e3c0700918fef5ba934909781cc8ab71384" - } - ] - } - }, - { - "date": "Wed, 05 Oct 2022 23:26:01 GMT", - "tag": "@microsoft/fast-foundation_v3.0.0-alpha.14", - "version": "3.0.0-alpha.14", - "comments": { - "none": [ - { - "author": "nicholasrice@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "21d1de94be2b9399ddc43a2b93c6483fa7304591", - "comment": "remove polyfills from storybook" - } - ], - "prerelease": [ - { - "author": "beachball", - "package": "@microsoft/fast-foundation", - "comment": "Bump @microsoft/fast-element to v2.0.0-beta.11", - "commit": "21d1de94be2b9399ddc43a2b93c6483fa7304591" - } - ] - } - }, - { - "date": "Mon, 03 Oct 2022 23:44:38 GMT", - "tag": "@microsoft/fast-foundation_v3.0.0-alpha.13", - "version": "3.0.0-alpha.13", - "comments": { - "prerelease": [ - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "e23f4375f183f0672f9aeafd0e58411adb66ae90", - "comment": "remove classes from host elements, add attributes to migrate observables, use data-t where it makes sensse" - }, - { - "author": "jes@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "81020717b427f8a162db99590d8cf271da945182", - "comment": "fix: remove class from hs template root" - }, - { - "author": "beachball", - "package": "@microsoft/fast-foundation", - "comment": "Bump @microsoft/fast-element to v2.0.0-beta.10", - "commit": "e23f4375f183f0672f9aeafd0e58411adb66ae90" - } - ], - "none": [ - { - "author": "yinon@hotmail.com", - "package": "@microsoft/fast-foundation", - "commit": "836f35843e8fe1a95c360c41329ae73297a5dbb9", - "comment": "number field documentation link to MDN spec corrected" - }, - { - "author": "863023+radium-v@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "b5b0aa90e37aa4141b49c29c9c6289570c5d6562", - "comment": "adjust tests to wait for stable state when needed" - } - ] - } - }, - { - "date": "Wed, 28 Sep 2022 20:45:51 GMT", - "tag": "@microsoft/fast-foundation_v3.0.0-alpha.12", - "version": "3.0.0-alpha.12", - "comments": { - "prerelease": [ - { - "author": "beachball", - "package": "@microsoft/fast-foundation", - "comment": "Bump @microsoft/fast-element to v2.0.0-beta.9", - "commit": "08fab33015853b7f820fdfdac2aecddfeb31843f" - } - ] - } - }, - { - "date": "Tue, 27 Sep 2022 22:31:52 GMT", - "tag": "@microsoft/fast-foundation_v3.0.0-alpha.11", - "version": "3.0.0-alpha.11", - "comments": { - "prerelease": [ - { - "author": "beachball", - "package": "@microsoft/fast-foundation", - "comment": "Bump @microsoft/fast-element to v2.0.0-beta.8", - "commit": "8834c6732c727d39f92f72b197388453a9c17f9b" - } - ] - } - }, - { - "date": "Fri, 23 Sep 2022 22:53:27 GMT", - "tag": "@microsoft/fast-foundation_v3.0.0-alpha.10", - "version": "3.0.0-alpha.10", - "comments": { - "prerelease": [ - { - "author": "roeisenb@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "1646b26450a08a77c8bd6302560fe12cc6989ae1", - "comment": "feat: update foundation to new capture type" - }, - { - "author": "863023+radium-v@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "ec2b158dcf39c8b4152b22c3b65963046b473e17", - "comment": "Convert karma and mocha tests to playwright" - }, - { - "author": "roeisenb@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "1039218eafa9a8dbea9da94e1c7803de48d1484c", - "comment": "fix(fast-foundation): update mixin helper to use new attribute api" - }, - { - "author": "roeisenb@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "2edd63a8abe24c68cfc7c76d773c912c6f2d6543", - "comment": "fix: update foundation to use the new behavior API" - }, - { - "author": "yinon@hotmail.com", - "package": "@microsoft/fast-foundation", - "commit": "cc49283b26b17f53edd5d4f8834207666315c910", - "comment": "removed redundant role setting in fast foundation menu-item template" - }, - { - "author": "beachball", - "package": "@microsoft/fast-foundation", - "comment": "Bump @microsoft/fast-element to v2.0.0-beta.7", - "commit": "1646b26450a08a77c8bd6302560fe12cc6989ae1" - } - ], - "none": [ - { - "author": "863023+radium-v@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "1884339a92b43c66fe8df992aa7c23d1feab4b41", - "comment": "fix test fixture rendering" - }, - { - "author": "863023+radium-v@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "12d3e6cedcbdc4729af33d1b52c874d222569279", - "comment": "fix storybook story bugs" - } - ] - } - }, - { - "date": "Thu, 01 Sep 2022 21:53:34 GMT", - "tag": "@microsoft/fast-foundation_v3.0.0-alpha.9", - "version": "3.0.0-alpha.9", - "comments": { - "none": [ - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "4109784a8717d0e55544c5b6637ad1336fea63c8", - "comment": "remove alt and src from avatar spec as they do not exist as attributes" - } - ], - "prerelease": [ - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "1d0341d86c9537628d7f345ff644a4a7ad6a8b3c", - "comment": "remove boolean logical operator use for setting default slotted content in favor of nullish coalescing operator" - }, - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "3b9ce1bbe8ca4a800d37f57a328e02f89491b80f", - "comment": "update templates to ensure component classes can be extended" - }, - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "da67749bf6b068ad8d143b5c7b3885b868d919a3", - "comment": "remove when directive from flipper" - }, - { - "author": "jes@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "6b0f08574475d8b28cc2df67bf72b9041c2ad285", - "comment": "call change when search component clear button is clicked" - }, - { - "author": "nicholasrice@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "ad8cef8b3f71fdffd50ddd9659b79a17ccca00b2", - "comment": "Lazily attach FASTDesignTokenNode to the default node to prevent errors\"" - }, - { - "author": "roeisenb@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "da9ebbe1b7471cd4e6f7b74f2f9bf02fcc54da4f", - "comment": "fix: update foundation to use new import paths" - }, - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "e0d263dd185a5f98a4634d4370f1b908507385c3", - "comment": "remove references to renderCollapsedNodes and renderCollapsedChildren from tree view and tree item" - }, - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "b3363d93a630c95dc052ac0d5d5fd98d45061b7a", - "comment": "ensure switch cannot be invoked via keyboard when in readonly mode" - }, - { - "author": "nicholasrice@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "e369dcd43050738ee30df7a7eef5fc497114106a", - "comment": "Adds DesignTokenStyleTarget to support DesignToken style collection for SSR" - }, - { - "author": "beachball", - "package": "@microsoft/fast-foundation", - "comment": "Bump @microsoft/fast-element to v2.0.0-beta.6", - "commit": "6b0f08574475d8b28cc2df67bf72b9041c2ad285" - } - ] - } - }, - { - "date": "Fri, 26 Aug 2022 18:06:43 GMT", - "tag": "@microsoft/fast-foundation_v3.0.0-alpha.8", - "version": "3.0.0-alpha.8", - "comments": { - "prerelease": [ - { - "author": "863023+radium-v@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "6fae6f01978c40a52121aed6700f4429e12e69af", - "comment": "normalize storybook stories" - }, - { - "author": "mathieulavoie94@gmail.com", - "package": "@microsoft/fast-foundation", - "commit": "84726aa1312068d10df176709d760764d577420f", - "comment": "fix(tabs): home and end navigation" - }, - { - "author": "nicholasrice@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "7ca925b4dba0cf2f376cb8e1a639b31bac8bdd1f", - "comment": "Fix constraint validation in focus-delegated components" - } - ] - } - }, - { - "date": "Thu, 18 Aug 2022 20:46:10 GMT", - "tag": "@microsoft/fast-foundation_v3.0.0-alpha.7", - "version": "3.0.0-alpha.7", - "comments": { - "prerelease": [ - { - "author": "7282195+m-akinc@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "03fed0cd16ad25a294f5890555dbeb2348eb251e", - "comment": "change select() method to public on number field, text field, and text area" - }, - { - "author": "32497422+KingOfTac@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "29308db7920baaaac5b31b206d551669e165bc06", - "comment": "add subpath export for package.json to packages" - }, - { - "author": "stephcomeau@msn.com", - "package": "@microsoft/fast-foundation", - "commit": "16cc1d791b4a2e02459cdf9ccf42d6c2d516fd02", - "comment": "anchored-region checks local shadow dom" - }, - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "7934089e4b161ea5a14da817ef2439c0fb47786b", - "comment": "use nullableNumberConverter for tooltip delay attribute" - }, - { - "author": "nicholasrice@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "d1492e8e378c30b684f4ff4bed5f86b99a88934f", - "comment": "adding event-based resolution strategy export" - }, - { - "author": "nicholasrice@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "ef35c85812c742aea0d53087174a059109e83731", - "comment": "refactor to allow arbitrary PropertyTarget types for DesignToken roots" - }, - { - "author": "robarb@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "fb8f6e34953499631fee7b6087135c4d979ad651", - "comment": "hidden horizontal-scroll fix" - }, - { - "author": "nicholasrice@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "218cfc014f5c76464493725f83bd883e8b07defa", - "comment": "Refactor DesignToken to provide a resolve function to derived token values, implements WebComponent implementation on top of isomorphic DesignToken infrastructure" - }, - { - "author": "beachball", - "package": "@microsoft/fast-foundation", - "comment": "Bump @microsoft/fast-element to v2.0.0-beta.5", - "commit": "0b57f1bc812e8e6371b7d27bb625f99a25bfaa66" - } - ] - } - }, - { - "date": "Wed, 27 Jul 2022 17:36:33 GMT", - "tag": "@microsoft/fast-foundation_v3.0.0-alpha.6", - "version": "3.0.0-alpha.6", - "comments": { - "prerelease": [ - { - "author": "robarb@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "7df4548954621d6247ab7fe3fae1a1ba0d33294b", - "comment": "Using getBoundingClientRect for horizontal-scroll" - }, - { - "author": "47367562+bheston@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "0f63894082e89bbd7502e507d92932561322899e", - "comment": "Removed the `fill`, `color`, and `shape` attributes and styling from Avatar" - } - ] - } - }, - { - "date": "Mon, 18 Jul 2022 21:10:01 GMT", - "tag": "@microsoft/fast-foundation_v3.0.0-alpha.5", - "version": "3.0.0-alpha.5", - "comments": { - "prerelease": [ - { - "author": "32497422+KingOfTac@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "2ff46a32cdd9af12b236d0e2f3436a4de782e8ee", - "comment": "add export for custom elements manifest" - }, - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "7da128444486845d714da4cd774910b5055107fe", - "comment": "add start and end slots to tab" - }, - { - "author": "roeisenb@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "27dc848327b25328e428f67505684d2171b58711", - "comment": "feat: update foundation to new binding APIs" - }, - { - "author": "roeisenb@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "aacfde6d1f52a20af5511c5e792f730bd091d452", - "comment": "feat: move testing and dependency injection to fast-element" - }, - { - "author": "roeisenb@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "b32eb1004960da95b74dba7f111ee859b6655896", - "comment": "feat: remove design system, foundation element & related infrastructure" - }, - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "c8bf61bf8dba9ebcc94b82a50f456f0c18cdd69f", - "comment": "update breadcrumb item to always use an anchor and ensure aria-current is applied correctly in breadcrumb" - }, - { - "author": "chhol@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "ee4b085c252768fc70309459ecc0625d7c382de9", - "comment": "add activeid to accordion change event" - }, - { - "author": "47367562+bheston@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "01ce4ed59b395177f5fdc2ccacf32442addd1d25", - "comment": "Removed the `fill` and `color` attributes and styling from Badge" - }, - { - "author": "roeisenb@microsoft.com", - "package": "@microsoft/fast-foundation", - "commit": "7f4d6b5587f6eff52e5b7f414e27543bb4d7772d", - "comment": "feat: enable fallback container creation for dependency injection location APIs" - }, - { - "author": "stephcomeau@msn.com", - "package": "@microsoft/fast-foundation", - "commit": "1d0a4a3ef3153421e5bfb7d8f92d1f3131567f6f", - "comment": "accordion verifies change events" - }, - { - "author": "863023+radium-v@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "0466b2c5c45aed2ea39466d1657aca027e56a955", - "comment": "add storybook to fast-foundation" - }, - { - "author": "beachball", - "package": "@microsoft/fast-foundation", - "comment": "Bump @microsoft/fast-element to v2.0.0-beta.4", - "commit": "2ff46a32cdd9af12b236d0e2f3436a4de782e8ee" - } - ], - "none": [ - { - "author": "alfkonee@hotmail.com", - "package": "@microsoft/fast-foundation", - "commit": "c383486d652ada3e6454c70a75a45562022376cc", - "comment": "docs: introduction page updates (#6173)" - }, - { - "author": "prudepixie@users.noreply.github.com", - "package": "@microsoft/fast-foundation", - "commit": "e7a233153781e3dd02adada2373748d7d0877cc1", - "comment": "update integration docs for react and webpack" - }, - { - "author": "steph@huynhicode.dev", - "package": "@microsoft/fast-foundation", - "commit": "1e4a383fada3a4895623e6b54088f9f2a07c7a78", - "comment": "add rollup integration guide" - }, - { - "author": "steph@huynhicode.dev", - "package": "@microsoft/fast-foundation", - "commit": "aeedccf89e6227b7e47ad5db9ba713046f3a5244", - "comment": "add Svelte integration guides and starter projects" - } - ] - } - }, - { - "date": "Wed, 22 Jun 2022 20:17:50 GMT", - "tag": "@microsoft/fast-foundation_v3.0.0-alpha.4", - "version": "3.0.0-alpha.4", - "comments": { - "prerelease": [ - { - "comment": "handle change for source.max set to sliderMaxPosition", - "author": "email not defined", - "commit": "eec60d5d7a59371d2429cbd7147f2671f35d705c", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "fast-foundation checkbox - turn off indeterminate on user `checked` change", - "author": "yinon@hotmail.com", - "commit": "a30264352369e9e9422a2616e1e35597430a21c9", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "prevent keyboard events with space when checkbox is readonly", - "author": "chhol@microsoft.com", - "commit": "6f1b027e7710475e30b83db10198cab2aafda146", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "feat: horizontal-scroll scroll item into view", - "author": "robarb@microsoft.com", - "commit": "e7893d838020d9fe721fcc3e4547ee8d98ce5cda", - "package": "@microsoft/fast-foundation" - } - ], - "none": [ - { - "comment": "add vite integration guide and starter templates", - "author": "steph@huynhicode.dev", - "commit": "267a014a3de09048e2e7cc22ad58a2cd2da25a3f", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Wed, 15 Jun 2022 17:41:10 GMT", - "tag": "@microsoft/fast-foundation_v3.0.0-alpha.3", - "version": "3.0.0-alpha.3", - "comments": { - "prerelease": [ - { - "comment": "chore: fix package.json type fields", - "author": "roeisenb@microsoft.com", - "commit": "e86a638b9e84cbf36d950025889742944e68e512", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "only rollup foundation after compiling with tsc", - "author": "863023+radium-v@users.noreply.github.com", - "commit": "ab05c42ea643940606f9dd2ec5e96b0eda76acc7", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Compare radio value property instead of attribute when value changes", - "author": "sknoslo@gmail.com", - "commit": "ab36086beb9868b2f3a907537c86ed42344e43e2", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "feat: simplify execution context to align closer with v1", - "author": "roeisenb@microsoft.com", - "commit": "488d051999c43b93a0beef4db30a2bddd6bbdc64", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "feat: implement W3C WC community context protocol and integrate with DI", - "author": "roeisenb@microsoft.com", - "commit": "c45297c0ca48b7e5f4343ba48e5183f2bccdb946", - "package": "@microsoft/fast-foundation" - } - ], - "none": [ - { - "comment": "Bump @microsoft/fast-web-utilities to v6.0.0", - "author": "7559015+janechu@users.noreply.github.com", - "commit": "a6b2a570c1cb592bc92b4c9d8366d197658819ae", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Wed, 01 Jun 2022 22:21:24 GMT", - "tag": "@microsoft/fast-foundation_v3.0.0-alpha.2", - "version": "3.0.0-alpha.2", - "comments": { - "prerelease": [ - { - "comment": "Force version update", - "author": "nicholasrice@users.noreply.github.com", - "commit": "e4740b8f077b77954ae82ff698f144181e1504a7", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Wed, 01 Jun 2022 17:53:14 GMT", - "tag": "@microsoft/fast-foundation_v3.0.0-alpha.1", - "version": "3.0.0-alpha.1", - "comments": { - "prerelease": [ - { - "comment": "fix: update foundation and components template types", - "author": "roeisenb@microsoft.com", - "commit": "4699e77715068f8610aae908ede6356a249574b6", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "chore: update imports to match latest fast-element exports", - "author": "roeisenb@microsoft.com", - "commit": "4699e77715068f8610aae908ede6356a249574b6", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "fix incorrect and unsemantic slot names for search", - "author": "chhol@microsoft.com", - "commit": "4699e77715068f8610aae908ede6356a249574b6", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "fix: update to latest fast-element and change exports", - "author": "roeisenb@microsoft.com", - "commit": "4699e77715068f8610aae908ede6356a249574b6", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "update the default value of dialog's modal attribute to false", - "author": "chhol@microsoft.com", - "commit": "4699e77715068f8610aae908ede6356a249574b6", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "remove unnecessary DOM nodes from start/end slot templates", - "author": "chhol@microsoft.com", - "commit": "4699e77715068f8610aae908ede6356a249574b6", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Updated to use the new FAST element 2.0 APIs for creating behaviors and creating element styles", - "author": "7559015+janechu@users.noreply.github.com", - "commit": "4699e77715068f8610aae908ede6356a249574b6", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "feat: officially expose testing helpers", - "author": "roeisenb@microsoft.com", - "commit": "4699e77715068f8610aae908ede6356a249574b6", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "chore: configure fast-foundation for internals stripping", - "author": "roeisenb@microsoft.com", - "commit": "4699e77715068f8610aae908ede6356a249574b6", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "change activeindicator attribute in tabs to hide-active-indicator to better support boolean attribute behavior", - "author": "chhol@microsoft.com", - "commit": "4699e77715068f8610aae908ede6356a249574b6", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "remove class and part names from slots in fast foundation templates", - "author": "chhol@microsoft.com", - "commit": "4699e77715068f8610aae908ede6356a249574b6", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Deprecates style utilities and hard-codes focus-visible value", - "author": "nicholasrice@users.noreply.github.com", - "commit": "4699e77715068f8610aae908ede6356a249574b6", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "update attribute and observable change handlers with internal logic to be protected instead of private", - "author": "chhol@microsoft.com", - "commit": "4699e77715068f8610aae908ede6356a249574b6", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "fix: update foundation to new CSSDirective API", - "author": "roeisenb@microsoft.com", - "commit": "4699e77715068f8610aae908ede6356a249574b6", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "fix: update foundation to new APIs", - "author": "roeisenb@microsoft.com", - "commit": "4699e77715068f8610aae908ede6356a249574b6", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "fix: update fast-foundation to not use deprecated APIs", - "author": "roeisenb@microsoft.com", - "commit": "4699e77715068f8610aae908ede6356a249574b6", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "remove deprecated item slot name on accordion as it is the default slot", - "author": "chhol@microsoft.com", - "commit": "4699e77715068f8610aae908ede6356a249574b6", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Set prerelease version", - "author": "nicholasrice@users.noreply.github.com", - "commit": "5b313a3262b977acbee3c2efac87d0d14a82f792", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "fix: update templates to use classList and fix classList bug", - "author": "roeisenb@microsoft.com", - "commit": "4699e77715068f8610aae908ede6356a249574b6", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "chore: fast-foundation package and build modernization", - "author": "roeisenb@microsoft.com", - "commit": "4699e77715068f8610aae908ede6356a249574b6", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "change trapFocus on dialog to noFocusTrap to better support boolean attributes", - "author": "chhol@microsoft.com", - "commit": "4699e77715068f8610aae908ede6356a249574b6", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "rename title attribute on disclosure to summary", - "author": "chhol@microsoft.com", - "commit": "4699e77715068f8610aae908ede6356a249574b6", - "package": "@microsoft/fast-foundation" - } - ], - "none": [ - { - "comment": "update api extractor and typescript to use the latest versions", - "author": "chhol@microsoft.com", - "commit": "4699e77715068f8610aae908ede6356a249574b6", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Bump @microsoft/fast-element to v2.0.0-beta.1", - "author": "roeisenb@microsoft.com", - "commit": "4699e77715068f8610aae908ede6356a249574b6", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Bump @microsoft/fast-web-utilities to v6.0.0", - "author": "roeisenb@microsoft.com", - "commit": "4699e77715068f8610aae908ede6356a249574b6", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Sun, 29 May 2022 07:08:52 GMT", - "tag": "@microsoft/fast-foundation_v2.46.9", - "version": "2.46.9", - "comments": { - "patch": [ - { - "comment": "fix: fast-foundation - 'get' and 'set' accessor must have the same type (#5964)", - "author": "aagharat@dstworldwideservices.com", - "commit": "36a803c13f0d1ff9bf61d0769d1f2a142be01231", - "package": "@microsoft/fast-foundation" - } - ], - "none": [ - { - "comment": "docs: update angular.md for two-way binding errors", - "author": "roeisenb@microsoft.com", - "commit": "b3eec2f46380d0db7fb3656e16fde57198813f87", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "add md extensions to referenced links for integration guides", - "author": "steph@huynhicode.dev", - "commit": "283b4838d46ed83c70ff4ad91f7f72a4936d59bf", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Bump @microsoft/fast-element to v1.10.2", - "author": "steph@huynhicode.dev", - "commit": "283b4838d46ed83c70ff4ad91f7f72a4936d59bf", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Thu, 26 May 2022 07:11:44 GMT", - "tag": "@microsoft/fast-foundation_v2.46.8", - "version": "2.46.8", - "comments": { - "patch": [ - { - "comment": "Revert \"fix: add missing required attribute binding to switch template (#6014)\"", - "author": "burtonsmith@microsoft.com", - "commit": "cbee01dd556ff6f32e1d35aef07eaad41e4eb44e", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Wed, 25 May 2022 07:09:21 GMT", - "tag": "@microsoft/fast-foundation_v2.46.7", - "version": "2.46.7", - "comments": { - "patch": [ - { - "comment": "add missing binding for required attribute in the switch template", - "author": "chhol@microsoft.com", - "commit": "352e888d8e30f4c1174264d15139f2cffc06c81a", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Tue, 24 May 2022 07:10:02 GMT", - "tag": "@microsoft/fast-foundation_v2.46.6", - "version": "2.46.6", - "comments": { - "patch": [ - { - "comment": "Bump @microsoft/fast-element to v1.10.2", - "author": "roeisenb@microsoft.com", - "commit": "476be7672653b2e63b9ab771949718aa8f43df0d", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Sun, 22 May 2022 07:09:02 GMT", - "tag": "@microsoft/fast-foundation_v2.46.5", - "version": "2.46.5", - "comments": { - "patch": [ - { - "comment": "disable keyboard controls for readonly sliders", - "author": "burtonsmith@microsoft.com", - "commit": "3e3309619b1292242881016ba46a4ef720a41f80", - "package": "@microsoft/fast-foundation" - } - ], - "none": [ - { - "comment": "Update blazor.md", - "author": "vnbaaij@outlook.com", - "commit": "d1f012e9ce9e6f7d3a0a199cbb15baa917f583af", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Thu, 19 May 2022 07:09:40 GMT", - "tag": "@microsoft/fast-foundation_v2.46.4", - "version": "2.46.4", - "comments": { - "patch": [ - { - "comment": "Handle disabled and hidden items in toolbar", - "author": "20542556+mollykreis@users.noreply.github.com", - "commit": "c429fa743a3f03fc4e90b31ae112c7a53d8426fe", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Sun, 15 May 2022 07:08:25 GMT", - "tag": "@microsoft/fast-foundation_v2.46.3", - "version": "2.46.3", - "comments": { - "none": [ - { - "comment": "Documentation updates on Blazor", - "author": "16669785+awentzel@users.noreply.github.com", - "commit": "529b74d8b42e66266769c5d58f3a24fc93c3d3ba", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Tue, 10 May 2022 07:11:04 GMT", - "tag": "@microsoft/fast-foundation_v2.46.3", - "version": "2.46.3", - "comments": { - "patch": [ - { - "comment": "select ignores l&r arrow keys", - "author": "scomea@microsoft.com", - "commit": "4a3175e8585af03e97b388849f697f8ee5dbe424", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Sun, 08 May 2022 07:08:18 GMT", - "tag": "@microsoft/fast-foundation_v2.46.2", - "version": "2.46.2", - "comments": { - "none": [ - { - "comment": "fix test typings that were throwing", - "author": "chhol@microsoft.com", - "commit": "890ff058b8771c84a9e669b4e9202c43f4d3e7fc", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Fri, 06 May 2022 20:58:02 GMT", - "tag": "@microsoft/fast-foundation_v2.46.2", - "version": "2.46.2", - "comments": { - "none": [ - { - "comment": "update api extractor to 7.23.1 to ensure we can support TS 4.7 internal API changes", - "author": "chhol@microsoft.com", - "commit": "fbc6a7fb670453322c93f8f12a223febad86f735", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Removed comment blocks from variable type markdown in README files", - "author": "44823142+williamw2@users.noreply.github.com", - "commit": "00f9a95e0f1be1b28a0f8b0584d1ef47ce08026e", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Thu, 05 May 2022 07:11:41 GMT", - "tag": "@microsoft/fast-foundation_v2.46.2", - "version": "2.46.2", - "comments": { - "patch": [ - { - "comment": "fix positioning of select dropdown", - "author": "abris96@gmail.com", - "commit": "10169e77fc1ee328c0e94e082e120e8d1c4171b5", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "reset selection range when selecting option with cursor", - "author": "abris96@gmail.com", - "commit": "5b82a4b2aa6cf4d59bd4bb6a893764d3386dbf5d", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Wed, 04 May 2022 07:14:00 GMT", - "tag": "@microsoft/fast-foundation_v2.46.1", - "version": "2.46.1", - "comments": { - "none": [ - { - "comment": "update markdown files", - "author": "steph@huynhicode.dev", - "commit": "c49a98f7f1bd8e167b0b7a96a181990f9a675f34", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Bump @microsoft/fast-element to v1.10.1", - "author": "steph@huynhicode.dev", - "commit": "c49a98f7f1bd8e167b0b7a96a181990f9a675f34", - "package": "@microsoft/fast-foundation" - } - ], - "patch": [ - { - "comment": "convert enums to const objects and add supported typings", - "author": "chhol@microsoft.com", - "commit": "d39284193f6d476b5b40b0fad75d3dbd836d55da", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Tue, 03 May 2022 07:15:44 GMT", - "tag": "@microsoft/fast-foundation_v2.46.0", - "version": "2.46.0", - "comments": { - "none": [ - { - "comment": "add initial jsdocs for foundation elements", - "author": "chhol@microsoft.com", - "commit": "8327524eaf8175c89c435275974243ab09f3afed", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Update to resolve console warnings during doc build-out", - "author": "16669785+awentzel@users.noreply.github.com", - "commit": "069cd9621f3125c724ccbcd5b87294ff54739861", - "package": "@microsoft/fast-foundation" - } - ], - "patch": [ - { - "comment": "reflect option value changes in select", - "author": "john.kreitlow@microsoft.com", - "commit": "472d0b6cf9dcc6662e8d69c16689c073d34b9ca4", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "fix: selectedIndex property ignores disabled options in listbox and select", - "author": "john.kreitlow@microsoft.com", - "commit": "9c36455b834421930e930ca24da9bd3c066cb7b8", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "viewport lock + fill behavior", - "author": "scomea@microsoft.com", - "commit": "2a5734222653656a7a5050be6f086add956d6376", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Upgraded api-extractor", - "author": "44823142+williamw2@users.noreply.github.com", - "commit": "2341496a6fafe3051dc50333c21ca652026f725b", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Bump @microsoft/fast-element to v1.10.1", - "author": "44823142+williamw2@users.noreply.github.com", - "commit": "2341496a6fafe3051dc50333c21ca652026f725b", - "package": "@microsoft/fast-foundation" - } - ], - "minor": [ - { - "comment": "add slots and events documentation", - "author": "scomea@microsoft.com", - "commit": "bd6e458d5bbca8838ae4e555e2b32f28d1b310c4", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Sun, 01 May 2022 07:12:05 GMT", - "tag": "@microsoft/fast-foundation_v2.45.0", - "version": "2.45.0", - "comments": { - "patch": [ - { - "comment": "ensure that tabs and tabpanels without ids stay in sync", - "author": "chhol@microsoft.com", - "commit": "46f935158aca1a4b28c0d9b4e74c083b31a40fdb", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "trim extra spaces from the text property for listbox-option", - "author": "john.kreitlow@microsoft.com", - "commit": "df1e9195f57710b2781602ee37d1ae8123614013", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "fix keyboarding behavior for right and left arrow keys in Tree View", - "author": "chhol@microsoft.com", - "commit": "5db724976b6e1678e74a6cd51a5324c2b6186bba", - "package": "@microsoft/fast-foundation" - } - ], - "minor": [ - { - "comment": "add select method to number field, text field, and text area components", - "author": "chhol@microsoft.com", - "commit": "575c89b2e98afbf91b08c1e18f2a080a0b779052", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Thu, 28 Apr 2022 07:12:47 GMT", - "tag": "@microsoft/fast-foundation_v2.44.0", - "version": "2.44.0", - "comments": { - "minor": [ - { - "comment": "update displayed selected value in select component when an option changes", - "author": "john.kreitlow@microsoft.com", - "commit": "26474a333da31741df31e5acd86139ba0e9244ad", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Wed, 27 Apr 2022 07:21:09 GMT", - "tag": "@microsoft/fast-foundation_v2.43.0", - "version": "2.43.0", - "comments": { - "minor": [ - { - "comment": "update to typescript 4.6.2 and update ARIAMixin typings", - "author": "chhol@microsoft.com", - "commit": "35bdab45550b5d8b8762041110eccb06de78add5", - "package": "@microsoft/fast-foundation" - } - ], - "patch": [ - { - "comment": "Bump @microsoft/fast-web-utilities to v5.4.0", - "author": "chhol@microsoft.com", - "commit": "35bdab45550b5d8b8762041110eccb06de78add5", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Bump @microsoft/fast-element to v1.10.0", - "author": "chhol@microsoft.com", - "commit": "35bdab45550b5d8b8762041110eccb06de78add5", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Sun, 24 Apr 2022 07:13:26 GMT", - "tag": "@microsoft/fast-foundation_v2.42.2", - "version": "2.42.2", - "comments": { - "none": [ - { - "comment": "Update to fix broken links and grammar.", - "author": "16669785+awentzel@users.noreply.github.com", - "commit": "ed08697132b639f3104562b16a0dcf5c5653a878", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Thu, 21 Apr 2022 07:13:54 GMT", - "tag": "@microsoft/fast-foundation_v2.42.2", - "version": "2.42.2", - "comments": { - "none": [ - { - "comment": "Improve wording for usage of `@@`.", - "author": "eimantas@stork.software", - "commit": "0be3fad176207292996440f208bd1c9812499b46", - "package": "@microsoft/fast-foundation" - } - ], - "patch": [ - { - "comment": "Added support for styling slider value on the track", - "author": "47367562+bheston@users.noreply.github.com", - "commit": "20836e97d291137c5600fb4ee6d643c2b55b11ee", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Wed, 20 Apr 2022 07:13:17 GMT", - "tag": "@microsoft/fast-foundation_v2.42.1", - "version": "2.42.1", - "comments": { - "none": [ - { - "comment": "Pull up api-extractor.json to root and then extend it for each project", - "author": "stephanosp@microsoft.com", - "commit": "e3076337cbc2d260a497116061ee3bba3866a97d", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Sun, 17 Apr 2022 07:11:18 GMT", - "tag": "@microsoft/fast-foundation_v2.42.1", - "version": "2.42.1", - "comments": { - "none": [ - { - "comment": "Merge branch 'master' into wanFixString", - "author": "74849806+wannieman98@users.noreply.github.com", - "commit": "14bc5d5f2ae608328eb16ad7e619bab00415f60a", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Bump @microsoft/fast-element to v1.9.0", - "author": "74849806+wannieman98@users.noreply.github.com", - "commit": "14bc5d5f2ae608328eb16ad7e619bab00415f60a", - "package": "@microsoft/fast-foundation" - } - ], - "patch": [ - { - "comment": "fix: scrolling back from end and forward retains next flipper in horizontal-scroll", - "author": "robarb@microsoft.com", - "commit": "1aded3649afee9645a68d3f642876e543c5019b8", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Ensured that tabs without an ID use a unique ID to prevent duplicate IDs when multiple tabs are on a page", - "author": "chhol@microsoft.com", - "commit": "79fe8b9bb4fe572d191fb07e4a73811f54d35d47", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Ensure the skeleton component's object element is not included in the accessibility tree", - "author": "chhol@microsoft.com", - "commit": "91cfbfe096d74ad2bf5a9421fa718585b342a32e", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Thu, 14 Apr 2022 07:12:36 GMT", - "tag": "@microsoft/fast-foundation_v2.42.0", - "version": "2.42.0", - "comments": { - "minor": [ - { - "comment": "Implements `` element events on FastDialog", - "author": "web@bennypowers.com", - "commit": "9f670f6b0b5df7b2c07199883226e07779d77dc5", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "add multiselect mode to select", - "author": "john.kreitlow@microsoft.com", - "commit": "adc9a35efa8045a2b7d4a7b7fc71a386d511cbab", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Tue, 12 Apr 2022 07:13:35 GMT", - "tag": "@microsoft/fast-foundation_v2.41.1", - "version": "2.41.1", - "comments": { - "none": [ - { - "comment": "Bump @microsoft/fast-element to v1.9.0", - "author": "yinon@hotmail.com", - "commit": "3e4d72447520f40d234b1df2cc70446dcef8bb47", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Thu, 07 Apr 2022 07:12:06 GMT", - "tag": "@microsoft/fast-foundation_v2.41.1", - "version": "2.41.1", - "comments": { - "patch": [ - { - "comment": "Improved README markdown formatting", - "author": "44823142+williamw2@users.noreply.github.com", - "commit": "35cc415fde15cf07627ca3007024833689284f86", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Wed, 06 Apr 2022 07:12:42 GMT", - "tag": "@microsoft/fast-foundation_v2.41.0", - "version": "2.41.0", - "comments": { - "minor": [ - { - "comment": "convert fast-foundation to type:module", - "author": "nicholasrice@users.noreply.github.com", - "commit": "ddfcf336f25a3151e1c150534269900cb8131181", - "package": "@microsoft/fast-foundation" - } - ], - "patch": [ - { - "comment": "Added CEM Analyzer and API markdown to readme files", - "author": "44823142+williamw2@users.noreply.github.com", - "commit": "bab7cd7ad235cd94357019f19953ca91711f22c7", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Bump @microsoft/fast-element to v1.9.0", - "author": "nicholasrice@users.noreply.github.com", - "commit": "ead7f7340654236f2503359e2fc6f0b41639b507", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Sun, 03 Apr 2022 07:12:01 GMT", - "tag": "@microsoft/fast-foundation_v2.40.0", - "version": "2.40.0", - "comments": { - "minor": [ - { - "comment": "update aria-current for breadcrumb items when new nodes are appended", - "author": "chhol@microsoft.com", - "commit": "77cd8a472f4e898245d3da91dbe40e2771a439e5", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "remove fromView from aria mixin attributes", - "author": "chhol@microsoft.com", - "commit": "f2314d034b9471c84b8e485a5e814e4482b694d4", - "package": "@microsoft/fast-foundation" - } - ], - "none": [ - { - "comment": "Bump @microsoft/fast-element to v1.8.0", - "author": "47367562+bheston@users.noreply.github.com", - "commit": "35913ce3a2dcba83bebb63cce2b8edf4e9da7df9", - "package": "@microsoft/fast-foundation" - } - ], - "patch": [ - { - "comment": "Bump @microsoft/fast-web-utilities to v5.2.0", - "author": "nicholasrice@users.noreply.github.com", - "commit": "f6107c448ab6446667f4d9e86d9f9c11fff075aa", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Thu, 31 Mar 2022 07:13:31 GMT", - "tag": "@microsoft/fast-foundation_v2.39.0", - "version": "2.39.0", - "comments": { - "patch": [ - { - "comment": "fix hidden menu items should not be included in the tabindex", - "author": "chhol@microsoft.com", - "commit": "3739c60925bc91dada3aaa71a72af5392c731fc1", - "package": "@microsoft/fast-foundation" - } - ], - "minor": [ - { - "comment": "remove duplicate use of heading class in accordion item and update part location", - "author": "chhol@microsoft.com", - "commit": "33a990cffd8c8044e886c9d777e212fa67f60acf", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Sun, 27 Mar 2022 07:11:50 GMT", - "tag": "@microsoft/fast-foundation_v2.38.0", - "version": "2.38.0", - "comments": { - "minor": [ - { - "comment": "Changed Select open attribute to public", - "author": "44823142+williamw2@users.noreply.github.com", - "commit": "8c41d877143f04377fc599b533317c4d950ebb0b", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Add string literal union types to all foundation components that use an enum for attribute options", - "author": "hawkticehurst@gmail.com", - "commit": "ae1215660dfe15beaf95ec73f718570a19fc72c6", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Thu, 24 Mar 2022 07:12:08 GMT", - "tag": "@microsoft/fast-foundation_v2.37.2", - "version": "2.37.2", - "comments": { - "patch": [ - { - "comment": "Detect changes to start and end slots in toolbar", - "author": "20542556+mollykreis@users.noreply.github.com", - "commit": "03a237b0007f6e446242043ae17b142e5cbb5359", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Sun, 20 Mar 2022 07:15:44 GMT", - "tag": "@microsoft/fast-foundation_v2.37.1", - "version": "2.37.1", - "comments": { - "patch": [ - { - "comment": "Fix for default selection behavior for listbox and select", - "author": "26874831+atmgrifter00@users.noreply.github.com", - "commit": "1898cd9a73f2cf9496a2a78d18e13bd87aa012df", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Wed, 16 Mar 2022 07:12:41 GMT", - "tag": "@microsoft/fast-foundation_v2.37.0", - "version": "2.37.0", - "comments": { - "minor": [ - { - "comment": "enable no tabbing", - "author": "scomea@microsoft.com", - "commit": "09b97ab3e9d7c1d71a048667d0aa0368569ab64a", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Tue, 15 Mar 2022 07:12:38 GMT", - "tag": "@microsoft/fast-foundation_v2.36.1", - "version": "2.36.1", - "comments": { - "patch": [ - { - "comment": "anchored region not beta", - "author": "scomea@microsoft.com", - "commit": "b996b057e3adbd8642ca07fc1dc6245aea2d3e50", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "tree view single select", - "author": "scomea@microsoft.com", - "commit": "a8aada16c7b089728a13a6bb7d98b8b928bb2b4f", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Fri, 11 Mar 2022 23:46:34 GMT", - "tag": "@microsoft/fast-foundation_v2.36.0", - "version": "2.36.0", - "comments": { - "patch": [ - { - "comment": "use WeakMap to prevent leaking element references from FormAssociated", - "author": "nicholasrice@users.noreply.github.com", - "commit": "05aef922b364f63d3d56e165eeb46840dec43f32", - "package": "@microsoft/fast-foundation" - } - ], - "minor": [ - { - "comment": "BREAKING CHANGE: replace WC button with stock HTML button", - "author": "jes@microsoft.com", - "commit": "9b838f36e388958f927c1f6d80d6fa736186897c", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "implement attribute reflection directive", - "author": "nicholasrice@users.noreply.github.com", - "commit": "efe6e62397cac815b68a688624ae35a31b826a53", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Wed, 09 Mar 2022 07:12:32 GMT", - "tag": "@microsoft/fast-foundation_v2.35.2", - "version": "2.35.2", - "comments": { - "patch": [ - { - "comment": "Fix bug with menu-item indention", - "author": "20542556+mollykreis@users.noreply.github.com", - "commit": "b4549c8a383d6ac43d2967491e5596bbffb87d80", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Tue, 08 Mar 2022 07:12:45 GMT", - "tag": "@microsoft/fast-foundation_v2.35.1", - "version": "2.35.1", - "comments": { - "none": [ - { - "comment": "docs: clarify the need for z-index on dialogs", - "author": "yinon@hotmail.com", - "commit": "44585c02af4e1cb31f168a7188b4b5fc1d499557", - "package": "@microsoft/fast-foundation" - } - ], - "patch": [ - { - "comment": "Fix programmatic disable/enable of tabs", - "author": "5454342+brianehenry@users.noreply.github.com", - "commit": "8f5549b87ef12ce892ab29f61f8a51269b1674b0", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Sun, 06 Mar 2022 07:13:48 GMT", - "tag": "@microsoft/fast-foundation_v2.35.0", - "version": "2.35.0", - "comments": { - "patch": [ - { - "comment": "passive handlers", - "author": "scomea@microsoft.com", - "commit": "0a25cee7a43743313e2eb9073dcdd89caae1342a", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "tooltip hover", - "author": "scomea@microsoft.com", - "commit": "b9eb24ed3dd66f2daf51efc8594900213934d4c7", - "package": "@microsoft/fast-foundation" - } - ], - "minor": [ - { - "comment": "add corner positions to tooltip", - "author": "sethdonohue@Admins-MBP.guest.corp.microsoft.com", - "commit": "bdeeb23bbaa56433d650660387e852c5eef87fee", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Thu, 03 Mar 2022 07:12:03 GMT", - "tag": "@microsoft/fast-foundation_v2.34.0", - "version": "2.34.0", - "comments": { - "none": [ - { - "comment": "add documentation to support decorators in cra", - "author": "email not defined", - "commit": "26ce299730c2a97d931a4a87fc64ef6f92b5580c", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Wed, 02 Mar 2022 07:12:58 GMT", - "tag": "@microsoft/fast-foundation_v2.34.0", - "version": "2.34.0", - "comments": { - "patch": [ - { - "comment": "generate grid columns for manual grid", - "author": "scomea@microsoft.com", - "commit": "3c557446160ecdc358b46fd35d72d53555f02fe5", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "auto columns fix", - "author": "scomea@microsoft.com", - "commit": "8da160bf10fc106917053350491fb88162d8bc45", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Fixing no previous scroll when only 2 items", - "author": "robarb@microsoft.com", - "commit": "9306471bb094e369ceb42de732d48bd9e519f1eb", - "package": "@microsoft/fast-foundation" - } - ], - "minor": [ - { - "comment": "add mermaid support", - "author": "steph@huynhicode.dev", - "commit": "638bd1e86cd3ecf4223371b48a4290cc7c75d765", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Fri, 25 Feb 2022 17:09:32 GMT", - "tag": "@microsoft/fast-foundation_v2.33.6", - "version": "2.33.6", - "comments": { - "patch": [ - { - "comment": "Bump @microsoft/fast-element to v1.7.2", - "author": "roeisenb@microsoft.com", - "commit": "76a9c866277cd13a92a9ca6b3518eae2fb625d79", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Thu, 24 Feb 2022 22:21:55 GMT", - "tag": "@microsoft/fast-foundation_v2.33.5", - "version": "2.33.5", - "comments": { - "patch": [ - { - "comment": "Format improvement to match standards", - "author": "16669785+awentzel@users.noreply.github.com", - "commit": "59fa5dada57dc5f3313d34ff6bd2d9b0bac0dbfb", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "fix combobox and select position when set after init", - "author": "corylaviska@microsoft.com", - "commit": "ebe1234f5590f90a77493ff5ae0a30f850876f0a", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "allow programmatic control of the open property for select and combobox", - "author": "john.kreitlow@microsoft.com", - "commit": "2caf345e541780600f1f961c17a2be2a6300a02c", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Sun, 20 Feb 2022 07:16:20 GMT", - "tag": "@microsoft/fast-foundation_v2.33.4", - "version": "2.33.4", - "comments": { - "patch": [ - { - "comment": "tree view events", - "author": "scomea@microsoft.com", - "commit": "6cadbdf6f4001a087dddba6c863604055a1da4d2", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Tue, 15 Feb 2022 07:11:28 GMT", - "tag": "@microsoft/fast-foundation_v2.33.3", - "version": "2.33.3", - "comments": { - "patch": [ - { - "comment": "disable noImplicitAny in fast-foundation", - "author": "mathieu.lavoie@shopify.com", - "commit": "bbf4e532cf9263727ef1bd8afbc30d79d1104c03", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Thu, 10 Feb 2022 07:12:01 GMT", - "tag": "@microsoft/fast-foundation_v2.33.2", - "version": "2.33.2", - "comments": { - "patch": [ - { - "comment": "Fix initial select value when set early after connect", - "author": "5454342+brianehenry@users.noreply.github.com", - "commit": "b8e71f23c976545c16cd3ca05ee6dfc6dc47788f", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Wed, 09 Feb 2022 07:14:00 GMT", - "tag": "@microsoft/fast-foundation_v2.33.1", - "version": "2.33.1", - "comments": { - "patch": [ - { - "comment": "allow empty string values for listbox-option value attribute", - "author": "john.kreitlow@microsoft.com", - "commit": "273749d704826d646141a45c8f0f82763376b3f9", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Sun, 06 Feb 2022 07:15:20 GMT", - "tag": "@microsoft/fast-foundation_v2.33.0", - "version": "2.33.0", - "comments": { - "patch": [ - { - "comment": "ensure menu items update", - "author": "scomea@microsoft.com", - "commit": "37af91137f47310968d6a919173cc9af52556309", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "fix: diabled listbox missing styles & allows click", - "author": "jes@microsoft.com", - "commit": "eff36b2834b7709cc2281738007019fd264c3d31", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "fix: allow slider to show small increment changes", - "author": "jes@microsoft.com", - "commit": "5ed29351c24596c9190d39d7742bcb4e2d604324", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "fix: flippersHiddenFromAT shouldn't map to aria-hidden", - "author": "robarb@microsoft.com", - "commit": "e00944dc842ccb169bdffea88f040f74643577b6", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "tooltip anchor attribute updates work", - "author": "scomea@microsoft.com", - "commit": "5d514c718d70a68aee835018b27782555f903b59", - "package": "@microsoft/fast-foundation" - } - ], - "minor": [ - { - "comment": "add menu positioning to picker", - "author": "scomea@microsoft.com", - "commit": "41f6eb951d79573f3a79547c6100485e0935dad3", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "add multiselect functionality to listbox", - "author": "john.kreitlow@microsoft.com", - "commit": "45116d16f62f2087e3daf1ed0d5c25f8e5ce1ad3", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Wed, 02 Feb 2022 07:13:39 GMT", - "tag": "@microsoft/fast-foundation_v2.32.3", - "version": "2.32.3", - "comments": { - "patch": [ - { - "comment": "fix: February tests are failing in calendar tests", - "author": "robarb@microsoft.com", - "commit": "72efc898ed23b08c9e7668844bc3a97f81b2bde9", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "fix broken links and formatting", - "author": "john.kreitlow@microsoft.com", - "commit": "48779abc5f0f746dc5d67b9d3c2875f455374ee6", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Sun, 30 Jan 2022 07:12:35 GMT", - "tag": "@microsoft/fast-foundation_v2.32.2", - "version": "2.32.2", - "comments": { - "patch": [ - { - "comment": "convert functions to templates", - "author": "mathieulavoie94@gmail.com", - "commit": "690b6218efc355985e3d97283ad043e7d085ef3c", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Tue, 25 Jan 2022 07:11:53 GMT", - "tag": "@microsoft/fast-foundation_v2.32.1", - "version": "2.32.1", - "comments": { - "patch": [ - { - "comment": "Bump @microsoft/fast-web-utilities to v5.1.0", - "author": "john.kreitlow@microsoft.com", - "commit": "97f653f8ee62c74d47df9b60024ff8eef05c79d1", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Sun, 23 Jan 2022 07:13:56 GMT", - "tag": "@microsoft/fast-foundation_v2.32.0", - "version": "2.32.0", - "comments": { - "patch": [ - { - "comment": "use default slot in accordion", - "author": "mathieulavoie94@gmail.com", - "commit": "415e7a49570ead5856ab8a4587aa6dfddf8c898e", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Bump @microsoft/fast-element to v1.7.0", - "author": "scomea@microsoft.com", - "commit": "897c39862b58a63ad9900426ae6ae2f95d222e1e", - "package": "@microsoft/fast-foundation" - } - ], - "minor": [ - { - "comment": "feat: add `orientation` to divider", - "author": "jes@microsoft.com", - "commit": "9f8e045d9fa4b8cc35b9c1d8ebe72cb7da0fd4ff", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Thu, 20 Jan 2022 07:12:04 GMT", - "tag": "@microsoft/fast-foundation_v2.31.0", - "version": "2.31.0", - "comments": { - "minor": [ - { - "comment": "add checked property to listbox-option", - "author": "john.kreitlow@microsoft.com", - "commit": "89cb932580c74aa070e05a9cc04a3fbe1495c1f3", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Sun, 16 Jan 2022 07:11:36 GMT", - "tag": "@microsoft/fast-foundation_v2.30.0", - "version": "2.30.0", - "comments": { - "minor": [ - { - "comment": "Add valueAsNumber to number field and slider", - "author": "5454342+brianehenry@users.noreply.github.com", - "commit": "53475edb39a2f87f603858718fb2abd8095ab5f9", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Wed, 12 Jan 2022 07:11:42 GMT", - "tag": "@microsoft/fast-foundation_v2.29.0", - "version": "2.29.0", - "comments": { - "none": [ - { - "comment": "update verbiage and add FAST snippets plugin to vs code page", - "author": "steph@huynhicode.dev", - "commit": "cf702d75b566afb396ceead5378d13d8a6b7c432", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Tue, 11 Jan 2022 07:09:27 GMT", - "tag": "@microsoft/fast-foundation_v2.29.0", - "version": "2.29.0", - "comments": { - "none": [ - { - "comment": "update rollup-plugin-filesize from 8.0.2 to 9.1.2", - "author": "john.kreitlow@microsoft.com", - "commit": "af847f2749ff605cced426e55a1580ea85c89cb0", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Sun, 09 Jan 2022 07:11:51 GMT", - "tag": "@microsoft/fast-foundation_v2.29.0", - "version": "2.29.0", - "comments": { - "minor": [ - { - "comment": "fix accessibility for listbox, select, and combobox", - "author": "john.kreitlow@microsoft.com", - "commit": "256fe07122c2838e6bf0edd639a539b9ceeaa1bf", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Thu, 06 Jan 2022 07:11:52 GMT", - "tag": "@microsoft/fast-foundation_v2.28.0", - "version": "2.28.0", - "comments": { - "minor": [ - { - "comment": "fix: prevent events to propagate from disabled button (#4884)", - "author": "email not defined", - "commit": "fb22059b2594cc8a7ca32a1f14570b6393ecb68f", - "package": "@microsoft/fast-foundation" - } - ], - "patch": [ - { - "comment": "tooltip uses \"center\"", - "author": "scomea@microsoft.com", - "commit": "a4c2a7e9a3f94c7079b56ae324223e10457c042e", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Sun, 19 Dec 2021 07:12:39 GMT", - "tag": "@microsoft/fast-foundation_v2.27.3", - "version": "2.27.3", - "comments": { - "patch": [ - { - "comment": "Replace equality check with NaN with the Number.isNan function", - "author": "anthonystewart@google.com", - "commit": "e11044f4aa3552398d5d1a0eeee82b1596a83486", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "add queueUpdate for setStops in horzontal scroll", - "author": "sethdonohue@Admins-MBP.guest.corp.microsoft.com", - "commit": "610fa12d4b88d98c333817f0649407d0ad61f5c6", - "package": "@microsoft/fast-foundation" - } - ], - "none": [ - { - "comment": "add link to issue describing decorator incompatibility issues with create-react-app", - "author": "nicholasrice@users.noreply.github.com", - "commit": "927fcebb788e42d94464143f603c33700ec3fa0e", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Bump @microsoft/fast-element to v1.6.2", - "author": "steph@huynhicode.dev", - "commit": "5056e83234e1c758375fa4882943d104fb476ca2", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Wed, 15 Dec 2021 07:14:44 GMT", - "tag": "@microsoft/fast-foundation_v2.27.2", - "version": "2.27.2", - "comments": { - "patch": [ - { - "comment": "focus on combobox control when clicking an associated label", - "author": "john.kreitlow@microsoft.com", - "commit": "2c538ea8bcf3fd63d07521d9c8a9b889653cd889", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Tue, 14 Dec 2021 07:12:12 GMT", - "tag": "@microsoft/fast-foundation_v2.27.1", - "version": "2.27.1", - "comments": { - "none": [ - { - "comment": "Bump @microsoft/fast-element to v1.6.2", - "author": "roeisenb@microsoft.com", - "commit": "babdb99e832319eaee76465765f9e6b72911d473", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Wed, 08 Dec 2021 07:10:04 GMT", - "tag": "@microsoft/fast-foundation_v2.27.1", - "version": "2.27.1", - "comments": { - "none": [ - { - "comment": "Bump @microsoft/fast-element to v1.6.2", - "author": "roeisenb@microsoft.com", - "commit": "bd7d84152a823cc21aab0dfa196da9d663ad0778", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Thu, 02 Dec 2021 07:11:13 GMT", - "tag": "@microsoft/fast-foundation_v2.27.1", - "version": "2.27.1", - "comments": { - "none": [ - { - "comment": "corrections to Blazor, webpack, and cdn links", - "author": "roeisenb@microsoft.com", - "commit": "2ec536794820959f771ebbfe25efd5a4489e7a76", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "update react itegration docs to address Windows specific setup steps", - "author": "nicholasrice@users.noreply.github.com", - "commit": "5600019854840e196060023b1b095bbb544d9d1a", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Bump @microsoft/fast-element to v1.6.2", - "author": "roeisenb@microsoft.com", - "commit": "2ec536794820959f771ebbfe25efd5a4489e7a76", - "package": "@microsoft/fast-foundation" - } - ], - "patch": [ - { - "comment": "fix: disabled tree items fire", - "author": "jes@microsoft.com", - "commit": "a0545ff0a7209c43460fc07913aa18685a4851fd", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Tue, 23 Nov 2021 07:12:23 GMT", - "tag": "@microsoft/fast-foundation_v2.27.0", - "version": "2.27.0", - "comments": { - "minor": [ - { - "comment": "add `size` attribute to listbox element", - "author": "john.kreitlow@microsoft.com", - "commit": "caa956557ea1d8b7722665d228898df629d46cc2", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Thu, 11 Nov 2021 07:15:33 GMT", - "tag": "@microsoft/fast-foundation_v2.26.2", - "version": "2.26.2", - "comments": { - "patch": [ - { - "comment": "convert tsdoc-config dependency to dev-dependency", - "author": "nicholasrice@users.noreply.github.com", - "commit": "116f30b236deffd48ede5488d167934cf848c492", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Wed, 10 Nov 2021 07:12:54 GMT", - "tag": "@microsoft/fast-foundation_v2.26.1", - "version": "2.26.1", - "comments": { - "patch": [ - { - "comment": "Enabling setting number-field value through script", - "author": "robarb@microsoft.com", - "commit": "14151d5ffa234babf237c5ea32282c5514e94b96", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Tue, 09 Nov 2021 07:14:09 GMT", - "tag": "@microsoft/fast-foundation_v2.26.0", - "version": "2.26.0", - "comments": { - "minor": [ - { - "comment": "feat: add search web component", - "author": "jes@microsoft.com", - "commit": "1a510ffa425375688d06fd7d696666745d1b367e", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Thu, 04 Nov 2021 07:11:59 GMT", - "tag": "@microsoft/fast-foundation_v2.25.1", - "version": "2.25.1", - "comments": { - "patch": [ - { - "comment": "fix: change event emitted twice", - "author": "jes@microsoft.com", - "commit": "58db7046b41b9318e02a8c49a70392c7504c8c28", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Wed, 03 Nov 2021 07:12:39 GMT", - "tag": "@microsoft/fast-foundation_v2.25.0", - "version": "2.25.0", - "comments": { - "minor": [ - { - "comment": "add placeholder attr to picker", - "author": "scomea@microsoft.com", - "commit": "449315688a794e702936ba73ce5d2b23aa660720", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Sun, 31 Oct 2021 07:17:45 GMT", - "tag": "@microsoft/fast-foundation_v2.24.0", - "version": "2.24.0", - "comments": { - "minor": [ - { - "comment": "Added the CheckableFormAssociated mixin to better support the addition of current-checked property/attribute that allows for setting checked state via the .setAttribute() API. This change also converts two lifecycle hooks to methods from properties so that they can be handled correctly by the browser.", - "author": "nicholasrice@users.noreply.github.com", - "commit": "e92a16b95e8410d59b46978bce1b02d5b80fc004", - "package": "@microsoft/fast-foundation" - } - ], - "none": [ - { - "comment": "Adding calendar component spec", - "author": "robarb@microsoft.com", - "commit": "5acf6b4e040fc32ba3bb00c38ceb437b42af9eb9", - "package": "@microsoft/fast-foundation" - } - ], - "patch": [ - { - "comment": "fix: number-field increment decrement logic", - "author": "robarb@microsoft.com", - "commit": "1bb8f9783a48c8eef8c7d84c4d833a39f4f2d0d8", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "picker focus on input after selection", - "author": "scomea@microsoft.com", - "commit": "e0910d1c1dfe64702695794d9976350ffd53a77d", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "update fast eslint package version", - "author": "chhol@microsoft.com", - "commit": "a150068ee196e73fe7a4f7b538a38752e0e506ba", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Bump @microsoft/fast-element to v1.6.2", - "author": "chhol@microsoft.com", - "commit": "a150068ee196e73fe7a4f7b538a38752e0e506ba", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Bump @microsoft/fast-web-utilities to v5.0.2", - "author": "chhol@microsoft.com", - "commit": "a150068ee196e73fe7a4f7b538a38752e0e506ba", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Thu, 28 Oct 2021 07:15:32 GMT", - "tag": "@microsoft/fast-foundation_v2.23.2", - "version": "2.23.2", - "comments": { - "patch": [ - { - "comment": "fixes emission of CSS custom properties in FireFox and Safari", - "author": "nicholasrice@users.noreply.github.com", - "commit": "124f3283c8c3b317c42519576cba054821891ab5", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Wed, 27 Oct 2021 07:11:58 GMT", - "tag": "@microsoft/fast-foundation_v2.23.1", - "version": "2.23.1", - "comments": { - "patch": [ - { - "comment": "switch should check when using both enter and space", - "author": "chhol@microsoft.com", - "commit": "b3943f922f1b6b78695b63ab957c45cc67a3173c", - "package": "@microsoft/fast-foundation" - } - ], - "none": [ - { - "comment": "docs: broken link for listbox-option parents", - "author": "mathieu.lavoie@shopify.com", - "commit": "6cd49983117f878392e1f1723f9b29accb7fc20c", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Fri, 22 Oct 2021 17:40:52 GMT", - "tag": "@microsoft/fast-foundation_v2.23.0", - "version": "2.23.0", - "comments": { - "patch": [ - { - "comment": "picker clear query on selection", - "author": "scomea@microsoft.com", - "commit": "7f5e056e3baeceac7ce398fba513718309931497", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Improving number field interactions and tests", - "author": "robarb@microsoft.com", - "commit": "c1d594dc1ac40f6d2ae3710bc269843c4a4f179f", - "package": "@microsoft/fast-foundation" - } - ], - "minor": [ - { - "comment": "adds a currentValue property to form-associated to facilitate attribute-based data binding for form values", - "author": "chhol@microsoft.com", - "commit": "35c227a146ba73ce81a820c187c2834fa0c95a00", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Thu, 21 Oct 2021 07:11:42 GMT", - "tag": "@microsoft/fast-foundation_v2.22.1", - "version": "2.22.1", - "comments": { - "patch": [ - { - "comment": "fix broken tooltip", - "author": "scomea@microsoft.com", - "commit": "87f26acd2aedde19c15a434932ec5de23f5bc021", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Wed, 20 Oct 2021 07:13:46 GMT", - "tag": "@microsoft/fast-foundation_v2.22.0", - "version": "2.22.0", - "comments": { - "minor": [ - { - "comment": "add centered positioning option to anchored region", - "author": "scomea@microsoft.com", - "commit": "a495df7f2f95ccbd2c6b98c66465d3646ab4d015", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Fri, 15 Oct 2021 23:24:14 GMT", - "tag": "@microsoft/fast-foundation_v2.21.0", - "version": "2.21.0", - "comments": { - "minor": [ - { - "comment": "Implement DesignToken root-element registration for CSS custom property emission of default token values", - "author": "nicholasrice@users.noreply.github.com", - "commit": "5cc73663ee585062b130da6d57400fa15bcd3707", - "package": "@microsoft/fast-foundation" - } - ], - "patch": [ - { - "comment": "implement level-2 DOM support for DesignToken in browsers that don't support Constructable StyleSheets", - "author": "nicholasrice@users.noreply.github.com", - "commit": "d1a991480646a1d03babb3a539e308b74c777aa3", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Wed, 13 Oct 2021 22:45:16 GMT", - "tag": "@microsoft/fast-foundation_v2.20.0", - "version": "2.20.0", - "comments": { - "patch": [ - { - "comment": "move style assignment for combobox and select into the class and off the DOM node", - "author": "chhol@microsoft.com", - "commit": "5c578249ef912e0bc49083ecbfa0993b3fe97fec", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Code fixes for calendar", - "author": "robarb@microsoft.com", - "commit": "06fbb91d14e50812d893c4d0945e81cb42649df4", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Bump @microsoft/fast-element to v1.6.1", - "author": "markwhitfeld@users.noreply.github.com", - "commit": "49d27d20bf430ea4639978ba363e017fc5aa88e4", - "package": "@microsoft/fast-foundation" - } - ], - "minor": [ - { - "comment": "Adding fast-calendar component", - "author": "robarb@microsoft.com", - "commit": "44576902475e935878357bd6b116c224e4cf6342", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Wed, 13 Oct 2021 01:53:37 GMT", - "tag": "@microsoft/fast-foundation_v2.19.0", - "version": "2.19.0", - "comments": { - "minor": [ - { - "comment": "data-grid: add support for rowheader role", - "author": "scomea@microsoft.com", - "commit": "8f9b5ab92aec9f6f3214976e0284554158be6a70", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Add focus event handler to tooltip", - "author": "v-dlesac@microsoft.com", - "commit": "6c2d50e6d37650330fbc31d243b214c982958930", - "package": "@microsoft/fast-foundation" - } - ], - "patch": [ - { - "comment": "refactor: remove lodash-es as a dependency", - "author": "connor@peet.io", - "commit": "4ef4b325f8259dd0f648b5fe1b393ef8839e643e", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "use css transforms and transitions in horizontal scroll", - "author": "john.kreitlow@microsoft.com", - "commit": "6644314a87917703731503f1fd76596868d45c75", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Bump @microsoft/fast-web-utilities to v5.0.1", - "author": "john.kreitlow@microsoft.com", - "commit": "d609cffb4657e8447fb65d3b52899f48b8bb87cb", - "package": "@microsoft/fast-foundation" - } - ], - "none": [ - { - "comment": "Bump @microsoft/fast-element to v1.6.0", - "author": "skawian@gmail.com", - "commit": "1dd6243d7564f00d8af77d1335ab96b0e8153c2e", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Tue, 12 Oct 2021 07:15:14 GMT", - "tag": "@microsoft/fast-foundation_v2.18.0", - "version": "2.18.0", - "comments": { - "patch": [ - { - "comment": "Update design-token default value emission to emit to a stylesheet instead of inline styles on the document body", - "author": "nicholasrice@users.noreply.github.com", - "commit": "45ff23412ec8757e717cf2fa0c7bfb8ba719ec2c", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "add aria-disabled to accordion-item for single-mode", - "author": "khamu@microsoft.com", - "commit": "51f1bdad79fa66103bf9c78eb1f5b4e02fad65dc", - "package": "@microsoft/fast-foundation" - } - ], - "minor": [ - { - "comment": "fix(di): context confused for key with some registrations", - "author": "roeisenb@microsoft.com", - "commit": "f9eeb257368aee0535ccfd4efd5a1dc25ab1a2fe", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Sun, 10 Oct 2021 07:12:26 GMT", - "tag": "@microsoft/fast-foundation_v2.17.3", - "version": "2.17.3", - "comments": { - "patch": [ - { - "comment": "fix linting errors in horizontal-scroll tests", - "author": "john.kreitlow@microsoft.com", - "commit": "d3a5955c4feba0b355189a4b28dbe8befcfb89df", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Fri, 08 Oct 2021 19:53:11 GMT", - "tag": "@microsoft/fast-foundation_v2.17.2", - "version": "2.17.2", - "comments": { - "patch": [ - { - "comment": "anchored region force update", - "author": "scomea@microsoft.com", - "commit": "2bf9005b895abe0828a4ebbc943ed0511c176d6f", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Wed, 06 Oct 2021 07:11:47 GMT", - "tag": "@microsoft/fast-foundation_v2.17.1", - "version": "2.17.1", - "comments": { - "patch": [ - { - "comment": "picker menu shows with only custom options", - "author": "scomea@microsoft.com", - "commit": "0d509e1bbd4f7e55b167986ea95497ef64bfd7ef", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Tue, 05 Oct 2021 00:45:07 GMT", - "tag": "@microsoft/fast-foundation_v2.17.0", - "version": "2.17.0", - "comments": { - "minor": [ - { - "comment": "feat: add scroll events to horizontal-scroll component", - "author": "robarb@microsoft.com", - "commit": "5f6c838b1511ebf26a34b3c4d26f82467de8a603", - "package": "@microsoft/fast-foundation" - } - ], - "patch": [ - { - "comment": "fix: nested tree items not selecting", - "author": "jes@microsoft.com", - "commit": "795ff6ab8e64b8b3474a8abe3018b5f76915de86", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Sun, 03 Oct 2021 07:12:33 GMT", - "tag": "@microsoft/fast-foundation_v2.16.5", - "version": "2.16.5", - "comments": { - "none": [ - { - "comment": "Update webpack migration documentation", - "author": "meyunus@microsoft.com", - "commit": "83d2ace2b485b730cf8ea11512d5782cab381a1b", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "docs: update React integration doc to use the new React wrapper", - "author": "roeisenb@microsoft.com", - "commit": "75aae3d432e1bb633baa925f7ff093b7a19e4e72", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Thu, 30 Sep 2021 07:13:45 GMT", - "tag": "@microsoft/fast-foundation_v2.16.5", - "version": "2.16.5", - "comments": { - "patch": [ - { - "comment": "Disabling scroll easing for speed=0", - "author": "robarb@microsoft.com", - "commit": "5646a82ad9cec5899f708b31cf8e41f513918920", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Wed, 29 Sep 2021 07:13:40 GMT", - "tag": "@microsoft/fast-foundation_v2.16.4", - "version": "2.16.4", - "comments": { - "patch": [ - { - "comment": "do not prevent default on tree item click", - "author": "chhol@microsoft.com", - "commit": "f027c065e7db66dceb53a762e40813587f166616", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "fix: allowing decimal values in fast number field", - "author": "robarb@microsoft.com", - "commit": "f3068d93920821a99fca2d8f4fb9ee6db5d0812f", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "fix: sliders mouseup is not firing when leaving the window", - "author": "robarb@microsoft.com", - "commit": "9105fb37edc3497a15939081b42c8dd5d63bed3f", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Tue, 28 Sep 2021 07:10:49 GMT", - "tag": "@microsoft/fast-foundation_v2.16.3", - "version": "2.16.3", - "comments": { - "patch": [ - { - "comment": "made orientation changed update child tab styles", - "author": "marjon@microsoft.com", - "commit": "2d07b6ab5a9500ced93e0c1d06eea4bcad430088", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Fix: active indicator keyboarding issue in tabs", - "author": "jes@microsoft.com", - "commit": "997fcc5b17e0f27401e938ec87d295b86f5a872b", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Mon, 27 Sep 2021 07:12:15 GMT", - "tag": "@microsoft/fast-foundation_v2.16.2", - "version": "2.16.2", - "comments": { - "patch": [ - { - "comment": "fix: ensure tree item selection is only managed in tree view", - "author": "jes@microsoft.com", - "commit": "c5d56bf3bfed31b3233d4f0fa0c03afcd31985a2", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Thu, 23 Sep 2021 07:14:34 GMT", - "tag": "@microsoft/fast-foundation_v2.16.1", - "version": "2.16.1", - "comments": { - "patch": [ - { - "comment": "Removing design-system-provider from storybook", - "author": "robarb@microsoft.com", - "commit": "02fa810f84c4b905789734102033f18e6573f301", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Horizontal-scroll tests cleanup", - "author": "robarb@microsoft.com", - "commit": "9105fb37edc3497a15939081b42c8dd5d63bed3f", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Wed, 22 Sep 2021 07:13:13 GMT", - "tag": "@microsoft/fast-foundation_v2.16.0", - "version": "2.16.0", - "comments": { - "patch": [ - { - "comment": "fix: active indicator does not update when activeid attr is changed", - "author": "jes@microsoft.com", - "commit": "5e2956f319f4d2736e78c05e7e8fc6df7a266fff", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "fix aria-describedby typos", - "author": "v-dlesac@microsoft.com", - "commit": "41fc891045fd1c2b457319e2fa5b26144b79bd9b", - "package": "@microsoft/fast-foundation" - } - ], - "minor": [ - { - "comment": "feat(di): add registerWithContext and use in design system", - "author": "roeisenb@microsoft.com", - "commit": "ede2a72a0be865346b52559400cbb685f3e4ad19", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Sun, 19 Sep 2021 07:17:17 GMT", - "tag": "@microsoft/fast-foundation_v2.15.0", - "version": "2.15.0", - "comments": { - "minor": [ - { - "comment": "add picker component", - "author": "scomea@microsoft.com", - "commit": "395775ca58b6529861aae2e2ab1a628e2d8db081", - "package": "@microsoft/fast-foundation" - } - ], - "patch": [ - { - "comment": "fix: remove dependency on document for root containers & design systems", - "author": "roeisenb@microsoft.com", - "commit": "88d50fadf907d12581c0faa7a08951b5e41bb2b2", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Bump @microsoft/fast-web-utilities to v5.0.0", - "author": "scomea@microsoft.com", - "commit": "395775ca58b6529861aae2e2ab1a628e2d8db081", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Thu, 16 Sep 2021 07:17:00 GMT", - "tag": "@microsoft/fast-foundation_v2.14.0", - "version": "2.14.0", - "comments": { - "none": [ - { - "comment": "correct error in data grid spec document", - "author": "scomea@microsoft.com", - "commit": "529117085a9394c8ff9da4a0d16f8be21fc798d1", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Wed, 15 Sep 2021 19:49:35 GMT", - "tag": "@microsoft/fast-foundation_v2.14.0", - "version": "2.14.0", - "comments": { - "patch": [ - { - "comment": "Fix design-token subscription bugs where subscribers were not getting notified", - "author": "nicholasrice@users.noreply.github.com", - "commit": "b5891e7f1b816628f58e96c66d28235ab42c5bdf", - "package": "@microsoft/fast-foundation" - } - ], - "minor": [ - { - "comment": "fix type issue for FoundationElementTemplate", - "author": "john.kreitlow@microsoft.com", - "commit": "89bf213b9e3693548b52f52d36cc0d36d208d4e6", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Tue, 14 Sep 2021 07:16:47 GMT", - "tag": "@microsoft/fast-foundation_v2.13.1", - "version": "2.13.1", - "comments": { - "patch": [ - { - "comment": "Using a manual focus to workaround delegatesFocus issues on Firefox for the button and anchor components", - "author": "jumarroq@microsoft.com", - "commit": "8094ba315ab24b4dca9b2aea1f5ef0ba5afb7725", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Sun, 12 Sep 2021 07:17:43 GMT", - "tag": "@microsoft/fast-foundation_v2.13.0", - "version": "2.13.0", - "comments": { - "minor": [ - { - "comment": "use class method for radio click handler property", - "author": "john.kreitlow@microsoft.com", - "commit": "d1e2b8dbbe1daec68f69d8df741f06fa2c74414a", - "package": "@microsoft/fast-foundation" - } - ], - "patch": [ - { - "comment": "remove dependencies on keycode", - "author": "scomea@microsoft.com", - "commit": "e8602a247065b0c916bdc8e55314f2d3e3403fd1", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Bump @microsoft/fast-web-utilities to v4.8.1", - "author": "scomea@microsoft.com", - "commit": "e8602a247065b0c916bdc8e55314f2d3e3403fd1", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Thu, 09 Sep 2021 07:21:36 GMT", - "tag": "@microsoft/fast-foundation_v2.12.0", - "version": "2.12.0", - "comments": { - "minor": [ - { - "comment": "add start/end slot definitions to support default slotted content", - "author": "chhol@microsoft.com", - "commit": "3ad50c8eec98b3156a4559586ca76e4abebefad8", - "package": "@microsoft/fast-foundation" - } - ], - "patch": [ - { - "comment": "fix(design-system): make FoundationElement.compose safe to use directly", - "author": "roeisenb@microsoft.com", - "commit": "a508e1e08780d741300d4a03e2bf43ad53a2c017", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Wed, 08 Sep 2021 07:16:17 GMT", - "tag": "@microsoft/fast-foundation_v2.11.0", - "version": "2.11.0", - "comments": { - "minor": [ - { - "comment": "fix: allow for base class", - "author": "mathieu.lavoie@logmein.com", - "commit": "5493d3ac1f0d2d854031f2211bc32c0bb9d2c234", - "package": "@microsoft/fast-foundation" - } - ], - "patch": [ - { - "comment": "force non-volatile binding and update docs to explain that DesignToken does not support volatile bindings", - "author": "nicholasrice@users.noreply.github.com", - "commit": "d48af06747dd8c9e1bd4265f8174ee81edc5fc07", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Bump @microsoft/fast-element to v1.5.1", - "author": "roeisenb@microsoft.com", - "commit": "bdd28c8861b3523a9984ca8feda2af9019861a8a", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Thu, 02 Sep 2021 17:17:56 GMT", - "tag": "@microsoft/fast-foundation_v2.10.0", - "version": "2.10.0", - "comments": { - "minor": [ - { - "comment": "feat(design-system): enable complete ignore of duplicate elements", - "author": "roeisenb@microsoft.com", - "commit": "fe1db8607dce8c80fa83ad01ee2c8dbc9e845c98", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Thu, 02 Sep 2021 07:15:21 GMT", - "tag": "@microsoft/fast-foundation_v2.9.1", - "version": "2.9.1", - "comments": { - "patch": [ - { - "comment": "configure system to use a single CSSStyleSheet for custom property setting", - "author": "nicholasrice@users.noreply.github.com", - "commit": "29cdc520f699eaf1f1669eaeacb4a7a8a7cfe1c2", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "progress component bar width", - "author": "scomea@microsoft.com", - "commit": "21c6791f13b17e08d131358e423c86b73b77a79e", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Removed remaining 'use-defaults' which no longer exists", - "author": "47367562+bheston@users.noreply.github.com", - "commit": "f34fa1b1bdbb0cf4c371b556c2486bd160646c53", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Wed, 01 Sep 2021 07:18:34 GMT", - "tag": "@microsoft/fast-foundation_v2.9.0", - "version": "2.9.0", - "comments": { - "minor": [ - { - "comment": "add viewport lock to tooltip", - "author": "scomea@microsoft.com", - "commit": "397d02d7bfc9b61bfafb44d4ccdf8db49fd25453", - "package": "@microsoft/fast-foundation" - } - ], - "patch": [ - { - "comment": "don't block all keys while focused", - "author": "corylaviska@microsoft.com", - "commit": "12efc3d7553ece88318b9fcdf8e11cc27253d30a", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Mon, 30 Aug 2021 22:30:39 GMT", - "tag": "@microsoft/fast-foundation_v2.8.1", - "version": "2.8.1", - "comments": { - "none": [ - { - "comment": "docs(integrations): add an ember tutorial", - "author": "roeisenb@microsoft.com", - "commit": "cb5d2b128a7f0283377642b8e7e97fc68d22d952", - "package": "@microsoft/fast-foundation" - } - ], - "patch": [ - { - "comment": "fixing issue where a token would subscribe to itself, causing max-callstack-exceded in certain scenarios", - "author": "nicholasrice@users.noreply.github.com", - "commit": "c4fe4d0706dae02bc2d4c8ea37dafe6c79c03075", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Fri, 27 Aug 2021 14:14:26 GMT", - "tag": "@microsoft/fast-foundation_v2.8.0", - "version": "2.8.0", - "comments": { - "minor": [ - { - "comment": "Refactor DesignToken implementation to support deep token dependency hierarchies", - "author": "nicholasrice@users.noreply.github.com", - "commit": "e498f1e35232169d2bf80e366350d0cde812d76d", - "package": "@microsoft/fast-foundation" - } - ], - "patch": [ - { - "comment": "add up/down key support to number-field", - "author": "corylaviska@microsoft.com", - "commit": "0dd749b39bb8d1a0005b0a511ebcc7853f6a077b", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Bump @microsoft/fast-element to v1.5.0", - "author": "nicholasrice@users.noreply.github.com", - "commit": "e498f1e35232169d2bf80e366350d0cde812d76d", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Thu, 26 Aug 2021 07:17:43 GMT", - "tag": "@microsoft/fast-foundation_v2.7.1", - "version": "2.7.1", - "comments": { - "patch": [ - { - "comment": "fix slider dragging when page is scrolled", - "author": "corylaviska@microsoft.com", - "commit": "bc0c7b0a0b99fd8463740b09870178ae192e5274", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Wed, 25 Aug 2021 07:17:07 GMT", - "tag": "@microsoft/fast-foundation_v2.7.0", - "version": "2.7.0", - "comments": { - "minor": [ - { - "comment": "allow context for partials on component compositions", - "author": "john.kreitlow@microsoft.com", - "commit": "bc9f51cb9357da7ccb34a3251b316c21dcc17b09", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Thu, 19 Aug 2021 07:15:21 GMT", - "tag": "@microsoft/fast-foundation_v2.6.5", - "version": "2.6.5", - "comments": { - "patch": [ - { - "comment": "add reducefocusableElements and all slotted items to keyboard interaction", - "author": "sethdonohue@Admins-MBP.guest.corp.microsoft.com", - "commit": "4a4e2c16987aa015c3f90adbe400f09a0d4c2563", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Thu, 12 Aug 2021 07:16:50 GMT", - "tag": "@microsoft/fast-foundation_v2.6.4", - "version": "2.6.4", - "comments": { - "none": [ - { - "comment": "chore: eslint fixes in fast-foundation", - "author": "mathieu.lavoie@logmein.com", - "commit": "7265f039d4e4d1a219a4ab6bf831b78540d339e8", - "package": "@microsoft/fast-foundation" - } - ], - "patch": [ - { - "comment": "fix dialog focus on open", - "author": "scomea@microsoft.com", - "commit": "ee9239067b2245056e066e3a4e532b4ad00d4815", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Wed, 04 Aug 2021 07:15:14 GMT", - "tag": "@microsoft/fast-foundation_v2.6.3", - "version": "2.6.3", - "comments": { - "patch": [ - { - "comment": "menu should check for slot before automatically assigning a value", - "author": "chhol@microsoft.com", - "commit": "98c45b1c087853529e157384fe514f6c79422189", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Tue, 03 Aug 2021 07:17:33 GMT", - "tag": "@microsoft/fast-foundation_v2.6.2", - "version": "2.6.2", - "comments": { - "none": [ - { - "comment": "Bump @microsoft/fast-element to v1.4.1", - "author": "mathieu.lavoie@logmein.com", - "commit": "65e86a86cbf2b584f7a76081a9bef5a76e78b6f3", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Sun, 01 Aug 2021 07:17:15 GMT", - "tag": "@microsoft/fast-foundation_v2.6.2", - "version": "2.6.2", - "comments": { - "none": [ - { - "comment": "refactor(fixture): mild change to typings to enable typical code pattern", - "author": "roeisenb@microsoft.com", - "commit": "46bb752c86f1112f4cc92f8b0c155addf05225e0", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Thu, 29 Jul 2021 07:18:18 GMT", - "tag": "@microsoft/fast-foundation_v2.6.2", - "version": "2.6.2", - "comments": { - "none": [ - { - "comment": "docs: fix various errors discovered while building the site", - "author": "roeisenb@microsoft.com", - "commit": "b2a640ff068917d251ca84be6dee72d4f4e941a3", - "package": "@microsoft/fast-foundation" - } - ], - "patch": [ - { - "comment": "remove unnecessary aria-hidden attributes", - "author": "47367562+bheston@users.noreply.github.com", - "commit": "45a348674554ac26d0153b1d850523d82fb89762", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Wed, 28 Jul 2021 07:17:22 GMT", - "tag": "@microsoft/fast-foundation_v2.6.1", - "version": "2.6.1", - "comments": { - "none": [ - { - "comment": "docs(components): add/update and expand content", - "author": "roeisenb@microsoft.com", - "commit": "07d03884b168bb66d482a72df2d2941f8561b9ce", - "package": "@microsoft/fast-foundation" - } - ], - "patch": [ - { - "comment": "update on !regionVisible", - "author": "scomea@microsoft.com", - "commit": "1e22a9ca163fba0830eef1d3fcf5d222fa01ed28", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Sun, 25 Jul 2021 07:17:41 GMT", - "tag": "@microsoft/fast-foundation_v2.6.0", - "version": "2.6.0", - "comments": { - "minor": [ - { - "comment": "add auto position tracking to tooltip", - "author": "scomea@microsoft.com", - "commit": "9f6e61d3b45af6da0430677f9d437ff7ba0cdae9", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "anchored region uses transform", - "author": "scomea@microsoft.com", - "commit": "4dd29d77f026b51c4031bf19acf494d1768a2611", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Thu, 22 Jul 2021 07:19:53 GMT", - "tag": "@microsoft/fast-foundation_v2.5.2", - "version": "2.5.2", - "comments": { - "none": [ - { - "comment": "doc: fix import adapter statement", - "author": "ben@platform5.ch", - "commit": "7cfed1eef45c4947bd0439d448b9c79befc58406", - "package": "@microsoft/fast-foundation" - } - ], - "patch": [ - { - "comment": "Fixed attr boolean mode on menu item", - "author": "47367562+bheston@users.noreply.github.com", - "commit": "6325e61798e5fee6bb09ce0336636a1d1f2c4959", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Wed, 21 Jul 2021 07:14:48 GMT", - "tag": "@microsoft/fast-foundation_v2.5.1", - "version": "2.5.1", - "comments": { - "none": [ - { - "comment": "fixing doc comments causing api-documenter to fail", - "author": "nicholasrice@users.noreply.github.com", - "commit": "d5f27df7b30e474c69a336741cf00e49a6806ca2", - "package": "@microsoft/fast-foundation" - } - ], - "patch": [ - { - "comment": "Hide step-up and step-down for number-field when readonly", - "author": "robarb@microsoft.com", - "commit": "6e53b2866250dc08881a57b371069a40a69df391", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Thu, 15 Jul 2021 01:41:48 GMT", - "tag": "@microsoft/fast-foundation_v2.5.0", - "version": "2.5.0", - "comments": { - "minor": [ - { - "comment": "extend design token type signature", - "author": "chhol@microsoft.com", - "commit": "35773aadf50b51e3d64dd8969398d2c473d437ed", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Tue, 13 Jul 2021 07:14:52 GMT", - "tag": "@microsoft/fast-foundation_v2.4.0", - "version": "2.4.0", - "comments": { - "minor": [ - { - "comment": "docs(di): make API public, stabilize, and add docs", - "author": "roeisenb@microsoft.com", - "commit": "3a9f152446a1a9e0afd6fd84c808eba46839aeeb", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Wed, 07 Jul 2021 07:19:51 GMT", - "tag": "@microsoft/fast-foundation_v2.3.0", - "version": "2.3.0", - "comments": { - "minor": [ - { - "comment": "focus trap improvement", - "author": "scomea@microsoft.com", - "commit": "ec7475de213ef4eb6a3964c902ae0fcf7657a640", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Sun, 04 Jul 2021 07:15:28 GMT", - "tag": "@microsoft/fast-foundation_v2.2.0", - "version": "2.2.0", - "comments": { - "minor": [ - { - "comment": "select should emit an input event before the change event", - "author": "john.kreitlow@microsoft.com", - "commit": "3f9131d61d0b3149fc99d77db6e5fb1d0231a5d1", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Thu, 01 Jul 2021 07:15:57 GMT", - "tag": "@microsoft/fast-foundation_v2.1.0", - "version": "2.1.0", - "comments": { - "patch": [ - { - "comment": "Fixes bug in DesignToken where aliased tokens didn't update CSS custom properties.", - "author": "nicholasrice@users.noreply.github.com", - "commit": "8c885780279ee8b8acddc2a0428fc09b4e1788c0", - "package": "@microsoft/fast-foundation" - } - ], - "minor": [ - { - "comment": "ensure DesignToken considers shadow DOM when determining DOM hierarchy", - "author": "nicholasrice@users.noreply.github.com", - "commit": "0ab5dec4ad2a9ce717d90912127e094d094ede6d", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Fri, 25 Jun 2021 02:02:57 GMT", - "tag": "@microsoft/fast-foundation_v2.0.0", - "version": "2.0.0", - "comments": { - "none": [ - { - "comment": "mark design-token public", - "author": "nicholasrice@users.noreply.github.com", - "commit": "e4f573db1bfd0a5ed65d0c12abdd6c971c44f1e0", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "fix incorrect name for select tests", - "author": "chhol@microsoft.com", - "commit": "e3b519d12278ef7bdac30b20dd9da0a68ee0c79e", - "package": "@microsoft/fast-foundation" - } - ], - "minor": [ - { - "comment": "fix(foundation-element): enable subclassing with customElement decorator", - "author": "roeisenb@microsoft.com", - "commit": "bb03c73e250f25d9eefd6e5f3126e0dbc28326d6", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "feat(design-system): enable overriding the shadow root mode", - "author": "roeisenb@microsoft.com", - "commit": "1f2aad19546389e299d43b5fda1de6e60b83e390", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "docs(fast-foundation): add api docs for design system and foundation ele", - "author": "roeisenb@microsoft.com", - "commit": "a94dd0f7b4aceddd93dab23e81c2b1eaa4f3dd62", - "package": "@microsoft/fast-foundation" - } - ], - "major": [ - { - "comment": "remove deprecated APIs and Design System Provider infrastructure", - "author": "nicholasrice@users.noreply.github.com", - "commit": "361c2e74066a50206719168d6d0b26e67bd0aed2", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "feat(design-system): better integrate with DI and enforce constraints", - "author": "roeisenb@microsoft.com", - "commit": "370b727537850f49a6cd8bf23bb34d7d462017f2", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "migrate directional-stylesheet utility", - "author": "nicholasrice@users.noreply.github.com", - "commit": "ce4aacb7cfd4f630a1836117a99dc5003c0e489c", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "update components to extend FoundationElement", - "author": "chhol@microsoft.com", - "commit": "6369ab1a3db8b693f14d4cf0ee67cc4e1d802dfb", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "feat: styling and text alignment for menu", - "author": "jes@microsoft.com", - "commit": "a440e2bc478dd666d80d7958718f8fcc2b46bc77", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "add API support for setting default slotted content as part of component composition", - "author": "chhol@microsoft.com", - "commit": "0a6bd40f568fa0f640a15bc7e6d669e80d169036", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "update card to extend foundation", - "author": "chhol@microsoft.com", - "commit": "1b73fe768e7ad339ecdd749373db07cff34302a7", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "feat: encapsulate and optimize ComponentPresentation resolution", - "author": "roeisenb@microsoft.com", - "commit": "4b220ef887dfa33c3e257df0cb789b511b293eff", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Wed, 23 Jun 2021 22:58:18 GMT", - "tag": "@microsoft/fast-foundation_v1.24.8", - "version": "1.24.8", - "comments": { - "patch": [ - { - "comment": "prevent left/right arrows from scrolling when expanding/collapsing tree-item", - "author": "tlmii@users.noreply.github.com", - "commit": "ef8b84eca2eb82f84abc4f08986c384e0f3b3305", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Sun, 20 Jun 2021 07:21:25 GMT", - "tag": "@microsoft/fast-foundation_v1.24.7", - "version": "1.24.7", - "comments": { - "patch": [ - { - "comment": "Enable stepping from null values on number-field", - "author": "robarb@microsoft.com", - "commit": "ab4bcdd57cedf82ba48460ed4290def3787d6599", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "fix malformed templates", - "author": "scomea@microsoft.com", - "commit": "7e6a11f80d4ab89c8e3a682d9f6b0db71ea3a317", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Sun, 13 Jun 2021 07:19:23 GMT", - "tag": "@microsoft/fast-foundation_v1.24.6", - "version": "1.24.6", - "comments": { - "patch": [ - { - "comment": "ensure host element of a shadowed element can be resolved", - "author": "nicholasrice@users.noreply.github.com", - "commit": "d1af72075ae857310f07183fb3e74583f27d0ded", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Tue, 08 Jun 2021 07:29:18 GMT", - "tag": "@microsoft/fast-foundation_v1.24.5", - "version": "1.24.5", - "comments": { - "patch": [ - { - "comment": "streamline horizontal scroll resize", - "author": "scomea@microsoft.com", - "commit": "7436c794f855e03e23494c5b87e895cd3221f5f6", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Sun, 30 May 2021 07:42:30 GMT", - "tag": "@microsoft/fast-foundation_v1.24.4", - "version": "1.24.4", - "comments": { - "none": [ - { - "comment": "Merge branch 'master' into patch-1", - "author": "xavier@norival.dev", - "commit": "b5d702a313a19ce62468c8093c830e460c44f9b5", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Bump @microsoft/fast-element to v1.4.0", - "author": "xavier@norival.dev", - "commit": "b5d702a313a19ce62468c8093c830e460c44f9b5", - "package": "@microsoft/fast-foundation" - } - ], - "patch": [ - { - "comment": "Ensure stale Design Token custom property stylesheets are removed when token values change.", - "author": "nicholasrice@users.noreply.github.com", - "commit": "e1664c07d73aabe154d927cdc97dacf7e726426b", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "fix bug caused by asserting parentElement was not null", - "author": "nicholasrice@users.noreply.github.com", - "commit": "d63476d95e1e83616396eda9f5c5916eb4154221", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Wed, 26 May 2021 07:33:37 GMT", - "tag": "@microsoft/fast-foundation_v1.24.3", - "version": "1.24.3", - "comments": { - "patch": [ - { - "comment": "allow a float to be accurately represented when a step is a fraction", - "author": "7559015+janechu@users.noreply.github.com", - "commit": "1e7f447f76a85be625ca890035794d28e7a84fad", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "fix css custom property emission for dependent DesignToken properties", - "author": "nicholasrice@users.noreply.github.com", - "commit": "e5c305740cc2399da80bea45da6b810eb98be1b1", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Tue, 25 May 2021 07:27:43 GMT", - "tag": "@microsoft/fast-foundation_v1.24.2", - "version": "1.24.2", - "comments": { - "patch": [ - { - "comment": "fix data grid tabbing", - "author": "scomea@microsoft.com", - "commit": "42e8fb5d98d41dac03230c89923ed80ab2a03eb5", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Fri, 21 May 2021 17:48:08 GMT", - "tag": "@microsoft/fast-foundation_v1.24.1", - "version": "1.24.1", - "comments": { - "patch": [ - { - "comment": "update to Design System Provider to use dom.supportsAdoptedStyleSheets", - "author": "nicholasrice@users.noreply.github.com", - "commit": "f56542a588c8b3535c249485987fc7e76e014a56", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Thu, 20 May 2021 07:24:10 GMT", - "tag": "@microsoft/fast-foundation_v1.24.0", - "version": "1.24.0", - "comments": { - "minor": [ - { - "comment": "add toolbar component", - "author": "john.kreitlow@microsoft.com", - "commit": "c7db517ac34ee6f0e5454bbf395711f464b438a0", - "package": "@microsoft/fast-foundation" - } - ], - "patch": [ - { - "comment": "Bump @microsoft/fast-web-utilities to v4.8.0", - "author": "john.kreitlow@microsoft.com", - "commit": "c7db517ac34ee6f0e5454bbf395711f464b438a0", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Wed, 19 May 2021 23:37:36 GMT", - "tag": "@microsoft/fast-foundation_v1.23.0", - "version": "1.23.0", - "comments": { - "none": [ - { - "comment": "docs: update Blazor docs with instructions for the new Nuget package", - "author": "roeisenb@microsoft.com", - "commit": "cc18a2c498cc9c0fb7ca83a234cb9896c661b3b1", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "remove await setTimeout in favor of nextMacroTask. disable broken tests", - "author": "nicholasrice@users.noreply.github.com", - "commit": "1afe35adf2bf730ac5c09c315b626eec168cd362", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "add combobox spec", - "author": "john.kreitlow@microsoft.com", - "commit": "ff1a6686c4eaaae3c1d24bc92d97bc58d3b789c1", - "package": "@microsoft/fast-foundation" - } - ], - "minor": [ - { - "comment": "Adds subscribe and unsubscribe methods to DesignToken", - "author": "nicholasrice@users.noreply.github.com", - "commit": "f6cd1173d0620642a171e2118df4af4cc726c3ec", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Adds feature to DesignToken to prevent emission to CSS", - "author": "nicholasrice@users.noreply.github.com", - "commit": "9a1fa925399f541c5d656f5ac91b3e896390146a", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Addresses significant performance issues with DesignToken implmentation. This change removes several alpha APIs on DesignToken.", - "author": "nicholasrice@users.noreply.github.com", - "commit": "d6a006b4c41316f9909d3987d0d671dc8620d9ca", - "package": "@microsoft/fast-foundation" - } - ], - "patch": [ - { - "comment": "fix: update scrolling with delay loaded content", - "author": "robarb@microsoft.com", - "commit": "604390a124630a9fe3f2d785d8e7058d10fd142f", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "menu should not reset tabIndex unnecessarily", - "author": "scomea@microsoft.com", - "commit": "90362fca45c9959992ef09bd09c0b7054a0aca49", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "selected option is not visible when dropdown is opened in fast-select", - "author": "john.kreitlow@microsoft.com", - "commit": "2c4732a17e4091b1dddecc25138370a1a3565bfb", - "package": "@microsoft/fast-foundation" - }, - { - "author": "nicholasrice@users.noreply.github.com", - "commit": "8a162ff7d6866db07125e8829ba451b4b5a2f4f8", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "fix: fast-number-field does not fire input event when buttons pressed", - "author": "robarb@microsoft.com", - "commit": "66bcd958ae59e56618631af50020d7234bb7a2e2", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Bump @microsoft/fast-element to v1.3.0", - "author": "nicholasrice@users.noreply.github.com", - "commit": "a433b6bcab871f24ccbe828b2023c256942d40af", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Sun, 25 Apr 2021 07:21:02 GMT", - "tag": "@microsoft/fast-foundation_v1.20.0", - "version": "1.20.0", - "comments": { - "minor": [ - { - "author": "nicholasrice@users.noreply.github.com", - "commit": "048081bd5d85c62911d4a4105cbbd23c60ae446d", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Thu, 22 Apr 2021 07:21:10 GMT", - "tag": "@microsoft/fast-foundation_v1.19.0", - "version": "1.19.0", - "comments": { - "minor": [ - { - "comment": "adding withDefault method to DesignToken", - "author": "nicholasrice@users.noreply.github.com", - "commit": "e53592ca1d600076cc91dc4e8a54dc9f6a51e1a1", - "package": "@microsoft/fast-foundation" - } - ], - "none": [ - { - "comment": "docs: missing events in the menu api", - "author": "mathieu.lavoie@logmein.com", - "commit": "679f9f026aec2c069e0387d6af9de7043a9cd7eb", - "package": "@microsoft/fast-foundation" - } - ], - "patch": [ - { - "comment": "add function to check for separator, add example and update style for not href item", - "author": "khamu@microsoft.com", - "commit": "e8efeefeca3743076874cd51c06fa3ea7d13e7d0", - "package": "@microsoft/fast-foundation" - } - ] - } - }, - { - "date": "Fri, 16 Apr 2021 01:19:08 GMT", - "tag": "@microsoft/fast-foundation_v1.18.0", - "version": "1.18.0", - "comments": { - "patch": [ - { - "comment": "add missing aria-expanded to the select template", - "author": "mathieu.lavoie@logmein.com", - "commit": "8a86d721281ab9a7341bb5694a8c93f7892aa841", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "remove incorrect role from horizontal-scroll element", - "author": "chhol@microsoft.com", - "commit": "b0d3816d089df8d353c14fb2667ad0aa8626dc8d", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "ensure DesignToken works with falsey values", - "author": "nicholasrice@users.noreply.github.com", - "commit": "a94fda52cc9c0c0d1d0fc1c749dee52780b45834", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "fix anchored region positioning bugs", - "author": "scomea@microsoft.com", - "commit": "b0aaad7a455e6fd08336ffe210eb4e2db72781c9", - "package": "@microsoft/fast-foundation" - } - ], - "minor": [ - { - "comment": "open up getter and setter functions to HTMLElement", - "author": "nicholasrice@users.noreply.github.com", - "commit": "b6c2929d5b0eddc334b302db553a91681d4c4a0a", - "package": "@microsoft/fast-foundation" - } - ], - "none": [ - { - "comment": "await a macro task instead of a DOM.nextUpdate()", - "author": "nicholasrice@users.noreply.github.com", - "commit": "f7fc9f1b9b4ac6ffa2176c952d1b433d8e4bf4e8", - "package": "@microsoft/fast-foundation" - }, - { - "comment": "Bump @microsoft/fast-web-utilities to v4.7.3", - "author": "7559015+janechu@users.noreply.github.com", - "commit": "832c1086c05099de4f7c9261dd85b7b32605538c", - "package": "@microsoft/fast-foundation" - } - ] - } - } - ] -} diff --git a/packages/web-components/fast-foundation/CHANGELOG.md b/packages/web-components/fast-foundation/CHANGELOG.md deleted file mode 100644 index 2274cf39104..00000000000 --- a/packages/web-components/fast-foundation/CHANGELOG.md +++ /dev/null @@ -1,2030 +0,0 @@ -# Change Log - @microsoft/fast-foundation - -This log was last generated on Thu, 20 Jun 2024 17:00:56 GMT and should not be manually modified. - - - -## 3.0.0-alpha.33 - -Thu, 20 Jun 2024 17:00:56 GMT - -### Changes - -- update picker component roles (145117767+JiginJayaprakash@users.noreply.github.com) -- add picker disabled state (stephcomeau@msn.com) -- no options missing (stephcomeau@msn.com) -- Various Combobox fixes with tests. (26874831+atmgrifter00@users.noreply.github.com) -- Remove unmatched closing div (7559015+janechu@users.noreply.github.com) -- removing readonly for Slider (olaf-k@users.noreply.github.com) -- Adds token name to token resolution error when the name exists for a token (nicholasrice@users.noreply.github.com) -- fix(foundation): textfield proxy enterkeyhint (7559015+janechu@users.noreply.github.com) -- feat(text-field): reset value on type change (43081j@users.noreply.github.com) -- fix(combobox): close the combobox even if there's no selection (zoepeterson@microsoft.com) -- upgrade to Storybook 8 (863023+radium-v@users.noreply.github.com) -- Foundation: Update Slider templates (https://github.com/microsoft/fast/pull/6800) (47367562+bheston@users.noreply.github.com) -- Fix toolbar stealing focus (fcollonval@users.noreply.github.com) -- Foundation: Update Number field, Search, Switch, Text area, and Text field templates (https://github.com/microsoft/fast/pull/6798) (47367562+bheston@users.noreply.github.com) -- Update Badge and Breadcrumb templates (https://github.com/microsoft/fast/pull/6797) (47367562+bheston@users.noreply.github.com) -- fix: allow tabs `setTabs` method to be extended (quic_scomeau@qualcomm.com) -- comparisons to document.activeElement consider shadowRoot (stephcomeau@msn.com) -- Foundation: Update Accordion template element naming (https://github.com/microsoft/fast/pull/6796) (47367562+bheston@users.noreply.github.com) - -## 3.0.0-alpha.32 - -Wed, 20 Dec 2023 19:03:48 GMT - -### Changes - -- Fix focus issue when clicking on an element in the toolbar (20542556+mollykreis@users.noreply.github.com) -- Fix bug in toolbar click handler when a slotted element has child elements (20542556+mollykreis@users.noreply.github.com) - -## 3.0.0-alpha.31 - -Fri, 18 Aug 2023 22:48:12 GMT - -### Changes - -- export patterns from foundation as package export (chhol@microsoft.com) - -## 3.0.0-alpha.30 - -Fri, 18 Aug 2023 00:04:39 GMT - -### Changes - -- update fast-element export paths to include extensions (chhol@microsoft.com) -- add export paths with extensions for each fast-foundation component and utilities (chhol@microsoft.com) -- fix: change public static methods for listbox and data grid to not be fat arrow fns (chhol@microsoft.com) -- Bump @microsoft/fast-element to v2.0.0-beta.26 - -## 3.0.0-alpha.29 - -Sat, 12 Aug 2023 00:26:35 GMT - -### Changes - -- block cell nav events (stephcomeau@msn.com) -- fix: add aria-orientation to divider only when role equals separator (chhol@microsoft.com) -- Removed the 'applyMixins' function from exported features. (nicholasrice@noreply.github.com) -- Prevent keyboard navigation to hidden tab (7282195+m-akinc@users.noreply.github.com) -- picker zero items (stephcomeau@msn.com) -- fix: toolbar should not throw if start or end is undefined (chhol@microsoft.com) -- Bump @microsoft/fast-element to v2.0.0-beta.25 - -## 3.0.0-alpha.28 - -Fri, 16 Jun 2023 18:17:12 GMT - -### Changes - -- remove keyboard ability to change value for readonly state in fast-number-field (saicharan0124@gmail.com) -- open picker menu on delete (stephcomeau@msn.com) -- set activeid when setting active tab (chhol@microsoft.com) -- Fix api-extractor doc warnings (47367562+bheston@users.noreply.github.com) -- Updates when directive instances to use 'else' template option (nicholasrice@users.noreply.github.com) -- picker show no options (stephcomeau@msn.com) -- fix picker scroll into view (stephcomeau@msn.com) -- picker filter ignores case (stephcomeau@msn.com) -- Bump @microsoft/fast-element to v2.0.0-beta.24 - -## 3.0.0-alpha.27 - -Tue, 28 Mar 2023 22:14:10 GMT - -### Changes - -- update @microsoft/fast-element to be fixed for foundation package (tebin.raouf@gmail.com) -- update slider changed methods to protected (chhol@microsoft.com) -- support row selection in data grid (scomea@microsoft.com) -- remove activeindicator from tabs component (chhol@microsoft.com) -- Bump @microsoft/fast-element to v2.0.0-beta.23 - -## 3.0.0-alpha.26 - -Sat, 11 Mar 2023 00:09:48 GMT - -### Changes - -- remove readonly support from fast radio (yinon@hotmail.com) -- update slider to increment and decrement without a default value for the step attribute (chhol@microsoft.com) -- picker should work in shadow dom (stephcomeau@msn.com) -- data grid header fix (stephcomeau@msn.com) -- fix: update components to new binding APIs (rob@bluespire.com) -- fix: remove focus management from slider (jes@microsoft.com) -- remove className logic from switch checkedChanged (chhol@microsoft.com) -- Fixes Slider vertical orientation so adjusting the slider increases the value when the thumb is moved upwards and corrects keyboard handling (ryan@ryanmerrill.net) -- Bump @microsoft/fast-element to v2.0.0-beta.22 - -## 3.0.0-alpha.25 - -Tue, 14 Feb 2023 04:02:34 GMT - -### Changes - -- fix radio group disabled handling (chhol@microsoft.com) -- remove readonly classname from switch (chhol@microsoft.com) -- add explicit exports for component orientations (chhol@microsoft.com) -- ensure single expand mode accordions support explicitly expanded items (chhol@microsoft.com) -- Cleaned up `start` and `end` definitions (47367562+bheston@users.noreply.github.com) -- add default slot to divider (chhol@microsoft.com) -- observe accordion children to accommodate single expand scenarios with programmatic changes (chhol@microsoft.com) -- Fix Picker template missing quote and dependent tag names (47367562+bheston@users.noreply.github.com) -- remove paused attribute from progress (chhol@microsoft.com) -- remove status messages from switch template (chhol@microsoft.com) -- fixes an issue where accordion expand-mode changes were not reflected in the component (chhol@microsoft.com) -- Remove link from Avatar (47367562+bheston@users.noreply.github.com) -- Bump @microsoft/fast-element to v2.0.0-beta.21 - -## 3.0.0-alpha.24 - -Wed, 11 Jan 2023 22:07:43 GMT - -### Changes - -- fix(Calendar): add fix for the timezones from #5539 (Mathieu.Salois@goto.com) -- export staticallyCompose function (chhol@microsoft.com) -- remove deprecation notice from display helpers (chhol@microsoft.com) -- add disabled attribute support to accordion item (chhol@microsoft.com) -- add ValuesOf helper for mapping types from a const object (chhol@microsoft.com) -- Removed legacy unsupported delegates focus from Anchor and Button now that `delgatesFocus` is supported in firefox since version 94. (32497422+KingOfTac@users.noreply.github.com) -- updates types for default slotted content to remove string and support DangerousHTMLDirective (chhol@microsoft.com) -- update default value of menu item checked attribute to false (chhol@microsoft.com) -- add missing part attribute for tabpanel in tabs (chhol@microsoft.com) -- clean up header on disconnect (stephcomeau@msn.com) -- Fixed bug in DesignTokenNode reparenting (nicholasrice@users.noreply.github.com) -- rework scroll into view (stephcomeau@msn.com) -- ensure submenu items are navigable after parent menu item has been clicked (chhol@microsoft.com) -- refactor(fast-foundation): template inline options and html.partial (roeisenb@microsoft.com) -- rewrite tooltip to use floating-ui (863023+radium-v@users.noreply.github.com) -- Bump @microsoft/fast-element to v2.0.0-beta.20 - -## 3.0.0-alpha.23 - -Fri, 02 Dec 2022 01:18:22 GMT - -### Changes - -- checkbox remove irrelevant read-only property (yinon@hotmail.com) -- Bump @microsoft/fast-element to v2.0.0-beta.19 - -## 3.0.0-alpha.22 - -Tue, 15 Nov 2022 02:40:34 GMT - -### Changes - -- add aria-orientation to radio-group (olaf-k@users.noreply.github.com) -- Fixing bug in DesignToken causing RangeError (nicholasrice@users.noreply.github.com) -- chore: move ViewBehaviorOrchestrator to utilities (roeisenb@microsoft.com) -- feat: add new DOM Policy protection throughout (roeisenb@microsoft.com) -- Bump @microsoft/fast-element to v2.0.0-beta.18 - -## 3.0.0-alpha.21 - -Fri, 04 Nov 2022 22:28:49 GMT - -### Changes - -- feat: enable using design tokens in html (roeisenb@microsoft.com) - -## 3.0.0-alpha.20 - -Tue, 01 Nov 2022 23:26:26 GMT - -### Changes - -- Bump @microsoft/fast-element to v2.0.0-beta.17 - -## 3.0.0-alpha.19 - -Fri, 28 Oct 2022 20:44:44 GMT - -### Changes - -- use floating-ui for menu-item submenus (863023+radium-v@users.noreply.github.com) -- use floating-ui for select and combobox (863023+radium-v@users.noreply.github.com) -- remove indent logic from foundation menu and menu item, move to example (chhol@microsoft.com) -- remove unnecessary composedParent & composedContains exports from Foundation (tebin.raouf@thomsonreuters.com) -- Bump @microsoft/fast-element to v2.0.0-beta.16 - -## 3.0.0-alpha.18 - -Tue, 25 Oct 2022 20:24:32 GMT - -### Changes - -- add readonly property to identify tree items and udpate isTreeItemElement check (chhol@microsoft.com) -- remove unnecessary click handler from legacy button span implementation (32497422+KingOfTac@users.noreply.github.com) -- Bump @microsoft/fast-element to v2.0.0-beta.15 - -## 3.0.0-alpha.17 - -Fri, 14 Oct 2022 18:26:11 GMT - -### Changes - -- indeterminate checkboxes should set an aria-checked state of mixed (chhol@microsoft.com) -- feat: calendar attr to adjust weekday start (robarb@microsoft.com) -- Bump @microsoft/fast-element to v2.0.0-beta.14 - -## 3.0.0-alpha.16 - -Mon, 10 Oct 2022 20:28:02 GMT - -### Changes - -- revert tree item changes from playwright migration (chhol@microsoft.com) -- Bump @microsoft/fast-element to v2.0.0-beta.13 - -## 3.0.0-alpha.15 - -Thu, 06 Oct 2022 23:21:20 GMT - -### Changes - -- Adds ability to close menu with Escape key (ryan@ryanmerrill.net) -- Bump @microsoft/fast-element to v2.0.0-beta.12 - -## 3.0.0-alpha.14 - -Wed, 05 Oct 2022 23:26:01 GMT - -### Changes - -- Bump @microsoft/fast-element to v2.0.0-beta.11 - -## 3.0.0-alpha.13 - -Mon, 03 Oct 2022 23:44:38 GMT - -### Changes - -- remove classes from host elements, add attributes to migrate observables, use data-t where it makes sensse (chhol@microsoft.com) -- fix: remove class from hs template root (jes@microsoft.com) -- Bump @microsoft/fast-element to v2.0.0-beta.10 - -## 3.0.0-alpha.12 - -Wed, 28 Sep 2022 20:45:51 GMT - -### Changes - -- Bump @microsoft/fast-element to v2.0.0-beta.9 - -## 3.0.0-alpha.11 - -Tue, 27 Sep 2022 22:31:52 GMT - -### Changes - -- Bump @microsoft/fast-element to v2.0.0-beta.8 - -## 3.0.0-alpha.10 - -Fri, 23 Sep 2022 22:53:27 GMT - -### Changes - -- feat: update foundation to new capture type (roeisenb@microsoft.com) -- Convert karma and mocha tests to playwright (863023+radium-v@users.noreply.github.com) -- fix(fast-foundation): update mixin helper to use new attribute api (roeisenb@microsoft.com) -- fix: update foundation to use the new behavior API (roeisenb@microsoft.com) -- removed redundant role setting in fast foundation menu-item template (yinon@hotmail.com) -- Bump @microsoft/fast-element to v2.0.0-beta.7 - -## 3.0.0-alpha.9 - -Thu, 01 Sep 2022 21:53:34 GMT - -### Changes - -- remove boolean logical operator use for setting default slotted content in favor of nullish coalescing operator (chhol@microsoft.com) -- update templates to ensure component classes can be extended (chhol@microsoft.com) -- remove when directive from flipper (chhol@microsoft.com) -- call change when search component clear button is clicked (jes@microsoft.com) -- Lazily attach FASTDesignTokenNode to the default node to prevent errors" (nicholasrice@users.noreply.github.com) -- fix: update foundation to use new import paths (roeisenb@microsoft.com) -- remove references to renderCollapsedNodes and renderCollapsedChildren from tree view and tree item (chhol@microsoft.com) -- ensure switch cannot be invoked via keyboard when in readonly mode (chhol@microsoft.com) -- Adds DesignTokenStyleTarget to support DesignToken style collection for SSR (nicholasrice@users.noreply.github.com) -- Bump @microsoft/fast-element to v2.0.0-beta.6 - -## 3.0.0-alpha.8 - -Fri, 26 Aug 2022 18:06:43 GMT - -### Changes - -- normalize storybook stories (863023+radium-v@users.noreply.github.com) -- fix(tabs): home and end navigation (mathieulavoie94@gmail.com) -- Fix constraint validation in focus-delegated components (nicholasrice@users.noreply.github.com) - -## 3.0.0-alpha.7 - -Thu, 18 Aug 2022 20:46:10 GMT - -### Changes - -- change select() method to public on number field, text field, and text area (7282195+m-akinc@users.noreply.github.com) -- add subpath export for package.json to packages (32497422+KingOfTac@users.noreply.github.com) -- anchored-region checks local shadow dom (stephcomeau@msn.com) -- use nullableNumberConverter for tooltip delay attribute (chhol@microsoft.com) -- adding event-based resolution strategy export (nicholasrice@users.noreply.github.com) -- refactor to allow arbitrary PropertyTarget types for DesignToken roots (nicholasrice@users.noreply.github.com) -- hidden horizontal-scroll fix (robarb@microsoft.com) -- Refactor DesignToken to provide a resolve function to derived token values, implements WebComponent implementation on top of isomorphic DesignToken infrastructure (nicholasrice@users.noreply.github.com) -- Bump @microsoft/fast-element to v2.0.0-beta.5 - -## 3.0.0-alpha.6 - -Wed, 27 Jul 2022 17:36:33 GMT - -### Changes - -- Using getBoundingClientRect for horizontal-scroll (robarb@microsoft.com) -- Removed the `fill`, `color`, and `shape` attributes and styling from Avatar (47367562+bheston@users.noreply.github.com) - -## 3.0.0-alpha.5 - -Mon, 18 Jul 2022 21:10:01 GMT - -### Changes - -- add export for custom elements manifest (32497422+KingOfTac@users.noreply.github.com) -- add start and end slots to tab (chhol@microsoft.com) -- feat: update foundation to new binding APIs (roeisenb@microsoft.com) -- feat: move testing and dependency injection to fast-element (roeisenb@microsoft.com) -- feat: remove design system, foundation element & related infrastructure (roeisenb@microsoft.com) -- update breadcrumb item to always use an anchor and ensure aria-current is applied correctly in breadcrumb (chhol@microsoft.com) -- add activeid to accordion change event (chhol@microsoft.com) -- Removed the `fill` and `color` attributes and styling from Badge (47367562+bheston@users.noreply.github.com) -- feat: enable fallback container creation for dependency injection location APIs (roeisenb@microsoft.com) -- accordion verifies change events (stephcomeau@msn.com) -- add storybook to fast-foundation (863023+radium-v@users.noreply.github.com) -- Bump @microsoft/fast-element to v2.0.0-beta.4 - -## 3.0.0-alpha.4 - -Wed, 22 Jun 2022 20:17:50 GMT - -### Changes - -- handle change for source.max set to sliderMaxPosition (email not defined) -- fast-foundation checkbox - turn off indeterminate on user `checked` change (yinon@hotmail.com) -- prevent keyboard events with space when checkbox is readonly (chhol@microsoft.com) -- feat: horizontal-scroll scroll item into view (robarb@microsoft.com) - -## 3.0.0-alpha.3 - -Wed, 15 Jun 2022 17:41:10 GMT - -### Changes - -- chore: fix package.json type fields (roeisenb@microsoft.com) -- only rollup foundation after compiling with tsc (863023+radium-v@users.noreply.github.com) -- Compare radio value property instead of attribute when value changes (sknoslo@gmail.com) -- feat: simplify execution context to align closer with v1 (roeisenb@microsoft.com) -- feat: implement W3C WC community context protocol and integrate with DI (roeisenb@microsoft.com) - -## 3.0.0-alpha.2 - -Wed, 01 Jun 2022 22:21:24 GMT - -### Changes - -- Force version update (nicholasrice@users.noreply.github.com) - -## 3.0.0-alpha.1 - -Wed, 01 Jun 2022 17:53:14 GMT - -### Changes - -- fix: update foundation and components template types (roeisenb@microsoft.com) -- chore: update imports to match latest fast-element exports (roeisenb@microsoft.com) -- fix incorrect and unsemantic slot names for search (chhol@microsoft.com) -- fix: update to latest fast-element and change exports (roeisenb@microsoft.com) -- update the default value of dialog's modal attribute to false (chhol@microsoft.com) -- remove unnecessary DOM nodes from start/end slot templates (chhol@microsoft.com) -- Updated to use the new FAST element 2.0 APIs for creating behaviors and creating element styles (7559015+janechu@users.noreply.github.com) -- feat: officially expose testing helpers (roeisenb@microsoft.com) -- chore: configure fast-foundation for internals stripping (roeisenb@microsoft.com) -- change activeindicator attribute in tabs to hide-active-indicator to better support boolean attribute behavior (chhol@microsoft.com) -- remove class and part names from slots in fast foundation templates (chhol@microsoft.com) -- Deprecates style utilities and hard-codes focus-visible value (nicholasrice@users.noreply.github.com) -- update attribute and observable change handlers with internal logic to be protected instead of private (chhol@microsoft.com) -- fix: update foundation to new CSSDirective API (roeisenb@microsoft.com) -- fix: update foundation to new APIs (roeisenb@microsoft.com) -- fix: update fast-foundation to not use deprecated APIs (roeisenb@microsoft.com) -- remove deprecated item slot name on accordion as it is the default slot (chhol@microsoft.com) -- Set prerelease version (nicholasrice@users.noreply.github.com) -- fix: update templates to use classList and fix classList bug (roeisenb@microsoft.com) -- chore: fast-foundation package and build modernization (roeisenb@microsoft.com) -- change trapFocus on dialog to noFocusTrap to better support boolean attributes (chhol@microsoft.com) -- rename title attribute on disclosure to summary (chhol@microsoft.com) - -## 2.46.9 - -Sun, 29 May 2022 07:08:52 GMT - -### Patches - -- fix: fast-foundation - 'get' and 'set' accessor must have the same type (#5964) (aagharat@dstworldwideservices.com) - -## 2.46.8 - -Thu, 26 May 2022 07:11:44 GMT - -### Patches - -- Revert "fix: add missing required attribute binding to switch template (#6014)" (burtonsmith@microsoft.com) - -## 2.46.7 - -Wed, 25 May 2022 07:09:21 GMT - -### Patches - -- add missing binding for required attribute in the switch template (chhol@microsoft.com) - -## 2.46.6 - -Tue, 24 May 2022 07:10:02 GMT - -### Patches - -- Bump @microsoft/fast-element to v1.10.2 (roeisenb@microsoft.com) - -## 2.46.5 - -Sun, 22 May 2022 07:09:02 GMT - -### Patches - -- disable keyboard controls for readonly sliders (burtonsmith@microsoft.com) - -## 2.46.4 - -Thu, 19 May 2022 07:09:40 GMT - -### Patches - -- Handle disabled and hidden items in toolbar (20542556+mollykreis@users.noreply.github.com) - -## 2.46.3 - -Tue, 10 May 2022 07:11:04 GMT - -### Patches - -- select ignores l&r arrow keys (scomea@microsoft.com) - -## 2.46.2 - -Thu, 05 May 2022 07:11:41 GMT - -### Patches - -- fix positioning of select dropdown (abris96@gmail.com) -- reset selection range when selecting option with cursor (abris96@gmail.com) - -## 2.46.1 - -Wed, 04 May 2022 07:14:00 GMT - -### Patches - -- convert enums to const objects and add supported typings (chhol@microsoft.com) - -## 2.46.0 - -Tue, 03 May 2022 07:15:44 GMT - -### Minor changes - -- add slots and events documentation (scomea@microsoft.com) - -### Patches - -- reflect option value changes in select (john.kreitlow@microsoft.com) -- fix: selectedIndex property ignores disabled options in listbox and select (john.kreitlow@microsoft.com) -- viewport lock + fill behavior (scomea@microsoft.com) -- Upgraded api-extractor (44823142+williamw2@users.noreply.github.com) -- Bump @microsoft/fast-element to v1.10.1 (44823142+williamw2@users.noreply.github.com) - -## 2.45.0 - -Sun, 01 May 2022 07:12:05 GMT - -### Minor changes - -- add select method to number field, text field, and text area components (chhol@microsoft.com) - -### Patches - -- ensure that tabs and tabpanels without ids stay in sync (chhol@microsoft.com) -- trim extra spaces from the text property for listbox-option (john.kreitlow@microsoft.com) -- fix keyboarding behavior for right and left arrow keys in Tree View (chhol@microsoft.com) - -## 2.44.0 - -Thu, 28 Apr 2022 07:12:47 GMT - -### Minor changes - -- update displayed selected value in select component when an option changes (john.kreitlow@microsoft.com) - -## 2.43.0 - -Wed, 27 Apr 2022 07:21:09 GMT - -### Minor changes - -- update to typescript 4.6.2 and update ARIAMixin typings (chhol@microsoft.com) - -### Patches - -- Bump @microsoft/fast-web-utilities to v5.4.0 (chhol@microsoft.com) -- Bump @microsoft/fast-element to v1.10.0 (chhol@microsoft.com) - -## 2.42.2 - -Thu, 21 Apr 2022 07:13:54 GMT - -### Patches - -- Added support for styling slider value on the track (47367562+bheston@users.noreply.github.com) - -## 2.42.1 - -Sun, 17 Apr 2022 07:11:18 GMT - -### Patches - -- fix: scrolling back from end and forward retains next flipper in horizontal-scroll (robarb@microsoft.com) -- Ensured that tabs without an ID use a unique ID to prevent duplicate IDs when multiple tabs are on a page (chhol@microsoft.com) -- Ensure the skeleton component's object element is not included in the accessibility tree (chhol@microsoft.com) - -## 2.42.0 - -Thu, 14 Apr 2022 07:12:36 GMT - -### Minor changes - -- Implements `` element events on FastDialog (web@bennypowers.com) -- add multiselect mode to select (john.kreitlow@microsoft.com) - -## 2.41.1 - -Thu, 07 Apr 2022 07:12:06 GMT - -### Patches - -- Improved README markdown formatting (44823142+williamw2@users.noreply.github.com) - -## 2.41.0 - -Wed, 06 Apr 2022 07:12:42 GMT - -### Minor changes - -- convert fast-foundation to type:module (nicholasrice@users.noreply.github.com) - -### Patches - -- Added CEM Analyzer and API markdown to readme files (44823142+williamw2@users.noreply.github.com) -- Bump @microsoft/fast-element to v1.9.0 (nicholasrice@users.noreply.github.com) - -## 2.40.0 - -Sun, 03 Apr 2022 07:12:01 GMT - -### Minor changes - -- update aria-current for breadcrumb items when new nodes are appended (chhol@microsoft.com) -- remove fromView from aria mixin attributes (chhol@microsoft.com) - -### Patches - -- Bump @microsoft/fast-web-utilities to v5.2.0 (nicholasrice@users.noreply.github.com) - -## 2.39.0 - -Thu, 31 Mar 2022 07:13:31 GMT - -### Minor changes - -- remove duplicate use of heading class in accordion item and update part location (chhol@microsoft.com) - -### Patches - -- fix hidden menu items should not be included in the tabindex (chhol@microsoft.com) - -## 2.38.0 - -Sun, 27 Mar 2022 07:11:50 GMT - -### Minor changes - -- Changed Select open attribute to public (44823142+williamw2@users.noreply.github.com) -- Add string literal union types to all foundation components that use an enum for attribute options (hawkticehurst@gmail.com) - -## 2.37.2 - -Thu, 24 Mar 2022 07:12:08 GMT - -### Patches - -- Detect changes to start and end slots in toolbar (20542556+mollykreis@users.noreply.github.com) - -## 2.37.1 - -Sun, 20 Mar 2022 07:15:44 GMT - -### Patches - -- Fix for default selection behavior for listbox and select (26874831+atmgrifter00@users.noreply.github.com) - -## 2.37.0 - -Wed, 16 Mar 2022 07:12:41 GMT - -### Minor changes - -- enable no tabbing (scomea@microsoft.com) - -## 2.36.1 - -Tue, 15 Mar 2022 07:12:38 GMT - -### Patches - -- anchored region not beta (scomea@microsoft.com) -- tree view single select (scomea@microsoft.com) - -## 2.36.0 - -Fri, 11 Mar 2022 23:46:34 GMT - -### Minor changes - -- BREAKING CHANGE: replace WC button with stock HTML button (jes@microsoft.com) -- implement attribute reflection directive (nicholasrice@users.noreply.github.com) - -### Patches - -- use WeakMap to prevent leaking element references from FormAssociated (nicholasrice@users.noreply.github.com) - -## 2.35.2 - -Wed, 09 Mar 2022 07:12:32 GMT - -### Patches - -- Fix bug with menu-item indention (20542556+mollykreis@users.noreply.github.com) - -## 2.35.1 - -Tue, 08 Mar 2022 07:12:45 GMT - -### Patches - -- Fix programmatic disable/enable of tabs (5454342+brianehenry@users.noreply.github.com) - -## 2.35.0 - -Sun, 06 Mar 2022 07:13:48 GMT - -### Minor changes - -- add corner positions to tooltip (sethdonohue@Admins-MBP.guest.corp.microsoft.com) - -### Patches - -- passive handlers (scomea@microsoft.com) -- tooltip hover (scomea@microsoft.com) - -## 2.34.0 - -Wed, 02 Mar 2022 07:12:58 GMT - -### Minor changes - -- add mermaid support (steph@huynhicode.dev) - -### Patches - -- generate grid columns for manual grid (scomea@microsoft.com) -- auto columns fix (scomea@microsoft.com) -- Fixing no previous scroll when only 2 items (robarb@microsoft.com) - -## 2.33.6 - -Fri, 25 Feb 2022 17:09:32 GMT - -### Patches - -- Bump @microsoft/fast-element to v1.7.2 (roeisenb@microsoft.com) - -## 2.33.5 - -Thu, 24 Feb 2022 22:21:55 GMT - -### Patches - -- Format improvement to match standards (16669785+awentzel@users.noreply.github.com) -- fix combobox and select position when set after init (corylaviska@microsoft.com) -- allow programmatic control of the open property for select and combobox (john.kreitlow@microsoft.com) - -## 2.33.4 - -Sun, 20 Feb 2022 07:16:20 GMT - -### Patches - -- tree view events (scomea@microsoft.com) - -## 2.33.3 - -Tue, 15 Feb 2022 07:11:28 GMT - -### Patches - -- disable noImplicitAny in fast-foundation (mathieu.lavoie@shopify.com) - -## 2.33.2 - -Thu, 10 Feb 2022 07:12:01 GMT - -### Patches - -- Fix initial select value when set early after connect (5454342+brianehenry@users.noreply.github.com) - -## 2.33.1 - -Wed, 09 Feb 2022 07:14:00 GMT - -### Patches - -- allow empty string values for listbox-option value attribute (john.kreitlow@microsoft.com) - -## 2.33.0 - -Sun, 06 Feb 2022 07:15:20 GMT - -### Minor changes - -- add menu positioning to picker (scomea@microsoft.com) -- add multiselect functionality to listbox (john.kreitlow@microsoft.com) - -### Patches - -- ensure menu items update (scomea@microsoft.com) -- fix: diabled listbox missing styles & allows click (jes@microsoft.com) -- fix: allow slider to show small increment changes (jes@microsoft.com) -- fix: flippersHiddenFromAT shouldn't map to aria-hidden (robarb@microsoft.com) -- tooltip anchor attribute updates work (scomea@microsoft.com) - -## 2.32.3 - -Wed, 02 Feb 2022 07:13:39 GMT - -### Patches - -- fix: February tests are failing in calendar tests (robarb@microsoft.com) -- fix broken links and formatting (john.kreitlow@microsoft.com) - -## 2.32.2 - -Sun, 30 Jan 2022 07:12:35 GMT - -### Patches - -- convert functions to templates (mathieulavoie94@gmail.com) - -## 2.32.1 - -Tue, 25 Jan 2022 07:11:53 GMT - -### Patches - -- Bump @microsoft/fast-web-utilities to v5.1.0 (john.kreitlow@microsoft.com) - -## 2.32.0 - -Sun, 23 Jan 2022 07:13:56 GMT - -### Minor changes - -- feat: add `orientation` to divider (jes@microsoft.com) - -### Patches - -- use default slot in accordion (mathieulavoie94@gmail.com) -- Bump @microsoft/fast-element to v1.7.0 (scomea@microsoft.com) - -## 2.31.0 - -Thu, 20 Jan 2022 07:12:04 GMT - -### Minor changes - -- add checked property to listbox-option (john.kreitlow@microsoft.com) - -## 2.30.0 - -Sun, 16 Jan 2022 07:11:36 GMT - -### Minor changes - -- Add valueAsNumber to number field and slider (5454342+brianehenry@users.noreply.github.com) - -## 2.29.0 - -Sun, 09 Jan 2022 07:11:51 GMT - -### Minor changes - -- fix accessibility for listbox, select, and combobox (john.kreitlow@microsoft.com) - -## 2.28.0 - -Thu, 06 Jan 2022 07:11:52 GMT - -### Minor changes - -- fix: prevent events to propagate from disabled button (#4884) (email not defined) - -### Patches - -- tooltip uses "center" (scomea@microsoft.com) - -## 2.27.3 - -Sun, 19 Dec 2021 07:12:39 GMT - -### Patches - -- Replace equality check with NaN with the Number.isNan function (anthonystewart@google.com) -- add queueUpdate for setStops in horzontal scroll (sethdonohue@Admins-MBP.guest.corp.microsoft.com) - -## 2.27.2 - -Wed, 15 Dec 2021 07:14:44 GMT - -### Patches - -- focus on combobox control when clicking an associated label (john.kreitlow@microsoft.com) - -## 2.27.1 - -Thu, 02 Dec 2021 07:11:13 GMT - -### Patches - -- fix: disabled tree items fire (jes@microsoft.com) - -## 2.27.0 - -Tue, 23 Nov 2021 07:12:23 GMT - -### Minor changes - -- add `size` attribute to listbox element (john.kreitlow@microsoft.com) - -## 2.26.2 - -Thu, 11 Nov 2021 07:15:33 GMT - -### Patches - -- convert tsdoc-config dependency to dev-dependency (nicholasrice@users.noreply.github.com) - -## 2.26.1 - -Wed, 10 Nov 2021 07:12:54 GMT - -### Patches - -- Enabling setting number-field value through script (robarb@microsoft.com) - -## 2.26.0 - -Tue, 09 Nov 2021 07:14:09 GMT - -### Minor changes - -- feat: add search web component (jes@microsoft.com) - -## 2.25.1 - -Thu, 04 Nov 2021 07:11:59 GMT - -### Patches - -- fix: change event emitted twice (jes@microsoft.com) - -## 2.25.0 - -Wed, 03 Nov 2021 07:12:39 GMT - -### Minor changes - -- add placeholder attr to picker (scomea@microsoft.com) - -## 2.24.0 - -Sun, 31 Oct 2021 07:17:45 GMT - -### Minor changes - -- Added the CheckableFormAssociated mixin to better support the addition of current-checked property/attribute that allows for setting checked state via the .setAttribute() API. This change also converts two lifecycle hooks to methods from properties so that they can be handled correctly by the browser. (nicholasrice@users.noreply.github.com) - -### Patches - -- fix: number-field increment decrement logic (robarb@microsoft.com) -- picker focus on input after selection (scomea@microsoft.com) -- update fast eslint package version (chhol@microsoft.com) -- Bump @microsoft/fast-element to v1.6.2 (chhol@microsoft.com) -- Bump @microsoft/fast-web-utilities to v5.0.2 (chhol@microsoft.com) - -## 2.23.2 - -Thu, 28 Oct 2021 07:15:32 GMT - -### Patches - -- fixes emission of CSS custom properties in FireFox and Safari (nicholasrice@users.noreply.github.com) - -## 2.23.1 - -Wed, 27 Oct 2021 07:11:58 GMT - -### Patches - -- switch should check when using both enter and space (chhol@microsoft.com) - -## 2.23.0 - -Fri, 22 Oct 2021 17:40:52 GMT - -### Minor changes - -- adds a currentValue property to form-associated to facilitate attribute-based data binding for form values (chhol@microsoft.com) - -### Patches - -- picker clear query on selection (scomea@microsoft.com) -- Improving number field interactions and tests (robarb@microsoft.com) - -## 2.22.1 - -Thu, 21 Oct 2021 07:11:42 GMT - -### Patches - -- fix broken tooltip (scomea@microsoft.com) - -## 2.22.0 - -Wed, 20 Oct 2021 07:13:46 GMT - -### Minor changes - -- add centered positioning option to anchored region (scomea@microsoft.com) - -## 2.21.0 - -Fri, 15 Oct 2021 23:24:14 GMT - -### Minor changes - -- Implement DesignToken root-element registration for CSS custom property emission of default token values (nicholasrice@users.noreply.github.com) - -### Patches - -- implement level-2 DOM support for DesignToken in browsers that don't support Constructable StyleSheets (nicholasrice@users.noreply.github.com) - -## 2.20.0 - -Wed, 13 Oct 2021 22:45:16 GMT - -### Minor changes - -- Adding fast-calendar component (robarb@microsoft.com) - -### Patches - -- move style assignment for combobox and select into the class and off the DOM node (chhol@microsoft.com) -- Code fixes for calendar (robarb@microsoft.com) -- Bump @microsoft/fast-element to v1.6.1 (markwhitfeld@users.noreply.github.com) - -## 2.19.0 - -Wed, 13 Oct 2021 01:53:37 GMT - -### Minor changes - -- data-grid: add support for rowheader role (scomea@microsoft.com) -- Add focus event handler to tooltip (v-dlesac@microsoft.com) - -### Patches - -- refactor: remove lodash-es as a dependency (connor@peet.io) -- use css transforms and transitions in horizontal scroll (john.kreitlow@microsoft.com) -- Bump @microsoft/fast-web-utilities to v5.0.1 (john.kreitlow@microsoft.com) - -## 2.18.0 - -Tue, 12 Oct 2021 07:15:14 GMT - -### Minor changes - -- fix(di): context confused for key with some registrations (roeisenb@microsoft.com) - -### Patches - -- Update design-token default value emission to emit to a stylesheet instead of inline styles on the document body (nicholasrice@users.noreply.github.com) -- add aria-disabled to accordion-item for single-mode (khamu@microsoft.com) - -## 2.17.3 - -Sun, 10 Oct 2021 07:12:26 GMT - -### Patches - -- fix linting errors in horizontal-scroll tests (john.kreitlow@microsoft.com) - -## 2.17.2 - -Fri, 08 Oct 2021 19:53:11 GMT - -### Patches - -- anchored region force update (scomea@microsoft.com) - -## 2.17.1 - -Wed, 06 Oct 2021 07:11:47 GMT - -### Patches - -- picker menu shows with only custom options (scomea@microsoft.com) - -## 2.17.0 - -Tue, 05 Oct 2021 00:45:07 GMT - -### Minor changes - -- feat: add scroll events to horizontal-scroll component (robarb@microsoft.com) - -### Patches - -- fix: nested tree items not selecting (jes@microsoft.com) - -## 2.16.5 - -Thu, 30 Sep 2021 07:13:45 GMT - -### Patches - -- Disabling scroll easing for speed=0 (robarb@microsoft.com) - -## 2.16.4 - -Wed, 29 Sep 2021 07:13:40 GMT - -### Patches - -- do not prevent default on tree item click (chhol@microsoft.com) -- fix: allowing decimal values in fast number field (robarb@microsoft.com) -- fix: sliders mouseup is not firing when leaving the window (robarb@microsoft.com) - -## 2.16.3 - -Tue, 28 Sep 2021 07:10:49 GMT - -### Patches - -- made orientation changed update child tab styles (marjon@microsoft.com) -- Fix: active indicator keyboarding issue in tabs (jes@microsoft.com) - -## 2.16.2 - -Mon, 27 Sep 2021 07:12:15 GMT - -### Patches - -- fix: ensure tree item selection is only managed in tree view (jes@microsoft.com) - -## 2.16.1 - -Thu, 23 Sep 2021 07:14:34 GMT - -### Patches - -- Removing design-system-provider from storybook (robarb@microsoft.com) -- Horizontal-scroll tests cleanup (robarb@microsoft.com) - -## 2.16.0 - -Wed, 22 Sep 2021 07:13:13 GMT - -### Minor changes - -- feat(di): add registerWithContext and use in design system (roeisenb@microsoft.com) - -### Patches - -- fix: active indicator does not update when activeid attr is changed (jes@microsoft.com) -- fix aria-describedby typos (v-dlesac@microsoft.com) - -## 2.15.0 - -Sun, 19 Sep 2021 07:17:17 GMT - -### Minor changes - -- add picker component (scomea@microsoft.com) - -### Patches - -- fix: remove dependency on document for root containers & design systems (roeisenb@microsoft.com) -- Bump @microsoft/fast-web-utilities to v5.0.0 (scomea@microsoft.com) - -## 2.14.0 - -Wed, 15 Sep 2021 19:49:35 GMT - -### Minor changes - -- fix type issue for FoundationElementTemplate (john.kreitlow@microsoft.com) - -### Patches - -- Fix design-token subscription bugs where subscribers were not getting notified (nicholasrice@users.noreply.github.com) - -## 2.13.1 - -Tue, 14 Sep 2021 07:16:47 GMT - -### Patches - -- Using a manual focus to workaround delegatesFocus issues on Firefox for the button and anchor components (jumarroq@microsoft.com) - -## 2.13.0 - -Sun, 12 Sep 2021 07:17:43 GMT - -### Minor changes - -- use class method for radio click handler property (john.kreitlow@microsoft.com) - -### Patches - -- remove dependencies on keycode (scomea@microsoft.com) -- Bump @microsoft/fast-web-utilities to v4.8.1 (scomea@microsoft.com) - -## 2.12.0 - -Thu, 09 Sep 2021 07:21:36 GMT - -### Minor changes - -- add start/end slot definitions to support default slotted content (chhol@microsoft.com) - -### Patches - -- fix(design-system): make FoundationElement.compose safe to use directly (roeisenb@microsoft.com) - -## 2.11.0 - -Wed, 08 Sep 2021 07:16:17 GMT - -### Minor changes - -- fix: allow for base class (mathieu.lavoie@logmein.com) - -### Patches - -- force non-volatile binding and update docs to explain that DesignToken does not support volatile bindings (nicholasrice@users.noreply.github.com) -- Bump @microsoft/fast-element to v1.5.1 (roeisenb@microsoft.com) - -## 2.10.0 - -Thu, 02 Sep 2021 17:17:56 GMT - -### Minor changes - -- feat(design-system): enable complete ignore of duplicate elements (roeisenb@microsoft.com) - -## 2.9.1 - -Thu, 02 Sep 2021 07:15:21 GMT - -### Patches - -- configure system to use a single CSSStyleSheet for custom property setting (nicholasrice@users.noreply.github.com) -- progress component bar width (scomea@microsoft.com) -- Removed remaining 'use-defaults' which no longer exists (47367562+bheston@users.noreply.github.com) - -## 2.9.0 - -Wed, 01 Sep 2021 07:18:34 GMT - -### Minor changes - -- add viewport lock to tooltip (scomea@microsoft.com) - -### Patches - -- don't block all keys while focused (corylaviska@microsoft.com) - -## 2.8.1 - -Mon, 30 Aug 2021 22:30:39 GMT - -### Patches - -- fixing issue where a token would subscribe to itself, causing max-callstack-exceded in certain scenarios (nicholasrice@users.noreply.github.com) - -## 2.8.0 - -Fri, 27 Aug 2021 14:14:26 GMT - -### Minor changes - -- Refactor DesignToken implementation to support deep token dependency hierarchies (nicholasrice@users.noreply.github.com) - -### Patches - -- add up/down key support to number-field (corylaviska@microsoft.com) -- Bump @microsoft/fast-element to v1.5.0 (nicholasrice@users.noreply.github.com) - -## 2.7.1 - -Thu, 26 Aug 2021 07:17:43 GMT - -### Patches - -- fix slider dragging when page is scrolled (corylaviska@microsoft.com) - -## 2.7.0 - -Wed, 25 Aug 2021 07:17:07 GMT - -### Minor changes - -- allow context for partials on component compositions (john.kreitlow@microsoft.com) - -## 2.6.5 - -Thu, 19 Aug 2021 07:15:21 GMT - -### Patches - -- add reducefocusableElements and all slotted items to keyboard interaction (sethdonohue@Admins-MBP.guest.corp.microsoft.com) - -## 2.6.4 - -Thu, 12 Aug 2021 07:16:50 GMT - -### Patches - -- fix dialog focus on open (scomea@microsoft.com) - -## 2.6.3 - -Wed, 04 Aug 2021 07:15:14 GMT - -### Patches - -- menu should check for slot before automatically assigning a value (chhol@microsoft.com) - -## 2.6.2 - -Thu, 29 Jul 2021 07:18:18 GMT - -### Patches - -- remove unnecessary aria-hidden attributes (47367562+bheston@users.noreply.github.com) - -## 2.6.1 - -Wed, 28 Jul 2021 07:17:22 GMT - -### Patches - -- update on !regionVisible (scomea@microsoft.com) - -## 2.6.0 - -Sun, 25 Jul 2021 07:17:41 GMT - -### Minor changes - -- add auto position tracking to tooltip (scomea@microsoft.com) -- anchored region uses transform (scomea@microsoft.com) - -## 2.5.2 - -Thu, 22 Jul 2021 07:19:53 GMT - -### Patches - -- Fixed attr boolean mode on menu item (47367562+bheston@users.noreply.github.com) - -## 2.5.1 - -Wed, 21 Jul 2021 07:14:48 GMT - -### Patches - -- Hide step-up and step-down for number-field when readonly (robarb@microsoft.com) - -## 2.5.0 - -Thu, 15 Jul 2021 01:41:48 GMT - -### Minor changes - -- extend design token type signature (chhol@microsoft.com) - -## 2.4.0 - -Tue, 13 Jul 2021 07:14:52 GMT - -### Minor changes - -- docs(di): make API public, stabilize, and add docs (roeisenb@microsoft.com) - -## 2.3.0 - -Wed, 07 Jul 2021 07:19:51 GMT - -### Minor changes - -- focus trap improvement (scomea@microsoft.com) - -## 2.2.0 - -Sun, 04 Jul 2021 07:15:28 GMT - -### Minor changes - -- select should emit an input event before the change event (john.kreitlow@microsoft.com) - -## 2.1.0 - -Thu, 01 Jul 2021 07:15:57 GMT - -### Minor changes - -- ensure DesignToken considers shadow DOM when determining DOM hierarchy (nicholasrice@users.noreply.github.com) - -### Patches - -- Fixes bug in DesignToken where aliased tokens didn't update CSS custom properties. (nicholasrice@users.noreply.github.com) - -## 2.0.0 - -Fri, 25 Jun 2021 02:02:57 GMT - -### Major changes - -- remove deprecated APIs and Design System Provider infrastructure (nicholasrice@users.noreply.github.com) -- feat(design-system): better integrate with DI and enforce constraints (roeisenb@microsoft.com) -- migrate directional-stylesheet utility (nicholasrice@users.noreply.github.com) -- update components to extend FoundationElement (chhol@microsoft.com) -- feat: styling and text alignment for menu (jes@microsoft.com) -- add API support for setting default slotted content as part of component composition (chhol@microsoft.com) -- update card to extend foundation (chhol@microsoft.com) -- feat: encapsulate and optimize ComponentPresentation resolution (roeisenb@microsoft.com) - -### Minor changes - -- fix(foundation-element): enable subclassing with customElement decorator (roeisenb@microsoft.com) -- feat(design-system): enable overriding the shadow root mode (roeisenb@microsoft.com) -- docs(fast-foundation): add api docs for design system and foundation ele (roeisenb@microsoft.com) - -## 1.24.8 - -Wed, 23 Jun 2021 22:58:18 GMT - -### Patches - -- prevent left/right arrows from scrolling when expanding/collapsing tree-item (tlmii@users.noreply.github.com) - -## 1.24.7 - -Sun, 20 Jun 2021 07:21:25 GMT - -### Patches - -- Enable stepping from null values on number-field (robarb@microsoft.com) -- fix malformed templates (scomea@microsoft.com) - -## 1.24.6 - -Sun, 13 Jun 2021 07:19:23 GMT - -### Patches - -- ensure host element of a shadowed element can be resolved (nicholasrice@users.noreply.github.com) - -## 1.24.5 - -Tue, 08 Jun 2021 07:29:18 GMT - -### Patches - -- streamline horizontal scroll resize (scomea@microsoft.com) - -## 1.24.4 - -Sun, 30 May 2021 07:42:30 GMT - -### Patches - -- Ensure stale Design Token custom property stylesheets are removed when token values change. (nicholasrice@users.noreply.github.com) -- fix bug caused by asserting parentElement was not null (nicholasrice@users.noreply.github.com) - -## 1.24.3 - -Wed, 26 May 2021 07:33:37 GMT - -### Patches - -- allow a float to be accurately represented when a step is a fraction (7559015+janechu@users.noreply.github.com) -- fix css custom property emission for dependent DesignToken properties (nicholasrice@users.noreply.github.com) - -## 1.24.2 - -Tue, 25 May 2021 07:27:43 GMT - -### Patches - -- fix data grid tabbing (scomea@microsoft.com) - -## 1.24.1 - -Fri, 21 May 2021 17:48:08 GMT - -### Patches - -- update to Design System Provider to use dom.supportsAdoptedStyleSheets (nicholasrice@users.noreply.github.com) - -## 1.24.0 - -Thu, 20 May 2021 07:24:10 GMT - -### Minor changes - -- add toolbar component (john.kreitlow@microsoft.com) - -### Patches - -- Bump @microsoft/fast-web-utilities to v4.8.0 (john.kreitlow@microsoft.com) - -## 1.23.0 - -Wed, 19 May 2021 23:37:36 GMT - -### Minor changes - -- Adds subscribe and unsubscribe methods to DesignToken (nicholasrice@users.noreply.github.com) -- Adds feature to DesignToken to prevent emission to CSS (nicholasrice@users.noreply.github.com) -- Addresses significant performance issues with DesignToken implmentation. This change removes several alpha APIs on DesignToken. (nicholasrice@users.noreply.github.com) - -### Patches - -- fix: update scrolling with delay loaded content (robarb@microsoft.com) -- menu should not reset tabIndex unnecessarily (scomea@microsoft.com) -- selected option is not visible when dropdown is opened in fast-select (john.kreitlow@microsoft.com) -- undefined (nicholasrice@users.noreply.github.com) -- fix: fast-number-field does not fire input event when buttons pressed (robarb@microsoft.com) -- Bump @microsoft/fast-element to v1.3.0 (nicholasrice@users.noreply.github.com) - -## 1.20.0 - -Sun, 25 Apr 2021 07:21:02 GMT - -### Minor changes - -- undefined (nicholasrice@users.noreply.github.com) - -## 1.19.0 - -Thu, 22 Apr 2021 07:21:10 GMT - -### Minor changes - -- adding withDefault method to DesignToken (nicholasrice@users.noreply.github.com) - -### Patches - -- add function to check for separator, add example and update style for not href item (khamu@microsoft.com) - -## 1.18.0 - -Fri, 16 Apr 2021 01:19:08 GMT - -### Minor changes - -- open up getter and setter functions to HTMLElement (nicholasrice@users.noreply.github.com) - -### Patches - -- add missing aria-expanded to the select template (mathieu.lavoie@logmein.com) -- remove incorrect role from horizontal-scroll element (chhol@microsoft.com) -- ensure DesignToken works with falsey values (nicholasrice@users.noreply.github.com) -- fix anchored region positioning bugs (scomea@microsoft.com) - -## [1.16.1](https://github.com/Microsoft/fast/compare/@microsoft/fast-foundation@1.16.0...@microsoft/fast-foundation@1.16.1) (2021-03-18) - - -### Bug Fixes - -* combobox with typescript ^4.0 ([#4475](https://github.com/Microsoft/fast/issues/4475)) ([e9d3b34](https://github.com/Microsoft/fast/commit/e9d3b345870b35c8ea9f2079537232c110129be1)) -* ensure no exception is thrown when no properties are defined ([#4469](https://github.com/Microsoft/fast/issues/4469)) ([40dc56c](https://github.com/Microsoft/fast/commit/40dc56c3b3a75af73d2bb92f653db11ae424cbf9)) - - - - - -# [1.16.0](https://github.com/Microsoft/fast/compare/@microsoft/fast-foundation@1.15.1...@microsoft/fast-foundation@1.16.0) (2021-03-16) - - -### Bug Fixes - -* add createMenuItem() to menu item template ([#4431](https://github.com/Microsoft/fast/issues/4431)) ([c86b63b](https://github.com/Microsoft/fast/commit/c86b63bd5323880f0dd859cbd2bf8a20ca1ccba0)), closes [#4414](https://github.com/Microsoft/fast/issues/4414) [#4412](https://github.com/Microsoft/fast/issues/4412) -* anchored region pointer events mk2 ([#4402](https://github.com/Microsoft/fast/issues/4402)) ([e0de62e](https://github.com/Microsoft/fast/commit/e0de62e0b1bbcccce9a757c6cd99b4130a702f8f)) -* broken formatting and link when generating docs site ([#4459](https://github.com/Microsoft/fast/issues/4459)) ([e817863](https://github.com/Microsoft/fast/commit/e81786349e7c65cfb888a151f0400c736c421912)) -* cannot use combobox with typescript ^4.0 ([#4442](https://github.com/Microsoft/fast/issues/4442)) ([3d52ef4](https://github.com/Microsoft/fast/commit/3d52ef43c327d4c5cdabc8f6a1dc514df4cea403)) -* combobox escape and arrow keys prevent listbox navigation ([#4443](https://github.com/Microsoft/fast/issues/4443)) ([aa594fe](https://github.com/Microsoft/fast/commit/aa594fecc8f237d80174e41dfff7cfe45562d6dd)) -* setting data grid focus should not throw ([#4466](https://github.com/Microsoft/fast/issues/4466)) ([3c56a18](https://github.com/Microsoft/fast/commit/3c56a185c6aa5dcb52c12a9393f51a36521c5f77)) - - -### Features - -* add ability to hide step controls and update reveal on hover and focus-within ([#4448](https://github.com/Microsoft/fast/issues/4448)) ([6f6497c](https://github.com/Microsoft/fast/commit/6f6497cba3883b741dddf3b6c78fd0d1571c02f3)) -* add expand/collapse icon to menu items ([#4438](https://github.com/Microsoft/fast/issues/4438)) ([db4e9fa](https://github.com/Microsoft/fast/commit/db4e9facad71dbfefce9d2c063dfc16c6b415426)) -* add horizontal scroll web component ([#4391](https://github.com/Microsoft/fast/issues/4391)) ([08508a5](https://github.com/Microsoft/fast/commit/08508a5860d6bf1f5a5719028c11e17433ac5ac3)), closes [#4414](https://github.com/Microsoft/fast/issues/4414) [#4412](https://github.com/Microsoft/fast/issues/4412) [#4416](https://github.com/Microsoft/fast/issues/4416) [#4437](https://github.com/Microsoft/fast/issues/4437) - - - - - -## [1.15.1](https://github.com/Microsoft/fast/compare/@microsoft/fast-foundation@1.15.0...@microsoft/fast-foundation@1.15.1) (2021-03-06) - - -### Bug Fixes - -* conditionally render input container for menuitemcheckbox and menuitemradio ([#4429](https://github.com/Microsoft/fast/issues/4429)) ([8561a99](https://github.com/Microsoft/fast/commit/8561a99898d012f1accd0658eef4e8fb211d5683)) - - - - - -# [1.15.0](https://github.com/Microsoft/fast/compare/@microsoft/fast-foundation@1.14.0...@microsoft/fast-foundation@1.15.0) (2021-03-06) - - -### Bug Fixes - -* add default expanded and collapsed SVGs to accordion-item component ([#4368](https://github.com/Microsoft/fast/issues/4368)) ([b0bea82](https://github.com/Microsoft/fast/commit/b0bea8203c3774b40e0561e37926a9f28794b4a9)) -* add radio and checkbox visual in fast-menu-item ([#4205](https://github.com/Microsoft/fast/issues/4205)) ([50efed4](https://github.com/Microsoft/fast/commit/50efed4a57b4a89d69a7079b581fdec8428dfe37)) -* data-grid stores generated templates ([#4412](https://github.com/Microsoft/fast/issues/4412)) ([7de9602](https://github.com/Microsoft/fast/commit/7de960213d593f0dcafcdcb291fc592564ca9ae4)) -* default selected option in listbox ([#4372](https://github.com/Microsoft/fast/issues/4372)) ([35870a6](https://github.com/Microsoft/fast/commit/35870a69d10ec52c983adb879d58343386d3a8d6)) -* focusout on empty select throws an error ([#4373](https://github.com/Microsoft/fast/issues/4373)) ([b2f2f29](https://github.com/Microsoft/fast/commit/b2f2f2907e0ad8f7f0eff89fc2106041edbe3474)) -* tooltip doc sample ([#4341](https://github.com/Microsoft/fast/issues/4341)) ([20e1b66](https://github.com/Microsoft/fast/commit/20e1b667abbe39058d5c4c358ccd8b8a93cee316)) -* whitespaceFilter filtering elements ([#4360](https://github.com/Microsoft/fast/issues/4360)) ([2f14137](https://github.com/Microsoft/fast/commit/2f14137579e1aa8f6724f0211c8baf2f2a6c8008)) -* **tooltip:** fix tooltip inside shadow root ([#4303](https://github.com/Microsoft/fast/issues/4303)) ([fc65f50](https://github.com/Microsoft/fast/commit/fc65f505fdf2b621c6cb9a29deccdb4a805b956a)) - - -### Features - -* add placeholder attribute to combobox component ([#4427](https://github.com/Microsoft/fast/issues/4427)) ([b507c25](https://github.com/Microsoft/fast/commit/b507c257c39ca44244bea7fdb4e07fc5b71b3eea)) -* **di:** enable dom containers to handle same element dep resolution ([#4406](https://github.com/Microsoft/fast/issues/4406)) ([e3145fe](https://github.com/Microsoft/fast/commit/e3145fe557eb56fc6aafa99f9803ecd7d07b55e5)) -* add combobox component ([#4379](https://github.com/Microsoft/fast/issues/4379)) ([aab8441](https://github.com/Microsoft/fast/commit/aab844120b40b14ef284718880dbe05da65a5392)) -* add nested menu support ([#4142](https://github.com/Microsoft/fast/issues/4142)) ([551ff04](https://github.com/Microsoft/fast/commit/551ff0467e9424bff00610c737744dbfa30cea9c)) -* **di:** enable use of the inject decorator on properties ([#4401](https://github.com/Microsoft/fast/issues/4401)) ([2f8355b](https://github.com/Microsoft/fast/commit/2f8355b932ba5083bdcb66a5c3381616699d2cef)) -* add prefers-color-scheme behaviors for light and dark mode ([#4382](https://github.com/Microsoft/fast/issues/4382)) ([1e467d7](https://github.com/Microsoft/fast/commit/1e467d7b6542e9e6910117e1d09c26cd73f7f599)) -* enable FoundationElement.compose to accept template functions ([#4390](https://github.com/Microsoft/fast/issues/4390)) ([468f2fc](https://github.com/Microsoft/fast/commit/468f2fca53be88d8551352c99b42c66c3d32fe47)) - - - - - -# [1.14.0](https://github.com/Microsoft/fast/compare/@microsoft/fast-foundation@1.12.0...@microsoft/fast-foundation@1.14.0) (2021-02-08) - - -### Bug Fixes - -* accordion arrow key press moves focus from content to accordion header ([#4331](https://github.com/Microsoft/fast/issues/4331)) ([d959c18](https://github.com/Microsoft/fast/commit/d959c18e5a5cba3b983c2cba096face14bec2bb8)) -* add check for intersection observer support before instanciating ([#4349](https://github.com/Microsoft/fast/issues/4349)) ([d106995](https://github.com/Microsoft/fast/commit/d106995dea3e7384633dbf2653b83aba3c815713)) - - -### Features - -* adds DI system, Configuration, and FoundationElement ([#4166](https://github.com/Microsoft/fast/issues/4166)) ([cfbe786](https://github.com/Microsoft/fast/commit/cfbe786f23623d69f2d658b51fe9211527ef9f0f)) - - - - - -# [1.13.0](https://github.com/Microsoft/fast/compare/@microsoft/fast-foundation@1.12.0...@microsoft/fast-foundation@1.13.0) (2021-02-08) - - -### Bug Fixes - -* accordion arrow key press moves focus from content to accordion header ([#4331](https://github.com/Microsoft/fast/issues/4331)) ([d959c18](https://github.com/Microsoft/fast/commit/d959c18e5a5cba3b983c2cba096face14bec2bb8)) -* add check for intersection observer support before instanciating ([#4349](https://github.com/Microsoft/fast/issues/4349)) ([d106995](https://github.com/Microsoft/fast/commit/d106995dea3e7384633dbf2653b83aba3c815713)) - - -### Features - -* adds DI system, Configuration, and FoundationElement ([#4166](https://github.com/Microsoft/fast/issues/4166)) ([cfbe786](https://github.com/Microsoft/fast/commit/cfbe786f23623d69f2d658b51fe9211527ef9f0f)) - - - - - -# [1.12.0](https://github.com/Microsoft/fast/compare/@microsoft/fast-foundation@1.11.1...@microsoft/fast-foundation@1.12.0) (2021-01-30) - - -### Bug Fixes - -* `UnhandledPromiseRejectionWarning`s when building fast-components ([#4218](https://github.com/Microsoft/fast/issues/4218)) ([48d52f4](https://github.com/Microsoft/fast/commit/48d52f43d8aa9938139f4dc0a2318fe400050216)) -* add class content to fix missing underline on button component ([#4226](https://github.com/Microsoft/fast/issues/4226)) ([bb9caaf](https://github.com/Microsoft/fast/commit/bb9caafd0edcbb0da46d74035fff246d36661f56)), closes [#4201](https://github.com/Microsoft/fast/issues/4201) [#16271](https://github.com/Microsoft/fast/issues/16271) -* add whitespace filter to text-field template to correctly hide label div with start and end content ([#4245](https://github.com/Microsoft/fast/issues/4245)) ([70ce353](https://github.com/Microsoft/fast/commit/70ce3537c3d29789b5030abe4ea6c58b098f69b5)) -* display active indicator when tab is disabled ([#4207](https://github.com/Microsoft/fast/issues/4207)) ([ca0efbb](https://github.com/Microsoft/fast/commit/ca0efbb2968b0f9b017f3b28ab5c1bb688fafd47)) -* expand collapse tree view svg ([#4225](https://github.com/Microsoft/fast/issues/4225)) ([c6d6259](https://github.com/Microsoft/fast/commit/c6d62597a89b7329b83f01520eebd811608c37d3)) -* tooltips are incorrectly positioned when parent is a flex container ([#4256](https://github.com/Microsoft/fast/issues/4256)) ([bc47c02](https://github.com/Microsoft/fast/commit/bc47c02a44b7b274f458322b65ce7b4555de49e3)) - - -### Features - -* add disclosure component ([#3921](https://github.com/Microsoft/fast/issues/3921)) ([dec77c9](https://github.com/Microsoft/fast/commit/dec77c99742e5aaddc5a2f3da2e340efc56ef00a)) -* add fast-number-field component for data applications ([#4204](https://github.com/Microsoft/fast/issues/4204)) ([7196215](https://github.com/Microsoft/fast/commit/7196215344e0f6141dbc7dff69fc4c0bde8b586a)) -* add getPosition service for anchored region ([#4210](https://github.com/Microsoft/fast/issues/4210)) ([94d5ffa](https://github.com/Microsoft/fast/commit/94d5ffa2235e2d681e03e32442346018a81c693f)) -* add radio group functionality to menu items ([#4208](https://github.com/Microsoft/fast/issues/4208)) ([89a3930](https://github.com/Microsoft/fast/commit/89a3930be83434b9039d25f82ae0c251e2d03956)) -* add select spec ([#4194](https://github.com/Microsoft/fast/issues/4194)) ([7af127a](https://github.com/Microsoft/fast/commit/7af127aa1e41d4a379cc8b5ce15798d9423b3726)) -* Create a behavior for attaching component styles based on an appearance ([#4238](https://github.com/Microsoft/fast/issues/4238)) ([7b498ce](https://github.com/Microsoft/fast/commit/7b498ce3101d90dee2558433fa0abadca5149d36)) - - - - - -## [1.11.1](https://github.com/Microsoft/fast/compare/@microsoft/fast-foundation@1.11.0...@microsoft/fast-foundation@1.11.1) (2020-12-17) - - -### Bug Fixes - -* update applyMixin function to ensure metadata for attrs are copied and applied correctly ([#4200](https://github.com/Microsoft/fast/issues/4200)) ([dcbd6a5](https://github.com/Microsoft/fast/commit/dcbd6a57d73691ced50c22db2b909ee6b6f96e1f)) - - - - - -# [1.11.0](https://github.com/Microsoft/fast/compare/@microsoft/fast-foundation@1.10.0...@microsoft/fast-foundation@1.11.0) (2020-12-16) - - -### Bug Fixes - -* anchored region default viewport ([#4146](https://github.com/Microsoft/fast/issues/4146)) ([a6806e9](https://github.com/Microsoft/fast/commit/a6806e9ed289e7ce570a542de5da9b6e0ba9e60b)) -* select should match native behavior for value changes and change event emitting ([#4176](https://github.com/Microsoft/fast/issues/4176)) ([07f5eaa](https://github.com/Microsoft/fast/commit/07f5eaa93b907cc4f712c954e8f6669c391a8d7f)) -* **dialog:** accidental improperly bound this in callback ([#4168](https://github.com/Microsoft/fast/issues/4168)) ([9d54fe9](https://github.com/Microsoft/fast/commit/9d54fe9c078cd3e16291a8c599d8d53f0df52670)) -* **fast-foundation:** ensure global aria attrs are applied ([#4172](https://github.com/Microsoft/fast/issues/4172)) ([dd3a1c9](https://github.com/Microsoft/fast/commit/dd3a1c9f9f5c96c1d7eb67a1f57f5f72136791cc)) -* disabled menu items should be focusable ([#4154](https://github.com/Microsoft/fast/issues/4154)) ([b971a18](https://github.com/Microsoft/fast/commit/b971a18281ba33f094a8dbc59a799a3e9c82ccb8)) -* ensure DSP subscribes to upstream DSP properties ([#4143](https://github.com/Microsoft/fast/issues/4143)) ([b403909](https://github.com/Microsoft/fast/commit/b403909282c115c99bf3dc66d5a9ff8715086dc7)) -* formassociated tests on firefox ([#4158](https://github.com/Microsoft/fast/issues/4158)) ([b3266fb](https://github.com/Microsoft/fast/commit/b3266fb5d12a200aeee5afb2ae44979db3c051f6)) -* remove shadowRoot in direction utility ([#4157](https://github.com/Microsoft/fast/issues/4157)) ([041ae70](https://github.com/Microsoft/fast/commit/041ae70ba3a8ba7280b1a571ba8952f443e724e2)) - - -### Features - -* add a data grid web component ([#4029](https://github.com/Microsoft/fast/issues/4029)) ([7239edc](https://github.com/Microsoft/fast/commit/7239edc775c26e003fd0c8cf11c0ba2bb62b76c6)) -* add beta anchored region component ([#4183](https://github.com/Microsoft/fast/issues/4183)) ([5d9f0ac](https://github.com/Microsoft/fast/commit/5d9f0acc4b8783d939bff389195fb92501d1a9ab)) -* add default slot changed to anchor ([#4159](https://github.com/Microsoft/fast/issues/4159)) ([8a264ec](https://github.com/Microsoft/fast/commit/8a264ec2a22d4f02e901a260b85f77c381a52231)) -* add loaded event to anchored region ([#4165](https://github.com/Microsoft/fast/issues/4165)) ([b54ac1b](https://github.com/Microsoft/fast/commit/b54ac1b09ccff95fc58ab84204a138dbfac9b8ba)) - - - - - -# [1.10.0](https://github.com/Microsoft/fast/compare/@microsoft/fast-foundation@1.9.0...@microsoft/fast-foundation@1.10.0) (2020-12-02) - - -### Bug Fixes - -* fix type error in custom property manager running on safari ([#4147](https://github.com/Microsoft/fast/issues/4147)) ([6320973](https://github.com/Microsoft/fast/commit/6320973ff0e14165b2f957b42a8feee1f71af9c1)) - - -### Features - -* add default slot change method ([#4148](https://github.com/Microsoft/fast/issues/4148)) ([5e9fb05](https://github.com/Microsoft/fast/commit/5e9fb0590833fe89d0a12132abdc0e88f64fbbcb)) - - - - - -# [1.9.0](https://github.com/Microsoft/fast/compare/@microsoft/fast-foundation@1.8.1...@microsoft/fast-foundation@1.9.0) (2020-11-19) - - -### Bug Fixes - -* active indicator losing track if double click ([#4085](https://github.com/Microsoft/fast/issues/4085)) ([fcecc75](https://github.com/Microsoft/fast/commit/fcecc759ed1cdddd3a5c73d38514dfce7edf432d)) -* active indicator no longer animating ([#4126](https://github.com/Microsoft/fast/issues/4126)) ([49e2608](https://github.com/Microsoft/fast/commit/49e26089c9275c5794af5d4e47427237363d333f)) -* corrects ElementInternals feature detection ([#4087](https://github.com/Microsoft/fast/issues/4087)) ([58b3e54](https://github.com/Microsoft/fast/commit/58b3e540c77eafa95ade021fd90b184d6f929a50)) -* ensure form elements reset when the parent form's reset() method is invoked. ([#4075](https://github.com/Microsoft/fast/issues/4075)) ([f19894e](https://github.com/Microsoft/fast/commit/f19894e746f0e1b7cffcce9d1269b9e6080f723a)) -* ensure StyleElementCustomPropertyManager works with disconnected elements ([#4112](https://github.com/Microsoft/fast/issues/4112)) ([e903bfa](https://github.com/Microsoft/fast/commit/e903bfa38b3ce2e8689c4eef4b552d9e7f8a9b88)) -* ensure tree items with children have a value for aria-expanded ([#4114](https://github.com/Microsoft/fast/issues/4114)) ([e7a7553](https://github.com/Microsoft/fast/commit/e7a7553c8e2fb205927d4d913de0d2790720ced7)) -* fast-slider sets value to NaN if developer tools open ([#4033](https://github.com/Microsoft/fast/issues/4033)) ([35d6903](https://github.com/Microsoft/fast/commit/35d6903cdc73fb4c5283bdfc5dcb0955b09d9b4c)) -* handle initially set value in FormAssociated ([#4047](https://github.com/Microsoft/fast/issues/4047)) ([bf7e874](https://github.com/Microsoft/fast/commit/bf7e87403883efcd438902bbfb43a74491a47b3f)) -* move component options to independent modules ([#4048](https://github.com/Microsoft/fast/issues/4048)) ([f8a88a8](https://github.com/Microsoft/fast/commit/f8a88a8b14b2eee4dd26619f7927be73bea94277)) -* revert radio to using class selector instead of attr, update slider-label to use internal styles for orientation ([#4108](https://github.com/Microsoft/fast/issues/4108)) ([c6ecedf](https://github.com/Microsoft/fast/commit/c6ecedf8427caf686bfebe89e78d2a6c2b7153f2)) - - -### Features - -* Add disabled attr to fast-tab ([#4013](https://github.com/Microsoft/fast/issues/4013)) ([caef4b1](https://github.com/Microsoft/fast/commit/caef4b15ce729ab1c1762bf0578edcf4d809351c)), closes [#4017](https://github.com/Microsoft/fast/issues/4017) -* add fast-breadcrumb and fast-breadcrumb-item web components ([#3627](https://github.com/Microsoft/fast/issues/3627)) ([e2e142c](https://github.com/Microsoft/fast/commit/e2e142c8ab91eb10906e74853f34afd5081ca12b)) -* add select component ([#4074](https://github.com/Microsoft/fast/issues/4074)) ([6984027](https://github.com/Microsoft/fast/commit/698402773e77b2766e995770b0d34c6d129e2ec3)) -* add show and hide methods to dialog ([#4030](https://github.com/Microsoft/fast/issues/4030)) ([00b69ff](https://github.com/Microsoft/fast/commit/00b69fff994035e769906563190cca86e3ae61f7)) -* convert FormAssociated to a constructable function ([#4115](https://github.com/Microsoft/fast/issues/4115)) ([da8d54b](https://github.com/Microsoft/fast/commit/da8d54b5a057812622471e1261200b8f9b290d12)) -* enable shared CSSStyleSheets in DesignSystemProvider ([#4065](https://github.com/Microsoft/fast/issues/4065)) ([5579c2e](https://github.com/Microsoft/fast/commit/5579c2ef424f8f63e00c8e29b5c4d43acb32c6db)) - - - - - -## [1.8.1](https://github.com/Microsoft/fast/compare/@microsoft/fast-foundation@1.8.0...@microsoft/fast-foundation@1.8.1) (2020-10-14) - - -### Bug Fixes - -* allow child radio buttons to be changed multiple times from javascript ([#3976](https://github.com/Microsoft/fast/issues/3976)) ([8ea7cc8](https://github.com/Microsoft/fast/commit/8ea7cc81cb34cf52d944136c9dc771fd03997bb1)) -* corrects keyboard behavior of tree view and tree view item. ([#4003](https://github.com/Microsoft/fast/issues/4003)) ([9d80632](https://github.com/Microsoft/fast/commit/9d806322c632ddf6294bddd782f39ec6c0300798)) -* designSystem property resolution behavior correction ([#4032](https://github.com/Microsoft/fast/issues/4032)) ([7e82cae](https://github.com/Microsoft/fast/commit/7e82caeb78c86898c38bd24d171d5ded8fc8473a)) -* leverage FASTController.addStyles to attach css custom property target sheet ([#4031](https://github.com/Microsoft/fast/issues/4031)) ([2ca2ed0](https://github.com/Microsoft/fast/commit/2ca2ed075879f6e1ec04d0ee2753cbf23dcaff9f)) -* tabs directional arrow key bug ([#3986](https://github.com/Microsoft/fast/issues/3986)) ([2d797a5](https://github.com/Microsoft/fast/commit/2d797a525eafd163aa9cba59823bc76d6b5b7d1f)) - - - - - -# [1.8.0](https://github.com/Microsoft/fast/compare/@microsoft/fast-foundation@1.7.2...@microsoft/fast-foundation@1.8.0) (2020-09-28) - - -### Bug Fixes - -* active id should update selected tab ([#3931](https://github.com/Microsoft/fast/issues/3931)) ([ff956ba](https://github.com/Microsoft/fast/commit/ff956ba15c7b4078e1a38283d1d45f763d761940)) -* adds constraint validation to all form-associated elements ([#3932](https://github.com/Microsoft/fast/issues/3932)) ([60fbec0](https://github.com/Microsoft/fast/commit/60fbec074d94606951311a2db4feff93a96a11e1)) -* aria attributes for slider should have explicit values ([#3915](https://github.com/Microsoft/fast/issues/3915)) ([8335702](https://github.com/Microsoft/fast/commit/8335702e28295e216fb7c673457a09285a388be4)) -* click does not uncheck radio if it was already checked ([#3888](https://github.com/Microsoft/fast/issues/3888)) ([989c785](https://github.com/Microsoft/fast/commit/989c7856fe5a8233a4744627d1710f0dd0467b69)) -* ensure a dsp pulls all relevant properties from the parent provider ([#3939](https://github.com/Microsoft/fast/issues/3939)) ([c70c519](https://github.com/Microsoft/fast/commit/c70c5190337890775f29b863b00d703ffda3a853)) -* ensure attributes are passed to text field template ([#3923](https://github.com/Microsoft/fast/issues/3923)) ([31afcd4](https://github.com/Microsoft/fast/commit/31afcd430d80fe2fb13d921b11b7ec92cf1a0bc8)) -* ensure badge always applies inline-style when attributes exist ([#3905](https://github.com/Microsoft/fast/issues/3905)) ([7624cba](https://github.com/Microsoft/fast/commit/7624cba3a7ec74bebc199a038a054fab8816684e)) -* fixed typos ([#3934](https://github.com/Microsoft/fast/issues/3934)) ([f82468c](https://github.com/Microsoft/fast/commit/f82468c730165983d64e51ce74abaa8a27a8fb64)) -* for tree-view removing space bar key handler and match aria spec ([#3954](https://github.com/Microsoft/fast/issues/3954)) ([4cb03e8](https://github.com/Microsoft/fast/commit/4cb03e86995efcd52c24ef4a0a606e0221df334a)), closes [/w3c.github.io/aria-practices/#keyboard-interaction-23](https://github.com//w3c.github.io/aria-practices//issues/keyboard-interaction-23) -* remove placeholder functions for boolean attributes in dialog component ([#3913](https://github.com/Microsoft/fast/issues/3913)) ([ab21eb7](https://github.com/Microsoft/fast/commit/ab21eb760ba2f84858b24dbf6c459f1602a3f7b0)) -* tree view item should have a click handler on root element ([#3951](https://github.com/Microsoft/fast/issues/3951)) ([913c2bd](https://github.com/Microsoft/fast/commit/913c2bd3a8f28622788c1f87a9f320ba7dbc1297)) -* tree-view right and left arrow keyboarding should behave as wai-aria spec suggests ([#3890](https://github.com/Microsoft/fast/issues/3890)) ([f866359](https://github.com/Microsoft/fast/commit/f8663590879ef2b1a064d10f9302f14cb7be0293)) - - -### Features - -* Anchored region reliability/perf improvements ([#3876](https://github.com/Microsoft/fast/issues/3876)) ([0e697f6](https://github.com/Microsoft/fast/commit/0e697f6ab6bd8f40894b9791d3eec8fe97a97d26)) -* add skeleton component ([#3877](https://github.com/Microsoft/fast/issues/3877)) ([aff7d30](https://github.com/Microsoft/fast/commit/aff7d3010574183744cf7105ae51a275c2c70a12)) -* add tooltip component ([#3549](https://github.com/Microsoft/fast/issues/3549)) ([cb7aa98](https://github.com/Microsoft/fast/commit/cb7aa98ccaaad00e9e86b4575ef011986c054d08)) - - - - - -## [1.7.2](https://github.com/Microsoft/fast/compare/@microsoft/fast-foundation@1.7.1...@microsoft/fast-foundation@1.7.2) (2020-09-10) - - -### Bug Fixes - -* able to keyboard tab back in the tree view ([#3867](https://github.com/Microsoft/fast/issues/3867)) ([d3e3cde](https://github.com/Microsoft/fast/commit/d3e3cde2fc3efd034569f6ade35a739aaf3e2738)), closes [#3801](https://github.com/Microsoft/fast/issues/3801) -* implicit form-associated submission ([#3861](https://github.com/Microsoft/fast/issues/3861)) ([8342912](https://github.com/Microsoft/fast/commit/8342912802b0cff20b38d16d28ccff49147088fa)) -* move right and move left functionality of radio-group in RTL ([f2735aa](https://github.com/Microsoft/fast/commit/f2735aa2fdb3c9ac71e143fddee84397f045afec)) -* tabs right and left keyboarding in rtl ([#3836](https://github.com/Microsoft/fast/issues/3836)) ([d9ac1b1](https://github.com/Microsoft/fast/commit/d9ac1b13bafbb94a204b58dcc56a02321fbc8fbd)) - - - - - -## [1.7.1](https://github.com/Microsoft/fast/compare/@microsoft/fast-foundation@1.7.0...@microsoft/fast-foundation@1.7.1) (2020-08-27) - - -### Bug Fixes - -* consistent with min-width, min-height is at least the thumb size add default height ([#3746](https://github.com/Microsoft/fast/issues/3746)) ([b3f9aee](https://github.com/Microsoft/fast/commit/b3f9aee644261ddcdd029fbafed69186db070c77)) -* proxy element causes empty check on slots to fail ([#3779](https://github.com/Microsoft/fast/issues/3779)) ([78787c3](https://github.com/Microsoft/fast/commit/78787c35631edb2b86f985dbfbc68036797f60d0)) -* **docs:** correct typos in readme and spec files ([#3740](https://github.com/Microsoft/fast/issues/3740)) ([9bdb11f](https://github.com/Microsoft/fast/commit/9bdb11f7eab686ab6de32eda352f1a0493ee9545)) - - - - - -# [1.7.0](https://github.com/Microsoft/fast/compare/@microsoft/fast-foundation@1.6.0...@microsoft/fast-foundation@1.7.0) (2020-08-13) - - -### Bug Fixes - -* anchored region fails on firefox ([#3701](https://github.com/Microsoft/fast/issues/3701)) ([1fd02e0](https://github.com/Microsoft/fast/commit/1fd02e013fc3798da8686ad2923d3bfcdeb796d7)) -* changed setupDefault to set initialValue which will set dirtyValue false after changing ([#3642](https://github.com/Microsoft/fast/issues/3642)) ([0b30fdf](https://github.com/Microsoft/fast/commit/0b30fdf78ebc6635ffb63e6b083f072871945d8c)) -* correct tabs animation when using home/end touch ([#3718](https://github.com/Microsoft/fast/issues/3718)) ([24ed0e5](https://github.com/Microsoft/fast/commit/24ed0e5262f8201f465db8798f7b01bcbbb21135)) -* correct typos on aria attributes ([#3690](https://github.com/Microsoft/fast/issues/3690)) ([d1c9ba4](https://github.com/Microsoft/fast/commit/d1c9ba4903dabe16487389917ad762d744356060)) -* fix radiogroup tabfocus ([#3650](https://github.com/Microsoft/fast/issues/3650)) ([59536fe](https://github.com/Microsoft/fast/commit/59536fe959c6d4ab2b48fa7636e11f8e68ecc0eb)) -* hitting enter key when in the text-field did not submit form ([#3687](https://github.com/Microsoft/fast/issues/3687)) ([3bc4384](https://github.com/Microsoft/fast/commit/3bc4384190af70ca082ef4e24a10f030e22a09e0)) -* turn off animation when dragging ([#3664](https://github.com/Microsoft/fast/issues/3664)) ([49e9d02](https://github.com/Microsoft/fast/commit/49e9d0294e3a98b0da443b4194d0006aaf5ff422)) -* wrapping set focus in dom.queueupdate ([#3703](https://github.com/Microsoft/fast/issues/3703)) ([7cb4616](https://github.com/Microsoft/fast/commit/7cb4616a9947639d6fb7a06e56db3d3900841674)) - - -### Features - -* anchored region revision ([#3527](https://github.com/Microsoft/fast/issues/3527)) ([63f3658](https://github.com/Microsoft/fast/commit/63f3658659a113bdc304f32e22b958e0d56ab7bf)) -* export form-associated under alpha flag ([#3618](https://github.com/Microsoft/fast/issues/3618)) ([cbcb217](https://github.com/Microsoft/fast/commit/cbcb2177c81740f6d6fc0be98973217dbb001e00)) - - -### Reverts - -* Revert "chore: update all http to https to resolve WS1262 security vulnerability (#3658)" (#3699) ([0cac64a](https://github.com/Microsoft/fast/commit/0cac64a869e1b65a94ef14ed50b1324d0e15be46)), closes [#3658](https://github.com/Microsoft/fast/issues/3658) [#3699](https://github.com/Microsoft/fast/issues/3699) - - - - - -# [1.6.0](https://github.com/Microsoft/fast/compare/@microsoft/fast-foundation@1.5.0...@microsoft/fast-foundation@1.6.0) (2020-07-31) - - -### Bug Fixes - -* add form submission and reset behavior to Button ([#3603](https://github.com/Microsoft/fast/issues/3603)) ([f646343](https://github.com/Microsoft/fast/commit/f6463436a001d07a7cfbd5d87460c76cf8584e65)) -* various fixes for form-associated custom elements ([#3581](https://github.com/Microsoft/fast/issues/3581)) ([ccba229](https://github.com/Microsoft/fast/commit/ccba229c6c1133485d0fac92eae88cb3a6369495)) - - -### Features - -* adding directional stylesheet behavior ([#3559](https://github.com/Microsoft/fast/issues/3559)) ([74c19af](https://github.com/Microsoft/fast/commit/74c19af79cb6b9c015ab3a454a3e69d453f1a217)) -* create an observable function to support aria-valuetext on slider component ([#3508](https://github.com/Microsoft/fast/issues/3508)) ([b4ac369](https://github.com/Microsoft/fast/commit/b4ac369e37ba591a5bb1d8c7bcbfde6dffcadeef)), closes [#3504](https://github.com/Microsoft/fast/issues/3504) - - - - - -# [1.5.0](https://github.com/Microsoft/fast/compare/@microsoft/fast-foundation@1.4.0...@microsoft/fast-foundation@1.5.0) (2020-07-23) - - -### Bug Fixes - -* address nested styling issues and provide a more intuitive API for nesting ([#3528](https://github.com/Microsoft/fast/issues/3528)) ([4fe0dd3](https://github.com/Microsoft/fast/commit/4fe0dd38ce8f2b43be0f13c7efac2f12ada6cd78)) -* move text field and text area appearances from foundation to components ([#3540](https://github.com/Microsoft/fast/issues/3540)) ([ca8ac76](https://github.com/Microsoft/fast/commit/ca8ac760cdf666fc79a47ba9a21c5f964556dbab)) -* rollup minify selectors should retain spaces ([#3524](https://github.com/Microsoft/fast/issues/3524)) ([cbdfc45](https://github.com/Microsoft/fast/commit/cbdfc45c2543fe9f94e0edc7687cc9f04a38e118)) -* update nested to be observable and set isNestedItem method to readonly ([#3539](https://github.com/Microsoft/fast/issues/3539)) ([9e67f52](https://github.com/Microsoft/fast/commit/9e67f52a8fd3e1736e3882ef7e2fa3f25e63a396)) - - -### Features - -* basic menu item check state toggling ([#3512](https://github.com/Microsoft/fast/issues/3512)) ([ea84cbd](https://github.com/Microsoft/fast/commit/ea84cbd125b16de0ff2ae888f82163178af8da69)) - - - - - -# [1.4.0](https://github.com/Microsoft/fast/compare/@microsoft/fast-foundation@1.3.0...@microsoft/fast-foundation@1.4.0) (2020-07-14) - - -### Bug Fixes - -* correct spelling of aria-labelledby in tabs ([#3463](https://github.com/Microsoft/fast/issues/3463)) ([c0385d9](https://github.com/Microsoft/fast/commit/c0385d97ec56ef8aef27047f6011261c2484a99d)) -* correct web component menu keyboarding and aria-expanded ([#3496](https://github.com/Microsoft/fast/issues/3496)) ([0530a42](https://github.com/Microsoft/fast/commit/0530a4230946d2aee39861001f3deea3b8816038)) -* move setAttribute calls for proxy elements to connectedCallback ([#3494](https://github.com/Microsoft/fast/issues/3494)) ([cdaf0ba](https://github.com/Microsoft/fast/commit/cdaf0bae4de3c995611e2e02313cc19e8e259b27)) -* reflect aria-hidden attribute in the DOM for the flipper component ([#3468](https://github.com/Microsoft/fast/issues/3468)) ([2f7b897](https://github.com/Microsoft/fast/commit/2f7b8977f4d5ea3173a70f719706155831bfa1bd)) -* removing un-needed nbsp; in slider-label and radio-group templates ([#3506](https://github.com/Microsoft/fast/issues/3506)) ([7cd003e](https://github.com/Microsoft/fast/commit/7cd003e5877d34ad926ee8268852176158cafc4b)) - - -### Features - -* adds mixin to support global aria-* attributes for components delegating focus ([#3470](https://github.com/Microsoft/fast/issues/3470)) ([054c890](https://github.com/Microsoft/fast/commit/054c89000d8931d9e203cb7f831c1e7f11c9038a)) -* export MatchMediaStylesheetBehavior constructor ([#3445](https://github.com/Microsoft/fast/issues/3445)) ([ffc59f8](https://github.com/Microsoft/fast/commit/ffc59f80166768550bf2488cd8b66e2d6b55b503)) -* move appearance attributes of anchor and button out of fast-foundation ([#3420](https://github.com/Microsoft/fast/issues/3420)) ([069e1ee](https://github.com/Microsoft/fast/commit/069e1ee000fc2f8e184919b16df0cb84bc610838)) -* simplify rollup configs and compress tagged template literals ([#3452](https://github.com/Microsoft/fast/issues/3452)) ([7533e92](https://github.com/Microsoft/fast/commit/7533e927f2467dd6f8dd46c1d3cef6c0df773fc4)) -* update typescript version and remove utility types dependencies for react packages ([#3422](https://github.com/Microsoft/fast/issues/3422)) ([09d07b5](https://github.com/Microsoft/fast/commit/09d07b580cda3bcc5d28f83d3568521f710c9576)) - - - - - -# [1.3.0](https://github.com/Microsoft/fast/compare/@microsoft/fast-foundation@1.2.2...@microsoft/fast-foundation@1.3.0) (2020-07-02) - - -### Bug Fixes - -* slider thumb does not respond to touch events, vertical sliders track parameters incorrect after scrolling page ([#3414](https://github.com/Microsoft/fast/issues/3414)) ([02f9ac4](https://github.com/Microsoft/fast/commit/02f9ac4306031aab1702e98083effc0ce858dec5)) - - -### Features - -* add tree-vew and tree-item components ([#3240](https://github.com/Microsoft/fast/issues/3240)) ([57eaa83](https://github.com/Microsoft/fast/commit/57eaa83293358383d03cbd3c5b6a9e6ffa797254)) -* make tabs adjust method public ([#3426](https://github.com/Microsoft/fast/issues/3426)) ([0dd2a5e](https://github.com/Microsoft/fast/commit/0dd2a5e016fd032b0a51ab441d3b3977220cf073)) - - - - - -## [1.2.2](https://github.com/Microsoft/fast/compare/@microsoft/fast-foundation@1.2.1...@microsoft/fast-foundation@1.2.2) (2020-06-26) - - -### Bug Fixes - -* selected tab becoming undefined when tab slot pass anything except icon or text node ([#3350](https://github.com/Microsoft/fast/issues/3350)) ([eda1aef](https://github.com/Microsoft/fast/commit/eda1aef79aeb612b05ea73b3861a93f5241c382f)) - - - - - -## [1.2.1](https://github.com/Microsoft/fast/compare/@microsoft/fast-foundation@1.2.0...@microsoft/fast-foundation@1.2.1) (2020-06-17) - -**Note:** Version bump only for package @microsoft/fast-foundation - - - - - -# [1.2.0](https://github.com/Microsoft/fast/compare/@microsoft/fast-foundation@1.1.2...@microsoft/fast-foundation@1.2.0) (2020-06-15) - - -### Bug Fixes - -* correct css part name for dialog component ([#3260](https://github.com/Microsoft/fast/issues/3260)) ([62eff11](https://github.com/Microsoft/fast/commit/62eff11685248f6e686eb761d2614f1f4a70d20e)) -* ensure all component internals have part names ([#3306](https://github.com/Microsoft/fast/issues/3306)) ([95360a7](https://github.com/Microsoft/fast/commit/95360a76ccb4ec40b2623dc01b55ea123d522b62)) - - -### Features - -* add live code examples to docs site ([#3216](https://github.com/Microsoft/fast/issues/3216)) ([763054f](https://github.com/Microsoft/fast/commit/763054f36433f9b87e620c0c8d03c229dcd8560f)) -* design-system-provider now paints CSS color and background color ([#3278](https://github.com/Microsoft/fast/issues/3278)) ([8e97ac4](https://github.com/Microsoft/fast/commit/8e97ac4aae18c8b17b90e61e139ad3fb0b7f7c3d)) -* provides access to the CSS variable created by CSSCustomProprtyBehaviors ([#3256](https://github.com/Microsoft/fast/issues/3256)) ([391f029](https://github.com/Microsoft/fast/commit/391f029da2d5a5502ee484af10aaef771d3c297c)) - - - - - -## [1.1.1](https://github.com/Microsoft/fast/compare/@microsoft/fast-foundation@1.1.0...@microsoft/fast-foundation@1.1.1) (2020-06-09) - - -### Bug Fixes - -* correct css part name for dialog component ([6e0c7a0](https://github.com/Microsoft/fast/commit/6e0c7a01fa3d28e0a725eb5e5bbc6462ca0b5d57)) - - - - - -# [1.1.0](https://github.com/Microsoft/fast/compare/@microsoft/fast-foundation@1.0.0...@microsoft/fast-foundation@1.1.0) (2020-06-05) - - -### Bug Fixes - -* children components not always added to the internal slotted radio control collection ([#3169](https://github.com/Microsoft/fast/issues/3169)) ([1d1ce86](https://github.com/Microsoft/fast/commit/1d1ce861f936800768b706de3b2175019c0cc18c)) -* remove static class from start/end template ([#3225](https://github.com/Microsoft/fast/issues/3225)) ([ea6e790](https://github.com/Microsoft/fast/commit/ea6e7906ef621f1875e7e24e5b79a3ed33189e33)) -* slider vertical navigation and value setting bugs ([#3176](https://github.com/Microsoft/fast/issues/3176)) ([f46d87d](https://github.com/Microsoft/fast/commit/f46d87d8d7dfe9101e0d1d8bec7d8a08097751bb)) - - -### Features - -* add accordion web component ([#3067](https://github.com/Microsoft/fast/issues/3067)) ([f551378](https://github.com/Microsoft/fast/commit/f55137803551711bef9eeb2c55c8d6f01a3eb74f)) -* **fast-foundation:** add element test helper ([#3184](https://github.com/Microsoft/fast/issues/3184)) ([a27161d](https://github.com/Microsoft/fast/commit/a27161d38526a7fb8cb39fe9b0d4addeb0c9ad11)) -* **website:** new docusaurus v2 setup with launch toc configuration ([#3159](https://github.com/Microsoft/fast/issues/3159)) ([f12ba16](https://github.com/Microsoft/fast/commit/f12ba1687bb46fd3f6717790b1687b441363671e)) - - - - - -# 1.0.0 (2020-05-18) - - -### Bug Fixes - -* replaces childNodes.length check with slotted ([#3130](https://github.com/Microsoft/fast/issues/3130)) ([b69d70c](https://github.com/Microsoft/fast/commit/b69d70c97d21660193c3cbcf9369b94135cfddb3)) -* update decorator signature to align with customElement ([#3131](https://github.com/Microsoft/fast/issues/3131)) ([10256b5](https://github.com/Microsoft/fast/commit/10256b59acbdfecfaaa1617ecf29eebe2cff47e4)) - - -### Features - -* **web-components:** new build/test/docs setup ([#3156](https://github.com/Microsoft/fast/issues/3156)) ([51d909a](https://github.com/Microsoft/fast/commit/51d909ad6a616cb63f7c62defe1ee1f3d2abaf02)) -* add fast-components-msft as a new package ([#3096](https://github.com/Microsoft/fast/issues/3096)) ([0515fff](https://github.com/Microsoft/fast/commit/0515fff5a1b7163e6f63f609e1efdba338e773c7)) -* add fast-foundation as a new package ([#3122](https://github.com/Microsoft/fast/issues/3122)) ([322af95](https://github.com/Microsoft/fast/commit/322af95b7b7b33e7db3e0689647ac301ea5be2f1)) -* update badge API and styles ([#3147](https://github.com/Microsoft/fast/issues/3147)) ([23eca38](https://github.com/Microsoft/fast/commit/23eca38c0c0ca4ac0d219315fcc1308e093f3363)) -* wrap attr and observable into designSystemProperty decorator ([#3132](https://github.com/Microsoft/fast/issues/3132)) ([b6d4d59](https://github.com/Microsoft/fast/commit/b6d4d594d7d91e3588f1b461db1054ed0e4daf22)) - - -### BREAKING CHANGES - -* fundamentally changes and breaks the badge component API and styles -* breaks certain package exports diff --git a/packages/web-components/fast-foundation/README.md b/packages/web-components/fast-foundation/README.md deleted file mode 100644 index daa5f9686b4..00000000000 --- a/packages/web-components/fast-foundation/README.md +++ /dev/null @@ -1,58 +0,0 @@ -# FAST Foundation - -[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) -[![npm version](https://badge.fury.io/js/%40microsoft%2Ffast-foundation.svg)](https://badge.fury.io/js/%40microsoft%2Ffast-foundation) - -The `fast-foundation` package is a library of Web Component classes, templates, and other utilities intended to be composed into registered Web Components by design systems (e.g. Fluent Design, Material Design, etc.). The exports of this package can generally be thought of as un-styled base components that implement semantic and accessible markup and behavior. - -This package does not export Web Components registered as [custom elements](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements) - it exports parts and pieces intended to be *composed* into Web Components, allowing you to implement your own design language by simply applying CSS styles and behaviors without having to write all the JavaScript that's involved in building production-quality component implementations. - -## Installation - -### From NPM - -To install the `fast-foundation` library, use either `npm` or `yarn` as follows: - -```shell -npm install --save @microsoft/fast-foundation -``` - -```shell -yarn add @microsoft/fast-foundation -``` - -Within your JavaScript or TypeScript code, you can then import library APIs like this: - -```ts -import { Anchor } from '@microsoft/fast-foundation'; -``` - -Looking for a setup that integrates with a particular front-end framework or bundler? Check out [our integration docs](https://fast.design/docs/integrations/introduction). - -### From CDN - -A pre-bundled script that contains all APIs needed to use FAST Foundation is available on CDN. You can use this script by adding [`type="module"`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) to the script element and then importing from the CDN. - -```html - - - - - - - -``` - -The markup above always references the latest release. When deploying to production, you will want to ship with a specific version. Here's an example of the markup for that: - -```html - -``` - -:::note -For simplicity, examples throughout the documentation will assume the library has been installed from NPM, but you can always replace the import location with the CDN URL. -::: \ No newline at end of file diff --git a/packages/web-components/fast-foundation/api-extractor.json b/packages/web-components/fast-foundation/api-extractor.json deleted file mode 100644 index e4906016804..00000000000 --- a/packages/web-components/fast-foundation/api-extractor.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - "extends": "../../../api-extractor.json", - "mainEntryPointFilePath": "./dist/dts/index.d.ts", - "compiler": { - "tsconfigFilePath": "./tsconfig.build.json" - }, - "dtsRollup": { - "enabled": true, - "untrimmedFilePath": "./dist/fast-foundation.untrimmed.d.ts", - "betaTrimmedFilePath": "./dist/fast-foundation.d.ts" - }, - "messages": { - "extractorMessageReporting": { - "ae-different-release-tags": { - "logLevel": "none", - "addToApiReportFile": true - } - } - } -} \ No newline at end of file diff --git a/packages/web-components/fast-foundation/custom-elements-manifest-plugins.mjs b/packages/web-components/fast-foundation/custom-elements-manifest-plugins.mjs deleted file mode 100644 index a24f9b15271..00000000000 --- a/packages/web-components/fast-foundation/custom-elements-manifest-plugins.mjs +++ /dev/null @@ -1,140 +0,0 @@ -import { getClassMemberDoc } from "@custom-elements-manifest/analyzer/src/utils/manifest-helpers.js"; -import { parse } from "comment-parser"; - -/** - * Code for this plugin was mostly copied from: https://github.com/bennypowers/cem-plugins/tree/main/plugins/cem-plugin-jsdoc-example - */ - -/** - * Does the AST node have JSDoc tags? - * @template {import('typescript').Node} N - * @param {N} node - * @return {node is N & { jsDoc: import('typescript').JSDoc[] }} - */ -function hasJsDocComments(node) { - return "jsDoc" in node; -} - -/** - * Given a manifest and a declaration name, get the declaration doc - * @param {Partial} moduleDoc - * @param {string} name - * @return {import("custom-elements-manifest/schema").Declaration} - */ -function getDeclarationDoc(moduleDoc, name) { - return moduleDoc.declarations.find(x => x.name === name); -} - -/** - * Fix a Node's JSDoc link comments - * @param {import('typescript').Node & { jsDoc: import('typescript').JSDoc[] }} node - * @param {import("custom-elements-manifest/schema").Declaration} doc - * @param {*} context - * @param {number} [offset=0] - */ -function fixLinks(node, doc, context, offset = 0) { - node?.jsDoc?.forEach(jsDoc => { - const parsed = parse(jsDoc?.getFullText()); - parsed?.forEach(parsedJsDoc => { - if ( - parsedJsDoc.description && - parsedJsDoc.description.indexOf("{@link") >= 0 - ) { - doc.description = parsedJsDoc.description.trim(); - } - }); - }); -} - -/** - * @return {import('@custom-elements-manifest/analyzer').Plugin} - */ -export function jsdocLinkFix() { - return { - name: "jsdoc-example", - analyzePhase({ ts, node, moduleDoc, context }) { - if (!hasJsDocComments(node)) return; - if (ts.isClassDeclaration(node)) { - const className = node.name.getText(); - const classDoc = getDeclarationDoc(moduleDoc, className); - if (!classDoc) - return ( - context.dev && - console.warn( - `[jsdoc-example]: Could not find class ${className} in module doc for path ${moduleDoc.path}` - ) - ); - fixLinks(node, classDoc, context); - } else if (ts.isPropertyDeclaration(node)) { - const propertyName = node.name.getText(); - const className = node.parent?.name?.getText?.(); - const classDoc = getDeclarationDoc(moduleDoc, className); - if (!classDoc) return; - const isStatic = node.modifiers?.some?.( - x => x.kind === ts.SyntaxKind.StaticKeyword - ); - const propertyDoc = getClassMemberDoc( - moduleDoc, - className, - propertyName, - isStatic - ); - if (!propertyDoc) - return ( - context.dev && - console.warn( - `[jsdoc-example]: Could not find property ${propertyName} of ${className} in module doc for path ${moduleDoc.path}` - ) - ); - fixLinks(node, propertyDoc, context, 1); - } else if (ts.isMethodDeclaration(node)) { - if (!ts.isClassDeclaration(node.parent)) return; - const methodName = node.name.getText(); - const className = node.parent.name.getText(); - const classDoc = getDeclarationDoc(moduleDoc, className); - if (!classDoc) return; - const isStatic = node.modifiers?.some?.( - x => x.kind === ts.SyntaxKind.StaticKeyword - ); - const methodDoc = getClassMemberDoc( - moduleDoc, - className, - methodName, - isStatic - ); - if (!methodDoc) - return ( - context.dev && - console.warn( - `[jsdoc-example]: Could not find method ${methodName} of ${className} in module doc for path ${moduleDoc.path}` - ) - ); - fixLinks(node, methodDoc, context, 1); - } else if (ts.isFunctionDeclaration(node)) { - const functionName = node.name.getText(); - const functionDoc = getDeclarationDoc(moduleDoc, functionName); - if (!functionDoc) - return ( - context.dev && - console.warn( - `[jsdoc-example]: Could not find function ${functionName} in module doc for path ${moduleDoc.path}` - ) - ); - fixLinks(node, functionDoc, context); - } else if (ts.isVariableStatement(node)) { - node.declarationList?.declarations.forEach(dec => { - const name = dec.name.getText(); - const doc = getDeclarationDoc(moduleDoc, name); - if (!doc) - return ( - context.dev && - console.warn( - `[jsdoc-example]: Could not find variable ${name} in module doc for path ${moduleDoc.path}` - ) - ); - fixLinks(node, doc, context); - }); - } - }, - }; -} diff --git a/packages/web-components/fast-foundation/custom-elements-manifest.config.mjs b/packages/web-components/fast-foundation/custom-elements-manifest.config.mjs deleted file mode 100644 index 51e73f982b4..00000000000 --- a/packages/web-components/fast-foundation/custom-elements-manifest.config.mjs +++ /dev/null @@ -1,24 +0,0 @@ -import { jsdocLinkFix } from "./custom-elements-manifest-plugins.mjs"; - -export default { - /** Globs to analyze */ - globs: ["src/**/*.ts"], - /** Globs to exclude */ - exclude: [ - "src/*.ts", - "src/__test__/*", - "src/di/*", - "src/design-token/*", - "src/**/*.md", - "src/**/*.spec.ts", - "src/**/index.ts", - "src/**/stories/*", - ], - /** Directory to output CEM to */ - outdir: "dist", - /** Run in dev mode, provides extra logging */ - dev: false, - /** Enable special handling for fast */ - fast: true, - plugins: [jsdocLinkFix()], -}; diff --git a/packages/web-components/fast-foundation/docs/api-report.md b/packages/web-components/fast-foundation/docs/api-report.md deleted file mode 100644 index e15656a501f..00000000000 --- a/packages/web-components/fast-foundation/docs/api-report.md +++ /dev/null @@ -1,2929 +0,0 @@ -## API Report File for "@microsoft/fast-foundation" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -import type { CaptureType } from '@microsoft/fast-element'; -import type { Constructable } from '@microsoft/fast-element'; -import type { CSSDirective } from '@microsoft/fast-element'; -import { Direction } from '@microsoft/fast-web-utilities'; -import type { ElementsFilter } from '@microsoft/fast-element'; -import type { ElementStyles } from '@microsoft/fast-element'; -import type { ElementViewTemplate } from '@microsoft/fast-element'; -import { FASTContext } from '@microsoft/fast-element/context.js'; -import { FASTElement } from '@microsoft/fast-element'; -import { FASTElementDefinition } from '@microsoft/fast-element'; -import type { HostBehavior } from '@microsoft/fast-element'; -import type { HostController } from '@microsoft/fast-element'; -import type { HTMLDirective } from '@microsoft/fast-element'; -import { Orientation } from '@microsoft/fast-web-utilities'; -import type { SyntheticViewTemplate } from '@microsoft/fast-element'; -import type { ViewTemplate } from '@microsoft/fast-element'; - -// @public -export const AccordionExpandMode: { - readonly single: "single"; - readonly multi: "multi"; -}; - -// @public -export type AccordionExpandMode = ValuesOf; - -// @public -export type AccordionItemOptions = StartEndOptions & { - expandCollapseIcon?: StaticallyComposableHTML; -}; - -// @public -export function accordionItemTemplate(options?: AccordionItemOptions): ElementViewTemplate; - -// @public -export function accordionTemplate(): ElementViewTemplate; - -// @public -export interface AnchoredRegionConfig { - readonly autoUpdateMode?: AutoUpdateMode; - readonly fixedPlacement?: boolean; - readonly horizontalDefaultPosition?: HorizontalPosition; - readonly horizontalInset?: boolean; - readonly horizontalPositioningMode?: AxisPositioningMode; - readonly horizontalScaling?: AxisScalingMode; - readonly horizontalThreshold?: number; - readonly horizontalViewportLock?: boolean; - readonly verticalDefaultPosition?: VerticalPosition; - readonly verticalInset?: boolean; - readonly verticalPositioningMode?: AxisPositioningMode; - readonly verticalScaling?: AxisScalingMode; - readonly verticalThreshold?: number; - readonly verticalViewportLock?: boolean; -} - -// @public -export const AnchoredRegionPositionLabel: { - readonly start: "start"; - readonly insetStart: "insetStart"; - readonly insetEnd: "insetEnd"; - readonly end: "end"; - readonly center: "center"; -}; - -// @public -export type AnchoredRegionPositionLabel = ValuesOf; - -// @public -export function anchoredRegionTemplate(): ElementViewTemplate; - -// @public -export type AnchorOptions = StartEndOptions; - -// @public -export const AnchorTarget: { - readonly _self: "_self"; - readonly _blank: "_blank"; - readonly _parent: "_parent"; - readonly _top: "_top"; -}; - -// @public -export type AnchorTarget = ValuesOf; - -// @public -export function anchorTemplate(options?: AnchorOptions): ViewTemplate; - -// @public -export class ARIAGlobalStatesAndProperties { - ariaAtomic: "true" | "false" | string | null; - ariaBusy: "true" | "false" | string | null; - ariaControls: string | null; - ariaCurrent: "page" | "step" | "location" | "date" | "time" | "true" | "false" | string | null; - ariaDescribedby: string | null; - ariaDetails: string | null; - ariaDisabled: "true" | "false" | string | null; - ariaErrormessage: string | null; - ariaFlowto: string | null; - ariaHaspopup: "false" | "true" | "menu" | "listbox" | "tree" | "grid" | "dialog" | string | null; - ariaHidden: "false" | "true" | string | null; - ariaInvalid: "false" | "true" | "grammar" | "spelling" | string | null; - ariaKeyshortcuts: string | null; - ariaLabel: string | null; - ariaLabelledby: string | null; - ariaLive: "assertive" | "off" | "polite" | string | null; - ariaOwns: string | null; - ariaRelevant: "additions" | "additions text" | "all" | "removals" | "text" | string | null; - ariaRoledescription: string | null; -} - -// @public -export const AutoUpdateMode: { - readonly anchor: "anchor"; - readonly auto: "auto"; -}; - -// @public -export type AutoUpdateMode = ValuesOf; - -// @public -export type AvatarOptions = { - media?: StaticallyComposableHTML; -}; - -// @public -export function avatarTemplate(options?: AvatarOptions): ElementViewTemplate; - -// @public -export const AxisPositioningMode: { - readonly uncontrolled: "uncontrolled"; - readonly locktodefault: "locktodefault"; - readonly dynamic: "dynamic"; -}; - -// @public -export type AxisPositioningMode = ValuesOf; - -// @public -export const AxisScalingMode: { - readonly anchor: "anchor"; - readonly content: "content"; - readonly fill: "fill"; -}; - -// @public -export type AxisScalingMode = ValuesOf; - -// @public -export type BadgeOptions = StartEndOptions; - -// @public -export function badgeTemplate(options?: BadgeOptions): ElementViewTemplate; - -// @public -export type BreadcrumbItemOptions = StartEndOptions & { - separator?: StaticallyComposableHTML; -}; - -// @public -export function breadcrumbItemTemplate(options?: BreadcrumbItemOptions): ElementViewTemplate; - -// @public -export type BreadcrumbOptions = StartEndOptions; - -// @public -export function breadcrumbTemplate(options?: BreadcrumbOptions): ElementViewTemplate; - -// @public -export type ButtonOptions = StartEndOptions; - -// @public -export function buttonTemplate(options?: ButtonOptions): ElementViewTemplate; - -// @public -export const ButtonType: { - readonly submit: "submit"; - readonly reset: "reset"; - readonly button: "button"; -}; - -// @public -export type ButtonType = ValuesOf; - -// @public -export function calendarCellTemplate(options: CalendarOptions, todayString: string): ViewTemplate; - -// @public -export type CalendarDateInfo = { - day: number; - month: number; - year: number; - disabled?: boolean; - selected?: boolean; -}; - -// @public -export type CalendarInfo = MonthInfo & { - previous: MonthInfo; - next: MonthInfo; -}; - -// @public -export type CalendarOptions = StartEndOptions & { - dataGridCell: TemplateElementDependency; - dataGridRow: TemplateElementDependency; - dataGrid: TemplateElementDependency; - title?: StaticallyComposableHTML; -}; - -// @public (undocumented) -export function calendarRowTemplate(options: CalendarOptions, todayString: string): ViewTemplate; - -// @public -export function calendarTemplate(options: CalendarOptions): ElementViewTemplate; - -// @public -export function calendarTitleTemplate(): ViewTemplate; - -// @public -export function calendarWeekdayTemplate(options: CalendarOptions): ViewTemplate; - -// @public -export function cardTemplate(): ElementViewTemplate; - -// @public -export type CellItemTemplateOptions = { - dataGridCell: TemplateElementDependency; -}; - -// @beta -export function CheckableFormAssociated(BaseCtor: T): T; - -// @beta -export interface CheckableFormAssociated extends FormAssociated { - // (undocumented) - checked: boolean; - // (undocumented) - checkedAttribute: boolean; - // (undocumented) - checkedChanged(oldValue: boolean | undefined, newValue: boolean): void; - // (undocumented) - currentChecked: boolean; - // (undocumented) - defaultChecked: boolean; - // (undocumented) - defaultCheckedChanged(oldValue: boolean | undefined, newValue: boolean): void; - // (undocumented) - dirtyChecked: boolean; -} - -// @beta -export type CheckableFormAssociatedElement = FormAssociatedElement & CheckableFormAssociated & { - proxy: HTMLInputElement; -}; - -// @public -export type CheckboxOptions = { - checkedIndicator?: StaticallyComposableHTML; - indeterminateIndicator?: StaticallyComposableHTML; -}; - -// @public -export function checkboxTemplate(options?: CheckboxOptions): ElementViewTemplate; - -// @public -export interface ColumnDefinition { - cellFocusTargetCallback?: (cell: FASTDataGridCell) => HTMLElement | null; - cellInternalFocusQueue?: boolean; - cellTemplate?: ViewTemplate | SyntheticViewTemplate; - columnDataKey: string; - gridColumn?: string; - headerCellFocusTargetCallback?: (cell: FASTDataGridCell) => HTMLElement | null; - headerCellInternalFocusQueue?: boolean; - headerCellTemplate?: ViewTemplate | SyntheticViewTemplate; - isRowHeader?: boolean; - title?: string; -} - -// @public -export const ComboboxAutocomplete: { - readonly inline: "inline"; - readonly list: "list"; - readonly both: "both"; - readonly none: "none"; -}; - -// @public -export type ComboboxAutocomplete = ValuesOf; - -// @public -export type ComboboxOptions = StartEndOptions & { - indicator?: StaticallyComposableHTML; -}; - -// @public -export function comboboxTemplate(options?: ComboboxOptions): ElementViewTemplate; - -// @beta -export type ConstructableFormAssociated = Constructable; - -// @public (undocumented) -export class CSSDesignToken extends DesignToken implements CSSDirective, HTMLDirective { - constructor(configuration: CSSDesignTokenConfiguration); - createCSS(): string; - createHTML(): string; - readonly cssCustomProperty: string; -} - -// @public (undocumented) -export interface CSSDesignTokenConfiguration extends DesignTokenConfiguration { - cssCustomPropertyName: string; -} - -// @public -export type CSSDisplayPropertyValue = "block" | "contents" | "flex" | "grid" | "inherit" | "initial" | "inline" | "inline-block" | "inline-flex" | "inline-grid" | "inline-table" | "list-item" | "none" | "run-in" | "table" | "table-caption" | "table-cell" | "table-column" | "table-column-group" | "table-footer-group" | "table-header-group" | "table-row" | "table-row-group"; - -// @public -export const darkModeStylesheetBehavior: (styles: ElementStyles) => MatchMediaStyleSheetBehavior; - -// @public -export function dataGridCellTemplate(): ElementViewTemplate; - -// @public -export const DataGridCellTypes: { - readonly default: "default"; - readonly columnHeader: "columnheader"; - readonly rowHeader: "rowheader"; -}; - -// @public -export type DataGridCellTypes = ValuesOf; - -// @public -export type DataGridOptions = { - dataGridRow: TemplateElementDependency; -}; - -// @public -export function dataGridRowTemplate(options: CellItemTemplateOptions): ElementViewTemplate; - -// @public -export const DataGridRowTypes: { - readonly default: "default"; - readonly header: "header"; - readonly stickyHeader: "sticky-header"; -}; - -// @public -export type DataGridRowTypes = ValuesOf; - -// @public -export const DataGridSelectionBehavior: { - readonly programmatic: "programmatic"; - readonly keyboardOnly: "keyboard-only"; - readonly auto: "auto"; -}; - -// @public -export type DataGridSelectionBehavior = ValuesOf; - -// @public -export const DataGridSelectionMode: { - readonly none: "none"; - readonly singleRow: "single-row"; - readonly multiRow: "multi-row"; -}; - -// @public -export type DataGridSelectionMode = ValuesOf; - -// @public -export function dataGridTemplate(options: DataGridOptions): ElementViewTemplate; - -// @public -export class DateFormatter { - constructor(config?: {}); - date: Date; - dayFormat: DayFormat; - // (undocumented) - getDate(date?: { - day: number; - month: number; - year: number; - } | string | Date, format?: Intl.DateTimeFormatOptions, locale?: string): string; - getDateObject(date: { - day: number; - month: number; - year: number; - } | string | Date): Date; - // (undocumented) - getDay(day?: number, format?: DayFormat, locale?: string): string; - // (undocumented) - getMonth(month?: number, format?: MonthFormat, locale?: string): string; - // (undocumented) - getWeekday(weekday?: number, format?: WeekdayFormat, locale?: string): string; - // (undocumented) - getWeekdays(format?: WeekdayFormat, locale?: string): string[]; - // (undocumented) - getYear(year?: number, format?: YearFormat, locale?: string): string; - locale: string; - monthFormat: MonthFormat; - weekdayFormat: WeekdayFormat; - yearFormat: YearFormat; -} - -// @public -export const DayFormat: { - readonly "2-digit": "2-digit"; - readonly numeric: "numeric"; -}; - -// @public -export type DayFormat = ValuesOf; - -// @public (undocumented) -export const defaultCellFocusTargetCallback: (cell: FASTDataGridCell) => HTMLElement | null; - -// Warning: (ae-different-release-tags) This symbol has another declaration with a different release tag -// Warning: (ae-internal-mixed-release-tag) Mixed release tags are not allowed for "DelegatesARIAButton" because one of its declarations is marked as @internal -// -// @public -export class DelegatesARIAButton { - ariaExpanded: "true" | "false" | string | null; - ariaPressed: "true" | "false" | "mixed" | string | null; -} - -// @internal -export interface DelegatesARIAButton extends ARIAGlobalStatesAndProperties { -} - -// Warning: (ae-different-release-tags) This symbol has another declaration with a different release tag -// Warning: (ae-internal-mixed-release-tag) Mixed release tags are not allowed for "DelegatesARIACombobox" because one of its declarations is marked as @internal -// -// @public -export class DelegatesARIACombobox { - ariaAutoComplete: "inline" | "list" | "both" | "none" | string | null; - ariaControls: string | null; -} - -// @internal -export interface DelegatesARIACombobox extends DelegatesARIAListbox { -} - -// Warning: (ae-different-release-tags) This symbol has another declaration with a different release tag -// Warning: (ae-internal-mixed-release-tag) Mixed release tags are not allowed for "DelegatesARIALink" because one of its declarations is marked as @internal -// -// @public -export class DelegatesARIALink { - ariaExpanded: "true" | "false" | string | null; -} - -// @internal -export interface DelegatesARIALink extends ARIAGlobalStatesAndProperties { -} - -// Warning: (ae-different-release-tags) This symbol has another declaration with a different release tag -// Warning: (ae-internal-mixed-release-tag) Mixed release tags are not allowed for "DelegatesARIAListbox" because one of its declarations is marked as @internal -// -// @public -export class DelegatesARIAListbox { - ariaActiveDescendant: string | null; - ariaDisabled: "true" | "false" | string | null; - ariaExpanded: "true" | "false" | string | null; - ariaMultiSelectable: "true" | "false" | string | null; -} - -// @internal -export interface DelegatesARIAListbox extends ARIAGlobalStatesAndProperties { -} - -// Warning: (ae-different-release-tags) This symbol has another declaration with a different release tag -// Warning: (ae-internal-mixed-release-tag) Mixed release tags are not allowed for "DelegatesARIAListboxOption" because one of its declarations is marked as @internal -// -// @public -export class DelegatesARIAListboxOption { - ariaChecked: "true" | "false" | string | null; - ariaPosInSet: string | null; - ariaSelected: "true" | "false" | string | null; - ariaSetSize: string | null; -} - -// @internal (undocumented) -export interface DelegatesARIAListboxOption extends ARIAGlobalStatesAndProperties { -} - -// Warning: (ae-different-release-tags) This symbol has another declaration with a different release tag -// Warning: (ae-internal-mixed-release-tag) Mixed release tags are not allowed for "DelegatesARIASearch" because one of its declarations is marked as @internal -// -// @public -export class DelegatesARIASearch { -} - -// @internal -export interface DelegatesARIASearch extends ARIAGlobalStatesAndProperties { -} - -// Warning: (ae-different-release-tags) This symbol has another declaration with a different release tag -// Warning: (ae-internal-mixed-release-tag) Mixed release tags are not allowed for "DelegatesARIASelect" because one of its declarations is marked as @internal -// -// @public -export class DelegatesARIASelect { - ariaControls: string | null; -} - -// @internal -export interface DelegatesARIASelect extends DelegatesARIAListbox { -} - -// Warning: (ae-different-release-tags) This symbol has another declaration with a different release tag -// Warning: (ae-internal-mixed-release-tag) Mixed release tags are not allowed for "DelegatesARIATextbox" because one of its declarations is marked as @internal -// -// @public -export class DelegatesARIATextbox { -} - -// @internal -export interface DelegatesARIATextbox extends ARIAGlobalStatesAndProperties { -} - -// Warning: (ae-different-release-tags) This symbol has another declaration with a different release tag -// Warning: (ae-internal-mixed-release-tag) Mixed release tags are not allowed for "DelegatesARIAToolbar" because one of its declarations is marked as @internal -// -// @public -export class DelegatesARIAToolbar { - ariaLabel: string | null; - ariaLabelledby: string | null; -} - -// @internal -export interface DelegatesARIAToolbar extends ARIAGlobalStatesAndProperties { -} - -// @public -export type DerivedDesignTokenValue = (resolve: DesignTokenResolver) => T; - -// @public (undocumented) -export class DesignToken { - get $value(): T | undefined; - constructor(configuration: DesignTokenConfiguration); - // (undocumented) - static create(name: string): CSSDesignToken; - // (undocumented) - static create(config: DesignTokenConfiguration): DesignToken; - // (undocumented) - static create(config: CSSDesignTokenConfiguration): CSSDesignToken; - get default(): T | undefined; - deleteValueFor(target: FASTElement): this; - getValueFor(target: FASTElement): T; - name: string; - static registerDefaultStyleTarget(target?: FASTElement | Document | PropertyTarget): void; - // Warning: (ae-forgotten-export) The symbol "DesignTokenValue" needs to be exported by the entry point index.d.ts - setValueFor(target: FASTElement, value: DesignToken | DesignTokenValue): void; - subscribe(subscriber: DesignTokenSubscriber): void; - static unregisterDefaultStyleTarget(target?: FASTElement | Document | PropertyTarget): void; - unsubscribe(subscriber: DesignTokenSubscriber): void; - withDefault(value: DesignToken | DesignTokenValue): this; - // Warning: (ae-forgotten-export) The symbol "DesignTokenResolutionStrategy" needs to be exported by the entry point index.d.ts - static withStrategy(strategy: DesignTokenResolutionStrategy): void; -} - -// @public (undocumented) -export interface DesignTokenChangeRecord> { - target: FASTElement | "default"; - token: T; -} - -// @public -export interface DesignTokenConfiguration { - name: string; -} - -// @public -export const DesignTokenEventResolutionStrategy: DesignTokenResolutionStrategy; - -// @public (undocumented) -export const enum DesignTokenMutationType { - // (undocumented) - add = 0, - // (undocumented) - change = 1, - // (undocumented) - delete = 2 -} - -// Warning: (ae-forgotten-export) The symbol "DesignToken" needs to be exported by the entry point index.d.ts -// -// @public -export type DesignTokenResolver = (token: DesignToken_2) => T; - -// @public -export class DesignTokenStyleTarget implements PropertyTarget { - get cssText(): string; - // (undocumented) - removeProperty(name: string): void; - // (undocumented) - setProperty(name: string, value: string): void; - get values(): Array<[string, string]>; -} - -// @public -export interface DesignTokenSubscriber> { - // (undocumented) - handleChange(token: T, record: DesignTokenChangeRecord): void; -} - -// @public -export function dialogTemplate(): ElementViewTemplate; - -// Warning: (ae-internal-missing-underscore) The name "Dimension" should be prefixed with an underscore because the declaration is marked as @internal -// -// @internal (undocumented) -export interface Dimension { - // (undocumented) - height: number; - // (undocumented) - width: number; -} - -// @public @deprecated -export const disabledCursor = "not-allowed"; - -// @public -export type DisclosureOptions = StartEndOptions; - -// @public -export function disclosureTemplate(options?: DisclosureOptions): ElementViewTemplate; - -// @public -export function display(displayValue: CSSDisplayPropertyValue): string; - -// @public -export const DividerOrientation: { - readonly horizontal: "horizontal"; - readonly vertical: "vertical"; -}; - -// @public -export type DividerOrientation = ValuesOf; - -// @public -export const DividerRole: { - readonly separator: "separator"; - readonly presentation: "presentation"; -}; - -// @public -export type DividerRole = ValuesOf; - -// @public -export function dividerTemplate(): ElementViewTemplate; - -// @public -export type EndOptions = { - end?: StaticallyComposableHTML; -}; - -// @public -export function endSlotTemplate(options: EndOptions): CaptureType; - -// @public -export class FASTAccordion extends FASTElement { - // (undocumented) - protected accordionItems: Element[]; - expandmode: AccordionExpandMode; - // (undocumented) - expandmodeChanged(prev: AccordionExpandMode, next: AccordionExpandMode): void; - // @internal (undocumented) - handleChange(source: any, propertyName: string): void; - // @internal (undocumented) - slottedAccordionItems: HTMLElement[]; - // @internal (undocumented) - slottedAccordionItemsChanged(oldValue: HTMLElement[], newValue: HTMLElement[]): void; -} - -// Warning: (ae-different-release-tags) This symbol has another declaration with a different release tag -// Warning: (ae-internal-mixed-release-tag) Mixed release tags are not allowed for "FASTAccordionItem" because one of its declarations is marked as @internal -// -// @public -export class FASTAccordionItem extends FASTElement { - // @internal (undocumented) - clickHandler: (e: MouseEvent) => void; - disabled: boolean; - // @internal (undocumented) - expandbutton: HTMLElement; - expanded: boolean; - headinglevel: 1 | 2 | 3 | 4 | 5 | 6; - id: string; -} - -// @internal -export interface FASTAccordionItem extends StartEnd { -} - -// Warning: (ae-different-release-tags) This symbol has another declaration with a different release tag -// Warning: (ae-internal-mixed-release-tag) Mixed release tags are not allowed for "FASTAnchor" because one of its declarations is marked as @internal -// -// @public -export class FASTAnchor extends FASTElement { - control: HTMLAnchorElement; - // @internal - defaultSlottedContent: HTMLElement[]; - download: string; - href: string; - hreflang: string; - ping: string; - referrerpolicy: string; - rel: string; - target: AnchorTarget; - type: string; -} - -// @internal -export interface FASTAnchor extends StartEnd, DelegatesARIALink { -} - -// @public -export class FASTAnchoredRegion extends FASTElement { - // @internal (undocumented) - adoptedCallback(): void; - anchor: string; - // (undocumented) - protected anchorChanged(): void; - anchorElement: HTMLElement | null; - // (undocumented) - protected anchorElementChanged(): void; - autoUpdateMode: AutoUpdateMode; - // (undocumented) - protected autoUpdateModeChanged(prevMode: AutoUpdateMode, newMode: AutoUpdateMode): void; - // @internal (undocumented) - connectedCallback(): void; - // @internal (undocumented) - disconnectedCallback(): void; - fixedPlacement: boolean; - // (undocumented) - protected fixedPlacementChanged(): void; - horizontalDefaultPosition: HorizontalPosition; - // (undocumented) - protected horizontalDefaultPositionChanged(): void; - horizontalInset: boolean; - // (undocumented) - protected horizontalInsetChanged(): void; - horizontalPosition: AnchoredRegionPositionLabel | undefined; - horizontalPositioningMode: AxisPositioningMode; - // (undocumented) - protected horizontalPositioningModeChanged(): void; - horizontalScaling: AxisScalingMode; - // (undocumented) - protected horizontalScalingChanged(): void; - horizontalThreshold: number; - // (undocumented) - protected horizontalThresholdChanged(): void; - horizontalViewportLock: boolean; - // (undocumented) - protected horizontalViewportLockChanged(): void; - // @internal - initialLayoutComplete: boolean; - update: () => void; - verticalDefaultPosition: VerticalPosition; - // (undocumented) - protected verticalDefaultPositionChanged(): void; - verticalInset: boolean; - // (undocumented) - protected verticalInsetChanged(): void; - verticalPosition: AnchoredRegionPositionLabel | undefined; - verticalPositioningMode: AxisPositioningMode; - // (undocumented) - protected verticalPositioningModeChanged(): void; - verticalScaling: AxisScalingMode; - // (undocumented) - protected verticalScalingChanged(): void; - verticalThreshold: number; - // (undocumented) - protected verticalThresholdChanged(): void; - verticalViewportLock: boolean; - // (undocumented) - protected verticalViewportLockChanged(): void; - viewport: string; - // (undocumented) - protected viewportChanged(): void; - viewportElement: HTMLElement | null; - // (undocumented) - protected viewportElementChanged(): void; -} - -// @public -export class FASTAvatar extends FASTElement { -} - -// Warning: (ae-different-release-tags) This symbol has another declaration with a different release tag -// Warning: (ae-internal-mixed-release-tag) Mixed release tags are not allowed for "FASTBadge" because one of its declarations is marked as @internal -// -// @public -export class FASTBadge extends FASTElement { -} - -// @internal -export interface FASTBadge extends StartEnd { -} - -// @public -export class FASTBaseProgress extends FASTElement { - // @internal (undocumented) - connectedCallback(): void; - max: number; - // (undocumented) - protected maxChanged(): void; - min: number; - // (undocumented) - protected minChanged(): void; - // @internal - percentComplete: number; - value: number | null; - // (undocumented) - protected valueChanged(): void; -} - -// Warning: (ae-different-release-tags) This symbol has another declaration with a different release tag -// Warning: (ae-internal-mixed-release-tag) Mixed release tags are not allowed for "FASTBreadcrumb" because one of its declarations is marked as @internal -// -// @public -export class FASTBreadcrumb extends FASTElement { - // @internal (undocumented) - slottedBreadcrumbItems: HTMLElement[]; - // (undocumented) - protected slottedBreadcrumbItemsChanged(): void; -} - -// @internal -export interface FASTBreadcrumb extends StartEnd { -} - -// Warning: (ae-different-release-tags) This symbol has another declaration with a different release tag -// Warning: (ae-internal-mixed-release-tag) Mixed release tags are not allowed for "FASTBreadcrumbItem" because one of its declarations is marked as @internal -// -// @public -export class FASTBreadcrumbItem extends FASTAnchor { - // @internal (undocumented) - separator: boolean; -} - -// @internal -export interface FASTBreadcrumbItem extends StartEnd, DelegatesARIALink { -} - -// Warning: (ae-different-release-tags) This symbol has another declaration with a different release tag -// Warning: (ae-forgotten-export) The symbol "FormAssociatedButton" needs to be exported by the entry point index.d.ts -// Warning: (ae-internal-mixed-release-tag) Mixed release tags are not allowed for "FASTButton" because one of its declarations is marked as @internal -// -// @public -export class FASTButton extends FormAssociatedButton { - autofocus: boolean; - // @internal (undocumented) - connectedCallback(): void; - // (undocumented) - control: HTMLButtonElement; - defaultSlottedContent: HTMLElement[]; - formaction: string; - // (undocumented) - protected formactionChanged(): void; - formenctype: string; - // (undocumented) - protected formenctypeChanged(): void; - formId: string; - formmethod: string; - // (undocumented) - protected formmethodChanged(): void; - formnovalidate: boolean; - // (undocumented) - protected formnovalidateChanged(): void; - formtarget: "_self" | "_blank" | "_parent" | "_top"; - // (undocumented) - protected formtargetChanged(): void; - type: ButtonType; - // (undocumented) - protected typeChanged(previous: ButtonType | undefined, next: ButtonType): void; - validate(): void; -} - -// @internal -export interface FASTButton extends StartEnd, DelegatesARIAButton { -} - -// Warning: (ae-different-release-tags) This symbol has another declaration with a different release tag -// Warning: (ae-internal-mixed-release-tag) Mixed release tags are not allowed for "FASTCalendar" because one of its declarations is marked as @internal -// -// @public -export class FASTCalendar extends FASTElement { - dateFormatter: DateFormatter; - dateInString(date: Date | string, datesString: string): boolean; - dayFormat: DayFormat; - // (undocumented) - protected dayFormatChanged(): void; - disabledDates: string; - firstDay: number; - getDayClassNames(date: CalendarDateInfo, todayString?: string): string; - getDays(info?: CalendarInfo, minWeeks?: number): CalendarDateInfo[][]; - getMonthInfo(month?: number, year?: number): CalendarInfo; - getWeekdayText(): WeekdayText[]; - handleDateSelect(event: Event, day: CalendarDateInfo): void; - handleKeydown(event: KeyboardEvent, date: CalendarDateInfo): boolean; - locale: string; - // (undocumented) - protected localeChanged(): void; - minWeeks: number; - month: number; - monthFormat: MonthFormat; - // (undocumented) - protected monthFormatChanged(): void; - readonly: boolean; - selectedDates: string; - weekdayFormat: WeekdayFormat; - // (undocumented) - protected weekdayFormatChanged(): void; - year: number; - yearFormat: YearFormat; - // (undocumented) - protected yearFormatChanged(): void; -} - -// @internal -export interface FASTCalendar extends StartEnd { -} - -// @public -export class FASTCard extends FASTElement { -} - -// Warning: (ae-forgotten-export) The symbol "FormAssociatedCheckbox" needs to be exported by the entry point index.d.ts -// -// @public -export class FASTCheckbox extends FormAssociatedCheckbox { - constructor(); - // @internal (undocumented) - clickHandler: (e: MouseEvent) => void; - // @internal (undocumented) - defaultSlottedNodes: Node[]; - indeterminate: boolean; - // @internal - initialValue: string; - // @internal (undocumented) - keypressHandler: (e: KeyboardEvent) => void; -} - -// Warning: (ae-different-release-tags) This symbol has another declaration with a different release tag -// Warning: (ae-forgotten-export) The symbol "FormAssociatedCombobox" needs to be exported by the entry point index.d.ts -// Warning: (ae-internal-mixed-release-tag) Mixed release tags are not allowed for "FASTCombobox" because one of its declarations is marked as @internal -// -// @public -export class FASTCombobox extends FormAssociatedCombobox { - autocomplete: ComboboxAutocomplete | undefined; - cleanup: () => void; - // @internal - clickHandler(e: MouseEvent): boolean | void; - // (undocumented) - connectedCallback(): void; - // @internal - control: HTMLInputElement; - // @internal - disabledChanged(prev: boolean, next: boolean): void; - // (undocumented) - disconnectedCallback(): void; - filteredOptions: FASTListboxOption[]; - filterOptions(): void; - // @internal - protected focusAndScrollOptionIntoView(): void; - // @internal - focusoutHandler(e: FocusEvent): boolean | void; - // @internal - formResetCallback(): void; - // @internal - inputHandler(e: InputEvent): boolean | void; - // @internal - keydownHandler(e: Event & KeyboardEvent): boolean | void; - // @internal - keyupHandler(e: KeyboardEvent): boolean | void; - // @internal - listbox: HTMLDivElement; - // @internal - listboxId: string; - open: boolean; - // @internal - protected openChanged(): void; - get options(): FASTListboxOption[]; - set options(value: FASTListboxOption[]); - placeholder: string; - // @internal - protected placeholderChanged(): void; - // @internal - selectedIndexChanged(prev: number | undefined, next: number): void; - // @internal - selectedOptionsChanged(prev: FASTListboxOption[] | undefined, next: FASTListboxOption[]): void; - // @internal - selectPreviousOption(): void; - // @internal - setDefaultSelectedOption(): void; - setPositioning(): void; - // @internal - slottedOptionsChanged(prev: Element[] | undefined, next: Element[]): void; - validate(): void; - get value(): string; - set value(next: string); -} - -// @internal -export interface FASTCombobox extends StartEnd, DelegatesARIACombobox { -} - -// @public -export class FASTDataGrid extends FASTElement { - cellItemTemplate?: ViewTemplate; - columnDefinitions: ColumnDefinition[] | null; - // (undocumented) - protected columnDefinitionsChanged(): void; - // @internal (undocumented) - connectedCallback(): void; - // @internal - defaultRowItemTemplate: ViewTemplate; - // @internal (undocumented) - disconnectedCallback(): void; - focusColumnIndex: number; - focusRowIndex: number; - static generateColumns(row: object): ColumnDefinition[]; - generateHeader: GenerateHeaderOptions; - gridTemplateColumns: string; - // (undocumented) - protected gridTemplateColumnsChanged(): void; - // @internal (undocumented) - handleFocus(e: FocusEvent): void; - // @internal (undocumented) - handleFocusOut(e: FocusEvent): void; - // @internal (undocumented) - handleKeydown(e: KeyboardEvent): void; - // @internal (undocumented) - handleRowFocus(e: Event): void; - // (undocumented) - handleRowSelectedChange(e: CustomEvent): void; - headerCellItemTemplate?: ViewTemplate; - initialRowSelection: string; - noTabbing: boolean; - // (undocumented) - protected noTabbingChanged(): void; - pageSize: number | undefined; - // @internal - rowElements: HTMLElement[]; - rowElementTag: string; - rowItemTemplate: ViewTemplate; - rowsData: object[]; - // (undocumented) - protected rowsDataChanged(): void; - rowSelectableCallback: (rowIndex: number, grid: FASTDataGrid) => boolean; - get selectedRowIndexes(): number[]; - set selectedRowIndexes(next: number[]); - selectionBehavior: DataGridSelectionBehavior; - selectionMode: DataGridSelectionMode; -} - -// @public -export class FASTDataGridCell extends FASTElement { - cellType: DataGridCellTypes; - columnDefinition: ColumnDefinition | null; - // (undocumented) - protected columnDefinitionChanged(oldValue: ColumnDefinition | null, newValue: ColumnDefinition | null): void; - // @internal (undocumented) - connectedCallback(): void; - // @internal (undocumented) - disconnectedCallback(): void; - gridColumn: string; - // (undocumented) - protected gridColumnChanged(): void; - // (undocumented) - handleFocusin(e: FocusEvent): void; - // (undocumented) - handleFocusout(e: FocusEvent): void; - // (undocumented) - handleKeydown(e: KeyboardEvent): void; - rowData: object | null; -} - -// @public -export class FASTDataGridRow extends FASTElement { - // @internal - activeCellItemTemplate?: ViewTemplate; - // @internal - cellElements: HTMLElement[]; - cellItemTemplate?: ViewTemplate; - columnDefinitions: ColumnDefinition[] | null; - // @internal (undocumented) - connectedCallback(): void; - // @internal - defaultCellItemTemplate?: ViewTemplate; - // @internal - defaultHeaderCellItemTemplate?: ViewTemplate; - // @internal (undocumented) - disconnectedCallback(): void; - // @internal (undocumented) - focusColumnIndex: number; - gridTemplateColumns: string; - // (undocumented) - protected gridTemplateColumnsChanged(): void; - // @internal (undocumented) - handleCellFocus(e: Event): void; - // @internal (undocumented) - handleClick(e: MouseEvent): void; - // (undocumented) - handleFocusout(e: FocusEvent): void; - // @internal (undocumented) - handleKeydown(e: KeyboardEvent): void; - headerCellItemTemplate?: ViewTemplate; - // @internal - isActiveRow: boolean; - rowData: object | null; - // (undocumented) - protected rowDataChanged(): void; - rowIndex: number; - rowType: DataGridRowTypes; - // @internal - selected: boolean; - // @internal - selectionBehavior: DataGridSelectionBehavior; - // @internal (undocumented) - slottedCellElements: HTMLElement[]; - // Warning: (ae-forgotten-export) The symbol "DataGridSelectionChangeDetail" needs to be exported by the entry point index.d.ts - toggleSelected(detail: DataGridSelectionChangeDetail): void; -} - -// @public -export class FASTDialog extends FASTElement { - ariaDescribedby: string; - ariaLabel: string; - ariaLabelledby: string; - // @internal (undocumented) - connectedCallback(): void; - // @internal (undocumented) - dialog: HTMLDivElement; - // @internal (undocumented) - disconnectedCallback(): void; - // @internal (undocumented) - dismiss(): void; - // @internal (undocumented) - handleChange(source: any, propertyName: string): void; - hidden: boolean; - hide(): void; - modal: boolean; - noFocusTrap: boolean; - show(): void; -} - -// Warning: (ae-different-release-tags) This symbol has another declaration with a different release tag -// Warning: (ae-internal-mixed-release-tag) Mixed release tags are not allowed for "FASTDisclosure" because one of its declarations is marked as @internal -// -// @public -export class FASTDisclosure extends FASTElement { - // @internal (undocumented) - connectedCallback(): void; - // @internal (undocumented) - details: HTMLDetailsElement; - // @internal (undocumented) - disconnectedCallback(): void; - expanded: boolean; - hide(): void; - protected onToggle(): void; - protected setup(): void; - show(): void; - summary: string; - toggle(): void; -} - -// @internal -export interface FASTDisclosure extends StartEnd { -} - -// @public -export class FASTDivider extends FASTElement { - orientation: DividerOrientation; - role: DividerRole; -} - -// @public -export class FASTFlipper extends FASTElement { - direction: FlipperDirection; - disabled: boolean; - hiddenFromAT: boolean; - keyupHandler(e: Event & KeyboardEvent): void; -} - -// Warning: (ae-different-release-tags) This symbol has another declaration with a different release tag -// Warning: (ae-internal-mixed-release-tag) Mixed release tags are not allowed for "FASTHorizontalScroll" because one of its declarations is marked as @internal -// -// @public -export class FASTHorizontalScroll extends FASTElement { - // (undocumented) - connectedCallback(): void; - content: HTMLDivElement; - // (undocumented) - disconnectedCallback(): void; - duration: string; - easing: ScrollEasing | string; - flippersHiddenFromAT: boolean; - keyupHandler(e: Event & KeyboardEvent): void; - nextFlipperContainer: HTMLDivElement; - previousFlipperContainer: HTMLDivElement; - resized(): void; - scrollContainer: HTMLDivElement; - scrolled(): void; - // @internal - scrollingChanged(prev: unknown, next: boolean): void; - scrollInView(item: HTMLElement | number, padding?: number, rightPadding?: number): void; - scrollItems: HTMLElement[]; - scrollItemsChanged(previous: HTMLElement[], next: HTMLElement[]): void; - scrollToNext(): void; - scrollToPosition(newPosition: number, position?: number): void; - scrollToPrevious(): void; - speed: number; - view: HorizontalScrollView; -} - -// @internal -export interface FASTHorizontalScroll extends StartEnd { -} - -// Warning: (ae-different-release-tags) This symbol has another declaration with a different release tag -// Warning: (ae-internal-mixed-release-tag) Mixed release tags are not allowed for "FASTListbox" because one of its declarations is marked as @internal -// -// @public -export abstract class FASTListbox extends FASTElement { - // @internal - clickHandler(e: MouseEvent): boolean | void; - disabled: boolean; - // @internal - get firstSelectedOption(): FASTListboxOption; - // @internal - protected focusAndScrollOptionIntoView(optionToFocus?: FASTListboxOption | null): void; - // @internal - focusinHandler(e: FocusEvent): void; - // @internal - protected getSelectableIndex(prev: number | undefined, next: number): number; - // @internal - protected getTypeaheadMatches(): FASTListboxOption[]; - // @internal - handleChange(source: any, propertyName: string): void; - // @internal - handleTypeAhead(key: string): void; - // @internal - protected get hasSelectableOptions(): boolean; - // @internal - keydownHandler(e: KeyboardEvent): boolean | void; - get length(): number; - // @internal - mousedownHandler(e: MouseEvent): boolean | void; - // @internal - multipleChanged(prev: boolean | undefined, next: boolean): void; - get options(): FASTListboxOption[]; - set options(value: FASTListboxOption[]); - // @internal - protected _options: FASTListboxOption[]; - selectedIndex: number; - // @internal - selectedIndexChanged(prev: number | undefined, next: number): void; - selectedOptions: FASTListboxOption[]; - // @internal - protected selectedOptionsChanged(prev: FASTListboxOption[] | undefined, next: FASTListboxOption[]): void; - selectFirstOption(): void; - // @internal - selectLastOption(): void; - // @internal - selectNextOption(): void; - // @internal - selectPreviousOption(): void; - // @internal - protected setDefaultSelectedOption(): void; - protected setSelectedOptions(): void; - // @internal - protected shouldSkipFocus: boolean; - static slottedOptionFilter(n: HTMLElement): boolean; - // @internal - slottedOptions: Element[]; - // @internal - slottedOptionsChanged(prev: Element[] | undefined, next: Element[]): void; - // @internal - protected static readonly TYPE_AHEAD_TIMEOUT_MS = 1000; - // @internal - protected typeaheadBuffer: string; - // @internal - typeaheadBufferChanged(prev: string, next: string): void; - // @internal @deprecated - protected get typeAheadExpired(): boolean; - protected set typeAheadExpired(value: boolean); - // @internal - protected typeaheadExpired: boolean; - // @internal - protected typeaheadTimeout: number; -} - -// @internal (undocumented) -export interface FASTListbox extends DelegatesARIAListbox { -} - -// @public -export class FASTListboxElement extends FASTListbox { - // @internal - protected activeIndex: number; - // @internal - protected activeIndexChanged(prev: number | undefined, next: number): void; - // @internal - get activeOption(): FASTListboxOption | null; - // @internal - protected checkActiveIndex(): void; - // @internal - protected get checkedOptions(): FASTListboxOption[]; - // @internal - protected checkFirstOption(preserveChecked?: boolean): void; - // @internal - protected checkLastOption(preserveChecked?: boolean): void; - // @internal - protected checkNextOption(preserveChecked?: boolean): void; - // @internal - protected checkPreviousOption(preserveChecked?: boolean): void; - // @internal @override - clickHandler(e: MouseEvent): boolean | void; - // @internal @override (undocumented) - connectedCallback(): void; - // @internal @override (undocumented) - disconnectedCallback(): void; - // @internal - get firstSelectedOptionIndex(): number; - // @internal @override (undocumented) - protected focusAndScrollOptionIntoView(): void; - // @internal @override - focusinHandler(e: FocusEvent): boolean | void; - // @internal - focusoutHandler(e: FocusEvent): void; - // @internal @override - keydownHandler(e: KeyboardEvent): boolean | void; - // @internal @override - mousedownHandler(e: MouseEvent): boolean | void; - multiple: boolean; - // @internal - multipleChanged(prev: boolean | undefined, next: boolean): void; - // @internal - protected rangeStartIndex: number; - // @override - protected setSelectedOptions(): void; - size: number; - // @internal - protected sizeChanged(prev: number | unknown, next: number): void; - // @internal - toggleSelectedForAllCheckedOptions(): void; - // @internal @override (undocumented) - typeaheadBufferChanged(prev: string, next: string): void; - // @internal - protected uncheckAllOptions(preserveChecked?: boolean): void; -} - -// Warning: (ae-different-release-tags) This symbol has another declaration with a different release tag -// Warning: (ae-internal-mixed-release-tag) Mixed release tags are not allowed for "FASTListboxOption" because one of its declarations is marked as @internal -// -// @public -export class FASTListboxOption extends FASTElement { - constructor(text?: string, value?: string, defaultSelected?: boolean, selected?: boolean); - checked?: boolean; - protected checkedChanged(prev: boolean | unknown, next?: boolean): void; - content: Node[]; - // @internal - protected contentChanged(prev: undefined | Node[], next: Node[]): void; - defaultSelected: boolean; - // (undocumented) - protected defaultSelectedChanged(): void; - dirtyValue: boolean; - disabled: boolean; - // (undocumented) - protected disabledChanged(prev: boolean, next: boolean): void; - // (undocumented) - get form(): HTMLFormElement | null; - protected initialValue: string; - // (undocumented) - initialValueChanged(previous: string, next: string): void; - // (undocumented) - get label(): string; - // @internal (undocumented) - proxy: HTMLOptionElement; - selected: boolean; - selectedAttribute: boolean; - // (undocumented) - protected selectedAttributeChanged(): void; - // (undocumented) - protected selectedChanged(): void; - // (undocumented) - get text(): string; - set value(next: string); - // (undocumented) - get value(): string; -} - -// @internal (undocumented) -export interface FASTListboxOption extends StartEnd, DelegatesARIAListboxOption { -} - -// @public -export class FASTMenu extends FASTElement { - collapseExpandedItem(): void; - // @internal (undocumented) - connectedCallback(): void; - // @internal (undocumented) - disconnectedCallback(): void; - focus(): void; - // (undocumented) - handleChange(source: any, propertyName: string): void; - // @internal - handleFocusOut: (e: FocusEvent) => void; - // @internal (undocumented) - handleMenuKeyDown(e: KeyboardEvent): void | boolean; - protected isMenuItemElement: (el: Element) => el is HTMLElement; - // @internal (undocumented) - readonly isNestedMenu: () => boolean; - // @internal (undocumented) - items: HTMLElement[]; - // (undocumented) - protected itemsChanged(oldValue: HTMLElement[], newValue: HTMLElement[]): void; - // (undocumented) - protected menuItems: Element[] | undefined; - // (undocumented) - protected setItems(): void; -} - -// Warning: (ae-different-release-tags) This symbol has another declaration with a different release tag -// Warning: (ae-internal-mixed-release-tag) Mixed release tags are not allowed for "FASTMenuItem" because one of its declarations is marked as @internal -// -// @public -export class FASTMenuItem extends FASTElement { - checked: boolean; - // (undocumented) - protected checkedChanged(oldValue: boolean, newValue: boolean): void; - cleanup: () => void; - disabled: boolean; - // @internal (undocumented) - disconnectedCallback(): void; - expanded: boolean; - // (undocumented) - protected expandedChanged(prev: boolean | undefined, next: boolean): void; - // @internal (undocumented) - handleMenuItemClick: (e: MouseEvent) => boolean; - // @internal (undocumented) - handleMenuItemKeyDown: (e: KeyboardEvent) => boolean; - // @internal (undocumented) - handleMouseOut: (e: MouseEvent) => boolean; - // @internal (undocumented) - handleMouseOver: (e: MouseEvent) => boolean; - // @internal (undocumented) - get hasSubmenu(): boolean; - hidden: boolean; - role: MenuItemRole; - // @internal - slottedSubmenu: HTMLElement[]; - // @internal - protected slottedSubmenuChanged(prev: HTMLElement[] | undefined, next: HTMLElement[]): void; - // @internal (undocumented) - submenu: HTMLElement | undefined; - // @internal - submenuContainer: HTMLDivElement; - // @internal (undocumented) - submenuLoaded: () => void; - updateSubmenu(): void; -} - -// @internal -export interface FASTMenuItem extends StartEnd { -} - -// Warning: (ae-different-release-tags) This symbol has another declaration with a different release tag -// Warning: (ae-forgotten-export) The symbol "FormAssociatedNumberField" needs to be exported by the entry point index.d.ts -// Warning: (ae-internal-mixed-release-tag) Mixed release tags are not allowed for "FASTNumberField" because one of its declarations is marked as @internal -// -// @public -export class FASTNumberField extends FormAssociatedNumberField { - autofocus: boolean; - // @internal - connectedCallback(): void; - // @internal - defaultSlottedNodes: Node[]; - // @internal - field: HTMLInputElement; - // @internal - handleBlur(): void; - // @internal - handleChange(): void; - // @internal - handleKeyDown(e: KeyboardEvent): boolean; - // @internal - handleTextInput(): void; - hideStep: boolean; - list: string; - max: number; - // @internal - maxChanged(previous: number, next: number): void; - maxlength: number; - min: number; - // @internal - minChanged(previous: number, next: number): void; - minlength: number; - placeholder: string; - readOnly: boolean; - select(): void; - size: number; - step: number; - stepDown(): void; - stepUp(): void; - validate(): void; - get valueAsNumber(): number; - set valueAsNumber(next: number); - // @internal - valueChanged(previous: string, next: string): void; -} - -// @internal -export interface FASTNumberField extends StartEnd, DelegatesARIATextbox { -} - -// Warning: (ae-forgotten-export) The symbol "FormAssociatedPicker" needs to be exported by the entry point index.d.ts -// -// @beta -export class FASTPicker extends FormAssociatedPicker { - // @internal - activeListItemTemplate?: ViewTemplate; - // @internal - activeMenuOptionTemplate?: ViewTemplate; - // @internal (undocumented) - connectedCallback(): void; - defaultListItemTemplate?: ViewTemplate; - // (undocumented) - protected defaultListItemTemplateChanged(): void; - defaultMenuOptionTemplate?: ViewTemplate; - // (undocumented) - protected defaultMenuOptionTemplateChanged(): void; - // @public - disabled: boolean; - // (undocumented) - disabledChanged(previous: boolean, next: boolean): void; - disableQueryFilter: boolean; - // (undocumented) - protected disableQueryFilterChanged(): void; - disableSelectionFilter: boolean; - // (undocumented) - protected disableSelectionFilterChanged(): void; - // (undocumented) - disconnectedCallback(): void; - // @internal - filteredOptionsList: string[]; - // @deprecated - filterQuery: boolean; - // (undocumented) - protected filterQueryChanged(): void; - // @deprecated - filterSelected: boolean; - // (undocumented) - protected filterSelectedChanged(): void; - // @internal - flyoutOpen: boolean; - // (undocumented) - protected flyoutOpenChanged(): void; - // @public - focus(): void; - handleFocusIn(e: FocusEvent): boolean; - handleFocusOut(e: FocusEvent): boolean; - handleItemInvoke(e: Event): boolean; - handleKeyDown(e: KeyboardEvent): boolean; - handleOptionInvoke(e: Event): boolean; - handleRegionLoaded(e: Event): void; - handleSelectionChange(): void; - // @internal - inputElement: HTMLInputElement; - itemsPlaceholderElement: Node; - label: string; - labelledBy: string; - // @internal - listElement: FASTPickerList; - listItemContentsTemplate: ViewTemplate; - listItemTemplate: ViewTemplate; - // (undocumented) - protected listItemTemplateChanged(): void; - loadingText: string; - maxSelected: number | null; - // @internal - menuConfig: AnchoredRegionConfig; - // @internal - menuElement: FASTPickerMenu; - // @internal - menuFocusIndex: number; - // @internal - menuFocusOptionId: string | undefined; - // @internal - menuId: string; - menuOptionContentsTemplate: ViewTemplate; - menuOptionTemplate: ViewTemplate; - // (undocumented) - protected menuOptionTemplateChanged(): void; - menuPlacement: MenuPlacement; - // (undocumented) - protected menuPlacementChanged(): void; - // @internal - menuTag: string; - noSuggestionsText: string; - options: string; - // (undocumented) - protected optionsChanged(): void; - optionsList: string[]; - placeholder: string; - query: string; - // (undocumented) - protected queryChanged(): void; - // @internal - region: FASTAnchoredRegion; - // @internal - selectedItems: string[]; - // @internal - selectedListTag: string; - selection: string; - // (undocumented) - protected selectionChanged(): void; - showLoading: boolean; - // (undocumented) - protected showLoadingChanged(): void; - // @internal - showNoOptions: boolean; - suggestionsAvailableText: string; -} - -// @beta -export class FASTPickerList extends FASTElement { -} - -// @beta -export class FASTPickerListItem extends FASTElement { - // @internal (undocumented) - connectedCallback(): void; - contentsTemplate: ViewTemplate; - // (undocumented) - protected contentsTemplateChanged(): void; - // @internal (undocumented) - disconnectedCallback(): void; - // (undocumented) - handleClick(e: MouseEvent): void; - // (undocumented) - handleKeyDown(e: KeyboardEvent): boolean; - // Warning: (ae-forgotten-export) The symbol "PickerContext" needs to be exported by the entry point index.d.ts - pickerContext: PickerContext; - value: string; -} - -// @beta -export class FASTPickerMenu extends FASTElement { - // @internal - footerElements: HTMLElement[]; - // (undocumented) - footerElementsChanged(): void; - // @internal - headerElements: HTMLElement[]; - // (undocumented) - headerElementsChanged(): void; - // @internal - menuElements: HTMLElement[]; - // (undocumented) - menuElementsChanged(): void; - // @internal - optionElements: HTMLElement[]; - suggestionsAvailableText: string; -} - -// @beta -export class FASTPickerMenuOption extends FASTElement { - // @internal (undocumented) - connectedCallback(): void; - contentsTemplate: ViewTemplate; - // (undocumented) - protected contentsTemplateChanged(): void; - // @internal (undocumented) - disconnectedCallback(): void; - // (undocumented) - handleClick(e: MouseEvent): boolean; - value: string; -} - -// @public -export class FASTProgress extends FASTBaseProgress { -} - -// @public -export class FASTProgressRing extends FASTBaseProgress { -} - -// Warning: (ae-forgotten-export) The symbol "FormAssociatedRadio" needs to be exported by the entry point index.d.ts -// -// @public -export class FASTRadio extends FormAssociatedRadio implements RadioControl { - constructor(); - // @internal (undocumented) - connectedCallback(): void; - // @internal (undocumented) - defaultCheckedChanged(): void; - // @internal (undocumented) - defaultSlottedNodes: Node[]; - // @internal - initialValue: string; - // @beta - keypressHandler(e: KeyboardEvent): boolean | void; - name: string; -} - -// @public -export class FASTRadioGroup extends FASTElement { - // (undocumented) - childItems: HTMLElement[]; - // @internal (undocumented) - clickHandler: (e: MouseEvent) => void | boolean; - // @internal (undocumented) - connectedCallback(): void; - disabled: boolean; - // (undocumented) - protected disabledChanged(): void; - // (undocumented) - disconnectedCallback(): void; - // @internal (undocumented) - focusOutHandler: (e: FocusEvent) => boolean | void; - // @internal (undocumented) - handleDisabledClick: (e: MouseEvent) => void | boolean; - // @internal - keydownHandler: (e: KeyboardEvent) => boolean | void; - name: string; - // (undocumented) - protected nameChanged(): void; - orientation: RadioGroupOrientation; - readOnly: boolean; - // @internal (undocumented) - slottedRadioButtons: HTMLElement[]; - // (undocumented) - protected slottedRadioButtonsChanged(oldValue: unknown, newValue: HTMLElement[]): void; - value: string; - // (undocumented) - protected valueChanged(): void; -} - -// Warning: (ae-different-release-tags) This symbol has another declaration with a different release tag -// Warning: (ae-forgotten-export) The symbol "FormAssociatedSearch" needs to be exported by the entry point index.d.ts -// Warning: (ae-internal-mixed-release-tag) Mixed release tags are not allowed for "FASTSearch" because one of its declarations is marked as @internal -// -// @public -export class FASTSearch extends FormAssociatedSearch { - autofocus: boolean; - // (undocumented) - protected autofocusChanged(): void; - // @internal (undocumented) - connectedCallback(): void; - // @internal (undocumented) - defaultSlottedNodes: Node[]; - // @internal - field: HTMLInputElement; - // @internal - handleChange(): void; - handleClearInput(): void; - // @internal - handleTextInput(): void; - list: string; - // (undocumented) - protected listChanged(): void; - maxlength: number; - // (undocumented) - protected maxlengthChanged(): void; - minlength: number; - // (undocumented) - protected minlengthChanged(): void; - pattern: string; - // (undocumented) - protected patternChanged(): void; - placeholder: string; - // (undocumented) - protected placeholderChanged(): void; - readOnly: boolean; - // (undocumented) - protected readOnlyChanged(): void; - size: number; - // (undocumented) - protected sizeChanged(): void; - spellcheck: boolean; - // (undocumented) - protected spellcheckChanged(): void; - validate(): void; -} - -// @internal -export interface FASTSearch extends StartEnd, DelegatesARIASearch { -} - -// Warning: (ae-different-release-tags) This symbol has another declaration with a different release tag -// Warning: (ae-forgotten-export) The symbol "FormAssociatedSelect" needs to be exported by the entry point index.d.ts -// Warning: (ae-internal-mixed-release-tag) Mixed release tags are not allowed for "FASTSelect" because one of its declarations is marked as @internal -// -// @public -export class FASTSelect extends FormAssociatedSelect { - cleanup: () => void; - // @internal - clickHandler(e: MouseEvent): boolean | void; - // @internal - get collapsible(): boolean; - // (undocumented) - connectedCallback(): void; - // @internal - control: HTMLElement; - // @internal - disabledChanged(prev: boolean, next: boolean): void; - // (undocumented) - disconnectedCallback(): void; - get displayValue(): string; - // @internal - focusoutHandler(e: FocusEvent): boolean | void; - // @internal - formResetCallback(): void; - // @internal @override - handleChange(source: any, propertyName: string): void; - // @internal - keydownHandler(e: KeyboardEvent): boolean | void; - // @internal - listbox: HTMLDivElement; - // @internal - listboxId: string; - // @internal @override - mousedownHandler(e: MouseEvent): boolean | void; - multipleChanged(prev: boolean | undefined, next: boolean): void; - open: boolean; - // @internal - protected openChanged(prev: boolean | undefined, next: boolean): void; - // @internal - selectedIndexChanged(prev: number | undefined, next: number): void; - // @internal @override - protected selectedOptionsChanged(prev: FASTListboxOption[] | undefined, next: FASTListboxOption[]): void; - // @internal @override - protected setDefaultSelectedOption(): void; - setPositioning(): void; - // @internal @override - protected sizeChanged(prev: number | undefined, next: number): void; - // @internal - slottedOptionsChanged(prev: Element[] | undefined, next: Element[]): void; - get value(): string; - set value(next: string); -} - -// @internal (undocumented) -export interface FASTSelect extends StartEnd, DelegatesARIASelect { -} - -// @public -export class FASTSkeleton extends FASTElement { - fill: string; - pattern: string; - shape: SkeletonShape; - shimmer: boolean; -} - -// Warning: (ae-forgotten-export) The symbol "FormAssociatedSlider" needs to be exported by the entry point index.d.ts -// -// @public -export class FASTSlider extends FormAssociatedSlider implements SliderConfiguration { - // @internal - calculateNewValue(rawValue: number): number; - // @internal (undocumented) - connectedCallback(): void; - decrement(): void; - // @internal (undocumented) - direction: Direction; - // @internal (undocumented) - disconnectedCallback(): void; - increment(): void; - // @internal (undocumented) - initialValue: string; - // @internal (undocumented) - isDragging: boolean; - // (undocumented) - protected keypressHandler: (e: KeyboardEvent) => void; - max: number; - // (undocumented) - protected maxChanged(): void; - min: number; - // (undocumented) - protected minChanged(): void; - mode: SliderMode; - orientation: Orientation; - // (undocumented) - protected orientationChanged(): void; - // @internal (undocumented) - position: string; - step: number | undefined; - // (undocumented) - protected stepChanged(): void; - // @internal (undocumented) - stepMultiplier: number; - // @internal (undocumented) - thumbContainer: HTMLDivElement; - // @internal (undocumented) - track: HTMLDivElement; - // @internal (undocumented) - trackHeight: number; - // @internal (undocumented) - trackLeft: number; - // @internal (undocumented) - trackMinHeight: number; - // @internal (undocumented) - trackMinWidth: number; - // @internal (undocumented) - trackWidth: number; - get valueAsNumber(): number; - set valueAsNumber(next: number); - // @internal (undocumented) - valueChanged(previous: string, next: string): void; - valueTextFormatter: (value: string) => string | null; -} - -// @public -export class FASTSliderLabel extends FASTElement { - // @internal (undocumented) - connectedCallback(): void; - // @internal (undocumented) - container: HTMLDivElement; - disabled: boolean; - // @internal (undocumented) - disconnectedCallback(): void; - // @internal (undocumented) - handleChange(source: any, propertyName: string): void; - hideMark: boolean; - // @deprecated - orientation: SliderOrientation; - // @internal (undocumented) - protected orientationChanged(): void; - position: string; - // (undocumented) - protected positionChanged(): void; - // @internal (undocumented) - positionStyle: string; - // @internal (undocumented) - sliderDirection: Direction; - // @internal (undocumented) - sliderMaxPosition: number; - // @internal (undocumented) - sliderMinPosition: number; -} - -// Warning: (ae-forgotten-export) The symbol "FormAssociatedSwitch" needs to be exported by the entry point index.d.ts -// -// @public -export class FASTSwitch extends FormAssociatedSwitch { - constructor(); - // @internal (undocumented) - clickHandler: (e: MouseEvent) => void; - // @internal (undocumented) - defaultSlottedNodes: Node[]; - // @internal - initialValue: string; - // @internal (undocumented) - keypressHandler: (e: KeyboardEvent) => void; - readOnly: boolean; - // (undocumented) - protected readOnlyChanged(): void; -} - -// Warning: (ae-different-release-tags) This symbol has another declaration with a different release tag -// Warning: (ae-internal-mixed-release-tag) Mixed release tags are not allowed for "FASTTab" because one of its declarations is marked as @internal -// -// @public -export class FASTTab extends FASTElement { - disabled: boolean; -} - -// @internal -export interface FASTTab extends StartEnd { -} - -// @public -export class FASTTabPanel extends FASTElement { -} - -// Warning: (ae-different-release-tags) This symbol has another declaration with a different release tag -// Warning: (ae-internal-mixed-release-tag) Mixed release tags are not allowed for "FASTTabs" because one of its declarations is marked as @internal -// -// @public -export class FASTTabs extends FASTElement { - activeid: string; - // @internal (undocumented) - activeidChanged(oldValue: string, newValue: string): void; - activetab: HTMLElement; - adjust(adjustment: number): void; - // @internal (undocumented) - connectedCallback(): void; - orientation: TabsOrientation; - // @internal (undocumented) - orientationChanged(): void; - protected setTabs(): void; - // @internal (undocumented) - tabpanels: HTMLElement[]; - // @internal (undocumented) - tabpanelsChanged(): void; - // @internal (undocumented) - tabs: HTMLElement[]; - // @internal (undocumented) - tabsChanged(): void; -} - -// @internal -export interface FASTTabs extends StartEnd { -} - -// Warning: (ae-different-release-tags) This symbol has another declaration with a different release tag -// Warning: (ae-forgotten-export) The symbol "FormAssociatedTextArea" needs to be exported by the entry point index.d.ts -// Warning: (ae-internal-mixed-release-tag) Mixed release tags are not allowed for "FASTTextArea" because one of its declarations is marked as @internal -// -// @public -export class FASTTextArea extends FormAssociatedTextArea { - autofocus: boolean; - // (undocumented) - protected autofocusChanged(): void; - cols: number; - // @internal (undocumented) - defaultSlottedNodes: Node[]; - // @internal - field: HTMLTextAreaElement; - formId: string; - // @internal - handleChange(): void; - // @internal (undocumented) - handleTextInput: () => void; - list: string; - // (undocumented) - protected listChanged(): void; - maxlength: number; - // (undocumented) - protected maxlengthChanged(): void; - minlength: number; - // (undocumented) - protected minlengthChanged(): void; - name: string; - placeholder: string; - readOnly: boolean; - // (undocumented) - protected readOnlyChanged(): void; - resize: TextAreaResize; - rows: number; - select(): void; - spellcheck: boolean; - // (undocumented) - protected spellcheckChanged(): void; - validate(): void; -} - -// @internal -export interface FASTTextArea extends StartEnd, DelegatesARIATextbox { -} - -// Warning: (ae-different-release-tags) This symbol has another declaration with a different release tag -// Warning: (ae-forgotten-export) The symbol "FormAssociatedTextField" needs to be exported by the entry point index.d.ts -// Warning: (ae-internal-mixed-release-tag) Mixed release tags are not allowed for "FASTTextField" because one of its declarations is marked as @internal -// -// @public -export class FASTTextField extends FormAssociatedTextField { - autofocus: boolean; - // (undocumented) - protected autofocusChanged(): void; - // @internal (undocumented) - connectedCallback(): void; - // @internal (undocumented) - defaultSlottedNodes: Node[]; - enterKeyHint: "enter" | "done" | "go" | "next" | "previous" | "search" | "send"; - // (undocumented) - protected enterKeyHintChanged(): void; - // @internal - field: HTMLInputElement; - // @internal - handleChange(): void; - // @internal - handleTextInput(): void; - list: string; - // (undocumented) - protected listChanged(): void; - maxlength: number; - // (undocumented) - protected maxlengthChanged(): void; - minlength: number; - // (undocumented) - protected minlengthChanged(): void; - pattern: string; - // (undocumented) - protected patternChanged(): void; - placeholder: string; - // (undocumented) - protected placeholderChanged(): void; - readOnly: boolean; - // (undocumented) - protected readOnlyChanged(): void; - select(): void; - size: number; - // (undocumented) - protected sizeChanged(): void; - spellcheck: boolean; - // (undocumented) - protected spellcheckChanged(): void; - type: TextFieldType; - validate(): void; -} - -// @internal -export interface FASTTextField extends StartEnd, DelegatesARIATextbox { -} - -// Warning: (ae-different-release-tags) This symbol has another declaration with a different release tag -// Warning: (ae-internal-mixed-release-tag) Mixed release tags are not allowed for "FASTToolbar" because one of its declarations is marked as @internal -// -// @public -export class FASTToolbar extends FASTElement { - // @internal - get activeIndex(): number; - set activeIndex(value: number); - // @internal - protected get allSlottedItems(): (HTMLElement | Node)[]; - // (undocumented) - childItems: Element[]; - // (undocumented) - protected childItemsChanged(prev: undefined | Element[], next: Element[]): void; - // @internal (undocumented) - connectedCallback(): void; - // @internal - direction: Direction; - // @internal - focusinHandler(e: FocusEvent): boolean | void; - // @internal - keydownHandler(e: KeyboardEvent): boolean | void; - // @internal - mouseDownHandler(e: MouseEvent): boolean | void; - orientation: ToolbarOrientation; - // @internal - protected reduceFocusableElements(): void; - // @internal - slottedItems: HTMLElement[]; - // (undocumented) - protected slottedItemsChanged(): void; - // @internal - slottedLabel: HTMLElement[]; -} - -// @internal (undocumented) -export interface FASTToolbar extends StartEnd, DelegatesARIAToolbar { -} - -// @public -export class FASTTooltip extends FASTElement { - anchor: string; - // @internal - protected anchorChanged(prev: string | undefined, next: string): void; - // @internal - anchorElement: Element | null; - cleanup: () => void; - // (undocumented) - connectedCallback(): void; - // @internal - protected controlledVisibilityChanged(prev: boolean | undefined, next: boolean): void; - // @internal - protected focusinAnchorHandler: () => void; - // @internal - protected focusoutAnchorHandler: () => void; - // @internal - hideTooltip(): void; - id: string; - // (undocumented) - idChanged(prev: string, next: string): void; - placement: TooltipPlacement; - // @internal - protected positionStyles: ElementStyles; - // @internal - protected positionStylesChanged(prev: ElementStyles | undefined, next: ElementStyles | undefined): void; - setPositioning(): void; - show: boolean | undefined; - // (undocumented) - showChanged(prev: boolean | undefined, next: boolean | undefined): void; - get visible(): boolean | undefined; -} - -// Warning: (ae-different-release-tags) This symbol has another declaration with a different release tag -// Warning: (ae-internal-mixed-release-tag) Mixed release tags are not allowed for "FASTTreeItem" because one of its declarations is marked as @internal -// -// @public -export class FASTTreeItem extends FASTElement { - // @internal - get childItemLength(): number; - // @internal (undocumented) - childItems: HTMLElement[]; - disabled: boolean; - // @internal - expandCollapseButton: HTMLDivElement; - expanded: boolean; - // (undocumented) - protected expandedChanged(prev: boolean | undefined, next: boolean): void; - // @internal - focusable: boolean; - static focusItem(el: HTMLElement): void; - // @internal - handleBlur: (e: FocusEvent) => void; - // @internal - handleExpandCollapseButtonClick: (e: MouseEvent) => void; - // @internal - handleFocus: (e: FocusEvent) => void; - readonly isNestedItem: () => boolean; - // @internal - readonly isTreeItem: boolean; - // @internal - items: HTMLElement[]; - // (undocumented) - protected itemsChanged(oldValue: unknown, newValue: HTMLElement[]): void; - // @deprecated - nested: boolean; - selected: boolean; - // (undocumented) - protected selectedChanged(prev: boolean | undefined, next: boolean): void; -} - -// @internal -export interface FASTTreeItem extends StartEnd { -} - -// @public -export class FASTTreeView extends FASTElement { - // (undocumented) - connectedCallback(): void; - // @internal - currentFocused: HTMLElement | FASTTreeItem | null; - currentSelected: HTMLElement | FASTTreeItem | null; - // @internal - handleBlur: (e: FocusEvent) => void; - // @internal - handleClick(e: Event): boolean | void; - // @internal - handleFocus: (e: FocusEvent) => void; - // @internal - handleKeyDown: (e: KeyboardEvent) => boolean | void; - // @internal - handleSelectedChange: (e: Event) => boolean | void; - // @internal - slottedTreeItems: HTMLElement[]; - // (undocumented) - protected slottedTreeItemsChanged(): void; - // @internal - treeView: HTMLElement; -} - -// @public -export const FlipperDirection: { - readonly next: "next"; - readonly previous: "previous"; -}; - -// @public -export type FlipperDirection = ValuesOf; - -// @public -export type FlipperOptions = { - next?: StaticallyComposableHTML; - previous?: StaticallyComposableHTML; -}; - -// @public -export function flipperTemplate(options?: FlipperOptions): ElementViewTemplate; - -// @public -export const FlyoutPosBottom: AnchoredRegionConfig; - -// @public -export const FlyoutPosBottomFill: AnchoredRegionConfig; - -// @public -export const FlyoutPosTallest: AnchoredRegionConfig; - -// @public -export const FlyoutPosTallestFill: AnchoredRegionConfig; - -// @public -export const FlyoutPosTop: AnchoredRegionConfig; - -// @public -export const FlyoutPosTopFill: AnchoredRegionConfig; - -// @public @deprecated -export const focusVisible = "focus-visible"; - -// @public -export const forcedColorsStylesheetBehavior: (styles: ElementStyles) => MatchMediaStyleSheetBehavior; - -// @beta -export function FormAssociated(BaseCtor: T): T; - -// Warning: (ae-forgotten-export) The symbol "ElementInternals" needs to be exported by the entry point index.d.ts -// -// @beta -export interface FormAssociated extends Omit { - // (undocumented) - attachProxy(): void; - // (undocumented) - currentValue: string; - // (undocumented) - detachProxy(): void; - // (undocumented) - dirtyValue: boolean; - // (undocumented) - disabled: boolean; - // (undocumented) - disabledChanged?(previous: boolean, next: boolean): void; - // (undocumented) - readonly elementInternals: ElementInternals_2 | null; - // (undocumented) - readonly formAssociated: boolean; - // (undocumented) - formDisabledCallback?(disabled: boolean): void; - // (undocumented) - formResetCallback(): void; - // (undocumented) - initialValue: string; - // (undocumented) - initialValueChanged?(previous: string, next: string): void; - // (undocumented) - readonly labels: ReadonlyArray; - // (undocumented) - name: string; - // (undocumented) - nameChanged?(previous: string, next: string): void; - // (undocumented) - required: boolean; - // (undocumented) - requiredChanged(prev: boolean, next: boolean): void; - // (undocumented) - stopPropagation(e: Event): void; - validate(anchor?: HTMLElement): void; - // (undocumented) - value: string; - // (undocumented) - valueChanged(previous: string, next: string): void; -} - -// @beta -export type FormAssociatedElement = FormAssociated & FASTElement & HTMLElement & FormAssociatedProxy; - -// @beta -export interface FormAssociatedProxy { - // (undocumented) - disabledChanged?(previous: boolean, next: boolean): void; - // (undocumented) - formDisabledCallback?(disabled: boolean): void; - // (undocumented) - formResetCallback?(): void; - // (undocumented) - initialValueChanged?(previous: string, next: string): void; - // (undocumented) - nameChanged?(previous: string, next: string): void; - // (undocumented) - proxy: ProxyElement; - // (undocumented) - valueChanged?(previous: string, next: string): void; -} - -// @public -export const GenerateHeaderOptions: { - readonly none: "none"; - readonly default: "default"; - readonly sticky: "sticky"; -}; - -// @public -export type GenerateHeaderOptions = ValuesOf; - -// @public -export const getDirection: (rootNode: HTMLElement) => Direction; - -// @public (undocumented) -export function getRootActiveElement(element: Element): Element | null; - -// @public -export const hidden = ":host([hidden]){display:none}"; - -// @public -export const HorizontalPosition: { - readonly start: "start"; - readonly end: "end"; - readonly left: "left"; - readonly right: "right"; - readonly center: "center"; - readonly unset: "unset"; -}; - -// @public -export type HorizontalPosition = ValuesOf; - -// @public -export type HorizontalScrollOptions = StartEndOptions & { - nextFlipper?: StaticallyComposableHTML; - previousFlipper?: StaticallyComposableHTML; -}; - -// @public (undocumented) -export function horizontalScrollTemplate(options?: HorizontalScrollOptions): ElementViewTemplate; - -// @public -export const HorizontalScrollView: { - readonly default: "default"; - readonly mobile: "mobile"; -}; - -// @public -export type HorizontalScrollView = ValuesOf; - -// Warning: (ae-internal-missing-underscore) The name "interactiveCalendarGridTemplate" should be prefixed with an underscore because the declaration is marked as @internal -// -// @internal -export function interactiveCalendarGridTemplate(options: CalendarOptions, todayString: string): ViewTemplate; - -// @public -export function isListboxOption(el: Element): el is FASTListboxOption; - -// @public -export function isTreeItemElement(el: Element): el is HTMLElement; - -// @public -export const lightModeStylesheetBehavior: (styles: ElementStyles) => MatchMediaStyleSheetBehavior; - -// @public -export type ListboxOptionOptions = StartEndOptions; - -// @public -export function listboxOptionTemplate(options?: ListboxOptionOptions): ElementViewTemplate; - -// @public -export function listboxTemplate(): ElementViewTemplate; - -// @public -export abstract class MatchMediaBehavior implements HostBehavior { - constructor(query: MediaQueryList); - connectedCallback(controller: HostController): void; - protected abstract constructListener(controller: HostController): MediaQueryListListener; - disconnectedCallback(controller: HostController): void; - readonly query: MediaQueryList; -} - -// @public -export class MatchMediaStyleSheetBehavior extends MatchMediaBehavior { - constructor(query: MediaQueryList, styles: ElementStyles); - protected constructListener(controller: HostController): MediaQueryListListener; - readonly query: MediaQueryList; - // @internal - removedCallback(controller: HostController): void; - readonly styles: ElementStyles; - static with(query: MediaQueryList): (styles: ElementStyles) => MatchMediaStyleSheetBehavior; -} - -// @public -export type MediaQueryListListener = (this: MediaQueryList, ev?: MediaQueryListEvent) => void; - -// @public -export type MenuItemOptions = StartEndOptions & { - checkboxIndicator?: StaticallyComposableHTML; - expandCollapseGlyph?: StaticallyComposableHTML; - radioIndicator?: StaticallyComposableHTML; -}; - -// @public -export const MenuItemRole: { - readonly menuitem: "menuitem"; - readonly menuitemcheckbox: "menuitemcheckbox"; - readonly menuitemradio: "menuitemradio"; -}; - -// @public -export type MenuItemRole = ValuesOf; - -// @public -export function menuItemTemplate(options?: MenuItemOptions): ElementViewTemplate; - -// @beta -export const MenuPlacement: { - readonly bottom: "bottom"; - readonly bottomFill: "bottom-fill"; - readonly tallest: "tallest"; - readonly tallestFill: "tallest-fill"; - readonly top: "top"; - readonly topFill: "top-fill"; -}; - -// @beta -export type MenuPlacement = ValuesOf; - -// @public -export function menuTemplate(): ElementViewTemplate; - -// @public -export const MonthFormat: { - readonly "2-digit": "2-digit"; - readonly numeric: "numeric"; - readonly short: "short"; - readonly long: "long"; - readonly narrow: "narrow"; -}; - -// @public -export type MonthFormat = ValuesOf; - -// @public -export type MonthInfo = { - month: number; - year: number; - length: number; - start: number; -}; - -// Warning: (ae-internal-missing-underscore) The name "noninteractiveCalendarTemplate" should be prefixed with an underscore because the declaration is marked as @internal -// -// @internal -export function noninteractiveCalendarTemplate(options: CalendarOptions, todayString: string): ViewTemplate; - -// @public -export type NumberFieldOptions = StartEndOptions & { - stepDownIcon?: StaticallyComposableHTML; - stepUpIcon?: StaticallyComposableHTML; -}; - -// @public -export function numberFieldTemplate(options?: NumberFieldOptions): ElementViewTemplate; - -// Warning: (ae-incompatible-release-tags) The symbol "pickerListItemTemplate" is marked as @public, but its signature references "FASTPickerListItem" which is marked as @beta -// -// @public (undocumented) -export function pickerListItemTemplate(): ElementViewTemplate; - -// Warning: (ae-incompatible-release-tags) The symbol "pickerListTemplate" is marked as @public, but its signature references "FASTPickerList" which is marked as @beta -// -// @public (undocumented) -export function pickerListTemplate(): ElementViewTemplate; - -// Warning: (ae-incompatible-release-tags) The symbol "pickerMenuOptionTemplate" is marked as @public, but its signature references "FASTPickerMenuOption" which is marked as @beta -// -// @public (undocumented) -export function pickerMenuOptionTemplate(): ElementViewTemplate; - -// Warning: (ae-incompatible-release-tags) The symbol "pickerMenuTemplate" is marked as @public, but its signature references "FASTPickerMenu" which is marked as @beta -// -// @public -export function pickerMenuTemplate(): ElementViewTemplate; - -// @public -export type PickerOptions = { - anchoredRegion: TemplateElementDependency; - pickerMenu: TemplateElementDependency; - pickerMenuOption: TemplateElementDependency; - pickerList: TemplateElementDependency; - pickerListItem: TemplateElementDependency; - progressRing: TemplateElementDependency; -}; - -// Warning: (ae-incompatible-release-tags) The symbol "pickerTemplate" is marked as @public, but its signature references "FASTPicker" which is marked as @beta -// -// @public -export function pickerTemplate(options: PickerOptions): ElementViewTemplate; - -// @public -export type ProgressOptions = { - indeterminateIndicator1?: StaticallyComposableHTML; - indeterminateIndicator2?: StaticallyComposableHTML; -}; - -// @public -export type ProgressRingOptions = { - indeterminateIndicator?: StaticallyComposableHTML; -}; - -// @public -export function progressRingTemplate(options?: ProgressRingOptions): ElementViewTemplate; - -// @public -export function progressTemplate(options?: ProgressOptions): ElementViewTemplate; - -// @public -export class PropertyStyleSheetBehavior implements HostBehavior { - constructor(propertyName: string, value: any, styles: ElementStyles); - addedCallback(controller: HostController): void; - // @internal - handleChange(source: FASTElement, key: string): void; - removedCallback(controller: HostController): void; -} - -// @public -export interface PropertyTarget { - // (undocumented) - removeProperty(name: string): void; - // (undocumented) - setProperty(name: string, value: string): void; -} - -// @beta -export type ProxyElement = HTMLSelectElement | HTMLTextAreaElement | HTMLInputElement; - -// @public -export type RadioControl = Pick; - -// @public -export const RadioGroupOrientation: { - readonly horizontal: "horizontal"; - readonly vertical: "vertical"; -}; - -// @public -export type RadioGroupOrientation = ValuesOf; - -// @public -export function radioGroupTemplate(): ElementViewTemplate; - -// @public -export type RadioOptions = { - checkedIndicator?: StaticallyComposableHTML; -}; - -// @public -export function radioTemplate(options?: RadioOptions): ElementViewTemplate; - -// @beta -export function reflectAttributes(...attributes: string[]): CaptureType; - -// Warning: (ae-internal-missing-underscore) The name "roleForMenuItem" should be prefixed with an underscore because the declaration is marked as @internal -// -// @internal (undocumented) -export const roleForMenuItem: { - [value in keyof typeof MenuItemRole]: (typeof MenuItemRole)[value]; -}; - -// @public -export const ScrollEasing: { - readonly linear: "linear"; - readonly easeIn: "ease-in"; - readonly easeOut: "ease-out"; - readonly easeInOut: "ease-in-out"; -}; - -// @public -export type ScrollEasing = ValuesOf; - -// @public -export type SearchOptions = StartEndOptions & { - clearIcon?: StaticallyComposableHTML; -}; - -// @public -export function searchTemplate(options?: SearchOptions): ElementViewTemplate; - -// @public -export type SelectOptions = StartEndOptions & { - indicator?: StaticallyComposableHTML; -}; - -// @public -export function selectTemplate(options?: SelectOptions): ElementViewTemplate; - -// @public -export const SkeletonShape: { - readonly rect: "rect"; - readonly circle: "circle"; -}; - -// @public (undocumented) -export type SkeletonShape = ValuesOf; - -// @public -export function skeletonTemplate(): ElementViewTemplate; - -// @public -export interface SliderConfiguration { - // (undocumented) - direction?: Direction; - // (undocumented) - disabled?: boolean; - // (undocumented) - max: number; - // (undocumented) - min: number; - // (undocumented) - orientation?: SliderOrientation; -} - -// @public -export function sliderLabelTemplate(): ElementViewTemplate; - -// @public -export const SliderMode: { - readonly singleValue: "single-value"; -}; - -// @public -export type SliderMode = ValuesOf; - -// @public -export type SliderOptions = { - thumb?: StaticallyComposableHTML; -}; - -// @public -export const SliderOrientation: { - readonly horizontal: "horizontal"; - readonly vertical: "vertical"; -}; - -// @public -export type SliderOrientation = ValuesOf; - -// @public -export function sliderTemplate(options?: SliderOptions): ElementViewTemplate; - -// @public -export class StartEnd { - // (undocumented) - end: HTMLSlotElement; - // (undocumented) - start: HTMLSlotElement; -} - -// @public -export type StartEndOptions = StartOptions & EndOptions; - -// @public -export type StartOptions = { - start?: StaticallyComposableHTML; -}; - -// @public -export function startSlotTemplate(options: StartOptions): CaptureType; - -// @public -export type StaticallyComposableHTML = string | HTMLDirective | SyntheticViewTemplate | undefined; - -// @public -export function staticallyCompose(item: StaticallyComposableHTML): CaptureType; - -// @public -export type StaticDesignTokenValue = T extends (...args: any[]) => any ? DerivedDesignTokenValue : T; - -// @alpha (undocumented) -export const supportsElementInternals: boolean; - -// @public -export type SwitchOptions = { - thumb?: StaticallyComposableHTML; -}; - -// @public -export function switchTemplate(options?: SwitchOptions): ElementViewTemplate; - -// @public -export type TabOptions = StartEndOptions; - -// @public -export function tabPanelTemplate(): ElementViewTemplate; - -// @public -export type TabsOptions = StartEndOptions; - -// @public -export const TabsOrientation: { - readonly horizontal: "horizontal"; - readonly vertical: "vertical"; -}; - -// @public -export type TabsOrientation = ValuesOf; - -// @public -export function tabsTemplate(options?: TabsOptions): ElementViewTemplate; - -// @public -export function tabTemplate(options?: TabOptions): ElementViewTemplate; - -// @beta -export function tagFor(dependency: TemplateElementDependency): string; - -// @beta -export type TemplateElementDependency = string | FASTElementDefinition | Constructable; - -// @public -export type TextAreaOptions = StartEndOptions; - -// @public -export const TextAreaResize: { - readonly none: "none"; - readonly both: "both"; - readonly horizontal: "horizontal"; - readonly vertical: "vertical"; -}; - -// @public -export type TextAreaResize = ValuesOf; - -// @public -export function textAreaTemplate(options?: TextAreaOptions): ElementViewTemplate; - -// @public -export type TextFieldOptions = StartEndOptions; - -// @public -export function textFieldTemplate(options?: TextFieldOptions): ElementViewTemplate; - -// @public -export const TextFieldType: { - readonly email: "email"; - readonly password: "password"; - readonly tel: "tel"; - readonly text: "text"; - readonly url: "url"; -}; - -// @public -export type TextFieldType = ValuesOf; - -// @public -export type ToolbarOptions = StartEndOptions; - -// @public -export const ToolbarOrientation: { - readonly horizontal: "horizontal"; - readonly vertical: "vertical"; -}; - -// @public -export type ToolbarOrientation = ValuesOf; - -// @public -export function toolbarTemplate(options?: ToolbarOptions): ElementViewTemplate; - -// @public -export const TooltipPlacement: { - readonly bottom: "bottom"; - readonly bottomEnd: "bottom-end"; - readonly bottomStart: "bottom-start"; - readonly left: "left"; - readonly leftEnd: "left-end"; - readonly leftStart: "left-start"; - readonly right: "right"; - readonly rightEnd: "right-end"; - readonly rightStart: "right-start"; - readonly top: "top"; - readonly topEnd: "top-end"; - readonly topStart: "top-start"; -}; - -// @public -export type TooltipPlacement = ValuesOf; - -// @public -export function tooltipTemplate(): ElementViewTemplate; - -// @public -export type TreeItemOptions = StartEndOptions & { - expandCollapseGlyph?: StaticallyComposableHTML; -}; - -// @public -export function treeItemTemplate(options?: TreeItemOptions): ElementViewTemplate; - -// @public -export function treeViewTemplate(): ElementViewTemplate; - -// @public -export type ValuesOf = T[keyof T]; - -// @public -export const VerticalPosition: { - readonly top: "top"; - readonly bottom: "bottom"; - readonly center: "center"; - readonly unset: "unset"; -}; - -// @public -export type VerticalPosition = ValuesOf; - -// @public -export const WeekdayFormat: { - readonly long: "long"; - readonly narrow: "narrow"; - readonly short: "short"; -}; - -// @public -export type WeekdayFormat = ValuesOf; - -// @public -export type WeekdayText = { - text: string; - abbr?: string; -}; - -// @public -export const whitespaceFilter: ElementsFilter; - -// @public -export const YearFormat: { - readonly "2-digit": "2-digit"; - readonly numeric: "numeric"; -}; - -// @public -export type YearFormat = ValuesOf; - -// Warnings were encountered during analysis: -// -// dist/dts/calendar/calendar.d.ts:52:5 - (ae-incompatible-release-tags) The symbol "dataGridCell" is marked as @public, but its signature references "TemplateElementDependency" which is marked as @beta -// dist/dts/calendar/calendar.d.ts:53:5 - (ae-incompatible-release-tags) The symbol "dataGridRow" is marked as @public, but its signature references "TemplateElementDependency" which is marked as @beta -// dist/dts/calendar/calendar.d.ts:54:5 - (ae-incompatible-release-tags) The symbol "dataGrid" is marked as @public, but its signature references "TemplateElementDependency" which is marked as @beta -// dist/dts/data-grid/data-grid-row.template.d.ts:9:5 - (ae-incompatible-release-tags) The symbol "dataGridCell" is marked as @public, but its signature references "TemplateElementDependency" which is marked as @beta -// dist/dts/data-grid/data-grid.template.d.ts:9:5 - (ae-incompatible-release-tags) The symbol "dataGridRow" is marked as @public, but its signature references "TemplateElementDependency" which is marked as @beta -// dist/dts/picker/picker.template.d.ts:9:5 - (ae-incompatible-release-tags) The symbol "anchoredRegion" is marked as @public, but its signature references "TemplateElementDependency" which is marked as @beta -// dist/dts/picker/picker.template.d.ts:10:5 - (ae-incompatible-release-tags) The symbol "pickerMenu" is marked as @public, but its signature references "TemplateElementDependency" which is marked as @beta -// dist/dts/picker/picker.template.d.ts:11:5 - (ae-incompatible-release-tags) The symbol "pickerMenuOption" is marked as @public, but its signature references "TemplateElementDependency" which is marked as @beta -// dist/dts/picker/picker.template.d.ts:12:5 - (ae-incompatible-release-tags) The symbol "pickerList" is marked as @public, but its signature references "TemplateElementDependency" which is marked as @beta -// dist/dts/picker/picker.template.d.ts:13:5 - (ae-incompatible-release-tags) The symbol "pickerListItem" is marked as @public, but its signature references "TemplateElementDependency" which is marked as @beta -// dist/dts/picker/picker.template.d.ts:14:5 - (ae-incompatible-release-tags) The symbol "progressRing" is marked as @public, but its signature references "TemplateElementDependency" which is marked as @beta - -// (No @packageDocumentation comment for this package) - -``` diff --git a/packages/web-components/fast-foundation/docs/integrations/angular.md b/packages/web-components/fast-foundation/docs/integrations/angular.md deleted file mode 100644 index 1b9af2e4b12..00000000000 --- a/packages/web-components/fast-foundation/docs/integrations/angular.md +++ /dev/null @@ -1,155 +0,0 @@ ---- -id: angular -title: Angular -sidebar_label: Angular -custom_edit_url: https://github.com/microsoft/fast/edit/master/packages/web-components/fast-foundation/docs/integrations/angular.md -description: FAST integrates nicely with Angular. Let's take a look at how you can set up an Angular project, starting from scratch. ---- - -FAST integrates nicely with Angular. Let's take a look at how you can set up an Angular project, starting from scratch. - -## Setting up the Angular project - -First, you'll need to make sure that you have Node.js installed. You can learn more and download that [on the official site](https://nodejs.org/). - -With Node.js installed, you can run the following command to install the Angular CLI: - -```shell -npm install -g @angular/cli -``` - -With the CLI installed, you have access to the `ng` command-line interface. This can be used to create a new Angular project. For example, to create a new Angular App named "fast-angular", you would use the following command: - -```shell -ng new fast-angular -``` - -Follow the prompts, answering each question in turn. When the CLI completes, you should have a basic runnable Angular application. - -## Configuring packages - -Next, we'll install the FAST packages, along with supporting libraries. To do that, run this command from your new project folder: - -```shell -npm install --save @microsoft/fast-components @microsoft/fast-element -``` - -## Using the components - -With all the basic pieces in place, let's run our app in dev mode with `ng serve --open`. The Angular CLI should build your project and make it available on localhost. Right now, it displays a basic welcome message, since we haven't added any code or interesting HTML. Let's change that. - -First, open your `src/main.ts` file and add the following code: - -```ts -import { - provideFASTDesignSystem, - fastCard, - fastButton, - fastTextField -} from '@microsoft/fast-components'; - -provideFASTDesignSystem() - .register( - fastCard(), - fastButton(), - fastTextField() - ); -``` - -This code uses the FAST Design System to register ``, `` and `` components. Once you save, the dev server will rebuild and refresh your browser. However, you still won't see anything. To get some UI showing up, we need to write some HTML that uses our components. Replace the HTML template in your `app/app.component.html` file with the following markup: - -```html - -

{{title}}

- - Click Me -
-``` - -Replace the code in your `app/app.component.ts` file contents with this: - -```ts -import { Component } from '@angular/core'; - -@Component({ - selector: 'app-root', - templateUrl: './app.component.html', - styleUrls: ['./app.component.css'] -}) -export class AppComponent { - title = 'fast-angular'; - - exampleTextField = ''; - - onClick() { - console.log(this.exampleTextField); - } -} -``` - -To allow an NgModule to contain Non-Angular element names, add the following code in your `app/app.module.ts` file: - -```ts -import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; - -@NgModule({ - schemas: [ CUSTOM_ELEMENTS_SCHEMA ] -}) -``` - -Moreover the "[(ngModel)]" might give you warnings that "Event can't be assigned to String", this can be fixed by importing FormsModule in the `app/app.module.ts` file like below which contains the above Code too for completeness: -```ts -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; - -import { AppComponent } from './app.component'; -import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; -import { FormsModule } from '@angular/forms'; - -@NgModule({ - declarations: [ - AppComponent - ], - imports: [ - BrowserModule, FormsModule - ], - providers: [], - bootstrap: [AppComponent], - schemas: [ CUSTOM_ELEMENTS_SCHEMA ] - -}) -``` -To add a splash of style, replace the `app/app.component.css` file contents with this: - -```css -fast-card { - padding: 16px; - display: flex; - flex-direction: column; -} - -fast-text-field { - margin-bottom: 12px; -} - -h2 { - font-size: var(--type-ramp-plus-5-font-size); - line-height: var(--type-ramp-plus-5-line-height); -} - -fast-card > fast-button { - align-self: flex-end; -} -``` - -:::note - -Third party controls require a ControlValueAccessor for writing a value and listening to changes on input elements. Add ngDefaultControl attribute to your component to have two-way binding working with FormControlDirective, FormControlName, or NgModel directives: - -::: - -```html - -``` - -Congratulations! You're now set up to use FAST and Angular! diff --git a/packages/web-components/fast-foundation/docs/integrations/aspnet.md b/packages/web-components/fast-foundation/docs/integrations/aspnet.md deleted file mode 100644 index bb778ad0817..00000000000 --- a/packages/web-components/fast-foundation/docs/integrations/aspnet.md +++ /dev/null @@ -1,107 +0,0 @@ ---- -id: aspnet -title: ASP.NET -sidebar_label: ASP.NET -custom_edit_url: https://github.com/microsoft/fast/edit/master/packages/web-components/fast-foundation/docs/integrations/aspnet.md -description: FAST works naturally with ASP.NET server-side development, by simply adding a script tag and using the custom HTML elements. Let's take a look at how to set things up. -keywords: - - asp.net ---- - -FAST works naturally with ASP.NET server-side development, by simply adding a script tag and using the custom HTML elements. Let's take a look at how to set things up. - -## Setting up the ASP.NET project - -First, you'll need to make sure that you have the .NET SDK installed. You can learn more and download that [on the official site](https://dotnet.microsoft.com/download). - -With the SDK installed, you have access to the `dotnet` command-line interface. This can be used to create a new ASP.NET project. For example, to create a new ASP.NET Core MVC Web App named "fast-aspnet", you would use the following command: - -```shell -dotnet new mvc -o fast-aspnet -``` - -Create a project using the command above if you don't already have one. When the CLI completes, you should have a basic runnable ASP.NET Core MVC application. - -## Configuring scripts - -Now that we've got our basic project setup, we need to add our web components script and update ASP.NET accordingly. You can either add the script from our CDN directly, or you can install it with NPM and then add that. - -To add a CDN script for `fast-components` use the following markup: - -```html - -``` - -The markup above always references the latest release of the components. When deploying to production, you will want to ship with a specific version. Here's an example of the markup for that: - -```html - -``` - -The best place to put this is typically in your `_Layout.cshtml` file in the script section at the bottom of the ``. Be sure to use double `@` if you are placing this script in any of the files with `cshtml` extension as compiler will treat it with Razor directive: - -```html - -``` - -If you wish to leverage NPM instead, run the following command: - -```shell -npm install --save @microsoft/fast-components -``` - -You can locate the single file script build in the following location: - -```shell -node_modules/@microsoft/fast-components/dist/fast-components.min.js -``` - -Copy this to your `wwwroot/js` folder and reference it with a script tag as described above. - -Should you wish to go one step further and leverage a client-side bundler, such as Webpack, there is some additional setup to integrate with ASP.NET that is beyond the scope of this tutorial. Basic Webpack instructions for FAST can be found [here](./webpack.md). The most important detail with respect to FAST is that you'll want to install a few more packages. Use the following command if this is your preferred setup: - -```shell -npm install --save @microsoft/fast-components @microsoft/fast-element -``` - -In this case, because Webpack can tree-shake unused components, you'll also want to be sure to register the components you want to use somewhere in your own JavaScript code. See [our Webpack guide](./webpack.md) for an example. - -## Using the components - -With your script tag added (or your client bundle in place), you can use any component in any of your views. For example, you could put something like this in your `Index.cshtml` file: - -```html -@{ - ViewData["Title"] = "Home Page"; -} - - -

@ViewData["Title"]

- Click Me -
-``` - -For a splash of style, add the following to your `wwwroot/css/site.css` file: - -```css -:not(:defined) { - visibility: hidden; -} - -fast-card { - padding: 16px; - display: flex; - flex-direction: column; -} - -h2 { - font-size: var(--type-ramp-plus-5-font-size); - line-height: var(--type-ramp-plus-5-line-height); -} - -#button { - align-self: flex-end; -} -``` - -Congratulations! You're now set up to use FAST with ASP.NET. You can use more components, build your own components, and when you are ready, build and deploy your website or app to production. diff --git a/packages/web-components/fast-foundation/docs/integrations/aurelia.md b/packages/web-components/fast-foundation/docs/integrations/aurelia.md deleted file mode 100644 index 93acc38d3f9..00000000000 --- a/packages/web-components/fast-foundation/docs/integrations/aurelia.md +++ /dev/null @@ -1,312 +0,0 @@ ---- -id: aurelia -title: Aurelia -sidebar_label: Aurelia -custom_edit_url: https://github.com/microsoft/fast/edit/master/packages/web-components/fast-foundation/docs/integrations/aurelia.md -description: FAST works flawlessly with both Aurelia 1 and Aurelia 2, with full integration into the binding engine and component model. Let's take a look at how you can set up an Aurelia project, starting from scratch. -keywords: - - aurelia ---- - -FAST works flawlessly with both Aurelia 1 and Aurelia 2, with full integration into the binding engine and component model. Let's take a look at how you can set up an Aurelia project, starting from scratch. - -## Aurelia 2 - -### Setting up the Aurelia 2 project - -First, you'll need to make sure that you have Node.js installed. You can learn more and download that [on the official site](https://nodejs.org/). - -With Node.js installed, you can run the following command to create a new Aurelia 2 project: - -```shell -npx makes Aurelia -``` - -Follow the prompts, answering each question in turn. It is recommended that you select the "Default TypeScript Aurelia 2 App" when prompted unless you have previous experience with the CLI. Be sure to choose to install dependencies when asked. - -When the CLI completes, you should have a basic runnable Aurelia 2 application. - -### Configuring packages - -Next, we'll install the FAST packages, along with supporting libraries. To do that, run this command from your new project folder: - -```shell -npm install --save @microsoft/fast-components @microsoft/fast-element -``` - -### Using the components - -With all the basic pieces in place, let's run our app in dev mode with `npm start`. Webpack should build your project and open your default browser with your `index.html` page. Right now, it should only have a hello message, since we haven't added any code or interesting HTML. Let's change that. - -First, open your `src/main.ts` file and add the following code: - -```ts -import { - provideFASTDesignSystem, - fastCard, - fastButton -} from '@microsoft/fast-components'; - -provideFASTDesignSystem() - .register( - fastCard(), - fastButton() - ); -``` - -This code uses the FAST Design System to register the `` and `` components. Once you save, the dev server will rebuild and refresh your browser. However, you still won't see anything. To get some UI showing up, we need to write some HTML that uses our components. Replace your `my-app.html` file with the following markup: - -```html - -

${message}

- Click Me -
-``` - -Replace your `my-app.ts` with this: - -```ts -export class MyApp { - public message = 'Hello World!'; - - onClick() { - console.log('clicked!'); - } -} -``` - -To add a splash of style, replace your `my-app.css` content with this: - -```css -fast-card { - padding: 16px; - display: flex; - flex-direction: column; -} - -h2 { - font-size: var(--type-ramp-plus-5-font-size); - line-height: var(--type-ramp-plus-5-line-height); -} - -fast-card > fast-button { - align-self: flex-end; -} -``` - -### Enabling two-way bindings - -Aurelia knows by default how to listen for changes in native elements. Now we need to teach it how to listen for changes in FAST elements. You can do so by [extending its templating syntax](https://docs.aurelia.io/examples/integration/ms-fast). - -You can either use a [wrapper](https://www.npmjs.com/package/aurelia-fast-adapter) developed by the community or teach Aurelia manually: - -### Import and register `aurelia-fast-adapter` - -Start by installing the adapter - -```ts -npm install aurelia-fast-adapter -``` - -and then simply register it from your `src/main.ts`: - -```ts -// src/main.ts - -import { FASTAdapter } from 'aurelia-fast-adapter'; - -Aurelia - .register(FASTAdapter) // add this line - // other registrations... - .start(); -``` - -If you use FAST in its default configuration that's all you need to do. But if you changed the prefix of your components to something else, you can customize the adapter as such: - -```ts -// src/main.ts - -import { FASTAdapter } from 'aurelia-fast-adapter'; - -Aurelia - .register(FASTAdapter.customize({withPrefix: 'my-custom-prefix'}) // customized with prefix - .start(); -``` - -Also, in case you have local components that require two-way binding, you can adjust the adapter before to register it as such: - -```ts -// src/main.ts - -import { FASTAdapter } from 'aurelia-fast-adapter'; - -// this line will tell the adapter that it must use two-way binding on the component and use this two-way binding on the `value` property. It's possible to add several properties at once if necessary -FASTAdapter.tags['DATE-FIELD'] = ['value']; - -Aurelia - .register(FASTAdapter.customize({withPrefix: 'my-custom-prefix'}) - .start(); -``` - -Congratulations! You're now set up to use FAST and Aurelia 2! - -### Manually teach Aurelia 2 about two-way binding: - -If the example doesn't seem obvious, the following prerequisite reads are recommended: - -* [extending Aurelia templating syntax](https://docs.aurelia.io/app-basics/extending-templating-syntax) - -The following is a code example of how to teach Aurelia to work seamlessly with Microsoft FAST. - -```typescript -import { AppTask, IContainer, IAttrMapper, NodeObserverLocator } from 'aurelia'; - -Aurelia.register(AppTask.beforeCreate(IContainer, container => { - const attrMapper = container.get(IAttrMapper); - const nodeObserverLocator = container.get(NodeObserverLocator); - attrMapper.useTwoWay((el, property) => { - switch (el.tagName) { - case 'FAST-SLIDER': - case 'FAST-TEXT-FIELD': - case 'FAST-TEXT-AREA': - return property === 'value'; - case 'FAST-CHECKBOX': - case 'FAST-RADIO': - case 'FAST-RADIO-GROUP': - case 'FAST-SWITCH': - return property === 'checked'; - case 'FAST-TABS': - return property === 'activeid'; - default: - return false; - } - }); - - // Teach Aurelia what events to use to observe properties of elements. - // Because FAST components all use a single change event to notify, - // we can use a single common object - const valuePropertyConfig = { events: ['input', 'change'] }; - nodeObserverLocator.useConfig({ - 'FAST-CHECKBOX': { - checked: valuePropertyConfig - }, - 'FAST-RADIO': { - checked: valuePropertyConfig - }, - 'FAST-RADIO-GROUP': { - value: valuePropertyConfig - }, - 'FAST-SLIDER': { - value: valuePropertyConfig - }, - 'FAST-SWITCH': { - checked: valuePropertyConfig - }, - 'FAST-TABS': { - activeid: valuePropertyConfig - }, - 'FAST-TEXT-FIELD': { - value: valuePropertyConfig - }, - 'FAST-TEXT-AREA': { - value: valuePropertyConfig - } - }); -})) -``` - -## Aurelia 1 - -### Setting up the Aurelia 1 project - -First, you'll need to make sure that you have Node.js installed. You can learn more and download that [on the official site](https://nodejs.org/). - -With Node.js installed, you can run the following command to install the Aurelia 1 CLI: - -```shell -npm install -g aurelia-cli -``` - -And then use the CLI like this: - -```shell -au new fast-aurelia -``` - -Follow the prompts, answering each question in turn. It is recommended that you select the "Default TypeScript App" when prompted unless you have previous experience with the CLI. Be sure to choose to install dependencies when asked. - -When the CLI completes, you should have a basic runnable Aurelia 1 application. - -### Configuring packages - -Next, we'll install the FAST packages, along with supporting libraries. To do that, run this command from your new project folder: - -```shell -npm install --save @microsoft/fast-components @microsoft/fast-element -``` - -### Using the components - -With all the basic pieces in place, let's run our app in dev mode with `npm start`. Webpack should build your project and make it available at `http://localhost:8080/`. If you visit this address it should only have a hello message, since we haven't added any code or interesting HTML. Let's change that. - -First, open your `src/main.ts` file and add the following code: - -```ts -import { - provideFASTDesignSystem, - fastCard, - fastButton -} from '@microsoft/fast-components'; - -provideFASTDesignSystem() - .register( - fastCard(), - fastButton() - ); -``` - -This code uses the FAST Design System to register the `` and `` components. Once you save, the dev server will rebuild and refresh your browser. However, you still won't see anything. To get some UI showing up, we need to write some HTML that uses our components. Replace your `app.html` file with the following markup: - -```html - -``` - -Replace your `app.ts` with this: - -```ts -export class App { - public message: string = 'Hello World!'; - - onClick() { - console.log('clicked!'); - } -} -``` - -To add a splash of style, add the following to your `app.html` template: - -```html - -``` - -Congratulations! You're now set up to use FAST and Aurelia 1! diff --git a/packages/web-components/fast-foundation/docs/integrations/blazor.md b/packages/web-components/fast-foundation/docs/integrations/blazor.md deleted file mode 100644 index c6bca1b1ff0..00000000000 --- a/packages/web-components/fast-foundation/docs/integrations/blazor.md +++ /dev/null @@ -1,291 +0,0 @@ ---- -id: blazor -title: Blazor -sidebar_label: Blazor -custom_edit_url: https://github.com/microsoft/fast/edit/master/packages/web-components/fast-foundation/docs/integrations/blazor.md -description: FAST works seamlessly with Blazor, including integration with Blazor's binding engine and components. Let's take a look at how to set things up. -keywords: - - blazor ---- - -FAST works seamlessly with Blazor, including integration with Blazor's binding engine and components. Let's take a look at how to set things up. - -## Setting up the Blazor project - -First, you'll need to make sure that you have the .NET SDK installed. You can learn more and download that [on the official site](https://dotnet.microsoft.com/download). - -With the SDK installed, you have access to the `dotnet` command-line interface. This can be used to create a new Blazor project. For example, to create a new Blazor App named "fast-blazor", you would use the following command: - -```shell -dotnet new blazorwasm -o fast-blazor -``` - -Create a project using the command above if you don't already have one. When the CLI completes, you should have a basic runnable Blazor application. For more information on setting up and using Blazor, [see the official Blazor Getting Started guide](https://docs.microsoft.com/en-us/aspnet/core/blazor/get-started). - -## Getting Started with the FluentUI Web Components - -FAST has special Blazor support for Microsoft's FluentUI Web Components. To get started using the Fluent UI Web Components for Blazor, you will first need to install [the official Nuget package for Fluent UI](https://www.nuget.org/packages/Microsoft.Fast.Components.FluentUI/). You can use the following command: - -```shell -dotnet add package Microsoft.Fast.Components.FluentUI -``` - -Next, you need to add the web components script. You can either add the script from CDN directly, or you can install it with NPM, whichever you prefer. - -To add the script from CDN use the following markup: - -```html - -``` - -The markup above always references the latest release of the components. When deploying to production, you will want to ship with a specific version. Here's an example of the markup for that: - -```html - -``` - -The best place to put the script tag is typically in your index.html file in the script section at the bottom of the ``. - -If you wish to leverage NPM instead, run the following command: - -```html -npm install --save @fluentui/web-components -``` - -You can locate the single file script build in the following location: - -```html -node_modules/@fluentui/web-components/dist/web-components.min.js -``` - -Copy this to your `wwwroot/script` folder and reference it with a script tag as described above. - -:::note - -If you are setting up Fluent UI Web Components on a Blazor Server project, you will need to escape the `@` character by repeating it in the source link. For more information check out the [Razor Pages syntax documentation](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/razor?view=aspnetcore-6.0). - -::: - -### Using the FluentUI Web Components - -With the package installed and the script configured, you can begin using the Fluent UI Web Components in the same way as any other Blazor component. Just be sure to add the following using statement to your views: - -```html -@using Microsoft.Fast.Components.FluentUI -``` - -Here's a small example of a `FluentCard` with a `FluentButton` that uses the Fluent "Accent" appearance: - -```html -@using Microsoft.Fast.Components.FluentUI - - -

Hello World!

- Click Me -
-``` - -:::tip - -You can add `@using Microsoft.Fast.Components.FluentUI` to the namespace collection in `_Imports.razor`, so that you can avoid repeating it in every single razor page. - -::: - -If you are using the .NET CLI, you can run your project with the following command from the project folder: - -```shell -dotnet watch run -``` - -Congratulations! You're now set up to use the Fluent UI Web Components with Blazor! -### Configuring the Design System - -The Fluent UI Web Components are built on FAST's Adaptive UI technology, which enables design customization and personalization, while automatically maintaining accessibility. This is accomplished through setting various "Design Tokens". As of version 1.4 you can use all of the (160) individual Design Tokens, both from code as in a declarative way in your `.razor` pages. See https://docs.microsoft.com/en-us/fluent-ui/web-components/design-system/design-tokens for more information on how Design Tokens work - -#### Option 1: Using Design Tokens from C# code - -Given the following `.razor` page fragment: -```html -A button -Another button -And one more -Last button - -``` -You can use Design Tokens to manipulate the styles from C# code as follows: - -```csharp -[Inject] -private BaseLayerLuminance BaseLayerLuminance { get; set; } = default!; - -[Inject] -private AccentBaseColor AccentBaseColor { get; set; } = default!; - -[Inject] -private BodyFont BodyFont { get; set; } = default!; - -[Inject] -private StrokeWidth StrokeWidth { get; set; } = default!; - -[Inject] -private ControlCornerRadius ControlCornerRadius { get; set; } = default!; - -private FluentButton? ref1; -private FluentButton? ref2; -private FluentButton? ref3; -private FluentButton? ref4; - -protected override async Task OnAfterRenderAsync(bool firstRender) -{ - if (firstRender) - { - //Set to dark mode - await BaseLayerLuminance.SetValueFor(ref1!.Element, (float)0.15); - - //Set to Excel color - await AccentBaseColor.SetValueFor(ref2!.Element, "#185ABD".ToColor()); - - //Set the font - await BodyFont.SetValueFor(ref3!.Element, "Comic Sans MS"); - - //Set 'border' width for ref4 - await StrokeWidth.SetValueFor(ref4!.Element, 7); - //And change conrner radius as well - await ControlCornerRadius.SetValueFor(ref4!.Element, 15); - - StateHasChanged(); - } - -} - -public async Task OnClick() -{ - //Remove the wide border - await StrokeWidth.DeleteValueFor(ref4!.Element); -} -``` -As can be seen in the code above (with the `ref4.Element`), it is posible to apply multiple tokens to the same component. - -For Design Tokens that work with a color value, it is needed to add the `ToColor()` extension method on the string value. This converts the string into a RGB value that the Design Token can operate with. Internally we are using the `System.Drawing.Color` struct for this and this means you can use all the available methods, operators, etc from that namespace in your code too. - -:::important - -The Design Tokens are manipulated through JavaScript interop working with an `ElementReference`. There is no JavaScript element until after the component is rendered. This means you can only work with the Design Tokens from code after the component has been rendered in `OnAfterRenderAsync` and not in any earlier lifecycle methods. - -::: - -#### Option 2: Using Design Tokens as components -The Design Tokens can also be used as components in a `.razor` page directely. It looks like this: - -```html - - -
- Dark - Accent - Stealth - Outline - Lightweight -
-
-
-``` - -To make this work, a link needs to be created between the Design Token component and its child components. This is done with the `BackReference="@context"` construct. - -:::note - -Only one Design Token component at a time can be used this way. If you need to set more tokens, use the code approach as described in Option 1 above. - -::: - - -#### Option 3: Using the `` -The third way to customize the design in Blazor is to wrap the entire block you want to manipulate in a ``. This special element has a number of properties you can set to configure a subset of the tokens. **Not all tokens are available/supported** and we recommend this to only be used as a fall-back mechanism. The preferred mehod of working with the desgn tokens is to manipulate them from code as described in option 1. - -Here's an example of changing the "accent base color" and switching the system into dark mode (in the file `app.razor`): - -```html - - - - - - - Not found - -

Sorry, there's nothing at this address.

-
-
-
-
-``` - -:::note - -Provider token attributes can be changed on-the-fly like any other Blazor component attribute. - -::: - -#### Colors for integration with specific Microsoft products -If you are attempting to configure the components for integration into a specific Microsoft product, the following table provides `AccentBaseColor` values you can use: - -Product | AccentBaseColor -------- | --------------- -| Office | #D83B01 | -| Word | #185ABD | -| Excel | #107C41 | -| PowerPoint | #C43E1C | -| Teams | #6264A7 | -| OneNote | #7719AA | -| SharePoint | #03787C | -| Stream | #BC1948 | - -For a list of all available token attributes, [see here](https://github.com/microsoft/fast-blazor/blob/main/src/Microsoft.Fast.Components.FluentUI/Components/FluentDesignSystemProvider.razor#L69). More examples for other components can be found in the `examples` folder [of this repository](https://github.com/microsoft/fast-blazor). - -## Web components / Blazor components mapping, implementation status and remarks -Web component | Blazor component | Status | Remarks ------------------ | -------------- | ------ | ------- -|[``](https://docs.microsoft.com/en-us/fluent-ui/web-components/components/accordion)|``|✔️|-| -|``|``|✔️|-| -|[``](https://docs.microsoft.com/en-us/fluent-ui/web-components/components/anchor)|``|✔️|-| -|[``](https://docs.microsoft.com/en-us/fluent-ui/web-components/components/anchored-region)|``|✔️|-| -|[``](https://docs.microsoft.com/en-us/fluent-ui/web-components/components/badge)|``|✔️|-| -|[``](https://docs.microsoft.com/en-us/fluent-ui/web-components/components/breadcrumb)|``|✔️|-| -|``|``|✔️|-| -|[``](https://docs.microsoft.com/en-us/fluent-ui/web-components/components/button)|``|✔️|-| -|[``](https://docs.microsoft.com/en-us/fluent-ui/web-components/components/card)|``|✔️|-| -|[``](https://docs.microsoft.com/en-us/fluent-ui/web-components/components/checkbox)|``|✔️|-| -|[``](https://docs.microsoft.com/en-us/fluent-ui/web-components/components/combobox)|``|✔️|-| -|[``](https://docs.microsoft.com/en-us/fluent-ui/web-components/components/data-grid)|``|✔️|-| -|``|``|✔️|-| -|``|``|✔️|-| -|[``](https://docs.microsoft.com/en-us/fluent-ui/web-components/components/provider)|``|✔️|-| -|[``](https://docs.microsoft.com/en-us/fluent-ui/web-components/components/dialog)|``|✔️|-| -|[``](https://docs.microsoft.com/en-us/fluent-ui/web-components/components/divider)|``|✔️|-| -|[``](https://docs.microsoft.com/en-us/fluent-ui/web-components/components/flipper)|``|✔️|-| -|[``](https://docs.microsoft.com/en-us/fluent-ui/web-components/components/horizontal-scroll)|``|✔️|-| -|No web component|``|✔️|-| -|[``](https://docs.microsoft.com/en-us/fluent-ui/web-components/components/listbox)|``|✔️|-| -|[``](https://docs.microsoft.com/en-us/fluent-ui/web-components/components/menu)|``|✔️|-| -|``|``|✔️|-| -|[``](https://docs.microsoft.com/en-us/fluent-ui/web-components/components/number-field)|``|✔️|-| -|``|``|✔️|-| -|[``](https://docs.microsoft.com/en-us/fluent-ui/web-components/components/progress)|``|✔️|-| -|[``](https://docs.microsoft.com/en-us/fluent-ui/web-components/components/progress-ring)|``|✔️|-| -|[``](https://docs.microsoft.com/en-us/fluent-ui/web-components/components/radio-group)|``|✔️|-| -|[``](https://docs.microsoft.com/en-us/fluent-ui/web-components/components/radio-group)|``|✔️|-| -|[``](https://docs.microsoft.com/en-us/fluent-ui/web-components/components/select)|``|✔️|-| -|[``](https://docs.microsoft.com/en-us/fluent-ui/web-components/components/skeleton)|``|✔️|-| -|[``](https://docs.microsoft.com/en-us/fluent-ui/web-components/components/slider)|``|✔️|-| -|``|``|✔️|-| -|[``](https://docs.microsoft.com/en-us/fluent-ui/web-components/components/switch)|``|✔️|-| -|[``](https://docs.microsoft.com/en-us/fluent-ui/web-components/components/tabs)|``|✔️|-| -|``|``|✔️|-| -|``|``|✔️|-| -|[``](https://docs.microsoft.com/en-us/fluent-ui/web-components/components/text-area)|``|✔️|-| -|[``](https://docs.microsoft.com/en-us/fluent-ui/web-components/components/text-field)|``|✔️|-| -|[``](https://docs.microsoft.com/en-us/fluent-ui/web-components/components/toolbar)|``|✔️|-| -|[``](https://docs.microsoft.com/en-us/fluent-ui/web-components/components/tooltip)|``|✔️|-| -|[``](https://docs.microsoft.com/en-us/fluent-ui/web-components/components/tree-view)|``|✔️|-| -|``|``|✔️|-| diff --git a/packages/web-components/fast-foundation/docs/integrations/ember.md b/packages/web-components/fast-foundation/docs/integrations/ember.md deleted file mode 100644 index d4f4d2ac9cf..00000000000 --- a/packages/web-components/fast-foundation/docs/integrations/ember.md +++ /dev/null @@ -1,124 +0,0 @@ ---- -id: ember -title: Ember -sidebar_label: Ember -custom_edit_url: https://github.com/microsoft/fast/edit/master/packages/web-components/fast-foundation/docs/integrations/ember.md -description: FAST and Ember work great together. Let's take a look at how you can set up an Ember project, starting from scratch. -keywords: - - ember ---- - -FAST and Ember work great together. Let's take a look at how you can set up an Ember project, starting from scratch. - -## Setting up the Ember project - -First, you'll need to make sure that you have Node.js installed. You can learn more and download that [on the official site](https://nodejs.org/). - -With Node.js installed, you can run the following command to install the Ember CLI: - -```shell -npm install -g ember-cli -``` - -With the CLI installed, you have access to the `ember` command-line interface. This can be used to create a new Ember project. For example, to create a new Ember App named "fast-ember", you would use the following command: - -```shell -ember new fast-ember --lang en -``` - -When the CLI completes, you should have a basic runnable Ember application. - -## Configuring packages - -Next, we'll install the FAST packages, along with supporting libraries. To do that, run this command from your new project folder: - -```shell -npm install --save @microsoft/fast-components @microsoft/fast-element -``` - -## Using the components - -With all the basic pieces in place, let's run our app with `npm start`. The Ember CLI should build your project and make it available on localhost. Right now, it displays a basic welcome message, since we haven't added any code or interesting HTML. Let's change that. - -First, open your `app/app.js` file and add the following code: - -```ts -import { - provideFASTDesignSystem, - fastCard, - fastButton, - fastTextField -} from '@microsoft/fast-components'; - -provideFASTDesignSystem() - .register( - fastCard(), - fastButton(), - fastTextField() - ); -``` - -This code uses the FAST Design System to register ``, `` and `` components. Once you save, the dev server will rebuild and refresh your browser. However, you still won't see anything. Open your `application.hbs` file and replace the `` component with the following HTML and then save again. - -```html - -

FAST Ember

- - Click Me -
-``` - -Now you should see the FAST web components displayed in your Ember application. - -Next, let's improve this by refactoring this code into a component. Stop the CLI and run the following command to scaffold an Ember component. - -```shell -ember generate component fast-demo -``` - -Copy the the HTML above and use it to replace the HTML in your `app/components/fast-demo.hbs` file. Next replace the same HTML in your `templates/application.hbs` file with the following Ember component use: - -```html - -``` - -Run `npm start` again and you should see the same output, but now we have moved our web components into a `FastDemo` Ember component. - -Let's go a little further. Create a `fast-demo.js` file in the same folder as your `fast-demo.hbs` file and paste the following code: - -```js -import Component from '@glimmer/component'; -import { action } from '@ember/object'; -import { tracked } from '@glimmer/tracking'; - -export default class FastDemoComponent extends Component { - @tracked exampleTextField = ''; - - @action - onClick() { - console.log(this.exampleTextField); - } - - @action - onInput(event) { - this.exampleTextField = event.target.value; - } -} -``` - -Next, update the `fast-demo.hbs` file with the following HTML: - -```html - -

FAST Ember

- - Click Me -
-``` - -With this code in place, you now have FAST Web Components fully binding to data and handling user interactions, all from inside an Ember component. - -Congratulations! You're now set up to use FAST and Ember! diff --git a/packages/web-components/fast-foundation/docs/integrations/introduction.md b/packages/web-components/fast-foundation/docs/integrations/introduction.md deleted file mode 100644 index 14f1f51492d..00000000000 --- a/packages/web-components/fast-foundation/docs/integrations/introduction.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -id: introduction -title: Introduction -sidebar_label: Introduction -custom_edit_url: https://github.com/microsoft/fast/edit/master/packages/web-components/fast-foundation/docs/integrations/introduction.md -description: The integrations section of our documentation is dedicated to helping you get FAST Element working with your existing or preferred stack. ---- - -FAST libraries can be used on their own to build modern web sites and applications, but they are also designed to be used in combination with a wide variety of existing technologies. The integrations section of our documentation is dedicated to helping you get FAST Element working with your existing or preferred stack. - -:::note -Not seeing an integration for your preferred technology? We'd be happy to work with you to add it. Feel free to kick off a discussion by [opening an issue on GitHub](https://github.com/microsoft/fast/issues). -::: \ No newline at end of file diff --git a/packages/web-components/fast-foundation/docs/integrations/react.md b/packages/web-components/fast-foundation/docs/integrations/react.md deleted file mode 100644 index 35588731d90..00000000000 --- a/packages/web-components/fast-foundation/docs/integrations/react.md +++ /dev/null @@ -1,313 +0,0 @@ ---- -id: react -title: React -sidebar_label: React -custom_edit_url: https://github.com/microsoft/fast/edit/master/packages/web-components/fast-foundation/docs/integrations/react.md -description: FAST can be used in React applications. We recommend using it with the TypeScript template. Let's take a look at how you can set up a project, starting from scratch. ---- - -FAST can be used in React applications. We recommend using it with the TypeScript template. Let's take a look at how you can set up a project, starting from scratch. - -## Setting up the React project - -First, you'll need to make sure that you have Node.js >= 8.2 and npm >= 5.6 installed. You can learn more and download that [on the official site](https://nodejs.org/). - -With Node.js installed, you can use [create-react-app](https://reactjs.org/docs/create-a-new-react-app.html#create-react-app) to create a new React project. - -```shell -npx create-react-app fast-app --template typescript -``` - -> It is recommended to set up the create-react-app project with TypeScript. - -## Configuring packages - -Next, we'll install the FAST packages, along with supporting libraries. To do that, run this command from your new project folder: - -```shell -npm install --save @microsoft/fast-components @microsoft/fast-foundation @microsoft/fast-element @microsoft/fast-react-wrapper -``` - -## Configure create-react-app - -[create-react-app](https://reactjs.org/docs/create-a-new-react-app.html#create-react-app) ships with an [eslint](https://eslint.org/) rule that makes working with FAST components difficult. There are two changes that will need to be made in the `package.json`: - -**Set the EXTEND_ESLINT environment variable in start, build, and test scripts** - -```jsonc -// package.json -{ - //... - "scripts": { - "start": "EXTEND_ESLINT=true react-scripts start", - "build": "EXTEND_ESLINT=true react-scripts build", - "test": "EXTEND_ESLINT=true react-scripts test" - } - // ... -} -``` - -> The above will not work on Windows. You can adjust the scripts to use [cross-env](https://www.npmjs.com/package/cross-env) to add Windows support. - -**Override the `eslintConfig` field to turn off the 'no-unused-expressions' rule** - -```jsonc -// package.json -{ - //.. - "eslintConfig": { - "extends": "react-app", - "rules": { - "no-unused-expressions": "off" - } - } - //.. -} -``` - -See [configuring eslint](https://create-react-app.dev/docs/setting-up-your-editor#experimental-extending-the-eslint-config) for more information. - -Next, be sure to update the TypeScript config file. - -**Set 'experimentalDecorators' to true in the `tsconfig.json` file** - -> When using decorators in a new create-react-app setup with TypeScript, you'll most likely see the warning `Support for the experimental syntax 'decorators-legacy' isn't currently enabled`. Configuring tsconfig will remove this warning. - -```jsonc -// tsconfig.json -{ - "compilerOptions": { - "experimentalDecorators": true, - //.. -} -``` - -## Using the components - -With all the basic pieces in place, let's run our app in dev mode with `npm start`. Right now, it displays the React logo and some editing instructions, since we haven't added any code or interesting HTML. Let's change that. - -First, open your `src/app.js` file and add the following code: - -```js -import { - provideFASTDesignSystem, - fastCard, - fastButton, -} from "@microsoft/fast-components"; -import { provideReactWrapper } from "@microsoft/fast-react-wrapper"; -import React from "react"; - -const { wrap } = provideReactWrapper(React, provideFASTDesignSystem()); - -export const FastCard = wrap(fastCard()); -export const FastButton = wrap(fastButton()); -``` - -This code uses the FAST Design System to register the `` and `` components while automatically wrapping them into React components. Once you save, the dev server will rebuild and refresh your browser. However, you still won't see anything. To get some UI showing up, we need to write some HTML that uses our components. Replace the App component in your `src/app.js` file with the following: - -```jsx -function App() { - return ( - -

FAST React

- console.log("clicked")}> - Click Me - -
- ); -} -``` - -To add a splash of style, add the following to the `src/App.css`: - -```css -fast-card { - padding: 16px; - display: flex; - flex-direction: column; -} - -h2 { - font-size: var(--type-ramp-plus-5-font-size); - line-height: var(--type-ramp-plus-5-line-height); -} - -fast-card > fast-button { - align-self: flex-end; -} -``` - -Congratulations! You're now set up to use FAST and React! - -## Using the React Wrapper - -Above, we leveraged the `@microsoft/fast-react-wrapper` library to enable seamless integration of FAST Components. There are a few additional ways to use this API for different web component scenarios. - -### Wrapping Design System Components - -Previously, you've seen that we can wrap a Design System component by passing its registration function to the `wrap` method as follows: - -```ts -const { wrap } = provideReactWrapper(React, provideFASTDesignSystem()); - -export const FastButton = wrap(fastButton()); -``` - -This code creates a wrapper that is configured with a React-compatible API and a Design System instance. When passing a Design System as the second parameter, you can then pass component registration functions to the `wrap` helper. The helper will both register the web component with the Design System and wrap it in a type-safe React component, all with a single call. - -Alternatively, you can skip providing the Design System to the wrapper, and use the generated registry to manually register all previously wrapped components. - -```ts -const { wrap, registry } = provideReactWrapper(React); - -export const FastButton = wrap(fastButton()); - -provideFASTDesignSystem().register(registry); -``` - -The final option is to handle everything by hand: - -```ts -const { wrap } = provideReactWrapper(React); - -export const FastButton = wrap(fastButton()); - -provideFASTDesignSystem().register(fastButton()); -``` - -### Wrapping FAST Components - -The `wrap` helper can also wrap any FAST Web Component defined using the `@customElement` decorator or by manually calling `FASTElement.define`. To do so, pass the custom element class to the wrapper. - -```ts -import { FASTElement, customElement, html } from '@microsoft/fast-element'; - -@customElement({ - name: 'my-component', - template: html`...`, - styles:... -}) -class _MyComponent extends FASTElement { - -} - -export const MyComponent = provideReactWrapper(React).wrap(_MyComponent); -``` - -### Wrapping VanillaJS Web Components - -If you have a component from a 3rd party library, not written with FAST, or a VanillaJS Web Component, you can wrap that as well. In this scenario you will have to provide some additional information, such as the element name and the list of properties that should be handled by the wrapper rather than React. Components created with libraries like `Lit` require the element name to be configured but not the properties, while some other libraries or hand-written components may also require the property list. This depends on how the component was defined. Below is an example of configuring both the name and the property list. - -```ts -import { CoolComponent as _CoolComponent } from "@cool/component"; - -const { wrap } = provideReactWrapper(React); - -export const CoolComponent = wrap(_CoolComponent, { - name: "cool-component", - properties: ["list", "properties", "here"], -}); -``` - -### Configuring Custom Events - -If the wrapped component uses custom events that you intend to use from React, you will need to manually configure a mapping from React event name to the native event name. Here's an example of what that would look like if you wanted to leverage the FAST MenuItem's `expanded-change` event: - -```ts -const { wrap } = provideReactWrapper(React, provideFASTDesignSystem()); - -export const FastMenuItem = wrap(fastMenuItem(), { - events: { - onExpandedChange: "expanded-change", - }, -}); -``` - -## Working without the fast-react-wrapper - -The `@microsoft/fast-react-wrapper` library described above addresses all the challenges involved in using Web Components from React. We strongly recommend using this library for integration. However, if you cannot use this library or want to explore other options, follow the steps below. - -#### Extend the React.Component - -After creating your custom element, define another class that extends `React.Component`, this will allow you to use your custom element in the _render()_ method. - -```ts -// App.tsx -import { FASTElement, customElement, attr } from "@microsoft/fast-element"; -import { provideFASTDesignSystem } from "@microsoft/fast-components"; - -@customElement("name-tag") -class _NameTag extends FASTElement { - @attr greeting: string = ""; -} - -provideFASTDesignSystem().register(_NameTag); - -class NameTag extends React.Component { - render() { - return ; - } -} - -function App() { - return ( -
- -
- ); -} - -export default App; -``` - -> At this stage, you will get a warning `Property 'name-tag' does not exist on type 'JSX.IntrinsicElements'`. Adding `custom-elements.d.ts` in the following step will remove this warning. - -#### TypeScript and TSX support - -With TypeScript, you'll need to augment the `JSX.IntrinsicElements` interface to use custom elements in TSX. To do so, create a `custom-elements.d.ts` file in your source directory and add the following: - -```ts -// custom-elements.d.ts -declare namespace JSX { - interface IntrinsicElements { - "fast-design-system-provider": React.DetailedHTMLProps< - React.HTMLAttributes, - HTMLElement - > & { - "use-defaults"?: boolean; - }; - "name-tag": React.DetailedHTMLProps< - React.HTMLAttributes, - HTMLElement - > & { - greeting?: string; - }; - } -} -``` - -> Note: The above example works with React version 18.0.0 - -## Additional Notes - -FAST makes use of decorators to define components. At this time, `create-react-app` [does not support decorators](https://create-react-app.dev/docs/can-i-use-decorators/). This won't be a problem when using components _imported_ from FAST because they have already been transpiled by TypeScript - but to _create_ components in a `create-react-app` application, here are some additional ways to work without the fast-react-wrapper: - -- [Creating custom components with Babel](https://fast.design/docs/integrations/webpack#creating-custom-components-with-babel) -- [Define components without decorators](https://fast.design/docs/fast-element/defining-elements#working-without-decorators) -- Use an intermediary like [react-app-rewired](https://www.npmjs.com/package/react-app-rewired) - -You can read more about decorator configuration issues [here.](https://github.com/microsoft/fast/issues/4503) - -#### HTML Attributes - -React is capable of rendering custom HTML elements and binding data to them, but it is beneficial to understand _how_ React does this. React will apply all _props_ to a custom HTML element as _HTML attributes_ - including non-primitive types such as arrays and objects. Where some UI libraries provide binding syntaxes to distinguish setting properties, attributes, and events, React does not. This means that it can be very easy to end up with `my-prop="[object Object]"` in your HTML. React is exploring solutions [in this issue](https://github.com/facebook/react/issues/11347). See the section on [interop layers](#interop-layers-skatejsval-and-reactify-wc) for a work-around for this issue. - -#### Custom events - -React's synthetic eventing system comes with an unfortunate side-effect of being incapable of declaratively applying [`CustomEvent`](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent) listeners. [interop layers](#interop-layers-skatejsval-and-reactify-wc) can be used to address this issue. Alternatively, a `ref` can be used on the custom element to imperatively apply the event listener to the HTML element directly. - -#### Interop layers: @skatejs/val and reactify-wc - -[@skatejs/val](https://github.com/skatejs/val) is a small library that wraps React's `createElement` function and provides the ability direct React _props_ explicitly to HTML attributes, DOM properties, or to declarative event listeners. - -Another good option is [reactify-wc](https://github.com/BBKolton/reactify-wc). It provides similar capabilities as `@skatejs/val` but does so by creating component wrappers. diff --git a/packages/web-components/fast-foundation/docs/integrations/rollup.md b/packages/web-components/fast-foundation/docs/integrations/rollup.md deleted file mode 100644 index a0347836201..00000000000 --- a/packages/web-components/fast-foundation/docs/integrations/rollup.md +++ /dev/null @@ -1,260 +0,0 @@ ---- -id: rollup -title: Rollup -sidebar_label: Rollup -custom_edit_url: https://github.com/microsoft/fast/edit/master/packages/web-components/fast-foundation/docs/integrations/rollup.md -description: FAST works great with Rollup and TypeScript, using a standard setup. Let's take a look at how you can set up a FAST+Rollup+TypeScript project, starting from scratch. -keywords: - - rollup - - typescript ---- - -FAST works great with Rollup and TypeScript, using a standard setup. Let's take a look at how you can set up a FAST+Rollup+TypeScript project, starting from scratch. - -## Setting up the package - -First, let's make a directory for our new project. From the terminal: - -```shell -mkdir fast-rollup -``` - -Next, let's move into that directory, where we'll set up our project: - -```shell -cd fast-rollup -``` - -From here, we'll initialize npm: - -```shell -npm init -``` - -Follow the prompts from npm, answering each question in turn. You can always accept the defaults at first and then make changes later in the `package.json` file. - -Next, we'll install the FAST packages, along with supporting libraries. To do that, run this command: - -```shell -npm install @microsoft/fast-components @microsoft/fast-element tslib --save -``` - -We also need to install the Rollup build tooling: - -```shell -npm install rollup typescript @rollup/plugin-typescript @rollup/plugin-node-resolve rollup-plugin-cleaner rollup-plugin-copy rollup-plugin-serve rollup-plugin-terser --save-dev -``` - -## Adding configuration and source - -Now that we've got our basic package and dependencies set up, let's create some source files and get things configured. Since we're going to be writing a bit of code, now is a great time to involve a code editor in the process. If you're looking for a great editor for TypeScript and front-end in general, we highly recommend [VS Code](https://code.visualstudio.com/). - -Open the `fast-rollup` folder in your favorite editor. You should see your `package.json` along with a `package-lock.json` and a `node_modules` folder. - -First, let's create a `src` folder where we'll put all our TypeScript code. In the `src` folder, add a `main.ts` file. You can leave the file empty for now. We'll come back to it in a bit. - -Then, in the root of your project folder, add a `tsconfig.json` file to configure the TypeScript compiler. Here's an example starter config that you can put into that file: - -```json -{ - "compilerOptions": { - "pretty": true, - "target": "ES2015", - "module": "ES2015", - "moduleResolution": "node", - "importHelpers": true, - "experimentalDecorators": true, - "declaration": true, - "declarationMap": true, - "sourceMap": true, - "noEmitOnError": true, - "strict": true, - "outDir": "dist/build", - "rootDir": "src", - "lib": [ - "dom", - "esnext" - ] - }, - "include": [ - "src" - ] -} -``` - -You can learn more about `tsconfig.json` options in [the official TypeScript documentation](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html). - -:::note -Do not set `useDefineForClassFields` to `true` in your `tsconfig.json` if you are using decorators (e.g. `ExperimentalDecorators`). These two features conflict at present. This will be resolved in future versions of TypeScript and FAST. -::: - -Next, create a `rollup.config.js` file in the root of your project folder with the following source: - -```js -import transformTaggedTemplate from 'rollup-plugin-transform-tagged-template'; -import typescript from '@rollup/plugin-typescript'; -import resolve from '@rollup/plugin-node-resolve'; -import cleaner from 'rollup-plugin-cleaner'; -import copy from 'rollup-plugin-copy'; -import serve from 'rollup-plugin-serve'; -import { terser } from 'rollup-plugin-terser'; - -export default { - input: 'src/main.ts', - output: { - file: 'dist/bundle.js', - name: 'bundle', - format: 'umd', - sourcemap: true - }, - plugins: [ - transformTaggedTemplate({ - tagsToProcess: ['html','css'], - parserOptions: { - sourceType: "module", - plugins: [ - "typescript", - [ - "decorators", - { decoratorsBeforeExport: true } - ] - ] - }, - transformer(data) { - data = data.replace(/\s([{}()>~+=^$:!;])\s/gm, '$1'); - data = data.replace(/([",[]])\s+/gm, '$1'); - data = data.replace(/\s{2,}/gm, ' '); - return data.trim(); - } - }), - typescript(), - resolve(), - cleaner({ - targets: [ - 'dist' - ] - }), - copy({ - targets: [ - { src: 'index.html', dest: 'dist' }, - ] - }), - serve({ - open: true, - contentBase: 'dist' - }), - terser(), - ] -}; -``` - -Let's go over our config file: - -- `input` specifies the entrypoint of our application. -- `output` defines the configuration for the JavaScript bundle that Rollup generates. - - This is the script that gets loaded by our `index.html` file; in our case, it is `bundle.js`. -- `plugins` is where you can add additional functionality to Rollup. - -Let's go over the plugins we're using: -- `transformTaggedTemplate` minifies content within tagged templates (e.g. html and css) -- `typescript` allows us to write our source files in TypeScript. -- `resolve` allows us to import modules installed from npm, like `@microsoft/fast-components`. -- `cleaner` will delete the `dist` folder before rebuilding. - - This ensures `dist` remains up-to-date with our source code. - - Without this plugin, Rollup would only add or overwrite files in the `dist` folder, but never delete them. -- `copy` will copy source files to our `dist` folder, ensuring everything we need for deploying our app is in one place. -- `serve` provides a development server that will open our application in the browser for us. -- `terser` will minify the generated es bundle. - -Let's add some helpful commands to our `package.json` file. Find the `scripts` section of your `package.json` file and add the following lines: - -```json -{ - "scripts": { - "build": "rollup --config", - "dev": "rollup --config --watch" - } -} -``` - -- `npm run build`: running this command in the terminal will build our application into the `dist` folder, allowing us to run it locally or deploy it. - -- `npm run dev`: running this command in the terminal does the same as `build`, except it will keep a process running that rebuilds our app whenever our source files change. Rollup will watch our entrypoint `main.ts` and any files that get imported from there. - -To complete our setup, we need to add an `index.html` file to the root of our project. We'll start with some basic content as follows: - -```html - - - - - FAST Rollup - - - - - -``` - -There's nothing special about the HTML yet, other than the `script` tag in the `body` that references the `bundle.js` file that our Rollup build will produce. - -## Using the components - -With all the basic pieces in place, let's run our app with `npm run build`. - -Rollup should build your project and open your default browser with your `index.html` page. Right now, it should be blank, since we haven't added any code or interesting HTML. Let's change that. - -First, open your `src/main.ts` file and add the following code: - -```ts -import { - provideFASTDesignSystem, - fastCard, - fastButton -} from '@microsoft/fast-components'; - -provideFASTDesignSystem() - .register( - fastCard(), - fastButton() - ); -``` - -This code uses the FAST Design System to register the `` and `` components. To get some UI showing, we need to write some HTML that uses our components. - -Replace the contents of the `` in your `index.html` file with the following markup: - -```html - - -

Hello World!

- Click Me -
- - - -``` - -After saving your `index.html` file, run `npm run build` again, and you should see a card with text and a button. - -Congratulations! You're now set up to use FAST, Rollup, and TypeScript. You can import and use more components, build your own components, and when you are ready, build and deploy your website or app to production. \ No newline at end of file diff --git a/packages/web-components/fast-foundation/docs/integrations/svelte.md b/packages/web-components/fast-foundation/docs/integrations/svelte.md deleted file mode 100644 index f40f9ceed7c..00000000000 --- a/packages/web-components/fast-foundation/docs/integrations/svelte.md +++ /dev/null @@ -1,132 +0,0 @@ ---- -id: svelte -title: Svelte -sidebar_label: Svelte -custom_edit_url: https://github.com/microsoft/fast/edit/master/packages/web-components/fast-foundation/docs/integrations/svelte.md -description: FAST works great with Svelte, Vite, and TypeScript, using a standard setup. Let's take a look at how you can set up a FAST+Svelte+Vite+TypeScript project, starting from scratch. -keywords: - - svelte - - vite - - typescript ---- - -FAST works great with `Svelte`, `Vite`, and `TypeScript`, using a standard setup. Let's take a look at how you can set up a FAST+Svelte+Vite+TypeScript project, starting from scratch. - -## Setting up the Svelte project - -First, you'll need to make sure that you have `Node.js` version >=12.2.0 installed. You can learn more and download that [on the official site](https://nodejs.org/). - -With `Node.js` installed, you can use [create-vite](https://github.com/vitejs/vite/tree/main/packages/create-vite) to scaffold a new Svelte project. - -```shell -npm create vite@latest fast-svelte --template svelte-ts -``` - -Follow the prompts, answering each question in turn. Select `svelte` as the framework and `svelte-ts` as the variant. When the CLI completes, you should have a basic runnable Svelte application. - -Let's move into the project directory, where we'll set up our project. - -```shell -cd fast-svelte -``` - -## Configuring packages - -From your new project folder, run this command to install the FAST packages, along with supporting libraries. - -```shell -npm install --save @microsoft/fast-components @microsoft/fast-foundation @microsoft/fast-element -``` - -## Adding configuration and source - -Now that we have a Svelte project scaffolded, let's get things configured. - -In the root of your project folder, you will see a `tsconfig.js` file. Replace the contents of the file with the following markup: - -```js -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "esnext", - "useDefineForClassFields": false, - "module": "esnext", - "resolveJsonModule": true, - "experimentalDecorators": true, - "baseUrl": ".", - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "isolatedModules": true - }, - "include": ["src/**/*.d.ts", "src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} -``` - -## Using the components - -Open your `main.ts` file and replace the contents of the file with the following code: - -```ts -import App from './App.svelte' - -import { - provideFASTDesignSystem, - fastCard, - fastButton -} from '@microsoft/fast-components'; - -provideFASTDesignSystem() - .register( - fastCard(), - fastButton() - ); - -const app = new App({ - target: document.getElementById('app') -}) - -export default app -``` - -This code uses the FAST Design System to register the `` and `` components. Let's update our App.svelte file to use our components. Replace the contents of the file with the following markup: - -```html -
- -

Hello World!

- Click Me -
- -
- - -``` - -With all the basic pieces in place, let's run our app in dev mode with `npm run dev`. The Svelte CLI should build your project and make it available on localhost. - -Congratulations! You're now set up to use FAST, Svelte, Vite, and TypeScript. You can import and use more components, build your own components, and when you are ready, build and deploy your website or app to production. - -See a FAST+Svelte+Vite+TypeScript starter project [here](https://github.com/microsoft/fast/tree/master/examples/svelte-starters/svelte-fast-typescript-starter). diff --git a/packages/web-components/fast-foundation/docs/integrations/vite.md b/packages/web-components/fast-foundation/docs/integrations/vite.md deleted file mode 100644 index 2344b158a8c..00000000000 --- a/packages/web-components/fast-foundation/docs/integrations/vite.md +++ /dev/null @@ -1,154 +0,0 @@ ---- -id: vite -title: Vite -sidebar_label: Vite -custom_edit_url: https://github.com/microsoft/fast/edit/master/packages/web-components/fast-foundation/docs/integrations/vite.md -description: FAST works great with TypeScript and Vite, using a fairly standard setup. Let's take a look at how you can set up a FAST+Vite+TypeScript project, starting from scratch. -keywords: - - vite ---- - -FAST works great with Vite and TypeScript, using a fairly standard setup. Let's take a look at how you can set up a FAST+TypeScript+Vite project, starting from scratch. - -## Setting up the Vite project - -First, you'll need to make sure that you have Node.js version >=12.2.0 installed. You can learn more and download that [on the official site](https://nodejs.org/). - -With Node.js installed, you can use [create-vite](https://github.com/vitejs/vite/tree/main/packages/create-vite) to scaffold a new Vite project. - -```shell -npm create vite@latest -``` - -Follow the prompts, answering each question in turn. Enter `fast-vite` as the project name, select `vanilla` as the framework, and `vanilla-ts` as the variant. When the CLI completes, you should have a basic runnable Vite application. - -Next, we'll move into the project directory, where we'll set up our project. - -```shell -cd fast-vite -``` - -## Configuring packages - -Let's install the FAST packages, along with supporting libraries. To do that, run this command from your new project folder: - -```shell -npm install --save @microsoft/fast-components @microsoft/fast-foundation @microsoft/fast-element -``` - -## Adding configuration and source - -Now that we have a Vite project scaffolded, let's get things configured. - -In the root of your project folder, you will see a `tsconfig.js` file. Replace the contents of the file with the following markup: - -```js -{ - "compilerOptions": { - "module": "esnext", - "lib": ["es2017", "dom"], - "declaration": true, - "emitDeclarationOnly": true, - "outDir": "./dist", - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noImplicitReturns": true, - "noImplicitAny": false, - "moduleResolution": "node", - "allowSyntheticDefaultImports": true, - "experimentalDecorators": true, - "forceConsistentCasingInFileNames": true, - "useDefineForClassFields": false - }, - "include": ["src/*/.ts"] -} -``` - -Then, create a new file at the root of your project folder called `vite.config.js` and add the following code: - -```js -import { defineConfig } from 'vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - build: { - lib: { - entry: 'src/main.ts', - formats: ['es'] - }, - rollupOptions: { - external: /^@microsoft\/fast-(element|components)/ - } - } -}) -``` -## Using the components - -With all the basic pieces in place, let's run our app in dev mode with `npm run dev`. The Vite CLI should build your project and make it available on localhost. Right now, it displays a basic welcome message since we haven't added any code or interesting HTML. Let's change that. - -First, open your `src/main.ts` file and replace the contents of the file with the following code: - -```ts -import { - provideFASTDesignSystem, - fastCard, - fastButton -} from '@microsoft/fast-components'; - -provideFASTDesignSystem() - .register( - fastCard(), - fastButton() - ); -``` - -This code uses the FAST Design System to register the `` and `` components. Once you save, the dev server will rebuild and refresh your browser. However, you still won't see anything. To get some UI showing up, we need to update the HTML that uses our components. Replace the HTML template at the root of your folder with the following markup: - -```html - - - - - FAST Vite - - - - - -

Hello World!

- Click Me -
- - -``` - -Next, replace the contents of your `src/style.css` file with the following code: - -```css -:not(:defined) { - visibility: hidden; -} - -fast-card { - padding: 16px; - display: flex; - flex-direction: column; -} - -h2 { - color: white; - font-size: var(--type-ramp-plus-5-font-size); - line-height: var(--type-ramp-plus-5-line-height); -} - -fast-card > fast-button { - align-self: flex-end; -} -``` - -After saving your `style.css` file, your browser will automatically refresh and you should see a card with text and a button. - -Congratulations! You're now set up to use FAST, TypeScript, and Vite. You can import and use more components, build your own components, and when you are ready, build and deploy your website or app to production. - -See a FAST+Vite+TypeScript starter project [here](https://github.com/microsoft/fast/tree/master/examples/vite-starters/vite-fast-typescript-starter). diff --git a/packages/web-components/fast-foundation/docs/integrations/vue.md b/packages/web-components/fast-foundation/docs/integrations/vue.md deleted file mode 100644 index 7d853aa6018..00000000000 --- a/packages/web-components/fast-foundation/docs/integrations/vue.md +++ /dev/null @@ -1,111 +0,0 @@ ---- -id: vue -title: Vue -sidebar_label: Vue -custom_edit_url: https://github.com/microsoft/fast/edit/master/packages/web-components/fast-foundation/docs/integrations/vue.md -description: FAST works great with Vue. Let's take a look at how you can set up a Vue project, starting from scratch. -keywords: - - vue ---- - -FAST works great with Vue. Let's take a look at how you can set up a Vue project, starting from scratch. - -## Setting up the Vue project - -First, you'll need to make sure that you have Node.js installed. You can learn more and download that [on the official site](https://nodejs.org/). - -With Node.js installed, you can run the following command to install the Vue CLI: - -```shell -npm install -g @vue/cli -``` - -With the CLI installed, you have access to the `vue` command-line interface. This can be used to create a new Vue project. For example, to create a new Vue App named "fast-vue", you would use the following command: - -```shell -vue create fast-vue -``` - -When prompted to select options, choose "Manually select features". Follow the prompts, answering each question in turn. It is recommended that you select "TypeScript" when prompted. - -When the CLI completes, you should have a basic runnable Vue application. - -## Configuring packages - -Next, we'll install the FAST packages, along with supporting libraries. To do that, run this command from your new project folder: - -```shell -npm install --save @microsoft/fast-components @microsoft/fast-element -``` - -## Using the components - -With all the basic pieces in place, let's run our app in dev mode with `npm run serve`. The Vue CLI should build your project and make it available on localhost. Right now, it displays a basic welcome message, since we haven't added any code or interesting HTML. Let's change that. - -First, open your `src/main.ts` file and add the following code: - -```ts -import { - provideFASTDesignSystem, - fastCard, - fastButton -} from '@microsoft/fast-components'; - -provideFASTDesignSystem() - .register( - fastCard(), - fastButton() - ); -``` - -This code uses the FAST Design System to register the `` and `` components. Once you save, the dev server will rebuild and refresh your browser. However, you still won't see anything. To get some UI showing up, we need to write some HTML that uses our components. Replace the HTML template in your `components/HelloWorld.vue` file with the following markup: - -```html - -``` - -Replace your script tag with this: - -```html - -``` - -To add a splash of style, replace the `style` tag with this: - -```html - -``` - -Congratulations! You're now set up to use FAST and Vue! diff --git a/packages/web-components/fast-foundation/docs/integrations/webpack.md b/packages/web-components/fast-foundation/docs/integrations/webpack.md deleted file mode 100644 index ad004d15a98..00000000000 --- a/packages/web-components/fast-foundation/docs/integrations/webpack.md +++ /dev/null @@ -1,419 +0,0 @@ ---- -id: webpack -title: Webpack -sidebar_label: Webpack -custom_edit_url: https://github.com/microsoft/fast/edit/master/packages/web-components/fast-foundation/docs/integrations/webpack.md -description: FAST works great with TypeScript and Webpack, using a fairly standard setup. Let's take a look at how you can set up a TypeScript+Webpack project, starting from scratch. ---- - -FAST works great with TypeScript and Webpack, using a fairly standard setup. Let's take a look at how you can set up a TypeScript+Webpack project, starting from scratch. -We recommend using TypeScript, but if you are using Babel, skip down to [Setting up the package with Babel](#setting-up-the-package-with-babel) - -## Setting up Webpack - -First, let's make a directory for our new project. From the terminal: - -```shell -mkdir fast-webpack -``` - -Next, let's move into that directory, where we'll set up our project: - -```shell -cd fast-webpack -``` - -From here, we'll initialize npm: - -```shell -npm init -``` - -Follow the prompts from npm, answering each question in turn. You can always accept the defaults at first and then make changes later in the package.json file. - -Next, we'll install the FAST packages, along with supporting libraries. To do that, run this command: - -```shell -npm install --save @microsoft/fast-components @microsoft/fast-element -``` - -We also need to install the Webpack build tooling: - -```shell -npm install --save-dev clean-webpack-plugin webpack webpack-cli webpack-dev-server -``` - -## Setting up the package with TypeScript - -Install TypeScript build tooling: - -```shell -npm install --save-dev ts-loader typescript -``` - -### Adding configuration for TypeScript - -Now that we've got our basic package and dependencies set up, let's create some source files and get things configured. Since we're going to be writing a bit of code, now is a great time to involve a code editor in the process. If you're looking for a great editor for TypeScript and front-end in general, we highly recommend [VS Code](https://code.visualstudio.com/). - -Open the `fast-webpack` folder in your favorite editor. You should see your `package.json` along with a `package-lock.json` and a `node_modules` folder. - -First, let's create a `src` folder where we'll put all our TypeScript code. In the `src` folder, add a `main.ts` file. You can leave the file empty for now. We'll come back to it in a bit. - -Next, in the root of your project folder, add a `tsconfig.json` file to configure the TypeScript compiler. Here's an example starter config that you can put into that file: - -```json -{ - "compilerOptions": { - "pretty": true, - "target": "ES2015", - "module": "ES2015", - "moduleResolution": "node", - "importHelpers": true, - "experimentalDecorators": true, - "declaration": true, - "declarationMap": true, - "sourceMap": true, - "noEmitOnError": true, - "strict": true, - "outDir": "dist/build", - "rootDir": "src", - "lib": ["dom", "esnext"] - }, - "include": ["src"] -} -``` - -You can learn more about `tsconfig.json` options in [the official TypeScript documentation](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html). - -:::note -Do not set `useDefineForClassFields` to `true` in your `tsconfig.json` if you are using decorators. These two features conflict at present. This will be resolved in future versions of TypeScript and FAST. -::: - -Next, create a `webpack.config.js` file in the root of your project folder with the following source: - -```js -const { CleanWebpackPlugin } = require("clean-webpack-plugin"); -const path = require("path"); - -module.exports = function (env, { mode }) { - const production = mode === "production"; - return { - mode: production ? "production" : "development", - devtool: production ? "source-map" : "inline-source-map", - entry: { - app: ["./src/main.ts"], - }, - output: { - filename: "bundle.js", - publicPath: "/", - }, - resolve: { - extensions: [".ts", ".js"], - modules: ["src", "node_modules"], - }, - devServer: { - port: 9000, - historyApiFallback: true, - open: !process.env.CI, - devMiddleware: { - writeToDisk: true, - }, - static: { - directory: path.join(__dirname, "./"), - }, - }, - plugins: [new CleanWebpackPlugin()], - module: { - rules: [ - { - test: /\.ts$/i, - use: [ - { - loader: "ts-loader", - }, - ], - exclude: /node_modules/, - }, - ], - }, - }; -}; -``` - -This setup uses `ts-loader` to process TypeScript. It will also enable both a production mode and a development mode that watches your source, recompiling and refreshing your browser as things change. You can read more about Webpack configuration in [the official Webpack documentation](https://webpack.js.org/). - -### Completing the setup - -To enable easy execution of both our production and development builds, let's add some script commands to our `package.json` file. Find the `scripts` section of your `package.json` file and add the following two scripts: - -```json -"scripts": { - "build": "webpack --mode=production", - "dev": "webpack serve" -} -``` - -The `build` script will build your TypeScript for production deployment while the `dev` script will run the development web server so you can write code and see the results in your browser. You can run these scripts with `npm run build` and `npm run dev` respectively. - -To complete our setup, we need to add an `index.html` file to the root of our project. We'll start with some basic content as follows: - -```html - - - - - FAST Webpack - - - - - -``` - -There's nothing special about the HTML yet other than the `script` tag in the `body` that references the `bundle.js` file that our Webpack build will produce. - -### Using the components - -With all the basic pieces in place, let's run our app in dev mode with `npm run dev`. Webpack should build your project and open your default browser with your `index.html` page. Right now, it should be blank, since we haven't added any code or interesting HTML. Let's change that. - -First, open your `src/main.ts` file and add the following code: - -```ts -import { - provideFASTDesignSystem, - fastCard, - fastButton, -} from "@microsoft/fast-components"; - -provideFASTDesignSystem().register(fastCard(), fastButton()); -``` - -This code uses the FAST Design System to register the `` and `` components. Once you save, the dev server will rebuild and refresh your browser. However, you still won't see anything. To get some UI showing up, we need to write some HTML that uses our components. Replace the contents of the `` in your `index.html` file with the following markup: - -```html - - -

Hello World!

- Click Me -
- - - -``` - -After saving your `index.html` file, refresh your browser and you should see a card with text and a button. - -Congratulations! You're now set up to use FAST, TypeScript, and Webpack. You can import and use more components, build your own components, and when you are ready, build and deploy your website or app to production. - -## Setting up the package with Babel - -Follow the steps from [Setting up Webpack](#setting-up-webpack) - -Then, install Babel build tooling: - -```shell -npm install --save-dev babel-loader @babel/preset-env -``` - -### Adding configuration for Babel - -First, let's create a `src` folder. In the `src` folder, add a `main.js` file. - -Next, in the root of your project folder, add a `jsconfig.json` file. Here's an example starter config that you can put into that file: - -```json -{ - "compilerOptions": { - "baseUrl": "./", - "paths": { - "@/*": ["./src/*"] - }, - "allowJs": true, - "experimentalDecorators": true - } -} -``` - -Next, we'll need a `.babelrc.json` file, we don't have one yet, so let's create one in the root directory. We can start with a simple setup: - -```json -{ - "presets": [ - [ - "@babel/preset-env", - { - "targets": { - "browsers": ["last 2 versions", "safari >= 7"] - } - } - ] - ] -} -``` - -Here, by adding `@babel/preset-env` to presets will allow you to use the latest JavaScript features. -Targeting specific browser versions prevents Babel from transpiling too much to support old JavaScript versions, increasing total file size and potentially hurting overall performance. - -Then, create a `webpack.config.js` file in the root of your project folder with the following source: - -```js -const { CleanWebpackPlugin } = require("clean-webpack-plugin"); -const path = require("path"); - -module.exports = function (env, { mode }) { - const production = mode === "production"; - return { - mode: production ? "production" : "development", - devtool: production ? "source-map" : "inline-source-map", - entry: { - app: ["./src/main.js"], - }, - output: { - filename: "bundle.js", - publicPath: "/", - }, - resolve: { - extensions: [".js"], - modules: ["src", "node_modules"], - }, - devServer: { - port: 9000, - historyApiFallback: true, - open: !process.env.CI, - devMiddleware: { - writeToDisk: true, - }, - static: { - directory: path.join(__dirname, "./"), - }, - }, - plugins: [new CleanWebpackPlugin()], - module: { - rules: [ - { - test: /\.js$/i, - use: [ - { - loader: "babel-loader", - }, - ], - exclude: /node_modules/, - }, - ], - }, - }; -}; -``` -This setup uses the `babel-loader` to transpile JavaScript files. - -Finish up the setup by following steps from [Completing the setup](#completing-the-setup). - -Then, try to add some components by following [Using the components](#using-the-components). - -At this point, you should be able to see some FAST components show up! You're now set up to use FAST, Babel, and Webpack. - -### Creating Custom Components with Babel - -Let's take a look at how you can create custom components with Babel. - -First, open your `src/main.js` file and add the following code: - -```js -import { FASTElement, customElement, attr } from "@microsoft/fast-element"; -import { - provideFASTDesignSystem, - fastCard, - fastButton, -} from "@microsoft/fast-components"; - -@customElement("name-tag") -class NameTag extends FASTElement { - @attr greeting = ""; -} - -provideFASTDesignSystem().register(fastCard(), fastButton(), NameTag); -``` - -At this point, when you try to build this piece of code, you will most likely get a error in `src/main.js`" - -> SyntaxError: Support for the experimental syntax 'decorators' isn't currently enabled - -Let's add a babel plugins to help us with this error: - -```shell -npm install --save-dev @babel/plugin-proposal-decorators -``` - -With this plugin installed, we'll need to add it in the `.babelrc.json` file: - -```json -{ - "presets": [ - [ - "@babel/preset-env", - { - "targets": { - "browsers": ["last 2 versions", "safari >= 7"] - } - } - ] - ], - "plugins": [["@babel/plugin-proposal-decorators", { "legacy": true }]] -} -``` - -Adding the `@babel/plugin-proposal-decorators` plugin should fix the syntax error we got earlier. And your Babel application should work with decorators now. - -Let's add our custom component to the `index.html` file: - -```html - - -

Hello World!

- Click Me - -
- - - -``` - -Now, when you inspect the devtools, you should be able to see the `greeting` attribute from `` present with the `hello` property! diff --git a/packages/web-components/fast-foundation/docs/tools/component-explorer.md b/packages/web-components/fast-foundation/docs/tools/component-explorer.md deleted file mode 100644 index 8f8f0c43074..00000000000 --- a/packages/web-components/fast-foundation/docs/tools/component-explorer.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -id: component-explorer -title: Component Explorer -sidebar_label: Component Explorer -custom_edit_url: https://github.com/microsoft/fast/edit/master/packages/web-components/fast-foundation/docs/tools/component-explorer.md -description: Launch our Component Explorer to experience our FAST Components and development tools. ---- - -Launch our [Component Explorer](https://explore.fast.design) to experience our [FAST Components](https://www.npmjs.com/package/@microsoft/fast-components) and development tools. \ No newline at end of file diff --git a/packages/web-components/fast-foundation/docs/tools/hot-module-reload.md b/packages/web-components/fast-foundation/docs/tools/hot-module-reload.md deleted file mode 100644 index f6605c8d32e..00000000000 --- a/packages/web-components/fast-foundation/docs/tools/hot-module-reload.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -id: hot-module-reload -title: Hot Module Reload -sidebar_label: Hot Module Reload -custom_edit_url: https://github.com/microsoft/fast/edit/master/packages/web-components/fast-foundation/docs/tools/hot-module-reload.md -description: Hot Module Replacement (HMR) allows your web components to be updated as you develop, without needing a full refresh of the browser. ---- - -Hot Module Replacement (HMR) allows your web components to be updated as you develop, without needing a full refresh of the browser. The [Open Web Components](https://open-wc.org/) project maintains a number of tools and libraries for working with Web Components, including a plugin for enabling HMR with FAST Web Components. - -To learn more about HMR for Web Components and to see how to setup HMR in your own FAST projects, [please see the Open Web Components HMR documentation](https://open-wc.org/docs/development/hot-module-replacement/). - -:::note -HMR is limited in what it can update for a given component. So, full-page refreshes are still needed in certain cases. Changes to constructor logic or adding new `@attr` properties are notable examples of HMR's update limitations. However, template and style changes should be handled automatically without needing a full refresh. -::: \ No newline at end of file diff --git a/packages/web-components/fast-foundation/docs/tools/vscode.md b/packages/web-components/fast-foundation/docs/tools/vscode.md deleted file mode 100644 index 30ef9cbbe1b..00000000000 --- a/packages/web-components/fast-foundation/docs/tools/vscode.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -id: vscode -title: Visual Studio Code -sidebar_label: Visual Studio Code -custom_edit_url: https://github.com/microsoft/fast/edit/master/packages/web-components/fast-foundation/docs/tools/vscode.md -description: You can use any code editor you like when working with FAST. One of our favorites is Visual Studio Code. ---- - -You can use any code editor you like when working with FAST. One of our favorites is [Visual Studio Code](https://code.visualstudio.com/). VS Code has great support for API autocomplete for TypeScript and JavaScript APIs, as well as a rich ecosystem of plugins. - -When working with VS Code, we recommend using these plugins: - -* [FAST Snippets](https://marketplace.visualstudio.com/items?itemName=kingoftac.fast-snippets) to get commonly used conventions when creating `FAST Components`. -* [literally-html](https://marketplace.visualstudio.com/items?itemName=webreflection.literally-html) to get syntax highlighting and documentation in your `html` blocks. -* [es6-string-css](https://marketplace.visualstudio.com/items?itemName=bashmish.es6-string-css) to get syntax highlighting in your `css` blocks. \ No newline at end of file diff --git a/packages/web-components/fast-foundation/package.json b/packages/web-components/fast-foundation/package.json deleted file mode 100644 index fe113c859d6..00000000000 --- a/packages/web-components/fast-foundation/package.json +++ /dev/null @@ -1,282 +0,0 @@ -{ - "name": "@microsoft/fast-foundation", - "description": "A library of Web Component building blocks", - "version": "3.0.0-alpha.33", - "sideEffects": false, - "author": { - "name": "Microsoft", - "url": "https://discord.gg/FcSNfg4" - }, - "homepage": "https://www.fast.design/", - "license": "MIT", - "repository": { - "type": "git", - "url": "git+https://github.com/Microsoft/fast.git", - "directory": "packages/web-components/fast-foundation" - }, - "bugs": { - "url": "https://github.com/Microsoft/fast/issues/new/choose" - }, - "main": "dist/esm/index.js", - "types": "dist/dts/index.d.ts", - "unpkg": "dist/fast-foundation.min.js", - "type": "module", - "exports": { - ".": { - "types": "./dist/dts/index.d.ts", - "default": "./dist/esm/index.js" - }, - "./accordion.js": { - "types": "./dist/dts/accordion/index.d.ts", - "default": "./dist/esm/accordion/index.js" - }, - "./accordion-item.js": { - "types": "./dist/dts/accordion-item/index.d.ts", - "default": "./dist/esm/accordion-item/index.js" - }, - "./anchor.js": { - "types": "./dist/dts/anchor/index.d.ts", - "default": "./dist/esm/anchor/index.js" - }, - "./anchored-region.js": { - "types": "./dist/dts/anchored-region/index.d.ts", - "default": "./dist/esm/anchored-region/index.js" - }, - "./avatar.js": { - "types": "./dist/dts/avatar/index.d.ts", - "default": "./dist/esm/avatar/index.js" - }, - "./badge.js": { - "types": "./dist/dts/badge/index.d.ts", - "default": "./dist/esm/badge/index.js" - }, - "./breadcrumb.js": { - "types": "./dist/dts/breadcrumb/index.d.ts", - "default": "./dist/esm/breadcrumb/index.js" - }, - "./breadcrumb-item.js": { - "types": "./dist/dts/breadcrumb-item/index.d.ts", - "default": "./dist/esm/breadcrumb-item/index.js" - }, - "./button.js": { - "types": "./dist/dts/button/index.d.ts", - "default": "./dist/esm/button/index.js" - }, - "./calendar.js": { - "types": "./dist/dts/calendar/index.d.ts", - "default": "./dist/esm/calendar/index.js" - }, - "./card.js": { - "types": "./dist/dts/card/index.d.ts", - "default": "./dist/esm/card/index.js" - }, - "./checkbox.js": { - "types": "./dist/dts/checkbox/index.d.ts", - "default": "./dist/esm/checkbox/index.js" - }, - "./combobox.js": { - "types": "./dist/dts/combobox/index.d.ts", - "default": "./dist/esm/combobox/index.js" - }, - "./data-grid.js": { - "types": "./dist/dts/data-grid/index.d.ts", - "default": "./dist/esm/data-grid/index.js" - }, - "./design-token.js": { - "types": "./dist/dts/design-token/exports.d.ts", - "default": "./dist/esm/design-token/exports.js" - }, - "./dialog.js": { - "types": "./dist/dts/dialog/index.d.ts", - "default": "./dist/esm/dialog/index.js" - }, - "./disclosure.js": { - "types": "./dist/dts/disclosure/index.d.ts", - "default": "./dist/esm/disclosure/index.js" - }, - "./divider.js": { - "types": "./dist/dts/divider/index.d.ts", - "default": "./dist/esm/divider/index.js" - }, - "./flipper.js": { - "types": "./dist/dts/flipper/index.d.ts", - "default": "./dist/esm/flipper/index.js" - }, - "./horizontal-scroll.js": { - "types": "./dist/dts/horizontal-scroll/index.d.ts", - "default": "./dist/esm/horizontal-scroll/index.js" - }, - "./listbox.js": { - "types": "./dist/dts/listbox/index.d.ts", - "default": "./dist/esm/listbox/index.js" - }, - "./listbox-option.js": { - "types": "./dist/dts/listbox-option/index.d.ts", - "default": "./dist/esm/listbox-option/index.js" - }, - "./menu.js": { - "types": "./dist/dts/menu/index.d.ts", - "default": "./dist/esm/menu/index.js" - }, - "./menu-item.js": { - "types": "./dist/dts/menu-item/index.d.ts", - "default": "./dist/esm/menu-item/index.js" - }, - "./number-field.js": { - "types": "./dist/dts/number-field/index.d.ts", - "default": "./dist/esm/number-field/index.js" - }, - "./picker.js": { - "types": "./dist/dts/picker/index.d.ts", - "default": "./dist/esm/picker/index.js" - }, - "./progress.js": { - "types": "./dist/dts/progress/index.d.ts", - "default": "./dist/esm/progress/index.js" - }, - "./progress-ring.js": { - "types": "./dist/dts/progress-ring/index.d.ts", - "default": "./dist/esm/progress-ring/index.js" - }, - "./radio.js": { - "types": "./dist/dts/radio/index.d.ts", - "default": "./dist/esm/radio/index.js" - }, - "./radio-group.js": { - "types": "./dist/dts/radio-group/index.d.ts", - "default": "./dist/esm/radio-group/index.js" - }, - "./search.js": { - "types": "./dist/dts/search/index.d.ts", - "default": "./dist/esm/search/index.js" - }, - "./select.js": { - "types": "./dist/dts/select/index.d.ts", - "default": "./dist/esm/select/index.js" - }, - "./skeleton.js": { - "types": "./dist/dts/skeleton/index.d.ts", - "default": "./dist/esm/skeleton/index.js" - }, - "./slider.js": { - "types": "./dist/dts/slider/index.d.ts", - "default": "./dist/esm/slider/index.js" - }, - "./slider-label.js": { - "types": "./dist/dts/slider-label/index.d.ts", - "default": "./dist/esm/slider-label/index.js" - }, - "./switch.js": { - "types": "./dist/dts/switch/index.d.ts", - "default": "./dist/esm/switch/index.js" - }, - "./tab.js": { - "types": "./dist/dts/tab/index.d.ts", - "default": "./dist/esm/tab/index.js" - }, - "./tab-panel.js": { - "types": "./dist/dts/tab-panel/index.d.ts", - "default": "./dist/esm/tab-panel/index.js" - }, - "./tabs.js": { - "types": "./dist/dts/tabs/index.d.ts", - "default": "./dist/esm/tabs/index.js" - }, - "./text-area.js": { - "types": "./dist/dts/text-area/index.d.ts", - "default": "./dist/esm/text-area/index.js" - }, - "./text-field.js": { - "types": "./dist/dts/text-field/index.d.ts", - "default": "./dist/esm/text-field/index.js" - }, - "./toolbar.js": { - "types": "./dist/dts/toolbar/index.d.ts", - "default": "./dist/esm/toolbar/index.js" - }, - "./tooltip.js": { - "types": "./dist/dts/tooltip/index.d.ts", - "default": "./dist/esm/tooltip/index.js" - }, - "./tree-item.js": { - "types": "./dist/dts/tree-item/index.d.ts", - "default": "./dist/esm/tree-item/index.js" - }, - "./tree-view.js": { - "types": "./dist/dts/tree-view/index.d.ts", - "default": "./dist/esm/tree-view/index.js" - }, - "./utilities.js": { - "types": "./dist/dts/utilities/index.d.ts", - "default": "./dist/esm/utilities/index.js" - }, - "./patterns.js": { - "types": "./dist/dts/patterns/index.d.ts", - "default": "./dist/esm/patterns/index.js" - }, - "./custom-elements.json": "./dist/custom-elements.json", - "./design-token-core.js": { - "types": "./dist/dts/design-token/core/exports.d.ts", - "default": "./dist/esm/design-token/core/exports.js" - }, - "./package.json": "./package.json" - }, - "scripts": { - "clean:dist": "rimraf dist storybook-static", - "doc": "api-extractor run --local", - "doc:ci": "api-extractor run", - "build:rollup": "rollup -c", - "build:tsc": "tsc -p ./tsconfig.build.json", - "prebuild": "yarn build:tsc", - "build": "yarn build:rollup", - "postbuild": "yarn doc && yarn cem", - "dev": "tsc -p ./tsconfig.build.json -w", - "cem": "yarn cem-analyze && yarn cem-markdown", - "cem-analyze": "cem analyze", - "cem-markdown": "node CEMToMarkdown.mjs", - "tdd": "yarn dev & yarn test-chrome:watch", - "tdd:firefox": "yarn dev & yarn test-firefox:watch", - "prepare": "yarn clean:dist && yarn build", - "prettier": "prettier --config ../../../.prettierrc --write \"**/*.ts\"", - "prettier:diff": "prettier --config ../../../.prettierrc \"**/*.ts\" --list-different", - "eslint": "eslint . --ext .ts", - "eslint:fix": "eslint . --ext .ts --fix", - "pretest": "yarn eslint && yarn storybook build --test", - "test": "playwright test", - "posttest:ci": "yarn doc:ci", - "start": "storybook dev -p 6006" - }, - "devDependencies": { - "@custom-elements-manifest/analyzer": "^0.9.3", - "@custom-elements-manifest/to-markdown": "^0.1.0", - "@microsoft/api-extractor": "7.24.2", - "@microsoft/tsdoc-config": "^0.13.4", - "@playwright/test": "^1.41.2", - "@rollup/plugin-node-resolve": "^13.3.0", - "@storybook/addon-essentials": "^8.0.0", - "@storybook/addon-links": "^8.0.0", - "@storybook/csf": "^0.1.3", - "@storybook/html-vite": "^8.0.0", - "@typescript-eslint/parser": "^5.0.0", - "eslint-plugin-storybook": "^0.8.0", - "express": "^4.18.1", - "expect": "29.2.1", - "prettier": "2.8.8", - "qs": "^6.11.0", - "rollup-plugin-filesize": "^9.1.2", - "rollup-plugin-terser": "^7.0.2", - "rollup-plugin-transform-tagged-template": "^0.0.3", - "rollup": "^2.71.1", - "storybook": "^8.0.0", - "typescript": "^4.7.0", - "vite": "^5.1.6" - }, - "dependencies": { - "@floating-ui/dom": "^1.0.3", - "@microsoft/fast-element": "2.0.0-beta.26", - "@microsoft/fast-web-utilities": "^6.0.0", - "tabbable": "^5.2.0", - "tslib": "^2.4.0" - }, - "customElements": "dist/custom-elements.json" -} diff --git a/packages/web-components/fast-foundation/playwright.config.ts b/packages/web-components/fast-foundation/playwright.config.ts deleted file mode 100644 index c82611b52b4..00000000000 --- a/packages/web-components/fast-foundation/playwright.config.ts +++ /dev/null @@ -1,26 +0,0 @@ -import type { PlaywrightTestConfig } from "@playwright/test"; - -const config: PlaywrightTestConfig = { - reporter: "list", - testMatch: /.*\.pw\.spec\.ts$/, - retries: 3, - fullyParallel: process.env.CI ? false : true, - timeout: process.env.CI ? 10000 : 30000, - use: { - baseURL: "http://localhost:6006/iframe.html", - deviceScaleFactor: 1, - launchOptions: { args: ["--force-device-scale-factor=1"] }, - viewport: { - height: 1280, - width: 720, - }, - }, - webServer: { - // double-quotes are required for Windows - command: "yarn start", - port: 6006, - reuseExistingServer: process.env.CI ? false : true, - }, -}; - -export default config; diff --git a/packages/web-components/fast-foundation/rollup.config.js b/packages/web-components/fast-foundation/rollup.config.js deleted file mode 100644 index 08b8d3cc235..00000000000 --- a/packages/web-components/fast-foundation/rollup.config.js +++ /dev/null @@ -1,63 +0,0 @@ -import filesize from "rollup-plugin-filesize"; -import { nodeResolve } from "@rollup/plugin-node-resolve"; -import { terser } from "rollup-plugin-terser"; -import transformTaggedTemplate from "rollup-plugin-transform-tagged-template"; -import { - transformCSSFragment, - transformHTMLFragment, -} from "../../../build/transform-fragments.js"; - -const parserOptions = { - sourceType: "module", -}; - -const plugins = [ - nodeResolve(), - transformTaggedTemplate({ - tagsToProcess: ["css"], - transformer: transformCSSFragment, - parserOptions, - }), - transformTaggedTemplate({ - tagsToProcess: ["child", "html", "item"], - transformer: transformHTMLFragment, - parserOptions, - }), - filesize({ - showMinifiedSize: false, - showBrotliSize: true, - }), -]; - -export default [ - { - input: "dist/esm/index.rollup.js", - output: [ - { - file: "dist/fast-foundation.js", - format: "esm", - }, - { - file: "dist/fast-foundation.min.js", - format: "esm", - plugins: [terser()], - }, - ], - plugins, - }, - { - input: "dist/esm/index.rollup.debug.js", - output: [ - { - file: "dist/fast-foundation.debug.js", - format: "esm", - }, - { - file: "dist/fast-foundation.debug.min.js", - format: "esm", - plugins: [terser()], - }, - ], - plugins, - }, -]; diff --git a/packages/web-components/fast-foundation/src/__test__/custom.d.ts b/packages/web-components/fast-foundation/src/__test__/custom.d.ts deleted file mode 100644 index 11f02fe2a00..00000000000 --- a/packages/web-components/fast-foundation/src/__test__/custom.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/packages/web-components/fast-foundation/src/__test__/global.d.ts b/packages/web-components/fast-foundation/src/__test__/global.d.ts deleted file mode 100644 index fb40d449329..00000000000 --- a/packages/web-components/fast-foundation/src/__test__/global.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -declare global { - namespace PlaywrightTest { - interface Matchers { - hasAttribute(a: string): Promise; - toHaveBooleanAttribute(a: string): Promise; - } - } -} - -export {}; diff --git a/packages/web-components/fast-foundation/src/__test__/helpers.ts b/packages/web-components/fast-foundation/src/__test__/helpers.ts deleted file mode 100644 index 1d09233ca12..00000000000 --- a/packages/web-components/fast-foundation/src/__test__/helpers.ts +++ /dev/null @@ -1,100 +0,0 @@ -import type { FASTElement, ViewTemplate } from "@microsoft/fast-element"; -import type { - AnnotatedStoryFn, - Args, - ComponentAnnotations, - StoryAnnotations, - StoryContext, -} from "@storybook/csf"; -import qs from "qs"; - -/** - * Returns a formatted URL for a given Storybook fixture. - * - * @param id - the Storybook fixture ID - * @param args - Story args - * @returns - the local URL for the Storybook fixture iframe - */ -export function fixtureURL( - id: string = "debug--blank", - args?: Record -): string { - const params: Record = { id }; - if (args) { - params.args = qs - .stringify(args, { - allowDots: true, - delimiter: ";", - format: "RFC1738", - encode: false, - }) - .replace(/=/g, ":") - .replace(/\//g, "--"); - } - - const url = qs.stringify(params, { - addQueryPrefix: true, - format: "RFC1738", - encode: false, - }); - - return url; -} - -/** - * A helper that returns a function to bind a Storybook story to a ViewTemplate. - * - * @param template - The ViewTemplate to render - * @returns - a function to bind a Storybook story - */ -export function renderComponent( - template: ViewTemplate -): (args: TArgs, context: StoryContext) => Element | DocumentFragment | null { - return function (args, { updateArgs }) { - const storyFragment = new DocumentFragment(); - template.render({ ...args, updateArgs }, storyFragment); - if (storyFragment.childElementCount === 1) { - return storyFragment.firstElementChild; - } - return storyFragment; - }; -} - -/** - * A helper that returns a function to bind a Storybook story to a ViewTemplate. - */ -export type FASTFramework = { - canvasElement: HTMLElement; - component: typeof FASTElement; - storyResult: FASTElement | Element | DocumentFragment; -}; - -/** - * Metadata to configure the stories for a component. - */ -export type Meta = ComponentAnnotations< - FASTFramework, - Omit ->; - -/** - * Story function that represents a CSFv3 component example. - */ -export declare type StoryObj = StoryAnnotations; - -/** - * Story function that represents a CSFv2 component example. - */ -export declare type StoryFn = AnnotatedStoryFn; - -/** - * Story function that represents a CSFv2 component example. - * - * NOTE that in Storybook 7.0, this type will be renamed to `StoryFn` and replaced by the current `StoryObj` type. - */ -export declare type Story = StoryFn>; - -/** - * Combined Storybook story args. - */ -export type StoryArgs = Partial> & Args; diff --git a/packages/web-components/fast-foundation/src/accordion-item/accordion-item.pw.spec.ts b/packages/web-components/fast-foundation/src/accordion-item/accordion-item.pw.spec.ts deleted file mode 100644 index ae6342d5e5e..00000000000 --- a/packages/web-components/fast-foundation/src/accordion-item/accordion-item.pw.spec.ts +++ /dev/null @@ -1,111 +0,0 @@ -import type { Locator, Page } from "@playwright/test"; -import { expect, test } from "@playwright/test"; -import { fixtureURL } from "../__test__/helpers.js"; -import type { FASTAccordionItem } from "./accordion-item.js"; - -test.describe("Accordion item", () => { - let page: Page; - let element: Locator; - let root: Locator; - let heading: Locator; - let button: Locator; - - test.beforeAll(async ({ browser }) => { - page = await browser.newPage(); - - element = page.locator("fast-accordion-item"); - - root = page.locator("#storybook-root"); - - heading = page.locator(`[role="heading"]`); - - button = element.locator("button"); - - await page.goto(fixtureURL("accordion-item--accordion-item")); - - await element.waitFor({ state: "visible" }); - }); - - test.afterAll(async () => { - await page.close(); - }); - - test("should set a default heading level of 2 when `headinglevel` is not provided", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - Heading 1 -
Content 1
-
- `; - }); - - await expect(element).not.toHaveAttribute("headinglevel"); - - await expect(element).toHaveJSProperty("headinglevel", 2); - }); - - test("should set the `aria-level` attribute on the internal heading element equal to the heading level", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - Heading 1 -
Content 1
-
- `; - }); - - await element.evaluate(node => { - node.headinglevel = 3; - }); - - await expect(heading).toHaveAttribute("aria-level", "3"); - }); - - test("should set `aria-expanded` property on the internal control equal to the `expanded` property", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(button).toHaveAttribute("aria-expanded", "true"); - - await element.evaluate(node => { - node.expanded = false; - }); - - await expect(button).toHaveAttribute("aria-expanded", "false"); - }); - - test("should set `disabled` attribute on the internal control equal to the `disabled` property", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(button).toHaveAttribute("disabled"); - - await element.evaluate(node => { - node.disabled = false; - }); - - await expect(button).not.toHaveAttribute("disabled"); - }); - - test("should set internal properties to match the id when provided", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element.locator(`[role="region"]`)).toHaveAttribute( - "aria-labelledby", - "foo" - ); - - await expect(button).toHaveId("foo"); - }); -}); diff --git a/packages/web-components/fast-foundation/src/accordion-item/accordion-item.template.ts b/packages/web-components/fast-foundation/src/accordion-item/accordion-item.template.ts deleted file mode 100644 index 2bd4e0321f2..00000000000 --- a/packages/web-components/fast-foundation/src/accordion-item/accordion-item.template.ts +++ /dev/null @@ -1,56 +0,0 @@ -import type { ElementViewTemplate } from "@microsoft/fast-element"; -import { html, ref } from "@microsoft/fast-element"; -import { endSlotTemplate, startSlotTemplate } from "../patterns/index.js"; -import { staticallyCompose } from "../utilities/template-helpers.js"; -import type { AccordionItemOptions, FASTAccordionItem } from "./accordion-item.js"; - -/** - * The template for the {@link @microsoft/fast-foundation#(FASTAccordionItem:class)} component. - * @public - */ -export function accordionItemTemplate( - options: AccordionItemOptions = {} -): ElementViewTemplate { - return html` -
- - ${ - /* The start slot is after the button for an improved screen reader experience */ "" - } - ${startSlotTemplate(options)} - ${endSlotTemplate(options)} -
-
- -
-`; -} diff --git a/packages/web-components/fast-foundation/src/accordion-item/accordion-item.ts b/packages/web-components/fast-foundation/src/accordion-item/accordion-item.ts deleted file mode 100644 index fc47fde155c..00000000000 --- a/packages/web-components/fast-foundation/src/accordion-item/accordion-item.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { attr, FASTElement, nullableNumberConverter } from "@microsoft/fast-element"; -import { uniqueId } from "@microsoft/fast-web-utilities"; -import type { StaticallyComposableHTML } from "../utilities/template-helpers.js"; -import { StartEnd } from "../patterns/index.js"; -import type { StartEndOptions } from "../patterns/start-end.js"; -import { applyMixins } from "../utilities/apply-mixins.js"; - -/** - * Accordion Item configuration options - * @public - */ -export type AccordionItemOptions = StartEndOptions & { - expandCollapseIcon?: StaticallyComposableHTML; -}; - -/** - * An individual item in an {@link @microsoft/fast-foundation#(FASTAccordion:class) }. - * - * @slot start - Content which can be provided between the heading and the icon - * @slot end - Content which can be provided between the start slot and icon - * @slot heading - Content which serves as the accordion item heading and text of the expand button - * @slot - The default slot for accordion item content - * @slot expand-collapse-icon - The expanded / collapsed icon - * @fires change - Fires a custom 'change' event when the button is invoked - * @csspart heading - Wraps the button - * @csspart button - The button which serves to invoke the item - * @csspart heading-content - Wraps the slot for the heading content within the button - * @csspart expand-collapse-icon - The icon container - * @csspart panel - The wrapper for the accordion item content - * - * @public - */ -export class FASTAccordionItem extends FASTElement { - /** - * Configures the {@link https://www.w3.org/TR/wai-aria-1.1/#aria-level | level} of the - * heading element. - * - * @defaultValue 2 - * @public - * @remarks - * HTML attribute: heading-level - */ - @attr({ - attribute: "heading-level", - mode: "fromView", - converter: nullableNumberConverter, - }) - public headinglevel: 1 | 2 | 3 | 4 | 5 | 6 = 2; - - /** - * Expands or collapses the item. - * - * @public - * @remarks - * HTML attribute: expanded - */ - @attr({ mode: "boolean" }) - public expanded: boolean = false; - - /** - * Disables an accordion item - * - * @public - * @remarks - * HTML attribute: disabled - */ - @attr({ mode: "boolean" }) - public disabled: boolean = false; - - /** - * The item ID - * - * @public - * @remarks - * HTML Attribute: id - */ - @attr - public id: string = uniqueId("accordion-"); - - /** - * @internal - */ - public expandbutton: HTMLElement; - - /** - * @internal - */ - public clickHandler = (e: MouseEvent) => { - if (this.disabled) { - return; - } - - this.$emit("click", e); - }; -} - -/** - * Mark internal because exporting class and interface of the same name - * confuses API documenter. - * TODO: https://github.com/microsoft/fast/issues/3317 - * @internal - */ -export interface FASTAccordionItem extends StartEnd {} -applyMixins(FASTAccordionItem, StartEnd); diff --git a/packages/web-components/fast-foundation/src/accordion-item/index.ts b/packages/web-components/fast-foundation/src/accordion-item/index.ts deleted file mode 100644 index 9cc9bc16fe0..00000000000 --- a/packages/web-components/fast-foundation/src/accordion-item/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { FASTAccordionItem } from "./accordion-item.js"; -export type { AccordionItemOptions } from "./accordion-item.js"; -export { accordionItemTemplate } from "./accordion-item.template.js"; diff --git a/packages/web-components/fast-foundation/src/accordion-item/stories/accordion-item.register.ts b/packages/web-components/fast-foundation/src/accordion-item/stories/accordion-item.register.ts deleted file mode 100644 index 1fe308e94b7..00000000000 --- a/packages/web-components/fast-foundation/src/accordion-item/stories/accordion-item.register.ts +++ /dev/null @@ -1,125 +0,0 @@ -import { css } from "@microsoft/fast-element"; -import chevronUpIcon from "../../../statics/svg/chevron_up_12_regular.svg"; -import { FASTAccordionItem } from "../accordion-item.js"; -import { accordionItemTemplate } from "../accordion-item.template.js"; - -const styles = css` - :host { - display: flex; - box-sizing: border-box; - font-family: var(--body-font); - flex-direction: column; - font-size: var(--type-ramp-base-font-size); - line-height: var(--type-ramp-base-line-height); - border-bottom: calc(var(--stroke-width) * 1px) solid - var(--neutral-stroke-divider-rest); - } - - :host([disabled]) { - opacity: var(--disabled-opacity); - } - - .panel { - display: none; - padding: calc((6 + (var(--design-unit) * 2 * var(--density))) * 1px); - } - - .heading { - display: grid; - position: relative; - grid-template-columns: auto 1fr auto calc( - (var(--base-height-multiplier) + var(--density)) * var(--design-unit) * - 1px - ); - } - - .button { - appearance: none; - border: none; - background: none; - grid-column: 2; - grid-row: 1; - outline: none; - padding: 0 calc((6 + (var(--design-unit) * 2 * var(--density))) * 1px); - text-align: left; - height: calc( - (var(--base-height-multiplier) + var(--density)) * var(--design-unit) * 1px - ); - color: var(--neutral-foreground-rest); - cursor: pointer; - font: inherit; - } - - .button:hover { - color: var(--neutral-foreground-rest); - } - - .button:active { - color: var(--neutral-foreground-rest); - } - - .button::before { - content: ""; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - cursor: pointer; - } - - .button:focus-visible::before { - outline: none; - border: calc(var(--focus-stroke-width) * 1px) solid var(--focus-stroke-outer); - border-radius: calc(var(--control-corner-radius) * 1px); - } - - :host([expanded]) .panel { - display: block; - } - - .expand-collapse-icon { - display: flex; - align-items: center; - justify-content: center; - grid-column: 4; - pointer-events: none; - position: relative; - } - - slot[name="expand-collapse-icon"] * { - transition: transform 0.1s linear; - transform: rotate(0deg); - transform-origin: center; - } - - :host([expanded]) slot[name="expand-collapse-icon"] * { - transform: rotate(90deg); - } - - ::slotted([slot="start"]) { - display: flex; - align-items: center; - margin-inline-end: calc(var(--design-unit) * 1px); - justify-content: center; - grid-column: 1; - position: relative; - } - - ::slotted([slot="end"]) { - display: flex; - align-items: center; - margin-inline-start: calc(var(--design-unit) * 1px); - justify-content: center; - grid-column: 3; - position: relative; - } -`; - -FASTAccordionItem.define({ - name: "fast-accordion-item", - template: accordionItemTemplate({ - expandCollapseIcon: chevronUpIcon, - }), - styles, -}); diff --git a/packages/web-components/fast-foundation/src/accordion-item/stories/accordion-item.stories.ts b/packages/web-components/fast-foundation/src/accordion-item/stories/accordion-item.stories.ts deleted file mode 100644 index 0bb7d8fe710..00000000000 --- a/packages/web-components/fast-foundation/src/accordion-item/stories/accordion-item.stories.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { html } from "@microsoft/fast-element"; -import type { Meta, Story, StoryArgs } from "../../__test__/helpers.js"; -import { renderComponent } from "../../__test__/helpers.js"; -import type { FASTAccordionItem } from "../accordion-item.js"; - -const storyTemplate = html>` - - ${x => x.storyContent} - -`; - -export default { - title: "Accordion Item", - args: { - expanded: false, - }, - argTypes: { - expanded: { control: "boolean" }, - headinglevel: { control: { type: "number", max: 6, min: 1 } }, - id: { control: "text" }, - storyContent: { table: { disable: true } }, - }, -} as Meta; - -export const AccordionItem: Story = renderComponent( - storyTemplate -).bind({}); -AccordionItem.args = { - storyContent: html` - Accordion Item Heading - Accordion Item Content - `, -}; - -export const AccordionItemWithSlottedStartEnd: Story = renderComponent( - storyTemplate -).bind({}); -AccordionItemWithSlottedStartEnd.args = { - storyContent: html` - start - Accordion Item Heading - end - Accordion Item Content - `, -}; diff --git a/packages/web-components/fast-foundation/src/accordion/README.md b/packages/web-components/fast-foundation/src/accordion/README.md deleted file mode 100644 index 7a7b0ef7651..00000000000 --- a/packages/web-components/fast-foundation/src/accordion/README.md +++ /dev/null @@ -1,219 +0,0 @@ ---- -id: accordion -title: fast-accordion -sidebar_label: accordion -custom_edit_url: https://github.com/microsoft/fast/edit/master/packages/web-components/fast-foundation/src/accordion/README.md -description: fast-accordion is a web component implementation of an accordion. ---- - -As defined by the [W3C](https://w3c.github.io/aria-practices/#accordion): - -> An accordion is a vertically stacked set of interactive headings that each contain a title, content snippet, or thumbnail representing a section of content. The headings function as controls that enable users to reveal or hide their associated sections of content. Accordions are commonly used to reduce the need to scroll when presenting multiple sections of content on a single page. - -## Setup - -### Basic Setup - -```ts -import { - provideFASTDesignSystem, - fastAccordion, - fastAccordionItem -} from "@microsoft/fast-components"; - -provideFASTDesignSystem() - .register( - fastAccordion(), - fastAccordionItem() - ); -``` - -### Customizing Icons - -```ts -import { - provideFASTDesignSystem, - fastAccordion, - fastAccordionItem -} from "@microsoft/fast-components"; - -provideFASTDesignSystem() - .register( - fastAccordion(), - fastAccordionItem({ - collapsedIcon: `...your collapsed icon...`, - expandedIcon: `...your expanded icon...`, - }) - ); -``` - -## Usage - -```html live - - - Panel one - Panel one content - - - Panel two - Panel two content - - - Panel three - Panel three content - - -``` - -## Create your own design - -### Accordion - -```ts -import { Accordion, accordionTemplate as template } from "@microsoft/fast-foundation"; -import { accordionStyles as styles } from "./my-accordion.styles"; - -export const myAccordion = Accordion.compose({ - baseName: "accordion", - template, - styles, -}); -``` - -### AccordionItem - -```ts -import { - AccordionItem, - AccordionItemOptions, - accordionItemTemplate as template, -} from "@microsoft/fast-foundation"; -import { accordionItemStyles as styles } from "./my-accordion-item.styles"; - -export const myAccordionItem = AccordionItem.compose({ - baseName: "accordion-item", - template, - styles, - collapsedIcon: `...default collapsed icon...`, - expandedIcon: `...default expanded icon...`, -}); -``` - -## API - - - -### Variables - -| Name | Description | Type | -| --------------------- | ----------------------------- | --------------------------------------- | -| `AccordionExpandMode` | Expand mode for FASTAccordion | `{ single: "single", multi: "multi", }` | - -
- - - -### class: `FASTAccordion` - -#### Superclass - -| Name | Module | Package | -| ------------- | ------ | ----------------------- | -| `FASTElement` | | @microsoft/fast-element | - -#### Fields - -| Name | Privacy | Type | Default | Description | Inherited From | -| ---------------- | --------- | --------------------- | ------- | --------------------------------------------------------------------------------------------- | -------------- | -| `expandmode` | public | `AccordionExpandMode` | | Controls the expand mode of the Accordion, either allowing single or multiple item expansion. | | -| `accordionItems` | protected | `Element[]` | | | | - -#### Methods - -| Name | Privacy | Description | Parameters | Return | Inherited From | -| ------------------- | ------- | ----------- | ------------------------------------------------------ | ------ | -------------- | -| `expandmodeChanged` | public | | `prev: AccordionExpandMode, next: AccordionExpandMode` | | | - -#### Events - -| Name | Type | Description | Inherited From | -| -------- | ---- | ---------------------------------------------------------- | -------------- | -| `change` | | Fires a custom 'change' event when the active item changes | | - -#### Attributes - -| Name | Field | Inherited From | -| ------------- | ---------- | -------------- | -| `expand-mode` | expandmode | | - -#### Slots - -| Name | Description | -| ---- | -------------------------------- | -| | The slot for the accordion items | - -
- - - -### class: `FASTAccordionItem` - -#### Superclass - -| Name | Module | Package | -| ------------- | ------ | ----------------------- | -| `FASTElement` | | @microsoft/fast-element | - -#### Fields - -| Name | Privacy | Type | Default | Description | Inherited From | -| -------------- | ------- | ---------------------------- | ------- | -------------------------------------------------------------------------------------------------- | -------------- | -| `headinglevel` | public | `1 or 2 or 3 or 4 or 5 or 6` | `2` | Configures the [level](https://www.w3.org/TR/wai-aria-1.1/#aria-level) of the heading element. | | -| `expanded` | public | `boolean` | `false` | Expands or collapses the item. | | -| `disabled` | public | `boolean` | `false` | Disables an accordion item | | -| `id` | public | `string` | | The item ID | | - -#### Events - -| Name | Type | Description | Inherited From | -| -------- | ---- | -------------------------------------------------------- | -------------- | -| `change` | | Fires a custom 'change' event when the button is invoked | | - -#### Attributes - -| Name | Field | Inherited From | -| --------------- | ------------ | -------------- | -| `heading-level` | headinglevel | | -| | expanded | | -| | disabled | | -| `id` | id | | - -#### CSS Parts - -| Name | Description | -| ---------------------- | -------------------------------------------------------- | -| `heading` | Wraps the button | -| `button` | The button which serves to invoke the item | -| `heading-content` | Wraps the slot for the heading content within the button | -| `expand-collapse-icon` | The icon container | -| `panel` | The wrapper for the accordion item content | - -#### Slots - -| Name | Description | -| ---------------------- | -------------------------------------------------------------------------------- | -| `start` | Content which can be provided between the heading and the icon | -| `end` | Content which can be provided between the start slot and icon | -| `heading` | Content which serves as the accordion item heading and text of the expand button | -| | The default slot for accordion item content | -| `expand-collapse-icon` | The expanded / collapsed icon | - -
- - -## Additional resources - -* [Component explorer examples](https://explore.fast.design/components/fast-accordion) -* [Component technical specification](https://github.com/microsoft/fast/blob/master/packages/web-components/fast-foundation/src/accordion/accordion.spec.md) -* [W3C Component Aria Practices](https://w3c.github.io/aria-practices/#accordion) \ No newline at end of file diff --git a/packages/web-components/fast-foundation/src/accordion/accordion.options.ts b/packages/web-components/fast-foundation/src/accordion/accordion.options.ts deleted file mode 100644 index 8a27baf18f4..00000000000 --- a/packages/web-components/fast-foundation/src/accordion/accordion.options.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { ValuesOf } from "../utilities/index.js"; - -/** - * Expand mode for {@link FASTAccordion} - * @public - */ -export const AccordionExpandMode = { - /** - * Designates only a single {@link @microsoft/fast-foundation#(FASTAccordionItem:class) } can be open a time. - */ - single: "single", - - /** - * Designates multiple {@link @microsoft/fast-foundation#(FASTAccordionItem:class) | FASTAccordionItemItems} can be open simultaneously. - */ - multi: "multi", -} as const; - -/** - * Type for the {@link FASTAccordion} Expand Mode - * @public - */ -export type AccordionExpandMode = ValuesOf; diff --git a/packages/web-components/fast-foundation/src/accordion/accordion.pw.spec.ts b/packages/web-components/fast-foundation/src/accordion/accordion.pw.spec.ts deleted file mode 100644 index b965ec1e9a4..00000000000 --- a/packages/web-components/fast-foundation/src/accordion/accordion.pw.spec.ts +++ /dev/null @@ -1,387 +0,0 @@ -import type { Locator, Page } from "@playwright/test"; -import { expect, test } from "@playwright/test"; -import { fixtureURL } from "../__test__/helpers.js"; -import { AccordionExpandMode } from "./accordion.options.js"; - -test.describe("Accordion", () => { - let page: Page; - let element: Locator; - let root: Locator; - - test.beforeAll(async ({ browser }) => { - page = await browser.newPage(); - - element = page.locator("fast-accordion"); - - root = page.locator("#storybook-root"); - - await page.goto(fixtureURL("accordion--accordion")); - - await element.waitFor({ state: "visible" }); - }); - - test.afterAll(async () => { - await page.close(); - }); - - test("should set an expand mode of `multi` when passed to the `expand-mode` attribute", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - - Heading 1 -
Content 1
-
- - Heading 2 -
Content 2
-
-
- `; - }); - - await expect(element).toHaveAttribute("expand-mode", AccordionExpandMode.multi); - }); - - test("should set an expand mode of `single` when passed to the `expand-mode` attribute", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - - Heading 1 -
Content 1
-
- - Heading 2 -
Content 2
-
-
- `; - }); - - await expect(element).toHaveAttribute("expand-mode", AccordionExpandMode.single); - }); - - test("should set a default expand mode of `multi` when `expand-mode` attribute is not passed", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - - Heading 1 -
Content 1
-
- - Heading 2 -
Content 2
-
-
- `; - }); - - await expect(element).toHaveJSProperty("expandmode", AccordionExpandMode.multi); - - await expect(element).toHaveAttribute("expand-mode", AccordionExpandMode.multi); - }); - - test("should expand/collapse items when clicked in multi mode", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - - Heading 1 -
Content 1
-
- - Heading 2 -
Content 2
-
-
- `; - }); - - const items = element.locator("fast-accordion-item"); - - await items.nth(0).click(); - - await items.nth(1).click(); - - await expect(items.nth(0)).toHaveAttribute("expanded", ""); - - await expect(items.nth(1)).toHaveAttribute("expanded", ""); - }); - - test("should only have one expanded item in single mode", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - - Heading 1 -
Content 1
-
- - Heading 2 -
Content 2
-
-
- `; - }); - - const items = element.locator("fast-accordion-item"); - - const firstItem = items.nth(0); - - const secondItem = items.nth(1); - - await firstItem.click(); - - await expect(firstItem).toHaveAttribute("expanded"); - - await expect(secondItem).not.toHaveAttribute("expanded"); - - const secondItemButton = secondItem.locator(`[part="button"]`); - - await secondItemButton.click(); - - await secondItemButton.evaluate(node => { - node.dispatchEvent(new MouseEvent("click", { bubbles: true })); - }); - - await expect(firstItem).not.toHaveAttribute("expanded"); - - await expect(secondItem).toHaveAttribute("expanded"); - }); - - test("should set the expanded items' button to aria-disabled when in single expand mode", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - - Heading 1 -
Content 1
-
- - Heading 2 -
Content 2
-
-
- `; - }); - - const items = element.locator("fast-accordion-item"); - - const firstItem = items.nth(0); - - const secondItem = items.nth(1); - - await firstItem.click(); - - await expect(firstItem).toHaveAttribute("expanded"); - - await expect(firstItem.locator("button")).toHaveAttribute( - "aria-disabled", - "true" - ); - - await secondItem.click(); - - await expect(firstItem).not.toHaveAttribute("expanded"); - - await expect(firstItem.locator("button")).not.toHaveAttribute( - "aria-disabled", - "true" - ); - await expect(firstItem.locator("button")).not.toHaveAttribute( - "aria-disabled", - "false" - ); - - await expect(secondItem).toHaveAttribute("expanded"); - - await expect(secondItem.locator("button")).toHaveAttribute( - "aria-disabled", - "true" - ); - }); - - /* eslint-disable-next-line max-len */ - test("should remove an expanded items' expandbutton aria-disabled attribute when expand mode changes from single to multi", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - - Heading 1 -
Content 1
-
- - Heading 2 -
Content 2
-
-
- `; - }); - - const items = element.locator("fast-accordion-item"); - - const firstItem = items.nth(0); - - await firstItem.click(); - - await expect(firstItem).toHaveAttribute("expanded"); - - await expect(firstItem.locator("button")).toHaveAttribute( - "aria-disabled", - "true" - ); - - await element.evaluate(node => { - node.setAttribute("expand-mode", "multi"); - }); - - await expect(firstItem.locator("button")).not.toHaveAttribute("aria-disabled"); - }); - - test("should set the first item as expanded if no child is expanded by default in single mode", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - - Heading 1 -
Content 1
-
- - Heading 2 -
Content 2
-
-
- `; - }); - - const items = element.locator("fast-accordion-item"); - - const firstItem = items.nth(0); - - const secondItem = items.nth(1); - - await expect(firstItem).toHaveAttribute("expanded"); - - await expect(secondItem).not.toHaveAttribute("expanded"); - - await secondItem.evaluate(node => node.setAttribute("expanded", "")); - - await expect(firstItem).not.toHaveAttribute("expanded"); - - await expect(secondItem).toHaveAttribute("expanded"); - }); - - test("should set the first item with an expanded attribute to expanded in single mode", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - - Heading 1 -
Content 1
-
- - Heading 2 -
Content 2
-
- - Heading 3 -
Content 2
-
-
- `; - }); - - const items = element.locator("fast-accordion-item"); - - const firstItem = items.nth(0); - - const secondItem = items.nth(1); - - const thirdItem = items.nth(2); - - await expect(firstItem).not.toHaveAttribute("expanded"); - - await expect(secondItem).toHaveAttribute("expanded"); - - await expect(thirdItem).not.toHaveAttribute("expanded"); - }); - - test("should allow disabled items to be expanded when in single mode", async () => { - test.slow(); - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - - Heading 1 -
Content 1
-
- - Heading 2 -
Content 2
-
- - Heading 3 -
Content 2
-
-
- `; - }); - - const items = element.locator("fast-accordion-item"); - - const firstItem = items.nth(0); - - const secondItem = items.nth(1); - - const thirdItem = items.nth(2); - - await expect(firstItem).not.toHaveAttribute("expanded"); - - await expect(secondItem).toHaveAttribute("expanded"); - - await expect(thirdItem).toHaveAttribute("expanded"); - - await secondItem.evaluate(node => { - node.removeAttribute("disabled"); - }); - - await expect(firstItem).not.toHaveAttribute("expanded"); - - await expect(secondItem).toHaveAttribute("expanded"); - - await expect(thirdItem).not.toHaveAttribute("expanded"); - }); - - test("should ignore `change` events from components other than accordion items", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - -
Accordion Item 1 Heading
- Accordion Item 1 Content -
- -
Accordion Item 2 Heading
- A checkbox as content -
-
- `; - }); - - const item = element.locator("fast-accordion-item").nth(1); - - const button = item.locator(`button[part="button"]`); - - await button.click(); - - await expect(item).toHaveAttribute("expanded", ""); - - const checkbox = item.locator("fast-checkbox"); - - await checkbox.click(); - - await expect(item).toHaveAttribute("expanded", ""); - }); -}); diff --git a/packages/web-components/fast-foundation/src/accordion/accordion.spec.md b/packages/web-components/fast-foundation/src/accordion/accordion.spec.md deleted file mode 100644 index a4786477cfe..00000000000 --- a/packages/web-components/fast-foundation/src/accordion/accordion.spec.md +++ /dev/null @@ -1,203 +0,0 @@ -# Accordion - -## Overview - -As defined by the W3C: -> An accordion is a vertically stacked set of interactive headings that each contain a title, content snippet, or thumbnail representing a section of content. The headings function as controls that enable users to reveal or hide their associated sections of content. Accordions are commonly used to reduce the need to scroll when presenting multiple sections of content on a single page. - -### Use Cases - -- Frank finds a spelling error in the FAST documentation. He submits a pull request (PR) to fix the error and goes to eat lunch while waiting for the maintainers to review his PR. Upon returning from lunch he notices a widget on the screen saying certain status checks failed. He clicks on the headline of the widget and it reveals additional information stating that he needs to run prettier to ensure proper formatting. He clicks the headline again and the additional information collapses. Frank runs prettier and his PR is completed successfully. - -- On April 16th Randy wakes up in a cold sweat because he realized he made a mistake in filing his taxes with the IRS. He opens his laptop and goes to the IRS website and sees a link to "frequently asked questions". Randy sees a list of questions on the page with an arrow next to it indicating that answers are hidden. He sees a question titled, "What should I do if I made a mistake on my federal turn that I've already filed?" Randy clicks the question and sees a section detailing out the exact steps to take. With his anxiety eased, Randy goes back to bed and falls asleep. - -### Features - -1. Optionally allow only a single section to be expanded. This behavior is opt-in and not default behavior. - -2. Support for interactive content within the header, such as a menu button, checkbox, etc. - -3. Optional support for nested accordions. Ideally this behavior will "just work" and no special behaviors will need to be added to enable/support this. The expectation here should be that an accordion takes content and whatever content is inside the accordion panel respects its own interaction model. - -### Prior Art/Examples - -- [Ant Design](https://ant.design/components/collapse/) -- [Carbon Design](https://www.carbondesignsystem.com/components/accordion/usage/) -- [Lightning Design](https://www.lightningdesignsystem.com/components/accordion/) -- [Fluent UI](https://fluentsite.z22.web.core.windows.net/components/accordion/accessibility) -- [Primer](https://primer.style/components/Details) -- [Bootstrap](https://getbootstrap.com/docs/4.3/components/collapse/) - ---- - -### API - -**Accordion** -*Component Name* -- `fast-accordion` - -*Attributes:* -- `expand-mode` - enum - - single - - multi - default - -*Events* -- `change: CustomEvent` - - no custom data - - bubbles - -**Accordion Item** -*Component names:* -- `fast-accordion-item` - -*Attributes:* -- `expanded` - boolean -- `id` - string -- `heading-level` - enum - - 1 - - 2 - - 3 - default - - 4 - - 5 - - 6 - -*Parts:* -- panel -- button - -*Slot Names* -- default -- heading -- collapsed-icon -- expanded-icon -- start -- end - -### Anatomy and Appearance - -```HTML - -
-
- - - - - - - -
-
- Panel one content -
-
- - - - - - - -
-
- Panel two content -
-
- - - - - - - -
-
- Panel three content -
-
- - -``` - ---- - -## Implementation - -```HTML - - - Panel one - ^ - Panel one content - - - Panel two - ^ - Panel two content - - - Panel three - ^ - Panel three content - - -``` - -### States - -Accordion has 2 modes of expansion let can be set via `expand-mode`. `expand-mode` defaults to `multi`, meaning multiple accordion-items can be expanded at any given time. If `expand-mode` is set to `single` then only one item can be expanded, meaning that when you activate a header all other headers with collapse. - - -### Accessibility - -Keyboard interactions for tabbing and up and down arrow should focus the next or previous header. Space bar should toggle the expansion of the focused header. - -### Globalization - -Component should mirror in RTL presentations. - -### Test Plan - -While testing is still TBD for our web components, we would expect this to align with the testing strategy and not require any additional test support. - ---- diff --git a/packages/web-components/fast-foundation/src/accordion/accordion.template.ts b/packages/web-components/fast-foundation/src/accordion/accordion.template.ts deleted file mode 100644 index 0e7f7051555..00000000000 --- a/packages/web-components/fast-foundation/src/accordion/accordion.template.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { ElementViewTemplate } from "@microsoft/fast-element"; -import { elements, html, slotted } from "@microsoft/fast-element"; -import type { FASTAccordion } from "./accordion.js"; - -/** - * Creates a template for the {@link @microsoft/fast-foundation#FASTAccordion} component. - * @public - */ -export function accordionTemplate(): ElementViewTemplate { - return html` - - `; -} diff --git a/packages/web-components/fast-foundation/src/accordion/accordion.ts b/packages/web-components/fast-foundation/src/accordion/accordion.ts deleted file mode 100644 index 9151e420e2e..00000000000 --- a/packages/web-components/fast-foundation/src/accordion/accordion.ts +++ /dev/null @@ -1,276 +0,0 @@ -import { Observable } from "@microsoft/fast-element"; -import { attr, FASTElement, observable } from "@microsoft/fast-element"; -import { - keyArrowDown, - keyArrowUp, - keyEnd, - keyHome, - wrapInBounds, -} from "@microsoft/fast-web-utilities"; -import { FASTAccordionItem } from "../accordion-item/accordion-item.js"; -import { AccordionExpandMode } from "./accordion.options.js"; - -/** - * An Accordion Custom HTML Element - * Implements {@link https://www.w3.org/TR/wai-aria-practices-1.1/#accordion | ARIA Accordion}. - * - * @slot - The slot for the accordion items - * @fires change - Fires a custom 'change' event when the active item changes - * @public - * - * @remarks - * Designed to be used with {@link @microsoft/fast-foundation#accordionTemplate} - * and {@link @microsoft/fast-foundation#(FASTAccordionItem:class)}. - */ -export class FASTAccordion extends FASTElement { - /** - * Controls the expand mode of the Accordion, either allowing - * single or multiple item expansion. - * @public - * - * @remarks - * HTML attribute: expand-mode - */ - @attr({ attribute: "expand-mode" }) - public expandmode: AccordionExpandMode = AccordionExpandMode.multi; - public expandmodeChanged(prev: AccordionExpandMode, next: AccordionExpandMode) { - if (!this.$fastController.isConnected) { - return; - } - - const expandedItem = this.findExpandedItem(); - - if (!expandedItem) { - return; - } - - if (next !== AccordionExpandMode.single) { - (expandedItem as FASTAccordionItem)?.expandbutton.removeAttribute( - "aria-disabled" - ); - } else { - this.setSingleExpandMode(expandedItem); - } - } - - /** - * @internal - */ - @observable - public slottedAccordionItems: HTMLElement[]; - - protected accordionItems: Element[]; - - /** - * @internal - */ - public slottedAccordionItemsChanged( - oldValue: HTMLElement[], - newValue: HTMLElement[] - ): void { - if (this.$fastController.isConnected) { - this.setItems(); - } - } - - /** - * @internal - */ - public handleChange(source: any, propertyName: string) { - if (propertyName === "disabled") { - this.setItems(); - } else if (propertyName === "expanded") { - // we only need to manage single expanded instances - // such as scenarios where a child is programatically expanded - if (source.expanded && this.isSingleExpandMode()) { - this.setSingleExpandMode(source); - } - } - } - - private activeid: string | null; - private activeItemIndex: number = 0; - private accordionIds: Array; - - private change = (): void => { - this.$emit("change", this.activeid); - }; - - private findExpandedItem(): FASTAccordionItem | Element | null { - if (this.accordionItems.length === 0) { - return null; - } - - return ( - this.accordionItems.find( - (item: Element | FASTAccordionItem) => - item instanceof FASTAccordionItem && item.expanded - ) ?? this.accordionItems[0] - ); - } - - private setItems = (): void => { - if (this.slottedAccordionItems.length === 0) { - return; - } - - const children: Element[] = Array.from(this.children); - - this.removeItemListeners(children); - - children.forEach((child: Element) => - Observable.getNotifier(child).subscribe(this, "disabled") - ); - - this.accordionItems = children.filter(child => !child.hasAttribute("disabled")); - - this.accordionIds = this.getItemIds(); - - this.accordionItems.forEach((item: HTMLElement, index: number) => { - if (item instanceof FASTAccordionItem) { - item.addEventListener("click", this.activeItemChange); - Observable.getNotifier(item).subscribe(this, "expanded"); - } - - const itemId: string | null = this.accordionIds[index]; - item.setAttribute( - "id", - typeof itemId !== "string" ? `accordion-${index + 1}` : itemId - ); - this.activeid = this.accordionIds[this.activeItemIndex] as string; - item.addEventListener("keydown", this.handleItemKeyDown); - item.addEventListener("focus", this.handleItemFocus); - }); - - if (this.isSingleExpandMode()) { - const expandedItem = this.findExpandedItem() as FASTAccordionItem; - this.setSingleExpandMode(expandedItem); - } - }; - - private setSingleExpandMode(expandedItem: Element): void { - if (this.accordionItems.length === 0) { - return; - } - const currentItems = Array.from(this.accordionItems); - this.activeItemIndex = currentItems.indexOf(expandedItem); - - currentItems.forEach((item: FASTAccordionItem, index: number) => { - if (this.activeItemIndex === index) { - item.expanded = true; - item.expandbutton.setAttribute("aria-disabled", "true"); - } else { - item.expanded = false; - - if (!item.hasAttribute("disabled")) { - item.expandbutton.removeAttribute("aria-disabled"); - } - } - }); - } - - private removeItemListeners = (oldValue: any): void => { - oldValue.forEach((item: HTMLElement, index: number) => { - Observable.getNotifier(item).unsubscribe(this, "disabled"); - Observable.getNotifier(item).unsubscribe(this, "expanded"); - item.removeEventListener("click", this.activeItemChange); - item.removeEventListener("keydown", this.handleItemKeyDown); - item.removeEventListener("focus", this.handleItemFocus); - }); - }; - - private activeItemChange = (event: Event): void => { - if (event.defaultPrevented || event.target !== event.currentTarget) { - return; - } - - event.preventDefault(); - - this.handleExpandedChange(event.target as HTMLElement); - }; - - private handleExpandedChange = (item: HTMLElement) => { - if (item instanceof FASTAccordionItem) { - this.activeid = item.getAttribute("id"); - - if (!this.isSingleExpandMode()) { - item.expanded = !item.expanded; - // setSingleExpandMode sets activeItemIndex on its own - this.activeItemIndex = this.accordionItems.indexOf(item); - } else { - this.setSingleExpandMode(item); - } - - this.change(); - } - }; - - private getItemIds(): Array { - return this.slottedAccordionItems.map((accordionItem: HTMLElement) => { - return accordionItem.id; - }); - } - - private isSingleExpandMode(): boolean { - return this.expandmode === AccordionExpandMode.single; - } - - private handleItemKeyDown = (event: KeyboardEvent): void => { - // only handle the keydown if the event target is the accordion item - // prevents arrow keys from moving focus to accordion headers when focus is on accordion item panel content - if (event.target !== event.currentTarget) { - return; - } - this.accordionIds = this.getItemIds(); - switch (event.key) { - case keyArrowUp: - event.preventDefault(); - this.adjust(-1); - break; - case keyArrowDown: - event.preventDefault(); - this.adjust(1); - break; - case keyHome: - this.activeItemIndex = 0; - this.focusItem(); - break; - case keyEnd: - this.activeItemIndex = this.accordionItems.length - 1; - this.focusItem(); - break; - } - }; - - private handleItemFocus = (event: FocusEvent): void => { - // update the active item index if the focus moves to an accordion item - // via a different method other than the up and down arrow key actions - // only do so if the focus is actually on the accordion item and not on any of its children - if (event.target === event.currentTarget) { - const focusedItem = event.target as HTMLElement; - const focusedIndex: number = (this.activeItemIndex = Array.from( - this.accordionItems - ).indexOf(focusedItem)); - if (this.activeItemIndex !== focusedIndex && focusedIndex !== -1) { - this.activeItemIndex = focusedIndex; - this.activeid = this.accordionIds[this.activeItemIndex] as string; - } - } - }; - - private adjust(adjustment: number): void { - this.activeItemIndex = wrapInBounds( - 0, - this.accordionItems.length - 1, - this.activeItemIndex + adjustment - ); - this.focusItem(); - } - - private focusItem(): void { - const element: Element = this.accordionItems[this.activeItemIndex]; - if (element instanceof FASTAccordionItem) { - element.expandbutton.focus(); - } - } -} diff --git a/packages/web-components/fast-foundation/src/accordion/index.ts b/packages/web-components/fast-foundation/src/accordion/index.ts deleted file mode 100644 index 36667b59460..00000000000 --- a/packages/web-components/fast-foundation/src/accordion/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { FASTAccordion } from "./accordion.js"; -export { AccordionExpandMode } from "./accordion.options.js"; -export { accordionTemplate } from "./accordion.template.js"; diff --git a/packages/web-components/fast-foundation/src/accordion/stories/accordion.register.ts b/packages/web-components/fast-foundation/src/accordion/stories/accordion.register.ts deleted file mode 100644 index 55cfd564d2b..00000000000 --- a/packages/web-components/fast-foundation/src/accordion/stories/accordion.register.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { css } from "@microsoft/fast-element"; -import { FASTAccordion } from "../accordion.js"; -import { accordionTemplate } from "../accordion.template.js"; - -const styles = css` - :host { - display: flex; - flex-direction: column; - border-top: calc(var(--stroke-width) * 1px) solid - var(--neutral-stroke-divider-rest); - } -`; - -FASTAccordion.define({ - name: "fast-accordion", - template: accordionTemplate(), - styles, -}); diff --git a/packages/web-components/fast-foundation/src/accordion/stories/accordion.stories.ts b/packages/web-components/fast-foundation/src/accordion/stories/accordion.stories.ts deleted file mode 100644 index 9f23c92e93e..00000000000 --- a/packages/web-components/fast-foundation/src/accordion/stories/accordion.stories.ts +++ /dev/null @@ -1,137 +0,0 @@ -import { html } from "@microsoft/fast-element"; -import type { Meta, Story, StoryArgs } from "../../__test__/helpers.js"; -import { renderComponent } from "../../__test__/helpers.js"; -import { FASTAccordion } from "../accordion.js"; -import { AccordionExpandMode } from "../accordion.options.js"; - -const storyTemplate = html>` - - ${x => x.storyContent} - -`; - -export default { - title: "Accordion", - component: FASTAccordion, - args: { - expandmode: AccordionExpandMode.multi, - }, - argTypes: { - expandmode: { control: "select", options: Object.values(AccordionExpandMode) }, - storyContent: { table: { disable: true } }, - }, -} as Meta; - -export const Accordion: Story = renderComponent(storyTemplate).bind({}); -Accordion.args = { - storyContent: html` - - Accordion Item 1 Heading - Accordion Item 1 Content - - - Accordion Item 2 Heading - A checkbox as content - - - Accordion Item 3 Heading - Accordion Item 3 Content - - `, -}; - -export const AccordionWithSlottedStartEnd: Story = renderComponent( - storyTemplate -).bind({}); -AccordionWithSlottedStartEnd.args = { - storyContent: html` - - start - Accordion Item 1 Heading - end - Accordion Item 1 Content - - - start - Accordion Item 2 Heading - end - A checkbox as content - - - start - Accordion Item 3 Heading - end - Accordion Item 3 Content - - `, -}; - -export const AccordionWithSlottedInteractiveStartEnd: Story = - renderComponent(storyTemplate).bind({}); -AccordionWithSlottedInteractiveStartEnd.args = { - storyContent: html` - - start - Accordion Item 1 Heading - end - Accordion Item 1 Content - - - start - Accordion Item 2 Heading - end - A checkbox as content - - - start - Accordion Item 3 Heading - end - Accordion Item 3 Content - - `, -}; - -export const AccordionWithExpandedChild: Story = renderComponent( - storyTemplate -).bind({}); -AccordionWithExpandedChild.args = { - storyContent: html` - -
Accordion Item 1 Heading
- Accordion Item 1 Content -
- -
Accordion Item 2 Heading
- A checkbox as content -
- -
Accordion Item 3 Heading
- Accordion Item 3 Content -
- `, -}; - -export const AccordionWithSingleExpandMode: Story = renderComponent( - storyTemplate -).bind({}); -AccordionWithSingleExpandMode.args = { - expandmode: "single", - storyContent: html` - -
Accordion Item 1 Heading
- Accordion Item 1 Content -
- -
Accordion Item 2 Heading
- A checkbox as content -
- -
Accordion Item 3 Heading
- Accordion Item 3 Content -
- -
Accordion Item 4 Heading
- Accordion Item 4 Content -
- `, -}; diff --git a/packages/web-components/fast-foundation/src/anchor/README.md b/packages/web-components/fast-foundation/src/anchor/README.md deleted file mode 100644 index a960150e000..00000000000 --- a/packages/web-components/fast-foundation/src/anchor/README.md +++ /dev/null @@ -1,143 +0,0 @@ ---- -id: anchor -title: fast-anchor -sidebar_label: anchor -custom_edit_url: https://github.com/microsoft/fast/edit/master/packages/web-components/fast-foundation/src/anchor/README.md -description: fast-anchor is a web component implementation of an anchor element. ---- - -As defined by the W3C: - -> An anchor is a piece of text which marks the beginning and/or the end of a hypertext link. - -`fast-anchor` is a web component implementation of an [HTML anchor element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a). The `fast-components` anchor supports the same visual appearances as the button component (accent, lightweight, neutral, outline, stealth) as well as a hypertext appearance for use inline with text. - -## Setup - -```ts -import { - provideFASTDesignSystem, - fastAnchor -} from "@microsoft/fast-components"; - -provideFASTDesignSystem() - .register( - fastAnchor() - ); -``` - -## Usage - -```html live -FAST -``` - -## Create your own design - -```ts -import { - Anchor, - anchorTemplate as template, -} from "@microsoft/fast-foundation"; -import { anchorStyles as styles } from "./my-anchor.styles"; - -export const myAnchor = Anchor.compose({ - baseName: "anchor", - template, - styles, - shadowOptions: { - delegatesFocus: true, - }, -}); -``` - -:::note -This component is built with the expectation that focus is delegated to the anchor element rendered into the shadow DOM. -::: - -## API - - - -### Variables - -| Name | Description | Type | -| -------------- | --------------------- | ------------------------------------------------------------------------- | -| `AnchorTarget` | Anchor target values. | `{ _self: "_self", _blank: "_blank", _parent: "_parent", _top: "_top", }` | - -
- - - -### class: `FASTAnchor` - -#### Superclass - -| Name | Module | Package | -| ------------- | ------ | ----------------------- | -| `FASTElement` | | @microsoft/fast-element | - -#### Fields - -| Name | Privacy | Type | Default | Description | Inherited From | -| ---------------- | ------- | ------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- | -| `download` | public | `string` | | Prompts the user to save the linked URL. See [`` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a) for more information. | | -| `href` | public | `string` | | The URL the hyperlink references. See [`` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a) for more information. | | -| `hreflang` | public | `string` | | Hints at the language of the referenced resource. See [`` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a) for more information. | | -| `ping` | public | `string` | | See [`` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a) for more information. | | -| `referrerpolicy` | public | `string` | | See [`` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a) for more information. | | -| `rel` | public | `string` | | See [`` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a) for more information. | | -| `target` | public | `AnchorTarget` | | See [`` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a) for more information. | | -| `type` | public | `string` | | See [`` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a) for more information. | | -| `control` | public | `HTMLAnchorElement` | | References the root element | | - -#### Attributes - -| Name | Field | Inherited From | -| ---------------- | -------------- | -------------- | -| `download` | download | | -| `href` | href | | -| `hreflang` | hreflang | | -| `ping` | ping | | -| `referrerpolicy` | referrerpolicy | | -| `rel` | rel | | -| `target` | target | | -| `type` | type | | - -#### CSS Parts - -| Name | Description | -| --------- | ----------------------------------- | -| `control` | The anchor element | -| `content` | The element wrapping anchor content | - -#### Slots - -| Name | Description | -| ------- | ------------------------------------------------------- | -| `start` | Content which can be provided before the anchor content | -| `end` | Content which can be provided after the anchor content | -| | The default slot for anchor content | - -
- -### class: `DelegatesARIALink` - -#### Fields - -| Name | Privacy | Type | Default | Description | Inherited From | -| -------------- | ------- | ------------------------------------- | ------- | -------------------------------------------------------------------- | -------------- | -| `ariaExpanded` | public | `"true" or "false" or string or null` | | See https://www.w3.org/WAI/PF/aria/roles#link for more information | | - -#### Attributes - -| Name | Field | Inherited From | -| --------------- | ------------ | -------------- | -| `aria-expanded` | ariaExpanded | | - -
- - -## Additional resources - -* [Component explorer examples](https://explore.fast.design/components/fast-anchor) \ No newline at end of file diff --git a/packages/web-components/fast-foundation/src/anchor/anchor.options.ts b/packages/web-components/fast-foundation/src/anchor/anchor.options.ts deleted file mode 100644 index 958aa911486..00000000000 --- a/packages/web-components/fast-foundation/src/anchor/anchor.options.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { ValuesOf } from "../utilities/index.js"; - -/** - * Anchor target values. - * - * @public - */ -export const AnchorTarget = { - _self: "_self", - _blank: "_blank", - _parent: "_parent", - _top: "_top", -} as const; - -/** - * Type for anchor target values. - * - * @public - */ -export type AnchorTarget = ValuesOf; diff --git a/packages/web-components/fast-foundation/src/anchor/anchor.pw.spec.ts b/packages/web-components/fast-foundation/src/anchor/anchor.pw.spec.ts deleted file mode 100644 index 9ff2b3c0f99..00000000000 --- a/packages/web-components/fast-foundation/src/anchor/anchor.pw.spec.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { spinalCase } from "@microsoft/fast-web-utilities"; -import { expect, test } from "@playwright/test"; -import type { Locator, Page } from "@playwright/test"; -import { fixtureURL } from "../__test__/helpers.js"; - -test.describe("Anchor", () => { - let page: Page; - let element: Locator; - - test.beforeAll(async ({ browser }) => { - page = await browser.newPage(); - - element = page.locator("fast-anchor"); - - await page.goto(fixtureURL("anchor", attributes)); - }); - - test.afterAll(async () => { - await page.close(); - }); - - const attributes = { - href: "href", - ping: "ping", - hreflang: "en-GB", - referrerpolicy: "no-referrer", - rel: "external", - target: "_blank", - type: "foo", - ariaAtomic: "true", - ariaBusy: "false", - ariaControls: "testId", - ariaCurrent: "page", - ariaDescribedby: "testId", - ariaDetails: "testId", - ariaDisabled: "true", - ariaErrormessage: "test", - ariaExpanded: "true", - ariaFlowto: "testId", - ariaHaspopup: "true", - ariaHidden: "true", - ariaInvalid: "spelling", - ariaKeyshortcuts: "F4", - ariaLabel: "foo", - ariaLabelledby: "testId", - ariaLive: "polite", - ariaOwns: "testId", - ariaRelevant: "removals", - ariaRoledescription: "slide", - }; - - for (const [attribute, value] of Object.entries(attributes)) { - const attributeSpinalCase = spinalCase(attribute); - - test(`should set the \`${attributeSpinalCase}\` attribute to \`${value}\` on the internal control`, async () => { - await expect(element).toHaveAttribute(attributeSpinalCase, `${value}`); - }); - } -}); diff --git a/packages/web-components/fast-foundation/src/anchor/anchor.template.ts b/packages/web-components/fast-foundation/src/anchor/anchor.template.ts deleted file mode 100644 index 6ef7f93c9b8..00000000000 --- a/packages/web-components/fast-foundation/src/anchor/anchor.template.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { ViewTemplate } from "@microsoft/fast-element"; -import { html, ref, slotted } from "@microsoft/fast-element"; -import { endSlotTemplate, startSlotTemplate } from "../patterns/index.js"; -import type { AnchorOptions, FASTAnchor } from "./anchor.js"; - -/** - * The template for the {@link @microsoft/fast-foundation#(FASTAnchor:class)} component. - * @public - */ -export function anchorTemplate( - options: AnchorOptions = {} -): ViewTemplate { - return html` -
- ${startSlotTemplate(options)} - - - - ${endSlotTemplate(options)} - - `; -} diff --git a/packages/web-components/fast-foundation/src/anchor/anchor.ts b/packages/web-components/fast-foundation/src/anchor/anchor.ts deleted file mode 100644 index 3b321d37511..00000000000 --- a/packages/web-components/fast-foundation/src/anchor/anchor.ts +++ /dev/null @@ -1,148 +0,0 @@ -import { attr, FASTElement, observable } from "@microsoft/fast-element"; -import { ARIAGlobalStatesAndProperties, StartEnd } from "../patterns/index.js"; -import type { StartEndOptions } from "../patterns/start-end.js"; -import { applyMixins } from "../utilities/apply-mixins.js"; -import type { AnchorTarget } from "./anchor.options.js"; - -/** - * Anchor configuration options - * @public - */ -export type AnchorOptions = StartEndOptions; - -/** - * An Anchor Custom HTML Element. - * Based largely on the {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a | element }. - * - * @slot start - Content which can be provided before the anchor content - * @slot end - Content which can be provided after the anchor content - * @slot - The default slot for anchor content - * @csspart control - The anchor element - * @csspart content - The element wrapping anchor content - * - * @public - */ -export class FASTAnchor extends FASTElement { - /** - * Prompts the user to save the linked URL. - * See {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a | element } for more information. - * @public - * @remarks - * HTML Attribute: download - */ - @attr - public download: string; - - /** - * The URL the hyperlink references. - * See {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a | element } for more information. - * @public - * @remarks - * HTML Attribute: href - */ - @attr - public href: string; - - /** - * Hints at the language of the referenced resource. - * See {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a | element } for more information. - * @public - * @remarks - * HTML Attribute: hreflang - */ - @attr - public hreflang: string; - - /** - * See {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a | element } for more information. - * @public - * @remarks - * HTML Attribute: ping - */ - @attr - public ping: string; - - /** - * See {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a | element } for more information. - * @public - * @remarks - * HTML Attribute: referrerpolicy - */ - @attr - public referrerpolicy: string; - - /** - * See {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a | element } for more information. - * @public - * @remarks - * HTML Attribute: rel - */ - @attr - public rel: string; - - /** - * See {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a | element } for more information. - * @public - * @remarks - * HTML Attribute: target - */ - @attr - public target: AnchorTarget; - - /** - * See {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a | element } for more information. - * @public - * @remarks - * HTML Attribute: type - */ - @attr - public type: string; - - /** - * - * Default slotted content - * - * @internal - */ - @observable - public defaultSlottedContent: HTMLElement[]; - - /** - * References the root element - */ - public control: HTMLAnchorElement; -} - -/** - * Includes ARIA states and properties relating to the ARIA link role - * - * @public - */ -export class DelegatesARIALink { - /** - * See {@link https://www.w3.org/WAI/PF/aria/roles#link} for more information - * @public - * @remarks - * HTML Attribute: aria-expanded - */ - @attr({ attribute: "aria-expanded" }) - public ariaExpanded: "true" | "false" | string | null; -} - -/** - * Mark internal because exporting class and interface of the same name - * confuses API documenter. - * TODO: https://github.com/microsoft/fast/issues/3317 - * @internal - */ -export interface DelegatesARIALink extends ARIAGlobalStatesAndProperties {} -applyMixins(DelegatesARIALink, ARIAGlobalStatesAndProperties); - -/** - * Mark internal because exporting class and interface of the same name - * confuses API documenter. - * TODO: https://github.com/microsoft/fast/issues/3317 - * @internal - */ -export interface FASTAnchor extends StartEnd, DelegatesARIALink {} -applyMixins(FASTAnchor, StartEnd, DelegatesARIALink); diff --git a/packages/web-components/fast-foundation/src/anchor/index.ts b/packages/web-components/fast-foundation/src/anchor/index.ts deleted file mode 100644 index b93278fb71c..00000000000 --- a/packages/web-components/fast-foundation/src/anchor/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { DelegatesARIALink, FASTAnchor } from "./anchor.js"; -export type { AnchorOptions } from "./anchor.js"; -export { AnchorTarget } from "./anchor.options.js"; -export { anchorTemplate } from "./anchor.template.js"; diff --git a/packages/web-components/fast-foundation/src/anchor/stories/anchor.register.ts b/packages/web-components/fast-foundation/src/anchor/stories/anchor.register.ts deleted file mode 100644 index 7cbfe7cd06a..00000000000 --- a/packages/web-components/fast-foundation/src/anchor/stories/anchor.register.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { css } from "@microsoft/fast-element"; -import { FASTAnchor } from "../anchor.js"; -import { anchorTemplate } from "../anchor.template.js"; - -const styles = css` - :host { - --shadow-spread: calc((var(--focus-stroke-width) - var(--stroke-width)) * 1px); - --base-size: calc((var(--base-height-multiplier)) * var(--design-unit) * 1px); - background-color: var(--neutral-fill-rest); - background: var(--accent-fill-rest); - border-radius: calc(var(--control-corner-radius) * 1px); - color: var(--foreground-on-accent-rest); - cursor: pointer; - display: inline-flex; - fill: currentcolor; - font-family: var(--body-font); - font-size: var(--type-ramp-base-font-size); - height: var(--base-size); - min-width: var(--base-size); - line-height: var(--type-ramp-base-line-height); - outline: none; - } - - .control { - all: inherit; - background: transparent; - flex-grow: 1; - box-sizing: border-box; - display: inline-flex; - justify-content: center; - align-items: center; - padding: 0 10px; - white-space: nowrap; - outline: none; - text-decoration: none; - border: calc(var(--stroke-width) * 1px) solid transparent; - } - - :host(:hover) { - background-color: var(--neutral-fill-hover); - } - - :host(:active) { - background-color: var(--neutral-fill-active); - } - - .control:focus-visible { - border-color: var(--focus-stroke-outer); - box-shadow: 0 0 0 var(--shadow-spread) var(--focus-stroke-outer) inset; - } - - .control::-moz-focus-inner { - border: 0; - } - - ::slotted([slot="start"]), - ::slotted([slot="content"]), - ::slotted([slot="end"]), - .content { - display: flex; - } - - .control.icon-only { - line-height: 0; - padding: 0; - } - - ::slotted([slot="start"]) { - margin-inline-end: 11px; - } - - ::slotted([slot="end"]) { - margin-inline-start: 11px; - } - - :host(:hover) { - background: var(--accent-fill-hover); - color: var(--foreground-on-accent-hover); - } - - :host(:active) .control:active { - background: var(--accent-fill-active); - color: var(--foreground-on-accent-active); - } -`; - -FASTAnchor.define({ - name: "fast-anchor", - template: anchorTemplate(), - styles, - shadowOptions: { - delegatesFocus: true, - }, -}); diff --git a/packages/web-components/fast-foundation/src/anchor/stories/anchor.stories.ts b/packages/web-components/fast-foundation/src/anchor/stories/anchor.stories.ts deleted file mode 100644 index d4c2a5a1331..00000000000 --- a/packages/web-components/fast-foundation/src/anchor/stories/anchor.stories.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { html } from "@microsoft/fast-element"; -import type { Meta, Story, StoryArgs } from "../../__test__/helpers.js"; -import { renderComponent } from "../../__test__/helpers.js"; -import type { FASTAnchor } from "../anchor.js"; -import { AnchorTarget } from "../anchor.options.js"; - -const storyTemplate = html>` - - ${x => x.storyContent} - -`; - -export default { - title: "Anchor", - argTypes: { - download: { control: "text" }, - href: { control: "text" }, - hreflang: { control: "text" }, - ping: { control: "text" }, - referrerpolicy: { control: "text" }, - rel: { control: "text" }, - target: { control: "select", options: Object.values(AnchorTarget) }, - type: { control: "text" }, - ariaAtomic: { control: "boolean" }, - ariaBusy: { control: "boolean" }, - ariaCurrent: { control: "text" }, - ariaControls: { control: "text" }, - ariaDescribedby: { control: "text" }, - ariaDisabled: { control: "text" }, - ariaDetails: { control: "text" }, - ariaErrormessage: { control: "text" }, - ariaExpanded: { control: "text" }, - ariaFlowto: { control: "text" }, - ariaHaspopup: { control: "boolean" }, - ariaHidden: { control: "boolean" }, - ariaInvalid: { control: "text" }, - ariaKeyshortcuts: { control: "text" }, - ariaLabel: { control: "text" }, - ariaLabelledby: { control: "text" }, - ariaLive: { control: "text" }, - ariaOwns: { control: "text" }, - ariaRelevant: { control: "text" }, - ariaRoledescription: { control: "text" }, - storyContent: { table: { disable: true } }, - }, -} as Meta; - -export const Anchor: Story = renderComponent(storyTemplate).bind({}); -Anchor.args = { - href: "https://www.fast.design/", - storyContent: "Anchor", -}; - -export const AnchorWithSlottedStartEnd: Story = renderComponent( - storyTemplate -).bind({}); -AnchorWithSlottedStartEnd.args = { - href: "https://www.fast.design/", - storyContent: html` - - Anchor - - `, -}; - -export const AnchorWithSlottedIconContent: Story = Anchor.bind({}); -AnchorWithSlottedIconContent.args = { - href: "https://www.fast.design/", - storyContent: html` - - `, -}; diff --git a/packages/web-components/fast-foundation/src/anchored-region/README.md b/packages/web-components/fast-foundation/src/anchored-region/README.md deleted file mode 100644 index 8113edce8aa..00000000000 --- a/packages/web-components/fast-foundation/src/anchored-region/README.md +++ /dev/null @@ -1,190 +0,0 @@ ---- -id: anchored-region -title: fast-anchored-region -sidebar_label: anchored-region -custom_edit_url: https://github.com/microsoft/fast/edit/master/packages/web-components/fast-foundation/src/anchored-region/README.md -description: fast-anchored-region is a container web component in which the contents of the anchored region can be positioned relative to another "anchor" element. ---- - -An *anchored region* is a container component which enables authors to create layouts where the contents of the anchored region can be positioned relative to another "anchor" element. Additionally, the *anchored region* can react to the available space between the anchor and a parent ["viewport"](https://developer.mozilla.org/en-US/docs/Glossary/viewport) element such that the region is placed on the side of the anchor with the most available space, or even resize itself based on that space. - -## Setup - -```ts -import { - provideFASTDesignSystem, - fastAnchoredRegion -} from "@microsoft/fast-components"; - -provideFASTDesignSystem() - .register( - fastAnchoredRegion() - ); -``` - -## Usage - -A region that always renders above the anchor element. - -```html live -
- - - This shows up above the button - -
-``` - -## Create your own design - -```ts -import { - AnchoredRegion, - anchoredRegionTemplate as template, -} from "@microsoft/fast-foundation"; -import { anchoredRegionStyles as styles } from "./my-anchored-region.styles"; - -export const myAnchoredRegion = AnchoredRegion.compose({ - baseName: "anchored-region", - template, - styles, -}); -``` - -## API - - - -### Variables - -| Name | Description | Type | -| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- | -| `FlyoutPosTop` | A region that always places itself above the anchor, has a width to match the anchor, and is sized vertically by content | `AnchoredRegionConfig` | -| `FlyoutPosBottom` | A region that always places itself below the anchor, has a width to match the anchor, and is sized vertically by content | `AnchoredRegionConfig` | -| `FlyoutPosTallest` | A region that places itself above or below the anchor based on available space, has a width to match the anchor, and is sized vertically by content | `AnchoredRegionConfig` | -| `FlyoutPosTopFill` | A region that always places itself above the anchor, has a width to match the anchor, and is sized vertically by available space | `AnchoredRegionConfig` | -| `FlyoutPosBottomFill` | A region that always places itself below the anchor, has a width to match the anchor, and is sized vertically by available space | `AnchoredRegionConfig` | -| `FlyoutPosTallestFill` | A region that places itself above or below the anchor based on available space, has a width to match the anchor, and is sized vertically by available space | `AnchoredRegionConfig` | - -
- - - -### Variables - -| Name | Description | Type | -| ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | -| `AxisPositioningMode` | Values to define the base behavior of an anchored region on a particular axis | `{ uncontrolled: "uncontrolled", locktodefault: "locktodefault", dynamic: "dynamic", }` | -| `AxisScalingMode` | Values to define the scaling behavior of an anchored region on a particular axis | `{ anchor: "anchor", content: "content", fill: "fill", }` | -| `HorizontalPosition` | Values for the horizontal positioning options for an anchored region | `{ start: "start", end: "end", left: "left", right: "right", center: "center", unset: "unset", }` | -| `VerticalPosition` | Values for the vertical positioning options for an anchored region | `{ top: "top", bottom: "bottom", center: "center", unset: "unset", }` | -| `AutoUpdateMode` | Defines if the component updates its position automatically. Calling update() always provokes an update. anchor - the component only updates its position when the anchor resizes (default) auto - the component updates its position when: - update() is called - the anchor resizes - the window resizes - the viewport resizes - any scroll event in the document | `{ anchor: "anchor", auto: "auto", }` | -| `AnchoredRegionPositionLabel` | Values to describe the possible positions of the region relative to its anchor. Depending on the axis start = left/top, end = right/bottom | `{ start: "start", insetStart: "insetStart", insetEnd: "insetEnd", end: "end", center: "center", }` | - -
- - - -### class: `FASTAnchoredRegion` - -#### Superclass - -| Name | Module | Package | -| ------------- | ------ | ----------------------- | -| `FASTElement` | | @microsoft/fast-element | - -#### Fields - -| Name | Privacy | Type | Default | Description | Inherited From | -| --------------------------- | ------- | ------------------------------------------ | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- | -| `anchor` | public | `string` | `""` | The HTML ID of the anchor element this region is positioned relative to | | -| `viewport` | public | `string` | `""` | The HTML ID of the viewport element this region is positioned relative to | | -| `horizontalPositioningMode` | public | `AxisPositioningMode` | `"uncontrolled"` | Sets what logic the component uses to determine horizontal placement. 'locktodefault' forces the default position 'dynamic' decides placement based on available space 'uncontrolled' does not control placement on the horizontal axis | | -| `horizontalDefaultPosition` | public | `HorizontalPosition` | `"unset"` | The default horizontal position of the region relative to the anchor element | | -| `horizontalViewportLock` | public | `boolean` | `false` | Whether the region remains in the viewport (ie. detaches from the anchor) on the horizontal axis | | -| `horizontalInset` | public | `boolean` | `false` | Whether the region overlaps the anchor on the horizontal axis | | -| `horizontalThreshold` | public | `number` | | How narrow the space allocated to the default position has to be before the widest area is selected for layout | | -| `horizontalScaling` | public | `AxisScalingMode` | `"content"` | Defines how the width of the region is calculated | | -| `verticalPositioningMode` | public | `AxisPositioningMode` | `"uncontrolled"` | Sets what logic the component uses to determine vertical placement. 'locktodefault' forces the default position 'dynamic' decides placement based on available space 'uncontrolled' does not control placement on the vertical axis | | -| `verticalDefaultPosition` | public | `VerticalPosition` | `"unset"` | The default vertical position of the region relative to the anchor element | | -| `verticalViewportLock` | public | `boolean` | `false` | Whether the region remains in the viewport (ie. detaches from the anchor) on the vertical axis | | -| `verticalInset` | public | `boolean` | `false` | Whether the region overlaps the anchor on the vertical axis | | -| `verticalThreshold` | public | `number` | | How short the space allocated to the default position has to be before the tallest area is selected for layout | | -| `verticalScaling` | public | `AxisScalingMode` | `"content"` | Defines how the height of the region is calculated | | -| `fixedPlacement` | public | `boolean` | `false` | Whether the region is positioned using css "position: fixed". Otherwise the region uses "position: absolute". Fixed placement allows the region to break out of parent containers, | | -| `autoUpdateMode` | public | `AutoUpdateMode` | `"anchor"` | Defines what triggers the anchored region to revaluate positioning | | -| `anchorElement` | public | `HTMLElement or null` | `null` | The HTML element being used as the anchor | | -| `viewportElement` | public | `HTMLElement or null` | `null` | The HTML element being used as the viewport | | -| `verticalPosition` | public | `AnchoredRegionPositionLabel or undefined` | | indicates the current horizontal position of the region | | -| `horizontalPosition` | public | `AnchoredRegionPositionLabel or undefined` | | indicates the current vertical position of the region | | -| `update` | public | | | update position | | - -#### Methods - -| Name | Privacy | Description | Parameters | Return | Inherited From | -| ---------------------------------- | --------- | ----------- | --------------------------------------------------- | ------ | -------------- | -| `anchorChanged` | protected | | | `void` | | -| `viewportChanged` | protected | | | `void` | | -| `horizontalPositioningModeChanged` | protected | | | `void` | | -| `horizontalDefaultPositionChanged` | protected | | | `void` | | -| `horizontalViewportLockChanged` | protected | | | `void` | | -| `horizontalInsetChanged` | protected | | | `void` | | -| `horizontalThresholdChanged` | protected | | | `void` | | -| `horizontalScalingChanged` | protected | | | `void` | | -| `verticalPositioningModeChanged` | protected | | | `void` | | -| `verticalDefaultPositionChanged` | protected | | | `void` | | -| `verticalViewportLockChanged` | protected | | | `void` | | -| `verticalInsetChanged` | protected | | | `void` | | -| `verticalThresholdChanged` | protected | | | `void` | | -| `verticalScalingChanged` | protected | | | `void` | | -| `fixedPlacementChanged` | protected | | | `void` | | -| `autoUpdateModeChanged` | protected | | `prevMode: AutoUpdateMode, newMode: AutoUpdateMode` | `void` | | -| `anchorElementChanged` | protected | | | `void` | | -| `viewportElementChanged` | protected | | | `void` | | - -#### Events - -| Name | Type | Description | Inherited From | -| ---------------- | ---- | ------------------------------------------------------------------- | -------------- | -| `loaded` | | Fires a custom 'loaded' event when the region is loaded and visible | | -| `positionchange` | | Fires a custom 'positionchange' event when the position has changed | | - -#### Attributes - -| Name | Field | Inherited From | -| ----------------------------- | ------------------------- | -------------- | -| `anchor` | anchor | | -| `viewport` | viewport | | -| `horizontal-positioning-mode` | horizontalPositioningMode | | -| `horizontal-default-position` | horizontalDefaultPosition | | -| `horizontal-viewport-lock` | horizontalViewportLock | | -| `horizontal-inset` | horizontalInset | | -| `horizontal-threshold` | horizontalThreshold | | -| `horizontal-scaling` | horizontalScaling | | -| `vertical-positioning-mode` | verticalPositioningMode | | -| `vertical-default-position` | verticalDefaultPosition | | -| `vertical-viewport-lock` | verticalViewportLock | | -| `vertical-inset` | verticalInset | | -| `vertical-threshold` | verticalThreshold | | -| `vertical-scaling` | verticalScaling | | -| `fixed-placement` | fixedPlacement | | -| `auto-update-mode` | autoUpdateMode | | - -#### Slots - -| Name | Description | -| ---- | -------------------------------- | -| | The default slot for the content | - -
- - -## Additional resources - -* [Component explorer examples](https://explore.fast.design/components/fast-anchored-region) -* [Component technical specification](https://github.com/microsoft/fast/blob/master/packages/web-components/fast-foundation/src/anchored-region/anchored-region.spec.md) \ No newline at end of file diff --git a/packages/web-components/fast-foundation/src/anchored-region/anchored-region-config.ts b/packages/web-components/fast-foundation/src/anchored-region/anchored-region-config.ts deleted file mode 100644 index 378f70ffccb..00000000000 --- a/packages/web-components/fast-foundation/src/anchored-region/anchored-region-config.ts +++ /dev/null @@ -1,184 +0,0 @@ -import type { - AutoUpdateMode, - AxisPositioningMode, - AxisScalingMode, - HorizontalPosition, - VerticalPosition, -} from "./anchored-region.options.js"; - -/** - * A utility interface to store anchored region - * configurations that correspond to various common flyout - * positioning schemes - * - * @public - */ -export interface AnchoredRegionConfig { - /** - * Whether the region is positioned using css "position: fixed". - * Otherwise the region uses "position: absolute". - * Fixed placement allows the region to break out of parent containers, - */ - readonly fixedPlacement?: boolean; - - /** - * The auto-update setting of the component - */ - readonly autoUpdateMode?: AutoUpdateMode; - - /** - * Sets what logic the component uses to determine vertical placement. - */ - readonly verticalPositioningMode?: AxisPositioningMode; - - /** - * The default vertical position of the region relative to the anchor element - */ - readonly verticalDefaultPosition?: VerticalPosition; - - /** - * Whether the region overlaps the anchor on the vertical axis - */ - readonly verticalInset?: boolean; - - /** - * Defines how the height of the region is calculated - */ - readonly verticalScaling?: AxisScalingMode; - - /** - * How short the space allocated to the default position has to be before the tallest area - * is selected for layout - */ - readonly verticalThreshold?: number; - - /** - * Whether the region remains in the viewport (ie. detaches from the anchor) on the vertical axis - */ - readonly verticalViewportLock?: boolean; - - /** - * Sets what logic the component uses to determine horizontal placement. - */ - readonly horizontalPositioningMode?: AxisPositioningMode; - - /** - * The default horizontal position of the region relative to the anchor element - */ - readonly horizontalDefaultPosition?: HorizontalPosition; - - /** - * hether the region overlaps the anchor on the horizontal axis - */ - readonly horizontalInset?: boolean; - - /** - * Defines how the width of the region is calculate - */ - readonly horizontalScaling?: AxisScalingMode; - - /** - * Whether the region remains in the viewport (ie. detaches from the anchor) on the horizontal axis - */ - readonly horizontalViewportLock?: boolean; - - /** - * How short the space allocated to the default position has to be before the widest area - * is selected for layout - */ - readonly horizontalThreshold?: number; -} - -/** - * Building blocks - partial configs - */ - -/** - * A region that matches the size and position of the anchor horizontally - */ -const horizontalAnchorOverlay: AnchoredRegionConfig = { - horizontalDefaultPosition: "center", - horizontalPositioningMode: "locktodefault", - horizontalInset: false, - horizontalScaling: "anchor", -}; - -/** - * Exported configs - */ - -/** - * A region that always places itself above the anchor, has - * a width to match the anchor, and is sized vertically by content - * - * @public - */ -export const FlyoutPosTop: AnchoredRegionConfig = { - ...horizontalAnchorOverlay, - verticalDefaultPosition: "top", - verticalPositioningMode: "locktodefault", - verticalInset: false, - verticalScaling: "content", -}; - -/** - * A region that always places itself below the anchor, has - * a width to match the anchor, and is sized vertically by content - * - * @public - */ -export const FlyoutPosBottom: AnchoredRegionConfig = { - ...horizontalAnchorOverlay, - verticalDefaultPosition: "bottom", - verticalPositioningMode: "locktodefault", - verticalInset: false, - verticalScaling: "content", -}; - -/** - * A region that places itself above or below the anchor - * based on available space, has a width to match the anchor, - * and is sized vertically by content - * - * @public - */ -export const FlyoutPosTallest: AnchoredRegionConfig = { - ...horizontalAnchorOverlay, - verticalPositioningMode: "dynamic", - verticalInset: false, - verticalScaling: "content", -}; - -/** - * A region that always places itself above the anchor, has - * a width to match the anchor, and is sized vertically by available space - * - * @public - */ -export const FlyoutPosTopFill: AnchoredRegionConfig = { - ...FlyoutPosTop, - verticalScaling: "fill", -}; - -/** - * A region that always places itself below the anchor, has - * a width to match the anchor, and is sized vertically by available space - * - * @public - */ -export const FlyoutPosBottomFill: AnchoredRegionConfig = { - ...FlyoutPosBottom, - verticalScaling: "fill", -}; - -/** - * A region that places itself above or below the anchor - * based on available space, has a width to match the anchor, - * and is sized vertically by available space - * - * @public - */ -export const FlyoutPosTallestFill: AnchoredRegionConfig = { - ...FlyoutPosTallest, - verticalScaling: "fill", -}; diff --git a/packages/web-components/fast-foundation/src/anchored-region/anchored-region.options.ts b/packages/web-components/fast-foundation/src/anchored-region/anchored-region.options.ts deleted file mode 100644 index 035c711d088..00000000000 --- a/packages/web-components/fast-foundation/src/anchored-region/anchored-region.options.ts +++ /dev/null @@ -1,124 +0,0 @@ -import type { ValuesOf } from "../utilities/index.js"; - -/** - * Values to define the base behavior of an anchored region on a particular axis - * @public - */ -export const AxisPositioningMode = { - uncontrolled: "uncontrolled", - locktodefault: "locktodefault", - dynamic: "dynamic", -} as const; - -/** - * Type to define the base behavior of an anchored region on a particular axis - * @public - */ -export type AxisPositioningMode = ValuesOf; - -/** - * Values to define the scaling behavior of an anchored region on a particular axis - * @public - */ -export const AxisScalingMode = { - anchor: "anchor", - content: "content", - fill: "fill", -} as const; - -/** - * Type to define the scaling behavior of an anchored region on a particular axis - * - * @public - */ -export type AxisScalingMode = ValuesOf; - -/** - * Values for the horizontal positioning options for an anchored region - * @public - */ -export const HorizontalPosition = { - start: "start", - end: "end", - left: "left", - right: "right", - center: "center", - unset: "unset", -} as const; - -/** - * Type for the horizontal positioning options for an anchored region - * - * @public - */ -export type HorizontalPosition = ValuesOf; - -/** - * Values for the vertical positioning options for an anchored region - * @public - */ -export const VerticalPosition = { - top: "top", - bottom: "bottom", - center: "center", - unset: "unset", -} as const; - -/** - * Type for the vertical positioning options for an anchored region - * - * @public - */ -export type VerticalPosition = ValuesOf; - -/** - * Defines if the component updates its position automatically. Calling update() always provokes an update. - * anchor - the component only updates its position when the anchor resizes (default) - * auto - the component updates its position when: - * - update() is called - * - the anchor resizes - * - the window resizes - * - the viewport resizes - * - any scroll event in the document - * - * @public - */ -export const AutoUpdateMode = { - anchor: "anchor", - auto: "auto", -} as const; - -/** - * Type for the auto update mode values - * @public - */ -export type AutoUpdateMode = ValuesOf; - -/** - * Values to describe the possible positions of the region relative to its anchor. - * Depending on the axis start = left/top, end = right/bottom - * @public - */ -export const AnchoredRegionPositionLabel = { - start: "start", - insetStart: "insetStart", - insetEnd: "insetEnd", - end: "end", - center: "center", -} as const; - -/** - * Describes the possible positions of the region relative - * to its anchor. Depending on the axis start = left/top, end = right/bottom - * - * @public - */ -export type AnchoredRegionPositionLabel = ValuesOf; - -/** - * @internal - */ -export interface Dimension { - height: number; - width: number; -} diff --git a/packages/web-components/fast-foundation/src/anchored-region/anchored-region.pw.spec.ts b/packages/web-components/fast-foundation/src/anchored-region/anchored-region.pw.spec.ts deleted file mode 100644 index 59701a28511..00000000000 --- a/packages/web-components/fast-foundation/src/anchored-region/anchored-region.pw.spec.ts +++ /dev/null @@ -1,83 +0,0 @@ -import type { Locator, Page } from "@playwright/test"; -import { expect, test } from "@playwright/test"; -import { fixtureURL } from "../__test__/helpers.js"; -import type { FASTAnchoredRegion } from "./anchored-region.js"; - -test.describe("Anchored Region", () => { - let page: Page; - let element: Locator; - let root: Locator; - - test.beforeAll(async ({ browser }) => { - page = await browser.newPage(); - - element = page.locator("fast-anchored-region"); - - root = page.locator("#storybook-root"); - - await page.goto(fixtureURL("anchored-region--anchored-region")); - - await element.waitFor({ state: "visible" }); - }); - - test.afterAll(async () => { - await page.close(); - }); - - test("should set positioning modes to 'uncontrolled' by default", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element).toHaveJSProperty("verticalPositioningMode", "uncontrolled"); - - await expect(element).toHaveJSProperty( - "horizontalPositioningMode", - "uncontrolled" - ); - }); - - test("should assign anchor and viewport elements by id", async () => { - const anchorId = "anchor"; - - await root.evaluate( - (node, { anchorId }) => { - node.innerHTML = /* html */ ` -
- - `; - }, - { anchorId } - ); - - await expect(element).toHaveAttribute("anchor", anchorId); - - await expect(element).toHaveJSProperty("anchor", anchorId); - - const anchorElementId = await element.evaluate( - (node: FASTAnchoredRegion) => node.anchorElement?.id - ); - - expect(anchorElementId).toBe(anchorId); - }); - - test("should be sized to match content by default", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - -
-
- `; - }); - - const elementClientHeight = await element.evaluate(node => node.clientHeight); - - const content = element.locator("#content"); - - const contentClientHeight = await content.evaluate(node => node.clientHeight); - - expect(elementClientHeight).toBe(contentClientHeight); - }); -}); diff --git a/packages/web-components/fast-foundation/src/anchored-region/anchored-region.spec.md b/packages/web-components/fast-foundation/src/anchored-region/anchored-region.spec.md deleted file mode 100644 index 52fad65385a..00000000000 --- a/packages/web-components/fast-foundation/src/anchored-region/anchored-region.spec.md +++ /dev/null @@ -1,270 +0,0 @@ -# Anchored region - -## Overview - -An *anchored region* is a container component which enables authors to create layouts where the contents of the anchored region can be positioned relative to another "anchor" element. Additionally, the *anchored region* can react to the available space between the anchor and a parent ["viewport"](https://developer.mozilla.org/en-US/docs/Glossary/viewport) element such that the region is placed on the side of the anchor with the most available space, or even resize itself based on that space. - -### Use Cases - -It is envisioned that this component would be used as a building block for other components in this library that need to position elements relative to another HTMLElement(select, flyout, tooltip, etc) as well as being available for standalone use in responsive layouts. - -### Features - -- **Relative positioning:** -Authors can use it to position an element relative to another another element, like enabling a menu to open above or below a trigger button. Additionally, the same anchored region can change which element it is anchored to dynamically, for example a single tooltip instance in a page could be positioned next to any other element on the page by switching the anchor property of the anchored region that contains it. - -- **Responsive positioning:** -Authors can use it to position an element relative to another element based on available space, for example a menu could open upwards if the trigger button is near the bottom of the page, and downwards if it is nearer the top. Authors can call the component's update() function to reevaluate positioning. - -- **Responsive scaling:** -Authors can use it to create a layout region that dynamically sizes depending on space between the anchor and the viewport elements. - -- **Auto updating** -Authors can control when the component updates its position after the initial render. - -For a more in-depth understanding of how this component works under the covers please refer to the [intersection observer api](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API). - - - -### Risks and Challenges -- must keep an eye on performance - ---- - -## Design - -### Relative placement: 'Inset' vs 'Adjacent'; -By default the anchored region is positioned adjacent to the element it is anchored to, but if the "horizontal-inset" or "vertical-inset" attributes are set then the region will be 'inset' and overlap the anchor on that axis. Various combinations of these attributes can enable some commonly desired layouts. In the following images the menu would be considered to be the *anchored region* and the "Select an option" button the anchor. - -| State | Image | -| ----- | ----- | -| Adjacent vertically and inset horizontally can be used for a typical drop down menu: | ![](./images/inset-adjacent.png) | -| Inset vertically and adjacent horizontally positions the region to the side of the anchor button: | ![](./images/adjacent-inset.png) | -| Inset on both axis positions the region so that it overlaps the anchor: | ![](./images/inset-inset.png) | -| Adjacent on both axis positions the region diagonally to the anchor: | ![](./images/adjacent-adjacent.png)| - - - -### Markup Examples -(note: examples are for the vertical axis, equivalent is true for horizontal) - -A region that always renders above the anchor element. -``` -
- ...stuff... - - - This shows up above the button - - ...stuff... -
- -``` - -A region that renders above or below the anchor depending on available space. -``` -
- ...stuff... - - - This shows up above or below the anchor depending on available space - - ...stuff... -
- -``` - -A region that renders above or below the anchor depending on available space but only on initial layout. -``` -
- ...stuff... - - - This shows up above or below the anchor depending on available space - - ...stuff... -
- -``` - -A region that overlaps the anchor and renders above or below it depending on available space. - -``` -
- ...stuff... - - - This overlaps the anchor and extends above or below it depending on available space. - - ...stuff... -
- -``` - -A region renders above or below the anchor based on available space and is sized to match the available. - -``` -
- ...stuff... - - - This region renders above or below the anchor based on available space and sizes itself to match. - - ...stuff... -
- -``` - -A region that renders below the anchor until that space is less than 100px. -``` -
- ...stuff... - - - This shows renders below the anchor as long as there is at least 100px available there. - - ...stuff... -
-``` - -The anchored region can be configured to scale to either the size of the content in its slot, to the size of the element it is anchored to, or the available space between the anchor and the edge of the viewport element by setting the vertical/horizontal scaling attribute: -- "anchor" - size to match anchor -- "fill" - size to match space between the anchor and the viewport edge. When the region is centered it will scale to remain centered on the anchor but remain inside the viewport, when centered with viewport lock the region will fill the viewport on that axis. -- "content" - the default, matches the size of the content in the region's slot. - -The dimensions of the anchored region will match the dimensions of the content unless scaling is enabled on a particular axis (verticalscalingenabled & horizontalscalingenabled) in which case it will fill all available space between the anchor and viewport. - -The component allows users to set a "Positioning Mode" on each axis which defines how the component will behave: -- 'uncontrolled': The anchored region will appear as it normally would in document flow. -- 'locktodefault': The anchored region will always be placed in the specified default position regardless of available space. For example a menu that always opens upwards. -- 'dynamic': The anchored region is placed relative to the anchor element based on how much space is available between it and the viewport. For example a menu that opens opens upwards when it is near the bottom of the page, and downwards when near the top. When the region's default position is set to 'center' dynamic positioning mode has no effect (ie. the region is always centered). - -### API - -NOTE: this component api will not be exposed outside of the fast-components package until we are satisfied that we have the correct implementation for this functionality. - -*Component name:* -- `fast-anchored-region` - -*Attributes:* -- anchor - The html id of the HTMLElement used as the anchor around which the positioning region is placed. This must be set for the component's positioning logic to be active. The component will first check for the element id in the local shadow DOM followed by the document light DOM. - -- viewport - The ID of the HTMLElement to be used as the viewport used to determine available layout space around the anchor element. If unset the parent element of the anchored region is used. - -- horizontal-positioning-mode - Can be 'uncontrolled', 'locktodefault' or 'dynamic'. Default is 'uncontrolled'. -- horizontal-default-position - Can be 'start', 'end', 'left', 'right', 'center' or 'unset'. Default is 'unset'. When default position is set to 'center' the 'dynamic' positioning mode has no effect. -- horizontal-inset - Boolean that indicates whether the region should overlap the anchor on the horizontal axis. Default is false which places the region adjacent to the anchor element. -- horizontal-threshold - Numeric value that defines how small in pixels the region must be to the edge of the viewport to switch to the opposite side of the anchor. The component favors the default position until this value is crossed. When there is not enough space on either side or the value is unset the side with the most space is chosen. -- horizontal-scaling - Can be "anchor", "fill" or "content". Default is "content" - -- vertical-positioning-mode - Can be 'uncontrolled', 'locktodefault' or 'dynamic'. Default is 'uncontrolled'. -- vertical-default-position - Can be 'top', 'bottom', 'center' or 'unset'. Default is unset. When default position is set to 'center' the 'dynamic' positioning mode has no effect. -- vertical-inset - Boolean that indicates whether the region should overlap the anchor on the vertical axis. Default is false which places the region adjacent to the anchor element. -- vertical-threshold - Numeric value that defines how small the region must be to the edge of the viewport to switch to the opposite side of the anchor. The component favors the default position until this value is crossed. When there is not enough space on either side or the value is unset the side with the most space is chosen. -- vertical-scaling - Can be 'anchor', 'fill' or 'content'. Default is 'content' -- auto-update-mode - Can be 'anchor' or 'auto'. Default is 'anchor'. In 'anchor' mode only anchor resizes and attribute changes will provoke an update. In 'auto' mode the component also updates because of - any scroll event on the document, window resizes and viewport resizes. Authors can always provoke an update via the 'update()' function. - -*Properties:* -- anchorElement - Holds a reference to the HTMLElement currently being used as the anchor. Can be set directly or be populated by setting the anchor attribute. - -- viewportElement - Holds a reference to the HTMLElement currently being used as the viewport. Can be set directly or be populated by setting the anchor attribute. - -*Slots:* -- default slot for content - -*functions:* -- updateAnchorOffset = ( - horizontalOffsetDelta: number, - verticalOffsetDelta: number -) - -*Events:* -- loaded - The contents of the anchored region are loaded into the DOM. -- positionchange - The positioning of the anchored region has changed. - - -Enables developers to update the offset between the anchor and the region as it changes, for example to promt layout recalculations as a result of scrolling so a scaling region tracks the viewport boundary. - - - -### Anatomy and Appearance -**Structure:** - -The anchored region is essentially a container around the slotted items. - -``` - -``` - -## Implementation - -### States -Positioning update checks in the component happen when: -- an attribute or property is changed on the component -- the component's "update()" function is called -- resize observer reports a resize event on the anchor or the component itself. - -These layout checks analyse the DOM geometry based on callbacks and repositions the anchored region appropriately: top/bottom/unset for the vertical axis and left/right/unset for the horizontal axis. - -The component will have an initialization state to determine placement where the instantiation of content will be delayed by one frame to give the component a chance to get placed correctly. This is to avoid content triggering the browser's scroll into view behavior prematurely if a contained element gains focus immediately. - -### Accessibility -None required. Basically a positioned div that authors can decorate for accessibility if required. - -### Globalization -Authors may want to change default position from left to right or vice versa based on rtl settings, but that can't be predicted by the component itself. - -### Performance -The component uses [IntersectionObserver](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver) events to determine positioning rather than more demanding calls to getBoundingClientRect. Further performance improvements, like perhaps sharing a singleton intersection observer instance across anchored regions, should be considered. - -### Dependencies -[IntersectionObserver api](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver) is unsupported on IE, and [ResizeObserver](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver) is unsupported on IE, Safari and Firefox. Both are required by the component. Authors who wish to use this component on these platforms will need to use polyfills. - - -### Test Plan -TBD - -## Next Steps -- investigate perf improvements diff --git a/packages/web-components/fast-foundation/src/anchored-region/anchored-region.template.ts b/packages/web-components/fast-foundation/src/anchored-region/anchored-region.template.ts deleted file mode 100644 index 4d48cc08a27..00000000000 --- a/packages/web-components/fast-foundation/src/anchored-region/anchored-region.template.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { ElementViewTemplate } from "@microsoft/fast-element"; -import { html, when } from "@microsoft/fast-element"; -import type { FASTAnchoredRegion } from "./anchored-region.js"; - -/** - * The template for the {@link @microsoft/fast-foundation#(FASTAnchoredRegion:class)} component. - * @public - */ -export function anchoredRegionTemplate< - T extends FASTAnchoredRegion ->(): ElementViewTemplate { - return html` - - `; -} diff --git a/packages/web-components/fast-foundation/src/anchored-region/anchored-region.ts b/packages/web-components/fast-foundation/src/anchored-region/anchored-region.ts deleted file mode 100644 index a7b3b512df1..00000000000 --- a/packages/web-components/fast-foundation/src/anchored-region/anchored-region.ts +++ /dev/null @@ -1,1279 +0,0 @@ -import { attr, FASTElement, observable, Updates } from "@microsoft/fast-element"; -import { Direction, eventResize, eventScroll } from "@microsoft/fast-web-utilities"; -import { getDirection } from "../utilities/direction.js"; -import { IntersectionService } from "../utilities/intersection-service.js"; -import type { - ResizeObserverClassDefinition, - ResizeObserverEntry, -} from "../utilities/resize-observer.js"; -import type { - AnchoredRegionPositionLabel, - AutoUpdateMode, - AxisPositioningMode, - AxisScalingMode, - Dimension, - HorizontalPosition, - VerticalPosition, -} from "./anchored-region.options.js"; - -/** - * An anchored region Custom HTML Element. - * - * @slot - The default slot for the content - * @fires loaded - Fires a custom 'loaded' event when the region is loaded and visible - * @fires positionchange - Fires a custom 'positionchange' event when the position has changed - * - * @public - */ -export class FASTAnchoredRegion extends FASTElement { - /** - * The HTML ID of the anchor element this region is positioned relative to - * - * @public - * @remarks - * HTML Attribute: anchor - */ - @attr - public anchor: string = ""; - protected anchorChanged(): void { - if (this.initialLayoutComplete) { - this.anchorElement = this.getAnchor(); - } - } - - /** - * The HTML ID of the viewport element this region is positioned relative to - * - * @public - * @remarks - * HTML Attribute: anchor - */ - @attr - public viewport: string = ""; - protected viewportChanged(): void { - if (this.initialLayoutComplete) { - this.viewportElement = this.getViewport(); - } - } - - /** - * Sets what logic the component uses to determine horizontal placement. - * 'locktodefault' forces the default position - * 'dynamic' decides placement based on available space - * 'uncontrolled' does not control placement on the horizontal axis - * - * @public - * @remarks - * HTML Attribute: horizontal-positioning-mode - */ - @attr({ attribute: "horizontal-positioning-mode" }) - public horizontalPositioningMode: AxisPositioningMode = "uncontrolled"; - protected horizontalPositioningModeChanged(): void { - this.requestReset(); - } - - /** - * The default horizontal position of the region relative to the anchor element - * - * @public - * @remarks - * HTML Attribute: horizontal-default-position - */ - @attr({ attribute: "horizontal-default-position" }) - public horizontalDefaultPosition: HorizontalPosition = "unset"; - protected horizontalDefaultPositionChanged(): void { - this.updateForAttributeChange(); - } - - /** - * Whether the region remains in the viewport (ie. detaches from the anchor) on the horizontal axis - * - * @public - * @remarks - * HTML Attribute: horizontal-viewport-lock - */ - @attr({ attribute: "horizontal-viewport-lock", mode: "boolean" }) - public horizontalViewportLock: boolean = false; - protected horizontalViewportLockChanged(): void { - this.updateForAttributeChange(); - } - - /** - * Whether the region overlaps the anchor on the horizontal axis - * - * @public - * @remarks - * HTML Attribute: horizontal-inset - */ - @attr({ attribute: "horizontal-inset", mode: "boolean" }) - public horizontalInset: boolean = false; - protected horizontalInsetChanged(): void { - this.updateForAttributeChange(); - } - - /** - * How narrow the space allocated to the default position has to be before the widest area - * is selected for layout - * - * @public - * @remarks - * HTML Attribute: horizontal-threshold - */ - @attr({ attribute: "horizontal-threshold" }) - public horizontalThreshold: number; - protected horizontalThresholdChanged(): void { - this.updateForAttributeChange(); - } - - /** - * Defines how the width of the region is calculated - * - * @public - * @remarks - * HTML Attribute: horizontal-scaling - */ - @attr({ attribute: "horizontal-scaling" }) - public horizontalScaling: AxisScalingMode = "content"; - protected horizontalScalingChanged(): void { - this.updateForAttributeChange(); - } - - /** - * Sets what logic the component uses to determine vertical placement. - * 'locktodefault' forces the default position - * 'dynamic' decides placement based on available space - * 'uncontrolled' does not control placement on the vertical axis - * - * @public - * @remarks - * HTML Attribute: vertical-positioning-mode - */ - @attr({ attribute: "vertical-positioning-mode" }) - public verticalPositioningMode: AxisPositioningMode = "uncontrolled"; - protected verticalPositioningModeChanged(): void { - this.requestReset(); - } - - /** - * The default vertical position of the region relative to the anchor element - * - * @public - * @remarks - * HTML Attribute: vertical-default-position - */ - @attr({ attribute: "vertical-default-position" }) - public verticalDefaultPosition: VerticalPosition = "unset"; - protected verticalDefaultPositionChanged(): void { - this.updateForAttributeChange(); - } - - /** - * Whether the region remains in the viewport (ie. detaches from the anchor) on the vertical axis - * - * @public - * @remarks - * HTML Attribute: vertical-viewport-lock - */ - @attr({ attribute: "vertical-viewport-lock", mode: "boolean" }) - public verticalViewportLock: boolean = false; - protected verticalViewportLockChanged(): void { - this.updateForAttributeChange(); - } - - /** - * Whether the region overlaps the anchor on the vertical axis - * - * @public - * @remarks - * HTML Attribute: vertical-inset - */ - @attr({ attribute: "vertical-inset", mode: "boolean" }) - public verticalInset: boolean = false; - protected verticalInsetChanged(): void { - this.updateForAttributeChange(); - } - - /** - * How short the space allocated to the default position has to be before the tallest area - * is selected for layout - * - * @public - * @remarks - * HTML Attribute: vertical-threshold - */ - @attr({ attribute: "vertical-threshold" }) - public verticalThreshold: number; - protected verticalThresholdChanged(): void { - this.updateForAttributeChange(); - } - - /** - * Defines how the height of the region is calculated - * - * @public - * @remarks - * HTML Attribute: vertical-scaling - */ - @attr({ attribute: "vertical-scaling" }) - public verticalScaling: AxisScalingMode = "content"; - protected verticalScalingChanged(): void { - this.updateForAttributeChange(); - } - - /** - * Whether the region is positioned using css "position: fixed". - * Otherwise the region uses "position: absolute". - * Fixed placement allows the region to break out of parent containers, - * - * @public - * @remarks - * HTML Attribute: fixed-placement - */ - @attr({ attribute: "fixed-placement", mode: "boolean" }) - public fixedPlacement: boolean = false; - protected fixedPlacementChanged(): void { - if (this.$fastController.isConnected && this.initialLayoutComplete) { - this.initialize(); - } - } - - /** - * Defines what triggers the anchored region to revaluate positioning - * - * @public - * @remarks - * HTML Attribute: auto-update-mode - */ - @attr({ attribute: "auto-update-mode" }) - public autoUpdateMode: AutoUpdateMode = "anchor"; - protected autoUpdateModeChanged( - prevMode: AutoUpdateMode, - newMode: AutoUpdateMode - ): void { - if (this.$fastController.isConnected && this.initialLayoutComplete) { - if (prevMode === "auto") { - this.stopAutoUpdateEventListeners(); - } - - if (newMode === "auto") { - this.startAutoUpdateEventListeners(); - } - } - } - - /** - * The HTML element being used as the anchor - * - * @public - */ - @observable - public anchorElement: HTMLElement | null = null; - protected anchorElementChanged(): void { - this.requestReset(); - } - - /** - * The HTML element being used as the viewport - * - * @public - */ - @observable - public viewportElement: HTMLElement | null = null; - protected viewportElementChanged(): void { - if (this.$fastController.isConnected && this.initialLayoutComplete) { - this.initialize(); - } - } - - /** - * indicates that an initial positioning pass on layout has completed - * - * @internal - */ - @observable - public initialLayoutComplete: boolean = false; - - /** - * indicates the current horizontal position of the region - */ - public verticalPosition: AnchoredRegionPositionLabel | undefined; - - /** - * indicates the current vertical position of the region - */ - public horizontalPosition: AnchoredRegionPositionLabel | undefined; - - /** - * values to be applied to the component's transform on render - */ - private translateX: number; - private translateY: number; - - /** - * the span to be applied to the region on each axis - */ - private regionWidth: string; - private regionHeight: string; - - private resizeDetector: ResizeObserverClassDefinition | null = null; - - private viewportRect: ClientRect | DOMRect | undefined; - private anchorRect: ClientRect | DOMRect | undefined; - private regionRect: ClientRect | DOMRect | undefined; - - /** - * base offsets between the positioner's base position and the anchor's - */ - private baseHorizontalOffset: number = 0; - private baseVerticalOffset: number = 0; - - private pendingPositioningUpdate: boolean = false; - private pendingReset: boolean = false; - private currentDirection: Direction = Direction.ltr; - private regionVisible: boolean = false; - - // indicates that a layout update should occur even if geometry has not changed - // used to ensure some attribute changes are applied - private forceUpdate: boolean = false; - - // defines how big a difference in pixels there must be between states to - // justify a layout update that affects the dom (prevents repeated sub-pixel corrections) - private updateThreshold: number = 0.5; - - private static intersectionService: IntersectionService = new IntersectionService(); - - /** - * @internal - */ - connectedCallback() { - super.connectedCallback(); - if (this.autoUpdateMode === "auto") { - this.startAutoUpdateEventListeners(); - } - this.initialize(); - } - - /** - * @internal - */ - public disconnectedCallback(): void { - super.disconnectedCallback(); - if (this.autoUpdateMode === "auto") { - this.stopAutoUpdateEventListeners(); - } - this.stopObservers(); - this.disconnectResizeDetector(); - } - - /** - * @internal - */ - public adoptedCallback() { - this.initialize(); - } - - /** - * update position - */ - public update = (): void => { - if (!this.pendingPositioningUpdate) { - this.requestPositionUpdates(); - } - }; - - /** - * destroys the instance's resize observer - */ - private disconnectResizeDetector(): void { - if (this.resizeDetector !== null) { - this.resizeDetector.disconnect(); - this.resizeDetector = null; - } - } - - /** - * initializes the instance's resize observer - */ - private initializeResizeDetector(): void { - this.disconnectResizeDetector(); - this.resizeDetector = new ( - window as unknown as WindowWithResizeObserver - ).ResizeObserver(this.handleResize); - } - - /** - * react to attribute changes that don't require a reset - */ - private updateForAttributeChange(): void { - if (this.$fastController.isConnected && this.initialLayoutComplete) { - this.forceUpdate = true; - this.update(); - } - } - - /** - * fully initializes the component - */ - private initialize(): void { - this.initializeResizeDetector(); - if (this.anchorElement === null) { - this.anchorElement = this.getAnchor(); - } - this.requestReset(); - } - - /** - * Request a reset if there are currently no open requests - */ - private requestReset(): void { - if (this.$fastController.isConnected && this.pendingReset === false) { - this.setInitialState(); - Updates.enqueue(() => this.reset()); - this.pendingReset = true; - } - } - - /** - * sets the starting configuration for component internal values - */ - private setInitialState(): void { - this.initialLayoutComplete = false; - this.regionVisible = false; - this.translateX = 0; - this.translateY = 0; - - this.baseHorizontalOffset = 0; - this.baseVerticalOffset = 0; - - this.viewportRect = undefined; - this.regionRect = undefined; - this.anchorRect = undefined; - - this.verticalPosition = undefined; - this.horizontalPosition = undefined; - - this.style.opacity = "0"; - this.style.pointerEvents = "none"; - - this.forceUpdate = false; - - this.style.position = this.fixedPlacement ? "fixed" : "absolute"; - this.updatePositionClasses(); - - this.updateRegionStyle(); - } - - /** - * starts observers - */ - private startObservers = (): void => { - this.stopObservers(); - - if (this.anchorElement === null) { - return; - } - - this.requestPositionUpdates(); - - if (this.resizeDetector !== null) { - this.resizeDetector.observe(this.anchorElement); - this.resizeDetector.observe(this); - } - }; - - /** - * get position updates - */ - private requestPositionUpdates = (): void => { - if (this.anchorElement === null || this.pendingPositioningUpdate) { - return; - } - FASTAnchoredRegion.intersectionService.requestPosition( - this, - this.handleIntersection - ); - FASTAnchoredRegion.intersectionService.requestPosition( - this.anchorElement, - this.handleIntersection - ); - if (this.viewportElement !== null) { - FASTAnchoredRegion.intersectionService.requestPosition( - this.viewportElement, - this.handleIntersection - ); - } - this.pendingPositioningUpdate = true; - }; - - /** - * stops observers - */ - private stopObservers = (): void => { - if (this.pendingPositioningUpdate) { - this.pendingPositioningUpdate = false; - FASTAnchoredRegion.intersectionService.cancelRequestPosition( - this, - this.handleIntersection - ); - if (this.anchorElement !== null) { - FASTAnchoredRegion.intersectionService.cancelRequestPosition( - this.anchorElement, - this.handleIntersection - ); - } - if (this.viewportElement !== null) { - FASTAnchoredRegion.intersectionService.cancelRequestPosition( - this.viewportElement, - this.handleIntersection - ); - } - } - if (this.resizeDetector !== null) { - this.resizeDetector.disconnect(); - } - }; - - /** - * Gets the viewport element by id, or defaults to document root - */ - private getViewport = (): HTMLElement | null => { - if (typeof this.viewport !== "string" || this.viewport === "") { - return document.documentElement; - } - - const rootNode = this.getRootNode(); - - if (rootNode instanceof ShadowRoot) { - return rootNode.getElementById(this.viewport); - } - - return document.getElementById(this.viewport); - }; - - /** - * Gets the anchor element by id - */ - private getAnchor = (): HTMLElement | null => { - const rootNode = this.getRootNode(); - - if (rootNode instanceof ShadowRoot) { - return rootNode.getElementById(this.anchor); - } - - return document.getElementById(this.anchor); - }; - - /** - * Handle intersections - */ - private handleIntersection = (entries: IntersectionObserverEntry[]): void => { - if (!this.pendingPositioningUpdate) { - return; - } - - this.pendingPositioningUpdate = false; - - if (!this.applyIntersectionEntries(entries)) { - return; - } - - this.updateLayout(); - }; - - /** - * iterate through intersection entries and apply data - */ - private applyIntersectionEntries = ( - entries: IntersectionObserverEntry[] - ): boolean => { - const regionEntry: IntersectionObserverEntry | undefined = entries.find( - x => x.target === this - ); - const anchorEntry: IntersectionObserverEntry | undefined = entries.find( - x => x.target === this.anchorElement - ); - const viewportEntry: IntersectionObserverEntry | undefined = entries.find( - x => x.target === this.viewportElement - ); - - if ( - regionEntry === undefined || - viewportEntry === undefined || - anchorEntry === undefined - ) { - return false; - } - - // don't update the dom unless there is a significant difference in rect positions - if ( - !this.regionVisible || - this.forceUpdate || - this.regionRect === undefined || - this.anchorRect === undefined || - this.viewportRect === undefined || - this.isRectDifferent(this.anchorRect, anchorEntry.boundingClientRect) || - this.isRectDifferent(this.viewportRect, viewportEntry.boundingClientRect) || - this.isRectDifferent(this.regionRect, regionEntry.boundingClientRect) - ) { - this.regionRect = regionEntry.boundingClientRect; - this.anchorRect = anchorEntry.boundingClientRect; - if (this.viewportElement === document.documentElement) { - this.viewportRect = new DOMRectReadOnly( - viewportEntry.boundingClientRect.x + - document.documentElement.scrollLeft, - viewportEntry.boundingClientRect.y + - document.documentElement.scrollTop, - viewportEntry.boundingClientRect.width, - viewportEntry.boundingClientRect.height - ); - } else { - this.viewportRect = viewportEntry.boundingClientRect; - } - - this.updateRegionOffset(); - - this.forceUpdate = false; - - return true; - } - - return false; - }; - - /** - * Update the offset values - */ - private updateRegionOffset = (): void => { - if (this.anchorRect && this.regionRect) { - this.baseHorizontalOffset = - this.baseHorizontalOffset + - (this.anchorRect.left - this.regionRect.left) + - (this.translateX - this.baseHorizontalOffset); - - this.baseVerticalOffset = - this.baseVerticalOffset + - (this.anchorRect.top - this.regionRect.top) + - (this.translateY - this.baseVerticalOffset); - } - }; - - /** - * compare rects to see if there is enough change to justify a DOM update - */ - private isRectDifferent = ( - rectA: DOMRect | ClientRect, - rectB: DOMRect | ClientRect - ): boolean => { - if ( - Math.abs(rectA.top - rectB.top) > this.updateThreshold || - Math.abs(rectA.right - rectB.right) > this.updateThreshold || - Math.abs(rectA.bottom - rectB.bottom) > this.updateThreshold || - Math.abs(rectA.left - rectB.left) > this.updateThreshold - ) { - return true; - } - return false; - }; - - /** - * Handle resize events - */ - private handleResize = (entries: ResizeObserverEntry[]): void => { - this.update(); - }; - - /** - * resets the component - */ - private reset = (): void => { - if (!this.pendingReset) { - return; - } - - this.pendingReset = false; - if (this.anchorElement === null) { - this.anchorElement = this.getAnchor(); - } - - if (this.viewportElement === null) { - this.viewportElement = this.getViewport(); - } - - this.currentDirection = getDirection(this); - this.startObservers(); - }; - - /** - * Recalculate layout related state values - */ - private updateLayout = (): void => { - let desiredVerticalPosition: AnchoredRegionPositionLabel | undefined = undefined; - let desiredHorizontalPosition: AnchoredRegionPositionLabel | undefined = - undefined; - - if (this.horizontalPositioningMode !== "uncontrolled") { - const horizontalOptions: AnchoredRegionPositionLabel[] = - this.getPositioningOptions(this.horizontalInset); - - if (this.horizontalDefaultPosition === "center") { - desiredHorizontalPosition = "center"; - } else if (this.horizontalDefaultPosition !== "unset") { - let dirCorrectedHorizontalDefaultPosition: string = - this.horizontalDefaultPosition; - - if ( - dirCorrectedHorizontalDefaultPosition === "start" || - dirCorrectedHorizontalDefaultPosition === "end" - ) { - // if direction changes we reset the layout - const newDirection: Direction = getDirection(this); - if (newDirection !== this.currentDirection) { - this.currentDirection = newDirection; - this.initialize(); - return; - } - - if (this.currentDirection === Direction.ltr) { - dirCorrectedHorizontalDefaultPosition = - dirCorrectedHorizontalDefaultPosition === "start" - ? "left" - : "right"; - } else { - dirCorrectedHorizontalDefaultPosition = - dirCorrectedHorizontalDefaultPosition === "start" - ? "right" - : "left"; - } - } - - switch (dirCorrectedHorizontalDefaultPosition) { - case "left": - desiredHorizontalPosition = this.horizontalInset - ? "insetStart" - : "start"; - break; - - case "right": - desiredHorizontalPosition = this.horizontalInset - ? "insetEnd" - : "end"; - break; - } - } - - const horizontalThreshold: number = - this.horizontalThreshold !== undefined - ? this.horizontalThreshold - : this.regionRect !== undefined - ? this.regionRect.width - : 0; - - const anchorLeft: number = - this.anchorRect !== undefined ? this.anchorRect.left : 0; - const anchorRight: number = - this.anchorRect !== undefined ? this.anchorRect.right : 0; - const anchorWidth: number = - this.anchorRect !== undefined ? this.anchorRect.width : 0; - const viewportLeft: number = - this.viewportRect !== undefined ? this.viewportRect.left : 0; - const viewportRight: number = - this.viewportRect !== undefined ? this.viewportRect.right : 0; - - if ( - desiredHorizontalPosition === undefined || - (!(this.horizontalPositioningMode === "locktodefault") && - this.getAvailableSpace( - desiredHorizontalPosition, - anchorLeft, - anchorRight, - anchorWidth, - viewportLeft, - viewportRight - ) < horizontalThreshold) - ) { - desiredHorizontalPosition = - this.getAvailableSpace( - horizontalOptions[0], - anchorLeft, - anchorRight, - anchorWidth, - viewportLeft, - viewportRight - ) > - this.getAvailableSpace( - horizontalOptions[1], - anchorLeft, - anchorRight, - anchorWidth, - viewportLeft, - viewportRight - ) - ? horizontalOptions[0] - : horizontalOptions[1]; - } - } - - if (this.verticalPositioningMode !== "uncontrolled") { - const verticalOptions: AnchoredRegionPositionLabel[] = - this.getPositioningOptions(this.verticalInset); - if (this.verticalDefaultPosition === "center") { - desiredVerticalPosition = "center"; - } else if (this.verticalDefaultPosition !== "unset") { - switch (this.verticalDefaultPosition) { - case "top": - desiredVerticalPosition = this.verticalInset - ? "insetStart" - : "start"; - break; - - case "bottom": - desiredVerticalPosition = this.verticalInset ? "insetEnd" : "end"; - break; - } - } - - const verticalThreshold: number = - this.verticalThreshold !== undefined - ? this.verticalThreshold - : this.regionRect !== undefined - ? this.regionRect.height - : 0; - - const anchorTop: number = - this.anchorRect !== undefined ? this.anchorRect.top : 0; - const anchorBottom: number = - this.anchorRect !== undefined ? this.anchorRect.bottom : 0; - const anchorHeight: number = - this.anchorRect !== undefined ? this.anchorRect.height : 0; - const viewportTop: number = - this.viewportRect !== undefined ? this.viewportRect.top : 0; - const viewportBottom: number = - this.viewportRect !== undefined ? this.viewportRect.bottom : 0; - - if ( - desiredVerticalPosition === undefined || - (!(this.verticalPositioningMode === "locktodefault") && - this.getAvailableSpace( - desiredVerticalPosition, - anchorTop, - anchorBottom, - anchorHeight, - viewportTop, - viewportBottom - ) < verticalThreshold) - ) { - desiredVerticalPosition = - this.getAvailableSpace( - verticalOptions[0], - anchorTop, - anchorBottom, - anchorHeight, - viewportTop, - viewportBottom - ) > - this.getAvailableSpace( - verticalOptions[1], - anchorTop, - anchorBottom, - anchorHeight, - viewportTop, - viewportBottom - ) - ? verticalOptions[0] - : verticalOptions[1]; - } - } - - const nextPositionerDimension: Dimension = this.getNextRegionDimension( - desiredHorizontalPosition, - desiredVerticalPosition - ); - - const positionChanged: boolean = - this.horizontalPosition !== desiredHorizontalPosition || - this.verticalPosition !== desiredVerticalPosition; - - this.setHorizontalPosition(desiredHorizontalPosition, nextPositionerDimension); - this.setVerticalPosition(desiredVerticalPosition, nextPositionerDimension); - - this.updateRegionStyle(); - - if (!this.initialLayoutComplete) { - this.initialLayoutComplete = true; - this.requestPositionUpdates(); - return; - } - - if (!this.regionVisible) { - this.regionVisible = true; - this.style.removeProperty("pointer-events"); - this.style.removeProperty("opacity"); - this.classList.toggle("loaded", true); - this.$emit("loaded", this, { bubbles: false }); - } - - this.updatePositionClasses(); - - if (positionChanged) { - // emit change event - this.$emit("positionchange", this, { bubbles: false }); - } - }; - - /** - * Updates the style string applied to the region element as well as the css classes attached - * to the root element - */ - private updateRegionStyle = (): void => { - this.style.width = this.regionWidth; - this.style.height = this.regionHeight; - this.style.transform = `translate(${this.translateX}px, ${this.translateY}px)`; - }; - - /** - * Updates the css classes that reflect the current position of the element - */ - private updatePositionClasses = (): void => { - this.classList.toggle("top", this.verticalPosition === "start"); - this.classList.toggle("bottom", this.verticalPosition === "end"); - this.classList.toggle("inset-top", this.verticalPosition === "insetStart"); - this.classList.toggle("inset-bottom", this.verticalPosition === "insetEnd"); - this.classList.toggle("vertical-center", this.verticalPosition === "center"); - - this.classList.toggle("left", this.horizontalPosition === "start"); - this.classList.toggle("right", this.horizontalPosition === "end"); - this.classList.toggle("inset-left", this.horizontalPosition === "insetStart"); - this.classList.toggle("inset-right", this.horizontalPosition === "insetEnd"); - this.classList.toggle("horizontal-center", this.horizontalPosition === "center"); - }; - - /** - * Get horizontal positioning state based on desired position - */ - private setHorizontalPosition = ( - desiredHorizontalPosition: AnchoredRegionPositionLabel | undefined, - nextPositionerDimension: Dimension - ): void => { - if ( - desiredHorizontalPosition === undefined || - this.regionRect === undefined || - this.anchorRect === undefined || - this.viewportRect === undefined - ) { - return; - } - - let nextRegionWidth: number = 0; - - switch (this.horizontalScaling) { - case "anchor": - case "fill": - nextRegionWidth = this.horizontalViewportLock - ? this.viewportRect.width - : nextPositionerDimension.width; - this.regionWidth = `${nextRegionWidth}px`; - break; - - case "content": - nextRegionWidth = this.regionRect.width; - this.regionWidth = "unset"; - break; - } - - let sizeDelta: number = 0; - - switch (desiredHorizontalPosition) { - case "start": - this.translateX = this.baseHorizontalOffset - nextRegionWidth; - if ( - this.horizontalViewportLock && - this.anchorRect.left > this.viewportRect.right - ) { - this.translateX = - this.translateX - - (this.anchorRect.left - this.viewportRect.right); - } - break; - - case "insetStart": - this.translateX = - this.baseHorizontalOffset - nextRegionWidth + this.anchorRect.width; - if ( - this.horizontalViewportLock && - this.anchorRect.right > this.viewportRect.right - ) { - this.translateX = - this.translateX - - (this.anchorRect.right - this.viewportRect.right); - } - break; - - case "insetEnd": - this.translateX = this.baseHorizontalOffset; - if ( - this.horizontalViewportLock && - this.anchorRect.left < this.viewportRect.left - ) { - this.translateX = - this.translateX - (this.anchorRect.left - this.viewportRect.left); - } - break; - - case "end": - this.translateX = this.baseHorizontalOffset + this.anchorRect.width; - if ( - this.horizontalViewportLock && - this.anchorRect.right < this.viewportRect.left - ) { - this.translateX = - this.translateX - - (this.anchorRect.right - this.viewportRect.left); - } - break; - - case "center": - sizeDelta = (this.anchorRect.width - nextRegionWidth) / 2; - this.translateX = this.baseHorizontalOffset + sizeDelta; - if (this.horizontalViewportLock) { - const regionLeft: number = this.anchorRect.left + sizeDelta; - const regionRight: number = this.anchorRect.right - sizeDelta; - - if ( - regionLeft < this.viewportRect.left && - !(regionRight > this.viewportRect.right) - ) { - this.translateX = - this.translateX - (regionLeft - this.viewportRect.left); - } else if ( - regionRight > this.viewportRect.right && - !(regionLeft < this.viewportRect.left) - ) { - this.translateX = - this.translateX - (regionRight - this.viewportRect.right); - } - } - break; - } - - this.horizontalPosition = desiredHorizontalPosition; - }; - - /** - * Set vertical positioning state based on desired position - */ - private setVerticalPosition = ( - desiredVerticalPosition: AnchoredRegionPositionLabel | undefined, - nextPositionerDimension: Dimension - ): void => { - if ( - desiredVerticalPosition === undefined || - this.regionRect === undefined || - this.anchorRect === undefined || - this.viewportRect === undefined - ) { - return; - } - - let nextRegionHeight: number = 0; - - switch (this.verticalScaling) { - case "anchor": - case "fill": - nextRegionHeight = this.verticalViewportLock - ? this.viewportRect.height - : nextPositionerDimension.height; - this.regionHeight = `${nextRegionHeight}px`; - break; - - case "content": - nextRegionHeight = this.regionRect.height; - this.regionHeight = "unset"; - break; - } - - let sizeDelta: number = 0; - - switch (desiredVerticalPosition) { - case "start": - this.translateY = this.baseVerticalOffset - nextRegionHeight; - if ( - this.verticalViewportLock && - this.anchorRect.top > this.viewportRect.bottom - ) { - this.translateY = - this.translateY - - (this.anchorRect.top - this.viewportRect.bottom); - } - break; - - case "insetStart": - this.translateY = - this.baseVerticalOffset - nextRegionHeight + this.anchorRect.height; - if ( - this.verticalViewportLock && - this.anchorRect.bottom > this.viewportRect.bottom - ) { - this.translateY = - this.translateY - - (this.anchorRect.bottom - this.viewportRect.bottom); - } - break; - - case "insetEnd": - this.translateY = this.baseVerticalOffset; - if ( - this.verticalViewportLock && - this.anchorRect.top < this.viewportRect.top - ) { - this.translateY = - this.translateY - (this.anchorRect.top - this.viewportRect.top); - } - break; - - case "end": - this.translateY = this.baseVerticalOffset + this.anchorRect.height; - if ( - this.verticalViewportLock && - this.anchorRect.bottom < this.viewportRect.top - ) { - this.translateY = - this.translateY - - (this.anchorRect.bottom - this.viewportRect.top); - } - break; - - case "center": - sizeDelta = (this.anchorRect.height - nextRegionHeight) / 2; - this.translateY = this.baseVerticalOffset + sizeDelta; - if (this.verticalViewportLock) { - const regionTop: number = this.anchorRect.top + sizeDelta; - const regionBottom: number = this.anchorRect.bottom - sizeDelta; - - if ( - regionTop < this.viewportRect.top && - !(regionBottom > this.viewportRect.bottom) - ) { - this.translateY = - this.translateY - (regionTop - this.viewportRect.top); - } else if ( - regionBottom > this.viewportRect.bottom && - !(regionTop < this.viewportRect.top) - ) { - this.translateY = - this.translateY - (regionBottom - this.viewportRect.bottom); - } - } - } - - this.verticalPosition = desiredVerticalPosition; - }; - - /** - * Get available positions based on positioning mode - */ - private getPositioningOptions = (inset: boolean): AnchoredRegionPositionLabel[] => { - if (inset) { - return ["insetStart", "insetEnd"]; - } - return ["start", "end"]; - }; - - /** - * Get the space available for a particular relative position - */ - private getAvailableSpace = ( - positionOption: AnchoredRegionPositionLabel, - anchorStart: number, - anchorEnd: number, - anchorSpan: number, - viewportStart: number, - viewportEnd: number - ): number => { - const spaceStart: number = anchorStart - viewportStart; - const spaceEnd: number = viewportEnd - (anchorStart + anchorSpan); - - switch (positionOption) { - case "start": - return spaceStart; - case "insetStart": - return spaceStart + anchorSpan; - case "insetEnd": - return spaceEnd + anchorSpan; - case "end": - return spaceEnd; - case "center": - return Math.min(spaceStart, spaceEnd) * 2 + anchorSpan; - } - }; - - /** - * Get region dimensions - */ - private getNextRegionDimension = ( - desiredHorizontalPosition: AnchoredRegionPositionLabel | undefined, - desiredVerticalPosition: AnchoredRegionPositionLabel | undefined - ): Dimension => { - const newRegionDimension: Dimension = { - height: this.regionRect !== undefined ? this.regionRect.height : 0, - width: this.regionRect !== undefined ? this.regionRect.width : 0, - }; - - if ( - desiredHorizontalPosition !== undefined && - this.horizontalScaling === "fill" - ) { - newRegionDimension.width = this.getAvailableSpace( - desiredHorizontalPosition, - this.anchorRect !== undefined ? this.anchorRect.left : 0, - this.anchorRect !== undefined ? this.anchorRect.right : 0, - this.anchorRect !== undefined ? this.anchorRect.width : 0, - this.viewportRect !== undefined ? this.viewportRect.left : 0, - this.viewportRect !== undefined ? this.viewportRect.right : 0 - ); - } else if (this.horizontalScaling === "anchor") { - newRegionDimension.width = - this.anchorRect !== undefined ? this.anchorRect.width : 0; - } - - if (desiredVerticalPosition !== undefined && this.verticalScaling === "fill") { - newRegionDimension.height = this.getAvailableSpace( - desiredVerticalPosition, - this.anchorRect !== undefined ? this.anchorRect.top : 0, - this.anchorRect !== undefined ? this.anchorRect.bottom : 0, - this.anchorRect !== undefined ? this.anchorRect.height : 0, - this.viewportRect !== undefined ? this.viewportRect.top : 0, - this.viewportRect !== undefined ? this.viewportRect.bottom : 0 - ); - } else if (this.verticalScaling === "anchor") { - newRegionDimension.height = - this.anchorRect !== undefined ? this.anchorRect.height : 0; - } - - return newRegionDimension; - }; - - /** - * starts event listeners that can trigger auto updating - */ - private startAutoUpdateEventListeners = (): void => { - window.addEventListener(eventResize, this.update, { passive: true }); - window.addEventListener(eventScroll, this.update, { - passive: true, - capture: true, - }); - if (this.resizeDetector !== null && this.viewportElement !== null) { - this.resizeDetector.observe(this.viewportElement); - } - }; - - /** - * stops event listeners that can trigger auto updating - */ - private stopAutoUpdateEventListeners = (): void => { - window.removeEventListener(eventResize, this.update); - window.removeEventListener(eventScroll, this.update); - if (this.resizeDetector !== null && this.viewportElement !== null) { - this.resizeDetector.unobserve(this.viewportElement); - } - }; -} diff --git a/packages/web-components/fast-foundation/src/anchored-region/images/adjacent-adjacent.png b/packages/web-components/fast-foundation/src/anchored-region/images/adjacent-adjacent.png deleted file mode 100644 index 214b9e7a0cc0319b80392f83f98b86c06a7b3d5b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23256 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 diff --git a/packages/web-components/fast-foundation/src/anchored-region/images/adjacent-inset.png b/packages/web-components/fast-foundation/src/anchored-region/images/adjacent-inset.png deleted file mode 100644 index 85df8a32ea0f95bc946fee0695a796b25ff1da5c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21570 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 diff --git a/packages/web-components/fast-foundation/src/anchored-region/images/inset-inset.png b/packages/web-components/fast-foundation/src/anchored-region/images/inset-inset.png deleted file mode 100644 index 3c2744f69f2c279acfc1d0a77d3b7996927a9bb2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18325 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 diff --git a/packages/web-components/fast-foundation/src/anchored-region/index.ts b/packages/web-components/fast-foundation/src/anchored-region/index.ts deleted file mode 100644 index 0f06c710503..00000000000 --- a/packages/web-components/fast-foundation/src/anchored-region/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -export { - FlyoutPosBottom, - FlyoutPosBottomFill, - FlyoutPosTallest, - FlyoutPosTallestFill, - FlyoutPosTop, - FlyoutPosTopFill, -} from "./anchored-region-config.js"; -export type { AnchoredRegionConfig } from "./anchored-region-config.js"; -export { FASTAnchoredRegion } from "./anchored-region.js"; -export { - AnchoredRegionPositionLabel, - AutoUpdateMode, - AxisPositioningMode, - AxisScalingMode, - HorizontalPosition, - VerticalPosition, -} from "./anchored-region.options.js"; -export type { Dimension } from "./anchored-region.options.js"; -export { anchoredRegionTemplate } from "./anchored-region.template.js"; diff --git a/packages/web-components/fast-foundation/src/anchored-region/stories/anchored-region.register.ts b/packages/web-components/fast-foundation/src/anchored-region/stories/anchored-region.register.ts deleted file mode 100644 index b17e7c0df62..00000000000 --- a/packages/web-components/fast-foundation/src/anchored-region/stories/anchored-region.register.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { css } from "@microsoft/fast-element"; -import { FASTAnchoredRegion } from "../anchored-region.js"; -import { anchoredRegionTemplate } from "../anchored-region.template.js"; - -const styles = css` - :host { - display: block; - } -`; - -FASTAnchoredRegion.define({ - name: "fast-anchored-region", - template: anchoredRegionTemplate(), - styles, -}); diff --git a/packages/web-components/fast-foundation/src/anchored-region/stories/anchored-region.stories.ts b/packages/web-components/fast-foundation/src/anchored-region/stories/anchored-region.stories.ts deleted file mode 100644 index e6e655c8a87..00000000000 --- a/packages/web-components/fast-foundation/src/anchored-region/stories/anchored-region.stories.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { html } from "@microsoft/fast-element"; -import { uniqueId } from "@microsoft/fast-web-utilities"; -import type { Meta, Story, StoryArgs } from "../../__test__/helpers.js"; -import { renderComponent } from "../../__test__/helpers.js"; -import type { FASTAnchoredRegion } from "../anchored-region.js"; -import { - AutoUpdateMode, - AxisPositioningMode, - AxisScalingMode, - HorizontalPosition, - VerticalPosition, -} from "../anchored-region.options.js"; - -const storyTemplate = html>` -
- Anchor - - ${x => x.storyContent} - -
-`; - -export default { - title: "Anchored Region", - args: { - storyContent: html` -
- anchored region -
- `, - fixedPlacement: false, - horizontalInset: false, - horizontalViewportLock: false, - verticalInset: false, - verticalViewportLock: false, - }, - argTypes: { - anchor: { control: "text" }, - anchorId: { table: { disable: true } }, - autoUpdateMode: { - control: "select", - options: Object.values(AutoUpdateMode), - }, - fixedPlacement: { control: "boolean" }, - horizontalDefaultPosition: { - control: "select", - options: Object.values(HorizontalPosition), - }, - horizontalInset: { control: "boolean" }, - horizontalPositioningMode: { - control: "select", - options: Object.values(AxisPositioningMode), - }, - horizontalScaling: { - control: "select", - options: Object.values(AxisScalingMode), - }, - horizontalThreshold: { control: "number" }, - horizontalViewportLock: { control: "boolean" }, - storyContent: { table: { disable: true } }, - verticalDefaultPosition: { - control: "select", - options: Object.values(VerticalPosition), - }, - verticalInset: { control: "boolean" }, - verticalPositioningMode: { - control: "select", - options: Object.values(AxisPositioningMode), - }, - verticalScaling: { - control: "select", - options: Object.values(AxisScalingMode), - }, - verticalThreshold: { control: "number" }, - verticalViewportLock: { control: "boolean" }, - viewport: { control: "text" }, - }, - decorators: [ - (Story, { args }) => { - // IDs are generated to ensure that they're unique for the docs page - const renderedStory = Story() as DocumentFragment; - const anchor = renderedStory.querySelector(".anchor") as HTMLElement; - const region = renderedStory.querySelector(".region") as HTMLElement; - - const anchorId = args.anchorId ?? uniqueId("anchor"); - - anchor.id = anchorId; - region.id = uniqueId("region"); - region.setAttribute("anchor", anchorId); - return renderedStory; - }, - ], -} as Meta; - -export const AnchoredRegion: Story = renderComponent( - storyTemplate -).bind({}); - -export const LockToDefault: Story = AnchoredRegion.bind({}); -LockToDefault.args = { - horizontalDefaultPosition: HorizontalPosition.right, - horizontalPositioningMode: AxisPositioningMode.locktodefault, - verticalDefaultPosition: VerticalPosition.bottom, - verticalPositioningMode: AxisPositioningMode.locktodefault, -}; diff --git a/packages/web-components/fast-foundation/src/avatar/README.md b/packages/web-components/fast-foundation/src/avatar/README.md deleted file mode 100644 index 0f8ce7769a1..00000000000 --- a/packages/web-components/fast-foundation/src/avatar/README.md +++ /dev/null @@ -1,130 +0,0 @@ ---- -id: avatar -title: fast-avatar -sidebar_label: avatar -custom_edit_url: https://github.com/microsoft/fast/edit/master/packages/web-components/fast-foundation/src/avatar/README.md -description: fast-avatar is a web component used to graphically represent a user or an object. ---- - -The `fast-avatar` component is used to graphically represent a user or an object. - -## Setup - -### Basic Setup - -```ts -import { - provideFASTDesignSystem, - fastAnchoredRegion -} from "@microsoft/fast-components"; - -provideFASTDesignSystem() - .register( - fastAvatar() - ); -``` - -### Custom Media - -```ts -import { Avatar } from "@microsoft/fast-foundation"; -import { - provideFASTDesignSystem, - fastAnchoredRegion -} from "@microsoft/fast-components"; - -const imgTemplate = html` - ...your own template that controls rendering images... -`; - -provideFASTDesignSystem() - .register( - fastAvatar({ - media: imgTemplate - }) - ); -``` - -## Usage - -### Basic Usage - -```html - - -``` - -### Used with a Badge - -```html - -   - -``` - -## Create your own design - -```ts -import { - AvatarOptions, - Avatar, - avatarTemplate as template, -} from "@microsoft/fast-foundation"; -import { avatarStyles as styles } from "./my-avatar.styles"; - -export const myAvatar = Avatar.compose({ - baseName: "avatar", - template, - styles, - media: imgTemplate, - shadowOptions: { - delegatesFocus: true, - }, -}); -``` - -:::note -This component is built with the expectation that focus is delegated to the anchor element rendered into the shadow DOM. -::: - -## API - - - -### class: `FASTAvatar` - -#### Superclass - -| Name | Module | Package | -| ------------- | ------ | ----------------------- | -| `FASTElement` | | @microsoft/fast-element | - -#### CSS Parts - -| Name | Description | -| ----------- | ------------------------------------- | -| `backplate` | The wrapping container for the avatar | -| `content` | The default slot | - -#### Slots - -| Name | Description | -| ------- | ------------------------------------------------------------- | -| `media` | Used for media such as an image | -| | The default slot for avatar text, commonly a name or initials | -| `badge` | Used to provide a badge, such as a status badge | - -
- - -## Additional resources - -* [Component explorer examples](https://explore.fast.design/components/fast-avatar) -* [Component technical specification](https://github.com/microsoft/fast/blob/master/packages/web-components/fast-foundation/src/avatar/avatar.spec.md) -* [Open UI Analysis](https://open-ui.org/components/avatar.research) \ No newline at end of file diff --git a/packages/web-components/fast-foundation/src/avatar/avatar.spec.md b/packages/web-components/fast-foundation/src/avatar/avatar.spec.md deleted file mode 100644 index 3f29dbd494b..00000000000 --- a/packages/web-components/fast-foundation/src/avatar/avatar.spec.md +++ /dev/null @@ -1,87 +0,0 @@ -# Avatar - -## Overview - -An avatar is a graphical representation of a user or object. - -### Use Cases - -A common use case would be to display an image or text (usually initials) of a user or an object, such as in a user profile. - -### Features -- A URL for an image can be passed to the component to be displayed in the backplate -- Badge slot: Able to slot in a badge component -- Media slot: Accepts an `img` or an `svg` - -### Prior Art/Examples - -- [Fluent UI (Persona)](https://developer.microsoft.com/en-us/fluentui#/controls/web/persona) -- [Fluent UI](https://fluentsite.z22.web.core.windows.net/components/avatar/definition) -- [Lighting Design](https://www.lightningdesignsystem.com/components/avatar/) -- [Evergreen](https://evergreen.segment.com/components/avatar) -- [Ant Design](https://ant.design/components/avatar/) -- [Atlassian](https://atlaskit.atlassian.com/packages/design-system/avatar) ---- -### API - -*Component Name* -- `fast-avatar` - -#### Attributes -None - -#### Slots - -| Name | Description | Elements | -|-------|---------------------------|--------------| -|- | Slot for initials | text | -|`badge`| Slot for fast badge | `fast-badge` | -|`media`| Slot for images and icons | `img`, `svg` | - -### Anatomy and Appearance - -*Template* -```js -
- ${definition.media || ""} - -
- -``` - ---- - -## Implementation - -```html - - -``` - -With `fast-badge` Component: -```html - -   - -``` - -### Accessibility - -It is important to ensure that when the contrast of text in the backplate meets [1.4.3 Contrast (Minimum)](https://www.w3.org/TR/UNDERSTANDING-WCAG20/visual-audio-contrast-contrast.html). - -### Globalization - -If a badge is used it should appear on the appropriate side of the backplate. - ---- - -## Resources - -- [WCAG - 1.4.3 Contrast (Minimum)](https://www.w3.org/TR/UNDERSTANDING-WCAG20/visual-audio-contrast-contrast.html) - -## Next Steps - -Some validation will be needed to determine whether a component sizing feature should be natively added to this component or if that should be controlled by the design system's sizing model. diff --git a/packages/web-components/fast-foundation/src/avatar/avatar.template.ts b/packages/web-components/fast-foundation/src/avatar/avatar.template.ts deleted file mode 100644 index 20d21b6d992..00000000000 --- a/packages/web-components/fast-foundation/src/avatar/avatar.template.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { ElementViewTemplate } from "@microsoft/fast-element"; -import { html } from "@microsoft/fast-element"; -import { staticallyCompose } from "../utilities/template-helpers.js"; -import type { AvatarOptions, FASTAvatar } from "./avatar.js"; - -/** - * The template for {@link @microsoft/fast-foundation#FASTAvatar} component. - * @public - */ -export function avatarTemplate( - options: AvatarOptions = {} -): ElementViewTemplate { - return html` -
- ${staticallyCompose(options.media)} - -
- - `; -} diff --git a/packages/web-components/fast-foundation/src/avatar/avatar.ts b/packages/web-components/fast-foundation/src/avatar/avatar.ts deleted file mode 100644 index fbc0afd3063..00000000000 --- a/packages/web-components/fast-foundation/src/avatar/avatar.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { FASTElement } from "@microsoft/fast-element"; -import type { StaticallyComposableHTML } from "../utilities/template-helpers.js"; - -/** - * Avatar configuration options - * @public - */ -export type AvatarOptions = { - media?: StaticallyComposableHTML; -}; - -/** - * An Avatar Custom HTML Element - * - * @slot media - Used for media such as an image - * @slot - The default slot for avatar text, commonly a name or initials - * @slot badge - Used to provide a badge, such as a status badge - * @csspart backplate - The wrapping container for the avatar - * @csspart content - The default slot - * - * @public - */ -export class FASTAvatar extends FASTElement {} diff --git a/packages/web-components/fast-foundation/src/avatar/index.ts b/packages/web-components/fast-foundation/src/avatar/index.ts deleted file mode 100644 index 481e489bc7f..00000000000 --- a/packages/web-components/fast-foundation/src/avatar/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { FASTAvatar } from "./avatar.js"; -export type { AvatarOptions } from "./avatar.js"; -export { avatarTemplate } from "./avatar.template.js"; diff --git a/packages/web-components/fast-foundation/src/avatar/stories/avatar.register.ts b/packages/web-components/fast-foundation/src/avatar/stories/avatar.register.ts deleted file mode 100644 index 678d5068f34..00000000000 --- a/packages/web-components/fast-foundation/src/avatar/stories/avatar.register.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { attr, css, html, when } from "@microsoft/fast-element"; -import { FASTAvatar } from "../avatar.js"; -import { avatarTemplate } from "../avatar.template.js"; - -const styles = css` - :host { - --avatar-size-default: 32px; - --avatar-text-size: var(--type-ramp-base-font-size); - --avatar-text-ratio: var(--design-unit); - display: flex; - height: var(--avatar-size, var(--avatar-size-default)); - max-width: var(--avatar-size, var(--avatar-size-default)); - position: relative; - color: var(--foreground-on-accent-rest); - } - - :host([hidden]) { - display: none; - } - - .backplate { - display: flex; - position: relative; - align-items: center; - justify-content: center; - border-radius: 100%; - min-width: 100%; - overflow: hidden; - background-color: var(--accent-fill-rest); - } - - .media, - ::slotted(img) { - display: block; - max-width: 100%; - position: absolute; - } - - .content { - --avatar-size: var(--avatar-size, var(--avatar-size-default)); - display: block; - font-size: calc( - (var(--avatar-text-size) + var(--avatar-size)) / var(--avatar-text-ratio) - ); - line-height: var(--avatar-size); - min-height: var(--avatar-size); - } - - ::slotted(fast-badge) { - display: block; - position: absolute; - } -`; - -class Avatar extends FASTAvatar { - @attr({ attribute: "src" }) - public imgSrc?: string; - - @attr - public alt?: string; -} - -const media = html` - ${when( - x => x.imgSrc, - html` - ${x => x.alt} - ` - )} -`; - -Avatar.define({ - name: "fast-avatar", - template: avatarTemplate({ media }), - styles, - shadowOptions: { - delegatesFocus: true, - }, -}); diff --git a/packages/web-components/fast-foundation/src/avatar/stories/avatar.stories.ts b/packages/web-components/fast-foundation/src/avatar/stories/avatar.stories.ts deleted file mode 100644 index 4a3b5d58198..00000000000 --- a/packages/web-components/fast-foundation/src/avatar/stories/avatar.stories.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { css, html, Updates } from "@microsoft/fast-element"; -import type { Meta, Story, StoryArgs } from "../../__test__/helpers.js"; -import { renderComponent } from "../../__test__/helpers.js"; -import type { FASTAvatar } from "../avatar.js"; - -const storyTemplate = html>` - ${x => x.storyContent} -`; - -export default { - title: "Avatar", - argTypes: { - storyContent: { table: { disable: true } }, - }, - decorators: [ - Story => { - const renderedStory = Story() as FASTAvatar; - - Updates.enqueue(() => { - renderedStory.$fastController.addStyles(css` - ::slotted(fast-badge) { - bottom: 0; - right: 0; - } - - .control { - height: 8px; - min-width: 8px; - } - - ::slotted(.container) { - padding: 1em; - } - `); - }); - - return renderedStory; - }, - ], -} as Meta; - -export const Avatar: Story = renderComponent(storyTemplate).bind({}); -Avatar.args = { - storyContent: html` - Annie's profile image - `, -}; - -export const AvatarCircleWithTextContent: Story = Avatar.bind({}); -AvatarCircleWithTextContent.args = { - storyContent: "CR", -}; diff --git a/packages/web-components/fast-foundation/src/badge/README.md b/packages/web-components/fast-foundation/src/badge/README.md deleted file mode 100644 index d604783a3cd..00000000000 --- a/packages/web-components/fast-foundation/src/badge/README.md +++ /dev/null @@ -1,77 +0,0 @@ ---- -id: badge -title: fast-badge -sidebar_label: badge -custom_edit_url: https://github.com/microsoft/fast/edit/master/packages/web-components/fast-foundation/src/badge/README.md -description: fast-badge is a web component used to highlight an item and attract attention or flag status. ---- - -The `fast-badge` component is used to highlight an item and attract attention or flag status. - -## Setup - -```ts -import { - provideFASTDesignSystem, - fastBadge -} from "@microsoft/fast-components"; - -provideFASTDesignSystem() - .register( - fastBadge() - ); -``` - -## Usage - -```html live -New -``` - -## Create your own design - -```ts -import { Badge, badgeTemplate as template } from "@microsoft/fast-foundation"; -import { badgeStyles as styles } from "./my-badge.styles"; - -export const myBadge = Badge.compose({ - baseName: "badge", - template, - styles, -}); -``` - -## API - - - -### class: `FASTBadge` - -#### Superclass - -| Name | Module | Package | -| ------------- | ------ | ----------------------- | -| `FASTElement` | | @microsoft/fast-element | - -#### CSS Parts - -| Name | Description | -| --------- | ------------------------------------- | -| `content` | The element wrapping the default slot | - -#### Slots - -| Name | Description | -| ------- | ----------------------------------------------------- | -| `start` | Content which can be provided before the default slot | -| `end` | Content which can be provided after the default slot | -| | The default slot for the badge | - -
- - -## Additional resources - -* [Component explorer examples](https://explore.fast.design/components/fast-badge) -* [Component technical specification](https://github.com/microsoft/fast/blob/master/packages/web-components/fast-foundation/src/badge/badge.spec.md) -* [Open UI Analysis](https://open-ui.org/components/badge.research) \ No newline at end of file diff --git a/packages/web-components/fast-foundation/src/badge/badge.spec.md b/packages/web-components/fast-foundation/src/badge/badge.spec.md deleted file mode 100644 index f0eb5d8bcb2..00000000000 --- a/packages/web-components/fast-foundation/src/badge/badge.spec.md +++ /dev/null @@ -1,68 +0,0 @@ -# fast-badge - -## Overview - -*Badge* component is used to highlight an item and attract attention or flag status, such as “New”, “Sale”, or other short phrases or a number to represent unread messages, updates available, etc.. - -### Use Cases - -Typical use cases include, but are not limited to, denoting a sale or new item, flagging an item as part of a category or representing a value of unread messages. - -### Features - -A badge has no functionality and no properties: - -### Prior Art/Examples -- [FAST Badge (React)](https://www.npmjs.com/package/@microsoft/fast-components-react-msft) -- [Material UI](https://material-ui.com/components/badges/) -- [Lightning Design](https://www.lightningdesignsystem.com/components/badges/) -- [Ant Design Badge](https://ant.design/components/badge/) -- [Ant Design Lozenge](https://atlaskit.atlassian.com/packages/core/lozenge) -- [Atlassian](https://atlaskit.atlassian.com/packages/core/badge) - ---- - -### API - -*Component name:* -- `fast-badge` - -*Attributes:* -- N/A - -*Slots:* -- `default` - -### Anatomy and Appearance - -*Template:* -``` - -``` - -## Implementation - - -``` - - New - -``` - -``` - - 99 - -``` - -### Accessibility - -Ensure text meets WCAG 2.1 color contrast against background. - -### Globalization - -*Badge* should mirror in RTL languages, meaning the *badge* should flip to the other side of the item it is labeling. - -### Dependencies - -No dependencies outside of fast-element itself. diff --git a/packages/web-components/fast-foundation/src/badge/badge.template.ts b/packages/web-components/fast-foundation/src/badge/badge.template.ts deleted file mode 100644 index 591404f3703..00000000000 --- a/packages/web-components/fast-foundation/src/badge/badge.template.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { ElementViewTemplate } from "@microsoft/fast-element"; -import { html } from "@microsoft/fast-element"; -import { endSlotTemplate, startSlotTemplate } from "../patterns/index.js"; -import type { BadgeOptions, FASTBadge } from "./badge.js"; - -/** - * The template for the {@link @microsoft/fast-foundation#(FASTBadge:class)} component. - * @public - */ -export function badgeTemplate( - options: BadgeOptions = {} -): ElementViewTemplate { - return html` - ${startSlotTemplate(options)} - - - - ${endSlotTemplate(options)} - `; -} diff --git a/packages/web-components/fast-foundation/src/badge/badge.ts b/packages/web-components/fast-foundation/src/badge/badge.ts deleted file mode 100644 index 45855ada296..00000000000 --- a/packages/web-components/fast-foundation/src/badge/badge.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { FASTElement } from "@microsoft/fast-element"; -import { StartEnd } from "../patterns/start-end.js"; -import type { StartEndOptions } from "../patterns/start-end.js"; -import { applyMixins } from "../utilities/apply-mixins.js"; - -/** - * Badge configuration options - * @public - */ -export type BadgeOptions = StartEndOptions; - -/** - * A Badge Custom HTML Element. - * @slot start - Content which can be provided before the default slot - * @slot end - Content which can be provided after the default slot - * @slot - The default slot for the badge - * @csspart content - The element wrapping the default slot - * - * @public - */ -export class FASTBadge extends FASTElement {} - -/** - * Mark internal because exporting class and interface of the same name - * confuses API documenter. - * TODO: https://github.com/microsoft/fast/issues/3317 - * @internal - */ -export interface FASTBadge extends StartEnd {} -applyMixins(FASTBadge, StartEnd); diff --git a/packages/web-components/fast-foundation/src/badge/index.ts b/packages/web-components/fast-foundation/src/badge/index.ts deleted file mode 100644 index 178723a4dc8..00000000000 --- a/packages/web-components/fast-foundation/src/badge/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { FASTBadge } from "./badge.js"; -export type { BadgeOptions } from "./badge.js"; -export { badgeTemplate } from "./badge.template.js"; diff --git a/packages/web-components/fast-foundation/src/badge/stories/badge.register.ts b/packages/web-components/fast-foundation/src/badge/stories/badge.register.ts deleted file mode 100644 index c9830f0bc0e..00000000000 --- a/packages/web-components/fast-foundation/src/badge/stories/badge.register.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { css } from "@microsoft/fast-element"; -import { FASTBadge } from "../badge.js"; -import { badgeTemplate } from "../badge.template.js"; - -const styles = css` - :host { - box-sizing: border-box; - display: inline-flex; - align-items: center; - font: var(--type-ramp-minus-1-font-size) / var(--type-ramp-minus-1-line-height) - var(--body-font); - background: var(--accent-fill-rest); - border: calc(var(--stroke-width) * 1px) solid transparent; - border-radius: calc(var(--control-corner-radius) * 1px); - color: var(--foreground-on-accent-rest); - fill: currentcolor; - padding: 1px 3px; - } - - ::slotted([slot="start"]) { - display: flex; - margin-inline-end: 4px; - } - - ::slotted([slot="end"]) { - display: flex; - margin-inline-start: 4px; - } -`; - -FASTBadge.define({ - name: "fast-badge", - template: badgeTemplate(), - styles, -}); diff --git a/packages/web-components/fast-foundation/src/badge/stories/badge.stories.ts b/packages/web-components/fast-foundation/src/badge/stories/badge.stories.ts deleted file mode 100644 index fe07f016aa7..00000000000 --- a/packages/web-components/fast-foundation/src/badge/stories/badge.stories.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { html } from "@microsoft/fast-element"; -import type { Meta, Story, StoryArgs } from "../../__test__/helpers.js"; -import { renderComponent } from "../../__test__/helpers.js"; -import type { FASTBadge } from "../badge.js"; - -const storyTemplate = html>` - ${x => x.storyContent} -`; - -export default { - title: "Badge", - args: { - storyContent: "Badge", - }, - argTypes: { - storyContent: { table: { disable: true } }, - }, -} as Meta; - -export const Badge: Story = renderComponent(storyTemplate).bind({}); - -export const BadgeWithSlottedStartEnd: Story = Badge.bind({}); -BadgeWithSlottedStartEnd.args = { - storyContent: html` - - Badge - - `, -}; diff --git a/packages/web-components/fast-foundation/src/breadcrumb-item/breadcrumb-item.pw.spec.ts b/packages/web-components/fast-foundation/src/breadcrumb-item/breadcrumb-item.pw.spec.ts deleted file mode 100644 index 7b5355f2dce..00000000000 --- a/packages/web-components/fast-foundation/src/breadcrumb-item/breadcrumb-item.pw.spec.ts +++ /dev/null @@ -1,137 +0,0 @@ -import { spinalCase } from "@microsoft/fast-web-utilities"; -import type { Locator, Page } from "@playwright/test"; -import { expect, test } from "@playwright/test"; -import { fixtureURL } from "../__test__/helpers.js"; -import type { FASTBreadcrumbItem } from "./breadcrumb-item.js"; - -test.describe("Breadcrumb item", () => { - let page: Page; - let element: Locator; - let root: Locator; - let control: Locator; - - test.beforeAll(async ({ browser }) => { - page = await browser.newPage(); - - element = page.locator("fast-breadcrumb-item"); - - root = page.locator("#storybook-root"); - - control = element.locator(".control"); - - await page.goto(fixtureURL("breadcrumb-item--breadcrumb-item")); - - await root.waitFor({ state: "visible" }); - }); - - test.afterAll(async () => { - await page.close(); - }); - - test("should include a `role` of `listitem`", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element).toHaveAttribute("role", "listitem"); - }); - - test("should render an internal anchor when the `href` attribute is not provided", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - const anchor = element.locator("a"); - - await expect(element).not.toHaveAttribute("href"); - - await expect(element).toHaveJSProperty("href", undefined); - - await expect(anchor).toHaveCount(1); - - await expect(element.locator("a")).toHaveCount(1); - }); - - test("should render an internal anchor when the `href` attribute is provided", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - const anchor = element.locator("a"); - - await expect(anchor).toHaveCount(1); - - await expect(anchor).toHaveAttribute("href", "https://fast.design"); - - await element.evaluate(node => { - node.removeAttribute("href"); - }); - }); - - test("should add an element with a class of `separator` when the `separator` property is true", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await element.evaluate(node => { - node.separator = true; - }); - - await expect(element.locator(".separator")).toHaveCount(1); - }); - - const attributes = { - download: "foo", - hreflang: "en-GB", - ping: "foo", - referrerpolicy: "no-referrer", - rel: "external", - target: "_blank", - type: "foo", - ariaAtomic: "true", - ariaBusy: "false", - ariaControls: "testId", - ariaCurrent: "page", - ariaDescribedby: "testId", - ariaDetails: "testId", - ariaDisabled: "true", - ariaErrormessage: "test", - ariaExpanded: "true", - ariaFlowto: "testId", - ariaHaspopup: "true", - ariaHidden: "true", - ariaInvalid: "spelling", - ariaKeyshortcuts: "F4", - ariaLabel: "foo", - ariaLabelledby: "testId", - ariaLive: "polite", - ariaOwns: "testId", - ariaRelevant: "removals", - ariaRoledescription: "slide", - }; - - for (const [attribute, value] of Object.entries(attributes)) { - const attrToken = spinalCase(attribute); - - test(`should set the \`${attrToken}\` attribute to \`${value}\` on the internal anchor`, async () => { - await root.evaluate( - (node, { attrToken, value }) => { - node.innerHTML = /* html */ ` - - `; - }, - { attrToken, value } - ); - - await expect(control).toHaveAttribute(attrToken, `${value}`); - }); - } -}); diff --git a/packages/web-components/fast-foundation/src/breadcrumb-item/breadcrumb-item.template.ts b/packages/web-components/fast-foundation/src/breadcrumb-item/breadcrumb-item.template.ts deleted file mode 100644 index 4372706a740..00000000000 --- a/packages/web-components/fast-foundation/src/breadcrumb-item/breadcrumb-item.template.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type { ElementViewTemplate } from "@microsoft/fast-element"; -import { html, when } from "@microsoft/fast-element"; -import { anchorTemplate } from "../anchor/anchor.template.js"; -import { staticallyCompose } from "../utilities/template-helpers.js"; -import type { BreadcrumbItemOptions, FASTBreadcrumbItem } from "./breadcrumb-item.js"; - -/** - * The template for the {@link @microsoft/fast-foundation#(FASTBreadcrumbItem:class)} component. - * @public - */ -export function breadcrumbItemTemplate( - options: BreadcrumbItemOptions = {} -): ElementViewTemplate { - return html` - - `; -} diff --git a/packages/web-components/fast-foundation/src/breadcrumb-item/breadcrumb-item.ts b/packages/web-components/fast-foundation/src/breadcrumb-item/breadcrumb-item.ts deleted file mode 100644 index 03ebdf15a58..00000000000 --- a/packages/web-components/fast-foundation/src/breadcrumb-item/breadcrumb-item.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { observable } from "@microsoft/fast-element"; -import type { StaticallyComposableHTML } from "../utilities/template-helpers.js"; -import { DelegatesARIALink, FASTAnchor } from "../anchor/anchor.js"; -import { StartEnd } from "../patterns/start-end.js"; -import type { StartEndOptions } from "../patterns/start-end.js"; -import { applyMixins } from "../utilities/apply-mixins.js"; - -/** - * Breadcrumb Item configuration options - * @public - */ -export type BreadcrumbItemOptions = StartEndOptions & { - separator?: StaticallyComposableHTML; -}; - -/** - * A Breadcrumb Item Custom HTML Element. - * - * @slot start - Content which can be provided before the breadcrumb content - * @slot end - Content which can be provided after the breadcrumb content - * @slot - The default slot for when no href is provided or for providing your own custom elements - * @slot separator - The slot for providing a custom separator - * @csspart listitem - The wrapping container for the item, represents a semantic listitem - * @csspart separator - The wrapping element for the separator - * - * @public - */ -export class FASTBreadcrumbItem extends FASTAnchor { - /** - * @internal - */ - @observable - public separator: boolean = true; -} - -/** - * Mark internal because exporting class and interface of the same name - * confuses API documenter. - * TODO: https://github.com/microsoft/fast/issues/3317 - * @internal - */ -/* eslint-disable-next-line */ -export interface FASTBreadcrumbItem extends StartEnd, DelegatesARIALink {} -applyMixins(FASTBreadcrumbItem, StartEnd, DelegatesARIALink); diff --git a/packages/web-components/fast-foundation/src/breadcrumb-item/index.ts b/packages/web-components/fast-foundation/src/breadcrumb-item/index.ts deleted file mode 100644 index e83c935a822..00000000000 --- a/packages/web-components/fast-foundation/src/breadcrumb-item/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { FASTBreadcrumbItem } from "./breadcrumb-item.js"; -export type { BreadcrumbItemOptions } from "./breadcrumb-item.js"; -export { breadcrumbItemTemplate } from "./breadcrumb-item.template.js"; diff --git a/packages/web-components/fast-foundation/src/breadcrumb-item/stories/breadcrumb-item.register.ts b/packages/web-components/fast-foundation/src/breadcrumb-item/stories/breadcrumb-item.register.ts deleted file mode 100644 index 34fca2d78ca..00000000000 --- a/packages/web-components/fast-foundation/src/breadcrumb-item/stories/breadcrumb-item.register.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { css } from "@microsoft/fast-element"; -import chevronRightIcon from "../../../statics/svg/chevron_right_12_regular.svg"; -import { FASTBreadcrumbItem } from "../breadcrumb-item.js"; -import { breadcrumbItemTemplate } from "../breadcrumb-item.template.js"; - -const styles = css` - :host { - background: transparent; - box-sizing: border-box; - display: inline-flex; - font-family: var(--body-font); - font-size: var(--type-ramp-base-font-size); - fill: currentColor; - line-height: var(--type-ramp-base-line-height); - min-width: calc(var(--height-number) * 1px); - outline: none; - color: var(--neutral-foreground-rest); - display: flex; - align-items: center; - width: max-content; - } - - .separator { - margin: 0 6px; - display: flex; - } - - .control { - align-items: center; - box-sizing: border-box; - color: var(--accent-foreground-rest); - cursor: pointer; - display: flex; - fill: inherit; - outline: none; - text-decoration: none; - white-space: nowrap; - } - - .control:hover { - color: var(--accent-foreground-hover); - } - - .control:active { - color: var(--accent-foreground-active); - } - - .control .content { - position: relative; - } - - .control .content::before { - content: ""; - display: block; - height: calc(var(--stroke-width) * 1px); - left: 0; - position: absolute; - right: 0; - top: calc(1em + 4px); - width: 100%; - } - - .control:hover .content::before { - background: var(--accent-foreground-hover); - } - - .control:active .content::before { - background: var(--accent-foreground-active); - } - - .control:focus-visible .content::before { - background: var(--neutral-foreground-rest); - height: calc(var(--focus-stroke-width) * 1px); - } - - .control:not([href]) { - color: var(--neutral-foreground-rest); - cursor: default; - } - - .control:not([href]) .content::before { - background: none; - } - - ::slotted([slot="start"]), - ::slotted([slot="end"]), - .content { - align-self: center; - } - - ::slotted([slot="start"]), - ::slotted([slot="end"]) { - display: flex; - } - - ::slotted([slot="start"]) { - margin-inline-end: 11px; - } - - ::slotted([slot="end"]) { - margin-inline-start: 11px; - } -`; - -FASTBreadcrumbItem.define({ - name: "fast-breadcrumb-item", - template: breadcrumbItemTemplate({ - separator: chevronRightIcon, - }), - styles, -}); diff --git a/packages/web-components/fast-foundation/src/breadcrumb-item/stories/breadcrumb-item.stories.ts b/packages/web-components/fast-foundation/src/breadcrumb-item/stories/breadcrumb-item.stories.ts deleted file mode 100644 index 50fbd3032c1..00000000000 --- a/packages/web-components/fast-foundation/src/breadcrumb-item/stories/breadcrumb-item.stories.ts +++ /dev/null @@ -1,120 +0,0 @@ -import { html } from "@microsoft/fast-element"; -import type { Meta, Story, StoryArgs } from "../../__test__/helpers.js"; -import { renderComponent } from "../../__test__/helpers.js"; -import type { FASTBreadcrumbItem } from "../breadcrumb-item.js"; - -const storyTemplate = html>` - - ${x => x.storyContent} - -`; - -export default { - title: "Breadcrumb Item", - argTypes: { - download: { control: "text" }, - href: { control: "text" }, - hreflang: { control: "text" }, - ping: { control: "text" }, - referrerpolicy: { control: "text" }, - rel: { control: "text" }, - separator: { control: "boolean" }, - target: { control: "text" }, - type: { control: "text" }, - ariaAtomic: { control: "boolean" }, - ariaBusy: { control: "boolean" }, - ariaControls: { control: "text" }, - ariaCurrent: { control: "text" }, - ariaDescribedby: { control: "text" }, - ariaDetails: { control: "text" }, - ariaDisabled: { control: "boolean" }, - ariaErrormessage: { control: "text" }, - ariaExpanded: { control: "boolean" }, - ariaFlowto: { control: "text" }, - ariaHaspopup: { control: "boolean" }, - ariaHidden: { control: "boolean" }, - ariaInvalid: { control: "text" }, - ariaKeyshortcuts: { control: "text" }, - ariaLabel: { control: "text" }, - ariaLabelledby: { control: "text" }, - ariaLive: { control: "text" }, - ariaOwns: { control: "text" }, - ariaRelevant: { control: "text" }, - ariaRoledescription: { control: "text" }, - storyContent: { table: { disable: true } }, - }, -} as Meta; - -export const BreadcrumbItem: Story = renderComponent( - storyTemplate -).bind({}); -BreadcrumbItem.args = { - storyContent: "Breadcrumb Item", -}; - -export const BreadcrumbItemWithHref: Story = BreadcrumbItem.bind({}); -BreadcrumbItemWithHref.args = { - storyContent: "Breadcrumb item with href attribute", - href: "https://www.fast.design/", -}; - -export const BreadcrumbItemWithSlottedStart: Story = - BreadcrumbItem.bind({}); -BreadcrumbItemWithSlottedStart.args = { - storyContent: html` - - Breadcrumb Item with slotted start icon - `, - href: "#", -}; - -export const BreadcrumbItemWithSlottedEnd: Story = - BreadcrumbItem.bind({}); -BreadcrumbItemWithSlottedEnd.args = { - storyContent: html` - Breadcrumb item with slotted end icon - - `, - href: "#", -}; - -export const BreadcrumbItemWithSlottedStartEnd: Story = - BreadcrumbItem.bind({}); -BreadcrumbItemWithSlottedStartEnd.args = { - storyContent: html` - - Breadcrumb Item with slotted start & end icon - - `, - href: "#", -}; diff --git a/packages/web-components/fast-foundation/src/breadcrumb/README.md b/packages/web-components/fast-foundation/src/breadcrumb/README.md deleted file mode 100644 index 4011ed93a7b..00000000000 --- a/packages/web-components/fast-foundation/src/breadcrumb/README.md +++ /dev/null @@ -1,196 +0,0 @@ ---- -id: breadcrumb -title: fast-breadcrumb -sidebar_label: breadcrumb -custom_edit_url: https://github.com/microsoft/fast/edit/master/packages/web-components/fast-foundation/src/breadcrumb/README.md -description: fast-breadcrumb is a web component used as a navigational aid. ---- - -As defined by the [W3C](https://w3c.github.io/aria-practices/#breadcrumb): - -> A breadcrumb trail consists of a list of links to the parent pages of the current page in hierarchical order. It helps users find their place within a website or web application. Breadcrumbs are often placed horizontally before a page's main content. - -## Setup - -### Basic Setup - -```ts -import { - provideFASTDesignSystem, - fastBreadcrumb, - fastBreadcrumbItem -} from "@microsoft/fast-components"; - -provideFASTDesignSystem() - .register( - fastBreadcrumb(), - fastBreadcrumbItem() - ); -``` - -### Custom Separator - -```ts -import { - provideFASTDesignSystem, - fastBreadcrumb, - fastBreadcrumbItem -} from "@microsoft/fast-components"; - -provideFASTDesignSystem() - .register( - fastBreadcrumb(), - fastBreadcrumbItem({ - separator: " -> " - }) - ); -``` - -## Usage - -```html live - - Breadcrumb item 1 - Breadcrumb item 2 - Breadcrumb item 3 - -``` - -## Create your own design - -### Breadcrumb - -```ts -import { Breadcrumb, breadcrumbTemplate as template } from "@microsoft/fast-foundation"; -import { breadcrumbStyles as styles } from "./my-breadcrumb.styles"; - -export const myBreadcrumb = Breadcrumb.compose({ - baseName: "breadcrumb", - template, - styles, -}); -``` - -### Breadcrumb Item - -```ts -import { - BreadcrumbItem, - BreadcrumbItemOptions, - breadcrumbItemTemplate as template, -} from "@microsoft/fast-foundation"; -import { breadcrumbItemStyles as styles } from "./my-breadcrumb-item.styles"; - -export const myBreadcrumbItem = BreadcrumbItem.compose({ - baseName: "breadcrumb-item", - template, - styles, - separator: "/", - shadowOptions: { - delegatesFocus: true, - }, -}); -``` - -:::note -This component is built with the expectation that focus is delegated to the anchor element rendered into the shadow DOM. -::: - -## API - - - -### class: `FASTBreadcrumb` - -#### Superclass - -| Name | Module | Package | -| ------------- | ------ | ----------------------- | -| `FASTElement` | | @microsoft/fast-element | - -#### Methods - -| Name | Privacy | Description | Parameters | Return | Inherited From | -| ------------------------------- | --------- | ----------- | ---------- | ------ | -------------- | -| `slottedBreadcrumbItemsChanged` | protected | | | | | - -#### CSS Parts - -| Name | Description | -| ------ | -------------------------------------- | -| `list` | The element wrapping the slotted items | - -#### Slots - -| Name | Description | -| ------- | ---------------------------------------------------- | -| `start` | Content which can be provided before the breadcrumbs | -| `end` | Content which can be provided after the breadcrumbs | -| | The default slot for the breadcrumb items | - -
- - - -### class: `FASTBreadcrumbItem` - -#### Superclass - -| Name | Module | Package | -| ------------ | --------------------- | ------- | -| `FASTAnchor` | /src/anchor/anchor.js | | - -#### Fields - -| Name | Privacy | Type | Default | Description | Inherited From | -| ---------------- | ------- | ------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- | -| `download` | public | `string` | | Prompts the user to save the linked URL. See [`
` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a) for more information. | FASTAnchor | -| `href` | public | `string` | | The URL the hyperlink references. See [`` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a) for more information. | FASTAnchor | -| `hreflang` | public | `string` | | Hints at the language of the referenced resource. See [`` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a) for more information. | FASTAnchor | -| `ping` | public | `string` | | See [`` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a) for more information. | FASTAnchor | -| `referrerpolicy` | public | `string` | | See [`` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a) for more information. | FASTAnchor | -| `rel` | public | `string` | | See [`` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a) for more information. | FASTAnchor | -| `target` | public | `AnchorTarget` | | See [`` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a) for more information. | FASTAnchor | -| `type` | public | `string` | | See [`` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a) for more information. | FASTAnchor | -| `control` | public | `HTMLAnchorElement` | | References the root element | FASTAnchor | - -#### Attributes - -| Name | Field | Inherited From | -| ---------------- | -------------- | -------------- | -| `download` | download | FASTAnchor | -| `href` | href | FASTAnchor | -| `hreflang` | hreflang | FASTAnchor | -| `ping` | ping | FASTAnchor | -| `referrerpolicy` | referrerpolicy | FASTAnchor | -| `rel` | rel | FASTAnchor | -| `target` | target | FASTAnchor | -| `type` | type | FASTAnchor | - -#### CSS Parts - -| Name | Description | -| ----------- | ------------------------------------------------------------------- | -| `listitem` | The wrapping container for the item, represents a semantic listitem | -| `separator` | The wrapping element for the separator | -| `control` | The anchor element | -| `content` | The element wrapping anchor content | - -#### Slots - -| Name | Description | -| ----------- | --------------------------------------------------------------------------------------- | -| `start` | Content which can be provided before the breadcrumb content | -| `end` | Content which can be provided after the breadcrumb content | -| | The default slot for when no href is provided or for providing your own custom elements | -| `separator` | The slot for providing a custom separator | - -
- - -## Additional resources - -* [Component explorer examples](https://explore.fast.design/components/fast-breadcrumb) -* [Component technical specification](https://github.com/microsoft/fast/blob/master/packages/web-components/fast-foundation/src/breadcrumb/breadcrumb.spec.md) -* [W3C Component Aria Practices](https://w3c.github.io/aria-practices/#breadcrumb) -* [Open UI Analysis](https://open-ui.org/components/Breadcrumb) \ No newline at end of file diff --git a/packages/web-components/fast-foundation/src/breadcrumb/breadcrumb.pw.spec.ts b/packages/web-components/fast-foundation/src/breadcrumb/breadcrumb.pw.spec.ts deleted file mode 100644 index 5994cd508ca..00000000000 --- a/packages/web-components/fast-foundation/src/breadcrumb/breadcrumb.pw.spec.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { expect, test } from "@playwright/test"; -import type { Locator, Page } from "@playwright/test"; -import { fixtureURL } from "../__test__/helpers.js"; -import type { FASTBreadcrumb } from "./breadcrumb.js"; - -test.describe("Breadcrumb", () => { - let page: Page; - let element: Locator; - let root: Locator; - - test.beforeAll(async ({ browser }) => { - page = await browser.newPage(); - - element = page.locator("fast-breadcrumb"); - - root = page.locator("#storybook-root"); - - await page.goto(fixtureURL("breadcrumb--breadcrumb")); - - await root.waitFor({ state: "visible" }); - }); - - test.afterAll(async () => { - await page.close(); - }); - - test("should have a role of 'navigation'", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element).toHaveAttribute("role", "navigation"); - }); - - test("should include an internal element with a `role` of `list`", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element.locator(".list")).toHaveAttribute("role", "list"); - }); - - test("should not render a separator on last item", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - Item 1 - Item 2 - Item 3 - - `; - }); - - const items = element.locator("fast-breadcrumb-item"); - - await expect(items).toHaveCount(3); - - await expect(items.last()).toHaveJSProperty("separator", false); - }); - - test("should set `aria-current` on the internal anchor of the last node when `href` is present", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - Item 1 - Item 2 - Item 3 - - `; - }); - - await expect( - element.locator("fast-breadcrumb-item:last-of-type a") - ).toHaveAttribute("aria-current", "page"); - }); - - /* eslint-disable-next-line max-len */ - test("should remove `aria-current` from any prior breadcrumb item children with child anchors when a new node is appended", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - Item 1 - Item 2 - Item 3 - - `; - }); - - await expect( - element.locator("fast-breadcrumb-item:last-of-type a") - ).toHaveAttribute("aria-current", "page"); - - await element.evaluate(node => { - node.append(document.createElement("fast-breadcrumb-item")); - }); - - await expect( - element.locator("fast-breadcrumb-item:nth-of-type(2) a") - ).not.toHaveAttribute("aria-current"); - }); -}); diff --git a/packages/web-components/fast-foundation/src/breadcrumb/breadcrumb.spec.md b/packages/web-components/fast-foundation/src/breadcrumb/breadcrumb.spec.md deleted file mode 100644 index db04b42825c..00000000000 --- a/packages/web-components/fast-foundation/src/breadcrumb/breadcrumb.spec.md +++ /dev/null @@ -1,130 +0,0 @@ -# Breadcrumb + Breadcrumb Item - -## Overview -A `fast-breadcrumb` component is used as a navigational aid, allowing users to maintain awareness of their locations within a program, app, or a website. - -### Use Cases -- James is browsing an ecommerce website and is looking for a few items to add to his new kitchen. He needs a knife set, and an espresso machine. He checks out `Home and Kitchen` page, then selects `Kitchen and Dining`, first category he picks is `Cutlery`, he finds the sets of knives. There is now a breadcrumb trail of the pages James has clicked through. `Home and Kitchen / Kitchen and Dining / Cutlery / Knife Sets` -He clicks on `Kitchen and Dining` to go back to the category of kitchen items, selects `Coffee and Espresso` finds the best one that suits his needs. If James wants to continue looking for another item for his kitchen, or other things for his home, he just needs to click on any of the links in the breadcrumb trail to continue his search. - -### Prior Art/Examples -- [Ant Design](https://ant.design/components/breadcrumb/) -- [Atlaskit](https://atlaskit.atlassian.com/packages/core/breadcrumbs) -- [Carbon Design](https://www.carbondesignsystem.com/components/breadcrumb/code/) -- [FAST Breadcrumb (React)](https://github.com/microsoft/fast-react/tree/master/packages/react/fast-components-react-msft/src/breadcrumb) -- [Lightning Design System](https://www.lightningdesignsystem.com/components/breadcrumbs/#site-main-content) -- [Material UI](https://material-ui.com/components/breadcrumbs/) -- [Office Fabric](https://developer.microsoft.com/en-us/fluentui#/controls/web/breadcrumb) - ---- - -### API - -*Component Name* -- `fast-breadcrumb` - -*Properties* -- `slottedBreadcrumbItems` - HTMLElement[] used in the slotted directive. - -*Attribute* - -*Slot Names* -- `slottedBreadcrumbItems` - a property used in a slotted directive. - -### Anatomy and Appearance - -```html - -``` - ---- - -## Implementation - -```html - - Breadcrumb item 1 - Breadcrumb item 2 - Breadcrumb item 3 - -``` - -### Accessibility - -The breadcrumb should align to the interaction model provided by the [W3C](https://www.w3.org/TR/wai-aria-practices/#breadcrumb) -- `aria-current` - W3 specs says when using `aria-current="page"` the element should be a link. `fast-breadcrumb` will set `aria-current="page"` to the last element if there is an href attribute. - -### Globalization - -The overall order inside the breadcrumb will be reversed when switching in LTR/RTL. - -### Test Plan - -While testing is still TBD for our web components, I would expect this to align with the testing strategy and not require any additional test support. - - - -# Breadcrumb Item - -## Overview - -The `fast-breadcrumb-item` is placed inside the `fast-breadcrumb` component. It provides a slot with a default anchor. The component also provides a slot for a separator that defaults using a `/`. - -### API - -*Component Name* -- `fast-breadcrumb-item` - -*Attribute* - -*Properties* -- `separator` - is a boolean to show and hide the separator. - -*Slots* -- default slot for item. -- `separator` - breadcrumb separator. The default separator is "/" - -*CSS Parts* -- `listitem` - class style to align the control and the separator. -- `separator` - class style to adjust margin layout. - -### Anatomy and Appearance - -```html -
- ${when( - x => x.href && x.href.length > 0, - html` - ${AnchorTemplate} - ` - )} - ${when( - x => !x.href, - html` - ${startTemplate} - - ${endTemplate} - ` - )} - ${when( - x => x.separator, - html` - - ` - )} -
-``` - -## Implementation - -```html -Breadcrumb item -``` diff --git a/packages/web-components/fast-foundation/src/breadcrumb/breadcrumb.template.ts b/packages/web-components/fast-foundation/src/breadcrumb/breadcrumb.template.ts deleted file mode 100644 index 9047539b28d..00000000000 --- a/packages/web-components/fast-foundation/src/breadcrumb/breadcrumb.template.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { ElementViewTemplate } from "@microsoft/fast-element"; -import { elements, html, slotted } from "@microsoft/fast-element"; -import { endSlotTemplate, startSlotTemplate } from "../patterns/index.js"; -import type { BreadcrumbOptions, FASTBreadcrumb } from "./breadcrumb.js"; - -/** - * The template for the {@link @microsoft/fast-foundation#(FASTBreadcrumb:class)} component. - * @public - */ -export function breadcrumbTemplate( - options: BreadcrumbOptions = {} -): ElementViewTemplate { - return html` - - `; -} diff --git a/packages/web-components/fast-foundation/src/breadcrumb/breadcrumb.ts b/packages/web-components/fast-foundation/src/breadcrumb/breadcrumb.ts deleted file mode 100644 index 1850baf3da9..00000000000 --- a/packages/web-components/fast-foundation/src/breadcrumb/breadcrumb.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { FASTElement, observable } from "@microsoft/fast-element"; -import { FASTBreadcrumbItem } from "../breadcrumb-item/breadcrumb-item.js"; -import { StartEnd } from "../patterns/start-end.js"; -import type { StartEndOptions } from "../patterns/start-end.js"; -import { applyMixins } from "../utilities/apply-mixins.js"; - -/** - * Breadcrumb configuration options - * @public - */ -export type BreadcrumbOptions = StartEndOptions; - -/** - * A Breadcrumb Custom HTML Element. - * - * @slot start - Content which can be provided before the breadcrumbs - * @slot end - Content which can be provided after the breadcrumbs - * @slot - The default slot for the breadcrumb items - * @csspart list - The element wrapping the slotted items - * - * @public - */ -export class FASTBreadcrumb extends FASTElement { - /** - * @internal - */ - @observable - public slottedBreadcrumbItems: HTMLElement[]; - protected slottedBreadcrumbItemsChanged() { - if (this.$fastController.isConnected) { - if ( - this.slottedBreadcrumbItems === undefined || - this.slottedBreadcrumbItems.length === 0 - ) { - return; - } - - const lastNode: HTMLElement = - this.slottedBreadcrumbItems[this.slottedBreadcrumbItems.length - 1]; - - this.slottedBreadcrumbItems.forEach((item: HTMLElement) => { - const itemIsLastNode: boolean = item === lastNode; - - this.setItemSeparator(item, itemIsLastNode); - this.setAriaCurrent(item, itemIsLastNode); - }); - } - } - - private setItemSeparator(item: HTMLElement, isLastNode: boolean): void { - if (item instanceof FASTBreadcrumbItem) { - item.separator = !isLastNode; - } - } - - /** - * Finds anchor childnodes in the light DOM or shadow DOM. - * We look in the shadow DOM because we use an anchor inside the breadcrumb-item template. - */ - private findChildAnchor(node: HTMLElement): HTMLElement | null { - if (node.childElementCount > 0) { - return node.querySelector("a"); - } else if (node.shadowRoot?.childElementCount) { - return node.shadowRoot?.querySelector("a"); - } else return node; - } - - /** - * Sets ARIA Current for the "current" node - * `aria-current` is not optional and should be set regardless of the href value of a given anchor - */ - private setAriaCurrent(item: HTMLElement, isLastNode: boolean): void { - const childNode: HTMLElement | null = this.findChildAnchor(item); - - if (childNode !== null) { - isLastNode - ? childNode.setAttribute("aria-current", "page") - : childNode.removeAttribute("aria-current"); - } - } -} - -/** - * Mark internal because exporting class and interface of the same name - * confuses API documenter. - * TODO: https://github.com/microsoft/fast/issues/3317 - * @internal - */ -export interface FASTBreadcrumb extends StartEnd {} -applyMixins(FASTBreadcrumb, StartEnd); diff --git a/packages/web-components/fast-foundation/src/breadcrumb/index.ts b/packages/web-components/fast-foundation/src/breadcrumb/index.ts deleted file mode 100644 index 15e9eee9073..00000000000 --- a/packages/web-components/fast-foundation/src/breadcrumb/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { FASTBreadcrumb } from "./breadcrumb.js"; -export type { BreadcrumbOptions } from "./breadcrumb.js"; -export { breadcrumbTemplate } from "./breadcrumb.template.js"; diff --git a/packages/web-components/fast-foundation/src/breadcrumb/stories/breadcrumb.register.ts b/packages/web-components/fast-foundation/src/breadcrumb/stories/breadcrumb.register.ts deleted file mode 100644 index e9022a36fa5..00000000000 --- a/packages/web-components/fast-foundation/src/breadcrumb/stories/breadcrumb.register.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { css } from "@microsoft/fast-element"; -import { FASTBreadcrumb } from "../breadcrumb.js"; -import { breadcrumbTemplate } from "../breadcrumb.template.js"; - -const styles = css` - :host { - box-sizing: border-box; - display: inline-flex; - gap: 12px; - font: var(--type-ramp-base-font-size) / var(--type-ramp-base-line-height) - var(--body-font); - } - - .list { - display: flex; - flex-wrap: wrap; - } - - ::slotted(a) { - color: var(--neutral-foreground-rest); - margin: 0 6px; - } - - ::slotted(a[href]) { - color: var(--accent-foreground-rest); - } -`; - -FASTBreadcrumb.define({ - name: "fast-breadcrumb", - template: breadcrumbTemplate(), - styles, -}); diff --git a/packages/web-components/fast-foundation/src/breadcrumb/stories/breadcrumb.stories.ts b/packages/web-components/fast-foundation/src/breadcrumb/stories/breadcrumb.stories.ts deleted file mode 100644 index abfef043d3b..00000000000 --- a/packages/web-components/fast-foundation/src/breadcrumb/stories/breadcrumb.stories.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { html } from "@microsoft/fast-element"; -import type { Meta, Story, StoryArgs } from "../../__test__/helpers.js"; -import { renderComponent } from "../../__test__/helpers.js"; -import type { FASTBreadcrumb } from "../breadcrumb.js"; - -const storyTemplate = html>` - ${x => x.storyContent} -`; - -export default { - title: "Breadcrumb", - argTypes: { - storyContent: { table: { disable: true } }, - }, -} as Meta; - -export const Breadcrumb: Story = renderComponent(storyTemplate).bind({}); -Breadcrumb.args = { - storyContent: html` - Breadcrumb Item 1 - Breadcrumb Item 2 - Breadcrumb Item 3 - `, -}; - -export const BreadcrumbWithSlottedSeparator: Story = Breadcrumb.bind({}); -BreadcrumbWithSlottedSeparator.args = { - storyContent: html` - - Breadcrumb Item 1 - - - - Breadcrumb Item 2 - - - - Breadcrumb Item 3 - - - `, -}; - -export const BreadcrumbWithSlottedStartEnd: Story = Breadcrumb.bind({}); -BreadcrumbWithSlottedStartEnd.args = { - storyContent: html` - - Breadcrumb Item 1 - Breadcrumb Item 2 - Breadcrumb Item 3 - - `, -}; - -export const BreadcrumbWithAnchors: Story = Breadcrumb.bind({}); -BreadcrumbWithAnchors.args = { - storyContent: html` -
Anchor 1 - Anchor 2 - Anchor 3 - `, -}; diff --git a/packages/web-components/fast-foundation/src/button/README.md b/packages/web-components/fast-foundation/src/button/README.md deleted file mode 100644 index f216240816c..00000000000 --- a/packages/web-components/fast-foundation/src/button/README.md +++ /dev/null @@ -1,186 +0,0 @@ ---- -id: button -title: fast-button -sidebar_label: button -custom_edit_url: https://github.com/microsoft/fast/edit/master/packages/web-components/fast-foundation/src/button/README.md -description: fast-button is a web component implementation of a button element. ---- - -As defined by the [W3C](https://w3c.github.io/aria-practices/#button): - -> A button is a widget that enables users to trigger an action or event, such as submitting a form, opening a dialog, canceling an action, or performing a delete operation. - -`fast-button` is a web component implementation of an [HTML button element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button). The `fast-components` button supports several visual appearances (accent, lightweight, neutral, outline, stealth). - -## Setup - -```ts -import { - provideFASTDesignSystem, - fastButton -} from "@microsoft/fast-components"; - -provideFASTDesignSystem() - .register( - fastButton() - ); -``` - -## Usage - -```html live -Submit -``` - -## Create your own design - -```ts -import { - Button, - buttonTemplate as template, -} from "@microsoft/fast-foundation"; -import { buttonStyles as styles } from "./my-button.styles"; - -export const myButton = Button.compose({ - baseName: "button", - template, - styles, - shadowOptions: { - delegatesFocus: true, - }, -}); -``` - -:::note -This component is built with the expectation that focus is delegated to the button element rendered into the shadow DOM. -::: - -## API - - - -### class: `FormAssociatedButton` - -#### Superclass - -| Name | Module | Package | -| --------- | ------------------------------------ | ------- | -| `_Button` | src/button/button.form-associated.ts | | - -#### Mixins - -| Name | Module | Package | -| ---------------- | --------------------------------------- | ------- | -| `FormAssociated` | /src/form-associated/form-associated.js | | - -#### Fields - -| Name | Privacy | Type | Default | Description | Inherited From | -| ------- | ------- | ---- | ------- | ----------- | -------------- | -| `proxy` | | | | | | - -
- - - -### Variables - -| Name | Description | Type | -| ------------ | ------------------- | --------------------------------------------------------- | -| `ButtonType` | Button type values. | `{ submit: "submit", reset: "reset", button: "button", }` | - -
- - - -### class: `FASTButton` - -#### Superclass - -| Name | Module | Package | -| ---------------------- | ------------------------------------- | ------- | -| `FormAssociatedButton` | /src/button/button.form-associated.js | | - -#### Fields - -| Name | Privacy | Type | Default | Description | Inherited From | -| ----------------------- | ------- | -------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------- | -------------------- | -| `autofocus` | public | `boolean` | | Determines if the element should receive document focus on page load. | | -| `formId` | public | `string` | | The id of a form to associate the element to. | | -| `formaction` | public | `string` | | See [` - -``` -#### Anchor -```html - - - - - - - -``` - -- *Slot Names* - - start: the content to place at the start of the primary content - - default: the element's content - - end: the content to place at the end of the the primary content - -### Accessibility -Both components create *internal* native elements to which attributes will get reflected. Focus will also be deferred to these internal elements. \ No newline at end of file diff --git a/packages/web-components/fast-foundation/src/button/button.template.ts b/packages/web-components/fast-foundation/src/button/button.template.ts deleted file mode 100644 index 04b0d3303d6..00000000000 --- a/packages/web-components/fast-foundation/src/button/button.template.ts +++ /dev/null @@ -1,58 +0,0 @@ -import type { ElementViewTemplate } from "@microsoft/fast-element"; -import { html, ref, slotted } from "@microsoft/fast-element"; -import { endSlotTemplate, startSlotTemplate } from "../patterns/index.js"; -import type { ButtonOptions, FASTButton } from "./button.js"; - -/** - * The template for the {@link @microsoft/fast-foundation#(FASTButton:class)} component. - * @public - */ -export function buttonTemplate( - options: ButtonOptions = {} -): ElementViewTemplate { - return html` - - `; -} diff --git a/packages/web-components/fast-foundation/src/button/button.ts b/packages/web-components/fast-foundation/src/button/button.ts deleted file mode 100644 index 5460fb04afc..00000000000 --- a/packages/web-components/fast-foundation/src/button/button.ts +++ /dev/null @@ -1,245 +0,0 @@ -import { attr, observable } from "@microsoft/fast-element"; -import { ARIAGlobalStatesAndProperties, StartEnd } from "../patterns/index.js"; -import type { StartEndOptions } from "../patterns/start-end.js"; -import { applyMixins } from "../utilities/apply-mixins.js"; -import { FormAssociatedButton } from "./button.form-associated.js"; -import { ButtonType } from "./button.options.js"; - -/** - * Button configuration options - * @public - */ -export type ButtonOptions = StartEndOptions; - -/** - * A Button Custom HTML Element. - * Based largely on the {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button | - `, - }; - }); - - await element.focus(); - - expect(await page.evaluate(() => document.activeElement?.textContent)).toBe( - "test button" - ); - }); - - test("should focus on custom header cell template when a focus target callback is provided", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await element.evaluate((node: FASTDataGridCell, DataGridCellTypes) => { - node.cellType = DataGridCellTypes.columnHeader; - node.columnDefinition = { - columnDataKey: "item2", - headerCellTemplate: html` - - `, - headerCellFocusTargetCallback: cell => - cell.querySelector("button") as HTMLButtonElement, - }; - }, DataGridCellTypes); - - await element.focus(); - - expect(await page.evaluate(() => document.activeElement?.textContent)).toBe( - "test header button" - ); - }); -}); diff --git a/packages/web-components/fast-foundation/src/data-grid/data-grid-cell.template.ts b/packages/web-components/fast-foundation/src/data-grid/data-grid-cell.template.ts deleted file mode 100644 index deb9d25d37e..00000000000 --- a/packages/web-components/fast-foundation/src/data-grid/data-grid-cell.template.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { ElementViewTemplate } from "@microsoft/fast-element"; -import { html } from "@microsoft/fast-element"; -import type { FASTDataGridCell } from "./data-grid-cell.js"; -import { DataGridCellRole } from "./data-grid.options.js"; - -/** - * Generates a template for the {@link @microsoft/fast-foundation#FASTDataGridCell} component using - * the provided prefix. - * @public - */ -export function dataGridCellTemplate< - T extends FASTDataGridCell ->(): ElementViewTemplate { - return html` - - `; -} diff --git a/packages/web-components/fast-foundation/src/data-grid/data-grid-cell.ts b/packages/web-components/fast-foundation/src/data-grid/data-grid-cell.ts deleted file mode 100644 index f2d322fc61b..00000000000 --- a/packages/web-components/fast-foundation/src/data-grid/data-grid-cell.ts +++ /dev/null @@ -1,332 +0,0 @@ -import type { HTMLView, ViewTemplate } from "@microsoft/fast-element"; -import { attr, FASTElement, html, observable } from "@microsoft/fast-element"; -import { - eventFocusIn, - eventFocusOut, - eventKeyDown, - keyArrowDown, - keyArrowLeft, - keyArrowRight, - keyArrowUp, - keyEnd, - keyEnter, - keyEscape, - keyFunction2, - keyHome, - keyPageDown, - keyPageUp, -} from "@microsoft/fast-web-utilities"; -import { isFocusable } from "tabbable"; -import { getRootActiveElement } from "../utilities/index.js"; -import type { ColumnDefinition } from "./data-grid.js"; -import { DataGridCellTypes } from "./data-grid.options.js"; - -export { DataGridCellTypes }; - -const defaultCellContentsTemplate: ViewTemplate = html` - -`; - -const defaultHeaderCellContentsTemplate: ViewTemplate = html` - -`; - -// basic focusTargetCallback that returns the first child of the cell -export const defaultCellFocusTargetCallback = ( - cell: FASTDataGridCell -): HTMLElement | null => { - for (let i = 0; i < cell.children.length; i++) { - if (isFocusable(cell.children[i])) { - return cell.children[i] as HTMLElement; - } - } - return null; -}; - -/** - * A Data Grid Cell Custom HTML Element. - * - * @fires cell-focused - Fires a custom 'cell-focused' event when focus is on the cell or its contents - * @slot - The default slot for cell contents. The "cell contents template" renders here. - * @public - */ -export class FASTDataGridCell extends FASTElement { - /** - * The type of cell - * - * @public - * @remarks - * HTML Attribute: cell-type - */ - @attr({ attribute: "cell-type" }) - public cellType: DataGridCellTypes = DataGridCellTypes.default; - private cellTypeChanged(): void { - if (this.$fastController.isConnected) { - this.updateCellView(); - } - } - - /** - * The column index of the cell. - * This will be applied to the css grid-column-index value - * applied to the cell - * - * @public - * @remarks - * HTML Attribute: grid-column - */ - @attr({ attribute: "grid-column" }) - public gridColumn: string; - protected gridColumnChanged(): void { - if (this.$fastController.isConnected) { - this.updateCellStyle(); - } - } - - /** - * The base data for the parent row - * - * @public - */ - @observable - public rowData: object | null = null; - - /** - * The base data for the column - * - * @public - */ - @observable - public columnDefinition: ColumnDefinition | null = null; - protected columnDefinitionChanged( - oldValue: ColumnDefinition | null, - newValue: ColumnDefinition | null - ): void { - if (this.$fastController.isConnected) { - this.updateCellView(); - } - } - - private isActiveCell: boolean = false; - private customCellView: HTMLView | null = null; - - /** - * @internal - */ - public connectedCallback(): void { - super.connectedCallback(); - - this.addEventListener(eventFocusIn, this.handleFocusin); - this.addEventListener(eventFocusOut, this.handleFocusout); - this.addEventListener(eventKeyDown, this.handleKeydown); - - this.style.gridColumn = `${ - this.columnDefinition?.gridColumn === undefined - ? 0 - : this.columnDefinition.gridColumn - }`; - - this.updateCellView(); - this.updateCellStyle(); - } - - /** - * @internal - */ - public disconnectedCallback(): void { - super.disconnectedCallback(); - - this.removeEventListener(eventFocusIn, this.handleFocusin); - this.removeEventListener(eventFocusOut, this.handleFocusout); - this.removeEventListener(eventKeyDown, this.handleKeydown); - - this.disconnectCellView(); - } - - public handleFocusin(e: FocusEvent): void { - if (this.isActiveCell) { - return; - } - - this.isActiveCell = true; - - switch (this.cellType) { - case DataGridCellTypes.columnHeader: - if ( - this.columnDefinition !== null && - this.columnDefinition.headerCellInternalFocusQueue !== true && - typeof this.columnDefinition.headerCellFocusTargetCallback === - "function" - ) { - // move focus to the focus target - const focusTarget: HTMLElement | null = - this.columnDefinition.headerCellFocusTargetCallback(this); - if (focusTarget !== null) { - focusTarget.focus(); - } - } - break; - - default: - if ( - this.columnDefinition !== null && - this.columnDefinition.cellInternalFocusQueue !== true && - typeof this.columnDefinition.cellFocusTargetCallback === "function" - ) { - // move focus to the focus target - const focusTarget: HTMLElement | null = - this.columnDefinition.cellFocusTargetCallback(this); - if (focusTarget !== null) { - focusTarget.focus(); - } - } - break; - } - - this.$emit("cell-focused", this); - } - - public handleFocusout(e: FocusEvent): void { - const activeElement: Element | null = getRootActiveElement(this); - if (this !== activeElement && !this.contains(activeElement)) { - this.isActiveCell = false; - } - } - - private hasInternalFocusQueue(): boolean { - if (this.columnDefinition === null) { - return false; - } - if ( - (this.cellType === DataGridCellTypes.default && - this.columnDefinition.cellInternalFocusQueue) || - (this.cellType === DataGridCellTypes.columnHeader && - this.columnDefinition.headerCellInternalFocusQueue) - ) { - return true; - } - return false; - } - - public handleKeydown(e: KeyboardEvent): void { - // if the cell does not have an internal focus queue we can ignore keystrokes - if ( - e.defaultPrevented || - this.columnDefinition === null || - !this.hasInternalFocusQueue() - ) { - return; - } - - const rootActiveElement: Element | null = getRootActiveElement(this); - - switch (e.key) { - case keyEnter: - case keyFunction2: - if (this.contains(rootActiveElement) && rootActiveElement !== this) { - return; - } - - switch (this.cellType) { - case DataGridCellTypes.columnHeader: - if ( - this.columnDefinition.headerCellFocusTargetCallback !== - undefined - ) { - const focusTarget: HTMLElement | null = - this.columnDefinition.headerCellFocusTargetCallback(this); - if (focusTarget !== null) { - focusTarget.focus(); - } - e.preventDefault(); - } - break; - - default: - if (this.columnDefinition.cellFocusTargetCallback !== undefined) { - const focusTarget: HTMLElement | null = - this.columnDefinition.cellFocusTargetCallback(this); - if (focusTarget !== null) { - focusTarget.focus(); - } - e.preventDefault(); - } - break; - } - break; - - case keyEscape: - if (this.contains(rootActiveElement) && rootActiveElement !== this) { - this.focus(); - e.preventDefault(); - } - break; - - // stop any unhandled grid nav events that may bubble from the cell - // when internal navigation is active. - // note: preventDefault would also block arrow keys in input elements - case keyArrowDown: - case keyArrowLeft: - case keyArrowRight: - case keyArrowUp: - case keyEnd: - case keyHome: - case keyPageDown: - case keyPageUp: - if (this.contains(rootActiveElement) && rootActiveElement !== this) { - e.stopPropagation(); - } - break; - } - } - - private updateCellView(): void { - this.disconnectCellView(); - - if (this.columnDefinition === null) { - return; - } - - switch (this.cellType) { - case DataGridCellTypes.columnHeader: - this.customCellView = html` - ${this.columnDefinition.headerCellTemplate ?? - defaultHeaderCellContentsTemplate} - `.render(this, this); - break; - - case undefined: - case DataGridCellTypes.rowHeader: - case DataGridCellTypes.default: - this.customCellView = html` - ${this.columnDefinition.cellTemplate ?? defaultCellContentsTemplate} - `.render(this, this); - break; - } - } - - private disconnectCellView(): void { - if (this.customCellView !== null) { - this.customCellView.dispose(); - this.customCellView = null; - } - } - - private updateCellStyle = (): void => { - this.style.gridColumn = this.gridColumn; - }; -} diff --git a/packages/web-components/fast-foundation/src/data-grid/data-grid-row.pw.spec.ts b/packages/web-components/fast-foundation/src/data-grid/data-grid-row.pw.spec.ts deleted file mode 100644 index b464eb09d5d..00000000000 --- a/packages/web-components/fast-foundation/src/data-grid/data-grid-row.pw.spec.ts +++ /dev/null @@ -1,241 +0,0 @@ -import type { Locator, Page } from "@playwright/test"; -import { expect, test } from "@playwright/test"; -import { fixtureURL } from "../__test__/helpers.js"; -import type { FASTDataGridRow } from "./data-grid-row.js"; - -test.describe("DataGridRow", () => { - const cellQueryString = "fast-data-grid-cell"; - - let page: Page; - let element: Locator; - let root: Locator; - - test.beforeAll(async ({ browser }) => { - page = await browser.newPage(); - - element = page.locator("fast-data-grid-row"); - - root = page.locator("#storybook-root"); - - await page.goto(fixtureURL("data-grid-data-grid-row--data-grid-row")); - - await root.waitFor({ state: "visible" }); - }); - - test.afterAll(async () => { - await page.close(); - }); - - test('should set the `role` attribute to "row" by default', async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element).toHaveAttribute("role", "row"); - }); - - test("should set `grid-template-columns` style to match attribute", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element).toHaveAttribute( - "style", - "grid-template-columns: 1fr 2fr 3fr;" - ); - }); - - test("should fire an event when a child cell is focused", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - - - `; - }); - - const cell = page.locator(cellQueryString).first(); - - const [wasFocused] = await Promise.all([ - element.evaluate(node => { - return new Promise(resolve => { - node.addEventListener("row-focused", () => { - resolve(true); - }); - }); - }), - cell.evaluate(node => { - node.focus(); - }), - ]); - - expect(wasFocused).toBeTruthy(); - }); - - test("should move focus with left/right arrow key strokes", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - - - - - `; - }); - - await element.locator(cellQueryString).first().focus(); - - await expect(element).toHaveJSProperty("focusColumnIndex", 0); - - await page.keyboard.press("ArrowRight"); - - await expect(element).toHaveJSProperty("focusColumnIndex", 1); - - await page.keyboard.press("ArrowLeft"); - - await expect(element).toHaveJSProperty("focusColumnIndex", 0); - }); - - test("should move focus to the start/end of the row with home/end keystrokes", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - - - - - `; - }); - - await element.locator(cellQueryString).first().focus(); - - await expect(element).toHaveJSProperty("focusColumnIndex", 0); - - await page.keyboard.press("End"); - - await expect(element).toHaveJSProperty("focusColumnIndex", 2); - - await page.keyboard.press("Home"); - - await expect(element).toHaveJSProperty("focusColumnIndex", 0); - }); - - test("should render no cells if provided no column definitions", async () => { - const cells = element.locator("fast-data-grid-cell"); - - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await element.evaluate((node: FASTDataGridRow) => { - node.rowData = { - name: "row 1", - value1: "value 1", - }; - }); - - await expect(cells).toHaveCount(0); - }); - - test("should render as many column header cells as specified in column definitions", async () => { - const cells = element.locator(cellQueryString); - - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await element.evaluate((node: FASTDataGridRow) => { - node.columnDefinitions = [{ columnDataKey: "item1" }]; - }); - - await expect(cells).toHaveCount(1); - - await element.evaluate((node: FASTDataGridRow) => { - node.columnDefinitions = [ - { columnDataKey: "item1" }, - { columnDataKey: "item2" }, - ]; - }); - - await expect(cells).toHaveCount(2); - - await element.evaluate((node: FASTDataGridRow) => { - node.columnDefinitions = [ - { columnDataKey: "item1" }, - { columnDataKey: "item2" }, - { columnDataKey: "item3" }, - ]; - }); - - await expect(cells).toHaveCount(3); - }); - - test("should emit a 'rowselectionchange' event when clicked with disableClickSelect disabled", async () => { - await root.evaluate((node: FASTDataGridRow) => { - node.innerHTML = /* html */ ` - - - - `; - node.disableClickSelect = false; - }); - - const wasInvoked = await Promise.all([ - element.evaluate(node => - node.addEventListener("rowselectionchange", () => true) - ), - element.click(), - ]); - - expect(wasInvoked).toBeTruthy; - }); - - test("should not emit a 'rowselectionchange' event when clicked with disableClickSelect disabled", async () => { - await root.evaluate((node: FASTDataGridRow) => { - node.innerHTML = /* html */ ` - - - - `; - node.disableClickSelect = true; - }); - - const wasInvoked = await Promise.all([ - element.evaluate(node => - node.addEventListener("rowselectionchange", () => true) - ), - element.click(), - ]); - - expect(wasInvoked).toBeFalsy; - }); - - test("should emit a 'rowselectionchange' event when space key is pressed with disableClickSelect disabled", async () => { - await root.evaluate((node: FASTDataGridRow) => { - node.innerHTML = /* html */ ` - - - - `; - node.disableClickSelect = false; - }); - - const wasInvoked = await Promise.all([ - element.evaluate(node => { - node.addEventListener("rowselectionchange", () => true); - // FIXME: Playwright's keyboard API is not working as expected. - node.dispatchEvent(new KeyboardEvent("keydown", { key: "Space" })); - }), - ]); - - expect(wasInvoked).toBeTruthy; - }); -}); diff --git a/packages/web-components/fast-foundation/src/data-grid/data-grid-row.template.ts b/packages/web-components/fast-foundation/src/data-grid/data-grid-row.template.ts deleted file mode 100644 index 3866e591f2c..00000000000 --- a/packages/web-components/fast-foundation/src/data-grid/data-grid-row.template.ts +++ /dev/null @@ -1,68 +0,0 @@ -import type { ElementViewTemplate, ViewTemplate } from "@microsoft/fast-element"; -import { children, elements, html, slotted } from "@microsoft/fast-element"; -import type { TemplateElementDependency } from "../patterns/index.js"; -import { tagFor } from "../patterns/index.js"; -import type { FASTDataGridRow } from "./data-grid-row.js"; -import type { ColumnDefinition } from "./data-grid.js"; - -/** - * Options for data grid cells. - * @public - */ -export type CellItemTemplateOptions = { - dataGridCell: TemplateElementDependency; -}; - -function cellItemTemplate( - options: CellItemTemplateOptions -): ViewTemplate { - const cellTag = html.partial(tagFor(options.dataGridCell)); - return html` - <${cellTag} - cell-type="${x => (x.isRowHeader ? "rowheader" : undefined)}" - grid-column="${(x, c) => c.index + 1}" - :rowData="${(x, c) => c.parent.rowData}" - :columnDefinition="${x => x}" - > -`; -} - -function headerCellItemTemplate( - options: CellItemTemplateOptions -): ViewTemplate { - const cellTag = html.partial(tagFor(options.dataGridCell)); - return html` - <${cellTag} - cell-type="columnheader" - grid-column="${(x, c) => c.index + 1}" - :columnDefinition="${x => x}" - > -`; -} - -/** - * Generates a template for the {@link @microsoft/fast-foundation#FASTDataGridRow} component using - * the provided prefix. - * - * @public - */ -export function dataGridRowTemplate( - options: CellItemTemplateOptions -): ElementViewTemplate { - return html` - - `; -} diff --git a/packages/web-components/fast-foundation/src/data-grid/data-grid-row.ts b/packages/web-components/fast-foundation/src/data-grid/data-grid-row.ts deleted file mode 100644 index b76704dc11a..00000000000 --- a/packages/web-components/fast-foundation/src/data-grid/data-grid-row.ts +++ /dev/null @@ -1,358 +0,0 @@ -import type { ViewTemplate } from "@microsoft/fast-element"; -import { - attr, - FASTElement, - observable, - oneWay, - RepeatDirective, -} from "@microsoft/fast-element"; -import { ViewBehaviorOrchestrator } from "@microsoft/fast-element/utilities.js"; -import { - eventClick, - eventFocusOut, - eventKeyDown, - keyArrowLeft, - keyArrowRight, - keyEnd, - keyHome, - keySpace, -} from "@microsoft/fast-web-utilities"; -import type { ColumnDefinition } from "./data-grid.js"; -import type { DataGridSelectionChangeDetail } from "./data-grid.options.js"; -import { DataGridRowTypes, DataGridSelectionBehavior } from "./data-grid.options.js"; - -/** - * A Data Grid Row Custom HTML Element. - * - * @fires row-focused - Fires a custom 'row-focused' event when focus is on an element (usually a cell or its contents) in the row - * @slot - The default slot for custom cell elements - * @public - */ -export class FASTDataGridRow extends FASTElement { - /** - * String that gets applied to the the css gridTemplateColumns attribute for the row - * - * @public - * @remarks - * HTML Attribute: grid-template-columns - */ - @attr({ attribute: "grid-template-columns" }) - public gridTemplateColumns: string; - protected gridTemplateColumnsChanged(): void { - if (this.$fastController.isConnected) { - this.updateRowStyle(); - } - } - - /** - * The type of row - * - * @public - * @remarks - * HTML Attribute: row-type - */ - @attr({ attribute: "row-type" }) - public rowType: DataGridRowTypes = DataGridRowTypes.default; - private rowTypeChanged(): void { - if (this.$fastController.isConnected) { - this.updateItemTemplate(); - } - } - - /** - * The base data for this row - * - * @public - */ - @observable - public rowData: object | null = null; - protected rowDataChanged(): void { - if (this.rowData !== null && this.isActiveRow) { - this.refocusOnLoad = true; - return; - } - } - - /** - * The column definitions of the row - * - * @public - */ - @observable - public columnDefinitions: ColumnDefinition[] | null = null; - - /** - * The template used to render cells in generated rows. - * - * @public - */ - @observable - public cellItemTemplate?: ViewTemplate; - private cellItemTemplateChanged(): void { - this.updateItemTemplate(); - } - - /** - * The template used to render header cells in generated rows. - * - * @public - */ - @observable - public headerCellItemTemplate?: ViewTemplate; - private headerCellItemTemplateChanged(): void { - this.updateItemTemplate(); - } - - /** - * The index of the row in the parent grid. - * This is typically set programmatically by the parent grid. - * - * @public - */ - @observable - public rowIndex: number; - - /** - * Whether focus is on/in a cell within this row. - * - * @internal - */ - @observable - public isActiveRow: boolean = false; - - /** - * The cell item template currently in use. - * - * @internal - */ - @observable - public activeCellItemTemplate?: ViewTemplate; - - /** - * The default cell item template. Set by the component templates. - * - * @internal - */ - @observable - public defaultCellItemTemplate?: ViewTemplate; - - /** - * The default header cell item template. Set by the component templates. - * - * @internal - */ - @observable - public defaultHeaderCellItemTemplate?: ViewTemplate; - - /** - * Children that are cells - * - * @internal - */ - @observable - public cellElements: HTMLElement[]; - - private behaviorOrchestrator: ViewBehaviorOrchestrator | null = null; - /** - * If the row is selected. - * - * @internal - */ - @observable - public selected: boolean; - - /** - * Selection behavior - * - * @internal - */ - public selectionBehavior: DataGridSelectionBehavior = DataGridSelectionBehavior.auto; - - /** - * @internal - */ - public slottedCellElements: HTMLElement[]; - - /** - * @internal - */ - public focusColumnIndex: number = 0; - - private refocusOnLoad: boolean = false; - - /** - * @internal - */ - public connectedCallback(): void { - super.connectedCallback(); - - // note that row elements can be reused with a different data object - // as the parent grid's repeat behavior reacts to changes in the data set. - if (this.behaviorOrchestrator === null) { - this.updateItemTemplate(); - - this.behaviorOrchestrator = ViewBehaviorOrchestrator.create(this); - this.$fastController.addBehavior(this.behaviorOrchestrator); - this.behaviorOrchestrator.addBehaviorFactory( - new RepeatDirective( - oneWay(x => x.columnDefinitions), - oneWay(x => x.activeCellItemTemplate), - { positioning: true } - ), - this.appendChild(document.createComment("")) - ); - } - - this.addEventListener("cell-focused", this.handleCellFocus); - this.addEventListener(eventFocusOut, this.handleFocusout); - this.addEventListener(eventKeyDown, this.handleKeydown); - this.addEventListener(eventClick, this.handleClick); - - this.updateRowStyle(); - - if (this.refocusOnLoad) { - // if focus was on the row when data changed try to refocus on same cell - this.refocusOnLoad = false; - if (this.cellElements.length > this.focusColumnIndex) { - (this.cellElements[this.focusColumnIndex] as HTMLElement).focus(); - } - } - } - - /** - * @internal - */ - public disconnectedCallback(): void { - super.disconnectedCallback(); - - this.removeEventListener("cell-focused", this.handleCellFocus); - this.removeEventListener(eventFocusOut, this.handleFocusout); - this.removeEventListener(eventKeyDown, this.handleKeydown); - this.removeEventListener(eventClick, this.handleClick); - } - - /** - * Attempts to set the selected state of the row - * - * @public - */ - public toggleSelected(detail: DataGridSelectionChangeDetail): void { - this.$emit("rowselectionchange", detail); - } - - public handleFocusout(e: FocusEvent): void { - if (!this.contains(e.target as Element)) { - this.isActiveRow = false; - this.focusColumnIndex = 0; - } - } - - /** - * @internal - */ - public handleCellFocus(e: Event): void { - this.isActiveRow = true; - this.focusColumnIndex = this.cellElements.indexOf(e.target as HTMLElement); - this.$emit("row-focused", this); - } - - /** - * @internal - */ - public handleKeydown(e: KeyboardEvent): void { - if (e.defaultPrevented) { - return; - } - let newFocusColumnIndex: number = 0; - switch (e.key) { - case keyArrowLeft: - // focus left one cell - newFocusColumnIndex = Math.max(0, this.focusColumnIndex - 1); - (this.cellElements[newFocusColumnIndex] as HTMLElement).focus(); - e.preventDefault(); - break; - - case keyArrowRight: - // focus right one cell - newFocusColumnIndex = Math.min( - this.cellElements.length - 1, - this.focusColumnIndex + 1 - ); - (this.cellElements[newFocusColumnIndex] as HTMLElement).focus(); - e.preventDefault(); - break; - - case keyHome: - if (!e.ctrlKey) { - (this.cellElements[0] as HTMLElement).focus(); - e.preventDefault(); - } - break; - case keyEnd: - if (!e.ctrlKey) { - // focus last cell of the row - ( - this.cellElements[this.cellElements.length - 1] as HTMLElement - ).focus(); - e.preventDefault(); - } - break; - - case keySpace: - if ( - this.selected !== undefined && - this.selectionBehavior !== DataGridSelectionBehavior.programmatic - ) { - e.preventDefault(); - this.toggleSelected({ - newValue: !this.isSelected(), - shiftKey: e.shiftKey, - ctrlKey: e.ctrlKey, - isKeyboardEvent: true, - }); - } - break; - } - } - - private isSelected(): boolean { - return this.selected; - } - - /** - * @internal - */ - public handleClick(e: MouseEvent): void { - if ( - e.defaultPrevented || - this.selectionBehavior !== DataGridSelectionBehavior.auto || - this.selected === undefined - ) { - return; - } - e.preventDefault(); - this.toggleSelected({ - newValue: !this.isSelected(), - shiftKey: e.shiftKey, - ctrlKey: e.ctrlKey, - isKeyboardEvent: false, - }); - } - - private updateItemTemplate(): void { - this.activeCellItemTemplate = - this.rowType === DataGridRowTypes.default && - this.cellItemTemplate !== undefined - ? this.cellItemTemplate - : this.rowType === DataGridRowTypes.default && - this.cellItemTemplate === undefined - ? this.defaultCellItemTemplate - : this.headerCellItemTemplate !== undefined - ? this.headerCellItemTemplate - : this.defaultHeaderCellItemTemplate; - } - - private updateRowStyle = (): void => { - this.style.gridTemplateColumns = this.gridTemplateColumns; - }; -} diff --git a/packages/web-components/fast-foundation/src/data-grid/data-grid.options.ts b/packages/web-components/fast-foundation/src/data-grid/data-grid.options.ts deleted file mode 100644 index 15dc693b6fb..00000000000 --- a/packages/web-components/fast-foundation/src/data-grid/data-grid.options.ts +++ /dev/null @@ -1,144 +0,0 @@ -import type { ValuesOf } from "../utilities/index.js"; - -/** - * Enumerates the data grid auto generated header options - * default option generates a non-sticky header row - * - * @public - */ -export const GenerateHeaderOptions = { - none: "none", - default: "default", - sticky: "sticky", -} as const; - -/** - * The types for the data grid auto generated header options - * - * @public - */ -export type GenerateHeaderOptions = ValuesOf; - -/** - * Enumerates possible data grid cell types. - * - * @public - */ -export const DataGridCellTypes = { - default: "default", - columnHeader: "columnheader", - rowHeader: "rowheader", -} as const; - -/** - * The possible cell types. - * - * @public - */ -export type DataGridCellTypes = ValuesOf; - -/** - * Enumerates possible data grid row types - * - * @public - */ -export const DataGridRowTypes = { - default: "default", - header: "header", - stickyHeader: "sticky-header", -} as const; - -/** - * The possible data grid row types - * - * @public - */ -export type DataGridRowTypes = ValuesOf; - -/** - * Class names for the data grid cell - * @public - */ -export const DataGridCellTypeClass = { - columnheader: "column-header", - default: "", - rowheader: "row-header", -} as const; - -/** - * Types for the data grid cell class names - * @public - */ -export type DataGridCellTypeClass = ValuesOf; - -/** - * Roles for the data grid cell - * - * @public - */ -export const DataGridCellRole = { - columnheader: "columnheader", - rowheader: "rowheader", - default: "gridcell", -} as const; - -/** - * Type for the data grid cell roles - * @public - */ -export type DataGridCellRole = ValuesOf; - -/** - * Event detail for DataGridRow row/cell selectionchanged events - * - * @internal - */ -export interface DataGridSelectionChangeDetail { - // the new selected value - newValue: boolean; - - // if the shiftKey is pressed - shiftKey: boolean; - - // if the control key is pressed - ctrlKey: boolean; - - // is keyboard event - isKeyboardEvent: boolean; -} - -/** - * Enumerates the data grid selection mode options - * - * @public - */ -export const DataGridSelectionMode = { - none: "none", - singleRow: "single-row", - multiRow: "multi-row", -} as const; - -/** - * The types for the data grid selection mode options - * - * @public - */ -export type DataGridSelectionMode = ValuesOf; - -/** - * Enumerates the data grid selection behavior options - * - * @public - */ -export const DataGridSelectionBehavior = { - programmatic: "programmatic", - keyboardOnly: "keyboard-only", - auto: "auto", -} as const; - -/** - * The types for the data grid selection mode options - * - * @public - */ -export type DataGridSelectionBehavior = ValuesOf; diff --git a/packages/web-components/fast-foundation/src/data-grid/data-grid.pw.spec.ts b/packages/web-components/fast-foundation/src/data-grid/data-grid.pw.spec.ts deleted file mode 100644 index bfa5c8f54d6..00000000000 --- a/packages/web-components/fast-foundation/src/data-grid/data-grid.pw.spec.ts +++ /dev/null @@ -1,777 +0,0 @@ -import { expect, test } from "@playwright/test"; -import type { Locator, Page } from "@playwright/test"; -import { fixtureURL } from "../__test__/helpers.js"; -import type { FASTDataGridRow } from "./data-grid-row.js"; -import type { FASTDataGrid } from "./data-grid.js"; -import { DataGridRowTypes } from "./data-grid.options.js"; - -test.describe("Data grid", () => { - let page: Page; - let element: Locator; - let root: Locator; - - const selectedRowQueryString = '[aria-selected="true"]'; - const rowQueryString = "fast-data-grid-row"; - - test.beforeAll(async ({ browser }) => { - page = await browser.newPage(); - - element = page.locator("fast-data-grid"); - - root = page.locator("#storybook-root"); - - await page.goto(fixtureURL("data-grid--data-grid")); - - await page.waitForSelector( - "#storybook-root, fast-data-grid, fast-data-grid-row, fast-data-grid-cell" - ); - }); - - test.afterAll(async () => { - await page.close(); - }); - - test("should set role to 'grid'", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element).toHaveAttribute("role", "grid"); - }); - - test("should have a tabIndex of 0 by default", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element).toHaveAttribute("tabindex", "0"); - }); - - test("should have a tabIndex of -1 when no-tabbing is true", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element).toHaveAttribute("tabindex", "-1"); - }); - - test("should have a tabIndex of -1 when a cell is focused", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - - Cell 1 - Cell 2 - - - `; - }); - - await element.locator("fast-data-grid-cell").first().focus(); - - await expect(element).toHaveAttribute("tabindex", "-1"); - }); - - test("should generate a basic grid with a row header based on rowsData only", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - element.evaluate((node: FASTDataGrid) => { - node.rowsData = [ - { id: "1", name: "Person 1" }, - { id: "2", name: "Person 2" }, - ]; - }); - - const rows = element.locator(rowQueryString); - - await expect(rows).toHaveCount(3); - - const row1 = rows.nth(0); - - await expect(row1).toHaveAttribute("row-type", DataGridRowTypes.header); - - const row1Cells = row1.locator("fast-data-grid-cell"); - - await expect(row1Cells).toHaveCount(2); - - await expect(row1Cells.nth(0)).toHaveText("id"); - - await expect(row1Cells.nth(1)).toHaveText("name"); - - const row2 = rows.nth(1); - - await expect(row2).toHaveAttribute("row-type", DataGridRowTypes.default); - - const row2Cells = row2.locator("fast-data-grid-cell"); - - await expect(row2Cells).toHaveCount(2); - - await expect(row2Cells.nth(0)).toHaveText("1"); - - await expect(row2Cells.nth(1)).toHaveText("Person 1"); - - const row3 = rows.nth(2); - - await expect(row3).toHaveAttribute("row-type", DataGridRowTypes.default); - - const row3Cells = row3.locator("fast-data-grid-cell"); - - await expect(row3Cells).toHaveCount(2); - - await expect(row3Cells.nth(0)).toHaveText("2"); - - await expect(row3Cells.nth(1)).toHaveText("Person 2"); - }); - - test("should not generate a header when `generateHeader` is `none`", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - element.evaluate((node: FASTDataGrid) => { - node.rowsData = [ - { id: "1", name: "Person 1" }, - { id: "2", name: "Person 2" }, - ]; - }); - - const rows = element.locator(rowQueryString); - - await expect(rows).toHaveCount(2); - - const row1 = rows.nth(0); - - await expect(row1).toHaveAttribute("row-type", DataGridRowTypes.default); - - const row1Cells = row1.locator("fast-data-grid-cell"); - - await expect(row1Cells).toHaveCount(2); - - await expect(row1Cells.nth(0)).toHaveText("1"); - - await expect(row1Cells.nth(1)).toHaveText("Person 1"); - - const row2 = rows.nth(1); - - await expect(row2).toHaveAttribute("row-type", DataGridRowTypes.default); - - const row2Cells = row2.locator("fast-data-grid-cell"); - - await expect(row2Cells).toHaveCount(2); - - await expect(row2Cells.nth(0)).toHaveText("2"); - - await expect(row2Cells.nth(1)).toHaveText("Person 2"); - }); - - test("should not generate a header when rowsData is empty", async () => { - await root.evaluate(node => { - node.innerHTML = ""; - - const dataGrid = document.createElement("fast-data-grid") as FASTDataGrid; - - dataGrid.rowsData = []; - - node.append(dataGrid); - }); - - const rows = element.locator(rowQueryString); - - await expect(rows).toHaveCount(0); - }); - - test("should generate a sticky header when generateHeader is set to 'sticky'", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - element.evaluate((node: FASTDataGrid) => { - node.rowsData = [ - { id: "1", name: "Person 1" }, - { id: "2", name: "Person 2" }, - ]; - }); - - const rows = element.locator(rowQueryString); - - await expect(rows).toHaveCount(3); - - const row1 = rows.nth(0); - - await expect(row1).toHaveAttribute("row-type", DataGridRowTypes.stickyHeader); - - const row1Cells = row1.locator("fast-data-grid-cell"); - - await expect(row1Cells).toHaveCount(2); - - await expect(row1Cells.nth(0)).toHaveText("id"); - - await expect(row1Cells.nth(1)).toHaveText("name"); - - const row2 = rows.nth(1); - - await expect(row2).toHaveAttribute("row-type", DataGridRowTypes.default); - - const row2Cells = row2.locator("fast-data-grid-cell"); - - await expect(row2Cells).toHaveCount(2); - - await expect(row2Cells.nth(0)).toHaveText("1"); - - await expect(row2Cells.nth(1)).toHaveText("Person 1"); - - const row3 = rows.nth(2); - - await expect(row3).toHaveAttribute("row-type", DataGridRowTypes.default); - - const row3Cells = row3.locator("fast-data-grid-cell"); - - await expect(row3Cells).toHaveCount(2); - - await expect(row3Cells.nth(0)).toHaveText("2"); - - await expect(row3Cells.nth(1)).toHaveText("Person 2"); - }); - - test("should set the row index attribute of child rows'", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - element.evaluate((node: FASTDataGrid) => { - node.rowsData = [ - { id: "1", name: "Person 1" }, - { id: "2", name: "Person 2" }, - ]; - }); - - const rows = element.locator(rowQueryString); - - await expect(rows).toHaveCount(3); - - const rowsCount = await rows.count(); - for (let i = 0; i < rowsCount; i++) { - expect( - await rows.nth(i).evaluate((node: FASTDataGridRow) => node.rowIndex) - ).toBe(i); - } - }); - - test("should move focus with up/down arrow key strokes", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - element.evaluate((node: FASTDataGrid) => { - node.rowsData = [ - { id: "1", name: "Person 1" }, - { id: "2", name: "Person 2" }, - { id: "3", name: "Person 3" }, - ]; - }); - - const rows = element.locator(rowQueryString); - - await expect(rows).toHaveCount(3); - - const row1 = rows.nth(0); - - const row2 = rows.nth(1); - - const row3 = rows.nth(2); - - const row1Cells = row1.locator("fast-data-grid-cell"); - - const row2Cells = row2.locator("fast-data-grid-cell"); - - const row3Cells = row3.locator("fast-data-grid-cell"); - - await row1Cells.nth(0).click(); - - await expect(row1Cells.nth(0)).toBeFocused(); - - await row1Cells.nth(0).press("ArrowDown"); - - await expect(row2Cells.nth(0)).toBeFocused(); - - await row2Cells.nth(0).press("ArrowDown"); - - await expect(row3Cells.nth(0)).toBeFocused(); - - await row3Cells.nth(0).press("ArrowUp"); - - await expect(row2Cells.nth(0)).toBeFocused(); - }); - - test("should move focus to first/last cells with ctrl + home/end key strokes", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - element.evaluate((node: FASTDataGrid) => { - node.rowsData = [ - { id: "1", name: "item 1", shape: "circle" }, - { id: "2", name: "item 2", shape: "square" }, - { id: "3", name: "item 3", shape: "triangle" }, - ]; - }); - - const rows = element.locator(rowQueryString); - - const firstCell = rows.nth(0).locator("fast-data-grid-cell").nth(0); - - const lastCell = rows.nth(2).locator("fast-data-grid-cell").nth(2); - - await firstCell.focus(); - - await expect(firstCell).toBeFocused(); - - await page.keyboard.press("Control+End"); - - await expect(lastCell).toBeFocused(); - - await page.keyboard.press("Control+Home"); - - await expect(firstCell).toBeFocused(); - }); - - test("should move focus by setting the `focusRowIndex` property", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - element.evaluate((node: FASTDataGrid) => { - node.rowsData = [ - { id: "1", name: "item 1", shape: "circle" }, - { id: "2", name: "item 2", shape: "square" }, - { id: "3", name: "item 3", shape: "triangle" }, - ]; - }); - - const cells = element.locator("fast-data-grid-cell"); - - await expect(cells).toHaveCount(9); - - await cells.nth(0).focus(); - - await expect(cells.nth(0)).toBeFocused(); - - await element.evaluate((node: FASTDataGrid) => { - node.focusRowIndex = 1; - }); - - await expect(cells.nth(3)).toBeFocused(); - - await element.evaluate((node: FASTDataGrid) => { - node.focusRowIndex = 2; - }); - - await expect(cells.nth(6)).toBeFocused(); - - await element.evaluate((node: FASTDataGrid) => { - node.focusRowIndex = 0; - }); - - await expect(cells.nth(0)).toBeFocused(); - }); - - test("should move focus by setting `focusColumnIndex`", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - element.evaluate((node: FASTDataGrid) => { - node.rowsData = [ - { id: "1", name: "item 1", shape: "circle" }, - { id: "2", name: "item 2", shape: "square" }, - { id: "3", name: "item 3", shape: "triangle" }, - ]; - }); - - const cells = element.locator("fast-data-grid-cell"); - - await expect(cells).toHaveCount(9); - - await cells.nth(0).focus(); - - await expect(cells.nth(0)).toBeFocused(); - - await element.evaluate((node: FASTDataGrid) => { - node.focusColumnIndex = 1; - }); - - await expect(cells.nth(1)).toBeFocused(); - - await element.evaluate((node: FASTDataGrid) => { - node.focusColumnIndex = 2; - }); - - await expect(cells.nth(2)).toBeFocused(); - - await element.evaluate((node: FASTDataGrid) => { - node.focusColumnIndex = 0; - }); - - await expect(cells.nth(0)).toBeFocused(); - }); - - test("should scroll into view on focus", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - - 1 - - - 2 - - - 3 - - - 3 - - - `; - }); - - const cells = element.locator("fast-data-grid-cell"); - await expect(cells).toHaveCount(4); - await expect(element).toHaveJSProperty("scrollTop", 0); - await cells.nth(0).focus(); - await expect(element).toHaveJSProperty("scrollTop", 0); - await cells.nth(1).focus(); - await expect(element).toHaveJSProperty("scrollTop", 100); - await cells.nth(2).focus(); - await expect(element).toHaveJSProperty("scrollTop", 200); - }); - - test("should not apply initial selection in default 'none' selection mode", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - - 1 - - - 2 - - - 2 - - - `; - }); - - await expect(element).toHaveJSProperty("selectedRowIndexes", []); - }); - - test("should apply initial selection in 'single-row' selection mode", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - - 1 - - - 2 - - - 2 - - - `; - }); - - await expect(element).toHaveJSProperty("selectedRowIndexes", [0]); - }); - - test("should apply initial selection in 'multi-row' selection mode", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - - 1 - - - 2 - - - 2 - - - `; - }); - - await expect(element).toHaveJSProperty("selectedRowIndexes", [0, 1]); - }); - - test("should apply user set selection in 'single-row' selection mode", async () => { - const selectedRows = element.locator(selectedRowQueryString); - - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - - 1 - - - 2 - - - 2 - - - `; - }); - - await expect(element).toHaveJSProperty("selectedRowIndexes", [0]); - await expect(selectedRows).toHaveCount(1); - - await element.evaluate((node: FASTDataGrid) => { - node.selectedRowIndexes = []; - }); - - await expect(selectedRows).toHaveCount(0); - - await element.evaluate((node: FASTDataGrid) => { - node.selectedRowIndexes = [2]; - }); - - await expect(selectedRows).toHaveCount(1); - }); - - test("should apply user set selection in 'multi-row' selection mode", async () => { - const selectedRows = element.locator(selectedRowQueryString); - - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - - 1 - - - 2 - - - 2 - - - `; - }); - - await expect(element).toHaveJSProperty("selectedRowIndexes", [0]); - await expect(selectedRows).toHaveCount(1); - - await element.evaluate((node: FASTDataGrid) => { - node.selectedRowIndexes = []; - }); - - await expect(selectedRows).toHaveCount(0); - - await element.evaluate((node: FASTDataGrid) => { - node.selectedRowIndexes = [0, 1, 2]; - }); - - await expect(selectedRows).toHaveCount(3); - }); - - test("should not allow selection of header row by default", async () => { - const selectedRows = element.locator(selectedRowQueryString); - - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - - 1 - - - 2 - - - 2 - - - `; - }); - - await expect(element).toHaveJSProperty("selectedRowIndexes", []); - await expect(selectedRows).toHaveCount(0); - }); - - test("should select and deselect rows with space bar + shift keys", async () => { - const rows = element.locator(rowQueryString); - const selectedRows = element.locator(selectedRowQueryString); - const firstCell = rows.nth(0).locator("fast-data-grid-cell").nth(0); - const lastCell = rows.nth(2).locator("fast-data-grid-cell").nth(2); - - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await element.evaluate((node: FASTDataGrid) => { - node.rowsData = [ - { id: "1", name: "item 1", shape: "circle" }, - { id: "2", name: "item 2", shape: "square" }, - { id: "3", name: "item 3", shape: "triangle" }, - ]; - }); - - await firstCell.focus(); - await expect(selectedRows).toHaveCount(0); - await page.keyboard.press("Shift+Space"); - await expect(selectedRows).toHaveCount(1); - await expect(element).toHaveJSProperty("selectedRowIndexes", [0]); - expect; - await page.keyboard.press("Shift+Space"); - await expect(selectedRows).toHaveCount(0); - await lastCell.focus(); - await page.keyboard.press("Shift+Space"); - await expect(selectedRows).toHaveCount(1); - await expect(element).toHaveJSProperty("selectedRowIndexes", [2]); - }); - - test("should select and deselect rows with a click", async () => { - const rows = element.locator(rowQueryString); - const selectedRows = element.locator(selectedRowQueryString); - const firstCell = rows.nth(0).locator("fast-data-grid-cell").nth(0); - const lastCell = rows.nth(2).locator("fast-data-grid-cell").nth(2); - - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await element.evaluate((node: FASTDataGrid) => { - node.rowsData = [ - { id: "1", name: "item 1", shape: "circle" }, - { id: "2", name: "item 2", shape: "square" }, - { id: "3", name: "item 3", shape: "triangle" }, - ]; - }); - - await expect(selectedRows).toHaveCount(0); - await firstCell.click(); - await expect(selectedRows).toHaveCount(1); - await expect(element).toHaveJSProperty("selectedRowIndexes", [0]); - await firstCell.click(); - await expect(selectedRows).toHaveCount(0); - await expect(element).toHaveJSProperty("selectedRowIndexes", []); - await lastCell.click(); - await expect(selectedRows).toHaveCount(1); - await expect(element).toHaveJSProperty("selectedRowIndexes", [2]); - }); - - test("should select/deselect all in row multi-select with a ctrl + a", async () => { - const selectedRows = element.locator(selectedRowQueryString); - const rows = element.locator(rowQueryString); - const firstCell = rows.nth(0).locator("fast-data-grid-cell").nth(0); - await firstCell.focus(); - - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await element.evaluate((node: FASTDataGrid) => { - node.rowsData = [ - { id: "1", name: "item 1", shape: "circle" }, - { id: "2", name: "item 2", shape: "square" }, - { id: "3", name: "item 3", shape: "triangle" }, - ]; - }); - - await firstCell.focus(); - await expect(selectedRows).toHaveCount(0); - await page.keyboard.press("Control+a"); - await expect(selectedRows).toHaveCount(3); - await page.keyboard.press("Control+a"); - await expect(selectedRows).toHaveCount(0); - }); - - test("should select/deselect multiple rows with shift key in multi-select mode", async () => { - const selectedRows = element.locator(selectedRowQueryString); - const rows = element.locator(rowQueryString); - const firstCell = rows.nth(0).locator("fast-data-grid-cell").nth(0); - const lastCell = rows.nth(2).locator("fast-data-grid-cell").nth(2); - await firstCell.focus(); - - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await element.evaluate((node: FASTDataGrid) => { - node.rowsData = [ - { id: "1", name: "item 1", shape: "circle" }, - { id: "2", name: "item 2", shape: "square" }, - { id: "3", name: "item 3", shape: "triangle" }, - ]; - }); - - await firstCell.focus(); - await page.keyboard.press("Shift+Space"); - await expect(selectedRows).toHaveCount(1); - await lastCell.focus(); - await page.keyboard.press("Shift+Space"); - await expect(selectedRows).toHaveCount(2); - }); - - test("should emit an event when row selection changes", async () => { - const rows = element.locator(rowQueryString); - const firstCell = rows.nth(0).locator("fast-data-grid-cell").nth(0); - await firstCell.focus(); - - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await element.evaluate((node: FASTDataGrid) => { - node.rowsData = [ - { id: "1", name: "item 1", shape: "circle" }, - { id: "2", name: "item 2", shape: "square" }, - { id: "3", name: "item 3", shape: "triangle" }, - ]; - }); - - const wasInvoked = await Promise.all([ - element.evaluate(node => - node.addEventListener("selectionchange", () => true) - ), - firstCell.click(), - ]); - - expect(wasInvoked).toBeTruthy; - }); -}); diff --git a/packages/web-components/fast-foundation/src/data-grid/data-grid.spec.md b/packages/web-components/fast-foundation/src/data-grid/data-grid.spec.md deleted file mode 100644 index ba3e174e09e..00000000000 --- a/packages/web-components/fast-foundation/src/data-grid/data-grid.spec.md +++ /dev/null @@ -1,443 +0,0 @@ -# Data Grid - -## Overview - -The `data grid` component enables authors to display an array of data in a tabular layout. The layout can include a "header" region where a title can be displayed for each column. - -![](./images/grid.png) - -`Data grid` actually consists of three components that work together: -- ``: The top level container element -- ``: Displays a single row of data associated with a single record or a header row -- ``: Displays a single cell of data within a row - -### Use Cases -Any time an author wants to display tabular data. - -### Non-goals -- The initial version of the component will not support virtualization or pagination to display large data sets but should be architected to support both in the future. - -### Features -- Generates a data grid layout based on provided data. -- Authors can take advantage of multiple customization points to control the grid display. -- Manages keyboard navigation across the grid. - -### Prior Art/Examples - -[FAST React](https://github.com/microsoft/fast-react/tree/master/packages/react/fast-components-react-msft/src/data-grid) - -[Infragistics](https://www.infragistics.com/products/ignite-ui-web-components/web-components/components/data-grid.html#:~:text=%20Data%20Grid%20Overview%20%201%20Demo.%20,Components%20data%20grid%20to%20the%20above...%20More%20) - -[Smart](https://www.htmlelements.com/docs/grid/) - -[Vaadin](https://vaadin.com/components/vaadin-grid) - -[Open UI](https://open-ui.org/components/table) - - ---- - -## Design - -The Fast **data grid** component is highly customizable. In addition to the base css styling that can be applied to the grid and its sub-components, authors can choose the templates applied to grid and header cells on a per column basis using the properties of the associated `ColumnDefinition`. Additionally, authors can specify the templates to be used for the creation of rows and cells through the item template properties of the grid and row components (`rowItemTemplate` and `cellItemTemplate`). - -The column layout is controlled by the grid's `grid-template-columns` attribute which maps directly to the css `grid-template-columns` attribute applied within each row (rows use a [css grid display](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout) internally). Cells within each row are positioned in the row by setting their `grid-column` css attribute to match the index of their associated `columnDefinition` in the `columnDefinitions` array unless there is a custom `gridColumn` value set in the `columnDefinition`. - -Note: using a custom `gridColumn` property allows authors to place cells anywhere in the row, but the order of elements in the dom is what determines the order elements are selected in keyboard navigation. The order of cells in the DOM is determined by the order of columns in the `columnDefinitions` property. - -### Component Roles - -``: -- Creates grid row elements based on provided data array and adds/removes rows as objects are added/removed from the array. -- Can create a header row if specified. -- Sets the column layout properties (`columnsData` and `grid-template-columns`) of each child row and updates them if they are changed. -- Sets the `row-index` attribute of child rows. -- Manages keyboard navigation between rows. -- Supports rendering of slotted elements and will include any slotted row elements in keyboard navigation and column layout updates. - -``: -- Creates cell elements based on provided column layout properties. -- Creates header cell elements if specified. -- Manages keyboarding within the row. -- Supports rendering of slotted elements and will include any slotted cell elements in keyboard navigation. - -``: -- Can render as either a data cell or a header cell. -- Can render based on a custom template included in the provided `columnDefinition`. -- Manages keyboard interactions to pass focus in/out of custom cells with focusable elements. -- Supports rendering of slotted elements. - -### Grid Navigation - -Users can navigate the component's grid cells using arrow keys as described [here](https://w3c.github.io/aria-practices/#keyboard-interaction-for-data-grids): - -- Right Arrow: Moves focus one cell to the right. If focus is on the right-most cell in the row, focus does not move. - -- Left Arrow: Moves focus one cell to the left. If focus is on the left-most cell in the row, focus does not move. - -- Down Arrow: Moves focus one cell down. If focus is on the bottom cell in the column, focus does not move. - -- Up Arrow: Moves focus one cell Up. If focus is on the top cell in the column, focus does not move. - -- Page Down: Moves focus down an author-determined number of rows, typically scrolling so the bottom row in the currently visible set of rows becomes one of the first visible rows. If focus is in the last row of the grid, focus does not move. - -- Page Up: Moves focus up an author-determined number of rows, typically scrolling so the top row in the currently visible set of rows becomes one of the last visible rows. If focus is in the first row of the grid, focus does not move. - -- Home: Moves focus to the first cell in the row that contains focus. - -- End: Moves focus to the last cell in the row that contains focus. - -- Control + Home: Moves focus to the first cell in the first row. - -- Control + End: Moves focus to the last cell in the last row. - -Further, authors can enable navigation within a cell as described [here](https://w3c.github.io/aria-practices/#gridNav_inside) using the `ColumnDefinition` for that cell's column. - -For example given a nested grid scenario like this: - -``` - - - 1.1 - - - - 1.2.1.1 - 1.2.1.2 - - - 1.2.2.1 - 1.2.2.2 - - - - - -``` - -An author could define a `ColumnDefinition` that specifies that the cells in that column have an internal focus queue and a callback that species where focus goes inside the cell: - -``` -function getFocusTarget(cell: DataGridCell): HTMLElement { - return cell.children[0] as HTMLElement; -} -const nestedColumn: ColumnDefinition = { - ... - cellInternalFocusQueue: true, - cellFocusTargetCallback: getFocusTarget, - ... -}; -``` - -### Grid Selection - -Selection of cells and rows within the grid can be enabled via the grid's `selection-mode` attribute. It is set to "none" by default. - -Keyboard selection model is based on guidance [here](https://w3c.github.io/aria-practices/#keyboard-interaction-for-data-grids) when applicable. - -#### "single-row" selection mode: - -When in single row selection mode a maximum of one row can be selected at a time. All rows are labelled with `aria-selected' with any selected row having a value of "true". - -When the grid's `disable-click-select` attribute is set to "false", the default, any click on a selectable row will select that row, or deselect if already selected. Setting it to `true` will disable automatically selecting a row via a mouse click. -Keyboard: -- Shift + Space: Selects the currently focused row, or deselects it if already selected. - -#### "multi-row" selection mode: -When in single row selection mode a maximum of one row can be selected at a time. All rows are labelled with `aria-selected' with any selected row having a value of "true". - -When the grid's `disable-click-select` attribute is set to "false", which is the default, any click on a selectable row will select that row, or deselect if already selected. It will additionally deselect all other selected rows. Holding the control key while selecting prevents deselection of other rows, and holding shift while selecting selects the row and all the rows between it and the last non-shift selected row, if any. Setting it to `true` will disable automatically selecting a row via a mouse click. - -Keyboard: - -- Space: Selects the currently focused row, or deselects it if already selected. Deselects all other rows - -- Space + Shift: Selects the currently focused row and all rows between it and the last non-shift selected row, if any. - -- Space + Ctrl: Selects/Deselects the currently focused row, does not affect the selection state of other rows. - -- "a" + Ctrl: Selects all rows, or deselects all if all rows already selected. - -### API - -#### The ColumnDefinition interface - -Most **data grid** components use the `ColumnDefinition` interface. A `ColumnDefinition` is an object that describes the properties of a single column in the grid as follows: - -- `columnDataKey`: A string that identifies which data item should be shown in the column. For example, if the source data had a field called "Name" the `columnDataKey` for the column that displays the values for "Name" would be "Name". - -- `title`: The title of the column, if not provided the `columnDataKey` is used instead. - -- `headerCellTemplate`: Custom [template](https://fast.design/docs/fast-element/declaring-templates) to use for header cells of this column. - -- `headerCellInternalFocusQueue`: Indicates whether the header cell has in internal focus queue. This should be set to `true` for header cells that host controls that need to use arrow keys or have multiple focusable internal elements. When the user hits the Enter or F2 key the element specified by the `cellFocusTargetCallback` function will be focused (see keyboard interactions described [here](https://w3c.github.io/aria-practices/#grid)). - -- `headerCellFocusTargetCallback`: Callback function that takes the cell node as a parameter and returns the HTMLElement to focus in a custom cell. This enables authors to direct focus in a custom cell with interactive elements. When `headerCellInternalFocusQueue` is `false` this function is called when the cell is first focused to immediately move focus to a cell element, for example a cell that contains a button could move focus directly to the button when focused. When `cellInternalFocusQueue` is `true` this function is called when the user hits Enter or F2. - -- `cellTemplate`: Custom [template](https://fast.design/docs/fast-element/declaring-templates) to use for data cells of this column. - -- `cellInternalFocusQueue`: Indicates whether the cell has in internal focus queue. This should be set to `true` for cells that host controls that need to use arrow keys or have multiple focusable internal elements. When the user hits the Enter or F2 key the element specified by the `cellFocusTargetCallback` function will be focused (see keyboard interactions descrived [here](https://w3c.github.io/aria-practices/#grid)). - -- `cellFocusTargetCallback`: Callback function that takes the cell node as a parameter and returns the `HTMLElement` to focus in a custom cell. This enables authors to direct focus in a custom cell with interactive elements. When `cellInternalFocusQueue` is `false` this function is called when the cell is first focused to immediately move focus to a cell element, for example a cell that contains a button could move focus directly to the button when focused. When `cellInternalFocusQueue` is `true` this function is called when the user hits Enter or F2. - -Authors can hook up custom events to html elements within cell templates in order to enable user interaction with grid data. - -For example a button handler on a `cellTemplate` could be implemented with a click event that calls back to the author's own function: - -```html - -``` - -- `isRowHeader`: A boolean that indicates whether this column contains row header cells. When true cells in this column that are not in a header row will render with a role of 'rowheader'. - -**Data grid** -- `` - -*Attributes:* -- `generate-header` -Can be either "none", "default" or "sticky" (the `GeneratHeaderOptions` enum). Automatically generate a header element based on provided columns. The default is `true`. Authors who wish to not have a header row or wish to generate their own can set this to `false`. - -- `grid-template-columns` -String that gets applied to the the css gridTemplateColumns attribute of child rows. Corresponds to the [grid-template-columns css attribute](https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-columns) - -- `selection-mode` -Sets how the grid handles selection. -"none" - The default. The grid does not enable selection. -"single-row" - Single row elements are selectable. -"multi-row" - Multiple rows can be selected. - -- `selection-behavior` -Determines what ui interactions can invoke selection. - "programmatic" - Elements can only be selected programmatically. - "keyboard-only" - Programmatic + keyboard. - "auto" - Programmatic + keyboard + pointer events. - -- `initial-row-selection` - The initially selected row elements. The format should be a comma delimited list of row indexes. ie. "1,3,5" - -- `no-tabbing` -Boolean, defaults to false. When true the grid does not add itself to the tab queue. -Useful when a grid is nested within a parent grid cell. - -*properties:* -- `rowsData` -An array of objects that contain the data to be displayed. Each object corresponds to one row. - -- `columnDefinitions` -An array of `ColumnDefinition` objects that define what columns will be displayed in the grid. The order of the columns determines their order in the grid. - -- `rowItemTemplate` -Custom [template](https://fast.design/docs/fast-element/declaring-templates) to use when generating rows by iterating over data. The default template uses `fast-data-grid-row`, this is where authors change that. - -- `cellItemTemplate` -Custom [template](https://fast.design/docs/fast-element/declaring-templates) to use when generating cells by iterating over data. The default template uses `fast-data-grid-cell`, this is where authors can change that. The component applies this to generated rows only. - -- `headerCellItemTemplate` -Custom [template](https://fast.design/docs/fast-element/declaring-templates) to use when generating header cells by iterating over data. The default template uses `fast-data-grid-cell`, this is where authors can change that. The component applies this to generated rows only. - - -- `focusRowIndex` -The index of the row that will receive focus the next time the grid is focused. This value changes as focus moves to different rows within the grid. Changing this value when focus is already within the grid moves focus to the specified row. Note that the header row if there is one is typically at index 0. - -- `focusColumnIndex` -The index of the column that will receive focus the next time the grid is focused. This value changes as focus moves to different rows within the grid. Changing this value when focus is already within the grid moves focus to the specified column. - -*Slots:* -- `default` -Custom generated rows can be placed here - -*Functions:* -- `generateColumns(object): ColumnDefinition` -Static function that creates a basic set of columns from an object representing a row. - -- `selectedRowIndexes` -The currently selected rows. Authors may set or get the current selection via this property. - -*Events* -- `selectionchanged` -Emitted when the selected elements of the grid have been updated. - -*parts:* -- none - -*enums:* -- `GenerateHeaderOptions` - Enumerates available options that control what kind of header the grid should automatically generate: "none, "default" or "sticky". - -**Data grid row** -- `` - -*Attributes:* -- `grid-template-columns` -String that gets applied to the the css `gridTemplateColumns` attribute for the row. This is typically set by the parent grid. - -- `row-index` -The index of the row in the parent grid. This is typically set by the parent grid. - -- `row-type` -The row can either be either "default", "header" or "sticky-header" type according to the `DataGridRowTypes` enum. This determines the type of cells the row generates and what css classes get applied to it. - -- `page-size` -The number of rows to move selection on page up/down keystrokes. -When undefined the grid will use viewport height/the height of the first non-header row. If the grid itself is a scrolling container it will be considered the viewport for this purpose, otherwise the document will be used. - -*properties:* -- `rowData` -The object that contains the data to be displayed in this row. - -- `columnDefinitions` -An array of `ColumnDefinition` objects that define what columns will be displayed in the grid. The order of the columns determines their order in the grid. - -- `cellItemTemplate` -Custom [template](https://fast.design/docs/fast-element/declaring-templates) to use when generating cells by iterating over data. The default template uses `fast-data-grid-cell`, this is where authors can change that. - -- `headerCellItemTemplate` -Custom [template](https://fast.design/docs/fast-element/declaring-templates) to use when generating header cells by iterating over data. The default template uses `fast-data-grid-cell`, this is where authors can change that. - -*Slots:* -- `default` -Default slot for items - -*Events* -- `row-focused` - Event triggered when a row or one of its internal elements is focused. - -- `selectionchanged` -Emitted when the selected elements of the grid have been updated. - -*parts:* -- `cellsSlot` - -*enums:* -- `DataGridRowTypes` - Enumerates available row types: "default, "header" and "sticky-header". - -**Data grid cell** -- `` - -*Attributes:* -- `grid-column` -The grid column this cell is placed in. - -- `cell-type` -A cell can either be either "default", "columnheader" or "rowheader" type. - -*properties:* -- `rowData` -The object that contains the data to be displayed in this row. Cells have access to the data object associated with the entire row because custom cells could render based on multiple values. - -- `columnDefiniton` -The `ColumnDefinition` this associated with this cell. - -- `columnDefiniton` -The `ColumnDefinition` this associated with this cell. - -*Slots:* -- `default` -Default slot for items - -*Events* -- `cell-focused` - Event triggered when a cell or one of its internal elements is focused. - -*parts:* -- `cellSlot` - -*enums:* -- `cellTypes` - Enumerates available cell types: "default and "header". - -## Implementation - -The most basic use case for this component would be to just pass it an array of objects for it to render. - -For example given a grid component: -```html - - ``` - - And some data: - ```js -const baseRows: object[] = [ - { name: "Rob", age: "19" }, - { name: "Bob", age: "20" }, -]; - ``` - - An author could pass the data to the component from a javascript function: - -```js -onLoad(): void { - const defaultGrid: DataGrid | null = document.getElementById( - "defaultGrid" - ) as DataGrid; - if (defaultGrid !== null) { - defaultGrid.rowsData = baseRows; - } -} -``` - -This renders a basic grid with a column titled "name" and another titled "age" in addition to the two rows of data populated with the values. - -![](./images/ex1.png) - -The next level of customization involves changing the default columns that are created by the component when none are provided. - -And author would define the columns by providing an array of `ColumnDefinition` objects to the component's `columnsData` property: - -```js -const baseColumns: ColumnDefinition[] = [ - { columnDataKey: "name", title:"Player name" }, - { columnDataKey: "age", title:"Age"}, -]; - -... - defaultGrid.columnDefinitions = baseColumns; -... -``` - -Applying these columns to our previous example results in our columns having the new titles applied as well as having a fixed width for the "Player age" column. - -![](./images/ex2.png) - -- Programmatically generated rows/cells will will be created using [repeat directives](https://fast.design/docs/fast-element/using-directives#the-repeat-directive). - -- Individual cells can be customized using by passing a custom `ViewTemplate` through the `ColumnDefinition` interface for the column in question. These templates are rendered in the light DOM within the cell so that authors can create custom cells with interactive elements. - -### Accessibility - -The `data grid` should align to the interaction model provided by the [W3C](https://w3c.github.io/aria-practices/#grid). - -### Globalization - -The order of grid columns is inverted in RTL layouts. - -### Security - -NA - -### Performance - -We want to take full advantage of fast-element templating and directives for fast rendering. - -### Dependencies - -None - -### Test Plan -This component should have component testing in the @microsoft/fast-foundation package. - -## Next Steps - -- Virtualization and/or Pagination for large data sets. -- Add support for cell selection. -- Investigate a horizontal grid layout? -- Stable data/element relationships. diff --git a/packages/web-components/fast-foundation/src/data-grid/data-grid.template.ts b/packages/web-components/fast-foundation/src/data-grid/data-grid.template.ts deleted file mode 100644 index f4b8892d94b..00000000000 --- a/packages/web-components/fast-foundation/src/data-grid/data-grid.template.ts +++ /dev/null @@ -1,52 +0,0 @@ -import type { ElementViewTemplate, ViewTemplate } from "@microsoft/fast-element"; -import { children, elements, html } from "@microsoft/fast-element"; -import type { TemplateElementDependency } from "../patterns/index.js"; -import { tagFor } from "../patterns/index.js"; -import type { FASTDataGrid } from "./data-grid.js"; - -/** - * Options for data grid templates. - * @public - */ -export type DataGridOptions = { - dataGridRow: TemplateElementDependency; -}; - -function rowItemTemplate( - options: DataGridOptions -): ViewTemplate { - const rowTag = html.partial(tagFor(options.dataGridRow)); - return html` - <${rowTag} - :rowData="${x => x}" - :cellItemTemplate="${(x, c) => c.parent.cellItemTemplate}" - :headerCellItemTemplate="${(x, c) => c.parent.headerCellItemTemplate}" - > -`; -} - -/** - * Generates a template for the {@link @microsoft/fast-foundation#FASTDataGrid} component using - * the provided prefix. - * - * @public - */ -export function dataGridTemplate( - options: DataGridOptions -): ElementViewTemplate { - const rowTag = tagFor(options.dataGridRow); - return html` - - `; -} diff --git a/packages/web-components/fast-foundation/src/data-grid/data-grid.ts b/packages/web-components/fast-foundation/src/data-grid/data-grid.ts deleted file mode 100644 index feeea96cc9b..00000000000 --- a/packages/web-components/fast-foundation/src/data-grid/data-grid.ts +++ /dev/null @@ -1,1033 +0,0 @@ -import type { SyntheticViewTemplate, ViewTemplate } from "@microsoft/fast-element"; -import { - attr, - FASTElement, - nullableNumberConverter, - observable, - oneWay, - RepeatDirective, - Updates, -} from "@microsoft/fast-element"; -import { ViewBehaviorOrchestrator } from "@microsoft/fast-element/utilities.js"; -import { - eventFocus, - eventFocusOut, - eventKeyDown, - keyArrowDown, - keyArrowUp, - keyEnd, - keyHome, - keyPageDown, - keyPageUp, -} from "@microsoft/fast-web-utilities"; -import { getRootActiveElement } from "../utilities/index.js"; -import type { FASTDataGridCell } from "./data-grid-cell.js"; -import type { FASTDataGridRow } from "./data-grid-row.js"; -import type { DataGridSelectionChangeDetail } from "./data-grid.options.js"; -import { - DataGridRowTypes, - DataGridSelectionBehavior, - DataGridSelectionMode, - GenerateHeaderOptions, -} from "./data-grid.options.js"; - -export { - DataGridRowTypes, - DataGridSelectionBehavior, - DataGridSelectionMode, - GenerateHeaderOptions, -}; - -/** - * Defines a column in the grid - * - * @public - */ -export interface ColumnDefinition { - /** - * Identifies the data item to be displayed in this column - * (i.e. how the data item is labelled in each row) - */ - columnDataKey: string; - - /** - * Sets the css grid-column property on the cell which controls its placement in - * the parent row. If left unset the cells will set this value to match the index - * of their column in the parent collection of ColumnDefinitions. - */ - gridColumn?: string; - - /** - * Column title, if not provided columnDataKey is used as title - */ - title?: string; - - /** - * Header cell template - */ - headerCellTemplate?: ViewTemplate | SyntheticViewTemplate; - - /** - * Whether the header cell has an internal focus queue - */ - headerCellInternalFocusQueue?: boolean; - - /** - * Callback function that returns the element to focus in a custom cell. - * When headerCellInternalFocusQueue is false this function is called when the cell is first focused - * to immediately move focus to a cell element, for example a cell that is a checkbox could move - * focus directly to the checkbox. - * When headerCellInternalFocusQueue is true this function is called when the user hits Enter or F2 - */ - headerCellFocusTargetCallback?: (cell: FASTDataGridCell) => HTMLElement | null; - - /** - * cell template - */ - cellTemplate?: ViewTemplate | SyntheticViewTemplate; - - /** - * Whether the cell has an internal focus queue - */ - cellInternalFocusQueue?: boolean; - - /** - * Callback function that returns the element to focus in a custom cell. - * When cellInternalFocusQueue is false this function is called when the cell is first focused - * to immediately move focus to a cell element, for example a cell that is a checkbox could move - * focus directly to the checkbox. - * When cellInternalFocusQueue is true this function is called when the user hits Enter or F2 - */ - - cellFocusTargetCallback?: (cell: FASTDataGridCell) => HTMLElement | null; - - /** - * Whether this column is the row header - */ - isRowHeader?: boolean; -} - -/** - * A Data Grid Custom HTML Element. - * - * @slot - The default slot for custom row elements - * @public - */ -export class FASTDataGrid extends FASTElement { - /** - * generates a basic column definition by examining sample row data - */ - public static generateColumns(row: object): ColumnDefinition[] { - return Object.getOwnPropertyNames(row).map((property: string, index: number) => { - return { - columnDataKey: property, - gridColumn: `${index}`, - }; - }); - } - - /** - * generates a gridTemplateColumns based on columndefinitions - */ - private static generateTemplateColumns( - columnDefinitions: ColumnDefinition[] - ): string { - let templateColumns: string = ""; - columnDefinitions.forEach((column: ColumnDefinition) => { - templateColumns = `${templateColumns}${ - templateColumns === "" ? "" : " " - }${"1fr"}`; - }); - return templateColumns; - } - - /** - * Default callback to determine if a row is selectable (also depends on selectionMode) - * By default all rows except for header rows are selectable - */ - private static defaultRowSelectableCallback( - rowIndex: number, - grid: FASTDataGrid - ): boolean { - if ( - grid.rowElements.length < rowIndex || - (grid.rowElements[rowIndex] as FASTDataGridRow).rowType !== - DataGridRowTypes.default - ) { - return false; - } - return true; - } - - /** - * When true the component will not add itself to the tab queue. - * Default is false. - * - * @public - * @remarks - * HTML Attribute: no-tabbing - */ - @attr({ attribute: "no-tabbing", mode: "boolean" }) - public noTabbing: boolean = false; - protected noTabbingChanged(): void { - if (this.$fastController.isConnected) { - if (this.noTabbing) { - this.setAttribute("tabIndex", "-1"); - } else { - const activeElement: Element | null = getRootActiveElement(this); - this.setAttribute( - "tabIndex", - this.contains(activeElement) || this === activeElement ? "-1" : "0" - ); - } - } - } - - /** - * Whether the grid should automatically generate a header row and its type - * - * @public - * @remarks - * HTML Attribute: generate-header - */ - @attr({ attribute: "generate-header" }) - public generateHeader: GenerateHeaderOptions = GenerateHeaderOptions.default; - private generateHeaderChanged(): void { - if (this.$fastController.isConnected) { - this.toggleGeneratedHeader(); - } - } - - /** - * String that gets applied to the the css gridTemplateColumns attribute of child rows - * - * @public - * @remarks - * HTML Attribute: grid-template-columns - */ - @attr({ attribute: "grid-template-columns" }) - public gridTemplateColumns: string; - protected gridTemplateColumnsChanged(): void { - if (this.$fastController.isConnected) { - this.updateRowIndexes(); - } - } - - /** - * The number of rows to move selection on page up/down keystrokes. - * When undefined the grid will use viewport height/the height of the first non-header row. - * If the grid itself is a scrolling container it will be considered the viewport for this purpose, - * otherwise the document will be used. - * - * @public - * @remarks - * HTML Attribute: page-size - */ - @attr({ attribute: "page-size", converter: nullableNumberConverter }) - public pageSize: number | undefined; - - /** - * Defines how the grid handles row or cell selection. - * - * @public - * @remarks - * HTML Attribute: selection-mode - */ - @attr({ attribute: "selection-mode" }) - public selectionMode: DataGridSelectionMode = DataGridSelectionMode.none; - private selectionModeChanged( - prev: DataGridSelectionMode, - next: DataGridSelectionMode - ): void { - if (this.$fastController.isConnected) { - if (prev === "single-row" || prev === "multi-row") { - this.removeEventListener( - "rowselectionchange", - this.handleRowSelectedChange - ); - } - if (next === "single-row" || next === "multi-row") { - this.addEventListener("rowselectionchange", this.handleRowSelectedChange); - } - this.deselectAllRows(); - } - } - - /** - * Controls selection behavior - * - * @public - * @remarks - * HTML Attribute: selection-behavior - */ - @attr({ attribute: "selection-behavior" }) - public selectionBehavior: DataGridSelectionBehavior = DataGridSelectionBehavior.auto; - - /** - * The indexes of initially selected grid elements. Includes header rows. - * In the case of row selection the format should be a comma delimited list of row indexes. ie. "1,3,5" - * - * @public - * @remarks - * HTML Attribute: initial-row-selection - */ - @attr({ attribute: "initial-row-selection" }) - public initialRowSelection: string; - - /** - * Callback that determines whether a particular row is selectable or not (depends on selectionMode also) - * By default all rows except header rows are selectable. - * - * @public - */ - @observable - public rowSelectableCallback: (rowIndex: number, grid: FASTDataGrid) => boolean = - FASTDataGrid.defaultRowSelectableCallback; - - /** - * The data being displayed in the grid - * - * @public - */ - @observable - public rowsData: object[] = []; - protected rowsDataChanged(): void { - if (this.columnDefinitions === null && this.rowsData.length > 0) { - this.columnDefinitions = FASTDataGrid.generateColumns(this.rowsData[0]); - } - if (this.$fastController.isConnected) { - this.toggleGeneratedHeader(); - this.deselectAllRows(); - } - } - - /** - * The column definitions of the grid - * - * @public - */ - @observable - public columnDefinitions: ColumnDefinition[] | null = null; - protected columnDefinitionsChanged(): void { - if (!this.columnDefinitions) { - return; - } - this.generatedGridTemplateColumns = FASTDataGrid.generateTemplateColumns( - this.columnDefinitions - ); - if (this.$fastController.isConnected) { - this.columnDefinitionsStale = true; - this.queueRowIndexUpdate(); - } - } - - /** - * The template to use for the programmatic generation of rows - * - * @public - */ - @observable - public rowItemTemplate: ViewTemplate; - - /** - * The template used to render cells in generated rows. - * - * @public - */ - @observable - public cellItemTemplate?: ViewTemplate; - - /** - * The template used to render header cells in generated rows. - * - * @public - */ - @observable - public headerCellItemTemplate?: ViewTemplate; - private headerCellItemTemplateChanged(): void { - if (this.$fastController.isConnected) { - if (this.generatedHeader !== null) { - this.generatedHeader.headerCellItemTemplate = this.headerCellItemTemplate; - } - } - } - - /** - * The index of the row that will receive focus the next time the - * grid is focused. This value changes as focus moves to different - * rows within the grid. Changing this value when focus is already - * within the grid moves focus to the specified row. - * - * @public - */ - @observable - public focusRowIndex: number = 0; - private focusRowIndexChanged(): void { - if (this.$fastController.isConnected) { - this.queueFocusUpdate(); - } - } - - /** - * The index of the column that will receive focus the next time the - * grid is focused. This value changes as focus moves to different rows - * within the grid. Changing this value when focus is already within - * the grid moves focus to the specified column. - * - * @public - */ - @observable - public focusColumnIndex: number = 0; - private focusColumnIndexChanged(): void { - if (this.$fastController.isConnected) { - this.queueFocusUpdate(); - } - } - - /** - * The default row item template. Set by the component templates. - * - * @internal - */ - @observable - public defaultRowItemTemplate: ViewTemplate; - - /** - * Set by the component templates. - * - */ - @observable - public rowElementTag: string; - - /** - * Children that are rows - * - * @internal - */ - @observable - public rowElements: HTMLElement[]; - - /** - * Selected row indexes - * - */ - private _selectedRowIndexes: number[] = []; - - /** - * The selectedRowIndexes property. - * - * @public - */ - public get selectedRowIndexes() { - return this._selectedRowIndexes.slice(); - } - - public set selectedRowIndexes(next: number[]) { - if ( - this.selectionMode !== DataGridSelectionMode.multiRow && - this.selectionMode !== DataGridSelectionMode.singleRow - ) { - return; - } - - // cull unselectable rows - next = next.filter(rowIndex => this.rowSelectableCallback(rowIndex, this)); - - if (this.selectionMode === DataGridSelectionMode.singleRow && next.length > 1) { - this._selectedRowIndexes.splice(0, this.selectedRowIndexes.length, next[0]); - } else { - this._selectedRowIndexes.splice(0, this.selectedRowIndexes.length, ...next); - } - this.selectionUpdated = true; - this.queueRowIndexUpdate(); - } - - private rowsPlaceholder: Node | null = null; - private behaviorOrchestrator: ViewBehaviorOrchestrator | null = null; - - private generatedHeader: FASTDataGridRow | null = null; - - // flag to indicate whether the grid is actively updating focus - // (so we don't self-trigger changes) - private isUpdatingFocus: boolean = false; - private pendingFocusUpdate: boolean = false; - - private observer: MutationObserver; - - private rowindexUpdateQueued: boolean = false; - private columnDefinitionsStale: boolean = true; - - private generatedGridTemplateColumns: string = ""; - - private lastNotShiftSelectedRowIndex = -1; - private preShiftRowSelection: number[] | null = null; - - private selectionUpdated: boolean = false; - - /** - * @internal - */ - public connectedCallback(): void { - super.connectedCallback(); - - if (this.rowItemTemplate === undefined) { - this.rowItemTemplate = this.defaultRowItemTemplate; - } - - if (this.behaviorOrchestrator === null) { - this.behaviorOrchestrator = ViewBehaviorOrchestrator.create(this); - this.$fastController.addBehavior(this.behaviorOrchestrator); - this.behaviorOrchestrator.addBehaviorFactory( - new RepeatDirective( - oneWay(x => x.rowsData), - oneWay(x => x.rowItemTemplate), - { positioning: true } - ), - this.appendChild((this.rowsPlaceholder = document.createComment(""))) - ); - } - - this.toggleGeneratedHeader(); - this.addEventListener("row-focused", this.handleRowFocus); - this.addEventListener(eventFocus, this.handleFocus); - this.addEventListener(eventKeyDown, this.handleKeydown); - this.addEventListener(eventFocusOut, this.handleFocusOut); - - if ( - this.selectionMode === DataGridSelectionMode.singleRow || - this.selectionMode === DataGridSelectionMode.multiRow - ) { - this.addEventListener("rowselectionchange", this.handleRowSelectedChange); - } - - this.observer = new MutationObserver(this.onChildListChange); - // only observe if nodes are added or removed - this.observer.observe(this, { childList: true }); - - if (this.noTabbing) { - this.setAttribute("tabindex", "-1"); - } - - // apply initial selection after the grid is populated - Updates.enqueue(() => { - if ( - this.selectionMode !== DataGridSelectionMode.none && - this.initialRowSelection - ) { - const selectionAsArray: string[] = this.initialRowSelection.split(","); - const initialSelection: number[] = []; - selectionAsArray.forEach((element: string): void => { - initialSelection.push(parseInt(element.trim())); - }); - - this.updateSelectedRows(initialSelection); - } - }); - - this.queueRowIndexUpdate(); - } - - /** - * @internal - */ - public disconnectedCallback(): void { - super.disconnectedCallback(); - - this.removeEventListener("row-focused", this.handleRowFocus); - this.removeEventListener(eventFocus, this.handleFocus); - this.removeEventListener(eventKeyDown, this.handleKeydown); - this.removeEventListener(eventFocusOut, this.handleFocusOut); - - if ( - this.selectionMode === DataGridSelectionMode.singleRow || - this.selectionMode === DataGridSelectionMode.multiRow - ) { - this.removeEventListener("rowselectionchange", this.handleRowSelectedChange); - } - - this.observer.disconnect(); - - if (this.generatedHeader !== null) { - this.removeChild(this.generatedHeader); - this.generatedHeader = null; - } - } - - /** - * @internal - */ - public handleRowFocus(e: Event): void { - this.isUpdatingFocus = true; - const focusRow: FASTDataGridRow = e.target as FASTDataGridRow; - this.focusRowIndex = this.rowElements.indexOf(focusRow); - this.focusColumnIndex = focusRow.focusColumnIndex; - this.setAttribute("tabIndex", "-1"); - this.isUpdatingFocus = false; - } - - /** - * @internal - */ - public handleFocus(e: FocusEvent): void { - this.focusOnCell(this.focusRowIndex, this.focusColumnIndex, "nearest"); - } - - /** - * @internal - */ - public handleFocusOut(e: FocusEvent): void { - if (e.relatedTarget === null || !this.contains(e.relatedTarget as Element)) { - this.setAttribute("tabIndex", this.noTabbing ? "-1" : "0"); - } - } - - /** - * @internal - */ - public handleKeydown(e: KeyboardEvent): void { - if (e.defaultPrevented) { - return; - } - - let newFocusRowIndex: number; - - switch (e.key) { - case keyArrowUp: - e.preventDefault(); - // focus up one row - this.focusOnCell( - this.focusRowIndex - 1, - this.focusColumnIndex, - "nearest" - ); - break; - - case keyArrowDown: - e.preventDefault(); - // focus down one row - this.focusOnCell( - this.focusRowIndex + 1, - this.focusColumnIndex, - "nearest" - ); - break; - - case keyPageUp: - e.preventDefault(); - if (this.rowElements.length === 0) { - this.focusOnCell(0, 0, "nearest"); - break; - } - - newFocusRowIndex = Math.max(0, this.focusRowIndex - this.getPageSize()); - - this.focusOnCell(newFocusRowIndex, this.focusColumnIndex, "start"); - break; - - case keyPageDown: - e.preventDefault(); - if (this.rowElements.length === 0) { - this.focusOnCell(0, 0, "nearest"); - break; - } - newFocusRowIndex = Math.min( - this.rowElements.length - 1, - this.focusRowIndex + this.getPageSize() - ); - this.focusOnCell(newFocusRowIndex, this.focusColumnIndex, "end"); - - break; - - case keyHome: - if (e.ctrlKey) { - e.preventDefault(); - // focus first cell of first row - this.focusOnCell(0, 0, "nearest"); - } - break; - - case keyEnd: - if (e.ctrlKey && this.columnDefinitions !== null) { - e.preventDefault(); - // focus last cell of last row - this.focusOnCell( - this.rowElements.length - 1, - this.columnDefinitions.length - 1, - "nearest" - ); - } - break; - - case "a": - if (!e.ctrlKey) { - return; - } - switch (this.selectionMode) { - case "multi-row": - this.selectAllRows(); - e.preventDefault(); - return; - } - break; - } - } - - public handleRowSelectedChange(e: CustomEvent): void { - if (e.defaultPrevented || this.selectionMode === DataGridSelectionMode.none) { - return; - } - - const path: EventTarget[] = e.composedPath(); - const rowMatch: EventTarget | undefined = path.find((target: EventTarget) => { - return this.rowElements.indexOf(target as HTMLElement) !== -1; - }); - - if (rowMatch) { - e.preventDefault(); - const changedRow: FASTDataGridRow = rowMatch as FASTDataGridRow; - const changeEventDetail: DataGridSelectionChangeDetail = e.detail; - - switch (this.selectionMode) { - case DataGridSelectionMode.singleRow: - this.handleSingleRowSelection(changedRow, changeEventDetail); - break; - - case DataGridSelectionMode.multiRow: - if (changeEventDetail.isKeyboardEvent) { - this.handleMultiRowKeyboardSelection( - changedRow, - changeEventDetail - ); - } else { - this.handleMultiRowPointerSelection( - changedRow, - changeEventDetail - ); - } - break; - } - } - } - - private handleMultiRowPointerSelection( - changedRow: FASTDataGridRow, - changeEventDetail: DataGridSelectionChangeDetail - ): void { - let newSelection: number[] = this.selectedRowIndexes.slice(); - if (changeEventDetail.shiftKey) { - if (this.lastNotShiftSelectedRowIndex === -1) { - this.handleSingleRowSelection(changedRow, changeEventDetail); - } else { - if (this.preShiftRowSelection !== null) { - // undo the last thing - newSelection = this.preShiftRowSelection.slice(); - } else { - this.preShiftRowSelection = newSelection.slice(); - } - - const dirMod: number = - changedRow.rowIndex > this.lastNotShiftSelectedRowIndex ? 1 : -1; - let i: number = this.lastNotShiftSelectedRowIndex + dirMod; - for (i; i !== changedRow.rowIndex + dirMod; i = i + dirMod) { - const selectedRowIndex: number = newSelection.indexOf(i); - if ( - !newSelection.includes(changedRow.rowIndex) && - selectedRowIndex === -1 - ) { - newSelection.push(i); - } - } - } - this.updateSelectedRows(newSelection); - } else if (changeEventDetail.ctrlKey) { - if ( - changeEventDetail.newValue && - !newSelection.includes(changedRow.rowIndex) - ) { - newSelection.push(changedRow.rowIndex); - this.lastNotShiftSelectedRowIndex = changedRow.rowIndex; - } - if ( - !changeEventDetail.newValue && - newSelection.includes(changedRow.rowIndex) - ) { - newSelection.splice(newSelection.indexOf(changedRow.rowIndex), 1); - this.lastNotShiftSelectedRowIndex = -1; - } - this.preShiftRowSelection = null; - this.updateSelectedRows(newSelection); - } else { - this.handleSingleRowSelection(changedRow, changeEventDetail); - this.preShiftRowSelection = null; - } - } - - private handleMultiRowKeyboardSelection( - changedRow: FASTDataGridRow, - changeEventDetail: DataGridSelectionChangeDetail - ): void { - if (changeEventDetail.isKeyboardEvent && !changeEventDetail.shiftKey) { - return; - } - this.preShiftRowSelection = null; - this.lastNotShiftSelectedRowIndex = -1; - const newSelection: number[] = this.selectedRowIndexes.slice(); - if (newSelection.includes(changedRow.rowIndex)) { - newSelection.splice(newSelection.indexOf(changedRow.rowIndex), 1); - } else { - newSelection.push(changedRow.rowIndex); - } - this.updateSelectedRows(newSelection); - } - - private handleSingleRowSelection( - changedRow: FASTDataGridRow, - changeEventDetail: DataGridSelectionChangeDetail - ): void { - if (changeEventDetail.isKeyboardEvent && !changeEventDetail.shiftKey) { - return; - } - if (changeEventDetail.newValue) { - this.updateSelectedRows([changedRow.rowIndex]); - this.lastNotShiftSelectedRowIndex = changedRow.rowIndex; - } else { - this.updateSelectedRows([]); - this.lastNotShiftSelectedRowIndex = -1; - } - } - - private getPageSize(): number { - if (this.pageSize) { - return this.pageSize; - } - - let rowHeight = 50; - this.rowElements.forEach(element => { - if ( - !element.hasAttribute("rowType") || - !element.getAttribute("rowType")?.includes("header") - ) { - rowHeight = element.clientHeight; - } - }); - - let pageSize: number = 1; - - if (rowHeight === 0) { - return pageSize; - } - - if (this.clientHeight < this.scrollHeight) { - pageSize = this.clientHeight / rowHeight; - } else { - pageSize = document.body.clientHeight / rowHeight; - } - - pageSize = Math.max(Math.round(pageSize), 1); - return pageSize; - } - - /** - * Validates that new selected rows are selectable and updates the selectedRowIndexes prop - */ - private updateSelectedRows(newSelection: number[]): void { - this.selectedRowIndexes = newSelection; - } - - private selectAllRows(): void { - if ( - this.selectionMode !== DataGridSelectionMode.multiRow || - this.rowElements.length === 0 - ) { - return; - } - - const unselectableRowIndexes: Array = []; - - for ( - let index: number = 0, maxIndex = this.rowElements.length; - index < maxIndex; - index++ - ) { - if (!this.rowSelectableCallback(index, this)) { - unselectableRowIndexes.push(index); - } - } - - const selectableRowCount: number = Math.max( - this.rowElements.length - unselectableRowIndexes.length, - 0 - ); - - if (this._selectedRowIndexes.length === selectableRowCount) { - // deselect all if all are already selected - this.updateSelectedRows([]); - return; - } - const newSelection: number[] = []; - this.rowElements.forEach(element => { - newSelection.push((element as FASTDataGridRow).rowIndex); - }); - this.lastNotShiftSelectedRowIndex = -1; - this.updateSelectedRows(newSelection); - } - - private deselectAllRows(): void { - this.updateSelectedRows([]); - this.lastNotShiftSelectedRowIndex = -1; - } - - private focusOnCell = ( - rowIndex: number, - columnIndex: number, - alignment: ScrollLogicalPosition - ): void => { - if (this.rowElements.length === 0) { - this.focusRowIndex = 0; - this.focusColumnIndex = 0; - return; - } - const focusRowIndex = Math.max( - 0, - Math.min(this.rowElements.length - 1, rowIndex) - ); - const focusRow: Element = this.rowElements[focusRowIndex]; - - const cells: NodeListOf = focusRow.querySelectorAll( - '[role="cell"], [role="gridcell"], [role="columnheader"], [role="rowheader"]' - ); - - const focusColumnIndex = Math.max(0, Math.min(cells.length - 1, columnIndex)); - - const focusTarget: HTMLElement = cells[focusColumnIndex] as HTMLElement; - if (focusTarget) { - focusTarget.scrollIntoView({ block: alignment }); - focusTarget.focus(); - } - }; - - private queueFocusUpdate(): void { - const activeElement: Element | null = getRootActiveElement(this); - if ( - this.isUpdatingFocus && - (this.contains(activeElement) || this === activeElement) - ) { - return; - } - if (this.pendingFocusUpdate === false) { - this.pendingFocusUpdate = true; - Updates.enqueue(() => this.updateFocus()); - } - } - - private updateFocus(): void { - this.pendingFocusUpdate = false; - this.focusOnCell(this.focusRowIndex, this.focusColumnIndex, "nearest"); - } - - private toggleGeneratedHeader(): void { - if (this.generatedHeader !== null) { - this.removeChild(this.generatedHeader); - this.generatedHeader = null; - } - - if ( - this.generateHeader !== GenerateHeaderOptions.none && - this.columnDefinitions && - this.columnDefinitions.length - ) { - const generatedHeaderElement: HTMLElement = document.createElement( - this.rowElementTag - ); - this.generatedHeader = generatedHeaderElement as unknown as FASTDataGridRow; - this.generatedHeader.columnDefinitions = this.columnDefinitions; - this.generatedHeader.gridTemplateColumns = this.gridTemplateColumns; - this.generatedHeader.rowType = - this.generateHeader === GenerateHeaderOptions.sticky - ? DataGridRowTypes.stickyHeader - : DataGridRowTypes.header; - if (this.firstChild !== null || this.rowsPlaceholder !== null) { - this.insertBefore( - generatedHeaderElement, - this.firstChild !== null ? this.firstChild : this.rowsPlaceholder - ); - } - return; - } - } - - private onChildListChange = ( - mutations: MutationRecord[], - /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ - observer: MutationObserver - ): void => { - this.deselectAllRows(); - if (mutations && mutations.length) { - mutations.forEach((mutation: MutationRecord): void => { - mutation.addedNodes.forEach((newNode: Node): void => { - if ( - newNode.nodeType === 1 && - (newNode as Element).getAttribute("role") === "row" - ) { - (newNode as FASTDataGridRow).columnDefinitions = - this.columnDefinitions; - } - }); - }); - - this.queueRowIndexUpdate(); - } - }; - - private queueRowIndexUpdate = (): void => { - if (!this.rowindexUpdateQueued) { - this.rowindexUpdateQueued = true; - Updates.enqueue(this.updateRowIndexes); - } - }; - - private updateRowIndexes = (): void => { - let newGridTemplateColumns = this.gridTemplateColumns; - - if (newGridTemplateColumns === undefined) { - // try to generate columns based on manual rows - if (this.generatedGridTemplateColumns === "" && this.rowElements.length > 0) { - const firstRow: FASTDataGridRow = this.rowElements[0] as FASTDataGridRow; - this.generatedGridTemplateColumns = new Array( - firstRow.cellElements.length - ) - .fill("1fr") - .join(" "); - } - - newGridTemplateColumns = this.generatedGridTemplateColumns; - } - - this.rowElements.forEach((element: Element, index: number): void => { - const thisRow = element as FASTDataGridRow; - thisRow.rowIndex = index; - thisRow.gridTemplateColumns = newGridTemplateColumns; - thisRow.selectionBehavior = this.selectionBehavior; - if ( - this.selectionMode === DataGridSelectionMode.singleRow || - this.selectionMode === DataGridSelectionMode.multiRow - ) { - thisRow.selected = this._selectedRowIndexes.includes(index) - ? true - : false; - } - - if (this.columnDefinitionsStale) { - thisRow.columnDefinitions = this.columnDefinitions; - } - }); - - this.rowindexUpdateQueued = false; - this.columnDefinitionsStale = false; - - if (this.selectionUpdated) { - this.selectionUpdated = false; - this.$emit("selectionchange"); - } - }; -} diff --git a/packages/web-components/fast-foundation/src/data-grid/images/ex1.png b/packages/web-components/fast-foundation/src/data-grid/images/ex1.png deleted file mode 100644 index 3d967274fb3da4c198fdbd5e9a541988d1125f96..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5419 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 b^azGMDo}pgqQeOeI3exZ@LSb4?H>OV!ICI< diff --git a/packages/web-components/fast-foundation/src/data-grid/images/ex2.png b/packages/web-components/fast-foundation/src/data-grid/images/ex2.png deleted file mode 100644 index 3371a7083f5d573a03696611864575780b2e1f8a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6335 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 U+2}C`|8yYJ)zXKRXgrMkFLvx{T>t<8 diff --git a/packages/web-components/fast-foundation/src/data-grid/images/grid.png b/packages/web-components/fast-foundation/src/data-grid/images/grid.png deleted file mode 100644 index d8815b17bec400f7c8dad7f743b5fbffc32b03af..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 123529 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 - - ${x => x.storyContent} - -`; - -export default { - title: "Data Grid/Data Grid Cell", - argTypes: { - cellType: { control: "select", options: Object.values(DataGridCellTypes) }, - columnDefinition: { control: "object" }, - gridColumn: { control: "text" }, - rowData: { control: "object" }, - storyContent: { table: { disable: true } }, - }, -} as Meta; - -export const DataGridCell: Story = renderComponent(storyTemplate).bind( - {} -); -DataGridCell.args = { - columnDefinition: { columnDataKey: "item1" }, - rowData: { - item1: "data grid cell value 1", - item2: "data grid cell value 2", - item3: "data grid cell value 3", - item4: "data grid cell value 4", - }, -}; diff --git a/packages/web-components/fast-foundation/src/data-grid/stories/data-grid-row.register.ts b/packages/web-components/fast-foundation/src/data-grid/stories/data-grid-row.register.ts deleted file mode 100644 index f200d0443a0..00000000000 --- a/packages/web-components/fast-foundation/src/data-grid/stories/data-grid-row.register.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { css } from "@microsoft/fast-element"; -import { FASTDataGridRow } from "../data-grid-row.js"; -import { dataGridRowTemplate } from "../data-grid-row.template.js"; - -const styles = css` - :host { - display: grid; - padding: 1px 0; - box-sizing: border-box; - width: 100%; - border-bottom: calc(var(--stroke-width) * 1px) solid - var(--neutral-stroke-divider-rest); - } - :host([row-type="sticky-header"]) { - background: var(--neutral-fill-rest); - position: sticky; - top: 0; - } - - :host([aria-selected="true"]) { - background: var(--accent-fill-rest); - color: var(--foreground-on-accent-active); - } -`; - -FASTDataGridRow.define({ - name: "fast-data-grid-row", - template: dataGridRowTemplate({ - dataGridCell: "fast-data-grid-cell", - }), - styles, -}); diff --git a/packages/web-components/fast-foundation/src/data-grid/stories/data-grid-row.stories.ts b/packages/web-components/fast-foundation/src/data-grid/stories/data-grid-row.stories.ts deleted file mode 100644 index de2e7e19de6..00000000000 --- a/packages/web-components/fast-foundation/src/data-grid/stories/data-grid-row.stories.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { html } from "@microsoft/fast-element"; -import type { Meta, Story, StoryArgs } from "../../__test__/helpers.js"; -import { renderComponent } from "../../__test__/helpers.js"; -import type { FASTDataGridRow } from "../data-grid-row.js"; -import { DataGridRowTypes } from "../data-grid.options.js"; - -const storyTemplate = html>` - - ${x => x.storyContent} - -`; - -export default { - title: "Data Grid/Data Grid Row", - args: { - columnDefinitions: [{ columnDataKey: "name" }, { columnDataKey: "value1" }], - rowData: { name: "row 1", value1: "Value 1" }, - }, - argTypes: { - columnDefinitions: { control: "object" }, - gridTemplateColumns: { control: "text" }, - rowType: { control: "select", options: Object.values(DataGridRowTypes) }, - storyContent: { table: { disable: true } }, - }, -} as Meta; - -export const DataGridRow: Story = renderComponent(storyTemplate).bind( - {} -); diff --git a/packages/web-components/fast-foundation/src/data-grid/stories/data-grid.register.ts b/packages/web-components/fast-foundation/src/data-grid/stories/data-grid.register.ts deleted file mode 100644 index ceb48e71e42..00000000000 --- a/packages/web-components/fast-foundation/src/data-grid/stories/data-grid.register.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { css } from "@microsoft/fast-element"; -import { FASTDataGrid } from "../data-grid.js"; -import { dataGridTemplate } from "../data-grid.template.js"; -import { registerComplexCell } from "./examples/complex-cell.js"; - -const styles = css` - :host { - display: block; - } - - :host([selection-mode="multi-row"]) { - user-select: none; - } -`; - -FASTDataGrid.define({ - name: "fast-data-grid", - template: dataGridTemplate({ - dataGridRow: "fast-data-grid-row", - }), - styles, -}); - -registerComplexCell(); diff --git a/packages/web-components/fast-foundation/src/data-grid/stories/data-grid.stories.ts b/packages/web-components/fast-foundation/src/data-grid/stories/data-grid.stories.ts deleted file mode 100644 index 0740033fcea..00000000000 --- a/packages/web-components/fast-foundation/src/data-grid/stories/data-grid.stories.ts +++ /dev/null @@ -1,160 +0,0 @@ -import { html } from "@microsoft/fast-element"; -import type { Meta, Story, StoryArgs } from "../../__test__/helpers.js"; -import { renderComponent } from "../../__test__/helpers.js"; -import { defaultCellFocusTargetCallback } from "../data-grid-cell.js"; -import type { FASTDataGrid } from "../data-grid.js"; -import { - DataGridSelectionBehavior, - DataGridSelectionMode, - GenerateHeaderOptions, -} from "../data-grid.js"; - -const storyTemplate = html>` - - ${x => x.content} - -`; - -function newDataRow(id: string): object { - return { - rowId: `rowid-${id}`, - item1: `value 1-${id}`, - item2: `value 2-${id}`, - item3: `value 3-${id}`, - item4: `value 4-${id}`, - item5: `value 5-${id}`, - item6: `value 6-${id}`, - }; -} - -function newDataSet(rowCount: number): any[] { - return Array.from({ length: rowCount }, (v, i) => newDataRow(`${i + 1}`)); -} - -export default { - title: "Data Grid", - args: { - rowsData: newDataSet(20), - }, - argTypes: { - style: { - control: "text", - }, - content: { table: { disable: true } }, - noTabbing: { - control: "boolean", - }, - generateHeader: { - options: Object.values(GenerateHeaderOptions), - control: "select", - }, - pageSize: { - control: "number", - }, - gridTemplateColumns: { - control: "text", - }, - columnDefinitions: { - control: { type: "object" }, - }, - storyContent: { - table: { disable: true }, - }, - selectionMode: { - options: Object.values(DataGridSelectionMode), - control: "select", - }, - selectionBehavior: { - options: Object.values(DataGridSelectionBehavior), - control: "select", - }, - disableClickSelect: { - control: "boolean", - }, - initialRowSelection: { - control: "text", - }, - }, -} as Meta; - -export const DataGrid: Story = renderComponent(storyTemplate).bind({}); - -export const DataGridFixedHeight: Story = renderComponent( - storyTemplate -).bind({}); -DataGridFixedHeight.args = { - style: "height: 200px; overflow-y: scroll;", -}; - -export const DataGridColumnDefinitions: Story = renderComponent( - storyTemplate -).bind({}); -DataGridColumnDefinitions.args = { - style: "height: 200px; overflow-y: scroll;", - columnDefinitions: [ - { columnDataKey: "rowId" }, - { columnDataKey: "item1" }, - { columnDataKey: "item2" }, - ], -}; - -const editCellTemplate = html` - -`; - -const checkboxCellTemplate = html` - -`; - -const complexCellTemplate = html` - -`; - -export const DataGridEditBoxes: Story = renderComponent(storyTemplate).bind( - {} -); -DataGridEditBoxes.args = { - columnDefinitions: [ - { columnDataKey: "rowId" }, - { - columnDataKey: "item1", - cellTemplate: checkboxCellTemplate, - cellFocusTargetCallback: defaultCellFocusTargetCallback, - }, - { - columnDataKey: "item2", - cellInternalFocusQueue: true, - cellTemplate: editCellTemplate, - cellFocusTargetCallback: defaultCellFocusTargetCallback, - }, - { - columnDataKey: "item3", - cellInternalFocusQueue: true, - cellTemplate: complexCellTemplate, - cellFocusTargetCallback: defaultCellFocusTargetCallback, - }, - ], -}; diff --git a/packages/web-components/fast-foundation/src/data-grid/stories/examples/complex-cell.ts b/packages/web-components/fast-foundation/src/data-grid/stories/examples/complex-cell.ts deleted file mode 100644 index bfe7216d2a7..00000000000 --- a/packages/web-components/fast-foundation/src/data-grid/stories/examples/complex-cell.ts +++ /dev/null @@ -1,67 +0,0 @@ -import type { ElementViewTemplate } from "@microsoft/fast-element"; -import { css, FASTElement, html, ref } from "@microsoft/fast-element"; -import { eventFocus, keyArrowLeft, keyArrowRight } from "@microsoft/fast-web-utilities"; - -export function registerComplexCell() { - ComplexCell.define({ - name: "complex-cell", - template: complexCellTemplate(), - styles: complexCellStyles, - }); -} - -export class ComplexCell extends FASTElement { - public buttonA: HTMLButtonElement; - public buttonB: HTMLButtonElement; - - public connectedCallback(): void { - super.connectedCallback(); - this.addEventListener(eventFocus, this.handleFocus); - } - - public disconnectedCallback(): void { - super.disconnectedCallback(); - } - - public handleFocus = (e: FocusEvent): void => { - this.buttonA.focus(); - }; - - public handleKeyDown = (e: KeyboardEvent): boolean => { - if (e.key !== keyArrowLeft && e.key !== keyArrowRight) { - return true; - } - if (e.target === this.buttonA) { - this.buttonB.focus(); - } else { - this.buttonA.focus(); - } - return false; - }; -} - -export function complexCellTemplate(): ElementViewTemplate { - return html` - - `; -} - -export const complexCellStyles = css` - :host { - } -`; diff --git a/packages/web-components/fast-foundation/src/design-token/core/design-token-node.pw.spec.ts b/packages/web-components/fast-foundation/src/design-token/core/design-token-node.pw.spec.ts deleted file mode 100644 index 346535dd740..00000000000 --- a/packages/web-components/fast-foundation/src/design-token/core/design-token-node.pw.spec.ts +++ /dev/null @@ -1,1246 +0,0 @@ -import "./test/fast-element-dom-shim.js"; -import type { Subscriber } from "@microsoft/fast-element"; -import { Observable } from "@microsoft/fast-element"; -import { reactive } from "@microsoft/fast-element/state.js"; -import { test } from "@playwright/test"; -import { expect } from "expect"; -import jest from "jest-mock"; -import type { DesignTokenResolver } from "./design-token-node.js"; -import { - DesignTokenChangeRecordImpl as DesignTokenChangeRecord, - DesignTokenMutationType, - DesignTokenNode, -} from "./design-token-node.js"; -import type { DesignToken as IDesignToken } from "./design-token.js"; - -function createChangeHandler() { - /* eslint-disable-next-line */ - const handleChange = jest.fn(() => {}); - const subscriber: Subscriber = { handleChange }; - return { handleChange, subscriber }; -} - -function createNode(parent?: DesignTokenNode) { - const node = new DesignTokenNode(); - - if (parent) { - parent.appendChild(node); - } - - return node; -} - -class DesignToken implements IDesignToken { - $value: T | undefined = undefined; -} - -test.describe("DesignTokenNode", () => { - test.describe("appending a child", () => { - test("should assign the `parent` property of the child to the caller", () => { - const parent = new DesignTokenNode(); - const child = new DesignTokenNode(); - - expect(child.parent).toBe(null); - parent.appendChild(child); - expect(child.parent).toEqual(parent); - }); - - test("should add the child to the `children` property of the caller", () => { - const parent = new DesignTokenNode(); - const child = new DesignTokenNode(); - - expect(parent.children.includes(child)).toBe(false); - parent.appendChild(child); - expect(parent.children.includes(child)).toBe(true); - }); - - test("should re-parent the child if the child is already a child of another node", () => { - const parent = new DesignTokenNode(); - const child = new DesignTokenNode(); - const newParent = new DesignTokenNode(); - - parent.appendChild(child); - newParent.appendChild(child); - - expect(child.parent).toEqual(newParent); - expect(parent.children.includes(child)).toBe(false); - expect(newParent.children.includes(child)).toBe(true); - }); - }); - test.describe("removing a child", () => { - test("should assign the `parent` property of the child to null if the child is a child of the parent", () => { - const parent = new DesignTokenNode(); - const child = new DesignTokenNode(); - - parent.appendChild(child); - expect(child.parent).toEqual(parent); - parent.removeChild(child); - expect(child.parent).toBe(null); - }); - test("should remove the child from the `children` set if the item is a child of the parent", () => { - const parent = new DesignTokenNode(); - const child = new DesignTokenNode(); - - parent.appendChild(child); - expect(parent.children.includes(child)).toBe(true); - parent.removeChild(child); - expect(child.parent).toBe(null); - }); - test("should no-op when called with an item that is not a child of the parent", () => { - const parent = new DesignTokenNode(); - const child = new DesignTokenNode(); - const tangent = new DesignTokenNode(); - - parent.appendChild(child); - expect(parent.children.includes(child)).toBe(true); - expect(child.parent).toEqual(parent); - - tangent.removeChild(child); - expect(parent.children.includes(child)).toBe(true); - expect(child.parent).toEqual(parent); - }); - }); - test.describe("setting a token to a static value", () => { - test("should support getting and setting falsey values", () => { - const target = new DesignTokenNode(); - [false, null, 0, "", NaN].forEach(value => { - const token = new DesignToken(); - target.setTokenValue(token, value); - - if (typeof value === "number" && isNaN(value)) { - expect(isNaN(target.getTokenValue(token) as number)).toEqual(true); - } else { - expect(target.getTokenValue(token)).toEqual(value); - } - }); - }); - - test("should return the value set for an ancestor if a value has not been set for the target", () => { - const ancestor = new DesignTokenNode(); - const target = new DesignTokenNode(); - ancestor.appendChild(target); - const token = new DesignToken(); - ancestor.setTokenValue(token, 12); - - expect(target.getTokenValue(token)).toEqual(12); - }); - - test("sound return the nearest ancestor's value after an intermediary value is set where no value was set prior", () => { - const grandparent = new DesignTokenNode(); - const parent = new DesignTokenNode(); - const target = new DesignTokenNode(); - - grandparent.appendChild(parent); - parent.appendChild(target); - - const token = new DesignToken(); - - grandparent.setTokenValue(token, 12); - - expect(target.getTokenValue(token)).toEqual(12); - - parent.setTokenValue(token, 14); - - expect(target.getTokenValue(token)).toEqual(14); - }); - - test("should return the new ancestor's value after being re-parented", () => { - const parentA = new DesignTokenNode(); - const parentB = new DesignTokenNode(); - const target = new DesignTokenNode(); - parentA.appendChild(target); - - const token = new DesignToken(); - - parentA.setTokenValue(token, 12); - parentB.setTokenValue(token, 14); - - expect(target.getTokenValue(token)).toEqual(12); - parentB.appendChild(target); - - expect(target.getTokenValue(token)).toEqual(14); - }); - - test("should not throw when setting a token value from within a change handler", () => { - const node = new DesignTokenNode(); - const tokenA = { $value: undefined }; - const tokenB = { $value: undefined }; - - node.setTokenValue(tokenA, 12); - Observable.getNotifier(tokenA).subscribe({ - handleChange(source, args) { - node.setTokenValue(tokenB, 14); - }, - }); - - expect(() => { - node.setTokenValue(tokenA, 13); - }).not.toThrow(); - }); - }); - test.describe("setting a token to a derived value", () => { - test("should support getting and setting falsey values", () => { - const target = new DesignTokenNode(); - [false, null, 0, "", NaN].forEach(value => { - const token = new DesignToken(); - target.setTokenValue(token, () => value as any); - - if (typeof value === "number" && isNaN(value)) { - expect(isNaN(target.getTokenValue(token) as number)).toEqual(true); - } else { - expect(target.getTokenValue(token)).toEqual(value); - } - }); - }); - - test("should get the return value of a derived value", () => { - const target = new DesignTokenNode(); - const token = new DesignToken(); - target.setTokenValue(token, () => 12); - - expect(target.getTokenValue(token)).toEqual(12); - }); - test("should get an updated value when other design tokens used in a derived property are changed", () => { - const target = new DesignTokenNode(); - const tokenA = new DesignToken(); - const tokenB = new DesignToken(); - - target.setTokenValue(tokenA, 6); - target.setTokenValue(tokenB, resolve => resolve(tokenA) * 2); - - expect(target.getTokenValue(tokenB)).toEqual(12); - - target.setTokenValue(tokenA, 7); - - expect(target.getTokenValue(tokenB)).toEqual(14); - }); - test("should use the closest value of a dependent token when getting a token for a target", () => { - const ancestor = new DesignTokenNode(); - const parent = new DesignTokenNode(); - const target = new DesignTokenNode(); - - ancestor.appendChild(parent); - parent.appendChild(target); - const tokenA = new DesignToken(); - const tokenB = new DesignToken(); - - ancestor.setTokenValue(tokenA, 7); - parent.setTokenValue(tokenA, 6); - ancestor.setTokenValue(tokenB, resolve => resolve(tokenA) * 2); - - expect(target.getTokenValue(tokenB)).toEqual(12); - }); - - test("should update value of a dependent token when getting a token for a target", () => { - const ancestor = new DesignTokenNode(); - const parent = new DesignTokenNode(); - const target = new DesignTokenNode(); - ancestor.appendChild(parent); - parent.appendChild(target); - const tokenA = new DesignToken(); - const tokenB = new DesignToken(); - - ancestor.setTokenValue(tokenA, 7); - parent.setTokenValue(tokenA, 6); - ancestor.setTokenValue(tokenB, resolve => resolve(tokenA) * 2); - - expect(target.getTokenValue(tokenB)).toEqual(12); - - parent.setTokenValue(tokenA, 7); - - expect(target.getTokenValue(tokenB)).toEqual(14); - }); - - test("should get an updated value when a used design token is set for a node closer to the target", () => { - const ancestor = new DesignTokenNode(); - const parent = new DesignTokenNode(); - const target = new DesignTokenNode(); - ancestor.appendChild(parent); - parent.appendChild(target); - - const tokenA = new DesignToken(); - const tokenB = new DesignToken(); - - ancestor.setTokenValue(tokenA, 6); - ancestor.setTokenValue(tokenB, resolve => resolve(tokenA) * 2); - - expect(target.getTokenValue(tokenB)).toEqual(12); - - target.setTokenValue(tokenA, 7); - - expect(target.getTokenValue(tokenB)).toEqual(14); - }); - test("should resolve a value for the token being assigned from the parent node", () => { - const token = new DesignToken(); - const parent = createNode(); - const child = createNode(parent); - - parent.setTokenValue(token, 12); - child.setTokenValue(token, resolve => { - return resolve(token) * 2; - }); - - expect(child.getTokenValue(token)).toEqual(24); - }); - test("should error if attempting to resolve the token being assigned and there is no parent node", () => { - const token = new DesignToken(); - const target = new DesignTokenNode(); - - expect(() => { - target.setTokenValue(token, resolve => { - return resolve(token) * 2; - }); - }).toThrow(); - }); - test("should error if attempting to resolve the token being assigned and the token is not assigned for any ancestor", () => { - const token = new DesignToken(); - const ancestor = createNode(); - const parent = createNode(ancestor); - const descendent = createNode(parent); - - expect(() => { - descendent.setTokenValue(token, resolve => { - return resolve(token) * 2; - }); - }).toThrow(); - }); - - test("should include the token name in the error message, if it exists, when a token is unable to be resolved", () => { - const token = { $value: undefined, name: "error-token" }; - expect(() => new DesignTokenNode().getTokenValue(token)).toThrow( - "No value set for token 'error-token' in node tree." - ); - }); - - test("should not throw when setting a token derived value from within a change handler", () => { - const node = new DesignTokenNode(); - const tokenA = { $value: undefined }; - const tokenB = { $value: undefined }; - - node.setTokenValue(tokenA, 12); - Observable.getNotifier(tokenA).subscribe({ - handleChange(source, args) { - node.setTokenValue(tokenB, () => 12); - }, - }); - - expect(() => { - node.setTokenValue(tokenA, 13); - }).not.toThrow(); - }); - }); - - test.describe("getting a token value", () => { - test("should throw if no token value has been set for the token in a node tree", () => { - const token = new DesignToken(); - const node = new DesignTokenNode(); - - expect(() => node.getTokenValue(token)).toThrow; - }); - test("should return the assigned value when a node is assigned a static value", () => { - const token = new DesignToken(); - const node = new DesignTokenNode(); - node.setTokenValue(token, 12); - - expect(node.getTokenValue(token)).toEqual(12); - }); - test("should return the resolved value when a node is assigned a derived value", () => { - const token = new DesignToken(); - const node = new DesignTokenNode(); - node.setTokenValue(token, () => 12); - - expect(node.getTokenValue(token)).toEqual(12); - }); - /* eslint-disable-next-line max-len */ - test("should resolve a static value from an ancestor node assigned a static value when the descendent node does not have the token assigned a value", () => { - const token = new DesignToken(); - const ancestor = createNode(); - const parent = createNode(ancestor); - const descendent = createNode(parent); - - ancestor.setTokenValue(token, 12); - - expect(descendent.getTokenValue(token)).toEqual(12); - }); - /* eslint-disable-next-line max-len */ - test("should resolve a static value from an ancestor node assigned a derived value when the descendent node does not have the token assigned a value", () => { - const token = new DesignToken(); - const ancestor = createNode(); - const parent = createNode(ancestor); - const descendent = createNode(parent); - - ancestor.setTokenValue(token, () => 12); - - expect(descendent.getTokenValue(token)).toEqual(12); - }); - }); - - test.describe("getAssignedTokensForNode", () => { - test("should return an empty set if no tokens are set for a node", () => { - const node = new DesignTokenNode(); - - expect(DesignTokenNode.getAssignedTokensForNode(node).length).toEqual(0); - }); - test("should return an array that contains the tokens set for the node", () => { - const node = new DesignTokenNode(); - const token = new DesignToken(); - node.setTokenValue(token, 12); - const assigned = DesignTokenNode.getAssignedTokensForNode(node); - - expect(assigned.includes(token)).toBe(true); - expect(assigned.length).toEqual(1); - }); - test("should return an array that does not contain tokens set for ancestor nodes", () => { - const parent = new DesignTokenNode(); - const node = new DesignTokenNode(); - parent.appendChild(node); - const token = new DesignToken(); - parent.setTokenValue(token, 12); - const assigned = DesignTokenNode.getAssignedTokensForNode(node); - - expect(assigned.includes(token)).toBe(false); - expect(assigned.length).toEqual(0); - }); - }); - test.describe("getAssignedTokensForNodeTree", () => { - test("should return an empty set if no tokens are set for a node or it's ancestors", () => { - const node = new DesignTokenNode(); - const parent = new DesignTokenNode(); - parent.appendChild(node); - - expect(DesignTokenNode.composeAssignedTokensForNode(node).length).toEqual(0); - }); - test("should return an array that contains the tokens set for the node", () => { - const node = new DesignTokenNode(); - const parent = new DesignTokenNode(); - parent.appendChild(node); - const token = new DesignToken(); - node.setTokenValue(token, 12); - const assigned = DesignTokenNode.composeAssignedTokensForNode(node); - - expect(assigned.includes(token)).toBe(true); - expect(assigned.length).toEqual(1); - }); - test("should return an array that does contains tokens set for ancestor nodes", () => { - const parent = new DesignTokenNode(); - const node = new DesignTokenNode(); - parent.appendChild(node); - const token = new DesignToken(); - parent.setTokenValue(token, 12); - const assigned = DesignTokenNode.composeAssignedTokensForNode(node); - - expect(assigned.includes(token)).toBe(true); - expect(assigned.length).toEqual(1); - }); - }); - - test.describe("should notify", () => { - test("the token with the node that has the token assigned a static value", () => { - const token = new DesignToken(); - const node = new DesignTokenNode(); - const { subscriber, handleChange } = createChangeHandler(); - - Observable.getNotifier(token).subscribe(subscriber); - node.setTokenValue(token, 12); - - expect(handleChange).toHaveBeenCalledTimes(1); - expect(handleChange).toHaveBeenCalledWith( - token, - new DesignTokenChangeRecord(node, DesignTokenMutationType.add, token, 12) - ); - expect(node.getTokenValue(token)).toEqual(12); - }); - test("the token for the node assigned a static value when the value assigned is the same as the inherited static value", () => { - const token = new DesignToken(); - const parent = createNode(); - const child = createNode(parent); - const { handleChange, subscriber } = createChangeHandler(); - - parent.setTokenValue(token, 12); - Observable.getNotifier(token).subscribe(subscriber); - - child.setTokenValue(token, 12); - - expect(handleChange).toHaveBeenCalledTimes(1); - expect(handleChange).toHaveBeenCalledWith( - token, - new DesignTokenChangeRecord(child, DesignTokenMutationType.add, token, 12) - ); - }); - test("the token with the node that has the token assigned a derived value", () => { - const token = new DesignToken(); - const node = new DesignTokenNode(); - const { subscriber, handleChange } = createChangeHandler(); - - Observable.getNotifier(token).subscribe(subscriber); - const value = () => 12; - node.setTokenValue(token, value); - - expect(handleChange).toHaveBeenCalledTimes(1); - expect(handleChange).toHaveBeenCalledWith( - token, - new DesignTokenChangeRecord( - node, - DesignTokenMutationType.add, - token, - value - ) - ); - expect(node.getTokenValue(token)).toEqual(12); - }); - test("the token with the node that has the token reassigned a static value from a derived value", () => { - const token = new DesignToken(); - const node = new DesignTokenNode(); - const { subscriber, handleChange } = createChangeHandler(); - - Observable.getNotifier(token).subscribe(subscriber); - const value = () => 12; - node.setTokenValue(token, value); - node.setTokenValue(token, 14); - - expect(handleChange).toHaveBeenCalledTimes(2); - expect(handleChange).toHaveBeenNthCalledWith( - 1, - token, - new DesignTokenChangeRecord( - node, - DesignTokenMutationType.add, - token, - value - ) - ); - expect(handleChange).toHaveBeenNthCalledWith( - 2, - token, - new DesignTokenChangeRecord( - node, - DesignTokenMutationType.change, - token, - 14 - ) - ); - expect(node.getTokenValue(token)).toEqual(14); - }); - test("the token with the node that has the token reassigned a derived value from a static value", () => { - const token = new DesignToken(); - const node = new DesignTokenNode(); - const { subscriber, handleChange } = createChangeHandler(); - - Observable.getNotifier(token).subscribe(subscriber); - node.setTokenValue(token, 12); - const value = () => 14; - node.setTokenValue(token, value); - expect(handleChange).toHaveBeenCalledTimes(2); - expect(handleChange).toHaveBeenNthCalledWith( - 1, - token, - new DesignTokenChangeRecord(node, DesignTokenMutationType.add, token, 12) - ); - expect(handleChange).toHaveBeenNthCalledWith( - 2, - token, - new DesignTokenChangeRecord( - node, - DesignTokenMutationType.change, - token, - value - ) - ); - expect(node.getTokenValue(token)).toEqual(14); - }); - test("the token with the node that has the token assigned a static value which is then deleted", () => { - const token = new DesignToken(); - const node = new DesignTokenNode(); - const { subscriber, handleChange } = createChangeHandler(); - - Observable.getNotifier(token).subscribe(subscriber); - node.setTokenValue(token, 12); - node.deleteTokenValue(token); - - expect(handleChange).toHaveBeenCalledTimes(2); - expect(handleChange).toHaveBeenNthCalledWith( - 1, - token, - new DesignTokenChangeRecord(node, DesignTokenMutationType.add, token, 12) - ); - expect(handleChange).toHaveBeenNthCalledWith( - 2, - token, - new DesignTokenChangeRecord(node, DesignTokenMutationType.delete, token) - ); - expect(() => node.getTokenValue(token)).toThrow(); - }); - test("the token with the node that has the token assigned a derived value which is then deleted", () => { - const token = new DesignToken(); - const node = new DesignTokenNode(); - const { subscriber, handleChange } = createChangeHandler(); - - Observable.getNotifier(token).subscribe(subscriber); - const value = () => 12; - node.setTokenValue(token, value); - node.deleteTokenValue(token); - - expect(handleChange).toHaveBeenCalledTimes(2); - expect(handleChange).toHaveBeenNthCalledWith( - 1, - token, - new DesignTokenChangeRecord( - node, - DesignTokenMutationType.add, - token, - value - ) - ); - expect(handleChange).toHaveBeenNthCalledWith( - 2, - token, - new DesignTokenChangeRecord(node, DesignTokenMutationType.delete, token) - ); - expect(() => node.getTokenValue(token)).toThrow(); - }); - /* eslint-disable-next-line max-len */ - test("the token with the node that has a token assigned a derived value and a dependency of the derived value changes for the node", () => { - const token = new DesignToken(); - const dependency = new DesignToken(); - const node = new DesignTokenNode(); - const { subscriber, handleChange } = createChangeHandler(); - - const value = (resolve: DesignTokenResolver) => resolve(dependency) * 2; - node.setTokenValue(dependency, 6); - node.setTokenValue(token, value); - - Observable.getNotifier(token).subscribe(subscriber); - - expect(node.getTokenValue(token)).toEqual(12); - - node.setTokenValue(dependency, 7); - - expect(handleChange).toHaveBeenCalledTimes(1); - expect(handleChange).toHaveBeenNthCalledWith( - 1, - token, - new DesignTokenChangeRecord( - node, - DesignTokenMutationType.change, - token, - value - ) - ); - expect(node.getTokenValue(token)).toEqual(14); - }); - /* eslint-disable-next-line max-len */ - test("the token with the descendent node that has a token assigned a static value that is a dependency of a value assigned for an ancestor", () => { - const token = new DesignToken(); - const dependency = new DesignToken(); - const ancestor = createNode(); - const parent = createNode(ancestor); - const descendent = createNode(parent); - const { subscriber, handleChange } = createChangeHandler(); - - ancestor.setTokenValue(dependency, 6); - const value = (resolve: DesignTokenResolver) => resolve(dependency) * 2; - ancestor.setTokenValue(token, value); - - Observable.getNotifier(token).subscribe(subscriber); - - expect(descendent.getTokenValue(token)).toEqual(12); - - descendent.setTokenValue(dependency, 7); - - expect(handleChange).toHaveBeenCalledTimes(1); - expect(handleChange).toHaveBeenNthCalledWith( - 1, - token, - new DesignTokenChangeRecord( - descendent, - DesignTokenMutationType.change, - token, - value - ) - ); - expect(ancestor.getTokenValue(token)).toEqual(12); - expect(parent.getTokenValue(token)).toEqual(12); - expect(descendent.getTokenValue(token)).toEqual(14); - }); - /* eslint-disable-next-line max-len */ - test("the token with the descendent node that has a token assigned a derived value that is a dependency of a value assigned for an ancestor", () => { - const token = new DesignToken(); - const dependency = new DesignToken(); - const ancestor = createNode(); - const parent = createNode(ancestor); - const descendent = createNode(parent); - const { subscriber, handleChange } = createChangeHandler(); - - ancestor.setTokenValue(dependency, 6); - const value = (resolve: DesignTokenResolver) => resolve(dependency) * 2; - ancestor.setTokenValue(token, value); - - Observable.getNotifier(token).subscribe(subscriber); - - expect(descendent.getTokenValue(token)).toEqual(12); - - descendent.setTokenValue(dependency, () => 7); - - expect(handleChange).toHaveBeenCalledTimes(1); - expect(handleChange).toHaveBeenNthCalledWith( - 1, - token, - new DesignTokenChangeRecord( - descendent, - DesignTokenMutationType.change, - token, - value - ) - ); - expect(ancestor.getTokenValue(token)).toEqual(12); - expect(parent.getTokenValue(token)).toEqual(12); - expect(descendent.getTokenValue(token)).toEqual(14); - }); - /* eslint-disable-next-line max-len */ - test("the token with the descendent node that has a token reassigned a static value that is a dependency of a value assigned for an ancestor", () => { - const token = new DesignToken(); - const dependency = new DesignToken(); - const ancestor = createNode(); - const parent = createNode(ancestor); - const descendent = createNode(parent); - const { subscriber, handleChange } = createChangeHandler(); - - const value = (resolve: DesignTokenResolver) => resolve(dependency) * 2; - ancestor.setTokenValue(dependency, 6); - ancestor.setTokenValue(token, value); - - expect(descendent.getTokenValue(token)).toEqual(12); - - descendent.setTokenValue(dependency, 7); - Observable.getNotifier(token).subscribe(subscriber); - - descendent.setTokenValue(dependency, 8); - - expect(handleChange).toHaveBeenCalledTimes(1); - expect(handleChange).toHaveBeenNthCalledWith( - 1, - token, - new DesignTokenChangeRecord( - descendent, - DesignTokenMutationType.change, - token, - value - ) - ); - expect(ancestor.getTokenValue(token)).toEqual(12); - expect(parent.getTokenValue(token)).toEqual(12); - expect(descendent.getTokenValue(token)).toEqual(16); - }); - /* eslint-disable-next-line max-len */ - test("the token with the descendent node that has a token reassigned a derived value that is a dependency of a value assigned for an ancestor", () => { - const token = new DesignToken(); - const dependency = new DesignToken(); - const ancestor = createNode(); - const parent = createNode(ancestor); - const descendent = createNode(parent); - const { subscriber, handleChange } = createChangeHandler(); - - ancestor.setTokenValue(dependency, 6); - const value = (resolve: DesignTokenResolver) => resolve(dependency) * 2; - ancestor.setTokenValue(token, value); - - expect(descendent.getTokenValue(token)).toEqual(12); - - descendent.setTokenValue(dependency, () => 7); - Observable.getNotifier(token).subscribe(subscriber); - - descendent.setTokenValue(dependency, () => 8); - - expect(handleChange).toHaveBeenCalledTimes(1); - expect(handleChange).toHaveBeenNthCalledWith( - 1, - token, - new DesignTokenChangeRecord( - descendent, - DesignTokenMutationType.change, - token, - value - ) - ); - expect(ancestor.getTokenValue(token)).toEqual(12); - expect(parent.getTokenValue(token)).toEqual(12); - expect(descendent.getTokenValue(token)).toEqual(16); - }); - /* eslint-disable-next-line max-len */ - test("the token with a descendent node when a ancestor and descendent both have a dependency assigned and the ancestor is reassigned a token to a derived value that resolves the dependency and results in a value change", () => { - const token = new DesignToken(); - const dependency = new DesignToken(); - const ancestor = createNode(); - const parent = createNode(ancestor); - const descendent = createNode(parent); - const { subscriber, handleChange } = createChangeHandler(); - - ancestor.setTokenValue(dependency, 5); - ancestor.setTokenValue(token, 12); - descendent.setTokenValue(dependency, 7); - Observable.getNotifier(token).subscribe(subscriber); - - expect(descendent.getTokenValue(token)).toEqual(12); - - const value = (resolve: DesignTokenResolver) => resolve(dependency) * 2; - ancestor.setTokenValue(token, value); - - expect(handleChange).toHaveBeenCalledTimes(2); - expect(handleChange).toHaveBeenNthCalledWith( - 1, - token, - new DesignTokenChangeRecord( - ancestor, - DesignTokenMutationType.change, - token, - value - ) - ); - expect(handleChange).toHaveBeenNthCalledWith( - 2, - token, - new DesignTokenChangeRecord( - descendent, - DesignTokenMutationType.add, - token, - value - ) - ); - expect(ancestor.getTokenValue(token)).toEqual(10); - expect(parent.getTokenValue(token)).toEqual(10); - expect(descendent.getTokenValue(token)).toEqual(14); - }); - /* eslint-disable-next-line max-len */ - test("the token with the descendent node that has a token assigned a static value deleted that is a dependency of a value assigned for an ancestor", () => { - const token = new DesignToken(); - const dependency = new DesignToken(); - const ancestor = createNode(); - const parent = createNode(ancestor); - const descendent = createNode(parent); - const { subscriber, handleChange } = createChangeHandler(); - - ancestor.setTokenValue(dependency, 6); - const value = (resolve: DesignTokenResolver) => resolve(dependency) * 2; - ancestor.setTokenValue(token, value); - descendent.setTokenValue(dependency, 7); - Observable.getNotifier(token).subscribe(subscriber); - expect(descendent.getTokenValue(token)).toEqual(14); - - descendent.deleteTokenValue(dependency); - - expect(handleChange).toHaveBeenCalledTimes(1); - expect(handleChange).toHaveBeenNthCalledWith( - 1, - token, - new DesignTokenChangeRecord( - descendent, - DesignTokenMutationType.change, - token, - value - ) - ); - expect(ancestor.getTokenValue(token)).toEqual(12); - expect(parent.getTokenValue(token)).toEqual(12); - expect(descendent.getTokenValue(token)).toEqual(12); - }); - /* eslint-disable-next-line max-len */ - test("the token with the descendent node that has a token assigned a derived value deleted that is a dependency of a value assigned for an ancestor", () => { - const token = new DesignToken(); - const dependency = new DesignToken(); - const ancestor = createNode(); - const parent = createNode(ancestor); - const descendent = createNode(parent); - const { subscriber, handleChange } = createChangeHandler(); - - ancestor.setTokenValue(dependency, 6); - const value = (resolve: DesignTokenResolver) => resolve(dependency) * 2; - ancestor.setTokenValue(token, value); - descendent.setTokenValue(dependency, () => 7); - Observable.getNotifier(token).subscribe(subscriber); - expect(descendent.getTokenValue(token)).toEqual(14); - - descendent.deleteTokenValue(dependency); - - expect(handleChange).toHaveBeenCalledTimes(1); - expect(handleChange).toHaveBeenNthCalledWith( - 1, - token, - new DesignTokenChangeRecord( - descendent, - DesignTokenMutationType.change, - token, - value - ) - ); - expect(ancestor.getTokenValue(token)).toEqual(12); - expect(parent.getTokenValue(token)).toEqual(12); - expect(descendent.getTokenValue(token)).toEqual(12); - }); - /* eslint-disable-next-line max-len */ - test("should the token for ancestor, parent, and descendent nodes when parent and descendent are assigned a value that depends on the token and the ancestor's value is changed", () => { - const token = new DesignToken(); - const ancestor = createNode(); - const parent = createNode(ancestor); - const descendent = createNode(parent); - const { subscriber, handleChange } = createChangeHandler(); - - ancestor.setTokenValue(token, 6); - const parentValue = (resolve: DesignTokenResolver) => resolve(token) * 2; - parent.setTokenValue(token, parentValue); - const descendentValue = (resolve: DesignTokenResolver) => resolve(token) * 2; - descendent.setTokenValue(token, descendentValue); - Observable.getNotifier(token).subscribe(subscriber); - - expect(descendent.getTokenValue(token)).toEqual(6 * 2 * 2); - - ancestor.setTokenValue(token, 7); - expect(handleChange).toHaveBeenCalledTimes(3); - expect(handleChange).toHaveBeenNthCalledWith( - 1, - token, - new DesignTokenChangeRecord( - ancestor, - DesignTokenMutationType.change, - token, - 7 - ) - ); - expect(handleChange).toHaveBeenNthCalledWith( - 2, - token, - new DesignTokenChangeRecord( - parent, - DesignTokenMutationType.change, - token, - parentValue - ) - ); - expect(handleChange).toHaveBeenNthCalledWith( - 3, - token, - new DesignTokenChangeRecord( - descendent, - DesignTokenMutationType.change, - token, - descendentValue - ) - ); - expect(ancestor.getTokenValue(token)).toEqual(7); - expect(parent.getTokenValue(token)).toEqual(7 * 2); - expect(descendent.getTokenValue(token)).toEqual(7 * 2 * 2); - }); - /** - * Appending nodes - */ - /* eslint-disable-next-line max-len */ - test("the token with the descendent node that has a dependency assigned when the node is appended to an ancestor with a derived value assigned that depends on the dependency", () => { - const ancestor = createNode(); - const parent = createNode(ancestor); - const descendent = createNode(); - const dependency = new DesignToken(); - const token = new DesignToken(); - const { subscriber, handleChange } = createChangeHandler(); - - ancestor.setTokenValue(dependency, 6); - const value = (resolve: DesignTokenResolver) => resolve(dependency) * 2; - ancestor.setTokenValue(token, value); - descendent.setTokenValue(dependency, 7); - - Observable.getNotifier(token).subscribe(subscriber); - - parent.appendChild(descendent); - - expect(handleChange).toHaveBeenCalledTimes(1); - expect(handleChange).toHaveBeenNthCalledWith( - 1, - token, - new DesignTokenChangeRecord( - descendent, - DesignTokenMutationType.add, - token, - value - ) - ); - expect(descendent.getTokenValue(token)).toEqual(14); - }); - /** - * Removing nodes - */ - /* eslint-disable-next-line max-len */ - test("the token with the descendent node that has a dependency assigned when the node is appended to an ancestor with a derived value assigned that depends on the dependency and is then removed", () => { - const ancestor = createNode(); - const parent = createNode(ancestor); - const descendent = createNode(); - const dependency = new DesignToken(); - const token = new DesignToken(); - const { subscriber, handleChange } = createChangeHandler(); - - ancestor.setTokenValue(dependency, 6); - ancestor.setTokenValue(token, resolve => resolve(dependency) * 2); - descendent.setTokenValue(dependency, 7); - - parent.appendChild(descendent); - Observable.getNotifier(token).subscribe(subscriber); - - parent.removeChild(descendent); - - expect(handleChange).toHaveBeenCalledTimes(1); - expect(handleChange).toHaveBeenNthCalledWith( - 1, - token, - new DesignTokenChangeRecord( - descendent, - DesignTokenMutationType.delete, - token - ) - ); - expect(() => descendent.getTokenValue(token)).toThrow; - expect(2).toEqual(2); - }); - /** - * Moving node - */ - /* eslint-disable-next-line max-len */ - test("the token with the descendent node that has a dependency assigned when the node is re-parented to an ancestor with a different derived value assigned that depends on the dependency", () => { - const ancestorA = createNode(); - const ancestorB = createNode(); - const parentA = createNode(ancestorA); - const parentB = createNode(ancestorB); - const descendent = createNode(parentA); - const dependency = new DesignToken(); - const token = new DesignToken(); - const { subscriber, handleChange } = createChangeHandler(); - - ancestorA.setTokenValue(dependency, 6); - ancestorA.setTokenValue(token, resolve => resolve(dependency) * 2); - ancestorB.setTokenValue(dependency, 7); - const value = (resolve: DesignTokenResolver) => resolve(dependency) * 3; - ancestorB.setTokenValue(token, value); - descendent.setTokenValue(dependency, 7); - - Observable.getNotifier(token).subscribe(subscriber); - - parentB.appendChild(descendent); - - expect(handleChange).toHaveBeenCalledTimes(1); - expect(handleChange).toHaveBeenCalledWith( - token, - new DesignTokenChangeRecord( - descendent, - DesignTokenMutationType.change, - token, - value - ) - ); - expect(descendent.getTokenValue(token)).toEqual(21); - }); - /* eslint-disable-next-line max-len */ - test("should support reparenting a node with a derived token assigned to a tree where the immediate parent doesn't not have the dependency assigned", () => { - const ancestor = new DesignTokenNode(); - const parent = new DesignTokenNode(); - const child = new DesignTokenNode(); - - const tokenA = new DesignToken(); - const tokenB = new DesignToken(); - ancestor.appendChild(child); - - ancestor.setTokenValue(tokenA, 12); - ancestor.setTokenValue(tokenB, 12); - - child.setTokenValue(tokenB, resolve => resolve(tokenA) * 2); - ancestor.appendChild(parent); - parent.appendChild(child); - - expect(child.getTokenValue(tokenB)).toBe(24); - }); - - /** - * Observable values - */ - test("the token with the node assigned a derived value when an observable value used by the value is changed", () => { - const node = createNode(); - const token = new DesignToken(); - const dependencies: { value: number } = reactive({ value: 6 }); - const { subscriber, handleChange } = createChangeHandler(); - - const value = () => dependencies.value * 2; - node.setTokenValue(token, value); - Observable.getNotifier(token).subscribe(subscriber); - - expect(node.getTokenValue(token)).toEqual(12); - - dependencies.value = 7; - - expect(node.getTokenValue(token)).toEqual(14); - expect(handleChange).toHaveBeenCalledTimes(1); - expect(handleChange).toHaveBeenNthCalledWith( - 1, - token, - new DesignTokenChangeRecord( - node, - DesignTokenMutationType.change, - token, - value - ) - ); - }); - /* eslint-disable-next-line max-len */ - test("the token with the ancestor and descendent node when the ancestor is assigned a derived value using an observable and a token, where both nodes contain a value set for the dependency", () => { - const ancestor = createNode(); - const parent = createNode(ancestor); - const descendent = createNode(parent); - const token = new DesignToken(); - const dependency = new DesignToken(); - const observableDependency: { value: number } = reactive({ value: 6 }); - const { subscriber, handleChange } = createChangeHandler(); - - ancestor.setTokenValue(dependency, 4); - const value = (resolve: DesignTokenResolver) => - observableDependency.value * 2 + resolve(dependency); - ancestor.setTokenValue(token, value); - descendent.setTokenValue(dependency, 8); - Observable.getNotifier(token).subscribe(subscriber); - - expect(ancestor.getTokenValue(token)).toEqual(16); - expect(descendent.getTokenValue(token)).toEqual(20); - - observableDependency.value = 7; - - expect(ancestor.getTokenValue(token)).toEqual(18); - expect(descendent.getTokenValue(token)).toEqual(22); - expect(handleChange).toHaveBeenCalledTimes(2); - expect(handleChange).toHaveBeenNthCalledWith( - 1, - token, - new DesignTokenChangeRecord( - ancestor, - DesignTokenMutationType.change, - token, - value - ) - ); - expect(handleChange).toHaveBeenNthCalledWith( - 2, - token, - new DesignTokenChangeRecord( - descendent, - DesignTokenMutationType.change, - token, - value - ) - ); - }); - }); - - test.describe("should not notify", () => { - test("the token when the static value assigned to a node is the same value as was previously assigned", () => { - const token = new DesignToken(); - const node = new DesignTokenNode(); - const { handleChange, subscriber } = createChangeHandler(); - node.setTokenValue(token, 12); - Observable.getNotifier(token).subscribe(subscriber); - - node.setTokenValue(token, 12); - - expect(handleChange).not.toHaveBeenCalled(); - }); - /* eslint-disable-next-line max-len */ - test("the token when the derived value assigned to a node results in the same value as the previously assigned static value", () => { - const token = new DesignToken(); - const node = new DesignTokenNode(); - const { handleChange, subscriber } = createChangeHandler(); - node.setTokenValue(token, 12); - Observable.getNotifier(token).subscribe(subscriber); - - node.setTokenValue(token, () => 12); - - expect(handleChange).not.toHaveBeenCalled(); - }); - /* eslint-disable-next-line max-len */ - test("the token when the derived value assigned to a node results in the same value as the previously assigned derived value", () => { - const token = new DesignToken(); - const node = new DesignTokenNode(); - const { handleChange, subscriber } = createChangeHandler(); - function a() { - return 12; - } - - function b() { - return 12; - } - - node.setTokenValue(token, a); - Observable.getNotifier(token).subscribe(subscriber); - - node.setTokenValue(token, b); - - expect(a).not.toEqual(b); - expect(handleChange).not.toHaveBeenCalled(); - }); - /* eslint-disable-next-line max-len */ - test("the token when a dependency of a derived token value is set for a descendent but there is an intermediary value set that is a static value", () => { - const token = new DesignToken(); - const dependency = new DesignToken(); - const ancestor = createNode(); - const parent = createNode(ancestor); - const child = createNode(parent); - const { subscriber, handleChange } = createChangeHandler(); - ancestor.setTokenValue(dependency, 12); - ancestor.setTokenValue(token, resolve => resolve(dependency) * 2); - parent.setTokenValue(token, 25); - - Observable.getNotifier(token).subscribe(subscriber); - child.setTokenValue(dependency, 13); - - expect(handleChange).not.toHaveBeenCalled(); - expect(child.getTokenValue(token)).toEqual(25); - }); - /* eslint-disable-next-line max-len */ - test.skip("the token when a dependency of a derived token value is set for a descendent but there is an intermediary value set that is a derived value that does not depend on the dependent token", () => { - const token = new DesignToken(); - const dependency = new DesignToken(); - const ancestor = createNode(); - const parent = createNode(ancestor); - const child = createNode(parent); - const { subscriber, handleChange } = createChangeHandler(); - ancestor.setTokenValue(dependency, 12); - ancestor.setTokenValue(token, resolve => resolve(dependency) * 2); - parent.setTokenValue(token, () => 25); - - Observable.getNotifier(token).subscribe(subscriber); - child.setTokenValue(dependency, 13); - - expect(handleChange).not.toHaveBeenCalled(); - expect(child.getTokenValue(token)).toEqual(25); - }); - test("the token when a derived value using an observable value is deleted and then the observable value is changed", () => { - const token = new DesignToken(); - const node = new DesignTokenNode(); - const { subscriber, handleChange } = createChangeHandler(); - node.setTokenValue(token, 12); - const dependencies = reactive({ value: 6 }); - - node.setTokenValue(token, () => dependencies.value * 2); - node.deleteTokenValue(token); - Observable.getNotifier(token).subscribe(subscriber); - - dependencies.value = 7; - - expect(handleChange).not.toHaveBeenCalled(); - }); - test("the token when a derived value using an observable value is re-assigned and then the observable value is changed", () => { - const token = new DesignToken(); - const node = new DesignTokenNode(); - const { subscriber, handleChange } = createChangeHandler(); - node.setTokenValue(token, 12); - const dependencies = reactive({ value: 6 }); - - node.setTokenValue(token, () => dependencies.value * 2); - node.setTokenValue(token, () => 14); - Observable.getNotifier(token).subscribe(subscriber); - dependencies.value = 7; - - expect(handleChange).not.toHaveBeenCalled(); - }); - }); -}); diff --git a/packages/web-components/fast-foundation/src/design-token/core/design-token-node.ts b/packages/web-components/fast-foundation/src/design-token/core/design-token-node.ts deleted file mode 100644 index 01220e95a4a..00000000000 --- a/packages/web-components/fast-foundation/src/design-token/core/design-token-node.ts +++ /dev/null @@ -1,724 +0,0 @@ -import type { Disposable, ExpressionNotifier, Subscriber } from "@microsoft/fast-element"; -import { Observable } from "@microsoft/fast-element"; -import type { DesignToken } from "./design-token.js"; - -/** - * A function that resolves the value of a DesignToken. - * @public - */ -export type DesignTokenResolver = (token: DesignToken) => T; - -/** - * A {@link DesignToken} value that is derived. These values can depend on other {@link DesignToken}s - * or arbitrary observable properties. - * @public - */ -export type DerivedDesignTokenValue = (resolve: DesignTokenResolver) => T; - -/** - * A design token value with no observable dependencies - * @public - */ -export type StaticDesignTokenValue = T extends (...args: any[]) => any - ? DerivedDesignTokenValue - : T; - -/** - * The type that a {@link DesignToken} can be set to. - * @public - */ -export type DesignTokenValue = StaticDesignTokenValue | DerivedDesignTokenValue; - -class DerivedValueEvaluator { - private readonly binding: ExpressionNotifier; - private notifier = Observable.getNotifier(this); - public readonly dependencies = new Set>(); - private static cache = new WeakMap< - DerivedDesignTokenValue, - DerivedValueEvaluator - >(); - - constructor(public readonly value: DerivedDesignTokenValue) { - this.binding = Observable.binding(value, this); - this.binding.setMode(false); - } - - public static getOrCreate( - value: DerivedDesignTokenValue - ): DerivedValueEvaluator { - let v = DerivedValueEvaluator.cache.get(value); - - if (v) { - return v; - } - v = new DerivedValueEvaluator(value); - DerivedValueEvaluator.cache.set(value, v); - - return v; - } - - public evaluate(node: DesignTokenNode, tokenContext: DesignToken): T { - const resolve = (token: DesignToken): T => { - this.dependencies.add(token); - if (tokenContext === token) { - if (node.parent) { - return node.parent.getTokenValue(token); - } - - throw new Error( - /* eslint-disable-next-line max-len */ - "DesignTokenNode has encountered a circular token reference. Avoid this by setting the token value for an ancestor node." - ); - } else { - return node.getTokenValue(token); - } - }; - - return this.binding.observe(resolve); - } - - public handleChange() { - this.notifier.notify(undefined); - } -} - -class DerivedValue implements Disposable { - value: T; - constructor( - public readonly token: DesignToken, - public readonly evaluator: DerivedValueEvaluator, - public readonly node: DesignTokenNode, - private subscriber?: Subscriber - ) { - this.value = evaluator.evaluate(node, token); - - if (this.subscriber) { - Observable.getNotifier(this.evaluator).subscribe(this.subscriber); - } - } - - public dispose(): void { - if (this.subscriber) { - Observable.getNotifier(this.evaluator).unsubscribe(this.subscriber); - } - } - - public update() { - this.value = this.evaluator.evaluate(this.node, this.token); - - return this; - } -} - -/** - * @public - */ -export interface DesignTokenChangeRecord { - readonly target: DesignTokenNode; - readonly type: DesignTokenMutationType; - readonly token: DesignToken; -} - -/** - * @internal - */ -export class DesignTokenChangeRecordImpl implements DesignTokenChangeRecord { - constructor( - public readonly target: DesignTokenNode, - public readonly type: DesignTokenMutationType, - public readonly token: DesignToken, - public readonly value?: DesignTokenValue - ) {} - - public notify() { - Observable.getNotifier(this.token).notify(this); - } -} - -/** - * @public - */ -export const enum DesignTokenMutationType { - add, - change, - delete, -} - -/** - * @public - */ -export class DesignTokenNode { - private _parent: DesignTokenNode | null = null; - private _children: Set = new Set(); - private _values: Map, DesignTokenValue> = new Map(); - private _derived: Map, DerivedValue> = new Map(); - private dependencyGraph: Map, Set>> = new Map(); - private static _notifications: DesignTokenChangeRecordImpl[] = []; - - /** - * Determines if a value is a {@link DerivedDesignTokenValue} - * @param value - The value to test - */ - private static isDerivedTokenValue( - value: DesignTokenValue - ): value is DerivedDesignTokenValue { - return typeof value === "function"; - } - - /** - * Determines if a token has a derived value for a node. - */ - private static isDerivedFor(node: DesignTokenNode, token: DesignToken) { - return node._derived.has(token); - } - - /** - * Collects token/value pairs for all derived token / values set on upstream nodes. - */ - private static collectDerivedContext( - node: DesignTokenNode - ): Map, DerivedValue> { - const collected = new Map, DerivedValue>(); - // Exit early if there is no parent - if (node.parent === null) { - return collected; - } - - let ignored = DesignTokenNode.getAssignedTokensForNode(node); - let current: DesignTokenNode | null = node.parent; - - do { - const assigned = DesignTokenNode.getAssignedTokensForNode(current); - for (let i = 0, l = assigned.length; i < l; i++) { - const token = assigned[i]; - - if ( - !ignored.includes(token) && - DesignTokenNode.isDerivedFor(current, token) - ) { - collected.set( - token, - current?._derived.get(token) as DerivedValue - ); - } - } - - ignored = Array.from(new Set(ignored.concat(assigned))); - current = current.parent; - } while (current !== null); - - return collected; - } - - /** - * Resolves the local value for a token if it is assigned, otherwise returns undefined. - */ - private static getLocalTokenValue( - node: DesignTokenNode, - token: DesignToken - ): StaticDesignTokenValue | undefined { - return !DesignTokenNode.isAssigned(node, token) - ? undefined - : DesignTokenNode.isDerivedFor(node, token) - ? node._derived.get(token)?.value - : node._values.get(token); - } - - private static getOrCreateDependencyGraph( - node: DesignTokenNode, - token: DesignToken - ): Set> { - let dependents = node.dependencyGraph.get(token); - - if (dependents) { - return dependents; - } - - dependents = new Set>(); - node.dependencyGraph.set(token, dependents); - - return dependents; - } - - /** - * Emit all queued notifications - */ - private static notify() { - const notifications = this._notifications; - this._notifications = []; - - for (const record of notifications) { - record.notify(); - } - } - - private static queueNotification(...records: DesignTokenChangeRecordImpl[]) { - this._notifications.push(...records); - } - - /** - * Retrieves all tokens assigned directly to a node. - * @param node - the node to retrieve assigned tokens for - * @returns - */ - public static getAssignedTokensForNode(node: DesignTokenNode): DesignToken[] { - return Array.from(node._values.keys()); - } - - /** - * Retrieves all tokens assigned to the node and ancestor nodes. - * @param node - the node to compose assigned tokens for - */ - public static composeAssignedTokensForNode( - node: DesignTokenNode - ): DesignToken[] { - const tokens = new Set(DesignTokenNode.getAssignedTokensForNode(node)); - let current = node.parent; - - while (current !== null) { - const assignedTokens = DesignTokenNode.getAssignedTokensForNode(current); - - for (const token of assignedTokens) { - tokens.add(token); - } - - current = current.parent; - } - - return Array.from(tokens); - } - - /** - * Tests if a token is assigned directly to a node - * @param node - The node to test - * @param token - The token to test - * @returns - */ - public static isAssigned(node: DesignTokenNode, token: DesignToken) { - return node._values.has(token); - } - - /** - * The parent node - */ - public get parent(): DesignTokenNode | null { - return this._parent; - } - - public get children(): DesignTokenNode[] { - return Array.from(this._children); - } - - /** - * Appends a child to the node, notifying for any tokens set for the node's context. - */ - public appendChild(child: DesignTokenNode) { - let prevContext: DesignToken[] | null = null; - - // If this node is already attached, get it's context so change record - // types can be determined - if (child.parent !== null) { - prevContext = DesignTokenNode.composeAssignedTokensForNode(child.parent); - child.parent._children.delete(child); - } - - const context = DesignTokenNode.composeAssignedTokensForNode(this); - const derivedContext = DesignTokenNode.collectDerivedContext(this); - child._parent = this; - this._children.add(child); - - for (const token of context) { - let type = DesignTokenMutationType.add; - if (prevContext !== null) { - const prevContextIndex = prevContext.indexOf(token); - if (prevContextIndex !== -1) { - type = DesignTokenMutationType.change; - prevContext.splice(prevContextIndex, 1); - } - } - child.dispatch( - new DesignTokenChangeRecordImpl( - this, - type, - token, - derivedContext.get(token)?.evaluator.value - ) - ); - } - - if (prevContext !== null && prevContext.length > 0) { - for (const token of prevContext) { - child.dispatch( - new DesignTokenChangeRecordImpl( - this, - DesignTokenMutationType.delete, - token, - derivedContext.get(token)?.evaluator.value - ) - ); - } - } - - DesignTokenNode.notify(); - } - - /** - * Appends a child to the node, notifying for any tokens set for the node's context. - */ - public removeChild(child: DesignTokenNode) { - if (child.parent === this) { - const context = DesignTokenNode.composeAssignedTokensForNode(this); - - child._parent = null; - this._children.delete(child); - - for (const token of context) { - child.dispatch( - new DesignTokenChangeRecordImpl( - this, - DesignTokenMutationType.delete, - token - ) - ); - } - - DesignTokenNode.notify(); - } - } - - /** - * Dispose of the node, removing parent/child relationships and - * unsubscribing all observable binding subscribers. Does not emit - * notifications. - */ - public dispose() { - if (this.parent) { - this.parent._children.delete(this); - this._parent = null; - } - - for (const [, derived] of this._derived) { - derived.dispose(); - } - } - - /** - * Sets a token to a value - */ - public setTokenValue(token: DesignToken, value: DesignTokenValue) { - const changeType = - DesignTokenNode.isAssigned(this, token) || - DesignTokenNode.isDerivedFor(this, token) - ? DesignTokenMutationType.change - : DesignTokenMutationType.add; - const prev = DesignTokenNode.getLocalTokenValue(this, token); - this._values.set(token, value); - if (DesignTokenNode.isDerivedFor(this, token)) { - this.tearDownDerivedTokenValue(token); - } - const isDerived = DesignTokenNode.isDerivedTokenValue(value); - const derivedContext = DesignTokenNode.collectDerivedContext(this); - let result: StaticDesignTokenValue; - - if (isDerived) { - const evaluator = this.setupDerivedTokenValue(token, value, true); - result = evaluator.value; - } else { - result = value; - } - - if (prev !== result) { - DesignTokenNode.queueNotification( - new DesignTokenChangeRecordImpl(this, changeType, token, value) - ); - } - - this.dispatch(new DesignTokenChangeRecordImpl(this, changeType, token, value)); - - derivedContext.forEach((derivedValue, token) => { - // Skip over any derived values already established locally, because - // those will get updated via this.notifyDerived and this.notifyStatic - if (!DesignTokenNode.isDerivedFor(this, token)) { - const prev = DesignTokenNode.getLocalTokenValue(this, token); - derivedValue = this.setupDerivedTokenValue( - token, - derivedValue.evaluator.value - ); - const result = derivedValue.value; - if (prev !== result) { - DesignTokenNode.queueNotification( - new DesignTokenChangeRecordImpl( - this, - DesignTokenMutationType.change, - token, - derivedValue.evaluator.value - ) - ); - } - - this.dispatch( - new DesignTokenChangeRecordImpl( - this, - DesignTokenMutationType.add, - token, - derivedValue.evaluator.value - ) - ); - } - }); - - DesignTokenNode.notify(); - } - - /** - * Returns the resolve value for a token - */ - public getTokenValue(token: DesignToken): T { - /* eslint-disable-next-line */ - let node: DesignTokenNode | null = this; - let value; - - while (node !== null) { - if (DesignTokenNode.isDerivedFor(node, token)) { - value = node._derived.get(token)?.value; - break; - } - - if (DesignTokenNode.isAssigned(node, token)) { - value = node._values.get(token); - break; - } - - node = node._parent; - } - - if (value !== undefined) { - return value; - } else { - throw new Error( - `No value set for token '${token.name ?? token}' in node tree.` - ); - } - } - - /** - * Deletes the token value for a node - */ - public deleteTokenValue(token: DesignToken): void { - if (DesignTokenNode.isAssigned(this, token)) { - const prev = DesignTokenNode.getLocalTokenValue(this, token); - this._values.delete(token); - this.tearDownDerivedTokenValue(token); - let newValue: T | undefined; - try { - newValue = this.getTokenValue(token); - } catch (e) { - newValue = undefined; - } - - DesignTokenNode.queueNotification( - new DesignTokenChangeRecordImpl( - this, - DesignTokenMutationType.delete, - token - ) - ); - - if (prev !== newValue) { - this.dispatch( - new DesignTokenChangeRecordImpl( - this, - DesignTokenMutationType.delete, - token - ) - ); - } - - DesignTokenNode.notify(); - } - } - - /** - * Notifies that a token has been mutated - */ - private dispatch(record: DesignTokenChangeRecordImpl) { - if (this !== record.target) { - const { token } = record; - // If the node is assigned the token being dispatched and the assigned value does not depend on the token - // (circular token reference) then terminate the dispatch. - const isAssigned = DesignTokenNode.isAssigned(this, token); - const containsCircularForToken = - isAssigned && this._derived.get(token)?.evaluator.dependencies.has(token); - if (isAssigned && !containsCircularForToken) { - return; - } - - // Delete token evaluations if the token is not assigned explicitly but is derived for the node and - // the record is a delete type. - if ( - record.type === DesignTokenMutationType.delete && - !isAssigned && - DesignTokenNode.isDerivedFor(this, token) - ) { - this.tearDownDerivedTokenValue(token); - DesignTokenNode.queueNotification( - new DesignTokenChangeRecordImpl( - this, - DesignTokenMutationType.delete, - token - ) - ); - } - - if (containsCircularForToken) { - record = new DesignTokenChangeRecordImpl( - this, - DesignTokenMutationType.change, - token, - this._derived.get(token)?.evaluator.value - ); - } - - const { value } = record; - - if (value && DesignTokenNode.isDerivedTokenValue(value)) { - const dependencies = - DerivedValueEvaluator.getOrCreate(value).dependencies; - // If this is not the originator, check to see if this node - // has any dependencies of the token value. If so, we need to evaluate for this node - let evaluate = false; - - for (const dependency of dependencies) { - if (DesignTokenNode.isAssigned(this, dependency)) { - evaluate = true; - break; - } - } - - if (evaluate) { - const prev = this._derived.get(token)?.value; - const derivedValue = this.setupDerivedTokenValue(token, value); - - if (prev !== derivedValue.value) { - const type = - prev === undefined - ? DesignTokenMutationType.add - : DesignTokenMutationType.change; - const notification = new DesignTokenChangeRecordImpl( - this, - type, - token, - derivedValue.evaluator.value - ); - DesignTokenNode.queueNotification(notification); - record = notification; - } - } - } - } - - this.collectLocalChangeRecords(record).forEach(_record => { - DesignTokenNode.queueNotification(_record); - this.dispatch(_record); - }); - - this.notifyChildren(record); - } - - /** - * Generate change-records for local dependencies of a change record - */ - private collectLocalChangeRecords( - record: DesignTokenChangeRecordImpl - ): Map, DesignTokenChangeRecordImpl> { - const collected = new Map, DesignTokenChangeRecordImpl>(); - for (const dependent of DesignTokenNode.getOrCreateDependencyGraph( - this, - record.token - )) { - if (dependent.value !== dependent.update().value) { - collected.set( - dependent.token, - new DesignTokenChangeRecordImpl( - this, - DesignTokenMutationType.change, - dependent.token, - dependent.evaluator.value - ) - ); - } - } - - return collected; - } - - /** - * - * Notify children of changes to the node - */ - private notifyChildren(...records: DesignTokenChangeRecordImpl[]) { - if (this.children.length) { - for (let i = 0, l = this.children.length; i < l; i++) { - for (let j = 0; j < records.length; j++) { - this.children[i].dispatch(records[j]); - } - } - } - } - - private tearDownDerivedTokenValue(token: DesignToken) { - if (DesignTokenNode.isDerivedFor(this, token)) { - const value = this._derived.get(token) as DerivedValue; - - value.dispose(); - - this._derived.delete(token); - - value.evaluator.dependencies.forEach(dependency => { - DesignTokenNode.getOrCreateDependencyGraph(this, dependency).delete( - value - ); - }); - } - } - - private setupDerivedTokenValue( - token: DesignToken, - value: DerivedDesignTokenValue, - subscribeNode = false - ) { - const deriver = new DerivedValue( - token, - DerivedValueEvaluator.getOrCreate(value), - this, - subscribeNode - ? { - handleChange: () => { - if (deriver.value !== deriver.update().value) { - const record = new DesignTokenChangeRecordImpl( - this, - DesignTokenMutationType.change, - deriver.token, - deriver.evaluator.value - ); - DesignTokenNode.queueNotification(record); - - this.dispatch(record); - DesignTokenNode.notify(); - } - }, - } - : undefined - ); - - this._derived.set(token, deriver); - - deriver.evaluator.dependencies.forEach(dependency => { - if (dependency !== token) { - DesignTokenNode.getOrCreateDependencyGraph(this, dependency).add(deriver); - } - }); - - return deriver; - } -} diff --git a/packages/web-components/fast-foundation/src/design-token/core/design-token.ts b/packages/web-components/fast-foundation/src/design-token/core/design-token.ts deleted file mode 100644 index 095cf94a131..00000000000 --- a/packages/web-components/fast-foundation/src/design-token/core/design-token.ts +++ /dev/null @@ -1,7 +0,0 @@ -/** - * @public - */ -export interface DesignToken { - readonly $value: T | undefined; - readonly name?: string; -} diff --git a/packages/web-components/fast-foundation/src/design-token/core/exports.ts b/packages/web-components/fast-foundation/src/design-token/core/exports.ts deleted file mode 100644 index 0b7954004da..00000000000 --- a/packages/web-components/fast-foundation/src/design-token/core/exports.ts +++ /dev/null @@ -1,9 +0,0 @@ -export { DesignTokenMutationType, DesignTokenNode } from "./design-token-node.js"; -export type { - DerivedDesignTokenValue, - DesignTokenChangeRecord, - DesignTokenResolver, - DesignTokenValue, - StaticDesignTokenValue, -} from "./design-token-node.js"; -export type { DesignToken } from "./design-token.js"; diff --git a/packages/web-components/fast-foundation/src/design-token/core/test/fast-element-dom-shim.ts b/packages/web-components/fast-foundation/src/design-token/core/test/fast-element-dom-shim.ts deleted file mode 100644 index add8dfa966d..00000000000 --- a/packages/web-components/fast-foundation/src/design-token/core/test/fast-element-dom-shim.ts +++ /dev/null @@ -1,9 +0,0 @@ -// Allow fast-element to bootstrap. This is necessary -// because DesignTokenNode uses fast-element's Observable, -// and importing Observable forces access to several DOM globals -(globalThis as any)["document"] = { - createElement() { - return {}; - }, -}; -(globalThis as any)["HTMLElement"] = class {}; diff --git a/packages/web-components/fast-foundation/src/design-token/custom-property-manager.ts b/packages/web-components/fast-foundation/src/design-token/custom-property-manager.ts deleted file mode 100644 index 4bc5a671c95..00000000000 --- a/packages/web-components/fast-foundation/src/design-token/custom-property-manager.ts +++ /dev/null @@ -1,229 +0,0 @@ -import type { - Constructable, - ElementController, - FASTElement, -} from "@microsoft/fast-element"; -import { ElementStyles, observable, Observable, Updates } from "@microsoft/fast-element"; - -/** - * A target that can have key/value pairs set and removed. - * @public - */ -export interface PropertyTarget { - setProperty(name: string, value: string): void; - removeProperty(name: string): void; -} - -abstract class QueuedStyleSheetTarget implements PropertyTarget { - protected abstract target: PropertyTarget; - - public setProperty(name: string, value: string) { - Updates.enqueue(() => this.target.setProperty(name, value)); - } - public removeProperty(name: string) { - Updates.enqueue(() => this.target.removeProperty(name)); - } -} -/** - * Handles setting properties for a FASTElement using Constructable Stylesheets - */ -class ConstructableStyleSheetTarget extends QueuedStyleSheetTarget { - protected target: PropertyTarget; - constructor(source: FASTElement) { - super(); - - const sheet = new CSSStyleSheet(); - this.target = (sheet.cssRules[sheet.insertRule(":host{}")] as CSSStyleRule).style; - source.$fastController.addStyles(new ElementStyles([sheet])); - } -} - -class DocumentStyleSheetTarget extends QueuedStyleSheetTarget { - protected target: PropertyTarget; - constructor() { - super(); - - const sheet = new CSSStyleSheet(); - this.target = (sheet.cssRules[sheet.insertRule(":root{}")] as CSSStyleRule).style; - (document as any).adoptedStyleSheets = [ - ...(document as any).adoptedStyleSheets, - sheet, - ]; - } -} - -class HeadStyleElementStyleSheetTarget extends QueuedStyleSheetTarget { - protected target: PropertyTarget; - private readonly style: HTMLStyleElement; - - constructor() { - super(); - - this.style = document.createElement("style") as HTMLStyleElement; - document.head.appendChild(this.style); - const { sheet } = this.style; - - // Because the HTMLStyleElement has been appended, - // there shouldn't exist a case where `sheet` is null, - // but if-check it just in case. - if (sheet) { - // https://github.com/jsdom/jsdom uses https://github.com/NV/CSSOM for it's CSSOM implementation, - // which implements the DOM Level 2 spec for CSSStyleSheet where insertRule() requires an index argument. - const index = sheet.insertRule(":root{}", sheet.cssRules.length); - this.target = (sheet.cssRules[index] as CSSStyleRule).style; - } - } -} - -/** - * Handles setting properties for a FASTElement using an HTMLStyleElement - */ -class StyleElementStyleSheetTarget implements PropertyTarget { - private store = new Map(); - private readonly style: HTMLStyleElement; - - @observable - private target: PropertyTarget | null = null; - private targetChanged() { - if (this.target !== null) { - for (const [key, value] of this.store.entries()) { - this.target.setProperty(key, value); - } - } - } - - constructor(target: FASTElement) { - const controller = target.$fastController; - this.style = document.createElement("style") as HTMLStyleElement; - - controller.addStyles(this.style); - - Observable.getNotifier(controller).subscribe(this, "isConnected"); - this.handleChange(controller, "isConnected"); - } - - public setProperty(name: string, value: string) { - this.store.set(name, value); - - Updates.enqueue(() => { - if (this.target !== null) { - this.target.setProperty(name, value); - } - }); - } - - public removeProperty(name: string) { - this.store.delete(name); - - Updates.enqueue(() => { - if (this.target !== null) { - this.target.removeProperty(name); - } - }); - } - - handleChange(source: ElementController, key: "isConnected") { - // HTMLStyleElement.sheet is null if the element isn't connected to the DOM, - // so this method reacts to changes in DOM connection for the element hosting - // the HTMLStyleElement. - // - // All rules applied via the CSSOM also get cleared when the element disconnects, - // so we need to add a new rule each time and populate it with the stored properties - const { sheet } = this.style; - if (sheet) { - // Safari will throw if we try to use the return result of insertRule() - // to index the rule inline, so store as a const prior to indexing. - // https://github.com/jsdom/jsdom uses https://github.com/NV/CSSOM for it's CSSOM implementation, - // which implements the DOM Level 2 spec for CSSStyleSheet where insertRule() requires an index argument. - const index = sheet.insertRule(":host{}", sheet.cssRules.length); - this.target = (sheet.cssRules[index] as CSSStyleRule).style; - } else { - this.target = null; - } - } -} - -/** - * Controls emission for default values. This control is capable - * of emitting to multiple {@link PropertyTarget | PropertyTargets}, - * and only emits if it has at least one root. - * - * @internal - */ -export class RootStyleSheetTarget implements PropertyTarget { - private static roots = new Set(); - private static properties: Record = {}; - public setProperty(name: string, value: any): void { - RootStyleSheetTarget.properties[name] = value; - - for (const target of RootStyleSheetTarget.roots.values()) { - target.setProperty(name, value); - } - } - - public removeProperty(name: string): void { - delete RootStyleSheetTarget.properties[name]; - for (const target of RootStyleSheetTarget.roots.values()) { - target.removeProperty(name); - } - } - - public static registerRoot(root: PropertyTarget) { - const { roots } = RootStyleSheetTarget; - if (!roots.has(root)) { - roots.add(root); - for (const key in RootStyleSheetTarget.properties) { - root.setProperty(key, RootStyleSheetTarget.properties[key]); - } - } - } - - public static unregisterRoot(root: PropertyTarget) { - const { roots } = RootStyleSheetTarget; - if (roots.has(root)) { - roots.delete(root); - - for (const key in RootStyleSheetTarget.properties) { - root.removeProperty(key); - } - } - } -} - -// Caches PropertyTarget instances -const propertyTargetCache: WeakMap = - new WeakMap(); -// Use Constructable StyleSheets for FAST elements when supported, otherwise use -// HTMLStyleElement instances -const propertyTargetCtor: Constructable = - ElementStyles.supportsAdoptedStyleSheets - ? ConstructableStyleSheetTarget - : StyleElementStyleSheetTarget; - -/** - * Manages creation and caching of PropertyTarget instances. - * - * @internal - */ -export const PropertyTargetManager = Object.freeze({ - getOrCreate(source: FASTElement | Document): PropertyTarget { - if (propertyTargetCache.has(source)) { - /* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */ - return propertyTargetCache.get(source)!; - } - - let target: PropertyTarget; - - if (source instanceof Document) { - target = ElementStyles.supportsAdoptedStyleSheets - ? new DocumentStyleSheetTarget() - : new HeadStyleElementStyleSheetTarget(); - } else { - target = new propertyTargetCtor(source); - } - - propertyTargetCache.set(source, target); - - return target; - }, -}); diff --git a/packages/web-components/fast-foundation/src/design-token/design-token-style-target.ts b/packages/web-components/fast-foundation/src/design-token/design-token-style-target.ts deleted file mode 100644 index 83c00c9a2d2..00000000000 --- a/packages/web-components/fast-foundation/src/design-token/design-token-style-target.ts +++ /dev/null @@ -1,41 +0,0 @@ -import type { PropertyTarget } from "./custom-property-manager.js"; - -/** - * A constructable style target that can be registered - * for DesignToken default style emission. - * - * Useful for controlling where CSS is emitted to, or when needing - * to collect styles for SSR processes. - * - * @public - */ -export class DesignTokenStyleTarget implements PropertyTarget { - private properties = new Map(); - setProperty(name: string, value: string): void { - this.properties.set(name, value); - } - removeProperty(name: string): void { - this.properties.delete(name); - } - - /** - * The CSS text for the style target. - * The text does *not* contain [CSS selector text](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors). - */ - public get cssText(): string { - let css = ""; - - for (const [key, value] of this.properties) { - css += `${key}: ${value};`; - } - - return css; - } - - /** - * The values set for the target as an array of key/value pairs. - */ - public get values(): Array<[string, string]> { - return Array.from(this.properties); - } -} diff --git a/packages/web-components/fast-foundation/src/design-token/event-strategy.spec.ts b/packages/web-components/fast-foundation/src/design-token/event-strategy.spec.ts deleted file mode 100644 index 43ee982bf47..00000000000 --- a/packages/web-components/fast-foundation/src/design-token/event-strategy.spec.ts +++ /dev/null @@ -1,91 +0,0 @@ - -import { css, customElement, FASTElement, HostController, html, Observable, Updates } from "@microsoft/fast-element"; -import chai, { expect } from "chai"; -import spies from "chai-spies"; -import { uniqueElementName } from "@microsoft/fast-element/testing.js"; -import {DesignTokenEventResolutionStrategy} from "./event-strategy.js" - -const elementName = uniqueElementName(); - - -@customElement({ - name: `fast-${elementName}`, - template: html`` -}) -export class MyElement extends FASTElement {} - -function createElement(): FASTElement & HTMLElement { - return document.createElement(`fast-${elementName}`) as any; -} -function addElement(parent = document.body): FASTElement & HTMLElement { - const el = createElement(); - parent.appendChild(el); - return el; -} - -function removeElement(...els: HTMLElement[]) { - els.forEach(el => { - el.parentElement?.removeChild(el); - }) -} - -describe("The DesignTokenEventResolutionStrategy's", () => { - describe("parent method", () => { - function createController(source: any): HostController { - return { - mainStyles: null, - isConnected: false, - source, - addStyles() {}, - removeStyles(styles) {}, - addBehavior() {}, - removeBehavior() {}, - }; - } - - it("should return the nearest parent element that has been bound", () => { - const parent = addElement() - const child = addElement(parent); - - DesignTokenEventResolutionStrategy.addedCallback!( - createController(parent) - ); - - DesignTokenEventResolutionStrategy.addedCallback!( - createController(child) - ); - - expect(DesignTokenEventResolutionStrategy.parent(child)).to.equal(parent); - }); - it("should return null if no parent element exists", () => { - const target = addElement(); - DesignTokenEventResolutionStrategy.addedCallback!( - createController(target) - ); - - expect(DesignTokenEventResolutionStrategy.parent(target)).to.equal(null); - }); - }); - - describe("contains method", () => { - it("should return false if the target is not the child of the parent", () => { - const parent = addElement() - const child = addElement(); - - expect(DesignTokenEventResolutionStrategy.contains(parent, child)).to.equal(false); - }); - it("should return true if the target is a child of the parent", () => { - const parent = addElement() - const child = addElement(parent); - - expect(DesignTokenEventResolutionStrategy.contains(parent, child)).to.equal(true); - }); - it("should return true if the target is a descendent of the parent", () => { - const ancestor = addElement(); - const parent = addElement(ancestor); - const child = addElement(parent); - - expect(DesignTokenEventResolutionStrategy.contains(ancestor, child)).to.equal(true); - }); - }); -}); diff --git a/packages/web-components/fast-foundation/src/design-token/event-strategy.ts b/packages/web-components/fast-foundation/src/design-token/event-strategy.ts deleted file mode 100644 index 2a7466a6b4e..00000000000 --- a/packages/web-components/fast-foundation/src/design-token/event-strategy.ts +++ /dev/null @@ -1,61 +0,0 @@ -import type { FASTElement, HostController } from "@microsoft/fast-element"; -import type { DesignTokenResolutionStrategy } from "./fast-design-token.js"; - -const parentLocatorEventName = "$$designToken__locate__parent$$"; -const containsEventName = "$$designToken__contains$$"; -type ParentLocatorEvent = CustomEvent<{ parent: FASTElement | null }>; -type ContainsEvent = CustomEvent<{ contains: boolean }>; -function parentLocatorHandler(event: ParentLocatorEvent) { - if (event.target !== this) { - event.detail.parent = this; - event.stopImmediatePropagation(); - } -} - -function containsHandler(event: ContainsEvent) { - if (event.detail !== this) { - event.detail.contains = true; - event.stopImmediatePropagation(); - } -} - -/** - * A DesignToken resolution strategy that uses custom events to resolve - * node hierarchies. - * - * @public - */ -export const DesignTokenEventResolutionStrategy: DesignTokenResolutionStrategy = { - addedCallback(controller: HostController) { - controller.source.addEventListener(parentLocatorEventName, parentLocatorHandler); - }, - removedCallback(controller: HostController) { - controller.source.removeEventListener( - parentLocatorEventName, - parentLocatorHandler - ); - }, - contains(parent, child): boolean { - parent.addEventListener(containsEventName, containsHandler); - const event = new CustomEvent(containsEventName, { - bubbles: true, - cancelable: true, - composed: true, - detail: { contains: false }, - }); - child.dispatchEvent(event); - parent.removeEventListener(containsEventName, containsHandler); - return event.detail.contains; - }, - parent(element): FASTElement | null { - const event: ParentLocatorEvent = new CustomEvent(parentLocatorEventName, { - bubbles: true, - cancelable: true, - composed: true, - detail: { parent: null }, - }); - element.dispatchEvent(event); - - return event.detail.parent; - }, -}; diff --git a/packages/web-components/fast-foundation/src/design-token/exports.ts b/packages/web-components/fast-foundation/src/design-token/exports.ts deleted file mode 100644 index 20025746003..00000000000 --- a/packages/web-components/fast-foundation/src/design-token/exports.ts +++ /dev/null @@ -1,16 +0,0 @@ -export type { - DerivedDesignTokenValue, - DesignTokenMutationType, - DesignTokenResolver, - StaticDesignTokenValue, -} from "./core/exports.js"; -export type { PropertyTarget } from "./custom-property-manager.js"; -export { DesignTokenStyleTarget } from "./design-token-style-target.js"; -export { DesignTokenEventResolutionStrategy } from "./event-strategy.js"; -export { CSSDesignToken, DesignToken } from "./fast-design-token.js"; -export type { - CSSDesignTokenConfiguration, - DesignTokenChangeRecord, - DesignTokenConfiguration, - DesignTokenSubscriber, -} from "./fast-design-token.js"; diff --git a/packages/web-components/fast-foundation/src/design-token/fast-design-token.pw.spec.ts b/packages/web-components/fast-foundation/src/design-token/fast-design-token.pw.spec.ts deleted file mode 100644 index 0a37378c2b0..00000000000 --- a/packages/web-components/fast-foundation/src/design-token/fast-design-token.pw.spec.ts +++ /dev/null @@ -1,1590 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function */ -import type { - css as FASTcss, - FASTElement, - Observable as FASTObservable, - Updates as FASTUpdates, -} from "@microsoft/fast-element"; -import type { Locator, Page } from "@playwright/test"; -import { expect, test } from "@playwright/test"; -import { fixtureURL } from "../__test__/helpers.js"; -import type { DesignTokenResolver } from "./core/design-token-node.js"; -import type { - CSSDesignToken as CSSDesignTokenImpl, - DesignToken as DesignTokenImpl, - DesignTokenSubscriber, -} from "./fast-design-token.js"; - -interface Spy extends Function { - calls: number; - calledWith(n: number): any; -} - -declare const DesignToken: typeof DesignTokenImpl; -declare const CSSDesignToken: typeof CSSDesignTokenImpl; -declare const createElement: () => FASTElement; -declare const addElement: (parent?: Element) => FASTElement; -declare const Updates: typeof FASTUpdates; -declare const css: typeof FASTcss; -declare const threw: (fn: () => void) => boolean; -declare const cleanup: () => void; -declare const Observable: typeof FASTObservable; -declare const spy: any>(fn: T) => Spy & T; - -function* nameGenerator(): Generator { - let i = 0; - - while (true) { - yield `token-name-${i}`; - i++; - } -} -const gen = nameGenerator(); - -function uniqueTokenName(): string { - return gen.next().value; -} - -// Test utilities - -test.describe("A DesignToken", () => { - let page: Page; - let root: Locator; - - test.beforeAll(async ({ browser }) => { - page = await browser.newPage(); - root = page.locator("#root"); - - await page.goto(fixtureURL("debug-designtoken--design-token")); - - await page.waitForSelector("fast-design-token-controller"); - - await page.evaluate(() => DesignToken.registerDefaultStyleTarget()); - }); - - test.afterAll(async () => { - await page.evaluate(() => DesignToken.registerDefaultStyleTarget()); - await page.close(); - }); - - test.afterEach(async () => { - await page.evaluate(() => cleanup()); - }); - - test("should support declared types", async () => { - await page.evaluate((name: string) => { - const number = DesignToken.create(name); - const nil = DesignToken.create(name); - const bool = DesignToken.create(name); - const arr = DesignToken.create(name); - const obj = DesignToken.create<{}>(name); - class Foo {} - const _class = DesignToken.create(name); - const sym = DesignToken.create(name); - }, uniqueTokenName()); - }); - - test.describe("should have a create method", () => { - test("that creates a CSSDesignToken when invoked with a string value", async () => { - const result = await page.evaluate( - (name: string) => DesignToken.create(name) instanceof CSSDesignToken, - uniqueTokenName() - ); - - expect(result).toBe(true); - }); - test("that creates a CSSDesignToken when invoked with a CSSDesignTokenConfiguration", async () => { - const result = await page.evaluate( - (name: string) => - DesignToken.create({ - name: name, - cssCustomPropertyName: "css", - }) instanceof CSSDesignToken, - uniqueTokenName() - ); - expect(result).toBe(true); - }); - test("that creates a DesignToken when invoked with a DesignTokenConfiguration", async () => { - const result = await page.evaluate( - (name: string) => DesignToken.create({ name }) instanceof CSSDesignToken, - uniqueTokenName() - ); - - expect(result).toBe(false); - }); - }); - - test.describe("that is not a CSSDesignToken", () => { - test("should not have a cssCustomProperty property", async () => { - const result = await page.evaluate((name: string) => { - return "cssCustomProperty" in DesignToken.create({ name }); - }, uniqueTokenName()); - - expect(result).toEqual(false); - }); - test("should not have a cssVar property", async () => { - const result = await page.evaluate((name: string) => { - return "cssVar" in DesignToken.create({ name }); - }, uniqueTokenName()); - expect(result).toEqual(false); - }); - }); - test.describe("getting and setting a simple value", () => { - test("should throw if the token value has never been set on the element or its ancestors", async () => { - const result = await page.evaluate((name: string) => { - const target = addElement(); - const token = DesignToken.create(name); - return threw(() => token.getValueFor(target)); - }, uniqueTokenName()); - - expect(result).toBe(true); - }); - - test("should return the value set for the element if one has been set", async () => { - const result = await page.evaluate((name: string) => { - const target = addElement(); - const token = DesignToken.create(name); - token.setValueFor(target, 12); - return token.getValueFor(target); - }, uniqueTokenName()); - - expect(result).toEqual(12); - }); - - test("should return the value set for an ancestor if a value has not been set for the target", async () => { - const result = await page.evaluate((name: string) => { - const ancestor = addElement(); - const target = addElement(ancestor); - const token = DesignToken.create(name); - token.setValueFor(ancestor, 12); - return token.getValueFor(target); - }, uniqueTokenName()); - - expect(result).toEqual(12); - }); - - test("sound return the nearest ancestor's value after an intermediary value is set where no value was set prior", async () => { - expect( - await page.evaluate(async () => { - const results = []; - const name = uniqueTokenName(); - const grandParent = addElement(); - const parent = addElement(grandParent); - const target = addElement(parent); - const token = DesignToken.create(name); - token.setValueFor(grandParent, 12); - - results.push(token.getValueFor(grandParent)); - - token.setValueFor(parent, 14); - results.push(token.getValueFor(target)); - return results; - }) - ).toEqual([12, 14]); - }); - - test("should return the new ancestor's value after being re-parented", async () => { - expect( - await page.evaluate(async () => { - const results = []; - const token = DesignToken.create(uniqueTokenName()); - const parentA = addElement(); - const parentB = addElement(); - const target = addElement(parentA); - - token.setValueFor(parentA, 12); - token.setValueFor(parentB, 14); - - results.push(token.getValueFor(target)); - - parentA.removeChild(target); - parentB.appendChild(target); - - results.push(token.getValueFor(target)); - return results; - }) - ).toEqual([12, 14]); - }); - - test("should persist explicitly set value even if it matches the inherited value", async () => { - expect( - await page.evaluate(async () => { - const results = []; - const ancestor = addElement(); - const target = addElement(ancestor); - const token = DesignToken.create(uniqueTokenName()); - token.setValueFor(ancestor, 12); - token.setValueFor(target, 12); - - results.push(token.getValueFor(target)); - - token.setValueFor(ancestor, 14); - - await Updates.next(); - - results.push(token.getValueFor(target)); - return results; - }) - ).toEqual([12, 12]); - }); - - test("should support getting and setting falsey values", async () => { - expect( - await page.evaluate(() => { - const target = addElement(); - - return [false, null, 0, "", NaN] - .map(value => { - const token = DesignToken.create( - uniqueTokenName() - ); - token.setValueFor(target, value); - - if (typeof value === "number" && isNaN(value)) { - return ( - isNaN(token.getValueFor(target) as number) === true - ); - } else { - return token.getValueFor(target) === value; - } - }) - .every(x => x === true); - }) - ).toBe(true); - }); - - test.describe("that is a CSSDesignToken", () => { - test("should set the CSS custom property for the element", async () => { - expect( - await page.evaluate(async () => { - const target = addElement(); - const token = DesignToken.create(uniqueTokenName()); - token.setValueFor(target, 12); - await Updates.next(); - return window - .getComputedStyle(target) - .getPropertyValue(token.cssCustomProperty); - }) - ).toBe("12"); - }); - test("should be a CSSDirective", async () => { - expect( - await page.evaluate(async () => { - const token = DesignToken.create( - uniqueTokenName() - ).withDefault(12); - const sheet = css` - :host { - --property: ${token}; - } - `; - const element = addElement(); - element.$fastController.addStyles(sheet); - - await Updates.next(); - return window - .getComputedStyle(element) - .getPropertyValue("--property") - .trim(); - }) - ).toBe("12"); - }); - - test("should inherit CSS custom property from ancestor", async () => { - expect( - await page.evaluate(async () => { - const results = []; - const ancestor = addElement(); - const target = addElement(ancestor); - const token = DesignToken.create(uniqueTokenName()); - token.setValueFor(ancestor, 12); - await Updates.next(); - results.push( - window - .getComputedStyle(target) - .getPropertyValue(token.cssCustomProperty) - ); - token.setValueFor(ancestor, 14); - await Updates.next(); - results.push( - window - .getComputedStyle(target) - .getPropertyValue(token.cssCustomProperty) - ); - return results; - }) - ).toEqual(["12", "14"]); - }); - - test("should set CSS custom property for element if value stops matching inherited value", async () => { - expect( - await page.evaluate(async () => { - const results = []; - const ancestor = addElement(); - const target = addElement(ancestor); - const token = DesignToken.create(uniqueTokenName()); - token.setValueFor(ancestor, 12); - token.setValueFor(target, 12); - await Updates.next(); - results.push( - window - .getComputedStyle(target) - .getPropertyValue(token.cssCustomProperty) - ); - token.setValueFor(ancestor, 14); - await Updates.next(); - results.push( - window - .getComputedStyle(target) - .getPropertyValue(token.cssCustomProperty) - ); - return results; - }) - ).toEqual(["12", "12"]); - }); - }); - test.describe("that is not a CSSDesignToken", () => { - test("should not set a CSS custom property for the element", async () => { - expect( - await page.evaluate(() => { - const name = uniqueTokenName(); - const target = addElement(); - const token = DesignToken.create({ name }); - token.setValueFor(target, 12); - return window - .getComputedStyle(target) - .getPropertyValue(`--${name}`); - }) - ).toBe(""); - }); - }); - }); - - test.describe("getting and setting derived values", () => { - test("should get the return value of a derived value", async () => { - const name = uniqueTokenName(); - expect( - await page.evaluate((name: string) => { - const target = addElement(); - const token = DesignToken.create(name); - token.setValueFor(target, () => 12); - - return token.getValueFor(target); - }, name) - ).toBe(12); - }); - test("should get an updated value when observable properties used in a derived property are changed", async () => { - const name = uniqueTokenName(); - expect( - await page.evaluate(async (name: string) => { - const target = addElement(); - const token = DesignToken.create(name); - const results = []; - const dependencies: { value: number } = {} as { value: number }; - Observable.defineProperty(dependencies, "value"); - dependencies.value = 6; - - token.setValueFor(target, () => dependencies.value * 2); - results.push(token.getValueFor(target)); - - dependencies.value = 7; - await Updates.next(); - - results.push(token.getValueFor(target)); - return results; - }, name) - ).toEqual([12, 14]); - }); - - test("should get an updated value when other design tokens used in a derived property are changed", async () => { - expect( - await page.evaluate(async () => { - const target = addElement(); - const results = []; - const tokenA = DesignToken.create(uniqueTokenName()); - const tokenB = DesignToken.create(uniqueTokenName()); - - tokenA.setValueFor(target, 6); - tokenB.setValueFor(target, resolve => resolve(tokenA) * 2); - - results.push(tokenB.getValueFor(target)); - tokenA.setValueFor(target, 7); - await Updates.next(); - - results.push(tokenB.getValueFor(target)); - return results; - }) - ).toEqual([12, 14]); - }); - test("should use the closest value of a dependent token when getting a token for a target", async () => { - expect( - await page.evaluate(async () => { - const ancestor = addElement(); - const parent = addElement(ancestor); - const target = addElement(parent); - const tokenA = DesignToken.create(uniqueTokenName()); - const tokenB = DesignToken.create(uniqueTokenName()); - - tokenA.setValueFor(ancestor, 7); - tokenA.setValueFor(parent, 6); - tokenB.setValueFor(ancestor, resolve => resolve(tokenA) * 2); - - return tokenB.getValueFor(target); - }) - ).toBe(12); - }); - - test("should update value of a dependent token when getting a token for a target", async () => { - expect( - await page.evaluate(async () => { - const results = []; - const ancestor = addElement(); - const parent = addElement(ancestor); - const target = addElement(parent); - const tokenA = DesignToken.create(uniqueTokenName()); - const tokenB = DesignToken.create(uniqueTokenName()); - - tokenA.setValueFor(ancestor, 7); - tokenA.setValueFor(parent, 6); - tokenB.setValueFor(ancestor, resolve => resolve(tokenA) * 2); - - results.push(tokenB.getValueFor(target)); - - tokenA.setValueFor(parent, 7); - await Updates.next(); - - results.push(tokenB.getValueFor(target)); - return results; - }) - ).toEqual([12, 14]); - }); - - test("should get an updated value when a used design token is set for a node closer to the target", async () => { - expect( - await page.evaluate(async () => { - const results = []; - const ancestor = addElement(); - const parent = addElement(ancestor); - const target = addElement(parent); - const tokenA = DesignToken.create(uniqueTokenName()); - const tokenB = DesignToken.create(uniqueTokenName()); - - tokenA.setValueFor(ancestor, 6); - tokenB.setValueFor(ancestor, resolve => resolve(tokenA) * 2); - - results.push(tokenB.getValueFor(target)); - - tokenA.setValueFor(target, 7); - results.push(tokenB.getValueFor(target)); - - return results; - }) - ).toEqual([12, 14]); - }); - - test.describe("that is a CSSDesignToken", () => { - test("should set a CSS custom property equal to the resolved value of a derived token value", async () => { - expect( - await page.evaluate(async () => { - const target = addElement(); - const token = DesignToken.create(uniqueTokenName()); - - token.setValueFor(target, target => 12); - - await Updates.next(); - return window - .getComputedStyle(target) - .getPropertyValue(token.cssCustomProperty); - }) - ).toBe("12"); - }); - /* eslint-disable-next-line max-len */ - test("should set a CSS custom property equal to the resolved value of a derived token value with a dependent token", async () => { - expect( - await page.evaluate(async () => { - const target = addElement(); - const tokenA = DesignToken.create(uniqueTokenName()); - const tokenB = DesignToken.create(uniqueTokenName()); - - tokenA.setValueFor(target, 6); - tokenB.setValueFor(target, resolve => resolve(tokenA) * 2); - - await Updates.next(); - - return window - .getComputedStyle(target) - .getPropertyValue(tokenB.cssCustomProperty); - }) - ).toBe("12"); - }); - /* eslint-disable-next-line max-len */ - test("should update a CSS custom property to the resolved value of a derived token value with a dependent token when the dependent token changes", async () => { - expect( - await page.evaluate(async () => { - const results = []; - const target = addElement(); - const tokenA = DesignToken.create(uniqueTokenName()); - const tokenB = DesignToken.create(uniqueTokenName()); - - tokenA.setValueFor(target, 6); - tokenB.setValueFor(target, resolve => resolve(tokenA) * 2); - - await Updates.next(); - results.push( - window - .getComputedStyle(target) - .getPropertyValue(tokenB.cssCustomProperty) - ); - - tokenA.setValueFor(target, 7); - await Updates.next(); - results.push( - window - .getComputedStyle(target) - .getPropertyValue(tokenB.cssCustomProperty) - ); - - return results; - }) - ).toEqual(["12", "14"]); - }); - /* eslint-disable-next-line max-len */ - test("should set a CSS custom property equal to the resolved value for an element of a derived token value with a dependent token", async () => { - expect( - await page.evaluate(async () => { - const results = []; - const parent = addElement(); - const target = addElement(parent); - const tokenA = DesignToken.create(uniqueTokenName()); - const tokenB = DesignToken.create(uniqueTokenName()); - - tokenA.setValueFor(parent, 6); - tokenB.setValueFor(parent, resolve => resolve(tokenA) * 2); - tokenA.setValueFor(target, 7); - - await Updates.next(); - - results.push( - window - .getComputedStyle(parent) - .getPropertyValue(tokenB.cssCustomProperty) - ); - results.push( - window - .getComputedStyle(target) - .getPropertyValue(tokenB.cssCustomProperty) - ); - return results; - }) - ).toEqual(["12", "14"]); - }); - /* eslint-disable-next-line max-len */ - test("should set a CSS custom property equal to the resolved value for an element in a shadow DOM of a derived token value with a dependent token", async () => { - expect( - await page.evaluate(async () => { - const results = []; - const parent = addElement(); - const child = addElement(parent); - const target = createElement(); - child.shadowRoot?.appendChild(target); - const tokenA = DesignToken.create(uniqueTokenName()); - const tokenB = DesignToken.create(uniqueTokenName()); - - tokenA.setValueFor(parent, 6); - tokenB.setValueFor(parent, resolve => resolve(tokenA) * 2); - tokenA.setValueFor(target, 7); - - await Updates.next(); - - results.push( - window - .getComputedStyle(parent) - .getPropertyValue(tokenB.cssCustomProperty) - ); - results.push( - window - .getComputedStyle(target) - .getPropertyValue(tokenB.cssCustomProperty) - ); - return results; - }) - ).toEqual(["12", "14"]); - }); - /* eslint-disable-next-line max-len */ - test("should set a CSS custom property equal to the resolved value for both elements for which a dependent token is set when setting a derived token value", async () => { - expect( - await page.evaluate(async () => { - const results = []; - const parent = addElement(); - const target = addElement(parent); - const tokenA = DesignToken.create(uniqueTokenName()); - const tokenB = DesignToken.create(uniqueTokenName()); - - tokenA.setValueFor(parent, 6); - tokenA.setValueFor(target, 7); - tokenB.setValueFor(parent, resolve => resolve(tokenA) * 2); - - await Updates.next(); - - results.push( - window - .getComputedStyle(parent) - .getPropertyValue(tokenB.cssCustomProperty) - ); - results.push( - window - .getComputedStyle(target) - .getPropertyValue(tokenB.cssCustomProperty) - ); - return results; - }) - ).toEqual(["12", "14"]); - }); - - test("should revert a CSS custom property back to a previous value when the Design Token value is reverted", async () => { - expect( - await page.evaluate(async () => { - const results = []; - const token = DesignToken.create(uniqueTokenName()); - const target = addElement(); - - token.setValueFor(target, 12); - await Updates.next(); - results.push( - window - .getComputedStyle(target) - .getPropertyValue(token.cssCustomProperty) - ); - - token.setValueFor(target, 14); - await Updates.next(); - results.push( - window - .getComputedStyle(target) - .getPropertyValue(token.cssCustomProperty) - ); - - token.setValueFor(target, 12); - await Updates.next(); - results.push( - window - .getComputedStyle(target) - .getPropertyValue(token.cssCustomProperty) - ); - - return results; - }) - ).toEqual(["12", "14", "12"]); - }); - }); - - test.describe("that is not a CSSDesignToken", () => { - test("should not emit a CSS custom property", async () => { - expect( - await page.evaluate(() => { - const target = addElement(); - const token = DesignToken.create({ - name: uniqueTokenName(), - }); - - token.setValueFor(target, () => 12); - - return window - .getComputedStyle(target) - .getPropertyValue(`--${token.name}`); - }) - ).toBe(""); - }); - }); - - test("should support getting and setting falsey values", async () => { - expect( - await page.evaluate(() => { - const target = addElement(); - return [false, null, 0, "", NaN] - .map(value => { - const token = DesignToken.create( - uniqueTokenName() - ); - token.setValueFor(target, () => value as any); - - if (typeof value === "number" && isNaN(value)) { - return ( - isNaN(token.getValueFor(target) as number) === true - ); - } else { - return token.getValueFor(target) === value; - } - }) - .every(x => x === true); - }) - ).toBe(true); - }); - }); - - test.describe("getting and setting a token value", () => { - test("should retrieve the value of the token it was set to", async () => { - expect( - await page.evaluate(() => { - const tokenA = DesignToken.create(uniqueTokenName()); - const tokenB = DesignToken.create(uniqueTokenName()); - const target = addElement(); - - tokenA.setValueFor(target, 12); - tokenB.setValueFor(target, tokenA); - - return tokenB.getValueFor(target); - }) - ).toBe(12); - }); - - test("should update the value of the token it was set to when the token's value changes", async () => { - expect( - await page.evaluate(async () => { - const results = []; - const tokenA = DesignToken.create(uniqueTokenName()); - const tokenB = DesignToken.create(uniqueTokenName()); - const target = addElement(); - - tokenA.setValueFor(target, 12); - tokenB.setValueFor(target, tokenA); - - results.push(tokenB.getValueFor(target)); - - tokenA.setValueFor(target, 14); - - results.push(tokenB.getValueFor(target)); - return results; - }) - ).toEqual([12, 14]); - }); - test("should update the derived value of the token when a dependency of the derived value changes", async () => { - expect( - await page.evaluate(async () => { - const results = []; - const tokenA = DesignToken.create(uniqueTokenName()); - const tokenB = DesignToken.create(uniqueTokenName()); - const tokenC = DesignToken.create(uniqueTokenName()); - const target = addElement(); - - tokenA.setValueFor(target, 6); - tokenB.setValueFor(target, resolve => resolve(tokenA) * 2); - tokenC.setValueFor(target, tokenB); - - results.push(tokenC.getValueFor(target)); - - tokenA.setValueFor(target, 7); - - results.push(tokenC.getValueFor(target)); - - return results; - }) - ).toEqual([12, 14]); - }); - - test.describe("that is a CSSDesignToken", () => { - test("should emit a CSS custom property", async () => { - expect( - await page.evaluate(async () => { - const tokenA = DesignToken.create("token-a"); - const tokenB = DesignToken.create("token-b"); - const target = addElement(); - - tokenA.setValueFor(target, 12); - tokenB.setValueFor(target, tokenA); - - await Updates.next(); - return window - .getComputedStyle(target) - .getPropertyValue(tokenB.cssCustomProperty); - }) - ); - }); - test("should update the emitted CSS custom property when the token's value changes", async () => { - expect( - await page.evaluate(async () => { - const results = []; - const tokenA = DesignToken.create(uniqueTokenName()); - const tokenB = DesignToken.create(uniqueTokenName()); - const target = addElement(); - - tokenA.setValueFor(target, 12); - tokenB.setValueFor(target, tokenA); - - await Updates.next(); - results.push( - window - .getComputedStyle(target) - .getPropertyValue(tokenB.cssCustomProperty) - ); - - tokenA.setValueFor(target, 14); - - await Updates.next(); - - results.push( - window - .getComputedStyle(target) - .getPropertyValue(tokenB.cssCustomProperty) - ); - - return results; - }) - ).toEqual(["12", "14"]); - }); - /* eslint-disable-next-line max-len */ - test("should update the emitted CSS custom property of a token assigned a derived value when the token dependency changes", async () => { - expect( - await page.evaluate(async () => { - const results = []; - const tokenA = DesignToken.create(uniqueTokenName()); - const tokenB = DesignToken.create(uniqueTokenName()); - const tokenC = DesignToken.create(uniqueTokenName()); - const target = addElement(); - - tokenA.setValueFor(target, 6); - tokenB.setValueFor(target, resolve => resolve(tokenA) * 2); - tokenC.setValueFor(target, tokenB); - - await Updates.next(); - results.push( - window - .getComputedStyle(target) - .getPropertyValue(tokenC.cssCustomProperty) - ); - - tokenA.setValueFor(target, 7); - - await Updates.next(); - results.push( - window - .getComputedStyle(target) - .getPropertyValue(tokenC.cssCustomProperty) - ); - - return results; - }) - ).toEqual(["12", "14"]); - }); - - test("should support accessing the token being assigned from the derived value, resolving to a parent value", async () => { - expect( - await page.evaluate(async () => { - const results = []; - const tokenA = DesignToken.create(uniqueTokenName()); - const parent = addElement(); - const child = addElement(parent); - const recipe = (resolve: DesignTokenResolver) => - resolve(tokenA) * 2; - tokenA.setValueFor(parent, 12); - tokenA.setValueFor(child, recipe); - - results.push(tokenA.getValueFor(parent)); - results.push(tokenA.getValueFor(child)); - - return results; - }) - ).toEqual([12, 24]); - }); - }); - /* eslint-disable-next-line max-len */ - test("should update the CSS custom property of a derived token with a dependency that is a derived token that depends on a third token", async () => { - expect( - await page.evaluate(async () => { - const results = []; - const tokenA = DesignToken.create(uniqueTokenName()); - const tokenB = DesignToken.create(uniqueTokenName()); - const tokenC = DesignToken.create(uniqueTokenName()); - const grandparent = addElement(); - const parent = addElement(grandparent); - const child = addElement(parent); - - tokenA.setValueFor(grandparent, 3); - tokenB.setValueFor(grandparent, resolve => resolve(tokenA) * 2); - tokenC.setValueFor(grandparent, resolve => resolve(tokenB) * 2); - - await Updates.next(); - - results.push(tokenC.getValueFor(child)); - results.push( - window - .getComputedStyle(child) - .getPropertyValue(tokenC.cssCustomProperty) - ); - - tokenA.setValueFor(child, 4); - - await Updates.next(); - results.push(tokenC.getValueFor(child)); - results.push( - window - .getComputedStyle(child) - .getPropertyValue(tokenC.cssCustomProperty) - ); - - return results; - }) - ).toEqual([12, "12", 16, "16"]); - }); - }); - test.describe("deleting simple values", () => { - test("should throw when deleted and no parent token value is set", async () => { - expect( - await page.evaluate(() => { - const results = []; - const target = addElement(); - const token = DesignToken.create(uniqueTokenName()); - - token.setValueFor(target, 12); - - results.push(token.getValueFor(target)); - - token.deleteValueFor(target); - - results.push(threw(() => token.getValueFor(target))); - return results; - }) - ).toEqual([12, true]); - }); - test("should allow getting a value that was set upstream", async () => { - expect( - await page.evaluate(() => { - const results = []; - const parent = addElement(); - const target = addElement(parent); - const token = DesignToken.create(uniqueTokenName()); - - token.setValueFor(parent, 12); - token.setValueFor(target, 14); - - results.push(token.getValueFor(target)); - - token.deleteValueFor(target); - - results.push(token.getValueFor(target)); - return results; - }) - ).toEqual([14, 12]); - }); - }); - test.describe("deleting derived values", () => { - test("should throw when deleted and no parent token value is set", async () => { - expect( - await page.evaluate(() => { - const results = []; - const target = addElement(); - const token = DesignToken.create(uniqueTokenName()); - - token.setValueFor(target, () => 12); - - results.push(token.getValueFor(target)); - - token.deleteValueFor(target); - - results.push(threw(() => token.getValueFor(target))); - return results; - }) - ).toEqual([12, true]); - }); - test("should allow getting a value that was set upstream", async () => { - expect( - await page.evaluate(() => { - const results = []; - const parent = addElement(); - const target = addElement(parent); - const token = DesignToken.create(uniqueTokenName()); - - token.setValueFor(parent, () => 12); - token.setValueFor(target, () => 14); - - results.push(token.getValueFor(target)); - - token.deleteValueFor(target); - - results.push(token.getValueFor(target)); - return results; - }) - ).toEqual([14, 12]); - }); - - test("should cause dependent tokens to re-evaluate", async () => { - expect( - await page.evaluate(() => { - const results = []; - const tokenA = DesignToken.create(uniqueTokenName()); - const tokenB = DesignToken.create(uniqueTokenName()); - const parent = addElement(); - const target = addElement(parent); - - tokenA.setValueFor(parent, 7); - tokenA.setValueFor(target, 6); - tokenB.setValueFor(target, resolve => resolve(tokenA) * 2); - - results.push(tokenB.getValueFor(target)); - - tokenA.deleteValueFor(target); - - results.push(tokenB.getValueFor(target)); - return results; - }) - ).toEqual([12, 14]); - }); - }); - test.describe("when used as a CSSDirective", () => { - test("should set a CSS custom property for the element when the token is set for the element", async () => { - expect( - await page.evaluate(async () => { - const target = addElement(); - const token = DesignToken.create(uniqueTokenName()); - token.setValueFor(target, 12); - const styles = css` - :host { - width: calc(${token} * 1px); - } - `; - target.$fastController.addStyles(styles); - - await Updates.next(); - return window.getComputedStyle(target).getPropertyValue("width"); - }) - ).toBe("12px"); - }); - test("should set a CSS custom property for the element when the token is set for an ancestor element", async () => { - expect( - await page.evaluate(async () => { - const parent = addElement(); - const target = addElement(parent); - const token = DesignToken.create(uniqueTokenName()); - token.setValueFor(parent, 12); - const styles = css` - :host { - width: calc(${token} * 1px); - } - `; - target.$fastController.addStyles(styles); - - await Updates.next(); - return window.getComputedStyle(target).getPropertyValue("width"); - }) - ).toBe("12px"); - }); - }); - - test.describe("with a default value set", () => { - test("should return the default value if no value is set for a target", async () => { - expect( - await page.evaluate(() => { - const target = addElement(); - const token = DesignToken.create(uniqueTokenName()); - token.withDefault(2); - return token.getValueFor(target); - }) - ).toBe(2); - }); - test("should return the default value for a descendent if no value is set for a target", async () => { - expect( - await page.evaluate(() => { - const parent = addElement(); - const target = addElement(parent); - const token = DesignToken.create(uniqueTokenName()); - token.withDefault(2); - - return token.getValueFor(target); - }) - ).toBe(2); - }); - test("should return the value set and not the default if value is set", async () => { - expect( - await page.evaluate(() => { - const target = addElement(); - const token = DesignToken.create(uniqueTokenName()); - token.withDefault(4); - token.setValueFor(target, 2); - - return token.getValueFor(target); - }) - ).toBe(2); - }); - test("should get a new default value if a new default is provided", async () => { - expect( - await page.evaluate(() => { - const target = addElement(); - const token = DesignToken.create(uniqueTokenName()); - token.withDefault(2); - token.withDefault(4); - - return token.getValueFor(target); - }) - ).toBe(4); - }); - test("should return the default value if retrieved for an element that has not been connected", async () => { - expect( - await page.evaluate(() => { - const token = DesignToken.create( - uniqueTokenName() - ).withDefault(12); - const element = createElement(); - - return token.getValueFor(element); - }) - ).toBe(12); - }); - test("should set a derived value that uses a token's default value prior to connection", async () => { - expect( - await page.evaluate(() => { - const dependency = DesignToken.create( - uniqueTokenName() - ).withDefault(12); - const token = DesignToken.create(uniqueTokenName()); - const element = createElement(); - - return threw(() => - token.setValueFor(element, resolve => resolve(dependency) * 2) - ); - }) - ).toBe(false); - }); - test("should delete a derived value that uses a token's default value prior to connection", async () => { - expect( - await page.evaluate(() => { - const dependency = DesignToken.create( - uniqueTokenName() - ).withDefault(12); - const token = DesignToken.create(uniqueTokenName()); - const element = createElement(); - token.setValueFor(element, resolve => resolve(dependency) * 2); - - return threw(() => token.deleteValueFor(element)); - }) - ).toBe(false); - }); - }); - - test.describe("with subscribers", () => { - test("should notify an un-targeted subscriber when the value changes for any element", async () => { - expect( - await page.evaluate(() => { - const results: any = []; - const ancestor = addElement(); - const parent = addElement(ancestor); - const target = addElement(parent); - const token = DesignToken.create(uniqueTokenName()); - const spies = new Map([ - [ancestor, false], - [parent, false], - [target, false], - ]); - - const subscriber: DesignTokenSubscriber = { - handleChange(token, record) { - spies.set(record.target, true); - }, - }; - - token.subscribe(subscriber); - - function storeResults() { - results.push([ - spies.get(ancestor), - spies.get(parent), - spies.get(target), - ]); - } - - token.setValueFor(ancestor, 12); - storeResults(); - - token.setValueFor(parent, 14); - storeResults(); - - token.setValueFor(target, 16); - storeResults(); - return results; - }) - ).toEqual([ - [true, false, false], - [true, true, false], - [true, true, true], - ]); - }); - test("should notify a target-subscriber if the value is changed for the provided target", async () => { - expect( - await page.evaluate(() => { - const results = []; - const parent = addElement(); - const target = addElement(parent); - const token = DesignToken.create(uniqueTokenName()); - - const handleChange = spy(() => {}); - const subscriber: DesignTokenSubscriber = { - handleChange, - }; - - token.subscribe(subscriber); - - token.setValueFor(parent, 12); - results.push(handleChange.calls); - - token.setValueFor(target, 14); - results.push(handleChange.calls); - return results; - }) - ).toEqual([1, 2]); - }); - - test("should not notify a subscriber after unsubscribing", async () => { - expect( - await page.evaluate(() => { - const target = addElement(); - const token = DesignToken.create(uniqueTokenName()); - - const handleChange = spy(() => {}); - const subscriber: DesignTokenSubscriber = { - handleChange, - }; - - token.subscribe(subscriber); - token.unsubscribe(subscriber); - - token.setValueFor(target, 12); - return handleChange.calls; - }) - ).toBe(0); - }); - - test("should infer DesignToken and CSSDesignToken token types on subscription record", async () => { - await page.evaluate(() => { - type AssertCSSDesignToken = T extends CSSDesignTokenImpl - ? T - : never; - DesignToken.create("css").subscribe({ - handleChange(token, record) { - const test: AssertCSSDesignToken = - record.token; - }, - }); - - type AssertDesignToken = T extends CSSDesignTokenImpl ? never : T; - - DesignToken.create({ name: "no-css" }).subscribe({ - handleChange(token, record) { - const test: AssertDesignToken = record.token; - }, - }); - }); - }); - - test("should notify a subscriber when a dependency of a subscribed token changes", async () => { - expect( - await page.evaluate(async () => { - const tokenA = DesignToken.create(uniqueTokenName()); - const tokenB = DesignToken.create(uniqueTokenName()); - - tokenA.withDefault(6); - tokenB.withDefault(resolve => resolve(tokenA) * 2); - - const handleChange = spy(() => {}); - const subscriber = { - handleChange, - }; - - tokenB.subscribe(subscriber); - - tokenA.withDefault(7); - await Updates.next(); - return handleChange.calls; - }) - ).toBe(1); - }); - - test("should notify a subscriber when a dependency of a dependency of a subscribed token changes", async () => { - expect( - await page.evaluate(async () => { - const tokenA = DesignToken.create(uniqueTokenName()); - const tokenB = DesignToken.create(uniqueTokenName()); - const tokenC = DesignToken.create(uniqueTokenName()); - - tokenA.withDefault(6); - tokenB.withDefault(resolve => resolve(tokenA) * 2); - tokenC.withDefault(resolve => resolve(tokenB) * 2); - - const handleChange = spy(() => {}); - const subscriber = { - handleChange, - }; - - tokenC.subscribe(subscriber); - - tokenA.withDefault(7); - await Updates.next(); - return handleChange.calls; - }) - ).toBe(1); - }); - - test("should notify a subscriber when a dependency changes for an element down the DOM tree", async () => { - expect( - await page.evaluate(async () => { - const tokenA = DesignToken.create(uniqueTokenName()); - const tokenB = DesignToken.create(uniqueTokenName()); - - const target = addElement(); - - tokenA.withDefault(6); - tokenB.withDefault(resolve => resolve(tokenA) * 2); - - const handleChange = spy(() => {}); - const subscriber = { - handleChange, - }; - - tokenB.subscribe(subscriber); - - tokenA.setValueFor(target, 7); - await Updates.next(); - return handleChange.calls; - }) - ).toBe(1); - }); - /* eslint-disable-next-line max-len */ - test("should notify a subscriber when a static-value dependency of subscribed token changes for a parent of the subscription target", async () => { - expect( - await page.evaluate(async () => { - const results = []; - const tokenA = DesignToken.create(uniqueTokenName()); - const tokenB = DesignToken.create(uniqueTokenName()); - - const parent = addElement(); - const target = addElement(parent); - - tokenA.withDefault(6); - tokenB.withDefault(resolve => resolve(tokenA) * 2); - - const handleChange = spy(() => {}); - const subscriber = { - handleChange, - }; - - tokenB.subscribe(subscriber /*target*/); - - tokenA.setValueFor(parent, 7); - await Updates.next(); - results.push(handleChange.calls); - results.push(tokenB.getValueFor(target)); - - return results; - }) - ).toEqual([1, 14]); - }); - /* eslint-disable-next-line max-len */ - test("should notify a subscriber when a derived-value dependency of subscribed token changes for a parent of the subscription target", async () => { - expect( - await page.evaluate(async () => { - const results = []; - const tokenA = DesignToken.create(uniqueTokenName()); - const tokenB = DesignToken.create(uniqueTokenName()); - - const parent = addElement(); - const target = addElement(parent); - - tokenA.withDefault(() => 6); - tokenB.withDefault(resolve => resolve(tokenA) * 2); - - const handleChange = spy(() => {}); - const subscriber = { - handleChange, - }; - - tokenB.subscribe(subscriber /*target*/); - - tokenA.setValueFor(parent, () => 7); - await Updates.next(); - results.push(handleChange.calls); - results.push(tokenB.getValueFor(target)); - return results; - }) - ).toEqual([1, 14]); - }); - /* eslint-disable-next-line max-len */ - test("should notify a subscriber when a dependency of subscribed token changes for a parent of the subscription target", async () => { - expect( - await page.evaluate(async () => { - const tokenA = DesignToken.create(uniqueTokenName()); - const tokenB = DesignToken.create(uniqueTokenName()); - - const grandparent = addElement(); - const parent = addElement(grandparent); - const child = addElement(parent); - - tokenA.withDefault(() => 6); - tokenB.withDefault(resolve => resolve(tokenA) * 2); - - const handleChange = spy(() => {}); - const subscriber = { - handleChange, - }; - - tokenB.subscribe(subscriber /*child*/); - - tokenA.setValueFor(grandparent, () => 7); - await Updates.next(); - return handleChange.calls; - }) - ).toBe(1); - }); - }); - - test.describe("with root registration", () => { - test("should not emit CSS custom properties for the default value if a root is not registered", async () => { - expect( - await page.evaluate(() => { - DesignToken.unregisterDefaultStyleTarget(); - const token = DesignToken.create( - uniqueTokenName() - ).withDefault(12); - const styles = window.getComputedStyle(document.body); - - return styles.getPropertyValue(token.cssCustomProperty); - }) - ); - }); - - test("should emit CSS custom properties for the default value when a design token root is registered", async () => { - expect( - await page.evaluate(async () => { - const token = DesignToken.create( - uniqueTokenName() - ).withDefault(12); - const styles = window.getComputedStyle(document.body); - - DesignToken.registerDefaultStyleTarget(); - - await Updates.next(); - - return styles.getPropertyValue(token.cssCustomProperty); - }) - ).toBe("12"); - }); - - test("should remove emitted CSS custom properties for a root when the root is deregistered", async () => { - expect( - await page.evaluate(async () => { - const results = []; - const token = DesignToken.create( - uniqueTokenName() - ).withDefault(12); - const styles = window.getComputedStyle(document.body); - - DesignToken.registerDefaultStyleTarget(); - - await Updates.next(); - - results.push(styles.getPropertyValue(token.cssCustomProperty)); - DesignToken.unregisterDefaultStyleTarget(); - - await Updates.next(); - - results.push(styles.getPropertyValue(token.cssCustomProperty)); - return results; - }) - ).toEqual(["12", ""]); - }); - - test("should emit CSS custom properties to an element when the element is provided as a root", async () => { - expect( - await page.evaluate(async () => { - const token = DesignToken.create( - uniqueTokenName() - ).withDefault(12); - const element = addElement(); - - DesignToken.registerDefaultStyleTarget(element); - - await Updates.next(); - const styles = window.getComputedStyle(element); - - return styles.getPropertyValue(token.cssCustomProperty); - }) - ).toBe("12"); - }); - test("should emit CSS custom properties to multiple roots", async () => { - expect( - await page.evaluate(async () => { - const results = [] as any; - DesignToken.unregisterDefaultStyleTarget(); - const token = DesignToken.create( - "default-with-multiple-roots" - ).withDefault(12); - const a = addElement(); - const b = addElement(); - - DesignToken.registerDefaultStyleTarget(a); - await Updates.next(); - - function storeResults() { - results.push([ - window - .getComputedStyle(a) - .getPropertyValue(token.cssCustomProperty), - window - .getComputedStyle(b) - .getPropertyValue(token.cssCustomProperty), - window - .getComputedStyle(document.body) - .getPropertyValue(token.cssCustomProperty), - ]); - } - - storeResults(); - - DesignToken.registerDefaultStyleTarget(b); - await Updates.next(); - storeResults(); - - DesignToken.registerDefaultStyleTarget(); - await Updates.next(); - storeResults(); - - return results; - }) - ).toEqual([ - ["12", "", ""], - ["12", "12", ""], - ["12", "12", "12"], - ]); - }); - - // Flakey and seems to be corrupted by other tests. - test.fixme( - "should set properties for a PropertyTarget registered as the root", - async () => { - const results = await page.evaluate(async () => { - const results = []; - const token = DesignToken.create( - uniqueTokenName() - ).withDefault(12); - const root = { - setProperty: spy(() => {}), - removeProperty: spy(() => {}), - }; - - DesignToken.registerDefaultStyleTarget(root); - - // expect(root.setProperty).to.have.been.called.with(token.cssCustomProperty, 12) - results.push(root.setProperty.calledWith(1)); - - token.withDefault(14); - - // expect(root.setProperty).to.have.been.called.with(token.cssCustomProperty, 14) - results.push(root.setProperty.calledWith(2)); - DesignToken.unregisterDefaultStyleTarget(root); - - return results; - }); - - expect(results[0][1]).toEqual(12); - expect(results[1][1]).toEqual(14); - } - ); - }); -}); diff --git a/packages/web-components/fast-foundation/src/design-token/fast-design-token.ts b/packages/web-components/fast-foundation/src/design-token/fast-design-token.ts deleted file mode 100644 index 9f4c7c47e21..00000000000 --- a/packages/web-components/fast-foundation/src/design-token/fast-design-token.ts +++ /dev/null @@ -1,459 +0,0 @@ -import type { - CSSDirective, - HostBehavior, - HostController, - HTMLDirective, - Subscriber, -} from "@microsoft/fast-element"; -import { - cssDirective, - FASTElement, - htmlDirective, - Observable, - SubscriberSet, -} from "@microsoft/fast-element"; -import { composedContains, composedParent } from "@microsoft/fast-element/utilities.js"; -import type { - DesignTokenChangeRecord as CoreDesignTokenChangeRecord, - DerivedDesignTokenValue, - DesignTokenResolver, - DesignTokenValue, -} from "./core/design-token-node.js"; -import { DesignTokenMutationType, DesignTokenNode } from "./core/design-token-node.js"; -import type { PropertyTarget } from "./custom-property-manager.js"; -import { - PropertyTargetManager, - RootStyleSheetTarget, -} from "./custom-property-manager.js"; - -/** - * @public - */ -export interface DesignTokenChangeRecord> { - /** - * The element for which the value was changed - */ - target: FASTElement | "default"; - - /** - * The token that was changed - */ - token: T; -} - -/** - * A subscriber that should receive {@link DesignTokenChangeRecord | change records} when a token changes for a target - * @public - */ -export interface DesignTokenSubscriber> { - handleChange(token: T, record: DesignTokenChangeRecord): void; -} - -/** - * Describes a {@link DesignToken} configuration - * @public - */ -export interface DesignTokenConfiguration { - /** - * The name of the {@link DesignToken}. - */ - name: string; -} - -/** - * @public - */ -export interface CSSDesignTokenConfiguration extends DesignTokenConfiguration { - /** - * The name of the CSS custom property to associate to the {@link CSSDesignToken} - */ - cssCustomPropertyName: string; -} - -/** - * @public - */ -export class DesignToken { - /** - * The name of the {@link DesignToken} - */ - public name: string; - - /** - * The default value of the token (alias of {@link DesignToken.default}) - */ - public get $value() { - return this.default; - } - - /** - * The default value of the token, or undefined if it has not been set. - */ - public get default(): T | undefined { - return FASTDesignTokenNode.defaultNode.getTokenValue(this); - } - - private _subscribers: SubscriberSet | undefined; - private get subscribers() { - if (this._subscribers) { - return this._subscribers; - } - this._subscribers = new SubscriberSet(this); - return this._subscribers; - } - - constructor(configuration: DesignTokenConfiguration) { - this.name = configuration.name; - - Observable.getNotifier(this).subscribe(this.subscriberNotifier); - } - - private static isCSSDesignTokenConfiguration( - config: CSSDesignTokenConfiguration | DesignTokenConfiguration - ): config is CSSDesignTokenConfiguration { - return ( - typeof (config as CSSDesignTokenConfiguration).cssCustomPropertyName === - "string" - ); - } - - /** - * - * @param name - Factory function for creating a {@link DesignToken} or {@link CSSDesignToken} - */ - public static create(name: string): CSSDesignToken; - public static create(config: DesignTokenConfiguration): DesignToken; - public static create(config: CSSDesignTokenConfiguration): CSSDesignToken; - public static create(config: any): any { - if (typeof config === "string") { - return new CSSDesignToken({ name: config, cssCustomPropertyName: config }); - } else { - return DesignToken.isCSSDesignTokenConfiguration(config) - ? new CSSDesignToken(config) - : new DesignToken(config); - } - } - - /** - * Configures the strategy for resolving hierarchical relationships between FASTElement targets. - */ - public static withStrategy(strategy: DesignTokenResolutionStrategy): void { - FASTDesignTokenNode.withStrategy(strategy); - } - - /** - * Registers a target for emitting default style values. - * {@link CSSDesignToken | CSSDesignTokens} with default values assigned via - * {@link DesignToken.withDefault} will emit CSS custom properties to all - * registered targets. - * @param target - The target to register, defaults to the document - */ - public static registerDefaultStyleTarget( - target: FASTElement | Document | PropertyTarget = document - ) { - if (target instanceof FASTElement || target instanceof Document) { - target = PropertyTargetManager.getOrCreate(target); - } - - RootStyleSheetTarget.registerRoot(target); - } - - /** - * Unregister a target for default style emission. - * @param target - The root to deregister, defaults to the document - */ - public static unregisterDefaultStyleTarget( - target: FASTElement | Document | PropertyTarget = document - ) { - if (target instanceof FASTElement || target instanceof Document) { - target = PropertyTargetManager.getOrCreate(target); - } - - RootStyleSheetTarget.unregisterRoot(target); - } - - /** - * Retrieves the value of the token for a target element. - */ - public getValueFor(target: FASTElement): T { - return FASTDesignTokenNode.getOrCreate(target).getTokenValue(this); - } - - /** - * Sets the value of the token for a target element. - */ - public setValueFor( - target: FASTElement, - value: DesignToken | DesignTokenValue - ): void { - FASTDesignTokenNode.getOrCreate(target).setTokenValue( - this, - this.normalizeValue(value) - ); - } - - /** - * Deletes the value of the token for a target element. - */ - public deleteValueFor(target: FASTElement): this { - FASTDesignTokenNode.getOrCreate(target).deleteTokenValue(this); - return this; - } - - /** - * Sets the default value of the token. - */ - public withDefault(value: DesignToken | DesignTokenValue): this { - FASTDesignTokenNode.defaultNode.setTokenValue(this, this.normalizeValue(value)); - return this; - } - - /** - * Subscribes a subscriber to notifications for the token. - */ - public subscribe(subscriber: DesignTokenSubscriber): void { - this.subscribers.subscribe(subscriber); - } - - /** - * Unsubscribes a subscriber to notifications for the token. - */ - public unsubscribe(subscriber: DesignTokenSubscriber): void { - this.subscribers.unsubscribe(subscriber); - } - - /** - * Alias the token to the provided token. - * @param token - the token to alias to - */ - private alias(token: DesignToken): DerivedDesignTokenValue { - return ((resolve: DesignTokenResolver) => - resolve(token)) as DerivedDesignTokenValue; - } - - private normalizeValue(value: DesignToken | DesignTokenValue) { - if (value instanceof DesignToken) { - value = this.alias(value); - } - - return value as DesignTokenValue; - } - - private subscriberNotifier: Subscriber = { - handleChange: ( - source: DesignToken, - change: CoreDesignTokenChangeRecord - ) => { - const record: DesignTokenChangeRecord = { - target: - change.target === FASTDesignTokenNode.defaultNode - ? "default" - : (change.target as FASTDesignTokenNode).target, - token: this, - }; - this.subscribers.notify(record); - }, - }; -} - -/** - * @public - */ -@cssDirective() -@htmlDirective() -export class CSSDesignToken - extends DesignToken - implements CSSDirective, HTMLDirective -{ - /** - * The CSS Custom property name of the token. - */ - public readonly cssCustomProperty: string; - private cssVar: string; - - /** - * The DesignToken represented as a string that can be used in CSS. - */ - public createCSS(): string { - return this.cssVar; - } - - /** - * Creates HTML to be used within a template. - */ - public createHTML(): string { - return this.cssVar; - } - - private cssReflector: Subscriber = { - handleChange: ( - source: DesignToken, - record: CoreDesignTokenChangeRecord - ) => { - const target = - record.target === FASTDesignTokenNode.defaultNode - ? FASTDesignTokenNode.rootStyleSheetTarget - : record.target instanceof FASTDesignTokenNode - ? PropertyTargetManager.getOrCreate(record.target.target) - : null; - if (target) { - if (record.type === DesignTokenMutationType.delete) { - target.removeProperty(this.cssCustomProperty); - } else { - target.setProperty( - this.cssCustomProperty, - this.resolveCSSValue(record.target.getTokenValue(this)) as any - ); - } - } - }, - }; - - constructor(configuration: CSSDesignTokenConfiguration) { - super(configuration); - this.cssCustomProperty = `--${configuration.cssCustomPropertyName}`; - this.cssVar = `var(${this.cssCustomProperty})`; - Observable.getNotifier(this).subscribe(this.cssReflector); - } - - private resolveCSSValue(value: any) { - return value && typeof value.createCSS === "function" ? value.createCSS() : value; - } -} - -export interface DesignTokenResolutionStrategy extends HostBehavior { - /** - * Determines if a 'child' element is contained by a 'parent'. - * @param child - The child element - * @param parent - The parent element - */ - contains(parent: FASTElement, child: FASTElement): boolean; - - /** - * Finds the nearest FASTElement parent node - * @param element - The element to find the parent of - */ - parent(element: FASTElement): FASTElement | null; -} - -const defaultDesignTokenResolutionStrategy: DesignTokenResolutionStrategy = { - contains: composedContains, - parent(element: FASTElement): FASTElement | null { - let parent: HTMLElement | null = composedParent(element); - - while (parent !== null) { - if (parent instanceof FASTElement) { - return parent as FASTElement; - } - - parent = composedParent(parent); - } - - return null; - }, -}; - -class FASTDesignTokenNode extends DesignTokenNode implements HostBehavior { - private static _strategy: DesignTokenResolutionStrategy; - private static get strategy() { - if (this._strategy === undefined) { - FASTDesignTokenNode.withStrategy(defaultDesignTokenResolutionStrategy); - } - - return this._strategy; - } - public static defaultNode = new DesignTokenNode(); - public static rootStyleSheetTarget = new RootStyleSheetTarget(); - private static cache = new WeakMap(); - - public connectedCallback(controller: HostController) { - let parent = FASTDesignTokenNode.findParent(controller.source); - - if (parent === null) { - parent = FASTDesignTokenNode.defaultNode; - } - - if (parent !== this.parent) { - const reparent: Array = []; - for (const child of parent.children) { - if ( - child instanceof FASTDesignTokenNode && - FASTDesignTokenNode.strategy.contains(controller.source, child.target) - ) { - reparent.push(child); - } - } - - parent.appendChild(this); - - for (const child of reparent) { - this.appendChild(child); - } - } - } - - public disconnectedCallback(controller: HostController): void { - FASTDesignTokenNode.cache.delete(this.target); - this.dispose(); - } - - public static getOrCreate(target: FASTElement) { - let found = FASTDesignTokenNode.cache.get(target); - - if (found) { - return found; - } - - found = new FASTDesignTokenNode(target); - FASTDesignTokenNode.cache.set(target, found); - target.$fastController.addBehavior(FASTDesignTokenNode.strategy); - target.$fastController.addBehavior(found); - - return found; - } - - public static withStrategy(strategy: DesignTokenResolutionStrategy) { - this._strategy = strategy; - } - - private static findParent(target: FASTElement): DesignTokenNode | null { - let current = FASTDesignTokenNode.strategy.parent(target); - - while (current !== null) { - const node = FASTDesignTokenNode.cache.get(current as FASTElement); - if (node) { - return node; - } - - current = FASTDesignTokenNode.strategy.parent(current); - } - - return null; - } - - constructor(public readonly target: FASTElement) { - super(); - // By default, nodes are not attached to the defaultNode for performance - // reasons. However, that behavior can throw if retrieval for a node - // happens before the bind() method is called. To guard against that, - // lazily attach to the defaultNode when get/set/delete methods are called. - this.setTokenValue = this.lazyAttachToDefault(super.setTokenValue); - this.getTokenValue = this.lazyAttachToDefault(super.getTokenValue); - this.deleteTokenValue = this.lazyAttachToDefault(super.deleteTokenValue); - } - - /** - * Creates a function from a function that lazily attaches the node to the default node. - */ - private lazyAttachToDefault any>(fn: T): T { - const cb = ((...args: Parameters): ReturnType => { - if (this.parent === null) { - FASTDesignTokenNode.defaultNode.appendChild(this); - } - - return fn.apply(this, args); - }) as T; - - return cb; - } -} diff --git a/packages/web-components/fast-foundation/src/design-token/stories/design-token.stories.ts b/packages/web-components/fast-foundation/src/design-token/stories/design-token.stories.ts deleted file mode 100644 index 54000b962ae..00000000000 --- a/packages/web-components/fast-foundation/src/design-token/stories/design-token.stories.ts +++ /dev/null @@ -1,115 +0,0 @@ -import { css, FASTElement, html, Observable, Updates } from "@microsoft/fast-element"; -import { uniqueElementName } from "@microsoft/fast-element/testing.js"; -import type { Meta, Story } from "../../__test__/helpers.js"; -import { CSSDesignToken, DesignToken as FASTDesignToken } from "../fast-design-token.js"; - -export default { - title: "Debug/DesignToken", -} as Meta; - -export const DesignToken: Story = () => { - const controllerElementName = "fast-design-token-controller"; - const fixtureElementName = "fast-design-token-fixture"; - - // Define element that can have token mutated for it - (class extends FASTElement {}).define({ - name: fixtureElementName, - template: html` - - `, - }); - - const elementCache = new Set(); - // The objects required for unit-testing - // DesignToken. These get installed on the - // globalThis during story connection, and - // removed during disconnection - const requiredTestObject = { - DesignToken: FASTDesignToken, - CSSDesignToken, - uniqueTokenName() { - return uniqueElementName() + "token"; - }, - createElement(): FASTElement { - const element = document.createElement(fixtureElementName) as FASTElement; - elementCache.add(element); - return element; - }, - addElement(parent = document.body) { - const el = requiredTestObject.createElement(); - el.setAttribute("id", "id" + uniqueElementName()); - parent.appendChild(el); - return el; - }, - css, - threw(fn: () => void): boolean { - try { - fn(); - return false; - } catch (e) { - return true; - } - }, - spy(fn: () => any) { - let calls: number = 0; - const callArgs: any = []; - const f = (...args: any[]) => { - calls += 1; - callArgs[calls] = args; - }; - Object.defineProperties(f, { - calls: { - get() { - return calls; - }, - }, - calledWith: { - value: function (n: number): any { - return callArgs[n]; - }, - }, - }); - - return f; - }, - Updates, - Observable, - cleanup() { - elementCache.forEach(value => { - value.parentElement?.removeChild(value); - elementCache.delete(value); - }); - }, - }; - - (class extends FASTElement { - connectedCallback(): void { - super.connectedCallback(); - - // Set up global variables necessary to execute unit tests - Object.entries(requiredTestObject).forEach(([key, value]) => { - Object.defineProperty(globalThis, key, { value, configurable: true }); - }); - } - - disconnectedCallback(): void { - super.disconnectedCallback(); - - // Tear down global variables set up during connectedCallback - Object.keys(requiredTestObject).forEach(key => { - delete globalThis[key]; - }); - } - }).define({ - name: controllerElementName, - template: html` -

Nothing to see here, folks.

-

- This page is an entrypoint for DesignToken unit tests and should only be - used for programmatic purposes -

- `, - }); - - return document.createElement(controllerElementName); -}; diff --git a/packages/web-components/fast-foundation/src/dialog/README.md b/packages/web-components/fast-foundation/src/dialog/README.md deleted file mode 100644 index 5373ba3a734..00000000000 --- a/packages/web-components/fast-foundation/src/dialog/README.md +++ /dev/null @@ -1,122 +0,0 @@ ---- -id: dialog -title: fast-dialog -sidebar_label: dialog -custom_edit_url: https://github.com/microsoft/fast/edit/master/packages/web-components/fast-foundation/src/dialog/README.md -description: fast-dialog is a web component implementation of a dialog. ---- - -As defined by the [W3C](https://w3c.github.io/aria-practices/#dialog_modal): - -> A dialog is a window overlaid on either the primary window or another dialog window. Windows under a modal dialog are inert. That is, users cannot interact with content outside an active dialog window. Inert content outside an active dialog is typically visually obscured or dimmed so it is difficult to discern, and in some implementations, attempts to interact with the inert content cause the dialog to close. -> -> Like non-modal dialogs, modal dialogs contain their tab sequence. That is, Tab and Shift + Tab do not move focus outside the dialog. However, unlike most non-modal dialogs, modal dialogs do not provide means for moving keyboard focus outside the dialog window without closing the dialog. - -## Setup - -```ts -import { - provideFASTDesignSystem, - fastDialog -} from "@microsoft/fast-components"; - -provideFASTDesignSystem() - .register( - fastDialog() - ); -``` - -## Usage - -```html - -``` - -## Create your own design - -```ts -import { Dialog, dialogTemplate as template } from "@microsoft/fast-foundation"; -import { dialogStyles as styles } from "./my-dialog.styles"; - -export const myDialog = Dialog.compose({ - baseName: "dialog", - template, - styles, -}); -``` - -## API - - - -### class: `FASTDialog` - -#### Superclass - -| Name | Module | Package | -| ------------- | ------ | ----------------------- | -| `FASTElement` | | @microsoft/fast-element | - -#### Fields - -| Name | Privacy | Type | Default | Description | Inherited From | -| ----------------- | ------- | --------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- | -| `modal` | public | `boolean` | `false` | Indicates the element is modal. When modal, user mouse interaction will be limited to the contents of the element by a modal overlay. Clicks on the overlay will cause the dialog to emit a "dismiss" event. | | -| `hidden` | public | `boolean` | `false` | The hidden state of the element. | | -| `noFocusTrap` | public | `boolean` | `false` | Indicates that the dialog should not trap focus. | | -| `ariaDescribedby` | public | `string` | | The id of the element describing the dialog. | | -| `ariaLabelledby` | public | `string` | | The id of the element labeling the dialog. | | -| `ariaLabel` | public | `string` | | The label surfaced to assistive technologies. | | - -#### Methods - -| Name | Privacy | Description | Parameters | Return | Inherited From | -| ------ | ------- | ------------------------------ | ---------- | ------ | -------------- | -| `show` | public | The method to show the dialog. | | `void` | | -| `hide` | public | The method to hide the dialog. | | `void` | | - -#### Events - -| Name | Type | Description | Inherited From | -| -------- | ---- | --------------------------------------------------------------- | -------------- | -| `cancel` | | Fires a custom 'cancel' event when the modal overlay is clicked | | -| `close` | | Fires a custom 'close' event when the dialog is hidden | | - -#### Attributes - -| Name | Field | Inherited From | -| ------------------ | --------------- | -------------- | -| | modal | | -| | hidden | | -| `no-focus-trap` | noFocusTrap | | -| `aria-describedby` | ariaDescribedby | | -| `aria-labelledby` | ariaLabelledby | | -| `aria-label` | ariaLabel | | - -#### CSS Parts - -| Name | Description | -| -------------------- | --------------------------------------------------------------------------- | -| `positioning-region` | A wrapping element used to center the dialog and position the modal overlay | -| `overlay` | The modal dialog overlay | -| `control` | The dialog element | - -#### Slots - -| Name | Description | -| ---- | --------------------------------------- | -| | The default slot for the dialog content | - -
- - -## Additional resources - -* [Component explorer examples](https://explore.fast.design/components/fast-dialog) -* [Component technical specification](https://github.com/microsoft/fast/blob/master/packages/web-components/fast-foundation/src/dialog/dialog.spec.md) -* [W3C Component Aria Practices](https://w3c.github.io/aria-practices/#dialog_modal) -* [Open UI Analysis](https://open-ui.org/components/dialog.research) \ No newline at end of file diff --git a/packages/web-components/fast-foundation/src/dialog/dialog.pw.spec.ts b/packages/web-components/fast-foundation/src/dialog/dialog.pw.spec.ts deleted file mode 100644 index 6c601cdeb24..00000000000 --- a/packages/web-components/fast-foundation/src/dialog/dialog.pw.spec.ts +++ /dev/null @@ -1,245 +0,0 @@ -import { expect, test } from "@playwright/test"; -import type { Locator, Page } from "@playwright/test"; -import { fixtureURL } from "../__test__/helpers.js"; -import type { FASTDialog } from "./index.js"; - -test.describe("Dialog", () => { - let page: Page; - let element: Locator; - let root: Locator; - let control: Locator; - let overlay: Locator; - - test.beforeAll(async ({ browser }) => { - page = await browser.newPage(); - - element = page.locator("fast-dialog"); - - root = page.locator("#storybook-root"); - - control = element.locator(`[role="dialog"]`); - - overlay = element.locator(".overlay"); - - await page.goto(fixtureURL("dialog--dialog")); - - await element.waitFor({ state: "attached" }); - }); - - test.afterAll(async () => { - await page.close(); - }); - - test("should include a role of `dialog` on the control", async () => { - await expect(control).toHaveClass(/control/); - }); - - test('should set the `tabindex` attribute on the control to "-1" by default', async () => { - await expect(control).toHaveAttribute("tabindex", "-1"); - }); - - test("should set the `hidden` attribute to equal the value of the `hidden` property", async () => { - await element.evaluate((node: FASTDialog) => { - node.hidden = true; - }); - - await expect(element).toHaveAttribute("hidden"); - - await element.evaluate((node: FASTDialog) => { - node.hidden = false; - }); - - await expect(element).not.toHaveAttribute("hidden"); - }); - - test("should set the `aria-describedby` attribute on the control when provided", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - -
Description
-
- `; - }); - - await expect(control).toHaveAttribute("aria-describedby", "description"); - }); - - test("should set the `aria-labelledby` attribute on the dialog control when provided", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - -
Label
-
- `; - }); - - await expect(control).toHaveAttribute("aria-labelledby", "label"); - }); - - test("should set the `aria-label` attribute on the dialog control when provided", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(control).toHaveAttribute("aria-label", "Label"); - }); - - test("should add an attribute of `aria-modal` with a value equal to the `modal` attribute", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(control).toHaveAttribute("aria-modal", "true"); - - await element.evaluate((node: FASTDialog) => { - node.modal = false; - }); - - await expect(control).not.toHaveAttribute("aria-modal"); - }); - - test('should add an overlay element with a `role` attribute of "presentation" when the `modal` property is true', async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(overlay).toHaveAttribute("role", "presentation"); - - await element.evaluate((node: FASTDialog) => { - node.modal = false; - }); - - await expect(overlay).toHaveCount(0); - }); - - test("should add an attribute of `no-focus-trap` when `noFocusTrap` is true", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await element.evaluate((node: FASTDialog) => { - node.noFocusTrap = true; - }); - - await expect(element).toHaveAttribute("no-focus-trap"); - - await element.evaluate((node: FASTDialog) => { - node.noFocusTrap = false; - }); - - await expect(element).not.toHaveAttribute("no-focus-trap"); - }); - - test("should add the `hidden` attribute when the `hide()` method is invoked", async () => { - await element.evaluate((node: FASTDialog) => { - node.hidden = false; - }); - - await expect(element).toHaveJSProperty("hidden", false); - - await expect(element).not.toHaveAttribute("hidden"); - - await element.evaluate((node: FASTDialog) => { - node.hide(); - }); - - await expect(element).toHaveJSProperty("hidden", true); - }); - - test("should remove the `hidden` attribute when the `show()` method is invoked", async () => { - await element.evaluate((node: FASTDialog) => { - node.hidden = true; - }); - - await expect(element).toHaveJSProperty("hidden", true); - - await expect(element).toHaveAttribute("hidden"); - - await element.evaluate((node: FASTDialog) => { - node.show(); - }); - - await expect(element).toHaveJSProperty("hidden", false); - - await expect(element).not.toHaveAttribute("hidden"); - }); - - test("should fire a 'dismiss' event when its overlay is clicked", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await (await overlay.elementHandle())?.waitForElementState("stable"); - - const [wasDismissed] = await Promise.all([ - element.evaluate( - node => - new Promise(resolve => { - node.addEventListener("dismiss", () => resolve(true)); - }) - ), - // click the overlay in the top-left corner to avoid the dialog element - overlay.click({ position: { x: 0, y: 0 } }), - ]); - - expect(wasDismissed).toBeTruthy(); - }); - - test("should fire a `cancel` event when its overlay is clicked", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await (await overlay.elementHandle())?.waitForElementState("stable"); - - const [wasDismissed] = await Promise.all([ - element.evaluate( - node => - new Promise(resolve => { - node.addEventListener("cancel", () => resolve(true)); - }) - ), - // click the overlay in the top-left corner to avoid the dialog element - overlay.click({ position: { x: 0, y: 0 } }), - ]); - - expect(wasDismissed).toBeTruthy(); - }); - - test("should fire a 'dismiss' event when keydown is invoked on the document", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await (await overlay.elementHandle())?.waitForElementState("stable"); - - const [wasDismissed] = await Promise.all([ - element.evaluate( - node => - new Promise(resolve => { - node.addEventListener("dismiss", () => resolve(true)); - }) - ), - element - .elementHandle() - .then(handle => handle?.waitForElementState("stable")) - .then(() => page.keyboard.press("Escape")), - ]); - - expect(wasDismissed).toBeTruthy(); - }); -}); diff --git a/packages/web-components/fast-foundation/src/dialog/dialog.spec.md b/packages/web-components/fast-foundation/src/dialog/dialog.spec.md deleted file mode 100644 index 08ebc6f9db1..00000000000 --- a/packages/web-components/fast-foundation/src/dialog/dialog.spec.md +++ /dev/null @@ -1,137 +0,0 @@ -# Dialog - -## Overview - -As defined by the W3C: -> A dialog is a window overlaid on either the primary window or another dialog window. Windows under a modal dialog are inert. That is, users cannot interact with content outside an active dialog window. Inert content outside an active dialog is typically visually obscured or dimmed so it is difficult to discern, and in some implementations, attempts to interact with the inert content cause the dialog to close. -> -> Like non-modal dialogs, modal dialogs contain their tab sequence. That is, Tab and Shift + Tab do not move focus outside the dialog. However, unlike most non-modal dialogs, modal dialogs do not provide means for moving keyboard focus outside the dialog window without closing the dialog. - -### Use Cases - -- Joanna has some friends coming over and is searching online for some adult beverage ideas. She visits a website of a local distillery and a form overlays the screen asking her to confirm she is over 21 years of age by entering her birthday. - -- Harold is in the process of removing old data sets from his company's content management system. He selects a group of data and clicks delete. A popup appears asking him to confirm that he wants to delete the selected files permanently. - -- Meredith is browsing news articles online and clicks a link to a local newspaper story about an upcoming heat wave in the region. She is informed that she has read through an allotted number of free articles for the month and must either login or become a subscriber of the news site to continue. Meredith tries to continue interacting with the web page, but she's unable to. Meredith decides to subscribe to the online newspaper because they are running a special. - -### Features - -- **Soft dismiss (light dismiss):** In certain implementations, app authors want a dialog to close when a user clicks outside the content region or presses the `esc` key with their keyboard. - -- **Focus management:** In all circumstances, focus should move to an element contained in the dialog. Per the W3C, "Unless a condition where doing otherwise is advisable, focus is initially set on the *first* focusable element" (emphasis mine). If an element within the dialog is set to be focused by an app author, our control should not override that behavior. In both modal and non-modal dialogs, tab focus should remain within the dialog content region and not move outside it. When the dialog is closed, users may also want a way to return focus to the element which invoked the dialog. - -Web components complicate the dialog focus queue implementation as the typical methods of identifying tabbable elements (ie. using [tabbable](https://github.com/focus-trap/tabbable)) does not necessarily recognize custom elements. Authors may be able to work around this by assigning a tabindex of '0' to elements. The dialog should, however, be able to correctly identify Fast based web components without this. Additionally, tabbable elements within the shadow dom of a web component will not be recognized as being part of the dialog's tab queue. A workaround for this case could be for authors to ensure such components are not the first or last elements of a dialog internal tab queue. These issues are being actively investigated. - -### Prior Art/Examples -- [FAST Dialog (React)](https://www.npmjs.com/package/@microsoft/fast-components-react-msft) -- [Material UI](https://material-ui.com/components/dialogs/) -- [Lightning Design](https://www.lightningdesignsystem.com/components/modals/) -- [Carbon Design](https://www.carbondesignsystem.com/components/modal/code/) -- [Ant Design](https://ant.design/components/modal/) -- [Atlassian](https://atlaskit.atlassian.com/packages/core/modal-dialog) -- [Office Fabric](https://developer.microsoft.com/en-us/fabric#/controls/web/dialog) -- [Windows (UWP)](https://docs.microsoft.com/en-us/windows/uwp/design/controls-and-patterns/dialogs-and-flyouts/dialogs) - ---- - -## Design - -### API - -*Component name:* -- `fast-dialog` - -*Attributes:* -- `modal` - boolean value for modal functionality. Sets aria-modal to true (defaults to true). -- `hidden` - boolean value to toggle the visibility of the dialog (defaults to false). -- `aria-labelledby` - optional based on implementation** -- `aria-describedby` - optional based on implementation** -- `aria-label` - optional, based on implementation** - -** See the [W3C Specification](https://w3c.github.io/aria-practices/#dialog_roles_states_props) for requirements and details. - -*CSS custom properties:* -- width -- height - -*Slots:* -- default slot for content - -*Events* -- dismiss - event fired when a user presses escape or clicks outside the dialog content - -### Anatomy and Appearance -**Structure:** -``` -
-
-
- -
-
-``` - -**Appearance:** -| State | Image | -| ----- | ----- | -| default | ![](./images/dialog.png) | -| dark mode | ![](./images/dialog-dark.png) | - -Parts: -- root - the root of the dialog -- positioning-region - ensuring the dialog is centered correctly requires a certain structure. Centering with absolute positioning can cause blurry content within the dialog itself. After investigating several implementations, the best and most common way of ensuring the dialog can be centered is to include a div to position the actual dialog itself using something like flexbox or css-grid. This ensures that the blurry content issue does not happen and the dialog centers easily within the screen. -- modal-overlay - the modal overlay -- content-region - the region where content is actually rendered. This part is where the `role="dialog"` will actually exist - -Animation: -The current working model (assumption) is that animation will be taken up as part of the adaptive ui story in the design system at some point. This will provide configurability to users. From a dialog standpoint, I think we'll have a default animation baked in, though this would be configurable through the design system. - -If we compose our dialog with two sets of styles, one for the dialog itself and another for the animation, that would also provide an easy way for users to create a new instance: - -```js -@customElement({ - name: "my-dialog", - template, - styles: css`${dialogBaseStyles}${myAnimationStyles}` -}) -``` ---- - -## Implementation - -### States - -Hidden - The dialog is hidden. This state is managed solely by the app author via the hidden attribute. The default for this is `false`. - -### Accessibility - -The tree view should align to the interaction model provided by the W3C: https://w3c.github.io/aria-practices/#keyboard-interaction-7 - -### Globalization - -The component visuals should not change when in RTL scenarios as the component is centered visually on the screen and has no LTR/RTL specific visuals or positioning. - -### Test Plan - -While testing is still TBD for our web components, I would expect this to align with the testing strategy and not require any additional test support. - -### Caveat - -> Document elements display precedence is formed by the imaginary z-axis [stacking context](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context), commonly by order of which elements are rendered and special properties (e.g. _z-index_). - -Dialog component is a low level element, unaware of its document context, but in most cases required to overlay on top of all elements. - -A common practice used in apps / frameworks to promote a dialog component to top other elements z-axis, is to utilise a service that dynamically appends a dialog component to the **end of the body element**, when called for. - -This helps ensure elements don't render over top a dialog undesirebly. diff --git a/packages/web-components/fast-foundation/src/dialog/dialog.template.ts b/packages/web-components/fast-foundation/src/dialog/dialog.template.ts deleted file mode 100644 index 891435903bd..00000000000 --- a/packages/web-components/fast-foundation/src/dialog/dialog.template.ts +++ /dev/null @@ -1,38 +0,0 @@ -import type { ElementViewTemplate } from "@microsoft/fast-element"; -import { html, ref, when } from "@microsoft/fast-element"; -import type { FASTDialog } from "./dialog.js"; - -/** - * The template for the {@link @microsoft/fast-foundation#FASTDialog} component. - * @public - */ -export function dialogTemplate(): ElementViewTemplate { - return html` -
- ${when( - x => x.modal, - html` - - ` - )} - -
- `; -} diff --git a/packages/web-components/fast-foundation/src/dialog/dialog.ts b/packages/web-components/fast-foundation/src/dialog/dialog.ts deleted file mode 100644 index ba6d9c78388..00000000000 --- a/packages/web-components/fast-foundation/src/dialog/dialog.ts +++ /dev/null @@ -1,341 +0,0 @@ -import type { Notifier } from "@microsoft/fast-element"; -import { attr, FASTElement, Observable, Updates } from "@microsoft/fast-element"; -import { keyEscape, keyTab } from "@microsoft/fast-web-utilities"; -import { isTabbable } from "tabbable"; -import { getRootActiveElement } from "../utilities/index.js"; - -/** - * A Switch Custom HTML Element. - * Implements the {@link https://www.w3.org/TR/wai-aria-1.1/#dialog | ARIA dialog }. - * - * @slot - The default slot for the dialog content - * @csspart positioning-region - A wrapping element used to center the dialog and position the modal overlay - * @csspart overlay - The modal dialog overlay - * @csspart control - The dialog element - * @fires cancel - Fires a custom 'cancel' event when the modal overlay is clicked - * @fires close - Fires a custom 'close' event when the dialog is hidden - * - * @public - */ -export class FASTDialog extends FASTElement { - /** - * Indicates the element is modal. When modal, user mouse interaction will be limited to the contents of the element by a modal - * overlay. Clicks on the overlay will cause the dialog to emit a "dismiss" event. - * @public - * @defaultValue - false - * @remarks - * HTML Attribute: modal - */ - @attr({ mode: "boolean" }) - public modal: boolean = false; - - /** - * The hidden state of the element. - * - * @public - * @defaultValue - false - * @remarks - * HTML Attribute: hidden - */ - @attr({ mode: "boolean" }) - public hidden: boolean = false; - - /** - * Indicates that the dialog should not trap focus. - * - * @public - * @defaultValue - true - * @remarks - * HTML Attribute: no-focus-trap - */ - @attr({ attribute: "no-focus-trap", mode: "boolean" }) - public noFocusTrap: boolean = false; - private noFocusTrapChanged = (): void => { - if (this.$fastController.isConnected) { - this.updateTrapFocus(); - } - }; - - /** - * The id of the element describing the dialog. - * @public - * @remarks - * HTML Attribute: aria-describedby - */ - @attr({ attribute: "aria-describedby" }) - public ariaDescribedby: string; - - /** - * The id of the element labeling the dialog. - * @public - * @remarks - * HTML Attribute: aria-labelledby - */ - @attr({ attribute: "aria-labelledby" }) - public ariaLabelledby: string; - - /** - * The label surfaced to assistive technologies. - * - * @public - * @remarks - * HTML Attribute: aria-label - */ - @attr({ attribute: "aria-label" }) - public ariaLabel: string; - - /** - * @internal - */ - public dialog: HTMLDivElement; - - /** - * @internal - */ - private isTrappingFocus: boolean = false; - - /** - * @internal - */ - private notifier: Notifier; - - /** - * @internal - */ - public dismiss(): void { - this.$emit("dismiss"); - // implement `` interface - this.$emit("cancel"); - } - - /** - * The method to show the dialog. - * - * @public - */ - public show(): void { - this.hidden = false; - } - - /** - * The method to hide the dialog. - * - * @public - */ - public hide(): void { - this.hidden = true; - // implement `` interface - this.$emit("close"); - } - - /** - * @internal - */ - public connectedCallback(): void { - super.connectedCallback(); - - document.addEventListener("keydown", this.handleDocumentKeydown); - this.notifier = Observable.getNotifier(this); - this.notifier.subscribe(this, "hidden"); - this.updateTrapFocus(); - } - - /** - * @internal - */ - public disconnectedCallback(): void { - super.disconnectedCallback(); - - // remove keydown event listener - document.removeEventListener("keydown", this.handleDocumentKeydown); - - // if we are trapping focus remove the focusin listener - this.updateTrapFocus(false); - - this.notifier.unsubscribe(this, "hidden"); - } - - /** - * @internal - */ - public handleChange(source: any, propertyName: string) { - switch (propertyName) { - case "hidden": - this.updateTrapFocus(); - break; - default: - break; - } - } - - private handleDocumentKeydown = (e: KeyboardEvent): void => { - if (!e.defaultPrevented && !this.hidden) { - switch (e.key) { - case keyEscape: - this.dismiss(); - e.preventDefault(); - break; - - case keyTab: - this.handleTabKeyDown(e); - break; - } - } - }; - - private handleDocumentFocus = (e: Event): void => { - if (!e.defaultPrevented && this.shouldForceFocus(e.target as HTMLElement)) { - this.focusFirstElement(); - e.preventDefault(); - } - }; - - private handleTabKeyDown = (e: KeyboardEvent): void => { - if (this.noFocusTrap || this.hidden) { - return; - } - - const bounds: (HTMLElement | SVGElement)[] = this.getTabQueueBounds(); - - if (bounds.length === 0) { - return; - } - - if (bounds.length === 1) { - // keep focus on single element - bounds[0].focus(); - e.preventDefault(); - return; - } - - if (e.shiftKey && e.target === bounds[0]) { - bounds[bounds.length - 1].focus(); - e.preventDefault(); - } else if (!e.shiftKey && e.target === bounds[bounds.length - 1]) { - bounds[0].focus(); - e.preventDefault(); - } - - return; - }; - - private getTabQueueBounds = (): (HTMLElement | SVGElement)[] => { - const bounds: HTMLElement[] = []; - - return FASTDialog.reduceTabbableItems(bounds, this); - }; - - /** - * focus on first element of tab queue - */ - private focusFirstElement = (): void => { - const bounds: (HTMLElement | SVGElement)[] = this.getTabQueueBounds(); - - if (bounds.length > 0) { - bounds[0].focus(); - } else { - if (this.dialog instanceof HTMLElement) { - this.dialog.focus(); - } - } - }; - - /** - * we should only focus if focus has not already been brought to the dialog - */ - private shouldForceFocus = (currentFocusElement: Element | null): boolean => { - return this.isTrappingFocus && !this.contains(currentFocusElement); - }; - - /** - * we should we be active trapping focus - */ - private shouldTrapFocus = (): boolean => { - return !this.noFocusTrap && !this.hidden; - }; - - /** - * - * - * @internal - */ - private updateTrapFocus = (shouldTrapFocusOverride?: boolean): void => { - const shouldTrapFocus = - shouldTrapFocusOverride === undefined - ? this.shouldTrapFocus() - : shouldTrapFocusOverride; - - if (shouldTrapFocus && !this.isTrappingFocus) { - this.isTrappingFocus = true; - // Add an event listener for focusin events if we are trapping focus - document.addEventListener("focusin", this.handleDocumentFocus); - Updates.enqueue(() => { - if (this.shouldForceFocus(getRootActiveElement(this))) { - this.focusFirstElement(); - } - }); - } else if (!shouldTrapFocus && this.isTrappingFocus) { - this.isTrappingFocus = false; - // remove event listener if we are not trapping focus - document.removeEventListener("focusin", this.handleDocumentFocus); - } - }; - - /** - * Reduce a collection to only its focusable elements. - * - * @param elements - Collection of elements to reduce - * @param element - The current element - * - * @internal - */ - private static reduceTabbableItems( - elements: HTMLElement[], - element: FASTElement - ): HTMLElement[] { - if (element.getAttribute("tabindex") === "-1") { - return elements; - } - - if ( - isTabbable(element) || - (FASTDialog.isFocusableFastElement(element) && - FASTDialog.hasTabbableShadow(element)) - ) { - elements.push(element); - return elements; - } - - if (element.childElementCount) { - return elements.concat( - Array.from(element.children).reduce(FASTDialog.reduceTabbableItems, []) - ); - } - - return elements; - } - - /** - * Test if element is focusable fast element - * - * @param element - The element to check - * - * @internal - */ - private static isFocusableFastElement(element: FASTElement): boolean { - return !!element.$fastController?.definition.shadowOptions?.delegatesFocus; - } - - /** - * Test if the element has a focusable shadow - * - * @param element - The element to check - * - * @internal - */ - private static hasTabbableShadow(element: FASTElement) { - return Array.from(element.shadowRoot?.querySelectorAll("*") ?? []).some(x => { - return isTabbable(x); - }); - } -} diff --git a/packages/web-components/fast-foundation/src/dialog/images/dialog-dark.png b/packages/web-components/fast-foundation/src/dialog/images/dialog-dark.png deleted file mode 100644 index 97f405527a0727e3b7532df007120c6bf03eb7f4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 122102 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 diff --git a/packages/web-components/fast-foundation/src/dialog/images/dialog.png b/packages/web-components/fast-foundation/src/dialog/images/dialog.png deleted file mode 100644 index 3e45f797aa420edc7c997dc514266ac4ff7cda0d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 137536 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%0Ade$m~ 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 Da@9m} diff --git a/packages/web-components/fast-foundation/src/dialog/index.ts b/packages/web-components/fast-foundation/src/dialog/index.ts deleted file mode 100644 index 61130c8a85b..00000000000 --- a/packages/web-components/fast-foundation/src/dialog/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { dialogTemplate } from "./dialog.template.js"; -export { FASTDialog } from "./dialog.js"; diff --git a/packages/web-components/fast-foundation/src/dialog/stories/dialog.register.ts b/packages/web-components/fast-foundation/src/dialog/stories/dialog.register.ts deleted file mode 100644 index 0d036e37e66..00000000000 --- a/packages/web-components/fast-foundation/src/dialog/stories/dialog.register.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { css } from "@microsoft/fast-element"; -import { FASTDialog } from "../dialog.js"; -import { dialogTemplate } from "../dialog.template.js"; - -const styles = css` - :host([hidden]) { - display: none; - } - - :host { - --elevation: 14; - --dialog-height: 480px; - --dialog-width: 640px; - display: block; - } - - .overlay { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: rgba(0, 0, 0, 0.3); - touch-action: none; - } - - .positioning-region { - display: flex; - justify-content: center; - position: fixed; - top: 0; - bottom: 0; - left: 0; - right: 0; - overflow: auto; - } - - .control { - box-shadow: 0 0 calc((var(--elevation) * 0.225px) + 2px) - rgba(0, 0, 0, calc(0.11 * (2 - var(--background-luminance, 1)))), - 0 calc(var(--elevation) * 0.4px) calc((var(--elevation) * 0.9px)) - rgba(0, 0, 0, calc(0.13 * (2 - var(--background-luminance, 1)))); - margin-top: auto; - margin-bottom: auto; - width: var(--dialog-width); - height: var(--dialog-height); - background-color: var(--fill-color); - z-index: 1; - border-radius: calc(var(--control-corner-radius) * 1px); - border: calc(var(--stroke-width) * 1px) solid transparent; - } -`; - -FASTDialog.define({ - name: "fast-dialog", - template: dialogTemplate(), - styles, -}); diff --git a/packages/web-components/fast-foundation/src/dialog/stories/dialog.stories.ts b/packages/web-components/fast-foundation/src/dialog/stories/dialog.stories.ts deleted file mode 100644 index 50baa1d1749..00000000000 --- a/packages/web-components/fast-foundation/src/dialog/stories/dialog.stories.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { html, ref } from "@microsoft/fast-element"; -import type { Meta, Story, StoryArgs } from "../../__test__/helpers.js"; -import { renderComponent } from "../../__test__/helpers.js"; -import type { FASTDialog } from "../dialog.js"; - -const storyTemplate = html>` - - ${x => x.storyContent} - -`; - -export default { - title: "Dialog", - args: { - hidden: false, - modal: false, - noFocusTrap: false, - }, - argTypes: { - hidden: { control: "boolean" }, - modal: { control: "boolean" }, - noFocusTrap: { control: "boolean" }, - ariaDescribedby: { control: "text" }, - ariaLabel: { control: "text" }, - ariaLabelledby: { control: "text" }, - storyContent: { table: { disable: true } }, - }, - // docs are disabled since the modals would all load at once on the docs page - parameters: { docs: { disable: true } }, -} as Meta; - -export const Dialog: Story = renderComponent(storyTemplate).bind({}); -Dialog.args = { - storyContent: html` - Button A - - A checkbox - - One - Three - - `, -}; - -export const DialogModal: Story = Dialog.bind({}); -DialogModal.args = { - modal: true, - storyContent: "A modal dialog element", -}; - -export const DialogWithDismiss: Story = renderComponent( - html>` -
- - show dialog - - - ${x => x.storyContent} - -
- ` -).bind({}); -DialogWithDismiss.args = { - modal: true, - storyContent: html` -

press Escape or click the button below to close

- - dismiss dialog - - `, -}; diff --git a/packages/web-components/fast-foundation/src/directives/reflect-attributes.spec.ts b/packages/web-components/fast-foundation/src/directives/reflect-attributes.spec.ts deleted file mode 100644 index 5b74c1d3888..00000000000 --- a/packages/web-components/fast-foundation/src/directives/reflect-attributes.spec.ts +++ /dev/null @@ -1,122 +0,0 @@ -import { html, ref, customElement, FASTElement, Updates } from "@microsoft/fast-element"; -import { fixture, uniqueElementName } from "@microsoft/fast-element/testing.js"; -import { reflectAttributes } from "./reflect-attributes.js"; -import { expect } from "chai"; - -const template = html` -
-
-` -const name = uniqueElementName(); -@customElement({ - name, - template -}) -class AttributeReflectionTestElement extends FASTElement { - public a: HTMLElement; - public b: HTMLElement; -} - -describe("reflectAttributes", () => { - it("should reflect configured attributes that exist on the host after connection", async () => { - const { element, connect, disconnect } = await fixture(name); - - element.setAttribute("foo", "bar"); - await connect(); - - expect(element.a.getAttribute("foo")).to.equal("bar"); - await disconnect(); - }); - - it("should reflect a configured attribute when set on the host to the directive target", async () => { - const { element, connect, disconnect } = await fixture(name); - - await connect(); - element.setAttribute("foo", "bar"); - await Updates.next(); - - expect(element.a.getAttribute("foo")).to.equal("bar"); - await disconnect(); - }); - - it("should reflect a configured attribute when set on the host to all directive targets", async () => { - const { element, connect, disconnect } = await fixture(name); - - await connect(); - element.setAttribute("bar", "bat"); - await Updates.next(); - - expect(element.a.getAttribute("bar")).to.equal("bat"); - expect(element.b.getAttribute("bar")).to.equal("bat"); - - await disconnect(); - }); - - it("should remove a configured attribute from the directive target when it is removed from the host", async () => { - const { element, connect, disconnect } = await fixture(name); - - await connect(); - element.setAttribute("foo", "bar"); - await Updates.next(); - - element.removeAttribute("foo"); - await Updates.next(); - - expect(element.a.hasAttribute("foo")).to.equal(false); - - await disconnect(); - }); - - it("should remove a configured attribute from all directive targets when it is removed from the host", async () => { - const { element, connect, disconnect } = await fixture(name); - - await connect(); - element.setAttribute("bar", "bat"); - await Updates.next(); - - element.removeAttribute("bar"); - await Updates.next(); - - expect(element.a.hasAttribute("bar")).to.equal(false); - expect(element.b.hasAttribute("bar")).to.equal(false); - - await disconnect(); - }); - - it("should only reflect attributes in the directive configuration to the directive target", async () => { - const { element, connect, disconnect } = await fixture(name); - - await connect(); - element.setAttribute("foo", "bar"); - - await Updates.next(); - expect(element.b.hasAttribute("foo")).to.equal(false); - - await disconnect(); - }); - - it("should not reflect attributes thats are not in any directive configuration", async () => { - const { element, connect, disconnect } = await fixture(name); - - await connect(); - element.setAttribute("bee", "bar"); - await Updates.next(); - - expect(element.a.hasAttribute("bee")).to.equal(false); - expect(element.b.hasAttribute("bee")).to.equal(false); - - await disconnect(); - }); -}) diff --git a/packages/web-components/fast-foundation/src/directives/reflect-attributes.ts b/packages/web-components/fast-foundation/src/directives/reflect-attributes.ts deleted file mode 100644 index ce7da379235..00000000000 --- a/packages/web-components/fast-foundation/src/directives/reflect-attributes.ts +++ /dev/null @@ -1,147 +0,0 @@ -import type { CaptureType, Subscriber, ViewController } from "@microsoft/fast-element"; -import { - DOM, - HTMLDirective, - StatelessAttachedAttributeDirective, - SubscriberSet, -} from "@microsoft/fast-element"; - -const observer = new MutationObserver((mutations: MutationRecord[]) => { - for (const mutation of mutations) { - AttributeReflectionSubscriptionSet.getOrCreateFor( - mutation.target as HTMLElement - ).notify(mutation.attributeName); - } -}); - -class AttributeReflectionSubscriptionSet { - private static subscriberCache: WeakMap = - new WeakMap(); - - private watchedAttributes: Set> = new Set(); - private subscribers = new SubscriberSet(this); - - constructor(public element: HTMLElement) { - AttributeReflectionSubscriptionSet.subscriberCache.set(element, this); - } - - public notify(attr: string | null) { - this.subscribers.notify(attr); - } - - public subscribe(subscriber: Subscriber & ReflectAttributesDirective) { - this.subscribers.subscribe(subscriber); - - if (!this.watchedAttributes.has(subscriber.attributes)) { - this.watchedAttributes.add(subscriber.attributes); - this.observe(); - } - } - - public unsubscribe(subscriber: Subscriber & ReflectAttributesDirective) { - this.subscribers.unsubscribe(subscriber); - - if (this.watchedAttributes.has(subscriber.attributes)) { - this.watchedAttributes.delete(subscriber.attributes); - this.observe(); - } - } - - private observe() { - const attributeFilter: string[] = []; - - for (const attributes of this.watchedAttributes.values()) { - for (let i = 0; i < attributes.length; i++) { - attributeFilter.push(attributes[i]); - } - } - - observer.observe(this.element, { attributeFilter }); - } - - public static getOrCreateFor(source: HTMLElement) { - return ( - this.subscriberCache.get(source) || - new AttributeReflectionSubscriptionSet(source) - ); - } -} - -class ReflectAttributesDirective extends StatelessAttachedAttributeDirective { - /** - * The attributes the behavior is reflecting - */ - public attributes: Readonly; - - /** - * The unique id of the factory. - */ - id: string; - - /** - * The structural id of the DOM node to which the created behavior will apply. - */ - targetNodeId: string; - - constructor(attributes: string[]) { - super(attributes); - this.attributes = Object.freeze(attributes); - } - - public bind(controller: ViewController): void { - const source = controller.source; - const subscription = AttributeReflectionSubscriptionSet.getOrCreateFor(source); - subscription[this.id] = controller.targets[this.targetNodeId]; - subscription.subscribe(this); - - // Reflect any existing attributes because MutationObserver will only - // handle *changes* to attributes. - if (source.hasAttributes()) { - for (let i = 0; i < source.attributes.length; i++) { - this.handleChange(subscription, source.attributes[i].name); - } - } - } - - public unbind(controller: ViewController): void { - AttributeReflectionSubscriptionSet.getOrCreateFor(controller.source).unsubscribe( - this - ); - } - - public handleChange(source: AttributeReflectionSubscriptionSet, arg: string): void { - // In cases where two or more ReflectAttrBehavior instances are bound to the same element, - // they will share a Subscriber implementation. In that case, this handle change can be invoked with - // attributes an instances doesn't need to reflect. This guards against reflecting attrs - // that shouldn't be reflected. - if (this.attributes.includes(arg)) { - const element = source.element; - const target = source[this.id] as HTMLElement; - DOM.setAttribute(target, arg, element.getAttribute(arg)); - } - } -} - -HTMLDirective.define(ReflectAttributesDirective); - -/** - * Reflects attributes from the host element to the target element of the directive. - * @param attributes - The attributes to reflect - * - * @beta - * @example - * ```ts - * const template = html` - * ( - ...attributes: string[] -): CaptureType { - return new ReflectAttributesDirective(attributes); -} diff --git a/packages/web-components/fast-foundation/src/disclosure/README.md b/packages/web-components/fast-foundation/src/disclosure/README.md deleted file mode 100644 index 3d39f15a62c..00000000000 --- a/packages/web-components/fast-foundation/src/disclosure/README.md +++ /dev/null @@ -1,112 +0,0 @@ ---- -id: disclosure -title: fast-disclosure -sidebar_label: disclosure -custom_edit_url: https://github.com/microsoft/fast/edit/master/packages/web-components/fast-foundation/src/disclosure/README.md -description: fast-disclosure is a web component based on disclosure specification. ---- - -A disclosure component is the implementation of native `details` and `summary` controls that toggles the visibility of the extra content. Visually, it would look like a button or hyperlink and beneath extra content. As defined by the W3C: - -> A disclosure is a button that controls the visibility of a section of content. When the controlled content is hidden, it is often styled as a typical push button with a right-pointing arrow or triangle to hint that activating the button will display additional content. When the content is visible, the arrow or triangle typically points down. - -## Setup - -```ts -import { - provideFASTDesignSystem, - fastDisclosure -} from "@microsoft/fast-components"; - -provideFASTDesignSystem() - .register( - fastDisclosure() - ); -``` - -## Usage - -```html live - - Read about FAST -
- FAST is a collection of technologies built on Web Components and modern Web Standards, designed to help you efficiently tackle some of the most common challenges in website and application design and development. -
-
-``` - -## Create your own design - -```ts -import { - Disclosure, - disclosureTemplate as template, -} from "@microsoft/fast-foundation"; -import { disclosureStyles as styles } from "./my-disclosure.styles"; - -export const myDisclosure = Disclosure.compose({ - baseName: "disclosure", - template, - styles, -}); -``` - -## API - - - -### class: `FASTDisclosure` - -#### Superclass - -| Name | Module | Package | -| ------------- | ------ | ----------------------- | -| `FASTElement` | | @microsoft/fast-element | - -#### Fields - -| Name | Privacy | Type | Default | Description | Inherited From | -| ---------- | ------- | --------- | ------- | --------------------------------------------------------------- | -------------- | -| `expanded` | public | `boolean` | `false` | Determines if the element should show the extra content or not. | | -| `summary` | public | `string` | | Invoker title | | - -#### Methods - -| Name | Privacy | Description | Parameters | Return | Inherited From | -| ---------- | --------- | ------------------------------------------------- | ---------- | ------ | -------------- | -| `show` | public | Show extra content. | | `void` | | -| `hide` | public | Hide extra content. | | `void` | | -| `toggle` | public | Toggle the current(expanded/collapsed) state. | | `void` | | -| `setup` | protected | Register listener and set default disclosure mode | | `void` | | -| `onToggle` | protected | Update the aria attr and fire \`toggle\` event | | | | - -#### Events - -| Name | Type | Description | Inherited From | -| -------- | ---- | ------------------------------------------------ | -------------- | -| `toggle` | | fires a toggle event when the summary is toggled | | - -#### Attributes - -| Name | Field | Inherited From | -| --------- | -------- | -------------- | -| | expanded | | -| `summary` | summary | | - -#### Slots - -| Name | Description | -| ------- | -------------------------------------------------------- | -| `start` | Content which can be provided before the summary content | -| `end` | Content which can be provided after the summary content | -| `title` | The summary content | -| | The default slot for the disclosure content | - -
- - -## Additional resources - -* [Component explorer examples](https://explore.fast.design/components/fast-disclosure) -* [Component technical specification](https://github.com/microsoft/fast/blob/master/packages/web-components/fast-foundation/src/disclosure/disclosure.spec.md) -* [W3C Component Aria Practices](https://w3c.github.io/aria-practices/#disclosure) \ No newline at end of file diff --git a/packages/web-components/fast-foundation/src/disclosure/disclosure.pw.spec.ts b/packages/web-components/fast-foundation/src/disclosure/disclosure.pw.spec.ts deleted file mode 100644 index f8c517a9c39..00000000000 --- a/packages/web-components/fast-foundation/src/disclosure/disclosure.pw.spec.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { expect, test } from "@playwright/test"; -import type { Locator, Page } from "@playwright/test"; -import { fixtureURL } from "../__test__/helpers.js"; -import type { FASTDisclosure } from "./disclosure.js"; - -test.describe("Disclosure", () => { - test.describe("States, Attributes, and Properties", () => { - let page: Page; - let element: Locator; - let root: Locator; - let summary: Locator; - - test.beforeAll(async ({ browser }) => { - page = await browser.newPage(); - - element = page.locator("fast-disclosure"); - - root = page.locator("#storybook-root"); - - summary = element.locator("summary"); - - await page.goto(fixtureURL("disclosure--disclosure")); - - await root.waitFor({ state: "visible" }); - }); - - test.afterAll(async () => { - await page.close(); - }); - - test("should set the `aria-controls` attribute on the internal summary element", async () => { - await expect(summary).toHaveAttribute("aria-controls", "disclosure-content"); - }); - - test("should toggle the `expanded` attribute based on the value of the `expanded` property", async () => { - await expect(element).not.toHaveAttribute("expanded"); - - await element.evaluate((node: FASTDisclosure) => { - node.expanded = true; - }); - - await expect(element).toHaveAttribute("expanded"); - - await element.evaluate((node: FASTDisclosure) => { - node.expanded = false; - }); - - await expect(element).not.toHaveAttribute("expanded"); - }); - - test("should set summary slot content to the value of the summary attribute", async () => { - const summaryContent = - "Should set the summary slot content to the value of the summary attribute"; - - await element.evaluate((node: FASTDisclosure, summaryContent) => { - node.summary = summaryContent; - }, summaryContent); - - await expect(summary).toHaveText(summaryContent); - }); - - test("should toggle the content when the `toggle()` method is invoked", async () => { - await element.evaluate((node: FASTDisclosure) => { - node.toggle(); - }); - - await expect(element).toHaveJSProperty("expanded", true); - - await element.evaluate((node: FASTDisclosure) => { - node.toggle(); - }); - - await expect(element).toHaveJSProperty("expanded", false); - }); - - test("should expand and collapse the content when the `show()` and `hide()` methods are invoked", async () => { - await expect(element).toHaveJSProperty("expanded", false); - - await element.evaluate((node: FASTDisclosure) => { - node.show(); - }); - - await expect(element).toHaveJSProperty("expanded", true); - - await element.evaluate((node: FASTDisclosure) => { - node.hide(); - }); - - await expect(element).toHaveJSProperty("expanded", false); - }); - - test("should set the `aria-expanded` attribute on the internal summary element equal to the `expanded` property", async () => { - await expect(summary).toHaveAttribute("aria-expanded", "false"); - - await element.evaluate((node: FASTDisclosure) => { - node.expanded = true; - }); - - await expect(summary).toHaveAttribute("aria-expanded", "true"); - - await element.evaluate((node: FASTDisclosure) => { - node.expanded = false; - }); - - await expect(summary).toHaveAttribute("aria-expanded", "false"); - }); - }); -}); diff --git a/packages/web-components/fast-foundation/src/disclosure/disclosure.spec.md b/packages/web-components/fast-foundation/src/disclosure/disclosure.spec.md deleted file mode 100644 index 4f079987540..00000000000 --- a/packages/web-components/fast-foundation/src/disclosure/disclosure.spec.md +++ /dev/null @@ -1,110 +0,0 @@ -# Disclosure - -## Overview - -A disclosure component is the implementation of native `details` and `summary` control that toggles the visibility of the extra content. Visually, it would look like a button or hyperlink and beneath extra content. As defined by the W3C: - -> A disclosure is a button that controls the visibility of a section of content. When the controlled content is hidden, it is often styled as a typical push button with a right-pointing arrow or triangle to hint that activating the button will display additional content. When the content is visible, the arrow or triangle typically points down. - -### Use Cases - -- In general, reveal the extra information on button click when the end-user is needed to know/see. -- Laurel wanted to buy a new phone and she was looking at one of the websites where all the basic information was shown. She read about a camera feature called Night Mode and there was a section labeled "See the advanced technology that goes into every Night mode shot". She clicked on it and found out how that feature would work. With that extra information on that feature, she was quite confident in her buying. - -### Non-goals - -Many times disclosures may take different appearances, such as a button or anchor. Inclusion of such attributes should be applied at the design system / component implementation level. - -### Features - -- Enter and Space: activates the disclosure component and toggles the visibility of the disclosure content. -- Use `expanded` attribute or `toggle()` to render default expanded -- Observe the state when the disclosure is toggled -- `show()` and `hide()` as helper methods to toggle the content from outside - -### Prior Art/Examples - -- [Shopify Polaris](https://polaris.shopify.com/components/behavior/collapsible) -- [Lightning Design](https://www.lightningdesignsystem.com/components/expandable-section/) -- [Bootstrap](https://getbootstrap.com/docs/4.3/components/collapse/) -- [Material UI](https://material-ui.com/api/collapse/) - ---- - -## Design - -The disclosure component can easily be extended for customization, for example adding animation to reveal the content or get the height of extra content slot. - -- Basic component which toggles the extra content and to add animation extra styles that can be applied to derived/extended component. - -### API - -- _Component Name:_ `fast-disclosure` -- _Props/Attrs:_ - - `expanded: boolean` - Current state of the disclosure component - - `title: string` - invoker title (slot title is also available for custom template) -- _Methods_: - - `show()`: to show the content - - `hide()`: to hide the content - - `toggle()`: to toggle the content -- _Events_: - - `toggle: CustomEvent` - No custom data. - -### Anatomy and Appearance - -```html - -
- - - - - -
- -
-
-
-``` - -- _Slot Names_ - - start: add glyph for toggle state - - title: invoker title (could look like as a button or hyperlink) - - end: add glyph for toggle state - - default: extra content to be placed - ---- - -## Implementation - -```html - - More about Green Arrow -
- Green Arrow is a fictional superhero who appears in comic books published by DC - Comics. Created by Mort Weisinger and designed by George Papp, he first appeared - in More Fun Comics #73 in November 1941. His real name is Oliver Jonas Queen, a - wealthy businessman and owner of Queen Industries who is also a well-known - celebrity in Star City. -
-
-``` - -### States - -Disclosure has one state which indicates whether the component has revealed the extra content or not. It can be accessed by `expanded` property or can be updated by all available public methods (`show`, `hide`, `toggle`). - -### Accessibility - -- When the disclosure component has focus: - - Enter or Space: activates the disclosure control and toggles the visibility of the disclosure content. -- As per the WAI-ARIA spec by [W3C](https://www.w3.org/TR/wai-aria-practices-1.2/#wai-aria-roles-states-and-properties-8): - > The element that shows and hides the content has a role button. - > When the content is visible, the element with the role button has aria-expanded set to true. When the content area is hidden, it is set to false. - > Optionally, the element with the role button has a value specified for aria-controls that refers to the element that contains all the content that is shown or hidden. - ---- - -## Resources - -- [W3C Disclosure ARIA Practices](https://www.w3.org/TR/wai-aria-practices-1.2/#disclosure) diff --git a/packages/web-components/fast-foundation/src/disclosure/disclosure.template.ts b/packages/web-components/fast-foundation/src/disclosure/disclosure.template.ts deleted file mode 100644 index b16e6faee69..00000000000 --- a/packages/web-components/fast-foundation/src/disclosure/disclosure.template.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { ElementViewTemplate } from "@microsoft/fast-element"; -import { html, ref } from "@microsoft/fast-element"; -import { endSlotTemplate, startSlotTemplate } from "../patterns/start-end.js"; -import type { DisclosureOptions, FASTDisclosure } from "./disclosure.js"; - -/** - * The template for the {@link @microsoft/fast-foundation#(FASTDisclosure:class)} component. - * @public - */ -export function disclosureTemplate( - options: DisclosureOptions = {} -): ElementViewTemplate { - return html` -
- - ${startSlotTemplate(options)} - ${x => x.summary} - ${endSlotTemplate(options)} - -
-
- `; -} diff --git a/packages/web-components/fast-foundation/src/disclosure/disclosure.ts b/packages/web-components/fast-foundation/src/disclosure/disclosure.ts deleted file mode 100644 index 1b2a41d1496..00000000000 --- a/packages/web-components/fast-foundation/src/disclosure/disclosure.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { attr, FASTElement } from "@microsoft/fast-element"; -import { StartEnd } from "../patterns/start-end.js"; -import type { StartEndOptions } from "../patterns/start-end.js"; -import { applyMixins } from "../utilities/apply-mixins.js"; - -/** - * Disclosure configuration options - * @public - */ -export type DisclosureOptions = StartEndOptions; - -/** - * A Disclosure Custom HTML Element. - * Based largely on the {@link https://w3c.github.io/aria-practices/#disclosure | disclosure element }. - * - * @slot start - Content which can be provided before the summary content - * @slot end - Content which can be provided after the summary content - * @slot title - The summary content - * @slot - The default slot for the disclosure content - * @fires toggle - fires a toggle event when the summary is toggled - * - * @public - */ -export class FASTDisclosure extends FASTElement { - /** - * Determines if the element should show the extra content or not. - * - * @public - */ - @attr({ mode: "boolean" }) - public expanded: boolean = false; - - /** - * Invoker title - * - * @public - */ - @attr - public summary: string; - - /** - * @internal - */ - public details: HTMLDetailsElement; - - /** - * @internal - */ - public connectedCallback(): void { - super.connectedCallback(); - this.setup(); - } - - /** - * @internal - */ - public disconnectedCallback(): void { - super.disconnectedCallback(); - this.details.removeEventListener("toggle", this.onToggle); - } - - /** - * Show extra content. - */ - public show(): void { - this.details.open = true; - } - - /** - * Hide extra content. - */ - public hide(): void { - this.details.open = false; - } - - /** - * Toggle the current(expanded/collapsed) state. - */ - public toggle(): void { - this.details.open = !this.details.open; - } - - /** - * Register listener and set default disclosure mode - */ - protected setup(): void { - this.onToggle = this.onToggle.bind(this); - this.details.addEventListener("toggle", this.onToggle); - if (this.expanded) { - this.show(); - } - } - - /** - * Update the aria attr and fire `toggle` event - */ - protected onToggle() { - this.expanded = this.details.open; - this.$emit("toggle"); - } -} - -/** - * Mark internal because exporting class and interface of the same name - * confuses API documenter. - * TODO: https://github.com/microsoft/fast/issues/3317 - * @internal - */ -export interface FASTDisclosure extends StartEnd {} -applyMixins(FASTDisclosure, StartEnd); diff --git a/packages/web-components/fast-foundation/src/disclosure/index.ts b/packages/web-components/fast-foundation/src/disclosure/index.ts deleted file mode 100644 index 0caa6b003e6..00000000000 --- a/packages/web-components/fast-foundation/src/disclosure/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { FASTDisclosure } from "./disclosure.js"; -export type { DisclosureOptions } from "./disclosure.js"; -export { disclosureTemplate } from "./disclosure.template.js"; diff --git a/packages/web-components/fast-foundation/src/disclosure/stories/disclosure.register.ts b/packages/web-components/fast-foundation/src/disclosure/stories/disclosure.register.ts deleted file mode 100644 index b8e884ec2f1..00000000000 --- a/packages/web-components/fast-foundation/src/disclosure/stories/disclosure.register.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { css } from "@microsoft/fast-element"; -import { FASTDisclosure } from "../disclosure.js"; -import { disclosureTemplate } from "../disclosure.template.js"; - -const styles = css` - .disclosure { - transition: height 0.35s; - } - .invoker::-webkit-details-marker { - display: none; - } - .invoker { - list-style-type: none; - background: var(--accent-fill-rest); - color: var(--foreground-accent-rest); - fill: currentcolor; - font-family: var(--body-font); - font-size: var(--type-ramp-base-font-size); - border-radius: calc(var(--control-corner-radius) * 1px); - outline: none; - cursor: pointer; - margin: 16px 0; - padding: 12px; - max-width: max-content; - } - .invoker:focus-visible, - .invoker:active { - background: var(--accent-fill-active); - color: var(--foreground-accent-active); - } - .invoker:hover { - background: var(--accent-fill-hover); - color: var(--foreground-on-accent-hover); - } - .invoker { - display: flex; - align-items: center; - background: transparent; - color: var(--accent-foreground-rest); - cursor: pointer; - width: max-content; - margin: 16px 0; - } - - ::slotted([slot="start"]), - ::slotted([slot="end"]) { - display: flex; - } - - ::slotted([slot="start"]) { - margin-inline-end: 11px; - } - - ::slotted([slot="end"]) { - margin-inline-start: 11px; - } - - .disclosure[open] .invoker ~ * { - animation: fadeIn 0.5s ease-in-out; - } - - @keyframes fadeIn { - 0% { - opacity: 0; - } - 100% { - opacity: 1; - } - } -`; - -FASTDisclosure.define({ - name: "fast-disclosure", - shadowOptions: { - delegatesFocus: true, - }, - styles, - template: disclosureTemplate(), -}); diff --git a/packages/web-components/fast-foundation/src/disclosure/stories/disclosure.stories.ts b/packages/web-components/fast-foundation/src/disclosure/stories/disclosure.stories.ts deleted file mode 100644 index 6dbe9bdbb65..00000000000 --- a/packages/web-components/fast-foundation/src/disclosure/stories/disclosure.stories.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { html } from "@microsoft/fast-element"; -import type { Meta, Story, StoryArgs } from "../../__test__/helpers.js"; -import { renderComponent } from "../../__test__/helpers.js"; -import type { FASTDisclosure } from "../disclosure.js"; - -const storyTemplate = html>` - - ${x => x.storyContent} - -`; - -export default { - title: "Disclosure", - args: { - expanded: false, - }, - argTypes: { - expanded: { control: "boolean" }, - storyContent: { table: { disable: true } }, - summary: { control: "text" }, - }, -} as Meta; - -export const Disclosure: Story = renderComponent(storyTemplate).bind({}); -Disclosure.args = { - storyContent: html` - ⚡️ -
- Created by writer Gardner Fox and artist Harry Lampert, the original Flash - first appeared in Flash Comics #1 (cover date January 1940/release month - November 1939). Nicknamed the "Scarlet Speedster", all incarnations of the - Flash possess "super speed", which includes the ability to run, move, and - think extremely fast, use superhuman reflexes, and seemingly violate certain - laws of physics. -
- `, - summary: "More about Flash", -}; - -export const DisclosureWithSlottedStartEnd: Story = Disclosure.bind({}); -DisclosureWithSlottedStartEnd.args = { - storyContent: html` - - Disclosure content - - `, - summary: "Summary", -}; diff --git a/packages/web-components/fast-foundation/src/divider/README.md b/packages/web-components/fast-foundation/src/divider/README.md deleted file mode 100644 index 56ce97207a9..00000000000 --- a/packages/web-components/fast-foundation/src/divider/README.md +++ /dev/null @@ -1,87 +0,0 @@ ---- -id: divider -title: fast-divider -sidebar_label: divider -custom_edit_url: https://github.com/microsoft/fast/edit/master/packages/web-components/fast-foundation/src/divider/README.md -description: fast-divider is a web component implementation of a horizontal rule. ---- - -A web component implementation of a [horizontal rule](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/hr). - -## Setup - -```ts -import { - provideFASTDesignSystem, - fastDivider -} from "@microsoft/fast-components"; - -provideFASTDesignSystem() - .register( - fastDivider() - ); -``` - -## Usage - -```html live - -``` - -## Create your own design - -```ts -import { Divider, dividerTemplate as template } from "@microsoft/fast-foundation"; -import { dividerStyles as styles } from "./my-divider.styles"; - -export const myDivider = Divider.compose({ - baseName: "divider", - template, - styles, -}); -``` - -## API - - - -### Variables - -| Name | Description | Type | -| -------------------- | ------------------- | ----------------------------------------------------------- | -| `DividerRole` | Divider roles | `{ separator: "separator", presentation: "presentation", }` | -| `DividerOrientation` | Divider orientation | | - -
- - - -### class: `FASTDivider` - -#### Superclass - -| Name | Module | Package | -| ------------- | ------ | ----------------------- | -| `FASTElement` | | @microsoft/fast-element | - -#### Fields - -| Name | Privacy | Type | Default | Description | Inherited From | -| ------------- | ------- | -------------------- | ------- | ------------------------------- | -------------- | -| `role` | public | `DividerRole` | | The role of the element. | | -| `orientation` | public | `DividerOrientation` | | The orientation of the divider. | | - -#### Attributes - -| Name | Field | Inherited From | -| ------------- | ----------- | -------------- | -| `role` | role | | -| `orientation` | orientation | | - -
- - -## Additional resources - -* [Component explorer examples](https://explore.fast.design/components/fast-divider) -* [Component technical specification](https://github.com/microsoft/fast/blob/master/packages/web-components/fast-foundation/src/divider/divider.spec.md) \ No newline at end of file diff --git a/packages/web-components/fast-foundation/src/divider/divider.options.ts b/packages/web-components/fast-foundation/src/divider/divider.options.ts deleted file mode 100644 index efa862d7dcd..00000000000 --- a/packages/web-components/fast-foundation/src/divider/divider.options.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { Orientation } from "@microsoft/fast-web-utilities"; -import type { ValuesOf } from "../utilities/index.js"; - -/** - * Divider roles - * @public - */ -export const DividerRole = { - /** - * The divider semantically separates content - */ - separator: "separator", - - /** - * The divider has no semantic value and is for visual presentation only. - */ - presentation: "presentation", -} as const; - -/** - * The types for Divider roles - * @public - */ -export type DividerRole = ValuesOf; - -/** - * Divider orientation - * @public - */ -export const DividerOrientation = Orientation; - -/** - * The types for Divider orientation - * @public - */ -export type DividerOrientation = ValuesOf; diff --git a/packages/web-components/fast-foundation/src/divider/divider.pw.spec.ts b/packages/web-components/fast-foundation/src/divider/divider.pw.spec.ts deleted file mode 100644 index 594234e45d8..00000000000 --- a/packages/web-components/fast-foundation/src/divider/divider.pw.spec.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { expect, test } from "@playwright/test"; -import type { Locator, Page } from "@playwright/test"; -import { fixtureURL } from "../__test__/helpers.js"; -import { DividerOrientation, DividerRole } from "./divider.options.js"; -import type { FASTDivider } from "./index.js"; - -test.describe("Divider", () => { - let page: Page; - let element: Locator; - let root: Locator; - - test.beforeAll(async ({ browser }) => { - page = await browser.newPage(); - - element = page.locator("fast-divider"); - - root = page.locator("#storybook-root"); - - await page.goto(fixtureURL("divider--divider")); - - await element.waitFor({ state: "attached" }); - }); - - test.afterAll(async () => { - await page.close(); - }); - - test('should set a default `role` attribute of "separator"', async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element).toHaveAttribute("role", DividerRole.separator); - }); - - test("should set the `role` attribute equal to the role provided", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element).toHaveAttribute("role", "presentation"); - - await element.evaluate((node: FASTDivider, DividerRole) => { - node.role = DividerRole.separator; - }, DividerRole); - - await expect(element).toHaveAttribute("role", DividerRole.separator); - }); - - test("should set the `aria-orientation` attribute equal to the `orientation` value", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element).toHaveAttribute( - "aria-orientation", - DividerOrientation.vertical - ); - - await element.evaluate((node: FASTDivider, DividerOrientation) => { - node.orientation = DividerOrientation.horizontal; - }, DividerOrientation); - - await expect(element).toHaveAttribute( - "aria-orientation", - DividerOrientation.horizontal - ); - }); - - test("should NOT set the `aria-orientation` attribute equal to the `orientation` value if the `role` is presentational", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element).toHaveAttribute( - "aria-orientation", - DividerOrientation.vertical - ); - - await element.evaluate((node: FASTDivider, DividerRole) => { - node.role = DividerRole.presentation; - }, DividerRole); - - await expect(element).not.toHaveAttribute( - "aria-orientation", - DividerOrientation.horizontal - ); - await expect(element).not.toHaveAttribute( - "aria-orientation", - DividerOrientation.vertical - ); - }); -}); diff --git a/packages/web-components/fast-foundation/src/divider/divider.spec.md b/packages/web-components/fast-foundation/src/divider/divider.spec.md deleted file mode 100644 index 994809ef74e..00000000000 --- a/packages/web-components/fast-foundation/src/divider/divider.spec.md +++ /dev/null @@ -1,60 +0,0 @@ -# Divider - -## Overview - -An implementation of a horizontal rule as a web-component. - -It would be ideal to be able to use the [`is` global attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/is) here so that we are not recreating the native `hr` element, but that portion of the web component spec seems to be at risk with certain browser implementors, which means that by leveraging that convention the control would likely not work in certain browsers. With that in mind, it makes sense to move forward with the componentized model. In the event that the `is` convention moves forward, we should revisit this implementation to take advantage of that standard. - -### Use Cases - -Used anywhere a horizontal rule might be used. - -### Prior Art/Examples -- [FAST Divider (React)](https://www.npmjs.com/package/@microsoft/fast-components-react-msft) -- [Ant Design](https://ant.design/components/divider/) -- [Semantic UI](https://semantic-ui.com/elements/divider.html) -- [Fluent UI](https://fluentsite.z22.web.core.windows.net/components/divider/definition) - ---- - -### API -Extends FAST Element - -*Component name:* -- `fast-divider` - -*Attributes:* -- `role` - The permitted roles of the divider. Defaults to `separator`. -- `orientation` - Horizontal or vertical values allowed. Defaults to horizontal. - -### Anatomy and Appearance - -*Template:* -``` - -``` - -## Implementation - -```html - -``` -```html - -``` -```html - -``` - - -### Accessibility - -The divider should default to having a role of `separator`, just as a typical horizontal rule would. When changing the look, functional, interactive, or structural relevance implied by the `hr` element a role of `presentation` may be applied. Since the role of [separator](https://w3c.github.io/aria/#separator) conveys meaning to assistive technology, the visual representation should likewise convey the same meaning. With that in mind, the visual treatment of a horizontal rule with a role of `separator` should meet non-text contrast requirements. A role of `presentation` implies that the divider is a visual treatment only so the contrast requirement does not apply in that case. - - -## Next Steps -- Monitor the status of [`is` global attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/is) across browser implementors. In the case that this is implemented by all major browsers, we want to move to leveraging this convention for the divider component rather than recreating the `
`. \ No newline at end of file diff --git a/packages/web-components/fast-foundation/src/divider/divider.template.ts b/packages/web-components/fast-foundation/src/divider/divider.template.ts deleted file mode 100644 index f81faddf44d..00000000000 --- a/packages/web-components/fast-foundation/src/divider/divider.template.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { ElementViewTemplate } from "@microsoft/fast-element"; -import { html } from "@microsoft/fast-element"; -import type { FASTDivider } from "./divider.js"; -import { DividerRole } from "./divider.options.js"; - -/** - * The template for the {@link @microsoft/fast-foundation#FASTDivider} component. - * @public - */ -export function dividerTemplate(): ElementViewTemplate { - return html` - - `; -} diff --git a/packages/web-components/fast-foundation/src/divider/divider.ts b/packages/web-components/fast-foundation/src/divider/divider.ts deleted file mode 100644 index 470234a2b00..00000000000 --- a/packages/web-components/fast-foundation/src/divider/divider.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { attr, FASTElement } from "@microsoft/fast-element"; -import { DividerOrientation, DividerRole } from "./divider.options.js"; - -/** - * A Divider Custom HTML Element. - * Implements the {@link https://www.w3.org/TR/wai-aria-1.1/#separator | ARIA separator } - * or {@link https://www.w3.org/TR/wai-aria-1.1/#presentation | ARIA presentation}. - * - * @public - */ -export class FASTDivider extends FASTElement { - /** - * The role of the element. - * - * @public - * @remarks - * HTML Attribute: role - */ - @attr - public role: DividerRole = DividerRole.separator; - - /** - * The orientation of the divider. - * - * @public - * @remarks - * HTML Attribute: orientation - */ - @attr - public orientation: DividerOrientation = DividerOrientation.horizontal; -} diff --git a/packages/web-components/fast-foundation/src/divider/index.ts b/packages/web-components/fast-foundation/src/divider/index.ts deleted file mode 100644 index 8093d5239a1..00000000000 --- a/packages/web-components/fast-foundation/src/divider/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { DividerOrientation, DividerRole } from "./divider.options.js"; -export { dividerTemplate } from "./divider.template.js"; -export { FASTDivider } from "./divider.js"; diff --git a/packages/web-components/fast-foundation/src/divider/stories/divider.register.ts b/packages/web-components/fast-foundation/src/divider/stories/divider.register.ts deleted file mode 100644 index 612197b89cf..00000000000 --- a/packages/web-components/fast-foundation/src/divider/stories/divider.register.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { css } from "@microsoft/fast-element"; -import { FASTDivider } from "../divider.js"; -import { dividerTemplate } from "../divider.template.js"; - -const styles = css` - :host { - border-left: none; - border-top: calc(var(--stroke-width) * 1px) solid - var(--neutral-stroke-divider-rest); - box-sizing: content-box; - display: block; - height: 0; - margin: calc(var(--design-unit) * 1px) 0; - } - :host([orientation="vertical"]) { - border-top: none; - border-left: calc(var(--stroke-width) * 1px) solid - var(--neutral-stroke-divider-rest); - height: 100%; - margin: 0 calc(var(--design-unit) * 1px); - } -`; - -FASTDivider.define({ - name: "fast-divider", - styles, - template: dividerTemplate(), -}); diff --git a/packages/web-components/fast-foundation/src/divider/stories/divider.stories.ts b/packages/web-components/fast-foundation/src/divider/stories/divider.stories.ts deleted file mode 100644 index 40405612477..00000000000 --- a/packages/web-components/fast-foundation/src/divider/stories/divider.stories.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { html } from "@microsoft/fast-element"; -import type { Meta, Story, StoryArgs } from "../../__test__/helpers.js"; -import { renderComponent } from "../../__test__/helpers.js"; -import type { FASTDivider } from "../divider.js"; -import { DividerOrientation, DividerRole } from "../divider.options.js"; - -export const storyTemplate = html>` - -`; - -export default { - title: "Divider", - excludeStories: ["storyTemplate"], - argTypes: { - orientation: { control: "radio", options: Object.values(DividerOrientation) }, - role: { control: "select", options: Object.values(DividerRole) }, - }, -} as Meta; - -export const Divider: Story = renderComponent(storyTemplate).bind({}); diff --git a/packages/web-components/fast-foundation/src/flipper/README.md b/packages/web-components/fast-foundation/src/flipper/README.md deleted file mode 100644 index d492fd64819..00000000000 --- a/packages/web-components/fast-foundation/src/flipper/README.md +++ /dev/null @@ -1,147 +0,0 @@ ---- -id: flipper -title: fast-flipper -sidebar_label: flipper -custom_edit_url: https://github.com/microsoft/fast/edit/master/packages/web-components/fast-foundation/src/flipper/README.md -description: fast-flipper is a web component used to page through blocks of content or collections of ui elements. ---- - -The flipper component is most often used to page through blocks of content or collections of ui elements. As flippers are often a supplemental form of navigation, the flippers are hidden by default to avoid duplicate keyboard interaction. Passing an attribute of `aria-hidden="false"` will expose the flippers to assistive technology. - -## Setup - -### Basic Setup - -```ts -import { - provideFASTDesignSystem, - fastFlipper -} from "@microsoft/fast-components"; - -provideFASTDesignSystem() - .register( - fastFlipper() - ); -``` - -### Customizing Icons - -```ts -import { - provideFASTDesignSystem, - fastFlipper -} from "@microsoft/fast-components"; - -provideFASTDesignSystem() - .register( - fastFlipper({ - next: `...your next icon...`, - previous: `...your previous icon...`, - }) - ); -``` - -## Usage - -### Previous - -```html live - -``` - -### Next - -```html live - -``` - -## Create your own design - -```ts -import { - Flipper, - FlipperOptions, - flipperTemplate as template, -} from "@microsoft/fast-foundation"; -import { flipperStyles as styles } from "./my-flipper.styles"; - -export const myFlipper = Flipper.compose({ - baseName: "flipper", - template, - styles, - next: `...default next icon...`, - previous: `...default previous icon...`, -}); -``` - -## API - - - -### Variables - -| Name | Description | Type | -| ------------------ | ---------------------------------- | ----------------------------------------- | -| `FlipperDirection` | The direction options for flipper. | `{ next: "next", previous: "previous", }` | - -
- - - -### class: `FASTFlipper` - -#### Superclass - -| Name | Module | Package | -| ------------- | ------ | ----------------------- | -| `FASTElement` | | @microsoft/fast-element | - -#### Fields - -| Name | Privacy | Type | Default | Description | Inherited From | -| -------------- | ------- | ------------------ | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- | -| `disabled` | public | `boolean` | | The disabled state of the flipper. | | -| `hiddenFromAT` | public | `boolean` | `true` | Indicates the flipper should be hidden from assistive technology. Because flippers are often supplementary navigation, they are often hidden from assistive technology. | | -| `direction` | public | `FlipperDirection` | | The direction that the flipper implies navigating. | | - -#### Methods - -| Name | Privacy | Description | Parameters | Return | Inherited From | -| -------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------ | -------------------------- | ------ | -------------- | -| `keyupHandler` | public | Simulate a click event when the flipper has focus and the user hits enter or space keys Blur focus if the user hits escape key | `e: Event & KeyboardEvent` | | | - -#### Events - -| Name | Type | Description | Inherited From | -| ------- | ---- | ------------------------------------------------------------------------------------------------------------------------------ | -------------- | -| `click` | | Fires a custom 'click' event when Enter or Space is invoked via keyboard and the flipper is exposed to assistive technologies. | | - -#### Attributes - -| Name | Field | Inherited From | -| ------------- | ------------ | -------------- | -| | disabled | | -| `aria-hidden` | hiddenFromAT | | -| `direction` | direction | | - -#### CSS Parts - -| Name | Description | -| ---------- | ---------------------------------- | -| `next` | Wraps the next flipper content | -| `previous` | Wraps the previous flipper content | - -#### Slots - -| Name | Description | -| ---------- | ---------------------------- | -| `next` | The next flipper content | -| `previous` | The previous flipper content | - -
- - -## Additional resources - -* [Component explorer examples](https://explore.fast.design/components/fast-flipper) -* [Component technical specification](https://github.com/microsoft/fast/blob/master/packages/web-components/fast-foundation/src/flipper/flipper.spec.md) \ No newline at end of file diff --git a/packages/web-components/fast-foundation/src/flipper/flipper.options.ts b/packages/web-components/fast-foundation/src/flipper/flipper.options.ts deleted file mode 100644 index 914de7835dd..00000000000 --- a/packages/web-components/fast-foundation/src/flipper/flipper.options.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { ValuesOf } from "../utilities/index.js"; - -/** - * The direction options for flipper. - * @public - */ -export const FlipperDirection = { - next: "next", - previous: "previous", -} as const; - -/** - * The types for the flipper direction options. - * @public - */ -export type FlipperDirection = ValuesOf; diff --git a/packages/web-components/fast-foundation/src/flipper/flipper.pw.spec.ts b/packages/web-components/fast-foundation/src/flipper/flipper.pw.spec.ts deleted file mode 100644 index 256db91ed5e..00000000000 --- a/packages/web-components/fast-foundation/src/flipper/flipper.pw.spec.ts +++ /dev/null @@ -1,152 +0,0 @@ -import { expect, test } from "@playwright/test"; -import type { Locator, Page } from "@playwright/test"; -import { fixtureURL } from "../__test__/helpers.js"; -import type { FASTFlipper } from "./flipper.js"; - -test.describe("Flipper", () => { - let page: Page; - let element: Locator; - let root: Locator; - - test.beforeAll(async ({ browser }) => { - page = await browser.newPage(); - - element = page.locator("fast-flipper"); - - root = page.locator("#storybook-root"); - - await page.goto(fixtureURL("flipper--flipper")); - - await element.waitFor({ state: "attached" }); - }); - - test.afterAll(async () => { - await page.close(); - }); - - test("should include a role of button", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element).toHaveAttribute("role", "button"); - }); - - test('should set `aria-hidden` to "true" by default', async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element).toHaveAttribute("aria-hidden", "true"); - }); - - test("should set the `hiddenFromAT` property to true by default", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element).toHaveJSProperty("hiddenFromAT", true); - }); - - test('should set the `direction` property to "next" by default', async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element.locator("span")).toHaveClass(/next/); - }); - - test("should toggle the `aria-disabled` attribute based on the value of the `disabled` property", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element).toHaveAttribute("aria-disabled", "true"); - - await element.evaluate((node: FASTFlipper) => { - node.disabled = false; - }); - - await (await element.elementHandle())?.waitForElementState("stable"); - - await expect(element).not.toHaveAttribute("aria-disabled"); - }); - - test('should set the `tabindex` attribute to "-1" when `hiddenFromAT` is true', async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element).toHaveAttribute("tabindex", "-1"); - - await element.evaluate((node: FASTFlipper) => { - node.hiddenFromAT = false; - }); - - await (await element.elementHandle())?.waitForElementState("stable"); - - await expect(element).toHaveAttribute("tabindex", "0"); - - await element.evaluate((node: FASTFlipper) => { - node.hiddenFromAT = true; - }); - - await expect(element).toHaveAttribute("tabindex", "-1"); - }); - - test("should set a `tabindex` of 0 when `aria-hidden` is false", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element).toHaveAttribute("tabindex", "0"); - - await element.evaluate(node => { - node.setAttribute("aria-hidden", "true"); - }); - - await expect(element).toHaveAttribute("tabindex", "-1"); - }); - - test('should render a span with a class of "next" when the `direction` attribute is "next"', async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - const spans = element.locator("span"); - - await expect(spans).toHaveCount(1); - - await expect(spans).toHaveClass(/next/); - }); - - test('should render a span with a class of "previous" when the `direction` attribute is "previous"', async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - const spans = element.locator("span"); - - await expect(spans).toHaveCount(1); - - await expect(spans).toHaveClass(/previous/); - }); -}); diff --git a/packages/web-components/fast-foundation/src/flipper/flipper.spec.md b/packages/web-components/fast-foundation/src/flipper/flipper.spec.md deleted file mode 100644 index 13b93ef1c86..00000000000 --- a/packages/web-components/fast-foundation/src/flipper/flipper.spec.md +++ /dev/null @@ -1,101 +0,0 @@ -# Flipper - -## Overview - -The flipper component is most often used to page through blocks of content or collections of ui elements. - -### Use Cases -- Tony is looking for a new refrigerator. He goes onto his computer and navigates the browser to a site that sells appliances. He sees a list of refrigerators but not the one he wants so he clicks an arrow button (flipper) to show more. He sees a new GE Cafe that interests him and clicks on it which directs him to a purchase page. - -- Bobby is blind and is also looking for a new refrigerator. He goes onto his computer and navigates the browser to the same site that sells appliances. He tabs through a list of refrigerators until he finds the one that was recommended to him by a friend. Bobby is unaware of the flipper. - -### Non-goals -- Other button implementations - -### Prior Art/Examples -Limited prior art is available from major component libraries, however many brands and products leverage flippers on the front page of their sites. From a cursory search, the following prominently display either a carousel or scrolling region powered by "flippers": -- Hulu -- Netflix -- Amazon -- Microsoft - ---- - - -### API - -Extends FAST Element - -*Component Name* -- `fast-flipper` - -*Attrs* -- `direction` - enum, previous or next. Defaults to next -- `hiddenFromAT` - The control is hidden from assistive technology. In the case that `aria-hidden` exists on the host, the control will default to that value and respond accordingly. If it doesn't exist, we'll internally default to hiding this from AT. -- `disabled` - the control is disabled. There are scenarios where a flipper would be visible and disabled - -*Events* -- `click` - mimics the click event of traditional buttons - -### Anatomy and Appearance - -``` - -``` - - -*Screenshots below are of the basic appearance of the component and are not exhaustive.* - -| State | Image | -| ----- | ----- | -| previous | ![](./images/previous.png) | -| previous (hover) | ![](./images/previous-hover.png) -| next | ![](./images/next.png) -| next (hover) | ![](./images/next-hover.png) -| dark | ![](./images/previous-dark.png) -| dark (hover) | ![](./images/previous-dark-hover.png) - -*Slot Names* -- next - often times a glyph, icon, or text to represent "next" interaction -- previous - often times a glyph, icon, or text to represent "previous" interaction - -*Host Classes* -- disabled - -*CSS Parts* -- next -- previous - ---- - -## Implementation - -### Accessibility - -In a majority of use cases, flippers should be hidden from assistive technologies as it typically is a secondary method of navigation which can be confusing for users. Flippers are hidden from screen readers by default, but can be exposed by passing `false` to the `hiddenFromAT` prop. When exposing flippers to screen readers, it's important to pass an `aria-label` if the flipper content is purely presentational and not text. Correct and precise labeling of a component that is purely visual and has no textual context is needed to give proper context to assistive technologies. - -### Globalization - -Next and previous content should swap in LTR/RTL presentations. - -### Test Plan - -While testing is still TBD for our web components, I would expect this to align with the testing strategy and not require any additional test support. \ No newline at end of file diff --git a/packages/web-components/fast-foundation/src/flipper/flipper.template.ts b/packages/web-components/fast-foundation/src/flipper/flipper.template.ts deleted file mode 100644 index 368b2663e53..00000000000 --- a/packages/web-components/fast-foundation/src/flipper/flipper.template.ts +++ /dev/null @@ -1,45 +0,0 @@ -import type { ElementViewTemplate } from "@microsoft/fast-element"; -import { html } from "@microsoft/fast-element"; -import { staticallyCompose } from "../utilities/template-helpers.js"; -import type { FASTFlipper, FlipperOptions } from "./flipper.js"; -import type { FlipperDirection } from "./flipper.options.js"; - -/** - * The template for the {@link @microsoft/fast-foundation#FASTFlipper} component. - * @public - */ -export function flipperTemplate( - options: FlipperOptions = {} -): ElementViewTemplate { - const templateCache = {}; - - function setFlipperTemplateByDirection( - direction: FlipperDirection, - options: FlipperOptions - ) { - let existing = templateCache[direction]; - - if (!existing) { - templateCache[direction] = existing = html` - - - ${staticallyCompose(options[direction])} - - - `; - } - - return existing; - } - - return html` - - `; -} diff --git a/packages/web-components/fast-foundation/src/flipper/flipper.ts b/packages/web-components/fast-foundation/src/flipper/flipper.ts deleted file mode 100644 index cfb8e1f393d..00000000000 --- a/packages/web-components/fast-foundation/src/flipper/flipper.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { attr, booleanConverter, FASTElement } from "@microsoft/fast-element"; -import type { StaticallyComposableHTML } from "../utilities/template-helpers.js"; -import { FlipperDirection } from "./flipper.options.js"; - -export { FlipperDirection }; - -/** - * Flipper configuration options - * @public - */ -export type FlipperOptions = { - next?: StaticallyComposableHTML; - previous?: StaticallyComposableHTML; -}; - -/** - * A Flipper Custom HTML Element. - * Flippers are a form of button that implies directional content navigation, such as in a carousel. - * - * @slot next - The next flipper content - * @slot previous - The previous flipper content - * @csspart next - Wraps the next flipper content - * @csspart previous - Wraps the previous flipper content - * @fires click - Fires a custom 'click' event when Enter or Space is invoked via keyboard - * and the flipper is exposed to assistive technologies. - * - * @public - */ -export class FASTFlipper extends FASTElement { - /** - * The disabled state of the flipper. - * @public - * @remarks - * HTML Attribute: disabled - */ - @attr({ mode: "boolean" }) - public disabled: boolean; - - /** - * Indicates the flipper should be hidden from assistive technology. - * Because flippers are often supplementary navigation, they are often hidden from assistive technology. - * - * @public - * @defaultValue - true - * @remarks - * HTML Attribute: aria-hidden - */ - @attr({ attribute: "aria-hidden", converter: booleanConverter }) - public hiddenFromAT: boolean = true; - - /** - * The direction that the flipper implies navigating. - * - * @public - * @remarks - * HTML Attribute: direction - */ - @attr - public direction: FlipperDirection = FlipperDirection.next; - - /** - * Simulate a click event when the flipper has focus and the user hits enter or space keys - * Blur focus if the user hits escape key - * @param e - Keyboard event - * @public - */ - public keyupHandler(e: Event & KeyboardEvent) { - if (!this.hiddenFromAT) { - const key = e.key; - - if (key === "Enter" || key === "Space") { - this.$emit("click", e); - } - - if (key === "Escape") { - this.blur(); - } - } - } -} diff --git a/packages/web-components/fast-foundation/src/flipper/images/next-hover.png b/packages/web-components/fast-foundation/src/flipper/images/next-hover.png deleted file mode 100644 index c538f014469d0a9071ea900cce7b5646d687722e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6195 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 diff --git a/packages/web-components/fast-foundation/src/flipper/images/next.png b/packages/web-components/fast-foundation/src/flipper/images/next.png deleted file mode 100644 index 836e384f931f77993c77d07cbc7acf46cec0f768..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5967 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 diff --git a/packages/web-components/fast-foundation/src/flipper/images/previous-dark-hover.png b/packages/web-components/fast-foundation/src/flipper/images/previous-dark-hover.png deleted file mode 100644 index 53fc086707061d3bd411df4f8d26bc07e193ecb5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6201 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%0D!R99E)oXFp~)9s%?-Gs#!5CVa2C{+I9(vs!S zAyos9>B-m8QP2ekJG)a`FUgnLS#3v0M@b0@we<9Kk+pErIcoRNP+9!6AdmXk-*2(~ zI!4t`Rh95nef{{<6r)}n|D#PJDJ7*sbaL{~{e2T6x{qAaqp`7sLxY1ilO9Ax6_tHm zfd5wqq@t%sb+`e0F5^gS`eFgU0$hE3a1j*muIkyUii)_F znb84?LrM5J+EeH36*;SB4U%0_u*)bbD+jd|vk5c}gRhT{vTrdl1+kb)Sx_=k=M@%m z^41^&e+mA08?Q)+7Vz@&;=PbO7pN(yJC`U94hk~1w=c@fE>ds@3mHHBm1^(_$5VU) z8sdLuJa95GF)?Hv{@Ss;I2!Zn72^vImDt5P{_jvD=2{GfNvrYTAfSijN|};QG;L|buzh9nTrO?(CwP4KqmUGj>V-SnaO#Z7z9=e^`9sa-r@7-Y1}C|@Swu=oir<7P z%=^;!bfZ;0@My`)%R7djvnLg)B6(bmlFKyFmiO;#;vcLKwW^>hS|l9$0uMi`KV!6Q zEiK<{?SB-92nycJsIFwg5!5pXPz`DK9ZXN(Dkv=cJ|C8) zs_{D{)~@n0JChEb;ASZ&9BL3pmML_7~S5JBzd9RR3gUn6|6Vm>P=i0r++M83YQr{NyJiK!EJlTq!W!I?-ZW#4Vaunlp zB8J)k@FYP^PBbFOAPxp+q&KP?Ny4A35QONdOX8mxC5K=(jjF$gJsk}L^?Fr@*#80g Clt|J5 diff --git a/packages/web-components/fast-foundation/src/flipper/images/previous-dark.png b/packages/web-components/fast-foundation/src/flipper/images/previous-dark.png deleted file mode 100644 index 30b2e2693dc046711f0ea539179ddc81f41be347..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5956 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 diff --git a/packages/web-components/fast-foundation/src/flipper/images/previous-hover.png b/packages/web-components/fast-foundation/src/flipper/images/previous-hover.png deleted file mode 100644 index 4a699b215d15a8ebac559a69ff5121d2492a68bb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6214 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 - -`; - -export default { - title: "Flipper", - args: { - disabled: false, - hiddenFromAT: true, - }, - argTypes: { - direction: { control: "radio", options: Object.values(FlipperDirection) }, - disabled: { control: "boolean" }, - hiddenFromAT: { control: "boolean" }, - }, -} as Meta; - -export const Flipper: Story = renderComponent(storyTemplate).bind({}); diff --git a/packages/web-components/fast-foundation/src/form-associated/README.md b/packages/web-components/fast-foundation/src/form-associated/README.md deleted file mode 100644 index 3991539ba36..00000000000 --- a/packages/web-components/fast-foundation/src/form-associated/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# FormAssociated - -An abstract class which can be used to provide a general implementation for components that should be form-associated, including checkboxes, radios, text inputs, and other components which store user input and should be captured during form submission. - -For more information view the [specification](https://github.com/microsoft/fast/blob/master/packages/web-components/fast-foundation/src/form-associated/form-associated-custom-element.spec.md). - -## API - - - -### Variables - -| Name | Description | Type | -| -------------------------- | ----------- | ---- | -| `supportsElementInternals` | | | - -


- -### Functions - -| Name | Description | Parameters | Return | -| ------------------------- | ------------------------------------------------------------ | ------------- | ------ | -| `FormAssociated` | Base function for providing Custom Element Form Association. | `BaseCtor: T` | `T` | -| `CheckableFormAssociated` | Creates a checkable form associated component. | `BaseCtor: T` | `T` | - -
- - diff --git a/packages/web-components/fast-foundation/src/form-associated/form-associated-custom-element.spec.md b/packages/web-components/fast-foundation/src/form-associated/form-associated-custom-element.spec.md deleted file mode 100644 index f4adee4c273..00000000000 --- a/packages/web-components/fast-foundation/src/form-associated/form-associated-custom-element.spec.md +++ /dev/null @@ -1,116 +0,0 @@ -# Form Associated Custom Elements - -## Overview -This spec regards a general implementation for components that should be form-associated, including checkboxes, radios, text inputs, and other components which store user input and should be captured during form submission. - -### Definitions and acronyms: -- FACE: form-associated custom elements - -### Background -Components that are intended to replace a native form element (input, textarea, select) should generally behave like their native counterpart. One key aspect to this is associating the element with the parent form. To do this, we will expose a mechanism to expose form-association to custom elements that can be shared across implementations with maximum re-use. - -### Use Cases -Any custom element that should associate a value to a form. - -## Design -The implementation will be an *abstract class* that will extend `FASTElement`. The class will expose implementations for all of the common form element capabilities. It will also expose and manage an implementation for when the FACE APIs are not available. - -Another possible implementation is a decorator, but there are a few challenges with that approach: - 1. decorators cannot augment the class type directly, so we would need to use a pattern similar to https://www.typescriptlang.org/docs/handbook/mixins.html to gain accurate type definitions - 2. Decorators cannot (easily?) provide a *default* implementation that can be overridden by the extending class. Using an abstract class allows straight overrides of implementation or merging of implementation with super - -The implementation will standardize an interface between two common cases: browsers with FACE API support and browsers without. - -### Browsers with FACE support -For browsers *with* support, methods and properties will generally proxy to the `ElementInternals` implementation. - -### Browsers with FACE support -The implementation will manage a "proxy" element that will be appended to the light-dom. This proxy element will serve as the custom-element's association to the form. All relevant properties will be forwarded to this element, and certain API calls will retrieve data from it. - -### API -#### IDL attributes -- `public static formAssociated: boolean` - - Requirement of FACE API. This will feature-detect the API and resolve a value corresponding to feature-support. -- `public readonly validity: ValidityState` - - Returns the [validity](https://developer.mozilla.org/en-US/docs/Web/API/ValidityState) of the component. -- `public readonly form: HTMLFormElement | null` - - The associated form element. -- `public readonly validationMessage: string` - - The current validation message of the element. -- `public readonly labels: Node[]` - - Labels associated to the element. See [risks and challenges](#retrieving-labels). -- `protected abstract proxy: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement` - - A proxy element that will be appended to the DOM when FACE APIs are unavailable. It will server as the custom-elements connection to the form. -- `protected elementInternals: ElementInternals` - - Provides form-association through dedicated APIs. -- `protected setFormValue(value: File | string | FormData | null, state?: File | string | FormData): void` - - When using `elementInternals`, this will set the value in the form. With no FACE support, this will do nothing because the value will automatically be associated by the proxy element. This can be overridden as necessary by components with more advanced behavior. -- `protected handleKeyPress(): void` - - Will trigger implicit submission when `enter` key is pressed to match standard input behavior. Can be overridden or extended. -- `protected setValidity(flags: ValidityStateFlags, message?: string, anchor?: HTMLElement): void;` - - With form association support, will set the validity of the component. With no form association, this will do nothing unless a message is passed. If a message is passed, the proxy element's `setCustomValidity` method will be invoked with the value of the message. - -#### Content attributes -- `id: string` - - The id attribute of the component. Used for label association. -- `value: string | File | FormData` - - When provided as a content attribute, value must be a string. When provided as an IDL property, value can be a `string`, `File`, or `FormData` -- `disabled: boolean` - - Boolean attribute. Disables the form control, ensuring it doesn't participate in form submission -- `name: string` - - The name of the element. Allows access by name from the associated form. -- `required: boolean` - - Boolean attribute. - -### Risks and Challenges - -#### Retrieving labels -Accessing the [`labels`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/labels) property of a native input returns a `NodeList`. In cases where the FACE APIs are available, the implementation from `ElementInternals.labels` works as expected. In cases where we implement a proxy element though, we need to construct the label set from the following: - 1. any parent `
)lL0 z%&I}oxq$_b3(W(SRNR@mvq|+EelDoB-yrW!X(n(|E%!h#5*NWa`|7-61`jhX>j=wZDztM- z+l!>5RvA2s7b#AyPj|E5bP#FKkN^rjE{`*!`_hgFi|q}9?~~5dJULNJQp(e2MhRW+ z2)cO~f61%Z9vzCYZez7Irq0(#MjhB_m?mS(PNA5*+uO0$(=u4zrzUT0e2lkmWA&qC zUkYwEvqY*&kS5((SH{%9_7vzPIvWiXKlHZ%Ei#LI+5J=_&CdYOvkCMH4elm}Qw{rPFo1`!Z^u^~u zo_38b0h0T8ib`*4@dwSkj$}XwK1Hq7b)Hh2|e6S z7XS%;G6k(~jrp6r(A_xn=R(R|z_->!rLA;3hyYje{2<4a26b$$nxSi7O0p8|uCg-! zD$r;vxBuF2K9RGd8N8|-AR}{Lf=RJ#+;aa0*jd>d>9?KV0d}Sa=RG67uFK1&x;uC9 zn^tfmLcu(fy}?%8l;K$+4Z~iPv~C8ApXy5QQS5 z>@^2ZvO&D6`@J%?1kO{l(yxJw8QDLe>RxSApRxj;RRL8Ja?mvF`DF=F(b~U-iOvmZ zg=={>Q^%fZSic#&Cv9j>T4UrM52~~h_2k)07+J_)f|@97a8d_lwlz}4TGY)LmV|!D zj9xPS$!gV}g^z^OGrRhtpylmsSk-q}v_y516JHHC1H~zo_GOv+W^2j*Vb9n~u9p!I zRLnf7@$ID1Hm-eSv$2KP${?AoZc;aMsC<)N_Zy(tcnde6kaN#+->Z&{FzSl- z5Tan_nb{RrGbc>($r}5TBils42OUFg`xza9lo_<^P%-5n!d0Kch!JW1zTA)t{gW7Cxtw<7&2y=p)mqEw~?B`3PI}J+)}4$ zV(E^XV<(=9|5~vbRr^S=!Gf=7g#AWz-NXIOO5*lqXgrJAwPgZN%ql|Ynot|k3`=cNZh7)6ySUU)zQ{JE=nhp(?cvLb(Yjj=9tF{IAox#%G#mz)L%oL+^7lzs}NDj&V_>0)B z&@Kr*s+0Vp{A9YQ;%l%WU*c&=7F6Fdr~dA^pBbF5!yBnmqHoKZuv21J&^oi8puKM; zts+^qu8$z`TGftdb`Llm4nHoV{jRd_-derzO(;7tU<)<3Tytvn8r}|j>k|$HR#3rP-k69WhJp6#)9_LEW z04}_RoJ)_DBOY-~qnL-SKbl7-I36Y6mnX!Zv|+X;e<8Fb0o#G~VzLpb{e2j!&F}dN zF97$5t|>wT_(O0dqm-46YGJb`&`FXr1sHhWGo~uOWD`gdHMsaX?wi~3#2&py=GGS_ z{@mY~S+WfLMFG*5>hlunZ_Kkt>Am#I+kF~3YYNth88PL7V!7#s`xsQ+5SQ@G?_2m3xHD zF*7cNLNxGltlU2QM9r+sKtMo1wqC6uOX|}%ZMF-V>c_*FXTVtx?Lx)i^71${iB-uW zT>I|;2f>HF00fNTbol%AFK^I?$0mMBWZj7Ndk=r>loHTsXs)d0U$1|Cc|`zdsuwYJ zU*s`eJgWZDnIvJ6BPmTj;Q#gd*OzzVp!WAwFa=HjkOAYbVnDt*lC$FofAWcWB5eJ| z{QDNupVR-}i21_5&>9v8o)>zi9jW? z!y_&OEo=R`sBq>DV4g-V^evb_#o~R diff --git a/packages/web-components/fast-foundation/src/menu/images/menu-item-glyph-hover.png b/packages/web-components/fast-foundation/src/menu/images/menu-item-glyph-hover.png deleted file mode 100644 index e958de8d75db356c6a907dd8c0ef5f5718fe18fb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10917 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 RfSor;LR40yLP*d5{{X_%uYdpm diff --git a/packages/web-components/fast-foundation/src/menu/images/menu-item-glyph.png b/packages/web-components/fast-foundation/src/menu/images/menu-item-glyph.png deleted file mode 100644 index 84aa8e286fff8a09d8231480ee165b27df2cdac5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10746 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 diff --git a/packages/web-components/fast-foundation/src/menu/images/menu-item-no-glyph-focus.png b/packages/web-components/fast-foundation/src/menu/images/menu-item-no-glyph-focus.png deleted file mode 100644 index 1e42198f84ed7fcba198e19154efc7e9c0dc8fc0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10189 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 A?f?J) diff --git a/packages/web-components/fast-foundation/src/menu/images/menu-item-no-glyph-hover.png b/packages/web-components/fast-foundation/src/menu/images/menu-item-no-glyph-hover.png deleted file mode 100644 index c9b2ef03397bba05892c0c37649183c96cdcb304..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10051 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 diff --git a/packages/web-components/fast-foundation/src/menu/images/menu-item.png b/packages/web-components/fast-foundation/src/menu/images/menu-item.png deleted file mode 100644 index bdc6bb4cab4a32fb87069a355572729fe1aa164b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9802 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 UT~7i7-|*ug7+pA5YTy|8UyR}fG5`Po diff --git a/packages/web-components/fast-foundation/src/menu/index.ts b/packages/web-components/fast-foundation/src/menu/index.ts deleted file mode 100644 index 3242f433eed..00000000000 --- a/packages/web-components/fast-foundation/src/menu/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { menuTemplate } from "./menu.template.js"; -export { FASTMenu } from "./menu.js"; diff --git a/packages/web-components/fast-foundation/src/menu/menu.pw.spec.ts b/packages/web-components/fast-foundation/src/menu/menu.pw.spec.ts deleted file mode 100644 index 35aeba897be..00000000000 --- a/packages/web-components/fast-foundation/src/menu/menu.pw.spec.ts +++ /dev/null @@ -1,459 +0,0 @@ -import type { Locator, Page } from "@playwright/test"; -import { expect, test } from "@playwright/test"; -import { fixtureURL } from "../__test__/helpers.js"; -import type { FASTMenu } from "./menu.js"; - -test.describe("Menu", () => { - let page: Page; - let element: Locator; - let root: Locator; - let menuItems: Locator; - - test.beforeAll(async ({ browser }) => { - page = await browser.newPage(); - - element = page.locator("fast-menu"); - - root = page.locator("#storybook-root"); - - menuItems = element.locator("fast-menu-item"); - - await page.goto(fixtureURL("menu--menu")); - - await element.waitFor({ state: "attached" }); - }); - - test.afterAll(async () => { - await page.close(); - }); - - test("should have a role of `menu`", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - Menu item - - `; - }); - - await expect(element).toHaveAttribute("role", "menu"); - }); - - test("should set `tabindex` of the first focusable menu item to 0", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - Menu item - Menu item - - `; - }); - - await expect(menuItems.first()).toHaveAttribute("tabindex", "0"); - }); - - test("should NOT set any `tabindex` on non-menu-item elements", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - Menu item -
Not a menu item
-
- `; - }); - - const divider = element.locator("div"); - - expect(await divider.getAttribute("tabindex")).toBeNull(); - }); - - test("should focus on first menu item when focus is called", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - Menu item - Menu item - - `; - }); - - await element.waitFor({ state: "attached" }); - - await expect(menuItems.first()).toHaveAttribute("tabindex", "0"); - - await root.evaluate(node => { - document.querySelector("fast-menu")?.focus(); - }); - - expect( - await menuItems.first().evaluate(node => { - return node.isSameNode(document.activeElement); - }) - ).toBeTruthy(); - }); - - test("should not throw when focus is called with no items", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await root.evaluate(node => { - document.querySelector("fast-menu")?.focus(); - }); - - expect(await page.evaluate(() => document.activeElement?.id)).toBe(""); - }); - - test("should not throw when focus is called before initialization is complete", async () => { - await root.evaluate(node => { - node.innerHTML = ""; - - const menu = document.createElement("fast-menu"); - - menu.focus(); - - node.append(menu); - }); - - expect(await page.evaluate(() => document.activeElement?.id)).toBe(""); - }); - - test("should focus disabled items", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - Menu item - Menu item - - `; - }); - - const firstMenuItem = menuItems.first(); - - await expect(firstMenuItem).toBeDisabled(); - - await expect(firstMenuItem).toHaveAttribute("tabindex", "0"); - - await firstMenuItem.focus(); - - await expect(firstMenuItem).toBeFocused(); - }); - - ["menuitem", "menuitemcheckbox", "menuitemradio"].forEach(role => { - test(`should accept elements as focusable child with "${role}" role`, async () => { - await root.evaluate( - (node, { role }) => { - node.innerHTML = /* html */ ` - -
Menu item
-
- `; - }, - { role } - ); - - await expect( - page.locator(`fast-menu [role="${role}"]`).first() - ).toHaveAttribute("tabindex", "0"); - }); - }); - - test("should not navigate to hidden items when changed after connection", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - Menu item 1 - Menu item 2 - Menu item 3 - Menu item 4 - - `; - }); - - await expect.soft(menuItems).toHaveCount(4); - - await menuItems.nth(2).evaluate(node => node.toggleAttribute("hidden")); - - await element.evaluate(node => { - node.focus(); - }); - - await (await element.elementHandle())?.waitForElementState("stable"); - - await expect(menuItems.nth(0)).toBeFocused(); - - await element.press("ArrowDown"); - - await expect(menuItems.nth(1)).toBeFocused(); - - await element.press("ArrowDown"); - - await expect(menuItems.nth(2)).not.toBeFocused(); - - await expect(menuItems.nth(3)).toBeFocused(); - - await element.press("ArrowUp"); - - await expect(menuItems.nth(2)).not.toBeFocused(); - - await expect(menuItems.nth(1)).toBeFocused(); - - await element.press("ArrowUp"); - - await expect(menuItems.nth(0)).toBeFocused(); - - await menuItems.nth(2).evaluate(node => { - node.removeAttribute("hidden"); - }); - - await (await element.elementHandle())?.waitForElementState("stable"); - - await element.press("ArrowDown"); - - await expect(menuItems.nth(1)).toBeFocused(); - - await element.press("ArrowDown"); - - await expect(menuItems.nth(2)).toBeFocused(); - }); - - test("should treat all checkbox menu items as individually selectable items", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - Menu item 1 - Menu item 2 - Menu item 3 - Menu item 4 - - `; - }); - - const menuItemsCount = await menuItems.count(); - - for (let i = 0; i < menuItemsCount; i++) { - const item = menuItems.nth(i); - - await expect(item).toHaveAttribute("aria-checked", "false"); - - await item.click(); - - await expect(item).toHaveAttribute("aria-checked", "true"); - - await item.click(); - - await expect(item).toHaveAttribute("aria-checked", "false"); - } - }); - - test(`should treat all radio menu items as a radiogroup and limit selection to one item within the group`, async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - Menu item 1 - Menu item 2 - Menu item 3 - - `; - }); - - await menuItems.first().click(); - - await expect(menuItems.first()).toHaveAttribute("aria-checked", "true"); - - await expect(menuItems.nth(1)).toHaveAttribute("aria-checked", "false"); - - await expect(menuItems.nth(2)).toHaveAttribute("aria-checked", "false"); - - await menuItems.nth(1).click(); - - await expect(menuItems.first()).toHaveAttribute("aria-checked", "false"); - - await expect(menuItems.nth(1)).toHaveAttribute("aria-checked", "true"); - - await expect(menuItems.nth(2)).toHaveAttribute("aria-checked", "false"); - - await menuItems.nth(2).click(); - - await expect(menuItems.first()).toHaveAttribute("aria-checked", "false"); - - await expect(menuItems.nth(1)).toHaveAttribute("aria-checked", "false"); - - await expect(menuItems.nth(2)).toHaveAttribute("aria-checked", "true"); - }); - - test('should use elements with `[role="separator"]` to divide radio menu items into different radio groups', async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - Menu item 1 - Menu item 2 - - Menu item 3 - Menu item 4 - - `; - }); - - await menuItems.nth(0).click(); - - await expect(menuItems.nth(0)).toHaveAttribute("aria-checked", "true"); - await expect(menuItems.nth(1)).toHaveAttribute("aria-checked", "false"); - await expect(menuItems.nth(2)).toHaveAttribute("aria-checked", "false"); - await expect(menuItems.nth(3)).toHaveAttribute("aria-checked", "false"); - - await menuItems.nth(1).click(); - - await expect(menuItems.nth(0)).toHaveAttribute("aria-checked", "false"); - await expect(menuItems.nth(1)).toHaveAttribute("aria-checked", "true"); - await expect(menuItems.nth(2)).toHaveAttribute("aria-checked", "false"); - await expect(menuItems.nth(3)).toHaveAttribute("aria-checked", "false"); - - await menuItems.nth(2).click(); - - await expect(menuItems.nth(0)).toHaveAttribute("aria-checked", "false"); - await expect(menuItems.nth(1)).toHaveAttribute("aria-checked", "true"); - await expect(menuItems.nth(2)).toHaveAttribute("aria-checked", "true"); - await expect(menuItems.nth(3)).toHaveAttribute("aria-checked", "false"); - - await menuItems.nth(3).click(); - - await expect(menuItems.nth(0)).toHaveAttribute("aria-checked", "false"); - await expect(menuItems.nth(1)).toHaveAttribute("aria-checked", "true"); - await expect(menuItems.nth(2)).toHaveAttribute("aria-checked", "false"); - await expect(menuItems.nth(3)).toHaveAttribute("aria-checked", "true"); - }); - - test.fixme("should navigate the menu on arrow up/down keys", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - Menu item 1 - Menu item 2 - Menu item 3 - Menu item 4 - - `; - }); - - await element.waitFor({ state: "attached" }); - - await element.evaluate(node => { - node.focus(); - }); - - await expect(menuItems).toHaveCount(4); - - await expect(menuItems.first()).toBeFocused(); - - await element.press("ArrowDown"); - - await expect(menuItems.nth(1)).toBeFocused(); - - await element.press("ArrowDown"); - - await expect(menuItems.nth(2)).toBeFocused(); - - await element.press("ArrowDown"); - - await expect(menuItems.nth(3)).toBeFocused(); - }); - - test.fixme("should close the menu when pressing the escape key", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - Menu item 1 - - Menu item 1.1 - Menu item 1.2 - Menu item 1.3 - - - - `; - }); - - await element.first().evaluate(node => { - node.focus(); - }); - - await element.first().press("ArrowRight"); - - await (await element.first().elementHandle())?.waitForElementState("stable"); - - await expect(menuItems.nth(1)).toBeFocused(); - - await element.first().press("Escape"); - - await (await element.first().elementHandle())?.waitForElementState("stable"); - - await expect(menuItems.first()).toBeFocused(); - }); - - test("should not navigate to hidden items when set before connection", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - Menu item 1 - - Menu item 3 - Menu item 4 - - `; - - // reset the focus to the window to help with flakiness - window.focus(); - }); - - await (await element.elementHandle())?.waitForElementState("stable"); - - await element.evaluate(node => { - node.focus(); - }); - - await expect(menuItems.nth(0)).toBeFocused({ timeout: 500 }); - - await element.evaluate(node => { - node.dispatchEvent( - new KeyboardEvent("keydown", { - key: "ArrowDown", - }) - ); - }); - - await expect(menuItems.nth(2)).toBeFocused(); - - await element.evaluate(node => { - node.dispatchEvent( - new KeyboardEvent("keydown", { - key: "ArrowDown", - }) - ); - }); - - await expect(menuItems.nth(3)).toBeFocused(); - - await element.evaluate(node => { - node.dispatchEvent( - new KeyboardEvent("keydown", { - key: "ArrowUp", - }) - ); - }); - - await expect(menuItems.nth(2)).toBeFocused(); - - await element.evaluate(node => { - node.dispatchEvent( - new KeyboardEvent("keydown", { - key: "ArrowUp", - }) - ); - }); - - await expect(menuItems.nth(0)).toBeFocused(); - }); -}); diff --git a/packages/web-components/fast-foundation/src/menu/menu.spec.md b/packages/web-components/fast-foundation/src/menu/menu.spec.md deleted file mode 100644 index 568ee681d21..00000000000 --- a/packages/web-components/fast-foundation/src/menu/menu.spec.md +++ /dev/null @@ -1,195 +0,0 @@ -# Menu + Menu Item - -## Overview - -There are two components being presented as part of this specification - menu, and menu item. - -As defined by the W3C: -> A menu is a widget that offers a list of choices to the user, such as a set of actions or functions. Menu widgets behave like native operating system menus, such as the menus that pull down from the menubars commonly found at the top of many desktop application windows. A menu is usually opened, or made visible, by activating a menu button, choosing an item in a menu that opens a sub menu, or by invoking a command, such as Shift + F10 in Windows, that opens a context specific menu. When a user activates a choice in a menu, the menu usually closes unless the choice opened a submenu. - -### Use Cases - -1. Paired with a persistent [menu button](https://w3c.github.io/aria-practices/#menubutton) to create a dropdown menu control. An example of this might be the common `...` overflow menu patterns where the menus visual state is toggled when the menu button is clicked. - -2. A contextual menu triggered via right click, not paired with a menu button. - -3. A less common, but still conventional pattern would be a visually persistent menu docked to the side of a screen, such as the example docked to the left (ltr) in this [Microsoft store example](https://www.microsoft.com/en-us/store/top-free/apps/pc). - -### Non-goals - -The horizontal menu bar is not currently part of the proposed control, nor is the menu button itself. - -This control is also not intended to be a "one size fits all" approach for controls which have menu-like behavior. While there are commonalities across different menu or list-like controls in terms of keyboarding behavior, those commonalities should be abstracted once we understand the nuance and deltas between the controls. This control is meant to be a semantic menu. While it may someday utilize some future abstracted utility, the control itself is not meant to be the abstract utility. - -### Risks and Challenges - -#### Icon support: - -Consider a scenario where we have the following menu - some menu items have glyphs, others do not: -```html - - Menu item one - Menu item two - - - Menu item three - - -``` -The third item in the menu has a glyph, which would inset the text from the other menu items. To ensure that the content of this menu item aligns with the rest of the items, all items need to visually shift to ensure alignment of the menu content. This presents an interesting challenge for how we will communicate these changes to ensure the styling is appropriately applied. Ultimately, the parent just needs to know that *one* of the items below has a menu item with the glyph. - -### Prior Art/Examples -- [FAST Context Menu (React)](https://www.npmjs.com/package/@microsoft/fast-components-react-msft) -- [Material UI](https://material-ui.com/components/menus/) -- [Lightning Design](https://www.lightningdesignsystem.com/components/menus/) -- [Ant Design - menu](https://ant.design/components/menu/) -- [Ant Design - dropdown](https://ant.design/components/menu/) -- [Atlassian - menu](https://atlaskit.atlassian.com/packages/core/menu) -- [Atlassian - dropdown menu](https://atlaskit.atlassian.com/packages/core/dropdown-menu) -- [Windows (UWP)](https://docs.microsoft.com/en-us/windows/uwp/design/controls-and-patterns/tree-view) - ---- - -## Design - -### API - -*The key elements of the component's public API surface:* - -**Menu** -*Component name:* -- `fast-menu` - -*Attributes:* -- extends HTML Element attributes - -*Slots:* -- default slot for items - -*Events* -- none - -**Menu Item** -*Component name:* -- `fast-menu-item` - -*Attributes:* -- role - an enum representing the menu items' role - - menuitem - - menuitemcheckbox - - menuitemradio -- disabled - the menu item is disabled -- checked - sets the checked value for menuitemcheckbox or menuitemradio items - -*Slots:* -- before - slot which precedes content -- default - slot for the content (the default slot for the item) -- after - slot which comes after content -- submenu - the slot used to generate a submenu -- radio-indicator - slot for radio item selection indicator -- checkbox-indicator - slot for the checkbox selection indicator -- expand-collapse-glyph - slot for the expand/collapse glyph for nested menus - -*CSS Parts* -- before -- content -- after -- submenu-region -- checkbox -- checkbox-indicator -- radio -- radio-indicator -- expand-collapse -- expand-collapse-glyph - -*Events:* -- click (event) - event for when the item has been clicked or invoked via keyboard -- change (event) - event for when the item has been clicked or invoked via keyboard, and will be prevented if the menu item is disabled -- expanded-change (event) - event for when the item has been expanded or collapsed - -### Anatomy and Appearance - -**Menu** - -| State | Image | -| ----- | ----- | -| default | ![](./images/menu.png) -| with glyph | ![](./images/menu-glyph.png) - -The menu has no named slots or parts - it has a default slot for menu items. - -Flat menu: -```html - - Root node one - Root node two - Root node three - Root node four - -``` - -Nested menu: -```html - - Menu item one - Menu item two - - Menu item three - - Nested item one - Nested item two - - Nested item three - - Nested item one - Nested item two - - - - - Menu item four - -``` - -**Menu item** - -| State | Image | -| ----- | ----- | -| default | ![](./images/menu-item.png) -| default (glyph) | ![](./images/menu-item-glyph.png) -| disabled | ![](./images/menu-item-disabled.png) -| focus | ![](./images/menu-item-no-glyph-focus.png) -| hover | ![](./images/menu-item-no-glyph-hover.png) -| focus (glyph) | ![](./images/menu-item-glyph-focus.png) -| hover (glyph) | ![](./images/menu-item-glyph-hover.png) - ---- - -## Implementation - -### States - -**Menu Item** - -Checked: - - A menu with menuitemcheckbox or menuitemradio roles can be "checked". - - - the control may be initialized in the checked state - - clicking on the control or using enter/spacebar would set the item as checked - -Disabled: -- disabled menu items are focusable but cannot be activated. - -### Accessibility - -The menu should align to the interaction model provided by the [W3C](https://w3c.github.io/aria-practices/#menu) - -### Globalization - -The component visuals should support RTL scenarios (per below): -![](./images/menu-rtl.png) - -### Test Plan - -While testing is still TBD for our web components, I would expect this to align with the testing strategy and not require any additional test support. diff --git a/packages/web-components/fast-foundation/src/menu/menu.template.ts b/packages/web-components/fast-foundation/src/menu/menu.template.ts deleted file mode 100644 index 03f8abf0827..00000000000 --- a/packages/web-components/fast-foundation/src/menu/menu.template.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { ElementViewTemplate } from "@microsoft/fast-element"; -import { html, slotted } from "@microsoft/fast-element"; -import type { FASTMenu } from "./menu.js"; - -/** - * The template for the {@link @microsoft/fast-foundation#FASTMenu} component. - * @public - */ -export function menuTemplate(): ElementViewTemplate { - return html` - - `; -} diff --git a/packages/web-components/fast-foundation/src/menu/menu.ts b/packages/web-components/fast-foundation/src/menu/menu.ts deleted file mode 100644 index 08b5e6a72b4..00000000000 --- a/packages/web-components/fast-foundation/src/menu/menu.ts +++ /dev/null @@ -1,333 +0,0 @@ -import { FASTElement, Observable, observable, Updates } from "@microsoft/fast-element"; -import { - isHTMLElement, - keyArrowDown, - keyArrowUp, - keyEnd, - keyHome, -} from "@microsoft/fast-web-utilities"; -import { FASTMenuItem, MenuItemRole } from "../menu-item/index.js"; - -/** - * A Menu Custom HTML Element. - * Implements the {@link https://www.w3.org/TR/wai-aria-1.1/#menu | ARIA menu }. - * - * @slot - The default slot for the menu items - * - * @public - */ -export class FASTMenu extends FASTElement { - /** - * @internal - */ - @observable - public items: HTMLElement[]; - protected itemsChanged(oldValue: HTMLElement[], newValue: HTMLElement[]): void { - // only update children after the component is connected and - // the setItems has run on connectedCallback - // (menuItems is undefined until then) - if (this.$fastController.isConnected && this.menuItems !== undefined) { - this.setItems(); - } - } - - protected menuItems: Element[] | undefined; - - private expandedItem: FASTMenuItem | null = null; - - /** - * The index of the focusable element in the items array - * defaults to -1 - */ - private focusIndex: number = -1; - - private static focusableElementRoles = MenuItemRole; - - /** - * @internal - */ - public connectedCallback(): void { - super.connectedCallback(); - Updates.enqueue(() => { - // wait until children have had a chance to - // connect before setting/checking their props/attributes - this.setItems(); - }); - - this.addEventListener("change", this.changeHandler); - } - - /** - * @internal - */ - public disconnectedCallback(): void { - super.disconnectedCallback(); - this.removeItemListeners(); - this.menuItems = undefined; - this.removeEventListener("change", this.changeHandler); - } - - /** - * @internal - */ - public readonly isNestedMenu = (): boolean => { - return ( - this.parentElement !== null && - isHTMLElement(this.parentElement) && - this.parentElement.getAttribute("role") === "menuitem" - ); - }; - - /** - * Focuses the first item in the menu. - * - * @public - */ - public focus(): void { - this.setFocus(0, 1); - } - - /** - * Collapses any expanded menu items. - * - * @public - */ - public collapseExpandedItem(): void { - if (this.expandedItem !== null) { - this.expandedItem.expanded = false; - this.expandedItem = null; - } - } - - /** - * @internal - */ - public handleMenuKeyDown(e: KeyboardEvent): void | boolean { - if (e.defaultPrevented || this.menuItems === undefined) { - return; - } - switch (e.key) { - case keyArrowDown: - // go forward one index - this.setFocus(this.focusIndex + 1, 1); - return; - case keyArrowUp: - // go back one index - this.setFocus(this.focusIndex - 1, -1); - return; - case keyEnd: - // set focus on last item - this.setFocus(this.menuItems.length - 1, -1); - return; - case keyHome: - // set focus on first item - this.setFocus(0, 1); - return; - - default: - // if we are not handling the event, do not prevent default - return true; - } - } - - /** - * if focus is moving out of the menu, reset to a stable initial state - * @internal - */ - public handleFocusOut = (e: FocusEvent) => { - if (!this.contains(e.relatedTarget as Element) && this.menuItems !== undefined) { - this.collapseExpandedItem(); - // find our first focusable element - const focusIndex: number = this.menuItems.findIndex(this.isFocusableElement); - // set the current focus index's tabindex to -1 - this.menuItems[this.focusIndex].setAttribute("tabindex", "-1"); - // set the first focusable element tabindex to 0 - this.menuItems[focusIndex].setAttribute("tabindex", "0"); - // set the focus index - this.focusIndex = focusIndex; - } - }; - - private handleItemFocus = (e: FocusEvent) => { - const targetItem: HTMLElement = e.target as HTMLElement; - - if ( - this.menuItems !== undefined && - targetItem !== this.menuItems[this.focusIndex] - ) { - this.menuItems[this.focusIndex].setAttribute("tabindex", "-1"); - this.focusIndex = this.menuItems.indexOf(targetItem); - targetItem.setAttribute("tabindex", "0"); - } - }; - - private handleExpandedChanged = (e: Event): void => { - if ( - e.defaultPrevented || - e.target === null || - this.menuItems === undefined || - this.menuItems.indexOf(e.target as Element) < 0 - ) { - return; - } - - e.preventDefault(); - const changedItem: FASTMenuItem = e.target as any as FASTMenuItem; - - // closing an expanded item without opening another - if ( - this.expandedItem !== null && - changedItem === this.expandedItem && - changedItem.expanded === false - ) { - this.expandedItem = null; - return; - } - - if (changedItem.expanded) { - if (this.expandedItem !== null && this.expandedItem !== changedItem) { - this.expandedItem.expanded = false; - } - this.menuItems[this.focusIndex].setAttribute("tabindex", "-1"); - this.expandedItem = changedItem; - this.focusIndex = this.menuItems.indexOf(changedItem); - changedItem.setAttribute("tabindex", "0"); - } - }; - - private removeItemListeners(items: Element[] = this.items): void { - items.forEach(item => { - item.removeEventListener("focus", this.handleItemFocus); - item.removeEventListener("expanded-changed", this.handleExpandedChanged); - Observable.getNotifier(item).unsubscribe(this, "hidden"); - }); - } - - protected setItems(): void { - const children = Array.from(this.children); - - this.removeItemListeners(children); - - children.forEach((child: Element) => - Observable.getNotifier(child).subscribe(this, "hidden") - ); - - const newItems: Element[] = children.filter( - child => !child.hasAttribute("hidden") - ); - - this.menuItems = newItems; - - const menuItems = this.menuItems.filter(this.isMenuItemElement); - - // if our focus index is not -1 we have items - if (menuItems.length) { - this.focusIndex = 0; - } - - menuItems.forEach((item: HTMLElement, index: number) => { - item.setAttribute("tabindex", index === 0 ? "0" : "-1"); - item.addEventListener("expanded-change", this.handleExpandedChanged); - item.addEventListener("focus", this.handleItemFocus); - }); - } - - public handleChange(source: any, propertyName: string) { - if (propertyName === "hidden") { - this.setItems(); - } - } - - /** - * handle change from child element - */ - private changeHandler = (e: CustomEvent): void => { - if (this.menuItems === undefined) { - return; - } - const changedMenuItem: FASTMenuItem = e.target as FASTMenuItem; - const changeItemIndex: number = this.menuItems.indexOf(changedMenuItem); - - if (changeItemIndex === -1) { - return; - } - - if ( - changedMenuItem.role === "menuitemradio" && - changedMenuItem.checked === true - ) { - for (let i = changeItemIndex - 1; i >= 0; --i) { - const item: Element = this.menuItems[i]; - const role: string | null = item.getAttribute("role"); - if (role === MenuItemRole.menuitemradio) { - (item as FASTMenuItem).checked = false; - } - if (role === "separator") { - break; - } - } - const maxIndex: number = this.menuItems.length - 1; - for (let i = changeItemIndex + 1; i <= maxIndex; ++i) { - const item: Element = this.menuItems[i]; - const role: string | null = item.getAttribute("role"); - if (role === MenuItemRole.menuitemradio) { - (item as FASTMenuItem).checked = false; - } - if (role === "separator") { - break; - } - } - } - }; - - /** - * check if the item is a menu item - */ - protected isMenuItemElement = (el: Element): el is HTMLElement => { - return ( - el instanceof FASTMenuItem || - (isHTMLElement(el) && - (el.getAttribute("role") as string) in FASTMenu.focusableElementRoles) - ); - }; - - /** - * check if the item is focusable - */ - private isFocusableElement = (el: Element): el is HTMLElement => { - return this.isMenuItemElement(el); - }; - - private setFocus(focusIndex: number, adjustment: number): void { - if (this.menuItems === undefined) { - return; - } - - while (focusIndex >= 0 && focusIndex < this.menuItems.length) { - const child: Element = this.menuItems[focusIndex]; - - if (this.isFocusableElement(child)) { - // change the previous index to -1 - if ( - this.focusIndex > -1 && - this.menuItems.length >= this.focusIndex - 1 - ) { - this.menuItems[this.focusIndex].setAttribute("tabindex", "-1"); - } - - // update the focus index - this.focusIndex = focusIndex; - - // update the tabindex of next focusable element - child.setAttribute("tabindex", "0"); - - // focus the element - child.focus(); - - break; - } - - focusIndex += adjustment; - } - } -} diff --git a/packages/web-components/fast-foundation/src/menu/stories/menu.register.ts b/packages/web-components/fast-foundation/src/menu/stories/menu.register.ts deleted file mode 100644 index b74de9abb73..00000000000 --- a/packages/web-components/fast-foundation/src/menu/stories/menu.register.ts +++ /dev/null @@ -1,403 +0,0 @@ -import { html } from "@microsoft/fast-element"; -import { attr } from "@microsoft/fast-element"; -import { css } from "@microsoft/fast-element"; -import { FASTMenuItem, MenuItemRole, menuItemTemplate } from "../../menu-item/index.js"; -import { FASTMenu } from "../menu.js"; -import { menuTemplate } from "../menu.template.js"; - -const styles = css` - :host([hidden]) { - display: none; - } - - :host { - --elevation: 11; - background: var(--neutral-layer-floating); - border: calc(var(--stroke-width) * 1px) solid transparent; - border-radius: calc(var(--control-corner-radius) * 1px); - box-shadow: 0 0 calc((var(--elevation) * 0.225px) + 2px) - rgba(0, 0, 0, calc(0.11 * (2 - var(--background-luminance, 1)))), - 0 calc(var(--elevation) * 0.4px) calc((var(--elevation) * 0.9px)) - rgba(0, 0, 0, calc(0.13 * (2 - var(--background-luminance, 1)))); - display: block; - margin: 0; - max-width: 368px; - min-width: 64px; - padding: calc(var(--design-unit) * 1px) 0; - } - - :host([slot="submenu"]) { - margin: 0 calc(var(--design-unit) * 1px); - width: max-content; - } - - ::slotted(fast-divider) { - border: none; - border-top: calc(var(--stroke-width) * 1px) solid - var(--neutral-stroke-divider-rest); - box-sizing: content-box; - height: 0; - margin: 0; - } -`; - -FASTMenu.define({ - name: "fast-menu", - styles, - template: menuTemplate(), -}); - -export class FancyMenu extends FASTMenu { - public connectedCallback(): void { - super.connectedCallback(); - } - - protected setItems(): void { - super.setItems(); - - this.menuItems - ?.filter(this.isMenuItemElement) - .forEach((item: HTMLElement, index: number) => { - const indent: FancyMenuItemColumnCount = - this.menuItems?.reduce((accum, current) => { - const elementValue = FancyMenu.elementIndent( - current as HTMLElement - ); - - return Math.max( - accum, - elementValue as number - ) as FancyMenuItemColumnCount; - }, 0) ?? 0; - - if (item instanceof FancyMenuItem) { - item.startColumnCount = indent; - } - }); - } - - private static elementIndent(el: HTMLElement): FancyMenuItemColumnCount { - const role = el.getAttribute("role"); - const startSlot = el.querySelector("[slot=start]"); - - if (role && role !== MenuItemRole.menuitem) { - return !startSlot ? 1 : 2; - } - - return !startSlot ? 0 : 1; - } -} - -/** - * Types of menu item column count. - * @internal - */ -type FancyMenuItemColumnCount = 0 | 1 | 2; - -/** - * @internal - */ -export class FancyMenuItem extends FASTMenuItem { - /** - * @public - * @deprecated - will be removed in a coming ALPHA version - */ - @attr({ attribute: "start-column-count" }) - public startColumnCount: FancyMenuItemColumnCount; - - public connectedCallback(): void { - super.connectedCallback(); - - if (!this.startColumnCount) { - this.startColumnCount = 1; - } - } -} - -FancyMenu.define({ - name: "fancy-menu", - styles, - template: menuTemplate(), -}); - -FancyMenuItem.define({ - name: "fancy-menu-item", - template: menuItemTemplate({ - checkboxIndicator: /* html */ html` - - - - `, - expandCollapseGlyph: /* html */ html` - - - - `, - radioIndicator: /* html */ html` - - `, - }), - styles: css` - :host([hidden]) { - display: none !important; - } - - :host { - --icon-col: minmax(42px, auto); - align-items: center; - background: var(--neutral-fill-stealth-rest); - border-radius: calc(var(--control-corner-radius) * 1px); - border: calc(var(--focus-stroke-width) * 1px) solid transparent; - box-sizing: border-box; - color: var(--neutral-foreground-rest); - contain: layout; - cursor: pointer; - display: grid; - fill: currentcolor; - font: var(--type-ramp-base-font-size) / var(--type-ramp-base-line-height) - var(--body-font); - grid-template-columns: var(--icon-col) 1fr var(--icon-col); - grid-template-rows: auto; - height: calc(var(--height-number) * 1px); - justify-items: center; - margin: 0 calc(var(--design-unit) * 1px); - outline: none; - overflow: visible; - padding: 0; - white-space: nowrap; - } - - :host(:hover) { - background: var(--neutral-fill-stealth-hover); - color: var(--neutral-foreground-rest); - position: relative; - z-index: 1; - } - - :host(:active) { - background: var(--neutral-fill-stealth-active); - } - - :host(:focus-visible) { - border-color: var(--focus-stroke-outer); - background: var(--neutral-fill-stealth-focus); - color: var(--neutral-foreground-rest); - } - - .content { - grid-column-start: 2; - justify-self: start; - overflow: hidden; - text-overflow: ellipsis; - } - - :host([start-column-count="0"]) { - grid-template-columns: auto 1fr var(--icon-col); - } - - :host([start-column-count="0"]) .content { - grid-column: 1; - grid-row: 1; - margin-inline-start: 10px; - } - - :host([start-column-count="0"]) .expand-collapse-glyph-container { - grid-column: 5; - grid-row: 1; - } - - :host([start-column-count="2"]) { - grid-template-columns: - var(--icon-col) var(--icon-col) 1fr var(--icon-col) - var(--icon-col); - } - - :host([start-column-count="2"]) .content { - grid-column: 3; - grid-row: 1; - margin-inline-start: 10px; - } - - :host([start-column-count="2"]) .expand-collapse-glyph-container { - grid-column: 5; - grid-row: 1; - } - - :host([start-column-count="2"]) ::slotted([slot="start"]) { - grid-column: 2; - } - - :host([start-column-count="2"]) ::slotted([slot="end"]) { - grid-column: 4; - } - - :host([aria-checked="true"]), - :host(.expanded) { - background: var(--neutral-fill-rest); - color: var(--neutral-foreground-rest); - } - - :host([disabled]) { - cursor: var(--disabled-cursor); - opacity: var(--disabled-opacity); - } - - :host([disabled]:hover) { - color: var(--neutral-foreground-rest); - fill: currentcolor; - background: var(--neutral-fill-stealth-rest); - } - - .expand-collapse-glyph { - width: 16px; - height: 16px; - } - - ::slotted([slot="start"]), - ::slotted([slot="end"]) { - display: flex; - } - - ::slotted([slot="start"]) { - margin-inline-start: 10px; - } - - ::slotted([slot="end"]) { - margin-inline-end: 10px; - } - - :host([start-column-count="0"][aria-haspopup="menu"]), - :host([start-column-count="1"][aria-haspopup="menu"]), - :host([start-column-count="1"][role="menuitemcheckbox"]), - :host([start-column-count="1"][role="menuitemradio"]) { - align-items: center; - display: grid; - grid-template-columns: var(--icon-col) auto 1fr var(--icon-col) var( - --icon-col - ); - min-height: 32px; - } - - :host([start-column-count="2"]:not([aria-haspopup="menu"])) - ::slotted([slot="end"]) { - grid-column: 5; - } - - .input-container, - .expand-collapse-glyph-container { - display: none; - } - - :host([aria-haspopup="menu"]) .expand-collapse-glyph-container, - :host([role="menuitemcheckbox"]) .input-container, - :host([role="menuitemradio"]) .input-container { - display: grid; - margin-inline-end: 10px; - } - - :host([aria-haspopup="menu"]) .content, - :host([role="menuitemcheckbox"]) .content, - :host([role="menuitemradio"]) .content { - grid-column-start: 3; - } - - :host([aria-haspopup="menu"][start-column-count="0"]) .content { - grid-column-start: 1; - } - - :host([aria-haspopup="menu"]) ::slotted([slot="end"]), - :host([role="menuitemcheckbox"]) ::slotted([slot="end"]), - :host([role="menuitemradio"]) ::slotted([slot="end"]) { - grid-column-start: 4; - } - - .expand-collapse, - .checkbox, - .radio { - display: flex; - align-items: center; - justify-content: center; - position: relative; - width: 20px; - height: 20px; - box-sizing: border-box; - outline: none; - margin-inline-start: 10px; - } - - .checkbox, - .radio { - border: calc(var(--stroke-width) * 1px) solid var(--neutral-foreground-rest); - } - - :host([aria-checked="true"]) .checkbox, - :host([aria-checked="true"]) .radio { - background: var(--accent-fill-rest); - border-color: var(--accent-fill-rest); - } - - .checkbox { - border-radius: calc(var(--control-corner-radius) * 1px); - } - - .radio { - border-radius: 999px; - } - - .checkbox-indicator, - .radio-indicator, - .expand-collapse-indicator, - ::slotted([slot="checkbox-indicator"]), - ::slotted([slot="radio-indicator"]), - ::slotted([slot="expand-collapse-indicator"]) { - display: none; - } - - ::slotted([slot="end"]:not(svg)) { - color: var(--neutral-foreground-hint); - margin-inline-end: 10px; - } - - :host([aria-checked="true"]) .checkbox-indicator, - :host([aria-checked="true"]) ::slotted([slot="checkbox-indicator"]) { - display: block; - fill: var(--foreground-on-accent-rest); - height: 100%; - pointer-events: none; - width: 100%; - } - - :host([aria-checked="true"]) .radio-indicator { - background: var(--foreground-on-accent-rest); - border-radius: 999px; - bottom: 4px; - display: block; - left: 4px; - pointer-events: none; - position: absolute; - right: 4px; - top: 4px; - } - - :host([aria-checked="true"]) ::slotted([slot="radio-indicator"]) { - display: block; - pointer-events: none; - } - `, -}); diff --git a/packages/web-components/fast-foundation/src/menu/stories/menu.stories.ts b/packages/web-components/fast-foundation/src/menu/stories/menu.stories.ts deleted file mode 100644 index 8dc9588c73b..00000000000 --- a/packages/web-components/fast-foundation/src/menu/stories/menu.stories.ts +++ /dev/null @@ -1,237 +0,0 @@ -import { html, repeat } from "@microsoft/fast-element"; -import { storyTemplate as dividerStoryTemplate } from "../../divider/stories/divider.stories.js"; -import type { FASTMenuItem } from "../../menu-item/menu-item.js"; -import { storyTemplate as menuItemStoryTemplate } from "../../menu-item/stories/menu-item.stories.js"; -import type { Meta, Story, StoryArgs } from "../../__test__/helpers.js"; -import { renderComponent } from "../../__test__/helpers.js"; -import type { FASTMenu } from "../menu.js"; -import type { FancyMenu as MyFancyMenu } from "./menu.register.js"; - -const storyTemplate = html>` - ${x => x.storyContent} -`; - -const storyContentTemplate = html` - ${repeat( - x => x.storyItems, - html>` - ${x => x.template ?? menuItemStoryTemplate} - ` - )} -`; - -const fancyStoryTemplate = html>` - ${x => x.storyContent} -`; - -const fancyMenuItemStoryTemplate = html>` - - ${x => x.storyContent} - -`; - -export default { - title: "Menu", - args: { - storyContent: storyContentTemplate, - storyItems: [ - { storyContent: "Menu Item 1" }, - { storyContent: "Menu Item 2" }, - { storyContent: "Menu Item 3" }, - ], - }, - argTypes: { - storyContent: { table: { disable: true } }, - }, -} as Meta; - -export const Menu: Story = renderComponent(storyTemplate).bind({}); -Menu.args = { - storyContent: html` - ${repeat( - x => x.storyItems, - html>` - ${x => x.template ?? menuItemStoryTemplate} - ` - )} - `, -}; - -export const MenuWithDivider: Story = Menu.bind({}); -MenuWithDivider.args = { - storyItems: [ - { storyContent: "Menu Item 1" }, - { storyContent: "Menu Item 2" }, - { template: dividerStoryTemplate }, - { storyContent: "Menu Item 3" }, - { storyContent: "Menu Item 4" }, - ], -}; - -export const MenuWithCheckboxItems: Story = Menu.bind({}); -MenuWithCheckboxItems.args = { - storyItems: [ - { storyContent: "Menu Item 1", role: "menuitemcheckbox" }, - { storyContent: "Menu Item 2", role: "menuitemcheckbox" }, - { storyContent: "Menu Item 3", role: "menuitemcheckbox" }, - ], -}; - -export const MenuWithRadioItems: Story = Menu.bind({}); -MenuWithRadioItems.args = { - storyItems: [ - { storyContent: "Menu Item 1", role: "menuitemradio" }, - { storyContent: "Menu Item 2", role: "menuitemradio" }, - { storyContent: "Menu Item 3", role: "menuitemradio" }, - ], -}; - -export const MenuWithNestedItems: Story = Menu.bind({}); -MenuWithNestedItems.args = { - storyItems: [ - { - storyContent: html` - Menu Item 1 ${repeat(x => x.storyItems, storyTemplate)} - `, - storyItems: [ - { - slot: "submenu", - storyContent: storyContentTemplate, - storyItems: [ - { storyContent: "Menu Item 1.1" }, - { storyContent: "Menu Item 1.2" }, - { storyContent: "Menu Item 1.3" }, - ], - }, - ], - }, - { - storyContent: html` - Menu Item 2 ${repeat(x => x.storyItems, storyTemplate)} - `, - storyItems: [ - { - slot: "submenu", - storyContent: storyContentTemplate, - storyItems: [ - { - storyContent: html` - Menu Item 2.1 ${repeat(x => x.storyItems, storyTemplate)} - `, - storyItems: [ - { - slot: "submenu", - storyContent: storyContentTemplate, - storyItems: [ - { storyContent: "Menu Item 2.1.1" }, - { storyContent: "Menu Item 2.1.2" }, - { storyContent: "Menu Item 2.1.3" }, - ], - }, - ], - }, - { storyContent: "Menu Item 2.2" }, - { storyContent: "Menu Item 2.3" }, - ], - }, - ], - }, - { - storyContent: html` - Menu Item 3 ${repeat(x => x.storyItems, storyTemplate)} - `, - storyItems: [ - { - slot: "submenu", - storyContent: storyContentTemplate, - storyItems: [ - { storyContent: "Menu Item 3.1" }, - { storyContent: "Menu Item 3.2" }, - { storyContent: "Menu Item 3.3" }, - ], - }, - ], - }, - ], -}; - -export const FancyMenu: Story = renderComponent(fancyStoryTemplate).bind({}); -FancyMenu.args = { - storyContent: html` - ${repeat( - x => x.storyItems, - html>` - ${x => x.template ?? fancyMenuItemStoryTemplate} - ` - )} - `, - storyItems: [ - { storyContent: "Fancy Menu Item 1" }, - { storyContent: "Fancy Menu Item 2" }, - { storyContent: "Fancy Menu Item 3" }, - ], -}; - -export const FancyMenuWithItemsWithIcons: Story = FancyMenu.bind({}); -FancyMenuWithItemsWithIcons.args = { - storyContent: html` - ${repeat( - x => x.storyItems, - html>` - ${x => x.template ?? fancyMenuItemStoryTemplate} - ` - )} - `, - storyItems: [ - { - storyContent: html` - - Slotted start icon - `, - }, - { - storyContent: html` - Slotted end icon - - `, - }, - { - storyContent: html` - - Slotted start & end icons - - `, - }, - ], -}; - -export const FancyMenuWithFormControls: Story = FancyMenu.bind({}); -FancyMenuWithFormControls.args = { - storyContent: html` - ${repeat( - x => x.storyItems, - html>` - ${x => x.template ?? fancyMenuItemStoryTemplate} - ` - )} - `, - storyItems: [ - { storyContent: "Fancy Menu Item 1" }, - { storyContent: "Fancy Menu Item 2" }, - { template: dividerStoryTemplate }, - { storyContent: "Fancy Checkbox 1", role: "menuitemcheckbox" }, - { storyContent: "Fancy Checkbox 2", role: "menuitemcheckbox" }, - { template: dividerStoryTemplate }, - { storyContent: "Fancy Radio 1.1", role: "menuitemradio" }, - { storyContent: "Fancy Radio 1.2", role: "menuitemradio" }, - { template: dividerStoryTemplate }, - { storyContent: "Fancy Radio 2.1", role: "menuitemradio" }, - { storyContent: "Fancy Radio 2.2", role: "menuitemradio" }, - ], -}; diff --git a/packages/web-components/fast-foundation/src/number-field/README.md b/packages/web-components/fast-foundation/src/number-field/README.md deleted file mode 100644 index 16fe9a42bf4..00000000000 --- a/packages/web-components/fast-foundation/src/number-field/README.md +++ /dev/null @@ -1,189 +0,0 @@ ---- -id: number-field -title: fast-number-field -sidebar_label: number-field -custom_edit_url: https://github.com/microsoft/fast/edit/master/packages/web-components/fast-foundation/src/number-field/README.md -description: fast-number-field is a web component implementation of a text field number input. ---- - -An implementation of a [text field](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input/text) as a form-connected web-component. The `fast-number-field` supports two visual appearances, outline and filled, with the control defaulting to the outline appearance. - -## Setup - -### Basic Setup - -```ts -import { - provideFASTDesignSystem, - fastNumberField -} from "@microsoft/fast-components"; - -provideFASTDesignSystem() - .register( - fastNumberField() - ); -``` - -### Customizing Glyphs - -```ts -import { - provideFASTDesignSystem, - fastNumberField -} from "@microsoft/fast-components"; - -provideFASTDesignSystem() - .register( - fastNumberField({ - stepDownGlyph: `...your step down glyph...`, - stepUpGlyph: `...your setup up glyph...`, - }) - ); -``` - -## Usage - -```html live - -``` - -## Create your own design - -```ts -import { - NumberField, - NumberFieldOptions, - numberFieldTemplate as template, -} from "@microsoft/fast-foundation"; -import { numberFieldStyles as styles } from "./my-number-field.styles"; - -export const myNumberField = NumberField.compose({ - baseName: "number-field", - styles, - template, - shadowOptions: { - delegatesFocus: true, - }, - stepDownGlyph: `...default step down glyph...`, - stepUpGlyph: `...default setup up glyph...`, -}); -``` - -:::note -This component is built with the expectation that focus is delegated to the input element rendered into the shadow DOM. -::: - -## API - - - -### class: `FormAssociatedNumberField` - -#### Superclass - -| Name | Module | Package | -| -------------- | ------------------------------------------------ | ------- | -| `_NumberField` | src/number-field/number-field.form-associated.ts | | - -#### Mixins - -| Name | Module | Package | -| ---------------- | --------------------------------------- | ------- | -| `FormAssociated` | /src/form-associated/form-associated.js | | - -#### Fields - -| Name | Privacy | Type | Default | Description | Inherited From | -| ------- | ------- | ---- | ------- | ----------- | -------------- | -| `proxy` | | | | | | - -
- - - -### class: `FASTNumberField` - -#### Superclass - -| Name | Module | Package | -| --------------------------- | ------------------------------------------------- | ------- | -| `FormAssociatedNumberField` | /src/number-field/number-field.form-associated.js | | - -#### Fields - -| Name | Privacy | Type | Default | Description | Inherited From | -| --------------- | ------- | --------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------- | -| `readOnly` | public | `boolean` | | When true, the control will be immutable by user interaction. See [readonly HTML attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/readonly) for more information. | | -| `autofocus` | public | `boolean` | | Indicates that this element should get focus after the page finishes loading. See [autofocus HTML attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefautofocus) for more information. | | -| `hideStep` | public | `boolean` | `false` | When true, spin buttons will not be rendered | | -| `placeholder` | public | `string` | | Sets the placeholder value of the element, generally used to provide a hint to the user. | | -| `list` | public | `string` | | Allows associating a [datalist](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/datalist) to the element by https://developer.mozilla.org/en-US/docs/Web/API/Element/id. | | -| `maxlength` | public | `number` | | The maximum number of characters a user can enter. | | -| `minlength` | public | `number` | | The minimum number of characters a user can enter. | | -| `size` | public | `number` | | Sets the width of the element to a specified number of characters. | | -| `step` | public | `number` | `1` | Amount to increment or decrement the value by | | -| `max` | public | `number` | | The maximum the value can be | | -| `min` | public | `number` | | The minimum the value can be | | -| `valueAsNumber` | public | `number` | | The value property, typed as a number. | | -| `proxy` | | | | | FormAssociatedNumberField | - -#### Methods - -| Name | Privacy | Description | Parameters | Return | Inherited From | -| ---------- | ------- | ------------------------------------------------- | ---------- | ------ | -------------- | -| `validate` | public | {@inheritDoc (FormAssociated:interface).validate} | | `void` | | -| `stepUp` | public | Increments the value using the step value | | `void` | | -| `stepDown` | public | Decrements the value using the step value | | `void` | | -| `select` | public | Selects all the text in the number field | | `void` | | - -#### Events - -| Name | Type | Description | Inherited From | -| -------- | ---- | -------------------------------------------------------- | -------------- | -| `input` | | Fires a custom 'input' event when the value has changed | | -| `change` | | Fires a custom 'change' event when the value has changed | | - -#### Attributes - -| Name | Field | Inherited From | -| ------------- | ----------- | -------------- | -| `readonly` | readOnly | | -| | autofocus | | -| `hide-step` | hideStep | | -| `placeholder` | placeholder | | -| `list` | list | | -| | maxlength | | -| | minlength | | -| | size | | -| | step | | -| | max | | -| | min | | - -#### CSS Parts - -| Name | Description | -| -------------- | ---------------------------------------------------------------------------------------- | -| `label` | The label | -| `control` | The logical control, the element wrapping the input field, including start and end slots | -| `field` | The element representing the input field | -| `step-buttons` | The step up and step down controls | -| `step-up` | The step up control | -| `step-down` | The step down control | - -#### Slots - -| Name | Description | -| ---------------- | ----------------------------------------------------------- | -| `start` | Content which can be provided before the number field input | -| `end` | Content which can be provided after the number field input | -| | The default slot for the label | -| `step-up-icon` | The icon for the step up control | -| `step-down-icon` | The icon for the step down control | - -
- - -## Additional resources - -* [Component explorer examples](https://explore.fast.design/components/fast-number-field) -* [Component technical specification](https://github.com/microsoft/fast/blob/master/packages/web-components/fast-foundation/src/number-field/number-field.spec.md) \ No newline at end of file diff --git a/packages/web-components/fast-foundation/src/number-field/index.ts b/packages/web-components/fast-foundation/src/number-field/index.ts deleted file mode 100644 index 84811c2307d..00000000000 --- a/packages/web-components/fast-foundation/src/number-field/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { FASTNumberField } from "./number-field.js"; -export type { NumberFieldOptions } from "./number-field.js"; -export { numberFieldTemplate } from "./number-field.template.js"; diff --git a/packages/web-components/fast-foundation/src/number-field/number-field.form-associated.ts b/packages/web-components/fast-foundation/src/number-field/number-field.form-associated.ts deleted file mode 100644 index cf100a9e18e..00000000000 --- a/packages/web-components/fast-foundation/src/number-field/number-field.form-associated.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { FASTElement } from "@microsoft/fast-element"; -import { FormAssociated } from "../form-associated/form-associated.js"; - -class _NumberField extends FASTElement {} -interface _NumberField extends FormAssociated {} - -/** - * A form-associated base class for the {@link @microsoft/fast-foundation#(NumberField:class)} component. - * - * @beta - */ -export class FormAssociatedNumberField extends FormAssociated(_NumberField) { - proxy = document.createElement("input"); -} diff --git a/packages/web-components/fast-foundation/src/number-field/number-field.pw.spec.ts b/packages/web-components/fast-foundation/src/number-field/number-field.pw.spec.ts deleted file mode 100644 index b8e63e7dfaa..00000000000 --- a/packages/web-components/fast-foundation/src/number-field/number-field.pw.spec.ts +++ /dev/null @@ -1,714 +0,0 @@ -import { spinalCase } from "@microsoft/fast-web-utilities"; -import { expect, test } from "@playwright/test"; -import type { Locator, Page } from "@playwright/test"; -import { fixtureURL } from "../__test__/helpers.js"; -import type { FASTNumberField } from "./number-field.js"; - -test.describe("NumberField", () => { - let page: Page; - let element: Locator; - let root: Locator; - let control: Locator; - - test.beforeAll(async ({ browser }) => { - page = await browser.newPage(); - - element = page.locator("fast-number-field"); - - root = page.locator("#storybook-root"); - - control = element.locator(".field"); - - await page.goto(fixtureURL("number-field--number-field")); - - await element.waitFor({ state: "attached" }); - }); - - test.afterAll(async () => { - await page.close(); - }); - - test("should initialize to the provided value attribute if set pre-connection", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element).toHaveJSProperty("value", "10"); - }); - - test("should set the `autofocus` attribute on the internal control", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(control).toHaveAttribute("autofocus"); - }); - - test("should set the `disabled` attribute on the internal control", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - await expect(control).toHaveAttribute("disabled"); - }); - - test("should set the `readonly` attribute on the internal control", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - await expect(control).toHaveAttribute("readonly"); - }); - - test("should set the `required` attribute on the internal control", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - await expect(control).toHaveAttribute("required"); - }); - - for (const [attribute, value] of Object.entries({ - min: 0, - max: 10, - list: "listId", - maxlength: 14, - minlength: 8, - placeholder: "placeholder", - size: 8, - ariaAtomic: "true", - ariaBusy: "false", - ariaControls: "testId", - ariaCurrent: "page", - ariaDescribedby: "testId", - ariaDetails: "testId", - ariaDisabled: "true", - ariaErrormessage: "test", - ariaFlowto: "testId", - ariaHaspopup: "true", - ariaHidden: "true", - ariaInvalid: "spelling", - ariaKeyshortcuts: "F4", - ariaLabel: "Foo label", - ariaLabelledby: "testId", - ariaLive: "polite", - ariaOwns: "testId", - ariaRelevant: "removals", - ariaRoledescription: "slide", - })) { - const attrToken = spinalCase(attribute); - - test(`should set the \`${attrToken}\` attribute to "${value}" on the internal control`, async () => { - await root.evaluate( - (node, { attrToken, value }) => { - node.innerHTML = /* html */ ` - - `; - }, - { attrToken, value } - ); - - await expect(control).toHaveAttribute(attrToken, `${value}`); - }); - } - - test("should set `value` property equal to the `max` property when value is greater than max", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await control.fill("11"); - - await expect(element).toHaveJSProperty("value", "10"); - }); - - test("should set `value` property equal to the `max` property when max is less than the value", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await element.evaluate((node: FASTNumberField) => { - node.max = 10; - }); - - await (await element.elementHandle())?.waitForElementState("stable"); - - await expect(element).toHaveJSProperty("value", "10"); - }); - - test("should set the `value` property equal to the `min` property when value is less than min", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await control.fill("9"); - - await expect(element).toHaveJSProperty("value", "10"); - - await expect(control).toHaveValue("10"); - }); - - test("should update the `value` property when the `min` property is greater than the `value`", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await element.evaluate((node: FASTNumberField) => { - node.min = 20; - }); - - await expect(element).toHaveJSProperty("value", "20"); - - await expect(control).toHaveValue("20"); - }); - - test("should set the `max` property equal to the `min` property when min is greater than max", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element).toHaveJSProperty("max", 10); - - await expect(control).toHaveJSProperty("max", "10"); - }); - - test("should initialize to the provided `value` attribute if set post-connection", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await element.evaluate((node: FASTNumberField) => { - node.value = "10"; - }); - - await expect(element).toHaveJSProperty("value", "10"); - }); - - test('should fire a "change" event when the internal control emits a "change" event', async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - const [wasChanged] = await Promise.all([ - element.evaluate( - node => - new Promise(resolve => { - node.addEventListener("change", () => resolve(true)); - }) - ), - - // FIXME: Playwright's keyboard API is not working as expected. - control.evaluate(node => - node.dispatchEvent(new KeyboardEvent("change", { key: "1" })) - ), - ]); - - expect(wasChanged).toBeTruthy(); - }); - - test('should fire an "input" event when incrementing or decrementing', async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - const [wasIncreased] = await Promise.all([ - element.evaluate( - node => - new Promise(resolve => { - node.addEventListener("input", () => resolve(true), { - once: true, - }); - }) - ), - element.evaluate((node: FASTNumberField) => node.stepUp()), - ]); - - expect(wasIncreased).toBeTruthy(); - - const [wasDecreased] = await Promise.all([ - element.evaluate( - node => - new Promise(resolve => { - node.addEventListener("input", () => resolve(true), { - once: true, - }); - }) - ), - element.evaluate((node: FASTNumberField) => node.stepDown()), - ]); - - expect(wasDecreased).toBeTruthy(); - }); - - test("should allow positive float numbers", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await control.fill("1.1"); - - await expect(element).toHaveJSProperty("value", "1.1"); - - await expect(control).toHaveValue("1.1"); - }); - - test("should allow negative float numbers", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await control.fill("-1.1"); - - await expect(element).toHaveJSProperty("value", "-1.1"); - - await expect(control).toHaveValue("-1.1"); - }); - - test("should allow positive integer numbers", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await control.fill("1"); - - await expect(element).toHaveJSProperty("value", "1"); - - await expect(control).toHaveValue("1"); - }); - - test("should allow negative integer numbers", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await control.fill("-1"); - - await expect(element).toHaveJSProperty("value", "-1"); - - await expect(control).toHaveValue("-1"); - }); - - // TODO: This test doesn't account for the `e` character. - // See https://github.com/microsoft/fast/issues/6251 - test("should disallow non-numeric characters", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await control.fill("a"); - - await expect(element).toHaveJSProperty("value", ""); - - await expect(control).toHaveValue(""); - }); - - test('should set the `step` property to "1" by default', async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(control).toHaveAttribute("step", "1"); - }); - - test("should update the `step` attribute on the internal control when the `step` property is changed", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await element.evaluate((node: FASTNumberField) => { - node.step = 2; - }); - - await expect(control).toHaveAttribute("step", "2"); - }); - - test("should increment the `value` property by the step amount when the `stepUp()` method is invoked", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await element.evaluate((node: FASTNumberField) => { - node.stepUp(); - }); - - await expect(element).toHaveJSProperty("value", "7"); - - await expect(control).toHaveValue("7"); - }); - - test("should decrement the `value` property by the step amount when the `stepDown()` method is invoked", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await element.evaluate((node: FASTNumberField) => { - node.stepDown(); - }); - - await expect(element).toHaveJSProperty("value", "3"); - - await expect(control).toHaveValue("3"); - }); - - test("should offset an undefined `value` from zero when stepped down", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await element.evaluate((node: FASTNumberField) => { - node.stepDown(); - }); - - await expect(element).toHaveJSProperty("value", "-2"); - - await expect(control).toHaveValue("-2"); - }); - - test("should offset an undefined `value` from zero when stepped up", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await element.evaluate((node: FASTNumberField) => { - node.stepUp(); - }); - - await expect(element).toHaveJSProperty("value", "2"); - - await expect(control).toHaveValue("2"); - }); - - test("should offset the `value` from zero after stepping down when `min` is a negative value", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await element.evaluate((node: FASTNumberField) => { - node.stepDown(); - }); - - await expect(element).toHaveJSProperty("value", "0"); - - await expect(control).toHaveValue("0"); - }); - - test("should offset the `value` from zero after stepping up when `min` is a negative value", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await element.evaluate((node: FASTNumberField) => { - node.stepUp(); - }); - - await expect(element).toHaveJSProperty("value", "0"); - - await expect(control).toHaveValue("0"); - }); - - test("should set `value` to match `min` after stepping down when `min` is greater than 0", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await element.evaluate((node: FASTNumberField) => { - node.stepDown(); - }); - - await expect(element).toHaveJSProperty("value", "10"); - - await expect(control).toHaveValue("10"); - }); - - test("should set `value` to match `min` after stepping up when `min` is greater than 0", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await element.evaluate((node: FASTNumberField) => { - node.stepUp(); - }); - - await expect(element).toHaveJSProperty("value", "10"); - - await expect(control).toHaveValue("10"); - }); - - /* eslint-disable-next-line max-len */ - test("should set the `value` to match `max` after stepping down when `value` is undefined and `min` and `max` are less than zero", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await element.evaluate((node: FASTNumberField) => { - node.stepDown(); - }); - - await expect(element).toHaveJSProperty("value", "-5"); - - await expect(control).toHaveValue("-5"); - }); - /* eslint-disable-next-line max-len */ - test("should set the `value` to match `max` after stepping up when `value` is undefined and `min` and `max` are less than zero", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await element.evaluate((node: FASTNumberField) => { - node.stepUp(); - }); - - await expect(element).toHaveJSProperty("value", "-5"); - - await expect(control).toHaveValue("-5"); - }); - - test("should update the proxy value when stepping down", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await element.evaluate((node: FASTNumberField) => { - node.stepDown(); - }); - - await expect(control).toHaveValue("3"); - - await expect(element).toHaveJSProperty("value", "3"); - - expect(await element.evaluate((node: FASTNumberField) => node.proxy.value)).toBe( - "3" - ); - }); - - test("should update the proxy value when stepping up", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await element.evaluate((node: FASTNumberField) => { - node.stepUp(); - }); - - await expect(control).toHaveValue("7"); - - await expect(element).toHaveJSProperty("value", "7"); - - expect(await element.evaluate((node: FASTNumberField) => node.proxy.value)).toBe( - "7" - ); - }); - - test("should correct rounding errors when stepping down", async () => { - const step = 0.1; - const value = 0.2; - - await root.evaluate( - (node, { step, value }) => { - node.innerHTML = /* html */ ` - - `; - }, - { step, value } - ); - - for (let i = 1; i < 10; i++) { - await element.evaluate((node: FASTNumberField) => { - node.stepUp(); - }); - - await expect(control).toHaveValue( - (value + step * i).toPrecision(2).replace(/\.?0+$/, "") - ); - } - }); - - test("should not render step controls when `hide-step` attribute is present", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - const controls = element.locator(".controls"); - - await expect(controls).toBeHidden(); - }); - - test("should not render step controls when `readonly` attribute is present", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - const controls = element.locator(".controls"); - - await expect(controls).toHaveCount(0); - }); - - test("should allow setting `valueAsNumber` property with a number", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await element.evaluate((node: FASTNumberField) => { - node.valueAsNumber = 18; - }); - - await expect(element).toHaveJSProperty("value", "18"); - }); - - test("should allow reading the `valueAsNumber` property as number", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element).toHaveJSProperty("valueAsNumber", 18); - }); - - test.describe("when the owning form's reset() method is invoked", () => { - test('should reset its `value` property to "" if no `value` attribute is set', async () => { - const form = page.locator("form"); - - await root.evaluate(node => { - node.innerHTML = /* html */ ` -
- -
- `; - }); - - await element.evaluate((node: FASTNumberField) => { - node.value = "10"; - }); - - await expect(element).toHaveJSProperty("value", "10"); - - await form.evaluate((node: HTMLFormElement) => node.reset()); - - await expect(element).toHaveJSProperty("value", ""); - }); - - test("should reset the `value` property to match the `value` attribute", async () => { - const form = page.locator("form"); - - await root.evaluate(node => { - node.innerHTML = /* html */ ` -
- -
- `; - }); - - await expect(element).toHaveJSProperty("value", "10"); - - await element.evaluate((node: FASTNumberField) => { - node.value = "20"; - }); - - await expect(element).toHaveJSProperty("value", "20"); - - await form.evaluate((node: HTMLFormElement) => node.reset()); - - await expect(element).toHaveJSProperty("value", "10"); - }); - /* eslint-disable-next-line max-len */ - test("should put the control into a clean state, where `value` attribute modifications change the `value` property prior to user or programmatic interaction", async () => { - const form = page.locator("form"); - - await root.evaluate(node => { - node.innerHTML = /* html */ ` -
- -
- `; - }); - - await expect(element).toHaveJSProperty("value", "10"); - - await element.evaluate((node: FASTNumberField) => { - node.value = "20"; - }); - - await expect(element).toHaveJSProperty("value", "20"); - - await form.evaluate((node: HTMLFormElement) => { - node.reset(); - }); - - await expect(element).toHaveJSProperty("value", "10"); - - await element.evaluate(node => { - node.setAttribute("value", "30"); - }); - - await expect(element).toHaveJSProperty("value", "30"); - }); - }); -}); diff --git a/packages/web-components/fast-foundation/src/number-field/number-field.spec.md b/packages/web-components/fast-foundation/src/number-field/number-field.spec.md deleted file mode 100644 index d201a07df75..00000000000 --- a/packages/web-components/fast-foundation/src/number-field/number-field.spec.md +++ /dev/null @@ -1,112 +0,0 @@ -# Number Field - -## Overview - -An implementation of a generic input for numerical values as a form-connected web-component. - -### Use Cases - -Used anywhere an author might otherwise use: -- input[type="number"] - -### Features - -1. Focus Delegation - ---- - -### API - -Extends FAST Element - -*Component Name* -- `fast-number-field` - -*Attrs* - Adapted from [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/number) -- `autofocus` - automatically focuses the control -- `readonly` - the text field should be submitted with the form but should not be editable. -- `placeholder` - an exemplar value to display in the input field whenever it is empty -- `required` - boolean value that sets the field as required -- `value` - string value of the text field, can be an empty string -- `disabled` - disables the control -- `list` - the id of the `` element that contains the optional pre-defined autocomplete options -- `maxlength` - the maximum number of characters the input should accept -- `minlength` - the minimum number of characters long the input can be and still be considered valid -- `name` - the name of the control -- `size` - a number indicating how many characters wide the input field should be -- `appearance` - enum - - outline (default) - - filled -- `max` - maximum numerical value -- `min` - minimum numerical value -- `step` - number amount to increment or decrement the value - -*Events* -- `change: CustomEvent` - - no custom data - - bubbles - -### Anatomy and Appearance - -```HTML - - -
- - -
- -
- -``` - - -*Screenshots below are of the basic appearance of the component and are not exhaustive.* - -| State | Image | -| ----- | ----- | - -*Slot Names* -- default - the label content -- start - often times a glyph, icon, or button precedes input -- end - often times a glyph, icon, or button follows the input - -*Host Classes* -- disabled -- required -- readonly - -*CSS Parts* -- label -- root -- start -- end -- control -- step-buttons - ---- - -## Implementation - -### States - -**disabled**: `true` or `false` - when disabled, the value will not be changeable through user interaction. It should also not expose it's value to a form submission. - -**readonly**: `true` or `false` - when readonly, the value will not be changeable through user interaction. The value will still be exposed to forms on submission. - -### Accessibility - -The input element inside the shadow-dom of the checkbox will be a focusable element. With this in mind, so long as the text field receives focus, assistive technology should treat it as such. - -### Globalization - -Before and after content should swap in LTR presentations. - -### Test Plan - -While testing is still TBD for our web components, I would expect this to align with the testing strategy and not require any additional test support. - ---- - -## Next Steps -Adding mechanisms, slots, and data for surfacing validation error messages. diff --git a/packages/web-components/fast-foundation/src/number-field/number-field.template.ts b/packages/web-components/fast-foundation/src/number-field/number-field.template.ts deleted file mode 100644 index 8713194cf27..00000000000 --- a/packages/web-components/fast-foundation/src/number-field/number-field.template.ts +++ /dev/null @@ -1,94 +0,0 @@ -import type { ElementViewTemplate } from "@microsoft/fast-element"; -import { html, ref, slotted, when } from "@microsoft/fast-element"; -import { endSlotTemplate, startSlotTemplate } from "../patterns/index.js"; -import { staticallyCompose } from "../utilities/template-helpers.js"; -import type { FASTNumberField, NumberFieldOptions } from "./number-field.js"; - -/** - * The template for the {@link @microsoft/fast-foundation#(FASTNumberField:class)} component. - * @public - */ -export function numberFieldTemplate( - options: NumberFieldOptions = {} -): ElementViewTemplate { - return html` - -
- ${startSlotTemplate(options)} - - ${when( - x => !x.hideStep && !x.readOnly && !x.disabled, - html` -
-
- - ${staticallyCompose(options.stepUpIcon)} - -
-
- - ${staticallyCompose(options.stepDownIcon)} - -
-
- ` - )} - ${endSlotTemplate(options)} -
- `; -} diff --git a/packages/web-components/fast-foundation/src/number-field/number-field.ts b/packages/web-components/fast-foundation/src/number-field/number-field.ts deleted file mode 100644 index 915dba5d95c..00000000000 --- a/packages/web-components/fast-foundation/src/number-field/number-field.ts +++ /dev/null @@ -1,404 +0,0 @@ -import { - attr, - nullableNumberConverter, - observable, - Updates, -} from "@microsoft/fast-element"; -import { keyArrowDown, keyArrowUp } from "@microsoft/fast-web-utilities"; -import type { StaticallyComposableHTML } from "../utilities/template-helpers.js"; -import { StartEnd } from "../patterns/start-end.js"; -import type { StartEndOptions } from "../patterns/start-end.js"; -import { applyMixins } from "../utilities/apply-mixins.js"; -import { DelegatesARIATextbox } from "../text-field/text-field.js"; -import { FormAssociatedNumberField } from "./number-field.form-associated.js"; - -/** - * Number Field configuration options - * @public - */ -export type NumberFieldOptions = StartEndOptions & { - stepDownIcon?: StaticallyComposableHTML; - stepUpIcon?: StaticallyComposableHTML; -}; - -/** - * A Number Field Custom HTML Element. - * Based largely on the {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/number | element }. - * - * @slot start - Content which can be provided before the number field input - * @slot end - Content which can be provided after the number field input - * @slot - The default slot for the label - * @slot step-up-icon - The icon for the step up control - * @slot step-down-icon - The icon for the step down control - * @csspart label - The label - * @csspart control - The logical control, the element wrapping the input field, including start and end slots - * @csspart field - The element representing the input field - * @csspart step-buttons - The step up and step down controls - * @csspart step-up - The step up control - * @csspart step-down - The step down control - * @fires input - Fires a custom 'input' event when the value has changed - * @fires change - Fires a custom 'change' event when the value has changed - * - * @public - */ -export class FASTNumberField extends FormAssociatedNumberField { - /** - * When true, the control will be immutable by user interaction. - * See {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/readonly | readonly HTML attribute} for more information. - * @public - * @remarks - * HTML Attribute: readonly - */ - @attr({ attribute: "readonly", mode: "boolean" }) - public readOnly: boolean; - - /** - * Indicates that this element should get focus after the page finishes loading. - * See {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefautofocus | autofocus HTML attribute} - * for more information. - * @public - * @remarks - * HTML Attribute: autofocus - */ - @attr({ mode: "boolean" }) - public autofocus: boolean; - - /** - * When true, spin buttons will not be rendered - * @public - * @remarks - * HTML Attribute: autofocus - */ - @attr({ attribute: "hide-step", mode: "boolean" }) - public hideStep: boolean = false; - - /** - * Sets the placeholder value of the element, generally used to provide a hint to the user. - * @public - * @remarks - * HTML Attribute: placeholder - * Using this attribute does is not a valid substitute for a labeling element. - */ - @attr - public placeholder: string; - - /** - * Allows associating a {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/datalist | datalist} - * to the element by {@link https://developer.mozilla.org/en-US/docs/Web/API/Element/id}. - * @public - * @remarks - * HTML Attribute: list - */ - @attr - public list: string; - - /** - * The maximum number of characters a user can enter. - * @public - * @remarks - * HTMLAttribute: maxlength - */ - @attr({ converter: nullableNumberConverter }) - public maxlength: number; - - /** - * The minimum number of characters a user can enter. - * @public - * @remarks - * HTMLAttribute: minlength - */ - @attr({ converter: nullableNumberConverter }) - public minlength: number; - - /** - * Sets the width of the element to a specified number of characters. - * @public - * @remarks - * HTMLAttribute: size - */ - @attr({ converter: nullableNumberConverter }) - public size: number; - - /** - * Amount to increment or decrement the value by - * @public - * @remarks - * HTMLAttribute: step - */ - @attr({ converter: nullableNumberConverter }) - public step: number = 1; - - /** - * The maximum the value can be - * @public - * @remarks - * HTMLAttribute: max - */ - @attr({ converter: nullableNumberConverter }) - public max: number; - - /** - * Ensures that the max is greater than the min and that the value - * is less than the max - * @param previous - the previous max value - * @param next - updated max value - * - * @internal - */ - public maxChanged(previous: number, next: number): void { - this.max = Math.max(next, this.min ?? next); - const min = Math.min(this.min, this.max); - if (this.min !== undefined && this.min !== min) { - this.min = min; - } - this.value = this.getValidValue(this.value); - } - - /** - * The minimum the value can be - * @public - * @remarks - * HTMLAttribute: min - */ - @attr({ converter: nullableNumberConverter }) - public min: number; - - /** - * Ensures that the min is less than the max and that the value - * is greater than the min - * @param previous - previous min value - * @param next - updated min value - * - * @internal - */ - public minChanged(previous: number, next: number): void { - this.min = Math.min(next, this.max ?? next); - const max = Math.max(this.min, this.max); - if (this.max !== undefined && this.max !== max) { - this.max = max; - } - this.value = this.getValidValue(this.value); - } - - /** - * The default slotted items - * @internal - */ - @observable - public defaultSlottedNodes: Node[]; - - /** - * A reference to the internal field element - * @internal - */ - public field: HTMLInputElement; - - /** - * Flag to indicate that the value change is from the user input - * @internal - */ - private isUserInput: boolean = false; - - /** - * The value property, typed as a number. - * - * @public - */ - public get valueAsNumber(): number { - return parseFloat(super.value); - } - - public set valueAsNumber(next: number) { - this.value = next.toString(); - } - - /** - * Validates that the value is a number between the min and max - * @param previous - previous stored value - * @param next - value being updated - * @internal - */ - public valueChanged(previous: string, next: string): void { - const value = this.getValidValue(next); - - if (next !== value) { - this.value = value; - return; - } - - if (this.$fastController.isConnected && this.field?.value !== value) { - this.field.value = this.value; - } - - super.valueChanged(previous, this.value); - - if (previous !== undefined && !this.isUserInput) { - this.$emit("input"); - this.$emit("change"); - } - - this.isUserInput = false; - } - - /** {@inheritDoc (FormAssociated:interface).validate} */ - public validate(): void { - super.validate(this.field); - } - - /** - * Sets the internal value to a valid number between the min and max properties - * @param value - user input - * - * @internal - */ - private getValidValue(value: string): string { - let validValue: number | string = parseFloat(parseFloat(value).toPrecision(12)); - if (isNaN(validValue)) { - validValue = ""; - } else { - validValue = Math.min(validValue, this.max ?? validValue); - validValue = Math.max(validValue, this.min ?? validValue).toString(); - } - - return validValue; - } - - /** - * Increments the value using the step value - * - * @public - */ - public stepUp(): void { - const value = parseFloat(this.value); - const stepUpValue = !isNaN(value) - ? value + this.step - : this.min > 0 - ? this.min - : this.max < 0 - ? this.max - : !this.min - ? this.step - : 0; - - this.value = stepUpValue.toString(); - } - - /** - * Decrements the value using the step value - * - * @public - */ - public stepDown(): void { - const value = parseFloat(this.value); - const stepDownValue = !isNaN(value) - ? value - this.step - : this.min > 0 - ? this.min - : this.max < 0 - ? this.max - : !this.min - ? 0 - this.step - : 0; - - this.value = stepDownValue.toString(); - } - - /** - * Sets up the initial state of the number field - * @internal - */ - public connectedCallback(): void { - super.connectedCallback(); - - this.proxy.setAttribute("type", "number"); - this.validate(); - this.field.value = this.value; - - if (this.autofocus) { - Updates.enqueue(() => { - this.focus(); - }); - } - } - - /** - * Selects all the text in the number field - * - * @public - */ - public select(): void { - this.field.select(); - - /** - * The select event does not permeate the shadow DOM boundary. - * This fn effectively proxies the select event, - * emitting a `select` event whenever the internal - * control emits a `select` event - */ - this.$emit("select"); - } - - /** - * Handles the internal input field's `input` event - * @internal - */ - public handleTextInput(): void { - this.field.value = this.field.value.replace(/[^0-9\-+e.]/g, ""); - this.isUserInput = true; - this.value = this.field.value; - } - - /** - * Change event handler for inner control. - * @remarks - * "Change" events are not `composable` so they will not - * permeate the shadow DOM boundary. This fn effectively proxies - * the change event, emitting a `change` event whenever the internal - * control emits a `change` event - * @internal - */ - public handleChange(): void { - this.$emit("change"); - } - - /** - * Handles the internal control's `keydown` event - * @internal - */ - public handleKeyDown(e: KeyboardEvent): boolean { - if (this.disabled || this.readOnly) { - return true; - } - const key = e.key; - - switch (key) { - case keyArrowUp: - this.stepUp(); - return false; - - case keyArrowDown: - this.stepDown(); - return false; - } - - return true; - } - - /** - * Handles populating the input field with a validated value when - * leaving the input field. - * @internal - */ - public handleBlur(): void { - this.field.value = this.value; - } -} - -/** - * Mark internal because exporting class and interface of the same name - * confuses API documenter. - * TODO: https://github.com/microsoft/fast/issues/3317 - * @internal - */ -export interface FASTNumberField extends StartEnd, DelegatesARIATextbox {} -applyMixins(FASTNumberField, StartEnd, DelegatesARIATextbox); diff --git a/packages/web-components/fast-foundation/src/number-field/stories/number-field.register.ts b/packages/web-components/fast-foundation/src/number-field/stories/number-field.register.ts deleted file mode 100644 index 8f2b9249f6f..00000000000 --- a/packages/web-components/fast-foundation/src/number-field/stories/number-field.register.ts +++ /dev/null @@ -1,154 +0,0 @@ -import { css } from "@microsoft/fast-element"; -import chevronDownIcon from "../../../statics/svg/chevron_down_12_regular.svg"; -import chevronUpIcon from "../../../statics/svg/chevron_up_12_regular.svg"; -import { FASTNumberField } from "../number-field.js"; -import { numberFieldTemplate } from "../number-field.template.js"; - -const styles = css` - :host { - display: inline-block; - font: var(--type-ramp-base-font-size) / var(--type-ramp-base-line-height) - var(--body-font); - outline: none; - user-select: none; - } - - :host([hidden]) { - display: none; - } - - .control { - align-items: center; - background: var(--neutral-fill-input-rest); - border-radius: calc(var(--control-corner-radius) * 1px); - border: calc(var(--stroke-width) * 1px) solid var(--accent-fill-rest); - box-sizing: border-box; - color: var(--neutral-foreground-rest); - fill: currentcolor; - display: flex; - flex-direction: row; - height: calc( - (var(--base-height-multiplier) + var(--density)) * var(--design-unit) * 1px - ); - position: relative; - } - - .field { - appearance: none; - background: transparent; - border: 0; - border: none; - color: inherit; - font: inherit; - height: calc(100% - 4px); - flex-grow: 1; - margin-bottom: auto; - margin-top: auto; - padding: 0 calc(var(--design-unit) * 2px + 1px); - } - - .field:hover, - .field:focus-visible, - .field:disabled, - .field:active { - outline: none; - } - - .step-buttons { - opacity: 0; - } - - .label { - color: var(--neutral-foreground-rest); - cursor: pointer; - display: block; - font: inherit; - margin-bottom: 4px; - } - - .label__hidden { - display: none; - visibility: hidden; - } - - ::slotted([slot="start"]), - ::slotted([slot="end"]), - .field, - .step-buttons { - align-self: center; - } - - ::slotted([slot="start"]), - ::slotted([slot="end"]) { - display: flex; - margin-inline: 11px; - } - - .field.icon-only { - line-height: 0; - padding: 0; - } - - .step-up, - .step-down { - cursor: pointer; - display: flex; - padding: 4px; - } - - :host(:hover:not([disabled])) .control { - background: var(--neutral-fill-input-hover); - border-color: var(--accent-fill-hover); - } - - :host(:active:not([disabled])) .control { - background: var(--neutral-fill-input-hover); - border-color: var(--accent-fill-active); - } - - :host(:focus-within:not([disabled])) .control { - border-color: var(--focus-stroke-outer); - box-shadow: 0 0 0 calc(var(--focus-stroke-width) * 1px) var(--focus-stroke-outer) - inset; - } - - :host(:hover:not([disabled])) .step-buttons, - :host(:focus-within:not([disabled])) .step-buttons { - opacity: 1; - } - - :host([appearance="filled"]) .control { - background: var(--neutral-fill-rest); - } - - :host([appearance="filled"]:hover:not([disabled])) .control { - background: var(--neutral-fill-hover); - } - - :host([disabled]) .label, - :host([readonly]) .label, - :host([readonly]) .field, - :host([disabled]) .field { - cursor: not-allowed; - } - - :host([disabled]) { - opacity: var(--disabled-opacity); - } - - :host([disabled]) .field { - border-color: var(--neutral-stroke-rest); - } -`; - -FASTNumberField.define({ - name: "fast-number-field", - styles, - template: numberFieldTemplate({ - stepDownIcon: chevronDownIcon, - stepUpIcon: chevronUpIcon, - }), - shadowOptions: { - delegatesFocus: true, - }, -}); diff --git a/packages/web-components/fast-foundation/src/number-field/stories/number-field.stories.ts b/packages/web-components/fast-foundation/src/number-field/stories/number-field.stories.ts deleted file mode 100644 index 6e6992efa98..00000000000 --- a/packages/web-components/fast-foundation/src/number-field/stories/number-field.stories.ts +++ /dev/null @@ -1,115 +0,0 @@ -import { html } from "@microsoft/fast-element"; -import type { Meta, Story, StoryArgs } from "../../__test__/helpers.js"; -import { renderComponent } from "../../__test__/helpers.js"; -import type { FASTNumberField } from "../number-field.js"; - -const storyTemplate = html>` - - ${x => x.storyContent} - -`; - -export default { - title: "Number Field", - args: { - readOnly: false, - required: false, - autofocus: false, - disabled: false, - hideStep: false, - storyContent: "Number Field", - }, - argTypes: { - autofocus: { control: "boolean" }, - disabled: { control: "boolean" }, - hideStep: { control: "boolean" }, - step: { control: "number" }, - list: { control: "text" }, - max: { control: "number" }, - maxlength: { control: "number" }, - min: { control: "number" }, - minlength: { control: "number" }, - placeholder: { control: "text" }, - readOnly: { control: "boolean" }, - required: { control: "boolean" }, - size: { control: "number" }, - value: { control: "number" }, - valueAsNumber: { control: "number" }, - ariaAtomic: { control: "text" }, - ariaBusy: { control: "text" }, - ariaControls: { control: "text" }, - ariaCurrent: { control: "text" }, - ariaDescribedby: { control: "text" }, - ariaDetails: { control: "text" }, - ariaDisabled: { control: "text" }, - ariaErrormessage: { control: "text" }, - ariaFlowto: { control: "text" }, - ariaHaspopup: { control: "text" }, - ariaHidden: { control: "text" }, - ariaInvalid: { control: "text" }, - ariaKeyshortcuts: { control: "text" }, - ariaLabel: { control: "text" }, - ariaLabelledby: { control: "text" }, - ariaLive: { control: "text" }, - ariaOwns: { control: "text" }, - ariaRelevant: { control: "text" }, - ariaRoledescription: { control: "text" }, - storyContent: { table: { disable: true } }, - }, -} as Meta; - -export const NumberField: Story = renderComponent(storyTemplate).bind( - {} -); - -export const NumberFieldWithSlottedStartEnd: Story = NumberField.bind( - {} -); -NumberFieldWithSlottedStartEnd.args = { - storyContent: html` - - Number Field - - `, -}; - -export const NumberFieldInForm: Story = renderComponent(html` -
- ${storyTemplate} - Submit -
-`).bind({}); diff --git a/packages/web-components/fast-foundation/src/patterns/aria-global.ts b/packages/web-components/fast-foundation/src/patterns/aria-global.ts deleted file mode 100644 index 5c12f192a40..00000000000 --- a/packages/web-components/fast-foundation/src/patterns/aria-global.ts +++ /dev/null @@ -1,253 +0,0 @@ -import { attr } from "@microsoft/fast-element"; - -/** - * Some states and properties are applicable to all host language elements regardless of whether a role is applied. - * The following global states and properties are supported by all roles and by all base markup elements. - * {@link https://www.w3.org/TR/wai-aria-1.1/#global_states} - * - * This is intended to be used as a mixin. Be sure you extend FASTElement. - * - * @public - */ -export class ARIAGlobalStatesAndProperties { - /** - * Indicates whether assistive technologies will present all, or only parts of, - * the changed region based on the change notifications defined by the aria-relevant attribute. - * {@link https://www.w3.org/TR/wai-aria-1.1/#aria-atomic} - * - * @public - * @remarks - * HTML Attribute: aria-atomic - */ - @attr({ attribute: "aria-atomic" }) - public ariaAtomic: "true" | "false" | string | null; - - /** - * Indicates an element is being modified and that assistive technologies MAY want to wait - * until the modifications are complete before exposing them to the user. - * {@link https://www.w3.org/TR/wai-aria-1.1/#aria-busy} - * - * @public - * @remarks - * HTML Attribute: aria-busy - */ - @attr({ attribute: "aria-busy" }) - public ariaBusy: "true" | "false" | string | null; - - /** - * Identifies the element (or elements) whose contents or presence are controlled by the current element. - * - * {@link https://www.w3.org/TR/wai-aria-1.1/#aria-controls} - * @public - * @remarks - * HTML Attribute: aria-controls - */ - @attr({ attribute: "aria-controls" }) - public ariaControls: string | null; - - /** - * Indicates the element that represents the current item within a container or set of related elements. - * - * {@link https://www.w3.org/TR/wai-aria-1.1/#aria-current} - * @public - * @remarks - * HTML Attribute: aria-current - */ - @attr({ attribute: "aria-current" }) - public ariaCurrent: - | "page" - | "step" - | "location" - | "date" - | "time" - | "true" - | "false" - | string - | null; - - /** - * Identifies the element (or elements) that describes the object. - * - * {@link https://www.w3.org/TR/wai-aria-1.1/#aria-describedby} - * @public - * @remarks - * HTML Attribute: aria-describedby - */ - @attr({ attribute: "aria-describedby" }) - public ariaDescribedby: string | null; - - /** - * Identifies the element that provides a detailed, extended description for the object. - * - * {@link https://www.w3.org/TR/wai-aria-1.1/#aria-details} - * @public - * @remarks - * HTML Attribute: aria-details - */ - @attr({ attribute: "aria-details" }) - public ariaDetails: string | null; - - /** - * Indicates that the element is perceivable but disabled, so it is not editable or otherwise operable. - * - * {@link https://www.w3.org/TR/wai-aria-1.1/#aria-disabled} - * @public - * @remarks - * HTML Attribute: aria-disabled - */ - @attr({ attribute: "aria-disabled" }) - public ariaDisabled: "true" | "false" | string | null; - - /** - * Identifies the element that provides an error message for the object. - * - * {@link https://www.w3.org/TR/wai-aria-1.1/#aria-errormessage} - * @public - * @remarks - * HTML Attribute: aria-errormessage - */ - @attr({ attribute: "aria-errormessage" }) - public ariaErrormessage: string | null; - - /** - * Identifies the next element (or elements) in an alternate reading order of content which, at the user's discretion, - * allows assistive technology to override the general default of reading in document source order. - * - * {@link https://www.w3.org/TR/wai-aria-1.1/#aria-flowto} - * @public - * @remarks - * HTML Attribute: aria-flowto - */ - @attr({ attribute: "aria-flowto" }) - public ariaFlowto: string | null; - - /** - * Indicates the availability and type of interactive popup element, - * such as menu or dialog, that can be triggered by an element. - * - * {@link https://www.w3.org/TR/wai-aria-1.1/#aria-haspopup} - * @public - * @remarks - * HTML Attribute: aria-haspopup - */ - @attr({ attribute: "aria-haspopup" }) - public ariaHaspopup: - | "false" - | "true" - | "menu" - | "listbox" - | "tree" - | "grid" - | "dialog" - | string - | null; - - /** - * Indicates whether the element is exposed to an accessibility API - * - * {@link https://www.w3.org/TR/wai-aria-1.1/#aria-hidden} - * @public - * @remarks - * HTML Attribute: aria-hidden - */ - @attr({ attribute: "aria-hidden" }) - public ariaHidden: "false" | "true" | string | null; - - /** - * Indicates the entered value does not conform to the format expected by the application. - * - * {@link https://www.w3.org/TR/wai-aria-1.1/#aria-invalid} - * @public - * @remarks - * HTML Attribute: aria-invalid - */ - @attr({ attribute: "aria-invalid" }) - public ariaInvalid: "false" | "true" | "grammar" | "spelling" | string | null; - - /** - * Indicates keyboard shortcuts that an author has implemented to activate or give focus to an element. - * - * {@link https://www.w3.org/TR/wai-aria-1.1/#aria-keyshortcuts} - * @public - * @remarks - * HTML Attribute: aria-keyshortcuts - */ - @attr({ attribute: "aria-keyshortcuts" }) - public ariaKeyshortcuts: string | null; - - /** - * Defines a string value that labels the current element. - * - * {@link https://www.w3.org/TR/wai-aria-1.1/#aria-label} - * @public - * @remarks - * HTML Attribute: aria-label - */ - @attr({ attribute: "aria-label" }) - public ariaLabel: string | null; - - /** - * Identifies the element (or elements) that labels the current element. - * - * {@link https://www.w3.org/TR/wai-aria-1.1/#aria-labelledby} - * @public - * @remarks - * HTML Attribute: aria-labelledby - */ - @attr({ attribute: "aria-labelledby" }) - public ariaLabelledby: string | null; - - /** - * Indicates that an element will be updated, and describes the types of updates the user agents, - * assistive technologies, and user can expect from the live region. - * - * {@link https://www.w3.org/TR/wai-aria-1.1/#aria-live} - * @public - * @remarks - * HTML Attribute: aria-live - */ - @attr({ attribute: "aria-live" }) - public ariaLive: "assertive" | "off" | "polite" | string | null; - - /** - * Identifies an element (or elements) in order to define a visual, - * functional, or contextual parent/child relationship between DOM elements - * where the DOM hierarchy cannot be used to represent the relationship. - * - * {@link https://www.w3.org/TR/wai-aria-1.1/#aria-owns} - * @public - * @remarks - * HTML Attribute: aria-owns - */ - @attr({ attribute: "aria-owns" }) - public ariaOwns: string | null; - - /** - * Indicates what notifications the user agent will trigger when the accessibility tree within a live region is modified. - * - * {@link https://www.w3.org/TR/wai-aria-1.1/#aria-relevant} - * @public - * @remarks - * HTML Attribute: aria-relevant - */ - @attr({ attribute: "aria-relevant" }) - public ariaRelevant: - | "additions" - | "additions text" - | "all" - | "removals" - | "text" - | string - | null; - - /** - * Defines a human-readable, author-localized description for the role of an element. - * - * {@link https://www.w3.org/TR/wai-aria-1.1/#aria-roledescription} - * @public - * @remarks - * HTML Attribute: aria-roledescription - */ - @attr({ attribute: "aria-roledescription" }) - public ariaRoledescription: string | null; -} diff --git a/packages/web-components/fast-foundation/src/patterns/index.ts b/packages/web-components/fast-foundation/src/patterns/index.ts deleted file mode 100644 index e74d6cb8848..00000000000 --- a/packages/web-components/fast-foundation/src/patterns/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export { ARIAGlobalStatesAndProperties } from "./aria-global.js"; -export { endSlotTemplate, StartEnd, startSlotTemplate } from "./start-end.js"; -export type { EndOptions, StartEndOptions, StartOptions } from "./start-end.js"; -export { tagFor } from "./tag-for.js"; -export type { TemplateElementDependency } from "./tag-for.js"; diff --git a/packages/web-components/fast-foundation/src/patterns/start-end.ts b/packages/web-components/fast-foundation/src/patterns/start-end.ts deleted file mode 100644 index 8625fc165b2..00000000000 --- a/packages/web-components/fast-foundation/src/patterns/start-end.ts +++ /dev/null @@ -1,68 +0,0 @@ -import type { CaptureType } from "@microsoft/fast-element"; -import { html, ref } from "@microsoft/fast-element"; -import type { StaticallyComposableHTML } from "../utilities/template-helpers.js"; -import { staticallyCompose } from "../utilities/template-helpers.js"; - -/** - * Start configuration options - * @public - */ -export type StartOptions = { - start?: StaticallyComposableHTML; -}; - -/** - * End configuration options - * @public - */ -export type EndOptions = { - end?: StaticallyComposableHTML; -}; - -/** - * Start/End configuration options - * @public - */ -export type StartEndOptions = StartOptions< - TSource, - TParent -> & - EndOptions; - -/** - * A mixin class implementing start and end slots. - * These are generally used to decorate text elements with icons or other visual indicators. - * @public - */ -export class StartEnd { - public start: HTMLSlotElement; - public end: HTMLSlotElement; -} - -/** - * The template for the end slot. - * For use with {@link StartEnd} - * - * @public - */ -export function endSlotTemplate( - options: EndOptions -): CaptureType { - return html` - ${staticallyCompose(options.end)} - `.inline(); -} - -/** - * The template for the start slots. - * For use with {@link StartEnd} - * - * @public - */ -export function startSlotTemplate( - options: StartOptions -): CaptureType { - return html` - ${staticallyCompose(options.start)} - `.inline(); -} diff --git a/packages/web-components/fast-foundation/src/patterns/tag-for.ts b/packages/web-components/fast-foundation/src/patterns/tag-for.ts deleted file mode 100644 index c02a641dabc..00000000000 --- a/packages/web-components/fast-foundation/src/patterns/tag-for.ts +++ /dev/null @@ -1,33 +0,0 @@ -import type { Constructable, FASTElement } from "@microsoft/fast-element"; -import { FASTElementDefinition } from "@microsoft/fast-element"; - -/** - * Used to designate a template's dependency on another custom element. - * @beta - */ -export type TemplateElementDependency = - | string - | FASTElementDefinition - | Constructable; - -/** - * Determines what HTML tag name to use for the dependency. - * @param dependency - The dependency the template is dependent on. - * @returns The tag name to use in markup. - * @beta - */ -export function tagFor(dependency: TemplateElementDependency): string { - if (typeof dependency === "string") { - return dependency; - } - - if (typeof dependency === "function") { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - dependency = FASTElementDefinition.getByType(dependency)!; - if (!dependency) { - throw new Error("Missing FASTElement definition."); - } - } - - return dependency.name; -} diff --git a/packages/web-components/fast-foundation/src/picker/README.md b/packages/web-components/fast-foundation/src/picker/README.md deleted file mode 100644 index 93a5ba58035..00000000000 --- a/packages/web-components/fast-foundation/src/picker/README.md +++ /dev/null @@ -1,284 +0,0 @@ - - -## API - - - -### class: `DefaultPickerContext` - -
- -### Variables - -| Name | Description | Type | -| --------------- | ----------- | ---- | -| `PickerContext` | | | - -
- - - -### class: `FASTPickerListItem` - -#### Superclass - -| Name | Module | Package | -| ------------- | ------ | ----------------------- | -| `FASTElement` | | @microsoft/fast-element | - -#### Fields - -| Name | Privacy | Type | Default | Description | Inherited From | -| ------------------ | ------- | --------------- | ------- | --------------------------------------------------------- | -------------- | -| `pickerContext` | | `PickerContext` | | Context object for the parent picker | | -| `value` | public | `string` | | The underlying string value of the item | | -| `contentsTemplate` | public | `ViewTemplate` | | The template used to render the contents of the list item | | - -#### Methods - -| Name | Privacy | Description | Parameters | Return | Inherited From | -| ------------------------- | --------- | ----------- | ------------------ | --------- | -------------- | -| `contentsTemplateChanged` | protected | | | `void` | | -| `handleKeyDown` | public | | `e: KeyboardEvent` | `boolean` | | -| `handleClick` | public | | `e: MouseEvent` | `void` | | - -#### Attributes - -| Name | Field | Inherited From | -| ------- | ----- | -------------- | -| `value` | value | | - -
- - - -### class: `FASTPickerList` - -#### Superclass - -| Name | Module | Package | -| ------------- | ------ | ----------------------- | -| `FASTElement` | | @microsoft/fast-element | - -
- - - -### class: `FASTPickerMenuOption` - -#### Superclass - -| Name | Module | Package | -| ------------- | ------ | ----------------------- | -| `FASTElement` | | @microsoft/fast-element | - -#### Fields - -| Name | Privacy | Type | Default | Description | Inherited From | -| ------------------ | ------- | -------------- | ------- | --------------------------------------------------------- | -------------- | -| `value` | public | `string` | | The underlying string value of the item | | -| `contentsTemplate` | public | `ViewTemplate` | | The template used to render the contents of the list item | | - -#### Methods - -| Name | Privacy | Description | Parameters | Return | Inherited From | -| ------------------------- | --------- | ----------- | --------------- | --------- | -------------- | -| `contentsTemplateChanged` | protected | | | `void` | | -| `handleClick` | public | | `e: MouseEvent` | `boolean` | | - -#### Attributes - -| Name | Field | Inherited From | -| ------- | ----- | -------------- | -| `value` | value | | - -
- - - -### class: `FASTPickerMenu` - -#### Superclass - -| Name | Module | Package | -| ------------- | ------ | ----------------------- | -| `FASTElement` | | @microsoft/fast-element | - -#### Fields - -| Name | Privacy | Type | Default | Description | Inherited From | -| -------------------------- | ------- | -------- | ------- | ---------------------------------------------------------------------- | -------------- | -| `suggestionsAvailableText` | public | `string` | | Text to display to assistive technology when suggestions are available | | - -#### Methods - -| Name | Privacy | Description | Parameters | Return | Inherited From | -| ----------------------- | ------- | ----------- | ---------- | ------ | -------------- | -| `menuElementsChanged` | public | | | `void` | | -| `headerElementsChanged` | public | | | `void` | | -| `footerElementsChanged` | public | | | `void` | | - -
- - - -### class: `FormAssociatedPicker` - -#### Superclass - -| Name | Module | Package | -| --------- | ------------------------------------ | ------- | -| `_Picker` | src/picker/picker.form-associated.ts | | - -#### Mixins - -| Name | Module | Package | -| ---------------- | --------------------------------------- | ------- | -| `FormAssociated` | /src/form-associated/form-associated.js | | - -#### Fields - -| Name | Privacy | Type | Default | Description | Inherited From | -| ------- | ------- | ---- | ------- | ----------- | -------------- | -| `proxy` | | | | | | - -
- - - -### Variables - -| Name | Description | Type | -| --------------- | -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | -| `MenuPlacement` | vertical positioning values for an anchored region | `{ bottom: "bottom", bottomFill: "bottom-fill", tallest: "tallest", tallestFill: "tallest-fill", top: "top", topFill: "top-fill", }` | - -
- - - -### class: `FASTPicker` - -#### Superclass - -| Name | Module | Package | -| ---------------------- | ------------------------------------- | ------- | -| `FormAssociatedPicker` | /src/picker/picker.form-associated.js | | - -#### Fields - -| Name | Privacy | Type | Default | Description | Inherited From | -| ---------------------------- | ------- | --------------------------- | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | -------------------- | -| `selection` | public | `string` | `""` | Currently selected items. Comma delineated string ie. "apples,oranges". | | -| `options` | public | `string` | | Currently available options. Comma delineated string ie. "apples,oranges". | | -| `filterSelected` | public | `boolean` | `false` | Indicates whether the component should remove an option from the list when it is in the selection. | | -| `disableSelectionFilter` | public | `boolean` | `false` | Indicates whether the component should remove an option from the list when it is in the selection. | | -| `filterQuery` | public | `boolean` | `true` | Indicates whether the component should remove options based on the current query. | | -| `disableQueryFilter` | public | `boolean` | `false` | Indicates whether the component should remove options based on the current query. | | -| `maxSelected` | public | `number or null` | `null` | The maximum number of items that can be selected. | | -| `noSuggestionsText` | public | `string` | `"No suggestions available"` | The text to present to assistive technolgies when no suggestions are available. | | -| `suggestionsAvailableText` | public | `string` | `"Suggestions available"` | The text to present to assistive technolgies when suggestions are available. | | -| `loadingText` | public | `string` | `"Loading suggestions"` | The text to present to assistive technologies when suggestions are loading. | | -| `disabled` | public | `boolean` | | Disables the picker. | | -| `label` | public | `string` | | Applied to the aria-label attribute of the input element | | -| `labelledBy` | public | `string` | | Applied to the aria-labelledby attribute of the input element | | -| `placeholder` | public | `string` | | Applied to the placeholder attribute of the input element | | -| `menuPlacement` | public | `MenuPlacement` | | Controls menu placement | | -| `showLoading` | public | `boolean` | `false` | Whether to display a loading state if the menu is opened. | | -| `listItemTemplate` | public | `ViewTemplate` | | Template used to generate selected items. This is used in a repeat directive. | | -| `defaultListItemTemplate` | public | `ViewTemplate or undefined` | | Default template to use for selected items (usually specified in the component template). This is used in a repeat directive. | | -| `menuOptionTemplate` | public | `ViewTemplate` | | Template to use for available options. This is used in a repeat directive. | | -| `defaultMenuOptionTemplate` | public | `ViewTemplate or undefined` | | Default template to use for available options (usually specified in the template). This is used in a repeat directive. | | -| `listItemContentsTemplate` | public | `ViewTemplate` | | Template to use for the contents of a selected list item | | -| `menuOptionContentsTemplate` | public | `ViewTemplate` | | Template to use for the contents of menu options | | -| `optionsList` | public | `string[]` | `[]` | Current list of options in array form | | -| `query` | public | `string` | | The text value currently in the input field | | -| `itemsPlaceholderElement` | public | `Node` | | Reference to the placeholder element for the repeat directive | | -| `proxy` | | | | | FormAssociatedPicker | - -#### Methods - -| Name | Privacy | Description | Parameters | Return | Inherited From | -| ---------------------------------- | --------- | ------------------------------------------------------------- | ---------------------------------- | --------- | -------------- | -| `selectionChanged` | protected | | | `void` | | -| `optionsChanged` | protected | | | `void` | | -| `filterSelectedChanged` | protected | | | `void` | | -| `disableSelectionFilterChanged` | protected | | | `void` | | -| `filterQueryChanged` | protected | | | `void` | | -| `disableQueryFilterChanged` | protected | | | `void` | | -| `disabledChanged` | public | | `previous: boolean, next: boolean` | `void` | | -| `menuPlacementChanged` | protected | | | `void` | | -| `showLoadingChanged` | protected | | | `void` | | -| `listItemTemplateChanged` | protected | | | `void` | | -| `defaultListItemTemplateChanged` | protected | | | `void` | | -| `menuOptionTemplateChanged` | protected | | | `void` | | -| `defaultMenuOptionTemplateChanged` | protected | | | `void` | | -| `queryChanged` | protected | | | `void` | | -| `flyoutOpenChanged` | protected | | | `void` | | -| `focus` | public | Move focus to the input element | | | | -| `handleKeyDown` | public | Handle key down events. | `e: KeyboardEvent` | `boolean` | | -| `handleFocusIn` | public | Handle focus in events. | `e: FocusEvent` | `boolean` | | -| `handleFocusOut` | public | Handle focus out events. | `e: FocusEvent` | `boolean` | | -| `handleSelectionChange` | public | The list of selected items has changed | | `void` | | -| `handleRegionLoaded` | public | Anchored region is loaded, menu and options exist in the DOM. | `e: Event` | `void` | | -| `handleItemInvoke` | public | A list item has been invoked. | `e: Event` | `boolean` | | -| `handleOptionInvoke` | public | A menu option has been invoked. | `e: Event` | `boolean` | | - -#### Attributes - -| Name | Field | Inherited From | -| ---------------------------- | ------------------------ | -------------- | -| `selection` | selection | | -| `options` | options | | -| `disable-selection-filter` | disableSelectionFilter | | -| `disable-query-filter` | disableQueryFilter | | -| `max-selected` | maxSelected | | -| `no-suggestions-text` | noSuggestionsText | | -| `suggestions-available-text` | suggestionsAvailableText | | -| `loading-text` | loadingText | | -| | disabled | | -| `label` | label | | -| `labelledby` | labelledBy | | -| `placeholder` | placeholder | | -| `menu-placement` | menuPlacement | | - -
- - diff --git a/packages/web-components/fast-foundation/src/picker/index.ts b/packages/web-components/fast-foundation/src/picker/index.ts deleted file mode 100644 index 65844e84866..00000000000 --- a/packages/web-components/fast-foundation/src/picker/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -export { FASTPickerListItem } from "./picker-list-item.js"; -export { pickerListItemTemplate } from "./picker-list-item.template.js"; -export { FASTPickerList } from "./picker-list.js"; -export { pickerListTemplate } from "./picker-list.template.js"; -export { FASTPickerMenuOption } from "./picker-menu-option.js"; -export { pickerMenuOptionTemplate } from "./picker-menu-option.template.js"; -export { FASTPickerMenu } from "./picker-menu.js"; -export { pickerMenuTemplate } from "./picker-menu.template.js"; -export { FASTPicker } from "./picker.js"; -export { MenuPlacement } from "./picker.options.js"; -export { pickerTemplate } from "./picker.template.js"; -export type { PickerOptions } from "./picker.template.js"; diff --git a/packages/web-components/fast-foundation/src/picker/picker-context.ts b/packages/web-components/fast-foundation/src/picker/picker-context.ts deleted file mode 100644 index b0f94c746b6..00000000000 --- a/packages/web-components/fast-foundation/src/picker/picker-context.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { observable } from "@microsoft/fast-element"; -import { Context } from "@microsoft/fast-element/context.js"; - -export interface PickerContext { - disabled: boolean; -} - -export const PickerContext = Context.create("picker-context"); - -export class DefaultPickerContext implements PickerContext { - /** - * The disabled state of the picker - * - * @internal - */ - @observable - public disabled: boolean = false; -} diff --git a/packages/web-components/fast-foundation/src/picker/picker-list-item.template.ts b/packages/web-components/fast-foundation/src/picker/picker-list-item.template.ts deleted file mode 100644 index b48c59ab7da..00000000000 --- a/packages/web-components/fast-foundation/src/picker/picker-list-item.template.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { ElementViewTemplate } from "@microsoft/fast-element"; -import { html } from "@microsoft/fast-element"; -import type { FASTPickerListItem } from "./picker-list-item.js"; - -/** - * - * @public - */ -export function pickerListItemTemplate< - T extends FASTPickerListItem ->(): ElementViewTemplate { - return html` - - `; -} diff --git a/packages/web-components/fast-foundation/src/picker/picker-list-item.ts b/packages/web-components/fast-foundation/src/picker/picker-list-item.ts deleted file mode 100644 index 44c0cb055d2..00000000000 --- a/packages/web-components/fast-foundation/src/picker/picker-list-item.ts +++ /dev/null @@ -1,98 +0,0 @@ -import type { HTMLView, ViewTemplate } from "@microsoft/fast-element"; -import { attr, FASTElement, html, observable } from "@microsoft/fast-element"; -import { keyEnter } from "@microsoft/fast-web-utilities"; -import { PickerContext } from "./picker-context.js"; - -const defaultContentsTemplate: ViewTemplate = html` - -`; - -/** - * A picker list item Custom HTML Element. - * - * @beta - */ -export class FASTPickerListItem extends FASTElement { - /** - * Context object for the parent picker - * - */ - @PickerContext - pickerContext: PickerContext; - - /** - * The underlying string value of the item - * - * @remarks - * HTML Attribute: value - */ - @attr({ attribute: "value" }) - public value: string; - - /** - * The template used to render the contents of the list item - * - */ - @observable - public contentsTemplate: ViewTemplate; - protected contentsTemplateChanged(): void { - if (this.$fastController.isConnected) { - this.updateView(); - } - } - - private customView: HTMLView | undefined; - - /** - * @internal - */ - public connectedCallback(): void { - super.connectedCallback(); - this.updateView(); - } - - /** - * @internal - */ - public disconnectedCallback(): void { - this.disconnectView(); - super.disconnectedCallback(); - } - - public handleKeyDown(e: KeyboardEvent): boolean { - if (e.defaultPrevented || this.pickerContext.disabled) { - return true; - } - - if (e.key === keyEnter) { - this.handleInvoke(); - return false; - } - - return true; - } - - public handleClick(e: MouseEvent): void { - if (e.defaultPrevented || this.pickerContext.disabled) { - return; - } - this.handleInvoke(); - } - - private handleInvoke(): void { - this.$emit("pickeriteminvoked"); - } - - private updateView(): void { - this.disconnectView(); - - this.customView = - this.contentsTemplate?.render(this, this) ?? - defaultContentsTemplate.render(this, this); - } - - private disconnectView(): void { - this.customView?.dispose(); - this.customView = undefined; - } -} diff --git a/packages/web-components/fast-foundation/src/picker/picker-list.template.ts b/packages/web-components/fast-foundation/src/picker/picker-list.template.ts deleted file mode 100644 index dee145fe132..00000000000 --- a/packages/web-components/fast-foundation/src/picker/picker-list.template.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { ElementViewTemplate } from "@microsoft/fast-element"; -import { html } from "@microsoft/fast-element"; -import type { FASTPickerList } from "./picker-list.js"; - -/** - * - * @public - */ -export function pickerListTemplate(): ElementViewTemplate { - return html` - - `; -} diff --git a/packages/web-components/fast-foundation/src/picker/picker-list.ts b/packages/web-components/fast-foundation/src/picker/picker-list.ts deleted file mode 100644 index 2b5244a01c7..00000000000 --- a/packages/web-components/fast-foundation/src/picker/picker-list.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { FASTElement } from "@microsoft/fast-element"; - -/** - * A List Picker Menu Custom HTML Element. - * - * @beta - */ -export class FASTPickerList extends FASTElement {} diff --git a/packages/web-components/fast-foundation/src/picker/picker-menu-option.template.ts b/packages/web-components/fast-foundation/src/picker/picker-menu-option.template.ts deleted file mode 100644 index e810f5ff798..00000000000 --- a/packages/web-components/fast-foundation/src/picker/picker-menu-option.template.ts +++ /dev/null @@ -1,21 +0,0 @@ -import type { ElementViewTemplate } from "@microsoft/fast-element"; -import { html } from "@microsoft/fast-element"; -import type { FASTPickerMenuOption } from "./picker-menu-option.js"; - -/** - * - * @public - */ -export function pickerMenuOptionTemplate< - T extends FASTPickerMenuOption ->(): ElementViewTemplate { - return html` - - `; -} diff --git a/packages/web-components/fast-foundation/src/picker/picker-menu-option.ts b/packages/web-components/fast-foundation/src/picker/picker-menu-option.ts deleted file mode 100644 index 81d02c0c85e..00000000000 --- a/packages/web-components/fast-foundation/src/picker/picker-menu-option.ts +++ /dev/null @@ -1,76 +0,0 @@ -import type { HTMLView, ViewTemplate } from "@microsoft/fast-element"; -import { attr, FASTElement, html, observable } from "@microsoft/fast-element"; - -const defaultContentsTemplate: ViewTemplate = html` - -`; - -/** - * A picker list item Custom HTML Element. - * - * @beta - */ -export class FASTPickerMenuOption extends FASTElement { - /** - * The underlying string value of the item - * - * @remarks - * HTML Attribute: value - */ - @attr({ attribute: "value" }) - public value: string; - - /** - * The template used to render the contents of the list item - */ - @observable - public contentsTemplate: ViewTemplate; - protected contentsTemplateChanged(): void { - if (this.$fastController.isConnected) { - this.updateView(); - } - } - - private customView: HTMLView | undefined; - - /** - * @internal - */ - public connectedCallback(): void { - super.connectedCallback(); - this.updateView(); - } - - /** - * @internal - */ - public disconnectedCallback(): void { - super.disconnectedCallback(); - this.disconnectView(); - } - - public handleClick(e: MouseEvent): boolean { - if (e.defaultPrevented) { - return false; - } - this.handleInvoked(); - return false; - } - - private handleInvoked(): void { - this.$emit("pickeroptioninvoked"); - } - - private updateView(): void { - this.disconnectView(); - - this.customView = - this.contentsTemplate?.render(this, this) ?? - defaultContentsTemplate.render(this, this); - } - - private disconnectView(): void { - this.customView?.dispose(); - this.customView = undefined; - } -} diff --git a/packages/web-components/fast-foundation/src/picker/picker-menu.template.ts b/packages/web-components/fast-foundation/src/picker/picker-menu.template.ts deleted file mode 100644 index f72c43b1b9a..00000000000 --- a/packages/web-components/fast-foundation/src/picker/picker-menu.template.ts +++ /dev/null @@ -1,32 +0,0 @@ -import type { ElementViewTemplate } from "@microsoft/fast-element"; -import { html, slotted } from "@microsoft/fast-element"; -import type { FASTPickerMenu } from "./picker-menu.js"; - -/** - * The template for the List Picker component. - * @public - */ -export function pickerMenuTemplate(): ElementViewTemplate { - return html` - - `; -} diff --git a/packages/web-components/fast-foundation/src/picker/picker-menu.ts b/packages/web-components/fast-foundation/src/picker/picker-menu.ts deleted file mode 100644 index 94657e1aa6f..00000000000 --- a/packages/web-components/fast-foundation/src/picker/picker-menu.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { uniqueId } from "@microsoft/fast-web-utilities"; -import { FASTElement, observable } from "@microsoft/fast-element"; - -/** - * A List Picker Menu Custom HTML Element. - * - * @beta - */ -export class FASTPickerMenu extends FASTElement { - /** - * Elements in the default slot - * - * @internal - */ - @observable - public menuElements: HTMLElement[]; - public menuElementsChanged(): void { - this.updateOptions(); - } - - /** - * Elements in the header slot - * - * - * @internal - */ - @observable - public headerElements: HTMLElement[]; - public headerElementsChanged(): void { - this.updateOptions(); - } - - /** - * Elements in the footer slot - * - * - * @internal - */ - @observable - public footerElements: HTMLElement[]; - public footerElementsChanged(): void { - this.updateOptions(); - } - - /** - * Text to display to assistive technology when - * suggestions are available - * - */ - @observable - public suggestionsAvailableText: string; - - /** - * Children that are list items - * - * @internal - */ - public optionElements: HTMLElement[] = []; - - private updateOptions(): void { - this.optionElements.splice(0, this.optionElements.length); - this.addSlottedListItems(this.headerElements); - this.addSlottedListItems(this.menuElements); - this.addSlottedListItems(this.footerElements); - this.$emit("optionsupdated", { bubbles: false }); - } - - private addSlottedListItems(slotChildren: HTMLElement[]) { - if (slotChildren === undefined) { - return; - } - slotChildren.forEach((child: HTMLElement): void => { - if (child.nodeType === 1 && child.getAttribute("role") === "option") { - child.id = child.id || uniqueId("option-"); - this.optionElements.push(child); - } - }); - } -} diff --git a/packages/web-components/fast-foundation/src/picker/picker.form-associated.ts b/packages/web-components/fast-foundation/src/picker/picker.form-associated.ts deleted file mode 100644 index 491c6a232a3..00000000000 --- a/packages/web-components/fast-foundation/src/picker/picker.form-associated.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { FASTElement } from "@microsoft/fast-element"; -import { FormAssociated } from "../form-associated/form-associated.js"; - -class _Picker extends FASTElement {} -interface _Picker extends FormAssociated {} - -/** - * A form-associated base class for the {@link @microsoft/fast-foundation#(FASTPicker:class)} component. - * - * @beta - */ -export class FormAssociatedPicker extends FormAssociated(_Picker) { - proxy = document.createElement("input"); -} diff --git a/packages/web-components/fast-foundation/src/picker/picker.options.ts b/packages/web-components/fast-foundation/src/picker/picker.options.ts deleted file mode 100644 index ab8e4a6be09..00000000000 --- a/packages/web-components/fast-foundation/src/picker/picker.options.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { ValuesOf } from "../utilities/index.js"; - -/** - * vertical positioning values for an anchored region - * @beta - */ -export const MenuPlacement = { - bottom: "bottom", - bottomFill: "bottom-fill", - tallest: "tallest", - tallestFill: "tallest-fill", - top: "top", - topFill: "top-fill", -} as const; - -/** - * Type for vertical positioning values for an anchored region - * @beta - */ -export type MenuPlacement = ValuesOf; diff --git a/packages/web-components/fast-foundation/src/picker/picker.spec.md b/packages/web-components/fast-foundation/src/picker/picker.spec.md deleted file mode 100644 index d196ae7fb49..00000000000 --- a/packages/web-components/fast-foundation/src/picker/picker.spec.md +++ /dev/null @@ -1,117 +0,0 @@ -# Picker - -## Overview - -NOTE: `picker` is an alpha version of the component. Developers should expect API changes until the component is stable. - -The 'picker' component enables users to select a list of items from a searchable list of options. A basic implemetation could be selecting pizza toppings from a relatively short local list, while a more advanced one could be selecting recients for an e-mail by querying a large directory of recipients on a remote server as the user types. - -### Use Cases - -- Choosing a list of recipients for an e-mail. -- Choosing a list of pizza toppings. - -### Non-goals -- Managing asynchronous data loading: Managing loading states and updating data should be left to components that wrap a `picker`. The component should enable the display of loading states to make it easy for authors to do create good experiences around async data loading, but otherwise not get involved. - -### Prior Art/Examples - -- Outlook.com mail recipient picker -- The existing MGT people picker https://mgt.dev/?path=/story/components-mgt-people-picker--people-picker - -## Design - -The 'picker' component is actually composed of five web components: -- The top-level 'picker' component. -- The 'picker-list' component which hosts a text input box and displays the items that have already been selected. -- The 'picker-list-item' component which displays a single selected item. -- The 'picker-menu' component which displays the currently available options. -- The 'picker-menu-option' component which displays a single option in the menu. - -Most end-user developers will simply deal with the top level 'picker' (ie. "people-picker", "topping-picker", etc...) and the 'picker-list' and 'picker-menu' sub-components should mostly only be a concern for developers creating these styled variations. - -### API - -**Picker** - -*Component name:* -- `picker` - -Picker is the top level container which hosts both a `picker-list` component to display the selected items and a `picker-menu` component for the list of currently available choices. - -*Attributes:* -- `selection`: List of currently selected items. Comma delineated string ie. "apples,oranges". -- `options`: Currently available options. Comma delineated string ie. "apples,oranges". -- `max-selected`: The maximum number of items that can be selected. Unset by default (ie. no maximum). If the value is "0" selecting an item updates the query instead. -- `no-suggestions-text`: The text to present when no suggestions are available. -- `suggestions-available-text`: The text to present when suggestions are available. -- `loading-text`: The text to present when suggestions are loading. -- `label`: The text applied to the `aria-label` attribute of the internal input element. -- `labelledby`: The text applied to the `aria-labelledby` attribute of the internal input element. -- `placeholder`: The text used as the `placeholder` value for the internal input element. -- `filter-selected`: Whether to remove selected elements from the option list (default=false) -- `disable-query-filter`: Whether to remove elements that don't match the query string (default=false) -- `menu-placement`: Controls the placement of the menu relative to the input element. -(default="bottom-fill") - - -*Properties:* -- `showLoading`: Whether to display a loading state if the menu is opened. -- `listItemTemplate`: (ViewTemplate) Template used to generate listItems, used as part of a repeat directive. -- `defaultListItemTemplate`: (ViewTemplate) Default template used to generate list items, used as part of a repeat directive. -- `menuOptionTemplate`: (ViewTemplate) Template used to generate menu options, used as part of a repeat directive. -- `defaultMenuOptionTemplate`: (ViewTemplate) Template used to generate menu options, used as part of a repeat directive. -- `listItemContentsTemplate`: (ViewTemplate) Template used for the internals of a list item. The built in default template simply renders the string. -- `menuItemContentsTemplate`: (ViewTemplate) Template used for the internals of a list item. The built in default template simply renders the string -- `optionsList`: (string[]) Array of currently available menu options. -- `query`: (string) The text currently in the input text box, essentially the search term. - -*Slots:* -- `list-region`: The slot where the list of currently selected items and the input element are placed by the picker component. -- `menu-region`: The slot where the flyout menu is placed. Authors can place a customized menu here, for example in order to add a header or footer. If no custom menu is added the component will generate a default one. -- `no-options-region`: The slot where the ui that displays in the flyout when there are no options available is placed. The default shows the `no-suggestions-text`. -- `loading-region`: The slot where the ui that displays in the flyout when options are loading is placed. The default shows the `loading-text` and an animated progress spinner. - -*Events* -`selectionchange`: (bubbles: false) emitted when the selection has changed. -`querychange`: (bubbles: false) The query has changed. -`menuopening`:(bubbles: false) Menu is opening. -`menuclosing`:(bubbles: false) menu is closing. -`menuloaded`: (bubbles: false) The menu is loaded and present in the DOM. - - -**Picker-List** - -The `picker-list` sub-component encapulates the display of selected items as well as the text input box. It is rendered to the light dom and has a role of "list". - -*Component name:* -- `picker-list` - -*Attributes:* -- `label`: The text applied to the `aria-label` attribute of the internal input element. Usually set by the parent picker component. -- `labelledby`: The text applied to the `aria-labelledby` attribute of the internal input element. Usually set by the parent picker component. - -**Picker-Menu** - -The `picker-menu` sub-component is displayed in a flyout and shows the available choices (or alternate messages like "loading" or "no choices available") based on user input. It is rendered to the light dom and has a role of "listbox". - -*Component name:* -- `picker-menu` - -*Attributes:* - -*Slots:* -- default: Options generated from data are inserted here. -- `header-region`: Authors can add a custom menu header here. Elements with a role of 'option' will be added to the menu navigation. Typically authors will need to handle invocation of custom items themselves. -- `footer-region`: Authors can add a custom menu footer here. Elements with a role of 'option' will be added to the menu navigation. Typically authors will need to handle invocation of custom items themselves. - -*Events* -- `optionsupdated`: Emitted when the available options change. - -## Implementation - -### Accessibility -Picker should apply all the appropriate aria attributes and roles to properly support assistive technologies. - -## Next Steps -- support picker as a form element \ No newline at end of file diff --git a/packages/web-components/fast-foundation/src/picker/picker.spec.ts b/packages/web-components/fast-foundation/src/picker/picker.spec.ts deleted file mode 100644 index c9d74944f2a..00000000000 --- a/packages/web-components/fast-foundation/src/picker/picker.spec.ts +++ /dev/null @@ -1,498 +0,0 @@ -import { expect } from "chai"; -import { - FASTPicker, - FASTPickerList, - FASTPickerListItem, - pickerListItemTemplate, - pickerListTemplate, - FASTPickerMenu, - FASTPickerMenuOption, - pickerMenuOptionTemplate, - pickerMenuTemplate, - pickerTemplate, -} from "./index.js"; -import { fixture, uniqueElementName } from "@microsoft/fast-element/testing.js"; -import { Updates } from "@microsoft/fast-element"; -import { - keyArrowLeft, - keyArrowRight, - keyBackspace, - keyDelete, - keyEnter, -} from "@microsoft/fast-web-utilities"; -import { FASTAnchoredRegion, anchoredRegionTemplate } from "../anchored-region/index.js"; -import { FASTProgressRing, progressRingTemplate } from "../progress-ring/index.js"; - -const anchoredRegionName = uniqueElementName(); -FASTAnchoredRegion.define({ - name: anchoredRegionName, - template: anchoredRegionTemplate() -}); - -const pickerListName = uniqueElementName(); -FASTPickerList.define({ - name: pickerListName, - template: pickerListTemplate(), - shadowOptions: null, -}); - -const pickerListItemName = uniqueElementName(); -FASTPickerListItem.define({ - name: pickerListItemName, - template: pickerListItemTemplate() -}); - -const pickerMenuName = uniqueElementName(); -FASTPickerMenu.define({ - name: pickerMenuName, - template: pickerMenuTemplate() -}); - -const pickerMenuOptionName = uniqueElementName(); -FASTPickerMenuOption.define({ - name: pickerMenuOptionName, - template: pickerMenuOptionTemplate() -}); - -const progressRingName = uniqueElementName(); -FASTProgressRing.define({ - name: progressRingName, - template: progressRingTemplate() -}); - -const pickerName = uniqueElementName(); -FASTPicker.define({ - name: pickerName, - template: pickerTemplate({ - anchoredRegion: anchoredRegionName, - pickerList: pickerListName, - pickerListItem: pickerListItemName, - pickerMenu: pickerMenuName, - pickerMenuOption: pickerMenuOptionName, - progressRing: progressRingName - }), - shadowOptions: { - delegatesFocus: true, - }, -}); - -const enterEvent = new KeyboardEvent("keydown", { - key: keyEnter, - bubbles: true, -} as KeyboardEventInit); - -const arrowLeftEvent = new KeyboardEvent("keydown", { - key: keyArrowLeft, - bubbles: true, -} as KeyboardEventInit); - -const arrowRightEvent = new KeyboardEvent("keydown", { - key: keyArrowRight, - bubbles: true, -} as KeyboardEventInit); - -const backEvent = new KeyboardEvent("keydown", { - key: keyBackspace, - bubbles: true, -} as KeyboardEventInit); - -const deleteEvent = new KeyboardEvent("keydown", { - key: keyDelete, - bubbles: true, -} as KeyboardEventInit); - - -async function setupPicker() { - const { element, connect, disconnect }: { - element: HTMLElement & FASTPicker, - connect: () => void, - disconnect: () => void - } = await fixture(pickerName); - - return { element, connect, disconnect }; -} - -async function setupPickerList() { - const { element, connect, disconnect } = await fixture(pickerListName); - - return { element, connect, disconnect }; -} - -async function setupPickerListItem() { - const { element, connect, disconnect } = await fixture(pickerListItemName); - - return { element, connect, disconnect }; -} - -async function setupPickerMenu() { - const { element, connect, disconnect } = await fixture(pickerMenuName); - - return { element, connect, disconnect }; -} - -async function setupPickerMenuOption() { - const { element, connect, disconnect } = await fixture(pickerMenuOptionName); - - return { element, connect, disconnect }; -} - -describe("Picker", () => { - /** - * Picker tests - */ - it("picker should create a list element when instantiated", async () => { - const { element, connect, disconnect } = await setupPicker(); - - await connect(); - - expect(element.listElement).to.be.instanceof(FASTPickerList); - - await disconnect(); - }); - - it("picker should include a text input with role of 'combobox'", async () => { - const { element, connect, disconnect } = await setupPicker(); - - await connect(); - - expect(element.inputElement?.getAttribute("role")).to.equal("combobox"); - - await disconnect(); - }); - - it("picker 'combobox' should reflect label/labbelledby/placeholder attributes on picker", async () => { - const { element, connect, disconnect } = await setupPicker(); - - element.label = "test label"; - element.labelledBy = "test labelledby"; - element.placeholder = "test placeholder"; - - await connect(); - - expect(element.inputElement?.getAttribute("aria-label")).to.equal("test label"); - expect(element.inputElement?.getAttribute("aria-labelledby")).to.equal("test labelledby"); - expect(element.inputElement?.getAttribute("placeholder")).to.equal("test placeholder"); - - await disconnect(); - }); - - it("picker 'combobox' should reflect disabled prop on picker", async () => { - const { element, connect, disconnect } = await setupPicker(); - element.disabled = true; - await connect(); - - expect(element.inputElement?.getAttribute("disabled")).to.equal(true); - - await disconnect(); - }); - - it("picker should create a menu element when instanciated", async () => { - const { element, connect, disconnect } = await setupPicker(); - await connect(); - - expect(element.menuElement).to.be.instanceof(FASTPickerMenu); - - await disconnect(); - }); - it("picker should generate list items for selected elements", async () => { - const { element, connect, disconnect } = await setupPicker(); - - element.selection = "apples,oranges,bananas" - - await connect(); - - await Updates.next(); - - expect(element.querySelectorAll(pickerListItemName).length).to.equal(3); - - await disconnect(); - }); - - it("picker should move focus to the input element when focused", async () => { - const { element, connect, disconnect } = await setupPicker(); - await connect(); - - await Updates.next(); - - element.focus(); - - expect(document.activeElement === element.inputElement).to.equal(true); - - await disconnect(); - }); - - it("picker should move focus accross list items with left/right arrow keys", async () => { - const { element, connect, disconnect } = await setupPicker(); - - element.selection = "apples,oranges,bananas" - - await connect(); - - await Updates.next(); - element.focus(); - - expect(document.activeElement === element.inputElement).to.equal(true); - - const listItems: Element[] = Array.from(element.querySelectorAll(pickerListItemName)); - - element.dispatchEvent(arrowLeftEvent); - expect(document.activeElement === listItems[2]).to.equal(true); - - element.dispatchEvent(arrowLeftEvent); - expect(document.activeElement === listItems[1]).to.equal(true); - - element.dispatchEvent(arrowLeftEvent); - expect(document.activeElement === listItems[0]).to.equal(true); - - element.dispatchEvent(arrowLeftEvent); - expect(document.activeElement === listItems[0]).to.equal(true); - - element.dispatchEvent(arrowRightEvent); - expect(document.activeElement === listItems[1]).to.equal(true); - - element.dispatchEvent(arrowRightEvent); - expect(document.activeElement === listItems[2]).to.equal(true); - - element.dispatchEvent(arrowRightEvent); - expect(document.activeElement === element.inputElement).to.equal(true); - - element.dispatchEvent(arrowRightEvent); - expect(document.activeElement === element.inputElement).to.equal(true); - - await disconnect(); - }); - - it("picker should delete entries with delete/backspace keystrokes", async () => { - const { element, connect, disconnect } = await setupPicker(); - - element.selection = "apples,oranges,bananas" - - await connect(); - - await Updates.next(); - element.focus(); - - let listItems: Element[] = Array.from(element.querySelectorAll(pickerListItemName)); - expect(listItems.length).to.equal(3); - expect(element.selection).to.equal("apples,oranges,bananas"); - - element.dispatchEvent(backEvent); - await Updates.next(); - listItems = Array.from(element.querySelectorAll(pickerListItemName)); - expect(listItems.length).to.equal(2); - expect(element.selection).to.equal("apples,oranges"); - - element.dispatchEvent(deleteEvent); - await Updates.next(); - listItems = Array.from(element.querySelectorAll(pickerListItemName)); - expect(listItems.length).to.equal(1); - expect(element.selection).to.equal("apples"); - - await disconnect(); - }); - - it("picker should apply settings to place scaling menu below input by default", async () => { - const { element, connect, disconnect } = await setupPicker(); - await connect(); - - await Updates.next(); - - expect(element.menuConfig.verticalDefaultPosition).to.equal("bottom"); - expect(element.menuConfig.verticalScaling).to.equal("fill"); - - await disconnect(); - }); - - it("picker should apply menu placement selections", async () => { - const { element, connect, disconnect } = await setupPicker(); - element.menuPlacement = "top-fill"; - await connect(); - - await Updates.next(); - - expect(element.menuConfig.verticalDefaultPosition).to.equal("top"); - expect(element.menuConfig.verticalPositioningMode).to.equal("locktodefault"); - expect(element.menuConfig.verticalScaling).to.equal("fill"); - - element.menuPlacement = "top"; - await Updates.next(); - - expect(element.menuConfig.verticalDefaultPosition).to.equal("top"); - expect(element.menuConfig.verticalPositioningMode).to.equal("locktodefault"); - expect(element.menuConfig.verticalScaling).to.equal("content"); - - element.menuPlacement = "bottom"; - await Updates.next(); - - expect(element.menuConfig.verticalDefaultPosition).to.equal("bottom"); - expect(element.menuConfig.verticalPositioningMode).to.equal("locktodefault"); - expect(element.menuConfig.verticalScaling).to.equal("content"); - - element.menuPlacement = "bottom-fill"; - await Updates.next(); - - expect(element.menuConfig.verticalDefaultPosition).to.equal("bottom"); - expect(element.menuConfig.verticalPositioningMode).to.equal("locktodefault"); - expect(element.menuConfig.verticalScaling).to.equal("fill"); - - element.menuPlacement = "tallest-fill"; - await Updates.next(); - - expect(element.menuConfig.verticalDefaultPosition).to.equal(undefined); - expect(element.menuConfig.verticalPositioningMode).to.equal("dynamic"); - expect(element.menuConfig.verticalScaling).to.equal("fill"); - - element.menuPlacement = "tallest"; - await Updates.next(); - - expect(element.menuConfig.verticalDefaultPosition).to.equal(undefined); - expect(element.menuConfig.verticalPositioningMode).to.equal("dynamic"); - expect(element.menuConfig.verticalScaling).to.equal("content"); - - await disconnect(); - }); - - /** - * Picker-list tests - */ - it("picker list should include a role of `list`", async () => { - const { element, connect, disconnect } = await setupPickerList(); - - await connect(); - - expect(element.getAttribute("role")).to.equal("list"); - - await disconnect(); - }); - - /** - * Picker-list-item tests - */ - it("picker list-item should include a role of `listitem`", async () => { - const { element, connect, disconnect } = await setupPickerListItem(); - - await connect(); - - expect(element.getAttribute("role")).to.equal("listitem"); - - await disconnect(); - }); - - it("picker list-item emits 'pickeriteminvoked' event when clicked", async () => { - const { element, connect, disconnect } = await setupPickerListItem(); - - let wasInvoked: boolean = false; - - element.addEventListener("pickeriteminvoked", e => { - wasInvoked = true; - }); - - await connect(); - - element.click(); - - expect(wasInvoked).to.equal(true); - - await disconnect(); - }); - - it("picker list-item emits 'pickeriteminvoked' event on 'Enter'", async () => { - const { element, connect, disconnect } = await setupPickerListItem(); - - let wasInvoked: boolean = false; - - element.addEventListener("pickeriteminvoked", e => { - wasInvoked = true; - }); - - await connect(); - - element.dispatchEvent(enterEvent); - - expect(wasInvoked).to.equal(true); - - await disconnect(); - }); - - it("picker list-item does not emit 'pickeriteminvoked' event when disabled and clicked", async () => { - const { element, connect, disconnect } = await setupPickerListItem(); - - let wasInvoked: boolean = false; - element.disabled = true; - - element.addEventListener("pickeriteminvoked", e => { - wasInvoked = true; - }); - - await connect(); - - element.click(); - - expect(wasInvoked).to.equal(false); - - await disconnect(); - }); - - it("picker list-item does not emit 'pickeriteminvoked' event on 'Enter' when disabled", async () => { - const { element, connect, disconnect } = await setupPickerListItem(); - - let wasInvoked: boolean = false; - - element.disabled = true; - element.addEventListener("pickeriteminvoked", e => { - wasInvoked = true; - }); - - await connect(); - - element.dispatchEvent(enterEvent); - - expect(wasInvoked).to.equal(false); - - await disconnect(); - }); - - /** - * Picker-menu tests - */ - it("picker menu should include a role of `list`", async () => { - const { element, connect, disconnect } = await setupPickerMenu(); - - await connect(); - - expect(element.getAttribute("role")).to.equal("listbox"); - - await disconnect(); - }); - - /** - * Picker-menu-option tests - */ - it("picker menu-option should include a role of `option`", async () => { - const { element, connect, disconnect } = await setupPickerMenuOption(); - - await connect(); - - expect(element.getAttribute("role")).to.equal("option"); - - await disconnect(); - }); - - it("picker menu-option emits 'pickeroptioninvoked' event when clicked", async () => { - const { element, connect, disconnect } = await setupPickerMenuOption(); - - let wasInvoked: boolean = false; - - element.addEventListener("pickeroptioninvoked", e => { - wasInvoked = true; - }); - - await connect(); - - element.click(); - - expect(wasInvoked).to.equal(true); - - await disconnect(); - }); -}); diff --git a/packages/web-components/fast-foundation/src/picker/picker.template.ts b/packages/web-components/fast-foundation/src/picker/picker.template.ts deleted file mode 100644 index fb5ea5c577b..00000000000 --- a/packages/web-components/fast-foundation/src/picker/picker.template.ts +++ /dev/null @@ -1,130 +0,0 @@ -import type { ElementViewTemplate, ViewTemplate } from "@microsoft/fast-element"; -import { html, ref, when } from "@microsoft/fast-element"; -import type { TemplateElementDependency } from "../patterns/index.js"; -import { tagFor } from "../patterns/index.js"; -import type { FASTPicker } from "./picker.js"; - -function defaultListItemTemplate(options: PickerOptions): ViewTemplate { - const pickerListItemTag = html.partial(tagFor(options.pickerListItem)); - return html` - <${pickerListItemTag} - ?disabled = "${(x, c) => c.parent.disabled}" - value="${x => x}" - :contentsTemplate="${(x, c) => c.parent.listItemContentsTemplate}" - > - - `; -} - -function defaultMenuOptionTemplate(options: PickerOptions): ViewTemplate { - const pickerMenuOptionTag = html.partial(tagFor(options.pickerMenuOption)); - return html` - <${pickerMenuOptionTag} - value="${x => x}" - :contentsTemplate="${(x, c) => c.parent.menuOptionContentsTemplate}" - > - - `; -} - -/** - * Picker configuration options - * @public - */ -export type PickerOptions = { - anchoredRegion: TemplateElementDependency; - pickerMenu: TemplateElementDependency; - pickerMenuOption: TemplateElementDependency; - pickerList: TemplateElementDependency; - pickerListItem: TemplateElementDependency; - progressRing: TemplateElementDependency; -}; - -/** - * The template for the List Picker component. - * @public - */ -export function pickerTemplate( - options: PickerOptions -): ElementViewTemplate { - const anchoredRegionTag = html.partial(tagFor(options.anchoredRegion)); - const pickerMenuTag = tagFor(options.pickerMenu); - const pickerListTag = tagFor(options.pickerList); - const progressRingTag = html.partial(tagFor(options.progressRing)); - - return html` - - `; -} diff --git a/packages/web-components/fast-foundation/src/picker/picker.ts b/packages/web-components/fast-foundation/src/picker/picker.ts deleted file mode 100644 index 3d8301e31d3..00000000000 --- a/packages/web-components/fast-foundation/src/picker/picker.ts +++ /dev/null @@ -1,1091 +0,0 @@ -import type { HTMLView, ViewTemplate } from "@microsoft/fast-element"; -import { - attr, - html, - nullableNumberConverter, - observable, - oneWay, - ref, - RepeatDirective, - Updates, -} from "@microsoft/fast-element"; -import { Context } from "@microsoft/fast-element/context.js"; -import { ViewBehaviorOrchestrator } from "@microsoft/fast-element/utilities.js"; -import { - keyArrowDown, - keyArrowLeft, - keyArrowRight, - keyArrowUp, - keyBackspace, - keyDelete, - keyEnter, - keyEscape, - uniqueId, -} from "@microsoft/fast-web-utilities"; -import type { - AnchoredRegionConfig, - FASTAnchoredRegion, -} from "../anchored-region/index.js"; -import { - FlyoutPosBottom, - FlyoutPosBottomFill, - FlyoutPosTallest, - FlyoutPosTallestFill, - FlyoutPosTop, - FlyoutPosTopFill, -} from "../anchored-region/index.js"; -import { getRootActiveElement } from "../utilities/index.js"; -import { FASTPickerListItem } from "./picker-list-item.js"; -import type { FASTPickerList } from "./picker-list.js"; -import { FASTPickerMenuOption } from "./picker-menu-option.js"; -import type { FASTPickerMenu } from "./picker-menu.js"; -import { FormAssociatedPicker } from "./picker.form-associated.js"; -import { MenuPlacement } from "./picker.options.js"; -import { DefaultPickerContext, PickerContext } from "./picker-context.js"; - -const pickerInputTemplate: ViewTemplate = html` - x.disabled} - autocapitalize="off" - autocomplete="off" - haspopup="list" - aria-label="${x => x.label}" - aria-labelledby="${x => x.labelledBy}" - placeholder="${x => x.placeholder}" - ${ref("inputElement")} - /> -`; - -/** - * A Picker Custom HTML Element. This is an early "alpha" version of the component. - * Developers should expect the api to evolve, breaking changes are possible. - * - * @beta - */ -export class FASTPicker extends FormAssociatedPicker { - /** - * Currently selected items. Comma delineated string ie. "apples,oranges". - * - * @remarks - * HTML Attribute: selection - */ - @attr({ attribute: "selection" }) - public selection: string = ""; - protected selectionChanged(): void { - if (this.$fastController.isConnected) { - this.handleSelectionChange(); - if (this.proxy instanceof HTMLInputElement) { - this.proxy.value = this.selection; - this.validate(); - } - } - } - - /** - * Currently available options. Comma delineated string ie. "apples,oranges". - * - * @remarks - * HTML Attribute: options - */ - @attr({ attribute: "options" }) - public options: string; - protected optionsChanged(): void { - this.optionsList = this.options - .split(",") - .map(opt => opt.trim()) - .filter(opt => opt !== ""); - } - - /** - * Indicates whether the component should remove an option from the list when it is in the selection. - * - * @deprecated - use `Picker.disableSelectionFilter`. - */ - @observable - public filterSelected: boolean = false; - protected filterSelectedChanged(): void { - // keep the main prop in sync - if (this.disableSelectionFilter === this.filterSelected) { - this.disableSelectionFilter = !this.filterSelected; - } - } - - /** - * Indicates whether the component should remove an option from the list when it is in the selection. - * - * @remarks - * HTML Attribute: disable-selection-filter - */ - @attr({ attribute: "disable-selection-filter", mode: "boolean" }) - public disableSelectionFilter: boolean = false; - protected disableSelectionFilterChanged(): void { - // keep depracated prop in sync - if (this.disableSelectionFilter === this.filterQuery) { - this.filterSelected = !this.disableSelectionFilter; - } - } - - /** - * Indicates whether the component should remove options based on the current query. - * - * @deprecated - use `Picker.disableQueryFilter`. - */ - @observable - public filterQuery: boolean = true; - protected filterQueryChanged(): void { - // keep the main prop in sync - if (this.disableQueryFilter === this.filterQuery) { - this.disableQueryFilter = !this.filterQuery; - } - } - - /** - * Indicates whether the component should remove options based on the current query. - * - * @remarks - * HTML Attribute: disable-query-filter - */ - @attr({ attribute: "disable-query-filter", mode: "boolean" }) - public disableQueryFilter: boolean = false; - protected disableQueryFilterChanged(): void { - // keep depracated prop in sync - if (this.disableQueryFilter === this.filterQuery) { - this.filterQuery = !this.disableQueryFilter; - } - } - - /** - * The maximum number of items that can be selected. - * - * @remarks - * HTML Attribute: max-selected - */ - @attr({ attribute: "max-selected", converter: nullableNumberConverter }) - public maxSelected: number | null = null; - - /** - * The text to present to assistive technolgies when no suggestions are available. - * - * @remarks - * HTML Attribute: no-suggestions-text - */ - @attr({ attribute: "no-suggestions-text" }) - public noSuggestionsText: string = "No suggestions available"; - - /** - * The text to present to assistive technolgies when suggestions are available. - * - * @remarks - * HTML Attribute: suggestions-available-text - */ - @attr({ attribute: "suggestions-available-text" }) - public suggestionsAvailableText: string = "Suggestions available"; - - /** - * The text to present to assistive technologies when suggestions are loading. - * - * @remarks - * HTML Attribute: loading-text - */ - @attr({ attribute: "loading-text" }) - public loadingText: string = "Loading suggestions"; - - /** - * Disables the picker. - * - * @public - * @remarks - * HTML Attribute: disabled - */ - @attr({ mode: "boolean" }) - public disabled: boolean; - public disabledChanged(previous: boolean, next: boolean): void { - if (super.disabledChanged) { - super.disabledChanged(previous, next); - } - if (this.$fastController.isConnected) { - this.pickerContext.disabled = this.disabled; - if (this.disabled) { - this.toggleFlyout(false); - } - } - } - - /** - * Applied to the aria-label attribute of the input element - * - * @remarks - * HTML Attribute: label - */ - @attr({ attribute: "label" }) - public label: string; - - /** - * Applied to the aria-labelledby attribute of the input element - * - * @remarks - * HTML Attribute: labelledby - */ - @attr({ attribute: "labelledby" }) - public labelledBy: string; - - /** - * Applied to the placeholder attribute of the input element - * - * @remarks - * HTML Attribute: placholder - */ - @attr({ attribute: "placeholder" }) - public placeholder: string; - - /** - * Controls menu placement - * - * @remarks - * HTML Attribute: menu-placement - */ - @attr({ attribute: "menu-placement" }) - public menuPlacement: MenuPlacement = MenuPlacement.bottomFill; - protected menuPlacementChanged(): void { - if (this.$fastController.isConnected) { - this.updateMenuConfig(); - } - } - - /** - * Whether to display a loading state if the menu is opened. - * - */ - @observable - public showLoading: boolean = false; - protected showLoadingChanged(): void { - if (this.$fastController.isConnected) { - Updates.enqueue(() => { - this.setFocusedOption(0); - }); - } - } - - /** - * Template used to generate selected items. - * This is used in a repeat directive. - * - */ - @observable - public listItemTemplate: ViewTemplate; - protected listItemTemplateChanged(): void { - this.updateListItemTemplate(); - } - - /** - * Default template to use for selected items (usually specified in the component template). - * This is used in a repeat directive. - * - */ - @observable - public defaultListItemTemplate?: ViewTemplate; - protected defaultListItemTemplateChanged(): void { - this.updateListItemTemplate(); - } - - /** - * The item template currently in use. - * - * @internal - */ - @observable - public activeListItemTemplate?: ViewTemplate; - - /** - * Template to use for available options. - * This is used in a repeat directive. - * - */ - @observable - public menuOptionTemplate: ViewTemplate; - protected menuOptionTemplateChanged(): void { - this.updateOptionTemplate(); - } - - /** - * Default template to use for available options (usually specified in the template). - * This is used in a repeat directive. - * - */ - @observable - public defaultMenuOptionTemplate?: ViewTemplate; - protected defaultMenuOptionTemplateChanged(): void { - this.updateOptionTemplate(); - } - - /** - * The option template currently in use. - * - * @internal - */ - @observable - public activeMenuOptionTemplate?: ViewTemplate; - - /** - * Template to use for the contents of a selected list item - * - */ - @observable - public listItemContentsTemplate: ViewTemplate; - - /** - * Template to use for the contents of menu options - * - */ - @observable - public menuOptionContentsTemplate: ViewTemplate; - - /** - * Current list of options in array form - * - */ - @observable - public optionsList: string[] = []; - private optionsListChanged(): void { - this.updateFilteredOptions(); - } - - /** - * The text value currently in the input field - * - */ - @observable - public query: string; - protected queryChanged(): void { - if (this.$fastController.isConnected) { - if (this.inputElement.value !== this.query) { - this.inputElement.value = this.query; - } - this.updateFilteredOptions(); - this.$emit("querychange", { bubbles: false }); - } - } - - /** - * Current list of filtered options in array form - * - * @internal - */ - @observable - public filteredOptionsList: string[] = []; - - /** - * Indicates if the flyout menu is open or not - * - * @internal - */ - @observable - public flyoutOpen: boolean = false; - protected flyoutOpenChanged(): void { - if (this.flyoutOpen) { - Updates.enqueue(this.setRegionProps); - this.$emit("menuopening", { bubbles: false }); - } else { - this.$emit("menuclosing", { bubbles: false }); - } - } - - /** - * The id of the menu element - * - * @internal - */ - @observable - public menuId: string; - - /** - * The tag for the selected list element (ie. "fast-picker-list" vs. "fluent-picker-list") - * - * @internal - */ - @observable - public selectedListTag: string; - - /** - * The tag for the menu element (ie. "fast-picker-menu" vs. "fluent-picker-menu") - * - * @internal - */ - @observable - public menuTag: string; - - /** - * Index of currently active menu option - * - * @internal - */ - @observable - public menuFocusIndex: number = -1; - - /** - * Id of currently active menu option. - * - * @internal - */ - @observable - public menuFocusOptionId: string | undefined; - - /** - * Internal flag to indicate no options available display should be shown. - * - * @internal - */ - @observable - public showNoOptions: boolean = true; - - /** - * The anchored region config to apply. - * - * @internal - */ - @observable - public menuConfig: AnchoredRegionConfig; - - /** - * Reference to the placeholder element for the repeat directive - * - */ - public itemsPlaceholderElement: Node; - - /** - * reference to the input element - * - * @internal - */ - public inputElement: HTMLInputElement; - - /** - * reference to the selected list element - * - * @internal - */ - public listElement: FASTPickerList; - - /** - * reference to the menu element - * - * @internal - */ - public menuElement: FASTPickerMenu; - - /** - * reference to the anchored region element - * - * @internal - */ - public region: FASTAnchoredRegion; - - /** - * Currently selected items - * - * @internal - */ - @observable - public selectedItems: string[] = []; - - private optionsPlaceholder: Node; - private inputElementView: HTMLView | null = null; - private behaviorOrchestrator: ViewBehaviorOrchestrator | null = null; - - private pickerContext: PickerContext = new DefaultPickerContext(); - /** - * @internal - */ - public connectedCallback(): void { - super.connectedCallback(); - this.pickerContext.disabled = this.disabled; - Context.provide(this, PickerContext, this.pickerContext); - if (!this.listElement) { - this.listElement = document.createElement( - this.selectedListTag - ) as FASTPickerList; - this.appendChild(this.listElement); - this.itemsPlaceholderElement = document.createComment(""); - this.listElement.appendChild(this.itemsPlaceholderElement); - } - - this.inputElementView = pickerInputTemplate.render(this, this.listElement); - - const match: string = this.menuTag.toUpperCase(); - this.menuElement = Array.from(this.children).find((element: HTMLElement) => { - return element.tagName === match; - }) as FASTPickerMenu; - - if (!this.menuElement) { - this.menuElement = document.createElement(this.menuTag) as FASTPickerMenu; - this.appendChild(this.menuElement); - - if (this.menuElement.id === "") { - this.menuElement.id = uniqueId("listbox-"); - } - - this.menuId = this.menuElement.id; - } - - if (!this.optionsPlaceholder) { - this.optionsPlaceholder = document.createComment(""); - this.menuElement.appendChild(this.optionsPlaceholder); - } - - this.updateMenuConfig(); - Updates.enqueue(() => this.initialize()); - } - - public disconnectedCallback() { - super.disconnectedCallback(); - this.toggleFlyout(false); - this.inputElement.removeEventListener("input", this.handleTextInput); - this.inputElement.removeEventListener("click", this.handleInputClick); - - if (this.inputElementView !== null) { - this.inputElementView.dispose(); - this.inputElementView = null; - } - } - - /** - * Move focus to the input element - * @public - */ - public focus() { - this.inputElement.focus(); - } - - /** - * Initialize the component. This is delayed a frame to ensure children are connected as well. - */ - private initialize(): void { - this.updateListItemTemplate(); - this.updateOptionTemplate(); - - if (this.behaviorOrchestrator === null) { - this.behaviorOrchestrator = ViewBehaviorOrchestrator.create(this); - this.$fastController.addBehavior(this.behaviorOrchestrator); - - this.behaviorOrchestrator.addBehaviorFactory( - new RepeatDirective( - oneWay(x => x.selectedItems), - oneWay(x => x.activeListItemTemplate), - { positioning: true } - ), - this.itemsPlaceholderElement - ); - - this.behaviorOrchestrator.addBehaviorFactory( - new RepeatDirective( - oneWay(x => x.filteredOptionsList), - oneWay(x => x.activeMenuOptionTemplate), - { positioning: true } - ), - this.optionsPlaceholder - ); - } - - this.inputElement.addEventListener("input", this.handleTextInput); - this.inputElement.addEventListener("click", this.handleInputClick); - this.menuElement.suggestionsAvailableText = this.suggestionsAvailableText; - this.menuElement.addEventListener( - "optionsupdated", - this.handleMenuOptionsUpdated - ); - this.handleSelectionChange(); - } - - /** - * Toggles the menu flyout - */ - private toggleFlyout(open: boolean): void { - if (this.flyoutOpen === open || (this.disabled && !this.flyoutOpen)) { - return; - } - - if (open && getRootActiveElement(this) === this.inputElement) { - this.flyoutOpen = open; - return; - } - - this.flyoutOpen = false; - this.disableMenu(); - return; - } - - /** - * Handle input event from input element - */ - private handleTextInput = (e: InputEvent): void => { - this.query = this.inputElement.value; - }; - - /** - * Handle click event from input element - */ - private handleInputClick = (e: MouseEvent): void => { - if (e.defaultPrevented || this.disabled) { - return; - } - e.preventDefault(); - this.toggleFlyout(true); - }; - - /** - * Handle the menu options updated event from the child menu - */ - private handleMenuOptionsUpdated = (e: Event): void => { - e.preventDefault(); - Updates.enqueue(() => { - this.setFocusedOption(0); - }); - }; - - /** - * Handle key down events. - */ - public handleKeyDown(e: KeyboardEvent): boolean { - if (e.defaultPrevented || this.disabled) { - return false; - } - const activeElement = getRootActiveElement(this); - switch (e.key) { - // TODO: what should "home" and "end" keys do, exactly? - // - // case keyHome: { - // if (!this.flyoutOpen) { - // this.toggleFlyout(true); - // } else { - // if (this.menuElement.optionElements.length > 0) { - // this.setFocusedOption(0); - // } - // } - // return false; - // } - - // case keyEnd: { - // if (!this.flyoutOpen) { - // this.toggleFlyout(true); - // } else { - // if (this.menuElement.optionElements.length > 0) { - // this.toggleFlyout(true); - // this.setFocusedOption(this.menuElement.optionElements.length - 1); - // } - // } - // return false; - // } - - case keyArrowDown: { - if (!this.flyoutOpen) { - this.toggleFlyout(true); - } else { - const nextFocusOptionIndex = this.flyoutOpen - ? Math.min( - this.menuFocusIndex + 1, - this.menuElement.optionElements.length - 1 - ) - : 0; - this.setFocusedOption(nextFocusOptionIndex); - } - return false; - } - - case keyArrowUp: { - if (!this.flyoutOpen) { - this.toggleFlyout(true); - } else { - const previousFocusOptionIndex = this.flyoutOpen - ? Math.max(this.menuFocusIndex - 1, 0) - : 0; - this.setFocusedOption(previousFocusOptionIndex); - } - return false; - } - - case keyEscape: { - this.toggleFlyout(false); - return false; - } - - case keyEnter: { - if ( - this.menuFocusIndex !== -1 && - this.menuElement.optionElements.length > this.menuFocusIndex - ) { - this.menuElement.optionElements[this.menuFocusIndex].click(); - } - return false; - } - - case keyArrowRight: { - if (activeElement !== this.inputElement) { - this.incrementFocusedItem(1); - return false; - } - // don't block if arrow keys moving caret in input element - return true; - } - - case keyArrowLeft: { - if (this.inputElement.selectionStart === 0) { - this.incrementFocusedItem(-1); - return false; - } - // don't block if arrow keys moving caret in input element - return true; - } - - case keyDelete: - case keyBackspace: { - if (activeElement === null) { - return true; - } - - if (activeElement === this.inputElement) { - if (this.inputElement.selectionStart === 0) { - this.selection = this.selectedItems - .slice(0, this.selectedItems.length - 1) - .toString(); - this.toggleFlyout(false); - return false; - } - // let text deletion proceed - return true; - } - - const selectedItems: Element[] = Array.from(this.listElement.children); - const currentFocusedItemIndex: number = - selectedItems.indexOf(activeElement); - - if (currentFocusedItemIndex > -1) { - // delete currently focused item - this.selection = this.selectedItems - .splice(currentFocusedItemIndex, 1) - .toString(); - Updates.enqueue(() => { - ( - selectedItems[ - Math.min(selectedItems.length, currentFocusedItemIndex) - ] as HTMLElement - ).focus(); - }); - return false; - } - return true; - } - } - this.toggleFlyout(true); - return true; - } - - /** - * Handle focus in events. - */ - public handleFocusIn(e: FocusEvent): boolean { - return false; - } - - /** - * Handle focus out events. - */ - public handleFocusOut(e: FocusEvent): boolean { - if ( - this.menuElement === undefined || - !this.menuElement.contains(e.relatedTarget as Element) - ) { - this.toggleFlyout(false); - } - - return false; - } - - /** - * The list of selected items has changed - */ - public handleSelectionChange(): void { - if (this.selectedItems.toString() === this.selection) { - return; - } - - this.selectedItems = this.selection === "" ? [] : this.selection.split(","); - - this.updateFilteredOptions(); - - Updates.enqueue(() => { - this.checkMaxItems(); - }); - this.$emit("selectionchange", { bubbles: false }); - } - - /** - * Anchored region is loaded, menu and options exist in the DOM. - */ - public handleRegionLoaded(e: Event): void { - Updates.enqueue(() => { - this.$emit("menuloaded", { bubbles: false }); - }); - } - - /** - * Sets properties on the anchored region once it is instanciated. - */ - private setRegionProps = (): void => { - if (!this.flyoutOpen) { - return; - } - if (this.region === null || this.region === undefined) { - // TODO: limit this - Updates.enqueue(this.setRegionProps); - return; - } - this.region.anchorElement = this.inputElement; - }; - - /** - * Checks if the maximum number of items has been chosen and updates the ui. - */ - private checkMaxItems(): void { - if (this.inputElement === undefined) { - return; - } - if ( - this.maxSelected !== null && - this.maxSelected !== 0 && - this.selectedItems.length >= this.maxSelected - ) { - if (getRootActiveElement(this) === this.inputElement) { - const selectedItemInstances: Element[] = Array.from( - this.listElement.querySelectorAll("[role='option']") - ); - ( - selectedItemInstances[selectedItemInstances.length - 1] as HTMLElement - ).focus(); - } - this.inputElement.hidden = true; - } else { - this.inputElement.hidden = false; - } - } - - /** - * A list item has been invoked. - */ - public handleItemInvoke(e: Event): boolean { - if (e.defaultPrevented) { - return false; - } - if (e.target instanceof FASTPickerListItem) { - const listItems: Element[] = Array.from( - this.listElement.querySelectorAll("[role='option']") - ); - const itemIndex: number = listItems.indexOf(e.target as Element); - if (itemIndex !== -1) { - const newSelection: string[] = this.selectedItems.slice(); - newSelection.splice(itemIndex, 1); - this.selection = newSelection.toString(); - Updates.enqueue(() => { - this.incrementFocusedItem(0); - this.toggleFlyout(true); - }); - } - return false; - } - return true; - } - - /** - * A menu option has been invoked. - */ - public handleOptionInvoke(e: Event): boolean { - if (e.defaultPrevented) { - return false; - } - - if (e.target instanceof FASTPickerMenuOption && e.target.value !== undefined) { - if (this.maxSelected === 0) { - // if we don't allow selection just update the query - this.query = e.target.value; - } else { - this.query = ""; - this.selection = `${this.selection}${this.selection === "" ? "" : ","}${ - e.target.value - }`; - } - - this.toggleFlyout(false); - this.inputElement.focus(); - return false; - } - - return true; - } - - /** - * Increments the focused list item by the specified amount - */ - private incrementFocusedItem(increment: number) { - if (this.selectedItems.length === 0) { - this.inputElement.focus(); - return; - } - - const selectedItemsAsElements: Element[] = Array.from( - this.listElement.querySelectorAll("[role='option']") - ); - - const activeElement = getRootActiveElement(this); - if (activeElement !== null) { - let currentFocusedItemIndex: number = - selectedItemsAsElements.indexOf(activeElement); - if (currentFocusedItemIndex === -1) { - // use the input element - currentFocusedItemIndex = selectedItemsAsElements.length; - } - - const newFocusedItemIndex = Math.min( - selectedItemsAsElements.length, - Math.max(0, currentFocusedItemIndex + increment) - ); - if (newFocusedItemIndex === selectedItemsAsElements.length) { - if ( - this.maxSelected !== null && - this.selectedItems.length >= this.maxSelected - ) { - ( - selectedItemsAsElements[newFocusedItemIndex - 1] as HTMLElement - ).focus(); - } else { - this.inputElement.focus(); - } - } else { - (selectedItemsAsElements[newFocusedItemIndex] as HTMLElement).focus(); - } - } - } - - /** - * Disables the menu. Note that the menu can be open, just doens't have any valid options on display. - */ - private disableMenu(): void { - this.menuFocusIndex = -1; - this.menuFocusOptionId = undefined; - this.inputElement?.removeAttribute("aria-activedescendant"); - this.inputElement?.removeAttribute("aria-owns"); - this.inputElement?.removeAttribute("aria-expanded"); - } - - /** - * Sets the currently focused menu option by index - */ - private setFocusedOption(optionIndex: number): void { - this.updateNoOptions(); - if ( - !this.flyoutOpen || - optionIndex === -1 || - this.showNoOptions || - this.showLoading - ) { - this.disableMenu(); - return; - } - - if (this.menuElement.optionElements.length === 0) { - return; - } - - this.menuElement.optionElements.forEach((element: HTMLElement) => { - element.setAttribute("aria-selected", "false"); - }); - - this.menuFocusIndex = optionIndex; - if (this.menuFocusIndex > this.menuElement.optionElements.length - 1) { - this.menuFocusIndex = this.menuElement.optionElements.length - 1; - } - - this.menuFocusOptionId = this.menuElement.optionElements[this.menuFocusIndex].id; - - this.inputElement.setAttribute("aria-owns", this.menuId); - this.inputElement.setAttribute("aria-expanded", "true"); - this.inputElement.setAttribute("aria-activedescendant", this.menuFocusOptionId); - - const focusedOption = this.menuElement.optionElements[this.menuFocusIndex]; - - focusedOption.setAttribute("aria-selected", "true"); - - focusedOption.scrollIntoView(true); - } - - /** - * Updates the template used for the list item repeat behavior - */ - private updateListItemTemplate(): void { - this.activeListItemTemplate = - this.listItemTemplate ?? this.defaultListItemTemplate; - } - - /** - * Updates the template used for the menu option repeat behavior - */ - private updateOptionTemplate(): void { - this.activeMenuOptionTemplate = - this.menuOptionTemplate ?? this.defaultMenuOptionTemplate; - } - - /** - * Updates the filtered options array - */ - private updateFilteredOptions(): void { - this.filteredOptionsList = this.optionsList.slice(0); - if (!this.disableSelectionFilter) { - this.filteredOptionsList = this.filteredOptionsList.filter( - el => this.selectedItems.indexOf(el) === -1 - ); - } - if (!this.disableQueryFilter && this.query !== "" && this.query !== undefined) { - // compare case-insensitive - const filterQuery = this.query.toLowerCase(); - this.filteredOptionsList = this.filteredOptionsList.filter( - el => el.toLowerCase().indexOf(filterQuery) !== -1 - ); - } - } - - /** - * Updates the menu configuration - */ - private updateMenuConfig(): void { - let newConfig = this.configLookup[this.menuPlacement]; - - if (newConfig === null) { - newConfig = FlyoutPosBottomFill; - } - - this.menuConfig = { - ...newConfig, - autoUpdateMode: "auto", - fixedPlacement: true, - horizontalViewportLock: false, - verticalViewportLock: false, - }; - } - - /** - * matches menu placement values with the associated menu config - */ - private configLookup: object = { - top: FlyoutPosTop, - bottom: FlyoutPosBottom, - tallest: FlyoutPosTallest, - "top-fill": FlyoutPosTopFill, - "bottom-fill": FlyoutPosBottomFill, - "tallest-fill": FlyoutPosTallestFill, - }; - - private updateNoOptions(): void { - this.showNoOptions = this.menuElement.optionElements.length === 0; - } -} diff --git a/packages/web-components/fast-foundation/src/picker/stories/picker.register.ts b/packages/web-components/fast-foundation/src/picker/stories/picker.register.ts deleted file mode 100644 index 7f35ad01e6d..00000000000 --- a/packages/web-components/fast-foundation/src/picker/stories/picker.register.ts +++ /dev/null @@ -1,240 +0,0 @@ -import { css } from "@microsoft/fast-element"; -import { FASTPickerListItem } from "../picker-list-item.js"; -import { pickerListItemTemplate } from "../picker-list-item.template.js"; -import { FASTPickerList } from "../picker-list.js"; -import { pickerListTemplate } from "../picker-list.template.js"; -import { FASTPickerMenuOption } from "../picker-menu-option.js"; -import { pickerMenuOptionTemplate } from "../picker-menu-option.template.js"; -import { FASTPickerMenu } from "../picker-menu.js"; -import { pickerMenuTemplate } from "../picker-menu.template.js"; -import { FASTPicker } from "../picker.js"; -import { pickerTemplate } from "../picker.template.js"; - -const pickerStyles = css` - :host([hidden]) { - display: none; - } - :host { - display: inline-flex; - box-sizing: border-box; - } - fast-anchored-region { - z-index: 1000; - display: flex; - font-family: var(--body-font); - font-size: var(--type-ramp-base-font-size); - } - .loaded { - opacity: 1; - pointer-events: none; - } - .loading-display, - .no-options-display { - background: var(--neutral-layer-floating); - width: 100%; - min-height: calc( - (var(--base-height-multiplier) + var(--density)) * var(--design-unit) * 1px - ); - box-sizing: border-box; - display: flex; - flex-direction: column; - align-items: center; - justify-items: center; - padding: calc((10 + (var(--design-unit) * 2 * var(--density))) * 1px); - } - .loading-progress { - width: 42px; - height: 42px; - } - .bottom { - flex-direction: column; - } - .top { - flex-direction: column-reverse; - } -`; - -const pickerListStyles = css` - :host { - min-height: calc( - (var(--base-height-multiplier) + var(--density)) * var(--design-unit) * 1px - ); - display: flex; - flex-direction: row; - column-gap: calc(var(--design-unit) * 1px); - row-gap: calc(var(--design-unit) * 1px); - flex-wrap: wrap; - box-sizing: border-box; - background: var(--neutral-fill-input-rest); - border-radius: calc(var(--control-corner-radius) * 1px); - border: calc(var(--stroke-width) * 1px) solid var(--accent-fill-rest); - font-family: var(--body-font); - font-size: var(--type-ramp-base-font-size); - line-height: var(--type-ramp-base-line-height); - padding: calc(var(--design-unit) * 1px) calc(var(--design-unit) * 2px); - } - :host(:not([disabled]):hover) { - background: var(--neutral-fill-input-hover); - border-color: var(--accent-fill-hover); - } - :host(:not([disabled]):active) { - background: var(--neutral-fill-input-active); - border-color: var(--accent-fill-active); - } - :host(:not([disabled]):focus-within) { - border-color: var(--focus-stroke-outer); - box-shadow: 0 0 0 1px var(--focus-stroke-outer) inset; - } - ::slotted([role="combobox"]) { - height: calc( - (var(--base-height-multiplier) + var(--density)) * var(--design-unit) * 1px - ); - width: auto; - box-sizing: border-box; - border: none; - color: var(--neutral-foreground-rest); - background: var(--neutral-fill-input-hover); - outline: none; - user-select: none; - padding: 0 calc(var(--design-unit) * 2px + 1px); - } - ::slotted([role="combobox"][disabled]) { - cursor: not-allowed; - } -`; - -const pickerListItemStyles = css` - :host { - display: flex; - align-items: center; - justify-items: center; - font-family: var(--body-font); - border-radius: calc(var(--control-corner-radius) * 1px); - border: calc(var(--stroke-width) * 1px) solid transparent; - box-sizing: border-box; - color: var(--neutral-foreground-rest); - cursor: pointer; - fill: currentcolor; - font-size: var(--type-ramp-base-font-size); - height: calc( - (var(--base-height-multiplier) + var(--density)) * var(--design-unit) * 1px - ); - line-height: var(--type-ramp-base-line-height); - outline: none; - overflow: hidden; - padding: 0 calc(var(--design-unit) * 1px); - user-select: none; - white-space: nowrap; - } - :host([disabled]) { - cursor: not-allowed; - } - :host(:focus-visible:not([disabled])), - :host(:hover:not([disabled])) { - background: var(--accent-fill-rest); - color: var(--foreground-on-accent-rest); - } - :host(:focus-visible:not([disabled])) { - border-color: var(--focus-stroke-outer); - } -`; - -const pickerMenuStyles = css` - :host { - margin: calc(var(--design-unit) * 1px) 0; - background: var(--neutral-layer-floating); - z-index: 1000; - display: flex; - width: 100%; - box-sizing: border-box; - flex-direction: column; - overflow-y: auto; - overflow-x: hidden; - pointer-events: auto; - border-radius: calc(var(--control-corner-radius) * 1px); - padding: calc(var(--design-unit) * 1px) 0; - border: calc(var(--stroke-width) * 1px) solid transparent; - box-shadow: var(--elevation-shadow); - } - .suggestions-available-alert { - height: 0; - opacity: 0; - overflow: hidden; - } -`; - -const pickerMenuOptionStyles = css` - :host { - display: flex; - align-items: center; - justify-items: center; - font-family: var(--body-font); - border-radius: calc(var(--control-corner-radius) * 1px); - border: calc(var(--focus-stroke-width) * 1px) solid transparent; - box-sizing: border-box; - color: var(--neutral-foreground-rest); - cursor: pointer; - fill: currentcolor; - font-size: var(--type-ramp-base-font-size); - height: calc( - (var(--base-height-multiplier) + var(--density)) * var(--design-unit) * 1px - ); - line-height: var(--type-ramp-base-line-height); - margin: 0 calc(var(--design-unit) * 1px); - outline: none; - overflow: hidden; - padding: 0 calc(var(--design-unit) * 2.25px); - user-select: none; - white-space: nowrap; - } - :host(:focus-visible[role="option"]) { - border-color: var(--focus-stroke-outer); - background: var(--neutral-fill-rest); - color: var(--neutral-foreground-rest); - } - :host(:hover) { - background: var(--neutral-fill-hover); - color: var(--neutral-foreground-rest); - } - :host([aria-selected="true"]) { - background: var(--accent-fill-rest); - color: var(--foreground-on-accent-rest); - } -`; - -FASTPickerList.define({ - name: "fast-picker-list", - template: pickerListTemplate(), - styles: pickerListStyles, -}); - -FASTPickerListItem.define({ - name: "fast-picker-list-item", - template: pickerListItemTemplate(), - styles: pickerListItemStyles, -}); - -FASTPickerMenu.define({ - name: "fast-picker-menu", - template: pickerMenuTemplate(), - styles: pickerMenuStyles, -}); - -FASTPickerMenuOption.define({ - name: "fast-picker-menu-option", - template: pickerMenuOptionTemplate(), - styles: pickerMenuOptionStyles, -}); - -FASTPicker.define({ - name: "fast-picker", - template: pickerTemplate({ - anchoredRegion: "fast-anchored-region", - pickerList: "fast-picker-list", - pickerListItem: "fast-picker-list-item", - pickerMenu: "fast-picker-menu", - pickerMenuOption: "fast-picker-menu-option", - progressRing: "fast-progress-ring", - }), - styles: pickerStyles, -}); diff --git a/packages/web-components/fast-foundation/src/picker/stories/picker.stories.ts b/packages/web-components/fast-foundation/src/picker/stories/picker.stories.ts deleted file mode 100644 index 660f95b3f1d..00000000000 --- a/packages/web-components/fast-foundation/src/picker/stories/picker.stories.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { html } from "@microsoft/fast-element"; -import type { Meta, Story, StoryArgs } from "../../__test__/helpers.js"; -import { renderComponent } from "../../__test__/helpers.js"; -import type { FASTPicker } from "../picker.js"; -import { MenuPlacement } from "../picker.options.js"; - -const storyTemplate = html>` - -`; - -export default { - title: "Picker", - args: {}, - argTypes: { - queryFilterDisabled: { control: "boolean" }, - disabled: { control: "boolean" }, - disableQueryFilter: { control: "boolean" }, - disableSelectionFilter: { control: "boolean" }, - showLoading: { control: "boolean" }, - label: { control: "text" }, - labelledBy: { control: "text" }, - loadingText: { control: "text" }, - maxSelected: { control: "number" }, - menuPlacement: { control: "select", options: Object.values(MenuPlacement) }, - noSuggestionsText: { control: "text" }, - placeholder: { control: "text" }, - suggestionsAvailableText: { control: "text" }, - }, -} as Meta; - -export const Picker: Story = renderComponent(storyTemplate).bind({}); -Picker.args = { - label: "Fruit picker", - loadingText: "Loading", - noSuggestionsText: "No suggestions available", - options: "apple, orange, banana, mango, strawberry, raspberry, blueberry", - placeholder: "Choose fruit", - selection: "apple", - suggestionsAvailableText: "Found some fruit", - disabled: false, -}; - -export const PickerEmpty: Story = renderComponent(storyTemplate).bind({}); -PickerEmpty.args = { - label: "Fruit picker", - loadingText: "Loading", - noSuggestionsText: "No suggestions available", - options: "", - placeholder: "Choose fruit", - selection: "", - suggestionsAvailableText: "Found some fruit", -}; diff --git a/packages/web-components/fast-foundation/src/progress-ring/index.ts b/packages/web-components/fast-foundation/src/progress-ring/index.ts deleted file mode 100644 index 2ea8c42df96..00000000000 --- a/packages/web-components/fast-foundation/src/progress-ring/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { FASTProgressRing } from "./progress-ring.js"; -export type { ProgressRingOptions } from "./progress-ring.options.js"; -export { progressRingTemplate } from "./progress-ring.template.js"; diff --git a/packages/web-components/fast-foundation/src/progress-ring/progress-ring.options.ts b/packages/web-components/fast-foundation/src/progress-ring/progress-ring.options.ts deleted file mode 100644 index 8b6169ec1e4..00000000000 --- a/packages/web-components/fast-foundation/src/progress-ring/progress-ring.options.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { StaticallyComposableHTML } from "../utilities/template-helpers.js"; -import type { FASTProgressRing } from "./progress-ring.js"; - -/** - * ProgressRing configuration options - * @public - */ -export type ProgressRingOptions = { - indeterminateIndicator?: StaticallyComposableHTML; -}; diff --git a/packages/web-components/fast-foundation/src/progress-ring/progress-ring.pw.spec.ts b/packages/web-components/fast-foundation/src/progress-ring/progress-ring.pw.spec.ts deleted file mode 100644 index 35aeda62497..00000000000 --- a/packages/web-components/fast-foundation/src/progress-ring/progress-ring.pw.spec.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { expect, test } from "@playwright/test"; -import type { Locator, Page } from "@playwright/test"; -import { fixtureURL } from "../__test__/helpers.js"; - -test.describe("Progress ring", () => { - let page: Page; - let element: Locator; - let root: Locator; - - test.beforeAll(async ({ browser }) => { - page = await browser.newPage(); - - element = page.locator("fast-progress-ring"); - - root = page.locator("#storybook-root"); - - await page.goto(fixtureURL("progress-progress-ring--progress-ring")); - - await element.waitFor({ state: "attached" }); - }); - - test.afterAll(async () => { - await page.close(); - }); - - test("should include a role of progressbar", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element).toHaveAttribute("role", "progressbar"); - }); - - test("should set the `aria-valuenow` attribute with the `value` property when provided", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element).toHaveAttribute("aria-valuenow", "50"); - }); - - test("should set the `aria-valuemin` attribute with the `min` property when provided", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element).toHaveAttribute("aria-valuemin", "10"); - }); - - test("should set the `aria-valuemax` attribute with the `max` property when provided", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element).toHaveAttribute("aria-valuemax", "75"); - }); - - test("should render an element with a `determinate` slot when a value is provided", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - const progress = element.locator(".progress"); - - await expect(progress).toHaveAttribute("slot", "determinate"); - }); -}); diff --git a/packages/web-components/fast-foundation/src/progress-ring/progress-ring.template.ts b/packages/web-components/fast-foundation/src/progress-ring/progress-ring.template.ts deleted file mode 100644 index 05ef4592a35..00000000000 --- a/packages/web-components/fast-foundation/src/progress-ring/progress-ring.template.ts +++ /dev/null @@ -1,59 +0,0 @@ -import type { ElementViewTemplate } from "@microsoft/fast-element"; -import { html, when } from "@microsoft/fast-element"; -import { staticallyCompose } from "../utilities/template-helpers.js"; -import type { FASTProgressRing } from "./progress-ring.js"; -import type { ProgressRingOptions } from "./progress-ring.options.js"; - -const progressSegments: number = 44; - -/** - * The template for the {@link @microsoft/fast-foundation#FASTProgressRing} component. - * @public - */ -export function progressRingTemplate( - options: ProgressRingOptions = {} -): ElementViewTemplate { - return html` - - `; -} diff --git a/packages/web-components/fast-foundation/src/progress-ring/progress-ring.ts b/packages/web-components/fast-foundation/src/progress-ring/progress-ring.ts deleted file mode 100644 index f3736588496..00000000000 --- a/packages/web-components/fast-foundation/src/progress-ring/progress-ring.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { FASTBaseProgress } from "../progress/base-progress.js"; - -/** - * An circular Progress HTML Element. - * Implements the {@link https://www.w3.org/TR/wai-aria-1.1/#progressbar | ARIA progressbar }. - * - * @slot indeterminate - The slot for a custom indeterminate indicator - * @slot determinate - The slot for a custom determinate indicator - * @csspart progress - Represents the progress element - * @csspart determinate - The determinate indicator - * @csspart background - The background - * - * @public - */ -export class FASTProgressRing extends FASTBaseProgress {} diff --git a/packages/web-components/fast-foundation/src/progress-ring/stories/progress-ring.register.ts b/packages/web-components/fast-foundation/src/progress-ring/stories/progress-ring.register.ts deleted file mode 100644 index b7a3cd31f8b..00000000000 --- a/packages/web-components/fast-foundation/src/progress-ring/stories/progress-ring.register.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { html } from "@microsoft/fast-element"; -import { css } from "@microsoft/fast-element"; -import { FASTProgressRing } from "../progress-ring.js"; -import { progressRingTemplate } from "../progress-ring.template.js"; - -const styles = css` - :host { - align-items: center; - display: flex; - outline: none; - height: calc(var(--height-number) * 1px); - width: calc(var(--height-number) * 1px); - margin: calc(var(--height-number) * 1px) 0; - } - - .progress { - height: 100%; - width: 100%; - } - - .background { - stroke: var(--neutral-fill-rest); - fill: none; - stroke-width: 2px; - } - - .determinate { - stroke: var(--accent-foreground-rest); - fill: none; - stroke-width: 2px; - stroke-linecap: round; - transform-origin: 50% 50%; - transform: rotate(-90deg); - transition: all 0.2s ease-in-out; - } - - .indeterminate-indicator-1 { - stroke: var(--accent-foreground-rest); - fill: none; - stroke-width: 2px; - stroke-linecap: round; - transform-origin: 50% 50%; - transform: rotate(-90deg); - transition: all 0.2s ease-in-out; - animation: spin-infinite 2s linear infinite; - } - - @keyframes spin-infinite { - 0% { - stroke-dasharray: 0.01px 43.97px; - transform: rotate(0deg); - } - 50% { - stroke-dasharray: 21.99px 21.99px; - transform: rotate(450deg); - } - 100% { - stroke-dasharray: 0.01px 43.97px; - transform: rotate(1080deg); - } - } -`; - -FASTProgressRing.define({ - name: "fast-progress-ring", - template: progressRingTemplate({ - indeterminateIndicator: /* html */ html` - - - - - `, - }), - styles, -}); diff --git a/packages/web-components/fast-foundation/src/progress-ring/stories/progress-ring.stories.ts b/packages/web-components/fast-foundation/src/progress-ring/stories/progress-ring.stories.ts deleted file mode 100644 index 11ca30dff98..00000000000 --- a/packages/web-components/fast-foundation/src/progress-ring/stories/progress-ring.stories.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { html } from "@microsoft/fast-element"; -import type { Meta, Story, StoryArgs } from "../../__test__/helpers.js"; -import { renderComponent } from "../../__test__/helpers.js"; -import type { FASTProgressRing } from "../progress-ring.js"; - -const storyTemplate = html>` - - ${x => x.storyContent} - -`; - -export default { - title: "Progress/Progress Ring", - args: { - indeterminate: false, - value: 75, - }, - argTypes: { - indeterminate: { control: "boolean" }, - min: { control: "number" }, - max: { control: "number" }, - storyContent: { table: { disable: true } }, - value: { control: "number", if: { arg: "indeterminate", truthy: false } }, - }, -} as Meta; - -export const ProgressRing: Story = renderComponent(storyTemplate).bind( - {} -); diff --git a/packages/web-components/fast-foundation/src/progress/README.md b/packages/web-components/fast-foundation/src/progress/README.md deleted file mode 100644 index f34be4523a2..00000000000 --- a/packages/web-components/fast-foundation/src/progress/README.md +++ /dev/null @@ -1,197 +0,0 @@ ---- -id: progress -title: fast-progress -sidebar_label: progress -custom_edit_url: https://github.com/microsoft/fast/edit/master/packages/web-components/fast-foundation/src/progress/README.md -description: fast-progress is a web component used to display the length of time a process will take or to visualize percentage value. ---- - -*Progress* and *progress ring* are used to display the length of time a process will take or to visualize percentage value (referred to as a **determinate** state) and to represent an unspecified wait time (referred to as an **indeterminate** state). *Progress* components are typically visually represented by a circular or linear animation. When the `value` attribute is passed the state is **determinate**, otherwise it is **indeterminate**. - -For progress components which have a linear visual appearance, use `fast-progress`. For progress implementations which are circular, use `fast-progress-ring`. - -## Setup - -### Basic Setup - -```ts -import { - provideFASTDesignSystem, - fastProgress, - fastProgressRing -} from "@microsoft/fast-components"; - -provideFASTDesignSystem() - .register( - fastProgress(), - fastProgressRing() - ); -``` - -### Customizing Indicators - -```ts -import { - provideFASTDesignSystem, - fastProgress, - fastProgressRing -} from "@microsoft/fast-components"; - -provideFASTDesignSystem() - .register( - fastProgress({ - indeterminateIndicator1: `...your indeterminate indicator...`, - indeterminateIndicator2: `...your indeterminate indicator...` - }), - fastProgressRing({ - indeterminateIndicator: `...your indeterminate indicator...` - }) - ); -``` - -## Usage - -### fast-progress - -```html live - -``` - -### fast-progress-ring - -```html live - -``` - -## Create your own design - -### Progress - -```ts -import { - BaseProgress as Progress, - ProgressOptions, - progressTemplate as template, -} from "@microsoft/fast-foundation"; -import { progressStyles as styles } from "./my-progress.styles"; - -export const myProgress = Progress.compose({ - baseName: "progress", - template, - styles, - indeterminateIndicator1: `...default indeterminate indicator...`, - indeterminateIndicator2: `...default indeterminate indicator...`, -}); -``` - -### ProgressRing - -```ts -import { - BaseProgress as ProgressRing, - ProgressRingOptions, - progressRingTemplate as template, -} from "@microsoft/fast-foundation"; -import { progressRingStyles as styles } from "./my-progress-ring.styles"; - -export const myProgressRing = ProgressRing.compose({ - baseName: "progress-ring", - template, - styles, - indeterminateIndicator: `...default indeterminate indicator...`, -}); -``` - -## API - - - -### class: `FASTBaseProgress` - -#### Superclass - -| Name | Module | Package | -| ------------- | ------ | ----------------------- | -| `FASTElement` | | @microsoft/fast-element | - -#### Fields - -| Name | Privacy | Type | Default | Description | Inherited From | -| ------- | ------- | ---------------- | ------- | ------------------------- | -------------- | -| `value` | public | `number or null` | | The value of the progress | | -| `min` | public | `number` | | The minimum value | | -| `max` | public | `number` | | The maximum value | | - -#### Methods - -| Name | Privacy | Description | Parameters | Return | Inherited From | -| -------------- | --------- | ----------- | ---------- | ------ | -------------- | -| `valueChanged` | protected | | | `void` | | -| `minChanged` | protected | | | `void` | | -| `maxChanged` | protected | | | `void` | | - -#### Attributes - -| Name | Field | Inherited From | -| ---- | ----- | -------------- | -| | value | | -| | min | | -| | max | | - -
- - - -### class: `FASTProgress` - -#### Superclass - -| Name | Module | Package | -| ------------------ | ------------------------------ | ------- | -| `FASTBaseProgress` | /src/progress/base-progress.js | | - -#### Fields - -| Name | Privacy | Type | Default | Description | Inherited From | -| ------- | ------- | ---------------- | ------- | ------------------------- | ---------------- | -| `value` | public | `number or null` | | The value of the progress | FASTBaseProgress | -| `min` | public | `number` | | The minimum value | FASTBaseProgress | -| `max` | public | `number` | | The maximum value | FASTBaseProgress | - -#### Methods - -| Name | Privacy | Description | Parameters | Return | Inherited From | -| -------------- | --------- | ----------- | ---------- | ------ | ---------------- | -| `valueChanged` | protected | | | `void` | FASTBaseProgress | -| `minChanged` | protected | | | `void` | FASTBaseProgress | -| `maxChanged` | protected | | | `void` | FASTBaseProgress | - -#### Attributes - -| Name | Field | Inherited From | -| ---- | ----- | ---------------- | -| | value | FASTBaseProgress | - -#### CSS Parts - -| Name | Description | -| --------------- | ------------------------------- | -| `progress` | Represents the progress element | -| `determinate` | The determinate indicator | -| `indeterminate` | The indeterminate indicator | - -#### Slots - -| Name | Description | -| --------------- | --------------------------------------------- | -| `indeterminate` | The slot for a custom indeterminate indicator | - -
- - -## Additional resources - -* [Component explorer examples for `progress`](https://explore.fast.design/components/fast-progress) -* [Component explorer examples for `progress-ring`](https://explore.fast.design/components/fast-progress-ring) -* [Component technical specification](https://github.com/microsoft/fast/blob/master/packages/web-components/fast-foundation/src/progress/progress.spec.md) -* [W3C Component Aria Practices](https://www.w3.org/TR/wai-aria/#progressbar) \ No newline at end of file diff --git a/packages/web-components/fast-foundation/src/progress/base-progress.ts b/packages/web-components/fast-foundation/src/progress/base-progress.ts deleted file mode 100644 index ffe48cf2f52..00000000000 --- a/packages/web-components/fast-foundation/src/progress/base-progress.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { - attr, - FASTElement, - nullableNumberConverter, - observable, -} from "@microsoft/fast-element"; - -/** - * A base class for progress components. - * @public - */ -export class FASTBaseProgress extends FASTElement { - /** - * The value of the progress - * @public - * @remarks - * HTML Attribute: value - */ - @attr({ converter: nullableNumberConverter }) - public value: number | null; - protected valueChanged(): void { - this.updatePercentComplete(); - } - - /** - * The minimum value - * @public - * @remarks - * HTML Attribute: min - */ - @attr({ converter: nullableNumberConverter }) - public min: number; - protected minChanged(): void { - if (this.$fastController.isConnected) { - this.updatePercentComplete(); - } - } - - /** - * The maximum value - * @public - * @remarks - * HTML Attribute: max - */ - @attr({ converter: nullableNumberConverter }) - public max: number; - protected maxChanged(): void { - if (this.$fastController.isConnected) { - this.updatePercentComplete(); - } - } - - /** - * Indicates progress in % - * @internal - */ - @observable - public percentComplete: number = 0; - - /** - * @internal - */ - public connectedCallback(): void { - super.connectedCallback(); - this.updatePercentComplete(); - } - - private updatePercentComplete(): void { - const min: number = typeof this.min === "number" ? this.min : 0; - const max: number = typeof this.max === "number" ? this.max : 100; - const value: number = typeof this.value === "number" ? this.value : 0; - const range: number = max - min; - - this.percentComplete = - range === 0 ? 0 : Math.fround(((value - min) / range) * 100); - } -} diff --git a/packages/web-components/fast-foundation/src/progress/index.ts b/packages/web-components/fast-foundation/src/progress/index.ts deleted file mode 100644 index 00d4827ab4d..00000000000 --- a/packages/web-components/fast-foundation/src/progress/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { FASTBaseProgress } from "./base-progress.js"; -export { FASTProgress } from "./progress.js"; -export type { ProgressOptions } from "./progress.options.js"; -export { progressTemplate } from "./progress.template.js"; diff --git a/packages/web-components/fast-foundation/src/progress/progress.options.ts b/packages/web-components/fast-foundation/src/progress/progress.options.ts deleted file mode 100644 index 6abd26ba064..00000000000 --- a/packages/web-components/fast-foundation/src/progress/progress.options.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { StaticallyComposableHTML } from "../utilities/template-helpers.js"; -import type { FASTProgress } from "./progress.js"; - -/** - * Progress configuration options - * @public - */ -export type ProgressOptions = { - indeterminateIndicator1?: StaticallyComposableHTML; - indeterminateIndicator2?: StaticallyComposableHTML; -}; diff --git a/packages/web-components/fast-foundation/src/progress/progress.pw.spec.ts b/packages/web-components/fast-foundation/src/progress/progress.pw.spec.ts deleted file mode 100644 index dd7a7de28d8..00000000000 --- a/packages/web-components/fast-foundation/src/progress/progress.pw.spec.ts +++ /dev/null @@ -1,128 +0,0 @@ -import type { Locator, Page } from "@playwright/test"; -import { expect, test } from "@playwright/test"; -import { fixtureURL } from "../__test__/helpers.js"; -import type { FASTProgress } from "./progress.js"; - -test.describe("Progress ring", () => { - let page: Page; - let element: Locator; - let root: Locator; - - test.beforeAll(async ({ browser }) => { - page = await browser.newPage(); - - element = page.locator("fast-progress"); - - root = page.locator("#storybook-root"); - - await page.goto(fixtureURL("progress--progress")); - - await element.waitFor({ state: "attached" }); - }); - - test.afterAll(async () => { - await page.close(); - }); - - test("should include a role of progressbar", async () => { - await expect(element).toHaveAttribute("role", "progressbar"); - }); - - test("should set the `aria-valuenow` attribute with the `value` property when provided", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element).toHaveAttribute("aria-valuenow", "50"); - }); - - test("should set the `aria-valuemin` attribute with the `min` property when provided", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element).toHaveAttribute("aria-valuemin", "50"); - }); - - test("should set the `aria-valuemax` attribute with the `max` property when provided", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element).toHaveAttribute("aria-valuemax", "50"); - }); - - test("should render an element with a `determinate` slot when a value is provided", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - const progress = element.locator(".progress"); - - await expect(progress).toHaveAttribute("slot", "determinate"); - }); - - test("should render an element with an `indeterminate` slot when no value is provided", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - const progress = element.locator(".progress"); - - await expect(progress).toHaveAttribute("slot", "indeterminate"); - }); - - test("should return the `percentComplete` property as a value between 0 and 100 when `min` and `max` are unset", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element).toHaveJSProperty("percentComplete", 50); - }); - - test("should set the `percentComplete` property to match the current `value` in the range of `min` and `max`", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element).toHaveJSProperty("percentComplete", 0); - - await element.evaluate((node: FASTProgress) => { - node.value = 50; - }); - - await expect(element).toHaveJSProperty("percentComplete", 50); - - await element.evaluate((node: FASTProgress) => { - node.value = 100; - }); - - await expect(element).toHaveJSProperty("percentComplete", 100); - - await element.evaluate((node: FASTProgress) => { - node.max = 200; - }); - - await expect(element).toHaveJSProperty("percentComplete", 50); - - await element.evaluate((node: FASTProgress) => { - node.min = 100; - }); - - await expect(element).toHaveJSProperty("percentComplete", 0); - }); -}); diff --git a/packages/web-components/fast-foundation/src/progress/progress.spec.md b/packages/web-components/fast-foundation/src/progress/progress.spec.md deleted file mode 100644 index 643ac59d833..00000000000 --- a/packages/web-components/fast-foundation/src/progress/progress.spec.md +++ /dev/null @@ -1,152 +0,0 @@ -# Progress - -## Overview - -*Progress* and *progress ring* are used to display the length of time a process will take or to visualize percentage value (referred to as a **determinate** state) and to represent an unspecified wait time (referred to as an **indeterminate** state). *Progress* components are typically visually represented by a circular or linear animation. When the `value` attribute is passed the state is **determinate**, otherwise it is **indeterminate**. - -### Use Cases - -- Jim is building a dashboard to track fulfillment for his online store, he uses progress ring to visualize various metrics. - -- Susan is downloading a large collection of music onto her hard-drive. She sees a linear progress displaying the percentage complete for the currently downloading song and indeterminate linear progress for those songs in queue. - -- Fin is scrolling a large list of continuously loading data as he scrolls he sees a indeterminate progress ring to let him know that data is loading. - -### Types -*Progress* can be visually represented in 2 ways. -- Linear - A straight horizontal line. `fast-progress` -- Circular - A circular ring shape. `fast-progress-ring` - -### Features - -A progress should allow the following attributes: -- `value`, the value of the progress, if not passed the progress will be put into its "indeterminate" state. -- `min`, the minimum value. -- `max`, the maximum value. -- `paused`, whether the progress is paused or not. - -### Prior Art/Examples -- [FAST Progress (React)](https://www.npmjs.com/package/@microsoft/fast-components-react-msft) -- [Material UI](https://material-ui.com/components/progress/) -- [Lightning Design / Linear](https://www.lightningdesignsystem.com/components/progress-bar/) -- [Lightning Design / Circular](https://www.lightningdesignsystem.com/components/progress-ring/) -- [Ant Design](https://ant.design/components/progress/) -- [Atlassian / Linear](https://atlaskit.atlassian.com/packages/server/progress-bar) -- [Atlassian / Circular](https://atlaskit.atlassian.com/packages/core/spinner) -- [Windows (UWP)](https://docs.microsoft.com/en-us/windows/uwp/design/controls-and-patterns/progress-controls) - ---- - -### API - -*Component names:* -- `fast-progress` -- `fast-progress-ring` - -*Attributes:* -- `value`: number -- `min`: number -- `max`: number -- `paused`: boolean - -*Slots:* -- `indeterminate` - -### Anatomy and Appearance - -*Parts:* -- background -- determinate -- indeterminate-indicator-1 -- indeterminate-indicator-2 -- progress - -*Progress Ring Determinate Template:* -``` - - - - - - -``` - -*Progress Ring Indeterminate Template:* -``` - - - - - - - - -``` - -*Progress Determinate Template:* -``` - -
-
-
- -``` - -*Progress Indeterminate Template:* -``` - -
- - - - -
-
-``` - - -## Implementation - -``` - -``` - -``` - -``` - -### States - -*Progress* and *progress ring* can either be **determinate** or **indeterminate** depending on whether the `value` attribute is passed. *Progress* renders in linear style progress and *progress ring* renders a circular style progress. - -### Accessibility - -If the *progress* or *progress ring* is describing the loading progress of a particular region of a page, the author **SHOULD** use [aria-describedby](https://www.w3.org/WAI/PF/aria/states_and_properties#aria-describedby) to point to the status, and set the [aria-busy](https://www.w3.org/WAI/PF/aria/states_and_properties#aria-busy) attribute to true on the region until it is finished loading. It is not possible for the user to alter the value of a *progress* or *progress ring* because it is always readonly. - -Consult the current [W3C WAI-ARIA documentation](https://www.w3.org/WAI/PF/aria/roles#progressbar) for best practices. - -### Globalization - -*Progress* and *progress ring* should mirror in RTL languages, meaning the determinate progression and indeterminate animations should be mirrored. - -### Dependencies - -No dependencies outside of fast-element itself. diff --git a/packages/web-components/fast-foundation/src/progress/progress.template.ts b/packages/web-components/fast-foundation/src/progress/progress.template.ts deleted file mode 100644 index 281df7e195d..00000000000 --- a/packages/web-components/fast-foundation/src/progress/progress.template.ts +++ /dev/null @@ -1,43 +0,0 @@ -import type { ElementViewTemplate } from "@microsoft/fast-element"; -import { html, when } from "@microsoft/fast-element"; -import { staticallyCompose } from "../utilities/template-helpers.js"; -import type { FASTProgress } from "./progress.js"; -import type { ProgressOptions } from "./progress.options.js"; - -/** - * The template for the {@link @microsoft/fast-foundation#FASTProgress} component. - * @public - */ -export function progressTemplate( - options: ProgressOptions = {} -): ElementViewTemplate { - return html` - - `; -} diff --git a/packages/web-components/fast-foundation/src/progress/progress.ts b/packages/web-components/fast-foundation/src/progress/progress.ts deleted file mode 100644 index 661b67cb366..00000000000 --- a/packages/web-components/fast-foundation/src/progress/progress.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { FASTBaseProgress } from "./base-progress.js"; - -/** - * An Progress HTML Element. - * Implements the {@link https://www.w3.org/TR/wai-aria-1.1/#progressbar | ARIA progressbar }. - * - * @slot indeterminate - The slot for a custom indeterminate indicator - * @csspart progress - Represents the progress element - * @csspart determinate - The determinate indicator - * @csspart indeterminate - The indeterminate indicator - * - * @public - */ -export class FASTProgress extends FASTBaseProgress {} diff --git a/packages/web-components/fast-foundation/src/progress/stories/progress.register.ts b/packages/web-components/fast-foundation/src/progress/stories/progress.register.ts deleted file mode 100644 index 78e4c909bb9..00000000000 --- a/packages/web-components/fast-foundation/src/progress/stories/progress.register.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { html } from "@microsoft/fast-element"; -import { css } from "@microsoft/fast-element"; -import { FASTProgress } from "../progress.js"; -import { progressTemplate } from "../progress.template.js"; - -const styles = css` - :host { - align-items: center; - display: flex; - contain: content; - outline: none; - height: calc(var(--design-unit) * 1px); - margin: calc(var(--design-unit) * 1px) 0; - } - - .progress { - background-color: var(--neutral-fill-rest); - border-radius: calc(var(--design-unit) * 1px); - width: 100%; - height: 100%; - display: flex; - align-items: center; - position: relative; - } - - .determinate { - background-color: var(--accent-foreground-rest); - border-radius: calc(var(--design-unit) * 1px); - height: 100%; - transition: all 0.2s ease-in-out; - display: flex; - } - - .indeterminate { - border-radius: calc(var(--design-unit) * 1px); - display: flex; - height: 100%; - overflow: hidden; - position: relative; - width: 100%; - } - - .indeterminate-indicator-1 { - animation: indeterminate-1 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; - background-color: var(--accent-foreground-rest); - border-radius: calc(var(--design-unit) * 1px); - height: 100%; - opacity: 0; - position: absolute; - width: 40%; - } - - .indeterminate-indicator-2 { - position: absolute; - opacity: 0; - height: 100%; - background-color: var(--accent-foreground-rest); - border-radius: calc(var(--design-unit) * 1px); - width: 60%; - animation: indeterminate-2 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; - } - - @keyframes indeterminate-1 { - 0% { - opacity: 1; - transform: translateX(-100%); - } - 70% { - opacity: 1; - transform: translateX(300%); - } - 70.01% { - opacity: 0; - } - 100% { - opacity: 0; - transform: translateX(300%); - } - } - - @keyframes indeterminate-2 { - 0% { - opacity: 0; - transform: translateX(-150%); - } - 29.99% { - opacity: 0; - } - 30% { - opacity: 1; - transform: translateX(-150%); - } - 100% { - transform: translateX(166.66%); - opacity: 1; - } - } -`; - -FASTProgress.define({ - name: "fast-progress", - template: progressTemplate({ - indeterminateIndicator1: /* html */ html` - - `, - indeterminateIndicator2: /* html */ html` - - `, - }), - styles, -}); diff --git a/packages/web-components/fast-foundation/src/progress/stories/progress.stories.ts b/packages/web-components/fast-foundation/src/progress/stories/progress.stories.ts deleted file mode 100644 index 56925198afc..00000000000 --- a/packages/web-components/fast-foundation/src/progress/stories/progress.stories.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { html } from "@microsoft/fast-element"; -import type { Meta, Story, StoryArgs } from "../../__test__/helpers.js"; -import { renderComponent } from "../../__test__/helpers.js"; -import type { FASTProgress } from "../progress.js"; - -const storyTemplate = html>` - - ${x => x.storyContent} - -`; - -export default { - title: "Progress", - args: { - indeterminate: false, - value: 75, - }, - argTypes: { - indeterminate: { control: "boolean" }, - min: { control: "number" }, - max: { control: "number" }, - storyContent: { table: { disable: true } }, - value: { control: "number", if: { arg: "indeterminate", truthy: false } }, - }, -} as Meta; - -export const Progress: Story = renderComponent(storyTemplate).bind({}); diff --git a/packages/web-components/fast-foundation/src/radio-group/README.md b/packages/web-components/fast-foundation/src/radio-group/README.md deleted file mode 100644 index 738a3c0a992..00000000000 --- a/packages/web-components/fast-foundation/src/radio-group/README.md +++ /dev/null @@ -1,133 +0,0 @@ ---- -id: radio-group -title: fast-radio-group -sidebar_label: radio-group -custom_edit_url: https://github.com/microsoft/fast/edit/master/packages/web-components/fast-foundation/src/radio-group/README.md -description: fast-radio-group is a web component implementation of a radio-group. ---- - -As defined by the [W3C](https://w3c.github.io/aria-practices/#radiobutton): - -> A radio group is a set of checkable buttons, known as radio buttons, where no more than one of the buttons can be checked at a time. Some implementations may initialize the set with all buttons in the unchecked state in order to force the user to check one of the buttons before moving past a certain point in the workflow. - -While any DOM content is permissible as a child of the radiogroup, only `fast-radio`'s and slotted content with a role of `radio` will receive keyboard support. - -## Setup - -```ts -import { - provideFASTDesignSystem, - fastRadio, - fastRadioGroup -} from "@microsoft/fast-components"; - -provideFASTDesignSystem() - .register( - fastRadio(), - fastRadioGroup() - ); -``` - -## Usage - -```html live - - Apple - Mango - Orange - -``` - -## Create your own design - -```ts -import { RadioGroup, radioGroupTemplate as template } from "@microsoft/fast-foundation"; -import { radioGroupStyles as styles } from "./my-radio-group.styles"; - -export const myRadioGroup = RadioGroup.compose({ - baseName: "radio-group", - template, - styles, -}); -``` - -## API - - - -### Variables - -| Name | Description | Type | -| ----------------------- | ----------------------- | ---- | -| `RadioGroupOrientation` | Radio Group orientation | | - -
- - - -### class: `FASTRadioGroup` - -#### Superclass - -| Name | Module | Package | -| ------------- | ------ | ----------------------- | -| `FASTElement` | | @microsoft/fast-element | - -#### Fields - -| Name | Privacy | Type | Default | Description | Inherited From | -| ------------- | ------- | ----------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------- | -| `readOnly` | public | `boolean` | | When true, the child radios will be immutable by user interaction. See [readonly HTML attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/readonly) for more information. | | -| `disabled` | public | `boolean` | | Disables the radio group and child radios. | | -| `name` | public | `string` | | The name of the radio group. Setting this value will set the name value for all child radio elements. | | -| `value` | public | `string` | | The value of the checked radio | | -| `orientation` | public | `RadioGroupOrientation` | | The orientation of the group | | -| `childItems` | public | `HTMLElement[]` | | | | - -#### Methods - -| Name | Privacy | Description | Parameters | Return | Inherited From | -| ---------------------------- | --------- | ----------- | -------------------------------------------- | ------ | -------------- | -| `disabledChanged` | protected | | | `void` | | -| `nameChanged` | protected | | | `void` | | -| `valueChanged` | protected | | | `void` | | -| `slottedRadioButtonsChanged` | protected | | `oldValue: unknown, newValue: HTMLElement[]` | `void` | | - -#### Events - -| Name | Type | Description | Inherited From | -| -------- | ---- | ---------------------------------------------------- | -------------- | -| `change` | | Fires a custom 'change' event when the value changes | | - -#### Attributes - -| Name | Field | Inherited From | -| ------------- | ----------- | -------------- | -| `readonly` | readOnly | | -| `disabled` | disabled | | -| `name` | name | | -| `value` | value | | -| `orientation` | orientation | | - -#### CSS Parts - -| Name | Description | -| -------------------- | ------------------------------------------------ | -| `positioning-region` | The positioning region for laying out the radios | - -#### Slots - -| Name | Description | -| ------- | ---------------------------------- | -| `label` | The slot for the label | -| | The default slot for radio buttons | - -
- - -## Additional resources - -* [Component explorer examples](https://explore.fast.design/components/fast-radio-group) -* [Component technical specification](https://github.com/microsoft/fast/blob/master/packages/web-components/fast-foundation/src/radio-group/radio-group.spec.md) -* [W3C Component Aria Practices](https://www.w3.org/TR/wai-aria/#radiogroup) -* [Open UI Analysis](https://open-ui.org/components/radio-button.research) \ No newline at end of file diff --git a/packages/web-components/fast-foundation/src/radio-group/index.ts b/packages/web-components/fast-foundation/src/radio-group/index.ts deleted file mode 100644 index 76b6dde54ce..00000000000 --- a/packages/web-components/fast-foundation/src/radio-group/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { RadioGroupOrientation } from "./radio-group.options.js"; -export { radioGroupTemplate } from "./radio-group.template.js"; -export { FASTRadioGroup } from "./radio-group.js"; diff --git a/packages/web-components/fast-foundation/src/radio-group/radio-group.options.ts b/packages/web-components/fast-foundation/src/radio-group/radio-group.options.ts deleted file mode 100644 index 4f8567c64f6..00000000000 --- a/packages/web-components/fast-foundation/src/radio-group/radio-group.options.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Orientation } from "@microsoft/fast-web-utilities"; -import type { ValuesOf } from "../utilities/index.js"; - -/** - * Radio Group orientation - * @public - */ -export const RadioGroupOrientation = Orientation; - -/** - * Types of Radio Group orientation - * @public - */ -export type RadioGroupOrientation = ValuesOf; diff --git a/packages/web-components/fast-foundation/src/radio-group/radio-group.pw.spec.ts b/packages/web-components/fast-foundation/src/radio-group/radio-group.pw.spec.ts deleted file mode 100644 index a252d3d1e2f..00000000000 --- a/packages/web-components/fast-foundation/src/radio-group/radio-group.pw.spec.ts +++ /dev/null @@ -1,481 +0,0 @@ -import { expect, test } from "@playwright/test"; -import type { Locator, Page } from "@playwright/test"; -import type { FASTRadio } from "../radio/index.js"; -import { fixtureURL } from "../__test__/helpers.js"; -import { RadioGroupOrientation } from "./radio-group.options.js"; -import type { FASTRadioGroup } from "./radio-group.js"; - -test.describe("Radio Group", () => { - let page: Page; - let element: Locator; - let root: Locator; - let radios: Locator; - - test.beforeAll(async ({ browser }) => { - page = await browser.newPage(); - - element = page.locator("fast-radio-group"); - - root = page.locator("#storybook-root"); - - radios = element.locator("fast-radio"); - - await page.goto(fixtureURL("radio-group--radio-group")); - - await element.waitFor({ state: "attached" }); - }); - - test.afterAll(async () => { - await page.close(); - }); - - test("should have a role of `radiogroup`", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element).toHaveAttribute("role", "radiogroup"); - }); - - test("should set a default `aria-orientation` value when `orientation` is not defined", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element).toHaveAttribute( - "aria-orientation", - `${RadioGroupOrientation.horizontal}` - ); - }); - - test("should set a matching class on the `positioning-region` when an orientation is provided", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - const positioningRegion = element.locator(".positioning-region"); - - // Horizontal by default - await expect(positioningRegion).toHaveClass(/horizontal/); - - await element.evaluate((node: FASTRadioGroup, RadioGroupOrientation) => { - node.orientation = RadioGroupOrientation.vertical; - }, RadioGroupOrientation); - - await expect(positioningRegion).toHaveClass(/vertical/); - - await element.evaluate((node: FASTRadioGroup, RadioGroupOrientation) => { - node.orientation = RadioGroupOrientation.horizontal; - }, RadioGroupOrientation); - - await expect(positioningRegion).toHaveClass(/horizontal/); - }); - - test("should set the `aria-orientation` attribute equal to the `orientation` value", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await element.evaluate((node: FASTRadioGroup, RadioGroupOrientation) => { - node.orientation = RadioGroupOrientation.horizontal; - }, RadioGroupOrientation); - - await expect(element).toHaveAttribute( - "aria-orientation", - RadioGroupOrientation.horizontal - ); - - await element.evaluate((node: FASTRadioGroup, RadioGroupOrientation) => { - node.orientation = RadioGroupOrientation.vertical; - }, RadioGroupOrientation); - - await expect(element).toHaveAttribute( - "aria-orientation", - RadioGroupOrientation.vertical - ); - }); - - test("should set the `aria-disabled` attribute when disabled", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element).toHaveAttribute("aria-disabled", "true"); - }); - - test("should set the `aria-disabled` attribute equal to the `disabled` property", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element).not.toHaveAttribute("aria-disabled"); - - await element.evaluate(node => { - node.disabled = true; - }); - - await expect(element).toHaveAttribute("aria-disabled", "true"); - - await element.evaluate(node => { - node.disabled = false; - }); - - await expect(element).toHaveAttribute("aria-disabled", "false"); - }); - - test("should set the `aria-readonly` attribute when the `readonly` attribute is present", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element).toHaveAttribute("aria-readonly", "true"); - }); - - test("should set the `aria-readonly` attribute equal to the `readonly` property", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element).not.toHaveAttribute("aria-readonly"); - - await element.evaluate(node => { - node.readOnly = true; - }); - - await expect(element).toHaveAttribute("aria-readonly", "true"); - - await element.evaluate(node => { - node.readOnly = false; - }); - - await expect(element).toHaveAttribute("aria-readonly", "false"); - }); - - test("should NOT set a default `aria-disabled` value when `disabled` is not defined", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element).not.toHaveAttribute("aria-disabled"); - }); - - test("should NOT modify child radio elements disabled state when the `disabled` attribute is present", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - - - - - `; - }); - - await expect(element).not.toHaveAttribute("disabled"); - - const firstRadio = radios.nth(0); - const secondRadio = radios.nth(1); - const thirdRadio = radios.nth(2); - - const expectedFirst = await firstRadio.evaluate(node => - node.hasAttribute("disabled") - ); - const expectedSecond = await secondRadio.evaluate(node => - node.hasAttribute("disabled") - ); - const expectedThird = await thirdRadio.evaluate(node => - node.hasAttribute("disabled") - ); - - expect( - await firstRadio.evaluate(radio => - radio.hasAttribute("disabled") - ) - ).toEqual(expectedFirst); - - expect( - await secondRadio.evaluate(radio => - radio.hasAttribute("disabled") - ) - ).toEqual(expectedSecond); - - expect( - await thirdRadio.evaluate(radio => - radio.hasAttribute("disabled") - ) - ).toEqual(expectedThird); - - element.evaluate(node => node.setAttribute("disabled", "")); - - await expect(element).toHaveAttribute("disabled"); - - expect( - await firstRadio.evaluate(radio => - radio.hasAttribute("disabled") - ) - ).toEqual(expectedFirst); - - expect( - await secondRadio.evaluate(radio => - radio.hasAttribute("disabled") - ) - ).toEqual(expectedSecond); - - expect( - await thirdRadio.evaluate(radio => - radio.hasAttribute("disabled") - ) - ).toEqual(expectedThird); - }); - - test("should NOT be focusable when disabled", async () => { - const first: Locator = page.locator("button", { hasText: "First" }); - const second: Locator = page.locator("button", { hasText: "Second" }); - - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - - - - - - - `; - }); - - await expect(element).toHaveAttribute("disabled"); - - await first.focus(); - - await expect(first).toBeFocused(); - - await first.press("Tab"); - - await expect(second).toBeFocused(); - - expect( - await element.evaluate( - node => node.getAttribute("tabindex") === "-1" - ) - ).toBeTruthy(); - }); - - test("should NOT be focusable via click when disabled", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - - - - - - `; - }); - - const radioItemsCount = await radios.count(); - - for (let i = 0; i < radioItemsCount; i++) { - const item = radios.nth(i); - - await item.click(); - - await expect(item).toBeFocused(); - } - - const button = page.locator("button", { hasText: "Button" }); - - await button.focus(); - - await expect(button).toBeFocused(); - - await element.evaluate(node => (node.disabled = true)); - - await expect(element).toHaveAttribute("disabled"); - - for (let i = 0; i < radioItemsCount; i++) { - const item = radios.nth(i); - - await item.click(); - - await expect(item).not.toBeFocused(); - } - }); - - test("should set tabindex of 0 to a child radio with a matching `value`", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - - - - - `; - }); - - await expect(radios.nth(0)).toHaveAttribute("tabindex", "0"); - }); - - test("should NOT set `tabindex` of 0 to a child radio if its value does not match the radiogroup `value`", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - - - - - `; - }); - - expect( - await radios.evaluateAll(radios => - radios.every(radio => radio.getAttribute("tabindex") === "-1") - ) - ).toBeTruthy(); - }); - - test("should set a child radio with a matching `value` to `checked`", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - - - - - `; - }); - - await expect(radios.nth(0)).not.toBeChecked(); - - await expect(radios.nth(1)).toBeChecked(); - - await expect(radios.nth(2)).not.toBeChecked(); - }); - - test("should set a child radio with a matching `value` to `checked` when value changes", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - - - - - `; - }); - - await element.evaluate((node: FASTRadioGroup) => { - node.value = "bar"; - }); - - await expect(radios.nth(0)).not.toBeChecked(); - - await expect(radios.nth(1)).toBeChecked(); - - await expect(radios.nth(2)).not.toBeChecked(); - }); - - test("should mark only the last radio defaulted to checked as checked", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - - - - - `; - }); - - expect( - await radios.evaluateAll( - radios => radios.filter(radio => radio.checked).length - ) - ).toBe(1); - - await expect(radios.nth(0)).not.toBeChecked(); - - await expect(radios.nth(1)).not.toBeChecked(); - - await expect(radios.nth(2)).toBeChecked(); - }); - - test("should mark radio matching value on radio-group over any checked attributes", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - - - - - `; - }); - - expect( - await radios.evaluateAll( - radios => radios.filter(radio => radio.checked).length - ) - ).toBe(1); - - await expect(radios.nth(0)).toBeChecked(); - - await expect(radios.nth(1)).not.toBeChecked(); - - // radio-group explicitly sets non-matching radio's checked to false if - // a value match was found, but the attribute should still persist. - await expect(radios.nth(1)).toHaveAttribute("checked"); - - await expect(radios.nth(2)).not.toBeChecked(); - }); - - test("should allow resetting of elements by the parent form", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` -
- - - - - -
- `; - }); - - const form = page.locator("form"); - - await radios.nth(2).evaluate(node => { - node.checked = true; - }); - - await expect(radios.nth(0)).not.toBeChecked(); - - await expect(radios.nth(1)).not.toBeChecked(); - - await expect(radios.nth(2)).toBeChecked(); - - await form.evaluate(node => { - node.reset(); - }); - - await expect(radios.nth(0)).not.toBeChecked(); - - await expect(radios.nth(1)).toBeChecked(); - - await expect(radios.nth(2)).not.toBeChecked(); - }); -}); diff --git a/packages/web-components/fast-foundation/src/radio-group/radio-group.spec.md b/packages/web-components/fast-foundation/src/radio-group/radio-group.spec.md deleted file mode 100644 index 8af817e3bd8..00000000000 --- a/packages/web-components/fast-foundation/src/radio-group/radio-group.spec.md +++ /dev/null @@ -1,88 +0,0 @@ -# Radio group - -## Overview - -As defined by the W3C: -> A radio group is a set of checkable buttons, known as radio buttons, where no more than one of the buttons can be checked at a time. Some implementations may initialize the set with all buttons in the unchecked state in order to force the user to check one of the buttons before moving past a certain point in the workflow. - -### Use Cases - -Radio group allows the user to be presented with a list of all the options visible which can facilitate the comparison of choice. - -### Features - -- **Selection:** A radio group can only support single select - - -### Prior Art/Examples -- [Material UI](https://material-ui.com/api/radio-group/) -- [Lightning Design](https://www.lightningdesignsystem.com/components/radio-group/) -- [Carbon design](https://www.carbondesignsystem.com/components/radio-button/code) -- [Ant Design](https://ant.design/components/radio/) -- [Atlassian](https://atlaskit.atlassian.com/packages/core/radio) -- [Windows (UWP)](https://docs.microsoft.com/en-us/windows/uwp/design/controls-and-patterns/radio-button) - ---- - -## Design - -### API - -*The key elements of the component's public API surface:* - -**Radio group** -*Component name:* -- `fast-radio-group` - -*Attributes:* -- `value` - allows user to set the initial radio selected within the group. -- `readonly` - - If there is a selected radio button in the group it should be submitted with the form but none of the radio buttons should be editable. -- `disabled` - - All of the radio buttons should be disabled from user interaction and will not be submitted with the form data. - -*Slots:* -- default slot for radio items -- label - provide a label for the radio group - - -### Anatomy and Appearance -*Parts:* -- positioning-region - -*Template:* -``` - -``` - - -### Accessibility - -Keyboard interaction will work as described by [W3C](https://w3c.github.io/aria-practices/#radiobutton) - -- Tab and Shift + Tab: Move focus into and out of the radio group. When focus moves into a radio group : - - If a radio button is checked, focus is set on the checked button. - - If none of the radio buttons are checked, focus is set on the first radio button in the group. -- Space: checks the focused radio button if it is not already checked. -- Right Arrow and Down Arrow: move focus to the next radio button in the group, uncheck the previously focused button, and check the newly focused button. If focus is on the last button, focus moves to the first button. -- Left Arrow and Up Arrow: move focus to the previous radio button in the group, uncheck the previously focused button, and check the newly focused button. If focus is on the first button, focus moves to the last button. - -Additional support for keyboard interaction while in a toolbar as described by [W3C](https://w3c.github.io/aria-practices/#for-radio-group-contained-in-a-toolbar) - -Radio group: -```html - - One - Two - Three - Four - -``` - diff --git a/packages/web-components/fast-foundation/src/radio-group/radio-group.template.ts b/packages/web-components/fast-foundation/src/radio-group/radio-group.template.ts deleted file mode 100644 index bdc6d9b351c..00000000000 --- a/packages/web-components/fast-foundation/src/radio-group/radio-group.template.ts +++ /dev/null @@ -1,40 +0,0 @@ -import type { ElementViewTemplate } from "@microsoft/fast-element"; -import { elements, html, slotted } from "@microsoft/fast-element"; -import type { FASTRadioGroup } from "./radio-group.js"; -import { RadioGroupOrientation } from "./radio-group.options.js"; - -/** - * The template for the {@link @microsoft/fast-foundation#FASTRadioGroup} component. - * @public - */ -export function radioGroupTemplate(): ElementViewTemplate { - return html` - - `; -} diff --git a/packages/web-components/fast-foundation/src/radio-group/radio-group.ts b/packages/web-components/fast-foundation/src/radio-group/radio-group.ts deleted file mode 100644 index ec098434893..00000000000 --- a/packages/web-components/fast-foundation/src/radio-group/radio-group.ts +++ /dev/null @@ -1,440 +0,0 @@ -import { attr, FASTElement, observable } from "@microsoft/fast-element"; -import { - ArrowKeys, - Direction, - keyArrowDown, - keyArrowLeft, - keyArrowRight, - keyArrowUp, - keyEnter, -} from "@microsoft/fast-web-utilities"; -import { FASTRadio } from "../radio/index.js"; -import { getDirection } from "../utilities/direction.js"; -import { RadioGroupOrientation } from "./radio-group.options.js"; - -/** - * An Radio Group Custom HTML Element. - * Implements the {@link https://www.w3.org/TR/wai-aria-1.1/#radiogroup | ARIA radiogroup }. - * - * @slot label - The slot for the label - * @slot - The default slot for radio buttons - * @csspart positioning-region - The positioning region for laying out the radios - * @fires change - Fires a custom 'change' event when the value changes - * - * @public - */ -export class FASTRadioGroup extends FASTElement { - /** - * When true, the child radios will be immutable by user interaction. - * See {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/readonly | readonly HTML attribute} for more information. - * @public - * @remarks - * HTML Attribute: readonly - */ - @attr({ attribute: "readonly", mode: "boolean" }) - public readOnly: boolean; - - /** - * Disables the radio group and child radios. - * - * @public - * @remarks - * HTML Attribute: disabled - */ - @attr({ attribute: "disabled", mode: "boolean" }) - public disabled: boolean; - protected disabledChanged(): void {} - - /** - * The name of the radio group. Setting this value will set the name value - * for all child radio elements. - * - * @public - * @remarks - * HTML Attribute: name - */ - @attr - public name: string; - protected nameChanged(): void { - if (this.slottedRadioButtons) { - this.slottedRadioButtons.forEach((radio: FASTRadio) => { - radio.setAttribute("name", this.name); - }); - } - } - - /** - * The value of the checked radio - * - * @public - * @remarks - * HTML Attribute: value - */ - @attr - public value: string; - protected valueChanged(): void { - if (this.slottedRadioButtons) { - this.slottedRadioButtons.forEach((radio: FASTRadio) => { - if (radio.value === this.value) { - radio.checked = true; - this.selectedRadio = radio; - } - }); - } - this.$emit("change"); - } - - /** - * The orientation of the group - * - * @public - * @remarks - * HTML Attribute: orientation - */ - @attr - public orientation: RadioGroupOrientation = RadioGroupOrientation.horizontal; - - @observable - public childItems: HTMLElement[]; - - /** - * @internal - */ - @observable - public slottedRadioButtons: HTMLElement[]; - protected slottedRadioButtonsChanged( - oldValue: unknown, - newValue: HTMLElement[] - ): void { - if (this.slottedRadioButtons && this.slottedRadioButtons.length > 0) { - this.setupRadioButtons(); - } - } - - private selectedRadio: FASTRadio | null; - private focusedRadio: FASTRadio | null; - private direction: Direction; - - private get parentToolbar(): HTMLElement | null { - return this.closest('[role="toolbar"]'); - } - - private get isInsideToolbar(): boolean { - return (this.parentToolbar ?? false) as boolean; - } - - private get isInsideFoundationToolbar(): boolean { - return !!this.parentToolbar?.["$fastController"]; - } - - /** - * @internal - */ - public connectedCallback(): void { - super.connectedCallback(); - this.direction = getDirection(this); - - this.setupRadioButtons(); - } - - public disconnectedCallback(): void { - this.slottedRadioButtons.forEach((radio: FASTRadio) => { - radio.removeEventListener("change", this.radioChangeHandler); - }); - } - - private setupRadioButtons(): void { - const checkedRadios: HTMLElement[] = this.slottedRadioButtons.filter( - (radio: FASTRadio) => { - return radio.hasAttribute("checked"); - } - ); - const numberOfCheckedRadios: number = checkedRadios ? checkedRadios.length : 0; - if (numberOfCheckedRadios > 1) { - const lastCheckedRadio: FASTRadio = checkedRadios[ - numberOfCheckedRadios - 1 - ] as FASTRadio; - lastCheckedRadio.checked = true; - } - let foundMatchingVal: boolean = false; - - this.slottedRadioButtons.forEach((radio: FASTRadio) => { - if (this.name !== undefined) { - radio.setAttribute("name", this.name); - } - - if (this.value && this.value === radio.value) { - this.selectedRadio = radio; - this.focusedRadio = radio; - radio.checked = true; - radio.setAttribute("tabindex", "0"); - foundMatchingVal = true; - } else { - if (!this.isInsideFoundationToolbar) { - radio.setAttribute("tabindex", "-1"); - } - radio.checked = false; - } - - radio.addEventListener("change", this.radioChangeHandler); - }); - - if (this.value === undefined && this.slottedRadioButtons.length > 0) { - const checkedRadios: HTMLElement[] = this.slottedRadioButtons.filter( - (radio: FASTRadio) => { - return radio.hasAttribute("checked"); - } - ); - const numberOfCheckedRadios: number = - checkedRadios !== null ? checkedRadios.length : 0; - if (numberOfCheckedRadios > 0 && !foundMatchingVal) { - const lastCheckedRadio: FASTRadio = checkedRadios[ - numberOfCheckedRadios - 1 - ] as FASTRadio; - lastCheckedRadio.checked = true; - this.focusedRadio = lastCheckedRadio; - lastCheckedRadio.setAttribute("tabindex", "0"); - } else { - this.slottedRadioButtons[0].setAttribute("tabindex", "0"); - this.focusedRadio = this.slottedRadioButtons[0] as FASTRadio; - } - } - } - - private radioChangeHandler = (e: CustomEvent): boolean | void => { - const changedRadio: FASTRadio = e.target as FASTRadio; - - if (changedRadio.checked) { - this.slottedRadioButtons.forEach((radio: FASTRadio) => { - if (radio !== changedRadio) { - radio.checked = false; - if (!this.isInsideFoundationToolbar) { - radio.setAttribute("tabindex", "-1"); - } - } - }); - this.selectedRadio = changedRadio; - this.value = changedRadio.value; - changedRadio.setAttribute("tabindex", "0"); - this.focusedRadio = changedRadio; - } - e.stopPropagation(); - }; - - private moveToRadioByIndex = (group: HTMLElement[], index: number) => { - const radio: FASTRadio = group[index] as FASTRadio; - if (!this.isInsideToolbar) { - radio.setAttribute("tabindex", "0"); - radio.checked = true; - this.selectedRadio = radio; - } - this.focusedRadio = radio; - radio.focus(); - }; - - private moveRightOffGroup = () => { - (this.nextElementSibling as FASTRadio)?.focus(); - }; - - private moveLeftOffGroup = () => { - (this.previousElementSibling as FASTRadio)?.focus(); - }; - - /** - * @internal - */ - public focusOutHandler = (e: FocusEvent): boolean | void => { - const group: HTMLElement[] = this.slottedRadioButtons; - const radio: FASTRadio | null = e.target as FASTRadio; - const index: number = radio !== null ? group.indexOf(radio) : 0; - const focusedIndex: number = this.focusedRadio - ? group.indexOf(this.focusedRadio) - : -1; - - if ( - (focusedIndex === 0 && index === focusedIndex) || - (focusedIndex === group.length - 1 && focusedIndex === index) - ) { - if (!this.selectedRadio) { - this.focusedRadio = group[0] as FASTRadio; - this.focusedRadio.setAttribute("tabindex", "0"); - group.forEach((nextRadio: FASTRadio) => { - if (nextRadio !== this.focusedRadio) { - nextRadio.setAttribute("tabindex", "-1"); - } - }); - } else { - this.focusedRadio = this.selectedRadio; - - if (!this.isInsideFoundationToolbar) { - this.selectedRadio.setAttribute("tabindex", "0"); - group.forEach((nextRadio: FASTRadio) => { - if (nextRadio !== this.selectedRadio) { - nextRadio.setAttribute("tabindex", "-1"); - } - }); - } - } - } - return true; - }; - - /** - * @internal - */ - public handleDisabledClick = (e: MouseEvent): void | boolean => { - // prevent focus events on items from the click handler when disabled - if (this.disabled) { - e.preventDefault(); - return; - } - - return true; - }; - - /** - * @internal - */ - public clickHandler = (e: MouseEvent): void | boolean => { - if (this.disabled) { - return; - } - - e.preventDefault(); - const radio: FASTRadio | null = e.target as FASTRadio; - - if (radio && radio instanceof FASTRadio) { - radio.checked = true; - radio.setAttribute("tabindex", "0"); - this.selectedRadio = radio; - this.focusedRadio = radio; - } - }; - - private shouldMoveOffGroupToTheRight = ( - index: number, - group: HTMLElement[], - key: string - ): boolean => { - return index === group.length && this.isInsideToolbar && key === keyArrowRight; - }; - - private shouldMoveOffGroupToTheLeft = ( - group: HTMLElement[], - key: string - ): boolean => { - const index = this.focusedRadio ? group.indexOf(this.focusedRadio) - 1 : 0; - return index < 0 && this.isInsideToolbar && key === keyArrowLeft; - }; - - private checkFocusedRadio = (): void => { - if (this.focusedRadio !== null && !this.focusedRadio.checked) { - this.focusedRadio.checked = true; - this.focusedRadio.setAttribute("tabindex", "0"); - this.focusedRadio.focus(); - this.selectedRadio = this.focusedRadio; - } - }; - - private moveRight = (e: KeyboardEvent): void => { - const group: HTMLElement[] = this.slottedRadioButtons; - let index: number = 0; - - index = this.focusedRadio ? group.indexOf(this.focusedRadio) + 1 : 1; - if (this.shouldMoveOffGroupToTheRight(index, group, e.key)) { - this.moveRightOffGroup(); - return; - } else if (index === group.length) { - index = 0; - } - /* looping to get to next radio that is not disabled */ - /* matching native radio/radiogroup which does not select an item if there is only 1 in the group */ - while (index < group.length && group.length > 1) { - if (!(group[index] as FASTRadio).disabled) { - this.moveToRadioByIndex(group, index); - break; - } else if (this.focusedRadio && index === group.indexOf(this.focusedRadio)) { - break; - } else if (index + 1 >= group.length) { - if (this.isInsideToolbar) { - break; - } else { - index = 0; - } - } else { - index += 1; - } - } - }; - - private moveLeft = (e: KeyboardEvent): void => { - const group: HTMLElement[] = this.slottedRadioButtons; - let index: number = 0; - - index = this.focusedRadio ? group.indexOf(this.focusedRadio) - 1 : 0; - index = index < 0 ? group.length - 1 : index; - - if (this.shouldMoveOffGroupToTheLeft(group, e.key)) { - this.moveLeftOffGroup(); - return; - } - /* looping to get to next radio that is not disabled */ - while (index >= 0 && group.length > 1) { - if (!(group[index] as FASTRadio).disabled) { - this.moveToRadioByIndex(group, index); - break; - } else if (this.focusedRadio && index === group.indexOf(this.focusedRadio)) { - break; - } else if (index - 1 < 0) { - index = group.length - 1; - } else { - index -= 1; - } - } - }; - - /** - * keyboard handling per https://w3c.github.io/aria-practices/#for-radio-groups-not-contained-in-a-toolbar - * navigation is different when there is an ancestor with role='toolbar' - * - * @internal - */ - public keydownHandler = (e: KeyboardEvent): boolean | void => { - const key = e.key; - - if (key in ArrowKeys && (this.isInsideFoundationToolbar || this.disabled)) { - return true; - } - - switch (key) { - case keyEnter: { - this.checkFocusedRadio(); - break; - } - - case keyArrowRight: - case keyArrowDown: { - if (this.direction === Direction.ltr) { - this.moveRight(e); - } else { - this.moveLeft(e); - } - break; - } - - case keyArrowLeft: - case keyArrowUp: { - if (this.direction === Direction.ltr) { - this.moveLeft(e); - } else { - this.moveRight(e); - } - break; - } - - default: { - return true; - } - } - }; -} diff --git a/packages/web-components/fast-foundation/src/radio-group/stories/radio-group.register.ts b/packages/web-components/fast-foundation/src/radio-group/stories/radio-group.register.ts deleted file mode 100644 index c7baedb719f..00000000000 --- a/packages/web-components/fast-foundation/src/radio-group/stories/radio-group.register.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { css } from "@microsoft/fast-element"; -import { FASTRadioGroup } from "../radio-group.js"; -import { radioGroupTemplate } from "../radio-group.template.js"; - -const styles = css` - :host([hidden]) { - display: none; - } - :host { - align-items: flex-start; - display: flex; - flex-direction: column; - margin: calc(var(--design-unit) * 1px) 0; - } - .positioning-region { - display: flex; - flex-wrap: wrap; - } - :host([orientation="vertical"]) .positioning-region { - flex-direction: column; - } - :host([orientation="horizontal"]) .positioning-region { - flex-direction: row; - } - - :host([disabled]) { - opacity: var(--disabled-opacity); - } -`; - -FASTRadioGroup.define({ - name: "fast-radio-group", - template: radioGroupTemplate(), - styles, -}); diff --git a/packages/web-components/fast-foundation/src/radio-group/stories/radio-group.stories.ts b/packages/web-components/fast-foundation/src/radio-group/stories/radio-group.stories.ts deleted file mode 100644 index c36c12679a0..00000000000 --- a/packages/web-components/fast-foundation/src/radio-group/stories/radio-group.stories.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { html, repeat } from "@microsoft/fast-element"; -import { storyTemplate as radioStoryTemplate } from "../../radio/stories/radio.stories.js"; -import type { Meta, Story, StoryArgs } from "../../__test__/helpers.js"; -import { renderComponent } from "../../__test__/helpers.js"; -import type { FASTRadioGroup } from "../radio-group.js"; -import { RadioGroupOrientation } from "../radio-group.options.js"; - -const storyTemplate = html>` - - ${x => x.storyContent} - -`; - -export default { - title: "Radio Group", - args: { - disabled: false, - name: "fruits", - readOnly: false, - storyContent: html>` - - ${repeat(x => x.storyItems, radioStoryTemplate)} - `, - storyItems: [ - { storyContent: "Apples", value: "apples" }, - { storyContent: "Bananas", value: "bananas" }, - { storyContent: "Blueberries", value: "blueberries" }, - { storyContent: "Grapefruit", value: "grapefruit" }, - { storyContent: "Kiwi", value: "kiwi" }, - { storyContent: "Mango", value: "mango" }, - { storyContent: "Oranges", value: "oranges" }, - { storyContent: "Pineapple", value: "pineapple" }, - { storyContent: "Strawberries", value: "strawberries" }, - ], - }, - argTypes: { - disabled: { control: "boolean" }, - name: { control: "text" }, - orientation: { control: "radio", options: Object.values(RadioGroupOrientation) }, - readOnly: { control: "boolean" }, - storyContent: { table: { disable: true } }, - storyItems: { control: "object" }, - value: { control: "text" }, - }, -} as Meta; - -export const RadioGroup: Story = renderComponent(storyTemplate).bind({}); - -export const RadioGroupVertical: Story = RadioGroup.bind({}); -RadioGroupVertical.args = { - orientation: RadioGroupOrientation.vertical, -}; - -export const RadioGroupInForm: Story = renderComponent( - html>` -
- ${storyTemplate} - Submit -
- ` -).bind({}); diff --git a/packages/web-components/fast-foundation/src/radio/README.md b/packages/web-components/fast-foundation/src/radio/README.md deleted file mode 100644 index d89775e7a8e..00000000000 --- a/packages/web-components/fast-foundation/src/radio/README.md +++ /dev/null @@ -1,155 +0,0 @@ ---- -id: radio -title: fast-radio -sidebar_label: radio -custom_edit_url: https://github.com/microsoft/fast/edit/master/packages/web-components/fast-foundation/src/radio/README.md -description: fast-radio is an implementation of a radio as a form-connected web component. ---- - -An implementation of a [radio](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/radio) as a form-connected web-component. - -## Setup - -### Basic Setup - -```ts -import { - provideFASTDesignSystem, - fastRadio -} from "@microsoft/fast-components"; - -provideFASTDesignSystem() - .register( - fastRadio() - ); -``` - -### Customizing the indicator - -```ts -import { - provideFASTDesignSystem, - fastRadio -} from "@microsoft/fast-components"; - -provideFASTDesignSystem() - .register( - fastRadio({ - checkedIndicator: `...your checked indicator...` - }) - ); -``` - -## Usage - -```html live -
-

Favorite fruit:

- Apple - Mango - Orange -
- ``` - -:::note - -For a more ergonomic usage of radios in groups, see [the `fast-radio-group` documentation](/docs/components/radio-group). - -::: - -## Create your own design - -```ts -import { - Radio, - RadioOptions, - radioTemplate as template, -} from "@microsoft/fast-foundation"; -import { radioStyles as styles } from "./my-radio.styles"; - -export const myRadio = Radio.compose({ - baseName: "radio", - template, - styles, - checkedIndicator: `...default checked indicator...`, -}); -``` - -## API - - - -### class: `FormAssociatedRadio` - -#### Superclass - -| Name | Module | Package | -| -------- | ---------------------------------- | ------- | -| `_Radio` | src/radio/radio.form-associated.ts | | - -#### Mixins - -| Name | Module | Package | -| ------------------------- | --------------------------------------- | ------- | -| `CheckableFormAssociated` | /src/form-associated/form-associated.js | | - -#### Fields - -| Name | Privacy | Type | Default | Description | Inherited From | -| ------- | ------- | ---- | ------- | ----------- | -------------- | -| `proxy` | | | | | | - -
- - - -### class: `FASTRadio` - -#### Superclass - -| Name | Module | Package | -| --------------------- | ----------------------------------- | ------- | -| `FormAssociatedRadio` | /src/radio/radio.form-associated.js | | - -#### Fields - -| Name | Privacy | Type | Default | Description | Inherited From | -| ------- | ------- | -------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- | -| `name` | public | `string` | | The name of the radio. See [name attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefname) for more info. | | -| `proxy` | | | | | FormAssociatedRadio | - -#### Methods - -| Name | Privacy | Description | Parameters | Return | Inherited From | -| ----------------- | ------- | --------------------------------- | ------------------ | ----------------- | -------------- | -| `keypressHandler` | public | Handles key presses on the radio. | `e: KeyboardEvent` | `boolean or void` | | - -#### Events - -| Name | Type | Description | Inherited From | -| -------- | ---- | ---------------------------------------------------------- | -------------- | -| `change` | | Emits a custom change event when the checked state changes | | - -#### CSS Parts - -| Name | Description | -| --------- | ------------------------------------------------- | -| `control` | The element representing the visual radio control | -| `label` | The label | - -#### Slots - -| Name | Description | -| ------------------- | ------------------------------ | -| `checked-indicator` | The checked indicator | -| | The default slot for the label | - -
- - -## Additional resources - -* [Component explorer examples](https://explore.fast.design/components/fast-radio) -* [Component technical specification](https://github.com/microsoft/fast/blob/master/packages/web-components/fast-foundation/src/radio/radio.spec.md) -* [W3C Component Aria Practices](https://www.w3.org/TR/wai-aria/#radio) -* [Open UI Analysis](https://open-ui.org/components/radio-button.research) \ No newline at end of file diff --git a/packages/web-components/fast-foundation/src/radio/index.ts b/packages/web-components/fast-foundation/src/radio/index.ts deleted file mode 100644 index 8cd87cd93af..00000000000 --- a/packages/web-components/fast-foundation/src/radio/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { FASTRadio } from "./radio.js"; -export type { RadioControl, RadioOptions } from "./radio.js"; -export { radioTemplate } from "./radio.template.js"; diff --git a/packages/web-components/fast-foundation/src/radio/radio.form-associated.ts b/packages/web-components/fast-foundation/src/radio/radio.form-associated.ts deleted file mode 100644 index 608940dcbff..00000000000 --- a/packages/web-components/fast-foundation/src/radio/radio.form-associated.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { FASTElement } from "@microsoft/fast-element"; -import { CheckableFormAssociated } from "../form-associated/form-associated.js"; - -class _Radio extends FASTElement {} -interface _Radio extends CheckableFormAssociated {} - -/** - * A form-associated base class for the {@link @microsoft/fast-foundation#(FASTRadio:class)} component. - * - * @beta - */ -export class FormAssociatedRadio extends CheckableFormAssociated(_Radio) { - proxy = document.createElement("input"); -} diff --git a/packages/web-components/fast-foundation/src/radio/radio.pw.spec.ts b/packages/web-components/fast-foundation/src/radio/radio.pw.spec.ts deleted file mode 100644 index ab00fc6e497..00000000000 --- a/packages/web-components/fast-foundation/src/radio/radio.pw.spec.ts +++ /dev/null @@ -1,312 +0,0 @@ -import { expect, test } from "@playwright/test"; -import type { Locator, Page } from "@playwright/test"; -import { fixtureURL } from "../__test__/helpers.js"; -import type { FASTRadio } from "./radio.js"; - -test.describe("Radio", () => { - let page: Page; - let element: Locator; - let root: Locator; - - test.beforeAll(async ({ browser }) => { - page = await browser.newPage(); - - element = page.locator("fast-radio"); - - root = page.locator("#storybook-root"); - - await page.goto(fixtureURL("radio--radio")); - - await element.waitFor({ state: "attached" }); - }); - - test.afterAll(async () => { - await page.close(); - }); - - test("should have a role of `radio`", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - Radio - `; - }); - - await expect(element).toHaveAttribute("role", "radio"); - }); - - test("should set ARIA attributes to match the state", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - Radio - `; - }); - - // Checked - await expect(element).toHaveAttribute("aria-checked", "false"); - - await element.evaluate((node: FASTRadio) => (node.checked = true)); - - await expect(element).toHaveAttribute("aria-checked", "true"); - - await element.evaluate((node: FASTRadio) => (node.checked = false)); - - await expect(element).toHaveAttribute("aria-checked", "false"); - - // Required - await expect(element).toHaveAttribute("aria-required", "false"); - - await element.evaluate((node: FASTRadio) => (node.required = true)); - - await expect(element).toHaveAttribute("aria-required", "true"); - - await element.evaluate((node: FASTRadio) => (node.required = false)); - - await expect(element).toHaveAttribute("aria-required", "false"); - - // Disabled - await expect(element).toHaveAttribute("aria-disabled", "false"); - - await element.evaluate((node: FASTRadio) => (node.disabled = true)); - - await expect(element).toHaveAttribute("aria-disabled", "true"); - - await element.evaluate((node: FASTRadio) => (node.disabled = false)); - - await expect(element).toHaveAttribute("aria-disabled", "false"); - }); - - test("should set a tabindex of 0 on the element", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - Radio - `; - }); - - await expect(element).toHaveAttribute("tabindex", "0"); - }); - - test("should NOT set a tabindex when disabled is `true`", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element).not.toHaveAttribute("tabindex"); - }); - - test("should initialize to the initial value if no value property is set", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - Radio - `; - }); - - await expect(element).toHaveJSProperty("value", "on"); - - await expect(element).toHaveJSProperty("initialValue", "on"); - }); - - test("should initialize to the provided value attribute if set pre-connection", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - Radio - `; - }); - - await element.evaluate((node: FASTRadio) => node.setAttribute("value", "foo")); - - await expect(element).toHaveJSProperty("value", "foo"); - }); - - test("should initialize to the provided value attribute if set post-connection", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - Radio - `; - }); - - await element.evaluate((node: FASTRadio) => node.setAttribute("value", "foo")); - - await expect(element).toHaveJSProperty("value", "foo"); - }); - - test("should initialize to the provided value property if set pre-connection", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - await expect(element).toHaveJSProperty("value", "foo"); - }); - - test("should set the `label__hidden` class on the internal label when default slotted content does not exist", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - label - `; - }); - - const label = element.locator("label"); - - await expect(label).toHaveClass(/^label$/); - - await element.evaluate(node => { - node.textContent = ""; - }); - - await expect(label).toHaveClass(/label__hidden/); - }); - - test("should fire an event when spacebar is pressed", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - Radio - `; - }); - - const [wasPressed] = await Promise.all([ - element.evaluate( - (node: FASTRadio) => - new Promise(resolve => - node.addEventListener("keydown", () => resolve(true), { - once: true, - }) - ) - ), - // FIXME: Playwright's keyboard API is not working as expected. - element.evaluate(node => - node.dispatchEvent(new KeyboardEvent("keydown", { key: " " })) - ), - ]); - - expect(wasPressed).toBeTruthy(); - }); - - test("should NOT fire events when clicked", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - Radio - `; - }); - - const [wasClicked] = await Promise.all([ - element.evaluate( - (node: FASTRadio) => - new Promise(resolve => - node.addEventListener("click", () => resolve(false), { - once: true, - }) - ) - ), - element.evaluate(node => { - node.dispatchEvent(new MouseEvent("click")); - }), - ]); - - expect(wasClicked).toBeFalsy(); - }); - - test("should handle validity when the `required` attribute is present", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - Radio - - `; - }); - - expect( - await element.evaluate((node: FASTRadio) => node.validity.valueMissing) - ).toBe(true); - - await element.click(); - - expect( - await element.evaluate((node: FASTRadio) => node.validity.valueMissing) - ).toBe(false); - }); - - test.describe("whose parent form has its reset() method invoked", () => { - test("should set its checked property to false if the checked attribute is unset", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` -
- Radio -
- `; - }); - - const form = page.locator("form"); - - await element.evaluate((node: FASTRadio) => (node.checked = true)); - - await expect(element).toBeChecked(); - - await form.evaluate((node: HTMLFormElement) => { - node.reset(); - }); - - await expect(element).not.toBeChecked(); - }); - - test("should set its checked property to true if the checked attribute is set", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` -
- -
- `; - }); - - const form = page.locator("form"); - - expect( - await element.evaluate(node => node.hasAttribute("checked")) - ).toBeTruthy(); - - await expect(element).toBeChecked(); - - await element.evaluate((node: FASTRadio) => (node.checked = false)); - - await expect(element).not.toBeChecked(); - - await form.evaluate((node: HTMLFormElement) => { - node.reset(); - }); - - await expect(element).toBeChecked(); - }); - /* eslint-disable-next-line max-len */ - test("should put the control into a clean state, where `checked` attribute modifications modify the `checked` property prior to user or programmatic interaction", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` -
- Radio -
- `; - }); - - const form = page.locator("form"); - - await element.evaluate((node: FASTRadio) => { - node.checked = true; - }); - - await element.evaluate(node => node.removeAttribute("checked")); - - await expect(element).toBeChecked(); - - await form.evaluate((node: HTMLFormElement) => { - node.reset(); - }); - - await expect(element).not.toBeChecked(); - - await element.evaluate(node => node.setAttribute("checked", "")); - - await expect(element).toBeChecked(); - }); - }); -}); diff --git a/packages/web-components/fast-foundation/src/radio/radio.spec.md b/packages/web-components/fast-foundation/src/radio/radio.spec.md deleted file mode 100644 index 2e37f6c8bf6..00000000000 --- a/packages/web-components/fast-foundation/src/radio/radio.spec.md +++ /dev/null @@ -1,99 +0,0 @@ -# Radio - -## Overview -An implementation of a radio button as a form-connected web-component. Facilitating single select from a group of visible choices. - -### Use Cases -Used anywhere an author might otherwise use an `input[type="radio"]`. Used to facilitate choice where only one choice is acceptable. - -### Features -- form association -- focus delegation - -### Risks and Challenges -We want general feature-parity between this component and an `input[type="radio"]`. - -### Prior Art/Examples -- [FAST Radio (React)](https://www.npmjs.com/package/@microsoft/fast-components-react-msft) -- [Material UI](https://material-ui.com/components/radio-buttons/) -- [Lightning Design](https://www.lightningdesignsystem.com/components/radio-group/) -- [Carbon Design](https://www.carbondesignsystem.com/components/radio-button/code) -- [Ant Design](https://ant.design/components/radio/) -- [Atlassian](https://atlaskit.atlassian.com/packages/core/radio) -- [Office Fabric](https://developer.microsoft.com/en-us/fluentui#/controls/web/choicegroup) -- [Windows (UWP)](https://docs.microsoft.com/en-us/windows/uwp/design/controls-and-patterns/radio-button) ---- - -### API -Extends [form associated custom element](../form-associated/form-associated-custom-element.md). - -*Component Name* -`fast-radio` - -*IDL attributes* -- `checked: boolean` - - The current checked state of the radio - -*Content attributes* -- `disabled` - - The radio should be disabled from user interaction and will not be submitted with the form data. -- `value` - Not visible to the user, it's used for form data and to distinguish between other radio buttons of the same name attribute value. -- `checked` - - The initial checked value. - -*Events* -- `change: CustomEvent` - - no custom data - - bubbles - -### Anatomy and Appearance - -```HTML - - -
- -
-
-
-
- -``` - -*Slot Names* -- default: label for the radio -- checked-indicator: visual indicator control is checked - -*Host Classes* -- checked -- disabled -- required - -*Slotted Content/Slotted Classes* -*CSS Parts* -- control -- label -- checked-indicator - -### States -**checked**: `true` or `false` -The checked state can be toggled by: -- Clicking the radio button (or any of it's labels) -- Pressing the space-bar while focus is placed on the radio button will toggle it on - -**disabled**: `true` or `false` -When disabled, the value will not be changeable through user interaction. It should also not expose it's value to a form submission. - -### Accessibility -The root element inside the shadow-dom of the radio will be a focusable element with the following accessibility content attributes: -[MDN Web docs](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_radio_role) -- role: radio -- aria-checked: the checked state of the component -- aria-required: the required state of the component -- aria-disabled: the disabled state of the component -- tabindex: 0 - -## Next steps -Adding mechanisms, slots, and data for surfacing validation error messages. \ No newline at end of file diff --git a/packages/web-components/fast-foundation/src/radio/radio.template.ts b/packages/web-components/fast-foundation/src/radio/radio.template.ts deleted file mode 100644 index 0a8e522aeec..00000000000 --- a/packages/web-components/fast-foundation/src/radio/radio.template.ts +++ /dev/null @@ -1,43 +0,0 @@ -import type { ElementViewTemplate } from "@microsoft/fast-element"; -import { html, slotted } from "@microsoft/fast-element"; -import { staticallyCompose } from "../utilities/template-helpers.js"; -import { whitespaceFilter } from "../utilities/whitespace-filter.js"; -import type { FASTRadio, RadioOptions } from "./radio.js"; - -/** - * The template for the {@link @microsoft/fast-foundation#(FASTRadio:class)} component. - * @public - */ -export function radioTemplate( - options: RadioOptions = {} -): ElementViewTemplate { - return html` - - `; -} diff --git a/packages/web-components/fast-foundation/src/radio/radio.ts b/packages/web-components/fast-foundation/src/radio/radio.ts deleted file mode 100644 index 53646c0882f..00000000000 --- a/packages/web-components/fast-foundation/src/radio/radio.ts +++ /dev/null @@ -1,132 +0,0 @@ -import { observable } from "@microsoft/fast-element"; -import { keySpace } from "@microsoft/fast-web-utilities"; -import type { FASTRadioGroup } from "../radio-group/index.js"; -import type { StaticallyComposableHTML } from "../utilities/template-helpers.js"; -import { FormAssociatedRadio } from "./radio.form-associated.js"; - -/** - * A structure representing a {@link @microsoft/fast-foundation#(FASTRadio:class)} element - * @public - */ -export type RadioControl = Pick< - HTMLInputElement, - "checked" | "disabled" | "focus" | "setAttribute" | "getAttribute" ->; - -/** - * Radio configuration options - * @public - */ -export type RadioOptions = { - checkedIndicator?: StaticallyComposableHTML; -}; - -/** - * A Radio Custom HTML Element. - * Implements the {@link https://www.w3.org/TR/wai-aria-1.1/#radio | ARIA radio }. - * - * @slot checked-indicator - The checked indicator - * @slot - The default slot for the label - * @csspart control - The element representing the visual radio control - * @csspart label - The label - * @fires change - Emits a custom change event when the checked state changes - * - * @public - */ -export class FASTRadio extends FormAssociatedRadio implements RadioControl { - /** - * The name of the radio. - * See {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefname | name attribute} for more info. - */ - @observable - public name: string; - - /** - * The element's value to be included in form submission when checked. - * Default to "on" to reach parity with input[type="radio"] - * - * @internal - */ - public initialValue: string = "on"; - - /** - * @internal - */ - @observable - public defaultSlottedNodes: Node[]; - - private get radioGroup() { - return (this as HTMLElement).closest( - "[role=radiogroup]" - ) as FASTRadioGroup | null; - } - - /** - * @internal - */ - public defaultCheckedChanged(): void { - if (this.$fastController.isConnected && !this.dirtyChecked) { - // Setting this.checked will cause us to enter a dirty state, - // but if we are clean when defaultChecked is changed, we want to stay - // in a clean state, so reset this.dirtyChecked - if (!this.isInsideRadioGroup()) { - this.checked = this.defaultChecked ?? false; - this.dirtyChecked = false; - } - } - } - - constructor() { - super(); - this.proxy.setAttribute("type", "radio"); - } - - /** - * @internal - */ - public connectedCallback(): void { - super.connectedCallback(); - this.validate(); - - if ( - this.parentElement?.getAttribute("role") !== "radiogroup" && - this.getAttribute("tabindex") === null - ) { - if (!this.disabled) { - this.setAttribute("tabindex", "0"); - } - } - - if (this.checkedAttribute) { - if (!this.dirtyChecked) { - // Setting this.checked will cause us to enter a dirty state, - // but if we are clean when defaultChecked is changed, we want to stay - // in a clean state, so reset this.dirtyChecked - if (!this.isInsideRadioGroup()) { - this.checked = this.defaultChecked ?? false; - this.dirtyChecked = false; - } - } - } - } - - private isInsideRadioGroup(): boolean { - return this.radioGroup !== null; - } - - /** - * Handles key presses on the radio. - * @beta - */ - public keypressHandler(e: KeyboardEvent): boolean | void { - switch (e.key) { - case keySpace: - if (!this.checked && !this.radioGroup?.readOnly) { - this.checked = true; - } - return; - } - - return true; - } -} diff --git a/packages/web-components/fast-foundation/src/radio/stories/radio.register.ts b/packages/web-components/fast-foundation/src/radio/stories/radio.register.ts deleted file mode 100644 index 24cffbc4ab2..00000000000 --- a/packages/web-components/fast-foundation/src/radio/stories/radio.register.ts +++ /dev/null @@ -1,143 +0,0 @@ -import { html } from "@microsoft/fast-element"; -import { css } from "@microsoft/fast-element"; -import { FASTRadio } from "../radio.js"; -import { radioTemplate } from "../radio.template.js"; - -const styles = css` - :host([hidden]) { - display: none; - } - :host { - --input-size: calc( - ((var(--base-height-multiplier) + var(--density)) * var(--design-unit) / 2) + - var(--design-unit) - ); - align-items: center; - display: inline-flex; - flex-direction: row; - margin: calc(var(--design-unit) * 1px) 0; - /* Chromium likes to select label text or the default slot when - the radio is clicked. Maybe there is a better solution here? */ - outline: none; - position: relative; - user-select: none; - } - - .control { - --size: calc( - ( - (var(--base-height-multiplier)) * var(--design-unit) / 2 + - var(--design-unit) - ) * 1px - ); - position: relative; - width: var(--size); - height: var(--size); - box-sizing: border-box; - border-radius: 100%; - border: calc(var(--stroke-width) * 1px) solid var(--neutral-stroke-rest); - background: var(--neutral-fill-input-rest); - outline: none; - cursor: pointer; - } - - .label { - --spacing: calc(var(--design-unit) * 2px + 2px); - color: var(--neutral-foreground-rest); - cursor: pointer; - font: var(--type-ramp-base-font-size) / var(--type-ramp-base-line-height) - var(--body-font); - margin-inline-end: var(--spacing); - padding-inline-start: var(--spacing); - } - - .label__hidden { - display: none; - visibility: hidden; - } - - .control, - .checked-indicator { - flex-shrink: 0; - } - - .checked-indicator { - position: absolute; - top: 5px; - left: 5px; - right: 5px; - bottom: 5px; - border-radius: 100%; - display: inline-block; - background: var(--foreground-on-accent-rest); - fill: var(--foreground-on-accent-rest); - opacity: 0; - pointer-events: none; - } - - :host(:not([disabled])) .control:hover { - background: var(--neutral-fill-input-hover); - border-color: var(--neutral-stroke-hover); - } - - :host(:not([disabled])) .control:active { - background: var(--neutral-fill-input-active); - border-color: var(--neutral-stroke-active); - } - - :host(:focus-visible) .control { - box-shadow: 0 0 0 2px var(--fill-color), 0 0 0 4px var(--focus-stroke-outer); - } - - :host([aria-checked="true"]) .control { - background: var(--accent-fill-rest); - border: calc(var(--stroke-width) * 1px) solid var(--accent-fill-rest); - } - - :host([aria-checked="true"]:not([disabled])) .control:hover { - background: var(--accent-fill-hover); - border: calc(var(--stroke-width) * 1px) solid var(--accent-fill-hover); - } - - :host([aria-checked="true"]:not([disabled])) .control:hover .checked-indicator { - background: var(--foreground-on-accent-hover); - fill: var(--foreground-on-accent-hover); - } - - :host([aria-checked="true"]:not([disabled])) .control:active { - background: var(--accent-fill-active); - border: calc(var(--stroke-width) * 1px) solid var(--accent-fill-active); - } - - :host([aria-checked="true"]:not([disabled])) .control:active .checked-indicator { - background: var(--foreground-on-accent-active); - fill: var(--foreground-on-accent-active); - } - - :host([aria-checked="true"]:focus-visible:not([disabled])) .control { - box-shadow: 0 0 0 2px var(--fill-color), 0 0 0 4px var(--focus-stroke-outer); - } - - :host([disabled]) .label, - :host([disabled]) .control { - cursor: not-allowed; - } - - :host([aria-checked="true"]) .checked-indicator { - opacity: 1; - } - - :host([disabled]) { - opacity: var(--disabled-opacity); - } -`; - -FASTRadio.define({ - name: "fast-radio", - template: radioTemplate({ - checkedIndicator: /* html */ html` -
- `, - }), - styles, -}); diff --git a/packages/web-components/fast-foundation/src/radio/stories/radio.stories.ts b/packages/web-components/fast-foundation/src/radio/stories/radio.stories.ts deleted file mode 100644 index 46165d70fe0..00000000000 --- a/packages/web-components/fast-foundation/src/radio/stories/radio.stories.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { html } from "@microsoft/fast-element"; -import type { Meta, Story, StoryArgs } from "../../__test__/helpers.js"; -import { renderComponent } from "../../__test__/helpers.js"; -import type { FASTRadio } from "../radio.js"; - -export const storyTemplate = html>` - - ${x => x.storyContent} - -`; - -export default { - title: "Radio", - excludeStories: ["storyTemplate"], - args: { - checked: false, - disabled: false, - required: false, - storyContent: "Label", - }, - argTypes: { - checked: { control: "boolean" }, - disabled: { control: "boolean" }, - name: { control: "text" }, - required: { control: "boolean" }, - storyContent: { table: { disable: true } }, - value: { control: "text" }, - }, -} as Meta; - -export const Radio: Story = renderComponent(storyTemplate).bind({}); - -export const RadioInForm: Story = renderComponent( - html>` -
- ${storyTemplate} - Submit -
- ` -).bind({}); diff --git a/packages/web-components/fast-foundation/src/search/README.md b/packages/web-components/fast-foundation/src/search/README.md deleted file mode 100644 index 0367b64f0d7..00000000000 --- a/packages/web-components/fast-foundation/src/search/README.md +++ /dev/null @@ -1,168 +0,0 @@ ---- -id: search -title: fast-search -sidebar_label: search -custom_edit_url: https://github.com/microsoft/fast/edit/master/packages/web-components/fast-foundation/src/search/README.md ---- - -An implementation of a [search](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input/search) as a form-connected web-component. The `fast-search` supports two visual appearances, outline and filled, with the control defaulting to the outline appearance. - -:::note -This component filters out slotted _text_ nodes that are only white space to properly hide the label when the label is not in use. -::: - -## Setup - -```ts -import { - provideFASTDesignSystem, - fastSearch -} from "@microsoft/fast-components"; - -provideFASTDesignSystem() - .register( - fastSearch() - ); -``` - -## Usage - -```html live -search -``` - -## Create your own design - -```ts -import { - Search, - searcgTemplate as template, -} from "@microsoft/fast-foundation"; -import { searchStyles as styles } from "./my-search.styles"; - - -export const mySearch = Search.compose({ - baseName: "search", - template, - styles, - shadowOptions: { - delegatesFocus: true, - }, -}); -``` - -:::note -This component is built with the expectation that focus is delegated to the input element rendered into the shadow DOM. -::: - -## API - - - -### class: `FormAssociatedSearch` - -#### Superclass - -| Name | Module | Package | -| --------- | ------------------------------------ | ------- | -| `_Search` | src/search/search.form-associated.ts | | - -#### Mixins - -| Name | Module | Package | -| ---------------- | --------------------------------------- | ------- | -| `FormAssociated` | /src/form-associated/form-associated.js | | - -#### Fields - -| Name | Privacy | Type | Default | Description | Inherited From | -| ------- | ------- | ---- | ------- | ----------- | -------------- | -| `proxy` | | | | | | - -
- - - -### class: `FASTSearch` - -#### Superclass - -| Name | Module | Package | -| ---------------------- | ------------------------------------- | ------- | -| `FormAssociatedSearch` | /src/search/search.form-associated.js | | - -#### Fields - -| Name | Privacy | Type | Default | Description | Inherited From | -| ------------- | ------- | --------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- | -| `readOnly` | public | `boolean` | | When true, the control will be immutable by user interaction. See [readonly HTML attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/readonly) for more information. | | -| `autofocus` | public | `boolean` | | Indicates that this element should get focus after the page finishes loading. See [autofocus HTML attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefautofocus) for more information. | | -| `placeholder` | public | `string` | | Sets the placeholder value of the element, generally used to provide a hint to the user. | | -| `list` | public | `string` | | Allows associating a [datalist](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/datalist) to the element by https://developer.mozilla.org/en-US/docs/Web/API/Element/id. | | -| `maxlength` | public | `number` | | The maximum number of characters a user can enter. | | -| `minlength` | public | `number` | | The minimum number of characters a user can enter. | | -| `pattern` | public | `string` | | A regular expression that the value must match to pass validation. | | -| `size` | public | `number` | | Sets the width of the element to a specified number of characters. | | -| `spellcheck` | public | `boolean` | | Controls whether or not to enable spell checking for the input field, or if the default spell checking configuration should be used. | | -| `proxy` | | | | | FormAssociatedSearch | - -#### Methods - -| Name | Privacy | Description | Parameters | Return | Inherited From | -| -------------------- | --------- | ------------------------------------------------- | ---------- | ------ | -------------- | -| `readOnlyChanged` | protected | | | `void` | | -| `autofocusChanged` | protected | | | `void` | | -| `placeholderChanged` | protected | | | `void` | | -| `listChanged` | protected | | | `void` | | -| `maxlengthChanged` | protected | | | `void` | | -| `minlengthChanged` | protected | | | `void` | | -| `patternChanged` | protected | | | `void` | | -| `sizeChanged` | protected | | | `void` | | -| `spellcheckChanged` | protected | | | `void` | | -| `validate` | public | {@inheritDoc (FormAssociated:interface).validate} | | `void` | | -| `handleClearInput` | public | Clears the value | | `void` | | - -#### Attributes - -| Name | Field | Inherited From | -| ------------- | ----------- | -------------- | -| `readonly` | readOnly | | -| | autofocus | | -| `placeholder` | placeholder | | -| `list` | list | | -| | maxlength | | -| | minlength | | -| `pattern` | pattern | | -| | size | | -| | spellcheck | | - -#### CSS Parts - -| Name | Description | -| -------------- | ---------------------------------------------------------------------------------------- | -| `label` | The label | -| `control` | The logical control, the element wrapping the input field, including start and end slots | -| `field` | The element representing the input field | -| `clear-button` | The button to clear the input | - -#### Slots - -| Name | Description | -| -------------- | ----------------------------------------------------------- | -| `start` | Content which can be provided before the search input | -| `end` | Content which can be provided after the search clear button | -| | The default slot for the label | -| `clear-button` | The clear button | -| `clear-icon` | The clear icon | - -
- -### class: `DelegatesARIASearch` - -
- - -## Additional resources - -* [Component explorer examples](https://explore.fast.design/components/fast-search) -* [Component technical specification](https://github.com/microsoft/fast/blob/master/packages/web-components/fast-foundation/src/search/search.spec.md) \ No newline at end of file diff --git a/packages/web-components/fast-foundation/src/search/index.ts b/packages/web-components/fast-foundation/src/search/index.ts deleted file mode 100644 index 14bc77fa570..00000000000 --- a/packages/web-components/fast-foundation/src/search/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { DelegatesARIASearch, FASTSearch } from "./search.js"; -export type { SearchOptions } from "./search.js"; -export { searchTemplate } from "./search.template.js"; diff --git a/packages/web-components/fast-foundation/src/search/search.form-associated.ts b/packages/web-components/fast-foundation/src/search/search.form-associated.ts deleted file mode 100644 index 531c5f7fd14..00000000000 --- a/packages/web-components/fast-foundation/src/search/search.form-associated.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { FASTElement } from "@microsoft/fast-element"; -import { FormAssociated } from "../form-associated/form-associated.js"; - -class _Search extends FASTElement {} -interface _Search extends FormAssociated {} - -/** - * A form-associated base class for the {@link @microsoft/fast-foundation#(FASTSearch:class)} component. - * - * @beta - */ -export class FormAssociatedSearch extends FormAssociated(_Search) { - proxy = document.createElement("input"); -} diff --git a/packages/web-components/fast-foundation/src/search/search.pw.spec.ts b/packages/web-components/fast-foundation/src/search/search.pw.spec.ts deleted file mode 100644 index b857e1c9d54..00000000000 --- a/packages/web-components/fast-foundation/src/search/search.pw.spec.ts +++ /dev/null @@ -1,331 +0,0 @@ -import { spinalCase } from "@microsoft/fast-web-utilities"; -import { expect, test } from "@playwright/test"; -import type { Locator, Page } from "@playwright/test"; -import { fixtureURL } from "../__test__/helpers.js"; -import type { FASTSearch } from "./search.js"; - -test.describe("Search", () => { - let page: Page; - let element: Locator; - let root: Locator; - let field: Locator; - - test.beforeAll(async ({ browser }) => { - page = await browser.newPage(); - - element = page.locator("fast-search"); - - root = page.locator("#storybook-root"); - - field = element.locator(".field"); - - await page.goto(fixtureURL("search--search")); - - await element.waitFor({ state: "attached" }); - }); - - test.afterAll(async () => { - await page.close(); - }); - - test.describe("should set the boolean attribute on the internal input", () => { - const attributes = { - autofocus: true, - disabled: true, - readonly: true, - required: true, - spellcheck: true, - }; - - for (const attribute of Object.keys(attributes)) { - test(`should set ${attribute}`, async () => { - await root.evaluate( - (node, { attribute }) => { - node.innerHTML = /* html */ ` - Search - `; - }, - { attribute } - ); - - await expect(element).toHaveAttribute(attribute); - }); - } - }); - - test.describe("should set the attribute on the internal control", () => { - const attributes = { - maxlength: 14, - minlength: 14, - placeholder: "foo", - size: 8, - list: "listId", - ariaAtomic: "true", - ariaBusy: "false", - ariaControls: "testId", - ariaCurrent: "page", - ariaDescribedby: "testId", - ariaDetails: "testId", - ariaDisabled: "true", - ariaErrormessage: "test", - ariaFlowto: "testId", - ariaHaspopup: "true", - ariaHidden: "true", - ariaInvalid: "spelling", - ariaKeyshortcuts: "F4", - ariaLabel: "Foo label", - ariaLabelledby: "testId", - ariaLive: "polite", - ariaOwns: "testId", - ariaRelevant: "removals", - ariaRoledescription: "search", - }; - - for (const [attribute, value] of Object.entries(attributes)) { - const attrToken = spinalCase(attribute); - test(`should set ${attrToken} to ${value}`, async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - Search - `; - }); - - await element.evaluate( - (node: FASTSearch, { attrToken, value }) => { - node.setAttribute(attrToken, `${value}`); - }, - { attrToken, value } - ); - - await expect(field).toHaveAttribute(spinalCase(attribute), `${value}`); - }); - } - }); - - test("should initialize to the initial value if no value property is set", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - Search - `; - }); - - await expect(element).toHaveJSProperty("value", ""); - }); - - test("should initialize to the provided value attribute if set pre-connection", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - Search - `; - }); - - await expect(element).toHaveJSProperty("value", "foo"); - }); - - test("should initialize to the provided value attribute if set post-connection", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - Search - `; - }); - - await element.evaluate(node => { - node.setAttribute("value", "foo"); - }); - - await expect(element).toHaveJSProperty("value", "foo"); - }); - - test("should initialize to the provided value property if set pre-connection", async () => { - await root.evaluate(node => { - node.innerHTML = ""; - - const searchElement = document.createElement("fast-search") as FASTSearch; - searchElement.value = "foo"; - node.append(searchElement); - }); - - await expect(element).toHaveJSProperty("value", "foo"); - }); - - test("should hide the label when no default slotted content is provided", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - `; - }); - - const label = element.locator(".label"); - - await expect(label).toHaveClass(/label__hidden/); - }); - - test("should hide the label when start content is provided", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - Start - `; - }); - - const label = element.locator(".label"); - - await expect(label).toHaveClass(/label__hidden/); - }); - - test("should hide the label when end content is provided", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - End - `; - }); - - const label = element.locator(".label"); - - await expect(label).toHaveClass(/label__hidden/); - }); - - test("should hide the label when start and end content is provided", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - - Start - End - - `; - }); - - const label = element.locator(".label"); - - await expect(label).toHaveClass(/label__hidden/); - }); - - test("should hide the label when space-only text nodes are slotted", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - label - `; - }); - - const label = element.locator(".label"); - - await expect(label).not.toHaveClass(/label__hidden/); - - await element.evaluate(node => { - node.innerHTML = ` \r `; - }); - - await expect(label).toHaveClass(/label__hidden/); - }); - - test("should fire a change event when the internal control emits a change event", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` - Search - `; - }); - - const field = element.locator(".field"); - - const [wasChanged] = await Promise.all([ - element.evaluate( - node => - new Promise(resolve => { - node.addEventListener("change", () => resolve(true)); - }) - ), - field.evaluate(node => { - node.dispatchEvent(new KeyboardEvent("change")); - }), - ]); - - expect(wasChanged).toBeTruthy(); - }); - - test.describe("when the owning form's reset() method is invoked", () => { - test("should reset its `value` property to an empty string when no value attribute is set", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` -
- Search -
- `; - }); - - const form = page.locator("form"); - - await element.evaluate(node => { - node.value = "test value"; - }); - - await expect(element).toHaveJSProperty("value", "test value"); - - await expect(element).not.toHaveAttribute("value"); - - await form.evaluate(node => { - node.reset(); - }); - - await expect(element).not.toHaveAttribute("value"); - - await expect(element).toHaveJSProperty("value", ""); - }); - - test("should reset its `value` property to the value of the value attribute if it is set", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` -
- Search -
- `; - }); - - const form = page.locator("form"); - - await element.evaluate(node => { - node.value = "new value"; - }); - - await expect(element).toHaveJSProperty("value", "new value"); - - await form.evaluate(node => { - node.reset(); - }); - - await expect(element).toHaveJSProperty("value", "test value"); - }); - /* eslint-disable-next-line max-len */ - test("should put the control into a clean state, where `value` attribute modifications change the `value` property prior to user or programmatic interaction", async () => { - await root.evaluate(node => { - node.innerHTML = /* html */ ` -
- Search -
- `; - }); - - const form = page.locator("form"); - - await element.evaluate(node => { - node.value = "test value"; - }); - - await element.evaluate(node => { - node.setAttribute("value", "attr value"); - }); - - await expect(element).toHaveJSProperty("value", "test value"); - - await form.evaluate(node => { - node.reset(); - }); - - await expect(element).toHaveJSProperty("value", "attr value"); - - await element.evaluate(node => { - node.setAttribute("value", "new attr value"); - }); - - await expect(element).toHaveJSProperty("value", "new attr value"); - }); - }); -}); diff --git a/packages/web-components/fast-foundation/src/search/search.spec.md b/packages/web-components/fast-foundation/src/search/search.spec.md deleted file mode 100644 index 8abf9f72f0f..00000000000 --- a/packages/web-components/fast-foundation/src/search/search.spec.md +++ /dev/null @@ -1,124 +0,0 @@ -# Search - -## Overview - -An implementation of a search box for textual values as a form-connected web-component. - -### Use Cases - -Used anywhere an author might otherwise use: -- input[type="search"] - -### Features -- form association -- focus delegation - -### Risks and Challenges - -One challenge with search forms is their accessibility; a common design pattern is to not provide a label for the search box (although there might be a magnifying glass icon or similar), as the purpose of a search forms is normally obvious for sighted users due to placement. - -### Prior Art/Examples - -- [Fluent UI - React](https://developer.microsoft.com/en-us/fluentui#/controls/web/searchbox) -- [Material UI](https://material-ui.com/components/text-fields/) -- [Lightning Design](https://www.lightningdesignsystem.com/components/input/) -- [Ant Design](https://ant.design/components/input/) -- [Windows (UWP)](https://docs.microsoft.com/en-us/windows/apps/design/controls/auto-suggest-box) - ---- - -### API - -Extends FAST Element -lerna run prepare -*Component Name* -- `fast-search` - -*Attrs* - Adapted from [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/search) -- `autofocus` - automatically focuses the control -- `placeholder` - an exemplar value to display in the input field whenever it is empty -- `label` - `aria-label` for the input when a