kempo-ui 0.3.0 → 0.3.1

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.
@@ -1,4 +1,4 @@
1
- import ShadowComponent from"./ShadowComponent.js";import{html,css}from"../lit-all.min.js";import{boolExists}from"../utils/propConverters.js";import"./Icon.js";import"./FocusCapture.js";const firstFocusable=e=>e.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])')[0];export default class Dialog extends ShadowComponent{static properties={opened:{type:Boolean,reflect:!0,converter:boolExists},closeBtn:{type:Boolean,reflect:!0,attribute:"close-btn",converter:boolExists},overlayClose:{type:Boolean,reflect:!0,attribute:"overlay-close",converter:boolExists},disableKeyboardClose:{type:Boolean,reflect:!0,attribute:"disable-keyboard-close",converter:boolExists},confirmText:{type:String,reflect:!0,attribute:"confirm-text"},confirmClasses:{type:String,reflect:!0,attribute:"confirm-classes"},cancelText:{type:String,reflect:!0,attribute:"cancel-text"},cancelClasses:{type:String,reflect:!0,attribute:"cancel-classes"}};constructor(){super(),this.opened=!1,this.closeBtn=!0,this.overlayClose=!0,this.disableKeyboardClose=!1,this.confirmText="",this.confirmClasses="success ml",this.cancelText="",this.cancelClasses="",this.confirmAction=()=>{},this.cancelAction=()=>{},this.closeCallback=()=>{},this.previousFocus=null}handleClick=e=>{const{target:t}=e,o=t.id||t.closest("[id]")?.id;"overlay"===o&&this.overlayClose||"close"===o?this.close():"cancel"===o&&(this.cancelAction(e),e.defaultPrevented||this.close())};handleSubmit=e=>{e.preventDefault(),this.confirmAction(e),e.keepDialogOpen||this.close()};handleSlotKeydown=e=>{if("Enter"===e.key&&this.confirmText){const t=e.target;if("INPUT"===t.tagName||"TEXTAREA"===t.tagName){e.preventDefault();const t=this.shadowRoot.querySelector("form");t&&t.requestSubmit()}}};handleKeydown=e=>{this.disableKeyboardClose||27!==e.keyCode||this.close()};connectedCallback(){super.connectedCallback()}disconnectedCallback(){super.disconnectedCallback(),window.removeEventListener("keydown",this.handleKeydown)}updated(e){super.updated(e),e.has("opened")&&this.dispatchEvent(new CustomEvent(this.opened?"opened":"close"))}open(){this.opened=!0,window.addEventListener("keydown",this.handleKeydown),document.body.classList.add("no-scroll");const e=this.updateComplete||this.requestUpdate();e&&e.then?e.then(()=>{const e=this.shadowRoot.querySelector("[autofocus]")||firstFocusable(this.shadowRoot);e&&e.focus()}):setTimeout(()=>{const e=this.shadowRoot.querySelector("[autofocus]")||firstFocusable(this.shadowRoot);e&&e.focus()},0)}close(){this.opened=!1,this.blur(),this.closeCallback(),window.removeEventListener("keydown",this.handleKeydown),document.body.classList.remove("no-scroll")}toggle(){this.opened?this.close():this.open()}focus(){const e=firstFocusable(this.shadowRoot);e&&(this.previousFocus=document.activeElement,e.focus())}blur(){this.previousFocus&&this.previousFocus.focus()}hasTitle(){return!!this.querySelector('[slot="title"]')}static styles=css`
1
+ import ShadowComponent from"./ShadowComponent.js";import{html,css,render}from"../lit-all.min.js";import{boolExists}from"../utils/propConverters.js";import"./Icon.js";import"./FocusCapture.js";const firstFocusable=e=>e.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])')[0];export default class Dialog extends ShadowComponent{static properties={opened:{type:Boolean,reflect:!0,converter:boolExists},closeBtn:{type:Boolean,reflect:!0,attribute:"close-btn",converter:boolExists},overlayClose:{type:Boolean,reflect:!0,attribute:"overlay-close",converter:boolExists},disableKeyboardClose:{type:Boolean,reflect:!0,attribute:"disable-keyboard-close",converter:boolExists},confirmText:{type:String,reflect:!0,attribute:"confirm-text"},confirmClasses:{type:String,reflect:!0,attribute:"confirm-classes"},cancelText:{type:String,reflect:!0,attribute:"cancel-text"},cancelClasses:{type:String,reflect:!0,attribute:"cancel-classes"}};constructor(){super(),this.opened=!1,this.closeBtn=!0,this.overlayClose=!0,this.disableKeyboardClose=!1,this.confirmText="",this.confirmClasses="success ml",this.cancelText="",this.cancelClasses="",this.confirmAction=()=>{},this.cancelAction=()=>{},this.closeCallback=()=>{},this.previousFocus=null}handleClick=e=>{const{target:t}=e,o=t.id||t.closest("[id]")?.id;"overlay"===o&&this.overlayClose||"close"===o?this.close():"cancel"===o&&(this.cancelAction(e),e.defaultPrevented||this.close())};handleSubmit=e=>{e.preventDefault(),this.confirmAction(e),e.keepDialogOpen||this.close()};handleSlotKeydown=e=>{if("Enter"===e.key&&this.confirmText){const t=e.target;if("INPUT"===t.tagName||"TEXTAREA"===t.tagName){e.preventDefault();const t=this.shadowRoot.querySelector("form");t&&t.requestSubmit()}}};handleKeydown=e=>{this.disableKeyboardClose||27!==e.keyCode||this.close()};connectedCallback(){super.connectedCallback()}disconnectedCallback(){super.disconnectedCallback(),window.removeEventListener("keydown",this.handleKeydown)}updated(e){super.updated(e),e.has("opened")&&this.dispatchEvent(new CustomEvent(this.opened?"opened":"close"))}open(){this.opened=!0,window.addEventListener("keydown",this.handleKeydown),document.body.classList.add("no-scroll");const e=this.updateComplete||this.requestUpdate();e&&e.then?e.then(()=>{const e=this.shadowRoot.querySelector("[autofocus]")||firstFocusable(this.shadowRoot);e&&e.focus()}):setTimeout(()=>{const e=this.shadowRoot.querySelector("[autofocus]")||firstFocusable(this.shadowRoot);e&&e.focus()},0)}close(){this.opened=!1,this.blur(),this.closeCallback(),window.removeEventListener("keydown",this.handleKeydown),document.body.classList.remove("no-scroll")}toggle(){this.opened?this.close():this.open()}focus(){const e=firstFocusable(this.shadowRoot);e&&(this.previousFocus=document.activeElement,e.focus())}blur(){this.previousFocus&&this.previousFocus.focus()}hasTitle(){return!!this.querySelector('[slot="title"]')}static styles=css`
2
2
  :host {
3
3
  position: fixed;
4
4
  top: 0;
@@ -118,4 +118,4 @@ import ShadowComponent from"./ShadowComponent.js";import{html,css}from"../lit-al
118
118
  </form>
119
119
  </k-focus-capture>
120
120
  </div>
121
- `}static create(e="",t={}){!1!==t.closeExisting&&document.querySelectorAll("k-dialog").forEach(e=>e.close());const{removeOnClose:o=!0,closeCallback:s=()=>{},title:i="",titleClasses:l="pyh px m0"}=t,a=new Dialog;if(Object.assign(a,{opened:!0,...t,closeCallback:(...e)=>{o&&a.remove(),s(...e)}}),i){const e=document.createElement("h5");e.slot="title",e.className=l,i instanceof HTMLElement?e.appendChild(i):e.innerHTML=i,a.appendChild(e)}if(e instanceof HTMLElement||e instanceof DocumentFragment)a.appendChild(e);else if(e){if(/<[^>]+>/.test(e))a.innerHTML+=e;else{const t=document.createElement("p");t.className="p",t.textContent=e,a.appendChild(t)}}return t.width&&a.style.setProperty("--width",t.width),t.minWidth&&a.style.setProperty("--min_width",t.minWidth),t.maxWidth&&a.style.setProperty("--max_width",t.maxWidth),t.height&&a.style.setProperty("--height",t.height),t.minHeight&&a.style.setProperty("--min_height",t.minHeight),t.maxHeight&&a.style.setProperty("--max_height",t.maxHeight),document.body.appendChild(a),a.open(),a}static confirm(e,t,o={}){return Dialog.create(e,{title:o.title||"Confirm",closeBtn:!1,overlayClose:!1,disableKeyboardClose:!0,confirmText:"Yes",confirmClasses:"success ml",confirmAction:()=>t(!0),cancelText:"No",cancelClasses:"danger",cancelAction:()=>t(!1),...o})}static alert(e,t=()=>{},o={}){return Dialog.create(e,{title:o.title||"Alert",closeCallback:t,cancelText:"Ok",...o})}static error(e,t=()=>{},o={}){return Dialog.create(e,{title:o.title||"Error",titleClasses:"pyh px m0 tc-danger",closeCallback:t,cancelText:"Ok",...o})}static success(e,t=()=>{},o={}){return Dialog.create(e,{title:o.title||"Success",titleClasses:"pyh px m0 tc-success",closeCallback:t,cancelText:"Ok",...o})}}customElements.define("k-dialog",Dialog);
121
+ `}static create(e="",t={}){!1!==t.closeExisting&&document.querySelectorAll("k-dialog").forEach(e=>e.close());const{removeOnClose:o=!0,closeCallback:s=()=>{},title:i="",titleClasses:l="pyh px m0"}=t,n=new Dialog;if(Object.assign(n,{opened:!0,...t,closeCallback:(...e)=>{o&&n.remove(),s(...e)}}),i){const e=document.createElement("h5");e.slot="title",e.className=l,i instanceof HTMLElement?e.appendChild(i):e.innerHTML=i,n.appendChild(e)}if(void 0!==e?._$litType$){const t=document.createElement("div");t.style.display="contents",render(e,t),n.appendChild(t)}else if(e instanceof HTMLElement||e instanceof DocumentFragment)n.appendChild(e);else if(e){if(/<[^>]+>/.test(e))n.innerHTML+=e;else{const t=document.createElement("p");t.className="p",t.textContent=e,n.appendChild(t)}}return t.width&&n.style.setProperty("--width",t.width),t.minWidth&&n.style.setProperty("--min_width",t.minWidth),t.maxWidth&&n.style.setProperty("--max_width",t.maxWidth),t.height&&n.style.setProperty("--height",t.height),t.minHeight&&n.style.setProperty("--min_height",t.minHeight),t.maxHeight&&n.style.setProperty("--max_height",t.maxHeight),document.body.appendChild(n),n.open(),n}static confirm(e,t,o={}){return Dialog.create(e,{title:o.title||"Confirm",closeBtn:!1,overlayClose:!1,disableKeyboardClose:!0,confirmText:"Yes",confirmClasses:"success ml",confirmAction:()=>t(!0),cancelText:"No",cancelClasses:"danger",cancelAction:()=>t(!1),...o})}static alert(e,t=()=>{},o={}){return Dialog.create(e,{title:o.title||"Alert",closeCallback:t,cancelText:"Ok",...o})}static error(e,t=()=>{},o={}){return Dialog.create(e,{title:o.title||"Error",titleClasses:"pyh px m0 tc-danger",closeCallback:t,cancelText:"Ok",...o})}static success(e,t=()=>{},o={}){return Dialog.create(e,{title:o.title||"Success",titleClasses:"pyh px m0 tc-success",closeCallback:t,cancelText:"Ok",...o})}}customElements.define("k-dialog",Dialog);
@@ -27,6 +27,7 @@
27
27
  <a href="#actionButtons">Action Buttons</a><br />
