Skip to content
This repository has been archived by the owner on Apr 25, 2023. It is now read-only.

feat: extend plugin API supports move widget #346

Merged
merged 12 commits into from
Nov 28, 2022
12 changes: 11 additions & 1 deletion src/components/molecules/Visualizer/Plugin/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import type {
Plugin,
Tag,
PopupPosition,
WidgetLocationOptions,
} from "./types";

export type CommonReearth = Omit<
Expand Down Expand Up @@ -41,6 +42,7 @@ export function exposed({
block,
widget,
overrideSceneProperty,
moveWidget,
}: {
render: (
html: string,
Expand Down Expand Up @@ -76,6 +78,7 @@ export function exposed({
block?: () => Block | undefined;
widget?: () => Widget | undefined;
overrideSceneProperty?: (pluginId: string, property: any) => void;
moveWidget?: (widgetId: string, options: WidgetLocationOptions) => void;
}): GlobalThis {
return merge({
console: {
Expand Down Expand Up @@ -184,7 +187,14 @@ export function exposed({
plugin?.extensionType === "widget"
? {
get widget() {
return widget?.();
return {
...widget?.(),
moveTo: (options: WidgetLocationOptions) => {
const widgetId = widget?.()?.id;
if (!widgetId) return;
moveWidget?.(widgetId, options);
},
};
},
}
: {},
Expand Down
6 changes: 6 additions & 0 deletions src/components/molecules/Visualizer/Plugin/context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import type {
Clock,
Viewport,
LatLngHeight,
WidgetLocationOptions,
} from "./types";

export type EngineContext = {
Expand Down Expand Up @@ -81,12 +82,14 @@ export type Props = {
moveRight: (amount: number) => void;
moveOverTerrain: () => void;
flyToGround: (destination: FlyToDestination, options?: CameraOptions, offset?: number) => void;
moveWidget: (widgetId: string, options: WidgetLocationOptions) => void;
};

export type Context = {
reearth: CommonReearth;
engine: EngineContext;
overrideSceneProperty: (id: string, property: any) => void;
moveWidget: (widgetId: string, options: WidgetLocationOptions) => void;
};

export const context = createContext<Context | undefined>(undefined);
Expand Down Expand Up @@ -140,6 +143,7 @@ export function Provider({
moveRight,
moveOverTerrain,
flyToGround,
moveWidget,
children,
}: Props): JSX.Element {
const [ev, emit] = useMemo(
Expand Down Expand Up @@ -218,6 +222,7 @@ export function Provider({
flyToGround,
}),
overrideSceneProperty,
moveWidget,
}),
[
api,
Expand Down Expand Up @@ -263,6 +268,7 @@ export function Provider({
moveOverTerrain,
flyToGround,
overrideSceneProperty,
moveWidget,
],
);

Expand Down
2 changes: 2 additions & 0 deletions src/components/molecules/Visualizer/Plugin/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -366,11 +366,13 @@ export function useAPI({
onResize?.(width, height, extended);
},
overrideSceneProperty: ctx.overrideSceneProperty,
moveWidget: ctx.moveWidget,
});
};
}, [
ctx?.reearth,
ctx?.overrideSceneProperty,
ctx?.moveWidget,
extensionId,
extensionType,
pluginId,
Expand Down
5 changes: 5 additions & 0 deletions src/components/molecules/Visualizer/Plugin/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ export type Widget<P = any> = {
vertically: boolean;
};
layout?: WidgetLayout;
moveTo?: (options: WidgetLocationOptions) => void;
};

export type WidgetLayout = {
Expand All @@ -223,6 +224,10 @@ export type WidgetLocation = {

export type WidgetAlignment = "start" | "centered" | "end";

export type WidgetLocationOptions = WidgetLocation & {
method?: "insert" | "append";
};

/** The API for iframes, which is required not only for displaying the UI but also for calling the browser API. */
export type UI = {
/**
Expand Down
103 changes: 103 additions & 0 deletions src/components/molecules/Visualizer/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,17 @@ import type {
Clock,
FlyToDestination,
LookAtDestination,
WidgetLocationOptions,
Tag,
} from "./Plugin/types";
import { useOverriddenProperty } from "./utils";
import type {
Widget,
WidgetAlignSystem,
WidgetSection,
WidgetZone,
WidgetArea,
} from "./WidgetAlignSystem";

export type Viewport = {
width: number;
Expand All @@ -50,6 +58,7 @@ export default ({
clock,
sceneProperty,
tags,
alignSystem,
onLayerSelect,
onBlockSelect,
onBlockChange,
Expand All @@ -72,6 +81,7 @@ export default ({
clock?: Clock;
sceneProperty?: SceneProperty;
tags?: Tag[];
alignSystem?: WidgetAlignSystem;
onLayerSelect?: (id?: string) => void;
onBlockSelect?: (id?: string) => void;
onBlockChange?: <T extends keyof ValueTypes>(
Expand Down Expand Up @@ -249,6 +259,97 @@ export default ({
pageview(window.location.pathname);
}, [isPublished, enableGA, trackingId]);

const [overriddenAlignSystem, setOverrideAlignSystem] = useState<WidgetAlignSystem | undefined>(
airslice marked this conversation as resolved.
Show resolved Hide resolved
alignSystem,
);

const moveWidget = useCallback((widgetId: string, options: WidgetLocationOptions) => {
if (
!widgetId ||
!["outer", "inner"].includes(options.zone) ||
!["left", "center", "right"].includes(options.section) ||
!["top", "middle", "bottom"].includes(options.area) ||
(options.section === "center" && options.area === "middle")
)
return;

let tarWidget: Widget | undefined;

setOverrideAlignSystem(alignSystem => {
if (!alignSystem) return alignSystem;
Object.keys(alignSystem).forEach(zoneName => {
const zone = alignSystem[zoneName as keyof WidgetAlignSystem];
if (zone) {
Object.keys(zone).forEach(sectionName => {
const section = zone[sectionName as keyof WidgetZone];
if (section) {
Object.keys(section).forEach(areaName => {
const area = section[areaName as keyof WidgetSection];
if (!tarWidget && area?.widgets) {
let tarIndex;
for (let i = 0, len = area.widgets.length; i < len; i += 1) {
if (area.widgets[i].id === widgetId) {
tarIndex = i;
break;
}
}
airslice marked this conversation as resolved.
Show resolved Hide resolved
if (tarIndex !== undefined) {
[tarWidget] = area.widgets.splice(tarIndex, 1);
}
}
});
}
});
}
});
return { ...alignSystem };
});

setTimeout(() => {
airslice marked this conversation as resolved.
Show resolved Hide resolved
setOverrideAlignSystem(alignSystem => {
if (!alignSystem || !tarWidget) return alignSystem;
if (!alignSystem[options.zone]) {
alignSystem[options.zone] = {
left: undefined,
center: undefined,
right: undefined,
};
}

const tarZone = alignSystem[options.zone] as WidgetZone;
if (!tarZone[options.section]) {
tarZone[options.section] = {
top: undefined,
middle: undefined,
bottom: undefined,
};
}

const tarSection = tarZone[options.section] as WidgetSection;
if (!tarSection[options.area]) {
tarSection[options.area] = {
align: "start",
widgets: [],
};
}

const tarArea = tarSection[options.area] as WidgetArea;
if (!tarArea.widgets) tarArea.widgets = [];
if (options.method === "insert") {
tarArea.widgets.unshift(tarWidget);
} else {
tarArea.widgets.push(tarWidget);
}

return { ...alignSystem };
});
}, 0);
}, []);

useEffect(() => {
setOverrideAlignSystem(alignSystem);
}, [alignSystem]);

const providerProps: ProviderProps = useProviderProps(
{
engineName: engineType || "",
Expand All @@ -268,6 +369,7 @@ export default ({
selectLayer,
overrideLayerProperty,
overrideSceneProperty,
moveWidget,
},
engineRef,
layers,
Expand Down Expand Up @@ -315,6 +417,7 @@ export default ({
pluginPopupContainerRef,
shownPluginPopupInfo,
viewport,
overriddenAlignSystem,
onPluginModalShow,
onPluginPopupShow,
isLayerHidden,
Expand Down
4 changes: 3 additions & 1 deletion src/components/molecules/Visualizer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ export default function Visualizer({
shownPluginModalInfo,
pluginPopupContainerRef,
shownPluginPopupInfo,
overriddenAlignSystem,
viewport,
onPluginModalShow,
onPluginPopupShow,
Expand Down Expand Up @@ -155,6 +156,7 @@ export default function Visualizer({
clock: props.clock,
sceneProperty,
tags,
alignSystem: widgets?.alignSystem,
onLayerSelect,
onBlockSelect,
onBlockChange,
Expand All @@ -171,7 +173,7 @@ export default function Visualizer({
{isDroppable && <DropHolder />}
{ready && widgets?.alignSystem && (
<WidgetAlignSystem
alignSystem={widgets.alignSystem}
alignSystem={overriddenAlignSystem}
editing={widgetAlignEditorActivated}
onWidgetUpdate={onWidgetUpdate}
onWidgetAlignSystemUpdate={onWidgetAlignSystemUpdate}
Expand Down
1 change: 1 addition & 0 deletions src/components/molecules/Visualizer/storybook.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ export const context: ProviderProps = {
moveRight: act("moveRight"),
moveOverTerrain: act("moveOverTerrain"),
flyToGround: act("flyToGround"),
moveWidget: act("moveWidget"),
};

function act<T extends any[], M extends (...args: T) => any>(
Expand Down