keystone_ui 0.38.0 → 0.39.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.
@@ -1,250 +1,106 @@
1
1
  ---
2
2
  name: keystone_ui-info
3
- description: Use to learn what Keystone UI offers — what the component system covers, its layout, color and theme model, and the vocabulary the install and develop locals assume.
3
+ description: Use to learn what keystone_ui offers — its UI components for pages, forms, tables, navigation and dashboards, its look, colour and theme model, and the vocabulary the install and develop locals assume.
4
4
  tools: Read
5
5
  scope: UI — pages, forms, tables, navigation, dashboards
6
6
  ---
7
7
 
8
- This local explains Keystone UI and sends you to the local that does the work.
9
- It changes nothing and gives no steps.
8
+ This local explains keystone_ui and says which local does the work. It changes
9
+ nothing and gives no steps.
10
10
 
11
- ## What Keystone UI is
11
+ ## What keystone_ui is
12
12
 
13
- Keystone UI is a Rails engine gem that supplies a host app's visual layer as a
14
- library of view helpers built on ViewComponent. Screens are built from named
15
- pieces — page shells, sections, panels, grids, form fields, data tables,
16
- navigation bars, breadcrumbs, cards, stat tiles, charts, funnels, goal buckets, pipelines,
17
- banners, the calculation behind a figure, a breakdown of amounts and their
18
- total, a figure coloured as a gain or a loss, an info button — instead of hand-written ERB and
19
- Tailwind. Every class the UI renders lives inside the gem, in frozen constants,
20
- so the look is defined in one place.
13
+ keystone_ui is a Rails engine gem that supplies a host app's UI as view helpers
14
+ built on ViewComponent. Screens are built from named pieces — page shells,
15
+ sections, panels, grids, forms and fields, data tables, navigation, cards, stat
16
+ tiles, charts, funnels, goal buckets, pipelines, breakdowns and info buttons —
17
+ instead of hand-written ERB and Tailwind. Every class the UI renders lives in the
18
+ gem, so two pages built from the same helpers cannot disagree about spacing,
19
+ colour or dark-mode treatment, and a change to a component reaches every page
20
+ that uses it.
21
21
 
22
22
  Reach for it whenever you build or change a screen in an app that has it
23
- installed. It exists to stop UI drift: two pages built from the same helpers
24
- cannot disagree about spacing, color or dark-mode treatment, and a change to a
25
- component updates every page that uses it. It is mobile-first — components ship
26
- separate mobile and desktop treatments (a bottom tab bar and mobile header on
27
- small screens, a full navigation bar from the `lg:` breakpoint up), because
28
- these apps are often viewed in a native webview. The form and show page shells
29
- follow the same split for going back: the mobile header carries the back arrow on
30
- small screens, and from `lg:` up the shell shows a "Back" link. Given a trail of
31
- earlier pages, the shell shows breadcrumbs under that "Back" link, ending with
32
- the page's own title. A page that passes no trail gets the one the app or
33
- another gem supplies for the request, if any, and a page that passes no back
34
- link goes back to that trail's last link. A trail or back link the page passes
35
- itself always wins. Supplying a trail is set up through the install local.
36
-
37
- A nav tab's own page has nowhere to go back to, and it says so by passing an
38
- empty trail. Such a page shows no "Back" link and no breadcrumbs, and its mobile
39
- header shows no back arrow. Every other form and show page must end up with a
40
- Back link. A page with no back link, no trail and no supplied trail raises
41
- `KeystoneUi::MissingBackLink` when it renders, and the message names the page's
42
- title and says an empty trail marks a nav tab's page. A trail with a link
43
- missing its label or its address raises `KeystoneUi::IncompleteTrail`, also
44
- naming the page. The "Back" link, the breadcrumbs and the form page's title
45
- appear at the top of the page container, inside its width and padding, so a
46
- page using either shell also uses the page container.
23
+ installed. It is mobile-first, because these apps are often shown in a native
24
+ web view: small screens get a mobile header and a bottom tab bar, and from the
25
+ `lg:` breakpoint up the app gets a full navigation bar or sidebar.
47
26
 
48
27
  ## Interface
49
28
 
