poetry-core 0.0.2
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 +7 -0
- data/CHANGELOG.md +3 -0
- data/DESIGN.md +145 -0
- data/LICENSE.txt +21 -0
- data/README.md +30 -0
- data/THIRD_PARTY_NOTICES.md +507 -0
- data/app/components/poetry/core/box/component.rb +82 -0
- data/app/components/poetry/core/component.rb +390 -0
- data/app/components/poetry/core/concerns/agent_tools.rb +418 -0
- data/app/components/poetry/core/concerns/declared_attributes.rb +267 -0
- data/app/components/poetry/core/concerns/introspection.rb +533 -0
- data/app/components/poetry/core/concerns/options.rb +262 -0
- data/app/components/poetry/core/concerns/parts.rb +148 -0
- data/app/components/poetry/core/concerns/stimulus.rb +363 -0
- data/app/components/poetry/core/concerns/styles.rb +323 -0
- data/app/components/poetry/core/style.rb +150 -0
- data/app/components/poetry/core/wrapper/component.rb +90 -0
- data/app/javascript/poetry/core/accordion_controller.js +165 -0
- data/app/javascript/poetry/core/action_bar_controller.js +109 -0
- data/app/javascript/poetry/core/autocomplete_controller.js +220 -0
- data/app/javascript/poetry/core/calendar_controller.js +406 -0
- data/app/javascript/poetry/core/carousel_controller.js +167 -0
- data/app/javascript/poetry/core/checkbox_group_controller.js +97 -0
- data/app/javascript/poetry/core/checked_controller.js +208 -0
- data/app/javascript/poetry/core/clipboard_text_controller.js +111 -0
- data/app/javascript/poetry/core/combobox_controller.js +1095 -0
- data/app/javascript/poetry/core/command_controller.js +510 -0
- data/app/javascript/poetry/core/context_menu_controller.js +204 -0
- data/app/javascript/poetry/core/date_field_controller.js +584 -0
- data/app/javascript/poetry/core/date_picker_controller.js +111 -0
- data/app/javascript/poetry/core/deferred_controller.js +111 -0
- data/app/javascript/poetry/core/dialog_controller.js +206 -0
- data/app/javascript/poetry/core/dismissable_controller.js +182 -0
- data/app/javascript/poetry/core/drawer_controller.js +365 -0
- data/app/javascript/poetry/core/file_input_controller.js +191 -0
- data/app/javascript/poetry/core/focus_scope_controller.js +162 -0
- data/app/javascript/poetry/core/helpers/announce.js +228 -0
- data/app/javascript/poetry/core/helpers/breakpoint.js +28 -0
- data/app/javascript/poetry/core/helpers/collection.js +18 -0
- data/app/javascript/poetry/core/helpers/direction.js +15 -0
- data/app/javascript/poetry/core/helpers/escape.js +38 -0
- data/app/javascript/poetry/core/helpers/filter_rank.js +104 -0
- data/app/javascript/poetry/core/helpers/focus_guards.js +46 -0
- data/app/javascript/poetry/core/helpers/hotkey.js +43 -0
- data/app/javascript/poetry/core/helpers/id_integrity.js +65 -0
- data/app/javascript/poetry/core/helpers/incomplete_date.js +328 -0
- data/app/javascript/poetry/core/helpers/mask.js +283 -0
- data/app/javascript/poetry/core/helpers/portal.js +217 -0
- data/app/javascript/poetry/core/helpers/presence.js +210 -0
- data/app/javascript/poetry/core/helpers/registration_guard.js +76 -0
- data/app/javascript/poetry/core/helpers/scroll_lock.js +67 -0
- data/app/javascript/poetry/core/helpers/scroller_geometry.js +422 -0
- data/app/javascript/poetry/core/helpers/state.js +80 -0
- data/app/javascript/poetry/core/helpers/tabbable.js +56 -0
- data/app/javascript/poetry/core/helpers/turbo_cache.js +21 -0
- data/app/javascript/poetry/core/helpers/typeahead.js +85 -0
- data/app/javascript/poetry/core/hotkey_controller.js +55 -0
- data/app/javascript/poetry/core/hover_card_controller.js +431 -0
- data/app/javascript/poetry/core/index.js +218 -0
- data/app/javascript/poetry/core/mask_controller.js +500 -0
- data/app/javascript/poetry/core/menu_controller.js +1050 -0
- data/app/javascript/poetry/core/menubar_controller.js +329 -0
- data/app/javascript/poetry/core/message_scroller_controller.js +930 -0
- data/app/javascript/poetry/core/navigation_menu_controller.js +458 -0
- data/app/javascript/poetry/core/number_field_controller.js +404 -0
- data/app/javascript/poetry/core/optimistic_form_controller.js +56 -0
- data/app/javascript/poetry/core/otp_controller.js +219 -0
- data/app/javascript/poetry/core/popover_controller.js +300 -0
- data/app/javascript/poetry/core/popper_controller.js +439 -0
- data/app/javascript/poetry/core/pressed_controller.js +74 -0
- data/app/javascript/poetry/core/questionnaire_controller.js +468 -0
- data/app/javascript/poetry/core/radio_group_controller.js +197 -0
- data/app/javascript/poetry/core/resizable_controller.js +202 -0
- data/app/javascript/poetry/core/roving_focus_controller.js +215 -0
- data/app/javascript/poetry/core/scroll_spy_controller.js +84 -0
- data/app/javascript/poetry/core/search_field_controller.js +95 -0
- data/app/javascript/poetry/core/select_controller.js +924 -0
- data/app/javascript/poetry/core/sensitive_input_controller.js +195 -0
- data/app/javascript/poetry/core/sheet_controller.js +24 -0
- data/app/javascript/poetry/core/sidebar_controller.js +272 -0
- data/app/javascript/poetry/core/slider_controller.js +419 -0
- data/app/javascript/poetry/core/state_controller.js +82 -0
- data/app/javascript/poetry/core/table_selection_controller.js +153 -0
- data/app/javascript/poetry/core/tabs_controller.js +151 -0
- data/app/javascript/poetry/core/tag_group_controller.js +134 -0
- data/app/javascript/poetry/core/toast_controller.js +228 -0
- data/app/javascript/poetry/core/toast_trigger_controller.js +26 -0
- data/app/javascript/poetry/core/toaster_controller.js +197 -0
- data/app/javascript/poetry/core/toggle_group_controller.js +206 -0
- data/app/javascript/poetry/core/tooltip_controller.js +541 -0
- data/app/javascript/poetry/core/tree_controller.js +265 -0
- data/app/javascript/poetry/core/vendor/floating_ui_core.js +1043 -0
- data/app/javascript/poetry/core/vendor/floating_ui_dom.js +794 -0
- data/app/javascript/poetry/core/vendor/floating_ui_utils.js +141 -0
- data/app/javascript/poetry/core/vendor/floating_ui_utils_dom.js +170 -0
- data/app/views/poetry/core/preview.html.erb +13 -0
- data/config/component_registry.yml +20 -0
- data/config/controllers_manifest.json +1528 -0
- data/config/importmap.rb +11 -0
- data/config/state_vocabulary.json +31 -0
- data/lib/active_model/type/list.rb +33 -0
- data/lib/active_model/type/symbol.rb +36 -0
- data/lib/poetry/core/check/stable_identity.rb +104 -0
- data/lib/poetry/core/check.rb +1445 -0
- data/lib/poetry/core/config.rb +286 -0
- data/lib/poetry/core/contrib/wrapped_helper.rb +68 -0
- data/lib/poetry/core/css/bem_merger.rb +45 -0
- data/lib/poetry/core/css/bem_reference.rb +87 -0
- data/lib/poetry/core/css/override_scan.rb +110 -0
- data/lib/poetry/core/css/resolver.rb +161 -0
- data/lib/poetry/core/css/safelist.rb +41 -0
- data/lib/poetry/core/css/tailwind_merger.rb +102 -0
- data/lib/poetry/core/css/template_classes.rb +102 -0
- data/lib/poetry/core/css/theme_coverage.rb +72 -0
- data/lib/poetry/core/css/var_coverage.rb +75 -0
- data/lib/poetry/core/css/verifier.rb +106 -0
- data/lib/poetry/core/design_lint.rb +720 -0
- data/lib/poetry/core/design_md/import.rb +250 -0
- data/lib/poetry/core/design_md.rb +461 -0
- data/lib/poetry/core/engine.rb +71 -0
- data/lib/poetry/core/errors.rb +53 -0
- data/lib/poetry/core/html/attributes.rb +667 -0
- data/lib/poetry/core/icons.rb +157 -0
- data/lib/poetry/core/llms_text.rb +354 -0
- data/lib/poetry/core/page_architectures.rb +304 -0
- data/lib/poetry/core/part_contract.rb +285 -0
- data/lib/poetry/core/preview/abstract.rb +121 -0
- data/lib/poetry/core/preview/base.rb +227 -0
- data/lib/poetry/core/preview/sidecarable.rb +136 -0
- data/lib/poetry/core/preview/template.rb +186 -0
- data/lib/poetry/core/recipe_items.rb +82 -0
- data/lib/poetry/core/registry.rb +363 -0
- data/lib/poetry/core/registry_address.rb +115 -0
- data/lib/poetry/core/registry_client.rb +217 -0
- data/lib/poetry/core/registry_installer.rb +234 -0
- data/lib/poetry/core/registry_items.rb +184 -0
- data/lib/poetry/core/skill_text.rb +288 -0
- data/lib/poetry/core/stable_id.rb +110 -0
- data/lib/poetry/core/stimulus/builder.rb +395 -0
- data/lib/poetry/core/stimulus/declarations.rb +444 -0
- data/lib/poetry/core/stimulus/manifest.rb +68 -0
- data/lib/poetry/core/stimulus/merger.rb +131 -0
- data/lib/poetry/core/stimulus_contract.rb +263 -0
- data/lib/poetry/core/tag_helper.rb +10 -0
- data/lib/poetry/core/template_compile.rb +74 -0
- data/lib/poetry/core/token_import.rb +317 -0
- data/lib/poetry/core/tokens/color.rb +215 -0
- data/lib/poetry/core/tokens/contrast_gate.rb +120 -0
- data/lib/poetry/core/tokens/generator.rb +211 -0
- data/lib/poetry/core/tokens.rb +117 -0
- data/lib/poetry/core/version.rb +9 -0
- data/lib/poetry/core.rb +52 -0
- data/lib/poetry-core.rb +5 -0
- data/tokens/aliases.css +145 -0
- data/tokens/tailwind-theme.css +47 -0
- data/tokens/tokens.css +78 -0
- data/tokens/tokens.dtcg.json +779 -0
- data/vendor/floating-ui/LICENSE +20 -0
- data/vendor/floating-ui/VENDORED_VERSIONS +15 -0
- data/vendor/shadcn-tailwind/LICENSE +21 -0
- data/vendor/shadcn-tailwind/VENDORED_COMMIT +1 -0
- data/vendor/shadcn-tailwind/tailwind.css +629 -0
- data/vendor/tw-animate-css/LICENSE +21 -0
- data/vendor/tw-animate-css/VENDORED_VERSION +1 -0
- data/vendor/tw-animate-css/tw-animate.css +1 -0
- metadata +267 -0
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
|
2
|
+
import { portalContent, resolvePortalContainer, restoreContent } from "@poetry/controllers/helpers/portal"
|
|
3
|
+
import { enterPresence, exitPresence } from "@poetry/controllers/helpers/presence"
|
|
4
|
+
import { setState, stateOf } from "@poetry/controllers/helpers/state"
|
|
5
|
+
|
|
6
|
+
// The Popover controller (the popper-consumer trio's click-open member):
|
|
7
|
+
// the menu controller's #show/#hide + token-activated layer skeleton with
|
|
8
|
+
// ALL item machinery deleted - no typeahead, no roving, no subs, no
|
|
9
|
+
// collection. What remains is exactly the APG dialog-pattern-lite: the
|
|
10
|
+
// trigger toggles a role=dialog panel, focus MOVES INTO the content on open
|
|
11
|
+
// (focus-scope's mount default - deliberately NOT vetoed, the contrast with
|
|
12
|
+
// the menu family's data-open-reason contract) and RETURNS to the trigger on
|
|
13
|
+
// close; the trap is enforced only when modal (the default is
|
|
14
|
+
// modal: FALSE - the deliberate contrast with the menu family's true).
|
|
15
|
+
//
|
|
16
|
+
// STRUCTURAL RESOLUTION, no targets: the content is found via the trigger's
|
|
17
|
+
// aria-controls id (portal-safe - the menu-controller pattern verbatim);
|
|
18
|
+
// content-level listeners are wired programmatically in connect for the same
|
|
19
|
+
// reason.
|
|
20
|
+
//
|
|
21
|
+
// The layer stack is ACTIVATED on open: focus-scope + dismissable are
|
|
22
|
+
// appended to the content's data-controller (a statically-connected trap on
|
|
23
|
+
// hidden content would steal focus at page load; a static dismissable would
|
|
24
|
+
// swallow topmost-Esc), with trapped / disable-outside-pointer-events both
|
|
25
|
+
// set from modal. Close reverses: presence exit -> hidden -> tokens removed
|
|
26
|
+
// -> focus-scope's disconnect restores focus to the trigger (suppressed for
|
|
27
|
+
// outside-press when non-modal: focus follows the click).
|
|
28
|
+
const TRIGGER_SELECTOR = '[data-slot="popover-trigger"]'
|
|
29
|
+
|
|
30
|
+
const EVENT_PREFIX = "poetry:popover"
|
|
31
|
+
|
|
32
|
+
const CONTENT_LAYER_CONTROLLERS = ["poetry--core--focus-scope", "poetry--core--dismissable"]
|
|
33
|
+
const POPPER_STRATEGY = "data-poetry--core--popper-strategy-value"
|
|
34
|
+
|
|
35
|
+
export default class PopoverController extends Controller {
|
|
36
|
+
// The events this controller dispatches (manifest surface;
|
|
37
|
+
// events_declaration.test.js enforces the list stays honest).
|
|
38
|
+
static events = ["poetry:popover:closed", "poetry:popover:open"]
|
|
39
|
+
|
|
40
|
+
static values = {
|
|
41
|
+
open: { type: Boolean, default: false },
|
|
42
|
+
modal: { type: Boolean, default: false }
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
#connected = false
|
|
46
|
+
#wired = []
|
|
47
|
+
#suppressRestore = false
|
|
48
|
+
#cancelExit = null
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Wires the content listeners (programmatic - portal-safe) and
|
|
52
|
+
* reconciles: server-open content adopts the layer stack and re-portals
|
|
53
|
+
* one frame late (the body comments hold the rules).
|
|
54
|
+
*/
|
|
55
|
+
connect() {
|
|
56
|
+
const content = this.#content()
|
|
57
|
+
|
|
58
|
+
if (content) this.#wireContent(content)
|
|
59
|
+
|
|
60
|
+
this.#connected = true
|
|
61
|
+
|
|
62
|
+
// Reconcile-on-connect: the server may own the open state (Turbo Stream
|
|
63
|
+
// re-render). DOM attributes win; the layer stack catches up.
|
|
64
|
+
if (this.#isOpen()) {
|
|
65
|
+
if (content) {
|
|
66
|
+
this.#activateLayers(content)
|
|
67
|
+
this.#portalPinned(content)
|
|
68
|
+
}
|
|
69
|
+
this.openValue = true
|
|
70
|
+
} else if (this.openValue) {
|
|
71
|
+
this.#show()
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Restores portaled content (drop-never-strand) and unwires the
|
|
77
|
+
* content listeners.
|
|
78
|
+
*/
|
|
79
|
+
disconnect() {
|
|
80
|
+
this.#connected = false
|
|
81
|
+
|
|
82
|
+
// Never leave content stranded at the container (drop-never-strand).
|
|
83
|
+
const content = this.#content()
|
|
84
|
+
|
|
85
|
+
if (content) restoreContent(content)
|
|
86
|
+
|
|
87
|
+
for (const [target, type, listener] of this.#wired) target.removeEventListener(type, listener)
|
|
88
|
+
|
|
89
|
+
this.#wired = []
|
|
90
|
+
this.#cancelExit?.()
|
|
91
|
+
this.#cancelExit = null
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Stimulus value callback - controllable state: a host (outlet / Turbo
|
|
96
|
+
* Stream / URL param) may own the open value; flipping the attribute
|
|
97
|
+
* drives the same machine.
|
|
98
|
+
*
|
|
99
|
+
* @param {boolean} value
|
|
100
|
+
*/
|
|
101
|
+
openValueChanged(value) {
|
|
102
|
+
if (!this.#connected) return
|
|
103
|
+
|
|
104
|
+
if (value && !this.#isOpen()) this.#show()
|
|
105
|
+
else if (!value && this.#isOpen()) this.#hide("none")
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* The trigger's click action (native button Enter/Space arrive as
|
|
110
|
+
* click - no custom keydown map, the deliberate contrast with the menu
|
|
111
|
+
* trigger).
|
|
112
|
+
*/
|
|
113
|
+
toggle() {
|
|
114
|
+
if (this.#isOpen()) this.#hide("trigger-press")
|
|
115
|
+
else this.#show()
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// --- programmatic API (the controllable-state surface) ---
|
|
119
|
+
|
|
120
|
+
/** Programmatically opens. */
|
|
121
|
+
open() {
|
|
122
|
+
this.#show()
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Programmatically closes.
|
|
127
|
+
*
|
|
128
|
+
* @param {string | Event} [reason="none"] - a family reason string; an
|
|
129
|
+
* Event (data-action use) reads as "none"
|
|
130
|
+
*/
|
|
131
|
+
close(reason = "none") {
|
|
132
|
+
this.#hide(reason instanceof Event ? "none" : reason)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// --- open / close ---
|
|
136
|
+
|
|
137
|
+
#show() {
|
|
138
|
+
const content = this.#content()
|
|
139
|
+
|
|
140
|
+
if (!content || this.#isOpen()) return
|
|
141
|
+
|
|
142
|
+
this.#cancelExit?.()
|
|
143
|
+
this.#cancelExit = null
|
|
144
|
+
this.#suppressRestore = false
|
|
145
|
+
|
|
146
|
+
const trigger = this.#trigger()
|
|
147
|
+
|
|
148
|
+
// Portal-on-open: move BEFORE the
|
|
149
|
+
// enter presence (reparenting mid-animation restarts it), re-anchor
|
|
150
|
+
// absolute - static under compositor scroll, transform-immune.
|
|
151
|
+
portalContent(content, { container: resolvePortalContainer(this.element) })
|
|
152
|
+
this.element.setAttribute(POPPER_STRATEGY, "absolute")
|
|
153
|
+
|
|
154
|
+
content.hidden = false
|
|
155
|
+
trigger?.setAttribute("aria-expanded", "true")
|
|
156
|
+
if (trigger) setState(trigger, "popup-open")
|
|
157
|
+
enterPresence(content)
|
|
158
|
+
this.#activateLayers(content)
|
|
159
|
+
this.openValue = true
|
|
160
|
+
|
|
161
|
+
// The layer controllers connect on the attribute-mutation microtask;
|
|
162
|
+
// focus-scope's mount-auto-focus (first tabbable, else the content) is
|
|
163
|
+
// NOT vetoed here - the dialog pattern. The open event rides one
|
|
164
|
+
// microtask behind so it fires after initial focus applied.
|
|
165
|
+
queueMicrotask(() => {
|
|
166
|
+
if (!this.#isOpen()) return
|
|
167
|
+
|
|
168
|
+
this.dispatch("open", { prefix: EVENT_PREFIX, detail: {} })
|
|
169
|
+
})
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
#hide(reason) {
|
|
173
|
+
const content = this.#content()
|
|
174
|
+
|
|
175
|
+
if (!content || !this.#isOpen()) return
|
|
176
|
+
|
|
177
|
+
// Focus return to the trigger is focus-scope's disconnect job - vetoed
|
|
178
|
+
// for outside interaction on a non-modal popover (non-modal
|
|
179
|
+
// semantics: focus follows the click).
|
|
180
|
+
this.#suppressRestore = reason === "outside-press" && !this.modalValue
|
|
181
|
+
|
|
182
|
+
const trigger = this.#trigger()
|
|
183
|
+
|
|
184
|
+
trigger?.setAttribute("aria-expanded", "false")
|
|
185
|
+
if (trigger) setState(trigger, "popup-closed")
|
|
186
|
+
this.openValue = false
|
|
187
|
+
|
|
188
|
+
this.#cancelExit = exitPresence(content, {
|
|
189
|
+
onRemove: () => {
|
|
190
|
+
this.#cancelExit = null
|
|
191
|
+
content.hidden = true
|
|
192
|
+
// Home AFTER the exit finished and hidden landed; the
|
|
193
|
+
// focus-scope teardown below restores focus by element ref,
|
|
194
|
+
// indifferent to where the node sits.
|
|
195
|
+
restoreContent(content)
|
|
196
|
+
this.element.setAttribute(POPPER_STRATEGY, "fixed")
|
|
197
|
+
this.#removeControllers(content, CONTENT_LAYER_CONTROLLERS)
|
|
198
|
+
this.dispatch("closed", { prefix: EVENT_PREFIX, detail: { reason } })
|
|
199
|
+
}
|
|
200
|
+
})
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// The reconcile path portals ONE FRAME LATE: connect order within a boot
|
|
204
|
+
// is unordered, and portaling before the sibling popper's connect would
|
|
205
|
+
// rob it of its content target before it could cache the node.
|
|
206
|
+
#portalPinned(content) {
|
|
207
|
+
window.requestAnimationFrame(() => {
|
|
208
|
+
if (!this.#connected || !this.#isOpen()) return
|
|
209
|
+
|
|
210
|
+
portalContent(content, { container: resolvePortalContainer(this.element) })
|
|
211
|
+
this.element.setAttribute(POPPER_STRATEGY, "absolute")
|
|
212
|
+
})
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// --- content wiring (programmatic: portal-safe, no data-action required) ---
|
|
216
|
+
|
|
217
|
+
#wireContent(content) {
|
|
218
|
+
this.#listen(content, "poetry--core--dismissable:dismiss", this.#onDismiss)
|
|
219
|
+
this.#listen(content, "poetry--core--dismissable:interact-outside", this.#onInteractOutside)
|
|
220
|
+
this.#listen(content, "poetry--core--focus-scope:unmount-auto-focus", this.#onUnmountAutoFocus)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
#listen(target, type, listener) {
|
|
224
|
+
target.addEventListener(type, listener)
|
|
225
|
+
this.#wired.push([target, type, listener])
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// A press on the popover's OWN trigger is the toggle's job, not an
|
|
229
|
+
// outside dismissal: without this veto the pointerdown closes and the
|
|
230
|
+
// trailing click re-opens, so the popover appears to never close on
|
|
231
|
+
// trigger press (the trigger-is-not-outside rule; iOS light-dismiss
|
|
232
|
+
// double-fires arrive through the same seam and are covered by it).
|
|
233
|
+
#onInteractOutside = (event) => {
|
|
234
|
+
if (event.target !== this.#content()) return
|
|
235
|
+
|
|
236
|
+
const origin = event.detail?.originalEvent?.target
|
|
237
|
+
|
|
238
|
+
if (origin instanceof Element && this.#trigger()?.contains(origin)) event.preventDefault()
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Esc / outside-press arrive as the dismissable layer's dismiss event
|
|
242
|
+
// (topmost-only via the class-level stack).
|
|
243
|
+
#onDismiss = (event) => {
|
|
244
|
+
if (event.target !== this.#content()) return
|
|
245
|
+
|
|
246
|
+
const escaped = event.detail?.originalEvent?.type === "keydown"
|
|
247
|
+
|
|
248
|
+
this.#hide(escaped ? "escape-key" : "outside-press")
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
#onUnmountAutoFocus = (event) => {
|
|
252
|
+
if (event.target === this.#content() && this.#suppressRestore) event.preventDefault()
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// --- the layer stack ---
|
|
256
|
+
|
|
257
|
+
#activateLayers(content) {
|
|
258
|
+
content.setAttribute("data-poetry--core--focus-scope-trapped-value", String(this.modalValue))
|
|
259
|
+
content.setAttribute(
|
|
260
|
+
"data-poetry--core--dismissable-disable-outside-pointer-events-value", String(this.modalValue)
|
|
261
|
+
)
|
|
262
|
+
this.#addControllers(content, CONTENT_LAYER_CONTROLLERS)
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
#addControllers(element, identifiers) {
|
|
266
|
+
const tokens = (element.getAttribute("data-controller") ?? "").split(/\s+/).filter(Boolean)
|
|
267
|
+
|
|
268
|
+
for (const identifier of identifiers) {
|
|
269
|
+
if (!tokens.includes(identifier)) tokens.push(identifier)
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
element.setAttribute("data-controller", tokens.join(" "))
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
#removeControllers(element, identifiers) {
|
|
276
|
+
const tokens = (element.getAttribute("data-controller") ?? "")
|
|
277
|
+
.split(/\s+/)
|
|
278
|
+
.filter((token) => token && !identifiers.includes(token))
|
|
279
|
+
|
|
280
|
+
element.setAttribute("data-controller", tokens.join(" "))
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// --- structural resolution (the DOM is the registry; ids are the seams) ---
|
|
284
|
+
|
|
285
|
+
#trigger() {
|
|
286
|
+
return this.element.querySelector(TRIGGER_SELECTOR)
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
#content() {
|
|
290
|
+
const id = this.#trigger()?.getAttribute("aria-controls")
|
|
291
|
+
|
|
292
|
+
return id ? document.getElementById(id) : null
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
#isOpen() {
|
|
296
|
+
const content = this.#content()
|
|
297
|
+
|
|
298
|
+
return Boolean(content) && stateOf(content) === "open"
|
|
299
|
+
}
|
|
300
|
+
}
|