diff --git a/CHANGELOG.md b/CHANGELOG.md index db2ddee..56ef6e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 0.3.1 + +**New** + +- Spread attributes in markup, ` +} + +export default component App() { + source extra: { count: number; tone?: string; title: string } := { count: 1, tone: "warn", title: "a" } + + + +} +``` + +The first badge's `title` comes after the spread, so it is `fixed` whatever +`extra` holds; its `tone` comes from `extra`. In the second, `tone="calm"` +comes before the spread, so `extra.tone` wins while it has one. + +## Frames + +| instant | action | frame | +| ------- | ---------------------------------------------- | -------------------------------------- | +| 0 | mount | `x:warn:1:fixedopeny:warn:1:aopen` | +| 1 | handler `extra := { count: 2, title: "b" }` | `x:info:2:fixedopeny:calm:2:bopen` | + +Instant 1: `extra` no longer has `tone`, so the first badge falls back to +its default and the second to the attribute before the spread. + +## Rejected variants + +```rx +-- reject: PARSE +export default component App() { + source extra := { title: "a" } +

hi

+} +``` + +An attribute in braces is a spread: `{...extra}`. + +```rx +-- reject: UNHANDLED_FAILURE +component Card(props: { title: string }) { +

{props.title}

+} + +export default component App() { + info = await fetch("info") + loading fallback {

…

} { + + } +} +``` + +A spread passes `info`'s failure on with its fields: `Card` reads `title`, +so the read can fail with `Error`, and nothing above it catches. diff --git a/site/index.html b/site/index.html index 73dea7a..e372f05 100644 --- a/site/index.html +++ b/site/index.html @@ -103,15 +103,15 @@

Mistakes of shape become errors

counter.rx:5:3 - error WRITE_TO_NON_SOURCE: double is an equation: only sources are written (W-1)

Destructure props, keep them live

-

In Solid, destructuring props reads them once and the component stops updating. In .rx, destructure them right in the parameter list: every name follows its prop, defaults and rest included.

-
inbox.rxcomponent Badge({ label, tone = "info", ...rest }: { label: string; tone?: string; count: number }) {
-  <span class={tone}>{label}: {rest.count}</span>
+  

In Solid, destructuring props reads them once and the component stops updating. In .rx, destructure them right in the parameter list: every name follows its prop, defaults and rest included, and the rest spreads onto an element as in JSX.

+
inbox.rxcomponent Badge({ label, tone = "info", ...rest }: { label: string; tone?: string; title?: string }) {
+  <span class={tone} {...rest}>{label}</span>
 }
 
 export default component Inbox() {
   source user := { name: "Ada", unread: 3 }
 
-  <Badge label={user.name} count={user.unread} />   // Badge updates when user changes
+  <Badge label={`${user.unread} unread`} title={user.name} />   // Badge updates when user changes
   <button onClick={() => { user := { ...user, unread: 0 } }}>Mark read</button>
 }
diff --git a/spec/07-surface.md b/spec/07-surface.md index 4f13591..06027bc 100644 --- a/spec/07-surface.md +++ b/spec/07-surface.md @@ -169,6 +169,14 @@ attributes are equations, children are readers, components are applied as element and bare at block level. `portal to(e) { … }` renders into `e` (RG-8). Each block is a region: declarations, then markup (RG-1, RG-2, RG-5). `if x { … }` narrows `x` inside (RG-1c). +- `{...e}` among the attributes is a spread, as JSX's: every field of `e`. + Parts merge in order and the last one that has a field wins (Solid's + `merge`), so an attribute after the spread overrides it and one before + it is a default. A spread is an equation like any attribute: its fields + keep updating. On a component it is passed, not read: its fields are + read where the component reads its props, and its failures and holds go + where any of those reads go (R-2, R-f-5). On an HTML element it is read + where the element is (S-surface-5). - `for x in e` keys rows by identity, or by the collection's `key` (ST-4b). - Text follows JSX: whitespace that contains a line break is not text, a line's leading and trailing whitespace is not text, and text that runs diff --git a/tooling/rx-language-server/package-lock.json b/tooling/rx-language-server/package-lock.json index 2abe140..2c38883 100644 --- a/tooling/rx-language-server/package-lock.json +++ b/tooling/rx-language-server/package-lock.json @@ -1,12 +1,12 @@ { "name": "@reactivescript/language-server", - "version": "0.3.0", + "version": "0.3.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@reactivescript/language-server", - "version": "0.3.0", + "version": "0.3.1", "license": "MIT", "dependencies": { "@volar/language-core": "2.4.30", diff --git a/tooling/rx-language-server/package.json b/tooling/rx-language-server/package.json index 2b35163..7059607 100644 --- a/tooling/rx-language-server/package.json +++ b/tooling/rx-language-server/package.json @@ -1,6 +1,6 @@ { "name": "@reactivescript/language-server", - "version": "0.3.0", + "version": "0.3.1", "description": "The .rx language server (spec/11 CP-8): Volar over the crate's TSX projection, TypeScript's answers mapped back onto .rx, the crate's own diagnostics; rx-tsc type-checks .rx from the command line.", "license": "MIT", "repository": { diff --git a/tooling/vscode-rx/README.md b/tooling/vscode-rx/README.md index 9446f3a..7f5990c 100644 --- a/tooling/vscode-rx/README.md +++ b/tooling/vscode-rx/README.md @@ -27,7 +27,7 @@ artifact of a run of the repository's `editor` workflow, or build one (below), then run **Extensions: Install from VSIX…** in the command palette, or ```sh -code --install-extension reactivescript-0.3.0.vsix +code --install-extension reactivescript-0.3.1.vsix ``` The project needs a `tsconfig.json` with Solid's JSX (`"jsx": "preserve"`, diff --git a/tooling/vscode-rx/package-lock.json b/tooling/vscode-rx/package-lock.json index 08c5218..9eae14a 100644 --- a/tooling/vscode-rx/package-lock.json +++ b/tooling/vscode-rx/package-lock.json @@ -1,12 +1,12 @@ { "name": "reactivescript", - "version": "0.3.0", + "version": "0.3.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "reactivescript", - "version": "0.3.0", + "version": "0.3.1", "license": "MIT", "dependencies": { "highlight.js": "^11.11.1", diff --git a/tooling/vscode-rx/package.json b/tooling/vscode-rx/package.json index 2d11377..9566816 100644 --- a/tooling/vscode-rx/package.json +++ b/tooling/vscode-rx/package.json @@ -2,7 +2,7 @@ "name": "reactivescript", "displayName": "ReactiveScript", "description": "ReactiveScript (.rx, .d.rx): highlighting, and TypeScript's types, hover, go to definition, completion and errors through the .rx language server, with the compiler's own diagnostics; ```rx blocks highlighted in Markdown.", - "version": "0.3.0", + "version": "0.3.1", "publisher": "solidjs", "license": "MIT", "icon": "icon.png",