loco_motion-rails 0.0.8 → 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.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +62 -14
  3. data/app/components/daisy/actions/button_component.html.haml +2 -2
  4. data/app/components/daisy/actions/button_component.rb +98 -59
  5. data/app/components/daisy/actions/dropdown_component.html.haml +1 -2
  6. data/app/components/daisy/actions/dropdown_component.rb +7 -10
  7. data/app/components/daisy/actions/modal_component.html.haml +10 -8
  8. data/app/components/daisy/actions/modal_component.rb +6 -6
  9. data/app/components/daisy/actions/swap_component.rb +13 -9
  10. data/app/components/daisy/actions/theme_controller.js +113 -0
  11. data/app/components/daisy/actions/theme_controller_component.rb +58 -17
  12. data/app/components/daisy/actions/theme_preview_component.html.haml +5 -0
  13. data/app/components/daisy/actions/theme_preview_component.rb +68 -0
  14. data/app/components/daisy/data_display/accordion_component.html.haml +0 -1
  15. data/app/components/daisy/data_display/accordion_component.rb +10 -3
  16. data/app/components/daisy/data_display/avatar_component.html.haml +1 -1
  17. data/app/components/daisy/data_display/avatar_component.rb +17 -7
  18. data/app/components/daisy/data_display/badge_component.rb +122 -4
  19. data/app/components/daisy/data_display/card_component.html.haml +1 -1
  20. data/app/components/daisy/data_display/card_component.rb +20 -6
  21. data/app/components/daisy/data_display/chat_component.rb +2 -2
  22. data/app/components/daisy/data_display/collapse_component.rb +9 -5
  23. data/app/components/daisy/data_display/countdown_component.rb +15 -5
  24. data/app/components/daisy/data_display/figure_component.rb +8 -3
  25. data/app/components/daisy/data_display/kbd_component.rb +13 -4
  26. data/app/components/daisy/data_display/list_component.html.haml +5 -0
  27. data/app/components/daisy/data_display/list_component.rb +82 -0
  28. data/app/components/daisy/data_display/list_item_component.rb +39 -0
  29. data/app/components/daisy/data_display/stat_component.html.haml +5 -6
  30. data/app/components/daisy/data_display/stat_component.rb +21 -8
  31. data/app/components/daisy/data_display/status_component.rb +47 -0
  32. data/app/components/daisy/data_display/timeline_component.rb +1 -1
  33. data/app/components/daisy/data_input/cally_component.html.haml +14 -0
  34. data/app/components/daisy/data_input/cally_component.rb +182 -0
  35. data/app/components/daisy/data_input/cally_input_component.html.haml +5 -0
  36. data/app/components/daisy/data_input/cally_input_component.rb +165 -0
  37. data/app/components/daisy/data_input/cally_input_controller.js +235 -0
  38. data/app/components/daisy/data_input/checkbox_component.html.haml +20 -0
  39. data/app/components/daisy/data_input/checkbox_component.rb +106 -0
  40. data/app/components/daisy/data_input/fieldset_component.html.haml +8 -0
  41. data/app/components/daisy/data_input/fieldset_component.rb +57 -0
  42. data/app/components/daisy/data_input/file_input_component.rb +98 -0
  43. data/app/components/daisy/data_input/filter_component.html.haml +3 -0
  44. data/app/components/daisy/data_input/filter_component.rb +221 -0
  45. data/app/components/daisy/data_input/label_component.rb +84 -0
  46. data/app/components/daisy/data_input/radio_button_component.rb +87 -0
  47. data/app/components/daisy/data_input/range_component.rb +95 -0
  48. data/app/components/daisy/data_input/rating_component.html.haml +11 -0
  49. data/app/components/daisy/data_input/rating_component.rb +139 -0
  50. data/app/components/daisy/data_input/select_component.html.haml +27 -0
  51. data/app/components/daisy/data_input/select_component.rb +320 -0
  52. data/app/components/daisy/data_input/text_area_component.rb +127 -0
  53. data/app/components/daisy/data_input/text_input_component.html.haml +27 -0
  54. data/app/components/daisy/data_input/text_input_component.rb +142 -0
  55. data/app/components/daisy/data_input/toggle_component.rb +48 -0
  56. data/app/components/daisy/feedback/alert_component.html.haml +1 -1
  57. data/app/components/daisy/feedback/alert_component.rb +86 -2
  58. data/app/components/daisy/feedback/loading_component.rb +10 -3
  59. data/app/components/daisy/feedback/skeleton_component.rb +1 -1
  60. data/app/components/daisy/layout/divider_component.rb +4 -2
  61. data/app/components/daisy/layout/drawer_component.html.haml +0 -1
  62. data/app/components/daisy/layout/footer_component.rb +6 -6
  63. data/app/components/daisy/mockup/device_component.rb +15 -18
  64. data/app/components/daisy/navigation/breadcrumbs_component.html.haml +0 -1
  65. data/app/components/daisy/navigation/breadcrumbs_component.rb +84 -9
  66. data/app/components/daisy/navigation/dock_component.rb +146 -0
  67. data/app/components/daisy/navigation/link_component.rb +18 -9
  68. data/app/components/daisy/navigation/menu_component.rb +15 -9
  69. data/app/components/daisy/navigation/navbar_component.html.haml +1 -1
  70. data/app/components/daisy/navigation/navbar_component.rb +2 -13
  71. data/app/components/daisy/navigation/steps_component.rb +6 -6
  72. data/app/components/daisy/navigation/tabs_component.html.haml +0 -1
  73. data/app/components/daisy/navigation/tabs_component.rb +26 -16
  74. data/app/components/hero/icon_component.rb +15 -5
  75. data/app/helpers/daisy/form_builder_helper.rb +186 -0
  76. data/app/views/examples/daisy/data_input/filters.html.haml +62 -0
  77. data/lib/daisy.rb +5 -0
  78. data/lib/hero.rb +1 -1
  79. data/lib/loco_motion/base_component.rb +53 -3
  80. data/lib/loco_motion/component_config.rb +1 -0
  81. data/lib/loco_motion/concerns/iconable_component.rb +134 -0
  82. data/lib/loco_motion/concerns/labelable_component.rb +142 -0
  83. data/lib/loco_motion/concerns/linkable_component.rb +40 -0
  84. data/lib/loco_motion/concerns/tippable_component.rb +25 -10
  85. data/lib/loco_motion/engine.rb +6 -0
  86. data/lib/loco_motion/helpers.rb +38 -17
  87. data/lib/loco_motion/patches/view_component/slot_loco_parent_patch.rb +37 -0
  88. data/lib/loco_motion/patches/view_component/slotable_default_patch.rb +21 -0
  89. data/lib/loco_motion/version.rb +1 -1
  90. data/lib/loco_motion.rb +12 -2
  91. metadata +93 -21
  92. data/app/components/daisy/actions/theme_controller_component.html.haml +0 -5
  93. data/app/components/daisy/layout/artboard_component.rb +0 -59
  94. data/app/components/daisy/navigation/bottom_nav_component.rb +0 -138
