@delacour/react-native-ui 0.4.0-alpha.20261020155447 → 0.4.1-alpha.20261020200151
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@delacour/react-native-ui",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1-alpha.20261020200151",
|
|
4
4
|
"description": "React Native UI components — Uniwind, Reanimated, Gesture Handler",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -181,7 +181,7 @@
|
|
|
181
181
|
"expo-blur": ">=15",
|
|
182
182
|
"@maplibre/maplibre-react-native": "^11.5.0",
|
|
183
183
|
"@central-icons-react-native/round-outlined-radius-1-stroke-1.5": "^1.1",
|
|
184
|
-
"@delacour/react-native-bottom-sheet": "0.2.0
|
|
184
|
+
"@delacour/react-native-bottom-sheet": ">=0.2.0",
|
|
185
185
|
"@delacour/react-native-charts": ">=0.1.0",
|
|
186
186
|
"@legendapp/list": ">=3.3",
|
|
187
187
|
"@shopify/react-native-skia": ">=2",
|
|
@@ -75,13 +75,18 @@ sheets.
|
|
|
75
75
|
|
|
76
76
|
## Drawing
|
|
77
77
|
|
|
78
|
-
- **A day is three layers:**
|
|
79
|
-
the label. The band spans the full cell so adjacent days join into one strip.
|
|
80
|
-
- **
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
78
|
+
- **A day is three layers:** the band (`bandTrack`, absolute, edge to edge, behind), `dayBase`
|
|
79
|
+
(the circle) and the label. The band spans the full cell so adjacent days join into one strip.
|
|
80
|
+
- **An end's band runs under the whole circle, capped at the circle's radius.** `bandTrack` clips
|
|
81
|
+
to the cell and centres `bandAnchor`, a box `w-input-*` wide — the width `size-input-*` gives the
|
|
82
|
+
circle. The band hangs off the anchor: start from its left edge (`rounded-l-full`) out past the
|
|
83
|
+
cell's right, end the mirror, middle past both edges and square; the clip trims each to the
|
|
84
|
+
cell. Three earlier versions failed: a band rounded across the whole end cell showed a crescent
|
|
85
|
+
beside the circle; one stopped at the cell's centre put half a translucent `secondary` circle
|
|
86
|
+
over band and half over the page — a two-tone circle; and one sized by `basis-input-*` did not
|
|
87
|
+
follow the house style's runtime retune of the input scale, so at `lg` the cap slid ~6pt off
|
|
88
|
+
the circle. A lone `only` day draws no band. At a week's edge the strip simply stops and
|
|
89
|
+
resumes on the next row.
|
|
85
90
|
- **Today is a ring (`border-ring`) and `text-primary`, never a fill**, so it cannot be mistaken
|
|
86
91
|
for a selection.
|
|
87
92
|
- **Variant:** `primary` fills `bg-primary`, band `bg-primary/15`; `secondary` fills
|
|
@@ -95,7 +95,13 @@ export function CalendarDay({ date, children, className }: CalendarDayProps): Re
|
|
|
95
95
|
onPress={handlePress}
|
|
96
96
|
testID={resolvePartTestID(calendar.testID, `day-${serialiseDate(date)}`)}
|
|
97
97
|
>
|
|
98
|
-
{showsBand ?
|
|
98
|
+
{showsBand ? (
|
|
99
|
+
<View className={slots.bandTrack()}>
|
|
100
|
+
<View className={slots.bandAnchor()}>
|
|
101
|
+
<View className={slots.band()} />
|
|
102
|
+
</View>
|
|
103
|
+
</View>
|
|
104
|
+
) : null}
|
|
99
105
|
<View className={slots.dayBase()}>{content}</View>
|
|
100
106
|
</Pressable>
|
|
101
107
|
);
|
|
@@ -90,6 +90,8 @@ describe("text colour stays on the text", () => {
|
|
|
90
90
|
"week",
|
|
91
91
|
"cell",
|
|
92
92
|
"dayBase",
|
|
93
|
+
"bandTrack",
|
|
94
|
+
"bandAnchor",
|
|
93
95
|
"band",
|
|
94
96
|
"pickerGrid",
|
|
95
97
|
"pickerItem",
|
|
@@ -111,33 +113,52 @@ describe("text colour stays on the text", () => {
|
|
|
111
113
|
});
|
|
112
114
|
|
|
113
115
|
describe("range band geometry", () => {
|
|
114
|
-
const
|
|
116
|
+
const slotsOf = (rangeRole: CalendarRangeRole) => calendarVariants({ rangeRole });
|
|
117
|
+
const bandOf = (rangeRole: CalendarRangeRole) => slotsOf(rangeRole).band();
|
|
115
118
|
|
|
116
119
|
// The cell is wider than the circle, so a band end rounded across the whole cell pokes out
|
|
117
|
-
// beside the circle. Each end instead
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
120
|
+
// beside the circle. Each end instead runs under the whole circle with a cap of its radius, so a
|
|
121
|
+
// translucent circle lies over band everywhere and never shows a two-tone half.
|
|
122
|
+
test("the track clips to the cell and centres the anchor", () => {
|
|
123
|
+
const track = slotsOf("start").bandTrack();
|
|
124
|
+
expect(track).toMatch(/\babsolute\b/);
|
|
125
|
+
expect(track).toMatch(/\binset-0\b/);
|
|
126
|
+
expect(track).toMatch(/\bitems-center\b/);
|
|
127
|
+
expect(track).toMatch(/\boverflow-hidden\b/);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// `w-input-*` is the width `size-input-*` sets, so the anchor tracks the circle through a
|
|
131
|
+
// runtime retune of the input scale; `basis-input-*` did not, and the cap slid off the circle.
|
|
132
|
+
test("the anchor is exactly as wide as the circle", () => {
|
|
133
|
+
for (const size of ["sm", "md", "lg"] as const) {
|
|
134
|
+
const slots = calendarVariants({ rangeRole: "start", size });
|
|
135
|
+
expect(slots.bandAnchor()).toContain(`w-input-${size}`);
|
|
136
|
+
expect(slots.dayBase()).toContain(`size-input-${size}`);
|
|
137
|
+
}
|
|
121
138
|
});
|
|
122
139
|
|
|
123
|
-
test("
|
|
124
|
-
expect(bandOf("
|
|
125
|
-
expect(bandOf("
|
|
140
|
+
test("start runs from the circle's left edge out past the cell, capped on the left", () => {
|
|
141
|
+
expect(bandOf("start")).toMatch(/(?:^|\s)left-0\b/);
|
|
142
|
+
expect(bandOf("start")).toMatch(/-right-\[\d+px\]/);
|
|
143
|
+
expect(bandOf("start")).toMatch(/\brounded-l-full\b/);
|
|
144
|
+
expect(bandOf("start")).not.toMatch(/\brounded-r-full\b/);
|
|
126
145
|
});
|
|
127
146
|
|
|
128
|
-
test("
|
|
129
|
-
expect(bandOf("
|
|
130
|
-
expect(bandOf("
|
|
147
|
+
test("end mirrors start", () => {
|
|
148
|
+
expect(bandOf("end")).toMatch(/(?:^|\s)right-0\b/);
|
|
149
|
+
expect(bandOf("end")).toMatch(/-left-\[\d+px\]/);
|
|
150
|
+
expect(bandOf("end")).toMatch(/\brounded-r-full\b/);
|
|
151
|
+
expect(bandOf("end")).not.toMatch(/\brounded-l-full\b/);
|
|
131
152
|
});
|
|
132
153
|
|
|
133
|
-
test("
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
154
|
+
test("middle runs past both edges, square", () => {
|
|
155
|
+
expect(bandOf("middle")).toMatch(/-left-\[\d+px\]/);
|
|
156
|
+
expect(bandOf("middle")).toMatch(/-right-\[\d+px\]/);
|
|
157
|
+
expect(bandOf("middle")).not.toMatch(/rounded-(?:l-|r-)?full/);
|
|
137
158
|
});
|
|
138
159
|
|
|
139
160
|
test("a lone day draws no band", () => {
|
|
140
|
-
expect(
|
|
161
|
+
expect(slotsOf("only").bandTrack()).toContain("hidden");
|
|
141
162
|
});
|
|
142
163
|
|
|
143
164
|
test("a selected day is a circle, never square", () => {
|
|
@@ -54,12 +54,14 @@ export const CALENDAR_PAGE_VELOCITY = 500;
|
|
|
54
54
|
* whole cell so neighbouring days join into one continuous strip — a gap between columns would
|
|
55
55
|
* break it into beads.
|
|
56
56
|
*
|
|
57
|
-
* **The band ends under the circle, never beside it.**
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
57
|
+
* **The band ends under the whole circle, never beside it.** `bandTrack` clips to the cell and
|
|
58
|
+
* centres `bandAnchor`, a box as wide as the circle — `w-input-*`, the width `size-input-*` sets,
|
|
59
|
+
* so a runtime retune of the input scale moves both. The band hangs off the anchor: start from
|
|
60
|
+
* its left edge, capped at the circle's radius, out past the cell's right; end the mirror; every
|
|
61
|
+
* day between past both edges, so the clip leaves it spanning the whole cell square — including at a week's edge, where the strip simply stops and
|
|
62
|
+
* picks up again on the next row. A band rounded across the whole end cell poked a crescent out
|
|
63
|
+
* beside the circle; one stopped at the cell's centre left half a translucent `secondary` circle
|
|
64
|
+
* over band and half over the page, a two-tone circle. A one-day range draws no band at all.
|
|
63
65
|
*
|
|
64
66
|
* **The cell steps on the input scale** — `h-input-*` and `text-input-*` — so a calendar inline
|
|
65
67
|
* beside a field shares its density, and a retune of the field retunes the calendar.
|
|
@@ -91,7 +93,11 @@ export const calendarVariants = tv({
|
|
|
91
93
|
week: "flex-row",
|
|
92
94
|
/** One day's column share, and the height of its touch target. */
|
|
93
95
|
cell: "flex-1 items-center justify-center",
|
|
94
|
-
/** The
|
|
96
|
+
/** The cell-sized clip behind a day inside a range, centring the band's anchor. */
|
|
97
|
+
bandTrack: "absolute inset-0 items-center overflow-hidden",
|
|
98
|
+
/** A circle-wide box where the circle sits, that the band hangs off. */
|
|
99
|
+
bandAnchor: "h-full",
|
|
100
|
+
/** The strip behind a day inside a range, run past the cell and clipped by the track. */
|
|
95
101
|
band: "absolute inset-y-0",
|
|
96
102
|
/** The circle a selection fills and today rings. */
|
|
97
103
|
dayBase: "items-center justify-center rounded-full border border-transparent",
|
|
@@ -113,6 +119,7 @@ export const calendarVariants = tv({
|
|
|
113
119
|
sm: {
|
|
114
120
|
captionText: "text-input-sm",
|
|
115
121
|
cell: "h-input-sm",
|
|
122
|
+
bandAnchor: "w-input-sm",
|
|
116
123
|
dayBase: "size-input-sm",
|
|
117
124
|
dayLabel: "text-input-sm",
|
|
118
125
|
pickerItem: "h-input-sm",
|
|
@@ -121,6 +128,7 @@ export const calendarVariants = tv({
|
|
|
121
128
|
md: {
|
|
122
129
|
captionText: "text-input-md",
|
|
123
130
|
cell: "h-input-md",
|
|
131
|
+
bandAnchor: "w-input-md",
|
|
124
132
|
dayBase: "size-input-md",
|
|
125
133
|
dayLabel: "text-input-md",
|
|
126
134
|
pickerItem: "h-input-md",
|
|
@@ -129,6 +137,7 @@ export const calendarVariants = tv({
|
|
|
129
137
|
lg: {
|
|
130
138
|
captionText: "text-input-lg",
|
|
131
139
|
cell: "h-input-lg",
|
|
140
|
+
bandAnchor: "w-input-lg",
|
|
132
141
|
dayBase: "size-input-lg",
|
|
133
142
|
dayLabel: "text-input-lg",
|
|
134
143
|
pickerItem: "h-input-lg",
|
|
@@ -141,11 +150,11 @@ export const calendarVariants = tv({
|
|
|
141
150
|
band: { dayBase: "bg-transparent" },
|
|
142
151
|
},
|
|
143
152
|
rangeRole: {
|
|
144
|
-
none: {
|
|
145
|
-
start: { band: "left-
|
|
146
|
-
middle: { band: "
|
|
147
|
-
end: { band: "left-
|
|
148
|
-
only: {
|
|
153
|
+
none: { bandTrack: "hidden" },
|
|
154
|
+
start: { band: "-right-[1000px] left-0 rounded-l-full" },
|
|
155
|
+
middle: { band: "-left-[1000px] -right-[1000px]" },
|
|
156
|
+
end: { band: "-left-[1000px] right-0 rounded-r-full" },
|
|
157
|
+
only: { bandTrack: "hidden" },
|
|
149
158
|
},
|
|
150
159
|
isToday: { true: {}, false: {} },
|
|
151
160
|
isOutside: { true: {}, false: {} },
|