@statistikzh/leu 0.4.0 → 0.5.0

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 (216) hide show
  1. package/.storybook/preview.js +1 -2
  2. package/CHANGELOG.md +24 -0
  3. package/custom-elements-manifest.config.js +46 -0
  4. package/dist/Accordion.d.ts +31 -0
  5. package/dist/Accordion.d.ts.map +1 -0
  6. package/dist/Accordion.js +257 -0
  7. package/dist/Breadcrumb.d.ts +69 -0
  8. package/dist/Breadcrumb.d.ts.map +1 -0
  9. package/dist/Breadcrumb.js +392 -0
  10. package/dist/Button-da11d064.d.ts +84 -0
  11. package/dist/Button-da11d064.d.ts.map +1 -0
  12. package/dist/Button-da11d064.js +542 -0
  13. package/dist/Button.d.ts +2 -0
  14. package/dist/Button.d.ts.map +1 -0
  15. package/dist/Button.js +6 -420
  16. package/dist/ButtonGroup.d.ts +24 -0
  17. package/dist/ButtonGroup.d.ts.map +1 -0
  18. package/dist/ButtonGroup.js +70 -39
  19. package/dist/Checkbox.d.ts +13 -0
  20. package/dist/Checkbox.d.ts.map +1 -0
  21. package/dist/Checkbox.js +2 -2
  22. package/dist/CheckboxGroup.d.ts +13 -0
  23. package/dist/CheckboxGroup.d.ts.map +1 -0
  24. package/dist/CheckboxGroup.js +3 -3
  25. package/dist/Chip.d.ts +5 -0
  26. package/dist/Chip.d.ts.map +1 -0
  27. package/dist/{Chip-dac7337d.js → Chip.js} +16 -5
  28. package/dist/ChipGroup.d.ts +28 -0
  29. package/dist/ChipGroup.d.ts.map +1 -0
  30. package/dist/ChipGroup.js +62 -5
  31. package/dist/ChipLink.d.ts +15 -0
  32. package/dist/ChipLink.d.ts.map +1 -0
  33. package/dist/ChipLink.js +1 -1
  34. package/dist/ChipRemovable.d.ts +13 -0
  35. package/dist/ChipRemovable.d.ts.map +1 -0
  36. package/dist/ChipRemovable.js +2 -2
  37. package/dist/ChipSelectable.d.ts +22 -0
  38. package/dist/ChipSelectable.d.ts.map +1 -0
  39. package/dist/ChipSelectable.js +5 -5
  40. package/dist/Dropdown.d.ts +15 -0
  41. package/dist/Dropdown.d.ts.map +1 -0
  42. package/dist/Dropdown.js +25 -7
  43. package/dist/Input.d.ts +154 -0
  44. package/dist/Input.d.ts.map +1 -0
  45. package/dist/Input.js +13 -7
  46. package/dist/Menu.d.ts +8 -0
  47. package/dist/Menu.d.ts.map +1 -0
  48. package/dist/MenuItem.d.ts +21 -0
  49. package/dist/MenuItem.d.ts.map +1 -0
  50. package/dist/MenuItem.js +3 -3
  51. package/dist/Pagination.d.ts +27 -0
  52. package/dist/Pagination.d.ts.map +1 -0
  53. package/dist/Pagination.js +93 -61
  54. package/dist/Popup.d.ts +18 -0
  55. package/dist/Popup.d.ts.map +1 -0
  56. package/dist/{leu-popup-4bf6f1f4.js → Popup.js} +4 -5
  57. package/dist/Radio.d.ts +12 -0
  58. package/dist/Radio.d.ts.map +1 -0
  59. package/dist/Radio.js +2 -2
  60. package/dist/RadioGroup.d.ts +20 -0
  61. package/dist/RadioGroup.d.ts.map +1 -0
  62. package/dist/RadioGroup.js +3 -3
  63. package/dist/ScrollTop.d.ts +19 -0
  64. package/dist/ScrollTop.d.ts.map +1 -0
  65. package/dist/ScrollTop.js +122 -0
  66. package/dist/Select.d.ts +98 -0
  67. package/dist/Select.d.ts.map +1 -0
  68. package/dist/Select.js +27 -82
  69. package/dist/Table.d.ts +48 -0
  70. package/dist/Table.d.ts.map +1 -0
  71. package/dist/Table.js +7 -4
  72. package/dist/VisuallyHidden.d.ts +8 -0
  73. package/dist/VisuallyHidden.d.ts.map +1 -0
  74. package/dist/VisuallyHidden.js +28 -0
  75. package/dist/_rollupPluginBabelHelpers-20f659f4.d.ts +3 -0
  76. package/dist/_rollupPluginBabelHelpers-20f659f4.d.ts.map +1 -0
  77. package/dist/defineElement-40372b4b.d.ts +9 -0
  78. package/dist/defineElement-40372b4b.d.ts.map +1 -0
  79. package/dist/{defineElement-47d4f665.js → defineElement-40372b4b.js} +1 -1
  80. package/dist/icon-03e86700.d.ts +11 -0
  81. package/dist/icon-03e86700.d.ts.map +1 -0
  82. package/dist/index.js.d.ts +21 -0
  83. package/dist/index.js.d.ts.map +1 -0
  84. package/dist/{index.js → index.js.js} +14 -8
  85. package/dist/leu-accordion.d.ts +3 -0
  86. package/dist/leu-accordion.d.ts.map +1 -0
  87. package/dist/leu-accordion.js +9 -0
  88. package/dist/leu-breadcrumb.d.ts +3 -0
  89. package/dist/leu-breadcrumb.d.ts.map +1 -0
  90. package/dist/leu-breadcrumb.js +23 -0
  91. package/dist/leu-button-group.d.ts +3 -0
  92. package/dist/leu-button-group.d.ts.map +1 -0
  93. package/dist/leu-button-group.js +1 -5
  94. package/dist/leu-button.d.ts +3 -0
  95. package/dist/leu-button.d.ts.map +1 -0
  96. package/dist/leu-button.js +3 -2
  97. package/dist/leu-checkbox-group.d.ts +3 -0
  98. package/dist/leu-checkbox-group.d.ts.map +1 -0
  99. package/dist/leu-checkbox-group.js +1 -1
  100. package/dist/leu-checkbox.d.ts +3 -0
  101. package/dist/leu-checkbox.d.ts.map +1 -0
  102. package/dist/leu-checkbox.js +1 -1
  103. package/dist/leu-chip-group.d.ts +3 -0
  104. package/dist/leu-chip-group.d.ts.map +1 -0
  105. package/dist/leu-chip-group.js +2 -1
  106. package/dist/leu-chip-link.d.ts +3 -0
  107. package/dist/leu-chip-link.d.ts.map +1 -0
  108. package/dist/leu-chip-link.js +2 -2
  109. package/dist/leu-chip-removable.d.ts +3 -0
  110. package/dist/leu-chip-removable.d.ts.map +1 -0
  111. package/dist/leu-chip-removable.js +2 -2
  112. package/dist/leu-chip-selectable.d.ts +3 -0
  113. package/dist/leu-chip-selectable.d.ts.map +1 -0
  114. package/dist/leu-chip-selectable.js +2 -2
  115. package/dist/leu-dropdown.d.ts +3 -0
  116. package/dist/leu-dropdown.d.ts.map +1 -0
  117. package/dist/leu-dropdown.js +5 -4
  118. package/dist/leu-input.d.ts +3 -0
  119. package/dist/leu-input.d.ts.map +1 -0
  120. package/dist/leu-input.js +1 -1
  121. package/dist/leu-menu-item.d.ts +3 -0
  122. package/dist/leu-menu-item.d.ts.map +1 -0
  123. package/dist/leu-menu-item.js +1 -1
  124. package/dist/leu-menu.d.ts +3 -0
  125. package/dist/leu-menu.d.ts.map +1 -0
  126. package/dist/leu-menu.js +1 -1
  127. package/dist/leu-pagination.d.ts +3 -0
  128. package/dist/leu-pagination.d.ts.map +1 -0
  129. package/dist/leu-pagination.js +5 -2
  130. package/dist/leu-popup.d.ts +3 -0
  131. package/dist/leu-popup.d.ts.map +1 -0
  132. package/dist/leu-popup.js +9 -0
  133. package/dist/leu-radio-group.d.ts +3 -0
  134. package/dist/leu-radio-group.d.ts.map +1 -0
  135. package/dist/leu-radio-group.js +1 -1
  136. package/dist/leu-radio.d.ts +3 -0
  137. package/dist/leu-radio.d.ts.map +1 -0
  138. package/dist/leu-radio.js +1 -1
  139. package/dist/leu-scroll-top.d.ts +3 -0
  140. package/dist/leu-scroll-top.d.ts.map +1 -0
  141. package/dist/leu-scroll-top.js +14 -0
  142. package/dist/leu-select.d.ts +3 -0
  143. package/dist/leu-select.d.ts.map +1 -0
  144. package/dist/leu-select.js +4 -3
  145. package/dist/leu-table.d.ts +3 -0
  146. package/dist/leu-table.d.ts.map +1 -0
  147. package/dist/leu-table.js +5 -2
  148. package/dist/leu-visually-hidden.d.ts +3 -0
  149. package/dist/leu-visually-hidden.d.ts.map +1 -0
  150. package/dist/leu-visually-hidden.js +8 -0
  151. package/dist/theme.css +386 -2
  152. package/dist/utils-65469421.d.ts +16 -0
  153. package/dist/utils-65469421.d.ts.map +1 -0
  154. package/dist/utils-65469421.js +35 -0
  155. package/index.js +3 -0
  156. package/package.json +30 -12
  157. package/postcss.config.cjs +2 -0
  158. package/rollup.config.js +21 -40
  159. package/scripts/generate-component/templates/[name].css +2 -2
  160. package/scripts/postcss-leu-font-styles.cjs +160 -0
  161. package/src/components/accordion/accordion.css +2 -2
  162. package/src/components/accordion/stories/accordion.stories.js +2 -1
  163. package/src/components/accordion/test/accordion.test.js +4 -2
  164. package/src/components/breadcrumb/Breadcrumb.js +2 -1
  165. package/src/components/breadcrumb/breadcrumb.css +2 -13
  166. package/src/components/button/Button.js +69 -8
  167. package/src/components/button/button.css +10 -2
  168. package/src/components/button/stories/button.stories.js +43 -90
  169. package/src/components/button/test/button.test.js +90 -19
  170. package/src/components/button-group/ButtonGroup.js +76 -34
  171. package/src/components/button-group/stories/button-group.stories.js +13 -6
  172. package/src/components/button-group/test/button-group.test.js +38 -31
  173. package/src/components/checkbox/checkbox-group.css +2 -2
  174. package/src/components/checkbox/checkbox.css +1 -1
  175. package/src/components/chip/ChipGroup.js +42 -2
  176. package/src/components/chip/ChipRemovable.js +1 -1
  177. package/src/components/chip/ChipSelectable.js +4 -4
  178. package/src/components/chip/chip-group.css +12 -2
  179. package/src/components/chip/chip.css +14 -3
  180. package/src/components/chip/stories/chip-group.stories.js +100 -46
  181. package/src/components/chip/test/chip-removable.test.js +3 -3
  182. package/src/components/dropdown/Dropdown.js +23 -3
  183. package/src/components/input/Input.js +7 -4
  184. package/src/components/input/input.css +2 -2
  185. package/src/components/input/stories/input.stories.js +13 -0
  186. package/src/components/input/test/input.test.js +1 -0
  187. package/src/components/menu/menu-item.css +3 -3
  188. package/src/components/pagination/Pagination.js +91 -60
  189. package/src/components/pagination/pagination.css +6 -1
  190. package/src/components/pagination/stories/pagination.stories.js +15 -2
  191. package/src/components/pagination/test/pagination.test.js +15 -15
  192. package/src/components/popup/popup.css +2 -2
  193. package/src/components/popup/stories/popup.stories.js +1 -1
  194. package/src/components/radio/radio-group.css +2 -2
  195. package/src/components/radio/radio.css +1 -1
  196. package/src/components/scroll-top/ScrollTop.js +87 -0
  197. package/src/components/scroll-top/leu-scroll-top.js +6 -0
  198. package/src/components/scroll-top/scroll-top.css +34 -0
  199. package/src/components/scroll-top/stories/scroll-top.stories.js +217 -0
  200. package/src/components/scroll-top/test/scroll-top.test.js +22 -0
  201. package/src/components/select/Select.js +24 -6
  202. package/src/components/select/select.css +2 -2
  203. package/src/components/table/table.css +2 -2
  204. package/src/components/visually-hidden/VisuallyHidden.js +13 -0
  205. package/src/components/visually-hidden/leu-visually-hidden.js +6 -0
  206. package/src/components/visually-hidden/stories/visually-hidden.stories.js +22 -0
  207. package/src/components/visually-hidden/test/visually-hidden.test.js +36 -0
  208. package/src/components/visually-hidden/visually-hidden.css +10 -0
  209. package/src/lib/defineElement.js +1 -1
  210. package/src/lib/hasSlotController.js +5 -3
  211. package/src/lib/utils.js +21 -3
  212. package/src/styles/custom-properties.css +6 -2
  213. package/src/styles/font-definitions.json +202 -0
  214. package/stylelint.config.mjs +2 -0
  215. package/tsconfig.build.json +21 -0
  216. package/tsconfig.json +16 -0
