melta-app 0.1.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 (311) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +197 -0
  3. package/THIRD_PARTY_LICENSES.md +198 -0
  4. package/lib/module/components/ActionSheet.js +87 -0
  5. package/lib/module/components/ActionSheet.js.map +1 -0
  6. package/lib/module/components/Alert.js +93 -0
  7. package/lib/module/components/Alert.js.map +1 -0
  8. package/lib/module/components/Avatar.js +93 -0
  9. package/lib/module/components/Avatar.js.map +1 -0
  10. package/lib/module/components/BottomSheet.js +69 -0
  11. package/lib/module/components/BottomSheet.js.map +1 -0
  12. package/lib/module/components/Card.js +93 -0
  13. package/lib/module/components/Card.js.map +1 -0
  14. package/lib/module/components/Checkbox.js +115 -0
  15. package/lib/module/components/Checkbox.js.map +1 -0
  16. package/lib/module/components/EmptyState.js +70 -0
  17. package/lib/module/components/EmptyState.js.map +1 -0
  18. package/lib/module/components/Header.js +53 -0
  19. package/lib/module/components/Header.js.map +1 -0
  20. package/lib/module/components/Image.js +67 -0
  21. package/lib/module/components/Image.js.map +1 -0
  22. package/lib/module/components/Modal.js +95 -0
  23. package/lib/module/components/Modal.js.map +1 -0
  24. package/lib/module/components/Progress.js +113 -0
  25. package/lib/module/components/Progress.js.map +1 -0
  26. package/lib/module/components/Radio.js +134 -0
  27. package/lib/module/components/Radio.js.map +1 -0
  28. package/lib/module/components/Screen.js +57 -0
  29. package/lib/module/components/Screen.js.map +1 -0
  30. package/lib/module/components/Skeleton.js +169 -0
  31. package/lib/module/components/Skeleton.js.map +1 -0
  32. package/lib/module/components/Surface.js +49 -0
  33. package/lib/module/components/Surface.js.map +1 -0
  34. package/lib/module/components/TextField.js +84 -0
  35. package/lib/module/components/TextField.js.map +1 -0
  36. package/lib/module/components/Toast.js +105 -0
  37. package/lib/module/components/Toast.js.map +1 -0
  38. package/lib/module/components/Toggle.js +77 -0
  39. package/lib/module/components/Toggle.js.map +1 -0
  40. package/lib/module/components/action-sheet.styles.js +70 -0
  41. package/lib/module/components/action-sheet.styles.js.map +1 -0
  42. package/lib/module/components/alert.styles.js +80 -0
  43. package/lib/module/components/alert.styles.js.map +1 -0
  44. package/lib/module/components/avatar.styles.js +94 -0
  45. package/lib/module/components/avatar.styles.js.map +1 -0
  46. package/lib/module/components/bottom-sheet.styles.js +55 -0
  47. package/lib/module/components/bottom-sheet.styles.js.map +1 -0
  48. package/lib/module/components/card.styles.js +50 -0
  49. package/lib/module/components/card.styles.js.map +1 -0
  50. package/lib/module/components/checkbox.styles.js +55 -0
  51. package/lib/module/components/checkbox.styles.js.map +1 -0
  52. package/lib/module/components/empty-state.styles.js +60 -0
  53. package/lib/module/components/empty-state.styles.js.map +1 -0
  54. package/lib/module/components/header.styles.js +33 -0
  55. package/lib/module/components/header.styles.js.map +1 -0
  56. package/lib/module/components/image.styles.js +37 -0
  57. package/lib/module/components/image.styles.js.map +1 -0
  58. package/lib/module/components/index.js +26 -0
  59. package/lib/module/components/index.js.map +1 -0
  60. package/lib/module/components/modal.styles.js +68 -0
  61. package/lib/module/components/modal.styles.js.map +1 -0
  62. package/lib/module/components/progress.styles.js +55 -0
  63. package/lib/module/components/progress.styles.js.map +1 -0
  64. package/lib/module/components/radio.styles.js +96 -0
  65. package/lib/module/components/radio.styles.js.map +1 -0
  66. package/lib/module/components/screen.styles.js +38 -0
  67. package/lib/module/components/screen.styles.js.map +1 -0
  68. package/lib/module/components/skeleton.styles.js +114 -0
  69. package/lib/module/components/skeleton.styles.js.map +1 -0
  70. package/lib/module/components/surface.styles.js +37 -0
  71. package/lib/module/components/surface.styles.js.map +1 -0
  72. package/lib/module/components/textfield.styles.js +121 -0
  73. package/lib/module/components/textfield.styles.js.map +1 -0
  74. package/lib/module/components/toast.styles.js +81 -0
  75. package/lib/module/components/toast.styles.js.map +1 -0
  76. package/lib/module/components/toggle.styles.js +69 -0
  77. package/lib/module/components/toggle.styles.js.map +1 -0
  78. package/lib/module/contracts/contract-types.js +192 -0
  79. package/lib/module/contracts/contract-types.js.map +1 -0
  80. package/lib/module/icons/Icon.js +57 -0
  81. package/lib/module/icons/Icon.js.map +1 -0
  82. package/lib/module/icons/glyphs.js +257 -0
  83. package/lib/module/icons/glyphs.js.map +1 -0
  84. package/lib/module/icons/icon.styles.js +28 -0
  85. package/lib/module/icons/icon.styles.js.map +1 -0
  86. package/lib/module/icons/index.js +14 -0
  87. package/lib/module/icons/index.js.map +1 -0
  88. package/lib/module/index.js +20 -0
  89. package/lib/module/index.js.map +1 -0
  90. package/lib/module/package.json +1 -0
  91. package/lib/module/primitives/Button.js +105 -0
  92. package/lib/module/primitives/Button.js.map +1 -0
  93. package/lib/module/primitives/Metric.js +68 -0
  94. package/lib/module/primitives/Metric.js.map +1 -0
  95. package/lib/module/primitives/Row.js +43 -0
  96. package/lib/module/primitives/Row.js.map +1 -0
  97. package/lib/module/primitives/Stack.js +39 -0
  98. package/lib/module/primitives/Stack.js.map +1 -0
  99. package/lib/module/primitives/Tag.js +160 -0
  100. package/lib/module/primitives/Tag.js.map +1 -0
  101. package/lib/module/primitives/Text.js +54 -0
  102. package/lib/module/primitives/Text.js.map +1 -0
  103. package/lib/module/primitives/_internal/focus-ring.js +57 -0
  104. package/lib/module/primitives/_internal/focus-ring.js.map +1 -0
  105. package/lib/module/primitives/button.styles.js +88 -0
  106. package/lib/module/primitives/button.styles.js.map +1 -0
  107. package/lib/module/primitives/index.js +11 -0
  108. package/lib/module/primitives/index.js.map +1 -0
  109. package/lib/module/primitives/metric.styles.js +54 -0
  110. package/lib/module/primitives/metric.styles.js.map +1 -0
  111. package/lib/module/primitives/row.styles.js +53 -0
  112. package/lib/module/primitives/row.styles.js.map +1 -0
  113. package/lib/module/primitives/stack.styles.js +37 -0
  114. package/lib/module/primitives/stack.styles.js.map +1 -0
  115. package/lib/module/primitives/tag.styles.js +56 -0
  116. package/lib/module/primitives/tag.styles.js.map +1 -0
  117. package/lib/module/primitives/text.styles.js +33 -0
  118. package/lib/module/primitives/text.styles.js.map +1 -0
  119. package/lib/module/theme/ThemeProvider.js +41 -0
  120. package/lib/module/theme/ThemeProvider.js.map +1 -0
  121. package/lib/module/theme/index.js +19 -0
  122. package/lib/module/theme/index.js.map +1 -0
  123. package/lib/module/theme/native-theme.js +201 -0
  124. package/lib/module/theme/native-theme.js.map +1 -0
  125. package/lib/module/theme/types.js +4 -0
  126. package/lib/module/theme/types.js.map +1 -0
  127. package/lib/typescript/package.json +1 -0
  128. package/lib/typescript/src/components/ActionSheet.d.ts +45 -0
  129. package/lib/typescript/src/components/ActionSheet.d.ts.map +1 -0
  130. package/lib/typescript/src/components/Alert.d.ts +43 -0
  131. package/lib/typescript/src/components/Alert.d.ts.map +1 -0
  132. package/lib/typescript/src/components/Avatar.d.ts +45 -0
  133. package/lib/typescript/src/components/Avatar.d.ts.map +1 -0
  134. package/lib/typescript/src/components/BottomSheet.d.ts +36 -0
  135. package/lib/typescript/src/components/BottomSheet.d.ts.map +1 -0
  136. package/lib/typescript/src/components/Card.d.ts +46 -0
  137. package/lib/typescript/src/components/Card.d.ts.map +1 -0
  138. package/lib/typescript/src/components/Checkbox.d.ts +40 -0
  139. package/lib/typescript/src/components/Checkbox.d.ts.map +1 -0
  140. package/lib/typescript/src/components/EmptyState.d.ts +36 -0
  141. package/lib/typescript/src/components/EmptyState.d.ts.map +1 -0
  142. package/lib/typescript/src/components/Header.d.ts +34 -0
  143. package/lib/typescript/src/components/Header.d.ts.map +1 -0
  144. package/lib/typescript/src/components/Image.d.ts +41 -0
  145. package/lib/typescript/src/components/Image.d.ts.map +1 -0
  146. package/lib/typescript/src/components/Modal.d.ts +46 -0
  147. package/lib/typescript/src/components/Modal.d.ts.map +1 -0
  148. package/lib/typescript/src/components/Progress.d.ts +39 -0
  149. package/lib/typescript/src/components/Progress.d.ts.map +1 -0
  150. package/lib/typescript/src/components/Radio.d.ts +52 -0
  151. package/lib/typescript/src/components/Radio.d.ts.map +1 -0
  152. package/lib/typescript/src/components/Screen.d.ts +42 -0
  153. package/lib/typescript/src/components/Screen.d.ts.map +1 -0
  154. package/lib/typescript/src/components/Skeleton.d.ts +37 -0
  155. package/lib/typescript/src/components/Skeleton.d.ts.map +1 -0
  156. package/lib/typescript/src/components/Surface.d.ts +31 -0
  157. package/lib/typescript/src/components/Surface.d.ts.map +1 -0
  158. package/lib/typescript/src/components/TextField.d.ts +45 -0
  159. package/lib/typescript/src/components/TextField.d.ts.map +1 -0
  160. package/lib/typescript/src/components/Toast.d.ts +45 -0
  161. package/lib/typescript/src/components/Toast.d.ts.map +1 -0
  162. package/lib/typescript/src/components/Toggle.d.ts +39 -0
  163. package/lib/typescript/src/components/Toggle.d.ts.map +1 -0
  164. package/lib/typescript/src/components/action-sheet.styles.d.ts +65 -0
  165. package/lib/typescript/src/components/action-sheet.styles.d.ts.map +1 -0
  166. package/lib/typescript/src/components/alert.styles.d.ts +61 -0
  167. package/lib/typescript/src/components/alert.styles.d.ts.map +1 -0
  168. package/lib/typescript/src/components/avatar.styles.d.ts +60 -0
  169. package/lib/typescript/src/components/avatar.styles.d.ts.map +1 -0
  170. package/lib/typescript/src/components/bottom-sheet.styles.d.ts +50 -0
  171. package/lib/typescript/src/components/bottom-sheet.styles.d.ts.map +1 -0
  172. package/lib/typescript/src/components/card.styles.d.ts +27 -0
  173. package/lib/typescript/src/components/card.styles.d.ts.map +1 -0
  174. package/lib/typescript/src/components/checkbox.styles.d.ts +55 -0
  175. package/lib/typescript/src/components/checkbox.styles.d.ts.map +1 -0
  176. package/lib/typescript/src/components/empty-state.styles.d.ts +58 -0
  177. package/lib/typescript/src/components/empty-state.styles.d.ts.map +1 -0
  178. package/lib/typescript/src/components/header.styles.d.ts +30 -0
  179. package/lib/typescript/src/components/header.styles.d.ts.map +1 -0
  180. package/lib/typescript/src/components/image.styles.d.ts +28 -0
  181. package/lib/typescript/src/components/image.styles.d.ts.map +1 -0
  182. package/lib/typescript/src/components/index.d.ts +23 -0
  183. package/lib/typescript/src/components/index.d.ts.map +1 -0
  184. package/lib/typescript/src/components/modal.styles.d.ts +66 -0
  185. package/lib/typescript/src/components/modal.styles.d.ts.map +1 -0
  186. package/lib/typescript/src/components/progress.styles.d.ts +44 -0
  187. package/lib/typescript/src/components/progress.styles.d.ts.map +1 -0
  188. package/lib/typescript/src/components/radio.styles.d.ts +91 -0
  189. package/lib/typescript/src/components/radio.styles.d.ts.map +1 -0
  190. package/lib/typescript/src/components/screen.styles.d.ts +34 -0
  191. package/lib/typescript/src/components/screen.styles.d.ts.map +1 -0
  192. package/lib/typescript/src/components/skeleton.styles.d.ts +105 -0
  193. package/lib/typescript/src/components/skeleton.styles.d.ts.map +1 -0
  194. package/lib/typescript/src/components/surface.styles.d.ts +31 -0
  195. package/lib/typescript/src/components/surface.styles.d.ts.map +1 -0
  196. package/lib/typescript/src/components/textfield.styles.d.ts +75 -0
  197. package/lib/typescript/src/components/textfield.styles.d.ts.map +1 -0
  198. package/lib/typescript/src/components/toast.styles.d.ts +62 -0
  199. package/lib/typescript/src/components/toast.styles.d.ts.map +1 -0
  200. package/lib/typescript/src/components/toggle.styles.d.ts +53 -0
  201. package/lib/typescript/src/components/toggle.styles.d.ts.map +1 -0
  202. package/lib/typescript/src/contracts/contract-types.d.ts +193 -0
  203. package/lib/typescript/src/contracts/contract-types.d.ts.map +1 -0
  204. package/lib/typescript/src/icons/Icon.d.ts +40 -0
  205. package/lib/typescript/src/icons/Icon.d.ts.map +1 -0
  206. package/lib/typescript/src/icons/glyphs.d.ts +259 -0
  207. package/lib/typescript/src/icons/glyphs.d.ts.map +1 -0
  208. package/lib/typescript/src/icons/icon.styles.d.ts +20 -0
  209. package/lib/typescript/src/icons/icon.styles.d.ts.map +1 -0
  210. package/lib/typescript/src/icons/index.d.ts +12 -0
  211. package/lib/typescript/src/icons/index.d.ts.map +1 -0
  212. package/lib/typescript/src/index.d.ts +12 -0
  213. package/lib/typescript/src/index.d.ts.map +1 -0
  214. package/lib/typescript/src/primitives/Button.d.ts +48 -0
  215. package/lib/typescript/src/primitives/Button.d.ts.map +1 -0
  216. package/lib/typescript/src/primitives/Metric.d.ts +38 -0
  217. package/lib/typescript/src/primitives/Metric.d.ts.map +1 -0
  218. package/lib/typescript/src/primitives/Row.d.ts +37 -0
  219. package/lib/typescript/src/primitives/Row.d.ts.map +1 -0
  220. package/lib/typescript/src/primitives/Stack.d.ts +33 -0
  221. package/lib/typescript/src/primitives/Stack.d.ts.map +1 -0
  222. package/lib/typescript/src/primitives/Tag.d.ts +43 -0
  223. package/lib/typescript/src/primitives/Tag.d.ts.map +1 -0
  224. package/lib/typescript/src/primitives/Text.d.ts +45 -0
  225. package/lib/typescript/src/primitives/Text.d.ts.map +1 -0
  226. package/lib/typescript/src/primitives/_internal/focus-ring.d.ts +31 -0
  227. package/lib/typescript/src/primitives/_internal/focus-ring.d.ts.map +1 -0
  228. package/lib/typescript/src/primitives/button.styles.d.ts +29 -0
  229. package/lib/typescript/src/primitives/button.styles.d.ts.map +1 -0
  230. package/lib/typescript/src/primitives/index.d.ts +8 -0
  231. package/lib/typescript/src/primitives/index.d.ts.map +1 -0
  232. package/lib/typescript/src/primitives/metric.styles.d.ts +43 -0
  233. package/lib/typescript/src/primitives/metric.styles.d.ts.map +1 -0
  234. package/lib/typescript/src/primitives/row.styles.d.ts +50 -0
  235. package/lib/typescript/src/primitives/row.styles.d.ts.map +1 -0
  236. package/lib/typescript/src/primitives/stack.styles.d.ts +34 -0
  237. package/lib/typescript/src/primitives/stack.styles.d.ts.map +1 -0
  238. package/lib/typescript/src/primitives/tag.styles.d.ts +32 -0
  239. package/lib/typescript/src/primitives/tag.styles.d.ts.map +1 -0
  240. package/lib/typescript/src/primitives/text.styles.d.ts +26 -0
  241. package/lib/typescript/src/primitives/text.styles.d.ts.map +1 -0
  242. package/lib/typescript/src/theme/ThemeProvider.d.ts +32 -0
  243. package/lib/typescript/src/theme/ThemeProvider.d.ts.map +1 -0
  244. package/lib/typescript/src/theme/index.d.ts +15 -0
  245. package/lib/typescript/src/theme/index.d.ts.map +1 -0
  246. package/lib/typescript/src/theme/native-theme.d.ts +3 -0
  247. package/lib/typescript/src/theme/native-theme.d.ts.map +1 -0
  248. package/lib/typescript/src/theme/types.d.ts +121 -0
  249. package/lib/typescript/src/theme/types.d.ts.map +1 -0
  250. package/package.json +120 -0
  251. package/src/components/ActionSheet.tsx +112 -0
  252. package/src/components/Alert.tsx +84 -0
  253. package/src/components/Avatar.tsx +110 -0
  254. package/src/components/BottomSheet.tsx +81 -0
  255. package/src/components/Card.tsx +102 -0
  256. package/src/components/Checkbox.tsx +107 -0
  257. package/src/components/EmptyState.tsx +64 -0
  258. package/src/components/Header.tsx +51 -0
  259. package/src/components/Image.tsx +89 -0
  260. package/src/components/Modal.tsx +113 -0
  261. package/src/components/Progress.tsx +124 -0
  262. package/src/components/Radio.tsx +151 -0
  263. package/src/components/Screen.tsx +62 -0
  264. package/src/components/Skeleton.tsx +154 -0
  265. package/src/components/Surface.tsx +37 -0
  266. package/src/components/TextField.tsx +102 -0
  267. package/src/components/Toast.tsx +103 -0
  268. package/src/components/Toggle.tsx +94 -0
  269. package/src/components/action-sheet.styles.ts +102 -0
  270. package/src/components/alert.styles.ts +115 -0
  271. package/src/components/avatar.styles.ts +110 -0
  272. package/src/components/bottom-sheet.styles.ts +78 -0
  273. package/src/components/card.styles.ts +56 -0
  274. package/src/components/checkbox.styles.ts +83 -0
  275. package/src/components/empty-state.styles.ts +98 -0
  276. package/src/components/header.styles.ts +44 -0
  277. package/src/components/image.styles.ts +36 -0
  278. package/src/components/index.ts +23 -0
  279. package/src/components/modal.styles.ts +106 -0
  280. package/src/components/progress.styles.ts +74 -0
  281. package/src/components/radio.styles.ts +132 -0
  282. package/src/components/screen.styles.ts +44 -0
  283. package/src/components/skeleton.styles.ts +155 -0
  284. package/src/components/surface.styles.ts +50 -0
  285. package/src/components/textfield.styles.ts +135 -0
  286. package/src/components/toast.styles.ts +115 -0
  287. package/src/components/toggle.styles.ts +73 -0
  288. package/src/contracts/contract-types.ts +199 -0
  289. package/src/icons/Icon.tsx +65 -0
  290. package/src/icons/glyphs.ts +54 -0
  291. package/src/icons/icon.styles.ts +37 -0
  292. package/src/icons/index.ts +12 -0
  293. package/src/index.ts +24 -0
  294. package/src/primitives/Button.tsx +114 -0
  295. package/src/primitives/Metric.tsx +67 -0
  296. package/src/primitives/Row.tsx +54 -0
  297. package/src/primitives/Stack.tsx +42 -0
  298. package/src/primitives/Tag.tsx +126 -0
  299. package/src/primitives/Text.tsx +71 -0
  300. package/src/primitives/_internal/focus-ring.tsx +59 -0
  301. package/src/primitives/button.styles.ts +69 -0
  302. package/src/primitives/index.ts +8 -0
  303. package/src/primitives/metric.styles.ts +75 -0
  304. package/src/primitives/row.styles.ts +66 -0
  305. package/src/primitives/stack.styles.ts +47 -0
  306. package/src/primitives/tag.styles.ts +65 -0
  307. package/src/primitives/text.styles.ts +42 -0
  308. package/src/theme/ThemeProvider.tsx +60 -0
  309. package/src/theme/index.ts +18 -0
  310. package/src/theme/native-theme.ts +215 -0
  311. package/src/theme/types.ts +137 -0
