-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit a88bbe6
Showing
109 changed files
with
14,701 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
importmap | ||
jsxdev | ||
jsxs | ||
kayahr | ||
lifecycles | ||
multilines | ||
Reimer |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# http://editorconfig.org | ||
|
||
root = true | ||
|
||
[*] | ||
charset = utf-8 | ||
end_of_line = lf | ||
indent_size = 4 | ||
indent_style = space | ||
insert_final_newline = true | ||
trim_trailing_whitespace = true | ||
|
||
[*.{html,xml}] | ||
indent_size = 2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
github: kayahr | ||
custom: https://paypal.me/kayaahr/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
name: ci | ||
on: [push] | ||
jobs: | ||
build: | ||
runs-on: ubuntu-latest | ||
strategy: | ||
matrix: | ||
node-version: [ 22.x ] | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- name: Use Node.js ${{ matrix.node-version }} | ||
uses: actions/setup-node@v4 | ||
with: | ||
node-version: ${{ matrix.node-version }} | ||
- name: Build | ||
run: npm ci | ||
- name: Test | ||
run: npm test | ||
- name: Build API Doc | ||
run: npm run apidoc | ||
- name: Deploy API Doc | ||
if: ${{ github.ref == 'refs/heads/main' && matrix.node-version == '22.x' }} | ||
uses: JamesIves/github-pages-deploy-action@v4 | ||
with: | ||
folder: lib/apidoc |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
/lib | ||
/node_modules | ||
/*.tgz | ||
sandbox | ||
/dist |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
{ | ||
"typescript.tsdk": "node_modules/typescript/lib", | ||
"files.exclude": { | ||
"lib": true, | ||
"node_modules": true | ||
}, | ||
"task.allowAutomaticTasks": "on", | ||
"javascript.preferences.importModuleSpecifierEnding": "js", | ||
"typescript.preferences.importModuleSpecifierEnding": "js", | ||
"typescript.preferences.autoImportFileExcludePatterns": [ | ||
"@kayahr/harmless", | ||
"@kayahr/harmless/jsx-runtime", | ||
"./src/main/index.ts", | ||
"./src/main/jsx-runtime.ts" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
{ | ||
"version": "2.0.0", | ||
"tasks": [ | ||
{ | ||
"label": "Compile and watch project", | ||
"type": "typescript", | ||
"tsconfig": "tsconfig.json", | ||
"option": "watch", | ||
"problemMatcher": [ | ||
"$tsc-watch" | ||
], | ||
"group": { | ||
"kind": "build", | ||
"isDefault": true | ||
}, | ||
"runOptions": { | ||
"runOn": "folderOpen" | ||
} | ||
}, | ||
{ | ||
"label": "Run unit tests", | ||
"command": "${command:testing.coverageAll}", | ||
"group": { | ||
"kind": "test", | ||
"isDefault": true | ||
} | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
MIT LICENSE | ||
=========== | ||
|
||
Copyright (C) 2024 Klaus Reimer, k@ailis.de | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to | ||
deal in the Software without restriction, including without limitation the | ||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||
sell copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in | ||
all copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||
IN THE SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
[GitHub] | [NPM] | [API Doc] | ||
|
||
| :warning: This project is currently under construction and missing crucial functionality | | ||
| - | | ||
|
||
A minimalistic reactive web frontend framework written in TypeScript. | ||
|
||
## Features | ||
|
||
* Fine-grained reactive DOM updates via [promises], [observables] and signals using a framework-independent [signal] implementation. | ||
* Based on standard [JSX] using the automatic runtime (aka `react-jsx` mode), so no special transpiler plugin needed. | ||
* Supports dependency injection via a framework-independent [cdi] implementation. | ||
* Provides built-in components for flow control, like [If], [Choose] and [Route]. | ||
* It's just a library without any build system requirements. Use whatever you like. | ||
* Easily testable with any JSX-capable testing framework (like [Vitest]). | ||
|
||
Some features are intentionally missing to keep Harmless small and focused: | ||
|
||
* No server rendering. Harmless is a client-only library. | ||
* No web component support. Should be easy enough to use Harmless inside a web component, though. | ||
* No CLI tools. Harmless is just a library and doesn't dictate how to structure your project or how to work with it. | ||
* No CommonJS support. It's time to leave the stone age behind and use [ESM] everywhere. | ||
|
||
## TODO | ||
|
||
* Write built-in components like `For` to iterate over collections of data. | ||
* Write documentation | ||
|
||
## More | ||
|
||
Check out the [documentation]. | ||
|
||
|
||
[API Doc]: https://kayahr.github.io/harmless/modules/_kayahr_harmless.html | ||
[Documentation]: https://kayahr.github.io/harmless/documents/Getting_started.html | ||
[GitHub]: https://github.com/kayahr/harmless | ||
[NPM]: https://www.npmjs.com/package/@kayahr/harmless | ||
[Vitest]: https://vitest.dev/ | ||
[signal]: https://www.npmjs.com/package/@kayahr/signal | ||
[cdi]: https://www.npmjs.com/package/@kayahr/cdi | ||
[promises]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise | ||
[observables]: https://github.com/tc39/proposal-observable | ||
[JSX]: https://www.typescriptlang.org/docs/handbook/jsx.html | ||
[ESM]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules | ||
[If]: https://kayahr.github.io/harmless/documents/Control_Flow.If.html | ||
[Choose]: https://kayahr.github.io/harmless/documents/Control_Flow.Choose.html | ||
[Route]: https://kayahr.github.io/harmless/documents/Control_Flow.Routes.html |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
TODO | ||
==== | ||
|
||
* There is a bug somewhere with fragments. Most likely reproducible with nested Show components which all use fragments. Noticed this with the Route | ||
component when switched child component is a fragment. | ||
* | ||
* Implement Route | ||
* Implement For |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
{ | ||
"$schema": "https://raw.githubusercontent.com/streetsidesoftware/cspell/master/cspell.schema.json", | ||
"version": "0.2", | ||
"language": "en", | ||
"files": [ "**/*" ], | ||
"dictionaryDefinitions": [ | ||
{ | ||
"name": "project-words", | ||
"path": "./.cspell/project-words.txt", | ||
"addWords": true | ||
} | ||
], | ||
"dictionaries": [ "project-words" ], | ||
"ignorePaths": [ | ||
"./.cspell", | ||
"./.git", | ||
"./lib", | ||
"./node_modules", | ||
"./package-lock.json", | ||
"sandbox" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
--- | ||
title: Components | ||
children: | ||
- ./components/function-components.md | ||
- ./components/class-components.md | ||
- ./components/rendering.md | ||
- ./components/reactive-content.md | ||
- ./components/component-lifecycles.md | ||
- ./components/event-handlers.md | ||
- ./components/dependency-injection.md | ||
--- | ||
|
||
# Components | ||
|
||
Components are written in form of simple functions or in form of [class components]. Both are equal in functionality so use whatever coding style you prefer. The examples in this documentation concentrates on functions but the shown concepts always also work with classes. | ||
|
||
Component names should always be upper-camelcase like `Contact` and `ToggleButton` because lower-case element names are reserved for normal HTML elements like `div`, `span` and all the others (also called intrinsic elements in the JSX world). | ||
|
||
## Basics | ||
|
||
The most basic form of a component is a function without parameters which just returns | ||
static HTML: | ||
|
||
```typescript | ||
export function HelloWorld() { | ||
return <h1>Hello World<h1>; | ||
} | ||
``` | ||
|
||
Other components can now import this component and use it in their own template: | ||
|
||
```typescript | ||
import { HelloWorld } from "./HelloWorld.js"; | ||
|
||
export function App() { | ||
return <div><HelloWorld /></div>; | ||
} | ||
``` | ||
|
||
## Properties | ||
|
||
Properties are passed in as the first function argument (or first constructor argument when using classes) in form of a plain key/value object. When the component doesn't expect such an argument then the component does not allow any properties. | ||
|
||
The following example shows the component `Contact.tsx`. It has two properties: `firstName` and `lastName`. | ||
|
||
```typescript | ||
export function Contact(props: { firstName: string, lastName: string }) { | ||
return <div class="contact"> | ||
<div>First name: {props.firstName}</span> | ||
<div>last name: {props.lastName}</span> | ||
</div>; | ||
} | ||
``` | ||
|
||
It can be used in other components like this: | ||
|
||
```typescript | ||
import { Contact } from "./Contact.js"; | ||
|
||
export function Contacts() { | ||
return <div class="contacts"> | ||
<Contact firstName="Tricia" lastName="McMillan" /> | ||
<Contact firstName="Arthur" lastName="Dent" /> | ||
</div>; | ||
} | ||
``` | ||
There are no limitations on component properties. Just treat them as you would treat a standard `object` type in TypeScript. Properties can be of any type and may also be optional. You can also use destructuring with default values and provide a properties interface to make the usage more pleasant: | ||
```typescript | ||
interface UserProperties { | ||
name: string; | ||
id: number; | ||
admin?: boolean; | ||
} | ||
|
||
function User({ name, id, admin = false }: UserProperties) { | ||
return <li class="user">{name}#{id}{admin ? " (Admin)" : ""}</li>; | ||
} | ||
|
||
function Users() { | ||
return <ul> | ||
<User name="root" id={0} admin={true} /> | ||
<User name="arthur" id={1000} /> | ||
</ul> | ||
} | ||
``` | ||
|
||
## Children | ||
|
||
Component children are passed as `children` property to a component. If the component does not specify such a property then children are not allowed. So to use children you have to explicitly specify them like this: | ||
|
||
```typescript | ||
function Bold(props: { children: JSX.Element }) { | ||
return <b>{props.children}</b>; | ||
} | ||
``` | ||
In most cases you want to use `JSX.Element` as children type to pass through any supported type and any number of children. | ||
For special use-cases the type can be narrowed down. Let's say you write a component which expects a list of numbers as children: | ||
```html | ||
<Numbers> | ||
{1} | ||
{2} | ||
{3} | ||
</Numbers> | ||
``` | ||
Note that JSX treats multiple children differently than a single child or no child at all. So you won't get an empty array, an array with one number or an array with multiple numbers. Instead you will get `undefined` when no child is specified, `number` when a single number is specified, and `number[]` when multiple numbers are given. Therefor an implementation accepting any number of values (even none) must be written like this: | ||
```typescript | ||
function Numbers({ children }: { children?: number | number[] }) { | ||
... | ||
} | ||
``` | ||
## More | ||
* [Function Components] | ||
* [Class Components] | ||
* [Rendering] | ||
* [Reactive Content] | ||
* [Component Lifecycles] | ||
* [Event Handlers] | ||
* [Dependency Injection] | ||
## Seel also | ||
* [TypeScript's JSX documentation](https://www.typescriptlang.org/docs/handbook/jsx.html) | ||
[signals]: https://www.npmjs.com/package/@kayahr/signal | ||
[promises]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise | ||
[observables]: https://github.com/tc39/proposal-observable | ||
[Class Components]: ./components/class-components.md | ||
[Function Components]: ./components/function-components.md | ||
[Rendering]: ./components/rendering.md | ||
[Reactive Content]: ./components/reactive-content.md | ||
[Component Lifecycles]: ./components/component-lifecycles.md | ||
[Event Handlers]: ./components/event-handlers.md | ||
[Dependency Injection]: ./components/dependency-injection.md |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
--- | ||
title: Class Components | ||
--- | ||
|
||
# Writing a class component | ||
|
||
And here is the same component written as a class: | ||
|
||
```typescript | ||
export interface ContactProperties { | ||
firstName: string; | ||
lastName: string; | ||
} | ||
|
||
export class Contact { | ||
public constructor(private readonly props: ContactProperties) {} | ||
|
||
public render() { | ||
return <div class="contact"> | ||
<div>First name: {this.props.firstName}</span> | ||
<div>Last name: {this.props.lastName}</span> | ||
</div>; | ||
} | ||
} | ||
``` | ||
|
||
If you prefer explicit return types and prefer specifying the implemented interface you can use the `JSX.Element` and `JSX.ElementClass` types: | ||
|
||
```typescript | ||
import { JSX } from "@kayahr/harmless"; | ||
|
||
export class Contact implements JSX.ElementClass { | ||
... | ||
public render(...): JSX.Element { | ||
... | ||
} | ||
... | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
--- | ||
title: Component Lifecycles | ||
--- | ||
|
||
# Component Lifecycles | ||
|
||
TODO |
Oops, something went wrong.