phoenix_duskmoon 10.0.9 → 10.0.10

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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ # [10.0.10](https://github.com/duskmoon-dev/phoenix-duskmoon-ui/compare/v10.0.9...v10.0.10) (2026-10-22)
2
+
3
+ ### Fixed
4
+
5
+ - Let the native confirmation command close its dialog once, avoiding duplicate-close
6
+ browser warnings while preserving LiveView events, form submit/reset and custom
7
+ command behavior, resolving
8
+ [#208](https://github.com/duskmoon-dev/phoenix-duskmoon-ui/issues/208).
9
+
1
10
  # [10.0.9](https://github.com/duskmoon-dev/phoenix-duskmoon-ui/compare/v10.0.8...v10.0.9) (2026-10-21)
2
11
 
3
12
  ### Fixed
@@ -258,13 +258,18 @@ export const FormElementHook = {
258
258
  },
259
259
  };
260
260
 
261
- /** Close the current confirm dialog before submit/reset/custom command default actions. */
261
+ /** Close before other actions, leaving native close commands to the browser. */
262
262
  export function handleDialogConfirmClick(event) {
263
263
  const path = event.composedPath?.() ?? [];
264
264
  const action = path.find((node) => node.matches?.(DIALOG_CONFIRM_SELECTOR));
265
265
  const dialog = path.find((node) => node.matches?.(DIALOG_SELECTOR));
266
266
 
267
- if (action && dialog?.open) dialog.close();
267
+ if (!action || !dialog?.open) return;
268
+
269
+ const formAction = action.form && ["submit", "reset"].includes(action.type);
270
+ const nativeClose = action.command === "close" && action.commandForElement === dialog;
271
+
272
+ if (!nativeClose || formAction) dialog.close();
268
273
  }
269
274
 
