poetry-ui 0.1.4 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.mcp.json +8 -0
- data/.yard-lint.yml +25 -0
- data/.yard_coverage_all +1 -0
- data/Archspec.rb +22 -0
- data/CHANGELOG.md +11 -0
- data/app/components/poetry/ui/accordion/component.html.erb +1 -1
- data/app/components/poetry/ui/accordion/component.rb +7 -7
- data/app/components/poetry/ui/alert/component.html.erb +1 -1
- data/app/components/poetry/ui/alert/component.rb +3 -6
- data/app/components/poetry/ui/alert_dialog/component.html.erb +2 -2
- data/app/components/poetry/ui/alert_dialog/component.rb +9 -3
- data/app/components/poetry/ui/aspect_ratio/component.rb +5 -7
- data/app/components/poetry/ui/attachment/component.html.erb +1 -1
- data/app/components/poetry/ui/attachment/component.rb +5 -5
- data/app/components/poetry/ui/autocomplete/component.html.erb +1 -1
- data/app/components/poetry/ui/autocomplete/component.rb +8 -7
- data/app/components/poetry/ui/avatar/component.rb +9 -7
- data/app/components/poetry/ui/badge/component.rb +5 -6
- data/app/components/poetry/ui/breadcrumb/component.html.erb +1 -1
- data/app/components/poetry/ui/breadcrumb/component.rb +4 -6
- data/app/components/poetry/ui/bubble/component.html.erb +1 -1
- data/app/components/poetry/ui/bubble/component.rb +4 -6
- data/app/components/poetry/ui/button/component.html.erb +1 -1
- data/app/components/poetry/ui/button/component.rb +7 -5
- data/app/components/poetry/ui/button_group/component.rb +6 -8
- data/app/components/poetry/ui/calendar/component.html.erb +1 -1
- data/app/components/poetry/ui/calendar/component.rb +24 -27
- data/app/components/poetry/ui/card/component.html.erb +1 -1
- data/app/components/poetry/ui/card/component.rb +3 -9
- data/app/components/poetry/ui/carousel/component.html.erb +1 -1
- data/app/components/poetry/ui/carousel/component.rb +4 -5
- data/app/components/poetry/ui/checkbox/component.html.erb +1 -1
- data/app/components/poetry/ui/checkbox/component.rb +4 -6
- data/app/components/poetry/ui/clipboard_text/component.html.erb +4 -4
- data/app/components/poetry/ui/clipboard_text/component.rb +11 -12
- data/app/components/poetry/ui/code_block/component.html.erb +2 -2
- data/app/components/poetry/ui/code_block/component.rb +9 -15
- data/app/components/poetry/ui/collapsible/component.html.erb +2 -2
- data/app/components/poetry/ui/collapsible/component.rb +5 -8
- data/app/components/poetry/ui/combobox/component.html.erb +6 -6
- data/app/components/poetry/ui/combobox/component.rb +63 -47
- data/app/components/poetry/ui/command/component.html.erb +3 -3
- data/app/components/poetry/ui/command/component.rb +36 -26
- data/app/components/poetry/ui/command/dialog_component.html.erb +2 -2
- data/app/components/poetry/ui/command/dialog_component.rb +5 -9
- data/app/components/poetry/ui/context_menu/component.html.erb +2 -2
- data/app/components/poetry/ui/context_menu/component.rb +8 -8
- data/app/components/poetry/ui/data_table/component.html.erb +3 -3
- data/app/components/poetry/ui/data_table/component.rb +10 -15
- data/app/components/poetry/ui/date_field/component.html.erb +3 -3
- data/app/components/poetry/ui/date_field/component.rb +15 -9
- data/app/components/poetry/ui/date_parsing.rb +36 -0
- data/app/components/poetry/ui/date_picker/component.html.erb +1 -1
- data/app/components/poetry/ui/date_picker/component.rb +8 -33
- data/app/components/poetry/ui/date_time_field/component.rb +4 -0
- data/app/components/poetry/ui/deferred/component.html.erb +1 -1
- data/app/components/poetry/ui/deferred/component.rb +3 -6
- data/app/components/poetry/ui/dialog/component.html.erb +2 -2
- data/app/components/poetry/ui/dialog/component.rb +3 -2
- data/app/components/poetry/ui/drawer/component.html.erb +2 -2
- data/app/components/poetry/ui/drawer/component.rb +4 -2
- data/app/components/poetry/ui/dropdown_menu/component.html.erb +2 -2
- data/app/components/poetry/ui/dropdown_menu/component.rb +7 -8
- data/app/components/poetry/ui/empty/component.html.erb +1 -1
- data/app/components/poetry/ui/empty/component.rb +1 -7
- data/app/components/poetry/ui/family_identity.rb +8 -11
- data/app/components/poetry/ui/field/component.html.erb +1 -1
- data/app/components/poetry/ui/field/component.rb +8 -10
- data/app/components/poetry/ui/field_group/component.rb +1 -9
- data/app/components/poetry/ui/field_separator/component.rb +5 -7
- data/app/components/poetry/ui/fieldset/component.rb +4 -7
- data/app/components/poetry/ui/file_input/component.html.erb +1 -1
- data/app/components/poetry/ui/file_input/component.rb +2 -6
- data/app/components/poetry/ui/hover_card/component.html.erb +2 -2
- data/app/components/poetry/ui/hover_card/component.rb +4 -2
- data/app/components/poetry/ui/icon/component.rb +6 -0
- data/app/components/poetry/ui/input/component.rb +4 -6
- data/app/components/poetry/ui/input_group/component.rb +2 -7
- data/app/components/poetry/ui/input_group_field.rb +4 -3
- data/app/components/poetry/ui/input_otp/component.html.erb +2 -2
- data/app/components/poetry/ui/input_otp/component.rb +9 -4
- data/app/components/poetry/ui/item/component.html.erb +1 -1
- data/app/components/poetry/ui/item/component.rb +4 -5
- data/app/components/poetry/ui/kbd/component.rb +1 -9
- data/app/components/poetry/ui/label/component.rb +5 -6
- data/app/components/poetry/ui/link/component.rb +6 -6
- data/app/components/poetry/ui/marker/component.html.erb +1 -1
- data/app/components/poetry/ui/marker/component.rb +4 -5
- data/app/components/poetry/ui/menubar/component.html.erb +1 -1
- data/app/components/poetry/ui/menubar/component.rb +28 -15
- data/app/components/poetry/ui/menus.rb +23 -0
- data/app/components/poetry/ui/message/component.html.erb +1 -1
- data/app/components/poetry/ui/message/component.rb +2 -6
- data/app/components/poetry/ui/message_scroller/component.html.erb +1 -1
- data/app/components/poetry/ui/message_scroller/component.rb +7 -8
- data/app/components/poetry/ui/metadata_list/component.rb +6 -7
- data/app/components/poetry/ui/meter/component.rb +11 -6
- data/app/components/poetry/ui/native_select/component.rb +5 -0
- data/app/components/poetry/ui/navigation_menu/component.html.erb +1 -1
- data/app/components/poetry/ui/navigation_menu/component.rb +10 -6
- data/app/components/poetry/ui/number_field/component.html.erb +6 -6
- data/app/components/poetry/ui/number_field/component.rb +19 -13
- data/app/components/poetry/ui/pagination/component.html.erb +1 -1
- data/app/components/poetry/ui/pagination/component.rb +10 -6
- data/app/components/poetry/ui/popover/component.html.erb +2 -2
- data/app/components/poetry/ui/popover/component.rb +7 -2
- data/app/components/poetry/ui/progress/component.rb +12 -6
- data/app/components/poetry/ui/questionnaire/component.html.erb +5 -22
- data/app/components/poetry/ui/questionnaire/component.rb +81 -29
- data/app/components/poetry/ui/radio_group/component.html.erb +1 -1
- data/app/components/poetry/ui/radio_group/component.rb +13 -6
- data/app/components/poetry/ui/resizable/component.html.erb +1 -1
- data/app/components/poetry/ui/resizable/component.rb +9 -4
- data/app/components/poetry/ui/scroll_area/component.rb +5 -9
- data/app/components/poetry/ui/search_field/component.html.erb +5 -5
- data/app/components/poetry/ui/search_field/component.rb +8 -9
- data/app/components/poetry/ui/select/component.html.erb +2 -2
- data/app/components/poetry/ui/select/component.rb +39 -14
- data/app/components/poetry/ui/sensitive_input/component.html.erb +6 -6
- data/app/components/poetry/ui/sensitive_input/component.rb +21 -23
- data/app/components/poetry/ui/separator/component.rb +5 -6
- data/app/components/poetry/ui/sheet/component.html.erb +2 -2
- data/app/components/poetry/ui/sheet/component.rb +1 -0
- data/app/components/poetry/ui/sidebar/component.html.erb +1 -1
- data/app/components/poetry/ui/sidebar/component.rb +11 -4
- data/app/components/poetry/ui/skeleton/component.rb +2 -10
- data/app/components/poetry/ui/slider/component.html.erb +1 -1
- data/app/components/poetry/ui/slider/component.rb +25 -6
- data/app/components/poetry/ui/spinner/component.rb +7 -7
- data/app/components/poetry/ui/stat/component.html.erb +1 -1
- data/app/components/poetry/ui/stat/component.rb +5 -8
- data/app/components/poetry/ui/switch/component.html.erb +1 -1
- data/app/components/poetry/ui/switch/component.rb +9 -6
- data/app/components/poetry/ui/table/component.html.erb +1 -1
- data/app/components/poetry/ui/table/component.rb +3 -8
- data/app/components/poetry/ui/tabs/component.html.erb +1 -1
- data/app/components/poetry/ui/tabs/component.rb +28 -19
- data/app/components/poetry/ui/tag_group/component.html.erb +2 -2
- data/app/components/poetry/ui/tag_group/component.rb +10 -8
- data/app/components/poetry/ui/textarea/component.rb +5 -6
- data/app/components/poetry/ui/time_field/component.rb +4 -0
- data/app/components/poetry/ui/timeline/component.rb +7 -8
- data/app/components/poetry/ui/toast/component.html.erb +1 -1
- data/app/components/poetry/ui/toast/component.rb +9 -5
- data/app/components/poetry/ui/toast_trigger/component.rb +1 -0
- data/app/components/poetry/ui/toaster/component.html.erb +1 -1
- data/app/components/poetry/ui/toaster/component.rb +4 -7
- data/app/components/poetry/ui/toggle/component.rb +6 -9
- data/app/components/poetry/ui/toggle_group/component.html.erb +1 -1
- data/app/components/poetry/ui/toggle_group/component.rb +9 -6
- data/app/components/poetry/ui/toolbar/component.rb +8 -7
- data/app/components/poetry/ui/tooltip/component.html.erb +2 -2
- data/app/components/poetry/ui/tooltip/component.rb +5 -2
- data/app/components/poetry/ui/tree/component.html.erb +3 -3
- data/app/components/poetry/ui/tree/component.rb +23 -12
- data/app/components/poetry/ui/typeset/component.rb +4 -9
- data/app/controllers/poetry/ui/llms_controller.rb +1 -0
- data/app/helpers/poetry/ui/form_builder/type_inference.rb +3 -0
- data/app/helpers/poetry/ui/form_builder.rb +37 -55
- data/app/helpers/poetry/ui/optimistic_form_builder.rb +1 -0
- data/app/helpers/poetry/ui/toast_stream_actions.rb +1 -0
- data/config/component_registry.yml +46 -0
- data/lib/generators/poetry/add/add_generator.rb +14 -0
- data/lib/generators/poetry/agent_rules/agent_rules_generator.rb +2 -0
- data/lib/generators/poetry/block/block_generator.rb +2 -0
- data/lib/generators/poetry/diff/diff_generator.rb +5 -0
- data/lib/generators/poetry/editor/editor_generator.rb +5 -0
- data/lib/generators/poetry/install/install_generator.rb +6 -0
- data/lib/generators/poetry/pagination/pagination_generator.rb +1 -0
- data/lib/generators/poetry/pagination/templates/poetry_pagy_helper.rb +4 -0
- data/lib/generators/poetry/skills_section.rb +1 -0
- data/lib/poetry/ui/chat.rb +82 -33
- data/lib/poetry/ui/code_block_highlighter.rb +4 -0
- data/lib/poetry/ui/fidelity.rb +28 -0
- data/lib/poetry/ui/recipes.rb +4 -0
- data/lib/poetry/ui/reset_floor.rb +15 -2
- data/lib/poetry/ui/testing/combobox.rb +12 -0
- data/lib/poetry/ui/testing/dialog.rb +2 -0
- data/lib/poetry/ui/testing/menu.rb +7 -0
- data/lib/poetry/ui/testing/select.rb +7 -0
- data/lib/poetry/ui/testing/tester.rb +11 -0
- data/lib/poetry/ui/testing.rb +1 -0
- data/lib/poetry/ui/themes.rb +3 -0
- data/lib/poetry/ui/version.rb +1 -1
- data/lib/poetry/ui/webmcp.rb +1 -0
- data/lib/poetry/ui.rb +17 -1
- data/rubydex_linter/rules/registry_class.rb +44 -0
- data/rubydex_linter/rules/style_sidecar.rb +38 -0
- metadata +11 -5
- data/app/components/poetry/ui/date_time_field/component.html.erb +0 -6
- data/app/components/poetry/ui/time_field/component.html.erb +0 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2ba8f8052a42b9369be8d97fb6e751471cf5e058080a0cb517d77d186883ece2
|
|
4
|
+
data.tar.gz: 22de85bd6a2f822bb9f9ff051cad36fb78a03d21b08e24d9766944d21b2ff045
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2668065dbf0776b50fb721b5feb212d56b3062171ff0de0c0551ba094469cab0c810ec2ef26e4be21b2d8c98d8503fddaabbcc287befa37711f7111b6478df21
|
|
7
|
+
data.tar.gz: 3b3b38c3242ebb5ef265551bc008e5d44bff9e2f37b083a4b237a7f9b779f319625c23d7403b28b0f78151e7715b309ea90c0465fc47c303a7a1deffead9504c
|
data/.mcp.json
ADDED
data/.yard-lint.yml
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# yard-lint: the documentation tier YARD's own gates miss - a documented
|
|
2
|
+
# method missing a @param, an @example that does not parse, option tags,
|
|
3
|
+
# tag order, invalid types. Runs as rake yard:lint (in the default task).
|
|
4
|
+
# UndocumentedObjects stays off: yard:coverage gates public objects at its
|
|
5
|
+
# recorded floor, and this validator counts the @api private internals the
|
|
6
|
+
# gems hide on purpose (--hide-api is not honoured here). MissingReturn is
|
|
7
|
+
# off until the @param backlog is cleared; revisit then.
|
|
8
|
+
AllValidators:
|
|
9
|
+
YardOptions:
|
|
10
|
+
- --no-private
|
|
11
|
+
Documentation/UndocumentedObjects:
|
|
12
|
+
Enabled: false
|
|
13
|
+
Documentation/MissingReturn:
|
|
14
|
+
Enabled: false
|
|
15
|
+
Tags/InvalidTypes:
|
|
16
|
+
Enabled: true
|
|
17
|
+
# A **options splat passed through to a control is documented as @param
|
|
18
|
+
# options [Hash], not one @option per key; and @example blocks here are
|
|
19
|
+
# ERB as often as Ruby, which this validator cannot parse.
|
|
20
|
+
Documentation/UndocumentedOptions:
|
|
21
|
+
Enabled: false
|
|
22
|
+
Tags/OptionTags:
|
|
23
|
+
Enabled: false
|
|
24
|
+
Tags/ExampleSyntax:
|
|
25
|
+
Enabled: false
|
data/.yard_coverage_all
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0
|
data/Archspec.rb
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# The architecture the family enforces by review, as checks (rake arch:check).
|
|
4
|
+
# ui depends on core alone. lib reaches the components only through the
|
|
5
|
+
# registry; the test helpers under lib/poetry/ui/testing drive components
|
|
6
|
+
# by name and may name them; the generators are install tooling nothing
|
|
7
|
+
# in a component depends on.
|
|
8
|
+
root "."
|
|
9
|
+
source "app/**/*.rb", "lib/**/*.rb"
|
|
10
|
+
|
|
11
|
+
component :components, in: "app/components/**/*.rb"
|
|
12
|
+
component :lib, in: "lib/**/*.rb", except: ["lib/generators/**/*", "lib/poetry/ui/testing/**/*"]
|
|
13
|
+
component :testing, in: "lib/poetry/ui/testing/**/*.rb"
|
|
14
|
+
component :generators, in: "lib/generators/**/*.rb"
|
|
15
|
+
|
|
16
|
+
lib.cannot_use :components, because: "lib reaches the components through the registry"
|
|
17
|
+
components.cannot_use :generators, because: "a component never depends on the install tooling"
|
|
18
|
+
lib.cannot_reference_constants "Poetry::Charts", "Poetry::Agent", "ApplicationController",
|
|
19
|
+
because: "ui depends on core alone and never names the host"
|
|
20
|
+
components.cannot_reference_constants "Poetry::Charts", "Poetry::Agent", "ApplicationController",
|
|
21
|
+
because: "ui depends on core alone and never names the host"
|
|
22
|
+
no_cycles among: %i[lib components]
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.1.5] - 2026-09-18
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- The registry carries the gem's internal namespaces (`internals`), so `poetry check` can warn a host that names one.
|
|
8
|
+
- 36 methods the reference already hid with `@api private` are Ruby-private now: each was called only by its own class or template, so the runtime enforces what the tag only stated. A host that reached one gets a NoMethodError instead of an internal that may change without notice. The tag remains on the internals the family shares between its gems and on whole internal classes.
|
|
9
|
+
- Every class, module and method carries a one-sentence description, private helpers included: `rake yard:coverage:all` measures the whole tree (a tag-only docstring counts as blank) and the committed floor now stands at zero.
|
|
10
|
+
- DateTimeField and TimeField render through DateField's template (their verbatim copies are gone); Calendar and DatePicker share `DateParsing`; the four value-field form builder methods ride one `control_field` helper; the chat turn compiler builds its frames through `Chat::AssistantTurn::Timeline`. No rendered markup changed.
|
|
11
|
+
- Every component's root rides the core default: `root_attributes` is the public `Poetry::Core::Component` method, and a component's override passes only its own markup up (`super("data-variant" => variant)`); the slot name, `data-component` and the root's Stimulus wiring come from the default. Twelve overrides that added nothing are gone, and the shared `FamilyIdentity` override passes the family's slot prefix the same way. The rendered attributes are unchanged apart from their order on the element.
|
|
12
|
+
- The part builders (a popup's content, a field's group, a tree row, a dialog panel, and the rest) return `element_attributes(...)`, the part's attributes with its Stimulus wiring merged safely, named after their part so the slot, the dictionary classes and the wiring come stamped, and the templates splat the result (`tag.div(**content_attributes)`); `to_attributes` and the `Poetry::Core::HTML::Attributes.new(...)` wrap at every call site are gone.
|
|
13
|
+
|
|
3
14
|
## [0.1.4] - 2026-09-15
|
|
4
15
|
|
|
5
16
|
### Fixed
|
|
@@ -132,21 +132,19 @@ module Poetry
|
|
|
132
132
|
Array(open).map(&:to_s)
|
|
133
133
|
end
|
|
134
134
|
|
|
135
|
-
#
|
|
135
|
+
# The root's attributes: this component's markup over the core default.
|
|
136
136
|
def root_attributes
|
|
137
|
-
|
|
138
|
-
{ "data-slot" => "accordion", "data-orientation" => "vertical" }
|
|
139
|
-
.merge(stimulus_attributes_for(:root))
|
|
140
|
-
.merge(component_data_attributes)
|
|
141
|
-
)
|
|
137
|
+
super({ "data-orientation" => "vertical" })
|
|
142
138
|
end
|
|
143
139
|
|
|
144
140
|
private
|
|
145
141
|
|
|
142
|
+
# The server-stable id every item id derives from.
|
|
146
143
|
def instance_id
|
|
147
144
|
@instance_id ||= poetry_instance_id("poetry-accordion")
|
|
148
145
|
end
|
|
149
146
|
|
|
147
|
+
# One item's header: the trigger button with its chevron, wired to the controller.
|
|
150
148
|
def accordion_header(item_id, title, open_item, disabled: false)
|
|
151
149
|
trigger_attrs = {
|
|
152
150
|
type: "button", id: "#{item_id}-trigger", class: css(:trigger),
|
|
@@ -173,6 +171,7 @@ module Poetry
|
|
|
173
171
|
end
|
|
174
172
|
end
|
|
175
173
|
|
|
174
|
+
# One item's panel region, hidden when closed, labelled by its trigger.
|
|
176
175
|
def accordion_panel(item_id, open_item, &)
|
|
177
176
|
attrs = {
|
|
178
177
|
id: "#{item_id}-panel", role: "region", class: css(:content),
|
|
@@ -185,12 +184,13 @@ module Poetry
|
|
|
185
184
|
end
|
|
186
185
|
end
|
|
187
186
|
|
|
187
|
+
# The trigger's chevron icon.
|
|
188
188
|
def chevron
|
|
189
189
|
render(Icon::Component.new(name: :"chevron-down", class: css(:indicator),
|
|
190
190
|
data: { slot: "accordion-trigger-icon" }))
|
|
191
191
|
end
|
|
192
192
|
|
|
193
|
-
private :open_values
|
|
193
|
+
private :open_values
|
|
194
194
|
end
|
|
195
195
|
end
|
|
196
196
|
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<%= content_tag(:div, **root_attributes
|
|
1
|
+
<%= content_tag(:div, **root_attributes) do %>
|
|
2
2
|
<%= icon %>
|
|
3
3
|
<% if title? %><div data-slot="alert-title" class="<%= css(:title) %>"><%= title %></div><% end %>
|
|
4
4
|
<div data-slot="alert-description" class="<%= css(:description) %>"><%= content %></div>
|
|
@@ -43,18 +43,15 @@ module Poetry
|
|
|
43
43
|
"pinned to the top-right by the theme"
|
|
44
44
|
part "alert-description", "The body copy - the content block renders here"
|
|
45
45
|
|
|
46
|
-
#
|
|
46
|
+
# The root's attributes: this component's markup over the core default.
|
|
47
47
|
def root_attributes
|
|
48
|
-
|
|
48
|
+
super(
|
|
49
49
|
{
|
|
50
|
-
"data-slot" => "alert",
|
|
51
50
|
"data-variant" => variant,
|
|
52
51
|
"role" => (variant == :destructive ? "alert" : "status")
|
|
53
|
-
}
|
|
52
|
+
}
|
|
54
53
|
)
|
|
55
54
|
end
|
|
56
|
-
|
|
57
|
-
private :root_attributes
|
|
58
55
|
end
|
|
59
56
|
end
|
|
60
57
|
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
<%= content_tag(:div, **root_attributes
|
|
1
|
+
<%= content_tag(:div, **root_attributes) do %>
|
|
2
2
|
<%= trigger %>
|
|
3
|
-
<%= content_tag(:dialog, **
|
|
3
|
+
<%= content_tag(:dialog, **dialog_attributes) do %>
|
|
4
4
|
<div data-slot="alert-dialog-header" class="<%= header_classes %>">
|
|
5
5
|
<% if media? %>
|
|
6
6
|
<div data-slot="alert-dialog-media" class="<%= media_classes %>"><%= media %></div>
|
|
@@ -148,29 +148,32 @@ module Poetry
|
|
|
148
148
|
raise ArgumentError, "AlertDialog requires with_cancel (the safe way out)" unless cancel?
|
|
149
149
|
end
|
|
150
150
|
|
|
151
|
+
# The title element's id.
|
|
151
152
|
# @api private
|
|
152
153
|
def title_id
|
|
153
154
|
"#{instance_id}-title"
|
|
154
155
|
end
|
|
155
156
|
|
|
157
|
+
# The description element's id.
|
|
156
158
|
# @api private
|
|
157
159
|
def description_id
|
|
158
160
|
"#{instance_id}-description"
|
|
159
161
|
end
|
|
160
162
|
|
|
163
|
+
# The dialog element's attributes: the alertdialog role, size, closed state and wiring.
|
|
161
164
|
# @api private
|
|
162
165
|
def dialog_attributes
|
|
163
|
-
{
|
|
166
|
+
attrs = {
|
|
164
167
|
"class" => css(:content, class: content_class),
|
|
165
168
|
# Explicit role: overrides the implicit dialog role (aria-modal
|
|
166
169
|
# still comes from showModal).
|
|
167
170
|
"role" => "alertdialog",
|
|
168
|
-
"data-slot" => "alert-dialog-content",
|
|
169
171
|
"data-size" => size,
|
|
170
172
|
"data-closed" => "",
|
|
171
173
|
"aria-labelledby" => title_id,
|
|
172
174
|
"aria-describedby" => description_id
|
|
173
|
-
}
|
|
175
|
+
}
|
|
176
|
+
element_attributes(:content, attrs)
|
|
174
177
|
end
|
|
175
178
|
|
|
176
179
|
# The media/size layout branches emitted as explicit server-side
|
|
@@ -185,16 +188,19 @@ module Poetry
|
|
|
185
188
|
].compact.join(" "))
|
|
186
189
|
end
|
|
187
190
|
|
|
191
|
+
# The media slot's classes, sized for the default dialog.
|
|
188
192
|
# @api private
|
|
189
193
|
def media_classes
|
|
190
194
|
css(:media, class: (css(:media_size_default) if size == :default))
|
|
191
195
|
end
|
|
192
196
|
|
|
197
|
+
# The title's classes, placed beside the media in the default size.
|
|
193
198
|
# @api private
|
|
194
199
|
def title_classes
|
|
195
200
|
css(:title, class: (css(:title_beside_media) if media? && size == :default))
|
|
196
201
|
end
|
|
197
202
|
|
|
203
|
+
# The footer's classes, tightened in the small size.
|
|
198
204
|
# @api private
|
|
199
205
|
def footer_classes
|
|
200
206
|
css(:footer, class: (css(:footer_size_sm) if size == :sm))
|
|
@@ -41,22 +41,20 @@ module Poetry
|
|
|
41
41
|
"AspectRatio ratio: must be a CSS ratio ('16/9', '1', '1.5') - got #{ratio.inspect}"
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
+
# Renders the ratio box around the content.
|
|
44
45
|
# @api private
|
|
45
46
|
def call
|
|
46
|
-
content_tag(:div, content, **root_attributes
|
|
47
|
+
content_tag(:div, content, **root_attributes)
|
|
47
48
|
end
|
|
48
49
|
|
|
49
|
-
#
|
|
50
|
+
# The root's attributes: this component's markup over the core default.
|
|
50
51
|
def root_attributes
|
|
51
|
-
|
|
52
|
+
super(
|
|
52
53
|
{
|
|
53
|
-
"data-slot" => "aspect-ratio",
|
|
54
54
|
"style" => "--ratio: #{ratio}"
|
|
55
|
-
}
|
|
55
|
+
}
|
|
56
56
|
)
|
|
57
57
|
end
|
|
58
|
-
|
|
59
|
-
private :root_attributes
|
|
60
58
|
end
|
|
61
59
|
end
|
|
62
60
|
end
|
|
@@ -122,17 +122,17 @@ module Poetry
|
|
|
122
122
|
ANNOUNCED_STATES.include?(state)
|
|
123
123
|
end
|
|
124
124
|
|
|
125
|
-
#
|
|
125
|
+
# The root's attributes: this component's markup over the core default.
|
|
126
126
|
def root_attributes
|
|
127
|
-
|
|
127
|
+
super(
|
|
128
128
|
{
|
|
129
|
-
"data-
|
|
129
|
+
"data-upload-state" => state,
|
|
130
130
|
"data-size" => size, "data-orientation" => orientation
|
|
131
|
-
}
|
|
131
|
+
}
|
|
132
132
|
)
|
|
133
133
|
end
|
|
134
134
|
|
|
135
|
-
private :announced
|
|
135
|
+
private :announced?
|
|
136
136
|
end
|
|
137
137
|
end
|
|
138
138
|
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<%= content_tag(:div, **root_attributes
|
|
1
|
+
<%= content_tag(:div, **root_attributes) do %>
|
|
2
2
|
<%= tag.input(**input_attributes, class: Poetry::Ui::Input::Style.css) %>
|
|
3
3
|
<%= tag.div(**content_attributes) do %>
|
|
4
4
|
<div data-slot="autocomplete-list" role="listbox" id="<%= list_id %>"
|
|
@@ -125,6 +125,7 @@ module Poetry
|
|
|
125
125
|
# @api private
|
|
126
126
|
def item_models = (@item_models ||= [])
|
|
127
127
|
|
|
128
|
+
# The root id: the given id as a token, else a stable instance id.
|
|
128
129
|
# @api private
|
|
129
130
|
def autocomplete_id
|
|
130
131
|
@autocomplete_id ||= if (token = dom_id_token(id))
|
|
@@ -134,18 +135,16 @@ module Poetry
|
|
|
134
135
|
end
|
|
135
136
|
end
|
|
136
137
|
|
|
138
|
+
# The listbox's id.
|
|
137
139
|
# @api private
|
|
138
140
|
def list_id = "#{autocomplete_id}-list"
|
|
139
141
|
|
|
140
|
-
#
|
|
142
|
+
# The root's attributes: this component's markup over the core default.
|
|
141
143
|
def root_attributes
|
|
142
|
-
|
|
143
|
-
{ "class" => css, "data-slot" => "autocomplete", "id" => autocomplete_id }
|
|
144
|
-
.merge(stimulus_attributes_for(:root))
|
|
145
|
-
.merge(component_data_attributes)
|
|
146
|
-
)
|
|
144
|
+
super({ "class" => css, "id" => autocomplete_id })
|
|
147
145
|
end
|
|
148
146
|
|
|
147
|
+
# The text input's attributes: the combobox role, its list and open state, and the wiring.
|
|
149
148
|
# @api private
|
|
150
149
|
def input_attributes
|
|
151
150
|
attrs = {
|
|
@@ -158,6 +157,7 @@ module Poetry
|
|
|
158
157
|
attrs.merge(stimulus_attributes_for(:input).transform_keys(&:to_sym))
|
|
159
158
|
end
|
|
160
159
|
|
|
160
|
+
# The popup's attributes with its open or closed state.
|
|
161
161
|
# @api private
|
|
162
162
|
def content_attributes
|
|
163
163
|
attrs = {
|
|
@@ -172,6 +172,7 @@ module Poetry
|
|
|
172
172
|
attrs.merge(stimulus_attributes_for(:content))
|
|
173
173
|
end
|
|
174
174
|
|
|
175
|
+
# One option's attributes: its id, value, label and highlighted state.
|
|
175
176
|
# @api private
|
|
176
177
|
def item_attributes(item, index)
|
|
177
178
|
attrs = {
|
|
@@ -190,7 +191,7 @@ module Poetry
|
|
|
190
191
|
# @api private
|
|
191
192
|
Item = Struct.new(:label, :value, :disabled, :highlighted, keyword_init: true)
|
|
192
193
|
|
|
193
|
-
private :item_models, :autocomplete_id, :list_id, :
|
|
194
|
+
private :item_models, :autocomplete_id, :list_id, :input_attributes, :content_attributes
|
|
194
195
|
private :item_attributes
|
|
195
196
|
end
|
|
196
197
|
end
|
|
@@ -57,30 +57,33 @@ module Poetry
|
|
|
57
57
|
ensure_content!
|
|
58
58
|
end
|
|
59
59
|
|
|
60
|
+
# Renders the avatar: the fallback, the image and the badge.
|
|
60
61
|
# @api private
|
|
61
62
|
def call
|
|
62
|
-
content_tag(:span, root_attributes
|
|
63
|
+
content_tag(:span, root_attributes) do
|
|
63
64
|
safe_join([fallback, image, badge_part].compact)
|
|
64
65
|
end
|
|
65
66
|
end
|
|
66
67
|
|
|
67
|
-
#
|
|
68
|
+
# The root's attributes: this component's markup over the core default.
|
|
68
69
|
def root_attributes
|
|
69
|
-
|
|
70
|
+
super(
|
|
70
71
|
{
|
|
71
|
-
"data-
|
|
72
|
+
"data-size" => size,
|
|
72
73
|
"role" => "img", "aria-label" => label
|
|
73
|
-
}
|
|
74
|
+
}
|
|
74
75
|
)
|
|
75
76
|
end
|
|
76
77
|
|
|
77
78
|
private
|
|
78
79
|
|
|
80
|
+
# The initials fallback span.
|
|
79
81
|
def fallback
|
|
80
82
|
content_tag(:span, content, "data-slot" => "avatar-fallback", "aria-hidden" => "true",
|
|
81
83
|
class: css(:fallback))
|
|
82
84
|
end
|
|
83
85
|
|
|
86
|
+
# The image, or nil without a source.
|
|
84
87
|
def image
|
|
85
88
|
return if src.blank?
|
|
86
89
|
|
|
@@ -90,13 +93,12 @@ module Poetry
|
|
|
90
93
|
tag.img(src: src, alt: "", "data-slot": "avatar-image", class: css(:image))
|
|
91
94
|
end
|
|
92
95
|
|
|
96
|
+
# The badge span, or nil without a badge.
|
|
93
97
|
def badge_part
|
|
94
98
|
return unless badge?
|
|
95
99
|
|
|
96
100
|
content_tag(:span, badge, "data-slot" => "avatar-badge", "aria-hidden" => "true", class: css(:badge))
|
|
97
101
|
end
|
|
98
|
-
|
|
99
|
-
private :root_attributes
|
|
100
102
|
end
|
|
101
103
|
end
|
|
102
104
|
end
|
|
@@ -54,19 +54,18 @@ module Poetry
|
|
|
54
54
|
ensure_content!
|
|
55
55
|
end
|
|
56
56
|
|
|
57
|
+
# Renders the badge as a link when it has an href, else as a span.
|
|
57
58
|
# @api private
|
|
58
59
|
def call
|
|
59
|
-
content_tag(href.present? ? :a : :span, content, **root_attributes
|
|
60
|
+
content_tag(href.present? ? :a : :span, content, **root_attributes)
|
|
60
61
|
end
|
|
61
62
|
|
|
62
|
-
#
|
|
63
|
+
# The root's attributes: this component's markup over the core default.
|
|
63
64
|
def root_attributes
|
|
64
|
-
attrs = { "data-
|
|
65
|
+
attrs = { "data-variant" => variant }
|
|
65
66
|
attrs["href"] = href if href.present?
|
|
66
|
-
|
|
67
|
+
super(attrs)
|
|
67
68
|
end
|
|
68
|
-
|
|
69
|
-
private :root_attributes
|
|
70
69
|
end
|
|
71
70
|
end
|
|
72
71
|
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<%= content_tag(:nav, **root_attributes
|
|
1
|
+
<%= content_tag(:nav, **root_attributes) do %>
|
|
2
2
|
<ol data-slot="breadcrumb-list" class="<%= css(:list) %>">
|
|
3
3
|
<% entries.each_with_index do |entry, index| %>
|
|
4
4
|
<li data-slot="breadcrumb-item" class="<%= css(:item) %>">
|
|
@@ -18,7 +18,6 @@ module Poetry
|
|
|
18
18
|
# <% end %>
|
|
19
19
|
class Component < Poetry::Core::Component
|
|
20
20
|
# The caller's separator block, captured by with_separator.
|
|
21
|
-
# @api private
|
|
22
21
|
attr_reader :separator_block
|
|
23
22
|
|
|
24
23
|
# Projected into the registry, llms.txt, and the agent surface.
|
|
@@ -84,18 +83,17 @@ module Poetry
|
|
|
84
83
|
@entries ||= []
|
|
85
84
|
end
|
|
86
85
|
|
|
87
|
-
#
|
|
86
|
+
# The root's attributes: this component's markup over the core default.
|
|
88
87
|
def root_attributes
|
|
89
|
-
|
|
90
|
-
{ "aria-label" => "breadcrumb", "data-slot" => "breadcrumb" }.merge(component_data_attributes)
|
|
91
|
-
)
|
|
88
|
+
super({ "aria-label" => "breadcrumb" })
|
|
92
89
|
end
|
|
93
90
|
|
|
94
91
|
# One declared crumb.
|
|
95
92
|
# @api private
|
|
96
93
|
Entry = Data.define(:label, :href, :ellipsis, :block)
|
|
97
94
|
|
|
98
|
-
private :entries
|
|
95
|
+
private :entries
|
|
96
|
+
private :separator_block
|
|
99
97
|
end
|
|
100
98
|
end
|
|
101
99
|
end
|
|
@@ -76,12 +76,9 @@ module Poetry
|
|
|
76
76
|
ensure_content!
|
|
77
77
|
end
|
|
78
78
|
|
|
79
|
-
#
|
|
79
|
+
# The root's attributes: this component's markup over the core default.
|
|
80
80
|
def root_attributes
|
|
81
|
-
|
|
82
|
-
{ "data-slot" => "bubble", "data-variant" => variant, "data-align" => align }
|
|
83
|
-
.merge(component_data_attributes)
|
|
84
|
-
)
|
|
81
|
+
super({ "data-variant" => variant, "data-align" => align })
|
|
85
82
|
end
|
|
86
83
|
|
|
87
84
|
# href: implies the anchor - an href on the default :div would
|
|
@@ -91,6 +88,7 @@ module Poetry
|
|
|
91
88
|
href.present? ? :a : tag
|
|
92
89
|
end
|
|
93
90
|
|
|
91
|
+
# The content element's attributes, with the href or button type its tag needs.
|
|
94
92
|
# @api private
|
|
95
93
|
def content_attributes
|
|
96
94
|
attrs = { class: css(:content), "data-slot" => "bubble-content" }
|
|
@@ -99,7 +97,7 @@ module Poetry
|
|
|
99
97
|
attrs
|
|
100
98
|
end
|
|
101
99
|
|
|
102
|
-
private :
|
|
100
|
+
private :content_tag_name, :content_attributes
|
|
103
101
|
end
|
|
104
102
|
end
|
|
105
103
|
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<%= content_tag(root_tag, **root_attributes
|
|
1
|
+
<%= content_tag(root_tag, **root_attributes) do %>
|
|
2
2
|
<% if loading %>
|
|
3
3
|
<span data-slot="spinner" aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" class="animate-spin"><path d="M21 12a9 9 0 1 1-6.219-8.56" /></svg></span>
|
|
4
4
|
<% end %>
|
|
@@ -113,18 +113,20 @@ module Poetry
|
|
|
113
113
|
tag == :a || href.present?
|
|
114
114
|
end
|
|
115
115
|
|
|
116
|
+
# The root tag: an anchor for a link, else a button.
|
|
116
117
|
# @api private
|
|
117
118
|
def root_tag
|
|
118
119
|
link_tag? ? :a : :button
|
|
119
120
|
end
|
|
120
121
|
|
|
121
|
-
#
|
|
122
|
+
# The root's attributes: the base and the tag's own, over the caller's.
|
|
122
123
|
def root_attributes
|
|
123
|
-
html_attributes.merge_if_not_set(base_attributes.merge(tag_attributes))
|
|
124
|
+
html_attributes.merge_if_not_set(base_attributes.merge(tag_attributes)).to_attributes
|
|
124
125
|
end
|
|
125
126
|
|
|
126
127
|
private
|
|
127
128
|
|
|
129
|
+
# The attributes every button root carries: identity, variant, size, label and loading state.
|
|
128
130
|
def base_attributes
|
|
129
131
|
attrs = { "data-slot" => "button", "data-variant" => variant, "data-size" => size }
|
|
130
132
|
.merge(component_data_attributes)
|
|
@@ -143,6 +145,7 @@ module Poetry
|
|
|
143
145
|
link_tag? ? link_attributes : button_attributes
|
|
144
146
|
end
|
|
145
147
|
|
|
148
|
+
# The anchor's attributes: the button role, and the href or the disabled state.
|
|
146
149
|
def link_attributes
|
|
147
150
|
attrs = { "role" => "button" }
|
|
148
151
|
if disabled || loading
|
|
@@ -153,15 +156,14 @@ module Poetry
|
|
|
153
156
|
attrs
|
|
154
157
|
end
|
|
155
158
|
|
|
159
|
+
# The button's attributes: its type and disabled state.
|
|
156
160
|
def button_attributes
|
|
157
161
|
attrs = { "type" => type }
|
|
158
162
|
attrs["disabled"] = true if disabled || loading
|
|
159
163
|
attrs
|
|
160
164
|
end
|
|
161
165
|
|
|
162
|
-
private :icon_only?, :link_tag?, :root_tag
|
|
163
|
-
|
|
164
|
-
private :icon_only?, :link_tag?, :root_tag, :root_attributes
|
|
166
|
+
private :icon_only?, :link_tag?, :root_tag
|
|
165
167
|
end
|
|
166
168
|
end
|
|
167
169
|
end
|
|
@@ -48,22 +48,20 @@ module Poetry
|
|
|
48
48
|
ensure_content!
|
|
49
49
|
end
|
|
50
50
|
|
|
51
|
+
# Renders the group around its content.
|
|
51
52
|
# @api private
|
|
52
53
|
def call
|
|
53
|
-
content_tag(:div, content, **root_attributes
|
|
54
|
+
content_tag(:div, content, **root_attributes)
|
|
54
55
|
end
|
|
55
56
|
|
|
56
|
-
#
|
|
57
|
+
# The root's attributes: this component's markup over the core default.
|
|
57
58
|
def root_attributes
|
|
58
|
-
|
|
59
|
+
super(
|
|
59
60
|
{
|
|
60
|
-
"role" => "group", "data-
|
|
61
|
-
|
|
62
|
-
}.merge(component_data_attributes)
|
|
61
|
+
"role" => "group", "data-orientation" => orientation
|
|
62
|
+
}
|
|
63
63
|
)
|
|
64
64
|
end
|
|
65
|
-
|
|
66
|
-
private :root_attributes
|
|
67
65
|
end
|
|
68
66
|
end
|
|
69
67
|
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<%= content_tag(:div, **root_attributes
|
|
1
|
+
<%= content_tag(:div, **root_attributes) do %>
|
|
2
2
|
<div data-slot="calendar-nav" class="<%= css(:nav) %>">
|
|
3
3
|
<%= render Poetry::Ui::Button::Component.new(**previous_options) do |button| %>
|
|
4
4
|
<% button.with_leading { render Poetry::Ui::Icon::Component.new(name: :"chevron-left") } %>
|