lostcoords-ui 0.4.1 → 0.5.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/README.md +303 -89
- data/app/assets/tailwind/lostcoords/ui/avatar.css +6 -6
- data/app/assets/tailwind/lostcoords/ui/base.css +45 -0
- data/app/assets/tailwind/lostcoords/ui/card.css +20 -22
- data/app/assets/tailwind/lostcoords/ui/choice.css +39 -0
- data/app/assets/tailwind/lostcoords/ui/code-block.css +10 -0
- data/app/assets/tailwind/lostcoords/ui/components.css +25 -0
- data/app/assets/tailwind/lostcoords/ui/copy-button.css +9 -9
- data/app/assets/tailwind/lostcoords/ui/dialog.css +17 -17
- data/app/assets/tailwind/lostcoords/ui/disclosure.css +5 -5
- data/app/assets/tailwind/lostcoords/ui/emoji-picker.css +43 -43
- data/app/assets/tailwind/lostcoords/ui/field.css +2 -2
- data/app/assets/tailwind/lostcoords/ui/glass.css +9 -8
- data/app/assets/tailwind/lostcoords/ui/layout.css +2 -2
- data/app/assets/tailwind/lostcoords/ui/popover.css +14 -14
- data/app/assets/tailwind/lostcoords/ui/reading.css +24 -24
- data/app/assets/tailwind/lostcoords/ui/sheet.css +60 -60
- data/app/assets/tailwind/lostcoords/ui/squircle.css +7 -27
- data/app/assets/tailwind/lostcoords/ui/table.css +51 -0
- data/app/assets/tailwind/lostcoords/ui/theme.css +194 -225
- data/app/assets/tailwind/lostcoords/ui/tooltip.css +50 -0
- data/app/assets/tailwind/lostcoords/ui/typography.css +37 -61
- data/app/assets/tailwind/lostcoords/ui/ui.css +2 -21
- data/app/assets/tailwind/lostcoords/ui/utilities.css +14 -22
- data/app/helpers/lostcoords/ui/badge_helper.rb +67 -110
- data/app/helpers/lostcoords/ui/button_helper.rb +36 -33
- data/app/helpers/lostcoords/ui/card_helper.rb +9 -52
- data/app/helpers/lostcoords/ui/choice_helper.rb +83 -0
- data/app/helpers/lostcoords/ui/code_block_helper.rb +22 -0
- data/app/helpers/lostcoords/ui/copy_button_helper.rb +7 -7
- data/app/helpers/lostcoords/ui/description_list_helper.rb +12 -0
- data/app/helpers/lostcoords/ui/dialog_helper.rb +6 -13
- data/app/helpers/lostcoords/ui/feedback_helper.rb +25 -6
- data/app/helpers/lostcoords/ui/form_helper.rb +36 -59
- data/app/helpers/lostcoords/ui/glass_helper.rb +7 -7
- data/app/helpers/lostcoords/ui/layout_helper.rb +13 -11
- data/app/helpers/lostcoords/ui/menu_helper.rb +8 -8
- data/app/helpers/lostcoords/ui/navigation_helper.rb +131 -0
- data/app/helpers/lostcoords/ui/overlay_helper.rb +17 -0
- data/app/helpers/lostcoords/ui/primitives_helper.rb +39 -61
- data/app/helpers/lostcoords/ui/reading_helper.rb +2 -2
- data/app/helpers/lostcoords/ui/sheet_helper.rb +3 -45
- data/app/helpers/lostcoords/ui/structures_helper.rb +55 -64
- data/app/helpers/lostcoords/ui/table_helper.rb +11 -0
- data/app/helpers/lostcoords/ui/tailwind_helper.rb +13 -4
- data/app/helpers/lostcoords/ui/typography_helper.rb +11 -11
- data/app/javascript/lostcoords/ui/controllers/lc_code_block_controller.js +23 -0
- data/app/javascript/lostcoords/ui/controllers/{disclosure_controller.js → lc_collapsible_controller.js} +3 -3
- data/app/javascript/lostcoords/ui/controllers/{confirm_dialog_controller.js → lc_confirm_dialog_controller.js} +4 -4
- data/app/javascript/lostcoords/ui/controllers/{modal_controller.js → lc_dialog_controller.js} +1 -1
- data/app/javascript/lostcoords/ui/controllers/{emoji_picker_controller.js → lc_emoji_picker_controller.js} +4 -4
- data/app/javascript/lostcoords/ui/controllers/{row_menu_controller.js → lc_menu_controller.js} +3 -3
- data/app/javascript/lostcoords/ui/controllers/{ui_popover_controller.js → lc_popover_controller.js} +1 -1
- data/app/javascript/lostcoords/ui/controllers/{ui_selection_controller.js → lc_selection_controller.js} +1 -1
- data/app/javascript/lostcoords/ui/controllers/{sheet_controller.js → lc_sheet_controller.js} +15 -15
- data/app/javascript/lostcoords/ui/controllers/lc_tabs_controller.js +39 -0
- data/app/javascript/lostcoords/ui/controllers/{toast_controller.js → lc_toast_controller.js} +2 -2
- data/app/javascript/lostcoords/ui/controllers/lc_tooltip_controller.js +14 -0
- data/app/javascript/lostcoords/ui/helpers/catalog_picker.js +5 -5
- data/app/javascript/lostcoords/ui/helpers/context_dialog.js +6 -6
- data/app/javascript/lostcoords/ui/helpers/dialog.js +2 -2
- data/app/javascript/lostcoords/ui/helpers/dismiss_stack.js +7 -7
- data/app/javascript/lostcoords/ui/helpers/floating_panel.js +2 -2
- data/app/javascript/lostcoords/ui/helpers/sheet_motion.js +4 -4
- data/app/javascript/lostcoords/ui/index.js +51 -0
- data/app/views/lostcoords/ui/components/_emoji_picker.html.erb +30 -30
- data/app/views/lostcoords/ui/components/_lc_code_block.html.erb +18 -0
- data/app/views/lostcoords/ui/components/_lc_collapsible.html.erb +5 -0
- data/app/views/lostcoords/ui/components/_lc_dialog.html.erb +11 -8
- data/app/views/lostcoords/ui/components/_lc_floating_panel.html.erb +8 -0
- data/config/helper_renames.json +23 -25
- data/config/importmap.rb +10 -2
- data/config/locales/en.yml +23 -0
- data/config/locales/es.yml +23 -0
- data/config/locales/ja.yml +23 -0
- data/lib/lostcoords/ui/action_view.rb +5 -3
- data/lib/lostcoords/ui/builders.rb +1 -1
- data/lib/lostcoords/ui/form_builder.rb +113 -0
- data/lib/lostcoords/ui/parts.rb +154 -0
- data/lib/lostcoords/ui/tokens.rb +24 -1
- data/lib/lostcoords/ui/version.rb +1 -1
- metadata +33 -17
- data/app/views/lostcoords/ui/components/_form_alert.html.erb +0 -4
- data/app/views/lostcoords/ui/components/_lc_disclosure.html.erb +0 -5
- data/app/views/lostcoords/ui/components/_skeleton.html.erb +0 -4
- data/app/views/lostcoords/ui/components/_spinner.html.erb +0 -10
- data/app/views/lostcoords/ui/components/_ui_floating_panel.html.erb +0 -8
- /data/app/javascript/lostcoords/ui/controllers/{ui_copy_controller.js → lc_copy_controller.js} +0 -0
- /data/app/javascript/lostcoords/ui/controllers/{ui_toggle_controller.js → lc_toggle_controller.js} +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { CatalogPicker } from "helpers/catalog_picker"
|
|
2
|
-
import { prefersReducedMotion } from "helpers/viewport"
|
|
1
|
+
import { CatalogPicker } from "lostcoords/ui/helpers/catalog_picker"
|
|
2
|
+
import { prefersReducedMotion } from "lostcoords/ui/helpers/viewport"
|
|
3
3
|
|
|
4
4
|
const TONE_MODIFIERS = ["", "\u{1F3FB}", "\u{1F3FC}", "\u{1F3FD}", "\u{1F3FE}", "\u{1F3FF}"]
|
|
5
|
-
const TONE_STORAGE_KEY = "lostcoords_ui:emoji-picker:tone"
|
|
5
|
+
const TONE_STORAGE_KEY = "lostcoords_ui:lc-emoji-picker:tone"
|
|
6
6
|
|
|
7
7
|
function markCurrent(element, current) {
|
|
8
8
|
element.setAttribute("aria-current", String(current))
|
|
@@ -322,7 +322,7 @@ export default class extends CatalogPicker {
|
|
|
322
322
|
return {
|
|
323
323
|
duration,
|
|
324
324
|
settle: duration && 280,
|
|
325
|
-
transition: "transform 260ms var(--ease-out-expo, ease-out)",
|
|
325
|
+
transition: "transform 260ms var(--lc-ease-out-expo, ease-out)",
|
|
326
326
|
offscreen: "translateY(100%)",
|
|
327
327
|
}
|
|
328
328
|
}
|
data/app/javascript/lostcoords/ui/controllers/{row_menu_controller.js → lc_menu_controller.js}
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { FloatingPanel } from "helpers/floating_panel"
|
|
2
|
-
import { focusFirstMenuItem, navigateMenu } from "helpers/menu_keys"
|
|
1
|
+
import { FloatingPanel } from "lostcoords/ui/helpers/floating_panel"
|
|
2
|
+
import { focusFirstMenuItem, navigateMenu } from "lostcoords/ui/helpers/menu_keys"
|
|
3
3
|
|
|
4
4
|
// The phone dock's action stack lays itself out over the fixed nav, so it
|
|
5
5
|
// passes lift: false and stays in place instead of lifting into the top layer.
|
|
@@ -29,7 +29,7 @@ export default class extends FloatingPanel {
|
|
|
29
29
|
|
|
30
30
|
toggleFromRow(event) {
|
|
31
31
|
if (this.popoverTarget.contains(event.target)) return
|
|
32
|
-
if (event.target.closest("a, button, input, select, textarea, [data-
|
|
32
|
+
if (event.target.closest("a, button, input, select, textarea, [data-lc-menu-ignore]")) return
|
|
33
33
|
|
|
34
34
|
event.preventDefault()
|
|
35
35
|
this.isOpen ? this.close() : this.open()
|
|
@@ -22,7 +22,7 @@ export default class extends Controller {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
select(event) {
|
|
25
|
-
const option = event.target.closest('[data-
|
|
25
|
+
const option = event.target.closest('[data-lc-selection-target~="option"]')
|
|
26
26
|
if (!this.options.includes(option)) return
|
|
27
27
|
this.apply(option)
|
|
28
28
|
this.changed(option)
|
data/app/javascript/lostcoords/ui/controllers/{sheet_controller.js → lc_sheet_controller.js}
RENAMED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { Controller } from "@hotwired/stimulus"
|
|
2
|
-
import { holdDocumentScroll } from "helpers/dismiss_stack"
|
|
3
|
-
import { SHEET_TIMING, sheetDuration } from "helpers/sheet_motion"
|
|
4
|
-
import { isSheetViewport, prefersReducedMotion, TEXT_ENTRY } from "helpers/viewport"
|
|
2
|
+
import { holdDocumentScroll } from "lostcoords/ui/helpers/dismiss_stack"
|
|
3
|
+
import { SHEET_TIMING, sheetDuration } from "lostcoords/ui/helpers/sheet_motion"
|
|
4
|
+
import { isSheetViewport, prefersReducedMotion, TEXT_ENTRY } from "lostcoords/ui/helpers/viewport"
|
|
5
5
|
|
|
6
6
|
const PROJECTION_MS = 180
|
|
7
7
|
const MEDIUM_FRACTION = 0.5
|
|
8
8
|
const PAGE_SCALE_LOSS = 0.06
|
|
9
|
-
const NO_DRAG = "input[type=range], [data-sheet-no-drag]"
|
|
10
|
-
const HANDLE = "[data-sheet-target~='handle']"
|
|
9
|
+
const NO_DRAG = "input[type=range], [data-lc-sheet-no-drag]"
|
|
10
|
+
const HANDLE = "[data-lc-sheet-target~='handle']"
|
|
11
11
|
const GRABBER_ZONE = 28
|
|
12
12
|
const KEYBOARD_FREE = 0.5
|
|
13
13
|
|
|
@@ -71,9 +71,9 @@ export default class extends Controller {
|
|
|
71
71
|
// The keyboard rises over the sheet. Safari and in-app browsers shrink the
|
|
72
72
|
// page under it, which would drag a bottom-pinned sheet up and squash it, so
|
|
73
73
|
// the sheet is placed from the top at the height the screen had when it
|
|
74
|
-
// opened (see --sheet-floor in the CSS).
|
|
74
|
+
// opened (see --lc-sheet-floor in the CSS).
|
|
75
75
|
pinFloor() {
|
|
76
|
-
if (this.isSheet) this.element.style.setProperty("--sheet-floor", `${window.innerHeight}px`)
|
|
76
|
+
if (this.isSheet) this.element.style.setProperty("--lc-sheet-floor", `${window.innerHeight}px`)
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
closed() {
|
|
@@ -330,7 +330,7 @@ export default class extends Controller {
|
|
|
330
330
|
}
|
|
331
331
|
|
|
332
332
|
setLargeness(p) {
|
|
333
|
-
this.element.style.setProperty("--sheet-p", p.toFixed(3))
|
|
333
|
+
this.element.style.setProperty("--lc-sheet-p", p.toFixed(3))
|
|
334
334
|
}
|
|
335
335
|
|
|
336
336
|
setPage(p) {
|
|
@@ -339,12 +339,12 @@ export default class extends Controller {
|
|
|
339
339
|
if (p <= 0) return
|
|
340
340
|
this.releaseScroll = holdDocumentScroll()
|
|
341
341
|
const lockedTop = -parseFloat(document.body.style.top || "0")
|
|
342
|
-
root.style.setProperty("--sheet-page-origin", `${window.scrollY + lockedTop}px`)
|
|
342
|
+
root.style.setProperty("--lc-sheet-page-origin", `${window.scrollY + lockedTop}px`)
|
|
343
343
|
root.dataset.sheetPage = ""
|
|
344
344
|
this.ownsPage = true
|
|
345
345
|
}
|
|
346
|
-
root.style.setProperty("--sheet-page-p", p.toFixed(3))
|
|
347
|
-
root.style.setProperty("--sheet-page-scale", (1 - PAGE_SCALE_LOSS * p).toFixed(4))
|
|
346
|
+
root.style.setProperty("--lc-sheet-page-p", p.toFixed(3))
|
|
347
|
+
root.style.setProperty("--lc-sheet-page-scale", (1 - PAGE_SCALE_LOSS * p).toFixed(4))
|
|
348
348
|
}
|
|
349
349
|
|
|
350
350
|
animatePage(p) {
|
|
@@ -363,13 +363,13 @@ export default class extends Controller {
|
|
|
363
363
|
const root = document.documentElement
|
|
364
364
|
delete root.dataset.sheetPage
|
|
365
365
|
for (const name of ["p", "scale", "origin", "transition"])
|
|
366
|
-
root.style.removeProperty(`--sheet-page-${name}`)
|
|
366
|
+
root.style.removeProperty(`--lc-sheet-page-${name}`)
|
|
367
367
|
this.releaseScroll()
|
|
368
368
|
}
|
|
369
369
|
|
|
370
370
|
pageTransition(value = prefersReducedMotion() ? "0s" : SHEET_TIMING) {
|
|
371
371
|
if (this.ownsPage || value !== "0s")
|
|
372
|
-
document.documentElement.style.setProperty("--sheet-page-transition", value)
|
|
372
|
+
document.documentElement.style.setProperty("--lc-sheet-page-transition", value)
|
|
373
373
|
}
|
|
374
374
|
|
|
375
375
|
transition() {
|
|
@@ -396,8 +396,8 @@ export default class extends Controller {
|
|
|
396
396
|
style.transform = ""
|
|
397
397
|
style.willChange = ""
|
|
398
398
|
style.blockSize = ""
|
|
399
|
-
style.removeProperty("--sheet-p")
|
|
400
|
-
style.removeProperty("--sheet-floor")
|
|
399
|
+
style.removeProperty("--lc-sheet-p")
|
|
400
|
+
style.removeProperty("--lc-sheet-floor")
|
|
401
401
|
}
|
|
402
402
|
|
|
403
403
|
scrollerFor(target) {
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
|
2
|
+
|
|
3
|
+
// Tabs with automatic activation: arrow keys, Home and End move focus and select.
|
|
4
|
+
export default class extends Controller {
|
|
5
|
+
static targets = ["tab", "panel"]
|
|
6
|
+
|
|
7
|
+
select(event) {
|
|
8
|
+
this.show(event.currentTarget)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
navigate(event) {
|
|
12
|
+
const tabs = this.tabTargets.filter((tab) => !tab.disabled)
|
|
13
|
+
const index = tabs.indexOf(event.currentTarget)
|
|
14
|
+
const step = getComputedStyle(this.element).direction === "rtl" ? -1 : 1
|
|
15
|
+
const next = {
|
|
16
|
+
ArrowRight: index + step,
|
|
17
|
+
ArrowLeft: index - step,
|
|
18
|
+
Home: 0,
|
|
19
|
+
End: tabs.length - 1,
|
|
20
|
+
}[event.key]
|
|
21
|
+
if (next === undefined) return
|
|
22
|
+
|
|
23
|
+
event.preventDefault()
|
|
24
|
+
const tab = tabs[(next + tabs.length) % tabs.length]
|
|
25
|
+
tab.focus()
|
|
26
|
+
this.show(tab)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
show(tab) {
|
|
30
|
+
for (const candidate of this.tabTargets) {
|
|
31
|
+
const selected = candidate === tab
|
|
32
|
+
candidate.setAttribute("aria-selected", String(selected))
|
|
33
|
+
candidate.tabIndex = selected ? 0 : -1
|
|
34
|
+
}
|
|
35
|
+
const panelId = tab.getAttribute("aria-controls")
|
|
36
|
+
for (const panel of this.panelTargets) panel.hidden = panel.id !== panelId
|
|
37
|
+
this.dispatch("change", { detail: { value: tab.dataset.value } })
|
|
38
|
+
}
|
|
39
|
+
}
|
data/app/javascript/lostcoords/ui/controllers/{toast_controller.js → lc_toast_controller.js}
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Controller } from "@hotwired/stimulus"
|
|
2
|
-
import { prefersReducedMotion } from "helpers/viewport"
|
|
2
|
+
import { prefersReducedMotion } from "lostcoords/ui/helpers/viewport"
|
|
3
3
|
|
|
4
4
|
export default class extends Controller {
|
|
5
5
|
static values = { timeout: { type: Number, default: 4000 } }
|
|
@@ -7,7 +7,7 @@ export default class extends Controller {
|
|
|
7
7
|
connect() {
|
|
8
8
|
for (const sibling of this.element.parentElement?.children || []) {
|
|
9
9
|
if (sibling === this.element) continue
|
|
10
|
-
this.application.getControllerForElementAndIdentifier(sibling, "toast")?.dismiss()
|
|
10
|
+
this.application.getControllerForElementAndIdentifier(sibling, "lc-toast")?.dismiss()
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
this.startedAt = performance.now()
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
|
2
|
+
|
|
3
|
+
// Escape hides a visible tooltip without moving the pointer or focus. It shows
|
|
4
|
+
// again after the pointer leaves or focus moves away.
|
|
5
|
+
export default class extends Controller {
|
|
6
|
+
dismiss(event) {
|
|
7
|
+
if (event.key !== "Escape" || !this.element.matches(":hover, :focus-within")) return
|
|
8
|
+
this.element.dataset.dismissed = ""
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
reset() {
|
|
12
|
+
delete this.element.dataset.dismissed
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { holdDocumentScroll } from "helpers/dismiss_stack"
|
|
2
|
-
import { FloatingPanel } from "helpers/floating_panel"
|
|
3
|
-
import { SHEET_TIMING, sheetDuration } from "helpers/sheet_motion"
|
|
4
|
-
import { isSheetViewport } from "helpers/viewport"
|
|
1
|
+
import { holdDocumentScroll } from "lostcoords/ui/helpers/dismiss_stack"
|
|
2
|
+
import { FloatingPanel } from "lostcoords/ui/helpers/floating_panel"
|
|
3
|
+
import { SHEET_TIMING, sheetDuration } from "lostcoords/ui/helpers/sheet_motion"
|
|
4
|
+
import { isSheetViewport } from "lostcoords/ui/helpers/viewport"
|
|
5
5
|
|
|
6
6
|
const catalogs = new Map()
|
|
7
7
|
const MAX_RESULTS = 250
|
|
@@ -433,7 +433,7 @@ export class CatalogPicker extends FloatingPanel {
|
|
|
433
433
|
duration,
|
|
434
434
|
settle: duration,
|
|
435
435
|
transition: `transform ${SHEET_TIMING}`,
|
|
436
|
-
offscreen: "translateY(var(--sheet-offscreen))",
|
|
436
|
+
offscreen: "translateY(var(--lc-sheet-offscreen))",
|
|
437
437
|
}
|
|
438
438
|
}
|
|
439
439
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isSheetViewport } from "helpers/viewport"
|
|
1
|
+
import { isSheetViewport } from "lostcoords/ui/helpers/viewport"
|
|
2
2
|
|
|
3
3
|
const EDGE = 16
|
|
4
4
|
|
|
@@ -10,19 +10,19 @@ export function showContextDialog(dialog, menu) {
|
|
|
10
10
|
const corner = rect?.height
|
|
11
11
|
? { top: Math.max(EDGE, rect.bottom - dialog.offsetHeight), right: rect.right }
|
|
12
12
|
: null
|
|
13
|
-
if (anchorDialog(dialog, corner)) dialog.style.setProperty("--dialog-origin", "bottom right")
|
|
13
|
+
if (anchorDialog(dialog, corner)) dialog.style.setProperty("--lc-dialog-origin", "bottom right")
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
export function anchorDialog(dialog, corner) {
|
|
17
17
|
delete dialog.dataset.anchored
|
|
18
|
-
dialog.style.removeProperty("--dialog-top")
|
|
19
|
-
dialog.style.removeProperty("--dialog-right")
|
|
18
|
+
dialog.style.removeProperty("--lc-dialog-top")
|
|
19
|
+
dialog.style.removeProperty("--lc-dialog-right")
|
|
20
20
|
if (!corner || isSheetViewport()) return false
|
|
21
21
|
|
|
22
22
|
dialog.dataset.anchored = ""
|
|
23
|
-
dialog.style.setProperty("--dialog-top", `${corner.top}px`)
|
|
23
|
+
dialog.style.setProperty("--lc-dialog-top", `${corner.top}px`)
|
|
24
24
|
dialog.style.setProperty(
|
|
25
|
-
"--dialog-right",
|
|
25
|
+
"--lc-dialog-right",
|
|
26
26
|
`${Math.max(EDGE, window.innerWidth - corner.right)}px`,
|
|
27
27
|
)
|
|
28
28
|
return true
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { registerDismissable } from "helpers/dismiss_stack"
|
|
1
|
+
import { registerDismissable } from "lostcoords/ui/helpers/dismiss_stack"
|
|
2
2
|
|
|
3
3
|
const registrations = new WeakMap()
|
|
4
4
|
|
|
@@ -8,7 +8,7 @@ export function registerDialog(dialog, { close = () => dialog.close(), lockScrol
|
|
|
8
8
|
|
|
9
9
|
const unregisterDismissable = registerDismissable({
|
|
10
10
|
element: dialog,
|
|
11
|
-
type: "
|
|
11
|
+
type: "lc-dialog",
|
|
12
12
|
lockScroll,
|
|
13
13
|
close,
|
|
14
14
|
isOpen: () => dialog.open,
|
|
@@ -3,9 +3,8 @@ let nextOrder = 0
|
|
|
3
3
|
let lockedScrollY = 0
|
|
4
4
|
let scrollHolds = 0
|
|
5
5
|
|
|
6
|
-
document.addEventListener("keydown", dismissOnEscape, true)
|
|
7
|
-
|
|
8
6
|
export function registerDismissable(options) {
|
|
7
|
+
if (stack.length === 0) document.addEventListener("keydown", dismissOnEscape, true)
|
|
9
8
|
const entry = {
|
|
10
9
|
type: "panel",
|
|
11
10
|
isOpen: defaultIsOpen,
|
|
@@ -17,7 +16,7 @@ export function registerDismissable(options) {
|
|
|
17
16
|
stack.push(entry)
|
|
18
17
|
syncModalScrollLock()
|
|
19
18
|
|
|
20
|
-
if (entry.type === "
|
|
19
|
+
if (entry.type === "lc-dialog" && entry.element instanceof HTMLDialogElement) {
|
|
21
20
|
entry.cancel = (event) => cancelDialog(event, entry)
|
|
22
21
|
entry.element.addEventListener("cancel", entry.cancel)
|
|
23
22
|
}
|
|
@@ -81,7 +80,7 @@ function topDismissable(scope = topModal()?.element) {
|
|
|
81
80
|
|
|
82
81
|
function topModal() {
|
|
83
82
|
return openEntries()
|
|
84
|
-
.filter((entry) => entry.type === "
|
|
83
|
+
.filter((entry) => entry.type === "lc-dialog")
|
|
85
84
|
.at(-1)
|
|
86
85
|
}
|
|
87
86
|
|
|
@@ -92,6 +91,7 @@ function openEntries() {
|
|
|
92
91
|
function unregisterDismissable(entry) {
|
|
93
92
|
const index = stack.indexOf(entry)
|
|
94
93
|
if (index >= 0) stack.splice(index, 1)
|
|
94
|
+
if (stack.length === 0) document.removeEventListener("keydown", dismissOnEscape, true)
|
|
95
95
|
|
|
96
96
|
if (entry.cancel) {
|
|
97
97
|
entry.element.removeEventListener("cancel", entry.cancel)
|
|
@@ -116,7 +116,7 @@ function priorityFor(type) {
|
|
|
116
116
|
function syncModalScrollLock() {
|
|
117
117
|
if (
|
|
118
118
|
scrollHolds > 0 ||
|
|
119
|
-
openEntries().some((entry) => entry.type === "
|
|
119
|
+
openEntries().some((entry) => entry.type === "lc-dialog" && entry.lockScroll !== false)
|
|
120
120
|
) {
|
|
121
121
|
lockDocumentScroll()
|
|
122
122
|
return
|
|
@@ -136,7 +136,7 @@ function lockDocumentScroll() {
|
|
|
136
136
|
body.style.top = `-${lockedScrollY}px`
|
|
137
137
|
// Pinning the body drags the sticky nav off with the scrolled-away page;
|
|
138
138
|
// the nav offsets itself by this to stay where it was.
|
|
139
|
-
body.style.setProperty("--scroll-lock-y", `${lockedScrollY}px`)
|
|
139
|
+
body.style.setProperty("--lc-scroll-lock-y", `${lockedScrollY}px`)
|
|
140
140
|
body.style.inlineSize = "100%"
|
|
141
141
|
}
|
|
142
142
|
|
|
@@ -147,7 +147,7 @@ function unlockDocumentScroll() {
|
|
|
147
147
|
body.style.position = ""
|
|
148
148
|
body.style.inset = ""
|
|
149
149
|
body.style.top = ""
|
|
150
|
-
body.style.removeProperty("--scroll-lock-y")
|
|
150
|
+
body.style.removeProperty("--lc-scroll-lock-y")
|
|
151
151
|
body.style.inlineSize = ""
|
|
152
152
|
delete body.dataset.modalScrollLock
|
|
153
153
|
window.scrollTo({ top: lockedScrollY, behavior: "instant" })
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Controller } from "@hotwired/stimulus"
|
|
2
|
-
import { registerDismissable } from "helpers/dismiss_stack"
|
|
3
|
-
import { liftToTopLayer } from "helpers/top_layer"
|
|
2
|
+
import { registerDismissable } from "lostcoords/ui/helpers/dismiss_stack"
|
|
3
|
+
import { liftToTopLayer } from "lostcoords/ui/helpers/top_layer"
|
|
4
4
|
|
|
5
5
|
const BEFORE_OPEN = "overlay:before-open"
|
|
6
6
|
const PAGE_LEAVES = ["turbo:before-cache", "turbo:before-visit", "turbo:before-render"]
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { prefersReducedMotion } from "helpers/viewport"
|
|
2
|
-
// The sheet beat lives in CSS (--sheet-duration, --ease-sheet) so CSS- and
|
|
1
|
+
import { prefersReducedMotion } from "lostcoords/ui/helpers/viewport"
|
|
2
|
+
// The sheet beat lives in CSS (--lc-sheet-duration, --lc-ease-sheet) so CSS- and
|
|
3
3
|
// JS-driven slides can't drift apart. Inline transitions use the variables
|
|
4
4
|
// directly; timers need the duration in milliseconds.
|
|
5
|
-
export const SHEET_TIMING = "var(--sheet-duration) var(--ease-sheet)"
|
|
5
|
+
export const SHEET_TIMING = "var(--lc-sheet-duration) var(--lc-ease-sheet)"
|
|
6
6
|
|
|
7
7
|
export function sheetDuration() {
|
|
8
8
|
if (prefersReducedMotion()) return 0
|
|
9
9
|
const value = getComputedStyle(document.documentElement)
|
|
10
|
-
.getPropertyValue("--sheet-duration")
|
|
10
|
+
.getPropertyValue("--lc-sheet-duration")
|
|
11
11
|
.trim()
|
|
12
12
|
return value.endsWith("ms") ? parseFloat(value) : parseFloat(value) * 1000
|
|
13
13
|
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import CodeBlock from "lostcoords/ui/controllers/lc_code_block_controller"
|
|
2
|
+
import Collapsible from "lostcoords/ui/controllers/lc_collapsible_controller"
|
|
3
|
+
import ConfirmDialog from "lostcoords/ui/controllers/lc_confirm_dialog_controller"
|
|
4
|
+
import Copy from "lostcoords/ui/controllers/lc_copy_controller"
|
|
5
|
+
import Dialog from "lostcoords/ui/controllers/lc_dialog_controller"
|
|
6
|
+
import EmojiPicker from "lostcoords/ui/controllers/lc_emoji_picker_controller"
|
|
7
|
+
import Menu from "lostcoords/ui/controllers/lc_menu_controller"
|
|
8
|
+
import Popover from "lostcoords/ui/controllers/lc_popover_controller"
|
|
9
|
+
import Selection from "lostcoords/ui/controllers/lc_selection_controller"
|
|
10
|
+
import Sheet from "lostcoords/ui/controllers/lc_sheet_controller"
|
|
11
|
+
import Tabs from "lostcoords/ui/controllers/lc_tabs_controller"
|
|
12
|
+
import Toast from "lostcoords/ui/controllers/lc_toast_controller"
|
|
13
|
+
import Toggle from "lostcoords/ui/controllers/lc_toggle_controller"
|
|
14
|
+
import Tooltip from "lostcoords/ui/controllers/lc_tooltip_controller"
|
|
15
|
+
|
|
16
|
+
const controllers = {
|
|
17
|
+
"lc-confirm-dialog": ConfirmDialog,
|
|
18
|
+
"lc-collapsible": Collapsible,
|
|
19
|
+
"lc-code-block": CodeBlock,
|
|
20
|
+
"lc-copy": Copy,
|
|
21
|
+
"lc-dialog": Dialog,
|
|
22
|
+
"lc-emoji-picker": EmojiPicker,
|
|
23
|
+
"lc-menu": Menu,
|
|
24
|
+
"lc-popover": Popover,
|
|
25
|
+
"lc-selection": Selection,
|
|
26
|
+
"lc-sheet": Sheet,
|
|
27
|
+
"lc-tabs": Tabs,
|
|
28
|
+
"lc-toast": Toast,
|
|
29
|
+
"lc-toggle": Toggle,
|
|
30
|
+
"lc-tooltip": Tooltip,
|
|
31
|
+
}
|
|
32
|
+
const registrations = new WeakMap()
|
|
33
|
+
|
|
34
|
+
export function registerControllers(application, { only = Object.keys(controllers) } = {}) {
|
|
35
|
+
if (!Array.isArray(only)) throw new TypeError("only must be an array of controller identifiers")
|
|
36
|
+
for (const identifier of only) {
|
|
37
|
+
if (!Object.hasOwn(controllers, identifier)) {
|
|
38
|
+
throw new Error(`Unknown lostcoords-ui controller: ${identifier}`)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
let registered = registrations.get(application)
|
|
42
|
+
if (!registered) {
|
|
43
|
+
registered = new Set()
|
|
44
|
+
registrations.set(application, registered)
|
|
45
|
+
}
|
|
46
|
+
for (const identifier of only) {
|
|
47
|
+
if (registered.has(identifier)) continue
|
|
48
|
+
application.register(identifier, controllers[identifier])
|
|
49
|
+
registered.add(identifier)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
tone_modifiers = [ "", "🏻", "🏼", "🏽", "🏾", "🏿" ]
|
|
8
8
|
tone_names = %w[default light medium_light medium medium_dark dark] %>
|
|
9
9
|
|
|
10
|
-
<%= tag.div(**lc_attributes({ class: lc_tw("emoji-picker", picker_class), data: { controller: "emoji-picker",
|
|
10
|
+
<%= tag.div(**lc_attributes({ class: lc_tw("lc-emoji-picker", picker_class), data: { controller: "lc-emoji-picker", lc_emoji_picker_auto_submit_value: auto_submit, lc_emoji_picker_catalog_url_value: catalog_url, lc_emoji_picker_recent_scope_value: recent_scope } }, attributes)) do %>
|
|
11
11
|
<%= form.hidden_field field,
|
|
12
12
|
value: selected,
|
|
13
|
-
data: {
|
|
13
|
+
data: { lc_emoji_picker_target: "input" } %>
|
|
14
14
|
|
|
15
15
|
<% quick.each do |emoji| %>
|
|
16
16
|
<button
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
class="emoji-picker__choice"
|
|
19
19
|
aria-current="<%= emoji == selected %>"
|
|
20
20
|
data-emoji="<%= emoji %>"
|
|
21
|
-
data-action="click->emoji-picker#select"
|
|
21
|
+
data-action="click->lc-emoji-picker#select"
|
|
22
22
|
>
|
|
23
23
|
<%= emoji %>
|
|
24
24
|
</button>
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
type="button"
|
|
30
30
|
class="emoji-picker__trigger <%= trigger_class %>"
|
|
31
31
|
aria-current="<%= !selected_is_quick %>"
|
|
32
|
-
data-emoji-picker-target="trigger"
|
|
33
|
-
data-action="click->emoji-picker#toggle"
|
|
32
|
+
data-lc-emoji-picker-target="trigger"
|
|
33
|
+
data-action="click->lc-emoji-picker#toggle"
|
|
34
34
|
data-default-label="+"
|
|
35
35
|
data-value="<%= selected %>"
|
|
36
36
|
aria-label="<%= label %>"
|
|
@@ -41,14 +41,14 @@
|
|
|
41
41
|
|
|
42
42
|
<div
|
|
43
43
|
class="emoji-picker__popover <%= popover_class %>"
|
|
44
|
-
data-emoji-picker-target="popover"
|
|
45
|
-
data-controller="sheet"
|
|
46
|
-
data-action="click->emoji-picker#select pointerover->emoji-picker#preview focusin->emoji-picker#preview sheet:dismiss->emoji-picker#close"
|
|
44
|
+
data-lc-emoji-picker-target="popover"
|
|
45
|
+
data-controller="lc-sheet"
|
|
46
|
+
data-action="click->lc-emoji-picker#select pointerover->lc-emoji-picker#preview focusin->lc-emoji-picker#preview lc-sheet:dismiss->lc-emoji-picker#close"
|
|
47
47
|
role="dialog"
|
|
48
48
|
aria-label="<%= label %>"
|
|
49
49
|
hidden
|
|
50
50
|
>
|
|
51
|
-
<span class="emoji-picker__handle" data-sheet-target="handle" aria-hidden="true"></span>
|
|
51
|
+
<span class="emoji-picker__handle" data-lc-sheet-target="handle" aria-hidden="true"></span>
|
|
52
52
|
|
|
53
53
|
<div class="emoji-picker__search">
|
|
54
54
|
<div class="emoji-picker__search-field">
|
|
@@ -67,30 +67,30 @@
|
|
|
67
67
|
enterkeyhint="search"
|
|
68
68
|
aria-label="<%= lc_t("lostcoords.ui.emoji_picker.search_label") %>"
|
|
69
69
|
placeholder="<%= lc_t("lostcoords.ui.emoji_picker.search_placeholder") %>"
|
|
70
|
-
data-emoji-picker-target="searchInput"
|
|
71
|
-
data-action="input->emoji-picker#filter keydown->emoji-picker#onSearchKeydown"
|
|
70
|
+
data-lc-emoji-picker-target="searchInput"
|
|
71
|
+
data-action="input->lc-emoji-picker#filter keydown->lc-emoji-picker#onSearchKeydown"
|
|
72
72
|
>
|
|
73
73
|
</div>
|
|
74
74
|
|
|
75
|
-
<div class="emoji-picker__tones" data-emoji-picker-target="tones">
|
|
75
|
+
<div class="emoji-picker__tones" data-lc-emoji-picker-target="tones">
|
|
76
76
|
<button
|
|
77
77
|
type="button"
|
|
78
78
|
class="emoji-picker__tone-toggle"
|
|
79
|
-
data-emoji-picker-target="toneToggle"
|
|
80
|
-
data-action="click->emoji-picker#toggleTones"
|
|
79
|
+
data-lc-emoji-picker-target="toneToggle"
|
|
80
|
+
data-action="click->lc-emoji-picker#toggleTones"
|
|
81
81
|
aria-haspopup="true"
|
|
82
82
|
aria-expanded="false"
|
|
83
83
|
aria-label="<%= lc_t("lostcoords.ui.emoji_picker.skin_tone") %>"
|
|
84
84
|
>✋</button>
|
|
85
85
|
|
|
86
|
-
<div class="emoji-picker__tone-menu <%= popover_class %>" data-emoji-picker-target="toneMenu" role="menu" hidden>
|
|
86
|
+
<div class="emoji-picker__tone-menu <%= popover_class %>" data-lc-emoji-picker-target="toneMenu" role="menu" hidden>
|
|
87
87
|
<% tone_modifiers.each_with_index do |modifier, index| %>
|
|
88
88
|
<button
|
|
89
89
|
type="button"
|
|
90
90
|
class="emoji-picker__tone"
|
|
91
91
|
role="menuitemradio"
|
|
92
92
|
data-tone-index="<%= index %>"
|
|
93
|
-
data-action="click->emoji-picker#selectTone"
|
|
93
|
+
data-action="click->lc-emoji-picker#selectTone"
|
|
94
94
|
aria-label="<%= lc_t("lostcoords.ui.emoji_picker.skin_tones.#{tone_names[index]}") %>"
|
|
95
95
|
>✋<%= modifier %></button>
|
|
96
96
|
<% end %>
|
|
@@ -98,14 +98,14 @@
|
|
|
98
98
|
</div>
|
|
99
99
|
</div>
|
|
100
100
|
|
|
101
|
-
<nav class="emoji-picker__tabs" data-emoji-picker-target="tabs" aria-label="<%= lc_t("lostcoords.ui.emoji_picker.categories_nav") %>">
|
|
101
|
+
<nav class="emoji-picker__tabs" data-lc-emoji-picker-target="tabs" aria-label="<%= lc_t("lostcoords.ui.emoji_picker.categories_nav") %>">
|
|
102
102
|
<% if recent.any? %>
|
|
103
103
|
<button
|
|
104
104
|
type="button"
|
|
105
105
|
class="emoji-picker__tab"
|
|
106
|
-
data-emoji-picker-target="tab"
|
|
106
|
+
data-lc-emoji-picker-target="tab"
|
|
107
107
|
data-target-section="recent"
|
|
108
|
-
data-action="click->emoji-picker#jumpTo"
|
|
108
|
+
data-action="click->lc-emoji-picker#jumpTo"
|
|
109
109
|
aria-label="<%= lc_t("lostcoords.ui.emoji_picker.recently_used") %>"
|
|
110
110
|
>🕘</button>
|
|
111
111
|
<% end %>
|
|
@@ -114,21 +114,21 @@
|
|
|
114
114
|
<button
|
|
115
115
|
type="button"
|
|
116
116
|
class="emoji-picker__tab"
|
|
117
|
-
data-emoji-picker-target="tab"
|
|
117
|
+
data-lc-emoji-picker-target="tab"
|
|
118
118
|
data-target-section="<%= group[:key] %>"
|
|
119
|
-
data-action="click->emoji-picker#jumpTo"
|
|
119
|
+
data-action="click->lc-emoji-picker#jumpTo"
|
|
120
120
|
aria-label="<%= group[:name] %>"
|
|
121
121
|
><%= group[:icon] %></button>
|
|
122
122
|
<% end %>
|
|
123
123
|
</nav>
|
|
124
124
|
|
|
125
|
-
<div class="emoji-picker__body" data-emoji-picker-target="body">
|
|
125
|
+
<div class="emoji-picker__body" data-lc-emoji-picker-target="body">
|
|
126
126
|
<% if recent.any? %>
|
|
127
127
|
<section
|
|
128
128
|
class="emoji-picker__recent"
|
|
129
129
|
data-section="recent"
|
|
130
130
|
aria-label="<%= lc_t('lostcoords.ui.emoji_picker.recently_used') %>"
|
|
131
|
-
data-emoji-picker-target="recent"
|
|
131
|
+
data-lc-emoji-picker-target="recent"
|
|
132
132
|
>
|
|
133
133
|
<header class="emoji-picker__category-head">
|
|
134
134
|
<h3><%= lc_t("lostcoords.ui.emoji_picker.recently_used") %></h3>
|
|
@@ -153,23 +153,23 @@
|
|
|
153
153
|
</section>
|
|
154
154
|
<% end %>
|
|
155
155
|
|
|
156
|
-
<section class="emoji-picker__results" data-emoji-picker-target="results" aria-label="<%= lc_t('lostcoords.ui.emoji_picker.search_results') %>" hidden>
|
|
156
|
+
<section class="emoji-picker__results" data-lc-emoji-picker-target="results" aria-label="<%= lc_t('lostcoords.ui.emoji_picker.search_results') %>" hidden>
|
|
157
157
|
<header class="emoji-picker__category-head">
|
|
158
158
|
<h3><%= lc_t("lostcoords.ui.emoji_picker.search_results") %></h3>
|
|
159
|
-
<span class="count" data-emoji-picker-target="resultsCount">0</span>
|
|
159
|
+
<span class="count" data-lc-emoji-picker-target="resultsCount">0</span>
|
|
160
160
|
</header>
|
|
161
161
|
|
|
162
|
-
<div class="emoji-picker__grid" data-emoji-picker-target="resultsGrid"></div>
|
|
162
|
+
<div class="emoji-picker__grid" data-lc-emoji-picker-target="resultsGrid"></div>
|
|
163
163
|
</section>
|
|
164
164
|
|
|
165
|
-
<p class="emoji-picker__empty" data-emoji-picker-target="empty" hidden>
|
|
165
|
+
<p class="emoji-picker__empty" data-lc-emoji-picker-target="empty" hidden>
|
|
166
166
|
<%= lc_t("lostcoords.ui.emoji_picker.no_results") %>
|
|
167
167
|
</p>
|
|
168
168
|
</div>
|
|
169
169
|
|
|
170
|
-
<footer class="emoji-picker__preview" data-emoji-picker-target="preview">
|
|
171
|
-
<span class="emoji-picker__preview-emoji" data-emoji-picker-target="previewEmoji"><%= selected %></span>
|
|
172
|
-
<span class="emoji-picker__preview-name" data-emoji-picker-target="previewName"><%= lc_emoji_picker_search_name(selected) %></span>
|
|
170
|
+
<footer class="emoji-picker__preview" data-lc-emoji-picker-target="preview">
|
|
171
|
+
<span class="emoji-picker__preview-emoji" data-lc-emoji-picker-target="previewEmoji"><%= selected %></span>
|
|
172
|
+
<span class="emoji-picker__preview-name" data-lc-emoji-picker-target="previewName"><%= lc_emoji_picker_search_name(selected) %></span>
|
|
173
173
|
</footer>
|
|
174
174
|
</div>
|
|
175
175
|
</div>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<%# locals: (id:, language:, title:, label:, content:, truncated:, max_lines:, attributes:) %>
|
|
2
|
+
<%= tag.div(**attributes) do %>
|
|
3
|
+
<% if title %>
|
|
4
|
+
<div class="flex h-10 items-center ps-inset pe-16 pt-inset">
|
|
5
|
+
<span class="truncate font-mono text-xs text-muted-foreground"><%= title %></span>
|
|
6
|
+
</div>
|
|
7
|
+
<% end %>
|
|
8
|
+
<div class="lc-code-block-copy absolute end-2 top-2 z-10 rounded-full bg-muted">
|
|
9
|
+
<%= lc_copy_button source: "#{id}-content", icon_only: true, variant: :ghost, size: :sm, aria: { label: lc_t("lostcoords.ui.code_block.copy", label: label) } %>
|
|
10
|
+
</div>
|
|
11
|
+
<div class="relative">
|
|
12
|
+
<pre id="<%= id %>-content" class="m-0 overflow-x-auto ps-inset pe-16 pb-inset font-mono text-[0.8125rem] text-muted-foreground [tab-size:2] <%= title ? 'pt-2 [--lc-code-block-padding:--spacing(7)]' : 'pt-inset [--lc-code-block-padding:--spacing(10)]' %> <%= 'max-h-[calc(var(--lc-code-block-lines)*1lh+var(--lc-code-block-padding))] overflow-y-hidden group-data-expanded/code-block:max-h-none' if truncated %>" style="<%= "--lc-code-block-lines: #{max_lines}" if truncated %>" tabindex="0" role="region" aria-label="<%= label %>"><%= tag.code(content, data: { language: language }) %></pre>
|
|
13
|
+
<% if truncated %><div class="pointer-events-none absolute inset-x-0 bottom-0 h-12 bg-linear-to-t from-muted to-transparent group-data-expanded/code-block:hidden" aria-hidden="true"></div><% end %>
|
|
14
|
+
</div>
|
|
15
|
+
<% if truncated %>
|
|
16
|
+
<%= lc_button lc_t("lostcoords.ui.code_block.expand"), variant: :ghost, size: :sm, class: "w-full rounded-none", aria: { expanded: false, controls: "#{id}-content" }, data: { action: "lc-code-block#toggle", lc_code_block_target: "toggle", expand_label: lc_t("lostcoords.ui.code_block.expand"), collapse_label: lc_t("lostcoords.ui.code_block.collapse") } %>
|
|
17
|
+
<% end %>
|
|
18
|
+
<% end %>
|
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
<%# locals: (id:, title:, trigger:, attributes:, content:) %>
|
|
2
|
-
<div data-controller="
|
|
3
|
-
<button type="button" class="<%= lc_button_class(variant: :secondary) %>" aria-haspopup="dialog" aria-controls="<%= id %>" data-action="
|
|
1
|
+
<%# locals: (id:, title:, description:, trigger:, attributes:, content:) %>
|
|
2
|
+
<div data-controller="lc-dialog">
|
|
3
|
+
<button type="button" class="<%= lc_button_class(variant: :secondary) %>" aria-haspopup="dialog" aria-controls="<%= id %>" data-action="lc-dialog#open" data-slot="dialog-trigger"><%= trigger %></button>
|
|
4
4
|
<%= tag.dialog(**attributes) do %>
|
|
5
|
-
<div class="flex flex-col gap-
|
|
6
|
-
<
|
|
7
|
-
<
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
<div class="flex flex-col gap-inset p-inset" data-slot="dialog-content">
|
|
6
|
+
<header class="flex items-start justify-between gap-content" data-slot="dialog-header">
|
|
7
|
+
<div class="flex min-w-0 flex-col gap-tight">
|
|
8
|
+
<h2 id="<%= id %>-title" class="<%= lc_heading_class(size: :subheading) %>" data-slot="dialog-title"><%= title %></h2>
|
|
9
|
+
<% if description.present? %><p id="<%= id %>-description" class="<%= lc_text_class(size: :small, tone: :muted) %>" data-slot="dialog-description"><%= description %></p><% end %>
|
|
10
|
+
</div>
|
|
11
|
+
<button type="button" class="<%= lc_icon_button_class(size: :sm, shape: :circle, extra: "-me-related -mt-tight") %>" aria-label="<%= lc_t("lostcoords.ui.dialog.close", title: title) %>" data-action="lc-dialog#close"><%= lc_icon "x-mark", options: { "aria-hidden": true } %></button>
|
|
12
|
+
</header>
|
|
10
13
|
<%= content %>
|
|
11
14
|
</div>
|
|
12
15
|
<% end %>
|