270
275
  /** Install CSP-safe delegated behavior for LiveView-patched confirm dialogs. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "phoenix_duskmoon",
3
- "version": "10.0.9",
3
+ "version": "10.0.10",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./priv/static/assets/js/phoenix_duskmoon.js",
@@ -1 +1 @@
1
- const e=[`dm-click`,`dm-change`,`dm-input`,`dm-focus`,`dm-blur`,`dm-submit`,`dm-select`,`dm-close`,`dm-open`,`dm-toggle`],t=Symbol.for(`phoenix-duskmoon.dialog-behavior-listeners`),n={mounted(){this._sendListeners=[],this._setupEventBridging(),this._setupAutomaticForwarding()},updated(){this._setupAutomaticForwarding()},destroyed(){this._sendListeners&&(this._sendListeners.forEach(({event:e,listener:t})=>{this.el.removeEventListener(e,t)}),this._sendListeners=null),e.forEach(e=>{let t=`_dm_listener_${e}`;this[t]&&(this.el.removeEventListener(e,this[t]),this[t]=null)})},_setupEventBridging(){let e=this.el.attributes,t=this.el.getAttribute(`phx-target`),n=(e,n,r)=>{t?this.pushEventTo(t,e,n,r):this.pushEvent(e,n,r)};for(let t=0;t<e.length;t++){let r=e[t];if(/^duskmoon-send-/.test(r.name)){let e=r.name.replace(/^duskmoon-send-/,``),[t,i]=r.value.split(`;`),a=({detail:r})=>{n(t,r||{},t=>{i&&typeof this[i]==`function`&&this[i](t,r,e)})};this.el.addEventListener(e,a),this._sendListeners.push({event:e,listener:a})}if(/^duskmoon-receive-/.test(r.name)){let e=r.name.replace(/^duskmoon-receive-/,``),t=r.value;this.handleEvent(e,n=>{t&&typeof this.el[t]==`function`?this.el[t](n):this.el.dispatchEvent(new CustomEvent(e,{detail:n,bubbles:!0,composed:!0}))})}if(r.name===`duskmoon-receive`){let[e,t]=r.value.split(`;`);this.handleEvent(e,e=>{typeof this.el[t]==`function`&&this.el[t](e)})}}},_setupAutomaticForwarding(){let t=this.el.getAttribute(`phx-target`);e.forEach(e=>{let n=`phx-`+e.replace(`dm-`,``),r=this.el.getAttribute(n);if(r){let n=`_dm_listener_${e}`;this[n]&&this.el.removeEventListener(e,this[n]),this[n]=e=>{let n={...e.detail||{},value:this.el.value,name:this.el.name,checked:this.el.checked};t?this.pushEventTo(t,r,n):this.pushEvent(r,n)},this.el.addEventListener(e,this[n])}})}},r={...n,mounted(){n.mounted.call(this),this._setupFormIntegration()},_setupFormIntegration(){let e=this.el.getAttribute(`name`),t=this.el.getAttribute(`phx-feedback-for`)||e;t&&this._setupFeedbackObserver(t)},destroyed(){n.destroyed.call(this),this._feedbackObserver&&(this._feedbackObserver.disconnect(),this._feedbackObserver=null)},_setupFeedbackObserver(e){let t=this.el.closest(`form`);t&&(this._feedbackObserver=new MutationObserver(n=>{n.forEach(n=>{if(n.attributeName===`class`){let n=t.classList.contains(`phx-no-feedback`);this.el.dispatchEvent(new CustomEvent(`dm-feedback-change`,{detail:{showFeedback:!n,field:e}}))}})}),this._feedbackObserver.observe(t,{attributes:!0,attributeFilter:[`class`]}))}};function i(e){let t=e.composedPath?.()??[],n=t.find(e=>e.matches?.(`[data-dm-confirm-action="true"]`)),r=t.find(e=>e.matches?.(`dialog[data-dm-confirm-dialog="true"]`));n&&r?.open&&r.close()}function a(e=globalThis.document){!e?.addEventListener||e[t]||(e.addEventListener(`click`,i,!0),e[t]=i)}a(),typeof window<`u`&&(window.__WebComponentHook__=n,window.__FormElementHook__=r);export{r as FormElementHook,n as WebComponentHook,i as handleDialogConfirmClick,a as installDialogBehavior};
1
+ const e=[`dm-click`,`dm-change`,`dm-input`,`dm-focus`,`dm-blur`,`dm-submit`,`dm-select`,`dm-close`,`dm-open`,`dm-toggle`],t=Symbol.for(`phoenix-duskmoon.dialog-behavior-listeners`),n={mounted(){this._sendListeners=[],this._setupEventBridging(),this._setupAutomaticForwarding()},updated(){this._setupAutomaticForwarding()},destroyed(){this._sendListeners&&(this._sendListeners.forEach(({event:e,listener:t})=>{this.el.removeEventListener(e,t)}),this._sendListeners=null),e.forEach(e=>{let t=`_dm_listener_${e}`;this[t]&&(this.el.removeEventListener(e,this[t]),this[t]=null)})},_setupEventBridging(){let e=this.el.attributes,t=this.el.getAttribute(`phx-target`),n=(e,n,r)=>{t?this.pushEventTo(t,e,n,r):this.pushEvent(e,n,r)};for(let t=0;t<e.length;t++){let r=e[t];if(/^duskmoon-send-/.test(r.name)){let e=r.name.replace(/^duskmoon-send-/,``),[t,i]=r.value.split(`;`),a=({detail:r})=>{n(t,r||{},t=>{i&&typeof this[i]==`function`&&this[i](t,r,e)})};this.el.addEventListener(e,a),this._sendListeners.push({event:e,listener:a})}if(/^duskmoon-receive-/.test(r.name)){let e=r.name.replace(/^duskmoon-receive-/,``),t=r.value;this.handleEvent(e,n=>{t&&typeof this.el[t]==`function`?this.el[t](n):this.el.dispatchEvent(new CustomEvent(e,{detail:n,bubbles:!0,composed:!0}))})}if(r.name===`duskmoon-receive`){let[e,t]=r.value.split(`;`);this.handleEvent(e,e=>{typeof this.el[t]==`function`&&this.el[t](e)})}}},_setupAutomaticForwarding(){let t=this.el.getAttribute(`phx-target`);e.forEach(e=>{let n=`phx-`+e.replace(`dm-`,``),r=this.el.getAttribute(n);if(r){let n=`_dm_listener_${e}`;this[n]&&this.el.removeEventListener(e,this[n]),this[n]=e=>{let n={...e.detail||{},value:this.el.value,name:this.el.name,checked:this.el.checked};t?this.pushEventTo(t,r,n):this.pushEvent(r,n)},this.el.addEventListener(e,this[n])}})}},r={...n,mounted(){n.mounted.call(this),this._setupFormIntegration()},_setupFormIntegration(){let e=this.el.getAttribute(`name`),t=this.el.getAttribute(`phx-feedback-for`)||e;t&&this._setupFeedbackObserver(t)},destroyed(){n.destroyed.call(this),this._feedbackObserver&&(this._feedbackObserver.disconnect(),this._feedbackObserver=null)},_setupFeedbackObserver(e){let t=this.el.closest(`form`);t&&(this._feedbackObserver=new MutationObserver(n=>{n.forEach(n=>{if(n.attributeName===`class`){let n=t.classList.contains(`phx-no-feedback`);this.el.dispatchEvent(new CustomEvent(`dm-feedback-change`,{detail:{showFeedback:!n,field:e}}))}})}),this._feedbackObserver.observe(t,{attributes:!0,attributeFilter:[`class`]}))}};function i(e){let t=e.composedPath?.()??[],n=t.find(e=>e.matches?.(`[data-dm-confirm-action="true"]`)),r=t.find(e=>e.matches?.(`dialog[data-dm-confirm-dialog="true"]`));if(!n||!r?.open)return;let i=n.form&&[`submit`,`reset`].includes(n.type);(!(n.command===`close`&&n.commandForElement===r)||i)&&r.close()}function a(e=globalThis.document){!e?.addEventListener||e[t]||(e.addEventListener(`click`,i,!0),e[t]=i)}a(),typeof window<`u`&&(window.__WebComponentHook__=n,window.__FormElementHook__=r);export{r as FormElementHook,n as WebComponentHook,i as handleDialogConfirmClick,a as installDialogBehavior};
@@ -1 +1 @@
1
- const e=[`dm-click`,`dm-change`,`dm-input`,`dm-focus`,`dm-blur`,`dm-submit`,`dm-select`,`dm-close`,`dm-open`,`dm-toggle`],t=Symbol.for(`phoenix-duskmoon.dialog-behavior-listeners`),n={mounted(){this._sendListeners=[],this._setupEventBridging(),this._setupAutomaticForwarding()},updated(){this._setupAutomaticForwarding()},destroyed(){this._sendListeners&&(this._sendListeners.forEach(({event:e,listener:t})=>{this.el.removeEventListener(e,t)}),this._sendListeners=null),e.forEach(e=>{let t=`_dm_listener_${e}`;this[t]&&(this.el.removeEventListener(e,this[t]),this[t]=null)})},_setupEventBridging(){let e=this.el.attributes,t=this.el.getAttribute(`phx-target`),n=(e,n,r)=>{t?this.pushEventTo(t,e,n,r):this.pushEvent(e,n,r)};for(let t=0;t<e.length;t++){let r=e[t];if(/^duskmoon-send-/.test(r.name)){let e=r.name.replace(/^duskmoon-send-/,``),[t,i]=r.value.split(`;`),a=({detail:r})=>{n(t,r||{},t=>{i&&typeof this[i]==`function`&&this[i](t,r,e)})};this.el.addEventListener(e,a),this._sendListeners.push({event:e,listener:a})}if(/^duskmoon-receive-/.test(r.name)){let e=r.name.replace(/^duskmoon-receive-/,``),t=r.value;this.handleEvent(e,n=>{t&&typeof this.el[t]==`function`?this.el[t](n):this.el.dispatchEvent(new CustomEvent(e,{detail:n,bubbles:!0,composed:!0}))})}if(r.name===`duskmoon-receive`){let[e,t]=r.value.split(`;`);this.handleEvent(e,e=>{typeof this.el[t]==`function`&&this.el[t](e)})}}},_setupAutomaticForwarding(){let t=this.el.getAttribute(`phx-target`);e.forEach(e=>{let n=`phx-`+e.replace(`dm-`,``),r=this.el.getAttribute(n);if(r){let n=`_dm_listener_${e}`;this[n]&&this.el.removeEventListener(e,this[n]),this[n]=e=>{let n={...e.detail||{},value:this.el.value,name:this.el.name,checked:this.el.checked};t?this.pushEventTo(t,r,n):this.pushEvent(r,n)},this.el.addEventListener(e,this[n])}})}},r={...n,mounted(){n.mounted.call(this),this._setupFormIntegration()},_setupFormIntegration(){let e=this.el.getAttribute(`name`),t=this.el.getAttribute(`phx-feedback-for`)||e;t&&this._setupFeedbackObserver(t)},destroyed(){n.destroyed.call(this),this._feedbackObserver&&(this._feedbackObserver.disconnect(),this._feedbackObserver=null)},_setupFeedbackObserver(e){let t=this.el.closest(`form`);t&&(this._feedbackObserver=new MutationObserver(n=>{n.forEach(n=>{if(n.attributeName===`class`){let n=t.classList.contains(`phx-no-feedback`);this.el.dispatchEvent(new CustomEvent(`dm-feedback-change`,{detail:{showFeedback:!n,field:e}}))}})}),this._feedbackObserver.observe(t,{attributes:!0,attributeFilter:[`class`]}))}};function i(e){let t=e.composedPath?.()??[],n=t.find(e=>e.matches?.(`[data-dm-confirm-action="true"]`)),r=t.find(e=>e.matches?.(`dialog[data-dm-confirm-dialog="true"]`));n&&r?.open&&r.close()}function a(e=globalThis.document){!e?.addEventListener||e[t]||(e.addEventListener(`click`,i,!0),e[t]=i)}a(),typeof window<`u`&&(window.__WebComponentHook__=n,window.__FormElementHook__=r);export{r as FormElementHook,n as WebComponentHook,i as handleDialogConfirmClick,a as installDialogBehavior};
1
+ const e=[`dm-click`,`dm-change`,`dm-input`,`dm-focus`,`dm-blur`,`dm-submit`,`dm-select`,`dm-close`,`dm-open`,`dm-toggle`],t=Symbol.for(`phoenix-duskmoon.dialog-behavior-listeners`),n={mounted(){this._sendListeners=[],this._setupEventBridging(),this._setupAutomaticForwarding()},updated(){this._setupAutomaticForwarding()},destroyed(){this._sendListeners&&(this._sendListeners.forEach(({event:e,listener:t})=>{this.el.removeEventListener(e,t)}),this._sendListeners=null),e.forEach(e=>{let t=`_dm_listener_${e}`;this[t]&&(this.el.removeEventListener(e,this[t]),this[t]=null)})},_setupEventBridging(){let e=this.el.attributes,t=this.el.getAttribute(`phx-target`),n=(e,n,r)=>{t?this.pushEventTo(t,e,n,r):this.pushEvent(e,n,r)};for(let t=0;t<e.length;t++){let r=e[t];if(/^duskmoon-send-/.test(r.name)){let e=r.name.replace(/^duskmoon-send-/,``),[t,i]=r.value.split(`;`),a=({detail:r})=>{n(t,r||{},t=>{i&&typeof this[i]==`function`&&this[i](t,r,e)})};this.el.addEventListener(e,a),this._sendListeners.push({event:e,listener:a})}if(/^duskmoon-receive-/.test(r.name)){let e=r.name.replace(/^duskmoon-receive-/,``),t=r.value;this.handleEvent(e,n=>{t&&typeof this.el[t]==`function`?this.el[t](n):this.el.dispatchEvent(new CustomEvent(e,{detail:n,bubbles:!0,composed:!0}))})}if(r.name===`duskmoon-receive`){let[e,t]=r.value.split(`;`);this.handleEvent(e,e=>{typeof this.el[t]==`function`&&this.el[t](e)})}}},_setupAutomaticForwarding(){let t=this.el.getAttribute(`phx-target`);e.forEach(e=>{let n=`phx-`+e.replace(`dm-`,``),r=this.el.getAttribute(n);if(r){let n=`_dm_listener_${e}`;this[n]&&this.el.removeEventListener(e,this[n]),this[n]=e=>{let n={...e.detail||{},value:this.el.value,name:this.el.name,checked:this.el.checked};t?this.pushEventTo(t,r,n):this.pushEvent(r,n)},this.el.addEventListener(e,this[n])}})}},r={...n,mounted(){n.mounted.call(this),this._setupFormIntegration()},_setupFormIntegration(){let e=this.el.getAttribute(`name`),t=this.el.getAttribute(`phx-feedback-for`)||e;t&&this._setupFeedbackObserver(t)},destroyed(){n.destroyed.call(this),this._feedbackObserver&&(this._feedbackObserver.disconnect(),this._feedbackObserver=null)},_setupFeedbackObserver(e){let t=this.el.closest(`form`);t&&(this._feedbackObserver=new MutationObserver(n=>{n.forEach(n=>{if(n.attributeName===`class`){let n=t.classList.contains(`phx-no-feedback`);this.el.dispatchEvent(new CustomEvent(`dm-feedback-change`,{detail:{showFeedback:!n,field:e}}))}})}),this._feedbackObserver.observe(t,{attributes:!0,attributeFilter:[`class`]}))}};function i(e){let t=e.composedPath?.()??[],n=t.find(e=>e.matches?.(`[data-dm-confirm-action="true"]`)),r=t.find(e=>e.matches?.(`dialog[data-dm-confirm-dialog="true"]`));if(!n||!r?.open)return;let i=n.form&&[`submit`,`reset`].includes(n.type);(!(n.command===`close`&&n.commandForElement===r)||i)&&r.close()}function a(e=globalThis.document){!e?.addEventListener||e[t]||(e.addEventListener(`click`,i,!0),e[t]=i)}a(),typeof window<`u`&&(window.__WebComponentHook__=n,window.__FormElementHook__=r);export{r as FormElementHook,n as WebComponentHook,i as handleDialogConfirmClick,a as installDialogBehavior};
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "!comment!":"This file was auto-generated by `mix phx.digest`. Remove it and all generated artefacts with `mix phx.digest.clean --all`",
3
3
  "version":1,
4
- "latest":{"assets/css/app.css":"assets/css/app-8305fbeb48a74c180d2d40e5e2a038c9.css","assets/css/manifest.json":"assets/css/manifest-771fd8eaae673c76a85c29e7b1106af0.json","assets/js/manifest.json":"assets/js/manifest-b1cb13d0ed943a03c54da6dd727c4ea5.json","assets/js/phoenix_duskmoon.js":"assets/js/phoenix_duskmoon-1d3f4951080405842d72f20baa38d4e9.js"},
5
- "digests":{"assets/css/app-8305fbeb48a74c180d2d40e5e2a038c9.css":{"size":807121,"sha512":"HhFYdMA1G3Em4WqiiVn3PVZtn/ycbYaXBI6s76lgSEOuHqdqHTppaSdvdyjo7cP9GOriidcrRt+fYpbhkH3t5w==","mtime":63959735577,"digest":"8305fbeb48a74c180d2d40e5e2a038c9","logical_path":"assets/css/app.css"},"assets/css/manifest-771fd8eaae673c76a85c29e7b1106af0.json":{"size":100,"sha512":"MNvnqDa/IgJZPGOqVMw/HbfH7xdXVKmJCtAxN2+C/85JfkoFIhxgJ/V+gUJcvHhBnBVTB1M9fU87FJzyAXPhyQ==","mtime":63959735577,"digest":"771fd8eaae673c76a85c29e7b1106af0","logical_path":"assets/css/manifest.json"},"assets/js/manifest-b1cb13d0ed943a03c54da6dd727c4ea5.json":{"size":184,"sha512":"BTfsrl88Ai6yWI57UhqJvF3SqXrV1dN60XQFdeHHv+kTdGuYz5jp6xBcK9STo9jdaW9JPVGAI8BjAImgxkGJdw==","mtime":63959735577,"digest":"b1cb13d0ed943a03c54da6dd727c4ea5","logical_path":"assets/js/manifest.json"},"assets/js/phoenix_duskmoon-1d3f4951080405842d72f20baa38d4e9.js":{"size":3005,"sha512":"YHfZAjNyxI37EHOVAYMaZPkKSxyBrCH4KZUb67lMYzAuv/XKzLlirAuehC30Z38zirmxoHfIE88UXePi/yjgtA==","mtime":63959735577,"digest":"1d3f4951080405842d72f20baa38d4e9","logical_path":"assets/js/phoenix_duskmoon.js"}}
4
+ "latest":{"assets/css/app.css":"assets/css/app-8305fbeb48a74c180d2d40e5e2a038c9.css","assets/css/manifest.json":"assets/css/manifest-771fd8eaae673c76a85c29e7b1106af0.json","assets/js/manifest.json":"assets/js/manifest-b1cb13d0ed943a03c54da6dd727c4ea5.json","assets/js/phoenix_duskmoon.js":"assets/js/phoenix_duskmoon-c22eb67823f82d7b0d27eba5dbd7be12.js"},
5
+ "digests":{"assets/css/app-8305fbeb48a74c180d2d40e5e2a038c9.css":{"size":807121,"sha512":"HhFYdMA1G3Em4WqiiVn3PVZtn/ycbYaXBI6s76lgSEOuHqdqHTppaSdvdyjo7cP9GOriidcrRt+fYpbhkH3t5w==","mtime":63959824722,"digest":"8305fbeb48a74c180d2d40e5e2a038c9","logical_path":"assets/css/app.css"},"assets/css/manifest-771fd8eaae673c76a85c29e7b1106af0.json":{"size":100,"sha512":"MNvnqDa/IgJZPGOqVMw/HbfH7xdXVKmJCtAxN2+C/85JfkoFIhxgJ/V+gUJcvHhBnBVTB1M9fU87FJzyAXPhyQ==","mtime":63959824722,"digest":"771fd8eaae673c76a85c29e7b1106af0","logical_path":"assets/css/manifest.json"},"assets/js/manifest-b1cb13d0ed943a03c54da6dd727c4ea5.json":{"size":184,"sha512":"BTfsrl88Ai6yWI57UhqJvF3SqXrV1dN60XQFdeHHv+kTdGuYz5jp6xBcK9STo9jdaW9JPVGAI8BjAImgxkGJdw==","mtime":63959824722,"digest":"b1cb13d0ed943a03c54da6dd727c4ea5","logical_path":"assets/js/manifest.json"},"assets/js/phoenix_duskmoon-c22eb67823f82d7b0d27eba5dbd7be12.js":{"size":3120,"sha512":"ulzAj2MAGVqSYL/QkVOqiAKj4psHe7hN6xx7DScYNIwg3g5AdSlh3onS3b6GxsBvZTolvfG3kqS2J6jRj6uTfg==","mtime":63959824722,"digest":"c22eb67823f82d7b0d27eba5dbd7be12","logical_path":"assets/js/phoenix_duskmoon.js"}}
6
6
  }