react-native-app-onboard 0.1.9 → 0.2.1

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.
Files changed (80) hide show
  1. package/README.md +89 -7
  2. package/lib/commonjs/components/CustomPages.js +31 -55
  3. package/lib/commonjs/components/CustomPages.js.map +1 -1
  4. package/lib/commonjs/components/OnboardingPages.js +63 -79
  5. package/lib/commonjs/components/OnboardingPages.js.map +1 -1
  6. package/lib/commonjs/components/Page.js +8 -3
  7. package/lib/commonjs/components/Page.js.map +1 -1
  8. package/lib/commonjs/components/Pagination.js +75 -13
  9. package/lib/commonjs/components/Pagination.js.map +1 -1
  10. package/lib/commonjs/components/Swiper.js +58 -85
  11. package/lib/commonjs/components/Swiper.js.map +1 -1
  12. package/lib/commonjs/components/button.js +3 -1
  13. package/lib/commonjs/components/button.js.map +1 -1
  14. package/lib/commonjs/context/OnboardingContext.js +101 -21
  15. package/lib/commonjs/context/OnboardingContext.js.map +1 -1
  16. package/lib/commonjs/hooks/useOnboarding.js +1 -1
  17. package/lib/commonjs/hooks/useOnboarding.js.map +1 -1
  18. package/lib/commonjs/index.js +33 -2
  19. package/lib/commonjs/index.js.map +1 -1
  20. package/lib/commonjs/utils/color.js +308 -0
  21. package/lib/commonjs/utils/color.js.map +1 -0
  22. package/lib/commonjs/utils/persistence.js +51 -0
  23. package/lib/commonjs/utils/persistence.js.map +1 -0
  24. package/lib/module/components/CustomPages.js +31 -55
  25. package/lib/module/components/CustomPages.js.map +1 -1
  26. package/lib/module/components/OnboardingPages.js +64 -79
  27. package/lib/module/components/OnboardingPages.js.map +1 -1
  28. package/lib/module/components/Page.js +8 -3
  29. package/lib/module/components/Page.js.map +1 -1
  30. package/lib/module/components/Pagination.js +76 -14
  31. package/lib/module/components/Pagination.js.map +1 -1
  32. package/lib/module/components/Swiper.js +59 -86
  33. package/lib/module/components/Swiper.js.map +1 -1
  34. package/lib/module/components/button.js +3 -1
  35. package/lib/module/components/button.js.map +1 -1
  36. package/lib/module/context/OnboardingContext.js +102 -22
  37. package/lib/module/context/OnboardingContext.js.map +1 -1
  38. package/lib/module/hooks/useOnboarding.js +1 -1
  39. package/lib/module/hooks/useOnboarding.js.map +1 -1
  40. package/lib/module/index.js +8 -1
  41. package/lib/module/index.js.map +1 -1
  42. package/lib/module/utils/color.js +299 -0
  43. package/lib/module/utils/color.js.map +1 -0
  44. package/lib/module/utils/persistence.js +42 -0
  45. package/lib/module/utils/persistence.js.map +1 -0
  46. package/lib/typescript/src/components/CustomPages.d.ts +6 -2
  47. package/lib/typescript/src/components/CustomPages.d.ts.map +1 -1
  48. package/lib/typescript/src/components/OnboardingPages.d.ts +6 -2
  49. package/lib/typescript/src/components/OnboardingPages.d.ts.map +1 -1
  50. package/lib/typescript/src/components/Page.d.ts +2 -0
  51. package/lib/typescript/src/components/Page.d.ts.map +1 -1
  52. package/lib/typescript/src/components/Pagination.d.ts +9 -0
  53. package/lib/typescript/src/components/Pagination.d.ts.map +1 -1
  54. package/lib/typescript/src/components/Swiper.d.ts.map +1 -1
  55. package/lib/typescript/src/components/button.d.ts.map +1 -1
  56. package/lib/typescript/src/context/OnboardingContext.d.ts +9 -0
  57. package/lib/typescript/src/context/OnboardingContext.d.ts.map +1 -1
  58. package/lib/typescript/src/hooks/useOnboarding.d.ts +3 -0
  59. package/lib/typescript/src/hooks/useOnboarding.d.ts.map +1 -1
  60. package/lib/typescript/src/index.d.ts +4 -0
  61. package/lib/typescript/src/index.d.ts.map +1 -1
  62. package/lib/typescript/src/types/index.d.ts +13 -0
  63. package/lib/typescript/src/types/index.d.ts.map +1 -1
  64. package/lib/typescript/src/utils/color.d.ts +18 -0
  65. package/lib/typescript/src/utils/color.d.ts.map +1 -0
  66. package/lib/typescript/src/utils/persistence.d.ts +31 -0
  67. package/lib/typescript/src/utils/persistence.d.ts.map +1 -0
  68. package/package.json +12 -6
  69. package/src/components/CustomPages.tsx +62 -69
  70. package/src/components/OnboardingPages.tsx +86 -89
  71. package/src/components/Page.tsx +8 -2
  72. package/src/components/Pagination.tsx +117 -29
  73. package/src/components/Swiper.tsx +65 -87
  74. package/src/components/button.tsx +6 -1
  75. package/src/context/OnboardingContext.tsx +145 -26
  76. package/src/hooks/useOnboarding.tsx +1 -3
  77. package/src/index.tsx +16 -1
  78. package/src/types/index.ts +13 -0
  79. package/src/utils/color.ts +284 -0
  80. package/src/utils/persistence.ts +58 -0
