@statistikzh/leu 0.0.2

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.
Files changed (141) hide show
  1. package/.editorconfig +29 -0
  2. package/.eslintrc.json +27 -0
  3. package/.github/workflows/publish.yml +19 -0
  4. package/.github/workflows/release-please.yml +19 -0
  5. package/.github/workflows/test.yml +38 -0
  6. package/.husky/commit-msg +4 -0
  7. package/.husky/pre-commit +4 -0
  8. package/.prettierignore +1 -0
  9. package/.storybook/main.js +11 -0
  10. package/.storybook/preview-head.html +5 -0
  11. package/.storybook/preview.js +23 -0
  12. package/CHANGELOG.md +63 -0
  13. package/CODE_OF_CONDUCT.md +128 -0
  14. package/CONTRIBUTING.md +31 -0
  15. package/LICENSE +21 -0
  16. package/README.md +170 -0
  17. package/commitlint.config.cjs +1 -0
  18. package/dist/Button-83c6df93.js +403 -0
  19. package/dist/Checkbox.js +144 -0
  20. package/dist/CheckboxGroup.js +82 -0
  21. package/dist/Chip-60af1402.js +162 -0
  22. package/dist/ChipGroup.js +79 -0
  23. package/dist/ChipLink.js +46 -0
  24. package/dist/ChipRemovable.js +43 -0
  25. package/dist/ChipSelectable.js +92 -0
  26. package/dist/Input.js +686 -0
  27. package/dist/Radio.js +156 -0
  28. package/dist/RadioGroup.js +194 -0
  29. package/dist/Select.js +859 -0
  30. package/dist/Table-72d305d7.js +506 -0
  31. package/dist/Table.js +8 -0
  32. package/dist/defineElement-47d4f665.js +15 -0
  33. package/dist/icon-b68c7e1e.js +202 -0
  34. package/dist/index.js +21 -0
  35. package/dist/leu-checkbox-group.js +6 -0
  36. package/dist/leu-checkbox.js +6 -0
  37. package/dist/leu-chip-group.js +5 -0
  38. package/dist/leu-chip-link.js +6 -0
  39. package/dist/leu-chip-removable.js +7 -0
  40. package/dist/leu-chip-selectable.js +6 -0
  41. package/dist/leu-input.js +9 -0
  42. package/dist/leu-radio-group.js +6 -0
  43. package/dist/leu-radio.js +5 -0
  44. package/dist/leu-select.js +12 -0
  45. package/dist/leu-table.js +10 -0
  46. package/dist/theme.css +51 -0
  47. package/index.js +10 -0
  48. package/package.json +85 -0
  49. package/postcss.config.cjs +14 -0
  50. package/rollup.config.js +54 -0
  51. package/scripts/generate-component/generate.js +167 -0
  52. package/scripts/generate-component/templates/[Name].js +33 -0
  53. package/scripts/generate-component/templates/[name].css +11 -0
  54. package/scripts/generate-component/templates/[namespace]-[name].js +3 -0
  55. package/scripts/generate-component/templates/stories/[name].stories.js +13 -0
  56. package/scripts/generate-component/templates/test/[name].test.js +22 -0
  57. package/src/components/button/Button.js +150 -0
  58. package/src/components/button/button.css +232 -0
  59. package/src/components/button/leu-button.js +3 -0
  60. package/src/components/button/stories/button.stories.js +333 -0
  61. package/src/components/button/test/button.test.js +22 -0
  62. package/src/components/button-group/ButtonGroup.js +63 -0
  63. package/src/components/button-group/button-group.css +10 -0
  64. package/src/components/button-group/leu-button-group.js +3 -0
  65. package/src/components/button-group/stories/button-group.stories.js +41 -0
  66. package/src/components/button-group/test/button-group.test.js +22 -0
  67. package/src/components/checkbox/Checkbox.js +142 -0
  68. package/src/components/checkbox/CheckboxGroup.js +80 -0
  69. package/src/components/checkbox/leu-checkbox-group.js +3 -0
  70. package/src/components/checkbox/leu-checkbox.js +3 -0
  71. package/src/components/checkbox/stories/checkbox-group.stories.js +52 -0
  72. package/src/components/checkbox/stories/checkbox.stories.js +43 -0
  73. package/src/components/checkbox/test/checkbox.test.js +101 -0
  74. package/src/components/chip/Chip.js +24 -0
  75. package/src/components/chip/ChipGroup.js +71 -0
  76. package/src/components/chip/ChipLink.js +45 -0
  77. package/src/components/chip/ChipRemovable.js +42 -0
  78. package/src/components/chip/ChipSelectable.js +91 -0
  79. package/src/components/chip/chip-group.css +5 -0
  80. package/src/components/chip/chip.css +130 -0
  81. package/src/components/chip/exports.js +10 -0
  82. package/src/components/chip/leu-chip-group.js +3 -0
  83. package/src/components/chip/leu-chip-link.js +3 -0
  84. package/src/components/chip/leu-chip-removable.js +3 -0
  85. package/src/components/chip/leu-chip-selectable.js +3 -0
  86. package/src/components/chip/stories/chip-group.stories.js +99 -0
  87. package/src/components/chip/stories/chip-link.stories.js +37 -0
  88. package/src/components/chip/stories/chip-removable.stories.js +28 -0
  89. package/src/components/chip/stories/chip-selectable.stories.js +46 -0
  90. package/src/components/chip/test/chip.test.js +22 -0
  91. package/src/components/dropdown/Dropdown.js +55 -0
  92. package/src/components/dropdown/dropdown.css +17 -0
  93. package/src/components/dropdown/leu-dropdown.js +3 -0
  94. package/src/components/dropdown/stories/dropdown.stories.js +25 -0
  95. package/src/components/dropdown/test/dropdown.test.js +31 -0
  96. package/src/components/icon/icon.js +201 -0
  97. package/src/components/input/Input.js +421 -0
  98. package/src/components/input/input.css +231 -0
  99. package/src/components/input/leu-input.js +3 -0
  100. package/src/components/input/stories/input.stories.js +185 -0
  101. package/src/components/input/test/input.test.js +22 -0
  102. package/src/components/menu/Menu.js +18 -0
  103. package/src/components/menu/MenuItem.js +95 -0
  104. package/src/components/menu/leu-menu-item.js +3 -0
  105. package/src/components/menu/leu-menu.js +3 -0
  106. package/src/components/menu/menu-item.css +72 -0
  107. package/src/components/menu/menu.css +14 -0
  108. package/src/components/menu/stories/menu-item.stories.js +51 -0
  109. package/src/components/menu/stories/menu.stories.js +21 -0
  110. package/src/components/menu/test/menu.test.js +22 -0
  111. package/src/components/pagination/Pagination.js +152 -0
  112. package/src/components/pagination/leu-pagination.js +3 -0
  113. package/src/components/pagination/pagination.css +49 -0
  114. package/src/components/pagination/stories/pagination.stories.js +82 -0
  115. package/src/components/pagination/test/pagination.test.js +22 -0
  116. package/src/components/radio/Radio.js +62 -0
  117. package/src/components/radio/RadioGroup.js +193 -0
  118. package/src/components/radio/leu-radio-group.js +3 -0
  119. package/src/components/radio/leu-radio.js +3 -0
  120. package/src/components/radio/radio.css +76 -0
  121. package/src/components/radio/stories/radio-group.stories.js +49 -0
  122. package/src/components/radio/stories/radio.stories.js +48 -0
  123. package/src/components/radio/test/radio.test.js +38 -0
  124. package/src/components/select/Select.js +350 -0
  125. package/src/components/select/leu-select.js +3 -0
  126. package/src/components/select/select.css +215 -0
  127. package/src/components/select/stories/select.stories.js +302 -0
  128. package/src/components/select/test/select.test.js +29 -0
  129. package/src/components/table/Table.js +301 -0
  130. package/src/components/table/leu-table.js +3 -0
  131. package/src/components/table/stories/table.stories.js +116 -0
  132. package/src/components/table/test/table.test.js +36 -0
  133. package/src/lib/defineElement.js +13 -0
  134. package/src/lib/hasSlotController.js +85 -0
  135. package/src/styles/custom-media.css +5 -0
  136. package/src/styles/custom-properties.css +51 -0
  137. package/src/styles/theme.css +1 -0
  138. package/stat_zh.png +0 -0
  139. package/stylelint.config.mjs +21 -0
  140. package/web-dev-server-storybook.config.mjs +19 -0
  141. package/web-test-runner.config.mjs +49 -0
