@unicef-polymer/etools-form-builder 3.1.2 → 3.1.3

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.
@@ -12,6 +12,7 @@ export declare abstract class AbstractFieldBaseClass<T> extends LitElement {
12
12
  placeholder: string;
13
13
  name: string;
14
14
  value: T | null;
15
+ showRichEditor: boolean;
15
16
  validators: FieldValidator[];
16
17
  touched: boolean;
17
18
  set defaultValue(value: any);
@@ -27,6 +27,7 @@ export class AbstractFieldBaseClass extends LitElement {
27
27
  this.placeholder = '';
28
28
  this.name = '';
29
29
  this.value = null;
30
+ this.showRichEditor = false;
30
31
  this.validators = [];
31
32
  this.touched = false;
32
33
  this._readonly = false;
@@ -97,7 +98,6 @@ export class AbstractFieldBaseClass extends LitElement {
97
98
  }
98
99
 
99
100
  :host(.wide) .question {
100
- margin-bottom: -8px;
101
101
  min-height: 0;
102
102
  }
103
103
 
@@ -197,3 +197,6 @@ __decorate([
197
197
  __decorate([
198
198
  property()
199
199
  ], AbstractFieldBaseClass.prototype, "value", void 0);
200
+ __decorate([
201
+ property({ type: Boolean })
202
+ ], AbstractFieldBaseClass.prototype, "showRichEditor", void 0);
@@ -16,7 +16,7 @@ export declare class FieldRendererComponent extends LitElement {
16
16
  defaultValue: any;
17
17
  render(): TemplateResult;
18
18
  renderField(blueprintField: BlueprintField): TemplateResult;
19
- renderStandardField({ input_type, label, help_text, required, placeholder, styling, name }: BlueprintField, isMandatory?: boolean): TemplateResult;
19
+ renderStandardField({ input_type, label, help_text, required, placeholder, styling, name }: BlueprintField, isMandatory?: boolean, isAdditionalField?: boolean): TemplateResult;
20
20
  renderTooltip(isMandatory: boolean): "" | TemplateResult<1>;
21
21
  renderRepeatableField({ input_type, label, help_text, required, placeholder, styling }: BlueprintField, isMandatory?: boolean): TemplateResult;
22
22
  renderFieldLabel(label: string, helperText: string, isMandatory?: boolean): TemplateResult;
@@ -23,7 +23,8 @@ let FieldRendererComponent = class FieldRendererComponent extends LitElement {
23
23
  return this.renderField(this.field);
24
24
  }
25
25
  renderField(blueprintField) {
26
- const additionalClass = blueprintField.styling.includes(StructureTypes.ADDITIONAL)
26
+ const isAdditionalField = blueprintField.styling.includes(StructureTypes.ADDITIONAL);
27
+ const additionalClass = isAdditionalField
27
28
  ? `additional-field ${blueprintField.name} `
28
29
  : `${blueprintField.name} `;
29
30
  const wideClass = blueprintField.styling.includes(StructureTypes.WIDE) ? 'wide-field-container ' : '';
@@ -34,11 +35,11 @@ let FieldRendererComponent = class FieldRendererComponent extends LitElement {
34
35
  <div class="${`${additionalClass}${wideClass}${mandatoryClass}finding-container`}">
35
36
  ${blueprintField.repeatable
36
37
  ? this.renderRepeatableField(blueprintField, !!mandatoryClass)
37
- : this.renderStandardField(blueprintField, !!mandatoryClass)}
38
+ : this.renderStandardField(blueprintField, !!mandatoryClass, isAdditionalField)}
38
39
  </div>
39
40
  `;
40
41
  }
41
- renderStandardField({ input_type, label, help_text, required, placeholder, styling, name }, isMandatory = false) {
42
+ renderStandardField({ input_type, label, help_text, required, placeholder, styling, name }, isMandatory = false, isAdditionalField = false) {
42
43
  var _a, _b, _c, _d;
43
44
  const isWide = styling.includes(StructureTypes.WIDE);
44
45
  switch (input_type) {
@@ -54,6 +55,7 @@ let FieldRendererComponent = class FieldRendererComponent extends LitElement {
54
55
  .validators="${this.validations}"
55
56
  .errorMessage="${this.errorMessage}"
56
57
  .defaultValue="${(_a = this.field) === null || _a === void 0 ? void 0 : _a.default_value}"
58
+ .showRichEditor="${isAdditionalField}"
57
59
  >
58
60
  ${this.renderFieldLabel(label, help_text, isMandatory)}
59
61
  </text-field>
@@ -1,8 +1,11 @@
1
- import { CSSResultArray, TemplateResult } from 'lit';
1
+ import { CSSResultArray, PropertyValues, TemplateResult } from 'lit';
2
2
  import { BaseField } from './base-field';
3
3
  import '@unicef-polymer/etools-unicef/src/etools-input/etools-textarea';
4
+ import '../../rich-editor/rich-text';
4
5
  export declare class TextField extends BaseField<string> {
6
+ protected originalValue: string | null;
5
7
  protected controlTemplate(): TemplateResult;
8
+ updated(changedProperties: PropertyValues): void;
6
9
  protected customValidation(): string | null;
7
10
  static get styles(): CSSResultArray;
8
11
  }
@@ -1,26 +1,51 @@
1
1
  import { __decorate } from "tslib";
2
2
  import { css, html } from 'lit';
3
- import { customElement } from 'lit/decorators.js';
3
+ import { customElement, property } from 'lit/decorators.js';
4
4
  import { BaseField } from './base-field';
5
5
  import '@unicef-polymer/etools-unicef/src/etools-input/etools-textarea';
6
+ import '../../rich-editor/rich-text';
6
7
  let TextField = class TextField extends BaseField {
8
+ constructor() {
9
+ super(...arguments);
10
+ this.originalValue = null;
11
+ }
7
12
  controlTemplate() {
8
- return html `
9
- <etools-textarea
10
- id="otherInfo"
11
- class="no-padding-left"
12
- no-label-float
13
- placeholder="${this.isReadonly ? '—' : this.placeholder}"
14
- .value="${this.value}"
15
- @value-changed="${({ detail }) => this.valueChanged(detail.value)}"
16
- @focus="${() => (this.touched = true)}"
17
- ?readonly="${this.isReadonly}"
18
- ?invalid="${this.errorMessage}"
19
- name="${this.name}"
20
- error-message="${this.errorMessage}"
21
- >
22
- </etools-textarea>
23
- `;
13
+ return this.showRichEditor
14
+ ? html `<div class="finding-container no-padding-left">
15
+ <rich-text
16
+ .value="${this.originalValue}"
17
+ ?readonly="${this.isReadonly}"
18
+ @editor-changed="${({ detail }) => {
19
+ if (detail.value !== this.value) {
20
+ this.valueChanged(detail.value);
21
+ }
22
+ }}"
23
+ ></rich-text>
24
+ </div>`
25
+ : html `
26
+ <etools-textarea
27
+ id="otherInfo"
28
+ class="no-padding-left"
29
+ no-label-float
30
+ placeholder="${this.isReadonly ? '—' : this.placeholder}"
31
+ .value="${this.value}"
32
+ @value-changed="${({ detail }) => this.valueChanged(detail.value)}"
33
+ @focus="${() => (this.touched = true)}"
34
+ ?readonly="${this.isReadonly}"
35
+ ?invalid="${this.errorMessage}"
36
+ name="${this.name}"
37
+ error-message="${this.errorMessage}"
38
+ >
39
+ </etools-textarea>
40
+ `;
41
+ }
42
+ updated(changedProperties) {
43
+ super.updated(changedProperties);
44
+ // set control value only at the beginning with a proxy param (originalValue),
45
+ // avoid requestUpdate when .value change because will move carret
46
+ if (changedProperties.has('value') && this.originalValue === null) {
47
+ this.originalValue = this.value;
48
+ }
24
49
  }
25
50
  customValidation() {
26
51
  return null;
@@ -42,6 +67,9 @@ let TextField = class TextField extends BaseField {
42
67
  ];
43
68
  }
44
69
  };
70
+ __decorate([
71
+ property()
72
+ ], TextField.prototype, "originalValue", void 0);
45
73
  TextField = __decorate([
46
74
  customElement('text-field')
47
75
  ], TextField);
@@ -0,0 +1,19 @@
1
+ import { LitElement } from 'lit';
2
+ import '@unicef-polymer/etools-unicef/src/etools-dropdown/etools-dropdown';
3
+ import '@unicef-polymer/etools-unicef/src/etools-icon-button/etools-icon-button';
4
+ export declare class RichAction extends LitElement {
5
+ static styles: import("lit").CSSResult;
6
+ command: string;
7
+ value?: string;
8
+ icon: string;
9
+ active: boolean;
10
+ color: string;
11
+ values: Option[];
12
+ render(): import("lit-html").TemplateResult<1>;
13
+ }
14
+ interface Option {
15
+ name: string;
16
+ value: string;
17
+ }
18
+ export declare function editorCommand(command: string, value?: string): void;
19
+ export {};
@@ -0,0 +1,105 @@
1
+ import { __decorate } from "tslib";
2
+ import { css, html, LitElement } from 'lit';
3
+ import { property, customElement } from 'lit/decorators.js';
4
+ import '@unicef-polymer/etools-unicef/src/etools-dropdown/etools-dropdown';
5
+ import '@unicef-polymer/etools-unicef/src/etools-icon-button/etools-icon-button';
6
+ let RichAction = class RichAction extends LitElement {
7
+ constructor() {
8
+ super(...arguments);
9
+ this.command = '';
10
+ this.icon = 'info';
11
+ this.active = false;
12
+ this.color = '#000000';
13
+ this.values = [];
14
+ }
15
+ render() {
16
+ const hasItems = this.values.length > 0;
17
+ return html `<section style="color:${this.color}">
18
+ ${hasItems
19
+ ? html ` <etools-dropdown
20
+ option-label="name"
21
+ option-value="value"
22
+ .options="${this.values}"
23
+ .selected="${this.values[0].value}"
24
+ dynamic-align
25
+ hide-search
26
+ trigger-value-change-event
27
+ @etools-selected-item-changed="${({ detail }) => {
28
+ if (detail === undefined || detail.selectedItem === null) {
29
+ return;
30
+ }
31
+ const selectedValue = detail.selectedItem.value;
32
+ if (selectedValue === '--') {
33
+ editorCommand('removeFormat', undefined);
34
+ }
35
+ else {
36
+ editorCommand(this.command, selectedValue);
37
+ }
38
+ }}"
39
+ >
40
+ </etools-dropdown>`
41
+ : html `<etools-icon-button
42
+ ?active="${this.active}"
43
+ name="${this.icon}"
44
+ @click=${() => {
45
+ if (this.command) {
46
+ editorCommand(this.command, this.value);
47
+ }
48
+ else {
49
+ this.dispatchEvent(new Event('action', {
50
+ bubbles: true,
51
+ composed: true
52
+ }));
53
+ }
54
+ }}
55
+ ></etools-icon-button>`}
56
+ <div><slot></slot></div>
57
+ </section>`;
58
+ }
59
+ };
60
+ RichAction.styles = css `
61
+ section {
62
+ height: 100%;
63
+ display: flex;
64
+ flex-direction: row;
65
+ align-items: center;
66
+ margin-inline-end: 4px;
67
+ }
68
+ section * {
69
+ margin: 2px;
70
+ }
71
+ etools-icon-button {
72
+ cursor: pointer;
73
+ width: 12px;
74
+ padding: 2px 4px;
75
+ }
76
+ etools-dropdown {
77
+ min-width: 140px;
78
+ margin-block-end: 24px;
79
+ }
80
+ `;
81
+ __decorate([
82
+ property({ type: String })
83
+ ], RichAction.prototype, "command", void 0);
84
+ __decorate([
85
+ property({ type: String })
86
+ ], RichAction.prototype, "value", void 0);
87
+ __decorate([
88
+ property({ type: String })
89
+ ], RichAction.prototype, "icon", void 0);
90
+ __decorate([
91
+ property({ type: Boolean })
92
+ ], RichAction.prototype, "active", void 0);
93
+ __decorate([
94
+ property({ type: String })
95
+ ], RichAction.prototype, "color", void 0);
96
+ __decorate([
97
+ property({ type: Array })
98
+ ], RichAction.prototype, "values", void 0);
99
+ RichAction = __decorate([
100
+ customElement('rich-action')
101
+ ], RichAction);
102
+ export { RichAction };
103
+ export function editorCommand(command, value) {
104
+ document.execCommand(command, true, value);
105
+ }
@@ -0,0 +1,12 @@
1
+ import { LitElement } from 'lit';
2
+ import './rich-toolbar';
3
+ import './rich-viewer';
4
+ export declare class RichText extends LitElement {
5
+ static styles: import("lit").CSSResult;
6
+ selection: Selection | null;
7
+ readonly: boolean;
8
+ node: Element;
9
+ value: string | null | undefined;
10
+ render(): import("lit-html").TemplateResult<1>;
11
+ firstUpdated(): void;
12
+ }
@@ -0,0 +1,125 @@
1
+ import { __decorate } from "tslib";
2
+ import { css, html, LitElement } from 'lit';
3
+ import { property, customElement } from 'lit/decorators.js';
4
+ import { fireEvent } from '../lib/utils/fire-custom-event';
5
+ import './rich-toolbar';
6
+ import './rich-viewer';
7
+ let RichText = class RichText extends LitElement {
8
+ constructor() {
9
+ super(...arguments);
10
+ this.selection = null;
11
+ this.readonly = false;
12
+ this.node = document.createElement('div');
13
+ }
14
+ render() {
15
+ const { selection, readonly, node } = this;
16
+ return html `<main>
17
+ <rich-toolbar
18
+ ?hidden="${this.readonly}"
19
+ .selection="${selection}"
20
+ .node="${node}"
21
+ @set-content=${(e) => {
22
+ var _a;
23
+ const event = e;
24
+ const parser = new DOMParser();
25
+ const doc = parser.parseFromString(event.detail, 'text/html');
26
+ const root = doc.querySelector('body');
27
+ this.node.innerHTML = (_a = root === null || root === void 0 ? void 0 : root.innerHTML) !== null && _a !== void 0 ? _a : '';
28
+ this.requestUpdate();
29
+ }}
30
+ ></rich-toolbar>
31
+ <rich-viewer
32
+ ?readonly="${readonly}"
33
+ .value="${this.value}"
34
+ @selection=${(e) => {
35
+ const event = e;
36
+ this.selection = event.detail.selection;
37
+ fireEvent(this, 'editor-changed', { value: event.detail.html });
38
+ }}
39
+ .node="${node}"
40
+ >
41
+ </rich-viewer>
42
+ </main>`;
43
+ }
44
+ firstUpdated() {
45
+ const children = this.children;
46
+ if ((children === null || children === void 0 ? void 0 : children.length) > 0) {
47
+ // Check if <template> is the first child
48
+ const template = children[0];
49
+ if (template.tagName === 'TEMPLATE') {
50
+ const content = template.innerHTML.trim();
51
+ if (content.length > 0) {
52
+ this.node.innerHTML = content;
53
+ this.requestUpdate();
54
+ }
55
+ }
56
+ }
57
+ }
58
+ };
59
+ RichText.styles = css `
60
+ :host {
61
+ --rich-color: black;
62
+ --rich-background: white;
63
+ --rich-action-active-color: red;
64
+ --icon-size: 24px;
65
+ border: solid 1px var(--rich-border-color, #eeeeee);
66
+ width: 100%;
67
+ }
68
+ main {
69
+ height: 100%;
70
+ width: 100%;
71
+ display: grid;
72
+ grid-template-rows: 1fr auto;
73
+ grid-template-columns: 1fr;
74
+ grid-template-areas:
75
+ 'viewer'
76
+ 'toolbar';
77
+ }
78
+
79
+ rich-toolbar {
80
+ grid-area: toolbar;
81
+ width: 100%;
82
+ background-color: var(--rich-toolbar-background, #ffffff);
83
+ color: var(--rich-color);
84
+ border-bottom: 1px solid var(--rich-toolbar-border-color, #eeeeee);
85
+ }
86
+
87
+ rich-viewer {
88
+ grid-area: viewer;
89
+ flex: 1;
90
+ width: 100%;
91
+ min-height: 40px;
92
+ overflow-y: auto;
93
+ background-color: var(--rich-background);
94
+ color: var(--rich-color);
95
+ }
96
+ rich-viewer[readonly] {
97
+ background-color: #eeeeee;
98
+ }
99
+ main {
100
+ grid-template-rows: auto 1fr;
101
+ grid-template-areas:
102
+ 'toolbar'
103
+ 'viewer';
104
+ }
105
+ rich-toolbar {
106
+ border-top: none;
107
+ border-bottom: 1px solid var(--rich-color);
108
+ }
109
+ `;
110
+ __decorate([
111
+ property({ type: Object, hasChanged: () => true })
112
+ ], RichText.prototype, "selection", void 0);
113
+ __decorate([
114
+ property({ type: Boolean })
115
+ ], RichText.prototype, "readonly", void 0);
116
+ __decorate([
117
+ property({ type: Object, hasChanged: () => true })
118
+ ], RichText.prototype, "node", void 0);
119
+ __decorate([
120
+ property({ type: String })
121
+ ], RichText.prototype, "value", void 0);
122
+ RichText = __decorate([
123
+ customElement('rich-text')
124
+ ], RichText);
125
+ export { RichText };
@@ -0,0 +1,14 @@
1
+ import { LitElement } from 'lit';
2
+ import './rich-action';
3
+ export declare class RichToolbar extends LitElement {
4
+ static styles: import("lit").CSSResult;
5
+ fgColorInput: HTMLInputElement;
6
+ bdColorInput: HTMLInputElement;
7
+ fileHandle?: any;
8
+ node: Element;
9
+ formatColor: string;
10
+ backgroundColor: string;
11
+ selection: Selection | null;
12
+ render(): import("lit-html").TemplateResult<1>;
13
+ getTags(): string[];
14
+ }
@@ -0,0 +1,194 @@
1
+ import { __decorate } from "tslib";
2
+ import { css, html, LitElement } from 'lit';
3
+ import { property, customElement, query, state } from 'lit/decorators.js';
4
+ import './rich-action';
5
+ import { editorCommand } from './rich-action';
6
+ let RichToolbar = class RichToolbar extends LitElement {
7
+ constructor() {
8
+ super(...arguments);
9
+ this.formatColor = '#000000';
10
+ this.backgroundColor = '#000000';
11
+ this.selection = null;
12
+ }
13
+ render() {
14
+ const tags = this.getTags();
15
+ return html `<header>
16
+ <rich-action icon="editor:format-clear" command="removeFormat"></rich-action>
17
+ <rich-action icon="editor:format-bold" command="bold" ?active=${tags.includes('b')}></rich-action>
18
+ <rich-action icon="editor:format-italic" command="italic" ?active=${tags.includes('i')}></rich-action>
19
+ <rich-action icon="editor:format-underlined" command="underline" ?active=${tags.includes('u')}></rich-action>
20
+ <rich-action icon="editor:format-align-left" command="justifyleft"></rich-action>
21
+ <rich-action icon="editor:format-align-center" command="justifycenter"></rich-action>
22
+ <rich-action icon="editor:format-align-right" command="justifyright"></rich-action>
23
+ <rich-action
24
+ icon="editor:format-list-numbered"
25
+ command="insertorderedlist"
26
+ ?active=${tags.includes('ol')}
27
+ ></rich-action>
28
+ <rich-action
29
+ icon="editor:format-list-bulleted"
30
+ command="insertunorderedlist"
31
+ ?active=${tags.includes('ul')}
32
+ ></rich-action>
33
+ <rich-action icon="format_quote" command="formatblock" value="blockquote"></rich-action>
34
+ <!-- <rich-action icon="format_indent_decrease" command="outdent"></rich-action>
35
+ <rich-action icon="format_indent_increase" command="indent"></rich-action> -->
36
+ <rich-action
37
+ icon="editor:add-link"
38
+ ?active=${tags.includes('a')}
39
+ @action=${() => {
40
+ const newLink = prompt('Write the URL here', 'https://');
41
+ // Check if valid url
42
+ if (newLink && newLink.match(/^(http|https):\/\/[^ "]+$/)) {
43
+ editorCommand('createlink', newLink);
44
+ }
45
+ }}
46
+ >
47
+ </rich-action>
48
+ <rich-action icon="editor:unlink" ?active=${tags.includes('a')} command="unlink"></rich-action>
49
+ <rich-action
50
+ icon="editor:format-color-text"
51
+ .color="${this.formatColor}"
52
+ @action=${() => this.fgColorInput.click()}
53
+ >
54
+ <input
55
+ type="color"
56
+ id="fg-color"
57
+ @input=${(e) => {
58
+ const input = e.target;
59
+ this.formatColor = input.value;
60
+ editorCommand('forecolor', input.value);
61
+ }}
62
+ />
63
+ </rich-action>
64
+ <rich-action
65
+ icon="editor:border-color"
66
+ .color="${this.backgroundColor}"
67
+ @action=${() => this.bdColorInput.click()}
68
+ >
69
+ <input
70
+ type="color"
71
+ id="bd-color"
72
+ @input=${(e) => {
73
+ const input = e.target;
74
+ this.backgroundColor = input.value;
75
+ editorCommand('backcolor', input.value);
76
+ }}
77
+ />
78
+ </rich-action>
79
+ <rich-action
80
+ icon="title"
81
+ command="formatblock"
82
+ .values=${[
83
+ { name: 'Normal Text', value: '--' },
84
+ { name: 'Heading 1', value: 'h1' },
85
+ { name: 'Heading 2', value: 'h2' },
86
+ { name: 'Heading 3', value: 'h3' },
87
+ { name: 'Heading 4', value: 'h4' },
88
+ { name: 'Heading 5', value: 'h5' },
89
+ { name: 'Heading 6', value: 'h6' },
90
+ { name: 'Paragraph', value: 'p' },
91
+ { name: 'Pre-Formatted', value: 'pre' }
92
+ ]}
93
+ ></rich-action>
94
+ <rich-action
95
+ icon="editor:format-size"
96
+ command="fontsize"
97
+ .values=${[
98
+ { name: 'Font Size', value: '--' },
99
+ { name: 'Very Small', value: '1' },
100
+ { name: 'Small', value: '2' },
101
+ { name: 'Normal', value: '3' },
102
+ { name: 'Medium Large', value: '4' },
103
+ { name: 'Large', value: '5' },
104
+ { name: 'Very Large', value: '6' },
105
+ { name: 'Maximum', value: '7' }
106
+ ]}
107
+ ></rich-action>
108
+ <rich-action icon="undo" command="undo"></rich-action>
109
+ <rich-action icon="redo" command="redo"></rich-action>
110
+ <!-- <rich-action icon="content_cut" command="cut"></rich-action> -->
111
+ <!-- <rich-action icon="content_copy" command="copy"></rich-action>
112
+ <rich-action icon="content_paste" command="paste"></rich-action> -->
113
+ </header>`;
114
+ }
115
+ getTags() {
116
+ var _a;
117
+ let tags = [];
118
+ if (this.selection) {
119
+ if (this.selection.type === 'Range') {
120
+ // @ts-ignore
121
+ let parentNode = this.selection.baseNode;
122
+ if (parentNode) {
123
+ const checkNode = () => {
124
+ var _a, _b;
125
+ const tag = (_b = (_a = parentNode === null || parentNode === void 0 ? void 0 : parentNode.tagName) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === null || _b === void 0 ? void 0 : _b.trim();
126
+ if (tag)
127
+ tags.push(tag);
128
+ };
129
+ while (parentNode != null) {
130
+ checkNode();
131
+ parentNode = parentNode === null || parentNode === void 0 ? void 0 : parentNode.parentNode;
132
+ }
133
+ }
134
+ // Remove root tag
135
+ tags.pop();
136
+ }
137
+ else {
138
+ const content = ((_a = this.selection) === null || _a === void 0 ? void 0 : _a.toString()) || '';
139
+ tags = (content.match(/<[^>]+>/g) || [])
140
+ .filter((tag) => !tag.startsWith('</'))
141
+ .map((tag) => tag.replace(/<|>/g, ''));
142
+ }
143
+ }
144
+ return tags;
145
+ }
146
+ };
147
+ RichToolbar.styles = css `
148
+ header {
149
+ width: 100%;
150
+ display: flex;
151
+ flex-direction: row;
152
+ align-items: center;
153
+ justify-content: flex-start;
154
+ padding-inline-start: 12px;
155
+ flex-wrap: wrap;
156
+ }
157
+ input[type='color'] {
158
+ -webkit-appearance: none;
159
+ border: none;
160
+ width: 0;
161
+ height: 0;
162
+ }
163
+ input[type='color']::-webkit-color-swatch-wrapper {
164
+ padding: 0;
165
+ }
166
+ input[type='color']::-webkit-color-swatch {
167
+ border: none;
168
+ }
169
+ `;
170
+ __decorate([
171
+ query('#fg-color')
172
+ ], RichToolbar.prototype, "fgColorInput", void 0);
173
+ __decorate([
174
+ query('#bd-color')
175
+ ], RichToolbar.prototype, "bdColorInput", void 0);
176
+ __decorate([
177
+ state()
178
+ ], RichToolbar.prototype, "fileHandle", void 0);
179
+ __decorate([
180
+ property({ type: Object, hasChanged: () => true })
181
+ ], RichToolbar.prototype, "node", void 0);
182
+ __decorate([
183
+ property({ type: String })
184
+ ], RichToolbar.prototype, "formatColor", void 0);
185
+ __decorate([
186
+ property({ type: String })
187
+ ], RichToolbar.prototype, "backgroundColor", void 0);
188
+ __decorate([
189
+ property({ type: Object, hasChanged: () => true })
190
+ ], RichToolbar.prototype, "selection", void 0);
191
+ RichToolbar = __decorate([
192
+ customElement('rich-toolbar')
193
+ ], RichToolbar);
194
+ export { RichToolbar };
@@ -0,0 +1,11 @@
1
+ import { LitElement } from 'lit';
2
+ export declare class RichViewer extends LitElement {
3
+ static styles: import("lit").CSSResult;
4
+ content: HTMLDivElement;
5
+ readonly: boolean;
6
+ value: string;
7
+ node: Element;
8
+ render(): import("lit-html").TemplateResult<1>;
9
+ updateSelection(): void;
10
+ firstUpdated(): void;
11
+ }
@@ -0,0 +1,78 @@
1
+ import { __decorate } from "tslib";
2
+ import { html, css, LitElement } from 'lit';
3
+ import { customElement, property, query } from 'lit/decorators.js';
4
+ import { fireEvent } from '../lib/utils/fire-custom-event';
5
+ let RichViewer = class RichViewer extends LitElement {
6
+ constructor() {
7
+ super(...arguments);
8
+ this.readonly = false;
9
+ this.value = '';
10
+ }
11
+ render() {
12
+ return html `<article
13
+ id="content"
14
+ contenteditable="${this.readonly ? 'false' : 'true'}"
15
+ .innerHTML="${this.value}"
16
+ @input=${() => this.updateSelection()}
17
+ ></article>`;
18
+ }
19
+ updateSelection() {
20
+ var _a, _b;
21
+ if (this.readonly) {
22
+ return;
23
+ }
24
+ // @ts-ignore
25
+ const shadowSelection = ((_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.getSelection)
26
+ ? // @ts-ignore
27
+ this.shadowRoot.getSelection()
28
+ : null;
29
+ const selection = shadowSelection || document.getSelection() || window.getSelection();
30
+ fireEvent(this, 'selection', { selection: selection, html: (_b = this.content) === null || _b === void 0 ? void 0 : _b.innerHTML });
31
+ }
32
+ firstUpdated() {
33
+ document.execCommand('defaultParagraphSeparator', false, 'br');
34
+ document.addEventListener('selectionchange', () => {
35
+ this.updateSelection();
36
+ });
37
+ window.addEventListener('selectionchange', () => {
38
+ this.updateSelection();
39
+ });
40
+ document.addEventListener('keydown', () => {
41
+ this.updateSelection();
42
+ });
43
+ }
44
+ };
45
+ RichViewer.styles = css `
46
+ article {
47
+ width: calc(100% - var(--rich-padding) * 2);
48
+ height: calc(100% - var(--rich-padding) * 2);
49
+ }
50
+
51
+ article[contenteditable='true'] {
52
+ border: none;
53
+ outline: none;
54
+ }
55
+ article[contenteditable='false'] {
56
+ background-color: var(--secondary-background-color);
57
+ }
58
+ blockquote {
59
+ margin-inline-start: 8px;
60
+ margin-inline-end: 8px;
61
+ }
62
+ `;
63
+ __decorate([
64
+ query('#content')
65
+ ], RichViewer.prototype, "content", void 0);
66
+ __decorate([
67
+ property({ type: Boolean, reflect: true })
68
+ ], RichViewer.prototype, "readonly", void 0);
69
+ __decorate([
70
+ property({ type: String })
71
+ ], RichViewer.prototype, "value", void 0);
72
+ __decorate([
73
+ property({ type: Object, hasChanged: () => true })
74
+ ], RichViewer.prototype, "node", void 0);
75
+ RichViewer = __decorate([
76
+ customElement('rich-viewer')
77
+ ], RichViewer);
78
+ export { RichViewer };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@unicef-polymer/etools-form-builder",
3
3
  "description": "Etools FM Form Builder components",
4
- "version": "3.1.2",
4
+ "version": "3.1.3",
5
5
  "type": "module",
6
6
  "contributors": [
7
7
  "eTools Team"
@@ -32,15 +32,15 @@
32
32
  "typescript": "^4.9.5"
33
33
  },
34
34
  "peerDependencies": {
35
- "@unicef-polymer/etools-unicef": ">=1.1.3"
35
+ "@unicef-polymer/etools-unicef": ">=1.2.0"
36
36
  },
37
37
  "devDependencies": {
38
- "@unicef-polymer/etools-unicef": "^1.1.3",
39
- "eslint": "^9.16.0",
40
38
  "@eslint/eslintrc": "^3.2.0",
41
39
  "@eslint/js": "^9.16.0",
42
40
  "@typescript-eslint/eslint-plugin": "^8.17.0",
43
41
  "@typescript-eslint/parser": "^8.17.0",
42
+ "@unicef-polymer/etools-unicef": "^1.2.0",
43
+ "eslint": "^9.16.0",
44
44
  "eslint-config-prettier": "^9.1.0",
45
45
  "eslint-plugin-html": "^8.1.2",
46
46
  "eslint-plugin-lit": "^1.15.0",