kempo-ui 0.3.10 → 0.3.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Aside.js +41 -19
- package/dist/components/Dropdown.js +2 -2
- package/dist/components/HtmlEditor.js +15 -15
- package/docs/components/dropdown.html +24 -0
- package/docs/src/components/Aside.js +41 -19
- package/docs/src/components/Dropdown.js +2 -2
- package/docs/src/components/HtmlEditor.js +15 -15
- package/docs-src/.config.js +10 -0
- package/docs-src/components/dropdown.page.html +24 -0
- package/package.json +1 -1
- package/src/components/Aside.js +53 -20
- package/src/components/Dropdown.js +19 -1
- package/src/components/HtmlEditor.js +24 -29
- package/tests/components/Aside.browser-test.js +141 -0
- package/tests/components/Dropdown.browser-test.js +61 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{html as e,css as t}from"../lit-all.min.js";import i from"./ShadowComponent.js";import o from"../utils/formatCode.js";import l from"../utils/debounce.js";import{getCalculatedTheme as r,subscribeToTheme as s}from"../utils/theme.js";import a from"./Dialog.js";export default class c extends i{static formAssociated=!0;static properties={name:{type:String,reflect:!0},value:{type:String,reflect:!0},selection:{type:Object,state:!0},mode:{type:String,reflect:!0},controls:{type:String,reflect:!0},lexicalSrc:{type:String,attribute:"lexical-src"},monacoSrc:{type:String,attribute:"monaco-src"},nodes:{type:String},hasTopToolbar:{type:Boolean,state:!0},hasBottomToolbar:{type:Boolean,state:!0},fullscreen:{type:Boolean,reflect:!0}};constructor(){super(),this.internals=this.attachInternals(),this.name="",this.value="",this.selection=null,this.cursor=null,this.mode="visual",this.controls="",this.controlsLoaded=!1,this.lexicalSrc="",this.monacoSrc="",this.nodes="",this.hasTopToolbar=!1,this.hasBottomToolbar=!1,this.skipValueSync=!1,this.lexicalValueSync=!1,this.savedSelection=null,this.lexicalEditor=null,this.monacoEditor=null,this.editorTheme="auto",this.wordWrap=!0,this.minimapEnabled=!1,this.fontSize=14,this.fullscreen=!1,this.lx={},this.debouncedSyncValue=l(()=>this.syncValueFromLexical(),300)}connectedCallback(){super.connectedCallback(),this.hasAttribute("value")&&(this.value=this.getAttribute("value")),this.slotObserver=new MutationObserver(()=>this.updateToolbarVisibility()),this.slotObserver.observe(this,{childList:!0,subtree:!0}),this.updateToolbarVisibility()}disconnectedCallback(){super.disconnectedCallback(),this.slotObserver?.disconnect(),this.cleanupFns?.forEach(e=>e?.()),this.monacoEditor?.dispose(),this.unsubscribeTheme?.(),this.syncShadowSelection&&document.removeEventListener("selectionchange",this.syncShadowSelection),this.fullscreen&&this.exitFullscreen()}updateToolbarVisibility(){const e=new Set(Array.from(this.children).map(e=>e.getAttribute("slot"))),t=this.constructor.controlSets[this.controls]??null;this.hasTopToolbar=!(!t?.topLeft&&!t?.topRight)||["toolbar-top","toolbar-top-left","toolbar-top-right"].some(t=>e.has(t)),this.hasBottomToolbar=!(!t?.bottomLeft&&!t?.bottomRight)||["toolbar-bottom","toolbar-bottom-left","toolbar-bottom-right"].some(t=>e.has(t))}updated(e){if(super.updated(e),e.has("controls")&&(this.updateToolbarVisibility(),this.controls&&"none"!==this.controls&&this.loadControls()),e.has("value")&&!this.skipValueSync&&(this.lexicalValueSync?this.lexicalValueSync=!1:this.lexicalEditor&&"visual"===this.mode&&!this.isVisualCompatible(this.value)?(this.skipLexicalExport=!0,this.mode="code"):this.syncContentToEditors(),this.updateFormValue(),this.dispatchEvent(new CustomEvent("change",{detail:{value:this.value},bubbles:!0}))),e.has("mode")){const t=window.scrollY;this.handleModeSwitch(e.get("mode")),this.dispatchEvent(new CustomEvent("mode-changed",{detail:{mode:this.mode},bubbles:!0})),requestAnimationFrame(()=>window.scrollTo(0,t))}e.has("fullscreen")&&requestAnimationFrame(()=>this.monacoEditor?.layout())}async firstUpdated(){this.lexicalContainer=this.shadowRoot.querySelector(".lexical-editor"),this.monacoContainer=this.shadowRoot.querySelector(".monaco-editor-container"),await this.initLexical(),this.dispatchEvent(new CustomEvent("ready",{detail:{value:this.value},bubbles:!0}))}async loadControls(){if(this.controlsLoaded)return;this.controlsLoaded=!0;const e=new URL("./htmlEditorControls/",import.meta.url).href;await Promise.all([import(`${e}Bold.js`),import(`${e}Italic.js`),import(`${e}Underline.js`),import(`${e}Strikethrough.js`),import(`${e}InlineCode.js`),import(`${e}DropdownControl.js`),import(`${e}FormatBlock.js`),import(`${e}CodeBlock.js`),import(`${e}BulletList.js`),import(`${e}NumberList.js`),import(`${e}AlignLeft.js`),import(`${e}AlignCenter.js`),import(`${e}AlignRight.js`),import(`${e}AlignJustify.js`),import(`${e}TextColor.js`),import(`${e}TextBackgroundColor.js`),import(`${e}ClearFormatting.js`),import(`${e}CreateLink.js`),import(`${e}InsertTable.js`),import(`${e}ControlGroup.js`),import(`${e}ControlSpacer.js`),import(`${e}Mode.js`),import(`${e}WordCount.js`),import(`${e}CharacterCount.js`)]);const t=new URL("./codeEditorControls/",import.meta.url).href;await Promise.all([import(`${t}FormatCode.js`),import(`${t}CopyCode.js`),import(`${t}Undo.js`),import(`${t}Redo.js`),import(`${t}WordWrap.js`),import(`${t}Minimap.js`),import(`${t}FindReplace.js`),import(`${t}FontSize.js`),import(`${t}FoldAll.js`),import(`${t}EditorTheme.js`),import(`${t}Fullscreen.js`),import(`${t}ControlGroup.js`)]),this.requestUpdate()}async loadNodeModules(){if(!this.nodes?.trim())return[];const e=new URL("./htmlEditorNodes/",import.meta.url).href;return(await Promise.all(this.nodes.split(",").map(e=>e.trim()).filter(Boolean).map(t=>import(`${e}${t}.js`)))).map(e=>e.default?.lexicalNode).filter(Boolean)}async loadLexicalModules(){const e=this.lexicalSrc||window.kempo?.lexicalUrl||"https://esm.sh",t=t=>((e,t)=>`${e}/${t}@0.43.0`)(e,t),[i,o,l,r,s,a,c,n,h]=await Promise.all([import(t("lexical")),import(t("@lexical/rich-text")),import(t("@lexical/html")),import(t("@lexical/history")),import(t("@lexical/list")),import(t("@lexical/link")),import(t("@lexical/selection")),import(t("@lexical/table")),import(t("@lexical/code"))]);this.lx={lexical:i,richText:o,lexicalHtml:l,history:r,list:s,link:a,selection:c,table:n,code:h},this.StyledTextNode=class extends i.TextNode{static getType(){return"styled-text"}static clone(e){return new this(e.__text,e.__key)}static importDOM(){return{span:()=>({conversion:e=>{const t=e.getAttribute("style");if(!t)return null;const o=i.$createTextNode(e.textContent);return o.setStyle(t),{node:o}},priority:1})}}static importJSON(e){return i.$createTextNode(e.text)}exportJSON(){return{...super.exportJSON(),type:"styled-text"}}}}async initLexical(){await this.loadLexicalModules(),this.customNodes=await this.loadNodeModules(),this.nodeCompatCheckers=this.customNodes.filter(e=>"function"==typeof e.isVisualCompatible).map(e=>e.isVisualCompatible),this.nodePreprocessors=this.customNodes.filter(e=>"function"==typeof e.preprocessHtml).map(e=>e.preprocessHtml);const{lexical:e,richText:t,history:i,list:o,link:l,table:r,code:s}=this.lx,a={namespace:"KempoHtmlEditor",theme:{paragraph:"k-editor-p",heading:{h1:"k-editor-h1",h2:"k-editor-h2",h3:"k-editor-h3",h4:"k-editor-h4",h5:"k-editor-h5",h6:"k-editor-h6"},text:{underline:"td-u",strikethrough:"td-lt"},list:{ul:"k-editor-ul",ol:"k-editor-ol",listitem:"k-editor-li"},link:"k-editor-link",quote:"k-editor-quote",code:"k-editor-code-block",codeHighlight:{},table:"k-editor-table",tableCell:"k-editor-table-cell",tableCellHeader:"k-editor-table-cell-header"},nodes:[t.HeadingNode,t.QuoteNode,o.ListNode,o.ListItemNode,l.LinkNode,r.TableNode,r.TableCellNode,r.TableRowNode,s.CodeNode,s.CodeHighlightNode,this.StyledTextNode,...this.customNodes],onError:console.error,editorState:null};this.lexicalEditor=e.createEditor(a),this.lexicalEditor.setRootElement(this.lexicalContainer),this.cleanupFns=[t.registerRichText(this.lexicalEditor),i.registerHistory(this.lexicalEditor,i.createEmptyHistoryState(),300)],o.registerList&&this.cleanupFns.push(o.registerList(this.lexicalEditor)),r.registerTable&&this.cleanupFns.push(r.registerTable(this.lexicalEditor)),s.registerCodeHighlighting&&this.cleanupFns.push(s.registerCodeHighlighting(this.lexicalEditor)),l.registerLink&&this.cleanupFns.push(l.registerLink(this.lexicalEditor,{validateUrl:e=>{try{return new URL(e),!0}catch{return!1}}})),this.value&&(this.isVisualCompatible(this.value)?this.importHtmlToLexical(this.value):(this.skipLexicalExport=!0,this.mode="code")),this.lexicalEditor.registerUpdateListener(({dirtyElements:e,dirtyLeaves:t})=>{0===e.size&&0===t.size||(this.debouncedSyncValue(),this.dispatchEvent(new CustomEvent("input",{detail:{value:this.exportHtmlFromLexical()},bubbles:!0})))}),this.lexicalEditor.registerCommand(e.SELECTION_CHANGE_COMMAND,()=>(this.updateSelection(),!1),e.COMMAND_PRIORITY_LOW),this.syncShadowSelection=()=>{if("visual"!==this.mode||!this.lexicalEditor)return;const t=this.shadowRoot.getSelection?.();if(!t||0===t.rangeCount)return;const i=t.getRangeAt(0);this.lexicalContainer.contains(i.startContainer)&&(this.lexicalEditor.update(()=>{const i=e.$createRangeSelectionFromDom(t,this.lexicalEditor);i&&e.$setSelection(i)},{discrete:!0}),this.updateSelection())},document.addEventListener("selectionchange",this.syncShadowSelection)}async initMonaco(){if(!this.monacoEditor){if(this.monacoInitPromise)return this.monacoInitPromise;this.monacoInitPromise=this._initMonaco(),await this.monacoInitPromise,this.monacoInitPromise=null}}async _initMonaco(){const e=this.monacoSrc||window.kempo?.monacoUrl||"https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min";await new Promise((t,i)=>{if(window.monaco)return void t();if(window.require?.defined?.("vs/editor/editor.main"))return void t();const o=document.querySelector(`script[src="${e}/vs/loader.js"]`);if(o)return void o.addEventListener("load",()=>{window.require.config({paths:{vs:`${e}/vs`}}),window.require(["vs/editor/editor.main"],()=>t(),i)});const l=document.createElement("script");l.src=`${e}/vs/loader.js`,l.onload=()=>{window.require.config({paths:{vs:`${e}/vs`}}),window.require(["vs/editor/editor.main"],()=>t(),i)},l.onerror=i,document.head.appendChild(l)}),this.monacoEditor=window.monaco.editor.create(this.monacoContainer,{value:o(this.value),language:"html",theme:this.resolveMonacoTheme(),minimap:{enabled:this.minimapEnabled},wordWrap:this.wordWrap?"on":"off",fontSize:this.fontSize,scrollBeyondLastLine:!1,automaticLayout:!0,tabSize:2,padding:{top:8}});const t=document.querySelector('link[href*="monaco"][href*="editor.main.css"]');if(t){const e=document.createElement("link");e.rel="stylesheet",e.href=t.href,this.shadowRoot.appendChild(e)}this.unsubscribeTheme=s(()=>{this.monacoEditor&&"auto"===this.editorTheme&&window.monaco.editor.setTheme(this.resolveMonacoTheme())}),this.monacoEditor.onDidChangeModelContent(()=>{this.skipValueSync=!0,this.value=this.monacoEditor.getValue(),this.skipValueSync=!1,this.updateFormValue(),this.dispatchEvent(new CustomEvent("change",{detail:{value:this.value},bubbles:!0})),this.dispatchEvent(new CustomEvent("input",{detail:{value:this.value},bubbles:!0}))})}importHtmlToLexical(e){if(!this.lexicalEditor||!this.lx.lexicalHtml)return;const{lexical:t,lexicalHtml:i}=this.lx,o=(this.nodePreprocessors||[]).reduce((e,t)=>t(e),e);this.lexicalEditor.update(()=>{if(t.$getRoot().clear(),!o?.trim())return;const e=(new DOMParser).parseFromString(o,"text/html"),l=i.$generateNodesFromDOM(this.lexicalEditor,e);l.length>0&&t.$insertNodes(l)},{discrete:!0})}exportHtmlFromLexical(){if(!this.lexicalEditor||!this.lx.lexicalHtml)return this.value;let e="";return this.lexicalEditor.getEditorState().read(()=>{e=this.lx.lexicalHtml.$generateHtmlFromNodes(this.lexicalEditor,null)}),this.cleanExportedHtml(e)}isVisualCompatible(e){if(!e?.trim())return!0;const t=new Set(["script","style","meta","link","head","iframe","object","embed","canvas","video","audio","form","input","button","select","textarea","fieldset","label","noscript","template","slot","svg","math"]),i=this.nodeCompatCheckers||[],o=(new DOMParser).parseFromString(e,"text/html"),l=document.createTreeWalker(o.body,NodeFilter.SHOW_ELEMENT|NodeFilter.SHOW_COMMENT);let r;for(;r=l.nextNode();)if(!i.some(e=>e(r))){if(r.nodeType===Node.COMMENT_NODE)return!1;if(t.has(r.tagName?.toLowerCase()))return!1}return!0}cleanExportedHtml(e){const t=(new DOMParser).parseFromString(e,"text/html");return t.body.querySelectorAll("[class]").forEach(e=>{const t=Array.from(e.classList).filter(e=>!e.startsWith("k-editor-")&&"td-u"!==e&&"td-lt"!==e);0===t.length?e.removeAttribute("class"):e.className=t.join(" ")}),t.body.querySelectorAll("[style]").forEach(e=>{const t=e.style.cssText.replace(/white-space:\s*pre-wrap;?\s*/g,"").trim();t?e.style.cssText=t:e.removeAttribute("style")}),t.body.querySelectorAll("span:not([class]):not([style]):not([id])").forEach(e=>{e.attributes.length||e.replaceWith(...e.childNodes)}),t.body.querySelectorAll("b > strong, i > em, b > b, strong > strong, i > i, em > em").forEach(e=>{e.replaceWith(...e.childNodes)}),t.body.querySelectorAll("pre[data-highlight-language], code[data-highlight-language]").forEach(e=>{e.removeAttribute("data-highlight-language"),e.removeAttribute("data-language")}),t.body.innerHTML}syncValueFromLexical(){this.lexicalEditor&&(this.lexicalValueSync=!0,this.value=this.exportHtmlFromLexical(),this.updateFormValue())}syncContentToEditors(){"visual"===this.mode&&this.lexicalEditor&&this.importHtmlToLexical(this.value)}async handleModeSwitch(e){"code"===this.mode?(this.lexicalEditor&&!this.skipLexicalExport&&(this.value=this.exportHtmlFromLexical()),this.skipLexicalExport=!1,await this.initMonaco(),this.monacoEditor&&(this.monacoEditor.setValue(o(this.value)),this.monacoEditor.layout())):"visual"===this.mode&&(this.monacoEditor&&(this.value=this.monacoEditor.getValue()),this.lexicalEditor&&this.importHtmlToLexical(this.value)),this.requestUpdate()}updateFormValue(){this.internals.setFormValue(this.getValue())}formResetCallback(){this.value=""}formStateRestoreCallback(e){this.value=e}updateSelection=()=>{if("visual"!==this.mode||!this.lexicalEditor)return void(this.selection=null);const{lexical:e}=this.lx;this.lexicalEditor.getEditorState().read(()=>{const t=e.$getSelection();e.$isRangeSelection(t)&&!t.isCollapsed()?this.selection={text:t.getTextContent(),collapsed:!1}:(this.selection=null,this.cursor=t?{anchor:t.anchor,focus:t.focus}:null)})};setMode(e){return["visual","code"].includes(e)?"visual"!==e||this.isVisualCompatible(this.getValue())?(this.mode=e,this):(a.confirm("This html contains code that is not compatible with the visual editor, the incompatible code will be lost",t=>{t&&(this.mode=e)},{title:"Warning",confirmText:"Change Anyways"}),this):this}toggleMode(){return this.setMode("visual"===this.mode?"code":"visual")}getValue(){if("visual"===this.mode&&this.lexicalEditor)this.skipValueSync=!0,this.value=this.exportHtmlFromLexical(),this.skipValueSync=!1;else if("code"===this.mode&&this.monacoEditor)return this.monacoEditor.getValue();return this.value}setValue(e){return this.lexicalEditor&&"visual"===this.mode&&!this.isVisualCompatible(e)?(this.value=e,this.skipLexicalExport=!0,this.mode="code",this.updateFormValue(),this):(this.skipValueSync=!0,this.value=e,"visual"===this.mode?this.syncContentToEditors():"code"===this.mode&&this.monacoEditor&&this.monacoEditor.setValue(o(e)),this.updateFormValue(),this.skipValueSync=!1,this)}clear(){return this.setValue("")}bold(){return this.lexicalFormat("bold"),this}italic(){return this.lexicalFormat("italic"),this}underline(){return this.lexicalFormat("underline"),this}strikethrough(){return this.lexicalFormat("strikethrough"),this}inlineCode(){return this.lexicalFormat("code"),this}orderedList(){return"visual"===this.mode&&this.lexicalEditor?(this.lexicalEditor.update(()=>{this.lx.list.$insertList("number")},{discrete:!0}),this):this}unorderedList(){return"visual"===this.mode&&this.lexicalEditor?(this.lexicalEditor.update(()=>{this.lx.list.$insertList("bullet")},{discrete:!0}),this):this}alignLeft(){return this.lexicalFormatElement("left"),this}alignCenter(){return this.lexicalFormatElement("center"),this}alignRight(){return this.lexicalFormatElement("right"),this}alignJustify(){return this.lexicalFormatElement("justify"),this}setTextColor(e){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:t,selection:i}=this.lx;return this.lexicalEditor.update(()=>{const o=t.$getSelection();t.$isRangeSelection(o)&&i.$patchStyleText(o,{color:e})},{discrete:!0}),this}removeTextColor(){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:e,selection:t}=this.lx;return this.lexicalEditor.update(()=>{const i=e.$getSelection();e.$isRangeSelection(i)&&t.$patchStyleText(i,{color:null})},{discrete:!0}),this}setTextBackgroundColor(e){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:t,selection:i}=this.lx;return this.lexicalEditor.update(()=>{const o=t.$getSelection();t.$isRangeSelection(o)&&i.$patchStyleText(o,{"background-color":e})},{discrete:!0}),this}removeTextBackgroundColor(){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:e,selection:t}=this.lx;return this.lexicalEditor.update(()=>{const i=e.$getSelection();e.$isRangeSelection(i)&&t.$patchStyleText(i,{"background-color":null})},{discrete:!0}),this}removeFormat(){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:e,selection:t}=this.lx;return this.lexicalEditor.update(()=>{const i=e.$getSelection();e.$isRangeSelection(i)&&(i.getNodes().forEach(t=>{e.$isTextNode(t)&&t.setFormat(0)}),t.$patchStyleText(i,{color:null,"background-color":null}))},{discrete:!0}),this}formatBlock(e){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:t,richText:i,code:o}=this.lx;return this.lexicalEditor.update(()=>{const l=t.$getSelection();if(!t.$isRangeSelection(l))return;const r=l.anchor.getNode().getTopLevelElementOrThrow(),s=o.$isCodeNode(r);let a;if("p"===e)a=t.$createParagraphNode();else if(e.match(/^h[1-6]$/))a=i.$createHeadingNode(e);else if("blockquote"===e)a=i.$createQuoteNode();else{if("pre"!==e)return;a=o.$createCodeNode()}if(s&&"pre"!==e){const e=r.getTextContent();r.replace(a),a.append(t.$createTextNode(e))}else{const e=r.getChildren();r.replace(a),e.forEach(e=>a.append(e))}a.selectEnd()},{discrete:!0}),this}isSelectionInCodeBlock(){if("visual"!==this.mode||!this.lexicalEditor)return!1;let e=!1;const{lexical:t,code:i}=this.lx;return this.lexicalEditor.getEditorState().read(()=>{const o=t.$getSelection();t.$isRangeSelection(o)&&(e=i.$isCodeNode(o.anchor.getNode().getTopLevelElementOrThrow()))}),e}getTableAtSelection(){if("visual"!==this.mode||!this.lexicalEditor)return null;let e=null;const{lexical:t,table:i}=this.lx;return this.lexicalEditor.getEditorState().read(()=>{const o=t.$getSelection();if(!t.$isRangeSelection(o))return;let l=o.anchor.getNode();for(;l;){if(i.$isTableNode(l)){const t=l.getChildren(),o=[];let r=!1,s=0;t.forEach((e,t)=>{const l=[];e.getChildren().forEach(e=>{0===t&&i.$isTableCellNode(e)&&e.getHeaderStyles()===i.TableCellHeaderStates.ROW&&(r=!0),l.push(e.getTextContent())}),l.length>s&&(s=l.length),o.push(l)}),e={key:l.getKey(),rows:r?t.length-1:t.length,cols:s,hasHeaders:r,cellData:o};break}l=l.getParent()}}),e}removeTableByKey(e){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:t}=this.lx;return this.lexicalEditor.update(()=>{const i=t.$getNodeByKey(e);i&&i.remove()},{discrete:!0}),this}insertHTML(e){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:t,lexicalHtml:i}=this.lx;return this.lexicalEditor.update(()=>{const o=(new DOMParser).parseFromString(e,"text/html"),l=i.$generateNodesFromDOM(this.lexicalEditor,o);t.$insertNodes(l)},{discrete:!0}),this}insertAtCursor(e){return this.insertHTML(e)}insertTable(e,t,i=!1,o=null){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:l,table:r}=this.lx;return this.lexicalEditor.update(()=>{const s=e+(i?1:0),a=[];for(let e=0;e<s;e++){const s=[];for(let a=0;a<t;a++){const t=i&&0===e,c=t?r.TableCellHeaderStates.ROW:r.TableCellHeaderStates.NO_STATUS,n=r.$createTableCellNode(c),h=o?.[e]?.[a]??(t?`Header ${a+1}`:""),d=l.$createParagraphNode();d.append(l.$createTextNode(h||" ")),n.append(d),s.push(n)}a.push(r.$createTableRowNode().append(...s))}const c=r.$createTableNode().append(...a),n=l.$getSelection();if(l.$isRangeSelection(n)){n.anchor.getNode().getTopLevelElementOrThrow().insertAfter(c);const e=l.$createParagraphNode();c.insertAfter(e),e.selectEnd()}else{const e=l.$getRoot();e.append(c),e.append(l.$createParagraphNode())}},{discrete:!0}),this}insertElementAtCursor(e){return this.insertHTML(e.outerHTML)}replaceSelectionWithElement(e){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:t,lexicalHtml:i}=this.lx;return this.lexicalEditor.update(()=>{const o=t.$getSelection();if(!t.$isRangeSelection(o))return;o.removeText();const l=(new DOMParser).parseFromString(e.outerHTML,"text/html"),r=i.$generateNodesFromDOM(this.lexicalEditor,l);t.$insertNodes(r)},{discrete:!0}),this}wrapSelection(e,t,i=null){if("visual"!==this.mode||!this.lexicalEditor)return this;const o=i||this.getSelectedText();return o?this.insertHTML(e+o+t):this}getSelection(){if("visual"!==this.mode||!this.lexicalEditor)return null;let e=null;const{lexical:t}=this.lx;return this.lexicalEditor.getEditorState().read(()=>{const i=t.$getSelection();t.$isRangeSelection(i)&&!i.isCollapsed()&&(e={text:i.getTextContent(),html:i.getTextContent(),selection:i})}),e}getSelectedText(){let e="";if("visual"!==this.mode||!this.lexicalEditor)return e;const{lexical:t}=this.lx;return this.lexicalEditor.getEditorState().read(()=>{const i=t.$getSelection();t.$isRangeSelection(i)&&(e=i.getTextContent())}),e}getSelectedHTML(){return this.getSelectedText()}selectAll(){if("visual"===this.mode&&this.lexicalEditor){const{lexical:e}=this.lx;this.lexicalEditor.update(()=>{e.$selectAll()},{discrete:!0})}else if(this.monacoEditor){const e=this.monacoEditor.getModel();e&&this.monacoEditor.setSelection(e.getFullModelRange())}return this}replaceSelection(e){return this.insertHTML(e)}deleteSelection(){return"visual"===this.mode?this.lexicalCmd("DELETE_CHARACTER_COMMAND",!1):this.monacoEditor&&this.monacoEditor.trigger("keyboard","deleteAllLeft",null),this}getValueWithSelectionMarkers(){if("visual"!==this.mode||!this.lexicalEditor)return{html:this.value,hasCursor:!1,hasSelection:!1,selectedText:""};let e={html:this.exportHtmlFromLexical(),hasCursor:!1,hasSelection:!1,selectedText:""};const{lexical:t}=this.lx;return this.lexicalEditor.getEditorState().read(()=>{const i=t.$getSelection();t.$isRangeSelection(i)&&(i.isCollapsed()?e.hasCursor=!0:(e.hasSelection=!0,e.selectedText=i.getTextContent()))}),e}setValueFromSelectionMarkers(e){return this.setValue(e)}captureSelection(){return this.selection}restoreSavedSelection(){return!1}clearSavedSelection(){this.savedSelection=null}createLink(e){if("visual"!==this.mode||!this.lexicalEditor)return this;const{link:t}=this.lx;return this.lexicalEditor.update(()=>{t.$toggleLink(e)},{discrete:!0}),this}createLinkWithText(e,t){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:i,link:o}=this.lx;return this.lexicalEditor.update(()=>{const l=i.$getSelection();i.$isRangeSelection(l)&&!l.isCollapsed()&&l.removeText();const r=o.$createLinkNode(e);r.append(i.$createTextNode(t)),i.$insertNodes([r])},{discrete:!0}),this}unlink(){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:e,link:t}=this.lx;return this.lexicalEditor.update(()=>{const i=e.$getSelection();e.$isRangeSelection(i)&&i.getNodes().forEach(e=>{const i=e.getParent();i&&t.$isLinkNode?.(i)&&(i.getChildren().forEach(e=>i.insertBefore(e)),i.remove())})},{discrete:!0}),this}insertImage(e){return this.insertHTML(`<img src="${encodeURI(e)}" />`)}undo(){return"code"===this.mode?this.monacoEditor?.trigger("toolbar","undo"):this.lexicalCmd("UNDO_COMMAND",void 0),this}redo(){return"code"===this.mode?this.monacoEditor?.trigger("toolbar","redo"):this.lexicalCmd("REDO_COMMAND",void 0),this}copyToClipboard(){return navigator.clipboard.writeText(this.getValue()),this}setEditorTheme(e){return["auto","light","dark"].includes(e)&&(this.editorTheme=e),this.monacoEditor&&window.monaco.editor.setTheme(this.resolveMonacoTheme()),this}openFind(){return this.monacoEditor?.getAction("actions.find")?.run(),this}foldAll(){return this.monacoEditor?.getAction("editor.foldAll")?.run(),this}unfoldAll(){return this.monacoEditor?.getAction("editor.unfoldAll")?.run(),this}enterFullscreen(){return this.fullscreen=!0,document.body.classList.add("no-scroll"),this.dispatchEvent(new CustomEvent("fullscreen-changed",{detail:{fullscreen:!0},bubbles:!0})),this}exitFullscreen(){return this.fullscreen=!1,document.body.classList.remove("no-scroll"),this.dispatchEvent(new CustomEvent("fullscreen-changed",{detail:{fullscreen:!1},bubbles:!0})),this}toggleFullscreen(){return this.fullscreen?this.exitFullscreen():this.enterFullscreen()}increaseFontSize(){return this.fontSize=Math.min(this.fontSize+2,40),this.monacoEditor?.updateOptions({fontSize:this.fontSize}),this}decreaseFontSize(){return this.fontSize=Math.max(this.fontSize-2,8),this.monacoEditor?.updateOptions({fontSize:this.fontSize}),this}setWordWrap(e){return this.wordWrap=e,this.monacoEditor?.updateOptions({wordWrap:e?"on":"off"}),this}setMinimap(e){return this.minimapEnabled=e,this.monacoEditor?.updateOptions({minimap:{enabled:e}}),this}resolveMonacoTheme(){return"dark"===this.editorTheme?"vs-dark":"light"===this.editorTheme?"vs":"dark"===r()?"vs-dark":"vs"}lexicalCmd(e,t){if("visual"!==this.mode||!this.lexicalEditor)return;const i=this.lx.lexical?.[e];i&&this.lexicalEditor.dispatchCommand(i,t)}lexicalFormat(e){if("visual"!==this.mode||!this.lexicalEditor)return;const{lexical:t}=this.lx;this.lexicalEditor.update(()=>{const i=t.$getSelection();t.$isRangeSelection(i)&&i.formatText(e)},{discrete:!0})}lexicalFormatElement(e){"visual"===this.mode&&this.lexicalEditor&&this.lexicalEditor.dispatchCommand(this.lx.lexical.FORMAT_ELEMENT_COMMAND,e)}render(){const t=this.constructor.controlSets[this.controls]??{};return e`
|
|
1
|
+
import{html as e,css as t}from"../lit-all.min.js";import i from"./ShadowComponent.js";import o from"../utils/formatCode.js";import l from"../utils/debounce.js";import{getCalculatedTheme as r,subscribeToTheme as s}from"../utils/theme.js";import a from"./Dialog.js";export default class c extends i{static formAssociated=!0;static properties={name:{type:String,reflect:!0},value:{type:String,reflect:!0},selection:{type:Object,state:!0},mode:{type:String,reflect:!0},controls:{type:String,reflect:!0},lexicalSrc:{type:String,attribute:"lexical-src"},monacoSrc:{type:String,attribute:"monaco-src"},nodes:{type:String},hasTopToolbar:{type:Boolean,state:!0},hasBottomToolbar:{type:Boolean,state:!0},fullscreen:{type:Boolean,reflect:!0}};constructor(){super(),this.internals=this.attachInternals(),this.name="",this.value="",this.selection=null,this.cursor=null,this.mode="visual",this.controls="",this.controlsLoaded=!1,this.lexicalSrc="",this.monacoSrc="",this.nodes="",this.hasTopToolbar=!1,this.hasBottomToolbar=!1,this.skipValueSync=!1,this.lexicalValueSync=!1,this.savedSelection=null,this.lexicalEditor=null,this.monacoEditor=null,this.editorTheme="auto",this.wordWrap=!0,this.minimapEnabled=!1,this.fontSize=14,this.fullscreen=!1,this.lx={},this.debouncedSyncValue=l(()=>this.syncValueFromLexical(),300)}connectedCallback(){super.connectedCallback(),this.hasAttribute("value")&&(this.value=this.getAttribute("value")),this.slotObserver=new MutationObserver(()=>this.updateToolbarVisibility()),this.slotObserver.observe(this,{childList:!0,subtree:!0}),this.updateToolbarVisibility()}disconnectedCallback(){super.disconnectedCallback(),this.slotObserver?.disconnect(),this.cleanupFns?.forEach(e=>e?.()),this.monacoEditor?.dispose(),this.unsubscribeTheme?.(),this.fullscreen&&this.exitFullscreen()}updateToolbarVisibility(){const e=new Set(Array.from(this.children).map(e=>e.getAttribute("slot"))),t=this.constructor.controlSets[this.controls]??null;this.hasTopToolbar=!(!t?.topLeft&&!t?.topRight)||["toolbar-top","toolbar-top-left","toolbar-top-right"].some(t=>e.has(t)),this.hasBottomToolbar=!(!t?.bottomLeft&&!t?.bottomRight)||["toolbar-bottom","toolbar-bottom-left","toolbar-bottom-right"].some(t=>e.has(t))}updated(e){if(super.updated(e),e.has("controls")&&(this.updateToolbarVisibility(),this.controls&&"none"!==this.controls&&this.loadControls()),e.has("value")&&!this.skipValueSync&&(this.lexicalValueSync?this.lexicalValueSync=!1:this.lexicalEditor&&"visual"===this.mode&&!this.isVisualCompatible(this.value)?(this.skipLexicalExport=!0,this.mode="code"):this.syncContentToEditors(),this.updateFormValue(),this.dispatchEvent(new CustomEvent("change",{detail:{value:this.value},bubbles:!0}))),e.has("mode")){const t=window.scrollY;this.handleModeSwitch(e.get("mode")),this.dispatchEvent(new CustomEvent("mode-changed",{detail:{mode:this.mode},bubbles:!0})),requestAnimationFrame(()=>window.scrollTo(0,t))}e.has("fullscreen")&&requestAnimationFrame(()=>this.monacoEditor?.layout())}async firstUpdated(){this.lexicalContainer=this.shadowRoot.querySelector(".lexical-editor"),this.monacoContainer=this.shadowRoot.querySelector(".monaco-editor-container"),await this.initLexical(),this.dispatchEvent(new CustomEvent("ready",{detail:{value:this.value},bubbles:!0}))}async loadControls(){if(this.controlsLoaded)return;this.controlsLoaded=!0;const e=new URL("./htmlEditorControls/",import.meta.url).href;await Promise.all([import(`${e}Bold.js`),import(`${e}Italic.js`),import(`${e}Underline.js`),import(`${e}Strikethrough.js`),import(`${e}InlineCode.js`),import(`${e}DropdownControl.js`),import(`${e}FormatBlock.js`),import(`${e}CodeBlock.js`),import(`${e}BulletList.js`),import(`${e}NumberList.js`),import(`${e}AlignLeft.js`),import(`${e}AlignCenter.js`),import(`${e}AlignRight.js`),import(`${e}AlignJustify.js`),import(`${e}TextColor.js`),import(`${e}TextBackgroundColor.js`),import(`${e}ClearFormatting.js`),import(`${e}CreateLink.js`),import(`${e}InsertTable.js`),import(`${e}ControlGroup.js`),import(`${e}ControlSpacer.js`),import(`${e}Mode.js`),import(`${e}WordCount.js`),import(`${e}CharacterCount.js`)]);const t=new URL("./codeEditorControls/",import.meta.url).href;await Promise.all([import(`${t}FormatCode.js`),import(`${t}CopyCode.js`),import(`${t}Undo.js`),import(`${t}Redo.js`),import(`${t}WordWrap.js`),import(`${t}Minimap.js`),import(`${t}FindReplace.js`),import(`${t}FontSize.js`),import(`${t}FoldAll.js`),import(`${t}EditorTheme.js`),import(`${t}Fullscreen.js`),import(`${t}ControlGroup.js`)]),this.requestUpdate()}async loadNodeModules(){if(!this.nodes?.trim())return[];const e=new URL("./htmlEditorNodes/",import.meta.url).href;return(await Promise.all(this.nodes.split(",").map(e=>e.trim()).filter(Boolean).map(t=>import(`${e}${t}.js`)))).map(e=>e.default?.lexicalNode).filter(Boolean)}async loadLexicalModules(){const e=this.lexicalSrc||window.kempo?.lexicalUrl||"https://esm.sh",t=t=>((e,t)=>`${e}/${t}@0.43.0`)(e,t),[i,o,l,r,s,a,c,n,h]=await Promise.all([import(t("lexical")),import(t("@lexical/rich-text")),import(t("@lexical/html")),import(t("@lexical/history")),import(t("@lexical/list")),import(t("@lexical/link")),import(t("@lexical/selection")),import(t("@lexical/table")),import(t("@lexical/code"))]);this.lx={lexical:i,richText:o,lexicalHtml:l,history:r,list:s,link:a,selection:c,table:n,code:h},this.StyledTextNode=class extends i.TextNode{static getType(){return"styled-text"}static clone(e){return new this(e.__text,e.__key)}static importDOM(){return{span:()=>({conversion:e=>{const t=e.getAttribute("style");if(!t)return null;const o=i.$createTextNode(e.textContent);return o.setStyle(t),{node:o}},priority:1})}}static importJSON(e){return i.$createTextNode(e.text)}exportJSON(){return{...super.exportJSON(),type:"styled-text"}}}}async initLexical(){await this.loadLexicalModules(),this.customNodes=await this.loadNodeModules(),this.nodeCompatCheckers=this.customNodes.filter(e=>"function"==typeof e.isVisualCompatible).map(e=>e.isVisualCompatible),this.nodePreprocessors=this.customNodes.filter(e=>"function"==typeof e.preprocessHtml).map(e=>e.preprocessHtml);const{lexical:e,richText:t,history:i,list:o,link:l,table:r,code:s}=this.lx,a={namespace:"KempoHtmlEditor",theme:{paragraph:"k-editor-p",heading:{h1:"k-editor-h1",h2:"k-editor-h2",h3:"k-editor-h3",h4:"k-editor-h4",h5:"k-editor-h5",h6:"k-editor-h6"},text:{underline:"td-u",strikethrough:"td-lt"},list:{ul:"k-editor-ul",ol:"k-editor-ol",listitem:"k-editor-li"},link:"k-editor-link",quote:"k-editor-quote",code:"k-editor-code-block",codeHighlight:{},table:"k-editor-table",tableCell:"k-editor-table-cell",tableCellHeader:"k-editor-table-cell-header"},nodes:[t.HeadingNode,t.QuoteNode,o.ListNode,o.ListItemNode,l.LinkNode,r.TableNode,r.TableCellNode,r.TableRowNode,s.CodeNode,s.CodeHighlightNode,this.StyledTextNode,...this.customNodes],onError:console.error,editorState:null};this.lexicalEditor=e.createEditor(a),this.lexicalEditor.setRootElement(this.lexicalContainer),this.lexicalEditor._window=new Proxy(window,{get:(e,t)=>{if("getSelection"===t)return()=>this.shadowRoot.getSelection();const i=Reflect.get(e,t);return"function"==typeof i?i.bind(e):i}}),this.cleanupFns=[t.registerRichText(this.lexicalEditor),i.registerHistory(this.lexicalEditor,i.createEmptyHistoryState(),300)],o.registerList&&this.cleanupFns.push(o.registerList(this.lexicalEditor)),r.registerTable&&this.cleanupFns.push(r.registerTable(this.lexicalEditor)),s.registerCodeHighlighting&&this.cleanupFns.push(s.registerCodeHighlighting(this.lexicalEditor)),l.registerLink&&this.cleanupFns.push(l.registerLink(this.lexicalEditor,{validateUrl:e=>{try{return new URL(e),!0}catch{return!1}}})),this.value&&(this.isVisualCompatible(this.value)?this.importHtmlToLexical(this.value):(this.skipLexicalExport=!0,this.mode="code")),this.lexicalEditor.registerUpdateListener(({dirtyElements:e,dirtyLeaves:t})=>{0===e.size&&0===t.size||(this.debouncedSyncValue(),this.dispatchEvent(new CustomEvent("input",{detail:{value:this.exportHtmlFromLexical()},bubbles:!0})))}),this.lexicalEditor.registerCommand(e.SELECTION_CHANGE_COMMAND,()=>(this.updateSelection(),!1),e.COMMAND_PRIORITY_LOW)}async initMonaco(){if(!this.monacoEditor){if(this.monacoInitPromise)return this.monacoInitPromise;this.monacoInitPromise=this._initMonaco(),await this.monacoInitPromise,this.monacoInitPromise=null}}async _initMonaco(){const e=this.monacoSrc||window.kempo?.monacoUrl||"https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min";await new Promise((t,i)=>{if(window.monaco)return void t();if(window.require?.defined?.("vs/editor/editor.main"))return void t();const o=document.querySelector(`script[src="${e}/vs/loader.js"]`);if(o)return void o.addEventListener("load",()=>{window.require.config({paths:{vs:`${e}/vs`}}),window.require(["vs/editor/editor.main"],()=>t(),i)});const l=document.createElement("script");l.src=`${e}/vs/loader.js`,l.onload=()=>{window.require.config({paths:{vs:`${e}/vs`}}),window.require(["vs/editor/editor.main"],()=>t(),i)},l.onerror=i,document.head.appendChild(l)}),this.monacoEditor=window.monaco.editor.create(this.monacoContainer,{value:o(this.value),language:"html",theme:this.resolveMonacoTheme(),minimap:{enabled:this.minimapEnabled},wordWrap:this.wordWrap?"on":"off",fontSize:this.fontSize,scrollBeyondLastLine:!1,automaticLayout:!0,tabSize:2,padding:{top:8}});const t=document.querySelector('link[href*="monaco"][href*="editor.main.css"]');if(t){const e=document.createElement("link");e.rel="stylesheet",e.href=t.href,this.shadowRoot.appendChild(e)}this.unsubscribeTheme=s(()=>{this.monacoEditor&&"auto"===this.editorTheme&&window.monaco.editor.setTheme(this.resolveMonacoTheme())}),this.monacoEditor.onDidChangeModelContent(()=>{this.skipValueSync=!0,this.value=this.monacoEditor.getValue(),this.skipValueSync=!1,this.updateFormValue(),this.dispatchEvent(new CustomEvent("change",{detail:{value:this.value},bubbles:!0})),this.dispatchEvent(new CustomEvent("input",{detail:{value:this.value},bubbles:!0}))})}importHtmlToLexical(e){if(!this.lexicalEditor||!this.lx.lexicalHtml)return;const{lexical:t,lexicalHtml:i}=this.lx,o=(this.nodePreprocessors||[]).reduce((e,t)=>t(e),e);this.lexicalEditor.update(()=>{if(t.$getRoot().clear(),!o?.trim())return;const e=(new DOMParser).parseFromString(o,"text/html"),l=i.$generateNodesFromDOM(this.lexicalEditor,e);l.length>0&&t.$insertNodes(l)},{discrete:!0})}exportHtmlFromLexical(){if(!this.lexicalEditor||!this.lx.lexicalHtml)return this.value;let e="";return this.lexicalEditor.getEditorState().read(()=>{e=this.lx.lexicalHtml.$generateHtmlFromNodes(this.lexicalEditor,null)}),this.cleanExportedHtml(e)}isVisualCompatible(e){if(!e?.trim())return!0;const t=new Set(["script","style","meta","link","head","iframe","object","embed","canvas","video","audio","form","input","button","select","textarea","fieldset","label","noscript","template","slot","svg","math"]),i=this.nodeCompatCheckers||[],o=(new DOMParser).parseFromString(e,"text/html"),l=document.createTreeWalker(o.body,NodeFilter.SHOW_ELEMENT|NodeFilter.SHOW_COMMENT);let r;for(;r=l.nextNode();)if(!i.some(e=>e(r))){if(r.nodeType===Node.COMMENT_NODE)return!1;if(t.has(r.tagName?.toLowerCase()))return!1}return!0}cleanExportedHtml(e){const t=(new DOMParser).parseFromString(e,"text/html");return t.body.querySelectorAll("[class]").forEach(e=>{const t=Array.from(e.classList).filter(e=>!e.startsWith("k-editor-")&&"td-u"!==e&&"td-lt"!==e);0===t.length?e.removeAttribute("class"):e.className=t.join(" ")}),t.body.querySelectorAll("[style]").forEach(e=>{const t=e.style.cssText.replace(/white-space:\s*pre-wrap;?\s*/g,"").trim();t?e.style.cssText=t:e.removeAttribute("style")}),t.body.querySelectorAll("span:not([class]):not([style]):not([id])").forEach(e=>{e.attributes.length||e.replaceWith(...e.childNodes)}),t.body.querySelectorAll("b > strong, i > em, b > b, strong > strong, i > i, em > em").forEach(e=>{e.replaceWith(...e.childNodes)}),t.body.querySelectorAll("pre[data-highlight-language], code[data-highlight-language]").forEach(e=>{e.removeAttribute("data-highlight-language"),e.removeAttribute("data-language")}),t.body.innerHTML}syncValueFromLexical(){this.lexicalEditor&&(this.lexicalValueSync=!0,this.value=this.exportHtmlFromLexical(),this.updateFormValue())}syncContentToEditors(){"visual"===this.mode&&this.lexicalEditor&&this.importHtmlToLexical(this.value)}async handleModeSwitch(e){"code"===this.mode?(this.lexicalEditor&&!this.skipLexicalExport&&(this.value=this.exportHtmlFromLexical()),this.skipLexicalExport=!1,await this.initMonaco(),this.monacoEditor&&(this.monacoEditor.setValue(o(this.value)),this.monacoEditor.layout())):"visual"===this.mode&&(this.monacoEditor&&(this.value=this.monacoEditor.getValue()),this.lexicalEditor&&this.importHtmlToLexical(this.value)),this.requestUpdate()}updateFormValue(){this.internals.setFormValue(this.getValue())}formResetCallback(){this.value=""}formStateRestoreCallback(e){this.value=e}updateSelection=()=>{if("visual"!==this.mode||!this.lexicalEditor)return void(this.selection=null);const{lexical:e}=this.lx;this.lexicalEditor.getEditorState().read(()=>{const t=e.$getSelection();e.$isRangeSelection(t)&&!t.isCollapsed()?this.selection={text:t.getTextContent(),collapsed:!1}:(this.selection=null,this.cursor=t?{anchor:t.anchor,focus:t.focus}:null)})};setMode(e){return["visual","code"].includes(e)?"visual"!==e||this.isVisualCompatible(this.getValue())?(this.mode=e,this):(a.confirm("This html contains code that is not compatible with the visual editor, the incompatible code will be lost",t=>{t&&(this.mode=e)},{title:"Warning",confirmText:"Change Anyways"}),this):this}toggleMode(){return this.setMode("visual"===this.mode?"code":"visual")}getValue(){if("visual"===this.mode&&this.lexicalEditor)this.skipValueSync=!0,this.value=this.exportHtmlFromLexical(),this.skipValueSync=!1;else if("code"===this.mode&&this.monacoEditor)return this.monacoEditor.getValue();return this.value}setValue(e){return this.lexicalEditor&&"visual"===this.mode&&!this.isVisualCompatible(e)?(this.value=e,this.skipLexicalExport=!0,this.mode="code",this.updateFormValue(),this):(this.skipValueSync=!0,this.value=e,"visual"===this.mode?this.syncContentToEditors():"code"===this.mode&&this.monacoEditor&&this.monacoEditor.setValue(o(e)),this.updateFormValue(),this.skipValueSync=!1,this)}clear(){return this.setValue("")}bold(){return this.lexicalFormat("bold"),this}italic(){return this.lexicalFormat("italic"),this}underline(){return this.lexicalFormat("underline"),this}strikethrough(){return this.lexicalFormat("strikethrough"),this}inlineCode(){return this.lexicalFormat("code"),this}orderedList(){return"visual"===this.mode&&this.lexicalEditor?(this.lexicalEditor.update(()=>{this.lx.list.$insertList("number")},{discrete:!0}),this):this}unorderedList(){return"visual"===this.mode&&this.lexicalEditor?(this.lexicalEditor.update(()=>{this.lx.list.$insertList("bullet")},{discrete:!0}),this):this}alignLeft(){return this.lexicalFormatElement("left"),this}alignCenter(){return this.lexicalFormatElement("center"),this}alignRight(){return this.lexicalFormatElement("right"),this}alignJustify(){return this.lexicalFormatElement("justify"),this}setTextColor(e){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:t,selection:i}=this.lx;return this.lexicalEditor.update(()=>{const o=t.$getSelection();t.$isRangeSelection(o)&&i.$patchStyleText(o,{color:e})},{discrete:!0}),this}removeTextColor(){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:e,selection:t}=this.lx;return this.lexicalEditor.update(()=>{const i=e.$getSelection();e.$isRangeSelection(i)&&t.$patchStyleText(i,{color:null})},{discrete:!0}),this}setTextBackgroundColor(e){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:t,selection:i}=this.lx;return this.lexicalEditor.update(()=>{const o=t.$getSelection();t.$isRangeSelection(o)&&i.$patchStyleText(o,{"background-color":e})},{discrete:!0}),this}removeTextBackgroundColor(){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:e,selection:t}=this.lx;return this.lexicalEditor.update(()=>{const i=e.$getSelection();e.$isRangeSelection(i)&&t.$patchStyleText(i,{"background-color":null})},{discrete:!0}),this}removeFormat(){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:e,selection:t}=this.lx;return this.lexicalEditor.update(()=>{const i=e.$getSelection();e.$isRangeSelection(i)&&(i.getNodes().forEach(t=>{e.$isTextNode(t)&&t.setFormat(0)}),t.$patchStyleText(i,{color:null,"background-color":null}))},{discrete:!0}),this}formatBlock(e){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:t,richText:i,code:o}=this.lx;return this.lexicalEditor.update(()=>{const l=t.$getSelection();if(!t.$isRangeSelection(l))return;const r=l.anchor.getNode().getTopLevelElementOrThrow(),s=o.$isCodeNode(r);let a;if("p"===e)a=t.$createParagraphNode();else if(e.match(/^h[1-6]$/))a=i.$createHeadingNode(e);else if("blockquote"===e)a=i.$createQuoteNode();else{if("pre"!==e)return;a=o.$createCodeNode()}if(s&&"pre"!==e){const e=r.getTextContent();r.replace(a),a.append(t.$createTextNode(e))}else{const e=r.getChildren();r.replace(a),e.forEach(e=>a.append(e))}a.selectEnd()},{discrete:!0}),this}isSelectionInCodeBlock(){if("visual"!==this.mode||!this.lexicalEditor)return!1;let e=!1;const{lexical:t,code:i}=this.lx;return this.lexicalEditor.getEditorState().read(()=>{const o=t.$getSelection();t.$isRangeSelection(o)&&(e=i.$isCodeNode(o.anchor.getNode().getTopLevelElementOrThrow()))}),e}getTableAtSelection(){if("visual"!==this.mode||!this.lexicalEditor)return null;let e=null;const{lexical:t,table:i}=this.lx;return this.lexicalEditor.getEditorState().read(()=>{const o=t.$getSelection();if(!t.$isRangeSelection(o))return;let l=o.anchor.getNode();for(;l;){if(i.$isTableNode(l)){const t=l.getChildren(),o=[];let r=!1,s=0;t.forEach((e,t)=>{const l=[];e.getChildren().forEach(e=>{0===t&&i.$isTableCellNode(e)&&e.getHeaderStyles()===i.TableCellHeaderStates.ROW&&(r=!0),l.push(e.getTextContent())}),l.length>s&&(s=l.length),o.push(l)}),e={key:l.getKey(),rows:r?t.length-1:t.length,cols:s,hasHeaders:r,cellData:o};break}l=l.getParent()}}),e}removeTableByKey(e){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:t}=this.lx;return this.lexicalEditor.update(()=>{const i=t.$getNodeByKey(e);i&&i.remove()},{discrete:!0}),this}insertHTML(e){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:t,lexicalHtml:i}=this.lx;return this.lexicalEditor.update(()=>{const o=(new DOMParser).parseFromString(e,"text/html"),l=i.$generateNodesFromDOM(this.lexicalEditor,o);t.$insertNodes(l)},{discrete:!0}),this}insertAtCursor(e){return this.insertHTML(e)}insertTable(e,t,i=!1,o=null){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:l,table:r}=this.lx;return this.lexicalEditor.update(()=>{const s=e+(i?1:0),a=[];for(let e=0;e<s;e++){const s=[];for(let a=0;a<t;a++){const t=i&&0===e,c=t?r.TableCellHeaderStates.ROW:r.TableCellHeaderStates.NO_STATUS,n=r.$createTableCellNode(c),h=o?.[e]?.[a]??(t?`Header ${a+1}`:""),d=l.$createParagraphNode();d.append(l.$createTextNode(h||" ")),n.append(d),s.push(n)}a.push(r.$createTableRowNode().append(...s))}const c=r.$createTableNode().append(...a),n=l.$getSelection();if(l.$isRangeSelection(n)){n.anchor.getNode().getTopLevelElementOrThrow().insertAfter(c);const e=l.$createParagraphNode();c.insertAfter(e),e.selectEnd()}else{const e=l.$getRoot();e.append(c),e.append(l.$createParagraphNode())}},{discrete:!0}),this}insertElementAtCursor(e){return this.insertHTML(e.outerHTML)}replaceSelectionWithElement(e){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:t,lexicalHtml:i}=this.lx;return this.lexicalEditor.update(()=>{const o=t.$getSelection();if(!t.$isRangeSelection(o))return;o.removeText();const l=(new DOMParser).parseFromString(e.outerHTML,"text/html"),r=i.$generateNodesFromDOM(this.lexicalEditor,l);t.$insertNodes(r)},{discrete:!0}),this}wrapSelection(e,t,i=null){if("visual"!==this.mode||!this.lexicalEditor)return this;const o=i||this.getSelectedText();return o?this.insertHTML(e+o+t):this}getSelection(){if("visual"!==this.mode||!this.lexicalEditor)return null;let e=null;const{lexical:t}=this.lx;return this.lexicalEditor.getEditorState().read(()=>{const i=t.$getSelection();t.$isRangeSelection(i)&&!i.isCollapsed()&&(e={text:i.getTextContent(),html:i.getTextContent(),selection:i})}),e}getSelectedText(){let e="";if("visual"!==this.mode||!this.lexicalEditor)return e;const{lexical:t}=this.lx;return this.lexicalEditor.getEditorState().read(()=>{const i=t.$getSelection();t.$isRangeSelection(i)&&(e=i.getTextContent())}),e}getSelectedHTML(){return this.getSelectedText()}selectAll(){if("visual"===this.mode&&this.lexicalEditor){const{lexical:e}=this.lx;this.lexicalEditor.update(()=>{e.$selectAll()},{discrete:!0})}else if(this.monacoEditor){const e=this.monacoEditor.getModel();e&&this.monacoEditor.setSelection(e.getFullModelRange())}return this}replaceSelection(e){return this.insertHTML(e)}deleteSelection(){return"visual"===this.mode?this.lexicalCmd("DELETE_CHARACTER_COMMAND",!1):this.monacoEditor&&this.monacoEditor.trigger("keyboard","deleteAllLeft",null),this}getValueWithSelectionMarkers(){if("visual"!==this.mode||!this.lexicalEditor)return{html:this.value,hasCursor:!1,hasSelection:!1,selectedText:""};let e={html:this.exportHtmlFromLexical(),hasCursor:!1,hasSelection:!1,selectedText:""};const{lexical:t}=this.lx;return this.lexicalEditor.getEditorState().read(()=>{const i=t.$getSelection();t.$isRangeSelection(i)&&(i.isCollapsed()?e.hasCursor=!0:(e.hasSelection=!0,e.selectedText=i.getTextContent()))}),e}setValueFromSelectionMarkers(e){return this.setValue(e)}captureSelection(){return this.selection}restoreSavedSelection(){return!1}clearSavedSelection(){this.savedSelection=null}createLink(e){if("visual"!==this.mode||!this.lexicalEditor)return this;const{link:t}=this.lx;return this.lexicalEditor.update(()=>{t.$toggleLink(e)},{discrete:!0}),this}createLinkWithText(e,t){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:i,link:o}=this.lx;return this.lexicalEditor.update(()=>{const l=i.$getSelection();i.$isRangeSelection(l)&&!l.isCollapsed()&&l.removeText();const r=o.$createLinkNode(e);r.append(i.$createTextNode(t)),i.$insertNodes([r])},{discrete:!0}),this}unlink(){if("visual"!==this.mode||!this.lexicalEditor)return this;const{lexical:e,link:t}=this.lx;return this.lexicalEditor.update(()=>{const i=e.$getSelection();e.$isRangeSelection(i)&&i.getNodes().forEach(e=>{const i=e.getParent();i&&t.$isLinkNode?.(i)&&(i.getChildren().forEach(e=>i.insertBefore(e)),i.remove())})},{discrete:!0}),this}insertImage(e){return this.insertHTML(`<img src="${encodeURI(e)}" />`)}undo(){return"code"===this.mode?this.monacoEditor?.trigger("toolbar","undo"):this.lexicalCmd("UNDO_COMMAND",void 0),this}redo(){return"code"===this.mode?this.monacoEditor?.trigger("toolbar","redo"):this.lexicalCmd("REDO_COMMAND",void 0),this}copyToClipboard(){return navigator.clipboard.writeText(this.getValue()),this}setEditorTheme(e){return["auto","light","dark"].includes(e)&&(this.editorTheme=e),this.monacoEditor&&window.monaco.editor.setTheme(this.resolveMonacoTheme()),this}openFind(){return this.monacoEditor?.getAction("actions.find")?.run(),this}foldAll(){return this.monacoEditor?.getAction("editor.foldAll")?.run(),this}unfoldAll(){return this.monacoEditor?.getAction("editor.unfoldAll")?.run(),this}enterFullscreen(){return this.fullscreen=!0,document.body.classList.add("no-scroll"),this.dispatchEvent(new CustomEvent("fullscreen-changed",{detail:{fullscreen:!0},bubbles:!0})),this}exitFullscreen(){return this.fullscreen=!1,document.body.classList.remove("no-scroll"),this.dispatchEvent(new CustomEvent("fullscreen-changed",{detail:{fullscreen:!1},bubbles:!0})),this}toggleFullscreen(){return this.fullscreen?this.exitFullscreen():this.enterFullscreen()}increaseFontSize(){return this.fontSize=Math.min(this.fontSize+2,40),this.monacoEditor?.updateOptions({fontSize:this.fontSize}),this}decreaseFontSize(){return this.fontSize=Math.max(this.fontSize-2,8),this.monacoEditor?.updateOptions({fontSize:this.fontSize}),this}setWordWrap(e){return this.wordWrap=e,this.monacoEditor?.updateOptions({wordWrap:e?"on":"off"}),this}setMinimap(e){return this.minimapEnabled=e,this.monacoEditor?.updateOptions({minimap:{enabled:e}}),this}resolveMonacoTheme(){return"dark"===this.editorTheme?"vs-dark":"light"===this.editorTheme?"vs":"dark"===r()?"vs-dark":"vs"}lexicalCmd(e,t){if("visual"!==this.mode||!this.lexicalEditor)return;const i=this.lx.lexical?.[e];i&&this.lexicalEditor.dispatchCommand(i,t)}lexicalFormat(e){if("visual"!==this.mode||!this.lexicalEditor)return;const{lexical:t}=this.lx;this.lexicalEditor.update(()=>{const i=t.$getSelection();t.$isRangeSelection(i)&&i.formatText(e)},{discrete:!0})}lexicalFormatElement(e){"visual"===this.mode&&this.lexicalEditor&&this.lexicalEditor.dispatchCommand(this.lx.lexical.FORMAT_ELEMENT_COMMAND,e)}render(){const t=this.constructor.controlSets[this.controls]??{};return e`
|
|
2
2
|
${this.hasTopToolbar?e`
|
|
3
3
|
<div class="toolbar-top bb">
|
|
4
4
|
<div class="toolbar-start">
|
|
@@ -201,20 +201,6 @@ import{html as e,css as t}from"../lit-all.min.js";import i from"./ShadowComponen
|
|
|
201
201
|
<k-hec-bullet-list></k-hec-bullet-list>
|
|
202
202
|
<k-hec-number-list></k-hec-number-list>
|
|
203
203
|
</k-hec-group>
|
|
204
|
-
`,topRight:e`
|
|
205
|
-
<k-hec-group>
|
|
206
|
-
<k-hec-align-left></k-hec-align-left>
|
|
207
|
-
<k-hec-align-center></k-hec-align-center>
|
|
208
|
-
<k-hec-align-right></k-hec-align-right>
|
|
209
|
-
<k-hec-align-justify></k-hec-align-justify>
|
|
210
|
-
</k-hec-group>
|
|
211
|
-
<k-hec-create-link></k-hec-create-link>
|
|
212
|
-
<k-hec-group>
|
|
213
|
-
<k-hec-text-color></k-hec-text-color>
|
|
214
|
-
<k-hec-text-background-color></k-hec-text-background-color>
|
|
215
|
-
</k-hec-group>
|
|
216
|
-
<k-hec-clear-formatting></k-hec-clear-formatting>
|
|
217
|
-
<k-hec-insert-table></k-hec-insert-table>
|
|
218
204
|
<k-cec-group>
|
|
219
205
|
<k-cec-undo></k-cec-undo>
|
|
220
206
|
<k-cec-redo></k-cec-redo>
|
|
@@ -230,6 +216,20 @@ import{html as e,css as t}from"../lit-all.min.js";import i from"./ShadowComponen
|
|
|
230
216
|
<k-cec-fold-all></k-cec-fold-all>
|
|
231
217
|
</k-cec-group>
|
|
232
218
|
<k-cec-font-size></k-cec-font-size>
|
|
219
|
+
`,topRight:e`
|
|
220
|
+
<k-hec-group>
|
|
221
|
+
<k-hec-align-left></k-hec-align-left>
|
|
222
|
+
<k-hec-align-center></k-hec-align-center>
|
|
223
|
+
<k-hec-align-right></k-hec-align-right>
|
|
224
|
+
<k-hec-align-justify></k-hec-align-justify>
|
|
225
|
+
</k-hec-group>
|
|
226
|
+
<k-hec-create-link></k-hec-create-link>
|
|
227
|
+
<k-hec-group>
|
|
228
|
+
<k-hec-text-color></k-hec-text-color>
|
|
229
|
+
<k-hec-text-background-color></k-hec-text-background-color>
|
|
230
|
+
</k-hec-group>
|
|
231
|
+
<k-hec-clear-formatting></k-hec-clear-formatting>
|
|
232
|
+
<k-hec-insert-table></k-hec-insert-table>
|
|
233
233
|
<k-cec-editor-theme></k-cec-editor-theme>
|
|
234
234
|
<k-hec-mode></k-hec-mode>
|
|
235
235
|
<k-cec-fullscreen></k-cec-fullscreen>
|
package/docs-src/.config.js
CHANGED
|
@@ -12,5 +12,15 @@ export default {
|
|
|
12
12
|
templating: {
|
|
13
13
|
ssr: true,
|
|
14
14
|
ssrPriority: true
|
|
15
|
+
},
|
|
16
|
+
"middleware": {
|
|
17
|
+
"security": {
|
|
18
|
+
"enabled": true,
|
|
19
|
+
"headers": {
|
|
20
|
+
"X-Content-Type-Options": "nosniff",
|
|
21
|
+
"X-Frame-Options": "SAMEORIGIN",
|
|
22
|
+
"X-XSS-Protection": "1; mode=block"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
15
25
|
}
|
|
16
26
|
};
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
<a href="#disabledItems">Disabled Items</a><br />
|
|
16
16
|
<a href="#links">Using Links</a><br />
|
|
17
17
|
<a href="#events">Events</a><br />
|
|
18
|
+
<a href="#hover">Hover</a><br />
|
|
18
19
|
|
|
19
20
|
<h6 class="mt"><a href="#jsRef" class="no-link">JavaScript Reference</a></h6>
|
|
20
21
|
<a href="#constructor">Constructor</a><br />
|
|
@@ -225,6 +226,26 @@
|
|
|
225
226
|
</div>
|
|
226
227
|
</div>
|
|
227
228
|
|
|
229
|
+
<h3 id="hover"><a href="#hover" class="no-link">Hover</a></h3>
|
|
230
|
+
<p>Add the <code>hover</code> attribute to open the menu when the trigger is hovered instead of clicked. The menu closes automatically 150ms after the cursor leaves the component.</p>
|
|
231
|
+
<div class="row -mx">
|
|
232
|
+
<div class="col m-span-12 px">
|
|
233
|
+
<k-card label="HTML">
|
|
234
|
+
<pre><code class="hljs xml"><span class="hljs-tag"><<span class="hljs-name">k-dropdown</span> <span class="hljs-attr">hover</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">button</span> <span class="hljs-attr">slot</span>=<span class="hljs-string">'trigger'</span>></span>Hover Me<span class="hljs-tag"></<span class="hljs-name">button</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">button</span> <span class="hljs-attr">data-value</span>=<span class="hljs-string">'edit'</span>></span>Edit<span class="hljs-tag"></<span class="hljs-name">button</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">button</span> <span class="hljs-attr">data-value</span>=<span class="hljs-string">'copy'</span>></span>Copy<span class="hljs-tag"></<span class="hljs-name">button</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">button</span> <span class="hljs-attr">data-value</span>=<span class="hljs-string">'delete'</span>></span>Delete<span class="hljs-tag"></<span class="hljs-name">button</span>></span><br><span class="hljs-tag"></<span class="hljs-name">k-dropdown</span>></span></code></pre>
|
|
235
|
+
</k-card>
|
|
236
|
+
</div>
|
|
237
|
+
<div class="col m-span-12 px">
|
|
238
|
+
<k-card label="Output">
|
|
239
|
+
<k-dropdown hover>
|
|
240
|
+
<button slot="trigger">Hover Me</button>
|
|
241
|
+
<button data-value="edit">Edit</button>
|
|
242
|
+
<button data-value="copy">Copy</button>
|
|
243
|
+
<button data-value="delete">Delete</button>
|
|
244
|
+
</k-dropdown>
|
|
245
|
+
</k-card>
|
|
246
|
+
</div>
|
|
247
|
+
</div>
|
|
248
|
+
|
|
228
249
|
<h2 id="jsRef"><a href="#jsRef" class="no-link">JavaScript Reference</a></h2>
|
|
229
250
|
|
|
230
251
|
<h3 id="constructor"><a href="#constructor" class="no-link">Constructor</a></h3>
|
|
@@ -253,6 +274,9 @@
|
|
|
253
274
|
<h5><code>submenu<i>: boolean</i></code></h5>
|
|
254
275
|
<p>Automatically set to <code>true</code> when a <code>k-dropdown</code> is nested inside another <code>k-dropdown</code>. Sub menus open on hover/focus, display a chevron icon, and default to <code>open-direction="right down"</code>. Supports <code>ArrowRight</code> to open and <code>ArrowLeft</code> to close via keyboard.</p>
|
|
255
276
|
|
|
277
|
+
<h5><code>hover<i>: boolean</i></code></h5>
|
|
278
|
+
<p>When present, the menu opens on <code>mouseenter</code> instead of trigger click. The menu closes 150ms after the cursor leaves the component. Default is <code>false</code>.</p>
|
|
279
|
+
|
|
256
280
|
<h3 id="methods"><a href="#methods" class="no-link">Methods</a></h3>
|
|
257
281
|
<h5><code>open()<i>: this</i></code></h5>
|
|
258
282
|
<p>Opens the dropdown menu and focuses the first item.</p>
|
package/package.json
CHANGED
package/src/components/Aside.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import ShadowComponent from './ShadowComponent.js';
|
|
2
2
|
import { html, css, nothing } from '../lit-all.min.js';
|
|
3
3
|
import { boolTrueFalse } from '../utils/propConverters.js';
|
|
4
|
+
import './Dropdown.js';
|
|
4
5
|
import './FocusCapture.js';
|
|
5
6
|
import './Icon.js';
|
|
6
7
|
|
|
@@ -240,10 +241,10 @@ export default class Aside extends ShadowComponent {
|
|
|
240
241
|
}
|
|
241
242
|
:host([main="push"][state="collapsed"]) aside {
|
|
242
243
|
width: var(--collapsed-width);
|
|
243
|
-
transform:
|
|
244
|
+
transform: none;
|
|
244
245
|
}
|
|
245
246
|
:host([main="push"][state="expanded"]) aside {
|
|
246
|
-
transform:
|
|
247
|
+
transform: none;
|
|
247
248
|
}
|
|
248
249
|
:host([main="overlay"]) aside {
|
|
249
250
|
width: var(--width);
|
|
@@ -252,13 +253,13 @@ export default class Aside extends ShadowComponent {
|
|
|
252
253
|
transform: translateX(-100%);
|
|
253
254
|
}
|
|
254
255
|
:host([main="overlay"][state="expanded"]) aside {
|
|
255
|
-
transform:
|
|
256
|
+
transform: none;
|
|
256
257
|
}
|
|
257
258
|
:host([main="overlay"][side="right"]) aside {
|
|
258
259
|
transform: translateX(100%);
|
|
259
260
|
}
|
|
260
261
|
:host([main="overlay"][side="right"][state="expanded"]) aside {
|
|
261
|
-
transform:
|
|
262
|
+
transform: none;
|
|
262
263
|
}
|
|
263
264
|
`;
|
|
264
265
|
}
|
|
@@ -294,7 +295,8 @@ class AsideItem extends ShadowComponent {
|
|
|
294
295
|
connectedCallback() {
|
|
295
296
|
super.connectedCallback();
|
|
296
297
|
this.aside = this.closest('k-aside');
|
|
297
|
-
|
|
298
|
+
this.inMenu = !!this.closest('k-aside-menu');
|
|
299
|
+
if(this.aside && !this.inMenu) {
|
|
298
300
|
this.collapsed = this.aside.state === 'collapsed';
|
|
299
301
|
this.aside.addEventListener('aside_state_change', this.handleStateChange);
|
|
300
302
|
}
|
|
@@ -466,6 +468,7 @@ class AsideMenu extends ShadowComponent {
|
|
|
466
468
|
label: { type: String },
|
|
467
469
|
open: { type: Boolean, reflect: true },
|
|
468
470
|
collapsed: { type: Boolean, reflect: true },
|
|
471
|
+
side: { type: String },
|
|
469
472
|
'no-expand': { type: Boolean, attribute: 'no-expand' },
|
|
470
473
|
'hide-when-collapsed': { type: Boolean, attribute: 'hide-when-collapsed' }
|
|
471
474
|
};
|
|
@@ -476,6 +479,7 @@ class AsideMenu extends ShadowComponent {
|
|
|
476
479
|
this.label = '';
|
|
477
480
|
this.open = false;
|
|
478
481
|
this.collapsed = false;
|
|
482
|
+
this.side = 'left';
|
|
479
483
|
this['no-expand'] = false;
|
|
480
484
|
this['hide-when-collapsed'] = false;
|
|
481
485
|
}
|
|
@@ -488,6 +492,7 @@ class AsideMenu extends ShadowComponent {
|
|
|
488
492
|
this.aside = this.closest('k-aside');
|
|
489
493
|
if(this.aside) {
|
|
490
494
|
this.collapsed = this.aside.state === 'collapsed';
|
|
495
|
+
this.side = this.aside.side || 'left';
|
|
491
496
|
this.aside.addEventListener('aside_state_change', this.handleStateChange);
|
|
492
497
|
}
|
|
493
498
|
}
|
|
@@ -510,28 +515,41 @@ class AsideMenu extends ShadowComponent {
|
|
|
510
515
|
} else if(state === 'expanded') {
|
|
511
516
|
this.collapsed = false;
|
|
512
517
|
}
|
|
518
|
+
this.side = this.aside?.side || 'left';
|
|
513
519
|
};
|
|
514
520
|
|
|
515
521
|
toggleMenu = () => {
|
|
516
|
-
if(this.collapsed
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
522
|
+
if(!this.collapsed) this.open = !this.open;
|
|
523
|
+
};
|
|
524
|
+
|
|
525
|
+
handleCollapsedClick = () => {
|
|
526
|
+
this.open = true;
|
|
527
|
+
this.aside?.expand();
|
|
521
528
|
};
|
|
522
529
|
|
|
523
530
|
/*
|
|
524
531
|
Rendering
|
|
525
532
|
*/
|
|
526
533
|
render() {
|
|
534
|
+
if(this.collapsed) {
|
|
535
|
+
const openDirection = this.side === 'right' ? 'left down' : 'right down';
|
|
536
|
+
return html`
|
|
537
|
+
<k-dropdown open-direction=${openDirection} hover>
|
|
538
|
+
<button slot="trigger" class="no-btn collapsed-trigger" @click=${this.handleCollapsedClick}>
|
|
539
|
+
${this.icon ? html`<k-icon name="${this.icon}"></k-icon>` : html`<k-icon name="dot"></k-icon>`}
|
|
540
|
+
</button>
|
|
541
|
+
<slot></slot>
|
|
542
|
+
</k-dropdown>
|
|
543
|
+
`;
|
|
544
|
+
}
|
|
527
545
|
return html`
|
|
528
546
|
<div class="menu-container">
|
|
529
547
|
<button class="no-btn menu-header ${this.open ? 'open' : ''}" @click=${this.toggleMenu}>
|
|
530
|
-
${this.icon ? html`<k-icon name="${this.icon}"></k-icon>` :
|
|
531
|
-
|
|
532
|
-
|
|
548
|
+
${this.icon ? html`<k-icon name="${this.icon}"></k-icon>` : nothing}
|
|
549
|
+
<span class="label">${this.label}</span>
|
|
550
|
+
<k-icon class="chevron" name="chevron" direction="${this.open ? 'down' : 'right'}"></k-icon>
|
|
533
551
|
</button>
|
|
534
|
-
<div class="menu-content ${this.open
|
|
552
|
+
<div class="menu-content ${this.open ? 'open' : ''}">
|
|
535
553
|
<slot></slot>
|
|
536
554
|
</div>
|
|
537
555
|
</div>
|
|
@@ -564,12 +582,29 @@ class AsideMenu extends ShadowComponent {
|
|
|
564
582
|
white-space: nowrap;
|
|
565
583
|
transition: background var(--animation_ms);
|
|
566
584
|
}
|
|
567
|
-
:host([collapsed]) .menu-header {
|
|
568
|
-
width: auto;
|
|
569
|
-
}
|
|
570
585
|
.menu-header:hover {
|
|
571
586
|
background: var(--c_bg_hover);
|
|
572
587
|
}
|
|
588
|
+
.collapsed-trigger {
|
|
589
|
+
display: flex;
|
|
590
|
+
align-items: center;
|
|
591
|
+
justify-content: center;
|
|
592
|
+
padding: var(--spacer_h);
|
|
593
|
+
color: var(--tc);
|
|
594
|
+
background: transparent;
|
|
595
|
+
border: none;
|
|
596
|
+
appearance: none;
|
|
597
|
+
border-radius: var(--radius);
|
|
598
|
+
margin: 0 var(--spacer_h);
|
|
599
|
+
cursor: pointer;
|
|
600
|
+
transition: background var(--animation_ms);
|
|
601
|
+
}
|
|
602
|
+
.collapsed-trigger:hover {
|
|
603
|
+
background: var(--c_bg_hover);
|
|
604
|
+
}
|
|
605
|
+
k-dropdown {
|
|
606
|
+
display: block;
|
|
607
|
+
}
|
|
573
608
|
k-icon {
|
|
574
609
|
flex-shrink: 0;
|
|
575
610
|
}
|
|
@@ -588,9 +623,6 @@ class AsideMenu extends ShadowComponent {
|
|
|
588
623
|
transition: max-height var(--animation_ms);
|
|
589
624
|
padding-left: calc(var(--spacer_h) * 2);
|
|
590
625
|
}
|
|
591
|
-
:host([collapsed]) .menu-content {
|
|
592
|
-
padding-left: 0;
|
|
593
|
-
}
|
|
594
626
|
.menu-content.open {
|
|
595
627
|
max-height: 500px;
|
|
596
628
|
}
|
|
@@ -717,6 +749,7 @@ class AsideToggle extends ShadowComponent {
|
|
|
717
749
|
width: 2rem;
|
|
718
750
|
height: 2rem;
|
|
719
751
|
border: none;
|
|
752
|
+
appearance: none;
|
|
720
753
|
background: transparent;
|
|
721
754
|
color: var(--c_text);
|
|
722
755
|
cursor: pointer;
|
|
@@ -11,7 +11,8 @@ export default class Dropdown extends ShadowComponent {
|
|
|
11
11
|
openDirection: { type: String, reflect: true, attribute: 'open-direction' },
|
|
12
12
|
closeOnSelect: { type: Boolean, reflect: true, attribute: 'close-on-select', converter: boolTrueFalse },
|
|
13
13
|
closeOnClickOutside: { type: Boolean, reflect: true, attribute: 'close-on-click-outside', converter: boolTrueFalse },
|
|
14
|
-
submenu: { type: Boolean, reflect: true }
|
|
14
|
+
submenu: { type: Boolean, reflect: true },
|
|
15
|
+
hover: { type: Boolean, reflect: true }
|
|
15
16
|
};
|
|
16
17
|
|
|
17
18
|
constructor() {
|
|
@@ -21,6 +22,7 @@ export default class Dropdown extends ShadowComponent {
|
|
|
21
22
|
this.closeOnSelect = true;
|
|
22
23
|
this.closeOnClickOutside = true;
|
|
23
24
|
this.submenu = false;
|
|
25
|
+
this.hover = false;
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
/*
|
|
@@ -37,6 +39,10 @@ export default class Dropdown extends ShadowComponent {
|
|
|
37
39
|
this.addEventListener('mouseleave', this.handleSubmenuLeave);
|
|
38
40
|
} else {
|
|
39
41
|
document.addEventListener('click', this.handleDocumentClick);
|
|
42
|
+
if(this.hover) {
|
|
43
|
+
this.addEventListener('mouseenter', this.handleHoverEnter);
|
|
44
|
+
this.addEventListener('mouseleave', this.handleHoverLeave);
|
|
45
|
+
}
|
|
40
46
|
}
|
|
41
47
|
document.addEventListener('keydown', this.handleKeydown);
|
|
42
48
|
}
|
|
@@ -48,6 +54,8 @@ export default class Dropdown extends ShadowComponent {
|
|
|
48
54
|
this.removeEventListener('mouseleave', this.handleSubmenuLeave);
|
|
49
55
|
} else {
|
|
50
56
|
document.removeEventListener('click', this.handleDocumentClick);
|
|
57
|
+
this.removeEventListener('mouseenter', this.handleHoverEnter);
|
|
58
|
+
this.removeEventListener('mouseleave', this.handleHoverLeave);
|
|
51
59
|
}
|
|
52
60
|
document.removeEventListener('keydown', this.handleKeydown);
|
|
53
61
|
openDropdowns.delete(this);
|
|
@@ -99,6 +107,7 @@ export default class Dropdown extends ShadowComponent {
|
|
|
99
107
|
};
|
|
100
108
|
|
|
101
109
|
handleTriggerClick = e => {
|
|
110
|
+
if(this.hover) return;
|
|
102
111
|
e.stopPropagation();
|
|
103
112
|
// Close all other dropdowns before opening this one
|
|
104
113
|
if(!this.opened) {
|
|
@@ -396,6 +405,15 @@ export default class Dropdown extends ShadowComponent {
|
|
|
396
405
|
}
|
|
397
406
|
`;
|
|
398
407
|
|
|
408
|
+
handleHoverEnter = () => {
|
|
409
|
+
clearTimeout(this.closeTimer);
|
|
410
|
+
if(!this.opened) this.open();
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
handleHoverLeave = () => {
|
|
414
|
+
this.closeTimer = setTimeout(() => this.close(), 150);
|
|
415
|
+
};
|
|
416
|
+
|
|
399
417
|
/*
|
|
400
418
|
Slot Change Handler
|
|
401
419
|
*/
|
|
@@ -80,7 +80,7 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
80
80
|
this.cleanupFns?.forEach(fn => fn?.());
|
|
81
81
|
this.monacoEditor?.dispose();
|
|
82
82
|
this.unsubscribeTheme?.();
|
|
83
|
-
|
|
83
|
+
|
|
84
84
|
if(this.fullscreen) this.exitFullscreen();
|
|
85
85
|
}
|
|
86
86
|
|
|
@@ -268,6 +268,13 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
268
268
|
|
|
269
269
|
this.lexicalEditor = lexical.createEditor(editorConfig);
|
|
270
270
|
this.lexicalEditor.setRootElement(this.lexicalContainer);
|
|
271
|
+
this.lexicalEditor._window = new Proxy(window, {
|
|
272
|
+
get: (target, prop) => {
|
|
273
|
+
if(prop === 'getSelection') return () => this.shadowRoot.getSelection();
|
|
274
|
+
const val = Reflect.get(target, prop);
|
|
275
|
+
return typeof val === 'function' ? val.bind(target) : val;
|
|
276
|
+
}
|
|
277
|
+
});
|
|
271
278
|
|
|
272
279
|
this.cleanupFns = [
|
|
273
280
|
richText.registerRichText(this.lexicalEditor),
|
|
@@ -304,19 +311,7 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
304
311
|
lexical.COMMAND_PRIORITY_LOW
|
|
305
312
|
);
|
|
306
313
|
|
|
307
|
-
|
|
308
|
-
if (this.mode !== 'visual' || !this.lexicalEditor) return;
|
|
309
|
-
const shadowSel = this.shadowRoot.getSelection?.();
|
|
310
|
-
if (!shadowSel || shadowSel.rangeCount === 0) return;
|
|
311
|
-
const range = shadowSel.getRangeAt(0);
|
|
312
|
-
if (!this.lexicalContainer.contains(range.startContainer)) return;
|
|
313
|
-
this.lexicalEditor.update(() => {
|
|
314
|
-
const lexSel = lexical.$createRangeSelectionFromDom(shadowSel, this.lexicalEditor);
|
|
315
|
-
if (lexSel) lexical.$setSelection(lexSel);
|
|
316
|
-
}, { discrete: true });
|
|
317
|
-
this.updateSelection();
|
|
318
|
-
};
|
|
319
|
-
document.addEventListener('selectionchange', this.syncShadowSelection);
|
|
314
|
+
|
|
320
315
|
}
|
|
321
316
|
|
|
322
317
|
async initMonaco() {
|
|
@@ -1364,21 +1359,6 @@ static controlSets = {
|
|
|
1364
1359
|
<k-hec-bullet-list></k-hec-bullet-list>
|
|
1365
1360
|
<k-hec-number-list></k-hec-number-list>
|
|
1366
1361
|
</k-hec-group>
|
|
1367
|
-
`,
|
|
1368
|
-
topRight: html`
|
|
1369
|
-
<k-hec-group>
|
|
1370
|
-
<k-hec-align-left></k-hec-align-left>
|
|
1371
|
-
<k-hec-align-center></k-hec-align-center>
|
|
1372
|
-
<k-hec-align-right></k-hec-align-right>
|
|
1373
|
-
<k-hec-align-justify></k-hec-align-justify>
|
|
1374
|
-
</k-hec-group>
|
|
1375
|
-
<k-hec-create-link></k-hec-create-link>
|
|
1376
|
-
<k-hec-group>
|
|
1377
|
-
<k-hec-text-color></k-hec-text-color>
|
|
1378
|
-
<k-hec-text-background-color></k-hec-text-background-color>
|
|
1379
|
-
</k-hec-group>
|
|
1380
|
-
<k-hec-clear-formatting></k-hec-clear-formatting>
|
|
1381
|
-
<k-hec-insert-table></k-hec-insert-table>
|
|
1382
1362
|
<k-cec-group>
|
|
1383
1363
|
<k-cec-undo></k-cec-undo>
|
|
1384
1364
|
<k-cec-redo></k-cec-redo>
|
|
@@ -1394,6 +1374,21 @@ static controlSets = {
|
|
|
1394
1374
|
<k-cec-fold-all></k-cec-fold-all>
|
|
1395
1375
|
</k-cec-group>
|
|
1396
1376
|
<k-cec-font-size></k-cec-font-size>
|
|
1377
|
+
`,
|
|
1378
|
+
topRight: html`
|
|
1379
|
+
<k-hec-group>
|
|
1380
|
+
<k-hec-align-left></k-hec-align-left>
|
|
1381
|
+
<k-hec-align-center></k-hec-align-center>
|
|
1382
|
+
<k-hec-align-right></k-hec-align-right>
|
|
1383
|
+
<k-hec-align-justify></k-hec-align-justify>
|
|
1384
|
+
</k-hec-group>
|
|
1385
|
+
<k-hec-create-link></k-hec-create-link>
|
|
1386
|
+
<k-hec-group>
|
|
1387
|
+
<k-hec-text-color></k-hec-text-color>
|
|
1388
|
+
<k-hec-text-background-color></k-hec-text-background-color>
|
|
1389
|
+
</k-hec-group>
|
|
1390
|
+
<k-hec-clear-formatting></k-hec-clear-formatting>
|
|
1391
|
+
<k-hec-insert-table></k-hec-insert-table>
|
|
1397
1392
|
<k-cec-editor-theme></k-cec-editor-theme>
|
|
1398
1393
|
<k-hec-mode></k-hec-mode>
|
|
1399
1394
|
<k-cec-fullscreen></k-cec-fullscreen>
|