keystone_ui 0.31.0 → 0.33.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a6c7e18e911657e41ed1a4eff2133400015bd7a58e0c437f6886d219173f01fa
4
- data.tar.gz: 91b2f652bb7313d9cda361e126e969d06b64827e80118888a73cce3840471f68
3
+ metadata.gz: 599c6b4269b4ca049a5aefe106cb71dc6205554c49fb6e72824f25cc3b6f2597
4
+ data.tar.gz: 390d82ea8082927248351ba74796fde3a05afe4994b151c79169e0cb190ecacd
5
5
  SHA512:
6
- metadata.gz: 466ea8fbb32ed4683db9537a52d7ba41d667f79dfa52aec27aaab85f5fc14b872fcc03b7d880136936133685fdc1af5f839aa4392c5ba698af62694e4a5832b0
7
- data.tar.gz: 435630df203142fa669f0d93333e6b2637b2d4ec2d25b6e8fa1a7aa00e54ba5fdace3a3416905c144f706f18373ad78b8b11c067f5d1a62ee6453655358b4b77
6
+ metadata.gz: 2b44fd40afcc3d275dab96ab0401f2748a5555d5e38eb319af16d998454e30f094d9e799603658b0597b7a0e8688a9a8d864aa2e170c3b750d5351a37db123d5
7
+ data.tar.gz: 65064fb15715bcebbe95efadb89b2a395d06889b6d4962467faeac520df18f88083acd7f5d23ffe8c6057f9434916906861a4c3f02515ae4306cf545bf9eba23
@@ -1,3 +1,6 @@
1
+ <% if column_picker %>
2
+ <%= render column_picker %>
3
+ <% end %>
1
4
  <div class="<%= Keystone::Ui::DataTableComponent::WRAPPER_CLASSES %>">
2
5
  <table class="relative min-w-full divide-y divide-gray-300 dark:divide-white/15">
3
6
  <thead class="<%= Keystone::Ui::DataTableComponent::HEAD_CLASSES %>">
@@ -6,10 +6,10 @@ module Keystone
6
6
  EMPTY_CELL_CLASSES = "ks-table-cell-middle text-sm"
7
7
  BODY_CLASSES = "ks-table-body"
8
8
  HEAD_CLASSES = "ks-table-head"
9
- WRAPPER_CLASSES = "ks-table overflow-hidden"
9
+ WRAPPER_CLASSES = "ks-table overflow-x-auto"
10
10
  HEADER_CLASSES_FIRST = "ks-table-header ks-table-header-first text-left text-sm"
11
11
  HEADER_CLASSES_MIDDLE = "ks-table-header ks-table-header-middle text-left text-sm"
12
- HEADER_CLASSES_LAST = "ks-table-header-last"
12
+ HEADER_CLASSES_LAST = "ks-table-header ks-table-header-last text-right text-sm"
13
13
 
14
14
  ROW_CLASSES_FIRST = "ks-table-cell-first text-sm whitespace-nowrap"
15
15
  ROW_CLASSES_MIDDLE = "ks-table-cell-middle text-sm whitespace-nowrap"
@@ -26,11 +26,12 @@ module Keystone
26
26
  SORT_DESC_ICON = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M10 3a.75.75 0 0 1 .75.75v10.638l3.96-4.158a.75.75 0 1 1 1.08 1.04l-5.25 5.5a.75.75 0 0 1-1.08 0l-5.25-5.5a.75.75 0 0 1 1.08-1.04l3.96 4.158V3.75A.75.75 0 0 1 10 3Z" clip-rule="evenodd" /></svg>'
27
27
  SORT_NEUTRAL_ICON = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M10 3a.75.75 0 0 1 .55.24l3.25 3.5a.75.75 0 1 1-1.1 1.02L10 4.852 7.3 7.76a.75.75 0 0 1-1.1-1.02l3.25-3.5A.75.75 0 0 1 10 3Zm-3.76 9.2a.75.75 0 0 1 1.06.04l2.7 2.908 2.7-2.908a.75.75 0 1 1 1.1 1.02l-3.25 3.5a.75.75 0 0 1-1.1 0l-3.25-3.5a.75.75 0 0 1 .04-1.06Z" clip-rule="evenodd" /></svg>'
