stimulus-components 1.0.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.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +133 -0
  4. data/app/javascript/animated-number.js +66 -0
  5. data/app/javascript/auto-submit.js +27 -0
  6. data/app/javascript/carousel.js +28 -0
  7. data/app/javascript/character-counter.js +47 -0
  8. data/app/javascript/chartjs.js +58 -0
  9. data/app/javascript/checkbox-select-all.js +76 -0
  10. data/app/javascript/clipboard.js +48 -0
  11. data/app/javascript/color-picker.js +75 -0
  12. data/app/javascript/confirmation.js +30 -0
  13. data/app/javascript/content-loader.js +109 -0
  14. data/app/javascript/dialog.js +53 -0
  15. data/app/javascript/dropdown.js +27 -0
  16. data/app/javascript/glow.js +30 -0
  17. data/app/javascript/hotkey.js +26 -0
  18. data/app/javascript/lightbox.js +26 -0
  19. data/app/javascript/notification.js +49 -0
  20. data/app/javascript/password-visibility.js +27 -0
  21. data/app/javascript/places-autocomplete.js +123 -0
  22. data/app/javascript/popover.js +53 -0
  23. data/app/javascript/prefetch.js +56 -0
  24. data/app/javascript/rails-nested-form.js +43 -0
  25. data/app/javascript/read-more.js +38 -0
  26. data/app/javascript/remote-rails.js +27 -0
  27. data/app/javascript/reveal-controller.js +33 -0
  28. data/app/javascript/scroll-progress.js +32 -0
  29. data/app/javascript/scroll-reveal.js +62 -0
  30. data/app/javascript/scroll-to.js +56 -0
  31. data/app/javascript/sortable.js +74 -0
  32. data/app/javascript/sound.js +39 -0
  33. data/app/javascript/speech-recognition.js +92 -0
  34. data/app/javascript/stimulus-components.js +71 -0
  35. data/app/javascript/textarea-autogrow.js +45 -0
  36. data/app/javascript/timeago.js +66 -0
  37. data/lib/stimulus-components/engine.rb +9 -0
  38. data/lib/stimulus-components/version.rb +3 -0
  39. data/lib/stimulus-components.rb +43 -0
  40. metadata +98 -0
