godown 3.12.0 → 3.13.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.
Files changed (146) hide show
  1. package/build/godown+lit.iife.js +12 -13
  2. package/build/godown+lit.iife.js.map +1 -1
  3. package/build/godown+lit.js +11 -12
  4. package/build/godown+lit.js.map +1 -1
  5. package/build/godown+lit.umd.js +12 -13
  6. package/build/godown+lit.umd.js.map +1 -1
  7. package/build/godown.iife.js +7 -7
  8. package/build/godown.iife.js.map +1 -1
  9. package/build/godown.js +5 -5
  10. package/build/godown.js.map +1 -1
  11. package/build/godown.umd.js +7 -7
  12. package/build/godown.umd.js.map +1 -1
  13. package/custom-elements.json +1 -1
  14. package/index.d.ts +1 -0
  15. package/index.d.ts.map +1 -1
  16. package/index.js +1 -1
  17. package/internal/global-style.d.ts.map +1 -1
  18. package/internal/global-style.js +1 -1
  19. package/internal/global-style.js.map +1 -1
  20. package/internal/popover.d.ts +3 -0
  21. package/internal/popover.d.ts.map +1 -0
  22. package/internal/popover.js +2 -0
  23. package/internal/popover.js.map +1 -0
  24. package/internal/reset-style.d.ts +3 -0
  25. package/internal/reset-style.d.ts.map +1 -0
  26. package/internal/reset-style.js +2 -0
  27. package/internal/reset-style.js.map +1 -0
  28. package/internal/ring.d.ts +1 -0
  29. package/internal/ring.d.ts.map +1 -1
  30. package/internal/ring.js +1 -1
  31. package/internal/ring.js.map +1 -1
  32. package/internal/super-input.d.ts +1 -1
  33. package/internal/super-input.d.ts.map +1 -1
  34. package/internal/super-input.js +1 -1
  35. package/internal/super-input.js.map +1 -1
  36. package/internal/utils.d.ts +2 -0
  37. package/internal/utils.d.ts.map +1 -0
  38. package/internal/utils.js +2 -0
  39. package/internal/utils.js.map +1 -0
  40. package/package.json +2 -3
  41. package/popover.d.ts +2 -0
  42. package/popover.d.ts.map +1 -0
  43. package/popover.js +2 -0
  44. package/popover.js.map +1 -0
  45. package/src/index.ts +1 -0
  46. package/src/internal/global-style.ts +5 -33
  47. package/src/internal/popover.ts +64 -0
  48. package/src/internal/reset-style.ts +63 -0
  49. package/src/internal/ring.ts +3 -2
  50. package/src/internal/super-input.ts +2 -2
  51. package/src/internal/utils.ts +10 -0
  52. package/src/popover.ts +1 -0
  53. package/src/web-components/alert/component.ts +3 -2
  54. package/src/web-components/avatar/component.ts +1 -0
  55. package/src/web-components/button/component.ts +2 -0
  56. package/src/web-components/card/component.ts +3 -2
  57. package/src/web-components/chip/component.ts +1 -3
  58. package/src/web-components/details/component.ts +27 -16
  59. package/src/web-components/dialog/component.ts +50 -67
  60. package/src/web-components/heading/component.ts +0 -1
  61. package/src/web-components/input/component.ts +1 -3
  62. package/src/web-components/link/component.ts +0 -2
  63. package/src/web-components/popover/component.ts +172 -0
  64. package/src/web-components/popover/definition.ts +11 -0
  65. package/src/web-components/range/component.ts +2 -1
  66. package/src/web-components/rotate/component.ts +0 -1
  67. package/src/web-components/select/component.ts +109 -173
  68. package/src/web-components/split/component.ts +2 -2
  69. package/src/web-components/switch/component.ts +2 -1
  70. package/src/web-components/tabs/component.ts +99 -100
  71. package/src/web-components/tooltip/component.ts +44 -112
  72. package/vscode.css-custom-data.json +1 -1
  73. package/vscode.html-custom-data.json +1 -1
  74. package/web-components/alert/component.d.ts.map +1 -1
  75. package/web-components/alert/component.js +1 -1
  76. package/web-components/alert/component.js.map +1 -1
  77. package/web-components/avatar/component.d.ts.map +1 -1
  78. package/web-components/avatar/component.js +1 -1
  79. package/web-components/avatar/component.js.map +1 -1
  80. package/web-components/button/component.d.ts.map +1 -1
  81. package/web-components/button/component.js +1 -1
  82. package/web-components/button/component.js.map +1 -1
  83. package/web-components/card/component.d.ts.map +1 -1
  84. package/web-components/card/component.js +1 -1
  85. package/web-components/card/component.js.map +1 -1
  86. package/web-components/chip/component.d.ts +1 -3
  87. package/web-components/chip/component.d.ts.map +1 -1
  88. package/web-components/chip/component.js.map +1 -1
  89. package/web-components/details/component.d.ts +9 -13
  90. package/web-components/details/component.d.ts.map +1 -1
  91. package/web-components/details/component.js +1 -1
  92. package/web-components/details/component.js.map +1 -1
  93. package/web-components/dialog/component.d.ts +12 -14
  94. package/web-components/dialog/component.d.ts.map +1 -1
  95. package/web-components/dialog/component.js +1 -1
  96. package/web-components/dialog/component.js.map +1 -1
  97. package/web-components/heading/component.d.ts.map +1 -1
  98. package/web-components/heading/component.js +1 -1
  99. package/web-components/heading/component.js.map +1 -1
  100. package/web-components/input/component.d.ts.map +1 -1
  101. package/web-components/input/component.js +1 -1
  102. package/web-components/input/component.js.map +1 -1
  103. package/web-components/link/component.d.ts.map +1 -1
  104. package/web-components/link/component.js +1 -1
  105. package/web-components/link/component.js.map +1 -1
  106. package/web-components/popover/component.d.ts +35 -0
  107. package/web-components/popover/component.d.ts.map +1 -0
  108. package/web-components/popover/component.js +2 -0
  109. package/web-components/popover/component.js.map +1 -0
  110. package/web-components/popover/definition.d.ts +8 -0
  111. package/web-components/popover/definition.d.ts.map +1 -0
  112. package/web-components/popover/definition.js +2 -0
  113. package/web-components/popover/definition.js.map +1 -0
  114. package/web-components/range/component.d.ts.map +1 -1
  115. package/web-components/range/component.js +1 -1
  116. package/web-components/range/component.js.map +1 -1
  117. package/web-components/rotate/component.d.ts.map +1 -1
  118. package/web-components/rotate/component.js.map +1 -1
  119. package/web-components/select/component.d.ts +11 -27
  120. package/web-components/select/component.d.ts.map +1 -1
  121. package/web-components/select/component.js +1 -1
  122. package/web-components/select/component.js.map +1 -1
  123. package/web-components/split/component.js +1 -1
  124. package/web-components/split/component.js.map +1 -1
  125. package/web-components/switch/component.d.ts.map +1 -1
  126. package/web-components/switch/component.js +1 -1
  127. package/web-components/switch/component.js.map +1 -1
  128. package/web-components/tabs/component.d.ts +18 -25
  129. package/web-components/tabs/component.d.ts.map +1 -1
  130. package/web-components/tabs/component.js +1 -1
  131. package/web-components/tabs/component.js.map +1 -1
  132. package/web-components/tooltip/component.d.ts +15 -39
  133. package/web-components/tooltip/component.d.ts.map +1 -1
  134. package/web-components/tooltip/component.js +1 -1
  135. package/web-components/tooltip/component.js.map +1 -1
  136. package/web-types.json +1 -1
  137. package/internal/direction.d.ts +0 -27
  138. package/internal/direction.d.ts.map +0 -1
  139. package/internal/direction.js +0 -2
  140. package/internal/direction.js.map +0 -1
  141. package/internal/super-openable.d.ts +0 -15
  142. package/internal/super-openable.d.ts.map +0 -1
  143. package/internal/super-openable.js +0 -2
  144. package/internal/super-openable.js.map +0 -1
  145. package/src/internal/direction.ts +0 -65
  146. package/src/internal/super-openable.ts +0 -34
