@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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CardBack.js","sourceRoot":"","sources":["../../../src/components/card-back/CardBack.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEhD,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AAGzD,MAAM,UAAU,QAAQ,CAAC,EACvB,IAAI,GAAG,QAAQ,EACf,KAAK,GAAG,KAAK,EACb,kBAAkB,EAClB,WAAW,EACX,MAAM,GACQ;IACd,MAAM,EAAE,KAAK,EAAE,GAAG,YAAY,EAAE,CAAC;IACjC,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAC1B,GAAG,EAAE,CAAC,yBAAyB,CAAC,KAAK,EAAE,WAAW,CAAC,EACnD,CAAC,WAAW,EAAE,KAAK,CAAC,CACrB,CAAC;IACF,MAAM,UAAU,GAAG,yBAAyB,CAAC,IAAI,CAAC,CAAC;IAEnD,OAAO,CACL,CAAC,IAAI,CACH,kBAAkB,CAAC,CAAC,kBAAkB,IAAI,qBAAqB,EAAE,CAAC,CAClE,iBAAiB,CAAC,OAAO,CACzB,KAAK,CAAC,CAAC;YACL,MAAM,CAAC,IAAI;YACX;gBACE,eAAe,EAAE,MAAM,CAAC,QAAQ;gBAChC,WAAW,EAAE,MAAM,CAAC,cAAc;gBAClC,YAAY,EAAE,UAAU,CAAC,MAAM;gBAC/B,MAAM,EAAE,UAAU,CAAC,MAAM;gBACzB,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBACzB,KAAK,EAAE,UAAU,CAAC,KAAK;aACxB;SACF,CAAC,CACF,MAAM,CAAC,CAAC,MAAM,CAAC,CAEf;MAAA,CAAC,IAAI,CACH,KAAK,CAAC,CAAC;YACL,MAAM,CAAC,KAAK;YACZ;gBACE,WAAW,EAAE,MAAM,CAAC,cAAc;gBAClC,YAAY,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC;aACjD;SACF,CAAC,EAEN;IAAA,EAAE,IAAI,CAAC,CACR,CAAC;AACJ,CAAC;AAED,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC;IAC/B,IAAI,EAAE;QACJ,UAAU,EAAE,QAAQ;QACpB,WAAW,EAAE,CAAC;QACd,cAAc,EAAE,QAAQ;KACzB;IACD,KAAK,EAAE;QACL,WAAW,EAAE,CAAC;QACd,MAAM,EAAE,KAAK;QACb,OAAO,EAAE,IAAI;QACb,KAAK,EAAE,KAAK;KACb;CACF,CAAC,CAAC","sourcesContent":["import { useZoraTheme } from '@ankhorage/zora';\nimport React from 'react';\nimport { StyleSheet, View } from 'react-native';\n\nimport { createHiddenCardLabel } from '../../cardLabel';\nimport { getTabletopCardDimensions } from '../../cardSizing';\nimport { createTabletopColorScheme } from '../../colors';\nimport type { CardBackProps } from './types';\n\nexport function CardBack({\n size = 'medium',\n muted = false,\n accessibilityLabel,\n colorScheme,\n testID,\n}: CardBackProps) {\n const { theme } = useZoraTheme();\n const colors = React.useMemo(\n () => createTabletopColorScheme(theme, colorScheme),\n [colorScheme, theme],\n );\n const dimensions = getTabletopCardDimensions(size);\n\n return (\n <View\n accessibilityLabel={accessibilityLabel ?? createHiddenCardLabel()}\n accessibilityRole=\"image\"\n style={[\n styles.card,\n {\n backgroundColor: colors.cardBack,\n borderColor: colors.cardBackBorder,\n borderRadius: dimensions.radius,\n height: dimensions.height,\n opacity: muted ? 0.48 : 1,\n width: dimensions.width,\n },\n ]}\n testID={testID}\n >\n <View\n style={[\n styles.inner,\n {\n borderColor: colors.cardBackBorder,\n borderRadius: Math.max(2, dimensions.radius - 3),\n },\n ]}\n />\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n card: {\n alignItems: 'center',\n borderWidth: 1,\n justifyContent: 'center',\n },\n inner: {\n borderWidth: 1,\n height: '68%',\n opacity: 0.48,\n width: '68%',\n },\n});\n"]}
|
|
1
|
+
{"version":3,"file":"CardBack.js","sourceRoot":"","sources":["../../../src/components/card-back/CardBack.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEhD,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AAGzD;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,QAAQ,CAAC,EACvB,IAAI,GAAG,QAAQ,EACf,KAAK,GAAG,KAAK,EACb,kBAAkB,EAClB,WAAW,EACX,MAAM,GACQ;IACd,MAAM,EAAE,KAAK,EAAE,GAAG,YAAY,EAAE,CAAC;IACjC,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAC1B,GAAG,EAAE,CAAC,yBAAyB,CAAC,KAAK,EAAE,WAAW,CAAC,EACnD,CAAC,WAAW,EAAE,KAAK,CAAC,CACrB,CAAC;IACF,MAAM,UAAU,GAAG,yBAAyB,CAAC,IAAI,CAAC,CAAC;IAEnD,OAAO,CACL,CAAC,IAAI,CACH,kBAAkB,CAAC,CAAC,kBAAkB,IAAI,qBAAqB,EAAE,CAAC,CAClE,iBAAiB,CAAC,OAAO,CACzB,KAAK,CAAC,CAAC;YACL,MAAM,CAAC,IAAI;YACX;gBACE,eAAe,EAAE,MAAM,CAAC,QAAQ;gBAChC,WAAW,EAAE,MAAM,CAAC,cAAc;gBAClC,YAAY,EAAE,UAAU,CAAC,MAAM;gBAC/B,MAAM,EAAE,UAAU,CAAC,MAAM;gBACzB,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBACzB,KAAK,EAAE,UAAU,CAAC,KAAK;aACxB;SACF,CAAC,CACF,MAAM,CAAC,CAAC,MAAM,CAAC,CAEf;MAAA,CAAC,IAAI,CACH,KAAK,CAAC,CAAC;YACL,MAAM,CAAC,KAAK;YACZ;gBACE,WAAW,EAAE,MAAM,CAAC,cAAc;gBAClC,YAAY,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC;aACjD;SACF,CAAC,EAEN;IAAA,EAAE,IAAI,CAAC,CACR,CAAC;AACJ,CAAC;AAED,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC;IAC/B,IAAI,EAAE;QACJ,UAAU,EAAE,QAAQ;QACpB,WAAW,EAAE,CAAC;QACd,cAAc,EAAE,QAAQ;KACzB;IACD,KAAK,EAAE;QACL,WAAW,EAAE,CAAC;QACd,MAAM,EAAE,KAAK;QACb,OAAO,EAAE,IAAI;QACb,KAAK,EAAE,KAAK;KACb;CACF,CAAC,CAAC","sourcesContent":["import { useZoraTheme } from '@ankhorage/zora';\nimport React from 'react';\nimport { StyleSheet, View } from 'react-native';\n\nimport { createHiddenCardLabel } from '../../cardLabel';\nimport { getTabletopCardDimensions } from '../../cardSizing';\nimport { createTabletopColorScheme } from '../../colors';\nimport type { CardBackProps } from './types';\n\n/***\n * Face-down playing-card primitive for hidden cards and decks.\n *\n * Use `CardBack` when a card should be represented visually without exposing its\n * rank or suit. The component keeps a generic accessible label for hidden cards.\n *\n * @readme\n * @example Hidden cards\n * ```tsx\n * <CardBack size=\"small\" />\n * ```\n */\nexport function CardBack({\n size = 'medium',\n muted = false,\n accessibilityLabel,\n colorScheme,\n testID,\n}: CardBackProps) {\n const { theme } = useZoraTheme();\n const colors = React.useMemo(\n () => createTabletopColorScheme(theme, colorScheme),\n [colorScheme, theme],\n );\n const dimensions = getTabletopCardDimensions(size);\n\n return (\n <View\n accessibilityLabel={accessibilityLabel ?? createHiddenCardLabel()}\n accessibilityRole=\"image\"\n style={[\n styles.card,\n {\n backgroundColor: colors.cardBack,\n borderColor: colors.cardBackBorder,\n borderRadius: dimensions.radius,\n height: dimensions.height,\n opacity: muted ? 0.48 : 1,\n width: dimensions.width,\n },\n ]}\n testID={testID}\n >\n <View\n style={[\n styles.inner,\n {\n borderColor: colors.cardBackBorder,\n borderRadius: Math.max(2, dimensions.radius - 3),\n },\n ]}\n />\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n card: {\n alignItems: 'center',\n borderWidth: 1,\n justifyContent: 'center',\n },\n inner: {\n borderWidth: 1,\n height: '68%',\n opacity: 0.48,\n width: '68%',\n },\n});\n"]}
|
|
@@ -1,4 +1,16 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { CardHandProps } from './types';
|
|
3
|
+
/***
|
|
4
|
+
* Compact row of visible and face-down playing cards.
|
|
5
|
+
*
|
|
6
|
+
* Use `CardHand` when a seat, pile, or custom layout needs to show multiple cards
|
|
7
|
+
* with consistent spacing, sizing, and muted state handling.
|
|
8
|
+
*
|
|
9
|
+
* @readme
|
|
10
|
+
* @example Mixed hand
|
|
11
|
+
* ```tsx
|
|
12
|
+
* <CardHand cards={[{ rank: 'Q', suit: 'hearts' }]} faceDownCards={1} />
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
3
15
|
export declare function CardHand({ cards, faceDownCards, size, muted, colorScheme, accessibilityLabel, testID, }: CardHandProps): React.JSX.Element;
|
|
4
16
|
//# sourceMappingURL=CardHand.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CardHand.d.ts","sourceRoot":"","sources":["../../../src/components/card-hand/CardHand.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAK1B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAM7C,wBAAgB,QAAQ,CAAC,EACvB,KAAU,EACV,aAAiB,EACjB,IAAe,EACf,KAAa,EACb,WAAW,EACX,kBAAkB,EAClB,MAAM,GACP,EAAE,aAAa,qBA0Bf"}
|
|
1
|
+
{"version":3,"file":"CardHand.d.ts","sourceRoot":"","sources":["../../../src/components/card-hand/CardHand.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAK1B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAM7C;;;;;;;;;;;GAWG;AACH,wBAAgB,QAAQ,CAAC,EACvB,KAAU,EACV,aAAiB,EACjB,IAAe,EACf,KAAa,EACb,WAAW,EACX,kBAAkB,EAClB,MAAM,GACP,EAAE,aAAa,qBA0Bf"}
|
|
@@ -5,6 +5,18 @@ import { PlayingCard } from '../playing-card';
|
|
|
5
5
|
function createFaceDownCards(count) {
|
|
6
6
|
return Array.from({ length: Math.max(0, count) }, (_, index) => index);
|
|
7
7
|
}
|
|
8
|
+
/***
|
|
9
|
+
* Compact row of visible and face-down playing cards.
|
|
10
|
+
*
|
|
11
|
+
* Use `CardHand` when a seat, pile, or custom layout needs to show multiple cards
|
|
12
|
+
* with consistent spacing, sizing, and muted state handling.
|
|
13
|
+
*
|
|
14
|
+
* @readme
|
|
15
|
+
* @example Mixed hand
|
|
16
|
+
* ```tsx
|
|
17
|
+
* <CardHand cards={[{ rank: 'Q', suit: 'hearts' }]} faceDownCards={1} />
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
8
20
|
export function CardHand({ cards = [], faceDownCards = 0, size = 'medium', muted = false, colorScheme, accessibilityLabel, testID, }) {
|
|
9
21
|
const hiddenCards = createFaceDownCards(faceDownCards);
|
|
10
22
|
return (<View accessibilityLabel={accessibilityLabel} style={styles.hand} testID={testID}>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CardHand.js","sourceRoot":"","sources":["../../../src/components/card-hand/CardHand.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEhD,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAG9C,SAAS,mBAAmB,CAAC,KAAa;IACxC,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC;AACzE,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,EACvB,KAAK,GAAG,EAAE,EACV,aAAa,GAAG,CAAC,EACjB,IAAI,GAAG,QAAQ,EACf,KAAK,GAAG,KAAK,EACb,WAAW,EACX,kBAAkB,EAClB,MAAM,GACQ;IACd,MAAM,WAAW,GAAG,mBAAmB,CAAC,aAAa,CAAC,CAAC;IAEvD,OAAO,CACL,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,kBAAkB,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAC/E;MAAA,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAC1B,CAAC,WAAW,CACV,IAAI,CAAC,CAAC,IAAI,CAAC,CACX,WAAW,CAAC,CAAC,WAAW,CAAC,CACzB,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI,KAAK,EAAE,CAAC,CAC1C,KAAK,CAAC,CAAC,KAAK,CAAC,CACb,IAAI,CAAC,CAAC,IAAI,CAAC,CACX,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,SAAS,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,EACvD,CACH,CAAC,CACF;MAAA,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAC1B,CAAC,QAAQ,CACP,WAAW,CAAC,CAAC,WAAW,CAAC,CACzB,GAAG,CAAC,CAAC,UAAU,KAAK,EAAE,CAAC,CACvB,KAAK,CAAC,CAAC,KAAK,CAAC,CACb,IAAI,CAAC,CAAC,IAAI,CAAC,CACX,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,WAAW,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,EACzD,CACH,CAAC,CACJ;IAAA,EAAE,IAAI,CAAC,CACR,CAAC;AACJ,CAAC;AAED,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC;IAC/B,IAAI,EAAE;QACJ,UAAU,EAAE,QAAQ;QACpB,aAAa,EAAE,KAAK;QACpB,GAAG,EAAE,CAAC;QACN,cAAc,EAAE,QAAQ;KACzB;CACF,CAAC,CAAC","sourcesContent":["import React from 'react';\nimport { StyleSheet, View } from 'react-native';\n\nimport { CardBack } from '../card-back';\nimport { PlayingCard } from '../playing-card';\nimport type { CardHandProps } from './types';\n\nfunction createFaceDownCards(count: number): readonly number[] {\n return Array.from({ length: Math.max(0, count) }, (_, index) => index);\n}\n\nexport function CardHand({\n cards = [],\n faceDownCards = 0,\n size = 'medium',\n muted = false,\n colorScheme,\n accessibilityLabel,\n testID,\n}: CardHandProps) {\n const hiddenCards = createFaceDownCards(faceDownCards);\n\n return (\n <View accessibilityLabel={accessibilityLabel} style={styles.hand} testID={testID}>\n {cards.map((card, index) => (\n <PlayingCard\n card={card}\n colorScheme={colorScheme}\n key={`${card.rank}-${card.suit}-${index}`}\n muted={muted}\n size={size}\n testID={testID ? `${testID}-card-${index}` : undefined}\n />\n ))}\n {hiddenCards.map((index) => (\n <CardBack\n colorScheme={colorScheme}\n key={`hidden-${index}`}\n muted={muted}\n size={size}\n testID={testID ? `${testID}-hidden-${index}` : undefined}\n />\n ))}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n hand: {\n alignItems: 'center',\n flexDirection: 'row',\n gap: 4,\n justifyContent: 'center',\n },\n});\n"]}
|
|
1
|
+
{"version":3,"file":"CardHand.js","sourceRoot":"","sources":["../../../src/components/card-hand/CardHand.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEhD,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAG9C,SAAS,mBAAmB,CAAC,KAAa;IACxC,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC;AACzE,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,QAAQ,CAAC,EACvB,KAAK,GAAG,EAAE,EACV,aAAa,GAAG,CAAC,EACjB,IAAI,GAAG,QAAQ,EACf,KAAK,GAAG,KAAK,EACb,WAAW,EACX,kBAAkB,EAClB,MAAM,GACQ;IACd,MAAM,WAAW,GAAG,mBAAmB,CAAC,aAAa,CAAC,CAAC;IAEvD,OAAO,CACL,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,kBAAkB,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAC/E;MAAA,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAC1B,CAAC,WAAW,CACV,IAAI,CAAC,CAAC,IAAI,CAAC,CACX,WAAW,CAAC,CAAC,WAAW,CAAC,CACzB,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI,KAAK,EAAE,CAAC,CAC1C,KAAK,CAAC,CAAC,KAAK,CAAC,CACb,IAAI,CAAC,CAAC,IAAI,CAAC,CACX,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,SAAS,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,EACvD,CACH,CAAC,CACF;MAAA,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAC1B,CAAC,QAAQ,CACP,WAAW,CAAC,CAAC,WAAW,CAAC,CACzB,GAAG,CAAC,CAAC,UAAU,KAAK,EAAE,CAAC,CACvB,KAAK,CAAC,CAAC,KAAK,CAAC,CACb,IAAI,CAAC,CAAC,IAAI,CAAC,CACX,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,WAAW,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,EACzD,CACH,CAAC,CACJ;IAAA,EAAE,IAAI,CAAC,CACR,CAAC;AACJ,CAAC;AAED,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC;IAC/B,IAAI,EAAE;QACJ,UAAU,EAAE,QAAQ;QACpB,aAAa,EAAE,KAAK;QACpB,GAAG,EAAE,CAAC;QACN,cAAc,EAAE,QAAQ;KACzB;CACF,CAAC,CAAC","sourcesContent":["import React from 'react';\nimport { StyleSheet, View } from 'react-native';\n\nimport { CardBack } from '../card-back';\nimport { PlayingCard } from '../playing-card';\nimport type { CardHandProps } from './types';\n\nfunction createFaceDownCards(count: number): readonly number[] {\n return Array.from({ length: Math.max(0, count) }, (_, index) => index);\n}\n\n/***\n * Compact row of visible and face-down playing cards.\n *\n * Use `CardHand` when a seat, pile, or custom layout needs to show multiple cards\n * with consistent spacing, sizing, and muted state handling.\n *\n * @readme\n * @example Mixed hand\n * ```tsx\n * <CardHand cards={[{ rank: 'Q', suit: 'hearts' }]} faceDownCards={1} />\n * ```\n */\nexport function CardHand({\n cards = [],\n faceDownCards = 0,\n size = 'medium',\n muted = false,\n colorScheme,\n accessibilityLabel,\n testID,\n}: CardHandProps) {\n const hiddenCards = createFaceDownCards(faceDownCards);\n\n return (\n <View accessibilityLabel={accessibilityLabel} style={styles.hand} testID={testID}>\n {cards.map((card, index) => (\n <PlayingCard\n card={card}\n colorScheme={colorScheme}\n key={`${card.rank}-${card.suit}-${index}`}\n muted={muted}\n size={size}\n testID={testID ? `${testID}-card-${index}` : undefined}\n />\n ))}\n {hiddenCards.map((index) => (\n <CardBack\n colorScheme={colorScheme}\n key={`hidden-${index}`}\n muted={muted}\n size={size}\n testID={testID ? `${testID}-hidden-${index}` : undefined}\n />\n ))}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n hand: {\n alignItems: 'center',\n flexDirection: 'row',\n gap: 4,\n justifyContent: 'center',\n },\n});\n"]}
|
|
@@ -1,4 +1,17 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { PlayingCardProps } from './types';
|
|
3
|
+
/***
|
|
4
|
+
* Theme-aware face-up playing card primitive.
|
|
5
|
+
*
|
|
6
|
+
* Use `PlayingCard` for visible card values in hands, shared table cards, piles,
|
|
7
|
+
* or custom tabletop layouts. The component renders rank and suit text and exposes
|
|
8
|
+
* an accessible card label by default.
|
|
9
|
+
*
|
|
10
|
+
* @readme
|
|
11
|
+
* @example Face-up card
|
|
12
|
+
* ```tsx
|
|
13
|
+
* <PlayingCard card={{ rank: 'A', suit: 'spades' }} selected />
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
3
16
|
export declare function PlayingCard({ card, size, selected, muted, accessibilityLabel, colorScheme, testID, }: PlayingCardProps): React.JSX.Element;
|
|
4
17
|
//# sourceMappingURL=PlayingCard.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlayingCard.d.ts","sourceRoot":"","sources":["../../../src/components/playing-card/PlayingCard.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAO1B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAahD,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,IAAe,EACf,QAAgB,EAChB,KAAa,EACb,kBAAkB,EAClB,WAAW,EACX,MAAM,GACP,EAAE,gBAAgB,qBAsDlB"}
|
|
1
|
+
{"version":3,"file":"PlayingCard.d.ts","sourceRoot":"","sources":["../../../src/components/playing-card/PlayingCard.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAO1B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAahD;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,IAAe,EACf,QAAgB,EAChB,KAAa,EACb,kBAAkB,EAClB,WAAW,EACX,MAAM,GACP,EAAE,gBAAgB,qBAsDlB"}
|
|
@@ -13,6 +13,19 @@ const suitMarks = {
|
|
|
13
13
|
function isRedSuit(suit) {
|
|
14
14
|
return suit === 'diamonds' || suit === 'hearts';
|
|
15
15
|
}
|
|
16
|
+
/***
|
|
17
|
+
* Theme-aware face-up playing card primitive.
|
|
18
|
+
*
|
|
19
|
+
* Use `PlayingCard` for visible card values in hands, shared table cards, piles,
|
|
20
|
+
* or custom tabletop layouts. The component renders rank and suit text and exposes
|
|
21
|
+
* an accessible card label by default.
|
|
22
|
+
*
|
|
23
|
+
* @readme
|
|
24
|
+
* @example Face-up card
|
|
25
|
+
* ```tsx
|
|
26
|
+
* <PlayingCard card={{ rank: 'A', suit: 'spades' }} selected />
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
16
29
|
export function PlayingCard({ card, size = 'medium', selected = false, muted = false, accessibilityLabel, colorScheme, testID, }) {
|
|
17
30
|
const { theme } = useZoraTheme();
|
|
18
31
|
const colors = React.useMemo(() => createTabletopColorScheme(theme, colorScheme), [colorScheme, theme]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlayingCard.js","sourceRoot":"","sources":["../../../src/components/playing-card/PlayingCard.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useZoraTheme } from '@ankhorage/zora';\nimport React from 'react';\nimport { StyleSheet, Text, View } from 'react-native';\n\nimport { getPlayingCardLabel } from '../../cardLabel';\nimport { getTabletopCardDimensions } from '../../cardSizing';\nimport { createTabletopColorScheme } from '../../colors';\nimport type { PlayingCardSuit } from '../../types';\nimport type { PlayingCardProps } from './types';\n\nconst suitMarks: Readonly<Record<PlayingCardSuit, string>> = {\n clubs: 'C',\n diamonds: 'D',\n hearts: 'H',\n spades: 'S',\n};\n\nfunction isRedSuit(suit: PlayingCardSuit): boolean {\n return suit === 'diamonds' || suit === 'hearts';\n}\n\nexport function PlayingCard({\n card,\n size = 'medium',\n selected = false,\n muted = false,\n accessibilityLabel,\n colorScheme,\n testID,\n}: PlayingCardProps) {\n const { theme } = useZoraTheme();\n const colors = React.useMemo(\n () => createTabletopColorScheme(theme, colorScheme),\n [colorScheme, theme],\n );\n const dimensions = getTabletopCardDimensions(size);\n const suitColor = isRedSuit(card.suit) ? colors.redSuitText : colors.cardText;\n\n return (\n <View\n accessibilityLabel={accessibilityLabel ?? getPlayingCardLabel(card)}\n accessibilityRole=\"image\"\n style={[\n styles.card,\n {\n backgroundColor: colors.cardSurface,\n borderColor: selected ? colors.seatSelectedBorder : colors.cardBorder,\n borderRadius: dimensions.radius,\n height: dimensions.height,\n opacity: muted ? 0.48 : 1,\n width: dimensions.width,\n },\n ]}\n testID={testID}\n >\n <Text\n selectable={false}\n style={[\n styles.rank,\n {\n color: suitColor,\n fontSize: dimensions.rankFontSize,\n lineHeight: dimensions.rankFontSize + 4,\n },\n ]}\n >\n {card.rank}\n </Text>\n <Text\n selectable={false}\n style={[\n styles.suit,\n {\n color: suitColor,\n fontSize: dimensions.suitFontSize,\n lineHeight: dimensions.suitFontSize + 3,\n },\n ]}\n >\n {suitMarks[card.suit]}\n </Text>\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n card: {\n alignItems: 'center',\n borderWidth: 1,\n justifyContent: 'center',\n },\n rank: {\n fontWeight: '800',\n },\n suit: {\n fontWeight: '700',\n marginTop: -2,\n },\n});\n"]}
|
|
1
|
+
{"version":3,"file":"PlayingCard.js","sourceRoot":"","sources":["../../../src/components/playing-card/PlayingCard.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useZoraTheme } from '@ankhorage/zora';\nimport React from 'react';\nimport { StyleSheet, Text, View } from 'react-native';\n\nimport { getPlayingCardLabel } from '../../cardLabel';\nimport { getTabletopCardDimensions } from '../../cardSizing';\nimport { createTabletopColorScheme } from '../../colors';\nimport type { PlayingCardSuit } from '../../types';\nimport type { PlayingCardProps } from './types';\n\nconst suitMarks: Readonly<Record<PlayingCardSuit, string>> = {\n clubs: 'C',\n diamonds: 'D',\n hearts: 'H',\n spades: 'S',\n};\n\nfunction isRedSuit(suit: PlayingCardSuit): boolean {\n return suit === 'diamonds' || suit === 'hearts';\n}\n\n/***\n * Theme-aware face-up playing card primitive.\n *\n * Use `PlayingCard` for visible card values in hands, shared table cards, piles,\n * or custom tabletop layouts. The component renders rank and suit text and exposes\n * an accessible card label by default.\n *\n * @readme\n * @example Face-up card\n * ```tsx\n * <PlayingCard card={{ rank: 'A', suit: 'spades' }} selected />\n * ```\n */\nexport function PlayingCard({\n card,\n size = 'medium',\n selected = false,\n muted = false,\n accessibilityLabel,\n colorScheme,\n testID,\n}: PlayingCardProps) {\n const { theme } = useZoraTheme();\n const colors = React.useMemo(\n () => createTabletopColorScheme(theme, colorScheme),\n [colorScheme, theme],\n );\n const dimensions = getTabletopCardDimensions(size);\n const suitColor = isRedSuit(card.suit) ? colors.redSuitText : colors.cardText;\n\n return (\n <View\n accessibilityLabel={accessibilityLabel ?? getPlayingCardLabel(card)}\n accessibilityRole=\"image\"\n style={[\n styles.card,\n {\n backgroundColor: colors.cardSurface,\n borderColor: selected ? colors.seatSelectedBorder : colors.cardBorder,\n borderRadius: dimensions.radius,\n height: dimensions.height,\n opacity: muted ? 0.48 : 1,\n width: dimensions.width,\n },\n ]}\n testID={testID}\n >\n <Text\n selectable={false}\n style={[\n styles.rank,\n {\n color: suitColor,\n fontSize: dimensions.rankFontSize,\n lineHeight: dimensions.rankFontSize + 4,\n },\n ]}\n >\n {card.rank}\n </Text>\n <Text\n selectable={false}\n style={[\n styles.suit,\n {\n color: suitColor,\n fontSize: dimensions.suitFontSize,\n lineHeight: dimensions.suitFontSize + 3,\n },\n ]}\n >\n {suitMarks[card.suit]}\n </Text>\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n card: {\n alignItems: 'center',\n borderWidth: 1,\n justifyContent: 'center',\n },\n rank: {\n fontWeight: '800',\n },\n suit: {\n fontWeight: '700',\n marginTop: -2,\n },\n});\n"]}
|
|
@@ -1,4 +1,21 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { TabletopTableProps } from './types';
|
|
3
|
+
/***
|
|
4
|
+
* Responsive tabletop surface for generic card-game and board-game scenes.
|
|
5
|
+
*
|
|
6
|
+
* Use `TabletopTable` to arrange seats around a themed table surface, display
|
|
7
|
+
* shared center cards, and show neutral seat labels/tokens without embedding game
|
|
8
|
+
* rules into the component.
|
|
9
|
+
*
|
|
10
|
+
* @readme
|
|
11
|
+
* @example Basic table
|
|
12
|
+
* ```tsx
|
|
13
|
+
* <TabletopTable
|
|
14
|
+
* seats={seats}
|
|
15
|
+
* centerCards={[{ rank: 'A', suit: 'spades' }]}
|
|
16
|
+
* centerLabel="Round 1"
|
|
17
|
+
* />
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
3
20
|
export declare function TabletopTable({ seats, centerCards, centerLabel, centerSublabel, shape, seatCount, cardSize, disabled, colorScheme, accessibilityLabel, testID, }: TabletopTableProps): React.JSX.Element;
|
|
4
21
|
//# sourceMappingURL=TabletopTable.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TabletopTable.d.ts","sourceRoot":"","sources":["../../../src/components/tabletop-table/TabletopTable.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAO1B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAelD,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,WAAgB,EAChB,WAAW,EACX,cAAc,EACd,KAAc,EACd,SAAS,EACT,QAAkB,EAClB,QAAgB,EAChB,WAAW,EACX,kBAAkB,EAClB,MAAM,GACP,EAAE,kBAAkB,qBAmGpB"}
|
|
1
|
+
{"version":3,"file":"TabletopTable.d.ts","sourceRoot":"","sources":["../../../src/components/tabletop-table/TabletopTable.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAO1B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAelD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,WAAgB,EAChB,WAAW,EACX,cAAc,EACd,KAAc,EACd,SAAS,EACT,QAAkB,EAClB,QAAgB,EAChB,WAAW,EACX,kBAAkB,EAClB,MAAM,GACP,EAAE,kBAAkB,qBAmGpB"}
|
|
@@ -20,6 +20,23 @@ function createSeatAccessibilityLabel(seat) {
|
|
|
20
20
|
parts.push('muted');
|
|
21
21
|
return parts.join(', ');
|
|
22
22
|
}
|
|
23
|
+
/***
|
|
24
|
+
* Responsive tabletop surface for generic card-game and board-game scenes.
|
|
25
|
+
*
|
|
26
|
+
* Use `TabletopTable` to arrange seats around a themed table surface, display
|
|
27
|
+
* shared center cards, and show neutral seat labels/tokens without embedding game
|
|
28
|
+
* rules into the component.
|
|
29
|
+
*
|
|
30
|
+
* @readme
|
|
31
|
+
* @example Basic table
|
|
32
|
+
* ```tsx
|
|
33
|
+
* <TabletopTable
|
|
34
|
+
* seats={seats}
|
|
35
|
+
* centerCards={[{ rank: 'A', suit: 'spades' }]}
|
|
36
|
+
* centerLabel="Round 1"
|
|
37
|
+
* />
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
23
40
|
export function TabletopTable({ seats, centerCards = [], centerLabel, centerSublabel, shape = 'oval', seatCount, cardSize = 'small', disabled = false, colorScheme, accessibilityLabel, testID, }) {
|
|
24
41
|
const { theme } = useZoraTheme();
|
|
25
42
|
const colors = React.useMemo(() => createTabletopColorScheme(theme, colorScheme), [colorScheme, theme]);
|
|
@@ -43,11 +60,11 @@ export function TabletopTable({ seats, centerCards = [], centerLabel, centerSubl
|
|
|
43
60
|
<View style={styles.centerContent}>
|
|
44
61
|
{centerCards.length > 0 ? (<CardHand cards={centerCards} colorScheme={colorScheme} size={cardSize}/>) : null}
|
|
45
62
|
{centerLabel !== undefined ? (<View style={[styles.centerLabel, { backgroundColor: colors.seatSurface }]}>
|
|
46
|
-
<Text style={[styles.centerLabelText, { color: colors.
|
|
63
|
+
<Text style={[styles.centerLabelText, { color: colors.seatText }]}>
|
|
47
64
|
{centerLabel}
|
|
48
65
|
</Text>
|
|
49
66
|
</View>) : null}
|
|
50
|
-
{centerSublabel !== undefined ? (<Text style={[styles.centerSublabel, { color: colors.
|
|
67
|
+
{centerSublabel !== undefined ? (<Text style={[styles.centerSublabel, { color: colors.tableMutedText }]}>
|
|
51
68
|
{centerSublabel}
|
|
52
69
|
</Text>) : null}
|
|
53
70
|
</View>
|
|
@@ -66,8 +83,8 @@ export function TabletopTable({ seats, centerCards = [], centerLabel, centerSubl
|
|
|
66
83
|
},
|
|
67
84
|
]} testID={testID ? `${testID}-seat-${seat.id}` : undefined}>
|
|
68
85
|
{seat.cards !== undefined || seat.faceDownCards !== undefined ? (<CardHand cards={seat.cards} colorScheme={colorScheme} faceDownCards={seat.faceDownCards} muted={seat.muted ?? seat.disabled} size={cardSize}/>) : null}
|
|
69
|
-
<Text style={[styles.seatLabel, { color: colors.
|
|
70
|
-
{seat.sublabel !== undefined ? (<Text style={[styles.seatSublabel, { color: colors.
|
|
86
|
+
<Text style={[styles.seatLabel, { color: colors.seatText }]}>{seat.label}</Text>
|
|
87
|
+
{seat.sublabel !== undefined ? (<Text style={[styles.seatSublabel, { color: colors.seatMutedText }]}>
|
|
71
88
|
{seat.sublabel}
|
|
72
89
|
</Text>) : null}
|
|
73
90
|
{seat.tokenLabel !== undefined ? (<View style={[styles.token, { backgroundColor: colors.tokenSurface }]}>
|
|
@@ -99,7 +116,7 @@ const styles = StyleSheet.create({
|
|
|
99
116
|
},
|
|
100
117
|
centerSublabel: {
|
|
101
118
|
fontSize: 11,
|
|
102
|
-
fontWeight: '
|
|
119
|
+
fontWeight: '700',
|
|
103
120
|
},
|
|
104
121
|
circleSurface: {
|
|
105
122
|
borderRadius: 999,
|
|
@@ -142,7 +159,7 @@ const styles = StyleSheet.create({
|
|
|
142
159
|
},
|
|
143
160
|
seatSublabel: {
|
|
144
161
|
fontSize: 10,
|
|
145
|
-
fontWeight: '
|
|
162
|
+
fontWeight: '700',
|
|
146
163
|
},
|
|
147
164
|
surface: {
|
|
148
165
|
borderWidth: 8,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TabletopTable.js","sourceRoot":"","sources":["../../../src/components/tabletop-table/TabletopTable.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useZoraTheme } from '@ankhorage/zora';\nimport React from 'react';\nimport { StyleSheet, Text, View } from 'react-native';\n\nimport { createTabletopColorScheme } from '../../colors';\nimport { getTabletopSeatPosition } from '../../tablePositions';\nimport type { TabletopSeatState } from '../../types';\nimport { CardHand } from '../card-hand';\nimport type { TabletopTableProps } from './types';\n\nfunction createSeatAccessibilityLabel(seat: TabletopSeatState): string | undefined {\n if (seat.accessibilityLabel !== undefined) return seat.accessibilityLabel;\n if (typeof seat.label !== 'string') return undefined;\n\n const parts = [seat.label];\n if (typeof seat.sublabel === 'string') parts.push(seat.sublabel);\n if (typeof seat.tokenLabel === 'string') parts.push(seat.tokenLabel);\n if (seat.selected) parts.push('selected');\n if (seat.muted) parts.push('muted');\n\n return parts.join(', ');\n}\n\nexport function TabletopTable({\n seats,\n centerCards = [],\n centerLabel,\n centerSublabel,\n shape = 'oval',\n seatCount,\n cardSize = 'small',\n disabled = false,\n colorScheme,\n accessibilityLabel,\n testID,\n}: TabletopTableProps) {\n const { theme } = useZoraTheme();\n const colors = React.useMemo(\n () => createTabletopColorScheme(theme, colorScheme),\n [colorScheme, theme],\n );\n const resolvedSeatCount = seatCount ?? seats.length;\n\n return (\n <View\n accessibilityLabel={accessibilityLabel}\n style={[styles.root, { opacity: disabled ? 0.56 : 1 }]}\n testID={testID}\n >\n <View\n style={[\n styles.surface,\n shape === 'circle' ? styles.circleSurface : styles.ovalSurface,\n shape === 'rounded' ? styles.roundedSurface : null,\n {\n backgroundColor: colors.tableFelt,\n borderColor: colors.tableBorder,\n },\n ]}\n >\n <View\n pointerEvents=\"none\"\n style={[\n styles.innerSurface,\n shape === 'circle' ? styles.circleSurface : styles.ovalSurface,\n shape === 'rounded' ? styles.roundedSurface : null,\n { borderColor: colors.tableInnerBorder },\n ]}\n />\n <View style={styles.centerContent}>\n {centerCards.length > 0 ? (\n <CardHand cards={centerCards} colorScheme={colorScheme} size={cardSize} />\n ) : null}\n {centerLabel !== undefined ? (\n <View style={[styles.centerLabel, { backgroundColor: colors.seatSurface }]}>\n <Text style={[styles.centerLabelText, { color: colors.cardText }]}>\n {centerLabel}\n </Text>\n </View>\n ) : null}\n {centerSublabel !== undefined ? (\n <Text style={[styles.centerSublabel, { color: colors.mutedText }]}>\n {centerSublabel}\n </Text>\n ) : null}\n </View>\n </View>\n\n {seats.map((seat, index) => {\n const position = getTabletopSeatPosition(index, resolvedSeatCount);\n return (\n <View\n accessibilityLabel={createSeatAccessibilityLabel(seat)}\n accessibilityRole=\"summary\"\n key={seat.id}\n style={[\n styles.seat,\n {\n borderColor: seat.selected ? colors.seatSelectedBorder : colors.seatBorder,\n backgroundColor: colors.seatSurface,\n left: position.left,\n opacity: seat.muted ? 0.48 : 1,\n top: position.top,\n },\n ]}\n testID={testID ? `${testID}-seat-${seat.id}` : undefined}\n >\n {seat.cards !== undefined || seat.faceDownCards !== undefined ? (\n <CardHand\n cards={seat.cards}\n colorScheme={colorScheme}\n faceDownCards={seat.faceDownCards}\n muted={seat.muted ?? seat.disabled}\n size={cardSize}\n />\n ) : null}\n <Text style={[styles.seatLabel, { color: colors.cardText }]}>{seat.label}</Text>\n {seat.sublabel !== undefined ? (\n <Text style={[styles.seatSublabel, { color: colors.mutedText }]}>\n {seat.sublabel}\n </Text>\n ) : null}\n {seat.tokenLabel !== undefined ? (\n <View style={[styles.token, { backgroundColor: colors.tokenSurface }]}>\n <Text style={[styles.tokenText, { color: colors.tokenText }]}>\n {seat.tokenLabel}\n </Text>\n </View>\n ) : null}\n </View>\n );\n })}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n centerContent: {\n alignItems: 'center',\n gap: 6,\n left: 0,\n position: 'absolute',\n right: 0,\n top: '35%',\n },\n centerLabel: {\n borderRadius: 999,\n paddingHorizontal: 10,\n paddingVertical: 4,\n },\n centerLabelText: {\n fontSize: 12,\n fontWeight: '800',\n },\n centerSublabel: {\n fontSize: 11,\n fontWeight: '600',\n },\n circleSurface: {\n borderRadius: 999,\n },\n innerSurface: {\n borderWidth: 1,\n bottom: 10,\n left: 10,\n opacity: 0.44,\n position: 'absolute',\n right: 10,\n top: 10,\n },\n ovalSurface: {\n borderRadius: 999,\n },\n root: {\n aspectRatio: 1.6,\n maxWidth: 760,\n position: 'relative',\n width: '100%',\n },\n roundedSurface: {\n borderRadius: 28,\n },\n seat: {\n alignItems: 'center',\n borderRadius: 10,\n borderWidth: 1,\n gap: 3,\n minWidth: 64,\n paddingHorizontal: 6,\n paddingVertical: 5,\n position: 'absolute',\n transform: [{ translateX: -32 }, { translateY: -28 }],\n },\n seatLabel: {\n fontSize: 11,\n fontWeight: '800',\n },\n seatSublabel: {\n fontSize: 10,\n fontWeight: '600',\n },\n surface: {\n borderWidth: 8,\n bottom: 28,\n left: 24,\n position: 'absolute',\n right: 24,\n top: 24,\n },\n token: {\n borderRadius: 999,\n paddingHorizontal: 6,\n paddingVertical: 2,\n },\n tokenText: {\n fontSize: 10,\n fontWeight: '800',\n },\n});\n"]}
|
|
1
|
+
{"version":3,"file":"TabletopTable.js","sourceRoot":"","sources":["../../../src/components/tabletop-table/TabletopTable.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useZoraTheme } from '@ankhorage/zora';\nimport React from 'react';\nimport { StyleSheet, Text, View } from 'react-native';\n\nimport { createTabletopColorScheme } from '../../colors';\nimport { getTabletopSeatPosition } from '../../tablePositions';\nimport type { TabletopSeatState } from '../../types';\nimport { CardHand } from '../card-hand';\nimport type { TabletopTableProps } from './types';\n\nfunction createSeatAccessibilityLabel(seat: TabletopSeatState): string | undefined {\n if (seat.accessibilityLabel !== undefined) return seat.accessibilityLabel;\n if (typeof seat.label !== 'string') return undefined;\n\n const parts = [seat.label];\n if (typeof seat.sublabel === 'string') parts.push(seat.sublabel);\n if (typeof seat.tokenLabel === 'string') parts.push(seat.tokenLabel);\n if (seat.selected) parts.push('selected');\n if (seat.muted) parts.push('muted');\n\n return parts.join(', ');\n}\n\n/***\n * Responsive tabletop surface for generic card-game and board-game scenes.\n *\n * Use `TabletopTable` to arrange seats around a themed table surface, display\n * shared center cards, and show neutral seat labels/tokens without embedding game\n * rules into the component.\n *\n * @readme\n * @example Basic table\n * ```tsx\n * <TabletopTable\n * seats={seats}\n * centerCards={[{ rank: 'A', suit: 'spades' }]}\n * centerLabel=\"Round 1\"\n * />\n * ```\n */\nexport function TabletopTable({\n seats,\n centerCards = [],\n centerLabel,\n centerSublabel,\n shape = 'oval',\n seatCount,\n cardSize = 'small',\n disabled = false,\n colorScheme,\n accessibilityLabel,\n testID,\n}: TabletopTableProps) {\n const { theme } = useZoraTheme();\n const colors = React.useMemo(\n () => createTabletopColorScheme(theme, colorScheme),\n [colorScheme, theme],\n );\n const resolvedSeatCount = seatCount ?? seats.length;\n\n return (\n <View\n accessibilityLabel={accessibilityLabel}\n style={[styles.root, { opacity: disabled ? 0.56 : 1 }]}\n testID={testID}\n >\n <View\n style={[\n styles.surface,\n shape === 'circle' ? styles.circleSurface : styles.ovalSurface,\n shape === 'rounded' ? styles.roundedSurface : null,\n {\n backgroundColor: colors.tableFelt,\n borderColor: colors.tableBorder,\n },\n ]}\n >\n <View\n pointerEvents=\"none\"\n style={[\n styles.innerSurface,\n shape === 'circle' ? styles.circleSurface : styles.ovalSurface,\n shape === 'rounded' ? styles.roundedSurface : null,\n { borderColor: colors.tableInnerBorder },\n ]}\n />\n <View style={styles.centerContent}>\n {centerCards.length > 0 ? (\n <CardHand cards={centerCards} colorScheme={colorScheme} size={cardSize} />\n ) : null}\n {centerLabel !== undefined ? (\n <View style={[styles.centerLabel, { backgroundColor: colors.seatSurface }]}>\n <Text style={[styles.centerLabelText, { color: colors.seatText }]}>\n {centerLabel}\n </Text>\n </View>\n ) : null}\n {centerSublabel !== undefined ? (\n <Text style={[styles.centerSublabel, { color: colors.tableMutedText }]}>\n {centerSublabel}\n </Text>\n ) : null}\n </View>\n </View>\n\n {seats.map((seat, index) => {\n const position = getTabletopSeatPosition(index, resolvedSeatCount);\n return (\n <View\n accessibilityLabel={createSeatAccessibilityLabel(seat)}\n accessibilityRole=\"summary\"\n key={seat.id}\n style={[\n styles.seat,\n {\n borderColor: seat.selected ? colors.seatSelectedBorder : colors.seatBorder,\n backgroundColor: colors.seatSurface,\n left: position.left,\n opacity: seat.muted ? 0.48 : 1,\n top: position.top,\n },\n ]}\n testID={testID ? `${testID}-seat-${seat.id}` : undefined}\n >\n {seat.cards !== undefined || seat.faceDownCards !== undefined ? (\n <CardHand\n cards={seat.cards}\n colorScheme={colorScheme}\n faceDownCards={seat.faceDownCards}\n muted={seat.muted ?? seat.disabled}\n size={cardSize}\n />\n ) : null}\n <Text style={[styles.seatLabel, { color: colors.seatText }]}>{seat.label}</Text>\n {seat.sublabel !== undefined ? (\n <Text style={[styles.seatSublabel, { color: colors.seatMutedText }]}>\n {seat.sublabel}\n </Text>\n ) : null}\n {seat.tokenLabel !== undefined ? (\n <View style={[styles.token, { backgroundColor: colors.tokenSurface }]}>\n <Text style={[styles.tokenText, { color: colors.tokenText }]}>\n {seat.tokenLabel}\n </Text>\n </View>\n ) : null}\n </View>\n );\n })}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n centerContent: {\n alignItems: 'center',\n gap: 6,\n left: 0,\n position: 'absolute',\n right: 0,\n top: '35%',\n },\n centerLabel: {\n borderRadius: 999,\n paddingHorizontal: 10,\n paddingVertical: 4,\n },\n centerLabelText: {\n fontSize: 12,\n fontWeight: '800',\n },\n centerSublabel: {\n fontSize: 11,\n fontWeight: '700',\n },\n circleSurface: {\n borderRadius: 999,\n },\n innerSurface: {\n borderWidth: 1,\n bottom: 10,\n left: 10,\n opacity: 0.44,\n position: 'absolute',\n right: 10,\n top: 10,\n },\n ovalSurface: {\n borderRadius: 999,\n },\n root: {\n aspectRatio: 1.6,\n maxWidth: 760,\n position: 'relative',\n width: '100%',\n },\n roundedSurface: {\n borderRadius: 28,\n },\n seat: {\n alignItems: 'center',\n borderRadius: 10,\n borderWidth: 1,\n gap: 3,\n minWidth: 64,\n paddingHorizontal: 6,\n paddingVertical: 5,\n position: 'absolute',\n transform: [{ translateX: -32 }, { translateY: -28 }],\n },\n seatLabel: {\n fontSize: 11,\n fontWeight: '800',\n },\n seatSublabel: {\n fontSize: 10,\n fontWeight: '700',\n },\n surface: {\n borderWidth: 8,\n bottom: 28,\n left: 24,\n position: 'absolute',\n right: 24,\n top: 24,\n },\n token: {\n borderRadius: 999,\n paddingHorizontal: 6,\n paddingVertical: 2,\n },\n tokenText: {\n fontSize: 10,\n fontWeight: '800',\n },\n});\n"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ankhorage/zora-tabletop",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.3",
|
|
5
5
|
"description": "Tabletop and card-game UI primitives for React Native and React Native Web, built on ZORA.",
|
|
6
6
|
"homepage": "https://github.com/ankhorage/zora-tabletop#readme",
|
|
7
7
|
"bugs": {
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
70
|
"@ankhorage/devtools": "^1.0.6",
|
|
71
|
-
"@ankhorage/paradox": "^0.1.
|
|
71
|
+
"@ankhorage/paradox": "^0.1.10",
|
|
72
72
|
"@ankhorage/zora": "^2.5.1",
|
|
73
73
|
"@changesets/cli": "^2.31.0",
|
|
74
74
|
"@types/bun": "^1.3.13",
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { describe, expect, test } from 'bun:test';
|
|
2
|
+
|
|
3
|
+
import { createTabletopColorScheme, type TabletopColorThemeShape } from './colors';
|
|
4
|
+
|
|
5
|
+
const baseTheme = {
|
|
6
|
+
semantics: {
|
|
7
|
+
action: {
|
|
8
|
+
primary: {
|
|
9
|
+
base: '#047857',
|
|
10
|
+
softBg: '#047857',
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
content: {
|
|
14
|
+
default: '#047857',
|
|
15
|
+
muted: '#059669',
|
|
16
|
+
},
|
|
17
|
+
neutral: {
|
|
18
|
+
border: '#d1d5db',
|
|
19
|
+
divider: '#e5e7eb',
|
|
20
|
+
surface: '#ffffff',
|
|
21
|
+
surfaceHover: '#f9fafb',
|
|
22
|
+
},
|
|
23
|
+
warning: {
|
|
24
|
+
base: '#b45309',
|
|
25
|
+
softBg: '#fef3c7',
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
} satisfies TabletopColorThemeShape;
|
|
29
|
+
|
|
30
|
+
describe('createTabletopColorScheme', () => {
|
|
31
|
+
test('derives readable table text when preferred theme text matches the table surface', () => {
|
|
32
|
+
const colors = createTabletopColorScheme(baseTheme);
|
|
33
|
+
|
|
34
|
+
expect(colors.tableFelt).toBe('#047857');
|
|
35
|
+
expect(colors.tableText).toBe('#ffffff');
|
|
36
|
+
expect(colors.tableMutedText).toBe('#ffffff');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('derives readable seat text for dark custom seat surfaces', () => {
|
|
40
|
+
const colors = createTabletopColorScheme(baseTheme, {
|
|
41
|
+
seatSurface: '#064e3b',
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
expect(colors.seatText).toBe('#ffffff');
|
|
45
|
+
expect(colors.seatMutedText).toBe('#ffffff');
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test('keeps explicit readable text overrides', () => {
|
|
49
|
+
const colors = createTabletopColorScheme(baseTheme, {
|
|
50
|
+
seatSurface: '#064e3b',
|
|
51
|
+
seatText: '#fef3c7',
|
|
52
|
+
tableText: '#fef3c7',
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
expect(colors.seatText).toBe('#fef3c7');
|
|
56
|
+
expect(colors.tableText).toBe('#fef3c7');
|
|
57
|
+
});
|
|
58
|
+
});
|
package/src/colors.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
|
}
|
|
@@ -43,25 +47,169 @@ export interface TabletopColorThemeShape {
|
|
|
43
47
|
};
|
|
44
48
|
}
|
|
45
49
|
|
|
50
|
+
interface RgbColor {
|
|
51
|
+
readonly red: number;
|
|
52
|
+
readonly green: number;
|
|
53
|
+
readonly blue: number;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const DARK_TEXT_FALLBACK = '#111827';
|
|
57
|
+
const LIGHT_TEXT_FALLBACK = '#ffffff';
|
|
58
|
+
const MINIMUM_READABLE_CONTRAST = 4.5;
|
|
59
|
+
|
|
60
|
+
/***
|
|
61
|
+
* Creates the theme-derived color palette used by tabletop primitives.
|
|
62
|
+
*
|
|
63
|
+
* Use `createTabletopColorScheme` when custom components need to align with the
|
|
64
|
+
* same card, table, seat, token, and contrast-aware foreground colors as the
|
|
65
|
+
* built-in tabletop components.
|
|
66
|
+
*
|
|
67
|
+
* @readme
|
|
68
|
+
* @example Custom color scheme
|
|
69
|
+
* ```ts
|
|
70
|
+
* const colors = createTabletopColorScheme(theme, { tableFelt: '#065f46' });
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
46
73
|
export function createTabletopColorScheme(
|
|
47
74
|
theme: TabletopColorThemeShape,
|
|
48
75
|
overrides: TabletopColorOverrides = {},
|
|
49
76
|
): TabletopColorScheme {
|
|
77
|
+
const cardSurface = overrides.cardSurface ?? theme.semantics.neutral.surface;
|
|
78
|
+
const seatSurface = overrides.seatSurface ?? theme.semantics.neutral.surface;
|
|
79
|
+
const tableFelt = overrides.tableFelt ?? theme.semantics.action.primary.softBg;
|
|
80
|
+
const tokenSurface = overrides.tokenSurface ?? theme.semantics.warning.softBg;
|
|
81
|
+
|
|
82
|
+
const cardText =
|
|
83
|
+
overrides.cardText ??
|
|
84
|
+
resolveReadableTextColor(cardSurface, theme.semantics.content.default, LIGHT_TEXT_FALLBACK);
|
|
85
|
+
const seatText =
|
|
86
|
+
overrides.seatText ??
|
|
87
|
+
resolveReadableTextColor(seatSurface, theme.semantics.content.default, LIGHT_TEXT_FALLBACK);
|
|
88
|
+
const tableText =
|
|
89
|
+
overrides.tableText ??
|
|
90
|
+
resolveReadableTextColor(tableFelt, theme.semantics.content.default, LIGHT_TEXT_FALLBACK);
|
|
91
|
+
const tokenText =
|
|
92
|
+
overrides.tokenText ??
|
|
93
|
+
resolveReadableTextColor(tokenSurface, theme.semantics.content.default, LIGHT_TEXT_FALLBACK);
|
|
94
|
+
|
|
50
95
|
return {
|
|
51
96
|
cardBack: overrides.cardBack ?? theme.semantics.warning.base,
|
|
52
97
|
cardBackBorder: overrides.cardBackBorder ?? theme.semantics.neutral.border,
|
|
53
98
|
cardBorder: overrides.cardBorder ?? theme.semantics.neutral.border,
|
|
54
|
-
cardSurface
|
|
55
|
-
cardText
|
|
56
|
-
mutedText:
|
|
57
|
-
|
|
99
|
+
cardSurface,
|
|
100
|
+
cardText,
|
|
101
|
+
mutedText:
|
|
102
|
+
overrides.mutedText ??
|
|
103
|
+
resolveReadableTextColor(cardSurface, theme.semantics.content.muted, cardText),
|
|
104
|
+
redSuitText:
|
|
105
|
+
overrides.redSuitText ??
|
|
106
|
+
resolveReadableTextColor(cardSurface, theme.semantics.warning.base, cardText),
|
|
58
107
|
seatBorder: overrides.seatBorder ?? theme.semantics.neutral.divider,
|
|
108
|
+
seatMutedText:
|
|
109
|
+
overrides.seatMutedText ??
|
|
110
|
+
resolveReadableTextColor(seatSurface, theme.semantics.content.muted, seatText),
|
|
59
111
|
seatSelectedBorder: overrides.seatSelectedBorder ?? theme.semantics.action.primary.base,
|
|
60
|
-
seatSurface
|
|
112
|
+
seatSurface,
|
|
113
|
+
seatText,
|
|
61
114
|
tableBorder: overrides.tableBorder ?? theme.semantics.warning.base,
|
|
62
|
-
tableFelt
|
|
115
|
+
tableFelt,
|
|
63
116
|
tableInnerBorder: overrides.tableInnerBorder ?? theme.semantics.neutral.divider,
|
|
64
|
-
|
|
65
|
-
|
|
117
|
+
tableMutedText:
|
|
118
|
+
overrides.tableMutedText ??
|
|
119
|
+
resolveReadableTextColor(tableFelt, theme.semantics.content.muted, tableText),
|
|
120
|
+
tableText,
|
|
121
|
+
tokenSurface,
|
|
122
|
+
tokenText,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function resolveReadableTextColor(background: string, preferred: string, fallback: string): string {
|
|
127
|
+
const preferredContrast = getContrastRatio(background, preferred);
|
|
128
|
+
if (preferredContrast !== null && preferredContrast >= MINIMUM_READABLE_CONTRAST) {
|
|
129
|
+
return preferred;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const candidates = uniqueColors([preferred, fallback, LIGHT_TEXT_FALLBACK, DARK_TEXT_FALLBACK]);
|
|
133
|
+
const [readableCandidate] = candidates
|
|
134
|
+
.map((candidate) => ({ candidate, contrast: getContrastRatio(background, candidate) }))
|
|
135
|
+
.filter(
|
|
136
|
+
(entry): entry is { readonly candidate: string; readonly contrast: number } =>
|
|
137
|
+
entry.contrast !== null,
|
|
138
|
+
)
|
|
139
|
+
.sort((left, right) => right.contrast - left.contrast);
|
|
140
|
+
|
|
141
|
+
return readableCandidate?.candidate ?? preferred;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function uniqueColors(colors: readonly string[]): string[] {
|
|
145
|
+
return [...new Set(colors)];
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function getContrastRatio(background: string, foreground: string): number | null {
|
|
149
|
+
const backgroundColor = parseHexColor(background);
|
|
150
|
+
const foregroundColor = parseHexColor(foreground);
|
|
151
|
+
|
|
152
|
+
if (backgroundColor === null || foregroundColor === null) return null;
|
|
153
|
+
|
|
154
|
+
const backgroundLuminance = getRelativeLuminance(backgroundColor);
|
|
155
|
+
const foregroundLuminance = getRelativeLuminance(foregroundColor);
|
|
156
|
+
const lighter = Math.max(backgroundLuminance, foregroundLuminance);
|
|
157
|
+
const darker = Math.min(backgroundLuminance, foregroundLuminance);
|
|
158
|
+
|
|
159
|
+
return (lighter + 0.05) / (darker + 0.05);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function parseHexColor(color: string): RgbColor | null {
|
|
163
|
+
const value = color.trim();
|
|
164
|
+
const hex = value.startsWith('#') ? value.slice(1) : '';
|
|
165
|
+
if (!isSupportedHexLength(hex) || !isHexColorValue(hex)) return null;
|
|
166
|
+
|
|
167
|
+
if (hex.length === 3) {
|
|
168
|
+
const red = hex.slice(0, 1);
|
|
169
|
+
const green = hex.slice(1, 2);
|
|
170
|
+
const blue = hex.slice(2, 3);
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
red: parseInt(red + red, 16),
|
|
174
|
+
green: parseInt(green + green, 16),
|
|
175
|
+
blue: parseInt(blue + blue, 16),
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return {
|
|
180
|
+
red: parseInt(hex.slice(0, 2), 16),
|
|
181
|
+
green: parseInt(hex.slice(2, 4), 16),
|
|
182
|
+
blue: parseInt(hex.slice(4, 6), 16),
|
|
66
183
|
};
|
|
67
184
|
}
|
|
185
|
+
|
|
186
|
+
function isSupportedHexLength(hex: string): boolean {
|
|
187
|
+
return hex.length === 3 || hex.length === 6 || hex.length === 8;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function isHexColorValue(hex: string): boolean {
|
|
191
|
+
return [...hex].every((character) => isHexCharacter(character));
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function isHexCharacter(character: string): boolean {
|
|
195
|
+
const code = character.charCodeAt(0);
|
|
196
|
+
const isDigit = code >= 48 && code <= 57;
|
|
197
|
+
const isUpperHex = code >= 65 && code <= 70;
|
|
198
|
+
const isLowerHex = code >= 97 && code <= 102;
|
|
199
|
+
|
|
200
|
+
return isDigit || isUpperHex || isLowerHex;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function getRelativeLuminance(color: RgbColor): number {
|
|
204
|
+
const red = normalizeColorChannel(color.red);
|
|
205
|
+
const green = normalizeColorChannel(color.green);
|
|
206
|
+
const blue = normalizeColorChannel(color.blue);
|
|
207
|
+
|
|
208
|
+
return 0.2126 * red + 0.7152 * green + 0.0722 * blue;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function normalizeColorChannel(value: number): number {
|
|
212
|
+
const normalized = value / 255;
|
|
213
|
+
if (normalized <= 0.03928) return normalized / 12.92;
|
|
214
|
+
return ((normalized + 0.055) / 1.055) ** 2.4;
|
|
215
|
+
}
|
|
@@ -7,6 +7,18 @@ import { getTabletopCardDimensions } from '../../cardSizing';
|
|
|
7
7
|
import { createTabletopColorScheme } from '../../colors';
|
|
8
8
|
import type { CardBackProps } from './types';
|
|
9
9
|
|
|
10
|
+
/***
|
|
11
|
+
* Face-down playing-card primitive for hidden cards and decks.
|
|
12
|
+
*
|
|
13
|
+
* Use `CardBack` when a card should be represented visually without exposing its
|
|
14
|
+
* rank or suit. The component keeps a generic accessible label for hidden cards.
|
|
15
|
+
*
|
|
16
|
+
* @readme
|
|
17
|
+
* @example Hidden cards
|
|
18
|
+
* ```tsx
|
|
19
|
+
* <CardBack size="small" />
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
10
22
|
export function CardBack({
|
|
11
23
|
size = 'medium',
|
|
12
24
|
muted = false,
|
|
@@ -9,6 +9,18 @@ function createFaceDownCards(count: number): readonly number[] {
|
|
|
9
9
|
return Array.from({ length: Math.max(0, count) }, (_, index) => index);
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
/***
|
|
13
|
+
* Compact row of visible and face-down playing cards.
|
|
14
|
+
*
|
|
15
|
+
* Use `CardHand` when a seat, pile, or custom layout needs to show multiple cards
|
|
16
|
+
* with consistent spacing, sizing, and muted state handling.
|
|
17
|
+
*
|
|
18
|
+
* @readme
|
|
19
|
+
* @example Mixed hand
|
|
20
|
+
* ```tsx
|
|
21
|
+
* <CardHand cards={[{ rank: 'Q', suit: 'hearts' }]} faceDownCards={1} />
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
12
24
|
export function CardHand({
|
|
13
25
|
cards = [],
|
|
14
26
|
faceDownCards = 0,
|
|
@@ -19,6 +19,19 @@ function isRedSuit(suit: PlayingCardSuit): boolean {
|
|
|
19
19
|
return suit === 'diamonds' || suit === 'hearts';
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
/***
|
|
23
|
+
* Theme-aware face-up playing card primitive.
|
|
24
|
+
*
|
|
25
|
+
* Use `PlayingCard` for visible card values in hands, shared table cards, piles,
|
|
26
|
+
* or custom tabletop layouts. The component renders rank and suit text and exposes
|
|
27
|
+
* an accessible card label by default.
|
|
28
|
+
*
|
|
29
|
+
* @readme
|
|
30
|
+
* @example Face-up card
|
|
31
|
+
* ```tsx
|
|
32
|
+
* <PlayingCard card={{ rank: 'A', suit: 'spades' }} selected />
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
22
35
|
export function PlayingCard({
|
|
23
36
|
card,
|
|
24
37
|
size = 'medium',
|