@momentum-design/components 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (235) hide show
  1. package/.eslintrc.js +16 -0
  2. package/CONTRIBUTING.md +5 -0
  3. package/README.md +39 -0
  4. package/SCRIPTS.md +15 -0
  5. package/TESTING.md +38 -0
  6. package/config/api-extractor.json +33 -0
  7. package/config/custom-elements-manifest.config.js +28 -0
  8. package/config/esbuild/configs/browser.js +21 -0
  9. package/config/esbuild/configs/e2e.js +10 -0
  10. package/config/esbuild/esbuild-e2e.config.js +22 -0
  11. package/config/esbuild/esbuild.config.js +9 -0
  12. package/config/playwright/playwright.config.ts +107 -0
  13. package/config/playwright/public/index.css +43 -0
  14. package/config/playwright/public/index.html +26 -0
  15. package/config/playwright/setup/Components.page.ts +163 -0
  16. package/config/playwright/setup/constants.ts +27 -0
  17. package/config/playwright/setup/index.ts +42 -0
  18. package/config/playwright/setup/steps/accessibility.ts +9 -0
  19. package/config/playwright/setup/types.ts +5 -0
  20. package/config/playwright/setup/utils/accessibility.ts +70 -0
  21. package/config/playwright/setup/utils/visual-regression.ts +35 -0
  22. package/config/plop/actions/AddComponent.ts +21 -0
  23. package/config/plop/actions/AddToComponentExports.ts +16 -0
  24. package/config/plop/actions/AddToComponentImports.ts +16 -0
  25. package/config/plop/constants/index.ts +31 -0
  26. package/config/plop/esbuild.config.plop.js +4 -0
  27. package/config/plop/generators/component/index.ts +25 -0
  28. package/config/plop/plopfile.ts +6 -0
  29. package/config/plop/prompts/index.ts +8 -0
  30. package/config/plop/templates/add/component/index.ts.hbs +12 -0
  31. package/config/plop/templates/add/component/{{componentName}}.component.ts.hbs +22 -0
  32. package/config/plop/templates/add/component/{{componentName}}.constants.ts.hbs +5 -0
  33. package/config/plop/templates/add/component/{{componentName}}.e2e-test.ts.hbs +67 -0
  34. package/config/plop/templates/add/component/{{componentName}}.fixtures.ts.hbs +13 -0
  35. package/config/plop/templates/add/component/{{componentName}}.stories.ts.hbs +18 -0
  36. package/config/plop/templates/add/component/{{componentName}}.styles.ts.hbs +8 -0
  37. package/config/plop/tsconfig.plop.json +11 -0
  38. package/config/storybook/MomentumStorybookTheme.js +41 -0
  39. package/config/storybook/main.js +21 -0
  40. package/config/storybook/manager.js +17 -0
  41. package/config/storybook/preview.js +63 -0
  42. package/config/storybook/provider/iconProvider.js +8 -0
  43. package/config/storybook/provider/themeProvider.js +31 -0
  44. package/config/storybook/public/background-graphic.png +0 -0
  45. package/config/storybook/public/fonts/Inter.var.woff2 +0 -0
  46. package/config/storybook/public/momentum-logo.png +0 -0
  47. package/config/storybook/themes/index.js +14 -0
  48. package/config/storybook/themes/themes.css +15 -0
  49. package/data/custom-elements.json +677 -0
  50. package/dist/browser/index.js +366 -0
  51. package/dist/browser/index.js.map +7 -0
  52. package/dist/components/avatar/avatar.component.d.ts +28 -0
  53. package/dist/components/avatar/avatar.component.js +79 -0
  54. package/dist/components/avatar/avatar.constants.d.ts +7 -0
  55. package/dist/components/avatar/avatar.constants.js +14 -0
  56. package/dist/components/avatar/avatar.styles.d.ts +2 -0
  57. package/dist/components/avatar/avatar.styles.js +20 -0
  58. package/dist/components/avatar/avatar.types.d.ts +1 -0
  59. package/dist/components/avatar/avatar.types.js +2 -0
  60. package/dist/components/avatar/index.d.ts +7 -0
  61. package/dist/components/avatar/index.js +7 -0
  62. package/dist/components/badge/badge.component.d.ts +51 -0
  63. package/dist/components/badge/badge.component.js +114 -0
  64. package/dist/components/badge/badge.constants.d.ts +8 -0
  65. package/dist/components/badge/badge.constants.js +15 -0
  66. package/dist/components/badge/badge.styles.d.ts +2 -0
  67. package/dist/components/badge/badge.styles.js +26 -0
  68. package/dist/components/badge/badge.types.d.ts +1 -0
  69. package/dist/components/badge/badge.types.js +2 -0
  70. package/dist/components/badge/index.d.ts +7 -0
  71. package/dist/components/badge/index.js +7 -0
  72. package/dist/components/icon/icon.component.d.ts +63 -0
  73. package/dist/components/icon/icon.component.js +158 -0
  74. package/dist/components/icon/icon.constants.d.ts +6 -0
  75. package/dist/components/icon/icon.constants.js +12 -0
  76. package/dist/components/icon/icon.styles.d.ts +2 -0
  77. package/dist/components/icon/icon.styles.js +15 -0
  78. package/dist/components/icon/icon.utils.d.ts +2 -0
  79. package/dist/components/icon/icon.utils.js +13 -0
  80. package/dist/components/icon/index.d.ts +7 -0
  81. package/dist/components/icon/index.js +7 -0
  82. package/dist/components/iconprovider/iconprovider.component.d.ts +34 -0
  83. package/dist/components/iconprovider/iconprovider.component.js +71 -0
  84. package/dist/components/iconprovider/iconprovider.constants.d.ts +7 -0
  85. package/dist/components/iconprovider/iconprovider.constants.js +14 -0
  86. package/dist/components/iconprovider/iconprovider.context.d.ts +9 -0
  87. package/dist/components/iconprovider/iconprovider.context.js +9 -0
  88. package/dist/components/iconprovider/index.d.ts +7 -0
  89. package/dist/components/iconprovider/index.js +7 -0
  90. package/dist/components/text/fonts.styles.d.ts +1 -0
  91. package/dist/components/text/fonts.styles.js +100 -0
  92. package/dist/components/text/index.d.ts +7 -0
  93. package/dist/components/text/index.js +7 -0
  94. package/dist/components/text/text.component.d.ts +29 -0
  95. package/dist/components/text/text.component.js +41 -0
  96. package/dist/components/text/text.constants.d.ts +9 -0
  97. package/dist/components/text/text.constants.js +28 -0
  98. package/dist/components/text/text.styles.d.ts +2 -0
  99. package/dist/components/text/text.styles.js +17 -0
  100. package/dist/components/text/text.types.d.ts +1 -0
  101. package/dist/components/text/text.types.js +2 -0
  102. package/dist/components/text/text.utils.d.ts +20 -0
  103. package/dist/components/text/text.utils.js +50 -0
  104. package/dist/components/themeprovider/index.d.ts +7 -0
  105. package/dist/components/themeprovider/index.js +7 -0
  106. package/dist/components/themeprovider/themeprovider.component.d.ts +48 -0
  107. package/dist/components/themeprovider/themeprovider.component.js +86 -0
  108. package/dist/components/themeprovider/themeprovider.constants.d.ts +10 -0
  109. package/dist/components/themeprovider/themeprovider.constants.js +31 -0
  110. package/dist/components/themeprovider/themeprovider.context.d.ts +9 -0
  111. package/dist/components/themeprovider/themeprovider.context.js +13 -0
  112. package/dist/components/themeprovider/themeprovider.styles.d.ts +2 -0
  113. package/dist/components/themeprovider/themeprovider.styles.js +13 -0
  114. package/dist/components/themeprovider/themeprovider.types.d.ts +5 -0
  115. package/dist/components/themeprovider/themeprovider.types.js +2 -0
  116. package/dist/components/themeprovider/themeprovider.utils.d.ts +9 -0
  117. package/dist/components/themeprovider/themeprovider.utils.js +10 -0
  118. package/dist/index.d.ts +8 -0
  119. package/dist/index.js +19 -0
  120. package/dist/models/component/component.component.d.ts +38 -0
  121. package/dist/models/component/component.component.js +45 -0
  122. package/dist/models/component/component.types.d.ts +15 -0
  123. package/dist/models/component/component.types.js +2 -0
  124. package/dist/models/component/index.d.ts +3 -0
  125. package/dist/models/component/index.js +5 -0
  126. package/dist/models/index.d.ts +4 -0
  127. package/dist/models/index.js +8 -0
  128. package/dist/models/provider/index.d.ts +2 -0
  129. package/dist/models/provider/index.js +5 -0
  130. package/dist/models/provider/provider.component.d.ts +70 -0
  131. package/dist/models/provider/provider.component.js +56 -0
  132. package/dist/models/provider/provider.styles.d.ts +2 -0
  133. package/dist/models/provider/provider.styles.js +14 -0
  134. package/dist/utils/provider/index.d.ts +13 -0
  135. package/dist/utils/provider/index.js +14 -0
  136. package/dist/utils/styles/index.d.ts +2 -0
  137. package/dist/utils/styles/index.js +14 -0
  138. package/dist/utils/tag-name/constants.d.ts +7 -0
  139. package/dist/utils/tag-name/constants.js +10 -0
  140. package/dist/utils/tag-name/index.d.ts +4 -0
  141. package/dist/utils/tag-name/index.js +10 -0
  142. package/dist/utils/types.d.ts +1 -0
  143. package/dist/utils/types.js +2 -0
  144. package/jest.config.js +3 -0
  145. package/package.json +78 -0
  146. package/scripts/copyFonts.js +31 -0
  147. package/scripts/copyIcons.js +31 -0
  148. package/scripts/copyTokens.js +24 -0
  149. package/src/components/avatar/__screenshots__/mdc-avatar.png +0 -0
  150. package/src/components/avatar/avatar.component.ts +74 -0
  151. package/src/components/avatar/avatar.constants.ts +12 -0
  152. package/src/components/avatar/avatar.e2e-test.ts +70 -0
  153. package/src/components/avatar/avatar.stories.ts +25 -0
  154. package/src/components/avatar/avatar.styles.ts +20 -0
  155. package/src/components/avatar/avatar.types.ts +1 -0
  156. package/src/components/avatar/index.ts +12 -0
  157. package/src/components/badge/__screenshots__/mdc-badge.png +0 -0
  158. package/src/components/badge/badge.component.ts +121 -0
  159. package/src/components/badge/badge.constants.ts +13 -0
  160. package/src/components/badge/badge.e2e-test.ts +68 -0
  161. package/src/components/badge/badge.stories.ts +33 -0
  162. package/src/components/badge/badge.styles.ts +26 -0
  163. package/src/components/badge/badge.types.ts +1 -0
  164. package/src/components/badge/index.ts +12 -0
  165. package/src/components/icon/__screenshots__/mdc-icon-default.png +0 -0
  166. package/src/components/icon/__screenshots__/mdc-icon-scale.png +0 -0
  167. package/src/components/icon/icon.component.ts +155 -0
  168. package/src/components/icon/icon.constants.ts +10 -0
  169. package/src/components/icon/icon.e2e-test.ts +101 -0
  170. package/src/components/icon/icon.stories.ts +34 -0
  171. package/src/components/icon/icon.styles.ts +15 -0
  172. package/src/components/icon/icon.utils.ts +13 -0
  173. package/src/components/icon/index.ts +12 -0
  174. package/src/components/iconprovider/__screenshots__/mdc-iconprovider.png +0 -0
  175. package/src/components/iconprovider/iconprovider.component.ts +76 -0
  176. package/src/components/iconprovider/iconprovider.constants.ts +12 -0
  177. package/src/components/iconprovider/iconprovider.context.ts +16 -0
  178. package/src/components/iconprovider/iconprovider.e2e-test.ts +65 -0
  179. package/src/components/iconprovider/iconprovider.stories.ts +27 -0
  180. package/src/components/iconprovider/iconprovider.stories.utils.ts +27 -0
  181. package/src/components/iconprovider/index.ts +12 -0
  182. package/src/components/text/__screenshots__/mdc-text-body-large.png +0 -0
  183. package/src/components/text/__screenshots__/mdc-text-body-regular.png +0 -0
  184. package/src/components/text/__screenshots__/mdc-text-body-small.png +0 -0
  185. package/src/components/text/__screenshots__/mdc-text-heading-1.png +0 -0
  186. package/src/components/text/__screenshots__/mdc-text-heading-2.png +0 -0
  187. package/src/components/text/__screenshots__/mdc-text-heading-3.png +0 -0
  188. package/src/components/text/__screenshots__/mdc-text-heading-4.png +0 -0
  189. package/src/components/text/__screenshots__/mdc-text-heading-5.png +0 -0
  190. package/src/components/text/__screenshots__/mdc-text-heading-6.png +0 -0
  191. package/src/components/text/__screenshots__/mdc-text-heading-7.png +0 -0
  192. package/src/components/text/__screenshots__/mdc-text-image-title.png +0 -0
  193. package/src/components/text/__screenshots__/mdc-text-label.png +0 -0
  194. package/src/components/text/fonts.styles.ts +99 -0
  195. package/src/components/text/index.ts +12 -0
  196. package/src/components/text/text.component.ts +51 -0
  197. package/src/components/text/text.constants.ts +27 -0
  198. package/src/components/text/text.e2e-test.ts +76 -0
  199. package/src/components/text/text.stories.ts +29 -0
  200. package/src/components/text/text.styles.ts +17 -0
  201. package/src/components/text/text.types.ts +13 -0
  202. package/src/components/text/text.utils.ts +51 -0
  203. package/src/components/themeprovider/__screenshots__/mdc-themeprovider-darkWebex.png +0 -0
  204. package/src/components/themeprovider/__screenshots__/mdc-themeprovider-lightWebex.png +0 -0
  205. package/src/components/themeprovider/index.ts +12 -0
  206. package/src/components/themeprovider/themeprovider.component.ts +91 -0
  207. package/src/components/themeprovider/themeprovider.constants.ts +32 -0
  208. package/src/components/themeprovider/themeprovider.context.ts +18 -0
  209. package/src/components/themeprovider/themeprovider.e2e-test.ts +89 -0
  210. package/src/components/themeprovider/themeprovider.stories.styles.css +22 -0
  211. package/src/components/themeprovider/themeprovider.stories.ts +38 -0
  212. package/src/components/themeprovider/themeprovider.stories.utils.ts +23 -0
  213. package/src/components/themeprovider/themeprovider.styles.ts +13 -0
  214. package/src/components/themeprovider/themeprovider.types.ts +7 -0
  215. package/src/components/themeprovider/themeprovider.utils.ts +16 -0
  216. package/src/index.ts +22 -0
  217. package/src/models/component/component.component.ts +46 -0
  218. package/src/models/component/component.types.ts +16 -0
  219. package/src/models/component/index.ts +7 -0
  220. package/src/models/index.ts +11 -0
  221. package/src/models/provider/index.ts +3 -0
  222. package/src/models/provider/provider.component.ts +87 -0
  223. package/src/models/provider/provider.styles.ts +14 -0
  224. package/src/stories/colors.mdx +32 -0
  225. package/src/stories/icons.mdx +13 -0
  226. package/src/stories/typography.mdx +20 -0
  227. package/src/utils/mixins/DisabledMixin.ts +19 -0
  228. package/src/utils/mixins/TabIndexMixin.ts +19 -0
  229. package/src/utils/provider/index.ts +21 -0
  230. package/src/utils/styles/index.ts +13 -0
  231. package/src/utils/tag-name/constants.ts +10 -0
  232. package/src/utils/tag-name/index.ts +15 -0
  233. package/src/utils/types.ts +1 -0
  234. package/tsconfig.json +45 -0
  235. package/tsconfig.module.json +47 -0
