@sdata/web-vue 4.0.0 → 4.1.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.
Files changed (47) hide show
  1. package/dist/sd.css +71 -0
  2. package/dist/sd.min.css +2 -2
  3. package/es/badge/badge.vue.d.ts +2 -0
  4. package/es/badge/badge.vue_vue_type_script_setup_true_lang.js +19 -4
  5. package/es/badge/index.d.ts +3 -0
  6. package/es/components.d.ts +2 -0
  7. package/es/index.css +71 -0
  8. package/es/index.d.ts +2 -0
  9. package/es/index.js +4 -1
  10. package/es/index.scss +1 -0
  11. package/es/number-flow/continuous.d.ts +2 -0
  12. package/es/number-flow/continuous.js +7 -0
  13. package/es/number-flow/formatter.d.ts +15 -0
  14. package/es/number-flow/formatter.js +54 -0
  15. package/es/number-flow/group-key.d.ts +11 -0
  16. package/es/number-flow/group-key.js +4 -0
  17. package/es/number-flow/index.d.ts +63 -0
  18. package/es/number-flow/index.js +15 -0
  19. package/es/number-flow/number-flow-group.js +5 -0
  20. package/es/number-flow/number-flow-group.vue.d.ts +12 -0
  21. package/es/number-flow/number-flow-group.vue_vue_type_script_setup_true_lang.js +58 -0
  22. package/es/number-flow/number-flow.js +5 -0
  23. package/es/number-flow/number-flow.vue.d.ts +20 -0
  24. package/es/number-flow/number-flow.vue_vue_type_script_setup_true_lang.js +284 -0
  25. package/es/number-flow/style/css.js +2 -0
  26. package/es/number-flow/style/index.css +85 -0
  27. package/es/number-flow/style/index.d.ts +2 -0
  28. package/es/number-flow/style/index.js +2 -0
  29. package/es/number-flow/style/index.scss +93 -0
  30. package/es/number-flow/style/token.scss +5 -0
  31. package/es/number-flow/types.d.ts +46 -0
  32. package/es/number-flow/use-can-animate.d.ts +4 -0
  33. package/es/number-flow/use-can-animate.js +30 -0
  34. package/es/rich-text-editor/index.d.ts +3 -3
  35. package/es/rich-text-editor/rich-text-editor.vue.d.ts +1 -1
  36. package/es/sd-vue.js +3 -0
  37. package/es/statistic/countdown.vue.d.ts +9 -0
  38. package/es/statistic/countdown.vue_vue_type_script_setup_true_lang.js +29 -2
  39. package/es/statistic/index.d.ts +15 -0
  40. package/es/statistic/statistic.vue.d.ts +3 -3
  41. package/es/statistic/statistic.vue_vue_type_script_setup_true_lang.js +31 -62
  42. package/es/statistic/style/index.css +3 -0
  43. package/es/statistic/style/index.scss +5 -0
  44. package/json/vetur-attributes.json +8 -0
  45. package/json/vetur-tags.json +9 -1
  46. package/json/web-types.json +29 -1
  47. package/package.json +1 -1
