@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
@@ -7,7 +7,7 @@
7
7
  * Unit tests for Button-CTA component rendering
8
8
  *
9
9
  * Tests component rendering with various props, size variants, variant styles,
10
- * icon integration, text wrapping, and disabled state.
10
+ * icon integration, and text wrapping.
11
11
  *
12
12
  * Stemma System Naming: [Family]-[Type] = Button-CTA
13
13
  * Component Type: Standalone (no behavioral variants)
@@ -66,7 +66,6 @@ describe('Button-CTA Component Rendering', () => {
66
66
  buttonVariant?: 'primary' | 'secondary' | 'tertiary';
67
67
  icon?: string;
68
68
  noWrap?: boolean;
69
- disabled?: boolean;
70
69
  testID?: string;
71
70
  }): ButtonCTA {
72
71
  // Create element - constructor runs and attaches shadow DOM
@@ -78,7 +77,6 @@ describe('Button-CTA Component Rendering', () => {
78
77
  if (props.buttonVariant) button.buttonVariant = props.buttonVariant;
79
78
  if (props.icon) button.icon = props.icon;
80
79
  if (props.noWrap !== undefined) button.noWrap = props.noWrap;
81
- if (props.disabled !== undefined) button.disabled = props.disabled;
82
80
  if (props.testID) button.testID = props.testID;
83
81
 
84
82
  // Append to container
@@ -287,40 +285,48 @@ describe('Button-CTA Component Rendering', () => {
287
285
  });
288
286
  });
289
287
 
290
- describe('Disabled State', () => {
291
- it('should render disabled button with correct attributes', () => {
292
- // Requirement: Disabled prop prevents interaction
293
- const button = createButton({ label: 'Disabled Button', disabled: true });
294
-
295
- const shadowButton = button.shadowRoot?.querySelector('button');
296
- expect(shadowButton?.hasAttribute('disabled')).toBe(true);
297
- expect(shadowButton?.getAttribute('aria-disabled')).toBe('true');
298
- expect(shadowButton?.className).toContain('button-cta--disabled');
288
+ describe('No Disabled State (philosophy exclusion)', () => {
289
+ // DesignerPunk does not support disabled states: if an action is
290
+ // unavailable, the component should not be rendered. state_disabled was
291
+ // removed from Button-CTA per the 2026-07-15 adjudication; these tests
292
+ // guard against the disabled state resurfacing.
293
+
294
+ it('should declare state_disabled under excludes (not contracts) in contracts.yaml', () => {
295
+ const fs = require('fs');
296
+ const path = require('path');
297
+ const contractsContent = fs.readFileSync(
298
+ path.join(__dirname, '../contracts.yaml'),
299
+ 'utf-8'
300
+ );
301
+
302
+ const contractsSection = contractsContent.split(/^excludes:/m)[0];
303
+ const excludesSection = contractsContent.split(/^excludes:/m)[1] ?? '';
304
+ expect(contractsSection).not.toContain('state_disabled');
305
+ expect(excludesSection).toContain('state_disabled');
299
306
  });
300
-
301
- it('should not have disabled attributes when disabled is false', () => {
302
- // Requirement: Enabled button is interactive
303
- const button = createButton({ label: 'Enabled Button', disabled: false });
304
-
305
- const shadowButton = button.shadowRoot?.querySelector('button');
306
- expect(shadowButton?.hasAttribute('disabled')).toBe(false);
307
- expect(shadowButton?.getAttribute('aria-disabled')).toBe('false');
308
- expect(shadowButton?.className).not.toContain('button-cta--disabled');
307
+
308
+ it('should not expose a disabled property or observe a disabled attribute', () => {
309
+ expect(ButtonCTA.observedAttributes).not.toContain('disabled');
310
+
311
+ const button = createButton({ label: 'Button' });
312
+ expect('disabled' in button).toBe(false);
309
313
  });
310
-
311
- it('should prevent press event when disabled', () => {
312
- // Requirement: Disabled button doesn't trigger onPress
313
- const button = createButton({ label: 'Disabled Button', disabled: true });
314
-
314
+
315
+ it('should ignore a disabled attribute set by consumers', () => {
316
+ const button = createButton({ label: 'Button' });
317
+ button.setAttribute('disabled', '');
318
+
315
319
  let pressCount = 0;
316
320
  button.addEventListener('press', () => {
317
321
  pressCount++;
318
322
  });
319
-
323
+
320
324
  const shadowButton = button.shadowRoot?.querySelector('button');
325
+ expect(shadowButton?.hasAttribute('disabled')).toBe(false);
326
+ expect(shadowButton?.className).not.toContain('button-cta--disabled');
327
+
321
328
  shadowButton?.click();
322
-
323
- expect(pressCount).toBe(0);
329
+ expect(pressCount).toBe(1);
324
330
  });
325
331
  });
326
332
 
@@ -409,21 +415,6 @@ describe('Button-CTA Component Rendering', () => {
409
415
  expect(pressCount).toBe(1);
410
416
  });
411
417
 
412
- it('should NOT call onPress when button disabled', () => {
413
- // Requirement 15.1: Disabled button doesn't trigger onPress
414
- const button = createButton({ label: 'Disabled Button', disabled: true });
415
-
416
- let pressCount = 0;
417
- button.addEventListener('press', () => {
418
- pressCount++;
419
- });
420
-
421
- const shadowButton = button.shadowRoot?.querySelector('button');
422
- shadowButton?.click();
423
-
424
- expect(pressCount).toBe(0);
425
- });
426
-
427
418
  it('should receive focus via Tab key', () => {
428
419
  // Requirement 15.2: Button is keyboard focusable
429
420
  const button = createButton({ label: 'Focusable Button' });
@@ -647,19 +638,6 @@ describe('Button-CTA Component Rendering', () => {
647
638
  expect(shadowButton?.getAttribute('role')).toBe('button');
648
639
  expect(shadowButton?.getAttribute('aria-label')).toBe('Accessible Button');
649
640
  expect(shadowButton?.getAttribute('type')).toBe('button');
650
- expect(shadowButton?.getAttribute('aria-disabled')).toBe('false');
651
- });
652
-
653
- it('should have proper ARIA attributes when disabled', () => {
654
- // Requirement 12.6: Disabled button has correct ARIA attributes
655
- const button = createButton({ label: 'Disabled Button', disabled: true });
656
-
657
- const shadowButton = button.shadowRoot?.querySelector('button');
658
-
659
- // Verify disabled ARIA attributes
660
- expect(shadowButton?.getAttribute('role')).toBe('button');
661
- expect(shadowButton?.getAttribute('aria-disabled')).toBe('true');
662
- expect(shadowButton?.hasAttribute('disabled')).toBe(true);
663
641
  });
664
642
 
665
643
  it('should support keyboard navigation with Enter key', () => {
@@ -716,37 +694,5 @@ describe('Button-CTA Component Rendering', () => {
716
694
  expect(pressCount).toBe(1);
717
695
  });
718
696
 
719
- it('should not activate on keyboard when disabled', () => {
720
- // Requirement 15.4: Disabled button doesn't respond to keyboard
721
- const button = createButton({ label: 'Disabled Keyboard', disabled: true });
722
-
723
- let pressCount = 0;
724
- button.addEventListener('press', () => {
725
- pressCount++;
726
- });
727
-
728
- const shadowButton = button.shadowRoot?.querySelector('button');
729
- shadowButton?.focus();
730
-
731
- // Try Enter key
732
- const enterEvent = new KeyboardEvent('keydown', {
733
- key: 'Enter',
734
- code: 'Enter',
735
- bubbles: true,
736
- cancelable: true
737
- });
738
- shadowButton?.dispatchEvent(enterEvent);
739
-
740
- // Try Space key
741
- const spaceEvent = new KeyboardEvent('keydown', {
742
- key: ' ',
743
- code: 'Space',
744
- bubbles: true,
745
- cancelable: true
746
- });
747
- shadowButton?.dispatchEvent(spaceEvent);
748
-
749
- expect(pressCount).toBe(0);
750
- });
751
697
  });
752
698
  });
@@ -123,7 +123,6 @@ describe('Button-CTA Test Infrastructure Setup', () => {
123
123
  buttonVariant: 'secondary',
124
124
  icon: 'arrow-right',
125
125
  noWrap: true,
126
- disabled: false,
127
126
  testID: 'test-button'
128
127
  });
129
128
 
@@ -132,7 +131,6 @@ describe('Button-CTA Test Infrastructure Setup', () => {
132
131
  expect(button.buttonVariant).toBe('secondary');
133
132
  expect(button.icon).toBe('arrow-right');
134
133
  expect(button.noWrap).toBe(true);
135
- expect(button.disabled).toBe(false);
136
134
  expect(button.testID).toBe('test-button');
137
135
  });
138
136
 
@@ -96,7 +96,6 @@ export async function createButtonCTA(props: {
96
96
  buttonVariant?: 'primary' | 'secondary' | 'tertiary';
97
97
  icon?: string;
98
98
  noWrap?: boolean;
99
- disabled?: boolean;
100
99
  testID?: string;
101
100
  }): Promise<ButtonCTA> {
102
101
  registerButtonCTA();
@@ -109,7 +108,6 @@ export async function createButtonCTA(props: {
109
108
  if (props.buttonVariant) button.buttonVariant = props.buttonVariant;
110
109
  if (props.icon) button.icon = props.icon;
111
110
  if (props.noWrap !== undefined) button.noWrap = props.noWrap;
112
- if (props.disabled !== undefined) button.disabled = props.disabled;
113
111
  if (props.testID) button.testID = props.testID;
114
112
 
115
113
  // Append to document to trigger rendering
@@ -9,17 +9,14 @@ contracts:
9
9
  behavior: |
10
10
  Component can receive focus via Tab key navigation.
11
11
  Focus state is visually indicated with a focus ring.
12
- Focus is managed appropriately when disabled state changes.
13
12
  wcag: "2.1.1 Keyboard"
14
13
  platforms: [web, ios, android]
15
14
  validation:
16
15
  - Tab key moves focus to button
17
16
  - Focus state is visually distinct with focus ring
18
17
  - Focus ring meets 3:1 contrast ratio
19
- - Disabled buttons are not focusable
20
18
  test_approach: |
21
19
  - Render button, press Tab, verify focus
22
- - Set disabled=true, verify not focusable
23
20
  required: true
24
21
 
25
22
  interaction_pressable:
@@ -27,7 +24,7 @@ contracts:
27
24
  description: Responds to press/click events
28
25
  behavior: |
29
26
  Component responds to click, tap, Enter key, and Space key.
30
- Press triggers the onPress callback when not disabled.
27
+ Press triggers the onPress callback.
31
28
  Platform-appropriate feedback is provided during press.
32
29
  wcag: "2.1.1 Keyboard"
33
30
  platforms: [web, ios, android]
@@ -35,11 +32,9 @@ contracts:
35
32
  - Click/tap triggers onPress callback
36
33
  - Enter key triggers onPress callback
37
34
  - Space key triggers onPress callback
38
- - onPress not called when disabled
39
35
  test_approach: |
40
36
  - Click button, verify onPress called
41
37
  - Focus and press Enter, verify onPress called
42
- - Set disabled, click, verify onPress not called
43
38
  required: true
44
39
 
45
40
  interaction_hover:
@@ -56,10 +51,8 @@ contracts:
56
51
  - Background color darkens on mouse enter (ΔL 0.02–0.05)
57
52
  - Background color reverts on mouse leave
58
53
  - Chroma unchanged between rest and hover states
59
- - Hover state not shown when disabled
60
54
  test_approach: |
61
55
  - Simulate hover, verify background change
62
- - Set disabled, simulate hover, verify no change
63
56
  required: true
64
57
 
65
58
  interaction_pressed:
@@ -76,31 +69,10 @@ contracts:
76
69
  - Visual feedback shown during press (ΔL 0.05–0.10)
77
70
  - Pressed state is perceptibly stronger than hover
78
71
  - Platform-appropriate animation/effect applied
79
- - Pressed state not shown when disabled
80
72
  test_approach: |
81
73
  - Simulate press, verify visual feedback
82
74
  required: true
83
75
 
84
- state_disabled:
85
- category: state
86
- description: Prevents interaction when disabled
87
- behavior: |
88
- When disabled, component cannot receive focus, cannot be clicked/tapped,
89
- appears visually muted via chroma reduction (OKLCH ΔC ≥0.03 desaturation),
90
- shows cursor: not-allowed (web), and communicates disabled state to
91
- assistive technology.
92
- wcag: "4.1.2 Name, Role, Value"
93
- platforms: [web, ios, android]
94
- validation:
95
- - Button cannot receive focus when disabled
96
- - onPress not called when disabled
97
- - Visual styling indicates disabled state (chroma reduced ≥0.03)
98
- - aria-disabled="true" set (web)
99
- test_approach: |
100
- - Set disabled=true, verify not focusable
101
- - Verify aria-disabled attribute (web)
102
- required: true
103
-
104
76
  state_loading:
105
77
  category: state
106
78
  description: Shows loading indicator during async operations
@@ -138,3 +110,8 @@ contracts:
138
110
  - Tab to button, verify focus ring visible
139
111
  - Test in each variant
140
112
  required: true
113
+
114
+ excludes:
115
+ state_disabled:
116
+ reason: "DesignerPunk does not support disabled states for usability and accessibility reasons. If an action is unavailable, the component should not be rendered."
117
+ category: state
@@ -99,12 +99,8 @@
99
99
  </div>
100
100
 
101
101
  <div class="example-section">
102
- <h2>Example 4: Disabled Button</h2>
103
- <p>Button in disabled state that cannot be interacted with.</p>
104
- <div class="button-container">
105
- <button-cta id="disabled-btn" label="Submit" disabled></button-cta>
106
- </div>
107
- <div class="output" id="disabled-output">This button is disabled and won't respond to clicks.</div>
102
+ <h2>Example 4: Unavailable Actions</h2>
103
+ <p>DesignerPunk does not support disabled states. If an action is unavailable, the button should not be rendered. For in-flight async operations, use the loading state instead.</p>
108
104
  </div>
109
105
 
110
106
  <script type="module">
@@ -132,14 +128,6 @@
132
128
  handlerOutput.textContent = `Form submitted at ${new Date().toLocaleTimeString()}`;
133
129
  // In a real app, you would validate and submit form data here
134
130
  });
135
-
136
- // Example 4: Disabled button
137
- const disabledBtn = document.getElementById('disabled-btn');
138
- const disabledOutput = document.getElementById('disabled-output');
139
- disabledBtn.addEventListener('press', () => {
140
- // This will never be called because button is disabled
141
- disabledOutput.textContent = 'This should never appear!';
142
- });
143
131
  </script>
144
132
  </body>
145
133
  </html>
@@ -22,7 +22,6 @@ import { ButtonCTA } from '../platforms/web/ButtonCTA.web';
22
22
  * - size: 'medium' (48px height)
23
23
  * - variant: 'primary' (filled background with primary color)
24
24
  * - noWrap: false (text wraps if needed)
25
- * - disabled: false (interactive)
26
25
  *
27
26
  * @example
28
27
  * ```html
@@ -79,7 +78,6 @@ export function customLabelButton(): void {
79
78
  *
80
79
  * The 'press' event:
81
80
  * - Bubbles up through the DOM
82
- * - Is not called when button is disabled
83
81
  * - Works with click, tap, Enter key, and Space key
84
82
  * - Provides originalEvent in event.detail for advanced use cases
85
83
  *
@@ -111,55 +109,37 @@ export function buttonWithHandler(): void {
111
109
  }
112
110
 
113
111
  /**
114
- * Example 4: Disabled Button
112
+ * Example 4: Unavailable Actions (no disabled state)
115
113
  *
116
- * Demonstrates how to disable a button to prevent user interaction.
117
- * Disabled buttons are commonly used during form submission, when prerequisites
118
- * aren't met, or when an action is temporarily unavailable.
114
+ * DesignerPunk does not support disabled states for usability and
115
+ * accessibility reasons. If an action is unavailable, the component
116
+ * should not be rendered.
119
117
  *
120
- * Disabled button behavior:
121
- * - Not keyboard focusable (skipped in Tab order)
122
- * - Does not respond to clicks or keyboard activation
123
- * - Visual styling indicates non-interactive state
124
- * - Screen readers announce disabled state
125
- * - onPress handler is not called
126
- *
127
- * Common use cases:
128
- * - Form submission in progress
129
- * - Required fields not filled
130
- * - User lacks permissions
131
- * - Action temporarily unavailable
132
- *
133
- * @example
134
- * ```html
135
- * <button-cta label="Submit" disabled></button-cta>
136
- * ```
118
+ * For in-flight async operations (e.g. form submission), use the loading
119
+ * state instead of disabling the button. For actions the user cannot take
120
+ * yet, keep the button interactive and validate on press, or do not render
121
+ * the button at all.
137
122
  *
138
123
  * @example
139
124
  * ```typescript
140
- * // Conditional disable based on form state
141
- * const button = document.createElement('button-cta') as ButtonCTA;
142
- * button.label = 'Submit';
143
- * button.disabled = isSubmitting || !isFormValid;
125
+ * // Conditionally render instead of disabling
126
+ * if (userCanSubmit) {
127
+ * const button = document.createElement('button-cta') as ButtonCTA;
128
+ * button.label = 'Submit';
129
+ * button.addEventListener('press', handleSubmit);
130
+ * document.body.appendChild(button);
131
+ * }
144
132
  * ```
145
133
  */
146
- export function disabledButton(): void {
134
+ export function conditionallyRenderedButton(): void {
147
135
  const button = document.createElement('button-cta') as ButtonCTA;
148
136
  button.label = 'Submit';
149
- button.disabled = true; // Button is non-interactive
150
137
 
151
- // This handler will NOT be called when button is disabled
152
138
  button.addEventListener('press', () => {
153
- console.log('This will not be logged when button is disabled');
139
+ console.log('Submitted');
154
140
  });
155
141
 
156
142
  document.body.appendChild(button);
157
-
158
- // Example: Enable button after 3 seconds (simulating async operation)
159
- setTimeout(() => {
160
- button.disabled = false;
161
- console.log('Button is now enabled');
162
- }, 3000);
163
143
  }
164
144
 
165
145
  /**
@@ -202,13 +182,6 @@ export function renderAllBasicExamples(): void {
202
182
  });
203
183
  container.appendChild(handlerBtn);
204
184
 
205
- // Example 4: Disabled
206
- const disabledBtn = document.createElement('button-cta') as ButtonCTA;
207
- disabledBtn.label = 'Disabled Button';
208
- disabledBtn.disabled = true;
209
- disabledBtn.addEventListener('press', () => console.log('This will not log'));
210
- container.appendChild(disabledBtn);
211
-
212
185
  // Add container to document
213
186
  document.body.appendChild(container);
214
187
  }
@@ -11,7 +11,7 @@
11
11
  * while maintaining API consistency with web and iOS platforms.
12
12
  *
13
13
  * Uses theme-aware blend utilities (Color extensions with Compose MaterialTheme) for
14
- * state colors (hover, pressed, disabled, icon) instead of opacity or Material ripple
14
+ * state colors (hover, pressed, icon) instead of opacity or Material ripple
15
15
  * workarounds. This ensures cross-platform consistency with Web and iOS implementations.
16
16
  *
17
17
  * Part of the DesignerPunk CTA Button Component system.
@@ -42,11 +42,10 @@ import androidx.compose.ui.unit.dp
42
42
  import androidx.compose.ui.unit.sp
43
43
  import com.designerpunk.tokens.DesignTokens
44
44
  // Import theme-aware blend utilities (Color extension functions from ThemeAwareBlendUtilities.android.kt)
45
- // These provide semantic blend methods: hoverBlend(), pressedBlend(), disabledBlend(), iconBlend()
45
+ // These provide semantic blend methods: hoverBlend(), pressedBlend(), iconBlend()
46
46
  // @see Requirements: 11.1, 11.2, 11.3 - Theme-aware utilities
47
47
  import com.designerpunk.tokens.hoverBlend
48
48
  import com.designerpunk.tokens.pressedBlend
49
- import com.designerpunk.tokens.disabledBlend
50
49
  import com.designerpunk.tokens.iconBlend
51
50
 
52
51
  /**
@@ -88,8 +87,8 @@ enum class ButtonCTAStyle {
88
87
  * three size variants, three visual styles, optional leading icons, and
89
88
  * theme-aware blend utilities for state colors.
90
89
  *
91
- * Uses theme-aware Color extensions (hoverBlend(), pressedBlend(), disabledBlend(),
92
- * iconBlend()) with Compose MaterialTheme for automatic theme color updates.
90
+ * Uses theme-aware Color extensions (hoverBlend(), pressedBlend(), iconBlend())
91
+ * with Compose MaterialTheme for automatic theme color updates.
93
92
  *
94
93
  * Usage:
95
94
  * ```kotlin
@@ -120,7 +119,7 @@ enum class ButtonCTAStyle {
120
119
  * Requirements:
121
120
  * - 1.1-1.7: Size variants (small: 40dp, medium: 48dp, large: 56dp)
122
121
  * - 2.1-2.4: Visual styles (primary, secondary, tertiary)
123
- * - 7.1-7.4: Blend utility state colors (hover, pressed, disabled, icon)
122
+ * - 7.1-7.4: Blend utility state colors (hover, pressed, icon)
124
123
  * - 8.1-8.6: Icon support with leading position
125
124
  * - 11.1-11.3: Theme-aware blend utilities with Compose MaterialTheme
126
125
  * - 13.1-13.4: Touch target accessibility (44dp minimum)
@@ -132,7 +131,6 @@ enum class ButtonCTAStyle {
132
131
  * @param noWrap Prevent text wrapping (default: false)
133
132
  * @param onPress Click/tap handler (required)
134
133
  * @param testID Optional test identifier
135
- * @param disabled Optional disabled state (default: false)
136
134
  */
137
135
  @Composable
138
136
  fun ButtonCTA(
@@ -142,8 +140,7 @@ fun ButtonCTA(
142
140
  icon: String? = null,
143
141
  noWrap: Boolean = false,
144
142
  onPress: () -> Unit,
145
- testID: String? = null,
146
- disabled: Boolean = false
143
+ testID: String? = null
147
144
  ) {
148
145
  val theme = LocalDPTheme.current
149
146
  // Remember interaction source for tracking pressed state
@@ -154,7 +151,7 @@ fun ButtonCTA(
154
151
  val sizeConfig = getButtonCTASizeConfig(size)
155
152
 
156
153
  // Get style-based configuration with blend utilities
157
- val styleConfig = getButtonCTAStyleConfig(style, isPressed, disabled)
154
+ val styleConfig = getButtonCTAStyleConfig(style, isPressed)
158
155
 
159
156
  // Use Surface with clickable modifier (no ripple indication for cross-platform consistency)
160
157
  Surface(
@@ -169,7 +166,6 @@ fun ButtonCTA(
169
166
  // Apply clickable without ripple indication (blend colors handle state feedback)
170
167
  .clickable(
171
168
  onClick = onPress,
172
- enabled = !disabled,
173
169
  interactionSource = interactionSource,
174
170
  indication = null // No ripple - using blend colors for state feedback
175
171
  ),
@@ -316,7 +312,7 @@ private fun getButtonCTASizeConfig(size: ButtonCTASize): ButtonCTASizeConfig {
316
312
  * Style configuration data class
317
313
  *
318
314
  * Encapsulates all style-related properties for a button visual style.
319
- * Uses blend utilities for state colors (pressed, disabled, icon optical balance).
315
+ * Uses blend utilities for state colors (pressed, icon optical balance).
320
316
  *
321
317
  * @property backgroundColor Background color (includes state-based blend)
322
318
  * @property textColor Text color
@@ -338,36 +334,32 @@ private data class ButtonCTAStyleConfig(
338
334
  * Returns configuration object with all style-related properties based on
339
335
  * semantic color tokens and theme-aware blend utilities for state colors.
340
336
  *
341
- * Uses theme-aware Color extensions (hoverBlend(), pressedBlend(), disabledBlend(),
342
- * iconBlend()) instead of direct blend calculations for cross-platform consistency
337
+ * Uses theme-aware Color extensions (hoverBlend(), pressedBlend(), iconBlend())
338
+ * instead of direct blend calculations for cross-platform consistency
343
339
  * with Web and iOS implementations.
344
340
  *
345
341
  * Requirements:
346
342
  * - 2.1-2.4: Visual styles (primary, secondary, tertiary)
347
- * - 7.1-7.4: Blend utility state colors (hover, pressed, disabled, icon)
343
+ * - 7.1-7.4: Blend utility state colors (hover, pressed, icon)
348
344
  * - 9.1-9.3: Icon color with optical balance using blend utility
349
345
  * - 11.1-11.3: Theme-aware blend utilities with Compose MaterialTheme
350
346
  *
351
347
  * @param style Button visual style
352
348
  * @param isPressed Whether button is currently pressed
353
- * @param disabled Whether button is disabled
354
349
  * @return Style configuration object with blend-calculated colors
355
350
  */
356
- private fun getButtonCTAStyleConfig(style: ButtonCTAStyle, isPressed: Boolean, disabled: Boolean): ButtonCTAStyleConfig {
351
+ private fun getButtonCTAStyleConfig(style: ButtonCTAStyle, isPressed: Boolean): ButtonCTAStyleConfig {
357
352
  // Import semantic color tokens from generated constants
358
353
 
359
354
  // Calculate state-based background colors using theme-aware blend utilities
360
355
  // @see Requirements: 7.1, 7.2, 7.3, 11.1, 11.2, 11.3
361
356
  val primaryBgColor = when {
362
- // @see Requirements: 7.3 - Disabled uses desaturate(color.action.primary, blend.disabledDesaturate)
363
- disabled -> colorActionPrimary.disabledBlend()
364
357
  // @see Requirements: 7.2 - Pressed uses darkerBlend(color.action.primary, blend.pressedDarker)
365
358
  isPressed -> colorActionPrimary.pressedBlend()
366
359
  else -> colorActionPrimary
367
360
  }
368
361
 
369
362
  val secondaryBgColor = when {
370
- disabled -> colorBackground
371
363
  // @see Requirements: 7.2 - Pressed uses darkerBlend for secondary background
372
364
  isPressed -> colorBackground.pressedBlend()
373
365
  else -> colorBackground