28
28
 
29
- def initialize(items:, columns:, empty_message: nil, sort: nil, sort_direction: nil, sort_url: nil, hidden_columns: [])
29
+ def initialize(items:, columns:, empty_message: nil, sort: nil, sort_direction: nil, sort_url: nil, hidden_columns: [], key: nil)
30
30
  @items = items.to_a
31
- all_columns = columns.map { |col| normalize_column(col) }
32
- hidden_keys = Array(hidden_columns).map(&:to_sym).to_set
33
- @columns = all_columns.reject { |col| col.hideable? && hidden_keys.include?(col.key) }
31
+ @all_columns = columns.map { |col| normalize_column(col) }
32
+ @hidden_columns = hidden_columns
33
+ @columns = visible_columns(hidden_columns)
34
+ @key = key
34
35
  @empty_message = empty_message
35
36
  @sort = sort&.to_sym
36
37
  @sort_direction = sort_direction&.to_sym
@@ -41,6 +42,7 @@ module Keystone
41
42
 
42
43
  def before_render
43
44
  content
45
+ apply_saved_layout if @key
44
46
  end
45
47
 
46
48
  def link(column_key, &block)
@@ -55,6 +57,12 @@ module Keystone
55
57
  !!@actions_block
56
58
  end
57
59
 
60
+ def column_picker
61
+ return unless @save_url
62
+
63
+ @column_picker ||= ColumnPickerComponent.new(columns: @all_columns, hidden_columns: @hidden_columns, save_url: @save_url)
64
+ end
65
+
58
66
  def column_keys
59
67
  @column_keys ||= @columns.map(&:key)
60
68
  end
@@ -134,6 +142,20 @@ module Keystone
134
142
 
135
143
  private
136
144
 
145
+ def apply_saved_layout
146
+ saved = KeystoneUi.configuration.supplied_preference(helpers, @key)
147
+ return unless saved
148
+
149
+ @hidden_columns = saved[:value]["hidden_columns"]
150
+ @columns = visible_columns(@hidden_columns)
151
+ @save_url = saved[:save_url]
152
+ end
153
+
154
+ def visible_columns(hidden_columns)
155
+ hidden_keys = Array(hidden_columns).map(&:to_sym).to_set
156
+ @all_columns.reject { |col| col.hideable? && hidden_keys.include?(col.key) }
157
+ end
158
+
137
159
  def visual_column_count
138
160
  @columns.length + (actions? ? 1 : 0)
139
161
  end
@@ -0,0 +1 @@
1
+ <span class="<%= classes %>"><%= text %></span>
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Keystone
4
+ module Ui
5
+ class FigureComponent < ViewComponent::Base
6
+ TONES = {
7
+ neutral: nil,
8
+ success: "ks-tone-success",
9
+ danger: "ks-tone-danger"
10
+ }.freeze
11
+
12
+ def initialize(text:, tone: :neutral)
13
+ @text = text
14
+ @tone = tone
15
+ end
16
+
17
+ attr_reader :text
18
+
19
+ def classes
20
+ [ "ks-figure", TONES.fetch(@tone) ].compact.join(" ")
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,4 +1,4 @@
1
- <span class="inline-flex" data-controller="info" data-action="click@window->info#hide scroll@window->info#close">
1
+ <span class="<%= wrapper_classes %>" data-controller="info" data-action="click@window->info#hide scroll@window->info#close">
2
2
  <button type="button" class="<%= button_classes %>" data-info-target="button" data-action="mouseenter->info#peek mouseleave->info#unpeek click->info#toggle" aria-label="More about this"><%= icon.html_safe %></button>
3
3
  <span class="<%= summary_classes %>" data-info-target="summary"><%= summary %></span>
4
4
  <% if content? %>
@@ -14,6 +14,12 @@ module Keystone
14
14
 
15
15
  attr_reader :summary
16
16
 
17
+ WRAPPER_CLASSES = "inline-flex align-middle"
18
+
19
+ def wrapper_classes
20
+ WRAPPER_CLASSES
21
+ end
22
+
17
23
  def summary_classes