@@ -0,0 +1,70 @@
1
+ /* eslint-disable no-restricted-syntax */
2
+ /* eslint-disable no-await-in-loop */
3
+ import { Locator, Page, expect, TestInfo } from '@playwright/test';
4
+ import AxeBuilder from '@axe-core/playwright';
5
+ import CONSTANTS from '../constants';
6
+
7
+ interface Accessibility {
8
+ page: Page;
9
+ testInfo: TestInfo;
10
+ }
11
+
12
+ /**
13
+ * Contains common `accessibility` utils, which are useful when doing accessibility tests
14
+ */
15
+ class Accessibility {
16
+ constructor(page: Page, testInfo: TestInfo) {
17
+ this.page = page;
18
+ this.testInfo = testInfo;
19
+ }
20
+
21
+ /**
22
+ * Attaches the provided scan results as JSON
23
+ * to the test report
24
+ * @param accessibilityScanResults
25
+ */
26
+ async attachA11yResults(accessibilityScanResults: any) {
27
+ await this.testInfo.attach('accessibility-scan-results', {
28
+ body: JSON.stringify(accessibilityScanResults, null, 2),
29
+ contentType: 'application/json',
30
+ });
31
+ }
32
+
33
+ /**
34
+ * Checks for Accessibility violations by scanning the whole
35
+ * page with axe-core, using the specific accessibility WCAG tags to check
36
+ * and disabled rules. The results will be attached as a JSON file
37
+ * to the test report afterwards.
38
+ *
39
+ * This function will fail if there are any accessibility violations.
40
+ */
41
+ async checkForA11yViolations() {
42
+ const accessibilityScanResults = await new AxeBuilder({ page: this.page })
43
+ .withTags(CONSTANTS.ACCESSIBILITY.WCAG_TAGS_TO_CHECK)
44
+ .disableRules(CONSTANTS.ACCESSIBILITY.RULES_TO_DISABLE)
45
+ .analyze();
46
+
47
+ await this.attachA11yResults(accessibilityScanResults);
48
+
49
+ expect(accessibilityScanResults.violations).toEqual([]);
50
+ }
51
+
52
+ /**
53
+ * pressAndCheckFocus utility function - it will press the provided `keyToPress` as often
54
+ * as the provided `elementsToBeFocused` are and checks afterwards, if the provided element of the
55
+ * `elementsToBeFocused` has been focused.
56
+ *
57
+ * If only 1 keyPress needs to be done, just simply provide the `elementsToBeFocused` array with
58
+ * 1 element, which should receive focus.
59
+ * @param keyToPress key which should be pressed
60
+ * @param elementsToBeFocused array of elements, which have to be focused after pressing a key
61
+ */
62
+ async pressAndCheckFocus(keyToPress: string, elementsToBeFocused: Array<Locator>) {
63
+ for (const elementToBeFocused of elementsToBeFocused) {
64
+ await this.page.keyboard.press(keyToPress);
65
+ await expect(elementToBeFocused).toBeFocused();
66
+ }
67
+ }
68
+ }
69
+
70
+ export default Accessibility;
@@ -0,0 +1,35 @@
1
+ import { Page, expect } from '@playwright/test';
2
+ import type { ScreenShotOptions } from '../types';
3
+ import CONSTANTS from '../constants';
4
+
5
+ interface VisualRegression {
6
+ page: Page;
7
+ }
8
+
9
+ /**
10
+ * Contains common `visual-regression` utils, which are useful when doing visual-regression tests
11
+ */
12
+ class VisualRegression {
13
+ constructor(page: Page) {
14
+ this.page = page;
15
+ }
16
+
17
+ /**
18
+ * Takes a screenshot of the whole page, with the passed in options
19
+ *
20
+ * @param name - name of the screenshot, file extension will be appended automatically!
21
+ * @param options - description
22
+ * @param options.element - element to take screenshot from
23
+ */
24
+ async takeScreenshot(name: string, options?: ScreenShotOptions): Promise<void> {
25
+ const elementToTakeScreenShotFrom = options?.element || this.page;
26
+
27
+ expect(await elementToTakeScreenShotFrom.screenshot(options)).toMatchSnapshot({
28
+ name: `${name}.${CONSTANTS.VISUAL_REGRESSION.FILE_EXTENSION}`,
29
+ threshold: CONSTANTS.VISUAL_REGRESSION.THRESHOLD,
30
+ maxDiffPixelRatio: CONSTANTS.VISUAL_REGRESSION.MAX_DIFF_PIXELS_RATIO,
31
+ });
32
+ }
33
+ }
34
+
35
+ export default VisualRegression;
@@ -0,0 +1,21 @@
1
+ import { join } from 'path';
2
+ import { ActionType } from 'plop';
3
+ import { folders, ACTION, TYPE, componentName, componentNamePrefix, componentNameSeparator } from '../constants';
4
+
5
+ const base = `${join(`${folders.templates}`, `${ACTION.ADD}`, `${TYPE.COMPONENT}`)}`;
6
+
7
+ export const AddComponent: ActionType = {
8
+ type: 'addMany',
9
+ base,
10
+ templateFiles: `${join(`${base}`, '**')}`,
11
+ destination: `${join(`${folders.components}`, `{{${componentName}}}`)}`,
12
+ data: {
13
+ componentName,
14
+ prefix: componentNamePrefix,
15
+ separator: componentNameSeparator,
16
+ },
17
+ globOptions: {
18
+ // allow hidden files to be copied as well:
19
+ dot: false,
20
+ },
21
+ };
@@ -0,0 +1,16 @@
1
+ /* eslint-disable max-len */
2
+ import { join } from 'path';
3
+ import { ActionType } from 'plop';
4
+ import { folders, componentName, componentNamePrefix } from '../constants';
5
+
6
+ export const AddToComponentExports: ActionType = {
7
+ type: 'modify',
8
+ path: `${join(`${folders.src}`, 'index.ts')}`,
9
+ pattern: /(};)/g,
10
+ data: {
11
+ componentName,
12
+ prefix: componentNamePrefix,
13
+ },
14
+ template:
15
+ ` {{sentenceCase prefix}}{{sentenceCase ${componentName}}},\n$1`,
16
+ };
@@ -0,0 +1,16 @@
1
+ /* eslint-disable max-len */
2
+ import { join } from 'path';
3
+ import { ActionType } from 'plop';
4
+ import { folders, componentName, componentNamePrefix } from '../constants';
5
+
6
+ export const AddToComponentImports: ActionType = {
7
+ type: 'modify',
8
+ path: `${join(`${folders.src}`, 'index.ts')}`,
9
+ pattern: /(\nexport)/g,
10
+ data: {
11
+ componentName,
12
+ prefix: componentNamePrefix,
13
+ },
14
+ template:
15
+ `import {{sentenceCase prefix}}{{sentenceCase ${componentName}}} from './components/{{${componentName}}}';\n$1`,
16
+ };
@@ -0,0 +1,31 @@
1
+ import { join } from 'path';
2
+ import CONSTANTS from '../../../src/utils/tag-name/constants';
3
+
4
+ export enum PROMPT_TYPE {
5
+ INPUT = 'input',
6
+ }
7
+
8
+ export enum GENERATOR_NAME {
9
+ COMPONENT_GENERATOR = 'component'
10
+ }
11
+
12
+ export enum ACTION {
13
+ ADD = 'add',
14
+ }
15
+
16
+ export enum TYPE {
17
+ COMPONENT = 'component',
18
+ }
19
+
20
+ export const componentName: string = 'componentName';
21
+ export const componentNamePrefix: string = CONSTANTS.NAMESPACE.PREFIX;
22
+ export const componentNameSeparator: string = CONSTANTS.NAMESPACE.SEPARATOR;
23
+
24
+ export const root: string = process.cwd();
25
+ export const plop: string = `${join(root, 'config', 'plop')}`;
26
+
27
+ export const folders = {
28
+ src: `${join(root, 'src')}`,
29
+ components: `${join(root, 'src', 'components')}`,
30
+ templates: `${join(plop, 'templates')}`,
31
+ };
@@ -0,0 +1,4 @@
1
+ // TODO: look into how to use this from momentum-design inside of here without relative import
2
+ const { plop } = require('../../../../../config/esbuild/esbuild.config.js');
3
+
4
+ plop();
@@ -0,0 +1,25 @@
1
+ /* eslint-disable quotes */
2
+ import { PlopGeneratorConfig } from 'plop';
3
+
4
+ import { GENERATOR_NAME, componentName, PROMPT_TYPE } from '../../constants';
5
+ import { AddComponent } from '../../actions/AddComponent';
6
+ import { prompt } from '../../prompts';
7
+ import { AddToComponentImports } from '../../actions/AddToComponentImports';
8
+ import { AddToComponentExports } from '../../actions/AddToComponentExports';
9
+
10
+ const componentNameMessage = `Choose the name of the component.
11
+ Requirements
12
+ - lowercase
13
+ - without prefix e.g. "button"
14
+ - no additional "hyphens", like "theme-provider"
15
+ `;
16
+ const generator: Partial<PlopGeneratorConfig> = {
17
+ description: 'Scaffold a new package',
18
+ prompts: [prompt(`${componentName}`, componentNameMessage, PROMPT_TYPE.INPUT)],
19
+ actions: [AddComponent, AddToComponentImports, AddToComponentExports],
20
+ };
21
+
22
+ export const ComponentGenerator = {
23
+ name: GENERATOR_NAME.COMPONENT_GENERATOR,
24
+ generator,
25
+ };
@@ -0,0 +1,6 @@
1
+ import { NodePlopAPI } from 'plop';
2
+ import { ComponentGenerator } from './generators/component';
3
+
4
+ export default (plop: NodePlopAPI) => {
5
+ plop.setGenerator(ComponentGenerator.name, ComponentGenerator.generator);
6
+ };
@@ -0,0 +1,8 @@
1
+ import { PromptQuestion } from 'node-plop';
2
+ import { PROMPT_TYPE } from '../constants';
3
+
4
+ export const prompt = (name: string, message: string, type: PROMPT_TYPE = PROMPT_TYPE.INPUT): PromptQuestion => ({
5
+ type,
6
+ name,
7
+ message,
8
+ });
@@ -0,0 +1,12 @@
1
+ import {{sentenceCase componentName}} from './{{componentName}}.component';
2
+ import { TAG_NAME } from './{{componentName}}.constants';
3
+
4
+ {{sentenceCase componentName}}.register(TAG_NAME);
5
+
6
+ declare global {
7
+ interface HTMLElementTagNameMap {
8
+ ['{{prefix}}{{separator}}{{componentName}}']: {{sentenceCase componentName}}
9
+ }
10
+ }
11
+
12
+ export default {{sentenceCase componentName}};
@@ -0,0 +1,22 @@
1
+ import { html } from 'lit';
2
+ import { property } from 'lit/decorators.js';
3
+ import styles from './{{componentName}}.styles';
4
+ import { Component } from '../../models';
5
+
6
+ /**
7
+ * @slot - This is a default/unnamed slot
8
+ *
9
+ * @summary This is MyElement
10
+ *
11
+ * @tag {{prefix}}-{{componentName}}
12
+ * @tagname {{prefix}}-{{componentName}}
13
+ */
14
+ class {{sentenceCase prefix}}{{sentenceCase componentName}} extends Component {
15
+ public override render() {
16
+ return html`<p>This is a dummy component!</p><slot></slot>`;
17
+ }
18
+
19
+ public static override styles = styles;
20
+ }
21
+
22
+ export default {{sentenceCase componentName}};
@@ -0,0 +1,5 @@
1
+ import utils from '../../utils/tag-name';
2
+
3
+ const TAG_NAME = utils.constructTagName('{{componentName}}');
4
+
5
+ export { TAG_NAME };
@@ -0,0 +1,67 @@
1
+ import { test } from '../../../config/playwright/setup';
2
+ import steps from '../../../config/playwright/setup/steps/accessibility';
3
+
4
+ test.beforeEach(async ({ componentsPage }) => {
5
+ await componentsPage.mount({
6
+ html: `
7
+ <{{prefix}}{{separator}}{{componentName}} />
8
+ `,
9
+ });
10
+ });
11
+
12
+ test('{{prefix}}{{separator}}{{componentName}}', async ({ componentsPage }) => {
13
+ const {{componentName}} = componentsPage.page.locator('{{prefix}}-{{componentName}}');
14
+
15
+ // initial check for the {{componentName}} be visible on the screen:
16
+ await {{componentName}}.waitFor();
17
+
18
+ /**
19
+ * ACCESSIBILITY
20
+ */
21
+ await test.step('accessibility', async () => {
22
+ await steps.automaticA11yCheckStep(componentsPage);
23
+ });
24
+
25
+ /**
26
+ * VISUAL REGRESSION
27
+ */
28
+ await test.step('visual-regression', async () => {
29
+ await test.step('matches screenshot of element', async () => {
30
+ await componentsPage.visualRegression.takeScreenshot('{{prefix}}{{separator}}{{componentName}}', { element: {{componentName}} });
31
+ });
32
+ });
33
+
34
+ /**
35
+ * ATTRIBUTES
36
+ */
37
+ await test.step('attributes', async () => {
38
+ await test.step('attribute X should be present on component by default', async () => {
39
+ // TODO: add test here
40
+ });
41
+ });
42
+
43
+ /**
44
+ * INTERACTIONS
45
+ */
46
+ await test.step('interactions', async () => {
47
+ await test.step('mouse/pointer', async () => {
48
+ await test.step('component should fire callback x when clicking on it', async () => {
49
+ // TODO: add test here
50
+ });
51
+ });
52
+
53
+ await test.step('focus', async () => {
54
+ await test.step('component should be focusable with tab', async () => {
55
+ // TODO: add test here
56
+ });
57
+
58
+ // add additional tests here, like tabbing through several parts of the component
59
+ });
60
+
61
+ await test.step('keyboard', async () => {
62
+ await test.step('component should fire callback x when pressing y', async () => {
63
+ // TODO: add test here
64
+ });
65
+ });
66
+ });
67
+ });
@@ -0,0 +1,13 @@
1
+ import { html } from 'lit';
2
+
3
+ type Args = {}
4
+
5
+ const base = (args: Args) => html`
6
+ <{{prefix}}{{separator}}{{componentName}}></{{prefix}}{{separator}}{{componentName}}>
7
+ `;
8
+
9
+ const fixtures = {
10
+ base,
11
+ };
12
+
13
+ export default fixtures;
@@ -0,0 +1,18 @@
1
+ import type { Meta, StoryObj, Args } from '@storybook/web-components';
2
+ import '.';
3
+ import fixtures from './{{componentName}}.fixtures';
4
+
5
+ const render = (args: Args) => fixtures.base(args);
6
+
7
+ const meta: Meta = {
8
+ tags: ['autodocs'],
9
+ component: '{{prefix}}{{separator}}{{componentName}}',
10
+ render,
11
+ argTypes: {},
12
+ };
13
+
14
+ export default meta;
15
+
16
+ export const Primary: StoryObj = {
17
+ args: {},
18
+ };
@@ -0,0 +1,8 @@
1
+ import { css } from 'lit';
2
+
3
+ const styles = css`
4
+ :host {
5
+ }
6
+ `;
7
+
8
+ export default styles;
@@ -0,0 +1,11 @@
1
+ {
2
+ "compilerOptions": {
3
+ "outDir": "./dist",
4
+ "module": "CommonJS",
5
+ "esModuleInterop": true,
6
+ "moduleResolution": "node"
7
+ },
8
+ "exclude": [
9
+ "./templates"
10
+ ]
11
+ }
@@ -0,0 +1,41 @@
1
+ import { create } from '@storybook/theming/create';
2
+
3
+ export default create({
4
+ base: 'dark',
5
+
6
+ // Typography for Manager
7
+ // (can't use Inter here without a lot of workarounds):
8
+ fontBase: 'Helvetica Neue, sans-serif',
9
+ fontCode: 'monospace',
10
+
11
+ brandTitle: 'Momentum Design',
12
+ brandUrl: 'https://momentum.design',
13
+ brandImage: '/momentum-logo.png',
14
+ brandTarget: '_self',
15
+
16
+ colorPrimary: '#64b4fa',
17
+ colorSecondary: '#64b4fa',
18
+
19
+ // UI
20
+ appBg: '#1a1a1a',
21
+ appContentBg: '#262626',
22
+ appBorderColor: '#ffffff4d',
23
+
24
+ // Text colors
25
+ textColor: '#FFFFF2',
26
+ textInverseColor: '#000002',
27
+
28
+ // Toolbar default and active colors
29
+ barTextColor: '#FFFFF2',
30
+ barSelectedColor: '#64b4fa',
31
+ barBg: '#262626',
32
+
33
+ // Form colors
34
+ inputBg: '#FFFFFF',
35
+ inputBorder: '#ffffffb3',
36
+ inputTextColor: '#000002',
37
+
38
+ // Buttons:
39
+ buttonBg: '#FFFFFF',
40
+ buttonBorder: '#ffffffb3',
41
+ });
@@ -0,0 +1,21 @@
1
+ const config = {
2
+ stories: ['../../src/**/*.stories.@(js|jsx|ts|tsx)', '../../src/stories/**/*.mdx'],
3
+ addons: [
4
+ '@storybook/addon-controls',
5
+ '@storybook/addon-links',
6
+ '@storybook/addon-essentials',
7
+ '@storybook/addon-a11y',
8
+ ],
9
+ framework: {
10
+ name: '@storybook/web-components-vite',
11
+ options: {},
12
+ },
13
+ core: {
14
+ disableTelemetry: true, // 👈 Disables telemetry
15
+ },
16
+ docs: {
17
+ autodocs: 'tag',
18
+ },
19
+ staticDirs: ['./public'],
20
+ };
21
+ export default config;
@@ -0,0 +1,17 @@
1
+ import { addons } from '@storybook/manager-api';
2
+ import momentum from './MomentumStorybookTheme';
3
+
4
+ addons.setConfig({
5
+ bottomPanelHeight: '500',
6
+ panelPosition: 'bottom',
7
+ sidebar: {
8
+ showRoots: true,
9
+ },
10
+ toolbar: {
11
+ zoom: { hidden: false },
12
+ eject: { hidden: false },
13
+ copy: { hidden: false },
14
+ fullscreen: { hidden: false },
15
+ },
16
+ theme: momentum,
17
+ });
@@ -0,0 +1,63 @@
1
+ import '../../src/components/themeprovider';
2
+ import '@momentum-design/tokens/dist/css/core/complete.css';
3
+ import '@momentum-design/tokens/dist/css/theme/webex/dark-stable.css';
4
+ import '@momentum-design/tokens/dist/css/theme/webex/light-stable.css';
5
+ import '@momentum-design/fonts/dist/css/fonts.css';
6
+
7
+ import { setCustomElementsManifest } from '@storybook/web-components';
8
+ import customElements from '../../data/custom-elements.json';
9
+ import { themes } from './themes';
10
+ import { withThemeProvider } from './provider/themeProvider';
11
+ import { withIconProvider } from './provider/iconProvider';
12
+
13
+ setCustomElementsManifest(customElements);
14
+
15
+ const preview = {
16
+ parameters: {
17
+ a11y: {
18
+ options: {
19
+ runOnly: {
20
+ type: 'tag',
21
+ values: ['best-practice', 'wcag2a', 'wcag2aa', 'wcag21aa', 'wcag22aa'],
22
+ },
23
+ },
24
+ },
25
+ backgrounds: {
26
+ disable: true,
27
+ grid: {
28
+ disable: true,
29
+ },
30
+ },
31
+ actions: { argTypesRegex: '^on[A-Z].*' },
32
+ controls: {
33
+ controls: { expanded: true },
34
+ matchers: {
35
+ color: /(background|color)$/i,
36
+ date: /Date$/,
37
+ },
38
+ },
39
+ options: {
40
+ storySort: {
41
+ order: ['System', 'Components'],
42
+ },
43
+ },
44
+ },
45
+ decorators: [withThemeProvider, withIconProvider],
46
+ globalTypes: {
47
+ theme: {
48
+ description: 'Global theme for components',
49
+ defaultValue: themes[0].displayName,
50
+ toolbar: {
51
+ // The label to show for this toolbar item
52
+ title: 'Theme',
53
+ icon: 'globe',
54
+ // Array of plain string values or MenuItem shape (see below)
55
+ items: themes.map((theme) => theme.displayName),
56
+ // Change title based on selected value
57
+ dynamicTitle: true,
58
+ },
59
+ },
60
+ },
61
+ };
62
+
63
+ export default preview;
@@ -0,0 +1,8 @@
1
+ import { html } from 'lit';
2
+
3
+ export const withIconProvider = (story) =>
4
+ html`<mdc-iconprovider
5
+ url="/icons/svg"
6
+ >
7
+ ${story()}
8
+ </mdc-iconprovider>`;
@@ -0,0 +1,31 @@
1
+ import { html } from 'lit';
2
+ import { themes } from '../themes';
3
+ import '../themes/themes.css';
4
+
5
+ const clearStyles = (element) => {
6
+ // eslint-disable-next-line no-restricted-syntax
7
+ for (const theme of themes) {
8
+ element.classList.remove(theme.className);
9
+ }
10
+ };
11
+
12
+ const applyStyle = (element, className) => {
13
+ element.classList.add(className);
14
+ };
15
+
16
+ export const withThemeProvider = (story, context) => {
17
+ const currentTheme = context.globals.theme;
18
+ const themeObject = themes.find((theme) => theme.displayName === currentTheme);
19
+
20
+ const body = document.querySelector('body.sb-show-main');
21
+ clearStyles(body);
22
+ applyStyle(body, themeObject.className);
23
+
24
+ return html`<mdc-themeprovider
25
+ id="theme-provider"
26
+ theme="${themeObject.name}"
27
+ themes="mds-theme-stable-darkWebex mds-theme-stable-lightWebex"
28
+ >
29
+ ${story()}
30
+ </mdc-themeprovider>`;
31
+ };
@@ -0,0 +1,14 @@
1
+ export const themes = [
2
+ {
3
+ name: 'mds-theme-stable-darkWebex',
4
+ displayName: 'darkWebex',
5
+ backgroundColor: '#000000',
6
+ className: 'dark',
7
+ },
8
+ {
9
+ name: 'mds-theme-stable-lightWebex',
10
+ displayName: 'lightWebex',
11
+ backgroundColor: '#ffffff',
12
+ className: 'light',
13
+ },
14
+ ];
@@ -0,0 +1,15 @@
1
+ .dark {
2
+ background-color: #000000;
3
+ height: 100vh;
4
+ background-image: url('/background-graphic.png');
5
+ background-repeat: no-repeat;
6
+ background-position: top right;
7
+ }
8
+
9
+ .light {
10
+ background-color: #ffffff;
11
+ height: 100vh;
12
+ background-image: url('/background-graphic.png');
13
+ background-repeat: no-repeat;
14
+ background-position: top right;
15
+ }