@santi020k/lumen 3.0.1 → 4.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.
Files changed (125) hide show
  1. package/README.md +207 -3
  2. package/dist/cli.js +49 -5
  3. package/dist/consumer-upgrade-audit.d.ts +10 -0
  4. package/dist/consumer-upgrade-audit.d.ts.map +1 -0
  5. package/dist/consumer-upgrade-audit.js +52 -0
  6. package/dist/index.d.ts +3 -0
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +3 -0
  9. package/dist/installer.d.ts.map +1 -1
  10. package/dist/installer.js +16 -0
  11. package/dist/integration-diagnostics.d.ts.map +1 -1
  12. package/dist/integration-diagnostics.js +199 -3
  13. package/dist/registry-component-name.d.ts +2 -0
  14. package/dist/registry-component-name.d.ts.map +1 -0
  15. package/dist/registry-component-name.js +53 -0
  16. package/dist/registry-data.d.ts +339 -18
  17. package/dist/registry-data.d.ts.map +1 -1
  18. package/dist/registry-data.js +789 -3
  19. package/dist/registry.d.ts.map +1 -1
  20. package/dist/registry.js +11 -9
  21. package/dist/source-script-ranges.d.ts +3 -0
  22. package/dist/source-script-ranges.d.ts.map +1 -0
  23. package/dist/source-script-ranges.js +41 -0
  24. package/dist/v2-migration.d.ts +38 -0
  25. package/dist/v2-migration.d.ts.map +1 -1
  26. package/dist/v2-migration.js +26 -14
  27. package/dist/v4-migration.d.ts +26 -0
  28. package/dist/v4-migration.d.ts.map +1 -0
  29. package/dist/v4-migration.js +272 -0
  30. package/dist/version-migration-dependencies.d.ts +8 -0
  31. package/dist/version-migration-dependencies.d.ts.map +1 -0
  32. package/dist/version-migration-dependencies.js +10 -0
  33. package/dist/version-migration-source.d.ts +4 -0
  34. package/dist/version-migration-source.d.ts.map +1 -0
  35. package/dist/version-migration-source.js +281 -0
  36. package/dist/version-migration.d.ts +34 -0
  37. package/dist/version-migration.d.ts.map +1 -0
  38. package/dist/version-migration.js +158 -0
  39. package/native-components.json +563 -16
  40. package/package.json +26 -11
  41. package/release-manifest.json +22 -17
  42. package/styles/critical.css +634 -61
  43. package/styles/motion.css +61 -0
  44. package/styles/world-map.css +30 -0
  45. package/styles.css +1736 -455
  46. package/templates/astro/advanced-fields/src/lumen/advanced-fields.astro +35 -0
  47. package/templates/astro/ai-docs/llms.txt +3 -0
  48. package/templates/astro/analytics-dashboard/src/lumen/analytics-dashboard.astro +110 -0
  49. package/templates/astro/auth-onboarding/src/lumen/auth-onboarding.astro +107 -0
  50. package/templates/astro/command-center/src/lumen/command-center.astro +34 -0
  51. package/templates/astro/commerce-dashboard/src/lumen/commerce-dashboard.astro +108 -0
  52. package/templates/astro/content-flow-actions/src/lumen/content-flow-actions.astro +10 -0
  53. package/templates/astro/content-flow-header/src/lumen/content-flow-header.astro +14 -0
  54. package/templates/astro/content-flow-list/src/lumen/content-flow-list.astro +13 -0
  55. package/templates/astro/content-flow-settings/src/lumen/content-flow-settings.astro +17 -0
  56. package/templates/astro/data-collections/src/lumen/data-collections.astro +52 -0
  57. package/templates/astro/feature-preview/src/lumen/feature-preview.astro +32 -0
  58. package/templates/astro/guided-onboarding/src/lumen/guided-onboarding.astro +35 -0
  59. package/templates/astro/interactive-pricing/src/lumen/interactive-pricing.astro +32 -0
  60. package/templates/astro/media-workspace/src/lumen/adjustment-controls.astro +89 -0
  61. package/templates/astro/media-workspace/src/lumen/media-processing.astro +47 -0
  62. package/templates/astro/media-workspace/src/lumen/media-workspace.astro +77 -0
  63. package/templates/astro/page-header/src/lumen/page-header.astro +41 -0
  64. package/templates/astro/project-workspace/src/lumen/project-workspace.astro +103 -0
  65. package/templates/astro/rich-text-editor/src/lumen/rich-text-editor.astro +21 -0
  66. package/templates/astro/saas-admin/src/lumen/saas-admin.astro +110 -0
  67. package/templates/astro/scheduler/src/lumen/scheduler.astro +36 -0
  68. package/templates/astro/section-header/src/lumen/section-header.astro +35 -0
  69. package/templates/astro/theme-builder/src/lumen/theme-builder.astro +28 -0
  70. package/templates/elements/advanced-fields/src/lumen/advanced-fields.html +25 -0
  71. package/templates/elements/analytics-dashboard/src/lumen/analytics-dashboard.html +28 -0
  72. package/templates/elements/auth-onboarding/src/lumen/auth-onboarding.html +79 -0
  73. package/templates/elements/command-center/src/lumen/command-center.html +15 -0
  74. package/templates/elements/commerce-dashboard/src/lumen/commerce-dashboard.html +24 -0
  75. package/templates/elements/content-flow-actions/src/lumen/content-flow-actions.html +11 -0
  76. package/templates/elements/content-flow-header/src/lumen/content-flow-header.html +15 -0
  77. package/templates/elements/content-flow-list/src/lumen/content-flow-list.html +14 -0
  78. package/templates/elements/content-flow-settings/src/lumen/content-flow-settings.html +18 -0
  79. package/templates/elements/data-collections/src/lumen/data-collections.html +31 -0
  80. package/templates/elements/feature-preview/src/lumen/feature-preview.html +13 -0
  81. package/templates/elements/guided-onboarding/src/lumen/guided-onboarding.html +16 -0
  82. package/templates/elements/interactive-pricing/src/lumen/interactive-pricing.html +13 -0
  83. package/templates/elements/media-workspace/src/lumen/media-workspace.html +57 -0
  84. package/templates/elements/media-workspace/src/lumen/media-workspace.ts +163 -0
  85. package/templates/elements/page-header/src/lumen/page-header.html +20 -0
  86. package/templates/elements/project-workspace/src/lumen/project-workspace.html +17 -0
  87. package/templates/elements/rich-text-editor/src/lumen/rich-text-editor.html +17 -0
  88. package/templates/elements/saas-admin/src/lumen/saas-admin.html +18 -0
  89. package/templates/elements/scheduler/src/lumen/scheduler.html +27 -0
  90. package/templates/elements/section-header/src/lumen/section-header.html +21 -0
  91. package/templates/elements/theme-builder/src/lumen/theme-builder.html +59 -0
  92. package/templates/react/advanced-fields/src/lumen/advanced-fields.tsx +37 -0
  93. package/templates/react/analytics-dashboard/src/lumen/analytics-dashboard.tsx +143 -0
  94. package/templates/react/auth-onboarding/src/lumen/auth-onboarding.tsx +129 -0
  95. package/templates/react/command-center/src/lumen/command-center.tsx +85 -0
  96. package/templates/react/commerce-dashboard/src/lumen/commerce-dashboard.tsx +148 -0
  97. package/templates/react/content-flow-actions/src/lumen/content-flow-actions.tsx +11 -0
  98. package/templates/react/content-flow-header/src/lumen/content-flow-header.tsx +14 -0
  99. package/templates/react/content-flow-list/src/lumen/content-flow-list.tsx +19 -0
  100. package/templates/react/content-flow-settings/src/lumen/content-flow-settings.tsx +26 -0
  101. package/templates/react/data-collections/src/lumen/data-collections.tsx +60 -0
  102. package/templates/react/feature-preview/src/lumen/feature-preview.tsx +42 -0
  103. package/templates/react/guided-onboarding/src/lumen/guided-onboarding.tsx +100 -0
  104. package/templates/react/import-review/src/lumen/import-review.tsx +150 -0
  105. package/templates/react/interactive-pricing/src/lumen/interactive-pricing.tsx +60 -0
  106. package/templates/react/media-workspace/src/lumen/adjustment-controls.tsx +61 -0
  107. package/templates/react/media-workspace/src/lumen/media-processing.tsx +43 -0
  108. package/templates/react/media-workspace/src/lumen/media-workspace.tsx +100 -0
  109. package/templates/react/operational-records/src/lumen/operational-records.tsx +92 -0
  110. package/templates/react/page-header/src/lumen/page-header.tsx +41 -0
  111. package/templates/react/project-workspace/src/lumen/project-workspace.tsx +112 -0
  112. package/templates/react/record-workspace/src/lumen/record-workspace.tsx +67 -0
  113. package/templates/react/review-workflow/src/lumen/review-workflow.tsx +202 -0
  114. package/templates/react/rich-text-editor/src/lumen/rich-text-editor.tsx +33 -0
  115. package/templates/react/saas-admin/src/lumen/saas-admin.tsx +119 -0
  116. package/templates/react/scheduler/src/lumen/scheduler.tsx +45 -0
  117. package/templates/react/section-header/src/lumen/section-header.tsx +33 -0
  118. package/templates/react/styles.d.ts +1 -0
  119. package/templates/react/theme-builder/src/lumen/theme-builder.tsx +57 -0
  120. package/templates/react/tsconfig.json +14 -0
  121. package/templates/react/validated-form/src/lumen/validated-form.tsx +166 -0
  122. package/templates/shared/common/src/lumen/lumen-template.css +247 -0
  123. package/templates/shared/media-workspace/src/lumen/media-workspace.css +14 -0
  124. package/templates/shared/visual-blocks/src/lumen/product-blocks.ts +224 -0
  125. package/v4-migration.json +447 -0
