@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
|
@@ -104,10 +104,7 @@ struct InputTextEmail: View {
|
|
|
104
104
|
|
|
105
105
|
/// Maximum length for input value
|
|
106
106
|
let maxLength: Int?
|
|
107
|
-
|
|
108
|
-
/// Disabled state
|
|
109
|
-
let isDisabled: Bool
|
|
110
|
-
|
|
107
|
+
|
|
111
108
|
/// Custom invalid email message
|
|
112
109
|
let invalidEmailMessage: String
|
|
113
110
|
|
|
@@ -155,7 +152,6 @@ struct InputTextEmail: View {
|
|
|
155
152
|
readOnly: Bool = false,
|
|
156
153
|
required: Bool = false,
|
|
157
154
|
maxLength: Int? = nil,
|
|
158
|
-
isDisabled: Bool = false,
|
|
159
155
|
invalidEmailMessage: String = defaultInvalidEmailMessage,
|
|
160
156
|
customValidator: ((String) -> Bool)? = nil
|
|
161
157
|
) {
|
|
@@ -174,7 +170,6 @@ struct InputTextEmail: View {
|
|
|
174
170
|
self.readOnly = readOnly
|
|
175
171
|
self.required = required
|
|
176
172
|
self.maxLength = maxLength
|
|
177
|
-
self.isDisabled = isDisabled
|
|
178
173
|
self.invalidEmailMessage = invalidEmailMessage
|
|
179
174
|
self.customValidator = customValidator
|
|
180
175
|
}
|
|
@@ -207,8 +202,7 @@ struct InputTextEmail: View {
|
|
|
207
202
|
placeholder: placeholder,
|
|
208
203
|
readOnly: readOnly,
|
|
209
204
|
required: required,
|
|
210
|
-
maxLength: maxLength
|
|
211
|
-
isDisabled: isDisabled
|
|
205
|
+
maxLength: maxLength
|
|
212
206
|
)
|
|
213
207
|
}
|
|
214
208
|
|
|
@@ -268,14 +262,6 @@ struct InputTextEmail_Previews: PreviewProvider {
|
|
|
268
262
|
isSuccess: true
|
|
269
263
|
)
|
|
270
264
|
|
|
271
|
-
InputTextEmail(
|
|
272
|
-
id: "preview-disabled",
|
|
273
|
-
label: "Email",
|
|
274
|
-
value: .constant("user@example.com"),
|
|
275
|
-
helperText: "This field is disabled",
|
|
276
|
-
isDisabled: true
|
|
277
|
-
)
|
|
278
|
-
|
|
279
265
|
InputTextEmail(
|
|
280
266
|
id: "preview-required",
|
|
281
267
|
label: "Email",
|
|
@@ -103,7 +103,12 @@ properties:
|
|
|
103
103
|
type: boolean
|
|
104
104
|
required: false
|
|
105
105
|
default: false
|
|
106
|
-
description:
|
|
106
|
+
description: >-
|
|
107
|
+
Accepted for API stability but IGNORED — readOnly is contracted out of
|
|
108
|
+
Input-Text-Password (contracts.yaml excludes.state_readonly; adjudication
|
|
109
|
+
.kiro/issues/input-text-base-ios-readonly-adjudication.md, RULED B-prime,
|
|
110
|
+
Peter 2026-07-15). Implementations never forward it to the base on any
|
|
111
|
+
platform.
|
|
107
112
|
|
|
108
113
|
required:
|
|
109
114
|
type: boolean
|
|
@@ -262,13 +267,15 @@ platform_notes:
|
|
|
262
267
|
ios:
|
|
263
268
|
implementation: SwiftUI View wrapping InputTextBase
|
|
264
269
|
file: platforms/ios/InputTextPassword.ios.swift
|
|
265
|
-
toggle: Button with SF Symbol eye/eye.slash
|
|
270
|
+
toggle: Button with SF Symbol eye/eye.slash, injected via the base's trailingContent slot
|
|
266
271
|
autocomplete: UITextContentType.password or .newPassword
|
|
272
|
+
visibility: Toggles by switching base type between .password and .text
|
|
267
273
|
android:
|
|
268
274
|
implementation: Jetpack Compose Composable wrapping InputTextBase
|
|
269
275
|
file: platforms/android/InputTextPassword.android.kt
|
|
270
|
-
toggle: IconButton with visibility icons
|
|
276
|
+
toggle: IconButton with visibility icons, injected via the base's trailingContent slot
|
|
271
277
|
autocomplete: Autofill framework password type
|
|
278
|
+
visibility: Toggles via the base's visualTransformation override (type stays PASSWORD)
|
|
272
279
|
|
|
273
280
|
# Inheritance relationship
|
|
274
281
|
inheritance:
|
|
@@ -178,7 +178,7 @@ InputTextPassword(
|
|
|
178
178
|
| `isSuccess` | boolean | No | false | Success state indicator |
|
|
179
179
|
| `showInfoIcon` | boolean | No | false | Show info icon |
|
|
180
180
|
| `placeholder` | string | No | - | Placeholder text |
|
|
181
|
-
| `readOnly` | boolean | No | false |
|
|
181
|
+
| `readOnly` | boolean | No | false | Accepted but **ignored** — readOnly is contracted out of Input-Text-Password (never forwarded to the base; see contracts.yaml `excludes.state_readonly` and the adjudication `.kiro/issues/input-text-base-ios-readonly-adjudication.md`, RULED B-prime 2026-07-15) |
|
|
182
182
|
| `required` | boolean | No | false | Required field indicator |
|
|
183
183
|
| `maxLength` | number | No | - | Maximum input length |
|
|
184
184
|
| `testID` | string | No | - | Test ID for automation |
|
|
@@ -216,16 +216,17 @@ InputTextPassword(
|
|
|
216
216
|
3. **validates_on_blur**: Validation triggers on blur
|
|
217
217
|
4. **error_state_display**: Shows error message and styling
|
|
218
218
|
5. **success_state_display**: Shows success styling
|
|
219
|
-
6. **
|
|
220
|
-
7. **
|
|
221
|
-
8. **
|
|
222
|
-
|
|
219
|
+
6. **trailing_icon_display**: Shows contextual trailing icons
|
|
220
|
+
7. **focus_ring**: WCAG 2.4.7 focus visible indicator
|
|
221
|
+
8. **reduced_motion_support**: Respects prefers-reduced-motion
|
|
222
|
+
|
|
223
|
+
**Excluded**: `state_disabled` — DesignerPunk does not support disabled states for usability and accessibility reasons. If an action is unavailable, the component should not be rendered (adjudicated 2026-07-15).
|
|
223
224
|
|
|
224
225
|
### Password-Specific Contracts
|
|
225
226
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
227
|
+
9. **provides_secure_input**: Masks password input by default
|
|
228
|
+
10. **supports_password_toggle**: Show/hide password functionality
|
|
229
|
+
11. **provides_password_autocomplete**: Enables browser/platform password autofill
|
|
229
230
|
|
|
230
231
|
## Validation
|
|
231
232
|
|
|
@@ -61,3 +61,8 @@ excludes:
|
|
|
61
61
|
state_disabled:
|
|
62
62
|
reason: "DesignerPunk does not support disabled states for usability and accessibility reasons. If an action is unavailable, the component should not be rendered."
|
|
63
63
|
category: state
|
|
64
|
+
|
|
65
|
+
state_readonly:
|
|
66
|
+
reason: "readOnly is contracted out of Input-Text-Password: zero named consumers, and excluding it deletes a security fork — the base's iOS read-only path (B-prime) renders the value as selectable plaintext Text, which must never be reachable for a secret. The profile idiom for a locked password is a display row ('Password ••••••••') plus a Change action, not a read-only password field. Implementations strip/ignore the inherited readOnly prop. If a product case ever materializes, the invariant-based fallback rule recorded in the adjudication ([DATA R2] §3: masked value never copyable; plaintext never in the accessibility tree while masked; announced semantically as hidden; no keyboard; toggle functional; revealed plaintext selectable/copyable) is the recorded alternative."
|
|
67
|
+
category: state
|
|
68
|
+
reference: ".kiro/issues/input-text-base-ios-readonly-adjudication.md (RULED B-prime, Peter 2026-07-15, condition 4)"
|
package/src/components/core/Input-Text-Password/platforms/android/InputTextPassword.android.kt
CHANGED
|
@@ -117,12 +117,20 @@ private fun validatePasswordRequirements(
|
|
|
117
117
|
* @param isSuccess Success state indicator
|
|
118
118
|
* @param showInfoIcon Info icon support
|
|
119
119
|
* @param placeholder Placeholder text (only shown when label is floated and input is empty)
|
|
120
|
-
* @param readOnly Read-only state
|
|
120
|
+
* @param readOnly Read-only state — NOT SUPPORTED on Input-Text-Password.
|
|
121
|
+
* readOnly is contracted OUT of the Password variant (see Input-Text-Password
|
|
122
|
+
* contracts.yaml excludes.state_readonly; adjudication condition 4:
|
|
123
|
+
* .kiro/issues/input-text-base-ios-readonly-adjudication.md — RULED B-prime,
|
|
124
|
+
* Peter 2026-07-15). Zero named consumers; contracting it out deletes the
|
|
125
|
+
* security fork rather than fencing it. Note this is contract conformance,
|
|
126
|
+
* not a security fix: on Android the masked PasswordVisualTransformation
|
|
127
|
+
* already suppresses copy/cut ([DATA R2] §3 verification). This param is
|
|
128
|
+
* accepted for API stability but IGNORED: it is never forwarded to
|
|
129
|
+
* InputTextBase.
|
|
121
130
|
* @param required Required field indicator
|
|
122
131
|
* @param maxLength Maximum length for input value
|
|
123
132
|
* @param imeAction IME action for keyboard
|
|
124
133
|
* @param keyboardActions Keyboard actions
|
|
125
|
-
* @param isDisabled Disabled state
|
|
126
134
|
* @param showToggle Whether to show the toggle button
|
|
127
135
|
* @param isNewPassword Whether this is for a new password
|
|
128
136
|
* @param invalidPasswordMessage Custom invalid password message
|
|
@@ -150,7 +158,6 @@ fun InputTextPassword(
|
|
|
150
158
|
maxLength: Int? = null,
|
|
151
159
|
imeAction: ImeAction = ImeAction.Done,
|
|
152
160
|
keyboardActions: KeyboardActions = KeyboardActions.Default,
|
|
153
|
-
isDisabled: Boolean = false,
|
|
154
161
|
showToggle: Boolean = true,
|
|
155
162
|
isNewPassword: Boolean = false,
|
|
156
163
|
invalidPasswordMessage: String = DEFAULT_INVALID_PASSWORD_MESSAGE,
|
|
@@ -212,8 +219,7 @@ fun InputTextPassword(
|
|
|
212
219
|
onClick = {
|
|
213
220
|
isPasswordVisible = !isPasswordVisible
|
|
214
221
|
onToggleVisibility?.invoke(isPasswordVisible)
|
|
215
|
-
}
|
|
216
|
-
enabled = !isDisabled
|
|
222
|
+
}
|
|
217
223
|
) {
|
|
218
224
|
Icon(
|
|
219
225
|
imageVector = if (isPasswordVisible) Icons.Filled.VisibilityOff else Icons.Filled.Visibility,
|
|
@@ -256,12 +262,16 @@ fun InputTextPassword(
|
|
|
256
262
|
type = InputType.PASSWORD,
|
|
257
263
|
visualTransformation = visualTransformation,
|
|
258
264
|
placeholder = placeholder,
|
|
259
|
-
readOnly
|
|
265
|
+
// readOnly is contracted out of Input-Text-Password (excludes.state_readonly;
|
|
266
|
+
// adjudication condition 4: .kiro/issues/input-text-base-ios-readonly-adjudication.md
|
|
267
|
+
// — RULED B-prime, Peter 2026-07-15). Always stripped. Contract conformance,
|
|
268
|
+
// not a security fix — Android's masked PasswordVisualTransformation already
|
|
269
|
+
// suppresses copy/cut, so Android was never the hazard here ([DATA R2] §3).
|
|
270
|
+
readOnly = false,
|
|
260
271
|
required = required,
|
|
261
272
|
maxLength = maxLength,
|
|
262
273
|
imeAction = imeAction,
|
|
263
274
|
keyboardActions = keyboardActions,
|
|
264
|
-
isDisabled = isDisabled,
|
|
265
275
|
trailingContent = toggleButton
|
|
266
276
|
)
|
|
267
277
|
}
|
|
@@ -132,7 +132,16 @@ struct InputTextPassword: View {
|
|
|
132
132
|
/// Placeholder text (only shown when label is floated and input is empty)
|
|
133
133
|
let placeholder: String?
|
|
134
134
|
|
|
135
|
-
/// Read-only state
|
|
135
|
+
/// Read-only state — NOT SUPPORTED on Input-Text-Password.
|
|
136
|
+
///
|
|
137
|
+
/// readOnly is contracted OUT of the Password variant (see
|
|
138
|
+
/// contracts.yaml excludes.state_readonly; adjudication condition 4:
|
|
139
|
+
/// .kiro/issues/input-text-base-ios-readonly-adjudication.md — RULED
|
|
140
|
+
/// B-prime, Peter 2026-07-15). Zero named consumers, and the Base's
|
|
141
|
+
/// read-only path renders selectable plaintext Text — a readOnly
|
|
142
|
+
/// Password must never reach it, masked or revealed. This prop is
|
|
143
|
+
/// accepted for API stability but IGNORED: it is never forwarded to
|
|
144
|
+
/// InputTextBase.
|
|
136
145
|
let readOnly: Bool
|
|
137
146
|
|
|
138
147
|
/// Required field indicator
|
|
@@ -140,10 +149,7 @@ struct InputTextPassword: View {
|
|
|
140
149
|
|
|
141
150
|
/// Maximum length for input value
|
|
142
151
|
let maxLength: Int?
|
|
143
|
-
|
|
144
|
-
/// Disabled state
|
|
145
|
-
let isDisabled: Bool
|
|
146
|
-
|
|
152
|
+
|
|
147
153
|
/// Whether to show the toggle button
|
|
148
154
|
let showToggle: Bool
|
|
149
155
|
|
|
@@ -212,7 +218,6 @@ struct InputTextPassword: View {
|
|
|
212
218
|
readOnly: Bool = false,
|
|
213
219
|
required: Bool = false,
|
|
214
220
|
maxLength: Int? = nil,
|
|
215
|
-
isDisabled: Bool = false,
|
|
216
221
|
showToggle: Bool = true,
|
|
217
222
|
isNewPassword: Bool = false,
|
|
218
223
|
invalidPasswordMessage: String = defaultInvalidPasswordMessage,
|
|
@@ -235,7 +240,6 @@ struct InputTextPassword: View {
|
|
|
235
240
|
self.readOnly = readOnly
|
|
236
241
|
self.required = required
|
|
237
242
|
self.maxLength = maxLength
|
|
238
|
-
self.isDisabled = isDisabled
|
|
239
243
|
self.showToggle = showToggle
|
|
240
244
|
self.isNewPassword = isNewPassword
|
|
241
245
|
self.invalidPasswordMessage = invalidPasswordMessage
|
|
@@ -273,10 +277,14 @@ struct InputTextPassword: View {
|
|
|
273
277
|
type: .text,
|
|
274
278
|
autocomplete: contentType,
|
|
275
279
|
placeholder: placeholder,
|
|
276
|
-
|
|
280
|
+
// SECURITY: readOnly is contracted out of Input-Text-Password
|
|
281
|
+
// (adjudication, RULED B-prime, Peter 2026-07-15). The revealed
|
|
282
|
+
// branch uses type .text — forwarding readOnly here would route
|
|
283
|
+
// the secret to the Base's selectable plaintext Text path.
|
|
284
|
+
// Always stripped.
|
|
285
|
+
readOnly: false,
|
|
277
286
|
required: required,
|
|
278
287
|
maxLength: maxLength,
|
|
279
|
-
isDisabled: isDisabled,
|
|
280
288
|
trailingContent: showToggle ? AnyView(toggleButton) : nil
|
|
281
289
|
)
|
|
282
290
|
} else {
|
|
@@ -304,10 +312,13 @@ struct InputTextPassword: View {
|
|
|
304
312
|
type: .password,
|
|
305
313
|
autocomplete: contentType,
|
|
306
314
|
placeholder: placeholder,
|
|
307
|
-
|
|
315
|
+
// SECURITY: readOnly is contracted out of Input-Text-Password
|
|
316
|
+
// (adjudication, RULED B-prime, Peter 2026-07-15). Stripped on
|
|
317
|
+
// the masked branch too — the Base additionally gates its
|
|
318
|
+
// read-only Text path away from secure fields (defense in depth).
|
|
319
|
+
readOnly: false,
|
|
308
320
|
required: required,
|
|
309
321
|
maxLength: maxLength,
|
|
310
|
-
isDisabled: isDisabled,
|
|
311
322
|
trailingContent: showToggle ? AnyView(toggleButton) : nil
|
|
312
323
|
)
|
|
313
324
|
}
|
|
@@ -327,7 +338,6 @@ struct InputTextPassword: View {
|
|
|
327
338
|
.contentShape(Rectangle())
|
|
328
339
|
}
|
|
329
340
|
.buttonStyle(PlainButtonStyle())
|
|
330
|
-
.disabled(isDisabled)
|
|
331
341
|
.accessibilityLabel(isPasswordVisible ? "Hide password" : "Show password")
|
|
332
342
|
.accessibilityAddTraits(.isButton)
|
|
333
343
|
}
|
|
@@ -408,14 +418,6 @@ struct InputTextPassword_Previews: PreviewProvider {
|
|
|
408
418
|
isSuccess: true
|
|
409
419
|
)
|
|
410
420
|
|
|
411
|
-
InputTextPassword(
|
|
412
|
-
id: "preview-disabled",
|
|
413
|
-
label: "Password",
|
|
414
|
-
value: .constant("secretpassword"),
|
|
415
|
-
helperText: "This field is disabled",
|
|
416
|
-
isDisabled: true
|
|
417
|
-
)
|
|
418
|
-
|
|
419
421
|
InputTextPassword(
|
|
420
422
|
id: "preview-new-password",
|
|
421
423
|
label: "New Password",
|
|
@@ -74,6 +74,9 @@ export class InputTextPassword extends HTMLElement {
|
|
|
74
74
|
'error-message',
|
|
75
75
|
'is-success',
|
|
76
76
|
'show-info-icon',
|
|
77
|
+
// read-only is accepted for API stability but IGNORED — readOnly is
|
|
78
|
+
// contracted out of Input-Text-Password (see render(), and
|
|
79
|
+
// contracts.yaml excludes.state_readonly).
|
|
77
80
|
'read-only',
|
|
78
81
|
'required',
|
|
79
82
|
'max-length',
|
|
@@ -154,7 +157,14 @@ export class InputTextPassword extends HTMLElement {
|
|
|
154
157
|
const propsErrorMessage = this.getAttribute('error-message') || '';
|
|
155
158
|
const isSuccess = this.getAttribute('is-success') === 'true';
|
|
156
159
|
const showInfoIcon = this.getAttribute('show-info-icon') === 'true';
|
|
157
|
-
|
|
160
|
+
// read-only is NOT read or forwarded: readOnly is contracted out of
|
|
161
|
+
// Input-Text-Password (adjudication condition 4:
|
|
162
|
+
// .kiro/issues/input-text-base-ios-readonly-adjudication.md — RULED
|
|
163
|
+
// B-prime, Peter 2026-07-15). On web this is contract conformance, not a
|
|
164
|
+
// security fix — a readonly password input stays masked and browsers
|
|
165
|
+
// block copy from type=password — but the exclusion holds uniformly on
|
|
166
|
+
// all three platforms. The attribute is accepted (observedAttributes)
|
|
167
|
+
// for API stability and ignored.
|
|
158
168
|
const required = this.hasAttribute('required');
|
|
159
169
|
const maxLength = this.getAttribute('max-length');
|
|
160
170
|
const showToggle = this.getAttribute('show-toggle') !== 'false'; // Default true
|
|
@@ -197,7 +207,6 @@ export class InputTextPassword extends HTMLElement {
|
|
|
197
207
|
${errorMessage ? `error-message="${errorMessage}"` : ''}
|
|
198
208
|
${isSuccess ? 'is-success="true"' : ''}
|
|
199
209
|
${showInfoIcon ? 'show-info-icon="true"' : ''}
|
|
200
|
-
${readOnly ? 'read-only' : ''}
|
|
201
210
|
${required ? 'required' : ''}
|
|
202
211
|
${maxLength ? `max-length="${maxLength}"` : ''}
|
|
203
212
|
></input-text-base>
|
|
@@ -103,7 +103,11 @@ properties:
|
|
|
103
103
|
type: boolean
|
|
104
104
|
required: false
|
|
105
105
|
default: false
|
|
106
|
-
description:
|
|
106
|
+
description: >-
|
|
107
|
+
Read-only display state (state_readonly contract) — the value is
|
|
108
|
+
non-editable but stays perceivable, selectable, and copyable; no
|
|
109
|
+
keyboard/IME is raised and disabled semantics are never applied. iOS
|
|
110
|
+
renders it as selectable static text inside the field chrome.
|
|
107
111
|
|
|
108
112
|
required:
|
|
109
113
|
type: boolean
|
|
@@ -101,7 +101,7 @@ InputTextPhoneNumber(
|
|
|
101
101
|
| `isSuccess` | boolean | No | false | Success state indicator |
|
|
102
102
|
| `showInfoIcon` | boolean | No | false | Show info icon |
|
|
103
103
|
| `placeholder` | string | No | - | Placeholder text |
|
|
104
|
-
| `readOnly` | boolean | No | false | Read-only state |
|
|
104
|
+
| `readOnly` | boolean | No | false | Read-only display state (`state_readonly` contract): value is non-editable but selectable and copyable; no keyboard raised; iOS renders selectable text in the field chrome |
|
|
105
105
|
| `required` | boolean | No | false | Required field indicator |
|
|
106
106
|
| `maxLength` | number | No | - | Maximum input length |
|
|
107
107
|
| `testID` | string | No | - | Test ID for automation |
|
|
@@ -149,16 +149,17 @@ InputTextPhoneNumber(
|
|
|
149
149
|
3. **validates_on_blur**: Validation triggers on blur
|
|
150
150
|
4. **error_state_display**: Shows error message and styling
|
|
151
151
|
5. **success_state_display**: Shows success styling
|
|
152
|
-
6. **
|
|
153
|
-
7. **
|
|
154
|
-
8. **
|
|
155
|
-
|
|
152
|
+
6. **trailing_icon_display**: Shows contextual trailing icons
|
|
153
|
+
7. **focus_ring**: WCAG 2.4.7 focus visible indicator
|
|
154
|
+
8. **reduced_motion_support**: Respects prefers-reduced-motion
|
|
155
|
+
|
|
156
|
+
**Excluded**: `state_disabled` — DesignerPunk does not support disabled states for usability and accessibility reasons. If an action is unavailable, the component should not be rendered (adjudicated 2026-07-15).
|
|
156
157
|
|
|
157
158
|
### Phone-Specific Contracts
|
|
158
159
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
160
|
+
9. **validates_phone_format**: Validates phone against country-specific patterns
|
|
161
|
+
10. **provides_phone_formatting**: Formats phone numbers as user types
|
|
162
|
+
11. **supports_international_formats**: Handles multiple country formats
|
|
162
163
|
|
|
163
164
|
## Validation
|
|
164
165
|
|
package/src/components/core/Input-Text-PhoneNumber/platforms/android/InputTextPhoneNumber.android.kt
CHANGED
|
@@ -151,7 +151,6 @@ private fun isValidPhoneNumber(phoneNumber: String, countryCode: String = DEFAUL
|
|
|
151
151
|
* @param maxLength Maximum length for input value
|
|
152
152
|
* @param imeAction IME action for keyboard
|
|
153
153
|
* @param keyboardActions Keyboard actions
|
|
154
|
-
* @param isDisabled Disabled state
|
|
155
154
|
* @param countryCode Country code for formatting and validation
|
|
156
155
|
* @param autoFormat Whether to auto-format as user types
|
|
157
156
|
* @param invalidPhoneMessage Custom invalid phone message
|
|
@@ -177,7 +176,6 @@ fun InputTextPhoneNumber(
|
|
|
177
176
|
maxLength: Int? = null,
|
|
178
177
|
imeAction: ImeAction = ImeAction.Done,
|
|
179
178
|
keyboardActions: KeyboardActions = KeyboardActions.Default,
|
|
180
|
-
isDisabled: Boolean = false,
|
|
181
179
|
countryCode: String = DEFAULT_COUNTRY_CODE,
|
|
182
180
|
autoFormat: Boolean = true,
|
|
183
181
|
invalidPhoneMessage: String = DEFAULT_INVALID_PHONE_MESSAGE,
|
|
@@ -252,14 +250,13 @@ fun InputTextPhoneNumber(
|
|
|
252
250
|
errorMessage = effectiveErrorMessage,
|
|
253
251
|
isSuccess = isSuccess,
|
|
254
252
|
showInfoIcon = showInfoIcon,
|
|
255
|
-
type = InputType.
|
|
253
|
+
type = InputType.TEL,
|
|
256
254
|
placeholder = placeholder,
|
|
257
255
|
readOnly = readOnly,
|
|
258
256
|
required = required,
|
|
259
257
|
maxLength = maxLength,
|
|
260
258
|
imeAction = imeAction,
|
|
261
|
-
keyboardActions = keyboardActions
|
|
262
|
-
isDisabled = isDisabled
|
|
259
|
+
keyboardActions = keyboardActions
|
|
263
260
|
)
|
|
264
261
|
}
|
|
265
262
|
|
package/src/components/core/Input-Text-PhoneNumber/platforms/ios/InputTextPhoneNumber.ios.swift
CHANGED
|
@@ -175,10 +175,7 @@ struct InputTextPhoneNumber: View {
|
|
|
175
175
|
|
|
176
176
|
/// Maximum length for input value
|
|
177
177
|
let maxLength: Int?
|
|
178
|
-
|
|
179
|
-
/// Disabled state
|
|
180
|
-
let isDisabled: Bool
|
|
181
|
-
|
|
178
|
+
|
|
182
179
|
/// Country code for formatting and validation
|
|
183
180
|
let countryCode: String
|
|
184
181
|
|
|
@@ -243,7 +240,6 @@ struct InputTextPhoneNumber: View {
|
|
|
243
240
|
readOnly: Bool = false,
|
|
244
241
|
required: Bool = false,
|
|
245
242
|
maxLength: Int? = nil,
|
|
246
|
-
isDisabled: Bool = false,
|
|
247
243
|
countryCode: String = defaultCountryCode,
|
|
248
244
|
autoFormat: Bool = true,
|
|
249
245
|
invalidPhoneMessage: String = defaultInvalidPhoneMessage,
|
|
@@ -264,7 +260,6 @@ struct InputTextPhoneNumber: View {
|
|
|
264
260
|
self.readOnly = readOnly
|
|
265
261
|
self.required = required
|
|
266
262
|
self.maxLength = maxLength
|
|
267
|
-
self.isDisabled = isDisabled
|
|
268
263
|
self.countryCode = countryCode
|
|
269
264
|
self.autoFormat = autoFormat
|
|
270
265
|
self.invalidPhoneMessage = invalidPhoneMessage
|
|
@@ -296,13 +291,12 @@ struct InputTextPhoneNumber: View {
|
|
|
296
291
|
errorMessage: effectiveErrorMessage,
|
|
297
292
|
isSuccess: isSuccess,
|
|
298
293
|
showInfoIcon: showInfoIcon,
|
|
299
|
-
type: .
|
|
294
|
+
type: .tel,
|
|
300
295
|
autocomplete: .telephoneNumber,
|
|
301
296
|
placeholder: placeholder,
|
|
302
297
|
readOnly: readOnly,
|
|
303
298
|
required: required,
|
|
304
|
-
maxLength: maxLength
|
|
305
|
-
isDisabled: isDisabled
|
|
299
|
+
maxLength: maxLength
|
|
306
300
|
)
|
|
307
301
|
.onAppear {
|
|
308
302
|
// Initialize formatted value from initial value
|
|
@@ -396,14 +390,6 @@ struct InputTextPhoneNumber_Previews: PreviewProvider {
|
|
|
396
390
|
countryCode: "GB"
|
|
397
391
|
)
|
|
398
392
|
|
|
399
|
-
InputTextPhoneNumber(
|
|
400
|
-
id: "preview-disabled",
|
|
401
|
-
label: "Phone Number",
|
|
402
|
-
value: .constant("5551234567"),
|
|
403
|
-
helperText: "This field is disabled",
|
|
404
|
-
isDisabled: true
|
|
405
|
-
)
|
|
406
|
-
|
|
407
393
|
InputTextPhoneNumber(
|
|
408
394
|
id: "preview-required",
|
|
409
395
|
label: "Phone Number",
|
|
@@ -12,7 +12,7 @@ contracts:
|
|
|
12
12
|
may contain logos, search inputs, or other non-heading content.
|
|
13
13
|
Heading semantics are the responsibility of Nav-Header-Page (h1)
|
|
14
14
|
and future variants (Nav-Header-Modal: h2).
|
|
15
|
-
wcag: null
|
|
15
|
+
wcag: "N/A" # legitimate-null: renders-no-heading negative guarantee, no positive WCAG SC (125-B 4.2)
|
|
16
16
|
platforms: [web, ios, android]
|
|
17
17
|
validation:
|
|
18
18
|
- No h1/h2/h3 element rendered
|
|
@@ -122,7 +122,7 @@ contracts:
|
|
|
122
122
|
description: Renders text label for text segments
|
|
123
123
|
behavior: |
|
|
124
124
|
When a segment has a label property, renders the label as text content.
|
|
125
|
-
wcag:
|
|
125
|
+
wcag: "1.3.1 Info and Relationships"
|
|
126
126
|
platforms: [web, ios, android]
|
|
127
127
|
validation:
|
|
128
128
|
- Text segment displays label string
|
|
@@ -59,7 +59,7 @@ contracts:
|
|
|
59
59
|
Connector-Base is marked as decorative (aria-hidden on web,
|
|
60
60
|
accessibilityHidden on iOS, clearAndSetSemantics on Android).
|
|
61
61
|
Semantic variants provide ARIA roles and labels.
|
|
62
|
-
wcag:
|
|
62
|
+
wcag: "1.1.1 Non-text Content"
|
|
63
63
|
platforms: [web, ios, android]
|
|
64
64
|
validation:
|
|
65
65
|
- Connector has aria-hidden="true" (web)
|
|
@@ -65,7 +65,7 @@ contracts:
|
|
|
65
65
|
Label-Base is marked as decorative (aria-hidden on web,
|
|
66
66
|
accessibilityHidden on iOS, clearAndSetSemantics on Android).
|
|
67
67
|
Semantic variants provide ARIA roles and labels.
|
|
68
|
-
wcag:
|
|
68
|
+
wcag: "1.1.1 Non-text Content"
|
|
69
69
|
platforms: [web, ios, android]
|
|
70
70
|
validation:
|
|
71
71
|
- Label has aria-hidden="true" (web)
|
|
@@ -85,7 +85,7 @@ contracts:
|
|
|
85
85
|
Node-Base is marked as decorative (aria-hidden on web,
|
|
86
86
|
accessibilityHidden on iOS, clearAndSetSemantics on Android).
|
|
87
87
|
Semantic variants provide ARIA roles and labels.
|
|
88
|
-
wcag:
|
|
88
|
+
wcag: "1.1.1 Non-text Content"
|
|
89
89
|
platforms: [web, ios, android]
|
|
90
90
|
validation:
|
|
91
91
|
- Node has aria-hidden="true" (web)
|
|
@@ -255,8 +255,11 @@ describe('Progress-Stepper-Base', () => {
|
|
|
255
255
|
});
|
|
256
256
|
|
|
257
257
|
it('throws error when size="sm" (Req 8.10)', () => {
|
|
258
|
-
// jsdom's custom element lifecycle is async, so we need to catch the error differently
|
|
259
|
-
|
|
258
|
+
// jsdom's custom element lifecycle is async, so we need to catch the error differently.
|
|
259
|
+
// preventDefault() marks the error HANDLED, which stops jsdom's default reporter from
|
|
260
|
+
// printing an "Uncaught [Error: ...]" console.error block for this expected throw
|
|
261
|
+
// (CI-log noise; the assertion below still receives the event first).
|
|
262
|
+
const errorHandler = jest.fn((event: ErrorEvent) => event.preventDefault());
|
|
260
263
|
window.addEventListener('error', errorHandler);
|
|
261
264
|
|
|
262
265
|
createStepper({ 'total-steps': '3', 'current-step': '1', size: 'sm' });
|
|
@@ -353,8 +353,11 @@ describe('Progress-Stepper-Detailed', () => {
|
|
|
353
353
|
});
|
|
354
354
|
|
|
355
355
|
it('throws error when size="sm" (Req 8.10)', () => {
|
|
356
|
-
// jsdom's custom element lifecycle is async, so we need to catch the error differently
|
|
357
|
-
|
|
356
|
+
// jsdom's custom element lifecycle is async, so we need to catch the error differently.
|
|
357
|
+
// preventDefault() marks the error HANDLED, which stops jsdom's default reporter from
|
|
358
|
+
// printing an "Uncaught [Error: ...]" console.error block for this expected throw
|
|
359
|
+
// (CI-log noise; the assertion below still receives the event first).
|
|
360
|
+
const errorHandler = jest.fn((event: ErrorEvent) => event.preventDefault());
|
|
358
361
|
window.addEventListener('error', errorHandler);
|
|
359
362
|
|
|
360
363
|
createStepperDetailed({
|
|
@@ -724,6 +724,12 @@ export class DTCGFormatGenerator {
|
|
|
724
724
|
} else if (token.direction === 'lighter') {
|
|
725
725
|
extensions.blendType = 'lighterBlend';
|
|
726
726
|
}
|
|
727
|
+
// Deprecation metadata (e.g. blend.disabledDesaturate) — lets includeDeprecated: false strip it
|
|
728
|
+
if (token.deprecated) {
|
|
729
|
+
extensions.deprecated = true;
|
|
730
|
+
if (token.deprecatedSince) extensions.deprecatedSince = token.deprecatedSince;
|
|
731
|
+
if (token.deprecatedReason) extensions.deprecatedReason = token.deprecatedReason;
|
|
732
|
+
}
|
|
727
733
|
|
|
728
734
|
group[key] = this.toDTCGToken(aliasValue, 'number', token.description, extensions);
|
|
729
735
|
}
|
|
@@ -200,9 +200,8 @@ describe('DTCGFormatGenerator Configuration Options', () => {
|
|
|
200
200
|
// -------------------------------------------------------------------------
|
|
201
201
|
describe('includeDeprecated: false', () => {
|
|
202
202
|
it('should exclude tokens marked as deprecated', () => {
|
|
203
|
-
//
|
|
204
|
-
//
|
|
205
|
-
// and confirming the output is identical (no deprecated tokens to strip)
|
|
203
|
+
// blend.disabledDesaturate is deprecated (2026-07-15, no-disabled-states ruling)
|
|
204
|
+
// and is currently the only deprecated token in the corpus
|
|
206
205
|
const withDeprecated = new DTCGFormatGenerator({ includeDeprecated: true });
|
|
207
206
|
const withoutDeprecated = new DTCGFormatGenerator({ includeDeprecated: false });
|
|
208
207
|
|
|
@@ -213,10 +212,20 @@ describe('DTCGFormatGenerator Configuration Options', () => {
|
|
|
213
212
|
expect(outputWith.$schema).toBeDefined();
|
|
214
213
|
expect(outputWithout.$schema).toBeDefined();
|
|
215
214
|
|
|
216
|
-
//
|
|
215
|
+
// includeDeprecated: true keeps the token and carries deprecation metadata
|
|
216
|
+
const blendWith = outputWith.semanticBlend as Record<string, any>;
|
|
217
|
+
expect(blendWith['blend.disabledDesaturate']).toBeDefined();
|
|
218
|
+
expect(blendWith['blend.disabledDesaturate'].$extensions?.designerpunk?.deprecated).toBe(true);
|
|
219
|
+
expect(blendWith['blend.disabledDesaturate'].$extensions?.designerpunk?.deprecatedSince).toBe('2026-07-15');
|
|
220
|
+
|
|
221
|
+
// includeDeprecated: false strips it
|
|
222
|
+
const blendWithout = outputWithout.semanticBlend as Record<string, any>;
|
|
223
|
+
expect(blendWithout['blend.disabledDesaturate']).toBeUndefined();
|
|
224
|
+
|
|
225
|
+
// Exactly the deprecated token is stripped — nothing else
|
|
217
226
|
const countWith = countAllTokens(outputWith);
|
|
218
227
|
const countWithout = countAllTokens(outputWithout);
|
|
219
|
-
expect(countWith).toBe(countWithout);
|
|
228
|
+
expect(countWith).toBe(countWithout + 1);
|
|
220
229
|
});
|
|
221
230
|
});
|
|
222
231
|
});
|
|
@@ -268,7 +268,7 @@ export class BuildErrorHandler {
|
|
|
268
268
|
'Validate configuration against schema'
|
|
269
269
|
],
|
|
270
270
|
documentation: [
|
|
271
|
-
'https://github.com/3fn/
|
|
271
|
+
'https://github.com/3fn/DesignerPunk/docs/build-integration.md'
|
|
272
272
|
]
|
|
273
273
|
};
|
|
274
274
|
}
|
|
@@ -293,7 +293,7 @@ export class BuildErrorHandler {
|
|
|
293
293
|
'Ensure platform files are generated correctly'
|
|
294
294
|
],
|
|
295
295
|
documentation: [
|
|
296
|
-
`https://github.com/3fn/
|
|
296
|
+
`https://github.com/3fn/DesignerPunk/docs/platforms/${platform}.md`
|
|
297
297
|
]
|
|
298
298
|
};
|
|
299
299
|
}
|
|
@@ -113,7 +113,7 @@ export const opacityTokens: Record<string, PrimitiveToken> = {
|
|
|
113
113
|
category: TokenCategory.OPACITY,
|
|
114
114
|
baseValue: OPACITY_BASE_VALUE * 6,
|
|
115
115
|
familyBaseValue: OPACITY_BASE_VALUE,
|
|
116
|
-
description: '
|
|
116
|
+
description: 'Very strong transparency - background scrims and modal overlays (referenced by opacity.heavy)',
|
|
117
117
|
mathematicalRelationship: 'base × 6 = 0.08 × 6 = 0.48',
|
|
118
118
|
baselineGridAlignment: false,
|
|
119
119
|
isStrategicFlexibility: false,
|
|
@@ -280,7 +280,9 @@ describe('Opacity Tokens', () => {
|
|
|
280
280
|
|
|
281
281
|
expect(opacity000?.description).toContain('Fully transparent');
|
|
282
282
|
expect(opacity008?.description).toContain('Subtle transparency');
|
|
283
|
-
|
|
283
|
+
// opacity048 description corrected 2026-07-15: disabled-state phrasing removed
|
|
284
|
+
// (no-disabled-states philosophy, Button-CTA adjudication)
|
|
285
|
+
expect(opacity048?.description).toContain('Very strong transparency');
|
|
284
286
|
expect(opacity100?.description).toContain('Fully opaque');
|
|
285
287
|
});
|
|
286
288
|
|