@fragments-sdk/ui 0.17.1 → 0.19.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 (286) hide show
  1. package/dist/assets/ui.css +2700 -3256
  2. package/dist/chart.cjs +0 -1
  3. package/dist/chart.js +0 -1
  4. package/dist/codeblock.cjs +0 -1
  5. package/dist/codeblock.js +0 -1
  6. package/dist/colorpicker.cjs +0 -1
  7. package/dist/colorpicker.js +0 -1
  8. package/dist/components/Accordion/Accordion.module.scss.cjs +8 -8
  9. package/dist/components/Accordion/Accordion.module.scss.js +8 -8
  10. package/dist/components/Alert/Alert.module.scss.cjs +12 -12
  11. package/dist/components/Alert/Alert.module.scss.js +12 -12
  12. package/dist/components/AppShell/AppShell.module.scss.cjs +12 -12
  13. package/dist/components/AppShell/AppShell.module.scss.js +12 -12
  14. package/dist/components/Avatar/Avatar.module.scss.cjs +13 -13
  15. package/dist/components/Avatar/Avatar.module.scss.js +13 -13
  16. package/dist/components/Badge/Badge.module.scss.cjs +13 -13
  17. package/dist/components/Badge/Badge.module.scss.js +13 -13
  18. package/dist/components/BentoGrid/BentoGrid.module.scss.cjs +14 -14
  19. package/dist/components/BentoGrid/BentoGrid.module.scss.js +14 -14
  20. package/dist/components/Box/Box.module.scss.cjs +152 -152
  21. package/dist/components/Box/Box.module.scss.js +152 -152
  22. package/dist/components/Breadcrumbs/Breadcrumbs.module.scss.cjs +8 -8
  23. package/dist/components/Breadcrumbs/Breadcrumbs.module.scss.js +8 -8
  24. package/dist/components/Button/Button.module.scss.cjs +12 -12
  25. package/dist/components/Button/Button.module.scss.js +12 -12
  26. package/dist/components/Card/Card.module.scss.cjs +14 -14
  27. package/dist/components/Card/Card.module.scss.js +14 -14
  28. package/dist/components/Chart/Chart.module.scss.cjs +15 -15
  29. package/dist/components/Chart/Chart.module.scss.js +15 -15
  30. package/dist/components/Chart/index.d.ts +0 -1
  31. package/dist/components/Chart/index.d.ts.map +1 -1
  32. package/dist/components/Checkbox/Checkbox.module.scss.cjs +10 -10
  33. package/dist/components/Checkbox/Checkbox.module.scss.js +10 -10
  34. package/dist/components/Chip/Chip.module.scss.cjs +15 -15
  35. package/dist/components/Chip/Chip.module.scss.js +15 -15
  36. package/dist/components/CodeBlock/CodeBlock.module.scss.cjs +21 -21
  37. package/dist/components/CodeBlock/CodeBlock.module.scss.js +21 -21
  38. package/dist/components/CodeBlock/index.d.ts +0 -1
  39. package/dist/components/CodeBlock/index.d.ts.map +1 -1
  40. package/dist/components/Collapsible/Collapsible.module.scss.cjs +10 -10
  41. package/dist/components/Collapsible/Collapsible.module.scss.js +10 -10
  42. package/dist/components/ColorPicker/ColorPicker.module.scss.cjs +14 -14
  43. package/dist/components/ColorPicker/ColorPicker.module.scss.js +14 -14
  44. package/dist/components/ColorPicker/index.d.ts +0 -1
  45. package/dist/components/ColorPicker/index.d.ts.map +1 -1
  46. package/dist/components/Combobox/Combobox.module.scss.cjs +23 -23
  47. package/dist/components/Combobox/Combobox.module.scss.js +23 -23
  48. package/dist/components/Combobox/index.cjs +13 -10
  49. package/dist/components/Combobox/index.d.ts.map +1 -1
  50. package/dist/components/Combobox/index.js +13 -10
  51. package/dist/components/Command/Command.module.scss.cjs +11 -11
  52. package/dist/components/Command/Command.module.scss.js +11 -11
  53. package/dist/components/ConversationList/ConversationList.module.scss.cjs +10 -10
  54. package/dist/components/ConversationList/ConversationList.module.scss.js +10 -10
  55. package/dist/components/DataTable/DataTable.module.scss.cjs +26 -26
  56. package/dist/components/DataTable/DataTable.module.scss.js +26 -26
  57. package/dist/components/DataTable/index.cjs +0 -1
  58. package/dist/components/DataTable/index.d.ts +0 -1
  59. package/dist/components/DataTable/index.d.ts.map +1 -1
  60. package/dist/components/DataTable/index.js +0 -1
  61. package/dist/components/DatePicker/DatePicker.module.scss.cjs +31 -31
  62. package/dist/components/DatePicker/DatePicker.module.scss.js +31 -31
  63. package/dist/components/DatePicker/index.d.ts +0 -1
  64. package/dist/components/DatePicker/index.d.ts.map +1 -1
  65. package/dist/components/Dialog/Dialog.module.scss.cjs +14 -14
  66. package/dist/components/Dialog/Dialog.module.scss.js +14 -14
  67. package/dist/components/Drawer/Drawer.module.scss.cjs +33 -27
  68. package/dist/components/Drawer/Drawer.module.scss.js +34 -28
  69. package/dist/components/Drawer/index.cjs +36 -14
  70. package/dist/components/Drawer/index.d.ts +21 -3
  71. package/dist/components/Drawer/index.d.ts.map +1 -1
  72. package/dist/components/Drawer/index.js +36 -14
  73. package/dist/components/Editor/Editor.module.scss.cjs +17 -17
  74. package/dist/components/Editor/Editor.module.scss.js +17 -17
  75. package/dist/components/EmptyState/EmptyState.module.scss.cjs +8 -8
  76. package/dist/components/EmptyState/EmptyState.module.scss.js +8 -8
  77. package/dist/components/Field/Field.module.scss.cjs +4 -4
  78. package/dist/components/Field/Field.module.scss.js +4 -4
  79. package/dist/components/Fieldset/Fieldset.module.scss.cjs +3 -3
  80. package/dist/components/Fieldset/Fieldset.module.scss.js +3 -3
  81. package/dist/components/Header/Header.module.scss.cjs +28 -28
  82. package/dist/components/Header/Header.module.scss.js +28 -28
  83. package/dist/components/Icon/Icon.module.scss.cjs +8 -8
  84. package/dist/components/Icon/Icon.module.scss.js +8 -8
  85. package/dist/components/Image/Image.module.scss.cjs +27 -27
  86. package/dist/components/Image/Image.module.scss.js +27 -27
  87. package/dist/components/Input/Input.module.scss.cjs +19 -19
  88. package/dist/components/Input/Input.module.scss.js +19 -19
  89. package/dist/components/Link/Link.module.scss.cjs +10 -10
  90. package/dist/components/Link/Link.module.scss.js +10 -10
  91. package/dist/components/Listbox/Listbox.module.scss.cjs +8 -8
  92. package/dist/components/Listbox/Listbox.module.scss.js +8 -8
  93. package/dist/components/Loading/Loading.module.scss.cjs +30 -30
  94. package/dist/components/Loading/Loading.module.scss.js +30 -30
  95. package/dist/components/Markdown/Markdown.module.scss.cjs +1 -1
  96. package/dist/components/Markdown/Markdown.module.scss.js +1 -1
  97. package/dist/components/Markdown/index.d.ts +0 -1
  98. package/dist/components/Markdown/index.d.ts.map +1 -1
  99. package/dist/components/Menu/Menu.module.scss.cjs +16 -13
  100. package/dist/components/Menu/Menu.module.scss.js +17 -14
  101. package/dist/components/Menu/index.cjs +1 -1
  102. package/dist/components/Menu/index.d.ts.map +1 -1
  103. package/dist/components/Menu/index.js +1 -1
  104. package/dist/components/Message/Message.module.scss.cjs +18 -18
  105. package/dist/components/Message/Message.module.scss.js +18 -18
  106. package/dist/components/NavigationMenu/NavigationMenu.module.scss.cjs +28 -28
  107. package/dist/components/NavigationMenu/NavigationMenu.module.scss.js +28 -28
  108. package/dist/components/Pagination/Pagination.module.scss.cjs +7 -7
  109. package/dist/components/Pagination/Pagination.module.scss.js +7 -7
  110. package/dist/components/Popover/Popover.module.scss.cjs +10 -10
  111. package/dist/components/Popover/Popover.module.scss.js +10 -10
  112. package/dist/components/Progress/Progress.module.scss.cjs +25 -25
  113. package/dist/components/Progress/Progress.module.scss.js +25 -25
  114. package/dist/components/Prompt/Prompt.module.scss.cjs +26 -14
  115. package/dist/components/Prompt/Prompt.module.scss.js +26 -14
  116. package/dist/components/Prompt/index.cjs +16 -0
  117. package/dist/components/Prompt/index.d.ts +17 -1
  118. package/dist/components/Prompt/index.d.ts.map +1 -1
  119. package/dist/components/Prompt/index.js +16 -0
  120. package/dist/components/RadioGroup/RadioGroup.module.scss.cjs +16 -16
  121. package/dist/components/RadioGroup/RadioGroup.module.scss.js +16 -16
  122. package/dist/components/ScrollArea/ScrollArea.module.scss.cjs +10 -10
  123. package/dist/components/ScrollArea/ScrollArea.module.scss.js +10 -10
  124. package/dist/components/Select/Select.module.scss.cjs +17 -17
  125. package/dist/components/Select/Select.module.scss.js +17 -17
  126. package/dist/components/Select/index.cjs +20 -20
  127. package/dist/components/Select/index.d.ts.map +1 -1
  128. package/dist/components/Select/index.js +20 -20
  129. package/dist/components/Separator/Separator.module.scss.cjs +10 -10
  130. package/dist/components/Separator/Separator.module.scss.js +10 -10
  131. package/dist/components/Sidebar/Sidebar.module.scss.cjs +42 -42
  132. package/dist/components/Sidebar/Sidebar.module.scss.js +42 -42
  133. package/dist/components/Slider/Slider.module.scss.cjs +12 -12
  134. package/dist/components/Slider/Slider.module.scss.js +12 -12
  135. package/dist/components/Slider/index.cjs +23 -21
  136. package/dist/components/Slider/index.js +23 -21
  137. package/dist/components/Stack/Stack.module.scss.cjs +35 -35
  138. package/dist/components/Stack/Stack.module.scss.js +35 -35
  139. package/dist/components/Table/Table.module.scss.cjs +16 -16
  140. package/dist/components/Table/Table.module.scss.js +16 -16
  141. package/dist/components/Table/index.d.ts +0 -1
  142. package/dist/components/Table/index.d.ts.map +1 -1
  143. package/dist/components/TableOfContents/TableOfContents.module.scss.cjs +7 -7
  144. package/dist/components/TableOfContents/TableOfContents.module.scss.js +7 -7
  145. package/dist/components/Tabs/Tabs.module.scss.cjs +9 -9
  146. package/dist/components/Tabs/Tabs.module.scss.js +9 -9
  147. package/dist/components/Text/Text.module.scss.cjs +38 -38
  148. package/dist/components/Text/Text.module.scss.js +38 -38
  149. package/dist/components/Textarea/Textarea.module.scss.cjs +23 -23
  150. package/dist/components/Textarea/Textarea.module.scss.js +23 -23
  151. package/dist/components/Theme/ThemeToggle.module.scss.cjs +6 -6
  152. package/dist/components/Theme/ThemeToggle.module.scss.js +6 -6
  153. package/dist/components/ThinkingIndicator/ThinkingIndicator.module.scss.cjs +22 -22
  154. package/dist/components/ThinkingIndicator/ThinkingIndicator.module.scss.js +22 -22
  155. package/dist/components/Toast/Toast.module.scss.cjs +20 -20
  156. package/dist/components/Toast/Toast.module.scss.js +20 -20
  157. package/dist/components/Toggle/Toggle.module.scss.cjs +13 -13
  158. package/dist/components/Toggle/Toggle.module.scss.js +13 -13
  159. package/dist/components/ToggleGroup/ToggleGroup.module.scss.cjs +17 -17
  160. package/dist/components/ToggleGroup/ToggleGroup.module.scss.js +17 -17
  161. package/dist/components/Tooltip/Tooltip.module.scss.cjs +3 -3
  162. package/dist/components/Tooltip/Tooltip.module.scss.js +3 -3
  163. package/dist/components/Tooltip/index.cjs +4 -3
  164. package/dist/components/Tooltip/index.d.ts +4 -1
  165. package/dist/components/Tooltip/index.d.ts.map +1 -1
  166. package/dist/components/Tooltip/index.js +4 -3
  167. package/dist/datepicker.cjs +0 -1
  168. package/dist/datepicker.js +0 -1
  169. package/dist/index.cjs +0 -1
  170. package/dist/index.d.ts +2 -3
  171. package/dist/index.d.ts.map +1 -1
  172. package/dist/index.js +0 -1
  173. package/dist/markdown.cjs +0 -1
  174. package/dist/markdown.js +0 -1
  175. package/dist/table.cjs +0 -1
  176. package/dist/table.js +0 -1
  177. package/dist/utils/seed-derivation.cjs +29 -0
  178. package/dist/utils/seed-derivation.d.ts +1 -1
  179. package/dist/utils/seed-derivation.d.ts.map +1 -1
  180. package/dist/utils/seed-derivation.js +29 -0
  181. package/fragments.json +1 -1
  182. package/package.json +18 -14
  183. package/src/components/Accordion/Accordion.contract.json +169 -0
  184. package/src/components/Alert/Alert.contract.json +157 -0
  185. package/src/components/AppShell/AppShell.contract.json +155 -0
  186. package/src/components/Avatar/Avatar.contract.json +189 -0
  187. package/src/components/Badge/Badge.contract.json +187 -0
  188. package/src/components/BentoGrid/BentoGrid.contract.json +135 -0
  189. package/src/components/Box/Box.contract.json +423 -0
  190. package/src/components/Breadcrumbs/Breadcrumbs.contract.json +143 -0
  191. package/src/components/Button/Button.contract.json +205 -0
  192. package/src/components/Button/Button.module.scss +24 -1
  193. package/src/components/ButtonGroup/ButtonGroup.contract.json +140 -0
  194. package/src/components/Card/Card.contract.json +185 -0
  195. package/src/components/Card/Card.module.scss +5 -1
  196. package/src/components/Chart/Chart.contract.json +129 -0
  197. package/src/components/Chart/index.tsx +0 -1
  198. package/src/components/Checkbox/Checkbox.contract.json +246 -0
  199. package/src/components/Chip/Chip.contract.json +212 -0
  200. package/src/components/Chip/Chip.module.scss +4 -4
  201. package/src/components/CodeBlock/CodeBlock.contract.json +388 -0
  202. package/src/components/CodeBlock/index.tsx +0 -1
  203. package/src/components/Collapsible/Collapsible.contract.json +154 -0
  204. package/src/components/ColorPicker/ColorPicker.contract.json +212 -0
  205. package/src/components/ColorPicker/index.tsx +0 -1
  206. package/src/components/Combobox/Combobox.contract.json +297 -0
  207. package/src/components/Combobox/index.tsx +7 -8
  208. package/src/components/Command/Command.contract.json +165 -0
  209. package/src/components/Command/Command.module.scss +22 -9
  210. package/src/components/ConversationList/ConversationList.contract.json +151 -0
  211. package/src/components/DataTable/DataTable.contract.json +302 -0
  212. package/src/components/DataTable/index.tsx +0 -2
  213. package/src/components/DatePicker/DatePicker.contract.json +288 -0
  214. package/src/components/DatePicker/index.tsx +0 -2
  215. package/src/components/Dialog/Dialog.contract.json +159 -0
  216. package/src/components/Drawer/Drawer.contract.json +161 -0
  217. package/src/components/Drawer/Drawer.module.scss +45 -5
  218. package/src/components/Drawer/index.tsx +66 -23
  219. package/src/components/Editor/Editor.contract.json +263 -0
  220. package/src/components/EmptyState/EmptyState.contract.json +133 -0
  221. package/src/components/Field/Field.contract.json +157 -0
  222. package/src/components/Fieldset/Fieldset.contract.json +117 -0
  223. package/src/components/Form/Form.contract.json +145 -0
  224. package/src/components/Grid/Grid.contract.json +195 -0
  225. package/src/components/Header/Header.contract.json +196 -0
  226. package/src/components/Icon/Icon.contract.json +194 -0
  227. package/src/components/Image/Image.contract.json +209 -0
  228. package/src/components/Input/Input.contract.json +344 -0
  229. package/src/components/Input/Input.module.scss +16 -6
  230. package/src/components/Link/Link.contract.json +180 -0
  231. package/src/components/List/List.contract.json +154 -0
  232. package/src/components/Listbox/Listbox.contract.json +158 -0
  233. package/src/components/Loading/Loading.contract.json +167 -0
  234. package/src/components/Markdown/Markdown.contract.json +127 -0
  235. package/src/components/Markdown/Markdown.module.scss +0 -3
  236. package/src/components/Markdown/index.tsx +0 -1
  237. package/src/components/Menu/Menu.contract.json +177 -0
  238. package/src/components/Menu/Menu.module.scss +6 -0
  239. package/src/components/Menu/index.tsx +3 -1
  240. package/src/components/Message/Message.contract.json +183 -0
  241. package/src/components/Message/Message.module.scss +2 -2
  242. package/src/components/NavigationMenu/NavigationMenu.contract.json +203 -0
  243. package/src/components/NavigationMenu/NavigationMenu.module.scss +18 -23
  244. package/src/components/Pagination/Pagination.contract.json +163 -0
  245. package/src/components/Pagination/Pagination.module.scss +1 -1
  246. package/src/components/Popover/Popover.contract.json +163 -0
  247. package/src/components/Progress/Progress.contract.json +176 -0
  248. package/src/components/Prompt/Prompt.contract.json +211 -0
  249. package/src/components/Prompt/Prompt.module.scss +117 -3
  250. package/src/components/Prompt/index.tsx +40 -0
  251. package/src/components/RadioGroup/RadioGroup.contract.json +226 -0
  252. package/src/components/ScrollArea/ScrollArea.contract.json +131 -0
  253. package/src/components/Select/Select.contract.json +269 -0
  254. package/src/components/Select/index.tsx +20 -25
  255. package/src/components/Separator/Separator.contract.json +143 -0
  256. package/src/components/Sidebar/Sidebar.contract.json +258 -0
  257. package/src/components/Sidebar/Sidebar.module.scss +1 -1
  258. package/src/components/Skeleton/Skeleton.contract.json +166 -0
  259. package/src/components/Slider/Slider.contract.json +248 -0
  260. package/src/components/Slider/index.tsx +10 -10
  261. package/src/components/Stack/Stack.contract.json +220 -0
  262. package/src/components/Table/Table.contract.json +171 -0
  263. package/src/components/Table/index.tsx +0 -2
  264. package/src/components/TableOfContents/TableOfContents.contract.json +145 -0
  265. package/src/components/TableOfContents/TableOfContents.module.scss +19 -15
  266. package/src/components/Tabs/Tabs.contract.json +159 -0
  267. package/src/components/Text/Text.contract.json +239 -0
  268. package/src/components/Textarea/Textarea.contract.json +308 -0
  269. package/src/components/Theme/Theme.contract.json +152 -0
  270. package/src/components/ThinkingIndicator/ThinkingIndicator.contract.json +165 -0
  271. package/src/components/Toast/Toast.contract.json +181 -0
  272. package/src/components/Toggle/Toggle.contract.json +231 -0
  273. package/src/components/Toggle/Toggle.module.scss +3 -3
  274. package/src/components/ToggleGroup/ToggleGroup.contract.json +206 -0
  275. package/src/components/Tooltip/Tooltip.contract.json +214 -0
  276. package/src/components/Tooltip/index.tsx +7 -3
  277. package/src/components/VisuallyHidden/VisuallyHidden.contract.json +116 -0
  278. package/src/index.ts +8 -3
  279. package/src/styles/globals.scss +6 -1
  280. package/src/tokens/_computed.scss +3 -1
  281. package/src/tokens/_density.scss +4 -4
  282. package/src/tokens/_derive.scss +52 -56
  283. package/src/tokens/_palettes.scss +20 -1
  284. package/src/tokens/_seeds.scss +2 -2
  285. package/src/tokens/_variables.scss +45 -29
  286. package/src/utils/seed-derivation.ts +23 -1
