solid-js 2.0.0-beta.7 → 2.0.0-beta.9

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/dist/solid.cjs CHANGED
@@ -277,9 +277,12 @@ function hydrateSignalFromAsyncIterable(coreFn, compute, options) {
277
277
  return it;
278
278
  }
279
279
  };
280
- return coreFn(() => iterable, options);
280
+ return coreFn(prev => {
281
+ subFetch(compute, prev);
282
+ return iterable;
283
+ }, options);
281
284
  }
282
- function hydrateStoreFromAsyncIterable(coreFn, initialValue, options) {
285
+ function hydrateStoreFromAsyncIterable(coreFn, fn, initialValue, options) {
283
286
  const parent = signals.getOwner();
284
287
  const expectedId = signals.peekNextChildId(parent);
285
288
  if (!sharedConfig.has(expectedId)) return null;
@@ -289,6 +292,10 @@ function hydrateStoreFromAsyncIterable(coreFn, initialValue, options) {
289
292
  let isFirst = true;
290
293
  let buffered = null;
291
294
  return coreFn(draft => {
295
+ const {
296
+ proxy
297
+ } = createShadowDraft(draft);
298
+ subFetch(fn, proxy);
292
299
  const process = res => {
293
300
  if (res.done) return {
294
301
  done: true,
@@ -296,11 +303,16 @@ function hydrateStoreFromAsyncIterable(coreFn, initialValue, options) {
296
303
  };
297
304
  if (isFirst) {
298
305
  isFirst = false;
299
- if (Array.isArray(res.value)) {
300
- for (let i = 0; i < res.value.length; i++) draft[i] = res.value[i];
301
- draft.length = res.value.length;
302
- } else {
303
- Object.assign(draft, res.value);
306
+ signals.setSnapshotCapture(false);
307
+ try {
308
+ if (Array.isArray(res.value)) {
309
+ for (let i = 0; i < res.value.length; i++) draft[i] = res.value[i];
310
+ draft.length = res.value.length;
311
+ } else {
312
+ Object.assign(draft, res.value);
313
+ }
314
+ } finally {
315
+ signals.setSnapshotCapture(true);
304
316
  }
305
317
  } else {
306
318
  applyPatches(draft, res.value);
@@ -369,13 +381,6 @@ function hydratedCreateMemo(compute, options) {
369
381
  setHydrated(true);
370
382
  return memo;
371
383
  }
372
- if (ssrSource === "initial") {
373
- return signals.createMemo(prev => {
374
- if (!sharedConfig.hydrating) return compute(prev);
375
- subFetch(compute, prev);
376
- return prev;
377
- }, options);
378
- }
379
384
  const aiResult = hydrateSignalFromAsyncIterable(signals.createMemo, compute, options);
380
385
  if (aiResult !== null) return aiResult;
381
386
  return signals.createMemo(prev => readSerializedOrCompute(compute, prev), options);
@@ -395,13 +400,6 @@ function hydratedCreateSignal(fn, second) {
395
400
  setHydrated(true);
396
401
  return sig;
397
402
  }
398
- if (ssrSource === "initial") {
399
- return signals.createSignal(prev => {
400
- if (!sharedConfig.hydrating) return fn(prev);
401
- subFetch(fn, prev);
402
- return prev;
403
- }, second);
404
- }
405
403
  const aiResult = hydrateSignalFromAsyncIterable(signals.createSignal, fn, second);
406
404
  if (aiResult !== null) return aiResult;
407
405
  return signals.createSignal(prev => readSerializedOrCompute(fn, prev), second);
@@ -441,13 +439,6 @@ function hydratedCreateOptimistic(fn, second) {
441
439
  setHydrated(true);
442
440
  return sig;
443
441
  }
444
- if (ssrSource === "initial") {
445
- return signals.createOptimistic(prev => {
446
- if (!sharedConfig.hydrating) return fn(prev);
447
- subFetch(fn, prev);
448
- return prev;
449
- }, second);
450
- }
451
442
  const aiResult = hydrateSignalFromAsyncIterable(signals.createOptimistic, fn, second);
452
443
  if (aiResult !== null) return aiResult;
453
444
  return signals.createOptimistic(prev => readSerializedOrCompute(fn, prev), second);
@@ -491,7 +482,7 @@ function hydrateStoreLikeFn(coreFn, fn, initialValue, options, ssrSource) {
491
482
  setHydrated(true);
492
483
  return result;
493
484
  }
494
- const aiResult = hydrateStoreFromAsyncIterable(coreFn, initialValue, options);
485
+ const aiResult = hydrateStoreFromAsyncIterable(coreFn, fn, initialValue, options);
495
486
  if (aiResult !== null) return aiResult;
496
487
  return coreFn(wrapStoreFn(fn), initialValue, options);
497
488
  }
@@ -499,21 +490,18 @@ function hydratedCreateStore(first, second, third) {
499
490
  if (typeof first !== "function" || !sharedConfig.hydrating) return signals.createStore(first, second, third);
500
491
  markTopLevelSnapshotScope();
501
492
  const ssrSource = third?.ssrSource;
502
- if (ssrSource === "initial") return signals.createStore(second ?? {});
503
493
  return hydrateStoreLikeFn(signals.createStore, first, second ?? {}, third, ssrSource);
504
494
  }
505
495
  function hydratedCreateOptimisticStore(first, second, third) {
506
496
  if (typeof first !== "function" || !sharedConfig.hydrating) return signals.createOptimisticStore(first, second, third);
507
497
  markTopLevelSnapshotScope();
508
498
  const ssrSource = third?.ssrSource;
509
- if (ssrSource === "initial") return signals.createOptimisticStore(second ?? {});
510
499
  return hydrateStoreLikeFn(signals.createOptimisticStore, first, second ?? {}, third, ssrSource);
511
500
  }
512
501
  function hydratedCreateProjection(fn, initialValue, options) {
513
502
  if (!sharedConfig.hydrating) return signals.createProjection(fn, initialValue, options);
514
503
  markTopLevelSnapshotScope();
515
504
  const ssrSource = options?.ssrSource;
516
- if (ssrSource === "initial") return signals.createProjection(draft => draft, initialValue, options);
517
505
  return hydrateStoreLikeFn(signals.createProjection, fn, initialValue, options, ssrSource);
518
506
  }
519
507
  function hydratedEffect(coreFn, compute, effectFn, options) {
@@ -535,14 +523,6 @@ function hydratedEffect(coreFn, compute, effectFn, options) {
535
523
  setHydrated(true);
536
524
  return;
537
525
  }
538
- if (ssrSource === "initial") {
539
- coreFn(prev => {
540
- if (!sharedConfig.hydrating) return compute(prev);
541
- subFetch(compute, prev);
542
- return prev;
543
- }, effectFn, options);
544
- return;
545
- }
546
526
  markTopLevelSnapshotScope();
547
527
  coreFn(prev => readSerializedOrCompute(compute, prev), effectFn, options);
548
528
  }
@@ -854,7 +834,7 @@ function Loading(props) {
854
834
  }
855
835
  function Reveal(props) {
856
836
  return signals.createRevealOrder(() => props.children, {
857
- together: () => !!props.together,
837
+ order: () => props.order ?? "sequential",
858
838
  collapsed: () => !!props.collapsed
859
839
  });
860
840
  }
package/dist/solid.js CHANGED
@@ -276,9 +276,12 @@ function hydrateSignalFromAsyncIterable(coreFn, compute, options) {
276
276
  return it;
277
277
  }
278
278
  };
279
- return coreFn(() => iterable, options);
279
+ return coreFn(prev => {
280
+ subFetch(compute, prev);
281
+ return iterable;
282
+ }, options);
280
283
  }
281
- function hydrateStoreFromAsyncIterable(coreFn, initialValue, options) {
284
+ function hydrateStoreFromAsyncIterable(coreFn, fn, initialValue, options) {
282
285
  const parent = getOwner();
283
286
  const expectedId = peekNextChildId(parent);
284
287
  if (!sharedConfig.has(expectedId)) return null;
@@ -288,6 +291,10 @@ function hydrateStoreFromAsyncIterable(coreFn, initialValue, options) {
288
291
  let isFirst = true;
289
292
  let buffered = null;
290
293
  return coreFn(draft => {
294
+ const {
295
+ proxy
296
+ } = createShadowDraft(draft);
297
+ subFetch(fn, proxy);
291
298
  const process = res => {
292
299
  if (res.done) return {
293
300
  done: true,
@@ -295,11 +302,16 @@ function hydrateStoreFromAsyncIterable(coreFn, initialValue, options) {
295
302
  };
296
303
  if (isFirst) {
297
304
  isFirst = false;
298
- if (Array.isArray(res.value)) {
299
- for (let i = 0; i < res.value.length; i++) draft[i] = res.value[i];
300
- draft.length = res.value.length;
301
- } else {
302
- Object.assign(draft, res.value);
305
+ setSnapshotCapture(false);
306
+ try {
307
+ if (Array.isArray(res.value)) {
308
+ for (let i = 0; i < res.value.length; i++) draft[i] = res.value[i];
309
+ draft.length = res.value.length;
310
+ } else {
311
+ Object.assign(draft, res.value);
312
+ }
313
+ } finally {
314
+ setSnapshotCapture(true);
303
315
  }
304
316
  } else {
305
317
  applyPatches(draft, res.value);
@@ -368,13 +380,6 @@ function hydratedCreateMemo(compute, options) {
368
380
  setHydrated(true);
369
381
  return memo;
370
382
  }
371
- if (ssrSource === "initial") {
372
- return createMemo$1(prev => {
373
- if (!sharedConfig.hydrating) return compute(prev);
374
- subFetch(compute, prev);
375
- return prev;
376
- }, options);
377
- }
378
383
  const aiResult = hydrateSignalFromAsyncIterable(createMemo$1, compute, options);
379
384
  if (aiResult !== null) return aiResult;
380
385
  return createMemo$1(prev => readSerializedOrCompute(compute, prev), options);
@@ -394,13 +399,6 @@ function hydratedCreateSignal(fn, second) {
394
399
  setHydrated(true);
395
400
  return sig;
396
401
  }
397
- if (ssrSource === "initial") {
398
- return createSignal$1(prev => {
399
- if (!sharedConfig.hydrating) return fn(prev);
400
- subFetch(fn, prev);
401
- return prev;
402
- }, second);
403
- }
404
402
  const aiResult = hydrateSignalFromAsyncIterable(createSignal$1, fn, second);
405
403
  if (aiResult !== null) return aiResult;
406
404
  return createSignal$1(prev => readSerializedOrCompute(fn, prev), second);
@@ -440,13 +438,6 @@ function hydratedCreateOptimistic(fn, second) {
440
438
  setHydrated(true);
441
439
  return sig;
442
440
  }
443
- if (ssrSource === "initial") {
444
- return createOptimistic$1(prev => {
445
- if (!sharedConfig.hydrating) return fn(prev);
446
- subFetch(fn, prev);
447
- return prev;
448
- }, second);
449
- }
450
441
  const aiResult = hydrateSignalFromAsyncIterable(createOptimistic$1, fn, second);
451
442
  if (aiResult !== null) return aiResult;
452
443
  return createOptimistic$1(prev => readSerializedOrCompute(fn, prev), second);
@@ -490,7 +481,7 @@ function hydrateStoreLikeFn(coreFn, fn, initialValue, options, ssrSource) {
490
481
  setHydrated(true);
491
482
  return result;
492
483
  }
493
- const aiResult = hydrateStoreFromAsyncIterable(coreFn, initialValue, options);
484
+ const aiResult = hydrateStoreFromAsyncIterable(coreFn, fn, initialValue, options);
494
485
  if (aiResult !== null) return aiResult;
495
486
  return coreFn(wrapStoreFn(fn), initialValue, options);
496
487
  }
@@ -498,21 +489,18 @@ function hydratedCreateStore(first, second, third) {
498
489
  if (typeof first !== "function" || !sharedConfig.hydrating) return createStore$1(first, second, third);
499
490
  markTopLevelSnapshotScope();
500
491
  const ssrSource = third?.ssrSource;
501
- if (ssrSource === "initial") return createStore$1(second ?? {});
502
492
  return hydrateStoreLikeFn(createStore$1, first, second ?? {}, third, ssrSource);
503
493
  }
504
494
  function hydratedCreateOptimisticStore(first, second, third) {
505
495
  if (typeof first !== "function" || !sharedConfig.hydrating) return createOptimisticStore$1(first, second, third);
506
496
  markTopLevelSnapshotScope();
507
497
  const ssrSource = third?.ssrSource;
508
- if (ssrSource === "initial") return createOptimisticStore$1(second ?? {});
509
498
  return hydrateStoreLikeFn(createOptimisticStore$1, first, second ?? {}, third, ssrSource);
510
499
  }
511
500
  function hydratedCreateProjection(fn, initialValue, options) {
512
501
  if (!sharedConfig.hydrating) return createProjection$1(fn, initialValue, options);
513
502
  markTopLevelSnapshotScope();
514
503
  const ssrSource = options?.ssrSource;
515
- if (ssrSource === "initial") return createProjection$1(draft => draft, initialValue, options);
516
504
  return hydrateStoreLikeFn(createProjection$1, fn, initialValue, options, ssrSource);
517
505
  }
518
506
  function hydratedEffect(coreFn, compute, effectFn, options) {
@@ -534,14 +522,6 @@ function hydratedEffect(coreFn, compute, effectFn, options) {
534
522
  setHydrated(true);
535
523
  return;
536
524
  }
537
- if (ssrSource === "initial") {
538
- coreFn(prev => {
539
- if (!sharedConfig.hydrating) return compute(prev);
540
- subFetch(compute, prev);
541
- return prev;
542
- }, effectFn, options);
543
- return;
544
- }
545
525
  markTopLevelSnapshotScope();
546
526
  coreFn(prev => readSerializedOrCompute(compute, prev), effectFn, options);
547
527
  }
@@ -853,7 +833,7 @@ function Loading(props) {
853
833
  }
854
834
  function Reveal(props) {
855
835
  return createRevealOrder(() => props.children, {
856
- together: () => !!props.together,
836
+ order: () => props.order ?? "sequential",
857
837
  collapsed: () => !!props.collapsed
858
838
  });
859
839
  }
package/package.json CHANGED
@@ -1,13 +1,14 @@
1
1
  {
2
2
  "name": "solid-js",
3
- "description": "A declarative JavaScript library for building user interfaces.",
4
- "version": "2.0.0-beta.7",
3
+ "description": "Reactive JavaScript library for building user interfaces. Compiles JSX to real DOM with fine-grained signal-based updates — no virtual DOM.",
4
+ "version": "2.0.0-beta.9",
5
5
  "author": "Ryan Carniato",
6
6
  "license": "MIT",
7
7
  "homepage": "https://solidjs.com",
8
8
  "repository": {
9
9
  "type": "git",
10
- "url": "https://github.com/solidjs/solid"
10
+ "url": "git+https://github.com/solidjs/solid.git",
11
+ "directory": "packages/solid"
11
12
  },
12
13
  "main": "./dist/server.cjs",
13
14
  "module": "./dist/server.js",
@@ -20,7 +21,8 @@
20
21
  "types",
21
22
  "types-cjs",
22
23
  "jsx-runtime.d.ts",
23
- "package.json"
24
+ "package.json",
25
+ "CHEATSHEET.md"
24
26
  ],
25
27
  "exports": {
26
28
  ".": {
@@ -126,7 +128,7 @@
126
128
  "performance"
127
129
  ],
128
130
  "dependencies": {
129
- "@solidjs/signals": "^2.0.0-beta.7",
131
+ "@solidjs/signals": "^2.0.0-beta.9",
130
132
  "csstype": "^3.1.0",
131
133
  "seroval": "~1.5.0",
132
134
  "seroval-plugins": "~1.5.0"
@@ -63,7 +63,39 @@ export type ComponentProps<T extends ValidComponent> = T extends Component<infer
63
63
  * @example Component<{ref: Ref<Element>}>
64
64
  */
65
65
  export type Ref<T> = T | ((val: T) => void);
66
+ /**
67
+ * Invokes a component, wrapping the call in `untrack` so that reactive reads
68
+ * inside the component body don't subscribe the parent computation. Compiled
69
+ * JSX uses this internally; manual calls are rarely needed unless authoring a
70
+ * custom JSX factory or renderer.
71
+ */
66
72
  export declare function createComponent<T extends Record<string, any>>(Comp: Component<T>, props: T): JSX.Element;
73
+ /**
74
+ * Defines a code-split component. The returned component triggers its dynamic
75
+ * import on first render and suspends through any enclosing `<Loading>`
76
+ * boundary while the chunk is in flight. Call `.preload()` to start the
77
+ * import early (e.g. on hover).
78
+ *
79
+ * @param fn dynamic import returning the module's default export
80
+ * @param moduleUrl optional module URL used during hydration to look up
81
+ * preloaded chunks; usually injected by the bundler integration
82
+ *
83
+ * @example
84
+ * ```tsx
85
+ * const Profile = lazy(() => import("./Profile"));
86
+ *
87
+ * function App() {
88
+ * return (
89
+ * <Loading fallback={<Spinner />}>
90
+ * <Profile id="42" />
91
+ * </Loading>
92
+ * );
93
+ * }
94
+ *
95
+ * // Preload before the user clicks
96
+ * <button onMouseEnter={() => Profile.preload()}>Open profile</button>
97
+ * ```
98
+ */
67
99
  export declare function lazy<T extends Component<any>>(fn: () => Promise<{
68
100
  default: T;
69
101
  }>, moduleUrl?: string): T & {
@@ -72,4 +104,22 @@ export declare function lazy<T extends Component<any>>(fn: () => Promise<{
72
104
  }>;
73
105
  moduleUrl?: string;
74
106
  };
107
+ /**
108
+ * Returns a stable id string that matches between server-rendered and
109
+ * client-hydrated trees. Use it for `<label for>`, `aria-labelledby`, and
110
+ * other attributes that need consistent ids across SSR.
111
+ *
112
+ * @example
113
+ * ```tsx
114
+ * function Field(props: { label: string }) {
115
+ * const id = createUniqueId();
116
+ * return (
117
+ * <>
118
+ * <label for={id}>{props.label}</label>
119
+ * <input id={id} />
120
+ * </>
121
+ * );
122
+ * }
123
+ * ```
124
+ */
75
125
  export declare function createUniqueId(): string;
@@ -9,34 +9,101 @@ export type ContextProviderComponent<T> = FlowComponent<{
9
9
  }>;
10
10
  export interface Context<T> extends ContextProviderComponent<T> {
11
11
  id: symbol;
12
- defaultValue: T;
12
+ defaultValue: T | undefined;
13
13
  }
14
14
  /**
15
- * Creates a Context to handle a state scoped for the children of a component
16
- * ```typescript
17
- * interface Context<T> {
18
- * id: symbol;
19
- * Provider: FlowComponent<{ value: T }>;
20
- * defaultValue: T;
15
+ * Creates a Context for sharing state with descendants of a Provider in the
16
+ * component tree.
17
+ *
18
+ * The returned `Context` is itself a provider component — pass it a `value`
19
+ * prop to scope a value to its children. Read it inside descendants with
20
+ * `useContext`.
21
+ *
22
+ * Two forms:
23
+ *
24
+ * - **`createContext<T>()`** (default-less, the canonical form). Reading via
25
+ * `useContext` outside an enclosing Provider throws `ContextNotFoundError`.
26
+ * Use this for everything that carries reactive state — signals, stores,
27
+ * `[state, actions]` tuples, services. The Provider is mandatory by
28
+ * construction; the throw makes a missing Provider a loud bug instead of a
29
+ * silent no-op. The annotation `<T>` is required because there is no value
30
+ * to infer from.
31
+ * - **`createContext<T>(defaultValue)`** (default form). Reserved for the
32
+ * narrow case of contexts whose value is a primitive with a meaningful
33
+ * static fallback (theme, locale, frozen config). Outside any Provider,
34
+ * `useContext` returns `defaultValue`.
35
+ *
36
+ * If you want truly app-wide state, **don't use Context** — a module-scope
37
+ * signal/store *is* a global. Context is for scoping state to a subtree;
38
+ * that's why a Provider is required.
39
+ *
40
+ * @param defaultValue optional default; only meaningful for primitive
41
+ * fallbacks. Omit for any context carrying reactive state.
42
+ * @param options `{ name }` for debugging in development
43
+ * @returns a context object that doubles as its own provider component
44
+ *
45
+ * @example
46
+ * ```tsx
47
+ * // Reactive payload — default-less, throws if no Provider.
48
+ * type TodosCtx = readonly [Store<Todo[]>, TodoActions];
49
+ * const TodosContext = createContext<TodosCtx>();
50
+ *
51
+ * function App() {
52
+ * return (
53
+ * <TodosContext value={createTodos()}>
54
+ * <TodoList />
55
+ * </TodosContext>
56
+ * );
57
+ * }
58
+ *
59
+ * function TodoList() {
60
+ * const [todos, { addTodo }] = useContext(TodosContext); // typed as TodosCtx
61
+ * // ...
62
+ * }
63
+ * ```
64
+ *
65
+ * @example
66
+ * ```tsx
67
+ * // Primitive default — falls back to "light" outside a Provider.
68
+ * const ThemeContext = createContext<"light" | "dark">("light");
69
+ *
70
+ * function Button() {
71
+ * const theme = useContext(ThemeContext); // "light" | "dark"
72
+ * return <button class={theme}>Click</button>;
21
73
  * }
22
- * export function createContext<T>(
23
- * defaultValue?: T,
24
- * options?: { name?: string }
25
- * ): Context<T | undefined>;
26
74
  * ```
27
- * @param defaultValue optional default to inject into context
28
- * @param options allows to set a name in dev mode for debugging purposes
29
- * @returns The context that contains the Provider Component and that can be used with `useContext`
30
75
  *
31
76
  * @description https://docs.solidjs.com/reference/component-apis/create-context
32
77
  */
33
- export declare function createContext<T>(defaultValue?: undefined, options?: EffectOptions): Context<T | undefined>;
34
- export declare function createContext<T>(defaultValue: T, options?: EffectOptions): Context<T>;
78
+ export declare function createContext<T>(defaultValue?: T, options?: EffectOptions): Context<T>;
35
79
  /**
36
- * Uses a context to receive a scoped state from a parent's Context.Provider
80
+ * Reads the current value of a context.
81
+ *
82
+ * - For `createContext<T>()` (default-less): returns the value from the
83
+ * nearest enclosing Provider, or throws `ContextNotFoundError` if none is
84
+ * mounted. Return type is `T` (no narrowing required).
85
+ * - For `createContext<T>(defaultValue)`: returns the value from the nearest
86
+ * enclosing Provider, or `defaultValue` if none is mounted.
37
87
  *
38
- * @param context Context object made by `createContext`
39
- * @returns the current or `defaultValue`, if present
88
+ * In Solid, `useContext` is the canonical way to read context. There is no
89
+ * need for a wrapper hook that throws on missing Provider — the default-less
90
+ * form already does that, and its return type is `T`.
91
+ *
92
+ * @param context a context returned from `createContext`
93
+ * @returns the value provided by the nearest enclosing Provider, or the
94
+ * default if one was supplied to `createContext`
95
+ * @throws `ContextNotFoundError` if no Provider is mounted and the context
96
+ * was created without a default
97
+ *
98
+ * @example
99
+ * ```tsx
100
+ * const TodosContext = createContext<TodosCtx>();
101
+ *
102
+ * function TodoList() {
103
+ * const [todos, { addTodo }] = useContext(TodosContext); // throws if no Provider
104
+ * // ...
105
+ * }
106
+ * ```
40
107
  *
41
108
  * @description https://docs.solidjs.com/reference/component-apis/use-context
42
109
  */
@@ -47,10 +114,20 @@ export type ChildrenReturn = Accessor<ResolvedChildren> & {
47
114
  toArray: () => ResolvedJSXElement[];
48
115
  };
49
116
  /**
50
- * Resolves child elements to help interact with children
117
+ * Resolves a `children` accessor and exposes the result as an accessor with
118
+ * a `.toArray()` helper. Use this when a component needs to inspect or
119
+ * iterate over its children rather than just render them through.
51
120
  *
52
121
  * @param fn an accessor for the children
53
- * @returns a accessor of the same children, but resolved
122
+ * @returns an accessor of the resolved children, with `.toArray()` for iteration
123
+ *
124
+ * @example
125
+ * ```tsx
126
+ * function List(props: { children: JSX.Element }) {
127
+ * const items = children(() => props.children);
128
+ * return <ul>{items.toArray().map(item => <li>{item}</li>)}</ul>;
129
+ * }
130
+ * ```
54
131
  *
55
132
  * @description https://docs.solidjs.com/reference/component-apis/children
56
133
  */