@@ -1,16 +1,21 @@
1
1
  class LocoMotion::BaseComponent < ViewComponent::Base
2
2
 
3
3
  SELF_CLOSING_TAGS = %i[area base br col embed hr img input keygen link meta param source track wbr].freeze
4
+ EMPTY_PART_IGNORED_TAGS = %i[textarea].freeze
4
5
 
5
- include Heroicons::IconsHelper
6
+ include RailsHeroicon::Helper
6
7
 
7
8
  class_attribute :component_name
8
9
  class_attribute :component_parts, default: { component: {} }
9
10
  class_attribute :valid_modifiers, default: []
10
11
  class_attribute :valid_sizes, default: []
11
12
 
13
+ # Hooks for concerns to register initialization and setup methods
14
+ class_attribute :component_initializers, default: []
15
+ class_attribute :component_setups, default: []
16
+
12
17
  #
13
- # Return the current configruation of this component.
18
+ # Return the current configuration of this component.
14
19
  #
15
20
  # @return LocoMotion::ComponentConfig
16
21
  #
@@ -30,6 +35,24 @@ class LocoMotion::BaseComponent < ViewComponent::Base
30
35
 
31
36
  # Create our config object
32
37
  @config = LocoMotion::ComponentConfig.new(self, **kws, &block)
38
+
39
+ # Run registered initializer hooks from concerns
40
+ self.class.component_initializers.each { |initializer| send(initializer) }
41
+
42
+ # Allow certain components to skip styling if they are being inherited
43
+ @skip_styling = config_option(:skip_styling, false)
44
+
45
+ # Allow manual passing of the loco parent on init if it's not auto-set
46
+ # via slots
47
+ @loco_parent = kws[:loco_parent] if kws.key?(:loco_parent)
48
+ end
49
+
50
+ #
51
+ # Run registered setup hooks from concerns before rendering.
52
+ #
53
+ def before_render
54
+ # Note: ViewComponent::Base does not define before_render, so no super call needed.
55
+ self.class.component_setups.each { |setup| send(setup) }
33
56
  end
34
57
 
35
58
  #
@@ -86,6 +109,26 @@ class LocoMotion::BaseComponent < ViewComponent::Base
86
109
  end
