poetry-ui 0.1.0 → 0.1.1
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/CHANGELOG.md +23 -1
- data/app/components/poetry/ui/combobox/component.rb +4 -1
- data/app/components/poetry/ui/command/component.rb +3 -2
- data/app/components/poetry/ui/context_menu/component.rb +4 -1
- data/app/components/poetry/ui/drawer/component.rb +3 -0
- data/app/components/poetry/ui/dropdown_menu/component.rb +5 -1
- data/app/components/poetry/ui/hover_card/component.rb +3 -2
- data/app/components/poetry/ui/menubar/component.rb +4 -3
- data/app/components/poetry/ui/menus.rb +21 -2
- data/app/components/poetry/ui/message_scroller/component.rb +28 -4
- data/app/components/poetry/ui/message_scroller/style.rb +7 -1
- data/app/components/poetry/ui/navigation_menu/component.rb +26 -10
- data/app/components/poetry/ui/number_field/component.rb +0 -1
- data/app/components/poetry/ui/select/component.rb +4 -2
- data/app/components/poetry/ui/toast_trigger/component.rb +4 -3
- data/config/component_registry.yml +32 -12
- data/lib/generators/poetry/agents_section.rb +1 -1
- data/lib/generators/poetry/install/install_generator.rb +29 -0
- data/lib/poetry/ui/chat.rb +5 -0
- data/lib/poetry/ui/themes.rb +1 -1
- data/lib/poetry/ui/version.rb +1 -1
- data/lib/tasks/poetry/check.rake +2 -1
- data/themes/luma.css +1 -1
- data/themes/lyra.css +1 -1
- data/themes/maia.css +1 -1
- data/themes/mira.css +1 -1
- data/themes/nova.css +1 -1
- data/themes/rhea.css +1 -1
- data/themes/sera.css +1 -1
- data/themes/vega.css +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: be9d330390d3bf48c36cd783dfaf4fdd00a0cf6073b9b8944caf10104abf66b7
|
|
4
|
+
data.tar.gz: 99aa8e106788b9a8d597b149e68c8d6353c7a49876a32969f106327a7d1be813
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6f60d8c522645d60374997d18bcea9ff4baaeb2f5fd888374966d008ef362f216b7cb0fa2f022f4f6b2127c10aa6750de2e37546c9aec380b37e79a909cee29a
|
|
7
|
+
data.tar.gz: 1b8bf7807b8f0836d702577677038fd1d42a5b2a8283579eee0471bd20026de193487d42ebe5861615fa9b2b1969087e1201a7fb5791b6715c4d6cdec63824d9
|
data/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,28 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## [
|
|
3
|
+
## [0.1.1] - 2026-09-08
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- `content_class:` on `poetry_dropdown_menu` and `poetry_context_menu`, on Menubar's `with_menu`, and on every menu family's `with_sub`: the panel's class merge seam, the one Popover, HoverCard and Dialog already had. A dropdown panel opens at its trigger's width (minimum 8rem), so `content_class: "w-56"` is how a menu with icons, shortcuts or long labels gets its width.
|
|
8
|
+
- NavigationMenu `with_item(title, value:, disabled: true)`: an inert trigger (`disabled` + `data-disabled`) that hover, click and the arrows skip. `disabled:` on a link raises.
|
|
9
|
+
- `Poetry::Ui::Chat::Error`, a `Poetry::Core::Error`: `AssistantTurn#continuation_frames` raises it on a turn without an approval pause, where a missing constant raised NameError before.
|
|
10
|
+
- `poetry:install --skip-bundle`.
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- `poetry:install` adds the `herb` gem to the development group (once, never when the Gemfile already declares it) and runs `bundle install`, so `bin/rails poetry:check` works on a fresh app with no manual step. `poetry:check`'s missing-parser message points at the installer.
|
|
15
|
+
- The upstream pin is shadcn@4.21.0. The theme CSS is unchanged between the releases; both fidelity ledgers are re-snapshotted at the new pin.
|
|
16
|
+
- MessageScroller renders `data-pending-scroll` on its root and viewport for `:end` and `:"last-anchor"`; the viewport hides while it is set (visibility, so the layout stays) and the hold lifts without JavaScript. The part contracts declare the state.
|
|
17
|
+
- Select, Combobox and Command group headings are `aria-hidden`: the group's name flows through `aria-labelledby`, so screen readers stop announcing the heading a second time. Menu groups wire `aria-labelledby` to a label rendered inside them and hide it the same way; a label outside any group stays plain text.
|
|
18
|
+
- HoverCard's trigger wiring is `pointerdown->pointerDown` (was `touchstart->touchGuard`), and NumberField's input no longer wires a `focus` action. A copy made with `poetry:add hover_card` or `poetry:add number_field` before this version carries the old wiring and logs a Stimulus "undefined method" error on those events: run `bin/rails g poetry:diff` and update the two lines. Apps on the gem-owned tier need nothing.
|
|
19
|
+
- ToastTrigger names its Button root through `identity:`.
|
|
20
|
+
- NavigationMenu's agent rules state the keyboard contract: ArrowLeft/ArrowRight between triggers and links, ArrowDown opens the focused trigger's panel, Escape closes.
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- HoverCard: a tap on the trigger clicks through on touch devices (the collapsed sidebar's icons did nothing on a tablet).
|
|
25
|
+
- NumberField: Tab's select-all and a click's caret placement stay native.
|
|
4
26
|
|
|
5
27
|
## [0.1.0] - 2026-09-05
|
|
6
28
|
|
|
@@ -236,9 +236,12 @@ module Poetry
|
|
|
236
236
|
"#{group_id}-heading"
|
|
237
237
|
end
|
|
238
238
|
|
|
239
|
+
# The group's name flows through aria-labelledby; aria-hidden keeps
|
|
240
|
+
# the text from being read a second time as a stray child of the
|
|
241
|
+
# listbox.
|
|
239
242
|
def heading_part
|
|
240
243
|
content_tag(:div, @heading_text, "data-slot" => "combobox-label", "id" => heading_id,
|
|
241
|
-
"class" => Style.css(:label))
|
|
244
|
+
"aria-hidden" => "true", "class" => Style.css(:label))
|
|
242
245
|
end
|
|
243
246
|
end
|
|
244
247
|
|
|
@@ -207,10 +207,11 @@ module Poetry
|
|
|
207
207
|
end
|
|
208
208
|
|
|
209
209
|
# A styled heading, no ARIA role - the group points at it via
|
|
210
|
-
# aria-labelledby
|
|
210
|
+
# aria-labelledby, and aria-hidden keeps the text from being read a
|
|
211
|
+
# second time as a stray child of the listbox.
|
|
211
212
|
def heading_part
|
|
212
213
|
content_tag(:div, @heading_text, "data-slot" => "command-group-heading", "id" => heading_id,
|
|
213
|
-
"class" => Style.css(:heading))
|
|
214
|
+
"aria-hidden" => "true", "class" => Style.css(:heading))
|
|
214
215
|
end
|
|
215
216
|
end
|
|
216
217
|
|
|
@@ -135,6 +135,9 @@ module Poetry
|
|
|
135
135
|
option :loop, :boolean, default: false, doc: "Wraps arrow-key movement past either end of the menu."
|
|
136
136
|
option :long_press_delay, :integer, default: 700, doc: "Touch long-press duration in ms before the menu opens."
|
|
137
137
|
option :disabled, :boolean, default: false, doc: "Inerts the surface - no gesture opens the menu."
|
|
138
|
+
option :content_class, :string,
|
|
139
|
+
doc: "Class merge seam for the menu panel (e.g. content_class: \"w-48\"). Root-level " \
|
|
140
|
+
"class: styles the surface wrapper, not the panel."
|
|
138
141
|
option :label, :string, doc: "The menu's accessible name (localized fallback when omitted)."
|
|
139
142
|
option :focusable_surface, :boolean, default: false,
|
|
140
143
|
doc: "Puts the surface in the tab order and advertises Shift+F10."
|
|
@@ -278,7 +281,7 @@ module Poetry
|
|
|
278
281
|
"data-slot" => "context-menu-content", (open ? "data-open" : "data-closed") => "",
|
|
279
282
|
# The initial placement (side: option; re-resolved live by popper).
|
|
280
283
|
"data-side" => side.to_s, "data-align" => "start",
|
|
281
|
-
"class" => css(:content)
|
|
284
|
+
"class" => css(:content, class: content_class)
|
|
282
285
|
}.merge(stimulus_attributes_for(:content))
|
|
283
286
|
attrs["hidden"] = true unless open
|
|
284
287
|
attrs
|
|
@@ -142,6 +142,9 @@ module Poetry
|
|
|
142
142
|
tool :open, description: "Open the drawer.", executes: :open, mutating: true
|
|
143
143
|
tool :close, description: "Close the drawer.", executes: :close, mutating: true
|
|
144
144
|
|
|
145
|
+
# The inherited render checks, then the snap-point rules when
|
|
146
|
+
# snap_points: is given.
|
|
147
|
+
# @api private
|
|
145
148
|
def before_render
|
|
146
149
|
super
|
|
147
150
|
validate_snap_points! if snap_points.present?
|
|
@@ -143,6 +143,10 @@ module Poetry
|
|
|
143
143
|
option :loop, :boolean, default: false, doc: "Arrow-key navigation wraps from the last item back to the first."
|
|
144
144
|
option :dir, :symbol, doc: "Reading direction; :rtl flips submenu sides and indicators."
|
|
145
145
|
option :disabled, :boolean, default: false, doc: "Disables the menu trigger button."
|
|
146
|
+
option :content_class, :string,
|
|
147
|
+
doc: "Class merge seam for the menu panel - the panel opens at the trigger's width " \
|
|
148
|
+
"(min 8rem), so content_class: \"w-56\" widens it. Root-level class: styles the " \
|
|
149
|
+
"wrapper, not the panel."
|
|
146
150
|
|
|
147
151
|
validates :side, inclusion: { in: SIDES }
|
|
148
152
|
validates :align, inclusion: { in: ALIGNS }
|
|
@@ -272,7 +276,7 @@ module Poetry
|
|
|
272
276
|
"data-slot" => "dropdown-menu-content", (open ? "data-open" : "data-closed") => "",
|
|
273
277
|
# Initial placement, re-resolved live by popper on open.
|
|
274
278
|
"data-side" => side, "data-align" => align,
|
|
275
|
-
"class" => css(:content)
|
|
279
|
+
"class" => css(:content, class: content_class)
|
|
276
280
|
}.merge(stimulus_attributes_for(:content))
|
|
277
281
|
attrs["hidden"] = true unless open
|
|
278
282
|
attrs
|
|
@@ -95,14 +95,15 @@ module Poetry
|
|
|
95
95
|
end
|
|
96
96
|
# The trigger handlers: pointerenter/leave pair
|
|
97
97
|
# timers (touch excluded), focus opens immediately / blur closes,
|
|
98
|
-
# and the
|
|
98
|
+
# and the pointerdown latch (a tap or click never focus-opens; the
|
|
99
|
+
# tap keeps its click, so it navigates).
|
|
99
100
|
on :trigger do
|
|
100
101
|
controller :hover_card do
|
|
101
102
|
action :pointer_enter, on: :pointerenter
|
|
102
103
|
action :pointer_leave, on: :pointerleave
|
|
103
104
|
action :focus_open, on: :focus
|
|
104
105
|
action :blur_close, on: :blur
|
|
105
|
-
action :
|
|
106
|
+
action :pointer_down, on: :pointerdown
|
|
106
107
|
end
|
|
107
108
|
controller(:popper) { target :anchor }
|
|
108
109
|
end
|
|
@@ -73,7 +73,7 @@ module Poetry
|
|
|
73
73
|
renders_many :menus,
|
|
74
74
|
doc: "The top-level menus. Each takes with_trigger (the menu button) plus the family item " \
|
|
75
75
|
"slots (with_item, with_checkbox_item, with_radio_group, with_sub, with_separator, ...); " \
|
|
76
|
-
"value: defaults to the menu's position.",
|
|
76
|
+
"value: defaults to the menu's position; content_class: is the panel's class merge seam.",
|
|
77
77
|
renders: ->(**options) { Menu.new(bar: self, dir: dir, **options) }
|
|
78
78
|
|
|
79
79
|
use_stimulus do
|
|
@@ -341,11 +341,12 @@ module Poetry
|
|
|
341
341
|
content_tag(:button, Poetry::Core::HTML::Attributes.merged(attrs, options)) { capture(&block) }
|
|
342
342
|
}
|
|
343
343
|
|
|
344
|
-
def initialize(bar:, value: nil, disabled: false, dir: nil, **extra_attributes)
|
|
344
|
+
def initialize(bar:, value: nil, disabled: false, dir: nil, content_class: nil, **extra_attributes)
|
|
345
345
|
super(extra_attributes)
|
|
346
346
|
@bar = bar
|
|
347
347
|
@disabled = disabled
|
|
348
348
|
@dir = dir
|
|
349
|
+
@content_class = content_class
|
|
349
350
|
position = @bar.register_menu(self)
|
|
350
351
|
@value = (value || "menu-#{position}").to_s
|
|
351
352
|
end
|
|
@@ -419,7 +420,7 @@ module Poetry
|
|
|
419
420
|
"data-slot" => "menubar-content", (open? ? "data-open" : "data-closed") => "",
|
|
420
421
|
# Initial placement, re-resolved live by popper on open.
|
|
421
422
|
"data-side" => "bottom", "data-align" => "start",
|
|
422
|
-
"class" => Style.css(:content)
|
|
423
|
+
"class" => Style.css(:content, class: @content_class)
|
|
423
424
|
}.merge(stimulus_attributes(:popper) { |popper| popper.with_target(:content) })
|
|
424
425
|
attrs["hidden"] = true unless open?
|
|
425
426
|
content_tag(:div, attrs) { safe_join(items.map(&:to_s)) }
|
|
@@ -226,11 +226,28 @@ module Poetry
|
|
|
226
226
|
|
|
227
227
|
def call
|
|
228
228
|
attrs = { "data-slot" => "#{family_slot_prefix}-group", "role" => "group" }
|
|
229
|
+
attrs["aria-labelledby"] = label_id if @labelled
|
|
229
230
|
content_tag(:div, Poetry::Core::HTML::Attributes.merged(attrs, html_attributes)) { safe_join(items.map(&:to_s)) }
|
|
230
231
|
end
|
|
231
232
|
|
|
232
233
|
private
|
|
233
234
|
|
|
235
|
+
# A label inside a group names the group (aria-labelledby) and is
|
|
236
|
+
# aria-hidden, so its text is not read a second time as a stray child
|
|
237
|
+
# of the menu; a label outside any group stays plain text.
|
|
238
|
+
def label_part(**, &)
|
|
239
|
+
@labelled = true
|
|
240
|
+
super("id" => label_id, "aria-hidden" => "true", **, &)
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
def group_id
|
|
244
|
+
@group_id ||= poetry_instance_id("poetry-#{family_slot_prefix}-group")
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
def label_id
|
|
248
|
+
"#{group_id}-label"
|
|
249
|
+
end
|
|
250
|
+
|
|
234
251
|
def menu_dir
|
|
235
252
|
@dir
|
|
236
253
|
end
|
|
@@ -311,9 +328,11 @@ module Poetry
|
|
|
311
328
|
end
|
|
312
329
|
}
|
|
313
330
|
|
|
314
|
-
|
|
331
|
+
# content_class: is the sub-panel's class merge seam (with_sub(content_class: "w-40")).
|
|
332
|
+
def initialize(dir: nil, content_class: nil, **extra_attributes)
|
|
315
333
|
super(extra_attributes)
|
|
316
334
|
@dir = dir
|
|
335
|
+
@content_class = content_class
|
|
317
336
|
end
|
|
318
337
|
|
|
319
338
|
def before_render
|
|
@@ -363,7 +382,7 @@ module Poetry
|
|
|
363
382
|
"id" => content_id, "role" => "menu", "aria-orientation" => "vertical",
|
|
364
383
|
"aria-labelledby" => trigger_id, "tabindex" => "-1",
|
|
365
384
|
"data-slot" => "#{family_slot_prefix}-sub-content", "data-closed" => "", "hidden" => true,
|
|
366
|
-
"class" => family_style.css(:sub_content)
|
|
385
|
+
"class" => family_style.css(:sub_content, class: @content_class)
|
|
367
386
|
}.merge(stimulus_attributes(:popper) { |popper| popper.with_target(:content) })
|
|
368
387
|
content_tag(:div, attrs) { safe_join(items.map(&:to_s)) }
|
|
369
388
|
end
|
|
@@ -9,6 +9,16 @@ module Poetry
|
|
|
9
9
|
# a jump-to-latest button. Without JavaScript it is a plain
|
|
10
10
|
# scrollable region, fully readable.
|
|
11
11
|
#
|
|
12
|
+
# Opening position: a scroll container always opens at the top, so a
|
|
13
|
+
# transcript opening at the newest message would paint the oldest
|
|
14
|
+
# rows first and jump once the controller runs. For :end and
|
|
15
|
+
# :"last-anchor" the root and the viewport render
|
|
16
|
+
# data-pending-scroll; the viewport's dictionary hides it while the
|
|
17
|
+
# attribute is present (visibility, so layout exists for the scroll)
|
|
18
|
+
# and the controller clears it once the position lands, or at once
|
|
19
|
+
# for an empty transcript. Without JavaScript the hold is lifted
|
|
20
|
+
# (a scripting: none media rule), so the region stays readable.
|
|
21
|
+
#
|
|
12
22
|
# The content element is the Turbo Stream append target (stable
|
|
13
23
|
# dom id "<id>-messages"); rows are poetry_message_scroller_item
|
|
14
24
|
# wrappers keyed by message id. History prepends keep the reading
|
|
@@ -92,14 +102,20 @@ module Poetry
|
|
|
92
102
|
"data-scrollable" => "overflow exists - carries which edges have room " \
|
|
93
103
|
"(start, end, or both as a space-separated pair)",
|
|
94
104
|
"data-autoscrolling" => "a programmatic scroll is settling - the " \
|
|
95
|
-
"follow-bottom release is suppressed while set"
|
|
105
|
+
"follow-bottom release is suppressed while set",
|
|
106
|
+
"data-pending-scroll" => "the opening-position hold - rendered for " \
|
|
107
|
+
"default_scroll_position :end / :\"last-anchor\", " \
|
|
108
|
+
"cleared once the position lands (at once for an " \
|
|
109
|
+
"empty transcript)"
|
|
96
110
|
}
|
|
97
111
|
part "message-scroller-viewport", "The native scroll region (role=region, " \
|
|
98
112
|
"focusable) - the controller mirrors the same " \
|
|
99
113
|
"runtime attributes here",
|
|
100
114
|
states: {
|
|
101
115
|
"data-scrollable" => "overflow exists - the same edge tokens as the root",
|
|
102
|
-
"data-autoscrolling" => "a programmatic scroll is settling"
|
|
116
|
+
"data-autoscrolling" => "a programmatic scroll is settling",
|
|
117
|
+
"data-pending-scroll" => "the opening-position hold (the root's) - the " \
|
|
118
|
+
"dictionary hides the viewport while it is set"
|
|
103
119
|
}
|
|
104
120
|
part "message-scroller-content", "The row container and Turbo Stream append target " \
|
|
105
121
|
"(stable dom id <id>-messages); role=log announces " \
|
|
@@ -120,6 +136,7 @@ module Poetry
|
|
|
120
136
|
{ "data-slot" => "message-scroller" }
|
|
121
137
|
.merge(stimulus_attributes_for(:root))
|
|
122
138
|
.merge(component_data_attributes)
|
|
139
|
+
.merge(pending_scroll_attributes)
|
|
123
140
|
)
|
|
124
141
|
end
|
|
125
142
|
|
|
@@ -129,7 +146,13 @@ module Poetry
|
|
|
129
146
|
"class" => css(:viewport), "data-slot" => "message-scroller-viewport",
|
|
130
147
|
"role" => "region", "tabindex" => "0",
|
|
131
148
|
"aria-label" => t("poetry.message_scroller.region")
|
|
132
|
-
}.merge(stimulus_attributes_for(:viewport))
|
|
149
|
+
}.merge(stimulus_attributes_for(:viewport)).merge(pending_scroll_attributes)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# The opening-position hold (the class doc) - the server renders it so
|
|
153
|
+
# the first paint never shows the top of the thread.
|
|
154
|
+
def pending_scroll_attributes
|
|
155
|
+
%i[end last-anchor].include?(default_scroll_position) ? { "data-pending-scroll" => "" } : {}
|
|
133
156
|
end
|
|
134
157
|
|
|
135
158
|
# @api private
|
|
@@ -156,7 +179,8 @@ module Poetry
|
|
|
156
179
|
}.merge(stimulus_attributes_for(:jump_button))
|
|
157
180
|
end
|
|
158
181
|
|
|
159
|
-
private :root_attributes, :viewport_attributes, :content_attributes, :spacer_attributes, :button_attributes
|
|
182
|
+
private :root_attributes, :viewport_attributes, :content_attributes, :spacer_attributes, :button_attributes,
|
|
183
|
+
:pending_scroll_attributes
|
|
160
184
|
end
|
|
161
185
|
end
|
|
162
186
|
end
|
|
@@ -16,8 +16,14 @@ module Poetry
|
|
|
16
16
|
# (rightly) rejects classes no build can produce.
|
|
17
17
|
base "relative flex size-full min-h-0 flex-col overflow-hidden group/message-scroller"
|
|
18
18
|
|
|
19
|
+
# data-pending-scroll:invisible = the opening-position hold: the
|
|
20
|
+
# viewport hides (layout intact) until the controller lands the
|
|
21
|
+
# opening position. The noscript pair lifts it when scripts are off -
|
|
22
|
+
# the plain scrollable region stays readable, this component's no-JS
|
|
23
|
+
# contract.
|
|
19
24
|
element :viewport, "size-full min-h-0 min-w-0 scroll-fade-b scrollbar-thin scrollbar-gutter-stable " \
|
|
20
|
-
"overflow-y-auto overscroll-contain contain-content data-autoscrolling:scrollbar-none"
|
|
25
|
+
"overflow-y-auto overscroll-contain contain-content data-autoscrolling:scrollbar-none " \
|
|
26
|
+
"data-pending-scroll:invisible noscript:data-pending-scroll:visible"
|
|
21
27
|
|
|
22
28
|
element :content, "cn-message-scroller-content flex h-max min-h-full flex-col"
|
|
23
29
|
|
|
@@ -30,27 +30,36 @@ module Poetry
|
|
|
30
30
|
"Panel content is poetry_navigation_menu_link entries (active: marks the current page) - " \
|
|
31
31
|
"never buttons; navigation navigates.",
|
|
32
32
|
"This is a DISCLOSURE bar: Tab moves through it normally and nothing traps - do not " \
|
|
33
|
-
"wire menu/menuitem roles."
|
|
33
|
+
"wire menu/menuitem roles. Keys: ArrowLeft/ArrowRight step between triggers and links, " \
|
|
34
|
+
"ArrowDown opens the focused trigger's panel (focus stays on the trigger; Tab enters it), " \
|
|
35
|
+
"Escape closes and returns focus to the trigger.",
|
|
34
36
|
"Rich panels (title + description grids) want viewport: true - the shared morphing " \
|
|
35
37
|
"card contains and sizes them; the default per-item mode suits simple link lists " \
|
|
36
38
|
"(the top-nav block shows the viewport pattern)."
|
|
37
39
|
].freeze
|
|
38
40
|
|
|
39
|
-
# One declared bar entry - a link (href:) or a trigger + panel pair
|
|
41
|
+
# One declared bar entry - a link (href:) or a trigger + panel pair
|
|
42
|
+
# (disabled: renders the trigger inert).
|
|
40
43
|
# @api private
|
|
41
|
-
Entry = Data.define(:title, :value, :href, :panel)
|
|
44
|
+
Entry = Data.define(:title, :value, :href, :panel, :disabled)
|
|
42
45
|
|
|
43
46
|
renders_many :items,
|
|
44
|
-
doc: "The bar entries. with_item(title, value:) { panel } declares a trigger + panel
|
|
45
|
-
"
|
|
46
|
-
|
|
47
|
+
doc: "The bar entries. with_item(title, value:) { panel } declares a trigger + panel " \
|
|
48
|
+
"(disabled: true renders the trigger inert - native disabled plus data-disabled; hover " \
|
|
49
|
+
"and click never open its panel); with_item(title, href:) a top-level link (with_link " \
|
|
50
|
+
"is the shorthand).",
|
|
51
|
+
renders: lambda { |title, value: nil, href: nil, disabled: false, &panel|
|
|
47
52
|
if href.nil? && panel.nil?
|
|
48
53
|
raise ArgumentError,
|
|
49
54
|
"NavigationMenu item #{title.inspect} needs href: (a link) or a panel block"
|
|
50
55
|
end
|
|
56
|
+
if href && disabled
|
|
57
|
+
raise ArgumentError,
|
|
58
|
+
"NavigationMenu item #{title.inspect}: disabled: applies to a trigger, not a link"
|
|
59
|
+
end
|
|
51
60
|
|
|
52
61
|
entries << Entry.new(title: title, value: value&.to_s || title.to_s.parameterize, href: href,
|
|
53
|
-
panel: panel)
|
|
62
|
+
panel: panel, disabled: disabled)
|
|
54
63
|
nil
|
|
55
64
|
}
|
|
56
65
|
|
|
@@ -116,7 +125,9 @@ module Poetry
|
|
|
116
125
|
"data-popup-open" => "its panel is open (written with aria-expanded - the chevron " \
|
|
117
126
|
"rotation hook)",
|
|
118
127
|
"data-open" => "its panel is open (the controller writes both vocabularies)",
|
|
119
|
-
"data-closed" => "its panel is closed (written after the first close)"
|
|
128
|
+
"data-closed" => "its panel is closed (written after the first close)",
|
|
129
|
+
"data-disabled" => "disabled: true - inert (native disabled rides along; hover and " \
|
|
130
|
+
"click never open the panel, the arrows step over it)"
|
|
120
131
|
}
|
|
121
132
|
part "navigation-menu-content", "One item's panel - presence-animated; in viewport mode it is " \
|
|
122
133
|
"adopted into the shared viewport on first activation",
|
|
@@ -203,11 +214,16 @@ module Poetry
|
|
|
203
214
|
|
|
204
215
|
# @api private
|
|
205
216
|
def trigger_attributes(entry)
|
|
206
|
-
{
|
|
217
|
+
attrs = {
|
|
207
218
|
"type" => "button", "data-slot" => "navigation-menu-trigger",
|
|
208
219
|
"aria-expanded" => "false", "aria-controls" => panel_id(entry),
|
|
209
220
|
"class" => "#{css(:trigger)} group"
|
|
210
|
-
}
|
|
221
|
+
}
|
|
222
|
+
if entry.disabled
|
|
223
|
+
attrs["disabled"] = true # inert: no focus, no click
|
|
224
|
+
attrs["data-disabled"] = "" # the contract's styling hook
|
|
225
|
+
end
|
|
226
|
+
attrs.merge(stimulus_attributes_for(:trigger))
|
|
211
227
|
end
|
|
212
228
|
|
|
213
229
|
# @api private
|
|
@@ -626,12 +626,14 @@ module Poetry
|
|
|
626
626
|
end
|
|
627
627
|
|
|
628
628
|
# A styled heading, no ARIA role - the group points at it via
|
|
629
|
-
# aria-labelledby
|
|
629
|
+
# aria-labelledby, and aria-hidden keeps the text from being read a
|
|
630
|
+
# second time as a stray child of the listbox (the name still flows
|
|
631
|
+
# through the reference).
|
|
630
632
|
def label_part
|
|
631
633
|
return if @label_text.blank?
|
|
632
634
|
|
|
633
635
|
content_tag(:div, @label_text, "data-slot" => "select-label", "id" => label_id,
|
|
634
|
-
"class" => Style.css(:label))
|
|
636
|
+
"aria-hidden" => "true", "class" => Style.css(:label))
|
|
635
637
|
end
|
|
636
638
|
end
|
|
637
639
|
end
|
|
@@ -65,12 +65,13 @@ module Poetry
|
|
|
65
65
|
def button_options
|
|
66
66
|
wiring = { data: { slot: "toast-trigger" } }
|
|
67
67
|
.merge(stimulus_attributes_for(:root))
|
|
68
|
-
.merge(component_data_attributes)
|
|
69
68
|
|
|
70
69
|
# Caller attributes never clobber the trigger's wiring: both sides
|
|
71
70
|
# flow through Attributes, so a host data-controller/action
|
|
72
|
-
# concatenates instead of silently killing fire-on-click.
|
|
73
|
-
|
|
71
|
+
# concatenates instead of silently killing fire-on-click. The
|
|
72
|
+
# Button root wears THIS component's identity through the
|
|
73
|
+
# identity: seam (the raw data-component is reserved).
|
|
74
|
+
{ variant: variant, size: size, identity: self.class.component_title }
|
|
74
75
|
.merge(Poetry::Core::HTML::Attributes.merged(wiring, html_attributes))
|
|
75
76
|
.symbolize_keys
|
|
76
77
|
end
|
|
@@ -2924,6 +2924,10 @@ components:
|
|
|
2924
2924
|
bem_block: poetry-ui-context_menu
|
|
2925
2925
|
styles: []
|
|
2926
2926
|
options:
|
|
2927
|
+
- name: content_class
|
|
2928
|
+
type: string
|
|
2929
|
+
description: 'Class merge seam for the menu panel (e.g. content_class: "w-48").
|
|
2930
|
+
Root-level class: styles the surface wrapper, not the panel.'
|
|
2927
2931
|
- name: dir
|
|
2928
2932
|
type: symbol
|
|
2929
2933
|
variants:
|
|
@@ -4527,6 +4531,11 @@ components:
|
|
|
4527
4531
|
type: boolean
|
|
4528
4532
|
default: true
|
|
4529
4533
|
description: Flips/shifts placement to keep the menu inside the viewport.
|
|
4534
|
+
- name: content_class
|
|
4535
|
+
type: string
|
|
4536
|
+
description: 'Class merge seam for the menu panel - the panel opens at the trigger''s
|
|
4537
|
+
width (min 8rem), so content_class: "w-56" widens it. Root-level class: styles
|
|
4538
|
+
the wrapper, not the panel.'
|
|
4530
4539
|
- name: dir
|
|
4531
4540
|
type: symbol
|
|
4532
4541
|
variants:
|
|
@@ -5651,9 +5660,9 @@ components:
|
|
|
5651
5660
|
- blurClose
|
|
5652
5661
|
- focusOpen
|
|
5653
5662
|
- openValueChanged
|
|
5663
|
+
- pointerDown
|
|
5654
5664
|
- pointerEnter
|
|
5655
5665
|
- pointerLeave
|
|
5656
|
-
- touchGuard
|
|
5657
5666
|
events:
|
|
5658
5667
|
- poetry:hover-card:closed
|
|
5659
5668
|
- poetry:hover-card:open
|
|
@@ -5773,8 +5782,8 @@ components:
|
|
|
5773
5782
|
'on': focus
|
|
5774
5783
|
- method: blurClose
|
|
5775
5784
|
'on': blur
|
|
5776
|
-
- method:
|
|
5777
|
-
'on':
|
|
5785
|
+
- method: pointerDown
|
|
5786
|
+
'on': pointerdown
|
|
5778
5787
|
- identifier: poetry--core--popper
|
|
5779
5788
|
targets:
|
|
5780
5789
|
- name: anchor
|
|
@@ -6362,7 +6371,8 @@ components:
|
|
|
6362
6371
|
many: true
|
|
6363
6372
|
description: 'The top-level menus. Each takes with_trigger (the menu button)
|
|
6364
6373
|
plus the family item slots (with_item, with_checkbox_item, with_radio_group,
|
|
6365
|
-
with_sub, with_separator, ...); value: defaults to the menu''s position
|
|
6374
|
+
with_sub, with_separator, ...); value: defaults to the menu''s position; content_class:
|
|
6375
|
+
is the panel''s class merge seam.'
|
|
6366
6376
|
setter_args:
|
|
6367
6377
|
menu: 0
|
|
6368
6378
|
builders:
|
|
@@ -7083,7 +7093,7 @@ components:
|
|
|
7083
7093
|
- content
|
|
7084
7094
|
- item
|
|
7085
7095
|
- button
|
|
7086
|
-
capsule:
|
|
7096
|
+
capsule: 7baeb0a95efa
|
|
7087
7097
|
controllers:
|
|
7088
7098
|
- identifier: poetry--core--message-scroller
|
|
7089
7099
|
targets:
|
|
@@ -7143,6 +7153,10 @@ components:
|
|
|
7143
7153
|
- attr: data-autoscrolling
|
|
7144
7154
|
condition: a programmatic scroll is settling - the follow-bottom release is
|
|
7145
7155
|
suppressed while set
|
|
7156
|
+
- attr: data-pending-scroll
|
|
7157
|
+
condition: the opening-position hold - rendered for default_scroll_position
|
|
7158
|
+
:end / :"last-anchor", cleared once the position lands (at once for an empty
|
|
7159
|
+
transcript)
|
|
7146
7160
|
- name: message-scroller-viewport
|
|
7147
7161
|
description: The native scroll region (role=region, focusable) - the controller
|
|
7148
7162
|
mirrors the same runtime attributes here
|
|
@@ -7151,6 +7165,9 @@ components:
|
|
|
7151
7165
|
condition: overflow exists - the same edge tokens as the root
|
|
7152
7166
|
- attr: data-autoscrolling
|
|
7153
7167
|
condition: a programmatic scroll is settling
|
|
7168
|
+
- attr: data-pending-scroll
|
|
7169
|
+
condition: the opening-position hold (the root's) - the dictionary hides the
|
|
7170
|
+
viewport while it is set
|
|
7154
7171
|
- name: message-scroller-content
|
|
7155
7172
|
description: The row container and Turbo Stream append target (stable dom id
|
|
7156
7173
|
<id>-messages); role=log announces additions
|
|
@@ -7420,9 +7437,10 @@ components:
|
|
|
7420
7437
|
slots:
|
|
7421
7438
|
- name: items
|
|
7422
7439
|
many: true
|
|
7423
|
-
description: The bar entries. with_item(title, value:) { panel } declares a
|
|
7424
|
-
trigger + panel
|
|
7425
|
-
|
|
7440
|
+
description: 'The bar entries. with_item(title, value:) { panel } declares a
|
|
7441
|
+
trigger + panel (disabled: true renders the trigger inert - native disabled
|
|
7442
|
+
plus data-disabled; hover and click never open its panel); with_item(title,
|
|
7443
|
+
href:) a top-level link (with_link is the shorthand).'
|
|
7426
7444
|
setter_args:
|
|
7427
7445
|
item: 1
|
|
7428
7446
|
yieldless:
|
|
@@ -7485,7 +7503,9 @@ components:
|
|
|
7485
7503
|
- 'Panel content is poetry_navigation_menu_link entries (active: marks the current
|
|
7486
7504
|
page) - never buttons; navigation navigates.'
|
|
7487
7505
|
- 'This is a DISCLOSURE bar: Tab moves through it normally and nothing traps -
|
|
7488
|
-
do not wire menu/menuitem roles.
|
|
7506
|
+
do not wire menu/menuitem roles. Keys: ArrowLeft/ArrowRight step between triggers
|
|
7507
|
+
and links, ArrowDown opens the focused trigger''s panel (focus stays on the
|
|
7508
|
+
trigger; Tab enters it), Escape closes and returns focus to the trigger.'
|
|
7489
7509
|
- 'Rich panels (title + description grids) want viewport: true - the shared morphing
|
|
7490
7510
|
card contains and sizes them; the default per-item mode suits simple link lists
|
|
7491
7511
|
(the top-nav block shows the viewport pattern).'
|
|
@@ -7513,6 +7533,9 @@ components:
|
|
|
7513
7533
|
condition: its panel is open (the controller writes both vocabularies)
|
|
7514
7534
|
- attr: data-closed
|
|
7515
7535
|
condition: its panel is closed (written after the first close)
|
|
7536
|
+
- attr: data-disabled
|
|
7537
|
+
condition: 'disabled: true - inert (native disabled rides along; hover and
|
|
7538
|
+
click never open the panel, the arrows step over it)'
|
|
7516
7539
|
- name: navigation-menu-content
|
|
7517
7540
|
description: One item's panel - presence-animated; in viewport mode it is adopted
|
|
7518
7541
|
into the shared viewport on first activation
|
|
@@ -7709,7 +7732,6 @@ components:
|
|
|
7709
7732
|
- wheel
|
|
7710
7733
|
actions:
|
|
7711
7734
|
- blur
|
|
7712
|
-
- focus
|
|
7713
7735
|
- hiddenChanged
|
|
7714
7736
|
- input
|
|
7715
7737
|
- keydown
|
|
@@ -7788,8 +7810,6 @@ components:
|
|
|
7788
7810
|
'on': keydown
|
|
7789
7811
|
- method: input
|
|
7790
7812
|
'on': input
|
|
7791
|
-
- method: focus
|
|
7792
|
-
'on': focus
|
|
7793
7813
|
- method: blur
|
|
7794
7814
|
'on': blur
|
|
7795
7815
|
- element: hidden
|
|
@@ -60,7 +60,7 @@ module Poetry
|
|
|
60
60
|
the last edit (unknown components/slots/variants/wiring, icon names,
|
|
61
61
|
enum values, typed-slot props, helper + setter arity, yield-less
|
|
62
62
|
blocks, setter keywords, required content blocks, required slots,
|
|
63
|
-
did-you-mean, `--json`;
|
|
63
|
+
did-you-mean, `--json`; `poetry:install` adds the `herb` gem it parses with). An edit
|
|
64
64
|
made after your last check is unverified markup - re-run it.
|
|
65
65
|
- Faster: the `poetry` MCP server (`.mcp.json`: command `bundle`, args
|
|
66
66
|
`["exec", "poetry-agent"]`, the poetry-agent gem) serves ten tools from the live registry
|
|
@@ -43,6 +43,12 @@ module Poetry
|
|
|
43
43
|
|
|
44
44
|
class_option :charts, type: :boolean, default: false,
|
|
45
45
|
desc: %(Also wire poetry-charts (requires gem "poetry-charts" in the bundle))
|
|
46
|
+
class_option :skip_bundle, type: :boolean, default: false,
|
|
47
|
+
desc: "Skip `bundle install` after adding the herb gem (poetry:check's parser)"
|
|
48
|
+
|
|
49
|
+
# A Gemfile line declaring herb, in any quoting, at any indentation
|
|
50
|
+
# (a `group :development do` block included).
|
|
51
|
+
HERB_GEM_LINE = /^\s*gem\s+["']herb["']/
|
|
46
52
|
|
|
47
53
|
# Install-time theme selection. Every themes/<name>.css fragment is
|
|
48
54
|
# a complete visual theme; the chosen one fills the style-default.css
|
|
@@ -253,6 +259,29 @@ module Poetry
|
|
|
253
259
|
JS
|
|
254
260
|
end
|
|
255
261
|
|
|
262
|
+
# poetry:check parses ERB with herb, which stays out of poetry's runtime
|
|
263
|
+
# dependencies on purpose (hosts never need it to render), so the
|
|
264
|
+
# install adds it to the development group - once, and never when the
|
|
265
|
+
# Gemfile already declares it anywhere. Then `bundle install`, unless
|
|
266
|
+
# --skip-bundle (the note says what is left to do).
|
|
267
|
+
# @api private
|
|
268
|
+
def add_herb_gem
|
|
269
|
+
gemfile = File.join(destination_root, "Gemfile")
|
|
270
|
+
return unless File.exist?(gemfile)
|
|
271
|
+
|
|
272
|
+
if File.read(gemfile).match?(HERB_GEM_LINE)
|
|
273
|
+
say_status :skip, "herb is already in the Gemfile (poetry:check's parser)", :cyan
|
|
274
|
+
return
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
gem "herb", group: :development, comment: "poetry:check parses ERB with herb (development only)"
|
|
278
|
+
if options[:skip_bundle]
|
|
279
|
+
say_status :note, "run `bundle install` to fetch herb before `bin/rails poetry:check`", :cyan
|
|
280
|
+
else
|
|
281
|
+
in_root { Bundler.with_unbundled_env { run "bundle install" } }
|
|
282
|
+
end
|
|
283
|
+
end
|
|
284
|
+
|
|
256
285
|
# The llms.txt / llms-full.txt agent docs are engine routes - without
|
|
257
286
|
# the mount they are unreachable (the fresh-app proof caught this).
|
|
258
287
|
# @api private
|
data/lib/poetry/ui/chat.rb
CHANGED
|
@@ -37,6 +37,11 @@ module Poetry
|
|
|
37
37
|
Script.new(&)
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
+
# Raised when a script is asked for what its shape cannot give -
|
|
41
|
+
# continuation frames from a turn that has no approval pause.
|
|
42
|
+
# Inherits the family base, so `rescue Poetry::Core::Error` covers it.
|
|
43
|
+
class Error < Poetry::Core::Error; end
|
|
44
|
+
|
|
40
45
|
# One rendered state of an assistant row mid-stream.
|
|
41
46
|
Frame = Struct.new(:parts, :sleep_ms, :version, keyword_init: true)
|
|
42
47
|
|
data/lib/poetry/ui/themes.rb
CHANGED
|
@@ -22,7 +22,7 @@ module Poetry
|
|
|
22
22
|
|
|
23
23
|
# The provenance line template for ported treatments,
|
|
24
24
|
# format-interpolated with the upstream style name.
|
|
25
|
-
PORTED = "ported from the source style-%s.css at pin shadcn@4.
|
|
25
|
+
PORTED = "ported from the source style-%s.css at pin shadcn@4.21.0 (7c9eaba1)"
|
|
26
26
|
|
|
27
27
|
# Per-theme DESIGN.md metadata: the typography pairing and the
|
|
28
28
|
# treatment provenance line.
|
data/lib/poetry/ui/version.rb
CHANGED
data/lib/tasks/poetry/check.rake
CHANGED
|
@@ -12,7 +12,8 @@ namespace :poetry do
|
|
|
12
12
|
# optional-parser posture as poetry:verify's template gate.
|
|
13
13
|
unless Poetry::Core::CSS::TemplateClasses.available?
|
|
14
14
|
abort "poetry:check: the herb gem is required to parse templates - " \
|
|
15
|
-
"
|
|
15
|
+
"`bin/rails g poetry:install` adds it to your development group " \
|
|
16
|
+
"(or add `gem \"herb\"` to the Gemfile yourself and bundle)"
|
|
16
17
|
end
|
|
17
18
|
|
|
18
19
|
# Default sweep: ERB through the template tier, app Ruby through the
|
data/themes/luma.css
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* poetry luma theme - upstream style-luma.css ported onto the
|
|
2
|
-
* cn-* layer (pinned clone
|
|
2
|
+
* cn-* layer (pinned clone 7c9eaba1, the shadcn@4.21.0 release). Same contract as default.css:
|
|
3
3
|
* imported layer(base); bare selectors while installs carry ONE theme;
|
|
4
4
|
* rule order per component = base < elements < variants < compounds;
|
|
5
5
|
* split-side, no-empty-rules and cross-component-last rules apply.
|
data/themes/lyra.css
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* poetry lyra theme - upstream style-lyra.css ported onto the
|
|
2
|
-
* cn-* layer (pinned clone
|
|
2
|
+
* cn-* layer (pinned clone 7c9eaba1, the shadcn@4.21.0 release). Same contract as default.css:
|
|
3
3
|
* imported layer(base); bare selectors while installs carry ONE theme;
|
|
4
4
|
* rule order per component = base < elements < variants < compounds;
|
|
5
5
|
* split-side, no-empty-rules and cross-component-last rules apply.
|
data/themes/maia.css
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* poetry maia theme - upstream style-maia.css ported onto the
|
|
2
|
-
* cn-* layer (pinned clone
|
|
2
|
+
* cn-* layer (pinned clone 7c9eaba1, the shadcn@4.21.0 release). Same contract as default.css:
|
|
3
3
|
* imported layer(base); bare selectors while installs carry ONE theme;
|
|
4
4
|
* rule order per component = base < elements < variants < compounds;
|
|
5
5
|
* split-side, no-empty-rules and cross-component-last rules apply.
|
data/themes/mira.css
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* poetry mira theme - upstream style-mira.css ported onto the
|
|
2
|
-
* cn-* layer (pinned clone
|
|
2
|
+
* cn-* layer (pinned clone 7c9eaba1, the shadcn@4.21.0 release). Same contract as default.css:
|
|
3
3
|
* imported layer(base); bare selectors while installs carry ONE theme;
|
|
4
4
|
* rule order per component = base < elements < variants < compounds;
|
|
5
5
|
* split-side, no-empty-rules and cross-component-last rules apply.
|
data/themes/nova.css
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* poetry nova theme - upstream style-nova.css ported onto the
|
|
2
|
-
* cn-* layer (pinned clone
|
|
2
|
+
* cn-* layer (pinned clone 7c9eaba1, the shadcn@4.21.0 release). Same contract as default.css:
|
|
3
3
|
* imported layer(base); bare selectors while installs carry ONE theme;
|
|
4
4
|
* rule order per component = base < elements < variants < compounds;
|
|
5
5
|
* split-side, no-empty-rules and cross-component-last rules apply.
|
data/themes/rhea.css
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* poetry rhea theme - upstream style-rhea.css ported onto the
|
|
2
|
-
* cn-* layer (pinned clone
|
|
2
|
+
* cn-* layer (pinned clone 7c9eaba1, the shadcn@4.21.0 release). Same contract as default.css:
|
|
3
3
|
* imported layer(base); bare selectors while installs carry ONE theme;
|
|
4
4
|
* rule order per component = base < elements < variants < compounds;
|
|
5
5
|
* split-side, no-empty-rules and cross-component-last rules apply.
|
data/themes/sera.css
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* poetry sera theme - upstream style-sera.css ported onto the
|
|
2
|
-
* cn-* layer (pinned clone
|
|
2
|
+
* cn-* layer (pinned clone 7c9eaba1, the shadcn@4.21.0 release). Same contract as default.css:
|
|
3
3
|
* imported layer(base); bare selectors while installs carry ONE theme;
|
|
4
4
|
* rule order per component = base < elements < variants < compounds;
|
|
5
5
|
* split-side, no-empty-rules and cross-component-last rules apply.
|
data/themes/vega.css
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* poetry vega theme - upstream style-vega.css ported onto the
|
|
2
|
-
* cn-* layer (pinned clone
|
|
2
|
+
* cn-* layer (pinned clone 7c9eaba1, the shadcn@4.21.0 release). Same contract as default.css:
|
|
3
3
|
* imported layer(base); bare selectors while installs carry ONE theme
|
|
4
4
|
* (the .style-<name> wrapper arrives with the docs switcher); rule order
|
|
5
5
|
* per component = base < elements < variants < compounds; split-side,
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: poetry-ui
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Matt Solt
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - '='
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 0.1.
|
|
18
|
+
version: 0.1.1
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - '='
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: 0.1.
|
|
25
|
+
version: 0.1.1
|
|
26
26
|
description: 'Poetry''s components for the AI-native UI component library: accessible,
|
|
27
27
|
themeable, agent-legible ViewComponents built entirely on poetry-core''s public
|
|
28
28
|
DSL.'
|