@ethlete/core 5.0.0-next.61 → 5.0.0-next.62

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.
@@ -1,7 +1,7 @@
1
1
  import * as ts from 'typescript';
2
2
  import { collectFiles } from './migration-files.js';
3
- const REMOVED_EXPORTS = new Map([
4
- ...['Memo', 'MemoConfig', 'MemoResolver', 'MapLike'].map((name) => [name, 'the @Memo decorator']),
3
+ export const REMOVED_EXPORTS = new Map([
4
+ ...['Memo', 'MemoConfig', 'MemoResolver', 'MapLike'].map((name) => [name, 'together with the @Memo decorator and has no replacement.']),
5
5
  ...[
6
6
  'createProps',
7
7
  'createHostProps',
@@ -29,7 +29,95 @@ const REMOVED_EXPORTS = new Map([
29
29
  'PropHandlers',
30
30
  'BindPropsOptions',
31
31
  'UnbindPropsOptions',
32
- ].map((name) => [name, 'the props module']),
32
+ ].map((name) => [name, 'together with the props module and has no replacement.']),
33
+ ...['LetDirective', 'LetContext'].map((name) => [
34
+ name,
35
+ "in v5. Use Angular's `@let`. `@ethlete/cdk:migrate-to-v5` rewrites `*etLet` templates; without the cdk, rewrite them by hand.",
36
+ ]),
37
+ ...['IsActiveElementDirective', 'IS_ACTIVE_ELEMENT', 'IsElementDirective', 'IS_ELEMENT'].map((name) => [
38
+ name,
39
+ 'in v5. Inside a scrollable, use `ScrollableIsActiveChildDirective`; `@ethlete/cdk:migrate-to-v5` rewrites it.',
40
+ ]),
41
+ ...['ObserveResizeDirective', 'ResizeObserverService', 'ResizeObserverFactory', 'createResizeObservable'].map((name) => [name, 'in v5. Use `signalElementDimensions()`.']),
42
+ ...['ObserveContentDirective', 'ContentObserverService', 'MutationObserverFactory', 'createMutationObservable'].map((name) => [name, 'in v5. Use `signalElementMutations()`.']),
43
+ ...[
44
+ 'ObserveVisibilityDirective',
45
+ 'OBSERVE_VISIBILITY_TOKEN',
46
+ 'ObserveVisibilityChange',
47
+ 'IntersectionObserverService',
48
+ 'IntersectionObserverFactory',
49
+ 'getIntersectionInfo',
50
+ 'signalVisibilityChangeClasses',
51
+ ].map((name) => [name, 'in v5. Use `signalElementIntersection()`.']),
52
+ ...[
53
+ 'ObserveScrollStateDirective',
54
+ 'OBSERVE_SCROLL_STATE',
55
+ 'ScrollObserverFirstElementDirective',
56
+ 'ScrollObserverLastElementDirective',
57
+ 'ScrollObserverIgnoreTargetDirective',
58
+ 'SCROLL_OBSERVER_FIRST_ELEMENT_CLASS',
59
+ 'SCROLL_OBSERVER_IGNORE_TARGET_CLASS',
60
+ 'SCROLL_OBSERVER_LAST_ELEMENT_CLASS',
61
+ 'SCROLL_OBSERVER_OBSERVING_FIRST_ELEMENT_CLASS',
62
+ 'SCROLL_OBSERVER_OBSERVING_LAST_ELEMENT_CLASS',
63
+ 'ScrollObserverScrollState',
64
+ 'ObservedScrollableChild',
65
+ 'areScrollStatesEqual',
66
+ ].map((name) => [
67
+ name,
68
+ 'in v5. Use `signalElementScrollState()`, or `ScrollableScrollState` of the `@ethlete/components` scrollable.',
69
+ ]),
70
+ ...['CursorDragScrollDirective', 'CURSOR_DRAG_SCROLLING_CLASS', 'CURSOR_DRAG_SCROLLING_PREPARED_CLASS'].map((name) => [name, 'in v5. Use `useCursorDragScroll()`.']),
71
+ ...['RootBoundaryDirective', 'ROOT_BOUNDARY_TOKEN'].map((name) => [name, 'in v5. Use `provideBoundaryElement()`.']),
72
+ ...['DelayableDirective', 'DELAYABLE_TOKEN'].map((name) => [name, 'in v5. Use `provideInfinityQueryResponseDelay()` from `@ethlete/query`.']),
73
+ ...[
74
+ 'SeoDirective',
75
+ 'SEO_DIRECTIVE_TOKEN',
76
+ 'SeoConfig',
77
+ 'mergeSeoConfig',
78
+ 'OpenGraph',
79
+ 'TwitterCard',
80
+ 'FacebookCard',
81
+ 'AlternateLink',
82
+ ].map((name) => [name, 'in v5. Use the `apply*Binding` functions; the SEO guide has a per-key migration table.']),
83
+ ...['AnimatedOverlayDirective', 'AnimatedOverlayComponentBase'].map((name) => [
84
+ name,
85
+ 'in v5. It moved to `@ethlete/cdk`; `@ethlete/components` overlays use the overlay strategy controller.',
86
+ ]),
87
+ ...[
88
+ 'SelectionModel',
89
+ 'ActiveSelectionModel',
90
+ 'SelectionModelBinding',
91
+ 'SelectionModelOptionValueFn',
92
+ 'SelectionModelPropertyPath',
93
+ 'SelectionModelTypes',
94
+ ].map((name) => [name, 'in v5. It moved into the `@ethlete/cdk` select and has no public replacement.']),
95
+ ...['FocusVisibleService'].map((name) => [name, 'in v5. Use `injectFocusVisibleTracker()`.']),
96
+ ...['createMediaQueryObservable'].map((name) => [name, 'in v5. Use `injectBreakpointIsMatched()` or the other media query signals.']),
97
+ ...['createReactiveBindings', 'ReactiveAttributes', 'ReactiveBindingResult'].map((name) => [name, 'in v5. Use `signalHostClasses()` / `signalHostAttributes()`.']),
98
+ ...['debouncedControlValueSignal', 'DebouncedControlValueSignalOptions'].map((name) => [name, 'in v5. Debounce the `controlValueSignal()` value with `toObservable()` and `debounceTime()`.']),
99
+ ...['ProviderResult', 'RootProviderResult', 'StaticProviderResult', 'CreateProviderOptions'].map((name) => [
100
+ name,
101
+ 'in v5. It belonged to the removed `create*Provider` factories, which `@ethlete/core:migrate-provider-shape` rewrites.',
102
+ ]),
103
+ ...['VIEWPORT_CONFIG'].map((name) => [name, 'in v5. Use `provideViewportConfig()`.']),
104
+ ...[
105
+ 'ClickObserverService',
106
+ 'ClickObserverFactory',
107
+ 'DebugDirective',
108
+ 'DEBUG_TOKEN',
109
+ 'HostDirective',
110
+ 'MaybeObservable',
111
+ 'Primitive',
112
+ 'Reference',
113
+ 'Size',
114
+ 'Validators',
115
+ 'isEmptyArray',
116
+ 'isObjectArray',
117
+ 'isPrimitiveArray',
118
+ 'ScrollEnhancementsConfig',
119
+ 'SmartBlockScrollStrategy',
120
+ ].map((name) => [name, 'in v5. It has no replacement.']),
33
121
  ]);
34
122
  const ET_PROPS_ATTRIBUTE = /\betProps\b/;
35
123
  export default async function reportRemovedExports(tree, scope) {
@@ -57,9 +145,9 @@ function findRemovedImports(tree, filePath) {
57
145
  continue;
58
146
  for (const element of bindings.elements) {
59
147
  const name = (element.propertyName ?? element.name).text;
60
- const origin = REMOVED_EXPORTS.get(name);
61
- if (origin) {
62
- messages.push(`${name} was removed from @ethlete/core together with ${origin} and has no replacement.`);
148
+ const successor = REMOVED_EXPORTS.get(name);
149
+ if (successor) {
150
+ messages.push(`${name} was removed from @ethlete/core ${successor}`);
63
151
  }
64
152
  }
65
153
  }
@@ -0,0 +1,38 @@
1
+ # Move the runtime color theming to Tailwind 4
2
+
3
+ `provideColorThemes()` injects the color theme CSS at runtime and pairs with a Tailwind 3 config built from
4
+ `createTailwindColorThemes()`. It is deprecated: `@ethlete/components` expects
5
+ `provideColorThemesWithTailwind4()`, the CSS the Tailwind 4 generators emit, and a set of surface themes.
6
+
7
+ The theme data carries over unchanged. A codemod does the mechanical part; the rest is setup that depends
8
+ on the app.
9
+
10
+ ## What to change
11
+
12
+ 1. Run the codemod:
13
+
14
+ ```bash
15
+ nx g @ethlete/core:migrate-legacy-color-themes
16
+ ```
17
+
18
+ It rewrites every `provideColorThemes(X)` imported from `@ethlete/core` into
19
+ `provideColorThemesWithTailwind4(X)`, fixes the import, and writes
20
+ `legacy-color-themes-migration-tasks.md` at the workspace root. Pass `--projects` or `--include` to
21
+ migrate one app at a time.
22
+
23
+ 2. Work through `legacy-color-themes-migration-tasks.md`. It lists, per call site, the
24
+ `tailwind-4-color-theme` generator run that replaces the runtime styles, every Tailwind 3 helper left
25
+ in a config, and - when no app provides any yet - the surface themes to build.
26
+
27
+ 3. Move the Tailwind 3 config to Tailwind 4, run both generators, and import the generated `.css` in each
28
+ app's global stylesheet. Keep the prefix the Tailwind 3 config used, so the utility names stay.
29
+
30
+ 4. Derive the first surface themes from the app's existing page background, text, muted text and border
31
+ colors. Ask the user before inventing colors the app does not have.
32
+
33
+ 5. Search the app's own CSS for `--et-color-alt-`. Those variables are not emitted any more; move the
34
+ region into its own `etProvideColor` scope and read `--et-color-primary` there.
35
+
36
+ 6. Build the app and compare a page against the old one: the colors must match.
37
+
38
+ The guide is at <https://ethlete-sdk-docs.web.app/core/theming#migrating-from-runtime-theming>.
@@ -9,7 +9,8 @@ function call. Both are decisions about the call site.
9
9
 
10
10
  ## What to change
11
11
 
12
- 1. Find every component that injects `SeoDirective` or lists it in `hostDirectives` or `imports`.
12
+ 1. Find every component that injects `SeoDirective` or `SEO_DIRECTIVE_TOKEN`, or lists the directive in
13
+ `hostDirectives` or `imports`.
13
14
  2. Remove the directive from the component.
14
15
  3. Replace the `updateConfig({ … })` call with one `apply*Binding` call per key it set.
15
16
  4. Turn an Observable value into a signal: `toSignal()` at the edge of the component, or a
package/migrations.json CHANGED
@@ -4,6 +4,7 @@
4
4
  "name": "to-v5",
5
5
  "version": "5.0.0-beta.11",
6
6
  "kind": "auto",
7
+ "level": "required",
7
8
  "description": "Rewrite the v4 core API into its v5 shape.",
8
9
  "generator": "@ethlete/core:migrate-to-v5"
9
10
  },
@@ -11,6 +12,7 @@
11
12
  "name": "provider-shape",
12
13
  "version": "5.0.0-next.37",
13
14
  "kind": "auto",
15
+ "level": "required",
14
16
  "description": "Rewrite destructured provider tuples into the tree-shakeable definition shape.",
15
17
  "generator": "@ethlete/core:migrate-provider-shape",
16
18
  "docs": "/core/providers"
@@ -19,6 +21,7 @@
19
21
  "name": "seo-directive-removed",
20
22
  "version": "5.0.0-next.41",
21
23
  "kind": "assisted",
24
+ "level": "required",
22
25
  "description": "SeoDirective and SeoConfig are gone. Every call site moves to the apply*Binding function for its key.",
23
26
  "instructions": "./migrations/seo-directive-removed.md",
24
27
  "docs": "/core/seo"
@@ -27,6 +30,7 @@
27
30
  "name": "surface-interaction-swatch",
28
31
  "version": "5.0.0-next.46",
29
32
  "kind": "auto",
33
+ "level": "required",
30
34
  "description": "Rewrite surface theme interactionColor maps into the { color, onColor, inkColor } swatch shape.",
31
35
  "generator": "@ethlete/core:migrate-surface-interaction-swatch",
32
36
  "docs": "/core/theming"
@@ -35,9 +39,20 @@
35
39
  "name": "surface-theme-regenerate",
36
40
  "version": "5.0.0-next.46",
37
41
  "kind": "manual",
42
+ "level": "required",
38
43
  "description": "Regenerate the surface theme stylesheet, so the new swatch reaches the CSS variables.",
39
44
  "instructions": "./migrations/surface-theme-regenerate.md",
40
45
  "docs": "/core/theming"
46
+ },
47
+ {
48
+ "name": "legacy-color-themes",
49
+ "version": "5.0.0-next.62",
50
+ "kind": "assisted",
51
+ "level": "recommended",
52
+ "description": "Move the runtime color theming to Tailwind 4: provideColorThemes becomes provideColorThemesWithTailwind4, and the generated CSS and surface themes replace the runtime styles.",
53
+ "scan": "@ethlete/core:migrate-legacy-color-themes",
54
+ "instructions": "./migrations/legacy-color-themes.md",
55
+ "docs": "/core/theming#migrating-from-runtime-theming"
41
56
  }
42
57
  ]
43
58
  }
package/package.json CHANGED
@@ -1,20 +1,20 @@
1
1
  {
2
2
  "name": "@ethlete/core",
3
- "version": "5.0.0-next.61",
3
+ "version": "5.0.0-next.62",
4
4
  "license": "MIT",
5
5
  "sideEffects": false,
6
6
  "peerDependencies": {
7
- "@angular/common": "22.1.6",
8
- "@angular/core": "22.1.6",
9
- "@angular/forms": "22.1.6",
10
- "@angular/platform-browser": "22.1.6",
11
- "@angular/router": "22.1.6",
7
+ "@angular/common": "^22.1.0",
8
+ "@angular/core": "^22.1.0",
9
+ "@angular/forms": "^22.1.0",
10
+ "@angular/platform-browser": "^22.1.0",
11
+ "@angular/router": "^22.1.0",
12
12
  "@ethlete/types": "^2.0.0-beta.4",
13
- "@floating-ui/dom": "1.8.0",
14
- "@nx/devkit": "23.1.0",
15
- "rxjs": "7.8.2",
16
- "ts-morph": "21.0.1",
17
- "typescript": "6.0.3"
13
+ "@floating-ui/dom": "^1.6.0",
14
+ "@nx/devkit": "^23.0.0",
15
+ "rxjs": "^7.8.0",
16
+ "ts-morph": "^21.0.0",
17
+ "typescript": "^6.0.0"
18
18
  },
19
19
  "peerDependenciesMeta": {
20
20
  "@nx/devkit": {