87
110
  end
88
111
 
112
+ #
113
+ # Register an instance method to be called during component initialization.
114
+ #
115
+ # @param method_name [Symbol] The name of the instance method to call.
116
+ #
117
+ def self.register_component_initializer(method_name)
118
+ # Ensure we don't modify the parent class's array directly
119
+ self.component_initializers += [method_name.to_sym]
120
+ end
121
+
122
+ #
123
+ # Register an instance method to be called before component rendering.
124
+ #
125
+ # @param method_name [Symbol] The name of the instance method to call.
126
+ #
127
+ def self.register_component_setup(method_name)
128
+ # Ensure we don't modify the parent class's array directly
129
+ self.component_setups += [method_name.to_sym]
130
+ end
131
+
89
132
  #
90
133
  # Defines a single modifier of this component. Modifiers control certain
91
134
  # rendering aspects of the component.
@@ -225,12 +268,18 @@ class LocoMotion::BaseComponent < ViewComponent::Base
225
268
  tag(tag_name, **rendered_html(part_name))
226
269
  else
227
270
  content_tag(tag_name, **rendered_html(part_name)) do
228
- "<!-- Empty Part Block //-->".html_safe
271
+ empty_part_content(tag_name)
229
272
  end
230
273
  end
231
274
  end
232
275
  end
233
276
 
277
+ def empty_part_content(tag_name)
278
+ unless EMPTY_PART_IGNORED_TAGS.include?(tag_name.to_sym)
279
+ "<!-- Empty Part Block //-->".html_safe
280
+ end
281
+ end
282
+
234
283
  #
235
284
  # Returns the user-provided or component-default HTML tag-name.
236
285
  #
@@ -366,6 +415,7 @@ class LocoMotion::BaseComponent < ViewComponent::Base
366
415
  "@valid_sizes=#{valid_sizes.inspect}",
367
416
  "@config=#{@config.inspect}",
368
417
  "@component_parts=#{parts.inspect}",
418
+ "@loco_parent=#{loco_parent.inspect}",
369
419
  ].join(" ") + ">"
370
420
  end
371
421
  end
@@ -40,6 +40,7 @@ class LocoMotion::ComponentConfig
40
40
  @parts[:component][:user_tag_name] = kws[:tag_name] if kws[:tag_name]
41
41
  @parts[:component][:user_css].push(kws[:css]) if kws[:css]
42
42
  @parts[:component][:user_html].deep_merge!(kws[:html]) if kws[:html]
43
+ @parts[:component][:user_stimulus_controllers].push(kws[:controller]) if kws[:controller]
43
44
  @parts[:component][:user_stimulus_controllers].push(kws[:controllers]) if kws[:controllers]
44
45
  end
45
46
 
