@widgetic/editor 4.0.11 → 4.1.2
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.
- package/README.md +124 -0
- package/dist/components/PreviewChromeControls.svelte +84 -0
- package/dist/components/PreviewChromeControls.svelte.d.ts +35 -0
- package/dist/components/WidgetPreview.svelte +90 -129
- package/dist/components/WidgetPreview.svelte.d.ts +1 -0
- package/dist/components/color-select/ColorSelect.svelte +4 -4
- package/dist/components/editors/CompositionEditorApp.svelte +69 -15
- package/dist/components/editors/CompositionEditorApp.svelte.d.ts +20 -0
- package/dist/components/editors/EmbedEditor.svelte +33 -22
- package/dist/components/editors/EmbedEditor.svelte.d.ts +1 -1
- package/dist/components/editors/PropsEditor.svelte +74 -58
- package/dist/components/editors/PropsEditor.svelte.d.ts +3 -3
- package/dist/components/ic/AngleInputController.svelte +1 -1
- package/dist/components/ic/BrowserInputController.svelte +37 -29
- package/dist/components/ic/ColorPickerInputController.svelte +31 -15
- package/dist/components/ic/DateFieldInputController.svelte +27 -11
- package/dist/components/ic/DatePickerInputController.svelte +27 -17
- package/dist/components/ic/DropdownInputController.svelte +10 -5
- package/dist/components/ic/DropdownInputController.svelte.d.ts +1 -1
- package/dist/components/ic/FixedPositionInputController.svelte +12 -6
- package/dist/components/ic/FontInputController.svelte +32 -27
- package/dist/components/ic/InputControllerHeader.svelte +5 -1
- package/dist/components/ic/NumberControls.svelte +4 -4
- package/dist/components/ic/NumberInputController.svelte +2 -2
- package/dist/components/ic/PositionInputController.svelte +9 -4
- package/dist/components/ic/RangeCalendarInputController.svelte +26 -16
- package/dist/components/ic/RoundedCornersInputController.svelte +22 -17
- package/dist/components/ic/SliderInputController.svelte +7 -2
- package/dist/components/ic/SwitchInputController.svelte +12 -3
- package/dist/components/ic/TagsInputController.svelte +19 -4
- package/dist/components/ic/TextAreaInputController.svelte +59 -44
- package/dist/components/ic/TextAreaPreviewInputController.svelte +8 -3
- package/dist/components/ic/TextInputController.svelte +17 -1
- package/dist/components/ic/TimeInputController.svelte +2 -1
- package/dist/components/ic/VectorInputController.svelte +21 -16
- package/dist/components/ic/shared/ItemGrid.svelte +7 -3
- package/dist/components/ic/shared/RecentItemsSection.svelte +16 -11
- package/dist/components/ic/shared/RecentItemsSection.svelte.d.ts +1 -1
- package/dist/composition/compositionEditorController.d.ts +11 -2
- package/dist/composition/compositionEditorController.js +33 -21
- package/dist/composition/compositionHelpers.d.ts +3 -1
- package/dist/composition/compositionHelpers.js +4 -2
- package/dist/i18n/index.d.ts +4 -0
- package/dist/i18n/index.js +4 -0
- package/dist/i18n/labels.d.ts +15 -0
- package/dist/i18n/labels.js +57 -0
- package/dist/i18n/language.d.ts +228 -0
- package/dist/i18n/language.js +34 -0
- package/dist/i18n/languageKit.d.ts +54 -0
- package/dist/i18n/languageKit.js +102 -0
- package/dist/i18n/messages.d.ts +241 -0
- package/dist/i18n/messages.js +253 -0
- package/dist/i18n/translate.d.ts +6 -0
- package/dist/i18n/translate.js +8 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +5 -0
- package/dist/utils/dockPlacement.d.ts +12 -0
- package/dist/utils/dockPlacement.js +13 -0
- package/dist/utils/fieldDirection.d.ts +13 -0
- package/dist/utils/fieldDirection.js +25 -0
- package/package.json +2 -2
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
import { onMount, onDestroy, createEventDispatcher, tick } from 'svelte';
|
|
3
3
|
import { GenerateLoader } from '@widgetic/design-system/components';
|
|
4
4
|
import { lockPointerStyle } from '../utils/shadowDom';
|
|
5
|
+
import { useEditorLanguage } from '../i18n/language';
|
|
6
|
+
import PreviewChromeControls from './PreviewChromeControls.svelte';
|
|
7
|
+
|
|
8
|
+
// The words of the editor in the language of the page: the editor above this one chose it (see `provideEditorLanguage`).
|
|
9
|
+
const { t } = useEditorLanguage();
|
|
5
10
|
|
|
6
11
|
const dispatch = createEventDispatcher<{
|
|
7
12
|
load: { src: string | null };
|
|
@@ -88,6 +93,7 @@
|
|
|
88
93
|
*/
|
|
89
94
|
export let resizeMode: 'concentric' | 'corner' = 'concentric';
|
|
90
95
|
/** Initial / reset placement inside the stage. */
|
|
96
|
+
// rtl-ok: 'right-half' names the half of the stage by its place on the screen; the composition editor docks the preview itself
|
|
91
97
|
export let defaultStageAlign: 'center' | 'right-half' = 'center';
|
|
92
98
|
/** Observe stage size and fill it (desktop modal) */
|
|
93
99
|
export let autoFitStage: boolean = false;
|
|
@@ -105,7 +111,6 @@
|
|
|
105
111
|
let internalIframeSrc: string | null = null;
|
|
106
112
|
let iframeLoaded = false;
|
|
107
113
|
let iframeError = false;
|
|
108
|
-
let errorMessage = '';
|
|
109
114
|
let isWidgetPublished = false;
|
|
110
115
|
let triedFallback = false;
|
|
111
116
|
let pendingWidget: any = null;
|
|
@@ -117,10 +122,8 @@
|
|
|
117
122
|
const MIN_WIDTH = 120;
|
|
118
123
|
const MIN_HEIGHT = 80;
|
|
119
124
|
const HANDLE_MARGIN = 6;
|
|
120
|
-
/** Inset
|
|
121
|
-
|
|
122
|
-
const RESIZE_PAD_TOP = 12;
|
|
123
|
-
const RESIZE_PAD_BOTTOM = 12;
|
|
125
|
+
/** Inset so resize handles stay inside bounds. 0 sits the frame on the stage edge. */
|
|
126
|
+
export let edgeInset = 12;
|
|
124
127
|
const PREVIEW_CHROME_HEADER_H = 36;
|
|
125
128
|
const PREVIEW_STROKE = '#3b82f6';
|
|
126
129
|
const PREVIEW_STROKE_ALT = '#f97316';
|
|
@@ -155,8 +158,8 @@
|
|
|
155
158
|
}
|
|
156
159
|
if (hasFixedBounds && boundsWidth != null && boundsHeight != null) {
|
|
157
160
|
return {
|
|
158
|
-
maxWidth: Math.max(MIN_WIDTH, boundsWidth -
|
|
159
|
-
maxHeight: Math.max(MIN_HEIGHT, boundsHeight -
|
|
161
|
+
maxWidth: Math.max(MIN_WIDTH, boundsWidth - edgeInset * 2),
|
|
162
|
+
maxHeight: Math.max(MIN_HEIGHT, boundsHeight - edgeInset - edgeInset - chromeH),
|
|
160
163
|
};
|
|
161
164
|
}
|
|
162
165
|
return { maxWidth: 720, maxHeight: 420 };
|
|
@@ -172,16 +175,17 @@
|
|
|
172
175
|
shellWidth: number,
|
|
173
176
|
shellHeight: number
|
|
174
177
|
): { left: number; top: number } {
|
|
175
|
-
const maxLeft = Math.max(
|
|
176
|
-
const maxTop = Math.max(
|
|
178
|
+
const maxLeft = Math.max(edgeInset, stageWidth - shellWidth - edgeInset);
|
|
179
|
+
const maxTop = Math.max(edgeInset, stageHeight - shellHeight - edgeInset);
|
|
180
|
+
// rtl-ok: the half of the stage is named by its place on the screen, see the prop
|
|
177
181
|
if (defaultStageAlign === 'right-half') {
|
|
178
182
|
const rightHalfCenterX = stageWidth * 0.75;
|
|
179
|
-
const left = clampDimension(rightHalfCenterX - shellWidth / 2,
|
|
180
|
-
const top = clampDimension((stageHeight - shellHeight) / 2,
|
|
183
|
+
const left = clampDimension(rightHalfCenterX - shellWidth / 2, edgeInset, maxLeft);
|
|
184
|
+
const top = clampDimension((stageHeight - shellHeight) / 2, edgeInset, maxTop);
|
|
181
185
|
return { left, top };
|
|
182
186
|
}
|
|
183
|
-
const left = clampDimension((stageWidth - shellWidth) / 2,
|
|
184
|
-
const top = clampDimension((stageHeight - shellHeight) / 2,
|
|
187
|
+
const left = clampDimension((stageWidth - shellWidth) / 2, edgeInset, maxLeft);
|
|
188
|
+
const top = clampDimension((stageHeight - shellHeight) / 2, edgeInset, maxTop);
|
|
185
189
|
return { left, top };
|
|
186
190
|
}
|
|
187
191
|
|
|
@@ -266,10 +270,10 @@
|
|
|
266
270
|
|
|
267
271
|
function onPointerMove(e: PointerEvent) {
|
|
268
272
|
if (!stageEl) return;
|
|
269
|
-
const maxLeft = Math.max(
|
|
270
|
-
const maxTop = Math.max(
|
|
271
|
-
previewShellLeft = clampDimension(startLeft + (e.clientX - startX),
|
|
272
|
-
previewShellTop = clampDimension(startTop + (e.clientY - startY),
|
|
273
|
+
const maxLeft = Math.max(edgeInset, stageEl.clientWidth - shellWidth - edgeInset);
|
|
274
|
+
const maxTop = Math.max(edgeInset, stageEl.clientHeight - shellHeight - edgeInset);
|
|
275
|
+
previewShellLeft = clampDimension(startLeft + (e.clientX - startX), edgeInset, maxLeft);
|
|
276
|
+
previewShellTop = clampDimension(startTop + (e.clientY - startY), edgeInset, maxTop);
|
|
273
277
|
}
|
|
274
278
|
|
|
275
279
|
function endDrag() {
|
|
@@ -360,7 +364,7 @@
|
|
|
360
364
|
$: showResizeHandles = enableResize && (mode === 'controlled' ? isContentReady : iframeLoaded);
|
|
361
365
|
$: hasFixedBounds = boundsWidth != null && boundsHeight != null;
|
|
362
366
|
$: containerPaddingStyle = enableResize
|
|
363
|
-
? `padding: ${
|
|
367
|
+
? `padding: ${edgeInset}px ${edgeInset}px ${edgeInset}px ${edgeInset}px;`
|
|
364
368
|
: !hasFixedBounds && !compactChrome && (showUrlBar || mode === 'controlled')
|
|
365
369
|
? `padding: ${HANDLE_MARGIN}px;`
|
|
366
370
|
: '';
|
|
@@ -378,8 +382,8 @@
|
|
|
378
382
|
: '';
|
|
379
383
|
$: iframeTitle =
|
|
380
384
|
mode === 'controlled'
|
|
381
|
-
? '
|
|
382
|
-
:
|
|
385
|
+
? $t('editor.preview.frameTitle')
|
|
386
|
+
: $t('editor.preview.frameTitleNamed', { name: widget?.name || $t('editor.preview.widgetName') });
|
|
383
387
|
|
|
384
388
|
function buildWidgetUrl(w: any): string | null {
|
|
385
389
|
if (!w) return null;
|
|
@@ -420,7 +424,6 @@
|
|
|
420
424
|
iframeLoaded = false;
|
|
421
425
|
iframeError = false;
|
|
422
426
|
widgetReady = false;
|
|
423
|
-
errorMessage = '';
|
|
424
427
|
pendingMessages = [];
|
|
425
428
|
isResolvingUrl = false;
|
|
426
429
|
|
|
@@ -476,7 +479,6 @@
|
|
|
476
479
|
isWidgetPublished = false;
|
|
477
480
|
iframeLoaded = false;
|
|
478
481
|
iframeError = false;
|
|
479
|
-
errorMessage = '';
|
|
480
482
|
widgetReady = false;
|
|
481
483
|
isResolvingUrl = false;
|
|
482
484
|
}
|
|
@@ -594,7 +596,6 @@
|
|
|
594
596
|
iframeError = true;
|
|
595
597
|
iframeLoaded = false;
|
|
596
598
|
widgetReady = false;
|
|
597
|
-
errorMessage = 'Failed to load widget preview.';
|
|
598
599
|
console.error('[WidgetPreview] Widget iframe onerror:', effectiveSrc);
|
|
599
600
|
dispatch('error', { src: effectiveSrc });
|
|
600
601
|
}
|
|
@@ -810,7 +811,7 @@
|
|
|
810
811
|
<span
|
|
811
812
|
class="preview-url-text flex-1 rounded border border-gray-300 px-2 py-1 text-xs text-gray-500 min-w-0 font-mono overflow-x-auto whitespace-nowrap"
|
|
812
813
|
>
|
|
813
|
-
{effectiveDisplayUrl || effectiveSrc || '
|
|
814
|
+
{effectiveDisplayUrl || effectiveSrc || $t('editor.preview.noUrl')}
|
|
814
815
|
</span>
|
|
815
816
|
<button
|
|
816
817
|
type="button"
|
|
@@ -818,7 +819,7 @@
|
|
|
818
819
|
const url = effectiveDisplayUrl || effectiveSrc;
|
|
819
820
|
if (url) navigator.clipboard.writeText(url);
|
|
820
821
|
}}
|
|
821
|
-
title=
|
|
822
|
+
title={$t('editor.preview.copyUrl')}
|
|
822
823
|
class="shrink-0 w-7 h-7 flex items-center justify-center rounded border border-gray-300 bg-white hover:bg-gray-100 text-sm cursor-pointer"
|
|
823
824
|
>
|
|
824
825
|
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
|
|
@@ -827,14 +828,14 @@
|
|
|
827
828
|
<button
|
|
828
829
|
type="button"
|
|
829
830
|
onclick={handleRefreshClick}
|
|
830
|
-
title=
|
|
831
|
+
title={$t('editor.preview.refresh')}
|
|
831
832
|
class="shrink-0 w-7 h-7 flex items-center justify-center rounded border border-gray-300 bg-white hover:bg-gray-100 text-sm cursor-pointer"
|
|
832
833
|
>🔄</button>
|
|
833
834
|
{#if showViewportButtons && enableResize}
|
|
834
835
|
<button
|
|
835
836
|
type="button"
|
|
836
837
|
onclick={handleFitToAreaClick}
|
|
837
|
-
title=
|
|
838
|
+
title={$t('editor.preview.fitToPanel')}
|
|
838
839
|
class="preview-fit-to-area-btn shrink-0 w-7 h-7 flex items-center justify-center rounded border border-gray-300 bg-white hover:bg-gray-100 cursor-pointer"
|
|
839
840
|
>
|
|
840
841
|
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3h6v6"/><path d="M9 21H3v-6"/><path d="M21 3l-7 7"/><path d="M3 21l7-7"/></svg>
|
|
@@ -842,7 +843,7 @@
|
|
|
842
843
|
<button
|
|
843
844
|
type="button"
|
|
844
845
|
onclick={applyMobileViewport}
|
|
845
|
-
title=
|
|
846
|
+
title={$t('editor.preview.mobileViewport')}
|
|
846
847
|
class="preview-mobile-viewport-btn shrink-0 w-7 h-7 flex items-center justify-center rounded border border-gray-300 bg-white hover:bg-gray-100 cursor-pointer"
|
|
847
848
|
>
|
|
848
849
|
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="5" y="2" width="14" height="20" rx="2" ry="2"/><line x1="12" y1="18" x2="12.01" y2="18"/></svg>
|
|
@@ -850,7 +851,7 @@
|
|
|
850
851
|
<button
|
|
851
852
|
type="button"
|
|
852
853
|
onclick={handleDesktopViewport}
|
|
853
|
-
title=
|
|
854
|
+
title={$t('editor.preview.desktopViewport')}
|
|
854
855
|
class="preview-desktop-viewport-btn shrink-0 w-7 h-7 flex items-center justify-center rounded border border-gray-300 bg-white hover:bg-gray-100 cursor-pointer"
|
|
855
856
|
>
|
|
856
857
|
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="14" rx="2" ry="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg>
|
|
@@ -859,9 +860,9 @@
|
|
|
859
860
|
<button
|
|
860
861
|
type="button"
|
|
861
862
|
onclick={handleOpenInTabClick}
|
|
862
|
-
title=
|
|
863
|
+
title={$t('editor.preview.openInNewTab')}
|
|
863
864
|
class="shrink-0 px-2 h-7 flex items-center justify-center rounded border border-gray-300 bg-white hover:bg-gray-100 text-xs cursor-pointer whitespace-nowrap"
|
|
864
|
-
|
|
865
|
+
>{$t('editor.preview.newTab')}</button>
|
|
865
866
|
{/if}
|
|
866
867
|
</div>
|
|
867
868
|
{/if}
|
|
@@ -880,7 +881,7 @@
|
|
|
880
881
|
|
|
881
882
|
{:else if mode === 'standalone' && !widget}
|
|
882
883
|
<div class="widget-preview-select-ct flex items-center justify-center h-full text-sm text-gray-400">
|
|
883
|
-
|
|
884
|
+
{$t('editor.preview.selectWidget')}
|
|
884
885
|
</div>
|
|
885
886
|
|
|
886
887
|
{:else if mode === 'standalone' && widget && !effectiveSrc && !isResolvingUrl && !iframeError}
|
|
@@ -892,11 +893,11 @@
|
|
|
892
893
|
</svg>
|
|
893
894
|
</div>
|
|
894
895
|
<div>
|
|
895
|
-
<p class="text-sm font-medium text-gray-600">{widget.name || '
|
|
896
|
-
<p class="text-xs text-gray-400 mt-1">
|
|
896
|
+
<p class="text-sm font-medium text-gray-600">{widget.name || $t('editor.preview.widgetName')}</p>
|
|
897
|
+
<p class="text-xs text-gray-400 mt-1">{$t('editor.preview.notPublished')}</p>
|
|
897
898
|
</div>
|
|
898
899
|
<p class="text-[11px] text-gray-300 max-w-[220px]">
|
|
899
|
-
|
|
900
|
+
{$t('editor.preview.publishToPreview')}
|
|
900
901
|
</p>
|
|
901
902
|
</div>
|
|
902
903
|
</div>
|
|
@@ -909,7 +910,7 @@
|
|
|
909
910
|
<div
|
|
910
911
|
class="preview-iframe-shell relative flex flex-col {enableResize ? 'preview-iframe-shell-positioned' : ''}"
|
|
911
912
|
class:preview-iframe-shell-symmetrical={showSymmetricalStroke}
|
|
912
|
-
style="{enableResize
|
|
913
|
+
style="{enableResize /* rtl-ok: the preview is placed in pixels from the left edge of the stage; the dock of the editor mirrors it */
|
|
913
914
|
? `position: absolute; left: ${previewShellLeft}px; top: ${previewShellTop}px; width: ${resizeWidth ? resizeWidth + 'px' : '100%'};`
|
|
914
915
|
: `width: ${resizeWidth ? resizeWidth + 'px' : '100%'}; height: ${resizeHeight ? resizeHeight + 'px' : '100%'};`} transition: {isResizing || isDraggingPreview ? 'none' : 'width 0.2s, height 0.2s, left 0.15s, top 0.15s'};"
|
|
915
916
|
>
|
|
@@ -921,69 +922,32 @@
|
|
|
921
922
|
onpointerdown={startPreviewDrag}
|
|
922
923
|
>
|
|
923
924
|
{#if enableDrag}
|
|
924
|
-
<span class="preview-chrome-drag-grip shrink-0 text-gray-400 text-xs leading-none" title=
|
|
925
|
-
{/if}
|
|
926
|
-
<span class="preview-chrome-title text-[11px] font-semibold uppercase tracking-wide text-gray-500 shrink-0">Preview</span>
|
|
927
|
-
{#if showChromeDeviceToggle}
|
|
928
|
-
<div
|
|
929
|
-
class="preview-chrome-device-toggle ml-auto flex shrink-0 items-center overflow-hidden rounded border border-gray-300"
|
|
930
|
-
onpointerdown={(event) => event.stopPropagation()}
|
|
931
|
-
>
|
|
932
|
-
<button
|
|
933
|
-
type="button"
|
|
934
|
-
class="preview-chrome-device-desktop flex h-6 w-6 items-center justify-center {!deviceMobile ? 'bg-gray-100 text-gray-800' : 'bg-white text-gray-400'} hover:text-gray-800 focus:outline-none focus-visible:outline-none"
|
|
935
|
-
aria-label="Desktop preview"
|
|
936
|
-
aria-pressed={!deviceMobile}
|
|
937
|
-
onclick={() => dispatch('deviceView', { mobile: false })}
|
|
938
|
-
onpointerdown={(event) => event.stopPropagation()}
|
|
939
|
-
>
|
|
940
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="2" y="3" width="20" height="14" rx="2" ry="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg>
|
|
941
|
-
</button>
|
|
942
|
-
<button
|
|
943
|
-
type="button"
|
|
944
|
-
class="preview-chrome-device-mobile flex h-6 w-6 items-center justify-center border-l border-gray-300 {deviceMobile ? 'bg-gray-100 text-gray-800' : 'bg-white text-gray-400'} hover:text-gray-800 focus:outline-none focus-visible:outline-none"
|
|
945
|
-
aria-label="Mobile preview"
|
|
946
|
-
aria-pressed={deviceMobile}
|
|
947
|
-
onclick={() => dispatch('deviceView', { mobile: true })}
|
|
948
|
-
onpointerdown={(event) => event.stopPropagation()}
|
|
949
|
-
>
|
|
950
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="5" y="2" width="14" height="20" rx="2" ry="2"/><line x1="12" y1="18" x2="12.01" y2="18"/></svg>
|
|
951
|
-
</button>
|
|
952
|
-
</div>
|
|
953
|
-
{/if}
|
|
954
|
-
{#if showDimensionInputs}
|
|
955
|
-
<div class="preview-chrome-dimensions flex items-center gap-1.5 {showChromeDeviceToggle ? '' : 'ml-auto'}">
|
|
956
|
-
<label class="preview-dim-label flex items-center gap-1 text-[10px] font-semibold text-gray-500">
|
|
957
|
-
<span>W</span>
|
|
958
|
-
<input
|
|
959
|
-
type="number"
|
|
960
|
-
min={MIN_WIDTH}
|
|
961
|
-
class="preview-dim-input w-14 h-6 rounded border border-gray-300 bg-white px-1 text-[11px] text-gray-800 focus:outline-none focus:border-blue-400 focus-visible:outline-none"
|
|
962
|
-
value={widthInputValue}
|
|
963
|
-
oninput={(e) => {
|
|
964
|
-
widthInputValue = e.currentTarget.value;
|
|
965
|
-
applyDimensionFromInput('width', e.currentTarget.value);
|
|
966
|
-
}}
|
|
967
|
-
onpointerdown={(e) => e.stopPropagation()}
|
|
968
|
-
/>
|
|
969
|
-
</label>
|
|
970
|
-
<span class="text-[10px] text-gray-400">×</span>
|
|
971
|
-
<label class="preview-dim-label flex items-center gap-1 text-[10px] font-semibold text-gray-500">
|
|
972
|
-
<span>H</span>
|
|
973
|
-
<input
|
|
974
|
-
type="number"
|
|
975
|
-
min={MIN_HEIGHT}
|
|
976
|
-
class="preview-dim-input w-14 h-6 rounded border border-gray-300 bg-white px-1 text-[11px] text-gray-800 focus:outline-none focus:border-blue-400 focus-visible:outline-none"
|
|
977
|
-
value={heightInputValue}
|
|
978
|
-
oninput={(e) => {
|
|
979
|
-
heightInputValue = e.currentTarget.value;
|
|
980
|
-
applyDimensionFromInput('height', e.currentTarget.value);
|
|
981
|
-
}}
|
|
982
|
-
onpointerdown={(e) => e.stopPropagation()}
|
|
983
|
-
/>
|
|
984
|
-
</label>
|
|
985
|
-
</div>
|
|
925
|
+
<span class="preview-chrome-drag-grip shrink-0 text-gray-400 text-xs leading-none" title={$t('editor.preview.dragHandle')} aria-hidden="true">⠿</span>
|
|
986
926
|
{/if}
|
|
927
|
+
<span class="preview-chrome-title text-[11px] font-semibold uppercase tracking-wide text-gray-500 shrink-0">{$t('editor.preview.title')}</span>
|
|
928
|
+
<PreviewChromeControls
|
|
929
|
+
class="{showChromeDeviceToggle || showDimensionInputs ? 'ms-auto' : ''}"
|
|
930
|
+
mobile={deviceMobile}
|
|
931
|
+
showDevices={showChromeDeviceToggle}
|
|
932
|
+
showDimensions={showDimensionInputs}
|
|
933
|
+
widthValue={widthInputValue}
|
|
934
|
+
heightValue={heightInputValue}
|
|
935
|
+
minWidth={MIN_WIDTH}
|
|
936
|
+
minHeight={MIN_HEIGHT}
|
|
937
|
+
desktopLabel={$t('editor.preview.desktop')}
|
|
938
|
+
mobileLabel={$t('editor.preview.mobile')}
|
|
939
|
+
widthLabel={$t('editor.preview.widthShort')}
|
|
940
|
+
heightLabel={$t('editor.preview.heightShort')}
|
|
941
|
+
onDevice={(nextMobile) => dispatch('deviceView', { mobile: nextMobile })}
|
|
942
|
+
onWidth={(value) => {
|
|
943
|
+
widthInputValue = value;
|
|
944
|
+
applyDimensionFromInput('width', value);
|
|
945
|
+
}}
|
|
946
|
+
onHeight={(value) => {
|
|
947
|
+
heightInputValue = value;
|
|
948
|
+
applyDimensionFromInput('height', value);
|
|
949
|
+
}}
|
|
950
|
+
/>
|
|
987
951
|
</div>
|
|
988
952
|
{/if}
|
|
989
953
|
|
|
@@ -1021,20 +985,20 @@
|
|
|
1021
985
|
<svg class="w-8 h-8 text-gray-300" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5">
|
|
1022
986
|
<path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z" />
|
|
1023
987
|
</svg>
|
|
1024
|
-
<span class="text-sm text-gray-500">{
|
|
988
|
+
<span class="text-sm text-gray-500">{$t('editor.preview.loadFailedPreview')}</span>
|
|
1025
989
|
</div>
|
|
1026
990
|
</div>
|
|
1027
991
|
{:else if mode === 'controlled' && previewError && !isGeneratingCode}
|
|
1028
992
|
<div class="preview-error-overlay absolute inset-0 z-10 flex h-full flex-col items-center justify-center bg-red-50/95 text-gray-700 p-6">
|
|
1029
993
|
<div class="text-4xl mb-3">⚠️</div>
|
|
1030
|
-
<div class="font-semibold text-lg text-red-600 mb-2">
|
|
994
|
+
<div class="font-semibold text-lg text-red-600 mb-2">{$t('editor.preview.unavailable')}</div>
|
|
1031
995
|
<div class="text-sm text-center max-w-md whitespace-pre-line text-gray-600 mb-4">{previewError}</div>
|
|
1032
996
|
<div class="flex gap-3">
|
|
1033
997
|
<button type="button" onclick={() => dispatch('retry')} class="px-3 py-1.5 text-xs rounded border border-blue-500 text-blue-600 bg-white hover:bg-blue-50 cursor-pointer">
|
|
1034
|
-
🔄
|
|
998
|
+
🔄 {$t('editor.preview.retry')} {previewRetryCount > 0 ? `(${previewRetryCount})` : ''}
|
|
1035
999
|
</button>
|
|
1036
1000
|
<button type="button" onclick={() => dispatch('openInTab')} class="px-3 py-1.5 text-xs rounded border border-gray-300 text-gray-600 bg-white hover:bg-gray-100 cursor-pointer">
|
|
1037
|
-
|
|
1001
|
+
{$t('editor.preview.openInNewTab')}
|
|
1038
1002
|
</button>
|
|
1039
1003
|
</div>
|
|
1040
1004
|
</div>
|
|
@@ -1042,21 +1006,17 @@
|
|
|
1042
1006
|
|
|
1043
1007
|
{#if showStandaloneLoading}
|
|
1044
1008
|
<div class="widget-preview-loading-ct absolute inset-0 z-10 flex items-center justify-center bg-gray-50/80">
|
|
1045
|
-
<GenerateLoader title=
|
|
1009
|
+
<GenerateLoader title={$t('editor.preview.loadingWidget')} subtitle="" size="md" />
|
|
1046
1010
|
</div>
|
|
1047
1011
|
{:else if showControlledLoading && !isGeneratingCode}
|
|
1048
1012
|
<div class="loading-overlay absolute inset-0 z-20 flex items-center justify-center bg-gray-50">
|
|
1049
1013
|
<GenerateLoader
|
|
1050
|
-
title={
|
|
1051
|
-
? 'Loading Preview…'
|
|
1052
|
-
: previewHydrating
|
|
1053
|
-
? 'Loading Preview…'
|
|
1054
|
-
: 'Loading Preview…'}
|
|
1014
|
+
title={$t('editor.preview.loadingPreview')}
|
|
1055
1015
|
subtitle={!src && isLoadingUrl
|
|
1056
|
-
? '
|
|
1016
|
+
? $t('editor.preview.checkingWidget')
|
|
1057
1017
|
: previewHydrating
|
|
1058
|
-
? '
|
|
1059
|
-
: '
|
|
1018
|
+
? $t('editor.preview.applyingSettings')
|
|
1019
|
+
: $t('editor.preview.connecting')}
|
|
1060
1020
|
size="lg"
|
|
1061
1021
|
/>
|
|
1062
1022
|
</div>
|
|
@@ -1067,17 +1027,17 @@
|
|
|
1067
1027
|
<div class="text-5xl mb-4">⚠️</div>
|
|
1068
1028
|
<div class="font-semibold text-xl mb-2">
|
|
1069
1029
|
{previewError && /TypeError|Uncaught|is not a function|is not defined/i.test(previewError)
|
|
1070
|
-
? '
|
|
1071
|
-
: '
|
|
1030
|
+
? $t('editor.preview.runtimeError')
|
|
1031
|
+
: $t('editor.preview.compilationErrors')}
|
|
1072
1032
|
</div>
|
|
1073
1033
|
<div class="text-sm text-center text-red-600 mb-4 max-w-md whitespace-pre-line">
|
|
1074
1034
|
{previewError
|
|
1075
|
-
||
|
|
1035
|
+
|| $t('editor.preview.compilationErrorsDetail', { status: previewRuntimeErrorStatus ?? '?' })}
|
|
1076
1036
|
</div>
|
|
1077
1037
|
<div class="flex gap-3 flex-wrap justify-center">
|
|
1078
|
-
<button type="button" onclick={() => dispatch('fixErrors')} class="px-4 py-2 text-xs rounded bg-red-600 hover:bg-red-700 text-white cursor-pointer border-0">🔧
|
|
1079
|
-
<button type="button" onclick={() => dispatch('viewErrors')} class="px-3 py-1.5 text-xs rounded border border-orange-400 text-orange-600 bg-white hover:bg-orange-50 cursor-pointer">📋
|
|
1080
|
-
<button type="button" onclick={() => dispatch('retryPreview')} class="px-3 py-1.5 text-xs rounded border border-red-300 text-red-600 bg-white hover:bg-red-50 cursor-pointer">🔄
|
|
1038
|
+
<button type="button" onclick={() => dispatch('fixErrors')} class="px-4 py-2 text-xs rounded bg-red-600 hover:bg-red-700 text-white cursor-pointer border-0">🔧 {$t('editor.preview.fixErrors')}</button>
|
|
1039
|
+
<button type="button" onclick={() => dispatch('viewErrors')} class="px-3 py-1.5 text-xs rounded border border-orange-400 text-orange-600 bg-white hover:bg-orange-50 cursor-pointer">📋 {$t('editor.preview.viewErrors')}</button>
|
|
1040
|
+
<button type="button" onclick={() => dispatch('retryPreview')} class="px-3 py-1.5 text-xs rounded border border-red-300 text-red-600 bg-white hover:bg-red-50 cursor-pointer">🔄 {$t('editor.preview.retryPreview')}</button>
|
|
1081
1041
|
</div>
|
|
1082
1042
|
</div>
|
|
1083
1043
|
{/if}
|
|
@@ -1109,7 +1069,7 @@
|
|
|
1109
1069
|
{/if}
|
|
1110
1070
|
|
|
1111
1071
|
{#if mode === 'controlled' && isGeneratingCode}
|
|
1112
|
-
<GenerateLoader overlay title=
|
|
1072
|
+
<GenerateLoader overlay title={$t('editor.preview.generatingCode')} subtitle="" size="lg" />
|
|
1113
1073
|
{/if}
|
|
1114
1074
|
</div>
|
|
1115
1075
|
</div>
|
|
@@ -1119,22 +1079,22 @@
|
|
|
1119
1079
|
{:else if mode === 'controlled'}
|
|
1120
1080
|
{#if isLoadingUrl}
|
|
1121
1081
|
<div class="flex h-full flex-col items-center justify-center p-6">
|
|
1122
|
-
<GenerateLoader title=
|
|
1082
|
+
<GenerateLoader title={$t('editor.preview.loadingPreview')} subtitle="" size="lg" />
|
|
1123
1083
|
</div>
|
|
1124
1084
|
{:else}
|
|
1125
1085
|
<div class="flex h-full flex-col items-center justify-center p-6 text-center text-sm text-gray-600">
|
|
1126
1086
|
{#if isGeneratingCode}
|
|
1127
|
-
<GenerateLoader title=
|
|
1087
|
+
<GenerateLoader title={$t('editor.preview.generatingCode')} subtitle="" size="lg" />
|
|
1128
1088
|
{:else if previewError === 'NO_CODE_YET'}
|
|
1129
|
-
<div class="font-semibold text-lg text-gray-700 mb-2">
|
|
1089
|
+
<div class="font-semibold text-lg text-gray-700 mb-2">{$t('editor.preview.noCodeYet')}</div>
|
|
1130
1090
|
{:else if previewError}
|
|
1131
|
-
<div class="font-semibold text-lg text-red-600 mb-2">
|
|
1091
|
+
<div class="font-semibold text-lg text-red-600 mb-2">{$t('editor.preview.unavailable')}</div>
|
|
1132
1092
|
<div class="text-sm text-gray-600 mb-4">{previewError}</div>
|
|
1133
|
-
<button type="button" onclick={() => dispatch('retry')} class="px-3 py-1.5 text-xs rounded border border-blue-500 text-blue-600 bg-white hover:bg-blue-50 cursor-pointer">🔄
|
|
1093
|
+
<button type="button" onclick={() => dispatch('retry')} class="px-3 py-1.5 text-xs rounded border border-blue-500 text-blue-600 bg-white hover:bg-blue-50 cursor-pointer">🔄 {$t('editor.preview.retryBuild')}</button>
|
|
1134
1094
|
{:else if previewLoading}
|
|
1135
|
-
<div class="text-lg font-medium text-gray-700">
|
|
1095
|
+
<div class="text-lg font-medium text-gray-700">{$t('editor.preview.building')}</div>
|
|
1136
1096
|
{:else}
|
|
1137
|
-
<div class="text-lg text-gray-600 mb-2">🖼️
|
|
1097
|
+
<div class="text-lg text-gray-600 mb-2">🖼️ {$t('editor.preview.noPreview')}</div>
|
|
1138
1098
|
{/if}
|
|
1139
1099
|
</div>
|
|
1140
1100
|
{/if}
|
|
@@ -1178,10 +1138,11 @@
|
|
|
1178
1138
|
box-shadow: none;
|
|
1179
1139
|
}
|
|
1180
1140
|
|
|
1181
|
-
|
|
1182
|
-
.preview-resize-handle-
|
|
1183
|
-
.preview-resize-handle-
|
|
1184
|
-
.preview-resize-handle-
|
|
1141
|
+
/* The four corner handles of the preview are on the four corners of the box, a place on the screen: the set is the same in both directions. */
|
|
1142
|
+
.preview-resize-handle-tl { top: -5px; left: -5px; cursor: nwse-resize; } /* rtl-ok: top left corner */
|
|
1143
|
+
.preview-resize-handle-tr { top: -5px; right: -5px; cursor: nesw-resize; } /* rtl-ok: top right corner */
|
|
1144
|
+
.preview-resize-handle-bl { bottom: -5px; left: -5px; cursor: nesw-resize; } /* rtl-ok: bottom left corner */
|
|
1145
|
+
.preview-resize-handle-br { bottom: -5px; right: -5px; cursor: nwse-resize; } /* rtl-ok: bottom right corner */
|
|
1185
1146
|
|
|
1186
1147
|
.preview-resize-handle:hover {
|
|
1187
1148
|
background: #eff6ff;
|
|
@@ -66,6 +66,7 @@ declare const WidgetPreview: $$__sveltets_2_IsomorphicComponent<{
|
|
|
66
66
|
resizeWidth?: number | null;
|
|
67
67
|
resizeHeight?: number | null;
|
|
68
68
|
iframeEl?: HTMLIFrameElement | null;
|
|
69
|
+
/** Inset so resize handles stay inside bounds. 0 sits the frame on the stage edge. */ edgeInset?: number;
|
|
69
70
|
getResizeLimits?: () => {
|
|
70
71
|
maxWidth: number;
|
|
71
72
|
maxHeight: number;
|
|
@@ -173,8 +173,10 @@ $: if (rgb && typeof a === 'number') {
|
|
|
173
173
|
|
|
174
174
|
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
|
175
175
|
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
|
176
|
+
<!-- The picker is a drawing: saturation grows to the right and hue is a strip next to it, on every screen, so it is a left to right island. -->
|
|
176
177
|
<div
|
|
177
178
|
class={$$props.class}
|
|
179
|
+
dir="ltr"
|
|
178
180
|
tabindex="0"
|
|
179
181
|
style="width: {width}px; height: {height}px;"
|
|
180
182
|
on:keydown={onKeydown}
|
|
@@ -184,8 +186,7 @@ $: if (rgb && typeof a === 'number') {
|
|
|
184
186
|
id="{instanceId}_sv"
|
|
185
187
|
width={pickerSize}
|
|
186
188
|
height={pickerSize}
|
|
187
|
-
style
|
|
188
|
-
style:left="{border_size}px"
|
|
189
|
+
style="top: {border_size}px; left: {border_size}px; /* rtl-ok: the saturation square is drawn from the left edge of the picker */"
|
|
189
190
|
use:pointer={update_sv}
|
|
190
191
|
use:render_main_image={color.h}
|
|
191
192
|
/>
|
|
@@ -193,8 +194,7 @@ $: if (rgb && typeof a === 'number') {
|
|
|
193
194
|
<canvas
|
|
194
195
|
width={sliderWidth}
|
|
195
196
|
height={pickerSize}
|
|
196
|
-
style
|
|
197
|
-
style:left="{pickerSize + gap_size}px"
|
|
197
|
+
style="top: {border_size}px; left: {pickerSize + gap_size}px; /* rtl-ok: the hue strip is drawn next to the square, from the left edge of the picker */"
|
|
198
198
|
use:pointer={update_h}
|
|
199
199
|
use:render_slider_image
|
|
200
200
|
/>
|