shadcn_phlexcomponents 0.1.18 → 0.1.19

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 (128) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +321 -23
  3. data/app/javascript/controllers/accordion_controller.js +101 -90
  4. data/app/javascript/controllers/alert_dialog_controller.js +5 -4
  5. data/app/javascript/controllers/avatar_controller.js +12 -11
  6. data/app/javascript/controllers/checkbox_controller.js +26 -26
  7. data/app/javascript/controllers/collapsible_controller.js +35 -36
  8. data/app/javascript/controllers/combobox_controller.js +262 -231
  9. data/app/javascript/controllers/command_controller.js +205 -184
  10. data/app/javascript/controllers/date_picker_controller.js +252 -253
  11. data/app/javascript/controllers/date_range_picker_controller.js +189 -200
  12. data/app/javascript/controllers/dialog_controller.js +79 -78
  13. data/app/javascript/controllers/dropdown_menu_controller.js +229 -208
  14. data/app/javascript/controllers/dropdown_menu_sub_controller.js +111 -97
  15. data/app/javascript/controllers/form_field_controller.js +17 -16
  16. data/app/javascript/controllers/hover_card_controller.js +69 -71
  17. data/app/javascript/controllers/loading_button_controller.js +11 -10
  18. data/app/javascript/controllers/popover_controller.js +85 -78
  19. data/app/javascript/controllers/progress_controller.js +12 -11
  20. data/app/javascript/controllers/radio_group_controller.js +75 -74
  21. data/app/javascript/controllers/select_controller.js +247 -232
  22. data/app/javascript/controllers/sidebar_controller.js +26 -27
  23. data/app/javascript/controllers/sidebar_trigger_controller.js +12 -9
  24. data/app/javascript/controllers/slider_controller.js +74 -74
  25. data/app/javascript/controllers/switch_controller.js +23 -23
  26. data/app/javascript/controllers/tabs_controller.js +61 -61
  27. data/app/javascript/controllers/theme_switcher_controller.js +28 -27
  28. data/app/javascript/controllers/toast_container_controller.js +45 -31
  29. data/app/javascript/controllers/toast_controller.js +19 -18
  30. data/app/javascript/controllers/toggle_controller.js +17 -17
  31. data/app/javascript/controllers/toggle_group_controller.js +17 -17
  32. data/app/javascript/controllers/tooltip_controller.js +75 -77
  33. data/app/javascript/shadcn_phlexcomponents.js +27 -60
  34. data/app/javascript/utils/command.js +390 -334
  35. data/app/javascript/utils/floating_ui.js +139 -107
  36. data/app/javascript/utils/index.js +253 -190
  37. data/app/typescript/controllers/accordion_controller.ts +2 -0
  38. data/app/typescript/controllers/alert_dialog_controller.ts +2 -0
  39. data/app/typescript/controllers/avatar_controller.ts +2 -0
  40. data/app/typescript/controllers/checkbox_controller.ts +2 -0
  41. data/app/typescript/controllers/collapsible_controller.ts +2 -0
  42. data/app/typescript/controllers/combobox_controller.ts +2 -0
  43. data/app/typescript/controllers/command_controller.ts +2 -0
  44. data/app/typescript/controllers/date_picker_controller.ts +2 -0
  45. data/app/typescript/controllers/date_range_picker_controller.ts +2 -0
  46. data/app/typescript/controllers/dialog_controller.ts +2 -0
  47. data/app/typescript/controllers/dropdown_menu_controller.ts +2 -0
  48. data/app/typescript/controllers/dropdown_menu_sub_controller.ts +2 -0
  49. data/app/typescript/controllers/form_field_controller.ts +2 -0
  50. data/app/typescript/controllers/hover_card_controller.ts +2 -0
  51. data/app/typescript/controllers/loading_button_controller.ts +2 -0
  52. data/app/typescript/controllers/popover_controller.ts +2 -0
  53. data/app/typescript/controllers/progress_controller.ts +2 -0
  54. data/app/typescript/controllers/radio_group_controller.ts +2 -0
  55. data/app/typescript/controllers/select_controller.ts +2 -0
  56. data/app/typescript/controllers/slider_controller.ts +2 -0
  57. data/app/typescript/controllers/switch_controller.ts +2 -0
  58. data/app/typescript/controllers/tabs_controller.ts +2 -0
  59. data/app/typescript/controllers/theme_switcher_controller.ts +2 -0
  60. data/app/typescript/controllers/toast_container_controller.ts +2 -0
  61. data/app/typescript/controllers/toast_controller.ts +2 -0
  62. data/app/typescript/controllers/toggle_controller.ts +2 -0
  63. data/app/typescript/controllers/toggle_group_controller.ts +2 -0
  64. data/app/typescript/controllers/tooltip_controller.ts +2 -0
  65. data/app/typescript/shadcn_phlexcomponents.ts +27 -61
  66. data/app/typescript/utils/index.ts +7 -0
  67. data/lib/install/upgrade_shadcn_phlexcomponents.rb +28 -0
  68. data/lib/shadcn_phlexcomponents/components/accordion.rb +55 -12
  69. data/lib/shadcn_phlexcomponents/components/alert.rb +35 -16
  70. data/lib/shadcn_phlexcomponents/components/alert_dialog.rb +52 -12
  71. data/lib/shadcn_phlexcomponents/components/aspect_ratio.rb +33 -2
  72. data/lib/shadcn_phlexcomponents/components/avatar.rb +24 -7
  73. data/lib/shadcn_phlexcomponents/components/badge.rb +23 -18
  74. data/lib/shadcn_phlexcomponents/components/breadcrumb.rb +46 -6
  75. data/lib/shadcn_phlexcomponents/components/button.rb +32 -27
  76. data/lib/shadcn_phlexcomponents/components/card.rb +59 -10
  77. data/lib/shadcn_phlexcomponents/components/checkbox.rb +51 -30
  78. data/lib/shadcn_phlexcomponents/components/checkbox_group.rb +24 -4
  79. data/lib/shadcn_phlexcomponents/components/combobox.rb +212 -69
  80. data/lib/shadcn_phlexcomponents/components/command.rb +156 -52
  81. data/lib/shadcn_phlexcomponents/components/date_picker.rb +134 -48
  82. data/lib/shadcn_phlexcomponents/components/date_range_picker.rb +20 -42
  83. data/lib/shadcn_phlexcomponents/components/dialog.rb +80 -26
  84. data/lib/shadcn_phlexcomponents/components/dropdown_menu.rb +74 -25
  85. data/lib/shadcn_phlexcomponents/components/dropdown_menu_sub.rb +52 -24
  86. data/lib/shadcn_phlexcomponents/components/form/form_checkbox.rb +1 -1
  87. data/lib/shadcn_phlexcomponents/components/form/form_checkbox_group.rb +1 -1
  88. data/lib/shadcn_phlexcomponents/components/form/form_combobox.rb +1 -1
  89. data/lib/shadcn_phlexcomponents/components/form/form_date_picker.rb +1 -1
  90. data/lib/shadcn_phlexcomponents/components/form/form_date_range_picker.rb +1 -1
  91. data/lib/shadcn_phlexcomponents/components/form/form_error.rb +8 -1
  92. data/lib/shadcn_phlexcomponents/components/form/form_helpers.rb +3 -2
  93. data/lib/shadcn_phlexcomponents/components/form/form_hint.rb +8 -1
  94. data/lib/shadcn_phlexcomponents/components/form/form_input.rb +1 -1
  95. data/lib/shadcn_phlexcomponents/components/form/form_radio_group.rb +1 -1
  96. data/lib/shadcn_phlexcomponents/components/form/form_select.rb +1 -1
  97. data/lib/shadcn_phlexcomponents/components/form/form_slider.rb +1 -1
  98. data/lib/shadcn_phlexcomponents/components/form/form_switch.rb +1 -1
  99. data/lib/shadcn_phlexcomponents/components/form/form_textarea.rb +1 -1
  100. data/lib/shadcn_phlexcomponents/components/form.rb +22 -6
  101. data/lib/shadcn_phlexcomponents/components/hover_card.rb +48 -18
  102. data/lib/shadcn_phlexcomponents/components/input.rb +13 -8
  103. data/lib/shadcn_phlexcomponents/components/label.rb +9 -4
  104. data/lib/shadcn_phlexcomponents/components/link.rb +8 -1
  105. data/lib/shadcn_phlexcomponents/components/pagination.rb +34 -6
  106. data/lib/shadcn_phlexcomponents/components/popover.rb +43 -13
  107. data/lib/shadcn_phlexcomponents/components/progress.rb +37 -6
  108. data/lib/shadcn_phlexcomponents/components/radio_group.rb +41 -15
  109. data/lib/shadcn_phlexcomponents/components/select.rb +99 -42
  110. data/lib/shadcn_phlexcomponents/components/separator.rb +9 -4
  111. data/lib/shadcn_phlexcomponents/components/sheet.rb +87 -21
  112. data/lib/shadcn_phlexcomponents/components/skeleton.rb +8 -1
  113. data/lib/shadcn_phlexcomponents/components/switch.rb +45 -17
  114. data/lib/shadcn_phlexcomponents/components/table.rb +84 -17
  115. data/lib/shadcn_phlexcomponents/components/tabs.rb +36 -12
  116. data/lib/shadcn_phlexcomponents/components/textarea.rb +12 -7
  117. data/lib/shadcn_phlexcomponents/components/toast.rb +46 -20
  118. data/lib/shadcn_phlexcomponents/components/toast_container.rb +19 -14
  119. data/lib/shadcn_phlexcomponents/components/toggle.rb +28 -23
  120. data/lib/shadcn_phlexcomponents/components/tooltip.rb +49 -14
  121. data/lib/shadcn_phlexcomponents/configuration.rb +46 -0
  122. data/lib/shadcn_phlexcomponents/initializers/shadcn_phlexcomponents.rb +28 -0
  123. data/lib/shadcn_phlexcomponents/version.rb +1 -1
  124. data/lib/shadcn_phlexcomponents.rb +12 -1
  125. data/lib/tasks/upgrade.rake +10 -0
  126. metadata +15 -14
  127. data/app/typescript/controllers/sidebar_controller.ts +0 -39
  128. data/app/typescript/controllers/sidebar_trigger_controller.ts +0 -21
