@widgetic/editor 4.0.6 → 4.0.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 (64) hide show
  1. package/README.md +12 -1
  2. package/dist/components/WidgetPreview.svelte +42 -1
  3. package/dist/components/WidgetPreview.svelte.d.ts +8 -0
  4. package/dist/components/editors/EmbedEditor.svelte +101 -530
  5. package/dist/components/editors/EmbedEditor.svelte.d.ts +7 -17
  6. package/dist/components/editors/PropsEditor.svelte +328 -142
  7. package/dist/components/editors/PropsEditor.svelte.d.ts +13 -2
  8. package/dist/components/ic/AngleInputController.svelte +21 -7
  9. package/dist/components/ic/AngleInputController.svelte.d.ts +16 -6
  10. package/dist/components/ic/BrowserInputController.svelte +28 -15
  11. package/dist/components/ic/BrowserInputController.svelte.d.ts +25 -19
  12. package/dist/components/ic/CheckboxInputController.svelte +21 -7
  13. package/dist/components/ic/CheckboxInputController.svelte.d.ts +25 -15
  14. package/dist/components/ic/ColorPickerInputController.svelte +47 -21
  15. package/dist/components/ic/ColorPickerInputController.svelte.d.ts +42 -19
  16. package/dist/components/ic/DateFieldInputController.svelte +21 -7
  17. package/dist/components/ic/DateFieldInputController.svelte.d.ts +24 -14
  18. package/dist/components/ic/DatePickerInputController.svelte +25 -8
  19. package/dist/components/ic/DatePickerInputController.svelte.d.ts +21 -8
  20. package/dist/components/ic/DropdownInputController.svelte +69 -19
  21. package/dist/components/ic/DropdownInputController.svelte.d.ts +33 -17
  22. package/dist/components/ic/FixedPositionInputController.svelte +24 -10
  23. package/dist/components/ic/FixedPositionInputController.svelte.d.ts +16 -4
  24. package/dist/components/ic/FontInputController.svelte +53 -18
  25. package/dist/components/ic/FontInputController.svelte.d.ts +33 -18
  26. package/dist/components/ic/InputControllerRenderer.svelte +98 -0
  27. package/dist/components/ic/InputControllerRenderer.svelte.d.ts +40 -0
  28. package/dist/components/ic/NumberInputController.svelte +23 -9
  29. package/dist/components/ic/NumberInputController.svelte.d.ts +18 -7
  30. package/dist/components/ic/PositionInputController.svelte +17 -5
  31. package/dist/components/ic/PositionInputController.svelte.d.ts +20 -11
  32. package/dist/components/ic/RadioGroupInputController.svelte +21 -7
  33. package/dist/components/ic/RadioGroupInputController.svelte.d.ts +22 -12
  34. package/dist/components/ic/RangeCalendarInputController.svelte +34 -16
  35. package/dist/components/ic/RangeCalendarInputController.svelte.d.ts +25 -11
  36. package/dist/components/ic/RoundedCornersInputController.svelte +26 -22
  37. package/dist/components/ic/RoundedCornersInputController.svelte.d.ts +26 -18
  38. package/dist/components/ic/SliderInputController.svelte +41 -18
  39. package/dist/components/ic/SliderInputController.svelte.d.ts +35 -19
  40. package/dist/components/ic/SliderRangeInputController.svelte +27 -11
  41. package/dist/components/ic/SliderRangeInputController.svelte.d.ts +22 -9
  42. package/dist/components/ic/SwitchInputController.svelte +17 -5
  43. package/dist/components/ic/SwitchInputController.svelte.d.ts +14 -5
  44. package/dist/components/ic/TagsInputController.svelte +21 -7
  45. package/dist/components/ic/TagsInputController.svelte.d.ts +16 -6
  46. package/dist/components/ic/TextAreaInputController.svelte +44 -25
  47. package/dist/components/ic/TextAreaInputController.svelte.d.ts +6 -4
  48. package/dist/components/ic/TextAreaPreviewInputController.svelte +21 -7
  49. package/dist/components/ic/TextAreaPreviewInputController.svelte.d.ts +16 -6
  50. package/dist/components/ic/TextInputController.svelte +23 -8
  51. package/dist/components/ic/TextInputController.svelte.d.ts +20 -8
  52. package/dist/components/ic/TimeInputController.svelte +17 -5
  53. package/dist/components/ic/TimeInputController.svelte.d.ts +14 -5
  54. package/dist/components/ic/VectorInputController.svelte +29 -10
  55. package/dist/components/ic/VectorInputController.svelte.d.ts +33 -18
  56. package/dist/components/icons/locked.svelte +5 -1
  57. package/dist/components/icons/locked.svelte.d.ts +11 -24
  58. package/dist/components/icons/unlocked.svelte +5 -1
  59. package/dist/components/icons/unlocked.svelte.d.ts +11 -24
  60. package/dist/index.d.ts +1 -0
  61. package/dist/schemaViews.d.ts +105 -0
  62. package/dist/schemaViews.js +11 -0
  63. package/dist/utils/FontManager.js +11 -4
  64. package/package.json +16 -12