18
24
  SUMMARY_CLASSES
19
25
  end
@@ -229,6 +229,10 @@ module KeystoneUiHelper
229
229
  render Keystone::Ui::CalculationComponent.new(**args)
230
230
  end
231
231
 
232
+ def ui_figure(**args)
233
+ render Keystone::Ui::FigureComponent.new(**args)
234
+ end
235
+
232
236
  def ui_info(**args, &block)
233
237
  render(Keystone::Ui::InfoComponent.new(**args), &block)
234
238
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module KeystoneUi
4
4
  class Configuration
5
- attr_accessor :accent, :surface, :theme_mode_supplier, :look_supplier, :trail_supplier
5
+ attr_accessor :accent, :surface, :theme_mode_supplier, :look_supplier, :trail_supplier, :preference_supplier
6
6
  attr_reader :tailwind_imports, :tailwind_sources, :looks, :default_look
7
7
 
8
8
  def initialize
@@ -33,6 +33,10 @@ module KeystoneUi
33
33
  def supplied_trail(view)
34
34
  trail_supplier&.call(view)
35
35
  end
36
+
37
+ def supplied_preference(view, key)
38
+ preference_supplier&.call(view, key)
39
+ end
36
40
  end
37
41
 
38
42
  def self.configuration
@@ -14,6 +14,7 @@ module Keystone
14
14
  Keystone::Ui::LineChartComponent,
15
15
  Keystone::Ui::CtaBannerComponent,
16
16
  Keystone::Ui::FeatureGridComponent,
17
+ Keystone::Ui::FigureComponent,
17
18
  Keystone::Ui::HeroComponent,
18
19
  Keystone::Ui::ModalComponent,
19
20
  Keystone::Ui::SelectComponent,
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module KeystoneUi
4
- VERSION = "0.31.0"
4
+ VERSION = "0.33.0"
5
5
  end
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: keystone_ui-develop
3
- description: Use PROACTIVELY for building or editing screens in a Rails app that has Keystone UI — pages, forms, tables, navigation, action menus for a record's Edit and Delete, dashboards, charts, marketing sections, a light/dark theme switch — MUST BE USED instead of hand-writing ERB and Tailwind for UI.
3
+ description: Use PROACTIVELY for building or editing screens in a Rails app that has Keystone UI — pages, forms, tables, navigation, action menus for a record's Edit and Delete, dashboards, charts, amounts shown in green or red as a gain or loss, marketing sections, a light/dark theme switch — MUST BE USED instead of hand-writing ERB and Tailwind for UI.
4
4
  tools: Read, Write, Edit, Grep
5
5
  scope: UI — pages, forms, tables, navigation, dashboards
6
6
  ---
@@ -207,19 +207,29 @@ outer element. See Conventions before using it.
207
207
 
208
208
  ### Tables
209
209
 
210
- - `ui_data_table(items:, columns:, empty_message: nil, sort: nil, sort_direction: nil, sort_url: nil, hidden_columns: [])`
210
+ - `ui_data_table(items:, columns:, empty_message: nil, sort: nil, sort_direction: nil, sort_url: nil, hidden_columns: [], key: nil)`
211
211
  — takes a block yielding the table. `items:` are records or hashes; each cell
212
212
  value is read by calling the column key on the item, falling back to `item[key]`.
213
213
  `columns:` accepts plain `{ key: "Label" }` hashes or `Keystone::Ui::Column`
214
214
  objects. In the block, `table.link(:column_key) { |item| url }` turns that
215
215
  column's cells into links and `table.actions { |item| ... }` appends a
216
- right-aligned actions column. Each row's actions render inside an action
216
+ right-aligned actions column. With no actions column, the last data
217
+ column's header and cells are both right-aligned, so put the column of
218
+ amounts last to line them up under their header. Each row's actions render inside an action
217
219
  menu, so the `actions` block holds `ui_action_menu_item` calls and nothing
218
220
  else, never buttons or bare links. Sorting requires all three of `sort:` (the
219
221
  current column key), `sort_direction:` (`:asc`/`:desc`), and `sort_url:` (a
220
222
  lambda taking `(column_key, direction)` and returning a URL); headers then
