x
1
<select name="remote[]" id="remote" multiple="multiple" data-controller="combobox" data-combobox-url-value="/searchables"><option value="">Pick a movie...</option></select>
1
<%= select_tag :remote, nil, include_blank: "Pick a movie...", multiple: true, data: { controller: "combobox", combobox_url_value: main_app.searchables_path } %>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
.ts-control { align-items: center; background-color: var(--color-bg); border: 1px solid var(--color-border); border-radius: var(--rounded-md); min-block-size: var(--size-10); color: var(--color-text); display: inline-flex; font-size: var(--text-sm); gap: var(--size-1); line-height: inherit; padding: var(--size-2) var(--size-3); > input { color: inherit; font-size: inherit; }}.ts-dropdown { background-color: var(--color-bg); border: 1px solid var(--color-border); border-radius: var(--rounded-md); box-shadow: var(--shadow-md); color: var(--color-text); font-size: var(--text-sm); line-height: inherit; .ts-dropdown-content:not(:has(.optgroup)) { padding: var(--size-1); } .optgroup:not(:first-child) { border-block-start-width: var(--border); } .optgroup { padding: var(--size-1); } .optgroup-header { background-color: inherit; color: var(--color-text-subtle); font-size: var(--text-xs); padding: var(--size-1_5) var(--size-2); } .create { padding: var(--size-1_5) var(--size-2); } .option { border: 1px solid transparent; border-radius: var(--rounded-md); padding: var(--size-1_5) var(--size-2); } .active { background-color: var(--color-secondary); color: inherit !important; } .highlight { background-color: transparent !important; } .spinner { margin: var(--size-1_5) 0 0; } .spinner::after { border-block-color: var(--color-border-dark); }}.ts-wrapper.single .ts-control { background-color: var(--color-bg) !important; background-image: url("select-arrow.svg") !important; background-position: center right var(--size-2) !important; background-repeat: no-repeat !important; background-size: var(--size-4) auto !important;}.ts-wrapper.multi .ts-control > .item { background: var(--color-secondary); border-radius: var(--rounded-md); color: inherit; line-height: var(--leading-tight); margin: 0;}.disabled .ts-control { opacity: var(--opacity-50);}.disabled .ts-control * { cursor: not-allowed !important;}.invalid .ts-control { border-color: var(--color-negative);}[data-controller*="combobox"] { clip: rect(0 0 0 0); position: absolute;}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import { Controller } from "@hotwired/stimulus"import { get } from "https://cdn.skypack.dev/@rails/request.js@0.0.11?min"import TomSelect from "https://cdn.skypack.dev/tom-select@2.3.1?min"export default class extends Controller { static values = { url: String, optionCreate: { type: String, default: "Add" }, noResults: { type: String, default: "No results found" } } initialize() { this.load = this.load.bind(this) } connect() { if (this.element.nodeName === "INPUT") { this.tomSelect = new TomSelect(this.element, this.#inputSettings) } else { this.tomSelect = new TomSelect(this.element, this.#selectSettings) } } disconnect() { this.tomSelect.destroy() } async load(query, callback) { const response = await get(this.urlValue, { responseKind: "json", query: { q: query } }) const jsonResponse = await response.json callback(jsonResponse) } get #inputSettings() { return { render: this.#render, load: this.#loadSetting, persist: false, createOnBlur: true, create: true } } get #selectSettings() { return { render: this.#render, load: this.#loadSetting } } get #render() { return { option_create: (data, escape) => { return `<div class="create">${this.optionCreateValue} <b>${escape(data.input)}</b>...</div>` }, no_results: () => { return `<div class="no-results">${this.noResultsValue}</div>` } } } get #loadSetting() { return this.hasUrlValue && this.load }}