@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,302 @@
1
+ import { html } from "lit"
2
+ import { ifDefined } from "lit/directives/if-defined.js"
3
+
4
+ import "../leu-select.js"
5
+
6
+ export default {
7
+ title: "select",
8
+ component: "leu-select",
9
+ }
10
+
11
+ const OPTIONS_EXAMPLES = [
12
+ { label: "Option 1", value: "1" },
13
+ "Option 2",
14
+ "Option 3",
15
+ "Sehr lange Option um zu schauen was passiert, wenn es zu lang wird.",
16
+ ]
17
+ const OPTIONS_MUNICIPALITIES = [
18
+ "Aeugst am Albis",
19
+ "Affoltern am Albis",
20
+ "Bonstetten",
21
+ "Hausen am Albis",
22
+ "Hedingen",
23
+ "Kappel am Albis",
24
+ "Knonau",
25
+ "Maschwanden",
26
+ "Mettmenstetten",
27
+ "Obfelden",
28
+ "Ottenbach",
29
+ "Rifferswil",
30
+ "Stallikon",
31
+ "Wettswil am Albis",
32
+ "Benken (ZH)",
33
+ "Berg am Irchel",
34
+ "Buch am Irchel",
35
+ "Dachsen",
36
+ "Dorf",
37
+ "Feuerthalen",
38
+ "Flaach",
39
+ "Flurlingen",
40
+ "Henggart",
41
+ "Kleinandelfingen",
42
+ "Laufen-Uhwiesen",
43
+ "Marthalen",
44
+ "Ossingen",
45
+ "Rheinau",
46
+ "Thalheim an der Thur",
47
+ "Trüllikon",
48
+ "Truttikon",
49
+ "Volken",
50
+ "Bachenbülach",
51
+ "Bassersdorf",
52
+ "Bülach",
53
+ "Dietlikon",
54
+ "Eglisau",
55
+ "Embrach",
56
+ "Freienstein-Teufen",
57
+ "Glattfelden",
58
+ "Hochfelden",
59
+ "Höri",
60
+ "Hüntwangen",
61
+ "Kloten",
62
+ "Lufingen",
63
+ "Nürensdorf",
64
+ "Oberembrach",
65
+ "Opfikon",
66
+ "Rafz",
67
+ "Rorbas",
68
+ "Wallisellen",
69
+ "Wasterkingen",
70
+ "Wil (ZH)",
71
+ "Winkel",
72
+ "Bachs",
73
+ "Boppelsen",
74
+ "Buchs (ZH)",
75
+ "Dällikon",
76
+ "Dänikon",
77
+ "Dielsdorf",
78
+ "Hüttikon",
79
+ "Neerach",
80
+ "Niederglatt",
81
+ "Niederhasli",
82
+ "Niederweningen",
83
+ "Oberglatt",
84
+ "Oberweningen",
85
+ "Otelfingen",
86
+ "Regensberg",
87
+ "Regensdorf",
88
+ "Rümlang",
89
+ "Schleinikon",
90
+ "Schöfflisdorf",
91
+ "Stadel",
92
+ "Steinmaur",
93
+ "Weiach",
94
+ "Bäretswil",
95
+ "Bubikon",
96
+ "Dürnten",
97
+ "Fischenthal",
98
+ "Gossau (ZH)",
99
+ "Grüningen",
100
+ "Hinwil",
101
+ "Rüti (ZH)",
102
+ "Seegräben",
103
+ "Wald (ZH)",
104
+ "Wetzikon (ZH)",
105
+ "Adliswil",
106
+ "Kilchberg (ZH)",
107
+ "Langnau am Albis",
108
+ "Oberrieden",
109
+ "Richterswil",
110
+ "Rüschlikon",
111
+ "Thalwil",
112
+ "Erlenbach (ZH)",
113
+ "Herrliberg",
114
+ "Hombrechtikon",
115
+ "Küsnacht (ZH)",
116
+ "Männedorf",
117
+ "Meilen",
118
+ "Oetwil am See",
119
+ "Stäfa",
120
+ "Uetikon am See",
121
+ "Zumikon",
122
+ "Zollikon",
123
+ "Fehraltorf",
124
+ "Hittnau",
125
+ "Lindau",
126
+ "Pfäffikon",
127
+ "Russikon",
128
+ "Weisslingen",
129
+ "Wila",
130
+ "Wildberg",
131
+ "Dübendorf",
132
+ "Egg",
133
+ "Fällanden",
134
+ "Greifensee",
135
+ "Maur",
136
+ "Mönchaltorf",
137
+ "Schwerzenbach",
138
+ "Uster",
139
+ "Volketswil",
140
+ "Wangen-Brüttisellen",
141
+ "Altikon",
142
+ "Brütten",
143
+ "Dägerlen",
144
+ "Dättlikon",
145
+ "Dinhard",
146
+ "Ellikon an der Thur",
147
+ "Elsau",
148
+ "Hagenbuch",
149
+ "Hettlingen",
150
+ "Neftenbach",
151
+ "Pfungen",
152
+ "Rickenbach (ZH)",
153
+ "Schlatt (ZH)",
154
+ "Seuzach",
155
+ "Turbenthal",
156
+ "Winterthur",
157
+ "Zell (ZH)",
158
+ "Aesch (ZH)",
159
+ "Birmensdorf (ZH)",
160
+ "Dietikon",
161
+ "Geroldswil",
162
+ "Oberengstringen",
163
+ "Oetwil an der Limmat",
164
+ "Schlieren",
165
+ "Uitikon",
166
+ "Unterengstringen",
167
+ "Urdorf",
168
+ "Weiningen (ZH)",
169
+ "Zürich",
170
+ "Andelfingen",
171
+ "Stammheim",
172
+ "Wädenswil",
173
+ "Elgg",
174
+ "Horgen",
175
+ "Illnau-Effretikon",
176
+ "Bauma",
177
+ "Wiesendangen",
178
+ ]
179
+
180
+ function Template({
181
+ label,
182
+ options,
183
+ value,
184
+ disabled = false,
185
+ clearable = false,
186
+ filterable = false,
187
+ multiple = false,
188
+ before,
189
+ after,
190
+ }) {
191
+ return html`
192
+ <leu-select
193
+ class="dropdown"
194
+ .options=${options}
195
+ label=${ifDefined(label)}
196
+ .value=${ifDefined(value)}
197
+ ?clearable=${clearable}
198
+ ?disabled=${disabled}
199
+ ?filterable=${filterable}
200
+ ?multiple=${multiple}
201
+ >
202
+ ${before ? html`<div slot="before">${before}</div>` : ""}
203
+ ${after ? html`<div slot="after">${after}</div>` : ""}
204
+ </leu-select>
205
+ `
206
+ }
207
+
208
+ function TemplateSlots(args) {
209
+ const before = html`<div>before</div>`
210
+ const after = html`<div>after <input type="text"></input></div>`
211
+
212
+ return Template({ ...args, before, after })
213
+ }
214
+
215
+ export const Regular = Template.bind({})
216
+ Regular.args = {
217
+ label: "Gemeinde",
218
+ options: OPTIONS_EXAMPLES,
219
+ }
220
+ Regular.parameters = {
221
+ docs: {
222
+ description: {
223
+ story: `To render a basic input field only the \`label\` attribute is required. The \`label\` is necessary for accessibility reasons.
224
+
225
+ The label is also used inside \`aria-label\` of the clear button ("\${label} zurücksetzen"). Therefore, the label must not contain a verb like "Gemende auswählen". This would be confusing for screen reader users.
226
+ `,
227
+ },
228
+ },
229
+ }
230
+
231
+ export const Filled = Template.bind({})
232
+ Filled.args = {
233
+ label: "Gemeinde",
234
+ options: OPTIONS_EXAMPLES,
235
+ value: [OPTIONS_EXAMPLES[1]],
236
+ }
237
+
238
+ export const Clearable = Template.bind({})
239
+ Clearable.args = {
240
+ label: "Gemeinde",
241
+ options: OPTIONS_EXAMPLES,
242
+ value: [OPTIONS_EXAMPLES[1]],
243
+ clearable: true,
244
+ }
245
+
246
+ export const Disabled = Template.bind({})
247
+ Disabled.args = {
248
+ label: "Gemeinde",
249
+ options: OPTIONS_EXAMPLES,
250
+ clearable: true,
251
+ disabled: true,
252
+ }
253
+
254
+ export const DisabledFilled = Template.bind({})
255
+ DisabledFilled.args = {
256
+ label: "Gemeinde",
257
+ options: OPTIONS_EXAMPLES,
258
+ value: [OPTIONS_EXAMPLES[1]],
259
+ clearable: true,
260
+ disabled: true,
261
+ }
262
+
263
+ export const Filterable = Template.bind({})
264
+ Filterable.args = {
265
+ label: "Gemeinde",
266
+ options: OPTIONS_MUNICIPALITIES,
267
+ clearable: true,
268
+ disabled: false,
269
+ filterable: true,
270
+ }
271
+
272
+ /* I also tried sloting the before and after. It doesn't work because the blur event is triggered everytime a slot is clicked */
273
+ export const BeforeAfterSlot = TemplateSlots.bind({})
274
+ BeforeAfterSlot.args = {
275
+ label: "Gemeinde",
276
+ options: OPTIONS_MUNICIPALITIES,
277
+ clearable: true,
278
+ disabled: false,
279
+ filterable: false,
280
+ multiple: true,
281
+ }
282
+
283
+ export const Multiple = Template.bind({})
284
+ Multiple.args = {
285
+ label: "Gemeinde",
286
+ options: OPTIONS_MUNICIPALITIES,
287
+ clearable: true,
288
+ disabled: false,
289
+ filterable: true,
290
+ multiple: true,
291
+ }
292
+
293
+ export const MultipleFilled = Template.bind({})
294
+ MultipleFilled.args = {
295
+ label: "Gemeinde",
296
+ options: OPTIONS_MUNICIPALITIES,
297
+ value: OPTIONS_MUNICIPALITIES.slice(0, 2),
298
+ clearable: true,
299
+ disabled: false,
300
+ filterable: true,
301
+ multiple: true,
302
+ }
@@ -0,0 +1,29 @@
1
+ import { html } from "lit"
2
+ import { fixture, expect } from "@open-wc/testing"
3
+
4
+ import "../leu-select.js"
5
+
6
+ async function defaultFixture() {
7
+ return fixture(html`
8
+ <leu-select
9
+ options='[{"label":"Option 1", "value":"1"}, "Option 2", "Option 3", "Sehr lange Option um zu schauen was passiert, wenn es zu lang wird."]'
10
+ label="Label"
11
+ value=${null}
12
+ >
13
+ </leu-select>
14
+ `)
15
+ }
16
+
17
+ describe("LeuSelect", () => {
18
+ it("is a defined element", async () => {
19
+ const el = await customElements.get("leu-select")
20
+
21
+ await expect(el).not.to.be.undefined
22
+ })
23
+
24
+ it("passes the a11y audit", async () => {
25
+ const el = await defaultFixture()
26
+
27
+ await expect(el).shadowDom.to.be.accessible()
28
+ })
29
+ })
@@ -0,0 +1,301 @@
1
+ import { html, css, LitElement, nothing } from "lit"
2
+ import { classMap } from "lit/directives/class-map.js"
3
+ import { styleMap } from "lit/directives/style-map.js"
4
+ import { createRef, ref } from "lit/directives/ref.js"
5
+ import { Icon } from "../icon/icon.js"
6
+ import { defineElement } from "../../lib/defineElement.js"
7
+ import { definePaginationElements } from "../pagination/Pagination.js"
8
+
9
+ /**
10
+ * @tagname leu-table
11
+ */
12
+ export class LeuTable extends LitElement {
13
+ static styles = css`
14
+ :host {
15
+ position: relative;
16
+ display: block;
17
+ }
18
+ div.scroll {
19
+ display: inline-block;
20
+ width: 100%;
21
+ overflow: auto;
22
+ }
23
+ div.shadow {
24
+ position: absolute;
25
+ left: 0;
26
+ top: 0;
27
+ width: 100%;
28
+ height: 100%;
29
+ pointer-events: none;
30
+ z-index: 1;
31
+ }
32
+ div.pagination {
33
+ height: calc(100% - 66px);
34
+ }
35
+ table {
36
+ width: 100%;
37
+ border-spacing: 0;
38
+ color: rgb(0 0 0 / 60%);
39
+ font-size: 16px;
40
+ font-family: var(--leu-font-regular);
41
+ line-height: 1.5;
42
+ }
43
+ td {
44
+ padding: 12px;
45
+ }
46
+ th {
47
+ padding: 16px 16px 8px;
48
+ text-align: left;
49
+ font-size: 12px;
50
+ font-weight: normal;
51
+ font-family: var(--leu-font-black);
52
+ background: var(--table-even-row-bg);
53
+ }
54
+ td:first-child,
55
+ th:first-child {
56
+ left: 0;
57
+ background: inherit;
58
+ z-index: 1;
59
+ }
60
+ tr {
61
+ background: #fff;
62
+ }
63
+ tbody tr:nth-child(odd) {
64
+ background: var(--leu-color-black-5);
65
+ }
66
+ button {
67
+ background: none;
68
+ cursor: pointer;
69
+ line-height: 1.5;
70
+ padding: 0;
71
+ border: 0;
72
+ width: 100%;
73
+ display: flex;
74
+ align-items: flex-center;
75
+ font-size: inherit;
76
+ font-family: inherit;
77
+ }
78
+ thead svg {
79
+ display: inline-block;
80
+ color: var(--leu-color-accent-blue);
81
+ padding: 0;
82
+ }
83
+
84
+ table.sticky td:first-child,
85
+ table.sticky th:first-child {
86
+ position: sticky;
87
+ }
88
+ div.shadow-left table.sticky td:first-child,
89
+ div.shadow-left table.sticky th:first-child {
90
+ box-shadow: 0 0 5px rgb(0 0 0 / 50%);
91
+ clip-path: inset(0 -15px 0 0);
92
+ }
93
+ div.shadow-left {
94
+ box-shadow: inset 5px 0 5px -5px rgb(0 0 0 / 50%);
95
+ }
96
+ div.shadow-right {
97
+ box-shadow: inset -5px 0 5px -5px rgb(0 0 0 / 50%);
98
+ }
99
+ `
100
+
101
+ static properties = {
102
+ columns: { type: Array },
103
+ data: { type: Array },
104
+ firstColumnSticky: { type: Boolean },
105
+ itemsOnAPage: { type: Number },
106
+ sortIndex: { type: Number },
107
+ sortOrderAsc: { type: Boolean },
108
+ width: { type: Number },
109
+
110
+ _shadowLeft: { type: Boolean, state: true },
111
+ _shadowRight: { type: Boolean, state: true },
112
+ _min: { type: Number, state: true },
113
+ _max: { type: Number, state: true },
114
+ }
115
+
116
+ constructor() {
117
+ super()
118
+ /** @type {array} */
119
+ this.columns = []
120
+ /** @type {array} */
121
+ this.data = []
122
+ /** @type {boolean} */
123
+ this.firstColumnSticky = false
124
+ /** @type {number} */
125
+ this.itemsOnAPage = null
126
+ /** @type {number} */
127
+ this.sortIndex = null
128
+ /** @type {boolean} */
129
+ this.sortOrderAsc = false
130
+ /** @type {number} */
131
+ this.width = null
132
+
133
+ /** @internal */
134
+ this._sortArrowDown = Icon("arrowDown", 20)
135
+ /** @internal */
136
+ this._sortArrowUp = Icon("arrowUp", 20)
137
+ /** @internal */
138
+ this._shadowLeft = false
139
+ /** @internal */
140
+ this._shadowRight = false
141
+ /** @internal */
142
+ this._scrollRef = createRef()
143
+ /** @internal */
144
+ this._min = 0
145
+ /** @internal */
146
+ this._max = null
147
+ }
148
+
149
+ firstUpdated() {
150
+ this.shadowToggle(this._scrollRef.value)
151
+ }
152
+
153
+ shadowToggle(target) {
154
+ this._shadowLeft = target.scrollLeftMax > 0 && target.scrollLeft > 0
155
+ this._shadowRight =
156
+ target.scrollLeftMax > 0 && target.scrollLeft < target.scrollLeftMax
157
+ }
158
+
159
+ scrollEvent(event) {
160
+ this.shadowToggle(event.target)
161
+ }
162
+
163
+ isOnePropNotValid() {
164
+ if (!this._columns) {
165
+ return "Der Parameter 'columns' ist erforderlich !"
166
+ }
167
+ if (!this._sortedData) {
168
+ return "Der Parameter 'data' ist erforderlich !"
169
+ }
170
+ return null
171
+ }
172
+
173
+ isSorted(col) {
174
+ return this.sortIndex === this._columns.indexOf(col)
175
+ }
176
+
177
+ sortClick(col) {
178
+ const index = this._columns.indexOf(col)
179
+ if (this.sortIndex === index) {
180
+ this.sortOrderAsc = !this.sortOrderAsc
181
+ } else {
182
+ this.sortIndex = index
183
+ this.sortOrder = "asc"
184
+ }
185
+ }
186
+
187
+ sortArrowIcon() {
188
+ return html`${this.sortOrderAsc ? this._sortArrowDown : this._sortArrowUp}`
189
+ }
190
+
191
+ sortArrow(col) {
192
+ return html` ${this.isSorted(col) ? this.sortArrowIcon() : nothing} `
193
+ }
194
+
195
+ get _columns() {
196
+ return this.columns
197
+ }
198
+
199
+ get _sortedData() {
200
+ if (this.sortIndex === null || this.sortIndex === undefined) {
201
+ return this.data
202
+ }
203
+ const col = this._columns[this.sortIndex]
204
+ return this.data.sort(this.sortOrderAsc ? col.sort.asc : col.sort.desc)
205
+ }
206
+
207
+ get _data() {
208
+ return this.itemsOnAPage && this.itemsOnAPage > 0
209
+ ? this._sortedData.slice(this._min, this._max)
210
+ : this._sortedData
211
+ }
212
+
213
+ render() {
214
+ const scrollClasses = {
215
+ scroll: true,
216
+ "shadow-left": this.firstColumnSticky && this._shadowLeft,
217
+ }
218
+
219
+ const shadowClassesLeft = {
220
+ shadow: true,
221
+ "shadow-left": !this.firstColumnSticky && this._shadowLeft,
222
+ pagination: this.itemsOnAPage > 0,
223
+ }
224
+
225
+ const shadowClassesRight = {
226
+ shadow: true,
227
+ "shadow-right": this._shadowRight,
228
+ pagination: this.itemsOnAPage > 0,
229
+ }
230
+
231
+ const stickyClass = {
232
+ sticky: this.firstColumnSticky,
233
+ }
234
+
235
+ return html`
236
+ <div
237
+ class=${classMap(scrollClasses)}
238
+ @scroll="${this.scrollEvent}"
239
+ ref=${ref(this._scrollRef)}
240
+ >
241
+ <table class=${classMap(stickyClass)}>
242
+ <thead>
243
+ <tr>
244
+ ${this._columns.map(
245
+ (col) =>
246
+ html`<th>
247
+ ${col.sort
248
+ ? html`<button @click=${(_) => this.sortClick(col)}>
249
+ <span>${col.name}</span>
250
+ ${this.sortArrow(col)}
251
+ </button>`
252
+ : col.name}
253
+ </th>`
254
+ )}
255
+ </tr>
256
+ </thead>
257
+ <tbody>
258
+ ${this._data.map(
259
+ (row) =>
260
+ html`<tr>
261
+ ${this._columns.map(
262
+ (col) =>
263
+ html`<td
264
+ style=${col.style ? styleMap(col.style(row)) : nothing}
265
+ >
266
+ ${col.value(row)}
267
+ </td>`
268
+ )}
269
+ </tr>`
270
+ )}
271
+ </tbody>
272
+ </table>
273
+ <div class=${classMap(shadowClassesLeft)}></div>
274
+ <div class=${classMap(shadowClassesRight)}></div>
275
+ </div>
276
+
277
+ ${this.itemsOnAPage > 0
278
+ ? html`
279
+ <leu-pagination
280
+ .dataLength=${this._sortedData.length}
281
+ .itemsOnAPage=${this.itemsOnAPage}
282
+ @range-updated=${(e) => {
283
+ this._min = e.detail.min
284
+ this._max = e.detail.max
285
+ // after render
286
+ setTimeout(() => {
287
+ this.shadowToggle(this._scrollRef.value)
288
+ }, 0)
289
+ }}
290
+ >
291
+ </leu-pagination>
292
+ `
293
+ : nothing}
294
+ `
295
+ }
296
+ }
297
+
298
+ export function defineTableElements() {
299
+ definePaginationElements()
300
+ defineElement("table", LeuTable)
301
+ }
@@ -0,0 +1,3 @@
1
+ import { defineTableElements } from "./Table.js"
2
+
3
+ defineTableElements()