import WUPBaseElement, { AttributeMap } from "./baseElement"; import IBaseControl from "./controls/baseControl.i"; export declare const enum SubmitActions { /** Disable any action */ none = 0, /** Scroll to first error (if exists) and focus control */ goToError = 1, /** Validate until first error is found (otherwise validate all) */ validateUntilFirst = 2, /** Collect to model only changed values */ collectChanged = 4, /** Reset isDirty and assign $value to $initValue for controls (on success only) */ reset = 8, /** Lock the whole form during the pending state (set $isPending = true or provide `promise` to submitEvent.waitFor); * Otherwise user can submit several times in a short time; * If promise resolves during the short-time pending state won't be set, otherwise it takes at least 300ms via helper {@link promiseWait} */ lockOnPending = 16 } declare const tagName = "wup-form"; declare global { namespace WUP.Form { interface SubmitDetails { /** Model collected from controls */ model: Record; /** Form related to submit event; equal to event.target */ relatedForm: WUPFormElement; /** Event that produced submit event; null if `form.$submit()` is called */ relatedEvent: MouseEvent | KeyboardEvent | null; /** Element that that produced submit event */ submitter: HTMLElement | null; /** Point a promise as callback to allow form show pending state during the promise */ waitFor?: Promise; } interface EventMap extends WUP.Base.EventMap { /** Fires before $submit is happened; can be prevented via `e.preventDefault()` */ $willSubmit: CustomEvent>; /** Fires by user-submit when validation successful and model is collected * * @tutorial * call `e.preventDefault()` to prevent dispatching `$submitEnd` & closing modal (if form in modal) */ $submit: CustomEvent; /** Fires when submit is end (after http-response); * @tutorial * call `e.preventDefault()` to prevent closing modal (if form in modal) */ $submitEnd: CustomEvent<{ success: boolean; }>; } interface Options { /** Actions that enabled on submit event; You can point several like: `goToError | collectChanged` * @defaultValue goToError | validateUntilFirst | reset | lockOnPending */ submitActions: SubmitActions; /** Enable to tore data in localStorage to prevent losing till submitted; * @defaultValue false * @tutorial Troubleshooting * * It doesn't save values that are complex objects. So `wup-select.$options.items = [{text: "N1",value: {id:1,name:'Nik'} }]` is skipped * * Point string-value if default storage-key doesn't fit: based on `url+control.names` @see{@link WUPFormElement.storageKey} * @defaultValue false */ autoStore: boolean | string; /** Focus first possible element when it's appended to layout * @defaultValue false */ autoFocus: boolean; /** Disallow edit/copy value; adds attr [disabled] for styling * @defaultValue false */ disabled: boolean; /** Disallow copy value; adds attr [readonly] for styling * @defaultValue false */ readOnly: boolean; /** Enable/disable browser-autocomplete; if control has no autocomplete option then it's inherited from form * @defaultValue false */ autoComplete: boolean; } interface JSXProps extends WUP.Base.OnlyNames { "w-submitActions"?: SubmitActions | number; "w-autoStore"?: boolean | string; "w-autoFocus"?: boolean | ""; "w-autoComplete"?: boolean | ""; /** @deprecated use [disabled] instead since related to CSS-styles */ "w-disabled"?: boolean | ""; disabled?: boolean | ""; /** @deprecated use [disabled] instead since related to CSS-styles */ "w-readonly"?: boolean | ""; readonly?: boolean | ""; /** @deprecated SyntheticEvent is not supported. Use ref.addEventListener('$change') instead */ onChange?: never; /** @deprecated SyntheticEvent is not supported. Use ref.addEventListener('$willSubmit') instead */ onWillSubmit?: never; /** @deprecated SyntheticEvent is not supported. Use ref.addEventListener('$submit') instead */ onSubmit?: never; } } interface HTMLElementTagNameMap { [tagName]: WUPFormElement; } namespace JSX { interface IntrinsicElements { /** Wrapper of FormHTMLElement that collect values from controls * @see {@link WUPFormElement} */ [tagName]: WUP.Base.ReactHTML & WUP.Form.JSXProps; } } } declare module "preact/jsx-runtime" { namespace JSX { interface HTMLAttributes { } interface IntrinsicElements { /** Wrapper of FormHTMLElement that collect values from controls * @see {@link WUPFormElement} */ [tagName]: HTMLAttributes & WUP.Form.JSXProps; } } } /** Wrapper of FormHTMLElement that collect values from controls * @example * // init form * const form = document.createElement("wup-form"); * form.$options.autoComplete = false; * form.$initModel = { email: "test-me@google.com" }; * form.addEventListener("$submit", (e) => console.warn(e.detail.model) ); * form.$onSubmit = async (e)=>{ await postHere(e.detail.model); } // equal to form.addEventListener * // init control * const el = document.createElement("wup-text"); * el.$options.name = "email"; * el.$options.validations = { required: true, email: true }; * form.appendChild(el); * const btn = form.appendChild(document.createElement("button")); * btn.textContent = "Submit"; * btn.type = "submit"; * document.body.appendChild(form); * // or HTML * * * /> */ export default class WUPFormElement = any, TOptions extends WUP.Form.Options = WUP.Form.Options, Events extends WUP.Form.EventMap = WUP.Form.EventMap> extends WUPBaseElement { #private; static get $styleRoot(): string; static get $style(): string; static get mappedAttributes(): Record; /** Find form related to control,register and apply initModel if initValue undefined */ static $tryConnect(control: IBaseControl & HTMLElement): WUPFormElement | undefined; /** Map model to control-values */ static $modelToControls>(m: T | undefined, controls: IBaseControl[], prop: keyof Pick): void; /** Collect model from control-values */ static $modelFromControls(prevModel: Partial, controls: IBaseControl[], prop: keyof Pick, isOnlyChanged?: boolean): Partial; static get observedAttributes(): Array; /** Default options - applied to every element. Change it to configure default behavior */ static $defaults: WUP.Form.Options; /** Fires before $submit is happened; can be prevented via `e.preventDefault()` */ $onWillSubmit?: (ev: WUP.Form.EventMap["$willSubmit"]) => void; /** Dispatched on submit * @tutorial * * need to return promise to lock form and show spinner on http-request * * call `e.preventDefault()` to prevent dispatching `$submitEnd` & closing modal (if form in modal) */ $onSubmit?: (ev: WUP.Form.EventMap["$submit"]) => void | Promise; /** Fires when submit is end (after http-response); * @tutorial * call `e.preventDefault()` to prevent closing modal (if form in modal) */ $onSubmitEnd?: (ev: WUP.Form.EventMap["$submitEnd"]) => void; /** Dispatched on submit */ /** All controls related to form */ $controls: IBaseControl[]; /** Returns related to form controls with $options.name != null */ get $controlsAttached(): IBaseControl[]; _model?: Partial; /** Model related to every control inside (mapped object via control.$options.name); * @see {@link BaseControl.prototype.$value} * @tutorial rules * * `form.$model = { firstName: 'Hell' }` updates only control with $options.name==='firstName' * * `form.$model = { firstName: undefined }` reset only control with $options.name==='firstName' */ get $model(): Partial; set $model(m: Partial); _initModel?: Partial; /** Default/init model related to every control inside; * @see {@link BaseControl.prototype.$initValue} */ get $initModel(): Partial | undefined; set $initModel(m: Partial | undefined); /** Pending state (spinner + lock form if SubmitActions.lockOnPending enabled) */ get $isPending(): boolean; set $isPending(v: boolean); /** Returns true if all nested controls (with name) are valid */ get $isValid(): boolean; /** Returns true if some of controls value is changed by user */ get $isChanged(): boolean; /** Call it to manually trigger submit or better to use `gotSubmit` for handling events properly */ $submit(): void; /** Validate all attached & not disabled controls * @param tillFirstInvalid point `true` if need to find first invalid control; if skipped then will be defined from `$options.submitActions: SubmitActions.validateUntilFirst` * @returns array of invalid controls (empty if all are valid) */ $validate(tillFirstInvalid?: boolean): Array; /** Called on every spin-render */ renderSpin(target: HTMLElement): { dispose: () => void; }; /** Change pending state */ protected changePending(v: boolean): void; /** Called on submit before validation (to fire validation & $onSubmit if successful) */ gotSubmit(e: KeyboardEvent | MouseEvent | null, submitter: HTMLElement): void; protected gotChanges(propsChanged: Array | null): void; protected gotReady(): void; protected connectedCallback(): void; /** Returns storage key based on url+control-names or `$options.autoStore` if `string` */ get storageKey(): string; /** Get & parse value from storage according to option `autoStore`, $model */ storageGet(): Partial | null; _preventStorageSave?: boolean; /** Save/remove model (only changes) to storage according to option `autoStore`, $model * @returns model saved to localStorage or Null if removed */ storageSave(model?: null | Record): Partial | null; protected disconnectedCallback(): void; } export {};