@3fn/core 13.0.0 → 14.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.kiro/agents/ada-prompt.md +80 -132
- package/.kiro/agents/ada-prompt.md.attribution.json +45 -0
- package/.kiro/agents/ada.json +44 -59
- package/.kiro/agents/ada.json.attribution.json +13 -0
- package/.kiro/agents/data-prompt.md +83 -74
- package/.kiro/agents/data-prompt.md.attribution.json +53 -0
- package/.kiro/agents/data.json +31 -38
- package/.kiro/agents/data.json.attribution.json +13 -0
- package/.kiro/agents/kenya-prompt.md +83 -72
- package/.kiro/agents/kenya-prompt.md.attribution.json +53 -0
- package/.kiro/agents/kenya.json +27 -35
- package/.kiro/agents/kenya.json.attribution.json +13 -0
- package/.kiro/agents/leonardo-prompt.md +176 -234
- package/.kiro/agents/leonardo-prompt.md.attribution.json +45 -0
- package/.kiro/agents/leonardo.json +28 -36
- package/.kiro/agents/leonardo.json.attribution.json +13 -0
- package/.kiro/agents/lina-prompt.md +110 -151
- package/.kiro/agents/lina-prompt.md.attribution.json +53 -0
- package/.kiro/agents/lina.json +46 -59
- package/.kiro/agents/lina.json.attribution.json +13 -0
- package/.kiro/agents/sparky-prompt.md +89 -72
- package/.kiro/agents/sparky-prompt.md.attribution.json +53 -0
- package/.kiro/agents/sparky.json +37 -37
- package/.kiro/agents/sparky.json.attribution.json +13 -0
- package/.kiro/agents/stacy-prompt.md +74 -48
- package/.kiro/agents/stacy-prompt.md.attribution.json +45 -0
- package/.kiro/agents/stacy.json +28 -30
- package/.kiro/agents/stacy.json.attribution.json +13 -0
- package/.kiro/agents/thurgood-prompt.md +94 -138
- package/.kiro/agents/thurgood-prompt.md.attribution.json +45 -0
- package/.kiro/agents/thurgood.json +31 -35
- package/.kiro/agents/thurgood.json.attribution.json +13 -0
- package/.kiro/steering/AI-Collaboration-Principles.md +3 -3
- package/.kiro/steering/Civitas-System-Overview.md +5 -5
- package/.kiro/steering/DesignerPunk-Systems-Overview.md +6 -6
- package/.kiro/steering/Task-Completion-Protocol.md +98 -17
- package/.kiro/steering/core-goals.md +3 -3
- package/.kiro/steering/personal-note.md +1 -1
- package/.kiro/steering/start-up-tasks.md +14 -3
- package/application-mcp-server/src/index.ts +26 -0
- package/dist/ComponentTokens.android.kt +1 -1
- package/dist/ComponentTokens.ios.swift +1 -1
- package/dist/ComponentTokens.web.css +1 -1
- package/dist/DesignTokens.android.kt +1 -1
- package/dist/DesignTokens.dtcg.json +8 -5
- package/dist/DesignTokens.figma.json +2 -2
- package/dist/DesignTokens.ios.swift +1 -1
- package/dist/DesignTokens.web.css +1 -1
- package/dist/android/DesignTokens.android.kt +1 -1
- package/dist/blend/OklchBlendCalculator.js +1 -0
- package/dist/blend/ThemeAwareBlendUtilities.web.d.ts +13 -2
- package/dist/blend/ThemeAwareBlendUtilities.web.js +6 -1
- package/dist/browser/designerpunk.esm.js +22 -81
- package/dist/browser/designerpunk.esm.min.js +29 -32
- package/dist/browser/designerpunk.umd.js +22 -81
- package/dist/browser/designerpunk.umd.min.js +42 -45
- package/dist/browser/tokens.css +1 -1
- package/dist/components/core/Avatar-Base/platforms/web/Avatar.web.js +24 -5
- package/dist/components/core/Button-CTA/examples/BasicUsage.d.ts +16 -28
- package/dist/components/core/Button-CTA/examples/BasicUsage.js +18 -43
- package/dist/components/core/Button-CTA/platforms/web/ButtonCTA.web.d.ts +3 -15
- package/dist/components/core/Button-CTA/platforms/web/ButtonCTA.web.js +9 -58
- package/dist/components/core/Button-CTA/types.d.ts +0 -24
- package/dist/components/core/Button-CTA/types.js +6 -0
- package/dist/components/core/Input-Text-Base/types.d.ts +13 -1
- package/dist/components/core/Input-Text-Password/platforms/web/InputTextPassword.web.js +11 -2
- package/dist/generators/DTCGFormatGenerator.js +8 -0
- package/dist/integration/BuildErrorHandler.js +2 -2
- package/dist/ios/DesignTokens.ios.swift +1 -1
- package/dist/mcp/application-mcp.js +24 -0
- package/dist/mcp/docs-mcp.js +130 -15
- package/dist/mcp/product-mcp.js +25 -0
- package/dist/tokens/OpacityTokens.js +1 -1
- package/dist/tokens/semantic/BlendTokens.d.ts +10 -3
- package/dist/tokens/semantic/BlendTokens.js +17 -5
- package/dist/tokens/semantic/OpacityTokens.d.ts +4 -4
- package/dist/tokens/semantic/OpacityTokens.js +4 -4
- package/dist/types/ComponentTypes.d.ts +1 -1
- package/dist/types/generated/TokenTypes.d.ts +1 -1
- package/dist/types/generated/TokenTypes.js +1 -1
- package/dist/validators/StemmaTokenUsageValidator.js +3 -2
- package/dist/web/DesignTokens.web.css +1 -1
- package/governance/Component-Development-Guide.md +22 -12
- package/governance/Component-Development-Standards.md +2 -2
- package/governance/Component-Family-Avatar.md +0 -1
- package/governance/Component-Family-Badge.md +0 -1
- package/governance/Component-Family-Button.md +4 -17
- package/governance/Component-Family-Chip.md +0 -1
- package/governance/Component-Family-Container.md +0 -1
- package/governance/Component-Family-Data-Display.md +1 -2
- package/governance/Component-Family-Divider.md +1 -2
- package/governance/Component-Family-Form-Inputs.md +5 -5
- package/governance/Component-Family-Icon.md +1 -2
- package/governance/Component-Family-Loading.md +1 -2
- package/governance/Component-Family-Modal.md +1 -2
- package/governance/Component-Family-Navigation.md +0 -1
- package/governance/Component-Family-Progress.md +0 -1
- package/governance/Component-Inheritance-Structures.md +195 -76
- package/governance/Component-MCP-Document-Template.md +6 -5
- package/governance/Component-Primitive-vs-Semantic-Philosophy.md +1 -1
- package/governance/Component-Quick-Reference.md +33 -33
- package/governance/Component-Readiness-Status.md +54 -38
- package/governance/Component-Templates.md +32 -36
- package/governance/Contract-System-Reference.md +6 -6
- package/governance/MCP-Integration-Guide.md +1 -1
- package/governance/Process-Cross-Reference-Standards.md +31 -13
- package/governance/Process-Development-Workflow.md +49 -59
- package/governance/Process-File-Organization.md +24 -24
- package/governance/Process-Hook-Operations.md +19 -7
- package/governance/Process-Orchestration-Model-Selection.md +92 -0
- package/governance/Process-Spec-Planning.md +91 -39
- package/governance/Process-Task-Type-Definitions.md +80 -4
- package/governance/Product-Handoff-Protocol.md +2 -0
- package/governance/Rosetta-System-Architecture.md +6 -6
- package/governance/Test-Behavioral-Contract-Validation.md +38 -31
- package/governance/Test-Failure-Audit-Methodology.md +1 -1
- package/governance/Token-Family-Accessibility.md +1 -2
- package/governance/Token-Family-Blend.md +18 -16
- package/governance/Token-Family-Blur.md +0 -1
- package/governance/Token-Family-Border.md +1 -2
- package/governance/Token-Family-Color.md +0 -1
- package/governance/Token-Family-Glow.md +1 -2
- package/governance/Token-Family-Layering.md +0 -1
- package/governance/Token-Family-Motion.md +1 -2
- package/governance/Token-Family-Opacity.md +0 -1
- package/governance/Token-Family-Radius.md +1 -2
- package/governance/Token-Family-Responsive.md +1 -2
- package/governance/Token-Family-Shadow.md +1 -2
- package/governance/Token-Family-Sizing.md +0 -1
- package/governance/Token-Family-Spacing.md +1 -2
- package/governance/Token-Family-Typography.md +1 -2
- package/governance/Token-Governance.md +8 -8
- package/governance/Token-Quick-Reference.md +21 -21
- package/governance/Token-Resolution-Patterns.md +1 -1
- package/governance/Token-Semantic-Structure.md +1 -1
- package/governance/Web-Authoring-Standards.md +5 -5
- package/governance/browser-distribution-guide.md +1 -4
- package/governance/classification-map.md +368 -0
- package/governance/completion-documentation-guide.md +11 -8
- package/governance/component-meta-authoring-guide.md +1 -1
- package/governance/cross-platform-vs-platform-specific-decision-framework.md +1 -1
- package/governance/platform-implementation-guidelines.md +1 -1
- package/governance/release-management-system.md +2 -2
- package/governance/rosetta-system-principles.md +8 -6
- package/governance/stemma-system-principles.md +18 -17
- package/mcp-server/src/index.ts +24 -6
- package/mcp-server/src/indexer/DocumentIndexer.ts +119 -9
- package/mcp-server/src/indexer/__tests__/bare-id-crossrefs.test.ts +250 -0
- package/mcp-server/src/indexer/cross-ref-parser.ts +29 -1
- package/mcp-server/src/indexer/index-health.ts +27 -2
- package/mcp-server/src/query/__tests__/find-docs-calibration.test.ts +11 -26
- package/mcp-server/src/relocation-integrity-gate/__tests__/relocation-integrity-gate.test.ts +72 -5
- package/mcp-server/src/relocation-integrity-gate/relocation-integrity-gate.ts +81 -24
- package/mcp-server/src/tools/list-cross-references.ts +2 -2
- package/package.json +23 -21
- package/src/__tests__/browser-distribution/css-bundling.test.ts +6 -4
- package/src/__tests__/console-allowlist.json +14 -0
- package/src/__tests__/console-fail-setup.ts +169 -0
- package/src/__tests__/integration/Spec107-DesignLanguageContext.test.ts +16 -0
- package/src/__tests__/stemma-system/behavioral-contract-validation.test.ts +70 -17
- package/src/__tests__/stemma-system/contract-catalog-name-validation.test.ts +28 -0
- package/src/__tests__/stemma-system/form-inputs-contracts.test.ts +223 -16
- package/src/__tests__/stemma-system/input-text-native-base-call-alignment.test.ts +298 -0
- package/src/blend/OklchBlendCalculator.ts +3 -0
- package/src/blend/ThemeAwareBlendUtilities.android.kt +3 -0
- package/src/blend/ThemeAwareBlendUtilities.ios.swift +3 -0
- package/src/blend/ThemeAwareBlendUtilities.web.ts +9 -1
- package/src/blend/__tests__/InteractionStateAudit.test.ts +12 -9
- package/src/build/errors/__tests__/ErrorHandler.integration.test.ts +8 -0
- package/src/build/errors/__tests__/ErrorHandler.test.ts +5 -0
- package/src/build/workflow/__tests__/CICDIntegration.test.ts +12 -1
- package/src/cli/__tests__/init.test.ts +45 -11
- package/src/components/core/Avatar-Base/Avatar-Base.schema.yaml +1 -1
- package/src/components/core/Avatar-Base/__tests__/Avatar.accessibility.test.ts +121 -7
- package/src/components/core/Avatar-Base/__tests__/Avatar.image.test.ts +3 -0
- package/src/components/core/Avatar-Base/__tests__/Avatar.test.ts +15 -6
- package/src/components/core/Avatar-Base/contracts.yaml +11 -1
- package/src/components/core/Avatar-Base/platforms/web/Avatar.web.ts +24 -5
- package/src/components/core/Badge-Count-Base/contracts.yaml +1 -1
- package/src/components/core/Badge-Label-Base/contracts.yaml +1 -1
- package/src/components/core/Button-CTA/Button-CTA.schema.yaml +2 -12
- package/src/components/core/Button-CTA/README.md +3 -6
- package/src/components/core/Button-CTA/__tests__/ButtonCTA.test.ts +35 -89
- package/src/components/core/Button-CTA/__tests__/setup.test.ts +0 -2
- package/src/components/core/Button-CTA/__tests__/test-utils.ts +0 -2
- package/src/components/core/Button-CTA/contracts.yaml +6 -29
- package/src/components/core/Button-CTA/examples/BasicUsage.html +2 -14
- package/src/components/core/Button-CTA/examples/BasicUsage.tsx +17 -44
- package/src/components/core/Button-CTA/platforms/android/ButtonCTA.android.kt +12 -20
- package/src/components/core/Button-CTA/platforms/ios/ButtonCTA.ios.swift +12 -51
- package/src/components/core/Button-CTA/platforms/web/ButtonCTA.web.css +2 -26
- package/src/components/core/Button-CTA/platforms/web/ButtonCTA.web.ts +18 -71
- package/src/components/core/Button-CTA/types.ts +10 -28
- package/src/components/core/Chip-Base/__tests__/ChipBase.test.ts +13 -0
- package/src/components/core/Chip-Filter/__tests__/ChipFilter.test.ts +13 -0
- package/src/components/core/Chip-Input/__tests__/ChipInput.test.ts +13 -0
- package/src/components/core/Input-Text-Base/Input-Text-Base.schema.yaml +30 -2
- package/src/components/core/Input-Text-Base/README.md +25 -2
- package/src/components/core/Input-Text-Base/__tests__/focusIndicators.test.ts +16 -15
- package/src/components/core/Input-Text-Base/contracts.yaml +90 -0
- package/src/components/core/Input-Text-Base/platforms/android/InputTextBase.android.kt +26 -12
- package/src/components/core/Input-Text-Base/platforms/ios/InputTextBase.ios.swift +195 -59
- package/src/components/core/Input-Text-Base/types.ts +13 -1
- package/src/components/core/Input-Text-Email/Input-Text-Email.schema.yaml +5 -1
- package/src/components/core/Input-Text-Email/README.md +8 -7
- package/src/components/core/Input-Text-Email/platforms/android/InputTextEmail.android.kt +1 -4
- package/src/components/core/Input-Text-Email/platforms/ios/InputTextEmail.ios.swift +2 -16
- package/src/components/core/Input-Text-Password/Input-Text-Password.schema.yaml +10 -3
- package/src/components/core/Input-Text-Password/README.md +9 -8
- package/src/components/core/Input-Text-Password/contracts.yaml +5 -0
- package/src/components/core/Input-Text-Password/platforms/android/InputTextPassword.android.kt +17 -7
- package/src/components/core/Input-Text-Password/platforms/ios/InputTextPassword.ios.swift +22 -20
- package/src/components/core/Input-Text-Password/platforms/web/InputTextPassword.web.ts +11 -2
- package/src/components/core/Input-Text-PhoneNumber/Input-Text-PhoneNumber.schema.yaml +5 -1
- package/src/components/core/Input-Text-PhoneNumber/README.md +9 -8
- package/src/components/core/Input-Text-PhoneNumber/platforms/android/InputTextPhoneNumber.android.kt +2 -5
- package/src/components/core/Input-Text-PhoneNumber/platforms/ios/InputTextPhoneNumber.ios.swift +3 -17
- package/src/components/core/Nav-Header-App/contracts.yaml +1 -1
- package/src/components/core/Nav-SegmentedChoice-Base/contracts.yaml +1 -1
- package/src/components/core/Progress-Indicator-Connector-Base/contracts.yaml +1 -1
- package/src/components/core/Progress-Indicator-Label-Base/contracts.yaml +1 -1
- package/src/components/core/Progress-Indicator-Node-Base/contracts.yaml +1 -1
- package/src/components/core/Progress-Stepper-Base/__tests__/StepperBase.test.ts +5 -2
- package/src/components/core/Progress-Stepper-Detailed/__tests__/StepperDetailed.test.ts +5 -2
- package/src/generators/DTCGFormatGenerator.ts +6 -0
- package/src/generators/__tests__/DTCGConfigOptions.test.ts +14 -5
- package/src/integration/BuildErrorHandler.ts +2 -2
- package/src/tokens/OpacityTokens.ts +1 -1
- package/src/tokens/__tests__/OpacityTokens.test.ts +3 -1
- package/src/tokens/semantic/BlendTokens.ts +26 -5
- package/src/tokens/semantic/OpacityTokens.ts +4 -4
- package/src/tools/release/__tests__/ReleasePipeline.test.ts +1 -1
- package/src/types/ComponentTypes.ts +1 -1
- package/src/types/generated/TokenTypes.ts +1 -1
- package/src/validators/StemmaTokenUsageValidator.ts +3 -2
- package/token-index/semantics.yaml +1 -2
|
@@ -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
|
|
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:
|
|
103
|
-
<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:
|
|
112
|
+
* Example 4: Unavailable Actions (no disabled state)
|
|
115
113
|
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
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
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
*
|
|
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
|
-
* //
|
|
141
|
-
*
|
|
142
|
-
* button
|
|
143
|
-
*
|
|
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
|
|
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('
|
|
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,
|
|
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(),
|
|
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(),
|
|
92
|
-
*
|
|
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,
|
|
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
|
|
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,
|
|
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(),
|
|
342
|
-
*
|
|
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,
|
|
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
|
|
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
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* while maintaining API consistency with web and Android platforms.
|
|
12
12
|
*
|
|
13
13
|
* Uses theme-aware blend utilities (Color extensions with SwiftUI environment) for
|
|
14
|
-
* state colors (hover, pressed,
|
|
14
|
+
* state colors (hover, pressed, icon) instead of opacity or scale workarounds.
|
|
15
15
|
* This ensures cross-platform consistency with Web and Android implementations.
|
|
16
16
|
*
|
|
17
17
|
* Part of the DesignerPunk CTA Button Component system.
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
import SwiftUI
|
|
24
24
|
|
|
25
25
|
// Import theme-aware blend utilities (Color extensions from ThemeAwareBlendUtilities.ios.swift)
|
|
26
|
-
// These provide semantic blend methods: hoverBlend(), pressedBlend(),
|
|
26
|
+
// These provide semantic blend methods: hoverBlend(), pressedBlend(), iconBlend()
|
|
27
27
|
// @see Requirements: 11.1, 11.2, 11.3 - Theme-aware utilities
|
|
28
28
|
|
|
29
29
|
/**
|
|
@@ -65,8 +65,8 @@ enum ButtonCTAStyle {
|
|
|
65
65
|
* three size variants, three visual styles, optional leading icons, and
|
|
66
66
|
* theme-aware blend utilities for state colors.
|
|
67
67
|
*
|
|
68
|
-
* Uses theme-aware Color extensions (hoverBlend(), pressedBlend(),
|
|
69
|
-
*
|
|
68
|
+
* Uses theme-aware Color extensions (hoverBlend(), pressedBlend(), iconBlend())
|
|
69
|
+
* with SwiftUI environment for automatic theme color updates.
|
|
70
70
|
*
|
|
71
71
|
* Usage:
|
|
72
72
|
* ```swift
|
|
@@ -97,7 +97,7 @@ enum ButtonCTAStyle {
|
|
|
97
97
|
* Requirements:
|
|
98
98
|
* - 1.1-1.7: Size variants (small: 40px, medium: 48px, large: 56px)
|
|
99
99
|
* - 2.1-2.4: Visual styles (primary, secondary, tertiary)
|
|
100
|
-
* - 7.1-7.4: Blend utility state colors (hover, pressed,
|
|
100
|
+
* - 7.1-7.4: Blend utility state colors (hover, pressed, icon)
|
|
101
101
|
* - 8.1-8.6: Icon support with leading position
|
|
102
102
|
* - 11.1-11.3: Theme-aware blend utilities with SwiftUI environment
|
|
103
103
|
* - 13.1-13.4: Touch target accessibility (44px minimum)
|
|
@@ -125,10 +125,7 @@ struct ButtonCTA: View {
|
|
|
125
125
|
|
|
126
126
|
/// Optional test ID for automated testing
|
|
127
127
|
let testID: String?
|
|
128
|
-
|
|
129
|
-
/// Optional disabled state (default: false)
|
|
130
|
-
let disabled: Bool
|
|
131
|
-
|
|
128
|
+
|
|
132
129
|
// MARK: - State
|
|
133
130
|
|
|
134
131
|
/// Tracks pressed state for scale transform animation
|
|
@@ -149,7 +146,6 @@ struct ButtonCTA: View {
|
|
|
149
146
|
* - noWrap: Prevent text wrapping (default: false)
|
|
150
147
|
* - onPress: Click/tap handler (required)
|
|
151
148
|
* - testID: Optional test identifier
|
|
152
|
-
* - disabled: Optional disabled state (default: false)
|
|
153
149
|
*/
|
|
154
150
|
init(
|
|
155
151
|
label: String,
|
|
@@ -158,8 +154,7 @@ struct ButtonCTA: View {
|
|
|
158
154
|
icon: String? = nil,
|
|
159
155
|
noWrap: Bool = false,
|
|
160
156
|
onPress: @escaping () -> Void,
|
|
161
|
-
testID: String? = nil
|
|
162
|
-
disabled: Bool = false
|
|
157
|
+
testID: String? = nil
|
|
163
158
|
) {
|
|
164
159
|
self.label = label
|
|
165
160
|
self.size = size
|
|
@@ -168,7 +163,6 @@ struct ButtonCTA: View {
|
|
|
168
163
|
self.noWrap = noWrap
|
|
169
164
|
self.onPress = onPress
|
|
170
165
|
self.testID = testID
|
|
171
|
-
self.disabled = disabled
|
|
172
166
|
}
|
|
173
167
|
|
|
174
168
|
// MARK: - Body
|
|
@@ -213,15 +207,12 @@ struct ButtonCTA: View {
|
|
|
213
207
|
.simultaneousGesture(
|
|
214
208
|
DragGesture(minimumDistance: 0)
|
|
215
209
|
.onChanged { _ in
|
|
216
|
-
|
|
217
|
-
isPressed = true
|
|
218
|
-
}
|
|
210
|
+
isPressed = true
|
|
219
211
|
}
|
|
220
212
|
.onEnded { _ in
|
|
221
213
|
isPressed = false
|
|
222
214
|
}
|
|
223
215
|
)
|
|
224
|
-
.disabled(disabled)
|
|
225
216
|
// Requirement 13.1-13.4, 16.4: Accessibility identifier for testing
|
|
226
217
|
.accessibilityIdentifier(testID ?? "")
|
|
227
218
|
// Requirement 17.4: Respect safe area insets for full-width buttons
|
|
@@ -230,14 +221,11 @@ struct ButtonCTA: View {
|
|
|
230
221
|
|
|
231
222
|
// MARK: - Blend Color Computed Properties
|
|
232
223
|
|
|
233
|
-
/// Current background color based on state (normal,
|
|
224
|
+
/// Current background color based on state (normal, pressed)
|
|
234
225
|
/// Uses theme-aware blend utilities (Color extensions) for cross-platform consistency
|
|
235
|
-
/// @see Requirements: 7.1, 7.2,
|
|
226
|
+
/// @see Requirements: 7.1, 7.2, 11.1, 11.2, 11.3
|
|
236
227
|
private var currentBackgroundColor: Color {
|
|
237
|
-
if
|
|
238
|
-
// @see Requirements: 7.3 - Disabled uses desaturate(color.primary, blend.disabledDesaturate)
|
|
239
|
-
return disabledBackgroundColor
|
|
240
|
-
} else if isPressed {
|
|
228
|
+
if isPressed {
|
|
241
229
|
// @see Requirements: 7.2 - Pressed uses darkerBlend(color.primary, blend.pressedDarker)
|
|
242
230
|
return pressedBackgroundColor
|
|
243
231
|
} else {
|
|
@@ -260,20 +248,6 @@ struct ButtonCTA: View {
|
|
|
260
248
|
}
|
|
261
249
|
}
|
|
262
250
|
|
|
263
|
-
/// Disabled state background color using theme-aware blend utility
|
|
264
|
-
/// Uses disabledBlend() which applies desaturate with blend.disabledDesaturate (12%)
|
|
265
|
-
/// @see Requirements: 7.3, 11.1, 11.2, 11.3
|
|
266
|
-
private var disabledBackgroundColor: Color {
|
|
267
|
-
switch style {
|
|
268
|
-
case .primary:
|
|
269
|
-
return theme.colorActionPrimary.disabledBlend()
|
|
270
|
-
case .secondary:
|
|
271
|
-
return theme.colorStructureCanvas
|
|
272
|
-
case .tertiary:
|
|
273
|
-
return Color.clear
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
|
|
277
251
|
// MARK: - Size-Based Computed Properties
|
|
278
252
|
|
|
279
253
|
/// Typography token based on button size
|
|
@@ -532,20 +506,7 @@ struct ButtonCTA_Previews: PreviewProvider {
|
|
|
532
506
|
onPress: { print("Confirm pressed") }
|
|
533
507
|
)
|
|
534
508
|
}
|
|
535
|
-
|
|
536
|
-
Divider()
|
|
537
|
-
|
|
538
|
-
// Disabled state
|
|
539
|
-
Text("Disabled State")
|
|
540
|
-
.font(.headline)
|
|
541
|
-
|
|
542
|
-
VStack(spacing: 12) {
|
|
543
|
-
ButtonCTA(
|
|
544
|
-
label: "Disabled Button",
|
|
545
|
-
disabled: true,
|
|
546
|
-
onPress: { print("Should not print") }
|
|
547
|
-
)
|
|
548
|
-
}
|
|
509
|
+
|
|
549
510
|
}
|
|
550
511
|
.padding()
|
|
551
512
|
}
|
|
@@ -275,7 +275,7 @@
|
|
|
275
275
|
* The --_cta-hover-bg custom property is set by the component
|
|
276
276
|
* using darkerBlend(color.primary, blend.hoverDarker) = 8% darker.
|
|
277
277
|
*/
|
|
278
|
-
.button-cta--primary:hover
|
|
278
|
+
.button-cta--primary:hover {
|
|
279
279
|
background-color: var(--_cta-hover-bg);
|
|
280
280
|
}
|
|
281
281
|
|
|
@@ -288,7 +288,7 @@
|
|
|
288
288
|
* The --_cta-pressed-bg custom property is set by the component
|
|
289
289
|
* using darkerBlend(color.primary, blend.pressedDarker) = 12% darker.
|
|
290
290
|
*/
|
|
291
|
-
.button-cta--primary:active
|
|
291
|
+
.button-cta--primary:active {
|
|
292
292
|
background-color: var(--_cta-pressed-bg);
|
|
293
293
|
}
|
|
294
294
|
|
|
@@ -318,30 +318,6 @@
|
|
|
318
318
|
outline: none;
|
|
319
319
|
}
|
|
320
320
|
|
|
321
|
-
/**
|
|
322
|
-
* Disabled state.
|
|
323
|
-
*
|
|
324
|
-
* Uses blend utility calculated color (desaturate with blend.disabledDesaturate)
|
|
325
|
-
* instead of opacity workaround for cross-platform consistency.
|
|
326
|
-
*
|
|
327
|
-
* The --button-disabled-color custom property is set by the component
|
|
328
|
-
* using desaturate(color.primary, blend.disabledDesaturate) = 12% less saturated.
|
|
329
|
-
*
|
|
330
|
-
* - Cursor changes to not-allowed
|
|
331
|
-
* - Prevents interaction
|
|
332
|
-
* - Maintains color contrast for accessibility
|
|
333
|
-
*/
|
|
334
|
-
.button-cta:disabled,
|
|
335
|
-
.button-cta--disabled {
|
|
336
|
-
cursor: not-allowed;
|
|
337
|
-
pointer-events: none;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
.button-cta--primary:disabled,
|
|
341
|
-
.button-cta--primary.button-cta--disabled {
|
|
342
|
-
background-color: var(--_cta-disabled-bg);
|
|
343
|
-
}
|
|
344
|
-
|
|
345
321
|
/* ==========================================================================
|
|
346
322
|
Responsive Behavior
|
|
347
323
|
========================================================================== */
|