Drive Field attrs from Soma runtime

active-uix
dev 5 months ago
parent 60403b95a3
commit c6cf313734

@ -15,14 +15,18 @@ export const fieldMorfo = {
optional: false, optional: false,
states: ['idle', 'error', 'disabled', 'readonly', 'loading'], states: ['idle', 'error', 'disabled', 'readonly', 'loading'],
data: [ data: [
{ attr: 'data-state', values: ['idle', 'error', 'disabled', 'readonly', 'loading'] }, {
{ attr: 'data-disabled', severity: 'optional' }, attr: 'data-state',
{ attr: 'data-readonly', severity: 'optional' }, values: ['idle', 'error', 'disabled', 'readonly', 'loading'],
{ attr: 'data-required', severity: 'optional' }, value: v.stateRef('state')
{ attr: 'data-invalid', severity: 'optional' }, },
{ attr: 'data-dirty', severity: 'optional' }, { attr: 'data-disabled', value: v.propRef('disabled'), severity: 'optional' },
{ attr: 'data-touched', severity: 'optional' }, { attr: 'data-readonly', value: v.propRef('readonly'), severity: 'optional' },
{ attr: 'data-field-name', severity: 'optional' } { attr: 'data-required', value: v.propRef('required'), severity: 'optional' },
{ attr: 'data-invalid', value: v.propRef('invalid'), severity: 'optional' },
{ attr: 'data-dirty', value: v.propRef('dirty'), severity: 'optional' },
{ attr: 'data-touched', value: v.propRef('touched'), severity: 'optional' },
{ attr: 'data-field-name', value: v.propRef('name'), emit: 'value', severity: 'optional' }
], ],
aria: [] aria: []
}, },
@ -34,9 +38,9 @@ export const fieldMorfo = {
defaultElement: 'label', defaultElement: 'label',
optional: true, optional: true,
data: [ data: [
{ attr: 'data-disabled', severity: 'optional' }, { attr: 'data-disabled', value: v.propRef('disabled'), severity: 'optional' },
{ attr: 'data-invalid', severity: 'optional' }, { attr: 'data-invalid', value: v.propRef('invalid'), severity: 'optional' },
{ attr: 'data-required', severity: 'optional' } { attr: 'data-required', value: v.propRef('required'), severity: 'optional' }
], ],
aria: [ aria: [
{ {
@ -55,9 +59,13 @@ export const fieldMorfo = {
optional: true, optional: true,
states: ['idle', 'error', 'disabled', 'readonly', 'loading'], states: ['idle', 'error', 'disabled', 'readonly', 'loading'],
data: [ data: [
{ attr: 'data-state', values: ['idle', 'error', 'disabled', 'readonly', 'loading'] }, {
{ attr: 'data-disabled', severity: 'optional' }, attr: 'data-state',
{ attr: 'data-invalid', severity: 'optional' } values: ['idle', 'error', 'disabled', 'readonly', 'loading'],
value: v.stateRef('state')
},
{ attr: 'data-disabled', value: v.propRef('disabled'), severity: 'optional' },
{ attr: 'data-invalid', value: v.propRef('invalid'), severity: 'optional' }
], ],
aria: [] aria: []
}, },
@ -69,7 +77,13 @@ export const fieldMorfo = {
defaultElement: 'input', defaultElement: 'input',
optional: true, optional: true,
states: ['idle', 'error', 'disabled', 'readonly', 'loading'], states: ['idle', 'error', 'disabled', 'readonly', 'loading'],
data: [{ attr: 'data-state', values: ['idle', 'error', 'disabled', 'readonly', 'loading'] }], data: [
{
attr: 'data-state',
values: ['idle', 'error', 'disabled', 'readonly', 'loading'],
value: v.stateRef('state')
}
],
aria: [ aria: [
{ attr: 'type', value: v.propRef('type') }, { attr: 'type', value: v.propRef('type') },
{ {
@ -106,7 +120,7 @@ export const fieldMorfo = {
kind: 'public', kind: 'public',
defaultElement: 'div', defaultElement: 'div',
optional: true, optional: true,
data: [{ attr: 'data-disabled', severity: 'optional' }], data: [{ attr: 'data-disabled', value: v.propRef('disabled'), severity: 'optional' }],
aria: [] aria: []
}, },
{ {

@ -1,5 +1,5 @@
import { context, type WithRefOpts } from '../../provider'; import { context, type WithRefOpts } from '../../provider';
import { boolToEmptyStrOrUndef, boolToStr } from '$adom'; import { boolToStr } from '$adom';
import { readableActive, state, type ActiveProps, type StateProps } from '$libs/reactive'; import { readableActive, state, type ActiveProps, type StateProps } from '$libs/reactive';
import type { OnChangeFn, SomaEvent } from '../../types'; import type { OnChangeFn, SomaEvent } from '../../types';
import type { FieldInputType, FieldState } from './types'; import type { FieldInputType, FieldState } from './types';
@ -56,12 +56,32 @@ export class FieldProvider {
private constructor(opts: FieldOpts) { private constructor(opts: FieldOpts) {
this.opts = opts; this.opts = opts;
this.soma = Soma.require(); this.soma = Soma.require();
this.runtime = this.soma.runtime(fieldMorfo, {}); this.runtime = this.soma.runtime(fieldMorfo, {
states: {
state: () => this.effectiveState
},
props: {
name: () => this.opts.name.current,
disabled: () => this.isDisabled,
readonly: () => this.isReadonly,
required: () => this.isRequired,
invalid: () => this.isInvalid,
dirty: () => this.isDirty,
touched: () => this.isTouched
},
parts: {
input: () => this.inputId.current || undefined,
label: () => this.labelId.current || undefined,
'helper-text': () => this.helperId.current || undefined,
'error-text': () => this.errorId.current || undefined
}
});
this.runtimePart = this.runtime.part('provider', { this.runtimePart = this.runtime.part('provider', {
id: opts.id, id: opts.id,
ref: opts.ref, ref: opts.ref,
owner: this, owner: this,
context: FieldProvider.ctx context: FieldProvider.ctx,
syncAttrs: true
}); });
// Auto-register / unregister with the parent Form (if `name` is set). // Auto-register / unregister with the parent Form (if `name` is set).
@ -153,14 +173,6 @@ export class FieldProvider {
readonly props = $derived.by(() => readonly props = $derived.by(() =>
this.runtimePart.assert({ this.runtimePart.assert({
...this.runtimePart.props, ...this.runtimePart.props,
'data-field-name': this.opts.name.current,
'data-state': this.effectiveState,
'data-disabled': boolToEmptyStrOrUndef(this.isDisabled),
'data-readonly': boolToEmptyStrOrUndef(this.isReadonly),
'data-required': boolToEmptyStrOrUndef(this.isRequired),
'data-invalid': boolToEmptyStrOrUndef(this.isInvalid),
'data-dirty': boolToEmptyStrOrUndef(this.isDirty),
'data-touched': boolToEmptyStrOrUndef(this.isTouched),
onfocusout: this.onfocusout onfocusout: this.onfocusout
} as const) } as const)
); );
@ -185,18 +197,15 @@ export class FieldLabelProvider {
this.runtimePart = this.provider.runtime.part('label', { this.runtimePart = this.provider.runtime.part('label', {
id: opts.id, id: opts.id,
ref: opts.ref, ref: opts.ref,
owner: this owner: this,
syncAttrs: true
}); });
this.provider.labelId.current = opts.id.current; this.provider.labelId.current = opts.id.current;
} }
readonly props = $derived.by(() => readonly props = $derived.by(() =>
this.runtimePart.assert({ this.runtimePart.assert({
...this.runtimePart.props, ...this.runtimePart.props
for: this.provider.inputId.current || undefined,
'data-disabled': boolToEmptyStrOrUndef(this.provider.isDisabled),
'data-invalid': boolToEmptyStrOrUndef(this.provider.isInvalid),
'data-required': boolToEmptyStrOrUndef(this.provider.isRequired)
} as const) } as const)
); );
} }
@ -220,16 +229,14 @@ export class FieldControlProvider {
this.runtimePart = this.provider.runtime.part('control', { this.runtimePart = this.provider.runtime.part('control', {
id: opts.id, id: opts.id,
ref: opts.ref, ref: opts.ref,
owner: this owner: this,
syncAttrs: true
}); });
} }
readonly props = $derived.by(() => readonly props = $derived.by(() =>
this.runtimePart.assert({ this.runtimePart.assert({
...this.runtimePart.props, ...this.runtimePart.props
'data-state': this.provider.effectiveState,
'data-disabled': boolToEmptyStrOrUndef(this.provider.isDisabled),
'data-invalid': boolToEmptyStrOrUndef(this.provider.isInvalid)
} as const) } as const)
); );
} }
@ -320,7 +327,8 @@ export class FieldHelperTextProvider {
this.runtimePart = this.provider.runtime.part('helper-text', { this.runtimePart = this.provider.runtime.part('helper-text', {
id: opts.id, id: opts.id,
ref: opts.ref, ref: opts.ref,
owner: this owner: this,
syncAttrs: true
}); });
this.provider.helperId.current = opts.id.current; this.provider.helperId.current = opts.id.current;
@ -334,8 +342,7 @@ export class FieldHelperTextProvider {
readonly props = $derived.by(() => readonly props = $derived.by(() =>
this.runtimePart.assert({ this.runtimePart.assert({
...this.runtimePart.props, ...this.runtimePart.props
'data-disabled': boolToEmptyStrOrUndef(this.provider.isDisabled)
} as const) } as const)
); );
} }
@ -359,7 +366,8 @@ export class FieldErrorTextProvider {
this.runtimePart = this.provider.runtime.part('error-text', { this.runtimePart = this.provider.runtime.part('error-text', {
id: opts.id, id: opts.id,
ref: opts.ref, ref: opts.ref,
owner: this owner: this,
syncAttrs: true
}); });
this.provider.errorId.current = opts.id.current; this.provider.errorId.current = opts.id.current;
@ -373,9 +381,7 @@ export class FieldErrorTextProvider {
readonly props = $derived.by(() => readonly props = $derived.by(() =>
this.runtimePart.assert({ this.runtimePart.assert({
...this.runtimePart.props, ...this.runtimePart.props
role: 'alert' as const,
'aria-live': 'polite' as const
} as const) } as const)
); );
} }

Loading…
Cancel
Save

Powered by TurnKey Linux.