react-native-football-formation 1.0.0

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.
Files changed (65) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +447 -0
  3. package/dist/assets/index.d.ts +13 -0
  4. package/dist/assets/index.d.ts.map +1 -0
  5. package/dist/assets/index.js +15 -0
  6. package/dist/components/FormationField.d.ts +5 -0
  7. package/dist/components/FormationField.d.ts.map +1 -0
  8. package/dist/components/FormationField.js +147 -0
  9. package/dist/components/PlayerCard.d.ts +5 -0
  10. package/dist/components/PlayerCard.d.ts.map +1 -0
  11. package/dist/components/PlayerCard.js +365 -0
  12. package/dist/components/index.d.ts +3 -0
  13. package/dist/components/index.d.ts.map +1 -0
  14. package/dist/components/index.js +10 -0
  15. package/dist/index.d.ts +11 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +35 -0
  18. package/dist/theme/defaultTheme.d.ts +12 -0
  19. package/dist/theme/defaultTheme.d.ts.map +1 -0
  20. package/dist/theme/defaultTheme.js +70 -0
  21. package/dist/theme/index.d.ts +2 -0
  22. package/dist/theme/index.d.ts.map +1 -0
  23. package/dist/theme/index.js +17 -0
  24. package/dist/types/component.types.d.ts +48 -0
  25. package/dist/types/component.types.d.ts.map +1 -0
  26. package/dist/types/component.types.js +2 -0
  27. package/dist/types/formation.types.d.ts +59 -0
  28. package/dist/types/formation.types.d.ts.map +1 -0
  29. package/dist/types/formation.types.js +5 -0
  30. package/dist/types/index.d.ts +4 -0
  31. package/dist/types/index.d.ts.map +1 -0
  32. package/dist/types/index.js +19 -0
  33. package/dist/types/theme.types.d.ts +44 -0
  34. package/dist/types/theme.types.d.ts.map +1 -0
  35. package/dist/types/theme.types.js +5 -0
  36. package/dist/utils/formationCoordinates.d.ts +10 -0
  37. package/dist/utils/formationCoordinates.d.ts.map +1 -0
  38. package/dist/utils/formationCoordinates.js +311 -0
  39. package/dist/utils/index.d.ts +3 -0
  40. package/dist/utils/index.d.ts.map +1 -0
  41. package/dist/utils/index.js +18 -0
  42. package/dist/utils/transformLineup.d.ts +21 -0
  43. package/dist/utils/transformLineup.d.ts.map +1 -0
  44. package/dist/utils/transformLineup.js +126 -0
  45. package/package.json +60 -0
  46. package/src/assets/images/field.png +0 -0
  47. package/src/assets/images/football.png +0 -0
  48. package/src/assets/images/kicker.png +0 -0
  49. package/src/assets/images/ownGoals.png +0 -0
  50. package/src/assets/images/playerPlaceholder.png +0 -0
  51. package/src/assets/images/renewal.png +0 -0
  52. package/src/assets/index.ts +12 -0
  53. package/src/components/FormationField.tsx +182 -0
  54. package/src/components/PlayerCard.tsx +452 -0
  55. package/src/components/index.ts +2 -0
  56. package/src/index.ts +20 -0
  57. package/src/theme/defaultTheme.ts +74 -0
  58. package/src/theme/index.ts +1 -0
  59. package/src/types/component.types.ts +72 -0
  60. package/src/types/formation.types.ts +88 -0
  61. package/src/types/index.ts +3 -0
  62. package/src/types/theme.types.ts +48 -0
  63. package/src/utils/formationCoordinates.ts +335 -0
  64. package/src/utils/index.ts +2 -0
  65. package/src/utils/transformLineup.ts +158 -0
