@yaoxiu/marketing-dsl 2.3.0 → 2.5.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/README.md +15 -0
- package/dist/{chunk-DTHKC5AL.js → chunk-DT3ZINDI.js} +381 -45
- package/dist/docs/index.cjs +1606 -104
- package/dist/docs/index.d.cts +4 -3
- package/dist/docs/index.d.ts +4 -3
- package/dist/docs/index.js +1574 -108
- package/dist/index.cjs +523 -87
- package/dist/index.d.cts +56 -4
- package/dist/index.d.ts +56 -4
- package/dist/index.js +140 -45
- package/dist/report/index.d.cts +1 -1
- package/dist/report/index.d.ts +1 -1
- package/dist/{types-Bj0xyWnx.d.cts → types-8FNxDXp0.d.cts} +116 -2
- package/dist/{types-Bj0xyWnx.d.ts → types-8FNxDXp0.d.ts} +116 -2
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -541,6 +541,11 @@ function isLength(value) {
|
|
|
541
541
|
if (/^calc\([^;{}]*\)$/.test(trimmed)) return true;
|
|
542
542
|
return LENGTH_RE.test(trimmed);
|
|
543
543
|
}
|
|
544
|
+
function clampZIndex(value) {
|
|
545
|
+
const num = typeof value === "number" ? value : parseFloat(String(value));
|
|
546
|
+
if (!isFinite(num)) return 0;
|
|
547
|
+
return Math.min(10, Math.max(0, Math.round(num)));
|
|
548
|
+
}
|
|
544
549
|
var STYLE_MAP = {
|
|
545
550
|
// 文字
|
|
546
551
|
color: ["color", String],
|
|
@@ -593,6 +598,26 @@ var STYLE_MAP = {
|
|
|
593
598
|
minHeight: ["minHeight", px],
|
|
594
599
|
maxWidth: ["maxWidth", px],
|
|
595
600
|
maxHeight: ["maxHeight", px],
|
|
601
|
+
// 动效相关。transform / transition 是做位移、缩放、hover 过渡的最小必需集;
|
|
602
|
+
// 不放开 position / display / grid —— rect 已经提供绝对定位,栅格用 flex wrap + 百分比宽复刻,
|
|
603
|
+
// 放开 position 等于把「全屏覆盖」这类越权手段又交回给配置。
|
|
604
|
+
transform: ["transform", String],
|
|
605
|
+
transformOrigin: ["transformOrigin", String],
|
|
606
|
+
transition: ["transition", String],
|
|
607
|
+
// 只为 hoverStyle 而放开:`animationPlayState: 'paused'` 才能做到「悬停时暂停呼吸动画」。
|
|
608
|
+
// 写进普通 style 也合法(等于一开始就暂停),但那基本没有意义。
|
|
609
|
+
animationPlayState: ["animationPlayState", String],
|
|
610
|
+
// 毛玻璃。Safari 至今只认带前缀的写法,所以两个键一起输出,见 EXTRA_CSS_KEYS
|
|
611
|
+
backdropFilter: ["backdropFilter", String],
|
|
612
|
+
textShadow: ["textShadow", String],
|
|
613
|
+
// 只允许 0~10:越权提层是弹窗类配置最容易做的坏事(盖住宿主自己的导航 / 收银台),
|
|
614
|
+
// 层内排布十层绰绰有余,真需要压过页面其它内容的是弹窗层,那由解释器自己给 1000
|
|
615
|
+
zIndex: ["zIndex", (v) => String(clampZIndex(v))],
|
|
616
|
+
// 装饰性图层(光斑、扫光)必须让点击穿透,否则会挡住下面的按钮
|
|
617
|
+
pointerEvents: ["pointerEvents", String],
|
|
618
|
+
// 横向排布里「这一项不许被压扁」,图标位和数字位常用
|
|
619
|
+
flexShrink: ["flexShrink", String],
|
|
620
|
+
fontStyle: ["fontStyle", String],
|
|
596
621
|
// 图片
|
|
597
622
|
objectFit: ["objectFit", String],
|
|
598
623
|
// 宽度给百分比、高度按比例算。整图 banner 的热区必须靠它才能用百分比定位:
|
|
@@ -600,6 +625,9 @@ var STYLE_MAP = {
|
|
|
600
625
|
aspectRatio: ["aspectRatio", String]
|
|
601
626
|
};
|
|
602
627
|
var ALLOWED_STYLE_KEYS = Object.keys(STYLE_MAP);
|
|
628
|
+
var EXTRA_CSS_KEYS = {
|
|
629
|
+
backdropFilter: ["WebkitBackdropFilter"]
|
|
630
|
+
};
|
|
603
631
|
function toCssStyle(style) {
|
|
604
632
|
const css = {};
|
|
605
633
|
if (!style) return css;
|
|
@@ -608,7 +636,11 @@ function toCssStyle(style) {
|
|
|
608
636
|
if (!rule) return;
|
|
609
637
|
const value = style[key];
|
|
610
638
|
if (value === void 0 || value === null || value === "") return;
|
|
611
|
-
|
|
639
|
+
const result = rule[1](value);
|
|
640
|
+
css[rule[0]] = result;
|
|
641
|
+
(EXTRA_CSS_KEYS[key] || []).forEach((extra) => {
|
|
642
|
+
css[extra] = result;
|
|
643
|
+
});
|
|
612
644
|
});
|
|
613
645
|
return css;
|
|
614
646
|
}
|
|
@@ -621,27 +653,128 @@ function toRectStyle(rect) {
|
|
|
621
653
|
return css;
|
|
622
654
|
}
|
|
623
655
|
function resolveNodeStyle(node, layout) {
|
|
624
|
-
|
|
656
|
+
const css = Object.assign(
|
|
625
657
|
{},
|
|
626
658
|
layout === "absolute" ? toRectStyle(node.rect) : {},
|
|
627
659
|
toCssStyle(node.style)
|
|
628
660
|
);
|
|
661
|
+
if (css.zIndex !== void 0 && !css.position) css.position = "relative";
|
|
662
|
+
return css;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
// src/css-value.ts
|
|
666
|
+
function sanitizeCssValue(value) {
|
|
667
|
+
if (value === void 0 || value === null) return null;
|
|
668
|
+
const text = String(value).trim();
|
|
669
|
+
if (!text) return null;
|
|
670
|
+
if (/[{}<>;@]/.test(text)) return null;
|
|
671
|
+
if (text.indexOf("/*") > -1 || text.indexOf("*/") > -1) return null;
|
|
672
|
+
if (text.indexOf("\\") > -1) return null;
|
|
673
|
+
return text;
|
|
674
|
+
}
|
|
675
|
+
function toCssProp(key) {
|
|
676
|
+
return key.replace(/[A-Z]/g, (ch) => `-${ch.toLowerCase()}`);
|
|
677
|
+
}
|
|
678
|
+
function declarations(style) {
|
|
679
|
+
return Object.keys(style).map((key) => {
|
|
680
|
+
const value = sanitizeCssValue(style[key]);
|
|
681
|
+
return value === null ? "" : `${toCssProp(key)}:${value}`;
|
|
682
|
+
}).filter(Boolean).join(";");
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
// src/css.ts
|
|
686
|
+
var CSS_NAME_PATTERN = /^[a-zA-Z][a-zA-Z0-9_-]{0,31}$/;
|
|
687
|
+
var ALLOWED_EASINGS = [
|
|
688
|
+
"linear",
|
|
689
|
+
"ease",
|
|
690
|
+
"ease-in",
|
|
691
|
+
"ease-out",
|
|
692
|
+
"ease-in-out",
|
|
693
|
+
"step-start",
|
|
694
|
+
"step-end"
|
|
695
|
+
];
|
|
696
|
+
var CUBIC_BEZIER_RE = /^cubic-bezier\(\s*-?\d+(\.\d+)?\s*,\s*-?\d+(\.\d+)?\s*,\s*-?\d+(\.\d+)?\s*,\s*-?\d+(\.\d+)?\s*\)$/;
|
|
697
|
+
var OFFSET_RE = /^(from|to|\d+(\.\d+)?%)$/;
|
|
698
|
+
function isValidEasing(value) {
|
|
699
|
+
if (typeof value !== "string") return false;
|
|
700
|
+
const trimmed = value.trim();
|
|
701
|
+
return ALLOWED_EASINGS.indexOf(trimmed) > -1 || CUBIC_BEZIER_RE.test(trimmed);
|
|
702
|
+
}
|
|
703
|
+
function isKeyframeOffset(value) {
|
|
704
|
+
return typeof value === "string" && OFFSET_RE.test(value.trim());
|
|
705
|
+
}
|
|
706
|
+
var scopeSeed = 0;
|
|
707
|
+
function nextScopeUid() {
|
|
708
|
+
scopeSeed += 1;
|
|
709
|
+
return scopeSeed;
|
|
710
|
+
}
|
|
711
|
+
function createCssBuilder(uid, keyframes, hover) {
|
|
712
|
+
const rootClassName = `dsl-renderer dsl-r${uid}`;
|
|
713
|
+
const scope = `.dsl-r${uid}`;
|
|
714
|
+
const defined = keyframes && typeof keyframes === "object" ? keyframes : {};
|
|
715
|
+
const hoverRules = hover ? hover.rules : [];
|
|
716
|
+
function scopedKeyframeName(name) {
|
|
717
|
+
return `dsl-kf-${uid}-${name}`;
|
|
718
|
+
}
|
|
719
|
+
function animation(animate) {
|
|
720
|
+
if (!animate || typeof animate !== "object") return void 0;
|
|
721
|
+
const name = animate.name;
|
|
722
|
+
if (typeof name !== "string" || !CSS_NAME_PATTERN.test(name)) return void 0;
|
|
723
|
+
if (!Object.prototype.hasOwnProperty.call(defined, name)) return void 0;
|
|
724
|
+
const duration = toMs(animate.duration, 0);
|
|
725
|
+
if (duration <= 0) return void 0;
|
|
726
|
+
const delay = toMs(animate.delay, 0);
|
|
727
|
+
const easing = isValidEasing(animate.easing) ? String(animate.easing).trim() : "ease";
|
|
728
|
+
const iteration = animate.iteration === "infinite" ? "infinite" : String(Math.max(1, Math.round(Number(animate.iteration) || 1)));
|
|
729
|
+
const direction = pick(animate.direction, DIRECTIONS, "normal");
|
|
730
|
+
const fill = pick(animate.fill, FILLS, "both");
|
|
731
|
+
return `${scopedKeyframeName(name)} ${duration}ms ${easing} ${delay}ms ${iteration} ${direction} ${fill}`;
|
|
732
|
+
}
|
|
733
|
+
function hoverClass(owner) {
|
|
734
|
+
return owner && hover ? hover.classOf.get(owner) : void 0;
|
|
735
|
+
}
|
|
736
|
+
function build() {
|
|
737
|
+
const rules = keyframeRules().concat(hoverRules);
|
|
738
|
+
if (!rules.length) return "";
|
|
739
|
+
rules.push(
|
|
740
|
+
`@media (prefers-reduced-motion: reduce){${scope} *{animation:none!important;transition:none!important}}`
|
|
741
|
+
);
|
|
742
|
+
return rules.join("\n");
|
|
743
|
+
}
|
|
744
|
+
function keyframeRules() {
|
|
745
|
+
return Object.keys(defined).filter((name) => CSS_NAME_PATTERN.test(name)).map((name) => {
|
|
746
|
+
const frames = defined[name];
|
|
747
|
+
if (!frames || typeof frames !== "object") return "";
|
|
748
|
+
const body = Object.keys(frames).filter(isKeyframeOffset).map((offset) => {
|
|
749
|
+
const decl = declarations(toCssStyle(frames[offset]));
|
|
750
|
+
return decl ? `${offset.trim()}{${decl}}` : "";
|
|
751
|
+
}).filter(Boolean).join("");
|
|
752
|
+
return body ? `@keyframes ${scopedKeyframeName(name)}{${body}}` : "";
|
|
753
|
+
}).filter(Boolean);
|
|
754
|
+
}
|
|
755
|
+
return { uid, rootClassName, animation, hoverClass, build };
|
|
756
|
+
}
|
|
757
|
+
var DIRECTIONS = ["normal", "reverse", "alternate", "alternate-reverse"];
|
|
758
|
+
var FILLS = ["none", "forwards", "backwards", "both"];
|
|
759
|
+
function pick(value, allowed, fallback) {
|
|
760
|
+
return typeof value === "string" && allowed.indexOf(value) > -1 ? value : fallback;
|
|
761
|
+
}
|
|
762
|
+
function toMs(value, fallback) {
|
|
763
|
+
const num = Number(value);
|
|
764
|
+
if (!isFinite(num) || num < 0) return fallback;
|
|
765
|
+
return Math.round(num);
|
|
629
766
|
}
|
|
630
767
|
|
|
631
768
|
// src/resolve.ts
|
|
632
769
|
function resolveTree(input) {
|
|
633
770
|
const { normalized, viewStack, ready } = input;
|
|
771
|
+
const css = createCssBuilder(input.scopeUid, input.keyframes, input.hover);
|
|
772
|
+
const pass = Object.assign({}, input, { css });
|
|
634
773
|
const layers = viewStack.map((name) => ({ name, view: normalized.views[name] })).filter((item) => !!item.view);
|
|
635
774
|
const hasPopup = layers.some((item) => item.view.type === "popup");
|
|
636
775
|
const countdowns = { endTimes: [], precision: "s" };
|
|
637
776
|
const renderLayers = ready ? layers.map(
|
|
638
|
-
(item, index) => resolveLayer(
|
|
639
|
-
item.name,
|
|
640
|
-
item.view,
|
|
641
|
-
index === layers.length - 1,
|
|
642
|
-
input,
|
|
643
|
-
countdowns
|
|
644
|
-
)
|
|
777
|
+
(item, index) => resolveLayer(item.name, item.view, index === layers.length - 1, pass, countdowns)
|
|
645
778
|
) : [];
|
|
646
779
|
return {
|
|
647
780
|
ready: ready && layers.length > 0,
|
|
@@ -652,7 +785,10 @@ function resolveTree(input) {
|
|
|
652
785
|
rootStyle: { position: "relative" },
|
|
653
786
|
layers: renderLayers,
|
|
654
787
|
countdownEndTimes: countdowns.endTimes,
|
|
655
|
-
countdownPrecision: countdowns.precision
|
|
788
|
+
countdownPrecision: countdowns.precision,
|
|
789
|
+
// build 必须在 layers 算完之后调:hover 规则是遍历节点时才登记进来的
|
|
790
|
+
css: css.build(),
|
|
791
|
+
rootClassName: css.rootClassName
|
|
656
792
|
};
|
|
657
793
|
}
|
|
658
794
|
function resolveLayer(name, view, isTop, input, countdowns) {
|
|
@@ -661,7 +797,7 @@ function resolveLayer(name, view, isTop, input, countdowns) {
|
|
|
661
797
|
const isPopup = view.type === "popup";
|
|
662
798
|
const rootLayout = stage.layout === "flow" ? "flow" : "absolute";
|
|
663
799
|
const maskClosable = !!stage.maskClosable;
|
|
664
|
-
const onMaskClick = maskClosable ? () => closeTop("mask") : void 0;
|
|
800
|
+
const onMaskClick = maskClosable ? stage.maskAction ? () => input.dispatch(stage.maskAction, context) : () => closeTop("mask") : void 0;
|
|
665
801
|
const nodes = (view.nodes || []).map(
|
|
666
802
|
(node, index) => resolveNode(node, `${name}-${index}`, rootLayout, context, input, countdowns)
|
|
667
803
|
).filter((el) => !!el);
|
|
@@ -669,20 +805,26 @@ function resolveLayer(name, view, isTop, input, countdowns) {
|
|
|
669
805
|
name,
|
|
670
806
|
type: view.type,
|
|
671
807
|
isTop,
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
808
|
+
/**
|
|
809
|
+
* 弹窗层恒画遮罩元素,**非栈顶时只是变透明**(见下方 maskStyle)。
|
|
810
|
+
*
|
|
811
|
+
* 【为什么不是「只有栈顶才画」】那样写视觉上也对(两层实心遮罩叠加会明显变黑,
|
|
812
|
+
* 所以下层必须让位),但下层的遮罩 DOM 会被整个移除、退回栈顶时再新建一个 ——
|
|
813
|
+
* 新元素身上的 `maskAnimate` 于是又播一遍:关掉二次挽留层回到主弹窗时,
|
|
814
|
+
* 背景会重新淡入一次,看起来就是「闪了一下」。元素常驻就没这问题。
|
|
815
|
+
*/
|
|
816
|
+
mask: isPopup && stage.mask !== false,
|
|
817
|
+
// 非栈顶层整层 pointerEvents: none,遮罩点不到,这里也就不必给它挂回调
|
|
818
|
+
onMaskClick: isTop ? onMaskClick : void 0,
|
|
675
819
|
layerStyle: layerStyle(isPopup, isTop),
|
|
676
|
-
maskStyle
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
right: "0",
|
|
680
|
-
bottom: "0",
|
|
681
|
-
left: "0",
|
|
682
|
-
background: "rgba(0, 0, 0, 0.55)"
|
|
683
|
-
},
|
|
820
|
+
// 合并顺序固定:内置默认 → stage.maskStyle 覆盖 → maskAnimate 的 animation 收尾。
|
|
821
|
+
// 遮罩样式也走一遍插值,切 tab 时能跟着变(同 stage.style)
|
|
822
|
+
maskStyle: maskStyle(stage, isTop, context, input),
|
|
684
823
|
scrollStyle: scrollStyle(isPopup),
|
|
685
|
-
stageStyle:
|
|
824
|
+
stageStyle: withAnimation(
|
|
825
|
+
resolveStageStyle(stage, isPopup, context),
|
|
826
|
+
input.css.animation(stage.animate)
|
|
827
|
+
),
|
|
686
828
|
clipStyle: {
|
|
687
829
|
position: "relative",
|
|
688
830
|
height: "100%",
|
|
@@ -690,10 +832,39 @@ function resolveLayer(name, view, isTop, input, countdowns) {
|
|
|
690
832
|
overflow: "hidden",
|
|
691
833
|
boxSizing: "border-box"
|
|
692
834
|
},
|
|
693
|
-
closeButton: resolveCloseButton(stage.closeButton, name, closeTop),
|
|
835
|
+
closeButton: resolveCloseButton(stage.closeButton, name, closeTop, input, context),
|
|
694
836
|
nodes
|
|
695
837
|
};
|
|
696
838
|
}
|
|
839
|
+
function withAnimation(style, animation) {
|
|
840
|
+
if (animation) style.animation = animation;
|
|
841
|
+
return style;
|
|
842
|
+
}
|
|
843
|
+
function maskStyle(stage, isTop, context, input) {
|
|
844
|
+
const style = withAnimation(
|
|
845
|
+
Object.assign(
|
|
846
|
+
{
|
|
847
|
+
position: "absolute",
|
|
848
|
+
top: "0",
|
|
849
|
+
right: "0",
|
|
850
|
+
bottom: "0",
|
|
851
|
+
left: "0",
|
|
852
|
+
background: "rgba(0, 0, 0, 0.55)"
|
|
853
|
+
},
|
|
854
|
+
toCssStyle(interpolateDeep(stage.maskStyle, context))
|
|
855
|
+
),
|
|
856
|
+
input.css.animation(stage.maskAnimate)
|
|
857
|
+
);
|
|
858
|
+
if (isTop) return style;
|
|
859
|
+
style.background = "transparent";
|
|
860
|
+
delete style.backdropFilter;
|
|
861
|
+
delete style.WebkitBackdropFilter;
|
|
862
|
+
return style;
|
|
863
|
+
}
|
|
864
|
+
function withHover(className, owner, css) {
|
|
865
|
+
const hoverClass = css.hoverClass(owner);
|
|
866
|
+
return hoverClass ? `${className} ${hoverClass}` : className;
|
|
867
|
+
}
|
|
697
868
|
function layerStyle(isPopup, isTop) {
|
|
698
869
|
const style = isPopup ? {
|
|
699
870
|
position: "fixed",
|
|
@@ -751,7 +922,8 @@ function resolveStageStyle(stage, isPopup, context) {
|
|
|
751
922
|
}
|
|
752
923
|
return style;
|
|
753
924
|
}
|
|
754
|
-
function resolveCloseButton(config, layerName, closeTop) {
|
|
925
|
+
function resolveCloseButton(config, layerName, closeTop, input, context) {
|
|
926
|
+
const css = input.css;
|
|
755
927
|
if (!config || config.show === false) return void 0;
|
|
756
928
|
const offset = config.offset || [8, 8];
|
|
757
929
|
const size = config.size === void 0 ? 26 : config.size;
|
|
@@ -789,12 +961,14 @@ function resolveCloseButton(config, layerName, closeTop) {
|
|
|
789
961
|
style.right = toLength(offset[0]);
|
|
790
962
|
}
|
|
791
963
|
Object.assign(style, toCssStyle(config.style));
|
|
792
|
-
|
|
964
|
+
withAnimation(style, css.animation(config.animate));
|
|
965
|
+
const className = withHover("dsl-close", config, css);
|
|
966
|
+
const onClick = config.action ? () => input.dispatch(config.action, context) : () => closeTop("close-button");
|
|
793
967
|
if (iconMode === "image") {
|
|
794
968
|
return {
|
|
795
969
|
key: `${layerName}-close`,
|
|
796
970
|
tag: "div",
|
|
797
|
-
className
|
|
971
|
+
className,
|
|
798
972
|
style,
|
|
799
973
|
onClick,
|
|
800
974
|
children: [
|
|
@@ -817,7 +991,7 @@ function resolveCloseButton(config, layerName, closeTop) {
|
|
|
817
991
|
return {
|
|
818
992
|
key: `${layerName}-close`,
|
|
819
993
|
tag: "div",
|
|
820
|
-
className
|
|
994
|
+
className,
|
|
821
995
|
style,
|
|
822
996
|
onClick,
|
|
823
997
|
text: config.icon
|
|
@@ -826,7 +1000,7 @@ function resolveCloseButton(config, layerName, closeTop) {
|
|
|
826
1000
|
return {
|
|
827
1001
|
key: `${layerName}-close`,
|
|
828
1002
|
tag: "div",
|
|
829
|
-
className
|
|
1003
|
+
className,
|
|
830
1004
|
style,
|
|
831
1005
|
onClick,
|
|
832
1006
|
children: [closeIcon(`${layerName}-close-icon`, size)]
|
|
@@ -914,6 +1088,12 @@ function resolveNode(node, key, layout, context, input, countdowns) {
|
|
|
914
1088
|
layout
|
|
915
1089
|
)
|
|
916
1090
|
);
|
|
1091
|
+
withAnimation(style, input.css.animation(node.animate));
|
|
1092
|
+
const hoverClass = input.css.hoverClass(node);
|
|
1093
|
+
const cls = (type, clickable) => {
|
|
1094
|
+
const base = nodeClass(type, clickable);
|
|
1095
|
+
return hoverClass ? `${base} ${hoverClass}` : base;
|
|
1096
|
+
};
|
|
917
1097
|
const onClick = node.action ? () => input.dispatch(node.action, context) : void 0;
|
|
918
1098
|
if (onClick && !style.cursor) style.cursor = "pointer";
|
|
919
1099
|
switch (node.type) {
|
|
@@ -921,7 +1101,7 @@ function resolveNode(node, key, layout, context, input, countdowns) {
|
|
|
921
1101
|
return {
|
|
922
1102
|
key,
|
|
923
1103
|
tag: "div",
|
|
924
|
-
className:
|
|
1104
|
+
className: cls("box", !!onClick),
|
|
925
1105
|
style: Object.assign({ position: "relative" }, style),
|
|
926
1106
|
onClick,
|
|
927
1107
|
children: resolveChildren(
|
|
@@ -937,7 +1117,7 @@ function resolveNode(node, key, layout, context, input, countdowns) {
|
|
|
937
1117
|
return {
|
|
938
1118
|
key,
|
|
939
1119
|
tag: "div",
|
|
940
|
-
className:
|
|
1120
|
+
className: cls("flex", !!onClick),
|
|
941
1121
|
style: Object.assign({ display: "flex" }, style),
|
|
942
1122
|
onClick,
|
|
943
1123
|
children: resolveChildren(node.children, key, "flow", context, input, countdowns)
|
|
@@ -946,7 +1126,7 @@ function resolveNode(node, key, layout, context, input, countdowns) {
|
|
|
946
1126
|
return {
|
|
947
1127
|
key,
|
|
948
1128
|
tag: "div",
|
|
949
|
-
className:
|
|
1129
|
+
className: cls("repeat", !!onClick),
|
|
950
1130
|
style: Object.assign({ display: "flex" }, style),
|
|
951
1131
|
onClick,
|
|
952
1132
|
children: resolveRepeat(node, key, context, input, countdowns)
|
|
@@ -955,7 +1135,7 @@ function resolveNode(node, key, layout, context, input, countdowns) {
|
|
|
955
1135
|
return {
|
|
956
1136
|
key,
|
|
957
1137
|
tag: "div",
|
|
958
|
-
className:
|
|
1138
|
+
className: cls("tabs", false),
|
|
959
1139
|
style: Object.assign({ display: "flex" }, style),
|
|
960
1140
|
children: resolveTabs(node, key, context, input)
|
|
961
1141
|
};
|
|
@@ -963,7 +1143,7 @@ function resolveNode(node, key, layout, context, input, countdowns) {
|
|
|
963
1143
|
return {
|
|
964
1144
|
key,
|
|
965
1145
|
tag: "img",
|
|
966
|
-
className:
|
|
1146
|
+
className: cls("image", !!onClick),
|
|
967
1147
|
src: safeImageUrl(interpolate(node.src, context)),
|
|
968
1148
|
style: Object.assign({ display: "block", objectFit: "cover" }, style),
|
|
969
1149
|
onClick
|
|
@@ -972,7 +1152,7 @@ function resolveNode(node, key, layout, context, input, countdowns) {
|
|
|
972
1152
|
return {
|
|
973
1153
|
key,
|
|
974
1154
|
tag: "div",
|
|
975
|
-
className:
|
|
1155
|
+
className: cls("text", !!onClick),
|
|
976
1156
|
style: Object.assign({ wordBreak: "break-word" }, style),
|
|
977
1157
|
text: toText(interpolate(node.content, context)),
|
|
978
1158
|
onClick
|
|
@@ -981,7 +1161,7 @@ function resolveNode(node, key, layout, context, input, countdowns) {
|
|
|
981
1161
|
return {
|
|
982
1162
|
key,
|
|
983
1163
|
tag: "div",
|
|
984
|
-
className:
|
|
1164
|
+
className: cls("button", true),
|
|
985
1165
|
style: Object.assign(
|
|
986
1166
|
{
|
|
987
1167
|
display: "flex",
|
|
@@ -997,7 +1177,7 @@ function resolveNode(node, key, layout, context, input, countdowns) {
|
|
|
997
1177
|
onClick
|
|
998
1178
|
};
|
|
999
1179
|
case "countdown":
|
|
1000
|
-
return resolveCountdown(node, key, style, context, input, countdowns);
|
|
1180
|
+
return resolveCountdown(node, key, style, context, input, countdowns, hoverClass);
|
|
1001
1181
|
// 配置比解释器新时,未知类型降级为不渲染,不阻断整个弹窗
|
|
1002
1182
|
default:
|
|
1003
1183
|
return void 0;
|
|
@@ -1059,10 +1239,23 @@ function resolveTabs(node, key, context, input) {
|
|
|
1059
1239
|
};
|
|
1060
1240
|
});
|
|
1061
1241
|
}
|
|
1062
|
-
function
|
|
1063
|
-
var _a;
|
|
1242
|
+
function resolveCountdownEndTime(node, key, context, input) {
|
|
1064
1243
|
const endTime = parseEndTime(interpolate(node.to, context));
|
|
1244
|
+
if (endTime > 0) return endTime;
|
|
1245
|
+
const duration = Number(interpolate(node.duration, context));
|
|
1246
|
+
if (!isFinite(duration) || duration <= 0) return 0;
|
|
1247
|
+
let start = input.countdownStarts.get(key);
|
|
1248
|
+
if (start === void 0) {
|
|
1249
|
+
start = Date.now();
|
|
1250
|
+
input.countdownStarts.set(key, start);
|
|
1251
|
+
}
|
|
1252
|
+
return start + duration;
|
|
1253
|
+
}
|
|
1254
|
+
function resolveCountdown(node, key, style, context, input, countdowns, hoverClass) {
|
|
1255
|
+
var _a;
|
|
1256
|
+
const endTime = resolveCountdownEndTime(node, key, context, input);
|
|
1065
1257
|
const parts = computeParts(endTime);
|
|
1258
|
+
const cls = (base) => hoverClass ? `${base} ${hoverClass}` : base;
|
|
1066
1259
|
countdowns.endTimes.push(endTime);
|
|
1067
1260
|
if (node.precision === "cs") countdowns.precision = "cs";
|
|
1068
1261
|
if (endTime && node.onEnd) {
|
|
@@ -1079,7 +1272,7 @@ function resolveCountdown(node, key, style, context, input, countdowns) {
|
|
|
1079
1272
|
return {
|
|
1080
1273
|
key,
|
|
1081
1274
|
tag: "div",
|
|
1082
|
-
className: "dsl-node dsl-text dsl-countdown",
|
|
1275
|
+
className: cls("dsl-node dsl-text dsl-countdown"),
|
|
1083
1276
|
style: Object.assign({ wordBreak: "break-word" }, style),
|
|
1084
1277
|
text: node.endText || "\u5DF2\u7ED3\u675F"
|
|
1085
1278
|
};
|
|
@@ -1088,7 +1281,7 @@ function resolveCountdown(node, key, style, context, input, countdowns) {
|
|
|
1088
1281
|
return {
|
|
1089
1282
|
key,
|
|
1090
1283
|
tag: "div",
|
|
1091
|
-
className: "dsl-node dsl-text dsl-countdown",
|
|
1284
|
+
className: cls("dsl-node dsl-text dsl-countdown"),
|
|
1092
1285
|
style: Object.assign({ wordBreak: "break-word" }, style),
|
|
1093
1286
|
text: formatParts(parts, node.format)
|
|
1094
1287
|
};
|
|
@@ -1097,7 +1290,7 @@ function resolveCountdown(node, key, style, context, input, countdowns) {
|
|
|
1097
1290
|
return {
|
|
1098
1291
|
key,
|
|
1099
1292
|
tag: "div",
|
|
1100
|
-
className: "dsl-node dsl-flex dsl-countdown",
|
|
1293
|
+
className: cls("dsl-node dsl-flex dsl-countdown"),
|
|
1101
1294
|
style: Object.assign({ display: "flex" }, style),
|
|
1102
1295
|
children: resolveChildren(
|
|
1103
1296
|
node.children,
|
|
@@ -1113,6 +1306,37 @@ function toText(value) {
|
|
|
1113
1306
|
return value === void 0 || value === null ? "" : String(value);
|
|
1114
1307
|
}
|
|
1115
1308
|
|
|
1309
|
+
// src/hover.ts
|
|
1310
|
+
function collectHoverStyles(views, uid, context) {
|
|
1311
|
+
const rules = [];
|
|
1312
|
+
const classOf = /* @__PURE__ */ new WeakMap();
|
|
1313
|
+
const scope = `.dsl-r${uid}`;
|
|
1314
|
+
let seed = 0;
|
|
1315
|
+
const register = (owner, style) => {
|
|
1316
|
+
if (!owner || !style || typeof style !== "object") return;
|
|
1317
|
+
const body = declarations(toCssStyle(interpolateDeep(style, context)));
|
|
1318
|
+
if (!body) return;
|
|
1319
|
+
seed += 1;
|
|
1320
|
+
const className = `dsl-hv-${uid}-${seed}`;
|
|
1321
|
+
classOf.set(owner, className);
|
|
1322
|
+
rules.push(`${scope} .${className}:hover{${body}}`);
|
|
1323
|
+
};
|
|
1324
|
+
const walkNode = (node) => {
|
|
1325
|
+
if (!node || typeof node !== "object") return;
|
|
1326
|
+
register(node, node.hoverStyle);
|
|
1327
|
+
(node.children || []).forEach(walkNode);
|
|
1328
|
+
walkNode(node.template);
|
|
1329
|
+
};
|
|
1330
|
+
Object.keys(views).forEach((name) => {
|
|
1331
|
+
const view = views[name];
|
|
1332
|
+
if (!view || typeof view !== "object") return;
|
|
1333
|
+
const closeButton = view.stage && view.stage.closeButton;
|
|
1334
|
+
register(closeButton, closeButton && closeButton.hoverStyle);
|
|
1335
|
+
(view.nodes || []).forEach(walkNode);
|
|
1336
|
+
});
|
|
1337
|
+
return { rules, classOf };
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1116
1340
|
// src/runtime.ts
|
|
1117
1341
|
var noopEmit = () => {
|
|
1118
1342
|
};
|
|
@@ -1124,6 +1348,7 @@ function createRuntime(dsl, options = {}) {
|
|
|
1124
1348
|
editMode: !!options.editMode
|
|
1125
1349
|
};
|
|
1126
1350
|
const normalized = normalizeViews(dsl);
|
|
1351
|
+
const scopeUid = nextScopeUid();
|
|
1127
1352
|
let state = Object.assign({}, dsl.state || {});
|
|
1128
1353
|
let resolvedData = {};
|
|
1129
1354
|
let viewStack = [normalized.entry];
|
|
@@ -1132,6 +1357,7 @@ function createRuntime(dsl, options = {}) {
|
|
|
1132
1357
|
let destroyed = false;
|
|
1133
1358
|
const listeners = /* @__PURE__ */ new Set();
|
|
1134
1359
|
const countdownEnds = /* @__PURE__ */ new Map();
|
|
1360
|
+
const countdownStarts = /* @__PURE__ */ new Map();
|
|
1135
1361
|
const notify = () => {
|
|
1136
1362
|
if (destroyed) return;
|
|
1137
1363
|
listeners.forEach((fn) => fn());
|
|
@@ -1265,7 +1491,9 @@ function createRuntime(dsl, options = {}) {
|
|
|
1265
1491
|
});
|
|
1266
1492
|
}
|
|
1267
1493
|
loadData();
|
|
1494
|
+
let hover;
|
|
1268
1495
|
function getTree() {
|
|
1496
|
+
if (!hover) hover = collectHoverStyles(normalized.views, scopeUid, buildContext());
|
|
1269
1497
|
const tree = resolveTree({
|
|
1270
1498
|
normalized,
|
|
1271
1499
|
viewStack,
|
|
@@ -1275,7 +1503,11 @@ function createRuntime(dsl, options = {}) {
|
|
|
1275
1503
|
dispatch,
|
|
1276
1504
|
setState,
|
|
1277
1505
|
closeTop,
|
|
1278
|
-
countdownEnds
|
|
1506
|
+
countdownEnds,
|
|
1507
|
+
countdownStarts,
|
|
1508
|
+
scopeUid,
|
|
1509
|
+
keyframes: dsl.keyframes,
|
|
1510
|
+
hover
|
|
1279
1511
|
});
|
|
1280
1512
|
ticker.sync(tree.countdownEndTimes, tree.countdownPrecision);
|
|
1281
1513
|
return tree;
|
|
@@ -1418,6 +1650,116 @@ function validateUserFields(dsl, allowed) {
|
|
|
1418
1650
|
return issues;
|
|
1419
1651
|
}
|
|
1420
1652
|
|
|
1653
|
+
// src/validate-animate.ts
|
|
1654
|
+
function validateKeyframes(keyframes, add, warn) {
|
|
1655
|
+
if (keyframes === void 0) return [];
|
|
1656
|
+
if (typeof keyframes !== "object" || keyframes === null || Array.isArray(keyframes)) {
|
|
1657
|
+
add(
|
|
1658
|
+
"keyframes",
|
|
1659
|
+
'keyframes \u5FC5\u987B\u662F\u5BF9\u8C61\uFF0C\u5F62\u5982 { "fadeIn": { "from": {...}, "to": {...} } }'
|
|
1660
|
+
);
|
|
1661
|
+
return [];
|
|
1662
|
+
}
|
|
1663
|
+
const names = Object.keys(keyframes);
|
|
1664
|
+
names.forEach((name) => {
|
|
1665
|
+
const at = `keyframes.${name}`;
|
|
1666
|
+
if (!CSS_NAME_PATTERN.test(name)) {
|
|
1667
|
+
add(
|
|
1668
|
+
at,
|
|
1669
|
+
`keyframes \u540D "${name}" \u4E0D\u5408\u89C4\uFF1A\u5B57\u6BCD\u5F00\u5934\uFF0C\u53EA\u80FD\u7528\u5B57\u6BCD / \u6570\u5B57 / \u4E0B\u5212\u7EBF / \u4E2D\u5212\u7EBF\uFF0C\u6700\u957F 32 \u4E2A\u5B57\u7B26`
|
|
1670
|
+
);
|
|
1671
|
+
}
|
|
1672
|
+
const frames = keyframes[name];
|
|
1673
|
+
if (!frames || typeof frames !== "object" || Array.isArray(frames)) {
|
|
1674
|
+
add(at, "\u6BCF\u7EC4 keyframes \u5FC5\u987B\u662F\u5BF9\u8C61\uFF0C\u952E\u662F\u504F\u79FB\u91CF\u3001\u503C\u662F\u6837\u5F0F");
|
|
1675
|
+
return;
|
|
1676
|
+
}
|
|
1677
|
+
const offsets = Object.keys(frames);
|
|
1678
|
+
if (!offsets.length) {
|
|
1679
|
+
add(at, 'keyframes \u81F3\u5C11\u8981\u6709\u4E00\u4E2A\u5173\u952E\u5E27\uFF08\u5982 "from" \u548C "to"\uFF09');
|
|
1680
|
+
return;
|
|
1681
|
+
}
|
|
1682
|
+
offsets.forEach((offset) => {
|
|
1683
|
+
if (!isKeyframeOffset(offset)) {
|
|
1684
|
+
add(
|
|
1685
|
+
`${at}.${offset}`,
|
|
1686
|
+
`\u5173\u952E\u5E27\u7684\u504F\u79FB\u91CF\u53EA\u80FD\u5199 "from" / "to" / "50%" \u8FD9\u4E09\u79CD\u5F62\u5F0F\uFF0C"${offset}" \u4E0D\u5408\u6CD5`
|
|
1687
|
+
);
|
|
1688
|
+
}
|
|
1689
|
+
const style = frames[offset];
|
|
1690
|
+
if (!style || typeof style !== "object" || Array.isArray(style)) {
|
|
1691
|
+
add(`${at}.${offset}`, "\u5173\u952E\u5E27\u7684\u503C\u5FC5\u987B\u662F\u6837\u5F0F\u5BF9\u8C61");
|
|
1692
|
+
return;
|
|
1693
|
+
}
|
|
1694
|
+
Object.keys(style).forEach((key) => {
|
|
1695
|
+
if (ALLOWED_STYLE_KEYS.indexOf(key) === -1) {
|
|
1696
|
+
warn(
|
|
1697
|
+
`${at}.${offset}.${key}`,
|
|
1698
|
+
`\u6837\u5F0F\u5C5E\u6027 "${key}" \u4E0D\u5728\u767D\u540D\u5355\u5185\uFF0C\u6E32\u67D3\u65F6\u4F1A\u88AB\u5FFD\u7565`
|
|
1699
|
+
);
|
|
1700
|
+
}
|
|
1701
|
+
});
|
|
1702
|
+
});
|
|
1703
|
+
});
|
|
1704
|
+
return names;
|
|
1705
|
+
}
|
|
1706
|
+
function validateAnimate(animate, path, add, keyframeNames, used) {
|
|
1707
|
+
if (animate === void 0) return;
|
|
1708
|
+
if (!animate || typeof animate !== "object" || Array.isArray(animate)) {
|
|
1709
|
+
add(path, "animate \u5FC5\u987B\u662F\u5BF9\u8C61\uFF0C\u5F62\u5982 { name, duration, easing, iteration }");
|
|
1710
|
+
return;
|
|
1711
|
+
}
|
|
1712
|
+
const config = animate;
|
|
1713
|
+
if (typeof config.name !== "string" || !config.name) {
|
|
1714
|
+
add(`${path}.name`, "animate \u5FC5\u987B\u63D0\u4F9B name\uFF08keyframes \u540D\uFF09");
|
|
1715
|
+
} else {
|
|
1716
|
+
used.add(config.name);
|
|
1717
|
+
if (keyframeNames.indexOf(config.name) === -1) {
|
|
1718
|
+
add(
|
|
1719
|
+
`${path}.name`,
|
|
1720
|
+
`keyframes \u91CC\u6CA1\u6709\u5B9A\u4E49 "${config.name}"\uFF0C\u52A8\u753B\u4E0D\u4F1A\u64AD\u653E\u3002` + (keyframeNames.length ? `\u5DF2\u5B9A\u4E49\u7684\u6709\uFF1A${keyframeNames.join(" / ")}` : "\u8BF7\u5148\u5728\u9876\u5C42 keyframes \u91CC\u5B9A\u4E49\u8FD9\u7EC4\u5173\u952E\u5E27")
|
|
1721
|
+
);
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
checkMs(config.duration, `${path}.duration`, add, true);
|
|
1725
|
+
checkMs(config.delay, `${path}.delay`, add, false);
|
|
1726
|
+
if (config.easing !== void 0 && !isValidEasing(config.easing)) {
|
|
1727
|
+
add(
|
|
1728
|
+
`${path}.easing`,
|
|
1729
|
+
`\u7F13\u52A8 "${String(config.easing)}" \u4E0D\u5728\u767D\u540D\u5355\u5185\u3002\u53EF\u7528\uFF1A${ALLOWED_EASINGS.join(" / ")} \u6216 cubic-bezier(0.34, 1.56, 0.64, 1)`
|
|
1730
|
+
);
|
|
1731
|
+
}
|
|
1732
|
+
if (config.iteration !== void 0 && config.iteration !== "infinite") {
|
|
1733
|
+
const times = config.iteration;
|
|
1734
|
+
if (typeof times !== "number" || !isFinite(times) || times <= 0 || times % 1 !== 0) {
|
|
1735
|
+
add(`${path}.iteration`, "iteration \u5FC5\u987B\u662F\u6B63\u6574\u6570\uFF0C\u6216\u5B57\u7B26\u4E32 'infinite'\uFF08\u65E0\u9650\u5FAA\u73AF\uFF09");
|
|
1736
|
+
}
|
|
1737
|
+
}
|
|
1738
|
+
checkEnum(config.direction, `${path}.direction`, DIRECTIONS2, add);
|
|
1739
|
+
checkEnum(config.fill, `${path}.fill`, FILLS2, add);
|
|
1740
|
+
}
|
|
1741
|
+
var DIRECTIONS2 = ["normal", "reverse", "alternate", "alternate-reverse"];
|
|
1742
|
+
var FILLS2 = ["none", "forwards", "backwards", "both"];
|
|
1743
|
+
function checkEnum(value, path, allowed, add) {
|
|
1744
|
+
if (value === void 0) return;
|
|
1745
|
+
if (typeof value !== "string" || allowed.indexOf(value) === -1) {
|
|
1746
|
+
add(path, `\u53EA\u80FD\u662F ${allowed.join(" / ")} \u4E4B\u4E00`);
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
function checkMs(value, path, add, required) {
|
|
1750
|
+
if (value === void 0) {
|
|
1751
|
+
if (required) add(path, "animate \u5FC5\u987B\u63D0\u4F9B duration\uFF08\u6BEB\u79D2\uFF0C\u6B63\u6570\uFF09");
|
|
1752
|
+
return;
|
|
1753
|
+
}
|
|
1754
|
+
if (typeof value !== "number" || !isFinite(value) || value < 0) {
|
|
1755
|
+
add(path, `"${String(value)}" \u4E0D\u5408\u6CD5\uFF1A\u5FC5\u987B\u662F\u975E\u8D1F\u6570\u5B57\uFF0C\u5355\u4F4D\u6BEB\u79D2`);
|
|
1756
|
+
return;
|
|
1757
|
+
}
|
|
1758
|
+
if (required && value === 0) {
|
|
1759
|
+
add(path, "duration \u5FC5\u987B\u5927\u4E8E 0\uFF0C\u5426\u5219\u52A8\u753B\u4E0D\u4F1A\u64AD\u653E");
|
|
1760
|
+
}
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1421
1763
|
// src/validate.ts
|
|
1422
1764
|
var LENGTH_STYLE_KEYS = [
|
|
1423
1765
|
"width",
|
|
@@ -1491,14 +1833,26 @@ function validate(dsl, options) {
|
|
|
1491
1833
|
const dataKeys = validateData(doc.data, add);
|
|
1492
1834
|
const stateKeys = validateState(doc.state, add);
|
|
1493
1835
|
validateDerived(doc.derived, dataKeys, stateKeys, add);
|
|
1836
|
+
const keyframeNames = validateKeyframes(doc.keyframes, add, warn);
|
|
1494
1837
|
const isMulti = doc.views !== void 0;
|
|
1495
1838
|
if (isMulti) validateMultiView(doc, add);
|
|
1496
1839
|
const { views } = normalizeViews(doc);
|
|
1497
1840
|
const viewNames = Object.keys(views);
|
|
1498
|
-
const ctx = {
|
|
1841
|
+
const ctx = {
|
|
1842
|
+
add,
|
|
1843
|
+
warn,
|
|
1844
|
+
viewNames,
|
|
1845
|
+
keyframeNames,
|
|
1846
|
+
usedKeyframes: /* @__PURE__ */ new Set()
|
|
1847
|
+
};
|
|
1499
1848
|
viewNames.forEach((name) => {
|
|
1500
1849
|
validateView(views[name], isMulti ? `views.${name}` : "", ctx);
|
|
1501
1850
|
});
|
|
1851
|
+
keyframeNames.forEach((name) => {
|
|
1852
|
+
if (!ctx.usedKeyframes.has(name)) {
|
|
1853
|
+
warn(`keyframes.${name}`, `keyframes "${name}" \u6CA1\u6709\u4EFB\u4F55 animate \u5F15\u7528\uFF0C\u4E0D\u4F1A\u751F\u6548`);
|
|
1854
|
+
}
|
|
1855
|
+
});
|
|
1502
1856
|
if (options && options.userFields) {
|
|
1503
1857
|
validateUserFields(doc, options.userFields).forEach(
|
|
1504
1858
|
(issue) => add(issue.path, issue.message)
|
|
@@ -1597,8 +1951,45 @@ function validateStage(stage, add, warn, ctx, prefix) {
|
|
|
1597
1951
|
if (stage.layout !== void 0 && ["absolute", "flow"].indexOf(stage.layout) === -1) {
|
|
1598
1952
|
add("stage.layout", "stage.layout \u53EA\u80FD\u662F 'absolute'\uFF08\u9ED8\u8BA4\uFF09\u6216 'flow'");
|
|
1599
1953
|
}
|
|
1600
|
-
validateCloseButton(stage.closeButton, add, warn);
|
|
1601
1954
|
const at = (key) => prefix ? `${prefix}.stage.${key}` : `stage.${key}`;
|
|
1955
|
+
if (stage.maskStyle !== void 0) {
|
|
1956
|
+
if (typeof stage.maskStyle !== "object" || stage.maskStyle === null || Array.isArray(stage.maskStyle)) {
|
|
1957
|
+
add("stage.maskStyle", "maskStyle \u5FC5\u987B\u662F\u6837\u5F0F\u5BF9\u8C61");
|
|
1958
|
+
} else {
|
|
1959
|
+
Object.keys(stage.maskStyle).forEach((key) => {
|
|
1960
|
+
if (ALLOWED_STYLE_KEYS.indexOf(key) === -1) {
|
|
1961
|
+
warn(
|
|
1962
|
+
`stage.maskStyle.${key}`,
|
|
1963
|
+
`\u6837\u5F0F\u5C5E\u6027 "${key}" \u4E0D\u5728\u767D\u540D\u5355\u5185\uFF0C\u6E32\u67D3\u65F6\u4F1A\u88AB\u5FFD\u7565`
|
|
1964
|
+
);
|
|
1965
|
+
}
|
|
1966
|
+
});
|
|
1967
|
+
}
|
|
1968
|
+
}
|
|
1969
|
+
if (stage.maskAction !== void 0) {
|
|
1970
|
+
validateAction(stage.maskAction, at("maskAction"), ctx);
|
|
1971
|
+
if (!stage.maskClosable) {
|
|
1972
|
+
warn(
|
|
1973
|
+
"stage.maskAction",
|
|
1974
|
+
"maskAction \u53EA\u6709\u5728 maskClosable \u4E3A true \u65F6\u624D\u4F1A\u6267\u884C\u2014\u2014\u906E\u7F69\u4E0D\u53EF\u70B9\uFF0C\u52A8\u4F5C\u5C31\u6CA1\u6709\u89E6\u53D1\u65F6\u673A"
|
|
1975
|
+
);
|
|
1976
|
+
}
|
|
1977
|
+
}
|
|
1978
|
+
validateCloseButton(stage.closeButton, add, warn, ctx, at("closeButton.action"));
|
|
1979
|
+
validateAnimate(
|
|
1980
|
+
stage.animate,
|
|
1981
|
+
"stage.animate",
|
|
1982
|
+
add,
|
|
1983
|
+
ctx.keyframeNames,
|
|
1984
|
+
ctx.usedKeyframes
|
|
1985
|
+
);
|
|
1986
|
+
validateAnimate(
|
|
1987
|
+
stage.maskAnimate,
|
|
1988
|
+
"stage.maskAnimate",
|
|
1989
|
+
add,
|
|
1990
|
+
ctx.keyframeNames,
|
|
1991
|
+
ctx.usedKeyframes
|
|
1992
|
+
);
|
|
1602
1993
|
if (stage.onShow !== void 0) validateAction(stage.onShow, at("onShow"), ctx);
|
|
1603
1994
|
if (stage.onClose !== void 0) validateAction(stage.onClose, at("onClose"), ctx);
|
|
1604
1995
|
if (stage.height === "auto" && stage.layout !== "flow") {
|
|
@@ -1608,7 +1999,7 @@ function validateStage(stage, add, warn, ctx, prefix) {
|
|
|
1608
1999
|
);
|
|
1609
2000
|
}
|
|
1610
2001
|
}
|
|
1611
|
-
function validateCloseButton(config, add, warn) {
|
|
2002
|
+
function validateCloseButton(config, add, warn, ctx, actionPath) {
|
|
1612
2003
|
if (config === void 0) return;
|
|
1613
2004
|
if (typeof config !== "object" || config === null || Array.isArray(config)) {
|
|
1614
2005
|
add("stage.closeButton", "closeButton \u5FC5\u987B\u662F\u5BF9\u8C61");
|
|
@@ -1640,16 +2031,28 @@ function validateCloseButton(config, add, warn) {
|
|
|
1640
2031
|
if (config.image !== void 0 && typeof config.image !== "string") {
|
|
1641
2032
|
add("stage.closeButton.image", "image \u5FC5\u987B\u662F\u56FE\u7247\u94FE\u63A5\u5B57\u7B26\u4E32");
|
|
1642
2033
|
}
|
|
1643
|
-
|
|
1644
|
-
|
|
2034
|
+
[
|
|
2035
|
+
["style", config.style],
|
|
2036
|
+
["hoverStyle", config.hoverStyle]
|
|
2037
|
+
].forEach(([field, style]) => {
|
|
2038
|
+
if (!style) return;
|
|
2039
|
+
Object.keys(style).forEach((key) => {
|
|
1645
2040
|
if (ALLOWED_STYLE_KEYS.indexOf(key) === -1) {
|
|
1646
2041
|
warn(
|
|
1647
|
-
`stage.closeButton
|
|
2042
|
+
`stage.closeButton.${field}.${key}`,
|
|
1648
2043
|
`\u6837\u5F0F\u5C5E\u6027 "${key}" \u4E0D\u5728\u767D\u540D\u5355\u5185\uFF0C\u6E32\u67D3\u65F6\u4F1A\u88AB\u5FFD\u7565`
|
|
1649
2044
|
);
|
|
1650
2045
|
}
|
|
1651
2046
|
});
|
|
1652
|
-
}
|
|
2047
|
+
});
|
|
2048
|
+
if (config.action !== void 0) validateAction(config.action, actionPath, ctx);
|
|
2049
|
+
validateAnimate(
|
|
2050
|
+
config.animate,
|
|
2051
|
+
"stage.closeButton.animate",
|
|
2052
|
+
add,
|
|
2053
|
+
ctx.keyframeNames,
|
|
2054
|
+
ctx.usedKeyframes
|
|
2055
|
+
);
|
|
1653
2056
|
}
|
|
1654
2057
|
function validateData(data, add) {
|
|
1655
2058
|
if (data === void 0) return [];
|
|
@@ -1698,8 +2101,41 @@ function validateDerived(derived, dataKeys, stateKeys, add) {
|
|
|
1698
2101
|
}
|
|
1699
2102
|
});
|
|
1700
2103
|
}
|
|
1701
|
-
function
|
|
2104
|
+
function validateNodeStyle(style, path, ctx) {
|
|
1702
2105
|
const { add, warn } = ctx;
|
|
2106
|
+
if (style) {
|
|
2107
|
+
Object.keys(style).forEach((key) => {
|
|
2108
|
+
if (ALLOWED_STYLE_KEYS.indexOf(key) === -1) {
|
|
2109
|
+
warn(`${path}.${key}`, `\u6837\u5F0F\u5C5E\u6027 "${key}" \u4E0D\u5728\u767D\u540D\u5355\u5185\uFF0C\u6E32\u67D3\u65F6\u4F1A\u88AB\u5FFD\u7565`);
|
|
2110
|
+
return;
|
|
2111
|
+
}
|
|
2112
|
+
if (LENGTH_STYLE_KEYS.indexOf(key) > -1 && !checkLength(style[key])) {
|
|
2113
|
+
add(
|
|
2114
|
+
`${path}.${key}`,
|
|
2115
|
+
`"${style[key]}" \u4E0D\u662F\u5408\u6CD5\u957F\u5EA6\uFF0C\u652F\u6301\u6570\u5B57(px) / '100%' / 'auto' \u7B49`
|
|
2116
|
+
);
|
|
2117
|
+
}
|
|
2118
|
+
if (key === "aspectRatio") {
|
|
2119
|
+
if (!checkAspectRatio(style[key])) {
|
|
2120
|
+
add(
|
|
2121
|
+
`${path}.aspectRatio`,
|
|
2122
|
+
"aspectRatio \u8981\u5199\u6210 '750 / 200' \u6216 1.5 \u8FD9\u6837\u7684\u5BBD\u9AD8\u6BD4"
|
|
2123
|
+
);
|
|
2124
|
+
} else if (ctx.viewType === "banner") {
|
|
2125
|
+
const ratio = parseAspectRatio(style[key]);
|
|
2126
|
+
if (ratio !== null && ratio < BANNER_MIN_ASPECT_RATIO) {
|
|
2127
|
+
add(
|
|
2128
|
+
`${path}.aspectRatio`,
|
|
2129
|
+
`banner \u7684\u5BBD\u9AD8\u6BD4\u4E0D\u80FD\u5C0F\u4E8E ${BANNER_MIN_ASPECT_RATIO}:1\uFF08\u5F53\u524D\u7EA6 ${ratio.toFixed(1)}:1\uFF09\u3002banner \u5751\u4F4D\u5E38\u9A7B\u9875\u9762\u9876\u90E8\uFF0C\u6BD4\u4F8B\u8D8A\u65B9\u5728\u5BBD\u5C4F\u4E0A\u8D8A\u9AD8 \u2014\u2014 1800px \u5BBD\u7684\u5751\u4F4D\u91CC\uFF0C${ratio.toFixed(1)}:1 \u4F1A\u7B97\u51FA ${Math.round(1800 / ratio)}px \u9AD8\uFF0C\u5403\u6389\u9996\u5C4F\u4E00\u5927\u5757`
|
|
2130
|
+
);
|
|
2131
|
+
}
|
|
2132
|
+
}
|
|
2133
|
+
}
|
|
2134
|
+
});
|
|
2135
|
+
}
|
|
2136
|
+
}
|
|
2137
|
+
function validateNode(node, path, layout, ctx) {
|
|
2138
|
+
const { add } = ctx;
|
|
1703
2139
|
if (!node || typeof node !== "object" || Array.isArray(node)) {
|
|
1704
2140
|
add(path, "\u8282\u70B9\u5FC5\u987B\u662F\u5BF9\u8C61");
|
|
1705
2141
|
return;
|
|
@@ -1725,36 +2161,15 @@ function validateNode(node, path, layout, ctx) {
|
|
|
1725
2161
|
});
|
|
1726
2162
|
}
|
|
1727
2163
|
}
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
`"${node.style[key]}" \u4E0D\u662F\u5408\u6CD5\u957F\u5EA6\uFF0C\u652F\u6301\u6570\u5B57(px) / '100%' / 'auto' \u7B49`
|
|
1738
|
-
);
|
|
1739
|
-
}
|
|
1740
|
-
if (key === "aspectRatio") {
|
|
1741
|
-
if (!checkAspectRatio(node.style[key])) {
|
|
1742
|
-
add(
|
|
1743
|
-
`${path}.style.aspectRatio`,
|
|
1744
|
-
"aspectRatio \u8981\u5199\u6210 '750 / 200' \u6216 1.5 \u8FD9\u6837\u7684\u5BBD\u9AD8\u6BD4"
|
|
1745
|
-
);
|
|
1746
|
-
} else if (ctx.viewType === "banner") {
|
|
1747
|
-
const ratio = parseAspectRatio(node.style[key]);
|
|
1748
|
-
if (ratio !== null && ratio < BANNER_MIN_ASPECT_RATIO) {
|
|
1749
|
-
add(
|
|
1750
|
-
`${path}.style.aspectRatio`,
|
|
1751
|
-
`banner \u7684\u5BBD\u9AD8\u6BD4\u4E0D\u80FD\u5C0F\u4E8E ${BANNER_MIN_ASPECT_RATIO}:1\uFF08\u5F53\u524D\u7EA6 ${ratio.toFixed(1)}:1\uFF09\u3002banner \u5751\u4F4D\u5E38\u9A7B\u9875\u9762\u9876\u90E8\uFF0C\u6BD4\u4F8B\u8D8A\u65B9\u5728\u5BBD\u5C4F\u4E0A\u8D8A\u9AD8 \u2014\u2014 1800px \u5BBD\u7684\u5751\u4F4D\u91CC\uFF0C${ratio.toFixed(1)}:1 \u4F1A\u7B97\u51FA ${Math.round(1800 / ratio)}px \u9AD8\uFF0C\u5403\u6389\u9996\u5C4F\u4E00\u5927\u5757`
|
|
1752
|
-
);
|
|
1753
|
-
}
|
|
1754
|
-
}
|
|
1755
|
-
}
|
|
1756
|
-
});
|
|
1757
|
-
}
|
|
2164
|
+
validateNodeStyle(node.style, `${path}.style`, ctx);
|
|
2165
|
+
validateNodeStyle(node.hoverStyle, `${path}.hoverStyle`, ctx);
|
|
2166
|
+
validateAnimate(
|
|
2167
|
+
node.animate,
|
|
2168
|
+
`${path}.animate`,
|
|
2169
|
+
add,
|
|
2170
|
+
ctx.keyframeNames,
|
|
2171
|
+
ctx.usedKeyframes
|
|
2172
|
+
);
|
|
1758
2173
|
if (node.visibleWhen !== void 0) {
|
|
1759
2174
|
if (typeof node.visibleWhen !== "string") {
|
|
1760
2175
|
add(`${path}.visibleWhen`, "visibleWhen \u5FC5\u987B\u662F\u8868\u8FBE\u5F0F\u5B57\u7B26\u4E32");
|
|
@@ -1767,7 +2182,7 @@ function validateNode(node, path, layout, ctx) {
|
|
|
1767
2182
|
validateNodeByType(node, path, ctx);
|
|
1768
2183
|
}
|
|
1769
2184
|
function validateNodeByType(node, path, ctx) {
|
|
1770
|
-
const { add } = ctx;
|
|
2185
|
+
const { add, warn } = ctx;
|
|
1771
2186
|
if (node.type === "image" && !node.src) {
|
|
1772
2187
|
add(`${path}.src`, "image \u5FC5\u987B\u63D0\u4F9B src");
|
|
1773
2188
|
}
|
|
@@ -1788,9 +2203,25 @@ function validateNodeByType(node, path, ctx) {
|
|
|
1788
2203
|
}
|
|
1789
2204
|
}
|
|
1790
2205
|
if (node.type === "countdown") {
|
|
1791
|
-
if (!node.to) {
|
|
1792
|
-
add(
|
|
1793
|
-
|
|
2206
|
+
if (!node.to && node.duration === void 0) {
|
|
2207
|
+
add(
|
|
2208
|
+
`${path}.to`,
|
|
2209
|
+
"countdown \u5FC5\u987B\u63D0\u4F9B to\uFF08\u7ED3\u675F\u65F6\u95F4\uFF09\u6216 duration\uFF08\u76F8\u5BF9\u65F6\u957F\uFF0C\u6BEB\u79D2\uFF0C\u4ECE\u8BE5\u89C6\u56FE\u5C55\u793A\u90A3\u4E00\u523B\u8D77\u7B97\uFF09"
|
|
2210
|
+
);
|
|
2211
|
+
}
|
|
2212
|
+
if (node.duration !== void 0) {
|
|
2213
|
+
const duration = node.duration;
|
|
2214
|
+
if (typeof duration !== "number" || !isFinite(duration) || duration <= 0) {
|
|
2215
|
+
add(`${path}.duration`, "duration \u5FC5\u987B\u662F\u6B63\u6570\uFF0C\u5355\u4F4D\u6BEB\u79D2\uFF085 \u5206\u949F\u5C31\u5199 300000\uFF09");
|
|
2216
|
+
}
|
|
2217
|
+
}
|
|
2218
|
+
if (node.to && node.duration !== void 0) {
|
|
2219
|
+
warn(
|
|
2220
|
+
`${path}.duration`,
|
|
2221
|
+
"\u540C\u65F6\u5199\u4E86 to \u548C duration\uFF0C\u8FD0\u884C\u65F6\u4EE5 to \u4E3A\u51C6\uFF0Cduration \u4E0D\u4F1A\u751F\u6548"
|
|
2222
|
+
);
|
|
2223
|
+
}
|
|
2224
|
+
if (!node.to) ; else if (!isValidEndTime(node.to)) {
|
|
1794
2225
|
add(
|
|
1795
2226
|
`${path}.to`,
|
|
1796
2227
|
`"${node.to}" \u4E0D\u662F\u80FD\u8BC6\u522B\u7684\u65F6\u95F4\u3002\u53EF\u4EE5\u5199 "2026-09-01 18:00:00" / "2026-09-01" / "2026\u5E749\u67081\u65E5 18\u70B9" / ISO \u683C\u5F0F / \u65F6\u95F4\u6233`
|
|
@@ -1883,10 +2314,10 @@ function formatIssues(issues) {
|
|
|
1883
2314
|
}
|
|
1884
2315
|
|
|
1885
2316
|
// src/host-capabilities.ts
|
|
1886
|
-
var HOST_SOURCE_NAMES = ["
|
|
2317
|
+
var HOST_SOURCE_NAMES = ["userStatistics", "listRenewTiers"];
|
|
1887
2318
|
var HOST_HANDLER_NAMES = [];
|
|
1888
2319
|
var HOST_SOURCE_LABELS = {
|
|
1889
|
-
|
|
2320
|
+
userStatistics: "\u7528\u6237\u6570\u636E\u7EDF\u8BA1\uFF08\u7D2F\u8BA1\u642C\u5BB6\u6570 / \u6B21\u6570\u4F59\u989D / AI \u4F18\u5316\u6B21\u6570\u7B49\uFF0C\u6241\u5E73\u5BF9\u8C61\uFF0C\u5B57\u6BB5\u540D\u4E3A\u540E\u7AEF snake_case\uFF09",
|
|
1890
2321
|
listRenewTiers: "\u7EED\u8D39\u4EF7\u683C\u6863\u4F4D\u5217\u8868\uFF08\u6708\u4ED8/\u5B63\u4ED8/\u534A\u5E74/\u5E74\u4ED8\uFF0C\u542B\u4E0B\u5355\u5730\u5740\uFF09"
|
|
1891
2322
|
};
|
|
1892
2323
|
var HOST_HANDLER_LABELS = {};
|
|
@@ -1898,9 +2329,11 @@ function isRegisteredHostHandler(name) {
|
|
|
1898
2329
|
}
|
|
1899
2330
|
|
|
1900
2331
|
exports.ACTION_TYPES = ACTION_TYPES;
|
|
2332
|
+
exports.ALLOWED_EASINGS = ALLOWED_EASINGS;
|
|
1901
2333
|
exports.ALLOWED_STYLE_KEYS = ALLOWED_STYLE_KEYS;
|
|
1902
2334
|
exports.BANNER_MIN_ASPECT_RATIO = BANNER_MIN_ASPECT_RATIO;
|
|
1903
2335
|
exports.CLOSE_POSITIONS = CLOSE_POSITIONS;
|
|
2336
|
+
exports.CSS_NAME_PATTERN = CSS_NAME_PATTERN;
|
|
1904
2337
|
exports.DEFAULT_USER_FIELDS = DEFAULT_USER_FIELDS;
|
|
1905
2338
|
exports.DSL_VERSION = DSL_VERSION;
|
|
1906
2339
|
exports.HOST_HANDLER_LABELS = HOST_HANDLER_LABELS;
|
|
@@ -1919,14 +2352,17 @@ exports.formatIssues = formatIssues;
|
|
|
1919
2352
|
exports.formatParts = formatParts;
|
|
1920
2353
|
exports.interpolate = interpolate;
|
|
1921
2354
|
exports.interpolateDeep = interpolateDeep;
|
|
2355
|
+
exports.isKeyframeOffset = isKeyframeOffset;
|
|
1922
2356
|
exports.isLength = isLength;
|
|
1923
2357
|
exports.isRegisteredHostHandler = isRegisteredHostHandler;
|
|
1924
2358
|
exports.isRegisteredHostSource = isRegisteredHostSource;
|
|
2359
|
+
exports.isValidEasing = isValidEasing;
|
|
1925
2360
|
exports.isValidEndTime = isValidEndTime;
|
|
1926
2361
|
exports.normalizeViews = normalizeViews;
|
|
1927
2362
|
exports.parseEndTime = parseEndTime;
|
|
1928
2363
|
exports.safeImageUrl = safeImageUrl;
|
|
1929
2364
|
exports.safeUrl = safeUrl;
|
|
2365
|
+
exports.sanitizeCssValue = sanitizeCssValue;
|
|
1930
2366
|
exports.toCssStyle = toCssStyle;
|
|
1931
2367
|
exports.toLength = toLength;
|
|
1932
2368
|
exports.validate = validate;
|