ripple 0.2.104 → 0.2.106

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.
@@ -0,0 +1,32 @@
1
+ /** @import { Block } from '#client' */
2
+
3
+ import { branch, destroy_block, render } from './blocks.js';
4
+ import { SWITCH_BLOCK } from './constants.js';
5
+
6
+ /**
7
+ * @param {Node} node
8
+ * @param {() => ((anchor: Node) => void)} fn
9
+ * @returns {void}
10
+ */
11
+ export function switch_block(node, fn) {
12
+ var anchor = node;
13
+ /** @type {any} */
14
+ var current_branch = null;
15
+ /** @type {Block | null} */
16
+ var b = null;
17
+
18
+ render(() => {
19
+ const branch_fn = fn() ?? null;
20
+ if (current_branch === branch_fn) return;
21
+ current_branch = branch_fn;
22
+
23
+ if (b !== null) {
24
+ destroy_block(b);
25
+ b = null;
26
+ }
27
+
28
+ if (branch_fn !== null) {
29
+ b = branch(() => branch_fn(anchor));
30
+ }
31
+ }, SWITCH_BLOCK);
32
+ }
@@ -0,0 +1,39 @@
1
+ import { on } from './internal/client/events.js';
2
+ import { get, safe_scope, set, tracked } from './internal/client/index.js';
3
+ import { ReactiveValue } from './reactive-value.js';
4
+
5
+ const parenthesis_regex = /\(.+\)/;
6
+ const non_parenthesized_keywords = new Set(['all', 'print', 'screen', 'and', 'or', 'not', 'only']);
7
+
8
+ /**
9
+ * @constructor
10
+ * @param {string} query
11
+ * @param {boolean | undefined} [fallback]
12
+ * @returns {ReactiveValue<boolean>}
13
+ */
14
+ export function MediaQuery(query, fallback) {
15
+ if (!new.target) {
16
+ throw new TypeError('MediaQuery must be called with new');
17
+ }
18
+
19
+ var block = safe_scope();
20
+
21
+ let final_query =
22
+ parenthesis_regex.test(query) ||
23
+ // we need to use `some` here because technically this `window.matchMedia('random,screen')` still returns true
24
+ query.split(/[\s,]+/).some((keyword) => non_parenthesized_keywords.has(keyword.trim()))
25
+ ? query
26
+ : `(${query})`;
27
+ const q = window.matchMedia(final_query);
28
+ const matches = tracked(q.matches, block);
29
+
30
+ return new ReactiveValue(
31
+ () => get(matches),
32
+ () => on(q, 'change', () => {
33
+ // skip wrapping in untrack as createSubscriber already does it
34
+ if (q.matches !== get(matches)) {
35
+ set(matches, q.matches, block)
36
+ }
37
+ })
38
+ );
39
+ }
@@ -0,0 +1,21 @@
1
+ /** @import { Derived } from '#client' */
2
+ import { createSubscriber } from './create-subscriber.js';
3
+ import { safe_scope, derived } from './internal/client/runtime.js';
4
+
5
+ /**
6
+ * @template V
7
+ * @constructor
8
+ * @param {() => V} fn
9
+ * @param {() => void | (() => void)} start
10
+ * @returns {Derived}
11
+ */
12
+ export function ReactiveValue(fn, start) {
13
+ if (!new.target) {
14
+ throw new TypeError('`ReactiveValue` must be called with new');
15
+ }
16
+
17
+ const s = createSubscriber(start);
18
+ const block = safe_scope();
19
+
20
+ return (derived(fn, block, () => { s(); return fn(); }, (_, prev) => prev));
21
+ }
@@ -0,0 +1,147 @@
1
+ import { get, increment, safe_scope, tracked } from './internal/client/runtime.js';
2
+ import { get_current_url } from './url.js';
3
+
4
+ export const REPLACE = Symbol();
5
+
6
+
7
+ export class TrackedURLSearchParams extends URLSearchParams {
8
+ #block = safe_scope();
9
+ #version = tracked(0, this.#block);
10
+ #url = get_current_url();
11
+
12
+ #updating = false;
13
+
14
+ #update_url() {
15
+ if (!this.#url || this.#updating) return;
16
+ this.#updating = true;
17
+
18
+ const search = this.toString();
19
+ this.#url.search = search && `?${search}`;
20
+
21
+ this.#updating = false;
22
+ }
23
+
24
+ /**
25
+ * @param {URLSearchParams} params
26
+ * @internal
27
+ */
28
+ [REPLACE](params) {
29
+ if (this.#updating) return;
30
+ this.#updating = true;
31
+
32
+ for (const key of [...super.keys()]) {
33
+ super.delete(key);
34
+ }
35
+
36
+ for (const [key, value] of params) {
37
+ super.append(key, value);
38
+ }
39
+
40
+ increment(this.#version, this.#block);
41
+ this.#updating = false;
42
+ }
43
+
44
+ /**
45
+ * @param {string} name
46
+ * @param {string} value
47
+ * @returns {void}
48
+ */
49
+ append(name, value) {
50
+ super.append(name, value);
51
+ this.#update_url();
52
+ increment(this.#version, this.#block);
53
+ }
54
+
55
+ /**
56
+ * @param {string} name
57
+ * @param {string=} value
58
+ * @returns {void}
59
+ */
60
+ delete(name, value) {
61
+ var has_value = super.has(name, value);
62
+ super.delete(name, value);
63
+ if (has_value) {
64
+ this.#update_url();
65
+ increment(this.#version, this.#block);
66
+ }
67
+ }
68
+
69
+ /**
70
+ * @param {string} name
71
+ * @returns {string|null}
72
+ */
73
+ get(name) {
74
+ get(this.#version);
75
+ return super.get(name);
76
+ }
77
+
78
+ /**
79
+ * @param {string} name
80
+ * @returns {string[]}
81
+ */
82
+ getAll(name) {
83
+ get(this.#version);
84
+ return super.getAll(name);
85
+ }
86
+
87
+ /**
88
+ * @param {string} name
89
+ * @param {string=} value
90
+ * @returns {boolean}
91
+ */
92
+ has(name, value) {
93
+ get(this.#version);
94
+ return super.has(name, value);
95
+ }
96
+
97
+ keys() {
98
+ get(this.#version);
99
+ return super.keys();
100
+ }
101
+
102
+ /**
103
+ * @param {string} name
104
+ * @param {string} value
105
+ * @returns {void}
106
+ */
107
+ set(name, value) {
108
+ var previous = super.getAll(name).join('');
109
+ super.set(name, value);
110
+ // can't use has(name, value), because for something like https://svelte.dev?foo=1&bar=2&foo=3
111
+ // if you set `foo` to 1, then foo=3 gets deleted whilst `has("foo", "1")` returns true
112
+ if (previous !== super.getAll(name).join('')) {
113
+ this.#update_url();
114
+ increment(this.#version, this.#block);
115
+ }
116
+ }
117
+
118
+ sort() {
119
+ super.sort();
120
+ this.#update_url();
121
+ increment(this.#version, this.#block);
122
+ }
123
+
124
+ toString() {
125
+ get(this.#version);
126
+ return super.toString();
127
+ }
128
+
129
+ values() {
130
+ get(this.#version);
131
+ return super.values();
132
+ }
133
+
134
+ entries() {
135
+ get(this.#version);
136
+ return super.entries();
137
+ }
138
+
139
+ [Symbol.iterator]() {
140
+ return this.entries();
141
+ }
142
+
143
+ get size() {
144
+ get(this.#version);
145
+ return super.size;
146
+ }
147
+ }
@@ -0,0 +1,164 @@
1
+ import { get, set, safe_scope, tracked } from './internal/client/runtime.js';
2
+ import { REPLACE, TrackedURLSearchParams } from './url-search-params.js';
3
+
4
+ /** @type {TrackedURL | null} */
5
+ let current_url = null;
6
+
7
+ export function get_current_url() {
8
+ return current_url;
9
+ }
10
+
11
+ export class TrackedURL extends URL {
12
+ #block = safe_scope();
13
+ #protocol = tracked(super.protocol, this.#block);
14
+ #username = tracked(super.username, this.#block);
15
+ #password = tracked(super.password, this.#block);
16
+ #hostname = tracked(super.hostname, this.#block);
17
+ #port = tracked(super.port, this.#block);
18
+ #pathname = tracked(super.pathname, this.#block);
19
+ #hash = tracked(super.hash, this.#block);
20
+ #search = tracked(super.search, this.#block);
21
+ #searchParams;
22
+
23
+ /**
24
+ * @param {string | URL} url
25
+ * @param {string | URL} [base]
26
+ */
27
+ constructor(url, base) {
28
+ url = new URL(url, base);
29
+ super(url);
30
+
31
+ current_url = this;
32
+ this.#searchParams = new TrackedURLSearchParams(url.searchParams);
33
+ current_url = null;
34
+ }
35
+
36
+ get hash() {
37
+ return get(this.#hash);
38
+ }
39
+
40
+ set hash(value) {
41
+ super.hash = value;
42
+ set(this.#hash, super.hash, this.#block);
43
+ }
44
+
45
+ get host() {
46
+ get(this.#hostname);
47
+ get(this.#port);
48
+ return super.host;
49
+ }
50
+
51
+ set host(value) {
52
+ super.host = value;
53
+ set(this.#hostname, super.hostname, this.#block);
54
+ set(this.#port, super.port, this.#block);
55
+ }
56
+
57
+ get hostname() {
58
+ return get(this.#hostname);
59
+ }
60
+
61
+ set hostname(value) {
62
+ super.hostname = value;
63
+ set(this.#hostname, super.hostname, this.#block);
64
+ }
65
+
66
+ get href() {
67
+ get(this.#protocol);
68
+ get(this.#username);
69
+ get(this.#password);
70
+ get(this.#hostname);
71
+ get(this.#port);
72
+ get(this.#pathname);
73
+ get(this.#hash);
74
+ get(this.#search);
75
+ return super.href;
76
+ }
77
+
78
+ set href(value) {
79
+ super.href = value;
80
+ set(this.#protocol, super.protocol, this.#block);
81
+ set(this.#username, super.username, this.#block);
82
+ set(this.#password, super.password, this.#block);
83
+ set(this.#hostname, super.hostname, this.#block);
84
+ set(this.#port, super.port, this.#block);
85
+ set(this.#pathname, super.pathname, this.#block);
86
+ set(this.#hash, super.hash, this.#block);
87
+ set(this.#search, super.search, this.#block);
88
+ this.#searchParams[REPLACE](super.searchParams);
89
+ }
90
+
91
+ get password() {
92
+ return get(this.#password);
93
+ }
94
+
95
+ set password(value) {
96
+ super.password = value;
97
+ set(this.#password, super.password, this.#block);
98
+ }
99
+
100
+ get pathname() {
101
+ return get(this.#pathname);
102
+ }
103
+
104
+ set pathname(value) {
105
+ super.pathname = value;
106
+ set(this.#pathname, super.pathname, this.#block);
107
+ }
108
+
109
+ get port() {
110
+ return get(this.#port);
111
+ }
112
+
113
+ set port(value) {
114
+ super.port = value;
115
+ set(this.#port, super.port, this.#block);
116
+ }
117
+
118
+ get protocol() {
119
+ return get(this.#protocol);
120
+ }
121
+
122
+ set protocol(value) {
123
+ super.protocol = value;
124
+ set(this.#protocol, super.protocol, this.#block);
125
+ }
126
+
127
+ get search() {
128
+ return get(this.#search);
129
+ }
130
+
131
+ set search(value) {
132
+ super.search = value;
133
+ set(this.#search, value, this.#block);
134
+ this.#searchParams[REPLACE](super.searchParams);
135
+ }
136
+
137
+ get username() {
138
+ return get(this.#username);
139
+ }
140
+
141
+ set username(value) {
142
+ super.username = value;
143
+ set(this.#username, super.username, this.#block);
144
+ }
145
+
146
+ get origin() {
147
+ get(this.#protocol);
148
+ get(this.#hostname);
149
+ get(this.#port);
150
+ return super.origin;
151
+ }
152
+
153
+ get searchParams() {
154
+ return this.#searchParams;
155
+ }
156
+
157
+ toString() {
158
+ return this.href;
159
+ }
160
+
161
+ toJSON() {
162
+ return this.href;
163
+ }
164
+ }
@@ -774,8 +774,39 @@ export function jsx_spread_attribute(argument) {
774
774
  };
775
775
  }
776
776
 
777
+
778
+ /**
779
+ * @returns {ESTree.SwitchStatement}
780
+ */
781
+ export function switch_builder(discriminant, cases) {
782
+ return {
783
+ type: 'SwitchStatement',
784
+ discriminant,
785
+ cases,
786
+ };
787
+ }
788
+
789
+ /**
790
+ * @returns {ESTree.SwitchCase}
791
+ */
792
+ export function switch_case(test = null, consequent = []) {
793
+ return {
794
+ type: 'SwitchCase',
795
+ test,
796
+ consequent,
797
+ };
798
+ }
799
+
777
800
  export const void0 = unary('void', literal(0));
778
801
 
802
+ /**
803
+ * @returns {ESTree.BreakStatement}
804
+ */
805
+ export const break_statement = {
806
+ type: 'BreakStatement',
807
+ label: null,
808
+ };
809
+
779
810
  export {
780
811
  await_builder as await,
781
812
  let_builder as let,
@@ -783,7 +814,9 @@ export {
783
814
  var_builder as var,
784
815
  true_instance as true,
785
816
  false_instance as false,
817
+ break_statement as break,
786
818
  for_builder as for,
819
+ switch_builder as switch,
787
820
  function_builder as function,
788
821
  return_builder as return,
789
822
  if_builder as if,
@@ -0,0 +1,12 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`compiler success tests > compiles tracked values in effect with assignment expression 1`] = `"state.count = _$_.get(count);"`;
4
+
5
+ exports[`compiler success tests > compiles tracked values in effect with update expressions 1`] = `
6
+ "_$_.with_scope(__block, () => untrack(() => {
7
+ state.preIncrement = _$_.update_pre(count, __block);
8
+ state.postIncrement = _$_.update(count, __block);
9
+ state.preDecrement = _$_.update_pre(count, __block, -1);
10
+ state.postDecrement = _$_.update(count, __block, -1);
11
+ }));"
12
+ `;
@@ -0,0 +1,34 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`TrackedExpression tests > should handle the syntax correctly 1`] = `
4
+ <div>
5
+ <div>
6
+ 0
7
+ </div>
8
+ <div>
9
+ 0
10
+ </div>
11
+ <div>
12
+ 1
13
+ </div>
14
+ <div>
15
+ 2
16
+ </div>
17
+ <div>
18
+ 2
19
+ </div>
20
+ <div>
21
+ 3
22
+ </div>
23
+ <div>
24
+ 4
25
+ </div>
26
+ <div>
27
+ false
28
+ </div>
29
+ <div>
30
+ true
31
+ </div>
32
+
33
+ </div>
34
+ `;
@@ -1843,5 +1843,50 @@ describe('basic client', () => {
1843
1843
 
1844
1844
  expect(error).toBe(undefined);
1845
1845
  });
1846
- });
1847
1846
 
1847
+ it('unwraps tracked values inside effect', () => {
1848
+ let state = {};
1849
+
1850
+ component Basic() {
1851
+ let count = track(0);
1852
+
1853
+ effect(() => {
1854
+ state.count = @count;
1855
+ })
1856
+ }
1857
+
1858
+ render(Basic);
1859
+ flushSync();
1860
+
1861
+ expect(state.count).toBe(0);
1862
+ });
1863
+
1864
+ it('does not unwrap values with update expressions inside effect', () => {
1865
+ let state = {};
1866
+
1867
+ component Basic() {
1868
+ let count = track(5);
1869
+
1870
+ effect(() => {
1871
+ untrack(() => {
1872
+ state.initialValue = @count;
1873
+ state.preIncrement = ++@count;
1874
+ state.postIncrement = @count++;
1875
+ state.preDecrement = --@count;
1876
+ state.postDecrement = @count--;
1877
+ state.finalValue = @count;
1878
+ });
1879
+ })
1880
+ }
1881
+
1882
+ render(Basic);
1883
+ flushSync();
1884
+
1885
+ expect(state.initialValue).toBe(5);
1886
+ expect(state.preIncrement).toBe(6);
1887
+ expect(state.postIncrement).toBe(6);
1888
+ expect(state.preDecrement).toBe(6);
1889
+ expect(state.postDecrement).toBe(6);
1890
+ expect(state.finalValue).toBe(5);
1891
+ });
1892
+ });