@yaoxiu/marketing-dsl 2.7.0 → 2.9.0

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.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { normalizeViews, nextScopeUid, createTicker, createCssBuilder, declarations, toCssStyle, interpolateDeep, evaluate, resolveNodeStyle, interpolate, toLength, computeParts, formatParts, parseEndTime } from './chunk-DT3ZINDI.js';
2
- export { ACTION_TYPES, ALLOWED_EASINGS, ALLOWED_STYLE_KEYS, BANNER_MIN_ASPECT_RATIO, CLOSE_POSITIONS, CSS_NAME_PATTERN, DEFAULT_USER_FIELDS, DSL_VERSION, NODE_TYPES, SINGLE_VIEW_NAME, TRACK_EVENT_PATTERN, USER_FIELD_LABELS, check, computeParts, evaluate, formatIssues, formatParts, interpolate, interpolateDeep, isKeyframeOffset, isLength, isValidEasing, isValidEndTime, normalizeViews, parseEndTime, sanitizeCssValue, toCssStyle, toLength, validate, validateUserFields } from './chunk-DT3ZINDI.js';
1
+ import { normalizeViews, nextScopeUid, createTicker, createAutoplay, createCssBuilder, declarations, toCssStyle, interpolateDeep, evaluate, resolveNodeStyle, interpolate, toLength, computeParts, formatParts, parseEndTime } from './chunk-B6BKOMWL.js';
2
+ export { ACTION_TYPES, ALLOWED_EASINGS, ALLOWED_STYLE_KEYS, AUTOPLAY_FIELDS, AUTOPLAY_MIN_INTERVAL, BANNER_MIN_ASPECT_RATIO, CLOSE_POSITIONS, CSS_NAME_PATTERN, DEFAULT_USER_FIELDS, DERIVED_FIELDS, DSL_VERSION, NODE_TYPES, SINGLE_VIEW_NAME, TRACK_EVENT_PATTERN, USER_FIELD_LABELS, check, computeParts, evaluate, formatIssues, formatParts, interpolate, interpolateDeep, isKeyframeOffset, isLength, isValidEasing, isValidEndTime, normalizeViews, parseEndTime, sanitizeCssValue, toCssStyle, toLength, validate, validateAutoplay, validateUserFields } from './chunk-B6BKOMWL.js';
3
3
 
4
4
  // src/url.ts
5
5
  var SAFE_PROTOCOLS = ["http:", "https:", "mailto:", "tel:"];
@@ -716,7 +716,19 @@ function createRuntime(dsl, options = {}) {
716
716
  state = Object.assign({}, state, { [key]: value });
717
717
  emit("state-change", Object.assign({}, state));
718
718
  notify();
719
+ autoplay.reset(key);
719
720
  }
