@rcarls/rc-combobox 0.5.0 → 0.7.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/CHANGELOG.md +307 -0
- package/README.md +76 -24
- package/dist/custom-elements.json +324 -8
- package/dist/rc-combobox-8jDCwAe_.js +371 -0
- package/dist/rc-combobox-8jDCwAe_.js.map +1 -0
- package/dist/rc-combobox-define.js +3 -1
- package/dist/rc-combobox-define.js.map +1 -1
- package/dist/rc-combobox.js +3 -2
- package/dist/types/packages/rc-combobox/src/rc-combobox.d.ts +78 -9
- package/package.json +5 -5
- package/dist/rc-combobox-BfEg1DVi.js +0 -398
- package/dist/rc-combobox-BfEg1DVi.js.map +0 -1
- package/dist/types/packages/rc-combobox/src/rc-combobox.test.d.ts +0 -0
|
@@ -1,14 +1,29 @@
|
|
|
1
|
-
import { RCSelect } from '@rcarls/rc-select';
|
|
1
|
+
import { RCSelect, RCSelectMessages, RCSelectPopupMode } from '@rcarls/rc-select';
|
|
2
2
|
import { FilterStrategy } from '@rcarls/rc-listbox';
|
|
3
3
|
export interface RCComboboxCreateEvent {
|
|
4
4
|
/** The text typed by the user that didn't match any existing option. */
|
|
5
5
|
text: string;
|
|
6
6
|
}
|
|
7
|
+
export type RCComboboxPopupMode = RCSelectPopupMode;
|
|
7
8
|
declare global {
|
|
8
9
|
interface HTMLElementTagNameMap {
|
|
9
10
|
'rc-combobox': RCCombobox;
|
|
10
11
|
}
|
|
11
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* Built-in text of `rc-combobox`: everything `rc-select` has, plus the
|
|
15
|
+
* dialog search label. The "Create" option's text belongs to `rc-listbox`.
|
|
16
|
+
*/
|
|
17
|
+
export interface RCComboboxMessages extends RCSelectMessages {
|
|
18
|
+
/** Visible label of the dialog search input. */
|
|
19
|
+
search: (name: string) => string;
|
|
20
|
+
}
|
|
21
|
+
export declare const DEFAULT_COMBOBOX_MESSAGES: Readonly<RCComboboxMessages>;
|
|
22
|
+
declare module '@rcarls/rc-common' {
|
|
23
|
+
interface RcMessageCatalog {
|
|
24
|
+
'rc-combobox': RCComboboxMessages;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
12
27
|
/**
|
|
13
28
|
* Editable combobox with filtering and optional allow-create behavior, configured from
|
|
14
29
|
* native option data and following the WAI-ARIA Combobox pattern.
|
|
@@ -36,10 +51,29 @@ declare global {
|
|
|
36
51
|
* @csspart input - The text input element.
|
|
37
52
|
* @csspart toggle - The chevron toggle button.
|
|
38
53
|
* @csspart listbox - The `<rc-listbox>` popup element.
|
|
54
|
+
* @csspart dialog - Dialog popup surface.
|
|
55
|
+
* @csspart dialog-header - Dialog title and action row.
|
|
56
|
+
* @csspart dialog-title - Visible dialog title.
|
|
57
|
+
* @csspart dialog-selected - Scrollable selected-chip region.
|
|
58
|
+
* @csspart dialog-search - Dialog search field wrapper.
|
|
59
|
+
* @csspart dialog-input - Dialog search input.
|
|
60
|
+
* @csspart dialog-listbox - Dialog option list.
|
|
61
|
+
* @csspart dialog-actions - Dialog action group.
|
|
62
|
+
* @csspart dialog-confirm - Commits pending dialog selection and closes the dialog.
|
|
63
|
+
* @csspart dialog-cancel - Discards pending dialog selection and closes the dialog.
|
|
64
|
+
*
|
|
65
|
+
* Built-in text follows the element's own `lang`, else `<html lang>`: per
|
|
66
|
+
* element through `messages`, or for every combobox through
|
|
67
|
+
* `registerMessages()` from `@rcarls/rc-common` under `rc-combobox`. Text
|
|
68
|
+
* registered under `rc-select` applies too, below the combobox's own. The
|
|
69
|
+
* "Create" option reads `rc-listbox`.
|
|
39
70
|
*
|
|
40
71
|
* @attr allow-create - When present, shows a "Create 'X'" option for unmatched input.
|
|
72
|
+
* @attr required - Inherited from `rc-select`; mirrors the slotted native `<select>`'s own
|
|
73
|
+
* `required`, for `aria-required` on the input trigger.
|
|
41
74
|
* @attr filter-strategy - How option labels are matched against typed input: `'contains'`
|
|
42
75
|
* (default), `'prefix'`, or a custom predicate set via the `filterStrategy` JS property.
|
|
76
|
+
* @attr popup-mode - Presents options in an anchored `popover` (default) or modal `dialog`.
|
|
43
77
|
*
|
|
44
78
|
* @cssprop [--rc-combobox-max-height=20em] - Maximum popup height.
|
|
45
79
|
* @cssprop [--rc-combobox-control-block-size=var(--rc-control-block-size)] - Anchor block size.
|
|
@@ -48,20 +82,41 @@ declare global {
|
|
|
48
82
|
* @cssprop [--rc-combobox-gap=var(--rc-control-gap)] - Gap between chips, input, and toggle.
|
|
49
83
|
* @cssprop [--rc-combobox-radius=var(--rc-control-radius)] - Anchor border radius.
|
|
50
84
|
* @cssprop [--rc-combobox-border=var(--rc-border)] - Anchor border.
|
|
51
|
-
* @cssprop [--rc-combobox-listbox-radius=var(--rc-
|
|
52
|
-
* @cssprop [--rc-combobox-listbox-
|
|
53
|
-
* @cssprop [--rc-combobox-
|
|
54
|
-
* @cssprop [--rc-combobox-listbox-
|
|
85
|
+
* @cssprop [--rc-combobox-listbox-radius=var(--rc-popup-radius)] - Popup listbox border radius.
|
|
86
|
+
* @cssprop [--rc-combobox-listbox-duration=150ms] - Popup listbox open/close fade transition duration.
|
|
87
|
+
* @cssprop [--rc-combobox-listbox-border=var(--rc-popup-border)] - Popup listbox border.
|
|
88
|
+
* @cssprop [--rc-combobox-listbox-background=var(--rc-popup-background)] - Popup listbox background.
|
|
89
|
+
* @cssprop [--rc-combobox-listbox-color=var(--rc-popup-color)] - Popup listbox text color.
|
|
90
|
+
* @cssprop [--rc-combobox-shadow=var(--rc-popup-shadow)] - Popup listbox box shadow.
|
|
91
|
+
* @cssprop [--rc-combobox-listbox-padding-block=var(--rc-popup-padding-block)] - Popup listbox block padding.
|
|
92
|
+
* @cssprop [--rc-combobox-dialog-input-border=var(--rc-border)] - Dialog search input border.
|
|
93
|
+
* @cssprop [--rc-combobox-dialog-input-radius=var(--rc-control-radius)] - Dialog search input radius.
|
|
94
|
+
* @cssprop [--rc-combobox-dialog-input-background=var(--rc-field)] - Dialog search input background.
|
|
95
|
+
* @cssprop [--rc-combobox-dialog-gap=1rem] - Gap between fullscreen dialog regions.
|
|
96
|
+
* @cssprop [--rc-combobox-dialog-header-gap=0.5rem] - Gap between fullscreen dialog header slots.
|
|
97
|
+
* @cssprop [--rc-combobox-dialog-search-gap=0.25rem] - Gap between the dialog search label and input.
|
|
98
|
+
* @cssprop [--rc-anchor-viewport-inline-size] - Visual-viewport inline space supplied by the anchor controller.
|
|
99
|
+
* @cssprop [--rc-anchor-viewport-block-size] - Visual-viewport block space supplied by the anchor controller.
|
|
55
100
|
* @cssprop [--rc-combobox-chip-radius=var(--rc-radius-md)] - Multi-select chip border radius.
|
|
56
101
|
* @cssprop [--rc-combobox-chip-padding-block=0.1em] - Multi-select chip block-axis padding.
|
|
57
|
-
* @cssprop [--rc-combobox-chip-padding-inline=0.3em] - Multi-select chip
|
|
102
|
+
* @cssprop [--rc-combobox-chip-padding-inline-start=0.3em] - Multi-select chip leading padding.
|
|
103
|
+
* @cssprop [--rc-combobox-chip-padding-inline-end=calc(var(--rc-chip-remove-target-size, 1.5rem) + var(--rc-chip-remove-offset-inline, 0.125rem))] - Multi-select chip trailing padding, including the remove affordance.
|
|
58
104
|
* @cssprop [--rc-combobox-chip-gap=calc(var(--rc-control-gap, 0.25em) * 0.8)] - Gap between chip
|
|
59
|
-
*
|
|
105
|
+
* content items.
|
|
60
106
|
* @cssprop [--rc-combobox-chip-border=var(--rc-border)] - Multi-select chip border.
|
|
107
|
+
* @cssprop [--rc-chip-remove-target-size=1.5rem] - Inherited remove-target width reserved by
|
|
108
|
+
* generated multi-select chips.
|
|
109
|
+
* @cssprop [--rc-chip-remove-offset-inline=0.125rem] - Inherited edge offset reserved by
|
|
110
|
+
* generated multi-select chips.
|
|
111
|
+
* @cssprop [--rc-chip-touch-target-overlap-block-start=0px] - Space returned between wrapped chip rows after a touch target overlaps the field's leading padding.
|
|
112
|
+
* @cssprop [--rc-chip-touch-target-overlap-block-end=0px] - Space returned between wrapped chip rows after a touch target overlaps the field's trailing padding.
|
|
61
113
|
* @cssprop [--rc-combobox-toggle-size=1.1em] - Inline size of the toggle button's icon area.
|
|
62
114
|
*/
|
|
63
115
|
export declare class RCCombobox extends RCSelect {
|
|
64
116
|
static styles: import('lit').CSSResult;
|
|
117
|
+
/** Built-in text overrides; unset keys fall back to registered text, then English. */
|
|
118
|
+
messages: Partial<RCComboboxMessages> | undefined;
|
|
119
|
+
protected get _text(): RCComboboxMessages;
|
|
65
120
|
/** When set, shows a "Create '{text}'" option for text that has no exact match. */
|
|
66
121
|
allowCreate: boolean;
|
|
67
122
|
/**
|
|
@@ -75,15 +130,22 @@ export declare class RCCombobox extends RCSelect {
|
|
|
75
130
|
* Function values are JS-only; string values may be set via the `filter-strategy` attribute.
|
|
76
131
|
*/
|
|
77
132
|
filterStrategy: FilterStrategy;
|
|
78
|
-
protected _$trigger:
|
|
133
|
+
protected _$trigger: HTMLElement;
|
|
134
|
+
private _$dialogInput?;
|
|
79
135
|
private _filterText;
|
|
80
136
|
private _closingPopup;
|
|
137
|
+
private _provisionalOptions;
|
|
138
|
+
private _preDialogOptions;
|
|
139
|
+
private get _$filterInput();
|
|
140
|
+
protected get _$activeDescendantHost(): HTMLElement | null;
|
|
81
141
|
openPopup(): void;
|
|
82
142
|
closePopup(_returnFocus?: boolean): void;
|
|
83
143
|
private _handleInput;
|
|
84
144
|
private _handleInputFocus;
|
|
85
145
|
private _handleToggleClick;
|
|
86
146
|
private _handleAnchorClick;
|
|
147
|
+
private _handleDialogAnchorClick;
|
|
148
|
+
private _handleDialogTriggerKeyDown;
|
|
87
149
|
private _updateCreateOption;
|
|
88
150
|
protected _handleListboxChange(e: CustomEvent): void;
|
|
89
151
|
private _activateCreate;
|
|
@@ -93,6 +155,13 @@ export declare class RCCombobox extends RCSelect {
|
|
|
93
155
|
private _handleInputKeyDown;
|
|
94
156
|
private _focusLastChipRemove;
|
|
95
157
|
private get _inputPlaceholder();
|
|
96
|
-
protected
|
|
158
|
+
protected _syncAccessibleName($select: HTMLSelectElement): void;
|
|
159
|
+
protected _focusDialogContent(): void;
|
|
160
|
+
protected _prepareDialogCommit(): void;
|
|
161
|
+
protected _commitDialogSelection(): void;
|
|
162
|
+
protected _discardDialogSelection(): void;
|
|
163
|
+
protected _finishDialogClose(returnFocus: boolean): void;
|
|
164
|
+
protected _renderDialogBody(): import('lit-html').TemplateResult<1>;
|
|
165
|
+
protected render(): import('lit-html').TemplateResult<1>;
|
|
97
166
|
}
|
|
98
167
|
export default RCCombobox;
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.7.0",
|
|
7
7
|
"description": "Editable combobox with filtering and optional allow-create behavior, configured from native option data.",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
@@ -45,9 +45,10 @@
|
|
|
45
45
|
"test:browser:firefox": "vitest --run --project=firefox"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@rcarls/rc-
|
|
49
|
-
"@rcarls/rc-
|
|
50
|
-
"@rcarls/rc-
|
|
48
|
+
"@rcarls/rc-chip-group": "0.7.0",
|
|
49
|
+
"@rcarls/rc-common": "0.7.0",
|
|
50
|
+
"@rcarls/rc-listbox": "0.7.0",
|
|
51
|
+
"@rcarls/rc-select": "0.7.0"
|
|
51
52
|
},
|
|
52
53
|
"devDependencies": {
|
|
53
54
|
"@custom-elements-manifest/analyzer": "0.11.0",
|
|
@@ -58,7 +59,6 @@
|
|
|
58
59
|
"typescript": "~5.9.3",
|
|
59
60
|
"vite": "^7.1.7",
|
|
60
61
|
"vite-plugin-dts": "^4.5.4",
|
|
61
|
-
"vite-plugin-static-copy": "^4.1.0",
|
|
62
62
|
"vitest": "^4.0.6",
|
|
63
63
|
"vitest-browser-lit": "^1.0.1"
|
|
64
64
|
},
|
|
@@ -1,398 +0,0 @@
|
|
|
1
|
-
import { css as p, nothing as d, html as u } from "lit";
|
|
2
|
-
import { property as h, query as b, state as g } from "lit/decorators.js";
|
|
3
|
-
import { RCSelect as v } from "@rcarls/rc-select";
|
|
4
|
-
const f = p`
|
|
5
|
-
:host {
|
|
6
|
-
display: inline-block;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
#anchor {
|
|
10
|
-
display: flex;
|
|
11
|
-
align-items: center;
|
|
12
|
-
flex-wrap: wrap;
|
|
13
|
-
gap: var(--rc-combobox-gap, var(--rc-control-gap, 0.25em));
|
|
14
|
-
min-block-size: var(--rc-combobox-control-block-size, var(--rc-control-block-size, auto));
|
|
15
|
-
padding: var(--rc-combobox-padding-block, var(--rc-control-padding-block, 1px))
|
|
16
|
-
var(--rc-combobox-padding-inline, var(--rc-control-padding-inline, 4px));
|
|
17
|
-
min-width: 8em;
|
|
18
|
-
cursor: text;
|
|
19
|
-
border: var(
|
|
20
|
-
--rc-combobox-border,
|
|
21
|
-
var(--rc-border, 1px solid var(--rc-border-color, ButtonBorder))
|
|
22
|
-
);
|
|
23
|
-
border-radius: var(
|
|
24
|
-
--rc-combobox-radius,
|
|
25
|
-
var(--rc-control-radius, var(--rc-radius-sm, 0.125em))
|
|
26
|
-
);
|
|
27
|
-
background: var(--rc-field, Field);
|
|
28
|
-
color: var(--rc-field-text, FieldText);
|
|
29
|
-
font-family: var(--rc-font-family, inherit);
|
|
30
|
-
font-size: var(--rc-font-size, inherit);
|
|
31
|
-
line-height: var(--rc-line-height, normal);
|
|
32
|
-
transition:
|
|
33
|
-
background-color var(--rc-motion-duration, 120ms),
|
|
34
|
-
border-color var(--rc-motion-duration, 120ms),
|
|
35
|
-
box-shadow var(--rc-motion-duration, 120ms);
|
|
36
|
-
|
|
37
|
-
/* Focus ring — anchor shows the ring when the internal input is focused */
|
|
38
|
-
outline: none;
|
|
39
|
-
&:focus-within {
|
|
40
|
-
outline: var(--rc-focus-ring, auto);
|
|
41
|
-
outline-offset: var(--rc-focus-ring-offset, 0);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/* Chips — the whole chip is the remove button for a larger touch target */
|
|
46
|
-
[part='chip'] {
|
|
47
|
-
display: inline-flex;
|
|
48
|
-
align-items: center;
|
|
49
|
-
gap: var(--rc-combobox-chip-gap, calc(var(--rc-control-gap, 0.25em) * 0.8));
|
|
50
|
-
padding: var(--rc-combobox-chip-padding-block, 0.1em)
|
|
51
|
-
var(--rc-combobox-chip-padding-inline, 0.3em);
|
|
52
|
-
border: var(
|
|
53
|
-
--rc-combobox-chip-border,
|
|
54
|
-
var(--rc-border, 1px solid var(--rc-border-color, ButtonBorder))
|
|
55
|
-
);
|
|
56
|
-
border-radius: var(--rc-combobox-chip-radius, var(--rc-radius-md, 0.25em));
|
|
57
|
-
background: var(--rc-button-bg, ButtonFace);
|
|
58
|
-
color: var(--rc-button-text, ButtonText);
|
|
59
|
-
font: inherit;
|
|
60
|
-
font-size: 0.875em;
|
|
61
|
-
cursor: pointer;
|
|
62
|
-
|
|
63
|
-
&:hover {
|
|
64
|
-
background: var(--rc-highlight, Highlight);
|
|
65
|
-
color: var(--rc-highlight-text, HighlightText);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
&:focus-visible {
|
|
69
|
-
outline: var(--rc-focus-ring, auto);
|
|
70
|
-
outline-offset: var(--rc-focus-ring-offset, 0);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/* Decorative × icon inside the chip — no interaction, aria-hidden */
|
|
75
|
-
[part='chip-remove'] {
|
|
76
|
-
display: inline-flex;
|
|
77
|
-
align-items: center;
|
|
78
|
-
justify-content: center;
|
|
79
|
-
width: 1em;
|
|
80
|
-
font-size: 0.85em;
|
|
81
|
-
pointer-events: none;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
#trigger {
|
|
85
|
-
flex: 1;
|
|
86
|
-
min-width: 0;
|
|
87
|
-
border: none;
|
|
88
|
-
background: transparent;
|
|
89
|
-
color: inherit;
|
|
90
|
-
font: inherit;
|
|
91
|
-
outline: none;
|
|
92
|
-
padding: 0;
|
|
93
|
-
cursor: text;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
#trigger::placeholder {
|
|
97
|
-
color: var(--rc-text-disabled, GrayText);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
#toggle {
|
|
101
|
-
flex-shrink: 0;
|
|
102
|
-
display: inline-flex;
|
|
103
|
-
align-items: center;
|
|
104
|
-
justify-content: center;
|
|
105
|
-
inline-size: var(--rc-combobox-toggle-size, 1.1em);
|
|
106
|
-
border: none;
|
|
107
|
-
background: transparent;
|
|
108
|
-
color: inherit;
|
|
109
|
-
cursor: default;
|
|
110
|
-
font: inherit;
|
|
111
|
-
|
|
112
|
-
&:focus-visible {
|
|
113
|
-
outline: var(--rc-focus-ring, auto);
|
|
114
|
-
outline-offset: var(--rc-focus-ring-offset, 0);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/* Hide the default slot — visually suppresses the slotted native <select> */
|
|
119
|
-
slot:not([name]) {
|
|
120
|
-
display: none;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/* Listbox popup — positioned by AnchorController via adoptedStyleSheets */
|
|
124
|
-
rc-listbox {
|
|
125
|
-
max-height: var(--rc-combobox-max-height, 20em);
|
|
126
|
-
overflow-y: auto;
|
|
127
|
-
background: var(--rc-surface, Canvas);
|
|
128
|
-
border: var(
|
|
129
|
-
--rc-combobox-listbox-border,
|
|
130
|
-
var(--rc-border, 1px solid var(--rc-border-color, ButtonBorder))
|
|
131
|
-
);
|
|
132
|
-
border-radius: var(--rc-combobox-listbox-radius, var(--rc-control-radius, 0));
|
|
133
|
-
box-shadow: var(
|
|
134
|
-
--rc-combobox-shadow,
|
|
135
|
-
var(--rc-shadow, 0 2px 8px color-mix(in srgb, CanvasText 15%, transparent))
|
|
136
|
-
);
|
|
137
|
-
color: var(--rc-field-text, FieldText);
|
|
138
|
-
padding-block: var(
|
|
139
|
-
--rc-combobox-listbox-padding-block,
|
|
140
|
-
var(--rc-control-padding-block, 0.25em)
|
|
141
|
-
);
|
|
142
|
-
--rc-listbox-option-gap: var(--rc-item-gap, 0.4em);
|
|
143
|
-
--rc-listbox-option-padding-block: var(--rc-item-padding-block, 0.3em);
|
|
144
|
-
--rc-listbox-option-padding-inline: var(--rc-item-padding-inline, 0.75em);
|
|
145
|
-
--rc-listbox-hover-bg: var(--rc-highlight, Highlight);
|
|
146
|
-
--rc-listbox-hover-color: var(--rc-highlight-text, HighlightText);
|
|
147
|
-
--rc-listbox-active-bg: var(--rc-highlight, Highlight);
|
|
148
|
-
--rc-listbox-active-color: var(--rc-highlight-text, HighlightText);
|
|
149
|
-
--rc-listbox-selected-bg: var(--rc-highlight, Highlight);
|
|
150
|
-
--rc-listbox-selected-color: var(--rc-highlight-text, HighlightText);
|
|
151
|
-
--rc-listbox-disabled-opacity: var(--rc-disabled-opacity, 0.5);
|
|
152
|
-
|
|
153
|
-
&:not(:popover-open) {
|
|
154
|
-
display: none;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
rc-listbox [part~='option'][hidden] {
|
|
159
|
-
display: none;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
rc-listbox [part~='option'][data-active]:not([aria-disabled='true']) {
|
|
163
|
-
outline: var(--rc-focus-ring, 2px solid var(--rc-accent, Highlight));
|
|
164
|
-
outline-offset: -2px;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
rc-listbox [part~='option'][aria-disabled='true'] {
|
|
168
|
-
cursor: not-allowed;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
rc-listbox [part~='option-checkmark'] {
|
|
172
|
-
flex-shrink: 0;
|
|
173
|
-
width: 1em;
|
|
174
|
-
text-align: center;
|
|
175
|
-
font-size: 0.85em;
|
|
176
|
-
visibility: hidden;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
rc-listbox [part~='option'][aria-selected='true'] [part~='option-checkmark'] {
|
|
180
|
-
visibility: visible;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
rc-listbox [part~='create-option'] {
|
|
184
|
-
font-style: italic;
|
|
185
|
-
border-top: 1px solid var(--rc-border-color, ButtonBorder);
|
|
186
|
-
margin-top: 0.25em;
|
|
187
|
-
padding-top: 0.3em;
|
|
188
|
-
}
|
|
189
|
-
`;
|
|
190
|
-
var x = Object.defineProperty, o = (n, t, e, a) => {
|
|
191
|
-
for (var i = void 0, s = n.length - 1, c; s >= 0; s--)
|
|
192
|
-
(c = n[s]) && (i = c(t, e, i) || i);
|
|
193
|
-
return i && x(t, e, i), i;
|
|
194
|
-
};
|
|
195
|
-
const l = class l extends v {
|
|
196
|
-
constructor() {
|
|
197
|
-
super(...arguments), this.allowCreate = !1, this.filterStrategy = "contains", this._filterText = "", this._closingPopup = !1;
|
|
198
|
-
}
|
|
199
|
-
openPopup() {
|
|
200
|
-
super.openPopup(), this._$listbox?.filterOptions(this._filterText);
|
|
201
|
-
}
|
|
202
|
-
closePopup(t = !0) {
|
|
203
|
-
this._filterText = "", this._$listbox?.clearFilter(), this._$listbox?.setCreateOption(null), this._closingPopup = !0, super.closePopup(!1), setTimeout(() => {
|
|
204
|
-
this._closingPopup = !1;
|
|
205
|
-
}, 0);
|
|
206
|
-
}
|
|
207
|
-
_handleInput(t) {
|
|
208
|
-
this._filterText = t.target.value, !this.open && this._filterText && this.openPopup(), this._$listbox?.filterOptions(this._filterText), this._updateCreateOption(), this._$listbox?.navigableItems.length ? this._activeDescendantCtrl.navigateToFirst() : this._activeDescendantCtrl.clear();
|
|
209
|
-
}
|
|
210
|
-
_handleInputFocus() {
|
|
211
|
-
!this.open && !this._closingPopup && this.openPopup();
|
|
212
|
-
}
|
|
213
|
-
_handleToggleClick(t) {
|
|
214
|
-
t.stopPropagation(), this.open ? this.closePopup() : (this.openPopup(), this._$trigger?.focus());
|
|
215
|
-
}
|
|
216
|
-
_handleAnchorClick(t) {
|
|
217
|
-
const e = t.target;
|
|
218
|
-
e.closest('[part~="chip"]') || e.id === "toggle" || this._$trigger?.focus();
|
|
219
|
-
}
|
|
220
|
-
_updateCreateOption() {
|
|
221
|
-
if (!this.allowCreate || !this._filterText.trim()) {
|
|
222
|
-
this._$listbox?.setCreateOption(null);
|
|
223
|
-
return;
|
|
224
|
-
}
|
|
225
|
-
const t = this._filterText.trim().toLowerCase(), e = this._$listbox?.allOptions.some((a) => a.label.toLowerCase() === t) ?? !1;
|
|
226
|
-
this._$listbox?.setCreateOption(e ? null : this._filterText.trim());
|
|
227
|
-
}
|
|
228
|
-
_handleListboxChange(t) {
|
|
229
|
-
const e = t.detail;
|
|
230
|
-
if (e.reason === "action" && e.action === "create") {
|
|
231
|
-
t.stopPropagation(), this._activateCreate(this._filterText.trim());
|
|
232
|
-
return;
|
|
233
|
-
}
|
|
234
|
-
super._handleListboxChange(t), this.multiple ? (this._filterText = "", this._$trigger && (this._$trigger.value = ""), this._$listbox?.clearFilter(), this._updateCreateOption()) : this._syncInputToSelection();
|
|
235
|
-
}
|
|
236
|
-
async _activateCreate(t) {
|
|
237
|
-
if (!t)
|
|
238
|
-
return;
|
|
239
|
-
const e = new CustomEvent("rc-combobox-create", {
|
|
240
|
-
bubbles: !0,
|
|
241
|
-
composed: !0,
|
|
242
|
-
cancelable: !0,
|
|
243
|
-
detail: { text: t }
|
|
244
|
-
});
|
|
245
|
-
if (this.dispatchEvent(e)) {
|
|
246
|
-
if (this._addOption({ value: t, label: t }), this.multiple) {
|
|
247
|
-
this._$listbox?.toggleOption(t), this._filterText = "", this._$trigger && (this._$trigger.value = ""), this._$listbox?.clearFilter(), this._$listbox?.setCreateOption(null);
|
|
248
|
-
return;
|
|
249
|
-
}
|
|
250
|
-
this._applySelection([t]), this._syncInputToSelection(), this.closePopup(!0), this._dispatchChange();
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
set value(t) {
|
|
254
|
-
super.value = t, this._syncInputToSelection();
|
|
255
|
-
}
|
|
256
|
-
get value() {
|
|
257
|
-
return super.value;
|
|
258
|
-
}
|
|
259
|
-
_syncInputToSelection() {
|
|
260
|
-
if (this.multiple)
|
|
261
|
-
return;
|
|
262
|
-
const t = this.selectedValues[0], e = t ? this._labelFor(t) : "";
|
|
263
|
-
this._filterText = e, this._$trigger && (this._$trigger.value = e);
|
|
264
|
-
}
|
|
265
|
-
_handleInputKeyDown(t) {
|
|
266
|
-
switch (t.key) {
|
|
267
|
-
case "ArrowDown":
|
|
268
|
-
t.preventDefault(), this.open ? this._activeDescendantCtrl.navigate(1) : (this.openPopup(), this._activeDescendantCtrl.navigateToFirst());
|
|
269
|
-
break;
|
|
270
|
-
case "ArrowUp":
|
|
271
|
-
t.preventDefault(), this.open && this._activeDescendantCtrl.navigate(-1);
|
|
272
|
-
break;
|
|
273
|
-
case "Home":
|
|
274
|
-
this.open && (t.preventDefault(), this._activeDescendantCtrl.navigateToFirst());
|
|
275
|
-
break;
|
|
276
|
-
case "End":
|
|
277
|
-
this.open && (t.preventDefault(), this._activeDescendantCtrl.navigateToLast());
|
|
278
|
-
break;
|
|
279
|
-
case "Enter": {
|
|
280
|
-
t.preventDefault();
|
|
281
|
-
const e = this._activeDescendantCtrl.activeItem;
|
|
282
|
-
e ? e.dispatchEvent(
|
|
283
|
-
new PointerEvent("pointerdown", { bubbles: !0, cancelable: !0 })
|
|
284
|
-
) : this.open && this._$listbox?.navigableItems.length && this._$listbox.navigableItems[0]?.dispatchEvent(
|
|
285
|
-
new PointerEvent("pointerdown", { bubbles: !0, cancelable: !0 })
|
|
286
|
-
);
|
|
287
|
-
break;
|
|
288
|
-
}
|
|
289
|
-
case "Tab":
|
|
290
|
-
if (this.open) {
|
|
291
|
-
const e = this._$listbox?.navigableItems[0];
|
|
292
|
-
e && e.dispatchEvent(
|
|
293
|
-
new PointerEvent("pointerdown", { bubbles: !0, cancelable: !0 })
|
|
294
|
-
), this.closePopup(!1);
|
|
295
|
-
}
|
|
296
|
-
break;
|
|
297
|
-
case "Escape":
|
|
298
|
-
t.preventDefault(), this._filterText = "", this._$trigger && (this._$trigger.value = ""), this.closePopup();
|
|
299
|
-
break;
|
|
300
|
-
case "Backspace":
|
|
301
|
-
this._filterText === "" && this.multiple && this._selectedValues.size > 0 && (t.preventDefault(), this._focusLastChipRemove());
|
|
302
|
-
break;
|
|
303
|
-
case "ArrowLeft":
|
|
304
|
-
t.target.selectionStart === 0 && this.multiple && this._selectedValues.size > 0 && (t.preventDefault(), this._focusLastChipRemove());
|
|
305
|
-
break;
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
_focusLastChipRemove() {
|
|
309
|
-
const t = Array.from(
|
|
310
|
-
this.renderRoot.querySelectorAll('button[part~="chip"]')
|
|
311
|
-
);
|
|
312
|
-
t[t.length - 1]?.focus();
|
|
313
|
-
}
|
|
314
|
-
get _inputPlaceholder() {
|
|
315
|
-
return this.multiple && this._selectedValues.size > 0 ? "" : this.placeholder;
|
|
316
|
-
}
|
|
317
|
-
render() {
|
|
318
|
-
const t = this.multiple && this._selectedValues.size > 0;
|
|
319
|
-
return u`
|
|
320
|
-
<div id="anchor" part="anchor" @click=${this._handleAnchorClick}>
|
|
321
|
-
${t ? this._renderChips() : d}
|
|
322
|
-
|
|
323
|
-
<input
|
|
324
|
-
id="trigger"
|
|
325
|
-
part="input"
|
|
326
|
-
type="text"
|
|
327
|
-
role="combobox"
|
|
328
|
-
aria-haspopup="listbox"
|
|
329
|
-
aria-expanded=${this.open ? "true" : "false"}
|
|
330
|
-
aria-controls="listbox"
|
|
331
|
-
aria-autocomplete="list"
|
|
332
|
-
?disabled=${this.disabled}
|
|
333
|
-
placeholder=${this._inputPlaceholder}
|
|
334
|
-
.value=${this._filterText}
|
|
335
|
-
autocomplete="off"
|
|
336
|
-
spellcheck="false"
|
|
337
|
-
@input=${this._handleInput}
|
|
338
|
-
@keydown=${this._handleInputKeyDown}
|
|
339
|
-
@focus=${this._handleInputFocus}
|
|
340
|
-
/>
|
|
341
|
-
|
|
342
|
-
<button
|
|
343
|
-
id="toggle"
|
|
344
|
-
type="button"
|
|
345
|
-
part="toggle"
|
|
346
|
-
aria-hidden="true"
|
|
347
|
-
tabindex="-1"
|
|
348
|
-
@click=${this._handleToggleClick}
|
|
349
|
-
>
|
|
350
|
-
<slot name="toggle-icon">
|
|
351
|
-
<svg
|
|
352
|
-
width="10"
|
|
353
|
-
height="6"
|
|
354
|
-
viewBox="0 0 10 6"
|
|
355
|
-
fill="none"
|
|
356
|
-
stroke="currentColor"
|
|
357
|
-
stroke-width="1.5"
|
|
358
|
-
stroke-linecap="round"
|
|
359
|
-
stroke-linejoin="round"
|
|
360
|
-
>
|
|
361
|
-
<polyline points="1,1 5,5 9,1" />
|
|
362
|
-
</svg>
|
|
363
|
-
</slot>
|
|
364
|
-
</button>
|
|
365
|
-
</div>
|
|
366
|
-
|
|
367
|
-
<rc-listbox
|
|
368
|
-
id="listbox"
|
|
369
|
-
part="listbox"
|
|
370
|
-
popover="manual"
|
|
371
|
-
?multiple=${this.multiple}
|
|
372
|
-
checkmark
|
|
373
|
-
.filterStrategy=${this.filterStrategy}
|
|
374
|
-
@rc-listbox-change=${this._handleListboxChange}
|
|
375
|
-
></rc-listbox>
|
|
376
|
-
|
|
377
|
-
<slot @slotchange=${this._handleSelectSlotChange}></slot>
|
|
378
|
-
`;
|
|
379
|
-
}
|
|
380
|
-
};
|
|
381
|
-
l.styles = f;
|
|
382
|
-
let r = l;
|
|
383
|
-
o([
|
|
384
|
-
h({ type: Boolean, attribute: "allow-create" })
|
|
385
|
-
], r.prototype, "allowCreate");
|
|
386
|
-
o([
|
|
387
|
-
h({ attribute: "filter-strategy", reflect: !1 })
|
|
388
|
-
], r.prototype, "filterStrategy");
|
|
389
|
-
o([
|
|
390
|
-
b("#trigger")
|
|
391
|
-
], r.prototype, "_$trigger");
|
|
392
|
-
o([
|
|
393
|
-
g()
|
|
394
|
-
], r.prototype, "_filterText");
|
|
395
|
-
export {
|
|
396
|
-
r as R
|
|
397
|
-
};
|
|
398
|
-
//# sourceMappingURL=rc-combobox-BfEg1DVi.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"rc-combobox-BfEg1DVi.js","sources":["../src/rc-combobox.styles.ts","../src/rc-combobox.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const comboboxStyles = css`\n :host {\n display: inline-block;\n }\n\n #anchor {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: var(--rc-combobox-gap, var(--rc-control-gap, 0.25em));\n min-block-size: var(--rc-combobox-control-block-size, var(--rc-control-block-size, auto));\n padding: var(--rc-combobox-padding-block, var(--rc-control-padding-block, 1px))\n var(--rc-combobox-padding-inline, var(--rc-control-padding-inline, 4px));\n min-width: 8em;\n cursor: text;\n border: var(\n --rc-combobox-border,\n var(--rc-border, 1px solid var(--rc-border-color, ButtonBorder))\n );\n border-radius: var(\n --rc-combobox-radius,\n var(--rc-control-radius, var(--rc-radius-sm, 0.125em))\n );\n background: var(--rc-field, Field);\n color: var(--rc-field-text, FieldText);\n font-family: var(--rc-font-family, inherit);\n font-size: var(--rc-font-size, inherit);\n line-height: var(--rc-line-height, normal);\n transition:\n background-color var(--rc-motion-duration, 120ms),\n border-color var(--rc-motion-duration, 120ms),\n box-shadow var(--rc-motion-duration, 120ms);\n\n /* Focus ring — anchor shows the ring when the internal input is focused */\n outline: none;\n &:focus-within {\n outline: var(--rc-focus-ring, auto);\n outline-offset: var(--rc-focus-ring-offset, 0);\n }\n }\n\n /* Chips — the whole chip is the remove button for a larger touch target */\n [part='chip'] {\n display: inline-flex;\n align-items: center;\n gap: var(--rc-combobox-chip-gap, calc(var(--rc-control-gap, 0.25em) * 0.8));\n padding: var(--rc-combobox-chip-padding-block, 0.1em)\n var(--rc-combobox-chip-padding-inline, 0.3em);\n border: var(\n --rc-combobox-chip-border,\n var(--rc-border, 1px solid var(--rc-border-color, ButtonBorder))\n );\n border-radius: var(--rc-combobox-chip-radius, var(--rc-radius-md, 0.25em));\n background: var(--rc-button-bg, ButtonFace);\n color: var(--rc-button-text, ButtonText);\n font: inherit;\n font-size: 0.875em;\n cursor: pointer;\n\n &:hover {\n background: var(--rc-highlight, Highlight);\n color: var(--rc-highlight-text, HighlightText);\n }\n\n &:focus-visible {\n outline: var(--rc-focus-ring, auto);\n outline-offset: var(--rc-focus-ring-offset, 0);\n }\n }\n\n /* Decorative × icon inside the chip — no interaction, aria-hidden */\n [part='chip-remove'] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1em;\n font-size: 0.85em;\n pointer-events: none;\n }\n\n #trigger {\n flex: 1;\n min-width: 0;\n border: none;\n background: transparent;\n color: inherit;\n font: inherit;\n outline: none;\n padding: 0;\n cursor: text;\n }\n\n #trigger::placeholder {\n color: var(--rc-text-disabled, GrayText);\n }\n\n #toggle {\n flex-shrink: 0;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n inline-size: var(--rc-combobox-toggle-size, 1.1em);\n border: none;\n background: transparent;\n color: inherit;\n cursor: default;\n font: inherit;\n\n &:focus-visible {\n outline: var(--rc-focus-ring, auto);\n outline-offset: var(--rc-focus-ring-offset, 0);\n }\n }\n\n /* Hide the default slot — visually suppresses the slotted native <select> */\n slot:not([name]) {\n display: none;\n }\n\n /* Listbox popup — positioned by AnchorController via adoptedStyleSheets */\n rc-listbox {\n max-height: var(--rc-combobox-max-height, 20em);\n overflow-y: auto;\n background: var(--rc-surface, Canvas);\n border: var(\n --rc-combobox-listbox-border,\n var(--rc-border, 1px solid var(--rc-border-color, ButtonBorder))\n );\n border-radius: var(--rc-combobox-listbox-radius, var(--rc-control-radius, 0));\n box-shadow: var(\n --rc-combobox-shadow,\n var(--rc-shadow, 0 2px 8px color-mix(in srgb, CanvasText 15%, transparent))\n );\n color: var(--rc-field-text, FieldText);\n padding-block: var(\n --rc-combobox-listbox-padding-block,\n var(--rc-control-padding-block, 0.25em)\n );\n --rc-listbox-option-gap: var(--rc-item-gap, 0.4em);\n --rc-listbox-option-padding-block: var(--rc-item-padding-block, 0.3em);\n --rc-listbox-option-padding-inline: var(--rc-item-padding-inline, 0.75em);\n --rc-listbox-hover-bg: var(--rc-highlight, Highlight);\n --rc-listbox-hover-color: var(--rc-highlight-text, HighlightText);\n --rc-listbox-active-bg: var(--rc-highlight, Highlight);\n --rc-listbox-active-color: var(--rc-highlight-text, HighlightText);\n --rc-listbox-selected-bg: var(--rc-highlight, Highlight);\n --rc-listbox-selected-color: var(--rc-highlight-text, HighlightText);\n --rc-listbox-disabled-opacity: var(--rc-disabled-opacity, 0.5);\n\n &:not(:popover-open) {\n display: none;\n }\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 rc-listbox [part~='option-checkmark'] {\n flex-shrink: 0;\n width: 1em;\n text-align: center;\n font-size: 0.85em;\n visibility: hidden;\n }\n\n rc-listbox [part~='option'][aria-selected='true'] [part~='option-checkmark'] {\n visibility: visible;\n }\n\n rc-listbox [part~='create-option'] {\n font-style: italic;\n border-top: 1px solid var(--rc-border-color, ButtonBorder);\n margin-top: 0.25em;\n padding-top: 0.3em;\n }\n`;\n\nexport default comboboxStyles;\n","import { html, nothing } from 'lit';\nimport { property, query, state } from 'lit/decorators.js';\n\nimport { RCSelect } from '@rcarls/rc-select';\nimport type { FilterStrategy, RCListboxChangeEvent } from '@rcarls/rc-listbox';\n\nimport { comboboxStyles } from './rc-combobox.styles.js';\n\nexport interface RCComboboxCreateEvent {\n /** The text typed by the user that didn't match any existing option. */\n text: string;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'rc-combobox': RCCombobox;\n }\n}\n\n/**\n * Editable combobox with filtering and optional allow-create behavior, configured from\n * native option data and following the WAI-ARIA Combobox pattern.\n *\n * Extends `rc-select` by replacing the trigger `<div>` with a text `<input>`\n * and adding: live filtering of the listbox, keyboard navigation from input,\n * and an optional \"Create '{text}'\" option for new entries.\n *\n * @see {@link https://richardcarls.github.io/rc-webcomponents/components/rc-combobox rc-combobox docs}\n * @see {@link https://www.w3.org/WAI/ARIA/apg/patterns/combobox/ WAI-ARIA Combobox pattern}\n *\n * @slot - Required. A native `<select>` element for form submission.\n * @slot toggle-icon - Optional. Replaces the default chevron icon.\n *\n * @fires rc-select-change - Inherited selection change event.\n * @fires rc-combobox-create - When the \"Create\" option is activated.\n * `detail: { text: string }`. Cancelable — call `preventDefault()` to stop\n * the default insertion of the new option.\n *\n * @csspart anchor - Outer container (includes chips + input + toggle).\n * @csspart chips - The chip group container (multiple mode).\n * @csspart chip - Individual chip (multiple mode).\n * @csspart chip-label - Text label inside a chip.\n * @csspart chip-remove - Remove button inside a chip.\n * @csspart input - The text input element.\n * @csspart toggle - The chevron toggle button.\n * @csspart listbox - The `<rc-listbox>` popup element.\n *\n * @attr allow-create - When present, shows a \"Create 'X'\" option for unmatched input.\n * @attr filter-strategy - How option labels are matched against typed input: `'contains'`\n * (default), `'prefix'`, or a custom predicate set via the `filterStrategy` JS property.\n *\n * @cssprop [--rc-combobox-max-height=20em] - Maximum popup height.\n * @cssprop [--rc-combobox-control-block-size=var(--rc-control-block-size)] - Anchor block size.\n * @cssprop [--rc-combobox-padding-block=calc(var(--rc-control-padding-block) / 2)] - Anchor block-axis padding.\n * @cssprop [--rc-combobox-padding-inline=calc(var(--rc-control-padding-inline) / 2)] - Anchor inline-axis padding.\n * @cssprop [--rc-combobox-gap=var(--rc-control-gap)] - Gap between chips, input, and toggle.\n * @cssprop [--rc-combobox-radius=var(--rc-control-radius)] - Anchor border radius.\n * @cssprop [--rc-combobox-border=var(--rc-border)] - Anchor border.\n * @cssprop [--rc-combobox-listbox-radius=var(--rc-control-radius)] - Popup listbox border radius.\n * @cssprop [--rc-combobox-listbox-border=var(--rc-border)] - Popup listbox border.\n * @cssprop [--rc-combobox-shadow=var(--rc-shadow)] - Popup listbox box shadow.\n * @cssprop [--rc-combobox-listbox-padding-block=var(--rc-control-padding-block)] - Popup listbox block padding.\n * @cssprop [--rc-combobox-chip-radius=var(--rc-radius-md)] - Multi-select chip border radius.\n * @cssprop [--rc-combobox-chip-padding-block=0.1em] - Multi-select chip block-axis padding.\n * @cssprop [--rc-combobox-chip-padding-inline=0.3em] - Multi-select chip inline-axis padding.\n * @cssprop [--rc-combobox-chip-gap=calc(var(--rc-control-gap, 0.25em) * 0.8)] - Gap between chip\n * label and remove icon.\n * @cssprop [--rc-combobox-chip-border=var(--rc-border)] - Multi-select chip border.\n * @cssprop [--rc-combobox-toggle-size=1.1em] - Inline size of the toggle button's icon area.\n */\nexport class RCCombobox extends RCSelect {\n static override styles = comboboxStyles;\n\n /** When set, shows a \"Create '{text}'\" option for text that has no exact match. */\n @property({ type: Boolean, attribute: 'allow-create' })\n allowCreate = false;\n\n /**\n * How option labels are matched against typed input.\n *\n * - Forwarded to the internal `rc-listbox`.\n * - Defaults to `'contains'` (substring).\n * - Set to `'prefix'` for starts-with matching, or\n * - Pass a custom `(label, query) => boolean` predicate.\n *\n * Function values are JS-only; string values may be set via the `filter-strategy` attribute.\n */\n @property({ attribute: 'filter-strategy', reflect: false })\n filterStrategy: FilterStrategy = 'contains';\n\n @query('#trigger')\n protected override _$trigger!: HTMLInputElement;\n\n @state()\n private _filterText = '';\n\n // Guard against _handleInputFocus re-opening the popup immediately after close.\n private _closingPopup = false;\n\n override openPopup() {\n super.openPopup();\n this._$listbox?.filterOptions(this._filterText);\n }\n\n override closePopup(_returnFocus = true) {\n this._filterText = '';\n this._$listbox?.clearFilter();\n this._$listbox?.setCreateOption(null);\n this._closingPopup = true;\n\n super.closePopup(false);\n\n // Deferred past any native focus-return from hidePopover() in Firefox\n setTimeout(() => {\n this._closingPopup = false;\n }, 0);\n }\n\n private _handleInput(e: InputEvent) {\n this._filterText = (e.target as HTMLInputElement).value;\n\n if (!this.open && this._filterText) {\n this.openPopup();\n }\n\n this._$listbox?.filterOptions(this._filterText);\n this._updateCreateOption();\n\n if (this._$listbox?.navigableItems.length) {\n this._activeDescendantCtrl.navigateToFirst();\n } else {\n this._activeDescendantCtrl.clear();\n }\n }\n\n private _handleInputFocus() {\n if (!this.open && !this._closingPopup) {\n this.openPopup();\n }\n }\n\n private _handleToggleClick(e: MouseEvent) {\n e.stopPropagation();\n\n if (this.open) {\n this.closePopup();\n } else {\n this.openPopup();\n this._$trigger?.focus();\n }\n }\n\n private _handleAnchorClick(e: MouseEvent) {\n const $target = e.target as HTMLElement;\n\n if (\n $target.closest('[part~=\"chip\"]') ||\n ($target as HTMLElement & { id?: string }).id === 'toggle'\n ) {\n return;\n }\n\n this._$trigger?.focus();\n }\n\n private _updateCreateOption() {\n if (!this.allowCreate || !this._filterText.trim()) {\n this._$listbox?.setCreateOption(null);\n\n return;\n }\n\n const trimmed = this._filterText.trim().toLowerCase();\n const hasExact =\n this._$listbox?.allOptions.some((o) => o.label.toLowerCase() === trimmed) ?? false;\n\n this._$listbox?.setCreateOption(hasExact ? null : this._filterText.trim());\n }\n\n protected override _handleListboxChange(e: CustomEvent) {\n const detail = e.detail as RCListboxChangeEvent;\n\n if (detail.reason === 'action' && detail.action === 'create') {\n e.stopPropagation();\n void this._activateCreate(this._filterText.trim());\n\n return;\n }\n\n super._handleListboxChange(e);\n\n if (!this.multiple) {\n this._syncInputToSelection();\n } else {\n this._filterText = '';\n\n if (this._$trigger) {\n this._$trigger.value = '';\n }\n\n this._$listbox?.clearFilter();\n this._updateCreateOption();\n }\n }\n\n private async _activateCreate(text: string) {\n if (!text) {\n return;\n }\n\n const createEvent = new CustomEvent<RCComboboxCreateEvent>('rc-combobox-create', {\n bubbles: true,\n composed: true,\n cancelable: true,\n detail: { text },\n });\n\n if (!this.dispatchEvent(createEvent)) {\n return;\n }\n\n this._addOption({ value: text, label: text });\n\n if (this.multiple) {\n this._$listbox?.toggleOption(text);\n this._filterText = '';\n\n if (this._$trigger) {\n this._$trigger.value = '';\n }\n\n this._$listbox?.clearFilter();\n this._$listbox?.setCreateOption(null);\n\n return;\n }\n\n this._applySelection([text]);\n this._syncInputToSelection();\n this.closePopup(true);\n this._dispatchChange();\n }\n\n override set value(value: string | string[] | undefined) {\n super.value = value;\n this._syncInputToSelection();\n }\n\n override get value(): string | string[] {\n return super.value;\n }\n\n private _syncInputToSelection(): void {\n if (this.multiple) {\n return;\n }\n\n const value = this.selectedValues[0];\n const label = value ? this._labelFor(value) : '';\n\n this._filterText = label;\n\n if (this._$trigger) {\n this._$trigger.value = label;\n }\n }\n\n private _handleInputKeyDown(e: KeyboardEvent) {\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n\n if (!this.open) {\n this.openPopup();\n this._activeDescendantCtrl.navigateToFirst();\n } else {\n this._activeDescendantCtrl.navigate(1);\n }\n\n break;\n\n case 'ArrowUp':\n e.preventDefault();\n\n if (this.open) {\n this._activeDescendantCtrl.navigate(-1);\n }\n\n break;\n\n case 'Home':\n if (this.open) {\n e.preventDefault();\n\n this._activeDescendantCtrl.navigateToFirst();\n }\n break;\n\n case 'End':\n if (this.open) {\n e.preventDefault();\n\n this._activeDescendantCtrl.navigateToLast();\n }\n break;\n\n case 'Enter': {\n e.preventDefault();\n const active = this._activeDescendantCtrl.activeItem;\n\n if (active) {\n active.dispatchEvent(\n new PointerEvent('pointerdown', { bubbles: true, cancelable: true }),\n );\n } else if (this.open && this._$listbox?.navigableItems.length) {\n const $first = this._$listbox.navigableItems[0];\n\n $first?.dispatchEvent(\n new PointerEvent('pointerdown', { bubbles: true, cancelable: true }),\n );\n }\n\n break;\n }\n\n case 'Tab':\n if (this.open) {\n const $first = this._$listbox?.navigableItems[0];\n\n if ($first) {\n $first.dispatchEvent(\n new PointerEvent('pointerdown', { bubbles: true, cancelable: true }),\n );\n }\n\n this.closePopup(false);\n }\n\n break;\n\n case 'Escape':\n e.preventDefault();\n this._filterText = '';\n\n if (this._$trigger) {\n this._$trigger.value = '';\n }\n\n this.closePopup();\n break;\n\n case 'Backspace':\n if (this._filterText === '' && this.multiple && this._selectedValues.size > 0) {\n e.preventDefault();\n this._focusLastChipRemove();\n }\n\n break;\n\n case 'ArrowLeft':\n if (\n (e.target as HTMLInputElement).selectionStart === 0 &&\n this.multiple &&\n this._selectedValues.size > 0\n ) {\n e.preventDefault();\n this._focusLastChipRemove();\n }\n\n break;\n }\n }\n\n private _focusLastChipRemove() {\n const $buttons = Array.from(\n this.renderRoot.querySelectorAll<HTMLButtonElement>('button[part~=\"chip\"]'),\n );\n\n $buttons[$buttons.length - 1]?.focus();\n }\n\n private get _inputPlaceholder(): string {\n if (this.multiple && this._selectedValues.size > 0) {\n return '';\n }\n\n return this.placeholder;\n }\n\n protected override render() {\n const showChips = this.multiple && this._selectedValues.size > 0;\n\n return html`\n <div id=\"anchor\" part=\"anchor\" @click=${this._handleAnchorClick}>\n ${showChips ? this._renderChips() : nothing}\n\n <input\n id=\"trigger\"\n part=\"input\"\n type=\"text\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n aria-expanded=${this.open ? 'true' : 'false'}\n aria-controls=\"listbox\"\n aria-autocomplete=\"list\"\n ?disabled=${this.disabled}\n placeholder=${this._inputPlaceholder}\n .value=${this._filterText}\n autocomplete=\"off\"\n spellcheck=\"false\"\n @input=${this._handleInput}\n @keydown=${this._handleInputKeyDown}\n @focus=${this._handleInputFocus}\n />\n\n <button\n id=\"toggle\"\n type=\"button\"\n part=\"toggle\"\n aria-hidden=\"true\"\n tabindex=\"-1\"\n @click=${this._handleToggleClick}\n >\n <slot name=\"toggle-icon\">\n <svg\n width=\"10\"\n height=\"6\"\n viewBox=\"0 0 10 6\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <polyline points=\"1,1 5,5 9,1\" />\n </svg>\n </slot>\n </button>\n </div>\n\n <rc-listbox\n id=\"listbox\"\n part=\"listbox\"\n popover=\"manual\"\n ?multiple=${this.multiple}\n checkmark\n .filterStrategy=${this.filterStrategy}\n @rc-listbox-change=${this._handleListboxChange}\n ></rc-listbox>\n\n <slot @slotchange=${this._handleSelectSlotChange}></slot>\n `;\n }\n}\n\nexport default RCCombobox;\n"],"names":["comboboxStyles","css","_RCCombobox","RCSelect","_returnFocus","e","$target","trimmed","hasExact","o","detail","text","createEvent","value","label","active","$first","$buttons","showChips","html","nothing","RCCombobox","__decorateClass","property","query","state"],"mappings":"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"}
|
|
File without changes
|