keystone_ui 0.26.0 → 0.28.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/checkbox_row_component.html.erb +8 -2
- data/app/components/keystone/ui/checkbox_row_component.rb +26 -2
- data/app/components/keystone/ui/form_field_component.html.erb +7 -0
- data/app/components/keystone/ui/form_field_component.rb +15 -1
- 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 +31 -8
- data/the_local/agents/keystone_ui-info.md +12 -1
- data/the_local/agents/keystone_ui-install.md +1 -1
- 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: 88ffa01b58c46bdab1ddcf7657b1b60e3caf4320519cb64e5bcf6dfc59e047c9
|
|
4
|
+
data.tar.gz: 151698597ec642c7a410e5835d4b66f3c5b17a1fc778c995f9b583d912e565df
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 97232de923802fef99483afbdfc76ecc8cac4a7220ed40e97aa4d19426fb885b0d5c012b587ec7e94cd980042fb27d70b99d832e332addd608e4d41645901618
|
|
7
|
+
data.tar.gz: 7b6cf8260919c664248a7246eda7d917e580d6d709737eb83b2d27d7e9e67e37c45fb4302061b8d824cf5e96bd20af403eb07e9f3c6c78f6e4571920f3d0ff6a
|
|
@@ -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
|
|
@@ -22,6 +22,13 @@
|
|
|
22
22
|
</select>
|
|
23
23
|
<% else %>
|
|
24
24
|
<%= tag.input(**input_options) %>
|
|
25
|
+
<% if suggestions? %>
|
|
26
|
+
<datalist id="<%= suggestions_id %>">
|
|
27
|
+
<% suggestions.each do |suggestion| %>
|
|
28
|
+
<option value="<%= suggestion %>"></option>
|
|
29
|
+
<% end %>
|
|
30
|
+
</datalist>
|
|
31
|
+
<% end %>
|
|
25
32
|
<% end %>
|
|
26
33
|
|
|
27
34
|
<% if hint? %>
|
|
@@ -11,7 +11,7 @@ module Keystone
|
|
|
11
11
|
CHECKBOX_CLASSES = "ks-checkbox"
|
|
12
12
|
CHECKBOX_WRAPPER_CLASSES = "ks-form-field-checkbox flex items-center"
|
|
13
13
|
|
|
14
|
-
def initialize(attribute:, label: nil, type: :text, required: false, hint: nil, placeholder: nil, min: nil, max: nil, step: nil, value: nil, options: [], errors: [], include_blank: nil, disabled: false)
|
|
14
|
+
def initialize(attribute:, label: nil, type: :text, required: false, hint: nil, placeholder: nil, min: nil, max: nil, step: nil, value: nil, options: [], errors: [], include_blank: nil, disabled: false, suggestions: [])
|
|
15
15
|
@attribute = attribute
|
|
16
16
|
@label = label
|
|
17
17
|
@type = type
|
|
@@ -26,6 +26,7 @@ module Keystone
|
|
|
26
26
|
@errors = Array(errors)
|
|
27
27
|
@include_blank = include_blank.to_s
|
|
28
28
|
@disabled = disabled
|
|
29
|
+
@suggestions = Array(suggestions)
|
|
29
30
|
end
|
|
30
31
|
|
|
31
32
|
def label_text
|
|
@@ -83,8 +84,21 @@ module Keystone
|
|
|
83
84
|
options[:max] = @max unless @max.nil?
|
|
84
85
|
options[:step] = @step unless @step.nil?
|
|
85
86
|
options[:disabled] = true if @disabled
|
|
87
|
+
options[:list] = suggestions_id if suggestions?
|
|
86
88
|
options
|
|
87
89
|
end
|
|
90
|
+
|
|
91
|
+
def suggestions?
|
|
92
|
+
@suggestions.any?
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def suggestions
|
|
96
|
+
@suggestions
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def suggestions_id
|
|
100
|
+
"#{@attribute.to_s.parameterize}-suggestions"
|
|
101
|
+
end
|
|
88
102
|
end
|
|
89
103
|
end
|
|
90
104
|
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
|
@@ -146,7 +146,7 @@ outer element. See Conventions before using it.
|
|
|
146
146
|
The `<form>` wrapper. `method:` may be `:patch`/`:put`/`:delete` and is
|
|
147
147
|
translated for Rails. Set `multipart: true` when the form contains a file
|
|
148
148
|
upload.
|
|
149
|
-
- `ui_form_field(attribute:, label: nil, type: :text, required: false, hint: nil, placeholder: nil, min: nil, max: nil, step: nil, value: nil, options: [], errors: [], include_blank: nil, disabled: false)`
|
|
149
|
+
- `ui_form_field(attribute:, label: nil, type: :text, required: false, hint: nil, placeholder: nil, min: nil, max: nil, step: nil, value: nil, options: [], errors: [], include_blank: nil, disabled: false, suggestions: [])`
|
|
150
150
|
— a labeled field with hint and error text. This is the default way to render
|
|
151
151
|
an input. `type:` `:text` `:number` `:email` `:password` `:date` `:textarea`
|
|
152
152
|
`:checkbox` `:select`. `attribute:` is used verbatim as the input's `name`, so
|
|
@@ -159,7 +159,12 @@ outer element. See Conventions before using it.
|
|
|
159
159
|
it. Never add your own empty choice to `options:` as well. A
|
|
160
160
|
`:checkbox` renders its label beside the box, submits `"0"` when unchecked and
|
|
161
161
|
`"1"` when checked, and pre-checks when `value:` is `"1"`. `errors:` is an
|
|
162
|
-
array of message strings.
|
|
162
|
+
array of message strings. `suggestions:` is an array of strings the browser
|
|
163
|
+
offers while the field's text is typed, and the user can still type a value
|
|
164
|
+
that is not in it. It applies to `:text`, `:number`, `:email`, `:password`
|
|
165
|
+
and `:date` fields, and a `:textarea`, `:checkbox` or `:select` ignores it.
|
|
166
|
+
The suggestion list's `id` is built from `attribute:`, so two fields with
|
|
167
|
+
suggestions on one screen need different `attribute:` values.
|
|
163
168
|
- `ui_input(name:, type: :text, value: nil, placeholder: nil, disabled: false, min: nil, max: nil, step: nil)`
|
|
164
169
|
— a bare styled input with no label. `type:` `:text` `:number` `:email`
|
|
165
170
|
`:password` `:date`.
|
|
@@ -178,13 +183,24 @@ outer element. See Conventions before using it.
|
|
|
178
183
|
enclosing form to be multipart.
|
|
179
184
|
- `ui_color_picker(name:, value: "#000000", label: nil)` — a swatch that opens a
|
|
180
185
|
hue/saturation panel and writes the hex into a hidden input named `name`.
|
|
181
|
-
- `ui_radio_card(name:, value:, label:, hint: nil, checked: false)`
|
|
182
|
-
selectable card backed by a real radio input; selection styling is pure
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
+
- `ui_radio_card(name:, value:, label:, hint: nil, info: nil, checked: false)`
|
|
187
|
+
— a selectable card backed by a real radio input; selection styling is pure
|
|
188
|
+
CSS. `hint:` is a line of text always shown under the label. `info:` is
|
|
189
|
+
longer text about the option, kept hidden: passing it adds an info button on
|
|
190
|
+
the row with the label, named "About <label>" for screen readers, and the
|
|
191
|
+
text shows in a panel floating below the card while the button is hovered,
|
|
192
|
+
and tapping the button toggles it. With no `info:` the card has no info
|
|
193
|
+
button.
|
|
194
|
+
- `ui_checkbox_row(name:, value:, label:, hint: nil, info: nil, checked: false)`
|
|
195
|
+
— a real checkbox with its label and optional hint inside one `<label>`, so a
|
|
196
|
+
tap anywhere on the row toggles the box. A checked row submits `value` under
|
|
186
197
|
`name`; give several rows the same array name, e.g. `"shown[]"`, to submit the
|
|
187
|
-
checked values as a list. An unchecked row submits nothing.
|
|
198
|
+
checked values as a list. An unchecked row submits nothing. `hint:` is a line
|
|
199
|
+
of text always shown under the label. `info:` works as it does on
|
|
200
|
+
`ui_radio_card`: passing it adds an info button on the line with the label,
|
|
201
|
+
named "About <label>" for screen readers, and the text shows in a panel
|
|
202
|
+
floating below the row while the button is hovered, and tapping the button
|
|
203
|
+
toggles it. With no `info:` the row has no info button.
|
|
188
204
|
- `ui_option_card(name:, value:, selected: false, input_data: {}, label_data: {})`
|
|
189
205
|
— takes a block. A radio whose visible body is whatever the block renders.
|
|
190
206
|
`input_data:`/`label_data:` become `data-*` attributes on the input and label.
|
|
@@ -381,6 +397,13 @@ outer element. See Conventions before using it.
|
|
|
381
397
|
To show the arithmetic behind a figure, put `ui_calculation` under it rather
|
|
382
398
|
than a hand-built list. Which lines and groups to show is the app's own
|
|
383
399
|
calculation, so ask the developer which steps a reader needs to see.
|
|
400
|
+
A field whose value must be one of a fixed list is a `:select` with
|
|
401
|
+
`options:`, and a field that accepts any text and offers common values is a
|
|
402
|
+
text field with `suggestions:`. Which one a field is, and which values it
|
|
403
|
+
suggests, is the app's own rule, so ask the developer rather than pick.
|
|
404
|
+
On a radio card or a checkbox row, text every reader needs to choose goes in `hint:` and
|
|
405
|
+
text only some will want goes in `info:`. Which is which is the app's own
|
|
406
|
+
wording, so ask the developer rather than pick.
|
|
384
407
|
Put the actions on a record, such as Edit and Delete, in an action menu
|
|
385
408
|
rather than in a row of buttons: `menu:` on the `ui_section` that shows the
|
|
386
409
|
record, `table.actions` for a table row, or `ui_action_menu` anywhere else.
|
|
@@ -83,6 +83,17 @@ holds the catalog.
|
|
|
83
83
|
"<label> this? This cannot be undone." unless it is given its own question,
|
|
84
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,
|
|
85
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.
|
|
91
|
+
- **Suggestions.** A form field can carry a list of suggested values. The
|
|
92
|
+
browser offers them while the field's text is typed, and the user can still
|
|
93
|
+
enter a value that is not on the list. This applies to a field with a typed
|
|
94
|
+
input, such as text, number, email, password or date. A textarea, select or
|
|
95
|
+
checkbox field ignores the list, and a field given no list offers nothing.
|
|
96
|
+
It needs no JavaScript.
|
|
86
97
|
- **Options are symbols, and each component accepts its own set.** Appearance is
|
|
87
98
|
chosen by name — `variant:`, `size:`, `type:`, `padding:`, `spacing:`,
|
|
88
99
|
`max_width:`, `radius:` — on a size scale (`:sm` … `:xl`) or a short list of
|
|
@@ -141,7 +152,7 @@ holds the catalog.
|
|
|
141
152
|
at boot where the component files are.
|
|
142
153
|
- **Interactivity is Stimulus.** Dropdowns, modals, dismissible alerts, file
|
|
143
154
|
uploads, the color picker, the multi-select, tab switchers, accordions, the
|
|
144
|
-
swipe deck, column pickers,
|
|
155
|
+
swipe deck, column pickers, info panels, line charts, clipboard copy
|
|
145
156
|
and the theme toggle ship with the gem as Stimulus controllers registered once
|
|
146
157
|
at install. A host writes no JavaScript to use them. Components that post
|
|
147
158
|
somewhere, such as the column picker and the pipeline, post to endpoints the
|
|
@@ -40,7 +40,7 @@ built on ViewComponent; hook it in before building any screen with those helpers
|
|
|
40
40
|
## How to use it
|
|
41
41
|
|
|
42
42
|
1. Confirm the prerequisites: Ruby >= 3.2 and **tailwindcss-rails v4+** in the
|
|
43
|
-
host app. The gem brings ViewComponent and keystone_ui-styles 0.
|
|
43
|
+
host app. The gem brings ViewComponent and keystone_ui-styles 0.8.0 or later with it.
|
|
44
44
|
Tailwind does not have to be initialized first, because the generator creates
|
|
45
45
|
the stylesheet if it is missing.
|
|
46
46
|
|
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.28.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
|