Skip to content

Commit f8f187d

Browse files
committed
feat(): support segues
1 parent a0b2c1e commit f8f187d

File tree

3 files changed

+202
-1
lines changed

3 files changed

+202
-1
lines changed

packages/runtime/src/internal/Renderer.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,7 @@ async function legacyRenderBrick(
350350
dataSource: brickIf,
351351
// `permissionsPreCheck` maybe required before computing `if`.
352352
permissionsPreCheck,
353+
iid: brickConf.iid,
353354
slots: {
354355
"": {
355356
type: "bricks",

packages/runtime/src/internal/fulfilStoryboard.ts

Lines changed: 200 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
1-
import type { RuntimeStoryboard } from "@next-core/types";
1+
import type {
2+
BrickConf,
3+
BrickEventHandler,
4+
BrickEventsMap,
5+
BuiltinBrickEventHandler,
6+
RouteConf,
7+
RouteConfOfBricks,
8+
RuntimeStoryboard,
9+
} from "@next-core/types";
10+
import { isEvaluable } from "@next-core/cook";
11+
import { uniqueId } from "lodash";
212
import { hooks } from "./Runtime.js";
313
import { registerAppI18n } from "./registerAppI18n.js";
14+
import { isBuiltinHandler } from "./bindListeners.js";
415

516
export async function fulfilStoryboard(storyboard: RuntimeStoryboard) {
617
if (storyboard.$$fulfilled) {
@@ -15,8 +26,196 @@ export async function fulfilStoryboard(storyboard: RuntimeStoryboard) {
1526
async function doFulfilStoryboard(storyboard: RuntimeStoryboard) {
1627
await hooks?.fulfilStoryboard?.(storyboard);
1728
registerAppI18n(storyboard);
29+
initializeSeguesForRoutes(storyboard.routes);
1830
Object.assign(storyboard, {
1931
$$fulfilled: true,
2032
$$fulfilling: null,
2133
});
2234
}
35+
36+
interface SegueConf {
37+
by: "drawer" | "modal";
38+
route?: {
39+
path: string;
40+
params: SegueRouteParam[];
41+
};
42+
eventsMapping?: Record<string, string>;
43+
events?: BrickEventsMap;
44+
}
45+
46+
interface SegueRouteParam {
47+
key: string;
48+
value: string;
49+
}
50+
51+
function initializeSeguesForRoutes(routes: RouteConf[]) {
52+
for (const route of routes) {
53+
if (route.type !== "redirect" && route.type !== "routes") {
54+
initializeSeguesForBricks(route.bricks, route);
55+
}
56+
}
57+
}
58+
59+
function initializeSeguesForBricks(
60+
bricks: BrickConf[],
61+
routeParent: RouteConfOfBricks
62+
) {
63+
for (const brick of bricks) {
64+
if (brick.events) {
65+
for (const [eventType, handlers] of Object.entries(brick.events)) {
66+
if (Array.isArray(handlers)) {
67+
handlers.forEach((handler, index) => {
68+
if (isBuiltinHandler(handler) && handler.action === "segue.go") {
69+
replaceSegues(handler, handlers, index, routeParent);
70+
}
71+
});
72+
} else if (
73+
isBuiltinHandler(handlers) &&
74+
handlers.action === "segue.go"
75+
) {
76+
replaceSegues(handlers, brick.events, eventType, routeParent);
77+
}
78+
}
79+
}
80+
81+
if (brick.slots) {
82+
for (const slotConf of Object.values(brick.slots)) {
83+
if (slotConf.type === "routes") {
84+
initializeSeguesForRoutes(slotConf.routes);
85+
} else {
86+
initializeSeguesForBricks(slotConf.bricks, routeParent);
87+
}
88+
}
89+
} else if (Array.isArray(brick.children)) {
90+
initializeSeguesForBricks(brick.children, routeParent);
91+
}
92+
}
93+
}
94+
95+
function replaceSegues(
96+
handler: BuiltinBrickEventHandler,
97+
handlers: BrickEventsMap | BrickEventHandler[],
98+
key: string | number,
99+
routeParent: RouteConfOfBricks
100+
) {
101+
let segueConf: SegueConf | undefined;
102+
let segueTarget: string | undefined;
103+
if (
104+
Array.isArray(handler.args) &&
105+
((segueTarget = handler.args[0] as string),
106+
typeof segueTarget === "string") &&
107+
(segueConf = handler.args[1] as SegueConf)
108+
) {
109+
switch (segueConf.by) {
110+
case "drawer": {
111+
if (segueConf.route) {
112+
const { params, path } = segueConf.route;
113+
const targetUrlExpr = path.replace(/:(\w+)/g, (_, key) => {
114+
const param = params.find((param) => param.key === key);
115+
return param
116+
? typeof param.value === "string" && isEvaluable(param.value)
117+
? `\${${param.value.replace(/^\s*<%[~=]?\s|\s%>\s*$/g, "")}}`
118+
: String(param.value).replace(/`/g, "\\`")
119+
: `\${PATH.${key}}`;
120+
});
121+
(handlers as BrickEventsMap)[key] = {
122+
action: "history.push",
123+
args: [`<% \`${targetUrlExpr}\` %>`],
124+
};
125+
const drawerId = uniqueId("internal-segue-drawer-");
126+
const drawerTarget = `#${drawerId}`;
127+
routeParent.bricks.push({
128+
brick: "eo-drawer",
129+
portal: true,
130+
properties: {
131+
id: drawerId,
132+
customTitle: "Detail",
133+
},
134+
events: {
135+
close: {
136+
action: "history.push",
137+
args: [
138+
`<% \`${routeParent.path.replace(/:(\w)+/g, "${PATH.$1}")}\` %>`,
139+
],
140+
},
141+
},
142+
slots: {
143+
"": {
144+
type: "routes",
145+
routes: [
146+
{
147+
path,
148+
exact: true,
149+
bricks: [
150+
{
151+
brick: segueTarget,
152+
properties: Object.fromEntries(
153+
params.map((param) => [
154+
param.key,
155+
`<% PATH.${param.key} %>`,
156+
])
157+
),
158+
lifeCycle: {
159+
onMount: {
160+
target: drawerTarget,
161+
method: "open",
162+
},
163+
onUnmount: {
164+
target: drawerTarget,
165+
method: "close",
166+
},
167+
},
168+
},
169+
],
170+
},
171+
],
172+
},
173+
},
174+
});
175+
}
176+
break;
177+
}
178+
179+
case "modal": {
180+
const modalId = uniqueId("internal-segue-modal-");
181+
const modalTarget = `#${modalId}`;
182+
const sceneId = uniqueId("internal-segue-scene-");
183+
const sceneTarget = `#${sceneId}`;
184+
(handlers as BrickEventsMap)[key] = {
185+
target: modalTarget,
186+
method: "open",
187+
};
188+
routeParent.bricks.push({
189+
brick: "eo-modal",
190+
portal: true,
191+
properties: {
192+
id: modalId,
193+
modalTitle: "Create",
194+
closeWhenConfirm: false,
195+
},
196+
events: segueConf.eventsMapping
197+
? Object.fromEntries(
198+
Object.entries(segueConf.eventsMapping).map(([from, to]) => [
199+
from,
200+
{
201+
target: sceneTarget,
202+
method: to,
203+
},
204+
])
205+
)
206+
: undefined,
207+
children: [
208+
{
209+
brick: segueTarget,
210+
properties: {
211+
id: sceneId,
212+
},
213+
events: segueConf.events,
214+
},
215+
],
216+
});
217+
break;
218+
}
219+
}
220+
}
221+
}

packages/types/src/manifest.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -926,6 +926,7 @@ export interface BuiltinBrickEventHandler {
926926
| "history.unblock"
927927

928928
// Segues
929+
| "segue.go"
929930
// | "segue.push"
930931
// | "segue.replace"
931932

0 commit comments

Comments
 (0)