@aquera/nile-elements 0.1.67-beta-1.4 → 0.1.67-beta-1.6

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.
Files changed (57) hide show
  1. package/demo/index.html +13 -6
  2. package/dist/index.js +143 -247
  3. package/dist/nile-rich-text-editor/nile-rich-text-editor.cjs.js +1 -1
  4. package/dist/nile-rich-text-editor/nile-rich-text-editor.cjs.js.map +1 -1
  5. package/dist/nile-rich-text-editor/nile-rich-text-editor.css.cjs.js +1 -1
  6. package/dist/nile-rich-text-editor/nile-rich-text-editor.css.cjs.js.map +1 -1
  7. package/dist/nile-rich-text-editor/nile-rich-text-editor.css.esm.js +68 -172
  8. package/dist/nile-rich-text-editor/nile-rich-text-editor.esm.js +1 -1
  9. package/dist/nile-rich-text-editor/nile-rte-select.cjs.js +1 -1
  10. package/dist/nile-rich-text-editor/nile-rte-select.cjs.js.map +1 -1
  11. package/dist/nile-rich-text-editor/nile-rte-select.esm.js +39 -39
  12. package/dist/nile-rich-text-editor/utils.cjs.js.map +1 -1
  13. package/dist/src/nile-rich-text-editor/nile-rich-text-editor.css.js +68 -172
  14. package/dist/src/nile-rich-text-editor/nile-rich-text-editor.css.js.map +1 -1
  15. package/dist/src/nile-rich-text-editor/nile-rich-text-editor.d.ts +0 -3
  16. package/dist/src/nile-rich-text-editor/nile-rich-text-editor.js +35 -125
  17. package/dist/src/nile-rich-text-editor/nile-rich-text-editor.js.map +1 -1
  18. package/dist/src/nile-rich-text-editor/nile-rte-select.js +62 -57
  19. package/dist/src/nile-rich-text-editor/nile-rte-select.js.map +1 -1
  20. package/dist/src/nile-rich-text-editor/rte-utils/content.d.ts +2 -0
  21. package/dist/src/nile-rich-text-editor/rte-utils/content.js +25 -0
  22. package/dist/src/nile-rich-text-editor/rte-utils/content.js.map +1 -0
  23. package/dist/src/nile-rich-text-editor/rte-utils/css.d.ts +1 -0
  24. package/dist/src/nile-rich-text-editor/rte-utils/css.js +9 -0
  25. package/dist/src/nile-rich-text-editor/rte-utils/css.js.map +1 -0
  26. package/dist/src/nile-rich-text-editor/rte-utils/dom.d.ts +2 -0
  27. package/dist/src/nile-rich-text-editor/rte-utils/dom.js +48 -0
  28. package/dist/src/nile-rich-text-editor/rte-utils/dom.js.map +1 -0
  29. package/dist/src/nile-rich-text-editor/rte-utils/formatting.d.ts +2 -0
  30. package/dist/src/nile-rich-text-editor/rte-utils/formatting.js +69 -0
  31. package/dist/src/nile-rich-text-editor/rte-utils/formatting.js.map +1 -0
  32. package/dist/src/nile-rich-text-editor/rte-utils/keys.d.ts +2 -0
  33. package/dist/src/nile-rich-text-editor/rte-utils/keys.js +38 -0
  34. package/dist/src/nile-rich-text-editor/rte-utils/keys.js.map +1 -0
  35. package/dist/src/nile-rich-text-editor/rte-utils/lists.d.ts +2 -0
  36. package/dist/src/nile-rich-text-editor/rte-utils/lists.js +28 -0
  37. package/dist/src/nile-rich-text-editor/rte-utils/lists.js.map +1 -0
  38. package/dist/src/nile-rich-text-editor/rte-utils/selection.d.ts +17 -0
  39. package/dist/src/nile-rich-text-editor/rte-utils/selection.js +39 -0
  40. package/dist/src/nile-rich-text-editor/rte-utils/selection.js.map +1 -0
  41. package/dist/src/nile-rich-text-editor/rte-utils/toolbar.d.ts +28 -0
  42. package/dist/src/nile-rich-text-editor/rte-utils/toolbar.js +161 -0
  43. package/dist/src/nile-rich-text-editor/rte-utils/toolbar.js.map +1 -0
  44. package/dist/src/nile-rich-text-editor/rte-utils/toolbarState.d.ts +13 -0
  45. package/dist/src/nile-rich-text-editor/rte-utils/toolbarState.js +119 -0
  46. package/dist/src/nile-rich-text-editor/rte-utils/toolbarState.js.map +1 -0
  47. package/dist/src/nile-rich-text-editor/rte-utils/vars.d.ts +1 -0
  48. package/dist/src/nile-rich-text-editor/rte-utils/vars.js +14 -0
  49. package/dist/src/nile-rich-text-editor/rte-utils/vars.js.map +1 -0
  50. package/dist/src/nile-rich-text-editor/utils.js.map +1 -1
  51. package/dist/tsconfig.tsbuildinfo +1 -1
  52. package/package.json +1 -1
  53. package/src/nile-rich-text-editor/nile-rich-text-editor.css.ts +68 -172
  54. package/src/nile-rich-text-editor/nile-rich-text-editor.ts +74 -160
  55. package/src/nile-rich-text-editor/nile-rte-select.ts +178 -173
  56. package/src/nile-rich-text-editor/utils.ts +342 -341
  57. package/vscode-html-custom-data.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"nile-rte-select.js","sourceRoot":"","sources":["../../../src/nile-rich-text-editor/nile-rte-select.ts"],"names":[],"mappings":"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","sourcesContent":[" // nile-rte-select.ts\n import { LitElement, html } from 'lit';\n import { customElement, property, state } from 'lit/decorators.js';\n\n type HeadingTag = 'p' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';\n type GenericOption = { value: string; label?: string; icon?: string };\n type HeadingOption = { value: HeadingTag; label?: string; icon?: string };\n type NormalizedOption = { value: string; label: string; icon?: string };\n\n const HEADING_ALLOWLIST: ReadonlySet<HeadingTag> = new Set([\n 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'\n ]);\n\n function isHeadingTag(v: string): v is HeadingTag {\n return HEADING_ALLOWLIST.has(v as HeadingTag);\n }\n\n @customElement('nile-rte-select')\n export class NileRteSelect extends LitElement {\n protected createRenderRoot() { return this; }\n\n /** 'heading' | 'font' | 'align' */\n @property({ type: String }) type = '';\n\n /** JSON: [{ value, label?, icon? }, ...] (attribute-based; runtime-validated) */\n @property({ type: String }) options = '[]';\n\n /** Programmatic options (preferred for TS safety). */\n @property({ attribute: false })\n optionsObj?: Array<GenericOption | HeadingOption>;\n\n /** Fallback label for trigger (e.g., \"Align\") */\n @property({ type: String }) label = '';\n\n @state() private selectedValue = '';\n\n private mapAlignIcon(v: string) {\n const map: Record<string,string> = {\n left: 'format_align_left',\n center: 'format_align_middle',\n right: 'format_align_right',\n justify: 'format_align_justify'\n };\n return map[v] || 'align-left';\n }\n\n private get parsedOptions(): NormalizedOption[] {\n // Prefer programmatic options if present (gives TS compile-time checks)\n const source: unknown = this.optionsObj ?? this.options;\n\n const rawArray: any[] = (() => {\n if (Array.isArray(source)) return source;\n try { return JSON.parse(String(source)); } catch { return []; }\n })();\n\n // Normalize to consistent shape\n let items: NormalizedOption[] = rawArray.map((o: any) => {\n const value: string = o?.value ?? o;\n const label: string = o?.label ?? o?.value ?? o;\n const icon: string | undefined =\n o?.icon ?? (this.type === 'align' ? this.mapAlignIcon(String(value)) : undefined);\n return { value, label, icon };\n });\n\n // If type is heading, enforce allowlist (runtime validation)\n if (this.type === 'heading') {\n const before = items.length;\n items = items.filter(i => isHeadingTag(i.value));\n if (items.length !== before) {\n }\n // If current selection is invalid for heading, reset\n if (this.selectedValue && !isHeadingTag(this.selectedValue)) {\n this.selectedValue = '';\n }\n }\n\n return items;\n }\n\n private ensureDefault() {\n if (!this.selectedValue) {\n const first = this.parsedOptions[0];\n if (first) this.selectedValue = first.value;\n }\n }\n\n private onSelect(value: string) {\n if (this.type === 'heading' && !isHeadingTag(value)) {\n console.warn(`[nile-rte-select] Ignoring invalid heading value: ${value}`);\n return;\n }\n this.selectedValue = value;\n this.dispatchEvent(new CustomEvent('change', {\n detail: value, bubbles: true, composed: true\n }));\n }\n\n connectedCallback(): void {\n super.connectedCallback();\n this.injectLocalStyles();\n }\n\n private injectLocalStyles() {\n if (this.querySelector('style[data-rte-select-style]')) return;\n\n const style = document.createElement('style');\n style.setAttribute('data-rte-select-style', 'true');\n style.textContent = `\n nile-menu.rte-align-menu::part(menu__items-wrapper) {\n display: flex;\n }\n nile-menu.rte-align-menu,\n nile-menu.rte-default-menu {\n margin-top: 0px;\n }\n nile-button.rte-align-trigger::part(base),\n nile-button.rte-default-trigger::part(base) {\n min-width: 32px;\n height: 32px;\n padding: 0px 6px;\n box-shadow: none;\n }\n `;\n this.insertBefore(style, this.firstChild);\n }\n\n render() {\n const opts = this.parsedOptions;\n this.ensureDefault();\n const current = opts.find(o => o.value === this.selectedValue);\n\n // ► Align: icon-only items + icon trigger\n if (this.type === 'align') {\n const trigger = current?.icon\n ? html`<nile-icon name=\"${current.icon}\"></nile-icon>`\n : (this.label || 'Align');\n\n return html`\n <nile-dropdown class=\"rte-align-dd\">\n <nile-button slot=\"trigger\" variant=\"tertiary\" class=\"rte-align-trigger\">\n ${trigger}\n </nile-button>\n <nile-menu class=\"rte-align-menu\">\n ${opts.map(o => html`\n <nile-menu-item\n class=\"rte-align-item\"\n ?active=${o.value === this.selectedValue}\n @click=${() => this.onSelect(o.value)}>\n <nile-icon name=\"${o.icon}\"></nile-icon>\n </nile-menu-item>\n `)}\n </nile-menu>\n </nile-dropdown>\n `;\n }\n\n // ► Font: show labels, preview fonts in items and trigger\n if (this.type === 'font') {\n const triggerText = current?.label || this.label || 'Font';\n return html`\n <nile-dropdown class=\"rte-default-dd\">\n <nile-button\n slot=\"trigger\"\n variant=\"tertiary\"\n class=\"rte-default-trigger\"\n style=\"font-family: ${current?.value || 'inherit'}\">\n ${triggerText} <nile-icon name=\"arrowdown\"></nile-icon>\n </nile-button>\n <nile-menu class=\"rte-default-menu\">\n ${opts.map(o => html`\n <nile-menu-item\n style=\"font-family: ${o.value}\"\n ?active=${o.value === this.selectedValue}\n @click=${() => this.onSelect(o.value)}>\n ${o.label}\n </nile-menu-item>\n `)}\n </nile-menu>\n </nile-dropdown>\n `;\n }\n\n // ► Default (e.g., heading): text items; heading values are validated already\n const triggerText = current?.label || this.label || 'Select';\n return html`\n <nile-dropdown class=\"rte-default-dd\">\n <nile-button slot=\"trigger\" variant=\"tertiary\" class=\"rte-default-trigger\">\n ${triggerText} <nile-icon name=\"arrowdown\"></nile-icon>\n </nile-button>\n <nile-menu class=\"rte-default-menu\">\n ${opts.map(o => html`\n <nile-menu-item\n ?active=${o.value === this.selectedValue}\n @click=${() => this.onSelect(o.value)}>\n ${o.label}\n </nile-menu-item>\n `)}\n </nile-menu>\n </nile-dropdown>\n `;\n }\n }\n\n declare global {\n interface HTMLElementTagNameMap {\n 'nile-rte-select': NileRteSelect;\n }\n }\n"]}
