@octane-xplat/patches 0.14.0 → 0.16.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/package.json +1 -1
- package/patches/@nativescript-community__octane@0.2.4.patch +182 -7
- package/patches/@nativescript-community__octane@0.2.5.patch +620 -0
- package/patches/@nativescript__doctor@2.0.18.patch +13 -0
- package/patches/@nativescript__vite@8.0.17.patch +227 -19
- package/patches/@triniwiz__nativescript-masonkit@1.0.0-beta.110.patch +13 -0
- package/patches/octane@0.11.0.patch +30 -3
package/package.json
CHANGED
|
@@ -1,20 +1,195 @@
|
|
|
1
1
|
diff --git a/dist/driver.js b/dist/driver.js
|
|
2
|
-
index c88828e30337ee566bc1a919940e58b4b0227aba..
|
|
2
|
+
index c88828e30337ee566bc1a919940e58b4b0227aba..5fcee7ffb92d8ddf937b65b27825cbb81944a195 100644
|
|
3
3
|
--- a/dist/driver.js
|
|
4
4
|
+++ b/dist/driver.js
|
|
5
|
-
@@ -
|
|
5
|
+
@@ -56,15 +56,34 @@ function applyProps(node, props) {
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
- * `update` carries the host's dynamic-prop snapshot; attributes that were
|
|
10
|
+
- * static in the compiled plan arrive only with `create`. Merge instead of
|
|
11
|
+
- * replace, or a first update would strip a node's static layout props.
|
|
12
|
+
+ * `update` carries the host's complete prop bag: a key present in the last
|
|
13
|
+
+ * applied bag but absent from the next is a removal, and the view state it
|
|
14
|
+
+ * installed returns to the prop's documented default. `undefined` never
|
|
15
|
+
+ * crosses the wire (the runtime elides it); `null` is "not supplied" for
|
|
16
|
+
+ * props without an explicit nullable contract — both reset through setProp.
|
|
17
|
+
*/
|
|
18
|
+
function updateProps(node, next) {
|
|
19
|
+
+ const dropped = [];
|
|
20
|
+
+ for (const name in node.props) {
|
|
21
|
+
+ if (node.props[name] != null && !(name in next))
|
|
22
|
+
+ dropped.push(name);
|
|
23
|
+
+ }
|
|
24
|
+
applyProps(node, next);
|
|
25
|
+
- node.props = { ...node.props, ...next };
|
|
26
|
+
+ for (const name of dropped) {
|
|
27
|
+
+ resetProp(node, node.view, name);
|
|
28
|
+
+ }
|
|
29
|
+
+ node.props = next;
|
|
30
|
+
}
|
|
31
|
+
function setProp(node, view, name, value) {
|
|
32
|
+
+ // Keep authored placement separate from Grid's computed native coordinates.
|
|
33
|
+
+ // NativeScript does not retain a setter write equal to its default (row/col 0).
|
|
34
|
+
+ if (name === 'row' || name === 'col' || name === 'rowSpan' || name === 'colSpan') {
|
|
35
|
+
+ const key = Symbol.for('octane-xplat.grid-placement');
|
|
36
|
+
+ const placement = view[key] ?? (view[key] = {});
|
|
37
|
+
+ if (value == null || value === unsetValue) delete placement[name];
|
|
38
|
+
+ else placement[name] = value;
|
|
39
|
+
+ view.notify({ eventName: 'xplatGridPlacementChange', object: view });
|
|
40
|
+
+ }
|
|
41
|
+
if (name === 'children' || name === 'key' || name === 'ref')
|
|
42
|
+
return;
|
|
43
|
+
// Event props arrive as their own `event` commands.
|
|
44
|
+
@@ -78,13 +97,28 @@ function setProp(node, view, name, value) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (name === 'style') {
|
|
48
|
+
- applyStyle(view, value);
|
|
49
|
+
+ applyStyle(node, view, value);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (name === 'renderItem' && view instanceof ListView) {
|
|
6
53
|
setRenderItem(view, value ?? null, createNativeScriptRoot);
|
|
7
54
|
return;
|
|
8
55
|
}
|
|
9
|
-
+ // `
|
|
10
|
-
+ //
|
|
11
|
-
+ //
|
|
12
|
-
+
|
|
56
|
+
+ // `null`/`unsetValue` restore the prop's default rather than writing a
|
|
57
|
+
+ // literal null through a native setter. `undefined` is a removal: skip it
|
|
58
|
+
+ // when nothing applied (NativeScript setters coerce it badly) and reset
|
|
59
|
+
+ // when a real value did.
|
|
60
|
+
+ if (value == null || value === unsetValue) {
|
|
61
|
+
+ if (value === undefined && node.props[name] == null)
|
|
62
|
+
+ return;
|
|
63
|
+
+ resetProp(node, view, name);
|
|
13
64
|
+ return;
|
|
65
|
+
+ }
|
|
66
|
+
+ // Capture the pre-prop value once so a plain (non-Property) field can be
|
|
67
|
+
+ // restored when the prop is removed later.
|
|
68
|
+
+ const defaults = (node.propDefaults ??= {});
|
|
69
|
+
+ if (!(name in defaults))
|
|
70
|
+
+ defaults[name] = view[name];
|
|
14
71
|
// Core raises `<name>Change` for a script write exactly as for a user
|
|
15
72
|
// edit; a controlled input must not see its own value come back as one.
|
|
16
73
|
const echo = `${name}Change`;
|
|
17
|
-
@@ -
|
|
74
|
+
@@ -99,6 +133,44 @@ function setProp(node, view, name, value) {
|
|
75
|
+
node.muted.delete(echo);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
+/** Restore a removed prop to the value it holds when never supplied. */
|
|
79
|
+
+function resetProp(node, view, name) {
|
|
80
|
+
+ if (view === null)
|
|
81
|
+
+ return;
|
|
82
|
+
+ if (name === 'children' || name === 'key' || name === 'ref')
|
|
83
|
+
+ return;
|
|
84
|
+
+ // `on*` handlers unbind through `event` commands, not props.
|
|
85
|
+
+ if (EVENT_PROP.test(name))
|
|
86
|
+
+ return;
|
|
87
|
+
+ if (name === 'className' || name === 'class') {
|
|
88
|
+
+ view.className = unsetValue;
|
|
89
|
+
+ return;
|
|
90
|
+
+ }
|
|
91
|
+
+ if (name === 'style') {
|
|
92
|
+
+ applyStyle(node, view, null);
|
|
93
|
+
+ return;
|
|
94
|
+
+ }
|
|
95
|
+
+ if (name === 'renderItem' && view instanceof ListView) {
|
|
96
|
+
+ setRenderItem(view, null, createNativeScriptRoot);
|
|
97
|
+
+ return;
|
|
98
|
+
+ }
|
|
99
|
+
+ const echo = `${name}Change`;
|
|
100
|
+
+ const listening = node.listeners.has(echo);
|
|
101
|
+
+ if (listening)
|
|
102
|
+
+ node.muted.add(echo);
|
|
103
|
+
+ try {
|
|
104
|
+
+ // Property/CssProperty setters consume the sentinel and restore the
|
|
105
|
+
+ // declared default. A plain field stores it raw — detect that and
|
|
106
|
+
+ // write back the captured pre-prop value instead.
|
|
107
|
+
+ view[name] = unsetValue;
|
|
108
|
+
+ if (view[name] === unsetValue)
|
|
109
|
+
+ view[name] = node.propDefaults?.[name];
|
|
110
|
+
+ }
|
|
111
|
+
+ finally {
|
|
112
|
+
+ if (listening)
|
|
113
|
+
+ node.muted.delete(echo);
|
|
114
|
+
+ }
|
|
115
|
+
+}
|
|
116
|
+
// `class`/`className` compose clsx-style on the DOM renderer; join arrays
|
|
117
|
+
// with spaces so NativeScript's class selectors can match each class.
|
|
118
|
+
function normalizeClass(value) {
|
|
119
|
+
@@ -112,15 +184,67 @@ function normalizeClass(value) {
|
|
120
|
+
.join(' ');
|
|
121
|
+
return '';
|
|
122
|
+
}
|
|
123
|
+
-function applyStyle(view, value) {
|
|
124
|
+
- if (value == null || value === unsetValue)
|
|
125
|
+
- return;
|
|
126
|
+
+/**
|
|
127
|
+
+ * The `style` prop replaces wholesale — a key dropped or nulled since the last
|
|
128
|
+
+ * apply resets what it installed (`unsetValue` clears a local CssProperty
|
|
129
|
+
+ * value so the cascade can re-apply). String styles are parsed for their
|
|
130
|
+
+ * declared names so a later object or removal can reset them.
|
|
131
|
+
+ */
|
|
132
|
+
+function applyStyle(node, view, value) {
|
|
133
|
+
+ const applied = node.styleKeys;
|
|
134
|
+
+ node.styleKeys = undefined;
|
|
135
|
+
if (typeof value === 'string') {
|
|
136
|
+
+ clearStyleKeys(view, applied);
|
|
137
|
+
view.setInlineStyle(value);
|
|
138
|
+
+ node.styleKeys = inlineStyleKeys(value);
|
|
139
|
+
+ return;
|
|
140
|
+
+ }
|
|
141
|
+
+ if (value == null || value === unsetValue || typeof value !== 'object') {
|
|
142
|
+
+ clearStyleKeys(view, applied);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
- if (typeof value === 'object')
|
|
146
|
+
- Object.assign(view.style, value);
|
|
147
|
+
+ if (applied !== undefined) {
|
|
148
|
+
+ for (const key of applied) {
|
|
149
|
+
+ if (!(key in value))
|
|
150
|
+
+ unsetStyleKey(view, key);
|
|
151
|
+
+ }
|
|
152
|
+
+ }
|
|
153
|
+
+ for (const [key, nextValue] of Object.entries(value)) {
|
|
154
|
+
+ if (nextValue == null)
|
|
155
|
+
+ unsetStyleKey(view, key);
|
|
156
|
+
+ else
|
|
157
|
+
+ view.style[key] = nextValue;
|
|
158
|
+
+ }
|
|
159
|
+
+ node.styleKeys = new Set(Object.keys(value));
|
|
160
|
+
+}
|
|
161
|
+
+function clearStyleKeys(view, keys) {
|
|
162
|
+
+ if (keys === undefined)
|
|
163
|
+
+ return;
|
|
164
|
+
+ for (const key of keys)
|
|
165
|
+
+ unsetStyleKey(view, key);
|
|
166
|
+
+}
|
|
167
|
+
+function unsetStyleKey(view, name) {
|
|
168
|
+
+ const style = view.style;
|
|
169
|
+
+ if (name.startsWith('--')) {
|
|
170
|
+
+ style.setUnscopedCssVariable?.(name, unsetValue);
|
|
171
|
+
+ return;
|
|
172
|
+
+ }
|
|
173
|
+
+ style[name] = unsetValue;
|
|
174
|
+
+ // A style field outside the CssProperty registry stores the sentinel raw.
|
|
175
|
+
+ if (style[name] === unsetValue)
|
|
176
|
+
+ style[name] = undefined;
|
|
177
|
+
+}
|
|
178
|
+
+function inlineStyleKeys(style) {
|
|
179
|
+
+ const keys = new Set();
|
|
180
|
+
+ for (const declaration of style.split(';')) {
|
|
181
|
+
+ const colon = declaration.indexOf(':');
|
|
182
|
+
+ if (colon === -1)
|
|
183
|
+
+ continue;
|
|
184
|
+
+ const name = declaration.slice(0, colon).trim();
|
|
185
|
+
+ if (name !== '')
|
|
186
|
+
+ keys.add(name.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase()));
|
|
187
|
+
+ }
|
|
188
|
+
+ return keys;
|
|
189
|
+
}
|
|
190
|
+
/** Recompute a text host's `text` from its `#text` children. */
|
|
191
|
+
function syncText(parent) {
|
|
192
|
+
@@ -482,7 +606,7 @@ function applyCommand(container, command) {
|
|
18
193
|
}
|
|
19
194
|
export const nativeScriptDriver = {
|
|
20
195
|
id: NATIVESCRIPT_RENDERER_ID,
|
|
@@ -0,0 +1,620 @@
|
|
|
1
|
+
diff --git a/dist/driver.js b/dist/driver.js
|
|
2
|
+
index 8bc563a..4cb1f95 100644
|
|
3
|
+
--- a/dist/driver.js
|
|
4
|
+
+++ b/dist/driver.js
|
|
5
|
+
@@ -3,6 +3,7 @@ import { createUniversalRoot, } from 'octane/universal/native';
|
|
6
|
+
import { NATIVESCRIPT_RENDERER_ID } from './config.js';
|
|
7
|
+
import { ELEMENTS, EVENT_PROP, eventNameFor, onElementReplaced, } from './elements.js';
|
|
8
|
+
import { releaseListView, setRenderItem, } from './list-view.js';
|
|
9
|
+
+import { Style as MasonStyle } from '@triniwiz/nativescript-masonkit/style';
|
|
10
|
+
/** `#text` nodes carry no view; the driver folds them into the parent's `text`. */
|
|
11
|
+
const TEXT = '#text';
|
|
12
|
+
/**
|
|
13
|
+
@@ -73,7 +74,10 @@ function instantiate(type) {
|
|
14
|
+
if (Element === undefined) {
|
|
15
|
+
throw new Error(`NativeScript driver: <${type}> is not a registered element.`);
|
|
16
|
+
}
|
|
17
|
+
- return new Element();
|
|
18
|
+
+ const view = new Element();
|
|
19
|
+
+ if (MASON_CONTAINER_TAGS.has(type))
|
|
20
|
+
+ applyMasonDefaults(type, view);
|
|
21
|
+
+ return view;
|
|
22
|
+
}
|
|
23
|
+
function applyProps(node, props) {
|
|
24
|
+
if (node.view === null) {
|
|
25
|
+
@@ -91,13 +95,23 @@ function applyProps(node, props) {
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
- * `update` carries the host's dynamic-prop snapshot; attributes that were
|
|
30
|
+
- * static in the compiled plan arrive only with `create`. Merge instead of
|
|
31
|
+
- * replace, or a first update would strip a node's static layout props.
|
|
32
|
+
+ * `update` carries the host's complete prop bag: a key present in the last
|
|
33
|
+
+ * applied bag but absent from the next is a removal, and the view state it
|
|
34
|
+
+ * installed returns to the prop's documented default. `undefined` never
|
|
35
|
+
+ * crosses the wire (the runtime elides it); `null` is "not supplied" for
|
|
36
|
+
+ * props without an explicit nullable contract — both reset through setProp.
|
|
37
|
+
*/
|
|
38
|
+
function updateProps(node, next) {
|
|
39
|
+
+ const dropped = [];
|
|
40
|
+
+ for (const name in node.props) {
|
|
41
|
+
+ if (node.props[name] != null && !(name in next))
|
|
42
|
+
+ dropped.push(name);
|
|
43
|
+
+ }
|
|
44
|
+
applyProps(node, next);
|
|
45
|
+
- node.props = { ...node.props, ...next };
|
|
46
|
+
+ for (const name of dropped) {
|
|
47
|
+
+ resetProp(node, node.view, name);
|
|
48
|
+
+ }
|
|
49
|
+
+ node.props = next;
|
|
50
|
+
}
|
|
51
|
+
function setProp(node, view, name, value) {
|
|
52
|
+
if (name === 'children' || name === 'key' || name === 'ref')
|
|
53
|
+
@@ -113,13 +127,36 @@ function setProp(node, view, name, value) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (name === 'style') {
|
|
57
|
+
- applyStyle(view, value);
|
|
58
|
+
+ applyStyle(node, view, value);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (name === 'renderItem' && view instanceof ListView) {
|
|
62
|
+
setRenderItem(view, value ?? null, createNativeScriptRoot);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
+ // Mason cutover — all layout props are style-only: warn when a former
|
|
66
|
+
+ // prop name arrives on a mason container or a child of one.
|
|
67
|
+
+ if (MASON_CONTAINER_TAGS.has(node.type))
|
|
68
|
+
+ applyMasonContainerProp(node, view, name, value);
|
|
69
|
+
+ if (MASON_STYLE_ONLY_PROPS.has(name) &&
|
|
70
|
+
+ (MASON_CONTAINER_TAGS.has(node.type) ||
|
|
71
|
+
+ (node.parent !== null && MASON_CONTAINER_TAGS.has(node.parent.type))))
|
|
72
|
+
+ warnStyleOnlyProp(node, name);
|
|
73
|
+
+ // `null`/`unsetValue` restore the prop's default rather than writing a
|
|
74
|
+
+ // literal null through a native setter. `undefined` is a removal: skip it
|
|
75
|
+
+ // when nothing applied (NativeScript setters coerce it badly) and reset
|
|
76
|
+
+ // when a real value did.
|
|
77
|
+
+ if (value == null || value === unsetValue) {
|
|
78
|
+
+ if (value === undefined && node.props[name] == null)
|
|
79
|
+
+ return;
|
|
80
|
+
+ resetProp(node, view, name);
|
|
81
|
+
+ return;
|
|
82
|
+
+ }
|
|
83
|
+
+ // Capture the pre-prop value once so a plain (non-Property) field can be
|
|
84
|
+
+ // restored when the prop is removed later.
|
|
85
|
+
+ const defaults = (node.propDefaults ??= {});
|
|
86
|
+
+ if (!(name in defaults))
|
|
87
|
+
+ defaults[name] = view[name];
|
|
88
|
+
// Core raises `<name>Change` for a script write exactly as for a user
|
|
89
|
+
// edit; a controlled input must not see its own value come back as one.
|
|
90
|
+
const echo = `${name}Change`;
|
|
91
|
+
@@ -134,6 +171,44 @@ function setProp(node, view, name, value) {
|
|
92
|
+
node.muted.delete(echo);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
+/** Restore a removed prop to the value it holds when never supplied. */
|
|
96
|
+
+function resetProp(node, view, name) {
|
|
97
|
+
+ if (view === null)
|
|
98
|
+
+ return;
|
|
99
|
+
+ if (name === 'children' || name === 'key' || name === 'ref')
|
|
100
|
+
+ return;
|
|
101
|
+
+ // `on*` handlers unbind through `event` commands, not props.
|
|
102
|
+
+ if (EVENT_PROP.test(name))
|
|
103
|
+
+ return;
|
|
104
|
+
+ if (name === 'className' || name === 'class') {
|
|
105
|
+
+ view.className = unsetValue;
|
|
106
|
+
+ return;
|
|
107
|
+
+ }
|
|
108
|
+
+ if (name === 'style') {
|
|
109
|
+
+ applyStyle(node, view, null);
|
|
110
|
+
+ return;
|
|
111
|
+
+ }
|
|
112
|
+
+ if (name === 'renderItem' && view instanceof ListView) {
|
|
113
|
+
+ setRenderItem(view, null, createNativeScriptRoot);
|
|
114
|
+
+ return;
|
|
115
|
+
+ }
|
|
116
|
+
+ const echo = `${name}Change`;
|
|
117
|
+
+ const listening = node.listeners.has(echo);
|
|
118
|
+
+ if (listening)
|
|
119
|
+
+ node.muted.add(echo);
|
|
120
|
+
+ try {
|
|
121
|
+
+ // Property/CssProperty setters consume the sentinel and restore the
|
|
122
|
+
+ // declared default. A plain field stores it raw — detect that and
|
|
123
|
+
+ // write back the captured pre-prop value instead.
|
|
124
|
+
+ view[name] = unsetValue;
|
|
125
|
+
+ if (view[name] === unsetValue)
|
|
126
|
+
+ view[name] = node.propDefaults?.[name];
|
|
127
|
+
+ }
|
|
128
|
+
+ finally {
|
|
129
|
+
+ if (listening)
|
|
130
|
+
+ node.muted.delete(echo);
|
|
131
|
+
+ }
|
|
132
|
+
+}
|
|
133
|
+
// `class`/`className` compose clsx-style on the DOM renderer; join arrays
|
|
134
|
+
// with spaces so NativeScript's class selectors can match each class.
|
|
135
|
+
function normalizeClass(value) {
|
|
136
|
+
@@ -147,16 +222,214 @@ function normalizeClass(value) {
|
|
137
|
+
.join(' ');
|
|
138
|
+
return '';
|
|
139
|
+
}
|
|
140
|
+
-function applyStyle(view, value) {
|
|
141
|
+
- if (value == null || value === unsetValue)
|
|
142
|
+
- return;
|
|
143
|
+
+/**
|
|
144
|
+
+ * The `style` prop replaces wholesale — a key dropped or nulled since the last
|
|
145
|
+
+ * apply resets what it installed (`unsetValue` clears a local CssProperty
|
|
146
|
+
+ * value so the cascade can re-apply). String styles are parsed for their
|
|
147
|
+
+ * declared names so a later object or removal can reset them.
|
|
148
|
+
+ */
|
|
149
|
+
+function applyStyle(node, view, value) {
|
|
150
|
+
+ const applied = node.styleKeys;
|
|
151
|
+
+ node.styleKeys = undefined;
|
|
152
|
+
if (typeof value === 'string') {
|
|
153
|
+
+ clearStyleKeys(view, applied);
|
|
154
|
+
view.setInlineStyle(value);
|
|
155
|
+
+ node.styleKeys = inlineStyleKeys(value);
|
|
156
|
+
+ return;
|
|
157
|
+
+ }
|
|
158
|
+
+ if (value == null || value === unsetValue || typeof value !== 'object') {
|
|
159
|
+
+ clearStyleKeys(view, applied);
|
|
160
|
+
+ return;
|
|
161
|
+
+ }
|
|
162
|
+
+ if (applied !== undefined) {
|
|
163
|
+
+ for (const key of applied) {
|
|
164
|
+
+ if (!(key in value))
|
|
165
|
+
+ unsetStyleKey(view, key);
|
|
166
|
+
+ }
|
|
167
|
+
+ }
|
|
168
|
+
+ // Mason layout keys target the leaf style under a mason parent —
|
|
169
|
+
+ // `view.style` is the NS surface where they land as dead fields. The leaf
|
|
170
|
+
+ // style exists only once the parent attaches the view, so entries are
|
|
171
|
+
+ // stashed and replayed by applyMasonChildLayout.
|
|
172
|
+
+ const parentIsMason = node.parent !== null && MASON_CONTAINER_TAGS.has(node.parent.type);
|
|
173
|
+
+ const masonLeaf = parentIsMason ? masonChildStyle(view) : undefined;
|
|
174
|
+
+ for (const [key, nextValue] of Object.entries(value)) {
|
|
175
|
+
+ if (MASON_LEAF_STYLE_KEYS.has(key)) {
|
|
176
|
+
+ const leafStash = view[MASON_LEAF_STYLE_STASH] ?? (view[MASON_LEAF_STYLE_STASH] = {});
|
|
177
|
+
+ leafStash[key] = nextValue == null ? undefined : nextValue;
|
|
178
|
+
+ if (masonLeaf !== undefined)
|
|
179
|
+
+ masonLeaf[key] = nextValue == null ? undefined : nextValue;
|
|
180
|
+
+ }
|
|
181
|
+
+ if (nextValue == null)
|
|
182
|
+
+ unsetStyleKey(view, key);
|
|
183
|
+
+ else
|
|
184
|
+
+ view.style[key] = nextValue;
|
|
185
|
+
+ }
|
|
186
|
+
+ node.styleKeys = new Set(Object.keys(value));
|
|
187
|
+
+}
|
|
188
|
+
+function clearStyleKeys(view, keys) {
|
|
189
|
+
+ if (keys === undefined)
|
|
190
|
+
+ return;
|
|
191
|
+
+ for (const key of keys)
|
|
192
|
+
+ unsetStyleKey(view, key);
|
|
193
|
+
+}
|
|
194
|
+
+function unsetStyleKey(view, name) {
|
|
195
|
+
+ const style = view.style;
|
|
196
|
+
+ if (name.startsWith('--')) {
|
|
197
|
+
+ style.setUnscopedCssVariable?.(name, unsetValue);
|
|
198
|
+
+ return;
|
|
199
|
+
+ }
|
|
200
|
+
+ style[name] = unsetValue;
|
|
201
|
+
+ // A style field outside the CssProperty registry stores the sentinel raw.
|
|
202
|
+
+ if (style[name] === unsetValue)
|
|
203
|
+
+ style[name] = undefined;
|
|
204
|
+
+}
|
|
205
|
+
+function inlineStyleKeys(style) {
|
|
206
|
+
+ const keys = new Set();
|
|
207
|
+
+ for (const declaration of style.split(';')) {
|
|
208
|
+
+ const colon = declaration.indexOf(':');
|
|
209
|
+
+ if (colon === -1)
|
|
210
|
+
+ continue;
|
|
211
|
+
+ const name = declaration.slice(0, colon).trim();
|
|
212
|
+
+ if (name !== '')
|
|
213
|
+
+ keys.add(name.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase()));
|
|
214
|
+
+ }
|
|
215
|
+
+ return keys;
|
|
216
|
+
+}
|
|
217
|
+
+
|
|
218
|
+
+// --- Mason layout cutover ---------------------------------------------------
|
|
219
|
+
+// masonview is the single layout intrinsic — all layout is expressed in CSS
|
|
220
|
+
+// props (display/flex/grid/position), forwarded onto the node's mason Style.
|
|
221
|
+
+// scrollview stays the platform scroll shell (MasonKit Scroll). Dispatch is
|
|
222
|
+
+// by node tag, so nothing below re-derives the view's class.
|
|
223
|
+
+const MASON_CONTAINER_TAGS = new Set(['masonview', 'scrollview']);
|
|
224
|
+
+// Props whose CssProperty is registered on core's layout classes, never on
|
|
225
|
+
+// MasonKit's ViewBase — `view.flexDirection` would store a dead field, so the
|
|
226
|
+
+// write is forwarded to the mason Style surface instead.
|
|
227
|
+
+// Every former layout-prop name — contract props, LayoutChildProps sugar,
|
|
228
|
+
+// and raw CSS keys alike — is style-only now. As direct props they land on a
|
|
229
|
+
+// dead native field, so the driver warns once per key instead.
|
|
230
|
+
+const MASON_STYLE_ONLY_PROPS = new Set([
|
|
231
|
+
+ 'display', 'position', 'inset', 'aspectRatio', 'overflow', 'overflowX',
|
|
232
|
+
+ 'overflowY', 'flexBasis', 'justifySelf', 'justifyItems', 'direction',
|
|
233
|
+
+ 'boxSizing', 'textAlign', 'scrollbarWidth', 'gridTemplateRows',
|
|
234
|
+
+ 'gridTemplateColumns', 'gridTemplateAreas', 'gridAutoFlow', 'gridAutoRows',
|
|
235
|
+
+ 'gridAutoColumns', 'gridRow', 'gridColumn', 'gridRowStart', 'gridRowEnd',
|
|
236
|
+
+ 'gridColumnStart', 'gridColumnEnd', 'gridArea', 'flexDirection', 'flexWrap',
|
|
237
|
+
+ 'justifyContent', 'alignItems', 'alignContent', 'gap', 'rowGap',
|
|
238
|
+
+ 'columnGap', 'flexGrow', 'flexShrink', 'alignSelf', 'order', 'row', 'col',
|
|
239
|
+
+ 'rowSpan', 'colSpan', 'dock', 'horizontalAlignment', 'verticalAlignment',
|
|
240
|
+
+ 'flexWrapBefore', 'stretchLastChild', 'itemWidth', 'itemHeight',
|
|
241
|
+
+ 'rows', 'columns',
|
|
242
|
+
+]);
|
|
243
|
+
+// Style-bag keys that mason owns — under a mason parent these are written to
|
|
244
|
+
+// the child's mason leaf style in addition to the NS style surface.
|
|
245
|
+
+const MASON_LEAF_STYLE_KEYS = new Set([
|
|
246
|
+
+ ...MASON_STYLE_ONLY_PROPS, 'left', 'top', 'right', 'bottom',
|
|
247
|
+
+]);
|
|
248
|
+
+const MASON_LEAF_STYLE_STASH = Symbol.for('octane-xplat.mason-leaf-style');
|
|
249
|
+
+const warnedStyleOnlyProps = new Set();
|
|
250
|
+
+function warnStyleOnlyProp(node, name) {
|
|
251
|
+
+ const key = node.type + ':' + name;
|
|
252
|
+
+ if (warnedStyleOnlyProps.has(key))
|
|
253
|
+
+ return;
|
|
254
|
+
+ warnedStyleOnlyProps.add(key);
|
|
255
|
+
+ console.warn(`[xplat] <${node.type} ${name}=...> is a layout key — move it into style={{ ${name}: ... }} or a class.`);
|
|
256
|
+
+}
|
|
257
|
+
+
|
|
258
|
+
+/** A mason Style bound to the node's mason leaf — `_styleHelper` on MasonKit's
|
|
259
|
+
+ * own views; for foreign ({N}-native) children, `Style.fromView` binds the
|
|
260
|
+
+ * leaf node `nodeForView` creates at insert. Returns undefined until the
|
|
261
|
+
+ * child's native view exists (props are stashed and replayed at attach). */
|
|
262
|
+
+function masonChildStyle(view) {
|
|
263
|
+
+ if (view === null || view === undefined)
|
|
264
|
+
+ return undefined;
|
|
265
|
+
+ const helper = view._styleHelper;
|
|
266
|
+
+ if (helper !== undefined)
|
|
267
|
+
+ return helper;
|
|
268
|
+
+ const native = view.nativeViewProtected;
|
|
269
|
+
+ if (!native)
|
|
270
|
+
+ return undefined;
|
|
271
|
+
+ try {
|
|
272
|
+
+ return MasonStyle.fromView(view, native);
|
|
273
|
+
+ }
|
|
274
|
+
+ catch {
|
|
275
|
+
+ return undefined;
|
|
276
|
+
+ }
|
|
277
|
+
+}
|
|
278
|
+
+
|
|
279
|
+
+/** NS attached alignment -> CSS self-alignment keyword. */
|
|
280
|
+
+function masonAlignKeyword(value) {
|
|
281
|
+
+ switch (value) {
|
|
282
|
+
+ case 'left':
|
|
283
|
+
+ case 'top':
|
|
284
|
+
+ return 'start';
|
|
285
|
+
+ case 'right':
|
|
286
|
+
+ case 'bottom':
|
|
287
|
+
+ return 'end';
|
|
288
|
+
+ case 'center':
|
|
289
|
+
+ case 'middle':
|
|
290
|
+
+ return 'center';
|
|
291
|
+
+ case 'stretch':
|
|
292
|
+
+ return 'stretch';
|
|
293
|
+
+ }
|
|
294
|
+
+ return undefined;
|
|
295
|
+
+}
|
|
296
|
+
+
|
|
297
|
+
+/** Container-role defaults — equivalent to each NS layout's built-in mode. */
|
|
298
|
+
+function applyMasonDefaults(type, view) {
|
|
299
|
+
+ const style = view.style;
|
|
300
|
+
+ if (type === 'scrollview') {
|
|
301
|
+
+ style.display = 'flex';
|
|
302
|
+
+ style.flexDirection = 'column';
|
|
303
|
+
+ style.overflowY = 'scroll';
|
|
304
|
+
+ style.overflowX = 'hidden';
|
|
305
|
+
+ }
|
|
306
|
+
+ style.alignItems = 'stretch';
|
|
307
|
+
+ // Containers establish the containing block for absolute descendants.
|
|
308
|
+
+ style.position = 'relative';
|
|
309
|
+
+}
|
|
310
|
+
+
|
|
311
|
+
+/** Container-role prop -> mason style write. Runs for every prop on a mason
|
|
312
|
+
+ * container; only the scrollview chrome keys (orientation/scroll toggles)
|
|
313
|
+
+ * still translate — everything else is style-only. */
|
|
314
|
+
+function applyMasonContainerProp(node, view, name, value) {
|
|
315
|
+
+ const style = view.style;
|
|
316
|
+
+ const unset = value == null || value === unsetValue;
|
|
317
|
+
+ if (node.type === 'scrollview') {
|
|
318
|
+
+ if (name === 'orientation' || name === 'horizontal') {
|
|
319
|
+
+ const horizontal = !unset && (value === 'horizontal' || value === true);
|
|
320
|
+
+ style.flexDirection = horizontal ? 'row' : 'column';
|
|
321
|
+
+ style.overflowX = horizontal ? 'scroll' : 'hidden';
|
|
322
|
+
+ style.overflowY = horizontal ? 'hidden' : 'scroll';
|
|
323
|
+
+ }
|
|
324
|
+
+ if (name === 'isScrollEnabled') {
|
|
325
|
+
+ const enabled = !unset && value !== false;
|
|
326
|
+
+ style.overflowX = enabled ? 'scroll' : 'hidden';
|
|
327
|
+
+ style.overflowY = enabled ? 'scroll' : 'hidden';
|
|
328
|
+
+ }
|
|
329
|
+
+ }
|
|
330
|
+
+}
|
|
331
|
+
+
|
|
332
|
+
+/** Replay a child's authored mason style entries onto its leaf — the leaf
|
|
333
|
+
+ * style only exists once the parent attaches the view, so `applyStyle`
|
|
334
|
+
+ * stashes leaf-intended keys and every attach replays them. Sibling order is
|
|
335
|
+
+ * irrelevant to the replay, but the pass runs per sibling anyway so a child
|
|
336
|
+
+ * inserted later still gets its stash flushed. */
|
|
337
|
+
+function applyMasonChildLayout(node, parent) {
|
|
338
|
+
+ const view = node.view;
|
|
339
|
+
+ if (view === null || view === undefined)
|
|
340
|
+
return;
|
|
341
|
+
+ const style = masonChildStyle(view);
|
|
342
|
+
+ if (style === undefined)
|
|
343
|
+
+ return;
|
|
344
|
+
+ const leafStash = view[MASON_LEAF_STYLE_STASH];
|
|
345
|
+
+ if (leafStash !== undefined) {
|
|
346
|
+
+ for (const key of Object.keys(leafStash))
|
|
347
|
+
+ style[key] = leafStash[key];
|
|
348
|
+
}
|
|
349
|
+
- if (typeof value === 'object')
|
|
350
|
+
- Object.assign(view.style, value);
|
|
351
|
+
}
|
|
352
|
+
+
|
|
353
|
+
/** Recompute a text host's `text` from its `#text` children. */
|
|
354
|
+
function syncText(parent) {
|
|
355
|
+
if (parent === null || isPortalTarget(parent))
|
|
356
|
+
@@ -190,6 +463,15 @@ function addViewChild(parentView, view, index) {
|
|
357
|
+
parentView.insertChild(view, Math.min(index, parentView.getChildrenCount()));
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
+ // Custom-layout containers that own their child list without subclassing
|
|
361
|
+
+ // LayoutBase (e.g. MasonKit ViewBase — CustomLayoutView → ContainerView).
|
|
362
|
+
+ // Plain View/ContainerView lacks insertChild, so this stays a capability
|
|
363
|
+
+ // check rather than a catch-all.
|
|
364
|
+
+ if (typeof parentView.insertChild === 'function' && typeof parentView.removeChild === 'function') {
|
|
365
|
+
+ const count = typeof parentView.getChildrenCount === 'function' ? parentView.getChildrenCount() : index;
|
|
366
|
+
+ parentView.insertChild(view, Math.min(index, count));
|
|
367
|
+
+ return;
|
|
368
|
+
+ }
|
|
369
|
+
if (parentView instanceof ContentView) {
|
|
370
|
+
parentView.content = view;
|
|
371
|
+
return;
|
|
372
|
+
@@ -234,6 +516,13 @@ function removeViewChild(parentView, view) {
|
|
373
|
+
parentView.removeChild(view);
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
+ // Same capability check as addViewChild: custom-layout containers that
|
|
377
|
+
+ // aren't LayoutBase subclasses remove children through removeChild.
|
|
378
|
+
+ if (typeof parentView.removeChild === 'function' && typeof parentView.insertChild === 'function') {
|
|
379
|
+
+ if (view.parent === parentView)
|
|
380
|
+
+ parentView.removeChild(view);
|
|
381
|
+
+ return;
|
|
382
|
+
+ }
|
|
383
|
+
if (parentView instanceof ContentView) {
|
|
384
|
+
if (parentView.content === view)
|
|
385
|
+
parentView.content = CLEARED;
|
|
386
|
+
@@ -370,6 +659,13 @@ function attach(container, node) {
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
addViewChild(parentView, node.view, index);
|
|
390
|
+
+ // The child's mason leaf node exists only once the parent has attached it;
|
|
391
|
+
+ // replay placement for every sibling (dock's stretchLastChild depends on
|
|
392
|
+
+ // the full sibling list).
|
|
393
|
+
+ if (parent !== null && MASON_CONTAINER_TAGS.has(parent.type)) {
|
|
394
|
+
+ for (const sibling of childrenOf(container, parent))
|
|
395
|
+
+ applyMasonChildLayout(sibling, parent);
|
|
396
|
+
+ }
|
|
397
|
+
markTabView(tabViewOwning(node));
|
|
398
|
+
}
|
|
399
|
+
function insert(container, parent, node, before) {
|
|
400
|
+
@@ -548,7 +844,7 @@ function preparePortalTarget(context) {
|
|
401
|
+
}
|
|
402
|
+
const target = owner?.node.view ?? suppliedTarget;
|
|
403
|
+
if (!(target instanceof LayoutBase)) {
|
|
404
|
+
- throw new TypeError(`NativeScript driver: a <${target.typeName}> view cannot host portal children; target a layout (e.g. rootlayout, gridlayout).`);
|
|
405
|
+
+ throw new TypeError(`NativeScript driver: a <${target.typeName}> view cannot host portal children; target a layout (e.g. rootlayout, masonview).`);
|
|
406
|
+
}
|
|
407
|
+
let id = portalTargetIds.get(target);
|
|
408
|
+
if (id === undefined) {
|
|
409
|
+
@@ -641,7 +937,7 @@ function applyCommand(container, command) {
|
|
410
|
+
}
|
|
411
|
+
export const nativeScriptDriver = {
|
|
412
|
+
id: NATIVESCRIPT_RENDERER_ID,
|
|
413
|
+
- capabilities: { text: 'host' },
|
|
414
|
+
+ capabilities: { text: 'host', visibility: true },
|
|
415
|
+
events: {
|
|
416
|
+
classify(name) {
|
|
417
|
+
if (!EVENT_PROP.test(name))
|
|
418
|
+
diff --git a/dist/elements.js b/dist/elements.js
|
|
419
|
+
index a13bcea..e9988e1 100644
|
|
420
|
+
--- a/dist/elements.js
|
|
421
|
+
+++ b/dist/elements.js
|
|
422
|
+
@@ -1,4 +1,7 @@
|
|
423
|
+
-import { AbsoluteLayout, ActionBar, ActionItem, ActivityIndicator, Button, LiquidGlass, ContentView, DatePicker, DockLayout, FlexboxLayout, FormattedString, Frame, GridLayout, HtmlView, Image, Label, ListPicker, ListView, NavigationButton, Page, Placeholder, Progress, ProxyViewContainer, RootLayout, ScrollView, SearchBar, SegmentedBar, SegmentedBarItem, Slider, Span, StackLayout, Switch, TabView, TabViewItem, TextField, TextView, TimePicker, WebView, WrapLayout, } from '@nativescript/core';
|
|
424
|
+
+import { ActionBar, ActionItem, ActivityIndicator, Button, LiquidGlass, ContentView, DatePicker, FormattedString, Frame, HtmlView, Image, Label, ListPicker, ListView, NavigationButton, Page, Placeholder, Progress, ProxyViewContainer, RootLayout, SearchBar, SegmentedBar, SegmentedBarItem, Slider, Span, Switch, TabView, TabViewItem, TextField, TextView, TimePicker, WebView, } from '@nativescript/core';
|
|
425
|
+
+// Mason cutover: container intrinsics resolve to MasonKit views; the driver
|
|
426
|
+
+// translates their NativeScript-shaped props into mason style writes.
|
|
427
|
+
+import { View as MasonView, Scroll as MasonScroll } from '@triniwiz/nativescript-masonkit';
|
|
428
|
+
/**
|
|
429
|
+
* Lowercase tag name -> view constructor. The keys are the JSX tag names of
|
|
430
|
+
* `intrinsics.ts`; an app extends the vocabulary with `registerElement`.
|
|
431
|
+
@@ -28,18 +31,14 @@ export function onElementReplaced(listener) {
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
const BUILTIN_ELEMENTS = [
|
|
435
|
+
- ['absolutelayout', AbsoluteLayout],
|
|
436
|
+
['actionbar', ActionBar],
|
|
437
|
+
['actionitem', ActionItem],
|
|
438
|
+
['activityindicator', ActivityIndicator],
|
|
439
|
+
['button', Button],
|
|
440
|
+
['contentview', ContentView],
|
|
441
|
+
['datepicker', DatePicker],
|
|
442
|
+
- ['docklayout', DockLayout],
|
|
443
|
+
- ['flexboxlayout', FlexboxLayout],
|
|
444
|
+
['formattedstring', FormattedString],
|
|
445
|
+
['frame', Frame],
|
|
446
|
+
- ['gridlayout', GridLayout],
|
|
447
|
+
['htmlview', HtmlView],
|
|
448
|
+
['image', Image],
|
|
449
|
+
['label', Label],
|
|
450
|
+
@@ -51,13 +50,12 @@ const BUILTIN_ELEMENTS = [
|
|
451
|
+
['progress', Progress],
|
|
452
|
+
['proxyviewcontainer', ProxyViewContainer],
|
|
453
|
+
['rootlayout', RootLayout],
|
|
454
|
+
- ['scrollview', ScrollView],
|
|
455
|
+
+ ['scrollview', MasonScroll],
|
|
456
|
+
['searchbar', SearchBar],
|
|
457
|
+
['segmentedbar', SegmentedBar],
|
|
458
|
+
['segmentedbaritem', SegmentedBarItem],
|
|
459
|
+
['slider', Slider],
|
|
460
|
+
['span', Span],
|
|
461
|
+
- ['stacklayout', StackLayout],
|
|
462
|
+
['switch', Switch],
|
|
463
|
+
['tabview', TabView],
|
|
464
|
+
['tabviewitem', TabViewItem],
|
|
465
|
+
@@ -65,8 +63,8 @@ const BUILTIN_ELEMENTS = [
|
|
466
|
+
['textview', TextView],
|
|
467
|
+
['timepicker', TimePicker],
|
|
468
|
+
['webview', WebView],
|
|
469
|
+
- ['wraplayout', WrapLayout],
|
|
470
|
+
['liquidglass', LiquidGlass],
|
|
471
|
+
+ ['masonview', MasonView],
|
|
472
|
+
];
|
|
473
|
+
for (const [tag, element] of BUILTIN_ELEMENTS)
|
|
474
|
+
registerElement(tag, element);
|
|
475
|
+
diff --git a/dist/intrinsics.d.ts b/dist/intrinsics.d.ts
|
|
476
|
+
index 45a47cb..668c920 100644
|
|
477
|
+
--- a/dist/intrinsics.d.ts
|
|
478
|
+
+++ b/dist/intrinsics.d.ts
|
|
479
|
+
@@ -24,9 +24,9 @@
|
|
480
|
+
*/
|
|
481
|
+
import type * as NS from '@nativescript/core';
|
|
482
|
+
export type NativeScriptNode = unknown;
|
|
483
|
+
-type Ref<TInstance> = ((instance: TInstance | null) => void) | {
|
|
484
|
+
+type Ref<TInstance> = ((instance: TInstance | null) => void | (() => void)) | {
|
|
485
|
+
current: TInstance | null;
|
|
486
|
+
-} | null;
|
|
487
|
+
+} | readonly Ref<TInstance>[] | null | undefined;
|
|
488
|
+
/**
|
|
489
|
+
* The driver assigns every non-event prop onto the view instance, so a JSX
|
|
490
|
+
* attribute is a NativeScript view property rather than a DOM attribute.
|
|
491
|
+
@@ -76,34 +76,67 @@ export interface CommonEvents<TInstance> {
|
|
492
|
+
export type ClassValue = string | boolean | null | undefined | readonly ClassValue[] | {
|
|
493
|
+
readonly [className: string]: unknown;
|
|
494
|
+
};
|
|
495
|
+
+/** Mason engine style keys accepted through `style`/`className` — under a
|
|
496
|
+
+ * masonview parent a child's leaf style consumes them; on a masonview they
|
|
497
|
+
+ * are the container's own layout. These are the only way to set raw layout
|
|
498
|
+
+ * properties: direct props of the same names are rejected by the driver. */
|
|
499
|
+
+export interface MasonStyleProps {
|
|
500
|
+
+ display?: string;
|
|
501
|
+
+ position?: string;
|
|
502
|
+
+ inset?: number | string;
|
|
503
|
+
+ left?: number | string;
|
|
504
|
+
+ top?: number | string;
|
|
505
|
+
+ right?: number | string;
|
|
506
|
+
+ bottom?: number | string;
|
|
507
|
+
+ direction?: string;
|
|
508
|
+
+ boxSizing?: string;
|
|
509
|
+
+ flexDirection?: string;
|
|
510
|
+
+ flexWrap?: string;
|
|
511
|
+
+ justifyContent?: string;
|
|
512
|
+
+ justifyItems?: string;
|
|
513
|
+
+ justifySelf?: string;
|
|
514
|
+
+ alignItems?: string;
|
|
515
|
+
+ alignContent?: string;
|
|
516
|
+
+ alignSelf?: string;
|
|
517
|
+
+ textAlign?: string;
|
|
518
|
+
+ gap?: number | string;
|
|
519
|
+
+ rowGap?: number | string;
|
|
520
|
+
+ columnGap?: number | string;
|
|
521
|
+
+ flexGrow?: number;
|
|
522
|
+
+ flexShrink?: number;
|
|
523
|
+
+ flexBasis?: number | string;
|
|
524
|
+
+ order?: number;
|
|
525
|
+
+ aspectRatio?: number;
|
|
526
|
+
+ overflow?: string;
|
|
527
|
+
+ overflowX?: string;
|
|
528
|
+
+ overflowY?: string;
|
|
529
|
+
+ scrollbarWidth?: number;
|
|
530
|
+
+ gridTemplateRows?: string;
|
|
531
|
+
+ gridTemplateColumns?: string;
|
|
532
|
+
+ gridTemplateAreas?: string;
|
|
533
|
+
+ gridAutoFlow?: string;
|
|
534
|
+
+ gridAutoRows?: string;
|
|
535
|
+
+ gridAutoColumns?: string;
|
|
536
|
+
+ gridRow?: string;
|
|
537
|
+
+ gridColumn?: string;
|
|
538
|
+
+ gridRowStart?: string | number;
|
|
539
|
+
+ gridRowEnd?: string | number;
|
|
540
|
+
+ gridColumnStart?: string | number;
|
|
541
|
+
+ gridColumnEnd?: string | number;
|
|
542
|
+
+ gridArea?: string;
|
|
543
|
+
+}
|
|
544
|
+
export interface CommonAttributes {
|
|
545
|
+
/** Resolved against `app.css`. */
|
|
546
|
+
className?: ClassValue;
|
|
547
|
+
class?: ClassValue;
|
|
548
|
+
/** A string is parsed as inline CSS; an object is assigned onto `view.style`. */
|
|
549
|
+
- style?: string | Partial<NS.Style>;
|
|
550
|
+
+ style?: string | Partial<NS.Style> | MasonStyleProps;
|
|
551
|
+
/**
|
|
552
|
+
* Name of the property on a slot-hosting parent (e.g. a drawer's
|
|
553
|
+
* `mainContent` / `leftDrawer`) this child should be assigned to instead of
|
|
554
|
+
* being added as a regular layout child.
|
|
555
|
+
*/
|
|
556
|
+
hostSlot?: string;
|
|
557
|
+
- /**
|
|
558
|
+
- * Attached layout properties. The layout modules register these on `View` at
|
|
559
|
+
- * runtime, so they are absent from the `@nativescript/core` class typings.
|
|
560
|
+
- */
|
|
561
|
+
- row?: number | string;
|
|
562
|
+
- col?: number | string;
|
|
563
|
+
- rowSpan?: number | string;
|
|
564
|
+
- colSpan?: number | string;
|
|
565
|
+
- dock?: 'top' | 'right' | 'bottom' | 'left';
|
|
566
|
+
- left?: number | string;
|
|
567
|
+
- top?: number | string;
|
|
568
|
+
- flexGrow?: number | string;
|
|
569
|
+
- flexShrink?: number | string;
|
|
570
|
+
- flexWrapBefore?: boolean | string;
|
|
571
|
+
- alignSelf?: 'auto' | 'flex-start' | 'flex-end' | 'center' | 'baseline' | 'stretch';
|
|
572
|
+
- order?: number | string;
|
|
573
|
+
}
|
|
574
|
+
export interface ListViewAttributes {
|
|
575
|
+
/**
|
|
576
|
+
@@ -117,25 +150,21 @@ export interface ListViewAttributes {
|
|
577
|
+
}
|
|
578
|
+
export interface OctaneAttributes<TInstance> {
|
|
579
|
+
key?: string | number;
|
|
580
|
+
- ref?: Ref<TInstance> | readonly Ref<TInstance>[];
|
|
581
|
+
+ ref?: Ref<TInstance>;
|
|
582
|
+
children?: NativeScriptNode;
|
|
583
|
+
}
|
|
584
|
+
type Overridden = keyof CommonAttributes | keyof OctaneAttributes<unknown> | keyof CommonEvents<unknown>;
|
|
585
|
+
/** Props of a JSX tag backed by a `@nativescript/core`-style view class; the type to use for app-registered tags. */
|
|
586
|
+
export type Attributes<TClass extends abstract new (...args: never[]) => unknown> = Omit<ViewProperties<InstanceType<TClass>> & DerivedEvents<TClass, InstanceType<TClass>>, Overridden> & CommonAttributes & CommonEvents<InstanceType<TClass>> & OctaneAttributes<InstanceType<TClass>>;
|
|
587
|
+
export interface NativeScriptElements {
|
|
588
|
+
- absolutelayout: Attributes<typeof NS.AbsoluteLayout>;
|
|
589
|
+
actionbar: Attributes<typeof NS.ActionBar>;
|
|
590
|
+
actionitem: Attributes<typeof NS.ActionItem>;
|
|
591
|
+
activityindicator: Attributes<typeof NS.ActivityIndicator>;
|
|
592
|
+
button: Attributes<typeof NS.Button>;
|
|
593
|
+
contentview: Attributes<typeof NS.ContentView>;
|
|
594
|
+
datepicker: Attributes<typeof NS.DatePicker>;
|
|
595
|
+
- docklayout: Attributes<typeof NS.DockLayout>;
|
|
596
|
+
- flexboxlayout: Attributes<typeof NS.FlexboxLayout>;
|
|
597
|
+
formattedstring: Attributes<typeof NS.FormattedString>;
|
|
598
|
+
frame: Attributes<typeof NS.Frame>;
|
|
599
|
+
- gridlayout: Attributes<typeof NS.GridLayout>;
|
|
600
|
+
htmlview: Attributes<typeof NS.HtmlView>;
|
|
601
|
+
image: Attributes<typeof NS.Image>;
|
|
602
|
+
label: Attributes<typeof NS.Label>;
|
|
603
|
+
@@ -153,7 +182,6 @@ export interface NativeScriptElements {
|
|
604
|
+
segmentedbaritem: Attributes<typeof NS.SegmentedBarItem>;
|
|
605
|
+
slider: Attributes<typeof NS.Slider>;
|
|
606
|
+
span: Attributes<typeof NS.Span>;
|
|
607
|
+
- stacklayout: Attributes<typeof NS.StackLayout>;
|
|
608
|
+
switch: Attributes<typeof NS.Switch>;
|
|
609
|
+
tabview: Attributes<typeof NS.TabView>;
|
|
610
|
+
tabviewitem: Attributes<typeof NS.TabViewItem>;
|
|
611
|
+
@@ -161,7 +189,8 @@ export interface NativeScriptElements {
|
|
612
|
+
textview: Attributes<typeof NS.TextView>;
|
|
613
|
+
timepicker: Attributes<typeof NS.TimePicker>;
|
|
614
|
+
webview: Attributes<typeof NS.WebView>;
|
|
615
|
+
- wraplayout: Attributes<typeof NS.WrapLayout>;
|
|
616
|
+
+ /** The single layout container — all layout flows through `style`/`className`; layout prop names are rejected by the driver. */
|
|
617
|
+
+ masonview: Attributes<typeof NS.View>;
|
|
618
|
+
/** iOS 26 glass surface (plain layout elsewhere); behaves as a GridLayout. */
|
|
619
|
+
liquidglass: Attributes<typeof NS.LiquidGlass>;
|
|
620
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
diff --git a/dist/android-tools-info.js b/dist/android-tools-info.js
|
|
2
|
+
index ed84fd1c23bbc3161d40fdd7c65dbd842704696c..ef647fb6b834a5fdf4d09da5e920e8befce1e6f2 100644
|
|
3
|
+
--- a/dist/android-tools-info.js
|
|
4
|
+
+++ b/dist/android-tools-info.js
|
|
5
|
+
@@ -383,7 +383,7 @@ class AndroidToolsInfo {
|
|
6
|
+
});
|
|
7
|
+
if (foundRuntime) {
|
|
8
|
+
let version = content.devDependencies[foundRuntime];
|
|
9
|
+
- if (version.includes("tgz")) {
|
|
10
|
+
+ if (version.includes("tgz") || version.startsWith("catalog:")) {
|
|
11
|
+
try {
|
|
12
|
+
const packagePath = require.resolve(`${foundRuntime}/package.json`, {
|
|
13
|
+
paths: [projectDir],
|
|
@@ -107,6 +107,43 @@ index a05696b679b3feecd1bafa267de44b59db559162..06648067a3fcf7f8c74437a82b94ec01
|
|
|
107
107
|
}
|
|
108
108
|
return ['.native', ''];
|
|
109
109
|
}
|
|
110
|
+
diff --git a/hmr/helpers/ast-normalizer.js b/hmr/helpers/ast-normalizer.js
|
|
111
|
+
index c6113c74247db616609b87d7f365c4d4c199c934..73651a1fd1892555cc5dd57bcefb9e93d30516b6 100644
|
|
112
|
+
--- a/hmr/helpers/ast-normalizer.js
|
|
113
|
+
+++ b/hmr/helpers/ast-normalizer.js
|
|
114
|
+
@@ -86,9 +86,10 @@ export function astNormalizeModuleImportsAndHelpers(code, opts) {
|
|
115
|
+
// path (e.g. `html-entities` when not in optimizeDeps) — those must be
|
|
116
|
+
// rewritten to the bare id (see below), not removed; removing them
|
|
117
|
+
// left consumer bindings undefined (`decode is not defined`).
|
|
118
|
+
+ // User virtual stylesheets must reach the native CSS registration route.
|
|
119
|
+
// Exemption: oxc runtime helper virtuals are real servable URLs that
|
|
120
|
+
// downstream passes preserve/origin-prefix — keep them here too.
|
|
121
|
+
- const isViteVirtual = (src) => !!src && (/\0/.test(src) || /__x00__/.test(src)) && !src.includes('__x00__@oxc-project+runtime');
|
|
122
|
+
+ const isViteVirtual = (src) => !!src && (/\0/.test(src) || /__x00__/.test(src)) && !src.includes('__x00__@oxc-project+runtime') && !/\.(css|scss|sass|less|styl|stylus)(?:[?#]|$)/i.test(src);
|
|
123
|
+
const realIdPrefixed = (src) => {
|
|
124
|
+
if (!src || !src.startsWith('/@id/'))
|
|
125
|
+
return null;
|
|
126
|
+
diff --git a/hmr/server/css-device-module.js b/hmr/server/css-device-module.js
|
|
127
|
+
index 0d7cd968eac690a85411cf3d6a24323a3d3a3992..98094d6ccfb918d00249d8087aebdd994b64244d 100644
|
|
128
|
+
--- a/hmr/server/css-device-module.js
|
|
129
|
+
+++ b/hmr/server/css-device-module.js
|
|
130
|
+
@@ -41,4 +41,15 @@ export function buildCssRegisterSnippet(tag, cssText) {
|
|
131
|
+
export function buildCssRegisterSnippetFromVar(tag, varName) {
|
|
132
|
+
return buildRegisterCall(JSON.stringify(tag), varName);
|
|
133
|
+
}
|
|
134
|
+
+/** Bridge only plugin-provided virtual stylesheets; file CSS has its own hot-update path. */
|
|
135
|
+
+export function virtualCssUpdates(payload) {
|
|
136
|
+
+ if (payload?.type !== 'update') return [];
|
|
137
|
+
+ return (payload.updates || []).flatMap((update) => {
|
|
138
|
+
+ if (update.type !== 'css-update' && update.type !== 'js-update') return [];
|
|
139
|
+
+ let spec = update.path?.split(/[?#]/)[0];
|
|
140
|
+
+ if (spec?.startsWith('\0')) spec = '/@id/' + spec.replace(/\0/g, '__x00__');
|
|
141
|
+
+ if (!spec?.startsWith('/@id/__x00__') || !CSS_MODULE_RE.test(spec)) return [];
|
|
142
|
+
+ return [{ type: 'css-update', path: '/ns/m' + spec, acceptedPath: '/ns/m' + spec, tag: spec, timestamp: update.timestamp }];
|
|
143
|
+
+ });
|
|
144
|
+
+}
|
|
145
|
+
//# sourceMappingURL=css-device-module.js.map
|
|
146
|
+
|
|
110
147
|
diff --git a/hmr/server/deps-bundle.js b/hmr/server/deps-bundle.js
|
|
111
148
|
index 8f2fa15556244f7ef811b5e2ea0fc6a19bab74d3..80137262ec46d347d39a7ee12d66d649b5f909f5 100644
|
|
112
149
|
--- a/hmr/server/deps-bundle.js
|
|
@@ -166,11 +203,41 @@ index 71574c48f655183af0c9601b020fd1febd63ccb3..0061d9c9e9fe9c6034576eae8449831d
|
|
|
166
203
|
if (!imports.length) {
|
|
167
204
|
return code;
|
|
168
205
|
}
|
|
206
|
+
diff --git a/hmr/server/process-code-for-device.js b/hmr/server/process-code-for-device.js
|
|
207
|
+
index c71d457806a8add919f7e2368e7ebc349bd908e7..998eb268ed0db1200f8b5ce30fc7da211125406f 100644
|
|
208
|
+
--- a/hmr/server/process-code-for-device.js
|
|
209
|
+
+++ b/hmr/server/process-code-for-device.js
|
|
210
|
+
@@ -1,3 +1,4 @@
|
|
211
|
+
+import { CSS_MODULE_RE } from './css-device-module.js';
|
|
212
|
+
// Device code-transform: cleans Vite/framework noise out of a served module,
|
|
213
|
+
// injects NativeScript build globals + the process.env shim, normalizes
|
|
214
|
+
// imports/helpers for the on-device ESM runtime, and collects an importer's
|
|
215
|
+
@@ -451,13 +452,13 @@ function processCodeForDevice(code, isVitePreBundled, preserveVendorImports = fa
|
|
216
|
+
// Unlike other virtual ids these are real, servable dev-server URLs returning
|
|
217
|
+
// self-contained ESM — stripping them leaves `_decorate`/`_decorateMetadata`
|
|
218
|
+
// undefined at runtime. They're origin-prefixed for the device in rewriteImports.
|
|
219
|
+
- result = result.replace(/import\s+[^;]+\s+from\s+["']\/@id\/(?!__x00__@oxc-project\+runtime)[^"']*["'];?\s*/g, '');
|
|
220
|
+
+ result = result.replace(/import\s+[^;]+\s+from\s+["'](\/@id\/(?!__x00__@oxc-project\+runtime)[^"']*)["'];?\s*/g, (statement, spec) => CSS_MODULE_RE.test(spec) ? statement : '');
|
|
221
|
+
// Also remove side-effect only virtual id imports like: import "/@id/__x00__vite/dynamic-import-helper.js";
|
|
222
|
+
// These can slip through and cause the NativeScript runtime to attempt resolving
|
|
223
|
+
// a non-existent physical file (e.g. /@id/__x00__vite/dynamic-import-helper.js) leading to
|
|
224
|
+
// module not found crashes during HMR evaluation.
|
|
225
|
+
if (/^[\t ]*import\s+["']\/@id\/[^"']+["'];?\s*$/m.test(result)) {
|
|
226
|
+
- result = result.replace(/^[\t ]*import\s+["']\/@id\/[^"']+["'];?\s*$/gm, '');
|
|
227
|
+
+ result = result.replace(/^[\t ]*import\s+["'](\/@id\/[^"']+)["'];?\s*$/gm, (statement, spec) => CSS_MODULE_RE.test(spec) ? statement : '');
|
|
228
|
+
// Inject a lightweight marker comment (harmless if left in output) so devs can confirm rewrite took place when viewing streamed artifact.
|
|
229
|
+
result = `// [hmr-sanitize] stripped virtual /@id/ side-effect imports\n${result}`;
|
|
230
|
+
}
|
|
169
231
|
diff --git a/hmr/server/rewrite-imports.js b/hmr/server/rewrite-imports.js
|
|
170
|
-
index 4a6575cb00a6aeecbbb7ac5ccac3268cb10d7f54..
|
|
232
|
+
index 4a6575cb00a6aeecbbb7ac5ccac3268cb10d7f54..2876cf3694c278249b9db182e2f89df34cc464f3 100644
|
|
171
233
|
--- a/hmr/server/rewrite-imports.js
|
|
172
234
|
+++ b/hmr/server/rewrite-imports.js
|
|
173
|
-
@@ -
|
|
235
|
+
@@ -1,3 +1,4 @@
|
|
236
|
+
+import { CSS_MODULE_RE } from './css-device-module.js';
|
|
237
|
+
// THE SINGLE import-rewrite function — used everywhere for consistency. Maps a
|
|
238
|
+
// served module's specifiers to device-reachable forms: the unified /ns/core
|
|
239
|
+
// bridge, /ns/m node_modules + app modules, /ns/sfc for Vue, vendor bare specs,
|
|
240
|
+
@@ -12,7 +13,93 @@ import { resolveAngularCoreHmrImportSource, rewriteAngularEntryRegisterOnly } fr
|
|
174
241
|
import { isNativeScriptCoreModule, isNativeScriptPluginModule, normalizeNativeScriptCoreSpecifier, normalizeNodeModulesSpecifier, resolveNodeModulesPackageBoundary, resolveVendorRouting, rewriteFsAbsoluteToNsM, shouldPreserveBareRuntimePluginSubpathImport } from './websocket-module-specifiers.js';
|
|
175
242
|
import { ensureDynamicHmrImportHelper } from './websocket-served-module-helpers.js';
|
|
176
243
|
import { collectMixedRuntimePluginHttpRootPackages, findDependencyFileName, getProjectRelativeImportPath, isApplicationImport, normalizeImportPath, stripToProjectRelative, toAppModuleBaseId, toNodeModulesHttpModuleId } from './device-transform-helpers.js';
|
|
@@ -264,7 +331,7 @@ index 4a6575cb00a6aeecbbb7ac5ccac3268cb10d7f54..ea97dfe6c895bb6b80b0c0403c866630
|
|
|
264
331
|
export function prepareAngularEntryForDevice(code, importerPath, sfcFileMap, depFileMap, projectRoot, verbose = false, outputDirOverrideRel, httpOrigin, resolveVendorAsHttp = false) {
|
|
265
332
|
const rewrittenCode = rewriteImports(code, importerPath, sfcFileMap, depFileMap, projectRoot, verbose, outputDirOverrideRel, httpOrigin, resolveVendorAsHttp);
|
|
266
333
|
return rewriteAngularEntryRegisterOnly(rewrittenCode, resolveAngularCoreHmrImportSource(rewrittenCode, httpOrigin));
|
|
267
|
-
@@ -236,6 +
|
|
334
|
+
@@ -236,6 +323,19 @@ export function rewriteImports(code, importerPath, sfcFileMap, depFileMap, proje
|
|
268
335
|
}
|
|
269
336
|
return `${prefix}${stub}${suffix}`;
|
|
270
337
|
}
|
|
@@ -284,7 +351,7 @@ index 4a6575cb00a6aeecbbb7ac5ccac3268cb10d7f54..ea97dfe6c895bb6b80b0c0403c866630
|
|
|
284
351
|
spec = normalizeNativeScriptCoreSpecifier(spec);
|
|
285
352
|
// Pull `/@fs/<abs-path>` URLs back into the `/ns/m/` pipeline so they
|
|
286
353
|
// hit our CJS/UMD-wrapping handler. Vite emits `/@fs/...` for any
|
|
287
|
-
@@ -253,
|
|
354
|
+
@@ -253,17 +353,39 @@ export function rewriteImports(code, importerPath, sfcFileMap, depFileMap, proje
|
|
288
355
|
}
|
|
289
356
|
return `${prefix}${rewritten}${suffix}`;
|
|
290
357
|
}
|
|
@@ -319,17 +386,32 @@ index 4a6575cb00a6aeecbbb7ac5ccac3268cb10d7f54..ea97dfe6c895bb6b80b0c0403c866630
|
|
|
319
386
|
}
|
|
320
387
|
// Vite 8 oxc runtime helpers (decorators etc.) — emitted as
|
|
321
388
|
// `/@id/__x00__@oxc-project+runtime@<ver>/helpers/<name>.js`. These are
|
|
389
|
+
// real dev-server URLs serving self-contained ESM, so just origin-prefix
|
|
390
|
+
// them for the device; no /ns/m wrapping needed (processCodeForDevice
|
|
391
|
+
// exempts them from the generic /@id/ strip for the same reason).
|
|
392
|
+
+ // User virtual CSS needs native compilation/registration, never the DOM module.
|
|
393
|
+
+ if (spec.startsWith('/@id/') && CSS_MODULE_RE.test(spec)) {
|
|
394
|
+
+ return `${prefix}${httpOriginSafe || ''}/ns/m${spec}${suffix}`;
|
|
395
|
+
+ }
|
|
396
|
+
if (spec.startsWith('/@id/__x00__@oxc-project+runtime')) {
|
|
397
|
+
if (httpOriginSafe) {
|
|
398
|
+
return `${prefix}${httpOriginSafe}${spec}${suffix}`;
|
|
322
399
|
diff --git a/hmr/server/websocket-module-specifiers.js b/hmr/server/websocket-module-specifiers.js
|
|
323
|
-
index 74f50a77f48f3873aebf375a29d06b16c29440a3..
|
|
400
|
+
index 74f50a77f48f3873aebf375a29d06b16c29440a3..0f06b6dc997118473e4a1ac6d3a3c48432311c71 100644
|
|
324
401
|
--- a/hmr/server/websocket-module-specifiers.js
|
|
325
402
|
+++ b/hmr/server/websocket-module-specifiers.js
|
|
326
|
-
@@ -1,
|
|
403
|
+
@@ -1,8 +1,8 @@
|
|
327
404
|
-import { existsSync, readdirSync, readFileSync, realpathSync } from 'fs';
|
|
328
405
|
+import { existsSync, readdirSync, readFileSync, realpathSync, statSync } from 'fs';
|
|
329
406
|
import * as path from 'path';
|
|
330
407
|
import * as PAT from './constants.js';
|
|
331
408
|
import { getVendorManifest, resolveVendorSpecifier } from '../shared/vendor/registry.js';
|
|
332
|
-
|
|
409
|
+
-import { getProjectRootPath } from '../../helpers/project.js';
|
|
410
|
+
+import { getMonorepoWorkspaceRoot, getProjectRootPath } from '../../helpers/project.js';
|
|
411
|
+
import { extractRootPackageName, getPackageRuntimeInfo } from '../shared/package-classifier.js';
|
|
412
|
+
import { getFlavorClientPackages } from '../framework-flavors.js';
|
|
413
|
+
const ESM_FRAMEWORK_PACKAGE_ROOTS = new Set(['@nativescript/angular', 'nativescript-angular']);
|
|
414
|
+
@@ -328,6 +328,76 @@ export function resolveVendorFromCandidate(specifier) {
|
|
333
415
|
}
|
|
334
416
|
return null;
|
|
335
417
|
}
|
|
@@ -339,7 +421,8 @@ index 74f50a77f48f3873aebf375a29d06b16c29440a3..cc196fb6b92d48179bf8e124ba2a2aa9
|
|
|
339
421
|
+ * its workspace layout — consulted when neither the project root nor the
|
|
340
422
|
+ * workspace root can anchor a served `/node_modules/` tail:
|
|
341
423
|
+ * - `link:`/`file:`/`portal:` deps keep their own `node_modules` at the real
|
|
342
|
-
+ * target;
|
|
424
|
+
+ * target; their workspace siblings can own transitive deps too. Reuse the
|
|
425
|
+
+ * bounded workspace scan rather than recursively walking dependency trees.
|
|
343
426
|
+ * - pnpm's isolated virtual store keeps every non-hoisted package under
|
|
344
427
|
+ * `node_modules/.pnpm/<name>@<ver>/node_modules/`.
|
|
345
428
|
+ * Importer info is gone from the URL — first hit wins, same as the workspace
|
|
@@ -351,9 +434,13 @@ index 74f50a77f48f3873aebf375a29d06b16c29440a3..cc196fb6b92d48179bf8e124ba2a2aa9
|
|
|
351
434
|
+ return cached;
|
|
352
435
|
+ }
|
|
353
436
|
+ const dirs = [];
|
|
437
|
+
+ const seen = new Set();
|
|
438
|
+
+ const linkedWorkspaces = new Set();
|
|
354
439
|
+ const pushIfPresent = (dir) => {
|
|
355
|
-
+ if (existsSync(dir))
|
|
440
|
+
+ if (!seen.has(dir) && existsSync(dir)) {
|
|
441
|
+
+ seen.add(dir);
|
|
356
442
|
+ dirs.push(dir);
|
|
443
|
+
+ }
|
|
357
444
|
+ };
|
|
358
445
|
+ const pnpmStore = path.join(projectRoot, 'node_modules', '.pnpm');
|
|
359
446
|
+ try {
|
|
@@ -374,8 +461,12 @@ index 74f50a77f48f3873aebf375a29d06b16c29440a3..cc196fb6b92d48179bf8e124ba2a2aa9
|
|
|
374
461
|
+ continue;
|
|
375
462
|
+ try {
|
|
376
463
|
+ const depDir = realpathSync(path.resolve(projectRoot, target));
|
|
377
|
-
+ if (statSync(depDir).isDirectory())
|
|
464
|
+
+ if (statSync(depDir).isDirectory()) {
|
|
378
465
|
+ pushIfPresent(path.join(depDir, 'node_modules'));
|
|
466
|
+
+ const workspace = getMonorepoWorkspaceRoot(depDir);
|
|
467
|
+
+ if (workspace)
|
|
468
|
+
+ linkedWorkspaces.add(workspace);
|
|
469
|
+
+ }
|
|
379
470
|
+ }
|
|
380
471
|
+ catch {
|
|
381
472
|
+ }
|
|
@@ -384,13 +475,20 @@ index 74f50a77f48f3873aebf375a29d06b16c29440a3..cc196fb6b92d48179bf8e124ba2a2aa9
|
|
|
384
475
|
+ }
|
|
385
476
|
+ catch {
|
|
386
477
|
+ }
|
|
478
|
+
+ // Preserve direct-dependency precedence. Scan each linked workspace once,
|
|
479
|
+
+ // using the existing two-level package scan and its per-workspace cache.
|
|
480
|
+
+ for (const workspace of linkedWorkspaces) {
|
|
481
|
+
+ pushIfPresent(path.join(workspace, 'node_modules'));
|
|
482
|
+
+ for (const dir of listWorkspaceNodeModulesDirs(workspace))
|
|
483
|
+
+ pushIfPresent(dir);
|
|
484
|
+
+ }
|
|
387
485
|
+ depFallbackDirsCache.set(projectRoot, dirs);
|
|
388
486
|
+ return dirs;
|
|
389
487
|
+}
|
|
390
488
|
const workspaceNodeModulesDirsCache = new Map();
|
|
391
489
|
/**
|
|
392
490
|
* `node_modules` dirs that can hold a package the served URL no longer
|
|
393
|
-
@@ -428,6 +
|
|
491
|
+
@@ -428,6 +498,16 @@ export function resolveCandidateFilePath(candidate, projectRoot, workspaceRoot)
|
|
394
492
|
}
|
|
395
493
|
}
|
|
396
494
|
}
|
|
@@ -407,14 +505,26 @@ index 74f50a77f48f3873aebf375a29d06b16c29440a3..cc196fb6b92d48179bf8e124ba2a2aa9
|
|
|
407
505
|
return null;
|
|
408
506
|
}
|
|
409
507
|
/**
|
|
410
|
-
@@ -
|
|
508
|
+
@@ -512,8 +592,8 @@ export function rewriteFsAbsoluteToNsM(spec, projectRoot, workspaceRoot) {
|
|
509
|
+
* `export const X: string = '...'`. Routing through the realpath makes
|
|
510
|
+
* Vite see a non-`node_modules` path and the TS transform applies.
|
|
511
|
+
*
|
|
512
|
+
- * App-local candidates whose real path is also app-local are returned
|
|
513
|
+
- * unchanged so existing behaviour is preserved bit-for-bit.
|
|
514
|
+
+ * Candidates are returned unchanged only when their URL addresses the file
|
|
515
|
+
+ * found. Fallback files need filesystem anchors even inside the app root.
|
|
516
|
+
*/
|
|
517
|
+
export function filterExistingNodeModulesTransformCandidates(spec, candidates, projectRoot, workspaceRoot) {
|
|
518
|
+
const cleanedSpec = spec.replace(PAT.QUERY_PATTERN, '');
|
|
519
|
+
@@ -557,22 +637,18 @@ export function filterExistingNodeModulesTransformCandidates(spec, candidates, p
|
|
411
520
|
// through to the existing project/workspace logic.
|
|
412
521
|
}
|
|
413
522
|
if (mapped === null) {
|
|
414
523
|
- if (!hasDistinctWorkspaceRoot) {
|
|
415
|
-
+ const
|
|
416
|
-
+
|
|
417
|
-
+
|
|
524
|
+
+ const candidatePath = cleanedCandidate.startsWith('/@fs/')
|
|
525
|
+
+ ? path.resolve(cleanedCandidate.slice('/@fs'.length))
|
|
526
|
+
+ : path.resolve(resolvedProjectRoot, cleanedCandidate.replace(/^\/+/, ''));
|
|
527
|
+
+ if (candidatePath === resolved) {
|
|
418
528
|
mapped = candidate;
|
|
419
529
|
}
|
|
420
530
|
else {
|
|
@@ -430,10 +540,10 @@ index 74f50a77f48f3873aebf375a29d06b16c29440a3..cc196fb6b92d48179bf8e124ba2a2aa9
|
|
|
430
540
|
- // hoisted package's `exports` field may refuse.
|
|
431
541
|
- mapped = `/@fs${resolved.replace(/\\/g, '/')}${querySuffix}`;
|
|
432
542
|
- }
|
|
433
|
-
+ //
|
|
434
|
-
+ //
|
|
435
|
-
+ //
|
|
436
|
-
+ //
|
|
543
|
+
+ // The candidate URL does not address the discovered file. A
|
|
544
|
+
+ // fallback may live inside the project (nested link: dependency
|
|
545
|
+
+ // or pnpm store) as well as outside it (hoisted dependency).
|
|
546
|
+
+ // Anchor the actual path so Vite loads the same file we found.
|
|
437
547
|
+ mapped = `/@fs${resolved.replace(/\\/g, '/')}${querySuffix}`;
|
|
438
548
|
}
|
|
439
549
|
}
|
|
@@ -475,6 +585,80 @@ index a11fbd5d24579cdf572a91f70cb06561bfa43cd0..c887334efce2c2f6cf85c75082761094
|
|
|
475
585
|
}
|
|
476
586
|
}
|
|
477
587
|
return null;
|
|
588
|
+
diff --git a/hmr/server/websocket-ns-m.js b/hmr/server/websocket-ns-m.js
|
|
589
|
+
index 63b5d9a4886d8da03b8e7deac8a16d53347ea5d7..0f92b3377e6d697f5e5c9eafad130d9579078d93 100644
|
|
590
|
+
--- a/hmr/server/websocket-ns-m.js
|
|
591
|
+
+++ b/hmr/server/websocket-ns-m.js
|
|
592
|
+
@@ -97,7 +97,7 @@ export function registerNsModuleServerRoute(server, options) {
|
|
593
|
+
// internal virtual modules (e.g., \0nsvite:nsconfig-json for
|
|
594
|
+
// ~/package.json) that don't exist on disk and must NOT run
|
|
595
|
+
// through the device post-processing pipeline below.
|
|
596
|
+
- if (spec.startsWith('/@id/')) {
|
|
597
|
+
+ if (spec.startsWith('/@id/') && !CSS_MODULE_RE.test(spec)) {
|
|
598
|
+
try {
|
|
599
|
+
// First try Vite's transform pipeline directly
|
|
600
|
+
const vr = await sharedTransformRequest(spec);
|
|
601
|
+
@@ -157,8 +157,21 @@ export function registerNsModuleServerRoute(server, options) {
|
|
602
|
+
// Workspace css outside the vite root must be anchored to /@fs or
|
|
603
|
+
// `?inline` is denied and the DOM css module (__vite__updateStyle)
|
|
604
|
+
// is served instead.
|
|
605
|
+
- const inlineSpec = resolveFsAnchoredSpec(spec, serverRoot, monorepoWorkspaceRoot) || spec;
|
|
606
|
+
- const inlineRes = await sharedTransformRequest(`${inlineSpec}?inline`);
|
|
607
|
+
+ const inlineSpec = spec.startsWith('/@id/')
|
|
608
|
+
+ ? spec.slice('/@id/'.length).replace(/__x00__/g, '\0')
|
|
609
|
+
+ : resolveFsAnchoredSpec(spec, serverRoot, monorepoWorkspaceRoot) || spec;
|
|
610
|
+
+ // Keep the canonical sheet's watch edges and CSS HMR boundary alive.
|
|
611
|
+
+ // The inline variant alone is not the node stylesheet plugins reload.
|
|
612
|
+
+ const virtualCss = spec.startsWith('/@id/');
|
|
613
|
+
+ // Plugin reloads can invalidate only the canonical sheet, not its
|
|
614
|
+
+ // inline sibling or the NativeScript transform-result TTL cache.
|
|
615
|
+
+ const compileCss = virtualCss ? (url) => server.transformRequest(url) : sharedTransformRequest;
|
|
616
|
+
+ if (virtualCss) {
|
|
617
|
+
+ await compileCss(inlineSpec);
|
|
618
|
+
+ const inlineModule = server.moduleGraph.getModuleById(`${inlineSpec}?inline`);
|
|
619
|
+
+ if (inlineModule) server.moduleGraph.invalidateModule(inlineModule);
|
|
620
|
+
+ }
|
|
621
|
+
+ const inlineRes = await compileCss(`${inlineSpec}?inline`);
|
|
622
|
+
const inlineCode = inlineRes?.code || '';
|
|
623
|
+
// `?inline` output is `export default "<compiled css>"`.
|
|
624
|
+
const m = inlineCode.match(/export\s+default\s+("(?:[^"\\]|\\.)*")\s*;?/s);
|
|
625
|
+
@@ -168,7 +181,14 @@ export function registerNsModuleServerRoute(server, options) {
|
|
626
|
+
css = JSON.parse(m[1]);
|
|
627
|
+
}
|
|
628
|
+
catch { }
|
|
629
|
+
- css = normalizeCssForDevice(css);
|
|
630
|
+
+ css = normalizeCssForDevice(css) || '/* empty stylesheet */';
|
|
631
|
+
+ // HMR fetches adapted text through this same compiler and tag.
|
|
632
|
+
+ if (urlObj.searchParams.has('direct')) {
|
|
633
|
+
+ res.setHeader('Content-Type', 'text/css; charset=utf-8');
|
|
634
|
+
+ res.statusCode = 200;
|
|
635
|
+
+ res.end(css);
|
|
636
|
+
+ return;
|
|
637
|
+
+ }
|
|
638
|
+
const out = `// [ns:m][css] ${spec}\n` + `const __ns_css_text__ = ${JSON.stringify(css)};\n` + buildCssRegisterSnippetFromVar(spec, '__ns_css_text__') + `export default __ns_css_text__;\n`;
|
|
639
|
+
res.statusCode = 200;
|
|
640
|
+
res.end(out);
|
|
641
|
+
@@ -181,7 +201,10 @@ export function registerNsModuleServerRoute(server, options) {
|
|
642
|
+
if (verbose)
|
|
643
|
+
console.warn('[ns:m][css] inline compile failed', spec, cssErr?.message);
|
|
644
|
+
}
|
|
645
|
+
- // Fall through to default handling if inline compile produced nothing.
|
|
646
|
+
+ // Never send raw CSS or a DOM injection module to the native loader.
|
|
647
|
+
+ res.statusCode = 500;
|
|
648
|
+
+ res.end('throw new Error(' + JSON.stringify('[ns:m] CSS compilation failed: ' + spec) + ');');
|
|
649
|
+
+ return;
|
|
650
|
+
}
|
|
651
|
+
// Queue and dedupe transformRequest calls so heavy app graphs do not
|
|
652
|
+
// overwhelm Vite with concurrent work. Slow-transform warnings start only
|
|
653
|
+
@@ -503,6 +526,8 @@ export function registerNsModuleServerRoute(server, options) {
|
|
654
|
+
continue;
|
|
655
|
+
}
|
|
656
|
+
else if (u.pathname.startsWith('/ns/m')) {
|
|
657
|
+
+ // The CSS route synthesizes a default string export after compilation.
|
|
658
|
+
+ if (CSS_MODULE_RE.test(u.pathname)) continue;
|
|
659
|
+
// Resolve the import target through the SAME
|
|
660
|
+
// canonical pipeline the /ns/m route itself uses
|
|
661
|
+
// (websocket-ns-m-request.ts) instead of a third
|
|
478
662
|
diff --git a/hmr/server/websocket-served-module-helpers.js b/hmr/server/websocket-served-module-helpers.js
|
|
479
663
|
index b9e3ab67eb4ae7c9b12bc4b02b9aa3660d712644..f857f4a5a5956af229e447ed04bf1a52a90c6399 100644
|
|
480
664
|
--- a/hmr/server/websocket-served-module-helpers.js
|
|
@@ -499,3 +683,27 @@ index b9e3ab67eb4ae7c9b12bc4b02b9aa3660d712644..f857f4a5a5956af229e447ed04bf1a52
|
|
|
499
683
|
.map((node) => ({
|
|
500
684
|
start: node.start,
|
|
501
685
|
end: node.end,
|
|
686
|
+
diff --git a/hmr/server/websocket.js b/hmr/server/websocket.js
|
|
687
|
+
index e6a14437f8990e2c631f23eb8db21aa0b28b5759..2b9fb450511b6e114b6e7e7ac8a48831b4a09dc9 100644
|
|
688
|
+
--- a/hmr/server/websocket.js
|
|
689
|
+
+++ b/hmr/server/websocket.js
|
|
690
|
+
@@ -1,3 +1,5 @@
|
|
691
|
+
+import { virtualCssUpdates } from './css-device-module.js';
|
|
692
|
+
+import { buildCssUpdatesMessage } from './css-update-message.js';
|
|
693
|
+
import { readFileSync } from 'fs';
|
|
694
|
+
import { WebSocketServer } from 'ws';
|
|
695
|
+
import * as path from 'path';
|
|
696
|
+
@@ -341,6 +343,13 @@ function createHmrWebSocketPlugin(opts, strategy) {
|
|
697
|
+
// to reach the device, since they drive the
|
|
698
|
+
// in-place `ɵɵreplaceMetadata` template-swap path.
|
|
699
|
+
// Filter the relay to those.
|
|
700
|
+
+ const cssUpdates = virtualCssUpdates(normalized);
|
|
701
|
+
+ if (cssUpdates.length) {
|
|
702
|
+
+ const message = JSON.stringify(buildCssUpdatesMessage(server, cssUpdates));
|
|
703
|
+
+ wss?.clients.forEach((client) => {
|
|
704
|
+
+ if (client?.readyState === 1) client.send(message);
|
|
705
|
+
+ });
|
|
706
|
+
+ }
|
|
707
|
+
if (normalized.type !== 'custom')
|
|
708
|
+
return;
|
|
709
|
+
// Root-component guard. Analog's in-place
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
diff --git a/list/index.ios.js b/list/index.ios.js
|
|
2
|
+
index d683fa030ea4adb1b442405458055256319e0adc..97f1953ffbc8ca9e809953c2024e17cd32beb1bb 100644
|
|
3
|
+
--- a/list/index.ios.js
|
|
4
|
+
+++ b/list/index.ios.js
|
|
5
|
+
@@ -42,7 +42,7 @@ var ListDelegateImpl = (function (_super) {
|
|
6
|
+
});
|
|
7
|
+
}
|
|
8
|
+
};
|
|
9
|
+
- ListDelegateImpl.ObjCProtocols = [MasonListDelegate];
|
|
10
|
+
+ ListDelegateImpl.ObjCProtocols = typeof MasonListDelegate !== "undefined" ? [MasonListDelegate] : [];
|
|
11
|
+
return ListDelegateImpl;
|
|
12
|
+
}(NSObject));
|
|
13
|
+
const listState_ = Symbol('[[listState]]');
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
diff --git a/dist/cjs/runtime.cjs b/dist/cjs/runtime.cjs
|
|
2
|
-
index a035f05..
|
|
2
|
+
index a035f05..e1c9ca1 100644
|
|
3
3
|
--- a/dist/cjs/runtime.cjs
|
|
4
4
|
+++ b/dist/cjs/runtime.cjs
|
|
5
5
|
@@ -365,6 +365,7 @@ var import_stream_protocol = require("./stream-protocol.cjs");
|
|
@@ -18,6 +18,15 @@ index a035f05..9912e51 100644
|
|
|
18
18
|
function useState(initial, slot) {
|
|
19
19
|
const s = readStateHook(initial, slot, arguments.length === 1);
|
|
20
20
|
return [s.value, s.setter];
|
|
21
|
+
@@ -9659,6 +9661,8 @@ function renderClientContextProvider(context, props, renderScope) {
|
|
22
|
+
ensureHooks(scope).set(CHILDREN_DIALECT_SLOT, dialect);
|
|
23
|
+
}
|
|
24
|
+
renderSharedBody(childrenAsBody(children), void 0, scope, void 0);
|
|
25
|
+
+ } else {
|
|
26
|
+
+ resetScopeChildren(scope);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
let SHARED_BODY_SCOPE = null;
|
|
21
30
|
diff --git a/dist/cjs/signals/client.cjs b/dist/cjs/signals/client.cjs
|
|
22
31
|
index 28e2844..af40518 100644
|
|
23
32
|
--- a/dist/cjs/signals/client.cjs
|
|
@@ -453,7 +462,7 @@ index 90848a6..474c2bb 100644
|
|
|
453
462
|
+ let specifiers = signalHelperImports.get(request);
|
|
454
463
|
+ if (specifiers === undefined) signalHelperImports.set(request, (specifiers = []));
|
|
455
464
|
diff --git a/dist/node/runtime.js b/dist/node/runtime.js
|
|
456
|
-
index 927d060..
|
|
465
|
+
index 927d060..d311ac9 100644
|
|
457
466
|
--- a/dist/node/runtime.js
|
|
458
467
|
+++ b/dist/node/runtime.js
|
|
459
468
|
@@ -185,6 +185,7 @@ import {
|
|
@@ -472,6 +481,15 @@ index 927d060..cef6b5b 100644
|
|
|
472
481
|
function useState(initial, slot) {
|
|
473
482
|
const s = readStateHook(initial, slot, arguments.length === 1);
|
|
474
483
|
return [s.value, s.setter];
|
|
484
|
+
@@ -9532,6 +9534,8 @@ function renderClientContextProvider(context, props, renderScope) {
|
|
485
|
+
ensureHooks(scope).set(CHILDREN_DIALECT_SLOT, dialect);
|
|
486
|
+
}
|
|
487
|
+
renderSharedBody(childrenAsBody(children), void 0, scope, void 0);
|
|
488
|
+
+ } else {
|
|
489
|
+
+ resetScopeChildren(scope);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
let SHARED_BODY_SCOPE = null;
|
|
475
493
|
diff --git a/dist/node/signals/client.js b/dist/node/signals/client.js
|
|
476
494
|
index 21a39c3..3f85700 100644
|
|
477
495
|
--- a/dist/node/signals/client.js
|
|
@@ -1034,7 +1052,7 @@ index 6427a01..8049b78 100644
|
|
|
1034
1052
|
createContext,
|
|
1035
1053
|
createSubSlot,
|
|
1036
1054
|
diff --git a/dist/runtime.js b/dist/runtime.js
|
|
1037
|
-
index 67ace09..
|
|
1055
|
+
index 67ace09..afeb8ea 100644
|
|
1038
1056
|
--- a/dist/runtime.js
|
|
1039
1057
|
+++ b/dist/runtime.js
|
|
1040
1058
|
@@ -184,6 +184,7 @@ import {
|
|
@@ -1053,6 +1071,15 @@ index 67ace09..ef61a91 100644
|
|
|
1053
1071
|
function useState(initial, slot) {
|
|
1054
1072
|
const s = readStateHook(initial, slot, arguments.length === 1);
|
|
1055
1073
|
return [s.value, s.setter];
|
|
1074
|
+
@@ -9531,6 +9533,8 @@ function renderClientContextProvider(context, props, renderScope) {
|
|
1075
|
+
ensureHooks(scope).set(CHILDREN_DIALECT_SLOT, dialect);
|
|
1076
|
+
}
|
|
1077
|
+
renderSharedBody(childrenAsBody(children), void 0, scope, void 0);
|
|
1078
|
+
+ } else {
|
|
1079
|
+
+ resetScopeChildren(scope);
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
let SHARED_BODY_SCOPE = null;
|
|
1056
1083
|
diff --git a/dist/signals/client.d.ts b/dist/signals/client.d.ts
|
|
1057
1084
|
index 6388c2f..f9e9862 100644
|
|
1058
1085
|
--- a/dist/signals/client.d.ts
|