@limetech/lime-elements 39.45.3 → 40.0.1
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.
- package/CHANGELOG.md +29 -0
- package/dist/cjs/lime-elements.cjs.js +1 -1
- package/dist/cjs/limel-action-bar_3.cjs.entry.js +1 -1
- package/dist/cjs/limel-ai-avatar.cjs.entry.js +1 -1
- package/dist/cjs/limel-callout.cjs.entry.js +1 -1
- package/dist/cjs/limel-chart.cjs.entry.js +1 -1
- package/dist/cjs/limel-chip-set.cjs.entry.js +1 -1
- package/dist/cjs/limel-chip_2.cjs.entry.js +1 -1
- package/dist/cjs/limel-code-diff.cjs.entry.js +1 -1
- package/dist/cjs/limel-code-editor.cjs.entry.js +1 -1
- package/dist/cjs/limel-collapsible-section.cjs.entry.js +1 -1
- package/dist/cjs/limel-drag-handle.cjs.entry.js +1 -1
- package/dist/cjs/limel-email-viewer.cjs.entry.js +1 -1
- package/dist/cjs/limel-file-viewer.cjs.entry.js +1 -1
- package/dist/cjs/limel-file.cjs.entry.js +1 -1
- package/dist/cjs/limel-flatpickr-adapter.cjs.entry.js +1 -1
- package/dist/cjs/limel-list-item.cjs.entry.js +2 -2
- package/dist/cjs/limel-picker.cjs.entry.js +1 -1
- package/dist/cjs/limel-profile-picture.cjs.entry.js +1 -1
- package/dist/cjs/limel-prosemirror-adapter.cjs.entry.js +40 -40
- package/dist/cjs/limel-slider.cjs.entry.js +140 -16
- package/dist/cjs/limel-snackbar.cjs.entry.js +1 -1
- package/dist/cjs/limel-table.cjs.entry.js +1 -1
- package/dist/cjs/limel-text-editor-link-menu.cjs.entry.js +1 -1
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/cjs/{translations-Bnw00bkf.js → translations-Do_D3pxu.js} +39 -2
- package/dist/collection/components/list-item/list-item.css +18 -2
- package/dist/collection/components/slider/slider.css +95 -0
- package/dist/collection/components/slider/slider.js +174 -21
- package/dist/collection/global/translations.js +15 -2
- package/dist/collection/translations/da.js +3 -0
- package/dist/collection/translations/de.js +3 -0
- package/dist/collection/translations/en.js +3 -0
- package/dist/collection/translations/fi.js +3 -0
- package/dist/collection/translations/fr.js +3 -0
- package/dist/collection/translations/nl.js +3 -0
- package/dist/collection/translations/no.js +3 -0
- package/dist/collection/translations/sv.js +3 -0
- package/dist/esm/lime-elements.js +1 -1
- package/dist/esm/limel-action-bar_3.entry.js +1 -1
- package/dist/esm/limel-ai-avatar.entry.js +1 -1
- package/dist/esm/limel-callout.entry.js +1 -1
- package/dist/esm/limel-chart.entry.js +1 -1
- package/dist/esm/limel-chip-set.entry.js +1 -1
- package/dist/esm/limel-chip_2.entry.js +1 -1
- package/dist/esm/limel-code-diff.entry.js +1 -1
- package/dist/esm/limel-code-editor.entry.js +1 -1
- package/dist/esm/limel-collapsible-section.entry.js +1 -1
- package/dist/esm/limel-drag-handle.entry.js +1 -1
- package/dist/esm/limel-email-viewer.entry.js +1 -1
- package/dist/esm/limel-file-viewer.entry.js +1 -1
- package/dist/esm/limel-file.entry.js +1 -1
- package/dist/esm/limel-flatpickr-adapter.entry.js +1 -1
- package/dist/esm/limel-list-item.entry.js +2 -2
- package/dist/esm/limel-picker.entry.js +1 -1
- package/dist/esm/limel-profile-picture.entry.js +1 -1
- package/dist/esm/limel-prosemirror-adapter.entry.js +40 -40
- package/dist/esm/limel-slider.entry.js +140 -16
- package/dist/esm/limel-snackbar.entry.js +1 -1
- package/dist/esm/limel-table.entry.js +1 -1
- package/dist/esm/limel-text-editor-link-menu.entry.js +1 -1
- package/dist/esm/loader.js +1 -1
- package/dist/esm/{translations-Cb9R_zmF.js → translations-DgqE77nk.js} +39 -2
- package/dist/lime-elements/lime-elements.esm.js +1 -1
- package/dist/lime-elements/{p-84526b93.entry.js → p-3e316685.entry.js} +1 -1
- package/dist/lime-elements/{p-c8116a01.entry.js → p-565f688a.entry.js} +1 -1
- package/dist/lime-elements/{p-aa080a8f.entry.js → p-5dde5d72.entry.js} +1 -1
- package/dist/lime-elements/{p-31713caf.entry.js → p-5e432a44.entry.js} +1 -1
- package/dist/lime-elements/{p-4a09fb2e.entry.js → p-62a25deb.entry.js} +1 -1
- package/dist/lime-elements/{p-8aa4a38e.entry.js → p-72a1d432.entry.js} +1 -1
- package/dist/lime-elements/{p-9a04a686.entry.js → p-83bdbaf7.entry.js} +1 -1
- package/dist/lime-elements/{p-2f223e46.entry.js → p-8b3b7505.entry.js} +1 -1
- package/dist/lime-elements/{p-ca0b86ee.entry.js → p-8c3798ee.entry.js} +1 -1
- package/dist/lime-elements/{p-8aeeeb53.entry.js → p-8cf79fa1.entry.js} +1 -1
- package/dist/lime-elements/{p-7487d65d.entry.js → p-9ed9d0de.entry.js} +1 -1
- package/dist/lime-elements/p-DgqE77nk.js +1 -0
- package/dist/lime-elements/{p-2284caa7.entry.js → p-a6500046.entry.js} +1 -1
- package/dist/lime-elements/{p-e545c9e8.entry.js → p-b04c6602.entry.js} +1 -1
- package/dist/lime-elements/{p-d97df2cd.entry.js → p-b4b43404.entry.js} +1 -1
- package/dist/lime-elements/p-b6528083.entry.js +1 -0
- package/dist/lime-elements/{p-6722e6e2.entry.js → p-cafebc7d.entry.js} +1 -1
- package/dist/lime-elements/{p-2e5d5e79.entry.js → p-dd116bb1.entry.js} +1 -1
- package/dist/lime-elements/{p-d7bb4310.entry.js → p-dda63b8b.entry.js} +1 -1
- package/dist/lime-elements/{p-7f7e2180.entry.js → p-e8783848.entry.js} +1 -1
- package/dist/lime-elements/{p-19c81ded.entry.js → p-eeddce38.entry.js} +1 -1
- package/dist/lime-elements/{p-9ae7d11b.entry.js → p-f53d8bda.entry.js} +1 -1
- package/dist/lime-elements/{p-03fd2181.entry.js → p-fa4edcf5.entry.js} +1 -1
- package/dist/types/components/slider/slider.d.ts +67 -4
- package/dist/types/components.d.ts +25 -10
- package/dist/types/translations/da.d.ts +3 -0
- package/dist/types/translations/de.d.ts +3 -0
- package/dist/types/translations/en.d.ts +3 -0
- package/dist/types/translations/fi.d.ts +3 -0
- package/dist/types/translations/fr.d.ts +3 -0
- package/dist/types/translations/nl.d.ts +3 -0
- package/dist/types/translations/no.d.ts +3 -0
- package/dist/types/translations/sv.d.ts +3 -0
- package/package.json +8 -8
- package/dist/lime-elements/p-Cb9R_zmF.js +0 -1
- package/dist/lime-elements/p-ee58f0b4.entry.js +0 -1
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var da = {
|
|
4
|
+
'clear-value': 'Ryd værdi',
|
|
5
|
+
'clear-value-of': 'Ryd værdien for { label }',
|
|
6
|
+
'value-not-set': 'Værdi ikke angivet',
|
|
4
7
|
remove: 'Fjern',
|
|
5
8
|
save: 'Gem',
|
|
6
9
|
cancel: 'Annullér',
|
|
@@ -119,6 +122,9 @@ Du kan fortsætte med at blokere billeder (e-mailen kan se ufuldstændig ud) ell
|
|
|
119
122
|
};
|
|
120
123
|
|
|
121
124
|
var de = {
|
|
125
|
+
'clear-value': 'Wert löschen',
|
|
126
|
+
'clear-value-of': 'Wert von { label } löschen',
|
|
127
|
+
'value-not-set': 'Wert nicht festgelegt',
|
|
122
128
|
remove: 'Entfernen',
|
|
123
129
|
save: 'Speichern',
|
|
124
130
|
cancel: 'Abbrechen',
|
|
@@ -237,6 +243,9 @@ Sie können Bilder weiterhin blockieren (die E-Mail kann unvollständig aussehen
|
|
|
237
243
|
};
|
|
238
244
|
|
|
239
245
|
var en = {
|
|
246
|
+
'clear-value': 'Clear value',
|
|
247
|
+
'clear-value-of': 'Clear value of { label }',
|
|
248
|
+
'value-not-set': 'Value not set',
|
|
240
249
|
remove: 'Remove',
|
|
241
250
|
save: 'Save',
|
|
242
251
|
cancel: 'Cancel',
|
|
@@ -355,6 +364,9 @@ You can keep images blocked (the email may look incomplete), or load them if you
|
|
|
355
364
|
};
|
|
356
365
|
|
|
357
366
|
var fi = {
|
|
367
|
+
'clear-value': 'Tyhjennä arvo',
|
|
368
|
+
'clear-value-of': 'Tyhjennä kentän { label } arvo',
|
|
369
|
+
'value-not-set': 'Arvoa ei asetettu',
|
|
358
370
|
remove: 'Poista',
|
|
359
371
|
save: 'Tallenna',
|
|
360
372
|
cancel: 'Peruuta',
|
|
@@ -473,6 +485,9 @@ Voit pitää kuvat estettyinä (sähköposti voi näyttää puutteelliselta) tai
|
|
|
473
485
|
};
|
|
474
486
|
|
|
475
487
|
var fr = {
|
|
488
|
+
'clear-value': 'Effacer la valeur',
|
|
489
|
+
'clear-value-of': 'Effacer la valeur de { label }',
|
|
490
|
+
'value-not-set': 'Valeur non définie',
|
|
476
491
|
remove: 'Supprimer',
|
|
477
492
|
save: 'Enregistrer',
|
|
478
493
|
cancel: 'Annuler',
|
|
@@ -591,6 +606,9 @@ Vous pouvez laisser les images bloquées (l'e-mail peut sembler incomplet) ou le
|
|
|
591
606
|
};
|
|
592
607
|
|
|
593
608
|
var nl = {
|
|
609
|
+
'clear-value': 'Waarde wissen',
|
|
610
|
+
'clear-value-of': 'Waarde van { label } wissen',
|
|
611
|
+
'value-not-set': 'Waarde niet ingesteld',
|
|
594
612
|
remove: 'Verwijder',
|
|
595
613
|
save: 'Opslaan',
|
|
596
614
|
cancel: 'Annuleren',
|
|
@@ -709,6 +727,9 @@ Je kunt afbeeldingen geblokkeerd houden (de e-mail kan er onvolledig uitzien) of
|
|
|
709
727
|
};
|
|
710
728
|
|
|
711
729
|
var no = {
|
|
730
|
+
'clear-value': 'Tøm verdi',
|
|
731
|
+
'clear-value-of': 'Tøm verdien for { label }',
|
|
732
|
+
'value-not-set': 'Verdi ikke angitt',
|
|
712
733
|
remove: 'Fjerne',
|
|
713
734
|
save: 'Lagre',
|
|
714
735
|
cancel: 'Avbryt',
|
|
@@ -827,6 +848,9 @@ Du kan fortsette å blokkere bilder (e-posten kan se ufullstendig ut), eller las
|
|
|
827
848
|
};
|
|
828
849
|
|
|
829
850
|
var sv = {
|
|
851
|
+
'clear-value': 'Rensa värde',
|
|
852
|
+
'clear-value-of': 'Rensa värdet för { label }',
|
|
853
|
+
'value-not-set': 'Värde inte angivet',
|
|
830
854
|
remove: 'Ta bort',
|
|
831
855
|
save: 'Spara',
|
|
832
856
|
cancel: 'Avbryt',
|
|
@@ -951,18 +975,31 @@ const allTranslations = {
|
|
|
951
975
|
fi: fi,
|
|
952
976
|
fr: fr,
|
|
953
977
|
no: no,
|
|
978
|
+
nb: no, // Norwegian Bokmål shares the Norwegian (`no`) translations
|
|
954
979
|
nl: nl,
|
|
955
980
|
sv: sv,
|
|
956
981
|
};
|
|
957
982
|
const REGEX = /\{\s*(\w+)\s*\}/g;
|
|
958
983
|
class Translations {
|
|
959
984
|
get(key, language = 'en', params) {
|
|
960
|
-
|
|
985
|
+
var _a, _b;
|
|
986
|
+
// Fall back to English when the requested language has no translations.
|
|
987
|
+
// The `language` props are typed, but a custom element takes whatever
|
|
988
|
+
// string an attribute carries, so an unknown language must never make a
|
|
989
|
+
// component throw.
|
|
990
|
+
const languageTranslations = (_a = allTranslations[language]) !== null && _a !== void 0 ? _a : allTranslations.en;
|
|
991
|
+
// Fall back per key as well: a mapped language whose file is missing
|
|
992
|
+
// this one key would otherwise render the key itself as UI text.
|
|
993
|
+
const translation = (_b = languageTranslations[key]) !== null && _b !== void 0 ? _b : allTranslations.en[key];
|
|
961
994
|
if (!translation) {
|
|
962
995
|
return key;
|
|
963
996
|
}
|
|
964
997
|
return translation.replaceAll(REGEX, (match, mergeCodeKey) => {
|
|
965
|
-
|
|
998
|
+
var _a;
|
|
999
|
+
// Nullish, not falsy: `0` and `false` are values a caller can
|
|
1000
|
+
// legitimately merge in, and `||` would leave the merge code
|
|
1001
|
+
// itself in the string instead.
|
|
1002
|
+
return String((_a = params === null || params === void 0 ? void 0 : params[mergeCodeKey]) !== null && _a !== void 0 ? _a : match);
|
|
966
1003
|
});
|
|
967
1004
|
}
|
|
968
1005
|
}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* @prop --limel-list-item-menu-order: Defines the order of the menu, within the list item's flexbox. Defaults to `3`.
|
|
6
6
|
* @prop --list-item-image-border-radius: Defines the border radius of the list item image. Defaults to `50%`.
|
|
7
7
|
* @prop --list-item-image-object-fit: Defines the object-fit property of the list item image. Defaults to `cover`.
|
|
8
|
+
* @prop --limel-list-item-image-size: Defines the size of the list item image. Defaults to `2rem`.
|
|
8
9
|
*/
|
|
9
10
|
/**
|
|
10
11
|
* Note! This file is forwarded via `src/style/exports.scss`
|
|
@@ -110,6 +111,7 @@
|
|
|
110
111
|
* @prop --limel-list-item-menu-order: Defines the order of the menu, within the list item's flexbox. Defaults to `3`.
|
|
111
112
|
* @prop --list-item-image-border-radius: Defines the border radius of the list item image. Defaults to `50%`.
|
|
112
113
|
* @prop --list-item-image-object-fit: Defines the object-fit property of the list item image. Defaults to `cover`.
|
|
114
|
+
* @prop --limel-list-item-image-size: Defines the size of the list item image. Defaults to `2rem`.
|
|
113
115
|
*/
|
|
114
116
|
/**
|
|
115
117
|
* :::important
|
|
@@ -145,6 +147,7 @@
|
|
|
145
147
|
* @prop --limel-list-item-menu-order: Defines the order of the menu, within the list item's flexbox. Defaults to `3`.
|
|
146
148
|
* @prop --list-item-image-border-radius: Defines the border radius of the list item image. Defaults to `50%`.
|
|
147
149
|
* @prop --list-item-image-object-fit: Defines the object-fit property of the list item image. Defaults to `cover`.
|
|
150
|
+
* @prop --limel-list-item-image-size: Defines the size of the list item image. Defaults to `2rem`.
|
|
148
151
|
*/
|
|
149
152
|
*,
|
|
150
153
|
*:before,
|
|
@@ -409,6 +412,7 @@ limel-dynamic-label {
|
|
|
409
412
|
}
|
|
410
413
|
|
|
411
414
|
limel-list-item {
|
|
415
|
+
--limel-list-item-image-size: 2rem;
|
|
412
416
|
min-height: 2.5rem;
|
|
413
417
|
}
|
|
414
418
|
limel-list-item:focus {
|
|
@@ -523,8 +527,8 @@ limel-list-item img {
|
|
|
523
527
|
flex-shrink: 0;
|
|
524
528
|
object-fit: var(--list-item-image-object-fit, cover);
|
|
525
529
|
border-radius: var(--list-item-image-border-radius, 50%);
|
|
526
|
-
width:
|
|
527
|
-
height:
|
|
530
|
+
width: var(--limel-list-item-image-size);
|
|
531
|
+
height: var(--limel-list-item-image-size);
|
|
528
532
|
box-shadow: 0 0 0 1px rgb(var(--contrast-800), 0.5);
|
|
529
533
|
}
|
|
530
534
|
limel-list-item limel-menu {
|
|
@@ -532,6 +536,18 @@ limel-list-item limel-menu {
|
|
|
532
536
|
order: var(--limel-list-item-menu-order, 3);
|
|
533
537
|
}
|
|
534
538
|
|
|
539
|
+
:has(> limel-list-item > img) > limel-list-item:not(:has(> img)) > limel-icon {
|
|
540
|
+
margin-left: 0;
|
|
541
|
+
min-width: var(--limel-list-item-image-size);
|
|
542
|
+
max-width: var(--limel-list-item-image-size);
|
|
543
|
+
min-height: var(--limel-list-item-image-size);
|
|
544
|
+
max-height: var(--limel-list-item-image-size);
|
|
545
|
+
box-shadow: 0 0 0 1px rgb(var(--contrast-800), 0.5);
|
|
546
|
+
}
|
|
547
|
+
:has(> limel-list-item > img) > limel-list-item:not(:has(> img)) > limel-icon:not([badge]) {
|
|
548
|
+
padding: 0.25rem;
|
|
549
|
+
}
|
|
550
|
+
|
|
535
551
|
limel-list-item[role=menuitem] limel-list-item .label {
|
|
536
552
|
font-size: var(--limel-theme-default-small-font-size);
|
|
537
553
|
}
|
|
@@ -241,8 +241,10 @@
|
|
|
241
241
|
border-radius: 1.25rem;
|
|
242
242
|
padding: 0 0.375rem;
|
|
243
243
|
height: 1.25rem;
|
|
244
|
+
min-width: 1.25rem;
|
|
244
245
|
display: flex;
|
|
245
246
|
align-items: center;
|
|
247
|
+
justify-content: center;
|
|
246
248
|
white-space: nowrap;
|
|
247
249
|
color: rgb(var(--color-white));
|
|
248
250
|
font-size: 0.6875rem;
|
|
@@ -383,6 +385,99 @@ input[type=range] {
|
|
|
383
385
|
color: var(--limel-notched-outline-label-color, rgb(var(--contrast-1200)));
|
|
384
386
|
}
|
|
385
387
|
|
|
388
|
+
:host(.has-clear-button) div[slot=content] {
|
|
389
|
+
padding-right: calc(1rem + 0.25rem);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
:host(.is-unset) .track .active {
|
|
393
|
+
width: 0;
|
|
394
|
+
}
|
|
395
|
+
:host(.is-unset) .thumb {
|
|
396
|
+
left: 50%;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
button.clear-button {
|
|
400
|
+
appearance: none;
|
|
401
|
+
background: none;
|
|
402
|
+
border: none;
|
|
403
|
+
padding: 0;
|
|
404
|
+
margin: 0;
|
|
405
|
+
font: inherit;
|
|
406
|
+
color: inherit;
|
|
407
|
+
text-align: inherit;
|
|
408
|
+
}
|
|
409
|
+
button.clear-button:focus {
|
|
410
|
+
outline: none;
|
|
411
|
+
}
|
|
412
|
+
button.clear-button:focus-visible {
|
|
413
|
+
outline: none;
|
|
414
|
+
box-shadow: var(--shadow-depth-8-focused);
|
|
415
|
+
}
|
|
416
|
+
button.clear-button:not([disabled]) {
|
|
417
|
+
transition: color var(--limel-clickable-transition-speed, 0.4s) ease, background-color var(--limel-clickable-transition-speed, 0.4s) ease, box-shadow var(--limel-clickable-transform-speed, 0.4s) ease, transform var(--limel-clickable-transform-speed, 0.4s) var(--limel-clickable-transform-timing-function, ease);
|
|
418
|
+
cursor: pointer;
|
|
419
|
+
color: rgb(var(--contrast-1100));
|
|
420
|
+
background-color: rgba(var(--contrast-700), 0.6);
|
|
421
|
+
}
|
|
422
|
+
button.clear-button:not([disabled]):hover, button.clear-button:not([disabled]):focus, button.clear-button:not([disabled]):focus-visible {
|
|
423
|
+
will-change: color, background-color, box-shadow, transform;
|
|
424
|
+
}
|
|
425
|
+
button.clear-button:not([disabled]):hover, button.clear-button:not([disabled]):focus-visible {
|
|
426
|
+
transform: translate3d(0, 0.01rem, 0);
|
|
427
|
+
color: rgb(var(--contrast-100));
|
|
428
|
+
background-color: rgb(var(--contrast-1000));
|
|
429
|
+
}
|
|
430
|
+
button.clear-button:not([disabled]):hover {
|
|
431
|
+
box-shadow: var(--button-shadow-hovered);
|
|
432
|
+
}
|
|
433
|
+
button.clear-button:not([disabled]):active {
|
|
434
|
+
--limel-clickable-transform-timing-function: cubic-bezier(
|
|
435
|
+
0.83,
|
|
436
|
+
-0.15,
|
|
437
|
+
0.49,
|
|
438
|
+
1.16
|
|
439
|
+
);
|
|
440
|
+
transform: translate3d(0, 0.05rem, 0);
|
|
441
|
+
box-shadow: var(--button-shadow-pressed);
|
|
442
|
+
}
|
|
443
|
+
button.clear-button:not([disabled]):hover, button.clear-button:not([disabled]):active {
|
|
444
|
+
--limel-clickable-transition-speed: 0.2s;
|
|
445
|
+
--limel-clickable-transform-speed: 0.16s;
|
|
446
|
+
}
|
|
447
|
+
button.clear-button:not([disabled]):focus-visible {
|
|
448
|
+
background-color: rgb(var(--contrast-1000));
|
|
449
|
+
}
|
|
450
|
+
button.clear-button {
|
|
451
|
+
position: absolute;
|
|
452
|
+
inset: 0.75rem 0 0 auto;
|
|
453
|
+
display: flex;
|
|
454
|
+
align-items: center;
|
|
455
|
+
justify-content: center;
|
|
456
|
+
height: 1rem;
|
|
457
|
+
width: 1rem;
|
|
458
|
+
border-radius: 50%;
|
|
459
|
+
}
|
|
460
|
+
button.clear-button svg {
|
|
461
|
+
width: calc(1rem - 0.25rem);
|
|
462
|
+
height: calc(1rem - 0.25rem);
|
|
463
|
+
fill: currentColor;
|
|
464
|
+
}
|
|
465
|
+
button.clear-button:before {
|
|
466
|
+
content: "";
|
|
467
|
+
position: absolute;
|
|
468
|
+
inset: 0 auto 0 0;
|
|
469
|
+
margin: auto;
|
|
470
|
+
height: 0.125rem;
|
|
471
|
+
width: 0.25rem;
|
|
472
|
+
background-color: rgba(var(--contrast-700), 0.6);
|
|
473
|
+
transform: translate(-100%, 0);
|
|
474
|
+
}
|
|
475
|
+
button.clear-button[disabled] {
|
|
476
|
+
color: rgb(var(--contrast-1000));
|
|
477
|
+
background-color: rgb(var(--contrast-600));
|
|
478
|
+
cursor: not-allowed;
|
|
479
|
+
}
|
|
480
|
+
|
|
386
481
|
:host(limel-slider:focus),
|
|
387
482
|
:host(limel-slider:focus-visible),
|
|
388
483
|
:host(limel-slider:focus-within) {
|
|
@@ -1,12 +1,25 @@
|
|
|
1
1
|
import { h, Host, } from "@stencil/core";
|
|
2
2
|
import { getPercentageClass } from "./get-percentage-class";
|
|
3
3
|
import { createRandomString } from "../../util/random-string";
|
|
4
|
+
import translate from "../../global/translations";
|
|
4
5
|
const DEFAULT_FACTOR = 1;
|
|
5
6
|
const DEFAULT_MAX_VALUE = 100;
|
|
6
7
|
const DEFAULT_MIN_VALUE = 0;
|
|
7
8
|
const MAX_VISIBLE_STEP_DOTS = 20;
|
|
9
|
+
/**
|
|
10
|
+
* Whether the slider holds a value at all. `Number.isFinite` is typed
|
|
11
|
+
* `(number: unknown) => boolean`, so it tests the right thing but narrows
|
|
12
|
+
* nothing; this does, which lets the unset check double as proof that what
|
|
13
|
+
* remains is a number the arithmetic can use. `null`, `undefined` and `NaN`
|
|
14
|
+
* all mean unset.
|
|
15
|
+
* @param value - the slider's `value` prop, which may not be a number.
|
|
16
|
+
*/
|
|
17
|
+
const isSetValue = (value) => {
|
|
18
|
+
return Number.isFinite(value);
|
|
19
|
+
};
|
|
8
20
|
/**
|
|
9
21
|
* @exampleComponent limel-example-slider-basic
|
|
22
|
+
* @exampleComponent limel-example-slider-unset
|
|
10
23
|
* @exampleComponent limel-example-slider-multiplier
|
|
11
24
|
* @exampleComponent limel-example-slider-multiplier-percentage-colors
|
|
12
25
|
* @exampleComponent limel-example-slider-unit
|
|
@@ -36,6 +49,9 @@ export class Slider {
|
|
|
36
49
|
this.factor = DEFAULT_FACTOR;
|
|
37
50
|
/**
|
|
38
51
|
* Set to `true` to indicate that the slider is required.
|
|
52
|
+
* A required slider does not offer the clear button, since a required
|
|
53
|
+
* value cannot be unset. It can still be initialized unset (with a
|
|
54
|
+
* non-finite `value`) to prompt the user to make a choice.
|
|
39
55
|
*/
|
|
40
56
|
this.required = false;
|
|
41
57
|
/**
|
|
@@ -52,6 +68,10 @@ export class Slider {
|
|
|
52
68
|
* Unit to display next to the value
|
|
53
69
|
*/
|
|
54
70
|
this.unit = '';
|
|
71
|
+
/**
|
|
72
|
+
* Defines the language for translations of the accessible labels.
|
|
73
|
+
*/
|
|
74
|
+
this.language = 'en';
|
|
55
75
|
/**
|
|
56
76
|
* The maximum value allowed
|
|
57
77
|
*/
|
|
@@ -60,6 +80,37 @@ export class Slider {
|
|
|
60
80
|
* The minimum value allowed
|
|
61
81
|
*/
|
|
62
82
|
this.valuemin = DEFAULT_MIN_VALUE;
|
|
83
|
+
/**
|
|
84
|
+
* `true` while the value on display is one the consumer has been told
|
|
85
|
+
* about — either it came from the `value` prop, or it has been emitted on
|
|
86
|
+
* `change`. It is `false` from the moment the slider becomes unset until a
|
|
87
|
+
* value is committed again.
|
|
88
|
+
*
|
|
89
|
+
* The native input always holds a value, so while unset it rests at the
|
|
90
|
+
* midpoint. A press that lands on that midpoint, or a drag that returns to
|
|
91
|
+
* it before releasing, leaves the input's value untouched and fires neither
|
|
92
|
+
* `input` nor `change`. Without this flag such an interaction is swallowed:
|
|
93
|
+
* the slider either stays unset, or shows a number the consumer never
|
|
94
|
+
* received.
|
|
95
|
+
*/
|
|
96
|
+
this.valueIsCommitted = false;
|
|
97
|
+
this.syncStateFromValue = () => {
|
|
98
|
+
const value = this.value;
|
|
99
|
+
if (!isSetValue(value)) {
|
|
100
|
+
this.enterUnsetState();
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
this.isUnset = false;
|
|
104
|
+
this.valueIsCommitted = true;
|
|
105
|
+
this.displayValue = this.multiplyByFactor(value);
|
|
106
|
+
this.setPercentageClass(value);
|
|
107
|
+
};
|
|
108
|
+
this.enterUnsetState = () => {
|
|
109
|
+
this.isUnset = true;
|
|
110
|
+
this.valueIsCommitted = false;
|
|
111
|
+
this.displayValue = this.getRestingDisplayValue();
|
|
112
|
+
this.percentageClass = undefined;
|
|
113
|
+
};
|
|
63
114
|
this.renderStepDots = (min, max) => {
|
|
64
115
|
if (!this.step) {
|
|
65
116
|
return;
|
|
@@ -77,24 +128,87 @@ export class Slider {
|
|
|
77
128
|
}
|
|
78
129
|
return (h("limel-helper-line", { helperText: this.helperText, helperTextId: this.helperTextId, invalid: this.invalid }));
|
|
79
130
|
};
|
|
131
|
+
/**
|
|
132
|
+
* A required slider must hold a value, so it offers no way to clear it,
|
|
133
|
+
* and a readonly one cannot be edited at all. The styling needs the same
|
|
134
|
+
* answer to reserve room for the button, so both read it from here rather
|
|
135
|
+
* than each deriving it — the stylesheet cannot see a parsed prop, only
|
|
136
|
+
* the attribute string, and `required="false"` is a present attribute.
|
|
137
|
+
*/
|
|
138
|
+
this.hasClearButton = () => {
|
|
139
|
+
return !this.readonly && !this.required;
|
|
140
|
+
};
|
|
141
|
+
this.renderClearButton = () => {
|
|
142
|
+
if (!this.hasClearButton()) {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
const label = this.label
|
|
146
|
+
? translate.get('clear-value-of', this.language, {
|
|
147
|
+
label: this.label,
|
|
148
|
+
})
|
|
149
|
+
: translate.get('clear-value', this.language);
|
|
150
|
+
return (h("button", { type: "button", id: this.clearButtonId, class: "clear-button", "aria-label": label, onClick: this.handleClear, disabled: this.isUnset || this.disabled }, h("svg", { viewBox: "0 0 32 32", "aria-hidden": "true", focusable: "false" }, h("path", { d: "M7.219 5.781L5.78 7.22 14.563 16 5.78 24.781 7.22 26.22 16 17.437l8.781 8.782 1.438-1.438L17.437 16l8.782-8.781L24.78 5.78 16 14.563z" })), h("limel-tooltip", { elementId: this.clearButtonId, label: label })));
|
|
151
|
+
};
|
|
80
152
|
this.handleInput = (event) => {
|
|
81
153
|
event.stopPropagation();
|
|
82
154
|
const input = event.target;
|
|
83
155
|
const value = Number(input.value);
|
|
156
|
+
this.isUnset = false;
|
|
84
157
|
this.displayValue = value;
|
|
85
158
|
this.setPercentageClass(value / this.factor);
|
|
86
159
|
};
|
|
87
160
|
this.handleChange = (event) => {
|
|
88
161
|
event.stopPropagation();
|
|
89
162
|
const input = event.target;
|
|
90
|
-
|
|
163
|
+
this.commitValue(Number(input.value));
|
|
164
|
+
};
|
|
165
|
+
this.handleClick = (event) => {
|
|
166
|
+
if (this.valueIsCommitted) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
// The interaction is over and the value on display still hasn't
|
|
170
|
+
// reached the consumer, so the native input never fired a `change`.
|
|
171
|
+
// Commit what it holds. The click is left to bubble, so consumers
|
|
172
|
+
// listening for clicks still see it.
|
|
173
|
+
const input = event.target;
|
|
174
|
+
this.commitValue(Number(input.value));
|
|
175
|
+
};
|
|
176
|
+
/**
|
|
177
|
+
* Leaves the unset state and emits the value, keeping the rendered state
|
|
178
|
+
* and the emitted value in step so the two cannot diverge.
|
|
179
|
+
* @param displayValue - the value held by the native input, already
|
|
180
|
+
* multiplied by `factor`.
|
|
181
|
+
*/
|
|
182
|
+
this.commitValue = (displayValue) => {
|
|
91
183
|
const step = this.multiplyByFactor(this.step);
|
|
92
|
-
|
|
93
|
-
|
|
184
|
+
const min = this.multiplyByFactor(this.valuemin);
|
|
185
|
+
let value = displayValue;
|
|
186
|
+
// Steps are counted from `valuemin`, not from zero — a range of 1–5 in
|
|
187
|
+
// steps of 2 stops at 1, 3 and 5. Rounding against zero would push
|
|
188
|
+
// every one of those to the next even number, past `valuemax`.
|
|
189
|
+
if (!this.isMultipleOfStep(value - min, step)) {
|
|
190
|
+
value = min + this.roundToStep(value - min, step);
|
|
94
191
|
}
|
|
192
|
+
this.valueIsCommitted = true;
|
|
193
|
+
this.isUnset = false;
|
|
194
|
+
this.displayValue = value;
|
|
195
|
+
this.setPercentageClass(value / this.factor);
|
|
95
196
|
this.change.emit(value / this.factor);
|
|
96
197
|
};
|
|
198
|
+
this.handleClear = (event) => {
|
|
199
|
+
var _a;
|
|
200
|
+
event.stopPropagation();
|
|
201
|
+
this.enterUnsetState();
|
|
202
|
+
this.change.emit(null);
|
|
203
|
+
// Move focus to the slider itself so keyboard users can immediately
|
|
204
|
+
// set a new value, and so assistive tech announces the now-unset state
|
|
205
|
+
// instead of focus falling to the body when the button self-disables.
|
|
206
|
+
(_a = this.inputElement) === null || _a === void 0 ? void 0 : _a.focus();
|
|
207
|
+
};
|
|
97
208
|
this.getContainerClassList = () => {
|
|
209
|
+
return Object.assign({ 'is-unset': this.isUnset, 'has-clear-button': this.hasClearButton() }, this.getPercentageClassList());
|
|
210
|
+
};
|
|
211
|
+
this.getPercentageClassList = () => {
|
|
98
212
|
if (!this.percentageClass) {
|
|
99
213
|
return {};
|
|
100
214
|
}
|
|
@@ -105,12 +219,18 @@ export class Slider {
|
|
|
105
219
|
this.multiplyByFactor = (value) => {
|
|
106
220
|
return Math.round(value * this.factor);
|
|
107
221
|
};
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
222
|
+
/**
|
|
223
|
+
* The display value the thumb rests at while unset: the midpoint of the
|
|
224
|
+
* range, so both arrow-key directions are live (unlike anchoring at the
|
|
225
|
+
* minimum). Aligned to the step — native range inputs default to a step of
|
|
226
|
+
* 1 — so it matches a real input value and the first key press doesn't jump.
|
|
227
|
+
*/
|
|
228
|
+
this.getRestingDisplayValue = () => {
|
|
229
|
+
const min = this.multiplyByFactor(this.valuemin);
|
|
230
|
+
const max = this.multiplyByFactor(this.valuemax);
|
|
231
|
+
const midpoint = (min + max) / 2;
|
|
232
|
+
const step = this.step ? this.multiplyByFactor(this.step) : 1;
|
|
233
|
+
return min + Math.round((midpoint - min) / step) * step;
|
|
114
234
|
};
|
|
115
235
|
this.getFraction = () => {
|
|
116
236
|
const min = this.multiplyByFactor(this.valuemin);
|
|
@@ -134,10 +254,10 @@ export class Slider {
|
|
|
134
254
|
};
|
|
135
255
|
this.labelId = createRandomString();
|
|
136
256
|
this.helperTextId = createRandomString();
|
|
257
|
+
this.clearButtonId = createRandomString();
|
|
137
258
|
}
|
|
138
259
|
componentWillLoad() {
|
|
139
|
-
this.
|
|
140
|
-
this.setPercentageClass(this.getValue());
|
|
260
|
+
this.syncStateFromValue();
|
|
141
261
|
}
|
|
142
262
|
render() {
|
|
143
263
|
const min = this.multiplyByFactor(this.valuemin);
|
|
@@ -150,13 +270,18 @@ export class Slider {
|
|
|
150
270
|
if (this.disabled || this.readonly) {
|
|
151
271
|
inputProps.disabled = true;
|
|
152
272
|
}
|
|
153
|
-
return (h(Host, { key: '
|
|
273
|
+
return (h(Host, { key: 'eecd22982d9180f24f947fd2ab9af9a25e64647e', class: this.getContainerClassList() }, h("limel-notched-outline", { key: '848578a10d64a4af81e296c9f961e9be788484a7', labelId: this.labelId, label: this.label, required: this.required, invalid: this.invalid, disabled: this.disabled, readonly: this.readonly, hasValue: !this.isUnset, hasFloatingLabel: true }, h("div", { key: '7ad977107b79fc9ca416562d5c7905b4a962053c', slot: "content" }, h("div", { key: 'dcb137a44b5244e63a4c8a95341d3918dc65445c', class: "slider", style: { '--slider-fraction': `${fraction}` } }, h("input", Object.assign({ key: '73af46f062991f3c715d13c0f44b0fb9478dc37c', type: "range", min: min, max: max, value: this.displayValue, "aria-labelledby": this.labelId, "aria-describedby": this.helperText
|
|
154
274
|
? this.helperTextId
|
|
155
|
-
: undefined,
|
|
275
|
+
: undefined, "aria-valuetext": this.isUnset
|
|
276
|
+
? translate.get('value-not-set', this.language)
|
|
277
|
+
: undefined, ref: (el) => {
|
|
278
|
+
this.inputElement = el;
|
|
279
|
+
}, onInput: this.handleInput, onChange: this.handleChange, onClick: this.handleClick }, inputProps)), h("div", { key: 'e9fb2af7f43cc040c382930d336c8eb903bc0162', class: "track" }, h("div", { key: '2cec88a4b8c99296473bbd9b064bccd0a6450b8f', class: "active" }), this.renderStepDots(min, max)), h("div", { key: '5a090fb0528478450510ff0240e6b5499a177238', class: "thumb" }, h("div", { key: 'fde6792041312183af0328d9fc75d19d2553bf46', class: "knob" }), h("div", { key: 'de717ffa20723870bb27aa22e99fe9fe5ebdd563', class: "indicator", "aria-hidden": "true" }, this.isUnset
|
|
280
|
+
? '\u2194\uFE0E'
|
|
281
|
+
: this.displayValue))), h("div", { key: 'd0c38d092fecc4bf9690680d8541c8d658056f08', class: "range-labels" }, h("span", { key: '581387615da0cdaf105a568e02212f8bdd22eeb6', class: "min" }, this.multiplyByFactor(this.valuemin), this.unit), h("span", { key: '33c5673d8e56995bffdc35340381f2e87ae0918c', class: "max" }, this.multiplyByFactor(this.valuemax), this.unit)))), this.renderClearButton(), this.renderHelperLine()));
|
|
156
282
|
}
|
|
157
283
|
watchValue() {
|
|
158
|
-
this.
|
|
159
|
-
this.setPercentageClass(this.getValue());
|
|
284
|
+
this.syncStateFromValue();
|
|
160
285
|
}
|
|
161
286
|
static get is() { return "limel-slider"; }
|
|
162
287
|
static get encapsulation() { return "shadow"; }
|
|
@@ -282,7 +407,7 @@ export class Slider {
|
|
|
282
407
|
"optional": false,
|
|
283
408
|
"docs": {
|
|
284
409
|
"tags": [],
|
|
285
|
-
"text": "Set to `true` to indicate that the slider is required."
|
|
410
|
+
"text": "Set to `true` to indicate that the slider is required.\nA required slider does not offer the clear button, since a required\nvalue cannot be unset. It can still be initialized unset (with a\nnon-finite `value`) to prompt the user to make a choice."
|
|
286
411
|
},
|
|
287
412
|
"getter": false,
|
|
288
413
|
"setter": false,
|
|
@@ -350,11 +475,38 @@ export class Slider {
|
|
|
350
475
|
"attribute": "unit",
|
|
351
476
|
"defaultValue": "''"
|
|
352
477
|
},
|
|
478
|
+
"language": {
|
|
479
|
+
"type": "string",
|
|
480
|
+
"mutable": false,
|
|
481
|
+
"complexType": {
|
|
482
|
+
"original": "Languages",
|
|
483
|
+
"resolved": "\"da\" | \"de\" | \"en\" | \"fi\" | \"fr\" | \"nb\" | \"nl\" | \"no\" | \"sv\"",
|
|
484
|
+
"references": {
|
|
485
|
+
"Languages": {
|
|
486
|
+
"location": "import",
|
|
487
|
+
"path": "../date-picker/date.types",
|
|
488
|
+
"id": "src/components/date-picker/date.types.ts::Languages",
|
|
489
|
+
"referenceLocation": "Languages"
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
},
|
|
493
|
+
"required": false,
|
|
494
|
+
"optional": false,
|
|
495
|
+
"docs": {
|
|
496
|
+
"tags": [],
|
|
497
|
+
"text": "Defines the language for translations of the accessible labels."
|
|
498
|
+
},
|
|
499
|
+
"getter": false,
|
|
500
|
+
"setter": false,
|
|
501
|
+
"reflect": true,
|
|
502
|
+
"attribute": "language",
|
|
503
|
+
"defaultValue": "'en'"
|
|
504
|
+
},
|
|
353
505
|
"value": {
|
|
354
506
|
"type": "number",
|
|
355
507
|
"mutable": false,
|
|
356
508
|
"complexType": {
|
|
357
|
-
"original": "number",
|
|
509
|
+
"original": "number | null",
|
|
358
510
|
"resolved": "number",
|
|
359
511
|
"references": {}
|
|
360
512
|
},
|
|
@@ -362,7 +514,7 @@ export class Slider {
|
|
|
362
514
|
"optional": false,
|
|
363
515
|
"docs": {
|
|
364
516
|
"tags": [],
|
|
365
|
-
"text": "The value of the input"
|
|
517
|
+
"text": "The value of the input. Set it to `null` to leave the slider unset,\nwhich is also what the `change` event emits once the value is cleared.\nAny other value that is not a finite number \u2014 `undefined`, or `NaN` \u2014\nunsets the slider too."
|
|
366
518
|
},
|
|
367
519
|
"getter": false,
|
|
368
520
|
"setter": false,
|
|
@@ -433,7 +585,8 @@ export class Slider {
|
|
|
433
585
|
static get states() {
|
|
434
586
|
return {
|
|
435
587
|
"percentageClass": {},
|
|
436
|
-
"displayValue": {}
|
|
588
|
+
"displayValue": {},
|
|
589
|
+
"isUnset": {}
|
|
437
590
|
};
|
|
438
591
|
}
|
|
439
592
|
static get events() {
|
|
@@ -445,10 +598,10 @@ export class Slider {
|
|
|
445
598
|
"composed": true,
|
|
446
599
|
"docs": {
|
|
447
600
|
"tags": [],
|
|
448
|
-
"text": "Emitted when the value has been changed"
|
|
601
|
+
"text": "Emitted when the value has been changed.\nEmits `null` when the value has been cleared and the slider becomes\nunset, so handlers must account for a value that is not a number."
|
|
449
602
|
},
|
|
450
603
|
"complexType": {
|
|
451
|
-
"original": "number",
|
|
604
|
+
"original": "number | null",
|
|
452
605
|
"resolved": "number",
|
|
453
606
|
"references": {}
|
|
454
607
|
}
|
|
@@ -13,18 +13,31 @@ const allTranslations = {
|
|
|
13
13
|
fi: fi,
|
|
14
14
|
fr: fr,
|
|
15
15
|
no: no,
|
|
16
|
+
nb: no, // Norwegian Bokmål shares the Norwegian (`no`) translations
|
|
16
17
|
nl: nl,
|
|
17
18
|
sv: sv,
|
|
18
19
|
};
|
|
19
20
|
const REGEX = /\{\s*(\w+)\s*\}/g;
|
|
20
21
|
export class Translations {
|
|
21
22
|
get(key, language = 'en', params) {
|
|
22
|
-
|
|
23
|
+
var _a, _b;
|
|
24
|
+
// Fall back to English when the requested language has no translations.
|
|
25
|
+
// The `language` props are typed, but a custom element takes whatever
|
|
26
|
+
// string an attribute carries, so an unknown language must never make a
|
|
27
|
+
// component throw.
|
|
28
|
+
const languageTranslations = (_a = allTranslations[language]) !== null && _a !== void 0 ? _a : allTranslations.en;
|
|
29
|
+
// Fall back per key as well: a mapped language whose file is missing
|
|
30
|
+
// this one key would otherwise render the key itself as UI text.
|
|
31
|
+
const translation = (_b = languageTranslations[key]) !== null && _b !== void 0 ? _b : allTranslations.en[key];
|
|
23
32
|
if (!translation) {
|
|
24
33
|
return key;
|
|
25
34
|
}
|
|
26
35
|
return translation.replaceAll(REGEX, (match, mergeCodeKey) => {
|
|
27
|
-
|
|
36
|
+
var _a;
|
|
37
|
+
// Nullish, not falsy: `0` and `false` are values a caller can
|
|
38
|
+
// legitimately merge in, and `||` would leave the merge code
|
|
39
|
+
// itself in the string instead.
|
|
40
|
+
return String((_a = params === null || params === void 0 ? void 0 : params[mergeCodeKey]) !== null && _a !== void 0 ? _a : match);
|
|
28
41
|
});
|
|
29
42
|
}
|
|
30
43
|
}
|