Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

0.6 #274

Merged
merged 28 commits into from
Apr 26, 2024
Merged

0.6 #274

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
33d60b9
tweak comments
Jan 9, 2024
a5ad8fd
deprecate prefixed spcial props in favor unprefixed special props
Jan 10, 2024
357a564
change ref behavior to only work for host elements and only fire once
Jan 10, 2024
0d82326
do not rerender reused elements in the same position or key
Jan 13, 2024
7cd4e26
pass context as the second argument to component
Jan 13, 2024
c23be88
warn when components yield multiple times in for...of loop
Jan 13, 2024
f7b16b8
skip stale renders in async generator for await of components
Jan 16, 2024
e217dfc
deprecate the props and value computed properties
Jan 22, 2024
4e99f63
update devDependencies
Feb 3, 2024
6ca26cf
website lint tweaks
Feb 3, 2024
e5a481b
linting tweaks
Feb 3, 2024
43d6284
avoid for...of in createElement
Feb 3, 2024
b1244a5
add an html test
Feb 4, 2024
5df100a
add support for React-style camelCased event props
Feb 4, 2024
b5e1947
use unprefixed props in website
Feb 4, 2024
89238ac
make sure refs work with hydration
Feb 4, 2024
b3da1ef
Update documentation
brainkim Mar 22, 2023
e57a452
rename static prop to copy prop
Feb 14, 2024
ad2f083
tweak website
Feb 14, 2024
cbec13b
fix code preview height change not working
Feb 29, 2024
19a6539
update docs
Feb 29, 2024
04525a5
undeprecate the props computed property
Mar 4, 2024
33ff270
Make dispatchEvent fire for camelCased event props
Mar 4, 2024
5468831
update CHANGELOG.md
Mar 4, 2024
b76512f
add jsxDEV to jsx-runtime shim
Mar 18, 2024
5b8a028
update astro plugin
Apr 17, 2024
faea477
tweak docs
Apr 17, 2024
5a05310
update README.md
Apr 17, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 5 additions & 15 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,18 @@
},
"plugins": [
"@typescript-eslint",
"prettier",
"react"
"prettier"
],
"extends": [
"eslint:recommended",
"plugin:prettier/recommended"
"plugin:prettier/recommended",
"plugin:crank/recommended"
],

"settings": {
"react": {
"pragma": "createElement",
"fragment": "Fragment"
}
},
"rules": {
"no-console": [
"error",
{
"allow": ["info", "error"]
"allow": ["info", "warn", "error"]
}
],
"no-unused-vars": 0,
Expand All @@ -41,7 +34,6 @@
"argsIgnorePattern": "^_"
}
],
"no-empty-pattern": 0,
"no-dupe-class-members": 0,
"@typescript-eslint/no-dupe-class-members": 1,
"no-undef": 0,
Expand All @@ -55,8 +47,6 @@
"bracketSpacing": false
}
],
"linebreak-style": ["error", "unix"],
"react/jsx-uses-vars": 1,
"react/jsx-uses-react": 1
"linebreak-style": ["error", "unix"]
}
}
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
# Changelog
## [0.6.0] - 2024-03-04
### Breaking Changes
- Special props are now unprefixed. All special prefixed props are deprecated.
- Special props are now passed into components via props.
- The `ref` prop behavior has been changed. For host elements, the callback is fired once when the element is created. For component elements, the callback must be manually passed to one of the component’s children to fire. The `ref` callback will have no effect for other elements like `<Fragment>`.
- The special `static` prop has been renamed to `copy` to avoid collisions with the `static` keyword.
- The `context.value` property, which allows you to access the current rendered value of a component from the context, has been deprecated.
- Elements which are reused between renders will skip rendering. This means you have to clone elements between renders if you want them to rerender.
### Features
- Component contexts are now passed to components as the second parameter.
- React style camelCased event names (`onChange`, `onInput`) are now supported.
- Stale renders are skipped with using `for await...of` in async generator components.
- Components will now warn when yielding multiple times per props iteration.
## [0.5.7] - 2023-12-05
- Fix keyed elements disappearing incorrectly, a bug introduced in 0.5.5
## [0.5.6] - 2023-11-07
Expand Down
247 changes: 225 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,216 @@
# Crank.js
### The Just JavaScript web framework.
## Try Crank

