@widgetic/editor 4.0.11 → 4.1.0

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 (58) hide show
  1. package/README.md +124 -0
  2. package/dist/components/WidgetPreview.svelte +58 -59
  3. package/dist/components/color-select/ColorSelect.svelte +4 -4
  4. package/dist/components/editors/CompositionEditorApp.svelte +69 -15
  5. package/dist/components/editors/CompositionEditorApp.svelte.d.ts +20 -0
  6. package/dist/components/editors/EmbedEditor.svelte +33 -22
  7. package/dist/components/editors/EmbedEditor.svelte.d.ts +1 -1
  8. package/dist/components/editors/PropsEditor.svelte +74 -58
  9. package/dist/components/editors/PropsEditor.svelte.d.ts +3 -3
  10. package/dist/components/ic/AngleInputController.svelte +1 -1
  11. package/dist/components/ic/BrowserInputController.svelte +37 -29
  12. package/dist/components/ic/ColorPickerInputController.svelte +31 -15
  13. package/dist/components/ic/DateFieldInputController.svelte +27 -11
  14. package/dist/components/ic/DatePickerInputController.svelte +27 -17
  15. package/dist/components/ic/DropdownInputController.svelte +10 -5
  16. package/dist/components/ic/DropdownInputController.svelte.d.ts +1 -1
  17. package/dist/components/ic/FixedPositionInputController.svelte +12 -6
  18. package/dist/components/ic/FontInputController.svelte +32 -27
  19. package/dist/components/ic/InputControllerHeader.svelte +5 -1
  20. package/dist/components/ic/NumberControls.svelte +4 -4
  21. package/dist/components/ic/NumberInputController.svelte +2 -2
  22. package/dist/components/ic/PositionInputController.svelte +9 -4
  23. package/dist/components/ic/RangeCalendarInputController.svelte +26 -16
  24. package/dist/components/ic/RoundedCornersInputController.svelte +22 -17
  25. package/dist/components/ic/SliderInputController.svelte +7 -2
  26. package/dist/components/ic/SwitchInputController.svelte +12 -3
  27. package/dist/components/ic/TagsInputController.svelte +19 -4
  28. package/dist/components/ic/TextAreaInputController.svelte +59 -44
  29. package/dist/components/ic/TextAreaPreviewInputController.svelte +8 -3
  30. package/dist/components/ic/TextInputController.svelte +17 -1
  31. package/dist/components/ic/TimeInputController.svelte +2 -1
  32. package/dist/components/ic/VectorInputController.svelte +21 -16
  33. package/dist/components/ic/shared/ItemGrid.svelte +7 -3
  34. package/dist/components/ic/shared/RecentItemsSection.svelte +16 -11
  35. package/dist/components/ic/shared/RecentItemsSection.svelte.d.ts +1 -1
  36. package/dist/composition/compositionEditorController.d.ts +11 -2
  37. package/dist/composition/compositionEditorController.js +33 -21
  38. package/dist/composition/compositionHelpers.d.ts +3 -1
  39. package/dist/composition/compositionHelpers.js +4 -2
  40. package/dist/i18n/index.d.ts +4 -0
  41. package/dist/i18n/index.js +4 -0
  42. package/dist/i18n/labels.d.ts +15 -0
  43. package/dist/i18n/labels.js +57 -0
  44. package/dist/i18n/language.d.ts +228 -0
  45. package/dist/i18n/language.js +34 -0
  46. package/dist/i18n/languageKit.d.ts +54 -0
  47. package/dist/i18n/languageKit.js +102 -0
  48. package/dist/i18n/messages.d.ts +241 -0
  49. package/dist/i18n/messages.js +253 -0
  50. package/dist/i18n/translate.d.ts +6 -0
  51. package/dist/i18n/translate.js +8 -0
  52. package/dist/index.d.ts +1 -0
  53. package/dist/index.js +4 -0
  54. package/dist/utils/dockPlacement.d.ts +12 -0
  55. package/dist/utils/dockPlacement.js +13 -0
  56. package/dist/utils/fieldDirection.d.ts +13 -0
  57. package/dist/utils/fieldDirection.js +25 -0
  58. package/package.json +2 -2
@@ -13,9 +13,14 @@
13
13
  // Import Check icon from design system
14
14
  import { Check } from '@widgetic/design-system/icons';
15
15
  import icTrash from '../../../assets/icons/ic-browser/trash.svg?url';
16
-
16
+ import { useEditorLanguage } from '../../../i18n/language';
17
+
18
+ // The words of the editor in the language of the page.
19
+ const { t } = useEditorLanguage();
20
+
17
21
  export let recentItems: any[] = [];
18
- export let title = "Recently used";
22
+ /** The title of the section. Without one, the editor's own word, in the language of the page. */
23
+ export let title: string | undefined = undefined;
19
24
  export let onItemSelect: (item: any) => void;
20
25
  export let onItemDelete: (item: any, event: Event) => void;
21
26
  export let isItemSelected: (item: any) => boolean;
@@ -36,7 +41,7 @@
36
41
 
