diff --git a/packages/k2-alpine/src/components/PageControl/PageControl.stories.tsx b/packages/k2-alpine/src/components/PageControl/PageControl.stories.tsx
new file mode 100644
index 000000000..87beffe81
--- /dev/null
+++ b/packages/k2-alpine/src/components/PageControl/PageControl.stories.tsx
@@ -0,0 +1,70 @@
+import React, { useState } from 'react'
+import { ScrollView, Text, View } from '../Primitives'
+import { Button, useTheme } from '../..'
+import { PageControl } from './PageControl'
+
+export default {
+ title: 'PageControl'
+}
+
+export const All = (): JSX.Element => {
+ const { theme } = useTheme()
+
+ const NUMBER_OF_PAGES = [3, 5, 20]
+
+ return (
+
+
+ {NUMBER_OF_PAGES.map((numberOfPage, index) => (
+
+
+
+ ))}
+
+
+ )
+}
+
+const PageControlStory = ({
+ numberOfPage
+}: {
+ numberOfPage: number
+}): JSX.Element => {
+ const [currentPage, setCurrentPage] = useState(0)
+
+ const handlePressPrevious = (): void => {
+ setCurrentPage(prev => Math.max(prev - 1, 0))
+ }
+
+ const handlePressNext = (): void => {
+ setCurrentPage(prev => Math.min(prev + 1, numberOfPage - 1))
+ }
+
+ return (
+ <>
+ Page Size: {numberOfPage}
+
+
+
+
+
+ >
+ )
+}
diff --git a/packages/k2-alpine/src/components/PageControl/PageControl.tsx b/packages/k2-alpine/src/components/PageControl/PageControl.tsx
new file mode 100644
index 000000000..77b3e8d45
--- /dev/null
+++ b/packages/k2-alpine/src/components/PageControl/PageControl.tsx
@@ -0,0 +1,145 @@
+import React, { useEffect, useState } from 'react'
+import { ViewStyle, View } from 'react-native'
+import Animated, {
+ runOnJS,
+ useAnimatedStyle,
+ useSharedValue,
+ withDelay,
+ withTiming
+} from 'react-native-reanimated'
+import { useTheme } from '../..'
+
+export const PageControl = ({
+ numberOfPage,
+ currentPage,
+ style
+}: {
+ numberOfPage: number
+ currentPage: number
+ style?: ViewStyle
+}): JSX.Element => {
+ const translationAnimation = useSharedValue(0)
+ const viewPortWidth =
+ (Configuration.dot.width + Configuration.gap) *
+ (Configuration.maxDotsInViewPort - 1) +
+ Configuration.dot.selectedWidth
+ const [translatedX, setTranslatedX] = useState(0)
+
+ useEffect(() => {
+ const currentOffset =
+ currentPage * (Configuration.dot.width + Configuration.gap)
+ const shouldTranslateLeft =
+ currentOffset + Configuration.dot.selectedWidth >
+ viewPortWidth - translatedX
+ const shouldTranslateRight = currentOffset < -translatedX
+ const targetTranslation = shouldTranslateLeft
+ ? translatedX - Configuration.dot.width - Configuration.gap
+ : shouldTranslateRight
+ ? translatedX + Configuration.dot.width + Configuration.gap
+ : translatedX
+
+ translationAnimation.value =
+ shouldTranslateLeft || shouldTranslateRight
+ ? withTiming(
+ targetTranslation,
+ { duration: Configuration.translationAnimation.duration },
+ () => {
+ runOnJS(setTranslatedX)(targetTranslation)
+ }
+ )
+ : targetTranslation
+ }, [currentPage, translationAnimation, viewPortWidth, translatedX])
+
+ const translationAnimatedStyle = useAnimatedStyle(() => {
+ return {
+ transform: [
+ {
+ translateX: translationAnimation.value
+ }
+ ]
+ }
+ })
+
+ return (
+
+
+
+ {Array.from({ length: numberOfPage }).map((_, index) => {
+ return
+ })}
+
+
+
+ )
+}
+
+const AnimatedDot = ({ selected }: { selected: boolean }): JSX.Element => {
+ const { theme } = useTheme()
+
+ const animatedStyle = useAnimatedStyle(() => {
+ return {
+ width: withDelay(
+ Configuration.dot.animation.delay,
+ withTiming(
+ selected ? Configuration.dot.selectedWidth : Configuration.dot.width,
+ { duration: Configuration.dot.animation.duration }
+ )
+ ),
+ opacity: withTiming(selected ? 1 : 0.4, {
+ duration: Configuration.dot.animation.duration
+ })
+ }
+ })
+
+ return (
+
+ )
+}
+
+const Configuration = {
+ gap: 5,
+ dot: {
+ width: 7,
+ height: 7,
+ selectedWidth: 17,
+ animation: {
+ delay: 0,
+ duration: 300
+ }
+ },
+ maxDotsInViewPort: 5,
+ translationAnimation: {
+ duration: 200
+ }
+}
diff --git a/packages/k2-alpine/src/components/PinInput/PinInput.stories.tsx b/packages/k2-alpine/src/components/PinInput/PinInput.stories.tsx
index d8a47b2cb..f54ecaa45 100644
--- a/packages/k2-alpine/src/components/PinInput/PinInput.stories.tsx
+++ b/packages/k2-alpine/src/components/PinInput/PinInput.stories.tsx
@@ -69,7 +69,7 @@ export const All = (): JSX.Element => {
marginBottom: 20,
justifyContent: 'space-between'
}}>
-
+
Your Pincode: {PIN_CODE}