@@ -17,6 +17,23 @@
17
17
  * - Maintains dropdown state consistency
18
18
  -->
19
19
 
20
+ <script module lang="ts">
21
+ import type { Writable } from 'svelte/store';
22
+
23
+ /** Declared props contract — export lets below are annotated from it so the
24
+ * interface cannot drift from what the component actually reads. */
25
+ export interface DatePickerInputControllerProps {
26
+ label: string;
27
+ value?: any;
28
+ onChange: (newValue: CalendarDate) => void;
29
+ description?: string;
30
+ controllerId: string;
31
+ openDropdowns: Writable<Set<string>>;
32
+ toggleDropdown: (id: string) => void;
33
+ onFocus?: () => void;
34
+ }
35
+ </script>
36
+
20
37
  <script lang="ts">
21
38
  // Svelte imports
22
39
  import { onMount, onDestroy } from 'svelte';
@@ -35,14 +52,14 @@
35
52
  import { IconCalendar } from '@widgetic/design-system/icons';
36
53
 
37
54
  // Component props with TypeScript types
38
- export let label: string;
39
- export let value: any;
40
- export let onChange: (newValue: CalendarDate) => void;
41
- export let description: string | undefined = undefined;
42
- export let controllerId: string;
43
- export let openDropdowns: any;
44
- export let toggleDropdown: (id: string) => void;
45
- export let onFocus: () => void = () => {};
55
+ export let label: DatePickerInputControllerProps['label'];
56
+ export let value: DatePickerInputControllerProps['value'];
57
+ export let onChange: DatePickerInputControllerProps['onChange'];
58
+ export let description: DatePickerInputControllerProps['description'] = undefined;
59
+ export let controllerId: DatePickerInputControllerProps['controllerId'];
60
+ export let openDropdowns: DatePickerInputControllerProps['openDropdowns'];
61
+ export let toggleDropdown: DatePickerInputControllerProps['toggleDropdown'];
62
+ export let onFocus: DatePickerInputControllerProps['onFocus'] = () => {};
46
63
 
47
64
  // Default to today's date in local timezone for placeholder
48
65
  let placeholder = today(getLocalTimeZone());
@@ -1,3 +1,16 @@
1
+ import type { Writable } from 'svelte/store';
2
+ /** Declared props contract — export lets below are annotated from it so the
3
+ * interface cannot drift from what the component actually reads. */
4
+ export interface DatePickerInputControllerProps {
5
+ label: string;
6
+ value?: any;
7
+ onChange: (newValue: CalendarDate) => void;
8
+ description?: string;
9
+ controllerId: string;
10
+ openDropdowns: Writable<Set<string>>;
11
+ toggleDropdown: (id: string) => void;
12
+ onFocus?: () => void;
13
+ }
1
14
  import { CalendarDate } from "@internationalized/date";
2
15
  interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
3
16
  new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
@@ -13,14 +26,14 @@ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> =
13
26
  z_$$bindings?: Bindings;
14
27
  }
15
28
  declare const DatePickerInputController: $$__sveltets_2_IsomorphicComponent<{
16
- label: string;
17
- value: any;
18
- onChange: (newValue: CalendarDate) => void;
19
- description?: string | undefined;
20
- controllerId: string;
21
- openDropdowns: any;
22
- toggleDropdown: (id: string) => void;
23
- onFocus?: () => void;
29
+ label: DatePickerInputControllerProps["label"];
30
+ value: DatePickerInputControllerProps["value"];
31
+ onChange: DatePickerInputControllerProps["onChange"];
32
+ description?: DatePickerInputControllerProps["description"];
33
+ controllerId: DatePickerInputControllerProps["controllerId"];
34
+ openDropdowns: DatePickerInputControllerProps["openDropdowns"];
35
+ toggleDropdown: DatePickerInputControllerProps["toggleDropdown"];
36
+ onFocus?: DatePickerInputControllerProps["onFocus"];
24
37
  }, {
25
38
  [evt: string]: CustomEvent<any>;
26
39
  }, {}, {}, string>;
