@realnation/builder-shared-sdk 2.4.2 → 2.5.1

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.
@@ -11,7 +11,7 @@
11
11
  export * from './types.js';
12
12
  export * from './imageFit.js';
13
13
  export { wrapText, tokenize, layoutLines, type MeasureText, type TextAlign, type TextVAlign, type PlacedLine, } from './text.js';
14
- export { renderSouvenir, drawOrder, pageHasOpaqueBackground, souvenirSignature, loadSouvenirImage, } from './render.js';
14
+ export { renderSouvenir, drawOrder, outputSize, regionOf, pageHasOpaqueBackground, souvenirSignature, loadSouvenirImage, } from './render.js';
15
15
  import { type SouvenirOptions, type SouvenirPage, type SouvenirResult, type SouvenirValues } from './types.js';
16
16
  export { parseSouvenirOutputId } from './outputId.js';
17
17
  /**
@@ -37,5 +37,5 @@ export declare function composeSouvenir(page: SouvenirPage, values?: SouvenirVal
37
37
  * Anything else uploaded in the same submission must use a different tag, or
38
38
  * it will be handed back the first file.
39
39
  */
40
- export declare function souvenirTag(page: SouvenirPage, values?: SouvenirValues): string;
40
+ export declare function souvenirTag(page: SouvenirPage, values?: SouvenirValues, options?: SouvenirOptions): string;
41
41
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/souvenir/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,WAAW,EACX,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,UAAU,GAChB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,cAAc,EACd,SAAS,EACT,uBAAuB,EACvB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,aAAa,CAAC;AAGrB,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,cAAc,EACpB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAEtD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,YAAY,EAClB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,EACtD,MAAM,CAAC,EAAE,MAAM,GACd,cAAc,CAUhB;AAYD;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,YAAY,EAClB,MAAM,GAAE,cAAmB,EAC3B,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,cAAc,CAAC,CAqBzB;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,GAAE,cAAmB,GAAG,MAAM,CAEnF"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/souvenir/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,WAAW,EACX,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,UAAU,GAChB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,cAAc,EACd,SAAS,EACT,UAAU,EACV,QAAQ,EACR,uBAAuB,EACvB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,aAAa,CAAC;AAGrB,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,cAAc,EACpB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAEtD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,YAAY,EAClB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,EACtD,MAAM,CAAC,EAAE,MAAM,GACd,cAAc,CAUhB;AAYD;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,YAAY,EAClB,MAAM,GAAE,cAAmB,EAC3B,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,cAAc,CAAC,CAqBzB;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,GAAE,cAAmB,EAAE,OAAO,GAAE,eAAoB,GAAG,MAAM,CAElH"}
@@ -11,7 +11,7 @@
11
11
  export * from './types.js';
12
12
  export * from './imageFit.js';
13
13
  export { wrapText, tokenize, layoutLines, } from './text.js';
14
- export { renderSouvenir, drawOrder, pageHasOpaqueBackground, souvenirSignature, loadSouvenirImage, } from './render.js';
14
+ export { renderSouvenir, drawOrder, outputSize, regionOf, pageHasOpaqueBackground, souvenirSignature, loadSouvenirImage, } from './render.js';
15
15
  import { pageHasOpaqueBackground, renderSouvenir, souvenirSignature } from './render.js';
16
16
  import { SouvenirError, } from './types.js';
17
17
  import { parseSouvenirOutputId } from './outputId.js';