@@ -0,0 +1,209 @@
1
+ {
2
+ "$schema": "https://usefragments.com/schemas/contract.v1.json",
3
+ "name": "Image",
4
+ "description": "Responsive image component with aspect ratio control, loading states, and error fallbacks. Handles image display with consistent styling.",
5
+ "category": "display",
6
+ "tags": [
7
+ "image",
8
+ "media",
9
+ "photo",
10
+ "picture",
11
+ "visual"
12
+ ],
13
+ "status": "stable",
14
+ "sourcePath": "src/components/Image/index.tsx",
15
+ "exportName": "Image",
16
+ "propsSummary": [
17
+ "src: string (required)",
18
+ "alt: string (required)",
19
+ "aspectRatio: 1:1|4:3|16:9|21:9|auto (default: auto)",
20
+ "objectFit: cover|contain|fill|none (default: cover)",
21
+ "width: union",
22
+ "height: union",
23
+ "rounded: none|sm|md|lg|full (default: none)",
24
+ "fallback: node",
25
+ "className: string",
26
+ "style: object",
27
+ "imgProps: object",
28
+ "onImageLoad: function",
29
+ "onImageError: function"
30
+ ],
31
+ "props": {
32
+ "src": {
33
+ "type": "string",
34
+ "description": "Image source URL",
35
+ "required": true
36
+ },
37
+ "alt": {
38
+ "type": "string",
39
+ "description": "Alt text for accessibility (required)",
40
+ "required": true
41
+ },
42
+ "aspectRatio": {
43
+ "type": "enum",
44
+ "description": "Aspect ratio of the image container",
45
+ "default": "auto",
46
+ "required": false,
47
+ "values": [
48
+ "1:1",
49
+ "4:3",
50
+ "16:9",
51
+ "21:9",
52
+ "auto"
53
+ ]
54
+ },
55
+ "objectFit": {
56
+ "type": "enum",
57
+ "description": "How the image fits within its container",
58
+ "default": "cover",
59
+ "required": false,
60
+ "values": [
61
+ "cover",
62
+ "contain",
63
+ "fill",
64
+ "none"
65
+ ]
66
+ },
67
+ "width": {
68
+ "type": "union",
69
+ "description": "Width of the image container",
70
+ "required": false
71
+ },
72
+ "height": {
73
+ "type": "union",
74
+ "description": "Height of the image container",
75
+ "required": false
76
+ },
77
+ "rounded": {
78
+ "type": "enum",
79
+ "description": "Border radius",
80
+ "default": "none",
81
+ "required": false,
82
+ "values": [
83
+ "none",
84
+ "sm",
85
+ "md",
86
+ "lg",
87
+ "full"
88
+ ]
89
+ },
90
+ "fallback": {
91
+ "type": "node",
92
+ "description": "Content to show while loading or on error",
93
+ "required": false
94
+ },
95
+ "className": {
96
+ "type": "string",
97
+ "description": "Additional class name",
98
+ "required": false
99
+ },
100
+ "style": {
101
+ "type": "object",
102
+ "description": "Inline styles",
103
+ "required": false
104
+ },
105
+ "imgProps": {
106
+ "type": "object",
107
+ "description": "Additional props for the underlying img element (except src/alt/size/style/events)",
108
+ "required": false
109
+ },
110
+ "onImageLoad": {
111
+ "type": "function",
112
+ "description": "Called when the underlying img element loads",
113
+ "required": false
114
+ },
115
+ "onImageError": {
116
+ "type": "function",
117
+ "description": "Called when the underlying img element fails to load",
118
+ "required": false
119
+ }
120
+ },
121
+ "usage": {
122
+ "when": [
123
+ "Displaying product images in cards or grids",
124
+ "Hero images with specific aspect ratios",
125
+ "User-uploaded content that may fail to load",
126
+ "Thumbnails in lists or galleries"
127
+ ],
128
+ "whenNot": [
129
+ "User avatars (use Avatar component)",
130
+ "Icons or symbols (use Icon component)",
131
+ "Background images (use CSS background-image)",
132
+ "SVG illustrations (use inline SVG or Image component)"
133
+ ],
134
+ "guidelines": [
135
+ "Always provide meaningful alt text for accessibility",
136
+ "Use appropriate aspect ratios for consistent layouts",
137
+ "Provide fallback content for failed loads",
138
+ "Use objectFit=\"contain\" for logos to preserve aspect ratio",
139
+ "Use imgProps / onImageLoad / onImageError when you need lower-level img control"
140
+ ],
141
+ "accessibility": [
142
+ "Alt text is required and must describe the image content",
143
+ "Decorative images should have empty alt=\"\"",
144
+ "Avoid text in images; if necessary, describe the text in alt",
145
+ "Ensure sufficient contrast between image and surrounding content"
146
+ ]
147
+ },
148
+ "examples": [
149
+ {
150
+ "name": "Default",
151
+ "description": "Basic image display",
152
+ "code": "<Image\n src=\"https://images.unsplash.com/photo-1555066931-4365d14bab8c?w=400&h=300&fit=crop\"\n alt=\"Code on a screen\"\n width={300}\n/>"
153
+ },
154
+ {
155
+ "name": "Aspect Ratios",
156
+ "description": "Different aspect ratio options",
157
+ "code": "<div style={{ display: 'flex', gap: '16px', flexWrap: 'wrap' }}>\n <Image\n src=\"https://images.unsplash.com/photo-1555066931-4365d14bab8c?w=200&h=200&fit=crop\"\n alt=\"Square image\"\n aspectRatio=\"1:1\"\n width={100}\n />\n <Image\n src=\"https://images.unsplash.com/photo-1555066931-4365d14bab8c?w=200&h=150&fit=crop\"\n alt=\"4:3 image\"\n aspectRatio=\"4:3\"\n width={120}\n />\n <Image\n src=\"https://images.unsplash.com/photo-1555066931-4365d14bab8c?w=320&h=180&fit=crop\"\n alt=\"16:9 image\"\n aspectRatio=\"16:9\"\n width={160}\n />\n</div>"
158
+ },
159
+ {
160
+ "name": "Rounded Corners",
161
+ "description": "Border radius options",
162
+ "code": "<div style={{ display: 'flex', gap: '16px', alignItems: 'center' }}>\n <Image\n src=\"https://images.unsplash.com/photo-1555066931-4365d14bab8c?w=100&h=100&fit=crop\"\n alt=\"No rounding\"\n rounded=\"none\"\n width={80}\n height={80}\n />\n <Image\n src=\"https://images.unsplash.com/photo-1555066931-4365d14bab8c?w=100&h=100&fit=crop\"\n alt=\"Medium rounding\"\n rounded=\"md\"\n width={80}\n height={80}\n />\n <Image\n src=\"https://images.unsplash.com/photo-1555066931-4365d14bab8c?w=100&h=100&fit=crop\"\n alt=\"Full rounding\"\n rounded=\"full\"\n width={80}\n height={80}\n />\n</div>"
163
+ },
164
+ {
165
+ "name": "With Fallback",
166
+ "description": "Fallback content for loading/error states",
167
+ "code": "<Image\n src=\"https://invalid-url.example/image.jpg\"\n alt=\"Image that will fail\"\n width={200}\n height={150}\n rounded=\"md\"\n fallback={\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', height: '100%', background: 'var(--fui-color-surface-secondary)' }}>\n <span style={{ color: 'var(--fui-color-text-tertiary)' }}>No image</span>\n </div>\n }\n/>"
168
+ }
169
+ ],
170
+ "relations": [
171
+ {
172
+ "component": "Card",
173
+ "relationship": "child",
174
+ "note": "Common pattern to use Image at top of product cards"
175
+ },
176
+ {
177
+ "component": "Avatar",
178
+ "relationship": "alternative",
179
+ "note": "Use Avatar for user profile pictures"
180
+ }
181
+ ],
182
+ "contract": {
183
+ "propsSummary": [
184
+ "src: string - image URL (required)",
185
+ "alt: string - accessibility text (required)",
186
+ "aspectRatio: 1:1|4:3|16:9|21:9|auto - container ratio",
187
+ "objectFit: cover|contain|fill|none - image fitting",
188
+ "rounded: none|sm|md|lg|full - border radius",
189
+ "fallback: ReactNode - loading/error content",
190
+ "imgProps/onImageLoad/onImageError - low-level img customization and events"
191
+ ],
192
+ "a11yRules": [
193
+ "A11Y_IMG_ALT",
194
+ "A11Y_IMG_DECORATIVE"
195
+ ]
196
+ },
197
+ "ai": {
198
+ "compositionPattern": "compound",
199
+ "subComponents": [
200
+ "Root"
201
+ ]
202
+ },
203
+ "provenance": {
204
+ "source": "migrated",
205
+ "verified": false,
206
+ "frameworkSupport": "native",
207
+ "extractedAt": "2026-03-13T23:18:59.379Z"
208
+ }
209
+ }
@@ -0,0 +1,344 @@
1
+ {
2
+ "$schema": "https://usefragments.com/schemas/contract.v1.json",
3
+ "name": "Input",
4
+ "description": "Text input field for single-line user data entry",
5
+ "category": "forms",
6
+ "tags": [
7
+ "form",
8
+ "input",
9
+ "text"
10
+ ],
11
+ "status": "stable",
12
+ "sourcePath": "src/components/Input/index.tsx",
13
+ "exportName": "Input",
14
+ "propsSummary": [
15
+ "value: string",
16
+ "defaultValue: string",
17
+ "placeholder: string",
18
+ "type: number|text|email|password|tel|url (default: text)",
19
+ "size: sm|md|lg (default: md)",
20
+ "disabled: boolean (default: false)",
21
+ "error: boolean (default: false)",
22
+ "success: boolean (default: false)",
23
+ "label: string",
24
+ "required: boolean (default: false)",
25
+ "helperText: string",
26
+ "startAdornment: node",
27
+ "endAdornment: node",
28
+ "shortcut: string",
29
+ "shortcutBehavior: display-only|focus-input (default: display-only)",
30
+ "onChange: function",
31
+ "onValueChange: function",
32
+ "onBlur: function",
33
+ "onFocus: function",
34
+ "onKeyDown: function",
35
+ "rootProps: object",
36
+ "inputStyle: object",
37
+ "inputClassName: string",
38
+ "withFieldWrapper: boolean (default: true)",
39
+ "className: string",
40
+ "style: object"
41
+ ],
42
+ "props": {
43
+ "value": {
44
+ "type": "string",
45
+ "description": "Current input value (controlled)",
46
+ "required": false
47
+ },
48
+ "defaultValue": {
49
+ "type": "string",
50
+ "description": "Default value for uncontrolled usage",
51
+ "required": false
52
+ },
53
+ "placeholder": {
54
+ "type": "string",
55
+ "description": "Placeholder text shown when empty",
56
+ "required": false,
57
+ "constraints": [
58
+ "Use for format hints only, not as a replacement for labels"
59
+ ]
60
+ },
61
+ "type": {
62
+ "type": "enum",
63
+ "description": "HTML input type for validation and keyboard",
64
+ "default": "text",
65
+ "required": false,
66
+ "values": [
67
+ "number",
68
+ "text",
69
+ "email",
70
+ "password",
71
+ "tel",
72
+ "url"
73
+ ]
74
+ },
75
+ "size": {
76
+ "type": "enum",
77
+ "description": "Size variant",
78
+ "default": "md",
79
+ "required": false,
80
+ "values": [
81
+ "sm",
82
+ "md",
83
+ "lg"
84
+ ]
85
+ },
86
+ "disabled": {
87
+ "type": "boolean",
88
+ "description": "Whether the input is interactive",
89
+ "default": "false",
90
+ "required": false
91
+ },
92
+ "error": {
93
+ "type": "boolean",
94
+ "description": "Whether to show error styling",
95
+ "default": "false",
96
+ "required": false
97
+ },
98
+ "success": {
99
+ "type": "boolean",
100
+ "description": "Whether to show success/validated styling",
101
+ "default": "false",
102
+ "required": false
103
+ },
104
+ "label": {
105
+ "type": "string",
106
+ "description": "Label text displayed above input",
107
+ "required": false
108
+ },
109
+ "required": {
110
+ "type": "boolean",
111
+ "description": "Whether the field is required (shows asterisk)",
112
+ "default": "false",
113
+ "required": false
114
+ },
115
+ "helperText": {
116
+ "type": "string",
117
+ "description": "Helper or error message below input",
118
+ "required": false
119
+ },
120
+ "startAdornment": {
121
+ "type": "node",
122
+ "description": "Content rendered before the input (icon or prefix text)",
123
+ "required": false
124
+ },
125
+ "endAdornment": {
126
+ "type": "node",
127
+ "description": "Content rendered after the input (icon or suffix text)",
128
+ "required": false
129
+ },
130
+ "shortcut": {
131
+ "type": "string",
132
+ "description": "Keyboard shortcut hint displayed inside the input",
133
+ "required": false
134
+ },
135
+ "shortcutBehavior": {
136
+ "type": "enum",
137
+ "description": "Whether shortcut hint is visual only or also registers a global focus hotkey",
138
+ "default": "display-only",
139
+ "required": false,
140
+ "values": [
141
+ "display-only",
142
+ "focus-input"
143
+ ]
144
+ },
145
+ "onChange": {
146
+ "type": "function",
147
+ "description": "Called with new value on change",
148
+ "required": false
149
+ },
150
+ "onValueChange": {
151
+ "type": "function",
152
+ "description": "Value-first change callback alias: (value: string) => void",
153
+ "required": false
154
+ },
155
+ "onBlur": {
156
+ "type": "function",
157
+ "description": "",
158
+ "required": false
159
+ },
160
+ "onFocus": {
161
+ "type": "function",
162
+ "description": "",
163
+ "required": false
164
+ },
165
+ "onKeyDown": {
166
+ "type": "function",
167
+ "description": "",
168
+ "required": false
169
+ },
170
+ "rootProps": {
171
+ "type": "object",
172
+ "description": "HTML attributes applied to the wrapper element",
173
+ "required": false
174
+ },
175
+ "inputStyle": {
176
+ "type": "object",
177
+ "description": "Inline styles applied directly to the input element",
178
+ "required": false
179
+ },
180
+ "inputClassName": {
181
+ "type": "string",
182
+ "description": "Class name applied directly to the input element",
183
+ "required": false
184
+ },
185
+ "withFieldWrapper": {
186
+ "type": "boolean",
187
+ "description": "Render built-in label/helper wrapper (set false for Field composition or bare input rendering)",
188
+ "default": "true",
189
+ "required": false
190
+ },
191
+ "className": {
192
+ "type": "string",
193
+ "description": "Wrapper class name",
194
+ "required": false
195
+ },
196
+ "style": {
197
+ "type": "object",
198
+ "description": "Wrapper styles",
199
+ "required": false
200
+ }
201
+ },
202
+ "usage": {
203
+ "when": [
204
+ "Collecting single-line text data from users",
205
+ "Email, password, phone number, or URL input",
206
+ "Search fields",
207
+ "Short form fields (name, title, etc.)"
208
+ ],
209
+ "whenNot": [
210
+ "Multi-line text (use Textarea)",
211
+ "Selecting from predefined options (use Select)",
212
+ "Boolean input (use Checkbox or Switch)",
213
+ "Date/time input (use DatePicker)"
214
+ ],
215
+ "guidelines": [
216
+ "Always provide a label for accessibility",
217
+ "Use appropriate input type for data validation",
218
+ "Show validation errors with error prop and helperText",
219
+ "Use placeholder for format hints, not labels",
220
+ "Shortcut hints are display-only by default; set shortcutBehavior=\"focus-input\" to opt into global hotkey focusing"
221
+ ],
222
+ "accessibility": [
223
+ "Labels must be associated with inputs",
224
+ "Error messages should be announced to screen readers",
225
+ "Required fields should be indicated"
226
+ ]
227
+ },
228
+ "examples": [
229
+ {
230
+ "name": "Default",
231
+ "description": "Basic text input",
232
+ "code": "<Input label=\"Name\" placeholder=\"Enter your name\" />"
233
+ },
234
+ {
235
+ "name": "With Value",
236
+ "description": "Input with pre-filled value",
237
+ "code": "<Input label=\"Email\" type=\"email\" value=\"user@example.com\" />"
238
+ },
239
+ {
240
+ "name": "With Helper",
241
+ "description": "Input with helper text",
242
+ "code": "<Input\n label=\"Password\"\n type=\"password\"\n placeholder=\"Create a password\"\n helperText=\"Must be at least 8 characters\"\n/>"
243
+ },
244
+ {
245
+ "name": "Error State",
246
+ "description": "Input showing validation error",
247
+ "code": "<Input\n label=\"Email\"\n type=\"email\"\n value=\"invalid-email\"\n error\n helperText=\"Please enter a valid email address\"\n/>"
248
+ },
249
+ {
250
+ "name": "Disabled",
251
+ "description": "Non-interactive input",
252
+ "code": "<Input label=\"Username\" value=\"readonly-user\" disabled />"
253
+ },
254
+ {
255
+ "name": "Required",
256
+ "description": "Required field with asterisk indicator",
257
+ "code": "<Input\n label=\"Email\"\n type=\"email\"\n placeholder=\"user@example.com\"\n required\n/>"
258
+ },
259
+ {
260
+ "name": "Sizes",
261
+ "description": "Available size variants",
262
+ "code": "<div style={{ display: 'flex', flexDirection: 'column', gap: '12px', maxWidth: '300px' }}>\n <Input label=\"Small\" size=\"sm\" placeholder=\"Small input\" />\n <Input label=\"Medium\" size=\"md\" placeholder=\"Medium input\" />\n <Input label=\"Large\" size=\"lg\" placeholder=\"Large input\" />\n</div>"
263
+ },
264
+ {
265
+ "name": "Bare Input (Field Composition)",
266
+ "description": "Disable the built-in wrapper for custom Field composition",
267
+ "code": "<Input\n withFieldWrapper={false}\n aria-label=\"Search\"\n placeholder=\"Search...\"\n rootProps={{ 'data-demo': 'bare-input-wrapper' }}\n/>"
268
+ },
269
+ {
270
+ "name": "Shortcut Focus Hotkey",
271
+ "description": "Display shortcut hint and opt into focus behavior",
272
+ "code": "<Input\n label=\"Command Palette\"\n placeholder=\"Search commands\"\n shortcut=\"⌘K\"\n shortcutBehavior=\"focus-input\"\n/>"
273
+ },
274
+ {
275
+ "name": "Success State",
276
+ "description": "Input showing validated/success styling",
277
+ "code": "<Input\n label=\"Email\"\n type=\"email\"\n value=\"user@example.com\"\n success\n helperText=\"Email verified\"\n/>"
278
+ },
279
+ {
280
+ "name": "With Start Adornment",
281
+ "description": "Input with icon or prefix before the text",
282
+ "code": "<Input\n label=\"Price\"\n placeholder=\"0.00\"\n startAdornment={<span>$</span>}\n/>"
283
+ },
284
+ {
285
+ "name": "With End Adornment",
286
+ "description": "Input with icon or suffix after the text",
287
+ "code": "<Input\n label=\"Weight\"\n placeholder=\"0\"\n endAdornment={<span>kg</span>}\n/>"
288
+ }
289
+ ],
290
+ "relations": [
291
+ {
292
+ "component": "Textarea",
293
+ "relationship": "alternative",
294
+ "note": "Use Textarea for multi-line text input"
295
+ },
296
+ {
297
+ "component": "Select",
298
+ "relationship": "alternative",
299
+ "note": "Use Select when choosing from predefined options"
300
+ },
301
+ {
302
+ "component": "Field",
303
+ "relationship": "parent",
304
+ "note": "Use Field for advanced form composition and custom controls"
305
+ }
306
+ ],
307
+ "contract": {
308
+ "propsSummary": [
309
+ "type: text|email|password|number|tel|url (default: text)",
310
+ "value: string - controlled input value",
311
+ "label: string - accessible label text",
312
+ "placeholder: string - format hint only",
313
+ "disabled: boolean - disables interaction",
314
+ "required: boolean - required field indicator",
315
+ "error: boolean - shows error styling",
316
+ "success: boolean - shows success/validated styling",
317
+ "startAdornment: ReactNode - content before the input (icon or prefix)",
318
+ "endAdornment: ReactNode - content after the input (icon or suffix)",
319
+ "helperText: string - helper/error message",
320
+ "onValueChange: (value: string) => void - value-first change callback alias",
321
+ "rootProps: HTMLAttributes<HTMLDivElement> - wrapper element props",
322
+ "withFieldWrapper: boolean - toggle built-in wrapper/label rendering (default: true)",
323
+ "shortcutBehavior: display-only|focus-input (default: display-only)",
324
+ "...native input attributes are supported (autoComplete, required, inputMode, pattern, etc.)"
325
+ ],
326
+ "a11yRules": [
327
+ "A11Y_INPUT_LABEL",
328
+ "A11Y_INPUT_ERROR",
329
+ "A11Y_INPUT_REQUIRED"
330
+ ]
331
+ },
332
+ "ai": {
333
+ "compositionPattern": "compound",
334
+ "subComponents": [
335
+ "Root"
336
+ ]
337
+ },
338
+ "provenance": {
339
+ "source": "migrated",
340
+ "verified": false,
341
+ "frameworkSupport": "native",
342
+ "extractedAt": "2026-03-13T23:18:59.208Z"
343
+ }
344
+ }
@@ -88,8 +88,11 @@
88
88
  align-items: center;
