Skip to content

Commit

Permalink
Merge pull request #244 from ryansolid/next
Browse files Browse the repository at this point in the history
Attributes By Default, SSR Improvements, Bug Fixes
  • Loading branch information
ryansolid authored Oct 18, 2020
2 parents 364124c + d3b207c commit c3211d7
Show file tree
Hide file tree
Showing 31 changed files with 17,024 additions and 16,847 deletions.
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
# Changelog

## 0.21.0 - 2020-10-17

### Attribute and Prop changes

We will now default to using Attributes where possible to be consistent. Solid is aiming to generally reflect the case insensitiveness of HTML. Custom Elements remain the one place that defaults to property setters on Dynamic elements.

While TypeScript 4.2 is yet to be released, we are introduce `attr`, `prop`, `use` and `style` namespace directives. To allow more expressiveness in binding syntax.

### Other Changes

* New `on` and `onMount` helpers
* More performant SSR escaping
* Lazy eval SSR Component props (fix SSR Context API)
* Add support for SSR with Solid Styled Components
* Fix Lit Dom Expressions style in Template tags
* Fix JSX Types

## 0.20.0 - 2020-09-24

### Re-scheduling Reactivity.
Expand Down
23 changes: 15 additions & 8 deletions documentation/api.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
# Core API

### `createSignal(initialValue, boolean | comparatorFn): [getValueFn, setValueFn]`

This is the smallest and most primitive reactive atom used to track a single value. By default signals always notify on setting a value. You can have it only notify on changes is you pass true to the second parameter. Or a custom comparator can be passed in to indicate whether the values should be considered equal and listeners not notified.

### `createState(initValue): [state, setState]`

Creates a new State object and setState pair that can be used to maintain your componenents state. State only triggers update on values changing. Tracking is done by intercepting property access and automatically tracks deep nesting via proxy.
Creates a new State proxy object and setState pair. State only triggers update on values changing. Tracking is done by intercepting property access and automatically tracks deep nesting via proxy.

### `createSignal(initialValue, boolean | comparatorFn): [getValueFn, setValueFn]`
### `onMount(() => <code>)`
Registers a method that runs after initial render and elements have been mounted. Ideal for using `ref`s and managing other one time side effects.

This is the smallest and most primitive reactive atom used to track a single value. By default signals always notify on setting a value. You can have it only notify on changes is you pass true to the second parameter. Or a custom comparator can be passed in to indicate whether the values should be considered equal and listeners not notified.
### `onCleanup(() => <code>)`

Registers a cleanup method that executes on disposal or recalculation of the current context. Can be used in components or computations.

### `createMemo(prev => <code>, initialValue, boolean | comparatorFn): getValueFn`

Expand All @@ -18,11 +25,7 @@ Creates a new computation that automatically tracks dependencies and runs immedi

### `createEffect(prev => <code>, initialValue): void`

Creates a new computation that automatically tracks dependencies and runs after render. Ideal for using `ref`s and managing other side effects. 2nd argument is the initial value.

### `onCleanup(() => <code>)`

Registers a cleanup methodthat executes on disposal or recalculation of the current context.
Creates a new computation that automatically tracks dependencies and runs after each render where a dependency has changed. Ideal for using `ref`s and managing other side effects. 2nd argument is the initial value.

### `createContext(defaultContext): Context`

Expand Down Expand Up @@ -59,6 +62,10 @@ Registers a error handler method that executes when child context errors. Only n

Creates memo that only notifies downstream changes when the browser is idle. `timeoutMS` is the maximum time to wait before forcing the update.

### `createRenderEffect(prev => <code>, initialValue): void`

Creates a new computation that automatically tracks dependencies and runs during the render phase as DOM elements are created and updated but not necessarily connected. All internal DOM updates happen at this time.

### `createSelector(() => <code>, comparatorFn?): (key) => boolean`

Creates a conditional signal that only notifies subscribers when entering or exiting their key matching the value. Useful for delegated selection state.
Expand Down
7 changes: 4 additions & 3 deletions documentation/components.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,9 @@ const [local, others] = splitProps(props, ["className"])

## Lifecycle

Instead of lifecycles in Solid are tied to the lifecycle of the reactive system.
All lifecycles in Solid are tied to the lifecycle of the reactive system.

If you wish to perform some side effect on mount or after update use `createEffect`:
If you wish to perform some side effect on mount or after update use `createEffect` after render has complete:

```jsx
import { createSignal, createEffect } from 'solid-js';
Expand All @@ -123,8 +123,9 @@ function Example() {
);
}
```
For convenience if you need to only run it once you can use `onMount` which is the same as `createEffect` but will only run once. Keep in mind Solid's cleanup is independent of this mechanism. So if you aren't reading the DOM you don't need to use these.

