cpk-ui 0.7.0 → 0.8.0-beta.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/README.md +14 -14
- package/components/uis/Calendar/Calendar.d.ts +6 -0
- package/components/uis/Calendar/Calendar.d.ts.map +1 -0
- package/components/uis/Calendar/Calendar.js +482 -0
- package/components/uis/Calendar/CalendarDay.d.ts +21 -0
- package/components/uis/Calendar/CalendarDay.d.ts.map +1 -0
- package/components/uis/Calendar/CalendarDay.js +172 -0
- package/components/uis/Calendar/CalendarHeader.d.ts +22 -0
- package/components/uis/Calendar/CalendarHeader.d.ts.map +1 -0
- package/components/uis/Calendar/CalendarHeader.js +40 -0
- package/components/uis/Calendar/CalendarPage.d.ts +46 -0
- package/components/uis/Calendar/CalendarPage.d.ts.map +1 -0
- package/components/uis/Calendar/CalendarPage.js +34 -0
- package/components/uis/Calendar/CalendarPager.d.ts +11 -0
- package/components/uis/Calendar/CalendarPager.d.ts.map +1 -0
- package/components/uis/Calendar/CalendarPager.js +115 -0
- package/components/uis/Calendar/CalendarPager.web.d.ts +11 -0
- package/components/uis/Calendar/CalendarPager.web.d.ts.map +1 -0
- package/components/uis/Calendar/CalendarPager.web.js +72 -0
- package/components/uis/Calendar/CalendarWeekRow.d.ts +20 -0
- package/components/uis/Calendar/CalendarWeekRow.d.ts.map +1 -0
- package/components/uis/Calendar/CalendarWeekRow.js +64 -0
- package/components/uis/Calendar/CalendarWeekdayRow.d.ts +24 -0
- package/components/uis/Calendar/CalendarWeekdayRow.d.ts.map +1 -0
- package/components/uis/Calendar/CalendarWeekdayRow.js +45 -0
- package/components/uis/Calendar/intl.d.ts +18 -0
- package/components/uis/Calendar/intl.d.ts.map +1 -0
- package/components/uis/Calendar/intl.js +146 -0
- package/components/uis/Calendar/palette.d.ts +10 -0
- package/components/uis/Calendar/palette.d.ts.map +1 -0
- package/components/uis/Calendar/palette.js +93 -0
- package/components/uis/Calendar/types.d.ts +286 -0
- package/components/uis/Calendar/types.d.ts.map +1 -0
- package/components/uis/Calendar/types.js +1 -0
- package/components/uis/Calendar/useCalendarState.d.ts +66 -0
- package/components/uis/Calendar/useCalendarState.d.ts.map +1 -0
- package/components/uis/Calendar/useCalendarState.js +211 -0
- package/components/uis/Calendar/utils.d.ts +114 -0
- package/components/uis/Calendar/utils.d.ts.map +1 -0
- package/components/uis/Calendar/utils.js +429 -0
- package/components/uis/ParallaxHeader/ParallaxHeader.d.ts +44 -0
- package/components/uis/ParallaxHeader/ParallaxHeader.d.ts.map +1 -0
- package/components/uis/ParallaxHeader/ParallaxHeader.js +142 -0
- package/index.d.ts +2 -0
- package/index.d.ts.map +1 -1
- package/index.js +2 -0
- package/package.json +2 -1
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
const MS_PER_DAY = 86_400_000;
|
|
2
|
+
export const clamp = (value, min, max) => value < min ? min : value > max ? max : value;
|
|
3
|
+
/**
|
|
4
|
+
* Every calendar `Date` in this component is anchored at LOCAL NOON.
|
|
5
|
+
* Local midnight does not exist in zones whose DST transition happens at 00:00
|
|
6
|
+
* (America/Santiago, America/Havana, …) and noon is more than 11 hours away from
|
|
7
|
+
* every real world transition, so no shift can move a date to another calendar day.
|
|
8
|
+
*/
|
|
9
|
+
export const localNoon = (year, month0, day) => new Date(year, month0, day, 12, 0, 0, 0);
|
|
10
|
+
const pad2 = (n) => (n < 10 ? `0${n}` : `${n}`);
|
|
11
|
+
export const toDayKey = (date) => `${date.getFullYear()}-${pad2(date.getMonth() + 1)}-${pad2(date.getDate())}`;
|
|
12
|
+
export const toMonthKey = (date) => `${date.getFullYear()}-${pad2(date.getMonth() + 1)}`;
|
|
13
|
+
export const isMonthKey = (key) => key.length === 7;
|
|
14
|
+
/** Field wise construction. Never `new Date('2026-08-24')`, which ECMA-262 parses as UTC. */
|
|
15
|
+
export const fromDayKey = (key) => localNoon(+key.slice(0, 4), +key.slice(5, 7) - 1, +key.slice(8, 10));
|
|
16
|
+
export const fromMonthKey = (key) => localNoon(+key.slice(0, 4), +key.slice(5, 7) - 1, 1);
|
|
17
|
+
/** Field arithmetic, so month, year and DST boundaries normalize correctly. */
|
|
18
|
+
export const addDays = (date, amount) => localNoon(date.getFullYear(), date.getMonth(), date.getDate() + amount);
|
|
19
|
+
export const daysInMonth = (date) => new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();
|
|
20
|
+
export const startOfMonth = (date) => localNoon(date.getFullYear(), date.getMonth(), 1);
|
|
21
|
+
export const addMonths = (date, amount) => {
|
|
22
|
+
const target = localNoon(date.getFullYear(), date.getMonth() + amount, 1);
|
|
23
|
+
return localNoon(target.getFullYear(), target.getMonth(), Math.min(date.getDate(), daysInMonth(target)));
|
|
24
|
+
};
|
|
25
|
+
export const startOfWeek = (date, weekStart) => addDays(date, -((((date.getDay() - weekStart) % 7) + 7) % 7));
|
|
26
|
+
/** The year is compared. Comparing only month and date highlights the same day of any year. */
|
|
27
|
+
export const isSameDay = (a, b) => a.getFullYear() === b.getFullYear() &&
|
|
28
|
+
a.getMonth() === b.getMonth() &&
|
|
29
|
+
a.getDate() === b.getDate();
|
|
30
|
+
/**
|
|
31
|
+
* Safe because both dates are local noon: a DST shift of one hour is 0.042 days,
|
|
32
|
+
* which `Math.round` can never turn into a different day count.
|
|
33
|
+
*/
|
|
34
|
+
export const diffInCalendarDays = (a, b) => Math.round((a.getTime() - b.getTime()) / MS_PER_DAY);
|
|
35
|
+
export const weeksInMonth = (date, weekStart) => {
|
|
36
|
+
const first = startOfMonth(date);
|
|
37
|
+
const offset = diffInCalendarDays(first, startOfWeek(first, weekStart));
|
|
38
|
+
return Math.ceil((offset + daysInMonth(date)) / 7);
|
|
39
|
+
};
|
|
40
|
+
const getWeekYear = (date, weekStart, firstWeekContainsDate) => {
|
|
41
|
+
const year = date.getFullYear();
|
|
42
|
+
const startOfNextYear = startOfWeek(localNoon(year + 1, 0, firstWeekContainsDate), weekStart);
|
|
43
|
+
const startOfThisYear = startOfWeek(localNoon(year, 0, firstWeekContainsDate), weekStart);
|
|
44
|
+
const time = date.getTime();
|
|
45
|
+
if (time >= startOfNextYear.getTime()) {
|
|
46
|
+
return year + 1;
|
|
47
|
+
}
|
|
48
|
+
if (time >= startOfThisYear.getTime()) {
|
|
49
|
+
return year;
|
|
50
|
+
}
|
|
51
|
+
return year - 1;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* ISO 8601 numbering when `weekStart` is Monday, otherwise the
|
|
55
|
+
* "the week containing Jan 1 is week 1" convention that US/KR/JP calendars show.
|
|
56
|
+
*/
|
|
57
|
+
export const getWeekNumber = (date, weekStart) => {
|
|
58
|
+
const firstWeekContainsDate = weekStart === 1 ? 4 : 1;
|
|
59
|
+
const weekYear = getWeekYear(date, weekStart, firstWeekContainsDate);
|
|
60
|
+
const startOfWeekYear = startOfWeek(localNoon(weekYear, 0, firstWeekContainsDate), weekStart);
|
|
61
|
+
return (Math.round(diffInCalendarDays(startOfWeek(date, weekStart), startOfWeekYear) / 7) + 1);
|
|
62
|
+
};
|
|
63
|
+
/** CLDR `weekData/firstDay`, reduced to the regions that do not start on Monday. */
|
|
64
|
+
const SUNDAY_FIRST = new Set([
|
|
65
|
+
'AR',
|
|
66
|
+
'BO',
|
|
67
|
+
'BR',
|
|
68
|
+
'CA',
|
|
69
|
+
'CL',
|
|
70
|
+
'CN',
|
|
71
|
+
'CO',
|
|
72
|
+
'DO',
|
|
73
|
+
'EC',
|
|
74
|
+
'GT',
|
|
75
|
+
'HK',
|
|
76
|
+
'HN',
|
|
77
|
+
'ID',
|
|
78
|
+
'IL',
|
|
79
|
+
'IN',
|
|
80
|
+
'JM',
|
|
81
|
+
'JP',
|
|
82
|
+
'KE',
|
|
83
|
+
'KR',
|
|
84
|
+
'MO',
|
|
85
|
+
'MX',
|
|
86
|
+
'NI',
|
|
87
|
+
'PA',
|
|
88
|
+
'PE',
|
|
89
|
+
'PH',
|
|
90
|
+
'PR',
|
|
91
|
+
'PY',
|
|
92
|
+
'SG',
|
|
93
|
+
'TH',
|
|
94
|
+
'TW',
|
|
95
|
+
'US',
|
|
96
|
+
'UY',
|
|
97
|
+
'VE',
|
|
98
|
+
'ZA',
|
|
99
|
+
'ZW',
|
|
100
|
+
]);
|
|
101
|
+
const SATURDAY_FIRST = new Set([
|
|
102
|
+
'AE',
|
|
103
|
+
'AF',
|
|
104
|
+
'BH',
|
|
105
|
+
'DJ',
|
|
106
|
+
'DZ',
|
|
107
|
+
'EG',
|
|
108
|
+
'IQ',
|
|
109
|
+
'IR',
|
|
110
|
+
'JO',
|
|
111
|
+
'KW',
|
|
112
|
+
'LY',
|
|
113
|
+
'OM',
|
|
114
|
+
'QA',
|
|
115
|
+
'SA',
|
|
116
|
+
'SD',
|
|
117
|
+
'SY',
|
|
118
|
+
'YE',
|
|
119
|
+
]);
|
|
120
|
+
/** Fallback for runtimes without `Intl.Locale`, covering the languages cpk-ui ships stories for. */
|
|
121
|
+
const LANGUAGE_REGION = {
|
|
122
|
+
ar: 'SA',
|
|
123
|
+
de: 'DE',
|
|
124
|
+
en: 'US',
|
|
125
|
+
es: 'ES',
|
|
126
|
+
fr: 'FR',
|
|
127
|
+
he: 'IL',
|
|
128
|
+
id: 'ID',
|
|
129
|
+
ja: 'JP',
|
|
130
|
+
ko: 'KR',
|
|
131
|
+
pt: 'BR',
|
|
132
|
+
th: 'TH',
|
|
133
|
+
vi: 'VN',
|
|
134
|
+
zh: 'CN',
|
|
135
|
+
};
|
|
136
|
+
export const regionOf = (locale) => {
|
|
137
|
+
const normalized = locale.replace(/_/g, '-');
|
|
138
|
+
const parts = normalized.split('-');
|
|
139
|
+
for (let i = 1; i < parts.length; i++) {
|
|
140
|
+
if (/^[A-Za-z]{2}$/.test(parts[i])) {
|
|
141
|
+
return parts[i].toUpperCase();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const intl = Intl;
|
|
145
|
+
if (typeof intl.Locale === 'function') {
|
|
146
|
+
try {
|
|
147
|
+
const region = new intl.Locale(normalized).maximize().region;
|
|
148
|
+
if (region) {
|
|
149
|
+
return region.toUpperCase();
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
// Exotic or malformed tag, fall through to the language table.
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return LANGUAGE_REGION[parts[0].toLowerCase()] ?? '';
|
|
157
|
+
};
|
|
158
|
+
export const resolveWeekStart = (locale) => {
|
|
159
|
+
const region = regionOf(locale);
|
|
160
|
+
if (SATURDAY_FIRST.has(region)) {
|
|
161
|
+
return 6;
|
|
162
|
+
}
|
|
163
|
+
if (SUNDAY_FIRST.has(region)) {
|
|
164
|
+
return 0;
|
|
165
|
+
}
|
|
166
|
+
return 1;
|
|
167
|
+
};
|
|
168
|
+
/** Accepts a `Date` or an already canonical key and always answers with a day key. */
|
|
169
|
+
export const toDateKeyInput = (value) => (typeof value === 'string' ? value : toDayKey(value));
|
|
170
|
+
/**
|
|
171
|
+
* Resolves a page anchor to the first rendered day of that page.
|
|
172
|
+
* Month pages anchor on the first of the month, week pages on the week start.
|
|
173
|
+
*/
|
|
174
|
+
export const pageFirstDate = (pageKey, mode, weekStart) => {
|
|
175
|
+
if (mode === 'week') {
|
|
176
|
+
const date = isMonthKey(pageKey)
|
|
177
|
+
? fromMonthKey(pageKey)
|
|
178
|
+
: fromDayKey(pageKey);
|
|
179
|
+
return startOfWeek(date, weekStart);
|
|
180
|
+
}
|
|
181
|
+
return isMonthKey(pageKey)
|
|
182
|
+
? fromMonthKey(pageKey)
|
|
183
|
+
: startOfMonth(fromDayKey(pageKey));
|
|
184
|
+
};
|
|
185
|
+
/** The last day that logically belongs to a page, ignoring the out of month padding. */
|
|
186
|
+
export const pageLastDate = (pageKey, mode, weekStart, monthsToShow) => {
|
|
187
|
+
const first = pageFirstDate(pageKey, mode, weekStart);
|
|
188
|
+
return mode === 'week'
|
|
189
|
+
? addDays(first, 6)
|
|
190
|
+
: addDays(addMonths(first, monthsToShow), -1);
|
|
191
|
+
};
|
|
192
|
+
export const toPageKey = (date, mode, weekStart) => mode === 'week' ? toDayKey(startOfWeek(date, weekStart)) : toMonthKey(date);
|
|
193
|
+
export const normalizePageKey = (value, mode, weekStart, monthsToShow) => {
|
|
194
|
+
const date = typeof value === 'string'
|
|
195
|
+
? isMonthKey(value)
|
|
196
|
+
? fromMonthKey(value)
|
|
197
|
+
: fromDayKey(value)
|
|
198
|
+
: value;
|
|
199
|
+
if (mode === 'week') {
|
|
200
|
+
return toDayKey(startOfWeek(date, weekStart));
|
|
201
|
+
}
|
|
202
|
+
if (monthsToShow > 1) {
|
|
203
|
+
const anchor = localNoon(date.getFullYear(), Math.floor(date.getMonth() / monthsToShow) * monthsToShow, 1);
|
|
204
|
+
return toMonthKey(anchor);
|
|
205
|
+
}
|
|
206
|
+
return toMonthKey(date);
|
|
207
|
+
};
|
|
208
|
+
/** Steps a page anchor by `delta` pages: months in month mode, weeks in week mode. */
|
|
209
|
+
export const addPages = (pageKey, delta, mode, weekStart, monthsToShow) => {
|
|
210
|
+
const first = pageFirstDate(pageKey, mode, weekStart);
|
|
211
|
+
return mode === 'week'
|
|
212
|
+
? toDayKey(addDays(first, delta * 7))
|
|
213
|
+
: toMonthKey(addMonths(first, delta * monthsToShow));
|
|
214
|
+
};
|
|
215
|
+
export function buildMonthGrid(month, weekStart, fixedWeeks, showWeekNumbers) {
|
|
216
|
+
const gridStart = startOfWeek(startOfMonth(month), weekStart);
|
|
217
|
+
const rowCount = fixedWeeks ? 6 : weeksInMonth(month, weekStart);
|
|
218
|
+
const cellCount = rowCount * 7;
|
|
219
|
+
const targetMonth = month.getMonth();
|
|
220
|
+
const cells = new Array(cellCount);
|
|
221
|
+
for (let i = 0; i < cellCount; i++) {
|
|
222
|
+
const date = addDays(gridStart, i);
|
|
223
|
+
cells[i] = {
|
|
224
|
+
key: toDayKey(date),
|
|
225
|
+
date,
|
|
226
|
+
dayOfMonth: date.getDate(),
|
|
227
|
+
weekday: date.getDay(),
|
|
228
|
+
isOutside: date.getMonth() !== targetMonth,
|
|
229
|
+
weekIndex: (i / 7) | 0,
|
|
230
|
+
weekNumber: showWeekNumbers ? getWeekNumber(date, weekStart) : 0,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
return Object.freeze(cells);
|
|
234
|
+
}
|
|
235
|
+
export function buildWeekGrid(anchor, weekStart, showWeekNumbers) {
|
|
236
|
+
const gridStart = startOfWeek(anchor, weekStart);
|
|
237
|
+
const cells = new Array(7);
|
|
238
|
+
for (let i = 0; i < 7; i++) {
|
|
239
|
+
const date = addDays(gridStart, i);
|
|
240
|
+
cells[i] = {
|
|
241
|
+
key: toDayKey(date),
|
|
242
|
+
date,
|
|
243
|
+
dayOfMonth: date.getDate(),
|
|
244
|
+
weekday: date.getDay(),
|
|
245
|
+
isOutside: false,
|
|
246
|
+
weekIndex: 0,
|
|
247
|
+
weekNumber: showWeekNumbers ? getWeekNumber(date, weekStart) : 0,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
return Object.freeze(cells);
|
|
251
|
+
}
|
|
252
|
+
const GRID_CACHE_LIMIT = 24;
|
|
253
|
+
const gridCache = new Map();
|
|
254
|
+
/**
|
|
255
|
+
* Module level LRU. Re-visiting a page (swiping back and forth) is a `Map.get`,
|
|
256
|
+
* so `Intl.DateTimeFormat#format` runs at most once per (page, locale) pair.
|
|
257
|
+
*/
|
|
258
|
+
export function getCalendarGrid(request) {
|
|
259
|
+
const { pageKey, mode, weekStart, fixedWeeks, showWeekNumbers, locale, formatters, formattersId, } = request;
|
|
260
|
+
const cacheKey = `${pageKey}|${mode}|${weekStart}|${fixedWeeks ? 1 : 0}|${showWeekNumbers ? 1 : 0}|${locale}|${formattersId}`;
|
|
261
|
+
const cached = gridCache.get(cacheKey);
|
|
262
|
+
if (cached) {
|
|
263
|
+
gridCache.delete(cacheKey);
|
|
264
|
+
gridCache.set(cacheKey, cached);
|
|
265
|
+
return cached;
|
|
266
|
+
}
|
|
267
|
+
const first = pageFirstDate(pageKey, mode, weekStart);
|
|
268
|
+
const days = mode === 'week'
|
|
269
|
+
? buildWeekGrid(first, weekStart, showWeekNumbers)
|
|
270
|
+
: buildMonthGrid(first, weekStart, fixedWeeks, showWeekNumbers);
|
|
271
|
+
const dayLabels = new Array(days.length);
|
|
272
|
+
const a11yLabels = new Array(days.length);
|
|
273
|
+
for (let i = 0; i < days.length; i++) {
|
|
274
|
+
dayLabels[i] = formatters.dayNumber(days[i].date, locale);
|
|
275
|
+
a11yLabels[i] = formatters.dayAccessibilityLabel(days[i].date, locale);
|
|
276
|
+
}
|
|
277
|
+
const rowCount = days.length / 7;
|
|
278
|
+
const rows = new Array(rowCount);
|
|
279
|
+
for (let row = 0; row < rowCount; row++) {
|
|
280
|
+
const from = row * 7;
|
|
281
|
+
rows[row] = Object.freeze({
|
|
282
|
+
weekIndex: row,
|
|
283
|
+
weekNumber: days[from].weekNumber,
|
|
284
|
+
days: Object.freeze(days.slice(from, from + 7)),
|
|
285
|
+
dayLabels: Object.freeze(dayLabels.slice(from, from + 7)),
|
|
286
|
+
a11yLabels: Object.freeze(a11yLabels.slice(from, from + 7)),
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
const grid = Object.freeze({
|
|
290
|
+
days,
|
|
291
|
+
rows: Object.freeze(rows),
|
|
292
|
+
rowCount,
|
|
293
|
+
firstKey: days[0].key,
|
|
294
|
+
lastKey: days[days.length - 1].key,
|
|
295
|
+
});
|
|
296
|
+
gridCache.set(cacheKey, grid);
|
|
297
|
+
if (gridCache.size > GRID_CACHE_LIMIT) {
|
|
298
|
+
const oldest = gridCache.keys().next().value;
|
|
299
|
+
if (oldest !== undefined) {
|
|
300
|
+
gridCache.delete(oldest);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
return grid;
|
|
304
|
+
}
|
|
305
|
+
/** Test seam. Keeps the LRU from leaking state between test files. */
|
|
306
|
+
export const clearCalendarGridCache = () => {
|
|
307
|
+
gridCache.clear();
|
|
308
|
+
};
|
|
309
|
+
/**
|
|
310
|
+
* True when the row's 7 keys contain `key`.
|
|
311
|
+
* Keys are sorted and consecutive, so this is two string compares, never a scan.
|
|
312
|
+
*/
|
|
313
|
+
export const rowHasKey = (days, key) => key !== null &&
|
|
314
|
+
days.length > 0 &&
|
|
315
|
+
key >= days[0].key &&
|
|
316
|
+
key <= days[days.length - 1].key;
|
|
317
|
+
/** Identity first, then a shallow value compare so a rebuilt but equal marker still bails. */
|
|
318
|
+
export function isSameMarker(a, b) {
|
|
319
|
+
if (a === b) {
|
|
320
|
+
return true;
|
|
321
|
+
}
|
|
322
|
+
if (!a || !b) {
|
|
323
|
+
return false;
|
|
324
|
+
}
|
|
325
|
+
return (a.dots === b.dots &&
|
|
326
|
+
a.badgeText === b.badgeText &&
|
|
327
|
+
a.badgeColor === b.badgeColor &&
|
|
328
|
+
a.selectedColor === b.selectedColor &&
|
|
329
|
+
a.textColor === b.textColor &&
|
|
330
|
+
a.disabled === b.disabled &&
|
|
331
|
+
a.accessibilityHint === b.accessibilityHint);
|
|
332
|
+
}
|
|
333
|
+
const HEX_SHORT = /^#([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])?$/i;
|
|
334
|
+
const HEX_LONG = /^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})?$/i;
|
|
335
|
+
const RGB_FN = /^rgba?\(\s*([\d.]+)[\s,]+([\d.]+)[\s,]+([\d.]+)/i;
|
|
336
|
+
export function parseColor(color) {
|
|
337
|
+
const value = color.trim();
|
|
338
|
+
const short = HEX_SHORT.exec(value);
|
|
339
|
+
if (short) {
|
|
340
|
+
return {
|
|
341
|
+
r: parseInt(short[1] + short[1], 16),
|
|
342
|
+
g: parseInt(short[2] + short[2], 16),
|
|
343
|
+
b: parseInt(short[3] + short[3], 16),
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
const long = HEX_LONG.exec(value);
|
|
347
|
+
if (long) {
|
|
348
|
+
return {
|
|
349
|
+
r: parseInt(long[1], 16),
|
|
350
|
+
g: parseInt(long[2], 16),
|
|
351
|
+
b: parseInt(long[3], 16),
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
const fn = RGB_FN.exec(value);
|
|
355
|
+
if (fn) {
|
|
356
|
+
return { r: +fn[1], g: +fn[2], b: +fn[3] };
|
|
357
|
+
}
|
|
358
|
+
return null;
|
|
359
|
+
}
|
|
360
|
+
const srgbToLinear = (channel) => channel <= 0.04045 ? channel / 12.92 : ((channel + 0.055) / 1.055) ** 2.4;
|
|
361
|
+
/** WCAG relative luminance, or `null` when the colour cannot be parsed. */
|
|
362
|
+
export function relativeLuminance(color) {
|
|
363
|
+
const rgb = parseColor(color);
|
|
364
|
+
if (!rgb) {
|
|
365
|
+
return null;
|
|
366
|
+
}
|
|
367
|
+
return (0.2126 * srgbToLinear(rgb.r / 255) +
|
|
368
|
+
0.7152 * srgbToLinear(rgb.g / 255) +
|
|
369
|
+
0.0722 * srgbToLinear(rgb.b / 255));
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Picks the readable label colour for a background.
|
|
373
|
+
* The 0.45 threshold makes a saturated yellow resolve to the dark label.
|
|
374
|
+
*/
|
|
375
|
+
export function readableTextOn(background, light, dark) {
|
|
376
|
+
const luminance = relativeLuminance(background);
|
|
377
|
+
if (luminance === null) {
|
|
378
|
+
return light;
|
|
379
|
+
}
|
|
380
|
+
return luminance > 0.45 ? dark : light;
|
|
381
|
+
}
|
|
382
|
+
const SIZE_PRESETS = {
|
|
383
|
+
compact: { cellSize: 36, rowGap: 4, weekdayRowHeight: 24, headerHeight: 44 },
|
|
384
|
+
regular: { cellSize: 44, rowGap: 6, weekdayRowHeight: 28, headerHeight: 48 },
|
|
385
|
+
expanded: { cellSize: 56, rowGap: 8, weekdayRowHeight: 32, headerHeight: 56 },
|
|
386
|
+
};
|
|
387
|
+
/**
|
|
388
|
+
* There is no measure pass in the vertical axis: every value below is a pure
|
|
389
|
+
* function of `size` and the device font scale, so the grid height is identical
|
|
390
|
+
* for every month and a swipe causes zero layout thrash.
|
|
391
|
+
*/
|
|
392
|
+
export function resolveMetrics(size, fontScale, maxFontSizeMultiplier) {
|
|
393
|
+
const base = typeof size === 'number'
|
|
394
|
+
? {
|
|
395
|
+
cellSize: size,
|
|
396
|
+
rowGap: clamp(Math.round(size * 0.14), 4, 10),
|
|
397
|
+
weekdayRowHeight: Math.round(size * 0.62),
|
|
398
|
+
headerHeight: Math.round(size * 1.1),
|
|
399
|
+
}
|
|
400
|
+
: (SIZE_PRESETS[size] ?? SIZE_PRESETS.regular);
|
|
401
|
+
// Guards a non finite font scale from an exotic runtime, and keeps a device
|
|
402
|
+
// reporting a scale below 1 from shrinking the touch targets.
|
|
403
|
+
const requested = Number.isFinite(fontScale) ? fontScale : 1;
|
|
404
|
+
const cap = Number.isFinite(maxFontSizeMultiplier)
|
|
405
|
+
? maxFontSizeMultiplier
|
|
406
|
+
: 1;
|
|
407
|
+
const scale = clamp(Math.min(requested, cap), 1, 4);
|
|
408
|
+
const cellSize = clamp(Math.round(base.cellSize * scale), 32, 96);
|
|
409
|
+
const rowHeight = cellSize + base.rowGap;
|
|
410
|
+
const numberSize = clamp(Math.round(cellSize * 0.68), 22, 72);
|
|
411
|
+
const dotSize = clamp(Math.round(cellSize * 0.11), 4, 8);
|
|
412
|
+
const dotRowHeight = dotSize + 1;
|
|
413
|
+
return Object.freeze({
|
|
414
|
+
cellSize,
|
|
415
|
+
rowGap: base.rowGap,
|
|
416
|
+
rowHeight,
|
|
417
|
+
weekdayRowHeight: Math.round(base.weekdayRowHeight * scale),
|
|
418
|
+
headerHeight: Math.round(base.headerHeight * scale),
|
|
419
|
+
numberSize,
|
|
420
|
+
dayFontSize: clamp(Math.round(cellSize * 0.34), 11, 24),
|
|
421
|
+
weekdayFontSize: clamp(Math.round(cellSize * 0.26), 10, 18),
|
|
422
|
+
headerFontSize: clamp(Math.round(cellSize * 0.4), 14, 26),
|
|
423
|
+
badgeFontSize: clamp(Math.round(cellSize * 0.19), 8, 11),
|
|
424
|
+
dotSize,
|
|
425
|
+
dotRowHeight,
|
|
426
|
+
pillOffset: Math.max(1, Math.round((rowHeight - numberSize - dotRowHeight) / 2)),
|
|
427
|
+
weekNumberWidth: clamp(Math.round(cellSize * 0.62), 20, 48),
|
|
428
|
+
});
|
|
429
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { type ReactElement, type ReactNode } from 'react';
|
|
2
|
+
import { type StyleProp, type ViewStyle } from 'react-native';
|
|
3
|
+
import { type ScrollHandlerProcessed, type SharedValue } from 'react-native-reanimated';
|
|
4
|
+
export type ParallaxHeaderStyles = {
|
|
5
|
+
container?: StyleProp<ViewStyle>;
|
|
6
|
+
surface?: StyleProp<ViewStyle>;
|
|
7
|
+
expandedContent?: StyleProp<ViewStyle>;
|
|
8
|
+
collapsedContent?: StyleProp<ViewStyle>;
|
|
9
|
+
navigation?: StyleProp<ViewStyle>;
|
|
10
|
+
};
|
|
11
|
+
export type ParallaxHeaderProps = {
|
|
12
|
+
/** Scroll offset from an Animated ScrollView, FlatList, or FlashList. */
|
|
13
|
+
scrollOffset: SharedValue<number>;
|
|
14
|
+
/** Full header height at scroll position zero. */
|
|
15
|
+
expandedHeight: number;
|
|
16
|
+
/** Sticky header height after the collapse distance is consumed. */
|
|
17
|
+
collapsedHeight: number;
|
|
18
|
+
/** Defaults to the active cpk-ui basic surface token. */
|
|
19
|
+
backgroundColor?: string;
|
|
20
|
+
/** Presentation shown below the persistent navigation while expanded. */
|
|
21
|
+
expandedContent?: ReactNode;
|
|
22
|
+
/** Presentation cross-faded into the compact header. */
|
|
23
|
+
collapsedContent?: ReactNode;
|
|
24
|
+
/** Interactive controls that stay mounted and fixed at the top. */
|
|
25
|
+
children?: ReactNode;
|
|
26
|
+
styles?: ParallaxHeaderStyles;
|
|
27
|
+
style?: StyleProp<ViewStyle>;
|
|
28
|
+
testID?: string;
|
|
29
|
+
};
|
|
30
|
+
export type ParallaxHeaderController = {
|
|
31
|
+
scrollOffset: SharedValue<number>;
|
|
32
|
+
onScroll: ScrollHandlerProcessed;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Creates one UI-thread scroll source shared by the header and any animated
|
|
36
|
+
* ScrollView-compatible list. The handler never schedules a React render.
|
|
37
|
+
*/
|
|
38
|
+
export declare function useParallaxHeader(): ParallaxHeaderController;
|
|
39
|
+
/**
|
|
40
|
+
* A list-agnostic collapsing header. Its layout height is fixed; scroll only
|
|
41
|
+
* drives compositor-friendly transforms and opacity on the UI thread.
|
|
42
|
+
*/
|
|
43
|
+
export declare function ParallaxHeader({ scrollOffset, expandedHeight, collapsedHeight, backgroundColor, expandedContent, collapsedContent, children, styles, style, testID, }: ParallaxHeaderProps): ReactElement;
|
|
44
|
+
//# sourceMappingURL=ParallaxHeader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ParallaxHeader.d.ts","sourceRoot":"","sources":["../../../../src/components/uis/ParallaxHeader/ParallaxHeader.tsx"],"names":[],"mappings":"AAAA,OAAc,EAGZ,KAAK,YAAY,EACjB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,EAIL,KAAK,SAAS,EACd,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AACtB,OAAiB,EAOf,KAAK,sBAAsB,EAC3B,KAAK,WAAW,EACjB,MAAM,yBAAyB,CAAC;AAIjC,MAAM,MAAM,oBAAoB,GAAG;IACjC,SAAS,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACjC,OAAO,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC/B,eAAe,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACvC,gBAAgB,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACxC,UAAU,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,yEAAyE;IACzE,YAAY,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAClC,kDAAkD;IAClD,cAAc,EAAE,MAAM,CAAC;IACvB,oEAAoE;IACpE,eAAe,EAAE,MAAM,CAAC;IACxB,yDAAyD;IACzD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,yEAAyE;IACzE,eAAe,CAAC,EAAE,SAAS,CAAC;IAC5B,wDAAwD;IACxD,gBAAgB,CAAC,EAAE,SAAS,CAAC;IAC7B,mEAAmE;IACnE,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,MAAM,CAAC,EAAE,oBAAoB,CAAC;IAC9B,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,YAAY,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAClC,QAAQ,EAAE,sBAAsB,CAAC;CAClC,CAAC;AAEF;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,wBAAwB,CAO5D;AA4BD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,EAC7B,YAAY,EACZ,cAAc,EACd,eAAe,EACf,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,QAAQ,EACR,MAAM,EACN,KAAK,EACL,MAA0B,GAC3B,EAAE,mBAAmB,GAAG,YAAY,CA8GpC"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState, } from 'react';
|
|
3
|
+
import { AccessibilityInfo, StyleSheet, View, } from 'react-native';
|
|
4
|
+
import Animated, { Extrapolation, interpolate, useAnimatedScrollHandler, useAnimatedStyle, useDerivedValue, useSharedValue, } from 'react-native-reanimated';
|
|
5
|
+
import { useTheme } from '../../../providers/ThemeProvider';
|
|
6
|
+
/**
|
|
7
|
+
* Creates one UI-thread scroll source shared by the header and any animated
|
|
8
|
+
* ScrollView-compatible list. The handler never schedules a React render.
|
|
9
|
+
*/
|
|
10
|
+
export function useParallaxHeader() {
|
|
11
|
+
const scrollOffset = useSharedValue(0);
|
|
12
|
+
const onScroll = useAnimatedScrollHandler((event) => {
|
|
13
|
+
scrollOffset.set(Math.max(event.contentOffset.y, 0));
|
|
14
|
+
});
|
|
15
|
+
return { onScroll, scrollOffset };
|
|
16
|
+
}
|
|
17
|
+
function useReducedMotionPreference() {
|
|
18
|
+
const [reduced, setReduced] = useState(false);
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
let mounted = true;
|
|
21
|
+
const update = (next) => {
|
|
22
|
+
if (mounted)
|
|
23
|
+
setReduced(next);
|
|
24
|
+
};
|
|
25
|
+
AccessibilityInfo.isReduceMotionEnabled()
|
|
26
|
+
.then(update)
|
|
27
|
+
.catch(() => undefined);
|
|
28
|
+
const subscription = AccessibilityInfo.addEventListener('reduceMotionChanged', update);
|
|
29
|
+
return () => {
|
|
30
|
+
mounted = false;
|
|
31
|
+
subscription.remove();
|
|
32
|
+
};
|
|
33
|
+
}, []);
|
|
34
|
+
return reduced;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* A list-agnostic collapsing header. Its layout height is fixed; scroll only
|
|
38
|
+
* drives compositor-friendly transforms and opacity on the UI thread.
|
|
39
|
+
*/
|
|
40
|
+
export function ParallaxHeader({ scrollOffset, expandedHeight, collapsedHeight, backgroundColor, expandedContent, collapsedContent, children, styles, style, testID = 'parallax-header', }) {
|
|
41
|
+
const { theme } = useTheme();
|
|
42
|
+
const reduceMotion = useReducedMotionPreference();
|
|
43
|
+
const compactHeight = Math.max(collapsedHeight, 0);
|
|
44
|
+
const fullHeight = Math.max(expandedHeight, compactHeight);
|
|
45
|
+
const collapseDistance = fullHeight - compactHeight;
|
|
46
|
+
const progress = useDerivedValue(() => {
|
|
47
|
+
if (collapseDistance === 0)
|
|
48
|
+
return 1;
|
|
49
|
+
return Math.min(Math.max(scrollOffset.get() / collapseDistance, 0), 1);
|
|
50
|
+
});
|
|
51
|
+
const surfaceStyle = useAnimatedStyle(() => ({
|
|
52
|
+
transform: [
|
|
53
|
+
{
|
|
54
|
+
translateY: -Math.min(Math.max(scrollOffset.get(), 0), collapseDistance),
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
}));
|
|
58
|
+
const expandedStyle = useAnimatedStyle(() => {
|
|
59
|
+
const value = progress.get();
|
|
60
|
+
return {
|
|
61
|
+
opacity: reduceMotion
|
|
62
|
+
? value < 1
|
|
63
|
+
? 1
|
|
64
|
+
: 0
|
|
65
|
+
: interpolate(value, [0, 0.72, 1], [1, 0, 0], Extrapolation.CLAMP),
|
|
66
|
+
transform: [
|
|
67
|
+
{
|
|
68
|
+
translateY: reduceMotion
|
|
69
|
+
? 0
|
|
70
|
+
: interpolate(value, [0, 1], [0, -12], Extrapolation.CLAMP),
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
};
|
|
74
|
+
});
|
|
75
|
+
const collapsedStyle = useAnimatedStyle(() => {
|
|
76
|
+
const value = progress.get();
|
|
77
|
+
return {
|
|
78
|
+
opacity: reduceMotion
|
|
79
|
+
? value >= 1
|
|
80
|
+
? 1
|
|
81
|
+
: 0
|
|
82
|
+
: interpolate(value, [0, 0.68, 1], [0, 0, 1], Extrapolation.CLAMP),
|
|
83
|
+
};
|
|
84
|
+
});
|
|
85
|
+
return (_jsxs(View, { pointerEvents: "box-none", style: [
|
|
86
|
+
componentStyles.container,
|
|
87
|
+
{ height: fullHeight },
|
|
88
|
+
styles?.container,
|
|
89
|
+
style,
|
|
90
|
+
], testID: testID, children: [_jsx(Animated.View, { pointerEvents: "none", style: [
|
|
91
|
+
componentStyles.surface,
|
|
92
|
+
{
|
|
93
|
+
backgroundColor: backgroundColor ?? theme.bg.basic,
|
|
94
|
+
height: fullHeight,
|
|
95
|
+
},
|
|
96
|
+
styles?.surface,
|
|
97
|
+
surfaceStyle,
|
|
98
|
+
], testID: `${testID}-surface`, children: _jsx(Animated.View, { style: [
|
|
99
|
+
componentStyles.expandedContent,
|
|
100
|
+
{ paddingTop: compactHeight },
|
|
101
|
+
styles?.expandedContent,
|
|
102
|
+
expandedStyle,
|
|
103
|
+
], testID: `${testID}-expanded`, children: expandedContent }) }), _jsx(Animated.View, { pointerEvents: "none", style: [
|
|
104
|
+
componentStyles.collapsedContent,
|
|
105
|
+
{ height: compactHeight },
|
|
106
|
+
styles?.collapsedContent,
|
|
107
|
+
collapsedStyle,
|
|
108
|
+
], testID: `${testID}-collapsed`, children: collapsedContent }), _jsx(View, { pointerEvents: "box-none", style: [
|
|
109
|
+
componentStyles.navigation,
|
|
110
|
+
{ height: compactHeight },
|
|
111
|
+
styles?.navigation,
|
|
112
|
+
], testID: `${testID}-navigation`, children: children })] }));
|
|
113
|
+
}
|
|
114
|
+
const componentStyles = StyleSheet.create({
|
|
115
|
+
collapsedContent: {
|
|
116
|
+
left: 0,
|
|
117
|
+
position: 'absolute',
|
|
118
|
+
right: 0,
|
|
119
|
+
top: 0,
|
|
120
|
+
},
|
|
121
|
+
container: {
|
|
122
|
+
left: 0,
|
|
123
|
+
overflow: 'hidden',
|
|
124
|
+
position: 'absolute',
|
|
125
|
+
right: 0,
|
|
126
|
+
top: 0,
|
|
127
|
+
zIndex: 1,
|
|
128
|
+
},
|
|
129
|
+
expandedContent: { flex: 1 },
|
|
130
|
+
navigation: {
|
|
131
|
+
left: 0,
|
|
132
|
+
position: 'absolute',
|
|
133
|
+
right: 0,
|
|
134
|
+
top: 0,
|
|
135
|
+
},
|
|
136
|
+
surface: {
|
|
137
|
+
left: 0,
|
|
138
|
+
position: 'absolute',
|
|
139
|
+
right: 0,
|
|
140
|
+
top: 0,
|
|
141
|
+
},
|
|
142
|
+
});
|
package/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export * from './components/common/ErrorBoundary/ErrorBoundary';
|
|
|
4
4
|
export * from './providers';
|
|
5
5
|
export * from './components/uis/Accordion/Accordion';
|
|
6
6
|
export * from './components/uis/Button/Button';
|
|
7
|
+
export * from './components/uis/Calendar/Calendar';
|
|
7
8
|
export * from './components/uis/Card/Card';
|
|
8
9
|
export * from './components/uis/Checkbox/Checkbox';
|
|
9
10
|
export * from './components/uis/CustomPressable/CustomPressable';
|
|
@@ -14,6 +15,7 @@ export * from './components/uis/Icon/Icon';
|
|
|
14
15
|
export * from './components/uis/IconButton/IconButton';
|
|
15
16
|
export * from './components/uis/LoadingIndicator/LoadingIndicator';
|
|
16
17
|
export * from './components/uis/PinchZoom/PinchZoom';
|
|
18
|
+
export * from './components/uis/ParallaxHeader/ParallaxHeader';
|
|
17
19
|
export * from './components/uis/Rating/Rating';
|
|
18
20
|
export * from './components/uis/RadioGroup/RadioGroup';
|
|
19
21
|
export * from './components/uis/SegmentedControl/SegmentedControl';
|
package/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AACA,cAAc,6CAA6C,CAAC;AAC5D,cAAc,uCAAuC,CAAC;AAGtD,cAAc,iDAAiD,CAAC;AAGhE,cAAc,aAAa,CAAC;AAG5B,cAAc,sCAAsC,CAAC;AACrD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,oCAAoC,CAAC;AACnD,cAAc,kDAAkD,CAAC;AACjE,cAAc,oCAAoC,CAAC;AACnD,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,wCAAwC,CAAC;AACvD,cAAc,oDAAoD,CAAC;AACnE,cAAc,sCAAsC,CAAC;AACrD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,wCAAwC,CAAC;AACvD,cAAc,oDAAoD,CAAC;AACnE,cAAc,0DAA0D,CAAC;AACzE,cAAc,4CAA4C,CAAC;AAC3D,cAAc,wCAAwC,CAAC;AAGvD,cAAc,SAAS,CAAC;AAGxB,cAAc,SAAS,CAAC;AAGxB,cAAc,SAAS,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AACA,cAAc,6CAA6C,CAAC;AAC5D,cAAc,uCAAuC,CAAC;AAGtD,cAAc,iDAAiD,CAAC;AAGhE,cAAc,aAAa,CAAC;AAG5B,cAAc,sCAAsC,CAAC;AACrD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,oCAAoC,CAAC;AACnD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,oCAAoC,CAAC;AACnD,cAAc,kDAAkD,CAAC;AACjE,cAAc,oCAAoC,CAAC;AACnD,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,wCAAwC,CAAC;AACvD,cAAc,oDAAoD,CAAC;AACnE,cAAc,sCAAsC,CAAC;AACrD,cAAc,gDAAgD,CAAC;AAC/D,cAAc,gCAAgC,CAAC;AAC/C,cAAc,wCAAwC,CAAC;AACvD,cAAc,oDAAoD,CAAC;AACnE,cAAc,0DAA0D,CAAC;AACzE,cAAc,4CAA4C,CAAC;AAC3D,cAAc,wCAAwC,CAAC;AAGvD,cAAc,SAAS,CAAC;AAGxB,cAAc,SAAS,CAAC;AAGxB,cAAc,SAAS,CAAC"}
|
package/index.js
CHANGED
|
@@ -8,6 +8,7 @@ export * from './providers';
|
|
|
8
8
|
// UIs
|
|
9
9
|
export * from './components/uis/Accordion/Accordion';
|
|
10
10
|
export * from './components/uis/Button/Button';
|
|
11
|
+
export * from './components/uis/Calendar/Calendar';
|
|
11
12
|
export * from './components/uis/Card/Card';
|
|
12
13
|
export * from './components/uis/Checkbox/Checkbox';
|
|
13
14
|
export * from './components/uis/CustomPressable/CustomPressable';
|
|
@@ -18,6 +19,7 @@ export * from './components/uis/Icon/Icon';
|
|
|
18
19
|
export * from './components/uis/IconButton/IconButton';
|
|
19
20
|
export * from './components/uis/LoadingIndicator/LoadingIndicator';
|
|
20
21
|
export * from './components/uis/PinchZoom/PinchZoom';
|
|
22
|
+
export * from './components/uis/ParallaxHeader/ParallaxHeader';
|
|
21
23
|
export * from './components/uis/Rating/Rating';
|
|
22
24
|
export * from './components/uis/RadioGroup/RadioGroup';
|
|
23
25
|
export * from './components/uis/SegmentedControl/SegmentedControl';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cpk-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0-beta.0",
|
|
4
4
|
"main": "index",
|
|
5
5
|
"react-native": "index",
|
|
6
6
|
"module": "index",
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
"react": ">=16.9",
|
|
39
39
|
"react-native": ">=0.58",
|
|
40
40
|
"react-native-gesture-handler": "*",
|
|
41
|
+
"react-native-reanimated": "*",
|
|
41
42
|
"@expo/vector-icons": "*",
|
|
42
43
|
"expo-haptics": "*"
|
|
43
44
|
},
|