@@ -0,0 +1,134 @@
1
+ require "active_support/concern"
2
+
3
+ module LocoMotion
4
+ module Concerns
5
+ #
6
+ # The IconableComponent concern provides functionality for components that
7
+ # display icons. It supports both left and right icons and allows for
8
+ # customization of their CSS classes and HTML attributes.
9
+ #
10
+ module IconableComponent
11
+ extend ActiveSupport::Concern
12
+
13
+ included do |base|
14
+ base.register_component_initializer(:_initialize_iconable_component)
15
+ base.register_component_setup(:_setup_iconable_component)
16
+ end
17
+
18
+ protected
19
+
20
+ #
21
+ # Initialize icon-related options.
22
+ #
23
+ # @option kws icon [String] The name of Hero icon to render. This is an
24
+ # alias of `left_icon`.
25
+ #
26
+ # @option kws icon_css [String] The CSS classes to apply to the icon. This
27
+ # is an alias of `left_icon_css`.
28
+ #
29
+ # @option kws icon_html [Hash] Additional HTML attributes to apply to the
30
+ # icon. This is an alias of `left_icon_html`.
31
+ #
32
+ # @option kws left_icon [String] The name of Hero icon to render to the
33
+ # left of the content.
34
+ #
35
+ # @option kws left_icon_css [String] The CSS classes to apply to the left
36
+ # icon.
37
+ #
38
+ # @option kws left_icon_html [Hash] Additional HTML attributes to apply to
39
+ # the left icon.
40
+ #
41
+ # @option kws right_icon [String] The name of Hero icon to render to the
42
+ # right of the content.
43
+ #
44
+ # @option kws right_icon_css [String] The CSS classes to apply to the right
45
+ # icon.
46
+ #
47
+ # @option kws right_icon_html [Hash] Additional HTML attributes to apply to
48
+ # the right icon.
49
+ #
50
+ def _initialize_iconable_component
51
+ @icon = config_option(:icon)
52
+ @icon_css = config_option(:icon_css, default_icon_size)
53
+ @icon_options = config_option(:icon_options, {})
54
+ @icon_html = config_option(:icon_html, {})
55
+
56
+ @left_icon = config_option(:left_icon, @icon)
57
+ @left_icon_css = config_option(:left_icon_css, @icon_css)
58
+ @left_icon_options = config_option(:left_icon_options, @icon_html)
59
+ @left_icon_html = config_option(:left_icon_html, @icon_html)
60
+
61
+ @right_icon = config_option(:right_icon)
62
+ @right_icon_css = config_option(:right_icon_css, @icon_css)
63
+ @right_icon_options = config_option(:right_icon_options, {})
64
+ @right_icon_html = config_option(:right_icon_html, @icon_html)
65
+ end
66
+
67
+ #
68
+ # Configure CSS classes for a component with icons.
69
+ # This adds necessary classes for proper icon spacing and alignment.
70
+ #
71
+ def _setup_iconable_component
72
+ if @icon || @left_icon || @right_icon
73
+ add_css(:component, "where:inline-flex where:items-center where:gap-2")
74
+ end
75
+ end
76
+
77
+ def default_icon_size
78
+ "where:size-5"
79
+ end
80
+
81
+ public # Ensure these helper methods remain public
82
+
83
+ #
84
+ # Returns the HTML attributes for the left icon.
85
+ #
86
+ # @return [Hash] HTML attributes for the left icon
87
+ #
88
+ def left_icon_html
89
+ { class: @left_icon_css }.merge(@left_icon_html)
90
+ end
91
+
92
+ #
93
+ # Returns the HTML attributes for the right icon.
94
+ #
95
+ # @return [Hash] HTML attributes for the right icon
96
+ #
97
+ def right_icon_html
98
+ { class: @right_icon_css }.merge(@right_icon_html)
99
+ end
100
+
101
+ #
102
+ # Determines if any icons are present in the component.
103
+ #
104
+ # @return [Boolean] true if any icons are configured, false otherwise
105
+ #
106
+ def has_icons?
107
+ @left_icon.present? || @right_icon.present?
108
+ end
109
+
110
+ #
111
+ # Renders the left icon as a Hero::IconComponent instance.
112
+ #
113
+ # @return [String] The rendered HTML for the icon
114
+ #
115
+ def render_left_icon
116
+ return unless @left_icon.present?
117
+
118
+ hero_icon(@left_icon, css: @left_icon_css, html: @left_icon_html, **@left_icon_options)
119
+ end
120
+ alias_method :render_icon, :render_left_icon
121
+
122
+ #
123
+ # Renders the right icon using a hero icon.
124
+ #
125
+ # @return [String] The rendered HTML for the icon
126
+ #
127
+ def render_right_icon
128
+ return unless @right_icon.present?
129
+
130
+ hero_icon(@right_icon, css: @right_icon_css, html: @right_icon_html, **@right_icon_options)
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,142 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LocoMotion
4
+ module Concerns
5
+ #
6
+ # Can be included in relevant components to add labeling functionality.
7
+ # This adds support for start, end, and floating labels that can either be
8
+ # provided as plain text or customized via slots.
9
+ #
10
+ # @loco_example Basic usage with a start label
11
+ # class MyInputComponent < LocoMotion::BaseComponent
12
+ # include LocoMotion::Concerns::LabelableComponent
13
+ # # component implementation ...
14
+ # end
15
+ #
16
+ # = daisy_my_input(name: "username", start: "Username")
17
+ #
18
+ # @loco_example With an end label (useful for checkboxes/radios)
19
+ # = daisy_checkbox(name: "terms", end: "I agree to the terms")
20
+ #
21
+ # @loco_example With a floating label
22
+ # = daisy_text_input(name: "email", floating: "Email Address")
23
+ #
24
+ # @loco_example Using a custom slot for the label
25
+ # = daisy_text_input(name: "password") do |input|
26
+ # - input.with_floating do
27
+ # Password
28
+ # %span.text-red-500 *
29
+ #
30
+ module LabelableComponent
31
+ extend ActiveSupport::Concern
32
+
33
+ #
34
+ # Called when the module is included in a component class.
35
+ # Sets up the necessary parts & slots for custom label content.
36
+ #
37
+ included do
38
+ define_parts :label_wrapper, :start, :end, :floating
39
+
40
+ renders_one :start
41
+ renders_one :end
42
+ renders_one :floating
43
+
44
+ # NOTE: We DO NOT define attr_reader properties here because it can
45
+ # cause confusion / problems with the parts and slots.
46
+ end
47
+
48
+ #
49
+ # Initializes the component and sets up the label options.
50
+ #
51
+ # @param instance_args [Array] Positional arguments passed to the component
52
+ #
53
+ # @param instance_kws [Hash] Keyword arguments passed to the component
54
+ #
55
+ # @option instance_kws [String, nil] :start Text to display in the start
56
+ # label position
57
+ #
58
+ # @option instance_kws [String, nil] :end Text to display in the end
59
+ # label position
60
+ #
61
+ # @option instance_kws [String, nil] :floating Text to display in the
62
+ # floating label position
63
+ #
64
+ # @option instance_kws [String, nil] :placeholder The input's placeholder
65
+ # text. If not provided and `floating_placeholder` is set, it will use
66
+ # that value.
67
+ #
68
+ # @option instance_kws [String, nil] :floating_placeholder Text to use for
69
+ # both the floating label and the input placeholder. This is a
70
+ # convenience option that sets both the `floating` and `placeholder`
71
+ # options to the same value. Both `floating` and `placeholder` take
72
+ # precedence over `floating_placeholder`.
73
+ #
74
+ # @param instance_block [Proc] Block passed to the component for rendering
75
+ # custom content
76
+ #
77
+ def initialize(*instance_args, **instance_kws, &instance_block)
78
+ super(*instance_args, **instance_kws, &instance_block)
79
+
80
+ @floating_placeholder = config_option(:floating_placeholder)
81
+
82
+ @start = config_option(:start)
83
+ @end = config_option(:end)
84
+ @floating = config_option(:floating, @floating_placeholder)
85
+ @placeholder = config_option(:placeholder, @floating_placeholder)
86
+ end
87
+
88
+ #
89
+ # Sets up the tag names for the label parts before rendering the component.
90
+ # This method is called automatically during the component rendering
91
+ # lifecycle.
92
+ #
93
+ # Note that CSS classes for labels must be handled by the implementing
94
+ # component since requirements differ for each type of input component.
95
+ #
96
+ def before_render
97
+ super
98
+
99
+ set_tag_name(:label_wrapper, :label)
100
+ set_tag_name(:start, :span)
101
+ set_tag_name(:end, :span)
102
+ set_tag_name(:floating, :span)
103
+ end
104
+
105
+ #
106
+ # Checks if any type of label is present.
107
+ #
108
+ # @return [Boolean] true if any label is present, false otherwise
109
+ #
110
+ def has_any_label?
111
+ has_start_label? || has_end_label? || has_floating_label?
112
+ end
113
+
114
+ #
115
+ # Checks if a start label is present.
116
+ #
117
+ # @return [Boolean] true if start label is present, false otherwise
118
+ #
119
+ def has_start_label?
120
+ start? || @start || config_option(:start).present?
121
+ end
122
+
123
+ #
124
+ # Checks if an end label is present.
125
+ #
126
+ # @return [Boolean] true if end label is present, false otherwise
127
+ #
128
+ def has_end_label?
129
+ end? || @end || config_option(:end).present?
130
+ end
131
+
132
+ #
133
+ # Checks if a floating label is present.
134
+ #
135
+ # @return [Boolean] true if floating label is present, false otherwise
136
+ #
137
+ def has_floating_label?
138
+ floating? || @floating || config_option(:floating).present?
139
+ end
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,40 @@
1
+ require "active_support/concern"
2
+
3
+ module LocoMotion
4
+ module Concerns
5
+ #
6
+ # Include this module to enable link functionality in a component.
7
+ # When an href is provided, the component will render as an <a> tag.
8
+ #
9
+ module LinkableComponent
10
+ extend ActiveSupport::Concern
11
+
12
+ included do |base|
13
+ base.register_component_initializer(:_initialize_linkable_component)
14
+ base.register_component_setup(:_setup_linkable_component)
15
+ end
16
+
17
+ protected
18
+
19
+ #
20
+ # Initialize link-related options.
21
+ #
22
+ def _initialize_linkable_component
23
+ @href = config_option(:href)
24
+ @target = config_option(:target)
25
+ @title = config_option(:title)
26
+ end
27
+
28
+ #
29
+ # Sets the component's tag to <a> if an href is provided and configures the
30
+ # appropriate HTML attributes.
31
+ #
32
+ def _setup_linkable_component
33
+ if @href
34
+ set_tag_name(:component, :a)
35
+ add_html(:component, { href: @href, target: @target, title: @title })
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -1,24 +1,39 @@
1
+ require "active_support/concern"
2
+
1
3
  module LocoMotion