@@ -0,0 +1,224 @@
1
+ /** Local recipe interactions. Applications own checkout, persistence, navigation, and authorization. */
2
+ const announce = (root: HTMLElement, text: string): void => {
3
+ const status = root.querySelector<HTMLElement>('[data-block-status]')
4
+
5
+ if (status) status.textContent = text
6
+ }
7
+
8
+ const dispatch = (root: HTMLElement, name: string, detail: Readonly<Record<string, string>>): boolean => (
9
+ root.dispatchEvent(new CustomEvent(name, { bubbles: true, cancelable: true, detail }))
10
+ )
11
+
12
+ const updateBilling = (root: HTMLElement, billing: string): void => {
13
+ for (const button of root.querySelectorAll<HTMLElement>('[data-billing]')) button.setAttribute('aria-pressed', String(button.dataset.billing === billing))
14
+
15
+ for (const amount of root.querySelectorAll<HTMLElement>('[data-monthly][data-annual]')) {
16
+ const price = (billing === 'annual' ? amount.dataset.annual : amount.dataset.monthly) ?? '0'
17
+
18
+ amount.textContent = `$${price} / ${billing === 'annual' ? 'year' : 'month'}`
19
+ }
20
+ }
21
+
22
+ const bindPricingBlock = (root: HTMLElement): (() => void) => {
23
+ let billing = 'monthly'
24
+
25
+ const click = (event: MouseEvent): void => {
26
+ if (!(event.target instanceof Element)) return
27
+
28
+ const control = event.target.closest<HTMLElement>('[data-billing], [data-plan]')
29
+
30
+ if (control?.closest('[data-product-block]') !== root) return
31
+
32
+ if (control.dataset.billing) {
33
+ billing = control.dataset.billing
34
+
35
+ updateBilling(root, billing)
36
+ } else if (control.dataset.plan) {
37
+ dispatch(root, 'ui:plan-select', { billing, plan: control.dataset.plan })
38
+
39
+ announce(root, `Selected ${control.dataset.plan}, ${billing}.`)
40
+ }
41
+ }
42
+
43
+ root.addEventListener('click', click)
44
+
45
+ return () => {
46
+ root.removeEventListener('click', click)
47
+ }
48
+ }
49
+
50
+ const bindFeatureBlock = (root: HTMLElement): (() => void) => {
51
+ const click = (event: MouseEvent): void => {
52
+ if (!(event.target instanceof Element)) return
53
+
54
+ const button = event.target.closest<HTMLElement>('[data-feature]')
55
+
56
+ if (button?.closest('[data-product-block]') !== root) return
57
+
58
+ const feature = button.dataset.feature ?? 'plan'
59
+
60
+ for (const control of root.querySelectorAll<HTMLElement>('[data-feature]')) control.setAttribute('aria-pressed', String(control.dataset.feature === feature))
61
+
62
+ for (const panel of root.querySelectorAll<HTMLElement>('[data-feature-panel]')) panel.hidden = panel.dataset.featurePanel !== feature
63
+
64
+ announce(root, `Previewing ${feature}.`)
65
+ }
66
+
67
+ root.addEventListener('click', click)
68
+
69
+ return () => {
70
+ root.removeEventListener('click', click)
71
+ }
72
+ }
73
+
74
+ export const bindOnboardingBlock = (root: HTMLElement): (() => void) => {
75
+ const form = root.querySelector('form')
76
+ const input = root.querySelector<HTMLInputElement>('input[data-workspace-name], [data-workspace-name] input')
77
+
78
+ if (!form || !input) return () => undefined
79
+
80
+ let step = 0
81
+
82
+ const updateValidity = (): void => {
83
+ const next = root.querySelector<HTMLElement>('[data-onboarding-next]')
84
+ const disabled = !input.value.trim()
85
+
86
+ next?.toggleAttribute('disabled', disabled)
87
+
88
+ next?.classList.toggle('ui-button--disabled', disabled)
89
+ }
90
+
91
+ input.addEventListener('input', updateValidity)
92
+
93
+ updateValidity()
94
+
95
+ const sync = (): void => {
96
+ for (const panel of root.querySelectorAll<HTMLElement>('[data-onboarding-step]')) panel.hidden = Number(panel.dataset.onboardingStep) !== step
97
+
98
+ const review = root.querySelector<HTMLElement>('[data-workspace-review]')
99
+
100
+ if (review) review.textContent = input.value
101
+
102
+ const back = root.querySelector<HTMLElement>('[data-onboarding-back]')
103
+
104
+ if (back) back.hidden = step !== 1
105
+
106
+ const next = root.querySelector<HTMLButtonElement>('[data-onboarding-next]')
107
+
108
+ if (next) {
109
+ next.hidden = step === 2
110
+
111
+ next.textContent = step === 0 ? 'Continue' : 'Complete setup'
112
+ }
113
+
114
+ announce(root, `Step ${step + 1} of 3${step === 2 ? ': draft completed.' : '.'}`)
115
+
116
+ root.querySelector<HTMLElement>(`[data-onboarding-step="${step}"] h3`)?.focus()
117
+ }
118
+
119
+ const submit = (event: SubmitEvent): void => {
120
+ event.preventDefault()
121
+
122
+ if (!input.value.trim() || !form.reportValidity() || step === 2) return
123
+
124
+ if (step === 1 && !dispatch(root, 'ui:onboarding-complete', { workspace: input.value.trim() })) return
125
+
126
+ step++
127
+
128
+ sync()
129
+ }
130
+
131
+ const back = (event: MouseEvent): void => {
132
+ if (!(event.target instanceof Element)) return
133
+
134
+ if (event.target.closest('lumen-button[data-onboarding-next]')) {
135
+ form.requestSubmit()
136
+
137
+ return
138
+ }
139
+
140
+ if (!event.target.closest('[data-onboarding-back], [data-onboarding-edit]')) return
141
+
142
+ step = 0
143
+
144
+ sync()
145
+ }
146
+
147
+ form.addEventListener('submit', submit)
148
+
149
+ root.addEventListener('click', back)
150
+
151
+ return () => {
152
+ input.removeEventListener('input', updateValidity)
153
+
154
+ form.removeEventListener('submit', submit)
155
+
156
+ root.removeEventListener('click', back)
157
+ }
158
+ }
159
+
160
+ const bindCommandBlock = (root: HTMLElement): (() => void) => {
161
+ const click = (event: MouseEvent): void => {
162
+ if (!(event.target instanceof Element)) return
163
+
164
+ const command = event.target.closest<HTMLElement>('[data-workspace-command]')
165
+
166
+ if (command?.closest('[data-product-block]') !== root || !command.dataset.workspaceCommand) return
167
+
168
+ dispatch(root, 'ui:workspace-command', { command: command.dataset.workspaceCommand })
169
+
170
+ announce(root, `Selected: ${command.textContent}`)
171
+ }
172
+
173
+ root.addEventListener('click', click)
174
+
175
+ return () => {
176
+ root.removeEventListener('click', click)
177
+ }
178
+ }
179
+
180
+ const mountedBlocks = new WeakMap<HTMLElement, () => void>()
181
+
182
+ export const mountProductBlocks = (scope: ParentNode): (() => void) => {
183
+ const cleanups: (() => void)[] = []
184
+
185
+ for (const root of scope.querySelectorAll<HTMLElement>('[data-product-block]')) {
186
+ if (mountedBlocks.has(root)) continue
187
+
188
+ let binding: (() => void) | undefined
189
+
190
+ switch (root.dataset.productBlock) {
191
+ case 'pricing': binding = bindPricingBlock(root)
192
+
193
+ break
194
+
195
+ case 'feature': binding = bindFeatureBlock(root)
196
+
197
+ break
198
+
199
+ case 'onboarding': binding = bindOnboardingBlock(root)
200
+
201
+ break
202
+
203
+ case 'command': binding = bindCommandBlock(root)
204
+
205
+ break
206
+ }
207
+
208
+ if (!binding) continue
209
+
210
+ mountedBlocks.set(root, binding)
211
+
212
+ const cleanup = binding
213
+
214
+ cleanups.push(() => {
215
+ cleanup()
216
+
217
+ mountedBlocks.delete(root)
218
+ })
219
+ }
220
+
221
+ return () => {
222
+ for (const cleanup of cleanups) cleanup()
223
+ }
224
+ }
@@ -0,0 +1,447 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "status": "approved",
4
+ "targetVersion": "4.0.0",
5
+ "policy": {
6
+ "compatibility": "Lumen 4 may deliberately replace v3 component and binary contracts. Consumer data, privacy, and release approval remain protected. Migration guidance documents externally visible changes.",
7
+ "versioning": "Prepare the coordinated v4 candidate locally. Publication requires separate approval of the final reviewed revision through the existing GitHub release workflow."
8
+ },
9
+ "changes": [
10
+ {
11
+ "id": "consumer-driven-component-polish",
12
+ "kind": "breaking",
13
+ "currentContract": "Consumers carry chart-label, hidden-state, clipboard, date-selection, and native-layout workarounds across older Lumen releases.",
14
+ "replacement": "Shared chart geometry and formatted axes, strict range selection, explicit clipboard recovery, accessible native layout controls, and a cross-framework image comparison primitive.",
15
+ "migration": "Use stable unique chart X identities; remove verified old chart/hidden patches; review button content selectors and loading activation; rebuild native consumers for changed initializer and formatter contracts.",
16
+ "evidence": [
17
+ "docs/lumen-4-consumer-audit.md",
18
+ "docs/lumen-4-readiness.md"
19
+ ],
20
+ "docs": [
21
+ "docs/migrating-to-lumen.md",
22
+ "docs/data-visualization.md",
23
+ "docs/ai-usage.md"
24
+ ],
25
+ "tests": [
26
+ "pnpm run validate",
27
+ "pnpm run test:a11y",
28
+ "swift test",
29
+ "cd packages/compose && ./gradlew test lint apiCheck"
30
+ ],
31
+ "packages": [
32
+ "@santi020k/lumen-core",
33
+ "@santi020k/lumen-astro",
34
+ "@santi020k/lumen-react",
35
+ "@santi020k/lumen-elements",
36
+ "@santi020k/lumen-react-native",
37
+ "LumenUI",
38
+ "com.santi020k:lumen-compose"
39
+ ],
40
+ "signals": [
41
+ "DatePicker",
42
+ "DateRange",
43
+ "Button",
44
+ "Chart",
45
+ "CopyButton",
46
+ "NavigationMenu",
47
+ "hidden="
48
+ ]
49
+ },
50
+ {
51
+ "id": "swift-native-control-polish",
52
+ "kind": "breaking",
53
+ "currentContract": "Eight v3 Swift initializer signatures do not expose compact chart, heatmap color scales, chart-data labels and formatting, slider-label, and symbol-selection options. The v3 icon enum lacks four reviewed catalog additions.",
54
+ "replacement": "Defaulted parameters provide bare chart frames, explicit plot height, heatmap color scales and legends, localized interval-chart data and formatting, optional slider headings, contextual symbol tint, and selection completion. The icon enum adds bangladeshiTaka, layoutGridCircles, letters, and printer3d.",
55
+ "migration": "Rebuild consumers against v4. Existing source calls generally retain defaults; method references and binary clients must adopt the new signatures. Exhaustive LumenIconName switches must handle the four new cases or provide an appropriate fallback. See native composition examples and the v4 migration guide.",
56
+ "packages": [
57
+ "LumenUI"
58
+ ],
59
+ "evidence": [
60
+ "docs/lumen-4-consumer-audit.md",
61
+ "docs/native-api-audit.md"
62
+ ],
63
+ "docs": [
64
+ "packages/swift/README.md",
65
+ "docs/native-patterns.md",
66
+ "docs/migrating-to-lumen.md"
67
+ ],
68
+ "tests": [
69
+ "swift test",
70
+ "pnpm run check:swift-api-baseline",
71
+ "pnpm run check:swift-source-compatibility"
72
+ ],
73
+ "swiftApiBreakages": [
74
+ "constructor LumenBarChart.init(label:series:layout:summary:labels:showData:selection:) has been removed",
75
+ "constructor LumenChartLabels.init(empty:notAvailable:size:viewData:formatHeatmapSummary:formatRangeSummary:formatSummary:) has been removed",
76
+ "constructor LumenHeatmap.init(label:data:summary:labels:showData:) has been removed",
77
+ "constructor LumenLineChart.init(label:series:heading:description:summary:labels:area:reference:showData:selection:) has been removed",
78
+ "constructor LumenSlider.init(_:value:in:step:valueLabel:) has been removed",
79
+ "constructor LumenSlider.init(_:value:in:step:valueLabel:onEditingChanged:) has been removed",
80
+ "constructor LumenSymbolPicker.init(_:selectedName:options:) has been removed",
81
+ "constructor LumenSymbolPickerButton.init(_:selectedName:options:) has been removed",
82
+ "enumelement LumenIconName.bangladeshiTaka has been added as a new enum case",
83
+ "enumelement LumenIconName.layoutGridCircles has been added as a new enum case",
84
+ "enumelement LumenIconName.letters has been added as a new enum case",
85
+ "enumelement LumenIconName.printer3d has been added as a new enum case"
86
+ ],
87
+ "signals": [
88
+ "LumenBarChart",
89
+ "LumenLineChart",
90
+ "LumenSlider",
91
+ "LumenSymbolPicker",
92
+ "LumenIconName",
93
+ "LumenHeatmap"
94
+ ]
95
+ },
96
+ {
97
+ "id": "native-sheet-accessibility-quality",
98
+ "kind": "breaking",
99
+ "currentContract": "SwiftUI and Compose sheets wrap unbounded content without configurable dismissal protection; native required-field and tab-panel descriptions include fixed English text.",
100
+ "replacement": "Native sheet scroll and dismissal policies, keyboard-safe content, compact-height and large-text fallbacks, explicit React Native focus targets, and caller-localized accessibility descriptions.",
101
+ "migration": "Rebuild SwiftUI and Compose consumers for the new sheet signatures. Set scrollable false for application-owned lazy or virtualized content. Supply translated requiredLabel and panelAccessibilityLabel in Compose and React Native when needed.",
102
+ "packages": [
103
+ "@santi020k/lumen-react-native",
104
+ "LumenUI",
105
+ "com.santi020k:lumen-compose"
106
+ ],
107
+ "evidence": [
108
+ "docs/lumen-4-native-quality.md"
109
+ ],
110
+ "docs": [
111
+ "docs/native-patterns.md",
112
+ "docs/migrating-to-lumen.md"
113
+ ],
114
+ "tests": [
115
+ "pnpm --filter @santi020k/lumen-react-native test",
116
+ "swift test",
117
+ "cd packages/compose && ./gradlew test lint apiCheck connectedDebugAndroidTest"
118
+ ],
119
+ "swiftApiBreakages": [
120
+ "func View.lumenSheet(isPresented:title:description:onDismiss:actions:content:) has been renamed to func lumenSheet(isPresented:title:description:dismissible:scrollable:onDismiss:actions:content:)",
121
+ "func View.lumenSheet(isPresented:title:description:onDismiss:actions:content:) has parameter 3 type change from () -> Swift.Void to Swift.Bool",
122
+ "func View.lumenSheet(isPresented:title:description:onDismiss:actions:content:) has parameter 4 type change from () -> Actions to Swift.Bool",
123
+ "func View.lumenSheet(isPresented:title:description:onDismiss:actions:content:) has parameter 5 type change from () -> SheetContent to () -> Swift.Void",
124
+ "func View.lumenSheet(isPresented:title:description:onDismiss:content:) has been renamed to func lumenSheet(isPresented:title:description:dismissible:scrollable:onDismiss:content:)",
125
+ "func View.lumenSheet(isPresented:title:description:onDismiss:content:) has parameter 3 type change from () -> Swift.Void to Swift.Bool",
126
+ "func View.lumenSheet(isPresented:title:description:onDismiss:content:) has parameter 4 type change from () -> SheetContent to Swift.Bool"
127
+ ],
128
+ "signals": [
129
+ "lumenSheet",
130
+ "LumenSheet",
131
+ "requiredLabel",
132
+ "panelAccessibilityLabel"
133
+ ]
134
+ },
135
+ {
136
+ "id": "embedded-mcp-sdk-v2",
137
+ "kind": "breaking",
138
+ "currentContract": "Embedded Lumen MCP integrations import SDK v1 server and transport objects.",
139
+ "replacement": "The embedded server uses SDK v2 server, client and transport packages.",
140
+ "migration": "Migrate known SDK module paths, update SDK dependencies to compatible v2 packages, rebuild and test the real transport. Other SDK imports require manual review.",
141
+ "packages": [
142
+ "@santi020k/lumen-mcp"
143
+ ],
144
+ "signals": [
145
+ "@modelcontextprotocol/sdk/"
146
+ ],
147
+ "evidence": [
148
+ "packages/mcp/src/server.ts"
149
+ ],
150
+ "docs": [
151
+ "docs/migrating-to-lumen.md"
152
+ ],
153
+ "tests": [
154
+ "pnpm run check:mcp-evaluation",
155
+ "pnpm run check:mcp-package"
156
+ ]
157
+ },
158
+ {
159
+ "id": "appearance-presets",
160
+ "kind": "breaking",
161
+ "currentContract": "Theme palettes and surface dimensions are customized separately in each adapter. Swift surface and theme initializer signatures do not expose appearance or material options.",
162
+ "replacement": "Canonical Default, Studio and Glass appearances, scoped web tokens, ThemeBuilder dimensions and explicit surface material with native opaque fallbacks.",
163
+ "migration": "Choose a preset, then override semantic tokens or native appearance values. Glass remains explicit per surface. Rebuild Swift and Compose consumers; Swift initializer references must include the defaulted appearance and material parameters.",
164
+ "packages": [
165
+ "@santi020k/lumen-core",
166
+ "@santi020k/lumen-astro",
167
+ "@santi020k/lumen-react",
168
+ "@santi020k/lumen-elements",
169
+ "@santi020k/lumen-react-native",
170
+ "@santi020k/lumen-tokens",
171
+ "@santi020k/lumen-mcp",
172
+ "LumenUI",
173
+ "com.santi020k:lumen-compose"
174
+ ],
175
+ "evidence": [
176
+ "docs/appearance-presets.md"
177
+ ],
178
+ "docs": [
179
+ "docs/appearance-presets.md",
180
+ "docs/migrating-to-lumen.md"
181
+ ],
182
+ "tests": [
183
+ "pnpm run validate",
184
+ "swift test",
185
+ "cd packages/compose && ./gradlew test lint apiCheck"
186
+ ],
187
+ "swiftApiBreakages": [
188
+ "constructor LumenCard.init(variant:action:content:) has been removed",
189
+ "constructor LumenCard.init(variant:padding:radius:action:content:) has been removed",
190
+ "constructor LumenSurface.init(tone:padding:radius:content:) has been removed",
191
+ "constructor LumenTheme.init(colors:scheme:) has been removed"
192
+ ],
193
+ "signals": [
194
+ "LumenTheme",
195
+ "LumenProvider",
196
+ "ThemeBuilder",
197
+ "data-lumen-preset",
198
+ "glass"
199
+ ]
200
+ },
201
+ {
202
+ "id": "swift-phone-presentation-signature",
203
+ "kind": "breaking",
204
+ "currentContract": "The v3 phone initializer does not expose presentation controls.",
205
+ "replacement": "Defaulted v4 selector, display format, placeholder, flag and size options for existing phone selection behavior.",
206
+ "migration": "Rebuild Swift consumers and update initializer references for the added defaulted phone presentation parameters.",
207
+ "packages": [
208
+ "LumenUI"
209
+ ],
210
+ "evidence": [
211
+ "docs/lumen-4-readiness.md"
212
+ ],
213
+ "docs": [
214
+ "packages/swift/README.md",
215
+ "docs/lumen-4-readiness.md"
216
+ ],
217
+ "tests": [
218
+ "swift test",
219
+ "pnpm run check:swift-source-compatibility"
220
+ ],
221
+ "swiftApiBreakages": [
222
+ "constructor LumenPhoneInput.init(_:value:countries:locale:description:errorMessage:showValidationError:invalidNumberMessage:numberLabel:countrySelectorLabel:countryPickerTitle:countrySearchLabel:required:enabled:) has been removed"
223
+ ],
224
+ "signals": [
225
+ "LumenPhoneInput"
226
+ ]
227
+ },
228
+ {
229
+ "id": "web-content-flow",
230
+ "kind": "breaking",
231
+ "currentContract": "Explicit v3 Stack/Grid gaps use a separate scale; cards and reading blocks rely on child margins and clipped overflow.",
232
+ "replacement": "Canonical web gaps, parent-owned spacing, Card density and visible overflow, responsive Container gutters and trimmed reading-block margins.",
233
+ "migration": "Map literal web gaps md/lg/xl to group/xl/2xl with lumen migrate v4. Review Card density, compensating margins and clipping; put media clipping in AspectRatio. Native spacing is unchanged.",
234
+ "packages": [
235
+ "@santi020k/lumen-core",
236
+ "@santi020k/lumen-astro",
237
+ "@santi020k/lumen-react",
238
+ "@santi020k/lumen-elements"
239
+ ],
240
+ "evidence": [
241
+ "docs/content-flow.md"
242
+ ],
243
+ "docs": [
244
+ "docs/migrating-v3-to-v4.md",
245
+ "docs/content-flow.md"
246
+ ],
247
+ "tests": [
248
+ "pnpm run test",
249
+ "pnpm run test:framework-conformance"
250
+ ],
251
+ "signals": [
252
+ "Stack",
253
+ "Grid",
254
+ "Card",
255
+ "Container",
256
+ "Prose",
257
+ "Typography"
258
+ ]
259
+ },
260
+ {
261
+ "id": "web-control-visual-size",
262
+ "kind": "breaking",
263
+ "currentContract": "Select, PhoneInput and Segmented use size for visual density; Select also accepts the visual md alias.",
264
+ "replacement": "visualSize in Astro/React and visual-size in Elements use default, sm or lg. Native input/select size remains numeric. Elements Select uses ui-select-field for its frame and ui-select for its native input and trigger.",
265
+ "migration": "Run lumen migrate v4 for recognized literals. Change wrapper, spread and dynamic visual size props manually; map Select md to default. Keep numeric size; PhoneInput forwards it through inputProps.size. Button, icon, container and native-platform sizes are unchanged. Update Elements Select host CSS selectors from ui-select to ui-select-field.",
266
+ "packages": [
267
+ "@santi020k/lumen-core",
268
+ "@santi020k/lumen-astro",
269
+ "@santi020k/lumen-react",
270
+ "@santi020k/lumen-elements"
271
+ ],
272
+ "evidence": [
273
+ "docs/form-controls.md"
274
+ ],
275
+ "docs": [
276
+ "docs/migrating-v3-to-v4.md",
277
+ "docs/form-controls.md"
278
+ ],
279
+ "tests": [
280
+ "pnpm run test",
281
+ "pnpm run test:framework-conformance"
282
+ ],
283
+ "signals": [
284
+ "Select",
285
+ "PhoneInput",
286
+ "Segmented",
287
+ "visualSize",
288
+ "visual-size"
289
+ ]
290
+ },
291
+ {
292
+ "id": "web-form-value-ownership",
293
+ "kind": "breaking",
294
+ "currentContract": "React Segmented does not retain controlled owner state; React Select popup interactions and resets can diverge from native submission. Elements scalar reconnection, checked defaults and multiple selections can diverge from native forms.",
295
+ "replacement": "Controlled values remain owner-held; accepted resets restore defaults silently and cancelled resets retain drafts. Each documented user callback fires once. Elements retain listeners and reset defaults after relocation and submit every enabled selected option.",
296
+ "migration": "Use value/onValueChange or defaultValue deliberately. Listen on Elements hosts and use checked for current state, defaultChecked for the reset baseline. Remove compensating reset or duplicate event handlers after verifying native and external form submission.",
297
+ "packages": [
298
+ "@santi020k/lumen-core",
299
+ "@santi020k/lumen-astro",
300
+ "@santi020k/lumen-react",
301
+ "@santi020k/lumen-elements"
302
+ ],
303
+ "evidence": [
304
+ "docs/form-controls.md"
305
+ ],
306
+ "docs": [
307
+ "docs/form-controls.md",
308
+ "docs/migrating-v3-to-v4.md"
309
+ ],
310
+ "tests": [
311
+ "pnpm run test",
312
+ "pnpm run test:framework-conformance"
313
+ ],
314
+ "signals": [
315
+ "Segmented",
316
+ "Select",
317
+ "NativeSelect",
318
+ "checked",
319
+ "defaultChecked",
320
+ "form.reset"
321
+ ]
322
+ },
323
+ {
324
+ "id": "web-combobox-focus",
325
+ "kind": "breaking",
326
+ "currentContract": "Editable Combobox consumers may assume option buttons receive focus and parent Escape handlers always dismiss.",
327
+ "replacement": "Input focus remains stable with aria-activedescendant; nested controls consume their own Escape.",
328
+ "migration": "Update focus assertions and option styling to active-descendant/selected state. Parent handlers must honor defaultPrevented; Enter without an active option retains native form behavior.",
329
+ "packages": [
330
+ "@santi020k/lumen-core",
331
+ "@santi020k/lumen-astro",
332
+ "@santi020k/lumen-react",
333
+ "@santi020k/lumen-elements"
334
+ ],
335
+ "evidence": [
336
+ "docs/migrating-v3-to-v4.md"
337
+ ],
338
+ "docs": [
339
+ "docs/migrating-v3-to-v4.md"
340
+ ],
341
+ "tests": [
342
+ "pnpm run test",
343
+ "pnpm run test:framework-conformance"
344
+ ],
345
+ "signals": [
346
+ "Combobox",
347
+ "aria-activedescendant",
348
+ "Escape"
349
+ ]
350
+ },
351
+ {
352
+ "id": "web-phone-input-identity",
353
+ "kind": "breaking",
354
+ "currentContract": "Web PhoneInput id may be treated as a frame identifier.",
355
+ "replacement": "Astro/React id identifies the number input that receives focus; Elements retains host id and uses input-id for its input.",
356
+ "migration": "Update labels and DOM queries; use Elements input-id for the input that receives focus. Native phone contracts are covered separately.",
357
+ "packages": [
358
+ "@santi020k/lumen-core",
359
+ "@santi020k/lumen-astro",
360
+ "@santi020k/lumen-react",
361
+ "@santi020k/lumen-elements"
362
+ ],
363
+ "evidence": [
364
+ "docs/migrating-v3-to-v4.md"
365
+ ],
366
+ "docs": [
367
+ "docs/migrating-v3-to-v4.md"
368
+ ],
369
+ "tests": [
370
+ "pnpm run test",
371
+ "pnpm run test:framework-conformance"
372
+ ],
373
+ "signals": [
374
+ "PhoneInput",
375
+ "input-id"
376
+ ]
377
+ },
378
+ {
379
+ "id": "web-virtual-list-ranges",
380
+ "kind": "breaking",
381
+ "currentContract": "Consumers may interpret virtual-list range endpoints as exclusive.",
382
+ "replacement": "Fixed-height windows report inclusive endpoints and endIndex -1 for empty lists. Mounted DOM remains the default; opt-in data rendering mounts visible rows and focused neighbors.",
383
+ "migration": "Update exclusive-end calculations and empty handling. Use stable unique keys and external state for opt-in data rendering; variable-height lists need a different strategy. Existing root imports remain supported; selective component imports are additive.",
384
+ "packages": [
385
+ "@santi020k/lumen-core",
386
+ "@santi020k/lumen-astro",
387
+ "@santi020k/lumen-react",
388
+ "@santi020k/lumen-elements"
389
+ ],
390
+ "evidence": [
391
+ "docs/virtual-list-data.md"
392
+ ],
393
+ "docs": [
394
+ "docs/migrating-v3-to-v4.md",
395
+ "docs/virtual-list-data.md"
396
+ ],
397
+ "tests": [
398
+ "pnpm run test",
399
+ "pnpm run test:framework-conformance"
400
+ ],
401
+ "signals": [
402
+ "VirtualList",
403
+ "endIndex"
404
+ ]
405
+ },
406
+ {
407
+ "id": "web-rich-text-command-ownership",
408
+ "kind": "breaking",
409
+ "currentContract": "External editor integrations may execute commands during completion events or fall back to browser commands after failure.",
410
+ "replacement": "Cancelable ui:editor-command-request owns execution; ui:editor-command reports completion without execution.",
411
+ "migration": "External engines must preventDefault on the request and set detail.executed synchronously; React can supply commandHandler. Remove completion handlers that execute commands again. Failed external commands do not fall back.",
412
+ "packages": [
413
+ "@santi020k/lumen-core",
414
+ "@santi020k/lumen-astro",
415
+ "@santi020k/lumen-react",
416
+ "@santi020k/lumen-elements"
417
+ ],
418
+ "evidence": [
419
+ "docs/migrating-v3-to-v4.md"
420
+ ],
421
+ "docs": [
422
+ "docs/migrating-v3-to-v4.md",
423
+ "docs/ai-usage.md"
424
+ ],
425
+ "tests": [
426
+ "pnpm run test",
427
+ "pnpm run test:framework-conformance"
428
+ ],
429
+ "signals": [
430
+ "ui:editor-command-request",
431
+ "ui:editor-command",
432
+ "commandHandler"
433
+ ]
434
+ }
435
+ ],
436
+ "swiftApiBaseline": "v3.0.1",
437
+ "approval": {
438
+ "approver": "Santiago Molina (santi020k)",
439
+ "date": "2026-10-07",
440
+ "decision": "Publish Lumen 4.0.0 and deploy the coordinated release; deliver playground 1.0.3 for Apple and Android review with current screenshots and listing metadata under the standing authorization, after all checks and reviews pass. Standing authorization is recorded by santi020k in PR #95 comment 6027959606.",
441
+ "reviewedRevision": "cdb28a38aca0071af35021341bb7fbbefd7730a6",
442
+ "evidence": [
443
+ "https://github.com/santi020k/lumen/commit/cdb28a38aca0071af35021341bb7fbbefd7730a6",
444
+ "https://github.com/santi020k/lumen/pull/95"
445
+ ]
446
+ }
447
+ }