@ckeditor/ckeditor5-ui
Version:
The UI framework and standard UI library of CKEditor 5.
188 lines (187 loc) • 6.67 kB
TypeScript
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
/**
* @module ui/labeledfield/labeledfieldview
*/
import View from '../view.js';
import LabelView from '../label/labelview.js';
import type { FocusableView } from '../focuscycler.js';
import type ViewCollection from '../viewcollection.js';
import { type Locale } from '@ckeditor/ckeditor5-utils';
import '../../theme/components/labeledfield/labeledfieldview.css';
/**
* The labeled field view class. It can be used to enhance any view with the following features:
*
* * a label,
* * (optional) an error message,
* * (optional) an info (status) text,
*
* all bound logically by proper DOM attributes for UX and accessibility. It also provides an interface
* (e.g. observable properties) that allows controlling those additional features.
*
* The constructor of this class requires a callback that returns a view to be labeled. The callback
* is called with unique ids that allow binding of DOM properties:
*
* ```ts
* const labeledInputView = new LabeledFieldView( locale, ( labeledFieldView, viewUid, statusUid ) => {
* const inputView = new InputTextView( labeledFieldView.locale );
*
* inputView.set( {
* id: viewUid,
* ariaDescribedById: statusUid
* } );
*
* inputView.bind( 'isReadOnly' ).to( labeledFieldView, 'isEnabled', value => !value );
* inputView.bind( 'hasError' ).to( labeledFieldView, 'errorText', value => !!value );
*
* return inputView;
* } );
*
* labeledInputView.label = 'User name';
* labeledInputView.infoText = 'Full name like for instance, John Doe.';
* labeledInputView.render();
*
* document.body.append( labeledInputView.element );
* ```
*
* See {@link module:ui/labeledfield/utils} to discover ready–to–use labeled input helpers for common
* UI components.
*/
export default class LabeledFieldView<TFieldView extends FocusableView = FocusableView> extends View {
/**
* The field view that gets labeled.
*/
readonly fieldView: TFieldView;
/**
* The label view instance that describes the entire view.
*/
readonly labelView: LabelView;
/**
* The status view for the {@link #fieldView}. It displays {@link #errorText} and
* {@link #infoText}.
*/
readonly statusView: View;
/**
* A collection of children of the internal wrapper element. Allows inserting additional DOM elements (views) next to
* the {@link #fieldView} for easy styling (e.g. positioning).
*
* By default, the collection contains {@link #fieldView} and {@link #labelView}.
*/
readonly fieldWrapperChildren: ViewCollection;
/**
* The text of the label.
*
* @observable
*/
label: string | undefined;
/**
* Controls whether the component is in read-only mode.
*
* @observable
*/
isEnabled: boolean;
/**
* An observable flag set to `true` when {@link #fieldView} is empty (`false` otherwise).
*
* @readonly
* @observable
* @default true
*/
isEmpty: boolean;
/**
* An observable flag set to `true` when {@link #fieldView} is currently focused by
* the user (`false` otherwise).
*
* @readonly
* @observable
* @default false
*/
isFocused: boolean;
/**
* The validation error text. When set, it will be displayed
* next to the {@link #fieldView} as a typical validation error message.
* Set it to `null` to hide the message.
*
* **Note:** Setting this property to anything but `null` will automatically
* make the `hasError` of the {@link #fieldView} `true`.
*
* @observable
*/
errorText: string | null;
/**
* The additional information text displayed next to the {@link #fieldView} which can
* be used to inform the user about its purpose, provide help or hints.
*
* Set it to `null` to hide the message.
*
* **Note:** This text will be displayed in the same place as {@link #errorText} but the
* latter always takes precedence: if the {@link #errorText} is set, it replaces
* {@link #infoText}.
*
* @observable
* @default null
*/
infoText: string | null;
/**
* (Optional) The additional CSS class set on the dropdown {@link #element}.
*
* @observable
*/
class: string | undefined;
/**
* The content of the `placeholder` attribute of the {@link #fieldView}.
*
* @observable
*/
placeholder: string | undefined;
/**
* The combined status text made of {@link #errorText} and {@link #infoText}.
* Note that when present, {@link #errorText} always takes precedence in the
* status.
*
* @see #errorText
* @see #infoText
* @see #statusView
* @private
* @observable
*/
_statusText: string | null;
/**
* Creates an instance of the labeled field view class using a provided creator function
* that provides the view to be labeled.
*
* @param locale The locale instance.
* @param viewCreator A function that returns a {@link module:ui/view~View}
* that will be labeled. The following arguments are passed to the creator function:
*
* * an instance of the `LabeledFieldView` to allow binding observable properties,
* * an UID string that connects the {@link #labelView label} and the labeled field view in DOM,
* * an UID string that connects the {@link #statusView status} and the labeled field view in DOM.
*/
constructor(locale: Locale | undefined, viewCreator: LabeledFieldViewCreator<TFieldView>);
/**
* Creates label view class instance and bind with view.
*
* @param id Unique id to set as labelView#for attribute.
*/
private _createLabelView;
/**
* Creates the status view instance. It displays {@link #errorText} and {@link #infoText}
* next to the {@link #fieldView}. See {@link #_statusText}.
*
* @param statusUid Unique id of the status, shared with the {@link #fieldView view's}
* `aria-describedby` attribute.
*/
private _createStatusView;
/**
* Focuses the {@link #fieldView}.
*/
focus(direction?: 1 | -1): void;
}
/**
* A creator function that returns a focusable view to be labeled by a {@link module:ui/labeledfield/labeledfieldview~LabeledFieldView}
* instance.
*/
export type LabeledFieldViewCreator<TFieldView extends FocusableView> = (labeledFieldView: LabeledFieldView, viewUid: string, statusUid: string) => TFieldView;