@@ -1,3 +1,24 @@
1
+ <script module lang="ts">
2
+ import type { Writable } from 'svelte/store';
3
+ import type { InputControllerConfig } from './index';
4
+
5
+ /** Declared props contract — export lets below are annotated from it so the
6
+ * interface cannot drift from what the component actually reads. */
7
+ export interface DropdownInputControllerProps {
8
+ label: string;
9
+ defaultSelectedLabel?: string;
10
+ value: string | { value: string; label: string };
11
+ onChange: (newValue: string) => void;
12
+ config?: InputControllerConfig;
13
+ options?: { value: string; label: string }[];
14
+ description?: string;
15
+ controllerId: string;
16
+ openDropdowns: Writable<Set<string>>;
17
+ toggleDropdown: (id: string) => void;
18
+ onFocus?: () => void;
19
+ }
20
+ </script>
21
+
1
22
  <script lang="ts">
2
23
  /**
3
24
  * DropdownInputController Component
@@ -10,7 +31,6 @@
10
31
  * Required for component setup and cleanup
11
32
  */
12
33
  import { onMount, onDestroy } from 'svelte';
13
- import type { InputControllerConfig } from './index';
14
34
 
15
35
  // Local Components imports
16
36
  import { InputControllerHeader } from './index';
@@ -28,22 +48,22 @@
28
48
  * Component Props
29
49
  * External properties that configure the dropdown's behavior and appearance
30
50
  */
31
- export let label: string; // Display label for the dropdown
32
- export let defaultSelectedLabel: string = "Select an option"; // Default value for the dropdown
33
- export let value: string | { value: string; label: string }; // Currently selected value
34
- export let onChange: (newValue: string) => void; // Callback for value changes
35
- export let config: InputControllerConfig = {}; // Additional configuration options
51
+ export let label: DropdownInputControllerProps['label'];
52
+ export let defaultSelectedLabel: DropdownInputControllerProps['defaultSelectedLabel'] = "Select an option";
53
+ export let value: DropdownInputControllerProps['value'];
54
+ export let onChange: DropdownInputControllerProps['onChange'];
55
+ export let config: DropdownInputControllerProps['config'] = {};
36
56
 
37
57
  /**
38
58
  * Configuration Options
39
59
  * Derived from config prop with fallbacks
40
60
  */
41
- export let options: { value: string; label: string }[] = config.options || []; // Available options
42
- export let description: string | undefined = undefined; // Optional help text
43
- export let controllerId: string; // Unique identifier for the controller
44
- export let openDropdowns: any; // External store tracking open dropdowns
45
- export let toggleDropdown: (id: string) => void; // Function to toggle dropdown state
46
- export let onFocus: () => void = () => {}; // Focus event handler
61
+ export let options: DropdownInputControllerProps['options'] = config.options || [];
62
+ export let description: DropdownInputControllerProps['description'] = undefined;
63
+ export let controllerId: DropdownInputControllerProps['controllerId'];
64
+ export let openDropdowns: DropdownInputControllerProps['openDropdowns'];
65
+ export let toggleDropdown: DropdownInputControllerProps['toggleDropdown'];
66
+ export let onFocus: DropdownInputControllerProps['onFocus'] = () => {};
47
67
 
48
68
  /**
49
69
  * Reactive State
@@ -51,6 +71,10 @@
51
71
  */
52
72
  $: open = $openDropdowns?.has(controllerId) || false;
53
73
 
74
+ /** Timestamp of the last open — used to ignore bits-ui's own opening scrolls. */
75
+ let lastOpenTimestamp = 0;
76
+ $: if (open) lastOpenTimestamp = performance.now();
77
+
54
78
  /**
55
79
  * Closes the dropdown if it's currently open
56
80
  * Used for cleanup and external close triggers
@@ -63,9 +87,25 @@
63
87
 
64
88
  /**
65
89
  * Scroll Event Handler
66
- * Closes dropdown when scrolling occurs to prevent floating UI issues
90
+ * Closes dropdown when scrolling occurs to prevent floating UI issues.
91
+ * Guarded: bits-ui may scroll the viewport/list right after opening, and the
92
+ * capture-phase listener would otherwise close the dropdown in the same frame
93
+ * (which looked like "the dropdown never opens" in the Embed overlay).
67
94
  */