28
28
  <a href="#disableKeyboardClose">Disabling Keyboard Close</a><br />
29
29
  <a href="#jsUsage">JavaScript Usage</a><br />
30
+ <a href="#litTemplate">Lit Template Content</a><br />
30
31
  <a href="#confirmDialog">Confirm Dialog</a><br />
31
32
 
32
33
  <h6 class="mt"><a href="#jsRef" class="no-link">JavaScript Reference</a></h6>
@@ -135,6 +136,25 @@
135
136
  });
136
137
  </script>
137
138
 
139
+ <h3 id="litTemplate"><a href="#litTemplate" class="no-link">Lit Template Content</a></h3>
140
+ <p>You can pass a Lit <code>html</code> tagged template literal directly as the content to any of the static methods (<code>Dialog.create</code>, <code>Dialog.confirm</code>, <code>Dialog.alert</code>, <code>Dialog.error</code>, <code>Dialog.success</code>).</p>
141
+ <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"d11"</span>&gt;</span>Open Dialog with Lit Template<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span><br /><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"module"</span>&gt;</span><span class="javascript"><br /> <span class="hljs-keyword">import</span> Dialog <span class="hljs-keyword">from</span> <span class="hljs-string">'/src/components/Dialog.js'</span>;<br /> <span class="hljs-keyword">import</span> { html } <span class="hljs-keyword">from</span> <span class="hljs-string">'/src/lit-all.min.js'</span>;<br /> <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'d11'</span>).addEventListener(<span class="hljs-string">'click'</span>, <span class="hljs-function">() =&gt;</span> {<br /> Dialog.create(html<span class="hljs-string">`<br /> &lt;div class="p"&gt;<br /> &lt;h6&gt;Custom Lit Content&lt;/h6&gt;<br /> &lt;p&gt;This was created with a Lit template.&lt;/p&gt;<br /> &lt;/div&gt;<br /> `</span>, {<br /> <span class="hljs-attr">title</span>: <span class="hljs-string">'Lit Template Dialog'</span><br /> });<br /> });<br /></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></code></pre>
142
+ <button id="d11" class="mb">Open Dialog with Lit Template</button>
143
+ <script type="module">
144
+ import Dialog from '../src/components/Dialog.js';
145
+ import { html } from '../src/lit-all.min.js';
146
+ document.getElementById('d11').addEventListener('click', () => {
147
+ Dialog.create(html`
148
+ <div class="p">
149
+ <h6>Custom Lit Content</h6>
150
+ <p>This was created with a Lit template.</p>
151
+ </div>
152
+ `, {
153
+ title: 'Lit Template Dialog'
154
+ });
155
+ });
156
+ </script>
157
+
138
158
  <h3 id="confirmDialog"><a href="#confirmDialog" class="no-link">Confirm Dialog</a></h3>