@@ -6,13 +6,19 @@ export type OnboardingProps = {
6
6
  nextLabel?: string | React.ReactNode;
7
7
  skipLabel?: string | React.ReactNode;
8
8
  doneLabel?: string | React.ReactNode;
9
+ previousLabel?: string | React.ReactNode;
9
10
  showSkip?: boolean;
10
11
  showNext?: boolean;
11
12
  showDone?: boolean;
13
+ showPrevious?: boolean;
12
14
  onDone?: () => void;
13
15
  onSkip?: () => void;
16
+ onPageChange?: (index: number) => void;
14
17
  showPagination?: boolean;
15
18
  scrollEnabled?: boolean;
19
+ autoPlay?: boolean;
20
+ autoPlayInterval?: number;
21
+ loop?: boolean;
16
22
  customFooter?: (props: { nextPage: () => void }) => React.ReactNode;
17
23
  paginationContainerStyle?: StyleProp<ViewStyle>;
18
24
  buttonRightContainerStyle?: StyleProp<ViewStyle>;
@@ -20,9 +26,11 @@ export type OnboardingProps = {
20
26
  dotsContainerStyle?: StyleProp<ViewStyle>;
21
27
  doneLabelStyle?: StyleProp<TextStyle>;
22
28
  skipLabelStyle?: StyleProp<TextStyle>;
29
+ previousLabelStyle?: StyleProp<TextStyle>;
23
30
  skipButtonContainerStyle?: StyleProp<ViewStyle>;
24
31
  nextButtonContainerStyle?: StyleProp<ViewStyle>;
25
32
  doneButtonContainerStyle?: StyleProp<ViewStyle>;
33
+ previousButtonContainerStyle?: StyleProp<ViewStyle>;
26
34
  skipButtonPosition?: 'top-left' | 'top-right';
27
35
  nextLabelStyle?: StyleProp<TextStyle>;
28
36
  containerStyle?: StyleProp<ViewStyle>;
@@ -31,8 +39,13 @@ export type OnboardingProps = {
31
39
  titleStyle?: StyleProp<TextStyle>;
32
40
  subtitleStyle?: StyleProp<TextStyle>;
33
41
  paginationPosition?: 'top' | 'bottom';
42
+ paginationStyle?: 'dots' | 'progress';
43
+ progressBarStyle?: StyleProp<ViewStyle>;
44
+ progressBarFillStyle?: StyleProp<ViewStyle>;
45
+ dotsAreTappable?: boolean;
34
46
  scrollAnimationDuration?: number;
35
47
  useNativeDriver?: boolean;
48
+ rtl?: boolean;
36
49
  width?: number;
37
50
  color?: string;
38
51
  pages?: Page[];
@@ -0,0 +1,284 @@
1
+ /**
2
+ * Minimal color helpers — a tiny, dependency-free replacement for the subset of
3
+ * tinycolor2 this library used: perceived brightness, HSL-based lighten/darken,
4
+ * and producing an `rgba()` string with a custom alpha.
5
+ *
6
+ * Accepts hex (`#rgb`, `#rgba`, `#rrggbb`, `#rrggbbaa`), `rgb()`/`rgba()`, and
7
+ * CSS named colors. Invalid input resolves to black, matching tinycolor's
8
+ * behavior of treating unparseable colors as having zero brightness.
9
+ */
10
+
11
+ type RGBA = { r: number; g: number; b: number; a: number };
12
+
13
+ // CSS extended color keywords (same set tinycolor recognizes).
14
+ const NAMED_COLORS: Record<string, string> = {
15
+ aliceblue: '#f0f8ff',
16
+ antiquewhite: '#faebd7',
17
+ aqua: '#00ffff',
18
+ aquamarine: '#7fffd4',
19
+ azure: '#f0ffff',
20
+ beige: '#f5f5dc',
21
+ bisque: '#ffe4c4',
22
+ black: '#000000',
23
+ blanchedalmond: '#ffebcd',
24
+ blue: '#0000ff',
25
+ blueviolet: '#8a2be2',
26
+ brown: '#a52a2a',
27
+ burlywood: '#deb887',
28
+ cadetblue: '#5f9ea0',
29
+ chartreuse: '#7fff00',
30
+ chocolate: '#d2691e',
31
+ coral: '#ff7f50',
32
+ cornflowerblue: '#6495ed',
33
+ cornsilk: '#fff8dc',
34
+ crimson: '#dc143c',
35
+ cyan: '#00ffff',
36
+ darkblue: '#00008b',
37
+ darkcyan: '#008b8b',
38
+ darkgoldenrod: '#b8860b',
39
+ darkgray: '#a9a9a9',
40
+ darkgreen: '#006400',
41
+ darkgrey: '#a9a9a9',
42
+ darkkhaki: '#bdb76b',
43
+ darkmagenta: '#8b008b',
44
+ darkolivegreen: '#556b2f',
45
+ darkorange: '#ff8c00',
46
+ darkorchid: '#9932cc',
47
+ darkred: '#8b0000',
48
+ darksalmon: '#e9967a',
49
+ darkseagreen: '#8fbc8f',
50
+ darkslateblue: '#483d8b',
51
+ darkslategray: '#2f4f4f',
52
+ darkslategrey: '#2f4f4f',
53
+ darkturquoise: '#00ced1',
54
+ darkviolet: '#9400d3',
55
+ deeppink: '#ff1493',
56
+ deepskyblue: '#00bfff',
57
+ dimgray: '#696969',
58
+ dimgrey: '#696969',
59
+ dodgerblue: '#1e90ff',
60
+ firebrick: '#b22222',
61
+ floralwhite: '#fffaf0',
62
+ forestgreen: '#228b22',
63
+ fuchsia: '#ff00ff',
64
+ gainsboro: '#dcdcdc',
65
+ ghostwhite: '#f8f8ff',
66
+ gold: '#ffd700',
67
+ goldenrod: '#daa520',
68
+ gray: '#808080',
69
+ green: '#008000',
70
+ greenyellow: '#adff2f',
71
+ grey: '#808080',
72
+ honeydew: '#f0fff0',
73
+ hotpink: '#ff69b4',
74
+ indianred: '#cd5c5c',
75
+ indigo: '#4b0082',
76
+ ivory: '#fffff0',
77
+ khaki: '#f0e68c',
78
+ lavender: '#e6e6fa',
79
+ lavenderblush: '#fff0f5',
80
+ lawngreen: '#7cfc00',
81
+ lemonchiffon: '#fffacd',
82
+ lightblue: '#add8e6',
83
+ lightcoral: '#f08080',
84
+ lightcyan: '#e0ffff',
85
+ lightgoldenrodyellow: '#fafad2',
86
+ lightgray: '#d3d3d3',
87
+ lightgreen: '#90ee90',
88
+ lightgrey: '#d3d3d3',
89
+ lightpink: '#ffb6c1',
90
+ lightsalmon: '#ffa07a',
91
+ lightseagreen: '#20b2aa',
92
+ lightskyblue: '#87cefa',
93
+ lightslategray: '#778899',
94
+ lightslategrey: '#778899',
95
+ lightsteelblue: '#b0c4de',
96
+ lightyellow: '#ffffe0',
97
+ lime: '#00ff00',
98
+ limegreen: '#32cd32',
99
+ linen: '#faf0e6',
100
+ magenta: '#ff00ff',
101
+ maroon: '#800000',
102
+ mediumaquamarine: '#66cdaa',
103
+ mediumblue: '#0000cd',
104
+ mediumorchid: '#ba55d3',
105
+ mediumpurple: '#9370db',
106
+ mediumseagreen: '#3cb371',
107
+ mediumslateblue: '#7b68ee',
108
+ mediumspringgreen: '#00fa9a',
109
+ mediumturquoise: '#48d1cc',
110
+ mediumvioletred: '#c71585',
111
+ midnightblue: '#191970',
112
+ mintcream: '#f5fffa',
113
+ mistyrose: '#ffe4e1',
114
+ moccasin: '#ffe4b5',
115
+ navajowhite: '#ffdead',
116
+ navy: '#000080',
117
+ oldlace: '#fdf5e6',
118
+ olive: '#808000',
119
+ olivedrab: '#6b8e23',
120
+ orange: '#ffa500',
121
+ orangered: '#ff4500',
122
+ orchid: '#da70d6',
123
+ palegoldenrod: '#eee8aa',
124
+ palegreen: '#98fb98',
125
+ paleturquoise: '#afeeee',
126
+ palevioletred: '#db7093',
127
+ papayawhip: '#ffefd5',
128
+ peachpuff: '#ffdab9',
129
+ peru: '#cd853f',
130
+ pink: '#ffc0cb',
131
+ plum: '#dda0dd',
132
+ powderblue: '#b0e0e6',
133
+ purple: '#800080',
134
+ rebeccapurple: '#663399',
135
+ red: '#ff0000',
136
+ rosybrown: '#bc8f8f',
137
+ royalblue: '#4169e1',
138
+ saddlebrown: '#8b4513',
139
+ salmon: '#fa8072',
140
+ sandybrown: '#f4a460',
141
+ seagreen: '#2e8b57',
142
+ seashell: '#fff5ee',
143
+ sienna: '#a0522d',
144
+ silver: '#c0c0c0',
145
+ skyblue: '#87ceeb',
146
+ slateblue: '#6a5acd',
147
+ slategray: '#708090',
148
+ slategrey: '#708090',
149
+ snow: '#fffafa',
150
+ springgreen: '#00ff7f',
151
+ steelblue: '#4682b4',
152
+ tan: '#d2b48c',
153
+ teal: '#008080',
154
+ thistle: '#d8bfd8',
155
+ tomato: '#ff6347',
156
+ turquoise: '#40e0d0',
157
+ violet: '#ee82ee',
158
+ wheat: '#f5deb3',
159
+ white: '#ffffff',
160
+ whitesmoke: '#f5f5f5',
161
+ yellow: '#ffff00',
162
+ yellowgreen: '#9acd32',
163
+ };
164
+
165
+ const clamp = (value: number, min: number, max: number) =>
166
+ Math.min(max, Math.max(min, value));
167
+
168
+ function parse(input: string): RGBA {
169
+ let color = (input || '').trim().toLowerCase();
170
+ const named = NAMED_COLORS[color];
171
+ if (named) color = named;
172
+
173
+ if (color[0] === '#') {
174
+ let hex = color.slice(1);
175
+ if (hex.length === 3 || hex.length === 4) {
176
+ hex = hex
177
+ .split('')
178
+ .map((c) => c + c)
179
+ .join('');
180
+ }
181
+ const r = parseInt(hex.slice(0, 2), 16);
182
+ const g = parseInt(hex.slice(2, 4), 16);
183
+ const b = parseInt(hex.slice(4, 6), 16);
184
+ const a = hex.length === 8 ? parseInt(hex.slice(6, 8), 16) / 255 : 1;
185
+ if (![r, g, b].some(Number.isNaN)) return { r, g, b, a };
186
+ }
187
+
188
+ const rgb = color.match(
189
+ /^rgba?\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)\s*(?:,\s*([\d.]+)\s*)?\)$/
190
+ );
191
+ if (rgb) {
192
+ return {
193
+ r: Number(rgb[1]),
194
+ g: Number(rgb[2]),
195
+ b: Number(rgb[3]),
196
+ a: rgb[4] !== undefined ? Number(rgb[4]) : 1,
197
+ };
198
+ }
199
+
200
+ return { r: 0, g: 0, b: 0, a: 1 };
201
+ }
202
+
203
+ function rgbToHsl({ r, g, b }: RGBA) {
204
+ const rn = r / 255;
205
+ const gn = g / 255;
206
+ const bn = b / 255;
207
+ const max = Math.max(rn, gn, bn);
208
+ const min = Math.min(rn, gn, bn);
209
+ const l = (max + min) / 2;
210
+ let h = 0;
211
+ let s = 0;
212
+ if (max !== min) {
213
+ const d = max - min;
214
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
215
+ switch (max) {
216
+ case rn:
217
+ h = (gn - bn) / d + (gn < bn ? 6 : 0);
218
+ break;
219
+ case gn:
220
+ h = (bn - rn) / d + 2;
221
+ break;
222
+ default:
223
+ h = (rn - gn) / d + 4;
224
+ }
225
+ h /= 6;
226
+ }
227
+ return { h, s, l };
228
+ }
229
+
230
+ function hslToRgb(h: number, s: number, l: number) {
231
+ if (s === 0) {
232
+ const v = l * 255;
233
+ return { r: v, g: v, b: v };
234
+ }
235
+ const hue2rgb = (p: number, q: number, t: number) => {
236
+ let tt = t;
237
+ if (tt < 0) tt += 1;
238
+ if (tt > 1) tt -= 1;
239
+ if (tt < 1 / 6) return p + (q - p) * 6 * tt;
240
+ if (tt < 1 / 2) return q;
241
+ if (tt < 2 / 3) return p + (q - p) * (2 / 3 - tt) * 6;
242
+ return p;
243
+ };
244
+ const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
245
+ const p = 2 * l - q;
246
+ return {
247
+ r: hue2rgb(p, q, h + 1 / 3) * 255,
248
+ g: hue2rgb(p, q, h) * 255,
249
+ b: hue2rgb(p, q, h - 1 / 3) * 255,
250
+ };
251
+ }
252
+
253
+ const toHex = (n: number) =>
254
+ Math.round(clamp(n, 0, 255))
255
+ .toString(16)
256
+ .padStart(2, '0');
257
+
258
+ /** Perceived brightness on a 0–255 scale (W3C formula, as tinycolor uses). */
259
+ export function getBrightness(input: string): number {
260
+ const { r, g, b } = parse(input);
261
+ return (r * 299 + g * 587 + b * 114) / 1000;
262
+ }
263
+
264
+ function adjustLightness(input: string, delta: number): string {
265
+ const hsl = rgbToHsl(parse(input));
266
+ const { r, g, b } = hslToRgb(hsl.h, hsl.s, clamp(hsl.l + delta, 0, 1));
267
+ return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
268
+ }
269
+
270
+ /** Lighten by `amount` percent (HSL lightness), returning a hex string. */
271
+ export function lighten(input: string, amount = 10): string {
272
+ return adjustLightness(input, amount / 100);
273
+ }
274
+
275
+ /** Darken by `amount` percent (HSL lightness), returning a hex string. */
276
+ export function darken(input: string, amount = 10): string {
277
+ return adjustLightness(input, -amount / 100);
278
+ }
279
+
280
+ /** Return an `rgba()` string for `input` with the given alpha. */
281
+ export function setAlpha(input: string, alpha: number): string {
282
+ const { r, g, b } = parse(input);
283
+ return `rgba(${Math.round(r)}, ${Math.round(g)}, ${Math.round(b)}, ${alpha})`;
284
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Minimal AsyncStorage-compatible interface. Any storage that implements these
3
+ * three methods works (e.g. @react-native-async-storage/async-storage,
4
+ * expo-secure-store wrappers, or an in-memory mock in tests). Keeping the
5
+ * dependency injected means this library does not have to ship a storage peer
6
+ * dependency of its own.
7
+ */
8
+ export type OnboardingStorageAdapter = {
9
+ getItem: (key: string) => Promise<string | null>;
10
+ setItem: (key: string, value: string) => Promise<void>;
11
+ removeItem: (key: string) => Promise<void>;
12
+ };
13
+
14
+ const DEFAULT_KEY = '@react-native-app-onboard/completed';
15
+ const COMPLETED_VALUE = 'true';
16
+
17
+ /**
18
+ * Returns whether the user has previously completed onboarding stored under
19
+ * `key`. Defaults to a namespaced key so callers usually only pass the storage.
20
+ */
21
+ export async function hasCompletedOnboarding(
22
+ storage: OnboardingStorageAdapter,
23
+ key: string = DEFAULT_KEY
24
+ ): Promise<boolean> {
25
+ const value = await storage.getItem(key);
26
+ return value === COMPLETED_VALUE;
27
+ }
28
+
29
+ /** Marks onboarding as completed so it can be skipped on subsequent launches. */
30
+ export async function markOnboardingComplete(
31
+ storage: OnboardingStorageAdapter,
32
+ key: string = DEFAULT_KEY
33
+ ): Promise<void> {
34
+ await storage.setItem(key, COMPLETED_VALUE);
35
+ }
36
+
37
+ /** Clears the stored completion flag (useful for "replay onboarding" actions). */
38
+ export async function resetOnboarding(
39
+ storage: OnboardingStorageAdapter,
40
+ key: string = DEFAULT_KEY
41
+ ): Promise<void> {
42
+ await storage.removeItem(key);
43
+ }
44
+
45
+ /**
46
+ * Convenience factory that binds a storage adapter (and optional key) once and
47
+ * returns ready-to-call helpers, so app code doesn't repeat the storage arg.
48
+ */
49
+ export function createOnboardingStorage(
50
+ storage: OnboardingStorageAdapter,
51
+ key: string = DEFAULT_KEY
52
+ ) {
53
+ return {
54
+ hasCompleted: () => hasCompletedOnboarding(storage, key),
55
+ markComplete: () => markOnboardingComplete(storage, key),
56
+ reset: () => resetOnboarding(storage, key),
57
+ };
58
+ }