2
4
  module Concerns
3
5
  #
4
- # Can be included in relevant components to allow a new `tip` attibute that
6
+ # Can be included in relevant components to allow a `tip` attribute that
5
7
  # automatically adds the `tooltip` CSS class and the `data-tip` attribute
6
8
  # to the component.
7
9
  #
8
10
  module TippableComponent
11
+ extend ActiveSupport::Concern
12
+
13
+ included do |base|
14
+ base.register_component_initializer(:_initialize_tippable_component)
15
+ base.register_component_setup(:_setup_tippable_component)
16
+ end
17
+
18
+ protected
19
+
9
20
  #
10
- # Calls the parent `before_render`. Then adds the `tooltip` CSS class and
11
- # the `data-tip` attribute to the component if the `tip` attribute is
12
- # present.
21
+ # Initialize tooltip-related options.
13
22
  #
14
- def before_render
15
- super
16
-
17
- tip = config_option(:tip)
23
+ # @option kws tip [String] The tooltip text to display when hovering
24
+ #
25
+ def _initialize_tippable_component
26
+ @tip = config_option(:tip)
27
+ end
18
28
 
19
- if tip
29
+ #
30
+ # Configure tooltip functionality for the component.
31
+ # Adds the `tooltip` CSS class and the `data-tip` attribute if a tip is provided.
32
+ #
33
+ def _setup_tippable_component
34
+ if @tip
20
35
  add_css(:component, "tooltip")
