@butternutbox/pawprint-native 0.10.7 → 0.10.9
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/.turbo/turbo-build.log +5 -5
- package/CHANGELOG.md +29 -0
- package/dist/index.cjs +82 -79
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +82 -79
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/molecules/DatePicker/DatePicker.tsx +31 -26
- package/src/components/molecules/Drawer/Drawer.stories.tsx +49 -0
- package/src/components/molecules/Drawer/DrawerContent.tsx +20 -38
- package/src/components/molecules/Radio/Radio.tsx +3 -0
package/package.json
CHANGED
|
@@ -129,34 +129,36 @@ export type DatePickerProps = DatePickerOwnProps &
|
|
|
129
129
|
Omit<ViewProps, keyof DatePickerOwnProps>
|
|
130
130
|
|
|
131
131
|
const StyledContainer = styled(View)<{
|
|
132
|
-
containerGap: number
|
|
133
132
|
containerMaxWidth: number
|
|
134
|
-
}>(({
|
|
133
|
+
}>(({ containerMaxWidth }) => ({
|
|
135
134
|
flexDirection: "column",
|
|
136
|
-
|
|
135
|
+
// Fill the parent by default (capped by maxWidth) so consumers don't need a
|
|
136
|
+
// wrapper. Overridable via the `style` prop.
|
|
137
|
+
width: "100%",
|
|
137
138
|
maxWidth: containerMaxWidth
|
|
138
139
|
}))
|
|
139
140
|
|
|
140
|
-
const StyledMonthHeader = styled(View)<{ headerGap: number }>(
|
|
141
|
-
({ headerGap }) => ({
|
|
141
|
+
const StyledMonthHeader = styled(View)<{ headerGap: number; datesGap: number }>(
|
|
142
|
+
({ headerGap, datesGap }) => ({
|
|
142
143
|
flexDirection: "row",
|
|
143
144
|
alignItems: "center",
|
|
144
|
-
gap: headerGap
|
|
145
|
+
gap: headerGap,
|
|
146
|
+
// Gap between the month header and the dates grid.
|
|
147
|
+
marginBottom: datesGap
|
|
145
148
|
})
|
|
146
149
|
)
|
|
147
150
|
|
|
148
|
-
const StyledWeekRow = styled(View)({
|
|
149
|
-
flexDirection: "row"
|
|
150
|
-
|
|
151
|
+
const StyledWeekRow = styled(View)<{ weekGap: number }>(({ weekGap }) => ({
|
|
152
|
+
flexDirection: "row",
|
|
153
|
+
// Gap between the week-day header and the month header.
|
|
154
|
+
marginBottom: weekGap
|
|
155
|
+
}))
|
|
151
156
|
|
|
152
|
-
const StyledWeekCell = styled(View)
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
height: cellHeight
|
|
158
|
-
})
|
|
159
|
-
)
|
|
157
|
+
const StyledWeekCell = styled(View)({
|
|
158
|
+
flex: 1,
|
|
159
|
+
alignItems: "center",
|
|
160
|
+
justifyContent: "center"
|
|
161
|
+
})
|
|
160
162
|
|
|
161
163
|
const StyledDatesGrid = styled(View)<{ rowGap: number }>(({ rowGap }) => ({
|
|
162
164
|
flexDirection: "column",
|
|
@@ -280,7 +282,8 @@ export const DatePicker = React.forwardRef<View, DatePickerProps>(
|
|
|
280
282
|
const [slideDir, setSlideDir] = useState<"forward" | "backward">("forward")
|
|
281
283
|
|
|
282
284
|
const {
|
|
283
|
-
|
|
285
|
+
weekGap,
|
|
286
|
+
datesGap,
|
|
284
287
|
containerMaxWidth,
|
|
285
288
|
headerGap,
|
|
286
289
|
cellHeight,
|
|
@@ -291,7 +294,10 @@ export const DatePicker = React.forwardRef<View, DatePickerProps>(
|
|
|
291
294
|
rowGap
|
|
292
295
|
} = useMemo(
|
|
293
296
|
() => ({
|
|
294
|
-
|
|
297
|
+
// Gap between the week-day header and the month header.
|
|
298
|
+
weekGap: parseTokenValue(datePicker.spacing.gap),
|
|
299
|
+
// Gap between the month header and the dates grid.
|
|
300
|
+
datesGap: parseTokenValue(theme.tokens.semantics.dimensions.spacing.md),
|
|
295
301
|
containerMaxWidth: parseTokenValue(dt.size.width) * 7,
|
|
296
302
|
headerGap: parseTokenValue(datePicker.month.spacing.gap),
|
|
297
303
|
cellHeight: parseTokenValue(dt.size.height),
|
|
@@ -301,7 +307,7 @@ export const DatePicker = React.forwardRef<View, DatePickerProps>(
|
|
|
301
307
|
disabledOpacity: parseTokenValue(dt.opacity.disabled),
|
|
302
308
|
rowGap: parseTokenValue(datePicker.dates.spacing.gap)
|
|
303
309
|
}),
|
|
304
|
-
[datePicker, dt]
|
|
310
|
+
[datePicker, dt, theme]
|
|
305
311
|
)
|
|
306
312
|
|
|
307
313
|
const resolvedGetDateState = useCallback(
|
|
@@ -423,14 +429,13 @@ export const DatePicker = React.forwardRef<View, DatePickerProps>(
|
|
|
423
429
|
return (
|
|
424
430
|
<StyledContainer
|
|
425
431
|
ref={ref}
|
|
426
|
-
containerGap={containerGap}
|
|
427
432
|
containerMaxWidth={containerMaxWidth}
|
|
428
433
|
{...rest}
|
|
429
434
|
>
|
|
430
435
|
{showWeekHeader && (
|
|
431
|
-
<StyledWeekRow accessibilityElementsHidden>
|
|
436
|
+
<StyledWeekRow weekGap={weekGap} accessibilityElementsHidden>
|
|
432
437
|
{weekDayLabels.map((label) => (
|
|
433
|
-
<StyledWeekCell key={label}
|
|
438
|
+
<StyledWeekCell key={label}>
|
|
434
439
|
<Typography
|
|
435
440
|
token={datePicker.week.typography}
|
|
436
441
|
align="center"
|
|
@@ -443,12 +448,12 @@ export const DatePicker = React.forwardRef<View, DatePickerProps>(
|
|
|
443
448
|
</StyledWeekRow>
|
|
444
449
|
)}
|
|
445
450
|
|
|
446
|
-
<StyledMonthHeader headerGap={headerGap}>
|
|
451
|
+
<StyledMonthHeader headerGap={headerGap} datesGap={datesGap}>
|
|
447
452
|
<View style={{ opacity: showPrevControl ? 1 : 0 }}>
|
|
448
453
|
<IconButton
|
|
449
454
|
icon={KeyboardArrowLeft}
|
|
450
455
|
variant="filled"
|
|
451
|
-
size="
|
|
456
|
+
size="md"
|
|
452
457
|
colour="primary"
|
|
453
458
|
aria-label="Previous month"
|
|
454
459
|
onPress={showPrevControl ? handlePrevMonth : undefined}
|
|
@@ -470,7 +475,7 @@ export const DatePicker = React.forwardRef<View, DatePickerProps>(
|
|
|
470
475
|
<IconButton
|
|
471
476
|
icon={KeyboardArrowRight}
|
|
472
477
|
variant="filled"
|
|
473
|
-
size="
|
|
478
|
+
size="md"
|
|
474
479
|
colour="primary"
|
|
475
480
|
aria-label="Next month"
|
|
476
481
|
onPress={showNextControl ? handleNextMonth : undefined}
|
|
@@ -205,6 +205,55 @@ export const LongContent = () => (
|
|
|
205
205
|
</View>
|
|
206
206
|
)
|
|
207
207
|
|
|
208
|
+
// Exercises the panel re-fit: toggling the extra paragraphs grows/shrinks the
|
|
209
|
+
// body after the drawer has opened. The panel should track the content —
|
|
210
|
+
// growing (up to its max, then scrolling) and shrinking back — never leaving a
|
|
211
|
+
// gap or clipping. Regression guard for the 0.10.8 re-measure feedback loop.
|
|
212
|
+
export const DynamicContent = () => {
|
|
213
|
+
const [expanded, setExpanded] = useState(false)
|
|
214
|
+
return (
|
|
215
|
+
<View style={styles.container}>
|
|
216
|
+
<Drawer.Root>
|
|
217
|
+
<Drawer.Trigger>
|
|
218
|
+
<Button variant="filled" colour="primary">
|
|
219
|
+
Open dynamic drawer
|
|
220
|
+
</Button>
|
|
221
|
+
</Drawer.Trigger>
|
|
222
|
+
<Drawer.Portal>
|
|
223
|
+
<Drawer.Overlay />
|
|
224
|
+
<Drawer.Content>
|
|
225
|
+
<Drawer.Header variant="titleAndText">
|
|
226
|
+
<Drawer.Title>Delivery details</Drawer.Title>
|
|
227
|
+
<Drawer.Close />
|
|
228
|
+
</Drawer.Header>
|
|
229
|
+
<Drawer.Body>
|
|
230
|
+
<Typography>{bodyText}</Typography>
|
|
231
|
+
<Button
|
|
232
|
+
variant="outlined"
|
|
233
|
+
colour="secondary"
|
|
234
|
+
onPress={() => setExpanded((prev) => !prev)}
|
|
235
|
+
>
|
|
236
|
+
{expanded ? "Show less" : "Show more"}
|
|
237
|
+
</Button>
|
|
238
|
+
{expanded &&
|
|
239
|
+
Array.from({ length: 12 }, (_, i) => (
|
|
240
|
+
<Typography
|
|
241
|
+
key={i}
|
|
242
|
+
>{`More detail ${i + 1}: ${bodyText}`}</Typography>
|
|
243
|
+
))}
|
|
244
|
+
</Drawer.Body>
|
|
245
|
+
<Drawer.Footer>
|
|
246
|
+
<Button variant="filled" colour="primary">
|
|
247
|
+
Confirm
|
|
248
|
+
</Button>
|
|
249
|
+
</Drawer.Footer>
|
|
250
|
+
</Drawer.Content>
|
|
251
|
+
</Drawer.Portal>
|
|
252
|
+
</Drawer.Root>
|
|
253
|
+
</View>
|
|
254
|
+
)
|
|
255
|
+
}
|
|
256
|
+
|
|
208
257
|
export const Controlled = () => {
|
|
209
258
|
const [open, setOpen] = useState(false)
|
|
210
259
|
return (
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useCallback, useEffect, useMemo, useRef
|
|
1
|
+
import React, { useCallback, useEffect, useMemo, useRef } from "react"
|
|
2
2
|
import {
|
|
3
3
|
Animated,
|
|
4
4
|
Easing,
|
|
@@ -35,7 +35,7 @@ const StyledPanel = styled(View)<{
|
|
|
35
35
|
panelShadowColor: string
|
|
36
36
|
panelShadowOffsetY: number
|
|
37
37
|
panelShadowBlur: number
|
|
38
|
-
|
|
38
|
+
panelMaxHeight: number
|
|
39
39
|
}>(
|
|
40
40
|
({
|
|
41
41
|
panelBorderRadius,
|
|
@@ -46,12 +46,17 @@ const StyledPanel = styled(View)<{
|
|
|
46
46
|
panelShadowColor,
|
|
47
47
|
panelShadowOffsetY,
|
|
48
48
|
panelShadowBlur,
|
|
49
|
-
|
|
49
|
+
panelMaxHeight
|
|
50
50
|
}) => ({
|
|
51
51
|
width: "100%",
|
|
52
52
|
maxWidth: panelMaxWidth,
|
|
53
|
+
// The panel wraps its content and caps at maxHeight. It is intentionally
|
|
54
|
+
// NOT given a fixed height: letting it size to content means it re-fits
|
|
55
|
+
// automatically whenever the body grows or shrinks (async load, expanding
|
|
56
|
+
// sections). The body's own maxHeight (see DrawerBody) bounds scrolling and
|
|
57
|
+
// keeps the ScrollView from collapsing, so no fixed panel height is needed.
|
|
58
|
+
maxHeight: panelMaxHeight,
|
|
53
59
|
alignSelf: "center",
|
|
54
|
-
...(panelFlex != null ? { flex: panelFlex } : undefined),
|
|
55
60
|
borderTopLeftRadius: panelBorderRadius,
|
|
56
61
|
borderTopRightRadius: panelBorderRadius,
|
|
57
62
|
borderTopWidth: panelBorderWidth,
|
|
@@ -114,12 +119,6 @@ export const DrawerContent = React.forwardRef<View, DrawerContentProps>(
|
|
|
114
119
|
const isOpenRef = useRef(isOpen)
|
|
115
120
|
const activeAnim = useRef<Animated.CompositeAnimation | null>(null)
|
|
116
121
|
|
|
117
|
-
// After the first onLayout we know the real rendered height (capped at
|
|
118
|
-
// MAX_HEIGHT). We immediately kick off the entry animation from that height
|
|
119
|
-
// and then set explicit height + flex: 1 on the panel so DrawerBody's
|
|
120
|
-
// ScrollView gets a bounded container and can scroll correctly.
|
|
121
|
-
const [panelHeight, setPanelHeight] = useState(0)
|
|
122
|
-
|
|
123
122
|
useEffect(() => {
|
|
124
123
|
const id = translateY.addListener(({ value }) => {
|
|
125
124
|
translateYValue.current = value
|
|
@@ -127,15 +126,6 @@ export const DrawerContent = React.forwardRef<View, DrawerContentProps>(
|
|
|
127
126
|
return () => translateY.removeListener(id)
|
|
128
127
|
}, [translateY])
|
|
129
128
|
|
|
130
|
-
// Clamp the cached panel height when the window shrinks (e.g. orientation
|
|
131
|
-
// change) so the entry animation never starts from below the screen.
|
|
132
|
-
useEffect(() => {
|
|
133
|
-
if (panelHeightRef.current > 0 && panelHeightRef.current > maxHeight) {
|
|
134
|
-
setPanelHeight(maxHeight)
|
|
135
|
-
panelHeightRef.current = maxHeight
|
|
136
|
-
}
|
|
137
|
-
}, [maxHeight])
|
|
138
|
-
|
|
139
129
|
const runEntry = useCallback(() => {
|
|
140
130
|
if (panelHeightRef.current === 0) return
|
|
141
131
|
translateY.setValue(panelHeightRef.current)
|
|
@@ -187,21 +177,17 @@ export const DrawerContent = React.forwardRef<View, DrawerContentProps>(
|
|
|
187
177
|
({ nativeEvent }: { nativeEvent: { layout: { height: number } } }) => {
|
|
188
178
|
const h = nativeEvent.layout.height
|
|
189
179
|
const capped = Math.min(h, maxHeight)
|
|
180
|
+
if (capped <= 0) return
|
|
190
181
|
|
|
191
|
-
//
|
|
192
|
-
//
|
|
193
|
-
//
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
panelHeightRef.current = capped
|
|
197
|
-
}
|
|
182
|
+
// The panel wraps its content, so this fires again whenever the body
|
|
183
|
+
// grows or shrinks. Keep the cached height current for the entry/exit
|
|
184
|
+
// and drag-dismiss animations; the panel re-fits itself via layout, so
|
|
185
|
+
// there is nothing else to do here (no state, no feedback loop).
|
|
186
|
+
panelHeightRef.current = capped
|
|
198
187
|
|
|
199
|
-
//
|
|
200
|
-
//
|
|
201
|
-
|
|
202
|
-
// is still off-screen, so there is no visible jump.
|
|
203
|
-
if (isOpenRef.current && !entryRanRef.current && capped > 0) {
|
|
204
|
-
panelHeightRef.current = capped
|
|
188
|
+
// Kick off the entry animation on the first measurement. translateY is
|
|
189
|
+
// still off-screen (9999) at this point, so there is no visible jump.
|
|
190
|
+
if (isOpenRef.current && !entryRanRef.current) {
|
|
205
191
|
runEntry()
|
|
206
192
|
}
|
|
207
193
|
},
|
|
@@ -294,11 +280,7 @@ export const DrawerContent = React.forwardRef<View, DrawerContentProps>(
|
|
|
294
280
|
<DrawerFooterContext.Provider value={hasFooter}>
|
|
295
281
|
<DrawerDragContext.Provider value={dragContextValue}>
|
|
296
282
|
<Animated.View
|
|
297
|
-
style={[
|
|
298
|
-
styles.animatedWrapper,
|
|
299
|
-
panelHeight > 0 ? { height: panelHeight } : undefined,
|
|
300
|
-
{ transform: [{ translateY }] }
|
|
301
|
-
]}
|
|
283
|
+
style={[styles.animatedWrapper, { transform: [{ translateY }] }]}
|
|
302
284
|
>
|
|
303
285
|
<StyledPanel
|
|
304
286
|
ref={ref}
|
|
@@ -306,7 +288,7 @@ export const DrawerContent = React.forwardRef<View, DrawerContentProps>(
|
|
|
306
288
|
panelBorderRadius={parseTokenValue(drawer.borderRadius.top)}
|
|
307
289
|
panelBgColor={colour.background.container.default}
|
|
308
290
|
panelMaxWidth={parseTokenValue(drawer.size.maxWidth)}
|
|
309
|
-
|
|
291
|
+
panelMaxHeight={maxHeight}
|
|
310
292
|
panelBorderWidth={parseTokenValue(dimensions.borderWidth.sm)}
|
|
311
293
|
panelBorderColor={colour.border.default}
|
|
312
294
|
panelShadowColor={modal.shadow.color}
|
|
@@ -96,6 +96,9 @@ const StyledIndicator = styled(View)<{
|
|
|
96
96
|
const StyledTextContent = styled(View)<{
|
|
97
97
|
textContentGap: number
|
|
98
98
|
}>(({ textContentGap }) => ({
|
|
99
|
+
// Take the row's remaining width so long label/subText wraps within the tile
|
|
100
|
+
// instead of pushing the trailing asset past the tile's edge.
|
|
101
|
+
flex: 1,
|
|
99
102
|
flexDirection: "column",
|
|
100
103
|
gap: textContentGap
|
|
101
104
|
}))
|