ripple 0.3.74 → 0.3.77
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/CHANGELOG.md +61 -0
- package/package.json +3 -3
- package/src/jsx-runtime.d.ts +2 -2
- package/src/runtime/dynamic-client.js +33 -0
- package/src/runtime/dynamic-server.js +80 -0
- package/src/runtime/index-client.js +2 -0
- package/src/runtime/index-server.js +2 -0
- package/src/runtime/internal/client/blocks.js +3 -2
- package/src/runtime/internal/client/composite.js +11 -6
- package/src/runtime/internal/client/render.js +5 -2
- package/src/runtime/internal/server/index.js +8 -1
- package/tests/client/basic/basic.components.test.tsrx +2 -2
- package/tests/client/basic/basic.styling.test.tsrx +16 -14
- package/tests/client/composite/composite.dynamic-components.test.tsrx +24 -6
- package/tests/client/css/global-additional-cases.test.tsrx +4 -4
- package/tests/client/css/style-identifier.test.tsrx +4 -4
- package/tests/client/dynamic-elements.test.tsrx +113 -38
- package/tests/client/head.test.tsrx +34 -0
- package/tests/client/svg.test.tsrx +8 -7
- package/tests/client/try.test.tsrx +2 -1
- package/tests/server/basic.components.test.tsrx +2 -2
- package/tests/server/basic.test.tsrx +3 -3
- package/tests/server/dynamic-elements.test.tsrx +60 -29
- package/tests/server/head.test.tsrx +23 -0
- package/tests/server/style-identifier.test.tsrx +4 -4
- package/tests/server/try.test.tsrx +2 -1
- package/types/index.d.ts +28 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,66 @@
|
|
|
1
1
|
# ripple
|
|
2
2
|
|
|
3
|
+
## 0.3.77
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies
|
|
8
|
+
[[`d14ec84`](https://github.com/Ripple-TS/ripple/commit/d14ec84f26233e514be9e59ffc94e61db5089587),
|
|
9
|
+
[`921fb9c`](https://github.com/Ripple-TS/ripple/commit/921fb9ce6485db41527b631f5236b7abbac74986),
|
|
10
|
+
[`1693c9e`](https://github.com/Ripple-TS/ripple/commit/1693c9e6daf1421e71171fe3c50e37adfc858b69)]:
|
|
11
|
+
- @tsrx/core@0.1.25
|
|
12
|
+
- @tsrx/ripple@0.1.25
|
|
13
|
+
|
|
14
|
+
## 0.3.76
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- [#1229](https://github.com/Ripple-TS/ripple/pull/1229)
|
|
19
|
+
[`6fd49c9`](https://github.com/Ripple-TS/ripple/commit/6fd49c9dd737e889844e254763f66e13ea4a7241)
|
|
20
|
+
Thanks [@leonidaz](https://github.com/leonidaz)! - Replace the removed `<@...>`
|
|
21
|
+
dynamic tag syntax with runtime `Dynamic` helpers. Ripple now exports `Dynamic`
|
|
22
|
+
and reuses its composite runtime path for dynamic elements/components, while
|
|
23
|
+
React, Preact, Solid, and Vue expose target-specific `Dynamic` helpers with
|
|
24
|
+
typed `is` props.
|
|
25
|
+
|
|
26
|
+
React, Preact, Solid, and Vue now mark imported runtime `Dynamic` elements
|
|
27
|
+
during shared JSX analysis so scoped CSS classes are applied through aliases
|
|
28
|
+
without treating local components named `Dynamic` as runtime elements.
|
|
29
|
+
|
|
30
|
+
Dynamic component prop forwarding now uses a shared core runtime helper that
|
|
31
|
+
excludes the internal `is` prop without snapshotting getter-backed reactive
|
|
32
|
+
props.
|
|
33
|
+
|
|
34
|
+
The TSRX parser, transforms, analyzers, prettier support, and related tests no
|
|
35
|
+
longer recognize dynamic tag syntax. Stale JSX identifier `tracked` plumbing
|
|
36
|
+
from that parser path has also been removed.
|
|
37
|
+
|
|
38
|
+
- Updated dependencies
|
|
39
|
+
[[`6fd49c9`](https://github.com/Ripple-TS/ripple/commit/6fd49c9dd737e889844e254763f66e13ea4a7241)]:
|
|
40
|
+
- @tsrx/core@0.1.24
|
|
41
|
+
- @tsrx/ripple@0.1.24
|
|
42
|
+
|
|
43
|
+
## 0.3.75
|
|
44
|
+
|
|
45
|
+
### Patch Changes
|
|
46
|
+
|
|
47
|
+
- Updated dependencies
|
|
48
|
+
[[`9eb4819`](https://github.com/Ripple-TS/ripple/commit/9eb4819cede6da7e93cbcd2bdf284bcb42d40464),
|
|
49
|
+
[`88a254c`](https://github.com/Ripple-TS/ripple/commit/88a254c69953a5ace33bc10047f11052ec598672),
|
|
50
|
+
[`ba3a7f6`](https://github.com/Ripple-TS/ripple/commit/ba3a7f6485ea163e60cc0750a8e8b06b50728009),
|
|
51
|
+
[`ac6f358`](https://github.com/Ripple-TS/ripple/commit/ac6f3582ca0b2814004439c882d6aa735c8afe50),
|
|
52
|
+
[`4c5f992`](https://github.com/Ripple-TS/ripple/commit/4c5f992b9a11e1f26abee476a6add89f959169bc),
|
|
53
|
+
[`78ffa8d`](https://github.com/Ripple-TS/ripple/commit/78ffa8d90fd01e85bf34e5c6adef0e51caae8da7),
|
|
54
|
+
[`16560cb`](https://github.com/Ripple-TS/ripple/commit/16560cb466430bdbe8749d9491bc79e69e58d02c),
|
|
55
|
+
[`186b3b2`](https://github.com/Ripple-TS/ripple/commit/186b3b2557761ff06c9056bf2e0b7ab8c7692477),
|
|
56
|
+
[`4be6e54`](https://github.com/Ripple-TS/ripple/commit/4be6e54bbfee20927adca473648a94aa173d7d77),
|
|
57
|
+
[`2b67f83`](https://github.com/Ripple-TS/ripple/commit/2b67f83d7ed7eab7a39bc33524fcf73f737d977e),
|
|
58
|
+
[`9918c52`](https://github.com/Ripple-TS/ripple/commit/9918c52e954f2b8e1a994892e7c555e8277f2d59),
|
|
59
|
+
[`e8493be`](https://github.com/Ripple-TS/ripple/commit/e8493be0b3489f402105297251e1919c103c2360),
|
|
60
|
+
[`c424675`](https://github.com/Ripple-TS/ripple/commit/c424675102a9edd4f1e356fb6db30124a9c2d885)]:
|
|
61
|
+
- @tsrx/core@0.1.23
|
|
62
|
+
- @tsrx/ripple@0.1.23
|
|
63
|
+
|
|
3
64
|
## 0.3.74
|
|
4
65
|
|
|
5
66
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "Ripple is an elegant TypeScript UI framework",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Dominic Gannaway",
|
|
6
|
-
"version": "0.3.
|
|
6
|
+
"version": "0.3.77",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"module": "src/runtime/index-client.js",
|
|
9
9
|
"main": "src/runtime/index-client.js",
|
|
@@ -74,8 +74,8 @@
|
|
|
74
74
|
"clsx": "^2.1.1",
|
|
75
75
|
"devalue": "^5.8.1",
|
|
76
76
|
"esm-env": "^1.2.2",
|
|
77
|
-
"@tsrx/core": "0.1.
|
|
78
|
-
"@tsrx/ripple": "0.1.
|
|
77
|
+
"@tsrx/core": "0.1.25",
|
|
78
|
+
"@tsrx/ripple": "0.1.25"
|
|
79
79
|
},
|
|
80
80
|
"devDependencies": {
|
|
81
81
|
"@types/estree": "^1.0.8",
|
package/src/jsx-runtime.d.ts
CHANGED
|
@@ -8,8 +8,8 @@ export type { RefValue } from '#public';
|
|
|
8
8
|
* renderable TSRX values when used in expression positions.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
// Ripple components
|
|
12
|
-
export type ComponentType<P = {}> = (props: P) => void;
|
|
11
|
+
// Ripple components are usually imperative, but helpers can return TSRX values.
|
|
12
|
+
export type ComponentType<P = {}> = (props: P) => void | TSRXElement;
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Create a JSX element (for elements with children)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** @import { Block } from '#client' */
|
|
2
|
+
|
|
3
|
+
import { composite } from './internal/client/composite.js';
|
|
4
|
+
import { with_block } from './internal/client/runtime.js';
|
|
5
|
+
import { tsrx_element } from './element.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @typedef {Function | string | null | undefined | false} DynamicTarget
|
|
9
|
+
* @typedef {{ is?: DynamicTarget, [key: string]: any }} DynamicProps
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @param {DynamicProps} props
|
|
14
|
+
* @returns {import('./element.js').TSRXElement}
|
|
15
|
+
*/
|
|
16
|
+
export function Dynamic(props) {
|
|
17
|
+
return tsrx_element(
|
|
18
|
+
/**
|
|
19
|
+
* @param {Node} anchor
|
|
20
|
+
* @param {Block | null} block
|
|
21
|
+
*/
|
|
22
|
+
(anchor, block) => {
|
|
23
|
+
const render_dynamic = () =>
|
|
24
|
+
composite(() => /** @type {DynamicTarget} */ (props?.is), anchor, props || {}, 'is');
|
|
25
|
+
|
|
26
|
+
if (block !== null) {
|
|
27
|
+
with_block(block, render_dynamic);
|
|
28
|
+
} else {
|
|
29
|
+
render_dynamic();
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
);
|
|
33
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { is_void_element } from '@tsrx/core/runtime/html';
|
|
2
|
+
import { exclude_prop_from_object } from '@tsrx/core/runtime/language-helpers';
|
|
3
|
+
import {
|
|
4
|
+
escape,
|
|
5
|
+
get,
|
|
6
|
+
is_tsrx_element,
|
|
7
|
+
output_push,
|
|
8
|
+
render_component,
|
|
9
|
+
render_tsrx_element,
|
|
10
|
+
spread_attrs,
|
|
11
|
+
spread_inner_html,
|
|
12
|
+
} from './internal/server/index.js';
|
|
13
|
+
import { tsrx_element } from './element.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @param {any} value
|
|
17
|
+
* @returns {void}
|
|
18
|
+
*/
|
|
19
|
+
function render_child(value) {
|
|
20
|
+
value = get(value);
|
|
21
|
+
|
|
22
|
+
if (is_tsrx_element(value)) {
|
|
23
|
+
render_tsrx_element(value);
|
|
24
|
+
} else if (Array.isArray(value)) {
|
|
25
|
+
for (const item of value) {
|
|
26
|
+
render_child(item);
|
|
27
|
+
}
|
|
28
|
+
} else if (value != null) {
|
|
29
|
+
output_push(escape(value));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @param {string} tag
|
|
35
|
+
* @param {Record<string, any>} props
|
|
36
|
+
* @returns {void}
|
|
37
|
+
*/
|
|
38
|
+
function render_element(tag, props) {
|
|
39
|
+
output_push(`<${tag}`);
|
|
40
|
+
output_push(spread_attrs(props, undefined, 'is'));
|
|
41
|
+
|
|
42
|
+
if (is_void_element(tag)) {
|
|
43
|
+
output_push(' />');
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
output_push('>');
|
|
48
|
+
|
|
49
|
+
const inner_html = spread_inner_html(props);
|
|
50
|
+
if (inner_html !== undefined) {
|
|
51
|
+
output_push(inner_html);
|
|
52
|
+
} else {
|
|
53
|
+
render_child(props.children);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
output_push(`</${tag}>`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* @param {{ is?: Function | string | null | undefined | false, [key: string]: any }} props
|
|
61
|
+
* @returns {import('./element.js').TSRXElement}
|
|
62
|
+
*/
|
|
63
|
+
export function Dynamic(props) {
|
|
64
|
+
return tsrx_element(() => {
|
|
65
|
+
const component = get(props?.is);
|
|
66
|
+
if (component == null || component === false) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const dynamic_props = props || {};
|
|
71
|
+
|
|
72
|
+
if (typeof component === 'function') {
|
|
73
|
+
render_component(component, exclude_prop_from_object(dynamic_props, 'is'));
|
|
74
|
+
} else if (is_tsrx_element(component)) {
|
|
75
|
+
throw new TypeError('Invalid component type: received a TSRXElement value.');
|
|
76
|
+
} else {
|
|
77
|
+
render_element(String(component), dynamic_props);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
@@ -183,6 +183,8 @@ export { user_effect as effect } from './internal/client/blocks.js';
|
|
|
183
183
|
|
|
184
184
|
export { Portal } from './internal/client/portal.js';
|
|
185
185
|
|
|
186
|
+
export { Dynamic } from './dynamic-client.js';
|
|
187
|
+
|
|
186
188
|
export { ref_prop as createRefKey } from './internal/client/runtime.js';
|
|
187
189
|
|
|
188
190
|
export { isRefProp } from '@tsrx/core/runtime/ref';
|
|
@@ -68,6 +68,8 @@ export const bindNode = noop;
|
|
|
68
68
|
export const bindOffsetWidth = noop;
|
|
69
69
|
export const bindOffsetHeight = noop;
|
|
70
70
|
|
|
71
|
+
export { Dynamic } from './dynamic-server.js';
|
|
72
|
+
|
|
71
73
|
/**
|
|
72
74
|
* Portal component noop for server-side rendering.
|
|
73
75
|
* Portals are client-only and do not render on the server.
|
|
@@ -85,9 +85,10 @@ export function render(fn, state, flags = 0) {
|
|
|
85
85
|
* @param {any} element
|
|
86
86
|
* @param {any} fn
|
|
87
87
|
* @param {number} [flags]
|
|
88
|
+
* @param {string} [exclude_prop]
|
|
88
89
|
*/
|
|
89
|
-
export function render_spread(element, fn, flags = 0) {
|
|
90
|
-
return block(RENDER_BLOCK | flags, apply_element_spread(element, fn));
|
|
90
|
+
export function render_spread(element, fn, flags = 0, exclude_prop) {
|
|
91
|
+
return block(RENDER_BLOCK | flags, apply_element_spread(element, fn, exclude_prop));
|
|
91
92
|
}
|
|
92
93
|
|
|
93
94
|
/**
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/** @import { Block } from '#client' */
|
|
2
2
|
|
|
3
|
+
import { exclude_prop_from_object } from '@tsrx/core/runtime/language-helpers';
|
|
3
4
|
import { branch, destroy_block, render, render_spread } from './blocks.js';
|
|
4
5
|
import { COMPOSITE_BLOCK, DEFAULT_NAMESPACE, NAMESPACE_URI } from './constants.js';
|
|
5
6
|
import { hydrate_next, hydrating } from './hydration.js';
|
|
@@ -9,13 +10,14 @@ import { is_tsrx_element } from '../../element.js';
|
|
|
9
10
|
import { render_component } from './component.js';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
|
-
* @typedef {
|
|
13
|
-
* @param {() =>
|
|
13
|
+
* @typedef {Function | string | null | undefined | false} CompositeTarget
|
|
14
|
+
* @param {() => CompositeTarget} get_component
|
|
14
15
|
* @param {Node} node
|
|
15
16
|
* @param {Record<string, any>} props
|
|
17
|
+
* @param {string} [exclude_prop]
|
|
16
18
|
* @returns {void}
|
|
17
19
|
*/
|
|
18
|
-
export function composite(get_component, node, props) {
|
|
20
|
+
export function composite(get_component, node, props, exclude_prop) {
|
|
19
21
|
if (hydrating) {
|
|
20
22
|
// During hydration, `node` may already point at the first real SSR node
|
|
21
23
|
// (e.g. layout children). Only skip forward when we are on an empty
|
|
@@ -42,7 +44,10 @@ export function composite(get_component, node, props) {
|
|
|
42
44
|
if (typeof component === 'function') {
|
|
43
45
|
// Handle as regular component
|
|
44
46
|
b = branch(() => {
|
|
45
|
-
|
|
47
|
+
const component_props = exclude_prop
|
|
48
|
+
? exclude_prop_from_object(props, exclude_prop)
|
|
49
|
+
: props;
|
|
50
|
+
render_component(component, anchor, component_props);
|
|
46
51
|
});
|
|
47
52
|
} else if (is_tsrx_element(component)) {
|
|
48
53
|
throw new TypeError('Invalid component type: received a TSRXElement value.');
|
|
@@ -69,7 +74,7 @@ export function composite(get_component, node, props) {
|
|
|
69
74
|
};
|
|
70
75
|
}
|
|
71
76
|
|
|
72
|
-
render_spread(element, () => props || {});
|
|
77
|
+
render_spread(element, () => props || {}, 0, exclude_prop);
|
|
73
78
|
|
|
74
79
|
if (is_tsrx_element(props?.children)) {
|
|
75
80
|
var child_anchor = document.createComment('');
|
|
@@ -84,7 +89,7 @@ export function composite(get_component, node, props) {
|
|
|
84
89
|
};
|
|
85
90
|
|
|
86
91
|
if (ns !== active_namespace) {
|
|
87
|
-
// support top-level dynamic element svg/math
|
|
92
|
+
// support top-level dynamic element svg/math tags
|
|
88
93
|
b = branch(() => with_ns(ns, run));
|
|
89
94
|
} else {
|
|
90
95
|
b = branch(run);
|
|
@@ -253,9 +253,10 @@ export function set_selected(element, selected) {
|
|
|
253
253
|
/**
|
|
254
254
|
* @param {Element} element
|
|
255
255
|
* @param {() => Record<string | symbol, any>} fn
|
|
256
|
+
* @param {string} [exclude_prop]
|
|
256
257
|
* @returns {() => void}
|
|
257
258
|
*/
|
|
258
|
-
export function apply_element_spread(element, fn) {
|
|
259
|
+
export function apply_element_spread(element, fn, exclude_prop) {
|
|
259
260
|
/** @type {Record<string | symbol, any>} */
|
|
260
261
|
var prev = {};
|
|
261
262
|
/** @type {Record<string | symbol, Block | undefined>} */
|
|
@@ -304,6 +305,8 @@ export function apply_element_spread(element, fn) {
|
|
|
304
305
|
var current_ref_props = {};
|
|
305
306
|
|
|
306
307
|
for (const key in next) {
|
|
308
|
+
if (key === exclude_prop) continue;
|
|
309
|
+
|
|
307
310
|
const ref_fn = next[key];
|
|
308
311
|
if (!is_ref_prop(ref_fn)) {
|
|
309
312
|
continue;
|
|
@@ -352,7 +355,7 @@ export function apply_element_spread(element, fn) {
|
|
|
352
355
|
/** @type {typeof prev} */
|
|
353
356
|
const current = {};
|
|
354
357
|
for (const key in next) {
|
|
355
|
-
if (key === 'children') continue;
|
|
358
|
+
if (key === 'children' || key === exclude_prop) continue;
|
|
356
359
|
|
|
357
360
|
let value = next[key];
|
|
358
361
|
if (is_ref_prop(value)) {
|
|
@@ -1244,18 +1244,25 @@ function get_styles(styles) {
|
|
|
1244
1244
|
/**
|
|
1245
1245
|
* @param {Record<string, any>} attrs
|
|
1246
1246
|
* @param {string | undefined} css_hash
|
|
1247
|
+
* @param {string} [exclude_prop]
|
|
1247
1248
|
* @returns {string}
|
|
1248
1249
|
*/
|
|
1249
|
-
export function spread_attrs(attrs, css_hash) {
|
|
1250
|
+
export function spread_attrs(attrs, css_hash, exclude_prop) {
|
|
1250
1251
|
let attr_str = '';
|
|
1251
1252
|
let name;
|
|
1252
1253
|
|
|
1254
|
+
if (css_hash === undefined && Object.prototype.hasOwnProperty.call(attrs, '#class')) {
|
|
1255
|
+
css_hash = attrs['#class'];
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1253
1258
|
for (name in attrs) {
|
|
1254
1259
|
var value = attrs[name];
|
|
1255
1260
|
|
|
1256
1261
|
if (
|
|
1257
1262
|
name === 'children' ||
|
|
1258
1263
|
name === 'innerHTML' ||
|
|
1264
|
+
name === '#class' ||
|
|
1265
|
+
name === exclude_prop ||
|
|
1259
1266
|
typeof value === 'function' ||
|
|
1260
1267
|
is_tsrx_element(value)
|
|
1261
1268
|
)
|
|
@@ -5,7 +5,7 @@ import type {
|
|
|
5
5
|
Component,
|
|
6
6
|
PropsWithChildrenOptional,
|
|
7
7
|
} from 'ripple';
|
|
8
|
-
import { flushSync, track } from 'ripple';
|
|
8
|
+
import { Dynamic, flushSync, track } from 'ripple';
|
|
9
9
|
import { did_error } from '../capture-error.js';
|
|
10
10
|
|
|
11
11
|
describe('basic client > components & composition', () => {
|
|
@@ -503,7 +503,7 @@ describe('basic client > components & composition', () => {
|
|
|
503
503
|
function App() @{
|
|
504
504
|
let &[Content] = track(() => Noop);
|
|
505
505
|
<>
|
|
506
|
-
|
|
506
|
+
<Dynamic is={Content} />
|
|
507
507
|
<button onClick={() => (Content = Op)}>{'Show Op'}</button>
|
|
508
508
|
</>
|
|
509
509
|
}
|
|
@@ -39,23 +39,25 @@ describe('basic client > styling', () => {
|
|
|
39
39
|
});
|
|
40
40
|
|
|
41
41
|
it('renders with keyframes in styling scoped to component', () => {
|
|
42
|
-
const source = `export function Basic() {
|
|
43
|
-
|
|
44
|
-
<
|
|
45
|
-
|
|
42
|
+
const source = `export function Basic() @{
|
|
43
|
+
<>
|
|
44
|
+
<div>
|
|
45
|
+
<p>{'Styled paragraph'}</p>
|
|
46
|
+
</div>
|
|
46
47
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
<style>
|
|
49
|
+
div {
|
|
50
|
+
animation-name: anim;
|
|
51
|
+
}
|
|
51
52
|
|
|
52
|
-
|
|
53
|
+
@keyframes anim {}
|
|
53
54
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
p {
|
|
56
|
+
animation-name: anim;
|
|
57
|
+
}
|
|
58
|
+
</style>
|
|
59
|
+
</>
|
|
60
|
+
}`;
|
|
59
61
|
|
|
60
62
|
const { css } = compile(source, 'test.tsrx');
|
|
61
63
|
const name = css.match(/@keyframes\s+([a-zA-Z0-9_-]+)\s*\{/)[1];
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { flushSync, track } from 'ripple';
|
|
1
|
+
import { Dynamic, flushSync, track } from 'ripple';
|
|
2
2
|
|
|
3
3
|
describe('composite > dynamic components', () => {
|
|
4
|
-
it('supports rendering composite components using
|
|
4
|
+
it('supports rendering composite components using <Dynamic is={component}> syntax', () => {
|
|
5
5
|
function basic() @{
|
|
6
6
|
<div>{'Basic Component'}</div>
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
function App() @{
|
|
10
10
|
const tracked_basic = track(() => basic);
|
|
11
|
-
|
|
11
|
+
<Dynamic is={tracked_basic} />
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
render(App);
|
|
@@ -28,7 +28,7 @@ describe('composite > dynamic components', () => {
|
|
|
28
28
|
tracked_basic,
|
|
29
29
|
};
|
|
30
30
|
const comp = obj.tracked_basic;
|
|
31
|
-
|
|
31
|
+
<Dynamic is={comp} />
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
render(App);
|
|
@@ -49,7 +49,7 @@ describe('composite > dynamic components', () => {
|
|
|
49
49
|
};
|
|
50
50
|
let &[inner] = track(obj);
|
|
51
51
|
const comp = inner.tracked_basic;
|
|
52
|
-
|
|
52
|
+
<Dynamic is={comp} />
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
render(App);
|
|
@@ -58,6 +58,24 @@ describe('composite > dynamic components', () => {
|
|
|
58
58
|
expect(container.textContent).toBe('Basic Component');
|
|
59
59
|
});
|
|
60
60
|
|
|
61
|
+
it('does not pass is to dynamic component props', () => {
|
|
62
|
+
function Child(props) @{
|
|
63
|
+
<div>
|
|
64
|
+
{props.is === undefined && !('is' in props) ? 'hidden' : 'leaked'}
|
|
65
|
+
</div>
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function App() @{
|
|
69
|
+
const component = track(() => Child);
|
|
70
|
+
<Dynamic is={component} label="child" />
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
render(App);
|
|
74
|
+
flushSync();
|
|
75
|
+
|
|
76
|
+
expect(container.textContent).toBe('hidden');
|
|
77
|
+
});
|
|
78
|
+
|
|
61
79
|
it('handles dynamic component switching', () => {
|
|
62
80
|
function Child1() @{
|
|
63
81
|
<div>{'I am child 1'}</div>
|
|
@@ -71,7 +89,7 @@ describe('composite > dynamic components', () => {
|
|
|
71
89
|
let &[thing] = track(() => Child1);
|
|
72
90
|
<>
|
|
73
91
|
<div id="container">
|
|
74
|
-
|
|
92
|
+
<Dynamic is={thing} />
|
|
75
93
|
</div>
|
|
76
94
|
<button
|
|
77
95
|
onClick={() => (thing = thing === Child1 ? Child2 : Child1)}
|
|
@@ -463,7 +463,7 @@ function Child1() @{
|
|
|
463
463
|
'handles sibling combinators with dynamic component and :global before scoped elements',
|
|
464
464
|
() => {
|
|
465
465
|
const source = `
|
|
466
|
-
import { track } from 'ripple';
|
|
466
|
+
import { Dynamic, track } from 'ripple';
|
|
467
467
|
|
|
468
468
|
export function Test({ children }) @{
|
|
469
469
|
const DynamicComponent = track(() => Child1);
|
|
@@ -471,7 +471,7 @@ export function Test({ children }) @{
|
|
|
471
471
|
<div>
|
|
472
472
|
<p class="before">{'before'}</p>
|
|
473
473
|
|
|
474
|
-
|
|
474
|
+
<Dynamic is={DynamicComponent} />
|
|
475
475
|
|
|
476
476
|
<p class="foo">
|
|
477
477
|
<span>{'foo'}</span>
|
|
@@ -512,7 +512,7 @@ function Child1() @{
|
|
|
512
512
|
'handles sibling combinators with dynamic element or regular element and :global before scoped elements',
|
|
513
513
|
() => {
|
|
514
514
|
const source = `
|
|
515
|
-
import { track } from 'ripple';
|
|
515
|
+
import { Dynamic, track } from 'ripple';
|
|
516
516
|
|
|
517
517
|
export function Test({ children, classes }) @{
|
|
518
518
|
const dynamicElement = track('div');
|
|
@@ -520,7 +520,7 @@ export function Test({ children, classes }) @{
|
|
|
520
520
|
<div>
|
|
521
521
|
<p class="before">{'before'}</p>
|
|
522
522
|
// Use Dynamic Element but it's the same with a regular one
|
|
523
|
-
|
|
523
|
+
<Dynamic is={dynamicElement} class={classes} />
|
|
524
524
|
|
|
525
525
|
<p class="foo">
|
|
526
526
|
<span>{'foo'}</span>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { track } from 'ripple';
|
|
1
|
+
import { Dynamic, track } from 'ripple';
|
|
2
2
|
import { compile } from '@tsrx/ripple';
|
|
3
3
|
|
|
4
4
|
const external_styles = <style>
|
|
@@ -75,7 +75,7 @@ describe('style class maps', () => {
|
|
|
75
75
|
it('allows style expression classes on child components with children', () => {
|
|
76
76
|
const source = `
|
|
77
77
|
function Child({ className }) @{
|
|
78
|
-
<div class={className}>
|
|
78
|
+
<div class={className}>hello world</div>
|
|
79
79
|
}
|
|
80
80
|
function App() @{
|
|
81
81
|
const styles = <style>
|
|
@@ -84,7 +84,7 @@ function App() @{
|
|
|
84
84
|
}
|
|
85
85
|
</style>;
|
|
86
86
|
|
|
87
|
-
<Child className={styles.container}>
|
|
87
|
+
<Child className={styles.container}>hello world</Child>
|
|
88
88
|
}`;
|
|
89
89
|
|
|
90
90
|
expect(() => compile(source, 'test.tsrx')).not.toThrow();
|
|
@@ -104,7 +104,7 @@ function App() @{
|
|
|
104
104
|
|
|
105
105
|
let dynamic = track(() => Child);
|
|
106
106
|
<div class="wrapper">
|
|
107
|
-
|
|
107
|
+
<Dynamic is={dynamic} cls={styles.text} />
|
|
108
108
|
</div>
|
|
109
109
|
}
|
|
110
110
|
|