@ankhorage/zora-tabletop 0.0.1 → 0.0.3
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/CHANGELOG.md +12 -0
- package/README.md +294 -72
- package/dist/colors.d.ts +17 -0
- package/dist/colors.d.ts.map +1 -1
- package/dist/colors.js +116 -8
- package/dist/colors.js.map +1 -1
- package/dist/components/card-back/CardBack.d.ts +12 -0
- package/dist/components/card-back/CardBack.d.ts.map +1 -1
- package/dist/components/card-back/CardBack.js +12 -0
- package/dist/components/card-back/CardBack.js.map +1 -1
- package/dist/components/card-hand/CardHand.d.ts +12 -0
- package/dist/components/card-hand/CardHand.d.ts.map +1 -1
- package/dist/components/card-hand/CardHand.js +12 -0
- package/dist/components/card-hand/CardHand.js.map +1 -1
- package/dist/components/playing-card/PlayingCard.d.ts +13 -0
- package/dist/components/playing-card/PlayingCard.d.ts.map +1 -1
- package/dist/components/playing-card/PlayingCard.js +13 -0
- package/dist/components/playing-card/PlayingCard.js.map +1 -1
- package/dist/components/tabletop-table/TabletopTable.d.ts +17 -0
- package/dist/components/tabletop-table/TabletopTable.d.ts.map +1 -1
- package/dist/components/tabletop-table/TabletopTable.js +23 -6
- package/dist/components/tabletop-table/TabletopTable.js.map +1 -1
- package/package.json +2 -2
- package/src/colors.test.ts +58 -0
- package/src/colors.ts +156 -8
- package/src/components/card-back/CardBack.tsx +12 -0
- package/src/components/card-hand/CardHand.tsx +12 -0
- package/src/components/playing-card/PlayingCard.tsx +13 -0
- package/src/components/tabletop-table/TabletopTable.tsx +23 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @ankhorage/zora-tabletop
|
|
2
2
|
|
|
3
|
+
## 0.0.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 25a2245: Add Paradox README and usage documentation comments for tabletop UI exports.
|
|
8
|
+
|
|
9
|
+
## 0.0.2
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 3b3651b: Improve tabletop label readability by deriving contrast-aware text colors for table and seat surfaces.
|
|
14
|
+
|
|
3
15
|
## 0.0.1
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -3,10 +3,92 @@
|
|
|
3
3
|
|
|
4
4
|
# @ankhorage/zora-tabletop
|
|
5
5
|
|
|
6
|
-
         
