keystone_ui 0.25.0 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/components/keystone/ui/action_menu_item_component.rb +9 -2
- data/app/components/keystone/ui/checkbox_row_component.html.erb +8 -2
- data/app/components/keystone/ui/checkbox_row_component.rb +26 -2
- data/app/components/keystone/ui/radio_card_component.html.erb +8 -2
- data/app/components/keystone/ui/radio_card_component.rb +27 -2
- data/lib/keystone_ui/version.rb +1 -1
- data/the_local/agents/keystone_ui-develop.md +33 -15
- data/the_local/agents/keystone_ui-info.md +10 -3
- data/the_local/agents/keystone_ui-install.md +3 -2
- data/the_local/interface.yml +1 -0
- 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: 77e17961bce047a1477df49c98660ff0484456e5add3eb78a59b67735296d91b
|
|
4
|
+
data.tar.gz: 75fa1c3b979a7490ea47423b5b5d64a075648ff203a9554af170a1dfc06865bf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5f1b133c91668e4fa4886c15f664588d2cec6fd972dae84caf199fd891aeb22c6e48c534f8274b5a64669fb02cd6adb09890f51b75656bd9943a2252b30555a8
|
|
7
|
+
data.tar.gz: 34db47e65e4304e7224557d1b29dc1abe8803edd920e851f4a9f8f456d680b71b78710fe2966fd2253b756373a6ca01197dbd1881ec53fa28b730c72e7516a0b
|
|
@@ -5,16 +5,23 @@ module Keystone
|
|
|
5
5
|
class ActionMenuItemComponent < ViewComponent::Base
|
|
6
6
|
ITEM_CLASSES = "ks-menu-option block w-full text-left"
|
|
7
7
|
|
|
8
|
-
def initialize(label:, href:, method: :get)
|
|
8
|
+
def initialize(label:, href:, method: :get, confirm: nil)
|
|
9
9
|
@label = label
|
|
10
10
|
@href = href
|
|
11
11
|
@method = method.to_sym
|
|
12
|
+
@confirm = confirm
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def question
|
|
16
|
+
return @confirm if @confirm
|
|
17
|
+
|
|
18
|
+
"#{@label} this? This cannot be undone." if @method == :delete
|
|
12
19
|
end
|
|
13
20
|
|
|
14
21
|
def call
|
|
15
22
|
return link_to(@label, @href, class: ITEM_CLASSES) if @method == :get
|
|
16
23
|
|
|
17
|
-
button_to(@href, method: @method, class: ITEM_CLASSES) { @label }
|
|
24
|
+
button_to(@href, method: @method, class: ITEM_CLASSES, form: { data: { turbo_confirm: question }.compact }) { @label }
|
|
18
25
|
end
|
|
19
26
|
end
|
|
20
27
|
end
|
|
@@ -1,7 +1,13 @@
|
|
|
1
|
-
<label class="<%= row_classes %>"
|
|
1
|
+
<label class="<%= row_classes %> relative"<%= ' data-controller="stat-card-info"'.html_safe if info? %>>
|
|
2
2
|
<input type="checkbox" name="<%= name %>" value="<%= value %>" <%= "checked" if checked? %> class="<%= input_classes %>">
|
|
3
3
|
<span>
|
|
4
|
-
<span class="<%=
|
|
4
|
+
<span class="<%= header_classes %>">
|
|
5
|
+
<span class="<%= label_classes %>"><%= label %></span>
|
|
6
|
+
<% if info? %>
|
|
7
|
+
<button type="button" class="<%= info_button_classes %>" data-action="click->stat-card-info#toggle" aria-label="About <%= label %>"><%= info_icon.html_safe %></button>
|
|
8
|
+
<span class="<%= disclosure_classes %>" data-stat-card-info-target="panel"><%= info %></span>
|
|
9
|
+
<% end %>
|
|
10
|
+
</span>
|
|
5
11
|
<% if hint? %>
|
|
6
12
|
<span class="<%= hint_classes %>"><%= hint %></span>
|
|
7
13
|
<% end %>
|
|
@@ -7,14 +7,18 @@ module Keystone
|
|
|
7
7
|
INPUT_CLASSES = "ks-checkbox-row-input size-4 shrink-0"
|
|
8
8
|
LABEL_CLASSES = "ks-checkbox-row-label block text-sm"
|
|
9
9
|
HINT_CLASSES = "ks-checkbox-row-hint block text-sm"
|
|
10
|
+
HEADER_CLASSES = RadioCardComponent::HEADER_CLASSES
|
|
11
|
+
INFO_BUTTON_CLASSES = RadioCardComponent::INFO_BUTTON_CLASSES
|
|
12
|
+
DISCLOSURE_CLASSES = RadioCardComponent::DISCLOSURE_CLASSES
|
|
10
13
|
|
|
11
|
-
attr_reader :name, :value, :label, :hint
|
|
14
|
+
attr_reader :name, :value, :label, :hint, :info
|
|
12
15
|
|
|
13
|
-
def initialize(name:, value:, label:, hint: nil, checked: false)
|
|
16
|
+
def initialize(name:, value:, label:, hint: nil, info: nil, checked: false)
|
|
14
17
|
@name = name
|
|
15
18
|
@value = value
|
|
16
19
|
@label = label
|
|
17
20
|
@hint = hint
|
|
21
|
+
@info = info
|
|
18
22
|
@checked = checked
|
|
19
23
|
end
|
|
20
24
|
|
|
@@ -26,6 +30,22 @@ module Keystone
|
|
|
26
30
|
!@hint.nil?
|
|
27
31
|
end
|
|
28
32
|
|
|
33
|
+
def info?
|
|
34
|
+
!@info.nil?
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def info_button_classes
|
|
38
|
+
INFO_BUTTON_CLASSES
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def disclosure_classes
|
|
42
|
+
DISCLOSURE_CLASSES
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def info_icon
|
|
46
|
+
RadioCardComponent::INFO_ICON
|
|
47
|
+
end
|
|
48
|
+
|
|
29
49
|
def row_classes
|
|
30
50
|
ROW_CLASSES
|
|
31
51
|
end
|
|
@@ -34,6 +54,10 @@ module Keystone
|
|
|
34
54
|
INPUT_CLASSES
|
|
35
55
|
end
|
|
36
56
|
|
|
57
|
+
def header_classes
|
|
58
|
+
HEADER_CLASSES
|
|
59
|
+
end
|
|
60
|
+
|
|
37
61
|
def label_classes
|
|
38
62
|
LABEL_CLASSES
|
|
39
63
|
end
|
|
@@ -1,7 +1,13 @@
|
|
|
1
|
-
<label class="inline-block cursor-pointer"
|
|
1
|
+
<label class="inline-block cursor-pointer relative"<%= ' data-controller="stat-card-info"'.html_safe if info? %>>
|
|
2
2
|
<input type="radio" name="<%= name %>" value="<%= value %>" <%= "checked" if checked? %> class="peer sr-only">
|
|
3
3
|
<span class="<%= classes %>">
|
|
4
|
-
<span class="<%=
|
|
4
|
+
<span class="<%= header_classes %>">
|
|
5
|
+
<span class="<%= label_classes %>"><%= label %></span>
|
|
6
|
+
<% if info? %>
|
|
7
|
+
<button type="button" class="<%= info_button_classes %>" data-action="click->stat-card-info#toggle" aria-label="About <%= label %>"><%= info_icon.html_safe %></button>
|
|
8
|
+
<span class="<%= disclosure_classes %>" data-stat-card-info-target="panel"><%= info %></span>
|
|
9
|
+
<% end %>
|
|
10
|
+
</span>
|
|
5
11
|
<% if hint? %>
|
|
6
12
|
<span class="<%= hint_classes %>"><%= hint %></span>
|
|
7
13
|
<% end %>
|
|
@@ -5,16 +5,21 @@ module Keystone
|
|
|
5
5
|
class RadioCardComponent < ViewComponent::Base
|
|
6
6
|
BASE_CLASSES = "ks-radio-card inline-flex flex-col cursor-pointer transition"
|
|
7
7
|
HIGHLIGHT_CLASSES = "ks-radio-card-highlight"
|
|
8
|
+
HEADER_CLASSES = "ks-radio-card-header flex items-start justify-between"
|
|
8
9
|
LABEL_CLASSES = "ks-radio-card-label block"
|
|
9
10
|
HINT_CLASSES = "ks-radio-card-hint block text-sm"
|
|
11
|
+
INFO_BUTTON_CLASSES = "ks-radio-card-info peer shrink-0"
|
|
12
|
+
DISCLOSURE_CLASSES = "ks-radio-card-disclosure hidden peer-hover:block absolute inset-x-0 top-full z-10 text-sm"
|
|
13
|
+
INFO_ICON = Keystone::Ui::StatCardComponent::INFO_ICON
|
|
10
14
|
|
|
11
|
-
attr_reader :name, :value, :label, :hint
|
|
15
|
+
attr_reader :name, :value, :label, :hint, :info
|
|
12
16
|
|
|
13
|
-
def initialize(name:, value:, label:, hint: nil, checked: false)
|
|
17
|
+
def initialize(name:, value:, label:, hint: nil, info: nil, checked: false)
|
|
14
18
|
@name = name
|
|
15
19
|
@value = value
|
|
16
20
|
@label = label
|
|
17
21
|
@hint = hint
|
|
22
|
+
@info = info
|
|
18
23
|
@checked = checked
|
|
19
24
|
end
|
|
20
25
|
|
|
@@ -26,10 +31,30 @@ module Keystone
|
|
|
26
31
|
!@hint.nil?
|
|
27
32
|
end
|
|
28
33
|
|
|
34
|
+
def info?
|
|
35
|
+
!@info.nil?
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def info_button_classes
|
|
39
|
+
INFO_BUTTON_CLASSES
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def info_icon
|
|
43
|
+
INFO_ICON
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def disclosure_classes
|
|
47
|
+
DISCLOSURE_CLASSES
|
|
48
|
+
end
|
|
49
|
+
|
|
29
50
|
def classes
|
|
30
51
|
"#{BASE_CLASSES} #{HIGHLIGHT_CLASSES}"
|
|
31
52
|
end
|
|
32
53
|
|
|
54
|
+
def header_classes
|
|
55
|
+
HEADER_CLASSES
|
|
56
|
+
end
|
|
57
|
+
|
|
33
58
|
def label_classes
|
|
34
59
|
LABEL_CLASSES
|
|
35
60
|
end
|
data/lib/keystone_ui/version.rb
CHANGED
|
@@ -120,12 +120,15 @@ outer element. See Conventions before using it.
|
|
|
120
120
|
- `ui_action_menu` — no keywords, takes a block. An ellipsis (⋯) button that
|
|
121
121
|
opens a dropdown of actions, shown at every screen size. Fill the block with
|
|
122
122
|
`ui_action_menu_item` calls.
|
|
123
|
-
- `ui_action_menu_item(label:, href:, method: :get)` — one entry
|
|
124
|
-
menu. With `method: :get` it is a link to `href`. Any other
|
|
125
|
-
`:post`, `:patch` or `:delete`, renders a button inside its
|
|
126
|
-
that sends that method to `href`, so never place such an item
|
|
127
|
-
`ui_form` block, since a form cannot contain another form.
|
|
128
|
-
|
|
123
|
+
- `ui_action_menu_item(label:, href:, method: :get, confirm: nil)` — one entry
|
|
124
|
+
in an action menu. With `method: :get` it is a link to `href`. Any other
|
|
125
|
+
method, such as `:post`, `:patch` or `:delete`, renders a button inside its
|
|
126
|
+
own small form that sends that method to `href`, so never place such an item
|
|
127
|
+
inside a `ui_form` block, since a form cannot contain another form.
|
|
128
|
+
`confirm:` is a question Turbo asks before the item sends. With no
|
|
129
|
+
`confirm:`, a `method: :delete` item asks "<label> this? This cannot be
|
|
130
|
+
undone.", and every other method sends without asking. A `method: :get` item
|
|
131
|
+
is a plain link and ignores `confirm:`.
|
|
129
132
|
- `ui_mobile_actions` — no keywords, takes a block. An ellipsis dropdown for
|
|
130
133
|
mobile actions; the block holds the menu items. Hidden above `lg:`. Use
|
|
131
134
|
`ui_action_menu` instead when the actions must also be reachable on desktop.
|
|
@@ -175,13 +178,24 @@ outer element. See Conventions before using it.
|
|
|
175
178
|
enclosing form to be multipart.
|
|
176
179
|
- `ui_color_picker(name:, value: "#000000", label: nil)` — a swatch that opens a
|
|
177
180
|
hue/saturation panel and writes the hex into a hidden input named `name`.
|
|
178
|
-
- `ui_radio_card(name:, value:, label:, hint: nil, checked: false)`
|
|
179
|
-
selectable card backed by a real radio input; selection styling is pure
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
181
|
+
- `ui_radio_card(name:, value:, label:, hint: nil, info: nil, checked: false)`
|
|
182
|
+
— a selectable card backed by a real radio input; selection styling is pure
|
|
183
|
+
CSS. `hint:` is a line of text always shown under the label. `info:` is
|
|
184
|
+
longer text about the option, kept hidden: passing it adds an info button on
|
|
185
|
+
the row with the label, named "About <label>" for screen readers, and the
|
|
186
|
+
text shows in a panel floating below the card while the button is hovered,
|
|
187
|
+
and tapping the button toggles it. With no `info:` the card has no info
|
|
188
|
+
button.
|
|
189
|
+
- `ui_checkbox_row(name:, value:, label:, hint: nil, info: nil, checked: false)`
|
|
190
|
+
— a real checkbox with its label and optional hint inside one `<label>`, so a
|
|
191
|
+
tap anywhere on the row toggles the box. A checked row submits `value` under
|
|
183
192
|
`name`; give several rows the same array name, e.g. `"shown[]"`, to submit the
|
|
184
|
-
checked values as a list. An unchecked row submits nothing.
|
|
193
|
+
checked values as a list. An unchecked row submits nothing. `hint:` is a line
|
|
194
|
+
of text always shown under the label. `info:` works as it does on
|
|
195
|
+
`ui_radio_card`: passing it adds an info button on the line with the label,
|
|
196
|
+
named "About <label>" for screen readers, and the text shows in a panel
|
|
197
|
+
floating below the row while the button is hovered, and tapping the button
|
|
198
|
+
toggles it. With no `info:` the row has no info button.
|
|
185
199
|
- `ui_option_card(name:, value:, selected: false, input_data: {}, label_data: {})`
|
|
186
200
|
— takes a block. A radio whose visible body is whatever the block renders.
|
|
187
201
|
`input_data:`/`label_data:` become `data-*` attributes on the input and label.
|
|
@@ -378,12 +392,16 @@ outer element. See Conventions before using it.
|
|
|
378
392
|
To show the arithmetic behind a figure, put `ui_calculation` under it rather
|
|
379
393
|
than a hand-built list. Which lines and groups to show is the app's own
|
|
380
394
|
calculation, so ask the developer which steps a reader needs to see.
|
|
395
|
+
On a radio card or a checkbox row, text every reader needs to choose goes in `hint:` and
|
|
396
|
+
text only some will want goes in `info:`. Which is which is the app's own
|
|
397
|
+
wording, so ask the developer rather than pick.
|
|
381
398
|
Put the actions on a record, such as Edit and Delete, in an action menu
|
|
382
399
|
rather than in a row of buttons: `menu:` on the `ui_section` that shows the
|
|
383
400
|
record, `table.actions` for a table row, or `ui_action_menu` anywhere else.
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
401
|
+
A delete item asks for confirmation on its own, so pass `confirm:` only
|
|
402
|
+
when the developer wants different wording. A `:post`, `:patch` or `:put`
|
|
403
|
+
item sends without asking, so ask the developer whether that action needs
|
|
404
|
+
a question, and pass it as `confirm:` if it does.
|
|
387
405
|
|
|
388
406
|
6. For a table, decide how columns are declared. Use `{ key: "Label" }` hashes
|
|
389
407
|
when every column is plain. Switch the whole set to `Keystone::Ui::Column`
|
|
@@ -78,9 +78,16 @@ holds the catalog.
|
|
|
78
78
|
of actions, shown at every screen size. The mobile action menu is the one
|
|
79
79
|
hidden from `lg:` up. Each action is a label, an address and an HTTP method.
|
|
80
80
|
A plain visit renders as a link. Any other method renders as a button that
|
|
81
|
-
sends that method, so an action that changes data is never a bare link.
|
|
82
|
-
|
|
81
|
+
sends that method, so an action that changes data is never a bare link. An
|
|
82
|
+
action can carry a question that Turbo asks before it runs. A delete asks
|
|
83
|
+
"<label> this? This cannot be undone." unless it is given its own question,
|
|
84
|
+
and other actions ask nothing unless given one. A data table puts each row's actions in one action menu at the end of the row,
|
|
83
85
|
and a section can carry an action menu in its header beside its title.
|
|
86
|
+
- **Info panels.** A stat card, a radio card and a checkbox row can each carry
|
|
87
|
+
extra text about themselves. Given that text, the piece shows an info button,
|
|
88
|
+
and the text stays hidden until the button is hovered or tapped. A piece
|
|
89
|
+
given no such text shows no button. On a radio card and a checkbox row the
|
|
90
|
+
button sits on the line with the label.
|
|
84
91
|
- **Options are symbols, and each component accepts its own set.** Appearance is
|
|
85
92
|
chosen by name — `variant:`, `size:`, `type:`, `padding:`, `spacing:`,
|
|
86
93
|
`max_width:`, `radius:` — on a size scale (`:sm` … `:xl`) or a short list of
|
|
@@ -139,7 +146,7 @@ holds the catalog.
|
|
|
139
146
|
at boot where the component files are.
|
|
140
147
|
- **Interactivity is Stimulus.** Dropdowns, modals, dismissible alerts, file
|
|
141
148
|
uploads, the color picker, the multi-select, tab switchers, accordions, the
|
|
142
|
-
swipe deck, column pickers,
|
|
149
|
+
swipe deck, column pickers, info panels, line charts, clipboard copy
|
|
143
150
|
and the theme toggle ship with the gem as Stimulus controllers registered once
|
|
144
151
|
at install. A host writes no JavaScript to use them. Components that post
|
|
145
152
|
somewhere, such as the column picker and the pipeline, post to endpoints the
|
|
@@ -215,8 +215,9 @@ built on ViewComponent; hook it in before building any screen with those helpers
|
|
|
215
215
|
A page that passes no Back link goes back to the trail's last link. A page
|
|
216
216
|
that passes its own trail or Back link keeps it. With no supplier, or a
|
|
217
217
|
`nil` return, the page shows its Back link. Return `nil`, not an empty
|
|
218
|
-
array, for a page with no trail
|
|
219
|
-
|
|
218
|
+
array, for a page with no trail. An empty array replaces the page's Back
|
|
219
|
+
link with breadcrumbs holding only its title, and on a page that passes
|
|
220
|
+
no Back link it raises `KeystoneUi::MissingBackLink`.
|
|
220
221
|
- Every form and show page must end up with a Back link. A page that passes
|
|
221
222
|
no Back link and no trail, and gets no trail from the supplier, raises
|
|
222
223
|
`KeystoneUi::MissingBackLink` naming the page's title when it renders.
|
data/the_local/interface.yml
CHANGED
|
@@ -128,6 +128,7 @@ sources:
|
|
|
128
128
|
- app/components/keystone/ui/theme_toggle_component.rb
|
|
129
129
|
- app/components/keystone/ui/progress_component.rb
|
|
130
130
|
- app/components/keystone/ui/radio_card_component.rb
|
|
131
|
+
- app/components/keystone/ui/radio_card_component.html.erb
|
|
131
132
|
- app/components/keystone/ui/section_component.rb
|
|
132
133
|
- app/components/keystone/ui/section_component.html.erb
|
|
133
134
|
- app/components/keystone/ui/select_component.rb
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: keystone_ui
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.27.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tyler Schneider
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - ">="
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 0.
|
|
18
|
+
version: 0.8.0
|
|
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.
|
|
25
|
+
version: 0.8.0
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: view_component
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|