@statistikzh/leu 0.0.2 → 0.2.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 (59) hide show
  1. package/.github/workflows/release-please.yml +20 -1
  2. package/CHANGELOG.md +30 -0
  3. package/README.md +27 -2
  4. package/babel.config.json +3 -0
  5. package/dist/{Button-83c6df93.js → Button.js} +58 -50
  6. package/dist/ButtonGroup.js +75 -0
  7. package/dist/Checkbox.js +60 -57
  8. package/dist/CheckboxGroup.js +35 -41
  9. package/dist/{Chip-60af1402.js → Chip-389013ff.js} +12 -13
  10. package/dist/ChipGroup.js +27 -34
  11. package/dist/ChipLink.js +18 -19
  12. package/dist/ChipRemovable.js +9 -13
  13. package/dist/ChipSelectable.js +42 -44
  14. package/dist/Dropdown.js +75 -0
  15. package/dist/Input.js +120 -122
  16. package/dist/Menu.js +40 -0
  17. package/dist/MenuItem.js +171 -0
  18. package/dist/Pagination.js +193 -0
  19. package/dist/Radio.js +26 -22
  20. package/dist/RadioGroup.js +75 -105
  21. package/dist/Select.js +125 -343
  22. package/dist/Table.js +294 -8
  23. package/dist/defineElement-ba770aed.js +44 -0
  24. package/dist/icon-03e86700.js +136 -0
  25. package/dist/index.js +14 -9
  26. package/dist/leu-button-group.js +8 -0
  27. package/dist/leu-button.js +7 -0
  28. package/dist/leu-checkbox-group.js +1 -1
  29. package/dist/leu-checkbox.js +2 -2
  30. package/dist/leu-chip-group.js +1 -1
  31. package/dist/leu-chip-link.js +2 -2
  32. package/dist/leu-chip-removable.js +3 -3
  33. package/dist/leu-chip-selectable.js +2 -2
  34. package/dist/leu-dropdown.js +10 -0
  35. package/dist/leu-input.js +2 -2
  36. package/dist/leu-menu-item.js +6 -0
  37. package/dist/leu-menu.js +5 -0
  38. package/dist/leu-pagination.js +8 -0
  39. package/dist/leu-radio-group.js +1 -1
  40. package/dist/leu-radio.js +1 -1
  41. package/dist/leu-select.js +5 -3
  42. package/dist/leu-table.js +5 -4
  43. package/dist/theme.css +7 -7
  44. package/index.js +7 -3
  45. package/package.json +3 -1
  46. package/rollup.config.js +26 -9
  47. package/src/components/accordion/Accordion.js +102 -0
  48. package/src/components/accordion/accordion.css +160 -0
  49. package/src/components/accordion/leu-accordion.js +3 -0
  50. package/src/components/accordion/stories/accordion.stories.js +55 -0
  51. package/src/components/accordion/test/accordion.test.js +22 -0
  52. package/src/components/input/Input.js +10 -0
  53. package/src/components/menu/menu.css +9 -3
  54. package/src/components/select/Select.js +28 -8
  55. package/src/styles/custom-properties.css +7 -7
  56. package/.github/workflows/publish.yml +0 -19
  57. package/dist/Table-72d305d7.js +0 -506
  58. package/dist/defineElement-47d4f665.js +0 -15
  59. package/dist/icon-b68c7e1e.js +0 -202
@@ -74,9 +74,19 @@ export class LeuSelect extends LitElement {
74
74
  this.toggleButtonRef = createRef()
75
75
  }
76
76
 
