openxiangda 1.0.1 → 1.0.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.
@@ -30,6 +30,7 @@ const runtimeDistDir = path.join(rootDir, "dist/form-runtime");
30
30
  const tmpDir = path.join(rootDir, ".tmp");
31
31
  const runtimeVersionPlaceholder = "__SY_FORM_RUNTIME_VERSION__";
32
32
  const runtimeCacheFileName = "build-cache.json";
33
+ const portalContainerResolverGlobal = "__OPENXIANGDA_GET_PORTAL_CONTAINER__";
33
34
 
34
35
  const runtimePackages = [
35
36
  "react",
@@ -164,7 +165,6 @@ function parseArgs(argv) {
164
165
  }
165
166
  if (arg === "--force") {
166
167
  result.force = true;
167
- result.runtimeCache = false;
168
168
  continue;
169
169
  }
170
170
  if (arg === "--dry-run") {
@@ -196,7 +196,7 @@ build-forms - 构建表单页面
196
196
  选项:
197
197
  --form <name> 只构建指定表单(src/forms/ 下的目录名)
198
198
  --only <list> 只构建指定模块,如 forms/customer,pages/dashboard
199
- --force 忽略增量缓存,强制重建
199
+ --force 忽略增量缓存,强制重建表单产物
200
200
  --dry-run 只打印增量计划,不构建
201
201
  --clean-cache 删除 .openxiangda/build-cache.json
202
202
  --no-runtime-cache 强制重建共享 runtime
@@ -242,7 +242,11 @@ import '../src/index.css';
242
242
 
243
243
  const runtimeVersion = '${runtimeVersionPlaceholder}';
244
244
  const roots = new WeakMap();
245
+ const portalContainerCleanups = new WeakMap();
245
246
  const { StandardFormPage, defineFormSchema } = SyFormComponentsModule;
247
+ const NAMESPACE_ROOT_CLASS = 'sy-app-workspace';
248
+ const PORTAL_CONTAINER_STACK_GLOBAL = '__OPENXIANGDA_PORTAL_CONTAINER_STACK__';
249
+ const PORTAL_CONTAINER_RESOLVER_GLOBAL = '${portalContainerResolverGlobal}';
246
250
 
247
251
  function getStyleContainer(el) {
248
252
  const rootNode = el.getRootNode?.();
@@ -251,58 +255,115 @@ function getStyleContainer(el) {
251
255
  : document.head;
252
256
  }
253
257
 
254
- function getNamespaceRoot(el) {
255
- return el.closest?.('.sy-app-workspace') || el;
256
- }
257
-
258
258
  function isInShadowRoot(el) {
259
259
  const rootNode = el.getRootNode?.();
260
260
  return typeof ShadowRoot !== 'undefined' && rootNode instanceof ShadowRoot;
261
261
  }
262
262
 
263
+ function getNamespaceRoot(el, triggerNode) {
264
+ if (isInShadowRoot(el)) return el;
265
+ const triggerRoot = triggerNode?.closest?.('.' + NAMESPACE_ROOT_CLASS);
266
+ return (
267
+ triggerRoot ||
268
+ el.closest?.('.' + NAMESPACE_ROOT_CLASS) ||
269
+ el.querySelector?.('.' + NAMESPACE_ROOT_CLASS) ||
270
+ el
271
+ );
272
+ }
273
+
263
274
  function getPopupContainer(el) {
264
- const inShadowRoot = isInShadowRoot(el);
265
- return (triggerNode) => {
266
- if (inShadowRoot) return el;
267
- return getNamespaceRoot(el) || triggerNode?.parentElement || document.body;
268
- };
275
+ return (triggerNode) => getNamespaceRoot(el, triggerNode);
269
276
  }
270
277
 
271
278
  function getTargetContainer(el) {
272
- return () => (isInShadowRoot(el) ? el : getNamespaceRoot(el) || document.body);
279
+ return () => getNamespaceRoot(el);
280
+ }
281
+
282
+ function createAntdConfig(el) {
283
+ return {
284
+ locale: zhCN,
285
+ prefixCls: 'sy-ant',
286
+ iconPrefixCls: 'sy-anticon',
287
+ theme: antdTheme,
288
+ getPopupContainer: getPopupContainer(el),
289
+ getTargetContainer: getTargetContainer(el),
290
+ };
291
+ }
292
+
293
+ function installRuntimePortalContainer(el) {
294
+ const stack = Array.isArray(globalThis[PORTAL_CONTAINER_STACK_GLOBAL])
295
+ ? globalThis[PORTAL_CONTAINER_STACK_GLOBAL]
296
+ : [];
297
+ stack.push(el);
298
+ globalThis[PORTAL_CONTAINER_STACK_GLOBAL] = stack;
299
+ globalThis[PORTAL_CONTAINER_RESOLVER_GLOBAL] = () => {
300
+ for (let index = stack.length - 1; index >= 0; index -= 1) {
301
+ const candidate = stack[index];
302
+ if (candidate?.isConnected) {
303
+ return getNamespaceRoot(candidate);
304
+ }
305
+ }
306
+ return document.querySelector('.' + NAMESPACE_ROOT_CLASS) || document.body;
307
+ };
308
+ return () => {
309
+ const position = stack.lastIndexOf(el);
310
+ if (position >= 0) stack.splice(position, 1);
311
+ };
312
+ }
313
+
314
+ function installAntdStaticHolder(el) {
315
+ ConfigProvider.config({
316
+ prefixCls: 'sy-ant',
317
+ iconPrefixCls: 'sy-anticon',
318
+ theme: antdTheme,
319
+ holderRender: (children) => {
320
+ if (!el.isConnected) {
321
+ return (
322
+ <ConfigProvider prefixCls="sy-ant" iconPrefixCls="sy-anticon" theme={antdTheme}>
323
+ {children}
324
+ </ConfigProvider>
325
+ );
326
+ }
327
+ return (
328
+ <StyleProvider hashPriority="high" container={getStyleContainer(el)}>
329
+ <ConfigProvider {...createAntdConfig(el)}>{children}</ConfigProvider>
330
+ </StyleProvider>
331
+ );
332
+ },
333
+ });
273
334
  }
274
335
 
275
336
  function renderStandardForm(el, schemaInput, context = {}) {
276
337
  let root = roots.get(el);
338
+ el.classList.add(NAMESPACE_ROOT_CLASS);
339
+ if (!portalContainerCleanups.has(el)) {
340
+ portalContainerCleanups.set(el, installRuntimePortalContainer(el));
341
+ }
342
+ installAntdStaticHolder(el);
277
343
  if (!root) {
278
- if (!isInShadowRoot(el)) el.classList.add('sy-app-workspace');
279
344
  root = createRoot(el);
280
345
  roots.set(el, root);
281
346
  }
282
347
 
283
348
  const schema = defineFormSchema(schemaInput);
349
+ const antdConfig = createAntdConfig(el);
284
350
  root.render(
285
351
  <StyleProvider hashPriority="high" container={getStyleContainer(el)}>
286
- <ConfigProvider
287
- locale={zhCN}
288
- prefixCls="sy-ant"
289
- iconPrefixCls="sy-anticon"
290
- theme={antdTheme}
291
- getPopupContainer={getPopupContainer(el)}
292
- getTargetContainer={getTargetContainer(el)}
293
- >
352
+ <ConfigProvider {...antdConfig}>
294
353
  <AntdApp>
295
- <StandardFormPage
296
- schema={schema}
297
- mode={context.mode || 'submit'}
298
- initialValues={context.initialValues}
299
- permissions={context.permissions}
300
- formUuid={context.formUuid}
301
- appType={context.appType}
302
- formInstanceId={context.formInstanceId}
303
- onSubmit={context.onSubmit}
304
- inDrawer={context.inDrawer}
305
- />
354
+ <div className="sy-app-workspace">
355
+ <StandardFormPage
356
+ schema={schema}
357
+ mode={context.mode || 'submit'}
358
+ initialValues={context.initialValues}
359
+ permissions={context.permissions}
360
+ formUuid={context.formUuid}
361
+ appType={context.appType}
362
+ formInstanceId={context.formInstanceId}
363
+ onSubmit={context.onSubmit}
364
+ inDrawer={context.inDrawer}
365
+ />
366
+ </div>
306
367
  </AntdApp>
307
368
  </ConfigProvider>
308
369
  </StyleProvider>
@@ -315,6 +376,11 @@ function unmountStandardForm(el) {
315
376
  root.unmount();
316
377
  roots.delete(el);
317
378
  }
379
+ const releasePortalContainer = portalContainerCleanups.get(el);
380
+ if (releasePortalContainer) {
381
+ releasePortalContainer();
382
+ portalContainerCleanups.delete(el);
383
+ }
318
384
  }
319
385
 
320
386
  export function createStandardFormModule(schemaInput) {
@@ -356,6 +422,24 @@ export default formRuntime;
356
422
  `;
357
423
  }
358
424
 
425
+ function createAntdMobilePortalPatchPlugin() {
426
+ const resolverExpression = `globalThis.${portalContainerResolverGlobal}?.() || document.body`;
427
+ return {
428
+ name: "openxiangda-antd-mobile-portal-container",
429
+ transform(code, id) {
430
+ if (!id.includes("/antd-mobile/") && !id.includes("\\\\antd-mobile\\\\")) {
431
+ return null;
432
+ }
433
+ const nextCode = code.replace(
434
+ /getContainer:\s*\(\)\s*=>\s*document\.body/g,
435
+ `getContainer: () => ${resolverExpression}`,
436
+ );
437
+ if (nextCode === code) return null;
438
+ return { code: nextCode, map: null };
439
+ },
440
+ };
441
+ }
442
+
359
443
  function createFormRuntimeProxyPlugin() {
360
444
  return {
361
445
  name: "sy-form-runtime-proxy",
@@ -547,7 +631,7 @@ async function buildSharedRuntime(options = {}) {
547
631
  },
548
632
  },
549
633
  },
550
- plugins: [reactPlugin],
634
+ plugins: [createAntdMobilePortalPatchPlugin(), reactPlugin],
551
635
  logLevel: "warn",
552
636
  });
553
637
 
@@ -689,7 +773,11 @@ async function buildForm(form) {
689
773
  },
690
774
  },
691
775
  },
692
- plugins: [createFormRuntimeProxyPlugin(), reactPlugin].filter(Boolean),
776
+ plugins: [
777
+ createAntdMobilePortalPatchPlugin(),
778
+ createFormRuntimeProxyPlugin(),
779
+ reactPlugin,
780
+ ].filter(Boolean),
693
781
  logLevel: "warn",
694
782
  });
695
783
 
@@ -34,12 +34,14 @@ const tmpDir = path.join(rootDir, ".tmp");
34
34
  const runtimeDistDir = path.join(distRoot, "page-runtime");
35
35
  const runtimeVersionPlaceholder = "__SY_PAGE_RUNTIME_VERSION__";
36
36
  const runtimeCacheFileName = "build-cache.json";
37
+ const portalContainerResolverGlobal = "__OPENXIANGDA_GET_PORTAL_CONTAINER__";
37
38
 
38
39
  const runtimePackages = [
39
40
  "react",
40
41
  "react-dom",
41
42
  "@ant-design/cssinjs",
42
43
  "antd",
44
+ "antd-mobile",
43
45
  "@ant-design/icons",
44
46
  "openxiangda",
45
47
  ];
@@ -163,7 +165,6 @@ function parseArgs(argv) {
163
165
  }
164
166
  if (arg === "--force") {
165
167
  result.force = true;
166
- result.runtimeCache = false;
167
168
  continue;
168
169
  }
169
170
  if (arg === "--dry-run") {
@@ -194,7 +195,7 @@ build-pages - 构建复杂代码页
194
195
  选项:
195
196
  --page <name> 只构建指定页面目录
196
197
  --only <list> 只构建指定模块,如 forms/customer,pages/dashboard
197
- --force 忽略增量缓存,强制重建
198
+ --force 忽略增量缓存,强制重建页面产物
198
199
  --dry-run 只打印增量计划,不构建
199
200
  --clean-cache 删除 .openxiangda/build-cache.json
200
201
  --no-runtime-cache 强制重建共享 runtime
@@ -339,6 +340,24 @@ async function createCssOptions() {
339
340
  };
340
341
  }
341
342
 
343
+ function createAntdMobilePortalPatchPlugin() {
344
+ const resolverExpression = `globalThis.${portalContainerResolverGlobal}?.() || document.body`;
345
+ return {
346
+ name: "openxiangda-antd-mobile-portal-container",
347
+ transform(code, id) {
348
+ if (!id.includes("/antd-mobile/") && !id.includes("\\\\antd-mobile\\\\")) {
349
+ return null;
350
+ }
351
+ const nextCode = code.replace(
352
+ /getContainer:\s*\(\)\s*=>\s*document\.body/g,
353
+ `getContainer: () => ${resolverExpression}`,
354
+ );
355
+ if (nextCode === code) return null;
356
+ return { code: nextCode, map: null };
357
+ },
358
+ };
359
+ }
360
+
342
361
  function createResolveAlias() {
343
362
  return [
344
363
  {
@@ -373,7 +392,7 @@ async function buildSharedRuntime(options = {}) {
373
392
  "process.env.NODE_ENV": JSON.stringify("production"),
374
393
  "process.env": JSON.stringify({ NODE_ENV: "production" }),
375
394
  },
376
- plugins: [react()],
395
+ plugins: [createAntdMobilePortalPatchPlugin(), react()],
377
396
  resolve: {
378
397
  alias: createResolveAlias(),
379
398
  dedupe: ["react", "react-dom", "antd", "@ant-design/cssinjs"],
@@ -655,7 +674,11 @@ async function buildPage(page) {
655
674
  "process.env.NODE_ENV": JSON.stringify("production"),
656
675
  "process.env": JSON.stringify({ NODE_ENV: "production" }),
657
676
  },
658
- plugins: [createSharedRuntimeProxyPlugin(), react()],
677
+ plugins: [
678
+ createAntdMobilePortalPatchPlugin(),
679
+ createSharedRuntimeProxyPlugin(),
680
+ react(),
681
+ ],
659
682
  resolve: {
660
683
  alias: createResolveAlias(),
661
684
  dedupe: ["react", "react-dom", "antd", "@ant-design/cssinjs"],