37
42
  {#if recentItems.length > 0}
38
43
  <div class="px-4 pt-4 pb-4 widgetic-colors">
39
- <h5 class="subtext text-grey7">{title}</h5>
44
+ <h5 class="subtext text-grey7">{title ?? $t('editor.list.recentlyUsed')}</h5>
40
45
 
41
46
  {#if displayMode === 'list'}
42
47
  <div class="grid grid-cols-1">
@@ -59,7 +64,7 @@
59
64
  data-item={getItemKey(item)}
60
65
  >
61
66
  <div class="flex items-center flex-1 min-w-0 group">
62
- <Check class="mr-2 h-6 w-6 flex-shrink-0 {selected ? 'text-white' : 'text-sage-green opacity-0'}"/>
67
+ <Check class="me-2 h-6 w-6 flex-shrink-0 {selected ? 'text-white' : 'text-sage-green opacity-0'}"/>
63
68
  <div class="flex-1 overflow-hidden">
64
69
  {#if typeof renderedItem === 'string'}
65
70
  <span class="text-[24px]">{renderedItem}</span>
@@ -78,7 +83,7 @@
78
83
  onItemDelete(item, e);
79
84
  }}
80
85
  >
81
- <img src={icTrash} alt="Delete" class="w-4 h-4" />
86
+ <img src={icTrash} alt={$t('editor.list.deleteItem')} class="w-4 h-4" />
82
87
  </button>
83
88
  {/if}
84
89
  </div>
@@ -97,7 +102,7 @@
97
102
  data-item={getItemKey(item)}
98
103
  >
99
104
  <div class="flex items-center flex-1 min-w-0 group">
100
- <Check class="mr-2 h-6 w-6 flex-shrink-0 {selected ? 'text-white' : 'text-sage-green opacity-0'}"/>
105
+ <Check class="me-2 h-6 w-6 flex-shrink-0 {selected ? 'text-white' : 'text-sage-green opacity-0'}"/>
101
106
  <div class="flex-1 overflow-hidden">
102
107
  {#if typeof renderedItem === 'string'}
103
108
  <span class="text-[24px]">{renderedItem}</span>
@@ -116,7 +121,7 @@
116
121
  onItemDelete(item, e);
117
122
  }}
118
123
  >
119
- <img src={icTrash} alt="Delete" class="w-4 h-4" />
124
+ <img src={icTrash} alt={$t('editor.list.deleteItem')} class="w-4 h-4" />
120
125
  </button>
121
126
  {/if}
122
127
  </div>
@@ -157,14 +162,14 @@
157
162
  {#if isCustomItem(item) && !hideTrashIcon}
158
163
  <button
159
164
  type="button"
160
- class="absolute top-1 right-1 p-1 rounded-full hover:bg-red-100 hover:text-red-500 transition-colors bg-white"
165
+ class="absolute top-1 end-1 p-1 rounded-full hover:bg-red-100 hover:text-red-500 transition-colors bg-white"
161
166
  tabindex="-1"
162
167
  onclick={(e) => {
163
168
  e.stopPropagation();
164
169
  onItemDelete(item, e);
165
170
  }}
166
171
  >
167
- <img src={icTrash} alt="Delete" class="w-3 h-3" />
172
+ <img src={icTrash} alt={$t('editor.list.deleteItem')} class="w-3 h-3" />
168
173
  </button>
169
174
  {/if}
170
175
  </div>
@@ -195,14 +200,14 @@
195
200
  {#if isCustomItem(item) && !hideTrashIcon}
196
201
  <button
197
202
  type="button"
198
- class="absolute top-1 right-1 p-1 rounded-full hover:bg-red-100 hover:text-red-500 transition-colors bg-white"
203
+ class="absolute top-1 end-1 p-1 rounded-full hover:bg-red-100 hover:text-red-500 transition-colors bg-white"
199
204
  tabindex="-1"
200
205
  onclick={(e) => {
201
206
  e.stopPropagation();
202
207
  onItemDelete(item, e);
203
208
  }}
204
209
  >
205
- <img src={icTrash} alt="Delete" class="w-3 h-3" />
210
+ <img src={icTrash} alt={$t('editor.list.deleteItem')} class="w-3 h-3" />
206
211
  </button>
207
212
  {/if}
208
213
  </div>
@@ -13,7 +13,7 @@ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> =
13
13
  }
14
14
  declare const RecentItemsSection: $$__sveltets_2_IsomorphicComponent<{
15
15
  recentItems?: any[];
16
- title?: string;
16
+ /** The title of the section. Without one, the editor's own word, in the language of the page. */ title?: string | undefined;
17
17
  onItemSelect: (item: any) => void;
18
18
  onItemDelete: (item: any, event: Event) => void;
19
19
  isItemSelected: (item: any) => boolean;
@@ -25,6 +25,8 @@
25
25
  * the size of the widget embedded on a site).
26
26
  * - After `dispose()` nothing more happens: no request goes out, and answers still on their way are ignored.
27
27
  */
28
+ import type { Translate } from '@widgetic/design-system/i18n';
29
+ import type { EditorMessageKey } from '../i18n/messages.js';
28
30
  import type { CompositionApi } from './compositionApi.js';
29
31
  import { type JsonRecord } from './compositionHelpers.js';
30
32
  /** Time to wait after the last edit before saving by itself. */
@@ -140,16 +142,23 @@ export interface CompositionEditorOptions {
140
142
  onPreviewMessage?: (message: PreviewMessage) => void;
141
143
  /** Writes the editor's own notes (a failure worth knowing about). Default: the console. */
142
144
  logger?: Pick<Console, 'warn' | 'error'>;
145
+ /**
146
+ * Says the editor's own sentences (why there is no preview, why there is nothing to edit) in the page's language.
147
+ * A sentence is made when what it tells happens, and stays in the language it was made in until it is replaced.
148
+ * Default: English.
149
+ */
150
+ translate?: Translate<EditorMessageKey>;
143
151
  }
144
152
  /** What went wrong, from whatever was thrown. */
145
153
  export declare function describeFailure(error: unknown): EditorFailure;
146
- /** A failure in words for the person using the editor. */
147
- export declare function failureMessage(failure: EditorFailure, doing: 'load' | 'save'): string;
154
+ /** A failure in words for the person using the editor, in the language of `translate` (English when it is left out). */
155
+ export declare function failureMessage(failure: EditorFailure, doing: 'load' | 'save', translate?: Translate<EditorMessageKey>): string;
148
156
  export declare class CompositionEditorController {
149
157
  private readonly options;
150
158
  private readonly timers;
151
159
  private readonly now;
152
160
  private readonly logger;
161
+ private readonly translate;
153
162
  private readonly autosaveDelayMs;
154
163
  private readonly autosaveRetryDelaysMs;
155
164
  private readonly abortController;
@@ -25,6 +25,7 @@
25
25
  * the size of the widget embedded on a site).
26
26
  * - After `dispose()` nothing more happens: no request goes out, and answers still on their way are ignored.
27
27
  */
28
+ import { translateEnglish } from '../i18n/translate.js';
28
29
  import { buildPropsEditorContentSchema, compositionWidgetId, contentItemsToEditorValueMap, ensureSubtitleFontInDesignSchema, extractContentItemsFromCompositionRaw, extractContentValuesFromCompositionRaw, flattenContentItemsForPreview, flattenDesignValuesForPreview, getCompositionEmbedSettings, mergeContentItemsWithSchema, mergeMissingContentValues, normalizeContentSchemaFromApiResponse, normalizeDesignSchemaFromApiResponse, parseEmbedDimension, seedMissingFontFaces } from './compositionHelpers.js';
29
30
  /** Time to wait after the last edit before saving by itself. */
30
31
  export const DEFAULT_AUTOSAVE_DELAY_MS = 2500;
@@ -50,6 +51,8 @@ function isCompositionApiError(error) {
50
51
  typeof candidate?.code === 'string' &&
51
52
  typeof candidate?.status === 'number');
52
53
  }
