medos-sdk 1.1.7 → 1.1.8

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 (27) hide show
  1. package/dist/components/SuccessStep.js +1 -1
  2. package/dist/vanilla/AppointmentCalendarWidget.d.ts +8 -0
  3. package/dist/vanilla/AppointmentCalendarWidget.js +463 -158
  4. package/dist/vanilla/EnquiryFormWidget.d.ts +2 -0
  5. package/dist/vanilla/EnquiryFormWidget.js +155 -100
  6. package/dist/vanilla/components/VanillaCalendar.d.ts +32 -0
  7. package/dist/vanilla/components/VanillaCalendar.js +366 -0
  8. package/dist/vanilla/components/VanillaIcons.d.ts +17 -0
  9. package/dist/vanilla/components/VanillaIcons.js +268 -0
  10. package/dist/vanilla/components/VanillaSelect.d.ts +46 -0
  11. package/dist/vanilla/components/VanillaSelect.js +523 -0
  12. package/dist/vanilla/components/index.d.ts +3 -0
  13. package/dist/vanilla/components/index.js +3 -0
  14. package/dist/vanilla/components/theme-injector.d.ts +1 -0
  15. package/dist/vanilla/components/theme-injector.js +447 -0
  16. package/dist/vanilla/enquiry-widget.js +1366 -100
  17. package/dist/vanilla/vanilla/AppointmentCalendarWidget.d.ts +8 -0
  18. package/dist/vanilla/vanilla/EnquiryFormWidget.d.ts +2 -0
  19. package/dist/vanilla/vanilla/components/VanillaCalendar.d.ts +32 -0
  20. package/dist/vanilla/vanilla/components/VanillaIcons.d.ts +17 -0
  21. package/dist/vanilla/vanilla/components/VanillaSelect.d.ts +46 -0
  22. package/dist/vanilla/vanilla/components/index.d.ts +3 -0
  23. package/dist/vanilla/vanilla/components/theme-injector.d.ts +1 -0
  24. package/dist/vanilla/vanilla/widget.d.ts +2 -0
  25. package/dist/vanilla/widget.d.ts +2 -0
  26. package/dist/vanilla/widget.js +2213 -257
  27. package/package.json +1 -1
