diff --git a/packages/components/src/components/form/shadow.tsx b/packages/components/src/components/form/shadow.tsx index b6548699c34..d6bab90be04 100644 --- a/packages/components/src/components/form/shadow.tsx +++ b/packages/components/src/components/form/shadow.tsx @@ -1,12 +1,12 @@ import type { JSX } from '@stencil/core'; +import { Component, h, Host, Method, Prop, State, Watch } from '@stencil/core'; import { validateErrorList, watchBoolean, watchString } from '../../schema'; -import { Component, h, Host, Prop, State, Watch, Method } from '@stencil/core'; import { translate } from '../../i18n'; -import type { ErrorListPropType, FormAPI, FormStates, KoliBriFormCallbacks, Stringified } from '../../schema'; import { KolLinkWcTag } from '../../core/component-names'; import KolAlertFc from '../../functional-components/Alert'; +import type { ErrorListPropType, FormAPI, FormStates, KoliBriFormCallbacks, Stringified } from '../../schema'; /** * @slot - Inhalt der Form. @@ -19,7 +19,8 @@ import KolAlertFc from '../../functional-components/Alert'; shadow: true, }) export class KolForm implements FormAPI { - errorListElement?: HTMLElement; + errorListBlock?: HTMLElement; + errorListFirstLink?: HTMLElement; /* Hint: This method may not be used at all while events are handled in form/controller#propagateSubmitEventToForm */ private readonly onSubmit = (event: Event) => { @@ -38,16 +39,11 @@ export class KolForm implements FormAPI { } }; - private readonly handleLinkClick = (event: Event) => { - const href = (event.target as HTMLAnchorElement | undefined)?.href; - if (href) { - const hrefUrl = new URL(href); - - const targetElement = document.querySelector(hrefUrl.hash); - if (targetElement && typeof targetElement.focus === 'function') { - targetElement.scrollIntoView({ behavior: 'smooth' }); - targetElement.focus(); - } + private readonly handleLinkClick = (selector: string) => { + const targetElement = document.querySelector(selector); + if (targetElement && typeof targetElement.focus === 'function') { + targetElement.scrollIntoView({ behavior: 'smooth' }); + targetElement.focus(); } }; @@ -55,12 +51,7 @@ export class KolForm implements FormAPI { return ( { - setTimeout(() => { - if (el && typeof el.focus === 'function') { - el.scrollIntoView({ behavior: 'smooth' }); - el.focus(); - } - }, 250); + this.errorListBlock = el; }} type="error" variant="card" @@ -71,11 +62,14 @@ export class KolForm implements FormAPI { {errorList?.map((error, index) => (
  • this.handleLinkClick(String(error.selector)) : error.selector }} ref={(el) => { - if (index === 0) this.errorListElement = el; + if (index === 0) { + this.errorListFirstLink = el; + this.scrollToErrorList(); + } }} />
  • @@ -114,11 +108,21 @@ export class KolForm implements FormAPI { ); } + private scrollToErrorList(): void { + setTimeout(() => { + this.errorListBlock?.scrollIntoView({ + behavior: 'smooth', + block: 'start', + }); + setTimeout(() => { + this.errorListFirstLink?.querySelector('a')?.focus(); + }, 1000); + }, 250); + } + @Method() async focusErrorList(): Promise { - if (this._errorList && this._errorList.length > 0) { - this.errorListElement?.focus(); - } + this.scrollToErrorList(); return Promise.resolve(); } diff --git a/packages/components/src/schema/props/error-list.ts b/packages/components/src/schema/props/error-list.ts index 8ba7891ff93..f2235ed064a 100644 --- a/packages/components/src/schema/props/error-list.ts +++ b/packages/components/src/schema/props/error-list.ts @@ -1,10 +1,11 @@ import type { Generic } from 'adopted-style-sheets'; +import { EventCallback } from '../types'; import { watchValidator } from '../utils'; /* types */ export type ErrorListPropType = { message: string; - selector: string; + selector: string | EventCallback; }; export type PropErrorList = { @@ -13,5 +14,11 @@ export type PropErrorList = { /* validator */ export const validateErrorList = (component: Generic.Element.Component, value?: ErrorListPropType[]): void => { - watchValidator(component, 'errorList', (value): boolean => typeof value === 'object', new Set(['Object']), value); + watchValidator( + component, + 'errorList', + (value): boolean => Array.isArray(value) && value.find((v) => !(typeof v === 'string' || typeof v === 'function')) === undefined, + new Set(['string', 'function']), + value, + ); }; diff --git a/packages/samples/react/src/components/form/error-list.tsx b/packages/samples/react/src/components/form/error-list.tsx index 6e7a8b102a6..311bbd92adb 100644 --- a/packages/samples/react/src/components/form/error-list.tsx +++ b/packages/samples/react/src/components/form/error-list.tsx @@ -1,28 +1,42 @@ +import { KolButton, KolForm, KolInputText } from '@public-ui/react'; import type { FC } from 'react'; -import React from 'react'; +import React, { useRef } from 'react'; import { SampleDescription } from '../SampleDescription'; -import { KolForm, KolInputText } from '@public-ui/react'; -export const FormErrorList: FC = () => ( - <> - -

    This sample shows a form with error messages.

    -
    +export const FormErrorList: FC = () => { + const formRef = useRef(); + return ( + <> + +

    This sample shows a form with error messages.

    +
    - -
    - - - -
    -
    - -); + +
    + + + +
    + { + formRef.current?.focusErrorList(); + }, + }} + /> +
    +
    +
    + + ); +};