@design.estate/dees-catalog 3.71.0 → 3.72.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.
- package/dist_bundle/bundle.js +189 -31
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/elements/00group-layout/dees-stepper/dees-stepper.d.ts +37 -0
- package/dist_ts_web/elements/00group-layout/dees-stepper/dees-stepper.js +120 -24
- package/dist_ts_web/elements/00group-layout/dees-tile/dees-tile.js +13 -3
- package/dist_ts_web/elements/00group-overlay/dees-modal/dees-modal.demo.js +76 -1
- package/dist_ts_web/elements/00group-overlay/dees-modal/dees-modal.js +1 -8
- package/dist_watch/bundle.js +187 -29
- package/dist_watch/bundle.js.map +3 -3
- package/package.json +1 -1
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/elements/00group-layout/dees-stepper/dees-stepper.ts +114 -23
- package/ts_web/elements/00group-layout/dees-tile/dees-tile.ts +12 -2
- package/ts_web/elements/00group-overlay/dees-modal/dees-modal.demo.ts +75 -0
- package/ts_web/elements/00group-overlay/dees-modal/dees-modal.ts +0 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@design.estate/dees-catalog",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.72.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A comprehensive library that provides dynamic web components for building sophisticated and modern web applications using JavaScript and TypeScript.",
|
|
6
6
|
"main": "dist_ts_web/index.js",
|
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@design.estate/dees-catalog',
|
|
6
|
-
version: '3.
|
|
6
|
+
version: '3.72.0',
|
|
7
7
|
description: 'A comprehensive library that provides dynamic web components for building sophisticated and modern web applications using JavaScript and TypeScript.'
|
|
8
8
|
}
|
|
@@ -18,6 +18,7 @@ import { themeDefaultStyles } from '../../00theme.js';
|
|
|
18
18
|
import { cssGeistFontFamily } from '../../00fonts.js';
|
|
19
19
|
import { zIndexRegistry } from '../../00zindex.js';
|
|
20
20
|
import { DeesWindowLayer } from '../../00group-overlay/dees-windowlayer/dees-windowlayer.js';
|
|
21
|
+
import { DeesModal } from '../../00group-overlay/dees-modal/dees-modal.js';
|
|
21
22
|
import type { DeesForm } from '../../00group-form/dees-form/dees-form.js';
|
|
22
23
|
import '../dees-tile/dees-tile.js';
|
|
23
24
|
|
|
@@ -45,15 +46,16 @@ export class DeesStepper extends DeesElement {
|
|
|
45
46
|
|
|
46
47
|
public static async createAndShow(optionsArg: {
|
|
47
48
|
steps: IStep[];
|
|
49
|
+
cancelable?: boolean;
|
|
48
50
|
}): Promise<DeesStepper> {
|
|
49
51
|
const body = document.body;
|
|
50
52
|
const stepper = new DeesStepper();
|
|
51
53
|
stepper.steps = optionsArg.steps;
|
|
52
54
|
stepper.overlay = true;
|
|
55
|
+
if (optionsArg.cancelable !== undefined) {
|
|
56
|
+
stepper.cancelable = optionsArg.cancelable;
|
|
57
|
+
}
|
|
53
58
|
stepper.windowLayer = await DeesWindowLayer.createAndShow({ blur: true });
|
|
54
|
-
stepper.windowLayer.addEventListener('click', async () => {
|
|
55
|
-
await stepper.destroy();
|
|
56
|
-
});
|
|
57
59
|
body.append(stepper.windowLayer);
|
|
58
60
|
body.append(stepper);
|
|
59
61
|
|
|
@@ -81,6 +83,18 @@ export class DeesStepper extends DeesElement {
|
|
|
81
83
|
})
|
|
82
84
|
accessor overlay: boolean = false;
|
|
83
85
|
|
|
86
|
+
/**
|
|
87
|
+
* When true (default), the stepper renders a Cancel button in every step's
|
|
88
|
+
* footer, and clicking the backdrop (overlay mode) triggers the same cancel
|
|
89
|
+
* confirmation flow. Set to false for forced flows where the user must
|
|
90
|
+
* complete the stepper — no Cancel button, no backdrop dismissal.
|
|
91
|
+
*/
|
|
92
|
+
@property({
|
|
93
|
+
type: Boolean,
|
|
94
|
+
reflect: true,
|
|
95
|
+
})
|
|
96
|
+
accessor cancelable: boolean = true;
|
|
97
|
+
|
|
84
98
|
@property({ type: Number, attribute: false })
|
|
85
99
|
accessor stepperZIndex: number = 1000;
|
|
86
100
|
|
|
@@ -280,15 +294,17 @@ export class DeesStepper extends DeesElement {
|
|
|
280
294
|
transition: all 0.15s ease;
|
|
281
295
|
background: transparent;
|
|
282
296
|
border: none;
|
|
283
|
-
border-left: 1px solid var(--dees-color-border-subtle);
|
|
284
297
|
color: var(--dees-color-text-muted);
|
|
285
298
|
white-space: nowrap;
|
|
286
299
|
display: flex;
|
|
287
300
|
align-items: center;
|
|
288
301
|
}
|
|
289
302
|
|
|
290
|
-
|
|
291
|
-
|
|
303
|
+
/* Border-left separator on every button EXCEPT the first one.
|
|
304
|
+
Uses general sibling so the stepHint (if rendered on the left) does
|
|
305
|
+
not shift which button counts as "first" and create a phantom border. */
|
|
306
|
+
.bottomButtons .bottomButton ~ .bottomButton {
|
|
307
|
+
border-left: 1px solid var(--dees-color-border-subtle);
|
|
292
308
|
}
|
|
293
309
|
|
|
294
310
|
.bottomButtons .bottomButton:hover {
|
|
@@ -347,6 +363,7 @@ export class DeesStepper extends DeesElement {
|
|
|
347
363
|
<div
|
|
348
364
|
class="stepperContainer ${this.overlay ? 'overlay' : ''}"
|
|
349
365
|
style=${this.overlay ? `z-index: ${this.stepperZIndex};` : ''}
|
|
366
|
+
@click=${this.handleOutsideClick}
|
|
350
367
|
>
|
|
351
368
|
${this.steps.map((stepArg, stepIndex) => {
|
|
352
369
|
const isSelected = stepArg === this.selectedStep;
|
|
@@ -370,23 +387,27 @@ export class DeesStepper extends DeesElement {
|
|
|
370
387
|
<div class="title">${stepArg.title}</div>
|
|
371
388
|
<div class="content">${stepArg.content}</div>
|
|
372
389
|
</div>
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
+
<div slot="footer" class="bottomButtons">
|
|
391
|
+
${isSelected && this.activeForm !== null && !this.activeFormValid
|
|
392
|
+
? html`<div class="stepHint">Complete form to continue</div>`
|
|
393
|
+
: ''}
|
|
394
|
+
${this.cancelable
|
|
395
|
+
? html`<div
|
|
396
|
+
class="bottomButton"
|
|
397
|
+
@click=${() => this.handleCancelRequest()}
|
|
398
|
+
>Cancel</div>`
|
|
399
|
+
: ''}
|
|
400
|
+
${stepArg.menuOptions?.map((actionArg, actionIndex) => {
|
|
401
|
+
const isPrimary = actionIndex === stepArg.menuOptions!.length - 1;
|
|
402
|
+
const isDisabled = isPrimary && this.activeForm !== null && !this.activeFormValid;
|
|
403
|
+
return html`
|
|
404
|
+
<div
|
|
405
|
+
class="bottomButton ${isPrimary ? 'primary' : ''} ${isDisabled ? 'disabled' : ''}"
|
|
406
|
+
@click=${() => this.handleMenuOptionClick(actionArg, isPrimary)}
|
|
407
|
+
>${actionArg.name}</div>
|
|
408
|
+
`;
|
|
409
|
+
}) ?? ''}
|
|
410
|
+
</div>
|
|
390
411
|
</dees-tile>`;
|
|
391
412
|
})}
|
|
392
413
|
</div>
|
|
@@ -556,6 +577,76 @@ export class DeesStepper extends DeesElement {
|
|
|
556
577
|
await optionArg.action(this);
|
|
557
578
|
}
|
|
558
579
|
|
|
580
|
+
/**
|
|
581
|
+
* Currently-open confirmation modal (if any). Prevents double-stacking when
|
|
582
|
+
* the user clicks the backdrop or the Cancel button while a confirm modal
|
|
583
|
+
* is already visible. The reference may become stale (point to a destroyed
|
|
584
|
+
* modal) if the user dismisses the confirm modal by clicking its own
|
|
585
|
+
* backdrop — so handleCancelRequest() uses isConnected to detect that.
|
|
586
|
+
*/
|
|
587
|
+
private cancelConfirmModal?: DeesModal;
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* Click handler on .stepperContainer. Mirrors dees-modal.handleOutsideClick:
|
|
591
|
+
* when the user clicks the empty backdrop area (target === stepperContainer,
|
|
592
|
+
* not any descendant tile), trigger the cancel confirmation flow. Clicks
|
|
593
|
+
* that originate inside a step tile have a different event.target and are
|
|
594
|
+
* ignored here.
|
|
595
|
+
*/
|
|
596
|
+
private handleOutsideClick(eventArg: MouseEvent) {
|
|
597
|
+
if (!this.overlay) return;
|
|
598
|
+
if (!this.cancelable) return;
|
|
599
|
+
eventArg.stopPropagation();
|
|
600
|
+
const stepperContainer = this.shadowRoot!.querySelector('.stepperContainer');
|
|
601
|
+
if (eventArg.target === stepperContainer) {
|
|
602
|
+
this.handleCancelRequest();
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
/**
|
|
607
|
+
* Shown by both the backdrop click and the Cancel button in the footer.
|
|
608
|
+
* Presents a dees-modal asking the user to confirm cancellation. If they
|
|
609
|
+
* confirm, the stepper and window layer are destroyed; otherwise the
|
|
610
|
+
* confirm modal is dismissed and the stepper stays open.
|
|
611
|
+
*
|
|
612
|
+
* The isConnected check on the cached reference handles the case where the
|
|
613
|
+
* user dismissed the previous confirm modal by clicking ITS OWN backdrop —
|
|
614
|
+
* dees-modal.handleOutsideClick calls destroy() directly, bypassing our
|
|
615
|
+
* action callbacks, so our cached reference would be stale without this
|
|
616
|
+
* fallback check.
|
|
617
|
+
*/
|
|
618
|
+
public async handleCancelRequest() {
|
|
619
|
+
if (!this.cancelable) return;
|
|
620
|
+
if (this.cancelConfirmModal && this.cancelConfirmModal.isConnected) return;
|
|
621
|
+
this.cancelConfirmModal = undefined;
|
|
622
|
+
this.cancelConfirmModal = await DeesModal.createAndShow({
|
|
623
|
+
heading: 'Cancel setup?',
|
|
624
|
+
width: 'small',
|
|
625
|
+
content: html`
|
|
626
|
+
<p style="margin: 0;">
|
|
627
|
+
Are you sure you want to cancel? Any progress on the current step will be lost.
|
|
628
|
+
</p>
|
|
629
|
+
`,
|
|
630
|
+
menuOptions: [
|
|
631
|
+
{
|
|
632
|
+
name: 'Continue setup',
|
|
633
|
+
action: async (modal) => {
|
|
634
|
+
this.cancelConfirmModal = undefined;
|
|
635
|
+
await modal!.destroy();
|
|
636
|
+
},
|
|
637
|
+
},
|
|
638
|
+
{
|
|
639
|
+
name: 'Yes, cancel',
|
|
640
|
+
action: async (modal) => {
|
|
641
|
+
this.cancelConfirmModal = undefined;
|
|
642
|
+
await modal!.destroy();
|
|
643
|
+
await this.destroy();
|
|
644
|
+
},
|
|
645
|
+
},
|
|
646
|
+
],
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
|
|
559
650
|
public async destroy() {
|
|
560
651
|
const domtools = await this.domtoolsPromise;
|
|
561
652
|
const container = this.shadowRoot!.querySelector('.stepperContainer');
|
|
@@ -87,14 +87,24 @@ export class DeesTile extends DeesElement {
|
|
|
87
87
|
color: var(--dees-color-text-secondary);
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
/* --- Content: the rounded inset ---
|
|
90
|
+
/* --- Content: the rounded inset ---
|
|
91
|
+
Uses overflow-y: auto so that when a consumer (e.g. dees-modal) caps
|
|
92
|
+
the tile with max-height, long content scrolls inside the tile
|
|
93
|
+
instead of being clipped. For consumers without max-height
|
|
94
|
+
(e.g. dees-stepper), the tile grows with content and the scroll
|
|
95
|
+
never activates. Horizontal overflow stays clipped to preserve the
|
|
96
|
+
rounded corners. */
|
|
91
97
|
.tile-content {
|
|
92
98
|
flex: 1;
|
|
93
99
|
position: relative;
|
|
94
100
|
border-radius: 8px;
|
|
95
101
|
border-top: 1px solid var(--dees-color-border-subtle);
|
|
96
102
|
border-bottom: 1px solid var(--dees-color-border-subtle);
|
|
97
|
-
overflow: hidden;
|
|
103
|
+
overflow-x: hidden;
|
|
104
|
+
overflow-y: auto;
|
|
105
|
+
overscroll-behavior: contain;
|
|
106
|
+
scrollbar-width: thin;
|
|
107
|
+
scrollbar-color: var(--dees-color-scrollbar-thumb) transparent;
|
|
98
108
|
}
|
|
99
109
|
|
|
100
110
|
.tile-content.no-footer {
|
|
@@ -352,5 +352,80 @@ export const demoFunc = () => html`
|
|
|
352
352
|
});
|
|
353
353
|
}}>Test Responsive</dees-button>
|
|
354
354
|
</div>
|
|
355
|
+
|
|
356
|
+
<div class="demo-section">
|
|
357
|
+
<h3>Scrollable Content</h3>
|
|
358
|
+
<p>When content exceeds the modal's max-height (<code>calc(100vh - 80px)</code>), the tile caps at that height and the content area scrolls inside. The heading and bottom buttons stay pinned.</p>
|
|
359
|
+
<div class="button-grid">
|
|
360
|
+
<dees-button @click=${() => {
|
|
361
|
+
DeesModal.createAndShow({
|
|
362
|
+
heading: 'Long Article',
|
|
363
|
+
width: 'medium',
|
|
364
|
+
content: html`
|
|
365
|
+
<h4 style="margin-top: 0;">Lorem ipsum dolor sit amet</h4>
|
|
366
|
+
${Array.from({ length: 40 }, (_, i) => html`
|
|
367
|
+
<p>
|
|
368
|
+
<strong>§ ${i + 1}.</strong>
|
|
369
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
|
|
370
|
+
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
|
|
371
|
+
enim ad minim veniam, quis nostrud exercitation ullamco laboris
|
|
372
|
+
nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
|
|
373
|
+
in reprehenderit in voluptate velit esse cillum dolore eu fugiat
|
|
374
|
+
nulla pariatur. Excepteur sint occaecat cupidatat non proident,
|
|
375
|
+
sunt in culpa qui officia deserunt mollit anim id est laborum.
|
|
376
|
+
</p>
|
|
377
|
+
`)}
|
|
378
|
+
`,
|
|
379
|
+
menuOptions: [{
|
|
380
|
+
name: 'Cancel',
|
|
381
|
+
action: async (modal) => modal!.destroy()
|
|
382
|
+
}, {
|
|
383
|
+
name: 'Accept',
|
|
384
|
+
action: async (modal) => modal!.destroy()
|
|
385
|
+
}],
|
|
386
|
+
});
|
|
387
|
+
}}>Long Article</dees-button>
|
|
388
|
+
|
|
389
|
+
<dees-button @click=${() => {
|
|
390
|
+
DeesModal.createAndShow({
|
|
391
|
+
heading: 'Long List',
|
|
392
|
+
width: 'small',
|
|
393
|
+
content: html`
|
|
394
|
+
<p>Selected items:</p>
|
|
395
|
+
<ul style="padding-left: 20px; margin: 0;">
|
|
396
|
+
${Array.from({ length: 80 }, (_, i) => html`
|
|
397
|
+
<li style="padding: 4px 0;">Item ${i + 1} — option label</li>
|
|
398
|
+
`)}
|
|
399
|
+
</ul>
|
|
400
|
+
`,
|
|
401
|
+
menuOptions: [{
|
|
402
|
+
name: 'Done',
|
|
403
|
+
action: async (modal) => modal!.destroy()
|
|
404
|
+
}],
|
|
405
|
+
});
|
|
406
|
+
}}>Long List</dees-button>
|
|
407
|
+
|
|
408
|
+
<dees-button @click=${() => {
|
|
409
|
+
DeesModal.createAndShow({
|
|
410
|
+
heading: 'Tall Form',
|
|
411
|
+
width: 'medium',
|
|
412
|
+
content: html`
|
|
413
|
+
<dees-form>
|
|
414
|
+
${Array.from({ length: 25 }, (_, i) => html`
|
|
415
|
+
<dees-input-text .label=${`Field ${i + 1}`}></dees-input-text>
|
|
416
|
+
`)}
|
|
417
|
+
</dees-form>
|
|
418
|
+
`,
|
|
419
|
+
menuOptions: [{
|
|
420
|
+
name: 'Cancel',
|
|
421
|
+
action: async (modal) => modal!.destroy()
|
|
422
|
+
}, {
|
|
423
|
+
name: 'Submit',
|
|
424
|
+
action: async (modal) => modal!.destroy()
|
|
425
|
+
}],
|
|
426
|
+
});
|
|
427
|
+
}}>Tall Form</dees-button>
|
|
428
|
+
</div>
|
|
429
|
+
</div>
|
|
355
430
|
</div>
|
|
356
431
|
`
|
|
@@ -271,13 +271,6 @@ export class DeesModal extends DeesElement {
|
|
|
271
271
|
font-size: 14px;
|
|
272
272
|
}
|
|
273
273
|
|
|
274
|
-
.content {
|
|
275
|
-
overflow-y: auto;
|
|
276
|
-
overflow-x: hidden;
|
|
277
|
-
overscroll-behavior: contain;
|
|
278
|
-
scrollbar-width: thin;
|
|
279
|
-
scrollbar-color: var(--dees-color-scrollbar-thumb) transparent;
|
|
280
|
-
}
|
|
281
274
|
.bottomButtons {
|
|
282
275
|
display: flex;
|
|
283
276
|
flex-direction: row;
|