@super-calendar/native 2.3.2 → 2.4.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 +21 -0
- package/dist/{DefaultMonthEvent-BW6qy50X.d.ts → DefaultMonthEvent-BSvuJUFk.d.ts} +174 -173
- package/dist/{DefaultMonthEvent-BbCMc60z.d.mts → DefaultMonthEvent-zDj9dHEv.d.mts} +174 -173
- package/dist/{MonthList-CFXm7BK_.js → MonthList-Aczb2RSY.js} +219 -108
- package/dist/{MonthList-BidXJMfm.mjs → MonthList-zPLklHAY.mjs} +203 -110
- package/dist/index.d.mts +221 -263
- package/dist/index.d.ts +221 -263
- package/dist/index.js +549 -209
- package/dist/index.mjs +542 -214
- package/dist/picker.d.mts +1 -1
- package/dist/picker.d.ts +1 -1
- package/dist/picker.js +1 -1
- package/dist/picker.mjs +1 -1
- package/package.json +2 -2
- package/src/components/Agenda.tsx +52 -11
- package/src/components/AllDayLane.tsx +22 -8
- package/src/components/Calendar.tsx +84 -5
- package/src/components/DefaultEvent.tsx +4 -0
- package/src/components/MonthList.tsx +52 -10
- package/src/components/MonthPager.tsx +45 -6
- package/src/components/MonthView.tsx +133 -74
- package/src/components/ResourceTimeline.tsx +276 -35
- package/src/components/TimeGrid.tsx +282 -162
- package/src/index.tsx +12 -4
- package/src/types.ts +16 -1
- package/src/utils/slots.ts +83 -0
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import type { ComponentType, ReactElement } from "react";
|
|
2
2
|
import { useCallback, useEffect, useMemo, useRef } from "react";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
type AccessibilityActionEvent,
|
|
5
|
+
Pressable,
|
|
6
|
+
ScrollView,
|
|
7
|
+
StyleSheet,
|
|
8
|
+
Text,
|
|
9
|
+
View,
|
|
10
|
+
} from "react-native";
|
|
4
11
|
import { Gesture, GestureDetector } from "react-native-gesture-handler";
|
|
5
12
|
import Animated, { runOnJS, useAnimatedStyle, useSharedValue } from "react-native-reanimated";
|
|
6
13
|
import {
|
|
@@ -29,16 +36,28 @@ export interface Resource {
|
|
|
29
36
|
/** Props passed to a custom resource-timeline event renderer. */
|
|
30
37
|
export interface ResourceEventArgs<T = unknown> {
|
|
31
38
|
event: CalendarEvent<T>;
|
|
32
|
-
/**
|
|
39
|
+
/**
|
|
40
|
+
* Pixel width of the event bar. In the vertical orientation the columns flex
|
|
41
|
+
* to the container, so this is 0 there; size against `height` instead.
|
|
42
|
+
*/
|
|
33
43
|
width: number;
|
|
44
|
+
/** Pixel height of the event bar; set in the vertical orientation. */
|
|
45
|
+
height?: number;
|
|
34
46
|
onPress: () => void;
|
|
35
47
|
}
|
|
36
48
|
|
|
37
49
|
/** Props for {@link ResourceTimeline}. */
|
|
38
50
|
export interface ResourceTimelineProps<T = unknown> {
|
|
39
|
-
/** The day to lay out along the
|
|
51
|
+
/** The day to lay out along the time axis. */
|
|
40
52
|
date: Date;
|
|
41
|
-
/**
|
|
53
|
+
/**
|
|
54
|
+
* Lay the day out along the horizontal axis with resources as rows (the
|
|
55
|
+
* default), or down the vertical axis with resources as columns, like the
|
|
56
|
+
* time grid. Vertical reads better on narrow screens: the columns share the
|
|
57
|
+
* width instead of the axis scrolling sideways.
|
|
58
|
+
*/
|
|
59
|
+
orientation?: "horizontal" | "vertical";
|
|
60
|
+
/** The resource lanes: rows when horizontal, columns when vertical. */
|
|
42
61
|
resources: Resource[];
|
|
43
62
|
/** Events; each is placed in the row named by `resourceId(event)`. */
|
|
44
63
|
events: CalendarEvent<T>[];
|
|
@@ -48,11 +67,13 @@ export interface ResourceTimelineProps<T = unknown> {
|
|
|
48
67
|
startHour?: number;
|
|
49
68
|
/** Last hour shown, exclusive (default 24). */
|
|
50
69
|
endHour?: number;
|
|
51
|
-
/** Pixels per hour along the axis (default 80). */
|
|
70
|
+
/** Pixels per hour along the horizontal axis (default 80). Horizontal only. */
|
|
52
71
|
hourWidth?: number;
|
|
53
|
-
/**
|
|
72
|
+
/** Pixels per hour down the vertical axis (default 48). Vertical only. */
|
|
73
|
+
hourHeight?: number;
|
|
74
|
+
/** Height of each resource row in px (default 56). Horizontal only. */
|
|
54
75
|
rowHeight?: number;
|
|
55
|
-
/** Width of the left resource-label column in px (default 140). */
|
|
76
|
+
/** Width of the left resource-label column in px (default 140). Horizontal only. */
|
|
56
77
|
labelWidth?: number;
|
|
57
78
|
/** 12-hour AM/PM axis labels (default false). */
|
|
58
79
|
ampm?: boolean;
|
|
@@ -72,8 +93,13 @@ export interface ResourceTimelineProps<T = unknown> {
|
|
|
72
93
|
|
|
73
94
|
const clamp = (v: number, lo: number, hi: number) => Math.min(hi, Math.max(lo, v));
|
|
74
95
|
|
|
75
|
-
|
|
96
|
+
// Hour-gutter width in the vertical orientation, matching the time grid's axis.
|
|
97
|
+
const GUTTER_WIDTH = 56;
|
|
98
|
+
|
|
99
|
+
function DefaultBar<T>({ event, width, height }: ResourceEventArgs<T>): ReactElement {
|
|
76
100
|
const theme = useCalendarTheme();
|
|
101
|
+
// Show the time line only when the bar has room for it along its long axis.
|
|
102
|
+
const showTime = height != null ? height > 34 : width > 56;
|
|
77
103
|
const time = eventTimeLabel({
|
|
78
104
|
mode: "day",
|
|
79
105
|
isAllDay: false,
|
|
@@ -97,7 +123,7 @@ function DefaultBar<T>({ event, width }: ResourceEventArgs<T>): ReactElement {
|
|
|
97
123
|
>
|
|
98
124
|
{event.title}
|
|
99
125
|
</Text>
|
|
100
|
-
{time &&
|
|
126
|
+
{time && showTime ? (
|
|
101
127
|
<Text
|
|
102
128
|
numberOfLines={1}
|
|
103
129
|
style={[styles.barTime, { color: theme.colors.eventText }]}
|
|
@@ -112,10 +138,19 @@ function DefaultBar<T>({ event, width }: ResourceEventArgs<T>): ReactElement {
|
|
|
112
138
|
|
|
113
139
|
type ResourceBarProps<T> = {
|
|
114
140
|
pe: PositionedEvent<T>;
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
141
|
+
/** Time flows down instead of across; gestures and resize follow. */
|
|
142
|
+
vertical: boolean;
|
|
143
|
+
/** Pixels per hour along the time axis. */
|
|
144
|
+
hourSize: number;
|
|
145
|
+
/** Cross-axis lane offset: px when horizontal, a percent string when vertical. */
|
|
146
|
+
left: number | `${number}%`;
|
|
147
|
+
top: number;
|
|
148
|
+
/** Along-axis size when horizontal (px); lane width (percent) when vertical. */
|
|
149
|
+
width: number | `${number}%`;
|
|
150
|
+
/** Lane height when horizontal; along-axis size when vertical (px). */
|
|
151
|
+
height: number;
|
|
152
|
+
/** What the custom renderer is told about the bar's box. */
|
|
153
|
+
rendererSize: { width: number; height?: number };
|
|
119
154
|
snapMinutes: number;
|
|
120
155
|
Renderer: ComponentType<ResourceEventArgs<T>>;
|
|
121
156
|
onPress: () => void;
|
|
@@ -123,15 +158,19 @@ type ResourceBarProps<T> = {
|
|
|
123
158
|
theme: ReturnType<typeof useCalendarTheme>;
|
|
124
159
|
};
|
|
125
160
|
|
|
126
|
-
// A bar with drag-to-move (long-press) and
|
|
127
|
-
//
|
|
128
|
-
//
|
|
161
|
+
// A bar with drag-to-move (long-press) and edge resize along the time axis
|
|
162
|
+
// (right edge when horizontal, bottom edge when vertical). The pure snap/commit
|
|
163
|
+
// math is shared with the time grid (`snapDeltaMinutes`, `resolveDraggedBounds`);
|
|
164
|
+
// this only wires the gestures.
|
|
129
165
|
function ResourceBar<T>({
|
|
130
166
|
pe,
|
|
167
|
+
vertical,
|
|
168
|
+
hourSize,
|
|
131
169
|
left,
|
|
170
|
+
top,
|
|
132
171
|
width,
|
|
133
|
-
|
|
134
|
-
|
|
172
|
+
height,
|
|
173
|
+
rendererSize,
|
|
135
174
|
snapMinutes,
|
|
136
175
|
Renderer,
|
|
137
176
|
onPress,
|
|
@@ -174,9 +213,50 @@ function ResourceBar<T>({
|
|
|
174
213
|
[snapMinutes, snapBack],
|
|
175
214
|
);
|
|
176
215
|
|
|
216
|
+
// Dragging is gesture-only, so mirror move AND resize as screen-reader actions on
|
|
217
|
+
// the same `commit` path. They all live on the bar's accessible Pressable (the
|
|
218
|
+
// resize grip is a non-focusable visual/gesture affordance, so an `adjustable`
|
|
219
|
+
// role there would never receive focus on a real device).
|
|
220
|
+
const unit = (n: number) => `${n} minute${n === 1 ? "" : "s"}`;
|
|
221
|
+
const barActions = draggable
|
|
222
|
+
? [
|
|
223
|
+
{ name: "move-later", label: `Move ${unit(snapMinutes)} later` },
|
|
224
|
+
{ name: "move-earlier", label: `Move ${unit(snapMinutes)} earlier` },
|
|
225
|
+
{ name: "extend", label: `Extend by ${unit(snapMinutes)}` },
|
|
226
|
+
{ name: "shrink", label: `Shorten by ${unit(snapMinutes)}` },
|
|
227
|
+
]
|
|
228
|
+
: undefined;
|
|
229
|
+
const onBarAction = draggable
|
|
230
|
+
? (e: AccessibilityActionEvent) => {
|
|
231
|
+
switch (e.nativeEvent.actionName) {
|
|
232
|
+
case "move-later":
|
|
233
|
+
commit(snapMinutes, snapMinutes);
|
|
234
|
+
break;
|
|
235
|
+
case "move-earlier":
|
|
236
|
+
commit(-snapMinutes, -snapMinutes);
|
|
237
|
+
break;
|
|
238
|
+
case "extend":
|
|
239
|
+
commit(0, snapMinutes);
|
|
240
|
+
break;
|
|
241
|
+
case "shrink":
|
|
242
|
+
commit(0, -snapMinutes);
|
|
243
|
+
break;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
: undefined;
|
|
247
|
+
|
|
177
248
|
const barStyle = useAnimatedStyle(
|
|
178
|
-
() =>
|
|
179
|
-
|
|
249
|
+
() =>
|
|
250
|
+
vertical
|
|
251
|
+
? {
|
|
252
|
+
transform: [{ translateY: moveX.value }],
|
|
253
|
+
height: Math.max(height + resizeW.value, 2),
|
|
254
|
+
}
|
|
255
|
+
: {
|
|
256
|
+
transform: [{ translateX: moveX.value }],
|
|
257
|
+
width: Math.max((width as number) + resizeW.value, 2),
|
|
258
|
+
},
|
|
259
|
+
[vertical, width, height],
|
|
180
260
|
);
|
|
181
261
|
|
|
182
262
|
const moveGesture = useMemo(
|
|
@@ -185,18 +265,19 @@ function ResourceBar<T>({
|
|
|
185
265
|
.enabled(draggable)
|
|
186
266
|
.activateAfterLongPress(MOVE_ACTIVATE_MS)
|
|
187
267
|
.onUpdate((e) => {
|
|
188
|
-
moveX.value = e.translationX;
|
|
268
|
+
moveX.value = vertical ? e.translationY : e.translationX;
|
|
189
269
|
})
|
|
190
270
|
.onEnd((e) => {
|
|
191
|
-
const
|
|
271
|
+
const translation = vertical ? e.translationY : e.translationX;
|
|
272
|
+
const delta = snapDeltaMinutes(translation, hourSize, snapMinutes);
|
|
192
273
|
if (delta === 0) {
|
|
193
274
|
moveX.value = 0;
|
|
194
275
|
return;
|
|
195
276
|
}
|
|
196
|
-
moveX.value = (delta / MINUTES_PER_HOUR) *
|
|
277
|
+
moveX.value = (delta / MINUTES_PER_HOUR) * hourSize;
|
|
197
278
|
runOnJS(commit)(delta, delta);
|
|
198
279
|
}),
|
|
199
|
-
[draggable,
|
|
280
|
+
[draggable, vertical, hourSize, snapMinutes, moveX, commit],
|
|
200
281
|
);
|
|
201
282
|
|
|
202
283
|
const resizeGesture = useMemo(
|
|
@@ -204,24 +285,26 @@ function ResourceBar<T>({
|
|
|
204
285
|
Gesture.Pan()
|
|
205
286
|
.enabled(draggable)
|
|
206
287
|
.onUpdate((e) => {
|
|
207
|
-
resizeW.value = e.translationX;
|
|
288
|
+
resizeW.value = vertical ? e.translationY : e.translationX;
|
|
208
289
|
})
|
|
209
290
|
.onEnd((e) => {
|
|
210
|
-
const
|
|
291
|
+
const translation = vertical ? e.translationY : e.translationX;
|
|
292
|
+
const delta = snapDeltaMinutes(translation, hourSize, snapMinutes);
|
|
211
293
|
if (delta === 0) {
|
|
212
294
|
resizeW.value = 0;
|
|
213
295
|
return;
|
|
214
296
|
}
|
|
215
|
-
resizeW.value = (delta / MINUTES_PER_HOUR) *
|
|
297
|
+
resizeW.value = (delta / MINUTES_PER_HOUR) * hourSize;
|
|
216
298
|
runOnJS(commit)(0, delta);
|
|
217
299
|
}),
|
|
218
|
-
[draggable,
|
|
300
|
+
[draggable, vertical, hourSize, snapMinutes, resizeW, commit],
|
|
219
301
|
);
|
|
220
302
|
|
|
221
303
|
return (
|
|
222
304
|
<Animated.View
|
|
223
305
|
style={[
|
|
224
|
-
{ position: "absolute", left, top
|
|
306
|
+
{ position: "absolute", left, top, padding: 1 },
|
|
307
|
+
vertical ? { width } : { height },
|
|
225
308
|
barStyle,
|
|
226
309
|
]}
|
|
227
310
|
>
|
|
@@ -230,16 +313,29 @@ function ResourceBar<T>({
|
|
|
230
313
|
onPress={onPress}
|
|
231
314
|
accessibilityRole="button"
|
|
232
315
|
accessibilityLabel={pe.event.title}
|
|
316
|
+
accessibilityActions={barActions}
|
|
317
|
+
onAccessibilityAction={onBarAction}
|
|
233
318
|
style={styles.fill}
|
|
234
319
|
>
|
|
235
|
-
<Renderer
|
|
320
|
+
<Renderer
|
|
321
|
+
event={pe.event}
|
|
322
|
+
width={rendererSize.width}
|
|
323
|
+
height={rendererSize.height}
|
|
324
|
+
onPress={onPress}
|
|
325
|
+
/>
|
|
236
326
|
</Pressable>
|
|
237
327
|
</GestureDetector>
|
|
238
328
|
<GestureDetector gesture={resizeGesture}>
|
|
329
|
+
{/* Visual + gesture resize affordance only; screen readers use the bar's
|
|
330
|
+
extend/shorten actions above (a non-focusable View can't hold them). */}
|
|
239
331
|
<View
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
332
|
+
testID="resource-resize-grip"
|
|
333
|
+
style={[
|
|
334
|
+
vertical ? styles.resizeGripBottom : styles.resizeGrip,
|
|
335
|
+
{ backgroundColor: theme.colors.eventText },
|
|
336
|
+
]}
|
|
337
|
+
accessibilityElementsHidden
|
|
338
|
+
importantForAccessibility="no"
|
|
243
339
|
/>
|
|
244
340
|
</GestureDetector>
|
|
245
341
|
</Animated.View>
|
|
@@ -266,12 +362,14 @@ function ResourceBar<T>({
|
|
|
266
362
|
*/
|
|
267
363
|
export function ResourceTimeline<T = unknown>({
|
|
268
364
|
date,
|
|
365
|
+
orientation = "horizontal",
|
|
269
366
|
resources,
|
|
270
367
|
events,
|
|
271
368
|
resourceId = (event) => (event as { resourceId?: string }).resourceId,
|
|
272
369
|
startHour = 0,
|
|
273
370
|
endHour = 24,
|
|
274
371
|
hourWidth = 80,
|
|
372
|
+
hourHeight = 48,
|
|
275
373
|
rowHeight = 56,
|
|
276
374
|
labelWidth = 140,
|
|
277
375
|
ampm = false,
|
|
@@ -299,6 +397,123 @@ export function ResourceTimeline<T = unknown>({
|
|
|
299
397
|
return map;
|
|
300
398
|
}, [resources, events, resourceId, date]);
|
|
301
399
|
|
|
400
|
+
if (orientation === "vertical") {
|
|
401
|
+
// Time flows down like the time grid: hour gutter on the left and one
|
|
402
|
+
// flexed column per resource, so narrow screens share the width instead of
|
|
403
|
+
// scrolling sideways. The resource headers stay fixed above the scroll.
|
|
404
|
+
const trackHeight = (endHour - startHour) * hourHeight;
|
|
405
|
+
return (
|
|
406
|
+
<View style={styles.vroot}>
|
|
407
|
+
<View style={[styles.header, { borderBottomColor: theme.colors.gridLine }]}>
|
|
408
|
+
<View style={{ width: GUTTER_WIDTH }} />
|
|
409
|
+
{resources.map((resource) => (
|
|
410
|
+
<View key={resource.id} style={[styles.vheaderCell, theme.containers.resourceLabel]}>
|
|
411
|
+
<Text
|
|
412
|
+
numberOfLines={1}
|
|
413
|
+
style={[styles.vheaderText, { color: theme.colors.text }]}
|
|
414
|
+
allowFontScaling={false}
|
|
415
|
+
>
|
|
416
|
+
{resource.title ?? resource.id}
|
|
417
|
+
</Text>
|
|
418
|
+
</View>
|
|
419
|
+
))}
|
|
420
|
+
</View>
|
|
421
|
+
<ScrollView showsVerticalScrollIndicator>
|
|
422
|
+
<View style={[styles.vbody, { height: trackHeight }]}>
|
|
423
|
+
<View style={{ width: GUTTER_WIDTH }}>
|
|
424
|
+
{hours.map((h) => (
|
|
425
|
+
<Text
|
|
426
|
+
key={h}
|
|
427
|
+
allowFontScaling={false}
|
|
428
|
+
style={[
|
|
429
|
+
styles.vhourLabel,
|
|
430
|
+
{
|
|
431
|
+
top: Math.max(0, (h - startHour) * hourHeight - 6),
|
|
432
|
+
color: theme.colors.textMuted,
|
|
433
|
+
},
|
|
434
|
+
]}
|
|
435
|
+
>
|
|
436
|
+
{formatHour(h, { ampm })}
|
|
437
|
+
</Text>
|
|
438
|
+
))}
|
|
439
|
+
</View>
|
|
440
|
+
{resources.map((resource) => {
|
|
441
|
+
const positioned = byResource.get(resource.id) ?? [];
|
|
442
|
+
return (
|
|
443
|
+
<View
|
|
444
|
+
key={resource.id}
|
|
445
|
+
style={[
|
|
446
|
+
styles.vcolumn,
|
|
447
|
+
{ borderLeftColor: theme.colors.gridLine },
|
|
448
|
+
theme.containers.resourceRow,
|
|
449
|
+
]}
|
|
450
|
+
>
|
|
451
|
+
{hours.slice(1).map((h) => (
|
|
452
|
+
<View
|
|
453
|
+
key={h}
|
|
454
|
+
pointerEvents="none"
|
|
455
|
+
style={[
|
|
456
|
+
styles.vgridLine,
|
|
457
|
+
{
|
|
458
|
+
top: (h - startHour) * hourHeight,
|
|
459
|
+
backgroundColor: theme.colors.gridLine,
|
|
460
|
+
},
|
|
461
|
+
]}
|
|
462
|
+
/>
|
|
463
|
+
))}
|
|
464
|
+
{positioned.map((pe, idx) => {
|
|
465
|
+
const top =
|
|
466
|
+
clamp(pe.startHours - startHour, 0, endHour - startHour) * hourHeight;
|
|
467
|
+
const bottomPx =
|
|
468
|
+
clamp(pe.startHours + pe.durationHours - startHour, 0, endHour - startHour) *
|
|
469
|
+
hourHeight;
|
|
470
|
+
const height = Math.max(bottomPx - top, 2);
|
|
471
|
+
// Overlapping events share the column as side-by-side sub-lanes.
|
|
472
|
+
const lanePct = 100 / pe.columns;
|
|
473
|
+
const left = `${pe.column * lanePct}%` as const;
|
|
474
|
+
const width = `${lanePct}%` as const;
|
|
475
|
+
const onPress = () => onPressEvent?.(pe.event);
|
|
476
|
+
if (onDragEvent) {
|
|
477
|
+
return (
|
|
478
|
+
<ResourceBar
|
|
479
|
+
key={idx}
|
|
480
|
+
pe={pe}
|
|
481
|
+
vertical
|
|
482
|
+
hourSize={hourHeight}
|
|
483
|
+
left={left}
|
|
484
|
+
top={top}
|
|
485
|
+
width={width}
|
|
486
|
+
height={height}
|
|
487
|
+
rendererSize={{ width: 0, height }}
|
|
488
|
+
snapMinutes={dragStepMinutes}
|
|
489
|
+
Renderer={Renderer}
|
|
490
|
+
onPress={onPress}
|
|
491
|
+
onDragEvent={onDragEvent}
|
|
492
|
+
theme={theme}
|
|
493
|
+
/>
|
|
494
|
+
);
|
|
495
|
+
}
|
|
496
|
+
return (
|
|
497
|
+
<Pressable
|
|
498
|
+
key={idx}
|
|
499
|
+
onPress={onPress}
|
|
500
|
+
accessibilityRole="button"
|
|
501
|
+
accessibilityLabel={pe.event.title}
|
|
502
|
+
style={{ position: "absolute", left, width, top, height, padding: 1 }}
|
|
503
|
+
>
|
|
504
|
+
<Renderer event={pe.event} width={0} height={height} onPress={onPress} />
|
|
505
|
+
</Pressable>
|
|
506
|
+
);
|
|
507
|
+
})}
|
|
508
|
+
</View>
|
|
509
|
+
);
|
|
510
|
+
})}
|
|
511
|
+
</View>
|
|
512
|
+
</ScrollView>
|
|
513
|
+
</View>
|
|
514
|
+
);
|
|
515
|
+
}
|
|
516
|
+
|
|
302
517
|
return (
|
|
303
518
|
<ScrollView horizontal showsHorizontalScrollIndicator style={styles.root}>
|
|
304
519
|
<View style={{ width: labelWidth + trackWidth }}>
|
|
@@ -374,10 +589,13 @@ export function ResourceTimeline<T = unknown>({
|
|
|
374
589
|
<ResourceBar
|
|
375
590
|
key={idx}
|
|
376
591
|
pe={pe}
|
|
592
|
+
vertical={false}
|
|
593
|
+
hourSize={hourWidth}
|
|
377
594
|
left={left}
|
|
595
|
+
top={pe.column * laneHeight}
|
|
378
596
|
width={width}
|
|
379
|
-
|
|
380
|
-
|
|
597
|
+
height={laneHeight}
|
|
598
|
+
rendererSize={{ width }}
|
|
381
599
|
snapMinutes={dragStepMinutes}
|
|
382
600
|
Renderer={Renderer}
|
|
383
601
|
onPress={onPress}
|
|
@@ -438,4 +656,27 @@ const styles = StyleSheet.create({
|
|
|
438
656
|
borderRadius: 2,
|
|
439
657
|
opacity: 0.5,
|
|
440
658
|
},
|
|
659
|
+
// Its bottom-edge counterpart in the vertical orientation.
|
|
660
|
+
resizeGripBottom: {
|
|
661
|
+
position: "absolute",
|
|
662
|
+
bottom: 1,
|
|
663
|
+
left: "30%",
|
|
664
|
+
right: "30%",
|
|
665
|
+
height: 4,
|
|
666
|
+
borderRadius: 2,
|
|
667
|
+
opacity: 0.5,
|
|
668
|
+
},
|
|
669
|
+
vroot: { flex: 1 },
|
|
670
|
+
vheaderCell: {
|
|
671
|
+
flex: 1,
|
|
672
|
+
paddingVertical: 6,
|
|
673
|
+
paddingHorizontal: 4,
|
|
674
|
+
alignItems: "center",
|
|
675
|
+
borderLeftWidth: StyleSheet.hairlineWidth,
|
|
676
|
+
},
|
|
677
|
+
vheaderText: { fontSize: 13, fontWeight: "600" },
|
|
678
|
+
vbody: { flexDirection: "row" },
|
|
679
|
+
vcolumn: { flex: 1, borderLeftWidth: StyleSheet.hairlineWidth },
|
|
680
|
+
vhourLabel: { position: "absolute", right: 6, fontSize: 10 },
|
|
681
|
+
vgridLine: { position: "absolute", left: 0, right: 0, height: StyleSheet.hairlineWidth },
|
|
441
682
|
});
|