diff --git a/src/uix/morfo/components/stepper.ts b/src/uix/morfo/components/stepper.ts index 41a84a5f4..de21a2b5f 100644 --- a/src/uix/morfo/components/stepper.ts +++ b/src/uix/morfo/components/stepper.ts @@ -17,8 +17,12 @@ export const stepperMorfo = { defaultElement: 'div', optional: false, data: [ - { attr: 'data-orientation', values: ['horizontal', 'vertical'] }, - { attr: 'data-linear', severity: 'optional' } + { + attr: 'data-orientation', + values: ['horizontal', 'vertical'], + value: v.propRef('orientation') + }, + { attr: 'data-linear', value: v.propRef('linear'), severity: 'optional' } ], aria: [] }, @@ -49,10 +53,19 @@ export const stepperMorfo = { optional: false, states: ['complete', 'current', 'incomplete'], data: [ - { attr: 'data-state', values: ['complete', 'current', 'incomplete'] }, - { attr: 'data-current', severity: 'optional' }, - { attr: 'data-complete', severity: 'optional' }, - { attr: 'data-incomplete', severity: 'optional' } + { + attr: 'data-state', + values: ['complete', 'current', 'incomplete'], + value: v.propRef('state') + }, + { + attr: 'data-orientation', + values: ['horizontal', 'vertical'], + value: v.propRef('orientation') + }, + { attr: 'data-current', value: v.propRef('current'), severity: 'optional' }, + { attr: 'data-complete', value: v.propRef('complete'), severity: 'optional' }, + { attr: 'data-incomplete', value: v.propRef('incomplete'), severity: 'optional' } ], aria: [] }, @@ -109,7 +122,16 @@ export const stepperMorfo = { defaultElement: 'div', optional: true, states: ['complete', 'current', 'incomplete'], - data: [{ attr: 'data-state', values: ['complete', 'current', 'incomplete'] }], + data: [ + { + attr: 'data-state', + values: ['complete', 'current', 'incomplete'], + value: v.propRef('state') + }, + { attr: 'data-current', value: v.propRef('current'), severity: 'optional' }, + { attr: 'data-complete', value: v.propRef('complete'), severity: 'optional' }, + { attr: 'data-incomplete', value: v.propRef('incomplete'), severity: 'optional' } + ], aria: [{ attr: 'aria-hidden', value: v.literal('true') }] }, { @@ -122,8 +144,19 @@ export const stepperMorfo = { optional: true, states: ['complete', 'current', 'incomplete'], data: [ - { attr: 'data-state', values: ['complete', 'current', 'incomplete'] }, - { attr: 'data-complete', severity: 'optional' } + { + attr: 'data-state', + values: ['complete', 'current', 'incomplete'], + value: v.propRef('state') + }, + { + attr: 'data-orientation', + values: ['horizontal', 'vertical'], + value: v.propRef('orientation') + }, + { attr: 'data-current', value: v.propRef('current'), severity: 'optional' }, + { attr: 'data-complete', value: v.propRef('complete'), severity: 'optional' }, + { attr: 'data-incomplete', value: v.propRef('incomplete'), severity: 'optional' } ], aria: [] }, @@ -136,7 +169,13 @@ export const stepperMorfo = { role: 'tabpanel', optional: true, states: ['complete', 'current', 'incomplete'], - data: [{ attr: 'data-state', values: ['complete', 'current', 'incomplete'] }], + data: [ + { + attr: 'data-state', + values: ['complete', 'current', 'incomplete'], + value: v.propRef('state') + } + ], aria: [] }, { @@ -145,7 +184,7 @@ export const stepperMorfo = { kind: 'public', defaultElement: 'div', optional: true, - data: [], + data: [{ attr: 'data-state', value: v.propRef('state'), emit: 'value' }], aria: [] }, { diff --git a/src/uix/soma/components/stepper/stepper-provider.svelte.ts b/src/uix/soma/components/stepper/stepper-provider.svelte.ts index ccc7c4ba1..b5c90c9d1 100644 --- a/src/uix/soma/components/stepper/stepper-provider.svelte.ts +++ b/src/uix/soma/components/stepper/stepper-provider.svelte.ts @@ -73,12 +73,18 @@ export class StepperProvider { private constructor(opts: StepperOpts) { this.opts = opts; this.soma = Soma.require(); - this.runtime = this.soma.runtime(stepperMorfo, {}); + this.runtime = this.soma.runtime(stepperMorfo, { + props: { + orientation: () => this.opts.orientation.current, + linear: () => this.opts.linear.current + } + }); this.runtimePart = this.runtime.part('provider', { id: opts.id, ref: opts.ref, owner: this, - context: StepperProvider.ctx + context: StepperProvider.ctx, + syncAttrs: true }); } @@ -125,9 +131,7 @@ export class StepperProvider { readonly props = $derived.by(() => this.runtimePart.assert({ ...this.runtimePart.props, - dir: this.opts.dir.current, - 'data-orientation': this.opts.orientation.current, - 'data-linear': boolToEmptyStrOrUndef(this.opts.linear.current) + dir: this.opts.dir.current } as const) ); } @@ -201,7 +205,15 @@ export class StepperItemProvider { id: opts.id, ref: opts.ref, owner: this, - context: StepperItemProvider.ctx + context: StepperItemProvider.ctx, + props: { + state: () => this.stepState, + orientation: () => this.provider.opts.orientation.current, + current: () => this.isCurrent, + complete: () => this.isComplete, + incomplete: () => this.isIncomplete + }, + syncAttrs: true }); // Track count: increment on mount, decrement on unmount @@ -219,12 +231,7 @@ export class StepperItemProvider { readonly props = $derived.by(() => this.runtimePart.assert({ - ...this.runtimePart.props, - 'data-state': this.stepState, - 'data-orientation': this.provider.opts.orientation.current, - 'data-current': boolToEmptyStrOrUndef(this.isCurrent), - 'data-complete': boolToEmptyStrOrUndef(this.isComplete), - 'data-incomplete': boolToEmptyStrOrUndef(this.isIncomplete) + ...this.runtimePart.props } as const) ); } @@ -351,7 +358,14 @@ export class StepperIndicatorProvider { this.runtimePart = this.item.provider.runtime.part('indicator', { id: opts.id, ref: opts.ref, - owner: this + owner: this, + props: { + state: () => this.item.stepState, + current: () => this.item.isCurrent, + complete: () => this.item.isComplete, + incomplete: () => this.item.isIncomplete + }, + syncAttrs: true }); } @@ -360,12 +374,7 @@ export class StepperIndicatorProvider { readonly props = $derived.by(() => this.runtimePart.assert({ - ...this.runtimePart.props, - 'aria-hidden': true as const, - 'data-state': this.item.stepState, - 'data-current': boolToEmptyStrOrUndef(this.item.isCurrent), - 'data-complete': boolToEmptyStrOrUndef(this.item.isComplete), - 'data-incomplete': boolToEmptyStrOrUndef(this.item.isIncomplete) + ...this.runtimePart.props } as const) ); } @@ -391,19 +400,21 @@ export class StepperSeparatorProvider { this.runtimePart = this.provider.runtime.part('separator', { id: opts.id, ref: opts.ref, - owner: this + owner: this, + props: { + state: () => this.item.stepState, + orientation: () => this.provider.opts.orientation.current, + current: () => this.item.isCurrent, + complete: () => this.item.isComplete, + incomplete: () => this.item.isIncomplete + }, + syncAttrs: true }); } readonly props = $derived.by(() => this.runtimePart.assert({ - ...this.runtimePart.props, - role: 'separator' as const, - 'data-state': this.item.stepState, - 'data-current': boolToEmptyStrOrUndef(this.item.isCurrent), - 'data-complete': boolToEmptyStrOrUndef(this.item.isComplete), - 'data-incomplete': boolToEmptyStrOrUndef(this.item.isIncomplete), - 'data-orientation': this.provider.opts.orientation.current + ...this.runtimePart.props } as const) ); } @@ -432,7 +443,11 @@ export class StepperContentProvider { this.runtimePart = this.provider.runtime.part('content', { id: opts.id, ref: opts.ref, - owner: this + owner: this, + props: { + state: () => this.stepState + }, + syncAttrs: true }); // Content can be inside or outside an Item — use get() not require() const item = StepperItemProvider.get(); @@ -446,9 +461,7 @@ export class StepperContentProvider { readonly props = $derived.by(() => this.runtimePart.assert({ ...this.runtimePart.props, - role: 'tabpanel' as const, - tabindex: this.isCurrent ? 0 : -1, - 'data-state': this.stepState + tabindex: this.isCurrent ? 0 : -1 } as const) ); } @@ -472,7 +485,11 @@ export class StepperCompletedContentProvider { this.runtimePart = this.provider.runtime.part('completed-content', { id: opts.id, ref: opts.ref, - owner: this + owner: this, + props: { + state: () => 'completed' + }, + syncAttrs: true }); } @@ -481,8 +498,7 @@ export class StepperCompletedContentProvider { readonly props = $derived.by(() => this.runtimePart.assert({ - ...this.runtimePart.props, - 'data-state': 'completed' as const + ...this.runtimePart.props } as const) ); }