21
- add_html(:component, { data: { tip: tip } })
36
+ add_html(:component, { data: { tip: @tip } })
22
37
  end
23
38
  end
24
39
  end
@@ -4,5 +4,11 @@ module LocoMotion
4
4
 
5
5
  config.autoload_paths << "#{root}/app"
6
6
  config.autoload_paths << "#{root}/lib"
7
+
8
+ initializer "loco_motion.form_builder_extensions" do
9
+ ActiveSupport.on_load(:action_view) do
10
+ require_relative "../../app/helpers/daisy/form_builder_helper"
11
+ end
12
+ end
7
13
  end
8
14
  end
@@ -14,24 +14,42 @@ module LocoMotion
14
14
  "Daisy::Actions::ThemeControllerComponent" => { names: "theme_controller", group: "Actions", title: "Theme Controllers", example: "theme_controllers" },
15
15
 
16
16
  # Data
17
- "Daisy::DataDisplay::AccordionComponent" => { names: "accordion", group: "Data", title: "Accordions", example: "accordions" },
18
- "Daisy::DataDisplay::AvatarComponent" => { names: "avatar", group: "Data", title: "Avatars", example: "avatars" },
19
- "Daisy::DataDisplay::BadgeComponent" => { names: "badge", group: "Data", title: "Badges", example: "badges" },
20
- "Daisy::DataDisplay::CardComponent" => { names: "card", group: "Data", title: "Cards", example: "cards" },
21
- "Daisy::DataDisplay::CarouselComponent" => { names: "carousel", group: "Data", title: "Carousels", example: "carousels" },
22
- "Daisy::DataDisplay::ChatComponent" => { names: "chat", group: "Data", title: "Chat Bubbles", example: "chat_bubbles" },
23
- "Daisy::DataDisplay::CollapseComponent" => { names: "collapse", group: "Data", title: "Collapses", example: "collapses" },
24
- "Daisy::DataDisplay::CountdownComponent" => { names: "countdown", group: "Data", title: "Countdowns", example: "countdowns" },
25
- "Daisy::DataDisplay::DiffComponent" => { names: "diff", group: "Data", title: "Diffs", example: "diffs" },
26
- "Daisy::DataDisplay::FigureComponent" => { names: "figure", group: "Data", title: "Figures", example: "figures" },
27
- "Daisy::DataDisplay::KbdComponent" => { names: "kbd", group: "Data", title: "Keyboard (KBD)", example: "kbds" },
28
- "Daisy::DataDisplay::StatComponent" => { names: "stat", group: "Data", title: "Stats", example: "stats" },
29
- "Daisy::DataDisplay::TableComponent" => { names: "table", group: "Data", title: "Tables", example: "tables" },
30
- "Daisy::DataDisplay::TimelineComponent" => { names: "timeline", group: "Data", title: "Timelines", example: "timelines" },
17
+ "Daisy::DataDisplay::AccordionComponent" => { names: "accordion", group: "Data Display", title: "Accordions", example: "accordions" },
18
+ "Daisy::DataDisplay::AvatarComponent" => { names: "avatar", group: "Data Display", title: "Avatars", example: "avatars" },
19
+ "Daisy::DataDisplay::BadgeComponent" => { names: "badge", group: "Data Display", title: "Badges", example: "badges" },
20
+ "Daisy::DataDisplay::CardComponent" => { names: "card", group: "Data Display", title: "Cards", example: "cards" },
21
+ "Daisy::DataDisplay::CarouselComponent" => { names: "carousel", group: "Data Display", title: "Carousels", example: "carousels" },
22
+ "Daisy::DataDisplay::ChatComponent" => { names: "chat", group: "Data Display", title: "Chat Bubbles", example: "chat_bubbles" },
23
+ "Daisy::DataDisplay::CollapseComponent" => { names: "collapse", group: "Data Display", title: "Collapses", example: "collapses" },
24
+ "Daisy::DataDisplay::CountdownComponent" => { names: "countdown", group: "Data Display", title: "Countdowns", example: "countdowns" },
25
+ "Daisy::DataDisplay::DiffComponent" => { names: "diff", group: "Data Display", title: "Diffs", example: "diffs" },
26
+ "Daisy::DataDisplay::FigureComponent" => { names: "figure", group: "Data Display", title: "Figures", example: "figures" },
27
+ "Daisy::DataDisplay::KbdComponent" => { names: "kbd", group: "Data Display", title: "Keyboard (KBD)", example: "kbds" },
28
+ "Daisy::DataDisplay::ListComponent" => { names: "list", group: "Data Display", title: "Lists", example: "lists" },
29
+ "Daisy::DataDisplay::StatComponent" => { names: "stat", group: "Data Display", title: "Stats", example: "stats" },
30
+ "Daisy::DataDisplay::StatusComponent" => { names: "status", group: "Data Display", title: "Statuses", example: "statuses" },
31
+ "Daisy::DataDisplay::TableComponent" => { names: "table", group: "Data Display", title: "Tables", example: "tables" },
32
+ "Daisy::DataDisplay::TimelineComponent" => { names: "timeline", group: "Data Display", title: "Timelines", example: "timelines" },
33
+
34
+ # Data Input
35
+ "Daisy::DataInput::CallyComponent" => { names: "cally", group: "Data Input", title: "Calendars", example: "calendars" },
36
+ "Daisy::DataInput::CallyInputComponent" => { names: "cally_input", group: "Data Input", title: "Cally Inputs", example: "cally_inputs" },
37
+ "Daisy::DataInput::CheckboxComponent" => { names: "checkbox", group: "Data Input", title: "Checkboxes", example: "checkboxes" },
38
+ "Daisy::DataInput::FileInputComponent" => { names: "file_input", group: "Data Input", title: "File Inputs", example: "file_inputs" },
39
+ "Daisy::DataInput::FieldsetComponent" => { names: "fieldset", group: "Data Input", title: "Fieldsets", example: "fieldsets" },
40
+ "Daisy::DataInput::FilterComponent" => { names: "filter", group: "Data Input", title: "Filters", example: "filters" },
41
+ "Daisy::DataInput::LabelComponent" => { names: "label", group: "Data Input", title: "Labels", example: "labels" },
42
+ "Daisy::DataInput::RadioButtonComponent" => { names: "radio", group: "Data Input", title: "Radio Buttons", example: "radio_buttons" },
43
+ "Daisy::DataInput::RangeComponent" => { names: "range", group: "Data Input", title: "Ranges", example: "ranges" },
44
+ "Daisy::DataInput::RatingComponent" => { names: "rating", group: "Data Input", title: "Ratings", example: "ratings" },
45
+ "Daisy::DataInput::SelectComponent" => { names: "select", group: "Data Input", title: "Selects", example: "selects" },
46
+ "Daisy::DataInput::TextInputComponent" => { names: ["input", "text_input"], group: "Data Input", title: "Text Inputs", example: "text_inputs" },
47
+ "Daisy::DataInput::TextAreaComponent" => { names: "text_area", group: "Data Input", title: "Text Areas", example: "text_areas" },
48
+ "Daisy::DataInput::ToggleComponent" => { names: "toggle", group: "Data Input", title: "Toggles", example: "toggles" },
31
49
 