@@ -0,0 +1,158 @@
1
+ import {
2
+ TeamLineup,
3
+ Player,
4
+ PlayerStats,
5
+ LineupFormationPlayer,
6
+ FieldCoordinate,
7
+ } from '../types';
8
+ import { FORMATION_COORDINATES_BY_PLACE } from './formationCoordinates';
9
+
10
+ type Stats = (PlayerStats | null)[];
11
+
12
+ /**
13
+ * Check if a player has a specific stat type
14
+ */
15
+ export const hasStat = (stats: Stats | undefined, statType: string): boolean => {
16
+ return stats?.some(stat => stat?.type === statType) ?? false;
17
+ };
18
+
19
+ /**
20
+ * Get the value of a specific stat type for a player
21
+ */
22
+ export const getStatValue = (
23
+ stats: Stats | undefined,
24
+ statType: string
25
+ ): number | string => {
26
+ return stats?.find(stat => stat?.type === statType)?.value ?? 0;
27
+ };
28
+
29
+ /**
30
+ * Get formation coordinates by formation place (1-11)
31
+ */
32
+ const getCoordinatesByFormationPlace = (
33
+ formation: string,
34
+ formationPlace: string
35
+ ): FieldCoordinate => {
36
+ const formationCoords = FORMATION_COORDINATES_BY_PLACE[formation as keyof typeof FORMATION_COORDINATES_BY_PLACE];
37
+ if (!formationCoords) {
38
+ return { x: 49, y: 40 }; // Default position (center field)
39
+ }
40
+
41
+ return formationCoords[formationPlace] || { x: 49, y: 40 };
42
+ };
43
+
44
+ /**
45
+ * Determine position type based on formationPlace and formation
46
+ */
47
+ const getPositionTypeByFormationPlace = (
48
+ formation: string,
49
+ formationPlace: string
50
+ ): string => {
51
+ const placeInt = parseInt(formationPlace);
52
+
53
+ // Common position mappings based on formationPlace
54
+ if (placeInt === 1) return 'GK';
55
+
56
+ // For most formations, places 2-6 are defenders
57
+ if (placeInt >= 2 && placeInt <= 6) {
58
+ if (formation?.startsWith('3-')) {
59
+ // 3-back formations: 4,5,6 are CBs, 2,3 might be wing-backs
60
+ if (placeInt >= 4 && placeInt <= 6) return 'CB';
61
+ if (placeInt === 2) return 'RB';
62
+ if (placeInt === 3) return 'LB';
63
+ } else if (formation?.startsWith('5-')) {
64
+ // 5-back formations: all are defenders
65
+ return placeInt === 2 || placeInt === 3 ? 'LB' : 'CB';
66
+ } else {
67
+ // 4-back formations
68
+ if (placeInt === 2) return 'RB';
69
+ if (placeInt === 3) return 'LB';
70
+ return 'CB';
71
+ }
72
+ }
73
+
74
+ // Places 7-8 are usually midfielders
75
+ if (placeInt >= 7 && placeInt <= 8) return 'CM';
76
+
77
+ // Place 9 is usually striker
78
+ if (placeInt === 9) return 'ST';
79
+
80
+ // Places 10-11 vary by formation
81
+ if (placeInt >= 10 && placeInt <= 11) {
82
+ if (formation.includes('-3-') && formation.endsWith('3')) {
83
+ return placeInt === 10 ? 'RW' : 'LW'; // 4-3-3, 3-4-3 etc.
84
+ }
85
+ return 'CAM'; // Default to attacking midfielder
86
+ }
87
+
88
+ return 'CM'; // Default fallback
89
+ };
90
+
91
+ /**
92
+ * Transform lineup data by formation place into positioned players
93
+ *
94
+ * @param data - TeamLineup data with players and formation
95
+ * @param formation - Formation string (e.g., "4-3-3", "4-2-3-1")
96
+ * @param getPlayerPhotoUrl - Optional function to generate photo URLs
97
+ * @returns Array of positioned players with stats
98
+ */
99
+ export const transformLineupByFormationPlace = (
100
+ data: TeamLineup,
101
+ formation: string = '4-2-3-1',
102
+ getPlayerPhotoUrl?: (playerId: string) => string
103
+ ): LineupFormationPlayer[] => {
104
+ // Filter starters (players with formationPlace 1-11)
105
+ const starters =
106
+ data?.players?.filter(
107
+ (p: Player) =>
108
+ p?.formationPlace &&
109
+ parseInt(p?.formationPlace) >= 1 &&
110
+ parseInt(p?.formationPlace) <= 11 &&
111
+ p?.position !== 'Substitute'
112
+ ) || [];
113
+
114
+ if (starters?.length < 11) {
115
+ return [];
116
+ }
117
+
118
+ const transformedPlayers = starters?.map(player => {
119
+ const coordinates = getCoordinatesByFormationPlace(formation, player?.formationPlace!);
120
+ const positionType = getPositionTypeByFormationPlace(formation, player?.formationPlace!);
121
+
122
+ // Generate photo URL using custom function or empty string
123
+ const photoUrl = getPlayerPhotoUrl
124
+ ? getPlayerPhotoUrl(player?.playerId)
125
+ : '';
126
+
127
+ return {
128
+ playerId: player?.playerId,
129
+ matchName: player?.matchName || '',
130
+ position: positionType,
131
+ formationPlace: player?.formationPlace!,
132
+ rating: player?.rating,
133
+ isScorer: player?.stats && player?.stats?.length ? hasStat(player?.stats, 'goals') : false,
134
+ isSubstitute:
135
+ player?.stats && player?.stats?.length ? hasStat(player?.stats, 'totalSubOff') : false,
136
+ isYellowCard:
137
+ player?.stats && player?.stats?.length ? hasStat(player?.stats, 'yellowCard') : false,
138
+ isRedCard: player?.stats && player?.stats?.length ? hasStat(player?.stats, 'redCard') : false,
139
+ isGoalAssist:
140
+ player?.stats && player?.stats?.length ? hasStat(player?.stats, 'goalAssist') : false,
141
+ isOwnGoal:
142
+ player?.stats && player?.stats?.length ? hasStat(player?.stats, 'ownGoals') : false,
143
+ goals: Number(getStatValue(player?.stats, 'goals')),
144
+ ownGoals: Number(getStatValue(player?.stats, 'ownGoals')),
145
+ shirtNumber: player?.shirtNumber,
146
+ photo: photoUrl,
147
+ x: coordinates?.x,
148
+ y: coordinates?.y,
149
+ };
150
+ });
151
+
152
+ // Sort by formationPlace to maintain consistent ordering
153
+ transformedPlayers.sort((a, b) => {
154
+ return parseInt(a.formationPlace) - parseInt(b.formationPlace);
155
+ });
156
+
157
+ return transformedPlayers;
158
+ };