Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 3 additions & 2 deletions Contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
git clone https://github.com/EasyWebApp/WebCell.git ~/Desktop/WebCell
cd ~/Desktop/WebCell

npm install
npm i pnpm -g
pnpm i
npm test
npm run build
pnpm build
```
40 changes: 27 additions & 13 deletions ReadMe.md
Original file line number Diff line number Diff line change
Expand Up @@ -454,11 +454,28 @@ export default AsyncTag;
#### `index.tsx`

```tsx
import { DOMRenderer } from 'dom-renderer';
import { lazy } from 'web-cell';

const AsyncTag = lazy(() => import('./AsyncTag'));

new DOMRenderer().render(<AsyncTag />);
```

### Animate CSS component

```tsx
import { DOMRenderer } from 'dom-renderer';
import { AnimateCSS } from 'web-cell';

new DOMRenderer().render(
<AnimateCSS
type="fadeIn"
component={props => <h1 {...props}>Fade In</h1>}
/>
);
```

## Node.js usage

### Tool chain
Expand Down Expand Up @@ -505,7 +522,7 @@ import 'web-cell/polyfill';

We recommend these libraries to use with WebCell:

- **State management**: [MobX][42] (also powered by **TypeScript** & **Decorator**)
- **State management**: [MobX][3] (also powered by **TypeScript** & **Decorator**)
- **Router**: [Cell Router][43]
- **UI components**

Expand All @@ -520,14 +537,13 @@ We recommend these libraries to use with WebCell:

## Roadmap

- [x] [Extend **Build-in Elements** with Virtual DOM][51]
- [x] [Server-side Render][52]
- [x] [Async Component loading][53]
- [x] [Server-side Render][51]
- [x] [Async Component loading][52]

## More guides

1. [v2 to v3 migration][54]
2. [Development contribution][55]
1. [v2 to v3 migration][53]
2. [Development contribution][54]

[1]: https://www.webcomponents.org/
[2]: https://facebook.github.io/jsx/
Expand All @@ -539,7 +555,7 @@ We recommend these libraries to use with WebCell:
[8]: https://github.com/jaywcjlove/awesome-uikit
[9]: https://tech-query.me/programming/web-components-practise/slide.html
[10]: https://gitter.im/EasyWebApp/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge
[11]: https://codesandbox.io/s/webcell-demo-9gyll?autoresize=1&fontsize=14&hidenavigation=1&module=%2Fsrc%2FClock.tsx&theme=dark
[11]: https://codesandbox.io/p/devbox/9gyll?embed=1&file=%2Fsrc%2FClock.tsx
[12]: https://nodei.co/npm/web-cell/
[13]: https://www.typescriptlang.org/
[14]: https://github.com/tc39/proposal-decorators
Expand Down Expand Up @@ -570,7 +586,6 @@ We recommend these libraries to use with WebCell:
[39]: https://github.com/EasyWebApp/scaffold
[40]: https://github.com/EasyWebApp/DashBoard
[41]: https://github.com/EasyWebApp/mark-wiki
[42]: https://github.com/mobxjs/mobx/blob/mobx4and5/docs/
[43]: https://web-cell.dev/cell-router/
[44]: https://bootstrap.web-cell.dev/
[45]: https://material.web-cell.dev/
Expand All @@ -579,8 +594,7 @@ We recommend these libraries to use with WebCell:
[48]: https://web-cell.dev/web-utility/
[49]: https://web-cell.dev/iterable-observer/
[50]: https://github.com/EasyWebApp/MarkCell
[51]: https://github.com/snabbdom/snabbdom/pull/829
[52]: https://web.dev/declarative-shadow-dom/
[53]: https://reactjs.org/docs/react-api.html#reactlazy
[54]: https://github.com/EasyWebApp/WebCell/blob/main/Migrating.md
[55]: https://github.com/EasyWebApp/WebCell/blob/main/Contributing.md
[51]: https://web.dev/declarative-shadow-dom/
[52]: https://reactjs.org/docs/react-api.html#reactlazy
[53]: https://github.com/EasyWebApp/WebCell/blob/main/Migrating.md
[54]: https://github.com/EasyWebApp/WebCell/blob/main/Contributing.md
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "web-cell",
"version": "3.0.0-rc.5",
"version": "3.0.0-rc.7",
"description": "Web Components engine based on VDOM, JSX, MobX & TypeScript",
"keywords": [
"web",
Expand Down Expand Up @@ -58,7 +58,7 @@
"lint-staged": "^15.2.0",
"open-cli": "^8.0.0",
"parcel": "~2.11.0",
"prettier": "^3.1.1",
"prettier": "^3.2.0",
"rimraf": "^5.0.5",
"ts-jest": "^29.1.1",
"ts-node": "^10.9.2",
Expand Down
8 changes: 4 additions & 4 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 7 additions & 4 deletions preview/Home.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import { formToJSON } from 'web-utility';
import { FC, PropsWithChildren, lazy } from '../source';
import { AnimateCSS, FC, WebCellProps, lazy } from '../source';

import { ClassClock, FunctionClock } from './Clock';
import { TestField } from './Field';

const Async = lazy(() => import('./Async'));

const Hello: FC<PropsWithChildren> = ({ children }) => (
<h1>Hello {children}!</h1>
const Hello: FC<WebCellProps> = ({ className, children }) => (
<h1 className={className}>Hello {children}!</h1>
);

export const HomePage = () => (
<>
<Hello>WebCell</Hello>
<AnimateCSS
type="fadeIn"
component={props => <Hello {...props}>WebCell</Hello>}
/>
<div>
We use the same configuration as Parcel to bundle this sandbox, you
can find more info about Parcel
Expand Down
60 changes: 60 additions & 0 deletions source/Animation/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { observable } from 'mobx';
import { importCSS } from 'web-utility';

import { WebCellProps } from '../Async';
import { animated } from '../MobX';
import { WebCell, component } from '../WebCell';
import { FC, attribute, observer, reaction } from '../decorator';
import { AnimationType } from './type';

export * from './type';

export interface AnimateCSS extends WebCell {}

export interface AnimateCSSProps {
type: AnimationType;
component: FC<WebCellProps>;
}

@component({ tagName: 'animation-css' })
@observer
export class AnimateCSS extends HTMLElement implements WebCell {
declare props: AnimateCSSProps;

@attribute
@observable
accessor type: AnimationType;

@attribute
@observable
accessor playing = false;

component: FC<WebCellProps>;

async connectedCallback() {
await importCSS('https://unpkg.com/animate.css@4/animate.min.css');

this.typeChanged();
}

@reaction(({ type }) => type)
async typeChanged() {
this.playing = true;

await animated(this, '.animate__animated');

this.playing = false;
}

render() {
const { type, playing, component: Tag } = this;

return playing ? (
<Tag className={`animate__animated animate__${type}`} />
) : type.includes('Out') ? (
<></>
) : (
<Tag />
);
}
}
56 changes: 56 additions & 0 deletions source/Animation/type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
export type PositionY = 'Top' | 'Bottom';
export type DirectionX = 'Left' | 'Right';
export type DirectionY = 'Up' | 'Down';
export type Direction = DirectionX | DirectionY;
export type AnimationMode = 'In' | 'Out';

export type AttentionSeekers =
| 'bounce'
| 'flash'
| 'pulse'
| 'rubberBand'
| `shake${'X' | 'Y'}`
| 'headShake'
| 'swing'
| 'tada'
| 'wobble'
| 'jello'
| 'heartBeat';
export type BackEntrances = `backIn${Direction}`;
export type BackExits = `backOut${Direction}`;
export type BouncingEntrances = `bounceIn${'' | Direction}`;
export type BouncingExits = `bounceOut${'' | Direction}`;
export type FadingEntrances =
| `fadeIn${'' | `${Direction}${'' | 'Big'}`}`
| `fadeIn${PositionY}${DirectionX}`;
export type FadingExits = `fadeOut${
| ''
| `${Direction}${'' | 'Big'}`
| `${PositionY}${DirectionX}`}`;
export type Flippers = `flip${'' | `${AnimationMode}${'X' | 'Y'}`}`;
export type Lightspeed = `lightSpeed${AnimationMode}${DirectionX}`;
export type RotatingEntrances = `rotateIn${'' | `${DirectionY}${DirectionX}`}`;
export type RotatingExits = `rotateOut${'' | `${DirectionY}${DirectionX}`}`;
export type Specials = 'hinge' | 'jackInTheBox' | `roll${'In' | 'Out'}`;
export type ZoomingEntrances = `zoomIn${'' | Direction}`;
export type ZoomingExits = `zoomOut${'' | Direction}`;
export type SlidingEntrances = `slideIn${Direction}`;
export type SlidingExits = `slideOut${Direction}`;

export type AnimationType =
| AttentionSeekers
| BackEntrances
| BackExits
| BouncingEntrances
| BouncingExits
| FadingEntrances
| FadingExits
| Flippers
| Lightspeed
| RotatingEntrances
| RotatingExits
| Specials
| ZoomingEntrances
| ZoomingExits
| SlidingEntrances
| SlidingExits;
23 changes: 10 additions & 13 deletions source/Async.tsx
Original file line number Diff line number Diff line change
@@ -1,48 +1,45 @@
import { observable } from 'mobx';
import { JsxProps } from 'dom-renderer';
import { observable } from 'mobx';

import { ClassComponent, WebCell, component } from './WebCell';
import {
FC,
FunctionComponent,
PropsWithChildren,
WebCellComponent,
observer,
reaction
observer
} from './decorator';

export type ComponentTag = string | WebCellComponent;

export type WebCellProps<T extends HTMLElement = HTMLElement> = JsxProps<T>;

export interface AsyncBoxProps extends WebCellProps {
export interface AsyncCellProps extends WebCellProps {
loader: () => Promise<ComponentTag>;
delegatedProps?: WebCellProps;
}

export interface AsyncBox extends WebCell {}
export interface AsyncCell extends WebCell {}

@component({
tagName: 'async-box'
tagName: 'async-cell'
})
@observer
export class AsyncBox extends HTMLElement {
declare props: AsyncBoxProps;
export class AsyncCell extends HTMLElement {
declare props: AsyncCellProps;

@observable
accessor loader: AsyncBoxProps['loader'];
loader: AsyncCellProps['loader'];

@observable
accessor component: FC<PropsWithChildren>;

@observable
accessor delegatedProps: AsyncBoxProps['delegatedProps'];
accessor delegatedProps: AsyncCellProps['delegatedProps'];

connectedCallback() {
this.load();
}

@reaction((element: AsyncBox) => element.loader)
protected async load() {
this.component = undefined;

Expand Down Expand Up @@ -72,7 +69,7 @@ export function lazy<
T extends () => Promise<{ default: FunctionComponent | ClassComponent }>
>(loader: T) {
return (props: GetAsyncProps<T>) => (
<AsyncBox
<AsyncCell
delegatedProps={props}
loader={async () => (await loader()).default}
/>
Expand Down
16 changes: 16 additions & 0 deletions source/MobX.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { DataObject } from 'dom-renderer';
import { ObservableValue } from 'mobx/dist/internal';
import { delegate } from 'web-utility';

export function getMobxData<T extends DataObject>(observable: T) {
for (const key of Object.getOwnPropertySymbols(observable)) {
Expand All @@ -13,3 +14,18 @@ export function getMobxData<T extends DataObject>(observable: T) {
) as T;
}
}

export const animated = <T extends HTMLElement | SVGElement>(
root: T,
targetSelector: string
) =>
new Promise<AnimationEvent>(resolve => {
const ended = delegate(targetSelector, (event: AnimationEvent) => {
root.removeEventListener('animationend', ended);
root.removeEventListener('animationcancel', ended);
resolve(event);
});

root.addEventListener('animationend', ended);
root.addEventListener('animationcancel', ended);
});
Loading