50
- This local declares no commands. The two working surfaces belong elsewhere:
29
+ This local declares no commands. The working surfaces belong to the other two:
51
30
 
52
- - **Getting the gem into a host app** — adding it, wiring Tailwind, Stimulus and
53
- the theme attributes on the layout, setting the palette, and the suppliers
54
- for trails, themes, looks and saved table layouts → **`keystone_ui-install`**.
55
- - **Building UI with it** — which helper renders what, what keywords it takes,
56
- how helpers nest → **`keystone_ui-develop`**.
31
+ - **Getting the gem into a host app** — the install generator, the
32
+ configuration block, the theme and look attributes on the layout, the palette,
33
+ registered looks, the navigation groups, and the suppliers for trails, themes,
34
+ looks, the current tab and saved preferences → **`keystone_ui-install`**.
35
+ - **Building screens with it** — which helper renders what, the keywords each
36
+ takes, and how they nest → **`keystone_ui-develop`**.
57
37
 
58
38
  ## How to use it
59
39
 
60
- One decision: is Keystone UI already set up in the app?
40
+ One decision: is keystone_ui set up in the app?
61
41
 
62
42
  - No, or the setup is out of date → **`keystone_ui-install`**.
63
- - Yes, and you have a screen to build or edit → **`keystone_ui-develop`**. Do not
64
- hand-write ERB or Tailwind for UI it covers.
65
-
66
- Questions about which piece fits a scenario also go to the develop local, which
67
- holds the catalog.
43
+ - Yes, and there is a screen to build or edit, or a question about which piece
44
+ fits → **`keystone_ui-develop`**. Do not hand-write ERB or Tailwind for UI it
45
+ covers.
68
46
 
69
47
  ## Conventions
70
48
 