139
159
  <p>Use the <code>Dialog.confirm</code> static method to create a confirmation dialog. This method takes a text message, a response callback, and an options object.</p>
140
160
  <pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"d9"</span>&gt;</span>Open Confirm Dialog<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span><br /><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"module"</span>&gt;</span><span class="javascript"><br /> <span class="hljs-keyword">import</span> Dialog <span class="hljs-keyword">from</span> <span class="hljs-string">'/src/components/Dialog.js'</span>;<br /> <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'d9'</span>).addEventListener(<span class="hljs-string">'click'</span>, () =&gt; {<br /> Dialog.confirm(<span class="hljs-string">"Are you sure you want to proceed?"</span>, <span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> {<br /> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"User response:"</span>, response);<br /> });<br /> });<br /></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></code></pre>
@@ -240,11 +260,11 @@
240
260
  <h3 id="staticMethods"><a href="#staticMethods" class="no-link">Static Methods</a></h3>
241
261
  <h5><code>Dialog.create(contents, options)<i>: Dialog</i></code></h5>
242
262
  <p>Creates and opens a new dialog with the specified contents and options. Returns the created Dialog instance.</p>
243
- <p>If <code>contents</code> is plain text (no HTML tags), it will automatically be wrapped in a <code>&lt;p class="p"&gt;</code> tag. If it contains HTML, it will be inserted as-is. If it's an HTMLElement or DocumentFragment, it will be appended directly.</p>
263
+ <p>If <code>contents</code> is plain text (no HTML tags), it will automatically be wrapped in a <code>&lt;p class="p"&gt;</code> tag. If it contains HTML, it will be inserted as-is. If it's an HTMLElement or DocumentFragment, it will be appended directly. You can also pass a Lit <code>html</code> tagged template literal (<code>TemplateResult</code>), which will be rendered using Lit's <code>render()</code>.</p>
244
264
 
