fernandes-ui 0.1.4 → 0.1.6
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/assets/javascripts/ui.esm.js +0 -1
- data/app/assets/javascripts/ui.js +0 -1
- data/app/behaviors/ui/button_behavior.rb +7 -5
- data/app/behaviors/ui/button_group_behavior.rb +6 -4
- data/app/behaviors/ui/input_group_button_behavior.rb +5 -3
- data/app/components/ui/slider.rb +80 -0
- data/app/components/ui/slider_range.rb +33 -0
- data/app/components/ui/slider_thumb.rb +47 -0
- data/app/components/ui/slider_track.rb +35 -0
- data/app/javascript/ui/common.js +0 -1
- data/app/views/ui/_item.html.erb +6 -1
- data/app/views/ui/field/_label.html.erb +2 -1
- data/app/views/ui/field/_separator.html.erb +7 -1
- data/docs/components/ANNOTATIONS.md +220 -0
- data/docs/components/accordion.yml +109 -0
- data/docs/components/alert.yml +47 -0
- data/docs/components/alert_dialog.yml +151 -0
- data/docs/components/aspect_ratio.yml +37 -0
- data/docs/components/avatar.yml +55 -0
- data/docs/components/badge.yml +24 -0
- data/docs/components/breadcrumb.yml +76 -0
- data/docs/components/button.yml +56 -0
- data/docs/components/button_group.yml +67 -0
- data/docs/components/calendar.yml +166 -0
- data/docs/components/card.yml +99 -0
- data/docs/components/carousel.yml +100 -0
- data/docs/components/checkbox.yml +59 -0
- data/docs/components/collapsible.yml +74 -0
- data/docs/components/combobox.yml +21 -0
- data/docs/components/command.yml +144 -0
- data/docs/components/context_menu.yml +124 -0
- data/docs/components/dialog.yml +155 -0
- data/docs/components/drawer.yml +219 -0
- data/docs/components/dropdown_menu.yml +151 -0
- data/docs/components/empty.yml +88 -0
- data/docs/components/field.yml +81 -0
- data/docs/components/hover_card.yml +75 -0
- data/docs/components/input.yml +51 -0
- data/docs/components/input_group.yml +37 -0
- data/docs/components/input_group_addon.yml +24 -0
- data/docs/components/input_group_button.yml +30 -0
- data/docs/components/input_otp.yml +80 -0
- data/docs/components/input_otp_slot.yml +39 -0
- data/docs/components/item.yml +84 -0
- data/docs/components/kbd.yml +26 -0
- data/docs/components/label.yml +26 -0
- data/docs/components/menubar.yml +201 -0
- data/docs/components/menubar_menu.yml +21 -0
- data/docs/components/navigation_menu.yml +161 -0
- data/docs/components/pagination.yml +86 -0
- data/docs/components/popover.yml +105 -0
- data/docs/components/progress.yml +37 -0
- data/docs/components/radio_button.yml +52 -0
- data/docs/components/resizable.yml +44 -0
- data/docs/components/scroll_area.yml +76 -0
- data/docs/components/select.yml +195 -0
- data/docs/components/separator.yml +26 -0
- data/docs/components/sheet.yml +133 -0
- data/docs/components/sidebar.yml +138 -0
- data/docs/components/skeleton.yml +17 -0
- data/docs/components/sonner.yml +46 -0
- data/docs/components/spinner.yml +22 -0
- data/docs/components/switch.yml +72 -0
- data/docs/components/table.yml +32 -0
- data/docs/components/tabs.yml +126 -0
- data/docs/components/textarea.yml +41 -0
- data/docs/components/toggle.yml +92 -0
- data/docs/components/toggle_group.yml +106 -0
- data/docs/components/tooltip.yml +75 -0
- data/lib/ui/version.rb +1 -1
- metadata +61 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: cd5c1b0e4c8f243753ae87b5ed616c6ec1bb5d654f9b36e4cd2a9d93d92afd3c
|
|
4
|
+
data.tar.gz: 12badc6858a2551334c142f8b99a5b896787f66e998a037e0e9caece9e84ed9d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dcce7dc49c2dcd0c1ca3fedcb8032c93ecc311bfa34a18d4a9f343b5d4d591c667b9ef7e835cdf512f215ee64d448b18699c7474e7ed6f472e57dcf6b57efed1
|
|
7
|
+
data.tar.gz: b35eb71c9ba0e9a53fc5a10eb3b9c372132ec1e3aa29c7f942afae622a53db8b5f9590cab1f9c8f0b2c04e2358f3c00b0392300132a277ef651c54c8b81147b5
|
|
@@ -14341,7 +14341,6 @@ function registerControllersInto(application, controllers) {
|
|
|
14341
14341
|
for (const [name, controller] of Object.entries(controllers)) {
|
|
14342
14342
|
try {
|
|
14343
14343
|
application.register(name, controller);
|
|
14344
|
-
console.log(`Registered Stimulus controller: ${name}`);
|
|
14345
14344
|
} catch (error) {
|
|
14346
14345
|
console.error(`Failed to register controller ${name}:`, error);
|
|
14347
14346
|
}
|
|
@@ -13913,7 +13913,6 @@
|
|
|
13913
13913
|
for (const [name, controller] of Object.entries(controllers)) {
|
|
13914
13914
|
try {
|
|
13915
13915
|
application.register(name, controller);
|
|
13916
|
-
console.log(`Registered Stimulus controller: ${name}`);
|
|
13917
13916
|
} catch (error) {
|
|
13918
13917
|
console.error(`Failed to register controller ${name}:`, error);
|
|
13919
13918
|
}
|
|
@@ -66,7 +66,7 @@ module UI::ButtonBehavior
|
|
|
66
66
|
|
|
67
67
|
# Base classes applied to all buttons
|
|
68
68
|
def button_base_classes
|
|
69
|
-
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-
|
|
69
|
+
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-[var(--radius,0.5rem)] text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive has-[>svg]:px-3"
|
|
70
70
|
end
|
|
71
71
|
|
|
72
72
|
# Variant-specific classes based on @variant
|
|
@@ -77,7 +77,7 @@ module UI::ButtonBehavior
|
|
|
77
77
|
when "destructive"
|
|
78
78
|
"bg-destructive text-destructive-foreground hover:bg-destructive/90 text-white"
|
|
79
79
|
when "outline"
|
|
80
|
-
"
|
|
80
|
+
"border border-input bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:hover:bg-input/50"
|
|
81
81
|
when "secondary"
|
|
82
82
|
"bg-secondary text-secondary-foreground hover:bg-secondary/80"
|
|
83
83
|
when "ghost"
|
|
@@ -90,8 +90,10 @@ module UI::ButtonBehavior
|
|
|
90
90
|
end
|
|
91
91
|
|
|
92
92
|
# Size-specific classes based on @size
|
|
93
|
+
# Normalizes size to handle both :icon_sm (underscore) and "icon-sm" (hyphen) formats
|
|
93
94
|
def button_size_classes
|
|
94
|
-
|
|
95
|
+
normalized_size = @size.to_s.tr("-", "_")
|
|
96
|
+
case normalized_size
|
|
95
97
|
when "default"
|
|
96
98
|
"h-9 px-4 py-2"
|
|
97
99
|
when "sm"
|
|
@@ -100,9 +102,9 @@ module UI::ButtonBehavior
|
|
|
100
102
|
"h-10 px-8"
|
|
101
103
|
when "icon"
|
|
102
104
|
"h-9 w-9"
|
|
103
|
-
when "
|
|
105
|
+
when "icon_sm"
|
|
104
106
|
"h-8 w-8"
|
|
105
|
-
when "
|
|
107
|
+
when "icon_lg"
|
|
106
108
|
"h-10 w-10"
|
|
107
109
|
else
|
|
108
110
|
"h-9 px-4 py-2"
|
|
@@ -42,14 +42,16 @@ module UI::ButtonGroupBehavior
|
|
|
42
42
|
|
|
43
43
|
# Orientation-specific classes based on @orientation
|
|
44
44
|
# Matches shadcn/ui v4 exactly
|
|
45
|
-
# Note: We exclude [role=menu] elements from border-radius rules
|
|
45
|
+
# Note: We exclude [role=menu], nested [data-slot=button-group], and [data-state] (popover/tooltip content) elements from border-radius rules
|
|
46
|
+
# Note: We use !important on border-radius rules to override button's shorthand `rounded-[var(--radius)]`
|
|
47
|
+
# Note: We use :has(+[data-state]) to exclude elements followed by popover/tooltip content from rounded-r-none
|
|
46
48
|
def button_group_orientation_classes
|
|
47
49
|
case @orientation.to_s
|
|
48
50
|
when "vertical"
|
|
49
|
-
"flex-col [&>*:not(:first-child):not([role=menu])]:rounded-t-none [&>*:not(:first-child):not([role=menu])]:border-t-0 [&>*:not(:last-child):not([role=menu])]:rounded-b-none"
|
|
51
|
+
"flex-col [&>*:not(:first-child):not([role=menu]):not([data-slot=button-group]):not([data-state])]:!rounded-t-none [&>*:not(:first-child):not([role=menu]):not([data-slot=button-group]):not([data-state])]:border-t-0 [&>*:not(:last-child):not(:has(+[data-state])):not([role=menu]):not([data-slot=button-group]):not([data-state])]:!rounded-b-none"
|
|
50
52
|
else # horizontal (default)
|
|
51
|
-
"[&>*:not(:first-child):not([role=menu])]:rounded-l-none [&>*:not(:first-child):not([role=menu])]:border-l-0 " \
|
|
52
|
-
"[&>*:not(:last-child):not(:has(+[role=menu])):not([role=menu])]:rounded-r-none"
|
|
53
|
+
"[&>*:not(:first-child):not([role=menu]):not([data-slot=button-group]):not([data-state])]:!rounded-l-none [&>*:not(:first-child):not([role=menu]):not([data-slot=button-group]):not([data-state])]:border-l-0 " \
|
|
54
|
+
"[&>*:not(:last-child):not(:has(+[role=menu])):not(:has(+[data-state])):not([role=menu]):not([data-slot=button-group]):not([data-state])]:!rounded-r-none"
|
|
53
55
|
end
|
|
54
56
|
end
|
|
55
57
|
end
|
|
@@ -73,15 +73,17 @@ module UI::InputGroupButtonBehavior
|
|
|
73
73
|
|
|
74
74
|
# Size-specific classes
|
|
75
75
|
# Uses calc(var(--radius, 0.375rem) - 5px) to create slightly smaller rounded corners for nested buttons
|
|
76
|
+
# Normalizes size to handle both :icon_xs (underscore) and "icon-xs" (hyphen) formats
|
|
76
77
|
def input_group_button_size_classes
|
|
77
|
-
|
|
78
|
+
normalized_size = @size.to_s.tr("-", "_")
|
|
79
|
+
case normalized_size
|
|
78
80
|
when "xs"
|
|
79
81
|
"h-6 gap-1 px-2 rounded-[calc(var(--radius,0.375rem)-5px)] [&>svg:not([class*='size-'])]:size-3.5 has-[>svg]:px-2"
|
|
80
82
|
when "sm"
|
|
81
83
|
"h-8 px-2.5 gap-1.5 rounded-[calc(var(--radius,0.375rem)-5px)] has-[>svg]:px-2.5"
|
|
82
|
-
when "
|
|
84
|
+
when "icon_xs"
|
|
83
85
|
"size-6 rounded-[calc(var(--radius,0.375rem)-5px)] p-0 has-[>svg]:p-0"
|
|
84
|
-
when "
|
|
86
|
+
when "icon_sm"
|
|
85
87
|
"size-8 rounded-[calc(var(--radius,0.375rem)-5px)] p-0 has-[>svg]:p-0"
|
|
86
88
|
else
|
|
87
89
|
"h-6 gap-1 px-2 rounded-[calc(var(--radius,0.375rem)-5px)] [&>svg:not([class*='size-'])]:size-3.5 has-[>svg]:px-2"
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Slider - Phlex implementation
|
|
4
|
+
#
|
|
5
|
+
# A range slider component for selecting values within a range.
|
|
6
|
+
# Uses SliderBehavior module for shared logic.
|
|
7
|
+
#
|
|
8
|
+
# @example Basic usage
|
|
9
|
+
# render UI::Slider.new(default_value: [50], max: 100) do
|
|
10
|
+
# render UI::SliderTrack.new do
|
|
11
|
+
# render UI::SliderRange.new
|
|
12
|
+
# end
|
|
13
|
+
# render UI::SliderThumb.new
|
|
14
|
+
# end
|
|
15
|
+
#
|
|
16
|
+
# @example Range slider with two thumbs
|
|
17
|
+
# render UI::Slider.new(default_value: [25, 75], max: 100) do
|
|
18
|
+
# render UI::SliderTrack.new do
|
|
19
|
+
# render UI::SliderRange.new
|
|
20
|
+
# end
|
|
21
|
+
# render UI::SliderThumb.new
|
|
22
|
+
# render UI::SliderThumb.new
|
|
23
|
+
# end
|
|
24
|
+
class UI::Slider < Phlex::HTML
|
|
25
|
+
include UI::SliderBehavior
|
|
26
|
+
|
|
27
|
+
# @param min [Integer] Minimum value
|
|
28
|
+
# @param max [Integer] Maximum value
|
|
29
|
+
# @param step [Integer] Step increment
|
|
30
|
+
# @param value [Array] Current value (controlled)
|
|
31
|
+
# @param default_value [Array] Initial value (uncontrolled)
|
|
32
|
+
# @param center_point [Integer] Center point for bidirectional sliders
|
|
33
|
+
# @param disabled [Boolean] Whether the slider is disabled
|
|
34
|
+
# @param orientation [String] Orientation (horizontal, vertical)
|
|
35
|
+
# @param inverted [Boolean] Whether the slider is inverted
|
|
36
|
+
# @param name [String] Form field name
|
|
37
|
+
# @param classes [String] Additional CSS classes
|
|
38
|
+
# @param attributes [Hash] Additional HTML attributes
|
|
39
|
+
def initialize(
|
|
40
|
+
min: 0,
|
|
41
|
+
max: 100,
|
|
42
|
+
step: 1,
|
|
43
|
+
value: nil,
|
|
44
|
+
default_value: nil,
|
|
45
|
+
center_point: nil,
|
|
46
|
+
disabled: false,
|
|
47
|
+
orientation: "horizontal",
|
|
48
|
+
inverted: false,
|
|
49
|
+
name: "",
|
|
50
|
+
classes: "",
|
|
51
|
+
attributes: {}
|
|
52
|
+
)
|
|
53
|
+
@min = min
|
|
54
|
+
@max = max
|
|
55
|
+
@step = step
|
|
56
|
+
@value = value
|
|
57
|
+
@center_point = center_point
|
|
58
|
+
@default_value = default_value || (center_point ? [center_point] : [min])
|
|
59
|
+
@disabled = disabled
|
|
60
|
+
@orientation = orientation
|
|
61
|
+
@inverted = inverted
|
|
62
|
+
@name = name
|
|
63
|
+
@classes = classes
|
|
64
|
+
@attributes = attributes
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def view_template(&block)
|
|
68
|
+
all_attributes = slider_html_attributes
|
|
69
|
+
|
|
70
|
+
# Merge data attributes
|
|
71
|
+
all_attributes[:data] = all_attributes[:data].merge(@attributes.fetch(:data, {}))
|
|
72
|
+
|
|
73
|
+
# Merge with user attributes (except data which we already handled)
|
|
74
|
+
all_attributes = all_attributes.merge(@attributes.except(:data))
|
|
75
|
+
|
|
76
|
+
div(**all_attributes) do
|
|
77
|
+
yield if block_given?
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SliderRange - Phlex implementation
|
|
4
|
+
#
|
|
5
|
+
# The range is the filled portion of the track showing the selected value.
|
|
6
|
+
# Uses SliderRangeBehavior module for shared logic.
|
|
7
|
+
#
|
|
8
|
+
# @example Basic usage (inside SliderTrack)
|
|
9
|
+
# render UI::SliderTrack.new do
|
|
10
|
+
# render UI::SliderRange.new
|
|
11
|
+
# end
|
|
12
|
+
class UI::SliderRange < Phlex::HTML
|
|
13
|
+
include UI::SliderRangeBehavior
|
|
14
|
+
|
|
15
|
+
# @param classes [String] Additional CSS classes
|
|
16
|
+
# @param attributes [Hash] Additional HTML attributes
|
|
17
|
+
def initialize(classes: "", attributes: {})
|
|
18
|
+
@classes = classes
|
|
19
|
+
@attributes = attributes
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def view_template
|
|
23
|
+
all_attributes = slider_range_html_attributes
|
|
24
|
+
|
|
25
|
+
# Merge data attributes
|
|
26
|
+
all_attributes[:data] = all_attributes[:data].merge(@attributes.fetch(:data, {}))
|
|
27
|
+
|
|
28
|
+
# Merge with user attributes (except data which we already handled)
|
|
29
|
+
all_attributes = all_attributes.merge(@attributes.except(:data))
|
|
30
|
+
|
|
31
|
+
div(**all_attributes)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SliderThumb - Phlex implementation
|
|
4
|
+
#
|
|
5
|
+
# The thumb is the draggable handle that controls the slider value.
|
|
6
|
+
# Uses SliderThumbBehavior module for shared logic.
|
|
7
|
+
#
|
|
8
|
+
# @example Basic usage
|
|
9
|
+
# render UI::Slider.new(default_value: [50]) do
|
|
10
|
+
# render UI::SliderTrack.new do
|
|
11
|
+
# render UI::SliderRange.new
|
|
12
|
+
# end
|
|
13
|
+
# render UI::SliderThumb.new
|
|
14
|
+
# end
|
|
15
|
+
#
|
|
16
|
+
# @example Range slider with two thumbs
|
|
17
|
+
# render UI::Slider.new(default_value: [25, 75]) do
|
|
18
|
+
# render UI::SliderTrack.new do
|
|
19
|
+
# render UI::SliderRange.new
|
|
20
|
+
# end
|
|
21
|
+
# render UI::SliderThumb.new
|
|
22
|
+
# render UI::SliderThumb.new
|
|
23
|
+
# end
|
|
24
|
+
class UI::SliderThumb < Phlex::HTML
|
|
25
|
+
include UI::SliderThumbBehavior
|
|
26
|
+
|
|
27
|
+
# @param disabled [Boolean] Whether the thumb is disabled
|
|
28
|
+
# @param classes [String] Additional CSS classes
|
|
29
|
+
# @param attributes [Hash] Additional HTML attributes
|
|
30
|
+
def initialize(disabled: false, classes: "", attributes: {})
|
|
31
|
+
@disabled = disabled
|
|
32
|
+
@classes = classes
|
|
33
|
+
@attributes = attributes
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def view_template
|
|
37
|
+
all_attributes = slider_thumb_html_attributes
|
|
38
|
+
|
|
39
|
+
# Merge data attributes
|
|
40
|
+
all_attributes[:data] = all_attributes[:data].merge(@attributes.fetch(:data, {}))
|
|
41
|
+
|
|
42
|
+
# Merge with user attributes (except data which we already handled)
|
|
43
|
+
all_attributes = all_attributes.merge(@attributes.except(:data))
|
|
44
|
+
|
|
45
|
+
div(**all_attributes)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SliderTrack - Phlex implementation
|
|
4
|
+
#
|
|
5
|
+
# The track is the background rail that contains the range.
|
|
6
|
+
# Uses SliderTrackBehavior module for shared logic.
|
|
7
|
+
#
|
|
8
|
+
# @example Basic usage
|
|
9
|
+
# render UI::SliderTrack.new do
|
|
10
|
+
# render UI::SliderRange.new
|
|
11
|
+
# end
|
|
12
|
+
class UI::SliderTrack < Phlex::HTML
|
|
13
|
+
include UI::SliderTrackBehavior
|
|
14
|
+
|
|
15
|
+
# @param classes [String] Additional CSS classes
|
|
16
|
+
# @param attributes [Hash] Additional HTML attributes
|
|
17
|
+
def initialize(classes: "", attributes: {})
|
|
18
|
+
@classes = classes
|
|
19
|
+
@attributes = attributes
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def view_template(&block)
|
|
23
|
+
all_attributes = slider_track_html_attributes
|
|
24
|
+
|
|
25
|
+
# Merge data attributes
|
|
26
|
+
all_attributes[:data] = all_attributes[:data].merge(@attributes.fetch(:data, {}))
|
|
27
|
+
|
|
28
|
+
# Merge with user attributes (except data which we already handled)
|
|
29
|
+
all_attributes = all_attributes.merge(@attributes.except(:data))
|
|
30
|
+
|
|
31
|
+
div(**all_attributes) do
|
|
32
|
+
yield if block_given?
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
data/app/javascript/ui/common.js
CHANGED
|
@@ -16,7 +16,6 @@ export function registerControllersInto(application, controllers) {
|
|
|
16
16
|
for (const [name, controller] of Object.entries(controllers)) {
|
|
17
17
|
try {
|
|
18
18
|
application.register(name, controller)
|
|
19
|
-
console.log(`Registered Stimulus controller: ${name}`)
|
|
20
19
|
} catch (error) {
|
|
21
20
|
console.error(`Failed to register controller ${name}:`, error)
|
|
22
21
|
}
|
data/app/views/ui/_item.html.erb
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
<% extend UI::ItemBehavior -%>
|
|
2
2
|
<% @variant = local_assigns.fetch(:variant, "default") -%>
|
|
3
3
|
<% @size = local_assigns.fetch(:size, "default") -%>
|
|
4
|
+
<% @as_child = local_assigns.fetch(:as_child, false) -%>
|
|
4
5
|
<% @classes = local_assigns.fetch(:classes, "") -%>
|
|
5
|
-
<% @attributes = local_assigns.except(:variant, :size, :classes) -%>
|
|
6
|
+
<% @attributes = local_assigns.except(:variant, :size, :as_child, :classes) -%>
|
|
6
7
|
<% attrs = item_html_attributes.merge(@attributes) -%>
|
|
8
|
+
<% if @as_child -%>
|
|
9
|
+
<%= yield(attrs) %>
|
|
10
|
+
<% else -%>
|
|
7
11
|
<div class="<%= attrs[:class] %>" data-slot="<%= attrs[:"data-slot"] %>" data-variant="<%= attrs[:"data-variant"] %>" data-size="<%= attrs[:"data-size"] %>">
|
|
8
12
|
<%= yield %>
|
|
9
13
|
</div>
|
|
14
|
+
<% end -%>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<%# FieldLabel Component - Label styled for form fields %>
|
|
2
2
|
<%
|
|
3
3
|
content ||= local_assigns.fetch(:content, nil)
|
|
4
|
+
@for_id = local_assigns.fetch(:for_id, nil)
|
|
4
5
|
@classes = local_assigns.fetch(:classes, "")
|
|
5
6
|
@attributes = local_assigns.fetch(:attributes, {})
|
|
6
7
|
|
|
@@ -10,6 +11,6 @@
|
|
|
10
11
|
# Get HTML attributes from behavior
|
|
11
12
|
all_attributes = field_label_html_attributes.deep_merge(@attributes)
|
|
12
13
|
-%>
|
|
13
|
-
<%= content_tag :
|
|
14
|
+
<%= content_tag :label, all_attributes do %>
|
|
14
15
|
<%= content || yield %>
|
|
15
16
|
<% end %>
|
|
@@ -9,7 +9,13 @@
|
|
|
9
9
|
|
|
10
10
|
# Get HTML attributes from behavior
|
|
11
11
|
all_attributes = field_separator_html_attributes.deep_merge(@attributes)
|
|
12
|
+
has_children = content.present? || block_given?
|
|
12
13
|
-%>
|
|
13
14
|
<%= content_tag :div, all_attributes do %>
|
|
14
|
-
<%=
|
|
15
|
+
<%= render "ui/separator", classes: "absolute inset-0 top-1/2" %>
|
|
16
|
+
<% if has_children %>
|
|
17
|
+
<span data-slot="field-separator-content" class="bg-background text-muted-foreground relative mx-auto block w-fit px-2">
|
|
18
|
+
<%= content || yield %>
|
|
19
|
+
</span>
|
|
20
|
+
<% end %>
|
|
15
21
|
<% end %>
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
# Component Documentation Annotations
|
|
2
|
+
|
|
3
|
+
Este documento descreve as anotações YARD e JSDoc usadas para documentar componentes UI.
|
|
4
|
+
|
|
5
|
+
## Ruby (YARD)
|
|
6
|
+
|
|
7
|
+
### Tags Customizadas para Componentes
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
# @ui_component Select
|
|
11
|
+
# Exibe uma lista de opções para o usuário escolher.
|
|
12
|
+
#
|
|
13
|
+
# @ui_category forms
|
|
14
|
+
#
|
|
15
|
+
# @ui_anatomy Select - Root container (required)
|
|
16
|
+
# @ui_anatomy Trigger - Button that opens dropdown (required)
|
|
17
|
+
# @ui_anatomy Content - Container for options (required)
|
|
18
|
+
# @ui_anatomy Item - Selectable option
|
|
19
|
+
#
|
|
20
|
+
# @ui_feature Single selection from a list
|
|
21
|
+
# @ui_feature Keyboard navigation
|
|
22
|
+
# @ui_feature Type-ahead search
|
|
23
|
+
#
|
|
24
|
+
# @ui_related combobox
|
|
25
|
+
# @ui_related dropdown_menu
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Tags para Parâmetros
|
|
29
|
+
|
|
30
|
+
```ruby
|
|
31
|
+
# @param value [String] Currently selected value
|
|
32
|
+
# @param disabled [Boolean] Whether the select is disabled
|
|
33
|
+
# @param name [String] Form field name
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Tags para Data Attributes
|
|
37
|
+
|
|
38
|
+
```ruby
|
|
39
|
+
# @ui_data_attr data-state ["open", "closed"] Current open/closed state
|
|
40
|
+
# @ui_data_attr data-side ["top", "bottom"] Which side content appears
|
|
41
|
+
# @ui_data_attr data-disabled ["true"] Present when disabled
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Tags para CSS Variables
|
|
45
|
+
|
|
46
|
+
```ruby
|
|
47
|
+
# @ui_css_var --trigger-width Width of the trigger element
|
|
48
|
+
# @ui_css_var --content-max-height Maximum height of content
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Tags para Acessibilidade
|
|
52
|
+
|
|
53
|
+
```ruby
|
|
54
|
+
# @ui_aria_pattern Listbox
|
|
55
|
+
# @ui_aria_reference https://www.w3.org/WAI/ARIA/apg/patterns/listbox/
|
|
56
|
+
# @ui_aria_attr role="combobox" on trigger
|
|
57
|
+
# @ui_aria_attr aria-expanded on trigger
|
|
58
|
+
# @ui_aria_attr aria-selected on items
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Tags para Keyboard
|
|
62
|
+
|
|
63
|
+
```ruby
|
|
64
|
+
# @ui_keyboard Space Opens dropdown when trigger focused
|
|
65
|
+
# @ui_keyboard Enter Opens dropdown / selects item
|
|
66
|
+
# @ui_keyboard ArrowDown Moves to next item
|
|
67
|
+
# @ui_keyboard Escape Closes dropdown
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## JavaScript (JSDoc)
|
|
71
|
+
|
|
72
|
+
### Tags para Stimulus Controllers
|
|
73
|
+
|
|
74
|
+
```javascript
|
|
75
|
+
/**
|
|
76
|
+
* @controller ui--select
|
|
77
|
+
* @description Manages select dropdown state and interactions
|
|
78
|
+
*
|
|
79
|
+
* @target trigger - Button that toggles dropdown
|
|
80
|
+
* @target content - Dropdown container
|
|
81
|
+
* @target item - Selectable options
|
|
82
|
+
*
|
|
83
|
+
* @value open {Boolean} Controls open state
|
|
84
|
+
* @value value {String} Current selected value
|
|
85
|
+
*
|
|
86
|
+
* @fires ui:select:change When selection changes
|
|
87
|
+
*/
|
|
88
|
+
export default class extends Controller {
|
|
89
|
+
/**
|
|
90
|
+
* Toggle the dropdown open/closed
|
|
91
|
+
* @action
|
|
92
|
+
*/
|
|
93
|
+
toggle() { }
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Select an item
|
|
97
|
+
* @action
|
|
98
|
+
* @param {Event} event - Click event from item
|
|
99
|
+
*/
|
|
100
|
+
selectItem(event) { }
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Exemplo Completo - Select Behavior
|
|
105
|
+
|
|
106
|
+
```ruby
|
|
107
|
+
# frozen_string_literal: true
|
|
108
|
+
|
|
109
|
+
# UI::SelectBehavior
|
|
110
|
+
#
|
|
111
|
+
# @ui_component Select
|
|
112
|
+
# @ui_description Displays a list of options for the user to pick from, triggered by a button.
|
|
113
|
+
# @ui_category forms
|
|
114
|
+
#
|
|
115
|
+
# @ui_anatomy Select - Root container with state management (required)
|
|
116
|
+
# @ui_anatomy Trigger - Button that opens the dropdown (required)
|
|
117
|
+
# @ui_anatomy Content - Container for the dropdown options (required)
|
|
118
|
+
# @ui_anatomy Item - Individual selectable option (required)
|
|
119
|
+
# @ui_anatomy Group - Groups related items with a label
|
|
120
|
+
# @ui_anatomy Label - Label for item groups
|
|
121
|
+
# @ui_anatomy Separator - Visual separator between items
|
|
122
|
+
#
|
|
123
|
+
# @ui_feature Single selection from a list of options
|
|
124
|
+
# @ui_feature Keyboard navigation with arrow keys
|
|
125
|
+
# @ui_feature Type-ahead search functionality
|
|
126
|
+
# @ui_feature Grouped options with labels
|
|
127
|
+
# @ui_feature Disabled items support
|
|
128
|
+
# @ui_feature Custom trigger with asChild pattern
|
|
129
|
+
# @ui_feature Placeholder text when no selection
|
|
130
|
+
# @ui_feature Form integration with hidden input
|
|
131
|
+
#
|
|
132
|
+
# @ui_data_attr data-state ["open", "closed"] Current open/closed state
|
|
133
|
+
# @ui_data_attr data-placeholder ["true"] Present when showing placeholder
|
|
134
|
+
# @ui_data_attr data-side ["top", "bottom"] Which side the content appears
|
|
135
|
+
#
|
|
136
|
+
# @ui_css_var --trigger-width Width of the trigger element
|
|
137
|
+
#
|
|
138
|
+
# @ui_aria_pattern Listbox
|
|
139
|
+
# @ui_aria_reference https://www.w3.org/WAI/ARIA/apg/patterns/listbox/
|
|
140
|
+
# @ui_aria_attr role="combobox" on the trigger
|
|
141
|
+
# @ui_aria_attr role="listbox" on the content container
|
|
142
|
+
# @ui_aria_attr role="option" on each item
|
|
143
|
+
# @ui_aria_attr aria-expanded on trigger
|
|
144
|
+
# @ui_aria_attr aria-selected on the selected item
|
|
145
|
+
# @ui_aria_attr aria-disabled on disabled items
|
|
146
|
+
#
|
|
147
|
+
# @ui_keyboard Space Opens dropdown when trigger is focused
|
|
148
|
+
# @ui_keyboard Enter Opens dropdown / selects highlighted item
|
|
149
|
+
# @ui_keyboard ArrowDown Opens dropdown / moves to next item
|
|
150
|
+
# @ui_keyboard ArrowUp Moves to previous item
|
|
151
|
+
# @ui_keyboard Home Moves to first item
|
|
152
|
+
# @ui_keyboard End Moves to last item
|
|
153
|
+
# @ui_keyboard Escape Closes dropdown
|
|
154
|
+
# @ui_keyboard A-Z,a-z Type-ahead to find matching item
|
|
155
|
+
#
|
|
156
|
+
# @ui_related combobox
|
|
157
|
+
# @ui_related dropdown_menu
|
|
158
|
+
# @ui_related radio_group
|
|
159
|
+
#
|
|
160
|
+
module UI::SelectBehavior
|
|
161
|
+
# Returns HTML attributes for the select element
|
|
162
|
+
#
|
|
163
|
+
# @return [Hash] HTML attributes
|
|
164
|
+
def select_html_attributes
|
|
165
|
+
# ...
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Exemplo Completo - Select Controller
|
|
171
|
+
|
|
172
|
+
```javascript
|
|
173
|
+
/**
|
|
174
|
+
* Select Controller
|
|
175
|
+
*
|
|
176
|
+
* @controller ui--select
|
|
177
|
+
* @description Manages select dropdown state, positioning, and keyboard navigation
|
|
178
|
+
*
|
|
179
|
+
* @target trigger - Button that toggles the dropdown
|
|
180
|
+
* @target content - Dropdown container
|
|
181
|
+
* @target item - Selectable option elements
|
|
182
|
+
* @target valueDisplay - Span showing selected value text
|
|
183
|
+
* @target hiddenInput - Hidden input for form submission
|
|
184
|
+
* @target viewport - Scrollable viewport containing items
|
|
185
|
+
*
|
|
186
|
+
* @value open {Boolean} Controls dropdown visibility
|
|
187
|
+
* @value value {String} Currently selected value
|
|
188
|
+
*
|
|
189
|
+
* @fires ui:select:change - Fired when selection changes (detail: { value, previousValue })
|
|
190
|
+
*/
|
|
191
|
+
export default class extends Controller {
|
|
192
|
+
static targets = ["trigger", "content", "item", "valueDisplay", "hiddenInput", "viewport"]
|
|
193
|
+
static values = { open: Boolean, value: String }
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Toggle dropdown open/closed
|
|
197
|
+
* @action
|
|
198
|
+
*/
|
|
199
|
+
toggle(event) { }
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Open the dropdown
|
|
203
|
+
* @action
|
|
204
|
+
*/
|
|
205
|
+
open() { }
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Close the dropdown
|
|
209
|
+
* @action
|
|
210
|
+
*/
|
|
211
|
+
close() { }
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Select an item from the dropdown
|
|
215
|
+
* @action
|
|
216
|
+
* @param {Event} event - Click event from the item
|
|
217
|
+
*/
|
|
218
|
+
selectItem(event) { }
|
|
219
|
+
}
|
|
220
|
+
```
|