Skip to content

Commit

Permalink
[add] Animate.css wrap component
Browse files Browse the repository at this point in the history
[fix] bugs of Observed Attribute , Async Cell & Read Me
  • Loading branch information
TechQuery committed Jan 12, 2024
1 parent 01be249 commit 8ccec10
Show file tree
Hide file tree
Showing 11 changed files with 201 additions and 49 deletions.
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

0 comments on commit 8ccec10

Please sign in to comment.