68
- function handleScroll() {
95
+ function handleScroll(event?: Event) {
96
+ if (!open) return;
97
+ // Grace period after opening — ignore self-inflicted scrolls from bits-ui.
98
+ if (performance.now() - lastOpenTimestamp < 300) return;
99
+ // Never close on scrolls that happen inside the dropdown itself or its portal.
100
+ const target = event?.target as Node | null;
101
+ if (
102
+ target instanceof Element &&
103
+ (target.closest('[data-bits-floating-content-wrapper]') ||
104
+ target.closest('[role="listbox"]') ||
105
+ target.closest('.dropdown-ic-content'))
106
+ ) {
107
+ return;
108
+ }
69
109
  closeDropdown();
70
110
  }
71
111
 
@@ -104,7 +144,13 @@
104
144
  }
105
145
  }
106
146
 
107
- $: triggerContent = options.find((o) => o.value === (value.value || value))?.label ?? defaultSelectedLabel;
147
+ /**
148
+ * The option label for the current selection. `value` accepts a bare string
149
+ * or an option object; normalize once instead of re-narrowing at each read.
150
+ */
151
+ $: selectedValue = typeof value === 'string' ? value : value?.value;
152
+ $: triggerContent =
153
+ options.find((o) => o.value === selectedValue)?.label ?? defaultSelectedLabel;
108
154
  </script>
109
155
 
110
156
  <!-- Dropdown Container -->
@@ -122,7 +168,7 @@
122
168
  >
123
169
  <Select.Root
124
170
  type="single"
125
- value={value.value || value}
171
+ value={selectedValue}
126
172
  onValueChange={handleValueChange}
127
173
  open={open}
128
174
  onOpenChange={handleOpenChange}
@@ -218,9 +264,13 @@
218
264
  display: none;
219
265
  }
220
266
 
221
- /* Override bits-ui floating wrapper z-index (default 50 is too low).
222
- The wrapper is portaled to body by bits-ui, so we target it globally. */
267
+ /* bits-ui portals the Select content to <body> and wraps it in
268
+ [data-bits-floating-content-wrapper]. The floating layer's default z-index
269
+ (50) sat below page overlays — in the composition Embed overlay
270
+ (z-index 100000) the dropdown opened but was painted behind the dark
271
+ backdrop, so it looked like it never opened. Lift the wrapper above any
272
+ app overlay. */
223
273
  :global([data-bits-floating-content-wrapper]) {
224
- z-index: 99999 !important;
274
+ z-index: 1000001 !important;
225
275
  }
226
276
  </style>
@@ -1,4 +1,26 @@
1
+ import type { Writable } from 'svelte/store';
1
2
  import type { InputControllerConfig } from './index';
3
+ /** Declared props contract — export lets below are annotated from it so the
4
+ * interface cannot drift from what the component actually reads. */
5
+ export interface DropdownInputControllerProps {
6
+ label: string;
7
+ defaultSelectedLabel?: string;
8
+ value: string | {
9
+ value: string;
10
+ label: string;
11
+ };
12
+ onChange: (newValue: string) => void;
13
+ config?: InputControllerConfig;
14
+ options?: {
15
+ value: string;
16
+ label: string;
17
+ }[];
18
+ description?: string;
19
+ controllerId: string;
20
+ openDropdowns: Writable<Set<string>>;
21
+ toggleDropdown: (id: string) => void;
22
+ onFocus?: () => void;
23
+ }
2
24
  interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
3
25
  new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
4
26
  $$bindings?: Bindings;
