loco_motion-rails 0.4.0 → 0.5.0
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 +6 -1
- data/app/components/daisy/actions/button_component.html.haml +2 -2
- data/app/components/daisy/actions/button_component.rb +98 -59
- data/app/components/daisy/actions/dropdown_component.html.haml +1 -2
- data/app/components/daisy/actions/dropdown_component.rb +7 -10
- data/app/components/daisy/actions/modal_component.html.haml +10 -8
- data/app/components/daisy/actions/modal_component.rb +6 -6
- data/app/components/daisy/actions/swap_component.rb +13 -9
- data/app/components/daisy/actions/theme_controller.js +113 -0
- data/app/components/daisy/actions/theme_controller_component.rb +58 -17
- data/app/components/daisy/actions/theme_preview_component.html.haml +5 -0
- data/app/components/daisy/actions/theme_preview_component.rb +68 -0
- data/app/components/daisy/data_display/accordion_component.html.haml +0 -1
- data/app/components/daisy/data_display/accordion_component.rb +10 -3
- data/app/components/daisy/data_display/avatar_component.html.haml +1 -1
- data/app/components/daisy/data_display/avatar_component.rb +17 -7
- data/app/components/daisy/data_display/badge_component.rb +122 -4
- data/app/components/daisy/data_display/card_component.html.haml +1 -1
- data/app/components/daisy/data_display/card_component.rb +20 -6
- data/app/components/daisy/data_display/chat_component.rb +2 -2
- data/app/components/daisy/data_display/collapse_component.rb +9 -5
- data/app/components/daisy/data_display/countdown_component.rb +15 -5
- data/app/components/daisy/data_display/figure_component.rb +8 -3
- data/app/components/daisy/data_display/kbd_component.rb +13 -4
- data/app/components/daisy/data_display/list_component.html.haml +5 -0
- data/app/components/daisy/data_display/list_component.rb +82 -0
- data/app/components/daisy/data_display/list_item_component.rb +39 -0
- data/app/components/daisy/data_display/stat_component.html.haml +5 -6
- data/app/components/daisy/data_display/stat_component.rb +21 -8
- data/app/components/daisy/data_display/status_component.rb +47 -0
- data/app/components/daisy/data_display/timeline_component.rb +1 -1
- data/app/components/daisy/data_input/cally_component.html.haml +14 -0
- data/app/components/daisy/data_input/cally_component.rb +182 -0
- data/app/components/daisy/data_input/cally_input_component.html.haml +5 -0
- data/app/components/daisy/data_input/cally_input_component.rb +165 -0
- data/app/components/daisy/data_input/cally_input_controller.js +235 -0
- data/app/components/daisy/data_input/checkbox_component.html.haml +20 -0
- data/app/components/daisy/data_input/checkbox_component.rb +21 -7
- data/app/components/daisy/data_input/fieldset_component.html.haml +8 -0
- data/app/components/daisy/data_input/fieldset_component.rb +57 -0
- data/app/components/daisy/data_input/file_input_component.rb +6 -0
- data/app/components/daisy/data_input/filter_component.html.haml +3 -0
- data/app/components/daisy/data_input/filter_component.rb +221 -0
- data/app/components/daisy/data_input/label_component.rb +2 -2
- data/app/components/daisy/data_input/radio_button_component.rb +1 -1
- data/app/components/daisy/data_input/rating_component.html.haml +0 -2
- data/app/components/daisy/data_input/rating_component.rb +3 -2
- data/app/components/daisy/data_input/select_component.html.haml +27 -15
- data/app/components/daisy/data_input/select_component.rb +152 -10
- data/app/components/daisy/data_input/text_area_component.rb +11 -8
- data/app/components/daisy/data_input/text_input_component.html.haml +25 -4
- data/app/components/daisy/data_input/text_input_component.rb +38 -36
- data/app/components/daisy/data_input/toggle_component.rb +12 -0
- data/app/components/daisy/feedback/alert_component.html.haml +1 -1
- data/app/components/daisy/feedback/alert_component.rb +86 -2
- data/app/components/daisy/feedback/loading_component.rb +10 -3
- data/app/components/daisy/feedback/skeleton_component.rb +1 -1
- data/app/components/daisy/layout/divider_component.rb +4 -2
- data/app/components/daisy/layout/drawer_component.html.haml +0 -1
- data/app/components/daisy/layout/footer_component.rb +6 -6
- data/app/components/daisy/mockup/device_component.rb +15 -18
- data/app/components/daisy/navigation/breadcrumbs_component.html.haml +0 -1
- data/app/components/daisy/navigation/breadcrumbs_component.rb +84 -9
- data/app/components/daisy/navigation/dock_component.rb +146 -0
- data/app/components/daisy/navigation/link_component.rb +18 -9
- data/app/components/daisy/navigation/menu_component.rb +15 -9
- data/app/components/daisy/navigation/navbar_component.html.haml +1 -1
- data/app/components/daisy/navigation/navbar_component.rb +2 -13
- data/app/components/daisy/navigation/steps_component.rb +6 -6
- data/app/components/daisy/navigation/tabs_component.html.haml +0 -1
- data/app/components/daisy/navigation/tabs_component.rb +26 -16
- data/app/components/hero/icon_component.rb +15 -5
- data/app/helpers/daisy/form_builder_helper.rb +30 -3
- data/app/views/examples/daisy/data_input/filters.html.haml +62 -0
- data/lib/hero.rb +1 -1
- data/lib/loco_motion/base_component.rb +44 -1
- data/lib/loco_motion/component_config.rb +1 -0
- data/lib/loco_motion/concerns/iconable_component.rb +134 -0
- data/lib/loco_motion/concerns/labelable_component.rb +142 -0
- data/lib/loco_motion/concerns/linkable_component.rb +40 -0
- data/lib/loco_motion/concerns/tippable_component.rb +25 -10
- data/lib/loco_motion/helpers.rb +27 -18
- data/lib/loco_motion/patches/view_component/slot_loco_parent_patch.rb +37 -0
- data/lib/loco_motion/patches/view_component/slotable_default_patch.rb +21 -0
- data/lib/loco_motion/version.rb +1 -1
- data/lib/loco_motion.rb +12 -2
- metadata +65 -19
- data/app/components/daisy/actions/theme_controller_component.html.haml +0 -5
- data/app/components/daisy/layout/artboard_component.rb +0 -59
- data/app/components/daisy/navigation/bottom_nav_component.rb +0 -138
@@ -0,0 +1,82 @@
|
|
1
|
+
#
|
2
|
+
# The List component is a vertical layout to display information in rows. It can
|
3
|
+
# contain various content types including text, images, and actions arranged in a
|
4
|
+
# consistent format.
|
5
|
+
#
|
6
|
+
# The List component is useful for displaying structured data like user profiles,
|
7
|
+
# media libraries, or content collections with a consistent layout.
|
8
|
+
#
|
9
|
+
# @part component The main list container (ul element)
|
10
|
+
# @part header The optional header container for the list
|
11
|
+
#
|
12
|
+
# @slot item+ {Daisy::DataDisplay::ListItemComponent} Individual list items or
|
13
|
+
# rows in the list
|
14
|
+
#
|
15
|
+
# @loco_example Basic Usage
|
16
|
+
# = daisy_list do |list|
|
17
|
+
# - list.with_item { "Item 1" }
|
18
|
+
# - list.with_item { "Item 2" }
|
19
|
+
# - list.with_item { "Item 3" }
|
20
|
+
#
|
21
|
+
# @loco_example With Header
|
22
|
+
# = daisy_list(header: "Featured Items") do |list|
|
23
|
+
# - list.with_item { "Featured Item 1" }
|
24
|
+
# - list.with_item { "Featured Item 2" }
|
25
|
+
# - list.with_item { "Featured Item 3" }
|
26
|
+
#
|
27
|
+
# @loco_example With Rich Content
|
28
|
+
# = daisy_list(header: "Most played songs", css: "bg-base-100 rounded-box shadow-md") do |list|
|
29
|
+
# - list.with_item do |item|
|
30
|
+
# .flex.items-center.gap-2
|
31
|
+
# = image_tag("album_cover.jpg", class: "size-10 rounded-box")
|
32
|
+
# .flex.flex-col
|
33
|
+
# .font-medium Song Title
|
34
|
+
# .text-xs.opacity-60 Artist Name
|
35
|
+
# = daisy_button(icon: "play", css: "btn-ghost btn-square")
|
36
|
+
#
|
37
|
+
# @loco_example With Dividers
|
38
|
+
# = daisy_list(css: "divide-y") do |list|
|
39
|
+
# - list.with_item { "Item with divider below" }
|
40
|
+
# - list.with_item { "Another divided item" }
|
41
|
+
# - list.with_item { "Last item" }
|
42
|
+
#
|
43
|
+
# @!parse class Daisy::DataDisplay::ListComponent < LocoMotion::BaseComponent; end
|
44
|
+
class Daisy::DataDisplay::ListComponent < LocoMotion::BaseComponent
|
45
|
+
renders_many :items, "Daisy::DataDisplay::ListItemComponent"
|
46
|
+
renders_one :header, LocoMotion::BasicComponent.build(tag_name: :li)
|
47
|
+
|
48
|
+
set_component_name :list
|
49
|
+
|
50
|
+
# @return [String] Optional header text for the list
|
51
|
+
attr_reader :simple_header, :header_css, :header_html
|
52
|
+
|
53
|
+
#
|
54
|
+
# Create a new List component.
|
55
|
+
#
|
56
|
+
# @param kwargs [Hash] The keyword arguments for the component.
|
57
|
+
#
|
58
|
+
# @option kwargs [String] :header Optional header text to display at the top
|
59
|
+
# of the list.
|
60
|
+
#
|
61
|
+
# @option kwargs [String] :css Additional CSS classes to apply to the list.
|
62
|
+
# Common options include:
|
63
|
+
# - `bg-base-100` for background color
|
64
|
+
# - `rounded-box` for rounded corners
|
65
|
+
# - `shadow-md` for drop shadow
|
66
|
+
# - `divide-y` for dividers between items
|
67
|
+
#
|
68
|
+
def initialize(**kws, &block)
|
69
|
+
super
|
70
|
+
|
71
|
+
@simple_header = config_option(:header)
|
72
|
+
@header_css = config_option(:header_css)
|
73
|
+
@header_html = config_option(:header_html)
|
74
|
+
end
|
75
|
+
|
76
|
+
def before_render
|
77
|
+
add_css(:component, "list")
|
78
|
+
set_tag_name(:component, :ul)
|
79
|
+
|
80
|
+
with_header(tag_name: :li, css: header_css, html: header_html) { simple_header } if simple_header && !header?
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
#
|
2
|
+
# The ListItem component represents an individual row within a List component.
|
3
|
+
# It provides a consistent layout for displaying content in a list format.
|
4
|
+
#
|
5
|
+
# @part image Optional image container for the item
|
6
|
+
#
|
7
|
+
# @loco_example Basic Usage
|
8
|
+
# = daisy_list do |list|
|
9
|
+
# - list.with_item { "Simple list item" }
|
10
|
+
#
|
11
|
+
# @loco_example With Image
|
12
|
+
# = daisy_list do |list|
|
13
|
+
# - list.with_item do
|
14
|
+
# = image_tag(src: "profile.jpg", class: "rounded-full size-8")
|
15
|
+
# User Profile
|
16
|
+
#
|
17
|
+
# @!parse class Daisy::DataDisplay::ListItemComponent < LocoMotion::BaseComponent; end
|
18
|
+
class Daisy::DataDisplay::ListItemComponent < LocoMotion::BaseComponent
|
19
|
+
#
|
20
|
+
# Create a new ListItem component.
|
21
|
+
#
|
22
|
+
# @param kwargs [Hash] The keyword arguments for the component.
|
23
|
+
#
|
24
|
+
# @option kwargs [String] :css Additional CSS classes to apply to the list item.
|
25
|
+
#
|
26
|
+
def initialize(**kwargs, &block)
|
27
|
+
super
|
28
|
+
end
|
29
|
+
|
30
|
+
# Called before rendering to setup the component CSS and structure
|
31
|
+
def before_render
|
32
|
+
set_tag_name(:component, :li)
|
33
|
+
add_css(:component, "list-row")
|
34
|
+
end
|
35
|
+
|
36
|
+
def call
|
37
|
+
part(:component) { content }
|
38
|
+
end
|
39
|
+
end
|
@@ -4,17 +4,17 @@
|
|
4
4
|
= part(:figure) do
|
5
5
|
- if figure?
|
6
6
|
= figure
|
7
|
-
|
8
|
-
|
7
|
+
|
8
|
+
= render_icon
|
9
|
+
|
9
10
|
- if @src.present?
|
10
11
|
= daisy_avatar(src: @src)
|
11
|
-
|
12
12
|
|
13
13
|
- if title?
|
14
14
|
= title
|
15
15
|
- elsif @simple_title.present?
|
16
16
|
= part(:title) do
|
17
|
-
= @simple_title
|
17
|
+
= @simple_title
|
18
18
|
|
19
19
|
= part(:value) do
|
20
20
|
= content
|
@@ -23,5 +23,4 @@
|
|
23
23
|
= description
|
24
24
|
- elsif @simple_description.present?
|
25
25
|
= part(:description) do
|
26
|
-
= @simple_description
|
27
|
-
|
26
|
+
= @simple_description
|
@@ -3,6 +3,9 @@
|
|
3
3
|
# description, and figure. It's perfect for dashboards, summaries, or any
|
4
4
|
# situation where you need to highlight important numbers or metrics.
|
5
5
|
#
|
6
|
+
# @note Stats have a transparent background by default. Use `bg-base-100` if you
|
7
|
+
# need a background color.
|
8
|
+
#
|
6
9
|
# Includes the {LocoMotion::Concerns::TippableComponent} module to enable easy
|
7
10
|
# tooltip addition.
|
8
11
|
#
|
@@ -21,27 +24,29 @@
|
|
21
24
|
# image via the src option or an icon via the icon option.
|
22
25
|
#
|
23
26
|
# @loco_example Basic Usage
|
24
|
-
# = daisy_stat(title: "Downloads", value: "31K"
|
27
|
+
# = daisy_stat(title: "Downloads", value: "31K")
|
25
28
|
#
|
26
29
|
# @loco_example With Description
|
27
|
-
# = daisy_stat(title: "New Users", value: "2.6K", description: "↗︎ 400 (22%)"
|
30
|
+
# = daisy_stat(title: "New Users", value: "2.6K", description: "↗︎ 400 (22%)")
|
28
31
|
#
|
29
32
|
# @loco_example With Icon
|
30
|
-
# = daisy_stat(title: "Page Views", value: "89,400", icon: "eye"
|
33
|
+
# = daisy_stat(title: "Page Views", value: "89,400", icon: "eye") do |stat|
|
31
34
|
# = stat.with_description do
|
32
35
|
# .flex.items-center.gap-1
|
33
|
-
# =
|
36
|
+
# = heroicon "arrow-up", class: "size-4 text-success"
|
34
37
|
# %span.text-success 14%
|
35
38
|
# from last month
|
36
39
|
#
|
37
40
|
# @loco_example With Custom Figure
|
38
|
-
# = daisy_stat(title: "Success Rate", value: "98%"
|
41
|
+
# = daisy_stat(title: "Success Rate", value: "98%") do |stat|
|
39
42
|
# = stat.with_figure do
|
40
43
|
# .text-success
|
41
|
-
# =
|
44
|
+
# = heroicon "check-circle", class: "size-10"
|
42
45
|
#
|
43
46
|
class Daisy::DataDisplay::StatComponent < LocoMotion::BaseComponent
|
44
|
-
|
47
|
+
include LocoMotion::Concerns::IconableComponent
|
48
|
+
include LocoMotion::Concerns::LinkableComponent
|
49
|
+
include LocoMotion::Concerns::TippableComponent
|
45
50
|
|
46
51
|
set_component_name :stat
|
47
52
|
|
@@ -76,17 +81,25 @@ class Daisy::DataDisplay::StatComponent < LocoMotion::BaseComponent
|
|
76
81
|
# @option kws [String] :icon Name of a heroicon to display in the figure
|
77
82
|
# section.
|
78
83
|
#
|
84
|
+
# @option kws [String] :tip The tooltip text to display when hovering over
|
85
|
+
# the component.
|
86
|
+
#
|
79
87
|
def initialize(*args, **kws, &block)
|
80
88
|
super
|
81
89
|
|
82
90
|
@simple_title = config_option(:title)
|
83
91
|
@simple_description = config_option(:description)
|
84
92
|
@src = config_option(:src)
|
85
|
-
@icon = config_option(:icon)
|
86
93
|
end
|
87
94
|
|
88
95
|
def before_render
|
89
96
|
setup_component
|
97
|
+
|
98
|
+
super
|
99
|
+
end
|
100
|
+
|
101
|
+
def default_icon_size
|
102
|
+
"where:size-8"
|
90
103
|
end
|
91
104
|
|
92
105
|
private
|
@@ -0,0 +1,47 @@
|
|
1
|
+
#
|
2
|
+
# The StatusComponent displays a small icon to visually show the current status of an element,
|
3
|
+
# such as online, offline, error, etc. It follows the DaisyUI status component pattern.
|
4
|
+
#
|
5
|
+
# @loco_example Basic Status
|
6
|
+
# = daisy_status()
|
7
|
+
#
|
8
|
+
# @loco_example Status with Size
|
9
|
+
# = daisy_status(css: "status-xs")
|
10
|
+
# = daisy_status(css: "status-sm")
|
11
|
+
# = daisy_status(css: "status-md")
|
12
|
+
# = daisy_status(css: "status-lg")
|
13
|
+
# = daisy_status(css: "status-xl")
|
14
|
+
#
|
15
|
+
# @loco_example Status with Color
|
16
|
+
# = daisy_status(css: "status-primary")
|
17
|
+
# = daisy_status(css: "status-secondary")
|
18
|
+
# = daisy_status(css: "status-accent")
|
19
|
+
# = daisy_status(css: "status-info")
|
20
|
+
# = daisy_status(css: "status-success")
|
21
|
+
# = daisy_status(css: "status-warning")
|
22
|
+
# = daisy_status(css: "status-error")
|
23
|
+
#
|
24
|
+
# @loco_example Status with Accessibility
|
25
|
+
# = daisy_status(css: "status-success", html: { aria: { label: "Status: Online" } })
|
26
|
+
class Daisy::DataDisplay::StatusComponent < LocoMotion::BaseComponent
|
27
|
+
include LocoMotion::Concerns::TippableComponent
|
28
|
+
|
29
|
+
def initialize(**kws)
|
30
|
+
super(**kws)
|
31
|
+
end
|
32
|
+
|
33
|
+
def before_render
|
34
|
+
setup_component
|
35
|
+
super # Call super after setup
|
36
|
+
end
|
37
|
+
|
38
|
+
def call
|
39
|
+
part(:component)
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def setup_component
|
45
|
+
add_css(:component, "status")
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
= part(:component) do
|
2
|
+
= previous_icon if previous_icon?
|
3
|
+
= next_icon if next_icon?
|
4
|
+
|
5
|
+
- if @month_count
|
6
|
+
= part(:months) do
|
7
|
+
- @month_count.times do |index|
|
8
|
+
= render(MonthComponent.new(**month_options(index)))
|
9
|
+
|
10
|
+
- elsif months?
|
11
|
+
= months
|
12
|
+
|
13
|
+
- else
|
14
|
+
= content
|
@@ -0,0 +1,182 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Daisy
|
4
|
+
module DataInput
|
5
|
+
# The Cally component provides a customizable calendar interface for date selection.
|
6
|
+
# It supports both single date and date range selection, with configurable display
|
7
|
+
# options including the number of months to show and navigation controls.
|
8
|
+
#
|
9
|
+
# @part component The root calendar element that contains all other parts.
|
10
|
+
# @part months The container element that holds the individual month components.
|
11
|
+
#
|
12
|
+
# @slot previous_icon [PreviousIcon] The icon used for navigating to the
|
13
|
+
# previous month. Defaults to a chevron-left icon.
|
14
|
+
# @see #default_previous_icon
|
15
|
+
# @slot next_icon [NextIcon] The icon used for navigating to the next month.
|
16
|
+
# Defaults to a chevron-right icon.
|
17
|
+
# @see #default_next_icon
|
18
|
+
# @slot months+ [MonthComponent] The month components to display in the calendar.
|
19
|
+
# Multiple months can be displayed side by side.
|
20
|
+
# @see #month_options
|
21
|
+
#
|
22
|
+
# @loco_example Basic calendar with default options
|
23
|
+
# = daisy_cally
|
24
|
+
#
|
25
|
+
# @loco_example Calendar with range selection enabled
|
26
|
+
# = daisy_cally(modifier: :range)
|
27
|
+
#
|
28
|
+
# @loco_example Calendar showing multiple months with custom value
|
29
|
+
# = daisy_cally(months: 2, value: Date.today)
|
30
|
+
#
|
31
|
+
# @loco_example Calendar with min/max date constraints
|
32
|
+
# = daisy_cally(min: 1.month.ago, max: 1.month.from_now)
|
33
|
+
class CallyComponent < LocoMotion::BaseComponent
|
34
|
+
include ViewComponent::SlotableDefault
|
35
|
+
|
36
|
+
# A component for the previous navigation icon in the calendar header.
|
37
|
+
#
|
38
|
+
# @note This is used internally by CallyComponent
|
39
|
+
class PreviousIcon < Hero::IconComponent
|
40
|
+
def before_render
|
41
|
+
super
|
42
|
+
|
43
|
+
add_html(:component, { slot: "previous" })
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# A component for the next navigation icon in the calendar header.
|
48
|
+
#
|
49
|
+
# @note This is used internally by CallyComponent
|
50
|
+
class NextIcon < Hero::IconComponent
|
51
|
+
def before_render
|
52
|
+
super
|
53
|
+
|
54
|
+
add_html(:component, { slot: "next" })
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# A component representing a single month in the calendar.
|
59
|
+
#
|
60
|
+
# @note This is used internally by CallyComponent
|
61
|
+
class MonthComponent < LocoMotion::BaseComponent
|
62
|
+
# @param offset [Integer, nil] The offset of this month from the start date
|
63
|
+
def initialize(**kws)
|
64
|
+
super
|
65
|
+
|
66
|
+
@offset = config_option(:offset)
|
67
|
+
end
|
68
|
+
|
69
|
+
def before_render
|
70
|
+
super
|
71
|
+
|
72
|
+
set_tag_name(:component, "calendar-month")
|
73
|
+
add_html(:component, { offset: @offset }) if @offset
|
74
|
+
end
|
75
|
+
|
76
|
+
def call
|
77
|
+
part(:component)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
define_modifiers :range
|
82
|
+
|
83
|
+
renders_one :previous_icon, PreviousIcon
|
84
|
+
renders_one :next_icon, NextIcon
|
85
|
+
renders_many :months, MonthComponent
|
86
|
+
|
87
|
+
define_parts :months
|
88
|
+
|
89
|
+
# Initializes a new CallyComponent.
|
90
|
+
#
|
91
|
+
# The Cally component provides a customizable calendar interface for date
|
92
|
+
# selection. It supports single date selection by default and can be
|
93
|
+
# configured for date range selection. The component automatically
|
94
|
+
# handles navigation between months and can display multiple months.
|
95
|
+
#
|
96
|
+
# @param change [String] ID of an input to update with the selected date.
|
97
|
+
# Mutually exclusive with `update`.
|
98
|
+
# @param update [String] ID of an element to update with the selected
|
99
|
+
# date. Mutually exclusive with `change`.
|
100
|
+
# @param id [String] The ID of the calendar element
|
101
|
+
# @param value [String, Date] The currently selected date or range
|
102
|
+
# @param min [String, Date] The minimum selectable date
|
103
|
+
# @param max [String, Date] The maximum selectable date
|
104
|
+
# @param today [String, Date] The date to consider as 'today'
|
105
|
+
# @param months [Integer] Number of months to display (default: 1)
|
106
|
+
def initialize(**kws)
|
107
|
+
super
|
108
|
+
|
109
|
+
# If we don't have any modifiers, assume we want a single month for a date select
|
110
|
+
@month_count = config_option(:months, modifiers.blank? ? 1 : nil)
|
111
|
+
@change = config_option(:change)
|
112
|
+
@update = config_option(:update)
|
113
|
+
|
114
|
+
@id = config_option(:id)
|
115
|
+
@value = config_option(:value)
|
116
|
+
@min = config_option(:min)
|
117
|
+
@max = config_option(:max)
|
118
|
+
@today = config_option(:today)
|
119
|
+
end
|
120
|
+
|
121
|
+
# Configures the calendar component before rendering.
|
122
|
+
#
|
123
|
+
# Sets up the appropriate tag name based on whether range selection is
|
124
|
+
# enabled, adds CSS classes, and configures HTML attributes for the
|
125
|
+
# calendar component.
|
126
|
+
def before_render
|
127
|
+
super
|
128
|
+
|
129
|
+
if modifiers.include?(:range)
|
130
|
+
set_tag_name(:component, "calendar-range")
|
131
|
+
else
|
132
|
+
set_tag_name(:component, "calendar-date")
|
133
|
+
end
|
134
|
+
|
135
|
+
add_css(:component, "cally")
|
136
|
+
add_html(:component, { months: @month_count }) if @month_count
|
137
|
+
|
138
|
+
add_html(:component, {
|
139
|
+
id: @id,
|
140
|
+
value: @value,
|
141
|
+
min: @min,
|
142
|
+
max: @max,
|
143
|
+
today: @today
|
144
|
+
})
|
145
|
+
|
146
|
+
if @change
|
147
|
+
add_html(:component, { onchange: "document.getElementById('#{@change}').value = this.value" })
|
148
|
+
end
|
149
|
+
|
150
|
+
if @update
|
151
|
+
add_html(:component, { onchange: "document.getElementById('#{@update}').innerHTML = this.value" })
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
# Generates options for a month component at the given index.
|
156
|
+
#
|
157
|
+
# @param index [Integer] The 0-based index of the month
|
158
|
+
# @return [Hash] Options hash for the month component
|
159
|
+
def month_options(index)
|
160
|
+
options = {}
|
161
|
+
|
162
|
+
options[:offset] = index if index > 0
|
163
|
+
|
164
|
+
options
|
165
|
+
end
|
166
|
+
|
167
|
+
# Provides a default previous icon if none is specified.
|
168
|
+
#
|
169
|
+
# @return [PreviousIcon] A chevron-left icon
|
170
|
+
def default_previous_icon
|
171
|
+
PreviousIcon.new(icon: "chevron-left")
|
172
|
+
end
|
173
|
+
|
174
|
+
# Provides a default next icon if none is specified.
|
175
|
+
#
|
176
|
+
# @return [NextIcon] A chevron-right icon
|
177
|
+
def default_next_icon
|
178
|
+
NextIcon.new(icon: "chevron-right")
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
@@ -0,0 +1,165 @@
|
|
1
|
+
module Daisy
|
2
|
+
module DataInput
|
3
|
+
# A specialized input component that combines a text input with a calendar
|
4
|
+
# picker. The calendar appears in a popover when the input is focused or
|
5
|
+
# clicked.
|
6
|
+
#
|
7
|
+
# @part popover The container for the calendar popover.
|
8
|
+
#
|
9
|
+
# @slot input The text input component.
|
10
|
+
# @slot calendar The calendar component that appears in the popover.
|
11
|
+
#
|
12
|
+
# @loco_example Basic Usage
|
13
|
+
# = daisy_cally_input(name: "event_date", value: Date.today)
|
14
|
+
#
|
15
|
+
# @loco_example With custom calendar and input components
|
16
|
+
# = daisy_cally_input(name: "event_date") do |c|
|
17
|
+
# = c.with_calendar(css: "custom-calendar")
|
18
|
+
# = c.with_input(css: "custom-input")
|
19
|
+
class CallyInputComponent < LocoMotion::BaseComponent
|
20
|
+
# A specialized text input component for the CallyInput that handles
|
21
|
+
# popover targeting and data attributes needed for the Stimulus
|
22
|
+
# controller.
|
23
|
+
class CallyTextInputComponent < Daisy::DataInput::TextInputComponent
|
24
|
+
# Sets up the HTML attributes needed for the text input before
|
25
|
+
# rendering. Configures the popover target, ID, name, and data
|
26
|
+
# attributes required for the Stimulus controller to function properly.
|
27
|
+
#
|
28
|
+
# @return [void]
|
29
|
+
def before_render
|
30
|
+
parent_config = loco_parent.config
|
31
|
+
|
32
|
+
# Since we're pulling options from the parent, we have to do a little
|
33
|
+
# more work to ensure we set it up correctly.
|
34
|
+
@start = config_option(:start, parent_config.options[:start])
|
35
|
+
@end = config_option(:end, parent_config.options[:end])
|
36
|
+
@floating_placeholder = config_option(:floating_placeholder, parent_config.options[:floating_placeholder])
|
37
|
+
@floating = config_option(:floating, parent_config.options[:floating] || @floating_placeholder)
|
38
|
+
@placeholder = config_option(:placeholder, parent_config.options[:placeholder] || @floating_placeholder)
|
39
|
+
|
40
|
+
super
|
41
|
+
|
42
|
+
add_html(:component, {
|
43
|
+
popovertarget: loco_parent.popover_id,
|
44
|
+
id: @id || loco_parent.input_id,
|
45
|
+
name: @name || loco_parent.name,
|
46
|
+
value: @value || parent_config.options[:value],
|
47
|
+
placeholder: @placeholder,
|
48
|
+
style: "anchor-name:--#{loco_parent.anchor}",
|
49
|
+
data: {
|
50
|
+
"loco-cally-input-target": "input"
|
51
|
+
}
|
52
|
+
})
|
53
|
+
end
|
54
|
+
|
55
|
+
def call
|
56
|
+
render_parent_to_string
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# A specialized calendar component for the CallyInput that handles the calendar
|
61
|
+
# display and interaction within a popover.
|
62
|
+
class CallyCalendarComponent < Daisy::DataInput::CallyComponent
|
63
|
+
# Sets up the HTML attributes needed for the calendar before rendering.
|
64
|
+
# Configures the ID, value, and data attributes required for the Stimulus controller.
|
65
|
+
#
|
66
|
+
# @return [void]
|
67
|
+
def before_render
|
68
|
+
super
|
69
|
+
|
70
|
+
add_html(:component, {
|
71
|
+
id: @id || loco_parent.calendar_id,
|
72
|
+
value: @value || loco_parent.value,
|
73
|
+
data: {
|
74
|
+
"loco-cally-input-target": "calendar"
|
75
|
+
}
|
76
|
+
})
|
77
|
+
end
|
78
|
+
|
79
|
+
def call
|
80
|
+
render_parent_to_string
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
include ViewComponent::SlotableDefault
|
85
|
+
include LocoMotion::Concerns::LabelableComponent
|
86
|
+
|
87
|
+
define_parts :popover
|
88
|
+
|
89
|
+
renders_one :calendar, CallyCalendarComponent
|
90
|
+
renders_one :input, CallyTextInputComponent
|
91
|
+
|
92
|
+
attr_reader :id, :name, :value, :calendar_id, :input_id, :popover_id, :anchor, :auto_scroll_padding
|
93
|
+
|
94
|
+
# Initializes a new CallyInputComponent.
|
95
|
+
#
|
96
|
+
# @param [Hash] kws The options hash
|
97
|
+
# @option kws [String] :id A unique identifier for the input (default: auto-generated)
|
98
|
+
# @option kws [String] :name The name attribute for the input field
|
99
|
+
# @option kws [Date, String] :value The initial value of the input (default: nil)
|
100
|
+
# @option kws [Integer] :auto_scroll_padding The padding to use when scrolling the calendar into view (default: 100)
|
101
|
+
# @option kws [String] :css Additional CSS classes for the component
|
102
|
+
def initialize(**kws)
|
103
|
+
super(**kws)
|
104
|
+
|
105
|
+
@id = config_option(:id, SecureRandom.uuid)
|
106
|
+
@name = config_option(:name)
|
107
|
+
@value = config_option(:value)
|
108
|
+
@auto_scroll_padding = config_option(:auto_scroll_padding, 100)
|
109
|
+
|
110
|
+
# Input ID should match our ID
|
111
|
+
@input_id = @id
|
112
|
+
|
113
|
+
# Other IDs / options are generated
|
114
|
+
@calendar_id = "#{@id}-calendar"
|
115
|
+
@popover_id = "#{@id}-popover"
|
116
|
+
@anchor = "#{@id}-anchor"
|
117
|
+
end
|
118
|
+
|
119
|
+
# Sets up the component before rendering.
|
120
|
+
# Calls the parent's before_render and then runs the component setup.
|
121
|
+
#
|
122
|
+
# @return [void]
|
123
|
+
def before_render
|
124
|
+
super
|
125
|
+
|
126
|
+
setup_component
|
127
|
+
end
|
128
|
+
|
129
|
+
# Provides a default calendar component instance.
|
130
|
+
# This is used when no custom calendar component is provided.
|
131
|
+
#
|
132
|
+
# @return [CallyCalendarComponent] A new instance of the default calendar component
|
133
|
+
def default_calendar
|
134
|
+
CallyCalendarComponent.new
|
135
|
+
end
|
136
|
+
|
137
|
+
# Provides a default input component instance.
|
138
|
+
# This is used when no custom input component is provided.
|
139
|
+
#
|
140
|
+
# @return [CallyTextInputComponent] A new instance of the default input component
|
141
|
+
def default_input
|
142
|
+
CallyTextInputComponent.new
|
143
|
+
end
|
144
|
+
|
145
|
+
private
|
146
|
+
|
147
|
+
# Sets up the component's HTML structure and attributes.
|
148
|
+
# Configures the Stimulus controller and popover attributes.
|
149
|
+
#
|
150
|
+
# @return [void]
|
151
|
+
# @private
|
152
|
+
def setup_component
|
153
|
+
# Ensure we attach the Stimulus controller
|
154
|
+
add_stimulus_controller(:component, "loco-cally-input")
|
155
|
+
|
156
|
+
# Add relevant popover part HTML
|
157
|
+
add_html(:popover, { id: @popover_id, popover: "auto", style: "position-anchor:--#{@anchor}" })
|
158
|
+
add_html(:popover, { data: { "loco-cally-input-target": "popover", "auto-scroll-padding": @auto_scroll_padding } })
|
159
|
+
|
160
|
+
# Note that we NEED the dropdown class so that the anchor positioning works properly
|
161
|
+
add_css(:popover, "where:dropdown where:bg-base-100 where:rounded where:shadow-lg")
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|