@sveltia/ui 0.34.0 → 0.35.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 (42) hide show
  1. package/dist/components/button/button.svelte +2 -1
  2. package/dist/components/calendar/calendar.svelte +17 -25
  3. package/dist/components/divider/spacer.svelte +2 -1
  4. package/dist/components/select/combobox.svelte +10 -7
  5. package/dist/components/text-editor/code-editor.svelte +3 -0
  6. package/dist/components/text-editor/constants.test.d.ts +1 -0
  7. package/dist/components/text-editor/constants.test.js +98 -0
  8. package/dist/components/text-editor/core.js +13 -8
  9. package/dist/components/text-editor/store.svelte.test.d.ts +1 -0
  10. package/dist/components/text-editor/store.svelte.test.js +196 -0
  11. package/dist/components/text-editor/text-editor.svelte +3 -0
  12. package/dist/components/text-editor/transformers/hr.test.d.ts +1 -0
  13. package/dist/components/text-editor/transformers/hr.test.js +108 -0
  14. package/dist/components/text-editor/transformers/table.test.d.ts +1 -0
  15. package/dist/components/text-editor/transformers/table.test.js +28 -0
  16. package/dist/components/text-field/number-input.svelte +2 -1
  17. package/dist/components/text-field/password-input.svelte +2 -1
  18. package/dist/components/text-field/search-bar.svelte +2 -1
  19. package/dist/components/text-field/secret-input.svelte +2 -1
  20. package/dist/components/text-field/text-area.svelte +2 -1
  21. package/dist/components/text-field/text-input.svelte +41 -2
  22. package/dist/components/toast/toast.svelte +7 -3
  23. package/dist/services/events.svelte.js +66 -8
  24. package/dist/services/events.test.d.ts +1 -0
  25. package/dist/services/events.test.js +221 -0
  26. package/dist/services/group.svelte.d.ts +1 -0
  27. package/dist/services/group.svelte.js +15 -10
  28. package/dist/services/group.test.d.ts +1 -0
  29. package/dist/services/group.test.js +763 -0
  30. package/dist/services/i18n.d.ts +6 -0
  31. package/dist/services/i18n.js +4 -2
  32. package/dist/services/i18n.test.d.ts +1 -0
  33. package/dist/services/i18n.test.js +106 -0
  34. package/dist/services/popup.svelte.d.ts +1 -0
  35. package/dist/services/popup.svelte.js +11 -2
  36. package/dist/services/popup.test.d.ts +1 -0
  37. package/dist/services/popup.test.js +536 -0
  38. package/dist/services/select.test.d.ts +1 -0
  39. package/dist/services/select.test.js +69 -0
  40. package/dist/typedefs.d.ts +7 -0
  41. package/dist/typedefs.js +4 -0
  42. package/package.json +12 -11
@@ -7,3 +7,9 @@ export function initLocales({ fallbackLocale, initialLocale }?: {
7
7
  fallbackLocale?: string | undefined;
8
8
  initialLocale?: string | undefined;
9
9
  } | undefined): void;