221
223
  render as links that flip direction. `hidden_columns:` drops columns
222
- server-side and only affects columns declared `hideable: true`.
224
+ server-side and only affects columns declared `hideable: true`. `key:` (a
225
+ symbol or string) names the table so it looks up a saved layout through the
226
+ app's preference supplier. When the supplier returns a saved value for the
227
+ key, the hideable columns listed under its `"hidden_columns"` replace the
228
+ ones passed in `hidden_columns:`, and when it also returns a save address the
229
+ table renders a "Columns" menu above itself that saves to it. When the
230
+ supplier returns nothing, when no supplier is set, or when no `key:` is
231
+ passed, the table renders from `hidden_columns:` with no Columns menu, so
232
+ `hidden_columns:` is the table's default layout.
223
233
  - `Keystone::Ui::Column.new(key, header_text, mobile_hidden: false, sortable: false, hideable: false)`
224
234
  — a column with per-column options, for when a `{ key: "Label" }` hash is not
225
235
  enough. `mobile_hidden:` hides the column below `sm:`; `sortable:` opts it into
@@ -228,7 +238,9 @@ outer element. See Conventions before using it.
228
238
  dropdown of checkboxes for every `hideable` column. Pass it the same columns
229
239
  and hidden keys as the table. On toggle it sends `PATCH save_url` with JSON
230
240
  `{ "hidden_columns": ["key", ...] }` and a `X-CSRF-Token` header, then reloads
231
- the page. The app must provide that endpoint and persist the list.
241
+ the page. The app must provide that endpoint and persist the list. A table
242
+ given `key:` renders its own Columns menu when the supplier gives a save
243
+ address, so never add `ui_column_picker` beside such a table.
232
244
 
233
245
  ### Content and status
234
246
 
@@ -238,6 +250,13 @@ outer element. See Conventions before using it.
238
250
  only to the button form.
239
251
  - `ui_badge(label:, variant: :neutral, class: nil)` — a pill. `variant:`
240
252
  `:neutral` `:success` `:danger` `:warning` `:info`.
253
+ - `ui_figure(text:, tone: :neutral)` — no block. One figure, such as an amount,
254
+ as inline text with no pill or box around it. `tone:` `:neutral` prints it in
255
+ the surrounding text colour, `:success` in green and `:danger` in red; any
256
+ other symbol raises `KeyError`. `text:` is printed as given, so format
257
+ numbers, currency and any minus sign before passing it. Its output can be
258
+ passed anywhere a string is shown, such as a `ui_data_table` cell value or
259
+ column label.
241
260
  - `ui_alert(message:, type: :info, title: nil, dismissible: false, class: nil)` —
242
261
  a banner.
243
262
  `type:` `:info` `:success` `:warning` `:error`. `dismissible: true` adds a
@@ -270,7 +289,8 @@ outer element. See Conventions before using it.
270
289
  numbers and currency before passing them. Place it directly under the figure
271
290
  it explains, such as a `ui_stat_card`.
272
291
  - `ui_info(summary:)` — an info button, named "More about this" for screen
273
- readers, placed inline beside the thing it explains. `summary:` is a short
292
+ readers, placed inline beside the thing it explains, and sits level with the
293
+ middle of the text beside it. `summary:` is a short
274
294
  line of text shown in a floating panel while the button is hovered. The block
275
295
  is optional and holds the full detail. With a block, tapping or clicking the
276
296
  button toggles a second floating panel holding the block's content, and the
@@ -453,6 +473,13 @@ outer element. See Conventions before using it.
453
473
  text with no columns and no separate total, the app's keystone_ui-styles
454
474
  version does not define the `ks-breakdown` classes, so stop and hand that
455
475
  part to `keystone_ui-install` as well, and add no classes to fix it.