@@ -0,0 +1,46 @@
1
+ export interface SelectOption {
2
+ value: string;
3
+ label: string;
4
+ disabled?: boolean;
5
+ }
6
+ export interface VanillaSelectOptions {
7
+ placeholder?: string;
8
+ disabled?: boolean;
9
+ error?: boolean;
10
+ onValueChange?: (value: string) => void;
11
+ }
12
+ export declare class VanillaSelect {
13
+ private readonly container;
14
+ private options;
15
+ private readonly config;
16
+ private selectedValue;
17
+ private selectedLabel;
18
+ private isOpen;
19
+ private triggerElement;
20
+ private contentElement;
21
+ private handleDocumentClick;
22
+ private handleWindowResize;
23
+ private handleWindowScroll;
24
+ constructor(container: HTMLElement | string, options: SelectOption[], config?: VanillaSelectOptions);
25
+ private renderTrigger;
26
+ private attachTriggerEvents;
27
+ private toggleOpen;
28
+ private open;
29
+ private close;
30
+ private createPortal;
31
+ private removePortal;
32
+ private updatePosition;
33
+ private attachPortalEvents;
34
+ private detachPortalEvents;
35
+ private focusNextItem;
36
+ private selectValue;
37
+ setValue(value: string): void;
38
+ getValue(): string;
39
+ setOptions(options: SelectOption[]): void;
40
+ setDisabled(disabled: boolean): void;
41
+ setError(error: boolean): void;
42
+ destroy(): void;
43
+ private escapeHtml;
44
+ }
45
+ export declare function upgradeNativeSelect(selectElement: HTMLSelectElement, config?: VanillaSelectOptions): VanillaSelect;
46
+ export default VanillaSelect;
@@ -0,0 +1,523 @@
1
+ import { VanillaIcons } from "./VanillaIcons";
2
+ function injectSelectStyles() {
3
+ if (typeof document === "undefined")
4
+ return;
5
+ const styleId = "medos-vanilla-select-styles";
6
+ if (document.getElementById(styleId))
7
+ return;
8
+ const styleElement = document.createElement("style");
9
+ styleElement.id = styleId;
10
+ styleElement.innerHTML = `
11
+ /* Container */
12
+ .medos-select-container {
13
+ position: relative;
14
+ display: inline-block;
15
+ width: 100%;
16
+ }
17
+
18
+ /* Trigger Button */
19
+ .medos-select-trigger {
20
+ display: flex;
21
+ width: 100%;
22
+ align-items: center;
23
+ justify-content: space-between;
24
+ white-space: nowrap;
25
+ border-radius: var(--medos-radius-md, 8px);
26
+ border: 1px solid var(--medos-color-border, #e5e7eb);
27
+ background-color: var(--medos-color-surface, #fff);
28
+ padding: var(--medos-spacing-sm, 10px) var(--medos-spacing-md, 12px);
29
+ font-size: var(--medos-typography-font-size-sm, 14px);
30
+ line-height: 1.5;
31
+ box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
32
+ transition: var(--medos-transition-normal, 200ms ease-in-out);
33
+ cursor: pointer;
34
+ outline: none;
35
+ font-family: inherit;
36
+ text-align: left;
37
+ box-sizing: border-box;
38
+ color: var(--medos-color-text, #111827);
39
+ }
40
+
41
+ .medos-select-trigger:hover:not(:disabled) {
42
+ border-color: var(--medos-color-border-hover, #d1d5db);
43
+ }
44
+
45
+ .medos-select-trigger:focus:not(:disabled) {
46
+ border-color: var(--medos-color-primary, #27903f);
47
+ box-shadow: 0 0 0 2px rgba(39, 144, 63, 0.15);
48
+ }
49
+
50
+ .medos-select-trigger:disabled {
51
+ cursor: not-allowed;
52
+ opacity: 0.5;
53
+ background-color: #f9fafb;
54
+ }
55
+
56
+ .medos-select-trigger-error {
57
+ border-color: #ef4444;
58
+ }
59
+
60
+ .medos-select-trigger-error:focus {
61
+ border-color: #ef4444;
62
+ box-shadow: 0 0 0 2px rgba(239, 68, 68, 0.2);
63
+ }
64
+
65
+ .medos-select-trigger[aria-expanded="true"] {
66
+ border-color: var(--medos-color-primary, #27903f);
67
+ box-shadow: 0 0 0 2px rgba(39, 144, 63, 0.15);
68
+ }
69
+
70
+ /* Select Value */
71
+ .medos-select-value {
72
+ flex: 1;
73
+ overflow: hidden;
74
+ text-overflow: ellipsis;
75
+ white-space: nowrap;
76
+ }
77
+
78
+ .medos-select-placeholder {
79
+ color: #94a3b8;
80
+ }
81
+
82
+ /* Select Icon */
83
+ .medos-select-icon {
84
+ height: 16px;
85
+ width: 16px;
86
+ opacity: 0.5;
87
+ flex-shrink: 0;
88
+ margin-left: 8px;
89
+ transition: transform 0.2s;
90
+ display: flex;
91
+ align-items: center;
92
+ justify-content: center;
93
+ }
94
+
95
+ .medos-select-trigger[aria-expanded="true"] .medos-select-icon {
96
+ transform: rotate(180deg);
97
+ }
98
+
99
+ .medos-select-icon-error {
100
+ color: #ef4444;
101
+ }
102
+
103
+ /* Content Dropdown - Portal */
104
+ .medos-select-content {
105
+ position: absolute;
106
+ z-index: 99999;
107
+ overflow: hidden;
108
+ border-radius: 6px;
109
+ border: 1px solid #e2e8f0;
110
+ background-color: #ffffff;
111
+ color: #1e293b;
112
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
113
+ animation: medos-select-show 0.15s ease-out;
114
+ box-sizing: border-box;
115
+ }
116
+
117
+ @keyframes medos-select-show {
118
+ from {
119
+ opacity: 0;
120
+ transform: translateY(-4px);
121
+ }
122
+ to {
123
+ opacity: 1;
124
+ transform: translateY(0);
125
+ }
126
+ }
127
+
128
+ /* Viewport */
129
+ .medos-select-viewport {
130
+ padding: 4px;
131
+ max-height: 256px;
132
+ overflow-y: auto;
133
+ }
134
+
135
+ /* Select Item */
136
+ .medos-select-item {
137
+ position: relative;
138
+ display: flex;
139
+ width: 100%;
140
+ cursor: pointer;
141
+ user-select: none;
142
+ align-items: center;
143
+ border-radius: 4px;
144
+ padding: 8px 8px 8px 32px;
145
+ font-size: 14px;
146
+ outline: none;
147
+ transition: background-color 0.1s ease;
148
+ box-sizing: border-box;
149
+ color: #1e293b;
150
+ }
151
+
152
+ .medos-select-item:hover:not(.medos-select-item-disabled) {
153
+ background-color: #f1f5f9;
154
+ }
155
+
156
+ .medos-select-item:focus {
157
+ background-color: #f1f5f9;
158
+ }
159
+
160
+ .medos-select-item-selected {
161
+ background-color: #f3f4f6;
162
+ }
163
+
164
+ .medos-select-item-disabled {
165
+ pointer-events: none;
166
+ opacity: 0.5;
167
+ cursor: not-allowed;
168
+ }
169
+
170
+ /* Item Indicator */
171
+ .medos-select-item-indicator {
172
+ position: absolute;
173
+ left: 8px;
174
+ display: flex;
175
+ height: 14px;
176
+ width: 14px;
177
+ align-items: center;
178
+ justify-content: center;
179
+ color: var(--medos-color-primary, #27903f);
180
+ }
181
+
182
+ /* Item Text */
183
+ .medos-select-item-text {
184
+ flex: 1;
185
+ }
186
+
187
+ /* Scrollbar styling */
188
+ .medos-select-viewport::-webkit-scrollbar {
189
+ width: 8px;
190
+ }
191
+
192
+ .medos-select-viewport::-webkit-scrollbar-track {
193
+ background: #f1f5f9;
194
+ border-radius: 4px;
195
+ }
196
+
197
+ .medos-select-viewport::-webkit-scrollbar-thumb {
198
+ background: #cbd5e1;
199
+ border-radius: 4px;
200
+ }
201
+
202
+ .medos-select-viewport::-webkit-scrollbar-thumb:hover {
203
+ background: #94a3b8;
204
+ }
205
+ `;
206
+ document.head.appendChild(styleElement);
207
+ }
208
+ export class VanillaSelect {
209
+ constructor(container, options, config = {}) {
210
+ this.selectedValue = "";
211
+ this.selectedLabel = "";
212
+ this.isOpen = false;
213
+ this.triggerElement = null;
214
+ this.contentElement = null;
215
+ this.handleDocumentClick = null;
216
+ this.handleWindowResize = null;
217
+ this.handleWindowScroll = null;
218
+ if (typeof container === "string") {
219
+ const el = document.getElementById(container);
220
+ if (!el) {
221
+ throw new Error(`Container element with id "${container}" not found`);
222
+ }
223
+ this.container = el;
224
+ }
225
+ else {
226
+ this.container = container;
227
+ }
228
+ this.options = options;
229
+ this.config = {
230
+ placeholder: "Select...",
231
+ disabled: false,
232
+ error: false,
233
+ ...config,
234
+ };
235
+ injectSelectStyles();
236
+ this.renderTrigger();
237
+ }
238
+ renderTrigger() {
239
+ const displayValue = this.selectedLabel || this.config.placeholder;
240
+ const isPlaceholder = !this.selectedLabel;
241
+ this.container.innerHTML = "";
242
+ this.container.classList.add("medos-select-container");
243
+ const button = document.createElement("button");
244
+ button.type = "button";
245
+ button.className = `medos-select-trigger ${this.config.error ? "medos-select-trigger-error" : ""}`;
246
+ button.setAttribute("aria-expanded", this.isOpen.toString());
247
+ button.setAttribute("aria-haspopup", "listbox");
248
+ if (this.config.disabled) {
249
+ button.disabled = true;
250
+ }
251
+ button.innerHTML = `
252
+ <span class="medos-select-value ${isPlaceholder ? "medos-select-placeholder" : ""}">
253
+ ${this.escapeHtml(displayValue || "")}
254
+ </span>
255
+ <span class="medos-select-icon ${this.config.error ? "medos-select-icon-error" : ""}">
256
+ ${VanillaIcons.chevronDown(16)}
257
+ </span>
258
+ `;
259
+ this.container.appendChild(button);
260
+ this.triggerElement = button;
261
+ this.attachTriggerEvents();
262
+ }
263
+ attachTriggerEvents() {
264
+ if (!this.triggerElement)
265
+ return;
266
+ this.triggerElement.addEventListener("click", (e) => {
267
+ e.preventDefault();
268
+ if (!this.config.disabled) {
269
+ this.toggleOpen();
270
+ }
271
+ });
272
+ this.triggerElement.addEventListener("keydown", (e) => {
273
+ if (this.config.disabled)
274
+ return;
275
+ if (e.key === "Enter" || e.key === " " || e.key === "ArrowDown") {
276
+ e.preventDefault();
277
+ this.open();
278
+ }
279
+ });
280
+ }
281
+ toggleOpen() {
282
+ if (this.isOpen) {
283
+ this.close();
284
+ }
285
+ else {
286
+ this.open();
287
+ }
288
+ }
289
+ open() {
290
+ if (this.isOpen || this.config.disabled)
291
+ return;
292
+ this.isOpen = true;
293
+ if (this.triggerElement) {
294
+ this.triggerElement.setAttribute("aria-expanded", "true");
295
+ }
296
+ this.createPortal();
297
+ this.attachPortalEvents();
298
+ setTimeout(() => {
299
+ if (this.contentElement) {
300
+ const selectedItem = this.contentElement.querySelector(".medos-select-item-selected");
301
+ const firstItem = this.contentElement.querySelector(".medos-select-item:not(.medos-select-item-disabled)");
302
+ (selectedItem || firstItem)?.focus();
303
+ }
304
+ }, 0);
305
+ }
306
+ close() {
307
+ if (!this.isOpen)
308
+ return;
309
+ this.isOpen = false;
310
+ if (this.triggerElement) {
311
+ this.triggerElement.setAttribute("aria-expanded", "false");
312
+ this.triggerElement.focus();
313
+ }
314
+ this.removePortal();
315
+ this.detachPortalEvents();
316
+ }
317
+ createPortal() {
318
+ if (!this.triggerElement)
319
+ return;
320
+ const rect = this.triggerElement.getBoundingClientRect();
321
+ const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
322
+ const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
323
+ this.contentElement = document.createElement("div");
324
+ this.contentElement.className = "medos-select-content";
325
+ this.contentElement.setAttribute("role", "listbox");
326
+ this.contentElement.style.top = `${rect.bottom + scrollTop + 4}px`;
327
+ this.contentElement.style.left = `${rect.left + scrollLeft}px`;
328
+ this.contentElement.style.width = `${rect.width}px`;
329
+ this.contentElement.innerHTML = `
330
+ <div class="medos-select-viewport">
331
+ ${this.options
332
+ .map((option) => `
333
+ <div
334
+ class="medos-select-item ${this.selectedValue === option.value
335
+ ? "medos-select-item-selected"
336
+ : ""} ${option.disabled ? "medos-select-item-disabled" : ""}"
337
+ role="option"
338
+ aria-selected="${this.selectedValue === option.value}"
339
+ data-value="${this.escapeHtml(option.value)}"
340
+ data-label="${this.escapeHtml(option.label)}"
341
+ ${option.disabled ? 'data-disabled="true"' : ""}
342
+ tabindex="${option.disabled ? "-1" : "0"}"
343
+ >
344
+ ${this.selectedValue === option.value
345
+ ? `
346
+ <span class="medos-select-item-indicator">
347
+ ${VanillaIcons.check(14)}
348
+ </span>
349
+ `
350
+ : ""}
351
+ <span class="medos-select-item-text">${this.escapeHtml(option.label)}</span>
352
+ </div>
353
+ `)
354
+ .join("")}
355
+ </div>
356
+ `;
357
+ document.body.appendChild(this.contentElement);
358
+ }
359
+ removePortal() {
360
+ this.contentElement?.remove();
361
+ this.contentElement = null;
362
+ }
363
+ updatePosition() {
364
+ if (!this.isOpen || !this.triggerElement || !this.contentElement)
365
+ return;
366
+ const rect = this.triggerElement.getBoundingClientRect();
367
+ const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
368
+ const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
369
+ this.contentElement.style.top = `${rect.bottom + scrollTop + 4}px`;
370
+ this.contentElement.style.left = `${rect.left + scrollLeft}px`;
371
+ this.contentElement.style.width = `${rect.width}px`;
372
+ }
373
+ attachPortalEvents() {
374
+ this.handleDocumentClick = (e) => {
375
+ const target = e.target;
376
+ if (this.isOpen &&
377
+ this.contentElement &&
378
+ !this.contentElement.contains(target) &&
379
+ this.triggerElement &&
380
+ !this.triggerElement.contains(target)) {
381
+ this.close();
382
+ }
383
+ };
384
+ document.addEventListener("mousedown", this.handleDocumentClick);
385
+ this.handleWindowResize = () => this.updatePosition();
386
+ this.handleWindowScroll = () => this.updatePosition();
387
+ window.addEventListener("resize", this.handleWindowResize);
388
+ window.addEventListener("scroll", this.handleWindowScroll, true);
389
+ if (this.contentElement) {
390
+ this.contentElement.addEventListener("click", (e) => {
391
+ const target = e.target;
392
+ const item = target.closest(".medos-select-item");
393
+ if (item && !item.dataset.disabled) {
394
+ const value = item.dataset.value || "";
395
+ const label = item.dataset.label || "";
396
+ this.selectValue(value, label);
397
+ }
398
+ });
399
+ this.contentElement.addEventListener("keydown", (e) => {
400
+ if (e.key === "Escape") {
401
+ this.close();
402
+ }
403
+ else if (e.key === "ArrowDown") {
404
+ e.preventDefault();
405
+ this.focusNextItem(1);
406
+ }
407
+ else if (e.key === "ArrowUp") {
408
+ e.preventDefault();
409
+ this.focusNextItem(-1);
410
+ }
411
+ else if (e.key === "Enter" || e.key === " ") {
412
+ e.preventDefault();
413
+ const focused = document.activeElement;
414
+ if (focused &&
415
+ focused.classList.contains("medos-select-item") &&
416
+ !focused.dataset.disabled) {
417
+ const value = focused.dataset.value || "";
418
+ const label = focused.dataset.label || "";
419
+ this.selectValue(value, label);
420
+ }
421
+ }
422
+ });
423
+ }
424
+ }
425
+ detachPortalEvents() {
426
+ if (this.handleDocumentClick) {
427
+ document.removeEventListener("mousedown", this.handleDocumentClick);
428
+ this.handleDocumentClick = null;
429
+ }
430
+ if (this.handleWindowResize) {
431
+ window.removeEventListener("resize", this.handleWindowResize);
432
+ this.handleWindowResize = null;
433
+ }
434
+ if (this.handleWindowScroll) {
435
+ window.removeEventListener("scroll", this.handleWindowScroll, true);
436
+ this.handleWindowScroll = null;
437
+ }
438
+ }
439
+ focusNextItem(direction) {
440
+ if (!this.contentElement)
441
+ return;
442
+ const items = Array.from(this.contentElement.querySelectorAll(".medos-select-item:not(.medos-select-item-disabled)"));
443
+ if (items.length === 0)
444
+ return;
445
+ const currentFocused = document.activeElement;
446
+ let currentIndex = items.indexOf(currentFocused);
447
+ let nextIndex = currentIndex + direction;
448
+ if (nextIndex < 0)
449
+ nextIndex = items.length - 1;
450
+ if (nextIndex >= items.length)
451
+ nextIndex = 0;
452
+ items[nextIndex]?.focus();
453
+ }
454
+ selectValue(value, label) {
455
+ this.selectedValue = value;
456
+ this.selectedLabel = label;
457
+ this.close();
458
+ this.renderTrigger();
459
+ this.config.onValueChange?.(value);
460
+ }
461
+ setValue(value) {
462
+ const option = this.options.find((o) => o.value === value);
463
+ if (option) {
464
+ this.selectedValue = option.value;
465
+ this.selectedLabel = option.label;
466
+ this.renderTrigger();
467
+ }
468
+ }
469
+ getValue() {
470
+ return this.selectedValue;
471
+ }
472
+ setOptions(options) {
473
+ this.options = options;
474
+ if (!options.some((o) => o.value === this.selectedValue)) {
475
+ this.selectedValue = "";
476
+ this.selectedLabel = "";
477
+ }
478
+ this.renderTrigger();
479
+ }
480
+ setDisabled(disabled) {
481
+ this.config.disabled = disabled;
482
+ this.renderTrigger();
483
+ this.attachTriggerEvents();
484
+ }
485
+ setError(error) {
486
+ this.config.error = error;
487
+ this.renderTrigger();
488
+ }
489
+ destroy() {
490
+ this.close();
491
+ this.container.innerHTML = "";
492
+ }
493
+ escapeHtml(text) {
494
+ const div = document.createElement("div");
495
+ div.textContent = text;
496
+ return div.innerHTML;
497
+ }
498
+ }
499
+ export function upgradeNativeSelect(selectElement, config = {}) {
500
+ const options = Array.from(selectElement.options).map((opt) => ({
501
+ value: opt.value,
502
+ label: opt.text,
503
+ disabled: opt.disabled,
504
+ }));
505
+ const container = document.createElement("div");
506
+ selectElement.parentNode?.insertBefore(container, selectElement);
507
+ selectElement.style.display = "none";
508
+ const vanillaSelect = new VanillaSelect(container, options, {
509
+ ...config,
510
+ placeholder: selectElement.options[0]?.text || "Select...",
511
+ disabled: selectElement.disabled,
512
+ onValueChange: (value) => {
513
+ selectElement.value = value;
514
+ selectElement.dispatchEvent(new Event("change", { bubbles: true }));
515
+ config.onValueChange?.(value);
516
+ },
517
+ });
518
+ if (selectElement.value) {
519
+ vanillaSelect.setValue(selectElement.value);
520
+ }
521
+ return vanillaSelect;
522
+ }
523
+ export default VanillaSelect;
@@ -0,0 +1,3 @@
1
+ export { VanillaIcons } from "./VanillaIcons";
2
+ export { VanillaSelect, upgradeNativeSelect, type SelectOption, type VanillaSelectOptions, } from "./VanillaSelect";
3
+ export { VanillaCalendar, type VanillaCalendarOptions, } from "./VanillaCalendar";
@@ -0,0 +1,3 @@
1
+ export { VanillaIcons } from "./VanillaIcons";
2
+ export { VanillaSelect, upgradeNativeSelect, } from "./VanillaSelect";
3
+ export { VanillaCalendar, } from "./VanillaCalendar";
@@ -0,0 +1 @@
1
+ export declare function injectThemedStyles(): void;