From 1c0c26f1cd0fc81a50eb0bab2bae6bc65e389581 Mon Sep 17 00:00:00 2001 From: webyom Date: Mon, 14 Sep 2020 17:27:57 +0800 Subject: [PATCH] refactor(field): onClick --- package-lock.json | 13 +++++++++++++ package.json | 1 + src/field/index.tsx | 40 +++++++++++++++++++++++++++++----------- src/form/demo/index.tsx | 7 +++++++ src/utils/dom.ts | 6 ++++++ types/closest.d.ts | 7 +++++++ 6 files changed, 63 insertions(+), 11 deletions(-) create mode 100644 types/closest.d.ts diff --git a/package-lock.json b/package-lock.json index fe4f636..cd4852d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4139,6 +4139,14 @@ "readable-stream": "^2.3.5" } }, + "closest": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/closest/-/closest-0.0.1.tgz", + "integrity": "sha1-JtpvgLPg4X5x+A8SeCgZ6fZTSVw=", + "requires": { + "matches-selector": "0.0.1" + } + }, "clsx": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.0.tgz", @@ -15160,6 +15168,11 @@ } } }, + "matches-selector": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/matches-selector/-/matches-selector-0.0.1.tgz", + "integrity": "sha1-HfUmIkOuNBwaCATdMCBIJnrHE7s=" + }, "mathml-tag-names": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz", diff --git a/package.json b/package.json index cd67957..bbf6dbd 100644 --- a/package.json +++ b/package.json @@ -86,6 +86,7 @@ "preact": ">=10.2.1" }, "dependencies": { + "closest": "0.0.1", "clsx": "^1.1.0" } } diff --git a/src/field/index.tsx b/src/field/index.tsx index 2ab6c82..b0c5823 100644 --- a/src/field/index.tsx +++ b/src/field/index.tsx @@ -1,5 +1,6 @@ import * as preact from 'preact'; import { isDef } from '../utils'; +import { closest } from '../utils/dom'; import { createBEM } from '../utils/bem'; import { Icon } from '../icon'; import { Cell, CellProps } from '../cell'; @@ -71,6 +72,7 @@ export type FieldProps = Omit & { onClosePopup?(field: Field, confirm?: boolean): void; onInputKeyDown?(evt: Event): void; onInputChange?(evt: Event): string | void; + onClick?: (evt: Event) => void; }; type FieldState = { @@ -108,6 +110,7 @@ const NO_MATCHED_RULE_FLAG = '__NO_MATCHED_RULE_FLAG__'; export class Field extends preact.Component, FieldState> { private isPopup = false; private readonly inputRef = preact.createRef(); + private readonly bodyRef = preact.createRef(); constructor(props: preact.RenderableProps>) { super(props); @@ -253,11 +256,17 @@ export class Field extends preact.Component, FieldState }); } - private openPopup(): void { + openPopup(): void { + if (!this.isPopup) { + return; + } this.setState({ showPopup: true }); } - private closePopup(confirm?: boolean): void { + closePopup(confirm?: boolean): void { + if (!this.isPopup) { + return; + } const { onClosePopup } = this.props; if (confirm) { this.setState({ showPopup: false, popupValue: this.formatReturnValue(this.inputRef.current.getValue()) }, () => { @@ -276,7 +285,12 @@ export class Field extends preact.Component, FieldState private onPopupControlClick(evt: Event): void { if (this.isPopup && !this.props.disabled) { const target = evt.target as HTMLElement; - if (target.className.indexOf('pant-field__control') !== -1) { + const field = closest(target, '.pant-field', true); + if ( + field && + field.querySelector('.pant-field__body') === this.bodyRef.current && + !closest(target, '.pant-popup, .pant-overlay', true) + ) { this.openPopup(); } } @@ -406,7 +420,7 @@ export class Field extends preact.Component, FieldState }); } - genInput(): preact.JSX.Element { + private genInput(): preact.JSX.Element { const { props } = this; const { type, name, inputAlign, children } = props; const { showPopup, popupValue, isInputType, value } = this.state; @@ -428,7 +442,6 @@ export class Field extends preact.Component, FieldState class={bem('control', [inputAlign, 'custom'])} value={this.formatDisplayValue(popupValue)} placeholder={props.placeholder} - onClick={this.onPopupControlClick} readOnly /> {childrenWithProps} @@ -487,7 +500,7 @@ export class Field extends preact.Component, FieldState } } - genRightIcon(): preact.JSX.Element { + private genRightIcon(): preact.JSX.Element { const { rightIcon } = this.props; if (typeof rightIcon === 'string') { return ; @@ -496,7 +509,7 @@ export class Field extends preact.Component, FieldState } } - genWordLimit(): preact.JSX.Element { + private genWordLimit(): preact.JSX.Element { const { showWordLimit, maxlength } = this.props; const { isInputType, value } = this.state; if (isInputType && showWordLimit && maxlength) { @@ -511,7 +524,7 @@ export class Field extends preact.Component, FieldState } } - genMessage(): preact.JSX.Element { + private genMessage(): preact.JSX.Element { const { errorMessage, errorMessageAlign } = this.props; const { validateMessage } = this.state; const message = validateMessage || errorMessage; @@ -522,6 +535,10 @@ export class Field extends preact.Component, FieldState render(): preact.JSX.Element { const { props } = this; + const { disabled } = props; + const input = this.genInput(); + const onClick = + typeof props.onClick === 'function' ? props.onClick : this.isPopup ? this.onPopupControlClick : null; return ( extends preact.Component, FieldState required={props.required} className={bem({ error: this.showError, - disabled: props.disabled, + disabled: disabled, 'min-height': props.type === 'textarea' && !props.autosize, })} titleClassName={bem('title')} valueClassName={bem('value')} + onClick={(!disabled && onClick) || null} > -
- {this.genInput()} +
+ {input} {this.showClear && } {this.genRightIcon()} {props.button &&
{props.button}
} diff --git a/src/form/demo/index.tsx b/src/form/demo/index.tsx index 79e2ce8..9d5d287 100644 --- a/src/form/demo/index.tsx +++ b/src/form/demo/index.tsx @@ -178,6 +178,13 @@ export class FormRouteComponent extends preact.Component { title="Switch" rules={[{ pattern: 'required', message: 'Required field', trigger: ['change'] }]} > + + type="checkbox" + defaultValue={true} + name="checkbox" + title="Checkbox" + rules={[{ pattern: 'required', message: 'Required field', trigger: ['change'] }]} + > name="checkbox-group" title="Checkbox Group" diff --git a/src/utils/dom.ts b/src/utils/dom.ts index f5c367e..c16b369 100755 --- a/src/utils/dom.ts +++ b/src/utils/dom.ts @@ -1,3 +1,5 @@ +import closestx from 'closest'; + export function removeNode(el: Node): void { const parent = el.parentNode; @@ -17,3 +19,7 @@ export function isHidden(el: HTMLElement): boolean { return hidden || parentHidden; } + +export function closest(element: Element | EventTarget, selector: string, checkYoSelf?: boolean): Element | null { + return closestx(element, selector, checkYoSelf); +} diff --git a/types/closest.d.ts b/types/closest.d.ts new file mode 100644 index 0000000..636b7c4 --- /dev/null +++ b/types/closest.d.ts @@ -0,0 +1,7 @@ +declare module 'closest' { + export default function closest( + element: Element | EventTarget, + selector: string, + checkYoSelf?: boolean, + ): Element | null; +}