245
265
  <h6>Parameters</h6>
246
266
  <ul>
247
- <li><code>contents<i>: string | HTMLElement | DocumentFragment</i></code> - The content to display in the dialog. Plain text will be wrapped in a paragraph tag automatically.</li>
267
+ <li><code>contents<i>: string | HTMLElement | DocumentFragment | TemplateResult</i></code> - The content to display in the dialog. Plain text will be wrapped in a paragraph tag automatically.</li>
248
268
  <li><code>options<i>: object</i></code> - Configuration options for the dialog.</li>
249
269
  </ul>
250
270
 
@@ -278,7 +298,7 @@
278
298
 
279
299
  <h6>Parameters</h6>
280
300
  <ul>
281
- <li><code>text<i>: string</i></code> - The message to display in the dialog.</li>
301
+ <li><code>text<i>: string | TemplateResult</i></code> - The message to display in the dialog.</li>
282
302
  <li><code>responseCallback<i>: function</i></code> - Function called with the user's response (<code>true</code> for confirm, <code>false</code> for cancel).</li>
283
303
  <li><code>options<i>: object</i></code> - Configuration options.</li>
284
304
  </ul>
@@ -300,7 +320,7 @@
300
320
 
301
321
  <h6>Parameters</h6>
302
322
  <ul>
303
- <li><code>text<i>: string</i></code> - The message to display in the dialog.</li>
323
+ <li><code>text<i>: string | TemplateResult</i></code> - The message to display in the dialog.</li>
304
324
  <li><code>responseCallback<i>: function</i></code> - Function called when the dialog is closed.</li>
305
325
  <li><code>options<i>: object</i></code> - Configuration options.</li>
306
326
  </ul>
@@ -316,7 +336,7 @@
316
336
 
