@aquera/nile-elements 0.1.67-beta-1.5 → 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 (55) hide show
  1. package/demo/index.html +13 -6
  2. package/dist/index.js +51 -48
  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 +11 -8
  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 +11 -8
  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.js +33 -25
  16. package/dist/src/nile-rich-text-editor/nile-rich-text-editor.js.map +1 -1
  17. package/dist/src/nile-rich-text-editor/nile-rte-select.js +62 -57
  18. package/dist/src/nile-rich-text-editor/nile-rte-select.js.map +1 -1
  19. package/dist/src/nile-rich-text-editor/rte-utils/content.d.ts +2 -0
  20. package/dist/src/nile-rich-text-editor/rte-utils/content.js +25 -0
  21. package/dist/src/nile-rich-text-editor/rte-utils/content.js.map +1 -0
  22. package/dist/src/nile-rich-text-editor/rte-utils/css.d.ts +1 -0
  23. package/dist/src/nile-rich-text-editor/rte-utils/css.js +9 -0
  24. package/dist/src/nile-rich-text-editor/rte-utils/css.js.map +1 -0
  25. package/dist/src/nile-rich-text-editor/rte-utils/dom.d.ts +2 -0
  26. package/dist/src/nile-rich-text-editor/rte-utils/dom.js +48 -0
  27. package/dist/src/nile-rich-text-editor/rte-utils/dom.js.map +1 -0
  28. package/dist/src/nile-rich-text-editor/rte-utils/formatting.d.ts +2 -0
  29. package/dist/src/nile-rich-text-editor/rte-utils/formatting.js +69 -0
  30. package/dist/src/nile-rich-text-editor/rte-utils/formatting.js.map +1 -0
  31. package/dist/src/nile-rich-text-editor/rte-utils/keys.d.ts +2 -0
  32. package/dist/src/nile-rich-text-editor/rte-utils/keys.js +38 -0
  33. package/dist/src/nile-rich-text-editor/rte-utils/keys.js.map +1 -0
  34. package/dist/src/nile-rich-text-editor/rte-utils/lists.d.ts +2 -0
  35. package/dist/src/nile-rich-text-editor/rte-utils/lists.js +28 -0
  36. package/dist/src/nile-rich-text-editor/rte-utils/lists.js.map +1 -0
  37. package/dist/src/nile-rich-text-editor/rte-utils/selection.d.ts +17 -0
  38. package/dist/src/nile-rich-text-editor/rte-utils/selection.js +39 -0
  39. package/dist/src/nile-rich-text-editor/rte-utils/selection.js.map +1 -0
  40. package/dist/src/nile-rich-text-editor/rte-utils/toolbar.d.ts +28 -0
  41. package/dist/src/nile-rich-text-editor/rte-utils/toolbar.js +161 -0
  42. package/dist/src/nile-rich-text-editor/rte-utils/toolbar.js.map +1 -0
  43. package/dist/src/nile-rich-text-editor/rte-utils/toolbarState.d.ts +13 -0
  44. package/dist/src/nile-rich-text-editor/rte-utils/toolbarState.js +119 -0
  45. package/dist/src/nile-rich-text-editor/rte-utils/toolbarState.js.map +1 -0
  46. package/dist/src/nile-rich-text-editor/rte-utils/vars.d.ts +1 -0
  47. package/dist/src/nile-rich-text-editor/rte-utils/vars.js +14 -0
  48. package/dist/src/nile-rich-text-editor/rte-utils/vars.js.map +1 -0
  49. package/dist/src/nile-rich-text-editor/utils.js.map +1 -1
  50. package/dist/tsconfig.tsbuildinfo +1 -1
  51. package/package.json +1 -1
  52. package/src/nile-rich-text-editor/nile-rich-text-editor.css.ts +11 -8
  53. package/src/nile-rich-text-editor/nile-rich-text-editor.ts +46 -26
  54. package/src/nile-rich-text-editor/nile-rte-select.ts +178 -173
  55. package/src/nile-rich-text-editor/utils.ts +342 -341
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Webcomponent nile-elements following open-wc recommendations",
4
4
  "license": "MIT",
5
5
  "author": "nile-elements",
6
- "version": "0.1.67-beta-1.5",
6
+ "version": "0.1.67-beta-1.6",
7
7
  "main": "dist/src/index.js",
8
8
  "type": "module",
9
9
  "module": "dist/src/index.js",
