layered-ui-rails 0.15.0 → 0.16.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/.claude/skills/layered-ui-rails/references/CSS.md +11 -0
- data/.claude/skills/layered-ui-rails/references/HELPERS.md +42 -1
- data/CHANGELOG.md +17 -0
- data/app/assets/tailwind/layered/ui/styles.css +40 -6
- data/app/helpers/layered/ui/form_helper.rb +2 -2
- data/app/helpers/layered/ui/modal_helper.rb +112 -0
- data/app/javascript/layered_ui/controllers/l_ui/modal_controller.js +13 -2
- data/app/views/layered/ui/managed_resource/_form.html.erb +1 -1
- data/app/views/layouts/layered_ui/_header.html.erb +6 -0
- data/app/views/layouts/layered_ui/_panel.html.erb +1 -1
- data/lib/layered/ui/engine.rb +1 -0
- data/lib/layered/ui/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e263735e08a190494c81dd8c50552f0f407e80bca6704abea9dca2f3dc78ce37
|
|
4
|
+
data.tar.gz: 611458285efd46bc8c6b64f5766b65626152ed0d10d8d1cfef3eac6226f6f3b4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 31aeaab41317883a2a027520b3aa656c5bc987825f51a7d79000d2746c7088046fe691a53827ad43aa2f0360558dd7208956bf5f18aad61536defea559f197cb
|
|
7
|
+
data.tar.gz: 128ac9723c177fbbcd4ff5a03f677e3c24fe924209b8a04fa985340b3b561bf07e3616e899cae352a1f02085c1e7f63a0c6aeb28137f453565017a0001e2a717
|
|
@@ -17,6 +17,16 @@ Two patterns deviate from strict BEM by design - leave them in place rather than
|
|
|
17
17
|
|
|
18
18
|
This gives author-written links inside long-form content (Markdown, prose, ad-hoc views) consistent underline/colour treatment without forcing an explicit class on every link. Engine elements opt out automatically because their class names contain `l-ui-`. Side effect: any host-app class containing the substring `l-ui-` will also opt an `<a>` out of bare-link styling.
|
|
19
19
|
|
|
20
|
+
## Body modifiers
|
|
21
|
+
|
|
22
|
+
Applied to `<body>` via the `:l_ui_body_class` yield to toggle layout-level behaviour:
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
.l-ui-body--always-show-navigation Pin sidebar navigation open on desktop
|
|
26
|
+
.l-ui-body--hide-header Hide the header and collapse its reserved space
|
|
27
|
+
.l-ui-body--header-contained Constrain the header's inner row to max-w-7xl (landing pages)
|
|
28
|
+
```
|
|
29
|
+
|
|
20
30
|
## Page layout
|
|
21
31
|
|
|
22
32
|
```
|
|
@@ -249,6 +259,7 @@ Always combine the base block with a modifier, e.g. `<span class="l-ui-badge l-u
|
|
|
249
259
|
```
|
|
250
260
|
.l-ui-header-container Fixed header container
|
|
251
261
|
.l-ui-header Header flexbox
|
|
262
|
+
.l-ui-header__links Inline link list for landing-page headers (yielded via :l_ui_header_links)
|
|
252
263
|
.l-ui-header__icon Header icon (responsive)
|
|
253
264
|
.l-ui-header__icon--light Light theme icon
|
|
254
265
|
.l-ui-header__icon--dark Dark theme icon
|
|
@@ -208,13 +208,14 @@ Formats a date/time value as `"%-d %b %Y, %H:%M"` (e.g. "15 Apr 2026, 10:30"). R
|
|
|
208
208
|
## Form
|
|
209
209
|
|
|
210
210
|
```ruby
|
|
211
|
-
l_ui_form(record, fields:, url:, method: nil)
|
|
211
|
+
l_ui_form(record, fields:, url:, method: nil, submit: nil)
|
|
212
212
|
```
|
|
213
213
|
|
|
214
214
|
- `record` (ActiveRecord) - the model instance
|
|
215
215
|
- `fields` (Array<Hash>) - field definitions (see below)
|
|
216
216
|
- `url` (String) - form action URL
|
|
217
217
|
- `method` (Symbol, optional) - HTTP method override
|
|
218
|
+
- `submit` (String, optional) - submit button text; defaults to "Create" for new records and "Save" for persisted records
|
|
218
219
|
|
|
219
220
|
Renders a complete form with all fields, error summary, and submit button via the `layered/ui/managed_resource/form` partial.
|
|
220
221
|
|
|
@@ -246,6 +247,46 @@ l_ui_field_error_id(record, attribute) # Error element ID for aria-describedby
|
|
|
246
247
|
l_ui_field_hint_id(record, attribute) # Hint element ID for aria-describedby
|
|
247
248
|
```
|
|
248
249
|
|
|
250
|
+
## Modal
|
|
251
|
+
|
|
252
|
+
```ruby
|
|
253
|
+
l_ui_modal(title:, id: nil, heading_level: :h3, container: {}, &block)
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
- `title` (String) - heading shown in the modal header and used for `aria-labelledby`
|
|
257
|
+
- `id` (String, optional) - DOM id for the `<dialog>`; defaults to an auto-generated id
|
|
258
|
+
- `heading_level` (Symbol, optional) - heading tag for the title (e.g. `:h2`, `:h3`). Defaults to `:h3`
|
|
259
|
+
- `container` (Hash, optional) - extra HTML attributes for the wrapping `<div>` (e.g. `class:`)
|
|
260
|
+
- `&block` - the block's content is the modal body; call `m.trigger(**options, &block)` inside it to render a colocated trigger button
|
|
261
|
+
|
|
262
|
+
```erb
|
|
263
|
+
<%= l_ui_modal(title: "Socials") do |m| %>
|
|
264
|
+
<% m.trigger(class: "l-ui-button l-ui-button--outline") do %>
|
|
265
|
+
Open socials
|
|
266
|
+
<% end %>
|
|
267
|
+
<p>Body content.</p>
|
|
268
|
+
<% end %>
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Renders the trigger `<button>` (if `m.trigger` is called), the `<dialog class="l-ui-modal">` with a header (title + close button), and wires the `l-ui--modal` Stimulus controller, including backdrop-click close.
|
|
272
|
+
|
|
273
|
+
If the trigger contains only an icon (no visible text), pass `aria-label:` to `m.trigger` so the button has an accessible name.
|
|
274
|
+
|
|
275
|
+
`m.trigger` renders a colocated trigger button. To open the same modal from elsewhere on the page (or to have multiple triggers), give the modal a known `id:` and add `data-l-ui-modal-open="<that id>"` to any button:
|
|
276
|
+
|
|
277
|
+
```erb
|
|
278
|
+
<%= l_ui_modal(title: "Confirm", id: "confirm-modal") do |m| %>
|
|
279
|
+
<% m.trigger(class: "l-ui-button") do %>Open<% end %>
|
|
280
|
+
<p>Body content.</p>
|
|
281
|
+
<% end %>
|
|
282
|
+
|
|
283
|
+
<button type="button" data-l-ui-modal-open="confirm-modal">Open from elsewhere</button>
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
The button does not need to be inside the helper's wrapper, and no `data-controller` or `data-action` is required - the `l-ui--modal` controller listens at the document level for clicks on `[data-l-ui-modal-open]` matching its dialog id.
|
|
287
|
+
|
|
288
|
+
Calling `dialog.showModal()` directly is not supported - it bypasses the `l-ui--modal` controller and skips scroll lock, focus restoration, open-count tracking, and the screen-reader announcement.
|
|
289
|
+
|
|
249
290
|
## Authentication
|
|
250
291
|
|
|
251
292
|
```ruby
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. This project follows [Semantic Versioning](https://semver.org/).
|
|
4
4
|
|
|
5
|
+
## [0.16.0] - 2026-05-16
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- `l_ui_modal` helper with external-trigger support for declaratively rendering modal dialogs
|
|
10
|
+
- `l-ui-header--contained` modifier and a yield slot for header links
|
|
11
|
+
- `submit:` option on `l_ui_form` to override the submit button text (defaults to "Create" for new records, "Save" for persisted)
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- Header links now left-aligned
|
|
16
|
+
- Navigation container right border restored at `md` and above; panel container left border restored
|
|
17
|
+
- Modal backdrop now tinted in addition to the existing blur (foreground at 25% in light mode, background at 60% in dark mode)
|
|
18
|
+
- Active navigation items now round on all four corners (`rounded-sm`) rather than the left only
|
|
19
|
+
- Panel close button now uses `l-ui-button--primary` instead of `l-ui-button--outline`
|
|
20
|
+
- Icons inside `l-ui-button--primary` now invert in light mode and stay un-inverted in dark mode, so they always contrast against the accent-coloured button background
|
|
21
|
+
|
|
5
22
|
## [0.15.0] - 2026-05-11
|
|
6
23
|
|
|
7
24
|
### Breaking
|
|
@@ -361,7 +361,7 @@
|
|
|
361
361
|
@apply overflow-x-auto
|
|
362
362
|
my-3 p-3
|
|
363
363
|
bg-surface
|
|
364
|
-
rounded-
|
|
364
|
+
rounded-sm;
|
|
365
365
|
}
|
|
366
366
|
|
|
367
367
|
.l-ui-markdown pre code {
|
|
@@ -489,11 +489,29 @@
|
|
|
489
489
|
px-4 py-3;
|
|
490
490
|
}
|
|
491
491
|
|
|
492
|
+
.l-ui-body--header-contained .l-ui-header {
|
|
493
|
+
@apply w-full max-w-7xl
|
|
494
|
+
mx-auto;
|
|
495
|
+
}
|
|
496
|
+
|
|
492
497
|
.l-ui-header__navigation {
|
|
493
498
|
@apply flex items-center
|
|
494
499
|
gap-4;
|
|
495
500
|
}
|
|
496
501
|
|
|
502
|
+
.l-ui-header__links {
|
|
503
|
+
@apply hidden sm:flex items-center
|
|
504
|
+
mr-auto ml-8
|
|
505
|
+
gap-8
|
|
506
|
+
text-sm font-medium;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
.l-ui-header__links a {
|
|
510
|
+
@apply text-foreground-muted
|
|
511
|
+
rounded-sm
|
|
512
|
+
focus-ring;
|
|
513
|
+
}
|
|
514
|
+
|
|
497
515
|
.l-ui-header__icon {
|
|
498
516
|
@apply h-5.5 w-auto;
|
|
499
517
|
}
|
|
@@ -563,6 +581,10 @@
|
|
|
563
581
|
@apply dark:invert;
|
|
564
582
|
}
|
|
565
583
|
|
|
584
|
+
.l-ui-button--primary .l-ui-icon {
|
|
585
|
+
@apply invert dark:invert-0;
|
|
586
|
+
}
|
|
587
|
+
|
|
566
588
|
.l-ui-icon--xs {
|
|
567
589
|
@apply w-4 h-4;
|
|
568
590
|
}
|
|
@@ -590,6 +612,7 @@
|
|
|
590
612
|
z-50
|
|
591
613
|
w-[256px]
|
|
592
614
|
bg-background
|
|
615
|
+
md:border-r md:border-border
|
|
593
616
|
-translate-x-full
|
|
594
617
|
transition-transform duration-300;
|
|
595
618
|
}
|
|
@@ -632,7 +655,7 @@
|
|
|
632
655
|
w-full min-h-[40px]
|
|
633
656
|
gap-3 px-3
|
|
634
657
|
text-sm font-medium text-foreground-muted
|
|
635
|
-
rounded-
|
|
658
|
+
rounded-sm
|
|
636
659
|
focus-ring
|
|
637
660
|
transition-colors;
|
|
638
661
|
}
|
|
@@ -1485,6 +1508,7 @@ pre.l-ui-surface {
|
|
|
1485
1508
|
z-40
|
|
1486
1509
|
w-full md:w-[480px]
|
|
1487
1510
|
bg-background
|
|
1511
|
+
border-l border-border
|
|
1488
1512
|
transform translate-x-full
|
|
1489
1513
|
transition-transform duration-300;
|
|
1490
1514
|
}
|
|
@@ -1521,12 +1545,13 @@ pre.l-ui-surface {
|
|
|
1521
1545
|
}
|
|
1522
1546
|
|
|
1523
1547
|
.l-ui-panel__header {
|
|
1524
|
-
@apply flex flex-col
|
|
1548
|
+
@apply flex flex-col
|
|
1549
|
+
border-b border-border;
|
|
1525
1550
|
}
|
|
1526
1551
|
|
|
1527
1552
|
.l-ui-panel__header-content {
|
|
1528
1553
|
@apply flex items-center
|
|
1529
|
-
p-4
|
|
1554
|
+
p-4 py-3;
|
|
1530
1555
|
}
|
|
1531
1556
|
|
|
1532
1557
|
.l-ui-panel__header-buttons {
|
|
@@ -1642,7 +1667,7 @@ pre.l-ui-surface {
|
|
|
1642
1667
|
p-4 gap-4
|
|
1643
1668
|
text-foreground
|
|
1644
1669
|
bg-surface
|
|
1645
|
-
rounded-
|
|
1670
|
+
rounded-sm;
|
|
1646
1671
|
}
|
|
1647
1672
|
|
|
1648
1673
|
.l-ui-message--sent .l-ui-message__bubble {
|
|
@@ -1787,8 +1812,17 @@ pre.l-ui-surface {
|
|
|
1787
1812
|
border-0 md:border md:border-border rounded-none md:rounded-sm;
|
|
1788
1813
|
}
|
|
1789
1814
|
|
|
1815
|
+
.l-ui-modal[open] {
|
|
1816
|
+
@apply flex flex-col;
|
|
1817
|
+
}
|
|
1818
|
+
|
|
1790
1819
|
.l-ui-modal::backdrop {
|
|
1791
1820
|
@apply backdrop-blur-sm;
|
|
1821
|
+
background-color: color-mix(in oklch, var(--foreground) 25%, transparent);
|
|
1822
|
+
}
|
|
1823
|
+
|
|
1824
|
+
.dark .l-ui-modal::backdrop {
|
|
1825
|
+
background-color: color-mix(in oklch, var(--background) 60%, transparent);
|
|
1792
1826
|
}
|
|
1793
1827
|
|
|
1794
1828
|
.l-ui-modal__header {
|
|
@@ -1798,7 +1832,7 @@ pre.l-ui-surface {
|
|
|
1798
1832
|
}
|
|
1799
1833
|
|
|
1800
1834
|
.l-ui-modal__body {
|
|
1801
|
-
@apply overflow-y-auto
|
|
1835
|
+
@apply flex-1 min-h-0 overflow-y-auto
|
|
1802
1836
|
px-5 py-4;
|
|
1803
1837
|
}
|
|
1804
1838
|
|
|
@@ -10,9 +10,9 @@ module Layered
|
|
|
10
10
|
# fields: Post.l_managed_resource_fields,
|
|
11
11
|
# url: managed_posts_path)
|
|
12
12
|
#
|
|
13
|
-
def l_ui_form(record, fields:, url:, method: nil)
|
|
13
|
+
def l_ui_form(record, fields:, url:, method: nil, submit: nil)
|
|
14
14
|
render partial: "layered/ui/managed_resource/form",
|
|
15
|
-
locals: { record: record, fields: fields, url: url, method: method }
|
|
15
|
+
locals: { record: record, fields: fields, url: url, method: method, submit: submit }
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
# Normalises a raw field config hash into a canonical form.
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
module Layered
|
|
2
|
+
module Ui
|
|
3
|
+
module ModalHelper
|
|
4
|
+
# Renders a modal as a <dialog> wired up to the +l-ui--modal+ Stimulus
|
|
5
|
+
# controller. The block's content is the modal body; call +m.trigger+ to
|
|
6
|
+
# render a colocated trigger button.
|
|
7
|
+
#
|
|
8
|
+
# <%= l_ui_modal(title: "Socials") do |m| %>
|
|
9
|
+
# <% m.trigger(class: "l-ui-button l-ui-button--outline") do %>
|
|
10
|
+
# Open socials
|
|
11
|
+
# <% end %>
|
|
12
|
+
# <p>Body content.</p>
|
|
13
|
+
# <% end %>
|
|
14
|
+
#
|
|
15
|
+
# To open the modal from elsewhere on the page (or to have multiple
|
|
16
|
+
# triggers), give it a known +id:+ and add +data-l-ui-modal-open="<id>"+
|
|
17
|
+
# to any button. The button does not need to live inside the helper's
|
|
18
|
+
# wrapper; the +l-ui--modal+ controller listens at the document level
|
|
19
|
+
# for matching clicks.
|
|
20
|
+
#
|
|
21
|
+
# <button type="button" data-l-ui-modal-open="confirm-modal">Open</button>
|
|
22
|
+
#
|
|
23
|
+
# Calling +dialog.showModal()+ directly is not supported: it bypasses the
|
|
24
|
+
# +l-ui--modal+ controller and skips scroll lock, focus restoration, open-
|
|
25
|
+
# count tracking, and the screen-reader announcement.
|
|
26
|
+
#
|
|
27
|
+
# Note: use +<% m.trigger %>+ (without the equals sign) so its content is
|
|
28
|
+
# captured by the builder rather than written to the body buffer.
|
|
29
|
+
#
|
|
30
|
+
# Options:
|
|
31
|
+
# title: (String) Required. Modal heading; also used for aria-labelledby.
|
|
32
|
+
# id: (String) DOM id for the <dialog>; defaults to an auto-generated id.
|
|
33
|
+
# heading_level: (Symbol) Heading tag for the title (e.g. :h2, :h3). Defaults to :h3.
|
|
34
|
+
# container: (Hash) Extra HTML attributes for the wrapping <div>.
|
|
35
|
+
def l_ui_modal(title:, id: nil, heading_level: :h3, container: {}, &block)
|
|
36
|
+
id ||= "l-ui-modal-#{SecureRandom.hex(4)}"
|
|
37
|
+
builder = ModalBuilder.new(self, title: title, id: id, heading_level: heading_level)
|
|
38
|
+
body_content = capture { block.call(builder) }
|
|
39
|
+
|
|
40
|
+
container_attrs = container.deep_dup
|
|
41
|
+
container_data = container_attrs[:data] || {}
|
|
42
|
+
existing_controller = container_data.delete(:controller) || container_data.delete("controller")
|
|
43
|
+
container_data[:controller] = [existing_controller, "l-ui--modal"].compact.reject(&:empty?).join(" ")
|
|
44
|
+
container_attrs[:data] = container_data
|
|
45
|
+
|
|
46
|
+
tag.div(**container_attrs) do
|
|
47
|
+
safe_join([
|
|
48
|
+
builder.trigger_html || ActiveSupport::SafeBuffer.new,
|
|
49
|
+
render_modal_dialog(builder, body_content)
|
|
50
|
+
])
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
class ModalBuilder
|
|
55
|
+
attr_reader :title, :id, :heading_level, :trigger_html
|
|
56
|
+
|
|
57
|
+
def initialize(view, title:, id:, heading_level: :h3)
|
|
58
|
+
@view = view
|
|
59
|
+
@title = title
|
|
60
|
+
@id = id
|
|
61
|
+
@heading_level = heading_level
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def trigger(**options, &block)
|
|
65
|
+
options = options.deep_dup
|
|
66
|
+
options[:type] ||= "button"
|
|
67
|
+
data = options[:data] || {}
|
|
68
|
+
existing_action = data.delete(:action) || data.delete("action")
|
|
69
|
+
data[:action] = [existing_action, "l-ui--modal#open"].compact.reject(&:empty?).join(" ")
|
|
70
|
+
options[:data] = data
|
|
71
|
+
content = @view.capture(&block)
|
|
72
|
+
@trigger_html = @view.tag.button(content, **options)
|
|
73
|
+
nil
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
private
|
|
78
|
+
|
|
79
|
+
def render_modal_dialog(builder, body_content)
|
|
80
|
+
heading_id = "#{builder.id}-heading"
|
|
81
|
+
|
|
82
|
+
dialog_attrs = {
|
|
83
|
+
id: builder.id,
|
|
84
|
+
class: "l-ui-modal",
|
|
85
|
+
data: {
|
|
86
|
+
"l-ui--modal-target" => "dialog",
|
|
87
|
+
"action" => "click->l-ui--modal#closeOnBackdrop"
|
|
88
|
+
},
|
|
89
|
+
aria: { labelledby: heading_id }
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
tag.dialog(**dialog_attrs) do
|
|
93
|
+
safe_join([
|
|
94
|
+
tag.div(class: "l-ui-modal__header") do
|
|
95
|
+
safe_join([
|
|
96
|
+
content_tag(builder.heading_level, builder.title, id: heading_id),
|
|
97
|
+
tag.button(
|
|
98
|
+
image_tag("layered_ui/icon_close.svg", alt: "", class: "l-ui-icon l-ui-icon--sm", aria: { hidden: true }),
|
|
99
|
+
class: "l-ui-button l-ui-button--icon",
|
|
100
|
+
type: "button",
|
|
101
|
+
data: { action: "l-ui--modal#close" },
|
|
102
|
+
"aria-label" => "Close"
|
|
103
|
+
)
|
|
104
|
+
])
|
|
105
|
+
end,
|
|
106
|
+
tag.div(body_content, class: "l-ui-modal__body")
|
|
107
|
+
])
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
@@ -57,7 +57,8 @@ export default class extends Controller {
|
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
// Handle the close event on the dialog
|
|
60
|
+
// Handle the close event on the dialog and document-level clicks from
|
|
61
|
+
// external triggers (any button with data-l-ui-modal-open="<dialog id>").
|
|
61
62
|
dialogTargetConnected(element) {
|
|
62
63
|
this._closeHandler = () => {
|
|
63
64
|
this.constructor.openCount = Math.max(0, this.constructor.openCount - 1)
|
|
@@ -71,11 +72,21 @@ export default class extends Controller {
|
|
|
71
72
|
announce("Dialog closed", this)
|
|
72
73
|
}
|
|
73
74
|
element.addEventListener("close", this._closeHandler)
|
|
75
|
+
|
|
76
|
+
this._externalOpenHandler = (event) => {
|
|
77
|
+
if (!element.id) return
|
|
78
|
+
const trigger = event.target.closest(`[data-l-ui-modal-open="${CSS.escape(element.id)}"]`)
|
|
79
|
+
if (!trigger) return
|
|
80
|
+
event.preventDefault()
|
|
81
|
+
this.open()
|
|
82
|
+
}
|
|
83
|
+
document.addEventListener("click", this._externalOpenHandler)
|
|
74
84
|
}
|
|
75
85
|
|
|
76
|
-
// Remove
|
|
86
|
+
// Remove listeners
|
|
77
87
|
dialogTargetDisconnected(element) {
|
|
78
88
|
element.removeEventListener("close", this._closeHandler)
|
|
89
|
+
document.removeEventListener("click", this._externalOpenHandler)
|
|
79
90
|
}
|
|
80
91
|
|
|
81
92
|
disconnect() {
|
|
@@ -7,6 +7,12 @@
|
|
|
7
7
|
<%= yield(:l_ui_logo_dark).presence || image_tag("layered_ui/logo_dark.svg", alt: "", class: "l-ui-header__logo l-ui-header__logo--dark") %>
|
|
8
8
|
<% end %>
|
|
9
9
|
|
|
10
|
+
<% if yield(:l_ui_header_links).present? %>
|
|
11
|
+
<nav class="l-ui-header__links" aria-label="Sections">
|
|
12
|
+
<%= yield(:l_ui_header_links) %>
|
|
13
|
+
</nav>
|
|
14
|
+
<% end %>
|
|
15
|
+
|
|
10
16
|
<nav class="l-ui-header__navigation" aria-label="Header navigation">
|
|
11
17
|
<button
|
|
12
18
|
type="button"
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
|
|
36
36
|
<div class="l-ui-panel__header-actions">
|
|
37
37
|
<button type="button"
|
|
38
|
-
class="l-ui-button l-ui-button--
|
|
38
|
+
class="l-ui-button l-ui-button--primary l-ui-button--icon"
|
|
39
39
|
aria-label="Hide panel"
|
|
40
40
|
aria-controls="panel"
|
|
41
41
|
title="Toggle panel (Ctrl+i / ⌘i)"
|
data/lib/layered/ui/engine.rb
CHANGED
data/lib/layered/ui/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: layered-ui-rails
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.16.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- layered.ai
|
|
@@ -213,6 +213,7 @@ files:
|
|
|
213
213
|
- app/helpers/layered/ui/authentication_helper.rb
|
|
214
214
|
- app/helpers/layered/ui/breadcrumbs_helper.rb
|
|
215
215
|
- app/helpers/layered/ui/form_helper.rb
|
|
216
|
+
- app/helpers/layered/ui/modal_helper.rb
|
|
216
217
|
- app/helpers/layered/ui/navigation_helper.rb
|
|
217
218
|
- app/helpers/layered/ui/pagy_helper.rb
|
|
218
219
|
- app/helpers/layered/ui/ransack_helper.rb
|