71
- - **Helpers, not classes.** Every piece of UI is a view helper prefixed `ui_`,
72
- called from ERB. The one layout helper that is not prefixed `ui_` writes the
73
- theme onto the page's `html` tag, and it belongs to the install local.
74
- Components live under the `Keystone::Ui` namespace, but a host app does not
75
- name a component class directly. The one exception is the table column value
76
- object, which is passed as an argument and renders nothing.
77
- - **Containers take blocks, leaves take keywords.** Helpers that wrap content
78
- (page shells, sections, panels, grids, forms, tables) yield a block. Helpers
79
- that render one thing (a button, a badge, a field, a stat, a bucket) are
80
- configured entirely by keyword arguments. The navigation bar exposes named
81
- slots instead of a single block.
82
- - **Action menus.** An action menu is an ellipsis button that opens a dropdown
83
- of actions, shown at every screen size. The mobile action menu is the one
84
- hidden from `lg:` up. Each action is a label, an address and an HTTP method.
85
- A plain visit renders as a link. Any other method renders as a button that
86
- sends that method, so an action that changes data is never a bare link. An
87
- action can carry a question that Turbo asks before it runs. A delete asks
88
- "<label> this? This cannot be undone." unless it is given its own question,
89
- 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,
90
- and a section can carry an action menu in its header beside its title.
91
- - **Info panels.** A stat card, a radio card and a checkbox row can each carry
92
- extra text about themselves. Given that text, the piece shows an info button,
93
- and the text stays hidden until the button is hovered or tapped. A piece
94
- given no such text shows no button. On a radio card and a checkbox row the
95
- button sits on the line with the label. Wherever it is placed, the button
96
- sits level with the text beside it.
97
- - **Standalone info button.** The same info button can be placed on its own,
98
- beside anything. It takes a short summary, which is required, and shows it
99
- when the button is hovered. Given nothing more, a tap shows the summary too.
100
- Given a block of further detail, a tap opens that detail instead, in a panel
101
- under the button, and the summary stays the hover text. Both popups are
102
- placed against the screen, not against the element the button sits in, so a
103
- table or any other container that clips its contents does not cut them off.
104
- Each opens under the button with its right edge on the button's, the first
105
- time as well as every later time, and is kept on the screen when the button
106
- is near the left edge. The detail panel is wider than the summary. Both carry
107
- one shared popup class from keystone_ui-styles, which decides how their text
108
- wraps and how they fit a narrow screen. A second tap closes
109
- what the first opened, a click anywhere else closes the detail, and
110
- scrolling the page closes both.
111
- - **A breakdown is text.** A breakdown lists amounts, each beside a label
112
- saying what it is, and ends with a total set apart from the lines above it.
113
- Every line and the total are an amount and a label, passed as
114
- already-formatted text and shown as written. The component adds nothing up,
115
- so the total is whatever it is given. Its whole layout comes from
116
- keystone_ui-styles' `ks-breakdown` classes: how the amounts and labels line
117
- up, and how the total is set apart. The component sets no widths or spacing
118
- of its own, so a breakdown looks right only with a keystone_ui-styles version
119
- that defines those classes. It has no button and no hidden state of
120
- its own, and it can be placed inside an info button's detail.
121
- - **A toned figure is text.** A figure shows one amount inline, in plain text
122
- or in the success or danger colour, so it reads as a gain or a loss without a
123
- badge around it. The amount is passed as already-formatted text and shown as
124
- written, and the tone is chosen by name. An unknown tone raises at render
125
- time. The colours come from keystone_ui-styles, so a figure shows its tone
126
- only with a keystone_ui-styles version that defines those classes.
127
- - **The last table column is right-aligned.** In a data table with no actions
128
- column, the last column's header is right-aligned like the cells beneath it,
129
- so a figure or total placed in that header lines up with the figures below.
130
- - **A locked first column.** A table column can be marked locked. When it is
131
- the table's first column, its header and cells stay in view while the rest
132
- of the table scrolls sideways, styled by keystone_ui-styles' locked header
133
- and cell classes. A locked column anywhere else renders as an ordinary
134
- column. A locked column cannot be hidden or moved, so it never appears in the
135
- "Columns" menu and a saved layout leaves it where it is, even when it is also
136
- marked hideable.
137
- - **Saved table layouts.** A data table can be given a key naming it. A table
138
- with a key asks the app, or another gem such as keystone_ui-preferences, for
139
- the layout saved under that key for the request. A saved layout lists the
140
- columns to hide, and only columns marked hideable can be hidden. The columns
141
- the table's own call hides are its default layout. A saved layout that lists
142
- columns to hide replaces that default, and a saved empty list shows every
143
- column. When nothing is saved, or the saved layout lists no columns to hide,
144
- the table keeps its default. A saved layout can also list an order for the
145
- columns. Only hideable columns move: they fill the places hideable columns
146
- held in the table's own call, in the saved order, and any the order leaves
147
- out follow the ones it names. Every other column keeps its place, and a
148
- layout with no order keeps the order the columns were declared in. When the
149
- supplier gives an address to save to, a "Columns" menu appears above the
150
- table, at its right, and saves the user's choice there, even before anything
151
- has been saved. The menu lists the hideable columns in the order the table
152
- shows them, each with a box to show or hide it and buttons to move it up or
153
- down. The menu and the table read the same saved layout, so the menu's
154
- ticked boxes and order always match the columns the table shows. An unticked column's name is greyed at once. Ticking boxes and moving
155
- columns sends nothing while the menu is open. Closing the menu, with its
156
- Columns button or by clicking anywhere outside it, saves the hidden columns
157
- and the order together once, then reloads the page. Closing it with nothing
158
- changed saves nothing. When the save is refused or cannot reach the server,
159
- the page does not reload. The Columns menu shows the message "Your
160
- column changes were not saved." and puts its boxes and order back to what
161
- the table shows.
162
- A table with no key, or an app with no supplier, renders from its own call
163
- alone. Setting up the supplier belongs to the install local.
164
- - **Suggestions.** A form field can carry a list of suggested values. The
165
- browser offers them while the field's text is typed, and the user can still
166
- enter a value that is not on the list. This applies to a field with a typed
167
- input, such as text, number, email, password or date. A textarea, select or
168
- checkbox field ignores the list, and a field given no list offers nothing.
169
- It needs no JavaScript.
170
- - **Options are symbols, and each component accepts its own set.** Appearance is
171
- chosen by name — `variant:`, `size:`, `type:`, `padding:`, `spacing:`,
172
- `max_width:`, `radius:` — on a size scale (`:sm` … `:xl`) or a short list of
173
- named choices. A button's `variant:` and a badge's `variant:` accept
174
- different symbols, and the develop local carries the real values. Most
175
- components raise on a symbol they do not know, so a wrong guess fails at
176
- render time.
177
- - **Measured values are numbers.** Components that measure or compare values, such as
178
- progress bars, funnels and buckets, do arithmetic on them. Pass a number, not
179
- a formatted string such as `"9,000"`. A bucket raises on one.
180
- - **A funnel has two shapes.** Both size each step against the first step and
181
- show the percent carried from one step to the next. The default draws one bar
182
- per step, each with its label and value on a row above it. The joined shape
183
- draws the steps as one figure: each step's value and label sit in a column on
184
- the left, each step is a block centred at its width, and a neutral band
185
- between two blocks narrows from one width to the next and holds the percent.
186
- Any other shape raises `ArgumentError`. Neither shape needs JavaScript.
187
- - **A line chart is labelled or dated.** A line chart draws one line per
188
- series, and each series is a name and its values, with an optional colour
189
- and an optional dashed line. Its horizontal axis is given one of two ways,
190
- never both and never neither, and the wrong combination raises
191
- `ArgumentError`. Labels are text, one per value, spaced evenly and shown as
192
- written. Dates are one day per value, and a dated chart places each point by
193
- its day, so a gap of a week is seven times as wide as a gap of a day. A dated
194
- axis runs from the first day to the last, marks only whole days, and reads
195
- each day as a date such as "Oct 2, 2026", which is also what a hovered point
196
- shows. A time of day is dropped, so a dated chart has one position per day.
197
- - **A calculation is text.** The calculation behind a figure is the opposite
198
- case. It is a list of groups, each with an optional title and its lines, and
199
- each line is a label, the working and the result. They are passed as
200
- already-formatted text and shown as written. The component does no
201
- arithmetic, and it is closed by default under a quiet summary row.
202
- - **Semantic color, not literal color.** The themed hue is `accent-*` and the
203
- themed neutral family is `surface-*`, both CSS custom properties whose
204
- defaults (blue and zinc) come from the keystone_ui-styles gem. Retheming an
205
- app changes those values, not the components. Some components still use
206
- Tailwind's stock `gray-*` and `zinc-*` neutrals, or fixed status colors such
207
- as green and amber, directly. Changing the defaults belongs to the install
208
- local.
209
- - **Looks.** A look is one CSS file that sets the `--ks-` variables from
210
- keystone_ui-styles 0.6.0 or later: corner radius, font, label weight, border
211
- width, padding and colours. Each colour variable has a `-dark` partner read
212
- on a dark page. Buttons, panels, cards, alerts, badges, form fields, the
213
- modal, the action menu, the mobile action menu, the column picker, multi select, copy button,
214
- theme toggle, checkbox row, radio card, option card, file upload and colour
215
- picker read these variables. So do the data display components: stat card,
216
- chart card, card link, CTA banner, feature grid, hero, data table, code,
217
- accordion, disclosure, calculation, tab switcher, progress, funnel, bucket,
218
- pipeline and swipe deck. So do the navigation components: navbar, nav item,
219
- nav dropdown, bottom nav, mobile header, breadcrumbs and settings link. A host imports its
220
- look after `keystone_source.css`, and a gem ships one through
221
- `tailwind_imports`, both set up through the install local.
222
- - **Registered looks.** Looks can also be registered by name, and each page
223
- gets one: the name another gem supplies for the request, then the configured
224
- default, each used only when registered. The layout's `<html>` tag carries
225
- `data-look="<name>"`, and a registered look file scopes its variables to
226
- `:root[data-look="<name>"]`. A host with no registered looks gets no
227
- `data-look`. Registering and choosing looks is set up through the install
228
- local.
229
- - **Light, dark, system and custom themes.** Every component has dark-mode
230
- styling. The theme is chosen in this order: the user's choice stored in a
49
+ - **Helpers, not classes.** Every piece of UI is a view helper prefixed `ui_`.
50
+ Components sit under the `Keystone::Ui` namespace, but a host app does not
51
+ name a component class. The one class a host does name is the table column
52
+ value object, which is passed as an argument and renders nothing.
53
+ - **Containers take blocks, leaves take keywords.** Page shells, sections,
54
+ panels, grids, forms and tables wrap a block. A button, badge, field, stat or
55
+ bucket is set entirely by keyword arguments. The navigation bar takes named
56
+ slots.
57
+ - **Options are symbols.** Appearance is chosen by name, such as `variant:`,
58
+ `size:` or `padding:`, and each component accepts its own set. Most raise on a
59
+ symbol they do not know, so a wrong guess fails at render time.
60
+ - **Numbers and text are different inputs.** Progress bars, funnels and buckets
61
+ do arithmetic, so they take numbers, and a bucket raises on `"9,000"`. A
62
+ breakdown, a calculation and a toned figure take already-formatted text, show
63
+ it as written and add nothing up.
64
+ - **Going back.** A form or show page shell needs a way back: a back link, a
65
+ trail of earlier pages shown as breadcrumbs, or a trail the app supplies for
66
+ the request. A nav tab's own page passes an empty trail and shows no back
67
+ link. A page with none of these raises `KeystoneUi::MissingBackLink`, and a
68
+ trail link missing a label or an address raises `KeystoneUi::IncompleteTrail`.
69
+ - **Navigation.** The app declares navigation groups, each a label and its tabs,
70
+ and each tab a key, label, address and permission check. Tabs the user may
71
+ not see are left out, and a group left with no tabs is left out. A saved
72
+ preference can place the navigation as a top bar or a left or right sidebar
73
+ and set the order of groups and tabs. A supplier names the current tab, which
74
+ is marked active with its group. A declaration with an empty group, a tab with
75
+ no label or address, or two tabs sharing a key stops the app at boot with
76
+ `KeystoneUi::NavigationCheck::Error`.
77
+ - **Saved table layouts.** A data table given a key reads the layout saved under
78
+ it: which hideable columns to hide and their order. With a save address, a
79
+ "Columns" menu lets the user change it. A locked first column stays in view
80
+ while the table scrolls sideways and is never hidden or moved.
81
+ - **Action menus.** Each action is a label, an address and an HTTP method. A
82
+ plain visit is a link, and any other method is a button, so an action that
83
+ changes data is never a bare link. A delete asks for confirmation by default.
84
+ - **Semantic colour.** The themed hue is `accent-*` and the themed neutrals are
85
+ `surface-*`, CSS custom properties whose defaults (blue and zinc) come from
86
+ the keystone_ui-styles gem. Retheming changes those values, not the
87
+ components.
88
+ - **Looks.** A look is one CSS file setting keystone_ui-styles' `--ks-`
89
+ variables for radius, font, weight, border, spacing and colour, each colour
90
+ with a `-dark` partner. Components render `ks-` classes that read them, and
91
+ their own Tailwind constants hold only layout, size and behaviour. Looks can
92
+ be registered by name, and the page's `html` tag carries `data-look` for the
93
+ supplied look or the default, when that name is registered.
94
+ - **Themes.** Light, dark, system and custom. The mode comes from the user's
231
95
  cookie, then a mode another gem supplies, then light. System leaves the page