721
+ const autoplay = createAutoplay({
722
+ derived: dsl.derived,
723
+ getLength: (name) => {
724
+ const list = resolvedData[name];
725
+ return Array.isArray(list) ? list.length : 0;
726
+ },
727
+ getIndex: (key) => Number(state[key]) || 0,
728
+ setState: (key, value) => {
729
+ if (!destroyed) setState(key, value);
730
+ }
731
+ });
720
732
  function openView(name, mode) {
721
733
  if (!normalized.views[name]) {
722
734
  emit("error", { type: "unknown-view", name });
@@ -817,6 +829,7 @@ function createRuntime(dsl, options = {}) {
817
829
  notify();
818
830
  fireLifecycle(normalized.entry, "onShow");
819
831
  emit("ready", { keys: Object.keys(resolved) });
832
+ autoplay.start();
820
833
  }).catch((error) => {
821
834
  if (destroyed) return;
822
835
  loading = false;
@@ -845,6 +858,10 @@ function createRuntime(dsl, options = {}) {
845
858
  hover
846
859
  });
847
860
  ticker.sync(tree.countdownEndTimes, tree.countdownPrecision);
861
+ if (autoplay.pausable) {
862
+ tree.onRootEnter = autoplay.pause;
863
+ tree.onRootLeave = autoplay.resume;
864
+ }
848
865
  return tree;
849
866
  }
850
867
  return {
@@ -864,6 +881,7 @@ function createRuntime(dsl, options = {}) {
864
881
  destroy() {
865
882
  destroyed = true;
866
883
  ticker.stop();
884
+ autoplay.stop();
867
885
  listeners.clear();
868
886
  }
869
887
  };
@@ -46,7 +46,7 @@ function mapRuntimeEventToReport(id, event, payload) {
46
46
  if (event !== "interaction") return null;
47
47
  const data = payload != null ? payload : {};
48
48
  if (data.trigger !== "action") return null;
49
- if (data.closes) return null;
49
+ if (data.closes && !data.navigate) return null;
50
50
  const extra = buildClickExtra(data);
51
51
  if (!extra) return null;
52
52
  return { id, event: "click", extra };
@@ -1,4 +1,4 @@
1
- import { I as RuntimeEventName, G as DslInteractionEvent } from '../types-8FNxDXp0.cjs';
1
+ import { J as RuntimeEventName, H as DslInteractionEvent } from '../types-BapBTTio.cjs';
2
2
 
3
3
  /**
4
4
  * 营销物料上报载荷类型(上报契约的唯一数据源)。
@@ -184,8 +184,10 @@ declare function buildCloseReport(id: string | undefined | null, options?: {
184
184
  * - `interaction` 且 `trigger='action'` → 一条 `click`,`extra` 见 {@link buildClickExtra}
185
185
  * - `interaction` 且 `trigger='show'` / `'close'` → `null`:曝光 / 关闭由宿主统一上报,
186
186
  * 运营配在这两个时机上的埋点名走 {@link buildExposureReport} / {@link buildCloseReport} 的 `extra`
187
- * - `interaction` 且 `trigger='action'` `closes` 为真(手势里执行了关闭动作)→ `null`:
188
- * 点关闭按钮的本质是关闭,不再算一次点击
187
+ * - `interaction` 且 `trigger='action'`、`closes` 为真(手势里执行了关闭动作)但**没有** `navigate`
188
+ * → `null`:纯关闭手势的本质是关闭,不再算一次点击
189
+ * - `interaction` 且 `trigger='action'`、`closes` 为真但同一次交互里**有** `navigate`
190
+ * → 照常产出 `click`:跳走了就是一次转化行为,「顺手关掉弹窗」只是它的副作用
189
191
  * - 其余事件(`track` / `navigate` / `close` / `call` / `error` / `state-change` /
190
192
  * `view-change` / `ready` / `open`)不产生上报 —— 它们是动作粒度的事件,按它们上报会重复计数
191
193
  *
@@ -1,4 +1,4 @@
1
- import { I as RuntimeEventName, G as DslInteractionEvent } from '../types-8FNxDXp0.js';
1
+ import { J as RuntimeEventName, H as DslInteractionEvent } from '../types-BapBTTio.js';
2
2
 
3
3
  /**
4
4
  * 营销物料上报载荷类型(上报契约的唯一数据源)。
@@ -184,8 +184,10 @@ declare function buildCloseReport(id: string | undefined | null, options?: {
184
184
  * - `interaction` 且 `trigger='action'` → 一条 `click`,`extra` 见 {@link buildClickExtra}
185
185
  * - `interaction` 且 `trigger='show'` / `'close'` → `null`:曝光 / 关闭由宿主统一上报,
186
186
  * 运营配在这两个时机上的埋点名走 {@link buildExposureReport} / {@link buildCloseReport} 的 `extra`
187
- * - `interaction` 且 `trigger='action'` `closes` 为真(手势里执行了关闭动作)→ `null`:
188
- * 点关闭按钮的本质是关闭,不再算一次点击
187
+ * - `interaction` 且 `trigger='action'`、`closes` 为真(手势里执行了关闭动作)但**没有** `navigate`
188
+ * → `null`:纯关闭手势的本质是关闭,不再算一次点击
189
+ * - `interaction` 且 `trigger='action'`、`closes` 为真但同一次交互里**有** `navigate`
190
+ * → 照常产出 `click`:跳走了就是一次转化行为,「顺手关掉弹窗」只是它的副作用
189
191
  * - 其余事件(`track` / `navigate` / `close` / `call` / `error` / `state-change` /
190
192
  * `view-change` / `ready` / `open`)不产生上报 —— 它们是动作粒度的事件,按它们上报会重复计数
191
193
  *
@@ -44,7 +44,7 @@ function mapRuntimeEventToReport(id, event, payload) {
44
44
  if (event !== "interaction") return null;
45
45
  const data = payload != null ? payload : {};
46
46
  if (data.trigger !== "action") return null;
47
- if (data.closes) return null;
47
+ if (data.closes && !data.navigate) return null;
48
48
  const extra = buildClickExtra(data);
49
49
  if (!extra) return null;
50
50
  return { id, event: "click", extra };
@@ -213,11 +213,25 @@ interface DslSourceRef {
213
213
  $source: string;
214
214
  params?: Record<string, unknown>;
215
215
  }
216
+ /**
217
+ * 自动轮播配置,挂在 `derived.xxx.autoplay` 上。
218
+ *
219
+ * 配了就开启、始终循环:每隔 `interval` 毫秒把 `state[indexBy]` 往下推一格
220
+ * (到末尾回到 0)。走的是和用户点 tab 同一个 setState,效果与手动切换完全一致。
221
+ */
222
+ interface DslAutoplay {
223
+ /** 切换间隔,毫秒,不小于 1000 */
224
+ interval: number;
225
+ /** 鼠标悬停在整个物料上时暂停,离开后重新计时。默认 false */
226
+ pauseOnHover?: boolean;
227
+ }
216
228
  interface DslDerived {
217
229
  /** data 里的数组字段名 */
218
230
  list: string;
219
231
  /** state 里的下标字段名 */
220
232
  indexBy: string;
233
+ /** 自动轮播;不写就不轮播 */
234
+ autoplay?: DslAutoplay;
221
235
  }
222
236
  /** 一份完整配置。单视图直接写 type/stage/nodes,多视图写 views + entry */
223
237
  interface Dsl extends Partial<DslView> {
@@ -341,6 +355,15 @@ interface RenderTree {
341
355
  * 同一个页面上出现多份物料时,各自的 hover 规则不会串台。
342
356
  */
343
357
  rootClassName: string;
358
+ /**
359
+ * 鼠标进入根容器时调用。只有配置里存在 `pauseOnHover: true` 的自动轮播时才有值。
360
+ *
361
+ * 框架壳的义务:有值时在根容器上绑 `mouseenter` 调它,**不阻止冒泡、不加任何判断**;
362
+ * 没值时什么都不绑。暂停哪些轮播、何时恢复,全由 core 决定。
363
+ */
364
+ onRootEnter?: () => void;
365
+ /** 鼠标离开根容器时调用,与 `onRootEnter` 成对出现,壳绑 `mouseleave` */
366
+ onRootLeave?: () => void;
344
367
  }
345
368
  type DslSource = (params: Record<string, unknown>, user: Record<string, unknown>) => unknown | Promise<unknown>;
346
369
  type DslHandler = (params: Record<string, unknown>) => void;
@@ -383,9 +406,14 @@ interface DslInteractionEvent {
383
406
  /**
384
407
  * 这次交互里执行了关闭动作(`close` / `closeAll`)。
385
408
  *
386
- * 用来把「点关闭按钮」和「点营销内容」区分开:前者的本质是关闭,不该再算一次点击。
387
- * 运营常把埋点配进关闭按钮的 `sequence: [track, close]`,不标记的话这一下会同时
388
- * 产出 close 和 click 两条,点击量照样虚增。埋点名不会丢 —— 宿主把它并进 close 上报。
409
+ * 用来把「点关闭按钮」和「点营销内容」区分开:**纯关闭手势**(有关闭动作、又没有
410
+ * `navigate`)的本质是关闭,不该再算一次点击。运营常把埋点配进关闭按钮的
411
+ * `sequence: [track, close]`,不标记的话这一下会同时产出 close 和 click 两条,
412
+ * 点击量虚增。埋点名不会丢 —— 宿主把它并进 close 上报。
413
+ *
414
+ * 例外:同一次交互里还有 `navigate` 时仍算一次 click。转化型主 CTA 常写成
415
+ * `sequence: [track, closeAll, navigate]`(跳走前顺手收掉弹窗),真跳转了就是转化行为,
416
+ * 关闭只是副作用。此时埋点名已进 click 的 `extra`,宿主不再把它并进 close。
389
417
  */
390
418
  closes?: boolean;
391
419
  }
@@ -456,4 +484,4 @@ interface RuntimeOptions {
456
484
  emit?: RuntimeEmit;
457
485
  }
458
486
 
459
- export type { RenderLayer as A, DslSource as B, CssStyle as C, Dsl as D, DslHandler as E, DslInteractionTrigger as F, DslInteractionEvent as G, RuntimeEvents as H, RuntimeEventName as I, RuntimeEmit as J, RuntimeOptions as R, RenderTree as a, DslView as b, DslStyle as c, DslViewType as d, DslNodeType as e, DslLength as f, DslRect as g, DslAnimate as h, DslKeyframe as i, DslActionBase as j, DslNavigateAction as k, DslCloseAction as l, DslCloseAllAction as m, DslOpenAction as n, DslSetStateAction as o, DslTrackAction as p, DslCallAction as q, DslSequenceAction as r, DslAction as s, DslNode as t, DslClosePosition as u, DslCloseButton as v, DslStage as w, DslSourceRef as x, DslDerived as y, RenderElement as z };
487
+ export type { RenderElement as A, RenderLayer as B, CssStyle as C, Dsl as D, DslSource as E, DslHandler as F, DslInteractionTrigger as G, DslInteractionEvent as H, RuntimeEvents as I, RuntimeEventName as J, RuntimeEmit as K, RuntimeOptions as R, RenderTree as a, DslView as b, DslStyle as c, DslViewType as d, DslNodeType as e, DslLength as f, DslRect as g, DslAnimate as h, DslKeyframe as i, DslActionBase as j, DslNavigateAction as k, DslCloseAction as l, DslCloseAllAction as m, DslOpenAction as n, DslSetStateAction as o, DslTrackAction as p, DslCallAction as q, DslSequenceAction as r, DslAction as s, DslNode as t, DslClosePosition as u, DslCloseButton as v, DslStage as w, DslSourceRef as x, DslAutoplay as y, DslDerived as z };
@@ -213,11 +213,25 @@ interface DslSourceRef {
213
213
  $source: string;
214
214
  params?: Record<string, unknown>;
215
215
  }
216
+ /**
217
+ * 自动轮播配置,挂在 `derived.xxx.autoplay` 上。
218
+ *
219
+ * 配了就开启、始终循环:每隔 `interval` 毫秒把 `state[indexBy]` 往下推一格
220
+ * (到末尾回到 0)。走的是和用户点 tab 同一个 setState,效果与手动切换完全一致。
221
+ */
222
+ interface DslAutoplay {
223
+ /** 切换间隔,毫秒,不小于 1000 */
224
+ interval: number;
225
+ /** 鼠标悬停在整个物料上时暂停,离开后重新计时。默认 false */
226
+ pauseOnHover?: boolean;
227
+ }
216
228
  interface DslDerived {
217
229
  /** data 里的数组字段名 */
218
230
  list: string;
219
231
  /** state 里的下标字段名 */
220
232
  indexBy: string;
233
+ /** 自动轮播;不写就不轮播 */
234
+ autoplay?: DslAutoplay;
221
235
  }
222
236
  /** 一份完整配置。单视图直接写 type/stage/nodes,多视图写 views + entry */
223
237
  interface Dsl extends Partial<DslView> {
@@ -341,6 +355,15 @@ interface RenderTree {
341
355
  * 同一个页面上出现多份物料时,各自的 hover 规则不会串台。
342
356
  */
343
357
  rootClassName: string;
358
+ /**
359
+ * 鼠标进入根容器时调用。只有配置里存在 `pauseOnHover: true` 的自动轮播时才有值。
360
+ *
361
+ * 框架壳的义务:有值时在根容器上绑 `mouseenter` 调它,**不阻止冒泡、不加任何判断**;
362
+ * 没值时什么都不绑。暂停哪些轮播、何时恢复,全由 core 决定。
363
+ */
364
+ onRootEnter?: () => void;
365
+ /** 鼠标离开根容器时调用,与 `onRootEnter` 成对出现,壳绑 `mouseleave` */
366
+ onRootLeave?: () => void;
344
367
  }
345
368
  type DslSource = (params: Record<string, unknown>, user: Record<string, unknown>) => unknown | Promise<unknown>;
346
369
  type DslHandler = (params: Record<string, unknown>) => void;
@@ -383,9 +406,14 @@ interface DslInteractionEvent {
383
406
  /**
384
407
  * 这次交互里执行了关闭动作(`close` / `closeAll`)。
385
408
  *
386
- * 用来把「点关闭按钮」和「点营销内容」区分开:前者的本质是关闭,不该再算一次点击。
387
- * 运营常把埋点配进关闭按钮的 `sequence: [track, close]`,不标记的话这一下会同时
388
- * 产出 close 和 click 两条,点击量照样虚增。埋点名不会丢 —— 宿主把它并进 close 上报。
409
+ * 用来把「点关闭按钮」和「点营销内容」区分开:**纯关闭手势**(有关闭动作、又没有
410
+ * `navigate`)的本质是关闭,不该再算一次点击。运营常把埋点配进关闭按钮的
411
+ * `sequence: [track, close]`,不标记的话这一下会同时产出 close 和 click 两条,
412
+ * 点击量虚增。埋点名不会丢 —— 宿主把它并进 close 上报。
413
+ *
414
+ * 例外:同一次交互里还有 `navigate` 时仍算一次 click。转化型主 CTA 常写成
415
+ * `sequence: [track, closeAll, navigate]`(跳走前顺手收掉弹窗),真跳转了就是转化行为,
416
+ * 关闭只是副作用。此时埋点名已进 click 的 `extra`,宿主不再把它并进 close。
389
417
  */
390
418
  closes?: boolean;
391
419
  }
@@ -456,4 +484,4 @@ interface RuntimeOptions {
456
484
  emit?: RuntimeEmit;
457
485
  }
458
486
 
459
- export type { RenderLayer as A, DslSource as B, CssStyle as C, Dsl as D, DslHandler as E, DslInteractionTrigger as F, DslInteractionEvent as G, RuntimeEvents as H, RuntimeEventName as I, RuntimeEmit as J, RuntimeOptions as R, RenderTree as a, DslView as b, DslStyle as c, DslViewType as d, DslNodeType as e, DslLength as f, DslRect as g, DslAnimate as h, DslKeyframe as i, DslActionBase as j, DslNavigateAction as k, DslCloseAction as l, DslCloseAllAction as m, DslOpenAction as n, DslSetStateAction as o, DslTrackAction as p, DslCallAction as q, DslSequenceAction as r, DslAction as s, DslNode as t, DslClosePosition as u, DslCloseButton as v, DslStage as w, DslSourceRef as x, DslDerived as y, RenderElement as z };
487
+ export type { RenderElement as A, RenderLayer as B, CssStyle as C, Dsl as D, DslSource as E, DslHandler as F, DslInteractionTrigger as G, DslInteractionEvent as H, RuntimeEvents as I, RuntimeEventName as J, RuntimeEmit as K, RuntimeOptions as R, RenderTree as a, DslView as b, DslStyle as c, DslViewType as d, DslNodeType as e, DslLength as f, DslRect as g, DslAnimate as h, DslKeyframe as i, DslActionBase as j, DslNavigateAction as k, DslCloseAction as l, DslCloseAllAction as m, DslOpenAction as n, DslSetStateAction as o, DslTrackAction as p, DslCallAction as q, DslSequenceAction as r, DslAction as s, DslNode as t, DslClosePosition as u, DslCloseButton as v, DslStage as w, DslSourceRef as x, DslAutoplay as y, DslDerived as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yaoxiu/marketing-dsl",
3
- "version": "2.7.0",
3
+ "version": "2.9.0",
4
4
  "type": "module",
5
5
  "description": "营销弹窗 DSL 解释器核心,纯逻辑无框架依赖",
6
6
  "license": "MIT",