Skip to content

Commit 2f215ca

Browse files
authored
feat(react): add ScrollNumber component and enhance Badge with scroll animation (#74)
* feat(react): add ScrollNumber component and enhance Badge with scroll animation Add a new ScrollNumber component for animated digit transitions with shortest-path scrolling across 0/9 boundary. Integrate it into Badge so count changes animate smoothly. * chore: add changeset for ScrollNumber and Badge enhancement * docs: add TextLoop component design spec * docs: update TextLoop spec with edge cases and accessibility * docs: add TextLoop implementation plan * feat(text-loop): add types and barrel export * test(text-loop): add tests for TextLoop component * feat(text-loop): implement TextLoop component * style(text-loop): add TextLoop styles * feat(text-loop): register exports and docs route * docs(text-loop): add demos and documentation * fix(alert): add content wrapper for proper flex layout Wraps Alert content in a ty-alert__content div with flex: 1 and overflow: hidden so child components like Marquee/TextLoop can properly expand within the flex container. * refactor(text-loop): remove horizontal direction and add demos Remove left/right direction support from TextLoop (vertical-only now). Restore Alert LoopBanner demo to use Marquee, add dedicated TextLoop demos for direction, interval, play-once, and alert banner. * chore: update changeset to include TextLoop * style(text-loop): register TextLoop styles in component bundle * chore: remove docs
1 parent c23eea1 commit 2f215ca

43 files changed

Lines changed: 2490 additions & 15 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@tiny-design/react": minor
3+
---
4+
5+
Add ScrollNumber component with animated digit transitions and shortest-path scrolling; integrate into Badge for smooth count animations. Add TextLoop component for cycling through children with vertical slide transitions.

apps/docs/src/routers.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ const c = {
9090
statistic: ll(() => import('../../../packages/react/src/statistic/index.md'), () => import('../../../packages/react/src/statistic/index.zh_CN.md')),
9191
table: ll(() => import('../../../packages/react/src/table/index.md'), () => import('../../../packages/react/src/table/index.zh_CN.md')),
9292
tag: ll(() => import('../../../packages/react/src/tag/index.md'), () => import('../../../packages/react/src/tag/index.zh_CN.md')),
93+
textLoop: ll(() => import('../../../packages/react/src/text-loop/index.md'), () => import('../../../packages/react/src/text-loop/index.zh_CN.md')),
9394
timeline: ll(() => import('../../../packages/react/src/timeline/index.md'), () => import('../../../packages/react/src/timeline/index.zh_CN.md')),
9495
tooltip: ll(() => import('../../../packages/react/src/tooltip/index.md'), () => import('../../../packages/react/src/tooltip/index.zh_CN.md')),
9596
tree: ll(() => import('../../../packages/react/src/tree/index.md'), () => import('../../../packages/react/src/tree/index.zh_CN.md')),
@@ -123,6 +124,7 @@ const c = {
123124
popConfirm: ll(() => import('../../../packages/react/src/pop-confirm/index.md'), () => import('../../../packages/react/src/pop-confirm/index.zh_CN.md')),
124125
result: ll(() => import('../../../packages/react/src/result/index.md'), () => import('../../../packages/react/src/result/index.zh_CN.md')),
125126
scrollIndicator: ll(() => import('../../../packages/react/src/scroll-indicator/index.md'), () => import('../../../packages/react/src/scroll-indicator/index.zh_CN.md')),
127+
scrollNumber: ll(() => import('../../../packages/react/src/scroll-number/index.md'), () => import('../../../packages/react/src/scroll-number/index.zh_CN.md')),
126128
skeleton: ll(() => import('../../../packages/react/src/skeleton/index.md'), () => import('../../../packages/react/src/skeleton/index.zh_CN.md')),
127129
strengthIndicator: ll(() => import('../../../packages/react/src/strength-indicator/index.md'), () => import('../../../packages/react/src/strength-indicator/index.zh_CN.md')),
128130
backTop: ll(() => import('../../../packages/react/src/back-top/index.md'), () => import('../../../packages/react/src/back-top/index.zh_CN.md')),
@@ -214,9 +216,11 @@ export const getComponentMenu = (s: SiteLocale): RouterItem[] => {
214216
{ title: 'Marquee', route: 'marquee', component: pick(c.marquee, z) },
215217
{ title: 'Popover', route: 'popover', component: pick(c.popover, z) },
216218
{ title: 'Progress', route: 'progress', component: pick(c.progress, z) },
219+
{ title: 'ScrollNumber', route: 'scroll-number', component: pick(c.scrollNumber, z) },
217220
{ title: 'Statistic', route: 'statistic', component: pick(c.statistic, z) },
218221
{ title: 'Table', route: 'table', component: pick(c.table, z) },
219222
{ title: 'Tag', route: 'tag', component: pick(c.tag, z) },
223+
{ title: 'TextLoop', route: 'text-loop', component: pick(c.textLoop, z) },
220224
{ title: 'Timeline', route: 'timeline', component: pick(c.timeline, z) },
221225
{ title: 'Tooltip', route: 'tooltip', component: pick(c.tooltip, z) },
222226
{ title: 'Tree', route: 'tree', component: pick(c.tree, z) },

packages/react/src/alert/__tests__/__snapshots__/alert.test.tsx.snap

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ exports[`<Alert /> should match the snapshot 1`] = `
66
class="ty-alert ty-alert_info ty-undefined-enter"
77
role="alert"
88
>
9-
<div>
9+
<div
10+
class="ty-alert__content"
11+
>
1012
Alert
1113
</div>
1214
</div>

packages/react/src/alert/alert.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ const Alert = React.forwardRef<HTMLDivElement, AlertProps>((props, forwardedRef)
7676
else if (forwardedRef) forwardedRef.current = node;
7777
}}>
7878
{icon && renderIcon()}
79-
<div>
79+
<div className={`${prefixCls}__content`}>
8080
{title && <p className={classNames(`${prefixCls}__title`, { [`${prefixCls}__title_has-content`]: children })}>{title}</p>}
8181
{children}
8282
</div>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import React from 'react';
2+
import { Alert, Marquee } from '@tiny-design/react';
3+
4+
export default function LoopBannerDemo() {
5+
return (
6+
<Alert type="warning" icon>
7+
<Marquee pauseOnHover fade={false}>
8+
This is a scrolling banner alert message — important announcements go here.
9+
</Marquee>
10+
</Alert>
11+
);
12+
}

packages/react/src/alert/index.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import TitleDemo from './demo/Title';
1010
import TitleSource from './demo/Title.tsx?raw';
1111
import TypeDemo from './demo/Type';
1212
import TypeSource from './demo/Type.tsx?raw';
13+
import LoopBannerDemo from './demo/LoopBanner';
14+
import LoopBannerSource from './demo/LoopBanner.tsx?raw';
1315

1416
# Alert
1517

@@ -85,6 +87,15 @@ Replace the default icon with customized text.
8587

8688
<DemoBlock component={CloseBtnDemo} source={CloseBtnSource} />
8789

90+
</Demo>
91+
<Demo>
92+
93+
### Loop Banner
94+
95+
Combine with `Marquee` component to create a scrolling banner alert. The text pauses on hover.
96+
97+
<DemoBlock component={LoopBannerDemo} source={LoopBannerSource} />
98+
8899
</Demo>
89100
</Column>
90101
</Layout>

packages/react/src/alert/style/_index.scss

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@
2020
margin-top: 14px;
2121
}
2222

23+
&__content {
24+
flex: 1;
25+
overflow: hidden;
26+
}
27+
2328
&__title {
2429
box-sizing: border-box;
2530
margin: 0;

0 commit comments

Comments
 (0)