476
+ To show an amount as a gain or a loss, use `ui_figure` with `tone:` rather
477
+ than a `ui_badge` or a colour class. Which amounts are coloured, and whether
478
+ a value counts as a gain or a loss, is the app's own rule, so ask the
479
+ developer rather than pick. If a figure with `:success` or `:danger` shows in
480
+ the plain text colour, the app's keystone_ui-styles version does not define
481
+ the `ks-figure` and `ks-tone-*` classes, so stop and hand that part to
482
+ `keystone_ui-install`, and add no classes to fix it.
456
483
  A field whose value must be one of a fixed list is a `:select` with
457
484
  `options:`, and a field that accepts any text and offers common values is a
458
485
  text field with `suggestions:`. Which one a field is, and which values it
@@ -485,6 +512,15 @@ outer element. See Conventions before using it.
485
512
  objects as soon as one column needs `mobile_hidden:`, `sortable:`, or
486
513
  `hideable:`.
487
514
 
515
+ For a table whose hideable columns a user should be able to choose and keep,
516
+ check whether the app's Keystone UI initializer sets a
517
+ `preference_supplier`. If it does, pass `key:` and the default
518
+ `hidden_columns:`, and add no `ui_column_picker`. Which key names the table
519
+ and which columns it hides by default are the developer's choice, so ask
520
+ rather than pick. If the app sets no supplier, either use `ui_column_picker`
521
+ with an endpoint the app owns, as in step 7, or hand setting up a supplier to
522
+ `keystone_ui-install`, and ask the developer which.
523
+
488
524
  7. Wire up anything that posts back. Several helpers render controls whose
489
525
  endpoints the app must own — the column picker's save URL, the pipeline's box
490
526
  and link URLs, the swipe deck's outcome events, the modal's open trigger, the
@@ -15,7 +15,7 @@ library of view helpers built on ViewComponent. Screens are built from named
15
15
  pieces — page shells, sections, panels, grids, form fields, data tables,
16
16
  navigation bars, breadcrumbs, cards, stat tiles, charts, funnels, goal buckets, pipelines,
17
17
  banners, the calculation behind a figure, a breakdown of amounts and their
18
- total, an info button — instead of hand-written ERB and
18
+ total, a figure coloured as a gain or a loss, an info button — instead of hand-written ERB and
19
19
  Tailwind. Every class the UI renders lives inside the gem, in frozen constants,
20
20
  so the look is defined in one place.
21
21
 
@@ -47,7 +47,8 @@ shell also uses the page container.
47
47
  This local declares no commands. The two working surfaces belong elsewhere:
48
48
 
49
49
  - **Getting the gem into a host app** — adding it, wiring Tailwind, Stimulus and
50
- the theme attributes on the layout, setting the palette → **`keystone_ui-install`**.
50
+ the theme attributes on the layout, setting the palette, and the suppliers
51
+ for trails, themes, looks and saved table layouts → **`keystone_ui-install`**.
51
52
  - **Building UI with it** — which helper renders what, what keywords it takes,
52
53
  how helpers nest → **`keystone_ui-develop`**.
53
54
 
@@ -88,7 +89,8 @@ holds the catalog.
88
89
  extra text about themselves. Given that text, the piece shows an info button,
89
90
  and the text stays hidden until the button is hovered or tapped. A piece
90
91
  given no such text shows no button. On a radio card and a checkbox row the
91
- button sits on the line with the label.
92
+ button sits on the line with the label. Wherever it is placed, the button
93
+ sits level with the text beside it.
92
94
  - **Standalone info button.** The same info button can be placed on its own,
93
95
  beside anything. It takes a short summary, which is required, and shows it
94
96
  when the button is hovered. Given nothing more, a tap shows the summary too.
@@ -113,6 +115,25 @@ holds the catalog.
113
115
  of its own, so a breakdown looks right only with a keystone_ui-styles version
114
116
  that defines those classes. It has no button and no hidden state of
115
117
  its own, and it can be placed inside an info button's detail.
