feat(dees-stepper): Revamp dees-stepper: modern styling, new steps and improved navigation/validation
This commit is contained in:
		
							
								
								
									
										10
									
								
								changelog.md
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								changelog.md
									
									
									
									
									
								
							| @@ -1,5 +1,15 @@ | ||||
| # Changelog | ||||
|  | ||||
| ## 2025-09-18 - 1.12.0 - feat(dees-stepper) | ||||
| Revamp dees-stepper: modern styling, new steps and improved navigation/validation | ||||
|  | ||||
| - Visual refresh for dees-stepper: updated card shapes, shadows, refined borders and stronger selected-state visuals for a modern shadcn-inspired look | ||||
| - Improved transitions and animations (transform, box-shadow, filter) for smoother step selection and show/hide behavior | ||||
| - Expanded default/demo steps: replaced small sample with a richer multi-step flow (Account Setup, Profile Details, Contact Information, Team Size, Goals, Brand Preferences, Integrations, Review & Launch) | ||||
| - Enhanced step interactions: safer goNext/goBack handling with boundary checks and reset of validation flags to avoid stale validation state | ||||
| - Better toolbar/controls placement for stepper demo (spacing, counters, accessible back control) and improved keyboard/UX affordances | ||||
| - Minor documentation and meta updates: readme.plan.md extended with dees-stepper plan items and added .claude/settings.local.json | ||||
|  | ||||
| ## 2025-09-18 - 1.11.8 - fix(ci) | ||||
| Add local tool permissions config to allow running pnpm scripts and enable mcp__zen__chat | ||||
|  | ||||
|   | ||||
							
								
								
									
										
											BIN
										
									
								
								readme.plan.md
									
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								readme.plan.md
									
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							| @@ -3,6 +3,6 @@ | ||||
|  */ | ||||
| export const commitinfo = { | ||||
|   name: '@design.estate/dees-catalog', | ||||
|   version: '1.11.8', | ||||
|   version: '1.12.0', | ||||
|   description: 'A comprehensive library that provides dynamic web components for building sophisticated and modern web applications using JavaScript and TypeScript.' | ||||
| } | ||||
|   | ||||
| @@ -36,30 +36,130 @@ export class DeesStepper extends DeesElement { | ||||
|       <dees-stepper | ||||
|         .steps=${[ | ||||
|           { | ||||
|             title: 'Whats your name?', | ||||
|             title: 'Account Setup', | ||||
|             content: html` | ||||
|               <dees-form> | ||||
|                 <dees-input-text | ||||
|                   key="email" | ||||
|                   label="Your Email" | ||||
|                   value="hello@something.com" | ||||
|                   disabled | ||||
|                 ></dees-input-text> | ||||
|                 <dees-input-text key="firstName" required label="Vorname"></dees-input-text> | ||||
|                 <dees-input-text key="lastName" required label="Nachname"></dees-input-text> | ||||
|                 <dees-form-submit>Next</dees-form-submit> | ||||
|                 <dees-input-text key="email" label="Work Email" required></dees-input-text> | ||||
|                 <dees-input-text key="password" label="Create Password" type="password" required></dees-input-text> | ||||
|                 <dees-form-submit>Continue</dees-form-submit> | ||||
|               </dees-form> | ||||
|             `, | ||||
|             validationFunc: async (stepperArg, elementArg) => { | ||||
|               const deesForm = elementArg.querySelector('dees-form'); | ||||
|               deesForm.addEventListener('formData', (eventArg) => { | ||||
|                 stepperArg.goNext(); | ||||
|               }); | ||||
|               deesForm.addEventListener('formData', () => stepperArg.goNext(), { once: true }); | ||||
|             }, | ||||
|           }, | ||||
|           { | ||||
|             title: 'Whats your mobile number?', | ||||
|             content: html``, | ||||
|             title: 'Profile Details', | ||||
|             content: html` | ||||
|               <dees-form> | ||||
|                 <dees-input-text key="firstName" label="First Name" required></dees-input-text> | ||||
|                 <dees-input-text key="lastName" label="Last Name" required></dees-input-text> | ||||
|                 <dees-form-submit>Continue</dees-form-submit> | ||||
|               </dees-form> | ||||
|             `, | ||||
|             validationFunc: async (stepperArg, elementArg) => { | ||||
|               const deesForm = elementArg.querySelector('dees-form'); | ||||
|               deesForm.addEventListener('formData', () => stepperArg.goNext(), { once: true }); | ||||
|             }, | ||||
|           }, | ||||
|           { | ||||
|             title: 'Contact Information', | ||||
|             content: html` | ||||
|               <dees-form> | ||||
|                 <dees-input-phone key="phone" label="Mobile Number" required></dees-input-phone> | ||||
|                 <dees-input-text key="company" label="Company"></dees-input-text> | ||||
|                 <dees-form-submit>Continue</dees-form-submit> | ||||
|               </dees-form> | ||||
|             `, | ||||
|             validationFunc: async (stepperArg, elementArg) => { | ||||
|               const deesForm = elementArg.querySelector('dees-form'); | ||||
|               deesForm.addEventListener('formData', () => stepperArg.goNext(), { once: true }); | ||||
|             }, | ||||
|           }, | ||||
|           { | ||||
|             title: 'Team Size', | ||||
|             content: html` | ||||
|               <dees-form> | ||||
|                 <dees-input-dropdown | ||||
|                   key="teamSize" | ||||
|                   label="How big is your team?" | ||||
|                   .options=${[ | ||||
|                     { label: '1-5', value: '1-5' }, | ||||
|                     { label: '6-20', value: '6-20' }, | ||||
|                     { label: '21-50', value: '21-50' }, | ||||
|                     { label: '51+', value: '51+' }, | ||||
|                   ]} | ||||
|                   required | ||||
|                 ></dees-input-dropdown> | ||||
|                 <dees-form-submit>Continue</dees-form-submit> | ||||
|               </dees-form> | ||||
|             `, | ||||
|             validationFunc: async (stepperArg, elementArg) => { | ||||
|               const deesForm = elementArg.querySelector('dees-form'); | ||||
|               deesForm.addEventListener('formData', () => stepperArg.goNext(), { once: true }); | ||||
|             }, | ||||
|           }, | ||||
|           { | ||||
|             title: 'Goals', | ||||
|             content: html` | ||||
|               <dees-form> | ||||
|                 <dees-input-multitoggle | ||||
|                   key="goal" | ||||
|                   label="Main objective" | ||||
|                   .options=${[ | ||||
|                     { label: 'Onboarding', value: 'onboarding' }, | ||||
|                     { label: 'Analytics', value: 'analytics' }, | ||||
|                     { label: 'Automation', value: 'automation' }, | ||||
|                   ]} | ||||
|                   required | ||||
|                 ></dees-input-multitoggle> | ||||
|                 <dees-form-submit>Continue</dees-form-submit> | ||||
|               </dees-form> | ||||
|             `, | ||||
|             validationFunc: async (stepperArg, elementArg) => { | ||||
|               const deesForm = elementArg.querySelector('dees-form'); | ||||
|               deesForm.addEventListener('formData', () => stepperArg.goNext(), { once: true }); | ||||
|             }, | ||||
|           }, | ||||
|           { | ||||
|             title: 'Brand Preferences', | ||||
|             content: html` | ||||
|               <dees-form> | ||||
|                 <dees-input-text key="brandColor" label="Primary brand color"></dees-input-text> | ||||
|                 <dees-input-text key="tone" label="Preferred tone (e.g. friendly, formal)"></dees-input-text> | ||||
|                 <dees-form-submit>Continue</dees-form-submit> | ||||
|               </dees-form> | ||||
|             `, | ||||
|             validationFunc: async (stepperArg, elementArg) => { | ||||
|               const deesForm = elementArg.querySelector('dees-form'); | ||||
|               deesForm.addEventListener('formData', () => stepperArg.goNext(), { once: true }); | ||||
|             }, | ||||
|           }, | ||||
|           { | ||||
|             title: 'Integrations', | ||||
|             content: html` | ||||
|               <dees-form> | ||||
|                 <dees-input-list | ||||
|                   key="integrations" | ||||
|                   label="Integrations in use" | ||||
|                   placeholder="Add integration" | ||||
|                 ></dees-input-list> | ||||
|                 <dees-form-submit>Continue</dees-form-submit> | ||||
|               </dees-form> | ||||
|             `, | ||||
|             validationFunc: async (stepperArg, elementArg) => { | ||||
|               const deesForm = elementArg.querySelector('dees-form'); | ||||
|               deesForm.addEventListener('formData', () => stepperArg.goNext(), { once: true }); | ||||
|             }, | ||||
|           }, | ||||
|           { | ||||
|             title: 'Review & Launch', | ||||
|             content: html` | ||||
|               <dees-panel> | ||||
|                 <p>Almost there! Review your selections and launch whenever you're ready.</p> | ||||
|               </dees-panel> | ||||
|             `, | ||||
|           }, | ||||
|         ] as IStep[]} | ||||
|       ></dees-stepper> | ||||
| @@ -99,30 +199,33 @@ export class DeesStepper extends DeesElement { | ||||
|         position: relative; | ||||
|         pointer-events: none; | ||||
|         overflow: hidden; | ||||
|         transition: all 0.7s ease-in-out; | ||||
|         transition: transform 0.35s ease, box-shadow 0.35s ease, filter 0.35s ease, border 0.35s ease; | ||||
|         max-width: 500px; | ||||
|         min-height: 300px; | ||||
|         border-radius: 16px; | ||||
|         background: ${cssManager.bdTheme('#ffffff', '#181818')}; | ||||
|         border-top: 1px solid ${cssManager.bdTheme('#ffffff', '#181818')}; | ||||
|         color: ${cssManager.bdTheme('#333', '#fff')}; | ||||
|         border-radius: 18px; | ||||
|         background: ${cssManager.bdTheme('#ffffff', '#18181b')}; | ||||
|         border: 1px solid ${cssManager.bdTheme('rgba(226, 232, 240, 0.9)', 'rgba(63, 63, 70, 0.85)')}; | ||||
|         color: ${cssManager.bdTheme('#0f172a', '#f5f5f5')}; | ||||
|         margin: auto; | ||||
|         margin-bottom: 20px; | ||||
|         filter: opacity(0.5) grayscale(1); | ||||
|         box-shadow: 0px 0px 3px #00000010; | ||||
|         filter: opacity(0.55) saturate(0.85); | ||||
|         box-shadow: ${cssManager.bdTheme('0 20px 40px -25px rgba(15, 23, 42, 0.45)', '0 20px 36px -22px rgba(15, 23, 42, 0.65)')}; | ||||
|         user-select: none; | ||||
|         background-clip: padding-box; | ||||
|       } | ||||
|  | ||||
|       .step.selected { | ||||
|         border-top: 1px solid #e4002b; | ||||
|         pointer-events: all; | ||||
|         filter: opacity(1) grayscale(0); | ||||
|         box-shadow: 0px 0px 5px #00000010; | ||||
|         filter: opacity(1) saturate(1); | ||||
|         transform: translateY(-6px); | ||||
|         border: 1px solid ${cssManager.bdTheme(colors.dark.blue, colors.dark.blue)}; | ||||
|         box-shadow: ${cssManager.bdTheme('0 28px 60px -30px rgba(15, 23, 42, 0.42)', '0 26px 55px -28px rgba(37, 99, 235, 0.6)')}; | ||||
|         user-select: auto; | ||||
|       } | ||||
|  | ||||
|       .step.hiddenStep { | ||||
|         filter: opacity(0); | ||||
|         transform: translateY(16px); | ||||
|       } | ||||
|  | ||||
|       .step:last-child { | ||||
| @@ -130,40 +233,50 @@ export class DeesStepper extends DeesElement { | ||||
|       } | ||||
|  | ||||
|       .step .stepCounter { | ||||
|         color: #999; | ||||
|         color: ${cssManager.bdTheme('#64748b', '#a1a1aa')}; | ||||
|         position: absolute; | ||||
|         top: 0px; | ||||
|         right: 0px; | ||||
|         padding: 10px 15px; | ||||
|         top: 12px; | ||||
|         right: 12px; | ||||
|         padding: 6px 14px; | ||||
|         font-size: 12px; | ||||
|         border-bottom-left-radius: 3px; | ||||
|         background: ${cssManager.bdTheme('#00000008', '#ffffff08')}; | ||||
|         border-radius: 999px; | ||||
|         background: ${cssManager.bdTheme('rgba(226, 232, 240, 0.5)', 'rgba(63, 63, 70, 0.45)')}; | ||||
|         border: 1px solid ${cssManager.bdTheme('rgba(226, 232, 240, 0.7)', 'rgba(63, 63, 70, 0.6)')}; | ||||
|       } | ||||
|  | ||||
|       .step .goBack { | ||||
|         color: #999; | ||||
|         cursor: default; | ||||
|         position: absolute; | ||||
|         top: 0px; | ||||
|         left: 0px; | ||||
|         padding: 10px 15px; | ||||
|         top: 12px; | ||||
|         left: 12px; | ||||
|         display: inline-flex; | ||||
|         align-items: center; | ||||
|         gap: 6px; | ||||
|         padding: 6px 12px; | ||||
|         font-size: 12px; | ||||
|         border-bottom-right-radius: 3px; | ||||
|         background: ${cssManager.bdTheme('#00000008', '#ffffff08')}; | ||||
|         font-weight: 500; | ||||
|         border-radius: 999px; | ||||
|         border: 1px solid ${cssManager.bdTheme('rgba(226, 232, 240, 0.9)', 'rgba(63, 63, 70, 0.85)')}; | ||||
|         background: ${cssManager.bdTheme('rgba(255, 255, 255, 0.9)', 'rgba(39, 39, 42, 0.85)')}; | ||||
|         color: ${cssManager.bdTheme('#475569', '#d4d4d8')}; | ||||
|         cursor: pointer; | ||||
|         transition: border 0.2s ease, color 0.2s ease, background 0.2s ease, transform 0.2s ease; | ||||
|       } | ||||
|  | ||||
|       .step .goBack:hover { | ||||
|         color: ${cssManager.bdTheme('#333', '#fff')}; | ||||
|         background: ${cssManager.bdTheme('#00000012', colors.dark.blue)}; | ||||
|         color: ${cssManager.bdTheme('#0f172a', '#fafafa')}; | ||||
|         border-color: ${cssManager.bdTheme(colors.dark.blue, colors.dark.blue)}; | ||||
|         background: ${cssManager.bdTheme('rgba(226, 232, 240, 0.95)', 'rgba(63, 63, 70, 0.7)')}; | ||||
|         transform: translateX(-2px); | ||||
|       } | ||||
|  | ||||
|       .step .goBack:active { | ||||
|         color: ${cssManager.bdTheme('#333', '#fff')}; | ||||
|         background: ${cssManager.bdTheme('#00000012', colors.dark.blueActive)}; | ||||
|         color: ${cssManager.bdTheme('#0f172a', '#fafafa')}; | ||||
|         border-color: ${cssManager.bdTheme(colors.dark.blueActive, colors.dark.blueActive)}; | ||||
|         background: ${cssManager.bdTheme('rgba(226, 232, 240, 0.85)', 'rgba(63, 63, 70, 0.6)')}; | ||||
|       } | ||||
|  | ||||
|       .step .goBack span { | ||||
|         transition: all 0.2s; | ||||
|         transition: transform 0.2s ease; | ||||
|         display: inline-block; | ||||
|       } | ||||
|  | ||||
| @@ -173,15 +286,16 @@ export class DeesStepper extends DeesElement { | ||||
|  | ||||
|       .step .title { | ||||
|         text-align: center; | ||||
|         padding-top: 50px; | ||||
|         padding-top: 64px; | ||||
|         font-family: 'Geist Sans', sans-serif; | ||||
|         font-size: 22px; | ||||
|  | ||||
|         font-weight: 500; | ||||
|         font-size: 24px; | ||||
|         font-weight: 600; | ||||
|         letter-spacing: -0.01em; | ||||
|         color: inherit; | ||||
|       } | ||||
|  | ||||
|       .step .content { | ||||
|         padding: 20px; | ||||
|         padding: 24px 28px 32px; | ||||
|       } | ||||
|     `, | ||||
|   ]; | ||||
| @@ -270,7 +384,14 @@ export class DeesStepper extends DeesElement { | ||||
|  | ||||
|   public async goBack() { | ||||
|     const currentIndex = this.steps.findIndex((stepArg) => stepArg === this.selectedStep); | ||||
|     this.selectedStep = this.steps[currentIndex - 1]; | ||||
|     if (currentIndex <= 0) { | ||||
|       return; | ||||
|     } | ||||
|     const currentStep = this.steps[currentIndex]; | ||||
|     currentStep.validationFuncCalled = false; | ||||
|     const previousStep = this.steps[currentIndex - 1]; | ||||
|     previousStep.validationFuncCalled = false; | ||||
|     this.selectedStep = previousStep; | ||||
|     await this.domtoolsPromise; | ||||
|     await this.domtools.convenience.smartdelay.delayFor(100); | ||||
|     this.selectedStep.onReturnToStepFunc?.(this, this.shadowRoot.querySelector('.selected')); | ||||
| @@ -278,6 +399,13 @@ export class DeesStepper extends DeesElement { | ||||
|  | ||||
|   public goNext() { | ||||
|     const currentIndex = this.steps.findIndex((stepArg) => stepArg === this.selectedStep); | ||||
|     this.selectedStep = this.steps[currentIndex + 1]; | ||||
|     if (currentIndex < 0 || currentIndex >= this.steps.length - 1) { | ||||
|       return; | ||||
|     } | ||||
|     const currentStep = this.steps[currentIndex]; | ||||
|     currentStep.validationFuncCalled = false; | ||||
|     const nextStep = this.steps[currentIndex + 1]; | ||||
|     nextStep.validationFuncCalled = false; | ||||
|     this.selectedStep = nextStep; | ||||
|   } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user