@@ -0,0 +1,116 @@
1
+ import { html } from "lit"
2
+ import "../leu-table.js"
3
+
4
+ export default {
5
+ title: "Table",
6
+ component: "leu-table",
7
+ }
8
+
9
+ function Template({ itemsOnAPage }) {
10
+ return html`
11
+ <leu-table
12
+ id="table"
13
+ itemsOnAPage=${itemsOnAPage}
14
+ style="max-width:500px;"
15
+ ></leu-table>
16
+ <script>
17
+ {
18
+ const table = document.querySelector("leu-table[id=table]")
19
+ table.columns = [
20
+ {
21
+ name: "Id",
22
+ value: (row) => row.id,
23
+ },
24
+ {
25
+ name: "Name",
26
+ value: (row) => row.name,
27
+ style: (row) => {
28
+ return {
29
+ minWidth: "400px",
30
+ }
31
+ },
32
+ sort: {
33
+ asc: (rowA, rowB) => rowA.name.localeCompare(rowB.name),
34
+ desc: (rowA, rowB) => rowB.name.localeCompare(rowA.name),
35
+ },
36
+ },
37
+ {
38
+ name: "Menge",
39
+ value: (row) => row.menge,
40
+ style: (row) => {
41
+ return {
42
+ color: row.menge > 10 ? "green" : "red",
43
+ }
44
+ },
45
+ sort: {
46
+ asc: (rowA, rowB) => rowA.menge - rowB.menge,
47
+ desc: (rowA, rowB) => rowB.menge - rowA.menge,
48
+ },
49
+ },
50
+ ]
51
+ table.data = [
52
+ { id: 1, name: "Ananas", menge: 7 },
53
+ { id: 2, name: "Apfel", menge: 12 },
54
+ { id: 3, name: "Aprikose", menge: 3 },
55
+ { id: 4, name: "Banare", menge: 11 },
56
+ { id: 5, name: "Birne", menge: 10 },
57
+ { id: 6, name: "Brombeere", menge: 5 },
58
+ { id: 7, name: "Cranberries", menge: 3 },
59
+ { id: 8, name: "Datteln", menge: 2 },
60
+ { id: 9, name: "Erdbeere", menge: 0 },
61
+ { id: 10, name: "Feige", menge: 11 },
62
+ { id: 11, name: "Granatapfel", menge: 14 },
63
+ { id: 12, name: "Grapefruit", menge: 7 },
64
+ { id: 13, name: "Heidelbeere", menge: 12 },
65
+ { id: 14, name: "Himbeere", menge: 3 },
66
+ { id: 15, name: "Johannisbeere", menge: 11 },
67
+ { id: 16, name: "Kirsche", menge: 10 },
68
+ { id: 17, name: "Kiwi", menge: 5 },
69
+ { id: 18, name: "Limette", menge: 3 },
70
+ { id: 19, name: "Litschi", menge: 2 },
71
+ { id: 20, name: "Mandarine", menge: 0 },
72
+ { id: 21, name: "Mango", menge: 11 },
73
+ { id: 22, name: "Melone", menge: 14 },
74
+ { id: 23, name: "Mirabelle", menge: 14 },
75
+ { id: 24, name: "Nashi", menge: 12 },
76
+ { id: 25, name: "Orange", menge: 3 },
77
+ { id: 26, name: "Papaya", menge: 6 },
78
+ { id: 27, name: "Pfirsich", menge: 5 },
79
+ { id: 28, name: "Pflaume", menge: 17 },
80
+ { id: 29, name: "Physalis", menge: 1 },
81
+ { id: 30, name: "Preiselbeere", menge: 19 },
82
+ { id: 31, name: "Pomelo", menge: 12 },
83
+ { id: 32, name: "Quitte", menge: 0 },
84
+ { id: 33, name: "Rhabarber", menge: 1 },
85
+ { id: 34, name: "Sanddorn", menge: 2 },
86
+ { id: 35, name: "Stachelbeere", menge: 19 },
87
+ { id: 36, name: "Ugli", menge: 9 },
88
+ { id: 37, name: "Weintraube", menge: 11 },
89
+ { id: 38, name: "Zitrone", menge: 4 },
90
+ { id: 39, name: "Zwetschge", menge: 20 },
91
+ ]
92
+ }
93
+ </script>
94
+ `
95
+ }
96
+
97
+ export const Regular = Template.bind({})
98
+ Regular.argTypes = {
99
+ itemsOnAPage: { type: "number" },
100
+ columns: { table: { disable: true } },
101
+ data: { table: { disable: true } },
102
+ _columns: { table: { disable: true } },
103
+ _data: { table: { disable: true } },
104
+ _min: { table: { disable: true } },
105
+ _max: { table: { disable: true } },
106
+ _shadowLeft: { table: { disable: true } },
107
+ _shadowRight: { table: { disable: true } },
108
+ _sortArrowDown: { table: { disable: true } },
109
+ _sortArrowUp: { table: { disable: true } },
110
+ _scrollRef: { table: { disable: true } },
111
+ _itemsOnAPage: { table: { disable: true } },
112
+ _sortedData: { table: { disable: true } },
113
+ }
114
+ Regular.args = {
115
+ itemsOnAPage: null,
116
+ }
@@ -0,0 +1,36 @@
1
+ import { html } from "lit"
2
+ import { fixture, expect } from "@open-wc/testing"
3
+
4
+ import "../leu-table.js"
5
+
6
+ const columns = [
7
+ { name: "Id", value: (row) => row.id },
8
+ { name: "Name", value: (row) => row.name },
9
+ { name: "Menge", value: (row) => row.menge },
10
+ ]
11
+
12
+ const data = [
13
+ { id: 1, name: "Apfel", menge: 4 },
14
+ { id: 2, name: "Birne", menge: 2 },
15
+ { id: 3, name: "Banane", menge: 3 },
16
+ { id: 4, name: "Orange", menge: 7 },
17
+ ]
18
+
19
+ async function defaultFixture() {
20
+ return fixture(html`<leu-table .columns=${columns} .data=${data}>
21
+ </leu-table>`)
22
+ }
23
+
24
+ describe("LeuTable", () => {
25
+ it("is a defined element", async () => {
26
+ const el = await customElements.get("leu-table")
27
+
28
+ await expect(el).not.to.be.undefined
29
+ })
30
+
31
+ it("passes the a11y audit", async () => {
32
+ const el = await defaultFixture()
33
+
34
+ await expect(el).shadowDom.to.be.accessible()
35
+ })
36
+ })
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Adds a definition for a custom element to the custom element
3
+ * registry if it isn't defined before. Prefixes the name with `leu-`.
4
+ * @param {string} name
5
+ * @param {HTMLElement} constructor
6
+ */
7
+ export function defineElement(name, constructor) {
8
+ if (!customElements.get(`leu-${name}`)) {
9
+ customElements.define(`leu-${name}`, constructor)
10
+ } else {
11
+ console.info(`leu-${name} is already defined`)
12
+ }
13
+ }
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Thanks Shoelace!
3
+ * Source: https://github.com/shoelace-style/shoelace/blob/next/src/internal/slot.ts
4
+ */
5
+
6
+ /**
7
+ * A reactive controller that determines when slots exist.
8
+ * @implements { import("lit").ReactiveController }
9
+ */
10
+ export class HasSlotController {
11
+ constructor(host, slotNames) {
12
+ this.host = host
13
+ host.addController(this)
14
+
15
+ this.slotNames = slotNames
16
+ }
17
+
18
+ /**
19
+ * @private
20
+ * @returns {Boolean}
21
+ */
22
+ hasDefaultSlot() {
23
+ return [...this.host.childNodes].some((node) => {
24
+ if (node.nodeType === node.TEXT_NODE && node.textContent.trim() !== "") {
25
+ return true
26
+ }
27
+
28
+ if (node.nodeType === node.ELEMENT_NODE) {
29
+ const el = node
30
+
31
+ // If it doesn't have a slot attribute, it's part of the default slot
32
+ if (!el.hasAttribute("slot")) {
33
+ return true
34
+ }
35
+ }
36
+
37
+ return false
38
+ })
39
+ }
40
+
41
+ /**
42
+ * @private
43
+ * @param {String} name
44
+ * @returns {Boolean}
45
+ */
46
+ hasNamedSlot(name) {
47
+ return this.host.querySelector(`:scope > [slot="${name}"]`) !== null
48
+ }
49
+
50
+ /**
51
+ * @param {String} slotName
52
+ * @returns {Boolean}
53
+ */
54
+ test(slotName) {
55
+ return slotName === "[default]"
56
+ ? this.hasDefaultSlot()
57
+ : this.hasNamedSlot(slotName)
58
+ }
59
+
60
+ hostConnected() {
61
+ this.host.shadowRoot.addEventListener("slotchange", this.handleSlotChange)
62
+ }
63
+
64
+ hostDisconnected() {
65
+ this.host.shadowRoot.removeEventListener(
66
+ "slotchange",
67
+ this.handleSlotChange
68
+ )
69
+ }
70
+
71
+ /**
72
+ * @private
73
+ * @param {Event} event
74
+ */
75
+ handleSlotChange = (event) => {
76
+ const slot = event.target
77
+
78
+ if (
79
+ (this.slotNames.includes("[default]") && !slot.name) ||
80
+ (slot.name && this.slotNames.includes(slot.name))
81
+ ) {
82
+ this.host.requestUpdate()
83
+ }
84
+ }
85
+ }
@@ -0,0 +1,5 @@
1
+ @custom-media --viewport-small (min-width: 400px);
2
+ @custom-media --viewport-regular (min-width: 600px);
3
+ @custom-media --viewport-medium (min-width: 840px);
4
+ @custom-media --viewport-large (min-width: 1024px);
5
+ @custom-media --viewport-xlarge (min-width: 1280px);
@@ -0,0 +1,51 @@
1
+ :root {
2
+ --leu-color-black-100: #000;
3
+ --leu-color-black-80: #333;
4
+ --leu-color-black-60: #666;
5
+ --leu-color-black-40: #949494;
6
+ --leu-color-black-20: #ccc;
7
+ --leu-color-black-10: #f0f0f0;
8
+ --leu-color-black-5: #f7f7f7;
9
+ --leu-color-black-0: #fffffe;
10
+
11
+ --leu-color-black-transp-80: rgb(0 0 0 / 80%);
12
+ --leu-color-black-transp-60: rgb(0 0 0 / 60%);
13
+ --leu-color-black-transp-40: rgb(0 0 0 / 40%);
14
+ --leu-color-black-transp-20: rgb(0 0 0 / 20%);
15
+ --leu-color-black-transp-10: rgb(0 0 0 / 10%);
16
+ --leu-color-black-transp-5: rgb(0 0 0 / 5%);
17
+
18
+ --leu-color-white-transp-90: rgb(255 255 255 / 90%);
19
+ --leu-color-white-transp-70: rgb(255 255 255 / 70%);
20
+ --leu-color-white-transp-40: rgb(255 255 255 / 40%);
21
+ --leu-color-white-transp-10: rgb(255 255 255 / 10%);
22
+
23
+ --leu-color-accent-blue: #0076bd;
24
+ --leu-color-accent-darkblue: #00407c;
25
+ --leu-color-accent-turquoise: #00797b;
26
+ --leu-color-accent-green: #1a7f1f;
27
+ --leu-color-accent-bordeaux: #b01657;
28
+ --leu-color-accent-magenta: #d40053;
29
+ --leu-color-accent-violet: #7f3da7;
30
+ --leu-color-accent-gray: var(--leu-color-black-60);
31
+
32
+ --leu-color-accent-blue-soft: ##edf5fa;
33
+ --leu-color-accent-darkblue-soft: ##e0e8ee;
34
+ --leu-color-accent-turquoise-soft: ##e8f3f2;
35
+ --leu-color-accent-green-soft: ##ebf6eb;
36
+ --leu-color-accent-bordeaux-soft: ##f6e3ea;
37
+ --leu-color-accent-magenta-soft: ##fcedf3;
38
+ --leu-color-accent-violet-soft: ##ece2f1;
39
+ --leu-color-accent-gray-soft: var(--leu-color-black-10);
40
+
41
+ --leu-color-func-cyan: #009ee0;
42
+ --leu-color-func-red: #d93c1a;
43
+ --leu-color-func-green: #1a7f1f;
44
+
45
+ --leu-font-regular: HelveticaNowRegular, Helvetica, sans-serif; /* stylelint-disable-line value-keyword-case */
46
+ --leu-font-black: HelveticaNowBlack, Arial Black, Helvetica, sans-serif; /* stylelint-disable-line value-keyword-case */
47
+
48
+ --leu-box-shadow-short: 0px 0px 2px var(--leu-color-black-transp-40);
49
+ --leu-box-shadow-regular: 0px 0px 16px var(--leu-color-black-transp-20);
50
+ --leu-box-shadow-long: 0px 0px 80px var(--leu-color-black-transp-20);
51
+ }
@@ -0,0 +1 @@
1
+ @import url("./custom-properties.css");
package/stat_zh.png ADDED
Binary file
@@ -0,0 +1,21 @@
1
+ export default {
2
+ extends: "stylelint-config-standard",
3
+ overrides: [
4
+ {
5
+ files: ["*.js"],
6
+ customSyntax: "postcss-lit",
7
+ },
8
+ ],
9
+ rules: {
10
+ // Disable empty line rules because we want to group related properties
11
+ // and want to separate them with empty lines.
12
+ "custom-property-empty-line-before": null,
13
+ "declaration-empty-line-before": null,
14
+ // Allowing kebab-case and an optional leading underscore
15
+ "custom-property-pattern": "^_?([a-z][a-z0-9]*)(-[a-z0-9]+)*$",
16
+ // Allowing kebab-case and BEM
17
+ "selector-class-pattern":
18
+ "^[a-z]([-]?[a-z0-9]+)*(__[a-z0-9]([-]?[a-z0-9]+)*)?(--[a-z0-9]([-]?[a-z0-9]+)*)?$",
19
+ },
20
+ ignoreFiles: ["scripts/generate-component/templates/**/*"],
21
+ }
@@ -0,0 +1,19 @@
1
+ import { fromRollup } from "@web/dev-server-rollup"
2
+ import rollupJson from "@rollup/plugin-json"
3
+ import { storybookPlugin } from "@web/dev-server-storybook"
4
+
5
+ import { plugins as rollupPlugins } from "./rollup.config.js"
6
+
7
+ export const plugins = rollupPlugins.map((p) => fromRollup(p.plugin)(...p.args))
8
+
9
+ const json = fromRollup(rollupJson)
10
+
11
+ export default /** @type {import('@web/dev-server').DevServerConfig} */ ({
12
+ nodeResolve: true,
13
+ watch: true,
14
+ mimeTypes: {
15
+ "**/custom-elements.json": "js",
16
+ "src/components/**/*.css": "js",
17
+ },
18
+ plugins: [storybookPlugin({ type: "web-components" }), ...plugins, json()],
19
+ })
@@ -0,0 +1,49 @@
1
+ import { playwrightLauncher } from "@web/test-runner-playwright"
2
+ import { plugins as devServerPlugins } from "./web-dev-server-storybook.config.mjs"
3
+
4
+ const filteredLogs = ["Running in dev mode", "lit-html is in dev mode"]
5
+
6
+ export default /** @type {import("@web/test-runner").TestRunnerConfig} */ ({
7
+ /** Test files to run */
8
+ files: "src/components/**/*.test.js",
9
+ plugins: devServerPlugins,
10
+ mimeTypes: {
11
+ "src/components/**/*.css": "js",
12
+ },
13
+
14
+ /** Resolve bare module imports */
15
+ nodeResolve: {
16
+ exportConditions: ["browser", "development"],
17
+ },
18
+
19
+ /** Filter out lit dev mode logs */
20
+ filterBrowserLogs(log) {
21
+ for (const arg of log.args) {
22
+ if (
23
+ typeof arg === "string" &&
24
+ filteredLogs.some((l) => arg.includes(l))
25
+ ) {
26
+ return false
27
+ }
28
+ }
29
+ return true
30
+ },
31
+
32
+ /** Compile JS for older browsers. Requires @web/dev-server-esbuild plugin */
33
+ // esbuildTarget: 'auto',
34
+
35
+ /** Amount of browsers to run concurrently */
36
+ concurrentBrowsers: 2,
37
+
38
+ /** Amount of test files per browser to test concurrently */
39
+ concurrency: 1,
40
+
41
+ /** Browsers to run tests on */
42
+ browsers: [
43
+ playwrightLauncher({ product: "chromium" }),
44
+ playwrightLauncher({ product: "firefox" }),
45
+ // playwrightLauncher({ product: "webkit" }),
46
+ ],
47
+
48
+ // See documentation for all available options
49
+ })