shadcn_phlexcomponents 0.1.11 → 0.1.14

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 (63) hide show
  1. checksums.yaml +4 -4
  2. data/app/javascript/controllers/accordion_controller.ts +65 -62
  3. data/app/javascript/controllers/alert_dialog_controller.ts +12 -0
  4. data/app/javascript/controllers/avatar_controller.ts +7 -2
  5. data/app/javascript/controllers/checkbox_controller.ts +11 -4
  6. data/app/javascript/controllers/collapsible_controller.ts +12 -5
  7. data/app/javascript/controllers/combobox_controller.ts +270 -39
  8. data/app/javascript/controllers/command_controller.ts +223 -51
  9. data/app/javascript/controllers/date_picker_controller.ts +185 -125
  10. data/app/javascript/controllers/date_range_picker_controller.ts +89 -79
  11. data/app/javascript/controllers/dialog_controller.ts +59 -57
  12. data/app/javascript/controllers/dropdown_menu_controller.ts +212 -36
  13. data/app/javascript/controllers/dropdown_menu_sub_controller.ts +31 -29
  14. data/app/javascript/controllers/form_field_controller.ts +6 -1
  15. data/app/javascript/controllers/hover_card_controller.ts +36 -26
  16. data/app/javascript/controllers/loading_button_controller.ts +6 -1
  17. data/app/javascript/controllers/popover_controller.ts +42 -65
  18. data/app/javascript/controllers/progress_controller.ts +9 -3
  19. data/app/javascript/controllers/radio_group_controller.ts +16 -9
  20. data/app/javascript/controllers/select_controller.ts +206 -65
  21. data/app/javascript/controllers/slider_controller.ts +23 -16
  22. data/app/javascript/controllers/switch_controller.ts +11 -4
  23. data/app/javascript/controllers/tabs_controller.ts +26 -18
  24. data/app/javascript/controllers/theme_switcher_controller.ts +6 -1
  25. data/app/javascript/controllers/toast_container_controller.ts +6 -1
  26. data/app/javascript/controllers/toast_controller.ts +7 -1
  27. data/app/javascript/controllers/toggle_controller.ts +28 -0
  28. data/app/javascript/controllers/toggle_group_controller.ts +28 -0
  29. data/app/javascript/controllers/tooltip_controller.ts +43 -31
  30. data/app/javascript/shadcn_phlexcomponents.ts +29 -25
  31. data/app/javascript/utils/command.ts +544 -0
  32. data/app/javascript/utils/floating_ui.ts +196 -0
  33. data/app/javascript/utils/index.ts +417 -0
  34. data/app/stylesheets/date_picker.css +118 -0
  35. data/lib/shadcn_phlexcomponents/alias.rb +3 -0
  36. data/lib/shadcn_phlexcomponents/components/accordion.rb +2 -1
  37. data/lib/shadcn_phlexcomponents/components/alert_dialog.rb +18 -15
  38. data/lib/shadcn_phlexcomponents/components/base.rb +14 -0
  39. data/lib/shadcn_phlexcomponents/components/collapsible.rb +1 -2
  40. data/lib/shadcn_phlexcomponents/components/combobox.rb +87 -57
  41. data/lib/shadcn_phlexcomponents/components/command.rb +77 -47
  42. data/lib/shadcn_phlexcomponents/components/date_picker.rb +25 -81
  43. data/lib/shadcn_phlexcomponents/components/date_range_picker.rb +21 -4
  44. data/lib/shadcn_phlexcomponents/components/dialog.rb +14 -12
  45. data/lib/shadcn_phlexcomponents/components/dropdown_menu.rb +5 -4
  46. data/lib/shadcn_phlexcomponents/components/dropdown_menu_sub.rb +2 -1
  47. data/lib/shadcn_phlexcomponents/components/form/form_combobox.rb +64 -0
  48. data/lib/shadcn_phlexcomponents/components/form.rb +14 -0
  49. data/lib/shadcn_phlexcomponents/components/hover_card.rb +3 -2
  50. data/lib/shadcn_phlexcomponents/components/popover.rb +3 -3
  51. data/lib/shadcn_phlexcomponents/components/select.rb +10 -25
  52. data/lib/shadcn_phlexcomponents/components/sheet.rb +15 -11
  53. data/lib/shadcn_phlexcomponents/components/table.rb +1 -1
  54. data/lib/shadcn_phlexcomponents/components/tabs.rb +1 -1
  55. data/lib/shadcn_phlexcomponents/components/toast_container.rb +1 -1
  56. data/lib/shadcn_phlexcomponents/components/toggle.rb +54 -0
  57. data/lib/shadcn_phlexcomponents/components/tooltip.rb +3 -2
  58. data/lib/shadcn_phlexcomponents/engine.rb +1 -5
  59. data/lib/shadcn_phlexcomponents/version.rb +1 -1
  60. metadata +9 -4
  61. data/app/javascript/controllers/command_root_controller.ts +0 -355
  62. data/app/javascript/controllers/dropdown_menu_root_controller.ts +0 -234
  63. data/app/javascript/utils.ts +0 -437
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e69ba212a41e6644e473fa1e443b1114b7095bec0b682399932d1d41451ba8fa
4
- data.tar.gz: 686b0e0582a7c277eb1ddaa5476edf08d300e8aa6ce1d0e0c8ceca7ed2dc3cdc
3
+ metadata.gz: e6ead95ebdeef8eac55b2ee6101b2fbdb7fb90c7d12f8f489bdb2f45ad507915
4
+ data.tar.gz: 6f067373fd86d04f7e2478b639c3d5021a265931b648a6729869d1c9bb472bee
5
5
  SHA512:
