rails-active-ui 0.1.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 (167) hide show
  1. checksums.yaml +7 -0
  2. data/Rakefile +6 -0
  3. data/app/assets/stylesheets.css +73555 -0
  4. data/app/components/accordion_component.rb +34 -0
  5. data/app/components/ad_component.rb +28 -0
  6. data/app/components/api_component.rb +24 -0
  7. data/app/components/breadcrumb_component.rb +26 -0
  8. data/app/components/button_component.rb +49 -0
  9. data/app/components/calendar_component.rb +34 -0
  10. data/app/components/card_component.rb +56 -0
  11. data/app/components/checkbox_component.rb +41 -0
  12. data/app/components/column_component.rb +62 -0
  13. data/app/components/comment_component.rb +45 -0
  14. data/app/components/concerns/alignable.rb +21 -0
  15. data/app/components/concerns/attachable.rb +16 -0
  16. data/app/components/concerns/orientable.rb +21 -0
  17. data/app/components/concerns/positionable.rb +21 -0
  18. data/app/components/concerns/sizeable.rb +18 -0
  19. data/app/components/container_component.rb +23 -0
  20. data/app/components/dimmer_component.rb +30 -0
  21. data/app/components/divider_component.rb +30 -0
  22. data/app/components/dropdown_component.rb +63 -0
  23. data/app/components/embed_component.rb +32 -0
  24. data/app/components/emoji_component.rb +15 -0
  25. data/app/components/feed_component.rb +22 -0
  26. data/app/components/flag_component.rb +15 -0
  27. data/app/components/flyout_component.rb +41 -0
  28. data/app/components/form_component.rb +39 -0
  29. data/app/components/grid_component.rb +85 -0
  30. data/app/components/h_stack_component.rb +67 -0
  31. data/app/components/header_component.rb +60 -0
  32. data/app/components/icon_component.rb +41 -0
  33. data/app/components/image_component.rb +46 -0
  34. data/app/components/input_component.rb +52 -0
  35. data/app/components/item_component.rb +39 -0
  36. data/app/components/item_group_component.rb +30 -0
  37. data/app/components/label_component.rb +49 -0
  38. data/app/components/link_component.rb +23 -0
  39. data/app/components/list_component.rb +39 -0
  40. data/app/components/loader_component.rb +33 -0
  41. data/app/components/menu_component.rb +64 -0
  42. data/app/components/menu_item_component.rb +52 -0
  43. data/app/components/message_component.rb +54 -0
  44. data/app/components/modal_component.rb +50 -0
  45. data/app/components/nag_component.rb +25 -0
  46. data/app/components/overlay_component.rb +16 -0
  47. data/app/components/placeholder_component.rb +39 -0
  48. data/app/components/popup_component.rb +31 -0
  49. data/app/components/progress_component.rb +48 -0
  50. data/app/components/pusher_component.rb +18 -0
  51. data/app/components/rail_component.rb +31 -0
  52. data/app/components/rating_component.rb +41 -0
  53. data/app/components/reset_component.rb +12 -0
  54. data/app/components/reveal_component.rb +39 -0
  55. data/app/components/row_component.rb +39 -0
  56. data/app/components/search_component.rb +44 -0
  57. data/app/components/segment_component.rb +57 -0
  58. data/app/components/segment_group_component.rb +36 -0
  59. data/app/components/shape_component.rb +25 -0
  60. data/app/components/sidebar_component.rb +33 -0
  61. data/app/components/site_component.rb +12 -0
  62. data/app/components/slider_component.rb +46 -0
  63. data/app/components/state_component.rb +25 -0
  64. data/app/components/statistic_component.rb +43 -0
  65. data/app/components/step_component.rb +56 -0
  66. data/app/components/step_group_component.rb +38 -0
  67. data/app/components/sticky_component.rb +22 -0
  68. data/app/components/sub_header_component.rb +15 -0
  69. data/app/components/sub_menu_component.rb +24 -0
  70. data/app/components/tab_component.rb +24 -0
  71. data/app/components/table_cell_component.rb +60 -0
  72. data/app/components/table_component.rb +160 -0
  73. data/app/components/table_row_component.rb +43 -0
  74. data/app/components/text_component.rb +73 -0
  75. data/app/components/toast_component.rb +36 -0
  76. data/app/components/transition_component.rb +32 -0
  77. data/app/components/v_stack_component.rb +31 -0
  78. data/app/components/visibility_component.rb +22 -0
  79. data/app/helpers/component_helper.rb +109 -0
  80. data/app/helpers/fui_helper.rb +53 -0
  81. data/app/javascript/accordion.js +547 -0
  82. data/app/javascript/accordion.min.js +11 -0
  83. data/app/javascript/api.js +1112 -0
  84. data/app/javascript/api.min.js +11 -0
  85. data/app/javascript/calendar.js +1960 -0
  86. data/app/javascript/calendar.min.js +11 -0
  87. data/app/javascript/checkbox.js +819 -0
  88. data/app/javascript/checkbox.min.js +11 -0
  89. data/app/javascript/dimmer.js +686 -0
  90. data/app/javascript/dimmer.min.js +11 -0
  91. data/app/javascript/dropdown.js +4019 -0
  92. data/app/javascript/dropdown.min.js +11 -0
  93. data/app/javascript/embed.js +646 -0
  94. data/app/javascript/embed.min.js +11 -0
  95. data/app/javascript/flyout.js +1405 -0
  96. data/app/javascript/flyout.min.js +11 -0
  97. data/app/javascript/form.js +2070 -0
  98. data/app/javascript/form.min.js +11 -0
  99. data/app/javascript/jquery.js +10716 -0
  100. data/app/javascript/jquery.min.js +2 -0
  101. data/app/javascript/modal.js +1507 -0
  102. data/app/javascript/modal.min.js +11 -0
  103. data/app/javascript/nag.js +522 -0
  104. data/app/javascript/nag.min.js +11 -0
  105. data/app/javascript/popup.js +1457 -0
  106. data/app/javascript/popup.min.js +11 -0
  107. data/app/javascript/progress.js +922 -0
  108. data/app/javascript/progress.min.js +11 -0
  109. data/app/javascript/rating.js +496 -0
  110. data/app/javascript/rating.min.js +11 -0
  111. data/app/javascript/search.js +1519 -0
  112. data/app/javascript/search.min.js +11 -0
  113. data/app/javascript/shape.js +721 -0
  114. data/app/javascript/shape.min.js +11 -0
  115. data/app/javascript/sidebar.js +952 -0
  116. data/app/javascript/sidebar.min.js +11 -0
  117. data/app/javascript/site.js +415 -0
  118. data/app/javascript/site.min.js +11 -0
  119. data/app/javascript/slider.js +1449 -0
  120. data/app/javascript/slider.min.js +11 -0
  121. data/app/javascript/state.js +653 -0
  122. data/app/javascript/state.min.js +11 -0
  123. data/app/javascript/sticky.js +852 -0
  124. data/app/javascript/sticky.min.js +11 -0
  125. data/app/javascript/tab.js +867 -0
  126. data/app/javascript/tab.min.js +11 -0
  127. data/app/javascript/toast.js +916 -0
  128. data/app/javascript/toast.min.js +11 -0
  129. data/app/javascript/transition.js +955 -0
  130. data/app/javascript/transition.min.js +11 -0
  131. data/app/javascript/ui/controllers/fui_accordion_controller.js +45 -0
  132. data/app/javascript/ui/controllers/fui_api_controller.js +80 -0
  133. data/app/javascript/ui/controllers/fui_calendar_controller.js +66 -0
  134. data/app/javascript/ui/controllers/fui_checkbox_controller.js +48 -0
  135. data/app/javascript/ui/controllers/fui_dimmer_controller.js +45 -0
  136. data/app/javascript/ui/controllers/fui_dropdown_controller.js +68 -0
  137. data/app/javascript/ui/controllers/fui_embed_controller.js +49 -0
  138. data/app/javascript/ui/controllers/fui_flyout_controller.js +49 -0
  139. data/app/javascript/ui/controllers/fui_form_controller.js +62 -0
  140. data/app/javascript/ui/controllers/fui_modal_controller.js +61 -0
  141. data/app/javascript/ui/controllers/fui_nag_controller.js +52 -0
  142. data/app/javascript/ui/controllers/fui_popup_controller.js +58 -0
  143. data/app/javascript/ui/controllers/fui_progress_controller.js +60 -0
  144. data/app/javascript/ui/controllers/fui_rating_controller.js +49 -0
  145. data/app/javascript/ui/controllers/fui_search_controller.js +76 -0
  146. data/app/javascript/ui/controllers/fui_shape_controller.js +45 -0
  147. data/app/javascript/ui/controllers/fui_sidebar_controller.js +48 -0
  148. data/app/javascript/ui/controllers/fui_site_controller.js +29 -0
  149. data/app/javascript/ui/controllers/fui_slider_controller.js +53 -0
  150. data/app/javascript/ui/controllers/fui_state_controller.js +63 -0
  151. data/app/javascript/ui/controllers/fui_sticky_controller.js +50 -0
  152. data/app/javascript/ui/controllers/fui_tab_controller.js +57 -0
  153. data/app/javascript/ui/controllers/fui_toast_controller.js +60 -0
  154. data/app/javascript/ui/controllers/fui_transition_controller.js +60 -0
  155. data/app/javascript/ui/controllers/fui_visibility_controller.js +55 -0
  156. data/app/javascript/ui/index.js +114 -0
  157. data/app/javascript/visibility.js +1196 -0
  158. data/app/javascript/visibility.min.js +11 -0
  159. data/app/lib/component.rb +63 -0
  160. data/config/importmap.rb +27 -0
  161. data/config/initializers/ruby_template_handler.rb +31 -0
  162. data/config/routes.rb +2 -0
  163. data/lib/tasks/ui_tasks.rake +4 -0
  164. data/lib/ui/engine.rb +27 -0
  165. data/lib/ui/version.rb +3 -0
  166. data/lib/ui.rb +6 -0
  167. metadata +220 -0
