diff --git a/CHANGELOG.md b/CHANGELOG.md
index c7f4df3..ed86737 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,21 @@
+# 3.0.0-next.1 (2026-07-17)
+* feat!: drawer now uses native Invoker Commands — `show`, `close` and `toggle` actions removed
+* feat: added shared `onCommand` helper for command-driven components
+* fix: popover now removes its command listener, positioning fallback and overridden element methods on disconnect
+
+# 3.0.0-next.0 (2026-07-02)
+* feat!: updated components to Winduum `3.0.0-next.7` (aligned with `winduum-elements`)
+* feat!: carousel rewritten to new API (`scrollBy`, `toggleScrollState`, `setSnappedAttribute`, `scrollToMarker`) — `pagination`, `counter` and `progress` targets replaced by `markerGroup`/`marker` targets and `vertical` value
+* feat!: drawer rewritten to new dialog-based API (`drawerEvents`, `drawerObserver`, `showDrawer`) — `dialog` value replaced by boolean `modal` value
+* feat!: popover rewritten to native Popover API with anchor positioning and `@floating-ui` fallback (`autoUpdate`, `placement` values)
+* feat!: removed dialog and details components (handled natively in Winduum 3)
+* feat!: form component now only validates on submit — field validation moved to the new field component
+* feat: added field component
+* feat: control component now toggles `data-active` attribute on change
+* feat: button component now shows ripple on click automatically
+* feat: toaster component now uses `toasterObserver`
+* fix: range component no longer calls `setTrackProperty` (handled internally by `setValue`)
+
# 2.0.10, 2.0.11 (2025-04-30)
* feat: added carousel component
diff --git a/README.md b/README.md
index d7a7f51..d64d9ca 100644
--- a/README.md
+++ b/README.md
@@ -14,6 +14,6 @@ Ready to use components and utilities for Stimulus
{
"@hotwired/stimulus": "^3",
"@newlogic-digital/utils-js": "^1",
- "winduum": "^2"
+ "winduum": "^3"
}
```
diff --git a/components/button/index.js b/components/button/index.js
index 4ec5a4e..c7f377a 100644
--- a/components/button/index.js
+++ b/components/button/index.js
@@ -1,4 +1,5 @@
import { Controller } from '@hotwired/stimulus'
+import { dataset } from '@newlogic-digital/utils-js'
export class Button extends Controller {
static values = {
@@ -30,6 +31,8 @@ export class Button extends Controller {
this.loadingValue && this.observer.observe(this.element, {
attributeFilter: [this.loadingAttribute],
})
+
+ dataset(this.element, 'action').add(`click->${this.identifier}#ripple`)
}
disconnect() {
diff --git a/components/carousel-experimental/index.js b/components/carousel-experimental/index.js
new file mode 100644
index 0000000..efc451d
--- /dev/null
+++ b/components/carousel-experimental/index.js
@@ -0,0 +1,60 @@
+import { Controller } from '@hotwired/stimulus'
+import { dataset } from '@newlogic-digital/utils-js'
+
+export class Carousel extends Controller {
+ static targets = ['content', 'markerGroup', 'marker', 'prev', 'next']
+
+ static values = {
+ vertical: Boolean,
+ }
+
+ async connect() {
+ const { setSnappedAttribute, toggleScrollState } = await import('winduum/src/components/carousel-experimental/index.js')
+
+ this.abortController = new AbortController()
+ const signal = this.abortController.signal
+
+ this.contentTarget.addEventListener('scrollsnapchanging', (event) => {
+ setSnappedAttribute(this.contentTarget, event.snapTargetInline ?? event.snapTargetBlock, this.hasMarkerGroupTarget ? this.markerGroupTarget : null)
+ }, { signal })
+
+ this.contentTarget.addEventListener('scroll', () => {
+ toggleScrollState(this.contentTarget, {
+ prevElement: this.hasPrevTarget ? this.prevTarget : null,
+ nextElement: this.hasNextTarget ? this.nextTarget : null,
+ vertical: this.verticalValue,
+ })
+ }, { signal })
+ }
+
+ disconnect() {
+ this.abortController?.abort()
+ }
+
+ markerTargetConnected(element) {
+ dataset(element, 'action').add(`click->${this.identifier}#scrollToMarker:prevent`)
+ }
+
+ async scrollToMarker({ currentTarget }) {
+ const { scrollToMarker } = await import('winduum/src/components/carousel-experimental/index.js')
+
+ scrollToMarker(this.contentTarget, currentTarget, this.markerGroupTarget, this.verticalValue ? { block: 'start' } : {})
+ }
+
+ async scroll(direction) {
+ const { scrollBy } = await import('winduum/src/components/carousel-experimental/index.js')
+
+ scrollBy(this.contentTarget, {
+ direction,
+ vertical: this.verticalValue,
+ })
+ }
+
+ scrollPrev() {
+ this.scroll(-1)
+ }
+
+ scrollNext() {
+ this.scroll(1)
+ }
+}
diff --git a/components/carousel-experimental/readme.md b/components/carousel-experimental/readme.md
new file mode 100644
index 0000000..30dcfd2
--- /dev/null
+++ b/components/carousel-experimental/readme.md
@@ -0,0 +1,26 @@
+# [Carousel Experimental](https://winduum.dev/docs/components/carousel-experimental.html)
+
+## Installation
+```shell
+npm i winduum-stimulus
+```
+
+```js
+import { Application } from '@hotwired/stimulus'
+import { Carousel } from 'winduum-stimulus/components/carousel-experimental/index.js'
+
+const application = Application.start()
+
+application.register('x-carousel-experimental', Carousel)
+```
+
+### Local imports
+By default, imports are directly from `npm` so you can leverage updates.
+Alternatively, you can also copy and paste the code from this directory to your project and remap the imports to local.
+
+```js
+import { Carousel } from '@/components/ui/carousel-experimental/index.js'
+```
+
+### Docs
+Visit [docs](https://winduum.dev/docs/components/carousel-experimental.html) to learn more about JavaScript API and see usage examples.
diff --git a/components/carousel/index.js b/components/carousel/index.js
index e2af46d..fa1b552 100644
--- a/components/carousel/index.js
+++ b/components/carousel/index.js
@@ -8,7 +8,7 @@ export class Carousel extends Controller {
async connect() {
await this.scroll()
- if (this.hasPaginationTarget) {
+ if (this.hasPaginationTarget && !this.paginationTarget.children.length) {
const { paginationCarousel } = await import('winduum/src/components/carousel/index.js')
paginationCarousel(this.contentTarget, {
diff --git a/components/control/index.js b/components/control/index.js
index 8229eb3..d247008 100644
--- a/components/control/index.js
+++ b/components/control/index.js
@@ -1,7 +1,22 @@
import { Controller } from '@hotwired/stimulus'
-import { dispatchCustomEvent } from '@newlogic-digital/utils-js'
+import { dataset, dispatchCustomEvent } from '@newlogic-digital/utils-js'
export class Control extends Controller {
+ activeAttribute = 'data-active'
+
+ connect() {
+ this.toggleActiveAttribute()
+ dataset(this.element, 'action').add(`change->${this.identifier}#toggleActiveAttribute`)
+ }
+
+ toggleActiveAttribute() {
+ const telCountryCode = this.element.querySelector('[autocomplete="tel-country-code"]')
+
+ if (telCountryCode) telCountryCode.nextElementSibling.textContent = telCountryCode.value
+
+ this.element.toggleAttribute(this.activeAttribute, !!this.element.querySelector('input:not([type="hidden"]), textarea, select')?.value)
+ }
+
stepUp() {
this.element.querySelector('input').stepUp()
dispatchCustomEvent(this.element.querySelector('input'))
diff --git a/components/details/index.js b/components/details/index.js
index 5deceb2..32f6866 100644
--- a/components/details/index.js
+++ b/components/details/index.js
@@ -1,38 +1,9 @@
import { Controller } from '@hotwired/stimulus'
export class Details extends Controller {
- async show({ currentTarget, params }) {
- const { showDetails } = await import('winduum/src/components/details/index.js')
-
- await showDetails(currentTarget, params)
- }
-
- async close({ currentTarget, params }) {
- const { closeDetails } = await import('winduum/src/components/details/index.js')
-
- await closeDetails(currentTarget, params)
- }
-
- async toggle({ currentTarget, params }) {
+ async toggleDetails({ currentTarget }) {
const { toggleDetails } = await import('winduum/src/components/details/index.js')
- this.closeSiblings({ params })
-
- await toggleDetails(currentTarget, params)
- }
-
- closeSiblings({ params }) {
- if (!this.element.dataset.name) return
-
- document.querySelectorAll(`details[data-name="${this.element.dataset.name}"]`).forEach((currentTarget) => {
- if (currentTarget !== this.element) this.close({ currentTarget, params })
- })
- }
-
- connect() {
- if (this.element.name) {
- this.element.dataset.name = this.element.name
- this.element.removeAttribute('name')
- }
+ toggleDetails(currentTarget, arguments[0]?.params)
}
}
diff --git a/components/dialog/index.js b/components/dialog/index.js
deleted file mode 100644
index 289467c..0000000
--- a/components/dialog/index.js
+++ /dev/null
@@ -1,23 +0,0 @@
-import { Controller } from '@hotwired/stimulus'
-
-export class Dialog extends Controller {
- static values = {
- params: Object,
- }
-
- connect() {
- this.dispatch('connect')
- }
-
- async show(event) {
- const { showDialog } = await import('winduum/src/components/dialog/index.js')
-
- await showDialog(this.element, this.hasParamsValue ? this.paramsValue : event?.params)
- }
-
- async close(event) {
- const { closeDialog } = await import('winduum/src/components/dialog/index.js')
-
- await closeDialog(this.element, this.hasParamsValue ? this.paramsValue : event?.params)
- }
-}
diff --git a/components/dialog/readme.md b/components/dialog/readme.md
deleted file mode 100644
index eb2af45..0000000
--- a/components/dialog/readme.md
+++ /dev/null
@@ -1,72 +0,0 @@
-# [Dialog](https://winduum.dev/docs/components/dialog.html)
-
-## Installation
-```shell
-npm i winduum-stimulus
-```
-
-```js
-import { Application } from '@hotwired/stimulus'
-import { Dialog } from 'winduum-stimulus/components/dialog/index.js'
-
-const application = Application.start()
-
-application.register('x-dialog', Dialog)
-```
-
-### Local imports
-By default, imports are directly from `npm` so you can leverage updates.
-Alternatively, you can also copy and paste the code from this directory to your project and remap the imports to local.
-
-```js
-import { Dialog } from '@/components/ui/dialog/index.js'
-```
-
-### Docs
-Visit [docs](https://winduum.dev/docs/components/dialog.html) to learn more about JavaScript API and see usage examples.
-
-## Actions
-
-Controller is present directly on the `dialog` element, so you need to use [Invoke](https://github.com/winduum/winduum-stimulus/tree/main/utilities/invoke) action to invoke an action outside the controller.
-
-### show
-Show a dialog via [showDialog](https://winduum.dev/docs/components/dialog.html#showdialog) method.
-You can add any params from [options](https://winduum.dev/docs/components/dialog.html#showoptions) via [Invoke](https://github.com/winduum/winduum-stimulus/tree/main/utilities/invoke) params or via `data-x-dialog-params-value` on `x-dialog`.
-
-#### Example
-
-```html
-
-
-
-
-```
-
-### close
-Close a dialog via [closeDialog](https://winduum.dev/docs/components/dialog.html#closedialog) method.
-You can add any params from [options](https://winduum.dev/docs/components/dialog.html#closeoptions) via [Action](https://stimulus.hotwired.dev/reference/actions#action-parameters) params or via `data-x-dialog-params-value` on `x-dialog`.
-
-#### Example
-
-```html
-
-
-
-```
diff --git a/components/drawer/index.js b/components/drawer/index.js
index f48d406..df59009 100644
--- a/components/drawer/index.js
+++ b/components/drawer/index.js
@@ -1,4 +1,5 @@
import { Controller } from '@hotwired/stimulus'
+import { onCommand } from '../../index.js'
export class Drawer extends Controller {
static targets = ['content']
@@ -8,99 +9,57 @@ export class Drawer extends Controller {
type: String,
default: 'left',
},
- dialog: {
- type: String,
- default: 'modal',
+ modal: {
+ type: Boolean,
+ default: true,
},
}
- async scroll({ target }) {
- const { scrollDrawer } = await import('winduum/src/components/drawer/index.js')
+ connect() {
+ this.showModal = HTMLDialogElement.prototype.showModal
+ this.show = HTMLDialogElement.prototype.show
+ this.close = HTMLDialogElement.prototype.close
+ this.abortController = new AbortController()
- const bottomTop = {
- snapClass: 'snap-y snap-mandatory',
- scrollSize: target.scrollHeight - target.clientHeight,
- scrollDirection: target.scrollTop,
- }
+ this.element.addEventListener('command', onCommand, { signal: this.abortController.signal })
- const rightBottom = {
- scrollClose: 0,
- opacityRatio: 0,
- }
+ this.element.showModal = async ({ source }) => {
+ const { showDrawer } = await import('winduum/src/components/drawer/index.js')
- const placement = {
- right: {
- ...rightBottom,
- scrollOpen: target.scrollWidth - target.clientWidth,
- },
- bottom: {
- ...rightBottom,
- ...bottomTop,
- scrollOpen: target.scrollHeight - target.clientHeight,
- },
- top: {
- ...bottomTop,
- scrollOpen: 0,
- scrollClose: target.scrollHeight - target.clientHeight,
- },
- }
+ this.triggerElement = source
- await scrollDrawer(target, placement[this.placementValue])
- }
+ if (this.element.open) return
- async show() {
- const { showDrawer, scrollInitDrawer } = await import('winduum/src/components/drawer/index.js')
+ if (this.modalValue) this.showModal.call(this.element)
+ else this.show.call(this.element)
- if (this.dialogValue === 'modal') {
- this.element.showModal()
- }
- else if (this.dialogValue === 'non-modal') {
- this.element.show()
+ source.ariaExpanded = true
+ showDrawer(this.element.firstElementChild, this.placementValue)
}
- const [distance, distanceClosed, direction] = {
- right: [this.element.scrollWidth, 0, 'left'],
- bottom: [this.element.scrollHeight, 0, 'top'],
- top: [0, this.element.scrollHeight, 'top'],
- }[this.placementValue] ?? []
+ this.element.close = () => {
+ this.close.call(this.element)
- await scrollInitDrawer(this.element, distanceClosed, direction)
-
- await showDrawer(this.element, distance, direction)
+ if (this.triggerElement) this.triggerElement.ariaExpanded = false
+ }
}
- async close() {
- const { closeDrawer } = await import('winduum/src/components/drawer/index.js')
-
- const [distance, direction] = {
- right: [0, 'left'],
- bottom: [0, 'top'],
- top: [this.element.scrollHeight, 'top'],
- }[this.placementValue] ?? []
-
- await closeDrawer(this.element, distance, direction)
-
- if (this.triggerElement) this.triggerElement.ariaExpanded = false
+ disconnect() {
+ delete this.element.showModal
+ delete this.element.close
+ this.abortController?.abort()
}
- async dismiss({ target }) {
- if (!this.element.open) return
+ async contentTargetConnected() {
+ const { drawerObserver, drawerEvents } = await import('winduum/src/components/drawer/index.js')
- if (!this.contentTarget.contains(target) && !this.contentTarget.isEqualNode(target)) {
- await this.close()
- }
- }
+ drawerEvents(this.element, this.contentTarget, this.placementValue, this.abortController.signal)
- async toggle({ currentTarget }) {
- this.triggerElement = currentTarget
+ this.observer = drawerObserver(this.element, this.placementValue)
+ this.observer.observe(this.contentTarget)
+ }
- if (this.element.inert) {
- currentTarget.ariaExpanded = true
- this.show()
- }
- else {
- currentTarget.ariaExpanded = false
- this.close()
- }
+ contentTargetDisconnected() {
+ this.observer?.disconnect()
}
}
diff --git a/components/drawer/readme.md b/components/drawer/readme.md
index 1c10fb9..cc22156 100644
--- a/components/drawer/readme.md
+++ b/components/drawer/readme.md
@@ -14,6 +14,28 @@ const application = Application.start()
application.register('x-drawer', Drawer)
```
+Open and close the Drawer with native Invoker Commands. The controller enhances `show-modal` with the Drawer scroll behavior, keeps the invoking button's `aria-expanded` state in sync and lets `request-close` preserve the swipe-style closing animation.
+
+```html
+
+
+
+```
+
+Use the [`invokers-polyfill`](https://www.npmjs.com/package/invokers-polyfill) when supporting browsers without Invoker Commands.
+
### Local imports
By default, imports are directly from `npm` so you can leverage updates.
Alternatively, you can also copy and paste the code from this directory to your project and remap the imports to local.
diff --git a/components/field/index.js b/components/field/index.js
new file mode 100644
index 0000000..7f22996
--- /dev/null
+++ b/components/field/index.js
@@ -0,0 +1,13 @@
+import { Controller } from '@hotwired/stimulus'
+import { validateField } from 'winduum/src/components/field/index.js'
+import { dataset } from '@newlogic-digital/utils-js'
+
+export class Field extends Controller {
+ connect() {
+ dataset(this.element, 'action').add(`change->${this.identifier}#validateField`)
+ }
+
+ validateField({ params }) {
+ validateField(this.element, params)
+ }
+}
diff --git a/components/field/readme.md b/components/field/readme.md
new file mode 100644
index 0000000..b96a96d
--- /dev/null
+++ b/components/field/readme.md
@@ -0,0 +1,26 @@
+# [Field](https://winduum.dev/docs/components/field.html)
+
+## Installation
+```shell
+npm i winduum-stimulus
+```
+
+```js
+import { Application } from '@hotwired/stimulus'
+import { Field } from 'winduum-stimulus/components/field/index.js'
+
+const application = Application.start()
+
+application.register('x-field', Field)
+```
+
+### Local imports
+By default, imports are directly from `npm` so you can leverage updates.
+Alternatively, you can also copy and paste the code from this directory to your project and remap the imports to local.
+
+```js
+import { Field } from '@/components/ui/field/index.js'
+```
+
+### Docs
+Visit [docs](https://winduum.dev/docs/components/field.html) to learn more about JavaScript API and see usage examples.
diff --git a/components/form/index.js b/components/form/index.js
index 82c44ef..afac183 100644
--- a/components/form/index.js
+++ b/components/form/index.js
@@ -1,5 +1,5 @@
import { Controller } from '@hotwired/stimulus'
-import { validateForm, validateField } from 'winduum/src/components/form/index.js'
+import { validateForm } from 'winduum/src/components/form/index.js'
import { dataset } from '@newlogic-digital/utils-js'
export class Form extends Controller {
@@ -11,8 +11,4 @@ export class Form extends Controller {
validateForm(event) {
validateForm(event, event?.params)
}
-
- validateField({ currentTarget, params }) {
- validateField(currentTarget, params)
- }
}
diff --git a/components/image/readme.md b/components/image/readme.md
new file mode 100644
index 0000000..03aab32
--- /dev/null
+++ b/components/image/readme.md
@@ -0,0 +1,26 @@
+# [Image](https://winduum.dev/docs/components/image.html)
+
+## Installation
+```shell
+npm i winduum-stimulus
+```
+
+```js
+import { Application } from '@hotwired/stimulus'
+import { Image } from 'winduum-stimulus/components/image/index.js'
+
+const application = Application.start()
+
+application.register('x-image', Image)
+```
+
+### Local imports
+By default, imports are directly from `npm` so you can leverage updates.
+Alternatively, you can also copy and paste the code from this directory to your project and remap the imports to local.
+
+```js
+import { Image } from '@/components/ui/image/index.js'
+```
+
+### Docs
+Visit [docs](https://winduum.dev/docs/components/image.html) to learn more about JavaScript API and see usage examples.
diff --git a/components/popover/index.js b/components/popover/index.js
index 1b1b73f..9653e10 100644
--- a/components/popover/index.js
+++ b/components/popover/index.js
@@ -1,45 +1,57 @@
import { Controller } from '@hotwired/stimulus'
-import { dataset } from '@newlogic-digital/utils-js'
+import { supportsAnchoredContainer, supportsAnchor } from 'winduum/src/common.js'
+import { onCommand } from '../../index.js'
export class Popover extends Controller {
- static targets = ['action']
static values = {
- params: Object,
+ autoUpdate: Boolean,
+ placement: String,
}
+ open = false
+
connect() {
- this.dispatch('connect')
- }
+ this.showPopover = HTMLElement.prototype.showPopover
+ this.hidePopover = HTMLElement.prototype.hidePopover
+ this.abortController = new AbortController()
- async toggle({ currentTarget }) {
- const { togglePopover } = await import('winduum/src/components/popover/index.js')
+ this.element.addEventListener('toggle', (event) => {
+ this.open = event.newState === 'open'
+ if (this.source?.ariaExpanded) this.source.ariaExpanded = this.open
+ }, { signal: this.abortController.signal })
- this.popoverTarget = document.getElementById(currentTarget.getAttribute('popovertarget'))
+ this.element.addEventListener('command', onCommand, { signal: this.abortController.signal })
- await togglePopover(currentTarget, this.hasParamsValue ? this.paramsValue : arguments[0]?.params)
- }
+ this.element.showPopover = async ({ source }) => {
+ if ((this.autoUpdateValue && !supportsAnchoredContainer) || !supportsAnchor) {
+ const { autoUpdatePopover } = await import('winduum/src/components/popover/index.js')
- async hide() {
- if (this.actionTarget.ariaExpanded !== 'true') return
+ this.cleanup = await autoUpdatePopover(source, this.element, this.placementValue, this.autoUpdateValue)
+ }
- const { hidePopover } = await import('winduum/src/components/popover/index.js')
+ this.source = source
- await hidePopover(this.actionTarget)
- }
+ this.showPopover.call(this.element, { source })
+ }
+
+ this.element.togglePopover = ({ source }) => {
+ !this.open
+ ? this.element.showPopover({ source })
+ : this.element.hidePopover()
+ }
- async dismiss({ target }) {
- if (this.actionTarget.ariaExpanded !== 'true') return
+ this.element.hidePopover = () => {
+ this.cleanup?.()
- if (!this.popoverTarget.contains(target) && !this.actionTarget.isEqualNode(target) && this.actionTarget.ariaExpanded === 'true') {
- await this.hide()
+ this.hidePopover.call(this.element)
}
}
- actionTargetConnected() {
- dataset(this.actionTarget, 'action').add(
- `click->${this.identifier}#${this.actionTarget.getAttribute('popovertargetaction')}:prevent`,
- `keydown.esc@window->${this.identifier}#hide`,
- `click@window->${this.identifier}#dismiss`,
- )
+ disconnect() {
+ this.cleanup?.()
+ delete this.element.showPopover
+ delete this.element.togglePopover
+ delete this.element.hidePopover
+ this.abortController?.abort()
}
}
diff --git a/components/range/index.js b/components/range/index.js
index eb7d43a..44f9895 100644
--- a/components/range/index.js
+++ b/components/range/index.js
@@ -4,20 +4,13 @@ export class Range extends Controller {
static targets = ['start', 'end']
async setValue({ currentTarget, params }) {
- const { setValue, setOutputValue, setTrackProperty } = await import('winduum/src/components/range/index.js')
+ const { setValue, setOutputValue } = await import('winduum/src/components/range/index.js')
setValue(currentTarget, {
- track: params.track ?? 'start',
+ track: params?.track ?? 'start',
})
setOutputValue(currentTarget, window[currentTarget.getAttribute('aria-labelledby')])
-
- setTrackProperty({
- element: this.element.parentElement,
- value: currentTarget.value,
- min: Number(currentTarget.min) || 0,
- max: Number(currentTarget.max) || 100,
- }, params.track ?? 'start')
}
async startTargetConnected() {
diff --git a/components/toast/index.js b/components/toast/index.js
index 8dd126f..c8ae2b1 100644
--- a/components/toast/index.js
+++ b/components/toast/index.js
@@ -1,4 +1,5 @@
import { Controller } from '@hotwired/stimulus'
+import { closeToast, showToast } from 'winduum/src/components/toast'
export class Toast extends Controller {
static values = {
@@ -10,14 +11,10 @@ export class Toast extends Controller {
}
async show(event) {
- const { showToast } = await import('winduum/src/components/toast/index.js')
-
await showToast(this.element, this.hasParamsValue ? this.paramsValue : event?.params)
}
async close(event) {
- const { closeToast } = await import('winduum/src/components/toast/index.js')
-
await closeToast(this.element, this.hasParamsValue ? this.paramsValue : event?.params)
}
}
diff --git a/components/toaster/index.js b/components/toaster/index.js
index cd46580..34d57b5 100644
--- a/components/toaster/index.js
+++ b/components/toaster/index.js
@@ -1,6 +1,17 @@
import { Controller } from '@hotwired/stimulus'
export class Toaster extends Controller {
+ async connect() {
+ const { toasterObserver } = await import('winduum/src/components/toaster/index.js')
+
+ this.observer = toasterObserver()
+ this.observer.observe(this.element, { childList: true })
+ }
+
+ disconnect() {
+ this.observer?.disconnect()
+ }
+
async close(event) {
const { closeToaster } = await import('winduum/src/components/toaster/index.js')
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..49a2887
--- /dev/null
+++ b/index.html
@@ -0,0 +1,180 @@
+
+
+
+
+
+ Popover demo
+
+
+
+
+
+
+ Popover demo
+
+ Demo pouziva controller z components/popover/index.js a nacita Stimulus i runtime dependencies pres import mapu.
+
+
+
+
+
+
+
+
+
Native popover
+
+ Tohle je obsah popoveru spravovany Stimulus controllerem.
+
+
+
+
+
+
+
+
diff --git a/index.js b/index.js
index 29ca5f0..e2381a1 100644
--- a/index.js
+++ b/index.js
@@ -1,5 +1,13 @@
import { dataset } from '@newlogic-digital/utils-js'
+export const onCommand = (event) => {
+ event.preventDefault()
+
+ const method = event.command.replace(/-\w/g, c => c[1].toUpperCase())
+
+ if (method in event.currentTarget) event.currentTarget[method](event)
+}
+
export function initActions(parent, selectors) {
if (!parent) return
@@ -35,4 +43,4 @@ export const useController = (controller, target, application) => {
return getController
}
-export default { initStimulus, initActions, initControllers, useController }
+export default { onCommand, initStimulus, initActions, initControllers, useController }
diff --git a/package-lock.json b/package-lock.json
index f6d74b1..3f2ddae 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,16 +1,16 @@
{
"name": "winduum-stimulus",
- "version": "2.0.13",
+ "version": "3.0.0-next.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "winduum-stimulus",
- "version": "2.0.13",
+ "version": "3.0.0-next.0",
"dependencies": {
"@hotwired/stimulus": "^3.2.2",
"@newlogic-digital/utils-js": "^1.2.0",
- "winduum": "^2.2.19"
+ "winduum": "^3.0.0-next.16"
},
"devDependencies": {
"@eslint/js": "^10.0.1",
@@ -974,9 +974,9 @@
}
},
"node_modules/winduum": {
- "version": "2.2.19",
- "resolved": "https://registry.npmjs.org/winduum/-/winduum-2.2.19.tgz",
- "integrity": "sha512-WDCpKD2V++492PHhUZTK8OOxjBHg5+q6pir1Fg9J8/BbiB1PdGrSLfS3mU+Tmn7ipo9jp9LJp8hJq0/fEhk9vA==",
+ "version": "3.0.0-next.16",
+ "resolved": "https://registry.npmjs.org/winduum/-/winduum-3.0.0-next.16.tgz",
+ "integrity": "sha512-Nk6GbAATr++Z1gGR46htvbzEaDxikgmmMVXz1DRb6hRJgL3UxqCIlXtKW3zs8yWJ5msvFxWdz1DoR8a/vd8dBg==",
"engines": {
"node": ">=20.0.0",
"npm": ">=9.0.0"
diff --git a/package.json b/package.json
index 68ed22f..bb42c39 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "winduum-stimulus",
- "version": "2.0.15",
+ "version": "3.0.0-next.1",
"type": "module",
"scripts": {
"eslint": "eslint",
@@ -10,7 +10,7 @@
"dependencies": {
"@hotwired/stimulus": "^3.2.2",
"@newlogic-digital/utils-js": "^1.2.0",
- "winduum": "^2.2.19"
+ "winduum": "^3.0.0-next.16"
},
"devDependencies": {
"@eslint/js": "^10.0.1",
diff --git a/utilities/invoke/readme.md b/utilities/invoke/readme.md
index 70eaa72..94a5939 100644
--- a/utilities/invoke/readme.md
+++ b/utilities/invoke/readme.md
@@ -10,13 +10,15 @@ This way you can place action anywhere you want. To trigger an invoke action, us
```html