@rcarls/rc-transfer-list 0.1.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 +10 -0
- package/dist/custom-elements.json +515 -0
- package/dist/demo.css +85 -0
- package/dist/demo.js +40 -0
- package/dist/rc-transfer-list-DDgVWhv6.js +357 -0
- package/dist/rc-transfer-list-DDgVWhv6.js.map +1 -0
- package/dist/rc-transfer-list-define.js +6 -0
- package/dist/rc-transfer-list-define.js.map +1 -0
- package/dist/rc-transfer-list.js +5 -0
- package/dist/rc-transfer-list.js.map +1 -0
- package/dist/types/packages/rc-transfer-list/src/define.d.ts +1 -0
- package/dist/types/packages/rc-transfer-list/src/index.d.ts +1 -0
- package/dist/types/packages/rc-transfer-list/src/rc-transfer-list.d.ts +108 -0
- package/dist/types/packages/rc-transfer-list/src/rc-transfer-list.test.d.ts +0 -0
- package/package.json +69 -0
package/README.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# @rcarls/rc-transfer-list
|
|
2
|
+
|
|
3
|
+
Side-by-side transfer list web component built from rc-listbox.
|
|
4
|
+
|
|
5
|
+
## Styling Hooks
|
|
6
|
+
|
|
7
|
+
Panels expose `data-empty` when their backing list has no options and
|
|
8
|
+
`data-has-selection` when that panel currently has highlighted rows. The root
|
|
9
|
+
exposes `data-can-move-up` and `data-can-move-down` when the selected panel has
|
|
10
|
+
highlighted rows that can be reordered in that direction.
|
|
@@ -0,0 +1,515 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "1.0.0",
|
|
3
|
+
"readme": "",
|
|
4
|
+
"modules": [
|
|
5
|
+
{
|
|
6
|
+
"kind": "javascript-module",
|
|
7
|
+
"path": "src/define.ts",
|
|
8
|
+
"declarations": [],
|
|
9
|
+
"exports": [
|
|
10
|
+
{
|
|
11
|
+
"kind": "custom-element-definition",
|
|
12
|
+
"name": "rc-transfer-list",
|
|
13
|
+
"declaration": {
|
|
14
|
+
"name": "RCTransferList",
|
|
15
|
+
"module": "/src/index.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"kind": "js",
|
|
20
|
+
"name": "*",
|
|
21
|
+
"declaration": {
|
|
22
|
+
"name": "*",
|
|
23
|
+
"module": "src/index.js"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"kind": "javascript-module",
|
|
30
|
+
"path": "src/index.ts",
|
|
31
|
+
"declarations": [],
|
|
32
|
+
"exports": [
|
|
33
|
+
{
|
|
34
|
+
"kind": "js",
|
|
35
|
+
"name": "*",
|
|
36
|
+
"declaration": {
|
|
37
|
+
"name": "*",
|
|
38
|
+
"module": "src/rc-transfer-list.js"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"kind": "javascript-module",
|
|
45
|
+
"path": "src/rc-transfer-list.ts",
|
|
46
|
+
"declarations": [
|
|
47
|
+
{
|
|
48
|
+
"kind": "class",
|
|
49
|
+
"description": "Side-by-side transfer list built from two `rc-listbox` instances.\n\nRequires a direct child `<select multiple>` element as the single source of\ntruth for option data and form participation. Unselected `<option>` elements\npopulate the available (left) panel; selected ones populate the selected\n(right) panel. Transfers are reflected back to the `<select>` so native form\nsubmission serialises the right-panel values in user-determined order.\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
|
+
"name": "RCTransferList",
|
|
51
|
+
"cssProperties": [
|
|
52
|
+
{
|
|
53
|
+
"description": "Gap between panels and the action toolbar",
|
|
54
|
+
"name": "--rc-transfer-list-gap",
|
|
55
|
+
"default": "var(--rc-control-gap)"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"description": "Gap between a panel label and its listbox",
|
|
59
|
+
"name": "--rc-transfer-list-panel-gap",
|
|
60
|
+
"default": "var(--rc-control-gap)"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"description": "Minimum block size for each listbox",
|
|
64
|
+
"name": "--rc-transfer-list-listbox-min-block-size",
|
|
65
|
+
"default": "10rem"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"description": "Border around each listbox",
|
|
69
|
+
"name": "--rc-transfer-list-listbox-border",
|
|
70
|
+
"default": "var(--rc-border)"
|
|
71
|
+
}
|
|
72
|
+
],
|
|
73
|
+
"cssParts": [
|
|
74
|
+
{
|
|
75
|
+
"description": "Root layout wrapper. Reflects data-can-move-up/down.",
|
|
76
|
+
"name": "root"
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"description": "Shared list panel surface.",
|
|
80
|
+
"name": "panel"
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"description": "Available/left panel. Reflects data-empty and data-has-selection.",
|
|
84
|
+
"name": "available-panel"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"description": "Selected/right panel. Reflects data-empty and data-has-selection.",
|
|
88
|
+
"name": "selected-panel"
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"description": "Transfer action toolbar.",
|
|
92
|
+
"name": "actions"
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"description": "Shared action button surface.",
|
|
96
|
+
"name": "button"
|
|
97
|
+
}
|
|
98
|
+
],
|
|
99
|
+
"members": [
|
|
100
|
+
{
|
|
101
|
+
"kind": "field",
|
|
102
|
+
"name": "multiple",
|
|
103
|
+
"type": {
|
|
104
|
+
"text": "boolean"
|
|
105
|
+
},
|
|
106
|
+
"default": "false",
|
|
107
|
+
"description": "Enable multi-selection in both lists.",
|
|
108
|
+
"attribute": "multiple",
|
|
109
|
+
"reflects": true
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"kind": "field",
|
|
113
|
+
"name": "availableLabel",
|
|
114
|
+
"type": {
|
|
115
|
+
"text": "string"
|
|
116
|
+
},
|
|
117
|
+
"default": "'Available'",
|
|
118
|
+
"description": "Visible label for the available list.",
|
|
119
|
+
"attribute": "available-label"
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"kind": "field",
|
|
123
|
+
"name": "selectedLabel",
|
|
124
|
+
"type": {
|
|
125
|
+
"text": "string"
|
|
126
|
+
},
|
|
127
|
+
"default": "'Selected'",
|
|
128
|
+
"description": "Visible label for the selected list.",
|
|
129
|
+
"attribute": "selected-label"
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
"kind": "field",
|
|
133
|
+
"name": "_$availableList",
|
|
134
|
+
"type": {
|
|
135
|
+
"text": "RCListbox | undefined"
|
|
136
|
+
},
|
|
137
|
+
"privacy": "private"
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
"kind": "field",
|
|
141
|
+
"name": "_$selectedList",
|
|
142
|
+
"type": {
|
|
143
|
+
"text": "RCListbox | undefined"
|
|
144
|
+
},
|
|
145
|
+
"privacy": "private"
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"kind": "field",
|
|
149
|
+
"name": "_availableSelection",
|
|
150
|
+
"type": {
|
|
151
|
+
"text": "string[]"
|
|
152
|
+
},
|
|
153
|
+
"privacy": "private",
|
|
154
|
+
"default": "[]",
|
|
155
|
+
"description": "Values currently highlighted in the available list. Drives the \"Add →\" button disable state."
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
"kind": "field",
|
|
159
|
+
"name": "_selectedSelection",
|
|
160
|
+
"type": {
|
|
161
|
+
"text": "string[]"
|
|
162
|
+
},
|
|
163
|
+
"privacy": "private",
|
|
164
|
+
"default": "[]",
|
|
165
|
+
"description": "Values currently highlighted in the selected list. Drives Remove/reorder button disable states."
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
"kind": "field",
|
|
169
|
+
"name": "_select",
|
|
170
|
+
"type": {
|
|
171
|
+
"text": "HTMLSelectElement | null"
|
|
172
|
+
},
|
|
173
|
+
"privacy": "private",
|
|
174
|
+
"default": "null"
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
"kind": "field",
|
|
178
|
+
"name": "_syncing",
|
|
179
|
+
"type": {
|
|
180
|
+
"text": "boolean"
|
|
181
|
+
},
|
|
182
|
+
"privacy": "private",
|
|
183
|
+
"default": "false",
|
|
184
|
+
"description": "Set while the component mutates the backing <select> to prevent observer feedback loops."
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
"kind": "field",
|
|
188
|
+
"name": "_defaultSelected",
|
|
189
|
+
"type": {
|
|
190
|
+
"text": "ListboxOption[] | undefined"
|
|
191
|
+
},
|
|
192
|
+
"privacy": "private"
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
"kind": "field",
|
|
196
|
+
"name": "_selectedInitialized",
|
|
197
|
+
"type": {
|
|
198
|
+
"text": "boolean"
|
|
199
|
+
},
|
|
200
|
+
"privacy": "private",
|
|
201
|
+
"default": "false"
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
"kind": "field",
|
|
205
|
+
"name": "_hostObserver",
|
|
206
|
+
"privacy": "private",
|
|
207
|
+
"default": "new MutationObserver(() => this._setupSelect())"
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
"kind": "field",
|
|
211
|
+
"name": "_selectObserver",
|
|
212
|
+
"privacy": "private",
|
|
213
|
+
"default": "new MutationObserver(() => { if (!this._syncing) this.requestUpdate(); })"
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
"kind": "field",
|
|
217
|
+
"name": "available",
|
|
218
|
+
"type": {
|
|
219
|
+
"text": "ListboxOption[]"
|
|
220
|
+
},
|
|
221
|
+
"description": "Available/left-hand options derived from unselected `<option>` elements.\n\nSetting this property replaces all unselected options in the backing\n`<select>`. Items whose values already appear in the selected list are\nskipped to prevent duplicate option values."
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
"kind": "field",
|
|
225
|
+
"name": "selected",
|
|
226
|
+
"type": {
|
|
227
|
+
"text": "ListboxOption[]"
|
|
228
|
+
},
|
|
229
|
+
"description": "Selected/right-hand options derived from selected `<option>` elements.\n\nSetting this property replaces all selected options in the backing\n`<select>`. Unselected options are left unchanged."
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
"kind": "field",
|
|
233
|
+
"name": "defaultSelected",
|
|
234
|
+
"type": {
|
|
235
|
+
"text": "ListboxOption[] | undefined"
|
|
236
|
+
},
|
|
237
|
+
"description": "Initial uncontrolled selected list. Applied before any `selected` write from the host."
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
"kind": "method",
|
|
241
|
+
"name": "_applyDefaultSelected",
|
|
242
|
+
"privacy": "private",
|
|
243
|
+
"return": {
|
|
244
|
+
"type": {
|
|
245
|
+
"text": "void"
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
"parameters": [
|
|
249
|
+
{
|
|
250
|
+
"name": "items",
|
|
251
|
+
"type": {
|
|
252
|
+
"text": "ListboxOption[]"
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
]
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
"kind": "method",
|
|
259
|
+
"name": "addSelected",
|
|
260
|
+
"return": {
|
|
261
|
+
"type": {
|
|
262
|
+
"text": "void"
|
|
263
|
+
}
|
|
264
|
+
},
|
|
265
|
+
"description": "Adds the highlighted available options to the selected list."
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
"kind": "method",
|
|
269
|
+
"name": "addAll",
|
|
270
|
+
"return": {
|
|
271
|
+
"type": {
|
|
272
|
+
"text": "void"
|
|
273
|
+
}
|
|
274
|
+
},
|
|
275
|
+
"description": "Adds every available option to the selected list."
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
"kind": "method",
|
|
279
|
+
"name": "removeSelected",
|
|
280
|
+
"return": {
|
|
281
|
+
"type": {
|
|
282
|
+
"text": "void"
|
|
283
|
+
}
|
|
284
|
+
},
|
|
285
|
+
"description": "Removes the highlighted right-hand options from the selected list."
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
"kind": "method",
|
|
289
|
+
"name": "clearSelected",
|
|
290
|
+
"return": {
|
|
291
|
+
"type": {
|
|
292
|
+
"text": "void"
|
|
293
|
+
}
|
|
294
|
+
},
|
|
295
|
+
"description": "Clears the selected/right-hand list."
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
"kind": "method",
|
|
299
|
+
"name": "moveSelected",
|
|
300
|
+
"return": {
|
|
301
|
+
"type": {
|
|
302
|
+
"text": "void"
|
|
303
|
+
}
|
|
304
|
+
},
|
|
305
|
+
"parameters": [
|
|
306
|
+
{
|
|
307
|
+
"name": "delta",
|
|
308
|
+
"type": {
|
|
309
|
+
"text": "number"
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
],
|
|
313
|
+
"description": "Moves highlighted right-hand options by `delta` rows (-1 = up, 1 = down)."
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
"kind": "field",
|
|
317
|
+
"name": "_onMoveUp",
|
|
318
|
+
"privacy": "private"
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
"kind": "field",
|
|
322
|
+
"name": "_onMoveDown",
|
|
323
|
+
"privacy": "private"
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
"kind": "method",
|
|
327
|
+
"name": "_canMoveSelected",
|
|
328
|
+
"privacy": "private",
|
|
329
|
+
"return": {
|
|
330
|
+
"type": {
|
|
331
|
+
"text": "boolean"
|
|
332
|
+
}
|
|
333
|
+
},
|
|
334
|
+
"parameters": [
|
|
335
|
+
{
|
|
336
|
+
"name": "selected",
|
|
337
|
+
"type": {
|
|
338
|
+
"text": "ListboxOption[]"
|
|
339
|
+
}
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
"name": "selectedValues",
|
|
343
|
+
"type": {
|
|
344
|
+
"text": "Set<string>"
|
|
345
|
+
}
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
"name": "delta",
|
|
349
|
+
"type": {
|
|
350
|
+
"text": "-1 | 1"
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
]
|
|
354
|
+
},
|
|
355
|
+
{
|
|
356
|
+
"kind": "field",
|
|
357
|
+
"name": "_onKeydown",
|
|
358
|
+
"privacy": "private"
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
"kind": "field",
|
|
362
|
+
"name": "_onListboxChange",
|
|
363
|
+
"privacy": "private"
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
"kind": "method",
|
|
367
|
+
"name": "_setupSelect",
|
|
368
|
+
"privacy": "private",
|
|
369
|
+
"return": {
|
|
370
|
+
"type": {
|
|
371
|
+
"text": "void"
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
},
|
|
375
|
+
{
|
|
376
|
+
"kind": "method",
|
|
377
|
+
"name": "_teardownSelect",
|
|
378
|
+
"privacy": "private",
|
|
379
|
+
"return": {
|
|
380
|
+
"type": {
|
|
381
|
+
"text": "void"
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
},
|
|
385
|
+
{
|
|
386
|
+
"kind": "method",
|
|
387
|
+
"name": "_reorderSelectOptions",
|
|
388
|
+
"privacy": "private",
|
|
389
|
+
"return": {
|
|
390
|
+
"type": {
|
|
391
|
+
"text": "void"
|
|
392
|
+
}
|
|
393
|
+
},
|
|
394
|
+
"parameters": [
|
|
395
|
+
{
|
|
396
|
+
"name": "movedValues",
|
|
397
|
+
"type": {
|
|
398
|
+
"text": "Set<string>"
|
|
399
|
+
}
|
|
400
|
+
},
|
|
401
|
+
{
|
|
402
|
+
"name": "delta",
|
|
403
|
+
"type": {
|
|
404
|
+
"text": "number"
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
],
|
|
408
|
+
"description": "Reorders selected `<option>` DOM nodes inside the backing `<select>` to\npreserve user-determined order in form serialisation."
|
|
409
|
+
},
|
|
410
|
+
{
|
|
411
|
+
"kind": "method",
|
|
412
|
+
"name": "_syncSelection",
|
|
413
|
+
"privacy": "private",
|
|
414
|
+
"return": {
|
|
415
|
+
"type": {
|
|
416
|
+
"text": "void"
|
|
417
|
+
}
|
|
418
|
+
},
|
|
419
|
+
"parameters": [
|
|
420
|
+
{
|
|
421
|
+
"name": "selectedValues",
|
|
422
|
+
"default": "new Set()",
|
|
423
|
+
"type": {
|
|
424
|
+
"text": "Set<string>"
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
]
|
|
428
|
+
},
|
|
429
|
+
{
|
|
430
|
+
"kind": "method",
|
|
431
|
+
"name": "_dispatchChange",
|
|
432
|
+
"privacy": "private",
|
|
433
|
+
"return": {
|
|
434
|
+
"type": {
|
|
435
|
+
"text": "void"
|
|
436
|
+
}
|
|
437
|
+
},
|
|
438
|
+
"parameters": [
|
|
439
|
+
{
|
|
440
|
+
"name": "selectedValues",
|
|
441
|
+
"optional": true,
|
|
442
|
+
"type": {
|
|
443
|
+
"text": "Set<string>"
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
]
|
|
447
|
+
}
|
|
448
|
+
],
|
|
449
|
+
"events": [
|
|
450
|
+
{
|
|
451
|
+
"name": "rc-transfer-list-change",
|
|
452
|
+
"type": {
|
|
453
|
+
"text": "CustomEvent"
|
|
454
|
+
},
|
|
455
|
+
"description": "Fires when the selected/right-hand list changes."
|
|
456
|
+
}
|
|
457
|
+
],
|
|
458
|
+
"attributes": [
|
|
459
|
+
{
|
|
460
|
+
"name": "multiple",
|
|
461
|
+
"type": {
|
|
462
|
+
"text": "boolean"
|
|
463
|
+
},
|
|
464
|
+
"default": "false",
|
|
465
|
+
"description": "Enable multi-selection in both lists.",
|
|
466
|
+
"fieldName": "multiple"
|
|
467
|
+
},
|
|
468
|
+
{
|
|
469
|
+
"name": "available-label",
|
|
470
|
+
"type": {
|
|
471
|
+
"text": "string"
|
|
472
|
+
},
|
|
473
|
+
"default": "'Available'",
|
|
474
|
+
"description": "Visible label for the available list.",
|
|
475
|
+
"fieldName": "availableLabel"
|
|
476
|
+
},
|
|
477
|
+
{
|
|
478
|
+
"name": "selected-label",
|
|
479
|
+
"type": {
|
|
480
|
+
"text": "string"
|
|
481
|
+
},
|
|
482
|
+
"default": "'Selected'",
|
|
483
|
+
"description": "Visible label for the selected list.",
|
|
484
|
+
"fieldName": "selectedLabel"
|
|
485
|
+
}
|
|
486
|
+
],
|
|
487
|
+
"superclass": {
|
|
488
|
+
"name": "LitElement",
|
|
489
|
+
"package": "lit"
|
|
490
|
+
},
|
|
491
|
+
"tagName": "rc-transfer-list",
|
|
492
|
+
"customElement": true
|
|
493
|
+
}
|
|
494
|
+
],
|
|
495
|
+
"exports": [
|
|
496
|
+
{
|
|
497
|
+
"kind": "js",
|
|
498
|
+
"name": "RCTransferList",
|
|
499
|
+
"declaration": {
|
|
500
|
+
"name": "RCTransferList",
|
|
501
|
+
"module": "src/rc-transfer-list.ts"
|
|
502
|
+
}
|
|
503
|
+
},
|
|
504
|
+
{
|
|
505
|
+
"kind": "js",
|
|
506
|
+
"name": "default",
|
|
507
|
+
"declaration": {
|
|
508
|
+
"name": "RCTransferList",
|
|
509
|
+
"module": "src/rc-transfer-list.ts"
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
]
|
|
513
|
+
}
|
|
514
|
+
]
|
|
515
|
+
}
|
package/dist/demo.css
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
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
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
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
|
+
});
|
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
import "@rcarls/rc-listbox/define";
|
|
2
|
+
import "@rcarls/rc-toolbar/define";
|
|
3
|
+
import { LitElement as _, nothing as c, html as m } from "lit";
|
|
4
|
+
import { property as p, query as b, state as f } from "lit/decorators.js";
|
|
5
|
+
var y = Object.defineProperty, n = (u, e, t, s) => {
|
|
6
|
+
for (var l = void 0, i = u.length - 1, r; i >= 0; i--)
|
|
7
|
+
(r = u[i]) && (l = r(e, t, l) || l);
|
|
8
|
+
return l && y(e, t, l), l;
|
|
9
|
+
};
|
|
10
|
+
class o extends _ {
|
|
11
|
+
constructor() {
|
|
12
|
+
super(...arguments), this.multiple = !1, this.availableLabel = "Available", this.selectedLabel = "Selected", this._availableSelection = [], this._selectedSelection = [], this._select = null, this._syncing = !1, this._selectedInitialized = !1, this._hostObserver = new MutationObserver(() => this._setupSelect()), this._selectObserver = new MutationObserver(() => {
|
|
13
|
+
this._syncing || this.requestUpdate();
|
|
14
|
+
}), this._onMoveUp = () => {
|
|
15
|
+
this.moveSelected(-1);
|
|
16
|
+
}, this._onMoveDown = () => {
|
|
17
|
+
this.moveSelected(1);
|
|
18
|
+
}, this._onKeydown = (e) => {
|
|
19
|
+
if (e.altKey) {
|
|
20
|
+
switch (e.key) {
|
|
21
|
+
case "ArrowRight":
|
|
22
|
+
e.preventDefault(), this.addSelected();
|
|
23
|
+
break;
|
|
24
|
+
case "ArrowLeft":
|
|
25
|
+
e.preventDefault(), this.removeSelected();
|
|
26
|
+
break;
|
|
27
|
+
case "ArrowUp":
|
|
28
|
+
e.preventDefault(), this.moveSelected(-1);
|
|
29
|
+
break;
|
|
30
|
+
case "ArrowDown":
|
|
31
|
+
e.preventDefault(), this.moveSelected(1);
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const t = e.target.id;
|
|
37
|
+
if (t === "available-list" && !this.multiple && e.key === "Enter") {
|
|
38
|
+
e.preventDefault(), this.addSelected();
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
t === "selected-list" && e.key === "Delete" && (e.preventDefault(), this.removeSelected());
|
|
42
|
+
}, this._onListboxChange = (e) => {
|
|
43
|
+
const s = e.detail.value, l = Array.isArray(s) ? s : s ? [s] : [], i = e.target?.id;
|
|
44
|
+
i === "available-list" ? this._availableSelection = l : i === "selected-list" && (this._selectedSelection = l);
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
createRenderRoot() {
|
|
48
|
+
return this;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Available/left-hand options derived from unselected `<option>` elements.
|
|
52
|
+
*
|
|
53
|
+
* Setting this property replaces all unselected options in the backing
|
|
54
|
+
* `<select>`. Items whose values already appear in the selected list are
|
|
55
|
+
* skipped to prevent duplicate option values.
|
|
56
|
+
*/
|
|
57
|
+
get available() {
|
|
58
|
+
return this._select ? Array.from(this._select.options).filter((e) => !e.selected).map((e) => ({ value: e.value, label: e.label || e.text })) : [];
|
|
59
|
+
}
|
|
60
|
+
set available(e) {
|
|
61
|
+
if (!this._select) return;
|
|
62
|
+
this._syncing = !0;
|
|
63
|
+
const t = new Set(
|
|
64
|
+
Array.from(this._select.options).filter((s) => s.selected).map((s) => s.value)
|
|
65
|
+
);
|
|
66
|
+
for (const s of Array.from(this._select.options))
|
|
67
|
+
s.selected || s.remove();
|
|
68
|
+
for (const s of e)
|
|
69
|
+
t.has(s.value) || this._select.add(new Option(s.label, s.value));
|
|
70
|
+
this._syncing = !1, this.requestUpdate();
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Selected/right-hand options derived from selected `<option>` elements.
|
|
74
|
+
*
|
|
75
|
+
* Setting this property replaces all selected options in the backing
|
|
76
|
+
* `<select>`. Unselected options are left unchanged.
|
|
77
|
+
*/
|
|
78
|
+
get selected() {
|
|
79
|
+
return this._select ? Array.from(this._select.options).filter((e) => e.selected).map((e) => ({ value: e.value, label: e.label || e.text })) : [];
|
|
80
|
+
}
|
|
81
|
+
set selected(e) {
|
|
82
|
+
if (this._selectedInitialized = !0, !!this._select) {
|
|
83
|
+
this._syncing = !0;
|
|
84
|
+
for (const t of Array.from(this._select.options))
|
|
85
|
+
t.selected && t.remove();
|
|
86
|
+
for (const t of e)
|
|
87
|
+
this._select.add(new Option(t.label, t.value, !1, !0));
|
|
88
|
+
this._syncing = !1, this.requestUpdate();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/** Initial uncontrolled selected list. Applied before any `selected` write from the host. */
|
|
92
|
+
get defaultSelected() {
|
|
93
|
+
return this._defaultSelected;
|
|
94
|
+
}
|
|
95
|
+
set defaultSelected(e) {
|
|
96
|
+
this._defaultSelected = e, !this._selectedInitialized && this._select && e !== void 0 && this._applyDefaultSelected(e);
|
|
97
|
+
}
|
|
98
|
+
_applyDefaultSelected(e) {
|
|
99
|
+
if (this._select) {
|
|
100
|
+
this._syncing = !0;
|
|
101
|
+
for (const t of Array.from(this._select.options))
|
|
102
|
+
t.selected = e.some((s) => s.value === t.value);
|
|
103
|
+
this._syncing = !1, this.requestUpdate();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
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
|
+
disconnectedCallback() {
|
|
110
|
+
super.disconnectedCallback(), this._hostObserver.disconnect(), this._teardownSelect(), this.removeEventListener("keydown", this._onKeydown), this.removeEventListener("rc-listbox-change", this._onListboxChange);
|
|
111
|
+
}
|
|
112
|
+
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), v = this._canMoveSelected(t, s, 1);
|
|
114
|
+
return m`
|
|
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>
|
|
159
|
+
<div
|
|
160
|
+
part="root"
|
|
161
|
+
class="rc-transfer-list-root"
|
|
162
|
+
data-can-move-up=${d ? "" : c}
|
|
163
|
+
data-can-move-down=${v ? "" : c}
|
|
164
|
+
>
|
|
165
|
+
<section
|
|
166
|
+
part="panel available-panel"
|
|
167
|
+
class="rc-transfer-list-panel"
|
|
168
|
+
aria-labelledby="available-label"
|
|
169
|
+
data-empty=${l ? "" : c}
|
|
170
|
+
data-has-selection=${h ? c : ""}
|
|
171
|
+
>
|
|
172
|
+
<span part="label available-label" id="available-label">${this.availableLabel}</span>
|
|
173
|
+
<rc-listbox
|
|
174
|
+
id="available-list"
|
|
175
|
+
part="listbox available-listbox"
|
|
176
|
+
aria-labelledby="available-label"
|
|
177
|
+
tabindex="0"
|
|
178
|
+
.options=${e}
|
|
179
|
+
.multiple=${this.multiple}
|
|
180
|
+
></rc-listbox>
|
|
181
|
+
</section>
|
|
182
|
+
|
|
183
|
+
<rc-toolbar
|
|
184
|
+
orientation="vertical"
|
|
185
|
+
label="Transfer actions"
|
|
186
|
+
part="actions"
|
|
187
|
+
class="rc-transfer-list-actions"
|
|
188
|
+
>
|
|
189
|
+
<button
|
|
190
|
+
type="button"
|
|
191
|
+
part="button add-button"
|
|
192
|
+
?disabled=${l || h}
|
|
193
|
+
@click=${this.addSelected}
|
|
194
|
+
>Add →</button>
|
|
195
|
+
<button
|
|
196
|
+
type="button"
|
|
197
|
+
part="button add-all-button"
|
|
198
|
+
?disabled=${l}
|
|
199
|
+
@click=${this.addAll}
|
|
200
|
+
>Add all →</button>
|
|
201
|
+
<button
|
|
202
|
+
type="button"
|
|
203
|
+
part="button remove-button"
|
|
204
|
+
?disabled=${i || a}
|
|
205
|
+
@click=${this.removeSelected}
|
|
206
|
+
>← Remove</button>
|
|
207
|
+
<button
|
|
208
|
+
type="button"
|
|
209
|
+
part="button clear-button"
|
|
210
|
+
?disabled=${i}
|
|
211
|
+
@click=${this.clearSelected}
|
|
212
|
+
>← Clear</button>
|
|
213
|
+
<button
|
|
214
|
+
type="button"
|
|
215
|
+
part="button move-up-button"
|
|
216
|
+
?disabled=${r || a}
|
|
217
|
+
@click=${this._onMoveUp}
|
|
218
|
+
>Move up</button>
|
|
219
|
+
<button
|
|
220
|
+
type="button"
|
|
221
|
+
part="button move-down-button"
|
|
222
|
+
?disabled=${r || a}
|
|
223
|
+
@click=${this._onMoveDown}
|
|
224
|
+
>Move down</button>
|
|
225
|
+
</rc-toolbar>
|
|
226
|
+
|
|
227
|
+
<section
|
|
228
|
+
part="panel selected-panel"
|
|
229
|
+
class="rc-transfer-list-panel"
|
|
230
|
+
aria-labelledby="selected-label"
|
|
231
|
+
data-empty=${i ? "" : c}
|
|
232
|
+
data-has-selection=${a ? c : ""}
|
|
233
|
+
>
|
|
234
|
+
<span part="label selected-label" id="selected-label">${this.selectedLabel}</span>
|
|
235
|
+
<rc-listbox
|
|
236
|
+
id="selected-list"
|
|
237
|
+
part="listbox selected-listbox"
|
|
238
|
+
aria-labelledby="selected-label"
|
|
239
|
+
tabindex="0"
|
|
240
|
+
.options=${t}
|
|
241
|
+
.multiple=${this.multiple}
|
|
242
|
+
></rc-listbox>
|
|
243
|
+
</section>
|
|
244
|
+
</div>
|
|
245
|
+
`;
|
|
246
|
+
}
|
|
247
|
+
/** Adds the highlighted available options to the selected list. */
|
|
248
|
+
addSelected() {
|
|
249
|
+
if (!this._select) return;
|
|
250
|
+
const e = new Set(this._$availableList?.selectedValues ?? []);
|
|
251
|
+
if (e.size !== 0) {
|
|
252
|
+
this._syncing = !0;
|
|
253
|
+
for (const t of Array.from(this._select.options))
|
|
254
|
+
!t.selected && e.has(t.value) && (t.selected = !0);
|
|
255
|
+
this._syncing = !1, this._availableSelection = [], this.requestUpdate(), this._dispatchChange();
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
/** Adds every available option to the selected list. */
|
|
259
|
+
addAll() {
|
|
260
|
+
if (this._select) {
|
|
261
|
+
this._syncing = !0;
|
|
262
|
+
for (const e of Array.from(this._select.options)) e.selected = !0;
|
|
263
|
+
this._syncing = !1, this._availableSelection = [], this.requestUpdate(), this._dispatchChange();
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
/** Removes the highlighted right-hand options from the selected list. */
|
|
267
|
+
removeSelected() {
|
|
268
|
+
if (!this._select) return;
|
|
269
|
+
const e = new Set(this._$selectedList?.selectedValues ?? []);
|
|
270
|
+
if (e.size !== 0) {
|
|
271
|
+
this._syncing = !0;
|
|
272
|
+
for (const t of Array.from(this._select.options))
|
|
273
|
+
t.selected && e.has(t.value) && (t.selected = !1);
|
|
274
|
+
this._syncing = !1, this._selectedSelection = [], this.requestUpdate(), this._dispatchChange();
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
/** Clears the selected/right-hand list. */
|
|
278
|
+
clearSelected() {
|
|
279
|
+
if (this._select) {
|
|
280
|
+
this._syncing = !0;
|
|
281
|
+
for (const e of Array.from(this._select.options)) e.selected = !1;
|
|
282
|
+
this._syncing = !1, this._selectedSelection = [], this.requestUpdate(), this._dispatchChange();
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
/** Moves highlighted right-hand options by `delta` rows (-1 = up, 1 = down). */
|
|
286
|
+
moveSelected(e) {
|
|
287
|
+
if (e === 0 || !this._select) return;
|
|
288
|
+
const t = new Set(this._$selectedList?.selectedValues ?? []);
|
|
289
|
+
t.size !== 0 && (this._syncing = !0, this._reorderSelectOptions(t, e), this._syncing = !1, this.requestUpdate(), this._dispatchChange(t));
|
|
290
|
+
}
|
|
291
|
+
_canMoveSelected(e, t, s) {
|
|
292
|
+
return t.size === 0 || e.length < 2 ? !1 : e.some((l, i) => {
|
|
293
|
+
if (!t.has(l.value)) return !1;
|
|
294
|
+
const r = i + s;
|
|
295
|
+
return r < 0 || r >= e.length ? !1 : !t.has(e[r].value);
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
_setupSelect() {
|
|
299
|
+
const e = this.querySelector(":scope > select[multiple]");
|
|
300
|
+
e !== this._select && (this._teardownSelect(), this._select = e, e && (e.style.display = "none", e.setAttribute("aria-hidden", "true"), e.tabIndex = -1, this._selectObserver.observe(e, { childList: !0 }), !this._selectedInitialized && this._defaultSelected !== void 0 && this._applyDefaultSelected(this._defaultSelected), this.requestUpdate()));
|
|
301
|
+
}
|
|
302
|
+
_teardownSelect() {
|
|
303
|
+
this._select && (this._select.style.display = "", this._select.removeAttribute("aria-hidden"), this._select.removeAttribute("tabindex")), this._selectObserver.disconnect(), this._select = null;
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Reorders selected `<option>` DOM nodes inside the backing `<select>` to
|
|
307
|
+
* preserve user-determined order in form serialisation.
|
|
308
|
+
*/
|
|
309
|
+
_reorderSelectOptions(e, t) {
|
|
310
|
+
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
|
+
for (let a = i; a !== r; a += h) {
|
|
312
|
+
const d = a + t;
|
|
313
|
+
!e.has(l[a].value) || e.has(l[d].value) || (t < 0 ? s.insertBefore(l[a], l[d]) : l[d].insertAdjacentElement("afterend", l[a]));
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
// Restores selection in the selected listbox after a mutation. Options are
|
|
317
|
+
// set declaratively in render() so only selection state needs imperative sync.
|
|
318
|
+
_syncSelection(e = /* @__PURE__ */ new Set()) {
|
|
319
|
+
this._$selectedList?.setSelectedValues([...e]);
|
|
320
|
+
}
|
|
321
|
+
_dispatchChange(e) {
|
|
322
|
+
this.updateComplete.then(() => {
|
|
323
|
+
this._syncSelection(e), this.dispatchEvent(
|
|
324
|
+
new CustomEvent("rc-transfer-list-change", {
|
|
325
|
+
bubbles: !0,
|
|
326
|
+
composed: !0,
|
|
327
|
+
detail: { selected: [...this.selected] }
|
|
328
|
+
})
|
|
329
|
+
);
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
n([
|
|
334
|
+
p({ type: Boolean, reflect: !0 })
|
|
335
|
+
], o.prototype, "multiple");
|
|
336
|
+
n([
|
|
337
|
+
p({ attribute: "available-label" })
|
|
338
|
+
], o.prototype, "availableLabel");
|
|
339
|
+
n([
|
|
340
|
+
p({ attribute: "selected-label" })
|
|
341
|
+
], o.prototype, "selectedLabel");
|
|
342
|
+
n([
|
|
343
|
+
b("#available-list")
|
|
344
|
+
], o.prototype, "_$availableList");
|
|
345
|
+
n([
|
|
346
|
+
b("#selected-list")
|
|
347
|
+
], o.prototype, "_$selectedList");
|
|
348
|
+
n([
|
|
349
|
+
f()
|
|
350
|
+
], o.prototype, "_availableSelection");
|
|
351
|
+
n([
|
|
352
|
+
f()
|
|
353
|
+
], o.prototype, "_selectedSelection");
|
|
354
|
+
export {
|
|
355
|
+
o as R
|
|
356
|
+
};
|
|
357
|
+
//# sourceMappingURL=rc-transfer-list-DDgVWhv6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rc-transfer-list-define.js","sources":["../src/define.ts"],"sourcesContent":["import { RCTransferList } from './index.js';\n\ncustomElements.get('rc-transfer-list') || customElements.define('rc-transfer-list', RCTransferList);\n\nexport * from './index.js';\n"],"names":["RCTransferList"],"mappings":";AAEA,eAAe,IAAI,kBAAkB,KAAK,eAAe,OAAO,oBAAoBA,CAAc;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rc-transfer-list.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './index.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './rc-transfer-list.js';
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { LitElement } from 'lit';
|
|
2
|
+
import { ListboxOption } from '@rcarls/rc-listbox';
|
|
3
|
+
export interface RCTransferListChangeEvent {
|
|
4
|
+
/** Ordered selected/right-hand list options. */
|
|
5
|
+
selected: ListboxOption[];
|
|
6
|
+
}
|
|
7
|
+
declare global {
|
|
8
|
+
interface HTMLElementTagNameMap {
|
|
9
|
+
'rc-transfer-list': RCTransferList;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Side-by-side transfer list built from two `rc-listbox` instances.
|
|
14
|
+
*
|
|
15
|
+
* Requires a direct child `<select multiple>` element as the single source of
|
|
16
|
+
* truth for option data and form participation. Unselected `<option>` elements
|
|
17
|
+
* populate the available (left) panel; selected ones populate the selected
|
|
18
|
+
* (right) panel. Transfers are reflected back to the `<select>` so native form
|
|
19
|
+
* submission serialises the right-panel values in user-determined order.
|
|
20
|
+
*
|
|
21
|
+
* The `available` and `selected` JS array properties write through to the
|
|
22
|
+
* backing `<select>`, so the component can also be driven imperatively from a
|
|
23
|
+
* framework without giving up form participation.
|
|
24
|
+
*
|
|
25
|
+
* @fires rc-transfer-list-change - Fires when the selected/right-hand list changes.
|
|
26
|
+
*
|
|
27
|
+
* @cssprop [--rc-transfer-list-gap=var(--rc-control-gap)] - Gap between panels and the action toolbar
|
|
28
|
+
* @cssprop [--rc-transfer-list-panel-gap=var(--rc-control-gap)] - Gap between a panel label and its listbox
|
|
29
|
+
* @cssprop [--rc-transfer-list-listbox-min-block-size=10rem] - Minimum block size for each listbox
|
|
30
|
+
* @cssprop [--rc-transfer-list-listbox-border=var(--rc-border)] - Border around each listbox
|
|
31
|
+
* @csspart root - Root layout wrapper. Reflects data-can-move-up/down.
|
|
32
|
+
* @csspart panel - Shared list panel surface.
|
|
33
|
+
* @csspart available-panel - Available/left panel. Reflects data-empty and data-has-selection.
|
|
34
|
+
* @csspart selected-panel - Selected/right panel. Reflects data-empty and data-has-selection.
|
|
35
|
+
* @csspart actions - Transfer action toolbar.
|
|
36
|
+
* @csspart button - Shared action button surface.
|
|
37
|
+
*/
|
|
38
|
+
export declare class RCTransferList extends LitElement {
|
|
39
|
+
createRenderRoot(): this;
|
|
40
|
+
/** Enable multi-selection in both lists. */
|
|
41
|
+
multiple: boolean;
|
|
42
|
+
/** Visible label for the available list. */
|
|
43
|
+
availableLabel: string;
|
|
44
|
+
/** Visible label for the selected list. */
|
|
45
|
+
selectedLabel: string;
|
|
46
|
+
private _$availableList?;
|
|
47
|
+
private _$selectedList?;
|
|
48
|
+
/** Values currently highlighted in the available list. Drives the "Add →" button disable state. */
|
|
49
|
+
private _availableSelection;
|
|
50
|
+
/** Values currently highlighted in the selected list. Drives Remove/reorder button disable states. */
|
|
51
|
+
private _selectedSelection;
|
|
52
|
+
private _select;
|
|
53
|
+
/** Set while the component mutates the backing <select> to prevent observer feedback loops. */
|
|
54
|
+
private _syncing;
|
|
55
|
+
private _defaultSelected;
|
|
56
|
+
private _selectedInitialized;
|
|
57
|
+
private _hostObserver;
|
|
58
|
+
private _selectObserver;
|
|
59
|
+
/**
|
|
60
|
+
* Available/left-hand options derived from unselected `<option>` elements.
|
|
61
|
+
*
|
|
62
|
+
* Setting this property replaces all unselected options in the backing
|
|
63
|
+
* `<select>`. Items whose values already appear in the selected list are
|
|
64
|
+
* skipped to prevent duplicate option values.
|
|
65
|
+
*/
|
|
66
|
+
get available(): ListboxOption[];
|
|
67
|
+
set available(items: ListboxOption[]);
|
|
68
|
+
/**
|
|
69
|
+
* Selected/right-hand options derived from selected `<option>` elements.
|
|
70
|
+
*
|
|
71
|
+
* Setting this property replaces all selected options in the backing
|
|
72
|
+
* `<select>`. Unselected options are left unchanged.
|
|
73
|
+
*/
|
|
74
|
+
get selected(): ListboxOption[];
|
|
75
|
+
set selected(items: ListboxOption[]);
|
|
76
|
+
/** Initial uncontrolled selected list. Applied before any `selected` write from the host. */
|
|
77
|
+
get defaultSelected(): ListboxOption[] | undefined;
|
|
78
|
+
set defaultSelected(items: ListboxOption[] | undefined);
|
|
79
|
+
private _applyDefaultSelected;
|
|
80
|
+
connectedCallback(): void;
|
|
81
|
+
disconnectedCallback(): void;
|
|
82
|
+
render(): import('lit').TemplateResult<1>;
|
|
83
|
+
/** Adds the highlighted available options to the selected list. */
|
|
84
|
+
addSelected(): void;
|
|
85
|
+
/** Adds every available option to the selected list. */
|
|
86
|
+
addAll(): void;
|
|
87
|
+
/** Removes the highlighted right-hand options from the selected list. */
|
|
88
|
+
removeSelected(): void;
|
|
89
|
+
/** Clears the selected/right-hand list. */
|
|
90
|
+
clearSelected(): void;
|
|
91
|
+
/** Moves highlighted right-hand options by `delta` rows (-1 = up, 1 = down). */
|
|
92
|
+
moveSelected(delta: number): void;
|
|
93
|
+
private _onMoveUp;
|
|
94
|
+
private _onMoveDown;
|
|
95
|
+
private _canMoveSelected;
|
|
96
|
+
private _onKeydown;
|
|
97
|
+
private _onListboxChange;
|
|
98
|
+
private _setupSelect;
|
|
99
|
+
private _teardownSelect;
|
|
100
|
+
/**
|
|
101
|
+
* Reorders selected `<option>` DOM nodes inside the backing `<select>` to
|
|
102
|
+
* preserve user-determined order in form serialisation.
|
|
103
|
+
*/
|
|
104
|
+
private _reorderSelectOptions;
|
|
105
|
+
private _syncSelection;
|
|
106
|
+
private _dispatchChange;
|
|
107
|
+
}
|
|
108
|
+
export default RCTransferList;
|
|
File without changes
|
package/package.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rcarls/rc-transfer-list",
|
|
3
|
+
"publishConfig": {
|
|
4
|
+
"access": "public"
|
|
5
|
+
},
|
|
6
|
+
"version": "0.1.0",
|
|
7
|
+
"description": "Headless WAI-ARIA transfer list web component built with Lit",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/richardcarls/rc-webcomponents.git",
|
|
11
|
+
"directory": "packages/rc-transfer-list"
|
|
12
|
+
},
|
|
13
|
+
"homepage": "https://github.com/richardcarls/rc-webcomponents#readme",
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"type": "module",
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"module": "./dist/rc-transfer-list.js",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"import": {
|
|
23
|
+
"types": "./dist/types/packages/rc-transfer-list/src/index.d.ts",
|
|
24
|
+
"default": "./dist/rc-transfer-list.js"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"./define": {
|
|
28
|
+
"import": {
|
|
29
|
+
"types": "./dist/types/packages/rc-transfer-list/src/define.d.ts",
|
|
30
|
+
"default": "./dist/rc-transfer-list-define.js"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"types": "./dist/types/packages/rc-transfer-list/src/index.d.ts",
|
|
35
|
+
"sideEffects": [
|
|
36
|
+
"./dist/rc-transfer-list-define.js"
|
|
37
|
+
],
|
|
38
|
+
"customElements": "dist/custom-elements.json",
|
|
39
|
+
"scripts": {
|
|
40
|
+
"dev": "vite",
|
|
41
|
+
"build": "tsc && vite build && cem analyze",
|
|
42
|
+
"cem:analyze": "cem analyze",
|
|
43
|
+
"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"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"@rcarls/rc-listbox": "workspace:^",
|
|
51
|
+
"@rcarls/rc-toolbar": "workspace:^"
|
|
52
|
+
},
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"@custom-elements-manifest/analyzer": "0.11.0",
|
|
55
|
+
"@guanghechen/rollup-plugin-copy": "^6.0.9",
|
|
56
|
+
"@vitest/browser-playwright": "4.1.5",
|
|
57
|
+
"lit": "^3.0.0",
|
|
58
|
+
"playwright": "^1.56.0",
|
|
59
|
+
"rollup": "^4.60.2",
|
|
60
|
+
"typescript": "~5.9.3",
|
|
61
|
+
"vite": "^7.1.7",
|
|
62
|
+
"vite-plugin-dts": "^4.5.4",
|
|
63
|
+
"vitest": "^4.0.6",
|
|
64
|
+
"vitest-browser-lit": "^1.0.1"
|
|
65
|
+
},
|
|
66
|
+
"peerDependencies": {
|
|
67
|
+
"lit": "^3.0.0"
|
|
68
|
+
}
|
|
69
|
+
}
|