/** * Copyright Aquera Inc 2023 * * This source code is licensed under the BSD-3-Clause license found in the * LICENSE file in the root directory of this source tree. */ import { html, TemplateResult } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { styles } from './nile-switcher.css'; import NileElement from '../internal/nile-element'; import { CSSResultGroup } from 'lit'; import { choose } from 'lit/directives/choose.js'; import { classMap } from 'lit/directives/class-map.js'; import { repeat } from 'lit/directives/repeat.js'; import { watch } from '../internal/watch'; import { HasSlotController } from '../internal/slot'; /** * @summary Allows you to switch between nile elements * * @dependency nile-icon * @dependency nile-input * @dependency nile-checkbox * @dependency nile-dropdown * @dependency nile-textarea * * @event nile-change - Emitted when the control's value changes. * @event nile-switch - Emitted when the nile component is being switched. */ export interface switchconfig { [key: string]: any; toggleSwitch: boolean; disable?: boolean; confirmation?: boolean; align: 'block' | 'inline'; inputs: switchInputType[]; } export interface switchInputType { inputType: | INPUT_TYPE_NAMES.DROPDOWN | INPUT_TYPE_NAMES.TEXT | INPUT_TYPE_NAMES.CHECKBOX | INPUT_TYPE_NAMES.TEXTAREA | INPUT_TYPE_NAMES.RADIO | INPUT_TYPE_NAMES.CONTENTEDITOR | INPUT_TYPE_NAMES.OBJECT_MAPPER | INPUT_TYPE_NAMES.CODE_EDITOR; value?: String | boolean; label?: String; readonly?: boolean; type?: string; icon: string; mode?: string; placeholder?: string; disabled?: boolean; required?: boolean; error?: boolean; errorMessage?: string; options?: Array; customAutoCompletions?: any; helperText?: string; multiple?: boolean; noborder?: boolean; multiLine?: boolean; expand?: boolean; updateValue?: false; } export enum POSITIONS { INLINE = 'inline', BLOCK = 'block', } export enum INPUT_TYPE { DEFAULT = 'defaultInput', SWITCH = 'switchInput', } export enum INPUT_TYPE_NAMES { DROPDOWN = 'dropdown', TEXT = 'text', CHECKBOX = 'checkbox', TEXTAREA = 'text-area', RADIO = 'radio', CONTENTEDITOR = 'content-editor', OBJECT_MAPPER = 'object-mapper', CODE_EDITOR = 'code-editor', } export enum MODE { CREATE = 'create', EDIT = 'edit', } @customElement('nile-switcher') export class NileSwitcher extends NileElement { /** * The styles for nile switcher * @remarks If you are extending this class you can extend the base styles with super. Eg `return [super(), myCustomStyles]` */ static styles: CSSResultGroup = styles; private readonly hasSlotController = new HasSlotController(this, 'label'); @property({ type: Object }) nileSwitchConfig: switchconfig; @property({ type: Number }) current: Number = 0; @property({ type: Object }) currentInput: switchInputType; connectedCallback() { super.connectedCallback(); this.emit('nile-init'); } @watch(['current'], { waitUntilFirstUpdate: true }) handleSwitcherChange() { this.setCurrentInput(); } setCurrentInput() { if (this.nileSwitchConfig?.inputs) { this.currentInput = this.nileSwitchConfig.inputs.filter( (input: switchInputType, index: Number) => { return index === this.current; } )[0]; } } disconnectedCallback() { super.disconnectedCallback(); this.emit('nile-destroy'); } renderNileText(Input: switchInputType) { const { value, label, placeholder, disabled, required, error, errorMessage, inputType, noborder, } = Input; return html` { this.handleChange(e, inputType); }} >`; } renderDropdown(Input: switchInputType) { const { options, multiple, placeholder, disabled, value, error, errorMessage, inputType, noborder, } = Input; return html` { this.handleChange(e, inputType); }} > ${options?.map((option: any) => { return html`${option} `; })} `; } renderNileTextArea(Input: switchInputType) { const { value, disabled, readonly, errorMessage, error, inputType } = Input; return html` { this.handleChange(e, inputType); }} >`; } renderNileCheckBox(Input: switchInputType) { const { value, label, disabled, inputType } = Input; return html` { this.handleChange(e, inputType); }} >; `; } renderNileRadio(Input: switchInputType) { const { options, value, disabled, errorMessage, inputType } = Input; const haserrorMessage = !!errorMessage; return html` { this.handleChange(e, inputType); }} > ${options && options.map((option: any) => { return html`${option} `; })} ${haserrorMessage ? this.renderErrorMessage(errorMessage) : ''} `; } renderErrorMessage(errorMessage: string) { return html` ${errorMessage} `; } renderContentEditor(Input: switchInputType) { let { options, inputType, errorMessage, type, readonly, noborder, value, updateValue, } = Input; return html` { this.handleChange(e, inputType); }} > `; } renderObjectMapper(Input: switchInputType) { let { options, inputType, error, errorMessage, type, readonly, noborder } = Input; const value = this.currentInput.mode === MODE.CREATE ? 'Click to Create - Not Mapped' : 'Click to Edit'; return html` `; } renderCodeEditor(Input: switchInputType) { const { value, multiLine, customAutoCompletions, disabled, readonly, errorMessage, error, inputType, noborder, expand, updateValue, } = Input; return html` `; } handleExpand(event: CustomEvent, inputType: string) { this.currentInput.expand = event.detail.expand; this.emit('nile-change', { input: this.currentInput }); } handleChange(event: CustomEvent, inputType: string) { switch (inputType) { case INPUT_TYPE_NAMES.OBJECT_MAPPER: this.currentInput.value = 'clicked'; break; case INPUT_TYPE_NAMES.CHECKBOX: this.currentInput.value = event.detail.checked; break; case INPUT_TYPE_NAMES.CODE_EDITOR: this.currentInput.value = event.detail.value; break; default: this.currentInput.value = event.detail.value; } event.stopPropagation(); this.emit('nile-change', { input: this.currentInput }); } renderIcon() { const inputs = this.nileSwitchConfig.inputs; const toolTipPosition = this.nileSwitchConfig.align === POSITIONS.BLOCK ? 'top' : 'bottom'; return html`
${repeat( inputs, (input: any, index: number) => html`
this.toggleField(input, index)} >
` )}
`; } isToggleSwitch = (item: any) => { return typeof item === 'undefined' || item; }; toggleField(currentInput: switchInputType, index: Number) { this.emit('nile-switch', { inputClicked: index, currentInput: currentInput, }); } singleFieldSwitcher() { this.setCurrentInput(); return html` ${choose( this.currentInput.inputType, [ [INPUT_TYPE_NAMES.TEXT, () => this.renderNileText(this.currentInput)], [ INPUT_TYPE_NAMES.CHECKBOX, () => this.renderNileCheckBox(this.currentInput), ], [ INPUT_TYPE_NAMES.TEXTAREA, () => this.renderNileTextArea(this.currentInput), ], [ INPUT_TYPE_NAMES.RADIO, () => this.renderNileRadio(this.currentInput), ], [ INPUT_TYPE_NAMES.DROPDOWN, () => this.renderDropdown(this.currentInput), ], [ INPUT_TYPE_NAMES.CONTENTEDITOR, () => this.renderContentEditor(this.currentInput), ], [ INPUT_TYPE_NAMES.OBJECT_MAPPER, () => this.renderObjectMapper(this.currentInput), ], [ INPUT_TYPE_NAMES.CODE_EDITOR, () => this.renderCodeEditor(this.currentInput), ], ], () => this.renderNileText(this.currentInput) )} `; } public render(): TemplateResult { const hasLabelSlot = this.hasSlotController.test('label'); const align = this.nileSwitchConfig.align; const disable = this.nileSwitchConfig.disable; return html`
${hasLabelSlot ? html`
` : ''} ${!disable ? html`${this.renderIcon()}` : ''}
${this.singleFieldSwitcher()}
`; } } export default NileSwitcher; declare global { interface HTMLElementTagNameMap { 'nile-switcher': NileSwitcher; } }