@@ -16,26 +38,20 @@ declare const DropdownInputController: $$__sveltets_2_IsomorphicComponent<{
16
38
  /**
17
39
  * Component Props
18
40
  * External properties that configure the dropdown's behavior and appearance
19
- */ label: string;
20
- defaultSelectedLabel?: string;
21
- value: string | {
22
- value: string;
23
- label: string;
24
- };
25
- onChange: (newValue: string) => void;
26
- config?: InputControllerConfig;
41
+ */ label: DropdownInputControllerProps["label"];
42
+ defaultSelectedLabel?: DropdownInputControllerProps["defaultSelectedLabel"];
43
+ value: DropdownInputControllerProps["value"];
44
+ onChange: DropdownInputControllerProps["onChange"];
45
+ config?: DropdownInputControllerProps["config"];
27
46
  /**
28
47
  * Configuration Options
29
48
  * Derived from config prop with fallbacks
30
- */ options?: {
31
- value: string;
32
- label: string;
33
- }[];
34
- description?: string | undefined;
35
- controllerId: string;
36
- openDropdowns: any;
37
- toggleDropdown: (id: string) => void;
38
- onFocus?: () => void;
49
+ */ options?: DropdownInputControllerProps["options"];
50
+ description?: DropdownInputControllerProps["description"];
51
+ controllerId: DropdownInputControllerProps["controllerId"];
52
+ openDropdowns: DropdownInputControllerProps["openDropdowns"];
53
+ toggleDropdown: DropdownInputControllerProps["toggleDropdown"];
54
+ onFocus?: DropdownInputControllerProps["onFocus"];
39
55
  }, {
40
56
  [evt: string]: CustomEvent<any>;
41
57
  }, {}, {}, string>;
@@ -17,6 +17,26 @@
17
17
  * - Manages dynamic SVG creation and disposal
18
18
  -->
19
19
 
20
+ <script module lang="ts">
21
+ /** The nine grid alignments the controller can select — shared between the
22
+ * props contract above and the instance script below. */
23
+ const positions = [
24
+ 'top-left', 'top-center', 'top-right',
25
+ 'center-left', 'center-center', 'center-right',
26
+ 'bottom-left', 'bottom-center', 'bottom-right'
27
+ ] as const;
28
+ type Position = typeof positions[number];
29
+
30
+ /** Declared props contract — export lets below are annotated from it so the
31
+ * interface cannot drift from what the component actually reads. */
32
+ export interface FixedPositionInputControllerProps {
33
+ value?: Position;
34
+ onChange: (newValue: Position) => void;
35
+ onFocus?: () => void;
36
+ id?: string;
37
+ }
38
+ </script>
39
+
20
40
  <script lang="ts">
21
41
  // Svelte imports
22
42
  import { onDestroy } from 'svelte';
@@ -79,21 +99,15 @@
79
99
  };
80
100
 
81
101
  // Component props
82
- export let value: Position = 'bottom-right'; // Update type to Position
83
- export let onChange: (newValue: Position) => void;
84
- export let onFocus: () => void = () => {};
85
- export let id: string | undefined = undefined;
102
+ export let value: FixedPositionInputControllerProps['value'] = 'bottom-right';
103
+ export let onChange: FixedPositionInputControllerProps['onChange'];
104
+ export let onFocus: FixedPositionInputControllerProps['onFocus'] = () => {};
105
+ export let id: FixedPositionInputControllerProps['id'] = undefined;
86
106
 
87
107
  /**
88
108
  * Defines all valid position combinations in a 3x3 grid
89
109
  * Order matters for visual layout and keyboard navigation
90
110
  */
91
- const positions = [
92
- 'top-left', 'top-center', 'top-right',
93
- 'center-left', 'center-center', 'center-right',
94
- 'bottom-left', 'bottom-center', 'bottom-right'
95
- ] as const;
96
-
97
111
  type Position = typeof positions[number];
98
112
 
99
113
  // Map positions to their corresponding icons
@@ -1,3 +1,15 @@
1
+ /** The nine grid alignments the controller can select — shared between the
2
+ * props contract above and the instance script below. */
3
+ declare const positions: readonly ["top-left", "top-center", "top-right", "center-left", "center-center", "center-right", "bottom-left", "bottom-center", "bottom-right"];
4
+ type Position = typeof positions[number];
5
+ /** Declared props contract — export lets below are annotated from it so the
6
+ * interface cannot drift from what the component actually reads. */
7
+ export interface FixedPositionInputControllerProps {
8
+ value?: Position;
9
+ onChange: (newValue: Position) => void;
10
+ onFocus?: () => void;
11
+ id?: string;
12
+ }
1
13
  interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
2
14
  new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
3
15
  $$bindings?: Bindings;
@@ -12,10 +24,10 @@ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> =
12
24
  z_$$bindings?: Bindings;