1
+ {"version":3,"file":"nile-rte-select.js","sourceRoot":"","sources":["../../../src/nile-rich-text-editor/nile-rte-select.ts"],"names":[],"mappings":"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","sourcesContent":["// nile-rte-select.ts\nimport { LitElement, html } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\n\ntype HeadingTag = 'p' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';\ntype GenericOption = { value: string; label?: string; icon?: string };\ntype HeadingOption = { value: HeadingTag; label?: string; icon?: string };\ntype NormalizedOption = { value: string; label: string; icon?: string };\n\nconst HEADING_ALLOWLIST: ReadonlySet<HeadingTag> = new Set([\n 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'\n]);\n\nfunction isHeadingTag(v: string): v is HeadingTag {\n return HEADING_ALLOWLIST.has(v as HeadingTag);\n}\n\n@customElement('nile-rte-select')\nexport class NileRteSelect extends LitElement {\n protected createRenderRoot() { return this; }\n\n /** 'heading' | 'font' | 'align' */\n @property({ type: String }) type = '';\n\n /** JSON: [{ value, label?, icon? }, ...] (attribute-based; runtime-validated) */\n @property({ type: String }) options = '[]';\n\n /** Programmatic options (preferred for TS safety). */\n @property({ attribute: false })\n optionsObj?: Array<GenericOption | HeadingOption>;\n\n /** Fallback label for trigger (e.g., \"Align\") */\n @property({ type: String }) label = '';\n\n @state() private selectedValue = '';\n\n private mapAlignIcon(v: string) {\n const map: Record<string,string> = {\n left: 'format_align_left',\n center: 'format_align_middle',\n right: 'format_align_right',\n justify: 'format_align_justify'\n };\n return map[v] || 'format_align_left';\n }\n\n private get parsedOptions(): NormalizedOption[] {\n // Prefer programmatic options if present (gives TS compile-time checks)\n const source: unknown = this.optionsObj ?? this.options;\n\n const rawArray: any[] = (() => {\n if (Array.isArray(source)) return source;\n try { return JSON.parse(String(source)); } catch { return []; }\n })();\n\n // Normalize to consistent shape\n let items: NormalizedOption[] = rawArray.map((o: any) => {\n const value: string = o?.value ?? o;\n const label: string = o?.label ?? o?.value ?? o;\n const icon: string | undefined =\n o?.icon ?? (this.type === 'align' ? this.mapAlignIcon(String(value)) : undefined);\n return { value, label, icon };\n });\n\n // If type is heading, enforce allowlist (runtime validation)\n if (this.type === 'heading') {\n const before = items.length;\n items = items.filter(i => isHeadingTag(i.value));\n if (items.length !== before) {\n }\n // If current selection is invalid for heading, reset\n if (this.selectedValue && !isHeadingTag(this.selectedValue)) {\n this.selectedValue = '';\n }\n }\n\n return items;\n }\n\n private ensureDefault() {\n if (!this.selectedValue) {\n const first = this.parsedOptions[0];\n if (first) this.selectedValue = first.value;\n }\n }\n\n private onSelect(value: string) {\n if (this.type === 'heading' && !isHeadingTag(value)) {\n console.warn(`[nile-rte-select] Ignoring invalid heading value: ${value}`);\n return;\n }\n this.selectedValue = value;\n this.dispatchEvent(new CustomEvent('change', {\n detail: value, bubbles: true, composed: true\n }));\n }\n\n connectedCallback(): void {\n super.connectedCallback();\n this.injectLocalStyles();\n }\n\n private injectLocalStyles() {\n if (this.querySelector('style[data-rte-select-style]')) return;\n\n const style = document.createElement('style');\n style.setAttribute('data-rte-select-style', 'true');\n style.textContent = `\n nile-menu.rte-align-menu::part(menu__items-wrapper) {\n display: flex;\n }\n nile-menu.rte-align-menu,\n nile-menu.rte-default-menu {\n margin-top: 0px;\n }\n nile-button.rte-align-trigger::part(base),\n nile-button.rte-default-trigger::part(base) {\n min-width: 32px;\n height: 32px;\n padding: 0px 6px;\n box-shadow: none;\n }\n nile-button.rte-align-trigger::part(base) {\n \n\n border: none;\n}\n `;\n this.insertBefore(style, this.firstChild);\n }\n\n render() {\n const opts = this.parsedOptions;\n this.ensureDefault();\n const current = opts.find(o => o.value === this.selectedValue);\n\n // ► Align: icon-only items + icon trigger\n if (this.type === 'align') {\n const trigger = current?.icon\n ? html`<nile-icon name=\"${current.icon}\"></nile-icon>`\n : (this.label || 'Align');\n\n return html`\n <nile-dropdown class=\"rte-align-dd\">\n <nile-button slot=\"trigger\" variant=\"tertiary\" class=\"rte-align-trigger\">\n ${trigger}\n </nile-button>\n <nile-menu class=\"rte-align-menu\">\n ${opts.map(o => html`\n <nile-menu-item\n class=\"rte-align-item\"\n ?active=${o.value === this.selectedValue}\n @click=${() => this.onSelect(o.value)}>\n <nile-icon name=\"${o.icon}\"></nile-icon>\n </nile-menu-item>\n `)}\n </nile-menu>\n </nile-dropdown>\n `;\n }\n\n // ► Font: show labels, preview fonts in items and trigger\n if (this.type === 'font') {\n const triggerText = current?.label || this.label || 'Font';\n return html`\n <nile-dropdown class=\"rte-default-dd\">\n <nile-button\n slot=\"trigger\"\n variant=\"tertiary\"\n class=\"rte-default-trigger\"\n style=\"font-family: ${current?.value || 'inherit'}\">\n ${triggerText} <nile-icon name=\"arrowdown\"></nile-icon>\n </nile-button>\n <nile-menu class=\"rte-default-menu\">\n ${opts.map(o => html`\n <nile-menu-item\n style=\"font-family: ${o.value}\"\n ?active=${o.value === this.selectedValue}\n @click=${() => this.onSelect(o.value)}>\n ${o.label}\n </nile-menu-item>\n `)}\n </nile-menu>\n </nile-dropdown>\n `;\n }\n\n // ► Default (e.g., heading): text items; heading values are validated already\n const triggerText = current?.label || this.label || 'Select';\n return html`\n <nile-dropdown class=\"rte-default-dd\">\n <nile-button slot=\"trigger\" variant=\"tertiary\" class=\"rte-default-trigger\">\n ${triggerText} <nile-icon name=\"arrowdown\"></nile-icon>\n </nile-button>\n <nile-menu class=\"rte-default-menu\">\n ${opts.map(o => html`\n <nile-menu-item\n ?active=${o.value === this.selectedValue}\n @click=${() => this.onSelect(o.value)}>\n ${o.label}\n </nile-menu-item>\n `)}\n </nile-menu>\n </nile-dropdown>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'nile-rte-select': NileRteSelect;\n }\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export declare function inlineComputedStyles(sourceEl: HTMLElement): string;
2
+ export declare function updateContentAndEmit(host: HTMLElement, editorEl: HTMLElement, previewEl: HTMLElement | null): string;
@@ -0,0 +1,25 @@
1
+ export function inlineComputedStyles(sourceEl) {
2
+ const clone = sourceEl.cloneNode(true);
3
+ const origWalker = document.createTreeWalker(sourceEl, NodeFilter.SHOW_ELEMENT);
4
+ const cloneWalker = document.createTreeWalker(clone, NodeFilter.SHOW_ELEMENT);
5
+ while (origWalker.nextNode() && cloneWalker.nextNode()) {
6
+ const origEl = origWalker.currentNode;
7
+ const cloneEl = cloneWalker.currentNode;
8
+ const computed = window.getComputedStyle(origEl);
9
+ const cssText = Array.from(computed).map(prop => `${prop}:${computed.getPropertyValue(prop)}`).join(';');
10
+ cloneEl.setAttribute('style', cssText);
11
+ }
12
+ return clone.innerHTML;
13
+ }
14
+ export function updateContentAndEmit(host, editorEl, previewEl) {
15
+ const content = inlineComputedStyles(editorEl);
16
+ if (previewEl)
17
+ previewEl.innerHTML = content;
18
+ host.dispatchEvent(new CustomEvent('content-changed', {
19
+ detail: { content },
20
+ bubbles: true,
21
+ composed: true,
22
+ }));
23
+ return content;
24
+ }
25
+ //# sourceMappingURL=content.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content.js","sourceRoot":"","sources":["../../../../src/nile-rich-text-editor/rte-utils/content.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,oBAAoB,CAAC,QAAqB;IACtD,MAAM,KAAK,GAAG,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAgB,CAAC;IAEtD,MAAM,UAAU,GAAG,QAAQ,CAAC,gBAAgB,CAAC,QAAQ,EAAE,UAAU,CAAC,YAAY,CAAC,CAAC;IAChF,MAAM,WAAW,GAAG,QAAQ,CAAC,gBAAgB,CAAC,KAAK,EAAE,UAAU,CAAC,YAAY,CAAC,CAAC;IAE9E,OAAO,UAAU,CAAC,QAAQ,EAAE,IAAI,WAAW,CAAC,QAAQ,EAAE,EAAE,CAAC;QACvD,MAAM,MAAM,GAAG,UAAU,CAAC,WAA0B,CAAC;QACrD,MAAM,OAAO,GAAG,WAAW,CAAC,WAA0B,CAAC;QACvD,MAAM,QAAQ,GAAG,MAAM,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;QACjD,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,IAAI,QAAQ,CAAC,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACzG,OAAO,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACzC,CAAC;IAED,OAAO,KAAK,CAAC,SAAS,CAAC;AACzB,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,IAAiB,EAAE,QAAqB,EAAE,SAA6B;IAC1G,MAAM,OAAO,GAAG,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IAC/C,IAAI,SAAS;QAAE,SAAS,CAAC,SAAS,GAAG,OAAO,CAAC;IAC7C,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,iBAAiB,EAAE;QACpD,MAAM,EAAE,EAAE,OAAO,EAAE;QACnB,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,IAAI;KACf,CAAC,CAAC,CAAC;IACJ,OAAO,OAAO,CAAC;AACjB,CAAC","sourcesContent":["export function inlineComputedStyles(sourceEl: HTMLElement): string {\n const clone = sourceEl.cloneNode(true) as HTMLElement;\n \n const origWalker = document.createTreeWalker(sourceEl, NodeFilter.SHOW_ELEMENT);\n const cloneWalker = document.createTreeWalker(clone, NodeFilter.SHOW_ELEMENT);\n \n while (origWalker.nextNode() && cloneWalker.nextNode()) {\n const origEl = origWalker.currentNode as HTMLElement;\n const cloneEl = cloneWalker.currentNode as HTMLElement;\n const computed = window.getComputedStyle(origEl);\n const cssText = Array.from(computed).map(prop => `${prop}:${computed.getPropertyValue(prop)}`).join(';');\n cloneEl.setAttribute('style', cssText);\n }\n \n return clone.innerHTML;\n }\n \n export function updateContentAndEmit(host: HTMLElement, editorEl: HTMLElement, previewEl: HTMLElement | null): string {\n const content = inlineComputedStyles(editorEl);\n if (previewEl) previewEl.innerHTML = content;\n host.dispatchEvent(new CustomEvent('content-changed', {\n detail: { content },\n bubbles: true,\n composed: true,\n }));\n return content;\n }\n "]}
@@ -0,0 +1 @@
1
+ export declare function injectCss(host: HTMLElement, cssText: string): void;
@@ -0,0 +1,9 @@
1
+ export function injectCss(host, cssText) {
2
+ if (host.querySelector('style[data-rte-style]'))
3
+ return;
4
+ const style = document.createElement('style');
5
+ style.setAttribute('data-rte-style', 'true');
6
+ style.textContent = cssText;
7
+ host.insertBefore(style, host.firstChild);
8
+ }
9
+ //# sourceMappingURL=css.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"css.js","sourceRoot":"","sources":["../../../../src/nile-rich-text-editor/rte-utils/css.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,SAAS,CAAC,IAAiB,EAAE,OAAe;IACxD,IAAI,IAAI,CAAC,aAAa,CAAC,uBAAuB,CAAC;QAAE,OAAO;IACxD,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAC9C,KAAK,CAAC,YAAY,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC;IAC7C,KAAK,CAAC,WAAW,GAAG,OAAO,CAAC;IAC5B,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;AAC5C,CAAC","sourcesContent":["export function injectCss(host: HTMLElement, cssText: string) {\n if (host.querySelector('style[data-rte-style]')) return;\n const style = document.createElement('style');\n style.setAttribute('data-rte-style', 'true');\n style.textContent = cssText;\n host.insertBefore(style, host.firstChild);\n }"]}
@@ -0,0 +1,2 @@
1
+ export declare function ensureEditor(host: HTMLElement, toolbarEl?: HTMLElement | null, previewEl?: HTMLElement | null): HTMLElement;
2
+ export declare function ensureAtLeastOneParagraph(el: HTMLElement): void;
@@ -0,0 +1,48 @@
1
+ export function ensureEditor(host, toolbarEl, previewEl) {
2
+ let editorEl = host.querySelector('.editor');
3
+ if (!editorEl) {
4
+ const editor = document.createElement('article');
5
+ editor.className = 'editor';
6
+ editor.setAttribute('contenteditable', 'true');
7
+ if (toolbarEl?.nextSibling) {
8
+ host.insertBefore(editor, toolbarEl.nextSibling);
9
+ }
10
+ else if (previewEl) {
11
+ host.insertBefore(editor, previewEl);
12
+ }
13
+ else {
14
+ host.appendChild(editor);
15
+ }
16
+ editorEl = editor;
17
+ }
18
+ if (!editorEl.innerHTML.trim())
19
+ editorEl.innerHTML = '<p><br></p>';
20
+ ensureAtLeastOneParagraph(editorEl);
21
+ return editorEl;
22
+ }
23
+ export function ensureAtLeastOneParagraph(el) {
24
+ if (!el)
25
+ return;
26
+ const onlyWhitespace = (el.textContent ?? '').replace(/\u200B/g, '').trim() === '';
27
+ if (el.childNodes.length === 0 || onlyWhitespace) {
28
+ el.innerHTML = '<p><br></p>';
29
+ return;
30
+ }
31
+ const hasBlock = el.querySelector('p,h1,h2,h3,h4,h5,h6,ul,ol,table,blockquote,pre');
32
+ if (!hasBlock) {
33
+ const p = document.createElement('p');
34
+ while (el.firstChild)
35
+ p.appendChild(el.firstChild);
36
+ if (!p.hasChildNodes())
37
+ p.appendChild(document.createElement('br'));
38
+ el.appendChild(p);
39
+ return;
40
+ }
41
+ el.querySelectorAll('p').forEach(p => {
42
+ if ((p.textContent ?? '').replace(/\u200B/g, '') === '') {
43
+ if (!p.innerHTML.toLowerCase().includes('<br'))
44
+ p.innerHTML = '<br>';
45
+ }
46
+ });
47
+ }
48
+ //# sourceMappingURL=dom.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dom.js","sourceRoot":"","sources":["../../../../src/nile-rich-text-editor/rte-utils/dom.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,YAAY,CAAC,IAAiB,EAAE,SAA8B,EAAE,SAA8B;IAC1G,IAAI,QAAQ,GAAG,IAAI,CAAC,aAAa,CAAC,SAAS,CAAuB,CAAC;IACnE,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;QACjD,MAAM,CAAC,SAAS,GAAG,QAAQ,CAAC;QAC5B,MAAM,CAAC,YAAY,CAAC,iBAAiB,EAAE,MAAM,CAAC,CAAC;QAC/C,IAAI,SAAS,EAAE,WAAW,EAAE,CAAC;YAC3B,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,SAAS,CAAC,WAAW,CAAC,CAAC;QACnD,CAAC;aAAM,IAAI,SAAS,EAAE,CAAC;YACrB,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QACvC,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAC3B,CAAC;QACD,QAAQ,GAAG,MAAM,CAAC;IACpB,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,EAAE;QAAE,QAAQ,CAAC,SAAS,GAAG,aAAa,CAAC;IACnE,yBAAyB,CAAC,QAAQ,CAAC,CAAC;IACpC,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,EAAe;IACvD,IAAI,CAAC,EAAE;QAAE,OAAO;IAEhB,MAAM,cAAc,GAAG,CAAC,EAAE,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;IACnF,IAAI,EAAE,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC,IAAI,cAAc,EAAE,CAAC;QACjD,EAAE,CAAC,SAAS,GAAG,aAAa,CAAC;QAC7B,OAAO;IACT,CAAC;IAED,MAAM,QAAQ,GAAG,EAAE,CAAC,aAAa,CAAC,gDAAgD,CAAC,CAAC;IACpF,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,CAAC,GAAG,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;QACtC,OAAO,EAAE,CAAC,UAAU;YAAE,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC;QACnD,IAAI,CAAC,CAAC,CAAC,aAAa,EAAE;YAAE,CAAC,CAAC,WAAW,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;QACpE,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;QAClB,OAAO;IACT,CAAC;IAED,EAAE,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;QACnC,IAAI,CAAC,CAAC,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC;YACxD,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC;gBAAE,CAAC,CAAC,SAAS,GAAG,MAAM,CAAC;QACvE,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["export function ensureEditor(host: HTMLElement, toolbarEl?: HTMLElement | null, previewEl?: HTMLElement | null) {\n let editorEl = host.querySelector('.editor') as HTMLElement | null;\n if (!editorEl) {\n const editor = document.createElement('article');\n editor.className = 'editor';\n editor.setAttribute('contenteditable', 'true');\n if (toolbarEl?.nextSibling) {\n host.insertBefore(editor, toolbarEl.nextSibling);\n } else if (previewEl) {\n host.insertBefore(editor, previewEl);\n } else {\n host.appendChild(editor);\n }\n editorEl = editor;\n }\n if (!editorEl.innerHTML.trim()) editorEl.innerHTML = '<p><br></p>';\n ensureAtLeastOneParagraph(editorEl);\n return editorEl;\n }\n \n export function ensureAtLeastOneParagraph(el: HTMLElement) {\n if (!el) return;\n \n const onlyWhitespace = (el.textContent ?? '').replace(/\\u200B/g, '').trim() === '';\n if (el.childNodes.length === 0 || onlyWhitespace) {\n el.innerHTML = '<p><br></p>';\n return;\n }\n \n const hasBlock = el.querySelector('p,h1,h2,h3,h4,h5,h6,ul,ol,table,blockquote,pre');\n if (!hasBlock) {\n const p = document.createElement('p');\n while (el.firstChild) p.appendChild(el.firstChild);\n if (!p.hasChildNodes()) p.appendChild(document.createElement('br'));\n el.appendChild(p);\n return;\n }\n \n el.querySelectorAll('p').forEach(p => {\n if ((p.textContent ?? '').replace(/\\u200B/g, '') === '') {\n if (!p.innerHTML.toLowerCase().includes('<br')) p.innerHTML = '<br>';\n }\n });\n }\n "]}
@@ -0,0 +1,2 @@
1
+ import { SelectionManager } from './selection';
2
+ export declare function clearSelectionFormatting(selection: SelectionManager, editorEl: HTMLElement): void;
@@ -0,0 +1,69 @@
1
+ const FORMATTING_TAGS = new Set(['B', 'STRONG', 'I', 'EM', 'U', 'SPAN', 'FONT', 'A']);
2
+ function isFormatting(el) {
3
+ return FORMATTING_TAGS.has(el.tagName) || el.hasAttribute('style');
4
+ }
5
+ function liftOutOfFormatting(editorEl, marker) {
6
+ let p = marker.parentElement;
7
+ while (p && p !== editorEl && isFormatting(p)) {
8
+ const before = p.cloneNode(false);
9
+ const after = p.cloneNode(false);
10
+ while (p.firstChild && p.firstChild !== marker)
11
+ before.appendChild(p.firstChild);
12
+ while (marker.nextSibling)
13
+ after.appendChild(marker.nextSibling);
14
+ if (before.firstChild)
15
+ p.parentNode.insertBefore(before, p);
16
+ p.parentNode.insertBefore(marker, p);
17
+ if (after.firstChild)
18
+ p.parentNode.insertBefore(after, p);
19
+ const next = p.parentElement;
20
+ p.remove();
21
+ p = next;
22
+ }
23
+ }
24
+ export function clearSelectionFormatting(selection, editorEl) {
25
+ selection.focusAndRestore();
26
+ const sel = window.getSelection();
27
+ if (!sel || sel.rangeCount === 0)
28
+ return;
29
+ const range = sel.getRangeAt(0);
30
+ if (!editorEl.contains(range.commonAncestorContainer))
31
+ return;
32
+ if (range.collapsed)
33
+ return;
34
+ const frag = range.extractContents();
35
+ const walker = document.createTreeWalker(frag, NodeFilter.SHOW_ELEMENT);
36
+ const toUnwrap = [];
37
+ while (walker.nextNode()) {
38
+ const el = walker.currentNode;
39
+ el.removeAttribute('style');
40
+ if (FORMATTING_TAGS.has(el.tagName))
41
+ toUnwrap.push(el);
42
+ }
43
+ for (const el of toUnwrap) {
44
+ const parent = el.parentNode;
45
+ while (el.firstChild)
46
+ parent.insertBefore(el.firstChild, el);
47
+ parent.removeChild(el);
48
+ }
49
+ const marker = document.createElement('span');
50
+ marker.setAttribute('data-rte-clear', '1');
51
+ marker.appendChild(frag);
52
+ range.insertNode(marker);
53
+ liftOutOfFormatting(editorEl, marker);
54
+ const last = marker.lastChild;
55
+ const parent = marker.parentNode;
56
+ while (marker.firstChild)
57
+ parent.insertBefore(marker.firstChild, marker);
58
+ parent.removeChild(marker);
59
+ const r = document.createRange();
60
+ if (last)
61
+ r.setStartAfter(last);
62
+ else
63
+ r.setStart(parent, parent.childNodes?.length ?? 0);
64
+ r.collapse(true);
65
+ sel.removeAllRanges();
66
+ sel.addRange(r);
67
+ selection.save();
68
+ }
69
+ //# sourceMappingURL=formatting.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatting.js","sourceRoot":"","sources":["../../../../src/nile-rich-text-editor/rte-utils/formatting.ts"],"names":[],"mappings":"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","sourcesContent":["import { SelectionManager } from './selection';\n\nconst FORMATTING_TAGS = new Set(['B','STRONG','I','EM','U','SPAN','FONT','A']);\n\nfunction isFormatting(el: HTMLElement) {\n return FORMATTING_TAGS.has(el.tagName) || el.hasAttribute('style');\n}\n\nfunction liftOutOfFormatting(editorEl: HTMLElement, marker: HTMLElement) {\n let p: HTMLElement | null = marker.parentElement;\n while (p && p !== editorEl && isFormatting(p)) {\n const before = p.cloneNode(false) as HTMLElement;\n const after = p.cloneNode(false) as HTMLElement;\n\n while (p.firstChild && p.firstChild !== marker) before.appendChild(p.firstChild);\n while (marker.nextSibling) after.appendChild(marker.nextSibling);\n\n if (before.firstChild) p.parentNode!.insertBefore(before, p);\n p.parentNode!.insertBefore(marker, p);\n if (after.firstChild) p.parentNode!.insertBefore(after, p);\n\n const next = p.parentElement;\n p.remove();\n p = next;\n }\n}\n\nexport function clearSelectionFormatting(selection: SelectionManager, editorEl: HTMLElement) {\n selection.focusAndRestore();\n\n const sel = window.getSelection();\n if (!sel || sel.rangeCount === 0) return;\n\n const range = sel.getRangeAt(0);\n if (!editorEl.contains(range.commonAncestorContainer)) return;\n if (range.collapsed) return;\n\n const frag = range.extractContents();\n\n const walker = document.createTreeWalker(frag, NodeFilter.SHOW_ELEMENT);\n const toUnwrap: HTMLElement[] = [];\n while (walker.nextNode()) {\n const el = walker.currentNode as HTMLElement;\n el.removeAttribute('style');\n if (FORMATTING_TAGS.has(el.tagName)) toUnwrap.push(el);\n }\n for (const el of toUnwrap) {\n const parent = el.parentNode!;\n while (el.firstChild) parent.insertBefore(el.firstChild, el);\n parent.removeChild(el);\n }\n\n const marker = document.createElement('span');\n marker.setAttribute('data-rte-clear', '1');\n marker.appendChild(frag);\n range.insertNode(marker);\n\n liftOutOfFormatting(editorEl, marker);\n\n const last = marker.lastChild;\n const parent = marker.parentNode!;\n while (marker.firstChild) parent.insertBefore(marker.firstChild, marker);\n parent.removeChild(marker);\n\n const r = document.createRange();\n if (last) r.setStartAfter(last); else r.setStart(parent, (parent as any).childNodes?.length ?? 0);\n r.collapse(true);\n sel.removeAllRanges(); sel.addRange(r);\n\n selection.save();\n}"]}
@@ -0,0 +1,2 @@
1
+ import { SelectionManager } from './selection';
2
+ export declare function handleTabKey(e: KeyboardEvent, selection: SelectionManager, onContent: () => void, onToolbar: () => void): void;
@@ -0,0 +1,38 @@
1
+ export function handleTabKey(e, selection, onContent, onToolbar) {
2
+ e.preventDefault();
3
+ selection.focusAndRestore();
4
+ const sel = window.getSelection();
5
+ if (!sel || sel.rangeCount === 0)
6
+ return;
7
+ const range = sel.getRangeAt(0);
8
+ if (e.shiftKey) {
9
+ if (range.collapsed && range.startContainer.nodeType === Node.TEXT_NODE) {
10
+ const t = range.startContainer;
11
+ const off = range.startOffset;
12
+ const before = t.data.slice(0, off);
13
+ const removed = before.replace(/(\t|[ \u00a0]{2})$/, '');
14
+ if (removed.length !== before.length) {
15
+ t.data = removed + t.data.slice(off);
16
+ const r = document.createRange();
17
+ r.setStart(t, removed.length);
18
+ r.collapse(true);
19
+ sel.removeAllRanges();
20
+ sel.addRange(r);
21
+ onContent();
22
+ onToolbar();
23
+ }
24
+ }
25
+ return;
26
+ }
27
+ range.deleteContents();
28
+ const tabNode = document.createTextNode('\t');
29
+ range.insertNode(tabNode);
30
+ const r = document.createRange();
31
+ r.setStartAfter(tabNode);
32
+ r.collapse(true);
33
+ sel.removeAllRanges();
34
+ sel.addRange(r);
35
+ onContent();
36
+ onToolbar();
37
+ }
38
+ //# sourceMappingURL=keys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keys.js","sourceRoot":"","sources":["../../../../src/nile-rich-text-editor/rte-utils/keys.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,YAAY,CAC1B,CAAgB,EAChB,SAA2B,EAC3B,SAAqB,EACrB,SAAqB;IAErB,CAAC,CAAC,cAAc,EAAE,CAAC;IACnB,SAAS,CAAC,eAAe,EAAE,CAAC;IAE5B,MAAM,GAAG,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC;IAClC,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,UAAU,KAAK,CAAC;QAAE,OAAO;IACzC,MAAM,KAAK,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IAEhC,IAAK,CAAS,CAAC,QAAQ,EAAE,CAAC;QACxB,IAAI,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,cAAc,CAAC,QAAQ,KAAK,IAAI,CAAC,SAAS,EAAE,CAAC;YACxE,MAAM,CAAC,GAAG,KAAK,CAAC,cAAsB,CAAC;YACvC,MAAM,GAAG,GAAG,KAAK,CAAC,WAAW,CAAC;YAC9B,MAAM,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;YACpC,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,oBAAoB,EAAE,EAAE,CAAC,CAAC;YACzD,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,CAAC;gBACrC,CAAC,CAAC,IAAI,GAAG,OAAO,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBACrC,MAAM,CAAC,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;gBACjC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;gBAC9B,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;gBACjB,GAAG,CAAC,eAAe,EAAE,CAAC;gBAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;gBACvC,SAAS,EAAE,CAAC;gBAAC,SAAS,EAAE,CAAC;YAC3B,CAAC;QACH,CAAC;QACD,OAAO;IACT,CAAC;IAED,KAAK,CAAC,cAAc,EAAE,CAAC;IACvB,MAAM,OAAO,GAAG,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;IAC9C,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAE1B,MAAM,CAAC,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;IACjC,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IACzB,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACjB,GAAG,CAAC,eAAe,EAAE,CAAC;IAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IAEvC,SAAS,EAAE,CAAC;IAAC,SAAS,EAAE,CAAC;AAC3B,CAAC","sourcesContent":["import { SelectionManager } from './selection';\n\nexport function handleTabKey(\n e: KeyboardEvent,\n selection: SelectionManager,\n onContent: () => void,\n onToolbar: () => void,\n) {\n e.preventDefault();\n selection.focusAndRestore();\n\n const sel = window.getSelection();\n if (!sel || sel.rangeCount === 0) return;\n const range = sel.getRangeAt(0);\n\n if ((e as any).shiftKey) {\n if (range.collapsed && range.startContainer.nodeType === Node.TEXT_NODE) {\n const t = range.startContainer as Text;\n const off = range.startOffset;\n const before = t.data.slice(0, off);\n const removed = before.replace(/(\\t|[ \\u00a0]{2})$/, '');\n if (removed.length !== before.length) {\n t.data = removed + t.data.slice(off);\n const r = document.createRange();\n r.setStart(t, removed.length);\n r.collapse(true);\n sel.removeAllRanges(); sel.addRange(r);\n onContent(); onToolbar();\n }\n }\n return;\n }\n\n range.deleteContents();\n const tabNode = document.createTextNode('\\t');\n range.insertNode(tabNode);\n\n const r = document.createRange();\n r.setStartAfter(tabNode);\n r.collapse(true);\n sel.removeAllRanges(); sel.addRange(r);\n\n onContent(); onToolbar();\n}\n"]}
@@ -0,0 +1,2 @@
1
+ import { SelectionManager } from './selection';
2
+ export declare function insertList(type: 'ul' | 'ol', selection: SelectionManager): void;
@@ -0,0 +1,28 @@
1
+ export function insertList(type, selection) {
2
+ selection.restore();
3
+ if (!selection.lastRange)
4
+ return;
5
+ const list = document.createElement(type);
6
+ const frag = selection.lastRange.extractContents();
7
+ const temp = document.createElement('div');
8
+ temp.appendChild(frag);
9
+ Array.from(temp.childNodes).forEach(n => {
10
+ if (n.nodeType === Node.TEXT_NODE && !(n.textContent ?? '').trim())
11
+ return;
12
+ const li = document.createElement('li');
13
+ li.appendChild(n); // moves node
14
+ list.appendChild(li);
15
+ });
16
+ selection.lastRange.insertNode(list);
17
+ afterListEdit(selection, list);
18
+ }
19
+ function afterListEdit(selection, node) {
20
+ const range = document.createRange();
21
+ range.setStartAfter(node);
22
+ range.collapse(true);
23
+ const sel = window.getSelection();
24
+ sel?.removeAllRanges();
25
+ sel?.addRange(range);
26
+ selection.save();
27
+ }
28
+ //# sourceMappingURL=lists.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lists.js","sourceRoot":"","sources":["../../../../src/nile-rich-text-editor/rte-utils/lists.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,UAAU,CAAC,IAAiB,EAAE,SAA2B;IACvE,SAAS,CAAC,OAAO,EAAE,CAAC;IACpB,IAAI,CAAC,SAAS,CAAC,SAAS;QAAE,OAAO;IAEjC,MAAM,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAG,SAAS,CAAC,SAAS,CAAC,eAAe,EAAE,CAAC;IACnD,MAAM,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IAC3C,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;IAEvB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;QACtC,IAAI,CAAC,CAAC,QAAQ,KAAK,IAAI,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE;YAAE,OAAO;QAC3E,MAAM,EAAE,GAAG,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;QACxC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa;QAChC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;IACvB,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IACrC,aAAa,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;AACjC,CAAC;AAED,SAAS,aAAa,CAAC,SAA2B,EAAE,IAAU;IAC5D,MAAM,KAAK,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;IACrC,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IAC1B,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACrB,MAAM,GAAG,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC;IAClC,GAAG,EAAE,eAAe,EAAE,CAAC;IACvB,GAAG,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;IACrB,SAAS,CAAC,IAAI,EAAE,CAAC;AACnB,CAAC","sourcesContent":["import { SelectionManager } from './selection';\n\nexport function insertList(type: 'ul' | 'ol', selection: SelectionManager) {\n selection.restore();\n if (!selection.lastRange) return;\n\n const list = document.createElement(type);\n const frag = selection.lastRange.extractContents();\n const temp = document.createElement('div');\n temp.appendChild(frag);\n\n Array.from(temp.childNodes).forEach(n => {\n if (n.nodeType === Node.TEXT_NODE && !(n.textContent ?? '').trim()) return;\n const li = document.createElement('li');\n li.appendChild(n); // moves node\n list.appendChild(li);\n });\n\n selection.lastRange.insertNode(list);\n afterListEdit(selection, list);\n}\n\nfunction afterListEdit(selection: SelectionManager, node: Node) {\n const range = document.createRange();\n range.setStartAfter(node);\n range.collapse(true);\n const sel = window.getSelection();\n sel?.removeAllRanges();\n sel?.addRange(range);\n selection.save();\n}"]}
@@ -0,0 +1,17 @@
1
+ export declare class SelectionManager {
2
+ private host;
3
+ private onChange;
4
+ editorEl: HTMLElement;
5
+ lastRange: Range | null;
6
+ private handler;
7
+ constructor(args: {
8
+ host: HTMLElement;
9
+ editorEl: HTMLElement;
10
+ onChange: () => void;
11
+ });
12
+ start(): void;
13
+ stop(): void;
14
+ save(): void;
15
+ restore(): void;
16
+ focusAndRestore(): void;
17
+ }
@@ -0,0 +1,39 @@
1
+ export class SelectionManager {
2
+ constructor(args) {
3
+ this.lastRange = null;
4
+ this.host = args.host;
5
+ this.editorEl = args.editorEl;
6
+ this.onChange = args.onChange;
7
+ }
8
+ start() {
9
+ this.handler = () => {
10
+ const sel = document.getSelection();
11
+ if (!sel || sel.rangeCount === 0)
12
+ return;
13
+ const range = sel.getRangeAt(0);
14
+ if (this.editorEl.contains(range.commonAncestorContainer)) {
15
+ this.lastRange = range.cloneRange();
16
+ this.onChange();
17
+ }
18
+ };
19
+ document.addEventListener('selectionchange', this.handler, true);
20
+ }
21
+ stop() { if (this.handler)
22
+ document.removeEventListener('selectionchange', this.handler, true); }
23
+ save() {
24
+ const sel = window.getSelection();
25
+ if (sel && sel.rangeCount)
26
+ this.lastRange = sel.getRangeAt(0).cloneRange();
27
+ }
28
+ restore() {
29
+ if (!this.lastRange)
30
+ return;
31
+ const sel = document.getSelection();
32
+ if (!sel)
33
+ return;
34
+ sel.removeAllRanges();
35
+ sel.addRange(this.lastRange);
36
+ }
37
+ focusAndRestore() { this.editorEl?.focus(); this.restore(); }
38
+ }
39
+ //# sourceMappingURL=selection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selection.js","sourceRoot":"","sources":["../../../../src/nile-rich-text-editor/rte-utils/selection.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,gBAAgB;IAOzB,YAAY,IAAwE;QAH7E,cAAS,GAAiB,IAAI,CAAC;QAIpC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACtB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC9B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;IAChC,CAAC;IAED,KAAK;QACH,IAAI,CAAC,OAAO,GAAG,GAAG,EAAE;YAClB,MAAM,GAAG,GAAG,QAAQ,CAAC,YAAY,EAAE,CAAC;YACpC,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,UAAU,KAAK,CAAC;gBAAE,OAAO;YACzC,MAAM,KAAK,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YAChC,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,uBAAuB,CAAC,EAAE,CAAC;gBAC1D,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,UAAU,EAAE,CAAC;gBACpC,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,CAAC;QACH,CAAC,CAAC;QACF,QAAQ,CAAC,gBAAgB,CAAC,iBAAiB,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACnE,CAAC;IAED,IAAI,KAAK,IAAI,IAAI,CAAC,OAAO;QAAE,QAAQ,CAAC,mBAAmB,CAAC,iBAAiB,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IAEjG,IAAI;QACF,MAAM,GAAG,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC;QAClC,IAAI,GAAG,IAAI,GAAG,CAAC,UAAU;YAAE,IAAI,CAAC,SAAS,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC;IAC7E,CAAC;IAED,OAAO;QACL,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE,OAAO;QAC5B,MAAM,GAAG,GAAG,QAAQ,CAAC,YAAY,EAAE,CAAC;QAAC,IAAI,CAAC,GAAG;YAAE,OAAO;QACtD,GAAG,CAAC,eAAe,EAAE,CAAC;QAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACtD,CAAC;IAED,eAAe,KAAK,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;CAC9D","sourcesContent":["export class SelectionManager {\n private host: HTMLElement;\n private onChange: () => void;\n public editorEl: HTMLElement;\n public lastRange: Range | null = null;\n private handler!: () => void;\n \n constructor(args: { host: HTMLElement; editorEl: HTMLElement; onChange: () => void }) {\n this.host = args.host;\n this.editorEl = args.editorEl;\n this.onChange = args.onChange;\n }\n \n start() {\n this.handler = () => {\n const sel = document.getSelection();\n if (!sel || sel.rangeCount === 0) return;\n const range = sel.getRangeAt(0);\n if (this.editorEl.contains(range.commonAncestorContainer)) {\n this.lastRange = range.cloneRange();\n this.onChange();\n }\n };\n document.addEventListener('selectionchange', this.handler, true);\n }\n \n stop() { if (this.handler) document.removeEventListener('selectionchange', this.handler, true); }\n \n save() {\n const sel = window.getSelection();\n if (sel && sel.rangeCount) this.lastRange = sel.getRangeAt(0).cloneRange();\n }\n \n restore() {\n if (!this.lastRange) return;\n const sel = document.getSelection(); if (!sel) return;\n sel.removeAllRanges(); sel.addRange(this.lastRange);\n }\n \n focusAndRestore() { this.editorEl?.focus(); this.restore(); }\n }\n "]}
@@ -0,0 +1,28 @@
1
+ export declare class ToolbarController {
2
+ buttonMap: Map<string, HTMLElement[]>;
3
+ headingSelect: HTMLSelectElement | null;
4
+ fontSelect: HTMLSelectElement | null;
5
+ colorInput: HTMLInputElement | null;
6
+ bgColorInput: HTMLInputElement | null;
7
+ colorSwatchEl: HTMLElement | null;
8
+ bgSwatchEl: HTMLElement | null;
9
+ private editorEl;
10
+ private onCommand;
11
+ private onChange;
12
+ private setAlignment;
13
+ private setBlockTag;
14
+ private setFontFamily;
15
+ private setForeColor;
16
+ private setBackColor;
17
+ constructor(args: {
18
+ editorEl: HTMLElement;
19
+ onCommand: (cmd: string) => void;
20
+ onChange: () => void;
21
+ setAlignment: (a: 'left' | 'center' | 'right' | 'justify') => void;
22
+ setBlockTag: (t: string) => void;
23
+ setFontFamily: (ff: string) => void;
24
+ setForeColor: (c: string) => void;
25
+ setBackColor: (c: string) => void;
26
+ });
27
+ wire(tb: HTMLElement): void;
28
+ }
@@ -0,0 +1,161 @@
1
+ import { DEFAULT_ICONS } from './vars';
2
+ export class ToolbarController {
3
+ constructor(args) {
4
+ this.buttonMap = new Map();
5
+ this.headingSelect = null;
6
+ this.fontSelect = null;
7
+ this.colorInput = null;
8
+ this.bgColorInput = null;
9
+ this.colorSwatchEl = null;
10
+ this.bgSwatchEl = null;
11
+ this.editorEl = args.editorEl;
12
+ this.onCommand = args.onCommand;
13
+ this.onChange = args.onChange;
14
+ this.setAlignment = args.setAlignment;
15
+ this.setBlockTag = args.setBlockTag;
16
+ this.setFontFamily = args.setFontFamily;
17
+ this.setForeColor = args.setForeColor;
18
+ this.setBackColor = args.setBackColor;
19
+ }
20
+ wire(tb) {
21
+ // reset
22
+ this.buttonMap.clear();
23
+ this.headingSelect = null;
24
+ this.fontSelect = null;
25
+ this.colorInput = null;
26
+ this.bgColorInput = null;
27
+ this.colorSwatchEl = null;
28
+ this.bgSwatchEl = null;
29
+ Array.from(tb.children).forEach(child => {
30
+ const tag = child.tagName.toLowerCase();
31
+ if (tag === 'nile-rte-select' && child.getAttribute('type') === 'align') {
32
+ child.addEventListener('change', (e) => {
33
+ const alignment = e.detail;
34
+ this.setAlignment(alignment);
35
+ this.onChange();
36
+ });
37
+ return;
38
+ }
39
+ if (tag === 'nile-rte-toolbar-item') {
40
+ let btn = child.querySelector(':scope > nile-button');
41
+ const cmd = child.getAttribute('name') || '';
42
+ const label = child.getAttribute('label') || cmd;
43
+ const iconAttr = child.getAttribute('icon');
44
+ const authoredHasContent = child.innerHTML.trim().length > 0;
45
+ if (!btn) {
46
+ btn = document.createElement('nile-button');
47
+ btn.variant = 'tertiary';
48
+ btn.size = 'small';
49
+ }
50
+ if (iconAttr) {
51
+ btn.innerHTML = `<nile-icon name="${iconAttr}" aria-label="${label}"></nile-icon>`;
52
+ child.innerHTML = '';
53
+ }
54
+ else if (!authoredHasContent) {
55
+ const defaultIcon = DEFAULT_ICONS[cmd];
56
+ if (defaultIcon) {
57
+ btn.innerHTML = `<nile-icon name="${defaultIcon}" size="20" color="black" aria-label="${label}"></nile-icon>`;
58
+ }
59
+ else {
60
+ btn.textContent = label || cmd;
61
+ }
62
+ child.innerHTML = '';
63
+ }
64
+ else {
65
+ btn.innerHTML = child.innerHTML;
66
+ child.innerHTML = '';
67
+ }
68
+ if (!btn.isConnected)
69
+ child.appendChild(btn);
70
+ btn.setAttribute('aria-label', label);
71
+ btn.addEventListener('mousedown', e => e.preventDefault());
72
+ btn.addEventListener('click', () => this.onCommand(cmd));
73
+ const arr = this.buttonMap.get(cmd) ?? [];
74
+ arr.push(btn);
75
+ this.buttonMap.set(cmd, arr);
76
+ return;
77
+ }
78
+ if (tag === 'nile-rte-select') {
79
+ const type = child.getAttribute('type') || '';
80
+ child.addEventListener('change', (e) => {
81
+ const val = e.detail;
82
+ if (type === 'heading')
83
+ this.setBlockTag(val);
84
+ else if (type === 'font')
85
+ this.setFontFamily(val);
86
+ this.onChange();
87
+ });
88
+ return;
89
+ }
90
+ if (tag === 'nile-rte-color') {
91
+ const label = child.getAttribute('label') ?? 'Text color';
92
+ const value = child.getAttribute('value') ?? '#000000';
93
+ const mode = child.getAttribute('mode') ?? 'text';
94
+ let input = child.querySelector(':scope > input[type="color"]');
95
+ if (!input) {
96
+ input = document.createElement('input');
97
+ input.type = 'color';
98
+ input.style.position = 'absolute';
99
+ input.style.opacity = '0';
100
+ input.style.pointerEvents = 'none';
101
+ child.appendChild(input);
102
+ }
103
+ input.title = label;
104
+ input.value = value;
105
+ let trigger = child.querySelector(':scope > button.rte-color-trigger');
106
+ if (!trigger) {
107
+ trigger = document.createElement('button');
108
+ trigger.type = 'button';
109
+ trigger.className = 'rte-color-trigger';
110
+ trigger.setAttribute('aria-label', label);
111
+ if (mode === 'background') {
112
+ trigger.innerHTML = `<span class="swatch-box" aria-hidden="true"></span>`;
113
+ }
114
+ else {
115
+ trigger.innerHTML = `
116
+ <span class="glyph-stack" aria-hidden="true">
117
+ <span class="glyph">A</span>
118
+ <span class="underline"></span>
119
+ </span>`;
120
+ }
121
+ child.appendChild(trigger);
122
+ }
123
+ const underline = trigger.querySelector('.underline');
124
+ const square = trigger.querySelector('.swatch-box');
125
+ if (mode === 'background') {
126
+ this.bgColorInput = input;
127
+ this.bgSwatchEl = square;
128
+ if (this.bgSwatchEl)
129
+ this.bgSwatchEl.style.backgroundColor = input.value;
130
+ }
131
+ else {
132
+ this.colorInput = input;
133
+ this.colorSwatchEl = underline;
134
+ if (this.colorSwatchEl)
135
+ this.colorSwatchEl.style.backgroundColor = input.value;
136
+ }
137
+ trigger.addEventListener('click', (e) => {
138
+ e.preventDefault();
139
+ // Caller will handle selection focus before invoking controller events
140
+ input.click();
141
+ });
142
+ input.addEventListener('input', () => {
143
+ if (mode === 'background') {
144
+ this.setBackColor(input.value);
145
+ if (this.bgSwatchEl)
146
+ this.bgSwatchEl.style.backgroundColor = input.value;
147
+ }
148
+ else {
149
+ this.setForeColor(input.value);
150
+ if (this.colorSwatchEl)
151
+ this.colorSwatchEl.style.backgroundColor = input.value;
152
+ }
153
+ this.onChange();
154
+ });
155
+ trigger.addEventListener('mousedown', e => e.preventDefault());
156
+ input.addEventListener('mousedown', e => e.preventDefault());
157
+ }
158
+ });
159
+ }
160
+ }
161
+ //# sourceMappingURL=toolbar.js.map