@3fn/core 13.0.0 → 14.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 (284) hide show
  1. package/.kiro/agents/ada-prompt.md +80 -132
  2. package/.kiro/agents/ada-prompt.md.attribution.json +45 -0
  3. package/.kiro/agents/ada.json +44 -59
  4. package/.kiro/agents/ada.json.attribution.json +13 -0
  5. package/.kiro/agents/data-prompt.md +83 -74
  6. package/.kiro/agents/data-prompt.md.attribution.json +53 -0
  7. package/.kiro/agents/data.json +31 -38
  8. package/.kiro/agents/data.json.attribution.json +13 -0
  9. package/.kiro/agents/kenya-prompt.md +83 -72
  10. package/.kiro/agents/kenya-prompt.md.attribution.json +53 -0
  11. package/.kiro/agents/kenya.json +27 -35
  12. package/.kiro/agents/kenya.json.attribution.json +13 -0
  13. package/.kiro/agents/leonardo-prompt.md +176 -234
  14. package/.kiro/agents/leonardo-prompt.md.attribution.json +45 -0
  15. package/.kiro/agents/leonardo.json +28 -36
  16. package/.kiro/agents/leonardo.json.attribution.json +13 -0
  17. package/.kiro/agents/lina-prompt.md +110 -151
  18. package/.kiro/agents/lina-prompt.md.attribution.json +53 -0
  19. package/.kiro/agents/lina.json +46 -59
  20. package/.kiro/agents/lina.json.attribution.json +13 -0
  21. package/.kiro/agents/sparky-prompt.md +89 -72
  22. package/.kiro/agents/sparky-prompt.md.attribution.json +53 -0
  23. package/.kiro/agents/sparky.json +37 -37
  24. package/.kiro/agents/sparky.json.attribution.json +13 -0
  25. package/.kiro/agents/stacy-prompt.md +74 -48
  26. package/.kiro/agents/stacy-prompt.md.attribution.json +45 -0
  27. package/.kiro/agents/stacy.json +28 -30
  28. package/.kiro/agents/stacy.json.attribution.json +13 -0
  29. package/.kiro/agents/thurgood-prompt.md +94 -138
  30. package/.kiro/agents/thurgood-prompt.md.attribution.json +45 -0
  31. package/.kiro/agents/thurgood.json +31 -35
  32. package/.kiro/agents/thurgood.json.attribution.json +13 -0
  33. package/.kiro/steering/AI-Collaboration-Principles.md +3 -3
  34. package/.kiro/steering/Civitas-System-Overview.md +7 -16
  35. package/.kiro/steering/DesignerPunk-Systems-Overview.md +6 -6
  36. package/.kiro/steering/Spec-Feedback-Protocol.md +2 -11
  37. package/.kiro/steering/Task-Completion-Protocol.md +98 -17
  38. package/.kiro/steering/core-goals.md +3 -3
  39. package/.kiro/steering/personal-note.md +1 -1
  40. package/.kiro/steering/start-up-tasks.md +17 -6
  41. package/application-mcp-server/src/index.ts +26 -0
  42. package/dist/ComponentTokens.android.kt +12 -12
  43. package/dist/ComponentTokens.ios.swift +12 -12
  44. package/dist/ComponentTokens.web.css +3 -3
  45. package/dist/DesignTokens.android.kt +1 -1
  46. package/dist/DesignTokens.dtcg.json +8 -5
  47. package/dist/DesignTokens.figma.json +2 -2
  48. package/dist/DesignTokens.ios.swift +1 -1
  49. package/dist/DesignTokens.web.css +1 -1
  50. package/dist/android/DesignTokens.android.kt +1 -1
  51. package/dist/blend/OklchBlendCalculator.js +1 -0
  52. package/dist/blend/ThemeAwareBlendUtilities.web.d.ts +13 -2
  53. package/dist/blend/ThemeAwareBlendUtilities.web.js +6 -1
  54. package/dist/browser/designerpunk.esm.js +36 -90
  55. package/dist/browser/designerpunk.esm.min.js +33 -36
  56. package/dist/browser/designerpunk.umd.js +36 -90
  57. package/dist/browser/designerpunk.umd.min.js +47 -50
  58. package/dist/browser/tokens.css +3 -3
  59. package/dist/build/tokens/defineComponentTokens.d.ts +10 -0
  60. package/dist/build/tokens/defineComponentTokens.js +26 -0
  61. package/dist/components/core/Avatar-Base/avatar.tokens.d.ts +21 -26
  62. package/dist/components/core/Avatar-Base/avatar.tokens.js +31 -34
  63. package/dist/components/core/Avatar-Base/index.d.ts +1 -1
  64. package/dist/components/core/Avatar-Base/index.js +2 -2
  65. package/dist/components/core/Avatar-Base/platforms/web/Avatar.web.js +24 -5
  66. package/dist/components/core/Button-CTA/examples/BasicUsage.d.ts +16 -28
  67. package/dist/components/core/Button-CTA/examples/BasicUsage.js +18 -43
  68. package/dist/components/core/Button-CTA/platforms/web/ButtonCTA.web.d.ts +3 -15
  69. package/dist/components/core/Button-CTA/platforms/web/ButtonCTA.web.js +9 -58
  70. package/dist/components/core/Button-CTA/types.d.ts +0 -24
  71. package/dist/components/core/Button-CTA/types.js +6 -0
  72. package/dist/components/core/Button-Icon/buttonIcon.tokens.d.ts +28 -14
  73. package/dist/components/core/Button-Icon/buttonIcon.tokens.js +35 -20
  74. package/dist/components/core/Input-Text-Base/types.d.ts +13 -1
  75. package/dist/components/core/Input-Text-Password/platforms/web/InputTextPassword.web.js +11 -2
  76. package/dist/generators/DTCGFormatGenerator.js +8 -0
  77. package/dist/generators/TokenFileGenerator.js +7 -2
  78. package/dist/integration/BuildErrorHandler.js +2 -2
  79. package/dist/ios/DesignTokens.ios.swift +1 -1
  80. package/dist/mcp/application-mcp.js +24 -0
  81. package/dist/mcp/docs-mcp.js +130 -15
  82. package/dist/mcp/product-mcp.js +25 -0
  83. package/dist/tokens/OpacityTokens.js +1 -1
  84. package/dist/tokens/component/progress.d.ts +65 -5
  85. package/dist/tokens/component/progress.js +79 -18
  86. package/dist/tokens/semantic/BlendTokens.d.ts +10 -3
  87. package/dist/tokens/semantic/BlendTokens.js +17 -5
  88. package/dist/tokens/semantic/OpacityTokens.d.ts +4 -4
  89. package/dist/tokens/semantic/OpacityTokens.js +4 -4
  90. package/dist/types/ComponentTypes.d.ts +1 -1
  91. package/dist/types/generated/TokenTypes.d.ts +1 -1
  92. package/dist/types/generated/TokenTypes.js +1 -1
  93. package/dist/validators/StemmaTokenUsageValidator.js +3 -2
  94. package/dist/web/DesignTokens.web.css +1 -1
  95. package/governance/BUILD-SYSTEM-SETUP.md +1 -2
  96. package/governance/Component-Development-Guide.md +23 -13
  97. package/governance/Component-Development-Standards.md +21 -20
  98. package/governance/Component-Family-Avatar.md +6 -7
  99. package/governance/Component-Family-Badge.md +19 -20
  100. package/governance/Component-Family-Button.md +30 -43
  101. package/governance/Component-Family-Chip.md +14 -15
  102. package/governance/Component-Family-Container.md +12 -13
  103. package/governance/Component-Family-Data-Display.md +1 -2
  104. package/governance/Component-Family-Divider.md +1 -2
  105. package/governance/Component-Family-Form-Inputs.md +65 -65
  106. package/governance/Component-Family-Icon.md +9 -10
  107. package/governance/Component-Family-Loading.md +1 -2
  108. package/governance/Component-Family-Modal.md +1 -2
  109. package/governance/Component-Family-Navigation.md +1 -2
  110. package/governance/Component-Family-Progress.md +0 -1
  111. package/governance/Component-Inheritance-Structures.md +219 -99
  112. package/governance/Component-MCP-Document-Template.md +6 -5
  113. package/governance/Component-Primitive-vs-Semantic-Philosophy.md +1 -1
  114. package/governance/Component-Quick-Reference.md +33 -33
  115. package/governance/Component-Readiness-Status.md +59 -44
  116. package/governance/Component-Templates.md +57 -61
  117. package/governance/Contract-System-Reference.md +7 -7
  118. package/governance/MCP-Integration-Guide.md +1 -1
  119. package/governance/Process-Cross-Reference-Standards.md +31 -13
  120. package/governance/Process-Development-Workflow.md +49 -59
  121. package/governance/Process-File-Organization.md +25 -28
  122. package/governance/Process-Hook-Operations.md +22 -11
  123. package/governance/Process-Orchestration-Model-Selection.md +92 -0
  124. package/governance/Process-Spec-Planning.md +98 -52
  125. package/governance/Process-Task-Type-Definitions.md +80 -4
  126. package/governance/Product-Handoff-Protocol.md +2 -0
  127. package/governance/Rosetta-System-Architecture.md +13 -11
  128. package/governance/Test-Behavioral-Contract-Validation.md +38 -31
  129. package/governance/Test-Failure-Audit-Methodology.md +1 -1
  130. package/governance/Token-Family-Accessibility.md +1 -2
  131. package/governance/Token-Family-Blend.md +18 -16
  132. package/governance/Token-Family-Blur.md +0 -1
  133. package/governance/Token-Family-Border.md +1 -2
  134. package/governance/Token-Family-Color.md +0 -1
  135. package/governance/Token-Family-Glow.md +1 -2
  136. package/governance/Token-Family-Layering.md +0 -1
  137. package/governance/Token-Family-Motion.md +1 -2
  138. package/governance/Token-Family-Opacity.md +0 -1
  139. package/governance/Token-Family-Radius.md +1 -2
  140. package/governance/Token-Family-Responsive.md +1 -2
  141. package/governance/Token-Family-Shadow.md +1 -2
  142. package/governance/Token-Family-Sizing.md +0 -1
  143. package/governance/Token-Family-Spacing.md +1 -2
  144. package/governance/Token-Family-Typography.md +1 -2
  145. package/governance/Token-Governance.md +8 -8
  146. package/governance/Token-Quick-Reference.md +47 -34
  147. package/governance/Token-Resolution-Patterns.md +1 -1
  148. package/governance/Token-Semantic-Structure.md +1 -1
  149. package/governance/Web-Authoring-Standards.md +5 -5
  150. package/governance/browser-distribution-guide.md +1 -4
  151. package/governance/classification-map.md +474 -0
  152. package/governance/completion-documentation-guide.md +23 -37
  153. package/governance/component-meta-authoring-guide.md +1 -1
  154. package/governance/cross-platform-vs-platform-specific-decision-framework.md +1 -1
  155. package/governance/platform-implementation-guidelines.md +2 -3
  156. package/governance/release-management-system.md +28 -63
  157. package/governance/rosetta-system-principles.md +8 -6
  158. package/governance/stemma-system-principles.md +18 -17
  159. package/mcp-server/src/index.ts +24 -6
  160. package/mcp-server/src/indexer/DocumentIndexer.ts +119 -9
  161. package/mcp-server/src/indexer/__tests__/bare-id-crossrefs.test.ts +250 -0
  162. package/mcp-server/src/indexer/cross-ref-parser.ts +29 -1
  163. package/mcp-server/src/indexer/index-health.ts +27 -2
  164. package/mcp-server/src/query/__tests__/find-docs-calibration.test.ts +11 -26
  165. package/mcp-server/src/relocation-integrity-gate/__tests__/relocation-integrity-gate.test.ts +72 -5
  166. package/mcp-server/src/relocation-integrity-gate/relocation-integrity-gate.ts +81 -24
  167. package/mcp-server/src/tools/list-cross-references.ts +2 -2
  168. package/package.json +24 -26
  169. package/src/__tests__/browser-distribution/css-bundling.test.ts +6 -4
  170. package/src/__tests__/console-allowlist.json +14 -0
  171. package/src/__tests__/console-fail-setup.ts +169 -0
  172. package/src/__tests__/integration/Spec107-DesignLanguageContext.test.ts +16 -0
  173. package/src/__tests__/stemma-system/behavioral-contract-validation.test.ts +70 -17
  174. package/src/__tests__/stemma-system/contract-catalog-name-validation.test.ts +28 -0
  175. package/src/__tests__/stemma-system/form-inputs-contracts.test.ts +223 -16
  176. package/src/__tests__/stemma-system/input-text-native-base-call-alignment.test.ts +298 -0
  177. package/src/blend/OklchBlendCalculator.ts +3 -0
  178. package/src/blend/ThemeAwareBlendUtilities.android.kt +3 -0
  179. package/src/blend/ThemeAwareBlendUtilities.ios.swift +3 -0
  180. package/src/blend/ThemeAwareBlendUtilities.web.ts +9 -1
  181. package/src/blend/__tests__/InteractionStateAudit.test.ts +12 -9
  182. package/src/build/errors/__tests__/ErrorHandler.integration.test.ts +8 -0
  183. package/src/build/errors/__tests__/ErrorHandler.test.ts +5 -0
  184. package/src/build/tokens/__tests__/defineComponentTokens.test.ts +113 -0
  185. package/src/build/tokens/defineComponentTokens.ts +43 -1
  186. package/src/build/workflow/__tests__/CICDIntegration.test.ts +12 -1
  187. package/src/cli/__tests__/init.test.ts +45 -11
  188. package/src/components/core/Avatar-Base/Avatar-Base.schema.yaml +1 -1
  189. package/src/components/core/Avatar-Base/__tests__/Avatar.accessibility.test.ts +121 -7
  190. package/src/components/core/Avatar-Base/__tests__/Avatar.image.test.ts +3 -0
  191. package/src/components/core/Avatar-Base/__tests__/Avatar.test.ts +15 -6
  192. package/src/components/core/Avatar-Base/avatar.tokens.ts +31 -34
  193. package/src/components/core/Avatar-Base/contracts.yaml +11 -1
  194. package/src/components/core/Avatar-Base/index.ts +1 -1
  195. package/src/components/core/Avatar-Base/platforms/web/Avatar.web.ts +24 -5
  196. package/src/components/core/Badge-Count-Base/contracts.yaml +1 -1
  197. package/src/components/core/Badge-Label-Base/contracts.yaml +1 -1
  198. package/src/components/core/Button-CTA/Button-CTA.schema.yaml +2 -12
  199. package/src/components/core/Button-CTA/README.md +3 -6
  200. package/src/components/core/Button-CTA/__tests__/ButtonCTA.test.ts +35 -89
  201. package/src/components/core/Button-CTA/__tests__/setup.test.ts +0 -2
  202. package/src/components/core/Button-CTA/__tests__/test-utils.ts +0 -2
  203. package/src/components/core/Button-CTA/contracts.yaml +6 -29
  204. package/src/components/core/Button-CTA/examples/BasicUsage.html +2 -14
  205. package/src/components/core/Button-CTA/examples/BasicUsage.tsx +17 -44
  206. package/src/components/core/Button-CTA/platforms/android/ButtonCTA.android.kt +12 -20
  207. package/src/components/core/Button-CTA/platforms/ios/ButtonCTA.ios.swift +12 -51
  208. package/src/components/core/Button-CTA/platforms/web/ButtonCTA.web.css +2 -26
  209. package/src/components/core/Button-CTA/platforms/web/ButtonCTA.web.ts +18 -71
  210. package/src/components/core/Button-CTA/types.ts +10 -28
  211. package/src/components/core/Button-Icon/buttonIcon.tokens.ts +43 -27
  212. package/src/components/core/Chip-Base/__tests__/ChipBase.test.ts +13 -0
  213. package/src/components/core/Chip-Filter/__tests__/ChipFilter.test.ts +13 -0
  214. package/src/components/core/Chip-Input/__tests__/ChipInput.test.ts +13 -0
  215. package/src/components/core/Input-Text-Base/Input-Text-Base.schema.yaml +30 -2
  216. package/src/components/core/Input-Text-Base/README.md +25 -2
  217. package/src/components/core/Input-Text-Base/__tests__/focusIndicators.test.ts +16 -15
  218. package/src/components/core/Input-Text-Base/contracts.yaml +90 -0
  219. package/src/components/core/Input-Text-Base/platforms/android/InputTextBase.android.kt +26 -12
  220. package/src/components/core/Input-Text-Base/platforms/ios/InputTextBase.ios.swift +195 -59
  221. package/src/components/core/Input-Text-Base/types.ts +13 -1
  222. package/src/components/core/Input-Text-Email/Input-Text-Email.schema.yaml +5 -1
  223. package/src/components/core/Input-Text-Email/README.md +8 -7
  224. package/src/components/core/Input-Text-Email/platforms/android/InputTextEmail.android.kt +1 -4
  225. package/src/components/core/Input-Text-Email/platforms/ios/InputTextEmail.ios.swift +2 -16
  226. package/src/components/core/Input-Text-Password/Input-Text-Password.schema.yaml +10 -3
  227. package/src/components/core/Input-Text-Password/README.md +9 -8
  228. package/src/components/core/Input-Text-Password/contracts.yaml +5 -0
  229. package/src/components/core/Input-Text-Password/platforms/android/InputTextPassword.android.kt +17 -7
  230. package/src/components/core/Input-Text-Password/platforms/ios/InputTextPassword.ios.swift +22 -20
  231. package/src/components/core/Input-Text-Password/platforms/web/InputTextPassword.web.ts +11 -2
  232. package/src/components/core/Input-Text-PhoneNumber/Input-Text-PhoneNumber.schema.yaml +5 -1
  233. package/src/components/core/Input-Text-PhoneNumber/README.md +9 -8
  234. package/src/components/core/Input-Text-PhoneNumber/platforms/android/InputTextPhoneNumber.android.kt +2 -5
  235. package/src/components/core/Input-Text-PhoneNumber/platforms/ios/InputTextPhoneNumber.ios.swift +3 -17
  236. package/src/components/core/Nav-Header-App/contracts.yaml +1 -1
  237. package/src/components/core/Nav-SegmentedChoice-Base/contracts.yaml +1 -1
  238. package/src/components/core/Progress-Indicator-Connector-Base/contracts.yaml +1 -1
  239. package/src/components/core/Progress-Indicator-Label-Base/contracts.yaml +1 -1
  240. package/src/components/core/Progress-Indicator-Node-Base/contracts.yaml +1 -1
  241. package/src/components/core/Progress-Stepper-Base/__tests__/StepperBase.test.ts +5 -2
  242. package/src/components/core/Progress-Stepper-Detailed/__tests__/StepperDetailed.test.ts +5 -2
  243. package/src/generators/DTCGFormatGenerator.ts +6 -0
  244. package/src/generators/TokenFileGenerator.ts +7 -2
  245. package/src/generators/__tests__/DTCGConfigOptions.test.ts +14 -5
  246. package/src/integration/BuildErrorHandler.ts +2 -2
  247. package/src/tokens/OpacityTokens.ts +1 -1
  248. package/src/tokens/__tests__/OpacityTokens.test.ts +3 -1
  249. package/src/tokens/__tests__/ProgressTokenCompliance.test.ts +5 -3
  250. package/src/tokens/__tests__/ProgressTokenFormulas.test.ts +11 -11
  251. package/src/tokens/__tests__/ProgressTokenTranslation.test.ts +22 -20
  252. package/src/tokens/component/progress.ts +83 -21
  253. package/src/tokens/semantic/BlendTokens.ts +26 -5
  254. package/src/tokens/semantic/OpacityTokens.ts +4 -4
  255. package/src/types/ComponentTypes.ts +1 -1
  256. package/src/types/generated/TokenTypes.ts +1 -1
  257. package/src/validators/StemmaTokenUsageValidator.ts +3 -2
  258. package/token-index/components.yaml +8 -8
  259. package/token-index/semantics.yaml +1 -2
  260. package/src/tools/release/__tests__/ChangeClassifier.test.ts +0 -133
  261. package/src/tools/release/__tests__/ChangeExtractor.test.ts +0 -222
  262. package/src/tools/release/__tests__/GitHubPublisher.test.ts +0 -240
  263. package/src/tools/release/__tests__/NotesRenderer.test.ts +0 -142
  264. package/src/tools/release/__tests__/NpmPublisher.test.ts +0 -289
  265. package/src/tools/release/__tests__/PipelineIntegration.test.ts +0 -188
  266. package/src/tools/release/__tests__/ReleasePipeline.test.ts +0 -192
  267. package/src/tools/release/__tests__/SemanticVersionValidator.test.ts +0 -49
  268. package/src/tools/release/__tests__/SummaryScanner.test.ts +0 -141
  269. package/src/tools/release/__tests__/TagResolver.test.ts +0 -91
  270. package/src/tools/release/__tests__/VersionCalculator.test.ts +0 -270
  271. package/src/tools/release/__tests__/helpers/NpmMockHelper.ts +0 -80
  272. package/src/tools/release/cli/ReleasePipeline.ts +0 -165
  273. package/src/tools/release/cli/release-tool.ts +0 -107
  274. package/src/tools/release/pipeline/ChangeClassifier.ts +0 -61
  275. package/src/tools/release/pipeline/ChangeExtractor.ts +0 -87
  276. package/src/tools/release/pipeline/NotesRenderer.ts +0 -66
  277. package/src/tools/release/pipeline/SummaryScanner.ts +0 -70
  278. package/src/tools/release/pipeline/TagResolver.ts +0 -40
  279. package/src/tools/release/pipeline/VersionCalculator.ts +0 -375
  280. package/src/tools/release/publishers/GitHubPublisher.ts +0 -228
  281. package/src/tools/release/publishers/NpmPublisher.ts +0 -196
  282. package/src/tools/release/release-config.json +0 -5
  283. package/src/tools/release/types/index.ts +0 -282
  284. package/src/tools/release/validators/SemanticVersionValidator.ts +0 -67
