sdk: improve legacy URL extraction; editor: ctrl right-click select
This commit is contained in:
parent
b6f69b8d6a
commit
de4243ca10
@ -165,8 +165,13 @@ export function Canvas(props: CanvasProps) {
|
|||||||
|
|
||||||
if (targetId && !props.selectionIds.includes(targetId)) {
|
if (targetId && !props.selectionIds.includes(targetId)) {
|
||||||
// goView-ish: right click selects the item.
|
// goView-ish: right click selects the item.
|
||||||
|
// Ctrl/Cmd keeps multi-select parity (add to selection instead of replacing).
|
||||||
|
if ((e as React.MouseEvent).ctrlKey || (e as React.MouseEvent).metaKey) {
|
||||||
|
props.onToggleSelect(targetId);
|
||||||
|
} else {
|
||||||
props.onSelectSingle(targetId);
|
props.onSelectSingle(targetId);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setCtx({ clientX: e.clientX, clientY: e.clientY, worldX: p.x, worldY: p.y, targetId });
|
setCtx({ clientX: e.clientX, clientY: e.clientY, worldX: p.x, worldY: p.y, targetId });
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import type { IframeWidgetNode } from '../schema';
|
import type { IframeWidgetNode } from '../schema';
|
||||||
|
import { pickUrlLike } from './urlLike';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* goView iframe option shape varies across versions.
|
* goView iframe option shape varies across versions.
|
||||||
@ -16,23 +17,8 @@ export interface GoViewIframeOption {
|
|||||||
*/
|
*/
|
||||||
export type LegacyIframeOption = GoViewIframeOption;
|
export type LegacyIframeOption = GoViewIframeOption;
|
||||||
|
|
||||||
function asString(v: unknown): string {
|
|
||||||
if (typeof v === 'string') return v;
|
|
||||||
if (!v) return '';
|
|
||||||
|
|
||||||
// Some goView widgets store data as { value: '...' } or { url: '...' }.
|
|
||||||
if (typeof v === 'object') {
|
|
||||||
const obj = v as Record<string, unknown>;
|
|
||||||
if (typeof obj.value === 'string') return obj.value;
|
|
||||||
if (typeof obj.url === 'string') return obj.url;
|
|
||||||
if (typeof obj.src === 'string') return obj.src;
|
|
||||||
}
|
|
||||||
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
function pickSrc(option: GoViewIframeOption): string {
|
function pickSrc(option: GoViewIframeOption): string {
|
||||||
return asString(option.dataset) || asString(option.src) || asString(option.url);
|
return pickUrlLike(option.dataset) || pickUrlLike(option.src) || pickUrlLike(option.url);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function convertGoViewIframeOptionToNodeProps(option: GoViewIframeOption): IframeWidgetNode['props'] {
|
export function convertGoViewIframeOptionToNodeProps(option: GoViewIframeOption): IframeWidgetNode['props'] {
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import type { ImageWidgetNode } from '../schema';
|
import type { ImageWidgetNode } from '../schema';
|
||||||
|
import { pickUrlLike } from './urlLike';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* goView Image option shape varies across versions. We keep this intentionally
|
* goView Image option shape varies across versions. We keep this intentionally
|
||||||
@ -24,25 +25,16 @@ export interface GoViewImageOption {
|
|||||||
borderRadius?: number;
|
borderRadius?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function pickSrc(option: GoViewImageOption): string {
|
||||||
|
return pickUrlLike(option.dataset) || pickUrlLike(option.src) || pickUrlLike(option.url);
|
||||||
|
}
|
||||||
|
|
||||||
function asString(v: unknown): string {
|
function asString(v: unknown): string {
|
||||||
if (typeof v === 'string') return v;
|
if (typeof v === 'string') return v;
|
||||||
if (!v) return '';
|
if (!v) return '';
|
||||||
|
|
||||||
// Some goView widgets store data as { value: '...' } or { url: '...' }.
|
|
||||||
if (typeof v === 'object') {
|
|
||||||
const obj = v as Record<string, unknown>;
|
|
||||||
if (typeof obj.value === 'string') return obj.value;
|
|
||||||
if (typeof obj.url === 'string') return obj.url;
|
|
||||||
if (typeof obj.src === 'string') return obj.src;
|
|
||||||
}
|
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
function pickSrc(option: GoViewImageOption): string {
|
|
||||||
return asString(option.dataset) || asString(option.src) || asString(option.url);
|
|
||||||
}
|
|
||||||
|
|
||||||
function pickFit(option: GoViewImageOption): ImageWidgetNode['props']['fit'] | undefined {
|
function pickFit(option: GoViewImageOption): ImageWidgetNode['props']['fit'] | undefined {
|
||||||
const raw = asString(option.fit) || asString(option.objectFit);
|
const raw = asString(option.fit) || asString(option.objectFit);
|
||||||
if (!raw) return undefined;
|
if (!raw) return undefined;
|
||||||
|
|||||||
48
packages/sdk/src/core/widgets/urlLike.ts
Normal file
48
packages/sdk/src/core/widgets/urlLike.ts
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/**
|
||||||
|
* Small helper for permissive imports (goView / low-code exports).
|
||||||
|
*
|
||||||
|
* Many widgets store their URL-ish source in slightly different shapes:
|
||||||
|
* - string
|
||||||
|
* - { value: string }
|
||||||
|
* - { url: string }
|
||||||
|
* - { src: string }
|
||||||
|
* - { dataset: string | { value/url/src } }
|
||||||
|
* - nested objects under `data` / `config` / `options`
|
||||||
|
*/
|
||||||
|
export function pickUrlLike(input: unknown, maxDepth = 3): string {
|
||||||
|
return pickUrlLikeInner(input, maxDepth);
|
||||||
|
}
|
||||||
|
|
||||||
|
function pickUrlLikeInner(input: unknown, depth: number): string {
|
||||||
|
if (typeof input === 'string') return input;
|
||||||
|
if (!input) return '';
|
||||||
|
|
||||||
|
if (Array.isArray(input)) {
|
||||||
|
for (const item of input) {
|
||||||
|
const v = pickUrlLikeInner(item, depth - 1);
|
||||||
|
if (v) return v;
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof input !== 'object') return '';
|
||||||
|
|
||||||
|
const obj = input as Record<string, unknown>;
|
||||||
|
|
||||||
|
// Common direct keys.
|
||||||
|
for (const key of ['value', 'url', 'src', 'href', 'link', 'path', 'iframeUrl', 'videoUrl', 'mp4']) {
|
||||||
|
const v = obj[key];
|
||||||
|
if (typeof v === 'string' && v) return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (depth <= 0) return '';
|
||||||
|
|
||||||
|
// Common nesting keys.
|
||||||
|
for (const key of ['dataset', 'data', 'config', 'option', 'options', 'props']) {
|
||||||
|
const v = obj[key];
|
||||||
|
const nested = pickUrlLikeInner(v, depth - 1);
|
||||||
|
if (nested) return nested;
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
@ -1,4 +1,5 @@
|
|||||||
import type { VideoWidgetNode } from '../schema';
|
import type { VideoWidgetNode } from '../schema';
|
||||||
|
import { pickUrlLike } from './urlLike';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* goView video option shape varies across versions.
|
* goView video option shape varies across versions.
|
||||||
@ -23,24 +24,16 @@ export interface GoViewVideoOption {
|
|||||||
*/
|
*/
|
||||||
export type LegacyVideoOption = GoViewVideoOption;
|
export type LegacyVideoOption = GoViewVideoOption;
|
||||||
|
|
||||||
|
function pickSrc(option: GoViewVideoOption): string {
|
||||||
|
return pickUrlLike(option.dataset) || pickUrlLike(option.src) || pickUrlLike(option.url);
|
||||||
|
}
|
||||||
|
|
||||||
function asString(v: unknown): string {
|
function asString(v: unknown): string {
|
||||||
if (typeof v === 'string') return v;
|
if (typeof v === 'string') return v;
|
||||||
if (!v) return '';
|
if (!v) return '';
|
||||||
|
|
||||||
if (typeof v === 'object') {
|
|
||||||
const obj = v as Record<string, unknown>;
|
|
||||||
if (typeof obj.value === 'string') return obj.value;
|
|
||||||
if (typeof obj.url === 'string') return obj.url;
|
|
||||||
if (typeof obj.src === 'string') return obj.src;
|
|
||||||
}
|
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
function pickSrc(option: GoViewVideoOption): string {
|
|
||||||
return asString(option.dataset) || asString(option.src) || asString(option.url);
|
|
||||||
}
|
|
||||||
|
|
||||||
function pickFit(option: GoViewVideoOption): VideoWidgetNode['props']['fit'] | undefined {
|
function pickFit(option: GoViewVideoOption): VideoWidgetNode['props']['fit'] | undefined {
|
||||||
const raw = asString(option.fit) || asString(option.objectFit);
|
const raw = asString(option.fit) || asString(option.objectFit);
|
||||||
if (!raw) return undefined;
|
if (!raw) return undefined;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user