89
89
 
90
90
  // Auto-detect shortcut kbd via :has() — replaces JS class toggle: `shortcut && styles.hasShortcut`
91
+ // Optical alignment: nudge left padding slightly to center the placeholder
92
+ // in the visible area between the left edge and the kbd badge.
91
93
  &:has(> .shortcut) .input {
92
94
  padding-right: var(--fui-space-12, 3rem);
95
+ padding-left: var(--fui-space-3, $fui-space-3);
93
96
  }
94
97
  }
95
98
 
@@ -101,6 +104,16 @@
101
104
  padding: 0 var(--fui-space-3, $fui-space-3);
102
105
  border-radius: var(--fui-radius-md, $fui-radius-md);
103
106
 
107
+ // Optical alignment: icons have built-in whitespace, so reduce padding
108
+ // on the side with an adornment to keep the content optically centered.
109
+ &:has(> .adornment:first-child) {
110
+ padding-left: var(--fui-space-2, $fui-space-2);
111
+ }
112
+
113
+ &:has(> .adornment:last-of-type:not(:first-child)) {
114
+ padding-right: var(--fui-space-2, $fui-space-2);
115
+ }
116
+
104
117
  &:focus-within {
105
118
  @include field-shell-focus;
106
119
  }
@@ -165,8 +178,8 @@
165
178
  align-items: center;
166
179
  justify-content: center;
167
180
  gap: calc(var(--fui-space-px, $fui-space-px) * 2);
168
- min-width: 1.25rem;
169
- height: 1.25rem;
181
+ min-width: 24px;
182
+ height: 24px;
170
183
  padding: 0 var(--fui-space-1, $fui-space-1);
171
184
  font-size: var(--fui-font-size-2xs, $fui-font-size-2xs);
172
185
  font-family: var(--fui-font-sans, $fui-font-sans);
@@ -175,11 +188,8 @@
175
188
  letter-spacing: 0.02em;
176
189
  color: var(--fui-text-tertiary, $fui-text-tertiary);
177
190
  background: var(--fui-bg-elevated, $fui-bg-elevated);
178
- border: 1px solid var(--fui-border-default, $fui-border-default);
179
- border-bottom-width: 2px;
191
+ border: 1px solid var(--fui-field-border, $fui-border);
180
192
  border-radius: var(--fui-radius-sm, $fui-radius-sm);
181
- box-shadow:
182
- inset 0 0.5px 0 color-mix(in srgb, white 6%, transparent);
183
193
  pointer-events: none;
184
194
  white-space: nowrap;
185
195
  user-select: none;