54
+ /** What a failure says when whatever was thrown said nothing. It is for the page's code, not for the person using the editor (see `failureMessage`). */
55
+ const GENERIC_FAILURE_MESSAGE = 'Something went wrong.';
53
56
  /** What went wrong, from whatever was thrown. */
54
57
  export function describeFailure(error) {
55
58
  if (isCompositionApiError(error)) {
@@ -63,43 +66,48 @@ export function describeFailure(error) {
63
66
  };
64
67
  }
65
68
  return {
66
- message: error instanceof Error && error.message ? error.message : 'Something went wrong.',
69
+ message: error instanceof Error && error.message ? error.message : GENERIC_FAILURE_MESSAGE,
67
70
  code: 'UNKNOWN',
68
71
  status: 0,
69
72
  retryable: false,
70
73
  sessionEnded: false
71
74
  };
72
75
  }
73
- /** A failure in words for the person using the editor. */
74
- export function failureMessage(failure, doing) {
76
+ /** A failure in words for the person using the editor, in the language of `translate` (English when it is left out). */
77
+ export function failureMessage(failure, doing, translate = translateEnglish) {
75
78
  if (failure.code === 'WIDGET_NOT_PUBLISHED')
76
- return 'Publish the widget before editing a composition.';
79
+ return translate('editor.failure.widgetNotPublished');
80
+ if (failure.code === 'COMPOSITION_HAS_NO_WIDGET')
81
+ return translate('editor.failure.noWidget');
77
82
  if (failure.sessionEnded) {
78
83
  return doing === 'save'
79
- ? 'Your session has ended, so your changes could not be saved. Reload the page to continue.'
80
- : 'Your session has ended. Reload the page to continue.';
84
+ ? translate('editor.failure.sessionEndedWhileSaving')
85
+ : translate('editor.failure.sessionEnded');
81
86
  }
82
87
  if (failure.status === 404)
83
- return 'This composition could not be found.';
88
+ return translate('editor.failure.compositionNotFound');
84
89
  if (failure.status === 403)
85
- return 'You do not have access to this composition.';
90
+ return translate('editor.failure.noAccess');
86
91
  if (failure.retryable) {
87
92
  return doing === 'save'
88
- ? 'Your changes could not be saved. Check the connection and try again.'
89
- : 'The editor could not be loaded. Check the connection and try again.';
90
- }
91
- return (failure.message ||
92
- (doing === 'save' ? 'Your changes could not be saved.' : 'The editor could not be loaded.'));
93
+ ? translate('editor.failure.saveNeedsConnection')
94
+ : translate('editor.failure.loadNeedsConnection');
95
+ }
96
+ // What the API said is shown as it came. What the editor said for it ("Something went wrong.") is not: that sentence
97
+ // is English, so the person is told in their own language that the editor could not do what it was asked.
98
+ const apiMessage = failure.message === GENERIC_FAILURE_MESSAGE ? '' : failure.message;
99
+ return (apiMessage ||
100
+ (doing === 'save' ? translate('editor.failure.saveFailed') : translate('editor.failure.loadFailed')));
93
101
  }
94
102
  /** A refusal that makes every other answer worthless: the session is over, or it may not see this composition. */
95
103
  function refusesAccess(failure) {
96
104
  return failure.sessionEnded || failure.status === 403;
97
105
  }
98
106
  /** Why there is no preview, in words for a person. */