|
|
7
7
|
|
|
8
8
|
Reusable tabletop, playing-card, seat, token, and card-game presentation components for React Native and React Native Web.
|
|
9
9
|
|
|
10
|
+
## Usage
|
|
11
|
+
|
|
12
|
+
### Minimal tabletop app root.
|
|
13
|
+
|
|
14
|
+
Use `TabletopTable` inside a ZORA app shell to render generic seats, visible
|
|
15
|
+
cards, face-down cards, and center-table labels without adding game rules.
|
|
16
|
+
|
|
17
|
+
Source: `examples/basic-tabletop/App.tsx`
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
import {
|
|
21
|
+
AppBar,
|
|
22
|
+
AppShell,
|
|
23
|
+
Screen,
|
|
24
|
+
ScreenSection,
|
|
25
|
+
ZoraProvider,
|
|
26
|
+
type ZoraTheme,
|
|
27
|
+
} from '@ankhorage/zora';
|
|
28
|
+
import { type TabletopSeatState, TabletopTable } from '@ankhorage/zora-tabletop';
|
|
29
|
+
|
|
30
|
+
const tabletopTheme: ZoraTheme = {
|
|
31
|
+
id: 'basic-tabletop',
|
|
32
|
+
name: 'Basic tabletop',
|
|
33
|
+
appCategory: 'games',
|
|
34
|
+
primaryColor: '#0f766e',
|
|
35
|
+
harmony: 'analogous',
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const seats: readonly TabletopSeatState[] = [
|
|
39
|
+
{
|
|
40
|
+
id: 'seat-a',
|
|
41
|
+
label: 'Seat A',
|
|
42
|
+
sublabel: 'Ready',
|
|
43
|
+
cards: [
|
|
44
|
+
{ rank: 'A', suit: 'spades' },
|
|
45
|
+
{ rank: 'K', suit: 'hearts' },
|
|
46
|
+
],
|
|
47
|
+
selected: true,
|
|
48
|
+
tokenLabel: 'Active',
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
id: 'seat-b',
|
|
52
|
+
label: 'Seat B',
|
|
53
|
+
sublabel: 'Hidden cards',
|
|
54
|
+
faceDownCards: 2,
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
id: 'seat-c',
|
|
58
|
+
label: 'Seat C',
|
|
59
|
+
sublabel: 'Paused',
|
|
60
|
+
faceDownCards: 2,
|
|
61
|
+
muted: true,
|
|
62
|
+
},
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
export default function BasicTabletopApp() {
|
|
66
|
+
return (
|
|
67
|
+
<ZoraProvider initialMode="light" theme={tabletopTheme}>
|
|
68
|
+
<AppShell header={<AppBar title="Tabletop" subtitle="Reusable card-game UI" />}>
|
|
69
|
+
<Screen>
|
|
70
|
+
<ScreenSection
|
|
71
|
+
title="Table state"
|
|
72
|
+
description="Map app data into generic seats and cards."
|
|
73
|
+
>
|
|
74
|
+
<TabletopTable
|
|
75
|
+
seats={seats}
|
|
76
|
+
centerCards={[
|
|
77
|
+
{ rank: 'Q', suit: 'diamonds' },
|
|
78
|
+
{ rank: 'J', suit: 'clubs' },
|
|
79
|
+
{ rank: '10', suit: 'spades' },
|
|
80
|
+
]}
|
|
81
|
+
centerLabel="Round 1"
|
|
82
|
+
centerSublabel="Shared cards"
|
|
83
|
+
/>
|
|
84
|
+
</ScreenSection>
|
|
85
|
+
</Screen>
|
|
86
|
+
</AppShell>
|
|
87
|
+
</ZoraProvider>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
10
92
|
## Generated documentation
|
|
11
93
|
|
|
12
94
|
- [Interactive documentation app](././paradox/index.html)
|
|
@@ -20,79 +102,219 @@ Reusable tabletop, playing-card, seat, token, and card-game presentation compone
|
|
|
20
102
|
- [PlayingCard sequence](././paradox/diagrams/sequences/playing-card.mmd)
|
|
21
103
|
- [TabletopTable sequence](././paradox/diagrams/sequences/tabletop-table.mmd)
|
|
22
104
|
|
|
23
|
-
##
|
|
105
|
+
## Public API
|
|
106
|
+
|
|
107
|
+
### Components
|
|
108
|
+
|
|
109
|
+
<details>
|
|
110
|
+
<summary>CardBack</summary>
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
CardBack({
|
|
114
|
+
size = 'medium',
|
|
115
|
+
muted = false,
|
|
116
|
+
accessibilityLabel,
|
|
117
|
+
colorScheme,
|
|
118
|
+
testID,
|
|
119
|
+
}: CardBackProps) => React.JSX.Element
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Face-down playing-card primitive for hidden cards and decks.
|
|
123
|
+
|
|
124
|
+
Use `CardBack` when a card should be represented visually without exposing its
|
|
125
|
+
rank or suit. The component keeps a generic accessible label for hidden cards.
|
|
126
|
+
|
|
127
|
+
#### Hidden cards
|
|
128
|
+
|
|
129
|
+
```tsx
|
|
130
|
+
<CardBack size="small" />
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Related types: `CardBackProps`
|
|
134
|
+
|
|
135
|
+
<details>
|
|
136
|
+
<summary>Props</summary>
|
|
137
|
+
|
|
138
|
+
| Prop | Type | Required | Default | Description |
|
|
139
|
+
| ------------------ | ------------------------------------- | -------- | ---------- | ----------- |
|
|
140
|
+
| accessibilityLabel | `string \| undefined` | no | — | |
|
|
141
|
+
| colorScheme | `TabletopColorOverrides \| undefined` | no | — | |
|
|
142
|
+
| muted | `boolean \| undefined` | no | `false` | |
|
|
143
|
+
| size | `TabletopCardSize \| undefined` | no | `'medium'` | |
|
|
144
|
+
| testID | `string \| undefined` | no | — | |
|
|
145
|
+
|
|
146
|
+
</details>
|
|
147
|
+
|
|
148
|
+
</details>
|
|
149
|
+
|
|
150
|
+
<details>
|
|
151
|
+
<summary>CardHand</summary>
|
|
152
|
+
|
|
153
|
+
```ts
|
|
154
|
+
CardHand({
|
|
155
|
+
cards = [],
|
|
156
|
+
faceDownCards = 0,
|
|
157
|
+
size = 'medium',
|
|
158
|
+
muted = false,
|
|
159
|
+
colorScheme,
|
|
160
|
+
accessibilityLabel,
|
|
161
|
+
testID,
|
|
162
|
+
}: CardHandProps) => React.JSX.Element
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Compact row of visible and face-down playing cards.
|
|
166
|
+
|
|
167
|
+
Use `CardHand` when a seat, pile, or custom layout needs to show multiple cards
|
|
168
|
+
with consistent spacing, sizing, and muted state handling.
|
|
169
|
+
|
|
170
|
+
#### Mixed hand
|
|
171
|
+
|
|
172
|
+
```tsx
|
|
173
|
+
<CardHand cards={[{ rank: 'Q', suit: 'hearts' }]} faceDownCards={1} />
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Related types: `CardHandProps`
|
|
177
|
+
|
|
178
|
+
<details>
|
|
179
|
+
<summary>Props</summary>
|
|
180
|
+
|
|
181
|
+
| Prop | Type | Required | Default | Description |
|
|
182
|
+
| ------------------ | ------------------------------------------ | -------- | ---------- | ----------- |
|
|
183
|
+
| accessibilityLabel | `string \| undefined` | no | — | |
|
|
184
|
+
| cards | `readonly PlayingCardValue[] \| undefined` | no | `[]` | |
|
|
185
|
+
| colorScheme | `TabletopColorOverrides \| undefined` | no | — | |
|
|
186
|
+
| faceDownCards | `number \| undefined` | no | `0` | |
|
|
187
|
+
| muted | `boolean \| undefined` | no | `false` | |
|
|
188
|
+
| size | `TabletopCardSize \| undefined` | no | `'medium'` | |
|
|
189
|
+
| testID | `string \| undefined` | no | — | |
|
|
190
|
+
|
|
191
|
+
</details>
|
|
192
|
+
|
|
193
|
+
</details>
|
|
194
|
+
|
|
195
|
+
<details>
|
|
196
|
+
<summary>PlayingCard</summary>
|
|
197
|
+
|
|
198
|
+
```ts
|
|
199
|
+
PlayingCard({
|
|
200
|
+
card,
|
|
201
|
+
size = 'medium',
|
|
202
|
+
selected = false,
|
|
203
|
+
muted = false,
|
|
204
|
+
accessibilityLabel,
|
|
205
|
+
colorScheme,
|
|
206
|
+
testID,
|
|
207
|
+
}: PlayingCardProps) => React.JSX.Element
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Theme-aware face-up playing card primitive.
|
|
211
|
+
|
|
212
|
+
Use `PlayingCard` for visible card values in hands, shared table cards, piles,
|
|
213
|
+
or custom tabletop layouts. The component renders rank and suit text and exposes
|
|
214
|
+
an accessible card label by default.
|
|
215
|
+
|
|
216
|
+
#### Face-up card
|
|
217
|
+
|
|
218
|
+
```tsx
|
|
219
|
+
<PlayingCard card={{ rank: 'A', suit: 'spades' }} selected />
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Related types: `PlayingCardProps`
|
|
24
223
|
|
|
25
224
|
<details>
|
|
26
|
-
<summary>
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
package__ankhorage_zora_tabletop -.-> module_src_components_card_hand_index_ts
|
|
60
|
-
module_src_components_card_hand_types_ts["src/components/card-hand/types.ts"]
|
|
61
|
-
package__ankhorage_zora_tabletop -.-> module_src_components_card_hand_types_ts
|
|
62
|
-
module_src_components_card_hand_types_ts --> module_src_colors_ts
|
|
63
|
-
module_src_components_card_hand_types_ts --> module_src_types_ts
|
|
64
|
-
module_src_components_playing_card_index_ts["src/components/playing-card/index.ts"]
|
|
65
|
-
package__ankhorage_zora_tabletop -.-> module_src_components_playing_card_index_ts
|
|
66
|
-
module_src_components_playing_card_PlayingCard_tsx["src/components/playing-card/PlayingCard.tsx"]
|
|
67
|
-
package__ankhorage_zora_tabletop -.-> module_src_components_playing_card_PlayingCard_tsx
|
|
68
|
-
module_src_components_playing_card_PlayingCard_tsx --> module_src_cardLabel_ts
|
|
69
|
-
module_src_components_playing_card_PlayingCard_tsx --> module_src_cardSizing_ts
|
|
70
|
-
module_src_components_playing_card_PlayingCard_tsx --> module_src_colors_ts
|
|
71
|
-
module_src_components_playing_card_PlayingCard_tsx --> module_src_components_playing_card_types_ts
|
|
72
|
-
module_src_components_playing_card_PlayingCard_tsx --> module_src_types_ts
|
|
73
|
-
module_src_components_playing_card_types_ts["src/components/playing-card/types.ts"]
|
|
74
|
-
package__ankhorage_zora_tabletop -.-> module_src_components_playing_card_types_ts
|
|
75
|
-
module_src_components_playing_card_types_ts --> module_src_colors_ts
|
|
76
|
-
module_src_components_playing_card_types_ts --> module_src_types_ts
|
|
77
|
-
module_src_components_tabletop_table_index_ts["src/components/tabletop-table/index.ts"]
|
|
78
|
-
package__ankhorage_zora_tabletop -.-> module_src_components_tabletop_table_index_ts
|
|
79
|
-
module_src_components_tabletop_table_TabletopTable_tsx["src/components/tabletop-table/TabletopTable.tsx"]
|
|
80
|
-
package__ankhorage_zora_tabletop -.-> module_src_components_tabletop_table_TabletopTable_tsx
|
|
81
|
-
module_src_components_tabletop_table_TabletopTable_tsx --> module_src_colors_ts
|
|
82
|
-
module_src_components_tabletop_table_TabletopTable_tsx --> module_src_components_card_hand_index_ts
|
|
83
|
-
module_src_components_tabletop_table_TabletopTable_tsx --> module_src_components_tabletop_table_types_ts
|
|
84
|
-
module_src_components_tabletop_table_TabletopTable_tsx --> module_src_tablePositions_ts
|
|
85
|
-
module_src_components_tabletop_table_TabletopTable_tsx --> module_src_types_ts
|
|
86
|
-
module_src_components_tabletop_table_types_ts["src/components/tabletop-table/types.ts"]
|
|
87
|
-
package__ankhorage_zora_tabletop -.-> module_src_components_tabletop_table_types_ts
|
|
88
|
-
module_src_components_tabletop_table_types_ts --> module_src_colors_ts
|
|
89
|
-
module_src_components_tabletop_table_types_ts --> module_src_types_ts
|
|
90
|
-
module_src_index_ts["src/index.ts"]
|
|
91
|
-
module_src_tablePositions_ts["src/tablePositions.ts"]
|
|
92
|
-
package__ankhorage_zora_tabletop -.-> module_src_tablePositions_ts
|
|
93
|
-
module_src_tablePositions_ts --> module_src_types_ts
|
|
94
|
-
module_src_types_ts["src/types.ts"]
|
|
95
|
-
package__ankhorage_zora_tabletop -.-> module_src_types_ts
|
|
225
|
+
<summary>Props</summary>
|
|
226
|
+
|
|
227
|
+
| Prop | Type | Required | Default | Description |
|
|
228
|
+
| ------------------ | ------------------------------------- | -------- | ---------- | ----------- |
|
|
229
|
+
| accessibilityLabel | `string \| undefined` | no | — | |
|
|
230
|
+
| card | `PlayingCardValue` | yes | — | |
|
|
231
|
+
| colorScheme | `TabletopColorOverrides \| undefined` | no | — | |
|
|
232
|
+
| muted | `boolean \| undefined` | no | `false` | |
|
|
233
|
+
| selected | `boolean \| undefined` | no | `false` | |
|
|
234
|
+
| size | `TabletopCardSize \| undefined` | no | `'medium'` | |
|
|
235
|
+
| testID | `string \| undefined` | no | — | |
|
|
236
|
+
|
|
237
|
+
</details>
|
|
238
|
+
|
|
239
|
+
</details>
|
|
240
|
+
|
|
241
|
+
<details>
|
|
242
|
+
<summary>TabletopTable</summary>
|
|
243
|
+
|
|
244
|
+
```ts
|
|
245
|
+
TabletopTable({
|
|
246
|
+
seats,
|
|
247
|
+
centerCards = [],
|
|
248
|
+
centerLabel,
|
|
249
|
+
centerSublabel,
|
|
250
|
+
shape = 'oval',
|
|
251
|
+
seatCount,
|
|
252
|
+
cardSize = 'small',
|
|
253
|
+
disabled = false,
|
|
254
|
+
colorScheme,
|
|
255
|
+
accessibilityLabel,
|
|
256
|
+
testID,
|
|
257
|
+
}: TabletopTableProps) => React.JSX.Element
|
|
96
258
|
```
|
|
97
259
|
|
|
260
|
+
Responsive tabletop surface for generic card-game and board-game scenes.
|
|
261
|
+
|
|
262
|
+
Use `TabletopTable` to arrange seats around a themed table surface, display
|
|
263
|
+
shared center cards, and show neutral seat labels/tokens without embedding game
|
|
264
|
+
rules into the component.
|
|
265
|
+
|
|
266
|
+
#### Basic table
|
|
267
|
+
|
|
268
|
+
```tsx
|
|
269
|
+
<TabletopTable seats={seats} centerCards={[{ rank: 'A', suit: 'spades' }]} centerLabel="Round 1" />
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
Related types: `TabletopTableProps`
|
|
273
|
+
|
|
274
|
+
<details>
|
|
275
|
+
<summary>Props</summary>
|
|
276
|
+
|
|
277
|
+
| Prop | Type | Required | Default | Description |
|
|
278
|
+
| ------------------ | ------------------------------------------ | -------- | --------- | ----------- |
|
|
279
|
+
| accessibilityLabel | `string \| undefined` | no | — | |
|
|
280
|
+
| cardSize | `TabletopCardSize \| undefined` | no | `'small'` | |
|
|
281
|
+
| centerCards | `readonly PlayingCardValue[] \| undefined` | no | `[]` | |
|
|
282
|
+
| centerLabel | `React.ReactNode \| undefined` | no | — | |
|
|
283
|
+
| centerSublabel | `React.ReactNode \| undefined` | no | — | |
|
|
284
|
+
| colorScheme | `TabletopColorOverrides \| undefined` | no | — | |
|
|
285
|
+
| disabled | `boolean \| undefined` | no | `false` | |
|
|
286
|
+
| seatCount | `TabletopSeatCount \| undefined` | no | — | |
|
|
287
|
+
| seats | `readonly TabletopSeatState[]` | yes | — | |
|
|
288
|
+
| shape | `TabletopShape \| undefined` | no | `'oval'` | |
|
|
289
|
+
| testID | `string \| undefined` | no | — | |
|
|
290
|
+
|
|
291
|
+
</details>
|
|
292
|
+
|
|
293
|
+
</details>
|
|
294
|
+
|
|
295
|
+
### Utilities
|
|
296
|
+
|
|
297
|
+
<details>
|
|
298
|
+
<summary>createTabletopColorScheme</summary>
|
|
299
|
+
|
|
300
|
+
```ts
|
|
301
|
+
createTabletopColorScheme(theme: TabletopColorThemeShape, overrides?: Partial<TabletopColorScheme>) => TabletopColorScheme
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
Creates the theme-derived color palette used by tabletop primitives.
|
|
305
|
+
|
|
306
|
+
Use `createTabletopColorScheme` when custom components need to align with the
|
|
307
|
+
same card, table, seat, token, and contrast-aware foreground colors as the
|
|
308
|
+
built-in tabletop components.
|
|
309
|
+
|
|
310
|
+
#### Custom color scheme
|
|
311
|
+
|
|
312
|
+
```ts
|
|
313
|
+
const colors = createTabletopColorScheme(theme, { tableFelt: '#065f46' });
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
Module: `src/colors.ts`
|
|
317
|
+
Source: `src/colors.ts:73:1`
|
|
318
|
+
Related symbols: `TabletopColorScheme`
|
|
319
|
+
|
|
98
320
|
</details>
|
package/dist/colors.d.ts
CHANGED
|
@@ -7,11 +7,15 @@ export interface TabletopColorScheme {
|
|
|
7
7
|
readonly mutedText: string;
|
|
8
8
|
readonly redSuitText: string;
|
|
9
9
|
readonly seatBorder: string;
|
|
10
|
+
readonly seatMutedText: string;
|
|
10
11
|
readonly seatSelectedBorder: string;
|
|
11
12
|
readonly seatSurface: string;
|
|
13
|
+
readonly seatText: string;
|
|
12
14
|
readonly tableBorder: string;
|
|
13
15
|
readonly tableFelt: string;
|
|
14
16
|
readonly tableInnerBorder: string;
|
|
17
|
+
readonly tableMutedText: string;
|
|
18
|
+
readonly tableText: string;
|
|
15
19
|
readonly tokenSurface: string;
|
|
16
20
|
readonly tokenText: string;
|
|
17
21
|
}
|
|
@@ -40,5 +44,18 @@ export interface TabletopColorThemeShape {
|
|
|
40
44
|
};
|
|
41
45
|
};
|
|
42
46
|
}
|
|
47
|
+
/***
|
|
48
|
+
* Creates the theme-derived color palette used by tabletop primitives.
|
|
49
|
+
*
|
|
50
|
+
* Use `createTabletopColorScheme` when custom components need to align with the
|
|
51
|
+
* same card, table, seat, token, and contrast-aware foreground colors as the
|
|
52
|
+
* built-in tabletop components.
|
|
53
|
+
*
|
|
54
|
+
* @readme
|
|
55
|
+
* @example Custom color scheme
|
|
56
|
+
* ```ts
|
|
57
|
+
* const colors = createTabletopColorScheme(theme, { tableFelt: '#065f46' });
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
43
60
|
export declare function createTabletopColorScheme(theme: TabletopColorThemeShape, overrides?: TabletopColorOverrides): TabletopColorScheme;
|
|
44
61
|
//# sourceMappingURL=colors.d.ts.map
|
package/dist/colors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"colors.d.ts","sourceRoot":"","sources":["../src/colors.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,MAAM,sBAAsB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;AAElE,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE;QACT,MAAM,EAAE;YACN,OAAO,EAAE;gBACP,IAAI,EAAE,MAAM,CAAC;gBACb,MAAM,EAAE,MAAM,CAAC;aAChB,CAAC;SACH,CAAC;QACF,OAAO,EAAE;YACP,OAAO,EAAE,MAAM,CAAC;YAChB,KAAK,EAAE,MAAM,CAAC;SACf,CAAC;QACF,OAAO,EAAE;YACP,MAAM,EAAE,MAAM,CAAC;YACf,OAAO,EAAE,MAAM,CAAC;YAChB,OAAO,EAAE,MAAM,CAAC;YAChB,YAAY,EAAE,MAAM,CAAC;SACtB,CAAC;QACF,OAAO,EAAE;YACP,IAAI,EAAE,MAAM,CAAC;YACb,MAAM,EAAE,MAAM,CAAC;SAChB,CAAC;KACH,CAAC;CACH;
|
|
1
|
+
{"version":3,"file":"colors.d.ts","sourceRoot":"","sources":["../src/colors.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,MAAM,sBAAsB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;AAElE,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE;QACT,MAAM,EAAE;YACN,OAAO,EAAE;gBACP,IAAI,EAAE,MAAM,CAAC;gBACb,MAAM,EAAE,MAAM,CAAC;aAChB,CAAC;SACH,CAAC;QACF,OAAO,EAAE;YACP,OAAO,EAAE,MAAM,CAAC;YAChB,KAAK,EAAE,MAAM,CAAC;SACf,CAAC;QACF,OAAO,EAAE;YACP,MAAM,EAAE,MAAM,CAAC;YACf,OAAO,EAAE,MAAM,CAAC;YAChB,OAAO,EAAE,MAAM,CAAC;YAChB,YAAY,EAAE,MAAM,CAAC;SACtB,CAAC;QACF,OAAO,EAAE;YACP,IAAI,EAAE,MAAM,CAAC;YACb,MAAM,EAAE,MAAM,CAAC;SAChB,CAAC;KACH,CAAC;CACH;AAYD;;;;;;;;;;;;GAYG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,uBAAuB,EAC9B,SAAS,GAAE,sBAA2B,GACrC,mBAAmB,CAgDrB"}
|
package/dist/colors.js
CHANGED
|
@@ -1,20 +1,128 @@
|
|
|
1
|
+
const DARK_TEXT_FALLBACK = '#111827';
|
|
2
|
+
const LIGHT_TEXT_FALLBACK = '#ffffff';
|
|
3
|
+
const MINIMUM_READABLE_CONTRAST = 4.5;
|
|
4
|
+
/***
|
|
5
|
+
* Creates the theme-derived color palette used by tabletop primitives.
|
|
6
|
+
*
|
|
7
|
+
* Use `createTabletopColorScheme` when custom components need to align with the
|
|
8
|
+
* same card, table, seat, token, and contrast-aware foreground colors as the
|
|
9
|
+
* built-in tabletop components.
|
|
10
|
+
*
|
|
11
|
+
* @readme
|
|
12
|
+
* @example Custom color scheme
|
|
13
|
+
* ```ts
|
|
14
|
+
* const colors = createTabletopColorScheme(theme, { tableFelt: '#065f46' });
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
1
17
|
export function createTabletopColorScheme(theme, overrides = {}) {
|
|
18
|
+
const cardSurface = overrides.cardSurface ?? theme.semantics.neutral.surface;
|
|
19
|
+
const seatSurface = overrides.seatSurface ?? theme.semantics.neutral.surface;
|
|
20
|
+
const tableFelt = overrides.tableFelt ?? theme.semantics.action.primary.softBg;
|
|
21
|
+
const tokenSurface = overrides.tokenSurface ?? theme.semantics.warning.softBg;
|
|
22
|
+
const cardText = overrides.cardText ??
|
|
23
|
+
resolveReadableTextColor(cardSurface, theme.semantics.content.default, LIGHT_TEXT_FALLBACK);
|
|
24
|
+
const seatText = overrides.seatText ??
|
|
25
|
+
resolveReadableTextColor(seatSurface, theme.semantics.content.default, LIGHT_TEXT_FALLBACK);
|
|
26
|
+
const tableText = overrides.tableText ??
|
|
27
|
+
resolveReadableTextColor(tableFelt, theme.semantics.content.default, LIGHT_TEXT_FALLBACK);
|
|
28
|
+
const tokenText = overrides.tokenText ??
|
|
29
|
+
resolveReadableTextColor(tokenSurface, theme.semantics.content.default, LIGHT_TEXT_FALLBACK);
|
|
2
30
|
return {
|
|
3
31
|
cardBack: overrides.cardBack ?? theme.semantics.warning.base,
|
|
4
32
|
cardBackBorder: overrides.cardBackBorder ?? theme.semantics.neutral.border,
|
|
5
33
|
cardBorder: overrides.cardBorder ?? theme.semantics.neutral.border,
|
|
6
|
-
cardSurface
|
|
7
|
-
cardText
|
|
8
|
-
mutedText: overrides.mutedText ??
|
|
9
|
-
|
|
34
|
+
cardSurface,
|
|
35
|
+
cardText,
|
|
36
|
+
mutedText: overrides.mutedText ??
|
|
37
|
+
resolveReadableTextColor(cardSurface, theme.semantics.content.muted, cardText),
|
|
38
|
+
redSuitText: overrides.redSuitText ??
|
|
39
|
+
resolveReadableTextColor(cardSurface, theme.semantics.warning.base, cardText),
|
|
10
40
|
seatBorder: overrides.seatBorder ?? theme.semantics.neutral.divider,
|
|
41
|
+
seatMutedText: overrides.seatMutedText ??
|
|
42
|
+
resolveReadableTextColor(seatSurface, theme.semantics.content.muted, seatText),
|
|
11
43
|
seatSelectedBorder: overrides.seatSelectedBorder ?? theme.semantics.action.primary.base,
|
|
12
|
-
seatSurface
|
|
44
|
+
seatSurface,
|
|
45
|
+
seatText,
|
|
13
46
|
tableBorder: overrides.tableBorder ?? theme.semantics.warning.base,
|
|
14
|
-
tableFelt
|
|
47
|
+
tableFelt,
|
|
15
48
|
tableInnerBorder: overrides.tableInnerBorder ?? theme.semantics.neutral.divider,
|
|
16
|
-
|
|
17
|
-
|
|
49
|
+
tableMutedText: overrides.tableMutedText ??
|
|
50
|
+
resolveReadableTextColor(tableFelt, theme.semantics.content.muted, tableText),
|
|
51
|
+
tableText,
|
|
52
|
+
tokenSurface,
|
|
53
|
+
tokenText,
|
|
18
54
|
};
|
|
19
55
|
}
|
|
56
|
+
function resolveReadableTextColor(background, preferred, fallback) {
|
|
57
|
+
const preferredContrast = getContrastRatio(background, preferred);
|
|
58
|
+
if (preferredContrast !== null && preferredContrast >= MINIMUM_READABLE_CONTRAST) {
|
|
59
|
+
return preferred;
|
|
60
|
+
}
|
|
61
|
+
const candidates = uniqueColors([preferred, fallback, LIGHT_TEXT_FALLBACK, DARK_TEXT_FALLBACK]);
|
|
62
|
+
const [readableCandidate] = candidates
|
|
63
|
+
.map((candidate) => ({ candidate, contrast: getContrastRatio(background, candidate) }))
|
|
64
|
+
.filter((entry) => entry.contrast !== null)
|
|
65
|
+
.sort((left, right) => right.contrast - left.contrast);
|
|
66
|
+
return readableCandidate?.candidate ?? preferred;
|
|
67
|
+
}
|
|
68
|
+
function uniqueColors(colors) {
|
|
69
|
+
return [...new Set(colors)];
|
|
70
|
+
}
|
|
71
|
+
function getContrastRatio(background, foreground) {
|
|
72
|
+
const backgroundColor = parseHexColor(background);
|
|
73
|
+
const foregroundColor = parseHexColor(foreground);
|
|
74
|
+
if (backgroundColor === null || foregroundColor === null)
|
|
75
|
+
return null;
|
|
76
|
+
const backgroundLuminance = getRelativeLuminance(backgroundColor);
|
|
77
|
+
const foregroundLuminance = getRelativeLuminance(foregroundColor);
|
|
78
|
+
const lighter = Math.max(backgroundLuminance, foregroundLuminance);
|
|
79
|
+
const darker = Math.min(backgroundLuminance, foregroundLuminance);
|
|
80
|
+
return (lighter + 0.05) / (darker + 0.05);
|
|
81
|
+
}
|
|
82
|
+
function parseHexColor(color) {
|
|
83
|
+
const value = color.trim();
|
|
84
|
+
const hex = value.startsWith('#') ? value.slice(1) : '';
|
|
85
|
+
if (!isSupportedHexLength(hex) || !isHexColorValue(hex))
|
|
86
|
+
return null;
|
|
87
|
+
if (hex.length === 3) {
|
|
88
|
+
const red = hex.slice(0, 1);
|
|
89
|
+
const green = hex.slice(1, 2);
|
|
90
|
+
const blue = hex.slice(2, 3);
|
|
91
|
+
return {
|
|
92
|
+
red: parseInt(red + red, 16),
|
|
93
|
+
green: parseInt(green + green, 16),
|
|
94
|
+
blue: parseInt(blue + blue, 16),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
red: parseInt(hex.slice(0, 2), 16),
|
|
99
|
+
green: parseInt(hex.slice(2, 4), 16),
|
|
100
|
+
blue: parseInt(hex.slice(4, 6), 16),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function isSupportedHexLength(hex) {
|
|
104
|
+
return hex.length === 3 || hex.length === 6 || hex.length === 8;
|
|
105
|
+
}
|
|
106
|
+
function isHexColorValue(hex) {
|
|
107
|
+
return [...hex].every((character) => isHexCharacter(character));
|
|
108
|
+
}
|
|
109
|
+
function isHexCharacter(character) {
|
|
110
|
+
const code = character.charCodeAt(0);
|
|
111
|
+
const isDigit = code >= 48 && code <= 57;
|
|
112
|
+
const isUpperHex = code >= 65 && code <= 70;
|
|
113
|
+
const isLowerHex = code >= 97 && code <= 102;
|
|
114
|
+
return isDigit || isUpperHex || isLowerHex;
|
|
115
|
+
}
|
|
116
|
+
function getRelativeLuminance(color) {
|
|
117
|
+
const red = normalizeColorChannel(color.red);
|
|
118
|
+
const green = normalizeColorChannel(color.green);
|
|
119
|
+
const blue = normalizeColorChannel(color.blue);
|
|
120
|
+
return 0.2126 * red + 0.7152 * green + 0.0722 * blue;
|
|
121
|
+
}
|
|
122
|
+
function normalizeColorChannel(value) {
|
|
123
|
+
const normalized = value / 255;
|
|
124
|
+
if (normalized <= 0.03928)
|
|
125
|
+
return normalized / 12.92;
|
|
126
|
+
return ((normalized + 0.055) / 1.055) ** 2.4;
|
|
127
|
+
}
|
|
20
128
|
//# sourceMappingURL=colors.js.map
|
package/dist/colors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"colors.js","sourceRoot":"","sources":["../src/colors.ts"],"names":[],"mappings":"AA6CA,MAAM,UAAU,yBAAyB,CACvC,KAA8B,EAC9B,YAAoC,EAAE;IAEtC,OAAO;QACL,QAAQ,EAAE,SAAS,CAAC,QAAQ,IAAI,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI;QAC5D,cAAc,EAAE,SAAS,CAAC,cAAc,IAAI,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM;QAC1E,UAAU,EAAE,SAAS,CAAC,UAAU,IAAI,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM;QAClE,WAAW,EAAE,SAAS,CAAC,WAAW,IAAI,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO;QACrE,QAAQ,EAAE,SAAS,CAAC,QAAQ,IAAI,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO;QAC/D,SAAS,EAAE,SAAS,CAAC,SAAS,IAAI,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK;QAC/D,WAAW,EAAE,SAAS,CAAC,WAAW,IAAI,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI;QAClE,UAAU,EAAE,SAAS,CAAC,UAAU,IAAI,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO;QACnE,kBAAkB,EAAE,SAAS,CAAC,kBAAkB,IAAI,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI;QACvF,WAAW,EAAE,SAAS,CAAC,WAAW,IAAI,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO;QACrE,WAAW,EAAE,SAAS,CAAC,WAAW,IAAI,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI;QAClE,SAAS,EAAE,SAAS,CAAC,SAAS,IAAI,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM;QACvE,gBAAgB,EAAE,SAAS,CAAC,gBAAgB,IAAI,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO;QAC/E,YAAY,EAAE,SAAS,CAAC,YAAY,IAAI,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM;QACtE,SAAS,EAAE,SAAS,CAAC,SAAS,IAAI,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO;KAClE,CAAC;AACJ,CAAC","sourcesContent":["export interface TabletopColorScheme {\n readonly cardBack: string;\n readonly cardBackBorder: string;\n readonly cardBorder: string;\n readonly cardSurface: string;\n readonly cardText: string;\n readonly mutedText: string;\n readonly redSuitText: string;\n readonly seatBorder: string;\n readonly seatSelectedBorder: string;\n readonly seatSurface: string;\n readonly tableBorder: string;\n readonly tableFelt: string;\n readonly tableInnerBorder: string;\n readonly tokenSurface: string;\n readonly tokenText: string;\n}\n\nexport type TabletopColorOverrides = Partial<TabletopColorScheme>;\n\nexport interface TabletopColorThemeShape {\n semantics: {\n action: {\n primary: {\n base: string;\n softBg: string;\n };\n };\n content: {\n default: string;\n muted: string;\n };\n neutral: {\n border: string;\n divider: string;\n surface: string;\n surfaceHover: string;\n };\n warning: {\n base: string;\n softBg: string;\n };\n };\n}\n\nexport function createTabletopColorScheme(\n theme: TabletopColorThemeShape,\n overrides: TabletopColorOverrides = {},\n): TabletopColorScheme {\n return {\n cardBack: overrides.cardBack ?? theme.semantics.warning.base,\n cardBackBorder: overrides.cardBackBorder ?? theme.semantics.neutral.border,\n cardBorder: overrides.cardBorder ?? theme.semantics.neutral.border,\n cardSurface: overrides.cardSurface ?? theme.semantics.neutral.surface,\n cardText: overrides.cardText ?? theme.semantics.content.default,\n mutedText: overrides.mutedText ?? theme.semantics.content.muted,\n redSuitText: overrides.redSuitText ?? theme.semantics.warning.base,\n seatBorder: overrides.seatBorder ?? theme.semantics.neutral.divider,\n seatSelectedBorder: overrides.seatSelectedBorder ?? theme.semantics.action.primary.base,\n seatSurface: overrides.seatSurface ?? theme.semantics.neutral.surface,\n tableBorder: overrides.tableBorder ?? theme.semantics.warning.base,\n tableFelt: overrides.tableFelt ?? theme.semantics.action.primary.softBg,\n tableInnerBorder: overrides.tableInnerBorder ?? theme.semantics.neutral.divider,\n tokenSurface: overrides.tokenSurface ?? theme.semantics.warning.softBg,\n tokenText: overrides.tokenText ?? theme.semantics.content.default,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"colors.js","sourceRoot":"","sources":["../src/colors.ts"],"names":[],"mappings":"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","sourcesContent":["export interface TabletopColorScheme {\n readonly cardBack: string;\n readonly cardBackBorder: string;\n readonly cardBorder: string;\n readonly cardSurface: string;\n readonly cardText: string;\n readonly mutedText: string;\n readonly redSuitText: string;\n readonly seatBorder: string;\n readonly seatMutedText: string;\n readonly seatSelectedBorder: string;\n readonly seatSurface: string;\n readonly seatText: string;\n readonly tableBorder: string;\n readonly tableFelt: string;\n readonly tableInnerBorder: string;\n readonly tableMutedText: string;\n readonly tableText: string;\n readonly tokenSurface: string;\n readonly tokenText: string;\n}\n\nexport type TabletopColorOverrides = Partial<TabletopColorScheme>;\n\nexport interface TabletopColorThemeShape {\n semantics: {\n action: {\n primary: {\n base: string;\n softBg: string;\n };\n };\n content: {\n default: string;\n muted: string;\n };\n neutral: {\n border: string;\n divider: string;\n surface: string;\n surfaceHover: string;\n };\n warning: {\n base: string;\n softBg: string;\n };\n };\n}\n\ninterface RgbColor {\n readonly red: number;\n readonly green: number;\n readonly blue: number;\n}\n\nconst DARK_TEXT_FALLBACK = '#111827';\nconst LIGHT_TEXT_FALLBACK = '#ffffff';\nconst MINIMUM_READABLE_CONTRAST = 4.5;\n\n/***\n * Creates the theme-derived color palette used by tabletop primitives.\n *\n * Use `createTabletopColorScheme` when custom components need to align with the\n * same card, table, seat, token, and contrast-aware foreground colors as the\n * built-in tabletop components.\n *\n * @readme\n * @example Custom color scheme\n * ```ts\n * const colors = createTabletopColorScheme(theme, { tableFelt: '#065f46' });\n * ```\n */\nexport function createTabletopColorScheme(\n theme: TabletopColorThemeShape,\n overrides: TabletopColorOverrides = {},\n): TabletopColorScheme {\n const cardSurface = overrides.cardSurface ?? theme.semantics.neutral.surface;\n const seatSurface = overrides.seatSurface ?? theme.semantics.neutral.surface;\n const tableFelt = overrides.tableFelt ?? theme.semantics.action.primary.softBg;\n const tokenSurface = overrides.tokenSurface ?? theme.semantics.warning.softBg;\n\n const cardText =\n overrides.cardText ??\n resolveReadableTextColor(cardSurface, theme.semantics.content.default, LIGHT_TEXT_FALLBACK);\n const seatText =\n overrides.seatText ??\n resolveReadableTextColor(seatSurface, theme.semantics.content.default, LIGHT_TEXT_FALLBACK);\n const tableText =\n overrides.tableText ??\n resolveReadableTextColor(tableFelt, theme.semantics.content.default, LIGHT_TEXT_FALLBACK);\n const tokenText =\n overrides.tokenText ??\n resolveReadableTextColor(tokenSurface, theme.semantics.content.default, LIGHT_TEXT_FALLBACK);\n\n return {\n cardBack: overrides.cardBack ?? theme.semantics.warning.base,\n cardBackBorder: overrides.cardBackBorder ?? theme.semantics.neutral.border,\n cardBorder: overrides.cardBorder ?? theme.semantics.neutral.border,\n cardSurface,\n cardText,\n mutedText:\n overrides.mutedText ??\n resolveReadableTextColor(cardSurface, theme.semantics.content.muted, cardText),\n redSuitText:\n overrides.redSuitText ??\n resolveReadableTextColor(cardSurface, theme.semantics.warning.base, cardText),\n seatBorder: overrides.seatBorder ?? theme.semantics.neutral.divider,\n seatMutedText:\n overrides.seatMutedText ??\n resolveReadableTextColor(seatSurface, theme.semantics.content.muted, seatText),\n seatSelectedBorder: overrides.seatSelectedBorder ?? theme.semantics.action.primary.base,\n seatSurface,\n seatText,\n tableBorder: overrides.tableBorder ?? theme.semantics.warning.base,\n tableFelt,\n tableInnerBorder: overrides.tableInnerBorder ?? theme.semantics.neutral.divider,\n tableMutedText:\n overrides.tableMutedText ??\n resolveReadableTextColor(tableFelt, theme.semantics.content.muted, tableText),\n tableText,\n tokenSurface,\n tokenText,\n };\n}\n\nfunction resolveReadableTextColor(background: string, preferred: string, fallback: string): string {\n const preferredContrast = getContrastRatio(background, preferred);\n if (preferredContrast !== null && preferredContrast >= MINIMUM_READABLE_CONTRAST) {\n return preferred;\n }\n\n const candidates = uniqueColors([preferred, fallback, LIGHT_TEXT_FALLBACK, DARK_TEXT_FALLBACK]);\n const [readableCandidate] = candidates\n .map((candidate) => ({ candidate, contrast: getContrastRatio(background, candidate) }))\n .filter(\n (entry): entry is { readonly candidate: string; readonly contrast: number } =>\n entry.contrast !== null,\n )\n .sort((left, right) => right.contrast - left.contrast);\n\n return readableCandidate?.candidate ?? preferred;\n}\n\nfunction uniqueColors(colors: readonly string[]): string[] {\n return [...new Set(colors)];\n}\n\nfunction getContrastRatio(background: string, foreground: string): number | null {\n const backgroundColor = parseHexColor(background);\n const foregroundColor = parseHexColor(foreground);\n\n if (backgroundColor === null || foregroundColor === null) return null;\n\n const backgroundLuminance = getRelativeLuminance(backgroundColor);\n const foregroundLuminance = getRelativeLuminance(foregroundColor);\n const lighter = Math.max(backgroundLuminance, foregroundLuminance);\n const darker = Math.min(backgroundLuminance, foregroundLuminance);\n\n return (lighter + 0.05) / (darker + 0.05);\n}\n\nfunction parseHexColor(color: string): RgbColor | null {\n const value = color.trim();\n const hex = value.startsWith('#') ? value.slice(1) : '';\n if (!isSupportedHexLength(hex) || !isHexColorValue(hex)) return null;\n\n if (hex.length === 3) {\n const red = hex.slice(0, 1);\n const green = hex.slice(1, 2);\n const blue = hex.slice(2, 3);\n\n return {\n red: parseInt(red + red, 16),\n green: parseInt(green + green, 16),\n blue: parseInt(blue + blue, 16),\n };\n }\n\n return {\n red: parseInt(hex.slice(0, 2), 16),\n green: parseInt(hex.slice(2, 4), 16),\n blue: parseInt(hex.slice(4, 6), 16),\n };\n}\n\nfunction isSupportedHexLength(hex: string): boolean {\n return hex.length === 3 || hex.length === 6 || hex.length === 8;\n}\n\nfunction isHexColorValue(hex: string): boolean {\n return [...hex].every((character) => isHexCharacter(character));\n}\n\nfunction isHexCharacter(character: string): boolean {\n const code = character.charCodeAt(0);\n const isDigit = code >= 48 && code <= 57;\n const isUpperHex = code >= 65 && code <= 70;\n const isLowerHex = code >= 97 && code <= 102;\n\n return isDigit || isUpperHex || isLowerHex;\n}\n\nfunction getRelativeLuminance(color: RgbColor): number {\n const red = normalizeColorChannel(color.red);\n const green = normalizeColorChannel(color.green);\n const blue = normalizeColorChannel(color.blue);\n\n return 0.2126 * red + 0.7152 * green + 0.0722 * blue;\n}\n\nfunction normalizeColorChannel(value: number): number {\n const normalized = value / 255;\n if (normalized <= 0.03928) return normalized / 12.92;\n return ((normalized + 0.055) / 1.055) ** 2.4;\n}\n"]}
|
|
@@ -1,4 +1,16 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { CardBackProps } from './types';
|
|
3
|
+
/***
|
|
4
|
+
* Face-down playing-card primitive for hidden cards and decks.
|
|
5
|
+
*
|
|
6
|
+
* Use `CardBack` when a card should be represented visually without exposing its
|
|
7
|
+
* rank or suit. The component keeps a generic accessible label for hidden cards.
|
|
8
|
+
*
|
|
9
|
+
* @readme
|
|
10
|
+
* @example Hidden cards
|
|
11
|
+
* ```tsx
|
|
12
|
+
* <CardBack size="small" />
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
3
15
|
export declare function CardBack({ size, muted, accessibilityLabel, colorScheme, testID, }: CardBackProps): React.JSX.Element;
|
|
4
16
|
//# sourceMappingURL=CardBack.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CardBack.d.ts","sourceRoot":"","sources":["../../../src/components/card-back/CardBack.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAM1B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE7C,wBAAgB,QAAQ,CAAC,EACvB,IAAe,EACf,KAAa,EACb,kBAAkB,EAClB,WAAW,EACX,MAAM,GACP,EAAE,aAAa,qBAoCf"}
|
|
1
|
+
{"version":3,"file":"CardBack.d.ts","sourceRoot":"","sources":["../../../src/components/card-back/CardBack.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAM1B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE7C;;;;;;;;;;;GAWG;AACH,wBAAgB,QAAQ,CAAC,EACvB,IAAe,EACf,KAAa,EACb,kBAAkB,EAClB,WAAW,EACX,MAAM,GACP,EAAE,aAAa,qBAoCf"}
|
|
@@ -4,6 +4,18 @@ import { StyleSheet, View } from 'react-native';
|
|
|
4
4
|
import { createHiddenCardLabel } from '../../cardLabel';
|
|
5
5
|
import { getTabletopCardDimensions } from '../../cardSizing';
|
|
6
6
|
import { createTabletopColorScheme } from '../../colors';
|
|
7
|
+
/***
|
|
8
|
+
* Face-down playing-card primitive for hidden cards and decks.
|
|
9
|
+
*
|
|
10
|
+
* Use `CardBack` when a card should be represented visually without exposing its
|
|
11
|
+
* rank or suit. The component keeps a generic accessible label for hidden cards.
|
|
12
|
+
*
|
|
13
|
+
* @readme
|
|
14
|
+
* @example Hidden cards
|
|
15
|
+
* ```tsx
|
|
16
|
+
* <CardBack size="small" />
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
7
19
|
export function CardBack({ size = 'medium', muted = false, accessibilityLabel, colorScheme, testID, }) {
|
|
8
20
|
const { theme } = useZoraTheme();
|
|
9
21
|
const colors = React.useMemo(() => createTabletopColorScheme(theme, colorScheme), [colorScheme, theme]);
|