Skip to content

Commit

Permalink
make ErrorPattern a mixin
Browse files Browse the repository at this point in the history
  • Loading branch information
mollykreis committed Nov 6, 2024
1 parent 9a83dfb commit 2c65ff5
Show file tree
Hide file tree
Showing 8 changed files with 60 additions and 152 deletions.
19 changes: 3 additions & 16 deletions packages/nimble-components/src/combobox/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import { iconArrowExpanderDownTag } from '../icons/arrow-expander-down';
import { iconExclamationMarkTag } from '../icons/exclamation-mark';

import { styles } from './styles';
import type { ErrorPattern } from '../patterns/error/types';
import { mixinErrorPattern } from '../patterns/error/types';
import {
DropdownAppearance,
type DropdownPattern
Expand All @@ -52,20 +52,11 @@ declare global {
* A nimble-styed HTML combobox
*/
export class Combobox
extends FormAssociatedCombobox
implements DropdownPattern, ErrorPattern {
extends mixinErrorPattern(FormAssociatedCombobox)
implements DropdownPattern {
@attr
public appearance: DropdownAppearance = DropdownAppearance.underline;

/**
* A message explaining why the value is invalid.
*/
@attr({ attribute: 'error-text' })
public errorText?: string;

@attr({ attribute: 'error-visible', mode: 'boolean' })
public errorVisible = false;

/**
* The autocomplete attribute.
*/
Expand Down Expand Up @@ -143,10 +134,6 @@ export class Combobox
@observable
public hasOverflow = false;

/* @internal */
@observable
public errorHasOverflow = false;

public override get value(): string {
Observable.track(this, 'value');
return this._value;
Expand Down
21 changes: 2 additions & 19 deletions packages/nimble-components/src/number-field/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
import { styles } from './styles';
import { NumberFieldAppearance } from './types';
import { errorTextTemplate } from '../patterns/error/template';
import type { ErrorPattern } from '../patterns/error/types';
import { mixinErrorPattern } from '../patterns/error/types';
import { buttonTag } from '../button';
import { iconMinusWideTag } from '../icons/minus-wide';
import { iconAddTag } from '../icons/add';
Expand All @@ -27,27 +27,10 @@ declare global {
/**
* A nimble-styled HTML number input
*/
export class NumberField extends FoundationNumberField implements ErrorPattern {
export class NumberField extends mixinErrorPattern(FoundationNumberField) {
@attr
public appearance: NumberFieldAppearance = NumberFieldAppearance.underline;

/**
* A message explaining why the value is invalid.
*
* @public
* @remarks
* HTML Attribute: error-text
*/
@attr({ attribute: 'error-text' })
public errorText?: string;

@attr({ attribute: 'error-visible', mode: 'boolean' })
public errorVisible = false;

/* @internal */
@observable
public errorHasOverflow = false;

public override connectedCallback(): void {
super.connectedCallback();

Expand Down
59 changes: 44 additions & 15 deletions packages/nimble-components/src/patterns/error/types.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,50 @@
/**
* This interface should be used by components that want to leverage the error pattern. The error pattern conditionally adds error text to the template when an error is configured to be visible.
*/
import { attr, FASTElement, observable } from '@microsoft/fast-element';

export interface ErrorPattern {
/**
* The error text that will be displayed when a component is in the error appearance
*/
errorText?: string;

/*
* Show the error appearance of the control
*/
errorVisible: boolean;
errorHasOverflow: boolean;
}

/* @internal
* Indicates if the error text has overflowed its container. The value should not be
* set directly. Instead, it is used with the `overflow` directive. When declared in an
* implementation of `ErrorPattern`, it must be declared as `@observable`.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type FASTElementConstructor = abstract new (...args: any[]) => FASTElement;

// As the returned class is internal to the function, we can't write a signature that uses is directly, so rely on inference
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/explicit-function-return-type
export function mixinErrorPattern<TBase extends FASTElementConstructor>(base: TBase) {
/**
* The Mixin that provides a concrete column with the API to support being resized
* proportionally within a Table.
*/
errorHasOverflow: boolean;
abstract class ErrorPatternElement extends base implements ErrorPattern {
/**
* The error text that will be displayed when a component is in the error appearance
*/
public errorText?: string;

/*
* Show the error appearance of the control
*/
public errorVisible = false;

/* @internal
* Indicates if the error text has overflowed its container. The value should not be
* set directly. Instead, it is used with the `overflow` directive.
*/
public errorHasOverflow = false;
}

attr({ attribute: 'error-text' })(
ErrorPatternElement.prototype,
'errorText'
);
attr({ attribute: 'error-visible', mode: 'boolean' })(
ErrorPatternElement.prototype,
'errorVisible'
);
observable(
ErrorPatternElement.prototype,
'errorHasOverflow'
);
return ErrorPatternElement;
}
15 changes: 2 additions & 13 deletions packages/nimble-components/src/radio-group/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@ import {
DesignSystem
} from '@microsoft/fast-foundation';
import { Orientation } from '@microsoft/fast-web-utilities';
import { attr, observable } from '@microsoft/fast-element';
import { styles } from './styles';
import { template } from './template';
import type { ErrorPattern } from '../patterns/error/types';
import { mixinErrorPattern } from '../patterns/error/types';

declare global {
interface HTMLElementTagNameMap {
Expand All @@ -19,17 +18,7 @@ export { Orientation };
/**
* A nimble-styled grouping element for radio buttons
*/
export class RadioGroup extends FoundationRadioGroup implements ErrorPattern {
@attr({ attribute: 'error-text' })
public errorText?: string;

@attr({ attribute: 'error-visible', mode: 'boolean' })
public errorVisible = false;

/* @internal */
@observable
public errorHasOverflow = false;
}
export class RadioGroup extends mixinErrorPattern(FoundationRadioGroup) { }

const nimbleRadioGroup = RadioGroup.compose({
baseName: 'radio-group',
Expand Down
26 changes: 2 additions & 24 deletions packages/nimble-components/src/rich-text/editor/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import {
MentionDetail,
FormatButtonsState
} from './types';
import type { ErrorPattern } from '../../patterns/error/types';
import { mixinErrorPattern } from '../../patterns/error/types';
import { RichTextMarkdownParser } from '../models/markdown-parser';
import { RichTextMarkdownSerializer } from '../models/markdown-serializer';
import { RichText } from '../base';
Expand All @@ -44,7 +44,7 @@ declare global {
/**
* A nimble styled rich text editor
*/
export class RichTextEditor extends RichText implements ErrorPattern {
export class RichTextEditor extends mixinErrorPattern(RichText) {
/**
* @internal
*/
Expand Down Expand Up @@ -90,24 +90,6 @@ export class RichTextEditor extends RichText implements ErrorPattern {
@attr({ attribute: 'footer-hidden', mode: 'boolean' })
public footerHidden = false;

/**
* Whether to display the error state.
*
* @public
* HTML Attribute: error-visible
*/
@attr({ attribute: 'error-visible', mode: 'boolean' })
public errorVisible = false;

/**
* A message explaining why the value is invalid.
*
* @public
* HTML Attribute: error-text
*/
@attr({ attribute: 'error-text' })
public errorText?: string;

/**
* @public
* HTML Attribute: placeholder
Expand Down Expand Up @@ -196,10 +178,6 @@ export class RichTextEditor extends RichText implements ErrorPattern {
*/
public editorContainer!: HTMLDivElement;

/* @internal */
@observable
public errorHasOverflow = false;

private resizeObserver?: ResizeObserver;
private updateScrollbarWidthQueued = false;

Expand Down
23 changes: 3 additions & 20 deletions packages/nimble-components/src/select/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import {
ListOptionOwner
} from '../patterns/dropdown/types';
import { errorTextTemplate } from '../patterns/error/template';
import type { ErrorPattern } from '../patterns/error/types';
import { mixinErrorPattern } from '../patterns/error/types';
import { iconExclamationMarkTag } from '../icons/exclamation-mark';
import { isListOption, isListOptionGroup, template } from './template';
import type { ListOption } from '../list-option';
Expand Down Expand Up @@ -71,8 +71,8 @@ const isOptionOrGroupVisible = (el: ListOption | ListOptionGroup): boolean => {
* A nimble-styled HTML select.
*/
export class Select
extends FormAssociatedSelect
implements ErrorPattern, ListOptionOwner {
extends mixinErrorPattern(FormAssociatedSelect)
implements ListOptionOwner {
@attr
public appearance: DropdownAppearance = DropdownAppearance.underline;

Expand All @@ -84,19 +84,6 @@ export class Select
@attr({ attribute: 'position' })
public positionAttribute?: SelectPosition;

/**
* A message explaining why the value is invalid.
*
* @public
* @remarks
* HTML Attribute: error-text
*/
@attr({ attribute: 'error-text' })
public errorText: string | undefined;

@attr({ attribute: 'error-visible', mode: 'boolean' })
public errorVisible = false;

@attr({ attribute: 'filter-mode' })
public filterMode: FilterMode = FilterMode.none;

Expand Down Expand Up @@ -213,10 +200,6 @@ export class Select
return slotTextContent(this.labelSlot);
}

/* @internal */
@observable
public errorHasOverflow = false;

private _value = '';
private forcedPosition = false;
private openActiveIndex?: number;
Expand Down
28 changes: 2 additions & 26 deletions packages/nimble-components/src/text-area/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
DesignSystem,
TextArea as FoundationTextArea
} from '@microsoft/fast-foundation';
import type { ErrorPattern } from '../patterns/error/types';
import { mixinErrorPattern } from '../patterns/error/types';
import { styles } from './styles';
import { template } from './template';
import { TextAreaAppearance } from './types';
Expand All @@ -17,7 +17,7 @@ declare global {
/**
* A nimble-styed HTML text area
*/
export class TextArea extends FoundationTextArea implements ErrorPattern {
export class TextArea extends mixinErrorPattern(FoundationTextArea) {
/**
* The appearance the text area should have.
*
Expand All @@ -28,37 +28,13 @@ export class TextArea extends FoundationTextArea implements ErrorPattern {
@attr
public appearance: TextAreaAppearance = TextAreaAppearance.outline;

/**
* A message explaining why the value is invalid.
*
* @public
* @remarks
* HTML Attribute: error-text
*/
@attr({ attribute: 'error-text' })
public errorText?: string;

/**
* Whether to display the error state.
*
* @public
* @remarks
* HTML Attribute: error-visible
*/
@attr({ attribute: 'error-visible', mode: 'boolean' })
public errorVisible = false;

/**
* The width of the vertical scrollbar, if displayed.
* @internal
*/
@observable
public scrollbarWidth = -1;

/* @internal */
@observable
public errorHasOverflow = false;

private resizeObserver?: ResizeObserver;
private updateScrollbarWidthQueued = false;

Expand Down
21 changes: 2 additions & 19 deletions packages/nimble-components/src/text-field/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
import { styles } from './styles';
import { TextFieldAppearance } from './types';
import { errorTextTemplate } from '../patterns/error/template';
import type { ErrorPattern } from '../patterns/error/types';
import { mixinErrorPattern } from '../patterns/error/types';
import { iconExclamationMarkTag } from '../icons/exclamation-mark';

declare global {
Expand All @@ -20,7 +20,7 @@ declare global {
/**
* A nimble-styed HTML text input
*/
export class TextField extends FoundationTextField implements ErrorPattern {
export class TextField extends mixinErrorPattern(FoundationTextField) {
/**
* The appearance the text field should have.
*
Expand All @@ -31,25 +31,8 @@ export class TextField extends FoundationTextField implements ErrorPattern {
@attr
public appearance: TextFieldAppearance = TextFieldAppearance.underline;

/**
* A message explaining why the value is invalid.
*
* @public
* @remarks
* HTML Attribute: error-text
*/
@attr({ attribute: 'error-text' })
public errorText?: string;

@attr({ attribute: 'error-visible', mode: 'boolean' })
public errorVisible = false;

@attr({ attribute: 'full-bleed', mode: 'boolean' })
public fullBleed = false;

/* @internal */
@observable
public errorHasOverflow = false;
}

const nimbleTextField = TextField.compose<TextFieldOptions>({
Expand Down

0 comments on commit 2c65ff5

Please sign in to comment.