@pairbo/ui-kit 0.0.1

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 (94) hide show
  1. package/.husky/pre-commit +1 -0
  2. package/.prettierignore +16 -0
  3. package/.prettierrc.json +17 -0
  4. package/README.md +61 -0
  5. package/cspell.json +9 -0
  6. package/dev.html +101 -0
  7. package/docs/README.md +1 -0
  8. package/docs/_includes/component.njk +16 -0
  9. package/docs/_includes/default.njk +39 -0
  10. package/docs/_includes/sidebar.njk +16 -0
  11. package/docs/eleventy.config.mjs +72 -0
  12. package/docs/pages/components/message-selector.md +17 -0
  13. package/docs/pages/fabric-example.html +46 -0
  14. package/docs/pages/fabric-example.js +28 -0
  15. package/docs/pages/index.md +76 -0
  16. package/eslint.config.mjs +32 -0
  17. package/ignote_temp +3 -0
  18. package/index.html +162 -0
  19. package/lint-stage.confg.js +6 -0
  20. package/package.json +66 -0
  21. package/pages/card-selection.html +65 -0
  22. package/pages/drawer.html +47 -0
  23. package/pages/editor.html +45 -0
  24. package/pages/page-mgn.html +51 -0
  25. package/pages/test_build.html +47 -0
  26. package/public/Greeting Card from Pairbo.png +0 -0
  27. package/scripts/plop/plopfile.js +51 -0
  28. package/scripts/plop/templates/components/component.hbs +34 -0
  29. package/scripts/plop/templates/components/define.hbs +10 -0
  30. package/scripts/plop/templates/components/styles.hbs +7 -0
  31. package/src/components/button/button.component.ts +93 -0
  32. package/src/components/button/button.styles.ts +273 -0
  33. package/src/components/button/button.ts +10 -0
  34. package/src/components/button-group/button-group.component.ts +36 -0
  35. package/src/components/button-group/button-group.styles.ts +7 -0
  36. package/src/components/button-group/button-group.ts +10 -0
  37. package/src/components/card-selection/card-selection.component.ts +43 -0
  38. package/src/components/card-selection/card-selection.styles.ts +7 -0
  39. package/src/components/card-selection/card-selection.ts +10 -0
  40. package/src/components/category/category.component.ts +91 -0
  41. package/src/components/category/category.styles.ts +27 -0
  42. package/src/components/category/category.ts +10 -0
  43. package/src/components/category-image/category-image.component.ts +38 -0
  44. package/src/components/category-image/category-image.styles.ts +11 -0
  45. package/src/components/category-image/category-image.ts +10 -0
  46. package/src/components/drawer/drawer.component.ts +82 -0
  47. package/src/components/drawer/drawer.styles.ts +54 -0
  48. package/src/components/drawer/drawer.ts +10 -0
  49. package/src/components/editor/editor.component.ts +135 -0
  50. package/src/components/editor/editor.styles.ts +13 -0
  51. package/src/components/editor/editor.ts +10 -0
  52. package/src/components/fabric-example/fabric-example.component.ts +268 -0
  53. package/src/components/fabric-example/fabric-example.styles.ts +23 -0
  54. package/src/components/fabric-example/fabric-example.test.ts +0 -0
  55. package/src/components/fabric-example/fabric-example.ts +12 -0
  56. package/src/components/image-slider/editor-card-slider.component.ts +136 -0
  57. package/src/components/image-slider/editor-card-slider.styles.ts +46 -0
  58. package/src/components/image-slider/editor-card-slider.ts +9 -0
  59. package/src/components/main.ts +17 -0
  60. package/src/components/message-selector/message-selector.component.ts +154 -0
  61. package/src/components/message-selector/message-selector.styles.ts +16 -0
  62. package/src/components/message-selector/message-selector.test.ts +64 -0
  63. package/src/components/message-selector/message-selector.ts +13 -0
  64. package/src/components/page-manager/page-manager.component.ts +228 -0
  65. package/src/components/page-manager/page-manager.styles.ts +9 -0
  66. package/src/components/page-manager/page-manager.ts +10 -0
  67. package/src/components/radio-button/radio-button.component.ts +118 -0
  68. package/src/components/radio-button/radio-button.styles.ts +13 -0
  69. package/src/components/radio-button/radio-button.ts +10 -0
  70. package/src/components/radio-group/radio-group.component.ts +203 -0
  71. package/src/components/radio-group/radio-group.styles.ts +19 -0
  72. package/src/components/radio-group/radio-group.ts +10 -0
  73. package/src/components/selector/selector.component.ts +115 -0
  74. package/src/components/selector/selector.styles.ts +9 -0
  75. package/src/components/selector/selector.ts +10 -0
  76. package/src/components/textarea/textarea.component.ts +234 -0
  77. package/src/components/textarea/textarea.styles.ts +178 -0
  78. package/src/components/textarea/textarea.ts +10 -0
  79. package/src/components/type-form/type-form.component.ts +121 -0
  80. package/src/components/type-form/type-form.styles.ts +7 -0
  81. package/src/components/type-form/type-form.ts +10 -0
  82. package/src/declaration.d.ts +44 -0
  83. package/src/events/events.ts +1 -0
  84. package/src/events/pbo-category-card-select.ts +7 -0
  85. package/src/internal/form.ts +376 -0
  86. package/src/internal/pairbo-element.ts +85 -0
  87. package/src/internal/slots.ts +54 -0
  88. package/src/internal/watch.ts +79 -0
  89. package/src/styles/component.styles.ts +17 -0
  90. package/src/styles/form-control.styles.ts +59 -0
  91. package/src/themes/default.css +414 -0
  92. package/temp +20 -0
  93. package/tsconfig.json +28 -0
  94. package/vite.config.ts +26 -0