32
50
  # Navigation
33
51
  "Daisy::Navigation::BreadcrumbsComponent" => { names: "breadcrumbs", group: "Navigation", title: "Breadcrumbs", example: "breadcrumbs" },
34
- "Daisy::Navigation::BottomNavComponent" => { names: "bottom_nav", group: "Navigation", title: "Bottom Navs", example: "bottom_navs" },
52
+ "Daisy::Navigation::DockComponent" => { names: "dock", group: "Navigation", title: "Dock", example: "docks" },
35
53
  "Daisy::Navigation::LinkComponent" => { names: "link", group: "Navigation", title: "Links", example: "links" },
36
54
  "Daisy::Navigation::MenuComponent" => { names: "menu", group: "Navigation", title: "Menus", example: "menus" },
37
55
  "Daisy::Navigation::NavbarComponent" => { names: "navbar", group: "Navigation", title: "Navbars", example: "navbars" },
@@ -49,7 +67,6 @@ module LocoMotion
49
67
  "Daisy::Feedback::TooltipComponent" => { names: ["tooltip", "tip"], group: "Feedback", title: "Tooltips", example: "tooltips" },
50
68
 
51
69
  # Layout
52
- "Daisy::Layout::ArtboardComponent" => { names: "artboard", group: "Layout", title: "Artboards", example: "artboards" },
53
70
  "Daisy::Layout::DividerComponent" => { names: "divider", group: "Layout", title: "Dividers", example: "dividers" },