13
25
  }
14
26
  declare const FixedPositionInputController: $$__sveltets_2_IsomorphicComponent<{
15
- value?: "top-left" | "top-center" | "top-right" | "center-left" | "center-center" | "center-right" | "bottom-left" | "bottom-center" | "bottom-right";
16
- onChange: (newValue: "top-left" | "top-center" | "top-right" | "center-left" | "center-center" | "center-right" | "bottom-left" | "bottom-center" | "bottom-right") => void;
17
- onFocus?: () => void;
18
- id?: string | undefined;
27
+ value?: FixedPositionInputControllerProps["value"];
28
+ onChange: FixedPositionInputControllerProps["onChange"];
29
+ onFocus?: FixedPositionInputControllerProps["onFocus"];
30
+ id?: FixedPositionInputControllerProps["id"];
19
31
  }, {
20
32
  [evt: string]: CustomEvent<any>;
21
33
  }, {}, {}, string>;
@@ -18,6 +18,23 @@
18
18
  * - Uses font-display: swap for better loading UX
19
19
  -->
20
20
 
21
+ <script module lang="ts">
22
+ /** Declared props contract — export lets below are annotated from it so the
23
+ * interface cannot drift from what the component actually reads. */
24
+ export interface FontInputControllerProps {
25
+ label?: string;
26
+ style?: string;
27
+ value?: { family: string; weight: string; category: string } | string | null;
28
+ onChange?: (newValue: { family: string; weight: string; category: string }) => void;
29
+ description?: string;
30
+ controllerId: string;
31
+ openDropdowns: Writable<Set<string>>;
32
+ toggleDropdown: (id: string) => void;
33
+ hideRecentFromList?: boolean;
34
+ hideTrashIcon?: boolean;
35
+ }
36
+ </script>
37
+
21
38
  <script lang="ts">
22
39
  // Svelte imports
23
40
  import { onMount, onDestroy, tick } from 'svelte';
@@ -46,6 +63,7 @@
46
63
  import FontManager, { mapGoogleVariantIdsToWeightNames } from '../../utils/FontManager';
47
64
 
48
65
  import { shouldSkipFont } from '../../utils/skipFonts';
66
+ import type { Writable } from 'svelte/store';
49
67
 
50
68
  import { InputControllerHeader } from './index';
51
69
 
@@ -77,16 +95,16 @@
77
95
  * @prop {Function} toggleDropdown - Function to toggle dropdown state
78
96
  * @prop {Function} onFocus - Optional focus handler
79
97
  */
80
- export let label: string = '';
98
+ export let label: FontInputControllerProps['label'] = '';
81
99
  let className = '';
82
100
  export { className as class };
83
- export let style = '';
84
- export let value: { family: string; weight: string; category: string } | string | null = null;
85
- export let onChange: ((newValue: { family: string; weight: string; category: string }) => void) | undefined = undefined;
86
- export let description: string | undefined = undefined;
87
- export let controllerId: string;
88
- export let openDropdowns: any;
89
- export let toggleDropdown: (id: string) => void;
101
+ export let style: FontInputControllerProps['style'] = '';
102
+ export let value: FontInputControllerProps['value'] = null;
103
+ export let onChange: FontInputControllerProps['onChange'] = undefined;
104
+ export let description: FontInputControllerProps['description'] = undefined;
105
+ export let controllerId: FontInputControllerProps['controllerId'];
106
+ export let openDropdowns: FontInputControllerProps['openDropdowns'];
107
+ export let toggleDropdown: FontInputControllerProps['toggleDropdown'];
90
108
 
91
109
  // Initialize timeouts
92
110
  let scrollTimeout: ReturnType<typeof setTimeout> | null = null;
@@ -95,6 +113,7 @@
95
113
  // Font weight state - remove localStorage check on init
96
114
  let selectedWeight = `${controllerId}-Regular`;
97
115
  let availableWeights: string[] = ['Regular', 'Medium', 'SemiBold', 'Bold'];
116
+ let fontCatalogFallbackWarned = false;
98
117
 
99
118
  // Font search and filter state
100
119
  let allFonts: FontItem[] = [];
@@ -123,8 +142,8 @@
123
142
  let isInitialLoading = true; // Start with loading state true
124
143
 
125
144
  // Add new prop for controlling font list behavior