6
- metadata.gz: 99248f0f5d9ec5d554d86aa24a4340f8fb9232b7a4618bfc689e2aa0fe6e2f355a426ac5b04549ac3548453c1be17623c3f8d0fab6158c18a80c9fadfbabaddc
7
- data.tar.gz: e285a996a8aa294d3fda26d16b9e2cf3108fec5c256faa13a123e5bff949c9ff6837cc38752006acc4824df3a2c1492c653a7674f17f85935c8330f7fb4da761
6
+ metadata.gz: c9ca6aacc79c59cc008ca03043616c4483dcc65c9858b0134d61ab0d53497fda9e8f2be85f05e9b1d030fc74af0524f725524d3a6830f79333fd14894188cb89
7
+ data.tar.gz: e1d3d10691bef9568c16af2e2f23f1a7bccce7b512e72a6ef1a53e6db3ce85a95fdefaadbf86bcd9ecbe07f9f61a423cda24aa412ad60d849a99d4efc3501653
@@ -1,53 +1,33 @@
1
1
  import { Controller } from '@hotwired/stimulus'
2
- import { showContent, hideContent } from '../utils'
2
+ import {
3
+ showContent,
4
+ hideContent,
5
+ getNextEnabledIndex,
6
+ getPreviousEnabledIndex,
7
+ } from '../utils'
8
+
9
+ const AccordionController = class extends Controller<HTMLElement> {
10
+ // targets
11
+ static targets = ['item', 'trigger', 'content']
12
+ declare itemTargets: HTMLElement[]
13
+ declare triggerTargets: HTMLButtonElement[]
14
+ declare contentTargets: HTMLElement[]
3
15
 
4
- export default class extends Controller<HTMLElement> {
5
- static targets = ['item']
16
+ // values
6
17
  static values = { openItems: Array }
7
- declare itemTargets: HTMLElement[]
8
- declare multiple: boolean
9
18
  declare openItemsValue: string[]
10
19
 
20
+ // custom properties
21
+ declare multiple: boolean
22
+
11
23
  connect() {
12
24
  this.multiple = this.element.dataset.multiple === 'true'
13
-
14
- setTimeout(() => {
15
- this.itemTargets.forEach((item) => {
16
- const content = item.querySelector(
17
- '[data-shadcn-phlexcomponents="accordion-content-container"]',
18
- ) as HTMLElement
19
- this.setContentHeight(content)
20
- })
21
- }, 250)
22
- }
23
-
24
- setContentHeight(element: HTMLElement) {
25
- const height = this.getContentHeight(element)
26
- element.style.setProperty('--radix-accordion-content-height', `${height}px`)
27
25
  }
28
26
 
29
- getContentHeight(element: HTMLElement) {
30
- // Store the original styles we need to modify
31
- const originalStyles = {
32
- display: element.style.display,
33
- visibility: element.style.visibility,
34
- position: element.style.position,
35
- }
36
-
37
- // Make the element visible but not displayed
38
- element.style.display = 'block' // or whatever is appropriate (flex, inline, etc.)
39
- element.style.visibility = 'hidden'
40
- element.style.position = 'absolute'
41
-
42
- // Get the height
43
- const height = element.offsetHeight
44
-
45
- // Restore the original styles
46
- element.style.display = originalStyles.display
47
- element.style.visibility = originalStyles.visibility
48
- element.style.position = originalStyles.position
49
-
50
- return height
27
+ contentTargetConnected(content: HTMLElement) {
28
+ setTimeout(() => {
29
+ this.setContentHeight(content)
30
+ }, 100)
51
31
  }
52
32
 
53
33
  toggle(event: MouseEvent) {
@@ -75,30 +55,27 @@ export default class extends Controller<HTMLElement> {
75
55
 
76
56
  focusTrigger(event: KeyboardEvent) {
77
57
  const trigger = event.currentTarget as HTMLButtonElement
78
- const key = event.key as 'ArrowUp' | 'ArrowDown'
58
+ const key = event.key
79
59
 
80
- let focusableTriggers = this.itemTargets.map((item) => {
81
- return item.querySelector(
82
- '[data-shadcn-phlexcomponents="accordion-trigger"]',
83
- )
84
- }) as HTMLButtonElement[]
60
+ const focusableTriggers = this.triggerTargets.filter(
61
+ (trigger) => !trigger.disabled,
62
+ )
85
63
 
86
- focusableTriggers = focusableTriggers.filter((trigger) => !trigger.disabled)
87
64
  const index = focusableTriggers.indexOf(trigger)
88
65
  let newIndex = 0
89
66
 
90
67
  if (key === 'ArrowUp') {
91
- newIndex = index - 1
92
-
93
- if (newIndex < 0) {
94
- newIndex = focusableTriggers.length - 1
95
- }
68
+ newIndex = getPreviousEnabledIndex({
69
+ items: focusableTriggers,
70
+ currentIndex: index,
71
+ wrapAround: true,
72
+ })
96
73
  } else {
97
- newIndex = index + 1
98
-
99
- if (newIndex > focusableTriggers.length - 1) {
100
- newIndex = 0
101
- }
74
+ newIndex = getNextEnabledIndex({
75
+ items: focusableTriggers,
76
+ currentIndex: index,
77
+ wrapAround: true,
78
+ })
102
79
  }
103
80
 
104
81
  focusableTriggers[newIndex].focus()
@@ -108,11 +85,11 @@ export default class extends Controller<HTMLElement> {
108
85
  this.itemTargets.forEach((item) => {
109
86
  const itemValue = item.dataset.value as string
110
87
 
111
- const trigger = item.querySelector(
112
- '[data-shadcn-phlexcomponents="accordion-trigger"]',
88
+ const trigger = this.triggerTargets.find((trigger) =>
89
+ item.contains(trigger),
113
90
  ) as HTMLElement
114
- const content = item.querySelector(
115
- '[data-shadcn-phlexcomponents="accordion-content-container"]',
91
+ const content = this.contentTargets.find((content) =>
92
+ item.contains(content),
116
93
  ) as HTMLElement
117
94
 
118
95
  if (openItems.includes(itemValue)) {
@@ -130,4 +107,30 @@ export default class extends Controller<HTMLElement> {
130
107
  }
131
108
  })
132
109
  }
110
+
111
+ protected setContentHeight(element: HTMLElement) {
112
+ const height =
113
+ this.getContentHeight(element) || element.getBoundingClientRect().height
114
+ element.style.setProperty('--radix-accordion-content-height', `${height}px`)
115
+ }
116
+
117
+ getContentHeight(el: HTMLElement) {
118
+ const clone = el.cloneNode(true) as HTMLElement
119
+ Object.assign(clone.style, {
120
+ display: 'block',
121
+ position: 'absolute',
122
+ visibility: 'hidden',
123
+ })
124
+
125
+ document.body.appendChild(clone)
126
+ const height = clone.getBoundingClientRect().height
127
+ document.body.removeChild(clone)
128
+
129
+ return height
130
+ }
133
131
  }
132
+
133
+ type Accordion = InstanceType<typeof AccordionController>
134
+
135
+ export { AccordionController }
136
+ export type { Accordion }
@@ -0,0 +1,12 @@
1
+ import { DialogController } from './dialog_controller'
2
+
3
+ const AlertDialogController = class extends DialogController {
4
+ protected onDOMClick() {
5
+ return
6
+ }
7
+ }
8
+
9
+ type AlertDialog = InstanceType<typeof AlertDialogController>
10
+
11
+ export { AlertDialogController }
12
+ export type { AlertDialog }
@@ -1,8 +1,8 @@
1
1
  import { Controller } from '@hotwired/stimulus'
2
2
 
3
- export default class extends Controller {
3
+ const AvatarController = class extends Controller {
4
+ // targets
4
5
  static targets = ['image', 'fallback']
5
-
6
6
  declare readonly imageTarget: HTMLElement
7
7
  declare readonly fallbackTarget: HTMLElement
8
8
  declare readonly hasFallbackTarget: boolean
@@ -17,3 +17,8 @@ export default class extends Controller {
17
17
  }
18
18
  }
19
19
  }
20
+
21
+ type Avatar = InstanceType<typeof AvatarController>
22
+
23
+ export { AvatarController }
24
+ export type { Avatar }
@@ -1,13 +1,15 @@
1
1
  import { Controller } from '@hotwired/stimulus'
2
2
 
3
- export default class extends Controller<HTMLElement> {
3
+ const CheckboxController = class extends Controller<HTMLElement> {
4
+ // targets
4
5
  static targets = ['input', 'indicator']
6
+ declare readonly inputTarget: HTMLInputElement
7
+ declare readonly indicatorTarget: HTMLInputElement
8
+
9
+ // values
5
10
  static values = {
6
11
  isChecked: Boolean,
7
12
  }
8
-
9
- declare readonly inputTarget: HTMLInputElement
10
- declare readonly indicatorTarget: HTMLInputElement
11
13
  declare isCheckedValue: boolean
12
14
 
13
15
  toggle() {
@@ -32,3 +34,8 @@ export default class extends Controller<HTMLElement> {
32
34
  }
33
35
  }
34
36
  }
37
+
38
+ type Checkbox = InstanceType<typeof CheckboxController>
39
+
40
+ export { CheckboxController }
41
+ export type { Checkbox }
@@ -1,14 +1,16 @@
1
1
  import { Controller } from '@hotwired/stimulus'
2
- import { hideContent, showContent } from '@shadcn_phlexcomponents/utils'
2
+ import { hideContent, showContent } from '../utils'
3
3
 
4
- export default class extends Controller {
4
+ const CollapsibleController = class extends Controller {
5
+ // targets
5
6
  static targets = ['trigger', 'content']
7
+ declare readonly triggerTarget: HTMLElement
8
+ declare readonly contentTarget: HTMLElement
9
+
10
+ // values
6
11
  static values = {
7
12
  isOpen: Boolean,
8
13
  }
9
-
10
- declare readonly triggerTarget: HTMLElement
11
- declare readonly contentTarget: HTMLElement
12
14
  declare isOpenValue: boolean
13
15
 
14
16
  toggle() {
@@ -43,3 +45,8 @@ export default class extends Controller {
43
45
  }
44
46
  }
45
47
  }
48
+
49
+ type Collapsible = InstanceType<typeof CollapsibleController>
50
+
51
+ export { CollapsibleController }
52
+ export type { Collapsible }
@@ -2,73 +2,191 @@ import {
2
2
  ON_OPEN_FOCUS_DELAY,
3
3
  lockScroll,
4
4
  showContent,
5
- initFloatingUi,
6
5
  unlockScroll,
7
6
  hideContent,
8
7
  focusTrigger,
8
+ setGroupLabelsId,
9
+ onClickOutside,
9
10
  } from '../utils'
10
- import CommandRootController from './command_root_controller'
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
+
25
+ import { useClickOutside, useDebounce } from 'stimulus-use'
11
26
 
12
- export default class extends CommandRootController {
27
+ const ComboboxController = class extends Controller<HTMLElement> {
28
+ // targets
13
29
  static targets = [
14
30
  'trigger',
31
+ 'triggerText',
15
32
  'contentContainer',
16
33
  'content',
17
34
  'item',
18
- 'triggerText',
19
35
  'group',
20
- 'label',
21
36
  'hiddenInput',
22
37
  'searchInput',
23
- 'results',
38
+ 'list',
39
+ 'listContainer',
24
40
  'empty',
41
+ 'loading',
42
+ 'error',
25
43
  ]
44
+ declare readonly triggerTarget: HTMLElement
45
+ declare readonly triggerTextTarget: HTMLElement
46
+ declare readonly contentContainerTarget: HTMLElement
47
+ declare readonly contentTarget: HTMLElement
48
+ declare readonly itemTargets: HTMLElement[]
49
+ declare readonly groupTargets: HTMLElement[]
50
+ declare readonly hiddenInputTarget: HTMLInputElement
51
+ declare readonly searchInputTarget: HTMLInputElement
52
+ declare readonly listTarget: HTMLElement
53
+ declare readonly listContainerTarget: HTMLElement
54
+ declare readonly emptyTarget: HTMLElement
55
+ declare readonly loadingTarget: HTMLElement
56
+ declare readonly errorTarget: HTMLElement
26
57
 
58
+ // values
27
59
  static values = {
28
60
  isOpen: Boolean,
29
61
  selected: String,
30
62
  filteredItemIndexes: Array,
31
63
  }
32
-
33
- declare readonly contentContainerTarget: HTMLElement
34
- declare readonly triggerTextTarget: HTMLElement
35
- declare readonly hiddenInputTarget: HTMLInputElement
64
+ declare isOpenValue: boolean
36
65
  declare selectedValue: string
37
- declare cleanup: () => void
66
+ declare filteredItemIndexesValue: number[]
38
67
 
39
- open() {
40
- this.isOpenValue = true
41
- this.highlightItemByIndex(0)
68
+ // custom properties
69
+ declare orderedItems: HTMLElement[]
70
+ declare itemsInnerText: string[]
71
+ declare filteredItems: HTMLElement[]
72
+ declare fuse: Fuse<string>
73
+ declare scrollingViaKeyboard: boolean
74
+ declare keyboardScrollTimeout: number
75
+ declare abortController?: AbortController
76
+ declare searchPath?: string
77
+ declare isDirty: boolean
78
+ declare isLoading: boolean
79
+ declare DOMKeydownListener: (event: KeyboardEvent) => void
80
+ declare cleanup: () => void
42
81
 
43
- let index = 0
82
+ static debounces = ['search']
44
83
 
45
- if (this.selectedValue) {
46
- const item = this.itemTargets.find(
47
- (i) => i.dataset.value === this.selectedValue,
48
- )
84
+ connect() {
85
+ this.orderedItems = [...this.itemTargets]
86
+ this.itemsInnerText = this.itemTargets.map((i) => i.innerText.trim())
87
+ this.fuse = new Fuse(this.itemsInnerText)
88
+ this.filteredItemIndexesValue = Array.from(
89
+ { length: this.itemTargets.length },
90
+ (_, i) => i,
91
+ )
92
+ this.isLoading = false
93
+ this.filteredItems = this.itemTargets
94
+ this.isDirty = false
95
+ this.searchPath = this.element.dataset.searchPath
96
+ setGroupLabelsId(this)
97
+ setItemsGroupId(this)
98
+ useDebounce(this)
99
+ useClickOutside(this, { element: this.contentTarget, dispatchEvent: false })
100
+ this.DOMKeydownListener = this.onDOMKeydown.bind(this)
101
+ }
49
102
 
50
- if (item && !item.dataset.disabled) {
51
- index = this.items.indexOf(item)
52
- }
103
+ toggle() {
104
+ if (this.isOpenValue) {
105
+ this.close()
106
+ } else {
107
+ this.open()
53
108
  }
109
+ }
54
110
 
55
- this.highlightItemByIndex(index)
111
+ open() {
112
+ this.isOpenValue = true
56
113
 
57
114
  setTimeout(() => {
58
115
  this.searchInputTarget.focus()
116
+
117
+ let index = 0
118
+ console.log('this.selectedValue', this.selectedValue)
119
+ if (this.selectedValue) {
120
+ const item = this.filteredItems.find(
121
+ (i) => i.dataset.value === this.selectedValue,
122
+ )
123
+
124
+ if (item && !item.dataset.disabled) {
125
+ index = this.filteredItems.indexOf(item)
126
+ }
127
+ }
128
+
129
+ this.highlightItemByIndex(index)
59
130
  }, ON_OPEN_FOCUS_DELAY)
60
131
  }
61
132
 
62
- toggle() {
63
- if (this.isOpenValue) {
64
- this.close()
133
+ close() {
134
+ this.isOpenValue = false
135
+ resetState(this)
136
+ }
137
+
138
+ scrollToItem(index: number) {
139
+ scrollToItem(this, index)
140
+ }
141
+
142
+ highlightItem(
143
+ event: MouseEvent | KeyboardEvent | null = null,
144
+ index: number | null = null,
145
+ ) {
146
+ highlightItem(this, event, index)
147
+ }
148
+
149
+ highlightItemByIndex(index: number) {
150
+ highlightItemByIndex(this, index)
151
+ }
152
+
153
+ select(event: MouseEvent | KeyboardEvent) {
154
+ let item = undefined as HTMLElement | undefined
155
+
156
+ if (event instanceof KeyboardEvent) {
157
+ item = this.filteredItems.find((i) => i.dataset.highlighted === 'true')
65
158
  } else {
66
- this.open()
159
+ // mouse event
160
+ item = event.currentTarget as HTMLElement
161
+ }
162
+
163
+ if (item) {
164
+ this.selectedValue = item.dataset.value as string
165
+
166
+ // setTimeout is needed for selectedValueChanged to finish executing
167
+ setTimeout(() => {
168
+ this.close()
169
+ }, 100)
67
170
  }
68
171
  }
69
172
 
70
- onSelect(value: string): void {
71
- this.selectedValue = value
173
+ inputKeydown(event: KeyboardEvent) {
174
+ if (event.key === ' ' && this.searchInputTarget.value.length === 0) {
175
+ event.preventDefault()
176
+ }
177
+
178
+ this.hideError()
179
+ this.showList()
180
+ }
181
+
182
+ search(event: InputEvent) {
183
+ this.isDirty = true
184
+ clearRemoteResults(this)
185
+ search(this, event)
186
+ }
187
+
188
+ clickOutside(event: MouseEvent) {
189
+ onClickOutside(this, event)
72
190
  }
73
191
 
74
192
  selectedValueChanged(value: string) {
@@ -99,7 +217,7 @@ export default class extends CommandRootController {
99
217
 
100
218
  isOpenValueChanged(isOpen: boolean, previousIsOpen: boolean) {
101
219
  if (isOpen) {
102
- lockScroll()
220
+ lockScroll(this.contentTarget.id)
103
221
 
104
222
  showContent({
105
223
  trigger: this.triggerTarget,
@@ -118,7 +236,7 @@ export default class extends CommandRootController {
118
236
 
119
237
  this.setupEventListeners()
120
238
  } else {
121
- unlockScroll()
239
+ unlockScroll(this.contentTarget.id)
122
240
 
123
241
  hideContent({
124
242
  trigger: this.triggerTarget,
@@ -126,20 +244,133 @@ export default class extends CommandRootController {
126
244
  contentContainer: this.contentContainerTarget,
127
245
  })
128
246
 
129
- this.cleanupEventListeners()
130
-
131
- // Only focus trigger when is previously opened
132
247
  if (previousIsOpen) {
133
248
  focusTrigger(this.triggerTarget)
134
249
  }
250
+
251
+ this.cleanupEventListeners()
135
252
  }
136
253
  }
137
254
 
138
- clickOutside(event: MouseEvent) {
139
- const target = event.target
140
- // Let #toggle to handle state when clicked on trigger
141
- if (target === this.triggerTarget) return
255
+ filteredItemIndexesValueChanged(filteredItemIndexes: number[]) {
256
+ filteredItemsChanged(this, filteredItemIndexes)
257
+ }
258
+
259
+ disconnect() {
260
+ this.cleanupEventListeners()
261
+ resetState(this)
262
+ }
263
+
264
+ showLoading() {
265
+ this.isLoading = true
266
+ this.loadingTarget.classList.remove('hidden')
267
+ }
268
+
269
+ hideLoading() {
270
+ this.isLoading = false
271
+ this.loadingTarget.classList.add('hidden')
272
+ }
273
+
274
+ showList() {
275
+ this.listTarget.classList.remove('hidden')
276
+ }
142
277
 
143
- this.close()
278
+ hideList() {
279
+ this.listTarget.classList.add('hidden')
280
+ }
281
+
282
+ showError() {
283
+ this.errorTarget.classList.remove('hidden')
284
+ }
285
+
286
+ hideError() {
287
+ this.errorTarget.classList.add('hidden')
288
+ }
289
+
290
+ showEmpty() {
291
+ this.emptyTarget.classList.remove('hidden')
292
+ }
293
+
294
+ hideEmpty() {
295
+ this.emptyTarget.classList.add('hidden')
296
+ }
297
+
298
+ showSelectedRemoteItems() {
299
+ const remoteItems = Array.from(
300
+ this.element.querySelectorAll(
301
+ `[data-shadcn-phlexcomponents="${this.identifier}-item"][data-remote='true']`,
302
+ ),
303
+ )
304
+
305
+ remoteItems.forEach((i) => {
306
+ const isInsideGroup =
307
+ i.parentElement?.dataset?.shadcnPhlexcomponents ===
308
+ `${this.identifier}-group`
309
+
310
+ if (isInsideGroup) {
311
+ const isRemoteGroup = i.parentElement.dataset.remote === 'true'
312
+
313
+ if (isRemoteGroup) {
314
+ i.parentElement.classList.remove('hidden')
315
+ }
316
+ }
317
+
318
+ i.ariaHidden = 'false'
319
+ i.classList.remove('hidden')
320
+ })
321
+ }
322
+
323
+ hideSelectedRemoteItems() {
324
+ const remoteItems = Array.from(
325
+ this.element.querySelectorAll(
326
+ `[data-shadcn-phlexcomponents="${this.identifier}-item"][data-remote='true']`,
327
+ ),
328
+ )
329
+
330
+ remoteItems.forEach((i) => {
331
+ const isInsideGroup =
332
+ i.parentElement?.dataset?.shadcnPhlexcomponents ===
333
+ `${this.identifier}-group`
334
+
335
+ if (isInsideGroup) {
336
+ const isRemoteGroup = i.parentElement.dataset.remote === 'true'
337
+
338
+ if (isRemoteGroup) {
339
+ i.parentElement.classList.add('hidden')
340
+ }
341
+ }
342
+
343
+ i.ariaHidden = 'true'
344
+ i.classList.add('hidden')
345
+ })
346
+ }
347
+
348
+ protected setupEventListeners() {
349
+ document.addEventListener('keydown', this.DOMKeydownListener)
350
+ }
351
+
352
+ protected cleanupEventListeners() {
353
+ document.removeEventListener('keydown', this.DOMKeydownListener)
354
+
355
+ if (this.abortController) {
356
+ this.abortController.abort()
357
+ }
358
+ }
359
+
360
+ protected onDOMKeydown(event: KeyboardEvent) {
361
+ if (!this.isOpenValue) return
362
+
363
+ const key = event.key
364
+
365
+ if (['Tab', 'Enter'].includes(key)) event.preventDefault()
366
+
367
+ if (key === 'Escape') {
368
+ this.close()
369
+ }
144
370
  }
145
371
  }
372
+
373
+ type Combobox = InstanceType<typeof ComboboxController>
374
+
375
+ export { ComboboxController }
376
+ export type { Combobox }