https://github.com/qrailibs/bubblejs
✨ Frontend framework that embeds everywhere & fully type-safe.
https://github.com/qrailibs/bubblejs
framework mvc mvvm typescript webcomponent
Last synced: 9 months ago
JSON representation
✨ Frontend framework that embeds everywhere & fully type-safe.
- Host: GitHub
- URL: https://github.com/qrailibs/bubblejs
- Owner: qrailibs
- Created: 2022-10-22T09:19:35.000Z (over 3 years ago)
- Default Branch: main
- Last Pushed: 2023-07-02T13:41:36.000Z (almost 3 years ago)
- Last Synced: 2025-02-27T19:04:53.237Z (about 1 year ago)
- Topics: framework, mvc, mvvm, typescript, webcomponent
- Language: TypeScript
- Homepage:
- Size: 8.7 MB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# BubbleJS
Frontend framework based on WebComponents with full support of TypeScript.
# Features
- [Components](#components)
- [`Refs`](#refs)
- [`WatchRefs`](#watchrefs)
- [`MapRefs`](#maprefs)
- [`CachedRefs`](#cachedrefs)
- [`Props`](#props)
- [`Elements`](#elements)
- [`Events`](#events)
- [`Slots`](#slots)
- [`Binding`](#binding)
- [Conditional elements (`--if`, `--else`)](#conditional-elements)
- [Conditional attributes (`attr:if`)](#conditional-attributes)
- [Loops](#loops)
- [Routing & Views](#routing)
- [Directives](#directives)
- [Stores](#stores)
- [Caching](#caching)
## Components
Components are classes that represents WebComponents. To define your component use a `Component` decorator with tag name of component as argument:
```ts
import { ComponentBase, Component, Ref, html } from 'bubblejs-core';
@Component('my-component')
class MyComponent extends ComponentBase {
@Ref()
public count: number = 0;
template() {
return html`
Clicked ${this.count} times
`;
}
onClick() {
this.count++;
}
// Lifecycle hooks
onBeforeMount() {
console.log('Before mounted');
}
onMount() {
console.log('Mounted');
}
onAdopt() {
console.log('Adopted');
}
onDestroy() {
console.log('Destroyed');
}
styles() {
return /*css*/`
button {
padding: 12px 20px;
background: #4938ff;
color: white;
border: none;
border-radius: 8px;
outline: none;
cursor: pointer;
font-size: 16px;
transition: 0.3s ease-in-out;
}
button:hover {
background: #6456fb;
}
`;
}
}
```
```html
```
When you define a component class, you should define a `template()` method, that returns HTML template that will be rendered.
The `styles()` method is optional and used to define CSS of your component.
## Refs
Refs are simply reactive data variables, that can be used inside component. To define a ref use a `Ref` decorator:
```ts
import { ComponentBase, Component, Ref, html } from 'bubblejs-core';
@Component('my-component')
class MyComponent extends ComponentBase {
@Ref()
public count: number = 0;
template() {
return html`
Count is ${ this.count }
`;
}
onMount() {
setInterval(() => {
this.count++
}, 100);
}
}
```
```html
```
Refs can be accessed via `this` context inside `template`, lifecycle hooks, event listeners, methods.
For more complex scenarios `Ref` has callbacks that you can use:
- `init` (Called before mount, when value of ref should be initialized)
- `get` (Called when someone is trying to get ref value)
- `set` (Called when someone is trying to change ref value)
```ts
import { ComponentBase, Component, Ref, html } from 'bubblejs-core';
@Component('my-component')
class MyComponent extends ComponentBase {
@Ref({
init(key) => console.log('Initialized ref'),
get(key) => console.log('Trying to get ref value'),
set(key, newVal, oldVal) => console.log('Trying to change ref value'),
})
public count: number = 0;
template() {
return html`
Count is ${ this.count }
`;
}
onMount() {
setInterval(() => {
this.count++
}, 100);
}
}
```
## WatchRefs
...
## Props
Props allows to define acceptable properties of your component. To define a component prop use a `Prop` decorator:
```ts
import { ComponentBase, Component, Prop, html } from 'bubblejs-core';
@Component('my-component')
class MyComponent extends ComponentBase {
@Prop()
public text: string = '';
template() {
return html`
${ this.text }
`;
}
}
```
```html
```
**Notice**: you can pass arrays/objects/functions as prop value also, but only inside another component template.
Props can be accessed via `this` context inside `template`, lifecycle hooks, event listeners, methods.
## Elements
Elements are simply refs that stores html elements. You can use them to automatically get html element from your template and work with it.
```ts
import { ComponentBase, Component, Element, html } from 'bubblejs-core';
@Component('my-component')
class MyComponent extends ComponentBase {
@Element('.some-input')
public inputEl?: HTMLInputElement;
template() {
return html`
`;
}
onMount() {
if(this.inputEl) {
this.inputEl.value = 'hello world!';
}
}
}
```
## Events
Events allows you to emit custom events up to parent component.
You just have to call `this.emit(eventName, ...args)` method to emit your event.
```ts
import { ComponentBase, Component, html } from 'bubblejs-core';
@Component('my-child')
class MyChild extends ComponentBase {
template() {
return html`
Button!
`;
}
onClick(e: Event) {
e.preventDefault();
// Emit custom event
this.emit('some-event');
}
}
@Component('my-parent')
class MyParent extends ComponentBase {
template() {
return html`
console.log('fired!')}">
`;
}
}
```
**Notice**: `emit` method is calls native `dispatchEvent`, that means you can also
use native `addEventListener` to catch your component's custom event.
## Slots
in progress.
## Binding
in progress.
## Conditional elements
For conditional rendering framework is provides special reserved directives `--if` and `--else`. You should pass boolean value, if value will be `true`, the element will be rendered, otherwise it will render the `--else` element.
```ts
import { ComponentBase, Component, Ref, html } from './lib/index';
@Component('my-component')
class MyComponent extends ComponentBase {
@Ref()
public doRender: boolean = false;
template() {
return html`
Hello world!
Bye world!
`;
}
}
```
After render:
```html
Bye world!
```
## Conditional attributes
As you apply conditions to render or not elements, you can apply conditions to set attribute or not. Framework provides special syntax for conditional attributes: `attrName:if="${true | false}"`. If value will be true, the element will have `attrName=""` attribute, otherwise attribute will be not added.
```ts
import { ComponentBase, Component, Ref, html } from './lib/index';
@Component('my-component')
class MyComponent extends ComponentBase {
@Ref()
public isRequired: boolean = false;
@Ref()
public isDisabled: boolean = true;
template() {
return html`
`;
}
}
```
After render:
```html
```
## Loops
Loops can be helpful when you need to render a list of something. To create a loop you can use a native array `.map` method.
```ts
import { ComponentBase, Component, Ref, html } from 'bubblejs-core';
@Component('some-list')
class SomeList extends ComponentBase {
@Ref()
public items: string[] = [
'hello',
'world',
'guys'
];
template() {
return html`
${this.items.map((item) => html`
${item}
`)}
`;
}
}
```
**Notice**: you can use alternative ways to do a loops, but in any way the returned value should be of type `HtmlTemplate[]`.
## Routing
Framework also provides a built-in lightweight routing system.
Firstly you have to use `bubble-router` component which is renders
current view inside:
```html
```
After that you can define views in your code using `View` decorator:
```ts
import { ComponentBase, View, Ref, html } from 'bubblejs-core';
@View('/')
class IndexView extends ComponentBase {
@Ref()
public subject = 'world';
template() {
return html`
Hello ${subject}!
`;
}
}
```
As you see, views are basically components but defined in different way.
## Directives
-
## Stores
-
## Caching
-