@@ -19,7 +19,7 @@ nile-rte-toolbar-item > nile-button::part(base) {
19
19
 
20
20
 
21
21
  .toolbar, nile-rte-toolbar {
22
- display:flex; align-items:center; gap:8px; padding:8px;
22
+ display:flex; align-items:center; gap:6px; padding:8px;
23
23
  border:1px solid #e5e7eb; border-bottom:none; border-radius:8px 8px 0 0; background:#fff;
24
24
  }
25
25
 
@@ -66,14 +66,17 @@ font-weight: bold;}
66
66
  display: inline-flex;
67
67
  align-items: center;
68
68
  justify-content: center;
69
- height: 28px;
70
- padding: 0 8px;
71
- border: 1px solid var(--nile-color-border, #d9d9d9);
69
+ /* border: 1px solid var(--nile-color-border, #d9d9d9); */
72
70
  border-radius: 6px;
73
71
  background: #fff;
74
72
  cursor: pointer;
75
- }
73
+ border:none;
74
+
76
75
 
76
+ }
77
+ nile-button.rte-color-trigger::part(base){
78
+ width:32px; height:32px; padding:0px 6px;
79
+ }
77
80
  .rte-color-trigger .glyph-stack {
78
81
  display: grid; /* stack vertically */
79
82
  grid-auto-rows: max-content;
@@ -85,17 +88,17 @@ font-weight: bold;}
85
88
  .rte-color-trigger .glyph {
86
89
  font-size: 14px;
87
90
  line-height: 1;
88
- margin-bottom: 2px; /* little breathing space above underline */
91
+ margin-bottom: 2px;
89
92
  }
90
93
 
91
94
  .rte-color-trigger .underline {
92
95
  width: 18px;
93
96
  height: 3px;
94
97
  border-radius: 2px;
95
- background: currentColor; /* we override via JS with backgroundColor */
98
+ background: currentColor;
96
99
  }
97
100
 