118
+ - **A toned figure is text.** A figure shows one amount inline, in plain text
119
+ or in the success or danger colour, so it reads as a gain or a loss without a
120
+ badge around it. The amount is passed as already-formatted text and shown as
121
+ written, and the tone is chosen by name. An unknown tone raises at render
122
+ time. The colours come from keystone_ui-styles, so a figure shows its tone
123
+ only with a keystone_ui-styles version that defines those classes.
124
+ - **The last table column is right-aligned.** In a data table with no actions
125
+ column, the last column's header is right-aligned like the cells beneath it,
126
+ so a figure or total placed in that header lines up with the figures below.
127
+ - **Saved table layouts.** A data table can be given a key naming it. A table
128
+ with a key asks the app, or another gem such as keystone_ui-preferences, for
129
+ the layout saved under that key for the request. A saved layout lists the
130
+ columns to hide, and only columns marked hideable can be hidden. When a
131
+ layout is saved, it replaces the columns the table hides by default. When
132
+ nothing is saved, the table hides the columns its own call names, so those
133
+ are its default layout. When the supplier also gives an address to save to,
134
+ a "Columns" menu appears above the table and saves the user's choice there.
135
+ A table with no key, or an app with no supplier, renders from its own call
136
+ alone. Setting up the supplier belongs to the install local.
116
137
  - **Suggestions.** A form field can carry a list of suggested values. The
117
138
  browser offers them while the field's text is typed, and the user can still
118
139
  enter a value that is not on the list. This applies to a field with a typed
@@ -126,7 +147,7 @@ holds the catalog.
126
147
  different symbols, and the develop local carries the real values. Most
127
148
  components raise on a symbol they do not know, so a wrong guess fails at
128
149
  render time.
129
- - **Figures are numbers.** Components that measure or compare values, such as
150
+ - **Measured values are numbers.** Components that measure or compare values, such as
130
151
  progress bars, funnels and buckets, do arithmetic on them. Pass a number, not
131
152
  a formatted string such as `"9,000"`. A bucket raises on one.
132
153
  - **A funnel has two shapes.** Both size each step against the first step and
@@ -198,5 +219,5 @@ holds the catalog.
198
219
  and the theme toggle ship with the gem as Stimulus controllers registered once
199
220
  at install. A host writes no JavaScript to use them. Components that post
200
221
  somewhere, such as the column picker and the pipeline, post to endpoints the
201
- host app owns.
222
+ host app or another gem owns.
202
223
  - Ruby >= 3.2. ViewComponent >= 2.0 and < 5.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: keystone_ui-install
3
- description: Use to hook Keystone UI into a project — adding the gem, running the install generator to wire Tailwind, the Stimulus controllers and the layout's theme attributes, and configuring the palette, the theme mode supplier, registered looks, the breadcrumb trail supplier and extra Tailwind imports and sources.
3
+ description: Use to hook Keystone UI into a project — adding the gem, running the install generator to wire Tailwind, the Stimulus controllers and the layout's theme attributes, and configuring the palette, the theme mode supplier, registered looks, the breadcrumb trail supplier, the saved table layout supplier and extra Tailwind imports and sources.
4
4
  tools: Bash, Read, Edit
5
5
  scope: UI — pages, forms, tables, navigation, dashboards
6
6
  ---
@@ -26,6 +26,8 @@ built on ViewComponent; hook it in before building any screen with those helpers
26
26
  `look_supplier` (which registered look a page gets),
27
27
  `trail_supplier` (a callable that supplies the breadcrumb trail for form and
28
28
  show pages that pass none, and their Back link when they pass none either),
29
+ `preference_supplier` (a callable that supplies the saved column layout of a
30
+ data table given a `key:`, and the address its Columns menu saves to),
29
31
  and the `tailwind_imports` and `tailwind_sources` lists (extra CSS files and
30
32
  scan paths added to the Tailwind build).
31
33
  - `keystone_theme_attributes` — a layout helper placed inside the `<html>` tag.
@@ -40,7 +42,7 @@ built on ViewComponent; hook it in before building any screen with those helpers
40
42
  ## How to use it
41
43
 
42
44
  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.9.0 or later with it.
45
+ host app. The gem brings ViewComponent and keystone_ui-styles 0.10.0 or later with it.
44
46
  Tailwind does not have to be initialized first, because the generator creates
45
47
  the stylesheet if it is missing.
46
48
 
@@ -153,7 +155,7 @@ built on ViewComponent; hook it in before building any screen with those helpers
153
155
  checkbox row, radio card, option card, file upload and colour picker read
