diff --git a/packages/banana-react/CHANGELOG.md b/packages/banana-react/CHANGELOG.md index 68726f79..21cf5818 100644 --- a/packages/banana-react/CHANGELOG.md +++ b/packages/banana-react/CHANGELOG.md @@ -1,5 +1,12 @@ # @banana/banana-react +## 1.19.4 + +### Patch Changes + +- Updated dependencies + - @banana-ui/banana@1.19.4 + ## 1.19.3 ### Patch Changes diff --git a/packages/banana-react/package.json b/packages/banana-react/package.json index 3ab7467c..444fafea 100644 --- a/packages/banana-react/package.json +++ b/packages/banana-react/package.json @@ -1,6 +1,6 @@ { "name": "@banana-ui/react", - "version": "1.19.3", + "version": "1.19.4", "description": "React components for Banana UI", "keywords": [ "web components", diff --git a/packages/banana/CHANGELOG.md b/packages/banana/CHANGELOG.md index f7629c72..55308255 100644 --- a/packages/banana/CHANGELOG.md +++ b/packages/banana/CHANGELOG.md @@ -1,5 +1,11 @@ # banana-ui +## 1.19.4 + +### Patch Changes + +- add fixed for marquee + ## 1.19.3 ### Patch Changes diff --git a/packages/banana/package.json b/packages/banana/package.json index 6d272f02..cb214b8e 100644 --- a/packages/banana/package.json +++ b/packages/banana/package.json @@ -1,6 +1,6 @@ { "name": "@banana-ui/banana", - "version": "1.19.3", + "version": "1.19.4", "description": "An UI library of web components can be used in any framework", "keywords": [ "web components", diff --git a/packages/banana/src/marquee/index.styles.ts b/packages/banana/src/marquee/index.styles.ts index d4cbe323..ec562472 100644 --- a/packages/banana/src/marquee/index.styles.ts +++ b/packages/banana/src/marquee/index.styles.ts @@ -21,14 +21,21 @@ export default [ align-items: center; } - .content { + .content-normal { overflow: hidden; display: inline-block; flex: 0 0 auto; white-space: nowrap; animation: marquee var(--banana-marquee-duration) linear infinite; - min-width: 100%; - animation-play-state: var(--banana-marquee-fixed); + transform: translateX(var(--banana-marquee-width, 100%)); + } + + .content-fixed { + overflow: hidden; + display: inline-block; + flex: 0 0 auto; + white-space: nowrap; + transform: translateX(0); } @media (any-hover: hover) { @@ -39,7 +46,7 @@ export default [ @keyframes marquee { 0% { - transform: translateX(0); + transform: translateX(var(--banana-marquee-width, 100%)); } 100% { diff --git a/packages/banana/src/marquee/index.test.ts b/packages/banana/src/marquee/index.test.ts index 479b53d0..a6629ce4 100644 --- a/packages/banana/src/marquee/index.test.ts +++ b/packages/banana/src/marquee/index.test.ts @@ -106,42 +106,40 @@ describe('b-marquee', () => { }); describe('custom fixed', () => { - it('should set the fixed when provided a boolean', async () => { - const element = await fixture(html``); - const fixed = window.getComputedStyle(element).getPropertyValue('--banana-marquee-fixed'); - expect(fixed).to.equal('paused'); - }); - it('pauses animation when content width is less than marquee width', async () => { const element = await fixture(html``); // Simulate content width being less than marquee width - element._mainContent!.getBoundingClientRect = () => ({ width: 50 } as DOMRect); element._marquee!.getBoundingClientRect = () => ({ width: 100 } as DOMRect); + element._content!.getBoundingClientRect = () => ({ width: 50 } as DOMRect); // 强制调用私有方法 // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + (element as any)?.firstUpdated(); + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access (element as any)?._calculateWidth(); // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - expect((element as any)._animationPlayState).to.equal('paused'); - expect(element.style.getPropertyValue('--banana-marquee-fixed')).to.equal('paused'); + expect((element as any)._isNormal).to.equal(false); + expect(element.style.getPropertyValue('--banana-marquee-width')).to.equal('100px'); }); it('resumes animation when content width is greater than marquee width', async () => { const element = await fixture(html``); // Simulate content width being greater than marquee width - element._mainContent!.getBoundingClientRect = () => ({ width: 200 } as DOMRect); element._marquee!.getBoundingClientRect = () => ({ width: 100 } as DOMRect); + element._content!.getBoundingClientRect = () => ({ width: 200 } as DOMRect); // 强制调用私有方法 // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + (element as any)?.firstUpdated(); + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access (element as any)?._calculateWidth(); // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - expect((element as any)._animationPlayState).to.equal('running'); - expect(element.style.getPropertyValue('--banana-marquee-fixed')).to.equal('running'); + expect((element as any)._isNormal).to.equal(true); + expect(element.style.getPropertyValue('--banana-marquee-width')).to.equal('100px'); }); }); }); diff --git a/packages/banana/src/marquee/index.ts b/packages/banana/src/marquee/index.ts index 0fa1b08b..a4b249a9 100644 --- a/packages/banana/src/marquee/index.ts +++ b/packages/banana/src/marquee/index.ts @@ -1,5 +1,5 @@ import { CSSResultGroup, html, LitElement, PropertyValueMap } from 'lit'; -import { customElement, property, query } from 'lit/decorators.js'; +import { customElement, property, query, state } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import styles from './index.styles'; @@ -16,7 +16,6 @@ export default class BMarquee extends LitElement { super.disconnectedCallback(); // 停止观察元素的尺寸变化 this._marquee && this.resizeObserver?.unobserve(this._marquee); - this._mainContent && this.resizeObserver?.unobserve(this._mainContent); } @property() @@ -32,47 +31,44 @@ export default class BMarquee extends LitElement { @property({ type: Boolean, attribute: 'pause-when-hover' }) pauseWhenHover = false; - @property({ type: Boolean }) + @property({ type: Boolean, reflect: true }) fixed = false; - private _animationPlayState: 'running' | 'paused' = 'running'; + // 判断是否是 normal还是fixed (fixed为true时,才生效) + @state() + _isNormal = true; @query('.marquee') _marquee: HTMLDivElement | undefined; - @query('#main-content') - _mainContent: HTMLDivElement | undefined; + @query('.content') + _content: HTMLDivElement | undefined; firstUpdated() { + this._setBananaMarqueeWidth(); + // 观察元素的尺寸变化 - if (this._marquee && this._mainContent && this.fixed) { + if (this._marquee) { this.resizeObserver = new ResizeObserver(() => this._calculateWidth()); this.resizeObserver?.observe(this._marquee); - this.resizeObserver?.observe(this._mainContent); } } private _calculateWidth() { - if (this._marquee && this._mainContent && this.fixed) { + // marquee的宽度变化了 重新设置marquee的宽度 + this._setBananaMarqueeWidth(); + + if (this._marquee && this._content && this.fixed) { const marqueeWidth = this._marquee.getBoundingClientRect().width; - const contentWidth = this._mainContent.getBoundingClientRect().width; - - if (contentWidth > marqueeWidth) { - this._animationPlayState = 'running'; - this._setStyleFixed(); - } else { - if (this._animationPlayState === 'running') { - // 暂停的时候等上一次的动画是否结束 结束后才暂停 这样比较友好 - this._animationPlayState = 'paused'; - this._mainContent.addEventListener('animationiteration', this._setStyleFixed.bind(this), { once: true }); - } - } + const contentWidth = this._content.getBoundingClientRect().width; + + this._isNormal = contentWidth > marqueeWidth; } } - private _setStyleFixed() { - this.style.setProperty('--banana-marquee-fixed', this._animationPlayState); + private _setBananaMarqueeWidth() { + this.style.setProperty('--banana-marquee-width', `${this._marquee!.getBoundingClientRect().width}px`); } protected willUpdate(_changedProperties: PropertyValueMap): void { @@ -85,25 +81,23 @@ export default class BMarquee extends LitElement { const duration = this.duration; this.style.setProperty('--banana-marquee-duration', `${duration}s`); } - - if (_changedProperties.has('fixed')) { - const fixed = this.fixed; - this._animationPlayState = fixed ? 'paused' : 'running'; - this._setStyleFixed(); - } } render() { + const marqueeClass = classMap({ + marquee: true, + 'marquee--pause-when-hover': this.pauseWhenHover, + }); + + const contentClass = classMap({ + content: true, + 'content-normal': this._isNormal, + 'content-fixed': !this._isNormal, + }); + return html` -
-
${this.content}
-
${this.content}
+
+
${this.content}
`; } diff --git a/public/Marquee/fixedUsage.html b/public/Marquee/fixedUsage.html new file mode 100644 index 00000000..2a4f6b09 --- /dev/null +++ b/public/Marquee/fixedUsage.html @@ -0,0 +1,2 @@ + \ No newline at end of file