@symbiote-native/components 1.0.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -4
- package/build/behaviors/activity-indicator/index.android.d.ts +1 -0
- package/build/behaviors/activity-indicator/index.android.js +16 -0
- package/build/behaviors/activity-indicator/index.d.ts +3 -0
- package/build/behaviors/activity-indicator/index.ios.d.ts +1 -0
- package/build/behaviors/activity-indicator/index.ios.js +14 -0
- package/build/behaviors/activity-indicator/index.js +5 -0
- package/build/behaviors/activity-indicator/shared.d.ts +18 -0
- package/build/behaviors/activity-indicator/shared.js +149 -0
- package/build/behaviors/button.d.ts +2 -0
- package/build/behaviors/button.js +328 -0
- package/build/behaviors/image-background.d.ts +2 -0
- package/build/behaviors/image-background.js +139 -0
- package/build/behaviors/image.d.ts +1 -1
- package/build/behaviors/image.js +2 -2
- package/build/behaviors/input-accessory-view.d.ts +1 -1
- package/build/behaviors/input-accessory-view.js +2 -2
- package/build/behaviors/pressable.d.ts +59 -1
- package/build/behaviors/pressable.js +93 -18
- package/build/behaviors/refresh-control.d.ts +2 -0
- package/build/behaviors/refresh-control.js +83 -0
- package/build/behaviors/scroll-view/index.android.d.ts +1 -0
- package/build/behaviors/scroll-view/index.android.js +52 -0
- package/build/behaviors/scroll-view/index.d.ts +2 -0
- package/build/behaviors/scroll-view/index.ios.d.ts +1 -0
- package/build/behaviors/scroll-view/index.ios.js +10 -0
- package/build/behaviors/scroll-view/index.js +5 -0
- package/build/behaviors/scroll-view/shared.d.ts +11 -0
- package/build/behaviors/scroll-view/shared.js +291 -0
- package/build/behaviors/scroll-view/sticky.d.ts +17 -0
- package/build/behaviors/scroll-view/sticky.js +568 -0
- package/build/behaviors/switch.d.ts +1 -1
- package/build/behaviors/switch.js +9 -5
- package/build/behaviors/text-input.d.ts +2 -2
- package/build/behaviors/text-input.js +43 -15
- package/build/behaviors/touchable-highlight.d.ts +9 -0
- package/build/behaviors/touchable-highlight.js +192 -0
- package/build/behaviors/touchable-native-feedback.d.ts +20 -0
- package/build/behaviors/touchable-native-feedback.js +333 -0
- package/build/behaviors/touchable-opacity.d.ts +12 -0
- package/build/behaviors/touchable-opacity.js +227 -0
- package/build/behaviors/touchable-without-feedback.d.ts +2 -0
- package/build/behaviors/touchable-without-feedback.js +296 -0
- package/build/component-names/index.android.js +29 -19
- package/build/component-names/index.ios.js +31 -19
- package/build/component-names/shared.d.ts +2 -1
- package/build/component-names/shared.js +16 -6
- package/build/descriptor.js +4 -4
- package/build/fold-host-bag.js +2 -2
- package/build/index.d.ts +17 -11
- package/build/index.js +44 -8
- package/build/register.d.ts +1 -0
- package/build/register.js +55 -0
- package/build/scroll-view-commands.d.ts +4 -0
- package/build/scroll-view-commands.js +30 -31
- package/build/state/text-input.d.ts +4 -1
- package/build/view/render-button.d.ts +36 -1
- package/build/view/render-button.js +101 -12
- package/build/view/render-image/index.js +2 -2
- package/build/view/render-input-accessory-view.js +1 -1
- package/build/view/render-modal.js +3 -3
- package/build/view/render-pressable/index.d.ts +2 -0
- package/build/view/render-pressable/index.js +24 -0
- package/build/view/render-scroll-view.d.ts +1 -0
- package/build/view/render-scroll-view.js +18 -9
- package/build/view/render-switch.d.ts +4 -1
- package/build/view/render-switch.js +2 -2
- package/build/view/render-text-input.js +2 -2
- package/build/view/render-touchable-native-feedback.d.ts +19 -0
- package/build/view/render-touchable-native-feedback.js +19 -0
- package/host-primitives.cjs +202 -150
- package/host-primitives.d.cts +0 -2
- package/package.json +8 -17
- package/build/state-style.d.ts +0 -15
- package/build/state-style.js +0 -47
- package/build/view/render-activity-indicator.d.ts +0 -25
- package/build/view/render-activity-indicator.js +0 -88
- package/build/view/render-image-background.d.ts +0 -9
- package/build/view/render-image-background.js +0 -48
- package/lowering-fixtures.cjs +0 -259
- package/lowering-fixtures.d.cts +0 -17
- package/specialize-state-style.cjs +0 -219
- package/specialize-state-style.d.cts +0 -15
|
@@ -1,219 +0,0 @@
|
|
|
1
|
-
// Turn `style={({ pressed }) => …}` into two plain style objects, so a Pressable that reads its own
|
|
2
|
-
// press state in the template can still be lowered to an intrinsic tag.
|
|
3
|
-
//
|
|
4
|
-
// WHY THIS EXISTS AT ALL. The alternative we shipped first is a `:active` CSS rule, and it works —
|
|
5
|
-
// but it asks a developer to abandon a genuine best-practice. A ternary in a style callback is how
|
|
6
|
-
// dynamic styling is written across this ecosystem, in this project's own examples and at large
|
|
7
|
-
// engineering organisations. A tool that demands a rewrite to be fast is a tool with a defect, so
|
|
8
|
-
// the compiler does the conversion instead of the human.
|
|
9
|
-
//
|
|
10
|
-
// IT IS A SUBSTITUTION, NOT AN EVALUATION, and that distinction is the whole safety argument. No
|
|
11
|
-
// user code runs at build time. The arrow's body is cloned twice, the state identifier is replaced
|
|
12
|
-
// by `true` in one copy and `false` in the other, and conditionals whose test has become a literal
|
|
13
|
-
// are folded. Anything else in the body — `color`, `props.x`, a call — is carried through as an
|
|
14
|
-
// expression in both copies, untouched. That is why a runtime prop survives the transform.
|
|
15
|
-
//
|
|
16
|
-
// WHY IT IS SAFE TO BE EXHAUSTIVE: the callback's argument is OURS. We declare `pressed`, so we
|
|
17
|
-
// know its domain is exactly {true, false} and two specialisations cover it completely. A callback
|
|
18
|
-
// whose argument domain we did not own could not be handled this way at all.
|
|
19
|
-
|
|
20
|
-
// The state keys a primitive exposes to a style callback. One today; the mechanism generalises to
|
|
21
|
-
// any FINITE domain we declare, which is the property that makes exhaustive specialisation legal.
|
|
22
|
-
const STATE_KEYS = new Set(['pressed']);
|
|
23
|
-
|
|
24
|
-
function singleReturnedObject(body, types) {
|
|
25
|
-
if (types.isObjectExpression(body)) return body;
|
|
26
|
-
if (!types.isBlockStatement(body) || body.body.length !== 1) return null;
|
|
27
|
-
const [statement] = body.body;
|
|
28
|
-
return types.isReturnStatement(statement) &&
|
|
29
|
-
types.isObjectExpression(statement.argument)
|
|
30
|
-
? statement.argument
|
|
31
|
-
: null;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// `({ pressed }) => …` only. An Identifier param (`state => state.pressed`) is a legal shape we
|
|
35
|
-
// deliberately do not accept yet: it needs member-expression substitution, which is a second
|
|
36
|
-
// mechanism, and refusing costs a call site rather than correctness.
|
|
37
|
-
function destructuredStateKeys(param, types) {
|
|
38
|
-
if (!types.isObjectPattern(param)) return null;
|
|
39
|
-
const keys = [];
|
|
40
|
-
for (const property of param.properties) {
|
|
41
|
-
if (
|
|
42
|
-
!types.isObjectProperty(property) ||
|
|
43
|
-
property.computed ||
|
|
44
|
-
!types.isIdentifier(property.key) ||
|
|
45
|
-
!types.isIdentifier(property.value) ||
|
|
46
|
-
property.key.name !== property.value.name ||
|
|
47
|
-
!STATE_KEYS.has(property.key.name)
|
|
48
|
-
) {
|
|
49
|
-
return null;
|
|
50
|
-
}
|
|
51
|
-
keys.push(property.key.name);
|
|
52
|
-
}
|
|
53
|
-
return keys.length > 0 ? keys : null;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// A nested function could REDECLARE the state name, and then substituting it would rewrite a
|
|
57
|
-
// binding that has nothing to do with the press state. Cheaper to refuse than to scope-track.
|
|
58
|
-
function containsFunction(node, types) {
|
|
59
|
-
let found = false;
|
|
60
|
-
walk(node, child => {
|
|
61
|
-
if (
|
|
62
|
-
types.isFunctionExpression(child) ||
|
|
63
|
-
types.isArrowFunctionExpression(child) ||
|
|
64
|
-
types.isFunctionDeclaration(child)
|
|
65
|
-
) {
|
|
66
|
-
found = true;
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
return found;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function walk(node, visit) {
|
|
73
|
-
if (node === null || typeof node !== 'object') return;
|
|
74
|
-
if (Array.isArray(node)) {
|
|
75
|
-
for (const item of node) walk(item, visit);
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
if (typeof node.type !== 'string') return;
|
|
79
|
-
visit(node);
|
|
80
|
-
for (const key of Object.keys(node)) {
|
|
81
|
-
if (key === 'loc' || key === 'start' || key === 'end') continue;
|
|
82
|
-
walk(node[key], visit);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Rewrites in place on an already-cloned tree. A property KEY named `pressed` is not a reference to
|
|
87
|
-
// the parameter, and neither is `x.pressed` — both are skipped, which is why this walks parents
|
|
88
|
-
// rather than blindly matching identifiers.
|
|
89
|
-
function substitute(node, name, literal, types) {
|
|
90
|
-
walk(node, parent => {
|
|
91
|
-
for (const key of Object.keys(parent)) {
|
|
92
|
-
const value = parent[key];
|
|
93
|
-
if (Array.isArray(value)) {
|
|
94
|
-
value.forEach((item, index) => {
|
|
95
|
-
if (isStateRef(parent, key, item, name, types))
|
|
96
|
-
value[index] = literal();
|
|
97
|
-
});
|
|
98
|
-
} else if (isStateRef(parent, key, value, name, types)) {
|
|
99
|
-
parent[key] = literal();
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
function isStateRef(parent, key, node, name, types) {
|
|
106
|
-
if (!types.isIdentifier(node) || node.name !== name) return false;
|
|
107
|
-
if (types.isObjectProperty(parent) && key === 'key' && !parent.computed)
|
|
108
|
-
return false;
|
|
109
|
-
if (
|
|
110
|
-
types.isMemberExpression(parent) &&
|
|
111
|
-
key === 'property' &&
|
|
112
|
-
!parent.computed
|
|
113
|
-
) {
|
|
114
|
-
return false;
|
|
115
|
-
}
|
|
116
|
-
return true;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// Bottom-up, because folding a branch can turn its parent's test into a literal too.
|
|
120
|
-
function fold(node, types) {
|
|
121
|
-
walk(node, parent => {
|
|
122
|
-
for (const key of Object.keys(parent)) {
|
|
123
|
-
const value = parent[key];
|
|
124
|
-
if (Array.isArray(value)) {
|
|
125
|
-
value.forEach((item, index) => {
|
|
126
|
-
const folded = foldOne(item, types);
|
|
127
|
-
if (folded !== null) value[index] = folded;
|
|
128
|
-
});
|
|
129
|
-
} else {
|
|
130
|
-
const folded = foldOne(value, types);
|
|
131
|
-
if (folded !== null) parent[key] = folded;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
function foldOne(node, types) {
|
|
138
|
-
if (
|
|
139
|
-
node === null ||
|
|
140
|
-
typeof node !== 'object' ||
|
|
141
|
-
typeof node.type !== 'string'
|
|
142
|
-
) {
|
|
143
|
-
return null;
|
|
144
|
-
}
|
|
145
|
-
fold(node, types);
|
|
146
|
-
if (
|
|
147
|
-
types.isConditionalExpression(node) &&
|
|
148
|
-
types.isBooleanLiteral(node.test)
|
|
149
|
-
) {
|
|
150
|
-
return node.test.value ? node.consequent : node.alternate;
|
|
151
|
-
}
|
|
152
|
-
if (
|
|
153
|
-
types.isUnaryExpression(node, { operator: '!' }) &&
|
|
154
|
-
types.isBooleanLiteral(node.argument)
|
|
155
|
-
) {
|
|
156
|
-
return types.booleanLiteral(!node.argument.value);
|
|
157
|
-
}
|
|
158
|
-
if (types.isLogicalExpression(node) && types.isBooleanLiteral(node.left)) {
|
|
159
|
-
if (node.operator === '&&') return node.left.value ? node.right : node.left;
|
|
160
|
-
if (node.operator === '||') return node.left.value ? node.left : node.right;
|
|
161
|
-
}
|
|
162
|
-
return null;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
function specializeAt(object, keys, value, types) {
|
|
166
|
-
const clone = types.cloneNode(object, true);
|
|
167
|
-
for (const key of keys) {
|
|
168
|
-
substitute(clone, key, () => types.booleanLiteral(value), types);
|
|
169
|
-
}
|
|
170
|
-
fold(clone, types);
|
|
171
|
-
return hasStateRef(clone, keys, types) ? null : clone;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// Returns the two specialisations, or null to refuse — the caller then keeps the component, which
|
|
175
|
-
// is exactly today's behaviour.
|
|
176
|
-
// A surviving REFERENCE means the body used the state somewhere the substitution could not reach,
|
|
177
|
-
// and emitting a half-specialised object would be worse than refusing. It must use the same
|
|
178
|
-
// parent-aware predicate as `substitute`, or a property named `pressed` and a `state.pressed` read
|
|
179
|
-
// both count as survivors and every such call site refuses for no reason — which is exactly what a
|
|
180
|
-
// naive identifier scan did here first.
|
|
181
|
-
function hasStateRef(node, keys, types) {
|
|
182
|
-
let found = false;
|
|
183
|
-
walk(node, parent => {
|
|
184
|
-
for (const key of Object.keys(parent)) {
|
|
185
|
-
const value = parent[key];
|
|
186
|
-
const items = Array.isArray(value) ? value : [value];
|
|
187
|
-
for (const item of items) {
|
|
188
|
-
if (
|
|
189
|
-
types.isIdentifier(item) &&
|
|
190
|
-
keys.includes(item.name) &&
|
|
191
|
-
isStateRef(parent, key, item, item.name, types)
|
|
192
|
-
) {
|
|
193
|
-
found = true;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
});
|
|
198
|
-
return found;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
function specializeStateStyle(expression, types) {
|
|
202
|
-
if (
|
|
203
|
-
!types.isArrowFunctionExpression(expression) &&
|
|
204
|
-
!types.isFunctionExpression(expression)
|
|
205
|
-
) {
|
|
206
|
-
return null;
|
|
207
|
-
}
|
|
208
|
-
if (expression.params.length !== 1) return null;
|
|
209
|
-
const keys = destructuredStateKeys(expression.params[0], types);
|
|
210
|
-
if (keys === null) return null;
|
|
211
|
-
const object = singleReturnedObject(expression.body, types);
|
|
212
|
-
if (object === null) return null;
|
|
213
|
-
if (containsFunction(object, types)) return null;
|
|
214
|
-
const base = specializeAt(object, keys, false, types);
|
|
215
|
-
const active = specializeAt(object, keys, true, types);
|
|
216
|
-
return base === null || active === null ? null : { base, active };
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
module.exports = { specializeStateStyle, STATE_KEYS };
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
// Hand-written types for the loose `.cjs` above — Babel/Metro transforms cannot import `.ts`, so
|
|
2
|
-
// the implementation stays CommonJS and its shape is declared here.
|
|
3
|
-
import type * as babelTypes from '@babel/types';
|
|
4
|
-
|
|
5
|
-
export interface ISpecializedStateStyle {
|
|
6
|
-
base: babelTypes.ObjectExpression;
|
|
7
|
-
active: babelTypes.ObjectExpression;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export declare function specializeStateStyle(
|
|
11
|
-
expression: babelTypes.Node,
|
|
12
|
-
types: typeof babelTypes,
|
|
13
|
-
): ISpecializedStateStyle | null;
|
|
14
|
-
|
|
15
|
-
export declare const STATE_KEYS: ReadonlySet<string>;
|