@rcarls/rc-transfer-list 0.2.0 → 0.3.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/README.md +115 -1
- package/dist/custom-elements.json +76 -10
- package/dist/{rc-transfer-list-DDgVWhv6.js → rc-transfer-list-DFPxuGJ2.js} +222 -104
- package/dist/rc-transfer-list-DFPxuGJ2.js.map +1 -0
- package/dist/rc-transfer-list-define.js +1 -1
- package/dist/rc-transfer-list.js +1 -1
- package/dist/types/packages/rc-transfer-list/src/rc-transfer-list.d.ts +21 -11
- package/dist/types/packages/rc-transfer-list/src/rc-transfer-list.styles.d.ts +2 -0
- package/package.json +9 -11
- package/dist/demo.css +0 -85
- package/dist/demo.js +0 -40
- package/dist/rc-transfer-list-DDgVWhv6.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,6 +1,99 @@
|
|
|
1
1
|
# @rcarls/rc-transfer-list
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Transfer list that enhances a native `<select multiple>` into available and selected panes.
|
|
4
|
+
|
|
5
|
+
Docs: [https://richardcarls.github.io/rc-webcomponents/components/rc-transfer-list](https://richardcarls.github.io/rc-webcomponents/components/rc-transfer-list).
|
|
6
|
+
|
|
7
|
+
The component renders two listboxes and transfer/reorder actions in between.
|
|
8
|
+
Available options are on the left, and selected options appear on the right. It
|
|
9
|
+
is an older enterprise/admin UI pattern, but solves the specific problem of
|
|
10
|
+
multiple selection within a large amount of options.
|
|
11
|
+
|
|
12
|
+
Modern use cases include user and permissions management tasks, multi-select for
|
|
13
|
+
columns / fields / filters and list re-ordering.
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install @rcarls/rc-transfer-list
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
yarn add @rcarls/rc-transfer-list
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Import
|
|
26
|
+
|
|
27
|
+
```js
|
|
28
|
+
import '@rcarls/rc-transfer-list/define';
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
|
|
33
|
+
```html
|
|
34
|
+
<rc-transfer-list available-label="Available planets" selected-label="Mission route">
|
|
35
|
+
<select name="planets" multiple>
|
|
36
|
+
<option value="mercury">Mercury</option>
|
|
37
|
+
<option value="venus" selected>Venus</option>
|
|
38
|
+
<option value="earth">Earth</option>
|
|
39
|
+
<option value="mars">Mars</option>
|
|
40
|
+
</select>
|
|
41
|
+
</rc-transfer-list>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The selected/right-hand list is reflected back to the native select, so form
|
|
45
|
+
submission serializes selected option values in the order shown in the selected
|
|
46
|
+
panel.
|
|
47
|
+
|
|
48
|
+
Use the `compact` attribute when the surrounding layout should present the
|
|
49
|
+
available list, actions, and selected list in one column. The component does not
|
|
50
|
+
switch layout automatically at viewport breakpoints.
|
|
51
|
+
|
|
52
|
+
## API
|
|
53
|
+
|
|
54
|
+
### Properties
|
|
55
|
+
|
|
56
|
+
| Property | Attribute | Type | Default | Description |
|
|
57
|
+
|---|---|---|---|---|
|
|
58
|
+
| `multiple` | `multiple` | `boolean` | `false` | Allows multiple highlighted rows in each listbox. |
|
|
59
|
+
| `compact` | `compact` | `boolean` | `false` | Stacks the panels and action toolbar into a compact one-column layout. |
|
|
60
|
+
| `availableLabel` | `available-label` | `string` | `'Available'` | Visible label for the available list. |
|
|
61
|
+
| `selectedLabel` | `selected-label` | `string` | `'Selected'` | Visible label for the selected list. |
|
|
62
|
+
| `available` | - | `ListboxOption[]` | native select state | Gets or replaces unselected options. |
|
|
63
|
+
| `selected` | - | `ListboxOption[]` | native select state | Gets or replaces selected options. |
|
|
64
|
+
| `defaultSelected` | - | `ListboxOption[] \| undefined` | `undefined` | Initial uncontrolled selected options, applied before host `selected` writes. |
|
|
65
|
+
|
|
66
|
+
### Methods
|
|
67
|
+
|
|
68
|
+
| Method | Description |
|
|
69
|
+
|---|---|
|
|
70
|
+
| `addSelected()` | Moves highlighted available options to the selected list. |
|
|
71
|
+
| `addAll()` | Moves every available option to the selected list. |
|
|
72
|
+
| `removeSelected()` | Moves highlighted selected options back to the available list. |
|
|
73
|
+
| `clearSelected()` | Moves every selected option back to the available list. |
|
|
74
|
+
| `moveSelected(delta)` | Reorders highlighted selected options by `-1` or `1` rows. |
|
|
75
|
+
|
|
76
|
+
### Events
|
|
77
|
+
|
|
78
|
+
| Event | Detail | Description |
|
|
79
|
+
|---|---|---|
|
|
80
|
+
| `rc-transfer-list-change` | `{ selected: ListboxOption[] }` | Fires after a user action changes the selected/right-hand list. |
|
|
81
|
+
|
|
82
|
+
Host property writes to `available`, `selected`, or `defaultSelected` are silent.
|
|
83
|
+
|
|
84
|
+
## Keyboard
|
|
85
|
+
|
|
86
|
+
The embedded `rc-listbox` controls provide list navigation and selection. The
|
|
87
|
+
transfer list also supports these shortcuts when focus is inside the component:
|
|
88
|
+
|
|
89
|
+
| Shortcut | Action |
|
|
90
|
+
|---|---|
|
|
91
|
+
| `Alt+ArrowRight` | Add highlighted available options. |
|
|
92
|
+
| `Alt+ArrowLeft` | Remove highlighted selected options. |
|
|
93
|
+
| `Alt+ArrowUp` | Move highlighted selected options up. |
|
|
94
|
+
| `Alt+ArrowDown` | Move highlighted selected options down. |
|
|
95
|
+
| `Enter` | Add the highlighted available option in single-select mode. |
|
|
96
|
+
| `Delete` | Remove highlighted selected options. |
|
|
4
97
|
|
|
5
98
|
## Styling Hooks
|
|
6
99
|
|
|
@@ -8,3 +101,24 @@ Panels expose `data-empty` when their backing list has no options and
|
|
|
8
101
|
`data-has-selection` when that panel currently has highlighted rows. The root
|
|
9
102
|
exposes `data-can-move-up` and `data-can-move-down` when the selected panel has
|
|
10
103
|
highlighted rows that can be reordered in that direction.
|
|
104
|
+
|
|
105
|
+
| CSS custom property | Default | Description |
|
|
106
|
+
|---|---|---|
|
|
107
|
+
| `--rc-transfer-list-gap` | `var(--rc-control-gap, 0.75rem)` | Gap between panels and the action toolbar. |
|
|
108
|
+
| `--rc-transfer-list-panel-gap` | `var(--rc-control-gap, 0.35rem)` | Gap between a panel label and its listbox. |
|
|
109
|
+
| `--rc-transfer-list-listbox-min-block-size` | `10rem` | Minimum block size for each listbox. |
|
|
110
|
+
| `--rc-transfer-list-listbox-border` | `var(--rc-border, 1px solid ButtonBorder)` | Border around each listbox. |
|
|
111
|
+
| `--rc-transfer-list-option-gap` | `var(--rc-item-gap, 0.4em)` | Gap between option adornments and labels. |
|
|
112
|
+
| `--rc-transfer-list-option-padding-block` | `var(--rc-item-padding-block, 0.3em)` | Block padding for option rows. |
|
|
113
|
+
| `--rc-transfer-list-option-padding-inline` | `var(--rc-item-padding-inline, 0.75em)` | Inline padding for option rows. |
|
|
114
|
+
| `--rc-transfer-list-option-selected-bg` | `var(--rc-highlight, Highlight)` | Selected option background. |
|
|
115
|
+
| `--rc-transfer-list-option-selected-color` | `var(--rc-highlight-text, HighlightText)` | Selected option foreground. |
|
|
116
|
+
|
|
117
|
+
| Part | Description |
|
|
118
|
+
|---|---|
|
|
119
|
+
| `root` | Root layout wrapper. |
|
|
120
|
+
| `panel` | Shared list panel surface. |
|
|
121
|
+
| `available-panel` | Available/left panel. |
|
|
122
|
+
| `selected-panel` | Selected/right panel. |
|
|
123
|
+
| `actions` | Transfer action toolbar. |
|
|
124
|
+
| `button` | Shared action button surface. |
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"declarations": [
|
|
47
47
|
{
|
|
48
48
|
"kind": "class",
|
|
49
|
-
"description": "
|
|
49
|
+
"description": "Transfer list that enhances a native <select multiple> into available and selected\npanes.\n\nThe component renders two listboxes and transfer/reorder actions in between.\nAvailable options are on the left, and selected options appear on the right. It\nis an older enterprise/admin UI pattern, but solves the specific problem of\nmultiple selection within a large amount of options.\n\nThe `available` and `selected` JS array properties write through to the\nbacking `<select>`, so the component can also be driven imperatively from a\nframework without giving up form participation.",
|
|
50
50
|
"name": "RCTransferList",
|
|
51
51
|
"cssProperties": [
|
|
52
52
|
{
|
|
@@ -68,6 +68,31 @@
|
|
|
68
68
|
"description": "Border around each listbox",
|
|
69
69
|
"name": "--rc-transfer-list-listbox-border",
|
|
70
70
|
"default": "var(--rc-border)"
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"description": "Gap between option adornments and labels",
|
|
74
|
+
"name": "--rc-transfer-list-option-gap",
|
|
75
|
+
"default": "var(--rc-item-gap)"
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"description": "Block padding for option rows",
|
|
79
|
+
"name": "--rc-transfer-list-option-padding-block",
|
|
80
|
+
"default": "var(--rc-item-padding-block)"
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"description": "Inline padding for option rows",
|
|
84
|
+
"name": "--rc-transfer-list-option-padding-inline",
|
|
85
|
+
"default": "var(--rc-item-padding-inline)"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"description": "Selected option background",
|
|
89
|
+
"name": "--rc-transfer-list-option-selected-bg",
|
|
90
|
+
"default": "var(--rc-highlight)"
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"description": "Selected option foreground",
|
|
94
|
+
"name": "--rc-transfer-list-option-selected-color",
|
|
95
|
+
"default": "var(--rc-highlight-text)"
|
|
71
96
|
}
|
|
72
97
|
],
|
|
73
98
|
"cssParts": [
|
|
@@ -108,6 +133,17 @@
|
|
|
108
133
|
"attribute": "multiple",
|
|
109
134
|
"reflects": true
|
|
110
135
|
},
|
|
136
|
+
{
|
|
137
|
+
"kind": "field",
|
|
138
|
+
"name": "compact",
|
|
139
|
+
"type": {
|
|
140
|
+
"text": "boolean"
|
|
141
|
+
},
|
|
142
|
+
"default": "false",
|
|
143
|
+
"description": "Stack the panels and action toolbar into a compact one-column layout.",
|
|
144
|
+
"attribute": "compact",
|
|
145
|
+
"reflects": true
|
|
146
|
+
},
|
|
111
147
|
{
|
|
112
148
|
"kind": "field",
|
|
113
149
|
"name": "availableLabel",
|
|
@@ -166,7 +202,7 @@
|
|
|
166
202
|
},
|
|
167
203
|
{
|
|
168
204
|
"kind": "field",
|
|
169
|
-
"name": "
|
|
205
|
+
"name": "_$select",
|
|
170
206
|
"type": {
|
|
171
207
|
"text": "HTMLSelectElement | null"
|
|
172
208
|
},
|
|
@@ -200,17 +236,12 @@
|
|
|
200
236
|
"privacy": "private",
|
|
201
237
|
"default": "false"
|
|
202
238
|
},
|
|
203
|
-
{
|
|
204
|
-
"kind": "field",
|
|
205
|
-
"name": "_hostObserver",
|
|
206
|
-
"privacy": "private",
|
|
207
|
-
"default": "new MutationObserver(() => this._setupSelect())"
|
|
208
|
-
},
|
|
209
239
|
{
|
|
210
240
|
"kind": "field",
|
|
211
241
|
"name": "_selectObserver",
|
|
212
242
|
"privacy": "private",
|
|
213
|
-
"
|
|
243
|
+
"readonly": true,
|
|
244
|
+
"default": "new MutationObserverController(this, { target: null, disabled: true, callback: () => { if (!this._syncing) { this.requestUpdate(); } }, })"
|
|
214
245
|
},
|
|
215
246
|
{
|
|
216
247
|
"kind": "field",
|
|
@@ -362,6 +393,24 @@
|
|
|
362
393
|
"name": "_onListboxChange",
|
|
363
394
|
"privacy": "private"
|
|
364
395
|
},
|
|
396
|
+
{
|
|
397
|
+
"kind": "method",
|
|
398
|
+
"name": "_getListboxEventTargetId",
|
|
399
|
+
"privacy": "private",
|
|
400
|
+
"return": {
|
|
401
|
+
"type": {
|
|
402
|
+
"text": "string | undefined"
|
|
403
|
+
}
|
|
404
|
+
},
|
|
405
|
+
"parameters": [
|
|
406
|
+
{
|
|
407
|
+
"name": "e",
|
|
408
|
+
"type": {
|
|
409
|
+
"text": "Event"
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
]
|
|
413
|
+
},
|
|
365
414
|
{
|
|
366
415
|
"kind": "method",
|
|
367
416
|
"name": "_setupSelect",
|
|
@@ -370,7 +419,15 @@
|
|
|
370
419
|
"type": {
|
|
371
420
|
"text": "void"
|
|
372
421
|
}
|
|
373
|
-
}
|
|
422
|
+
},
|
|
423
|
+
"parameters": [
|
|
424
|
+
{
|
|
425
|
+
"name": "$select",
|
|
426
|
+
"type": {
|
|
427
|
+
"text": "HTMLSelectElement | null"
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
]
|
|
374
431
|
},
|
|
375
432
|
{
|
|
376
433
|
"kind": "method",
|
|
@@ -465,6 +522,15 @@
|
|
|
465
522
|
"description": "Enable multi-selection in both lists.",
|
|
466
523
|
"fieldName": "multiple"
|
|
467
524
|
},
|
|
525
|
+
{
|
|
526
|
+
"name": "compact",
|
|
527
|
+
"type": {
|
|
528
|
+
"text": "boolean"
|
|
529
|
+
},
|
|
530
|
+
"default": "false",
|
|
531
|
+
"description": "Stack the panels and action toolbar into a compact one-column layout.",
|
|
532
|
+
"fieldName": "compact"
|
|
533
|
+
},
|
|
468
534
|
{
|
|
469
535
|
"name": "available-label",
|
|
470
536
|
"type": {
|
|
@@ -1,16 +1,129 @@
|
|
|
1
|
+
import { css as _, LitElement as m, nothing as c, html as y } from "lit";
|
|
2
|
+
import { property as p, query as f, state as v } from "lit/decorators.js";
|
|
3
|
+
import { MutationObserverController as $, NativeChildController as x } from "@rcarls/rc-common";
|
|
1
4
|
import "@rcarls/rc-listbox/define";
|
|
2
5
|
import "@rcarls/rc-toolbar/define";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
+
const S = _`
|
|
7
|
+
:host {
|
|
8
|
+
display: block;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
:host([hidden]) {
|
|
12
|
+
display: none;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
#root {
|
|
16
|
+
display: grid;
|
|
17
|
+
grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
|
|
18
|
+
align-items: stretch;
|
|
19
|
+
gap: var(--rc-transfer-list-gap, var(--rc-control-gap, 0.75rem));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
:host([compact]) #root {
|
|
23
|
+
grid-template-columns: minmax(0, 1fr);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.rc-transfer-list-panel {
|
|
27
|
+
display: flex;
|
|
28
|
+
min-inline-size: 0;
|
|
29
|
+
flex-direction: column;
|
|
30
|
+
gap: var(--rc-transfer-list-panel-gap, var(--rc-control-gap, 0.35rem));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.rc-transfer-list-panel > rc-listbox {
|
|
34
|
+
flex: 1 1 auto;
|
|
35
|
+
min-block-size: var(--rc-transfer-list-listbox-min-block-size, 10rem);
|
|
36
|
+
overflow: auto;
|
|
37
|
+
border: var(--rc-transfer-list-listbox-border, var(--rc-border, 1px solid ButtonBorder));
|
|
38
|
+
background: var(--rc-transfer-list-listbox-bg, var(--rc-surface, Canvas));
|
|
39
|
+
color: var(--rc-transfer-list-listbox-color, var(--rc-field-text, FieldText));
|
|
40
|
+
--rc-listbox-option-gap: var(--rc-transfer-list-option-gap, var(--rc-item-gap, 0.4em));
|
|
41
|
+
--rc-listbox-option-padding-block: var(
|
|
42
|
+
--rc-transfer-list-option-padding-block,
|
|
43
|
+
var(--rc-item-padding-block, 0.3em)
|
|
44
|
+
);
|
|
45
|
+
--rc-listbox-option-padding-inline: var(
|
|
46
|
+
--rc-transfer-list-option-padding-inline,
|
|
47
|
+
var(--rc-item-padding-inline, 0.75em)
|
|
48
|
+
);
|
|
49
|
+
--rc-listbox-hover-bg: var(
|
|
50
|
+
--rc-transfer-list-option-hover-bg,
|
|
51
|
+
var(--rc-transfer-list-option-selected-bg, var(--rc-highlight, Highlight))
|
|
52
|
+
);
|
|
53
|
+
--rc-listbox-hover-color: var(
|
|
54
|
+
--rc-transfer-list-option-hover-color,
|
|
55
|
+
var(--rc-transfer-list-option-selected-color, var(--rc-highlight-text, HighlightText))
|
|
56
|
+
);
|
|
57
|
+
--rc-listbox-active-bg: var(
|
|
58
|
+
--rc-transfer-list-option-hover-bg,
|
|
59
|
+
var(--rc-transfer-list-option-selected-bg, var(--rc-highlight, Highlight))
|
|
60
|
+
);
|
|
61
|
+
--rc-listbox-active-color: var(
|
|
62
|
+
--rc-transfer-list-option-hover-color,
|
|
63
|
+
var(--rc-transfer-list-option-selected-color, var(--rc-highlight-text, HighlightText))
|
|
64
|
+
);
|
|
65
|
+
--rc-listbox-selected-bg: var(
|
|
66
|
+
--rc-transfer-list-option-selected-bg,
|
|
67
|
+
var(--rc-highlight, Highlight)
|
|
68
|
+
);
|
|
69
|
+
--rc-listbox-selected-color: var(
|
|
70
|
+
--rc-transfer-list-option-selected-color,
|
|
71
|
+
var(--rc-highlight-text, HighlightText)
|
|
72
|
+
);
|
|
73
|
+
--rc-listbox-disabled-opacity: var(--rc-disabled-opacity, 0.5);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
rc-listbox [part~='option'][hidden] {
|
|
77
|
+
display: none;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
rc-listbox [part~='option'][data-active]:not([aria-disabled='true']) {
|
|
81
|
+
outline: var(--rc-focus-ring, 2px solid var(--rc-accent, Highlight));
|
|
82
|
+
outline-offset: -2px;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
rc-listbox [part~='option'][aria-disabled='true'] {
|
|
86
|
+
cursor: not-allowed;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
#actions {
|
|
90
|
+
align-self: center;
|
|
91
|
+
transform: translateY(
|
|
92
|
+
calc((1lh + var(--rc-transfer-list-panel-gap, var(--rc-control-gap, 0.35rem))) / 2)
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
:host([compact]) #actions {
|
|
97
|
+
align-self: stretch;
|
|
98
|
+
transform: none;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
:host([compact]) #actions::part(root) {
|
|
102
|
+
flex-wrap: wrap;
|
|
103
|
+
justify-content: center;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
#actions button {
|
|
107
|
+
white-space: nowrap;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
slot:not([name]) {
|
|
111
|
+
display: none;
|
|
112
|
+
}
|
|
113
|
+
`;
|
|
114
|
+
var w = Object.defineProperty, n = (u, e, t, s) => {
|
|
6
115
|
for (var l = void 0, i = u.length - 1, r; i >= 0; i--)
|
|
7
116
|
(r = u[i]) && (l = r(e, t, l) || l);
|
|
8
|
-
return l &&
|
|
117
|
+
return l && w(e, t, l), l;
|
|
9
118
|
};
|
|
10
|
-
class
|
|
119
|
+
const b = class b extends m {
|
|
11
120
|
constructor() {
|
|
12
|
-
super(
|
|
13
|
-
|
|
121
|
+
super(), this.multiple = !1, this.compact = !1, this.availableLabel = "Available", this.selectedLabel = "Selected", this._availableSelection = [], this._selectedSelection = [], this._$select = null, this._syncing = !1, this._selectedInitialized = !1, this._selectObserver = new $(this, {
|
|
122
|
+
target: null,
|
|
123
|
+
disabled: !0,
|
|
124
|
+
callback: () => {
|
|
125
|
+
this._syncing || this.requestUpdate();
|
|
126
|
+
}
|
|
14
127
|
}), this._onMoveUp = () => {
|
|
15
128
|
this.moveSelected(-1);
|
|
16
129
|
}, this._onMoveDown = () => {
|
|
@@ -33,19 +146,27 @@ class o extends _ {
|
|
|
33
146
|
}
|
|
34
147
|
return;
|
|
35
148
|
}
|
|
36
|
-
const t = e
|
|
149
|
+
const t = this._getListboxEventTargetId(e);
|
|
37
150
|
if (t === "available-list" && !this.multiple && e.key === "Enter") {
|
|
38
151
|
e.preventDefault(), this.addSelected();
|
|
39
152
|
return;
|
|
40
153
|
}
|
|
41
154
|
t === "selected-list" && e.key === "Delete" && (e.preventDefault(), this.removeSelected());
|
|
42
155
|
}, this._onListboxChange = (e) => {
|
|
43
|
-
const
|
|
156
|
+
const t = e;
|
|
157
|
+
if (t.detail.reason === "action") {
|
|
158
|
+
e.stopPropagation();
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
const s = t.detail.value, l = Array.isArray(s) ? s : s ? [s] : [], i = e.currentTarget?.id;
|
|
44
162
|
i === "available-list" ? this._availableSelection = l : i === "selected-list" && (this._selectedSelection = l);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
163
|
+
}, new x(this, {
|
|
164
|
+
selector: ":scope > select[multiple]",
|
|
165
|
+
observe: !0,
|
|
166
|
+
onChange: (e) => this._setupSelect(e),
|
|
167
|
+
onMissing: () => {
|
|
168
|
+
}
|
|
169
|
+
});
|
|
49
170
|
}
|
|
50
171
|
/**
|
|
51
172
|
* Available/left-hand options derived from unselected `<option>` elements.
|
|
@@ -55,18 +176,19 @@ class o extends _ {
|
|
|
55
176
|
* skipped to prevent duplicate option values.
|
|
56
177
|
*/
|
|
57
178
|
get available() {
|
|
58
|
-
return this.
|
|
179
|
+
return this._$select ? Array.from(this._$select.options).filter((e) => !e.selected).map((e) => ({ value: e.value, label: e.label || e.text })) : [];
|
|
59
180
|
}
|
|
60
181
|
set available(e) {
|
|
61
|
-
if (!this.
|
|
182
|
+
if (!this._$select)
|
|
183
|
+
return;
|
|
62
184
|
this._syncing = !0;
|
|
63
185
|
const t = new Set(
|
|
64
|
-
Array.from(this.
|
|
186
|
+
Array.from(this._$select.options).filter((s) => s.selected).map((s) => s.value)
|
|
65
187
|
);
|
|
66
|
-
for (const s of Array.from(this.
|
|
188
|
+
for (const s of Array.from(this._$select.options))
|
|
67
189
|
s.selected || s.remove();
|
|
68
190
|
for (const s of e)
|
|
69
|
-
t.has(s.value) || this.
|
|
191
|
+
t.has(s.value) || this._$select.add(new Option(s.label, s.value));
|
|
70
192
|
this._syncing = !1, this.requestUpdate();
|
|
71
193
|
}
|
|
72
194
|
/**
|
|
@@ -76,15 +198,15 @@ class o extends _ {
|
|
|
76
198
|
* `<select>`. Unselected options are left unchanged.
|
|
77
199
|
*/
|
|
78
200
|
get selected() {
|
|
79
|
-
return this.
|
|
201
|
+
return this._$select ? Array.from(this._$select.options).filter((e) => e.selected).map((e) => ({ value: e.value, label: e.label || e.text })) : [];
|
|
80
202
|
}
|
|
81
203
|
set selected(e) {
|
|
82
|
-
if (this._selectedInitialized = !0, !!this.
|
|
204
|
+
if (this._selectedInitialized = !0, !!this._$select) {
|
|
83
205
|
this._syncing = !0;
|
|
84
|
-
for (const t of Array.from(this.
|
|
206
|
+
for (const t of Array.from(this._$select.options))
|
|
85
207
|
t.selected && t.remove();
|
|
86
208
|
for (const t of e)
|
|
87
|
-
this.
|
|
209
|
+
this._$select.add(new Option(t.label, t.value, !1, !0));
|
|
88
210
|
this._syncing = !1, this.requestUpdate();
|
|
89
211
|
}
|
|
90
212
|
}
|
|
@@ -93,74 +215,29 @@ class o extends _ {
|
|
|
93
215
|
return this._defaultSelected;
|
|
94
216
|
}
|
|
95
217
|
set defaultSelected(e) {
|
|
96
|
-
this._defaultSelected = e, !this._selectedInitialized && this.
|
|
218
|
+
this._defaultSelected = e, !this._selectedInitialized && this._$select && e !== void 0 && this._applyDefaultSelected(e);
|
|
97
219
|
}
|
|
98
220
|
_applyDefaultSelected(e) {
|
|
99
|
-
if (this.
|
|
221
|
+
if (this._$select) {
|
|
100
222
|
this._syncing = !0;
|
|
101
|
-
for (const t of Array.from(this.
|
|
223
|
+
for (const t of Array.from(this._$select.options))
|
|
102
224
|
t.selected = e.some((s) => s.value === t.value);
|
|
103
225
|
this._syncing = !1, this.requestUpdate();
|
|
104
226
|
}
|
|
105
227
|
}
|
|
106
|
-
connectedCallback() {
|
|
107
|
-
super.connectedCallback(), this._hostObserver.observe(this, { childList: !0 }), this.addEventListener("keydown", this._onKeydown), this.addEventListener("rc-listbox-change", this._onListboxChange), this._setupSelect();
|
|
108
|
-
}
|
|
109
228
|
disconnectedCallback() {
|
|
110
|
-
super.disconnectedCallback(), this.
|
|
229
|
+
super.disconnectedCallback(), this._teardownSelect();
|
|
111
230
|
}
|
|
112
231
|
render() {
|
|
113
|
-
const e = this.available, t = this.selected, s = new Set(this._selectedSelection), l = e.length === 0, i = t.length === 0, r = t.length < 2, h = this._availableSelection.length === 0, a = this._selectedSelection.length === 0, d = this._canMoveSelected(t, s, -1),
|
|
114
|
-
return
|
|
115
|
-
<style>
|
|
116
|
-
rc-transfer-list {
|
|
117
|
-
display: block;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
rc-transfer-list .rc-transfer-list-root {
|
|
121
|
-
display: grid;
|
|
122
|
-
grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
|
|
123
|
-
align-items: stretch;
|
|
124
|
-
gap: var(--rc-transfer-list-gap, var(--rc-control-gap, 0.75rem));
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
rc-transfer-list .rc-transfer-list-panel {
|
|
128
|
-
display: flex;
|
|
129
|
-
min-inline-size: 0;
|
|
130
|
-
flex-direction: column;
|
|
131
|
-
gap: var(--rc-transfer-list-panel-gap, var(--rc-control-gap, 0.35rem));
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
rc-transfer-list .rc-transfer-list-panel > rc-listbox {
|
|
135
|
-
flex: 1 1 auto;
|
|
136
|
-
min-block-size: var(--rc-transfer-list-listbox-min-block-size, 10rem);
|
|
137
|
-
overflow: auto;
|
|
138
|
-
border: var(--rc-transfer-list-listbox-border, var(--rc-border, 1px solid ButtonBorder));
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
rc-transfer-list .rc-transfer-list-actions {
|
|
142
|
-
align-self: center;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
rc-transfer-list .rc-transfer-list-actions button {
|
|
146
|
-
white-space: nowrap;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
@media (max-width: 42rem) {
|
|
150
|
-
rc-transfer-list .rc-transfer-list-root {
|
|
151
|
-
grid-template-columns: minmax(0, 1fr);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
rc-transfer-list .rc-transfer-list-actions {
|
|
155
|
-
align-self: stretch;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
</style>
|
|
232
|
+
const e = this.available, t = this.selected, s = new Set(this._selectedSelection), l = e.length === 0, i = t.length === 0, r = t.length < 2, h = this._availableSelection.length === 0, a = this._selectedSelection.length === 0, d = this._canMoveSelected(t, s, -1), g = this._canMoveSelected(t, s, 1);
|
|
233
|
+
return y`
|
|
159
234
|
<div
|
|
235
|
+
id="root"
|
|
160
236
|
part="root"
|
|
161
237
|
class="rc-transfer-list-root"
|
|
162
238
|
data-can-move-up=${d ? "" : c}
|
|
163
|
-
data-can-move-down=${
|
|
239
|
+
data-can-move-down=${g ? "" : c}
|
|
240
|
+
@keydown=${this._onKeydown}
|
|
164
241
|
>
|
|
165
242
|
<section
|
|
166
243
|
part="panel available-panel"
|
|
@@ -177,11 +254,13 @@ class o extends _ {
|
|
|
177
254
|
tabindex="0"
|
|
178
255
|
.options=${e}
|
|
179
256
|
.multiple=${this.multiple}
|
|
257
|
+
@rc-listbox-change=${this._onListboxChange}
|
|
180
258
|
></rc-listbox>
|
|
181
259
|
</section>
|
|
182
260
|
|
|
183
261
|
<rc-toolbar
|
|
184
|
-
|
|
262
|
+
id="actions"
|
|
263
|
+
orientation=${this.compact ? "horizontal" : "vertical"}
|
|
185
264
|
label="Transfer actions"
|
|
186
265
|
part="actions"
|
|
187
266
|
class="rc-transfer-list-actions"
|
|
@@ -191,37 +270,54 @@ class o extends _ {
|
|
|
191
270
|
part="button add-button"
|
|
192
271
|
?disabled=${l || h}
|
|
193
272
|
@click=${this.addSelected}
|
|
194
|
-
>
|
|
273
|
+
>
|
|
274
|
+
Add →
|
|
275
|
+
</button>
|
|
276
|
+
|
|
195
277
|
<button
|
|
196
278
|
type="button"
|
|
197
279
|
part="button add-all-button"
|
|
198
280
|
?disabled=${l}
|
|
199
281
|
@click=${this.addAll}
|
|
200
|
-
>
|
|
282
|
+
>
|
|
283
|
+
Add all →
|
|
284
|
+
</button>
|
|
285
|
+
|
|
201
286
|
<button
|
|
202
287
|
type="button"
|
|
203
288
|
part="button remove-button"
|
|
204
289
|
?disabled=${i || a}
|
|
205
290
|
@click=${this.removeSelected}
|
|
206
|
-
|
|
291
|
+
>
|
|
292
|
+
← Remove
|
|
293
|
+
</button>
|
|
294
|
+
|
|
207
295
|
<button
|
|
208
296
|
type="button"
|
|
209
297
|
part="button clear-button"
|
|
210
298
|
?disabled=${i}
|
|
211
299
|
@click=${this.clearSelected}
|
|
212
|
-
|
|
300
|
+
>
|
|
301
|
+
← Clear
|
|
302
|
+
</button>
|
|
303
|
+
|
|
213
304
|
<button
|
|
214
305
|
type="button"
|
|
215
306
|
part="button move-up-button"
|
|
216
307
|
?disabled=${r || a}
|
|
217
308
|
@click=${this._onMoveUp}
|
|
218
|
-
>
|
|
309
|
+
>
|
|
310
|
+
Move up
|
|
311
|
+
</button>
|
|
312
|
+
|
|
219
313
|
<button
|
|
220
314
|
type="button"
|
|
221
315
|
part="button move-down-button"
|
|
222
316
|
?disabled=${r || a}
|
|
223
317
|
@click=${this._onMoveDown}
|
|
224
|
-
>
|
|
318
|
+
>
|
|
319
|
+
Move down
|
|
320
|
+
</button>
|
|
225
321
|
</rc-toolbar>
|
|
226
322
|
|
|
227
323
|
<section
|
|
@@ -232,6 +328,7 @@ class o extends _ {
|
|
|
232
328
|
data-has-selection=${a ? c : ""}
|
|
233
329
|
>
|
|
234
330
|
<span part="label selected-label" id="selected-label">${this.selectedLabel}</span>
|
|
331
|
+
|
|
235
332
|
<rc-listbox
|
|
236
333
|
id="selected-list"
|
|
237
334
|
part="listbox selected-listbox"
|
|
@@ -239,75 +336,91 @@ class o extends _ {
|
|
|
239
336
|
tabindex="0"
|
|
240
337
|
.options=${t}
|
|
241
338
|
.multiple=${this.multiple}
|
|
339
|
+
@rc-listbox-change=${this._onListboxChange}
|
|
242
340
|
></rc-listbox>
|
|
243
341
|
</section>
|
|
244
342
|
</div>
|
|
343
|
+
<slot></slot>
|
|
245
344
|
`;
|
|
246
345
|
}
|
|
247
346
|
/** Adds the highlighted available options to the selected list. */
|
|
248
347
|
addSelected() {
|
|
249
|
-
if (!this.
|
|
348
|
+
if (!this._$select)
|
|
349
|
+
return;
|
|
250
350
|
const e = new Set(this._$availableList?.selectedValues ?? []);
|
|
251
351
|
if (e.size !== 0) {
|
|
252
352
|
this._syncing = !0;
|
|
253
|
-
for (const t of Array.from(this.
|
|
353
|
+
for (const t of Array.from(this._$select.options))
|
|
254
354
|
!t.selected && e.has(t.value) && (t.selected = !0);
|
|
255
355
|
this._syncing = !1, this._availableSelection = [], this.requestUpdate(), this._dispatchChange();
|
|
256
356
|
}
|
|
257
357
|
}
|
|
258
358
|
/** Adds every available option to the selected list. */
|
|
259
359
|
addAll() {
|
|
260
|
-
if (this.
|
|
360
|
+
if (this._$select) {
|
|
261
361
|
this._syncing = !0;
|
|
262
|
-
for (const e of Array.from(this.
|
|
362
|
+
for (const e of Array.from(this._$select.options))
|
|
363
|
+
e.selected = !0;
|
|
263
364
|
this._syncing = !1, this._availableSelection = [], this.requestUpdate(), this._dispatchChange();
|
|
264
365
|
}
|
|
265
366
|
}
|
|
266
367
|
/** Removes the highlighted right-hand options from the selected list. */
|
|
267
368
|
removeSelected() {
|
|
268
|
-
if (!this.
|
|
369
|
+
if (!this._$select)
|
|
370
|
+
return;
|
|
269
371
|
const e = new Set(this._$selectedList?.selectedValues ?? []);
|
|
270
372
|
if (e.size !== 0) {
|
|
271
373
|
this._syncing = !0;
|
|
272
|
-
for (const t of Array.from(this.
|
|
374
|
+
for (const t of Array.from(this._$select.options))
|
|
273
375
|
t.selected && e.has(t.value) && (t.selected = !1);
|
|
274
376
|
this._syncing = !1, this._selectedSelection = [], this.requestUpdate(), this._dispatchChange();
|
|
275
377
|
}
|
|
276
378
|
}
|
|
277
379
|
/** Clears the selected/right-hand list. */
|
|
278
380
|
clearSelected() {
|
|
279
|
-
if (this.
|
|
381
|
+
if (this._$select) {
|
|
280
382
|
this._syncing = !0;
|
|
281
|
-
for (const e of Array.from(this.
|
|
383
|
+
for (const e of Array.from(this._$select.options))
|
|
384
|
+
e.selected = !1;
|
|
282
385
|
this._syncing = !1, this._selectedSelection = [], this.requestUpdate(), this._dispatchChange();
|
|
283
386
|
}
|
|
284
387
|
}
|
|
285
388
|
/** Moves highlighted right-hand options by `delta` rows (-1 = up, 1 = down). */
|
|
286
389
|
moveSelected(e) {
|
|
287
|
-
if (e === 0 || !this.
|
|
390
|
+
if (e === 0 || !this._$select)
|
|
391
|
+
return;
|
|
288
392
|
const t = new Set(this._$selectedList?.selectedValues ?? []);
|
|
289
393
|
t.size !== 0 && (this._syncing = !0, this._reorderSelectOptions(t, e), this._syncing = !1, this.requestUpdate(), this._dispatchChange(t));
|
|
290
394
|
}
|
|
291
395
|
_canMoveSelected(e, t, s) {
|
|
292
396
|
return t.size === 0 || e.length < 2 ? !1 : e.some((l, i) => {
|
|
293
|
-
if (!t.has(l.value))
|
|
397
|
+
if (!t.has(l.value))
|
|
398
|
+
return !1;
|
|
294
399
|
const r = i + s;
|
|
295
400
|
return r < 0 || r >= e.length ? !1 : !t.has(e[r].value);
|
|
296
401
|
});
|
|
297
402
|
}
|
|
298
|
-
|
|
299
|
-
const
|
|
300
|
-
|
|
403
|
+
_getListboxEventTargetId(e) {
|
|
404
|
+
for (const t of e.composedPath())
|
|
405
|
+
if (t instanceof Element && (t.id === "available-list" || t.id === "selected-list"))
|
|
406
|
+
return t.id;
|
|
407
|
+
}
|
|
408
|
+
_setupSelect(e) {
|
|
409
|
+
e !== this._$select && (this._teardownSelect(), this._$select = e, e && (e.style.display = "none", e.setAttribute("aria-hidden", "true"), e.tabIndex = -1, this._selectObserver.setOptions({
|
|
410
|
+
target: e,
|
|
411
|
+
disabled: !1,
|
|
412
|
+
observerOptions: { childList: !0 }
|
|
413
|
+
}), !this._selectedInitialized && this._defaultSelected !== void 0 && this._applyDefaultSelected(this._defaultSelected), this.requestUpdate()));
|
|
301
414
|
}
|
|
302
415
|
_teardownSelect() {
|
|
303
|
-
this.
|
|
416
|
+
this._$select && (this._$select.style.display = "", this._$select.removeAttribute("aria-hidden"), this._$select.removeAttribute("tabindex")), this._selectObserver.setOptions({ target: null, disabled: !0 }), this._$select = null;
|
|
304
417
|
}
|
|
305
418
|
/**
|
|
306
419
|
* Reorders selected `<option>` DOM nodes inside the backing `<select>` to
|
|
307
420
|
* preserve user-determined order in form serialisation.
|
|
308
421
|
*/
|
|
309
422
|
_reorderSelectOptions(e, t) {
|
|
310
|
-
const s = this.
|
|
423
|
+
const s = this._$select, l = Array.from(s.options).filter((a) => a.selected), i = t < 0 ? 1 : l.length - 2, r = t < 0 ? l.length : -1, h = t < 0 ? 1 : -1;
|
|
311
424
|
for (let a = i; a !== r; a += h) {
|
|
312
425
|
const d = a + t;
|
|
313
426
|
!e.has(l[a].value) || e.has(l[d].value) || (t < 0 ? s.insertBefore(l[a], l[d]) : l[d].insertAdjacentElement("afterend", l[a]));
|
|
@@ -329,10 +442,15 @@ class o extends _ {
|
|
|
329
442
|
);
|
|
330
443
|
});
|
|
331
444
|
}
|
|
332
|
-
}
|
|
445
|
+
};
|
|
446
|
+
b.styles = S;
|
|
447
|
+
let o = b;
|
|
333
448
|
n([
|
|
334
449
|
p({ type: Boolean, reflect: !0 })
|
|
335
450
|
], o.prototype, "multiple");
|
|
451
|
+
n([
|
|
452
|
+
p({ type: Boolean, reflect: !0 })
|
|
453
|
+
], o.prototype, "compact");
|
|
336
454
|
n([
|
|
337
455
|
p({ attribute: "available-label" })
|
|
338
456
|
], o.prototype, "availableLabel");
|
|
@@ -340,18 +458,18 @@ n([
|
|
|
340
458
|
p({ attribute: "selected-label" })
|
|
341
459
|
], o.prototype, "selectedLabel");
|
|
342
460
|
n([
|
|
343
|
-
|
|
461
|
+
f("#available-list")
|
|
344
462
|
], o.prototype, "_$availableList");
|
|
345
463
|
n([
|
|
346
|
-
|
|
464
|
+
f("#selected-list")
|
|
347
465
|
], o.prototype, "_$selectedList");
|
|
348
466
|
n([
|
|
349
|
-
|
|
467
|
+
v()
|
|
350
468
|
], o.prototype, "_availableSelection");
|
|
351
469
|
n([
|
|
352
|
-
|
|
470
|
+
v()
|
|
353
471
|
], o.prototype, "_selectedSelection");
|
|
354
472
|
export {
|
|
355
473
|
o as R
|
|
356
474
|
};
|
|
357
|
-
//# sourceMappingURL=rc-transfer-list-
|
|
475
|
+
//# sourceMappingURL=rc-transfer-list-DFPxuGJ2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rc-transfer-list-DFPxuGJ2.js","sources":["../src/rc-transfer-list.styles.ts","../src/rc-transfer-list.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const transferListStyles = css`\n :host {\n display: block;\n }\n\n :host([hidden]) {\n display: none;\n }\n\n #root {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);\n align-items: stretch;\n gap: var(--rc-transfer-list-gap, var(--rc-control-gap, 0.75rem));\n }\n\n :host([compact]) #root {\n grid-template-columns: minmax(0, 1fr);\n }\n\n .rc-transfer-list-panel {\n display: flex;\n min-inline-size: 0;\n flex-direction: column;\n gap: var(--rc-transfer-list-panel-gap, var(--rc-control-gap, 0.35rem));\n }\n\n .rc-transfer-list-panel > rc-listbox {\n flex: 1 1 auto;\n min-block-size: var(--rc-transfer-list-listbox-min-block-size, 10rem);\n overflow: auto;\n border: var(--rc-transfer-list-listbox-border, var(--rc-border, 1px solid ButtonBorder));\n background: var(--rc-transfer-list-listbox-bg, var(--rc-surface, Canvas));\n color: var(--rc-transfer-list-listbox-color, var(--rc-field-text, FieldText));\n --rc-listbox-option-gap: var(--rc-transfer-list-option-gap, var(--rc-item-gap, 0.4em));\n --rc-listbox-option-padding-block: var(\n --rc-transfer-list-option-padding-block,\n var(--rc-item-padding-block, 0.3em)\n );\n --rc-listbox-option-padding-inline: var(\n --rc-transfer-list-option-padding-inline,\n var(--rc-item-padding-inline, 0.75em)\n );\n --rc-listbox-hover-bg: var(\n --rc-transfer-list-option-hover-bg,\n var(--rc-transfer-list-option-selected-bg, var(--rc-highlight, Highlight))\n );\n --rc-listbox-hover-color: var(\n --rc-transfer-list-option-hover-color,\n var(--rc-transfer-list-option-selected-color, var(--rc-highlight-text, HighlightText))\n );\n --rc-listbox-active-bg: var(\n --rc-transfer-list-option-hover-bg,\n var(--rc-transfer-list-option-selected-bg, var(--rc-highlight, Highlight))\n );\n --rc-listbox-active-color: var(\n --rc-transfer-list-option-hover-color,\n var(--rc-transfer-list-option-selected-color, var(--rc-highlight-text, HighlightText))\n );\n --rc-listbox-selected-bg: var(\n --rc-transfer-list-option-selected-bg,\n var(--rc-highlight, Highlight)\n );\n --rc-listbox-selected-color: var(\n --rc-transfer-list-option-selected-color,\n var(--rc-highlight-text, HighlightText)\n );\n --rc-listbox-disabled-opacity: var(--rc-disabled-opacity, 0.5);\n }\n\n rc-listbox [part~='option'][hidden] {\n display: none;\n }\n\n rc-listbox [part~='option'][data-active]:not([aria-disabled='true']) {\n outline: var(--rc-focus-ring, 2px solid var(--rc-accent, Highlight));\n outline-offset: -2px;\n }\n\n rc-listbox [part~='option'][aria-disabled='true'] {\n cursor: not-allowed;\n }\n\n #actions {\n align-self: center;\n transform: translateY(\n calc((1lh + var(--rc-transfer-list-panel-gap, var(--rc-control-gap, 0.35rem))) / 2)\n );\n }\n\n :host([compact]) #actions {\n align-self: stretch;\n transform: none;\n }\n\n :host([compact]) #actions::part(root) {\n flex-wrap: wrap;\n justify-content: center;\n }\n\n #actions button {\n white-space: nowrap;\n }\n\n slot:not([name]) {\n display: none;\n }\n`;\n\nexport default transferListStyles;\n","import { LitElement, html, nothing } from 'lit';\nimport { property, query, state } from 'lit/decorators.js';\n\nimport {\n MutationObserverController,\n NativeChildController,\n warnMissingDirectChild,\n} from '@rcarls/rc-common';\nimport type { ListboxOption, RCListbox, RCListboxChangeEvent } from '@rcarls/rc-listbox';\n\nimport '@rcarls/rc-listbox/define';\nimport '@rcarls/rc-toolbar/define';\n\nimport { transferListStyles } from './rc-transfer-list.styles.js';\n\nexport interface RCTransferListChangeEvent {\n /** Ordered selected/right-hand list options. */\n selected: ListboxOption[];\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'rc-transfer-list': RCTransferList;\n }\n}\n\n/**\n * Transfer list that enhances a native <select multiple> into available and selected\n * panes.\n *\n * The component renders two listboxes and transfer/reorder actions in between.\n * Available options are on the left, and selected options appear on the right. It\n * is an older enterprise/admin UI pattern, but solves the specific problem of\n * multiple selection within a large amount of options.\n *\n * The `available` and `selected` JS array properties write through to the\n * backing `<select>`, so the component can also be driven imperatively from a\n * framework without giving up form participation.\n *\n * @see {@link https://richardcarls.github.io/rc-webcomponents/components/rc-transfer-list rc-transfer-list docs}\n *\n * @fires rc-transfer-list-change - Fires when the selected/right-hand list changes.\n *\n * @cssprop [--rc-transfer-list-gap=var(--rc-control-gap)] - Gap between panels and the action toolbar\n * @cssprop [--rc-transfer-list-panel-gap=var(--rc-control-gap)] - Gap between a panel label and its listbox\n * @cssprop [--rc-transfer-list-listbox-min-block-size=10rem] - Minimum block size for each listbox\n * @cssprop [--rc-transfer-list-listbox-border=var(--rc-border)] - Border around each listbox\n * @cssprop [--rc-transfer-list-option-gap=var(--rc-item-gap)] - Gap between option adornments and labels\n * @cssprop [--rc-transfer-list-option-padding-block=var(--rc-item-padding-block)] - Block padding for option rows\n * @cssprop [--rc-transfer-list-option-padding-inline=var(--rc-item-padding-inline)] - Inline padding for option rows\n * @cssprop [--rc-transfer-list-option-selected-bg=var(--rc-highlight)] - Selected option background\n * @cssprop [--rc-transfer-list-option-selected-color=var(--rc-highlight-text)] - Selected option foreground\n *\n * @csspart root - Root layout wrapper. Reflects data-can-move-up/down.\n * @csspart panel - Shared list panel surface.\n * @csspart available-panel - Available/left panel. Reflects data-empty and data-has-selection.\n * @csspart selected-panel - Selected/right panel. Reflects data-empty and data-has-selection.\n * @csspart actions - Transfer action toolbar.\n * @csspart button - Shared action button surface.\n */\nexport class RCTransferList extends LitElement {\n static override styles = transferListStyles;\n\n /** Enable multi-selection in both lists. */\n @property({ type: Boolean, reflect: true })\n multiple = false;\n\n /** Stack the panels and action toolbar into a compact one-column layout. */\n @property({ type: Boolean, reflect: true })\n compact = false;\n\n /** Visible label for the available list. */\n @property({ attribute: 'available-label' })\n availableLabel = 'Available';\n\n /** Visible label for the selected list. */\n @property({ attribute: 'selected-label' })\n selectedLabel = 'Selected';\n\n @query('#available-list')\n private _$availableList?: RCListbox;\n\n @query('#selected-list')\n private _$selectedList?: RCListbox;\n\n /** Values currently highlighted in the available list. Drives the \"Add →\" button disable state. */\n @state()\n private _availableSelection: string[] = [];\n\n /** Values currently highlighted in the selected list. Drives Remove/reorder button disable states. */\n @state()\n private _selectedSelection: string[] = [];\n\n private _$select: HTMLSelectElement | null = null;\n\n /** Set while the component mutates the backing <select> to prevent observer feedback loops. */\n private _syncing = false;\n\n private _defaultSelected: ListboxOption[] | undefined;\n\n private _selectedInitialized = false;\n\n private readonly _selectObserver = new MutationObserverController(this, {\n target: null,\n disabled: true,\n callback: () => {\n if (!this._syncing) {\n this.requestUpdate();\n }\n },\n });\n\n constructor() {\n super();\n\n new NativeChildController<HTMLSelectElement>(this, {\n selector: ':scope > select[multiple]',\n observe: true,\n onChange: ($select) => this._setupSelect($select),\n onMissing: () => {\n if (import.meta.env.DEV) {\n warnMissingDirectChild(this, {\n selector: ':scope > select[multiple]',\n message:\n '[rc-transfer-list] No direct child <select multiple> found. ' +\n 'Add a <select multiple> child for form participation and progressive enhancement.',\n });\n }\n },\n });\n }\n\n /**\n * Available/left-hand options derived from unselected `<option>` elements.\n *\n * Setting this property replaces all unselected options in the backing\n * `<select>`. Items whose values already appear in the selected list are\n * skipped to prevent duplicate option values.\n */\n get available(): ListboxOption[] {\n if (!this._$select) {\n return [];\n }\n\n return Array.from(this._$select.options)\n .filter(($option) => !$option.selected)\n .map(($option) => ({ value: $option.value, label: $option.label || $option.text }));\n }\n\n set available(items: ListboxOption[]) {\n if (!this._$select) {\n return;\n }\n\n this._syncing = true;\n\n const selectedValues = new Set(\n Array.from(this._$select.options)\n .filter(($option) => $option.selected)\n .map(($option) => $option.value),\n );\n\n for (const $option of Array.from(this._$select.options)) {\n if (!$option.selected) {\n $option.remove();\n }\n }\n\n for (const item of items) {\n if (!selectedValues.has(item.value)) {\n this._$select.add(new Option(item.label, item.value));\n }\n }\n\n this._syncing = false;\n this.requestUpdate();\n }\n\n /**\n * Selected/right-hand options derived from selected `<option>` elements.\n *\n * Setting this property replaces all selected options in the backing\n * `<select>`. Unselected options are left unchanged.\n */\n get selected(): ListboxOption[] {\n if (!this._$select) {\n return [];\n }\n\n return Array.from(this._$select.options)\n .filter(($option) => $option.selected)\n .map(($option) => ({ value: $option.value, label: $option.label || $option.text }));\n }\n\n set selected(items: ListboxOption[]) {\n this._selectedInitialized = true;\n\n if (!this._$select) {\n return;\n }\n\n this._syncing = true;\n\n for (const $option of Array.from(this._$select.options)) {\n if ($option.selected) {\n $option.remove();\n }\n }\n\n for (const item of items) {\n this._$select.add(new Option(item.label, item.value, false, true));\n }\n\n this._syncing = false;\n this.requestUpdate();\n }\n\n /** Initial uncontrolled selected list. Applied before any `selected` write from the host. */\n get defaultSelected(): ListboxOption[] | undefined {\n return this._defaultSelected;\n }\n\n set defaultSelected(items: ListboxOption[] | undefined) {\n this._defaultSelected = items;\n\n if (!this._selectedInitialized && this._$select && items !== undefined) {\n this._applyDefaultSelected(items);\n }\n }\n\n private _applyDefaultSelected(items: ListboxOption[]): void {\n if (!this._$select) {\n return;\n }\n\n this._syncing = true;\n\n for (const $option of Array.from(this._$select.options)) {\n $option.selected = items.some((item) => item.value === $option.value);\n }\n\n this._syncing = false;\n this.requestUpdate();\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._teardownSelect();\n }\n\n override render() {\n const available = this.available; // reads <select> directly; requestUpdate() always precedes render\n const selected = this.selected;\n const selectedValues = new Set(this._selectedSelection);\n const noAvailable = available.length === 0;\n const noSelected = selected.length === 0;\n const cannotReorder = selected.length < 2;\n const noAvailableSelection = this._availableSelection.length === 0;\n const noSelectedSelection = this._selectedSelection.length === 0;\n const canMoveUp = this._canMoveSelected(selected, selectedValues, -1);\n const canMoveDown = this._canMoveSelected(selected, selectedValues, 1);\n\n return html`\n <div\n id=\"root\"\n part=\"root\"\n class=\"rc-transfer-list-root\"\n data-can-move-up=${canMoveUp ? '' : nothing}\n data-can-move-down=${canMoveDown ? '' : nothing}\n @keydown=${this._onKeydown}\n >\n <section\n part=\"panel available-panel\"\n class=\"rc-transfer-list-panel\"\n aria-labelledby=\"available-label\"\n data-empty=${noAvailable ? '' : nothing}\n data-has-selection=${!noAvailableSelection ? '' : nothing}\n >\n <span part=\"label available-label\" id=\"available-label\">${this.availableLabel}</span>\n <rc-listbox\n id=\"available-list\"\n part=\"listbox available-listbox\"\n aria-labelledby=\"available-label\"\n tabindex=\"0\"\n .options=${available}\n .multiple=${this.multiple}\n @rc-listbox-change=${this._onListboxChange}\n ></rc-listbox>\n </section>\n\n <rc-toolbar\n id=\"actions\"\n orientation=${this.compact ? 'horizontal' : 'vertical'}\n label=\"Transfer actions\"\n part=\"actions\"\n class=\"rc-transfer-list-actions\"\n >\n <button\n type=\"button\"\n part=\"button add-button\"\n ?disabled=${noAvailable || noAvailableSelection}\n @click=${this.addSelected}\n >\n Add →\n </button>\n\n <button\n type=\"button\"\n part=\"button add-all-button\"\n ?disabled=${noAvailable}\n @click=${this.addAll}\n >\n Add all →\n </button>\n\n <button\n type=\"button\"\n part=\"button remove-button\"\n ?disabled=${noSelected || noSelectedSelection}\n @click=${this.removeSelected}\n >\n ← Remove\n </button>\n\n <button\n type=\"button\"\n part=\"button clear-button\"\n ?disabled=${noSelected}\n @click=${this.clearSelected}\n >\n ← Clear\n </button>\n\n <button\n type=\"button\"\n part=\"button move-up-button\"\n ?disabled=${cannotReorder || noSelectedSelection}\n @click=${this._onMoveUp}\n >\n Move up\n </button>\n\n <button\n type=\"button\"\n part=\"button move-down-button\"\n ?disabled=${cannotReorder || noSelectedSelection}\n @click=${this._onMoveDown}\n >\n Move down\n </button>\n </rc-toolbar>\n\n <section\n part=\"panel selected-panel\"\n class=\"rc-transfer-list-panel\"\n aria-labelledby=\"selected-label\"\n data-empty=${noSelected ? '' : nothing}\n data-has-selection=${!noSelectedSelection ? '' : nothing}\n >\n <span part=\"label selected-label\" id=\"selected-label\">${this.selectedLabel}</span>\n\n <rc-listbox\n id=\"selected-list\"\n part=\"listbox selected-listbox\"\n aria-labelledby=\"selected-label\"\n tabindex=\"0\"\n .options=${selected}\n .multiple=${this.multiple}\n @rc-listbox-change=${this._onListboxChange}\n ></rc-listbox>\n </section>\n </div>\n <slot></slot>\n `;\n }\n\n /** Adds the highlighted available options to the selected list. */\n addSelected(): void {\n if (!this._$select) {\n return;\n }\n\n const values = new Set(this._$availableList?.selectedValues ?? []);\n\n if (values.size === 0) {\n return;\n }\n\n this._syncing = true;\n\n for (const $option of Array.from(this._$select.options)) {\n if (!$option.selected && values.has($option.value)) {\n $option.selected = true;\n }\n }\n\n this._syncing = false;\n this._availableSelection = [];\n this.requestUpdate();\n this._dispatchChange();\n }\n\n /** Adds every available option to the selected list. */\n addAll(): void {\n if (!this._$select) {\n return;\n }\n\n this._syncing = true;\n\n for (const $option of Array.from(this._$select.options)) {\n $option.selected = true;\n }\n\n this._syncing = false;\n\n this._availableSelection = [];\n this.requestUpdate();\n this._dispatchChange();\n }\n\n /** Removes the highlighted right-hand options from the selected list. */\n removeSelected(): void {\n if (!this._$select) {\n return;\n }\n\n const values = new Set(this._$selectedList?.selectedValues ?? []);\n\n if (values.size === 0) {\n return;\n }\n\n this._syncing = true;\n\n for (const $option of Array.from(this._$select.options)) {\n if ($option.selected && values.has($option.value)) {\n $option.selected = false;\n }\n }\n\n this._syncing = false;\n this._selectedSelection = [];\n this.requestUpdate();\n this._dispatchChange();\n }\n\n /** Clears the selected/right-hand list. */\n clearSelected(): void {\n if (!this._$select) {\n return;\n }\n\n this._syncing = true;\n\n for (const $option of Array.from(this._$select.options)) {\n $option.selected = false;\n }\n\n this._syncing = false;\n\n this._selectedSelection = [];\n this.requestUpdate();\n this._dispatchChange();\n }\n\n /** Moves highlighted right-hand options by `delta` rows (-1 = up, 1 = down). */\n moveSelected(delta: number): void {\n if (delta === 0 || !this._$select) {\n return;\n }\n\n const values = new Set(this._$selectedList?.selectedValues ?? []);\n\n if (values.size === 0) {\n return;\n }\n\n this._syncing = true;\n this._reorderSelectOptions(values, delta);\n this._syncing = false;\n\n this.requestUpdate();\n this._dispatchChange(values);\n }\n\n private _onMoveUp = (): void => {\n this.moveSelected(-1);\n };\n\n private _onMoveDown = (): void => {\n this.moveSelected(1);\n };\n\n private _canMoveSelected(\n selected: ListboxOption[],\n selectedValues: Set<string>,\n delta: -1 | 1,\n ): boolean {\n if (selectedValues.size === 0 || selected.length < 2) {\n return false;\n }\n\n return selected.some((item, index) => {\n if (!selectedValues.has(item.value)) {\n return false;\n }\n\n const target = index + delta;\n\n if (target < 0 || target >= selected.length) {\n return false;\n }\n\n return !selectedValues.has(selected[target].value);\n });\n }\n\n private _onKeydown = (e: KeyboardEvent): void => {\n if (e.altKey) {\n switch (e.key) {\n case 'ArrowRight':\n e.preventDefault();\n this.addSelected();\n\n break;\n\n case 'ArrowLeft':\n e.preventDefault();\n this.removeSelected();\n\n break;\n\n case 'ArrowUp':\n e.preventDefault();\n this.moveSelected(-1);\n\n break;\n\n case 'ArrowDown':\n e.preventDefault();\n this.moveSelected(1);\n\n break;\n }\n\n return;\n }\n\n const targetId = this._getListboxEventTargetId(e);\n\n // APG shortcut: Enter in the available list adds the active item.\n\n // Restricted to single-select: in multi mode Enter toggles selection in rc-listbox\n // first, so triggering addSelected() here would immediately transfer a single item\n // and discard any multi-item selection the user was building.\n if (targetId === 'available-list' && !this.multiple && e.key === 'Enter') {\n e.preventDefault();\n this.addSelected();\n\n return;\n }\n\n // APG shortcut: Delete in the selected list removes the highlighted items.\n if (targetId === 'selected-list' && e.key === 'Delete') {\n e.preventDefault();\n\n this.removeSelected();\n }\n };\n\n private _onListboxChange = (e: Event): void => {\n const ev = e as CustomEvent<RCListboxChangeEvent>;\n\n if (ev.detail.reason === 'action') {\n e.stopPropagation();\n return;\n }\n\n const raw = ev.detail.value;\n const values = Array.isArray(raw) ? raw : raw ? [raw] : [];\n const targetId = (e.currentTarget as Element | null)?.id;\n\n if (targetId === 'available-list') {\n this._availableSelection = values;\n } else if (targetId === 'selected-list') {\n this._selectedSelection = values;\n }\n };\n\n private _getListboxEventTargetId(e: Event): string | undefined {\n for (const node of e.composedPath()) {\n if (\n node instanceof Element &&\n (node.id === 'available-list' || node.id === 'selected-list')\n ) {\n return node.id;\n }\n }\n\n return undefined;\n }\n\n private _setupSelect($select: HTMLSelectElement | null): void {\n if ($select === this._$select) {\n return;\n }\n\n this._teardownSelect();\n this._$select = $select;\n\n if (!$select) {\n return;\n }\n\n // Remove from visual display, AT, and tab order — the rc-listbox UI is the\n // accessible interface; the <select> is only present for form serialisation.\n $select.style.display = 'none';\n $select.setAttribute('aria-hidden', 'true');\n $select.tabIndex = -1;\n\n // Watch for external option additions/removals (attribute-level opt.selected\n // changes via IDL are not observable; use the component API instead).\n this._selectObserver.setOptions({\n target: $select,\n disabled: false,\n observerOptions: { childList: true },\n });\n\n if (!this._selectedInitialized && this._defaultSelected !== undefined) {\n this._applyDefaultSelected(this._defaultSelected);\n }\n\n this.requestUpdate();\n }\n\n private _teardownSelect(): void {\n if (this._$select) {\n this._$select.style.display = '';\n this._$select.removeAttribute('aria-hidden');\n this._$select.removeAttribute('tabindex');\n }\n\n this._selectObserver.setOptions({ target: null, disabled: true });\n this._$select = null;\n }\n\n /**\n * Reorders selected `<option>` DOM nodes inside the backing `<select>` to\n * preserve user-determined order in form serialisation.\n */\n private _reorderSelectOptions(movedValues: Set<string>, delta: number): void {\n const $select = this._$select!;\n const $options = Array.from($select.options).filter(($option) => $option.selected);\n\n const start = delta < 0 ? 1 : $options.length - 2;\n const end = delta < 0 ? $options.length : -1;\n const step = delta < 0 ? 1 : -1;\n\n for (let i = start; i !== end; i += step) {\n const target = i + delta;\n\n if (!movedValues.has($options[i].value) || movedValues.has($options[target].value)) {\n continue;\n }\n\n if (delta < 0) {\n $select.insertBefore($options[i], $options[target]);\n } else {\n $options[target].insertAdjacentElement('afterend', $options[i]);\n }\n }\n }\n\n // Restores selection in the selected listbox after a mutation. Options are\n // set declaratively in render() so only selection state needs imperative sync.\n private _syncSelection(selectedValues: Set<string> = new Set()): void {\n this._$selectedList?.setSelectedValues([...selectedValues]);\n }\n\n private _dispatchChange(selectedValues?: Set<string>): void {\n this.updateComplete.then(() => {\n this._syncSelection(selectedValues);\n\n this.dispatchEvent(\n new CustomEvent<RCTransferListChangeEvent>('rc-transfer-list-change', {\n bubbles: true,\n composed: true,\n detail: { selected: [...this.selected] },\n }),\n );\n });\n }\n}\n\nexport default RCTransferList;\n"],"names":["transferListStyles","css","_RCTransferList","LitElement","MutationObserverController","targetId","ev","raw","values","NativeChildController","$select","$option","items","selectedValues","item","available","selected","noAvailable","noSelected","cannotReorder","noAvailableSelection","noSelectedSelection","canMoveUp","canMoveDown","html","nothing","delta","index","target","node","movedValues","$options","start","end","step","i","RCTransferList","__decorateClass","property","query","state"],"mappings":"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"}
|
package/dist/rc-transfer-list.js
CHANGED
|
@@ -10,24 +10,32 @@ declare global {
|
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
13
|
+
* Transfer list that enhances a native <select multiple> into available and selected
|
|
14
|
+
* panes.
|
|
14
15
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* submission serialises the right-panel values in user-determined order.
|
|
16
|
+
* The component renders two listboxes and transfer/reorder actions in between.
|
|
17
|
+
* Available options are on the left, and selected options appear on the right. It
|
|
18
|
+
* is an older enterprise/admin UI pattern, but solves the specific problem of
|
|
19
|
+
* multiple selection within a large amount of options.
|
|
20
20
|
*
|
|
21
21
|
* The `available` and `selected` JS array properties write through to the
|
|
22
22
|
* backing `<select>`, so the component can also be driven imperatively from a
|
|
23
23
|
* framework without giving up form participation.
|
|
24
24
|
*
|
|
25
|
+
* @see {@link https://richardcarls.github.io/rc-webcomponents/components/rc-transfer-list rc-transfer-list docs}
|
|
26
|
+
*
|
|
25
27
|
* @fires rc-transfer-list-change - Fires when the selected/right-hand list changes.
|
|
26
28
|
*
|
|
27
29
|
* @cssprop [--rc-transfer-list-gap=var(--rc-control-gap)] - Gap between panels and the action toolbar
|
|
28
30
|
* @cssprop [--rc-transfer-list-panel-gap=var(--rc-control-gap)] - Gap between a panel label and its listbox
|
|
29
31
|
* @cssprop [--rc-transfer-list-listbox-min-block-size=10rem] - Minimum block size for each listbox
|
|
30
32
|
* @cssprop [--rc-transfer-list-listbox-border=var(--rc-border)] - Border around each listbox
|
|
33
|
+
* @cssprop [--rc-transfer-list-option-gap=var(--rc-item-gap)] - Gap between option adornments and labels
|
|
34
|
+
* @cssprop [--rc-transfer-list-option-padding-block=var(--rc-item-padding-block)] - Block padding for option rows
|
|
35
|
+
* @cssprop [--rc-transfer-list-option-padding-inline=var(--rc-item-padding-inline)] - Inline padding for option rows
|
|
36
|
+
* @cssprop [--rc-transfer-list-option-selected-bg=var(--rc-highlight)] - Selected option background
|
|
37
|
+
* @cssprop [--rc-transfer-list-option-selected-color=var(--rc-highlight-text)] - Selected option foreground
|
|
38
|
+
*
|
|
31
39
|
* @csspart root - Root layout wrapper. Reflects data-can-move-up/down.
|
|
32
40
|
* @csspart panel - Shared list panel surface.
|
|
33
41
|
* @csspart available-panel - Available/left panel. Reflects data-empty and data-has-selection.
|
|
@@ -36,9 +44,11 @@ declare global {
|
|
|
36
44
|
* @csspart button - Shared action button surface.
|
|
37
45
|
*/
|
|
38
46
|
export declare class RCTransferList extends LitElement {
|
|
39
|
-
|
|
47
|
+
static styles: import('lit').CSSResult;
|
|
40
48
|
/** Enable multi-selection in both lists. */
|
|
41
49
|
multiple: boolean;
|
|
50
|
+
/** Stack the panels and action toolbar into a compact one-column layout. */
|
|
51
|
+
compact: boolean;
|
|
42
52
|
/** Visible label for the available list. */
|
|
43
53
|
availableLabel: string;
|
|
44
54
|
/** Visible label for the selected list. */
|
|
@@ -49,13 +59,13 @@ export declare class RCTransferList extends LitElement {
|
|
|
49
59
|
private _availableSelection;
|
|
50
60
|
/** Values currently highlighted in the selected list. Drives Remove/reorder button disable states. */
|
|
51
61
|
private _selectedSelection;
|
|
52
|
-
private
|
|
62
|
+
private _$select;
|
|
53
63
|
/** Set while the component mutates the backing <select> to prevent observer feedback loops. */
|
|
54
64
|
private _syncing;
|
|
55
65
|
private _defaultSelected;
|
|
56
66
|
private _selectedInitialized;
|
|
57
|
-
private
|
|
58
|
-
|
|
67
|
+
private readonly _selectObserver;
|
|
68
|
+
constructor();
|
|
59
69
|
/**
|
|
60
70
|
* Available/left-hand options derived from unselected `<option>` elements.
|
|
61
71
|
*
|
|
@@ -77,7 +87,6 @@ export declare class RCTransferList extends LitElement {
|
|
|
77
87
|
get defaultSelected(): ListboxOption[] | undefined;
|
|
78
88
|
set defaultSelected(items: ListboxOption[] | undefined);
|
|
79
89
|
private _applyDefaultSelected;
|
|
80
|
-
connectedCallback(): void;
|
|
81
90
|
disconnectedCallback(): void;
|
|
82
91
|
render(): import('lit').TemplateResult<1>;
|
|
83
92
|
/** Adds the highlighted available options to the selected list. */
|
|
@@ -95,6 +104,7 @@ export declare class RCTransferList extends LitElement {
|
|
|
95
104
|
private _canMoveSelected;
|
|
96
105
|
private _onKeydown;
|
|
97
106
|
private _onListboxChange;
|
|
107
|
+
private _getListboxEventTargetId;
|
|
98
108
|
private _setupSelect;
|
|
99
109
|
private _teardownSelect;
|
|
100
110
|
/**
|
package/package.json
CHANGED
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.
|
|
7
|
-
"description": "
|
|
6
|
+
"version": "0.3.0",
|
|
7
|
+
"description": "Transfer list that enhances a native <select multiple> into available and selected panes.",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
10
10
|
"url": "git+https://github.com/richardcarls/rc-webcomponents.git",
|
|
11
11
|
"directory": "packages/rc-transfer-list"
|
|
12
12
|
},
|
|
13
|
-
"homepage": "https://github.
|
|
13
|
+
"homepage": "https://richardcarls.github.io/rc-webcomponents/components/rc-transfer-list",
|
|
14
14
|
"license": "MIT",
|
|
15
15
|
"type": "module",
|
|
16
16
|
"files": [
|
|
@@ -37,22 +37,20 @@
|
|
|
37
37
|
],
|
|
38
38
|
"customElements": "dist/custom-elements.json",
|
|
39
39
|
"scripts": {
|
|
40
|
-
"dev": "vite",
|
|
41
40
|
"build": "tsc && vite build && cem analyze",
|
|
42
41
|
"cem:analyze": "cem analyze",
|
|
43
42
|
"preview": "vite preview",
|
|
44
|
-
"test:browser": "vitest",
|
|
45
|
-
"test:browser:chrome": "vitest --project=chromium",
|
|
46
|
-
"test:browser:firefox": "vitest --project=firefox"
|
|
47
|
-
"yalc:publish": "yalc publish --push"
|
|
43
|
+
"test:browser": "vitest --run",
|
|
44
|
+
"test:browser:chrome": "vitest --run --project=chromium",
|
|
45
|
+
"test:browser:firefox": "vitest --run --project=firefox"
|
|
48
46
|
},
|
|
49
47
|
"dependencies": {
|
|
50
|
-
"@rcarls/rc-
|
|
51
|
-
"@rcarls/rc-
|
|
48
|
+
"@rcarls/rc-common": "workspace:*",
|
|
49
|
+
"@rcarls/rc-listbox": "workspace:*",
|
|
50
|
+
"@rcarls/rc-toolbar": "workspace:*"
|
|
52
51
|
},
|
|
53
52
|
"devDependencies": {
|
|
54
53
|
"@custom-elements-manifest/analyzer": "0.11.0",
|
|
55
|
-
"@guanghechen/rollup-plugin-copy": "^6.0.9",
|
|
56
54
|
"@vitest/browser-playwright": "4.1.5",
|
|
57
55
|
"lit": "^3.0.0",
|
|
58
56
|
"playwright": "^1.56.0",
|
package/dist/demo.css
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
*, *::before, *::after {
|
|
2
|
-
box-sizing: border-box;
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
:root {
|
|
6
|
-
color-scheme: light dark;
|
|
7
|
-
--rc-accent: Highlight; /* Chrome doesn't support AccentColor on the open web */
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
@supports (color: AccentColor) {
|
|
11
|
-
:root {
|
|
12
|
-
--rc-accent: AccentColor;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
[data-theme="light"] { color-scheme: light; }
|
|
17
|
-
[data-theme="dark"] { color-scheme: dark; }
|
|
18
|
-
|
|
19
|
-
[data-theme="solarized-light"] {
|
|
20
|
-
color-scheme: light;
|
|
21
|
-
--rc-surface: #fdf6e3;
|
|
22
|
-
--rc-text: #657b83;
|
|
23
|
-
--rc-border: 1px solid #93a1a1;
|
|
24
|
-
--rc-shadow: 0 2px 8px rgba(0, 0, 0, .12);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
[data-theme="solarized-dark"] {
|
|
28
|
-
color-scheme: dark;
|
|
29
|
-
--rc-surface: #002b36;
|
|
30
|
-
--rc-text: #839496;
|
|
31
|
-
--rc-border: 1px solid #586e75;
|
|
32
|
-
--rc-shadow: 0 2px 8px rgba(0, 0, 0, .3);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
body {
|
|
36
|
-
font-family: system-ui, sans-serif;
|
|
37
|
-
margin: 0;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
.demo-page {
|
|
41
|
-
max-width: 60rem;
|
|
42
|
-
margin: 0 auto;
|
|
43
|
-
padding: 2rem 1.5rem;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
.demo-controls {
|
|
47
|
-
display: flex;
|
|
48
|
-
align-items: center;
|
|
49
|
-
gap: 1rem;
|
|
50
|
-
margin-bottom: 2rem;
|
|
51
|
-
padding-bottom: 1rem;
|
|
52
|
-
border-bottom: 1px solid ButtonBorder;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
.demo-controls .demo-title {
|
|
56
|
-
flex: 1;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
.demo-controls h1 {
|
|
60
|
-
margin: 0 0 0.15rem;
|
|
61
|
-
font-size: 1.5rem;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
.demo-controls a {
|
|
65
|
-
font-size: 0.8rem;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
.demo-section {
|
|
69
|
-
margin-bottom: 2rem;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
.demo-section h2 {
|
|
73
|
-
margin: 0 0 0.5rem;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
.theme-picker {
|
|
77
|
-
padding: 0.35em 0.75em;
|
|
78
|
-
font-family: inherit;
|
|
79
|
-
font-size: 0.8rem;
|
|
80
|
-
cursor: pointer;
|
|
81
|
-
border: 1px solid ButtonBorder;
|
|
82
|
-
border-radius: 4px;
|
|
83
|
-
background: Canvas;
|
|
84
|
-
color: CanvasText;
|
|
85
|
-
}
|
package/dist/demo.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
const THEMES = ['', 'light', 'dark', 'solarized-light', 'solarized-dark'];
|
|
2
|
-
const LABELS = ['Auto', 'Light', 'Dark', 'Solarized ☀', 'Solarized ☾'];
|
|
3
|
-
|
|
4
|
-
const stored = localStorage.getItem('rc-demo-theme') ?? '';
|
|
5
|
-
applyTheme(stored);
|
|
6
|
-
|
|
7
|
-
function applyTheme(theme) {
|
|
8
|
-
if (theme) {
|
|
9
|
-
document.documentElement.dataset.theme = theme;
|
|
10
|
-
} else {
|
|
11
|
-
delete document.documentElement.dataset.theme;
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function currentIndex() {
|
|
16
|
-
const current = document.documentElement.dataset.theme ?? '';
|
|
17
|
-
const idx = THEMES.indexOf(current);
|
|
18
|
-
return idx === -1 ? 0 : idx;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function updateButtons() {
|
|
22
|
-
const label = LABELS[currentIndex()];
|
|
23
|
-
document.querySelectorAll('.theme-picker').forEach((btn) => {
|
|
24
|
-
btn.textContent = label;
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
window.cycleTheme = function () {
|
|
29
|
-
const next = THEMES[(currentIndex() + 1) % THEMES.length];
|
|
30
|
-
applyTheme(next);
|
|
31
|
-
localStorage.setItem('rc-demo-theme', next);
|
|
32
|
-
updateButtons();
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
document.addEventListener('DOMContentLoaded', () => {
|
|
36
|
-
updateButtons();
|
|
37
|
-
document.querySelectorAll('.theme-picker').forEach((btn) => {
|
|
38
|
-
btn.addEventListener('click', window.cycleTheme);
|
|
39
|
-
});
|
|
40
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"rc-transfer-list-DDgVWhv6.js","sources":["../src/rc-transfer-list.ts"],"sourcesContent":["import '@rcarls/rc-listbox/define';\nimport '@rcarls/rc-toolbar/define';\n\nimport { LitElement, html, nothing } from 'lit';\nimport { property, query, state } from 'lit/decorators.js';\nimport type { ListboxOption, RCListbox, RCListboxChangeEvent } from '@rcarls/rc-listbox';\n\nexport interface RCTransferListChangeEvent {\n /** Ordered selected/right-hand list options. */\n selected: ListboxOption[];\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'rc-transfer-list': RCTransferList;\n }\n}\n\n/**\n * Side-by-side transfer list built from two `rc-listbox` instances.\n *\n * Requires a direct child `<select multiple>` element as the single source of\n * truth for option data and form participation. Unselected `<option>` elements\n * populate the available (left) panel; selected ones populate the selected\n * (right) panel. Transfers are reflected back to the `<select>` so native form\n * submission serialises the right-panel values in user-determined order.\n *\n * The `available` and `selected` JS array properties write through to the\n * backing `<select>`, so the component can also be driven imperatively from a\n * framework without giving up form participation.\n *\n * @fires rc-transfer-list-change - Fires when the selected/right-hand list changes.\n *\n * @cssprop [--rc-transfer-list-gap=var(--rc-control-gap)] - Gap between panels and the action toolbar\n * @cssprop [--rc-transfer-list-panel-gap=var(--rc-control-gap)] - Gap between a panel label and its listbox\n * @cssprop [--rc-transfer-list-listbox-min-block-size=10rem] - Minimum block size for each listbox\n * @cssprop [--rc-transfer-list-listbox-border=var(--rc-border)] - Border around each listbox\n * @csspart root - Root layout wrapper. Reflects data-can-move-up/down.\n * @csspart panel - Shared list panel surface.\n * @csspart available-panel - Available/left panel. Reflects data-empty and data-has-selection.\n * @csspart selected-panel - Selected/right panel. Reflects data-empty and data-has-selection.\n * @csspart actions - Transfer action toolbar.\n * @csspart button - Shared action button surface.\n */\nexport class RCTransferList extends LitElement {\n override createRenderRoot() { return this; }\n\n /** Enable multi-selection in both lists. */\n @property({ type: Boolean, reflect: true }) multiple = false;\n\n /** Visible label for the available list. */\n @property({ attribute: 'available-label' }) availableLabel = 'Available';\n\n /** Visible label for the selected list. */\n @property({ attribute: 'selected-label' }) selectedLabel = 'Selected';\n\n @query('#available-list') private _$availableList?: RCListbox;\n @query('#selected-list') private _$selectedList?: RCListbox;\n\n /** Values currently highlighted in the available list. Drives the \"Add →\" button disable state. */\n @state() private _availableSelection: string[] = [];\n\n /** Values currently highlighted in the selected list. Drives Remove/reorder button disable states. */\n @state() private _selectedSelection: string[] = [];\n\n private _select: HTMLSelectElement | null = null;\n\n /** Set while the component mutates the backing <select> to prevent observer feedback loops. */\n private _syncing = false;\n\n private _defaultSelected: ListboxOption[] | undefined;\n private _selectedInitialized = false;\n\n private _hostObserver = new MutationObserver(() => this._setupSelect());\n private _selectObserver = new MutationObserver(() => {\n if (!this._syncing) this.requestUpdate();\n });\n\n\n /**\n * Available/left-hand options derived from unselected `<option>` elements.\n *\n * Setting this property replaces all unselected options in the backing\n * `<select>`. Items whose values already appear in the selected list are\n * skipped to prevent duplicate option values.\n */\n get available(): ListboxOption[] {\n if (!this._select) return [];\n\n return Array.from(this._select.options)\n .filter((o) => !o.selected)\n .map((o) => ({ value: o.value, label: o.label || o.text }));\n }\n\n set available(items: ListboxOption[]) {\n if (!this._select) return;\n\n this._syncing = true;\n\n const selectedValues = new Set(\n Array.from(this._select.options).filter((o) => o.selected).map((o) => o.value),\n );\n\n for (const opt of Array.from(this._select.options)) {\n if (!opt.selected) opt.remove();\n }\n\n for (const item of items) {\n if (!selectedValues.has(item.value)) {\n this._select.add(new Option(item.label, item.value));\n }\n }\n\n this._syncing = false;\n this.requestUpdate();\n }\n\n\n /**\n * Selected/right-hand options derived from selected `<option>` elements.\n *\n * Setting this property replaces all selected options in the backing\n * `<select>`. Unselected options are left unchanged.\n */\n get selected(): ListboxOption[] {\n if (!this._select) return [];\n\n return Array.from(this._select.options)\n .filter((o) => o.selected)\n .map((o) => ({ value: o.value, label: o.label || o.text }));\n }\n\n set selected(items: ListboxOption[]) {\n this._selectedInitialized = true;\n if (!this._select) return;\n\n this._syncing = true;\n\n for (const opt of Array.from(this._select.options)) {\n if (opt.selected) opt.remove();\n }\n\n for (const item of items) {\n this._select.add(new Option(item.label, item.value, false, true));\n }\n\n this._syncing = false;\n this.requestUpdate();\n }\n\n\n /** Initial uncontrolled selected list. Applied before any `selected` write from the host. */\n get defaultSelected(): ListboxOption[] | undefined {\n return this._defaultSelected;\n }\n set defaultSelected(items: ListboxOption[] | undefined) {\n this._defaultSelected = items;\n if (!this._selectedInitialized && this._select && items !== undefined) {\n this._applyDefaultSelected(items);\n }\n }\n\n private _applyDefaultSelected(items: ListboxOption[]): void {\n if (!this._select) return;\n this._syncing = true;\n for (const opt of Array.from(this._select.options)) {\n opt.selected = items.some((item) => item.value === opt.value);\n }\n this._syncing = false;\n this.requestUpdate();\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n this._hostObserver.observe(this, { childList: true });\n this.addEventListener('keydown', this._onKeydown);\n this.addEventListener('rc-listbox-change', this._onListboxChange);\n this._setupSelect();\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._hostObserver.disconnect();\n this._teardownSelect();\n this.removeEventListener('keydown', this._onKeydown);\n this.removeEventListener('rc-listbox-change', this._onListboxChange);\n }\n\n override render() {\n const available = this.available; // reads <select> directly; requestUpdate() always precedes render\n const selected = this.selected;\n const selectedValues = new Set(this._selectedSelection);\n const noAvailable = available.length === 0;\n const noSelected = selected.length === 0;\n const cannotReorder = selected.length < 2;\n const noAvailableSelection = this._availableSelection.length === 0;\n const noSelectedSelection = this._selectedSelection.length === 0;\n const canMoveUp = this._canMoveSelected(selected, selectedValues, -1);\n const canMoveDown = this._canMoveSelected(selected, selectedValues, 1);\n\n return html`\n <style>\n rc-transfer-list {\n display: block;\n }\n\n rc-transfer-list .rc-transfer-list-root {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);\n align-items: stretch;\n gap: var(--rc-transfer-list-gap, var(--rc-control-gap, 0.75rem));\n }\n\n rc-transfer-list .rc-transfer-list-panel {\n display: flex;\n min-inline-size: 0;\n flex-direction: column;\n gap: var(--rc-transfer-list-panel-gap, var(--rc-control-gap, 0.35rem));\n }\n\n rc-transfer-list .rc-transfer-list-panel > rc-listbox {\n flex: 1 1 auto;\n min-block-size: var(--rc-transfer-list-listbox-min-block-size, 10rem);\n overflow: auto;\n border: var(--rc-transfer-list-listbox-border, var(--rc-border, 1px solid ButtonBorder));\n }\n\n rc-transfer-list .rc-transfer-list-actions {\n align-self: center;\n }\n\n rc-transfer-list .rc-transfer-list-actions button {\n white-space: nowrap;\n }\n\n @media (max-width: 42rem) {\n rc-transfer-list .rc-transfer-list-root {\n grid-template-columns: minmax(0, 1fr);\n }\n\n rc-transfer-list .rc-transfer-list-actions {\n align-self: stretch;\n }\n }\n </style>\n <div\n part=\"root\"\n class=\"rc-transfer-list-root\"\n data-can-move-up=${canMoveUp ? '' : nothing}\n data-can-move-down=${canMoveDown ? '' : nothing}\n >\n <section\n part=\"panel available-panel\"\n class=\"rc-transfer-list-panel\"\n aria-labelledby=\"available-label\"\n data-empty=${noAvailable ? '' : nothing}\n data-has-selection=${!noAvailableSelection ? '' : nothing}\n >\n <span part=\"label available-label\" id=\"available-label\">${this.availableLabel}</span>\n <rc-listbox\n id=\"available-list\"\n part=\"listbox available-listbox\"\n aria-labelledby=\"available-label\"\n tabindex=\"0\"\n .options=${available}\n .multiple=${this.multiple}\n ></rc-listbox>\n </section>\n\n <rc-toolbar\n orientation=\"vertical\"\n label=\"Transfer actions\"\n part=\"actions\"\n class=\"rc-transfer-list-actions\"\n >\n <button\n type=\"button\"\n part=\"button add-button\"\n ?disabled=${noAvailable || noAvailableSelection}\n @click=${this.addSelected}\n >Add →</button>\n <button\n type=\"button\"\n part=\"button add-all-button\"\n ?disabled=${noAvailable}\n @click=${this.addAll}\n >Add all →</button>\n <button\n type=\"button\"\n part=\"button remove-button\"\n ?disabled=${noSelected || noSelectedSelection}\n @click=${this.removeSelected}\n >← Remove</button>\n <button\n type=\"button\"\n part=\"button clear-button\"\n ?disabled=${noSelected}\n @click=${this.clearSelected}\n >← Clear</button>\n <button\n type=\"button\"\n part=\"button move-up-button\"\n ?disabled=${cannotReorder || noSelectedSelection}\n @click=${this._onMoveUp}\n >Move up</button>\n <button\n type=\"button\"\n part=\"button move-down-button\"\n ?disabled=${cannotReorder || noSelectedSelection}\n @click=${this._onMoveDown}\n >Move down</button>\n </rc-toolbar>\n\n <section\n part=\"panel selected-panel\"\n class=\"rc-transfer-list-panel\"\n aria-labelledby=\"selected-label\"\n data-empty=${noSelected ? '' : nothing}\n data-has-selection=${!noSelectedSelection ? '' : nothing}\n >\n <span part=\"label selected-label\" id=\"selected-label\">${this.selectedLabel}</span>\n <rc-listbox\n id=\"selected-list\"\n part=\"listbox selected-listbox\"\n aria-labelledby=\"selected-label\"\n tabindex=\"0\"\n .options=${selected}\n .multiple=${this.multiple}\n ></rc-listbox>\n </section>\n </div>\n `;\n }\n\n /** Adds the highlighted available options to the selected list. */\n addSelected(): void {\n if (!this._select) return;\n\n const values = new Set(this._$availableList?.selectedValues ?? []);\n if (values.size === 0) return;\n\n this._syncing = true;\n\n for (const opt of Array.from(this._select.options)) {\n if (!opt.selected && values.has(opt.value)) opt.selected = true;\n }\n\n this._syncing = false;\n this._availableSelection = [];\n this.requestUpdate();\n this._dispatchChange();\n }\n\n /** Adds every available option to the selected list. */\n addAll(): void {\n if (!this._select) return;\n\n this._syncing = true;\n for (const opt of Array.from(this._select.options)) opt.selected = true;\n this._syncing = false;\n\n this._availableSelection = [];\n this.requestUpdate();\n this._dispatchChange();\n }\n\n /** Removes the highlighted right-hand options from the selected list. */\n removeSelected(): void {\n if (!this._select) return;\n\n const values = new Set(this._$selectedList?.selectedValues ?? []);\n if (values.size === 0) return;\n\n this._syncing = true;\n\n for (const opt of Array.from(this._select.options)) {\n if (opt.selected && values.has(opt.value)) opt.selected = false;\n }\n\n this._syncing = false;\n this._selectedSelection = [];\n this.requestUpdate();\n this._dispatchChange();\n }\n\n /** Clears the selected/right-hand list. */\n clearSelected(): void {\n if (!this._select) return;\n\n this._syncing = true;\n for (const opt of Array.from(this._select.options)) opt.selected = false;\n this._syncing = false;\n\n this._selectedSelection = [];\n this.requestUpdate();\n this._dispatchChange();\n }\n\n /** Moves highlighted right-hand options by `delta` rows (-1 = up, 1 = down). */\n moveSelected(delta: number): void {\n if (delta === 0 || !this._select) return;\n\n const values = new Set(this._$selectedList?.selectedValues ?? []);\n if (values.size === 0) return;\n\n this._syncing = true;\n this._reorderSelectOptions(values, delta);\n this._syncing = false;\n\n this.requestUpdate();\n this._dispatchChange(values);\n }\n\n private _onMoveUp = (): void => { this.moveSelected(-1); };\n\n private _onMoveDown = (): void => { this.moveSelected(1); };\n\n private _canMoveSelected(\n selected: ListboxOption[],\n selectedValues: Set<string>,\n delta: -1 | 1,\n ): boolean {\n if (selectedValues.size === 0 || selected.length < 2) return false;\n\n return selected.some((item, index) => {\n if (!selectedValues.has(item.value)) return false;\n\n const target = index + delta;\n if (target < 0 || target >= selected.length) return false;\n\n return !selectedValues.has(selected[target].value);\n });\n }\n\n private _onKeydown = (e: KeyboardEvent): void => {\n if (e.altKey) {\n switch (e.key) {\n case 'ArrowRight': e.preventDefault(); this.addSelected(); break;\n case 'ArrowLeft': e.preventDefault(); this.removeSelected(); break;\n case 'ArrowUp': e.preventDefault(); this.moveSelected(-1); break;\n case 'ArrowDown': e.preventDefault(); this.moveSelected(1); break;\n }\n return;\n }\n\n const targetId = (e.target as Element).id;\n\n // APG shortcut: Enter in the available list adds the active item.\n // Restricted to single-select: in multi mode Enter toggles selection in rc-listbox\n // first, so triggering addSelected() here would immediately transfer a single item\n // and discard any multi-item selection the user was building.\n if (targetId === 'available-list' && !this.multiple && e.key === 'Enter') {\n e.preventDefault();\n this.addSelected();\n return;\n }\n\n // APG shortcut: Delete in the selected list removes the highlighted items.\n if (targetId === 'selected-list' && e.key === 'Delete') {\n e.preventDefault();\n this.removeSelected();\n }\n };\n\n private _onListboxChange = (e: Event): void => {\n const ev = e as CustomEvent<RCListboxChangeEvent>;\n const raw = ev.detail.value;\n const values = Array.isArray(raw) ? raw : raw ? [raw] : [];\n const targetId = (e.target as Element | null)?.id;\n if (targetId === 'available-list') this._availableSelection = values;\n else if (targetId === 'selected-list') this._selectedSelection = values;\n };\n\n private _setupSelect(): void {\n const select = this.querySelector<HTMLSelectElement>(':scope > select[multiple]');\n\n if (select === this._select) return;\n\n this._teardownSelect();\n this._select = select;\n\n if (!select) {\n if (import.meta.env.DEV) {\n console.warn(\n '[rc-transfer-list] No direct child <select multiple> found. ' +\n 'Add a <select multiple> child for form participation and progressive enhancement.',\n this,\n );\n }\n return;\n }\n\n // Remove from visual display, AT, and tab order — the rc-listbox UI is the\n // accessible interface; the <select> is only present for form serialisation.\n select.style.display = 'none';\n select.setAttribute('aria-hidden', 'true');\n select.tabIndex = -1;\n\n // Watch for external option additions/removals (attribute-level opt.selected\n // changes via IDL are not observable; use the component API instead).\n this._selectObserver.observe(select, { childList: true });\n\n if (!this._selectedInitialized && this._defaultSelected !== undefined) {\n this._applyDefaultSelected(this._defaultSelected);\n }\n\n this.requestUpdate();\n }\n\n private _teardownSelect(): void {\n if (this._select) {\n this._select.style.display = '';\n this._select.removeAttribute('aria-hidden');\n this._select.removeAttribute('tabindex');\n }\n this._selectObserver.disconnect();\n this._select = null;\n }\n\n /**\n * Reorders selected `<option>` DOM nodes inside the backing `<select>` to\n * preserve user-determined order in form serialisation.\n */\n private _reorderSelectOptions(movedValues: Set<string>, delta: number): void {\n const select = this._select!;\n const opts = Array.from(select.options).filter((o) => o.selected);\n\n const start = delta < 0 ? 1 : opts.length - 2;\n const end = delta < 0 ? opts.length : -1;\n const step = delta < 0 ? 1 : -1;\n\n for (let i = start; i !== end; i += step) {\n const target = i + delta;\n if (!movedValues.has(opts[i].value) || movedValues.has(opts[target].value)) continue;\n\n if (delta < 0) {\n select.insertBefore(opts[i], opts[target]);\n } else {\n opts[target].insertAdjacentElement('afterend', opts[i]);\n }\n }\n }\n\n // Restores selection in the selected listbox after a mutation. Options are\n // set declaratively in render() so only selection state needs imperative sync.\n private _syncSelection(selectedValues: Set<string> = new Set()): void {\n this._$selectedList?.setSelectedValues([...selectedValues]);\n }\n\n private _dispatchChange(selectedValues?: Set<string>): void {\n this.updateComplete.then(() => {\n this._syncSelection(selectedValues);\n\n this.dispatchEvent(\n new CustomEvent<RCTransferListChangeEvent>('rc-transfer-list-change', {\n bubbles: true,\n composed: true,\n detail: { selected: [...this.selected] },\n }),\n );\n });\n }\n}\n\nexport default RCTransferList;\n"],"names":["RCTransferList","LitElement","targetId","raw","values","o","items","selectedValues","opt","item","available","selected","noAvailable","noSelected","cannotReorder","noAvailableSelection","noSelectedSelection","canMoveUp","canMoveDown","html","nothing","delta","index","target","select","movedValues","opts","start","end","step","i","__decorateClass","property","query","state"],"mappings":"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"}
|