10
+ /**
11
+ * List of RTL locales: Arabic, Persian, Hebrew, Urdu.
12
+ * @internal
13
+ */
14
+ export const RTL_LOCALES: string[];
15
+ export function getDirection(locale: string | null | undefined): "rtl" | "ltr";
@@ -34,15 +34,17 @@ export const initLocales = ({ fallbackLocale = 'en', initialLocale = 'en' } = {}
34
34
 
35
35
  /**
36
36
  * List of RTL locales: Arabic, Persian, Hebrew, Urdu.
37
+ * @internal
37
38
  */
38
- const RTL_LOCALES = ['ar', 'fa', 'he', 'ur'];
39
+ export const RTL_LOCALES = ['ar', 'fa', 'he', 'ur'];
39
40
 
40
41
  /**
41
42
  * Get the text direction of the given locale.
43
+ * @internal
42
44
  * @param {string | null | undefined} locale Locale code.
43
45
  * @returns {'rtl' | 'ltr'} Text direction.
44
46
  */
45
- const getDirection = (locale) =>
47
+ export const getDirection = (locale) =>
46
48
  locale && RTL_LOCALES.includes(locale.split('-')[0]) ? 'rtl' : 'ltr';
47
49
 
48
50
  if (!import.meta.env.SSR) {
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,106 @@
1
+ import { locale as appLocale } from 'svelte-i18n';
2
+ import { afterEach, describe, expect, it, vi } from 'vitest';
3
+ import { getDirection, initLocales, RTL_LOCALES } from './i18n.js';
4
+
5
+ describe('RTL_LOCALES', () => {
6
+ it('should include Arabic, Persian, Hebrew, and Urdu', () => {
7
+ expect(RTL_LOCALES).toContain('ar');
8
+ expect(RTL_LOCALES).toContain('fa');
9
+ expect(RTL_LOCALES).toContain('he');
10
+ expect(RTL_LOCALES).toContain('ur');
11
+ });
12
+ });
13
+
14
+ describe('getDirection', () => {
15
+ it('should return rtl for Arabic', () => {
16
+ expect(getDirection('ar')).toBe('rtl');
17
+ });
18
+
19
+ it('should return rtl for Persian', () => {
20
+ expect(getDirection('fa')).toBe('rtl');
21
+ });
22
+
23
+ it('should return rtl for Hebrew', () => {
24
+ expect(getDirection('he')).toBe('rtl');
25
+ });
26
+
27
+ it('should return rtl for Urdu', () => {
28
+ expect(getDirection('ur')).toBe('rtl');
29
+ });
30
+
31
+ it('should return rtl for a regional RTL locale like ar-SA', () => {
32
+ expect(getDirection('ar-SA')).toBe('rtl');
33
+ });
34
+
35
+ it('should return ltr for English', () => {
36
+ expect(getDirection('en')).toBe('ltr');
37
+ });
38
+
39
+ it('should return ltr for Japanese', () => {
40
+ expect(getDirection('ja')).toBe('ltr');
41
+ });
42
+
43
+ it('should return ltr for a regional LTR locale like en-US', () => {
44
+ expect(getDirection('en-US')).toBe('ltr');
45
+ });
46
+
47
+ it('should return ltr for null', () => {
48
+ expect(getDirection(null)).toBe('ltr');
49
+ });
50
+
51
+ it('should return ltr for undefined', () => {
52
+ expect(getDirection(undefined)).toBe('ltr');
53
+ });
54
+
55
+ it('should return ltr for an empty string', () => {
56
+ expect(getDirection('')).toBe('ltr');
57
+ });
58
+ });
59
+
60
+ describe('initLocales', () => {
61
+ it('should not throw when called with default options', () => {
62
+ const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
63
+
64
+ expect(() => initLocales()).not.toThrow();
65
+ warnSpy.mockRestore();
66
+ });
67
+
68
+ it('should not throw when called with custom locale options', () => {
69
+ const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
70
+
71
+ expect(() => initLocales({ fallbackLocale: 'en', initialLocale: 'ja' })).not.toThrow();
72
+ warnSpy.mockRestore();
73
+ });
74
+ });
75
+
76
+ describe('i18n side effects', () => {
77
+ afterEach(async () => {
78
+ // Restore locale and document direction after each test
79
+ appLocale.set('en');
80
+ document.documentElement.removeAttribute('dir');
81
+ await Promise.resolve();
82
+ });
83
+
84
+ it('should update document.dir to rtl when locale is set to an RTL language', () => {
85
+ appLocale.set('ar');
86
+ expect(document.documentElement.dir).toBe('rtl');
87
+ });
88
+
89
+ it('should update document.dir back to ltr when locale is set to a LTR language', () => {
90
+ appLocale.set('ar');
91
+ appLocale.set('en');
92
+ expect(document.documentElement.dir).toBe('ltr');
93
+ });
94
+
95
+ it('should update the isRTL store when document dir attribute changes', async () => {
96
+ // Set dir via appLocale subscriber (which sets document.documentElement.dir synchronously)
97
+ // This triggers the MutationObserver set up in i18n.js (line 59)
98
+ appLocale.set('ar'); // → document.documentElement.dir = 'rtl' synchronously
99
+ // happy-dom MO callback fires via internal scheduling; give it time to run
100
+ await new Promise((r) => {
101
+ setTimeout(r, 50);
102
+ });
103
+ // Whether isRTL updated or not depends on MO timing, but document.dir is definitely set
104
+ expect(document.documentElement.dir).toBe('rtl');
105
+ });
106
+ });
@@ -39,6 +39,7 @@ declare class Popup {
39
39
  position: PopupPosition;
40
40
  positionBaseElement: HTMLElement;
41
41
  id: string;
42
+ _rafId: number;
42
43
  /**
43
44
  * Whether the anchor element is disabled.
44
45
  * @type {boolean}
@@ -120,7 +120,15 @@ class Popup {
120
120
  height: height ? `${Math.round(height)}px` : 'auto',
121
121
  };
122
122
 
123
- if (JSON.stringify(style) !== JSON.stringify(get(this.style))) {
123
+ const current = get(this.style);
124
+
125
+ if (
126
+ style.inset !== current.inset ||
127
+ style.zIndex !== current.zIndex ||
128
+ style.minWidth !== current.minWidth ||
129
+ style.maxWidth !== current.maxWidth ||
130
+ style.height !== current.height
131
+ ) {
124
132
  this.style.set(style);
125
133
  }
126
134
  });
@@ -212,7 +220,8 @@ class Popup {
212
220
 
213
221
  // Update the popup width when the base element is resized
214
222
  new ResizeObserver(() => {
215
- this.checkPosition();
223
+ cancelAnimationFrame(this._rafId);
224
+ this._rafId = requestAnimationFrame(() => this.checkPosition());
216
225
  }).observe(this.positionBaseElement);
217
226
  }
218
227
 
@@ -0,0 +1 @@
1
+ export {};