If you wish to release something on the Component being destroyed, simply wrap in an `onCleanup`:
If you wish to release something on the Component being destroyed, simply wrap in an `onCleanup`.

```jsx
const Ticker = () => {
Expand Down
44 changes: 42 additions & 2 deletions documentation/rendering.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Solid supports templating in 3 forms JSX, Tagged Template Literals, and Solid's HyperScript variant. Although JSX is the predominate form. Why? JSX is a great DSL made for compilation. It has clear syntax, supports TypeScript, works with Babel, supports other tooling like Code Syntax Highlighting and Prettier. It was only pragmatic to use a tool that basically gives you that all for free. As a compiled solution it provides great DX. Why struggle with custom Syntax DSLs when you can use one so widely supported?

Still there is some confusion as to what JSX is and is not. JSX is an XML-like syntax extension to EcmaScript (https://facebook.github.io/jsx/). It is not a language or runtime. Those can be refered to as HyperScript. So while Solid's JSX and might resemble React it by no means works like React and there should be no illusions that a JSX library will just work with Solid. Afterall, there are no JSX libraries, as they all work without JSX, only HyperScript or React ones.
Still there is some confusion as to what JSX is and is not. JSX is an XML-like syntax extension to EcmaScript (https://facebook.github.io/jsx/). It is not a language or runtime. Those can be refered to as HyperScript. So while Solid's JSX and might resemble React it by no means works like React and there should be no illusions that a JSX library will just work with Solid. Afterall, there are no JSX libraries, as they all work without JSX, only HyperScript ones.

## JSX Compilation

Expand All @@ -16,7 +16,22 @@ This approach both is more performant and produces less code then creating each

More documentation is available at: [babel-plugin-jsx-dom-expressions](https://github.com/ryansolid/dom-expressions/tree/master/packages/babel-plugin-jsx-dom-expressions)

### Note on attribute binding order
## Attributes and Props

Solid attempts to reflect HTML conventions as much as possible including case insensitivity of attributes.

The majority of all attributes on native element JSX are set as DOM attributes. Static values are built right into the template that is cloned. There a number of exceptions like `class`, `style`, `value`, `innerHTML` which provide extra functionality.

However, custom elements (with exception of native built-ins) default to properties when dynamic. This is to handle more complex data types. It does this conversion by camel casing standard snake case attribute names `some-attr` to `someAttr`.

However, it is possible to control this behavior directly with namespace directives. You can force an attribute with `attr:` or force prop `prop:`

```jsx
<my-element prop:UniqACC={state.value} attr:title={state.title} />
```
> Support for namespace in JSX is coming in TS 4.2.
### Note on binding order

Static attributes are created as part of the html template together. Expressions fixed and dynamic are applied afterwards in JSX binding order. While this is fine for most DOM elements there are some like input elements with `type='range'` where order matters. Keep this in mind when binding elements.

Expand Down Expand Up @@ -257,6 +272,31 @@ function App() {

This just passes the function through as `props.ref` again and work similar to the example above except it would run synchronously during render. You can use this to chain as many `ref` up a Component chain as you wish.

## Custom Directives

> Support for Namespaced JSX Attributes is coming to TypeScript in version 4.2
Creating a Component is the cleanest way to package reusable functionality data and view behavior. Reactive primitive composition is often the best way to reuse data behavior. However sometimes there is a need for behavior that can be re-used cross DOM element.

Solid provides a custom directive syntax for adding additional behavior to native elements as a syntax sugar over `ref` making it easy to combine multiple on a single element.

```jsx
<div use:draggable use:pannable />

const [name, setName] = createSignal("");
<input type="text" use:model={[name, setName]} />
```

To create a directive simply expose a function with this signature `(el: HTMLElement, valueAccessor: () => /*binding value*/) => {}`. Value accessor lets you track it if you wish to. And you can register `onCleanup` methods to cleanup any side effects you create.

```jsx
function model(el, value) {
const [field, setField] = value();
createRenderEffect(() => el.value = field());
el.addEventListener(e => setField(e.target.value));
}
```

## Server Side Rendering (Experimental)

See [solid-ssr](https://github.com/ryansolid/solid/blob/master/packages/solid-ssr)
12 changes: 6 additions & 6 deletions lerna.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"packages": [
"packages/*"
],
"version": "0.20.3"
}
{
"packages": [
"packages/*"
],
"version": "0.21.0-beta.0"
}
Loading

0 comments on commit c3211d7

Please sign in to comment.