98
- /* (unchanged) highlight square */
101
+
99
102
  .rte-color-trigger .swatch-box {
100
103
  width: 18px;
101
104
  height: 16px;
@@ -33,8 +33,8 @@ const DEFAULT_ICONS: Record<string, string> = {
33
33
  center: 'format_align_middle',
34
34
  right: 'format_align_right',
35
35
  justify: 'format_align_justify',
36
- ul: 'nile-ul',
37
- ol: 'nile-ol',
36
+ ul: 'format_list_bulleted',
37
+ ol: 'format_list_numbered',
38
38
  clear: 'error',
39
39
  };
40
40
 
@@ -355,28 +355,28 @@ private bgSwatchEl: HTMLElement | null = null;
355
355
  input.title = label;
356
356
  input.value = value;
357
357
 
358
- // Build a custom trigger that shows the current color
359
- let trigger = child.querySelector(':scope > button.rte-color-trigger') as HTMLButtonElement | null;
358
+ let trigger = child.querySelector(':scope > nile-button') as HTMLElement | null;
360
359
  if (!trigger) {
361
- trigger = document.createElement('button');
362
- trigger.type = 'button';
363
- trigger.className = 'rte-color-trigger';
364
- trigger.setAttribute('aria-label', label);
365
-
360
+ const nb = document.createElement('nile-button');
361
+ (nb as any).variant = 'ghost';
362
+ nb.className = 'rte-color-trigger';
363
+ nb.setAttribute('aria-label', label);
364
+
366
365
  if (mode === 'background') {
367
- trigger.innerHTML = `
368
- <span class="swatch-box" aria-hidden="true"></span>
369
- `;
366
+ nb.innerHTML = `<span class="swatch-box" aria-hidden="true"></span>`;
370
367
  } else {
371
- trigger.innerHTML = `
372
- <span class="glyph-stack" aria-hidden="true">
373
- <span class="glyph">A</span>
374
- <span class="underline"></span>
375
- </span>
368
+ nb.innerHTML = `
369
+ <span class="glyph-stack" aria-hidden="true">
370
+ <span class="glyph">A</span>
371
+ <span class="underline"></span>
372
+ </span>
376
373
  `;
377
374
  }
378
- child.appendChild(trigger);
375
+
376
+ child.appendChild(nb);
377
+ trigger = nb;
379
378
  }
379
+
380
380
 
381
381
  // Cache swatch elements to update later
382
382
  const underline = trigger.querySelector('.underline') as HTMLElement | null;
@@ -672,33 +672,52 @@ private ensureAtLeastOneParagraph() {
672
672
  if (!this.editorEl) return;
673
673
  this.ensureAtLeastOneParagraph();
674
674
 
675
- // Clone content for safe manipulation
675
+
676
676
  const clone = this.editorEl.cloneNode(true) as HTMLElement;
677
677
 
678
- // Walk the original DOM and the clone in parallel
678
+
679
679
  const origWalker = document.createTreeWalker(this.editorEl, NodeFilter.SHOW_ELEMENT);
680
680
  const cloneWalker = document.createTreeWalker(clone, NodeFilter.SHOW_ELEMENT);
681
681
 
682
+
683
+ const importantProps = [
684
+ 'font-weight',
685
+ 'font-style',
686
+ 'text-decoration',
687
+ 'color',
688
+ 'background-color',
689
+ 'font-size',
690
+ 'font-family',
691
+ 'text-align',
692
+ 'line-height',
693
+ 'letter-spacing',
694
+ 'white-space',
695
+ 'vertical-align'
696
+ ];
697
+
682
698
  while (origWalker.nextNode() && cloneWalker.nextNode()) {
683
699
  const origEl = origWalker.currentNode as HTMLElement;
684
700
  const cloneEl = cloneWalker.currentNode as HTMLElement;
685
701
  const computed = window.getComputedStyle(origEl);
686
702
 
687
- // Dump *all* computed styles into a single inline style attribute
688
- const cssText = Array.from(computed)
703
+
704
+ const cssText = importantProps
689
705
  .map(prop => `${prop}:${computed.getPropertyValue(prop)}`)
690
706
  .join(';');
691
707
 
692
- cloneEl.setAttribute('style', cssText);
708
+
709
+ if (cssText.trim()) {
710
+ cloneEl.setAttribute('style', cssText);
711
+ }
693
712
  }
694
713
 
695
- // Store the fully inlined HTML
714
+
696
715
  this.content = clone.innerHTML;
697
716
 
698
- // Live preview updates
717
+
699
718
  if (this.previewEl) this.previewEl.innerHTML = this.content;
700
719
 
701
- // Emit event with full inline styles
720
+
702
721
  this.dispatchEvent(new CustomEvent('content-changed', {
703
722
  detail: { content: this.content },
704
723
  bubbles: true,
@@ -708,6 +727,7 @@ private ensureAtLeastOneParagraph() {
708
727
 
709
728
 
710
729
 
730
+
711
731
  }
712
732
 
713
733
  declare global {
@@ -1,195 +1,180 @@
1
- // nile-rte-select.ts
2
- import { LitElement, html } from 'lit';
3
- import { customElement, property, state } from 'lit/decorators.js';
4
-
5
- type HeadingTag = 'p' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
6
- type GenericOption = { value: string; label?: string; icon?: string };
7
- type HeadingOption = { value: HeadingTag; label?: string; icon?: string };
8
- type NormalizedOption = { value: string; label: string; icon?: string };
9
-
10
- const HEADING_ALLOWLIST: ReadonlySet<HeadingTag> = new Set([
11
- 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'
12
- ]);
13
-
14
- function isHeadingTag(v: string): v is HeadingTag {
15
- return HEADING_ALLOWLIST.has(v as HeadingTag);
1
+ // nile-rte-select.ts
2
+ import { LitElement, html } from 'lit';
3
+ import { customElement, property, state } from 'lit/decorators.js';
4
+
5
+ type HeadingTag = 'p' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
6
+ type GenericOption = { value: string; label?: string; icon?: string };
7
+ type HeadingOption = { value: HeadingTag; label?: string; icon?: string };
8
+ type NormalizedOption = { value: string; label: string; icon?: string };
9
+
10
+ const HEADING_ALLOWLIST: ReadonlySet<HeadingTag> = new Set([
11
+ 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'
12
+ ]);
13
+
14
+ function isHeadingTag(v: string): v is HeadingTag {
15
+ return HEADING_ALLOWLIST.has(v as HeadingTag);
16
+ }
17
+
18
+ @customElement('nile-rte-select')
19
+ export class NileRteSelect extends LitElement {
20
+ protected createRenderRoot() { return this; }
21
+
22
+ /** 'heading' | 'font' | 'align' */
23
+ @property({ type: String }) type = '';
24
+
25
+ /** JSON: [{ value, label?, icon? }, ...] (attribute-based; runtime-validated) */
26
+ @property({ type: String }) options = '[]';
27
+
28
+ /** Programmatic options (preferred for TS safety). */
29
+ @property({ attribute: false })
30
+ optionsObj?: Array<GenericOption | HeadingOption>;
31
+
32
+ /** Fallback label for trigger (e.g., "Align") */
33
+ @property({ type: String }) label = '';
34
+
35
+ @state() private selectedValue = '';
36
+
37
+ private mapAlignIcon(v: string) {
38
+ const map: Record<string,string> = {
39
+ left: 'format_align_left',
40
+ center: 'format_align_middle',
41
+ right: 'format_align_right',
42
+ justify: 'format_align_justify'
43
+ };
44
+ return map[v] || 'format_align_left';
16
45
  }
17
46
 
18
- @customElement('nile-rte-select')
19
- export class NileRteSelect extends LitElement {
20
- protected createRenderRoot() { return this; }
21
-
22
- /** 'heading' | 'font' | 'align' */
23
- @property({ type: String }) type = '';
24
-
25
- /** JSON: [{ value, label?, icon? }, ...] (attribute-based; runtime-validated) */
26
- @property({ type: String }) options = '[]';
27
-
28
- /** Programmatic options (preferred for TS safety). */
29
- @property({ attribute: false })
30
- optionsObj?: Array<GenericOption | HeadingOption>;
47
+ private get parsedOptions(): NormalizedOption[] {
48
+ // Prefer programmatic options if present (gives TS compile-time checks)
49
+ const source: unknown = this.optionsObj ?? this.options;
50
+
51
+ const rawArray: any[] = (() => {
52
+ if (Array.isArray(source)) return source;
53
+ try { return JSON.parse(String(source)); } catch { return []; }
54
+ })();
55
+
56
+ // Normalize to consistent shape
57
+ let items: NormalizedOption[] = rawArray.map((o: any) => {
58
+ const value: string = o?.value ?? o;
59
+ const label: string = o?.label ?? o?.value ?? o;
60
+ const icon: string | undefined =
61
+ o?.icon ?? (this.type === 'align' ? this.mapAlignIcon(String(value)) : undefined);
62
+ return { value, label, icon };
63
+ });
64
+
65
+ // If type is heading, enforce allowlist (runtime validation)
66
+ if (this.type === 'heading') {
67
+ const before = items.length;
68
+ items = items.filter(i => isHeadingTag(i.value));
69
+ if (items.length !== before) {
70
+ }
71
+ // If current selection is invalid for heading, reset
72
+ if (this.selectedValue && !isHeadingTag(this.selectedValue)) {
73
+ this.selectedValue = '';
74
+ }
75
+ }
31
76
 
32
- /** Fallback label for trigger (e.g., "Align") */
33
- @property({ type: String }) label = '';
77
+ return items;
78
+ }
34
79
 
35
- @state() private selectedValue = '';
80
+ private ensureDefault() {
81
+ if (!this.selectedValue) {
82
+ const first = this.parsedOptions[0];
83
+ if (first) this.selectedValue = first.value;
84
+ }
85
+ }
36
86
 
37
- private mapAlignIcon(v: string) {
38
- const map: Record<string,string> = {
39
- left: 'format_align_left',
40
- center: 'format_align_middle',
41
- right: 'format_align_right',
42
- justify: 'format_align_justify'
43
- };
44
- return map[v] || 'align-left';
87
+ private onSelect(value: string) {
88
+ if (this.type === 'heading' && !isHeadingTag(value)) {
89
+ console.warn(`[nile-rte-select] Ignoring invalid heading value: ${value}`);
90
+ return;
45
91
  }
92
+ this.selectedValue = value;
93
+ this.dispatchEvent(new CustomEvent('change', {
94
+ detail: value, bubbles: true, composed: true
95
+ }));
96
+ }
46
97
 
47
- private get parsedOptions(): NormalizedOption[] {
48
- // Prefer programmatic options if present (gives TS compile-time checks)
49
- const source: unknown = this.optionsObj ?? this.options;
50
-
51
- const rawArray: any[] = (() => {
52
- if (Array.isArray(source)) return source;
53
- try { return JSON.parse(String(source)); } catch { return []; }
54
- })();
55
-
56
- // Normalize to consistent shape
57
- let items: NormalizedOption[] = rawArray.map((o: any) => {
58
- const value: string = o?.value ?? o;
59
- const label: string = o?.label ?? o?.value ?? o;
60
- const icon: string | undefined =
61
- o?.icon ?? (this.type === 'align' ? this.mapAlignIcon(String(value)) : undefined);
62
- return { value, label, icon };
63
- });
64
-
65
- // If type is heading, enforce allowlist (runtime validation)
66
- if (this.type === 'heading') {
67
- const before = items.length;
68
- items = items.filter(i => isHeadingTag(i.value));
69
- if (items.length !== before) {
70
- }
71
- // If current selection is invalid for heading, reset
72
- if (this.selectedValue && !isHeadingTag(this.selectedValue)) {
73
- this.selectedValue = '';
74
- }
75
- }
98
+ connectedCallback(): void {
99
+ super.connectedCallback();
100
+ this.injectLocalStyles();
101
+ }
76
102
 
77
- return items;
78
- }
103
+ private injectLocalStyles() {
104
+ if (this.querySelector('style[data-rte-select-style]')) return;
79
105
 
80
- private ensureDefault() {
81
- if (!this.selectedValue) {
82
- const first = this.parsedOptions[0];
83
- if (first) this.selectedValue = first.value;
106
+ const style = document.createElement('style');
107
+ style.setAttribute('data-rte-select-style', 'true');
108
+ style.textContent = `
109
+ nile-menu.rte-align-menu::part(menu__items-wrapper) {
110
+ display: flex;
84
111
  }
85
- }
86
-
87
- private onSelect(value: string) {
88
- if (this.type === 'heading' && !isHeadingTag(value)) {
89
- console.warn(`[nile-rte-select] Ignoring invalid heading value: ${value}`);
90
- return;
112
+ nile-menu.rte-align-menu,
113
+ nile-menu.rte-default-menu {
114
+ margin-top: 0px;
91
115
  }
92
- this.selectedValue = value;
93
- this.dispatchEvent(new CustomEvent('change', {
94
- detail: value, bubbles: true, composed: true
95
- }));
96
- }
116
+ nile-button.rte-align-trigger::part(base),
117
+ nile-button.rte-default-trigger::part(base) {
118
+ min-width: 32px;
119
+ height: 32px;
120
+ padding: 0px 6px;
121
+ box-shadow: none;
122
+ }
123
+ nile-button.rte-align-trigger::part(base) {
124
+
97
125
 
98
- connectedCallback(): void {
99
- super.connectedCallback();
100
- this.injectLocalStyles();
101
- }
126
+ border: none;
127
+ }
128
+ `;
129
+ this.insertBefore(style, this.firstChild);
130
+ }
102
131
 
103
- private injectLocalStyles() {
104
- if (this.querySelector('style[data-rte-select-style]')) return;
105
-
106
- const style = document.createElement('style');
107
- style.setAttribute('data-rte-select-style', 'true');
108
- style.textContent = `
109
- nile-menu.rte-align-menu::part(menu__items-wrapper) {
110
- display: flex;
111
- }
112
- nile-menu.rte-align-menu,
113
- nile-menu.rte-default-menu {
114
- margin-top: 0px;
115
- }
116
- nile-button.rte-align-trigger::part(base),
117
- nile-button.rte-default-trigger::part(base) {
118
- min-width: 32px;
119
- height: 32px;
120
- padding: 0px 6px;
121
- box-shadow: none;
122
- }
123
- `;
124
- this.insertBefore(style, this.firstChild);
125
- }
132
+ render() {
133
+ const opts = this.parsedOptions;
134
+ this.ensureDefault();
135
+ const current = opts.find(o => o.value === this.selectedValue);
126
136
 
127
- render() {
128
- const opts = this.parsedOptions;
129
- this.ensureDefault();
130
- const current = opts.find(o => o.value === this.selectedValue);
131
-
132
- // ► Align: icon-only items + icon trigger
133
- if (this.type === 'align') {
134
- const trigger = current?.icon
135
- ? html`<nile-icon name="${current.icon}"></nile-icon>`
136
- : (this.label || 'Align');
137
-
138
- return html`
139
- <nile-dropdown class="rte-align-dd">
140
- <nile-button slot="trigger" variant="tertiary" class="rte-align-trigger">
141
- ${trigger}
142
- </nile-button>
143
- <nile-menu class="rte-align-menu">
144
- ${opts.map(o => html`
145
- <nile-menu-item
146
- class="rte-align-item"
147
- ?active=${o.value === this.selectedValue}
148
- @click=${() => this.onSelect(o.value)}>
149
- <nile-icon name="${o.icon}"></nile-icon>
150
- </nile-menu-item>
151
- `)}
152
- </nile-menu>
153
- </nile-dropdown>
154
- `;
155
- }
137
+ // ► Align: icon-only items + icon trigger
138
+ if (this.type === 'align') {
139
+ const trigger = current?.icon
140
+ ? html`<nile-icon name="${current.icon}"></nile-icon>`
141
+ : (this.label || 'Align');
156
142
 
157
- // ► Font: show labels, preview fonts in items and trigger
158
- if (this.type === 'font') {
159
- const triggerText = current?.label || this.label || 'Font';
160
- return html`
161
- <nile-dropdown class="rte-default-dd">
162
- <nile-button
163
- slot="trigger"
164
- variant="tertiary"
165
- class="rte-default-trigger"
166
- style="font-family: ${current?.value || 'inherit'}">
167
- ${triggerText} <nile-icon name="arrowdown"></nile-icon>
168
- </nile-button>
169
- <nile-menu class="rte-default-menu">
170
- ${opts.map(o => html`
171
- <nile-menu-item
172
- style="font-family: ${o.value}"
173
- ?active=${o.value === this.selectedValue}
174
- @click=${() => this.onSelect(o.value)}>
175
- ${o.label}
176
- </nile-menu-item>
177
- `)}
178
- </nile-menu>
179
- </nile-dropdown>
180
- `;
181
- }
143
+ return html`
144
+ <nile-dropdown class="rte-align-dd">
145
+ <nile-button slot="trigger" variant="tertiary" class="rte-align-trigger">
146
+ ${trigger}
147
+ </nile-button>
148
+ <nile-menu class="rte-align-menu">
149
+ ${opts.map(o => html`
150
+ <nile-menu-item
151
+ class="rte-align-item"
152
+ ?active=${o.value === this.selectedValue}
153
+ @click=${() => this.onSelect(o.value)}>
154
+ <nile-icon name="${o.icon}"></nile-icon>
155
+ </nile-menu-item>
156
+ `)}
157
+ </nile-menu>
158
+ </nile-dropdown>
159
+ `;
160
+ }
182
161
 
183
- // ► Default (e.g., heading): text items; heading values are validated already
184
- const triggerText = current?.label || this.label || 'Select';
162
+ // ► Font: show labels, preview fonts in items and trigger
163
+ if (this.type === 'font') {
164
+ const triggerText = current?.label || this.label || 'Font';
185
165
  return html`
186
166
  <nile-dropdown class="rte-default-dd">
187
- <nile-button slot="trigger" variant="tertiary" class="rte-default-trigger">
167
+ <nile-button
168
+ slot="trigger"
169
+ variant="tertiary"
170
+ class="rte-default-trigger"
171
+ style="font-family: ${current?.value || 'inherit'}">
188
172
  ${triggerText} <nile-icon name="arrowdown"></nile-icon>
189
173
  </nile-button>
190
174
  <nile-menu class="rte-default-menu">
191
175
  ${opts.map(o => html`
192
176
  <nile-menu-item
177
+ style="font-family: ${o.value}"
193
178
  ?active=${o.value === this.selectedValue}
194
179
  @click=${() => this.onSelect(o.value)}>
195
180
  ${o.label}
@@ -199,10 +184,30 @@
199
184
  </nile-dropdown>
200
185
  `;
201
186
  }
187
+
188
+ // ► Default (e.g., heading): text items; heading values are validated already
189
+ const triggerText = current?.label || this.label || 'Select';
190
+ return html`
191
+ <nile-dropdown class="rte-default-dd">
192
+ <nile-button slot="trigger" variant="tertiary" class="rte-default-trigger">
193
+ ${triggerText} <nile-icon name="arrowdown"></nile-icon>
194
+ </nile-button>
195
+ <nile-menu class="rte-default-menu">
196
+ ${opts.map(o => html`
197
+ <nile-menu-item
198
+ ?active=${o.value === this.selectedValue}
199
+ @click=${() => this.onSelect(o.value)}>
200
+ ${o.label}
201
+ </nile-menu-item>
202
+ `)}
203
+ </nile-menu>
204
+ </nile-dropdown>
205
+ `;
202
206
  }
207
+ }
203
208
 
204
- declare global {
205
- interface HTMLElementTagNameMap {
206
- 'nile-rte-select': NileRteSelect;
207
- }
209
+ declare global {
210
+ interface HTMLElementTagNameMap {
211
+ 'nile-rte-select': NileRteSelect;
208
212
  }
213
+ }