@@ -0,0 +1,160 @@
1
+ const path = require("path")
2
+ const fs = require("fs/promises")
3
+
4
+ /* Plugin logic */
5
+
6
+ function getPixelValue(value) {
7
+ return parseInt(value.replace("px", ""), 10)
8
+ }
9
+
10
+ async function parseFile(file) {
11
+ const string = await fs.readFile(file, "utf-8")
12
+
13
+ return JSON.parse(string)
14
+ }
15
+
16
+ function generateCustomPropertyDeclarations({
17
+ identifier,
18
+ fontSize,
19
+ fontWeight,
20
+ lineHeight,
21
+ spacing,
22
+ }) {
23
+ const customPropertyPrefix = `--leu-t-${identifier}-${fontWeight}`
24
+
25
+ const varFontSize = `${customPropertyPrefix}-font-size`
26
+ const varLineHeight = `${customPropertyPrefix}-line-height`
27
+ const varSpacing = `${customPropertyPrefix}-spacing`
28
+ const varFont = `${customPropertyPrefix}-font`
29
+ const varFontFamily = `--leu-font-family-${fontWeight}`
30
+
31
+ return [
32
+ { type: "fontSize", name: varFontSize, value: `${fontSize / 16}rem` },
33
+ { type: "lineHeight", name: varLineHeight, value: `${lineHeight}` },
34
+ { type: "spacing", name: varSpacing, value: `${spacing}rem` },
35
+ {
36
+ type: "font",
37
+ name: varFont,
38
+ value: `var(${varFontSize}) / var(${varLineHeight}) var(${varFontFamily})`,
39
+ },
40
+ ]
41
+ }
42
+
43
+ function curveStepDeclarations(curvePrefix, stepStyle) {
44
+ const fontSizeVar = stepStyle.declarations.find(
45
+ (s) => s.type === "fontSize"
46
+ ).name
47
+ const lineHeightVar = stepStyle.declarations.find(
48
+ (s) => s.type === "lineHeight"
49
+ ).name
50
+ const spacingVar = stepStyle.declarations.find(
51
+ (s) => s.type === "spacing"
52
+ ).name
53
+ const fontVar = stepStyle.declarations.find((s) => s.type === "font").name
54
+
55
+ return [
56
+ { prop: `${curvePrefix}-font-size`, value: ` var(${fontSizeVar})` },
57
+ { prop: `${curvePrefix}-line-height`, value: ` var(${lineHeightVar})` },
58
+ { prop: `${curvePrefix}-spacing`, value: ` var(${spacingVar})` },
59
+ { prop: `${curvePrefix}-font`, value: ` var(${fontVar})` },
60
+ ]
61
+ }
62
+
63
+ /**
64
+ *
65
+ * @param {*} file
66
+ * @param {import('postcss')} postcss
67
+ * @param {import('postcss').Source} nodeSource
68
+ * @returns
69
+ */
70
+ async function createLeuFontStyleNodes(file, postcss, nodeSource) {
71
+ const { definitions, curves } = await parseFile(file)
72
+
73
+ const fontStyleDeclarations = definitions.flatMap((style) => {
74
+ const fontSize = getPixelValue(style.fontSize)
75
+ const fontWeights = Array.isArray(style.fontWeight)
76
+ ? style.fontWeight
77
+ : [style.fontWeight]
78
+ const spacing = getPixelValue(style.spacing) / 16
79
+
80
+ const identifier = (fontSize / 4) * 10
81
+
82
+ return fontWeights.map((fontWeight) => ({
83
+ name: style.name,
84
+ fontWeight,
85
+ identifier,
86
+ declarations: generateCustomPropertyDeclarations({
87
+ identifier,
88
+ fontSize,
89
+ fontWeight,
90
+ lineHeight: style.lineHeight,
91
+ spacing,
92
+ }),
93
+ }))
94
+ })
95
+
96
+ const fontStyleNodes = fontStyleDeclarations.flatMap((style) =>
97
+ style.declarations.map(
98
+ ({ name, value }) =>
99
+ new postcss.Declaration({ prop: name, value, source: nodeSource })
100
+ )
101
+ )
102
+
103
+ const curveNodes = curves.flatMap((curve) => {
104
+ const [_, lastStepName] = curve.steps.at(-1)
105
+ const { identifier } = fontStyleDeclarations.find(
106
+ (style) => style.name === lastStepName && style.fontWeight === "black"
107
+ )
108
+
109
+ const curvePrefix = `--leu-t-curve-${identifier}-black`
110
+
111
+ return curve.steps.flatMap((step) => {
112
+ const [viewport, styleName] = step
113
+
114
+ const stepStyle = fontStyleDeclarations.find(
115
+ (s) => s.name === styleName && s.fontWeight === "black"
116
+ )
117
+
118
+ const nodes = curveStepDeclarations(curvePrefix, stepStyle).map(
119
+ ({ prop, value }) =>
120
+ new postcss.Declaration({ prop, value, source: nodeSource })
121
+ )
122
+
123
+ return viewport === null
124
+ ? nodes
125
+ : new postcss.AtRule({
126
+ name: "media",
127
+ params: `(${viewport})`,
128
+ nodes,
129
+ source: nodeSource,
130
+ })
131
+ })
132
+ })
133
+
134
+ return [...fontStyleNodes, ...curveNodes]
135
+ }
136
+
137
+ /* Plugin config */
138
+
139
+ /**
140
+ * @type {import('postcss').PluginCreator}
141
+ */
142
+ module.exports = () => ({
143
+ postcssPlugin: "leu-font-styles",
144
+ AtRule: {
145
+ "leu-font-styles": async (atRule, postcss) => {
146
+ const rootDir = path.dirname(atRule.source.input.file)
147
+ const jsonFile = atRule.params.replace(/['"]+/g, "")
148
+
149
+ const nodes = await createLeuFontStyleNodes(
150
+ path.resolve(rootDir, jsonFile),
151
+ postcss,
152
+ atRule.source
153
+ )
154
+
155
+ atRule.replaceWith(nodes)
156
+ },
157
+ },
158
+ })
159
+
160
+ module.exports.postcss = true
@@ -6,8 +6,8 @@
6
6
  }
7
7
 
8
8
  :host {
9
- --accordion-font-regular: var(--leu-font-regular);
10
- --accordion-font-black: var(--leu-font-black);
9
+ --accordion-font-regular: var(--leu-font-family-regular);
10
+ --accordion-font-black: var(--leu-font-family-black);
11
11
 
12
12
  --accordion-toggle-font: var(--accordion-font-black);
13
13
 
@@ -8,7 +8,8 @@ export default {
8
8
  component: "leu-accordion",
9
9
  argTypes: {
10
10
  headingLevel: {
11
- options: [0, 1, 2, 3, 4, 5, 6],
11
+ control: "select",
12
+ options: [1, 2, 3, 4, 5, 6],
12
13
  },
13
14
  content: {
14
15
  control: {
@@ -1,5 +1,5 @@
1
1
  import { html } from "lit"
2
- import { fixture, expect } from "@open-wc/testing"
2
+ import { fixture, expect, elementUpdated, aTimeout } from "@open-wc/testing"
3
3
 
4
4
  import "../leu-accordion.js"
5
5
 
@@ -88,11 +88,13 @@ describe("LeuAccordion", () => {
88
88
  )
89
89
 
90
90
  const button = el.shadowRoot.querySelector("button")
91
- const content = el.shadowRoot.querySelector(".content")
91
+ const content = el.querySelector("[slot=content]")
92
92
 
93
93
  expect(content).not.to.be.visible
94
94
 
95
95
  button.click()
96
+ await elementUpdated(el)
97
+ await aTimeout(100)
96
98
  expect(content).to.be.visible
97
99
  })
98
100
 
@@ -7,6 +7,7 @@ import { Icon } from "../icon/icon.js"
7
7
  import "../menu/leu-menu.js"
8
8
  import "../menu/leu-menu-item.js"
9
9
  import "../popup/leu-popup.js"
10
+ import "../visually-hidden/leu-visually-hidden.js"
10
11
  import { debounce } from "../../lib/utils.js"
11
12
 
12
13
  /**
@@ -276,7 +277,7 @@ export class LeuBreadcrumb extends LitElement {
276
277
 
277
278
  return html`
278
279
  <nav class=${classMap(wrapperClasses)}>
279
- <h2 class="visuallyhidden">Sie sind hier:</h2>
280
+ <leu-visually-hidden><h2>Sie sind hier:</h2></leu-visually-hidden>
280
281
  <ol class="breadcrumbs__list" ref=${ref(this._containerRef)}>
281
282
  ${showBackOnly
282
283
  ? html` <li class="breadcrumbs__item breadcrumbs__item--back">
@@ -4,8 +4,8 @@
4
4
  }
5
5
 
6
6
  :host {
7
- --breadcrumb-font-regular: var(--leu-font-regular);
8
- --breadcrumb-font-black: var(--leu-font-black);
7
+ --breadcrumb-font-regular: var(--leu-font-family-regular);
8
+ --breadcrumb-font-black: var(--leu-font-family-black);
9
9
 
10
10
  font-family: var(--breadcrumb-font-regular);
11
11
  line-height: 1.5;
@@ -74,17 +74,6 @@
74
74
  box-shadow: var(--leu-box-shadow-short);
75
75
  }
76
76
 
77
- .visuallyhidden {
78
- clip: rect(0 0 0 0);
79
- border: 0;
80
- height: 1px;
81
- margin: -1px !important;
82
- overflow: hidden;
83
- padding: 0 !important;
84
- position: absolute;
85
- width: 1px;
86
- }
87
-
88
77
  .breadcrumbs {
89
78
  font-size: 1rem;
90
79
  }
@@ -1,6 +1,9 @@
1
1
  import { html, nothing, LitElement } from "lit"
2
2
  import { classMap } from "lit/directives/class-map.js"
3
+ import { ifDefined } from "lit/directives/if-defined.js"
4
+
3
5
  import { Icon } from "../icon/icon.js"
6
+ import { HasSlotController } from "../../lib/hasSlotController.js"
4
7
 
5
8
  import styles from "./button.css"
6
9
 
@@ -21,9 +24,36 @@ const BUTTON_TYPES = ["button", "submit", "reset"]
21
24
  Object.freeze(BUTTON_TYPES)
22
25
  export { BUTTON_TYPES }
23
26
 
24
- export const BUTTON_EXPANDED_OPTIONS = ["open", "closed"]
27
+ export const BUTTON_EXPANDED_OPTIONS = ["true", "false"]
25
28
  Object.freeze(BUTTON_EXPANDED_OPTIONS)
26
29
 
30
+ /**
31
+ * All roles that are associated with a aria-checked attribute
32
+ * @link https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-checked
33
+ */
34
+ const ARIA_ROLES_CHECKED = [
35
+ "checkbox",
36
+ "menuitemcheckbox",
37
+ "menuitemradio",
38
+ "option",
39
+ "radio",
40
+ "switch",
41
+ ]
42
+
43
+ /**
44
+ * All roles that are associated with a aria-selected attribute
45
+ * @link https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-selected
46
+ */
47
+ const ARIA_ROLES_SELECTED = [
48
+ "gridcell",
49
+ "option",
50
+ "row",
51
+ "tab",
52
+ "columnheader",
53
+ "rowheader",
54
+ "treeitem",
55
+ ]
56
+
27
57
  /**
28
58
  * @tagname leu-button
29
59
  */
@@ -38,6 +68,11 @@ export class LeuButton extends LitElement {
38
68
  delegatesFocus: true,
39
69
  }
40
70
 
71
+ /**
72
+ * @internal
73
+ */
74
+ hasSlotController = new HasSlotController(this, ["[default]"])
75
+
41
76
  static properties = {
42
77
  label: { type: String, reflect: true },
43
78
  icon: { type: String, reflect: true },
@@ -45,6 +80,7 @@ export class LeuButton extends LitElement {
45
80
  size: { type: String, reflect: true },
46
81
  variant: { type: String, reflect: true },
47
82
  type: { type: String, reflect: true },
83
+ componentRole: { type: String, reflect: true },
48
84
 
49
85
  disabled: { type: Boolean, reflect: true },
50
86
  round: { type: Boolean, reflect: true },
@@ -66,7 +102,7 @@ export class LeuButton extends LitElement {
66
102
  this.size = "regular"
67
103
  /** @type {string} */
68
104
  this.variant = "primary"
69
- /** @type {string} */
105
+ /** @type {"button" | "submit" | "reset"} */
70
106
  this.type = "button"
71
107
 
72
108
  /** @type {boolean} */
@@ -83,7 +119,7 @@ export class LeuButton extends LitElement {
83
119
 
84
120
  /**
85
121
  * Only taken into account if variant is "ghost"
86
- * @type {("open" | "closed" | undefined)}
122
+ * @type {("true" | "false" | undefined)}
87
123
  */
88
124
  this.expanded = undefined
89
125
  }
@@ -103,7 +139,7 @@ export class LeuButton extends LitElement {
103
139
  }
104
140
 
105
141
  renderIconAfter() {
106
- if (this.icon && this.label && this.iconPosition === "after") {
142
+ if (this.icon && this.iconPosition === "after") {
107
143
  return html`<div class="icon-wrapper icon-wrapper--after">
108
144
  ${Icon(this.icon, this.getIconSize())}
109
145
  </div>`
@@ -122,10 +158,30 @@ export class LeuButton extends LitElement {
122
158
  return nothing
123
159
  }
124
160
 
161
+ getAriaAttributes() {
162
+ const attributes = {
163
+ role: this.componentRole,
164
+ label: this.label,
165
+ }
166
+
167
+ if (this.componentRole) {
168
+ if (ARIA_ROLES_CHECKED.includes(this.componentRole)) {
169
+ attributes.checked = this.active ? "true" : "false"
170
+ } else if (ARIA_ROLES_SELECTED.includes(this.componentRole)) {
171
+ attributes.selected = this.active ? "true" : "false"
172
+ }
173
+ }
174
+
175
+ return attributes
176
+ }
177
+
125
178
  render() {
179
+ const hasContent = this.hasSlotController.test("[default]")
180
+ const aria = this.getAriaAttributes()
181
+
126
182
  const cssClasses = {
127
- icon: !this.label && this.icon,
128
- round: !this.label && this.icon && this.round,
183
+ icon: !hasContent && this.icon,
184
+ round: !hasContent && this.icon && this.round,
129
185
  active: this.active,
130
186
  inverted: this.inverted,
131
187
  [this.variant]: true,
@@ -133,12 +189,17 @@ export class LeuButton extends LitElement {
133
189
  }
134
190
  return html`
135
191
  <button
192
+ aria-label=${ifDefined(aria.label)}
193
+ aria-selected=${ifDefined(aria.selected)}
194
+ aria-checked=${ifDefined(aria.checked)}
195
+ role=${ifDefined(aria.role)}
136
196
  class=${classMap(cssClasses)}
137
197
  ?disabled=${this.disabled}
138
198
  type=${this.type}
139
199
  >
140
- ${this.renderIconBefore()} ${this.label} ${this.renderIconAfter()}
141
- ${this.renderExpandingIcon()}
200
+ ${this.renderIconBefore()}
201
+ <slot></slot>
202
+ ${this.renderIconAfter()} ${this.renderExpandingIcon()}
142
203
  </button>
143
204
  `
144
205
  }
@@ -3,7 +3,7 @@
3
3
  }
4
4
 
5
5
  button {
6
- font-family: var(--leu-font-black);
6
+ font-family: var(--leu-font-family-black);
7
7
  text-align: center;
8
8
  appearance: none;
9
9
  transition: background 0.1s ease;
@@ -76,6 +76,10 @@ button.primary.active {
76
76
  background: var(--leu-color-black-100);
77
77
  }
78
78
 
79
+ button.primary.active:hover {
80
+ background: var(--leu-color-black-transp-80);
81
+ }
82
+
79
83
  button.primary:disabled {
80
84
  color: var(--leu-color-black-0);
81
85
  background: var(--leu-color-black-transp-20);
@@ -97,6 +101,10 @@ button.secondary.active {
97
101
  background: var(--leu-color-black-100);
98
102
  }
99
103
 
104
+ button.secondary.active:hover {
105
+ background: var(--leu-color-black-transp-80);
106
+ }
107
+
100
108
  button.secondary:disabled {
101
109
  color: var(--leu-color-black-transp-20);
102
110
  background: var(--leu-color-black-transp-5);
@@ -107,7 +115,7 @@ button.ghost {
107
115
  background: transparent;
108
116
  padding: 0 0.5rem;
109
117
  color: var(--leu-color-black-60);
110
- font-family: var(--leu-font-regular);
118
+ font-family: var(--leu-font-family-regular);
111
119
  }
112
120
 
113
121
  button.ghost:hover {
@@ -10,11 +10,8 @@ import {
10
10
  BUTTON_EXPANDED_OPTIONS,
11
11
  } from "../Button.js"
12
12
 
13
- function copyContent(params) {
14
- const string = `<leu-button${Object.values(params)
15
- .filter((o) => o)
16
- .join("")}>\n</leu-button>`
17
- navigator.clipboard.writeText(string)
13
+ function copyContent(e) {
14
+ navigator.clipboard.writeText(e.target.outerHTML.replace(/<!--.*?-->/g, ""))
18
15
  }
19
16
 
20
17
  export default {
@@ -31,47 +28,24 @@ export default {
31
28
  },
32
29
  }
33
30
 
34
- function Template({
35
- label,
36
- round,
37
- size,
38
- active,
39
- inverted,
40
- variant,
41
- disabled,
42
- icon,
43
- iconPosition,
44
- type,
45
- expanded,
46
- }) {
47
- const params = {
48
- label: label ? ` label="${label}"` : undefined,
49
- size: size === "small" ? ' size="small"' : undefined,
50
- variant: variant !== "primary" ? ` variant="${variant}"` : undefined,
51
- icon: icon ? ` icon="${icon}"` : undefined,
52
- iconPosition: iconPosition ? ` icon="${iconPosition}"` : undefined,
53
- round: round ? " round" : undefined,
54
- active: active ? " active" : undefined,
55
- disabled: disabled ? " disabled" : undefined,
56
- inverted: inverted ? " inverted" : undefined,
57
- expanded: expanded ? ` expanded="${expanded}"` : undefined,
58
- }
31
+ function Template(args = {}) {
59
32
  const component = html`
60
33
  <div data-root>
61
34
  <leu-button
62
- label=${ifDefined(label)}
63
- size=${ifDefined(size)}
64
- variant=${ifDefined(variant)}
65
- icon=${ifDefined(icon)}
66
- iconPosition=${ifDefined(iconPosition)}
67
- type=${ifDefined(type)}
68
- expanded=${ifDefined(expanded)}
69
- ?round=${round}
70
- ?active=${active}
71
- ?inverted=${inverted}
72
- ?disabled=${disabled}
73
- @click=${() => copyContent(params)}
35
+ content=${ifDefined(args.content)}
36
+ size=${ifDefined(args.size)}
37
+ variant=${ifDefined(args.variant)}
38
+ icon=${ifDefined(args.icon)}
39
+ iconPosition=${ifDefined(args.iconPosition)}
40
+ type=${ifDefined(args.type)}
41
+ expanded=${ifDefined(args.expanded)}
42
+ ?round=${args.round}
43
+ ?active=${args.active}
44
+ ?inverted=${args.inverted}
45
+ ?disabled=${args.disabled}
46
+ @click=${copyContent}
74
47
  >
48
+ ${args.content}
75
49
  </leu-button>
76
50
  </div>
77
51
  <br />
@@ -85,7 +59,7 @@ function Template({
85
59
  }
86
60
  </style>
87
61
  <div
88
- style="${inverted
62
+ style="${args.inverted
89
63
  ? "background:var(--leu-color-accent-blue); color: var(--leu-color-white-transp-90);"
90
64
  : ""}padding:40px;"
91
65
  >
@@ -96,7 +70,7 @@ function Template({
96
70
 
97
71
  export const Regular = Template.bind({})
98
72
  Regular.argTypes = {
99
- label: { type: "string" },
73
+ content: { type: "string" },
100
74
  icon: { control: "select", options: ICON_NAMES },
101
75
  iconPosition: { control: "select", options: ["before", "after"] },
102
76
  type: { control: "radio", options: BUTTON_TYPES },
@@ -105,7 +79,7 @@ Regular.argTypes = {
105
79
  expanded: { control: "radio", options: BUTTON_EXPANDED_OPTIONS },
106
80
  }
107
81
  Regular.args = {
108
- label: "Click Mich...",
82
+ content: "Click Mich...",
109
83
  round: false,
110
84
  disabled: false,
111
85
  active: false,
@@ -119,18 +93,18 @@ Regular.args = {
119
93
  }
120
94
 
121
95
  const items = [
122
- { label: "Normal" },
123
- { label: "Active", active: true },
124
- { label: "Disabled", disabled: true },
96
+ { content: "Normal" },
97
+ { content: "Active", active: true },
98
+ { content: "Disabled", disabled: true },
125
99
 
126
- { label: "Normal", icon: "calendar" },
127
- { label: "Active", icon: "calendar", active: true },
128
- { label: "Disabled", icon: "calendar", disabled: true },
100
+ { content: "Normal", icon: "calendar" },
101
+ { content: "Active", icon: "calendar", active: true },
102
+ { content: "Disabled", icon: "calendar", disabled: true },
129
103
 
130
- { label: "Normal", icon: "calendar", iconPosition: "after" },
131
- { label: "Active", icon: "calendar", iconPosition: "after", active: true },
104
+ { content: "Normal", icon: "calendar", iconPosition: "after" },
105
+ { content: "Active", icon: "calendar", iconPosition: "after", active: true },
132
106
  {
133
- label: "Disabled",
107
+ content: "Disabled",
134
108
  icon: "calendar",
135
109
  iconPosition: "after",
136
110
  disabled: true,
@@ -146,18 +120,18 @@ const items = [
146
120
  ]
147
121
 
148
122
  const ghostItems = [
149
- { label: "Normal", icon: "calendar" },
150
- { label: "Active", icon: "calendar", active: true },
151
- { label: "Disabled", icon: "calendar", disabled: true },
123
+ { content: "Normal", icon: "calendar" },
124
+ { content: "Active", icon: "calendar", active: true },
125
+ { content: "Disabled", icon: "calendar", disabled: true },
152
126
 
153
- { label: "Normal", icon: "calendar", expanded: "closed" },
154
- { label: "Active", icon: "calendar", active: true, expanded: "closed" },
155
- { label: "Disabled", icon: "calendar", disabled: true, expanded: "closed" },
127
+ { content: "Normal", icon: "calendar", expanded: "closed" },
128
+ { content: "Active", icon: "calendar", active: true, expanded: "closed" },
129
+ { content: "Disabled", icon: "calendar", disabled: true, expanded: "closed" },
156
130
 
157
- { label: "Normal", icon: "calendar", iconPosition: "after" },
158
- { label: "Active", icon: "calendar", iconPosition: "after", active: true },
131
+ { content: "Normal", icon: "calendar", iconPosition: "after" },
132
+ { content: "Active", icon: "calendar", iconPosition: "after", active: true },
159
133
  {
160
- label: "Disabled",
134
+ content: "Disabled",
161
135
  icon: "calendar",
162
136
  iconPosition: "after",
163
137
  disabled: true,
@@ -289,30 +263,8 @@ function TemplateOverview() {
289
263
  html`
290
264
  <div>
291
265
  <div class=${classMap({ table: true })} data-root>
292
- ${size.items.map((item) => {
293
- const params = {
294
- label: item.label
295
- ? ` label="${item.label}"`
296
- : undefined,
297
- size:
298
- size.size === "small" ? ' size="small"' : undefined,
299
- variant:
300
- group.variant !== "primary"
301
- ? ` variant="${group.variant}"`
302
- : undefined,
303
- icon: item.icon ? ` icon="${item.icon}"` : undefined,
304
- iconPosition: item.iconPosition
305
- ? ` iconPosition="${item.iconPosition}"`
306
- : undefined,
307
- round: item.round ? " round" : undefined,
308
- active: item.active ? " active" : undefined,
309
- disabled: item.disabled ? " disabled" : undefined,
310
- inverted: group.inverted ? " inverted" : undefined,
311
- expanded: item.expanded
312
- ? ` expanded="${item.expanded}"`
313
- : undefined,
314
- }
315
- return html`
266
+ ${size.items.map(
267
+ (item) => html`
316
268
  <leu-button
317
269
  label=${ifDefined(item.label)}
318
270
  size=${ifDefined(size.size)}
@@ -324,11 +276,12 @@ function TemplateOverview() {
324
276
  ?active=${item.active}
325
277
  ?disabled=${item.disabled}
326
278
  ?inverted=${group.inverted}
327
- @click=${() => copyContent(params)}
279
+ @click=${copyContent}
328
280
  >
281
+ ${item.content}
329
282
  </leu-button>
330
283
  `
331
- })}
284
+ )}
332
285
  </div>
333
286
  </div>
334
287
  `
@@ -341,7 +294,7 @@ function TemplateOverview() {
341
294
 
342
295
  export const Overview = TemplateOverview.bind({})
343
296
  Overview.argTypes = {
344
- label: { table: { disable: true } },
297
+ content: { table: { disable: true } },
345
298
  icon: { table: { disable: true } },
346
299
  iconPosition: { table: { disable: true } },
347
300
  size: { table: { disable: true } },