@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.
- 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 +7 -16
- package/.kiro/steering/DesignerPunk-Systems-Overview.md +6 -6
- package/.kiro/steering/Spec-Feedback-Protocol.md +2 -11
- 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 +17 -6
- package/application-mcp-server/src/index.ts +26 -0
- package/dist/ComponentTokens.android.kt +12 -12
- package/dist/ComponentTokens.ios.swift +12 -12
- package/dist/ComponentTokens.web.css +3 -3
- 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 +36 -90
- package/dist/browser/designerpunk.esm.min.js +33 -36
- package/dist/browser/designerpunk.umd.js +36 -90
- package/dist/browser/designerpunk.umd.min.js +47 -50
- package/dist/browser/tokens.css +3 -3
- package/dist/build/tokens/defineComponentTokens.d.ts +10 -0
- package/dist/build/tokens/defineComponentTokens.js +26 -0
- package/dist/components/core/Avatar-Base/avatar.tokens.d.ts +21 -26
- package/dist/components/core/Avatar-Base/avatar.tokens.js +31 -34
- package/dist/components/core/Avatar-Base/index.d.ts +1 -1
- package/dist/components/core/Avatar-Base/index.js +2 -2
- 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/Button-Icon/buttonIcon.tokens.d.ts +28 -14
- package/dist/components/core/Button-Icon/buttonIcon.tokens.js +35 -20
- 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/generators/TokenFileGenerator.js +7 -2
- 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/component/progress.d.ts +65 -5
- package/dist/tokens/component/progress.js +79 -18
- 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/BUILD-SYSTEM-SETUP.md +1 -2
- package/governance/Component-Development-Guide.md +23 -13
- package/governance/Component-Development-Standards.md +21 -20
- package/governance/Component-Family-Avatar.md +6 -7
- package/governance/Component-Family-Badge.md +19 -20
- package/governance/Component-Family-Button.md +30 -43
- package/governance/Component-Family-Chip.md +14 -15
- package/governance/Component-Family-Container.md +12 -13
- package/governance/Component-Family-Data-Display.md +1 -2
- package/governance/Component-Family-Divider.md +1 -2
- package/governance/Component-Family-Form-Inputs.md +65 -65
- package/governance/Component-Family-Icon.md +9 -10
- package/governance/Component-Family-Loading.md +1 -2
- package/governance/Component-Family-Modal.md +1 -2
- package/governance/Component-Family-Navigation.md +1 -2
- package/governance/Component-Family-Progress.md +0 -1
- package/governance/Component-Inheritance-Structures.md +219 -99
- 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 +59 -44
- package/governance/Component-Templates.md +57 -61
- package/governance/Contract-System-Reference.md +7 -7
- 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 +25 -28
- package/governance/Process-Hook-Operations.md +22 -11
- package/governance/Process-Orchestration-Model-Selection.md +92 -0
- package/governance/Process-Spec-Planning.md +98 -52
- package/governance/Process-Task-Type-Definitions.md +80 -4
- package/governance/Product-Handoff-Protocol.md +2 -0
- package/governance/Rosetta-System-Architecture.md +13 -11
- 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 +47 -34
- 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 +474 -0
- package/governance/completion-documentation-guide.md +23 -37
- 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 +2 -3
- package/governance/release-management-system.md +28 -63
- 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 +24 -26
- 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/tokens/__tests__/defineComponentTokens.test.ts +113 -0
- package/src/build/tokens/defineComponentTokens.ts +43 -1
- 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/avatar.tokens.ts +31 -34
- package/src/components/core/Avatar-Base/contracts.yaml +11 -1
- package/src/components/core/Avatar-Base/index.ts +1 -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/Button-Icon/buttonIcon.tokens.ts +43 -27
- 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/TokenFileGenerator.ts +7 -2
- 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/__tests__/ProgressTokenCompliance.test.ts +5 -3
- package/src/tokens/__tests__/ProgressTokenFormulas.test.ts +11 -11
- package/src/tokens/__tests__/ProgressTokenTranslation.test.ts +22 -20
- package/src/tokens/component/progress.ts +83 -21
- package/src/tokens/semantic/BlendTokens.ts +26 -5
- package/src/tokens/semantic/OpacityTokens.ts +4 -4
- 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/components.yaml +8 -8
- package/token-index/semantics.yaml +1 -2
- package/src/tools/release/__tests__/ChangeClassifier.test.ts +0 -133
- package/src/tools/release/__tests__/ChangeExtractor.test.ts +0 -222
- package/src/tools/release/__tests__/GitHubPublisher.test.ts +0 -240
- package/src/tools/release/__tests__/NotesRenderer.test.ts +0 -142
- package/src/tools/release/__tests__/NpmPublisher.test.ts +0 -289
- package/src/tools/release/__tests__/PipelineIntegration.test.ts +0 -188
- package/src/tools/release/__tests__/ReleasePipeline.test.ts +0 -192
- package/src/tools/release/__tests__/SemanticVersionValidator.test.ts +0 -49
- package/src/tools/release/__tests__/SummaryScanner.test.ts +0 -141
- package/src/tools/release/__tests__/TagResolver.test.ts +0 -91
- package/src/tools/release/__tests__/VersionCalculator.test.ts +0 -270
- package/src/tools/release/__tests__/helpers/NpmMockHelper.ts +0 -80
- package/src/tools/release/cli/ReleasePipeline.ts +0 -165
- package/src/tools/release/cli/release-tool.ts +0 -107
- package/src/tools/release/pipeline/ChangeClassifier.ts +0 -61
- package/src/tools/release/pipeline/ChangeExtractor.ts +0 -87
- package/src/tools/release/pipeline/NotesRenderer.ts +0 -66
- package/src/tools/release/pipeline/SummaryScanner.ts +0 -70
- package/src/tools/release/pipeline/TagResolver.ts +0 -40
- package/src/tools/release/pipeline/VersionCalculator.ts +0 -375
- package/src/tools/release/publishers/GitHubPublisher.ts +0 -228
- package/src/tools/release/publishers/NpmPublisher.ts +0 -196
- package/src/tools/release/release-config.json +0 -5
- package/src/tools/release/types/index.ts +0 -282
- 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
|
|
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
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
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
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
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
|
|
312
|
-
|
|
313
|
-
|
|
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
|
|
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
|