@butternutbox/pawprint-native 0.1.0 → 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.
- package/.turbo/turbo-build.log +8 -8
- package/CHANGELOG.md +20 -0
- package/dist/index.cjs +2213 -2174
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -3
- package/dist/index.d.ts +2 -3
- package/dist/index.js +2212 -2173
- package/dist/index.js.map +1 -1
- package/package.json +3 -4
- package/src/components/atoms/Illustration/Illustration.stories.tsx +2 -2
- package/src/components/atoms/Illustration/Illustration.tsx +3 -3
- package/src/components/atoms/Link/Link.test.tsx +3 -3
- package/src/components/atoms/Link/Link.tsx +7 -6
- package/src/components/atoms/Switch/Switch.tsx +13 -5
- package/src/components/molecules/ButtonDock/ButtonDock.stories.tsx +44 -25
- package/src/components/molecules/ButtonDock/ButtonDock.tsx +16 -13
- package/src/components/molecules/ButtonGroup/ButtonGroup.stories.tsx +47 -22
- package/src/components/molecules/FilterTab/FilterTab.tsx +4 -4
- package/src/components/molecules/PasswordField/PasswordFieldError.tsx +6 -5
- package/src/components/molecules/PasswordField/PasswordFieldRequirements.tsx +11 -8
- package/src/components/molecules/PictureSelector/PictureSelector.stories.tsx +0 -39
- package/src/components/molecules/PictureSelector/PictureSelector.tsx +58 -36
- package/tsup.config.ts +1 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React from "react"
|
|
2
2
|
import { View, Pressable, ViewProps, PressableProps } from "react-native"
|
|
3
|
+
import Svg, { Path } from "react-native-svg"
|
|
3
4
|
import styled from "@emotion/native"
|
|
4
5
|
import { useTheme } from "@emotion/react"
|
|
5
|
-
import { Icon, type PawprintIcon } from "../../atoms/Icon"
|
|
6
6
|
import { Illustration } from "../../atoms/Illustration"
|
|
7
7
|
import { Typography } from "../../atoms/Typography"
|
|
8
8
|
import { MessageCard } from "../MessageCard"
|
|
@@ -17,7 +17,6 @@ type PawprintIllustration = React.ComponentType<{
|
|
|
17
17
|
export type PictureSelectorItem = {
|
|
18
18
|
value: string
|
|
19
19
|
illustration?: PawprintIllustration
|
|
20
|
-
icon?: PawprintIcon
|
|
21
20
|
disabled?: boolean
|
|
22
21
|
ariaLabel?: string
|
|
23
22
|
insightTitle?: string
|
|
@@ -48,11 +47,44 @@ type PressableOwnForItem = Omit<PressableProps, "onPress" | "disabled">
|
|
|
48
47
|
// ─── Pointer shape ────────────────────────────────────────────────────────────
|
|
49
48
|
|
|
50
49
|
// TODO: add to pictureSelector.json — pointer is 24w × 12h triangle in Figma.
|
|
51
|
-
|
|
52
|
-
// (the CSS/RN triangle trick), which *are* the shape itself.
|
|
53
|
-
const POINTER_HALF_WIDTH = 12
|
|
50
|
+
const POINTER_WIDTH = 24
|
|
54
51
|
const POINTER_HEIGHT = 12
|
|
55
52
|
|
|
53
|
+
// Build an SVG path for the rounded-corner pointer: apex centered at the top
|
|
54
|
+
// of a 24×12 box, bottom edge along the bottom. `r` is the corner radius. The
|
|
55
|
+
// triangle is isoceles with apex interior angle 90° and bottom interior angles
|
|
56
|
+
// 45°, so the inset distances along each edge from a vertex are r·cot(θ/2) —
|
|
57
|
+
// i.e. r at the apex and r·(√2 + 1) at the bottom corners.
|
|
58
|
+
const buildPointerPath = (r: number): string => {
|
|
59
|
+
const w = POINTER_WIDTH
|
|
60
|
+
const h = POINTER_HEIGHT
|
|
61
|
+
const apexInset = r
|
|
62
|
+
const botInset = r * (Math.SQRT2 + 1)
|
|
63
|
+
const sin45 = Math.SQRT1_2
|
|
64
|
+
const apexAxis = apexInset * sin45
|
|
65
|
+
const botAxis = botInset * sin45
|
|
66
|
+
|
|
67
|
+
const apexLeftX = w / 2 - apexAxis
|
|
68
|
+
const apexRightX = w / 2 + apexAxis
|
|
69
|
+
const apexY = apexAxis
|
|
70
|
+
const blEdgeX = botAxis
|
|
71
|
+
const blEdgeY = h - botAxis
|
|
72
|
+
const blBottomX = botInset
|
|
73
|
+
const brBottomX = w - botInset
|
|
74
|
+
const brEdgeX = w - botAxis
|
|
75
|
+
|
|
76
|
+
return [
|
|
77
|
+
`M ${blEdgeX} ${blEdgeY}`,
|
|
78
|
+
`L ${apexLeftX} ${apexY}`,
|
|
79
|
+
`A ${r} ${r} 0 0 1 ${apexRightX} ${apexY}`,
|
|
80
|
+
`L ${brEdgeX} ${blEdgeY}`,
|
|
81
|
+
`A ${r} ${r} 0 0 1 ${brBottomX} ${h}`,
|
|
82
|
+
`L ${blBottomX} ${h}`,
|
|
83
|
+
`A ${r} ${r} 0 0 1 ${blEdgeX} ${blEdgeY}`,
|
|
84
|
+
"Z"
|
|
85
|
+
].join(" ")
|
|
86
|
+
}
|
|
87
|
+
|
|
56
88
|
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
57
89
|
|
|
58
90
|
const parseTokenValue = (value: string): number => parseFloat(value)
|
|
@@ -120,30 +152,13 @@ const StyledPictureButton = styled(Pressable)<{
|
|
|
120
152
|
})
|
|
121
153
|
)
|
|
122
154
|
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
// the pointer visually connects the selected button to the insight
|
|
131
|
-
// card below. Using rotate instead of `borderBottom` because RN's
|
|
132
|
-
// triangle-via-borders rendering is inconsistent when the coloured
|
|
133
|
-
// border is on the bottom with transparent left/right on certain
|
|
134
|
-
// platforms.
|
|
135
|
-
width: 0,
|
|
136
|
-
height: 0,
|
|
137
|
-
borderLeftWidth: POINTER_HALF_WIDTH,
|
|
138
|
-
borderRightWidth: POINTER_HALF_WIDTH,
|
|
139
|
-
borderTopWidth: POINTER_HEIGHT,
|
|
140
|
-
borderLeftColor: "transparent",
|
|
141
|
-
borderRightColor: "transparent",
|
|
142
|
-
borderTopColor: pointerColor,
|
|
143
|
-
borderStyle: "solid",
|
|
144
|
-
transform: [{ rotate: "180deg" }],
|
|
145
|
-
opacity: pointerVisible ? 1 : 0
|
|
146
|
-
}))
|
|
155
|
+
const StyledPointer = styled(Svg)<{ pointerVisible: boolean }>(
|
|
156
|
+
({ pointerVisible }) => ({
|
|
157
|
+
width: POINTER_WIDTH,
|
|
158
|
+
height: POINTER_HEIGHT,
|
|
159
|
+
opacity: pointerVisible ? 1 : 0
|
|
160
|
+
})
|
|
161
|
+
)
|
|
147
162
|
|
|
148
163
|
// ─── Component ────────────────────────────────────────────────────────────────
|
|
149
164
|
|
|
@@ -217,6 +232,9 @@ export const PictureSelector = React.forwardRef<View, PictureSelectorProps>(
|
|
|
217
232
|
pictureButton.borderWidth.default
|
|
218
233
|
)
|
|
219
234
|
const borderWidthActive = parseTokenValue(pictureButton.borderWidth.active)
|
|
235
|
+
const pointerPath = buildPointerPath(
|
|
236
|
+
parseTokenValue(pictureButton.pointer.borderRadius.default)
|
|
237
|
+
)
|
|
220
238
|
const resolvedMinWidth =
|
|
221
239
|
itemMinWidth ?? parseTokenValue(pictureButton.size.minWidth)
|
|
222
240
|
// Default min-height to min-width so the cards stay square at the floor,
|
|
@@ -244,7 +262,6 @@ export const PictureSelector = React.forwardRef<View, PictureSelectorProps>(
|
|
|
244
262
|
{items.map((item) => {
|
|
245
263
|
const isSelected = item.value === selectedValue
|
|
246
264
|
const Visual = item.illustration
|
|
247
|
-
const IconComp = item.icon
|
|
248
265
|
const buttonProps: Omit<
|
|
249
266
|
React.ComponentProps<typeof StyledPictureButton>,
|
|
250
267
|
keyof PressableOwnForItem
|
|
@@ -284,15 +301,20 @@ export const PictureSelector = React.forwardRef<View, PictureSelectorProps>(
|
|
|
284
301
|
{...buttonProps}
|
|
285
302
|
>
|
|
286
303
|
{Visual ? (
|
|
287
|
-
<Illustration illustration={Visual} size="
|
|
288
|
-
) : IconComp ? (
|
|
289
|
-
<Icon icon={IconComp} size="2xl" />
|
|
304
|
+
<Illustration illustration={Visual} size="xl" />
|
|
290
305
|
) : null}
|
|
291
306
|
</StyledPictureButton>
|
|
292
|
-
<
|
|
293
|
-
pointerColor={pictureButton.colour.pointer.default}
|
|
307
|
+
<StyledPointer
|
|
294
308
|
pointerVisible={isSelected && hasInsight}
|
|
295
|
-
|
|
309
|
+
width={POINTER_WIDTH}
|
|
310
|
+
height={POINTER_HEIGHT}
|
|
311
|
+
viewBox={`0 0 ${POINTER_WIDTH} ${POINTER_HEIGHT}`}
|
|
312
|
+
>
|
|
313
|
+
<Path
|
|
314
|
+
d={pointerPath}
|
|
315
|
+
fill={pictureButton.colour.pointer.default}
|
|
316
|
+
/>
|
|
317
|
+
</StyledPointer>
|
|
296
318
|
</StyledItemStack>
|
|
297
319
|
)
|
|
298
320
|
})}
|