@studiometa/js-toolkit 4.0.0-alpha.1 → 4.0.0-alpha.2
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/README.md +10 -0
- package/package.json +5 -2
- package/skills/studiometa-js-toolkit/SKILL.md +87 -0
- package/skills/studiometa-js-toolkit/references/api/configuration.md +169 -0
- package/skills/studiometa-js-toolkit/references/api/context/createContext.md +46 -0
- package/skills/studiometa-js-toolkit/references/api/context/createGroup.md +67 -0
- package/skills/studiometa-js-toolkit/references/api/context/index.md +69 -0
- package/skills/studiometa-js-toolkit/references/api/context/injectContext.md +58 -0
- package/skills/studiometa-js-toolkit/references/api/context/injectContextSync.md +44 -0
- package/skills/studiometa-js-toolkit/references/api/context/provideContext.md +61 -0
- package/skills/studiometa-js-toolkit/references/api/context/provideRootContext.md +42 -0
- package/skills/studiometa-js-toolkit/references/api/context/signal.md +85 -0
- package/skills/studiometa-js-toolkit/references/api/context/subscribeContext.md +71 -0
- package/skills/studiometa-js-toolkit/references/api/decorators/children.md +92 -0
- package/skills/studiometa-js-toolkit/references/api/decorators/component.md +75 -0
- package/skills/studiometa-js-toolkit/references/api/decorators/index.md +41 -0
- package/skills/studiometa-js-toolkit/references/api/decorators/inject.md +73 -0
- package/skills/studiometa-js-toolkit/references/api/decorators/on.md +149 -0
- package/skills/studiometa-js-toolkit/references/api/decorators/provide.md +77 -0
- package/skills/studiometa-js-toolkit/references/api/decorators/read-write.md +93 -0
- package/skills/studiometa-js-toolkit/references/api/diagnostics/DIAGNOSTICS.md +137 -0
- package/skills/studiometa-js-toolkit/references/api/diagnostics/EVENTS.md +45 -0
- package/skills/studiometa-js-toolkit/references/api/diagnostics/index.md +58 -0
- package/skills/studiometa-js-toolkit/references/api/diagnostics/reportDiagnostic.md +67 -0
- package/skills/studiometa-js-toolkit/references/api/diagnostics/warn.md +54 -0
- package/skills/studiometa-js-toolkit/references/api/dom/breakpoints.md +81 -0
- package/skills/studiometa-js-toolkit/references/api/dom/domUpdate.md +70 -0
- package/skills/studiometa-js-toolkit/references/api/dom/emitExtendable.md +68 -0
- package/skills/studiometa-js-toolkit/references/api/dom/index.md +26 -0
- package/skills/studiometa-js-toolkit/references/api/dom/swap.md +105 -0
- package/skills/studiometa-js-toolkit/references/api/dom/watchAttributeNamespace.md +96 -0
- package/skills/studiometa-js-toolkit/references/api/dom/watchAttributes.md +56 -0
- package/skills/studiometa-js-toolkit/references/api/dom/whenDOMSettled.md +41 -0
- package/skills/studiometa-js-toolkit/references/api/html/data-component.md +105 -0
- package/skills/studiometa-js-toolkit/references/api/html/data-mount.md +69 -0
- package/skills/studiometa-js-toolkit/references/api/html/data-option.md +106 -0
- package/skills/studiometa-js-toolkit/references/api/html/data-ref.md +63 -0
- package/skills/studiometa-js-toolkit/references/api/html/index.md +32 -0
- package/skills/studiometa-js-toolkit/references/api/index.md +73 -0
- package/skills/studiometa-js-toolkit/references/api/instance-events.md +75 -0
- package/skills/studiometa-js-toolkit/references/api/instance-methods.md +267 -0
- package/skills/studiometa-js-toolkit/references/api/instance-properties.md +90 -0
- package/skills/studiometa-js-toolkit/references/api/methods-hooks-events.md +149 -0
- package/skills/studiometa-js-toolkit/references/api/methods-hooks-lifecycle.md +90 -0
- package/skills/studiometa-js-toolkit/references/api/methods-hooks-options.md +96 -0
- package/skills/studiometa-js-toolkit/references/api/methods-hooks-services.md +164 -0
- package/skills/studiometa-js-toolkit/references/api/registry/defineManifest.md +57 -0
- package/skills/studiometa-js-toolkit/references/api/registry/fromMetaGlob.md +33 -0
- package/skills/studiometa-js-toolkit/references/api/registry/fromWebpackContext.md +37 -0
- package/skills/studiometa-js-toolkit/references/api/registry/getInstance.md +52 -0
- package/skills/studiometa-js-toolkit/references/api/registry/getInstances.md +48 -0
- package/skills/studiometa-js-toolkit/references/api/registry/getMountedInstances.md +39 -0
- package/skills/studiometa-js-toolkit/references/api/registry/getUnmountedInstances.md +46 -0
- package/skills/studiometa-js-toolkit/references/api/registry/index.md +49 -0
- package/skills/studiometa-js-toolkit/references/api/registry/registerComponent.md +93 -0
- package/skills/studiometa-js-toolkit/references/api/registry/registerComponents.md +37 -0
- package/skills/studiometa-js-toolkit/references/api/registry/registerManifest.md +72 -0
- package/skills/studiometa-js-toolkit/references/api/scheduler/defaultScheduler.md +104 -0
- package/skills/studiometa-js-toolkit/references/api/scheduler/index.md +27 -0
- package/skills/studiometa-js-toolkit/references/api/scheduler/nextFrame.md +31 -0
- package/skills/studiometa-js-toolkit/references/api/scheduler/viewTransition.md +53 -0
- package/skills/studiometa-js-toolkit/references/api/services/createService.md +95 -0
- package/skills/studiometa-js-toolkit/references/api/services/createServiceMixin.md +81 -0
- package/skills/studiometa-js-toolkit/references/api/services/index.md +94 -0
- package/skills/studiometa-js-toolkit/references/api/services/mixins.md +148 -0
- package/skills/studiometa-js-toolkit/references/api/services/perTarget.md +65 -0
- package/skills/studiometa-js-toolkit/references/api/services/toggle.md +80 -0
- package/skills/studiometa-js-toolkit/references/api/services/until.md +44 -0
- package/skills/studiometa-js-toolkit/references/api/services/useBreakpoint.md +42 -0
- package/skills/studiometa-js-toolkit/references/api/services/useDrag.md +119 -0
- package/skills/studiometa-js-toolkit/references/api/services/useInView.md +64 -0
- package/skills/studiometa-js-toolkit/references/api/services/useKey.md +105 -0
- package/skills/studiometa-js-toolkit/references/api/services/useMediaQuery.md +45 -0
- package/skills/studiometa-js-toolkit/references/api/services/useMutation.md +69 -0
- package/skills/studiometa-js-toolkit/references/api/services/usePointer.md +91 -0
- package/skills/studiometa-js-toolkit/references/api/services/usePrefersReducedMotion.md +42 -0
- package/skills/studiometa-js-toolkit/references/api/services/useRaf.md +91 -0
- package/skills/studiometa-js-toolkit/references/api/services/useResize.md +60 -0
- package/skills/studiometa-js-toolkit/references/api/services/useScroll.md +88 -0
- package/skills/studiometa-js-toolkit/references/api/services/useScrollProgress.md +88 -0
- package/skills/studiometa-js-toolkit/references/api/services/useWindowScroll.md +25 -0
- package/skills/studiometa-js-toolkit/references/api/services/useWindowSize.md +25 -0
- package/skills/studiometa-js-toolkit/references/api/storage/createStorage.md +126 -0
- package/skills/studiometa-js-toolkit/references/api/storage/index.md +33 -0
- package/skills/studiometa-js-toolkit/references/api/storage/presets.md +58 -0
- package/skills/studiometa-js-toolkit/references/api/storage/providers.md +109 -0
- package/skills/studiometa-js-toolkit/references/api/test/index.md +214 -0
- package/skills/studiometa-js-toolkit/references/guide/concepts/attribute-grammar.md +93 -0
- package/skills/studiometa-js-toolkit/references/guide/concepts/mutation-engine.md +71 -0
- package/skills/studiometa-js-toolkit/references/guide/concepts/philosophy.md +78 -0
- package/skills/studiometa-js-toolkit/references/guide/concepts/the-registry.md +110 -0
- package/skills/studiometa-js-toolkit/references/guide/going-further/autoloading.md +104 -0
- package/skills/studiometa-js-toolkit/references/guide/going-further/handling-diagnostics.md +104 -0
- package/skills/studiometa-js-toolkit/references/guide/going-further/mount-strategies.md +95 -0
- package/skills/studiometa-js-toolkit/references/guide/going-further/scheduling-work.md +124 -0
- package/skills/studiometa-js-toolkit/references/guide/going-further/sharing-state.md +218 -0
- package/skills/studiometa-js-toolkit/references/guide/going-further/swapping-content.md +92 -0
- package/skills/studiometa-js-toolkit/references/guide/going-further/testing-components.md +137 -0
- package/skills/studiometa-js-toolkit/references/guide/going-further/typing-components.md +190 -0
- package/skills/studiometa-js-toolkit/references/guide/going-further/using-decorators.md +168 -0
- package/skills/studiometa-js-toolkit/references/guide/going-further/using-storage.md +125 -0
- package/skills/studiometa-js-toolkit/references/guide/index.md +163 -0
- package/skills/studiometa-js-toolkit/references/guide/introduction/installation.md +144 -0
- package/skills/studiometa-js-toolkit/references/guide/introduction/lifecycle-hooks.md +174 -0
- package/skills/studiometa-js-toolkit/references/guide/introduction/managing-components.md +229 -0
- package/skills/studiometa-js-toolkit/references/guide/introduction/managing-options.md +235 -0
- package/skills/studiometa-js-toolkit/references/guide/introduction/managing-refs.md +174 -0
- package/skills/studiometa-js-toolkit/references/guide/introduction/using-services.md +218 -0
- package/skills/studiometa-js-toolkit/references/guide/introduction/working-with-events.md +251 -0
- package/skills/studiometa-js-toolkit/references/guide/migration/v3-to-v4.md +373 -0
- package/skills/studiometa-js-toolkit/references/utils/css.md +98 -0
- package/skills/studiometa-js-toolkit/references/utils/dom.md +54 -0
- package/skills/studiometa-js-toolkit/references/utils/easings.md +217 -0
- package/skills/studiometa-js-toolkit/references/utils/focus.md +84 -0
- package/skills/studiometa-js-toolkit/references/utils/history.md +69 -0
- package/skills/studiometa-js-toolkit/references/utils/index.md +53 -0
- package/skills/studiometa-js-toolkit/references/utils/is.md +84 -0
- package/skills/studiometa-js-toolkit/references/utils/load.md +59 -0
- package/skills/studiometa-js-toolkit/references/utils/math.md +129 -0
- package/skills/studiometa-js-toolkit/references/utils/motion.md +218 -0
- package/skills/studiometa-js-toolkit/references/utils/objects.md +68 -0
- package/skills/studiometa-js-toolkit/references/utils/scroll.md +128 -0
- package/skills/studiometa-js-toolkit/references/utils/strings.md +176 -0
- package/skills/studiometa-js-toolkit/references/utils/timing.md +111 -0
- package/skills/studiometa-js-toolkit/references/utils/transitions.md +122 -0
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
# Migrating from v3 to v4
|
|
2
|
+
|
|
3
|
+
v4 is a full breaking major. There is no bridge release and no compatibility layer: `@studiometa/js-toolkit` 4.0 and `@studiometa/ui` 2.0 ship together.
|
|
4
|
+
|
|
5
|
+
Migration help is tooling, not runtime shims. Lint rules flag `$children`, `$parent`, `updated()` and the old handler signatures, and codemods cover mechanical renames only.
|
|
6
|
+
|
|
7
|
+
## The component tree
|
|
8
|
+
|
|
9
|
+
### `$parent`, `$children` and `$root` are removed
|
|
10
|
+
|
|
11
|
+
Parent and child are DOM ancestry, never ownership, so nothing holds a reference in either direction.
|
|
12
|
+
|
|
13
|
+
```js
|
|
14
|
+
this.$children.SliderItem; // [!code --]
|
|
15
|
+
this.$query('SliderItem'); // [!code ++]
|
|
16
|
+
|
|
17
|
+
this.$parent.goTo(index); // [!code --]
|
|
18
|
+
this.$closest('Slider')?.goTo(index); // [!code ++]
|
|
19
|
+
|
|
20
|
+
this.$root.doSomething(); // [!code --]
|
|
21
|
+
this.$closest('App')?.doSomething(); // [!code ++]
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`$query(name)` returns a flat `Base[]` of all matching descendants, at any depth — not the keyed object `$children` was. `$closest(name)` is resolved on every access and returns `Base | null`, so guard it and never dereference it unguarded in `mounted()`.
|
|
25
|
+
|
|
26
|
+
Better than either: a parent watches its children, and a child emits.
|
|
27
|
+
|
|
28
|
+
```js
|
|
29
|
+
items = this.$watchChildren('SliderItem'); // [!code ++]
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### `createApp()` is removed
|
|
33
|
+
|
|
34
|
+
There is no root component and no application object.
|
|
35
|
+
|
|
36
|
+
```js
|
|
37
|
+
createApp(App); // [!code --]
|
|
38
|
+
registerComponents(Accordion, Slider, TodoList); // [!code ++]
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
A component is registered, not mounted by a parent, so nothing has to own the page.
|
|
42
|
+
|
|
43
|
+
### `ChildrenManager` is gone
|
|
44
|
+
|
|
45
|
+
A nested `data-component` is discovered by the registry on its own. `config.components` still exists, but it now declares a **family** — it registers those names and supplies the name set that `on<Child><Event>` resolution needs. It does not construct anything.
|
|
46
|
+
|
|
47
|
+
Unmounting a parent no longer unmounts its children.
|
|
48
|
+
|
|
49
|
+
## Refs
|
|
50
|
+
|
|
51
|
+
### `$update()` is removed
|
|
52
|
+
|
|
53
|
+
Refs are live: each `$refs` property reads the DOM on access.
|
|
54
|
+
|
|
55
|
+
```js
|
|
56
|
+
this.$refs.list.append(li);
|
|
57
|
+
this.$update(); // [!code --]
|
|
58
|
+
console.log(this.$refs.items.length); // already correct
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### A list ref keeps the `[]` in the attribute
|
|
62
|
+
|
|
63
|
+
```html
|
|
64
|
+
<li data-ref="items"></li>
|
|
65
|
+
<!-- [!code --] -->
|
|
66
|
+
<li data-ref="items[]"></li>
|
|
67
|
+
<!-- [!code ++] -->
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
`config.refs: ['items[]']` matches `data-ref="items[]"` **and nothing else**. The mismatch gives a `ref.mismatch` warning naming both spellings.
|
|
71
|
+
|
|
72
|
+
The property name never carries the suffix: `$refs.items`, `onItemsClick`, `@on('items[]', 'click')`.
|
|
73
|
+
|
|
74
|
+
## Options
|
|
75
|
+
|
|
76
|
+
### `$options` is read-only
|
|
77
|
+
|
|
78
|
+
Every property is a getter with no setter, so an assignment throws.
|
|
79
|
+
|
|
80
|
+
```js
|
|
81
|
+
this.$options.open = true; // [!code --]
|
|
82
|
+
this.$el.setAttribute('data-option-open', ''); // [!code ++]
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Or keep a private field, when the value was never an input:
|
|
86
|
+
|
|
87
|
+
```js
|
|
88
|
+
#isOpen = this.$options.open; // [!code ++]
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### A boolean option reads presence
|
|
92
|
+
|
|
93
|
+
The attribute's value is never read.
|
|
94
|
+
|
|
95
|
+
```html
|
|
96
|
+
<div data-option-open="false"></div>
|
|
97
|
+
<!-- v3: false · v4: true -->
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Turn one off by removing the attribute, or — for an option declared `default: true` — with the negated spelling:
|
|
101
|
+
|
|
102
|
+
```html
|
|
103
|
+
<div data-component="Dialog" data-option-no-trap-focus></div>
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Templates must write the attribute conditionally rather than interpolate a boolean into it.
|
|
107
|
+
|
|
108
|
+
### Non-primitive defaults must be factories
|
|
109
|
+
|
|
110
|
+
```js
|
|
111
|
+
options: {
|
|
112
|
+
tween: { type: Object, default: { ease: 'linear' } }, // [!code --]
|
|
113
|
+
tween: { type: Object, default: () => ({ ease: 'linear' }) }, // [!code ++]
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
A literal gives an `option.literal-default` warning, and the value is then shared between instances.
|
|
118
|
+
|
|
119
|
+
### Responsive options lose the list syntax
|
|
120
|
+
|
|
121
|
+
Every option is responsive with nothing to declare. `withResponsiveOptions` is gone, and so is the set spelling.
|
|
122
|
+
|
|
123
|
+
```html
|
|
124
|
+
<div data-option-columns:xs:s="2"></div>
|
|
125
|
+
<!-- [!code --] -->
|
|
126
|
+
<div data-option-columns:xs="2"></div>
|
|
127
|
+
<!-- [!code ++] -->
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
A suffix names **one** breakpoint and cascades upwards. An unknown suffix warns once per mount.
|
|
131
|
+
|
|
132
|
+
### `config.emits` is a type now
|
|
133
|
+
|
|
134
|
+
```js
|
|
135
|
+
static config = { name: 'Slider', emits: ['goto'] }; // [!code --]
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
```ts
|
|
139
|
+
class Slider extends Base<{ $emits: { goto: { index: number } } }> {} // [!code ++]
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Nothing of it stays in the bundle.
|
|
143
|
+
|
|
144
|
+
## Events
|
|
145
|
+
|
|
146
|
+
### `$emit()` takes one payload object
|
|
147
|
+
|
|
148
|
+
```js
|
|
149
|
+
this.$emit('slide', 1, 'left'); // [!code --]
|
|
150
|
+
this.$emit('slide', { index: 1, direction: 'left' }); // [!code ++]
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
`detail` **is** that object, and an omitted payload leaves `detail` at the platform value `null`. A value that is not an object is refused by the type and reported as `event.invalid-emit-payload`.
|
|
154
|
+
|
|
155
|
+
### Handler payloads are one object
|
|
156
|
+
|
|
157
|
+
```js
|
|
158
|
+
onSliderItemClick(event, index) {} // [!code --]
|
|
159
|
+
onSliderItemClick({ event, target, index }) {} // [!code ++]
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
- a ref handler receives `{ event, target, index }`, where `target` is the **ref element**, not `event.target`;
|
|
163
|
+
- a child handler receives `{ event, target, payload }`, where `target` is the **instance**;
|
|
164
|
+
- a global handler receives `{ event, target }`, with no `payload` and no `index`.
|
|
165
|
+
|
|
166
|
+
### `onWindow<Event>` and `onDocument<Event>` are reserved prefixes
|
|
167
|
+
|
|
168
|
+
They match before children and refs. To reach a child named `Window`, use `@on('Window', 'resize')`.
|
|
169
|
+
|
|
170
|
+
## Lifecycle
|
|
171
|
+
|
|
172
|
+
### `updated()` is removed
|
|
173
|
+
|
|
174
|
+
There is no third lifecycle notion. Use [`option<Name>Changed()`](../introduction/managing-options.md#live-effects) for an option that chooses a resource, and [`watchAttributes()`](../../api/dom/watchAttributes.md) for an attribute the framework does not read.
|
|
175
|
+
|
|
176
|
+
### `mounted()` can return its cleanup
|
|
177
|
+
|
|
178
|
+
```js
|
|
179
|
+
mounted() {
|
|
180
|
+
this.unsubscribe = useScroll().subscribe(this.onScroll); // [!code --]
|
|
181
|
+
return useScroll().subscribe(this.onScroll); // [!code ++]
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
unmounted() {
|
|
185
|
+
this.unsubscribe(); // [!code --]
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Sync or async, a function or an array of functions. An async `mounted()` that resolves after the unmount runs its cleanup immediately.
|
|
190
|
+
|
|
191
|
+
### `terminated` and the permanent state are gone
|
|
192
|
+
|
|
193
|
+
`$unmount()` leaves the instance on its element, so "do this once per element" is a plain field:
|
|
194
|
+
|
|
195
|
+
```js
|
|
196
|
+
mounted() {
|
|
197
|
+
if (this.hasLoaded) return;
|
|
198
|
+
…
|
|
199
|
+
this.hasLoaded = true;
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Loading and mounting
|
|
204
|
+
|
|
205
|
+
### `data-load` becomes `data-mount`
|
|
206
|
+
|
|
207
|
+
Deferring the import and deferring the mount are one decision.
|
|
208
|
+
|
|
209
|
+
```html
|
|
210
|
+
<div data-component="Map" data-load="visible"></div>
|
|
211
|
+
<!-- [!code --] -->
|
|
212
|
+
<div data-component="Map" data-mount="visible"></div>
|
|
213
|
+
<!-- [!code ++] -->
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### The `withMountWhen*` decorators are deleted
|
|
217
|
+
|
|
218
|
+
| v3 | v4 |
|
|
219
|
+
| --------------------------------------------------- | ------------------------------------------------------------ |
|
|
220
|
+
| `withMountWhenInView(Base)` | `data-mount="visible"` or `config.mountStrategy` |
|
|
221
|
+
| `withMountOnMediaQuery(Base, '(min-width: 48rem)')` | `data-mount="media:(min-width: 48rem)"` |
|
|
222
|
+
| `withMountWhenPrefersMotion(Base)` | `data-mount="media:(prefers-reduced-motion: no-preference)"` |
|
|
223
|
+
|
|
224
|
+
A strategy constructs nothing; it decides when the registry calls the mount and unmount hooks. See [Mount strategies](../going-further/mount-strategies.md).
|
|
225
|
+
|
|
226
|
+
### The lazy import helpers are replaced by the manifest
|
|
227
|
+
|
|
228
|
+
`importWhenVisible`, `importWhenIdle`, `importOnInteraction`, `importOnMediaQuery` and `importWhenPrefersMotion` are gone. One entry carries both halves:
|
|
229
|
+
|
|
230
|
+
```js
|
|
231
|
+
registerManifest({
|
|
232
|
+
Map: { load: () => import('./Map.js'), mountStrategy: 'visible' },
|
|
233
|
+
});
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
`readEagerTokens` and `<meta name="js-toolkit:eager">` are not ported — `data-mount` on the element says the same thing.
|
|
237
|
+
|
|
238
|
+
### `<tk-name>` and arbitrary selectors are removed
|
|
239
|
+
|
|
240
|
+
Only plain and configured scoped `data-component` declarations are discovered. `data-component` still works on native elements.
|
|
241
|
+
|
|
242
|
+
## Configuration and composition
|
|
243
|
+
|
|
244
|
+
### `withExtraConfig()` is removed
|
|
245
|
+
|
|
246
|
+
`$config` merges along the prototype chain, so declare a class:
|
|
247
|
+
|
|
248
|
+
```js
|
|
249
|
+
const Compact = withExtraConfig(Vendor, { options: { compact: Boolean } }); // [!code --]
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
```js
|
|
253
|
+
registerComponent(
|
|
254
|
+
// [!code ++]
|
|
255
|
+
class extends Vendor {
|
|
256
|
+
// [!code ++]
|
|
257
|
+
static config = { name: 'CompactVendor', options: { compact: Boolean } }; // [!code ++]
|
|
258
|
+
}, // [!code ++]
|
|
259
|
+
); // [!code ++]
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
`refs`, `options` and `components` merge; scalar keys stay overridable by the most derived class.
|
|
263
|
+
|
|
264
|
+
### `withGroup` is removed
|
|
265
|
+
|
|
266
|
+
Use `provideRootContext()` for page state, and `createGroup()` with provide/inject for a scoped set of peers. See [Shared state](../going-further/sharing-state.md).
|
|
267
|
+
|
|
268
|
+
### `defineFeatures()` is removed
|
|
269
|
+
|
|
270
|
+
Breakpoints are set with `setBreakpoints()`. The attribute names and the prefix are not configurable.
|
|
271
|
+
|
|
272
|
+
## Services
|
|
273
|
+
|
|
274
|
+
### `LoadService` is not ported
|
|
275
|
+
|
|
276
|
+
### Props are flat
|
|
277
|
+
|
|
278
|
+
The grouped objects are gone, and so are the derived fields.
|
|
279
|
+
|
|
280
|
+
```js
|
|
281
|
+
scrolled({ y, changed, direction, max, progress }) {} // [!code --]
|
|
282
|
+
scrolled({ y, deltaY, maxY, progressY, directionY, isScrolling }) {} // [!code ++]
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
- `lastX` is `x - deltaX`; `changedX` is `deltaX !== 0`.
|
|
286
|
+
- `directionX` and `directionY` are `-1 | 0 | 1`, one signed value that multiplies.
|
|
287
|
+
- `ResizeService` keeps `width`, `height`, `ratio` and `orientation`, and drops `breakpoints` and `activeBreakpoints`.
|
|
288
|
+
- `DragService` drops `isGrabbing`, `hasInertia`, `target` and `props.MODES`, fixes the `dragTreshold` spelling, and gains an `idle` mode.
|
|
289
|
+
- `PointerService` uses pointer events only and follows one `pointerId` at a time.
|
|
290
|
+
- **Every prop field is `readonly`, and the props object belongs to its service.** Use `{ ...props }` to keep one.
|
|
291
|
+
|
|
292
|
+
### Services are scoped to a target
|
|
293
|
+
|
|
294
|
+
```js
|
|
295
|
+
useScroll(); // the document element
|
|
296
|
+
useWindowScroll(); // the same, named
|
|
297
|
+
useScroll(this.$refs.panel); // a region
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
`useKey()` takes a target too, which is what removes the `hasFocus` bookkeeping a document-only service forced on a consumer. Its named key booleans are resolved from `KeyboardEvent.key` rather than the deprecated `keyCode`, and `triggered` now counts repeats of **one** key.
|
|
301
|
+
|
|
302
|
+
### A mixin never occupies a lifecycle hook
|
|
303
|
+
|
|
304
|
+
`withRaf`, `withScroll` and friends override `$mount()`/`$unmount()`, not `mounted()`. A class that mixes a service in and writes its own `mounted()` **without** `super.mounted()` still subscribes.
|
|
305
|
+
|
|
306
|
+
`hook` options are gone: one method name per mixin, and it is the name of the service. Any other target is an explicit `subscribe()` in `mounted()`.
|
|
307
|
+
|
|
308
|
+
## Scheduling and animation
|
|
309
|
+
|
|
310
|
+
### One scheduler replaces three
|
|
311
|
+
|
|
312
|
+
`domScheduler`, the `RafService` loop, `SmartQueue` and the view-transition scheduler are one frame-aligned scheduler. `this.$read()` and `this.$write()` tie tasks to the instance.
|
|
313
|
+
|
|
314
|
+
**`afterWrite` is removed.** rAF callbacks run before style, layout and paint, so no phase inside the frame can read post-layout geometry. Measure in the next frame's `read` phase, or use a `ResizeObserver`.
|
|
315
|
+
|
|
316
|
+
### `tween` and `animate` are not shipped
|
|
317
|
+
|
|
318
|
+
Time-based playback, stagger, sequencing, morphing and text splitting move to a separate `ui-animation` package, with Motion as declarative components and GSAP as a lifecycle-and-scoping decorator.
|
|
319
|
+
|
|
320
|
+
`exit`, `layout` and `layoutId` are not an engine's job — native view transitions solve them, and [`viewTransition()`](../../api/scheduler/viewTransition.md) is in core.
|
|
321
|
+
|
|
322
|
+
What was promoted into core instead: `transition` with `enterTransition` and `leaveTransition`, the easing functions, `spring()` and `smoothTo()`.
|
|
323
|
+
|
|
324
|
+
### `damp()` takes the elapsed time
|
|
325
|
+
|
|
326
|
+
```js
|
|
327
|
+
damp(current, target, 0.1); // [!code --]
|
|
328
|
+
damp(current, target, 0.1, delta); // [!code ++]
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
`factor` is the fraction of the gap that closes per reference frame, which makes it stable for every value a caller can pass. Decay is expressed in time, not in frames.
|
|
332
|
+
|
|
333
|
+
### `scrollTo()` splits in two
|
|
334
|
+
|
|
335
|
+
`scrollPosition()` measures and returns; `scrollTo()` calls it and moves. A carousel that asks which slide is nearest no longer has to scroll to find out.
|
|
336
|
+
|
|
337
|
+
## Diagnostics
|
|
338
|
+
|
|
339
|
+
`EVENTS.error`, `ToolkitErrorDetail` and `ToolkitErrorStage` are removed with **no alias**:
|
|
340
|
+
|
|
341
|
+
```js
|
|
342
|
+
document.addEventListener(EVENTS.error, …); // [!code --]
|
|
343
|
+
document.addEventListener(EVENTS.diagnostic, …); // [!code ++]
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
The detail now carries `severity`, `code`, `message`, an optional `component`, and — for an error only — the original caught value as `error`. See [Diagnostics](../going-further/handling-diagnostics.md).
|
|
347
|
+
|
|
348
|
+
## What is not promoted to core
|
|
349
|
+
|
|
350
|
+
`Action`, `SafeAction`, `Fetch`, `Transition` and the `Data*` family stay out of core. Core keeps general primitives only; those components belong to `@studiometa/ui`.
|
|
351
|
+
|
|
352
|
+
## Removal checklist
|
|
353
|
+
|
|
354
|
+
| Removed | Replacement |
|
|
355
|
+
| --------------------------------- | ---------------------------------------------- |
|
|
356
|
+
| `$parent`, `$children`, `$root` | `$closest()`, `$query()`, `$watchChildren()` |
|
|
357
|
+
| `createApp()` | `registerComponent()` / `registerComponents()` |
|
|
358
|
+
| `$update()` | nothing — refs are live |
|
|
359
|
+
| `updated()` | `option<Name>Changed()`, `watchAttributes()` |
|
|
360
|
+
| `config.emits` | the `$emits` props type |
|
|
361
|
+
| `withExtraConfig()` | a subclass |
|
|
362
|
+
| `withGroup` | `provideRootContext()`, `createGroup()` |
|
|
363
|
+
| `withResponsiveOptions` | nothing — every option is responsive |
|
|
364
|
+
| `withMountWhenInView` and friends | mount strategies |
|
|
365
|
+
| `data-load`, `loadStrategy` | `data-mount` |
|
|
366
|
+
| the `importWhen*` helpers | `registerManifest()` entries |
|
|
367
|
+
| `defineFeatures()` | `setBreakpoints()` |
|
|
368
|
+
| `LoadService` | — |
|
|
369
|
+
| `domScheduler`, `SmartQueue` | `defaultScheduler` |
|
|
370
|
+
| `afterWrite` | the next frame's `read`, or a `ResizeObserver` |
|
|
371
|
+
| `tween`, `animate` | the `ui-animation` package |
|
|
372
|
+
| `EVENTS.error` | `EVENTS.diagnostic` |
|
|
373
|
+
| `<tk-name>`, arbitrary selectors | `data-component` |
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# CSS
|
|
2
|
+
|
|
3
|
+
```js
|
|
4
|
+
import { matrix, transform } from '@studiometa/js-toolkit/utils';
|
|
5
|
+
```
|
|
6
|
+
|
|
7
|
+
## Transforms
|
|
8
|
+
|
|
9
|
+
### transform
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
transform(props: TransformProps): string
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
```js
|
|
16
|
+
import { transform } from '@studiometa/js-toolkit/utils';
|
|
17
|
+
|
|
18
|
+
transform({ x: 10, y: 20, scale: 1.5, rotate: 45 });
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Builds a `transform` value from named parts, so a component composes a transform instead of assembling a string. `TransformProps` takes `x`, `y`, `z`, `rotate`, `rotateX`, `rotateY`, `rotateZ`, `scale`, `scaleX`, `scaleY`, `scaleZ`, `skew` and the rest of the family.
|
|
22
|
+
|
|
23
|
+
**The order is fixed by `TRANSFORM_PROPS`, not by the object.** Transform functions do not commute, so two components building "the same" transform from differently-ordered literals must still get the same matrix.
|
|
24
|
+
|
|
25
|
+
### matrix
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
matrix(props?: MatrixProps): string
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
```js
|
|
32
|
+
import { matrix } from '@studiometa/js-toolkit/utils';
|
|
33
|
+
|
|
34
|
+
matrix({ scaleX: 2, translateX: 10 });
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
A `matrix()` string. Reach for it when a value has to be interpolated as a matrix rather than as separate functions.
|
|
38
|
+
|
|
39
|
+
### TRANSFORM_PROPS
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
const TRANSFORM_PROPS: readonly (keyof TransformProps)[];
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
The ordered list of keys `transform()` reads.
|
|
46
|
+
|
|
47
|
+
## Measuring
|
|
48
|
+
|
|
49
|
+
### getOffsetSizes
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
getOffsetSizes(element: HTMLElement): { x, y, width, height, top, right, bottom, left }
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
```js
|
|
56
|
+
import { getOffsetSizes } from '@studiometa/js-toolkit/utils';
|
|
57
|
+
|
|
58
|
+
const box = getOffsetSizes(document.body);
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The element's box from its **offset** properties rather than from `getBoundingClientRect()` — so a transform the component itself applied does not move the measurement.
|
|
62
|
+
|
|
63
|
+
That is exactly what a drag or a tilt needs: the layout box is the frame of reference, and the transform is the output.
|
|
64
|
+
|
|
65
|
+
**It is a layout read**
|
|
66
|
+
|
|
67
|
+
Call it from the `read` phase — [`$read()`](../api/instance-methods.md#read-and-write) — so it batches with every other measurement of the frame.
|
|
68
|
+
|
|
69
|
+
## Applying
|
|
70
|
+
|
|
71
|
+
### setClassesOrStyles
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
setClassesOrStyles(
|
|
75
|
+
el: HTMLElement,
|
|
76
|
+
value: string | string[] | Partial<CSSStyleDeclaration> | undefined,
|
|
77
|
+
method?: 'add' | 'remove',
|
|
78
|
+
): void
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
```js
|
|
82
|
+
import { setClassesOrStyles } from '@studiometa/js-toolkit/utils';
|
|
83
|
+
|
|
84
|
+
const el = document.body;
|
|
85
|
+
|
|
86
|
+
setClassesOrStyles(el, 'is-active'); // a class
|
|
87
|
+
setClassesOrStyles(el, ['is-active', 'is-open']); // several
|
|
88
|
+
setClassesOrStyles(el, { opacity: '0' }); // inline styles
|
|
89
|
+
setClassesOrStyles(el, 'is-active', 'remove'); // undo it
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Applies a value that may be **either** classes or inline styles, which is what lets [`transition()`](transitions.md) take one option in both forms.
|
|
93
|
+
|
|
94
|
+
An `undefined` value does nothing, so a caller with an optional state does not have to branch.
|
|
95
|
+
|
|
96
|
+
## What is not here
|
|
97
|
+
|
|
98
|
+
`addClass`, `removeClass`, `toggleClass`, `addStyle`, `removeStyle` and `animate` are not shipped. `el.classList` and `el.style` say the first five, and time-based playback belongs to the separate `ui-animation` package.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# DOM
|
|
2
|
+
|
|
3
|
+
```js
|
|
4
|
+
import { createElement, selectorFor } from '@studiometa/js-toolkit/utils';
|
|
5
|
+
```
|
|
6
|
+
|
|
7
|
+
## createElement
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
createElement(tag?, children?): HTMLElement
|
|
11
|
+
createElement(tag?, attributes?, children?): HTMLElement
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
```js
|
|
15
|
+
import { createElement } from '@studiometa/js-toolkit/utils';
|
|
16
|
+
|
|
17
|
+
createElement('div');
|
|
18
|
+
createElement('p', 'Hello');
|
|
19
|
+
createElement('ul', [createElement('li', 'One'), createElement('li', 'Two')]);
|
|
20
|
+
createElement('button', { class: 'btn', data: { component: 'Action' } }, 'Send');
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Parameters**
|
|
24
|
+
|
|
25
|
+
- `tag` — defaults to `'div'`, and the return type follows it: `createElement('input')` gives an `HTMLInputElement`.
|
|
26
|
+
- `attributes` — plain attributes, plus a `data` object whose keys become `data-*`.
|
|
27
|
+
- `children` — a string, a `Node`, or an array of either.
|
|
28
|
+
|
|
29
|
+
The `data` key is why this exists rather than three lines of `document.createElement`: building an element that carries `data-component` and a few `data-option-*` is the common case, and spelling each `setAttribute()` out loses the shape.
|
|
30
|
+
|
|
31
|
+
## selectorFor
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
selectorFor(name: string): string
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```js
|
|
38
|
+
import { selectorFor } from '@studiometa/js-toolkit/utils';
|
|
39
|
+
|
|
40
|
+
selectorFor('Dialog');
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The CSS selector that matches every element declaring a component name — **including the responsive `data-component:<breakpoint>` spellings**.
|
|
44
|
+
|
|
45
|
+
It is the **one place** that writes the name-to-selector contract, which is why it is public: a consumer that queries for components must match what the registry matches, and a hand-written `[data-component="X"]` misses the scoped declarations.
|
|
46
|
+
|
|
47
|
+
**It over-matches on purpose**
|
|
48
|
+
|
|
49
|
+
A responsive declaration that is not active still matches the selector. That is why the four [instance lookups](../api/registry/getInstances.md) read the element's instance map afterwards: **a matching element with no instance is skipped, and that is the whole narrowing.**
|
|
50
|
+
|
|
51
|
+
## See also
|
|
52
|
+
|
|
53
|
+
- [CSS](css.md) — `getOffsetSizes`, `transform`, `matrix`
|
|
54
|
+
- [`swap()`](../api/dom/swap.md) — replacing content, with the framework waiting
|