@material/web 1.0.2-nightly.77fd177.0 → 1.0.2-nightly.a0baa4d.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/labs/behaviors/validators/text-field-validator.d.ts +110 -0
- package/labs/behaviors/validators/text-field-validator.js +146 -0
- package/labs/behaviors/validators/text-field-validator.js.map +1 -0
- package/labs/card/internal/_outlined-card.scss +1 -1
- package/labs/card/internal/_shared.scss +10 -2
- package/labs/card/internal/outlined-styles.css.js +1 -1
- package/labs/card/internal/outlined-styles.css.js.map +1 -1
- package/labs/card/internal/shared-styles.css.js +1 -1
- package/labs/card/internal/shared-styles.css.js.map +1 -1
- package/menu/internal/controllers/menuItemController.d.ts +13 -1
- package/menu/internal/controllers/menuItemController.js +32 -6
- package/menu/internal/controllers/menuItemController.js.map +1 -1
- package/menu/internal/menuitem/menu-item.d.ts +2 -0
- package/menu/internal/menuitem/menu-item.js +13 -1
- package/menu/internal/menuitem/menu-item.js.map +1 -1
- package/package.json +1 -1
- package/select/internal/_shared.scss +5 -0
- package/select/internal/select.d.ts +6 -0
- package/select/internal/select.js +28 -0
- package/select/internal/select.js.map +1 -1
- package/select/internal/selectoption/select-option.d.ts +2 -0
- package/select/internal/selectoption/select-option.js +13 -1
- package/select/internal/selectoption/select-option.js.map +1 -1
- package/select/internal/selectoption/selectOptionController.d.ts +7 -3
- package/select/internal/selectoption/selectOptionController.js +8 -11
- package/select/internal/selectoption/selectOptionController.js.map +1 -1
- package/select/internal/shared-styles.css.js +1 -1
- package/select/internal/shared-styles.css.js.map +1 -1
- package/textfield/internal/text-field.d.ts +9 -74
- package/textfield/internal/text-field.js +34 -150
- package/textfield/internal/text-field.js.map +1 -1
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2023 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { Validator } from './validator.js';
|
|
7
|
+
/**
|
|
8
|
+
* Constraint validation for a text field.
|
|
9
|
+
*/
|
|
10
|
+
export interface TextFieldState {
|
|
11
|
+
/**
|
|
12
|
+
* The input or textarea state to validate.
|
|
13
|
+
*/
|
|
14
|
+
state: InputState | TextAreaState;
|
|
15
|
+
/**
|
|
16
|
+
* The `<input>` or `<textarea>` that is rendered on the page.
|
|
17
|
+
*
|
|
18
|
+
* `minlength` and `maxlength` validation do not apply until a user has
|
|
19
|
+
* interacted with the control and the element is internally marked as dirty.
|
|
20
|
+
* This is a spec quirk, the two properties behave differently from other
|
|
21
|
+
* constraint validation.
|
|
22
|
+
*
|
|
23
|
+
* This means we need an actual rendered element instead of a virtual one,
|
|
24
|
+
* since the virtual element will never be marked as dirty.
|
|
25
|
+
*
|
|
26
|
+
* This can be `null` if the element has not yet rendered, and the validator
|
|
27
|
+
* will fall back to virtual elements for other constraint validation
|
|
28
|
+
* properties, which do apply even if the control is not dirty.
|
|
29
|
+
*/
|
|
30
|
+
renderedControl: HTMLInputElement | HTMLTextAreaElement | null;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Constraint validation properties for an `<input>`.
|
|
34
|
+
*/
|
|
35
|
+
export interface InputState extends SharedInputAndTextAreaState {
|
|
36
|
+
/**
|
|
37
|
+
* The `<input>` type.
|
|
38
|
+
*
|
|
39
|
+
* Not all constraint validation properties apply to every type. See
|
|
40
|
+
* https://developer.mozilla.org/en-US/docs/Web/HTML/Constraint_validation#validation-related_attributes
|
|
41
|
+
* for which properties will apply to which types.
|
|
42
|
+
*/
|
|
43
|
+
readonly type: string;
|
|
44
|
+
/**
|
|
45
|
+
* The regex pattern a value must match.
|
|
46
|
+
*/
|
|
47
|
+
readonly pattern: string;
|
|
48
|
+
/**
|
|
49
|
+
* The minimum value.
|
|
50
|
+
*/
|
|
51
|
+
readonly min: string;
|
|
52
|
+
/**
|
|
53
|
+
* The maximum value.
|
|
54
|
+
*/
|
|
55
|
+
readonly max: string;
|
|
56
|
+
/**
|
|
57
|
+
* The step interval of the value.
|
|
58
|
+
*/
|
|
59
|
+
readonly step: string;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Constraint validation properties for a `<textarea>`.
|
|
63
|
+
*/
|
|
64
|
+
export interface TextAreaState extends SharedInputAndTextAreaState {
|
|
65
|
+
/**
|
|
66
|
+
* The type, must be "textarea" to inform the validator to use `<textarea>`
|
|
67
|
+
* instead of `<input>`.
|
|
68
|
+
*/
|
|
69
|
+
readonly type: 'textarea';
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Constraint validation properties shared between an `<input>` and
|
|
73
|
+
* `<textarea>`.
|
|
74
|
+
*/
|
|
75
|
+
interface SharedInputAndTextAreaState {
|
|
76
|
+
/**
|
|
77
|
+
* The current value.
|
|
78
|
+
*/
|
|
79
|
+
readonly value: string;
|
|
80
|
+
/**
|
|
81
|
+
* Whether the textarea is required.
|
|
82
|
+
*/
|
|
83
|
+
readonly required: boolean;
|
|
84
|
+
/**
|
|
85
|
+
* The minimum length of the value.
|
|
86
|
+
*/
|
|
87
|
+
readonly minLength: number;
|
|
88
|
+
/**
|
|
89
|
+
* The maximum length of the value.
|
|
90
|
+
*/
|
|
91
|
+
readonly maxLength: number;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* A validator that provides constraint validation that emulates `<input>` and
|
|
95
|
+
* `<textarea>` validation.
|
|
96
|
+
*/
|
|
97
|
+
export declare class TextFieldValidator extends Validator<TextFieldState> {
|
|
98
|
+
private inputControl?;
|
|
99
|
+
private textAreaControl?;
|
|
100
|
+
protected computeValidity({ state, renderedControl }: TextFieldState): {
|
|
101
|
+
validity: ValidityState;
|
|
102
|
+
validationMessage: string;
|
|
103
|
+
};
|
|
104
|
+
protected equals({ state: prev }: TextFieldState, { state: next }: TextFieldState): boolean;
|
|
105
|
+
protected copy({ state }: TextFieldState): TextFieldState;
|
|
106
|
+
private copyInput;
|
|
107
|
+
private copyTextArea;
|
|
108
|
+
private copySharedState;
|
|
109
|
+
}
|
|
110
|
+
export {};
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2023 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { Validator } from './validator.js';
|
|
7
|
+
/**
|
|
8
|
+
* A validator that provides constraint validation that emulates `<input>` and
|
|
9
|
+
* `<textarea>` validation.
|
|
10
|
+
*/
|
|
11
|
+
export class TextFieldValidator extends Validator {
|
|
12
|
+
computeValidity({ state, renderedControl }) {
|
|
13
|
+
let inputOrTextArea = renderedControl;
|
|
14
|
+
if (isInputState(state) && !inputOrTextArea) {
|
|
15
|
+
// Get cached <input> or create it.
|
|
16
|
+
inputOrTextArea = this.inputControl || document.createElement('input');
|
|
17
|
+
// Cache the <input> to re-use it next time.
|
|
18
|
+
this.inputControl = inputOrTextArea;
|
|
19
|
+
}
|
|
20
|
+
else if (!inputOrTextArea) {
|
|
21
|
+
// Get cached <textarea> or create it.
|
|
22
|
+
inputOrTextArea =
|
|
23
|
+
this.textAreaControl || document.createElement('textarea');
|
|
24
|
+
// Cache the <textarea> to re-use it next time.
|
|
25
|
+
this.textAreaControl = inputOrTextArea;
|
|
26
|
+
}
|
|
27
|
+
// Set this variable so we can check it for input-specific properties.
|
|
28
|
+
const input = isInputState(state)
|
|
29
|
+
? inputOrTextArea
|
|
30
|
+
: null;
|
|
31
|
+
// Set input's "type" first, since this can change the other properties
|
|
32
|
+
if (input) {
|
|
33
|
+
input.type = state.type;
|
|
34
|
+
}
|
|
35
|
+
if (inputOrTextArea.value !== state.value) {
|
|
36
|
+
// Only programmatically set the value if there's a difference. When using
|
|
37
|
+
// the rendered control, the value will always be up to date. Setting the
|
|
38
|
+
// property (even if it's the same string) will reset the internal <input>
|
|
39
|
+
// dirty flag, making minlength and maxlength validation reset.
|
|
40
|
+
inputOrTextArea.value = state.value;
|
|
41
|
+
}
|
|
42
|
+
inputOrTextArea.required = state.required;
|
|
43
|
+
// The following IDLAttribute properties will always hydrate an attribute,
|
|
44
|
+
// even if set to a the default value ('' or -1). The presence of the
|
|
45
|
+
// attribute triggers constraint validation, so we must remove the attribute
|
|
46
|
+
// when empty.
|
|
47
|
+
if (input) {
|
|
48
|
+
const inputState = state;
|
|
49
|
+
if (inputState.pattern) {
|
|
50
|
+
input.pattern = inputState.pattern;
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
input.removeAttribute('pattern');
|
|
54
|
+
}
|
|
55
|
+
if (inputState.min) {
|
|
56
|
+
input.min = inputState.min;
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
input.removeAttribute('min');
|
|
60
|
+
}
|
|
61
|
+
if (inputState.max) {
|
|
62
|
+
input.max = inputState.max;
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
input.removeAttribute('max');
|
|
66
|
+
}
|
|
67
|
+
if (inputState.step) {
|
|
68
|
+
input.step = inputState.step;
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
input.removeAttribute('step');
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// Use -1 to represent no minlength and maxlength, which is what the
|
|
75
|
+
// platform input returns. However, it will throw an error if you try to
|
|
76
|
+
// manually set it to -1.
|
|
77
|
+
if (state.minLength > -1) {
|
|
78
|
+
inputOrTextArea.minLength = state.minLength;
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
inputOrTextArea.removeAttribute('minlength');
|
|
82
|
+
}
|
|
83
|
+
if (state.maxLength > -1) {
|
|
84
|
+
inputOrTextArea.maxLength = state.maxLength;
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
inputOrTextArea.removeAttribute('maxlength');
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
validity: inputOrTextArea.validity,
|
|
91
|
+
validationMessage: inputOrTextArea.validationMessage,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
equals({ state: prev }, { state: next }) {
|
|
95
|
+
// Check shared input and textarea properties
|
|
96
|
+
const inputOrTextAreaEqual = prev.type === next.type &&
|
|
97
|
+
prev.value === next.value &&
|
|
98
|
+
prev.required === next.required &&
|
|
99
|
+
prev.minLength === next.minLength &&
|
|
100
|
+
prev.maxLength === next.maxLength;
|
|
101
|
+
if (!isInputState(prev) || !isInputState(next)) {
|
|
102
|
+
// Both are textareas, all relevant properties are equal.
|
|
103
|
+
return inputOrTextAreaEqual;
|
|
104
|
+
}
|
|
105
|
+
// Check additional input-specific properties.
|
|
106
|
+
return (inputOrTextAreaEqual &&
|
|
107
|
+
prev.pattern === next.pattern &&
|
|
108
|
+
prev.min === next.min &&
|
|
109
|
+
prev.max === next.max &&
|
|
110
|
+
prev.step === next.step);
|
|
111
|
+
}
|
|
112
|
+
copy({ state }) {
|
|
113
|
+
// Don't hold a reference to the rendered control when copying since we
|
|
114
|
+
// don't use it when checking if the state changed.
|
|
115
|
+
return {
|
|
116
|
+
state: isInputState(state)
|
|
117
|
+
? this.copyInput(state)
|
|
118
|
+
: this.copyTextArea(state),
|
|
119
|
+
renderedControl: null,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
copyInput(state) {
|
|
123
|
+
const { type, pattern, min, max, step } = state;
|
|
124
|
+
return {
|
|
125
|
+
...this.copySharedState(state),
|
|
126
|
+
type,
|
|
127
|
+
pattern,
|
|
128
|
+
min,
|
|
129
|
+
max,
|
|
130
|
+
step,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
copyTextArea(state) {
|
|
134
|
+
return {
|
|
135
|
+
...this.copySharedState(state),
|
|
136
|
+
type: state.type,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
copySharedState({ value, required, minLength, maxLength, }) {
|
|
140
|
+
return { value, required, minLength, maxLength };
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
function isInputState(state) {
|
|
144
|
+
return state.type !== 'textarea';
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=text-field-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text-field-validator.js","sourceRoot":"","sources":["text-field-validator.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license\n * Copyright 2023 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {Validator} from './validator.js';\n\n/**\n * Constraint validation for a text field.\n */\nexport interface TextFieldState {\n /**\n * The input or textarea state to validate.\n */\n state: InputState | TextAreaState;\n\n /**\n * The `<input>` or `<textarea>` that is rendered on the page.\n *\n * `minlength` and `maxlength` validation do not apply until a user has\n * interacted with the control and the element is internally marked as dirty.\n * This is a spec quirk, the two properties behave differently from other\n * constraint validation.\n *\n * This means we need an actual rendered element instead of a virtual one,\n * since the virtual element will never be marked as dirty.\n *\n * This can be `null` if the element has not yet rendered, and the validator\n * will fall back to virtual elements for other constraint validation\n * properties, which do apply even if the control is not dirty.\n */\n renderedControl: HTMLInputElement | HTMLTextAreaElement | null;\n}\n\n/**\n * Constraint validation properties for an `<input>`.\n */\nexport interface InputState extends SharedInputAndTextAreaState {\n /**\n * The `<input>` type.\n *\n * Not all constraint validation properties apply to every type. See\n * https://developer.mozilla.org/en-US/docs/Web/HTML/Constraint_validation#validation-related_attributes\n * for which properties will apply to which types.\n */\n readonly type: string;\n\n /**\n * The regex pattern a value must match.\n */\n readonly pattern: string;\n\n /**\n * The minimum value.\n */\n readonly min: string;\n\n /**\n * The maximum value.\n */\n readonly max: string;\n\n /**\n * The step interval of the value.\n */\n readonly step: string;\n}\n\n/**\n * Constraint validation properties for a `<textarea>`.\n */\nexport interface TextAreaState extends SharedInputAndTextAreaState {\n /**\n * The type, must be \"textarea\" to inform the validator to use `<textarea>`\n * instead of `<input>`.\n */\n readonly type: 'textarea';\n}\n\n/**\n * Constraint validation properties shared between an `<input>` and\n * `<textarea>`.\n */\ninterface SharedInputAndTextAreaState {\n /**\n * The current value.\n */\n readonly value: string;\n\n /**\n * Whether the textarea is required.\n */\n readonly required: boolean;\n\n /**\n * The minimum length of the value.\n */\n readonly minLength: number;\n\n /**\n * The maximum length of the value.\n */\n readonly maxLength: number;\n}\n\n/**\n * A validator that provides constraint validation that emulates `<input>` and\n * `<textarea>` validation.\n */\nexport class TextFieldValidator extends Validator<TextFieldState> {\n private inputControl?: HTMLInputElement;\n private textAreaControl?: HTMLTextAreaElement;\n\n protected override computeValidity({state, renderedControl}: TextFieldState) {\n let inputOrTextArea = renderedControl;\n if (isInputState(state) && !inputOrTextArea) {\n // Get cached <input> or create it.\n inputOrTextArea = this.inputControl || document.createElement('input');\n // Cache the <input> to re-use it next time.\n this.inputControl = inputOrTextArea;\n } else if (!inputOrTextArea) {\n // Get cached <textarea> or create it.\n inputOrTextArea =\n this.textAreaControl || document.createElement('textarea');\n // Cache the <textarea> to re-use it next time.\n this.textAreaControl = inputOrTextArea;\n }\n\n // Set this variable so we can check it for input-specific properties.\n const input = isInputState(state)\n ? (inputOrTextArea as HTMLInputElement)\n : null;\n\n // Set input's \"type\" first, since this can change the other properties\n if (input) {\n input.type = state.type;\n }\n\n if (inputOrTextArea.value !== state.value) {\n // Only programmatically set the value if there's a difference. When using\n // the rendered control, the value will always be up to date. Setting the\n // property (even if it's the same string) will reset the internal <input>\n // dirty flag, making minlength and maxlength validation reset.\n inputOrTextArea.value = state.value;\n }\n\n inputOrTextArea.required = state.required;\n\n // The following IDLAttribute properties will always hydrate an attribute,\n // even if set to a the default value ('' or -1). The presence of the\n // attribute triggers constraint validation, so we must remove the attribute\n // when empty.\n if (input) {\n const inputState = state as InputState;\n if (inputState.pattern) {\n input.pattern = inputState.pattern;\n } else {\n input.removeAttribute('pattern');\n }\n\n if (inputState.min) {\n input.min = inputState.min;\n } else {\n input.removeAttribute('min');\n }\n\n if (inputState.max) {\n input.max = inputState.max;\n } else {\n input.removeAttribute('max');\n }\n\n if (inputState.step) {\n input.step = inputState.step;\n } else {\n input.removeAttribute('step');\n }\n }\n\n // Use -1 to represent no minlength and maxlength, which is what the\n // platform input returns. However, it will throw an error if you try to\n // manually set it to -1.\n if (state.minLength > -1) {\n inputOrTextArea.minLength = state.minLength;\n } else {\n inputOrTextArea.removeAttribute('minlength');\n }\n\n if (state.maxLength > -1) {\n inputOrTextArea.maxLength = state.maxLength;\n } else {\n inputOrTextArea.removeAttribute('maxlength');\n }\n\n return {\n validity: inputOrTextArea.validity,\n validationMessage: inputOrTextArea.validationMessage,\n };\n }\n\n protected override equals(\n {state: prev}: TextFieldState,\n {state: next}: TextFieldState,\n ) {\n // Check shared input and textarea properties\n const inputOrTextAreaEqual =\n prev.type === next.type &&\n prev.value === next.value &&\n prev.required === next.required &&\n prev.minLength === next.minLength &&\n prev.maxLength === next.maxLength;\n\n if (!isInputState(prev) || !isInputState(next)) {\n // Both are textareas, all relevant properties are equal.\n return inputOrTextAreaEqual;\n }\n\n // Check additional input-specific properties.\n return (\n inputOrTextAreaEqual &&\n prev.pattern === next.pattern &&\n prev.min === next.min &&\n prev.max === next.max &&\n prev.step === next.step\n );\n }\n\n protected override copy({state}: TextFieldState): TextFieldState {\n // Don't hold a reference to the rendered control when copying since we\n // don't use it when checking if the state changed.\n return {\n state: isInputState(state)\n ? this.copyInput(state)\n : this.copyTextArea(state),\n renderedControl: null,\n };\n }\n\n private copyInput(state: InputState): InputState {\n const {type, pattern, min, max, step} = state;\n return {\n ...this.copySharedState(state),\n type,\n pattern,\n min,\n max,\n step,\n };\n }\n\n private copyTextArea(state: TextAreaState): TextAreaState {\n return {\n ...this.copySharedState(state),\n type: state.type,\n };\n }\n\n private copySharedState({\n value,\n required,\n minLength,\n maxLength,\n }: SharedInputAndTextAreaState): SharedInputAndTextAreaState {\n return {value, required, minLength, maxLength};\n }\n}\n\nfunction isInputState(state: InputState | TextAreaState): state is InputState {\n return state.type !== 'textarea';\n}\n"]}
|
|
@@ -10,9 +10,12 @@
|
|
|
10
10
|
@mixin styles() {
|
|
11
11
|
:host {
|
|
12
12
|
border-radius: var(--_container-shape);
|
|
13
|
+
box-sizing: border-box;
|
|
13
14
|
display: flex;
|
|
14
|
-
|
|
15
|
+
flex-direction: column;
|
|
15
16
|
position: relative;
|
|
17
|
+
// Reset z-index for background elements.
|
|
18
|
+
z-index: 0;
|
|
16
19
|
}
|
|
17
20
|
|
|
18
21
|
// Separate element will be needed for disabled opacities (b/307361748)
|
|
@@ -21,10 +24,14 @@
|
|
|
21
24
|
border-radius: inherit;
|
|
22
25
|
inset: 0;
|
|
23
26
|
position: absolute;
|
|
27
|
+
// Place behind content.
|
|
28
|
+
z-index: -1;
|
|
24
29
|
}
|
|
25
30
|
|
|
26
31
|
md-elevation {
|
|
27
32
|
border-radius: inherit;
|
|
33
|
+
// Place behind content.
|
|
34
|
+
z-index: -1;
|
|
28
35
|
|
|
29
36
|
@include elevation.theme(
|
|
30
37
|
(
|
|
@@ -35,6 +42,7 @@
|
|
|
35
42
|
}
|
|
36
43
|
|
|
37
44
|
slot {
|
|
38
|
-
|
|
45
|
+
// Allow content to inherit card's border radius
|
|
46
|
+
border-radius: inherit;
|
|
39
47
|
}
|
|
40
48
|
}
|
|
@@ -4,6 +4,6 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
import { css } from 'lit';
|
|
7
|
-
export const styles = css `:host{--_container-color: var(--md-outlined-card-container-color, var(--md-sys-color-surface, #fef7ff));--_container-elevation: var(--md-outlined-card-container-elevation, 0);--_container-shadow-color: var(--md-outlined-card-container-shadow-color, var(--md-sys-color-shadow, #000));--_container-shape: var(--md-outlined-card-container-shape, 12px);--_outline-color: var(--md-outlined-card-outline-color, var(--md-sys-color-outline-variant, #cac4d0));--_outline-width: var(--md-outlined-card-outline-width, 1px)}.container{
|
|
7
|
+
export const styles = css `:host{--_container-color: var(--md-outlined-card-container-color, var(--md-sys-color-surface, #fef7ff));--_container-elevation: var(--md-outlined-card-container-elevation, 0);--_container-shadow-color: var(--md-outlined-card-container-shadow-color, var(--md-sys-color-shadow, #000));--_container-shape: var(--md-outlined-card-container-shape, 12px);--_outline-color: var(--md-outlined-card-outline-color, var(--md-sys-color-outline-variant, #cac4d0));--_outline-width: var(--md-outlined-card-outline-width, 1px)}.container{border:var(--_outline-width) solid var(--_outline-color)}/*# sourceMappingURL=outlined-styles.css.map */
|
|
8
8
|
`;
|
|
9
9
|
//# sourceMappingURL=outlined-styles.css.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"outlined-styles.css.js","sourceRoot":"","sources":["outlined-styles.css.ts"],"names":[],"mappings":"AAAA;;;;IAII;AACH,OAAO,EAAC,GAAG,EAAC,MAAM,KAAK,CAAC;AACxB,MAAM,CAAC,MAAM,MAAM,GAAG,GAAG,CAAA;CACzB,CAAC","sourcesContent":["/**\n * @license\n * Copyright 2022 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n import {css} from 'lit';\n export const styles = css`:host{--_container-color: var(--md-outlined-card-container-color, var(--md-sys-color-surface, #fef7ff));--_container-elevation: var(--md-outlined-card-container-elevation, 0);--_container-shadow-color: var(--md-outlined-card-container-shadow-color, var(--md-sys-color-shadow, #000));--_container-shape: var(--md-outlined-card-container-shape, 12px);--_outline-color: var(--md-outlined-card-outline-color, var(--md-sys-color-outline-variant, #cac4d0));--_outline-width: var(--md-outlined-card-outline-width, 1px)}.container{
|
|
1
|
+
{"version":3,"file":"outlined-styles.css.js","sourceRoot":"","sources":["outlined-styles.css.ts"],"names":[],"mappings":"AAAA;;;;IAII;AACH,OAAO,EAAC,GAAG,EAAC,MAAM,KAAK,CAAC;AACxB,MAAM,CAAC,MAAM,MAAM,GAAG,GAAG,CAAA;CACzB,CAAC","sourcesContent":["/**\n * @license\n * Copyright 2022 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n import {css} from 'lit';\n export const styles = css`:host{--_container-color: var(--md-outlined-card-container-color, var(--md-sys-color-surface, #fef7ff));--_container-elevation: var(--md-outlined-card-container-elevation, 0);--_container-shadow-color: var(--md-outlined-card-container-shadow-color, var(--md-sys-color-shadow, #000));--_container-shape: var(--md-outlined-card-container-shape, 12px);--_outline-color: var(--md-outlined-card-outline-color, var(--md-sys-color-outline-variant, #cac4d0));--_outline-width: var(--md-outlined-card-outline-width, 1px)}.container{border:var(--_outline-width) solid var(--_outline-color)}/*# sourceMappingURL=outlined-styles.css.map */\n`;\n "]}
|
|
@@ -4,6 +4,6 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
import { css } from 'lit';
|
|
7
|
-
export const styles = css `:host{border-radius:var(--_container-shape);display:flex;
|
|
7
|
+
export const styles = css `:host{border-radius:var(--_container-shape);box-sizing:border-box;display:flex;flex-direction:column;position:relative;z-index:0}.container{background:var(--_container-color);border-radius:inherit;inset:0;position:absolute;z-index:-1}md-elevation{border-radius:inherit;z-index:-1;--md-elevation-level: var(--_container-elevation);--md-elevation-shadow-color: var(--_container-shadow-color)}slot{border-radius:inherit}/*# sourceMappingURL=shared-styles.css.map */
|
|
8
8
|
`;
|
|
9
9
|
//# sourceMappingURL=shared-styles.css.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared-styles.css.js","sourceRoot":"","sources":["shared-styles.css.ts"],"names":[],"mappings":"AAAA;;;;IAII;AACH,OAAO,EAAC,GAAG,EAAC,MAAM,KAAK,CAAC;AACxB,MAAM,CAAC,MAAM,MAAM,GAAG,GAAG,CAAA;CACzB,CAAC","sourcesContent":["/**\n * @license\n * Copyright 2022 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n import {css} from 'lit';\n export const styles = css`:host{border-radius:var(--_container-shape);display:flex;
|
|
1
|
+
{"version":3,"file":"shared-styles.css.js","sourceRoot":"","sources":["shared-styles.css.ts"],"names":[],"mappings":"AAAA;;;;IAII;AACH,OAAO,EAAC,GAAG,EAAC,MAAM,KAAK,CAAC;AACxB,MAAM,CAAC,MAAM,MAAM,GAAG,GAAG,CAAA;CACzB,CAAC","sourcesContent":["/**\n * @license\n * Copyright 2022 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n import {css} from 'lit';\n export const styles = css`:host{border-radius:var(--_container-shape);box-sizing:border-box;display:flex;flex-direction:column;position:relative;z-index:0}.container{background:var(--_container-color);border-radius:inherit;inset:0;position:absolute;z-index:-1}md-elevation{border-radius:inherit;z-index:-1;--md-elevation-level: var(--_container-elevation);--md-elevation-shadow-color: var(--_container-shadow-color)}slot{border-radius:inherit}/*# sourceMappingURL=shared-styles.css.map */\n`;\n "]}
|
|
@@ -60,6 +60,14 @@ export interface MenuItemControllerConfig {
|
|
|
60
60
|
* A function that returns the headline element of the menu item.
|
|
61
61
|
*/
|
|
62
62
|
getHeadlineElements: () => HTMLElement[];
|
|
63
|
+
/**
|
|
64
|
+
* A function that returns the supporting-text element of the menu item.
|
|
65
|
+
*/
|
|
66
|
+
getSupportingTextElements: () => HTMLElement[];
|
|
67
|
+
/**
|
|
68
|
+
* A function that returns the default slot / misc content.
|
|
69
|
+
*/
|
|
70
|
+
getDefaultElements: () => Node[];
|
|
63
71
|
/**
|
|
64
72
|
* The HTML Element that accepts user interactions like click. Used for
|
|
65
73
|
* occasions like programmatically clicking anchor tags when `Enter` is
|
|
@@ -75,6 +83,8 @@ export declare class MenuItemController implements ReactiveController {
|
|
|
75
83
|
private readonly host;
|
|
76
84
|
private internalTypeaheadText;
|
|
77
85
|
private readonly getHeadlineElements;
|
|
86
|
+
private readonly getSupportingTextElements;
|
|
87
|
+
private readonly getDefaultElements;
|
|
78
88
|
private readonly getInteractiveElement;
|
|
79
89
|
/**
|
|
80
90
|
* @param host The MenuItem in which to attach this controller to.
|
|
@@ -83,7 +93,9 @@ export declare class MenuItemController implements ReactiveController {
|
|
|
83
93
|
constructor(host: ReactiveControllerHost & MenuItem, config: MenuItemControllerConfig);
|
|
84
94
|
/**
|
|
85
95
|
* The text that is selectable via typeahead. If not set, defaults to the
|
|
86
|
-
* innerText of the item slotted into the `"headline"` slot
|
|
96
|
+
* innerText of the item slotted into the `"headline"` slot, and if there are
|
|
97
|
+
* no slotted elements into headline, then it checks the _default_ slot, and
|
|
98
|
+
* then the `"supporting-text"` slot if nothing is in _default_.
|
|
87
99
|
*/
|
|
88
100
|
get typeaheadText(): string;
|
|
89
101
|
/**
|
|
@@ -39,10 +39,15 @@ export class MenuItemController {
|
|
|
39
39
|
interactiveElement.click();
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
|
-
if (
|
|
42
|
+
if (event.defaultPrevented)
|
|
43
43
|
return;
|
|
44
|
+
// If the host has keepOpen = true we should ignore clicks & Space/Enter,
|
|
45
|
+
// however we always maintain the ability to close a menu with a explicit
|
|
46
|
+
// `escape` keypress.
|
|
44
47
|
const keyCode = event.code;
|
|
45
|
-
if (
|
|
48
|
+
if (this.host.keepOpen && keyCode !== 'Escape')
|
|
49
|
+
return;
|
|
50
|
+
if (isClosableKey(keyCode)) {
|
|
46
51
|
event.preventDefault();
|
|
47
52
|
this.host.dispatchEvent(createDefaultCloseMenuEvent(this.host, {
|
|
48
53
|
kind: CloseReason.KEYDOWN,
|
|
@@ -50,14 +55,17 @@ export class MenuItemController {
|
|
|
50
55
|
}));
|
|
51
56
|
}
|
|
52
57
|
};
|
|
53
|
-
|
|
54
|
-
this.
|
|
55
|
-
this.
|
|
58
|
+
this.getHeadlineElements = config.getHeadlineElements;
|
|
59
|
+
this.getSupportingTextElements = config.getSupportingTextElements;
|
|
60
|
+
this.getDefaultElements = config.getDefaultElements;
|
|
61
|
+
this.getInteractiveElement = config.getInteractiveElement;
|
|
56
62
|
this.host.addController(this);
|
|
57
63
|
}
|
|
58
64
|
/**
|
|
59
65
|
* The text that is selectable via typeahead. If not set, defaults to the
|
|
60
|
-
* innerText of the item slotted into the `"headline"` slot
|
|
66
|
+
* innerText of the item slotted into the `"headline"` slot, and if there are
|
|
67
|
+
* no slotted elements into headline, then it checks the _default_ slot, and
|
|
68
|
+
* then the `"supporting-text"` slot if nothing is in _default_.
|
|
61
69
|
*/
|
|
62
70
|
get typeaheadText() {
|
|
63
71
|
if (this.internalTypeaheadText !== null) {
|
|
@@ -70,6 +78,24 @@ export class MenuItemController {
|
|
|
70
78
|
textParts.push(headlineElement.textContent.trim());
|
|
71
79
|
}
|
|
72
80
|
});
|
|
81
|
+
// If there are no headline elements, check the default slot's text content
|
|
82
|
+
if (textParts.length === 0) {
|
|
83
|
+
this.getDefaultElements().forEach((defaultElement) => {
|
|
84
|
+
if (defaultElement.textContent && defaultElement.textContent.trim()) {
|
|
85
|
+
textParts.push(defaultElement.textContent.trim());
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
// If there are no headline nor default slot elements, check the
|
|
90
|
+
//supporting-text slot's text content
|
|
91
|
+
if (textParts.length === 0) {
|
|
92
|
+
this.getSupportingTextElements().forEach((supportingTextElement) => {
|
|
93
|
+
if (supportingTextElement.textContent &&
|
|
94
|
+
supportingTextElement.textContent.trim()) {
|
|
95
|
+
textParts.push(supportingTextElement.textContent.trim());
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
}
|
|
73
99
|
return textParts.join(' ');
|
|
74
100
|
}
|
|
75
101
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"menuItemController.js","sourceRoot":"","sources":["menuItemController.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license\n * Copyright 2023 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {ReactiveController, ReactiveControllerHost} from 'lit';\n\nimport {\n CloseReason,\n createDefaultCloseMenuEvent,\n isClosableKey,\n} from './shared.js';\n\n/**\n * Interface specific to menu item and not HTMLElement.\n *\n * NOTE: required properties are expected to be reactive.\n */\ninterface MenuItemAdditions {\n /**\n * Whether or not the item is in the disabled state.\n */\n disabled: boolean;\n /**\n * The text of the item that will be used for typeahead. If not set, defaults\n * to the textContent of the element slotted into the headline.\n */\n typeaheadText: string;\n /**\n * Whether or not the item is in the selected visual state.\n */\n selected: boolean;\n /**\n * Sets the behavior and role of the menu item, defaults to \"menuitem\".\n */\n type: MenuItemType;\n /**\n * Whether it should keep the menu open after click.\n */\n keepOpen?: boolean;\n /**\n * Sets the underlying `HTMLAnchorElement`'s `href` resource attribute.\n */\n href?: string;\n /**\n * Focuses the item.\n */\n focus: () => void;\n}\n\n/**\n * The interface of every menu item interactive with a menu. All menu items\n * should implement this interface to be compatible with md-menu. Additionally\n * it should have the `md-menu-item` attribute set.\n *\n * NOTE, the required properties are recommended to be reactive properties.\n */\nexport type MenuItem = MenuItemAdditions & HTMLElement;\n\n/**\n * Supported behaviors for a menu item.\n */\nexport type MenuItemType = 'menuitem' | 'option' | 'button' | 'link';\n\n/**\n * The options used to inialize MenuItemController.\n */\nexport interface MenuItemControllerConfig {\n /**\n * A function that returns the headline element of the menu item.\n */\n getHeadlineElements: () => HTMLElement[];\n\n /**\n * The HTML Element that accepts user interactions like click. Used for\n * occasions like programmatically clicking anchor tags when `Enter` is\n * pressed.\n */\n getInteractiveElement: () => HTMLElement | null;\n}\n\n/**\n * A controller that provides most functionality of an element that implements\n * the MenuItem interface.\n */\nexport class MenuItemController implements ReactiveController {\n private internalTypeaheadText: string | null = null;\n private readonly getHeadlineElements: MenuItemControllerConfig['getHeadlineElements'];\n private readonly getInteractiveElement: MenuItemControllerConfig['getInteractiveElement'];\n\n /**\n * @param host The MenuItem in which to attach this controller to.\n * @param config The object that configures this controller's behavior.\n */\n constructor(\n private readonly host: ReactiveControllerHost & MenuItem,\n config: MenuItemControllerConfig,\n ) {\n const {getHeadlineElements, getInteractiveElement} = config;\n this.getHeadlineElements = getHeadlineElements;\n this.getInteractiveElement = getInteractiveElement;\n this.host.addController(this);\n }\n\n /**\n * The text that is selectable via typeahead. If not set, defaults to the\n * innerText of the item slotted into the `\"headline\"` slot.\n */\n get typeaheadText() {\n if (this.internalTypeaheadText !== null) {\n return this.internalTypeaheadText;\n }\n\n const headlineElements = this.getHeadlineElements();\n\n const textParts: string[] = [];\n headlineElements.forEach((headlineElement) => {\n if (headlineElement.textContent && headlineElement.textContent.trim()) {\n textParts.push(headlineElement.textContent.trim());\n }\n });\n\n return textParts.join(' ');\n }\n\n /**\n * The recommended tag name to render as the list item.\n */\n get tagName() {\n const type = this.host.type;\n\n switch (type) {\n case 'link':\n return 'a' as const;\n case 'button':\n return 'button' as const;\n default:\n case 'menuitem':\n case 'option':\n return 'li' as const;\n }\n }\n\n /**\n * The recommended role of the menu item.\n */\n get role() {\n return this.host.type === 'option' ? 'option' : 'menuitem';\n }\n\n hostConnected() {\n this.host.toggleAttribute('md-menu-item', true);\n }\n\n hostUpdate() {\n if (this.host.href) {\n this.host.type = 'link';\n }\n }\n\n /**\n * Bind this click listener to the interactive element. Handles closing the\n * menu.\n */\n onClick = () => {\n if (this.host.keepOpen) return;\n\n this.host.dispatchEvent(\n createDefaultCloseMenuEvent(this.host, {\n kind: CloseReason.CLICK_SELECTION,\n }),\n );\n };\n\n /**\n * Bind this click listener to the interactive element. Handles closing the\n * menu.\n */\n onKeydown = (event: KeyboardEvent) => {\n // Check if the interactive element is an anchor tag. If so, click it.\n if (this.host.href && event.code === 'Enter') {\n const interactiveElement = this.getInteractiveElement();\n if (interactiveElement instanceof HTMLAnchorElement) {\n interactiveElement.click();\n }\n }\n\n if (this.host.keepOpen || event.defaultPrevented) return;\n const keyCode = event.code;\n\n if (!event.defaultPrevented && isClosableKey(keyCode)) {\n event.preventDefault();\n this.host.dispatchEvent(\n createDefaultCloseMenuEvent(this.host, {\n kind: CloseReason.KEYDOWN,\n key: keyCode,\n }),\n );\n }\n };\n\n /**\n * Use to set the typeaheadText when it changes.\n */\n setTypeaheadText(text: string) {\n this.internalTypeaheadText = text;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"menuItemController.js","sourceRoot":"","sources":["menuItemController.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license\n * Copyright 2023 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {ReactiveController, ReactiveControllerHost} from 'lit';\n\nimport {\n CloseReason,\n createDefaultCloseMenuEvent,\n isClosableKey,\n} from './shared.js';\n\n/**\n * Interface specific to menu item and not HTMLElement.\n *\n * NOTE: required properties are expected to be reactive.\n */\ninterface MenuItemAdditions {\n /**\n * Whether or not the item is in the disabled state.\n */\n disabled: boolean;\n /**\n * The text of the item that will be used for typeahead. If not set, defaults\n * to the textContent of the element slotted into the headline.\n */\n typeaheadText: string;\n /**\n * Whether or not the item is in the selected visual state.\n */\n selected: boolean;\n /**\n * Sets the behavior and role of the menu item, defaults to \"menuitem\".\n */\n type: MenuItemType;\n /**\n * Whether it should keep the menu open after click.\n */\n keepOpen?: boolean;\n /**\n * Sets the underlying `HTMLAnchorElement`'s `href` resource attribute.\n */\n href?: string;\n /**\n * Focuses the item.\n */\n focus: () => void;\n}\n\n/**\n * The interface of every menu item interactive with a menu. All menu items\n * should implement this interface to be compatible with md-menu. Additionally\n * it should have the `md-menu-item` attribute set.\n *\n * NOTE, the required properties are recommended to be reactive properties.\n */\nexport type MenuItem = MenuItemAdditions & HTMLElement;\n\n/**\n * Supported behaviors for a menu item.\n */\nexport type MenuItemType = 'menuitem' | 'option' | 'button' | 'link';\n\n/**\n * The options used to inialize MenuItemController.\n */\nexport interface MenuItemControllerConfig {\n /**\n * A function that returns the headline element of the menu item.\n */\n getHeadlineElements: () => HTMLElement[];\n\n /**\n * A function that returns the supporting-text element of the menu item.\n */\n getSupportingTextElements: () => HTMLElement[];\n\n /**\n * A function that returns the default slot / misc content.\n */\n getDefaultElements: () => Node[];\n\n /**\n * The HTML Element that accepts user interactions like click. Used for\n * occasions like programmatically clicking anchor tags when `Enter` is\n * pressed.\n */\n getInteractiveElement: () => HTMLElement | null;\n}\n\n/**\n * A controller that provides most functionality of an element that implements\n * the MenuItem interface.\n */\nexport class MenuItemController implements ReactiveController {\n private internalTypeaheadText: string | null = null;\n private readonly getHeadlineElements: MenuItemControllerConfig['getHeadlineElements'];\n private readonly getSupportingTextElements: MenuItemControllerConfig['getSupportingTextElements'];\n private readonly getDefaultElements: MenuItemControllerConfig['getDefaultElements'];\n private readonly getInteractiveElement: MenuItemControllerConfig['getInteractiveElement'];\n\n /**\n * @param host The MenuItem in which to attach this controller to.\n * @param config The object that configures this controller's behavior.\n */\n constructor(\n private readonly host: ReactiveControllerHost & MenuItem,\n config: MenuItemControllerConfig,\n ) {\n this.getHeadlineElements = config.getHeadlineElements;\n this.getSupportingTextElements = config.getSupportingTextElements;\n this.getDefaultElements = config.getDefaultElements;\n this.getInteractiveElement = config.getInteractiveElement;\n this.host.addController(this);\n }\n\n /**\n * The text that is selectable via typeahead. If not set, defaults to the\n * innerText of the item slotted into the `\"headline\"` slot, and if there are\n * no slotted elements into headline, then it checks the _default_ slot, and\n * then the `\"supporting-text\"` slot if nothing is in _default_.\n */\n get typeaheadText() {\n if (this.internalTypeaheadText !== null) {\n return this.internalTypeaheadText;\n }\n\n const headlineElements = this.getHeadlineElements();\n\n const textParts: string[] = [];\n headlineElements.forEach((headlineElement) => {\n if (headlineElement.textContent && headlineElement.textContent.trim()) {\n textParts.push(headlineElement.textContent.trim());\n }\n });\n\n // If there are no headline elements, check the default slot's text content\n if (textParts.length === 0) {\n this.getDefaultElements().forEach((defaultElement) => {\n if (defaultElement.textContent && defaultElement.textContent.trim()) {\n textParts.push(defaultElement.textContent.trim());\n }\n });\n }\n\n // If there are no headline nor default slot elements, check the\n //supporting-text slot's text content\n if (textParts.length === 0) {\n this.getSupportingTextElements().forEach((supportingTextElement) => {\n if (\n supportingTextElement.textContent &&\n supportingTextElement.textContent.trim()\n ) {\n textParts.push(supportingTextElement.textContent.trim());\n }\n });\n }\n\n return textParts.join(' ');\n }\n\n /**\n * The recommended tag name to render as the list item.\n */\n get tagName() {\n const type = this.host.type;\n\n switch (type) {\n case 'link':\n return 'a' as const;\n case 'button':\n return 'button' as const;\n default:\n case 'menuitem':\n case 'option':\n return 'li' as const;\n }\n }\n\n /**\n * The recommended role of the menu item.\n */\n get role() {\n return this.host.type === 'option' ? 'option' : 'menuitem';\n }\n\n hostConnected() {\n this.host.toggleAttribute('md-menu-item', true);\n }\n\n hostUpdate() {\n if (this.host.href) {\n this.host.type = 'link';\n }\n }\n\n /**\n * Bind this click listener to the interactive element. Handles closing the\n * menu.\n */\n onClick = () => {\n if (this.host.keepOpen) return;\n\n this.host.dispatchEvent(\n createDefaultCloseMenuEvent(this.host, {\n kind: CloseReason.CLICK_SELECTION,\n }),\n );\n };\n\n /**\n * Bind this click listener to the interactive element. Handles closing the\n * menu.\n */\n onKeydown = (event: KeyboardEvent) => {\n // Check if the interactive element is an anchor tag. If so, click it.\n if (this.host.href && event.code === 'Enter') {\n const interactiveElement = this.getInteractiveElement();\n if (interactiveElement instanceof HTMLAnchorElement) {\n interactiveElement.click();\n }\n }\n\n if (event.defaultPrevented) return;\n\n // If the host has keepOpen = true we should ignore clicks & Space/Enter,\n // however we always maintain the ability to close a menu with a explicit\n // `escape` keypress.\n const keyCode = event.code;\n if (this.host.keepOpen && keyCode !== 'Escape') return;\n\n if (isClosableKey(keyCode)) {\n event.preventDefault();\n this.host.dispatchEvent(\n createDefaultCloseMenuEvent(this.host, {\n kind: CloseReason.KEYDOWN,\n key: keyCode,\n }),\n );\n }\n };\n\n /**\n * Use to set the typeaheadText when it changes.\n */\n setTypeaheadText(text: string) {\n this.internalTypeaheadText = text;\n }\n}\n"]}
|
|
@@ -47,6 +47,8 @@ export declare class MenuItemEl extends LitElement implements MenuItem {
|
|
|
47
47
|
selected: boolean;
|
|
48
48
|
protected readonly listItemRoot: HTMLElement | null;
|
|
49
49
|
protected readonly headlineElements: HTMLElement[];
|
|
50
|
+
protected readonly supportingTextElements: HTMLElement[];
|
|
51
|
+
protected readonly defaultElements: Node[];
|
|
50
52
|
/**
|
|
51
53
|
* The text that is selectable via typeahead. If not set, defaults to the
|
|
52
54
|
* innerText of the item slotted into the `"headline"` slot.
|
|
@@ -8,7 +8,7 @@ import '../../../focus/md-focus-ring.js';
|
|
|
8
8
|
import '../../../labs/item/item.js';
|
|
9
9
|
import '../../../ripple/ripple.js';
|
|
10
10
|
import { html, LitElement, nothing } from 'lit';
|
|
11
|
-
import { property, query, queryAssignedElements } from 'lit/decorators.js';
|
|
11
|
+
import { property, query, queryAssignedElements, queryAssignedNodes, } from 'lit/decorators.js';
|
|
12
12
|
import { classMap } from 'lit/directives/class-map.js';
|
|
13
13
|
import { literal, html as staticHtml } from 'lit/static-html.js';
|
|
14
14
|
import { requestUpdateOnAriaChange } from '../../../internal/aria/delegate.js';
|
|
@@ -49,6 +49,12 @@ export class MenuItemEl extends LitElement {
|
|
|
49
49
|
getHeadlineElements: () => {
|
|
50
50
|
return this.headlineElements;
|
|
51
51
|
},
|
|
52
|
+
getSupportingTextElements: () => {
|
|
53
|
+
return this.supportingTextElements;
|
|
54
|
+
},
|
|
55
|
+
getDefaultElements: () => {
|
|
56
|
+
return this.defaultElements;
|
|
57
|
+
},
|
|
52
58
|
getInteractiveElement: () => this.listItemRoot,
|
|
53
59
|
});
|
|
54
60
|
}
|
|
@@ -194,6 +200,12 @@ __decorate([
|
|
|
194
200
|
__decorate([
|
|
195
201
|
queryAssignedElements({ slot: 'headline' })
|
|
196
202
|
], MenuItemEl.prototype, "headlineElements", void 0);
|
|
203
|
+
__decorate([
|
|
204
|
+
queryAssignedElements({ slot: 'supporting-text' })
|
|
205
|
+
], MenuItemEl.prototype, "supportingTextElements", void 0);
|
|
206
|
+
__decorate([
|
|
207
|
+
queryAssignedNodes({ slot: '' })
|
|
208
|
+
], MenuItemEl.prototype, "defaultElements", void 0);
|
|
197
209
|
__decorate([
|
|
198
210
|
property({ attribute: 'typeahead-text' })
|
|
199
211
|
], MenuItemEl.prototype, "typeaheadText", null);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"menu-item.js","sourceRoot":"","sources":["menu-item.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license\n * Copyright 2022 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport '../../../focus/md-focus-ring.js';\nimport '../../../labs/item/item.js';\nimport '../../../ripple/ripple.js';\n\nimport {html, LitElement, nothing, TemplateResult} from 'lit';\nimport {property, query, queryAssignedElements} from 'lit/decorators.js';\nimport {ClassInfo, classMap} from 'lit/directives/class-map.js';\nimport {literal, html as staticHtml, StaticValue} from 'lit/static-html.js';\n\nimport {ARIAMixinStrict} from '../../../internal/aria/aria.js';\nimport {requestUpdateOnAriaChange} from '../../../internal/aria/delegate.js';\nimport {\n MenuItem,\n MenuItemController,\n MenuItemType,\n} from '../controllers/menuItemController.js';\n\n/**\n * @fires close-menu {CustomEvent<{initiator: SelectOption, reason: Reason, itemPath: SelectOption[]}>}\n * Closes the encapsulating menu on closable interaction. --bubbles --composed\n */\nexport class MenuItemEl extends LitElement implements MenuItem {\n static {\n requestUpdateOnAriaChange(MenuItemEl);\n }\n\n /** @nocollapse */\n static override shadowRootOptions = {\n ...LitElement.shadowRootOptions,\n delegatesFocus: true,\n };\n\n /**\n * Disables the item and makes it non-selectable and non-interactive.\n */\n @property({type: Boolean, reflect: true}) disabled = false;\n\n /**\n * Sets the behavior and role of the menu item, defaults to \"menuitem\".\n */\n @property() type: MenuItemType = 'menuitem';\n\n /**\n * Sets the underlying `HTMLAnchorElement`'s `href` resource attribute.\n */\n @property() href = '';\n\n /**\n * Sets the underlying `HTMLAnchorElement`'s `target` attribute when `href` is\n * set.\n */\n @property() target: '_blank' | '_parent' | '_self' | '_top' | '' = '';\n\n /**\n * Keeps the menu open if clicked or keyboard selected.\n */\n @property({type: Boolean, attribute: 'keep-open'}) keepOpen = false;\n\n /**\n * Sets the item in the selected visual state when a submenu is opened.\n */\n @property({type: Boolean}) selected = false;\n\n @query('.list-item') protected readonly listItemRoot!: HTMLElement | null;\n\n @queryAssignedElements({slot: 'headline'})\n protected readonly headlineElements!: HTMLElement[];\n\n /**\n * The text that is selectable via typeahead. If not set, defaults to the\n * innerText of the item slotted into the `\"headline\"` slot.\n */\n get typeaheadText() {\n return this.menuItemController.typeaheadText;\n }\n\n @property({attribute: 'typeahead-text'})\n set typeaheadText(text: string) {\n this.menuItemController.setTypeaheadText(text);\n }\n\n private readonly menuItemController = new MenuItemController(this, {\n getHeadlineElements: () => {\n return this.headlineElements;\n },\n getInteractiveElement: () => this.listItemRoot,\n });\n\n protected override render() {\n return this.renderListItem(html`\n <md-item>\n <div slot=\"container\">\n ${this.renderRipple()} ${this.renderFocusRing()}\n </div>\n <slot name=\"start\" slot=\"start\"></slot>\n <slot name=\"end\" slot=\"end\"></slot>\n ${this.renderBody()}\n </md-item>\n `);\n }\n\n /**\n * Renders the root list item.\n *\n * @param content the child content of the list item.\n */\n protected renderListItem(content: unknown) {\n const isAnchor = this.type === 'link';\n let tag: StaticValue;\n switch (this.menuItemController.tagName) {\n case 'a':\n tag = literal`a`;\n break;\n case 'button':\n tag = literal`button`;\n break;\n default:\n case 'li':\n tag = literal`li`;\n break;\n }\n\n // TODO(b/265339866): announce \"button\"/\"link\" inside of a list item. Until\n // then all are \"menuitem\" roles for correct announcement.\n const target = isAnchor && !!this.target ? this.target : nothing;\n return staticHtml`\n <${tag}\n id=\"item\"\n tabindex=${this.disabled && !isAnchor ? -1 : 0}\n role=${this.menuItemController.role}\n aria-label=${(this as ARIAMixinStrict).ariaLabel || nothing}\n aria-selected=${(this as ARIAMixinStrict).ariaSelected || nothing}\n aria-checked=${(this as ARIAMixinStrict).ariaChecked || nothing}\n aria-expanded=${(this as ARIAMixinStrict).ariaExpanded || nothing}\n aria-haspopup=${(this as ARIAMixinStrict).ariaHasPopup || nothing}\n class=\"list-item ${classMap(this.getRenderClasses())}\"\n href=${this.href || nothing}\n target=${target}\n @click=${this.menuItemController.onClick}\n @keydown=${this.menuItemController.onKeydown}\n >${content}</${tag}>\n `;\n }\n\n /**\n * Handles rendering of the ripple element.\n */\n protected renderRipple(): TemplateResult | typeof nothing {\n return html` <md-ripple\n part=\"ripple\"\n for=\"item\"\n ?disabled=${this.disabled}></md-ripple>`;\n }\n\n /**\n * Handles rendering of the focus ring.\n */\n protected renderFocusRing(): TemplateResult | typeof nothing {\n return html` <md-focus-ring\n part=\"focus-ring\"\n for=\"item\"\n inward></md-focus-ring>`;\n }\n\n /**\n * Classes applied to the list item root.\n */\n protected getRenderClasses(): ClassInfo {\n return {\n 'disabled': this.disabled,\n 'selected': this.selected,\n };\n }\n\n /**\n * Handles rendering the headline and supporting text.\n */\n protected renderBody() {\n return html`\n <slot></slot>\n <slot name=\"overline\" slot=\"overline\"></slot>\n <slot name=\"headline\" slot=\"headline\"></slot>\n <slot name=\"supporting-text\" slot=\"supporting-text\"></slot>\n <slot\n name=\"trailing-supporting-text\"\n slot=\"trailing-supporting-text\"></slot>\n `;\n }\n\n override focus() {\n // TODO(b/300334509): needed for some cases where delegatesFocus doesn't\n // work programmatically like in FF and select-option\n this.listItemRoot?.focus();\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"menu-item.js","sourceRoot":"","sources":["menu-item.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license\n * Copyright 2022 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport '../../../focus/md-focus-ring.js';\nimport '../../../labs/item/item.js';\nimport '../../../ripple/ripple.js';\n\nimport {html, LitElement, nothing, TemplateResult} from 'lit';\nimport {\n property,\n query,\n queryAssignedElements,\n queryAssignedNodes,\n} from 'lit/decorators.js';\nimport {ClassInfo, classMap} from 'lit/directives/class-map.js';\nimport {literal, html as staticHtml, StaticValue} from 'lit/static-html.js';\n\nimport {ARIAMixinStrict} from '../../../internal/aria/aria.js';\nimport {requestUpdateOnAriaChange} from '../../../internal/aria/delegate.js';\nimport {\n MenuItem,\n MenuItemController,\n MenuItemType,\n} from '../controllers/menuItemController.js';\n\n/**\n * @fires close-menu {CustomEvent<{initiator: SelectOption, reason: Reason, itemPath: SelectOption[]}>}\n * Closes the encapsulating menu on closable interaction. --bubbles --composed\n */\nexport class MenuItemEl extends LitElement implements MenuItem {\n static {\n requestUpdateOnAriaChange(MenuItemEl);\n }\n\n /** @nocollapse */\n static override shadowRootOptions = {\n ...LitElement.shadowRootOptions,\n delegatesFocus: true,\n };\n\n /**\n * Disables the item and makes it non-selectable and non-interactive.\n */\n @property({type: Boolean, reflect: true}) disabled = false;\n\n /**\n * Sets the behavior and role of the menu item, defaults to \"menuitem\".\n */\n @property() type: MenuItemType = 'menuitem';\n\n /**\n * Sets the underlying `HTMLAnchorElement`'s `href` resource attribute.\n */\n @property() href = '';\n\n /**\n * Sets the underlying `HTMLAnchorElement`'s `target` attribute when `href` is\n * set.\n */\n @property() target: '_blank' | '_parent' | '_self' | '_top' | '' = '';\n\n /**\n * Keeps the menu open if clicked or keyboard selected.\n */\n @property({type: Boolean, attribute: 'keep-open'}) keepOpen = false;\n\n /**\n * Sets the item in the selected visual state when a submenu is opened.\n */\n @property({type: Boolean}) selected = false;\n\n @query('.list-item') protected readonly listItemRoot!: HTMLElement | null;\n\n @queryAssignedElements({slot: 'headline'})\n protected readonly headlineElements!: HTMLElement[];\n @queryAssignedElements({slot: 'supporting-text'})\n protected readonly supportingTextElements!: HTMLElement[];\n @queryAssignedNodes({slot: ''})\n protected readonly defaultElements!: Node[];\n\n /**\n * The text that is selectable via typeahead. If not set, defaults to the\n * innerText of the item slotted into the `\"headline\"` slot.\n */\n get typeaheadText() {\n return this.menuItemController.typeaheadText;\n }\n\n @property({attribute: 'typeahead-text'})\n set typeaheadText(text: string) {\n this.menuItemController.setTypeaheadText(text);\n }\n\n private readonly menuItemController = new MenuItemController(this, {\n getHeadlineElements: () => {\n return this.headlineElements;\n },\n getSupportingTextElements: () => {\n return this.supportingTextElements;\n },\n getDefaultElements: () => {\n return this.defaultElements;\n },\n getInteractiveElement: () => this.listItemRoot,\n });\n\n protected override render() {\n return this.renderListItem(html`\n <md-item>\n <div slot=\"container\">\n ${this.renderRipple()} ${this.renderFocusRing()}\n </div>\n <slot name=\"start\" slot=\"start\"></slot>\n <slot name=\"end\" slot=\"end\"></slot>\n ${this.renderBody()}\n </md-item>\n `);\n }\n\n /**\n * Renders the root list item.\n *\n * @param content the child content of the list item.\n */\n protected renderListItem(content: unknown) {\n const isAnchor = this.type === 'link';\n let tag: StaticValue;\n switch (this.menuItemController.tagName) {\n case 'a':\n tag = literal`a`;\n break;\n case 'button':\n tag = literal`button`;\n break;\n default:\n case 'li':\n tag = literal`li`;\n break;\n }\n\n // TODO(b/265339866): announce \"button\"/\"link\" inside of a list item. Until\n // then all are \"menuitem\" roles for correct announcement.\n const target = isAnchor && !!this.target ? this.target : nothing;\n return staticHtml`\n <${tag}\n id=\"item\"\n tabindex=${this.disabled && !isAnchor ? -1 : 0}\n role=${this.menuItemController.role}\n aria-label=${(this as ARIAMixinStrict).ariaLabel || nothing}\n aria-selected=${(this as ARIAMixinStrict).ariaSelected || nothing}\n aria-checked=${(this as ARIAMixinStrict).ariaChecked || nothing}\n aria-expanded=${(this as ARIAMixinStrict).ariaExpanded || nothing}\n aria-haspopup=${(this as ARIAMixinStrict).ariaHasPopup || nothing}\n class=\"list-item ${classMap(this.getRenderClasses())}\"\n href=${this.href || nothing}\n target=${target}\n @click=${this.menuItemController.onClick}\n @keydown=${this.menuItemController.onKeydown}\n >${content}</${tag}>\n `;\n }\n\n /**\n * Handles rendering of the ripple element.\n */\n protected renderRipple(): TemplateResult | typeof nothing {\n return html` <md-ripple\n part=\"ripple\"\n for=\"item\"\n ?disabled=${this.disabled}></md-ripple>`;\n }\n\n /**\n * Handles rendering of the focus ring.\n */\n protected renderFocusRing(): TemplateResult | typeof nothing {\n return html` <md-focus-ring\n part=\"focus-ring\"\n for=\"item\"\n inward></md-focus-ring>`;\n }\n\n /**\n * Classes applied to the list item root.\n */\n protected getRenderClasses(): ClassInfo {\n return {\n 'disabled': this.disabled,\n 'selected': this.selected,\n };\n }\n\n /**\n * Handles rendering the headline and supporting text.\n */\n protected renderBody() {\n return html`\n <slot></slot>\n <slot name=\"overline\" slot=\"overline\"></slot>\n <slot name=\"headline\" slot=\"headline\"></slot>\n <slot name=\"supporting-text\" slot=\"supporting-text\"></slot>\n <slot\n name=\"trailing-supporting-text\"\n slot=\"trailing-supporting-text\"></slot>\n `;\n }\n\n override focus() {\n // TODO(b/300334509): needed for some cases where delegatesFocus doesn't\n // work programmatically like in FF and select-option\n this.listItemRoot?.focus();\n }\n}\n"]}
|
package/package.json
CHANGED