@design.estate/dees-catalog 9.5.0 → 9.6.2

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.
Files changed (31) hide show
  1. package/dist_bundle/bundle.js +1319 -1452
  2. package/dist_bundle/bundle.js.map +1 -1
  3. package/dist_ts_web/00_commitinfo_data.js +1 -1
  4. package/dist_ts_web/elements/00group-dataview/dees-table/dees-table.js +5 -4
  5. package/dist_ts_web/elements/00group-input/dees-input-base/dees-input-base.d.ts +1 -8
  6. package/dist_ts_web/elements/00group-input/dees-input-base/dees-input-base.js +7 -2
  7. package/dist_ts_web/elements/00group-layout/dees-stepper/dees-stepper.d.ts +21 -2
  8. package/dist_ts_web/elements/00group-layout/dees-stepper/dees-stepper.demo.d.ts +4 -0
  9. package/dist_ts_web/elements/00group-layout/dees-stepper/dees-stepper.demo.js +218 -193
  10. package/dist_ts_web/elements/00group-layout/dees-stepper/dees-stepper.js +288 -403
  11. package/dist_ts_web/elements/00group-layout/dees-stepper/styles.d.ts +1 -0
  12. package/dist_ts_web/elements/00group-layout/dees-stepper/styles.js +41 -0
  13. package/dist_ts_web/elements/00group-overlay/dees-contextmenu/dees-contextmenu.d.ts +1 -1
  14. package/dist_ts_web/elements/00group-overlay/dees-contextmenu/dees-contextmenu.js +5 -4
  15. package/package.json +2 -2
  16. package/readme.md +52 -3
  17. package/scripts/check-bdtheme-ratchet.cjs +2 -2
  18. package/scripts/check-packed-consumer.mjs +45 -0
  19. package/ts_web/00_commitinfo_data.ts +1 -1
  20. package/ts_web/elements/00group-dataview/dees-table/dees-table.ts +3 -2
  21. package/ts_web/elements/00group-input/dees-input-base/dees-input-base.ts +6 -1
  22. package/ts_web/elements/00group-layout/dees-stepper/dees-stepper.demo.ts +142 -200
  23. package/ts_web/elements/00group-layout/dees-stepper/dees-stepper.ts +216 -400
  24. package/ts_web/elements/00group-layout/dees-stepper/styles.ts +41 -0
  25. package/ts_web/elements/00group-overlay/dees-contextmenu/dees-contextmenu.ts +3 -3
  26. package/readme.hints.md +0 -1233
  27. package/readme.icons.md +0 -1849
  28. package/readme.info.md +0 -80
  29. package/readme.plan.md +0 -671
  30. package/readme.playbook.md +0 -820
  31. package/readme.theme-migration.md +0 -168
@@ -1,212 +1,154 @@
1
- import { html } from '@design.estate/dees-element';
1
+ import { DeesElement, customElement, property, state, html, css, cssManager } from '@design.estate/dees-element';
2
2
  import { DeesStepper, type IStep } from './dees-stepper.js';
3
+ import { themeDefaultStyles } from '../../00theme.js';
4
+ import { demoPage } from '../../../demos/templates.js';
5
+ import '../../00group-form/dees-form/dees-form.js';
6
+ import '../../00group-input/dees-input-text/dees-input-text.js';
7
+ import '../../00group-input/dees-input-multitoggle/dees-input-multitoggle.js';
8
+ import '../../00group-input/dees-input-toggle/dees-input-toggle.js';
3
9
 
