@limetech/lime-elements 40.11.3 → 40.12.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 +21 -0
- package/dist/cjs/{checkbox.template-CoNVC4Nf.js → checkbox.template-_WUgtMJy.js} +2 -2
- package/dist/cjs/lime-elements.cjs.js +1 -1
- package/dist/cjs/limel-breadcrumbs_6.cjs.entry.js +5 -10
- package/dist/cjs/limel-checkbox.cjs.entry.js +1 -1
- package/dist/cjs/limel-chip-set.cjs.entry.js +8 -3
- package/dist/cjs/limel-code-editor.cjs.entry.js +1 -2
- package/dist/cjs/limel-color-picker.cjs.entry.js +1 -1
- package/dist/cjs/limel-file-viewer.cjs.entry.js +81 -47
- package/dist/cjs/limel-form.cjs.entry.js +7 -7
- package/dist/cjs/limel-helper-line_3.cjs.entry.js +3 -3
- package/dist/cjs/limel-list-item.cjs.entry.js +1 -1
- package/dist/cjs/limel-select.cjs.entry.js +8 -3
- package/dist/cjs/limel-side-panel.cjs.entry.js +72 -5
- package/dist/cjs/limel-text-editor.cjs.entry.js +2 -2
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/collection/components/checkbox/checkbox.template.js +2 -2
- package/dist/collection/components/chip-set/chip-set.js +8 -3
- package/dist/collection/components/code-editor/code-editor.js +1 -2
- package/dist/collection/components/color-picker/color-picker.js +3 -3
- package/dist/collection/components/date-picker/date-picker.js +2 -2
- package/dist/collection/components/helper-line/helper-line.css +10 -14
- package/dist/collection/components/helper-line/helper-line.js +9 -6
- package/dist/collection/components/input-field/input-field.js +7 -12
- package/dist/collection/components/select/select.template.js +8 -3
- package/dist/collection/components/side-panel/side-panel.css +118 -6
- package/dist/collection/components/side-panel/side-panel.js +120 -77
- package/dist/collection/components/text-editor/text-editor.js +2 -2
- package/dist/esm/{checkbox.template-IDyv2bgn.js → checkbox.template-BFL4SMzl.js} +2 -2
- package/dist/esm/lime-elements.js +1 -1
- package/dist/esm/limel-breadcrumbs_6.entry.js +5 -10
- package/dist/esm/limel-checkbox.entry.js +1 -1
- package/dist/esm/limel-chip-set.entry.js +8 -3
- package/dist/esm/limel-code-editor.entry.js +1 -2
- package/dist/esm/limel-color-picker.entry.js +1 -1
- package/dist/esm/limel-file-viewer.entry.js +81 -47
- package/dist/esm/limel-form.entry.js +7 -7
- package/dist/esm/limel-helper-line_3.entry.js +3 -3
- package/dist/esm/limel-list-item.entry.js +1 -1
- package/dist/esm/limel-select.entry.js +8 -3
- package/dist/esm/limel-side-panel.entry.js +72 -5
- package/dist/esm/limel-text-editor.entry.js +2 -2
- package/dist/esm/loader.js +1 -1
- package/dist/lime-elements/lime-elements.esm.js +1 -1
- package/dist/lime-elements/p-06850418.entry.js +1 -0
- package/dist/lime-elements/p-0e662a3c.entry.js +1 -0
- package/dist/lime-elements/p-1qqvOwzC.js +1 -0
- package/dist/lime-elements/p-236743f1.entry.js +1 -0
- package/dist/lime-elements/p-2528f75e.entry.js +159 -0
- package/dist/lime-elements/{p-cf6fab84.entry.js → p-43c36a02.entry.js} +1 -1
- package/dist/lime-elements/{p-ae2e5e87.entry.js → p-49eb2f64.entry.js} +1 -1
- package/dist/lime-elements/p-4f58c6b3.entry.js +1 -0
- package/dist/lime-elements/p-5a15606a.entry.js +1 -0
- package/dist/lime-elements/{p-7a2e0e18.entry.js → p-675a7469.entry.js} +1 -1
- package/dist/lime-elements/{p-9b1934fb.entry.js → p-90286e5c.entry.js} +1 -1
- package/dist/lime-elements/p-92fab922.entry.js +23 -0
- package/dist/lime-elements/{p-14aff731.entry.js → p-c492af1b.entry.js} +1 -1
- package/dist/types/components/chip-set/chip-set.d.ts +2 -0
- package/dist/types/components/color-picker/color-picker.d.ts +10 -3
- package/dist/types/components/date-picker/date-picker.d.ts +11 -2
- package/dist/types/components/helper-line/helper-line.d.ts +7 -3
- package/dist/types/components/input-field/input-field.d.ts +10 -2
- package/dist/types/components/side-panel/side-panel.d.ts +35 -73
- package/dist/types/components.d.ts +108 -260
- package/package.json +6 -6
- package/dist/lime-elements/p-25d0d06b.entry.js +0 -159
- package/dist/lime-elements/p-33b58741.entry.js +0 -1
- package/dist/lime-elements/p-732e7807.entry.js +0 -23
- package/dist/lime-elements/p-82c65f70.entry.js +0 -1
- package/dist/lime-elements/p-9ed21407.entry.js +0 -1
- package/dist/lime-elements/p-DqQOawxc.js +0 -1
- package/dist/lime-elements/p-b69af611.entry.js +0 -1
- package/dist/lime-elements/p-ec74a07a.entry.js +0 -1
|
@@ -7,8 +7,12 @@ import { Host, h } from "@stencil/core";
|
|
|
7
7
|
* We created this to keep the visual styles the same everywhere
|
|
8
8
|
* and to avoid importing styles separately.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
10
|
+
* :::note
|
|
11
|
+
* The component has `shadow: false`, so that the helper text is part of the
|
|
12
|
+
* DOM of the consumer. This way, the `id` of the helper text can be used in
|
|
13
|
+
* the `aria-describedby` of the input element in the consumer, which is
|
|
14
|
+
* not possible across a shadow root.
|
|
15
|
+
* :::
|
|
12
16
|
*
|
|
13
17
|
* @exampleComponent limel-example-helper-line-basic
|
|
14
18
|
* @exampleComponent limel-example-helper-line-invalid
|
|
@@ -46,12 +50,11 @@ export class HelperLine {
|
|
|
46
50
|
};
|
|
47
51
|
}
|
|
48
52
|
render() {
|
|
49
|
-
return (h(Host, { key: '
|
|
53
|
+
return (h(Host, { key: 'ac3dcfadd4d281bf64bce4124602279eef598d87', tabIndex: -1, class: {
|
|
50
54
|
invalid: this.invalid,
|
|
51
|
-
}, style: this.hasContent() ? {} : { display: 'none' }, "aria-hidden": !this.hasContent() }, h("div", { key: '
|
|
55
|
+
}, style: this.hasContent() ? {} : { display: 'none' }, "aria-hidden": !this.hasContent() }, h("div", { key: '80aaa762e38841ed13a880cc5444c8aa23025130' }, this.renderHelperText(), this.renderCharacterCounter())));
|
|
52
56
|
}
|
|
53
57
|
static get is() { return "limel-helper-line"; }
|
|
54
|
-
static get encapsulation() { return "shadow"; }
|
|
55
58
|
static get originalStyleUrls() {
|
|
56
59
|
return {
|
|
57
60
|
"$": ["helper-line.scss"]
|
|
@@ -153,7 +156,7 @@ export class HelperLine {
|
|
|
153
156
|
"optional": true,
|
|
154
157
|
"docs": {
|
|
155
158
|
"tags": [],
|
|
156
|
-
"text": "Used by `aria-
|
|
159
|
+
"text": "Used by `aria-describedby` in the parent component."
|
|
157
160
|
},
|
|
158
161
|
"getter": false,
|
|
159
162
|
"setter": false,
|
|
@@ -590,21 +590,16 @@ export class InputField {
|
|
|
590
590
|
properties.required = this.required;
|
|
591
591
|
properties.readonly = this.readonly;
|
|
592
592
|
properties.disabled = this.disabled || this.readonly;
|
|
593
|
-
let ariaControls = '';
|
|
594
593
|
if (this.hasHelperText()) {
|
|
595
|
-
ariaControls += this.helperTextId;
|
|
596
594
|
properties['aria-describedby'] = this.helperTextId;
|
|
597
595
|
}
|
|
598
|
-
if (this.
|
|
599
|
-
|
|
600
|
-
ariaControls += ' ';
|
|
601
|
-
}
|
|
602
|
-
ariaControls += this.portalId;
|
|
596
|
+
if (this.isInvalid()) {
|
|
597
|
+
properties['aria-invalid'] = 'true';
|
|
603
598
|
}
|
|
604
|
-
if (
|
|
605
|
-
properties['aria-controls'] =
|
|
599
|
+
if (this.renderAutocompleteList()) {
|
|
600
|
+
properties['aria-controls'] = this.portalId;
|
|
606
601
|
}
|
|
607
|
-
return (h(Host, { key: '
|
|
602
|
+
return (h(Host, { key: '88b9b2a3b7763341aff9796754e8e59ea979ed1f' }, h("limel-notched-outline", { key: '27a236db38f4f6f9690c7a44e294867b7a4f915f', labelId: this.inputId, labelElementId: this.labelElementId, label: this.label, required: this.required, invalid: this.invalid || this.isInvalid(), disabled: this.disabled, readonly: this.readonly, hasValue: !!this.value, hasLeadingIcon: !!this.leadingIcon }, h("label", { key: 'b20d232b3f4cf805b5a6b459b6d9193dc95e8b19', slot: "content", class: this.getContainerClassList() }, this.renderLeadingIcon(), this.renderPrefix(), this.renderFormattedNumber(), this.renderInput(properties), this.renderSuffix(), this.renderTextarea(properties), this.renderTrailingLinkOrButton())), this.renderHelperLine(), this.renderAutocompleteList()));
|
|
608
603
|
}
|
|
609
604
|
valueWatcher(newValue) {
|
|
610
605
|
if (!this.mdcTextField || this.changeWaiting) {
|
|
@@ -738,7 +733,7 @@ export class InputField {
|
|
|
738
733
|
"optional": false,
|
|
739
734
|
"docs": {
|
|
740
735
|
"tags": [],
|
|
741
|
-
"text": "
|
|
736
|
+
"text": "A hint about what to type, such as an example or the format of the\nvalue. It is shown inside the field when the field is focused and empty.\n\nDo not use it instead of a `label`, and do not put anything in it that\nthe user needs to know. It disappears when the user starts to type, and\nsome screen readers do not read it. Use `helperText` for that."
|
|
742
737
|
},
|
|
743
738
|
"getter": false,
|
|
744
739
|
"setter": false,
|
|
@@ -757,7 +752,7 @@ export class InputField {
|
|
|
757
752
|
"optional": false,
|
|
758
753
|
"docs": {
|
|
759
754
|
"tags": [],
|
|
760
|
-
"text": "Optional helper text to display below the input field when it has focus"
|
|
755
|
+
"text": "Optional helper text to display below the input field when it has focus.\nScreen readers read it as the description of the field, so use it for\nwhat the user needs to know, such as the format of the value or a\nrequirement."
|
|
761
756
|
},
|
|
762
757
|
"getter": false,
|
|
763
758
|
"setter": false,
|
|
@@ -5,6 +5,7 @@ import { getIconColor, getIconName } from "../icon/get-icon-props";
|
|
|
5
5
|
const TRIGGER_ID = 's-trigger';
|
|
6
6
|
const LABEL_ID = 's-label';
|
|
7
7
|
const SELECTED_TEXT_ID = 's-selected-text';
|
|
8
|
+
const HELPER_TEXT_ID = 's-helper-text';
|
|
8
9
|
export const SelectTemplate = (props) => {
|
|
9
10
|
const value = props.value;
|
|
10
11
|
let hasValue = !!props.value;
|
|
@@ -37,6 +38,10 @@ export const SelectTemplate = (props) => {
|
|
|
37
38
|
h(SelectDropdown, Object.assign({}, props)),
|
|
38
39
|
];
|
|
39
40
|
};
|
|
41
|
+
const getDescribedBy = (props) => {
|
|
42
|
+
var _a;
|
|
43
|
+
return ((_a = props.helperText) === null || _a === void 0 ? void 0 : _a.trim()) ? HELPER_TEXT_ID : undefined;
|
|
44
|
+
};
|
|
40
45
|
const floatLabelAbove = (props) => {
|
|
41
46
|
if (props.isOpen) {
|
|
42
47
|
return true;
|
|
@@ -58,7 +63,7 @@ const SelectValue = (props) => {
|
|
|
58
63
|
};
|
|
59
64
|
return (h("button", { id: TRIGGER_ID, slot: "content", class: anchorClassList, onClick: props.open, onKeyDown: props.onTriggerKeyDown, "aria-haspopup": "listbox", "aria-expanded": props.isOpen, "aria-controls": props.id, "aria-labelledby": props.label
|
|
60
65
|
? `${LABEL_ID} ${SELECTED_TEXT_ID}`
|
|
61
|
-
: SELECTED_TEXT_ID, "aria-required": props.required, disabled: props.disabled || props.readonly }, h("span", { class: "mdc-select__selected-text-container limel-select__selected-option" }, getSelectedIcon(props.value), getSelectedPrimaryComponent(props.value), h("span", { id: SELECTED_TEXT_ID, class: "mdc-select__selected-text limel-select__selected-option__text" }, getSelectedText(props.value))), h(ShowIcon, Object.assign({}, props, { isValid: props.isValid })), h("span", { class: "mdc-select__dropdown-icon" }, h("svg", { class: "mdc-select__dropdown-icon-graphic", viewBox: "7 10 10 5", focusable: "false" }, h("polygon", { stroke: "none", "fill-rule": "evenodd", points: "7 10 12 15 17 10" })))));
|
|
66
|
+
: SELECTED_TEXT_ID, "aria-describedby": getDescribedBy(props), "aria-required": props.required, disabled: props.disabled || props.readonly }, h("span", { class: "mdc-select__selected-text-container limel-select__selected-option" }, getSelectedIcon(props.value), getSelectedPrimaryComponent(props.value), h("span", { id: SELECTED_TEXT_ID, class: "mdc-select__selected-text limel-select__selected-option__text" }, getSelectedText(props.value))), h(ShowIcon, Object.assign({}, props, { isValid: props.isValid })), h("span", { class: "mdc-select__dropdown-icon" }, h("svg", { class: "mdc-select__dropdown-icon-graphic", viewBox: "7 10 10 5", focusable: "false" }, h("polygon", { stroke: "none", "fill-rule": "evenodd", points: "7 10 12 15 17 10" })))));
|
|
62
67
|
};
|
|
63
68
|
const ShowIcon = (props) => {
|
|
64
69
|
if (props.isValid) {
|
|
@@ -70,7 +75,7 @@ const HelperText = (props) => {
|
|
|
70
75
|
if (typeof props.text !== 'string') {
|
|
71
76
|
return;
|
|
72
77
|
}
|
|
73
|
-
return (h("limel-helper-line", { helperText: props.text.trim(), invalid: !props.isValid }));
|
|
78
|
+
return (h("limel-helper-line", { helperText: props.text.trim(), helperTextId: HELPER_TEXT_ID, invalid: !props.isValid }));
|
|
74
79
|
};
|
|
75
80
|
const SelectDropdown = (props) => {
|
|
76
81
|
if (props.native) {
|
|
@@ -92,7 +97,7 @@ const NativeDropdown = (props) => {
|
|
|
92
97
|
const options = props.options
|
|
93
98
|
.filter((option) => !('separator' in option))
|
|
94
99
|
.map(renderOption(props.value));
|
|
95
|
-
return (h("select", { required: props.required, "aria-labelledby": props.label ? LABEL_ID : undefined, "aria-disabled": props.disabled, "aria-required": props.required, onChange: props.onNativeChange, onFocus: props.open, onBlur: props.close, class: "limel-select__native-control", disabled: props.disabled, multiple: props.multiple }, options));
|
|
100
|
+
return (h("select", { required: props.required, "aria-labelledby": props.label ? LABEL_ID : undefined, "aria-describedby": getDescribedBy(props), "aria-disabled": props.disabled, "aria-required": props.required, onChange: props.onNativeChange, onFocus: props.open, onBlur: props.close, class: "limel-select__native-control", disabled: props.disabled, multiple: props.multiple }, options));
|
|
96
101
|
};
|
|
97
102
|
const renderOption = (selectedOption) => {
|
|
98
103
|
return (option) => {
|
|
@@ -132,19 +132,19 @@
|
|
|
132
132
|
}
|
|
133
133
|
section {
|
|
134
134
|
position: absolute;
|
|
135
|
-
z-index: var(--_side-panel-z-index);
|
|
136
135
|
top: var(--_side-panel-top-inset);
|
|
137
136
|
right: var(--_side-panel-right-inset);
|
|
138
137
|
bottom: var(--_side-panel-bottom-inset);
|
|
139
138
|
margin: 0.5rem;
|
|
140
|
-
display: flex;
|
|
141
|
-
flex-direction: column;
|
|
142
|
-
isolation: isolate;
|
|
143
139
|
width: var(--_side-panel-width);
|
|
144
140
|
min-width: min(var(--_side-panel-min-width), 100% - 1rem);
|
|
145
141
|
max-width: min(100% - 1rem - 3rem, 60%);
|
|
146
142
|
max-height: 100%;
|
|
147
143
|
border-radius: 1rem;
|
|
144
|
+
z-index: var(--_side-panel-z-index);
|
|
145
|
+
display: flex;
|
|
146
|
+
flex-direction: column;
|
|
147
|
+
isolation: isolate;
|
|
148
148
|
box-shadow: var(--shadow-depth-64);
|
|
149
149
|
transform-origin: left center;
|
|
150
150
|
transition: background-color 0.5s ease, transform 0.3s ease, opacity 0.2s ease, right 0.2s ease;
|
|
@@ -160,7 +160,8 @@ section:focus {
|
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
-
.content
|
|
163
|
+
.content,
|
|
164
|
+
.stack {
|
|
164
165
|
--dropdown-z-index: var(
|
|
165
166
|
--_side-panel-dropdown-z-index,
|
|
166
167
|
calc(var(--_side-panel-z-index) + 1)
|
|
@@ -173,6 +174,21 @@ section:focus {
|
|
|
173
174
|
--_side-panel-tooltip-z-index,
|
|
174
175
|
calc(var(--_side-panel-z-index) + 1)
|
|
175
176
|
);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
:host([full-screen]) section {
|
|
180
|
+
left: 0;
|
|
181
|
+
width: 100%;
|
|
182
|
+
min-width: 100%;
|
|
183
|
+
max-width: 100%;
|
|
184
|
+
margin: 0;
|
|
185
|
+
}
|
|
186
|
+
:host([full-screen]) section,
|
|
187
|
+
:host([full-screen]) .content {
|
|
188
|
+
border-radius: 0;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.content {
|
|
176
192
|
display: flex;
|
|
177
193
|
flex-direction: column;
|
|
178
194
|
flex-grow: 1;
|
|
@@ -415,7 +431,7 @@ section:focus {
|
|
|
415
431
|
--side-panel-header-text-color: var(--limel-theme-on-surface-color);
|
|
416
432
|
--header-top-right-left-border-radius: 0;
|
|
417
433
|
flex-shrink: 0;
|
|
418
|
-
min-height:
|
|
434
|
+
min-height: 2.5rem;
|
|
419
435
|
padding: 0.125rem 0.75rem 0.125rem 0.25rem;
|
|
420
436
|
background-color: var(--header-background-color, rgb(var(--contrast-200)));
|
|
421
437
|
}
|
|
@@ -472,4 +488,100 @@ section:focus {
|
|
|
472
488
|
|
|
473
489
|
[data-limit=max] {
|
|
474
490
|
width: min(100% - 1rem - 3rem, 60%);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
.stack {
|
|
494
|
+
position: absolute;
|
|
495
|
+
inset: 0;
|
|
496
|
+
z-index: calc(var(--_side-panel-z-index) - 1);
|
|
497
|
+
pointer-events: none;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
.back {
|
|
501
|
+
appearance: none;
|
|
502
|
+
background: none;
|
|
503
|
+
border: none;
|
|
504
|
+
padding: 0;
|
|
505
|
+
margin: 0;
|
|
506
|
+
font: inherit;
|
|
507
|
+
color: inherit;
|
|
508
|
+
text-align: inherit;
|
|
509
|
+
position: absolute;
|
|
510
|
+
top: var(--_side-panel-top-inset);
|
|
511
|
+
right: var(--_side-panel-right-inset);
|
|
512
|
+
bottom: var(--_side-panel-bottom-inset);
|
|
513
|
+
margin: 0.5rem;
|
|
514
|
+
width: var(--_side-panel-width);
|
|
515
|
+
min-width: min(var(--_side-panel-min-width), 100% - 1rem);
|
|
516
|
+
max-width: min(100% - 1rem - 3rem, 60%);
|
|
517
|
+
max-height: 100%;
|
|
518
|
+
border-radius: 1rem;
|
|
519
|
+
}
|
|
520
|
+
.back:focus {
|
|
521
|
+
outline: none;
|
|
522
|
+
}
|
|
523
|
+
.back:focus-visible {
|
|
524
|
+
outline: none;
|
|
525
|
+
box-shadow: var(--shadow-depth-8-focused);
|
|
526
|
+
}
|
|
527
|
+
.back {
|
|
528
|
+
pointer-events: auto;
|
|
529
|
+
cursor: pointer;
|
|
530
|
+
box-sizing: border-box;
|
|
531
|
+
overflow: hidden;
|
|
532
|
+
display: flex;
|
|
533
|
+
flex-direction: column;
|
|
534
|
+
background-color: rgb(var(--contrast-100));
|
|
535
|
+
box-shadow: var(--shadow-depth-16);
|
|
536
|
+
transform-origin: left center;
|
|
537
|
+
transition: transform 0.3s ease, box-shadow 0.2s ease, background-color 0.2s ease, right 0.2s ease;
|
|
538
|
+
}
|
|
539
|
+
@media (prefers-reduced-motion) {
|
|
540
|
+
.back {
|
|
541
|
+
transition: none;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
.back:nth-last-child(1) {
|
|
545
|
+
transform: translate3d(-1.4rem, 0, 0) scale(0.98);
|
|
546
|
+
}
|
|
547
|
+
.back:nth-last-child(2) {
|
|
548
|
+
transform: translate3d(-2.3rem, 0, 0) scale(0.96);
|
|
549
|
+
}
|
|
550
|
+
.back:nth-last-child(3) {
|
|
551
|
+
transform: translate3d(-3rem, 0, 0) scale(0.94);
|
|
552
|
+
}
|
|
553
|
+
.back:nth-last-child(n+4) {
|
|
554
|
+
transform: translate3d(-3.4rem, 0, 0) scale(0.92);
|
|
555
|
+
}
|
|
556
|
+
.back:hover {
|
|
557
|
+
box-shadow: var(--shadow-depth-64);
|
|
558
|
+
}
|
|
559
|
+
.back:hover, .back:focus-visible {
|
|
560
|
+
right: calc(var(--_side-panel-right-inset) + 0.25rem);
|
|
561
|
+
background-color: var(--lime-elevated-surface-background-color);
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
.stack:has(.back:hover) .back:nth-last-child(2) {
|
|
565
|
+
transform: translate3d(-2.6rem, 0, 0) scale(0.96);
|
|
566
|
+
}
|
|
567
|
+
.stack:has(.back:hover) .back:nth-last-child(3) {
|
|
568
|
+
transform: translate3d(-3.8rem, 0, 0) scale(0.94);
|
|
569
|
+
}
|
|
570
|
+
.stack:has(.back:hover) .back:nth-last-child(n+4) {
|
|
571
|
+
transform: translate3d(-4.9rem, 0, 0) scale(0.92);
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
.back-toolbar,
|
|
575
|
+
.back-band {
|
|
576
|
+
flex-shrink: 0;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
.back-toolbar {
|
|
580
|
+
height: 2.375rem;
|
|
581
|
+
background-color: rgb(var(--contrast-300));
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
.back-band {
|
|
585
|
+
height: 2.5rem;
|
|
586
|
+
background-color: rgb(var(--contrast-200));
|
|
475
587
|
}
|
|
@@ -22,87 +22,28 @@ function stopEvent(event) {
|
|
|
22
22
|
}
|
|
23
23
|
/**
|
|
24
24
|
* A resizable panel that is displayed on top of the right side of the page.
|
|
25
|
-
*
|
|
25
|
+
* It does not block the rest of the page. Place it in an element with
|
|
26
|
+
* `position: relative`.
|
|
26
27
|
*
|
|
27
|
-
* The panel
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
28
|
+
* The panel has:
|
|
29
|
+
* - a toolbar with a close button, and buttons from `actions`
|
|
30
|
+
* - a header that shows the last entry of `stack`, with a slot for controls
|
|
31
|
+
* - backs behind its left edge, for the other entries of `stack`
|
|
32
|
+
* - a handle on its left edge, to resize the panel
|
|
33
|
+
* - a full screen mode, for small screens
|
|
31
34
|
*
|
|
32
|
-
* The
|
|
35
|
+
* The panel emits `close`, but does not remove itself. The consumer must
|
|
36
|
+
* remove it from the DOM.
|
|
33
37
|
*
|
|
34
|
-
*
|
|
35
|
-
* to give it an accessible name, which screen readers announce. When the panel
|
|
36
|
-
* opens, focus moves into it. When the panel is removed, focus returns to the
|
|
37
|
-
* element that had it before, unless focus is somewhere else by then.
|
|
38
|
-
*
|
|
39
|
-
* The panel emits `close` when the user clicks the close button, or presses
|
|
40
|
-
* Escape. It does not remove itself. The consumer must remove it from the DOM.
|
|
41
|
-
* The user can resize the panel by dragging its left edge, or with the arrow
|
|
42
|
-
* keys. The panel emits `changeWidth` when a resize is finished.
|
|
43
|
-
*
|
|
44
|
-
* See the examples for how closing and resizing work in detail.
|
|
45
|
-
*
|
|
46
|
-
* ## Header
|
|
47
|
-
*
|
|
48
|
-
* The header shows the heading, subheading and icon of the last entry in
|
|
49
|
-
* `stack`. When the entry has a `color`, the header gets that background color,
|
|
50
|
-
* and the headings are white with a text shadow. When `stack` is empty, the
|
|
51
|
-
* panel has no header.
|
|
52
|
-
*
|
|
53
|
-
* Put controls for the header, for example a follow button or a menu, in the
|
|
54
|
-
* `header-actions` slot. They are shown at the right end of the header. When
|
|
55
|
-
* `stack` is empty, there is no header, and the slot content is not shown.
|
|
56
|
-
*
|
|
57
|
-
* The slot is for small controls. It is at most half as wide as the header,
|
|
58
|
-
* and at most as tall as the heading and subheading together. Larger content
|
|
59
|
-
* is cut off, so that the header keeps its size.
|
|
60
|
-
*
|
|
61
|
-
* The slot content is not tied to an entry in `stack`. When the last entry
|
|
62
|
-
* changes, the consumer must also change the slot content.
|
|
63
|
-
*
|
|
64
|
-
* The slot content keeps its own colors. Use `--side-panel-header-text-color`
|
|
65
|
-
* to match the text color of the header. It is white when the header has a
|
|
66
|
-
* `color`. It can also be used as the `color` of an `Icon`.
|
|
67
|
-
*
|
|
68
|
-
* ## Actions
|
|
69
|
-
*
|
|
70
|
-
* The toolbar has a close button on the left. Other buttons are set with
|
|
71
|
-
* `actions`, and are shown on the right. The `type` of an action decides its
|
|
72
|
-
* icon. When the user clicks an action, the panel emits `selectAction` with the
|
|
73
|
-
* `id` of the action and the click event. The consumer decides what the action
|
|
74
|
-
* does.
|
|
75
|
-
*
|
|
76
|
-
* An action with an `href` is a link, so the user can open it in a new tab.
|
|
77
|
-
* To handle the navigation in another way, for example with the router of the
|
|
78
|
-
* application, call `preventDefault` on the click event in `selectAction`. Do
|
|
79
|
-
* this only for a plain click with the primary button. Let the browser handle
|
|
80
|
-
* all other clicks, so that Ctrl-click and Cmd-click still open the link in a
|
|
81
|
-
* new tab:
|
|
82
|
-
*
|
|
83
|
-
* ```ts
|
|
84
|
-
* function handleSelectAction(event: CustomEvent<SidePanelActionSelect>) {
|
|
85
|
-
* const click = event.detail.event;
|
|
86
|
-
* const isPlainClick =
|
|
87
|
-
* click.button === 0 &&
|
|
88
|
-
* !click.metaKey &&
|
|
89
|
-
* !click.ctrlKey &&
|
|
90
|
-
* !click.shiftKey &&
|
|
91
|
-
* !click.altKey;
|
|
92
|
-
* if (!isPlainClick) {
|
|
93
|
-
* return;
|
|
94
|
-
* }
|
|
95
|
-
*
|
|
96
|
-
* click.preventDefault();
|
|
97
|
-
* router.navigate(event.detail.id);
|
|
98
|
-
* }
|
|
99
|
-
* ```
|
|
38
|
+
* Each example shows one feature in detail, and when to use it.
|
|
100
39
|
*
|
|
101
40
|
* @exampleComponent limel-example-side-panel-basic
|
|
102
41
|
* @exampleComponent limel-example-side-panel-insets
|
|
103
42
|
* @exampleComponent limel-example-side-panel-escape
|
|
104
43
|
* @exampleComponent limel-example-side-panel-actions
|
|
105
44
|
* @exampleComponent limel-example-side-panel-header-actions
|
|
45
|
+
* @exampleComponent limel-example-side-panel-stacking
|
|
46
|
+
* @exampleComponent limel-example-side-panel-full-screen
|
|
106
47
|
* @slot - Content of the panel
|
|
107
48
|
* @slot header-actions - Small controls at the right end of the header. Content that is larger than half the header width or the height of the headings is cut off.
|
|
108
49
|
* @private
|
|
@@ -117,7 +58,7 @@ export class SidePanel {
|
|
|
117
58
|
/**
|
|
118
59
|
* The panels in the stack, outermost first. The last entry is the panel
|
|
119
60
|
* that is displayed. Its heading, subheading and icon are shown in the
|
|
120
|
-
* header.
|
|
61
|
+
* header. The other entries are shown as backs behind the panel.
|
|
121
62
|
*/
|
|
122
63
|
this.stack = [];
|
|
123
64
|
/**
|
|
@@ -134,13 +75,27 @@ export class SidePanel {
|
|
|
134
75
|
* event either.
|
|
135
76
|
*/
|
|
136
77
|
this.closeOnEscape = true;
|
|
78
|
+
/**
|
|
79
|
+
* Set to `true` when the screen is too narrow for the panel to be displayed
|
|
80
|
+
* on top of the page. The panel then covers the full width of the
|
|
81
|
+
* positioned ancestor. It cannot be resized, and the backs of the stack are
|
|
82
|
+
* not shown.
|
|
83
|
+
*/
|
|
84
|
+
this.fullScreen = false;
|
|
137
85
|
this.closeButtonId = createRandomString();
|
|
138
86
|
this.actionIdPrefix = createRandomString();
|
|
87
|
+
this.backIdPrefix = createRandomString();
|
|
88
|
+
this.focusCloseButtonAfterRender = false;
|
|
139
89
|
this.renderAction = (action, index) => {
|
|
140
90
|
const id = `${this.actionIdPrefix}-${index}`;
|
|
141
91
|
const Tag = action.href ? 'a' : 'button';
|
|
142
92
|
return (h(Tag, { class: action.type, id: id, href: action.href, target: getLinkTarget(action), "aria-label": action.label, onClick: this.handleClickAction(action) }, h("limel-icon", { name: ACTION_ICONS[action.type], "aria-hidden": "true" }), h("limel-tooltip", { elementId: id, label: action.label, helperLabel: action.helperLabel })));
|
|
143
93
|
};
|
|
94
|
+
this.renderBack = (entry, index) => {
|
|
95
|
+
var _a;
|
|
96
|
+
const id = `${this.backIdPrefix}-${index}`;
|
|
97
|
+
return (h("button", { class: "back", id: id, style: { width: (_a = this.panel) === null || _a === void 0 ? void 0 : _a.style.width }, "aria-label": entry.heading, onClick: this.handleClickBack(index) }, h("span", { class: "back-toolbar" }), h("span", { class: "back-band", style: { 'background-color': entry.color } }), h("limel-tooltip", { elementId: id, label: entry.heading, helperLabel: entry.subheading, openDirection: "left" })));
|
|
98
|
+
};
|
|
144
99
|
/**
|
|
145
100
|
* Components in the content can emit events with the same names as the
|
|
146
101
|
* panel's events, for example `close` from `limel-dialog` or
|
|
@@ -235,6 +190,9 @@ export class SidePanel {
|
|
|
235
190
|
event: event,
|
|
236
191
|
});
|
|
237
192
|
};
|
|
193
|
+
this.handleClickBack = (index) => () => {
|
|
194
|
+
this.selectStackEntry.emit(index);
|
|
195
|
+
};
|
|
238
196
|
this.handleClickClose = () => {
|
|
239
197
|
this.close.emit();
|
|
240
198
|
};
|
|
@@ -256,8 +214,24 @@ export class SidePanel {
|
|
|
256
214
|
this.removeFromOpenPanels();
|
|
257
215
|
queueMicrotask(this.restoreFocus);
|
|
258
216
|
}
|
|
217
|
+
// A removed button takes the focus with it, so a keyboard user that goes
|
|
218
|
+
// back would lose their place in the page. Both props can change in the
|
|
219
|
+
// same update, so the result comes from both, and not from the prop that
|
|
220
|
+
// changed last.
|
|
221
|
+
handleBacksChange() {
|
|
222
|
+
this.focusCloseButtonAfterRender = this.isFocusedBackRemoved();
|
|
223
|
+
}
|
|
224
|
+
componentDidRender() {
|
|
225
|
+
var _a;
|
|
226
|
+
if (!this.focusCloseButtonAfterRender) {
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
this.focusCloseButtonAfterRender = false;
|
|
230
|
+
(_a = this.host.shadowRoot
|
|
231
|
+
.querySelector('button.close')) === null || _a === void 0 ? void 0 : _a.focus();
|
|
232
|
+
}
|
|
259
233
|
render() {
|
|
260
|
-
return (h(Host, { key: '
|
|
234
|
+
return (h(Host, { key: 'ca07c3557df3be7e026a95da296689e1e3c0cf41' }, h("section", { key: '610a8b47c7b34a6d4cb4d253d40cff889ea4c73d', ref: this.setPanel, role: "dialog", "aria-label": this.label, tabindex: "-1" }, this.renderHandle(), h("div", { key: 'c9ddb80456ac82cb39801943b55fcd4de3928852', class: "content" }, h("div", { key: 'f1430da0610a4fe71363ead5c7730d627a8a935c', class: "toolbar" }, this.renderCloseButton(), this.renderActions()), this.renderHeader(), this.renderBody())), this.renderStack(), h("span", { key: 'c7d204c8b323f88962508a4c54493717fe347c8e', "data-limit": "min", ref: this.setMinLimit }), h("span", { key: '2a7fa787fd0d4c777f90b2ef7dff1d9316108416', "data-limit": "max", ref: this.setMaxLimit })));
|
|
261
235
|
}
|
|
262
236
|
// A native button and not `limel-icon-button`, because the hover animation
|
|
263
237
|
// styles the icon, which is inside the shadow root of `limel-icon-button`.
|
|
@@ -270,6 +244,21 @@ export class SidePanel {
|
|
|
270
244
|
}
|
|
271
245
|
return (h("div", { class: "actions" }, this.actions.map((action, index) => this.renderAction(action, index))));
|
|
272
246
|
}
|
|
247
|
+
renderStack() {
|
|
248
|
+
const backs = this.stack.slice(0, -1);
|
|
249
|
+
if (this.fullScreen || backs.length === 0) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
return (h("div", { class: "stack" }, backs.map((entry, index) => this.renderBack(entry, index))));
|
|
253
|
+
}
|
|
254
|
+
isFocusedBackRemoved() {
|
|
255
|
+
const backs = [...this.host.shadowRoot.querySelectorAll('.back')];
|
|
256
|
+
const index = backs.indexOf(this.host.shadowRoot.activeElement);
|
|
257
|
+
if (index === -1) {
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
260
|
+
return this.fullScreen || index >= this.stack.length - 1;
|
|
261
|
+
}
|
|
273
262
|
renderHeader() {
|
|
274
263
|
const entry = this.stack.at(-1);
|
|
275
264
|
if (!entry) {
|
|
@@ -279,6 +268,9 @@ export class SidePanel {
|
|
|
279
268
|
}
|
|
280
269
|
renderHandle() {
|
|
281
270
|
var _a, _b, _c;
|
|
271
|
+
if (this.fullScreen) {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
282
274
|
return (h("limel-resize-handle", { class: "handle", label: this.resizeLabel, value: (_a = this.widthRange) === null || _a === void 0 ? void 0 : _a.now, min: (_b = this.widthRange) === null || _b === void 0 ? void 0 : _b.min, max: (_c = this.widthRange) === null || _c === void 0 ? void 0 : _c.max, onChangeSize: this.handleChangeSize, onEndResize: this.handleEndResize }));
|
|
283
275
|
}
|
|
284
276
|
renderBody() {
|
|
@@ -324,9 +316,16 @@ export class SidePanel {
|
|
|
324
316
|
// An inline width wins over `--side-panel-width`, and is still limited by
|
|
325
317
|
// `min-width` and `max-width`. The width is set on the element and not with
|
|
326
318
|
// a state, because a render and a measurement on each pointer move make
|
|
327
|
-
// the drag slow when the content is large.
|
|
319
|
+
// the drag slow when the content is large. The backs of the stack get the
|
|
320
|
+
// width too, so that they have the same width as the panel.
|
|
328
321
|
setWidth(width) {
|
|
329
|
-
this.
|
|
322
|
+
for (const element of this.getPanelBoxes()) {
|
|
323
|
+
element.style.width = `${width}px`;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
getPanelBoxes() {
|
|
327
|
+
const backs = this.host.shadowRoot.querySelectorAll('.back');
|
|
328
|
+
return [this.panel, ...backs];
|
|
330
329
|
}
|
|
331
330
|
rememberWidthBeforeResize() {
|
|
332
331
|
if (this.isResizing()) {
|
|
@@ -456,7 +455,7 @@ export class SidePanel {
|
|
|
456
455
|
"optional": false,
|
|
457
456
|
"docs": {
|
|
458
457
|
"tags": [],
|
|
459
|
-
"text": "The panels in the stack, outermost first. The last entry is the panel\nthat is displayed. Its heading, subheading and icon are shown in the\nheader."
|
|
458
|
+
"text": "The panels in the stack, outermost first. The last entry is the panel\nthat is displayed. Its heading, subheading and icon are shown in the\nheader. The other entries are shown as backs behind the panel."
|
|
460
459
|
},
|
|
461
460
|
"getter": false,
|
|
462
461
|
"setter": false,
|
|
@@ -526,6 +525,26 @@ export class SidePanel {
|
|
|
526
525
|
"reflect": false,
|
|
527
526
|
"attribute": "close-on-escape",
|
|
528
527
|
"defaultValue": "true"
|
|
528
|
+
},
|
|
529
|
+
"fullScreen": {
|
|
530
|
+
"type": "boolean",
|
|
531
|
+
"mutable": false,
|
|
532
|
+
"complexType": {
|
|
533
|
+
"original": "boolean",
|
|
534
|
+
"resolved": "boolean",
|
|
535
|
+
"references": {}
|
|
536
|
+
},
|
|
537
|
+
"required": false,
|
|
538
|
+
"optional": false,
|
|
539
|
+
"docs": {
|
|
540
|
+
"tags": [],
|
|
541
|
+
"text": "Set to `true` when the screen is too narrow for the panel to be displayed\non top of the page. The panel then covers the full width of the\npositioned ancestor. It cannot be resized, and the backs of the stack are\nnot shown."
|
|
542
|
+
},
|
|
543
|
+
"getter": false,
|
|
544
|
+
"setter": false,
|
|
545
|
+
"reflect": true,
|
|
546
|
+
"attribute": "full-screen",
|
|
547
|
+
"defaultValue": "false"
|
|
529
548
|
}
|
|
530
549
|
};
|
|
531
550
|
}
|
|
@@ -587,9 +606,33 @@ export class SidePanel {
|
|
|
587
606
|
"resolved": "number",
|
|
588
607
|
"references": {}
|
|
589
608
|
}
|
|
609
|
+
}, {
|
|
610
|
+
"method": "selectStackEntry",
|
|
611
|
+
"name": "selectStackEntry",
|
|
612
|
+
"bubbles": true,
|
|
613
|
+
"cancelable": true,
|
|
614
|
+
"composed": true,
|
|
615
|
+
"docs": {
|
|
616
|
+
"tags": [],
|
|
617
|
+
"text": "Emitted when a back of the stack is clicked. The detail is the index of\nits entry in `stack`."
|
|
618
|
+
},
|
|
619
|
+
"complexType": {
|
|
620
|
+
"original": "number",
|
|
621
|
+
"resolved": "number",
|
|
622
|
+
"references": {}
|
|
623
|
+
}
|
|
590
624
|
}];
|
|
591
625
|
}
|
|
592
626
|
static get elementRef() { return "host"; }
|
|
627
|
+
static get watchers() {
|
|
628
|
+
return [{
|
|
629
|
+
"propName": "stack",
|
|
630
|
+
"methodName": "handleBacksChange"
|
|
631
|
+
}, {
|
|
632
|
+
"propName": "fullScreen",
|
|
633
|
+
"methodName": "handleBacksChange"
|
|
634
|
+
}];
|
|
635
|
+
}
|
|
593
636
|
static get listeners() {
|
|
594
637
|
return [{
|
|
595
638
|
"name": "close",
|
|
@@ -180,9 +180,9 @@ export class TextEditor {
|
|
|
180
180
|
}
|
|
181
181
|
renderEditor() {
|
|
182
182
|
if (this.readonly) {
|
|
183
|
-
return (h("limel-markdown", { slot: "content", value: this.value,
|
|
183
|
+
return (h("limel-markdown", { slot: "content", value: this.value, id: this.editorId }));
|
|
184
184
|
}
|
|
185
|
-
return (h("limel-prosemirror-adapter", { ref: (el) => (this.adapterElement = el), slot: "content", "aria-placeholder": this.placeholder, contentType: this.contentType, onChange: this.handleChange, onImagePasted: this.handleImagePasted, onImageRemoved: this.handleImageRemoved, onMetadataChange: this.handleMetadataChange, customElements: this.customElements, inlineImages: this.inlineImages, value: this.value,
|
|
185
|
+
return (h("limel-prosemirror-adapter", { ref: (el) => (this.adapterElement = el), slot: "content", "aria-placeholder": this.placeholder, contentType: this.contentType, onChange: this.handleChange, onImagePasted: this.handleImagePasted, onImageRemoved: this.handleImageRemoved, onMetadataChange: this.handleMetadataChange, customElements: this.customElements, inlineImages: this.inlineImages, value: this.value, id: this.editorId, "aria-disabled": this.disabled, "aria-invalid": this.invalid, "aria-required": this.required, language: this.language, triggerCharacters: this.triggers, disabled: this.disabled, ui: this.ui }));
|
|
186
186
|
}
|
|
187
187
|
renderPlaceholder() {
|
|
188
188
|
if (!this.placeholder || this.value) {
|
|
@@ -10,7 +10,7 @@ const CheckboxTemplate = (props) => {
|
|
|
10
10
|
};
|
|
11
11
|
}
|
|
12
12
|
return [
|
|
13
|
-
h("limel-dynamic-label", { value: props.checked,
|
|
13
|
+
h("limel-dynamic-label", { value: props.checked, defaultLabel: { text: props.label, icon: icon }, labels: props.readonlyLabels }),
|
|
14
14
|
h(HelperText, { text: props.helperText, helperTextId: props.helperTextId, invalid: props.invalid }),
|
|
15
15
|
];
|
|
16
16
|
}
|
|
@@ -35,7 +35,7 @@ const CheckboxTemplate = (props) => {
|
|
|
35
35
|
required: props.required,
|
|
36
36
|
indeterminate: props.indeterminate,
|
|
37
37
|
readonly: props.readonly,
|
|
38
|
-
} }, h("input", Object.assign({ type: "checkbox", id: props.id, checked: props.checked, disabled: props.disabled || props.readonly, required: props.required, onChange: props.onChange, "aria-
|
|
38
|
+
} }, h("input", Object.assign({ type: "checkbox", id: props.id, checked: props.checked, disabled: props.disabled || props.readonly, required: props.required, onChange: props.onChange, "aria-describedby": props.helperTextId }, inputProps)), h("div", { class: "box" }, h("svg", { class: "check-mark", viewBox: "0 0 24 24", "aria-hidden": "true", focusable: "false" }, h("path", { fill: "none", d: "M1.73,12.91 8.1,19.28 22.79,4.59" }))), h("label", { class: "boolean-input-label", htmlFor: props.id }, props.label)),
|
|
39
39
|
h(HelperText, { text: props.helperText, helperTextId: props.helperTextId, invalid: props.invalid }),
|
|
40
40
|
];
|
|
41
41
|
};
|