126
- export let hideRecentFromList: boolean = false;
127
- export let hideTrashIcon: boolean = true;
145
+ export let hideRecentFromList: FontInputControllerProps['hideRecentFromList'] = false;
146
+ export let hideTrashIcon: FontInputControllerProps['hideTrashIcon'] = true;
128
147
 
129
148
  function updateFamilyPopoverBox() {
130
149
  if (!familyTriggerEl || typeof window === 'undefined') return;
@@ -625,7 +644,7 @@
625
644
 
626
645
  // try {
627
646
  // // Get the current font's ID if it exists in our custom fonts
628
- // const selectedId = value?.family ?
647
+ // const selectedId = resolvedFont?.family ?
629
648
  // fontManagerInstance?.getCachedFontList()
630
649
  // .find(f => f.family === value.family && f.category === 'Mine')?.id
631
650
  // : undefined;
@@ -1360,6 +1379,9 @@
1360
1379
  */
1361
1380
  async function fetchFontWeights(fontFamily: string) {
1362
1381
  try {
1382
+ // Wait for FontManager init — reactive weight fetch can race ahead of onMount.
1383
+ fontManagerInstance = await FontManager.getInstance(appConfig.GOOGLE_FONTS_API_KEY);
1384
+
1363
1385
  // First check if it's a custom font using FontManager
1364
1386
  if (fontManagerInstance?.isCustomFont(fontFamily)) {
1365
1387
  // Get custom font data
@@ -1397,7 +1419,16 @@
1397
1419
  }
1398
1420
 
1399
1421
  // Google font: use catalog cached by FontManager (no extra API call per font)
1400
- const variantIds = fontManagerInstance?.getGoogleFontVariantIds(fontFamily);
1422
+ let variantIds = fontManagerInstance?.getGoogleFontVariantIds(fontFamily);
1423
+ if (!variantIds?.length) {
1424
+ // Catalog may still be empty right after init edge cases — force list load once.
1425
+ try {
1426
+ await fontManagerInstance.getInitialFontList();
1427
+ } catch (catalogError) {
1428
+ console.warn('[FontInput] Catalog refresh failed before weight lookup:', catalogError);
1429
+ }
1430
+ variantIds = fontManagerInstance?.getGoogleFontVariantIds(fontFamily);
1431
+ }
1401
1432
  if (variantIds?.length) {
1402
1433
  availableWeights = mapGoogleVariantIdsToWeightNames(variantIds);
1403
1434
  if (!availableWeights.includes(selectedWeight.replace(`${controllerId}-`, ''))) {
@@ -1407,7 +1438,11 @@
1407
1438
  }
1408
1439
 
1409
1440
  // API unavailable (403 / no catalog): sensible defaults, still loads via fonts.googleapis.com CSS
1410
- console.warn('[FontInput] Using default weights for font (Google catalog not loaded):', fontFamily);
1441
+ // Warn once — not on every reactive re-run during catalog race.
1442
+ if (!fontCatalogFallbackWarned) {
1443
+ fontCatalogFallbackWarned = true;
1444
+ console.warn('[FontInput] Using default weights (Google catalog not loaded). Later fonts will use the same fallback silently.');
1445
+ }
1411
1446
  availableWeights = ['Regular', 'Bold'];
1412
1447
  selectedWeight = `${controllerId}-Regular`;
1413
1448
  } catch (error) {
@@ -1431,7 +1466,7 @@
1431
1466
  */
1432
1467
  function highlightMatch(name: string, term: string) {
1433
1468
  // Check if this font is the selected one
1434
- const isSelected = value?.family === name;
1469
+ const isSelected = resolvedFont?.family === name;
1435
1470
 
1436
1471
  if (!term) {
1437
1472
  // If no search term, just return the name with appropriate color
@@ -1558,7 +1593,7 @@
1558
1593
  await fontManagerInstance?.removeCustomFont(fontFamily);
1559
1594
 
1560
1595
  // If the removed font was selected, clear the selection
1561
- if (value?.family === fontFamily && onChange) {
1596
+ if (resolvedFont?.family === fontFamily && onChange) {
1562
1597
  onChange({
1563
1598
  family: '',
1564
1599
  weight: 'Regular',
@@ -1719,7 +1754,7 @@
1719
1754
  }
1720
1755
  }}
1721
1756
  >
1722
- <Popover.Trigger tabindex="-1" class="w-full h-full flex items-center border-0 bg-transparent hover:bg-transparent focus:bg-transparent pl-3 pr-[16px] group"
1757
+ <Popover.Trigger tabindex={-1} class="w-full h-full flex items-center border-0 bg-transparent hover:bg-transparent focus:bg-transparent pl-3 pr-[16px] group"
1723
1758
  onmouseenter={() => {
1724
1759
  // Preload fonts when hovering over the button
1725
1760
  // This reduces the delay when actually clicking to open
@@ -1896,7 +1931,7 @@
1896
1931
  <div
1897
1932
  role="button"
1898
1933
  tabindex="-1"
1899
- class="ml-auto transition-opacity {value?.family === font.family ? 'opacity-0 pointer-events-none' : 'opacity-0 group-hover:opacity-100'}"
1934
+ class="ml-auto transition-opacity {resolvedFont?.family === font.family ? 'opacity-0 pointer-events-none' : 'opacity-0 group-hover:opacity-100'}"
1900
1935
  onclick={(e) => {
1901
1936
  e.stopPropagation();
1902
1937
  e.preventDefault();
@@ -1939,7 +1974,7 @@
1939
1974
  }
1940
1975
  }}
1941
1976
  >
1942
- <Popover.Trigger tabindex="-1" class="w-full h-full flex items-center border-0 bg-transparent hover:bg-transparent focus:bg-transparent pl-3 pr-[16px] group">
1977
+ <Popover.Trigger tabindex={-1} class="w-full h-full flex items-center border-0 bg-transparent hover:bg-transparent focus:bg-transparent pl-3 pr-[16px] group">
1943
1978
  <span class="truncate flex-1 text-left subtext text-grey7">
1944
1979
  {displayWeight || 'Regular'}
1945
1980
  </span>
@@ -1,3 +1,26 @@
1
+ /** Declared props contract — export lets below are annotated from it so the
2
+ * interface cannot drift from what the component actually reads. */
3
+ export interface FontInputControllerProps {
4
+ label?: string;
5
+ style?: string;
6
+ value?: {
7
+ family: string;
8
+ weight: string;
9
+ category: string;
10
+ } | string | null;
11
+ onChange?: (newValue: {
12
+ family: string;
13
+ weight: string;
14
+ category: string;
15
+ }) => void;
16
+ description?: string;
17
+ controllerId: string;
18
+ openDropdowns: Writable<Set<string>>;
19
+ toggleDropdown: (id: string) => void;
20
+ hideRecentFromList?: boolean;
21
+ hideTrashIcon?: boolean;
22
+ }
23
+ import type { Writable } from 'svelte/store';
1
24
  interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
2
25
  new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
3
26
  $$bindings?: Bindings;
@@ -23,25 +46,17 @@ declare const FontInputController: $$__sveltets_2_IsomorphicComponent<{
23
46
  * @prop {any} openDropdowns - Store tracking open dropdown states
24
47
  * @prop {Function} toggleDropdown - Function to toggle dropdown state
25
48
  * @prop {Function} onFocus - Optional focus handler
26
- */ label?: string;
49
+ */ label?: FontInputControllerProps["label"];
27
50
  class?: string;
28
- style?: string;
29
- value?: {
30
- family: string;
31
- weight: string;
32
- category: string;
33
- } | string | null;
34
- onChange?: ((newValue: {
35
- family: string;
36
- weight: string;
37
- category: string;
38
- }) => void) | undefined;
39
- description?: string | undefined;
40
- controllerId: string;
41
- openDropdowns: any;
42
- toggleDropdown: (id: string) => void;
43
- hideRecentFromList?: boolean;
44
- hideTrashIcon?: boolean;
51
+ style?: FontInputControllerProps["style"];
52
+ value?: FontInputControllerProps["value"];
53
+ onChange?: FontInputControllerProps["onChange"];
54
+ description?: FontInputControllerProps["description"];
55
+ controllerId: FontInputControllerProps["controllerId"];
56
+ openDropdowns: FontInputControllerProps["openDropdowns"];
57
+ toggleDropdown: FontInputControllerProps["toggleDropdown"];
58
+ hideRecentFromList?: FontInputControllerProps["hideRecentFromList"];
59
+ hideTrashIcon?: FontInputControllerProps["hideTrashIcon"];
45
60
  }, {
46
61
  [evt: string]: CustomEvent<any>;
47
62
  }, {}, {}, string>;