99
- function previewFailureMessage(failure) {
107
+ function previewFailureMessage(failure, translate) {
100
108
  if (failure.status === 404)
101
- return 'The widget this composition is made with could not be found.';
102
- return failureMessage(failure, 'load');
109
+ return translate('editor.failure.widgetNotFound');
110
+ return failureMessage(failure, 'load', translate);
103
111
  }
104
112
  function isRecord(value) {
105
113
  return typeof value === 'object' && value !== null && !Array.isArray(value);
@@ -122,6 +130,7 @@ export class CompositionEditorController {
122
130
  timers;
123
131
  now;
124
132
  logger;
133
+ translate;
125
134
  autosaveDelayMs;
126
135
  autosaveRetryDelaysMs;
127
136
  abortController = new AbortController();
@@ -156,6 +165,7 @@ export class CompositionEditorController {
156
165
  };
157
166
  this.now = options.now ?? Date.now;
158
167
  this.logger = options.logger ?? console;
168
+ this.translate = options.translate ?? translateEnglish;
159
169
  this.autosaveDelayMs = options.autosaveDelayMs ?? DEFAULT_AUTOSAVE_DELAY_MS;
160
170
  this.autosaveRetryDelaysMs = options.autosaveRetryDelaysMs ?? DEFAULT_AUTOSAVE_RETRY_DELAYS_MS;
161
171
  this.state = {
@@ -295,7 +305,7 @@ export class CompositionEditorController {
295
305
  name: String(composition.name || 'Untitled Composition'),
296
306
  widgetId,
297
307
  preview,
298
- previewError: previewFailure ? previewFailureMessage(previewFailure) : null,
308
+ previewError: previewFailure ? previewFailureMessage(previewFailure, this.translate) : null,
299
309
  designSchema: schemas.designSchema,
300
310
  contentSchema: schemas.contentSchema,
301
311
  schemasLoading: false,
@@ -334,7 +344,7 @@ export class CompositionEditorController {
334
344
  // Either schema may be missing, but not both.
335
345
  const designSchema = designFailure
336
346
  ? (previous?.designSchema ?? null)
337
- : ensureSubtitleFontInDesignSchema(normalizeDesignSchemaFromApiResponse(valueOf(designResult)));
347
+ : ensureSubtitleFontInDesignSchema(normalizeDesignSchemaFromApiResponse(valueOf(designResult)), this.translate('editor.schema.subtitleFont'));
338
348
  const contentSchema = contentFailure
339
349
  ? (previous?.contentSchema ?? null)
340
350
  : normalizeContentSchemaFromApiResponse(valueOf(contentResult));
@@ -342,8 +352,8 @@ export class CompositionEditorController {
342
352
  let schemasError = null;
343
353
  if (!designSchema && !contentSchema) {
344
354
  schemasError = failure
345
- ? 'The editor settings could not be loaded. Try again.'
346
- : 'No editable settings found. Generate and publish the widget first.';
355
+ ? this.translate('editor.failure.settingsLoadFailed')
356
+ : this.translate('editor.failure.noSettings');
347
357
  }
348
358
  return { designSchema, contentSchema, schemasError, failure };
349
359
  }
@@ -355,7 +365,9 @@ export class CompositionEditorController {
355
365
  type: 'error',
356
366
  during: 'schemas',
357
367
  failure: schemas.failure ?? {
358
- message: schemas.schemasError,
368
+ // For the page's code (a log, a report), not for the person using the editor: it stays English, like what
369
+ // the API says, however the page set the language. The person is told `schemasError`.
370
+ message: translateEnglish('editor.failure.noSettings'),
359
371
  code: 'NO_EDITABLE_SETTINGS',
360
372
  status: 0,
361
373
  retryable: false,
@@ -31,8 +31,10 @@ export declare function normalizeDesignSchemaFromApiResponse(designResponse: unk
31
31
  * Gives a design schema that has a title font but no subtitle font a subtitle font beside the title's (a copy of
32
32
  * it), so widgets that read `subtitleFont` can be edited. A schema that already has one, or has no title font to
33
33
  * copy, is returned as it is.
34
+ *
35
+ * `description` is what the new font is called on the screen: the editor's own word, so the page's language can give it.
34
36
  */
35
- export declare function ensureSubtitleFontInDesignSchema(schema: unknown): unknown;
37
+ export declare function ensureSubtitleFontInDesignSchema(schema: unknown, description?: string): unknown;
36
38
  /** The content schema as the editor draws it, or `null` when there is none. */
37
39
  export declare function normalizeContentSchemaFromApiResponse(contentResponse: unknown): any;
38
40
  /**
@@ -66,8 +66,10 @@ export function normalizeDesignSchemaFromApiResponse(designResponse) {
66
66
  * Gives a design schema that has a title font but no subtitle font a subtitle font beside the title's (a copy of
67
67
  * it), so widgets that read `subtitleFont` can be edited. A schema that already has one, or has no title font to
68
68
  * copy, is returned as it is.
69
+ *
70
+ * `description` is what the new font is called on the screen: the editor's own word, so the page's language can give it.
69
71
  */
70
- export function ensureSubtitleFontInDesignSchema(schema) {
72
+ export function ensureSubtitleFontInDesignSchema(schema, description = 'Subtitle Font') {
71
73
  if (!schema)
72
74
  return schema;
73
75
  try {
@@ -96,7 +98,7 @@ export function ensureSubtitleFontInDesignSchema(schema) {
96
98
  ...structuredClone(titleProp),
97
99
  id: 'subtitleFont',
98
100
  name: 'subtitleFont',
99
- description: 'Subtitle Font'
101
+ description
100
102
  };
101
103
  const titleIndex = firstComponent.properties.findIndex((prop) => (prop?.name || prop?.id) ===
102
104
  (titleProp.name ||
@@ -0,0 +1,4 @@
1
+ export { EDITOR_MESSAGES, type EditorMessageKey } from './messages.js';
2
+ export { ALL_EDITOR_MESSAGES, EDITOR_CATALOGS, checkEditorMessages, provideEditorLanguage, useEditorLanguage, type EditorLanguage, type EditorLanguageHandle } from './language.js';
3
+ export { translateEnglish } from './translate.js';
4
+ export { categoryLabel, fixedPositionLabel, fontWeightLabel } from './labels.js';
@@ -0,0 +1,4 @@
1
+ export { EDITOR_MESSAGES } from './messages.js';
2
+ export { ALL_EDITOR_MESSAGES, EDITOR_CATALOGS, checkEditorMessages, provideEditorLanguage, useEditorLanguage } from './language.js';
3
+ export { translateEnglish } from './translate.js';
4
+ export { categoryLabel, fixedPositionLabel, fontWeightLabel } from './labels.js';
@@ -0,0 +1,15 @@
1
+ import type { Translate } from '@widgetic/design-system/i18n';
2
+ import type { EditorMessageKey } from './messages.js';
3
+ /**
4
+ * Some things the editor keeps by an English name (the tab "Sans Serif" that was last open, the weight "Bold Italic" that
5
+ * is saved with a font) and shows to a person by a name in their language. The name that is kept does not change with the
6
+ * language: these functions only turn it into what is shown, and show a name they do not know as it is.
7
+ */
8
+ type Translator = Translate<EditorMessageKey>;
9
+ /** The tab of a list of fonts or vectors, by the name the list keeps it under ("Sans Serif"). */
10
+ export declare function categoryLabel(category: string, t: Translator): string;
11
+ /** A weight of a font, by the name that is saved ("Bold", "Medium Italic", "Italic"). A name the editor does not know is shown as it is. */
12
+ export declare function fontWeightLabel(weight: string, t: Translator): string;
13
+ /** The name of one of the nine places on a screen, by the name the widget keeps it under ("top-left"). */
14
+ export declare function fixedPositionLabel(position: string, t: Translator): string;
15
+ export {};
@@ -0,0 +1,57 @@
1
+ /** `own[name]`, only when `name` is the table's own entry (a weight called "constructor" is not a method of the table). */
2
+ function ownEntry(table, name) {
3
+ return Object.prototype.hasOwnProperty.call(table, name) ? table[name] : undefined;
4
+ }
5
+ const CATEGORY_KEYS = {
6
+ All: 'editor.category.all',
7
+ Mine: 'editor.category.mine',
8
+ 'Sans Serif': 'editor.category.sansSerif',
9
+ Serif: 'editor.category.serif',
10
+ Script: 'editor.category.script',
11
+ Other: 'editor.category.other',
12
+ Icons: 'editor.category.icons',
13
+ Emojis: 'editor.category.emojis',
14
+ Clipart: 'editor.category.clipart'
15
+ };
16
+ /** The tab of a list of fonts or vectors, by the name the list keeps it under ("Sans Serif"). */
17
+ export function categoryLabel(category, t) {
18
+ const key = ownEntry(CATEGORY_KEYS, category);
19
+ return key ? t(key) : category;
20
+ }
21
+ const WEIGHT_KEYS = {
22
+ Thin: 'editor.fontWeight.thin',
23
+ ExtraLight: 'editor.fontWeight.extraLight',
24
+ Light: 'editor.fontWeight.light',
25
+ Regular: 'editor.fontWeight.regular',
26
+ Medium: 'editor.fontWeight.medium',
27
+ SemiBold: 'editor.fontWeight.semiBold',
28
+ Bold: 'editor.fontWeight.bold',
29
+ ExtraBold: 'editor.fontWeight.extraBold',
30
+ Black: 'editor.fontWeight.black'
31
+ };
32
+ /** A weight of a font, by the name that is saved ("Bold", "Medium Italic", "Italic"). A name the editor does not know is shown as it is. */
33
+ export function fontWeightLabel(weight, t) {
34
+ if (weight === 'Italic')
35
+ return t('editor.fontWeight.italic');
36
+ const italic = /^(\S+) Italic$/.exec(weight);
37
+ const baseKey = ownEntry(WEIGHT_KEYS, italic ? italic[1] : weight);
38
+ if (!baseKey)
39
+ return weight;
40
+ return italic ? t('editor.fontWeight.withItalic', { weight: t(baseKey) }) : t(baseKey);
41
+ }
42
+ const POSITION_KEYS = {
43
+ 'top-left': 'editor.fixedPosition.topLeft',
44
+ 'top-center': 'editor.fixedPosition.topCenter',
45
+ 'top-right': 'editor.fixedPosition.topRight',
46
+ 'center-left': 'editor.fixedPosition.centerLeft',
47
+ 'center-center': 'editor.fixedPosition.centerCenter',
48
+ 'center-right': 'editor.fixedPosition.centerRight',
49
+ 'bottom-left': 'editor.fixedPosition.bottomLeft',
50
+ 'bottom-center': 'editor.fixedPosition.bottomCenter',
51
+ 'bottom-right': 'editor.fixedPosition.bottomRight'
52
+ };
53
+ /** The name of one of the nine places on a screen, by the name the widget keeps it under ("top-left"). */
54
+ export function fixedPositionLabel(position, t) {
55
+ const key = ownEntry(POSITION_KEYS, position);
56
+ return key ? t(key) : position;
57
+ }
@@ -0,0 +1,228 @@
1
+ import { SHAD_EDITOR_MESSAGES } from '@widgetic/design-system/shad-editor';
2
+ export type { EditorCatalogs, EditorLanguage, EditorLanguageHandle } from './languageKit.js';
3
+ /**
4
+ * The language of an editor on a page. The editor has two packages inside it (the File Browser that picks a file, and
5
+ * the rich text editor of the text boxes), each with its own catalog; a page gives ONE flat `messages` object and the
6
+ * editor hands each package the keys that are its own. See `languageKit.ts` for how, and for what a test can swap.
7
+ */
8
+ /** The catalogs of the editor and of the packages inside it. A key belongs to one of them. */
9
+ export declare const EDITOR_CATALOGS: {
10
+ readonly editor: {
11
+ readonly 'editor.app.loading': "Loading editor…";
12
+ readonly 'editor.app.tryAgain': "Try again";
13
+ readonly 'editor.app.retry': "Retry";
14
+ readonly 'editor.failure.widgetNotPublished': "Publish the widget before editing a composition.";
15
+ readonly 'editor.failure.sessionEndedWhileSaving': "Your session has ended, so your changes could not be saved. Reload the page to continue.";
16
+ readonly 'editor.failure.sessionEnded': "Your session has ended. Reload the page to continue.";
17
+ readonly 'editor.failure.compositionNotFound': "This composition could not be found.";
18
+ readonly 'editor.failure.noAccess': "You do not have access to this composition.";
19
+ readonly 'editor.failure.noWidget': "This composition has no widget.";
20
+ readonly 'editor.failure.widgetNotFound': "The widget this composition is made with could not be found.";
21
+ readonly 'editor.failure.saveNeedsConnection': "Your changes could not be saved. Check the connection and try again.";
22
+ readonly 'editor.failure.loadNeedsConnection': "The editor could not be loaded. Check the connection and try again.";
23
+ readonly 'editor.failure.saveFailed': "Your changes could not be saved.";
24
+ readonly 'editor.failure.loadFailed': "The editor could not be loaded.";
25
+ readonly 'editor.failure.settingsLoadFailed': "The editor settings could not be loaded. Try again.";
26
+ readonly 'editor.failure.noSettings': "No editable settings found. Generate and publish the widget first.";
27
+ readonly 'editor.failure.errorCode': "Error code: {code}";
28
+ readonly 'editor.props.title': "Edit Properties";
29
+ readonly 'editor.props.designTab': "Design";
30
+ readonly 'editor.props.contentTab': "Content";
31
+ readonly 'editor.props.contentCard': "Content";
32
+ readonly 'editor.props.save': "Save";
33
+ readonly 'editor.props.saving': "Saving";
34
+ readonly 'editor.props.noConfiguration': "No schema configuration available";
35
+ readonly 'editor.props.noDesignSchema': "No design schema available";
36
+ readonly 'editor.props.noSchemaData': "No schema data available";
37
+ readonly 'editor.props.noComponents': "No components defined in schema";
38
+ readonly 'editor.props.noProperties': "No properties available";
39
+ readonly 'editor.props.addItem': "Add new";
40
+ readonly 'editor.props.deleteItem': "Delete item";
41
+ readonly 'editor.embed.title': "Edit Options";
42
+ readonly 'editor.embed.loading': "Loading...";
43
+ readonly 'editor.embed.noCode': "No embed code available";
44
+ readonly 'editor.embed.codeHeader': "Embed code";
45
+ readonly 'editor.embed.headerArea': "Embed code header area";
46
+ readonly 'editor.embed.readMore': "Read more about embedding";
47
+ readonly 'editor.embed.copy': "Copy to clipboard";
48
+ readonly 'editor.embed.copied': "Copied to clipboard";
49
+ readonly 'editor.embed.copiedHint': "Paste it anywhere on your site.";
50
+ readonly 'editor.embed.copiedDone': "Content copied successfully.";
51
+ readonly 'editor.embed.copyFailed': "Copy failed";
52
+ readonly 'editor.embed.copyFailedHint': "Please try manual selection";
53
+ readonly 'editor.preview.title': "Preview";
54
+ readonly 'editor.preview.dragHandle': "Drag preview";
55
+ readonly 'editor.preview.desktop': "Desktop preview";
56
+ readonly 'editor.preview.mobile': "Mobile preview";
57
+ readonly 'editor.preview.widthShort': "W";
58
+ readonly 'editor.preview.heightShort': "H";
59
+ readonly 'editor.preview.noUrl': "no URL";
60
+ readonly 'editor.preview.copyUrl': "Copy URL";
61
+ readonly 'editor.preview.refresh': "Refresh preview";
62
+ readonly 'editor.preview.fitToPanel': "Fit preview to panel";
63
+ readonly 'editor.preview.mobileViewport': "Mobile viewport";
64
+ readonly 'editor.preview.desktopViewport': "Desktop viewport (full window)";
65
+ readonly 'editor.preview.openInNewTab': "Open in new tab";
66
+ readonly 'editor.preview.newTab': "↗ New tab";
67
+ readonly 'editor.preview.selectWidget': "Select a widget to preview";
68
+ readonly 'editor.preview.widgetName': "Widget";
69
+ readonly 'editor.preview.notPublished': "Not published yet";
70
+ readonly 'editor.preview.publishToPreview': "Publish the widget in Widget Creator to preview it here.";
71
+ readonly 'editor.preview.frameTitle': "Widget preview";
72
+ readonly 'editor.preview.frameTitleNamed': "Widget preview – {name}";
73
+ readonly 'editor.preview.unavailable': "Preview Unavailable";
74
+ readonly 'editor.preview.loadFailedPreview': "Failed to load widget preview.";
75
+ readonly 'editor.preview.retry': "Retry";
76
+ readonly 'editor.preview.retryBuild': "Retry Build";
77
+ readonly 'editor.preview.retryPreview': "Retry Preview";
78
+ readonly 'editor.preview.fixErrors': "Fix Errors";
79
+ readonly 'editor.preview.viewErrors': "View Errors";
80
+ readonly 'editor.preview.runtimeError': "Widget runtime error";
81
+ readonly 'editor.preview.compilationErrors': "Code Has Compilation Errors";
82
+ readonly 'editor.preview.compilationErrorsDetail': "The generated code has syntax or compilation errors (HTTP {status}).";
83
+ readonly 'editor.preview.noCodeYet': "No Code Generated Yet";
84
+ readonly 'editor.preview.noPreview': "No Preview Available";
85
+ readonly 'editor.preview.building': "Building Preview...";
86
+ readonly 'editor.preview.loadingWidget': "Loading widget…";
87
+ readonly 'editor.preview.loadingPreview': "Loading Preview…";
88
+ readonly 'editor.preview.checkingWidget': "Checking widget on Worker…";
89
+ readonly 'editor.preview.applyingSettings': "Applying composition settings…";
90
+ readonly 'editor.preview.connecting': "Connecting to the widget preview…";
91
+ readonly 'editor.preview.generatingCode': "Generating code…";
92
+ readonly 'editor.list.recentlyUsed': "Recently used";
93
+ readonly 'editor.list.more': "More";
94
+ readonly 'editor.list.searchResults': "Search results";
95
+ readonly 'editor.list.loadingMore': "Loading more items...";
96
+ readonly 'editor.list.deleteItem': "Delete";
97
+ readonly 'editor.category.all': "All";
98
+ readonly 'editor.category.mine': "Mine";
99
+ readonly 'editor.category.sansSerif': "Sans Serif";
100
+ readonly 'editor.category.serif': "Serif";
101
+ readonly 'editor.category.script': "Script";
102
+ readonly 'editor.category.other': "Other";
103
+ readonly 'editor.category.icons': "Icons";
104
+ readonly 'editor.category.emojis': "Emojis";
105
+ readonly 'editor.category.clipart': "Clipart";
106
+ readonly 'editor.font.select': "Select font...";
107
+ readonly 'editor.font.title': "Fonts";
108
+ readonly 'editor.font.search': "Search fonts...";
109
+ readonly 'editor.font.list': "Font list";
110
+ readonly 'editor.font.loading': "Loading fonts";
111
+ readonly 'editor.font.noneFound': "No fonts found";
112
+ readonly 'editor.font.noneAvailable': "No fonts available";
113
+ readonly 'editor.font.remove': "Remove font";
114
+ readonly 'editor.font.weight': "Font Weight";
115
+ readonly 'editor.font.weightList': "Font weights";
116
+ readonly 'editor.fontWeight.withItalic': "{weight} Italic";
117
+ readonly 'editor.fontWeight.italic': "Italic";
118
+ readonly 'editor.fontWeight.thin': "Thin";
119
+ readonly 'editor.fontWeight.extraLight': "ExtraLight";
120
+ readonly 'editor.fontWeight.light': "Light";
121
+ readonly 'editor.fontWeight.regular': "Regular";
122
+ readonly 'editor.fontWeight.medium': "Medium";
123
+ readonly 'editor.fontWeight.semiBold': "SemiBold";
124
+ readonly 'editor.fontWeight.bold': "Bold";
125
+ readonly 'editor.fontWeight.extraBold': "ExtraBold";
126
+ readonly 'editor.fontWeight.black': "Black";
127
+ readonly 'editor.vector.select': "Select vector...";
128
+ readonly 'editor.vector.title': "Vectors";
129
+ readonly 'editor.vector.search': "Search vectors...";
130
+ readonly 'editor.vector.list': "Vector list";
131
+ readonly 'editor.vector.noneFound': "No vectors found";
132
+ readonly 'editor.vector.noneAvailable': "No vectors available";
133
+ readonly 'editor.file.useFile': "Use file";
134
+ readonly 'editor.file.useImage': "Use image";
135
+ readonly 'editor.file.useVideo': "Use video";
136
+ readonly 'editor.file.useAudio': "Use audio";
137
+ readonly 'editor.file.useDocument': "Use document";
138
+ readonly 'editor.file.addFile': "Add file...";
139
+ readonly 'editor.file.addImage': "Add image...";
140
+ readonly 'editor.file.addVideo': "Add video...";
141
+ readonly 'editor.file.addAudio': "Add audio...";
142
+ readonly 'editor.file.addDocument': "Add docs...";
143
+ readonly 'editor.file.play': "Play";
144
+ readonly 'editor.file.pause': "Pause";
145
+ readonly 'editor.file.notFound': "File not found";
146
+ readonly 'editor.file.emptyFolder': "Empty folder";
147
+ readonly 'editor.file.clear': "Clear file";
148
+ readonly 'editor.file.dialogTitle': "Select file";
149
+ readonly 'editor.file.closeDialog': "Close file browser";
150
+ readonly 'editor.color.noRecent': "No recent colors";
151
+ readonly 'editor.color.picker': "Color picker";
152
+ readonly 'editor.date.pick': "Pick a date";
153
+ readonly 'editor.date.pickRange': "Pick a date range";
154
+ readonly 'editor.date.invalid': "Invalid date";
155
+ readonly 'editor.date.selectMonth': "Select month";
156
+ readonly 'editor.date.selectYear': "Select year";
157
+ readonly 'editor.date.calendarLabel': "Date";
158
+ readonly 'editor.date.rangeCalendarLabel': "Date range";
159
+ readonly 'editor.date.previousMonth': "Previous month";
160
+ readonly 'editor.date.nextMonth': "Next month";
161
+ readonly 'editor.dateField.dayHint': "DD";
162
+ readonly 'editor.dateField.monthHint': "MM";
163
+ readonly 'editor.dateField.yearHint': "YYYY";
164
+ readonly 'editor.dateField.dayLabel': "Day input";
165
+ readonly 'editor.dateField.monthLabel': "Month input";
166
+ readonly 'editor.dateField.yearLabel': "Year input";
167
+ readonly 'editor.dropdown.select': "Select an option";
168
+ readonly 'editor.switch.off': "Off";
169
+ readonly 'editor.switch.on': "On";
170
+ readonly 'editor.tags.add': "Add tag...";
171
+ readonly 'editor.position.x': "X:";
172
+ readonly 'editor.position.y': "Y:";
173
+ readonly 'editor.fixedPosition.set': "Set position to {position}";
174
+ readonly 'editor.fixedPosition.topLeft': "top-left";
175
+ readonly 'editor.fixedPosition.topCenter': "top-center";
176
+ readonly 'editor.fixedPosition.topRight': "top-right";
177
+ readonly 'editor.fixedPosition.centerLeft': "center-left";
178
+ readonly 'editor.fixedPosition.centerCenter': "center-center";
179
+ readonly 'editor.fixedPosition.centerRight': "center-right";
180
+ readonly 'editor.fixedPosition.bottomLeft': "bottom-left";
181
+ readonly 'editor.fixedPosition.bottomCenter': "bottom-center";
182
+ readonly 'editor.fixedPosition.bottomRight': "bottom-right";
183
+ readonly 'editor.corners.group': "Corner radius";
184
+ readonly 'editor.corners.topLeft': "Top left corner radius";
185
+ readonly 'editor.corners.topRight': "Top right corner radius";
186
+ readonly 'editor.corners.bottomLeft': "Bottom left corner radius";
187
+ readonly 'editor.corners.bottomRight': "Bottom right corner radius";
188
+ readonly 'editor.corners.lock': "Lock corner radius values";
189
+ readonly 'editor.corners.unlock': "Unlock corner radius values";
190
+ readonly 'editor.textArea.toolbar': "Text formatting toolbar";
191
+ readonly 'editor.textArea.toggleBold': "Toggle bold";
192
+ readonly 'editor.textArea.toggleItalic': "Toggle italic";
193
+ readonly 'editor.textArea.toggleUnderline': "Toggle underline";
194
+ readonly 'editor.textArea.toggleLink': "Toggle link";
195
+ readonly 'editor.textArea.text': "Text";
196
+ readonly 'editor.textArea.paragraph': "Paragraph";
197
+ readonly 'editor.textArea.heading1': "H1";
198
+ readonly 'editor.textArea.heading2': "H2";
199
+ readonly 'editor.textArea.heading3': "H3";
200
+ readonly 'editor.textArea.bulletList': "Bullet List";
201
+ readonly 'editor.textArea.numberedList': "Numbered List";
202
+ readonly 'editor.textArea.checkList': "Check List";
203
+ readonly 'editor.textArea.textStyles': "Text styles";
204
+ readonly 'editor.textArea.listStyles': "List styles";
205
+ readonly 'editor.textArea.enterUrl': "Enter URL";
206
+ readonly 'editor.schema.subtitleFont': "Subtitle Font";
207
+ };
208
+ readonly fileBrowser: any;
209
+ readonly shadEditor: any;
210
+ };
211
+ /** Every message of the editor and of the packages inside it, as one catalog: what a page's `messages` may have a key of. */
212
+ export declare const ALL_EDITOR_MESSAGES: Readonly<Record<string, string>>;
213
+ /**
214
+ * Checks a page's `messages` against all the editor's catalogs without showing anything: a key that does not exist (with
215
+ * the nearest real one), a value that is not text, a template that does not parse, or one that asks for a value the message
216
+ * is never given. An empty list means every message will be used. For a test or a build step of the page.
217
+ */
218
+ export declare const checkEditorMessages: (messages: SHAD_EDITOR_MESSAGES) => SHAD_EDITOR_MESSAGES[];
219
+ /**
220
+ * Called by the root component of an editor while it is created, so everything inside it speaks the page's language.
221
+ * The context belongs to one root component, so two editors on a page can speak two languages.
222
+ */
223
+ export declare const provideEditorLanguage: (initial: SHAD_EDITOR_MESSAGES) => import("./languageKit.js").EditorLanguageHandle;
224
+ /**
225
+ * Called by a part of the editor while it is created. Gives its words as stores, so a part that is already on the screen
226
+ * changes when the page sets the language again. Outside an editor (a control used on its own) it speaks English.
227
+ */
228
+ export declare const useEditorLanguage: () => import("./languageKit.js").EditorLanguage;