317
337
  <h6>Parameters</h6>
318
338
  <ul>
319
- <li><code>text<i>: string</i></code> - The error message to display in the dialog.</li>
339
+ <li><code>text<i>: string | TemplateResult</i></code> - The error message to display in the dialog.</li>
320
340
  <li><code>responseCallback<i>: function</i></code> - Function called when the dialog is closed.</li>
321
341
  <li><code>options<i>: object</i></code> - Configuration options.</li>
322
342
  </ul>
@@ -332,7 +352,7 @@
332
352
 
333
353
  <h6>Parameters</h6>
334
354
  <ul>
335
- <li><code>text<i>: string</i></code> - The success message to display in the dialog.</li>
355
+ <li><code>text<i>: string | TemplateResult</i></code> - The success message to display in the dialog.</li>
336
356
  <li><code>responseCallback<i>: function</i></code> - Function called when the dialog is closed.</li>
337
357
  <li><code>options<i>: object</i></code> - Configuration options.</li>
338
358
  </ul>
@@ -1,4 +1,4 @@
1
- import ShadowComponent from"./ShadowComponent.js";import{html,css}from"../lit-all.min.js";import{boolExists}from"../utils/propConverters.js";import"./Icon.js";import"./FocusCapture.js";const firstFocusable=e=>e.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])')[0];export default class Dialog extends ShadowComponent{static properties={opened:{type:Boolean,reflect:!0,converter:boolExists},closeBtn:{type:Boolean,reflect:!0,attribute:"close-btn",converter:boolExists},overlayClose:{type:Boolean,reflect:!0,attribute:"overlay-close",converter:boolExists},disableKeyboardClose:{type:Boolean,reflect:!0,attribute:"disable-keyboard-close",converter:boolExists},confirmText:{type:String,reflect:!0,attribute:"confirm-text"},confirmClasses:{type:String,reflect:!0,attribute:"confirm-classes"},cancelText:{type:String,reflect:!0,attribute:"cancel-text"},cancelClasses:{type:String,reflect:!0,attribute:"cancel-classes"}};constructor(){super(),this.opened=!1,this.closeBtn=!0,this.overlayClose=!0,this.disableKeyboardClose=!1,this.confirmText="",this.confirmClasses="success ml",this.cancelText="",this.cancelClasses="",this.confirmAction=()=>{},this.cancelAction=()=>{},this.closeCallback=()=>{},this.previousFocus=null}handleClick=e=>{const{target:t}=e,o=t.id||t.closest("[id]")?.id;"overlay"===o&&this.overlayClose||"close"===o?this.close():"cancel"===o&&(this.cancelAction(e),e.defaultPrevented||this.close())};handleSubmit=e=>{e.preventDefault(),this.confirmAction(e),e.keepDialogOpen||this.close()};handleSlotKeydown=e=>{if("Enter"===e.key&&this.confirmText){const t=e.target;if("INPUT"===t.tagName||"TEXTAREA"===t.tagName){e.preventDefault();const t=this.shadowRoot.querySelector("form");t&&t.requestSubmit()}}};handleKeydown=e=>{this.disableKeyboardClose||27!==e.keyCode||this.close()};connectedCallback(){super.connectedCallback()}disconnectedCallback(){super.disconnectedCallback(),window.removeEventListener("keydown",this.handleKeydown)}updated(e){super.updated(e),e.has("opened")&&this.dispatchEvent(new CustomEvent(this.opened?"opened":"close"))}open(){this.opened=!0,window.addEventListener("keydown",this.handleKeydown),document.body.classList.add("no-scroll");const e=this.updateComplete||this.requestUpdate();e&&e.then?e.then(()=>{const e=this.shadowRoot.querySelector("[autofocus]")||firstFocusable(this.shadowRoot);e&&e.focus()}):setTimeout(()=>{const e=this.shadowRoot.querySelector("[autofocus]")||firstFocusable(this.shadowRoot);e&&e.focus()},0)}close(){this.opened=!1,this.blur(),this.closeCallback(),window.removeEventListener("keydown",this.handleKeydown),document.body.classList.remove("no-scroll")}toggle(){this.opened?this.close():this.open()}focus(){const e=firstFocusable(this.shadowRoot);e&&(this.previousFocus=document.activeElement,e.focus())}blur(){this.previousFocus&&this.previousFocus.focus()}hasTitle(){return!!this.querySelector('[slot="title"]')}static styles=css`
1
+ import ShadowComponent from"./ShadowComponent.js";import{html,css,render}from"../lit-all.min.js";import{boolExists}from"../utils/propConverters.js";import"./Icon.js";import"./FocusCapture.js";const firstFocusable=e=>e.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])')[0];export default class Dialog extends ShadowComponent{static properties={opened:{type:Boolean,reflect:!0,converter:boolExists},closeBtn:{type:Boolean,reflect:!0,attribute:"close-btn",converter:boolExists},overlayClose:{type:Boolean,reflect:!0,attribute:"overlay-close",converter:boolExists},disableKeyboardClose:{type:Boolean,reflect:!0,attribute:"disable-keyboard-close",converter:boolExists},confirmText:{type:String,reflect:!0,attribute:"confirm-text"},confirmClasses:{type:String,reflect:!0,attribute:"confirm-classes"},cancelText:{type:String,reflect:!0,attribute:"cancel-text"},cancelClasses:{type:String,reflect:!0,attribute:"cancel-classes"}};constructor(){super(),this.opened=!1,this.closeBtn=!0,this.overlayClose=!0,this.disableKeyboardClose=!1,this.confirmText="",this.confirmClasses="success ml",this.cancelText="",this.cancelClasses="",this.confirmAction=()=>{},this.cancelAction=()=>{},this.closeCallback=()=>{},this.previousFocus=null}handleClick=e=>{const{target:t}=e,o=t.id||t.closest("[id]")?.id;"overlay"===o&&this.overlayClose||"close"===o?this.close():"cancel"===o&&(this.cancelAction(e),e.defaultPrevented||this.close())};handleSubmit=e=>{e.preventDefault(),this.confirmAction(e),e.keepDialogOpen||this.close()};handleSlotKeydown=e=>{if("Enter"===e.key&&this.confirmText){const t=e.target;if("INPUT"===t.tagName||"TEXTAREA"===t.tagName){e.preventDefault();const t=this.shadowRoot.querySelector("form");t&&t.requestSubmit()}}};handleKeydown=e=>{this.disableKeyboardClose||27!==e.keyCode||this.close()};connectedCallback(){super.connectedCallback()}disconnectedCallback(){super.disconnectedCallback(),window.removeEventListener("keydown",this.handleKeydown)}updated(e){super.updated(e),e.has("opened")&&this.dispatchEvent(new CustomEvent(this.opened?"opened":"close"))}open(){this.opened=!0,window.addEventListener("keydown",this.handleKeydown),document.body.classList.add("no-scroll");const e=this.updateComplete||this.requestUpdate();e&&e.then?e.then(()=>{const e=this.shadowRoot.querySelector("[autofocus]")||firstFocusable(this.shadowRoot);e&&e.focus()}):setTimeout(()=>{const e=this.shadowRoot.querySelector("[autofocus]")||firstFocusable(this.shadowRoot);e&&e.focus()},0)}close(){this.opened=!1,this.blur(),this.closeCallback(),window.removeEventListener("keydown",this.handleKeydown),document.body.classList.remove("no-scroll")}toggle(){this.opened?this.close():this.open()}focus(){const e=firstFocusable(this.shadowRoot);e&&(this.previousFocus=document.activeElement,e.focus())}blur(){this.previousFocus&&this.previousFocus.focus()}hasTitle(){return!!this.querySelector('[slot="title"]')}static styles=css`
2
2
  :host {
3
3
  position: fixed;
4
4
  top: 0;
@@ -118,4 +118,4 @@ import ShadowComponent from"./ShadowComponent.js";import{html,css}from"../lit-al
118
118
  </form>
119
119
  </k-focus-capture>
120
120
  </div>
121
- `}static create(e="",t={}){!1!==t.closeExisting&&document.querySelectorAll("k-dialog").forEach(e=>e.close());const{removeOnClose:o=!0,closeCallback:s=()=>{},title:i="",titleClasses:l="pyh px m0"}=t,a=new Dialog;if(Object.assign(a,{opened:!0,...t,closeCallback:(...e)=>{o&&a.remove(),s(...e)}}),i){const e=document.createElement("h5");e.slot="title",e.className=l,i instanceof HTMLElement?e.appendChild(i):e.innerHTML=i,a.appendChild(e)}if(e instanceof HTMLElement||e instanceof DocumentFragment)a.appendChild(e);else if(e){if(/<[^>]+>/.test(e))a.innerHTML+=e;else{const t=document.createElement("p");t.className="p",t.textContent=e,a.appendChild(t)}}return t.width&&a.style.setProperty("--width",t.width),t.minWidth&&a.style.setProperty("--min_width",t.minWidth),t.maxWidth&&a.style.setProperty("--max_width",t.maxWidth),t.height&&a.style.setProperty("--height",t.height),t.minHeight&&a.style.setProperty("--min_height",t.minHeight),t.maxHeight&&a.style.setProperty("--max_height",t.maxHeight),document.body.appendChild(a),a.open(),a}static confirm(e,t,o={}){return Dialog.create(e,{title:o.title||"Confirm",closeBtn:!1,overlayClose:!1,disableKeyboardClose:!0,confirmText:"Yes",confirmClasses:"success ml",confirmAction:()=>t(!0),cancelText:"No",cancelClasses:"danger",cancelAction:()=>t(!1),...o})}static alert(e,t=()=>{},o={}){return Dialog.create(e,{title:o.title||"Alert",closeCallback:t,cancelText:"Ok",...o})}static error(e,t=()=>{},o={}){return Dialog.create(e,{title:o.title||"Error",titleClasses:"pyh px m0 tc-danger",closeCallback:t,cancelText:"Ok",...o})}static success(e,t=()=>{},o={}){return Dialog.create(e,{title:o.title||"Success",titleClasses:"pyh px m0 tc-success",closeCallback:t,cancelText:"Ok",...o})}}customElements.define("k-dialog",Dialog);
121
+ `}static create(e="",t={}){!1!==t.closeExisting&&document.querySelectorAll("k-dialog").forEach(e=>e.close());const{removeOnClose:o=!0,closeCallback:s=()=>{},title:i="",titleClasses:l="pyh px m0"}=t,n=new Dialog;if(Object.assign(n,{opened:!0,...t,closeCallback:(...e)=>{o&&n.remove(),s(...e)}}),i){const e=document.createElement("h5");e.slot="title",e.className=l,i instanceof HTMLElement?e.appendChild(i):e.innerHTML=i,n.appendChild(e)}if(void 0!==e?._$litType$){const t=document.createElement("div");t.style.display="contents",render(e,t),n.appendChild(t)}else if(e instanceof HTMLElement||e instanceof DocumentFragment)n.appendChild(e);else if(e){if(/<[^>]+>/.test(e))n.innerHTML+=e;else{const t=document.createElement("p");t.className="p",t.textContent=e,n.appendChild(t)}}return t.width&&n.style.setProperty("--width",t.width),t.minWidth&&n.style.setProperty("--min_width",t.minWidth),t.maxWidth&&n.style.setProperty("--max_width",t.maxWidth),t.height&&n.style.setProperty("--height",t.height),t.minHeight&&n.style.setProperty("--min_height",t.minHeight),t.maxHeight&&n.style.setProperty("--max_height",t.maxHeight),document.body.appendChild(n),n.open(),n}static confirm(e,t,o={}){return Dialog.create(e,{title:o.title||"Confirm",closeBtn:!1,overlayClose:!1,disableKeyboardClose:!0,confirmText:"Yes",confirmClasses:"success ml",confirmAction:()=>t(!0),cancelText:"No",cancelClasses:"danger",cancelAction:()=>t(!1),...o})}static alert(e,t=()=>{},o={}){return Dialog.create(e,{title:o.title||"Alert",closeCallback:t,cancelText:"Ok",...o})}static error(e,t=()=>{},o={}){return Dialog.create(e,{title:o.title||"Error",titleClasses:"pyh px m0 tc-danger",closeCallback:t,cancelText:"Ok",...o})}static success(e,t=()=>{},o={}){return Dialog.create(e,{title:o.title||"Success",titleClasses:"pyh px m0 tc-success",closeCallback:t,cancelText:"Ok",...o})}}customElements.define("k-dialog",Dialog);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kempo-ui",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "type": "module",
5
5
  "description": "A Lit based web-component library",
