UNPKG

@arcgis/coding-components

Version:

Contains components for editing code in different languages. The currently supported languages are html, css, json, TypeScript, JavaScript, and Arcade.

261 lines (260 loc) • 15.4 kB
import { g as u, c as g } from "../../chunks/runtime.js"; import { html as t, nothing as r } from "lit"; import { KeyCode as _ } from "monaco-editor"; import "monaco-editor/esm/vs/editor/standalone/browser/standaloneServices.js"; import "monaco-editor/esm/vs/editor/standalone/common/standaloneTheme.js"; import "monaco-editor/esm/vs/editor/common/languages/supports/tokenization.js"; import { LitElement as m, createEvent as c, noShadowRoot as f } from "@arcgis/lumina"; import { Deferred as x, generateGuid as b } from "@arcgis/components-utils"; import { D as v, e as l } from "../../chunks/arcade-executor.js"; import { s as P, a as w } from "../../chunks/arcade-service-accessors.js"; import { b as s } from "../../chunks/arcade-defaults.js"; import { u as E } from "../../chunks/useT9n.js"; import { createRef as S, ref as A } from "lit-html/directives/ref.js"; import { css as $ } from "@lit/reactive-element/css-tag.js"; /*! All material copyright Esri, All Rights Reserved, unless otherwise specified. See https://js.arcgis.com/4.32/esri/copyright.txt for details. v4.32.13 */ const y = (n) => { if (!n.toString().includes("calcite-flow-item")) throw new Error("Renderer must return a JSX node that starts with <calcite-flow-item>"); return !0; }, D = $`@layer{arcgis-arcade-editor{display:flex;flex-direction:column;position:relative;overflow:hidden;border:var(--arcgis-coding-components-border);box-sizing:border-box;background-color:var(--arcgis-coding-components-background-color);height:100%;.flex-adjustable{flex:1 1 auto;overflow:hidden}.flex-panel{flex:1 0 auto}.position-relative{position:relative}.flex-row{display:flex;flex-direction:row;overflow:hidden}.flex-column{display:flex;flex-direction:column;overflow:hidden}.border-inline-start{border-inline-start:var(--arcgis-coding-components-border);box-sizing:border-box}.border-inline-end{border-inline-end:var(--arcgis-coding-components-border);box-sizing:border-box}.sticky{position:sticky;top:0;z-index:10}.notice-container{margin:var(--calcite-spacing-xxs);padding:var(--calcite-spacing-sm);background-color:var(--calcite-color-foreground-1);text-align:center}.side-action-bar{max-width:var(--arcgis-coding-components-side-action-bar-max-w)}.side-panel{max-width:var(--arcgis-coding-components-side-panel-max-w);width:var(--arcgis-coding-components-side-panel-w);calcite-flow{height:100%}}.main-action-bar{border-bottom:var(--arcgis-coding-components-border);flex:0 0 auto;calcite-action-group{padding-inline-end:var(--calcite-spacing-sm);calcite-action{padding-inline-end:var(--calcite-spacing-sm)}calcite-action:not(:first-child){padding-inline-start:var(--calcite-spacing-sm)}}calcite-action-group:last-child{border-inline-end-width:0px}calcite-action-group:not(:first-child){padding-inline-start:var(--calcite-spacing-sm)}}arcgis-arcade-results{border-top:var(--arcgis-coding-components-border);box-sizing:border-box;max-height:50%;min-height:50%;margin-bottom:-1px}calcite-flow{[slot=footer]{word-break:break-word}}}}`; class C extends m { constructor() { super(...arguments), this._codeEditorElt = S(), this._componentReadyDefer = new x(), this._disposables = [], this._editorProfilePromise = Promise.resolve(void 0), this.messages = E(), this._modelId = b(), this._openArcadeHelp = () => void window.open(v, "Arcade Help"), this._toggleSidePanel = (e) => { if (!e.target) return; const i = e.target?.dataset.panelName ?? "none"; this.openedSidePanel = i === this.openedSidePanel ? "none" : i, this.openedSidePanel === "none" && this._codeEditorElt.value?.setFocus().catch(console.error); }, this._consoleLogs = [], this._executingScript = !1, this._preparingArcade = !1, this._resultPanel = "output", this._showExecutionPanel = !1, this.hideDocumentationActions = !1, this.hideSideBar = !1, this.openedSidePanel = "none", this.script = "", this.sideActionBarExpanded = !1, this.arcgisDiagnosticsChange = c({ bubbles: !1 }), this.arcgisScriptChange = c({ bubbles: !1 }); } static { this.properties = { _apiLibrary: 16, _consoleLogs: 16, _editorProfile: 16, _executingScript: 16, _executionResult: 16, _preparingArcade: 16, _resultPanel: 16, _showExecutionPanel: 16, editorInstance: 32, editorOptions: 0, hideDocumentationActions: 5, hideSideBar: 5, openedSidePanel: 2, profile: 0, script: 1, sideActionBarExpanded: 7, snippets: 0, suggestions: 0, testData: 0, customPanels: 0 }; } static { this.shadowRootOptions = f; } static { this.styles = D; } // #endregion // #region Public Properties /** * The instance of the Monaco Editor after the component has been rendered. * To determine when a component is rendered, you can use componentOnReady() method. * The method returns a Promise that resolves after the component rendered for the first time. * * @readonly * @private */ get editorInstance() { return this._codeEditorElt.value?.editorInstance; } // #endregion // #region Public Methods /** * @private * @deprecated Use `editorInstance` property instead. */ async getEditorInstance() { return await this._componentReadyDefer.promise, this._codeEditorElt.value?.editorInstance; } /** @deprecated Use `script` property instead. */ async getScript() { return await this._componentReadyDefer.promise, this._codeEditorElt.value?.value; } /** Returns the Arcade result for the script for the provided test data. */ async getTestResult() { if (!this.testData) return { type: "error", value: "Missing test data", error: null }; const e = await this._editorProfilePromise; if (!e) return { type: "error", value: "Missing editor profile", error: null }; await this._componentReadyDefer.promise; const i = this._codeEditorElt.value?.value; return await l(e.definition, i, this.testData); } /** Set the focus on the element. */ async setFocus() { await this._componentReadyDefer.promise, await this._codeEditorElt.value?.setFocus(); } // #endregion // #region Lifecycle async load() { const e = u("./assets"); P(e), await this._updateEditorProfile(); } willUpdate(e) { (e.has("messages") || e.has("profile")) && this._updateDataModelDeps(), e.has("testData") && this._testDataChanged(), e.has("snippets") && s.updateApiContextForModel(this._modelId, { snippets: this.snippets }); } /** This lifecycle method is not expected to return a promise. The returned promise will be ignored by Lit rather than awaited. */ async loaded() { this._componentReadyDefer.resolve(), await this._updateApiLibrary(); const e = await w(); this._disposables.push(e.onDiagnosticsChange((i) => !this._preparingArcade && this.arcgisDiagnosticsChange.emit(i.diagnostics))), this.testData && this._addExecuteScriptAction(), await this._codeEditorElt.value?.setFocus(); } disconnectedCallback() { for (super.disconnectedCallback(); this._disposables.length; ) this._disposables.pop()?.dispose(); } // #endregion // #region Private Methods async _updateDataModelDeps() { await this._updateEditorProfile(), await this._updateApiLibrary(); } _testDataChanged() { !this.testData && this._executeScriptAction && (this._disposeSafely(this._executeScriptAction), this._executeScriptAction = void 0), this.testData && !this._executeScriptAction && this._addExecuteScriptAction(), this._showExecutionPanel && this._executeScript().catch(console.error); } async _updateEditorProfile() { this._preparingArcade = !0; try { await s.setProfileForModel(this._modelId, this.profile, { locale: this.messages._t9nLocale, snippets: this.snippets }), this._editorProfile = s.getEditorProfileForModel(this._modelId); } catch { this._editorProfile = void 0; } finally { this._editorProfilePromise = Promise.resolve(this._editorProfile), this._preparingArcade = !1; } } async _updateApiLibrary() { this._apiLibrary = await s.getApiLibraryForModel(this._modelId); } async _executeScript() { const e = this.testData; if (!this._codeEditorElt.value || !e) return; const i = await this._editorProfilePromise; if (!i) { this._executionResult = { type: "error", value: "Missing editor profile", error: null }; return; } this._showExecutionPanel = !0, this._executingScript = !0, this._consoleLogs = [], setTimeout(() => void (async () => { const a = this._codeEditorElt.value?.value; this._executionResult = await l(i.definition, a, e, (o) => setTimeout(() => this._consoleLogs = [...this._consoleLogs, o], 0)), this._executingScript = !1; })(), 0); } _toggleShowExecutionPanel() { this._showExecutionPanel = !this._showExecutionPanel; } _toggleSideActionBarExpanded() { this.sideActionBarExpanded = !this.sideActionBarExpanded; } _onCodeEditorValueChange(e) { e.stopPropagation(), this.script = e.detail, this.arcgisScriptChange.emit(e.detail); } _insertAsSnippet(e) { this._codeEditorElt.value?.insertSnippet(e.detail).catch(console.error); } _insertAsText(e) { this._insertText(e.detail); } _insertText(e) { this._codeEditorElt.value?.insertText(e).catch(console.error); } _onResultPanelChange(e) { this._resultPanel = e.detail; } _onExecutionPanelClose() { this._showExecutionPanel = !1; } _addExecuteScriptAction() { const e = this.editorInstance?.addAction({ // An unique identifier for the action. id: "run-script", label: "Run Arcade Expression", keybindings: [_.F5], contextMenuGroupId: "code", contextMenuOrder: 1, run: () => { this.testData && this._executeScript().catch(console.error); } }); e && (this._executeScriptAction = e, this._disposables.push(e)); } // Method to safely dispose of an IDisposable _disposeSafely(e) { const i = this._disposables.indexOf(e); i !== -1 && this._disposables.splice(i, 1), e.dispose(); } // #endregion // #region Rendering renderMainActionBar() { return this.testData ? t`<calcite-action-bar class="main-action-bar" layout=horizontal scale=s expanded expand-disabled><calcite-action-group scale=s><calcite-action .text=${this.messages.run ?? ""} text-enabled icon=play scale=s .loading=${this._preparingArcade} @click=${() => void this._executeScript().catch(console.error)}></calcite-action>${this._executionResult ? t`<calcite-action .text=${this.messages.lastresults ?? ""} .active=${this._showExecutionPanel} text-enabled icon=access-string-results icon-flip-rtl scale=s @click=${this._toggleShowExecutionPanel}></calcite-action>` : null}</calcite-action-group></calcite-action-bar>` : null; } renderMainPanel() { return t`<arcgis-code-editor class="flex-adjustable" .editorOptions=${this.editorOptions} .language=${s.languageId} .value=${this.script ?? ""} .modelId=${this._modelId} @arcgisValueChange=${this._onCodeEditorValueChange} ${A(this._codeEditorElt)}></arcgis-code-editor>`; } renderAction({ id: e, label: i, icon: a, active: o, panelName: d, iconFlipRtl: h = !1, onClick: p = this._toggleSidePanel }) { return t`<calcite-action id=${e ?? r} .text=${i} .textEnabled=${this.sideActionBarExpanded} .icon=${a} .active=${o} @click=${p} data-panel-name=${d ?? r} .iconFlipRtl=${h}></calcite-action>${!this.sideActionBarExpanded && t`<calcite-tooltip .referenceElement=${e}><span>${i}</span></calcite-tooltip>` || ""}`; } renderSideActionBar() { return this.hideSideBar ? null : t`<calcite-action-bar class="side-action-bar border-inline-start" .expanded=${!!this.sideActionBarExpanded} position=end @calciteActionBarToggle=${this._toggleSideActionBarExpanded}><calcite-action-group>${this.renderAction({ id: "profile-variables-action", label: this.messages.profilevariables ?? "", icon: "profile-variables", active: this.openedSidePanel === "variables", panelName: "variables" })}${this.renderAction({ id: "function-action", label: this.messages.constantsandfunctions ?? "", icon: "function", active: this.openedSidePanel === "api", panelName: "api" })}${this.suggestions?.length ? this.renderAction({ id: "suggestions-action", label: this.messages.suggestions ?? "", icon: "lightbulb", active: this.openedSidePanel === "suggestions", panelName: "suggestions" }) : null}${this.customPanels?.map((e) => this.renderAction({ id: e.id, label: e.name, icon: e.icon, active: this.openedSidePanel === e.id, panelName: e.id }))}${this.hideDocumentationActions ? null : this.renderAction({ id: "developer-website-action", label: this.messages.help ?? "", icon: "question", active: !1, panelName: "none", iconFlipRtl: this.messages._lang === "ar", onClick: this._openArcadeHelp })}</calcite-action-group></calcite-action-bar>`; } renderSidePanel() { if (this.hideSideBar) return null; switch (this.openedSidePanel) { case "api": return t`<arcgis-language-api-panel class="side-panel flex-panel border-inline-start" .loading=${this._preparingArcade} .apiLibrary=${this._apiLibrary} .hideDocumentationActions=${this.hideDocumentationActions} @arcgisItemSelected=${this._insertAsSnippet} @arcgisClose=${this._toggleSidePanel} data-panel-name=none></arcgis-language-api-panel>`; case "variables": return t`<arcgis-editor-variables class="side-panel flex-panel border-inline-start" .loading=${this._preparingArcade} .modelId=${this._modelId} @arcgisItemSelected=${this._insertAsText} @arcgisClose=${this._toggleSidePanel} data-panel-name=none .variable=${this._editorProfile}></arcgis-editor-variables>`; case "suggestions": return t`<arcgis-arcade-suggestions class="side-panel flex-panel border-inline-start" .suggestions=${this.suggestions} @arcgisItemSelected=${this._insertAsText} @arcgisClose=${this._toggleSidePanel} data-panel-name=none></arcgis-arcade-suggestions>`; case "none": return null; } const e = this.customPanels?.find((i) => i.id === this.openedSidePanel); if (e) { const i = !!e?.useFlows; return t`<calcite-flow class="side-panel flex-panel border-inline-start">${i && y(e.renderer) ? e.renderer({ closePanel: this._toggleSidePanel, insertText: this._insertText.bind(this) }) : t`<calcite-flow-item .heading=${e.name} closable @calciteFlowItemClose=${this._toggleSidePanel} .description=${e.description}>${e.renderer({ closePanel: this._toggleSidePanel, insertText: this._insertText.bind(this) })}</calcite-flow-item>`}</calcite-flow>`; } return null; } renderResultsPanel() { return this._showExecutionPanel ? t`<arcgis-arcade-results class="flex-adjustable" .openedResultPanel=${this._resultPanel} .loading=${this._executingScript} .result=${this._executionResult} .consoleLogs=${this._consoleLogs} @arcgisOpenedResultPanelChange=${this._onResultPanelChange} @arcgisClose=${this._onExecutionPanelClose}></arcgis-arcade-results>` : null; } render() { return t`${this.renderMainActionBar()}<div class="flex-row flex-adjustable"><div class="flex-column flex-adjustable">${this.renderMainPanel()}${this.renderResultsPanel()}</div>${this.renderSidePanel()}${this.renderSideActionBar()}</div>`; } } g("arcgis-arcade-editor", C); export { C as ArcgisArcadeEditor };