odt-ui-rails 2.2.4 → 2.2.5
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/README.md +21 -2
- data/app/assets/stylesheets/odt_ui/styles.css +489 -109
- data/app/assets/stylesheets/odt_ui.css +489 -109
- data/lib/generators/odt/install_generator.rb +2 -3
- data/lib/generators/odt/templates/odt_dropdown_controller.js +137 -0
- data/lib/generators/odt/templates/odt_modal_controller.js +24 -0
- data/lib/generators/odt/templates/odt_toast_controller.js +12 -0
- data/lib/generators/odt/templates/odt_toaster_controller.js +114 -0
- data/lib/generators/odt/templates/odt_ui.rbs +119 -61
- data/lib/odt_ui/engine.rb +0 -1
- data/lib/odt_ui/helper.rb +324 -282
- data/lib/odt_ui/version.rb +1 -1
- data/lib/odt_ui.rb +6 -1
- data/sig/odt_ui.rbs +119 -61
- metadata +3 -4
- data/app/assets/stylesheets/odt_ui/theme.css +0 -126
- data/app/javascript/controllers/odt_modal_controller.js +0 -61
- data/app/javascript/controllers/odt_toast_controller.js +0 -40
|
@@ -10,7 +10,6 @@ module Odt
|
|
|
10
10
|
desc "Configures ODT UI standalone stylesheets, Tailwind theme, and RBS type signatures for Rails application"
|
|
11
11
|
|
|
12
12
|
def setup_stylesheets
|
|
13
|
-
# 1. Setup Tailwind CSS v4 Theme if Tailwind is present
|
|
14
13
|
tailwind_candidates = [
|
|
15
14
|
"app/assets/tailwind/application.css",
|
|
16
15
|
"app/assets/stylesheets/application.tailwind.css"
|
|
@@ -29,12 +28,10 @@ module Odt
|
|
|
29
28
|
end
|
|
30
29
|
end
|
|
31
30
|
|
|
32
|
-
# 2. Inject stylesheet_link_tag into application.html.erb layout
|
|
33
31
|
layout_file = "app/views/layouts/application.html.erb"
|
|
34
32
|
if File.exist?(layout_file)
|
|
35
33
|
layout_content = File.read(layout_file)
|
|
36
34
|
unless layout_content.include?("odt_ui")
|
|
37
|
-
# Inject right after stylesheet_link_tag :app or in <head>
|
|
38
35
|
if layout_content.include?("<%= stylesheet_link_tag :app")
|
|
39
36
|
insert_into_file layout_file, "\n <%= stylesheet_link_tag \"odt_ui\", \"data-turbo-track\": \"reload\" %>", after: /<%= stylesheet_link_tag :app[^\n]*%>/
|
|
40
37
|
elsif layout_content.include?("<%= stylesheet_link_tag \"application\"")
|
|
@@ -56,8 +53,10 @@ module Odt
|
|
|
56
53
|
def copy_stimulus_controller
|
|
57
54
|
if File.directory?("app/javascript/controllers") || File.directory?("app/javascript")
|
|
58
55
|
empty_directory "app/javascript/controllers"
|
|
56
|
+
copy_file "odt_toaster_controller.js", "app/javascript/controllers/odt_toaster_controller.js"
|
|
59
57
|
copy_file "odt_toast_controller.js", "app/javascript/controllers/odt_toast_controller.js"
|
|
60
58
|
copy_file "odt_modal_controller.js", "app/javascript/controllers/odt_modal_controller.js"
|
|
59
|
+
copy_file "odt_dropdown_controller.js", "app/javascript/controllers/odt_dropdown_controller.js"
|
|
61
60
|
say "Copied Stimulus controllers to app/javascript/controllers/", :green
|
|
62
61
|
end
|
|
63
62
|
end
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
|
2
|
+
|
|
3
|
+
export default class extends Controller {
|
|
4
|
+
static targets = ["trigger", "content", "chevron", "hiddenInput", "text"]
|
|
5
|
+
static values = {
|
|
6
|
+
open: { type: Boolean, default: false },
|
|
7
|
+
closeOnClickOutside: { type: Boolean, default: true },
|
|
8
|
+
closeOnSelect: { type: Boolean, default: true }
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
connect() {
|
|
12
|
+
this.boundPointerDown = (event) => {
|
|
13
|
+
if (!this.openValue || !this.closeOnClickOutsideValue) return
|
|
14
|
+
if (!this.element.contains(event.target)) {
|
|
15
|
+
this.close()
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
document.addEventListener("pointerdown", this.boundPointerDown)
|
|
19
|
+
|
|
20
|
+
this.boundKeyDown = (event) => {
|
|
21
|
+
if (!this.openValue) return
|
|
22
|
+
if (event.key === "Escape") {
|
|
23
|
+
event.stopPropagation()
|
|
24
|
+
this.close()
|
|
25
|
+
if (this.hasTriggerTarget) this.triggerTarget.focus()
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
window.addEventListener("keydown", this.boundKeyDown)
|
|
29
|
+
|
|
30
|
+
if (this.openValue) {
|
|
31
|
+
this.open()
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
disconnect() {
|
|
36
|
+
if (this.boundPointerDown) {
|
|
37
|
+
document.removeEventListener("pointerdown", this.boundPointerDown)
|
|
38
|
+
}
|
|
39
|
+
if (this.boundKeyDown) {
|
|
40
|
+
window.removeEventListener("keydown", this.boundKeyDown)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
toggle(event) {
|
|
45
|
+
if (event) event.preventDefault()
|
|
46
|
+
if (this.openValue) {
|
|
47
|
+
this.close()
|
|
48
|
+
} else {
|
|
49
|
+
this.open()
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
open(event) {
|
|
54
|
+
if (event) event.preventDefault()
|
|
55
|
+
this.openValue = true
|
|
56
|
+
|
|
57
|
+
if (this.hasContentTarget) {
|
|
58
|
+
this.contentTarget.classList.remove("hidden")
|
|
59
|
+
this.contentTarget.classList.remove("odt-dropdown__content--exiting")
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (this.hasTriggerTarget) {
|
|
63
|
+
this.triggerTarget.classList.add("odt-dropdown__trigger--open")
|
|
64
|
+
this.triggerTarget.setAttribute("aria-expanded", "true")
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (this.hasChevronTarget) {
|
|
68
|
+
this.chevronTarget.classList.add("odt-dropdown__chevron--open")
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
this.element.dispatchEvent(new CustomEvent("odt-dropdown:opened", { bubbles: true }))
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
close(event) {
|
|
75
|
+
if (event) event.preventDefault()
|
|
76
|
+
this.openValue = false
|
|
77
|
+
|
|
78
|
+
if (this.hasTriggerTarget) {
|
|
79
|
+
this.triggerTarget.classList.remove("odt-dropdown__trigger--open")
|
|
80
|
+
this.triggerTarget.setAttribute("aria-expanded", "false")
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (this.hasChevronTarget) {
|
|
84
|
+
this.chevronTarget.classList.remove("odt-dropdown__chevron--open")
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (this.hasContentTarget) {
|
|
88
|
+
this.contentTarget.classList.add("odt-dropdown__content--exiting")
|
|
89
|
+
setTimeout(() => {
|
|
90
|
+
this.contentTarget.classList.add("hidden")
|
|
91
|
+
this.contentTarget.classList.remove("odt-dropdown__content--exiting")
|
|
92
|
+
this.element.dispatchEvent(new CustomEvent("odt-dropdown:closed", { bubbles: true }))
|
|
93
|
+
}, 110)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
select(event) {
|
|
98
|
+
const item = event.currentTarget
|
|
99
|
+
const value = item.dataset.value
|
|
100
|
+
const label = item.dataset.label || item.textContent.trim()
|
|
101
|
+
|
|
102
|
+
if (this.hasHiddenInputTarget && value !== undefined) {
|
|
103
|
+
this.hiddenInputTarget.value = value
|
|
104
|
+
this.hiddenInputTarget.dispatchEvent(new Event("change", { bubbles: true }))
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (this.hasTextTarget && label) {
|
|
108
|
+
this.textTarget.textContent = label
|
|
109
|
+
this.textTarget.classList.remove("odt-dropdown__placeholder")
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (this.closeOnSelectValue) {
|
|
113
|
+
this.close()
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
navigate(event) {
|
|
118
|
+
if (!this.hasContentTarget || !this.openValue) return
|
|
119
|
+
|
|
120
|
+
const items = Array.from(
|
|
121
|
+
this.contentTarget.querySelectorAll('[role="menuitem"]:not([disabled]):not(.odt-dropdown__item--disabled)')
|
|
122
|
+
)
|
|
123
|
+
if (!items.length) return
|
|
124
|
+
|
|
125
|
+
const activeIndex = items.indexOf(document.activeElement)
|
|
126
|
+
|
|
127
|
+
if (event.key === "ArrowDown") {
|
|
128
|
+
event.preventDefault()
|
|
129
|
+
const nextIndex = activeIndex < items.length - 1 ? activeIndex + 1 : 0
|
|
130
|
+
items[nextIndex]?.focus()
|
|
131
|
+
} else if (event.key === "ArrowUp") {
|
|
132
|
+
event.preventDefault()
|
|
133
|
+
const prevIndex = activeIndex > 0 ? activeIndex - 1 : items.length - 1
|
|
134
|
+
items[prevIndex]?.focus()
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -8,6 +8,24 @@ export default class extends Controller {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
connect() {
|
|
11
|
+
if (this.element.id) {
|
|
12
|
+
this.boundTriggerHandler = (event) => {
|
|
13
|
+
const trigger = event.target.closest(`[data-odt-modal-target-id="${this.element.id}"], [data-modal-target="${this.element.id}"], [href="#${this.element.id}"]`)
|
|
14
|
+
if (trigger) {
|
|
15
|
+
event.preventDefault()
|
|
16
|
+
this.open()
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
document.addEventListener("click", this.boundTriggerHandler)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
this.boundTurboSubmitHandler = (event) => {
|
|
23
|
+
if (event.detail?.success && this.element.contains(event.target)) {
|
|
24
|
+
this.close()
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
this.element.addEventListener("turbo:submit-end", this.boundTurboSubmitHandler)
|
|
28
|
+
|
|
11
29
|
if (this.openValue) {
|
|
12
30
|
this.open()
|
|
13
31
|
}
|
|
@@ -57,5 +75,11 @@ export default class extends Controller {
|
|
|
57
75
|
|
|
58
76
|
disconnect() {
|
|
59
77
|
document.body.style.overflow = ""
|
|
78
|
+
if (this.boundTriggerHandler) {
|
|
79
|
+
document.removeEventListener("click", this.boundTriggerHandler)
|
|
80
|
+
}
|
|
81
|
+
if (this.boundTurboSubmitHandler) {
|
|
82
|
+
this.element.removeEventListener("turbo:submit-end", this.boundTurboSubmitHandler)
|
|
83
|
+
}
|
|
60
84
|
}
|
|
61
85
|
}
|
|
@@ -7,6 +7,7 @@ export default class extends Controller {
|
|
|
7
7
|
|
|
8
8
|
connect() {
|
|
9
9
|
this.startTimer()
|
|
10
|
+
this.notifyToaster()
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
startTimer() {
|
|
@@ -26,11 +27,22 @@ export default class extends Controller {
|
|
|
26
27
|
this.startTimer()
|
|
27
28
|
}
|
|
28
29
|
|
|
30
|
+
notifyToaster() {
|
|
31
|
+
const toaster = this.element.closest("[data-controller~='odt-toaster']")
|
|
32
|
+
if (toaster) {
|
|
33
|
+
const toasterController = this.application.getControllerForElementAndIdentifier(toaster, "odt-toaster")
|
|
34
|
+
toasterController?.updateStack()
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
29
38
|
dismiss() {
|
|
30
39
|
this.pauseTimer()
|
|
31
40
|
this.element.classList.add("odt-toast--exiting")
|
|
41
|
+
this.notifyToaster()
|
|
42
|
+
|
|
32
43
|
setTimeout(() => {
|
|
33
44
|
this.element.remove()
|
|
45
|
+
this.notifyToaster()
|
|
34
46
|
}, 250)
|
|
35
47
|
}
|
|
36
48
|
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
|
2
|
+
|
|
3
|
+
export default class extends Controller {
|
|
4
|
+
static values = {
|
|
5
|
+
position: { type: String, default: "top-right" },
|
|
6
|
+
expand: { type: Boolean, default: true }
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
connect() {
|
|
10
|
+
this.isHovered = false
|
|
11
|
+
this.leaveTimeout = null
|
|
12
|
+
this.mutationObserver = new MutationObserver(() => this.handleMutations())
|
|
13
|
+
this.mutationObserver.observe(this.element, { childList: true })
|
|
14
|
+
this.handleMutations()
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
disconnect() {
|
|
18
|
+
if (this.mutationObserver) {
|
|
19
|
+
this.mutationObserver.disconnect()
|
|
20
|
+
}
|
|
21
|
+
if (this.leaveTimeout) {
|
|
22
|
+
clearTimeout(this.leaveTimeout)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
handleMutations() {
|
|
27
|
+
const unmountedToasts = this.element.querySelectorAll(":scope > .odt-toast:not([data-toast-mounted]):not(.odt-toast--exiting)")
|
|
28
|
+
const isTop = this.positionValue.startsWith("top")
|
|
29
|
+
|
|
30
|
+
unmountedToasts.forEach((toast) => {
|
|
31
|
+
toast.style.transform = `translate3d(0, ${isTop ? -24 : 24}px, 0) scale(0.92)`
|
|
32
|
+
toast.style.opacity = "0"
|
|
33
|
+
toast.style.pointerEvents = "none"
|
|
34
|
+
toast.dataset.toastMounted = "pending"
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
requestAnimationFrame(() => {
|
|
38
|
+
requestAnimationFrame(() => {
|
|
39
|
+
unmountedToasts.forEach((toast) => {
|
|
40
|
+
toast.dataset.toastMounted = "true"
|
|
41
|
+
})
|
|
42
|
+
this.updateStack()
|
|
43
|
+
})
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
hover() {
|
|
48
|
+
if (!this.expandValue) return
|
|
49
|
+
if (this.leaveTimeout) {
|
|
50
|
+
clearTimeout(this.leaveTimeout)
|
|
51
|
+
this.leaveTimeout = null
|
|
52
|
+
}
|
|
53
|
+
if (!this.isHovered) {
|
|
54
|
+
this.isHovered = true
|
|
55
|
+
this.element.style.pointerEvents = "auto"
|
|
56
|
+
this.updateStack()
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
leave() {
|
|
61
|
+
if (!this.expandValue) return
|
|
62
|
+
if (this.leaveTimeout) {
|
|
63
|
+
clearTimeout(this.leaveTimeout)
|
|
64
|
+
}
|
|
65
|
+
this.leaveTimeout = setTimeout(() => {
|
|
66
|
+
this.isHovered = false
|
|
67
|
+
this.element.style.pointerEvents = "none"
|
|
68
|
+
this.updateStack()
|
|
69
|
+
}, 180)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
get toasts() {
|
|
73
|
+
return Array.from(this.element.querySelectorAll(":scope > .odt-toast:not(.odt-toast--exiting)"))
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
updateStack() {
|
|
77
|
+
const toasts = this.toasts.reverse()
|
|
78
|
+
const isTop = this.positionValue.startsWith("top")
|
|
79
|
+
const GAP = 12
|
|
80
|
+
|
|
81
|
+
let accumulatedOffset = 0
|
|
82
|
+
|
|
83
|
+
toasts.forEach((toast, index) => {
|
|
84
|
+
if (toast.dataset.toastMounted === "pending") return
|
|
85
|
+
|
|
86
|
+
const isVisible = index < 3 || this.isHovered
|
|
87
|
+
const zIndex = 50 - index
|
|
88
|
+
const stackedBaseY = isTop ? index * 14 : -(index * 14)
|
|
89
|
+
const stackedBaseScale = Math.max(0.84, 1 - index * 0.06)
|
|
90
|
+
|
|
91
|
+
let targetY = 0
|
|
92
|
+
let targetScale = 1
|
|
93
|
+
let targetOpacity = 1
|
|
94
|
+
|
|
95
|
+
if (this.isHovered) {
|
|
96
|
+
targetY = isTop ? accumulatedOffset : -accumulatedOffset
|
|
97
|
+
targetScale = 1
|
|
98
|
+
targetOpacity = isVisible ? 1 : 0
|
|
99
|
+
} else {
|
|
100
|
+
targetY = stackedBaseY
|
|
101
|
+
targetScale = stackedBaseScale
|
|
102
|
+
targetOpacity = index === 0 ? 1 : index === 1 ? 0.92 : index === 2 ? 0.75 : 0
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
toast.style.transform = `translate3d(0, ${targetY}px, 0) scale(${targetScale})`
|
|
106
|
+
toast.style.opacity = targetOpacity
|
|
107
|
+
toast.style.zIndex = zIndex
|
|
108
|
+
toast.style.pointerEvents = isVisible ? "auto" : "none"
|
|
109
|
+
|
|
110
|
+
const height = toast.offsetHeight || 64
|
|
111
|
+
accumulatedOffset += height + GAP
|
|
112
|
+
})
|
|
113
|
+
}
|
|
114
|
+
}
|
|
@@ -2,41 +2,45 @@ module OdtUi
|
|
|
2
2
|
VERSION: String
|
|
3
3
|
|
|
4
4
|
module Helper
|
|
5
|
-
type button_variant = :filled | :frosted | :capsule | :ghost
|
|
6
|
-
type button_color = :primary | :secondary | :surface | :muted | :inverse | :success | :warning | :danger | :info
|
|
7
|
-
type button_size = :
|
|
8
|
-
type radius_size = :none | :xs | :sm | :md | :lg | :xl | :"2xl" | :"3xl" | :"4xl" | :full
|
|
9
|
-
type shadow_size = :none | :card | :dropdown | :modal | :popover
|
|
10
|
-
|
|
11
|
-
type badge_variant = :subtle | :filled | :outlined
|
|
12
|
-
type badge_color = :primary | :secondary | :success | :warning | :danger | :info | :neutral
|
|
13
|
-
type badge_size = :sm | :md
|
|
14
|
-
|
|
15
|
-
type card_variant = :elevated | :outlined | :subtle | :
|
|
16
|
-
type card_background = :base | :surface | :surface_elevated | :surface_muted | :surface_subtle | :gradient_primary | :gradient_secondary | :gradient_vibrant | :gradient_hero | :frosted | :frosted_muted | :frosted_subtle | :frosted_gradient_primary | :
|
|
17
|
-
type card_border = :none | :muted | :base | :strong | :primary | :secondary | :danger | :success | bool
|
|
18
|
-
type card_padding = :none | :xs | :sm | :md | :lg | :xl | :"2xl"
|
|
19
|
-
type card_tag = :div | :article | :section | :aside | :main
|
|
20
|
-
|
|
21
|
-
type alert_variant = :success | :warning | :danger | :info
|
|
22
|
-
|
|
23
|
-
type
|
|
24
|
-
type
|
|
25
|
-
type
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
type
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
type
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
type
|
|
35
|
-
type
|
|
36
|
-
type
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
5
|
+
type button_variant = :filled | :frosted | :capsule | :ghost
|
|
6
|
+
type button_color = :primary | :secondary | :surface | :muted | :inverse | :success | :warning | :danger | :info
|
|
7
|
+
type button_size = :sm | :md | :lg
|
|
8
|
+
type radius_size = :none | :xs | :sm | :md | :lg | :xl | :"2xl" | :"3xl" | :"4xl" | :full
|
|
9
|
+
type shadow_size = :none | :card | :dropdown | :modal | :popover
|
|
10
|
+
|
|
11
|
+
type badge_variant = :subtle | :filled | :outlined
|
|
12
|
+
type badge_color = :primary | :secondary | :success | :warning | :danger | :info | :neutral
|
|
13
|
+
type badge_size = :sm | :md
|
|
14
|
+
|
|
15
|
+
type card_variant = :elevated | :outlined | :subtle | :ghost
|
|
16
|
+
type card_background = :base | :surface | :surface_elevated | :"surface-elevated" | :surface_muted | :"surface-muted" | :surface_subtle | :"surface-subtle" | :gradient_primary | :"gradient-primary" | :gradient_secondary | :"gradient-secondary" | :gradient_vibrant | :"gradient-vibrant" | :gradient_hero | :"gradient-hero" | :frosted | :frosted_muted | :"frosted-muted" | :frosted_subtle | :"frosted-subtle" | :frosted_gradient_primary | :"frosted-gradient-primary" | :frosted_gradient_secondary | :"frosted-gradient-secondary" | :transparent
|
|
17
|
+
type card_border = :none | :muted | :base | :strong | :primary | :secondary | :danger | :success | bool
|
|
18
|
+
type card_padding = :none | :xs | :sm | :md | :lg | :xl | :"2xl"
|
|
19
|
+
type card_tag = :div | :article | :section | :aside | :main
|
|
20
|
+
|
|
21
|
+
type alert_variant = :success | :warning | :danger | :info
|
|
22
|
+
|
|
23
|
+
type heading_tag = :h1 | :h2 | :h3 | :h4 | :h5 | :h6
|
|
24
|
+
type heading_size = :"5xl" | :"4xl" | :"3xl" | :"2xl" | :xl | :lg
|
|
25
|
+
type font_weight = :light | :normal | :medium | :semibold | :bold | :extrabold
|
|
26
|
+
type typography_color = :strong | :default | :muted | :subtle | :disabled | :inverse | :"inverse-strong" | :inverse_strong | :"inverse-muted" | :inverse_muted | :"inverse-subtle" | :inverse_subtle | :"inverse-disabled" | :inverse_disabled | :primary | :secondary | :success | :warning | :danger | :info
|
|
27
|
+
|
|
28
|
+
type text_tag = :p | :span | :div | :label | :small
|
|
29
|
+
type text_size = :xs | :sm | :base | :lg | :xl | :"2xl"
|
|
30
|
+
|
|
31
|
+
type avatar_size = :xs | :sm | :md | :lg | :xl | :"2xl"
|
|
32
|
+
type avatar_color = :primary | :secondary | :neutral
|
|
33
|
+
|
|
34
|
+
type input_variant = :outlined | :filled | :frosted | :unstyled
|
|
35
|
+
type input_size = :sm | :md | :lg
|
|
36
|
+
type input_resize = :none | :vertical | :horizontal | :both
|
|
37
|
+
|
|
38
|
+
type checkbox_color = :primary | :secondary | :success | :warning | :danger | :dark
|
|
39
|
+
type checkbox_size = :sm | :md | :lg
|
|
40
|
+
type radio_color = :primary | :secondary | :success | :warning | :danger | :dark
|
|
41
|
+
type radio_size = :sm | :md | :lg
|
|
42
|
+
type radio_orientation = :horizontal | :vertical
|
|
43
|
+
|
|
40
44
|
def odt_button: (
|
|
41
45
|
?String? text,
|
|
42
46
|
?variant: button_variant,
|
|
@@ -55,7 +59,6 @@ module OdtUi
|
|
|
55
59
|
**untyped
|
|
56
60
|
) ?{ () -> untyped } -> untyped
|
|
57
61
|
|
|
58
|
-
# Renders an ODT Badge component.
|
|
59
62
|
def odt_badge: (
|
|
60
63
|
?String? text,
|
|
61
64
|
?variant: badge_variant,
|
|
@@ -67,7 +70,6 @@ module OdtUi
|
|
|
67
70
|
**untyped
|
|
68
71
|
) ?{ () -> untyped } -> untyped
|
|
69
72
|
|
|
70
|
-
# Renders an ODT Card component.
|
|
71
73
|
def odt_card: (
|
|
72
74
|
?title: String?,
|
|
73
75
|
?subtitle: String?,
|
|
@@ -83,7 +85,6 @@ module OdtUi
|
|
|
83
85
|
**untyped
|
|
84
86
|
) ?{ () -> untyped } -> untyped
|
|
85
87
|
|
|
86
|
-
# Renders an ODT Alert banner.
|
|
87
88
|
def odt_alert: (
|
|
88
89
|
?String? message,
|
|
89
90
|
?variant: alert_variant,
|
|
@@ -91,7 +92,6 @@ module OdtUi
|
|
|
91
92
|
**untyped
|
|
92
93
|
) ?{ () -> untyped } -> untyped
|
|
93
94
|
|
|
94
|
-
# Renders an ODT Heading element.
|
|
95
95
|
def odt_heading: (
|
|
96
96
|
?String? text,
|
|
97
97
|
?as: heading_tag,
|
|
@@ -102,7 +102,6 @@ module OdtUi
|
|
|
102
102
|
**untyped
|
|
103
103
|
) ?{ () -> untyped } -> untyped
|
|
104
104
|
|
|
105
|
-
# Renders styled body text.
|
|
106
105
|
def odt_text: (
|
|
107
106
|
?String? text,
|
|
108
107
|
?as: text_tag,
|
|
@@ -113,18 +112,16 @@ module OdtUi
|
|
|
113
112
|
**untyped
|
|
114
113
|
) ?{ () -> untyped } -> untyped
|
|
115
114
|
|
|
116
|
-
# Renders an ODT Avatar element.
|
|
117
115
|
def odt_avatar: (
|
|
118
116
|
?name: String?,
|
|
119
117
|
?src: String?,
|
|
120
118
|
?size: avatar_size,
|
|
121
119
|
?color: avatar_color,
|
|
122
|
-
?icon: String
|
|
120
|
+
?icon: String?,
|
|
123
121
|
?fallback: String?,
|
|
124
122
|
**untyped
|
|
125
123
|
) -> untyped
|
|
126
124
|
|
|
127
|
-
# Renders a styled input field.
|
|
128
125
|
def odt_input: (
|
|
129
126
|
?label: String?,
|
|
130
127
|
?variant: input_variant,
|
|
@@ -147,7 +144,6 @@ module OdtUi
|
|
|
147
144
|
**untyped
|
|
148
145
|
) -> untyped
|
|
149
146
|
|
|
150
|
-
# Renders a styled textarea field.
|
|
151
147
|
def odt_textarea: (
|
|
152
148
|
?label: String?,
|
|
153
149
|
?variant: input_variant,
|
|
@@ -164,7 +160,6 @@ module OdtUi
|
|
|
164
160
|
**untyped
|
|
165
161
|
) ?{ () -> untyped } -> untyped
|
|
166
162
|
|
|
167
|
-
# Renders a styled native <select> dropdown.
|
|
168
163
|
def odt_select: (
|
|
169
164
|
?label: String?,
|
|
170
165
|
?options: untyped,
|
|
@@ -181,7 +176,6 @@ module OdtUi
|
|
|
181
176
|
**untyped
|
|
182
177
|
) -> untyped
|
|
183
178
|
|
|
184
|
-
# Renders a styled checkbox.
|
|
185
179
|
def odt_checkbox: (
|
|
186
180
|
?label: String?,
|
|
187
181
|
?description: String?,
|
|
@@ -194,19 +188,17 @@ module OdtUi
|
|
|
194
188
|
**untyped
|
|
195
189
|
) -> untyped
|
|
196
190
|
|
|
197
|
-
# Renders a styled radio button.
|
|
198
191
|
def odt_radio: (
|
|
199
192
|
?label: String?,
|
|
200
193
|
?description: String?,
|
|
201
194
|
?checked: bool,
|
|
202
|
-
?color:
|
|
203
|
-
?size:
|
|
195
|
+
?color: radio_color,
|
|
196
|
+
?size: radio_size,
|
|
204
197
|
?disabled: bool,
|
|
205
198
|
?error: String?,
|
|
206
199
|
**untyped
|
|
207
200
|
) -> untyped
|
|
208
201
|
|
|
209
|
-
# Renders a form field wrapper.
|
|
210
202
|
def odt_form_group: (
|
|
211
203
|
?label: String?,
|
|
212
204
|
?error: String?,
|
|
@@ -217,48 +209,49 @@ module OdtUi
|
|
|
217
209
|
**untyped
|
|
218
210
|
) ?{ () -> untyped } -> untyped
|
|
219
211
|
|
|
220
|
-
type toaster_position = :top_right | :top_center | :top_left | :bottom_right | :bottom_center | :
|
|
221
|
-
type toast_variant = :
|
|
212
|
+
type toaster_position = :top_right | :"top-right" | :top_center | :"top-center" | :top_left | :"top-left" | :bottom_right | :"bottom-right" | :bottom_center | :"bottom-center" | :bottom_left | :"bottom-left"
|
|
213
|
+
type toast_variant = :elevated | :frosted | :subtle | :outlined
|
|
214
|
+
type toast_type = :default | :success | :warning | :danger | :error | :info | :loading
|
|
222
215
|
|
|
223
|
-
# Renders an ODT Toaster viewport container.
|
|
224
216
|
def odt_toaster: (
|
|
225
217
|
?position: toaster_position,
|
|
226
218
|
?id: String,
|
|
219
|
+
?expand: bool,
|
|
227
220
|
**untyped
|
|
228
221
|
) ?{ () -> untyped } -> untyped
|
|
229
222
|
|
|
230
|
-
# Renders a single ODT Toast card.
|
|
231
223
|
def odt_toast: (
|
|
232
224
|
?String? message,
|
|
233
225
|
?title: String?,
|
|
234
226
|
?variant: toast_variant,
|
|
227
|
+
?type: toast_type,
|
|
235
228
|
?icon: String?,
|
|
236
229
|
?duration: Integer,
|
|
237
230
|
?dismissible: bool,
|
|
238
231
|
?radius: radius_size?,
|
|
232
|
+
?rich_colors: bool,
|
|
239
233
|
**untyped
|
|
240
234
|
) ?{ () -> untyped } -> untyped
|
|
241
235
|
|
|
242
|
-
# Renders active flash messages as ODT Toasts.
|
|
243
236
|
def odt_flash_toasts: (
|
|
244
237
|
?untyped flash_hash,
|
|
245
238
|
?duration: Integer
|
|
246
239
|
) -> untyped
|
|
247
240
|
|
|
248
|
-
# Generates a Turbo Stream action for a toast.
|
|
249
241
|
def odt_toast_stream: (
|
|
250
242
|
?String? message,
|
|
251
243
|
?title: String?,
|
|
252
244
|
?variant: toast_variant,
|
|
245
|
+
?type: toast_type,
|
|
253
246
|
?target: String,
|
|
254
247
|
?action: Symbol | String,
|
|
255
248
|
?duration: Integer,
|
|
249
|
+
?rich_colors: bool,
|
|
256
250
|
**untyped
|
|
257
251
|
) -> untyped
|
|
258
252
|
|
|
259
|
-
type modal_size = :sm | :md | :lg | :xl | :full
|
|
253
|
+
type modal_size = :sm | :md | :lg | :xl | :full
|
|
260
254
|
|
|
261
|
-
# Renders an ODT Modal dialog container.
|
|
262
255
|
def odt_modal: (
|
|
263
256
|
?id: String?,
|
|
264
257
|
?title: String?,
|
|
@@ -271,7 +264,6 @@ module OdtUi
|
|
|
271
264
|
**untyped
|
|
272
265
|
) ?{ () -> untyped } -> untyped
|
|
273
266
|
|
|
274
|
-
# Renders an ODT Modal Header subcomponent.
|
|
275
267
|
def odt_modal_header: (
|
|
276
268
|
?title: String?,
|
|
277
269
|
?subtitle: String?,
|
|
@@ -279,15 +271,81 @@ module OdtUi
|
|
|
279
271
|
**untyped
|
|
280
272
|
) ?{ () -> untyped } -> untyped
|
|
281
273
|
|
|
282
|
-
# Renders an ODT Modal Body subcomponent.
|
|
283
274
|
def odt_modal_body: (
|
|
284
275
|
**untyped
|
|
285
276
|
) ?{ () -> untyped } -> untyped
|
|
286
277
|
|
|
287
|
-
# Renders an ODT Modal Footer subcomponent.
|
|
288
278
|
def odt_modal_footer: (
|
|
289
279
|
**untyped
|
|
290
280
|
) ?{ () -> untyped } -> untyped
|
|
281
|
+
|
|
282
|
+
type dropdown_align = :start | :center | :end
|
|
283
|
+
type dropdown_side = :bottom | :top | :left | :right
|
|
284
|
+
type dropdown_variant = :outlined | :filled | :frosted
|
|
285
|
+
type dropdown_size = :sm | :md | :lg
|
|
286
|
+
|
|
287
|
+
def odt_dropdown_menu: (
|
|
288
|
+
?open: bool,
|
|
289
|
+
?close_on_click_outside: bool,
|
|
290
|
+
?close_on_select: bool,
|
|
291
|
+
?full_width: bool,
|
|
292
|
+
**untyped
|
|
293
|
+
) ?{ () -> untyped } -> untyped
|
|
294
|
+
|
|
295
|
+
def odt_dropdown_trigger: (
|
|
296
|
+
?String? text,
|
|
297
|
+
?label: String?,
|
|
298
|
+
?helper: String?,
|
|
299
|
+
?helper_text: String?,
|
|
300
|
+
?error: String?,
|
|
301
|
+
?variant: dropdown_variant,
|
|
302
|
+
?size: dropdown_size,
|
|
303
|
+
?radius: radius_size?,
|
|
304
|
+
?chevron: bool,
|
|
305
|
+
?placeholder: String?,
|
|
306
|
+
?left_icon: String?,
|
|
307
|
+
?right_icon: String?,
|
|
308
|
+
?full_width: bool,
|
|
309
|
+
?disabled: bool,
|
|
310
|
+
**untyped
|
|
311
|
+
) ?{ () -> untyped } -> untyped
|
|
312
|
+
|
|
313
|
+
def odt_dropdown_content: (
|
|
314
|
+
?align: dropdown_align,
|
|
315
|
+
?side: dropdown_side,
|
|
316
|
+
?radius: radius_size?,
|
|
317
|
+
?shadow: shadow_size?,
|
|
318
|
+
?full_width: bool,
|
|
319
|
+
**untyped
|
|
320
|
+
) ?{ () -> untyped } -> untyped
|
|
321
|
+
|
|
322
|
+
def odt_dropdown_item: (
|
|
323
|
+
?String? text,
|
|
324
|
+
?href: String?,
|
|
325
|
+
?left_icon: String?,
|
|
326
|
+
?right_icon: String?,
|
|
327
|
+
?shortcut: String?,
|
|
328
|
+
?destructive: bool,
|
|
329
|
+
?disabled: bool,
|
|
330
|
+
?inset: bool,
|
|
331
|
+
?value: String?,
|
|
332
|
+
**untyped
|
|
333
|
+
) ?{ () -> untyped } -> untyped
|
|
334
|
+
|
|
335
|
+
def odt_dropdown_label: (
|
|
336
|
+
?String? text,
|
|
337
|
+
?inset: bool,
|
|
338
|
+
**untyped
|
|
339
|
+
) ?{ () -> untyped } -> untyped
|
|
340
|
+
|
|
341
|
+
def odt_dropdown_separator: (
|
|
342
|
+
**untyped
|
|
343
|
+
) -> untyped
|
|
344
|
+
|
|
345
|
+
def odt_dropdown_shortcut: (
|
|
346
|
+
?String? text,
|
|
347
|
+
**untyped
|
|
348
|
+
) ?{ () -> untyped } -> untyped
|
|
291
349
|
end
|
|
292
350
|
end
|
|
293
351
|
|
data/lib/odt_ui/engine.rb
CHANGED
|
@@ -7,7 +7,6 @@ module OdtUi
|
|
|
7
7
|
initializer "odt_ui.assets" do |app|
|
|
8
8
|
if app.config.respond_to?(:assets) && app.config.assets.respond_to?(:paths)
|
|
9
9
|
app.config.assets.paths << root.join("app/assets/stylesheets").to_s
|
|
10
|
-
app.config.assets.paths << root.join("app/javascript").to_s if root.join("app/javascript").exist?
|
|
11
10
|
end
|
|
12
11
|
end
|
|
13
12
|
|