UNPKG

@instawork/design-system

Version:

The design system for Instawork's web apps

346 lines 12.4 kB
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, privateMap) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return privateMap.get(receiver); }; var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, privateMap, value) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to set private field on non-instance"); } privateMap.set(receiver, value); return value; }; var __disabled; import * as $ from 'jquery'; import { CustomInputComponent } from '../custom-input'; import './nested-input.component.scss'; const DATA_ATTR_DISABLED_PLACEHOLDER = 'disabled-placeholder'; const ATTR_SHOW_DISABLED_VALUE = 'show-disabled-value'; const DATA_CURRENT_VALUE = 'current-value'; const DATA_PLACEHOLDER = 'placeholder'; const DATA_ORIGINAL_VALUE = 'original-value'; const DATA_TABINDEX = 'tab-index'; // keys that need to have their property values synced with the value element's attributes const ATTR_PROPS = [ 'max', 'maxLength', 'min', 'minLength', ]; /** * A custom component that supports adding extra content inside a .form-control styled input. * * Optional attributes: * data-disabled-placeholder: If set, hides the input value and uses the specified placeholder when the input is * disabled. * * Usage: * <iw-nested-input [data-disabled-placeholder]="-"> * <input type="text" name="..." /> * <span>Extra content here</span> * </iw-nested-input> */ export class NestedInputComponent extends CustomInputComponent { constructor($el) { var _a, _b; super($el); __disabled.set(this, void 0); this.$display = this.getDisplayInput(); this.$displayPlaceholder = this.getDisplayPlaceholder(); this.$value = this.getValueInput(); this.valueEl = this.$value[0]; this.required = this.$value.prop('required') || typeof this.$el.attr('required') !== 'undefined'; this.disabled = this.$value.prop('disabled') || typeof this.$el.attr('disabled') !== 'undefined'; this.placeholder = this.$display.prop('placeholder') || this.$el.attr('placeholder'); this.$el.data(DATA_PLACEHOLDER, this.placeholder); this.init(); // define these property setters/getters so that they can be set via jQuery Object.defineProperties(this.el, Object.assign({ disabled: { get: () => this.disabled, set: (disabled) => this.disabled = !!disabled, }, showDisabledValue: { get: () => this.showDisabledValue, set: (showDisabledValue) => this.showDisabledValue = showDisabledValue, }, placeholder: { get: () => this.placeholder, set: (placeholder) => this.placeholder = placeholder, }, value: { get: () => this.value, set: (value) => this.value = value, }, validity: { get: () => { var _a; return (_a = this.valueEl) === null || _a === void 0 ? void 0 : _a.validity; }, }, checkValidity: { value: (_a = this.valueEl) === null || _a === void 0 ? void 0 : _a.checkValidity.bind(this.valueEl), }, reportValidity: { value: (_b = this.valueEl) === null || _b === void 0 ? void 0 : _b.reportValidity.bind(this.valueEl), }, required: { get: () => this.required, set: (value) => this.required = value, } }, ATTR_PROPS.reduce((result, key) => { result[key] = { get: () => this[key], set: (value) => this[key] = value, }; return result; }, {}))); } static loadPlugin() { super.loadPlugin(); if (!$.fn.iwNestedInput) { $.fn.iwNestedInput = this.jQueryPlugin('NestedInputComponent'); } } get disabled() { return __classPrivateFieldGet(this, __disabled); } set disabled(disabled) { const isChange = (!!__classPrivateFieldGet(this, __disabled)) !== (!!disabled); __classPrivateFieldSet(this, __disabled, !!disabled); if (isChange) { this.onDisabledChange(__classPrivateFieldGet(this, __disabled)); } } get placeholder() { return this._placeholder; } set placeholder(placeholder) { this._placeholder = placeholder; if (this.disabled && this.disabledPlaceholder) { return; } if (typeof placeholder === 'undefined') { this.$display.removeProp('placeholder'); } else { this.$display.prop('placeholder', placeholder); } } get disabledPlaceholder() { return this.$el.data(DATA_ATTR_DISABLED_PLACEHOLDER); } get value() { return this.$value.val(); } set value(value) { if (value !== this.value) { this.$el.attr('value', value); // so the attribute updates in the DOM this.setDisplay(value); this.setValue(value); this.$el.trigger('change'); } } get max() { return this.getAttrProp('max'); } set max(value) { this.setAttrProp('max', value); } get maxLength() { return this.getAttrProp('maxLength'); } set maxLength(value) { this.setAttrProp('maxLength', value); } get min() { return this.getAttrProp('min'); } set min(value) { this.setAttrProp('min', value); } get minLength() { return this.getAttrProp('minLength'); } set minLength(value) { this.setAttrProp('minLength', value); } get required() { return this.getAttrProp('required'); } set required(value) { this.setAttrProp('required', value); } get showDisabledValue() { return this.$el.attr(ATTR_SHOW_DISABLED_VALUE) !== undefined; } set showDisabledValue(value) { if (value) { this.$el.attr(ATTR_SHOW_DISABLED_VALUE); } else { this.$el.removeAttr(ATTR_SHOW_DISABLED_VALUE); } } /** * Returns the value set at the time of initialization, if any */ get originalValue() { return this.$el.data(DATA_ORIGINAL_VALUE); } /** * Gets the current value, regardless of disabled state. */ get currentValue() { return this.$el.data(DATA_CURRENT_VALUE); } get isModified() { var _a, _b; return ((_a = this.originalValue) === null || _a === void 0 ? void 0 : _a.valueOf()) !== ((_b = this.currentValue) === null || _b === void 0 ? void 0 : _b.valueOf()); } /** * Returns a {@link JQuery} object representing the input element(s) that the user will be able see and interact with */ getDisplayInput() { return this.getValueInput(); } /** * Returns a {@link JQuery} object representing the input element(s) that the will be used to display the placeholder * value. This may be the same as {@link getDisplayInput}. */ getDisplayPlaceholder() { return this.getDisplayInput(); } /** * Returns a {@link JQuery} object representing the input element(s) that the will be used to represent the value of * the input component. This may be the same as {@link getDisplayInput}. */ getValueInput() { return this.$el.find(':input'); } /** * Encapsulates all initialization logic that can be customized by subclasses */ init() { // TODO: move all of this except initValue to CustomComponent this.initDomRefs(); this.validateHostAttributes(); this.initDom(); this.initValue(); this.initAttrProps(); this.initEvents(); } /** * Hook for subclasses to find and initialize references to child elements created by the template */ initDomRefs() { } /** * Copies the "value" attribute from the host element to the value element, saves the original value in a data * property */ initValue() { const value = this.findOriginalValue() || ''; const importedValue = this.importValue(value); this.setValue(this.formatValue(importedValue)); this.$el .data(DATA_ORIGINAL_VALUE, value) .data(DATA_CURRENT_VALUE, value); } /** * Hook for subclasses to make any additional updates to the DOM */ initDom() { } /** * Syncs attribute values from the host element to corresponding attributes on the value element */ initAttrProps() { ATTR_PROPS.forEach(name => this.setAttrProp(name, this.$el.attr(name))); } /** * Hook for subclasses to validate parsed values from attributes */ validateHostAttributes() { } /** * Set up event handlers */ initEvents() { // focus the first input when clicking directly on the element itself or any non-input child element this.$el.on('click', (e) => { if ($(e.target).is(':not(:input)')) { this.$display.first().focus(); } }); this.$el.on('change', () => { this.$el.data(DATA_CURRENT_VALUE, this.value); }); } /** * Returns the string representation of the original value as defined in the initial rendering of the document */ findOriginalValue() { return this.$el.attr('value') || this.$value.val(); } /** * Sets the representation of the value that is shown in the UI */ setDisplay(value) { this.$display.val(value); } /** * Optionally convert the string representation of a value to a parsed value */ importValue(value) { // TODO: extract more of TemporalComponent's importValue / syncValue / onValue pattern to standardize the value // processing pipeline for "nested" components return value; } /** * Updates the value element's value property with a new value */ setValue(value) { this.$value.val(value); } /** * Convert a parsed value to its string representation for storing in the value element's value property */ formatValue(value) { if (typeof value === 'undefined') { return ''; } return value.toString(); } onDisabledChange(disabled) { this.$display.prop('disabled', disabled); if (disabled) { this.$el .attr('disabled', '') // remove the tabindex attribute so that the element cannot be given focus when disabled .data(DATA_TABINDEX, this.$el.attr('tabindex')) .removeAttr('tabindex'); } else { this.$el .removeAttr('disabled') // restore the previously set tabindex .attr('tabindex', this.$el.data(DATA_TABINDEX)); } this.updatePlaceholderState(disabled); } syncPlaceholder(disabled) { const enabledPlaceholder = this.placeholder || ''; const disabledPlaceholder = this.disabledPlaceholder || enabledPlaceholder; this.$displayPlaceholder.prop('placeholder', disabled ? disabledPlaceholder : enabledPlaceholder); } updatePlaceholderState(disabled) { if (disabled) { if (this.disabledPlaceholder && !this.showDisabledValue) { this.setDisplay(''); } } else { this.setDisplay(this.currentValue); } const nonInputContentVisibility = disabled && !!this.disabledPlaceholder && !this.showDisabledValue ? 'hidden' : 'visible'; this.$el.find(':not(:input)').css('visibility', nonInputContentVisibility); this.syncPlaceholder(disabled); } // TODO: add mapped types for supported attribute-based properties getAttrProp(name) { return this.$value.prop(name); } setAttrProp(name, value) { this.$value.prop(name, value); } } __disabled = new WeakMap(); NestedInputComponent.COMPONENT_SELECTOR = 'iw-nested-input'; //# sourceMappingURL=nested-input.component.js.map