@@ -1,25 +1,17 @@
1
1
  import { type HandlerEvent, attr, godown, htmlSlot, queryPart, styles } from "@godown/element";
2
2
  import svgCaretDown from "../../internal/icons/caret-down.js";
3
3
  import { type TemplateResult, css, html, nothing } from "lit";
4
- import { property, state } from "lit/decorators.js";
4
+ import { property } from "lit/decorators.js";
5
5
 
6
6
  import Input from "../input/component.js";
7
- import { cssGlobalVars } from "../../internal/global-style.js";
8
- import { type DirectionCardinalY, directionOutsetPlace } from "../../internal/direction.js";
7
+ import { hidePopover, showPopover } from "../../internal/popover.js";
8
+ import { memoize } from "../../internal/utils.js";
9
9
 
10
- function contain(a: string, b: string): boolean {
11
- return a && b && a.toLowerCase().includes(b.toLowerCase());
12
- }
13
-
14
- function betweenAt(i: number, s: string, c: string) {
15
- const start = s.slice(0, i).lastIndexOf(c) + 1 || 0;
16
- const end = s.indexOf(c, i) || s.length;
17
- return s.slice(start, end);
18
- }
10
+ const supportsPositionArea = memoize(() => CSS.supports("position-area:top"));
19
11
 
