chunk.2FDSGE6D.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  1. import {
  2. getLabelledBy,
  3. renderFormControl
  4. } from "./chunk.LLZCD55S.js";
  5. import {
  6. getTextContent,
  7. hasSlot
  8. } from "./chunk.FMCX45AD.js";
  9. import {
  10. l
  11. } from "./chunk.5MED2A3H.js";
  12. import {
  13. event,
  14. watch
  15. } from "./chunk.XX234VRK.js";
  16. import {
  17. e as e2
  18. } from "./chunk.YXKHB4AC.js";
  19. import {
  20. T,
  21. e,
  22. h,
  23. n,
  24. o,
  25. r,
  26. r2
  27. } from "./chunk.5PIDMFOE.js";
  28. import {
  29. __decorateClass
  30. } from "./chunk.IHGPZX35.js";
  31. // _uyihdawu1:/Users/claviska/Projects/shoelace/src/components/select/select.scss
  32. var select_default = ":host {\n position: relative;\n box-sizing: border-box;\n}\n:host *, :host *:before, :host *:after {\n box-sizing: inherit;\n}\n\n[hidden] {\n display: none !important;\n}\n\n.form-control .form-control__label {\n display: none;\n}\n.form-control .form-control__help-text {\n display: none;\n}\n\n.form-control--has-label .form-control__label {\n display: inline-block;\n color: var(--sl-input-label-color);\n margin-bottom: var(--sl-spacing-xxx-small);\n}\n.form-control--has-label.form-control--small .form-control__label {\n font-size: var(--sl-input-label-font-size-small);\n}\n.form-control--has-label.form-control--medium .form-control__label {\n font-size: var(--sl-input-label-font-size-medium);\n}\n.form-control--has-label.form-control--large .form-control_label {\n font-size: var(--sl-input-label-font-size-large);\n}\n\n.form-control--has-help-text .form-control__help-text {\n display: block;\n color: var(--sl-input-help-text-color);\n}\n.form-control--has-help-text .form-control__help-text ::slotted(*) {\n margin-top: var(--sl-spacing-xxx-small);\n}\n.form-control--has-help-text.form-control--small .form-control__help-text {\n font-size: var(--sl-input-help-text-font-size-small);\n}\n.form-control--has-help-text.form-control--medium .form-control__help-text {\n font-size: var(--sl-input-help-text-font-size-medium);\n}\n.form-control--has-help-text.form-control--large .form-control__help-text {\n font-size: var(--sl-input-help-text-font-size-large);\n}\n\n:host {\n --focus-ring: 0 0 0 var(--sl-focus-ring-width) var(--sl-focus-ring-color-primary);\n display: block;\n}\n\n.select {\n display: block;\n}\n\n.select__box {\n display: inline-flex;\n align-items: center;\n justify-content: start;\n position: relative;\n width: 100%;\n font-family: var(--sl-input-font-family);\n font-weight: var(--sl-input-font-weight);\n letter-spacing: var(--sl-input-letter-spacing);\n background-color: var(--sl-input-background-color);\n border: solid var(--sl-input-border-width) var(--sl-input-border-color);\n vertical-align: middle;\n overflow: hidden;\n transition: var(--sl-transition-fast) color, var(--sl-transition-fast) border, var(--sl-transition-fast) box-shadow;\n cursor: pointer;\n}\n\n.select:not(.select--disabled) .select__box:hover {\n background-color: var(--sl-input-background-color-hover);\n border-color: var(--sl-input-border-color-hover);\n color: var(--sl-input-color-hover);\n}\n\n.select:not(.select--disabled) .select__box:focus {\n background-color: var(--sl-input-background-color-focus);\n border-color: var(--sl-input-border-color-focus);\n box-shadow: var(--focus-ring);\n outline: none;\n color: var(--sl-input-color-focus);\n}\n\n.select--disabled .select__box {\n background-color: var(--sl-input-background-color-disabled);\n border-color: var(--sl-input-border-color-disabled);\n color: var(--sl-input-color-disabled);\n opacity: 0.5;\n cursor: not-allowed;\n outline: none;\n}\n.select--disabled .select__tags,\n.select--disabled .select__clear {\n pointer-events: none;\n}\n\n.select__label {\n flex: 1 1 auto;\n display: flex;\n align-items: center;\n user-select: none;\n scrollbar-width: none;\n -ms-overflow-style: none;\n overflow-x: auto;\n overflow-y: hidden;\n white-space: nowrap;\n}\n.select__label::-webkit-scrollbar {\n width: 0;\n height: 0;\n}\n\n.select__clear {\n flex: 0 0 auto;\n}\n\n.select__icon {\n flex: 0 0 auto;\n display: inline-flex;\n transition: var(--sl-transition-medium) transform ease;\n}\n\n.select--open .select__icon {\n transform: rotate(-180deg);\n}\n\n.select--placeholder-visible .select__label {\n color: var(--sl-input-placeholder-color);\n}\n\n.select--disabled.select--placeholder-visible .select__label {\n color: var(--sl-input-placeholder-color-disabled);\n}\n\n.select__tags {\n display: inline-flex;\n align-items: center;\n flex-wrap: wrap;\n justify-content: left;\n margin-left: var(--sl-spacing-xx-small);\n}\n\n.select__hidden-select {\n clip: rect(0 0 0 0);\n clip-path: inset(50%);\n height: 1px;\n overflow: hidden;\n position: absolute;\n white-space: nowrap;\n width: 1px;\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n}\n\n.select--small .select__box {\n border-radius: var(--sl-input-border-radius-small);\n font-size: var(--sl-input-font-size-small);\n min-height: var(--sl-input-height-small);\n}\n.select--small .select__label {\n margin: 0 var(--sl-input-spacing-small);\n}\n.select--small .select__clear {\n margin-right: var(--sl-input-spacing-small);\n}\n.select--small .select__icon {\n margin-right: var(--sl-input-spacing-small);\n}\n.select--small .select__tags {\n padding-bottom: 2px;\n}\n.select--small .select__tags sl-tag {\n padding-top: 2px;\n}\n.select--small .select__tags sl-tag:not(:last-of-type) {\n margin-right: var(--sl-spacing-xx-small);\n}\n.select--small.select--has-tags .select__label {\n margin-left: 0;\n}\n\n.select--medium .select__box {\n border-radius: var(--sl-input-border-radius-medium);\n font-size: var(--sl-input-font-size-medium);\n min-height: var(--sl-input-height-medium);\n}\n.select--medium .select__label {\n margin: 0 var(--sl-input-spacing-medium);\n}\n.select--medium .select__clear {\n margin-right: var(--sl-input-spacing-medium);\n}\n.select--medium .select__icon {\n margin-right: var(--sl-input-spacing-medium);\n}\n.select--medium .select__tags {\n padding-bottom: 3px;\n}\n.select--medium .select__tags sl-tag {\n padding-top: 3px;\n}\n.select--medium .select__tags sl-tag:not(:last-of-type) {\n margin-right: var(--sl-spacing-xx-small);\n}\n.select--medium.select--has-tags .select__label {\n margin-left: 0;\n}\n\n.select--large .select__box {\n border-radius: var(--sl-input-border-radius-large);\n font-size: var(--sl-input-font-size-large);\n min-height: var(--sl-input-height-large);\n}\n.select--large .select__label {\n margin: 0 var(--sl-input-spacing-large);\n}\n.select--large .select__clear {\n margin-right: var(--sl-input-spacing-large);\n}\n.select--large .select__icon {\n margin-right: var(--sl-input-spacing-large);\n}\n.select--large .select__tags {\n padding-bottom: 4px;\n}\n.select--large .select__tags sl-tag {\n padding-top: 4px;\n}\n.select--large .select__tags sl-tag:not(:last-of-type) {\n margin-right: var(--sl-spacing-xx-small);\n}\n.select--large.select--has-tags .select__label {\n margin-left: 0;\n}\n\n.select--pill.select--small .select__box {\n border-radius: var(--sl-input-height-small);\n}\n.select--pill.select--medium .select__box {\n border-radius: var(--sl-input-height-medium);\n}\n.select--pill.select--large .select__box {\n border-radius: var(--sl-input-height-large);\n}";
  33. // src/components/select/select.ts
  34. var id = 0;
  35. var SlSelect = class extends h {
  36. constructor() {
  37. super(...arguments);
  38. this.inputId = `select-${++id}`;
  39. this.helpTextId = `select-help-text-${id}`;
  40. this.labelId = `select-label-${id}`;
  41. this.hasFocus = false;
  42. this.hasHelpTextSlot = false;
  43. this.hasLabelSlot = false;
  44. this.isOpen = false;
  45. this.displayLabel = "";
  46. this.displayTags = [];
  47. this.multiple = false;
  48. this.maxTagsVisible = 3;
  49. this.disabled = false;
  50. this.name = "";
  51. this.placeholder = "";
  52. this.size = "medium";
  53. this.hoist = false;
  54. this.value = "";
  55. this.pill = false;
  56. this.required = false;
  57. this.clearable = false;
  58. this.invalid = false;
  59. }
  60. connectedCallback() {
  61. super.connectedCallback();
  62. this.handleSlotChange = this.handleSlotChange.bind(this);
  63. this.resizeObserver = new ResizeObserver(() => this.resizeMenu());
  64. this.updateComplete.then(() => {
  65. this.resizeObserver.observe(this);
  66. this.shadowRoot.addEventListener("slotchange", this.handleSlotChange);
  67. this.syncItemsFromValue();
  68. });
  69. }
  70. disconnectedCallback() {
  71. super.disconnectedCallback();
  72. this.resizeObserver.unobserve(this);
  73. this.shadowRoot.removeEventListener("slotchange", this.handleSlotChange);
  74. }
  75. reportValidity() {
  76. return this.input.reportValidity();
  77. }
  78. setCustomValidity(message) {
  79. this.input.setCustomValidity(message);
  80. this.invalid = !this.input.checkValidity();
  81. }
  82. getItemLabel(item) {
  83. const slot = item.shadowRoot.querySelector("slot:not([name])");
  84. return getTextContent(slot);
  85. }
  86. getItems() {
  87. return [...this.querySelectorAll("sl-menu-item")];
  88. }
  89. getValueAsArray() {
  90. return Array.isArray(this.value) ? this.value : [this.value];
  91. }
  92. handleBlur() {
  93. this.hasFocus = false;
  94. this.slBlur.emit();
  95. }
  96. handleClearClick(event2) {
  97. event2.stopPropagation();
  98. this.value = this.multiple ? [] : "";
  99. this.slClear.emit();
  100. this.syncItemsFromValue();
  101. }
  102. handleDisabledChange() {
  103. if (this.disabled && this.isOpen) {
  104. this.dropdown.hide();
  105. }
  106. }
  107. handleFocus() {
  108. this.hasFocus = true;
  109. this.slFocus.emit();
  110. }
  111. handleKeyDown(event2) {
  112. const target = event2.target;
  113. const items = this.getItems();
  114. const firstItem = items[0];
  115. const lastItem = items[items.length - 1];
  116. if (target.tagName.toLowerCase() === "sl-tag") {
  117. return;
  118. }
  119. if (event2.key === "Tab") {
  120. if (this.isOpen) {
  121. this.dropdown.hide();
  122. }
  123. return;
  124. }
  125. if (["ArrowDown", "ArrowUp"].includes(event2.key)) {
  126. event2.preventDefault();
  127. if (!this.isOpen) {
  128. this.dropdown.show();
  129. }
  130. if (event2.key === "ArrowDown" && firstItem) {
  131. firstItem.focus();
  132. return;
  133. }
  134. if (event2.key === "ArrowUp" && lastItem) {
  135. lastItem.focus();
  136. return;
  137. }
  138. }
  139. if (!this.isOpen) {
  140. event2.stopPropagation();
  141. event2.preventDefault();
  142. this.dropdown.show();
  143. this.menu.typeToSelect(event2.key);
  144. }
  145. }
  146. handleLabelClick() {
  147. var _a;
  148. const box = (_a = this.shadowRoot) == null ? void 0 : _a.querySelector(".select__box");
  149. box.focus();
  150. }
  151. handleMenuSelect(event2) {
  152. const item = event2.detail.item;
  153. if (this.multiple) {
  154. this.value = this.value.includes(item.value) ? this.value.filter((v) => v !== item.value) : [...this.value, item.value];
  155. } else {
  156. this.value = item.value;
  157. }
  158. this.syncItemsFromValue();
  159. }
  160. handleMenuShow() {
  161. this.resizeMenu();
  162. this.isOpen = true;
  163. }
  164. handleMenuHide() {
  165. this.isOpen = false;
  166. }
  167. handleMultipleChange() {
  168. const value = this.getValueAsArray();
  169. this.value = this.multiple ? value : value[0] || "";
  170. this.syncItemsFromValue();
  171. }
  172. async handleSlotChange() {
  173. this.hasHelpTextSlot = hasSlot(this, "help-text");
  174. this.hasLabelSlot = hasSlot(this, "label");
  175. const items = this.getItems();
  176. await Promise.all(items.map((item) => item.render)).then(() => this.syncItemsFromValue());
  177. }
  178. handleTagInteraction(event2) {
  179. const path = event2.composedPath();
  180. const clearButton = path.find((el) => {
  181. if (el instanceof HTMLElement) {
  182. const element = el;
  183. return element.classList.contains("tag__clear");
  184. }
  185. return false;
  186. });
  187. if (clearButton) {
  188. event2.stopPropagation();
  189. }
  190. }
  191. handleValueChange() {
  192. this.syncItemsFromValue();
  193. this.slChange.emit();
  194. }
  195. resizeMenu() {
  196. var _a;
  197. const box = (_a = this.shadowRoot) == null ? void 0 : _a.querySelector(".select__box");
  198. this.menu.style.width = `${box.clientWidth}px`;
  199. if (this.dropdown) {
  200. this.dropdown.reposition();
  201. }
  202. }
  203. syncItemsFromValue() {
  204. const items = this.getItems();
  205. const value = this.getValueAsArray();
  206. items.map((item) => item.checked = value.includes(item.value));
  207. if (this.multiple) {
  208. const checkedItems = items.filter((item) => value.includes(item.value));
  209. this.displayLabel = checkedItems[0] ? this.getItemLabel(checkedItems[0]) : "";
  210. this.displayTags = checkedItems.map((item) => {
  211. return T`
  212. <sl-tag
  213. exportparts="base:tag"
  214. type="info"
  215. size=${this.size}
  216. ?pill=${this.pill}
  217. clearable
  218. @click=${this.handleTagInteraction}
  219. @keydown=${this.handleTagInteraction}
  220. @sl-clear=${(event2) => {
  221. event2.stopPropagation();
  222. if (!this.disabled) {
  223. item.checked = false;
  224. this.syncValueFromItems();
  225. }
  226. }}
  227. >
  228. ${this.getItemLabel(item)}
  229. </sl-tag>
  230. `;
  231. });
  232. if (this.maxTagsVisible > 0 && this.displayTags.length > this.maxTagsVisible) {
  233. const total = this.displayTags.length;
  234. this.displayLabel = "";
  235. this.displayTags = this.displayTags.slice(0, this.maxTagsVisible);
  236. this.displayTags.push(T`
  237. <sl-tag exportparts="base:tag" type="info" size=${this.size}> +${total - this.maxTagsVisible} </sl-tag>
  238. `);
  239. }
  240. } else {
  241. const checkedItem = items.filter((item) => item.value === value[0])[0];
  242. this.displayLabel = checkedItem ? this.getItemLabel(checkedItem) : "";
  243. this.displayTags = [];
  244. }
  245. }
  246. syncValueFromItems() {
  247. const items = this.getItems();
  248. const checkedItems = items.filter((item) => item.checked);
  249. const checkedValues = checkedItems.map((item) => item.value);
  250. if (this.multiple) {
  251. this.value = this.value.filter((val) => checkedValues.includes(val));
  252. } else {
  253. this.value = checkedValues.length > 0 ? checkedValues[0] : "";
  254. }
  255. }
  256. render() {
  257. var _a;
  258. const hasSelection = this.multiple ? this.value.length > 0 : this.value !== "";
  259. return renderFormControl({
  260. inputId: this.inputId,
  261. label: this.label,
  262. labelId: this.labelId,
  263. hasLabelSlot: this.hasLabelSlot,
  264. helpTextId: this.helpTextId,
  265. helpText: this.helpText,
  266. hasHelpTextSlot: this.hasHelpTextSlot,
  267. size: this.size,
  268. onLabelClick: () => this.handleLabelClick()
  269. }, T`
  270. <sl-dropdown
  271. part="base"
  272. .hoist=${this.hoist}
  273. .closeOnSelect=${!this.multiple}
  274. .containingElement=${this}
  275. ?disabled=${this.disabled}
  276. class=${e2({
  277. select: true,
  278. "select--open": this.isOpen,
  279. "select--empty": ((_a = this.value) == null ? void 0 : _a.length) === 0,
  280. "select--focused": this.hasFocus,
  281. "select--clearable": this.clearable,
  282. "select--disabled": this.disabled,
  283. "select--multiple": this.multiple,
  284. "select--has-tags": this.multiple && this.displayTags.length > 0,
  285. "select--placeholder-visible": this.displayLabel === "",
  286. "select--small": this.size === "small",
  287. "select--medium": this.size === "medium",
  288. "select--large": this.size === "large",
  289. "select--pill": this.pill,
  290. "select--invalid": this.invalid
  291. })}
  292. @sl-show=${this.handleMenuShow}
  293. @sl-hide=${this.handleMenuHide}
  294. >
  295. <div
  296. slot="trigger"
  297. id=${this.inputId}
  298. class="select__box"
  299. role="combobox"
  300. aria-labelledby=${l(getLabelledBy({
  301. label: this.label,
  302. labelId: this.labelId,
  303. hasLabelSlot: this.hasLabelSlot,
  304. helpText: this.helpText,
  305. helpTextId: this.helpTextId,
  306. hasHelpTextSlot: this.hasHelpTextSlot
  307. }))}
  308. aria-haspopup="true"
  309. aria-expanded=${this.isOpen ? "true" : "false"}
  310. tabindex=${this.disabled ? "-1" : "0"}
  311. @blur=${this.handleBlur}
  312. @focus=${this.handleFocus}
  313. @keydown=${this.handleKeyDown}
  314. >
  315. <div class="select__label">
  316. ${this.displayTags.length ? T` <span part="tags" class="select__tags"> ${this.displayTags} </span> ` : this.displayLabel || this.placeholder}
  317. </div>
  318. ${this.clearable && hasSelection ? T`
  319. <sl-icon-button
  320. exportparts="base:clear-button"
  321. class="select__clear"
  322. name="x-circle"
  323. library="system"
  324. @click=${this.handleClearClick}
  325. tabindex="-1"
  326. ></sl-icon-button>
  327. ` : ""}
  328. <span part="icon" class="select__icon" aria-hidden="true">
  329. <sl-icon name="chevron-down" library="system"></sl-icon>
  330. </span>
  331. <!-- The hidden input tricks the browser's built-in validation so it works as expected. We use an input
  332. instead of a select because, otherwise, iOS will show a list of options during validation. -->
  333. <input
  334. class="select__hidden-select"
  335. aria-hidden="true"
  336. ?required=${this.required}
  337. .value=${hasSelection ? "1" : ""}
  338. tabindex="-1"
  339. />
  340. </div>
  341. <sl-menu part="menu" class="select__menu" @sl-select=${this.handleMenuSelect}>
  342. <slot @slotchange=${this.handleSlotChange}></slot>
  343. </sl-menu>
  344. </sl-dropdown>
  345. `);
  346. }
  347. };
  348. SlSelect.styles = r(select_default);
  349. __decorateClass([
  350. o(".select")
  351. ], SlSelect.prototype, "dropdown", 2);
  352. __decorateClass([
  353. o(".select__hidden-select")
  354. ], SlSelect.prototype, "input", 2);
  355. __decorateClass([
  356. o(".select__menu")
  357. ], SlSelect.prototype, "menu", 2);
  358. __decorateClass([
  359. r2()
  360. ], SlSelect.prototype, "hasFocus", 2);
  361. __decorateClass([
  362. r2()
  363. ], SlSelect.prototype, "hasHelpTextSlot", 2);
  364. __decorateClass([
  365. r2()
  366. ], SlSelect.prototype, "hasLabelSlot", 2);
  367. __decorateClass([
  368. r2()
  369. ], SlSelect.prototype, "isOpen", 2);
  370. __decorateClass([
  371. r2()
  372. ], SlSelect.prototype, "displayLabel", 2);
  373. __decorateClass([
  374. r2()
  375. ], SlSelect.prototype, "displayTags", 2);
  376. __decorateClass([
  377. e({ type: Boolean, reflect: true })
  378. ], SlSelect.prototype, "multiple", 2);
  379. __decorateClass([
  380. e({ attribute: "max-tags-visible", type: Number })
  381. ], SlSelect.prototype, "maxTagsVisible", 2);
  382. __decorateClass([
  383. e({ type: Boolean, reflect: true })
  384. ], SlSelect.prototype, "disabled", 2);
  385. __decorateClass([
  386. e()
  387. ], SlSelect.prototype, "name", 2);
  388. __decorateClass([
  389. e()
  390. ], SlSelect.prototype, "placeholder", 2);
  391. __decorateClass([
  392. e()
  393. ], SlSelect.prototype, "size", 2);
  394. __decorateClass([
  395. e({ type: Boolean })
  396. ], SlSelect.prototype, "hoist", 2);
  397. __decorateClass([
  398. e()
  399. ], SlSelect.prototype, "value", 2);
  400. __decorateClass([
  401. e({ type: Boolean, reflect: true })
  402. ], SlSelect.prototype, "pill", 2);
  403. __decorateClass([
  404. e()
  405. ], SlSelect.prototype, "label", 2);
  406. __decorateClass([
  407. e({ attribute: "help-text" })
  408. ], SlSelect.prototype, "helpText", 2);
  409. __decorateClass([
  410. e({ type: Boolean, reflect: true })
  411. ], SlSelect.prototype, "required", 2);
  412. __decorateClass([
  413. e({ type: Boolean })
  414. ], SlSelect.prototype, "clearable", 2);
  415. __decorateClass([
  416. e({ type: Boolean, reflect: true })
  417. ], SlSelect.prototype, "invalid", 2);
  418. __decorateClass([
  419. event("sl-clear")
  420. ], SlSelect.prototype, "slClear", 2);
  421. __decorateClass([
  422. event("sl-change")
  423. ], SlSelect.prototype, "slChange", 2);
  424. __decorateClass([
  425. event("sl-focus")
  426. ], SlSelect.prototype, "slFocus", 2);
  427. __decorateClass([
  428. event("sl-blur")
  429. ], SlSelect.prototype, "slBlur", 2);
  430. __decorateClass([
  431. watch("disabled")
  432. ], SlSelect.prototype, "handleDisabledChange", 1);
  433. __decorateClass([
  434. watch("multiple")
  435. ], SlSelect.prototype, "handleMultipleChange", 1);
  436. __decorateClass([
  437. watch("helpText"),
  438. watch("label")
  439. ], SlSelect.prototype, "handleSlotChange", 1);
  440. __decorateClass([
  441. watch("value")
  442. ], SlSelect.prototype, "handleValueChange", 1);
  443. SlSelect = __decorateClass([
  444. n("sl-select")
  445. ], SlSelect);
  446. var select_default2 = SlSelect;
  447. export {
  448. select_default2 as select_default
  449. };