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

Commit

Permalink
feat: extend plugin API supports move widget (#346)
Browse files Browse the repository at this point in the history
* feat: add plugin api set widget position

* refactor: add missing set state

* refactor: set state

* refactor: async insert

* refactor: clean up

* refactor: type definition & naming

* refactor: separate hooks

* refactor: clean up & renaming
  • Loading branch information
airslice authored Nov 28, 2022
1 parent 846a6e2 commit c828254
Show file tree
Hide file tree
Showing 8 changed files with 139 additions and 2 deletions.
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
10 changes: 10 additions & 0 deletions src/components/molecules/Visualizer/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ import type {
LookAtDestination,
Tag,
} from "./Plugin/types";
import useWidgetAlignSystem from "./useWidgetAlignSystem";
import { useOverriddenProperty } from "./utils";
import type { WidgetAlignSystem } from "./WidgetAlignSystem";

export type Viewport = {
width: number;
Expand All @@ -50,6 +52,7 @@ export default ({
clock,
sceneProperty,
tags,
alignSystem,
onLayerSelect,
onBlockSelect,
onBlockChange,
Expand All @@ -72,6 +75,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 +253,10 @@ export default ({
pageview(window.location.pathname);
}, [isPublished, enableGA, trackingId]);

const { overriddenAlignSystem, moveWidget } = useWidgetAlignSystem({
alignSystem,
});

const providerProps: ProviderProps = useProviderProps(
{
engineName: engineType || "",
Expand All @@ -268,6 +276,7 @@ export default ({
selectLayer,
overrideLayerProperty,
overrideSceneProperty,
moveWidget,
},
engineRef,
layers,
Expand Down Expand Up @@ -315,6 +324,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
101 changes: 101 additions & 0 deletions src/components/molecules/Visualizer/useWidgetAlignSystem.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import { useEffect, useState, useCallback } from "react";

import type { WidgetLocationOptions } from "./Plugin/types";
import type {
Widget,
WidgetAlignSystem,
WidgetSection,
WidgetZone,
WidgetArea,
} from "./WidgetAlignSystem";

export default ({ alignSystem }: { alignSystem: WidgetAlignSystem | undefined }) => {
const [overriddenAlignSystem, setOverrideAlignSystem] = useState<WidgetAlignSystem | undefined>(
alignSystem,
);

const moveWidget = useCallback((widgetId: string, options: WidgetLocationOptions) => {
if (
!["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 widget: 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 (!widget && area?.widgets) {
const sourceIndex = area.widgets.findIndex(w => w.id === widgetId);
if (sourceIndex !== -1) {
[widget] = area.widgets.splice(sourceIndex, 1);
}
}
});
}
});
}
});
return { ...alignSystem };
});

setTimeout(() => {
setOverrideAlignSystem(alignSystem => {
if (!alignSystem || !widget) return alignSystem;
if (!alignSystem[options.zone]) {
alignSystem[options.zone] = {
left: undefined,
center: undefined,
right: undefined,
};
}

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

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

const targetArea = targetSection[options.area] as WidgetArea;
if (!targetArea.widgets) targetArea.widgets = [];
if (options.method === "insert") {
targetArea.widgets.unshift(widget);
} else {
targetArea.widgets.push(widget);
}

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

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

return {
overriddenAlignSystem,
moveWidget,
};
};

0 comments on commit c828254

Please sign in to comment.