@@ -52,7 +52,7 @@ export async function composeSouvenir(page, values = {}, options = {}) {
52
52
  const canvas = await renderSouvenir(page, values, options);
53
53
  const format = options.format && options.format !== 'auto'
54
54
  ? options.format
55
- : pageHasOpaqueBackground(page)
55
+ : pageHasOpaqueBackground(page, options.region)
56
56
  ? 'jpeg'
57
57
  : 'png';
58
58
  const quality = typeof options.quality === 'number' ? options.quality : 0.9;
@@ -63,7 +63,7 @@ export async function composeSouvenir(page, values = {}, options = {}) {
63
63
  return {
64
64
  file,
65
65
  canvas,
66
- tag: souvenirTag(page, values),
66
+ tag: souvenirTag(page, values, options),
67
67
  width: canvas.width,
68
68
  height: canvas.height,
69
69
  format,
@@ -77,6 +77,6 @@ export async function composeSouvenir(page, values = {}, options = {}) {
77
77
  * Anything else uploaded in the same submission must use a different tag, or
78
78
  * it will be handed back the first file.
79
79
  */
80
- export function souvenirTag(page, values = {}) {
81
- return `souvenir-${souvenirSignature(page, values)}`;
80
+ export function souvenirTag(page, values = {}, options = {}) {
81
+ return `souvenir-${souvenirSignature(page, values, options)}`;
82
82
  }
@@ -9,7 +9,7 @@
9
9
  * mirrors the runner's `elementStyle`, which is what the operator sees in the
10
10
  * editor and the preview.
11
11
  */
12
- import { type SouvenirOptions, type SouvenirPage, type SouvenirProperty, type SouvenirValues } from './types.js';
12
+ import { type SouvenirOptions, type SouvenirPage, type SouvenirProperty, type SouvenirRegion, type SouvenirValues } from './types.js';
13
13
  /**
14
14
  * An element bound to a Data field whose field has no value is left out, the
15
15
  * way the runner hides it on a live page. Falling back to what the Builder
@@ -30,15 +30,25 @@ export declare function loadSouvenirImage(url: string, crossOrigin: string | nul
30
30
  width: number;
31
31
  height: number;
32
32
  }>;
33
+ /**
34
+ * 整页时用它,给了区域时按区域算。区域外的元件照常留在页面上,由 runner 画。
35
+ */
36
+ export declare function regionOf(page: SouvenirPage, region?: SouvenirRegion): SouvenirRegion;
37
+ /** 出图尺寸:形状跟着区域,长边取 longEdge;不给 longEdge 就按区域原尺寸。 */
38
+ export declare function outputSize(region: SouvenirRegion, longEdge?: number): {
39
+ width: number;
40
+ height: number;
41
+ scale: number;
42
+ };
33
43
  /** Element ids in draw order: z-index ascending, insertion order for ties. */
34
- export declare function drawOrder(page: SouvenirPage): string[];
44
+ export declare function drawOrder(page: SouvenirPage, region?: SouvenirRegion): string[];
35
45
  /**
36
46
  * True when every pixel is guaranteed opaque, i.e. a `bg` element covers the
37
47
  * page with a colour or an image. Decides JPEG versus PNG in `auto`.
38
48
  */
39
- export declare function pageHasOpaqueBackground(page: SouvenirPage): boolean;
40
- /** A stable signature for (page, values): same inputs, same tag, same upload. */
41
- export declare function souvenirSignature(page: SouvenirPage, values: SouvenirValues): string;
49
+ export declare function pageHasOpaqueBackground(page: SouvenirPage, region?: SouvenirRegion): boolean;
50
+ /** A stable signature for (page, values, region, size): same inputs, same tag, same upload. */
51
+ export declare function souvenirSignature(page: SouvenirPage, values: SouvenirValues, options?: SouvenirOptions): string;
42
52
  /**
43
53
  * Draws the page and returns the canvas.
44
54
  *
@@ -1 +1 @@
1
- {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/souvenir/render.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,EAIL,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EAEpB,MAAM,YAAY,CAAC;AA6CpB;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,GAAG,OAAO,CAI7E;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAO5F;AAyPD,gFAAgF;AAChF,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,MAAM,EACX,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACrC,OAAO,CAAC,iBAAiB,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAoBhE;AAED,8EAA8E;AAC9E,wBAAgB,SAAS,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,EAAE,CAStD;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAYnE;AAED,iFAAiF;AACjF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,cAAc,GAAG,MAAM,CAMpF;AAED;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,YAAY,EAClB,MAAM,GAAE,cAAmB,EAC3B,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,iBAAiB,CAAC,CAsE5B"}
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/souvenir/render.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,EAKL,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,cAAc,EAEpB,MAAM,YAAY,CAAC;AA6CpB;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,GAAG,OAAO,CAI7E;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAO5F;AAyPD,gFAAgF;AAChF,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,MAAM,EACX,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACrC,OAAO,CAAC,iBAAiB,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAoBhE;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,CAAC,EAAE,cAAc,GAAG,cAAc,CAEpF;AAED,oDAAoD;AACpD,wBAAgB,UAAU,CAAC,MAAM,EAAE,cAAc,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAStH;AAED,8EAA8E;AAC9E,wBAAgB,SAAS,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,CAAC,EAAE,cAAc,GAAG,MAAM,EAAE,CAa/E;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,CAAC,EAAE,cAAc,GAAG,OAAO,CAc5F;AAED,+FAA+F;AAC/F,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,GAAE,eAAoB,GAAG,MAAM,CAQnH;AAED;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,YAAY,EAClB,MAAM,GAAE,cAAmB,EAC3B,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,iBAAiB,CAAC,CA2E5B"}
@@ -12,7 +12,7 @@
12
12
  import { computeImageFitDrawRect, hashSignature, normalizeImageFit } from './imageFit.js';
13
13
  import { parseSouvenirOutputId } from './outputId.js';
14
14
  import { layoutLines, wrapText } from './text.js';
15
- import { isSouvenirInteractive, isSouvenirSizeAllowed, SouvenirError, SOUVENIR_ELEMENT_TYPES, } from './types.js';
15
+ import { isInsideRegion, isSouvenirInteractive, isSouvenirSizeAllowed, SouvenirError, SOUVENIR_ELEMENT_TYPES, } from './types.js';
16
16
  const DEFAULT_LINE_HEIGHT = 1.2;
17
17
  const TRANSPARENT = 'TRANSPARENT';
18
18
  const num = (value, fallback = 0) => {
@@ -281,13 +281,34 @@ export async function loadSouvenirImage(url, crossOrigin) {
281
281
  image.src = url;
282
282
  });
283
283
  }
284
+ /**
285
+ * 整页时用它,给了区域时按区域算。区域外的元件照常留在页面上,由 runner 画。
286
+ */
287
+ export function regionOf(page, region) {
288
+ return region ?? { x: 0, y: 0, width: num(page.width), height: num(page.height) };
289
+ }
290
+ /** 出图尺寸:形状跟着区域,长边取 longEdge;不给 longEdge 就按区域原尺寸。 */
291
+ export function outputSize(region, longEdge) {
292
+ const edge = Number.isFinite(longEdge) && longEdge > 0 ? longEdge : 0;
293
+ const longest = Math.max(region.width, region.height);
294
+ const scale = edge > 0 && longest > 0 ? edge / longest : 1;
295
+ return {
296
+ width: Math.max(1, Math.round(region.width * scale)),
297
+ height: Math.max(1, Math.round(region.height * scale)),
298
+ scale,
299
+ };
300
+ }
284
301
  /** Element ids in draw order: z-index ascending, insertion order for ties. */
285
- export function drawOrder(page) {
302
+ export function drawOrder(page, region) {
303
+ const box = region;
286
304
  return Object.keys(page.elements ?? {})
287
305
  .filter((eid) => SOUVENIR_ELEMENT_TYPES.includes(page.elements[eid]?.type))
288
306
  .filter((eid) => !isHidden(page.properties?.[eid] ?? {}))
289
307
  // Controls stay on screen over the picture, so they are not in it
290
308
  .filter((eid) => !isSouvenirInteractive(page.elements[eid]?.type, page.properties?.[eid] ?? {}))
309
+ // 框外的元件是页面的一部分,不进图。背景是整页的底,框在哪一块都画在它上面,
310
+ // 所以不按中心点判(背景的中心是画布中心,框摆到一边就会把底丢掉,出图透明一片)
311
+ .filter((eid) => !box || page.elements[eid]?.type === 'bg' || isInsideRegion(page.properties?.[eid] ?? {}, box))
291
312
  .map((eid, index) => ({ eid, index, z: num((page.properties?.[eid] ?? {})['zIndex']) }))
292
313
  .sort((a, b) => (a.z === b.z ? a.index - b.index : a.z - b.z))
293
314
  .map((entry) => entry.eid);
@@ -296,7 +317,8 @@ export function drawOrder(page) {
296
317
  * True when every pixel is guaranteed opaque, i.e. a `bg` element covers the
297
318
  * page with a colour or an image. Decides JPEG versus PNG in `auto`.
298
319
  */
299
- export function pageHasOpaqueBackground(page) {
320
+ export function pageHasOpaqueBackground(page, region) {
321
+ const box = regionOf(page, region);
300
322
  for (const eid of Object.keys(page.elements ?? {})) {
301
323
  if (page.elements[eid]?.type !== 'bg')
302
324
  continue;
@@ -304,7 +326,7 @@ export function pageHasOpaqueBackground(page) {
304
326
  if (isHidden(property))
305
327
  continue;
306
328
  const geo = geometryOf(property);
307
- const covers = geo.x <= 0 && geo.y <= 0 && geo.width >= page.width && geo.height >= page.height;
329
+ const covers = geo.x <= box.x && geo.y <= box.y && geo.x + geo.width >= box.x + box.width && geo.y + geo.height >= box.y + box.height;
308
330
  if (!covers)
309
331
  continue;
310
332
  if (geo.opacity < 100 || geo.radius > 0 || geo.rotation)
@@ -314,10 +336,12 @@ export function pageHasOpaqueBackground(page) {
314
336
  }
315
337
  return false;
316
338
  }
317
- /** A stable signature for (page, values): same inputs, same tag, same upload. */
318
- export function souvenirSignature(page, values) {
319
- const parts = [`${page.width}x${page.height}`];
320
- for (const eid of drawOrder(page)) {
339
+ /** A stable signature for (page, values, region, size): same inputs, same tag, same upload. */
340
+ export function souvenirSignature(page, values, options = {}) {
341
+ const box = regionOf(page, options.region);
342
+ const size = outputSize(box, options.longEdge);
343
+ const parts = [`${box.x},${box.y},${box.width}x${box.height}`, `${size.width}x${size.height}`];
344
+ for (const eid of drawOrder(page, options.region)) {
321
345
  parts.push(eid, page.elements[eid]?.type ?? '', JSON.stringify(page.properties?.[eid] ?? {}), String(values[eid] ?? ''));
322
346
  }
323
347
  return hashSignature(parts.join('|'));
@@ -333,12 +357,14 @@ export async function renderSouvenir(page, values = {}, options = {}) {
333
357
  if (typeof document === 'undefined') {
334
358
  throw new SouvenirError('no_dom', 'The souvenir composer needs a browser document.');
335
359
  }
336
- const width = Math.round(num(page.width));
337
- const height = Math.round(num(page.height));
360
+ const box = regionOf(page, options.region);
361
+ const size = outputSize(box, options.longEdge);
362
+ const width = size.width;
363
+ const height = size.height;
338
364
  if (!isSouvenirSizeAllowed(width, height)) {
339
- throw new SouvenirError(width < 1 || height < 1 ? 'bad_size' : 'too_large', `Souvenir page size ${width}x${height} is out of range.`);
365
+ throw new SouvenirError(width < 1 || height < 1 ? 'bad_size' : 'too_large', `Souvenir image size ${width}x${height} is out of range.`);
340
366
  }
341
- const order = drawOrder(page);
367
+ const order = drawOrder(page, options.region);
342
368
  // Webfonts first: measuring before they land silently lays the text out in
343
369
  // the fallback font and the first souvenir of an event comes out wrong.
344
370
  if (!options.skipFontWait && typeof document !== 'undefined' && document.fonts?.ready) {
@@ -368,6 +394,9 @@ export async function renderSouvenir(page, values = {}, options = {}) {
368
394
  const ctx = canvas.getContext('2d');
369
395
  if (!ctx)
370
396
  throw new SouvenirError('canvas_unavailable', 'Could not get a 2d context.');
397
+ // 元件坐标是页面坐标:先按出图倍数放大,再把框的左上角移到画布原点。描边宽度与字号
398
+ // 跟着这一层变换等比放大,所以各元件照页面坐标画就行。
399
+ ctx.setTransform(size.scale, 0, 0, size.scale, -box.x * size.scale, -box.y * size.scale);
371
400
  for (const eid of order) {
372
401
  const type = page.elements[eid]?.type ?? '';
373
402
  const property = page.properties?.[eid] ?? {};
@@ -55,12 +55,34 @@ export interface SouvenirPage {
55
55
  */
56
56
  export type SouvenirValues = Record<string, string | null | undefined>;
57
57
  export type SouvenirFormat = 'auto' | 'jpeg' | 'png';
58
+ /**
59
+ * The part of the page that becomes the image, in the page's own coordinates.
60
+ *
61
+ * A module that lays the souvenir out on a page participants see marks a frame
62
+ * on it: what is inside becomes the picture, what is outside stays a normal
63
+ * page (PF 2026-09-18). Left out, the whole page is composed.
64
+ */
65
+ export interface SouvenirRegion {
66
+ x: number;
67
+ y: number;
68
+ width: number;
69
+ height: number;
70
+ }
71
+ /** 一个元件算不算在框里:按中心点判定(PF 2026-09-18),画的时候再按框裁切。 */
72
+ export declare function isInsideRegion(property: SouvenirProperty, region: SouvenirRegion): boolean;
58
73
  export interface SouvenirOptions {
59
74
  /**
60
75
  * `auto` (default) picks JPEG unless the page has no opaque background, in
61
76
  * which case the transparency has to survive and PNG wins.
62
77
  */
63
78
  format?: SouvenirFormat;
79
+ /** 只合成页面上的这一块。不给就是整页(Live Input 的离屏页走这一条)。 */
80
+ region?: SouvenirRegion;
81
+ /**
82
+ * 出图的长边像素。短边按区域比例算,所以运营改框的形状不必再改这个数。
83
+ * 不给就按区域的原始尺寸出图。
84
+ */
85
+ longEdge?: number;
64
86
  /** JPEG quality, 0 to 1. Default 0.9. */
65
87
  quality?: number;
66
88
  /** File name handed to the upload endpoint. Extension is set from the format. */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/souvenir/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,8EAA8E;AAC9E,eAAO,MAAM,sBAAsB,8FAQzB,CAAC;AAEX,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1E;;;;;;GAMG;AACH,eAAO,MAAM,0BAA0B,8CAA+C,CAAC;AAKvF;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,EAAE,QAAQ,GAAE,gBAAqB,GAAG,OAAO,CAG/G;AAED,uFAAuF;AACvF,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEvD,iEAAiE;AACjE,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,mFAAmF;IACnF,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC1C,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CAC9C;AAED;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;AAEvE,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;AAErD,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,yCAAyC;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,wGAAwG;IACxG,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,iBAAiB,CAAC;IAC1B,oFAAoF;IACpF,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,OAAO,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;CACzC;AAED,0EAA0E;AAC1E,qBAAa,aAAc,SAAQ,KAAK;aAEpB,IAAI,EAChB,QAAQ,GACR,UAAU,GACV,WAAW,GACX,oBAAoB,GACpB,cAAc,GACd,eAAe;gBANH,IAAI,EAChB,QAAQ,GACR,UAAU,GACV,WAAW,GACX,oBAAoB,GACpB,cAAc,GACd,eAAe,EACnB,OAAO,EAAE,MAAM;CAKlB;AAED;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,OAAO,CAAC;AACtC,eAAO,MAAM,iBAAiB,WAAa,CAAC;AAE5C,oFAAoF;AACpF,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAK5E;AAED,4DAA4D;AAC5D,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,EAAE,CAW5E"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/souvenir/types.ts"],"names":[],"mappings":"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"}
@@ -40,6 +40,19 @@ export function isSouvenirInteractive(type, property = {}) {
40
40
  return true;
41
41
  return INTERACTIVE_PROPERTIES.some((key) => String(property?.[key] ?? '').trim() !== '');
42
42
  }
43
+ /** 一个元件算不算在框里:按中心点判定(PF 2026-09-18),画的时候再按框裁切。 */
44
+ export function isInsideRegion(property, region) {
45
+ const num = (value) => {
46
+ const parsed = typeof value === 'number' ? value : parseFloat(String(value ?? ''));
47
+ return Number.isFinite(parsed) ? parsed : 0;
48
+ };
49
+ const centerX = num(property['x-position']) + num(property['width']) / 2;
50
+ const centerY = num(property['y-position']) + num(property['height']) / 2;
51
+ return (centerX >= region.x &&
52
+ centerX <= region.x + region.width &&
53
+ centerY >= region.y &&
54
+ centerY <= region.y + region.height);
55
+ }
43
56
  /** Thrown for every refusal the caller is expected to handle and show. */
44
57
  export class SouvenirError extends Error {
45
58
  code;
package/package.json CHANGED
@@ -1,64 +1,64 @@
1
- {
2
- "name": "@realnation/builder-shared-sdk",
3
- "version": "2.4.2",
4
- "type": "module",
5
- "private": false,
6
- "exports": {
7
- "./package.json": "./package.json",
8
- ".": {
9
- "types": "./dist/index.d.ts",
10
- "import": "./dist/index.js"
11
- },
12
- "./runtime": {
13
- "types": "./dist/runtime/index.d.ts",
14
- "import": "./dist/runtime/index.js"
15
- },
16
- "./runtime/vue": {
17
- "types": "./dist/runtime/vue/index.d.ts",
18
- "import": "./dist/runtime/vue/index.js"
19
- },
20
- "./interaction": {
21
- "types": "./dist/interaction/index.d.ts",
22
- "import": "./dist/interaction/index.js"
23
- },
24
- "./interaction/vue": {
25
- "types": "./dist/interaction/vue.d.ts",
26
- "import": "./dist/interaction/vue.js"
27
- },
28
- "./souvenir": {
29
- "types": "./dist/souvenir/index.d.ts",
30
- "import": "./dist/souvenir/index.js"
31
- }
32
- },
33
- "files": [
34
- "dist"
35
- ],
36
- "scripts": {
37
- "build": "tsc -p tsconfig.json",
38
- "clean": "rimraf dist",
39
- "test": "vitest run",
40
- "test:watch": "vitest",
41
- "prepublishOnly": "npm run clean && npm run test && npm run build",
42
- "prepare": "npm run clean && npm run build"
43
- },
44
- "dependencies": {
45
- "ali-oss": "^6.23.0",
46
- "axios": "^1.7.7"
47
- },
48
- "peerDependencies": {
49
- "vue": "^3.4.0"
50
- },
51
- "peerDependenciesMeta": {
52
- "vue": {
53
- "optional": true
54
- }
55
- },
56
- "devDependencies": {
57
- "@types/ali-oss": "^6.16.11",
58
- "@types/node": "^26.1.2",
59
- "rimraf": "^5.0.5",
60
- "typescript": "^5.4.5",
61
- "vitest": "^2.1.0",
62
- "vue": "^3.4.0"
63
- }
64
- }
1
+ {
2
+ "name": "@realnation/builder-shared-sdk",
3
+ "version": "2.5.1",
4
+ "type": "module",
5
+ "private": false,
6
+ "exports": {
7
+ "./package.json": "./package.json",
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "import": "./dist/index.js"
11
+ },
12
+ "./runtime": {
13
+ "types": "./dist/runtime/index.d.ts",
14
+ "import": "./dist/runtime/index.js"
15
+ },
16
+ "./runtime/vue": {
17
+ "types": "./dist/runtime/vue/index.d.ts",
18
+ "import": "./dist/runtime/vue/index.js"
19
+ },
20
+ "./interaction": {
21
+ "types": "./dist/interaction/index.d.ts",
22
+ "import": "./dist/interaction/index.js"
23
+ },
24
+ "./interaction/vue": {
25
+ "types": "./dist/interaction/vue.d.ts",
26
+ "import": "./dist/interaction/vue.js"
27
+ },
28
+ "./souvenir": {
29
+ "types": "./dist/souvenir/index.d.ts",
30
+ "import": "./dist/souvenir/index.js"
31
+ }
32
+ },
33
+ "files": [
34
+ "dist"
35
+ ],
36
+ "scripts": {
37
+ "build": "tsc -p tsconfig.json",
38
+ "clean": "rimraf dist",
39
+ "test": "vitest run",
40
+ "test:watch": "vitest",
41
+ "prepublishOnly": "npm run clean && npm run test && npm run build",
42
+ "prepare": "npm run clean && npm run build"
43
+ },
44
+ "dependencies": {
45
+ "ali-oss": "^6.23.0",
46
+ "axios": "^1.7.7"
47
+ },
48
+ "peerDependencies": {
49
+ "vue": "^3.4.0"
50
+ },
51
+ "peerDependenciesMeta": {
52
+ "vue": {
53
+ "optional": true
54
+ }
55
+ },
56
+ "devDependencies": {
57
+ "@types/ali-oss": "^6.16.11",
58
+ "@types/node": "^26.1.2",
59
+ "rimraf": "^5.0.5",
60
+ "typescript": "^5.4.5",
61
+ "vitest": "^2.1.0",
62
+ "vue": "^3.4.0"
63
+ }
64
+ }