@impulse-ui-native/pagination 5.0.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.
- package/LICENSE +21 -0
- package/README.md +41 -0
- package/dist/components/index.d.mts +6 -0
- package/dist/components/index.js +5 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/pagination-button.d.mts +17 -0
- package/dist/components/pagination-button.js +77 -0
- package/dist/components/pagination-button.js.map +1 -0
- package/dist/components/pagination.d.mts +9 -0
- package/dist/components/pagination.js +166 -0
- package/dist/components/pagination.js.map +1 -0
- package/dist/index.d.mts +6 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/types/index.d.mts +3 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/pagination-internal.types.d.mts +3 -0
- package/dist/types/pagination-internal.types.js +1 -0
- package/dist/types/pagination-internal.types.js.map +1 -0
- package/dist/types/pagination.types.d.mts +33 -0
- package/dist/types/pagination.types.js +1 -0
- package/dist/types/pagination.types.js.map +1 -0
- package/dist/utils/index.d.mts +5 -0
- package/dist/utils/index.js +2 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/pagination.utils.d.mts +12 -0
- package/dist/utils/pagination.utils.js +70 -0
- package/dist/utils/pagination.utils.js.map +1 -0
- package/package.json +63 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ImpulseUI Native contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# @impulse-ui-native/pagination
|
|
2
|
+
|
|
3
|
+
Token-aware page navigation for React Native mobile applications.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
pnpm add @impulse-ui-native/pagination
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Render the component inside `ThemeProvider` from `@impulse-ui-native/theme`.
|
|
12
|
+
The package expects compatible `react`, `react-native`, and `react-native-svg`
|
|
13
|
+
peer dependencies in the host application.
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import { Pagination } from "@impulse-ui-native/pagination";
|
|
19
|
+
|
|
20
|
+
export function ResultsPagination() {
|
|
21
|
+
return <Pagination defaultPage={1} pageCount={12} />;
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Use `page` and `onPageChange` for controlled state, or `defaultPage` for
|
|
26
|
+
uncontrolled state. Page values are normalized to the available range.
|
|
27
|
+
|
|
28
|
+
Set `compact` for the mobile-friendly previous/status/next layout:
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
<Pagination compact defaultPage={3} pageCount={12} />
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The control supports `small`, `medium`, and `large` sizes. Its visible page
|
|
35
|
+
window adapts to the measured width: it shows up to seven page items, condenses
|
|
36
|
+
to five items around the current page, and falls back to the compact status
|
|
37
|
+
layout when space is tighter. Set `compact` to force that layout. Override
|
|
38
|
+
`getCompactLabel` to localize the visible compact status text.
|
|
39
|
+
|
|
40
|
+
Pagination items use the shared primitives `Pressable`; pressed feedback comes
|
|
41
|
+
from that primitive and is not modeled as Pagination state or theme tokens.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/index.ts"],"sourcesContent":["export { Pagination } from \"./pagination\";\n"],"mappings":"AAAA,SAAS,kBAAkB;","names":[]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
+
import { IconProps } from '@impulse-ui-native/icon/types';
|
|
4
|
+
import { ComponentSize } from '@impulse-ui-native/theme';
|
|
5
|
+
|
|
6
|
+
interface PaginationButtonProps {
|
|
7
|
+
current?: boolean;
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
Icon?: IconProps["icon"];
|
|
10
|
+
label?: number;
|
|
11
|
+
onSelect: (page: number) => void;
|
|
12
|
+
size: ComponentSize;
|
|
13
|
+
targetPage: number;
|
|
14
|
+
}
|
|
15
|
+
declare const PaginationButton: react.MemoExoticComponent<({ current, disabled, Icon: IconComponent, label, onSelect, size, targetPage, }: PaginationButtonProps) => react_jsx_runtime.JSX.Element>;
|
|
16
|
+
|
|
17
|
+
export { PaginationButton };
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { memo } from "react";
|
|
3
|
+
import { StyleSheet } from "react-native";
|
|
4
|
+
import { useEventCallback } from "@impulse-ui-native/core";
|
|
5
|
+
import { Icon } from "@impulse-ui-native/icon/components/icon";
|
|
6
|
+
import { Pressable, Typography } from "@impulse-ui-native/primitives";
|
|
7
|
+
import {
|
|
8
|
+
getPaginationStateTokens,
|
|
9
|
+
useComponentsTokens,
|
|
10
|
+
useThemedStyles
|
|
11
|
+
} from "@impulse-ui-native/theme";
|
|
12
|
+
const PaginationButton = memo(function PaginationButton2({
|
|
13
|
+
current = false,
|
|
14
|
+
disabled = false,
|
|
15
|
+
Icon: IconComponent,
|
|
16
|
+
label,
|
|
17
|
+
onSelect,
|
|
18
|
+
size,
|
|
19
|
+
targetPage
|
|
20
|
+
}) {
|
|
21
|
+
const tokens = useComponentsTokens().pagination;
|
|
22
|
+
const styles = useThemedStyles(themedStyles, { current, disabled, size }, [
|
|
23
|
+
current,
|
|
24
|
+
disabled,
|
|
25
|
+
size
|
|
26
|
+
]);
|
|
27
|
+
const handlePress = useEventCallback((_event) => {
|
|
28
|
+
onSelect(targetPage);
|
|
29
|
+
});
|
|
30
|
+
return /* @__PURE__ */ jsx(
|
|
31
|
+
Pressable,
|
|
32
|
+
{
|
|
33
|
+
disabled,
|
|
34
|
+
hitSlop: tokens.sizes[size].hitSlop,
|
|
35
|
+
onPress: handlePress,
|
|
36
|
+
style: styles.root,
|
|
37
|
+
children: IconComponent ? /* @__PURE__ */ jsx(
|
|
38
|
+
Icon,
|
|
39
|
+
{
|
|
40
|
+
color: styles.content.color,
|
|
41
|
+
icon: IconComponent,
|
|
42
|
+
size: tokens.sizes[size].iconSize,
|
|
43
|
+
variant: "bold"
|
|
44
|
+
}
|
|
45
|
+
) : /* @__PURE__ */ jsx(Typography.Label, { numeric: true, style: styles.content, children: label })
|
|
46
|
+
}
|
|
47
|
+
);
|
|
48
|
+
});
|
|
49
|
+
function themedStyles(theme, props) {
|
|
50
|
+
const tokens = theme.components.pagination;
|
|
51
|
+
const sizeTokens = tokens.sizes[props.size];
|
|
52
|
+
const stateTokens = getPaginationStateTokens(tokens.states, {
|
|
53
|
+
current: props.current,
|
|
54
|
+
disabled: props.disabled
|
|
55
|
+
});
|
|
56
|
+
return StyleSheet.create({
|
|
57
|
+
root: {
|
|
58
|
+
alignItems: "center",
|
|
59
|
+
justifyContent: "center",
|
|
60
|
+
width: sizeTokens.controlSize,
|
|
61
|
+
height: sizeTokens.controlSize,
|
|
62
|
+
backgroundColor: stateTokens.backgroundColor,
|
|
63
|
+
borderColor: stateTokens.borderColor,
|
|
64
|
+
borderRadius: tokens.borderRadius,
|
|
65
|
+
borderWidth: tokens.borderWidth
|
|
66
|
+
},
|
|
67
|
+
content: {
|
|
68
|
+
color: stateTokens.color,
|
|
69
|
+
fontSize: sizeTokens.fontSize,
|
|
70
|
+
textAlign: "center"
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
export {
|
|
75
|
+
PaginationButton
|
|
76
|
+
};
|
|
77
|
+
//# sourceMappingURL=pagination-button.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/pagination-button.tsx"],"sourcesContent":["import type { GestureResponderEvent } from \"react-native\";\nimport { memo } from \"react\";\nimport { StyleSheet } from \"react-native\";\n\nimport type { IconProps } from \"@impulse-ui-native/icon/types\";\nimport type { AppTheme, ComponentSize } from \"@impulse-ui-native/theme\";\nimport { useEventCallback } from \"@impulse-ui-native/core\";\nimport { Icon } from \"@impulse-ui-native/icon/components/icon\";\nimport { Pressable, Typography } from \"@impulse-ui-native/primitives\";\nimport {\n getPaginationStateTokens,\n useComponentsTokens,\n useThemedStyles,\n} from \"@impulse-ui-native/theme\";\n\nimport type { PaginationButtonThemeProps } from \"../types\";\n\ninterface PaginationButtonProps {\n current?: boolean;\n disabled?: boolean;\n Icon?: IconProps[\"icon\"];\n label?: number;\n onSelect: (page: number) => void;\n size: ComponentSize;\n targetPage: number;\n}\n\nexport const PaginationButton = memo(function PaginationButton({\n current = false,\n disabled = false,\n Icon: IconComponent,\n label,\n onSelect,\n size,\n targetPage,\n}: PaginationButtonProps) {\n const tokens = useComponentsTokens().pagination;\n const styles = useThemedStyles(themedStyles, { current, disabled, size }, [\n current,\n disabled,\n size,\n ]);\n\n const handlePress = useEventCallback((_event: GestureResponderEvent) => {\n onSelect(targetPage);\n });\n\n return (\n <Pressable\n disabled={disabled}\n hitSlop={tokens.sizes[size].hitSlop}\n onPress={handlePress}\n style={styles.root}\n >\n {IconComponent ? (\n <Icon\n color={styles.content.color}\n icon={IconComponent}\n size={tokens.sizes[size].iconSize}\n variant=\"bold\"\n />\n ) : (\n <Typography.Label numeric style={styles.content}>\n {label}\n </Typography.Label>\n )}\n </Pressable>\n );\n});\n\nfunction themedStyles(theme: AppTheme, props: PaginationButtonThemeProps) {\n const tokens = theme.components.pagination;\n const sizeTokens = tokens.sizes[props.size];\n const stateTokens = getPaginationStateTokens(tokens.states, {\n current: props.current,\n disabled: props.disabled,\n });\n\n return StyleSheet.create({\n root: {\n alignItems: \"center\",\n justifyContent: \"center\",\n\n width: sizeTokens.controlSize,\n height: sizeTokens.controlSize,\n\n backgroundColor: stateTokens.backgroundColor,\n borderColor: stateTokens.borderColor,\n borderRadius: tokens.borderRadius,\n borderWidth: tokens.borderWidth,\n },\n content: {\n color: stateTokens.color,\n fontSize: sizeTokens.fontSize,\n textAlign: \"center\",\n },\n });\n}\n"],"mappings":"AAuDQ;AAtDR,SAAS,YAAY;AACrB,SAAS,kBAAkB;AAI3B,SAAS,wBAAwB;AACjC,SAAS,YAAY;AACrB,SAAS,WAAW,kBAAkB;AACtC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAcA,MAAM,mBAAmB,KAAK,SAASA,kBAAiB;AAAA,EAC7D,UAAU;AAAA,EACV,WAAW;AAAA,EACX,MAAM;AAAA,EACN;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA0B;AACxB,QAAM,SAAS,oBAAoB,EAAE;AACrC,QAAM,SAAS,gBAAgB,cAAc,EAAE,SAAS,UAAU,KAAK,GAAG;AAAA,IACxE;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,cAAc,iBAAiB,CAAC,WAAkC;AACtE,aAAS,UAAU;AAAA,EACrB,CAAC;AAED,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,SAAS,OAAO,MAAM,IAAI,EAAE;AAAA,MAC5B,SAAS;AAAA,MACT,OAAO,OAAO;AAAA,MAEb,0BACC;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,OAAO,QAAQ;AAAA,UACtB,MAAM;AAAA,UACN,MAAM,OAAO,MAAM,IAAI,EAAE;AAAA,UACzB,SAAQ;AAAA;AAAA,MACV,IAEA,oBAAC,WAAW,OAAX,EAAiB,SAAO,MAAC,OAAO,OAAO,SACrC,iBACH;AAAA;AAAA,EAEJ;AAEJ,CAAC;AAED,SAAS,aAAa,OAAiB,OAAmC;AACxE,QAAM,SAAS,MAAM,WAAW;AAChC,QAAM,aAAa,OAAO,MAAM,MAAM,IAAI;AAC1C,QAAM,cAAc,yBAAyB,OAAO,QAAQ;AAAA,IAC1D,SAAS,MAAM;AAAA,IACf,UAAU,MAAM;AAAA,EAClB,CAAC;AAED,SAAO,WAAW,OAAO;AAAA,IACvB,MAAM;AAAA,MACJ,YAAY;AAAA,MACZ,gBAAgB;AAAA,MAEhB,OAAO,WAAW;AAAA,MAClB,QAAQ,WAAW;AAAA,MAEnB,iBAAiB,YAAY;AAAA,MAC7B,aAAa,YAAY;AAAA,MACzB,cAAc,OAAO;AAAA,MACrB,aAAa,OAAO;AAAA,IACtB;AAAA,IACA,SAAS;AAAA,MACP,OAAO,YAAY;AAAA,MACnB,UAAU,WAAW;AAAA,MACrB,WAAW;AAAA,IACb;AAAA,EACF,CAAC;AACH;","names":["PaginationButton"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
+
import { PaginationProps } from '../types/pagination.types.mjs';
|
|
4
|
+
import 'react-native';
|
|
5
|
+
import '@impulse-ui-native/theme';
|
|
6
|
+
|
|
7
|
+
declare const Pagination: react.MemoExoticComponent<({ compact, defaultPage, disabled, getCompactLabel, onLayout, onPageChange, page: pageProp, pageCount, size, style, ...props }: PaginationProps) => react_jsx_runtime.JSX.Element>;
|
|
8
|
+
|
|
9
|
+
export { Pagination };
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { memo, useMemo, useState } from "react";
|
|
3
|
+
import { I18nManager, StyleSheet } from "react-native";
|
|
4
|
+
import {
|
|
5
|
+
useControllableState,
|
|
6
|
+
useEventCallback
|
|
7
|
+
} from "@impulse-ui-native/core";
|
|
8
|
+
import { CaretLeftIcon } from "@impulse-ui-native/icon/icons/caret-left";
|
|
9
|
+
import { CaretRightIcon } from "@impulse-ui-native/icon/icons/caret-right";
|
|
10
|
+
import { Typography, View } from "@impulse-ui-native/primitives";
|
|
11
|
+
import {
|
|
12
|
+
getPaginationStateTokens,
|
|
13
|
+
useComponentsTokens,
|
|
14
|
+
useThemedStyles
|
|
15
|
+
} from "@impulse-ui-native/theme";
|
|
16
|
+
import {
|
|
17
|
+
clampPage,
|
|
18
|
+
getDefaultCompactLabel,
|
|
19
|
+
getPaginationItems,
|
|
20
|
+
getPaginationWindowLayout,
|
|
21
|
+
normalizePageCount
|
|
22
|
+
} from "../utils";
|
|
23
|
+
import { PaginationButton } from "./pagination-button";
|
|
24
|
+
const Pagination = memo(function Pagination2({
|
|
25
|
+
compact = false,
|
|
26
|
+
defaultPage = 1,
|
|
27
|
+
disabled = false,
|
|
28
|
+
getCompactLabel = getDefaultCompactLabel,
|
|
29
|
+
onLayout,
|
|
30
|
+
onPageChange,
|
|
31
|
+
page: pageProp,
|
|
32
|
+
pageCount,
|
|
33
|
+
size = "medium",
|
|
34
|
+
style,
|
|
35
|
+
...props
|
|
36
|
+
}) {
|
|
37
|
+
const tokens = useComponentsTokens().pagination;
|
|
38
|
+
const [availableWidth, setAvailableWidth] = useState();
|
|
39
|
+
const normalizedPageCount = normalizePageCount(pageCount);
|
|
40
|
+
const [page, setPage] = useControllableState({
|
|
41
|
+
prop: pageProp,
|
|
42
|
+
defaultProp: clampPage(defaultPage, normalizedPageCount),
|
|
43
|
+
onChange: onPageChange
|
|
44
|
+
});
|
|
45
|
+
const resolvedPage = clampPage(page, normalizedPageCount);
|
|
46
|
+
const styles = useThemedStyles(themedStyles, { disabled, size }, [
|
|
47
|
+
disabled,
|
|
48
|
+
size
|
|
49
|
+
]);
|
|
50
|
+
const windowLayout = useMemo(
|
|
51
|
+
() => getPaginationWindowLayout(
|
|
52
|
+
availableWidth,
|
|
53
|
+
normalizedPageCount,
|
|
54
|
+
tokens.sizes[size].controlSize,
|
|
55
|
+
tokens.sizes[size].compactMinWidth,
|
|
56
|
+
tokens.gap
|
|
57
|
+
),
|
|
58
|
+
[availableWidth, normalizedPageCount, size, tokens.gap, tokens.sizes]
|
|
59
|
+
);
|
|
60
|
+
const items = useMemo(
|
|
61
|
+
() => getPaginationItems(
|
|
62
|
+
resolvedPage,
|
|
63
|
+
normalizedPageCount,
|
|
64
|
+
windowLayout === "condensed" ? 5 : 7
|
|
65
|
+
),
|
|
66
|
+
[normalizedPageCount, resolvedPage, windowLayout]
|
|
67
|
+
);
|
|
68
|
+
const rootStyle = useMemo(() => [styles.root, style], [style, styles.root]);
|
|
69
|
+
const selectPage = useEventCallback((nextPage) => {
|
|
70
|
+
if (!disabled) {
|
|
71
|
+
setPage(clampPage(nextPage, normalizedPageCount));
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
const handleLayout = useEventCallback((event) => {
|
|
75
|
+
setAvailableWidth(event.nativeEvent.layout.width);
|
|
76
|
+
onLayout?.(event);
|
|
77
|
+
});
|
|
78
|
+
const PreviousIcon = I18nManager.isRTL ? CaretRightIcon : CaretLeftIcon;
|
|
79
|
+
const NextIcon = I18nManager.isRTL ? CaretLeftIcon : CaretRightIcon;
|
|
80
|
+
const previousDisabled = disabled || resolvedPage === 1;
|
|
81
|
+
const nextDisabled = disabled || resolvedPage === normalizedPageCount;
|
|
82
|
+
const showCompact = compact || windowLayout === "compact";
|
|
83
|
+
return /* @__PURE__ */ jsxs(View, { ...props, onLayout: handleLayout, style: rootStyle, children: [
|
|
84
|
+
/* @__PURE__ */ jsx(
|
|
85
|
+
PaginationButton,
|
|
86
|
+
{
|
|
87
|
+
disabled: previousDisabled,
|
|
88
|
+
Icon: PreviousIcon,
|
|
89
|
+
onSelect: selectPage,
|
|
90
|
+
size,
|
|
91
|
+
targetPage: resolvedPage - 1
|
|
92
|
+
}
|
|
93
|
+
),
|
|
94
|
+
showCompact ? /* @__PURE__ */ jsx(View, { style: styles.compactStatus, children: /* @__PURE__ */ jsx(Typography.Label, { numeric: true, style: styles.compactLabel, children: getCompactLabel(resolvedPage, normalizedPageCount) }) }) : items.map(
|
|
95
|
+
(item) => typeof item === "number" ? /* @__PURE__ */ jsx(
|
|
96
|
+
PaginationButton,
|
|
97
|
+
{
|
|
98
|
+
current: item === resolvedPage,
|
|
99
|
+
disabled,
|
|
100
|
+
label: item,
|
|
101
|
+
onSelect: selectPage,
|
|
102
|
+
size,
|
|
103
|
+
targetPage: item
|
|
104
|
+
},
|
|
105
|
+
item
|
|
106
|
+
) : /* @__PURE__ */ jsx(View, { style: styles.ellipsis, children: /* @__PURE__ */ jsx(Typography.Label, { style: styles.ellipsisLabel, children: "\u2026" }) }, item)
|
|
107
|
+
),
|
|
108
|
+
/* @__PURE__ */ jsx(
|
|
109
|
+
PaginationButton,
|
|
110
|
+
{
|
|
111
|
+
disabled: nextDisabled,
|
|
112
|
+
Icon: NextIcon,
|
|
113
|
+
onSelect: selectPage,
|
|
114
|
+
size,
|
|
115
|
+
targetPage: resolvedPage + 1
|
|
116
|
+
}
|
|
117
|
+
)
|
|
118
|
+
] });
|
|
119
|
+
});
|
|
120
|
+
function themedStyles(theme, props) {
|
|
121
|
+
const tokens = theme.components.pagination;
|
|
122
|
+
const sizeTokens = tokens.sizes[props.size];
|
|
123
|
+
const statusTokens = getPaginationStateTokens(tokens.states, {
|
|
124
|
+
current: false,
|
|
125
|
+
disabled: props.disabled
|
|
126
|
+
});
|
|
127
|
+
return StyleSheet.create({
|
|
128
|
+
root: {
|
|
129
|
+
alignItems: "center",
|
|
130
|
+
flexDirection: "row",
|
|
131
|
+
flexWrap: "nowrap",
|
|
132
|
+
gap: tokens.gap
|
|
133
|
+
},
|
|
134
|
+
compactStatus: {
|
|
135
|
+
alignItems: "center",
|
|
136
|
+
justifyContent: "center",
|
|
137
|
+
minWidth: sizeTokens.compactMinWidth,
|
|
138
|
+
height: sizeTokens.controlSize,
|
|
139
|
+
paddingHorizontal: sizeTokens.paddingHorizontal,
|
|
140
|
+
backgroundColor: statusTokens.backgroundColor,
|
|
141
|
+
borderColor: statusTokens.borderColor,
|
|
142
|
+
borderRadius: tokens.borderRadius,
|
|
143
|
+
borderWidth: tokens.borderWidth
|
|
144
|
+
},
|
|
145
|
+
compactLabel: {
|
|
146
|
+
color: statusTokens.color,
|
|
147
|
+
fontSize: sizeTokens.fontSize,
|
|
148
|
+
textAlign: "center"
|
|
149
|
+
},
|
|
150
|
+
ellipsis: {
|
|
151
|
+
alignItems: "center",
|
|
152
|
+
justifyContent: "center",
|
|
153
|
+
width: sizeTokens.controlSize,
|
|
154
|
+
height: sizeTokens.controlSize
|
|
155
|
+
},
|
|
156
|
+
ellipsisLabel: {
|
|
157
|
+
color: statusTokens.ellipsisColor,
|
|
158
|
+
fontSize: sizeTokens.fontSize,
|
|
159
|
+
textAlign: "center"
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
export {
|
|
164
|
+
Pagination
|
|
165
|
+
};
|
|
166
|
+
//# sourceMappingURL=pagination.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/pagination.tsx"],"sourcesContent":["import type { LayoutChangeEvent } from \"react-native\";\nimport { memo, useMemo, useState } from \"react\";\nimport { I18nManager, StyleSheet } from \"react-native\";\n\nimport type { AppTheme } from \"@impulse-ui-native/theme\";\nimport {\n useControllableState,\n useEventCallback,\n} from \"@impulse-ui-native/core\";\nimport { CaretLeftIcon } from \"@impulse-ui-native/icon/icons/caret-left\";\nimport { CaretRightIcon } from \"@impulse-ui-native/icon/icons/caret-right\";\nimport { Typography, View } from \"@impulse-ui-native/primitives\";\nimport {\n getPaginationStateTokens,\n useComponentsTokens,\n useThemedStyles,\n} from \"@impulse-ui-native/theme\";\n\nimport type { PaginationProps, PaginationThemeProps } from \"../types\";\nimport {\n clampPage,\n getDefaultCompactLabel,\n getPaginationItems,\n getPaginationWindowLayout,\n normalizePageCount,\n} from \"../utils\";\nimport { PaginationButton } from \"./pagination-button\";\n\nexport const Pagination = memo(function Pagination({\n compact = false,\n defaultPage = 1,\n disabled = false,\n getCompactLabel = getDefaultCompactLabel,\n onLayout,\n onPageChange,\n page: pageProp,\n pageCount,\n size = \"medium\",\n style,\n ...props\n}: PaginationProps) {\n const tokens = useComponentsTokens().pagination;\n const [availableWidth, setAvailableWidth] = useState<number>();\n const normalizedPageCount = normalizePageCount(pageCount);\n const [page, setPage] = useControllableState<number>({\n prop: pageProp,\n defaultProp: clampPage(defaultPage, normalizedPageCount),\n onChange: onPageChange,\n });\n const resolvedPage = clampPage(page, normalizedPageCount);\n const styles = useThemedStyles(themedStyles, { disabled, size }, [\n disabled,\n size,\n ]);\n\n const windowLayout = useMemo(\n () =>\n getPaginationWindowLayout(\n availableWidth,\n normalizedPageCount,\n tokens.sizes[size].controlSize,\n tokens.sizes[size].compactMinWidth,\n tokens.gap,\n ),\n [availableWidth, normalizedPageCount, size, tokens.gap, tokens.sizes],\n );\n const items = useMemo(\n () =>\n getPaginationItems(\n resolvedPage,\n normalizedPageCount,\n windowLayout === \"condensed\" ? 5 : 7,\n ),\n [normalizedPageCount, resolvedPage, windowLayout],\n );\n const rootStyle = useMemo(() => [styles.root, style], [style, styles.root]);\n\n const selectPage = useEventCallback((nextPage: number) => {\n if (!disabled) {\n setPage(clampPage(nextPage, normalizedPageCount));\n }\n });\n const handleLayout = useEventCallback((event: LayoutChangeEvent) => {\n setAvailableWidth(event.nativeEvent.layout.width);\n onLayout?.(event);\n });\n\n const PreviousIcon = I18nManager.isRTL ? CaretRightIcon : CaretLeftIcon;\n const NextIcon = I18nManager.isRTL ? CaretLeftIcon : CaretRightIcon;\n const previousDisabled = disabled || resolvedPage === 1;\n const nextDisabled = disabled || resolvedPage === normalizedPageCount;\n const showCompact = compact || windowLayout === \"compact\";\n\n return (\n <View {...props} onLayout={handleLayout} style={rootStyle}>\n <PaginationButton\n disabled={previousDisabled}\n Icon={PreviousIcon}\n onSelect={selectPage}\n size={size}\n targetPage={resolvedPage - 1}\n />\n\n {showCompact ? (\n <View style={styles.compactStatus}>\n <Typography.Label numeric style={styles.compactLabel}>\n {getCompactLabel(resolvedPage, normalizedPageCount)}\n </Typography.Label>\n </View>\n ) : (\n items.map((item) =>\n typeof item === \"number\" ? (\n <PaginationButton\n key={item}\n current={item === resolvedPage}\n disabled={disabled}\n label={item}\n onSelect={selectPage}\n size={size}\n targetPage={item}\n />\n ) : (\n <View key={item} style={styles.ellipsis}>\n <Typography.Label style={styles.ellipsisLabel}>\n {\"\\u2026\"}\n </Typography.Label>\n </View>\n ),\n )\n )}\n\n <PaginationButton\n disabled={nextDisabled}\n Icon={NextIcon}\n onSelect={selectPage}\n size={size}\n targetPage={resolvedPage + 1}\n />\n </View>\n );\n});\n\nfunction themedStyles(theme: AppTheme, props: PaginationThemeProps) {\n const tokens = theme.components.pagination;\n const sizeTokens = tokens.sizes[props.size];\n const statusTokens = getPaginationStateTokens(tokens.states, {\n current: false,\n disabled: props.disabled,\n });\n\n return StyleSheet.create({\n root: {\n alignItems: \"center\",\n flexDirection: \"row\",\n flexWrap: \"nowrap\",\n gap: tokens.gap,\n },\n compactStatus: {\n alignItems: \"center\",\n justifyContent: \"center\",\n\n minWidth: sizeTokens.compactMinWidth,\n height: sizeTokens.controlSize,\n paddingHorizontal: sizeTokens.paddingHorizontal,\n\n backgroundColor: statusTokens.backgroundColor,\n borderColor: statusTokens.borderColor,\n borderRadius: tokens.borderRadius,\n borderWidth: tokens.borderWidth,\n },\n compactLabel: {\n color: statusTokens.color,\n fontSize: sizeTokens.fontSize,\n textAlign: \"center\",\n },\n ellipsis: {\n alignItems: \"center\",\n justifyContent: \"center\",\n width: sizeTokens.controlSize,\n height: sizeTokens.controlSize,\n },\n ellipsisLabel: {\n color: statusTokens.ellipsisColor,\n fontSize: sizeTokens.fontSize,\n textAlign: \"center\",\n },\n });\n}\n"],"mappings":"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","names":["Pagination"]}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { Pagination } from './components/pagination.mjs';
|
|
2
|
+
export { PaginationButtonThemeProps, PaginationCompactLabelFormatter, PaginationItemValue, PaginationProps, PaginationThemeProps } from './types/pagination.types.mjs';
|
|
3
|
+
import 'react';
|
|
4
|
+
import 'react/jsx-runtime';
|
|
5
|
+
import 'react-native';
|
|
6
|
+
import '@impulse-ui-native/theme';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from \"./components\";\nexport * from \"./types\";\n"],"mappings":"AAAA,cAAc;AACd,cAAc;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/types/index.ts"],"sourcesContent":["export * from \"./pagination.types\";\n"],"mappings":"AAAA,cAAc;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=pagination-internal.types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { ViewProps } from 'react-native';
|
|
2
|
+
import { ComponentSize } from '@impulse-ui-native/theme';
|
|
3
|
+
|
|
4
|
+
type PaginationItemValue = number | "start-ellipsis" | "end-ellipsis";
|
|
5
|
+
type PaginationCompactLabelFormatter = (page: number, pageCount: number) => string;
|
|
6
|
+
interface PaginationCommonProps extends Omit<ViewProps, "children"> {
|
|
7
|
+
compact?: boolean;
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
getCompactLabel?: PaginationCompactLabelFormatter;
|
|
10
|
+
onPageChange?: (page: number) => void;
|
|
11
|
+
pageCount: number;
|
|
12
|
+
size?: ComponentSize;
|
|
13
|
+
}
|
|
14
|
+
interface PaginationControlledProps extends PaginationCommonProps {
|
|
15
|
+
defaultPage?: never;
|
|
16
|
+
page: number;
|
|
17
|
+
}
|
|
18
|
+
interface PaginationUncontrolledProps extends PaginationCommonProps {
|
|
19
|
+
defaultPage?: number;
|
|
20
|
+
page?: never;
|
|
21
|
+
}
|
|
22
|
+
type PaginationProps = PaginationControlledProps | PaginationUncontrolledProps;
|
|
23
|
+
interface PaginationThemeProps {
|
|
24
|
+
disabled: boolean;
|
|
25
|
+
size: ComponentSize;
|
|
26
|
+
}
|
|
27
|
+
interface PaginationButtonThemeProps {
|
|
28
|
+
current: boolean;
|
|
29
|
+
disabled: boolean;
|
|
30
|
+
size: ComponentSize;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type { PaginationButtonThemeProps, PaginationCompactLabelFormatter, PaginationItemValue, PaginationProps, PaginationThemeProps };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=pagination.types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { clampPage, getDefaultCompactLabel, getPaginationItems, getPaginationWindowLayout, normalizePageCount } from './pagination.utils.mjs';
|
|
2
|
+
import '../types/pagination.types.mjs';
|
|
3
|
+
import 'react-native';
|
|
4
|
+
import '@impulse-ui-native/theme';
|
|
5
|
+
import '../types/pagination-internal.types.mjs';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/index.ts"],"sourcesContent":["export * from \"./pagination.utils\";\n"],"mappings":"AAAA,cAAc;","names":[]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { PaginationItemValue } from '../types/pagination.types.mjs';
|
|
2
|
+
import { PaginationWindowLayout } from '../types/pagination-internal.types.mjs';
|
|
3
|
+
import 'react-native';
|
|
4
|
+
import '@impulse-ui-native/theme';
|
|
5
|
+
|
|
6
|
+
declare function normalizePageCount(pageCount: number): number;
|
|
7
|
+
declare function clampPage(page: number, pageCount: number): number;
|
|
8
|
+
declare function getPaginationItems(page: number, pageCount: number, maximumItemCount?: number): PaginationItemValue[];
|
|
9
|
+
declare function getPaginationWindowLayout(availableWidth: number | undefined, pageCount: number, controlSize: number, compactMinWidth: number, gap: number): PaginationWindowLayout;
|
|
10
|
+
declare function getDefaultCompactLabel(page: number, pageCount: number): string;
|
|
11
|
+
|
|
12
|
+
export { clampPage, getDefaultCompactLabel, getPaginationItems, getPaginationWindowLayout, normalizePageCount };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
function normalizePageCount(pageCount) {
|
|
2
|
+
if (!Number.isFinite(pageCount)) {
|
|
3
|
+
return 1;
|
|
4
|
+
}
|
|
5
|
+
return Math.max(1, Math.floor(pageCount));
|
|
6
|
+
}
|
|
7
|
+
function clampPage(page, pageCount) {
|
|
8
|
+
if (!Number.isFinite(page)) {
|
|
9
|
+
return 1;
|
|
10
|
+
}
|
|
11
|
+
return Math.min(Math.max(1, Math.floor(page)), pageCount);
|
|
12
|
+
}
|
|
13
|
+
function getPaginationItems(page, pageCount, maximumItemCount = 7) {
|
|
14
|
+
const normalizedMaximumItemCount = maximumItemCount >= 7 ? 7 : 5;
|
|
15
|
+
if (pageCount <= normalizedMaximumItemCount) {
|
|
16
|
+
return Array.from({ length: pageCount }, (_, index) => index + 1);
|
|
17
|
+
}
|
|
18
|
+
if (normalizedMaximumItemCount === 5) {
|
|
19
|
+
if (page <= 3) {
|
|
20
|
+
return [1, 2, 3, "end-ellipsis", pageCount];
|
|
21
|
+
}
|
|
22
|
+
if (page >= pageCount - 2) {
|
|
23
|
+
return [1, "start-ellipsis", pageCount - 2, pageCount - 1, pageCount];
|
|
24
|
+
}
|
|
25
|
+
return [1, "start-ellipsis", page, "end-ellipsis", pageCount];
|
|
26
|
+
}
|
|
27
|
+
if (page <= 3) {
|
|
28
|
+
return [1, 2, 3, "end-ellipsis", pageCount];
|
|
29
|
+
}
|
|
30
|
+
if (page >= pageCount - 2) {
|
|
31
|
+
return [1, "start-ellipsis", pageCount - 2, pageCount - 1, pageCount];
|
|
32
|
+
}
|
|
33
|
+
return [
|
|
34
|
+
1,
|
|
35
|
+
"start-ellipsis",
|
|
36
|
+
page - 1,
|
|
37
|
+
page,
|
|
38
|
+
page + 1,
|
|
39
|
+
"end-ellipsis",
|
|
40
|
+
pageCount
|
|
41
|
+
];
|
|
42
|
+
}
|
|
43
|
+
function getPaginationWindowLayout(availableWidth, pageCount, controlSize, compactMinWidth, gap) {
|
|
44
|
+
if (availableWidth === void 0) {
|
|
45
|
+
return "full";
|
|
46
|
+
}
|
|
47
|
+
const fullItemCount = Math.min(pageCount, 7) + 2;
|
|
48
|
+
const fullWidth = fullItemCount * controlSize + (fullItemCount - 1) * gap;
|
|
49
|
+
if (availableWidth >= fullWidth) {
|
|
50
|
+
return "full";
|
|
51
|
+
}
|
|
52
|
+
const condensedItemCount = Math.min(pageCount, 5) + 2;
|
|
53
|
+
const condensedWidth = condensedItemCount * controlSize + (condensedItemCount - 1) * gap;
|
|
54
|
+
if (availableWidth >= condensedWidth) {
|
|
55
|
+
return "condensed";
|
|
56
|
+
}
|
|
57
|
+
const compactWidth = controlSize * 2 + compactMinWidth + gap * 2;
|
|
58
|
+
return compactWidth < condensedWidth ? "compact" : "full";
|
|
59
|
+
}
|
|
60
|
+
function getDefaultCompactLabel(page, pageCount) {
|
|
61
|
+
return `Page ${page} of ${pageCount}`;
|
|
62
|
+
}
|
|
63
|
+
export {
|
|
64
|
+
clampPage,
|
|
65
|
+
getDefaultCompactLabel,
|
|
66
|
+
getPaginationItems,
|
|
67
|
+
getPaginationWindowLayout,
|
|
68
|
+
normalizePageCount
|
|
69
|
+
};
|
|
70
|
+
//# sourceMappingURL=pagination.utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/pagination.utils.ts"],"sourcesContent":["import type { PaginationItemValue } from \"../types\";\nimport type { PaginationWindowLayout } from \"../types/pagination-internal.types\";\n\nexport function normalizePageCount(pageCount: number): number {\n if (!Number.isFinite(pageCount)) {\n return 1;\n }\n\n return Math.max(1, Math.floor(pageCount));\n}\n\nexport function clampPage(page: number, pageCount: number): number {\n if (!Number.isFinite(page)) {\n return 1;\n }\n\n return Math.min(Math.max(1, Math.floor(page)), pageCount);\n}\n\nexport function getPaginationItems(\n page: number,\n pageCount: number,\n maximumItemCount = 7,\n): PaginationItemValue[] {\n const normalizedMaximumItemCount = maximumItemCount >= 7 ? 7 : 5;\n\n if (pageCount <= normalizedMaximumItemCount) {\n return Array.from({ length: pageCount }, (_, index) => index + 1);\n }\n\n if (normalizedMaximumItemCount === 5) {\n if (page <= 3) {\n return [1, 2, 3, \"end-ellipsis\", pageCount];\n }\n\n if (page >= pageCount - 2) {\n return [1, \"start-ellipsis\", pageCount - 2, pageCount - 1, pageCount];\n }\n\n return [1, \"start-ellipsis\", page, \"end-ellipsis\", pageCount];\n }\n\n if (page <= 3) {\n return [1, 2, 3, \"end-ellipsis\", pageCount];\n }\n\n if (page >= pageCount - 2) {\n return [1, \"start-ellipsis\", pageCount - 2, pageCount - 1, pageCount];\n }\n\n return [\n 1,\n \"start-ellipsis\",\n page - 1,\n page,\n page + 1,\n \"end-ellipsis\",\n pageCount,\n ];\n}\n\nexport function getPaginationWindowLayout(\n availableWidth: number | undefined,\n pageCount: number,\n controlSize: number,\n compactMinWidth: number,\n gap: number,\n): PaginationWindowLayout {\n if (availableWidth === undefined) {\n return \"full\";\n }\n\n const fullItemCount = Math.min(pageCount, 7) + 2;\n const fullWidth = fullItemCount * controlSize + (fullItemCount - 1) * gap;\n\n if (availableWidth >= fullWidth) {\n return \"full\";\n }\n\n const condensedItemCount = Math.min(pageCount, 5) + 2;\n const condensedWidth =\n condensedItemCount * controlSize + (condensedItemCount - 1) * gap;\n\n if (availableWidth >= condensedWidth) {\n return \"condensed\";\n }\n\n const compactWidth = controlSize * 2 + compactMinWidth + gap * 2;\n\n return compactWidth < condensedWidth ? \"compact\" : \"full\";\n}\n\nexport function getDefaultCompactLabel(\n page: number,\n pageCount: number,\n): string {\n return `Page ${page} of ${pageCount}`;\n}\n"],"mappings":"AAGO,SAAS,mBAAmB,WAA2B;AAC5D,MAAI,CAAC,OAAO,SAAS,SAAS,GAAG;AAC/B,WAAO;AAAA,EACT;AAEA,SAAO,KAAK,IAAI,GAAG,KAAK,MAAM,SAAS,CAAC;AAC1C;AAEO,SAAS,UAAU,MAAc,WAA2B;AACjE,MAAI,CAAC,OAAO,SAAS,IAAI,GAAG;AAC1B,WAAO;AAAA,EACT;AAEA,SAAO,KAAK,IAAI,KAAK,IAAI,GAAG,KAAK,MAAM,IAAI,CAAC,GAAG,SAAS;AAC1D;AAEO,SAAS,mBACd,MACA,WACA,mBAAmB,GACI;AACvB,QAAM,6BAA6B,oBAAoB,IAAI,IAAI;AAE/D,MAAI,aAAa,4BAA4B;AAC3C,WAAO,MAAM,KAAK,EAAE,QAAQ,UAAU,GAAG,CAAC,GAAG,UAAU,QAAQ,CAAC;AAAA,EAClE;AAEA,MAAI,+BAA+B,GAAG;AACpC,QAAI,QAAQ,GAAG;AACb,aAAO,CAAC,GAAG,GAAG,GAAG,gBAAgB,SAAS;AAAA,IAC5C;AAEA,QAAI,QAAQ,YAAY,GAAG;AACzB,aAAO,CAAC,GAAG,kBAAkB,YAAY,GAAG,YAAY,GAAG,SAAS;AAAA,IACtE;AAEA,WAAO,CAAC,GAAG,kBAAkB,MAAM,gBAAgB,SAAS;AAAA,EAC9D;AAEA,MAAI,QAAQ,GAAG;AACb,WAAO,CAAC,GAAG,GAAG,GAAG,gBAAgB,SAAS;AAAA,EAC5C;AAEA,MAAI,QAAQ,YAAY,GAAG;AACzB,WAAO,CAAC,GAAG,kBAAkB,YAAY,GAAG,YAAY,GAAG,SAAS;AAAA,EACtE;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,OAAO;AAAA,IACP;AAAA,IACA,OAAO;AAAA,IACP;AAAA,IACA;AAAA,EACF;AACF;AAEO,SAAS,0BACd,gBACA,WACA,aACA,iBACA,KACwB;AACxB,MAAI,mBAAmB,QAAW;AAChC,WAAO;AAAA,EACT;AAEA,QAAM,gBAAgB,KAAK,IAAI,WAAW,CAAC,IAAI;AAC/C,QAAM,YAAY,gBAAgB,eAAe,gBAAgB,KAAK;AAEtE,MAAI,kBAAkB,WAAW;AAC/B,WAAO;AAAA,EACT;AAEA,QAAM,qBAAqB,KAAK,IAAI,WAAW,CAAC,IAAI;AACpD,QAAM,iBACJ,qBAAqB,eAAe,qBAAqB,KAAK;AAEhE,MAAI,kBAAkB,gBAAgB;AACpC,WAAO;AAAA,EACT;AAEA,QAAM,eAAe,cAAc,IAAI,kBAAkB,MAAM;AAE/D,SAAO,eAAe,iBAAiB,YAAY;AACrD;AAEO,SAAS,uBACd,MACA,WACQ;AACR,SAAO,QAAQ,IAAI,OAAO,SAAS;AACrC;","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@impulse-ui-native/pagination",
|
|
3
|
+
"version": "5.0.0",
|
|
4
|
+
"description": "Token-aware pagination controls for ImpulseUI Native applications.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"react-native",
|
|
7
|
+
"pagination",
|
|
8
|
+
"navigation",
|
|
9
|
+
"components",
|
|
10
|
+
"impulse-ui-native"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"source": "src/index.ts",
|
|
14
|
+
"module": "dist/index.js",
|
|
15
|
+
"types": "dist/index.d.mts",
|
|
16
|
+
"react-native": "src/index.ts",
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./dist/index.d.mts",
|
|
20
|
+
"react-native": "./src/index.ts",
|
|
21
|
+
"import": "./dist/index.js"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"dist",
|
|
26
|
+
"README.md",
|
|
27
|
+
"LICENSE"
|
|
28
|
+
],
|
|
29
|
+
"sideEffects": false,
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@impulse-ui-native/core": "5.0.0",
|
|
32
|
+
"@impulse-ui-native/icon": "5.0.0",
|
|
33
|
+
"@impulse-ui-native/theme": "5.0.0",
|
|
34
|
+
"@impulse-ui-native/primitives": "5.0.0"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/react": "~19.2.14",
|
|
38
|
+
"eslint": "^9.38.0",
|
|
39
|
+
"prettier": "^3.6.2",
|
|
40
|
+
"react": "19.2.3",
|
|
41
|
+
"react-native": "0.86.2",
|
|
42
|
+
"react-native-svg": "15.15.4",
|
|
43
|
+
"typescript": "~6.0.3",
|
|
44
|
+
"@impulse-ui-native/eslint-config": "1.0.0",
|
|
45
|
+
"@impulse-ui-native/prettier-config": "1.0.0",
|
|
46
|
+
"@impulse-ui-native/tsconfig": "1.0.0"
|
|
47
|
+
},
|
|
48
|
+
"peerDependencies": {
|
|
49
|
+
"react": ">=18",
|
|
50
|
+
"react-native": ">=0.73",
|
|
51
|
+
"react-native-svg": ">=13.9.0"
|
|
52
|
+
},
|
|
53
|
+
"publishConfig": {
|
|
54
|
+
"access": "public"
|
|
55
|
+
},
|
|
56
|
+
"prettier": "@impulse-ui-native/prettier-config",
|
|
57
|
+
"scripts": {
|
|
58
|
+
"build": "tsup --config tsup.config.ts",
|
|
59
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
60
|
+
"lint": "pnpm exec eslint . --fix",
|
|
61
|
+
"format": "prettier --write \"./**/*.{ts,tsx,js,jsx,json,md}\" --ignore-path ../../.prettierignore"
|
|
62
|
+
}
|
|
63
|
+
}
|