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.
- checksums.yaml +4 -4
- data/app/javascript/controllers/accordion_controller.ts +65 -62
- data/app/javascript/controllers/alert_dialog_controller.ts +12 -0
- data/app/javascript/controllers/avatar_controller.ts +7 -2
- data/app/javascript/controllers/checkbox_controller.ts +11 -4
- data/app/javascript/controllers/collapsible_controller.ts +12 -5
- data/app/javascript/controllers/combobox_controller.ts +270 -39
- data/app/javascript/controllers/command_controller.ts +223 -51
- data/app/javascript/controllers/date_picker_controller.ts +185 -125
- data/app/javascript/controllers/date_range_picker_controller.ts +89 -79
- data/app/javascript/controllers/dialog_controller.ts +59 -57
- data/app/javascript/controllers/dropdown_menu_controller.ts +212 -36
- data/app/javascript/controllers/dropdown_menu_sub_controller.ts +31 -29
- data/app/javascript/controllers/form_field_controller.ts +6 -1
- data/app/javascript/controllers/hover_card_controller.ts +36 -26
- data/app/javascript/controllers/loading_button_controller.ts +6 -1
- data/app/javascript/controllers/popover_controller.ts +42 -65
- data/app/javascript/controllers/progress_controller.ts +9 -3
- data/app/javascript/controllers/radio_group_controller.ts +16 -9
- data/app/javascript/controllers/select_controller.ts +206 -65
- data/app/javascript/controllers/slider_controller.ts +23 -16
- data/app/javascript/controllers/switch_controller.ts +11 -4
- data/app/javascript/controllers/tabs_controller.ts +26 -18
- data/app/javascript/controllers/theme_switcher_controller.ts +6 -1
- data/app/javascript/controllers/toast_container_controller.ts +6 -1
- data/app/javascript/controllers/toast_controller.ts +7 -1
- data/app/javascript/controllers/toggle_controller.ts +28 -0
- data/app/javascript/controllers/toggle_group_controller.ts +28 -0
- data/app/javascript/controllers/tooltip_controller.ts +43 -31
- data/app/javascript/shadcn_phlexcomponents.ts +29 -25
- data/app/javascript/utils/command.ts +544 -0
- data/app/javascript/utils/floating_ui.ts +196 -0
- data/app/javascript/utils/index.ts +417 -0
- data/app/stylesheets/date_picker.css +118 -0
- data/lib/shadcn_phlexcomponents/alias.rb +3 -0
- data/lib/shadcn_phlexcomponents/components/accordion.rb +2 -1
- data/lib/shadcn_phlexcomponents/components/alert_dialog.rb +18 -15
- data/lib/shadcn_phlexcomponents/components/base.rb +14 -0
- data/lib/shadcn_phlexcomponents/components/collapsible.rb +1 -2
- data/lib/shadcn_phlexcomponents/components/combobox.rb +87 -57
- data/lib/shadcn_phlexcomponents/components/command.rb +77 -47
- data/lib/shadcn_phlexcomponents/components/date_picker.rb +25 -81
- data/lib/shadcn_phlexcomponents/components/date_range_picker.rb +21 -4
- data/lib/shadcn_phlexcomponents/components/dialog.rb +14 -12
- data/lib/shadcn_phlexcomponents/components/dropdown_menu.rb +5 -4
- data/lib/shadcn_phlexcomponents/components/dropdown_menu_sub.rb +2 -1
- data/lib/shadcn_phlexcomponents/components/form/form_combobox.rb +64 -0
- data/lib/shadcn_phlexcomponents/components/form.rb +14 -0
- data/lib/shadcn_phlexcomponents/components/hover_card.rb +3 -2
- data/lib/shadcn_phlexcomponents/components/popover.rb +3 -3
- data/lib/shadcn_phlexcomponents/components/select.rb +10 -25
- data/lib/shadcn_phlexcomponents/components/sheet.rb +15 -11
- data/lib/shadcn_phlexcomponents/components/table.rb +1 -1
- data/lib/shadcn_phlexcomponents/components/tabs.rb +1 -1
- data/lib/shadcn_phlexcomponents/components/toast_container.rb +1 -1
- data/lib/shadcn_phlexcomponents/components/toggle.rb +54 -0
- data/lib/shadcn_phlexcomponents/components/tooltip.rb +3 -2
- data/lib/shadcn_phlexcomponents/engine.rb +1 -5
- data/lib/shadcn_phlexcomponents/version.rb +1 -1
- metadata +9 -4
- data/app/javascript/controllers/command_root_controller.ts +0 -355
- data/app/javascript/controllers/dropdown_menu_root_controller.ts +0 -234
- data/app/javascript/utils.ts +0 -437
@@ -1,20 +1,25 @@
|
|
1
1
|
import { Controller } from '@hotwired/stimulus'
|
2
2
|
import { useHover } from 'stimulus-use'
|
3
|
-
import { initFloatingUi
|
3
|
+
import { initFloatingUi } from '../utils/floating_ui'
|
4
|
+
import { showContent, hideContent } from '../utils'
|
4
5
|
|
5
|
-
|
6
|
+
const HoverCardController = class extends Controller<HTMLElement> {
|
7
|
+
// targets
|
6
8
|
static targets = ['trigger', 'content', 'contentContainer']
|
9
|
+
declare readonly triggerTarget: HTMLElement
|
10
|
+
declare readonly contentTarget: HTMLElement
|
11
|
+
declare readonly contentContainerTarget: HTMLElement
|
12
|
+
|
13
|
+
// values
|
7
14
|
static values = {
|
8
15
|
isOpen: Boolean,
|
9
16
|
}
|
10
|
-
|
11
17
|
declare isOpenValue: boolean
|
12
|
-
|
13
|
-
|
14
|
-
declare readonly contentContainerTarget: HTMLElement
|
15
|
-
declare cleanup: () => void
|
18
|
+
|
19
|
+
// custom properties
|
16
20
|
declare closeTimeout: number
|
17
21
|
declare DOMKeydownListener: (event: KeyboardEvent) => void
|
22
|
+
declare cleanup: () => void
|
18
23
|
|
19
24
|
connect() {
|
20
25
|
this.DOMKeydownListener = this.onDOMKeydown.bind(this)
|
@@ -42,25 +47,6 @@ export default class extends Controller<HTMLElement> {
|
|
42
47
|
this.close()
|
43
48
|
}
|
44
49
|
|
45
|
-
setupEventListeners() {
|
46
|
-
document.addEventListener('keydown', this.DOMKeydownListener)
|
47
|
-
}
|
48
|
-
|
49
|
-
cleanupEventListeners() {
|
50
|
-
if (this.cleanup) this.cleanup()
|
51
|
-
document.removeEventListener('keydown', this.DOMKeydownListener)
|
52
|
-
}
|
53
|
-
|
54
|
-
onDOMKeydown(event: KeyboardEvent) {
|
55
|
-
if (!this.isOpenValue) return
|
56
|
-
|
57
|
-
const key = event.key
|
58
|
-
|
59
|
-
if (key === 'Escape') {
|
60
|
-
this.close()
|
61
|
-
}
|
62
|
-
}
|
63
|
-
|
64
50
|
isOpenValueChanged(isOpen: boolean) {
|
65
51
|
if (isOpen) {
|
66
52
|
showContent({
|
@@ -90,4 +76,28 @@ export default class extends Controller<HTMLElement> {
|
|
90
76
|
disconnect() {
|
91
77
|
this.cleanupEventListeners()
|
92
78
|
}
|
79
|
+
|
80
|
+
protected setupEventListeners() {
|
81
|
+
document.addEventListener('keydown', this.DOMKeydownListener)
|
82
|
+
}
|
83
|
+
|
84
|
+
protected cleanupEventListeners() {
|
85
|
+
if (this.cleanup) this.cleanup()
|
86
|
+
document.removeEventListener('keydown', this.DOMKeydownListener)
|
87
|
+
}
|
88
|
+
|
89
|
+
protected onDOMKeydown(event: KeyboardEvent) {
|
90
|
+
if (!this.isOpenValue) return
|
91
|
+
|
92
|
+
const key = event.key
|
93
|
+
|
94
|
+
if (key === 'Escape') {
|
95
|
+
this.close()
|
96
|
+
}
|
97
|
+
}
|
93
98
|
}
|
99
|
+
|
100
|
+
type HoverCard = InstanceType<typeof HoverCardController>
|
101
|
+
|
102
|
+
export { HoverCardController }
|
103
|
+
export type { HoverCard }
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import { Controller } from '@hotwired/stimulus'
|
2
2
|
|
3
|
-
|
3
|
+
const LoadingButtonController = class extends Controller<HTMLButtonElement> {
|
4
4
|
connect() {
|
5
5
|
const el = this.element
|
6
6
|
const form = el.closest('form')
|
@@ -13,3 +13,8 @@ export default class extends Controller<HTMLButtonElement> {
|
|
13
13
|
}
|
14
14
|
}
|
15
15
|
}
|
16
|
+
|
17
|
+
type LoadingButton = InstanceType<typeof LoadingButtonController>
|
18
|
+
|
19
|
+
export { LoadingButtonController }
|
20
|
+
export type { LoadingButton }
|
@@ -1,22 +1,28 @@
|
|
1
1
|
import { Controller } from '@hotwired/stimulus'
|
2
2
|
import { useClickOutside } from 'stimulus-use'
|
3
|
+
import { initFloatingUi } from '../utils/floating_ui'
|
3
4
|
import {
|
4
|
-
initFloatingUi,
|
5
5
|
focusTrigger,
|
6
|
-
ON_OPEN_FOCUS_DELAY,
|
7
6
|
getFocusableElements,
|
8
7
|
showContent,
|
9
8
|
hideContent,
|
9
|
+
onClickOutside,
|
10
|
+
handleTabNavigation,
|
11
|
+
focusElement,
|
10
12
|
} from '../utils'
|
11
13
|
|
12
|
-
|
14
|
+
const PopoverController = class extends Controller<HTMLElement> {
|
15
|
+
// targets
|
13
16
|
static targets = ['trigger', 'contentContainer', 'content']
|
14
|
-
static values = { isOpen: Boolean }
|
15
|
-
|
16
|
-
declare isOpenValue: boolean
|
17
17
|
declare readonly triggerTarget: HTMLElement
|
18
18
|
declare readonly contentContainerTarget: HTMLElement
|
19
19
|
declare readonly contentTarget: HTMLElement
|
20
|
+
|
21
|
+
// values
|
22
|
+
static values = { isOpen: Boolean }
|
23
|
+
declare isOpenValue: boolean
|
24
|
+
|
25
|
+
// custom properties
|
20
26
|
declare DOMKeydownListener: (event: KeyboardEvent) => void
|
21
27
|
declare cleanup: () => void
|
22
28
|
|
@@ -35,67 +41,18 @@ export default class extends Controller<HTMLElement> {
|
|
35
41
|
|
36
42
|
open() {
|
37
43
|
this.isOpenValue = true
|
38
|
-
this.onOpen()
|
39
|
-
|
40
|
-
setTimeout(() => {
|
41
|
-
this.onOpenFocusedElement().focus()
|
42
|
-
}, ON_OPEN_FOCUS_DELAY)
|
43
44
|
}
|
44
45
|
|
45
46
|
close() {
|
46
47
|
this.isOpenValue = false
|
47
|
-
this.onClose()
|
48
|
-
}
|
49
|
-
|
50
|
-
onDOMKeydown(event: KeyboardEvent) {
|
51
|
-
if (!this.isOpenValue) return
|
52
|
-
|
53
|
-
const key = event.key
|
54
|
-
|
55
|
-
if (key === 'Escape') {
|
56
|
-
this.close()
|
57
|
-
} else if (key === 'Tab') {
|
58
|
-
const focusableElements = getFocusableElements(this.contentTarget)
|
59
|
-
|
60
|
-
const firstElement = focusableElements[0]
|
61
|
-
const lastElement = focusableElements[focusableElements.length - 1]
|
62
|
-
|
63
|
-
// If Shift + Tab pressed on first element, go to last element
|
64
|
-
if (event.shiftKey && document.activeElement === firstElement) {
|
65
|
-
event.preventDefault()
|
66
|
-
lastElement.focus()
|
67
|
-
}
|
68
|
-
// If Tab pressed on last element, go to first element
|
69
|
-
else if (!event.shiftKey && document.activeElement === lastElement) {
|
70
|
-
event.preventDefault()
|
71
|
-
firstElement.focus()
|
72
|
-
}
|
73
|
-
}
|
74
48
|
}
|
75
49
|
|
76
50
|
clickOutside(event: MouseEvent) {
|
77
|
-
|
78
|
-
// Let #toggle to handle state when clicked on trigger
|
79
|
-
if (target === this.triggerTarget) return
|
80
|
-
|
81
|
-
this.close()
|
82
|
-
}
|
83
|
-
|
84
|
-
onOpen() {}
|
85
|
-
|
86
|
-
onOpenFocusedElement() {
|
87
|
-
const focusableElements = getFocusableElements(this.contentTarget)
|
88
|
-
return focusableElements[0]
|
89
|
-
}
|
90
|
-
|
91
|
-
onClose() {}
|
92
|
-
|
93
|
-
referenceElement() {
|
94
|
-
return this.triggerTarget
|
51
|
+
onClickOutside(this, event)
|
95
52
|
}
|
96
53
|
|
97
54
|
isOpenValueChanged(isOpen: boolean, previousIsOpen: boolean) {
|
98
|
-
if (isOpen
|
55
|
+
if (isOpen) {
|
99
56
|
showContent({
|
100
57
|
trigger: this.triggerTarget,
|
101
58
|
content: this.contentTarget,
|
@@ -103,12 +60,16 @@ export default class extends Controller<HTMLElement> {
|
|
103
60
|
})
|
104
61
|
|
105
62
|
this.cleanup = initFloatingUi({
|
106
|
-
referenceElement: this.
|
63
|
+
referenceElement: this.triggerTarget,
|
107
64
|
floatingElement: this.contentContainerTarget,
|
108
65
|
side: this.contentTarget.dataset.side,
|
109
66
|
align: this.contentTarget.dataset.align,
|
110
67
|
sideOffset: 4,
|
111
68
|
})
|
69
|
+
|
70
|
+
const focusableElements = getFocusableElements(this.contentTarget)
|
71
|
+
focusElement(focusableElements[0])
|
72
|
+
|
112
73
|
this.setupEventListeners()
|
113
74
|
} else {
|
114
75
|
hideContent({
|
@@ -117,25 +78,41 @@ export default class extends Controller<HTMLElement> {
|
|
117
78
|
contentContainer: this.contentContainerTarget,
|
118
79
|
})
|
119
80
|
|
120
|
-
this.cleanupEventListeners()
|
121
|
-
|
122
|
-
// Only focus trigger when is previously opened
|
123
81
|
if (previousIsOpen) {
|
124
82
|
focusTrigger(this.triggerTarget)
|
125
83
|
}
|
84
|
+
|
85
|
+
this.cleanupEventListeners()
|
126
86
|
}
|
127
87
|
}
|
128
88
|
|
129
|
-
|
89
|
+
disconnect() {
|
90
|
+
this.cleanupEventListeners()
|
91
|
+
}
|
92
|
+
|
93
|
+
protected setupEventListeners() {
|
130
94
|
document.addEventListener('keydown', this.DOMKeydownListener)
|
131
95
|
}
|
132
96
|
|
133
|
-
cleanupEventListeners() {
|
97
|
+
protected cleanupEventListeners() {
|
134
98
|
if (this.cleanup) this.cleanup()
|
135
99
|
document.removeEventListener('keydown', this.DOMKeydownListener)
|
136
100
|
}
|
137
101
|
|
138
|
-
|
139
|
-
this.
|
102
|
+
protected onDOMKeydown(event: KeyboardEvent) {
|
103
|
+
if (!this.isOpenValue) return
|
104
|
+
|
105
|
+
const key = event.key
|
106
|
+
|
107
|
+
if (key === 'Escape') {
|
108
|
+
this.close()
|
109
|
+
} else if (key === 'Tab') {
|
110
|
+
handleTabNavigation(this.contentTarget, event)
|
111
|
+
}
|
140
112
|
}
|
141
113
|
}
|
114
|
+
|
115
|
+
type Popover = InstanceType<typeof PopoverController>
|
116
|
+
|
117
|
+
export { PopoverController }
|
118
|
+
export type { Popover }
|
@@ -1,13 +1,14 @@
|
|
1
1
|
import { Controller } from '@hotwired/stimulus'
|
2
2
|
|
3
|
-
|
3
|
+
const ProgressController = class extends Controller {
|
4
|
+
// targets
|
4
5
|
static targets = ['indicator']
|
6
|
+
declare readonly indicatorTarget: HTMLElement
|
5
7
|
|
8
|
+
// values
|
6
9
|
static values = {
|
7
10
|
percent: Number,
|
8
11
|
}
|
9
|
-
|
10
|
-
declare readonly indicatorTarget: HTMLElement
|
11
12
|
declare percentValue: number
|
12
13
|
|
13
14
|
percentValueChanged(value: number) {
|
@@ -15,3 +16,8 @@ export default class extends Controller {
|
|
15
16
|
this.indicatorTarget.style.transform = `translateX(-${100 - value}%)`
|
16
17
|
}
|
17
18
|
}
|
19
|
+
|
20
|
+
type Progress = InstanceType<typeof ProgressController>
|
21
|
+
|
22
|
+
export { ProgressController }
|
23
|
+
export type { Progress }
|
@@ -1,14 +1,16 @@
|
|
1
1
|
import { Controller } from '@hotwired/stimulus'
|
2
2
|
|
3
|
-
|
3
|
+
const RadioGroupController = class extends Controller<HTMLElement> {
|
4
|
+
// targets
|
4
5
|
static targets = ['item', 'input', 'indicator']
|
5
|
-
static values = {
|
6
|
-
selected: String,
|
7
|
-
}
|
8
|
-
|
9
6
|
declare readonly itemTargets: HTMLInputElement[]
|
10
7
|
declare readonly inputTargets: HTMLInputElement[]
|
11
8
|
declare readonly indicatorTargets: HTMLInputElement[]
|
9
|
+
|
10
|
+
// values
|
11
|
+
static values = {
|
12
|
+
selected: String,
|
13
|
+
}
|
12
14
|
declare selectedValue: string
|
13
15
|
|
14
16
|
connect() {
|
@@ -22,10 +24,6 @@ export default class extends Controller<HTMLElement> {
|
|
22
24
|
this.selectedValue = item.dataset.value as string
|
23
25
|
}
|
24
26
|
|
25
|
-
preventDefault(event: KeyboardEvent) {
|
26
|
-
event.preventDefault()
|
27
|
-
}
|
28
|
-
|
29
27
|
selectItem(event: KeyboardEvent) {
|
30
28
|
const focusableItems = this.itemTargets.filter(
|
31
29
|
(t) => !t.disabled,
|
@@ -53,6 +51,10 @@ export default class extends Controller<HTMLElement> {
|
|
53
51
|
this.selectedValue = focusableItems[newIndex].dataset.value as string
|
54
52
|
}
|
55
53
|
|
54
|
+
preventDefault(event: KeyboardEvent) {
|
55
|
+
event.preventDefault()
|
56
|
+
}
|
57
|
+
|
56
58
|
focusItem() {
|
57
59
|
const item = this.itemTargets.find(
|
58
60
|
(i) => i.dataset.value === this.selectedValue,
|
@@ -104,3 +106,8 @@ export default class extends Controller<HTMLElement> {
|
|
104
106
|
this.focusItem()
|
105
107
|
}
|
106
108
|
}
|
109
|
+
|
110
|
+
type RadioGroup = InstanceType<typeof RadioGroupController>
|
111
|
+
|
112
|
+
export { RadioGroupController }
|
113
|
+
export type { RadioGroup }
|