@@ -1,390 +1,446 @@
1
- import { ComboboxController, } from '../controllers/combobox_controller';
2
- import { getNextEnabledIndex, getPreviousEnabledIndex } from '.';
1
+ import { ComboboxController } from "../controllers/combobox_controller";
2
+ import { getNextEnabledIndex, getPreviousEnabledIndex } from ".";
3
3
  const scrollToItem = (controller, index) => {
4
- const item = controller.filteredItems[index];
5
- const itemRect = item.getBoundingClientRect();
6
- const listContainerRect = controller.listContainerTarget.getBoundingClientRect();
7
- let newScrollTop = null;
8
- const maxScrollTop = controller.listContainerTarget.scrollHeight -
9
- controller.listContainerTarget.clientHeight;
10
- // scroll to bottom
11
- if (itemRect.bottom - listContainerRect.bottom > 0) {
12
- if (index === controller.filteredItems.length - 1) {
13
- newScrollTop = maxScrollTop;
14
- }
15
- else {
16
- newScrollTop =
17
- controller.listContainerTarget.scrollTop +
18
- (itemRect.bottom - listContainerRect.bottom);
19
- }
4
+ const item = controller.filteredItems[index];
5
+ const itemRect = item.getBoundingClientRect();
6
+ const listContainerRect =
7
+ controller.listContainerTarget.getBoundingClientRect();
8
+ let newScrollTop = null;
9
+ const maxScrollTop =
10
+ controller.listContainerTarget.scrollHeight -
11
+ controller.listContainerTarget.clientHeight;
12
+ // scroll to bottom
13
+ if (itemRect.bottom - listContainerRect.bottom > 0) {
14
+ if (index === controller.filteredItems.length - 1) {
15
+ newScrollTop = maxScrollTop;
16
+ } else {
17
+ newScrollTop =
18
+ controller.listContainerTarget.scrollTop +
19
+ (itemRect.bottom - listContainerRect.bottom);
20
20
  }
21
- else if (listContainerRect.top - itemRect.top > 0) {
22
- // scroll to top
23
- if (index === 0) {
24
- newScrollTop = 0;
25
- }
26
- else {
27
- newScrollTop =
28
- controller.listContainerTarget.scrollTop -
29
- (listContainerRect.top - itemRect.top);
30
- }
21
+ } else if (listContainerRect.top - itemRect.top > 0) {
22
+ // scroll to top
23
+ if (index === 0) {
24
+ newScrollTop = 0;
25
+ } else {
26
+ newScrollTop =
27
+ controller.listContainerTarget.scrollTop -
28
+ (listContainerRect.top - itemRect.top);
31
29
  }
32
- if (newScrollTop !== null) {
33
- controller.scrollingViaKeyboard = true;
34
- if (newScrollTop >= 0 && newScrollTop <= maxScrollTop) {
35
- controller.listContainerTarget.scrollTop = newScrollTop;
36
- }
37
- // Clear the flag after scroll settles
38
- clearTimeout(controller.keyboardScrollTimeout);
39
- controller.keyboardScrollTimeout = window.setTimeout(() => {
40
- controller.scrollingViaKeyboard = false;
41
- }, 200);
30
+ }
31
+ if (newScrollTop !== null) {
32
+ controller.scrollingViaKeyboard = true;
33
+ if (newScrollTop >= 0 && newScrollTop <= maxScrollTop) {
34
+ controller.listContainerTarget.scrollTop = newScrollTop;
42
35
  }
36
+ // Clear the flag after scroll settles
37
+ clearTimeout(controller.keyboardScrollTimeout);
38
+ controller.keyboardScrollTimeout = window.setTimeout(() => {
39
+ controller.scrollingViaKeyboard = false;
40
+ }, 200);
41
+ }
43
42
  };
44
43
  const highlightItem = (controller, event = null, index = null) => {
45
- if (event !== null) {
46
- if (event instanceof KeyboardEvent) {
47
- const key = event.key;
48
- const item = controller.filteredItems.find((i) => i.dataset.highlighted === 'true');
49
- if (item) {
50
- const index = controller.filteredItems.indexOf(item);
51
- let newIndex = 0;
52
- if (key === 'ArrowUp') {
53
- newIndex = getPreviousEnabledIndex({
54
- items: controller.filteredItems,
55
- currentIndex: index,
56
- filterFn: (item) => item.dataset.disabled === undefined,
57
- wrapAround: false,
58
- });
59
- }
60
- else {
61
- newIndex = getNextEnabledIndex({
62
- items: controller.filteredItems,
63
- currentIndex: index,
64
- filterFn: (item) => item.dataset.disabled === undefined,
65
- wrapAround: false,
66
- });
67
- }
68
- controller.highlightItemByIndex(newIndex);
69
- controller.scrollToItem(newIndex);
70
- }
71
- else {
72
- if (key === 'ArrowUp') {
73
- controller.highlightItemByIndex(controller.filteredItems.length - 1);
74
- }
75
- else {
76
- controller.highlightItemByIndex(0);
77
- }
78
- }
44
+ if (event !== null) {
45
+ if (event instanceof KeyboardEvent) {
46
+ const key = event.key;
47
+ const item = controller.filteredItems.find(
48
+ (i) => i.dataset.highlighted === "true",
49
+ );
50
+ if (item) {
51
+ const index = controller.filteredItems.indexOf(item);
52
+ let newIndex = 0;
53
+ if (key === "ArrowUp") {
54
+ newIndex = getPreviousEnabledIndex({
55
+ items: controller.filteredItems,
56
+ currentIndex: index,
57
+ filterFn: (item) => item.dataset.disabled === undefined,
58
+ wrapAround: false,
59
+ });
60
+ } else {
61
+ newIndex = getNextEnabledIndex({
62
+ items: controller.filteredItems,
63
+ currentIndex: index,
64
+ filterFn: (item) => item.dataset.disabled === undefined,
65
+ wrapAround: false,
66
+ });
79
67
  }
80
- else {
81
- // mouse event
82
- if (controller.scrollingViaKeyboard) {
83
- event.stopImmediatePropagation();
84
- return;
85
- }
86
- else {
87
- const item = event.currentTarget;
88
- const index = controller.filteredItems.indexOf(item);
89
- controller.highlightItemByIndex(index);
90
- }
68
+ controller.highlightItemByIndex(newIndex);
69
+ controller.scrollToItem(newIndex);
70
+ } else {
71
+ if (key === "ArrowUp") {
72
+ controller.highlightItemByIndex(controller.filteredItems.length - 1);
73
+ } else {
74
+ controller.highlightItemByIndex(0);
91
75
  }
92
- }
93
- else if (index !== null) {
76
+ }
77
+ } else {
78
+ // mouse event
79
+ if (controller.scrollingViaKeyboard) {
80
+ event.stopImmediatePropagation();
81
+ return;
82
+ } else {
83
+ const item = event.currentTarget;
84
+ const index = controller.filteredItems.indexOf(item);
94
85
  controller.highlightItemByIndex(index);
86
+ }
95
87
  }
88
+ } else if (index !== null) {
89
+ controller.highlightItemByIndex(index);
90
+ }
96
91
  };
97
92
  const highlightItemByIndex = (controller, index) => {
98
- controller.filteredItems.forEach((item, i) => {
99
- if (i === index) {
100
- item.dataset.highlighted = 'true';
101
- }
102
- else {
103
- item.dataset.highlighted = 'false';
104
- }
105
- });
93
+ controller.filteredItems.forEach((item, i) => {
94
+ if (i === index) {
95
+ item.dataset.highlighted = "true";
96
+ } else {
97
+ item.dataset.highlighted = "false";
98
+ }
99
+ });
106
100
  };
107
101
  const filteredItemsChanged = (controller, filteredItemIndexes) => {
108
- if (controller.orderedItems) {
109
- const filteredItems = filteredItemIndexes.map((i) => controller.orderedItems[i]);
110
- // 1. Toggle visibility of items
111
- controller.orderedItems.forEach((item) => {
112
- if (filteredItems.includes(item)) {
113
- item.ariaHidden = 'false';
114
- item.classList.remove('hidden');
115
- }
116
- else {
117
- item.ariaHidden = 'true';
118
- item.classList.add('hidden');
119
- }
120
- });
121
- // 2. Get groups based on order of filtered items
122
- const groupIds = filteredItems.map((item) => item.dataset.groupId);
123
- const uniqueGroupIds = [...new Set(groupIds)].filter((groupId) => !!groupId);
124
- const orderedGroups = uniqueGroupIds.map((groupId) => {
125
- return controller.listTarget.querySelector(`[aria-labelledby=${groupId}]`);
126
- });
127
- // 3. Append items and groups based on filtered items
128
- const appendedGroupIds = [];
129
- filteredItems.forEach((item) => {
130
- const groupId = item.dataset.groupId;
131
- if (groupId) {
132
- const group = orderedGroups.find((g) => g.getAttribute('aria-labelledby') === groupId);
133
- if (group) {
134
- group.appendChild(item);
135
- if (!appendedGroupIds.includes(groupId)) {
136
- controller.listTarget.appendChild(group);
137
- appendedGroupIds.push(groupId);
138
- }
139
- }
140
- }
141
- else {
142
- controller.listTarget.appendChild(item);
143
- }
144
- });
145
- // 4. Toggle visibility of groups
146
- controller.groupTargets.forEach((group) => {
147
- const itemsCount = group.querySelectorAll(`[data-${controller.identifier}-target=item][aria-hidden=false]`).length;
148
- if (itemsCount > 0) {
149
- group.classList.remove('hidden');
150
- }
151
- else {
152
- group.classList.add('hidden');
153
- }
154
- });
155
- // 5. Move remote items to the end
156
- const remoteItems = Array.from(controller.element.querySelectorAll(`[data-shadcn-phlexcomponents="${controller.identifier}-item"][data-remote='true']`));
157
- remoteItems.forEach((i) => {
158
- const isInsideGroup = i.parentElement?.dataset?.shadcnPhlexcomponents ===
159
- `${controller.identifier}-group`;
160
- if (isInsideGroup) {
161
- const isRemoteGroup = i.parentElement.dataset.remote === 'true';
162
- // Move group to last
163
- if (isRemoteGroup) {
164
- controller.listTarget.appendChild(i.parentElement);
165
- }
166
- }
167
- else {
168
- // Move item to last
169
- controller.listTarget.appendChild(i);
170
- }
171
- });
172
- // 6. Assign filteredItems based on the order it is displayed in the DOM
173
- controller.filteredItems = Array.from(controller.listTarget.querySelectorAll(`[data-${controller.identifier}-target=item][aria-hidden=false]`));
174
- // 7. Highlight first item
175
- controller.highlightItemByIndex(0);
176
- // 8. Toggle visibility of empty
177
- if (controller.isDirty && !controller.isLoading) {
178
- if (controller.filteredItems.length > 0) {
179
- hideEmpty(controller);
180
- }
181
- else {
182
- showEmpty(controller);
183
- }
102
+ if (controller.orderedItems) {
103
+ const filteredItems = filteredItemIndexes.map(
104
+ (i) => controller.orderedItems[i],
105
+ );
106
+ // 1. Toggle visibility of items
107
+ controller.orderedItems.forEach((item) => {
108
+ if (filteredItems.includes(item)) {
109
+ item.ariaHidden = "false";
110
+ item.classList.remove("hidden");
111
+ } else {
112
+ item.ariaHidden = "true";
113
+ item.classList.add("hidden");
114
+ }
115
+ });
116
+ // 2. Get groups based on order of filtered items
117
+ const groupIds = filteredItems.map((item) => item.dataset.groupId);
118
+ const uniqueGroupIds = [...new Set(groupIds)].filter(
119
+ (groupId) => !!groupId,
120
+ );
121
+ const orderedGroups = uniqueGroupIds.map((groupId) => {
122
+ return controller.listTarget.querySelector(
123
+ `[aria-labelledby=${groupId}]`,
124
+ );
125
+ });
126
+ // 3. Append items and groups based on filtered items
127
+ const appendedGroupIds = [];
128
+ filteredItems.forEach((item) => {
129
+ const groupId = item.dataset.groupId;
130
+ if (groupId) {
131
+ const group = orderedGroups.find(
132
+ (g) => g.getAttribute("aria-labelledby") === groupId,
133
+ );
134
+ if (group) {
135
+ group.appendChild(item);
136
+ if (!appendedGroupIds.includes(groupId)) {
137
+ controller.listTarget.appendChild(group);
138
+ appendedGroupIds.push(groupId);
139
+ }
140
+ }
141
+ } else {
142
+ controller.listTarget.appendChild(item);
143
+ }
144
+ });
145
+ // 4. Toggle visibility of groups
146
+ controller.groupTargets.forEach((group) => {
147
+ const itemsCount = group.querySelectorAll(
148
+ `[data-${controller.identifier}-target=item][aria-hidden=false]`,
149
+ ).length;
150
+ if (itemsCount > 0) {
151
+ group.classList.remove("hidden");
152
+ } else {
153
+ group.classList.add("hidden");
154
+ }
155
+ });
156
+ // 5. Move remote items to the end
157
+ const remoteItems = Array.from(
158
+ controller.element.querySelectorAll(
159
+ `[data-shadcn-phlexcomponents="${controller.identifier}-item"][data-remote='true']`,
160
+ ),
161
+ );
162
+ remoteItems.forEach((i) => {
163
+ const isInsideGroup =
164
+ i.parentElement?.dataset?.shadcnPhlexcomponents ===
165
+ `${controller.identifier}-group`;
166
+ if (isInsideGroup) {
167
+ const isRemoteGroup = i.parentElement.dataset.remote === "true";
168
+ // Move group to last
169
+ if (isRemoteGroup) {
170
+ controller.listTarget.appendChild(i.parentElement);
184
171
  }
172
+ } else {
173
+ // Move item to last
174
+ controller.listTarget.appendChild(i);
175
+ }
176
+ });
177
+ // 6. Assign filteredItems based on the order it is displayed in the DOM
178
+ controller.filteredItems = Array.from(
179
+ controller.listTarget.querySelectorAll(
180
+ `[data-${controller.identifier}-target=item][aria-hidden=false]`,
181
+ ),
182
+ );
183
+ // 7. Highlight first item
184
+ controller.highlightItemByIndex(0);
185
+ // 8. Toggle visibility of empty
186
+ if (controller.isDirty && !controller.isLoading) {
187
+ if (controller.filteredItems.length > 0) {
188
+ hideEmpty(controller);
189
+ } else {
190
+ showEmpty(controller);
191
+ }
185
192
  }
193
+ }
186
194
  };
187
195
  const setItemsGroupId = (controller) => {
188
- controller.itemTargets.forEach((item) => {
189
- const parent = item.parentElement;
190
- if (parent?.dataset[`${controller.identifier}Target`] === 'group') {
191
- item.dataset.groupId = parent.getAttribute('aria-labelledby');
192
- }
193
- });
196
+ controller.itemTargets.forEach((item) => {
197
+ const parent = item.parentElement;
198
+ if (parent?.dataset[`${controller.identifier}Target`] === "group") {
199
+ item.dataset.groupId = parent.getAttribute("aria-labelledby");
200
+ }
201
+ });
194
202
  };
195
203
  const search = (controller, event) => {
196
- const input = event.target;
197
- const value = input.value.trim();
198
- if (value.length > 0) {
199
- const results = controller.fuse.search(value);
200
- // Don't show disabled items when filtering
201
- let filteredItemIndexes = results.map((result) => result.refIndex);
202
- filteredItemIndexes = filteredItemIndexes.filter((index) => {
203
- const item = controller.orderedItems[index];
204
- return item.dataset.disabled === undefined;
205
- });
206
- if (controller.searchPath) {
207
- hideSelectedRemoteItems(controller);
208
- showLoading(controller);
209
- hideList(controller);
210
- hideEmpty(controller);
211
- controller.filteredItemIndexesValue = filteredItemIndexes;
212
- performRemoteSearch(controller, value);
213
- }
214
- else {
215
- controller.filteredItemIndexesValue = filteredItemIndexes;
216
- }
204
+ const input = event.target;
205
+ const value = input.value.trim();
206
+ if (value.length > 0) {
207
+ const results = controller.fuse.search(value);
208
+ // Don't show disabled items when filtering
209
+ let filteredItemIndexes = results.map((result) => result.refIndex);
210
+ filteredItemIndexes = filteredItemIndexes.filter((index) => {
211
+ const item = controller.orderedItems[index];
212
+ return item.dataset.disabled === undefined;
213
+ });
214
+ if (controller.searchPath) {
215
+ hideSelectedRemoteItems(controller);
216
+ showLoading(controller);
217
+ hideList(controller);
218
+ hideEmpty(controller);
219
+ controller.filteredItemIndexesValue = filteredItemIndexes;
220
+ performRemoteSearch(controller, value);
221
+ } else {
222
+ controller.filteredItemIndexesValue = filteredItemIndexes;
217
223
  }
218
- else {
219
- if (controller.searchPath) {
220
- showSelectedRemoteItems(controller);
221
- }
222
- controller.filteredItemIndexesValue = Array.from({ length: controller.orderedItems.length }, (_, i) => i);
224
+ } else {
225
+ if (controller.searchPath) {
226
+ showSelectedRemoteItems(controller);
223
227
  }
228
+ controller.filteredItemIndexesValue = Array.from(
229
+ { length: controller.orderedItems.length },
230
+ (_, i) => i,
231
+ );
232
+ }
224
233
  };
225
234
  const performRemoteSearch = async (controller, query) => {
226
- // Cancel previous request
227
- if (controller.abortController) {
228
- controller.abortController.abort();
229
- }
230
- // Create new abort controller
231
- controller.abortController = new AbortController();
232
- try {
233
- const response = await fetch(`${controller.searchPath}?q=${query}`, {
234
- signal: controller.abortController.signal,
235
- headers: {
236
- Accept: 'application/json',
237
- 'Content-Type': 'application/json',
238
- },
239
- });
240
- if (!response.ok) {
241
- throw new Error(`HTTP error! status: ${response.status}`);
242
- }
243
- const data = await response.json();
244
- renderRemoteResults(controller, data);
245
- showList(controller);
246
- }
247
- catch (error) {
248
- if (error instanceof Error && error.name !== 'AbortError') {
249
- console.error('Remote search error:', error);
250
- showError(controller);
251
- }
235
+ // Cancel previous request
236
+ if (controller.abortController) {
237
+ controller.abortController.abort();
238
+ }
239
+ // Create new abort controller
240
+ controller.abortController = new AbortController();
241
+ try {
242
+ const response = await fetch(`${controller.searchPath}?q=${query}`, {
243
+ signal: controller.abortController.signal,
244
+ headers: {
245
+ Accept: "application/json",
246
+ "Content-Type": "application/json",
247
+ },
248
+ });
249
+ if (!response.ok) {
250
+ throw new Error(`HTTP error! status: ${response.status}`);
252
251
  }
253
- finally {
254
- hideLoading(controller);
252
+ const data = await response.json();
253
+ renderRemoteResults(controller, data);
254
+ showList(controller);
255
+ } catch (error) {
256
+ if (error instanceof Error && error.name !== "AbortError") {
257
+ console.error("Remote search error:", error);
258
+ showError(controller);
255
259
  }
260
+ } finally {
261
+ hideLoading(controller);
262
+ }
256
263
  };
257
264
  const renderRemoteResults = (controller, data) => {
258
- data.forEach((item) => {
259
- const tempDiv = document.createElement('div');
260
- tempDiv.innerHTML = item.html;
261
- const itemEl = tempDiv.firstElementChild;
262
- itemEl.dataset.remote = 'true';
263
- itemEl.ariaHidden = 'false';
264
- if (controller instanceof ComboboxController) {
265
- // Don't append same item
266
- if (controller.selectedValue === itemEl.dataset.value) {
267
- const item = controller.itemTargets.find((i) => i.dataset.value === controller.selectedValue);
268
- if (item) {
269
- item.classList.remove('hidden');
270
- item.ariaHidden = 'false';
271
- }
272
- return;
273
- }
265
+ data.forEach((item) => {
266
+ const tempDiv = document.createElement("div");
267
+ tempDiv.innerHTML = item.html;
268
+ const itemEl = tempDiv.firstElementChild;
269
+ itemEl.dataset.remote = "true";
270
+ itemEl.ariaHidden = "false";
271
+ if (controller instanceof ComboboxController) {
272
+ // Don't append same item
273
+ if (controller.selectedValue === itemEl.dataset.value) {
274
+ const item = controller.itemTargets.find(
275
+ (i) => i.dataset.value === controller.selectedValue,
276
+ );
277
+ if (item) {
278
+ item.classList.remove("hidden");
279
+ item.ariaHidden = "false";
274
280
  }
275
- const group = item.group;
276
- if (group) {
277
- const groupEl = controller.groupTargets.find((g) => {
278
- const label = g.querySelector(`[data-shadcn-phlexcomponents="${controller.identifier}-label"]`);
279
- if (!label)
280
- return false;
281
- return label.textContent === group;
282
- });
283
- if (groupEl) {
284
- groupEl.classList.remove('hidden');
285
- groupEl.append(itemEl);
286
- }
287
- else {
288
- const template = controller.element.querySelector('template');
289
- const clone = template.content.cloneNode(true);
290
- const groupEl = clone.querySelector(`[data-shadcn-phlexcomponents="${controller.identifier}-group"]`);
291
- const groupId = crypto.randomUUID();
292
- const label = clone.querySelector(`[data-shadcn-phlexcomponents="${controller.identifier}-label"]`);
293
- label.textContent = group;
294
- label.id = groupId;
295
- groupEl.setAttribute('aria-labelledby', groupId);
296
- groupEl.dataset.remote = 'true';
297
- groupEl.append(itemEl);
298
- controller.listTarget.append(clone);
299
- }
300
- }
301
- else {
302
- controller.listTarget.append(itemEl);
303
- }
304
- });
305
- // Update filtered items for keyboard navigation
306
- controller.filteredItems = Array.from(controller.listTarget.querySelectorAll(`[data-${controller.identifier}-target="item"][aria-hidden=false]`));
307
- controller.highlightItemByIndex(0);
308
- if (controller.filteredItems.length > 0) {
309
- hideEmpty(controller);
281
+ return;
282
+ }
310
283
  }
311
- else {
312
- showEmpty(controller);
284
+ const group = item.group;
285
+ if (group) {
286
+ const groupEl = controller.groupTargets.find((g) => {
287
+ const label = g.querySelector(
288
+ `[data-shadcn-phlexcomponents="${controller.identifier}-label"]`,
289
+ );
290
+ if (!label) return false;
291
+ return label.textContent === group;
292
+ });
293
+ if (groupEl) {
294
+ groupEl.classList.remove("hidden");
295
+ groupEl.append(itemEl);
296
+ } else {
297
+ const template = controller.element.querySelector("template");
298
+ const clone = template.content.cloneNode(true);
299
+ const groupEl = clone.querySelector(
300
+ `[data-shadcn-phlexcomponents="${controller.identifier}-group"]`,
301
+ );
302
+ const groupId = crypto.randomUUID();
303
+ const label = clone.querySelector(
304
+ `[data-shadcn-phlexcomponents="${controller.identifier}-label"]`,
305
+ );
306
+ label.textContent = group;
307
+ label.id = groupId;
308
+ groupEl.setAttribute("aria-labelledby", groupId);
309
+ groupEl.dataset.remote = "true";
310
+ groupEl.append(itemEl);
311
+ controller.listTarget.append(clone);
312
+ }
313
+ } else {
314
+ controller.listTarget.append(itemEl);
313
315
  }
316
+ });
317
+ // Update filtered items for keyboard navigation
318
+ controller.filteredItems = Array.from(
319
+ controller.listTarget.querySelectorAll(
320
+ `[data-${controller.identifier}-target="item"][aria-hidden=false]`,
321
+ ),
322
+ );
323
+ controller.highlightItemByIndex(0);
324
+ if (controller.filteredItems.length > 0) {
325
+ hideEmpty(controller);
326
+ } else {
327
+ showEmpty(controller);
328
+ }
314
329
  };
315
330
  const clearRemoteResults = (controller) => {
316
- const remoteGroups = Array.from(controller.element.querySelectorAll(`[data-shadcn-phlexcomponents="${controller.identifier}-group"][data-remote='true']`));
317
- remoteGroups.forEach((g) => {
318
- const containsSelected = g.querySelector('[aria-selected="true"]');
319
- if (!containsSelected) {
320
- g.remove();
321
- }
322
- });
323
- const remoteItems = Array.from(controller.element.querySelectorAll(`[data-shadcn-phlexcomponents="${controller.identifier}-item"][data-remote='true']:not([aria-selected="true"])`));
324
- remoteItems.forEach((i) => i.remove());
331
+ const remoteGroups = Array.from(
332
+ controller.element.querySelectorAll(
333
+ `[data-shadcn-phlexcomponents="${controller.identifier}-group"][data-remote='true']`,
334
+ ),
335
+ );
336
+ remoteGroups.forEach((g) => {
337
+ const containsSelected = g.querySelector('[aria-selected="true"]');
338
+ if (!containsSelected) {
339
+ g.remove();
340
+ }
341
+ });
342
+ const remoteItems = Array.from(
343
+ controller.element.querySelectorAll(
344
+ `[data-shadcn-phlexcomponents="${controller.identifier}-item"][data-remote='true']:not([aria-selected="true"])`,
345
+ ),
346
+ );
347
+ remoteItems.forEach((i) => i.remove());
325
348
  };
326
349
  const resetState = (controller) => {
327
- controller.searchInputTarget.value = '';
328
- if (controller.searchPath) {
329
- clearRemoteResults(controller);
330
- showSelectedRemoteItems(controller);
331
- }
332
- controller.filteredItemIndexesValue = Array.from({ length: controller.orderedItems.length }, (_, i) => i);
350
+ controller.searchInputTarget.value = "";
351
+ if (controller.searchPath) {
352
+ clearRemoteResults(controller);
353
+ showSelectedRemoteItems(controller);
354
+ }
355
+ controller.filteredItemIndexesValue = Array.from(
356
+ { length: controller.orderedItems.length },
357
+ (_, i) => i,
358
+ );
333
359
  };
334
360
  const showLoading = (controller) => {
335
- controller.isLoading = true;
336
- controller.loadingTarget.classList.remove('hidden');
361
+ controller.isLoading = true;
362
+ controller.loadingTarget.classList.remove("hidden");
337
363
  };
338
364
  const hideLoading = (controller) => {
339
- controller.isLoading = false;
340
- controller.loadingTarget.classList.add('hidden');
365
+ controller.isLoading = false;
366
+ controller.loadingTarget.classList.add("hidden");
341
367
  };
342
368
  const showList = (controller) => {
343
- controller.listTarget.classList.remove('hidden');
369
+ controller.listTarget.classList.remove("hidden");
344
370
  };
345
371
  const hideList = (controller) => {
346
- controller.listTarget.classList.add('hidden');
372
+ controller.listTarget.classList.add("hidden");
347
373
  };
348
374
  const showError = (controller) => {
349
- controller.errorTarget.classList.remove('hidden');
375
+ controller.errorTarget.classList.remove("hidden");
350
376
  };
351
377
  const hideError = (controller) => {
352
- controller.errorTarget.classList.add('hidden');
378
+ controller.errorTarget.classList.add("hidden");
353
379
  };
354
380
  const showEmpty = (controller) => {
355
- controller.emptyTarget.classList.remove('hidden');
381
+ controller.emptyTarget.classList.remove("hidden");
356
382
  };
357
383
  const hideEmpty = (controller) => {
358
- controller.emptyTarget.classList.add('hidden');
384
+ controller.emptyTarget.classList.add("hidden");
359
385
  };
360
386
  const showSelectedRemoteItems = (controller) => {
361
- const remoteItems = Array.from(controller.element.querySelectorAll(`[data-shadcn-phlexcomponents="${controller.identifier}-item"][data-remote='true']`));
362
- remoteItems.forEach((i) => {
363
- const isInsideGroup = i.parentElement?.dataset?.shadcnPhlexcomponents ===
364
- `${controller.identifier}-group`;
365
- if (isInsideGroup) {
366
- const isRemoteGroup = i.parentElement.dataset.remote === 'true';
367
- if (isRemoteGroup) {
368
- i.parentElement.classList.remove('hidden');
369
- }
370
- }
371
- i.ariaHidden = 'false';
372
- i.classList.remove('hidden');
373
- });
387
+ const remoteItems = Array.from(
388
+ controller.element.querySelectorAll(
389
+ `[data-shadcn-phlexcomponents="${controller.identifier}-item"][data-remote='true']`,
390
+ ),
391
+ );
392
+ remoteItems.forEach((i) => {
393
+ const isInsideGroup =
394
+ i.parentElement?.dataset?.shadcnPhlexcomponents ===
395
+ `${controller.identifier}-group`;
396
+ if (isInsideGroup) {
397
+ const isRemoteGroup = i.parentElement.dataset.remote === "true";
398
+ if (isRemoteGroup) {
399
+ i.parentElement.classList.remove("hidden");
400
+ }
401
+ }
402
+ i.ariaHidden = "false";
403
+ i.classList.remove("hidden");
404
+ });
374
405
  };
375
406
  const hideSelectedRemoteItems = (controller) => {
376
- const remoteItems = Array.from(controller.element.querySelectorAll(`[data-shadcn-phlexcomponents="${controller.identifier}-item"][data-remote='true']`));
377
- remoteItems.forEach((i) => {
378
- const isInsideGroup = i.parentElement?.dataset?.shadcnPhlexcomponents ===
379
- `${controller.identifier}-group`;
380
- if (isInsideGroup) {
381
- const isRemoteGroup = i.parentElement.dataset.remote === 'true';
382
- if (isRemoteGroup) {
383
- i.parentElement.classList.add('hidden');
384
- }
385
- }
386
- i.ariaHidden = 'true';
387
- i.classList.add('hidden');
388
- });
407
+ const remoteItems = Array.from(
408
+ controller.element.querySelectorAll(
409
+ `[data-shadcn-phlexcomponents="${controller.identifier}-item"][data-remote='true']`,
410
+ ),
411
+ );
412
+ remoteItems.forEach((i) => {
413
+ const isInsideGroup =
414
+ i.parentElement?.dataset?.shadcnPhlexcomponents ===
415
+ `${controller.identifier}-group`;
416
+ if (isInsideGroup) {
417
+ const isRemoteGroup = i.parentElement.dataset.remote === "true";
418
+ if (isRemoteGroup) {
419
+ i.parentElement.classList.add("hidden");
420
+ }
421
+ }
422
+ i.ariaHidden = "true";
423
+ i.classList.add("hidden");
424
+ });
425
+ };
426
+ export {
427
+ scrollToItem,
428
+ highlightItem,
429
+ highlightItemByIndex,
430
+ filteredItemsChanged,
431
+ setItemsGroupId,
432
+ search,
433
+ performRemoteSearch,
434
+ clearRemoteResults,
435
+ resetState,
436
+ showLoading,
437
+ hideLoading,
438
+ showList,
439
+ hideList,
440
+ showError,
441
+ hideError,
442
+ showEmpty,
443
+ hideEmpty,
444
+ showSelectedRemoteItems,
445
+ hideSelectedRemoteItems,
389
446
  };
390
- export { scrollToItem, highlightItem, highlightItemByIndex, filteredItemsChanged, setItemsGroupId, search, performRemoteSearch, clearRemoteResults, resetState, showLoading, hideLoading, showList, hideList, showError, hideError, showEmpty, hideEmpty, showSelectedRemoteItems, hideSelectedRemoteItems, };