@@ -11,7 +11,7 @@
11
11
  name: Input-Text-Base
12
12
  type: primitive
13
13
  family: FormInput
14
- version: "1.0.0"
14
+ version: "1.1.0"
15
15
  readiness:
16
16
  web:
17
17
  reviewed: true
@@ -25,6 +25,16 @@ composition:
25
25
  - component: Icon-Base
26
26
  role: Trailing contextual icon (error, success, info)
27
27
  required: false
28
+ slots:
29
+ - name: trailingContent
30
+ description: >-
31
+ Trailing content slot rendered after the status icons. Semantic
32
+ variants use it to inject interactive trailing controls (e.g.,
33
+ Input-Text-Password's visibility toggle). Native platforms only
34
+ (iOS: AnyView?, Android: @Composable lambda) — the web base has no
35
+ equivalent slot; web variants render trailing controls in their
36
+ own Shadow DOM.
37
+ required: false
28
38
 
29
39
  # Component description
30
40
  description: |
@@ -113,7 +123,11 @@ properties:
113
123
  type: boolean
114
124
  required: false
115
125
  default: false
116
- description: Read-only state (alternative to disabled)
126
+ description: >-
127
+ Read-only display state (state_readonly contract) — the value is
128
+ non-editable but stays perceivable, selectable, and copyable; no
129
+ keyboard/IME is raised and disabled semantics are never applied. iOS
130
+ renders it as selectable static text inside the field chrome.
117
131
 
118
132
  required:
119
133
  type: boolean
@@ -188,9 +202,23 @@ platform_notes:
188
202
  ios:
189
203
  implementation: SwiftUI View
190
204
  file: platforms/ios/InputTextBase.ios.swift
205
+ notes: |
206
+ Platform composition parameters (not part of the cross-platform props):
207
+ - trailingContent: AnyView? = nil — trailing content slot (see composition.slots)
208
+ Masking: type .password renders SecureField; other types render TextField.
209
+ Variants toggle visibility by switching type between .password and .text.
191
210
  android:
192
211
  implementation: Jetpack Compose Composable
193
212
  file: platforms/android/InputTextBase.android.kt
213
+ notes: |
214
+ Platform composition parameters (not part of the cross-platform props):
215
+ - modifier, imeAction, keyboardActions — standard Compose passthroughs
216
+ - visualTransformation: VisualTransformation? = null — masking override;
217
+ null derives from type (PasswordVisualTransformation for PASSWORD)
218
+ - trailingContent: (@Composable () -> Unit)? = null — trailing content
219
+ slot (see composition.slots)
220
+ Variants toggle password visibility via visualTransformation while
221
+ keeping type = PASSWORD (preserves the password keyboard type).
194
222
 
195
223
  # Semantic components that inherit from this primitive
196
224
  semantic_variants:
@@ -36,11 +36,12 @@ This component guarantees the following behaviors across all platforms:
36
36
  | `validates_on_blur` | Validation triggers on blur | 3.3.1 |
37
37
  | `error_state_display` | Shows error message and styling | 3.3.1, 1.4.1 |
38
38
  | `success_state_display` | Shows success styling | 1.4.1 |
39
- | `disabled_state` | Prevents interaction when disabled | 4.1.2 |
40
39
  | `trailing_icon_display` | Shows contextual trailing icons | 1.4.1 |
41
40
  | `focus_ring` | WCAG 2.4.7 focus visible indicator | 2.4.7 |
42
41
  | `reduced_motion_support` | Respects prefers-reduced-motion | 2.3.3 |
43
42
 
43
+ **Excluded**: `state_disabled` — DesignerPunk does not support disabled states for usability and accessibility reasons. If an action is unavailable, the component should not be rendered (adjudicated 2026-07-15).
44
+
44
45
  ---
45
46
 
46
47
  ## Related Documentation
@@ -145,12 +146,27 @@ InputTextBase(
145
146
  | `type` | `'text' \| 'email' \| 'password' \| 'tel' \| 'url'` | No | `'text'` | Input type |
146
147
  | `autocomplete` | `string` | No | - | Autocomplete attribute for browser autofill |
147
148
  | `placeholder` | `string` | No | - | Placeholder text (only shown when label is floated and input is empty) |
148
- | `readOnly` | `boolean` | No | `false` | Read-only state (alternative to disabled) |
149
+ | `readOnly` | `boolean` | No | `false` | Read-only display state (`state_readonly` contract): value is non-editable but selectable and copyable; no keyboard raised; iOS renders selectable text in the field chrome. Ignored for secure types; not supported by Input-Text-Password |
149
150
  | `required` | `boolean` | No | `false` | Required field indicator |
150
151
  | `maxLength` | `number` | No | - | Maximum length for input value |
151
152
  | `testID` | `string` | No | - | Test ID for automated testing |
152
153
  | `className` | `string` | No | - | Additional CSS class names (web only) |
153
154
 
155
+ ### Platform Composition Parameters (native only)
156
+
157
+ These parameters exist on the native implementations for platform composition —
158
+ they are not part of the cross-platform props contract above:
159
+
160
+ | Parameter | Platform | Type | Default | Description |
161
+ |-----------|----------|------|---------|-------------|
162
+ | `trailingContent` | iOS | `AnyView?` | `nil` | Trailing content slot rendered after the status icons (e.g., Input-Text-Password's visibility toggle) |
163
+ | `trailingContent` | Android | `(@Composable () -> Unit)?` | `null` | Same slot, Compose form |
164
+ | `visualTransformation` | Android | `VisualTransformation?` | `null` | Masking override; `null` derives from `type` (`PasswordVisualTransformation` for `PASSWORD`). Lets variants toggle password visibility while keeping the password keyboard type |
165
+ | `modifier`, `imeAction`, `keyboardActions` | Android | — | — | Standard Compose passthroughs |
166
+
167
+ The web base has no trailing slot equivalent — web semantic variants render
168
+ trailing controls inside their own Shadow DOM.
169
+
154
170
  ---
155
171
 
156
172
  ## Token Consumption
@@ -221,6 +237,13 @@ Legacy type aliases are provided for backward compatibility during migration.
221
237
 
222
238
  ## Changelog
223
239
 
240
+ ### v1.1.0 (July 2026)
241
+
242
+ - Native bases gain a `trailingContent` composition slot (iOS `AnyView?`, Android `@Composable` lambda) so semantic variants can inject trailing controls — required by Input-Text-Password's visibility toggle
243
+ - Android base gains a `visualTransformation` override (null = derived from `type`) so variants can toggle masking without changing the input type
244
+ - Fixed Input-Text-PhoneNumber native callers referencing nonexistent enum members (`.phone`/`PHONE` → `.tel`/`TEL`)
245
+ - Added static base-call alignment test (`src/__tests__/stemma-system/input-text-native-base-call-alignment.test.ts`) guarding native call sites against parameter/enum drift
246
+
224
247
  ### v1.0.0 (January 2026)
225
248
 
226
249
  - Initial release as Input-Text-Base (renamed from TextInputField)
@@ -165,8 +165,8 @@ describe('Input-Text-Base Focus Indicators', () => {
165
165
  expect(iosComponentContent).toContain('accessibilityFocusWidth');
166
166
  expect(iosComponentContent).toContain('accessibilityFocusOffset');
167
167
 
168
- // Verify focus ring is visible when focused (and not disabled)
169
- expect(iosComponentContent).toContain('.opacity(isFocused && !isDisabled ? 1 : 0)');
168
+ // Verify focus ring is visible when focused
169
+ expect(iosComponentContent).toContain('.opacity(isFocused ? 1 : 0)');
170
170
  });
171
171
 
172
172
  it('should have focus ring animation that respects reduce motion', () => {
@@ -194,8 +194,8 @@ describe('Input-Text-Base Focus Indicators', () => {
194
194
  expect(androidComponentContent).toContain('accessibilityFocusColor');
195
195
  expect(androidComponentContent).toContain('accessibilityFocusOffset');
196
196
 
197
- // Verify focus ring is conditional on focus state (and not disabled)
198
- expect(androidComponentContent).toContain('if (isFocused && !isDisabled)');
197
+ // Verify focus ring is conditional on focus state
198
+ expect(androidComponentContent).toContain('if (isFocused)');
199
199
  });
200
200
  });
201
201
 
@@ -219,16 +219,17 @@ describe('Input-Text-Base Focus Indicators', () => {
219
219
 
220
220
  // iOS: Verify focus ring is not conditional on error/success state
221
221
  // (it should always show when focused, regardless of validation state)
222
- // Note: Focus ring is hidden when disabled (isDisabled check is expected)
223
- // Find the focus ring section in the InputTextBaseFieldStyle
222
+ // Find the focus ring section in InputTextBaseFieldChrome (the shared
223
+ // field chrome, extracted from InputTextBaseFieldStyle per the B-prime
224
+ // readOnly ruling, 2026-07-15)
224
225
  const iosFocusRingSection = iosContent.substring(
225
- iosContent.indexOf('.opacity(isFocused && !isDisabled ? 1 : 0)'),
226
- iosContent.indexOf('.opacity(isFocused && !isDisabled ? 1 : 0)') + 200
226
+ iosContent.indexOf('.opacity(isFocused ? 1 : 0)'),
227
+ iosContent.indexOf('.opacity(isFocused ? 1 : 0)') + 200
227
228
  );
228
- expect(iosFocusRingSection).toContain('.opacity(isFocused && !isDisabled ? 1 : 0)');
229
-
230
- // Android: Verify focus ring is conditional on focus state (and not disabled)
231
- expect(androidContent).toContain('if (isFocused && !isDisabled)');
229
+ expect(iosFocusRingSection).toContain('.opacity(isFocused ? 1 : 0)');
230
+
231
+ // Android: Verify focus ring is conditional on focus state
232
+ expect(androidContent).toContain('if (isFocused)');
232
233
  });
233
234
  });
234
235
 
@@ -249,10 +250,10 @@ describe('Input-Text-Base Focus Indicators', () => {
249
250
  expect(cssContent).toContain(':focus-visible');
250
251
 
251
252
  // iOS: Uses overlay with opacity based on focus state
252
- expect(iosContent).toContain('.opacity(isFocused && !isDisabled ? 1 : 0)');
253
-
253
+ expect(iosContent).toContain('.opacity(isFocused ? 1 : 0)');
254
+
254
255
  // Android: Uses conditional border based on focus state
255
- expect(androidContent).toContain('if (isFocused && !isDisabled)');
256
+ expect(androidContent).toContain('if (isFocused)');
256
257
  });
257
258
 
258
259
  it('should document WCAG 2.4.7 compliance in behavioral contracts', () => {
@@ -9,12 +9,29 @@ contracts:
9
9
  behavior: |
10
10
  Component can receive focus via Tab key navigation.
11
11
  Focus state is visually indicated and triggers label animation.
12
+
13
+ Platform note — iOS readOnly carve-out (declared, adjudicated): when
14
+ readOnly is true, iOS renders the value as selectable static text
15
+ (see state_readonly) and does NOT participate in keyboard/Full
16
+ Keyboard Access focus order; onFocus/onBlur are declared not-fired on
17
+ that path. Web and Android readOnly fields affirmatively REMAIN in
18
+ focus order and fire focus events (removing an Android readOnly field
19
+ from focus order would require enabled=false — banned disabled
20
+ semantics — so normalizing web/Android down to iOS is not an
21
+ available move). The carve-out is a mitigable declared exception, not
22
+ a settled permanent difference: an on-device .focusable(interactions:)
23
+ prototype is tracked, and if it verifies (FKA reachability + keyboard
24
+ copy), iOS re-enters focus order and this note tightens to full
25
+ three-platform participation.
26
+ Ruling: .kiro/issues/input-text-base-ios-readonly-adjudication.md
27
+ (RULED B-prime, Peter 2026-07-15).
12
28
  wcag: "2.1.1 Keyboard"
13
29
  platforms: [web, ios, android]
14
30
  validation:
15
31
  - Tab key moves focus to input
16
32
  - Focus state is visually distinct
17
33
  - Focus triggers label float animation
34
+ - readOnly fields remain in keyboard focus order on web and Android
18
35
  test_approach: |
19
36
  - Press Tab, verify input receives focus
20
37
  - Verify label animates on focus
@@ -74,6 +91,79 @@ contracts:
74
91
  - Set error state, verify border/label/icon/message
75
92
  required: true
76
93
 
94
+ # state_readonly concept ratified into the Concept Catalog via ballot
95
+ # (.kiro/docs/ballots/2026-07-15-state-readonly-concept.md, RATIFIED Peter
96
+ # 2026-07-15). Authored under the B-prime ruling:
97
+ # .kiro/issues/input-text-base-ios-readonly-adjudication.md (RULED by Peter,
98
+ # 2026-07-15).
99
+ state_readonly:
100
+ category: state
101
+ description: Displays a non-editable value that stays perceivable, selectable, and copyable — never disabled semantics
102
+ behavior: |
103
+ When readOnly is true, the component displays its value without
104
+ allowing edits. Invariants on all platforms:
105
+ - Content is selectable and copyable (whole-string copy is the
106
+ accepted iOS behavior — long-press select/copy on static text).
107
+ - Content is not editable; no software keyboard/IME is raised.
108
+ - Assistive technology announces the label, the value, and a
109
+ read-only indication — NEVER a disabled/dimmed trait or state.
110
+ - No disabled semantics of any kind (no SwiftUI .disabled(), no
111
+ Compose enabled=false, no aria-disabled/disabled attribute).
112
+
113
+ Announcement per platform:
114
+ - Web: native readonly attribute semantics (implicit aria-readonly).
115
+ - Android: explicit stateDescription("read only") in semantics.
116
+ - iOS: composed accessibility — label + value + read-only hint.
117
+
118
+ Focus order per platform:
119
+ - Web and Android: readOnly fields affirmatively PARTICIPATE in
120
+ keyboard focus order and fire onFocus/onBlur.
121
+ - iOS: readOnly content is rendered as selectable static text inside
122
+ the shared field chrome (B-prime); it is NOT in keyboard/FKA focus
123
+ order and onFocus/onBlur are DECLARED not-fired — a mitigable
124
+ declared exception. A .focusable(interactions:) on-device prototype
125
+ is tracked; if it verifies, this contract auto-tightens and iOS
126
+ re-enters focus order.
127
+
128
+ Tap-acknowledgment delta (platform note): tapping an Android readOnly
129
+ field focuses it (focus ring engages; empty-field label floats);
130
+ tapping the iOS readOnly text gives no acknowledgment until
131
+ long-press (select/copy). Declared, cosmetic.
132
+
133
+ Empty-value behavior: the label rests in placeholder position on all
134
+ platforms (no platform force-floats it), and the field chrome
135
+ reserves its full height unconditionally.
136
+
137
+ Secure-type carve-out (declared): when Input-Text-Base is used
138
+ directly with a secure/password type, readOnly is IGNORED — the field
139
+ remains an editable secure field. The read-only display path renders
140
+ the value as selectable plaintext and must be unreachable for
141
+ secrets; read-only passwords are excluded at the variant level
142
+ (Input-Text-Password excludes state_readonly and never forwards
143
+ readOnly).
144
+ wcag: "4.1.2 Name, Role, Value"
145
+ platforms: [web, ios, android]
146
+ validation:
147
+ - Value is not editable when readOnly is true
148
+ - Content is selectable and copyable on all platforms
149
+ - No software keyboard/IME is raised
150
+ - Web renders the native readonly attribute
151
+ - Android passes readOnly to the text field with enabled=true and sets
152
+ stateDescription("read only")
153
+ - iOS renders selectable Text (textSelection enabled) inside the
154
+ shared field chrome and composes a read-only accessibility hint
155
+ - No platform applies disabled semantics (.disabled(), enabled=false,
156
+ aria-disabled, dimmed trait)
157
+ - readOnly fields remain in keyboard focus order on web and Android
158
+ test_approach: |
159
+ - Static (Jest): web readonly attribute wiring; Android
160
+ readOnly = readOnly pass-through; iOS textSelection path present and
161
+ no .disabled( anywhere in Form Inputs iOS sources
162
+ - Device: attempt edit (rejected), copy value, verify announcement
163
+ (VoiceOver: label + value + read-only hint, never "dimmed";
164
+ TalkBack: "read only")
165
+ required: true
166
+
77
167
  state_success:
78
168
  category: state
79
169
  description: Shows success styling
@@ -13,17 +13,17 @@
13
13
  * - Color animation (text.subtle → primary with blend.focusSaturate)
14
14
  * - Offset animation (translateY)
15
15
  * - Trailing icon support (error, success, info)
16
+ * - Trailing content slot for semantic variants (e.g., password toggle)
16
17
  * - Respects reduce motion settings
17
18
  * - WCAG 2.1 AA compliant
18
- * - Uses theme-aware blend utilities for state colors (focus, disabled)
19
- *
19
+ * - Uses theme-aware blend utilities for state colors (focus)
20
+ *
20
21
  * Behavioral Contracts:
21
22
  * - focusable: Can receive keyboard focus
22
23
  * - float_label_animation: Label animates on focus
23
24
  * - validates_on_blur: Validation triggers on blur
24
25
  * - error_state_display: Shows error message and styling
25
26
  * - success_state_display: Shows success styling
26
- * - disabled_state: Prevents interaction when disabled
27
27
  * - trailing_icon_display: Shows contextual trailing icons
28
28
  * - focus_ring: WCAG 2.4.7 focus visible indicator
29
29
  * - reduced_motion_support: Respects prefers-reduced-motion
@@ -57,6 +57,7 @@ import androidx.compose.ui.platform.LocalDensity
57
57
  import androidx.compose.ui.semantics.contentDescription
58
58
  import androidx.compose.ui.semantics.error
59
59
  import androidx.compose.ui.semantics.semantics
60
+ import androidx.compose.ui.semantics.stateDescription
60
61
  import androidx.compose.ui.text.TextStyle
61
62
  import androidx.compose.ui.text.font.FontWeight
62
63
  import androidx.compose.ui.text.input.ImeAction
@@ -68,7 +69,6 @@ import androidx.compose.ui.unit.dp
68
69
  import androidx.compose.ui.unit.sp
69
70
  import android.provider.Settings
70
71
  import com.designerpunk.tokens.focusBlend
71
- import com.designerpunk.tokens.disabledBlend
72
72
 
73
73
  /**
74
74
  * Input type enumeration
@@ -99,13 +99,17 @@ enum class InputType {
99
99
  * @param isSuccess Success state indicator
100
100
  * @param showInfoIcon Info icon support
101
101
  * @param type Input type
102
+ * @param visualTransformation Override for the input's visual transformation.
103
+ * When null, derived from type (PasswordVisualTransformation for PASSWORD).
104
+ * Semantic variants use this to control masking (e.g., password visibility toggle).
102
105
  * @param placeholder Placeholder text (only shown when label is floated and input is empty)
103
106
  * @param readOnly Read-only state
104
107
  * @param required Required field indicator
105
108
  * @param maxLength Maximum length for input value
106
109
  * @param imeAction IME action for keyboard
107
110
  * @param keyboardActions Keyboard actions
108
- * @param isDisabled Disabled state
111
+ * @param trailingContent Trailing content slot rendered after the status icons
112
+ * (e.g., password visibility toggle)
109
113
  */
110
114
  @Composable
111
115
  fun InputTextBase(
@@ -121,13 +125,14 @@ fun InputTextBase(
121
125
  isSuccess: Boolean = false,
122
126
  showInfoIcon: Boolean = false,
123
127
  type: InputType = InputType.TEXT,
128
+ visualTransformation: VisualTransformation? = null,
124
129
  placeholder: String? = null,
125
130
  readOnly: Boolean = false,
126
131
  required: Boolean = false,
127
132
  maxLength: Int? = null,
128
133
  imeAction: ImeAction = ImeAction.Done,
129
134
  keyboardActions: KeyboardActions = KeyboardActions.Default,
130
- isDisabled: Boolean = false
135
+ trailingContent: (@Composable () -> Unit)? = null
131
136
  ) {
132
137
  // State
133
138
  var isFocused by remember { mutableStateOf(false) }
@@ -192,7 +197,6 @@ fun InputTextBase(
192
197
  targetValue = when {
193
198
  hasError -> colorFeedbackErrorText
194
199
  isSuccess -> colorFeedbackSuccessText
195
- isDisabled -> colorActionPrimary.disabledBlend()
196
200
  isFocused -> colorActionPrimary.focusBlend()
197
201
  else -> colorTextMuted
198
202
  },
@@ -204,7 +208,6 @@ fun InputTextBase(
204
208
  targetValue = when {
205
209
  hasError -> colorFeedbackErrorText
206
210
  isSuccess -> colorFeedbackSuccessText
207
- isDisabled -> colorActionPrimary.disabledBlend()
208
211
  isFocused -> colorActionPrimary.focusBlend()
209
212
  else -> colorBorder
210
213
  },
@@ -230,6 +233,14 @@ fun InputTextBase(
230
233
  if (errorMessage != null) {
231
234
  error(errorMessage)
232
235
  }
236
+ if (readOnly) {
237
+ // Explicit TalkBack read-only announcement — label, value,
238
+ // and "read only", never a disabled/dimmed state
239
+ // (state_readonly contract, announcement-parity condition 3:
240
+ // .kiro/issues/input-text-base-ios-readonly-adjudication.md,
241
+ // RULED B-prime, Peter 2026-07-15).
242
+ stateDescription = "read only"
243
+ }
233
244
  }
234
245
  ) {
235
246
  // Input wrapper with label and trailing icon
@@ -278,7 +289,7 @@ fun InputTextBase(
278
289
  shape = RoundedCornerShape(radius150)
279
290
  )
280
291
  .then(
281
- if (isFocused && !isDisabled) {
292
+ if (isFocused) {
282
293
  Modifier.border(
283
294
  width = accessibilityFocusWidth,
284
295
  color = accessibilityFocusColor,
@@ -295,7 +306,7 @@ fun InputTextBase(
295
306
  lineHeight = typographyInputLineHeight.sp,
296
307
  fontWeight = FontWeight(typographyInputFontWeight),
297
308
  letterSpacing = typographyInputLetterSpacing.sp,
298
- color = if (isDisabled) colorTextMuted else colorTextDefault
309
+ color = colorTextDefault
299
310
  ),
300
311
  keyboardOptions = KeyboardOptions(
301
312
  keyboardType = getKeyboardType(type),
@@ -303,8 +314,8 @@ fun InputTextBase(
303
314
  ),
304
315
  keyboardActions = keyboardActions,
305
316
  singleLine = true,
306
- readOnly = readOnly || isDisabled,
307
- visualTransformation = if (type == InputType.PASSWORD) {
317
+ readOnly = readOnly,
318
+ visualTransformation = visualTransformation ?: if (type == InputType.PASSWORD) {
308
319
  PasswordVisualTransformation()
309
320
  } else {
310
321
  VisualTransformation.None
@@ -373,6 +384,9 @@ fun InputTextBase(
373
384
  )
374
385
  }
375
386
  }
387
+
388
+ // Trailing content slot (e.g., password visibility toggle)
389
+ trailingContent?.invoke()
376
390
  }
377
391
 
378
392
  // Helper text (persistent)