154
156
  these variables. So do the data display components: stat card, chart card,
155
157
  card link, CTA banner, feature grid, hero, data table, code, accordion,
156
- disclosure, calculation, info button, breakdown, tab switcher, progress,
158
+ disclosure, calculation, info button, breakdown, figure, tab switcher, progress,
157
159
  funnel, bucket, pipeline and swipe deck.
158
160
  So do the navigation components: navbar, nav item, nav dropdown, bottom nav,
159
161
  mobile header and settings link. The desktop "Back" link and the breadcrumbs
@@ -179,6 +181,7 @@ built on ViewComponent; hook it in before building any screen with those helpers
179
181
  config.default_look = :compact
180
182
  config.look_supplier = ->(view) { view.current_user&.look }
181
183
  config.trail_supplier = ->(view) { view.breadcrumb_trail }
184
+ config.preference_supplier = ->(view, key) { TablePreferences.for(view.current_user, key) }
182
185
  config.tailwind_imports << "/absolute/path/to/extra.css"
183
186
  config.tailwind_sources << "/absolute/path/to/components/**/*.{erb,rb}"
184
187
  end
@@ -229,6 +232,24 @@ built on ViewComponent; hook it in before building any screen with those helpers
229
232
  writing the callable. If some form or show pages pass no `back_url:`, ask
230
233
  where their Back link should come from before enabling the supplier or
231
234
  leaving it out.
235
+ - `preference_supplier` — a callable that receives the view and a data
236
+ table's key and returns `{ value:, save_url: }`, or `nil` when nothing is
237
+ saved for that key. It is asked only for tables rendered with a `key:`. A
238
+ table with no `key:`, a supplier returning `nil`, or no supplier at all
239
+ renders with the hidden columns its own call passes.
240
+ - `value` must hold the hidden column names under the string key
241
+ `"hidden_columns"`, such as `{ "hidden_columns" => ["sku"] }`. A symbol key
242
+ is not read, and the table then hides no columns. Only columns marked
243
+ hideable are hidden.
244
+ - When `save_url` is present, the table shows a Columns menu above itself.
245
+ Toggling a column sends a `PATCH` to `save_url` with the JSON body
246
+ `{"hidden_columns": [...]}` and the page's CSRF token, then reloads the
247
+ page. The host must have a route and action at that address that store the
248
+ list for that key. With no `save_url`, the saved layout applies and no menu
249
+ is shown.
250
+ - A companion preferences gem may set this supplier for the app. Ask the
251
+ developer whether the app uses one, or which code stores each user's table
252
+ layouts, before writing the callable.
232
253
  - `tailwind_imports` and `tailwind_sources` — lists to append to, never
233
254
  assign. Each import becomes an `@import` line and each source becomes an
234
255
  `@source` line in `keystone_source.css` on the next boot. They are for
@@ -62,11 +62,13 @@ develop:
62
62
  - ui_disclosure
63
63
  - ui_calculation
64
64
  - ui_info
65
+ - ui_figure
65
66
  - ui_breakdown
66
67
  - ui_theme_toggle
67
68
  - Keystone::Ui::Column
68
69
 
69
70
  sources:
71
+ - app/components/keystone/ui/figure_component.rb
70
72
  - lib/generators/keystone/install_generator.rb
71
73
  - lib/keystone_ui/configuration.rb
72
74
  - lib/keystone_ui/missing_back_link.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.31.0
4
+ version: 0.33.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tyler Schneider
@@ -125,6 +125,8 @@ files:
125
125
  - app/components/keystone/ui/disclosure_component.rb
126
126
  - app/components/keystone/ui/feature_grid_component.html.erb
127
127
  - app/components/keystone/ui/feature_grid_component.rb
128
+ - app/components/keystone/ui/figure_component.html.erb
129
+ - app/components/keystone/ui/figure_component.rb
128
130
  - app/components/keystone/ui/file_upload_component.html.erb
129
131
  - app/components/keystone/ui/file_upload_component.rb
130
132
  - app/components/keystone/ui/form_component.html.erb