4
- const waitForProgressTick = async (timeoutArg: number, signal?: AbortSignal): Promise<boolean> => {
5
- return new Promise((resolve) => {
6
- let completed = false;
10
+ const waitForProgressTick = (duration: number, signal?: AbortSignal): Promise<boolean> => new Promise(resolve => {
11
+ if (signal?.aborted) { resolve(false); return; }
12
+ const abort = () => { clearTimeout(timer); resolve(false); };
13
+ const timer = setTimeout(() => { signal?.removeEventListener('abort', abort); resolve(true); }, duration);
14
+ signal?.addEventListener('abort', abort, { once: true });
15
+ });
7
16
 
8
- const finish = (result: boolean) => {
9
- if (completed) {
10
- return;
11
- }
17
+ const contentStyles = html`<style>
18
+ .setup-summary { margin: 0; display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 12px 24px; font-size: 13px; }
19
+ .setup-summary dt { color: var(--dees-color-text-secondary); }
20
+ .setup-summary dd { margin: 0; text-align: right; overflow-wrap: anywhere; font-weight: 500; }
21
+ .setup-note { color: var(--dees-color-text-secondary); font-size: 12px; line-height: 1.6; margin: 20px 0 0; }
22
+ .setup-success { display: flex; align-items: center; gap: 10px; margin: 0 0 20px; color: var(--dees-color-text-success); }
23
+ </style>`;
12
24
 
13
- completed = true;
14
- if (signal) {
15
- signal.removeEventListener('abort', handleAbort);
16
- }
17
- resolve(result);
18
- };
19
-
20
- const handleAbort = () => {
21
- window.clearTimeout(timeoutId);
22
- finish(false);
23
- };
24
-
25
- const timeoutId = window.setTimeout(() => {
26
- finish(true);
27
- }, timeoutArg);
28
-
29
- if (signal) {
30
- signal.addEventListener('abort', handleAbort, { once: true });
31
- }
32
- });
33
- };
34
-
35
- const createContinueMenuOptions = (labelArg = 'Continue') => [
36
- {
37
- name: labelArg,
38
- action: async (stepper?: DeesStepper) => stepper?.goNext(),
39
- },
40
- ];
41
-
42
- const createDemoSteps = (): IStep[] => [
43
- {
44
- title: 'Account Setup',
45
- content: html`
46
- <dees-form>
47
- <dees-input-text key="email" label="Work Email" required></dees-input-text>
48
- <dees-input-text key="password" label="Create Password" type="password" required></dees-input-text>
49
- </dees-form>
50
- `,
51
- menuOptions: createContinueMenuOptions(),
52
- },
53
- {
54
- title: 'Profile Details',
55
- content: html`
56
- <dees-form>
57
- <dees-input-text key="firstName" label="First Name" required></dees-input-text>
58
- <dees-input-text key="lastName" label="Last Name" required></dees-input-text>
59
- </dees-form>
60
- `,
61
- menuOptions: createContinueMenuOptions(),
62
- },
63
- {
64
- title: 'Contact Information',
65
- content: html`
66
- <dees-form>
67
- <dees-input-phone key="phone" label="Mobile Number" required></dees-input-phone>
68
- <dees-input-text key="company" label="Company"></dees-input-text>
69
- </dees-form>
70
- `,
71
- menuOptions: createContinueMenuOptions(),
72
- },
73
- {
74
- title: 'Provision Workspace',
75
- content: html`
76
- <dees-panel>
77
- <p>
78
- We are creating your starter workspace, applying your onboarding choices,
79
- and preparing a live preview. This step moves forward automatically when
80
- the environment is ready.
81
- </p>
82
- </dees-panel>
83
- `,
84
- progressStep: {
85
- label: 'Workspace setup',
86
- percentage: 8,
87
- indeterminate: true,
88
- statusRows: 4,
89
- statusText: 'Allocating a clean workspace...',
90
- terminalLines: ['Allocating a clean workspace'],
25
+ const createDemoSteps = (failFirst: boolean, finish: (name: string) => void): IStep[] => {
26
+ const draft = { name: '', email: '', purpose: 'Product', updates: true };
27
+ let attempts = 0;
28
+ const summary = () => html`${contentStyles}<dl class="setup-summary">
29
+ <dt>Workspace</dt><dd>${draft.name}</dd><dt>Owner</dt><dd>${draft.email}</dd>
30
+ <dt>Built for</dt><dd>${draft.purpose}</dd><dt>Weekly digest</dt><dd>${draft.updates ? 'On' : 'Off'}</dd>
31
+ </dl>`;
32
+ const collect = (event: CustomEvent<{ data: Partial<typeof draft> }>) => {
33
+ Object.assign(draft, event.detail.data);
34
+ steps[2].content = summary();
35
+ steps[4].content = html`${contentStyles}<p class="setup-success"><dees-icon icon="lucide:CircleCheck" iconSize="20"></dees-icon>Everything is in place.</p>${summary()}`;
36
+ };
37
+ const next = [{ name: 'Continue', action: async (stepper?: DeesStepper) => stepper?.goNext() }];
38
+ const steps: IStep[] = [
39
+ {
40
+ title: 'Create a workspace.',
41
+ description: 'Give your workspace a name and choose who will own it.',
42
+ content: html`<dees-form @formData=${collect}>
43
+ <dees-input-text key="name" label="Workspace name" placeholder="Studio Notes" required></dees-input-text>
44
+ <dees-input-text key="email" label="Work email" placeholder="alex@example.com" type="email" required></dees-input-text>
45
+ </dees-form>`,
46
+ menuOptions: next,
91
47
  },
92
- validationFunc: async (stepper, _htmlElement, signal) => {
93
- const progressFrames = [
94
- { line: 'Allocating a clean workspace', percentage: 8, delay: 500 },
95
- { line: 'Syncing account preferences', percentage: 24, delay: 650 },
96
- { line: 'Installing selected integrations', percentage: 47, delay: 700 },
97
- { line: 'Generating starter project files', percentage: 71, delay: 650 },
98
- { line: 'Booting the live preview environment', percentage: 92, delay: 700 },
99
- ];
100
-
101
- stepper.resetProgressStep();
102
-
103
- for (const [index, progressFrame] of progressFrames.entries()) {
104
- if (signal?.aborted) {
105
- return;
48
+ {
49
+ title: 'Make it yours.',
50
+ description: 'Start with a focus. You can change these choices later.',
51
+ content: html`<dees-form @formData=${collect}>
52
+ <dees-input-multitoggle key="purpose" label="What are you working on?" .options=${['Product', 'Operations', 'Research']}></dees-input-multitoggle>
53
+ <dees-input-toggle key="updates" label="Weekly workspace digest" .value=${true}></dees-input-toggle>
54
+ </dees-form>`,
55
+ menuOptions: next,
56
+ },
57
+ {
58
+ title: 'Ready to create?',
59
+ description: 'Take a moment to check your choices.',
60
+ content: summary(),
61
+ menuOptions: [{ name: 'Create workspace', action: async (stepper) => stepper?.goNext() }],
62
+ },
63
+ {
64
+ title: 'Bringing it together.',
65
+ description: 'Your workspace is taking shape. This usually takes a few seconds.',
66
+ content: html`${contentStyles}<p class="setup-note">You can go back to adjust your choices, or cancel while setup is running.</p>`,
67
+ progressStep: { label: 'Creating workspace', percentage: 0, statusRows: 3 },
68
+ validationFunc: async (stepper, _element, signal) => {
69
+ attempts++;
70
+ const messages = ['Creating your space', 'Applying preferences', 'Preparing starter files', 'Workspace ready'];
71
+ for (const [index, message] of messages.entries()) {
72
+ if (!await waitForProgressTick(650, signal)) return;
73
+ if (failFirst && attempts === 1 && index === 2) throw new Error('Starter files could not be copied. Your choices are saved. Try again.');
74
+ stepper.appendProgressStepLine(message);
75
+ stepper.updateProgressStep({ percentage: (index + 1) * 25, statusText: message, indeterminate: false });
106
76
  }
77
+ await waitForProgressTick(450, signal);
78
+ },
79
+ },
80
+ {
81
+ title: 'Your workspace is ready.',
82
+ description: 'A fresh start, with all the details you chose.',
83
+ allowBack: false,
84
+ content: summary(),
85
+ menuOptions: [{ name: 'Done', action: async stepper => { finish(draft.name); await stepper?.destroy(); } }],
86
+ },
87
+ ];
88
+ return steps;
89
+ };
107
90
 
108
- if (index === 0) {
109
- stepper.updateProgressStep({
110
- percentage: progressFrame.percentage,
111
- indeterminate: true,
112
- statusText: `${progressFrame.line}...`,
113
- terminalLines: [progressFrame.line],
114
- });
115
- } else {
116
- stepper.appendProgressStepLine(progressFrame.line);
117
- stepper.updateProgressStep({
118
- percentage: progressFrame.percentage,
119
- indeterminate: true,
120
- statusText: `${progressFrame.line}...`,
121
- });
122
- }
91
+ @customElement('dees-demo-stepper')
92
+ class DeesDemoStepper extends DeesElement {
93
+ @property() accessor scenario = 'Standard setup';
94
+ @state() private accessor closed = false;
95
+ @state() private accessor result = '';
96
+ private steps = createDemoSteps(false, name => { this.result = `${name} is ready.`; });
97
+ private overlayStepper?: DeesStepper;
123
98
 
124
- const completed = await waitForProgressTick(progressFrame.delay, signal);
125
- if (!completed) {
126
- return;
127
- }
128
- }
99
+ public static styles = [themeDefaultStyles, cssManager.defaultStyles, css`
100
+ :host { display: block; min-width: 0; }
101
+ .toolbar { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-bottom: 20px; }
102
+ .actions { display: flex; gap: 8px; flex-wrap: wrap; }
103
+ .stage { position: relative; height: 540px; border: 1px solid var(--dees-color-border-subtle); border-radius: 18px; background: var(--dees-color-bg-secondary); overflow: hidden; }
104
+ .finished { display: grid; place-content: center; justify-items: center; gap: 16px; height: 100%; padding: 24px; box-sizing: border-box; text-align: center; }
105
+ .finished h2 { margin: 0; font-size: 20px; letter-spacing: -.025em; font-weight: 600; }
106
+ .finished p, .caption { font-size: 12px; line-height: 1.6; color: var(--dees-color-text-secondary); }
107
+ .caption { margin: 16px 0 0; }
108
+ summary.caption { cursor: pointer; font-size: 13px; font-weight: 500; }
109
+ .finished dees-icon { color: var(--dees-color-text-success); }
110
+ @media (max-width: 540px) { .stage { height: 560px; } }
111
+ `];
129
112
 
130
- stepper.appendProgressStepLine('Workspace ready');
131
- stepper.updateProgressStep({
132
- percentage: 100,
133
- indeterminate: false,
134
- statusText: 'Workspace ready.',
135
- });
113
+ private reset() {
114
+ this.result = '';
115
+ this.closed = false;
116
+ this.steps = createDemoSteps(this.scenario === 'Retry example', name => { this.result = `${name} is ready.`; });
117
+ this.requestUpdate();
118
+ }
136
119
 
137
- await waitForProgressTick(350, signal);
138
- },
139
- },
140
- {
141
- title: 'Team Size',
142
- content: html`
143
- <dees-form>
144
- <dees-input-dropdown
145
- key="teamSize"
146
- label="How big is your team?"
147
- .options=${[
148
- { label: '1-5', value: '1-5' },
149
- { label: '6-20', value: '6-20' },
150
- { label: '21-50', value: '21-50' },
151
- { label: '51+', value: '51+' },
152
- ]}
153
- required
154
- ></dees-input-dropdown>
155
- </dees-form>
156
- `,
157
- menuOptions: createContinueMenuOptions(),
158
- },
159
- {
160
- title: 'Goals',
161
- content: html`
162
- <dees-form>
163
- <dees-input-multitoggle
164
- key="goal"
165
- label="Main objective"
166
- .options=${[
167
- { label: 'Onboarding', key: 'onboarding' },
168
- { label: 'Analytics', key: 'analytics' },
169
- { label: 'Automation', key: 'automation' },
170
- ]}
171
- ></dees-input-multitoggle>
172
- </dees-form>
173
- `,
174
- menuOptions: createContinueMenuOptions(),
175
- },
176
- {
177
- title: 'Review & Launch',
178
- content: html`
179
- <dees-panel>
180
- <p>
181
- Your workspace is ready. Review the collected details and launch when
182
- you are ready to start.
183
- </p>
184
- </dees-panel>
185
- `,
186
- menuOptions: [
187
- {
188
- name: 'Launch',
189
- action: async (stepper?: DeesStepper) => {
190
- if (stepper?.overlay) {
191
- await stepper.destroy();
192
- }
193
- },
194
- },
195
- ],
196
- },
197
- ];
120
+ private async openOverlay(cancelable = true) {
121
+ if (this.overlayStepper?.isConnected) return;
122
+ this.overlayStepper = await DeesStepper.createAndShow({
123
+ cancelable,
124
+ steps: createDemoSteps(this.scenario === 'Retry example', name => { this.result = `${name} is ready.`; }),
125
+ });
126
+ }
198
127
 
199
- export const stepperDemo = () => html`
200
- <div style="position: absolute; inset: 0;">
201
- <div
202
- style="position: absolute; top: 16px; left: 50%; transform: translateX(-50%); z-index: 10;"
203
- >
204
- <dees-button
205
- @click=${async () => {
206
- await DeesStepper.createAndShow({ steps: createDemoSteps() });
207
- }}
208
- >Open stepper as overlay</dees-button>
128
+ public render() {
129
+ return html`<div class="toolbar">
130
+ <dees-input-multitoggle size="sm" label="Demo scenario" labelPosition="none"
131
+ .options=${['Standard setup', 'Retry example']} .selectedOption=${this.scenario}
132
+ @change=${(event: CustomEvent<{ value: string }>) => { this.scenario = event.detail.value; this.reset(); }}></dees-input-multitoggle>
133
+ <div class="actions"><dees-button type="secondary" text="Open overlay" @clicked=${() => this.openOverlay()}></dees-button>
134
+ <dees-button type="ghost" text="Reset" @clicked=${this.reset}></dees-button></div>
209
135
  </div>
210
- <dees-stepper .steps=${createDemoSteps()}></dees-stepper>
211
- </div>
212
- `;
136
+ <div class="stage">${this.closed ? html`<div class="finished">
137
+ <dees-icon icon=${this.result ? 'lucide:CircleCheck' : 'lucide:Layers'} iconSize="32"></dees-icon>
138
+ <h2>${this.result || 'Setup cancelled.'}</h2><p>This example uses local sample data.</p>
139
+ <dees-button type="secondary" text="Start again" @clicked=${this.reset}></dees-button>
140
+ </div>` : html`<dees-stepper .steps=${this.steps} @stepper-close=${() => { this.closed = true; }}></dees-stepper>`}</div>
141
+ <p class="caption">${this.scenario === 'Retry example' ? 'The first setup attempt pauses with an error. Try again to continue with your saved choices.' : 'Move forward, go back, and review your choices. Changes stay in this demo.'}</p>
142
+ <details><summary class="caption">Completion required</summary>
143
+ <p class="caption">For a flow that must finish, such as a required update, cancellation can be disabled.</p>
144
+ <dees-button type="secondary" text="Open required setup" @clicked=${() => this.openOverlay(false)}></dees-button>
145
+ </details>`;
146
+ }
147
+
148
+ public async disconnectedCallback() {
149
+ if (this.overlayStepper?.isConnected) await this.overlayStepper.destroy();
150
+ await super.disconnectedCallback();
151
+ }
152
+ }
153
+
154
+ export const stepperDemo = () => demoPage('Stepper', 'A clear path from the first detail to the finished result.', html`<dees-demo-stepper></dees-demo-stepper>`);