@@ -0,0 +1,82 @@
1
+ import { customElement, property, query } from "lit/decorators.js";
2
+ import { html, LitElement } from "lit";
3
+ import type { CSSResultGroup, PropertyValues } from "lit";
4
+ import componentStyles from "../../styles/component.styles.js";
5
+ import PairboElement from "../../internal/pairbo-element.js";
6
+ import styles from "./drawer.styles.js";
7
+ import { classMap } from "lit/directives/class-map.js";
8
+ import { watch } from "../../internal/watch.js";
9
+
10
+ /**
11
+ * @summary Short summary of the component's intended use.
12
+ * @status experimental
13
+ *
14
+ * @dependency pbo-example
15
+ *
16
+ * @event pbo-event-name - Emitted as an example.
17
+ *
18
+ * @slot - The default slot.
19
+ * @slot example - An example slot.
20
+ *
21
+ * @csspart base - The component's base wrapper.
22
+ *
23
+ * @cssproperty --example - An example CSS custom property.
24
+ */
25
+
26
+ @customElement("pbo-drawer")
27
+ export default class PboModal extends PairboElement {
28
+ static styles: CSSResultGroup = [componentStyles, styles];
29
+
30
+ @query(".drawer") drawer!: HTMLDivElement;
31
+ @property({ type: Boolean, reflect: true }) open = false;
32
+
33
+ private requestClose(source: "close-button" | "keyboard" | "overlay") {
34
+ this.hide();
35
+ }
36
+
37
+ async hide() {
38
+ this.open = false;
39
+ }
40
+
41
+ async show() {
42
+ if (this.open) {
43
+ return undefined;
44
+ }
45
+ this.open = true;
46
+ }
47
+
48
+ @watch("open", { waitUntilFirstUpdate: true })
49
+ handleOpenChange() {
50
+ if (this.open) this.drawer.hidden = false;
51
+ else this.drawer.hidden = true;
52
+ }
53
+
54
+ // Init the component
55
+ protected firstUpdated(): void {
56
+ this.drawer.hidden = !this.open;
57
+ }
58
+ render() {
59
+ return html`
60
+ <div
61
+ part="base"
62
+ class=${classMap({
63
+ drawer: true,
64
+ "drawer--bottom": true,
65
+ "drawer--open": this.open,
66
+ })}
67
+ >
68
+ <div part="overlay" class="drawer__overlay" @click=${() => this.requestClose("overlay")}></div>
69
+ <div
70
+ part="panel"
71
+ class="drawer__panel"
72
+ role="dialog"
73
+ aria-modal="true"
74
+ aria-hidden=${this.open ? "false" : "true"}
75
+ tabindex="0"
76
+ >
77
+ <slot part="body" class="drawer__body"></slot>
78
+ </div>
79
+ </div>
80
+ `;
81
+ }
82
+ }
@@ -0,0 +1,54 @@
1
+ import { css } from "lit";
2
+
3
+ export default css`
4
+ :host {
5
+ --size: 30rem;
6
+ --header-spacing: var(--sl-spacing-large);
7
+ --body-spacing: var(--sl-spacing-large);
8
+ --footer-spacing: var(--sl-spacing-large);
9
+
10
+ display: contents;
11
+ }
12
+
13
+ .drawer {
14
+ top: 0;
15
+ inset-inline-start: 0;
16
+ width: 100%;
17
+ height: 100%;
18
+ pointer-events: none;
19
+ overflow: hidden;
20
+ }
21
+
22
+ .drawer__overlay {
23
+ display: block;
24
+ position: fixed;
25
+ top: 0;
26
+ right: 0;
27
+ bottom: 0;
28
+ left: 0;
29
+ background-color: var(--sl-overlay-background-color);
30
+ pointer-events: all;
31
+ }
32
+
33
+ .drawer__panel {
34
+ position: absolute;
35
+ display: flex;
36
+ flex-direction: column;
37
+ z-index: 2;
38
+ max-width: 100%;
39
+ max-height: 100%;
40
+ background-color: var(--sl-panel-background-color);
41
+ box-shadow: var(--sl-shadow-x-large);
42
+ overflow: auto;
43
+ pointer-events: all;
44
+ }
45
+
46
+ .drawer--bottom .drawer__panel {
47
+ top: auto;
48
+ inset-inline-end: auto;
49
+ bottom: 0;
50
+ inset-inline-start: 0;
51
+ width: 100%;
52
+ height: var(--size);
53
+ }
54
+ `;
@@ -0,0 +1,10 @@
1
+ import PboDrawer from "./drawer.component.js";
2
+
3
+ export * from "./drawer.component.js";
4
+ export default PboDrawer;
5
+
6
+ declare global {
7
+ interface HTMLElementTagNameMap {
8
+ "pbo-modal": PboDrawer;
9
+ }
10
+ }
@@ -0,0 +1,135 @@
1
+ import { customElement, property, query, state } from "lit/decorators.js";
2
+ import { html, LitElement } from "lit";
3
+ import type { CSSResultGroup, PropertyValues } from "lit";
4
+ import componentStyles from "../../styles/component.styles.js";
5
+ import PairboElement from "../../internal/pairbo-element.js";
6
+ import styles from "./editor.styles.js";
7
+ import FabricExample from "../fabric-example/fabric-example.component.js";
8
+ import PboTypeForm from "../type-form/type-form.component.js";
9
+ import { styleMap } from "lit/directives/style-map.js";
10
+ import PboEditorCardSlider from "../image-slider/editor-card-slider.component.js";
11
+
12
+ /**
13
+ * @summary Short summary of the component's intended use.
14
+ * @status experimental
15
+ *
16
+ * @dependency pbo-example
17
+ *
18
+ * @event pbo-event-name - Emitted as an example.
19
+ *
20
+ * @slot - The default slot.
21
+ * @slot example - An example slot.
22
+ *
23
+ * @csspart base - The component's base wrapper.
24
+ *
25
+ * @cssproperty --example - An example CSS custom property.
26
+ */
27
+
28
+ interface FormData {
29
+ cardId: string;
30
+ }
31
+
32
+ interface TypingFormData extends FormData {
33
+ font: string;
34
+ text: string;
35
+ color: string;
36
+ alignment: string;
37
+ }
38
+
39
+ @customElement("pbo-editor")
40
+ export default class PboEditor extends PairboElement {
41
+ static styles: CSSResultGroup = [componentStyles, styles];
42
+ static dependencies = {
43
+ "editor-card-slider": PboEditorCardSlider,
44
+ "fabric-example": FabricExample,
45
+ "pbo-type-form": PboTypeForm,
46
+ };
47
+
48
+ @property({ type: String, reflect: true }) cardInnerImageUrl = "../../../public/Greeting Card from Pairbo.png";
49
+
50
+ @query("pbo-type-form") typingForm!: PboTypeForm;
51
+ private handleTypingFormChange() {
52
+ console.log(this.typingForm.form);
53
+ }
54
+ @query("pbo-editor-card-slider") slider!: PboEditorCardSlider;
55
+ // private _card: Card | null = null;
56
+
57
+ @property({ type: Object }) card: Card | null = null;
58
+ @state()
59
+ private formData = { font: "Monsieur La Doulaise", text: "", color: "rgb(0,0,0)", alignment: "left" };
60
+
61
+ protected firstUpdated(): void {
62
+ this.typingForm.addEventListener("pbo-change", event => {
63
+ this.formData = this.typingForm.form;
64
+ });
65
+ }
66
+
67
+ isCardType(obj: any): obj is Card {
68
+ return (
69
+ obj &&
70
+ typeof obj === "object" &&
71
+ "id" in obj &&
72
+ "name" in obj &&
73
+ "category" in obj &&
74
+ "medias" in obj &&
75
+ typeof obj.medias === "object" &&
76
+ "cover" in obj.medias &&
77
+ "render_1" in obj.medias &&
78
+ "render_2" in obj.medias &&
79
+ "inner" in obj.medias
80
+ );
81
+ }
82
+
83
+ updated(changedProperties: PropertyValues<this>): void {
84
+ if (changedProperties.has("cardInnerImageUrl")) {
85
+ this.requestUpdate();
86
+ }
87
+ if (changedProperties.has("card")) {
88
+ this.slider.card = this.card;
89
+ this.requestUpdate();
90
+ }
91
+ }
92
+
93
+ disconnectedCallback(): void {
94
+ this.typingForm.removeEventListener("pbo-change", this.handleTypingFormChange);
95
+ }
96
+
97
+ render() {
98
+ return html`
99
+ ${JSON.stringify(this.card)} In the editor
100
+ <div class="editor">
101
+ <div
102
+ style=${styleMap({
103
+ maxWidth: "500px",
104
+ })}
105
+ >
106
+ <!--
107
+ <fabric-example
108
+ backgroundUrl=${this.cardInnerImageUrl}
109
+ alignment=${this.formData?.alignment || ""}
110
+ message=${this.formData?.text || ""}
111
+ color=${this.formData?.color || ""}
112
+ fontFamily=${this.formData?.font || ""}
113
+ ></fabric-example>
114
+ -->
115
+ <pbo-editor-card-slider focusIndex="0" .livePreviewProps=${this.formData}></pbo-editor-card-slider>
116
+ </div>
117
+
118
+ <div>
119
+ <pbo-type-form></pbo-type-form>
120
+ ${JSON.stringify(this.formData)}
121
+ </div>
122
+ </div>
123
+ <button
124
+ @click=${() => {
125
+ const slider = this.shadowRoot?.querySelector("pbo-editor-card-slider");
126
+ if (slider && slider.getAttribute("focusIndex") !== "1") {
127
+ slider.setAttribute("focusIndex", "1");
128
+ }
129
+ }}
130
+ >
131
+ Set main image to canvas
132
+ </button>
133
+ `;
134
+ }
135
+ }
@@ -0,0 +1,13 @@
1
+ import { css } from "lit";
2
+
3
+ export default css`
4
+ :host {
5
+ display: block;
6
+ }
7
+
8
+ .editor {
9
+ display: grid;
10
+ grid-template-columns: 1fr 1fr;
11
+ gap: 1rem;
12
+ }
13
+ `;
@@ -0,0 +1,10 @@
1
+ import PboEditor from "./editor.component.js";
2
+
3
+ export * from "./editor.component.js";
4
+ export default PboEditor;
5
+
6
+ declare global {
7
+ interface HTMLElementTagNameMap {
8
+ "pbo-editor": PboEditor;
9
+ }
10
+ }
@@ -0,0 +1,268 @@
1
+ import { LitElement, html, css } from "lit";
2
+ import { customElement, property, query, state } from "lit/decorators.js";
3
+ import { Canvas, ITextEvents, SerializedTextboxProps, Textbox, TextboxProps, TOptions, FabricImage } from "fabric";
4
+ import { prototype } from "mocha";
5
+
6
+ @customElement("fabric-example")
7
+ export default class FabricExample extends LitElement {
8
+ @property() backgroundUrl: string =
9
+ "https://upload.wikimedia.org/wikipedia/commons/0/06/Daedalus_Spaceship_concept.jpg";
10
+ @property()
11
+ message: string = "Dear fridends,\n\nMy name is xxxxx. sadf;lkasdf\ngood aklsdfja";
12
+ @property({ type: String, reflect: true }) alignment: "left" | "center" | "right" = "left";
13
+ @property({ type: String }) fontFamily: string = "Arial";
14
+ @property({ type: String }) color: string = "#000";
15
+
16
+ @query(".fabric-container")
17
+ private _fabricContainer!: HTMLDivElement;
18
+
19
+ @state()
20
+ private _canvas?: Canvas;
21
+ @state()
22
+ private _canvasElement?: HTMLCanvasElement;
23
+ @state()
24
+ private _textbox?: Textbox<TOptions<TextboxProps>, SerializedTextboxProps, ITextEvents>;
25
+ @state()
26
+ private _backgroundImg: HTMLImageElement = new Image();
27
+ @state()
28
+ private _natureSize: { width: number; height: number } = { width: 0, height: 0 };
29
+ @state()
30
+ private _scale: number = 1;
31
+ @state()
32
+ private _lineHeight: number = 0;
33
+ @state()
34
+ private _fontSize: number = 0;
35
+
36
+ constructor() {
37
+ super();
38
+ this._backgroundImg = new Image();
39
+ }
40
+
41
+ static styles = css`
42
+ :host {
43
+ display: block;
44
+ height: 100%;
45
+ width: 100%;
46
+ }
47
+ .fabric-container {
48
+ display: block;
49
+ border: 2px solid #333;
50
+ border-radius: 4px;
51
+ background: #fff;
52
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
53
+ height: 100%;
54
+ width: 100%;
55
+ }
56
+ canvas {
57
+ border: 1px solid #ccc;
58
+ width: 100%;
59
+ height: 100%;
60
+ }
61
+ .grechen-fuemen-regular {
62
+ font-family: "Grechen Fuemen", serif;
63
+ font-weight: 400;
64
+ font-style: normal;
65
+ }
66
+ `;
67
+ connectedCallback() {
68
+ super.connectedCallback();
69
+ this._backgroundImg.src = this.backgroundUrl;
70
+ this._backgroundImg.onload = () => {
71
+ this._natureSize = { width: this._backgroundImg.naturalWidth, height: this._backgroundImg.naturalHeight };
72
+ };
73
+ this._canvasElement = document.createElement("canvas");
74
+ }
75
+ formatTextbox(textbox: Textbox<TOptions<TextboxProps>, SerializedTextboxProps, ITextEvents>) {
76
+ console.log({
77
+ line: textbox?.textLines,
78
+ text: textbox?.text,
79
+ });
80
+ let lines = textbox.textLines;
81
+ console.log(lines.length);
82
+ if (lines.length > 12) {
83
+ // Prevent adding more lines after 12
84
+ const limitedLines = lines.slice(0, 12);
85
+ textbox.set("text", limitedLines.join("\n"));
86
+ textbox.setSelectionStart(textbox.text.length);
87
+ textbox.setSelectionEnd(textbox.text.length);
88
+ this._canvas?.renderAll();
89
+ }
90
+ }
91
+
92
+ firstUpdated() {
93
+ const canvasElement = document.createElement("canvas");
94
+ this._fabricContainer.appendChild(canvasElement);
95
+
96
+ this._backgroundImg.onload = () => {
97
+ const fabricBackgroundImage = new FabricImage(this._backgroundImg);
98
+
99
+ this._canvas = new Canvas(canvasElement, {
100
+ backgroundImage: fabricBackgroundImage,
101
+ width: this._backgroundImg.naturalWidth,
102
+ height: this._backgroundImg.naturalHeight,
103
+ });
104
+ this._lineHeight = (0.45 * this._backgroundImg.height) / 12;
105
+ this._fontSize = this._lineHeight / 1.16;
106
+
107
+ const props: TOptions<TextboxProps> = {
108
+ fontSize: 16,
109
+ left: 0.084 * this._backgroundImg.naturalWidth,
110
+ // top: 0.4874 * this._backgroundImg.naturalHeight,
111
+ top: 0.52 * this._backgroundImg.naturalHeight,
112
+ width: 0.832 * this._backgroundImg.naturalWidth,
113
+ height: 0.45 * this._backgroundImg.naturalHeight,
114
+ hasControls: false,
115
+ editable: false,
116
+ breakWords: false,
117
+ splitByGrapheme: false, // Ensure text wraps correctly
118
+ textAlign: this.alignment,
119
+ lockMovementX: true,
120
+ lockMovementY: true,
121
+ selectable: false, // Make the textbox non-interactive
122
+ };
123
+
124
+ this._textbox = new Textbox(this.message, props);
125
+ this._textbox.set("fill", this.color);
126
+ // Custom logic to handle continuous characters without splitting words
127
+ this._textbox.on("changed", () => {
128
+ const maxLines = 12;
129
+ const maxCharsPerLine = 20;
130
+ if (!this._textbox) return;
131
+ let lines = this._textbox.text.split("\n");
132
+ let newLines: string[] = [];
133
+ lines.forEach(line => {
134
+ if (line.length > maxCharsPerLine) {
135
+ const words = line.split(" ");
136
+ let newLine = "";
137
+ let currentLength = 0;
138
+ words.forEach(word => {
139
+ if (currentLength + word.length > maxCharsPerLine) {
140
+ newLines.push(newLine.trim());
141
+ newLine = word + " ";
142
+ currentLength = word.length + 1;
143
+ } else {
144
+ newLine += word + " ";
145
+ currentLength += word.length + 1;
146
+ }
147
+ });
148
+ if (newLine.trim().length > 0) {
149
+ newLines.push(newLine.trim());
150
+ }
151
+ } else {
152
+ newLines.push(line);
153
+ }
154
+ });
155
+ if (newLines.length > maxLines) {
156
+ newLines = newLines.slice(0, maxLines);
157
+ }
158
+ this._textbox.text = newLines.join("\n");
159
+ this._textbox.setSelectionStart(this._textbox.text.length);
160
+ this._textbox.setSelectionEnd(this._textbox.text.length);
161
+ this._canvas?.renderAll();
162
+ });
163
+
164
+ // Add text to canvas
165
+ this._canvas.add(this._textbox);
166
+ this._canvas.centerObject(this._textbox);
167
+ this._canvas.renderAll();
168
+ };
169
+ window.addEventListener("resize", () => {
170
+ canvasElement.width = this._fabricContainer.clientWidth;
171
+ canvasElement.height = this._fabricContainer.clientHeight;
172
+ this.adjustCanvasElements();
173
+ this._canvas?.renderAll(); // Re-render canvas content if necessary
174
+ });
175
+ setTimeout(() => this.adjustCanvasElements(), 100);
176
+ }
177
+
178
+ adjustCanvasElements() {
179
+ if (this._canvas && this._textbox && this._backgroundImg && this._backgroundImg.complete) {
180
+ // Now we can safely work with the loaded image
181
+
182
+ const containerDiv = this.shadowRoot?.querySelector(".fabric-container");
183
+ if (!containerDiv) return;
184
+ const parentWidth = containerDiv.clientWidth;
185
+ const parentHeight = containerDiv.clientHeight;
186
+ const naturalWidth = this._backgroundImg.naturalWidth;
187
+ const naturalHeight = this._backgroundImg.naturalHeight;
188
+ const heightRatio = parentHeight / naturalHeight;
189
+ const widthRatio = parentWidth / naturalWidth;
190
+ const scale = Math.min(heightRatio, widthRatio);
191
+ this._scale = scale;
192
+ console.log({ parentWidth, parentHeight, naturalWidth, naturalHeight });
193
+
194
+ // Set the canvas dimensions
195
+ this._canvas.setWidth(naturalWidth * scale);
196
+ this._canvas.setHeight(naturalHeight * scale);
197
+
198
+ // Scale the background image
199
+ const background = this._canvas.backgroundImage;
200
+ if (background) {
201
+ background.scaleToWidth(naturalWidth * scale);
202
+ background.scaleToHeight(naturalHeight * scale);
203
+ }
204
+
205
+ // Scale the textbox
206
+ this._textbox.set({
207
+ left: 0.084 * naturalWidth * scale,
208
+ top: 0.52 * naturalHeight * scale,
209
+ width: 0.832 * naturalWidth * scale,
210
+ height: 0.45 * naturalHeight * scale,
211
+ fontSize: this._fontSize * scale,
212
+ });
213
+
214
+ console.log(((0.45 * naturalHeight) / 12) * 0.9 * scale);
215
+ console.log(`Line height pixel: ${this._textbox.get("lineHeight") * this._textbox.get("fontSize")}px`);
216
+ console.log(`Line height: ${this._textbox.get("lineHeight")}`);
217
+ console.log(`Font size: ${this._textbox.get("fontSize")}px`);
218
+ const lineHeight = (0.45 * naturalHeight * scale) / 12;
219
+ console.log(`desired line height: ${lineHeight}`);
220
+ console.log(`scale width: ${0.832 * naturalWidth * scale} - scale height: ${0.45 * naturalHeight * scale}`);
221
+
222
+ this._canvas.renderAll(); // Re-render canvas content if necessary
223
+ }
224
+ }
225
+
226
+ updated(changedProperties: Map<string | number | symbol, unknown>) {
227
+ console.log(changedProperties);
228
+ if (!this._textbox) return;
229
+ if (changedProperties.has("message")) {
230
+ this._textbox?.set("text", this.message);
231
+ this.formatTextbox(this._textbox);
232
+ this._canvas?.renderAll();
233
+ }
234
+
235
+ if (changedProperties.has("alignment")) {
236
+ this._textbox?.set("textAlign", this.alignment);
237
+ this._canvas?.renderAll();
238
+ }
239
+
240
+ if (changedProperties.has("fontFamily")) {
241
+ this._textbox?.set("fontFamily", this.fontFamily);
242
+ this._canvas?.renderAll();
243
+ }
244
+
245
+ if (changedProperties.has("color")) {
246
+ this._textbox?.set("fill", this.color);
247
+ this._canvas?.renderAll();
248
+ }
249
+ }
250
+
251
+ render() {
252
+ return html`
253
+ <div
254
+ style="position: fixed; top: 0; left: 0; padding: 1rem; z-index: 1000; background: rgba(255, 255, 255, 0.5); color: rgba(0, 0, 0, 0.5);"
255
+ >
256
+ Nature font size: ${this._fontSize} <br />
257
+ Nature line height: ${this._lineHeight} <br />
258
+ Line height: ${this._textbox?.get("lineHeight")} <br />
259
+ Font size: ${this._textbox?.get("fontSize")} <br />
260
+ real textbox width: ${this._backgroundImg.width * 0.382} <br />
261
+ real textbox height: ${this._backgroundImg.height * 0.45} <br />
262
+ Textbox width: ${this._textbox?.width} <br />
263
+ Textbox height: ${this._textbox?.height} <br />
264
+ </div>
265
+ <div class="fabric-container"></div>
266
+ `;
267
+ }
268
+ }
@@ -0,0 +1,23 @@
1
+ import { css } from "lit";
2
+
3
+ export default css`
4
+ :host {
5
+ display: block;
6
+ font-family: Arial, sans-serif;
7
+ }
8
+ .message-selector {
9
+ border: 1px solid #ccc;
10
+ padding: 1rem;
11
+ border-radius: 4px;
12
+ background-color: #fff;
13
+ color: black;
14
+ }
15
+ .fabric-container {
16
+ display: block;
17
+ margin-top: 1rem;
18
+ position: absolute;
19
+ top: 50%;
20
+ left: 50%;
21
+ transform: translate(-50%, -50%);
22
+ }
23
+ `;
@@ -0,0 +1,12 @@
1
+ import FabricExample from "./fabric-example.component.js";
2
+
3
+ export * from "./fabric-example.component.js";
4
+ export default FabricExample;
5
+
6
+ // customElements.define("pairbo-message-selector", PairboMessageSelector);
7
+
8
+ declare global {
9
+ interface HTMLElementTagNameMap {
10
+ "fabric-example": FabricExample;
11
+ }
12
+ }