@@ -0,0 +1,109 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ export default class ContentLoader extends Controller<HTMLElement> {
4
+ declare refreshTimer: number
5
+ declare readonly hasUrlValue: boolean
6
+ declare readonly hasLazyLoadingValue: boolean
7
+ declare readonly hasRefreshIntervalValue: boolean
8
+ declare readonly lazyLoadingThresholdValue: number
9
+ declare readonly lazyLoadingRootMarginValue: string
10
+ declare readonly urlValue: string
11
+ declare readonly loadScriptsValue: boolean
12
+ declare readonly refreshIntervalValue: number
13
+
14
+ static values = {
15
+ url: String,
16
+ lazyLoading: Boolean,
17
+ lazyLoadingThreshold: Number,
18
+ lazyLoadingRootMargin: {
19
+ type: String,
20
+ default: "0px",
21
+ },
22
+ refreshInterval: Number,
23
+ loadScripts: Boolean,
24
+ }
25
+
26
+ connect(): void {
27
+ if (!this.hasUrlValue) {
28
+ console.error("[stimulus-content-loader] You need to pass an url to fetch the remote content.")
29
+ return
30
+ }
31
+
32
+ this.hasLazyLoadingValue ? this.lazyLoad() : this.load()
33
+ }
34
+
35
+ disconnect(): void {
36
+ this.stopRefreshing()
37
+ }
38
+
39
+ load(): void {
40
+ this.fetch()
41
+
42
+ if (this.hasRefreshIntervalValue) {
43
+ this.startRefreshing()
44
+ }
45
+ }
46
+
47
+ lazyLoad(): void {
48
+ const options: IntersectionObserverInit = {
49
+ threshold: this.lazyLoadingThresholdValue,
50
+ rootMargin: this.lazyLoadingRootMarginValue,
51
+ }
52
+
53
+ const observer = new IntersectionObserver(
54
+ (entries, observer) => {
55
+ entries.forEach((entry) => {
56
+ if (entry.isIntersecting) {
57
+ this.load()
58
+ observer.unobserve(entry.target)
59
+ }
60
+ })
61
+ },
62
+ options
63
+ )
64
+
65
+ observer.observe(this.element)
66
+ }
67
+
68
+ fetch(): void {
69
+ fetch(this.urlValue)
70
+ .then((response) => {
71
+ if (!response.ok) {
72
+ throw new Error(response.statusText)
73
+ }
74
+ return response.text()
75
+ })
76
+ .then((html) => {
77
+ this.element.innerHTML = html
78
+
79
+ if (this.loadScriptsValue) {
80
+ this.loadScripts()
81
+ }
82
+
83
+ this.dispatch("success")
84
+ })
85
+ .catch((error) => {
86
+ this.dispatch("error", { detail: { error } })
87
+ })
88
+ }
89
+
90
+ startRefreshing(): void {
91
+ this.refreshTimer = setInterval(() => {
92
+ this.fetch()
93
+ }, this.refreshIntervalValue)
94
+ }
95
+
96
+ stopRefreshing(): void {
97
+ if (this.refreshTimer) {
98
+ clearInterval(this.refreshTimer)
99
+ }
100
+ }
101
+
102
+ loadScripts(): void {
103
+ this.element.querySelectorAll("script").forEach((content) => {
104
+ const script = document.createElement("script")
105
+ script.innerHTML = content.innerHTML
106
+ document.head.appendChild(script).parentNode.removeChild(script)
107
+ })
108
+ }
109
+ }
@@ -0,0 +1,53 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ export default class Dialog extends Controller {
4
+ declare readonly dialogTarget: HTMLDialogElement
5
+ declare readonly openValue: boolean
6
+
7
+ static targets = ["dialog"]
8
+ static values = {
9
+ open: {
10
+ type: Boolean,
11
+ default: false,
12
+ },
13
+ }
14
+
15
+ initialize() {
16
+ this.forceClose = this.forceClose.bind(this)
17
+ }
18
+
19
+ connect(): void {
20
+ if (this.openValue) {
21
+ this.open()
22
+ }
23
+
24
+ document.addEventListener("turbo:before-render", this.forceClose)
25
+ }
26
+
27
+ disconnect(): void {
28
+ document.removeEventListener("turbo:before-render", this.forceClose)
29
+ }
30
+
31
+ open(): void {
32
+ this.dialogTarget.showModal()
33
+ }
34
+
35
+ close(): void {
36
+ this.dialogTarget.setAttribute("closing", "")
37
+
38
+ Promise.all(this.dialogTarget.getAnimations().map((animation) => animation.finished)).then(() => {
39
+ this.dialogTarget.removeAttribute("closing")
40
+ this.dialogTarget.close()
41
+ })
42
+ }
43
+
44
+ backdropClose(event: Event): void {
45
+ if (event.target === this.dialogTarget) {
46
+ this.close()
47
+ }
48
+ }
49
+
50
+ forceClose(): void {
51
+ this.dialogTarget.close()
52
+ }
53
+ }
@@ -0,0 +1,27 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+ import { useTransition } from "stimulus-use"
3
+
4
+ export default class Dropdown extends Controller {
5
+ declare readonly menuTarget: HTMLElement
6
+ declare toggleTransition: (event?: Event) => void
7
+ declare leave: (event?: Event) => void
8
+ declare transitioned: false
9
+
10
+ static targets = ["menu"]
11
+
12
+ connect(): void {
13
+ useTransition(this, {
14
+ element: this.menuTarget,
15
+ })
16
+ }
17
+
18
+ toggle(): void {
19
+ this.toggleTransition()
20
+ }
21
+
22
+ hide(event: Event): void {
23
+ if (!this.element.contains(event.target) && !this.menuTarget.classList.contains("hidden")) {
24
+ this.leave()
25
+ }
26
+ }
27
+ }
@@ -0,0 +1,30 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ export default class Glow extends Controller<HTMLElement> {
4
+ declare childTarget: HTMLElement
5
+ declare overlayTarget: HTMLElement
6
+
7
+ static targets = ["child", "overlay"]
8
+
9
+ initialize(): void {
10
+ this.move = this.move.bind(this)
11
+ }
12
+
13
+ connect(): void {
14
+ this.overlayTarget.append(this.childTarget.cloneNode(true))
15
+ document.body.addEventListener("pointermove", this.move)
16
+ }
17
+
18
+ disconnect(): void {
19
+ document.body.removeEventListener("pointermove", this.move)
20
+ }
21
+
22
+ move(e: PointerEvent): void {
23
+ const x = e.pageX - this.element.offsetLeft
24
+ const y = e.pageY - this.element.offsetTop
25
+
26
+ this.element.style.setProperty("--glow-opacity", "1")
27
+ this.element.style.setProperty("--glow-x", `${x}px`)
28
+ this.element.style.setProperty("--glow-y", `${y}px`)
29
+ }
30
+ }
@@ -0,0 +1,26 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ export default class Hotkey extends Controller<HTMLElement> {
4
+ click(event: KeyboardEvent): void {
5
+ if (this.isClickable && !this.shouldIgnore(event)) {
6
+ event.preventDefault()
7
+ this.element.click()
8
+ }
9
+ }
10
+
11
+ focus(event: KeyboardEvent): void {
12
+ if (this.isClickable && !this.shouldIgnore(event)) {
13
+ event.preventDefault()
14
+ this.element.focus()
15
+ }
16
+ }
17
+
18
+ private shouldIgnore(event: KeyboardEvent): boolean {
19
+ const target = event.target as Element | null
20
+ return event.defaultPrevented || !!target?.closest("input, textarea, [contenteditable]")
21
+ }
22
+
23
+ private get isClickable(): boolean {
24
+ return getComputedStyle(this.element).pointerEvents !== "none"
25
+ }
26
+ }
@@ -0,0 +1,26 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+ import lightGallery, { LightGallerySettings, LightGallery } from "lightgallery"
3
+
4
+ export default class Lightbox extends Controller<HTMLElement> {
5
+ declare optionsValue: LightGallerySettings
6
+ declare lightGallery: LightGallery
7
+
8
+ static values = {
9
+ options: Object,
10
+ }
11
+
12
+ connect(): void {
13
+ this.lightGallery = lightGallery(this.element, {
14
+ ...this.defaultOptions,
15
+ ...this.optionsValue,
16
+ })
17
+ }
18
+
19
+ disconnect(): void {
20
+ this.lightGallery.destroy()
21
+ }
22
+
23
+ get defaultOptions(): LightGallerySettings {
24
+ return {}
25
+ }
26
+ }
@@ -0,0 +1,49 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+ import { useTransition } from "stimulus-use"
3
+
4
+ export default class Notification extends Controller {
5
+ declare timeout: number
6
+ declare enter: (event?: Event) => void
7
+ declare leave: (event?: Event) => void
8
+ declare transitioned: false
9
+ declare delayValue: number
10
+ declare hiddenValue: boolean
11
+
12
+ static values = {
13
+ delay: {
14
+ type: Number,
15
+ default: 3000,
16
+ },
17
+ hidden: {
18
+ type: Boolean,
19
+ default: false,
20
+ },
21
+ }
22
+
23
+ initialize() {
24
+ this.hide = this.hide.bind(this)
25
+ }
26
+
27
+ connect() {
28
+ useTransition(this)
29
+
30
+ if (this.hiddenValue === false) {
31
+ this.show()
32
+ }
33
+ }
34
+
35
+ show() {
36
+ this.enter()
37
+
38
+ this.timeout = setTimeout(this.hide, this.delayValue)
39
+ }
40
+
41
+ async hide() {
42
+ if (this.timeout) {
43
+ clearTimeout(this.timeout)
44
+ }
45
+
46
+ await this.leave()
47
+ this.element.remove()
48
+ }
49
+ }
@@ -0,0 +1,27 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ export default class PasswordVisibility extends Controller {
4
+ declare hasHiddenClass: boolean
5
+ declare hiddenClass: string
6
+ declare class: string
7
+ declare hidden: boolean
8
+ declare inputTarget: HTMLInputElement
9
+ declare iconTargets: HTMLElement[]
10
+
11
+ static targets = ["input", "icon"]
12
+ static classes = ["hidden"]
13
+
14
+ connect(): void {
15
+ this.hidden = this.inputTarget.type === "password"
16
+ this.class = this.hasHiddenClass ? this.hiddenClass : "hidden"
17
+ }
18
+
19
+ toggle(e: Event): void {
20
+ e.preventDefault()
21
+
22
+ this.inputTarget.type = this.hidden ? "text" : "password"
23
+ this.hidden = !this.hidden
24
+
25
+ this.iconTargets.forEach((icon) => icon.classList.toggle(this.class))
26
+ }
27
+ }
@@ -0,0 +1,123 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ interface Address {
4
+ street_number: string
5
+ route: string
6
+ locality: string
7
+ administrative_area_level_2: string
8
+ administrative_area_level_1: string
9
+ country: string
10
+ postal_code: string
11
+ }
12
+
13
+ export default class PlacesAutocomplete extends Controller {
14
+ declare autocomplete: google.maps.places.Autocomplete
15
+ declare place: google.maps.places.PlaceResult
16
+ declare addressTarget: HTMLInputElement
17
+ declare streetNumberTarget: HTMLInputElement
18
+ declare routeTarget: HTMLInputElement
19
+ declare cityTarget: HTMLInputElement
20
+ declare countyTarget: HTMLInputElement
21
+ declare stateTarget: HTMLInputElement
22
+ declare countryTarget: HTMLInputElement
23
+ declare postalCodeTarget: HTMLInputElement
24
+ declare longitudeTarget: HTMLInputElement
25
+ declare latitudeTarget: HTMLInputElement
26
+ declare hasStreetNumberTarget: boolean
27
+ declare hasRouteTarget: boolean
28
+ declare hasCityTarget: boolean
29
+ declare hasCountryTarget: boolean
30
+ declare hasCountyTarget: boolean
31
+ declare hasPostalCodeTarget: boolean
32
+ declare hasStateTarget: boolean
33
+ declare hasLongitudeTarget: boolean
34
+ declare hasLatitudeTarget: boolean
35
+ declare countryValue: Array<string>
36
+
37
+ static targets = [
38
+ "address",
39
+ "city",
40
+ "streetNumber",
41
+ "route",
42
+ "postalCode",
43
+ "country",
44
+ "county",
45
+ "state",
46
+ "longitude",
47
+ "latitude",
48
+ ]
49
+
50
+ static values = {
51
+ country: Array,
52
+ }
53
+
54
+ initialize(): void {
55
+ this.placeChanged = this.placeChanged.bind(this)
56
+ }
57
+
58
+ connect(): void {
59
+ if (typeof google !== "undefined") {
60
+ this.initAutocomplete()
61
+ }
62
+ }
63
+
64
+ initAutocomplete(): void {
65
+ this.autocomplete = new google.maps.places.Autocomplete(this.addressTarget, this.autocompleteOptions)
66
+ this.autocomplete.addListener("place_changed", this.placeChanged)
67
+ }
68
+
69
+ placeChanged(): void {
70
+ this.place = this.autocomplete.getPlace()
71
+ const addressComponents = this.place.address_components
72
+
73
+ if (addressComponents !== undefined) {
74
+ const formattedAddress = this.formatAddressComponents(addressComponents) as Address
75
+ this.setAddressComponents(formattedAddress)
76
+ }
77
+
78
+ if (this.place.geometry !== undefined) {
79
+ this.setGeometry(this.place.geometry)
80
+ }
81
+ }
82
+
83
+ setAddressComponents(address: Address): void {
84
+ if (this.hasStreetNumberTarget) this.streetNumberTarget.value = address.street_number || ""
85
+ if (this.hasRouteTarget) this.routeTarget.value = address.route || ""
86
+ if (this.hasCityTarget) this.cityTarget.value = address.locality || ""
87
+ if (this.hasCountyTarget) this.countyTarget.value = address.administrative_area_level_2 || ""
88
+ if (this.hasStateTarget) this.stateTarget.value = address.administrative_area_level_1 || ""
89
+ if (this.hasCountryTarget) this.countryTarget.value = address.country || ""
90
+ if (this.hasPostalCodeTarget) this.postalCodeTarget.value = address.postal_code || ""
91
+ }
92
+
93
+ setGeometry(geometry: google.maps.places.PlaceGeometry): void {
94
+ if (this.hasLongitudeTarget) this.longitudeTarget.value = geometry.location.lng().toString()
95
+ if (this.hasLatitudeTarget) this.latitudeTarget.value = geometry.location.lat().toString()
96
+ }
97
+
98
+ get autocompleteOptions(): google.maps.places.AutocompleteOptions {
99
+ return {
100
+ fields: ["address_components", "geometry"],
101
+ componentRestrictions: {
102
+ country: this.countryValue,
103
+ },
104
+ }
105
+ }
106
+
107
+ preventSubmit(event: KeyboardEvent): void {
108
+ if (event.code === "Enter") {
109
+ event.preventDefault()
110
+ }
111
+ }
112
+
113
+ private formatAddressComponents(addressComponents): Address {
114
+ const data = {}
115
+
116
+ addressComponents.forEach((component) => {
117
+ const type = component.types[0]
118
+ data[type] = component.long_name
119
+ })
120
+
121
+ return data as Address
122
+ }
123
+ }
@@ -0,0 +1,53 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ export default class Popover extends Controller {
4
+ declare readonly hasCardTarget: boolean
5
+ declare readonly hasContentTarget: boolean
6
+ declare readonly hasUrlValue: boolean
7
+ declare readonly contentTarget: HTMLElement
8
+ declare readonly cardTarget: HTMLElement
9
+ declare readonly urlValue: string
10
+ declare remoteContent: string
11
+
12
+ static targets = ["card", "content"]
13
+ static values = {
14
+ url: String,
15
+ }
16
+
17
+ async show(event: Event): Promise<void> {
18
+ const element = event.currentTarget
19
+
20
+ let content: string = null
21
+
22
+ if (this.hasContentTarget) {
23
+ content = this.contentTarget.innerHTML
24
+ } else {
25
+ content = await this.fetch()
26
+ }
27
+
28
+ if (!content) return
29
+
30
+ const fragment = document.createRange().createContextualFragment(content)
31
+ element.appendChild(fragment)
32
+ }
33
+
34
+ hide(): void {
35
+ if (this.hasCardTarget) {
36
+ this.cardTarget.remove()
37
+ }
38
+ }
39
+
40
+ async fetch(): Promise<string> {
41
+ if (!this.remoteContent) {
42
+ if (!this.hasUrlValue) {
43
+ console.error("[stimulus-popover] You need to pass an url to fetch the popover content.")
44
+ return
45
+ }
46
+
47
+ const response = await fetch(this.urlValue)
48
+ this.remoteContent = await response.text()
49
+ }
50
+
51
+ return this.remoteContent
52
+ }
53
+ }
@@ -0,0 +1,56 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ export default class Prefetch extends Controller<HTMLAnchorElement> {
4
+ initialize(): void {
5
+ this.prefetch = this.prefetch.bind(this)
6
+ this.load = this.load.bind(this)
7
+ }
8
+
9
+ connect(): void {
10
+ if (!this.hasPrefetch) return
11
+ this.load()
12
+ }
13
+
14
+ load(): void {
15
+ const observer = new IntersectionObserver(
16
+ (entries, observer) => {
17
+ entries.forEach((entry) => {
18
+ if (entry.isIntersecting) {
19
+ this.prefetch()
20
+ observer.unobserve(entry.target)
21
+ }
22
+ })
23
+ }
24
+ )
25
+
26
+ observer.observe(this.element)
27
+ }
28
+
29
+ prefetch(): void {
30
+ const connection = navigator.connection
31
+
32
+ if (connection) {
33
+ if (connection.saveData) {
34
+ console.warn("[@stimulus-components/prefetch] Cannot prefetch, Save-Data is enabled.")
35
+ return
36
+ }
37
+
38
+ if (connection.effectiveType !== "4g") {
39
+ console.warn("[@stimulus-components/prefetch] Cannot prefetch, network conditions are poor.")
40
+ return
41
+ }
42
+ }
43
+
44
+ const link = document.createElement("link")
45
+ link.rel = "prefetch"
46
+ link.href = this.element.href
47
+ link.as = "document"
48
+
49
+ document.head.appendChild(link)
50
+ }
51
+
52
+ get hasPrefetch(): boolean {
53
+ const link = document.createElement("link")
54
+ return link.relList && link.relList.supports && link.relList.supports("prefetch")
55
+ }
56
+ }
@@ -0,0 +1,43 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ export default class RailsNestedForm extends Controller {
4
+ declare targetTarget: HTMLElement
5
+ declare templateTarget: HTMLElement
6
+ declare wrapperSelectorValue: string
7
+
8
+ static targets = ["target", "template"]
9
+ static values = {
10
+ wrapperSelector: {
11
+ type: String,
12
+ default: ".nested-form-wrapper",
13
+ },
14
+ }
15
+
16
+ add(e: Event): void {
17
+ e.preventDefault()
18
+
19
+ const content = this.templateTarget.innerHTML.replace(/NEW_RECORD/g, new Date().getTime().toString())
20
+ this.targetTarget.insertAdjacentHTML("beforebegin", content)
21
+
22
+ const event = new CustomEvent("rails-nested-form:add", { bubbles: true })
23
+ this.element.dispatchEvent(event)
24
+ }
25
+
26
+ remove(e: Event): void {
27
+ e.preventDefault()
28
+
29
+ const wrapper = e.target.closest(this.wrapperSelectorValue)
30
+
31
+ if (wrapper.dataset.newRecord === "true") {
32
+ wrapper.remove()
33
+ } else {
34
+ wrapper.style.display = "none"
35
+
36
+ const input = wrapper.querySelector("input[name*='_destroy']")
37
+ input.value = "1"
38
+ }
39
+
40
+ const event = new CustomEvent("rails-nested-form:remove", { bubbles: true })
41
+ this.element.dispatchEvent(event)
42
+ }
43
+ }
@@ -0,0 +1,38 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ export default class ReadMore extends Controller {
4
+ declare open: boolean
5
+ declare contentTarget: HTMLElement
6
+ declare moreTextValue: string
7
+ declare lessTextValue: string
8
+
9
+ static targets: string[] = ["content"]
10
+ static values = {
11
+ moreText: String,
12
+ lessText: String,
13
+ }
14
+
15
+ connect(): void {
16
+ this.open = false
17
+ }
18
+
19
+ toggle(event: Event): void {
20
+ this.open === false ? this.show(event) : this.hide(event)
21
+ }
22
+
23
+ show(event: Event): void {
24
+ this.open = true
25
+
26
+ const target = event.target as HTMLElement
27
+ target.innerHTML = this.lessTextValue
28
+ this.contentTarget.style.setProperty("--read-more-line-clamp", "'unset'")
29
+ }
30
+
31
+ hide(event: Event): void {
32
+ this.open = false
33
+
34
+ const target = event.target as HTMLElement
35
+ target.innerHTML = this.moreTextValue
36
+ this.contentTarget.style.removeProperty("--read-more-line-clamp")
37
+ }
38
+ }
@@ -0,0 +1,27 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ export default class RemoteRails extends Controller<HTMLElement> {
4
+ replace(event: CustomEvent): void {
5
+ event.preventDefault()
6
+ event.stopPropagation()
7
+
8
+ const [, , xhr] = event.detail
9
+ this.element.outerHTML = xhr.response
10
+ }
11
+
12
+ append(event: CustomEvent): void {
13
+ event.preventDefault()
14
+ event.stopPropagation()
15
+
16
+ const [, , xhr] = event.detail
17
+ this.element.insertAdjacentHTML("afterend", xhr.response)
18
+ }
19
+
20
+ prepend(event: CustomEvent): void {
21
+ event.preventDefault()
22
+ event.stopPropagation()
23
+
24
+ const [, , xhr] = event.detail
25
+ this.element.insertAdjacentHTML("beforebegin", xhr.response)
26
+ }
27
+ }