@@ -0,0 +1,284 @@
1
+ import _objectSpread2 from "../_virtual/_@oxc-project_runtime@0.142.0/helpers/esm/objectSpread2.js";
2
+ import { getPrefixCls } from "../_utils/global-config.js";
3
+ import _asyncToGenerator from "../_virtual/_@oxc-project_runtime@0.142.0/helpers/esm/asyncToGenerator.js";
4
+ import { GROUP_KEY } from "./group-key.js";
5
+ import { formatNumberFlow } from "./formatter.js";
6
+ import { useCanAnimate } from "./use-can-animate.js";
7
+ import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, defineComponent, inject, nextTick, normalizeClass, onBeforeUnmount, onMounted, openBlock, renderList, renderSlot, resolveDynamicComponent, shallowRef, toDisplayString, unref, useSlots, useTemplateRef, watch, withCtx } from "vue";
8
+ //#region components/number-flow/number-flow.vue?vue&type=script&setup=true&lang.ts
9
+ var _hoisted_1 = ["data-number-flow-id", "aria-label"];
10
+ var _hoisted_2 = ["data-number-flow-part"];
11
+ var number_flow_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent(_objectSpread2(_objectSpread2({}, { name: "NumberFlow" }), {}, {
12
+ __name: "number-flow",
13
+ props: {
14
+ value: {},
15
+ locales: {},
16
+ format: {},
17
+ prefix: {},
18
+ suffix: {},
19
+ trend: {
20
+ type: [Number, Function],
21
+ default: (oldValue, newValue) => Math.sign(newValue - oldValue)
22
+ },
23
+ plugins: {},
24
+ animated: {
25
+ type: Boolean,
26
+ default: true
27
+ },
28
+ transformTiming: { default: () => (() => ({
29
+ duration: 900,
30
+ easing: "cubic-bezier(0.16, 1, 0.3, 1)"
31
+ })) },
32
+ spinTiming: {},
33
+ opacityTiming: { default: () => (() => ({
34
+ duration: 450,
35
+ easing: "ease-out"
36
+ })) },
37
+ respectMotionPreference: {
38
+ type: Boolean,
39
+ default: true
40
+ },
41
+ digits: {},
42
+ willChange: {
43
+ type: Boolean,
44
+ default: false
45
+ },
46
+ nonce: {}
47
+ },
48
+ emits: ["animationsstart", "animationsfinish"],
49
+ setup(__props, { expose: __expose, emit: __emit }) {
50
+ const emit = __emit;
51
+ const prefixCls = getPrefixCls("number-flow");
52
+ const slots = useSlots();
53
+ const rootRef = useTemplateRef("rootRef");
54
+ const styleScope = shallowRef();
55
+ onMounted(() => {
56
+ styleScope.value = `sd-number-flow-${crypto.randomUUID()}`;
57
+ });
58
+ const numberFormatter = computed(() => new Intl.NumberFormat(__props.locales, __props.format));
59
+ function formatData(val) {
60
+ return formatNumberFlow(val, numberFormatter.value, slots.prefix ? void 0 : __props.prefix, slots.suffix ? void 0 : __props.suffix);
61
+ }
62
+ const previousData = shallowRef(formatData(__props.value));
63
+ const currentValue = computed(() => __props.value);
64
+ const currentData = computed(() => formatData(__props.value));
65
+ const animationPhase = shallowRef("idle");
66
+ const isAnimating = computed(() => animationPhase.value === "animating");
67
+ let animationVersion = 0;
68
+ let finishTimer;
69
+ const resolvedTransformTiming = computed(() => typeof __props.transformTiming === "function" ? __props.transformTiming() : __props.transformTiming);
70
+ const resolvedOpacityTiming = computed(() => typeof __props.opacityTiming === "function" ? __props.opacityTiming() : __props.opacityTiming);
71
+ const transformDuration = computed(() => typeof resolvedTransformTiming.value.duration === "number" ? resolvedTransformTiming.value.duration : 900);
72
+ const transformEasing = computed(() => {
73
+ var _resolvedTransformTim, _resolvedTransformTim2;
74
+ return (_resolvedTransformTim = (_resolvedTransformTim2 = resolvedTransformTiming.value.easing) === null || _resolvedTransformTim2 === void 0 ? void 0 : _resolvedTransformTim2.toString()) !== null && _resolvedTransformTim !== void 0 ? _resolvedTransformTim : "cubic-bezier(0.16, 1, 0.3, 1)";
75
+ });
76
+ const spinDuration = computed(() => {
77
+ if (__props.spinTiming && typeof __props.spinTiming.duration === "number") return __props.spinTiming.duration;
78
+ return transformDuration.value;
79
+ });
80
+ const spinEasing = computed(() => {
81
+ var _props$spinTiming;
82
+ if ((_props$spinTiming = __props.spinTiming) === null || _props$spinTiming === void 0 ? void 0 : _props$spinTiming.easing) return __props.spinTiming.easing.toString();
83
+ return transformEasing.value;
84
+ });
85
+ const opacityDuration = computed(() => typeof resolvedOpacityTiming.value.duration === "number" ? resolvedOpacityTiming.value.duration : 450);
86
+ const motionCanAnimate = useCanAnimate({ respectMotionPreference: () => __props.respectMotionPreference });
87
+ const canAnimate = computed(() => __props.animated && motionCanAnimate.value);
88
+ const computedTrend = computed(() => typeof __props.trend === "function" ? __props.trend(previousData.value.value, currentData.value.value) : __props.trend);
89
+ const classes = computed(() => [prefixCls, {
90
+ [`${prefixCls}-animated`]: canAnimate.value,
91
+ [`${prefixCls}-prepared`]: animationPhase.value === "prepared",
92
+ [`${prefixCls}-animating`]: isAnimating.value,
93
+ [`${prefixCls}-will-change`]: __props.willChange
94
+ }]);
95
+ function sanitizeDuration(duration) {
96
+ return Number.isFinite(duration) && duration >= 0 ? duration : 0;
97
+ }
98
+ function sanitizeEasing(easing) {
99
+ return /^[a-zA-Z0-9(),.\s+-]+$/.test(easing) ? easing : "linear";
100
+ }
101
+ const dynamicStyles = computed(() => {
102
+ if (!styleScope.value) return "";
103
+ const rootSelector = `[data-number-flow-id="${styleScope.value}"]`;
104
+ const rules = [`${rootSelector}{--sd-number-flow-duration:${sanitizeDuration(transformDuration.value)}ms;--sd-number-flow-easing:${sanitizeEasing(transformEasing.value)};--sd-number-flow-spin-duration:${sanitizeDuration(spinDuration.value)}ms;--sd-number-flow-spin-easing:${sanitizeEasing(spinEasing.value)};--sd-number-flow-opacity-duration:${sanitizeDuration(opacityDuration.value)}ms}`];
105
+ currentData.value.parts.forEach((part, index) => {
106
+ if (part.digit === void 0) return;
107
+ const delta = getDigitDelta(part);
108
+ const distance = Math.abs(delta);
109
+ rules.push(`${rootSelector} [data-number-flow-part="${index}"]{--sd-number-flow-start:${delta < 0 ? -distance : 0};--sd-number-flow-end:${delta > 0 ? -distance : 0}}`);
110
+ });
111
+ return rules.join("");
112
+ });
113
+ function getPreviousDigit(part) {
114
+ var _previousData$value$p, _previousData$value$p2;
115
+ return (_previousData$value$p = (_previousData$value$p2 = previousData.value.parts.find((candidate) => candidate.key === part.key)) === null || _previousData$value$p2 === void 0 ? void 0 : _previousData$value$p2.digit) !== null && _previousData$value$p !== void 0 ? _previousData$value$p : part.digit;
116
+ }
117
+ const highestChangedPosition = computed(() => {
118
+ const previousDigits = new Map(previousData.value.parts.filter((part) => part.digit !== void 0).map((part) => [part.key, part]));
119
+ const changedPositions = currentData.value.parts.flatMap((part) => {
120
+ var _part$position;
121
+ if (part.digit === void 0) return [];
122
+ const previous = previousDigits.get(part.key);
123
+ return (previous === null || previous === void 0 ? void 0 : previous.digit) === part.digit ? [] : [(_part$position = part.position) !== null && _part$position !== void 0 ? _part$position : 0];
124
+ });
125
+ return changedPositions.length === 0 ? void 0 : Math.max(...changedPositions);
126
+ });
127
+ function getDigitDelta(part) {
128
+ var _props$digits$max, _props$digits, _part$position2, _part$position3, _props$plugins;
129
+ const current = part.digit;
130
+ const previous = getPreviousDigit(part);
131
+ const length = ((_props$digits$max = (_props$digits = __props.digits) === null || _props$digits === void 0 || (_props$digits = _props$digits[(_part$position2 = part.position) !== null && _part$position2 !== void 0 ? _part$position2 : 0]) === null || _props$digits === void 0 ? void 0 : _props$digits.max) !== null && _props$digits$max !== void 0 ? _props$digits$max : 9) + 1;
132
+ const context = {
133
+ position: (_part$position3 = part.position) !== null && _part$position3 !== void 0 ? _part$position3 : 0,
134
+ length,
135
+ trend: computedTrend.value,
136
+ highestChangedPosition: highestChangedPosition.value
137
+ };
138
+ for (const plugin of (_props$plugins = __props.plugins) !== null && _props$plugins !== void 0 ? _props$plugins : []) {
139
+ var _plugin$getDelta;
140
+ const delta = (_plugin$getDelta = plugin.getDelta) === null || _plugin$getDelta === void 0 ? void 0 : _plugin$getDelta.call(plugin, current, previous, context);
141
+ if (delta !== void 0) return delta;
142
+ }
143
+ const difference = current - previous;
144
+ if (computedTrend.value < 0 && current > previous) return current - length - previous;
145
+ if (computedTrend.value > 0 && current < previous) return length - previous + current;
146
+ return difference;
147
+ }
148
+ function getDigitSequence(part) {
149
+ var _props$digits$max2, _props$digits2, _part$position4;
150
+ const current = part.digit;
151
+ const previous = getPreviousDigit(part);
152
+ const delta = getDigitDelta(part);
153
+ if (animationPhase.value === "idle" || delta === 0) return [{
154
+ key: `current-${current}`,
155
+ value: current
156
+ }];
157
+ const length = ((_props$digits$max2 = (_props$digits2 = __props.digits) === null || _props$digits2 === void 0 || (_props$digits2 = _props$digits2[(_part$position4 = part.position) !== null && _part$position4 !== void 0 ? _part$position4 : 0]) === null || _props$digits2 === void 0 ? void 0 : _props$digits2.max) !== null && _props$digits$max2 !== void 0 ? _props$digits$max2 : 9) + 1;
158
+ const start = delta > 0 ? previous : current;
159
+ return Array.from({ length: Math.abs(delta) + 1 }, (_, index) => ({
160
+ key: `step-${index}`,
161
+ value: (start + index) % length
162
+ }));
163
+ }
164
+ function finishAnimation(version = animationVersion) {
165
+ if (version !== animationVersion || animationPhase.value === "idle") return;
166
+ clearTimeout(finishTimer);
167
+ finishTimer = void 0;
168
+ previousData.value = currentData.value;
169
+ animationPhase.value = "idle";
170
+ emit("animationsfinish");
171
+ }
172
+ const group = inject(GROUP_KEY, void 0);
173
+ function prepareAnimation(oldData, data, force = false) {
174
+ var _props$plugins2;
175
+ const version = ++animationVersion;
176
+ clearTimeout(finishTimer);
177
+ finishTimer = void 0;
178
+ previousData.value = oldData;
179
+ (_props$plugins2 = __props.plugins) === null || _props$plugins2 === void 0 || _props$plugins2.forEach((plugin) => {
180
+ var _plugin$onUpdate;
181
+ return (_plugin$onUpdate = plugin.onUpdate) === null || _plugin$onUpdate === void 0 ? void 0 : _plugin$onUpdate.call(plugin, {
182
+ value: data.value,
183
+ previousValue: oldData.value,
184
+ trend: computedTrend.value
185
+ });
186
+ });
187
+ if (!canAnimate.value || !force && data.value === oldData.value) {
188
+ previousData.value = data;
189
+ animationPhase.value = "idle";
190
+ return;
191
+ }
192
+ animationPhase.value = "prepared";
193
+ return version;
194
+ }
195
+ function commitAnimationStart(version) {
196
+ var _rootRef$value;
197
+ if (version !== animationVersion || animationPhase.value !== "prepared") return false;
198
+ (_rootRef$value = rootRef.value) === null || _rootRef$value === void 0 || _rootRef$value.getBoundingClientRect();
199
+ return true;
200
+ }
201
+ function startAnimation(version) {
202
+ if (version !== animationVersion || animationPhase.value !== "prepared") return;
203
+ animationPhase.value = "animating";
204
+ emit("animationsstart");
205
+ finishTimer = setTimeout(() => finishAnimation(version), spinDuration.value + 50);
206
+ }
207
+ if (group) {
208
+ const unregister = group.register({
209
+ value: currentValue,
210
+ prepare: () => prepareAnimation(previousData.value, currentData.value, true),
211
+ commit: commitAnimationStart,
212
+ start: startAnimation
213
+ });
214
+ onBeforeUnmount(unregister);
215
+ } else watch(currentValue, function() {
216
+ var _ref = _asyncToGenerator(function* (data, oldData) {
217
+ const version = prepareAnimation(formatData(oldData), formatData(data));
218
+ if (version === void 0) return;
219
+ yield nextTick();
220
+ if (!commitAnimationStart(version)) return;
221
+ startAnimation(version);
222
+ });
223
+ return function(_x, _x2) {
224
+ return _ref.apply(this, arguments);
225
+ };
226
+ }(), { flush: "pre" });
227
+ onBeforeUnmount(() => clearTimeout(finishTimer));
228
+ __expose({ get el() {
229
+ return rootRef.value;
230
+ } });
231
+ return (_ctx, _cache) => {
232
+ return openBlock(), createElementBlock("span", {
233
+ ref_key: "rootRef",
234
+ ref: rootRef,
235
+ class: normalizeClass(classes.value),
236
+ "data-number-flow-id": styleScope.value,
237
+ role: "img",
238
+ "aria-label": currentData.value.valueAsString
239
+ }, [
240
+ (openBlock(), createBlock(resolveDynamicComponent("style"), { nonce: __props.nonce }, {
241
+ default: withCtx(() => [createTextVNode(toDisplayString(dynamicStyles.value), 1)]),
242
+ _: 1
243
+ }, 8, ["nonce"])),
244
+ _ctx.$slots.prefix ? (openBlock(), createElementBlock("span", {
245
+ key: 0,
246
+ class: normalizeClass(`${unref(prefixCls)}-custom-prefix`),
247
+ "aria-hidden": "true"
248
+ }, [renderSlot(_ctx.$slots, "prefix")], 2)) : createCommentVNode("", true),
249
+ createElementVNode("span", {
250
+ class: normalizeClass(`${unref(prefixCls)}-content`),
251
+ "aria-hidden": "true"
252
+ }, [(openBlock(true), createElementBlock(Fragment, null, renderList(currentData.value.parts, (part, partIndex) => {
253
+ return openBlock(), createElementBlock("span", {
254
+ key: part.key,
255
+ "data-number-flow-part": partIndex,
256
+ class: normalizeClass([
257
+ `${unref(prefixCls)}-part`,
258
+ `${unref(prefixCls)}-${part.type}`,
259
+ { [`${unref(prefixCls)}-digit`]: part.digit !== void 0 }
260
+ ])
261
+ }, [part.digit !== void 0 ? (openBlock(), createElementBlock("span", {
262
+ key: 0,
263
+ class: normalizeClass(`${unref(prefixCls)}-digit-track`)
264
+ }, [(openBlock(true), createElementBlock(Fragment, null, renderList(getDigitSequence(part), (digit) => {
265
+ return openBlock(), createElementBlock("span", {
266
+ key: digit.key,
267
+ class: normalizeClass(`${unref(prefixCls)}-digit-value`)
268
+ }, toDisplayString(digit.value), 3);
269
+ }), 128))], 2)) : (openBlock(), createElementBlock("span", {
270
+ key: 1,
271
+ class: normalizeClass(`${unref(prefixCls)}-symbol`)
272
+ }, toDisplayString(part.value), 3))], 10, _hoisted_2);
273
+ }), 128))], 2),
274
+ _ctx.$slots.suffix ? (openBlock(), createElementBlock("span", {
275
+ key: 1,
276
+ class: normalizeClass(`${unref(prefixCls)}-custom-suffix`),
277
+ "aria-hidden": "true"
278
+ }, [renderSlot(_ctx.$slots, "suffix")], 2)) : createCommentVNode("", true)
279
+ ], 10, _hoisted_1);
280
+ };
281
+ }
282
+ }));
283
+ //#endregion
284
+ export { number_flow_vue_vue_type_script_setup_true_lang_default as default };
@@ -0,0 +1,2 @@
1
+ import "../../style/index.css";
2
+ import "./index.css";
@@ -0,0 +1,85 @@
1
+ /******** borderSize *******/
2
+ /******** borderStyle *******/
3
+ /******** radius *******/
4
+ /******** shadow distance *******/
5
+ /******** size *******/
6
+ /******** spacing *******/
7
+ /******** shadow *******/
8
+ /******** opacity *******/
9
+ /******** fontSize *******/
10
+ /******** fontWeight ********/
11
+ /******** Primary *******/
12
+ /******** success *******/
13
+ /******** warning *******/
14
+ /******** danger *******/
15
+ /******** link *******/
16
+ /******** radius *******/
17
+ /********* icon hover *********/
18
+ .sd-number-flow {
19
+ display: inline-flex;
20
+ align-items: baseline;
21
+ line-height: 1;
22
+ direction: ltr;
23
+ white-space: nowrap;
24
+ isolation: isolate;
25
+ }
26
+ .sd-number-flow-content, .sd-number-flow-part, .sd-number-flow-digit-track, .sd-number-flow-digit-value, .sd-number-flow-symbol {
27
+ display: inline-block;
28
+ }
29
+ .sd-number-flow-content {
30
+ margin: -0.25em -0.2em;
31
+ padding: 0.25em 0.2em;
32
+ overflow: hidden;
33
+ }
34
+ .sd-number-flow-part {
35
+ position: relative;
36
+ vertical-align: bottom;
37
+ }
38
+ .sd-number-flow-digit {
39
+ height: 1em;
40
+ overflow: hidden;
41
+ }
42
+ .sd-number-flow-digit-track {
43
+ display: flex;
44
+ flex-direction: column;
45
+ height: 1em;
46
+ transform: translateY(calc(1em * var(--sd-number-flow-start)));
47
+ }
48
+ .sd-number-flow-digit-value {
49
+ flex: 0 0 1em;
50
+ height: 1em;
51
+ line-height: 1;
52
+ text-align: center;
53
+ font-variant-numeric: tabular-nums;
54
+ }
55
+ .sd-number-flow-prepared .sd-number-flow-digit-track {
56
+ transition: none;
57
+ }
58
+ .sd-number-flow-animating .sd-number-flow-digit-track {
59
+ transform: translateY(calc(1em * var(--sd-number-flow-end)));
60
+ transition: transform var(--sd-number-flow-spin-duration, var(--sd-number-flow-duration)) var(--sd-number-flow-spin-easing, var(--sd-number-flow-easing)), opacity var(--sd-number-flow-opacity-duration) ease-out;
61
+ }
62
+ .sd-number-flow-symbol {
63
+ white-space: pre;
64
+ }
65
+ .sd-number-flow-will-change :is(.sd-number-flow-content, .sd-number-flow-part, .sd-number-flow-digit-track, .sd-number-flow-symbol) {
66
+ will-change: transform;
67
+ }
68
+ .sd-number-flow-custom-prefix {
69
+ margin-right: 4px;
70
+ }
71
+ .sd-number-flow-custom-suffix {
72
+ margin-left: 4px;
73
+ }
74
+
75
+ .sd-number-flow-group {
76
+ display: inline-flex;
77
+ gap: 4px;
78
+ align-items: baseline;
79
+ }
80
+
81
+ @media (prefers-reduced-motion: reduce) {
82
+ .sd-number-flow-digit-track {
83
+ transition: none;
84
+ }
85
+ }
@@ -0,0 +1,2 @@
1
+ import '../../style/index.scss';
2
+ import './index.scss';
@@ -0,0 +1,2 @@
1
+ import "../../style/index.scss";
2
+ import "./index.scss";
@@ -0,0 +1,93 @@
1
+ @use 'sass:string';
2
+ @use '@style/theme/index.scss' as theme;
3
+ @use '@components/number-flow/style/token.scss' as *;
4
+
5
+ $number-flow-prefix-cls: string.unquote('#{theme.$prefix}-number-flow');
6
+
7
+ .#{$number-flow-prefix-cls} {
8
+ display: inline-flex;
9
+ align-items: baseline;
10
+ line-height: 1;
11
+ direction: ltr;
12
+ white-space: nowrap;
13
+ isolation: isolate;
14
+
15
+ &-content,
16
+ &-part,
17
+ &-digit-track,
18
+ &-digit-value,
19
+ &-symbol {
20
+ display: inline-block;
21
+ }
22
+
23
+ &-content {
24
+ margin: calc(-1 * $number-flow-mask-height) calc(-1 * $number-flow-mask-width);
25
+ padding: $number-flow-mask-height $number-flow-mask-width;
26
+ overflow: hidden;
27
+ }
28
+
29
+ &-part {
30
+ position: relative;
31
+ vertical-align: bottom;
32
+ }
33
+
34
+ &-digit {
35
+ height: 1em;
36
+ overflow: hidden;
37
+ }
38
+
39
+ &-digit-track {
40
+ display: flex;
41
+ flex-direction: column;
42
+ height: 1em;
43
+ transform: translateY(calc(1em * var(--sd-number-flow-start)));
44
+ }
45
+
46
+ &-digit-value {
47
+ flex: 0 0 1em;
48
+ height: 1em;
49
+ line-height: 1;
50
+ text-align: center;
51
+ font-variant-numeric: tabular-nums;
52
+ }
53
+
54
+ &-prepared &-digit-track {
55
+ transition: none;
56
+ }
57
+
58
+ &-animating &-digit-track {
59
+ transform: translateY(calc(1em * var(--sd-number-flow-end)));
60
+ transition:
61
+ transform var(--sd-number-flow-spin-duration, var(--sd-number-flow-duration))
62
+ var(--sd-number-flow-spin-easing, var(--sd-number-flow-easing)),
63
+ opacity var(--sd-number-flow-opacity-duration) ease-out;
64
+ }
65
+
66
+ &-symbol {
67
+ white-space: pre;
68
+ }
69
+
70
+ &-will-change :is(&-content, &-part, &-digit-track, &-symbol) {
71
+ will-change: transform;
72
+ }
73
+
74
+ &-custom-prefix {
75
+ margin-right: $number-flow-gap;
76
+ }
77
+
78
+ &-custom-suffix {
79
+ margin-left: $number-flow-gap;
80
+ }
81
+ }
82
+
83
+ .#{$number-flow-prefix-cls}-group {
84
+ display: inline-flex;
85
+ gap: $number-flow-gap;
86
+ align-items: baseline;
87
+ }
88
+
89
+ @media (prefers-reduced-motion: reduce) {
90
+ .#{$number-flow-prefix-cls}-digit-track {
91
+ transition: none;
92
+ }
93
+ }
@@ -0,0 +1,5 @@
1
+ @use '@style/theme/index.scss' as global;
2
+
3
+ $number-flow-gap: global.$spacing-2;
4
+ $number-flow-mask-height: 0.25em;
5
+ $number-flow-mask-width: 0.2em;
@@ -0,0 +1,46 @@
1
+ import type { CSSProperties } from 'vue';
2
+ export type NumberFlowValue = number | string;
3
+ export type NumberFlowFormat = Omit<Intl.NumberFormatOptions, 'notation'> & {
4
+ notation?: Exclude<Intl.NumberFormatOptions['notation'], 'scientific' | 'engineering'>;
5
+ };
6
+ export type NumberFlowTrend = number | ((oldValue: number, value: number) => number);
7
+ export type NumberFlowDigitOptions = {
8
+ max?: number;
9
+ };
10
+ export type NumberFlowDigits = Record<number, NumberFlowDigitOptions>;
11
+ export interface NumberFlowDigitContext {
12
+ position: number;
13
+ length: number;
14
+ trend: number;
15
+ highestChangedPosition?: number;
16
+ }
17
+ export interface NumberFlowPluginContext {
18
+ value: number;
19
+ previousValue: number;
20
+ trend: number;
21
+ }
22
+ export interface NumberFlowPlugin {
23
+ onUpdate?(context: NumberFlowPluginContext): void;
24
+ getDelta?(value: number, previousValue: number, context: NumberFlowDigitContext): number | void;
25
+ }
26
+ export interface NumberFlowProps {
27
+ value: NumberFlowValue;
28
+ locales?: Intl.LocalesArgument;
29
+ format?: NumberFlowFormat;
30
+ prefix?: string;
31
+ suffix?: string;
32
+ trend?: NumberFlowTrend;
33
+ plugins?: NumberFlowPlugin[];
34
+ animated?: boolean;
35
+ transformTiming?: KeyframeAnimationOptions;
36
+ spinTiming?: KeyframeAnimationOptions;
37
+ opacityTiming?: KeyframeAnimationOptions;
38
+ respectMotionPreference?: boolean;
39
+ digits?: NumberFlowDigits;
40
+ willChange?: boolean;
41
+ nonce?: string;
42
+ }
43
+ export interface NumberFlowExposed {
44
+ el: HTMLElement | null;
45
+ }
46
+ export type NumberFlowStyle = CSSProperties & Record<`--${string}`, string | number>;
@@ -0,0 +1,4 @@
1
+ import { type MaybeRefOrGetter } from 'vue';
2
+ export declare function useCanAnimate({ respectMotionPreference, }?: {
3
+ respectMotionPreference?: MaybeRefOrGetter<boolean>;
4
+ }): import("vue").ComputedRef<boolean>;
@@ -0,0 +1,30 @@
1
+ import { computed, onMounted, shallowRef, toValue, watchEffect } from "vue";
2
+ //#region components/number-flow/use-can-animate.ts
3
+ /**
4
+ * SSR-safe composable that returns whether number-flow animations can run.
5
+ * Respects `prefers-reduced-motion` and listens for changes.
6
+ */
7
+ function useCanAnimate({ respectMotionPreference = true } = {}) {
8
+ const canAnimate = shallowRef(false);
9
+ const reducedMotion = shallowRef(false);
10
+ const mediaQuery = shallowRef();
11
+ onMounted(() => {
12
+ canAnimate.value = typeof window !== "undefined";
13
+ mediaQuery.value = window.matchMedia("(prefers-reduced-motion: reduce)");
14
+ reducedMotion.value = mediaQuery.value.matches;
15
+ });
16
+ watchEffect((onCleanup) => {
17
+ if (!toValue(respectMotionPreference)) return;
18
+ const onChange = ({ matches }) => {
19
+ reducedMotion.value = matches;
20
+ };
21
+ const query = mediaQuery.value;
22
+ query === null || query === void 0 || query.addEventListener("change", onChange);
23
+ onCleanup(() => {
24
+ query === null || query === void 0 || query.removeEventListener("change", onChange);
25
+ });
26
+ });
27
+ return computed(() => canAnimate.value && (!toValue(respectMotionPreference) || !reducedMotion.value));
28
+ }
29
+ //#endregion
30
+ export { useCanAnimate };
@@ -54,8 +54,8 @@ declare const RichTextEditor: {
54
54
  }, import("vue").PublicProps, {
55
55
  classNames: Partial<Record<import("./types").RichTextEditorSemanticType, string>>;
56
56
  autoSize: boolean | import("./types").RichTextEditorAutoSize;
57
- styles: Partial<Record<import("./types").RichTextEditorSemanticType, import("vue").CSSProperties>>;
58
57
  plugins: readonly import("./types").RichTextEditorPlugin[];
58
+ styles: Partial<Record<import("./types").RichTextEditorSemanticType, import("vue").CSSProperties>>;
59
59
  transformers: readonly import("@lexical/markdown").Transformer[];
60
60
  history: boolean;
61
61
  historyDelay: number;
@@ -112,8 +112,8 @@ declare const RichTextEditor: {
112
112
  }, {}, {}, {}, {
113
113
  classNames: Partial<Record<import("./types").RichTextEditorSemanticType, string>>;
114
114
  autoSize: boolean | import("./types").RichTextEditorAutoSize;
115
- styles: Partial<Record<import("./types").RichTextEditorSemanticType, import("vue").CSSProperties>>;
116
115
  plugins: readonly import("./types").RichTextEditorPlugin[];
116
+ styles: Partial<Record<import("./types").RichTextEditorSemanticType, import("vue").CSSProperties>>;
117
117
  transformers: readonly import("@lexical/markdown").Transformer[];
118
118
  history: boolean;
119
119
  historyDelay: number;
@@ -175,8 +175,8 @@ declare const RichTextEditor: {
175
175
  }, string, {
176
176
  classNames: Partial<Record<import("./types").RichTextEditorSemanticType, string>>;
177
177
  autoSize: boolean | import("./types").RichTextEditorAutoSize;
178
- styles: Partial<Record<import("./types").RichTextEditorSemanticType, import("vue").CSSProperties>>;
179
178
  plugins: readonly import("./types").RichTextEditorPlugin[];
179
+ styles: Partial<Record<import("./types").RichTextEditorSemanticType, import("vue").CSSProperties>>;
180
180
  transformers: readonly import("@lexical/markdown").Transformer[];
181
181
  history: boolean;
182
182
  historyDelay: number;
@@ -58,8 +58,8 @@ declare const __VLS_base: import("vue").DefineComponent<RichTextEditorProps, {
58
58
  }>, {
59
59
  classNames: Partial<Record<import("./types").RichTextEditorSemanticType, string>>;
60
60
  autoSize: boolean | import("./types").RichTextEditorAutoSize;
61
- styles: Partial<Record<import("./types").RichTextEditorSemanticType, CSSProperties>>;
62
61
  plugins: readonly import("./types").RichTextEditorPlugin[];
62
+ styles: Partial<Record<import("./types").RichTextEditorSemanticType, CSSProperties>>;
63
63
  transformers: readonly import("@lexical/markdown").Transformer[];
64
64
  history: boolean;
65
65
  historyDelay: number;
package/es/sd-vue.js CHANGED
@@ -21,6 +21,7 @@ import Popover from "./popover/index.js";
21
21
  import avatar_group_default from "./avatar/avatar-group.js";
22
22
  import Avatar from "./avatar/index.js";
23
23
  import BackTop from "./back-top/index.js";
24
+ import NumberFlow, { NumberFlowGroup } from "./number-flow/index.js";
24
25
  import Badge from "./badge/index.js";
25
26
  import Ellipsis, { PerformantEllipsis } from "./ellipsis/index.js";
26
27
  import Link from "./link/index.js";
@@ -218,6 +219,7 @@ var components = {
218
219
  Modal,
219
220
  ModelSelector,
220
221
  Notification,
222
+ NumberFlow,
221
223
  Popconfirm,
222
224
  Progress,
223
225
  QrCode,
@@ -299,6 +301,7 @@ var SDVue = _objectSpread2(_objectSpread2({}, components), {}, {
299
301
  SkeletonLine: line_default,
300
302
  SkeletonShape: shape_default,
301
303
  Countdown: countdown_default,
304
+ NumberFlowGroup,
302
305
  Step: step_default,
303
306
  Thead: table_thead_default,
304
307
  Td: table_td_default,
@@ -21,6 +21,10 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
21
21
  type: BooleanConstructor;
22
22
  default: boolean;
23
23
  };
24
+ animation: {
25
+ type: BooleanConstructor;
26
+ default: boolean;
27
+ };
24
28
  valueStyle: {
25
29
  type: PropType<CSSProperties>;
26
30
  };
@@ -44,6 +48,10 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
44
48
  type: BooleanConstructor;
45
49
  default: boolean;
46
50
  };
51
+ animation: {
52
+ type: BooleanConstructor;
53
+ default: boolean;
54
+ };
47
55
  valueStyle: {
48
56
  type: PropType<CSSProperties>;
49
57
  };
@@ -52,6 +60,7 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
52
60
  }>, {
53
61
  value: number;
54
62
  start: boolean;
63
+ animation: boolean;
55
64
  format: string;
56
65
  now: number;
57
66
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;