20
- function updateChecked(element: HTMLElement | null, operation: 0 | 1) {
12
+ function updateSelected(element: HTMLElement | null, operation: 0 | 1) {
21
13
  if (element) {
22
- const name = "checked";
14
+ const name = "selected";
23
15
  if (operation) {
24
16
  element.setAttribute(name, "");
25
17
  } else {
@@ -33,14 +25,6 @@ const protoName = "select";
33
25
  /**
34
26
  * {@linkcode Select} is similar to `<select>`.
35
27
  *
36
- * Elements with the value attribute/property can be used as options.
37
- *
38
- * The checked attribute will be added to the selected element.
39
- *
40
- * Multi-selected state looks the same as single-selected.
41
- *
42
- * Input will filter the options.
43
- *
44
28
  * @fires input - Fires when the input value changes.
45
29
  * @fires change - Fires when the input value changes.
46
30
  * @fires select - Fires when select an option.
@@ -48,67 +32,63 @@ const protoName = "select";
48
32
  * @category input
49
33
  */
50
34
  @godown(protoName)
51
- @styles(
52
- directionOutsetPlace,
53
- css`
54
- :host(:focus-within),
55
- .outline {
56
- ${cssGlobalVars.input}-outline-color: currentColor;
57
- }
35
+ @styles(css`
36
+ [part="root"] {
37
+ position: relative;
38
+ anchor-name: --select;
39
+ }
58
40
 
59
- [part="input"] {
60
- text-overflow: ellipsis;
61
- }
41
+ label {
42
+ display: contents;
43
+ }
62
44
 
63
- [part="content"] {
64
- position: absolute;
65
- width: 100%;
66
- visibility: hidden;
67
- }
45
+ [part="popover"] {
46
+ border: 0;
47
+ width: 100%;
48
+ background: none;
49
+ position-anchor: --select;
50
+ position-area: bottom center;
51
+ position-try-fallbacks: flip-block;
52
+ }
53
+
54
+ [part="input"] {
55
+ text-overflow: ellipsis;
56
+ }
68
57
 
69
- [visible] [part="content"] {
70
- visibility: visible;
58
+ @supports not (position-area: top) {
59
+ [part="popover"] {
60
+ left: 0;
61
+ top: 100%;
62
+ display: none;
63
+ position: absolute;
71
64
  }
72
- `,
73
- )
65
+ }
66
+ `)
74
67
  class Select extends Input {
75
- // @ts-ignore
76
- value: string | string[];
77
-
78
- /**
79
- * Selected texts.
80
- */
81
68
  @property()
82
69
  text: string;
83
70
 
84
- @queryPart("content")
85
- protected _content: HTMLElement;
86
-
87
- @property()
88
- direction: DirectionCardinalY;
89
-
90
71
  @property({ type: Boolean })
91
72
  multiple = false;
92
73
 
93
74
  @property({ type: Boolean })
94
- visible = false;
75
+ noEdit = false;
76
+
77
+ @property({ type: Array })
78
+ values: {
79
+ value: string;
80
+ label?: string;
81
+ }[] = [];
95
82
 
96
- @state()
97
- protected autoDirection: DirectionCardinalY = "bottom";
83
+ @queryPart("popover")
84
+ _popover: HTMLElement;
98
85
 
99
86
  protected lastChecked: HTMLElement;
100
87
  protected defaultText: string;
101
- protected defaultChecked: HTMLElement[];
102
- private __store: { value: string; text: string }[] = [];
103
-
104
- get observedRecord(): Record<string, any> {
105
- return {
106
- ...super.observedRecord,
107
- direction: this.direction || this.autoDirection,
108
- };
109
- }
88
+ protected optionsVisible = false;
110
89
 
111
90
  protected render(): TemplateResult<1> {
91
+ const inputNoEdit = this.noEdit || this.disabled;
112
92
  return html`
113
93
  <label
114
94
  part="root"
@@ -116,171 +96,127 @@ class Select extends Input {
116
96
  >
117
97
  ${[
118
98
  this._renderPrefix(),
99
+ this.noEdit
100
+ ? html`
101
+ <input style="position: absolute;inset: 0;opacity: 0;" />
102
+ `
103
+ : "",
119
104
  html`
120
105
  <input
121
106
  part="input"
122
- type="${this.type}"
123
107
  .value="${this.text}"
124
108
  ?autofocus="${this.autofocus}"
125
- ?disabled="${this.disabled}"
109
+ ?disabled="${inputNoEdit}"
126
110
  autocapitalize="${this.autocapitalize || nothing}"
127
111
  autocomplete="${this.autocomplete || nothing}"
128
112
  placeholder="${this.placeholder || nothing}"
129
- @focus="${this._handleFocus}"
130
- @input="${this._handleInput}"
131
- @change="${this._handleChange}"
113
+ @input="${inputNoEdit ? null : this._handleInput}"
114
+ @change="${inputNoEdit ? null : this._handleChange}"
132
115
  />
133
116
  `,
134
117
  this._renderSuffix(),
135
- html`
136
- <label
137
- part="content"
138
- direction-outset-place
139
- >
140
- ${htmlSlot()}
141
- </label>
142
- `,
143
118
  ]}
119
+ <div
120
+ part="popover"
121
+ popover="${supportsPositionArea() ? "manual" : nothing}"
122
+ >
123
+ ${htmlSlot()}
124
+ </div>
144
125
  </label>
145
126
  `;
146
127
  }
147
128
 
148
129
  protected _renderSuffix(): TemplateResult<1> {
149
130
  return html`
150
- <i part="suffix icon">${svgCaretDown()}</i>
131
+ <i part="suffix">${htmlSlot("suffix", svgCaretDown())}</i>
151
132
  `;
152
133
  }
153
134
 
154
- protected _handleFocus(): void {
155
- if (!this.direction) {
156
- const { top, bottom } = this.getBoundingClientRect();
157
- if (window.innerHeight - bottom < this._content.clientHeight && top > this._content.clientHeight) {
158
- this.autoDirection = "top";
159
- } else {
160
- this.autoDirection = "bottom";
161
- }
162
- }
163
- this.visible = true;
164
- }
165
-
166
135
  protected firstUpdated(): void {
167
- this.events.add(this._content, "click", (e: HandlerEvent) => {
168
- e.preventDefault();
169
- e.stopPropagation();
136
+ this.events.add(this._slot, "click", (e: HandlerEvent<HTMLOptionElement>) => {
170
137
  const { target } = e;
171
- const value = this.optionValue(target);
172
- if (value) {
173
- const operation = this.select(value, target.textContent);
174
- if (!this.multiple) {
175
- updateChecked(this.lastChecked, 0);
176
- }
177
- updateChecked(target, operation);
178
- this.lastChecked = target;
138
+ if (target.tagName !== "OPTION") {
139
+ return;
179
140
  }
180
- this._input.focus();
181
- });
182
- this.events.add(document, "click", (e: HandlerEvent) => {
183
- // e.preventDefault();
184
- e.stopPropagation();
185
- const composed1 = e.composedPath()[0] as HTMLElement;
186
- if (composed1 && !this.shadowRoot.contains(composed1)) {
187
- this.blur();
141
+ const { label, value } = target;
142
+ const operation = this.select(value, label);
143
+ if (!this.multiple) {
144
+ updateSelected(this.lastChecked, 0);
145
+ this.hideOptions();
188
146
  }
147
+ updateSelected(target, operation);
148
+ this.lastChecked = target;
189
149
  });
190
150
  }
191
151
 
192
152
  protected _connectedInit(): void {
193
- if (!this.value) {
194
- const checked = [...this.querySelectorAll<HTMLElement>("[checked]")];
195
- const list = this.multiple ? checked : checked.length ? [(this.lastChecked = checked[0])] : [];
196
- list.forEach((element: HTMLElement) => {
197
- const operation = this.select(this.optionValue(element), element.textContent);
198
- updateChecked(element, operation);
199
- });
200
-
201
- this.default = this.value;
202
- this.defaultText = this.text;
203
- this.defaultChecked = checked;
204
- }
205
- if (!this.text) {
206
- this.text = "";
207
- }
153
+ this.default = this.value ??= "";
154
+ this.defaultText = this.text ??= "";
155
+ this.events.add(this, "focus", this.showOptions);
208
156
  }
209
157
 
210
158
  reset(): void {
211
159
  this.value = this.default;
212
160
  this.text = this.defaultText;
213
- this.querySelectorAll<HTMLElement>("[checked]").forEach((element) => updateChecked(element, 0));
214
- this.defaultChecked.forEach((element) => updateChecked(element, 1));
215
161
  }
216
162
 
217
- select(value: string, text?: string): 0 | 1 {
218
- text ||= value;
219
- text = text.trim();
163
+ select(value: string, label: string): 0 | 1 {
164
+ label ||= value;
220
165
  let operation: 0 | 1 = 0;
221
- if (this.multiple) {
222
- const i = this.__store.findIndex((s) => s.value === value);
223
- if (i > -1) {
224
- this.__store.splice(i, 1);
225
- } else {
226
- this.__store.push({ value, text });
227
- operation = 1;
228
- }
229
- this.value = this.__store.map((s) => s.value);
230
- this.text = this.__store.map((s) => s.text).join(", ");
166
+ const i = this.values.findIndex((s) => s.value === value);
167
+ if (i > -1) {
168
+ this.values.splice(i, 1);
231
169
  } else {
232
- if (this.value === value) {
233
- this.value = "";
234
- this.text = "";
235
- } else {
236
- this.value = value;
237
- this.text = text;
238
- operation = 1;
239
- }
170
+ this.values.push({ value, label });
171
+ operation = 1;
240
172
  }
173
+ this.checkValues();
174
+ this.value = this.values.map((s) => s.value).join(",");
175
+ this.text = this.values.map((s) => s.label).join(", ");
241
176
  this.dispatchCustomEvent("select", this.value);
242
- this.filter();
243
177
  return operation;
244
178
  }
245
179
 
246
- filter(query?: string): void {
247
- query = query?.trim();
248
- [...this.children].forEach((element: HTMLElement) => {
249
- this.filterCallback(
250
- element,
251
- !query || contain(this.optionValue(element), query) || contain(element.textContent, query),
252
- query,
253
- );
254
- });
180
+ checkValues(): void {
181
+ if (!this.multiple && this.values.length > 1) {
182
+ this.values.splice(0, this.values.length - 1);
183
+ this.requestUpdate();
184
+ }
255
185
  }
256
186
 
257
- filterCallback(element: HTMLElement, match: boolean, query: string): void {
258
- element.style.display = match ? "" : "none";
187
+ showOptions(): void {
188
+ if (this.optionsVisible) {
189
+ return;
190
+ }
191
+ showPopover(this._popover);
192
+ const listener = (e) => {
193
+ if (!this.contains(e.target)) {
194
+ this.hideOptions();
195
+ this.events.remove(document, "click", listener);
196
+ }
197
+ };
198
+ this.events.add(document, "click", listener);
199
+ this.optionsVisible = true;
259
200
  }
260
201
 
261
- protected _handleInput(e: HandlerEvent<HTMLInputElement>): void {
262
- e.stopPropagation();
263
- if (this.compositing) {
202
+ hideOptions(): void {
203
+ if (!this.optionsVisible) {
264
204
  return;
265
205
  }
266
- const s = this._input.value;
267
- this.filter(this.multiple ? betweenAt(this._input.selectionStart, s, ",") : s);
268
- this.dispatchCustomEvent("input", this.value, { bubbles: true });
206
+ hidePopover(this._popover);
207
+ this.optionsVisible = false;
269
208
  }
270
209
 
271
210
  focus(options?: FocusOptions): void {
211
+ super.focus();
272
212
  this._input.focus(options);
273
- this.visible = true;
213
+ this.showOptions();
274
214
  }
275
215
 
276
216
  blur(): void {
277
- this._input.blur();
278
- this.visible = false;
279
217
  super.blur();
280
- }
281
-
282
- optionValue(option: HTMLElement): string {
283
- return (option as any).value || option.getAttribute("value") || "";
218
+ this._input.blur();
219
+ hidePopover(this._popover);
284
220
  }
285
221
  }
286
222
 
@@ -4,7 +4,7 @@ import { property, state } from "lit/decorators.js";
4
4
 
5
5
  import { cssGlobalVars, scopePrefix } from "../../internal/global-style.js";
6
6
  import { SuperInput } from "../../internal/super-input.js";
7
- import { RingBuilder } from "../../internal/ring.js";
7
+ import { RingBuilder, ringTypeAttribute } from "../../internal/ring.js";
8
8
 
9
9
  const protoName = "split";
10
10
  const cssScope = scopePrefix(protoName);
@@ -97,7 +97,7 @@ class Split extends SuperInput {
97
97
  }
98
98
 
99
99
  get observedRecord(): Record<string, any> {
100
- return omit(super.observedRecord, "ring-type");
100
+ return omit(super.observedRecord, ringTypeAttribute);
101
101
  }
102
102
 
103
103
  protected render(): TemplateResult<1> {
@@ -4,6 +4,7 @@ import { property } from "lit/decorators.js";
4
4
 
5
5
  import { cssGlobalVars, scopePrefix } from "../../internal/global-style.js";
6
6
  import { SuperInput } from "../../internal/super-input.js";
7
+ import { ringTypeAttribute } from "../../internal/ring.js";
7
8
 
8
9
  const protoName = "switch";
9
10
  const cssScope = scopePrefix(protoName);
@@ -94,7 +95,7 @@ class Switch extends SuperInput<boolean> {
94
95
  value = false;
95
96
 
96
97
  get observedRecord(): Record<string, any> {
97
- return omit(super.observedRecord, "ring-type");
98
+ return omit(super.observedRecord, ringTypeAttribute);
98
99
  }
99
100
 
100
101
  protected render(): TemplateResult<1> {