Fix Confetti ignoring the trigger's options when data-bs-target is set (#3195)

Co-authored-by: codecalm <codecalm@gmail.com>
This commit is contained in:
Bartosz-Doandcodecalm authored and GitHub committed 2026-09-25 14:56:06 +02:00
1 parent 29818fcc83
commit d104e78947
4 files changed
+45 -2

No files matched your search

@@ -0,0 +1,6 @@
---
"@tabler/core": patch
"@tabler/docs": patch
---
Fixed Confetti ignoring the trigger's `data-bs-*` options when `data-bs-target` points elsewhere.
+11 -1
View File
@@ -7,6 +7,7 @@
import BaseComponent from './bootstrap/base-component' import BaseComponent from './bootstrap/base-component'
import EventHandler from './bootstrap/dom/event-handler' import EventHandler from './bootstrap/dom/event-handler'
import Manipulator from './bootstrap/dom/manipulator'
import SelectorEngine from './bootstrap/dom/selector-engine' import SelectorEngine from './bootstrap/dom/selector-engine'
import { isDisabled } from './bootstrap/util/index' import { isDisabled } from './bootstrap/util/index'
import type { ComponentConfig as BaseConfig, ElementSelector } from './bootstrap/types' import type { ComponentConfig as BaseConfig, ElementSelector } from './bootstrap/types'
@@ -432,7 +433,16 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (
} }
const target = SelectorEngine.getElementFromSelector(this) || this const target = SelectorEngine.getElementFromSelector(this) || this
const instance = Confetti.getOrCreateInstance(target) as Confetti const config = Manipulator.getDataAttributes(this)
const instance = Confetti.getOrCreateInstance(target, config) as Confetti
// The instance lives on the target and keeps the config it was created
// with, so re-read the trigger's options on every click; several triggers
// can then share one target with their own look.
if (target !== this) {
instance._config = instance._getConfig(config) as ComponentConfig
}
instance.burst() instance.burst()
}) })
+27
View File
@@ -171,6 +171,33 @@ describe('Confetti', () => {
expect(Confetti.getInstance(fixtureEl.querySelector('a')!)).toBeNull() expect(Confetti.getInstance(fixtureEl.querySelector('a')!)).toBeNull()
}) })
it('should read options from the trigger even when data-bs-target points elsewhere', () => {
fixtureEl.innerHTML = '<button type="button" data-bs-toggle="confetti" data-bs-target="#order" data-bs-count="5" data-bs-colors="#f00"></button><div id="order"></div>'
reduceMotion(true)
button().click()
const instance = Confetti.getInstance(fixtureEl.querySelector('#order')!) as Confetti
expect(instance).not.toBeNull()
expect(instance._config.count).toBe(5)
expect(instance._config.colors).toEqual(['#f00'])
})
it("should apply each trigger's own options when several share a target", () => {
fixtureEl.innerHTML = '<button type="button" id="small" data-bs-toggle="confetti" data-bs-target="#order" data-bs-count="5"></button><button type="button" id="big" data-bs-toggle="confetti" data-bs-target="#order" data-bs-count="600"></button><div id="order"></div>'
reduceMotion(true)
const target = fixtureEl.querySelector('#order')!
fixtureEl.querySelector<HTMLElement>('#small')!.click()
expect((Confetti.getInstance(target) as Confetti)._config.count).toBe(5)
fixtureEl.querySelector<HTMLElement>('#big')!.click()
expect((Confetti.getInstance(target) as Confetti)._config.count).toBe(600)
fixtureEl.querySelector<HTMLElement>('#small')!.click()
expect((Confetti.getInstance(target) as Confetti)._config.count).toBe(5)
})
it('should ignore a disabled trigger', () => { it('should ignore a disabled trigger', () => {
fixtureEl.innerHTML = '<button type="button" data-bs-toggle="confetti" disabled></button>' fixtureEl.innerHTML = '<button type="button" data-bs-toggle="confetti" disabled></button>'
reduceMotion(true) reduceMotion(true)
+1 -1
View File
@@ -58,7 +58,7 @@ Set `data-bs-speed` to scale how fast the pieces fall. `1` is the default. A low
### Target ### Target
Point `data-bs-target` at another element to run the shower from there. The element does not change how the shower looks; it is where the events fire and where the instance is stored, so a page can listen in one place. Point `data-bs-target` at another element to run the shower from there. Options are still read from the trigger, so the target only changes where the events fire and where the instance is stored, letting a page listen in one place.
<Example centered> <Example centered>
<button type="button" class="btn btn-green" data-bs-toggle="confetti" data-bs-target="#confetti-order">Place order</button> <button type="button" class="btn btn-green" data-bs-toggle="confetti" data-bs-target="#confetti-order">Place order</button>