shadcn_phlexcomponents 0.1.17 → 0.1.18

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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/app/javascript/controllers/accordion_controller.js +90 -100
  3. data/app/javascript/controllers/alert_dialog_controller.js +4 -4
  4. data/app/javascript/controllers/avatar_controller.js +11 -11
  5. data/app/javascript/controllers/checkbox_controller.js +26 -25
  6. data/app/javascript/controllers/collapsible_controller.js +36 -34
  7. data/app/javascript/controllers/combobox_controller.js +231 -262
  8. data/app/javascript/controllers/command_controller.js +184 -204
  9. data/app/javascript/controllers/date_picker_controller.js +257 -240
  10. data/app/javascript/controllers/date_range_picker_controller.js +200 -188
  11. data/app/javascript/controllers/dialog_controller.js +78 -78
  12. data/app/javascript/controllers/dropdown_menu_controller.js +208 -228
  13. data/app/javascript/controllers/dropdown_menu_sub_controller.js +97 -110
  14. data/app/javascript/controllers/form_field_controller.js +16 -16
  15. data/app/javascript/controllers/hover_card_controller.js +71 -68
  16. data/app/javascript/controllers/loading_button_controller.js +10 -10
  17. data/app/javascript/controllers/popover_controller.js +78 -84
  18. data/app/javascript/controllers/progress_controller.js +11 -11
  19. data/app/javascript/controllers/radio_group_controller.js +74 -74
  20. data/app/javascript/controllers/select_controller.js +232 -246
  21. data/app/javascript/controllers/sidebar_controller.js +27 -26
  22. data/app/javascript/controllers/sidebar_trigger_controller.js +9 -12
  23. data/app/javascript/controllers/slider_controller.js +74 -73
  24. data/app/javascript/controllers/switch_controller.js +23 -22
  25. data/app/javascript/controllers/tabs_controller.js +61 -60
  26. data/app/javascript/controllers/theme_switcher_controller.js +27 -27
  27. data/app/javascript/controllers/toast_container_controller.js +31 -44
  28. data/app/javascript/controllers/toast_controller.js +18 -18
  29. data/app/javascript/controllers/toggle_controller.js +17 -16
  30. data/app/javascript/controllers/toggle_group_controller.js +17 -16
  31. data/app/javascript/controllers/tooltip_controller.js +77 -74
  32. data/app/javascript/shadcn_phlexcomponents.js +58 -58
  33. data/app/javascript/utils/command.js +334 -392
  34. data/app/javascript/utils/floating_ui.js +108 -147
  35. data/app/javascript/utils/index.js +190 -253
  36. data/app/stylesheets/date_picker.css +1 -1
  37. data/app/stylesheets/shadcn_phlexcomponents.css +173 -0
  38. data/app/typescript/controllers/combobox_controller.ts +0 -1
  39. data/app/typescript/controllers/date_picker_controller.ts +25 -7
  40. data/app/typescript/controllers/tooltip_controller.ts +1 -1
  41. data/app/typescript/utils/command.ts +0 -2
  42. data/app/typescript/utils/floating_ui.ts +11 -20
  43. data/app/typescript/utils/index.ts +0 -7
  44. data/lib/shadcn_phlexcomponents/components/accordion.rb +1 -1
  45. data/lib/shadcn_phlexcomponents/components/alert_dialog.rb +6 -6
  46. data/lib/shadcn_phlexcomponents/components/base.rb +2 -2
  47. data/lib/shadcn_phlexcomponents/components/combobox.rb +13 -13
  48. data/lib/shadcn_phlexcomponents/components/command.rb +13 -13
  49. data/lib/shadcn_phlexcomponents/components/date_picker.rb +18 -12
  50. data/lib/shadcn_phlexcomponents/components/date_range_picker.rb +7 -3
  51. data/lib/shadcn_phlexcomponents/components/dialog.rb +6 -6
  52. data/lib/shadcn_phlexcomponents/components/sheet.rb +7 -7
  53. data/lib/shadcn_phlexcomponents/components/toggle.rb +1 -1
  54. data/lib/shadcn_phlexcomponents/version.rb +1 -1
  55. metadata +2 -1