77
+ connectedCallback() {
78
+ super.connectedCallback()
79
+ document.addEventListener("click", this.handleDocumentClick)
80
+ }
81
+
82
+ disconnectedCallback() {
83
+ super.disconnectedCallback()
84
+ document.removeEventListener("click", this.handleDocumentClick)
85
+ }
86
+
77
87
  updated(changedProperties) {
78
88
  if (changedProperties.has("open") && this.open) {
79
- if (this.multiple) {
89
+ if (this.filterable) {
80
90
  this.optionFilterRef.value.focus()
81
91
  } else {
82
92
  this.menuRef.value.focus()
@@ -86,6 +96,17 @@ export class LeuSelect extends LitElement {
86
96
  }
87
97
  }
88
98
 
99
+ /**
100
+ * Handles clicks outside of the component to close the dropdown.
101
+ * @internal
102
+ * @param {MouseEvent} event
103
+ */
104
+ handleDocumentClick = (event) => {
105
+ if (!this.contains(event.target) && this.open) {
106
+ this.closeDropdown()
107
+ }
108
+ }
109
+
89
110
  /**
90
111
  * @internal
91
112
  * @param {KeyboardEvent} e
@@ -143,12 +164,6 @@ export class LeuSelect extends LitElement {
143
164
  this.emitUpdateEvents()
144
165
  }
145
166
 
146
- clearOptionFilter() {
147
- // refocus before removing the button, otherwise closeDropdown is triggered
148
- this.optionFilterRef.value.focus()
149
- this.optionFilter = ""
150
- }
151
-
152
167
  toggleDropdown() {
153
168
  if (!this.disabled) {
154
169
  this.open = !this.open
@@ -242,7 +257,11 @@ export class LeuSelect extends LitElement {
242
257
  ${LeuSelect.getOptionLabel(option)}
243
258
  </leu-menu-item>`
244
259
  })
245
- : html`<leu-menu-item disabled>Keine Resultate</leu-menu-item>`}
260
+ : html`<leu-menu-item disabled
261
+ >${this.optionFilter === ""
262
+ ? "Keine Optionen"
263
+ : "Keine Resultate"}</leu-menu-item
264
+ >`}
246
265
  </leu-menu>
247
266
  `
248
267
  }
@@ -254,6 +273,7 @@ export class LeuSelect extends LitElement {
254
273
  size="small"
255
274
  @input=${this.handleFilterInput}
256
275
  clearable
276
+ ref=${ref(this.optionFilterRef)}
257
277
  >Nach Stichwort filtern</leu-input
258
278
  >`
259
279
  }
@@ -29,13 +29,13 @@
29
29
  --leu-color-accent-violet: #7f3da7;
30
30
  --leu-color-accent-gray: var(--leu-color-black-60);
31
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;
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
39
  --leu-color-accent-gray-soft: var(--leu-color-black-10);
40
40
 
41
41
  --leu-color-func-cyan: #009ee0;
@@ -1,19 +0,0 @@
1
- name: Publish Package to npmjs
2
- on:
3
- release:
4
- types: [published]
5
- jobs:
6
- build:
7
- runs-on: ubuntu-latest
8
- steps:
9
- - uses: actions/checkout@v4
10
- # Setup .npmrc file to publish to npm
11
- - uses: actions/setup-node@v3
12
- with:
13
- node-version: "20.x"
14
- registry-url: "https://registry.npmjs.org"
15
- - run: npm ci
16
- - run: npm run build
17
- - run: npm publish --access public
18
- env:
19
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
@@ -1,506 +0,0 @@
1
- import { css, LitElement, html, 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 { I as Icon } from './icon-b68c7e1e.js';
6
- import { d as defineElement } from './defineElement-47d4f665.js';
7
- import { d as defineButtonElements } from './Button-83c6df93.js';
8
-
9
- var css_248z = css`:host {
10
- margin-top: 16px;
11
- display: flex;
12
- justify-content: end;
13
- font-family: var(--leu-font-regular);
14
- }
15
-
16
- .input {
17
- width: 50px;
18
- padding: 0;
19
- border: 2px solid var(--leu-color-black-40);
20
- border-radius: 2px;
21
- color: var(--leu-color-black-transp-60);
22
- text-align: center;
23
- font-size: 16px;
24
- font-style: normal;
25
- font-weight: 400;
26
- line-height: 24px;
27
- outline-offset: 2px;
28
- }
29
-
30
- /* no arrows: Chrome, Safari, Edge, Opera */
31
-
32
- .input::-webkit-outer-spin-button,
33
- .input::-webkit-inner-spin-button {
34
- -webkit-appearance: none;
35
- appearance: none;
36
- margin: 0;
37
- }
38
-
39
- /* no arrows: Firefox */
40
-
41
- .input[type="number"] {
42
- -webkit-appearance: textfield;
43
- -moz-appearance: textfield;
44
- appearance: textfield;
45
- }
46
-
47
- .input:focus,
48
- .input:hover {
49
- border-color: var(--leu-color-func-cyan);
50
- outline: none;
51
- }
52
-
53
- .input:focus-visible {
54
- outline: 2px solid var(--leu-color-func-cyan);
55
- }
56
-
57
- .label {
58
- margin: 0 16px;
59
- line-height: 50px;
60
- color: var(--leu-color-black-transp-60);
61
- white-space: nowrap;
62
- }
63
- `;
64
-
65
- const MIN_PAGE = 1;
66
-
67
- /**
68
- * @tagname leu-pagination
69
- */
70
- class LeuPagination extends LitElement {
71
- static styles = css_248z
72
-
73
- static events = {
74
- range: {},
75
- }
76
-
77
- static properties = {
78
- page: { type: Number, reflect: true },
79
- itemsOnAPage: { type: Number },
80
- dataLength: { type: Number },
81
-
82
- _minPage: { type: Number, state: true },
83
- }
84
-
85
- constructor() {
86
- super();
87
- /** @type {number} */
88
- this.page = 1;
89
- /** @type {number} */
90
- this.dataLength = 0;
91
- /** @type {number} */
92
- this.itemsOnAPage = 30;
93
- }
94
-
95
- get maxPage() {
96
- return Math.ceil(this.dataLength / this.itemsOnAPage)
97
- }
98
-
99
- get firstPage() {
100
- return this.page === MIN_PAGE
101
- }
102
-
103
- get lastPage() {
104
- return this.page === this.maxPage
105
- }
106
-
107
- holdInRange(value) {
108
- return Math.min(Math.max(value, MIN_PAGE), this.maxPage)
109
- }
110
-
111
- numberUpdate(number) {
112
- this.page = this.holdInRange(number);
113
-
114
- const min = (this.page - 1) * this.itemsOnAPage;
115
- const max = Math.min(min + this.itemsOnAPage, this.dataLength);
116
- this.dispatchEvent(
117
- new CustomEvent("range-updated", {
118
- detail: {
119
- min,
120
- max,
121
- },
122
- bubbles: false,
123
- })
124
- );
125
- }
126
-
127
- change(event) {
128
- // target.value = this.page // eslint-disable-line
129
- this.numberUpdate(parseInt(event.target.value, 10) || 0);
130
- }
131
-
132
- input(event) {
133
- if (event.target.value !== "") {
134
- event.preventDefault();
135
- this.change(event);
136
- }
137
- }
138
-
139
- keydown(event) {
140
- const specialKeys = [
141
- "ArrowUp",
142
- "ArrowDown",
143
- "ArrowLeft",
144
- "ArrowRight",
145
- "Backspace",
146
- "Enter",
147
- "Tab",
148
- ];
149
- const numberKeys = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"];
150
- if (!numberKeys.includes(event.key) && !specialKeys.includes(event.key)) {
151
- event.preventDefault();
152
- } else {
153
- if (event.key === "ArrowUp") {
154
- event.preventDefault();
155
- this.numberUpdate(this.page + 1);
156
- }
157
- if (event.key === "ArrowDown") {
158
- event.preventDefault();
159
- this.numberUpdate(this.page - 1);
160
- }
161
- }
162
- }
163
-
164
- firstUpdated() {
165
- this.numberUpdate(this.page);
166
- }
167
-
168
- requestUpdate(name, oldValue, newValue) {
169
- if (name === "itemsOnAPage") {
170
- this.numberUpdate(this.page);
171
- }
172
- return super.requestUpdate(name, oldValue, newValue)
173
- }
174
-
175
- render() {
176
- return html`
177
- <input
178
- class="input"
179
- .value=${this.page}
180
- @input=${this.input}
181
- @change=${this.change}
182
- @keydown=${this.keydown}
183
- type="number"
184
- />
185
- <div class="label">von ${this.maxPage}</div>
186
- <leu-button
187
- icon="angleLeft"
188
- variant="secondary"
189
- @click=${(_) => {
190
- this.numberUpdate(this.page - 1);
191
- }}
192
- ?disabled=${this.firstPage}
193
- ></leu-button>
194
- <leu-button
195
- icon="angleRight"
196
- variant="secondary"
197
- @click=${(_) => {
198
- this.numberUpdate(this.page + 1);
199
- }}
200
- ?disabled=${this.lastPage}
201
- style="margin-left:4px;"
202
- ></leu-button>
203
- `
204
- }
205
- }
206
-
207
- function definePaginationElements() {
208
- defineButtonElements();
209
- defineElement("pagination", LeuPagination);
210
- }
211
-
212
- /**
213
- * @tagname leu-table
214
- */
215
- class LeuTable extends LitElement {
216
- static styles = css`
217
- :host {
218
- position: relative;
219
- display: block;
220
- }
221
- div.scroll {
222
- display: inline-block;
223
- width: 100%;
224
- overflow: auto;
225
- }
226
- div.shadow {
227
- position: absolute;
228
- left: 0;
229
- top: 0;
230
- width: 100%;
231
- height: 100%;
232
- pointer-events: none;
233
- z-index: 1;
234
- }
235
- div.pagination {
236
- height: calc(100% - 66px);
237
- }
238
- table {
239
- width: 100%;
240
- border-spacing: 0;
241
- color: rgb(0 0 0 / 60%);
242
- font-size: 16px;
243
- font-family: var(--leu-font-regular);
244
- line-height: 1.5;
245
- }
246
- td {
247
- padding: 12px;
248
- }
249
- th {
250
- padding: 16px 16px 8px;
251
- text-align: left;
252
- font-size: 12px;
253
- font-weight: normal;
254
- font-family: var(--leu-font-black);
255
- background: var(--table-even-row-bg);
256
- }
257
- td:first-child,
258
- th:first-child {
259
- left: 0;
260
- background: inherit;
261
- z-index: 1;
262
- }
263
- tr {
264
- background: #fff;
265
- }
266
- tbody tr:nth-child(odd) {
267
- background: var(--leu-color-black-5);
268
- }
269
- button {
270
- background: none;
271
- cursor: pointer;
272
- line-height: 1.5;
273
- padding: 0;
274
- border: 0;
275
- width: 100%;
276
- display: flex;
277
- align-items: flex-center;
278
- font-size: inherit;
279
- font-family: inherit;
280
- }
281
- thead svg {
282
- display: inline-block;
283
- color: var(--leu-color-accent-blue);
284
- padding: 0;
285
- }
286
-
287
- table.sticky td:first-child,
288
- table.sticky th:first-child {
289
- position: sticky;
290
- }
291
- div.shadow-left table.sticky td:first-child,
292
- div.shadow-left table.sticky th:first-child {
293
- box-shadow: 0 0 5px rgb(0 0 0 / 50%);
294
- clip-path: inset(0 -15px 0 0);
295
- }
296
- div.shadow-left {
297
- box-shadow: inset 5px 0 5px -5px rgb(0 0 0 / 50%);
298
- }
299
- div.shadow-right {
300
- box-shadow: inset -5px 0 5px -5px rgb(0 0 0 / 50%);
301
- }
302
- `
303
-
304
- static properties = {
305
- columns: { type: Array },
306
- data: { type: Array },
307
- firstColumnSticky: { type: Boolean },
308
- itemsOnAPage: { type: Number },
309
- sortIndex: { type: Number },
310
- sortOrderAsc: { type: Boolean },
311
- width: { type: Number },
312
-
313
- _shadowLeft: { type: Boolean, state: true },
314
- _shadowRight: { type: Boolean, state: true },
315
- _min: { type: Number, state: true },
316
- _max: { type: Number, state: true },
317
- }
318
-
319
- constructor() {
320
- super();
321
- /** @type {array} */
322
- this.columns = [];
323
- /** @type {array} */
324
- this.data = [];
325
- /** @type {boolean} */
326
- this.firstColumnSticky = false;
327
- /** @type {number} */
328
- this.itemsOnAPage = null;
329
- /** @type {number} */
330
- this.sortIndex = null;
331
- /** @type {boolean} */
332
- this.sortOrderAsc = false;
333
- /** @type {number} */
334
- this.width = null;
335
-
336
- /** @internal */
337
- this._sortArrowDown = Icon("arrowDown", 20);
338
- /** @internal */
339
- this._sortArrowUp = Icon("arrowUp", 20);
340
- /** @internal */
341
- this._shadowLeft = false;
342
- /** @internal */
343
- this._shadowRight = false;
344
- /** @internal */
345
- this._scrollRef = createRef();
346
- /** @internal */
347
- this._min = 0;
348
- /** @internal */
349
- this._max = null;
350
- }
351
-
352
- firstUpdated() {
353
- this.shadowToggle(this._scrollRef.value);
354
- }
355
-
356
- shadowToggle(target) {
357
- this._shadowLeft = target.scrollLeftMax > 0 && target.scrollLeft > 0;
358
- this._shadowRight =
359
- target.scrollLeftMax > 0 && target.scrollLeft < target.scrollLeftMax;
360
- }
361
-
362
- scrollEvent(event) {
363
- this.shadowToggle(event.target);
364
- }
365
-
366
- isOnePropNotValid() {
367
- if (!this._columns) {
368
- return "Der Parameter 'columns' ist erforderlich !"
369
- }
370
- if (!this._sortedData) {
371
- return "Der Parameter 'data' ist erforderlich !"
372
- }
373
- return null
374
- }
375
-
376
- isSorted(col) {
377
- return this.sortIndex === this._columns.indexOf(col)
378
- }
379
-
380
- sortClick(col) {
381
- const index = this._columns.indexOf(col);
382
- if (this.sortIndex === index) {
383
- this.sortOrderAsc = !this.sortOrderAsc;
384
- } else {
385
- this.sortIndex = index;
386
- this.sortOrder = "asc";
387
- }
388
- }
389
-
390
- sortArrowIcon() {
391
- return html`${this.sortOrderAsc ? this._sortArrowDown : this._sortArrowUp}`
392
- }
393
-
394
- sortArrow(col) {
395
- return html` ${this.isSorted(col) ? this.sortArrowIcon() : nothing} `
396
- }
397
-
398
- get _columns() {
399
- return this.columns
400
- }
401
-
402
- get _sortedData() {
403
- if (this.sortIndex === null || this.sortIndex === undefined) {
404
- return this.data
405
- }
406
- const col = this._columns[this.sortIndex];
407
- return this.data.sort(this.sortOrderAsc ? col.sort.asc : col.sort.desc)
408
- }
409
-
410
- get _data() {
411
- return this.itemsOnAPage && this.itemsOnAPage > 0
412
- ? this._sortedData.slice(this._min, this._max)
413
- : this._sortedData
414
- }
415
-
416
- render() {
417
- const scrollClasses = {
418
- scroll: true,
419
- "shadow-left": this.firstColumnSticky && this._shadowLeft,
420
- };
421
-
422
- const shadowClassesLeft = {
423
- shadow: true,
424
- "shadow-left": !this.firstColumnSticky && this._shadowLeft,
425
- pagination: this.itemsOnAPage > 0,
426
- };
427
-
428
- const shadowClassesRight = {
429
- shadow: true,
430
- "shadow-right": this._shadowRight,
431
- pagination: this.itemsOnAPage > 0,
432
- };
433
-
434
- const stickyClass = {
435
- sticky: this.firstColumnSticky,
436
- };
437
-
438
- return html`
439
- <div
440
- class=${classMap(scrollClasses)}
441
- @scroll="${this.scrollEvent}"
442
- ref=${ref(this._scrollRef)}
443
- >
444
- <table class=${classMap(stickyClass)}>
445
- <thead>
446
- <tr>
447
- ${this._columns.map(
448
- (col) =>
449
- html`<th>
450
- ${col.sort
451
- ? html`<button @click=${(_) => this.sortClick(col)}>
452
- <span>${col.name}</span>
453
- ${this.sortArrow(col)}
454
- </button>`
455
- : col.name}
456
- </th>`
457
- )}
458
- </tr>
459
- </thead>
460
- <tbody>
461
- ${this._data.map(
462
- (row) =>
463
- html`<tr>
464
- ${this._columns.map(
465
- (col) =>
466
- html`<td
467
- style=${col.style ? styleMap(col.style(row)) : nothing}
468
- >
469
- ${col.value(row)}
470
- </td>`
471
- )}
472
- </tr>`
473
- )}
474
- </tbody>
475
- </table>
476
- <div class=${classMap(shadowClassesLeft)}></div>
477
- <div class=${classMap(shadowClassesRight)}></div>
478
- </div>
479
-
480
- ${this.itemsOnAPage > 0
481
- ? html`
482
- <leu-pagination
483
- .dataLength=${this._sortedData.length}
484
- .itemsOnAPage=${this.itemsOnAPage}
485
- @range-updated=${(e) => {
486
- this._min = e.detail.min;
487
- this._max = e.detail.max;
488
- // after render
489
- setTimeout(() => {
490
- this.shadowToggle(this._scrollRef.value);
491
- }, 0);
492
- }}
493
- >
494
- </leu-pagination>
495
- `
496
- : nothing}
497
- `
498
- }
499
- }
500
-
501
- function defineTableElements() {
502
- definePaginationElements();
503
- defineElement("table", LeuTable);
504
- }
505
-
506
- export { LeuPagination as L, LeuTable as a, defineTableElements as b, definePaginationElements as d };
@@ -1,15 +0,0 @@
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
- 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
- }
14
-
15
- export { defineElement as d };