232
- to follow the operating system. Custom marks the page for a palette another
233
- gem defines. The theme toggle does not offer it, so a page reaches it when
234
- another gem supplies it. On a Turbo visit, the page being shown sets the
235
- theme, so a change to the mode on the server shows up without a full reload.
236
- Marking the layout with the theme is set up through the install local, and
237
- placing the toggle on a screen goes through the develop local.
238
- - **Tailwind classes are static strings.** Class names are never interpolated,
239
- so Tailwind's scanner can find them. Widths and heights that depend on data,
240
- such as a progress bar or a bucket's fill, are set with an inline style
241
- instead. The host needs tailwindcss-rails v4+, and the engine tells Tailwind
242
- at boot where the component files are.
243
- - **Interactivity is Stimulus.** Dropdowns, modals, dismissible alerts, file
244
- uploads, the color picker, the multi-select, tab switchers, accordions, the
245
- swipe deck, column pickers, info panels, line charts, clipboard copy
246
- and the theme toggle ship with the gem as Stimulus controllers registered once
247
- at install. A host writes no JavaScript to use them. Components that post
248
- somewhere, such as the column picker and the pipeline, post to endpoints the
249
- host app or another gem owns.
250
- - Ruby >= 3.2. ViewComponent >= 2.0 and < 5.
96
+ to follow the operating system, and custom marks the page for a palette
97
+ another gem defines, which the theme toggle does not offer.
98
+ - **Static Tailwind classes.** Class names are never interpolated, so Tailwind's
99
+ scanner finds them. Sizes that depend on data, such as a progress bar's
100
+ width, use an inline style. The host needs tailwindcss-rails v4+.
101
+ - **Interactivity is Stimulus.** Dropdowns, modals, tab switchers, the column
102
+ picker, info buttons, charts, copy buttons and the theme toggle ship as
103
+ Stimulus controllers, so a host writes no JavaScript. Components that post,
104
+ such as the column picker and the pipeline, post to endpoints the host or
105
+ another gem owns.
106
+ - Ruby >= 3.2, ViewComponent >= 2.0 and < 5, keystone_ui-styles >= 0.14.0.
@@ -29,10 +29,10 @@ built on ViewComponent; hook it in before building any screen with those helpers
29
29
  `preference_supplier` (a callable that supplies the saved hidden columns and
30
30
  column order of a data table given a `key:`, and the address its Columns menu
31
31
  saves to, and the navigation's placement under the key `:navigation`),
32
- `navigation_group` (a labelled group of desktop tabs that `ui_navigation`
33
- draws, each tab declared with `tab key, label:, href:, permitted:`),
32
+ `navigation_group` (a labelled group of desktop tabs that the navigation
33
+ helper draws, each tab declared with `tab key, label:, href:, permitted:`),
34
34
  `current_tab_supplier` (a callable that supplies the key of the declared tab
35
- the current page belongs to, so `ui_navigation` marks it and its group
35
+ the current page belongs to, so the navigation marks it and its group
36
36
  active),
37
37
  and the `tailwind_imports` and `tailwind_sources` lists (extra CSS files and
38
38
  scan paths added to the Tailwind build).
@@ -48,7 +48,7 @@ built on ViewComponent; hook it in before building any screen with those helpers
48
48
  ## How to use it
49
49
 
50
50
  1. Confirm the prerequisites: Ruby >= 3.2 and **tailwindcss-rails v4+** in the
51
- host app. The gem brings ViewComponent and keystone_ui-styles 0.12.0 or later with it.
51
+ host app. The gem brings ViewComponent and keystone_ui-styles 0.14.0 or later with it.
52
52
  Tailwind does not have to be initialized first, because the generator creates
53
53
  the stylesheet if it is missing.
54
54
 
@@ -235,9 +235,9 @@ built on ViewComponent; hook it in before building any screen with those helpers
235
235
  pages, and `nil` for a page whose Back link comes from its own
236
236
  `back_url:`.
237
237
  - Every other form and show page must end up with a Back link. A page that
238
- passes no `back_url:`, and has no trail or a trail whose last link has no
239
- address, raises `KeystoneUi::MissingBackLink` naming the page's title when
240
- it renders. The message tells the developer to pass `back_url:` or
238
+ passes no `back_url:`, and has no trail or a trail whose last link's
239
+ address is `nil`, raises `KeystoneUi::MissingBackLink` naming the page's
240
+ title when it renders. The message tells the developer to pass `back_url:` or
241
241
  `trail:`, to supply a trail through `trail_supplier`, or to pass
242
242
  `trail: []` on a nav tab's own page.
243
243
  - Every link in a trail needs both a label and an address. A trail with a
@@ -298,7 +298,7 @@ built on ViewComponent; hook it in before building any screen with those helpers
298
298
  to what the table shows.
299
299
  - For the key `:navigation` the supplier returns the person's navigation
300
300
  placement as `{ value: { "placement" => "left" } }`, with `"left"`,
301
- `"right"` or `"top"`. `ui_navigation` draws a sidebar on the left or the
301
+ `"right"` or `"top"`. The navigation draws a sidebar on the left or the
302
302
  right of the page content on desktop screens for the first two, and the
303
303
  top bar for `"top"`, `nil`, a value with no `"placement"` string key, or
304
304
  any other placement.
@@ -306,7 +306,7 @@ built on ViewComponent; hook it in before building any screen with those helpers
306
306
  tabs under `"order"`, as
307
307
  `[ { "group" => "Admin" }, { "group" => "Sales", "tabs" => [ "orders", "quotes" ] } ]`.
308
308
  A group is named by its declared label and a tab by its key as a string.
309
- `ui_navigation` draws the named groups and tabs first in that order, then
309
+ The navigation draws the named groups and tabs first in that order, then
310
310
  the rest in declared order, and ignores names no longer declared.
311
311
  - A companion preferences gem may set this supplier for the app. Ask the
312
312
  developer whether the app uses one, or which code stores each user's table
@@ -316,16 +316,20 @@ built on ViewComponent; hook it in before building any screen with those helpers
316
316
  `group.tab key, label:, href:, permitted:` adds a tab in order. `href:` is
317
317
  an address or a callable that receives the view and returns one.
318
318
  `permitted:` is a callable that receives the view and returns whether the
319
- current person may see the tab. The layout renders them with
320
- `ui_navigation` around `yield`, setting the app's logo with
321
- `navigation.with_logo` and its account and user menus with
322
- `navigation.with_menus` inside the block, so the layout draws no other
323
- top bar. Ask the developer which tabs and groups the app has, and which
324
- permission check guards each, before declaring them.
319
+ current person may see the tab. A tab the person may not see is left
320
+ out, and a group with no tab left is left out. Ask the developer which
321
+ tabs and groups the app has, and which permission check guards each,
322
+ before declaring them. Boot stops with
323
+ `KeystoneUi::NavigationCheck::Error` when a tab has no label or no
324
+ `href:`, when two tabs share a key, or when a group has no tabs. Drawing
325
+ the declared groups in the layout is done with the navigation helper,
326
+ which belongs to `keystone_ui-develop`.
325
327
  - `current_tab_supplier` — a callable that receives the view and returns the
326
328
  key of the declared tab the current page belongs to, or `nil`.
327
- `ui_navigation` shows that tab and its group as active in the top bar and
329
+ The navigation shows that tab and its group as active in the top bar and
328
330
  gives that tab and its group's label the `active` class in the sidebar.
331
+ The key must equal the declared key exactly, so a tab declared as
332
+ `:quotes` is not matched by the string `"quotes"`.
329
333
  `nil`, a key no declared tab has, or no supplier marks nothing. The
330
334
  callable must answer for every page the layout draws, so a page with no
331
335
  tab returns `nil` rather than raising. Ask the developer how a page names
@@ -74,6 +74,7 @@ sources:
74
74
  - lib/keystone_ui/configuration.rb
75
75
  - lib/keystone_ui/navigation_group.rb
76
76
  - lib/keystone_ui/navigation_order.rb
77
+ - lib/keystone_ui/visible_navigation.rb
77
78
  - lib/keystone_ui/missing_back_link.rb
78
79
  - lib/keystone_ui/incomplete_trail.rb
79
80
  - lib/keystone_ui/theme_choice.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.38.0
4
+ version: 0.39.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tyler Schneider
@@ -208,12 +208,14 @@ files:
208
208
  - lib/keystone_ui/look_check.rb
209
209
  - lib/keystone_ui/look_choice.rb
210
210
  - lib/keystone_ui/missing_back_link.rb
211
+ - lib/keystone_ui/navigation_check.rb
211
212
  - lib/keystone_ui/navigation_group.rb
212
213
  - lib/keystone_ui/navigation_order.rb
213
214
  - lib/keystone_ui/safelist.rb
214
215
  - lib/keystone_ui/source_css.rb
215
216
  - lib/keystone_ui/theme_choice.rb
216
217
  - lib/keystone_ui/version.rb
218
+ - lib/keystone_ui/visible_navigation.rb
217
219
  - the_local/agents/keystone_ui-develop.md
218
220
  - the_local/agents/keystone_ui-info.md
219
221
  - the_local/agents/keystone_ui-install.md