54
71
  "Daisy::Layout::DrawerComponent" => { names: "drawer", group: "Layout", title: "Drawers", example: "drawers" },
55
72
  "Daisy::Layout::FooterComponent" => { names: "footer", group: "Layout", title: "Footers", example: "footers" },
@@ -80,6 +97,10 @@ module LocoMotion
80
97
  end
81
98
 
82
99
  def component_example_path(component_name)
100
+ "/examples/#{component_name}"
101
+ end
102
+
103
+ def component_partial_path(component_name)
83
104
  comp = COMPONENTS[component_name]
84
105
 
85
106
  comp_split = component_name.split("::")
@@ -91,6 +112,6 @@ module LocoMotion
91
112
  "/examples/#{framework}/#{section_path}#{example}"
92
113
  end
93
114
 
94
- module_function :component_example_path
115
+ module_function :component_example_path, :component_partial_path
95
116
  end
96
117
  end
@@ -0,0 +1,37 @@
1
+ # Monkey patch ViewComponent::Slot to save the parent component
2
+
3
+ module LocoMotion
4
+ module Patches
5
+ module ViewComponent
6
+ module SlotPatch
7
+
8
+ # Set the loco parent any time the instance changes
9
+ def __vc_component_instance=(instance)
10
+ # Call the original implementation
11
+ super
12
+
13
+ # And set the Loco parent
14
+ set_loco_parent
15
+ end
16
+
17
+ def to_s
18
+ set_loco_parent
19
+
20
+ super
21
+ end
22
+
23
+ def set_loco_parent(parent = @parent)
24
+ return if parent.nil?
25
+ return if @__vc_component_instance.nil?
26
+ return if @__vc_component_instance.loco_parent.present?
27
+
28
+ @__vc_component_instance.set_loco_parent(parent)
29
+ end
30
+
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ # Apply the patch
37
+ ::ViewComponent::Slot.prepend(LocoMotion::Patches::ViewComponent::SlotPatch)
@@ -0,0 +1,21 @@
1
+ # Monkey patch ViewComponent::SlotableDefault to modify get_slot behavior
2
+
3
+ module LocoMotion
4
+ module Patches
5
+ module ViewComponent
6
+ module SlotableDefaultPatch
7
+ # Override get_slot method
8
+ def get_slot(slot_name)
9
+ # ensure content is loaded so slots will be defined
10
+ content unless content_evaluated?
11
+
12
+ # Call the original implementation
13
+ super
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+
20
+ # Apply the patch
21
+ ::ViewComponent::SlotableDefault.prepend(LocoMotion::Patches::ViewComponent::SlotableDefaultPatch)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LocoMotion
4
- VERSION = "0.0.8"
4
+ VERSION = "0.5.0"
5
5
  end
data/lib/loco_motion.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  require "rails"
2
2
  require "haml-rails"
3
- require "heroicons-rails"
3
+ require "rails_heroicon"
4
4
 
5
- require Gem::Specification.find_by_name("heroicons-rails").gem_dir + "/app/helpers/heroicons/icons_helper.rb"
5
+ require Gem::Specification.find_by_name("rails_heroicon").gem_dir + "/lib/rails_heroicon/helper.rb"
6
6
 
7
7
  require "view_component"
8
8
 
@@ -14,5 +14,15 @@ require "loco_motion/basic_component"
14
14
  require "loco_motion/engine"
15
15
  require "loco_motion/helpers"
16
16
 
17
+ # Load patches
18
+ require "loco_motion/patches/view_component/slotable_default_patch"
19
+ require "loco_motion/patches/view_component/slot_loco_parent_patch"
20
+
17
21
  require "hero"
18
22
  require "daisy"
23
+
24
+ begin
25
+ require "pry" if Rails.env.development?
26
+ rescue LoadError
27
+ # Don't throw an error, pry should really only be used while debugging locally
28
+ end