@@ -0,0 +1,160 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Table — data tables with column accumulator pattern.
4
+ #
5
+ # Usage:
6
+ # Table(striped: true, rows: @users) { |c|
7
+ # c.column(:name, heading: "Name") { |user|
8
+ # Text(weight: :bold) { text user.name }
9
+ # }
10
+ # c.column(:email) { |user|
11
+ # Text(color: :grey) { text user.email }
12
+ # }
13
+ # }
14
+ #
15
+ # Or with manual content:
16
+ # Table(celled: true) { |c|
17
+ # c.header {
18
+ # TableRow {
19
+ # TableCell(heading: true) { text "Name" }
20
+ # TableCell(heading: true) { text "Age" }
21
+ # }
22
+ # }
23
+ # TableRow {
24
+ # TableCell { text "Alice" }
25
+ # TableCell { text "30" }
26
+ # }
27
+ # }
28
+
29
+ class TableComponent < Component
30
+ attribute :rows, default: nil
31
+ attribute :definition, :boolean, default: false
32
+ attribute :structured, :boolean, default: false
33
+ attribute :single_line, :boolean, default: false
34
+ attribute :fixed, :boolean, default: false
35
+ attribute :selectable, :boolean, default: false
36
+ attribute :striped, :boolean, default: false
37
+ attribute :sortable, :boolean, default: false
38
+ attribute :celled, :boolean, default: false
39
+ attribute :basic, :string, default: nil
40
+ attribute :compact, :string, default: nil
41
+ attribute :padded, :string, default: nil
42
+ attribute :collapsing, :boolean, default: false
43
+ attribute :inverted, :boolean, default: false
44
+ attribute :color, :string, default: nil
45
+ attribute :size, :string, default: nil
46
+ attribute :unstackable, :boolean, default: false
47
+ attribute :stackable, :boolean, default: false
48
+ attribute :attached, :string, default: nil
49
+
50
+ slot :header
51
+ slot :footer
52
+
53
+ def columns
54
+ @columns ||= []
55
+ end
56
+
57
+ def column(key, heading: key.to_s.titleize, &block)
58
+ columns << { key: key, heading: heading, block: block }
59
+ end
60
+
61
+ def to_s
62
+ classes = class_names(
63
+ "ui",
64
+ size,
65
+ color,
66
+ basic_class,
67
+ compact_class,
68
+ padded_class,
69
+ attached_class,
70
+ { "definition" => definition,
71
+ "structured" => structured,
72
+ "single line" => single_line,
73
+ "fixed" => fixed,
74
+ "selectable" => selectable,
75
+ "striped" => striped,
76
+ "sortable" => sortable,
77
+ "celled" => celled,
78
+ "collapsing" => collapsing,
79
+ "inverted" => inverted,
80
+ "unstackable" => unstackable,
81
+ "stackable" => stackable },
82
+ "table"
83
+ )
84
+
85
+ if columns.any? && rows
86
+ column_table(classes)
87
+ else
88
+ manual_table(classes)
89
+ end
90
+ end
91
+
92
+ private
93
+
94
+ def column_table(classes)
95
+ head_cells = columns.map { |col| tag.th { col[:heading] } }
96
+
97
+ body_rows = Array(rows).map { |row|
98
+ cells = columns.map { |col|
99
+ cell_content = col[:block]
100
+ .then { |b| b && @view_context.capture(row, &b) }
101
+ .then { |c| c || ERB::Util.html_escape(row.public_send(col[:key]).to_s) }
102
+ tag.td { cell_content }
103
+ }
104
+ tag.tr { safe_join(cells) }
105
+ }
106
+
107
+ footer_el = @slots[:footer] ? tag.tfoot { @slots[:footer] } : nil
108
+
109
+ tag.table(class: classes) {
110
+ safe_join([
111
+ tag.thead { tag.tr { safe_join(head_cells) } },
112
+ tag.tbody { safe_join(body_rows) },
113
+ footer_el
114
+ ])
115
+ }
116
+ end
117
+
118
+ def manual_table(classes)
119
+ header_el = @slots[:header] ? tag.thead { @slots[:header] } : nil
120
+ footer_el = @slots[:footer] ? tag.tfoot { @slots[:footer] } : nil
121
+ body_el = @content.presence ? tag.tbody { @content } : nil
122
+
123
+ tag.table(class: classes) {
124
+ safe_join([ header_el, body_el, footer_el ])
125
+ }
126
+ end
127
+
128
+ def basic_class
129
+ case basic
130
+ when "very" then "very basic"
131
+ when "true", true then "basic"
132
+ when String then "#{basic} basic"
133
+ end
134
+ end
135
+
136
+ def compact_class
137
+ case compact
138
+ when "very" then "very compact"
139
+ when "true", true then "compact"
140
+ when String then "#{compact} compact"
141
+ end
142
+ end
143
+
144
+ def attached_class
145
+ case attached
146
+ when "top" then "top attached"
147
+ when "bottom" then "bottom attached"
148
+ when "" then "attached"
149
+ when String then "#{attached} attached"
150
+ end
151
+ end
152
+
153
+ def padded_class
154
+ case padded
155
+ when "very" then "very padded"
156
+ when "true", true then "padded"
157
+ when String then "#{padded} padded"
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ # TableRow — a table row.
4
+ #
5
+ # Usage:
6
+ # Table(celled: true) { |c|
7
+ # c.header {
8
+ # TableRow {
9
+ # TableCell(heading: true) { text "Name" }
10
+ # TableCell(heading: true) { text "Age" }
11
+ # }
12
+ # }
13
+ # TableRow {
14
+ # TableCell { text "Alice" }
15
+ # TableCell { text "30" }
16
+ # }
17
+ # }
18
+
19
+ class TableRowComponent < Component
20
+ attribute :active, :boolean, default: false
21
+ attribute :positive, :boolean, default: false
22
+ attribute :negative, :boolean, default: false
23
+ attribute :warning, :boolean, default: false
24
+ attribute :error, :boolean, default: false
25
+ attribute :disabled, :boolean, default: false
26
+
27
+ def to_s
28
+ classes = [
29
+ ("active" if active),
30
+ ("positive" if positive),
31
+ ("negative" if negative),
32
+ ("warning" if warning),
33
+ ("error" if error),
34
+ ("disabled" if disabled)
35
+ ].compact
36
+
37
+ if classes.any?
38
+ tag.tr(class: classes.join(" ")) { @content }
39
+ else
40
+ tag.tr { @content }
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Text — inline text container. Merges the holy spec primitive with Fomantic-UI text.
4
+ #
5
+ # Usage:
6
+ # Text { text "Hello" }
7
+ # Text(size: :sm, style: :secondary) { text "Muted text" }
8
+ # Text(weight: :bold, color: :red) { text "Important" }
9
+
10
+ class TextComponent < Component
11
+ attribute :style, :string, default: nil
12
+ attribute :size, :string, default: nil
13
+ attribute :weight, :string, default: nil
14
+ attribute :color, :string, default: nil
15
+
16
+ def to_s
17
+ has_fui_class = color || size_fui
18
+
19
+ fui_classes = if has_fui_class
20
+ class_names(
21
+ "ui",
22
+ color,
23
+ size_fui,
24
+ "text"
25
+ )
26
+ end
27
+
28
+ style_parts = [
29
+ (style && "text-#{style}"),
30
+ (size_css && "font-size:#{size_css}"),
31
+ (weight && "font-weight:#{weight_value}")
32
+ ].compact
33
+
34
+ opts = {}
35
+ opts[:class] = fui_classes if fui_classes
36
+ opts[:style] = style_parts.join(";") if style_parts.any?
37
+
38
+ tag.span(**opts) { @content }
39
+ end
40
+
41
+ private
42
+
43
+ # Fomantic-UI text size classes
44
+ def size_fui
45
+ case size
46
+ when "mini", "tiny", "small", "medium", "large", "big", "huge", "massive"
47
+ size
48
+ end
49
+ end
50
+
51
+ # CSS font-size for spec-style sizes (sm, xs, etc.)
52
+ def size_css
53
+ case size
54
+ when "xs" then "0.75rem"
55
+ when "sm" then "0.875rem"
56
+ when "lg" then "1.125rem"
57
+ when "xl" then "1.25rem"
58
+ when "2xl" then "1.5rem"
59
+ end
60
+ end
61
+
62
+ def weight_value
63
+ case weight.to_s
64
+ when "light" then "300"
65
+ when "normal" then "400"
66
+ when "medium" then "500"
67
+ when "semibold" then "600"
68
+ when "bold" then "700"
69
+ when "heavy" then "900"
70
+ else weight
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Toast — toast notifications.
4
+ #
5
+ # Usage:
6
+ # Toast(title: "Success", message: "Item saved.", type: :success)
7
+ # Toast(title: "Error", message: "Something went wrong.", type: :error, position: "bottom right")
8
+
9
+ class ToastComponent < Component
10
+ include Positionable
11
+ default position: "top right"
12
+
13
+ attribute :title, :string, default: nil
14
+ attribute :message, :string, default: nil
15
+ attribute :type, :string, default: "neutral"
16
+ attribute :display_time, :integer, default: 3000
17
+ attribute :close_icon, :boolean, default: false
18
+ attribute :compact, :boolean, default: true
19
+ attribute :show_progress, :boolean, default: false
20
+
21
+ def to_s
22
+ data = {
23
+ controller: "fui-toast",
24
+ fui_toast_class_value: type,
25
+ fui_toast_position_value: position,
26
+ fui_toast_display_time_value: display_time
27
+ }
28
+ data[:fui_toast_title_value] = title if title
29
+ data[:fui_toast_message_value] = message if message
30
+ data[:fui_toast_close_icon_value] = "true" if close_icon
31
+ data[:fui_toast_compact_value] = "true" if compact
32
+ data[:fui_toast_show_progress_value] = "true" if show_progress
33
+
34
+ tag.div(data: data) { @content }
35
+ end
36
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Transition — CSS animation framework.
4
+ #
5
+ # Usage:
6
+ # Transition(animation: :fade, visible: true) { text "Fading content" }
7
+ # Transition(animation: :scale, duration: 500) { text "Scaling content" }
8
+
9
+ class TransitionComponent < Component
10
+ attribute :animation, :string, default: "fade"
11
+ attribute :duration, :integer, default: 500
12
+ attribute :visible, :boolean, default: true
13
+
14
+ def to_s
15
+ classes = class_names(
16
+ animation,
17
+ { "visible" => visible,
18
+ "hidden" => !visible },
19
+ "transition"
20
+ )
21
+
22
+ tag.div(
23
+ class: classes,
24
+ style: "animation-duration:#{duration}ms",
25
+ data: {
26
+ controller: "fui-transition",
27
+ fui_transition_animation_value: animation,
28
+ fui_transition_duration_value: duration
29
+ }
30
+ ) { @content }
31
+ end
32
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ class VStackComponent < Component
4
+ attribute :spacing, :integer, default: 0
5
+ attribute :align, :string, default: "start"
6
+
7
+ def to_s
8
+ style_parts = [
9
+ "display:flex",
10
+ "flex-direction:column",
11
+ ("gap:#{spacing}px" if spacing > 0),
12
+ ("align-items:#{align_value}" if align != "start")
13
+ ].compact.join(";")
14
+
15
+ opts = {}
16
+ opts[:style] = style_parts unless style_parts.empty?
17
+
18
+ tag.div(**opts) { @content }
19
+ end
20
+
21
+ private
22
+
23
+ def align_value
24
+ case align
25
+ when "center" then "center"
26
+ when "end" then "flex-end"
27
+ when "stretch" then "stretch"
28
+ else "flex-start"
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Visibility — scroll-based visibility detection.
4
+ #
5
+ # Usage:
6
+ # Visibility(once: true) { Image(src: "lazy.jpg") }
7
+ # Visibility(offset: 100) { text "I trigger when visible" }
8
+
9
+ class VisibilityComponent < Component
10
+ attribute :type, :string, default: nil
11
+ attribute :offset, :integer, default: 0
12
+ attribute :once, :boolean, default: false
13
+
14
+ def to_s
15
+ data = { controller: "fui-visibility" }
16
+ data[:fui_visibility_type_value] = type if type
17
+ data[:fui_visibility_offset_value] = offset if offset > 0
18
+ data[:fui_visibility_once_value] = "true" if once
19
+
20
+ tag.div(data: data) { @content }
21
+ end
22
+ end
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The Registry of Names
4
+ #
5
+ # All components available to views are declared here. There is no
6
+ # method_missing sorcery, no dynamic resolution, no convention-based guessing.
7
+ # If a component is not in the registry, it does not exist.
8
+ #
9
+ # To create a new component: add one line to COMPONENT_MAP and create the class.
10
+ #
11
+ # See: specs/the-holy-view-spec.md, Article 3
12
+
13
+ module ComponentHelper
14
+ COMPONENT_MAP = {
15
+ # Layout Primitives
16
+ VStack: VStackComponent,
17
+ HStack: HStackComponent,
18
+ Column: ColumnComponent,
19
+ Row: RowComponent,
20
+ Pusher: PusherComponent,
21
+ Overlay: OverlayComponent,
22
+ Link: LinkComponent,
23
+ SubHeader: SubHeaderComponent,
24
+
25
+ # Globals
26
+ Reset: ResetComponent,
27
+ Site: SiteComponent,
28
+
29
+ # Elements
30
+ Button: ButtonComponent,
31
+ Container: ContainerComponent,
32
+ Divider: DividerComponent,
33
+ Emoji: EmojiComponent,
34
+ Flag: FlagComponent,
35
+ Header: HeaderComponent,
36
+ Icon: IconComponent,
37
+ Image: ImageComponent,
38
+ Input: InputComponent,
39
+ Label: LabelComponent,
40
+ List: ListComponent,
41
+ Loader: LoaderComponent,
42
+ Placeholder: PlaceholderComponent,
43
+ Rail: RailComponent,
44
+ Reveal: RevealComponent,
45
+ Segment: SegmentComponent,
46
+ SegmentGroup: SegmentGroupComponent,
47
+ Step: StepComponent,
48
+ StepGroup: StepGroupComponent,
49
+ Text: TextComponent,
50
+
51
+ # Collections
52
+ Breadcrumb: BreadcrumbComponent,
53
+ Form: FormComponent,
54
+ Grid: GridComponent,
55
+ Menu: MenuComponent,
56
+ MenuItem: MenuItemComponent,
57
+ SubMenu: SubMenuComponent,
58
+ Message: MessageComponent,
59
+ Table: TableComponent,
60
+ TableRow: TableRowComponent,
61
+ TableCell: TableCellComponent,
62
+
63
+ # Views
64
+ Ad: AdComponent,
65
+ ItemGroup: ItemGroupComponent,
66
+ Card: CardComponent,
67
+ Comment: CommentComponent,
68
+ Feed: FeedComponent,
69
+ Item: ItemComponent,
70
+ Statistic: StatisticComponent,
71
+
72
+ # Modules
73
+ Accordion: AccordionComponent,
74
+ Calendar: CalendarComponent,
75
+ Checkbox: CheckboxComponent,
76
+ Dimmer: DimmerComponent,
77
+ Dropdown: DropdownComponent,
78
+ Embed: EmbedComponent,
79
+ Flyout: FlyoutComponent,
80
+ Modal: ModalComponent,
81
+ Nag: NagComponent,
82
+ Popup: PopupComponent,
83
+ Progress: ProgressComponent,
84
+ Slider: SliderComponent,
85
+ Rating: RatingComponent,
86
+ Search: SearchComponent,
87
+ Shape: ShapeComponent,
88
+ Sidebar: SidebarComponent,
89
+ Sticky: StickyComponent,
90
+ Tab: TabComponent,
91
+ Toast: ToastComponent,
92
+ Transition: TransitionComponent,
93
+
94
+ # Behaviors
95
+ Api: ApiComponent,
96
+ State: StateComponent,
97
+ Visibility: VisibilityComponent
98
+ }.freeze
99
+
100
+ COMPONENT_MAP.each do |name, klass|
101
+ define_method(name) { |**kwargs, &block|
102
+ output_buffer << render(klass.new(**kwargs), &block)
103
+ }
104
+ end
105
+
106
+ def text(content)
107
+ output_buffer << content.to_s
108
+ end
109
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Provides the fui_javascript_tags helper for loading jQuery and
4
+ # Fomantic-UI component scripts in the correct order.
5
+ #
6
+ # Usage (in your application layout, before javascript_importmap_tags):
7
+ #
8
+ # <%= fui_javascript_tags %>
9
+ # <%= javascript_importmap_tags %>
10
+ #
11
+ # This emits <script> tags for jQuery and each Fomantic-UI component.
12
+ # The Stimulus bridge controllers are loaded separately via importmap.
13
+
14
+ module FuiHelper
15
+ # Fomantic component scripts in load order.
16
+ # site and transition must come first — other components depend on them.
17
+ FOMANTIC_SCRIPTS = %w[
18
+ site
19
+ transition
20
+ accordion
21
+ api
22
+ calendar
23
+ checkbox
24
+ dimmer
25
+ dropdown
26
+ embed
27
+ flyout
28
+ form
29
+ modal
30
+ nag
31
+ popup
32
+ progress
33
+ rating
34
+ search
35
+ shape
36
+ sidebar
37
+ slider
38
+ state
39
+ sticky
40
+ tab
41
+ toast
42
+ visibility
43
+ ].freeze
44
+
45
+ def fui_javascript_tags
46
+ tags = []
47
+ tags << javascript_include_tag("jquery")
48
+ FOMANTIC_SCRIPTS.each do |name|
49
+ tags << javascript_include_tag(name)
50
+ end
51
+ safe_join(tags, "\n")
52
+ end
53
+ end