@@ -1,278 +1,247 @@
1
- import {
2
- ON_OPEN_FOCUS_DELAY,
3
- lockScroll,
4
- showContent,
5
- unlockScroll,
6
- hideContent,
7
- focusTrigger,
8
- setGroupLabelsId,
9
- onClickOutside,
10
- } from "../utils";
11
- import { initFloatingUi } from "../utils/floating_ui";
12
- import { Controller } from "@hotwired/stimulus";
13
- import Fuse from "fuse.js";
14
- import {
15
- scrollToItem,
16
- highlightItem,
17
- highlightItemByIndex,
18
- filteredItemsChanged,
19
- setItemsGroupId,
20
- search,
21
- clearRemoteResults,
22
- resetState,
23
- } from "../utils/command";
24
- import { useClickOutside, useDebounce } from "stimulus-use";
1
+ import { ON_OPEN_FOCUS_DELAY, lockScroll, showContent, unlockScroll, hideContent, focusTrigger, setGroupLabelsId, onClickOutside, } from '../utils';
2
+ import { initFloatingUi } from '../utils/floating_ui';
3
+ import { Controller } from '@hotwired/stimulus';
4
+ import Fuse from 'fuse.js';
5
+ import { scrollToItem, highlightItem, highlightItemByIndex, filteredItemsChanged, setItemsGroupId, search, clearRemoteResults, resetState, } from '../utils/command';
6
+ import { useClickOutside, useDebounce } from 'stimulus-use';
25
7
  const ComboboxController = class extends Controller {
26
- // targets
27
- static targets = [
28
- "trigger",
29
- "triggerText",
30
- "contentContainer",
31
- "content",
32
- "item",
33
- "group",
34
- "hiddenInput",
35
- "searchInput",
36
- "list",
37
- "listContainer",
38
- "empty",
39
- "loading",
40
- "error",
41
- ];
42
- // values
43
- static values = {
44
- isOpen: Boolean,
45
- selected: String,
46
- filteredItemIndexes: Array,
47
- };
48
- static debounces = ["search"];
49
- connect() {
50
- this.orderedItems = [...this.itemTargets];
51
- this.itemsInnerText = this.itemTargets.map((i) => i.innerText.trim());
52
- this.fuse = new Fuse(this.itemsInnerText);
53
- this.filteredItemIndexesValue = Array.from(
54
- { length: this.itemTargets.length },
55
- (_, i) => i,
56
- );
57
- this.isLoading = false;
58
- this.filteredItems = this.itemTargets;
59
- this.isDirty = false;
60
- this.searchPath = this.element.dataset.searchPath;
61
- setGroupLabelsId(this);
62
- setItemsGroupId(this);
63
- useDebounce(this);
64
- useClickOutside(this, {
65
- element: this.contentTarget,
66
- dispatchEvent: false,
67
- });
68
- this.DOMKeydownListener = this.onDOMKeydown.bind(this);
69
- }
70
- toggle() {
71
- if (this.isOpenValue) {
72
- this.close();
73
- } else {
74
- this.open();
8
+ // targets
9
+ static targets = [
10
+ 'trigger',
11
+ 'triggerText',
12
+ 'contentContainer',
13
+ 'content',
14
+ 'item',
15
+ 'group',
16
+ 'hiddenInput',
17
+ 'searchInput',
18
+ 'list',
19
+ 'listContainer',
20
+ 'empty',
21
+ 'loading',
22
+ 'error',
23
+ ];
24
+ // values
25
+ static values = {
26
+ isOpen: Boolean,
27
+ selected: String,
28
+ filteredItemIndexes: Array,
29
+ };
30
+ static debounces = ['search'];
31
+ connect() {
32
+ this.orderedItems = [...this.itemTargets];
33
+ this.itemsInnerText = this.itemTargets.map((i) => i.innerText.trim());
34
+ this.fuse = new Fuse(this.itemsInnerText);
35
+ this.filteredItemIndexesValue = Array.from({ length: this.itemTargets.length }, (_, i) => i);
36
+ this.isLoading = false;
37
+ this.filteredItems = this.itemTargets;
38
+ this.isDirty = false;
39
+ this.searchPath = this.element.dataset.searchPath;
40
+ setGroupLabelsId(this);
41
+ setItemsGroupId(this);
42
+ useDebounce(this);
43
+ useClickOutside(this, { element: this.contentTarget, dispatchEvent: false });
44
+ this.DOMKeydownListener = this.onDOMKeydown.bind(this);
75
45
  }
76
- }
77
- open() {
78
- this.isOpenValue = true;
79
- setTimeout(() => {
80
- this.searchInputTarget.focus();
81
- let index = 0;
82
- console.log("this.selectedValue", this.selectedValue);
83
- if (this.selectedValue) {
84
- const item = this.filteredItems.find(
85
- (i) => i.dataset.value === this.selectedValue,
86
- );
87
- if (item && !item.dataset.disabled) {
88
- index = this.filteredItems.indexOf(item);
46
+ toggle() {
47
+ if (this.isOpenValue) {
48
+ this.close();
89
49
  }
90
- }
91
- this.highlightItemByIndex(index);
92
- }, ON_OPEN_FOCUS_DELAY);
93
- }
94
- close() {
95
- this.isOpenValue = false;
96
- resetState(this);
97
- }
98
- scrollToItem(index) {
99
- scrollToItem(this, index);
100
- }
101
- highlightItem(event = null, index = null) {
102
- highlightItem(this, event, index);
103
- }
104
- highlightItemByIndex(index) {
105
- highlightItemByIndex(this, index);
106
- }
107
- select(event) {
108
- let item = undefined;
109
- if (event instanceof KeyboardEvent) {
110
- item = this.filteredItems.find((i) => i.dataset.highlighted === "true");
111
- } else {
112
- // mouse event
113
- item = event.currentTarget;
50
+ else {
51
+ this.open();
52
+ }
53
+ }
54
+ open() {
55
+ this.isOpenValue = true;
56
+ setTimeout(() => {
57
+ this.searchInputTarget.focus();
58
+ let index = 0;
59
+ if (this.selectedValue) {
60
+ const item = this.filteredItems.find((i) => i.dataset.value === this.selectedValue);
61
+ if (item && !item.dataset.disabled) {
62
+ index = this.filteredItems.indexOf(item);
63
+ }
64
+ }
65
+ this.highlightItemByIndex(index);
66
+ }, ON_OPEN_FOCUS_DELAY);
67
+ }
68
+ close() {
69
+ this.isOpenValue = false;
70
+ resetState(this);
71
+ }
72
+ scrollToItem(index) {
73
+ scrollToItem(this, index);
114
74
  }
115
- if (item) {
116
- this.selectedValue = item.dataset.value;
117
- // setTimeout is needed for selectedValueChanged to finish executing
118
- setTimeout(() => {
119
- this.close();
120
- }, 100);
75
+ highlightItem(event = null, index = null) {
76
+ highlightItem(this, event, index);
121
77
  }
122
- }
123
- inputKeydown(event) {
124
- if (event.key === " " && this.searchInputTarget.value.length === 0) {
125
- event.preventDefault();
78
+ highlightItemByIndex(index) {
79
+ highlightItemByIndex(this, index);
80
+ }
81
+ select(event) {
82
+ let item = undefined;
83
+ if (event instanceof KeyboardEvent) {
84
+ item = this.filteredItems.find((i) => i.dataset.highlighted === 'true');
85
+ }
86
+ else {
87
+ // mouse event
88
+ item = event.currentTarget;
89
+ }
90
+ if (item) {
91
+ this.selectedValue = item.dataset.value;
92
+ // setTimeout is needed for selectedValueChanged to finish executing
93
+ setTimeout(() => {
94
+ this.close();
95
+ }, 100);
96
+ }
126
97
  }
127
- this.hideError();
128
- this.showList();
129
- }
130
- search(event) {
131
- this.isDirty = true;
132
- clearRemoteResults(this);
133
- search(this, event);
134
- }
135
- clickOutside(event) {
136
- onClickOutside(this, event);
137
- }
138
- selectedValueChanged(value) {
139
- const item = this.itemTargets.find((i) => i.dataset.value === value);
140
- if (item) {
141
- this.triggerTextTarget.textContent = item.textContent;
142
- this.itemTargets.forEach((i) => {
143
- if (i.dataset.value === value) {
144
- i.setAttribute("aria-selected", "true");
145
- } else {
146
- i.setAttribute("aria-selected", "false");
98
+ inputKeydown(event) {
99
+ if (event.key === ' ' && this.searchInputTarget.value.length === 0) {
100
+ event.preventDefault();
147
101
  }
148
- });
149
- this.hiddenInputTarget.value = value;
102
+ this.hideError();
103
+ this.showList();
104
+ }
105
+ search(event) {
106
+ this.isDirty = true;
107
+ clearRemoteResults(this);
108
+ search(this, event);
150
109
  }
151
- this.triggerTarget.dataset.hasValue = `${!!value && value.length > 0}`;
152
- const placeholder = this.triggerTarget.dataset.placeholder;
153
- if (placeholder && this.triggerTarget.dataset.hasValue === "false") {
154
- this.triggerTextTarget.textContent = placeholder;
110
+ clickOutside(event) {
111
+ onClickOutside(this, event);
155
112
  }
156
- }
157
- isOpenValueChanged(isOpen, previousIsOpen) {
158
- if (isOpen) {
159
- lockScroll(this.contentTarget.id);
160
- showContent({
161
- trigger: this.triggerTarget,
162
- content: this.contentTarget,
163
- contentContainer: this.contentContainerTarget,
164
- setEqualWidth: true,
165
- });
166
- this.cleanup = initFloatingUi({
167
- referenceElement: this.triggerTarget,
168
- floatingElement: this.contentContainerTarget,
169
- side: this.contentTarget.dataset.side,
170
- align: this.contentTarget.dataset.align,
171
- sideOffset: 4,
172
- });
173
- this.setupEventListeners();
174
- } else {
175
- unlockScroll(this.contentTarget.id);
176
- hideContent({
177
- trigger: this.triggerTarget,
178
- content: this.contentTarget,
179
- contentContainer: this.contentContainerTarget,
180
- });
181
- if (previousIsOpen) {
182
- focusTrigger(this.triggerTarget);
183
- }
184
- this.cleanupEventListeners();
113
+ selectedValueChanged(value) {
114
+ const item = this.itemTargets.find((i) => i.dataset.value === value);
115
+ if (item) {
116
+ this.triggerTextTarget.textContent = item.textContent;
117
+ this.itemTargets.forEach((i) => {
118
+ if (i.dataset.value === value) {
119
+ i.setAttribute('aria-selected', 'true');
120
+ }
121
+ else {
122
+ i.setAttribute('aria-selected', 'false');
123
+ }
124
+ });
125
+ this.hiddenInputTarget.value = value;
126
+ }
127
+ this.triggerTarget.dataset.hasValue = `${!!value && value.length > 0}`;
128
+ const placeholder = this.triggerTarget.dataset.placeholder;
129
+ if (placeholder && this.triggerTarget.dataset.hasValue === 'false') {
130
+ this.triggerTextTarget.textContent = placeholder;
131
+ }
185
132
  }
186
- }
187
- filteredItemIndexesValueChanged(filteredItemIndexes) {
188
- filteredItemsChanged(this, filteredItemIndexes);
189
- }
190
- disconnect() {
191
- this.cleanupEventListeners();
192
- resetState(this);
193
- }
194
- showLoading() {
195
- this.isLoading = true;
196
- this.loadingTarget.classList.remove("hidden");
197
- }
198
- hideLoading() {
199
- this.isLoading = false;
200
- this.loadingTarget.classList.add("hidden");
201
- }
202
- showList() {
203
- this.listTarget.classList.remove("hidden");
204
- }
205
- hideList() {
206
- this.listTarget.classList.add("hidden");
207
- }
208
- showError() {
209
- this.errorTarget.classList.remove("hidden");
210
- }
211
- hideError() {
212
- this.errorTarget.classList.add("hidden");
213
- }
214
- showEmpty() {
215
- this.emptyTarget.classList.remove("hidden");
216
- }
217
- hideEmpty() {
218
- this.emptyTarget.classList.add("hidden");
219
- }
220
- showSelectedRemoteItems() {
221
- const remoteItems = Array.from(
222
- this.element.querySelectorAll(
223
- `[data-shadcn-phlexcomponents="${this.identifier}-item"][data-remote='true']`,
224
- ),
225
- );
226
- remoteItems.forEach((i) => {
227
- const isInsideGroup =
228
- i.parentElement?.dataset?.shadcnPhlexcomponents ===
229
- `${this.identifier}-group`;
230
- if (isInsideGroup) {
231
- const isRemoteGroup = i.parentElement.dataset.remote === "true";
232
- if (isRemoteGroup) {
233
- i.parentElement.classList.remove("hidden");
133
+ isOpenValueChanged(isOpen, previousIsOpen) {
134
+ if (isOpen) {
135
+ lockScroll(this.contentTarget.id);
136
+ showContent({
137
+ trigger: this.triggerTarget,
138
+ content: this.contentTarget,
139
+ contentContainer: this.contentContainerTarget,
140
+ setEqualWidth: true,
141
+ });
142
+ this.cleanup = initFloatingUi({
143
+ referenceElement: this.triggerTarget,
144
+ floatingElement: this.contentContainerTarget,
145
+ side: this.contentTarget.dataset.side,
146
+ align: this.contentTarget.dataset.align,
147
+ sideOffset: 4,
148
+ });
149
+ this.setupEventListeners();
234
150
  }
235
- }
236
- i.ariaHidden = "false";
237
- i.classList.remove("hidden");
238
- });
239
- }
240
- hideSelectedRemoteItems() {
241
- const remoteItems = Array.from(
242
- this.element.querySelectorAll(
243
- `[data-shadcn-phlexcomponents="${this.identifier}-item"][data-remote='true']`,
244
- ),
245
- );
246
- remoteItems.forEach((i) => {
247
- const isInsideGroup =
248
- i.parentElement?.dataset?.shadcnPhlexcomponents ===
249
- `${this.identifier}-group`;
250
- if (isInsideGroup) {
251
- const isRemoteGroup = i.parentElement.dataset.remote === "true";
252
- if (isRemoteGroup) {
253
- i.parentElement.classList.add("hidden");
151
+ else {
152
+ unlockScroll(this.contentTarget.id);
153
+ hideContent({
154
+ trigger: this.triggerTarget,
155
+ content: this.contentTarget,
156
+ contentContainer: this.contentContainerTarget,
157
+ });
158
+ if (previousIsOpen) {
159
+ focusTrigger(this.triggerTarget);
160
+ }
161
+ this.cleanupEventListeners();
254
162
  }
255
- }
256
- i.ariaHidden = "true";
257
- i.classList.add("hidden");
258
- });
259
- }
260
- setupEventListeners() {
261
- document.addEventListener("keydown", this.DOMKeydownListener);
262
- }
263
- cleanupEventListeners() {
264
- document.removeEventListener("keydown", this.DOMKeydownListener);
265
- if (this.abortController) {
266
- this.abortController.abort();
267
163
  }
268
- }
269
- onDOMKeydown(event) {
270
- if (!this.isOpenValue) return;
271
- const key = event.key;
272
- if (["Tab", "Enter"].includes(key)) event.preventDefault();
273
- if (key === "Escape") {
274
- this.close();
164
+ filteredItemIndexesValueChanged(filteredItemIndexes) {
165
+ filteredItemsChanged(this, filteredItemIndexes);
166
+ }
167
+ disconnect() {
168
+ this.cleanupEventListeners();
169
+ resetState(this);
170
+ }
171
+ showLoading() {
172
+ this.isLoading = true;
173
+ this.loadingTarget.classList.remove('hidden');
174
+ }
175
+ hideLoading() {
176
+ this.isLoading = false;
177
+ this.loadingTarget.classList.add('hidden');
178
+ }
179
+ showList() {
180
+ this.listTarget.classList.remove('hidden');
181
+ }
182
+ hideList() {
183
+ this.listTarget.classList.add('hidden');
184
+ }
185
+ showError() {
186
+ this.errorTarget.classList.remove('hidden');
187
+ }
188
+ hideError() {
189
+ this.errorTarget.classList.add('hidden');
190
+ }
191
+ showEmpty() {
192
+ this.emptyTarget.classList.remove('hidden');
193
+ }
194
+ hideEmpty() {
195
+ this.emptyTarget.classList.add('hidden');
196
+ }
197
+ showSelectedRemoteItems() {
198
+ const remoteItems = Array.from(this.element.querySelectorAll(`[data-shadcn-phlexcomponents="${this.identifier}-item"][data-remote='true']`));
199
+ remoteItems.forEach((i) => {
200
+ const isInsideGroup = i.parentElement?.dataset?.shadcnPhlexcomponents ===
201
+ `${this.identifier}-group`;
202
+ if (isInsideGroup) {
203
+ const isRemoteGroup = i.parentElement.dataset.remote === 'true';
204
+ if (isRemoteGroup) {
205
+ i.parentElement.classList.remove('hidden');
206
+ }
207
+ }
208
+ i.ariaHidden = 'false';
209
+ i.classList.remove('hidden');
210
+ });
211
+ }
212
+ hideSelectedRemoteItems() {
213
+ const remoteItems = Array.from(this.element.querySelectorAll(`[data-shadcn-phlexcomponents="${this.identifier}-item"][data-remote='true']`));
214
+ remoteItems.forEach((i) => {
215
+ const isInsideGroup = i.parentElement?.dataset?.shadcnPhlexcomponents ===
216
+ `${this.identifier}-group`;
217
+ if (isInsideGroup) {
218
+ const isRemoteGroup = i.parentElement.dataset.remote === 'true';
219
+ if (isRemoteGroup) {
220
+ i.parentElement.classList.add('hidden');
221
+ }
222
+ }
223
+ i.ariaHidden = 'true';
224
+ i.classList.add('hidden');
225
+ });
226
+ }
227
+ setupEventListeners() {
228
+ document.addEventListener('keydown', this.DOMKeydownListener);
229
+ }
230
+ cleanupEventListeners() {
231
+ document.removeEventListener('keydown', this.DOMKeydownListener);
232
+ if (this.abortController) {
233
+ this.abortController.abort();
234
+ }
235
+ }
236
+ onDOMKeydown(event) {
237
+ if (!this.isOpenValue)
238
+ return;
239
+ const key = event.key;
240
+ if (['Tab', 'Enter'].includes(key))
241
+ event.preventDefault();
242
+ if (key === 'Escape') {
243
+ this.close();
244
+ }
275
245
  }
276
- }
277
246
  };
278
247
  export { ComboboxController };