From 7f6b8602bebdfda352b2797a66ce5573607964c5 Mon Sep 17 00:00:00 2001 From: bbazukun123 Date: Wed, 22 May 2024 16:58:57 +0700 Subject: [PATCH 1/2] [v8] Feat: add text and icon default anchor options (#157) Co-authored-by: Baz Utsahajit Co-authored-by: Zyie <24736175+Zyie@users.noreply.github.com> Fix: Fancy Button Content Fitting (#149) --- src/FancyButton.ts | 81 +++++++++++++++++-- .../FancyButtonBitmapText.stories.ts | 10 ++- .../FancyButtonDynamicUpdate.stories.ts | 10 +++ .../FancyButtonGraphics.stories.ts | 10 +++ .../FancyButtonHTMLText.stories.ts | 5 ++ .../fancyButton/FancyButtonIcon.stories.ts | 5 ++ .../FancyButtonNineSliceSprite.stories.ts | 14 +++- .../fancyButton/FancyButtonSprite.stories.ts | 5 ++ 8 files changed, 130 insertions(+), 10 deletions(-) diff --git a/src/FancyButton.ts b/src/FancyButton.ts index da998dc4..57892ad9 100644 --- a/src/FancyButton.ts +++ b/src/FancyButton.ts @@ -1,3 +1,4 @@ +/* eslint-disable max-len */ import { Container, isMobile, NineSliceSprite, ObservablePoint, Rectangle, Texture, Ticker } from 'pixi.js'; import { Group, Tween } from 'tweedle.js'; import { ButtonContainer } from './Button'; @@ -63,6 +64,8 @@ export type ButtonOptions = ViewsInput & { iconOffset?: Offset; defaultTextScale?: Pos | number; defaultIconScale?: Pos | number; + defaultTextAnchor?: Pos | number; + defaultIconAnchor?: Pos | number; animations?: StateAnimations; nineSliceSprite?: [number, number, number, number]; ignoreRefitting?: boolean; @@ -144,6 +147,12 @@ export class FancyButton extends ButtonContainer /** Base icon scaling to take into account when fitting inside the button */ protected _defaultIconScale: Pos = { x: 1, y: 1 }; + /** Base text anchor to take into account when fitting and placing inside the button */ + protected _defaultTextAnchor: Pos = { x: 0.5, y: 0.5 }; + + /** Base icon anchor to take into account when fitting and placing inside the button */ + protected _defaultIconAnchor: Pos = { x: 0.5, y: 0.5 }; + /** * Creates a button with a lot of tweaks. * @param {object} options - Button options. @@ -162,6 +171,8 @@ export class FancyButton extends ButtonContainer * when all animations scales will be applied to the inner view. * @param {number} options.defaultTextScale - Base text scaling to take into account when fitting inside the button. * @param {number} options.defaultIconScale - Base icon scaling to take into account when fitting inside the button. + * @param {number} options.defaultTextAnchor - Base text anchor to take into account when fitting and placing inside the button. + * @param {number} options.defaultIconAnchor - Base icon anchor to take into account when fitting and placing inside the button. * @param {number} options.anchor - Anchor point of the button. * @param {number} options.anchorX - Horizontal anchor point of the button. * @param {number} options.anchorY - Vertical anchor point of the button. @@ -185,6 +196,8 @@ export class FancyButton extends ButtonContainer iconOffset, defaultTextScale: textScale, defaultIconScale: iconScale, + defaultTextAnchor: textAnchor, + defaultIconAnchor: iconAnchor, scale, anchor, anchorX, @@ -206,6 +219,8 @@ export class FancyButton extends ButtonContainer this.iconOffset = iconOffset; this.defaultTextScale = textScale; this.defaultIconScale = iconScale; + this.defaultTextAnchor = textAnchor; + this.defaultIconAnchor = iconAnchor; this.scale.set(scale ?? 1); if (animations) @@ -323,7 +338,6 @@ export class FancyButton extends ButtonContainer this._defaultTextScale = { x, y }; } - this._views.textView.anchor.set(0); this.innerView.addChild(this._views.textView); this.adjustTextView(this.state); @@ -395,6 +409,7 @@ export class FancyButton extends ButtonContainer if (!this.text) return; const activeView = this.getStateView(this.state); + const { x: anchorX, y: anchorY } = this._defaultTextAnchor; if (activeView) { @@ -409,7 +424,7 @@ export class FancyButton extends ButtonContainer this._views.textView.y = activeView.y + (activeView.height / 2); } - this._views.textView.anchor.set(0.5); + this._views.textView.anchor.set(anchorX, anchorY); this.setOffset(this._views.textView, state, this.textOffset); } @@ -437,12 +452,24 @@ export class FancyButton extends ButtonContainer this._views.iconView.scale.set(this._defaultIconScale.x, this._defaultIconScale.y); } + const { x: anchorX, y: anchorY } = this._defaultIconAnchor; + fitToView(activeView, this._views.iconView, this.padding, false); - (this._views.iconView as Sprite).anchor?.set(0); + if ('anchor' in this._views.iconView) + { + (this._views.iconView.anchor as ObservablePoint).set(anchorX, anchorY); + } + else + { + this._views.iconView.pivot.set( + anchorX * (this._views.iconView.width / this._views.iconView.scale.x), + anchorY * (this._views.iconView.height / this._views.iconView.scale.y) + ); + } - this._views.iconView.x = activeView.x + (activeView.width / 2) - (this._views.iconView.width / 2); - this._views.iconView.y = activeView.y + (activeView.height / 2) - (this._views.iconView.height / 2); + this._views.iconView.x = activeView.x + (activeView.width / 2); + this._views.iconView.y = activeView.y + (activeView.height / 2); this.setOffset(this._views.iconView, state, this.iconOffset); } @@ -888,6 +915,50 @@ export class FancyButton extends ButtonContainer return this.defaultIconScale; } + /** + * Sets the base anchor for the text view to take into account when fitting and placing inside the button. + * @param {Pos | number} anchor - base anchor of the text view. + */ + set defaultTextAnchor(anchor: Pos | number) + { + if (anchor === undefined) return; + // Apply to the options so that the manual anchor is prioritized. + this.options.defaultTextAnchor = anchor; + const isNumber = typeof anchor === 'number'; + + this._defaultTextAnchor.x = isNumber ? anchor : anchor.x ?? 1; + this._defaultTextAnchor.y = isNumber ? anchor : anchor.y ?? 1; + this.adjustTextView(this.state); + } + + /** Returns the text view base anchor. */ + get defaultTextAnchor(): Pos + { + return this.defaultTextAnchor; + } + + /** + * Sets the base anchor for the icon view to take into account when fitting and placing inside the button. + * @param {Pos | number} anchor - base anchor of the icon view. + */ + set defaultIconAnchor(anchor: Pos | number) + { + if (anchor === undefined) return; + // Apply to the options so that the manual anchor is prioritized. + this.options.defaultIconAnchor = anchor; + const isNumber = typeof anchor === 'number'; + + this._defaultIconAnchor.x = isNumber ? anchor : anchor.x ?? 1; + this._defaultIconAnchor.y = isNumber ? anchor : anchor.y ?? 1; + this.adjustIconView(this.state); + } + + /** Returns the icon view base anchor. */ + get defaultIconAnchor(): Pos + { + return this.defaultIconAnchor; + } + /** * Sets width of a FancyButtons state views. * If nineSliceSprite is set, then width will be set to nineSliceSprites of a views. diff --git a/src/stories/fancyButton/FancyButtonBitmapText.stories.ts b/src/stories/fancyButton/FancyButtonBitmapText.stories.ts index 9674bee4..fecb241d 100644 --- a/src/stories/fancyButton/FancyButtonBitmapText.stories.ts +++ b/src/stories/fancyButton/FancyButtonBitmapText.stories.ts @@ -14,6 +14,8 @@ const args = { textOffsetX: 0, textOffsetY: -7, defaultTextScale: 0.99, + defaultTextAnchorX: 0.5, + defaultTextAnchorY: 0.5, anchorX: 0.5, anchorY: 0.5, animationDuration: 100, @@ -31,9 +33,11 @@ export const UsingSpriteAndBitmapText: StoryFn = ( textOffsetX, textOffsetY, defaultTextScale, + defaultTextAnchorX, + defaultTextAnchorY, anchorX, anchorY, - animationDuration + animationDuration, }, context ) => @@ -54,14 +58,13 @@ export const UsingSpriteAndBitmapText: StoryFn = ( name: 'TitleFont', style: { ...defaultTextStyle, - fill: textColor || defaultTextStyle.fill, }, }); const title = new BitmapText({ text, - style: { fontFamily: 'TitleFont' }, + style: { fontFamily: 'TitleFont', fontSize: defaultTextStyle.fontSize }, }); // Component usage !!! @@ -74,6 +77,7 @@ export const UsingSpriteAndBitmapText: StoryFn = ( padding, textOffset: { x: textOffsetX, y: textOffsetY }, defaultTextScale, + defaultTextAnchor: { x: defaultTextAnchorX, y: defaultTextAnchorY }, animations: { hover: { props: { diff --git a/src/stories/fancyButton/FancyButtonDynamicUpdate.stories.ts b/src/stories/fancyButton/FancyButtonDynamicUpdate.stories.ts index fea13287..a6c078f0 100644 --- a/src/stories/fancyButton/FancyButtonDynamicUpdate.stories.ts +++ b/src/stories/fancyButton/FancyButtonDynamicUpdate.stories.ts @@ -13,6 +13,10 @@ const args = { textColor: '#FFFFFF', defaultTextScale: 0.99, defaultIconScale: 0.2, + defaultTextAnchorX: 0.5, + defaultTextAnchorY: 0.5, + defaultIconAnchorX: 0.5, + defaultIconAnchorY: 0.5, padding: 11, anchorX: 0.5, anchorY: 0.5, @@ -25,6 +29,10 @@ export const DynamicUpdate: StoryFn = ({ textColor, defaultTextScale, defaultIconScale, + defaultTextAnchorX, + defaultTextAnchorY, + defaultIconAnchorX, + defaultIconAnchorY, disabled, onPress, padding, @@ -50,6 +58,7 @@ export const DynamicUpdate: StoryFn = ({ button.iconView = Sprite.from(icon); button.defaultIconScale = defaultIconScale; + button.defaultIconAnchor = { x: defaultIconAnchorX, y: defaultIconAnchorY }; button.iconOffset = { x: -100, y: -7 }; button.textView = new Text({ @@ -59,6 +68,7 @@ export const DynamicUpdate: StoryFn = ({ } }); button.defaultTextScale = defaultTextScale; + button.defaultTextAnchor = { x: defaultTextAnchorX, y: defaultTextAnchorY }; button.textOffset = { x: 30, y: -7 }; button.padding = padding; diff --git a/src/stories/fancyButton/FancyButtonGraphics.stories.ts b/src/stories/fancyButton/FancyButtonGraphics.stories.ts index 8b67596b..3c039405 100644 --- a/src/stories/fancyButton/FancyButtonGraphics.stories.ts +++ b/src/stories/fancyButton/FancyButtonGraphics.stories.ts @@ -26,6 +26,10 @@ const args = { textOffsetY: 140, defaultTextScale: 0.99, defaultIconScale: 0.99, + defaultTextAnchorX: 0.5, + defaultTextAnchorY: 0.5, + defaultIconAnchorX: 0.5, + defaultIconAnchorY: 0.5, defaultOffsetY: 0, hoverOffsetY: -1, pressedOffsetY: 5, @@ -57,6 +61,10 @@ export const UseGraphics: StoryFn = ({ textOffsetY, defaultTextScale, defaultIconScale, + defaultTextAnchorX, + defaultTextAnchorY, + defaultIconAnchorX, + defaultIconAnchorY, defaultOffsetY, hoverOffsetY, pressedOffsetY, @@ -113,6 +121,8 @@ export const UseGraphics: StoryFn = ({ }, defaultTextScale, defaultIconScale, + defaultTextAnchor: { x: defaultTextAnchorX, y: defaultTextAnchorY }, + defaultIconAnchor: { x: defaultIconAnchorX, y: defaultIconAnchorY }, animations: { default: { props: { diff --git a/src/stories/fancyButton/FancyButtonHTMLText.stories.ts b/src/stories/fancyButton/FancyButtonHTMLText.stories.ts index b6674f3b..436c4c68 100644 --- a/src/stories/fancyButton/FancyButtonHTMLText.stories.ts +++ b/src/stories/fancyButton/FancyButtonHTMLText.stories.ts @@ -14,6 +14,8 @@ const args = { textOffsetX: 0, textOffsetY: -7, defaultTextScale: 0.99, + defaultTextAnchorX: 0.5, + defaultTextAnchorY: 0.5, anchorX: 0.5, anchorY: 0.5, animationDuration: 100, @@ -31,6 +33,8 @@ export const UsingSpriteAndHTMLText: StoryFn = ( textOffsetX, textOffsetY, defaultTextScale, + defaultTextAnchorX, + defaultTextAnchorY, anchorX, anchorY, animationDuration @@ -68,6 +72,7 @@ export const UsingSpriteAndHTMLText: StoryFn = ( padding, textOffset: { x: textOffsetX, y: textOffsetY }, defaultTextScale, + defaultTextAnchor: { x: defaultTextAnchorX, y: defaultTextAnchorY }, animations: { hover: { props: { diff --git a/src/stories/fancyButton/FancyButtonIcon.stories.ts b/src/stories/fancyButton/FancyButtonIcon.stories.ts index 5c175a10..777d5ac9 100644 --- a/src/stories/fancyButton/FancyButtonIcon.stories.ts +++ b/src/stories/fancyButton/FancyButtonIcon.stories.ts @@ -19,6 +19,8 @@ const args = { iconOffsetX: 0, iconOffsetY: 0, defaultIconScale: 0.99, + defaultIconAnchorX: 0.5, + defaultIconAnchorY: 0.5, defaultOffset: 0, hoverOffset: -1, pressedOffset: 5, @@ -43,6 +45,8 @@ export const UseIcon: StoryFn = ({ iconOffsetX, iconOffsetY, defaultIconScale, + defaultIconAnchorX, + defaultIconAnchorY, defaultOffset, hoverOffset, pressedOffset, @@ -86,6 +90,7 @@ export const UseIcon: StoryFn = ({ y: iconOffsetY }, defaultIconScale, + defaultIconAnchor: { x: defaultIconAnchorX, y: defaultIconAnchorY }, animations: { hover: { props: { diff --git a/src/stories/fancyButton/FancyButtonNineSliceSprite.stories.ts b/src/stories/fancyButton/FancyButtonNineSliceSprite.stories.ts index 362158e2..17cf4790 100644 --- a/src/stories/fancyButton/FancyButtonNineSliceSprite.stories.ts +++ b/src/stories/fancyButton/FancyButtonNineSliceSprite.stories.ts @@ -16,6 +16,10 @@ const args = { height: 137, defaultTextScale: 0.99, defaultIconScale: 0.2, + defaultTextAnchorX: 0.5, + defaultTextAnchorY: 0.5, + defaultIconAnchorX: 0.5, + defaultIconAnchorY: 0.5, anchorX: 0.5, anchorY: 0.5, animationDuration: 100, @@ -36,6 +40,10 @@ export const UseNineSliceSprite: StoryFn = ({ height, defaultTextScale, defaultIconScale, + defaultTextAnchorX, + defaultTextAnchorY, + defaultIconAnchorX, + defaultIconAnchorY }, context) => new PixiStory({ context, @@ -69,7 +77,11 @@ export const UseNineSliceSprite: StoryFn = ({ }), padding, textOffset: { x: 30, y: -5 }, + iconOffset: { x: -100, y: -7 }, defaultTextScale, + defaultIconScale, + defaultTextAnchor: { x: defaultTextAnchorX, y: defaultTextAnchorY }, + defaultIconAnchor: { x: defaultIconAnchorX, y: defaultIconAnchorY }, animations: { hover: { props: { @@ -94,8 +106,6 @@ export const UseNineSliceSprite: StoryFn = ({ borderWidth: 10, borderColor: 0xFFFFFF }); - button.defaultIconScale = defaultIconScale; - button.iconOffset = { x: -100, y: -7 }; button.anchor.set(anchorX, anchorY); diff --git a/src/stories/fancyButton/FancyButtonSprite.stories.ts b/src/stories/fancyButton/FancyButtonSprite.stories.ts index 8cf14399..def5a422 100644 --- a/src/stories/fancyButton/FancyButtonSprite.stories.ts +++ b/src/stories/fancyButton/FancyButtonSprite.stories.ts @@ -14,6 +14,8 @@ const args = { textOffsetX: 0, textOffsetY: -7, defaultTextScale: 0.99, + defaultTextAnchorX: 0.5, + defaultTextAnchorY: 0.5, anchorX: 0.5, anchorY: 0.5, animationDuration: 100, @@ -30,6 +32,8 @@ export const UseSprite: StoryFn = ({ textOffsetX, textOffsetY, defaultTextScale, + defaultTextAnchorX, + defaultTextAnchorY, anchorX, anchorY, animationDuration @@ -57,6 +61,7 @@ export const UseSprite: StoryFn = ({ padding, textOffset: { x: textOffsetX, y: textOffsetY }, defaultTextScale, + defaultTextAnchor: { x: defaultTextAnchorX, y: defaultTextAnchorY }, animations: { hover: { props: { From 6ca85ef839a2ab45e2e3534979b9ec8708495d0e Mon Sep 17 00:00:00 2001 From: bbazukun123 Date: Wed, 22 May 2024 17:01:40 +0700 Subject: [PATCH 2/2] [v8] Feat: ScrollBox Item Proximity Event (#162) Co-authored-by: Baz Utsahajit --- src/ScrollBox.ts | 57 ++++++++- .../scrollBox/ScrollBoxProximity.stories.ts | 121 ++++++++++++++++++ 2 files changed, 171 insertions(+), 7 deletions(-) create mode 100644 src/stories/scrollBox/ScrollBoxProximity.stories.ts diff --git a/src/ScrollBox.ts b/src/ScrollBox.ts index ebcaa8ee..4bc95aad 100644 --- a/src/ScrollBox.ts +++ b/src/ScrollBox.ts @@ -9,6 +9,7 @@ import { Point, Ticker, } from 'pixi.js'; +import { Signal } from 'typed-signals'; import { List } from './List'; import { Trackpad } from './utils/trackpad/Trackpad'; @@ -25,8 +26,17 @@ export type ScrollBoxOptions = { dragTrashHold?: number; globalScroll?: boolean; shiftScroll?: boolean; + proximityRange?: number; + proximityDebounce?: number; + disableProximityCheck?: boolean; } & Omit; +type ProximityEventData = { + item: Container; + index: number; + inRange: boolean; +}; + /** * Scrollable view, for arranging lists of Pixi container-based elements. * @@ -76,6 +86,13 @@ export class ScrollBox extends Container protected dragStarTouchPoint: Point; protected isOver = false; + protected proximityRange: number; + protected proximityStatusCache: boolean[] = []; + protected lastScrollX!: number | null; + protected lastScrollY!: number | null; + protected proximityCheckFrameCounter = 0; + public onProximityChange = new Signal<(data: ProximityEventData) => void>(); + /** * @param options * @param {number} options.background - background color of the ScrollBox. @@ -128,6 +145,8 @@ export class ScrollBox extends Container this.__width = options.width | this.background.width; this.__height = options.height | this.background.height; + this.proximityRange = options.proximityRange ?? 0; + if (!this.list) { this.list = new List(); @@ -182,6 +201,7 @@ export class ScrollBox extends Container /** Remove all items from a scrollable list. */ removeItems() { + this.proximityStatusCache.length = 0; this.list.removeChildren(); } @@ -207,6 +227,7 @@ export class ScrollBox extends Container child.eventMode = 'static'; this.list.addChild(child); + this.proximityStatusCache.push(false); if (!this.options.disableDynamicRendering) { @@ -226,15 +247,16 @@ export class ScrollBox extends Container removeItem(itemID: number) { this.list.removeItem(itemID); - + this.proximityStatusCache.splice(itemID, 1); this.resize(); } /** * Checks if the item is visible or scrolled out of the visible part of the view.* Adds an item to a scrollable list. * @param {Container} item - item to check. + * @param padding - proximity padding to consider the item visible. */ - isItemVisible(item: Container): boolean + isItemVisible(item: Container, padding = 0): boolean { const isVertical = this.options.type === 'vertical' || !this.options.type; let isVisible = false; @@ -244,10 +266,7 @@ export class ScrollBox extends Container { const posY = item.y + list.y; - if ( - posY + item.height + this.list.bottomPadding >= 0 - && posY - this.list.topPadding <= this.options.height - ) + if (posY + item.height >= -padding && posY <= this.options.height + padding) { isVisible = true; } @@ -256,7 +275,7 @@ export class ScrollBox extends Container { const posX = item.x + list.x; - if (posX + item.width >= 0 && posX <= this.options.width) + if (posX + item.width >= -padding && posX <= this.options.width + padding) { isVisible = true; } @@ -735,6 +754,30 @@ export class ScrollBox extends Container { this.list[type] = this._trackpad[type]; } + + if (!this.options.disableProximityCheck && ( + this._trackpad.x !== this.lastScrollX || this._trackpad.y !== this.lastScrollY + )) + { + this.proximityCheckFrameCounter++; + if (this.proximityCheckFrameCounter >= (this.options.proximityDebounce ?? 10)) + { + this.items.forEach((item, index) => + { + const inRange = this.isItemVisible(item, this.proximityRange); + const wasInRange = this.proximityStatusCache[index]; + + if (inRange !== wasInRange) + { + this.proximityStatusCache[index] = inRange; + this.onProximityChange.emit({ item, index, inRange }); + } + }); + this.lastScrollX = this._trackpad.x; + this.lastScrollY = this._trackpad.y; + this.proximityCheckFrameCounter = 0; + } + } } /** diff --git a/src/stories/scrollBox/ScrollBoxProximity.stories.ts b/src/stories/scrollBox/ScrollBoxProximity.stories.ts new file mode 100644 index 00000000..ba4196ea --- /dev/null +++ b/src/stories/scrollBox/ScrollBoxProximity.stories.ts @@ -0,0 +1,121 @@ +import { Graphics, Text } from 'pixi.js'; +import { PixiStory, StoryFn } from '@pixi/storybook-renderer'; +import { FancyButton } from '../../FancyButton'; +import { ScrollBox } from '../../ScrollBox'; +import { centerElement } from '../../utils/helpers/resize'; +import { defaultTextStyle } from '../../utils/helpers/styles'; +import { argTypes, getDefaultArgs } from '../utils/argTypes'; +import { action } from '@storybook/addon-actions'; + +const args = { + proximityRange: 100, + proximityDebounce: 10, + width: 320, + height: 420, + radius: 20, + elementsMargin: 10, + elementsPadding: 10, + elementsWidth: 300, + elementsHeight: 80, + itemsAmount: 100, + type: [undefined, 'vertical', 'horizontal'], + fadeSpeed: 0.5, +}; + +const items: FancyButton[] = []; +const inRangeCache: boolean[] = []; + +export const ProximityEvent: StoryFn = ({ + width, + height, + radius, + elementsMargin, + elementsPadding, + elementsWidth, + elementsHeight, + itemsAmount, + proximityRange, + proximityDebounce, + type, + fadeSpeed, +}, context) => + new PixiStory({ + context, + init: (view) => + { + const fontColor = '#000000'; + const backgroundColor = '#F5E3A9'; + const disableEasing = false; + const globalScroll = true; + const shiftScroll = type === 'horizontal'; + const onPress = action('Button pressed'); + + items.length = 0; + inRangeCache.length = 0; + + for (let i = 0; i < itemsAmount; i++) + { + const button = new FancyButton({ + defaultView: new Graphics().roundRect(0, 0, elementsWidth, elementsHeight, radius).fill(0xa5e24d), + hoverView: new Graphics().roundRect(0, 0, elementsWidth, elementsHeight, radius).fill(0xfec230), + pressedView: new Graphics().roundRect(0, 0, elementsWidth, elementsHeight, radius).fill(0xfe6048), + text: new Text({ + text: `Item ${i + 1}`, style: { + ...defaultTextStyle, + fill: fontColor + } + }) + }); + + button.anchor.set(0); + button.onPress.connect(() => onPress(i + 1)); + button.alpha = 0; + + items.push(button); + inRangeCache.push(false); + } + + const scrollBox = new ScrollBox({ + background: backgroundColor, + elementsMargin, + width, + height, + radius, + padding: elementsPadding, + disableEasing, + globalScroll, + shiftScroll, + type, + proximityRange, + proximityDebounce, + }); + + scrollBox.addItems(items); + + // Handle on proximity change event. + scrollBox.onProximityChange.connect(({ index, inRange }) => + { + inRangeCache[index] = inRange; + }); + + view.addChild(scrollBox); + }, + resize: (view) => centerElement(view.children[0]), + update: () => + { + items.forEach((item, index) => + { + const inRange = inRangeCache[index]; + + // Fade in/out according to whether the item is within the specified range. + if (inRange && item.alpha < 1) item.alpha += 0.04 * fadeSpeed; + else if (!inRange && item.alpha > 0) item.alpha -= 0.04 * fadeSpeed; + }); + }, + }); + +export default { + title: 'Components/ScrollBox/Proximity Event', + argTypes: argTypes(args), + args: getDefaultArgs(args) +};