@limetech/lime-elements 40.1.0 → 40.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.
- package/CHANGELOG.md +14 -0
- package/dist/cjs/limel-button-group.cjs.entry.js +17 -6
- package/dist/cjs/limel-chip-set.cjs.entry.js +5 -5
- package/dist/cjs/limel-picker.cjs.entry.js +36 -16
- package/dist/collection/components/button-group/button-group.css +13 -15
- package/dist/collection/components/button-group/button-group.js +18 -6
- package/dist/collection/components/chip-set/chip-set.js +6 -6
- package/dist/collection/components/picker/picker.js +36 -16
- package/dist/esm/limel-button-group.entry.js +17 -6
- package/dist/esm/limel-chip-set.entry.js +5 -5
- package/dist/esm/limel-picker.entry.js +36 -16
- package/dist/lime-elements/lime-elements.esm.js +1 -1
- package/dist/lime-elements/{p-dd116bb1.entry.js → p-056ba5c5.entry.js} +1 -1
- package/dist/lime-elements/p-0c47d262.entry.js +1 -0
- package/dist/lime-elements/{p-fa4edcf5.entry.js → p-f2294e26.entry.js} +1 -1
- package/dist/types/components/button/button.types.d.ts +10 -0
- package/dist/types/components/button-group/button-group.d.ts +5 -1
- package/dist/types/components/chip-set/chip-set.d.ts +4 -4
- package/dist/types/components/picker/picker.d.ts +14 -0
- package/dist/types/components.d.ts +8 -4
- package/package.json +2 -2
- package/dist/lime-elements/p-92bbb643.entry.js +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## [40.2.0](https://github.com/Lundalogik/lime-elements/compare/v40.1.1...v40.2.0) (2026-09-07)
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
* **button-group:** support disabling individual buttons ([3fa1726](https://github.com/Lundalogik/lime-elements/commit/3fa1726c6ea8613ad53732d6fdc4ab1d786711d6))
|
|
7
|
+
|
|
8
|
+
## [40.1.1](https://github.com/Lundalogik/lime-elements/compare/v40.1.0...v40.1.1) (2026-09-07)
|
|
9
|
+
|
|
10
|
+
### Bug Fixes
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
* **picker:** clear the search query when an item is picked ([7692e87](https://github.com/Lundalogik/lime-elements/commit/7692e872e9cad63120349966013cac874437ac0a))
|
|
14
|
+
|
|
1
15
|
## [40.1.0](https://github.com/Lundalogik/lime-elements/compare/v40.0.3...v40.1.0) (2026-09-04)
|
|
2
16
|
|
|
3
17
|
### Features
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
var index = require('./index-DYg_7kkT.js');
|
|
4
4
|
var randomString = require('./random-string-BTzDB2ee.js');
|
|
5
5
|
|
|
6
|
-
const buttonGroupCss = () => `@charset "UTF-8";*,*:before,*:after{box-sizing:border-box}:host(limel-button-group){display:flex;box-sizing:border-box;align-items:center;border-radius:3.75rem;background-color:var(--button-group-background-color, rgb(var(--contrast-400)));width:max-content;max-width:100%;flex-wrap:nowrap}:
|
|
6
|
+
const buttonGroupCss = () => `@charset "UTF-8";*,*:before,*:after{box-sizing:border-box}:host(limel-button-group){display:flex;box-sizing:border-box;align-items:center;border-radius:3.75rem;background-color:var(--button-group-background-color, rgb(var(--contrast-400)));width:max-content;max-width:100%;flex-wrap:nowrap}.button{color:var(--limel-theme-on-surface-color)}.button:not(:has(:disabled)){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);cursor:pointer;color:var(--limel-theme-on-surface-color);background-color:transparent}.button:not(:has(:disabled)):hover,.button:not(:has(:disabled)):focus,.button:not(:has(:disabled)):focus-visible{will-change:color, background-color, box-shadow, transform}.button:not(:has(:disabled)):hover,.button:not(:has(:disabled)):focus-visible{transform:translate3d(0, -0.04rem, 0);color:var(--limel-theme-on-surface-color);background-color:var(--lime-elevated-surface-background-color)}.button:not(:has(:disabled)):hover{box-shadow:var(--button-shadow-hovered)}.button:not(:has(:disabled)):active{--limel-clickable-transform-timing-function:cubic-bezier( 0.83, -0.15, 0.49, 1.16 );transform:translate3d(0, 0.05rem, 0);background-color:var(--limel-theme-surface-background-color);box-shadow:var(--button-shadow-inset-pressed)}.button:not(:has(:disabled)):hover,.button:not(:has(:disabled)):active{--limel-clickable-transition-speed:0.2s;--limel-clickable-transform-speed:0.16s}.button{position:relative;display:inline-grid;grid-auto-flow:column;align-items:center;max-width:100%;min-width:2rem;height:2rem;padding:0 0.0625rem;margin:0.125rem;border-radius:1rem;font-size:var(--limel-theme-default-font-size);user-select:none}.button:not(:last-child):after{content:"";display:block;height:1rem;width:0.125rem;border-radius:0.25rem;background-color:var(--button-group-text-color, rgb(var(--contrast-1200)));opacity:0.1;position:absolute;right:-0.1875rem;top:0;bottom:0;margin:auto}.button label{cursor:pointer;transition:color 0.2s ease;display:flex;align-items:center;flex:1;height:100%;min-width:0}.button label:has(>limel-badge) .button__label{padding-right:0.25rem}.button:has(:disabled) label{cursor:not-allowed;opacity:0.4}.button input[type=radio]{position:absolute;width:0;opacity:0}.button input[type=radio]:focus-visible+label:after{content:"";display:block;position:absolute;top:0;right:0;bottom:0;left:0;border-radius:3.75rem;box-shadow:var(--shadow-depth-8-focused)}.button:focus-within{outline:none;color:var(--lime-primary-color, var(--limel-theme-primary-color))}.button:only-child .button__label{padding-left:0.75rem}.button:first-child .button__label{padding-left:0.75rem}.button.button--selected{background-color:var(--limel-theme-surface-background-color);box-shadow:var(--button-shadow-inset);color:var(--lime-primary-color, var(--limel-theme-primary-color))}.button.button--selected:not(:has(:disabled)):active{box-shadow:var(--button-shadow-inset-pressed)}.button__label{overflow:hidden;white-space:nowrap;text-overflow:ellipsis;font-size:var(--limel-theme-default-small-font-size);padding:0 0.75rem}.button__icon{border-radius:50%;vertical-align:middle}limel-badge{margin-right:0.25rem;pointer-events:none}.button:not(.button--selected){--badge-background-color:rgb(var(--contrast-200))}`;
|
|
7
7
|
|
|
8
8
|
const ButtonGroup = class {
|
|
9
9
|
constructor(hostRef) {
|
|
@@ -14,7 +14,10 @@ const ButtonGroup = class {
|
|
|
14
14
|
*/
|
|
15
15
|
this.value = [];
|
|
16
16
|
/**
|
|
17
|
-
* True if the button-group should be disabled
|
|
17
|
+
* True if the button-group should be disabled.
|
|
18
|
+
*
|
|
19
|
+
* Disables every button in the group, regardless of the `disabled` value
|
|
20
|
+
* of each individual button.
|
|
18
21
|
*/
|
|
19
22
|
this.disabled = false;
|
|
20
23
|
this.radioGroupName = randomString.createRandomString();
|
|
@@ -32,17 +35,18 @@ const ButtonGroup = class {
|
|
|
32
35
|
this.setSelectedButton();
|
|
33
36
|
}
|
|
34
37
|
render() {
|
|
35
|
-
return (index.h(index.Host, { key: '
|
|
38
|
+
return (index.h(index.Host, { key: '7823fd4593ee4eddb6d56ce55e7ff5eb1cc28397', role: "radiogroup" }, this.value.map(this.renderButton)));
|
|
36
39
|
}
|
|
37
40
|
renderButton(button) {
|
|
38
41
|
// Prefix with 'b' because html IDs cannot start with a digit,
|
|
39
42
|
// and we need to differentiate from the ID on the limel-icon. /Ads
|
|
40
43
|
const buttonId = `b${button.id}`;
|
|
44
|
+
const isDisabled = this.disabled || button.disabled;
|
|
41
45
|
const classes = {
|
|
42
46
|
button: true,
|
|
43
47
|
'button--selected': this.isButtonChecked(button),
|
|
44
48
|
};
|
|
45
|
-
return (index.h("div", { class: classes }, index.h("input", { type: "radio", name: this.radioGroupName, checked: this.isButtonChecked(button), disabled:
|
|
49
|
+
return (index.h("div", { class: classes }, index.h("input", { type: "radio", name: this.radioGroupName, checked: this.isButtonChecked(button), disabled: isDisabled, "aria-disabled": isDisabled ? 'true' : 'false', id: buttonId, onChange: this.onChange }), index.h("label", { htmlFor: buttonId }, this.renderContent(button), this.renderBadge(button))));
|
|
46
50
|
}
|
|
47
51
|
renderContent(button) {
|
|
48
52
|
if (button.icon) {
|
|
@@ -75,10 +79,17 @@ const ButtonGroup = class {
|
|
|
75
79
|
event.stopPropagation();
|
|
76
80
|
const target = event.target;
|
|
77
81
|
// The ID is prefixed with `b` in the HTML, remember? /Ads
|
|
78
|
-
|
|
82
|
+
const buttonId = target.id.slice(1);
|
|
79
83
|
const button = this.value.find((item) => {
|
|
80
|
-
return item.id ===
|
|
84
|
+
return item.id === buttonId;
|
|
81
85
|
});
|
|
86
|
+
// The `disabled` attribute on the input already stops the browser
|
|
87
|
+
// from getting here. This makes it hold even if the attribute is
|
|
88
|
+
// removed from the DOM, or a `change` event is dispatched by hand.
|
|
89
|
+
if (!button || this.disabled || button.disabled) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
this.selectedButtonId = buttonId;
|
|
82
93
|
this.change.emit(button);
|
|
83
94
|
}
|
|
84
95
|
valueChanged() {
|
|
@@ -182,10 +182,10 @@ const ChipSet = class {
|
|
|
182
182
|
* <kbd>Enter</kbd>. The input is then cleared to make room for the
|
|
183
183
|
* next chip, and help user type a new keyword from scratch.
|
|
184
184
|
*
|
|
185
|
-
* Set to `false` when the input
|
|
186
|
-
*
|
|
187
|
-
*
|
|
188
|
-
*
|
|
185
|
+
* Set to `false` when the input is a search query over an external
|
|
186
|
+
* suggestion list and the consumer decides when the keyword has served
|
|
187
|
+
* its purpose, clearing it itself via `emptyInput()`, as
|
|
188
|
+
* `limel-picker` does.
|
|
189
189
|
*/
|
|
190
190
|
this.emptyInputOnChange = true;
|
|
191
191
|
/**
|
|
@@ -374,7 +374,7 @@ const ChipSet = class {
|
|
|
374
374
|
});
|
|
375
375
|
}
|
|
376
376
|
const value = this.getValue();
|
|
377
|
-
return (index.h(index.Host, { key: '
|
|
377
|
+
return (index.h(index.Host, { key: 'e800200b0f31ad297fb25ceac46624c7731a9197' }, index.h("limel-notched-outline", { key: 'e5c3b7ec97f7063010af7c9eea45e5a89f00bd65', labelId: this.labelId, label: this.label, required: this.required, invalid: this.invalid || this.isInvalid(), disabled: this.disabled, readonly: this.readonly, hasValue: !!((_a = this.value) === null || _a === void 0 ? void 0 : _a.length), hasLeadingIcon: !!this.leadingIcon, hasFloatingLabel: this.floatLabelAbove() }, index.h("div", Object.assign({ key: '96344e9fd7a12a019cbe9896d5c6ff91925f6ca8', slot: "content" }, this.getContentProps(), { class: classes }), this.renderContent(value))), this.renderHelperLine()));
|
|
378
378
|
}
|
|
379
379
|
getContentProps() {
|
|
380
380
|
if (this.type === 'input') {
|
|
@@ -367,7 +367,7 @@ const Picker = class {
|
|
|
367
367
|
* @param event - event
|
|
368
368
|
*/
|
|
369
369
|
handleListChange(event) {
|
|
370
|
-
var _a, _b
|
|
370
|
+
var _a, _b;
|
|
371
371
|
event.stopPropagation();
|
|
372
372
|
if (!this.value || this.value !== event.detail) {
|
|
373
373
|
let newValue = event.detail;
|
|
@@ -376,22 +376,23 @@ const Picker = class {
|
|
|
376
376
|
newValue = [...currentValue, event.detail];
|
|
377
377
|
}
|
|
378
378
|
this.change.emit(newValue);
|
|
379
|
-
|
|
380
|
-
const remaining = this.items.filter((item) => item !== event.detail);
|
|
381
|
-
this.items = this.hasPickableItems(remaining) ? remaining : [];
|
|
382
|
-
}
|
|
383
|
-
else {
|
|
384
|
-
// Single-pick: the search session ends with the pick, so
|
|
385
|
-
// wipe the input. (In multi-pick we deliberately keep the
|
|
386
|
-
// typed query so the user can keep adding matches.)
|
|
387
|
-
this.items = [];
|
|
388
|
-
this.textValue = '';
|
|
389
|
-
(_b = this.chipSet) === null || _b === void 0 ? void 0 : _b.emptyInput();
|
|
390
|
-
}
|
|
379
|
+
this.updateSearchAfterPick();
|
|
391
380
|
}
|
|
392
381
|
if (this.multiple) {
|
|
393
|
-
(
|
|
382
|
+
(_b = this.chipSet) === null || _b === void 0 ? void 0 : _b.setFocus();
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Ends the search session a pick concludes. A single-pick picker is
|
|
387
|
+
* full, so its dropdown has nothing left to show; a multi-pick one
|
|
388
|
+
* starts over from the default suggestions.
|
|
389
|
+
*/
|
|
390
|
+
updateSearchAfterPick() {
|
|
391
|
+
if (!this.multiple) {
|
|
392
|
+
this.clearInputField();
|
|
393
|
+
return;
|
|
394
394
|
}
|
|
395
|
+
this.resetSearchAfterValueChange();
|
|
395
396
|
}
|
|
396
397
|
/**
|
|
397
398
|
* Change handler for the list
|
|
@@ -414,9 +415,9 @@ const Picker = class {
|
|
|
414
415
|
const query = this.textValue;
|
|
415
416
|
this.debouncedSearch(query);
|
|
416
417
|
}
|
|
417
|
-
handleChange(event) {
|
|
418
|
+
async handleChange(event) {
|
|
419
|
+
var _a, _b;
|
|
418
420
|
event.stopPropagation();
|
|
419
|
-
this.textValue = '';
|
|
420
421
|
let newValue = null;
|
|
421
422
|
if (this.multiple) {
|
|
422
423
|
const chips = event.detail;
|
|
@@ -428,6 +429,14 @@ const Picker = class {
|
|
|
428
429
|
});
|
|
429
430
|
}
|
|
430
431
|
this.change.emit(newValue);
|
|
432
|
+
const wasEditingInput = await ((_a = this.chipSet) === null || _a === void 0 ? void 0 : _a.getEditMode());
|
|
433
|
+
const wasShowingDropdown = ((_b = this.items) === null || _b === void 0 ? void 0 : _b.length) > 0 || this.textValue !== '';
|
|
434
|
+
if (this.multiple && wasEditingInput && wasShowingDropdown) {
|
|
435
|
+
this.resetSearchAfterValueChange();
|
|
436
|
+
}
|
|
437
|
+
else {
|
|
438
|
+
this.clearInputField();
|
|
439
|
+
}
|
|
431
440
|
}
|
|
432
441
|
handleInteract(event) {
|
|
433
442
|
event.stopPropagation();
|
|
@@ -538,6 +547,17 @@ const Picker = class {
|
|
|
538
547
|
this.clearTextValue();
|
|
539
548
|
this.search('');
|
|
540
549
|
}
|
|
550
|
+
/**
|
|
551
|
+
* Ends the search session and shows the default suggestions once the
|
|
552
|
+
* consumer has had a chance to answer the `change` event this follows.
|
|
553
|
+
* Consumers commonly drop the picked item from `allItems`, and that
|
|
554
|
+
* arrives as a prop on their next render, so searching at once would
|
|
555
|
+
* read the list from before.
|
|
556
|
+
*/
|
|
557
|
+
resetSearchAfterValueChange() {
|
|
558
|
+
this.clearTextValue();
|
|
559
|
+
this.debouncedSearch('');
|
|
560
|
+
}
|
|
541
561
|
/**
|
|
542
562
|
* Two-stage Esc: first press clears the typed query but keeps the
|
|
543
563
|
* dropdown open showing the default suggestions; a second press
|
|
@@ -123,29 +123,27 @@
|
|
|
123
123
|
flex-wrap: nowrap;
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
-
:host([disabled]:not([disabled=false])) {
|
|
127
|
-
cursor: not-allowed;
|
|
128
|
-
opacity: 0.4;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
126
|
.button {
|
|
127
|
+
color: var(--limel-theme-on-surface-color);
|
|
128
|
+
}
|
|
129
|
+
.button:not(:has(:disabled)) {
|
|
132
130
|
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);
|
|
133
131
|
cursor: pointer;
|
|
134
132
|
color: var(--limel-theme-on-surface-color);
|
|
135
133
|
background-color: transparent;
|
|
136
134
|
}
|
|
137
|
-
.button:hover, .button:focus, .button:focus-visible {
|
|
135
|
+
.button:not(:has(:disabled)):hover, .button:not(:has(:disabled)):focus, .button:not(:has(:disabled)):focus-visible {
|
|
138
136
|
will-change: color, background-color, box-shadow, transform;
|
|
139
137
|
}
|
|
140
|
-
.button:hover, .button:focus-visible {
|
|
138
|
+
.button:not(:has(:disabled)):hover, .button:not(:has(:disabled)):focus-visible {
|
|
141
139
|
transform: translate3d(0, -0.04rem, 0);
|
|
142
140
|
color: var(--limel-theme-on-surface-color);
|
|
143
141
|
background-color: var(--lime-elevated-surface-background-color);
|
|
144
142
|
}
|
|
145
|
-
.button:hover {
|
|
143
|
+
.button:not(:has(:disabled)):hover {
|
|
146
144
|
box-shadow: var(--button-shadow-hovered);
|
|
147
145
|
}
|
|
148
|
-
.button:active {
|
|
146
|
+
.button:not(:has(:disabled)):active {
|
|
149
147
|
--limel-clickable-transform-timing-function: cubic-bezier(
|
|
150
148
|
0.83,
|
|
151
149
|
-0.15,
|
|
@@ -156,14 +154,10 @@
|
|
|
156
154
|
background-color: var(--limel-theme-surface-background-color);
|
|
157
155
|
box-shadow: var(--button-shadow-inset-pressed);
|
|
158
156
|
}
|
|
159
|
-
.button:hover, .button:active {
|
|
157
|
+
.button:not(:has(:disabled)):hover, .button:not(:has(:disabled)):active {
|
|
160
158
|
--limel-clickable-transition-speed: 0.2s;
|
|
161
159
|
--limel-clickable-transform-speed: 0.16s;
|
|
162
160
|
}
|
|
163
|
-
.button:has(input[disabled]):hover {
|
|
164
|
-
box-shadow: none;
|
|
165
|
-
transform: none;
|
|
166
|
-
}
|
|
167
161
|
.button {
|
|
168
162
|
position: relative;
|
|
169
163
|
display: inline-grid;
|
|
@@ -204,6 +198,10 @@
|
|
|
204
198
|
.button label:has(> limel-badge) .button__label {
|
|
205
199
|
padding-right: 0.25rem;
|
|
206
200
|
}
|
|
201
|
+
.button:has(:disabled) label {
|
|
202
|
+
cursor: not-allowed;
|
|
203
|
+
opacity: 0.4;
|
|
204
|
+
}
|
|
207
205
|
.button input[type=radio] {
|
|
208
206
|
position: absolute;
|
|
209
207
|
width: 0;
|
|
@@ -235,7 +233,7 @@
|
|
|
235
233
|
box-shadow: var(--button-shadow-inset);
|
|
236
234
|
color: var(--lime-primary-color, var(--limel-theme-primary-color));
|
|
237
235
|
}
|
|
238
|
-
.button.button--selected:active {
|
|
236
|
+
.button.button--selected:not(:has(:disabled)):active {
|
|
239
237
|
box-shadow: var(--button-shadow-inset-pressed);
|
|
240
238
|
}
|
|
241
239
|
|
|
@@ -34,6 +34,7 @@ import { createRandomString } from "../../util/random-string";
|
|
|
34
34
|
* @exampleComponent limel-example-button-group-basic
|
|
35
35
|
* @exampleComponent limel-example-button-group-mix
|
|
36
36
|
* @exampleComponent limel-example-button-group-badges
|
|
37
|
+
* @exampleComponent limel-example-button-group-disabled-item
|
|
37
38
|
* @exampleComponent limel-example-button-group-composite
|
|
38
39
|
*/
|
|
39
40
|
export class ButtonGroup {
|
|
@@ -43,7 +44,10 @@ export class ButtonGroup {
|
|
|
43
44
|
*/
|
|
44
45
|
this.value = [];
|
|
45
46
|
/**
|
|
46
|
-
* True if the button-group should be disabled
|
|
47
|
+
* True if the button-group should be disabled.
|
|
48
|
+
*
|
|
49
|
+
* Disables every button in the group, regardless of the `disabled` value
|
|
50
|
+
* of each individual button.
|
|
47
51
|
*/
|
|
48
52
|
this.disabled = false;
|
|
49
53
|
this.radioGroupName = createRandomString();
|
|
@@ -61,17 +65,18 @@ export class ButtonGroup {
|
|
|
61
65
|
this.setSelectedButton();
|
|
62
66
|
}
|
|
63
67
|
render() {
|
|
64
|
-
return (h(Host, { key: '
|
|
68
|
+
return (h(Host, { key: '7823fd4593ee4eddb6d56ce55e7ff5eb1cc28397', role: "radiogroup" }, this.value.map(this.renderButton)));
|
|
65
69
|
}
|
|
66
70
|
renderButton(button) {
|
|
67
71
|
// Prefix with 'b' because html IDs cannot start with a digit,
|
|
68
72
|
// and we need to differentiate from the ID on the limel-icon. /Ads
|
|
69
73
|
const buttonId = `b${button.id}`;
|
|
74
|
+
const isDisabled = this.disabled || button.disabled;
|
|
70
75
|
const classes = {
|
|
71
76
|
button: true,
|
|
72
77
|
'button--selected': this.isButtonChecked(button),
|
|
73
78
|
};
|
|
74
|
-
return (h("div", { class: classes }, h("input", { type: "radio", name: this.radioGroupName, checked: this.isButtonChecked(button), disabled:
|
|
79
|
+
return (h("div", { class: classes }, h("input", { type: "radio", name: this.radioGroupName, checked: this.isButtonChecked(button), disabled: isDisabled, "aria-disabled": isDisabled ? 'true' : 'false', id: buttonId, onChange: this.onChange }), h("label", { htmlFor: buttonId }, this.renderContent(button), this.renderBadge(button))));
|
|
75
80
|
}
|
|
76
81
|
renderContent(button) {
|
|
77
82
|
if (button.icon) {
|
|
@@ -104,10 +109,17 @@ export class ButtonGroup {
|
|
|
104
109
|
event.stopPropagation();
|
|
105
110
|
const target = event.target;
|
|
106
111
|
// The ID is prefixed with `b` in the HTML, remember? /Ads
|
|
107
|
-
|
|
112
|
+
const buttonId = target.id.slice(1);
|
|
108
113
|
const button = this.value.find((item) => {
|
|
109
|
-
return item.id ===
|
|
114
|
+
return item.id === buttonId;
|
|
110
115
|
});
|
|
116
|
+
// The `disabled` attribute on the input already stops the browser
|
|
117
|
+
// from getting here. This makes it hold even if the attribute is
|
|
118
|
+
// removed from the DOM, or a `change` event is dispatched by hand.
|
|
119
|
+
if (!button || this.disabled || button.disabled) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
this.selectedButtonId = buttonId;
|
|
111
123
|
this.change.emit(button);
|
|
112
124
|
}
|
|
113
125
|
valueChanged() {
|
|
@@ -164,7 +176,7 @@ export class ButtonGroup {
|
|
|
164
176
|
"optional": false,
|
|
165
177
|
"docs": {
|
|
166
178
|
"tags": [],
|
|
167
|
-
"text": "True if the button-group should be disabled"
|
|
179
|
+
"text": "True if the button-group should be disabled.\n\nDisables every button in the group, regardless of the `disabled` value\nof each individual button."
|
|
168
180
|
},
|
|
169
181
|
"getter": false,
|
|
170
182
|
"setter": false,
|
|
@@ -100,10 +100,10 @@ export class ChipSet {
|
|
|
100
100
|
* <kbd>Enter</kbd>. The input is then cleared to make room for the
|
|
101
101
|
* next chip, and help user type a new keyword from scratch.
|
|
102
102
|
*
|
|
103
|
-
* Set to `false` when the input
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
103
|
+
* Set to `false` when the input is a search query over an external
|
|
104
|
+
* suggestion list and the consumer decides when the keyword has served
|
|
105
|
+
* its purpose, clearing it itself via `emptyInput()`, as
|
|
106
|
+
* `limel-picker` does.
|
|
107
107
|
*/
|
|
108
108
|
this.emptyInputOnChange = true;
|
|
109
109
|
/**
|
|
@@ -292,7 +292,7 @@ export class ChipSet {
|
|
|
292
292
|
});
|
|
293
293
|
}
|
|
294
294
|
const value = this.getValue();
|
|
295
|
-
return (h(Host, { key: '
|
|
295
|
+
return (h(Host, { key: 'e800200b0f31ad297fb25ceac46624c7731a9197' }, h("limel-notched-outline", { key: 'e5c3b7ec97f7063010af7c9eea45e5a89f00bd65', labelId: this.labelId, label: this.label, required: this.required, invalid: this.invalid || this.isInvalid(), disabled: this.disabled, readonly: this.readonly, hasValue: !!((_a = this.value) === null || _a === void 0 ? void 0 : _a.length), hasLeadingIcon: !!this.leadingIcon, hasFloatingLabel: this.floatLabelAbove() }, h("div", Object.assign({ key: '96344e9fd7a12a019cbe9896d5c6ff91925f6ca8', slot: "content" }, this.getContentProps(), { class: classes }), this.renderContent(value))), this.renderHelperLine()));
|
|
296
296
|
}
|
|
297
297
|
getContentProps() {
|
|
298
298
|
if (this.type === 'input') {
|
|
@@ -778,7 +778,7 @@ export class ChipSet {
|
|
|
778
778
|
"optional": false,
|
|
779
779
|
"docs": {
|
|
780
780
|
"tags": [],
|
|
781
|
-
"text": "Whether the input field should be emptied when the set of chips\nchanges (i.e. when the `value` prop is updated \u2014 a chip is added,\nremoved, or the array is replaced).\n\nDefaults to `true`, which is the right behavior for a standalone\ninput chip-set where the typed text *becomes* the next chip on\n<kbd>Enter</kbd>. The input is then cleared to make room for the\nnext chip, and help user type a new keyword from scratch.\n\nSet to `false` when the input
|
|
781
|
+
"text": "Whether the input field should be emptied when the set of chips\nchanges (i.e. when the `value` prop is updated \u2014 a chip is added,\nremoved, or the array is replaced).\n\nDefaults to `true`, which is the right behavior for a standalone\ninput chip-set where the typed text *becomes* the next chip on\n<kbd>Enter</kbd>. The input is then cleared to make room for the\nnext chip, and help user type a new keyword from scratch.\n\nSet to `false` when the input is a search query over an external\nsuggestion list and the consumer decides when the keyword has served\nits purpose, clearing it itself via `emptyInput()`, as\n`limel-picker` does."
|
|
782
782
|
},
|
|
783
783
|
"getter": false,
|
|
784
784
|
"setter": false,
|
|
@@ -370,7 +370,7 @@ export class Picker {
|
|
|
370
370
|
* @param event - event
|
|
371
371
|
*/
|
|
372
372
|
handleListChange(event) {
|
|
373
|
-
var _a, _b
|
|
373
|
+
var _a, _b;
|
|
374
374
|
event.stopPropagation();
|
|
375
375
|
if (!this.value || this.value !== event.detail) {
|
|
376
376
|
let newValue = event.detail;
|
|
@@ -379,22 +379,23 @@ export class Picker {
|
|
|
379
379
|
newValue = [...currentValue, event.detail];
|
|
380
380
|
}
|
|
381
381
|
this.change.emit(newValue);
|
|
382
|
-
|
|
383
|
-
const remaining = this.items.filter((item) => item !== event.detail);
|
|
384
|
-
this.items = this.hasPickableItems(remaining) ? remaining : [];
|
|
385
|
-
}
|
|
386
|
-
else {
|
|
387
|
-
// Single-pick: the search session ends with the pick, so
|
|
388
|
-
// wipe the input. (In multi-pick we deliberately keep the
|
|
389
|
-
// typed query so the user can keep adding matches.)
|
|
390
|
-
this.items = [];
|
|
391
|
-
this.textValue = '';
|
|
392
|
-
(_b = this.chipSet) === null || _b === void 0 ? void 0 : _b.emptyInput();
|
|
393
|
-
}
|
|
382
|
+
this.updateSearchAfterPick();
|
|
394
383
|
}
|
|
395
384
|
if (this.multiple) {
|
|
396
|
-
(
|
|
385
|
+
(_b = this.chipSet) === null || _b === void 0 ? void 0 : _b.setFocus();
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Ends the search session a pick concludes. A single-pick picker is
|
|
390
|
+
* full, so its dropdown has nothing left to show; a multi-pick one
|
|
391
|
+
* starts over from the default suggestions.
|
|
392
|
+
*/
|
|
393
|
+
updateSearchAfterPick() {
|
|
394
|
+
if (!this.multiple) {
|
|
395
|
+
this.clearInputField();
|
|
396
|
+
return;
|
|
397
397
|
}
|
|
398
|
+
this.resetSearchAfterValueChange();
|
|
398
399
|
}
|
|
399
400
|
/**
|
|
400
401
|
* Change handler for the list
|
|
@@ -417,9 +418,9 @@ export class Picker {
|
|
|
417
418
|
const query = this.textValue;
|
|
418
419
|
this.debouncedSearch(query);
|
|
419
420
|
}
|
|
420
|
-
handleChange(event) {
|
|
421
|
+
async handleChange(event) {
|
|
422
|
+
var _a, _b;
|
|
421
423
|
event.stopPropagation();
|
|
422
|
-
this.textValue = '';
|
|
423
424
|
let newValue = null;
|
|
424
425
|
if (this.multiple) {
|
|
425
426
|
const chips = event.detail;
|
|
@@ -431,6 +432,14 @@ export class Picker {
|
|
|
431
432
|
});
|
|
432
433
|
}
|
|
433
434
|
this.change.emit(newValue);
|
|
435
|
+
const wasEditingInput = await ((_a = this.chipSet) === null || _a === void 0 ? void 0 : _a.getEditMode());
|
|
436
|
+
const wasShowingDropdown = ((_b = this.items) === null || _b === void 0 ? void 0 : _b.length) > 0 || this.textValue !== '';
|
|
437
|
+
if (this.multiple && wasEditingInput && wasShowingDropdown) {
|
|
438
|
+
this.resetSearchAfterValueChange();
|
|
439
|
+
}
|
|
440
|
+
else {
|
|
441
|
+
this.clearInputField();
|
|
442
|
+
}
|
|
434
443
|
}
|
|
435
444
|
handleInteract(event) {
|
|
436
445
|
event.stopPropagation();
|
|
@@ -541,6 +550,17 @@ export class Picker {
|
|
|
541
550
|
this.clearTextValue();
|
|
542
551
|
this.search('');
|
|
543
552
|
}
|
|
553
|
+
/**
|
|
554
|
+
* Ends the search session and shows the default suggestions once the
|
|
555
|
+
* consumer has had a chance to answer the `change` event this follows.
|
|
556
|
+
* Consumers commonly drop the picked item from `allItems`, and that
|
|
557
|
+
* arrives as a prop on their next render, so searching at once would
|
|
558
|
+
* read the list from before.
|
|
559
|
+
*/
|
|
560
|
+
resetSearchAfterValueChange() {
|
|
561
|
+
this.clearTextValue();
|
|
562
|
+
this.debouncedSearch('');
|
|
563
|
+
}
|
|
544
564
|
/**
|
|
545
565
|
* Two-stage Esc: first press clears the typed query but keeps the
|
|
546
566
|
* dropdown open showing the default suggestions; a second press
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { r as registerInstance, c as createEvent, h, H as Host } from './index-BGxJfR2f.js';
|
|
2
2
|
import { c as createRandomString } from './random-string-JbKhhoXs.js';
|
|
3
3
|
|
|
4
|
-
const buttonGroupCss = () => `@charset "UTF-8";*,*:before,*:after{box-sizing:border-box}:host(limel-button-group){display:flex;box-sizing:border-box;align-items:center;border-radius:3.75rem;background-color:var(--button-group-background-color, rgb(var(--contrast-400)));width:max-content;max-width:100%;flex-wrap:nowrap}:
|
|
4
|
+
const buttonGroupCss = () => `@charset "UTF-8";*,*:before,*:after{box-sizing:border-box}:host(limel-button-group){display:flex;box-sizing:border-box;align-items:center;border-radius:3.75rem;background-color:var(--button-group-background-color, rgb(var(--contrast-400)));width:max-content;max-width:100%;flex-wrap:nowrap}.button{color:var(--limel-theme-on-surface-color)}.button:not(:has(:disabled)){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);cursor:pointer;color:var(--limel-theme-on-surface-color);background-color:transparent}.button:not(:has(:disabled)):hover,.button:not(:has(:disabled)):focus,.button:not(:has(:disabled)):focus-visible{will-change:color, background-color, box-shadow, transform}.button:not(:has(:disabled)):hover,.button:not(:has(:disabled)):focus-visible{transform:translate3d(0, -0.04rem, 0);color:var(--limel-theme-on-surface-color);background-color:var(--lime-elevated-surface-background-color)}.button:not(:has(:disabled)):hover{box-shadow:var(--button-shadow-hovered)}.button:not(:has(:disabled)):active{--limel-clickable-transform-timing-function:cubic-bezier( 0.83, -0.15, 0.49, 1.16 );transform:translate3d(0, 0.05rem, 0);background-color:var(--limel-theme-surface-background-color);box-shadow:var(--button-shadow-inset-pressed)}.button:not(:has(:disabled)):hover,.button:not(:has(:disabled)):active{--limel-clickable-transition-speed:0.2s;--limel-clickable-transform-speed:0.16s}.button{position:relative;display:inline-grid;grid-auto-flow:column;align-items:center;max-width:100%;min-width:2rem;height:2rem;padding:0 0.0625rem;margin:0.125rem;border-radius:1rem;font-size:var(--limel-theme-default-font-size);user-select:none}.button:not(:last-child):after{content:"";display:block;height:1rem;width:0.125rem;border-radius:0.25rem;background-color:var(--button-group-text-color, rgb(var(--contrast-1200)));opacity:0.1;position:absolute;right:-0.1875rem;top:0;bottom:0;margin:auto}.button label{cursor:pointer;transition:color 0.2s ease;display:flex;align-items:center;flex:1;height:100%;min-width:0}.button label:has(>limel-badge) .button__label{padding-right:0.25rem}.button:has(:disabled) label{cursor:not-allowed;opacity:0.4}.button input[type=radio]{position:absolute;width:0;opacity:0}.button input[type=radio]:focus-visible+label:after{content:"";display:block;position:absolute;top:0;right:0;bottom:0;left:0;border-radius:3.75rem;box-shadow:var(--shadow-depth-8-focused)}.button:focus-within{outline:none;color:var(--lime-primary-color, var(--limel-theme-primary-color))}.button:only-child .button__label{padding-left:0.75rem}.button:first-child .button__label{padding-left:0.75rem}.button.button--selected{background-color:var(--limel-theme-surface-background-color);box-shadow:var(--button-shadow-inset);color:var(--lime-primary-color, var(--limel-theme-primary-color))}.button.button--selected:not(:has(:disabled)):active{box-shadow:var(--button-shadow-inset-pressed)}.button__label{overflow:hidden;white-space:nowrap;text-overflow:ellipsis;font-size:var(--limel-theme-default-small-font-size);padding:0 0.75rem}.button__icon{border-radius:50%;vertical-align:middle}limel-badge{margin-right:0.25rem;pointer-events:none}.button:not(.button--selected){--badge-background-color:rgb(var(--contrast-200))}`;
|
|
5
5
|
|
|
6
6
|
const ButtonGroup = class {
|
|
7
7
|
constructor(hostRef) {
|
|
@@ -12,7 +12,10 @@ const ButtonGroup = class {
|
|
|
12
12
|
*/
|
|
13
13
|
this.value = [];
|
|
14
14
|
/**
|
|
15
|
-
* True if the button-group should be disabled
|
|
15
|
+
* True if the button-group should be disabled.
|
|
16
|
+
*
|
|
17
|
+
* Disables every button in the group, regardless of the `disabled` value
|
|
18
|
+
* of each individual button.
|
|
16
19
|
*/
|
|
17
20
|
this.disabled = false;
|
|
18
21
|
this.radioGroupName = createRandomString();
|
|
@@ -30,17 +33,18 @@ const ButtonGroup = class {
|
|
|
30
33
|
this.setSelectedButton();
|
|
31
34
|
}
|
|
32
35
|
render() {
|
|
33
|
-
return (h(Host, { key: '
|
|
36
|
+
return (h(Host, { key: '7823fd4593ee4eddb6d56ce55e7ff5eb1cc28397', role: "radiogroup" }, this.value.map(this.renderButton)));
|
|
34
37
|
}
|
|
35
38
|
renderButton(button) {
|
|
36
39
|
// Prefix with 'b' because html IDs cannot start with a digit,
|
|
37
40
|
// and we need to differentiate from the ID on the limel-icon. /Ads
|
|
38
41
|
const buttonId = `b${button.id}`;
|
|
42
|
+
const isDisabled = this.disabled || button.disabled;
|
|
39
43
|
const classes = {
|
|
40
44
|
button: true,
|
|
41
45
|
'button--selected': this.isButtonChecked(button),
|
|
42
46
|
};
|
|
43
|
-
return (h("div", { class: classes }, h("input", { type: "radio", name: this.radioGroupName, checked: this.isButtonChecked(button), disabled:
|
|
47
|
+
return (h("div", { class: classes }, h("input", { type: "radio", name: this.radioGroupName, checked: this.isButtonChecked(button), disabled: isDisabled, "aria-disabled": isDisabled ? 'true' : 'false', id: buttonId, onChange: this.onChange }), h("label", { htmlFor: buttonId }, this.renderContent(button), this.renderBadge(button))));
|
|
44
48
|
}
|
|
45
49
|
renderContent(button) {
|
|
46
50
|
if (button.icon) {
|
|
@@ -73,10 +77,17 @@ const ButtonGroup = class {
|
|
|
73
77
|
event.stopPropagation();
|
|
74
78
|
const target = event.target;
|
|
75
79
|
// The ID is prefixed with `b` in the HTML, remember? /Ads
|
|
76
|
-
|
|
80
|
+
const buttonId = target.id.slice(1);
|
|
77
81
|
const button = this.value.find((item) => {
|
|
78
|
-
return item.id ===
|
|
82
|
+
return item.id === buttonId;
|
|
79
83
|
});
|
|
84
|
+
// The `disabled` attribute on the input already stops the browser
|
|
85
|
+
// from getting here. This makes it hold even if the attribute is
|
|
86
|
+
// removed from the DOM, or a `change` event is dispatched by hand.
|
|
87
|
+
if (!button || this.disabled || button.disabled) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
this.selectedButtonId = buttonId;
|
|
80
91
|
this.change.emit(button);
|
|
81
92
|
}
|
|
82
93
|
valueChanged() {
|
|
@@ -180,10 +180,10 @@ const ChipSet = class {
|
|
|
180
180
|
* <kbd>Enter</kbd>. The input is then cleared to make room for the
|
|
181
181
|
* next chip, and help user type a new keyword from scratch.
|
|
182
182
|
*
|
|
183
|
-
* Set to `false` when the input
|
|
184
|
-
*
|
|
185
|
-
*
|
|
186
|
-
*
|
|
183
|
+
* Set to `false` when the input is a search query over an external
|
|
184
|
+
* suggestion list and the consumer decides when the keyword has served
|
|
185
|
+
* its purpose, clearing it itself via `emptyInput()`, as
|
|
186
|
+
* `limel-picker` does.
|
|
187
187
|
*/
|
|
188
188
|
this.emptyInputOnChange = true;
|
|
189
189
|
/**
|
|
@@ -372,7 +372,7 @@ const ChipSet = class {
|
|
|
372
372
|
});
|
|
373
373
|
}
|
|
374
374
|
const value = this.getValue();
|
|
375
|
-
return (h(Host, { key: '
|
|
375
|
+
return (h(Host, { key: 'e800200b0f31ad297fb25ceac46624c7731a9197' }, h("limel-notched-outline", { key: 'e5c3b7ec97f7063010af7c9eea45e5a89f00bd65', labelId: this.labelId, label: this.label, required: this.required, invalid: this.invalid || this.isInvalid(), disabled: this.disabled, readonly: this.readonly, hasValue: !!((_a = this.value) === null || _a === void 0 ? void 0 : _a.length), hasLeadingIcon: !!this.leadingIcon, hasFloatingLabel: this.floatLabelAbove() }, h("div", Object.assign({ key: '96344e9fd7a12a019cbe9896d5c6ff91925f6ca8', slot: "content" }, this.getContentProps(), { class: classes }), this.renderContent(value))), this.renderHelperLine()));
|
|
376
376
|
}
|
|
377
377
|
getContentProps() {
|
|
378
378
|
if (this.type === 'input') {
|