@@ -0,0 +1,199 @@
1
+ // ⚠️ 自動生成ファイル — 手で編集しないこと。
2
+ // 生成元: scripts/generate-contract-types.ts(入力 melta-contracts/components/*.contract.json)
3
+ // 各 component の variant/size/state を contract から codegen した型 + 実行時メタ(__contract 用)。
4
+
5
+ /** 各 contract メタの shape(§2 A-3: 生成結果が shape から逸脱したら型で検知する)。 */
6
+ export interface ContractShape {
7
+ id: string;
8
+ version: string;
9
+ variants: readonly string[];
10
+ sizes: readonly string[];
11
+ states: readonly string[];
12
+ }
13
+
14
+ export const CONTRACTS = {
15
+ text: {
16
+ id: "text",
17
+ version: "0.1.0",
18
+ variants: ["xs", "sm", "base", "lg", "xl", "2xl", "3xl"],
19
+ sizes: [],
20
+ states: ["default"],
21
+ },
22
+ button: {
23
+ id: "button",
24
+ version: "2.0.0",
25
+ variants: ["contained", "outlined", "brand-outline", "neutral", "lighted", "danger", "subtle"],
26
+ sizes: ["small", "medium", "large"],
27
+ states: ["default", "hover", "focus", "disabled", "loading"],
28
+ },
29
+ tag: {
30
+ id: "tag",
31
+ version: "2.0.0",
32
+ variants: ["basic", "removable", "filter-chip"],
33
+ sizes: [],
34
+ states: ["default", "active", "inactive", "hover", "focus"],
35
+ },
36
+ card: {
37
+ id: "card",
38
+ version: "2.0.0",
39
+ variants: ["basic", "media", "action", "link"],
40
+ sizes: [],
41
+ states: ["default", "hover", "focus-within"],
42
+ },
43
+ image: {
44
+ id: "image",
45
+ version: "0.1.0",
46
+ variants: ["default"],
47
+ sizes: [],
48
+ states: ["default", "error"],
49
+ },
50
+ surface: {
51
+ id: "surface",
52
+ version: "0.1.0",
53
+ variants: ["default"],
54
+ sizes: [],
55
+ states: ["default"],
56
+ },
57
+ skeleton: {
58
+ id: "skeleton",
59
+ version: "2.0.0",
60
+ variants: ["text", "card", "circle"],
61
+ sizes: [],
62
+ states: ["default", "loading", "loaded"],
63
+ },
64
+ emptyState: {
65
+ id: "empty-state",
66
+ version: "0.1.0",
67
+ variants: ["default"],
68
+ sizes: [],
69
+ states: ["default"],
70
+ },
71
+ metric: {
72
+ id: "metric",
73
+ version: "0.1.0",
74
+ variants: ["default"],
75
+ sizes: ["sm", "md", "lg"],
76
+ states: ["default"],
77
+ },
78
+ stack: {
79
+ id: "stack",
80
+ version: "0.1.0",
81
+ variants: ["default"],
82
+ sizes: [],
83
+ states: ["default"],
84
+ },
85
+ row: {
86
+ id: "row",
87
+ version: "0.1.0",
88
+ variants: ["default"],
89
+ sizes: [],
90
+ states: ["default"],
91
+ },
92
+ screen: {
93
+ id: "screen",
94
+ version: "0.1.0",
95
+ variants: ["fixed", "scroll"],
96
+ sizes: [],
97
+ states: ["default"],
98
+ },
99
+ header: {
100
+ id: "header",
101
+ version: "0.1.0",
102
+ variants: ["default"],
103
+ sizes: [],
104
+ states: ["default"],
105
+ },
106
+ icon: {
107
+ id: "icon",
108
+ version: "0.1.0",
109
+ variants: ["default"],
110
+ sizes: ["sm", "md", "lg"],
111
+ states: ["default"],
112
+ },
113
+ avatar: {
114
+ id: "avatar",
115
+ version: "2.0.0",
116
+ variants: ["image", "initials", "group"],
117
+ sizes: ["small", "medium", "large"],
118
+ states: ["default", "online", "away", "offline"],
119
+ },
120
+ textfield: {
121
+ id: "textfield",
122
+ version: "2.0.0",
123
+ variants: ["default", "error", "disabled", "success"],
124
+ sizes: ["small", "medium", "large"],
125
+ states: ["default", "hover", "focus", "error", "disabled", "success"],
126
+ },
127
+ toggle: {
128
+ id: "toggle",
129
+ version: "2.0.0",
130
+ variants: ["off", "on"],
131
+ sizes: ["medium", "large"],
132
+ states: ["off", "on", "hover", "focus", "disabled"],
133
+ },
134
+ checkbox: {
135
+ id: "checkbox",
136
+ version: "2.0.0",
137
+ variants: ["default", "disabled", "indeterminate"],
138
+ sizes: [],
139
+ states: ["default", "checked", "unchecked", "indeterminate", "disabled", "error", "focus"],
140
+ },
141
+ radio: {
142
+ id: "radio",
143
+ version: "2.0.0",
144
+ variants: ["vertical", "horizontal", "card-style"],
145
+ sizes: [],
146
+ states: ["default", "selected", "unselected", "disabled", "error", "focus"],
147
+ },
148
+ alert: {
149
+ id: "alert",
150
+ version: "2.0.0",
151
+ variants: ["info", "success", "warning", "error"],
152
+ sizes: [],
153
+ states: ["default", "dismissing"],
154
+ },
155
+ toast: {
156
+ id: "toast",
157
+ version: "2.0.0",
158
+ variants: ["success", "error", "warning", "info"],
159
+ sizes: [],
160
+ states: ["default", "entering", "visible", "dismissing", "hover"],
161
+ },
162
+ progress: {
163
+ id: "progress",
164
+ version: "2.0.0",
165
+ variants: ["primary", "success", "indeterminate"],
166
+ sizes: [],
167
+ states: ["default", "determinate", "indeterminate", "complete"],
168
+ },
169
+ modal: {
170
+ id: "modal",
171
+ version: "2.0.0",
172
+ variants: ["confirmation", "form", "alert"],
173
+ sizes: ["small", "medium", "large"],
174
+ states: ["default", "open", "closing"],
175
+ },
176
+ actionSheet: {
177
+ id: "action-sheet",
178
+ version: "0.1.0",
179
+ variants: ["default"],
180
+ sizes: [],
181
+ states: ["default"],
182
+ },
183
+ bottomSheet: {
184
+ id: "bottom-sheet",
185
+ version: "0.1.0",
186
+ variants: ["default"],
187
+ sizes: [],
188
+ states: ["default"],
189
+ },
190
+ } as const satisfies Record<string, ContractShape>;
191
+
192
+ export type ContractId = keyof typeof CONTRACTS;
193
+
194
+ /** contract の variant キー union(例: VariantOf<"text"> = "xs" | ... | "3xl")。空なら never。 */
195
+ export type VariantOf<K extends ContractId> = (typeof CONTRACTS)[K]["variants"][number];
196
+ /** contract の size キー union(空なら never)。 */
197
+ export type SizeOf<K extends ContractId> = (typeof CONTRACTS)[K]["sizes"][number];
198
+ /** contract の state キー union。 */
199
+ export type StateOf<K extends ContractId> = (typeof CONTRACTS)[K]["states"][number];
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Icon — 統一アイコン primitive(Charcoal Icons、単色 tint)。
3
+ * contract: icon(app 先行定義、melta-contracts)。dogfood 不足-2(絵文字・生 Text 代用)の解消。
4
+ *
5
+ * ⚠️ 依存境界: このファイルだけが react-native-svg を import する。melta-app 本体エントリ
6
+ * ("melta-app")は依存ゼロを維持し、Icon は subpath エントリ "melta-app/icons" からだけ
7
+ * export される(optional peerDependency。利用者は `npx expo install react-native-svg` が必要)。
8
+ *
9
+ * - name は glyphs.ts(assets/icons/*.svg からの codegen、commit 済み配布)のキー。
10
+ * - color は semantic token キー限定(default "text-default")、size は contract sizes(sm/md/lg)。
11
+ * - a11y: 意味を持つ場合は accessibilityLabel を渡す。無指定は装飾扱いで a11y ツリーから除外
12
+ * (contract a11y required の両ケース)。
13
+ * - 決定ロジックは pure resolver(icon.styles.ts)に分離 — recipe との機械照合対象。
14
+ */
15
+
16
+ import { useMemo } from "react";
17
+ import Svg, { Path } from "react-native-svg";
18
+ import { useTheme } from "../theme";
19
+ import type { SemanticColors } from "../theme";
20
+ import { CONTRACTS, type SizeOf } from "../contracts/contract-types";
21
+ import { resolveIconStyle, type IconStyle } from "./icon.styles";
22
+ import { GLYPHS, type IconName } from "./glyphs";
23
+
24
+ interface IconProps {
25
+ /** グリフ名(glyphs.ts のキー。例 "close" / "share-ios")。 */
26
+ name: IconName;
27
+ /** サイズ(contract sizes)。default "md"(20px)。 */
28
+ size?: SizeOf<"icon">;
29
+ /** 色(semantic token キーのみ)。default "text-default"。 */
30
+ color?: keyof SemanticColors;
31
+ /** 意味を持つ icon は必須。省略時は装飾扱い(a11y ツリーから除外)。 */
32
+ accessibilityLabel?: string;
33
+ testID?: string;
34
+ }
35
+
36
+ export function Icon({ name, size = "md", color = "text-default", accessibilityLabel, testID }: IconProps) {
37
+ const { theme, mode } = useTheme();
38
+
39
+ const resolved = useMemo<IconStyle>(
40
+ () => resolveIconStyle(theme, mode, size, color),
41
+ [theme, mode, size, color],
42
+ );
43
+ const glyph = GLYPHS[name];
44
+ const decorative = accessibilityLabel == null;
45
+
46
+ return (
47
+ <Svg
48
+ width={resolved.width}
49
+ height={resolved.height}
50
+ viewBox={glyph.viewBox}
51
+ accessible={!decorative}
52
+ accessibilityRole="image"
53
+ accessibilityLabel={accessibilityLabel}
54
+ accessibilityElementsHidden={decorative}
55
+ importantForAccessibility={decorative ? "no-hide-descendants" : "yes"}
56
+ testID={testID}
57
+ >
58
+ {glyph.paths.map((p, i) => (
59
+ <Path key={i} d={p.d} fillRule={p.fillRule} fill={resolved.color} />
60
+ ))}
61
+ </Svg>
62
+ );
63
+ }
64
+
65
+ Icon.__contract = CONTRACTS.icon;
@@ -0,0 +1,54 @@
1
+ // ⚠️ 自動生成ファイル — 手で編集しないこと。
2
+ // 生成元: scripts/generate-icons.ts(入力 assets/icons/*.svg = Charcoal Icons, Apache-2.0)
3
+ // 帰属表示は THIRD_PARTY_LICENSES.md を参照。
4
+
5
+ export interface Glyph {
6
+ viewBox: string;
7
+ paths: readonly { d: string; fillRule?: "evenodd" }[];
8
+ }
9
+
10
+ const GLYPHS_SOURCE = {
11
+ "add": { viewBox: "0 0 24 24", paths: [{ d: "M14 10h4a2 2 0 110 4h-4v4a2 2 0 11-4 0v-4H6a2 2 0 110-4h4V6a2 2 0 114 0v4z" }] },
12
+ "back": { viewBox: "0 0 16 16", paths: [{ d: "M9.961 11.043a1 1 0 01-1.414 1.414L4.09 8l4.457-4.457a1 1 0 011.414 1.414L6.918 8l3.043 3.043z" }] },
13
+ "calendar": { viewBox: "0 0 24 24", paths: [{ d: "M8 3a1 1 0 00-2 0v1.126C4.275 4.57 3 6.136 3 8v10a4 4 0 004 4h10a4 4 0 004-4V8a4.002 4.002 0 00-3-3.874V3a1 1 0 10-2 0v1H8V3zm-3 7v8a2 2 0 002 2h10a2 2 0 002-2v-8H5z", fillRule: "evenodd" as const }] },
14
+ "camera": { viewBox: "0 0 24 24", paths: [{ d: "M8.5 13.5a3.5 3.5 0 117 0 3.5 3.5 0 01-7 0z" }, { d: "M9.295 3.557A2 2 0 0110.68 3h2.742a2 2 0 011.414.586L17.25 6H20a2 2 0 012 2v11a2 2 0 01-2 2H4a2 2 0 01-2-2V8a2 2 0 012-2h2.75l2.545-2.443zM12 8a5.5 5.5 0 100 11 5.5 5.5 0 000-11z", fillRule: "evenodd" as const }] },
15
+ "check": { viewBox: "0 0 24 24", paths: [{ d: "M15.848 7.449a2 2 0 012.804 2.853l-8.664 8.514-4.402-4.402a2 2 0 112.828-2.828l1.598 1.598 5.836-5.735z" }] },
16
+ "close": { viewBox: "0 0 24 24", paths: [{ d: "M8.414 5.586a2 2 0 10-2.828 2.828L9.172 12l-3.586 3.586a2 2 0 102.828 2.828L12 14.828l3.586 3.586a2 2 0 102.828-2.828L14.828 12l3.586-3.586a2 2 0 10-2.828-2.828L12 9.172 8.414 5.586z" }] },
17
+ "comment": { viewBox: "0 0 16 16", paths: [{ d: "M5.4 13.409l-2.64.377.333-2.332a6 6 0 112.306 1.955z" }] },
18
+ "copy": { viewBox: "0 0 24 24", paths: [{ d: "M3 7a1 1 0 011 1v10a2 2 0 002 2h11a1 1 0 110 2H6a4 4 0 01-4-4V8a1 1 0 011-1z" }, { d: "M19 2a3 3 0 013 3v10a3 3 0 01-3 3H9a3 3 0 01-3-3V5a3 3 0 013-3h10zM9 4a1 1 0 00-1 1v10a1 1 0 001 1h10a1 1 0 001-1V5a1 1 0 00-1-1H9z", fillRule: "evenodd" as const }] },
19
+ "discovery": { viewBox: "0 0 24 24", paths: [{ d: "M22 12c0 5.523-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2s10 4.477 10 10zM6 18l4-8 8-4-4 8-8 4zm6-5a1 1 0 100-2 1 1 0 000 2z", fillRule: "evenodd" as const }] },
20
+ "down": { viewBox: "0 0 24 24", paths: [{ d: "M16.125 12V5a1 1 0 00-1-1h-6a1 1 0 00-1 1v7H4.539c-.89 0-1.337 1.077-.707 1.707L12.125 22l8.194-8.297c.623-.632.176-1.703-.712-1.703h-3.482z", fillRule: "evenodd" as const }] },
21
+ "edit": { viewBox: "0 0 32 32", paths: [{ d: "M7.26 23.537l1.12-5.6 7.955-7.955 5.657 5.657 1.768-1.768-5.657-5.657 2.121-2.121a2 2 0 012.828 0l2.829 2.828a2 2 0 010 2.829L14.037 23.594l-5.6 1.12a1 1 0 01-1.177-1.177z", fillRule: "evenodd" as const }] },
22
+ "error": { viewBox: "0 0 24 24", paths: [{ d: "M12 4a2 2 0 00-2 2v6.5a2 2 0 104 0V6a2 2 0 00-2-2zm2.25 13.75a2.25 2.25 0 11-4.5 0 2.25 2.25 0 014.5 0z", fillRule: "evenodd" as const }] },
23
+ "filter": { viewBox: "0 0 24 24", paths: [{ d: "M10.5 13.468L3.574 6.4C2.335 5.133 3.232 3 5.005 3h13.99c1.773 0 2.67 2.133 1.43 3.4L13.5 13.467V19a3 3 0 01-3.002 3v-8.532z" }] },
24
+ "home": { viewBox: "0 0 24 24", paths: [{ d: "M9 19a1 1 0 01-1 1H4a1 1 0 01-1-1v-7.586a1 1 0 01.293-.707l8-8a1 1 0 011.414 0l8 8a1 1 0 01.293.707V19a1 1 0 01-1 1h-4a1 1 0 01-1-1v-3.5a3 3 0 10-6 0V19z", fillRule: "evenodd" as const }] },
25
+ "image": { viewBox: "0 0 24 24", paths: [{ d: "M6 4a3 3 0 00-3 3v10a3 3 0 003 3h12a3 3 0 003-3V7a3 3 0 00-3-3H6zm13 8.5l-4 2-6-3-4 2V17a1 1 0 001 1h12a1 1 0 001-1v-4.5zM18 9a2 2 0 11-4 0 2 2 0 014 0z", fillRule: "evenodd" as const }] },
26
+ "info": { viewBox: "0 0 24 24", paths: [{ d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2.5 9a1 1 0 011-1H12a1 1 0 011 1v5h1a1 1 0 110 2h-4a1 1 0 110-2h1v-4h-.5a1 1 0 01-1-1zM12 5a1.5 1.5 0 100 3 1.5 1.5 0 000-3z", fillRule: "evenodd" as const }] },
27
+ "like-off": { viewBox: "0 0 24 24", paths: [{ d: "M13.087 21.021C18.792 17.831 22 13.81 22 8.91A5.91 5.91 0 0016.09 3c-1.529 0-2.976.747-4.09 1.834C10.886 3.747 9.439 3 7.91 3A5.91 5.91 0 002 8.91c0 4.9 3.208 8.92 8.913 12.111a2.227 2.227 0 002.174 0zM16.09 5A3.91 3.91 0 0120 8.91c0 3.86-2.482 7.342-7.889 10.366a.229.229 0 01-.222 0C6.482 16.252 4 12.77 4 8.91A3.91 3.91 0 017.91 5c1.115 0 2.38.723 3.287 1.943L12 8.021l.803-1.078C13.71 5.723 14.975 5 16.09 5z", fillRule: "evenodd" as const }] },
28
+ "like-on": { viewBox: "0 0 24 24", paths: [{ d: "M2 9.023A6.023 6.023 0 018.023 3c1.486 0 2.88.68 3.977 1.677C13.096 3.68 14.49 3 15.977 3A6.023 6.023 0 0122 9.023c0 4.908-3.22 8.893-8.807 12.018a2.443 2.443 0 01-2.386 0C5.22 17.916 2 13.931 2 9.023z", fillRule: "evenodd" as const }] },
29
+ "link": { viewBox: "0 0 24 24", paths: [{ d: "M14.031 3.367a4.666 4.666 0 116.6 6.598l-4.243 4.243a4.665 4.665 0 01-2.163 1.226h-.037l-.193.04-.107.02-.23.034h-.113c-.05 0-.097.005-.142.01a1.296 1.296 0 01-.095.01l-.2.023h-.253a4.616 4.616 0 01-.497-.047 5.356 5.356 0 01-.403-.083l-.197-.053a2.64 2.64 0 01-.213-.07l-.078-.029c-.045-.016-.09-.032-.135-.051a4.71 4.71 0 00-.07-.03 4.627 4.627 0 01-1.473-.994 1.333 1.333 0 010-1.879 1.366 1.366 0 011.873 0 2 2 0 002.826 0l1.093-1.086.027-.03 3.126-3.123a2 2 0 00-2.83-2.83l-2.51 2.507a.333.333 0 01-.362.073 5.6 5.6 0 00-2.13-.417h-.123a.333.333 0 01-.243-.57l3.495-3.492z" }, { d: "M13.418 9.166c.284.18.547.391.784.63.27.27.41.644.386 1.026-.023.32-.16.62-.386.847a1.366 1.366 0 01-1.873 0 2 2 0 00-2.827 0L5.246 15.92a2 2 0 002.83 2.83l2.516-2.52a.333.333 0 01.363-.073 5.612 5.612 0 002.133.413h.134a.333.333 0 01.236.57l-3.5 3.5A4.636 4.636 0 016.664 22a4.666 4.666 0 01-3.3-7.962l4.24-4.242a4.666 4.666 0 015.816-.63z" }] },
30
+ "menu": { viewBox: "0 0 24 24", paths: [{ d: "M4 7a1 1 0 011-1h14a1 1 0 110 2H5a1 1 0 01-1-1zM4 12a1 1 0 011-1h14a1 1 0 110 2H5a1 1 0 01-1-1zM5 16a1 1 0 100 2h14a1 1 0 100-2H5z" }] },
31
+ "more": { viewBox: "0 0 16 16", paths: [{ d: "M6.043 4.957a1 1 0 011.414-1.414L11.914 8l-4.457 4.457a1 1 0 01-1.414-1.414L9.086 8 6.043 4.957z" }] },
32
+ "next": { viewBox: "0 0 24 24", paths: [{ d: "M8.086 16.586a2 2 0 102.828 2.828L18.328 12l-7.414-7.414a2 2 0 10-2.828 2.828L12.672 12l-4.586 4.586z" }] },
33
+ "notification": { viewBox: "0 0 24 24", paths: [{ d: "M18 9.25V12l1.561 4.684A1 1 0 0118.613 18H5.387a1 1 0 01-.948-1.316L6 12V9.25C6 5.798 8.686 3 12 3s6 2.798 6 6.25zM12 21a3.001 3.001 0 01-2.83-2h5.66A3.001 3.001 0 0112 21z" }] },
34
+ "prev": { viewBox: "0 0 24 24", paths: [{ d: "M15.913 16.586a2 2 0 01-2.829 2.828L5.67 12l7.414-7.414a2 2 0 012.829 2.828L11.327 12l4.586 4.586z" }] },
35
+ "question": { viewBox: "0 0 24 24", paths: [{ d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1.179 15.254a1.25 1.25 0 11-2.5 0 1.25 1.25 0 012.5 0zm.058-3.98c.01-.02.02-.04.03-.05.272-.4.651-.732 1.036-1.069.886-.777 1.8-1.579 1.494-3.281-.29-1.69-1.64-3.08-3.33-3.33-2.06-.3-3.88.97-4.43 2.79-.17.58.27 1.17.87 1.17h.2c.41 0 .74-.29.88-.65.32-.89 1.26-1.5 2.3-1.28.96.2 1.66 1.15 1.57 2.13-.068.763-.613 1.186-1.219 1.654-.377.293-.778.603-1.101 1.026l-.01-.01a.326.326 0 00-.046.066 1.302 1.302 0 01-.084.129 2.261 2.261 0 00-.27.515.156.156 0 01-.025.05c-.01.015-.02.03-.025.05-.01.01-.01.02-.01.03-.12.36-.2.79-.2 1.3h2.01a2.11 2.11 0 01.18-.89c.01-.04.02-.08.04-.11.04-.08.09-.16.14-.24z", fillRule: "evenodd" as const }] },
36
+ "reload": { viewBox: "0 0 24 24", paths: [{ d: "M12 7a6 6 0 106 6 1 1 0 112 0 8 8 0 11-8-8h1.42l-1.7-2.125a1 1 0 111.56-1.25l3 3.75a1 1 0 010 1.25l-3 3.75a1 1 0 01-1.56-1.25L13.42 7H12z" }] },
37
+ "search": { viewBox: "0 0 24 24", paths: [{ d: "M15.461 10.615c0-1.334-.474-2.475-1.422-3.423-.948-.949-2.09-1.423-3.424-1.423s-2.475.474-3.423 1.423c-.949.948-1.423 2.09-1.423 3.423 0 1.335.474 2.476 1.423 3.424.948.948 2.09 1.422 3.423 1.422 1.335 0 2.476-.474 3.424-1.422s1.422-2.09 1.422-3.424zm5.539 9c0 .375-.137.7-.411.974a1.33 1.33 0 01-.974.411c-.389 0-.714-.137-.973-.411l-3.71-3.7a7.407 7.407 0 01-4.317 1.342c-1.03 0-2.017-.2-2.958-.6a7.613 7.613 0 01-2.434-1.623A7.614 7.614 0 013.6 13.574c-.4-.941-.6-1.927-.6-2.959 0-1.03.2-2.017.6-2.958.4-.941.941-1.753 1.623-2.434A7.614 7.614 0 017.657 3.6c.941-.4 1.927-.6 2.958-.6 1.032 0 2.018.2 2.959.6.941.4 1.752.941 2.434 1.623a7.613 7.613 0 011.622 2.434c.4.941.6 1.927.6 2.958a7.407 7.407 0 01-1.34 4.316l3.71 3.71c.267.268.4.592.4.974z", fillRule: "evenodd" as const }] },
38
+ "send": { viewBox: "0 0 24 24", paths: [{ d: "M3 13.5h5a1.5 1.5 0 000-3H3V3.695a1 1 0 011.466-.885l15.853 8.343a1 1 0 010 1.77L4.466 21.267A1 1 0 013 20.382V13.5z", fillRule: "evenodd" as const }] },
39
+ "settings": { viewBox: "0 0 24 24", paths: [{ d: "M19.5 12c0 .61.224 1.21.704 1.586l1.336 1.044c.19.15.24.42.12.64l-2 3.46c-.12.22-.38.31-.61.22l-1.589-.638c-.56-.225-1.186-.13-1.705.176-.528.31-.94.814-1.026 1.42l-.24 1.672c-.03.24-.24.42-.49.42h-4c-.25 0-.46-.18-.49-.42l-.24-1.68c-.087-.6-.495-1.098-1.02-1.404-.524-.305-1.156-.407-1.718-.181l-1.582.635c-.22.08-.49 0-.61-.22l-2-3.46a.505.505 0 01.12-.64l1.335-1.044c.48-.376.705-.976.705-1.586 0-.61-.224-1.21-.705-1.586L2.46 9.37a.493.493 0 01-.12-.64l2-3.46c.12-.22.38-.31.61-.22l1.588.638c.56.225 1.186.13 1.706-.176.528-.31.94-.814 1.026-1.42l.24-1.672c.03-.24.24-.42.49-.42h4c.25 0 .46.18.49.42l.24 1.68c.087.6.494 1.098 1.02 1.404.524.306 1.155.407 1.718.181l1.582-.635c.22-.08.49 0 .61.22l2 3.46c.12.22.07.49-.12.64l-1.336 1.044c-.48.376-.704.976-.704 1.586zm-11 0c0 1.93 1.57 3.5 3.5 3.5s3.5-1.57 3.5-3.5-1.57-3.5-3.5-3.5-3.5 1.57-3.5 3.5z", fillRule: "evenodd" as const }] },
40
+ "share-android": { viewBox: "0 0 24 24", paths: [{ d: "M13 6.375a2.75 2.75 0 111.03 2.146L8.72 11.586a2.773 2.773 0 010 .828l5.312 3.065a2.75 2.75 0 11-1 1.732l-5.312-3.065a2.75 2.75 0 110-4.293l5.312-3.064A2.773 2.773 0 0113 6.375z" }] },
41
+ "share-ios": { viewBox: "0 0 24 24", paths: [{ d: "M12 2.586L7.293 7.293a1 1 0 001.414 1.414L11 6.414V13a1 1 0 102 0V6.414l2.293 2.293a1 1 0 101.414-1.414L12 2.586z" }, { d: "M6 18v-6H4v6a3 3 0 003 3h10a3 3 0 003-3v-6h-2v6a1 1 0 01-1 1H7a1 1 0 01-1-1z" }] },
42
+ "trash": { viewBox: "0 0 24 24", paths: [{ d: "M9 4h6v1h2.5a1 1 0 110 2h-11a1 1 0 010-2H9V4zM7.01 8a1 1 0 00-1 1.01l.105 10a1 1 0 001 .99H17a1 1 0 001-1V9a1 1 0 00-1-1H7.01z" }] },
43
+ "up": { viewBox: "0 0 24 24", paths: [{ d: "M16 12v7a1 1 0 01-1 1H9a1 1 0 01-1-1v-7H4.414c-.89 0-1.337-1.077-.707-1.707L12 2l8.194 8.297c.623.632.176 1.703-.712 1.703H16z", fillRule: "evenodd" as const }] },
44
+ "user": { viewBox: "0 0 32 32", paths: [{ d: "M21.39 11.357c0 2.959-2.386 5.357-5.328 5.357-2.941 0-5.326-2.398-5.326-5.357S13.12 6 16.062 6c2.942 0 5.327 2.398 5.327 5.357zm-5.328 5.357c4.315 0 7.813 3.402 7.813 7.598v.26c0 .788-.636 1.428-1.42 1.428H9.67c-.784 0-1.42-.64-1.42-1.429v-.26c0-4.195 3.498-7.597 7.813-7.597z", fillRule: "evenodd" as const }] },
45
+ "users": { viewBox: "0 0 24 24", paths: [{ d: "M7.507 10.5a3.75 3.75 0 10-.014 0C4.459 10.504 2 12.883 2 15.818 2 16.471 2.53 17 3.182 17h7.451a5.608 5.608 0 012.21-2.445c-.585-2.325-2.752-4.052-5.336-4.055zm8.993 4a3.75 3.75 0 100-7.5 3.75 3.75 0 000 7.5zm0 0c-3.038 0-5.5 2.381-5.5 5.318V20a1 1 0 001 1h9a1 1 0 001-1v-.182c0-2.937-2.462-5.318-5.5-5.318z", fillRule: "evenodd" as const }] },
46
+ "warning": { viewBox: "0 0 24 24", paths: [{ d: "M4.47 21h15.06c1.54 0 2.5-1.67 1.73-3L13.73 4.99c-.77-1.33-2.69-1.33-3.46 0L2.74 18c-.77 1.33.19 3 1.73 3zM11 9a1 1 0 112 0v4a1 1 0 11-2 0V9zm1 7a1.25 1.25 0 100 2.5 1.25 1.25 0 000-2.5z", fillRule: "evenodd" as const }] },
47
+ } as const;
48
+
49
+ export type IconName = keyof typeof GLYPHS_SOURCE;
50
+
51
+ export const GLYPHS: Record<IconName, Glyph> = GLYPHS_SOURCE;
52
+
53
+ /** 利用可能な icon name 一覧(catalog / ドキュメント生成用)。 */
54
+ export const ICON_NAMES = Object.keys(GLYPHS) as IconName[];
@@ -0,0 +1,37 @@
1
+ /**
2
+ * icon.styles — Icon の pure style resolver(styleRefs conformance 対応で Icon.tsx から分離)。
3
+ *
4
+ * react-native を import しない純粋モジュールにすることで node テスト(tsx --test)から
5
+ * 直接実行できる。recipes/app/icon.recipe.json(melta-contracts の styleRefs)との
6
+ * 機械照合は scripts/lib/icon-conformance.test.ts が行う。
7
+ */
8
+
9
+ import type { NativeTheme, SemanticColors, ThemeMode } from "../theme";
10
+
11
+ export type IconSize = "sm" | "md" | "lg";
12
+
13
+ /** サイズ軸(contract sizes の height と 1:1。width=height の正方形)。 */
14
+ const SIZE_TABLE = { sm: 16, md: 20, lg: 24 } as const;
15
+
16
+ export interface IconStyle {
17
+ width: number;
18
+ height: number;
19
+ color: string;
20
+ }
21
+
22
+ /**
23
+ * size / color → Icon style の解決(icon.recipe styleRefs の 1:1 写像)。
24
+ * デフォルト(size=md / color=text-default)は recipe の default variant と一致させている。
25
+ */
26
+ export function resolveIconStyle(
27
+ theme: NativeTheme,
28
+ mode: ThemeMode,
29
+ size: IconSize = "md",
30
+ color: keyof SemanticColors = "text-default",
31
+ ): IconStyle {
32
+ return {
33
+ width: SIZE_TABLE[size],
34
+ height: SIZE_TABLE[size],
35
+ color: theme.color.semantic[mode][color],
36
+ };
37
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * melta-app/icons — Icon の subpath エントリ。
3
+ *
4
+ * 本体エントリ("melta-app")から分離している理由: Icon だけが react-native-svg
5
+ * (optional peerDependency)に依存するため。Metro は import を静的に解決するので、
6
+ * 本体エントリに Icon を含めると react-native-svg 未 install の利用者がバンドルできなくなる。
7
+ * この subpath を import する利用者だけが react-native-svg を要求される。
8
+ */
9
+
10
+ export { Icon } from "./Icon";
11
+ export { GLYPHS, ICON_NAMES } from "./glyphs";
12
+ export type { IconName, Glyph } from "./glyphs";
package/src/index.ts ADDED
@@ -0,0 +1,24 @@
1
+ /**
2
+ * melta-app — melta デザインシステムの React Native 実装(公開エントリ)。
3
+ *
4
+ * 契約(npm: melta-contracts)を SSOT とし、theme(トークンの RN 正規化)/
5
+ * primitives / components がその契約を満たす。契約との整合は conformance テストが機械照合する。
6
+ * アプリ本体ではなく UI kit。使い方はルートを ThemeProvider で包み、コンポーネントを import する。
7
+ */
8
+
9
+ // theme: トークン(melta-contracts/tokens.json 由来、codegen 済み)+ Provider + helpers
10
+ export * from "./theme";
11
+
12
+ // primitives / components(契約 appStatus=implemented の集合と一致。conformance が担保)
13
+ export * from "./primitives";
14
+ export * from "./components";
15
+
16
+ // 契約メタ(variant/size/state の実行時参照 + 型。__contract 照合にも使う)
17
+ export {
18
+ CONTRACTS,
19
+ type ContractId,
20
+ type ContractShape,
21
+ type VariantOf,
22
+ type SizeOf,
23
+ type StateOf,
24
+ } from "./contracts/contract-types";
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Button — CTA / セカンダリ / アイコンボタン(設計書 §1, §4 C-3)。contract: button。
3
+ *
4
+ * - variant 7(contained/outlined/brand-outline/neutral/lighted/danger/subtle)× size 3(small/medium/large)。
5
+ * - iconOnly は discriminated union で accessibilityLabel 必須を型強制(§4、label 排他)。
6
+ * - states(§2 mapping): hover→pressed(背景を pressed 色に)、focus→FocusRing overlay(共通 helper)、
7
+ * disabled→prop(opacity + 非活性)、loading→Spinner + disabled 相当。
8
+ * - 色は variant ごとに NativeTheme から解決(button.contract tokenRefs を 1:1 で写像)。
9
+ * contained の pressed は hover-bg=primary.700(contract に native readable token あり、唯一)。
10
+ * 他 variant の pressed 視覚変化は contract が Tailwind のみ=Phase1 non-conformant(§2 M-1)、
11
+ * ここでは pressed 時に薄い overlay を敷く近似に留め、Phase2 で contract に pressed-* token 追加。
12
+ * - height は contract sizes(small32/medium40/large48)。
13
+ */
14
+
15
+ import { useMemo, type ReactNode } from "react";
16
+ import {
17
+ ActivityIndicator,
18
+ Pressable,
19
+ View,
20
+ type StyleProp,
21
+ type ViewStyle,
22
+ } from "react-native";
23
+ import { Text } from "./Text";
24
+ import { useTheme } from "../theme";
25
+ import { useFocusRing, FocusRing } from "./_internal/focus-ring";
26
+ import { CONTRACTS } from "../contracts/contract-types";
27
+ import { SIZE_SPEC, resolveVariant, type ButtonVariant, type ButtonSize } from "./button.styles";
28
+
29
+ interface ButtonBase {
30
+ variant?: ButtonVariant;
31
+ size?: ButtonSize;
32
+ leadingIcon?: ReactNode;
33
+ trailingIcon?: ReactNode;
34
+ disabled?: boolean;
35
+ loading?: boolean;
36
+ onPress?: () => void;
37
+ style?: StyleProp<ViewStyle>;
38
+ testID?: string;
39
+ }
40
+
41
+ type ButtonProps = ButtonBase &
42
+ (
43
+ // iconOnly は leadingIcon 必須(空ボタンを型で排除、§4 の最小 DU を保ちつつ icon 1個必須)。
44
+ | { iconOnly: true; accessibilityLabel: string; leadingIcon: ReactNode; label?: never }
45
+ | { iconOnly?: false; label: string }
46
+ );
47
+
48
+ export function Button(props: ButtonProps) {
49
+ const { theme, mode } = useTheme();
50
+ const {
51
+ variant = "contained",
52
+ size = "medium",
53
+ leadingIcon,
54
+ trailingIcon,
55
+ disabled = false,
56
+ loading = false,
57
+ onPress,
58
+ style,
59
+ testID,
60
+ } = props;
61
+ const { focused, focusHandlers } = useFocusRing();
62
+
63
+ const spec = SIZE_SPEC[size];
64
+ const colors = useMemo(() => resolveVariant(theme, mode, variant), [theme, mode, variant]);
65
+ const isDisabled = disabled || loading;
66
+ const iconOnly = props.iconOnly === true;
67
+
68
+ return (
69
+ <Pressable
70
+ {...focusHandlers}
71
+ onPress={onPress}
72
+ disabled={isDisabled}
73
+ accessibilityRole="button"
74
+ accessibilityState={{ disabled: isDisabled, busy: loading }}
75
+ accessibilityLabel={iconOnly ? props.accessibilityLabel : undefined}
76
+ testID={testID}
77
+ style={({ pressed }) => [
78
+ {
79
+ height: spec.height,
80
+ flexDirection: "row",
81
+ alignItems: "center",
82
+ justifyContent: "center",
83
+ gap: theme.spacing["2"],
84
+ borderRadius: theme.radius.md,
85
+ backgroundColor: pressed && !isDisabled ? colors.pressedBg : colors.bg,
86
+ ...(iconOnly
87
+ ? { width: spec.iconBox }
88
+ : { paddingHorizontal: theme.spacing[spec.px] }),
89
+ ...(colors.border != null ? { borderWidth: 1, borderColor: colors.border } : null),
90
+ opacity: isDisabled ? 0.5 : 1,
91
+ },
92
+ style,
93
+ ]}
94
+ >
95
+ {loading ? (
96
+ <ActivityIndicator color={colors.textColor} />
97
+ ) : (
98
+ <>
99
+ {leadingIcon != null && <View>{leadingIcon}</View>}
100
+ {!iconOnly && (
101
+ <Text variant={spec.font} weight="medium" style={{ color: colors.textColor }}>
102
+ {props.label}
103
+ </Text>
104
+ )}
105
+ {trailingIcon != null && <View>{trailingIcon}</View>}
106
+ </>
107
+ )}
108
+ <FocusRing visible={focused && !isDisabled} radius={theme.radius.md} />
109
+ </Pressable>
110
+ );
111
+ }
112
+
113
+ // Phase 2 conformance test 用の contract メタ(§2 A-3)。
114
+ Button.__contract = CONTRACTS.button;
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Metric — 数値 + 単位 + ラベルの指標表示 primitive(設計書 §1、意思決定3)。
3
+ * contract: metric(app 先行定義)。ツー活カードの主役(走行距離 / 時間 / 獲得標高 等)。
4
+ *
5
+ * - value は tabular(fontVariant:["tabular-nums"])で桁揃え。Text primitive は fontVariant を
6
+ * 公開しないので、value は RN Text を直接使う。
7
+ * - size(sm/md/lg) は value の fontSize token にマップ(contract の height は想定行高、実 fontSize は
8
+ * pure resolver(metric.styles.ts)で token 解決する。metric.contract intent 参照)。
9
+ * - unit は value の1段下の fontSize でベースライン揃え。label は muted。
10
+ * - a11y: value+unit+label を1つの accessibilityLabel に合成して読み上げる(contract a11y)。
11
+ */
12
+
13
+ import { useMemo } from "react";
14
+ import { Text as RNText, View, type StyleProp, type ViewStyle } from "react-native";
15
+ import { useTheme } from "../theme";
16
+ import { CONTRACTS, type SizeOf } from "../contracts/contract-types";
17
+ import { resolveMetricStyles } from "./metric.styles";
18
+
19
+ type MetricSize = SizeOf<"metric">; // "sm" | "md" | "lg"
20
+
21
+ interface MetricProps {
22
+ /** 整形済みの数値文字列(整形は呼び出し側)。 */
23
+ value: string;
24
+ /** 単位("km" / "m" / "h:mm" 等)。 */
25
+ unit?: string;
26
+ /** ラベル("走行距離" 等)。 */
27
+ label?: string;
28
+ size?: MetricSize;
29
+ align?: "start" | "center";
30
+ style?: StyleProp<ViewStyle>;
31
+ testID?: string;
32
+ }
33
+
34
+ export function Metric({
35
+ value,
36
+ unit,
37
+ label,
38
+ size = "md",
39
+ align = "start",
40
+ style,
41
+ testID,
42
+ }: MetricProps) {
43
+ const { theme, mode } = useTheme();
44
+
45
+ // 決定ロジックは pure resolver(metric.styles.ts)に分離済み — recipe との機械照合対象。
46
+ const styles = useMemo(() => resolveMetricStyles(theme, mode, size), [theme, mode, size]);
47
+
48
+ const a11yLabel = [value, unit, label].filter(Boolean).join(" ");
49
+
50
+ return (
51
+ <View
52
+ testID={testID}
53
+ accessible
54
+ accessibilityLabel={a11yLabel}
55
+ style={[{ alignItems: align === "center" ? "center" : "flex-start" }, style]}
56
+ >
57
+ <View style={{ flexDirection: "row", alignItems: "baseline" }}>
58
+ <RNText style={styles.valueStyle}>{value}</RNText>
59
+ {unit != null && <RNText style={styles.unitStyle}>{unit}</RNText>}
60
+ </View>
61
+ {label != null && <RNText style={styles.labelStyle}>{label}</RNText>}
62
+ </View>
63
+ );
64
+ }
65
+
66
+ // Phase 2 conformance test 用の contract メタ(§2 A-3)。
67
+ Metric.__contract = CONTRACTS.metric;
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Row — 横並び layout primitive。RN コア View の薄いラッパ。
3
+ * contract: row(app 先行定義、melta-contracts)。dogfood 不足-1(生 flexbox 手書き)の解消。
4
+ *
5
+ * - gap は spacing token キー限定(生数値不可、§5 lint の意味を保つ)。
6
+ * - align(交差軸、default center)/ justify(主軸、default start)/ wrap(折返し)。
7
+ * - 決定ロジックは pure resolver(row.styles.ts)に分離 — recipe との機械照合対象。
8
+ */
9
+
10
+ import { useMemo, type ReactNode } from "react";
11
+ import { View, type StyleProp, type ViewStyle } from "react-native";
12
+ import { useTheme } from "../theme";
13
+ import type { SpacingKey } from "../theme";
14
+ import { CONTRACTS } from "../contracts/contract-types";
15
+ import { resolveRowStyle, type RowAlign, type RowJustify, type RowStyle } from "./row.styles";
16
+
17
+ interface RowProps {
18
+ /** 子要素間の gap(spacing token キー限定)。省略時 gap なし。 */
19
+ gap?: SpacingKey;
20
+ /** 交差軸の配置。default "center"。 */
21
+ align?: RowAlign;
22
+ /** 主軸の配置。default "start"。 */
23
+ justify?: RowJustify;
24
+ /** 折返し。default false。 */
25
+ wrap?: boolean;
26
+ style?: StyleProp<ViewStyle>;
27
+ testID?: string;
28
+ children: ReactNode;
29
+ }
30
+
31
+ export function Row({
32
+ gap,
33
+ align = "center",
34
+ justify = "start",
35
+ wrap = false,
36
+ style,
37
+ testID,
38
+ children,
39
+ }: RowProps) {
40
+ const { theme } = useTheme();
41
+
42
+ const layout = useMemo<RowStyle>(
43
+ () => resolveRowStyle(theme, { gap, align, justify, wrap }),
44
+ [theme, gap, align, justify, wrap],
45
+ );
46
+
47
+ return (
48
+ <View style={[layout, style]} testID={testID}>
49
+ {children}
50
+ </View>
51
+ );
52
+ }
53
+
54
+ Row.__contract = CONTRACTS.row;