@momentum-design/components 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +16 -0
- package/CONTRIBUTING.md +5 -0
- package/README.md +39 -0
- package/SCRIPTS.md +15 -0
- package/TESTING.md +38 -0
- package/config/api-extractor.json +33 -0
- package/config/custom-elements-manifest.config.js +28 -0
- package/config/esbuild/configs/browser.js +21 -0
- package/config/esbuild/configs/e2e.js +10 -0
- package/config/esbuild/esbuild-e2e.config.js +22 -0
- package/config/esbuild/esbuild.config.js +9 -0
- package/config/playwright/playwright.config.ts +107 -0
- package/config/playwright/public/index.css +43 -0
- package/config/playwright/public/index.html +26 -0
- package/config/playwright/setup/Components.page.ts +163 -0
- package/config/playwright/setup/constants.ts +27 -0
- package/config/playwright/setup/index.ts +42 -0
- package/config/playwright/setup/steps/accessibility.ts +9 -0
- package/config/playwright/setup/types.ts +5 -0
- package/config/playwright/setup/utils/accessibility.ts +70 -0
- package/config/playwright/setup/utils/visual-regression.ts +35 -0
- package/config/plop/actions/AddComponent.ts +21 -0
- package/config/plop/actions/AddToComponentExports.ts +16 -0
- package/config/plop/actions/AddToComponentImports.ts +16 -0
- package/config/plop/constants/index.ts +31 -0
- package/config/plop/esbuild.config.plop.js +4 -0
- package/config/plop/generators/component/index.ts +25 -0
- package/config/plop/plopfile.ts +6 -0
- package/config/plop/prompts/index.ts +8 -0
- package/config/plop/templates/add/component/index.ts.hbs +12 -0
- package/config/plop/templates/add/component/{{componentName}}.component.ts.hbs +22 -0
- package/config/plop/templates/add/component/{{componentName}}.constants.ts.hbs +5 -0
- package/config/plop/templates/add/component/{{componentName}}.e2e-test.ts.hbs +67 -0
- package/config/plop/templates/add/component/{{componentName}}.fixtures.ts.hbs +13 -0
- package/config/plop/templates/add/component/{{componentName}}.stories.ts.hbs +18 -0
- package/config/plop/templates/add/component/{{componentName}}.styles.ts.hbs +8 -0
- package/config/plop/tsconfig.plop.json +11 -0
- package/config/storybook/MomentumStorybookTheme.js +41 -0
- package/config/storybook/main.js +21 -0
- package/config/storybook/manager.js +17 -0
- package/config/storybook/preview.js +63 -0
- package/config/storybook/provider/iconProvider.js +8 -0
- package/config/storybook/provider/themeProvider.js +31 -0
- package/config/storybook/public/background-graphic.png +0 -0
- package/config/storybook/public/fonts/Inter.var.woff2 +0 -0
- package/config/storybook/public/momentum-logo.png +0 -0
- package/config/storybook/themes/index.js +14 -0
- package/config/storybook/themes/themes.css +15 -0
- package/data/custom-elements.json +677 -0
- package/dist/browser/index.js +366 -0
- package/dist/browser/index.js.map +7 -0
- package/dist/components/avatar/avatar.component.d.ts +28 -0
- package/dist/components/avatar/avatar.component.js +79 -0
- package/dist/components/avatar/avatar.constants.d.ts +7 -0
- package/dist/components/avatar/avatar.constants.js +14 -0
- package/dist/components/avatar/avatar.styles.d.ts +2 -0
- package/dist/components/avatar/avatar.styles.js +20 -0
- package/dist/components/avatar/avatar.types.d.ts +1 -0
- package/dist/components/avatar/avatar.types.js +2 -0
- package/dist/components/avatar/index.d.ts +7 -0
- package/dist/components/avatar/index.js +7 -0
- package/dist/components/badge/badge.component.d.ts +51 -0
- package/dist/components/badge/badge.component.js +114 -0
- package/dist/components/badge/badge.constants.d.ts +8 -0
- package/dist/components/badge/badge.constants.js +15 -0
- package/dist/components/badge/badge.styles.d.ts +2 -0
- package/dist/components/badge/badge.styles.js +26 -0
- package/dist/components/badge/badge.types.d.ts +1 -0
- package/dist/components/badge/badge.types.js +2 -0
- package/dist/components/badge/index.d.ts +7 -0
- package/dist/components/badge/index.js +7 -0
- package/dist/components/icon/icon.component.d.ts +63 -0
- package/dist/components/icon/icon.component.js +158 -0
- package/dist/components/icon/icon.constants.d.ts +6 -0
- package/dist/components/icon/icon.constants.js +12 -0
- package/dist/components/icon/icon.styles.d.ts +2 -0
- package/dist/components/icon/icon.styles.js +15 -0
- package/dist/components/icon/icon.utils.d.ts +2 -0
- package/dist/components/icon/icon.utils.js +13 -0
- package/dist/components/icon/index.d.ts +7 -0
- package/dist/components/icon/index.js +7 -0
- package/dist/components/iconprovider/iconprovider.component.d.ts +34 -0
- package/dist/components/iconprovider/iconprovider.component.js +71 -0
- package/dist/components/iconprovider/iconprovider.constants.d.ts +7 -0
- package/dist/components/iconprovider/iconprovider.constants.js +14 -0
- package/dist/components/iconprovider/iconprovider.context.d.ts +9 -0
- package/dist/components/iconprovider/iconprovider.context.js +9 -0
- package/dist/components/iconprovider/index.d.ts +7 -0
- package/dist/components/iconprovider/index.js +7 -0
- package/dist/components/text/fonts.styles.d.ts +1 -0
- package/dist/components/text/fonts.styles.js +100 -0
- package/dist/components/text/index.d.ts +7 -0
- package/dist/components/text/index.js +7 -0
- package/dist/components/text/text.component.d.ts +29 -0
- package/dist/components/text/text.component.js +41 -0
- package/dist/components/text/text.constants.d.ts +9 -0
- package/dist/components/text/text.constants.js +28 -0
- package/dist/components/text/text.styles.d.ts +2 -0
- package/dist/components/text/text.styles.js +17 -0
- package/dist/components/text/text.types.d.ts +1 -0
- package/dist/components/text/text.types.js +2 -0
- package/dist/components/text/text.utils.d.ts +20 -0
- package/dist/components/text/text.utils.js +50 -0
- package/dist/components/themeprovider/index.d.ts +7 -0
- package/dist/components/themeprovider/index.js +7 -0
- package/dist/components/themeprovider/themeprovider.component.d.ts +48 -0
- package/dist/components/themeprovider/themeprovider.component.js +86 -0
- package/dist/components/themeprovider/themeprovider.constants.d.ts +10 -0
- package/dist/components/themeprovider/themeprovider.constants.js +31 -0
- package/dist/components/themeprovider/themeprovider.context.d.ts +9 -0
- package/dist/components/themeprovider/themeprovider.context.js +13 -0
- package/dist/components/themeprovider/themeprovider.styles.d.ts +2 -0
- package/dist/components/themeprovider/themeprovider.styles.js +13 -0
- package/dist/components/themeprovider/themeprovider.types.d.ts +5 -0
- package/dist/components/themeprovider/themeprovider.types.js +2 -0
- package/dist/components/themeprovider/themeprovider.utils.d.ts +9 -0
- package/dist/components/themeprovider/themeprovider.utils.js +10 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +19 -0
- package/dist/models/component/component.component.d.ts +38 -0
- package/dist/models/component/component.component.js +45 -0
- package/dist/models/component/component.types.d.ts +15 -0
- package/dist/models/component/component.types.js +2 -0
- package/dist/models/component/index.d.ts +3 -0
- package/dist/models/component/index.js +5 -0
- package/dist/models/index.d.ts +4 -0
- package/dist/models/index.js +8 -0
- package/dist/models/provider/index.d.ts +2 -0
- package/dist/models/provider/index.js +5 -0
- package/dist/models/provider/provider.component.d.ts +70 -0
- package/dist/models/provider/provider.component.js +56 -0
- package/dist/models/provider/provider.styles.d.ts +2 -0
- package/dist/models/provider/provider.styles.js +14 -0
- package/dist/utils/provider/index.d.ts +13 -0
- package/dist/utils/provider/index.js +14 -0
- package/dist/utils/styles/index.d.ts +2 -0
- package/dist/utils/styles/index.js +14 -0
- package/dist/utils/tag-name/constants.d.ts +7 -0
- package/dist/utils/tag-name/constants.js +10 -0
- package/dist/utils/tag-name/index.d.ts +4 -0
- package/dist/utils/tag-name/index.js +10 -0
- package/dist/utils/types.d.ts +1 -0
- package/dist/utils/types.js +2 -0
- package/jest.config.js +3 -0
- package/package.json +78 -0
- package/scripts/copyFonts.js +31 -0
- package/scripts/copyIcons.js +31 -0
- package/scripts/copyTokens.js +24 -0
- package/src/components/avatar/__screenshots__/mdc-avatar.png +0 -0
- package/src/components/avatar/avatar.component.ts +74 -0
- package/src/components/avatar/avatar.constants.ts +12 -0
- package/src/components/avatar/avatar.e2e-test.ts +70 -0
- package/src/components/avatar/avatar.stories.ts +25 -0
- package/src/components/avatar/avatar.styles.ts +20 -0
- package/src/components/avatar/avatar.types.ts +1 -0
- package/src/components/avatar/index.ts +12 -0
- package/src/components/badge/__screenshots__/mdc-badge.png +0 -0
- package/src/components/badge/badge.component.ts +121 -0
- package/src/components/badge/badge.constants.ts +13 -0
- package/src/components/badge/badge.e2e-test.ts +68 -0
- package/src/components/badge/badge.stories.ts +33 -0
- package/src/components/badge/badge.styles.ts +26 -0
- package/src/components/badge/badge.types.ts +1 -0
- package/src/components/badge/index.ts +12 -0
- package/src/components/icon/__screenshots__/mdc-icon-default.png +0 -0
- package/src/components/icon/__screenshots__/mdc-icon-scale.png +0 -0
- package/src/components/icon/icon.component.ts +155 -0
- package/src/components/icon/icon.constants.ts +10 -0
- package/src/components/icon/icon.e2e-test.ts +101 -0
- package/src/components/icon/icon.stories.ts +34 -0
- package/src/components/icon/icon.styles.ts +15 -0
- package/src/components/icon/icon.utils.ts +13 -0
- package/src/components/icon/index.ts +12 -0
- package/src/components/iconprovider/__screenshots__/mdc-iconprovider.png +0 -0
- package/src/components/iconprovider/iconprovider.component.ts +76 -0
- package/src/components/iconprovider/iconprovider.constants.ts +12 -0
- package/src/components/iconprovider/iconprovider.context.ts +16 -0
- package/src/components/iconprovider/iconprovider.e2e-test.ts +65 -0
- package/src/components/iconprovider/iconprovider.stories.ts +27 -0
- package/src/components/iconprovider/iconprovider.stories.utils.ts +27 -0
- package/src/components/iconprovider/index.ts +12 -0
- package/src/components/text/__screenshots__/mdc-text-body-large.png +0 -0
- package/src/components/text/__screenshots__/mdc-text-body-regular.png +0 -0
- package/src/components/text/__screenshots__/mdc-text-body-small.png +0 -0
- package/src/components/text/__screenshots__/mdc-text-heading-1.png +0 -0
- package/src/components/text/__screenshots__/mdc-text-heading-2.png +0 -0
- package/src/components/text/__screenshots__/mdc-text-heading-3.png +0 -0
- package/src/components/text/__screenshots__/mdc-text-heading-4.png +0 -0
- package/src/components/text/__screenshots__/mdc-text-heading-5.png +0 -0
- package/src/components/text/__screenshots__/mdc-text-heading-6.png +0 -0
- package/src/components/text/__screenshots__/mdc-text-heading-7.png +0 -0
- package/src/components/text/__screenshots__/mdc-text-image-title.png +0 -0
- package/src/components/text/__screenshots__/mdc-text-label.png +0 -0
- package/src/components/text/fonts.styles.ts +99 -0
- package/src/components/text/index.ts +12 -0
- package/src/components/text/text.component.ts +51 -0
- package/src/components/text/text.constants.ts +27 -0
- package/src/components/text/text.e2e-test.ts +76 -0
- package/src/components/text/text.stories.ts +29 -0
- package/src/components/text/text.styles.ts +17 -0
- package/src/components/text/text.types.ts +13 -0
- package/src/components/text/text.utils.ts +51 -0
- package/src/components/themeprovider/__screenshots__/mdc-themeprovider-darkWebex.png +0 -0
- package/src/components/themeprovider/__screenshots__/mdc-themeprovider-lightWebex.png +0 -0
- package/src/components/themeprovider/index.ts +12 -0
- package/src/components/themeprovider/themeprovider.component.ts +91 -0
- package/src/components/themeprovider/themeprovider.constants.ts +32 -0
- package/src/components/themeprovider/themeprovider.context.ts +18 -0
- package/src/components/themeprovider/themeprovider.e2e-test.ts +89 -0
- package/src/components/themeprovider/themeprovider.stories.styles.css +22 -0
- package/src/components/themeprovider/themeprovider.stories.ts +38 -0
- package/src/components/themeprovider/themeprovider.stories.utils.ts +23 -0
- package/src/components/themeprovider/themeprovider.styles.ts +13 -0
- package/src/components/themeprovider/themeprovider.types.ts +7 -0
- package/src/components/themeprovider/themeprovider.utils.ts +16 -0
- package/src/index.ts +22 -0
- package/src/models/component/component.component.ts +46 -0
- package/src/models/component/component.types.ts +16 -0
- package/src/models/component/index.ts +7 -0
- package/src/models/index.ts +11 -0
- package/src/models/provider/index.ts +3 -0
- package/src/models/provider/provider.component.ts +87 -0
- package/src/models/provider/provider.styles.ts +14 -0
- package/src/stories/colors.mdx +32 -0
- package/src/stories/icons.mdx +13 -0
- package/src/stories/typography.mdx +20 -0
- package/src/utils/mixins/DisabledMixin.ts +19 -0
- package/src/utils/mixins/TabIndexMixin.ts +19 -0
- package/src/utils/provider/index.ts +21 -0
- package/src/utils/styles/index.ts +13 -0
- package/src/utils/tag-name/constants.ts +10 -0
- package/src/utils/tag-name/index.ts +15 -0
- package/src/utils/types.ts +1 -0
- package/tsconfig.json +45 -0
- package/tsconfig.module.json +47 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { html } from 'lit';
|
|
2
|
+
import { property, state } from 'lit/decorators.js';
|
|
3
|
+
import styles from './icon.styles';
|
|
4
|
+
import { Component } from '../../models';
|
|
5
|
+
import providerUtils from '../../utils/provider';
|
|
6
|
+
import IconProvider from '../iconprovider/iconprovider.component';
|
|
7
|
+
import { dynamicSVGImport } from './icon.utils';
|
|
8
|
+
import { DEFAULTS } from './icon.constants';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Icon component, which has to be mounted inside of a `IconProvider`
|
|
12
|
+
* component.
|
|
13
|
+
*
|
|
14
|
+
* The `IconProvider` component defines where icons should be consumed from (`url`).
|
|
15
|
+
* This `Icon` component accepts the `name` attribute, which will be
|
|
16
|
+
* the file name of the icon to be loaded from the given `url`.
|
|
17
|
+
*
|
|
18
|
+
* Once fetched, the icon will be mounted. If fetching wasn't successful,
|
|
19
|
+
* nothing will be shown.
|
|
20
|
+
*
|
|
21
|
+
* The `scale` attribute allows scaling the icon based on the provided
|
|
22
|
+
* `length-unit` attribute (which will either come from the IconProvider or
|
|
23
|
+
* could be overridden per icon). For example:
|
|
24
|
+
* if `scale = 1` and `length-unit = 'em'`, the size of the icon will be
|
|
25
|
+
* `width: 1em; height: 1em`.
|
|
26
|
+
*
|
|
27
|
+
* For accessibility the `role` and `aria-label` of the icon can be set.
|
|
28
|
+
*
|
|
29
|
+
* @tag mdc-icon
|
|
30
|
+
* @tagname mdc-icon
|
|
31
|
+
*/
|
|
32
|
+
class Icon extends Component {
|
|
33
|
+
@state()
|
|
34
|
+
private iconData?: HTMLElement;
|
|
35
|
+
|
|
36
|
+
@state()
|
|
37
|
+
private lengthUnitFromContext?: string;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Name of the icon (= filename)
|
|
41
|
+
*/
|
|
42
|
+
@property({ type: String, reflect: true })
|
|
43
|
+
name?: string = DEFAULTS.NAME;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Scale of the icon (works in combination with length unit)
|
|
47
|
+
*/
|
|
48
|
+
@property({ type: Number })
|
|
49
|
+
scale?: number = DEFAULTS.SCALE;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Length unit attribute for overridding length-unit from `IconProvider`
|
|
53
|
+
*/
|
|
54
|
+
@property({ type: String, attribute: 'length-unit' })
|
|
55
|
+
lengthUnit?: string;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Role attribute to be set for accessibility
|
|
59
|
+
*/
|
|
60
|
+
@property({ type: String })
|
|
61
|
+
override role: string | null = null;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Aria-label attribute to be set for accessibility
|
|
65
|
+
*/
|
|
66
|
+
@property({ type: String, attribute: 'aria-label' })
|
|
67
|
+
override ariaLabel: string | null = null;
|
|
68
|
+
|
|
69
|
+
private iconProviderContext = providerUtils.consume({ host: this, context: IconProvider.Context });
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Get Icon Data function which will fetch the icon (currently only svg)
|
|
73
|
+
* and sets state and attributes once fetched successfully
|
|
74
|
+
*/
|
|
75
|
+
private async getIconData() {
|
|
76
|
+
if (this.iconProviderContext.value) {
|
|
77
|
+
const { fileExtension, url } = this.iconProviderContext.value;
|
|
78
|
+
if (url && fileExtension && this.name) {
|
|
79
|
+
const iconHtml = await dynamicSVGImport(url, this.name, fileExtension);
|
|
80
|
+
|
|
81
|
+
// update iconData state once fetched:
|
|
82
|
+
this.iconData = iconHtml as HTMLElement;
|
|
83
|
+
|
|
84
|
+
// when icon got fetched, set role and aria-label:
|
|
85
|
+
this.setRoleOnIcon();
|
|
86
|
+
this.setAriaLabelOnIcon();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Updates the size by setting the width and height
|
|
93
|
+
*/
|
|
94
|
+
private updateSize() {
|
|
95
|
+
if (this.scale && (this.lengthUnit || this.lengthUnitFromContext)) {
|
|
96
|
+
const value = `${this.scale}${this.lengthUnit || this.lengthUnitFromContext}`;
|
|
97
|
+
this.style.width = value;
|
|
98
|
+
this.style.height = value;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
private setRoleOnIcon() {
|
|
103
|
+
if (this.role) {
|
|
104
|
+
// pass through role attribute to svg if set on mdc-icon
|
|
105
|
+
this.iconData?.setAttribute('role', this.role);
|
|
106
|
+
} else {
|
|
107
|
+
this.iconData?.removeAttribute('role');
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
private setAriaLabelOnIcon() {
|
|
112
|
+
if (this.ariaLabel) {
|
|
113
|
+
// pass through aria-label attribute to svg if set on mdc-icon
|
|
114
|
+
this.iconData?.setAttribute('aria-label', this.ariaLabel);
|
|
115
|
+
} else {
|
|
116
|
+
this.iconData?.removeAttribute('aria-label');
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
override updated(changedProperties: Map<string, any>) {
|
|
121
|
+
super.updated(changedProperties);
|
|
122
|
+
|
|
123
|
+
if (changedProperties.has('name')) {
|
|
124
|
+
// fetch icon data if name changes:
|
|
125
|
+
this.getIconData().catch((err) => {
|
|
126
|
+
console.error(err);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (changedProperties.has('role')) {
|
|
131
|
+
this.setRoleOnIcon();
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (changedProperties.has('ariaLabel')) {
|
|
135
|
+
this.setAriaLabelOnIcon();
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (changedProperties.has('scale') || changedProperties.has('lengthUnit')) {
|
|
139
|
+
this.updateSize();
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (this.lengthUnitFromContext !== this.iconProviderContext.value?.lengthUnit) {
|
|
143
|
+
this.lengthUnitFromContext = this.iconProviderContext.value?.lengthUnit;
|
|
144
|
+
this.updateSize();
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
override render() {
|
|
149
|
+
return html` ${this.iconData} `;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
static override styles = styles;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export default Icon;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { expect } from '@playwright/test';
|
|
2
|
+
import { ComponentsPage, test } from '../../../config/playwright/setup';
|
|
3
|
+
import steps from '../../../config/playwright/setup/steps/accessibility';
|
|
4
|
+
|
|
5
|
+
type SetupOptions = {
|
|
6
|
+
componentsPage: ComponentsPage;
|
|
7
|
+
name: string;
|
|
8
|
+
scale?: number;
|
|
9
|
+
role?: string;
|
|
10
|
+
ariaLabel?: string;
|
|
11
|
+
};
|
|
12
|
+
const setup = async (args: SetupOptions) => {
|
|
13
|
+
const { componentsPage, ...restArgs } = args;
|
|
14
|
+
await componentsPage.mount({
|
|
15
|
+
html: `
|
|
16
|
+
<mdc-icon
|
|
17
|
+
name="${restArgs.name}"
|
|
18
|
+
${restArgs.scale ? `scale="${restArgs.scale}"` : ''}
|
|
19
|
+
${restArgs.role ? `role="${restArgs.role}"` : ''}
|
|
20
|
+
${restArgs.ariaLabel ? `aria-label="${restArgs.ariaLabel}"` : ''}
|
|
21
|
+
>
|
|
22
|
+
</mdc-icon>
|
|
23
|
+
`,
|
|
24
|
+
clearDocument: true,
|
|
25
|
+
});
|
|
26
|
+
const icon = componentsPage.page.locator('mdc-icon');
|
|
27
|
+
await icon.waitFor();
|
|
28
|
+
return icon;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
test('mdc-icon', async ({ componentsPage }) => {
|
|
32
|
+
const name = 'accessibility-regular';
|
|
33
|
+
await setup({ componentsPage, name });
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* ACCESSIBILITY
|
|
37
|
+
*/
|
|
38
|
+
await test.step('accessibility with default props', async () => {
|
|
39
|
+
await steps.automaticA11yCheckStep(componentsPage);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const iconWithRole = await setup({
|
|
43
|
+
componentsPage,
|
|
44
|
+
name,
|
|
45
|
+
role: 'graphics-document',
|
|
46
|
+
ariaLabel: 'test aria label',
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
await test.step('accessibility with role / aria-label passed in', async () => {
|
|
50
|
+
await steps.automaticA11yCheckStep(componentsPage);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* VISUAL REGRESSION
|
|
55
|
+
*/
|
|
56
|
+
|
|
57
|
+
// TODO: fix visual regression test on CI
|
|
58
|
+
// await test.step('visual-regression', async () => {
|
|
59
|
+
// await test.step('matches screenshot of element with role / aria-label passed in', async () => {
|
|
60
|
+
// await componentsPage.visualRegression.takeScreenshot('mdc-icon-default', { element: iconWithRole });
|
|
61
|
+
// });
|
|
62
|
+
|
|
63
|
+
// await test.step('matches screenshot of element with scale set to 2', async () => {
|
|
64
|
+
// const iconScaled = await setup({
|
|
65
|
+
// componentsPage,
|
|
66
|
+
// name,
|
|
67
|
+
// scale: 2,
|
|
68
|
+
// });
|
|
69
|
+
// await componentsPage.visualRegression.takeScreenshot('mdc-icon-scale', { element: iconScaled });
|
|
70
|
+
// });
|
|
71
|
+
// });
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* ATTRIBUTES
|
|
75
|
+
*/
|
|
76
|
+
await test.step('attributes', async () => {
|
|
77
|
+
await test.step('attributes should be present on component by default', async () => {
|
|
78
|
+
const icon = await setup({ componentsPage, name });
|
|
79
|
+
await expect(icon).toHaveAttribute('name', name);
|
|
80
|
+
await expect(icon).toHaveAttribute('style', 'width: 1em; height: 1em;');
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
await test.step('attributes should be present on component with scale passed in', async () => {
|
|
84
|
+
const icon = await setup({ componentsPage, name, scale: 2 });
|
|
85
|
+
await expect(icon).toHaveAttribute('name', name);
|
|
86
|
+
await expect(icon).toHaveAttribute('scale', '2');
|
|
87
|
+
await expect(icon).toHaveAttribute('style', 'width: 2em; height: 2em;');
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
await test.step('attributes should be present on component with role / aria-label passed in', async () => {
|
|
91
|
+
const iconWithRole = await setup({
|
|
92
|
+
componentsPage,
|
|
93
|
+
name,
|
|
94
|
+
role: 'graphics-document',
|
|
95
|
+
ariaLabel: 'test aria label',
|
|
96
|
+
});
|
|
97
|
+
await expect(iconWithRole).toHaveAttribute('name', name);
|
|
98
|
+
await expect(iconWithRole).toHaveAttribute('style', 'width: 1em; height: 1em;');
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Meta, StoryObj, Args } from '@storybook/web-components';
|
|
2
|
+
import '.';
|
|
3
|
+
import { html } from 'lit';
|
|
4
|
+
|
|
5
|
+
const render = (args: Args) => html` <mdc-icon name="${args.name}" scale="${args.scale}"></mdc-icon> `;
|
|
6
|
+
const renderAccessibility = (args: Args) => html`
|
|
7
|
+
<mdc-icon name="${args.name}" scale="${args.scale}" role="${args.role}" aria-label="${args['aria-label']}"></mdc-icon>
|
|
8
|
+
`;
|
|
9
|
+
|
|
10
|
+
const meta: Meta = {
|
|
11
|
+
tags: ['autodocs'],
|
|
12
|
+
component: 'mdc-icon',
|
|
13
|
+
render,
|
|
14
|
+
argTypes: {},
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default meta;
|
|
18
|
+
|
|
19
|
+
export const Primary: StoryObj = {
|
|
20
|
+
args: {
|
|
21
|
+
name: 'accessibility-regular',
|
|
22
|
+
scale: 1,
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const Accessibility: StoryObj = {
|
|
27
|
+
render: renderAccessibility,
|
|
28
|
+
args: {
|
|
29
|
+
name: 'accessibility-regular',
|
|
30
|
+
scale: 1,
|
|
31
|
+
role: 'graphics-document',
|
|
32
|
+
'aria-label': 'This is the accessibility icon',
|
|
33
|
+
},
|
|
34
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/* eslint-disable implicit-arrow-linebreak */
|
|
2
|
+
|
|
3
|
+
const dynamicSVGImport = async (url: string, name: string, fileExtension: string): Promise<Element> =>
|
|
4
|
+
fetch(`${url}/${name}.${fileExtension}`)
|
|
5
|
+
.then((response) => {
|
|
6
|
+
if (!response.ok) {
|
|
7
|
+
throw new Error('There was a problem while fetching the icon!');
|
|
8
|
+
}
|
|
9
|
+
return response.text();
|
|
10
|
+
})
|
|
11
|
+
.then((iconResponse) => new DOMParser().parseFromString(iconResponse, 'text/html').body.children[0]);
|
|
12
|
+
|
|
13
|
+
export { dynamicSVGImport };
|
|
Binary file
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { property } from 'lit/decorators.js';
|
|
2
|
+
import { Provider } from '../../models';
|
|
3
|
+
import IconProviderContext from './iconprovider.context';
|
|
4
|
+
import { ALLOWED_FILE_EXTENSIONS, DEFAULTS } from './iconprovider.constants';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* IconProvider component, which allows to be consumed from sub components
|
|
8
|
+
* (see `providerUtils.consume` for how to consume)
|
|
9
|
+
*
|
|
10
|
+
* Bundling icons will be up to the consumer of this component, such
|
|
11
|
+
* that only a url has to be passed in from which the icons will be
|
|
12
|
+
* fetched.
|
|
13
|
+
*
|
|
14
|
+
* @tag mdc-iconprovider
|
|
15
|
+
* @tagname mdc-iconprovider
|
|
16
|
+
*/
|
|
17
|
+
class IconProvider extends Provider<IconProviderContext> {
|
|
18
|
+
constructor() {
|
|
19
|
+
// initialise the context by running the Provider constructor:
|
|
20
|
+
super({
|
|
21
|
+
context: IconProviderContext.context,
|
|
22
|
+
initialValue: new IconProviderContext(),
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public static get Context() {
|
|
27
|
+
return IconProviderContext.context;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Url of where icons will be fetched from
|
|
32
|
+
*/
|
|
33
|
+
@property({ type: String })
|
|
34
|
+
url?: string;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* File extension of icons, default: 'svg'
|
|
38
|
+
*/
|
|
39
|
+
@property({ type: String, attribute: 'file-extension', reflect: true })
|
|
40
|
+
fileExtension?: string = DEFAULTS.FILE_EXTENSION;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Length unit used for sizing of icons, default: 'em'
|
|
44
|
+
*/
|
|
45
|
+
@property({ type: String, attribute: 'length-unit', reflect: true })
|
|
46
|
+
lengthUnit?: string = DEFAULTS.LENGTH_UNIT;
|
|
47
|
+
|
|
48
|
+
private updateValuesInContext() {
|
|
49
|
+
// only update fileExtension on context if its an allowed fileExtension
|
|
50
|
+
if (this.fileExtension && ALLOWED_FILE_EXTENSIONS.includes(this.fileExtension)) {
|
|
51
|
+
this.context.value.fileExtension = this.fileExtension;
|
|
52
|
+
}
|
|
53
|
+
this.context.value.url = this.url;
|
|
54
|
+
this.context.value.lengthUnit = this.lengthUnit;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
protected updateContext(): void {
|
|
58
|
+
let shouldUpdateConsumers = false;
|
|
59
|
+
|
|
60
|
+
if (
|
|
61
|
+
this.context.value.fileExtension !== this.fileExtension
|
|
62
|
+
|| this.context.value.url !== this.url
|
|
63
|
+
|| this.context.value.lengthUnit !== this.lengthUnit
|
|
64
|
+
) {
|
|
65
|
+
this.updateValuesInContext();
|
|
66
|
+
|
|
67
|
+
shouldUpdateConsumers = true;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (shouldUpdateConsumers) {
|
|
71
|
+
this.context.updateObservers();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export default IconProvider;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import utils from '../../utils/tag-name';
|
|
2
|
+
|
|
3
|
+
const TAG_NAME = utils.constructTagName('iconprovider');
|
|
4
|
+
|
|
5
|
+
const ALLOWED_FILE_EXTENSIONS = ['svg'];
|
|
6
|
+
|
|
7
|
+
const DEFAULTS = {
|
|
8
|
+
FILE_EXTENSION: 'svg',
|
|
9
|
+
LENGTH_UNIT: 'em',
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export { TAG_NAME, DEFAULTS, ALLOWED_FILE_EXTENSIONS };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createContext } from '@lit-labs/context';
|
|
2
|
+
|
|
3
|
+
import { TAG_NAME } from './iconprovider.constants';
|
|
4
|
+
|
|
5
|
+
class IconProviderContext {
|
|
6
|
+
public fileExtension?: string;
|
|
7
|
+
|
|
8
|
+
public url?: string;
|
|
9
|
+
|
|
10
|
+
public lengthUnit?: string;
|
|
11
|
+
|
|
12
|
+
// create typed lit context as part of the IconProviderContext
|
|
13
|
+
public static context = createContext<IconProviderContext>(TAG_NAME);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export default IconProviderContext;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { expect } from '@playwright/test';
|
|
2
|
+
import { ComponentsPage, test } from '../../../config/playwright/setup';
|
|
3
|
+
import steps from '../../../config/playwright/setup/steps/accessibility';
|
|
4
|
+
import { DEFAULTS } from './iconprovider.constants';
|
|
5
|
+
|
|
6
|
+
type SetupOptions = {
|
|
7
|
+
componentsPage: ComponentsPage;
|
|
8
|
+
url: string;
|
|
9
|
+
fileExtension?: string;
|
|
10
|
+
lengthUnit?: string;
|
|
11
|
+
};
|
|
12
|
+
const setup = async (args: SetupOptions) => {
|
|
13
|
+
const { componentsPage, ...restArgs } = args;
|
|
14
|
+
await componentsPage.mount({
|
|
15
|
+
html: `
|
|
16
|
+
<mdc-iconprovider
|
|
17
|
+
url="${restArgs.url}"
|
|
18
|
+
id="local"
|
|
19
|
+
${restArgs.fileExtension ? `file-extension="${restArgs.fileExtension}"` : ''}
|
|
20
|
+
${restArgs.lengthUnit ? `length-unit="${restArgs.lengthUnit}"` : ''}
|
|
21
|
+
>
|
|
22
|
+
<mdc-icon name="accessibility-regular" scale="2"></mdc-icon>
|
|
23
|
+
</mdc-iconprovider>
|
|
24
|
+
`,
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
test('mdc-iconprovider', async ({ componentsPage }) => {
|
|
29
|
+
const url = '/dist/icons/svg';
|
|
30
|
+
await setup({ componentsPage, url });
|
|
31
|
+
const iconprovider = componentsPage.page.locator('mdc-iconprovider#local');
|
|
32
|
+
|
|
33
|
+
// initial check for the iconprovider be visible on the screen:
|
|
34
|
+
await iconprovider.waitFor();
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* ACCESSIBILITY
|
|
38
|
+
*/
|
|
39
|
+
await test.step('accessibility', async () => {
|
|
40
|
+
await steps.automaticA11yCheckStep(componentsPage);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* VISUAL REGRESSION
|
|
45
|
+
*/
|
|
46
|
+
// TODO: fix visual regression test on CI
|
|
47
|
+
// await test.step('visual-regression', async () => {
|
|
48
|
+
// await test.step('matches screenshot of element with default values', async () => {
|
|
49
|
+
// await componentsPage.visualRegression.takeScreenshot('mdc-iconprovider', {
|
|
50
|
+
// element: iconprovider,
|
|
51
|
+
// });
|
|
52
|
+
// });
|
|
53
|
+
// });
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* ATTRIBUTES
|
|
57
|
+
*/
|
|
58
|
+
await test.step('attributes', async () => {
|
|
59
|
+
await test.step('attribute X should be present on component by default', async () => {
|
|
60
|
+
await expect(iconprovider).toHaveAttribute('url', url);
|
|
61
|
+
await expect(iconprovider).toHaveAttribute('file-extension', DEFAULTS.FILE_EXTENSION);
|
|
62
|
+
await expect(iconprovider).toHaveAttribute('length-unit', DEFAULTS.LENGTH_UNIT);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Meta, StoryObj, Args } from '@storybook/web-components';
|
|
2
|
+
import '.';
|
|
3
|
+
import './iconprovider.stories.utils';
|
|
4
|
+
import { html } from 'lit';
|
|
5
|
+
|
|
6
|
+
const render = (args: Args) => html`
|
|
7
|
+
<mdc-iconprovider url="${args.url}" file-extension="${args.fileExtension}" length-unit="${args.lengthUnit}">
|
|
8
|
+
<mdc-subcomponent-icon></mdc-subcomponent-icon>
|
|
9
|
+
</mdc-iconprovider>
|
|
10
|
+
`;
|
|
11
|
+
|
|
12
|
+
const meta: Meta = {
|
|
13
|
+
tags: ['autodocs'],
|
|
14
|
+
component: 'mdc-iconprovider',
|
|
15
|
+
render,
|
|
16
|
+
argTypes: {},
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export default meta;
|
|
20
|
+
|
|
21
|
+
export const Primary: StoryObj = {
|
|
22
|
+
args: {
|
|
23
|
+
url: '/test',
|
|
24
|
+
fileExtension: 'svg',
|
|
25
|
+
lengthUnit: 'em',
|
|
26
|
+
},
|
|
27
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { html } from 'lit';
|
|
2
|
+
import { Component } from '../../models';
|
|
3
|
+
import IconProvider from './iconprovider.component';
|
|
4
|
+
import providerUtils from '../../utils/provider';
|
|
5
|
+
|
|
6
|
+
// Subcomponent to be rendered in storybook, to showcase that the
|
|
7
|
+
// theme can be consumed as a subcomponent
|
|
8
|
+
class SubComponentIconProvider extends Component {
|
|
9
|
+
currentTheme?: string;
|
|
10
|
+
|
|
11
|
+
private iconProviderContext = providerUtils.consume({ host: this, context: IconProvider.Context });
|
|
12
|
+
|
|
13
|
+
override render() {
|
|
14
|
+
return html`
|
|
15
|
+
<p>URL: ${this.iconProviderContext.value?.url}</p>
|
|
16
|
+
<p>File Extension: ${this.iconProviderContext.value?.fileExtension}</p>
|
|
17
|
+
<p>Length Unit: ${this.iconProviderContext.value?.lengthUnit}</p>
|
|
18
|
+
`;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
SubComponentIconProvider.register('mdc-subcomponent-icon');
|
|
23
|
+
declare global {
|
|
24
|
+
interface HTMLElementTagNameMap {
|
|
25
|
+
['mdc-subcomponent-icon']: SubComponentIconProvider;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import IconProvider from './iconprovider.component';
|
|
2
|
+
import { TAG_NAME } from './iconprovider.constants';
|
|
3
|
+
|
|
4
|
+
IconProvider.register(TAG_NAME);
|
|
5
|
+
|
|
6
|
+
export default IconProvider;
|
|
7
|
+
|
|
8
|
+
declare global {
|
|
9
|
+
interface HTMLElementTagNameMap {
|
|
10
|
+
['mdc-iconprovider']: IconProvider
|
|
11
|
+
}
|
|
12
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|