6
6
  "main": "index.js",
@@ -1,5 +1,5 @@
1
1
  import ShadowComponent from './ShadowComponent.js';
2
- import { html, css } from '../lit-all.min.js';
2
+ import { html, css, render } from '../lit-all.min.js';
3
3
  import { boolExists } from '../utils/propConverters.js';
4
4
  import './Icon.js';
5
5
  import './FocusCapture.js';
@@ -330,10 +330,14 @@ export default class Dialog extends ShadowComponent {
330
330
  }
331
331
 
332
332
  // Set content
333
- if(contents instanceof HTMLElement || contents instanceof DocumentFragment) {
333
+ if(contents?._$litType$ !== undefined) {
334
+ const container = document.createElement('div');
335
+ container.style.display = 'contents';
336
+ render(contents, container);
337
+ dialog.appendChild(container);
338
+ } else if(contents instanceof HTMLElement || contents instanceof DocumentFragment) {
334
339
  dialog.appendChild(contents);
335
340
  } else if(contents) {
336
- // Check if content is plain text (no HTML tags)
337
341
  const hasHtmlTags = /<[^>]+>/.test(contents);
338
342
  if(hasHtmlTags) {
339
343
  dialog.innerHTML += contents;
@@ -1,4 +1,5 @@
1
1
  import Dialog from '../../src/components/Dialog.js';
2
+ import { html } from '../../src/lit-all.min.js';
2
3
 
3
4
  const createDialog = async (options = {}) => {
4
5
  const container = document.createElement('div');
@@ -673,5 +674,101 @@ export default {
673
674
 
674
675
  cleanup(container);
675
676
  pass('Default content slot rendered');
677
+ },
678
+
679
+ /*
680
+ Lit TemplateResult Content Tests
681
+ */
682
+ 'Dialog.create should accept Lit TemplateResult as content': async ({pass, fail}) => {
683
+ const dialog = Dialog.create(html`<p class="p">Lit template content</p>`);
684
+ await dialog.updateComplete;
685
+
686
+ const container = dialog.querySelector('div[style="display: contents;"]');
687
+ if(!container){
688
+ cleanupAllDialogs();
689
+ fail('Should render TemplateResult into a display:contents wrapper');
690
+ return;
691
+ }
692
+
693
+ const p = container.querySelector('p');
694
+ if(!p || p.textContent !== 'Lit template content'){
695
+ cleanupAllDialogs();
696
+ fail(`Expected paragraph with "Lit template content", got "${p?.textContent}"`);
697
+ return;
698
+ }
699
+
700
+ cleanupAllDialogs();
701
+ pass('Dialog.create accepts Lit TemplateResult');
702
+ },
703
+
704
+ 'Dialog.confirm should accept Lit TemplateResult as content': async ({pass, fail}) => {
705
+ let response = null;
706
+ const dialog = Dialog.confirm(
707
+ html`<p class="p">Confirm this?</p>`,
708
+ r => { response = r; }
709
+ );
710
+ await dialog.updateComplete;
711
+
712
+ const container = dialog.querySelector('div[style="display: contents;"]');
713
+ if(!container){
714
+ cleanupAllDialogs();
715
+ fail('Should render TemplateResult in confirm dialog');
716
+ return;
717
+ }
718
+
719
+ const p = container.querySelector('p');
720
+ if(!p || p.textContent !== 'Confirm this?'){
721
+ cleanupAllDialogs();
722
+ fail(`Expected paragraph with "Confirm this?", got "${p?.textContent}"`);
723
+ return;
724
+ }
725
+
726
+ cleanupAllDialogs();
727
+ pass('Dialog.confirm accepts Lit TemplateResult');
728
+ },
729
+
730
+ 'Dialog.alert should accept Lit TemplateResult as content': async ({pass, fail}) => {
731
+ const dialog = Dialog.alert(html`<p class="p">Alert content</p>`);
732
+ await dialog.updateComplete;
733
+
734
+ const container = dialog.querySelector('div[style="display: contents;"]');
735
+ if(!container){
736
+ cleanupAllDialogs();
737
+ fail('Should render TemplateResult in alert dialog');
738
+ return;
739
+ }
740
+
741
+ cleanupAllDialogs();
742
+ pass('Dialog.alert accepts Lit TemplateResult');
743
+ },
744
+
745
+ 'Dialog.error should accept Lit TemplateResult as content': async ({pass, fail}) => {
746
+ const dialog = Dialog.error(html`<p class="p">Error content</p>`);
747
+ await dialog.updateComplete;
748
+
749
+ const container = dialog.querySelector('div[style="display: contents;"]');
750
+ if(!container){
751
+ cleanupAllDialogs();
752
+ fail('Should render TemplateResult in error dialog');
753
+ return;
754
+ }
755
+
756
+ cleanupAllDialogs();
757
+ pass('Dialog.error accepts Lit TemplateResult');
758
+ },
759
+
760
+ 'Dialog.success should accept Lit TemplateResult as content': async ({pass, fail}) => {
761
+ const dialog = Dialog.success(html`<p class="p">Success content</p>`);
762
+ await dialog.updateComplete;
763
+
764
+ const container = dialog.querySelector('div[style="display: contents;"]');
765
+ if(!container){
766
+ cleanupAllDialogs();
767
+ fail('Should render TemplateResult in success dialog');
768
+ return;
769
+ }
770
+
771
+ cleanupAllDialogs();
772
+ pass('Dialog.success accepts Lit TemplateResult');
676
773
  }
677
774
  };