Crank is a web framework where components can be defined with sync functions, async functions and generator functions. The documentation for Crank.js is available at [crank.js.org](https://crank.js.org).
The fastest way to try Crank is via the [online playground](https://crank.js.org/playground). In addition, many of the code examples in these guides feature live previews.

## Get Started
## Installation

Crank.js is published on NPM under the `@b9g` organization (short for “b*ikeshavin*g”).
The Crank package is available on [NPM](https://npmjs.org/@b9g/crank) through
the [@b9g organization](https://www.npmjs.com/org/b9g) (short for
b*ikeshavin*g).

```shell
$ npm i @b9g/crank
npm i @b9g/crank
```

### Key Examples
### Importing Crank with the **classic** JSX transform.

#### A Simple Component
```jsx live
/** @jsx createElement */
/** @jsxFrag Fragment */
import {createElement, Fragment} from "@b9g/crank";
import {renderer} from "@b9g/crank/dom";

renderer.render(
<p>This paragraph element is transpiled with the classic transform.</p>,
document.body,
);
```

### Importing Crank with the **automatic** JSX transform.

```jsx live
/** @jsxImportSource @b9g/crank */
import {renderer} from "@b9g/crank/dom";

renderer.render(
<p>This paragraph element is transpiled with the automatic transform.</p>,
document.body,
);
```

You will likely have to configure your tools to support JSX, especially if you do not want to use `@jsx` comment pragmas. See below for common tools and configurations.

### Importing the JSX template tag.

Starting in version `0.5`, the Crank package ships a [tagged template function](/guides/jsx-template-tag) which provides similar syntax and semantics as the JSX transform. This allows you to write Crank components in vanilla JavaScript.

```js live
import {jsx} from "@b9g/crank/standalone";
import {renderer} from "@b9g/crank/dom";

renderer.render(jsx`
<p>No transpilation is necessary with the JSX template tag.</p>
`, document.body);
```

### ECMAScript Module CDNs
Crank is also available on CDNs like [unpkg](https://unpkg.com)
(https://unpkg.com/@b9g/crank?module) and [esm.sh](https://esm.sh)
(https://esm.sh/@b9g/crank) for usage in ESM-ready environments.

```jsx live
/** @jsx createElement */

// This is an ESM-ready environment!
// If code previews work, your browser is an ESM-ready environment!

import {createElement} from "https://unpkg.com/@b9g/crank/crank?module";
import {renderer} from "https://unpkg.com/@b9g/crank/dom?module";

renderer.render(
<div id="hello">
Running on <a href="https://unpkg.com">unpkg.com</a>
</div>,
document.body,
);
```

## Common tool configurations
The following is an incomplete list of configurations to get started with Crank.

### [TypeScript](https://www.typescriptlang.org)

TypeScript is a typed superset of JavaScript.

Here’s the configuration you will need to set up automatic JSX transpilation.

```tsconfig.json
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "@b9g/crank"
}
}
```

The classic transform is supported as well.

```tsconfig.json
{
"compilerOptions": {
"jsx": "react",
"jsxFactory": "createElement",
"jsxFragmentFactory": "Fragment"
}
}
```

Crank is written in TypeScript. Refer to [the guide on TypeScript](/guides/working-with-typescript) for more information about Crank types.

```tsx
import type {Context} from "@b9g/crank";
function *Timer(this: Context) {
let seconds = 0;
const interval = setInterval(() => {
seconds++;
this.refresh();
}, 1000);
for ({} of this) {
yield <div>Seconds: {seconds}</div>;
}

clearInterval(interval);
}
```

### [Babel](https://babeljs.io)

Babel is a popular open-source JavaScript compiler which allows you to write code with modern syntax (including JSX) and run it in environments which do not support the syntax.

Here is how to get Babel to transpile JSX for Crank.

Automatic transform:
```.babelrc.json
{
"plugins": [
"@babel/plugin-syntax-jsx",
[
"@babel/plugin-transform-react-jsx",
{
"runtime": "automatic",
"importSource": "@b9g/crank",

"throwIfNamespace": false,
"useSpread": true
}
]
]
}
```

Classic transform:
```.babelrc.json
{
"plugins": [
"@babel/plugin-syntax-jsx",
[
"@babel/plugin-transform-react-jsx",
{
"runtime": "class",
"pragma": "createElement",
"pragmaFrag": "''",

"throwIfNamespace": false,
"useSpread": true
}
]
]
}
```

### [ESLint](https://eslint.org)

ESLint is a popular open-source tool for analyzing and detecting problems in JavaScript code.

Crank provides a configuration preset for working with ESLint under the package name `eslint-plugin-crank`.

```bash
npm i eslint eslint-plugin-crank
```

In your eslint configuration:

```.eslintrc.json
{
"extends": ["plugin:crank/recommended"]
}
```

### [Astro](https://astro.build)

Astro.js is a modern static site builder and framework.

Crank provides an [Astro integration](https://docs.astro.build/en/guides/integrations-guide/) to enable server-side rendering and client-side hydration with Astro.

```bash
npm i astro-crank
```

In your `astro.config.mjs`.

```astro.config.mjs
import {defineConfig} from "astro/config";
import crank from "astro-crank";

// https://astro.build/config
export default defineConfig({
integrations: [crank()],
});
```

## Key Examples

### A Simple Component

```jsx live
import {renderer} from "@b9g/crank/dom";
Expand All @@ -27,7 +224,7 @@ function Greeting({name = "World"}) {
renderer.render(<Greeting />, document.body);
```

#### A Stateful Component
### A Stateful Component

```jsx live
import {renderer} from "@b9g/crank/dom";
Expand All @@ -50,22 +247,28 @@ function *Timer() {
renderer.render(<Timer />, document.body);
```

#### An Async Component
### An Async Component

```jsx live
import {renderer} from "@b9g/crank/dom";
async function Definition({word}) {
// API courtesy https://dictionaryapi.dev
const res = await fetch(`https://api.dictionaryapi.dev/api/v2/entries/en/${word}`);
const data = await res.json();
if (!Array.isArray(data)) {
return <p>No definition found for {word}</p>;
}

async function QuoteOfTheDay() {
const res = await fetch("https://favqs.com/api/qotd");
const {quote} = await res.json();
return (
<p>
“{quote.body}” – <a href={quote.url}>{quote.author}</a>
</p>
);
const {phonetic, meanings} = data[0];
const {partOfSpeech, definitions} = meanings[0];
const {definition} = definitions[0];
return <>
<p>{word} <code>{phonetic}</code></p>
<p><b>{partOfSpeech}.</b> {definition}</p>
</>;
}

renderer.render(<QuoteOfTheDay />, document.body);
await renderer.render(<Definition word="framework" />, document.body);
```

### A Loading Component
Expand Down Expand Up @@ -112,10 +315,10 @@ function *RandomDogApp() {
for ({} of this) {
yield (
<Fragment>
<div>
<button>Show me another dog.</button>
</div>
<RandomDogLoader throttle={throttle} />
<p>
<button>Show me another dog.</button>
</p>
</Fragment>
);
}
Expand Down
Loading
Loading