@vaadin/select 22.0.0-rc1 → 23.0.0-alpha2
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/package.json +14 -14
- package/src/vaadin-select-item.js +20 -0
- package/src/vaadin-select-list-box.js +20 -0
- package/src/vaadin-select-value-button.js +2 -2
- package/src/vaadin-select.d.ts +60 -5
- package/src/vaadin-select.js +122 -28
- package/theme/lumo/vaadin-select-styles.js +1 -1
- package/theme/material/vaadin-select-styles.js +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vaadin/select",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "23.0.0-alpha2",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -34,24 +34,24 @@
|
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@polymer/iron-media-query": "^3.0.0",
|
|
36
36
|
"@polymer/polymer": "^3.2.0",
|
|
37
|
-
"@vaadin/button": "
|
|
38
|
-
"@vaadin/component-base": "
|
|
39
|
-
"@vaadin/field-base": "
|
|
40
|
-
"@vaadin/input-container": "
|
|
41
|
-
"@vaadin/item": "
|
|
42
|
-
"@vaadin/list-box": "
|
|
43
|
-
"@vaadin/vaadin-list-mixin": "
|
|
44
|
-
"@vaadin/vaadin-lumo-styles": "
|
|
45
|
-
"@vaadin/vaadin-material-styles": "
|
|
46
|
-
"@vaadin/vaadin-overlay": "
|
|
47
|
-
"@vaadin/vaadin-themable-mixin": "
|
|
37
|
+
"@vaadin/button": "23.0.0-alpha2",
|
|
38
|
+
"@vaadin/component-base": "23.0.0-alpha2",
|
|
39
|
+
"@vaadin/field-base": "23.0.0-alpha2",
|
|
40
|
+
"@vaadin/input-container": "23.0.0-alpha2",
|
|
41
|
+
"@vaadin/item": "23.0.0-alpha2",
|
|
42
|
+
"@vaadin/list-box": "23.0.0-alpha2",
|
|
43
|
+
"@vaadin/vaadin-list-mixin": "23.0.0-alpha2",
|
|
44
|
+
"@vaadin/vaadin-lumo-styles": "23.0.0-alpha2",
|
|
45
|
+
"@vaadin/vaadin-material-styles": "23.0.0-alpha2",
|
|
46
|
+
"@vaadin/vaadin-overlay": "23.0.0-alpha2",
|
|
47
|
+
"@vaadin/vaadin-themable-mixin": "23.0.0-alpha2"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@esm-bundle/chai": "^4.3.4",
|
|
51
|
-
"@vaadin/polymer-legacy-adapter": "
|
|
51
|
+
"@vaadin/polymer-legacy-adapter": "23.0.0-alpha2",
|
|
52
52
|
"@vaadin/testing-helpers": "^0.3.2",
|
|
53
53
|
"lit": "^2.0.0",
|
|
54
54
|
"sinon": "^9.2.0"
|
|
55
55
|
},
|
|
56
|
-
"gitHead": "
|
|
56
|
+
"gitHead": "070f586dead02ca41b66717820c647f48bf1665f"
|
|
57
57
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright (c) 2021 Vaadin Ltd.
|
|
4
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
|
+
*/
|
|
6
|
+
import { Item } from '@vaadin/item/src/vaadin-item.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* An element used internally by `<vaadin-select>`. Not intended to be used separately.
|
|
10
|
+
*
|
|
11
|
+
* @extends Item
|
|
12
|
+
* @protected
|
|
13
|
+
*/
|
|
14
|
+
class SelectItem extends Item {
|
|
15
|
+
static get is() {
|
|
16
|
+
return 'vaadin-select-item';
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
customElements.define(SelectItem.is, SelectItem);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright (c) 2021 Vaadin Ltd.
|
|
4
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
|
+
*/
|
|
6
|
+
import { ListBox } from '@vaadin/list-box/src/vaadin-list-box.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* An element used internally by `<vaadin-select>`. Not intended to be used separately.
|
|
10
|
+
*
|
|
11
|
+
* @extends ListBox
|
|
12
|
+
* @protected
|
|
13
|
+
*/
|
|
14
|
+
class SelectListBox extends ListBox {
|
|
15
|
+
static get is() {
|
|
16
|
+
return 'vaadin-select-list-box';
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
customElements.define(SelectListBox.is, SelectListBox);
|
|
@@ -14,14 +14,14 @@ registerStyles(
|
|
|
14
14
|
min-width: 0;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
::slotted(
|
|
17
|
+
::slotted(:not([slot])) {
|
|
18
18
|
padding-left: 0;
|
|
19
19
|
padding-right: 0;
|
|
20
20
|
flex: auto;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
/* placeholder styles */
|
|
24
|
-
::slotted(:not([selected])) {
|
|
24
|
+
::slotted(:not([slot]):not([selected])) {
|
|
25
25
|
line-height: normal;
|
|
26
26
|
}
|
|
27
27
|
|
package/src/vaadin-select.d.ts
CHANGED
|
@@ -9,6 +9,19 @@ import { DelegateFocusMixin } from '@vaadin/field-base/src/delegate-focus-mixin.
|
|
|
9
9
|
import { FieldMixin } from '@vaadin/field-base/src/field-mixin.js';
|
|
10
10
|
import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
|
|
11
11
|
|
|
12
|
+
export interface SelectItem {
|
|
13
|
+
label?: string;
|
|
14
|
+
component?: string;
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Fired when the user commits a value change.
|
|
20
|
+
*/
|
|
21
|
+
export type SelectChangeEvent = Event & {
|
|
22
|
+
target: Select;
|
|
23
|
+
};
|
|
24
|
+
|
|
12
25
|
/**
|
|
13
26
|
* Function for rendering the content of the `<vaadin-select>`.
|
|
14
27
|
* Receives two arguments:
|
|
@@ -42,22 +55,41 @@ export interface SelectCustomEventMap {
|
|
|
42
55
|
'value-changed': SelectValueChangedEvent;
|
|
43
56
|
}
|
|
44
57
|
|
|
45
|
-
export interface SelectEventMap extends HTMLElementEventMap, SelectCustomEventMap {
|
|
58
|
+
export interface SelectEventMap extends HTMLElementEventMap, SelectCustomEventMap {
|
|
59
|
+
change: SelectChangeEvent;
|
|
60
|
+
}
|
|
46
61
|
|
|
47
62
|
/**
|
|
48
63
|
* `<vaadin-select>` is a Web Component for selecting values from a list of items.
|
|
49
64
|
*
|
|
65
|
+
* ### Items
|
|
66
|
+
*
|
|
67
|
+
* Use the `items` property to define possible options for the select:
|
|
68
|
+
*
|
|
69
|
+
* ```html
|
|
70
|
+
* <vaadin-select id="select"></vaadin-select>
|
|
71
|
+
* ```
|
|
72
|
+
* ```js
|
|
73
|
+
* const select = document.querySelector('#select');
|
|
74
|
+
* select.items = [
|
|
75
|
+
* { label: 'Most recent first', value: 'recent' },
|
|
76
|
+
* { component: 'hr' },
|
|
77
|
+
* { label: 'Rating: low to high', value: 'rating-asc' },
|
|
78
|
+
* { label: 'Rating: high to low', value: 'rating-desc' },
|
|
79
|
+
* { component: 'hr' },
|
|
80
|
+
* { label: 'Price: low to high', value: 'price-asc', disabled: true },
|
|
81
|
+
* { label: 'Price: high to low', value: 'price-desc', disabled: true }
|
|
82
|
+
* ];
|
|
83
|
+
* ```
|
|
84
|
+
*
|
|
50
85
|
* ### Rendering
|
|
51
86
|
*
|
|
52
|
-
*
|
|
87
|
+
* Alternatively, the content of the select can be populated by using the renderer callback function.
|
|
53
88
|
*
|
|
54
89
|
* The renderer function provides `root`, `select` arguments.
|
|
55
90
|
* Generate DOM content, append it to the `root` element and control the state
|
|
56
91
|
* of the host element by accessing `select`.
|
|
57
92
|
*
|
|
58
|
-
* ```html
|
|
59
|
-
* <vaadin-select id="select"></vaadin-select>
|
|
60
|
-
* ```
|
|
61
93
|
* ```js
|
|
62
94
|
* const select = document.querySelector('#select');
|
|
63
95
|
* select.renderer = function(root, select) {
|
|
@@ -132,6 +164,29 @@ export interface SelectEventMap extends HTMLElementEventMap, SelectCustomEventMa
|
|
|
132
164
|
* @fires {CustomEvent} value-changed - Fired when the `value` property changes.
|
|
133
165
|
*/
|
|
134
166
|
declare class Select extends DelegateFocusMixin(FieldMixin(SlotMixin(ElementMixin(ThemableMixin(HTMLElement))))) {
|
|
167
|
+
/**
|
|
168
|
+
* An array containing items that will be rendered as the options of the select.
|
|
169
|
+
*
|
|
170
|
+
* #### Example
|
|
171
|
+
* ```js
|
|
172
|
+
* select.items = [
|
|
173
|
+
* { label: 'Most recent first', value: 'recent' },
|
|
174
|
+
* { component: 'hr' },
|
|
175
|
+
* { label: 'Rating: low to high', value: 'rating-asc' },
|
|
176
|
+
* { label: 'Rating: high to low', value: 'rating-desc' },
|
|
177
|
+
* { component: 'hr' },
|
|
178
|
+
* { label: 'Price: low to high', value: 'price-asc', disabled: true },
|
|
179
|
+
* { label: 'Price: high to low', value: 'price-desc', disabled: true }
|
|
180
|
+
* ];
|
|
181
|
+
* ```
|
|
182
|
+
*
|
|
183
|
+
* Note: each item is rendered by default as the internal `<vaadin-select-item>` that is an extension of `<vaadin-item>`.
|
|
184
|
+
* To render the item with a custom component, provide a tag name by the `component` property.
|
|
185
|
+
*
|
|
186
|
+
* @type {!Array<!SelectItem>}
|
|
187
|
+
*/
|
|
188
|
+
items: SelectItem[] | null | undefined;
|
|
189
|
+
|
|
135
190
|
/**
|
|
136
191
|
* Set when the select is open
|
|
137
192
|
*/
|
package/src/vaadin-select.js
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import '@polymer/iron-media-query/iron-media-query.js';
|
|
7
7
|
import '@vaadin/input-container/src/vaadin-input-container.js';
|
|
8
|
+
import './vaadin-select-item.js';
|
|
9
|
+
import './vaadin-select-list-box.js';
|
|
8
10
|
import './vaadin-select-overlay.js';
|
|
9
11
|
import './vaadin-select-value-button.js';
|
|
10
12
|
import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
|
|
@@ -22,17 +24,34 @@ registerStyles('vaadin-select', [fieldShared, inputFieldContainer], { moduleId:
|
|
|
22
24
|
/**
|
|
23
25
|
* `<vaadin-select>` is a Web Component for selecting values from a list of items.
|
|
24
26
|
*
|
|
27
|
+
* ### Items
|
|
28
|
+
*
|
|
29
|
+
* Use the `items` property to define possible options for the select:
|
|
30
|
+
*
|
|
31
|
+
* ```html
|
|
32
|
+
* <vaadin-select id="select"></vaadin-select>
|
|
33
|
+
* ```
|
|
34
|
+
* ```js
|
|
35
|
+
* const select = document.querySelector('#select');
|
|
36
|
+
* select.items = [
|
|
37
|
+
* { label: 'Most recent first', value: 'recent' },
|
|
38
|
+
* { component: 'hr' },
|
|
39
|
+
* { label: 'Rating: low to high', value: 'rating-asc' },
|
|
40
|
+
* { label: 'Rating: high to low', value: 'rating-desc' },
|
|
41
|
+
* { component: 'hr' },
|
|
42
|
+
* { label: 'Price: low to high', value: 'price-asc', disabled: true },
|
|
43
|
+
* { label: 'Price: high to low', value: 'price-desc', disabled: true }
|
|
44
|
+
* ];
|
|
45
|
+
* ```
|
|
46
|
+
*
|
|
25
47
|
* ### Rendering
|
|
26
48
|
*
|
|
27
|
-
*
|
|
49
|
+
* Alternatively, the content of the select can be populated by using the renderer callback function.
|
|
28
50
|
*
|
|
29
51
|
* The renderer function provides `root`, `select` arguments.
|
|
30
52
|
* Generate DOM content, append it to the `root` element and control the state
|
|
31
53
|
* of the host element by accessing `select`.
|
|
32
54
|
*
|
|
33
|
-
* ```html
|
|
34
|
-
* <vaadin-select id="select"></vaadin-select>
|
|
35
|
-
* ```
|
|
36
55
|
* ```js
|
|
37
56
|
* const select = document.querySelector('#select');
|
|
38
57
|
* select.renderer = function(root, select) {
|
|
@@ -169,6 +188,32 @@ class Select extends DelegateFocusMixin(FieldMixin(SlotMixin(ElementMixin(Themab
|
|
|
169
188
|
|
|
170
189
|
static get properties() {
|
|
171
190
|
return {
|
|
191
|
+
/**
|
|
192
|
+
* An array containing items that will be rendered as the options of the select.
|
|
193
|
+
*
|
|
194
|
+
* #### Example
|
|
195
|
+
* ```js
|
|
196
|
+
* select.items = [
|
|
197
|
+
* { label: 'Most recent first', value: 'recent' },
|
|
198
|
+
* { component: 'hr' },
|
|
199
|
+
* { label: 'Rating: low to high', value: 'rating-asc' },
|
|
200
|
+
* { label: 'Rating: high to low', value: 'rating-desc' },
|
|
201
|
+
* { component: 'hr' },
|
|
202
|
+
* { label: 'Price: low to high', value: 'price-asc', disabled: true },
|
|
203
|
+
* { label: 'Price: high to low', value: 'price-desc', disabled: true }
|
|
204
|
+
* ];
|
|
205
|
+
* ```
|
|
206
|
+
*
|
|
207
|
+
* Note: each item is rendered by default as the internal `<vaadin-select-item>` that is an extension of `<vaadin-item>`.
|
|
208
|
+
* To render the item with a custom component, provide a tag name by the `component` property.
|
|
209
|
+
*
|
|
210
|
+
* @type {!Array<!SelectItem>}
|
|
211
|
+
*/
|
|
212
|
+
items: {
|
|
213
|
+
type: Array,
|
|
214
|
+
observer: '__itemsChanged'
|
|
215
|
+
},
|
|
216
|
+
|
|
172
217
|
/**
|
|
173
218
|
* Set when the select is open
|
|
174
219
|
* @type {boolean}
|
|
@@ -357,13 +402,17 @@ class Select extends DelegateFocusMixin(FieldMixin(SlotMixin(ElementMixin(Themab
|
|
|
357
402
|
}
|
|
358
403
|
}
|
|
359
404
|
|
|
360
|
-
/**
|
|
405
|
+
/**
|
|
406
|
+
* @param {SelectRenderer | undefined | null} renderer
|
|
407
|
+
* @param {SelectOverlay | undefined} overlay
|
|
408
|
+
* @private
|
|
409
|
+
*/
|
|
361
410
|
_rendererChanged(renderer, overlay) {
|
|
362
411
|
if (!overlay) {
|
|
363
412
|
return;
|
|
364
413
|
}
|
|
365
414
|
|
|
366
|
-
overlay.setProperties({ owner: this, renderer });
|
|
415
|
+
overlay.setProperties({ owner: this, renderer: renderer || this.__defaultRenderer });
|
|
367
416
|
|
|
368
417
|
this.requestContentUpdate();
|
|
369
418
|
|
|
@@ -372,6 +421,17 @@ class Select extends DelegateFocusMixin(FieldMixin(SlotMixin(ElementMixin(Themab
|
|
|
372
421
|
}
|
|
373
422
|
}
|
|
374
423
|
|
|
424
|
+
/**
|
|
425
|
+
* @param {SelectItem[] | undefined | null} newItems
|
|
426
|
+
* @param {SelectItem[] | undefined | null} oldItems
|
|
427
|
+
* @private
|
|
428
|
+
*/
|
|
429
|
+
__itemsChanged(newItems, oldItems) {
|
|
430
|
+
if (newItems || oldItems) {
|
|
431
|
+
this.requestContentUpdate();
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
375
435
|
/** @private */
|
|
376
436
|
_assignMenuElement() {
|
|
377
437
|
const menuElement = this.__getMenuElement();
|
|
@@ -489,13 +549,9 @@ class Select extends DelegateFocusMixin(FieldMixin(SlotMixin(ElementMixin(Themab
|
|
|
489
549
|
|
|
490
550
|
this._menuElement.focus();
|
|
491
551
|
} else if (wasOpened) {
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
this.focus();
|
|
496
|
-
if (this._openedWithFocusRing) {
|
|
497
|
-
this.setAttribute('focus-ring', '');
|
|
498
|
-
}
|
|
552
|
+
this.focus();
|
|
553
|
+
if (this._openedWithFocusRing) {
|
|
554
|
+
this.setAttribute('focus-ring', '');
|
|
499
555
|
}
|
|
500
556
|
this.validate();
|
|
501
557
|
}
|
|
@@ -532,7 +588,7 @@ class Select extends DelegateFocusMixin(FieldMixin(SlotMixin(ElementMixin(Themab
|
|
|
532
588
|
|
|
533
589
|
const label = selected.getAttribute('label');
|
|
534
590
|
if (label) {
|
|
535
|
-
labelItem = this.
|
|
591
|
+
labelItem = this.__createItemElement({ label });
|
|
536
592
|
} else {
|
|
537
593
|
labelItem = selected.cloneNode(true);
|
|
538
594
|
}
|
|
@@ -540,26 +596,40 @@ class Select extends DelegateFocusMixin(FieldMixin(SlotMixin(ElementMixin(Themab
|
|
|
540
596
|
// store reference to the original item
|
|
541
597
|
labelItem._sourceItem = selected;
|
|
542
598
|
|
|
543
|
-
this.
|
|
599
|
+
this.__appendValueItemElement(labelItem);
|
|
544
600
|
|
|
545
601
|
// ensure the item gets proper styles
|
|
546
602
|
labelItem.selected = true;
|
|
547
603
|
}
|
|
548
604
|
|
|
549
|
-
/**
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
605
|
+
/**
|
|
606
|
+
* @param {!SelectItem} item
|
|
607
|
+
* @private
|
|
608
|
+
*/
|
|
609
|
+
__createItemElement(item) {
|
|
610
|
+
const itemElement = document.createElement(item.component || 'vaadin-select-item');
|
|
611
|
+
if (item.label) {
|
|
612
|
+
itemElement.textContent = item.label;
|
|
613
|
+
}
|
|
614
|
+
if (item.value) {
|
|
615
|
+
itemElement.value = item.value;
|
|
616
|
+
}
|
|
617
|
+
if (item.disabled) {
|
|
618
|
+
itemElement.disabled = item.disabled;
|
|
619
|
+
}
|
|
620
|
+
return itemElement;
|
|
554
621
|
}
|
|
555
622
|
|
|
556
|
-
/**
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
623
|
+
/**
|
|
624
|
+
* @param {!HTMLElement} itemElement
|
|
625
|
+
* @private
|
|
626
|
+
*/
|
|
627
|
+
__appendValueItemElement(itemElement) {
|
|
628
|
+
itemElement.removeAttribute('tabindex');
|
|
629
|
+
itemElement.removeAttribute('role');
|
|
630
|
+
itemElement.setAttribute('id', this._fieldId);
|
|
561
631
|
|
|
562
|
-
this._valueButton.appendChild(
|
|
632
|
+
this._valueButton.appendChild(itemElement);
|
|
563
633
|
}
|
|
564
634
|
|
|
565
635
|
/** @private */
|
|
@@ -576,8 +646,8 @@ class Select extends DelegateFocusMixin(FieldMixin(SlotMixin(ElementMixin(Themab
|
|
|
576
646
|
|
|
577
647
|
if (!selected) {
|
|
578
648
|
if (this.placeholder) {
|
|
579
|
-
const item = this.
|
|
580
|
-
this.
|
|
649
|
+
const item = this.__createItemElement({ label: this.placeholder });
|
|
650
|
+
this.__appendValueItemElement(item);
|
|
581
651
|
this._valueButton.setAttribute('placeholder', '');
|
|
582
652
|
}
|
|
583
653
|
} else {
|
|
@@ -644,6 +714,30 @@ class Select extends DelegateFocusMixin(FieldMixin(SlotMixin(ElementMixin(Themab
|
|
|
644
714
|
return !(this.invalid = !(this.disabled || !this.required || this.value));
|
|
645
715
|
}
|
|
646
716
|
|
|
717
|
+
/**
|
|
718
|
+
* Renders items when they are provided by the `items` property and clears the content otherwise.
|
|
719
|
+
* @param {!HTMLElement} root
|
|
720
|
+
* @param {!Select} _select
|
|
721
|
+
* @private
|
|
722
|
+
*/
|
|
723
|
+
__defaultRenderer(root, _select) {
|
|
724
|
+
if (!this.items || this.items.length === 0) {
|
|
725
|
+
root.textContent = '';
|
|
726
|
+
return;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
let listBox = root.firstElementChild;
|
|
730
|
+
if (!listBox) {
|
|
731
|
+
listBox = document.createElement('vaadin-select-list-box');
|
|
732
|
+
root.appendChild(listBox);
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
listBox.textContent = '';
|
|
736
|
+
this.items.forEach((item) => {
|
|
737
|
+
listBox.appendChild(this.__createItemElement(item));
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
|
|
647
741
|
/**
|
|
648
742
|
* Fired when the user commits a value change.
|
|
649
743
|
*
|
|
@@ -54,12 +54,12 @@ registerStyles(
|
|
|
54
54
|
display: none;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
::slotted(
|
|
57
|
+
::slotted(:not([slot])) {
|
|
58
58
|
font: inherit;
|
|
59
59
|
padding: 4px 0;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
::slotted(
|
|
62
|
+
::slotted(:not([slot]):hover) {
|
|
63
63
|
background-color: transparent;
|
|
64
64
|
}
|
|
65
65
|
`,
|