Comparing version 8.1.9 to 8.1.10
@@ -5,2 +5,11 @@ # Changelog | ||
### [8.1.10](https://github.com/hybridsjs/hybrids/compare/v8.1.9...v8.1.10) (2022-12-07) | ||
### Bug Fixes | ||
* **layout:** Add padding rule with box-sizing for display types ([9b31b87](https://github.com/hybridsjs/hybrids/commit/9b31b87b50633b5db91424a11da7694f74fe0dd2)) | ||
* **layout:** support for multiline attribute value ([a88f101](https://github.com/hybridsjs/hybrids/commit/a88f1011ba7489d452bd1af121c59c531e033e84)) | ||
* **router:** delay restore focus when navigate (safari) ([d6ba541](https://github.com/hybridsjs/hybrids/commit/d6ba5419aab3a4d4b00951e355faf6f3acc67cf1)) | ||
### [8.1.9](https://github.com/hybridsjs/hybrids/compare/v8.1.8...v8.1.9) (2022-11-17) | ||
@@ -7,0 +16,0 @@ |
@@ -5,3 +5,3 @@ # Layout Engine | ||
The layout engine provides creating CSS layouts in-place in templates without any external dependencies. It's built in similar way to utility-first CSS frameworks, but with much more powerful features. | ||
The layout engine provides creating CSS layouts in-place in templates without external dependencies. It's built in similar way to utility-first CSS frameworks, but with much more powerful features. | ||
@@ -147,8 +147,8 @@ It focuses on "invisible" CSS rules, like display types, alignments, positioning, sizing, etc. The rest should be defined inside of the reusable UI components by [styling](/component-model/templates.md#styling) supported by the templates. | ||
| Rule | Arguments | Defaults | Properties | | ||
|----------|---------------|----------|-----------------------------------------------| | ||
| block | [align:value] | block | `display: block`<br>`text-align: [align]` | | ||
| inline | --- | --- | `display: inline`<br>`display: [type]-inline` | | ||
| contents | --- | --- | `display: contents` | | ||
| hidden | --- | --- | `display: none` | | ||
| Rule | Arguments | Defaults | Properties | | ||
|----------|---------------|----------|--------------------------------------------------------------------------| | ||
| block | [align:value] | block | `display: block`<br>`box-sizing: border-box`<br>`text-align: [align]` | | ||
| inline | --- | --- | `display: inline`<br>`display: [type]-inline` | | ||
| contents | --- | --- | `display: contents` | | ||
| hidden | --- | --- | `display: none` | | ||
@@ -167,3 +167,3 @@ The `inline` rule can be used after other display types to make the element inline with corresponding type: | ||
|------------------------------------------------|--------------------------|---------------|----------------------------------------------| | ||
| row<br>row-reverse<br>column<br>column-reverse | [wrap:value] | [type]:nowrap | `display: flex` <br>`flex-flow: type [wrap]` | | ||
| row<br>row-reverse<br>column<br>column-reverse | [wrap:value] | [type]:nowrap | `display: flex`<br>`box-sizing: border-box`<br>`flex-flow: type [wrap]` | | ||
| grow | [number:value] | grow:1 | `flex-grow: [number]` | | ||
@@ -179,3 +179,3 @@ | shrink | [number:value] | shrink:1 | `flex-shrink: [number]` | | ||
|-------|-------------------------------------------|----------|-------------------------------------------------------------------------------------------------------------------------------| | ||
| grid | [columns]:[rows]:[autoFlow:value]:[dense] | grid:1 | `display: grid`<br>`grid-template-columns: [columns]`<br>`grid-template-rows: [rows]`<br>`grid-auto-flow: [autoFlow] [dense]` | | ||
| grid | [columns]:[rows]:[autoFlow:value]:[dense] | grid:1 | `display: grid`<br>`box-sizing: border-box`<br>`grid-template-columns: [columns]`<br>`grid-template-rows: [rows]`<br>`grid-auto-flow: [autoFlow] [dense]` | | ||
| area | [column:value]:[row:value] | none | `grid-column: span [number] \| [value]`<br>`grid-row: span [number] \| [value]` | | ||
@@ -216,3 +216,4 @@ | gap | [column:dimension]:[row:dimension] | gap:1 | `column-gap: [column];`<br>`row-gap: [row];` | | ||
| overflow | [type:value]<br>[axis:value]:[type:value] | overflow:hidden | `overflow: [type]`<br>`overflow-[axis]: [type]`<br>When `scroll` also:<br>`flex: 1 1 0`<br>`overscroll-behavior: contain`<br>`--webkit-overflow-scrolling: touch` | | ||
| margin | [v1:dim.]:[v2:dim.]:[v3:dim.]:[v4:dim.]<br>[side:value]:[v1:dimension] | margin:1<br>margin:[side]:1 | `margin: [v1] [v2] [v3] [v4]`<br>`margin-[side]` | | ||
| margin | [v1:dim.]:[v2:dim.]:[v3:dim.]:[v4:dim.]<br>[side:value]:[v:dimension] | margin:1<br>margin:[side]:1 | `margin: [v1] [v2] [v3] [v4]`<br>`margin-[side]: [v]` | | ||
| padding | [v1:dim.]:[v2:dim.]:[v3:dim.]:[v4:dim.]<br>[side:value]:[v:dimension] | padding:1<br>padding:[side]:1 | `padding: [v1] [v2] [v3] [v4]`<br>`padding-[side]: [v]` | | ||
@@ -219,0 +220,0 @@ ### Position |
@@ -5,3 +5,3 @@ # Getting Started | ||
If your application uses a bundler (like [Vite](https://vitejs.dev/) or [Snowpack](https://www.snowpack.dev/)), just add the [npm package](https://www.npmjs.com/package/hybrids) to your application: | ||
If your application setup uses a bundler (like [Vite](https://vitejs.dev/)), just add the [npm package](https://www.npmjs.com/package/hybrids) to your application: | ||
@@ -20,4 +20,9 @@ ```bash | ||
<script type="module"> | ||
import { html, define } from 'https://esm.sh/hybrids@^8'; | ||
... | ||
import { define, html } from 'https://esm.sh/hybrids@^8'; | ||
define({ | ||
tag: "hello-world", | ||
name: '', | ||
content: ({ name }) => html`<p>Hello ${name}!</p>`, | ||
}); | ||
</script> | ||
@@ -28,6 +33,6 @@ ``` | ||
HMR works out of the box, but your bundler setup may require indication that an entry point can be replaced on the fly. For example, for bundlers using ES module syntax, you can use the following code: | ||
HMR is supported out of the box, but your bundler setup may require indication that an entry point can be replaced on the fly. For example, for bundlers using ES module syntax, you can use the following code: | ||
```javascript | ||
// Enable HMR for development | ||
// Enable HMR only in development mode | ||
if (import.meta.hot) import.meta.hot.accept(); | ||
@@ -34,0 +39,0 @@ ``` |
<center> | ||
<h1> | ||
<img alt="hybrids" src="https://raw.githubusercontent.com/hybridsjs/hybrids/main/docs/assets/hybrids-full-logo.svg?sanitize=true" align="center"> | ||
<img alt="hybrids" src="/assets/hybrids-full-logo.svg" align="center"> | ||
</h1> | ||
@@ -8,14 +8,21 @@ </center> | ||
[![build status](https://github.com/hybridsjs/hybrids/actions/workflows/test.yml/badge.svg)](https://github.com/hybridsjs/hybrids/actions/workflows/test.yml?query=branch%3Amain) | ||
[![coverage status](https://img.shields.io/coveralls/github/hybridsjs/hybrids.svg?style=flat)](https://coveralls.io/github/hybridsjs/hybrids?branch=main) | ||
[![coverage status](https://coveralls.io/repos/github/hybridsjs/hybrids/badge.svg?branch=main)](https://coveralls.io/github/hybridsjs/hybrids?branch=main) | ||
[![npm version](https://img.shields.io/npm/v/hybrids.svg?style=flat)](https://www.npmjs.com/package/hybrids) | ||
**hybrids** is a JavaScript UI framework for creating fully-featured web applications, components libraries, or single web components with unique mixed declarative and functional architecture. | ||
> An extraordinary JavaScript framework for creating client-side web applications, UI components libraries, or single web components with unique mixed declarative and functional architecture | ||
The main goal of the framework is to provide a complete set of tools for the web platform - everything without external dependencies. It supports building UI components, managing complex states, creating app flows with client-side routing, and localizing its content for the worldwide markets. All of the parts follow the same unique concepts making it easy to understand and use! | ||
**hybrids** provides a complete set of tools for the web platform - everything without external dependencies: | ||
* **Component Model** based on plain objects and pure functions | ||
* **Global State Management** with external storages, offline caching, relations, and more | ||
* **App-like Routing** based on the graph structure of views | ||
* **Localization** with automatic translation of the templates content | ||
* **Layout Engine** making UI layouts development much faster | ||
* **Hot Module Replacement** support and other DX features | ||
## Quick Look | ||
### The Simplest Structure | ||
### Component Model | ||
The component model is based on plain objects and pure functions*, still using the [Web Components API](https://developer.mozilla.org/en-US/docs/Web/Web_Components) under the hood: | ||
It's based on plain objects and pure functions*, still using the [Web Components API](https://developer.mozilla.org/en-US/docs/Web/Web_Components) under the hood: | ||
@@ -50,31 +57,7 @@ ```javascript | ||
### Seamless Localization | ||
### Global State Management | ||
Built-in support for automatic translation of the component's content makes translation seamless and easy to integrate. Additionally, the framework provides a way to add dynamic messages with plural forms, HTML content, or use messages outside of the template context. Also, it comes with handy CLI tool to extract messages from the source code! | ||
A global state management uses declarative model definitions with support for async external storages, relations, offline caching, and many more: | ||
```javascript | ||
import { define, html, localize } from "hybrids"; | ||
export default define({ | ||
tag: "my-element", | ||
name: "", | ||
render: ({ name }) => html` | ||
<div>Hello ${name}!</div> | ||
`, | ||
}); | ||
localize("pl", { | ||
"Hello ${0}!": { | ||
message: "Witaj ${0}!", | ||
}, | ||
}); | ||
``` | ||
You can read more in the [Localization](https://hybrids.js.org/#/component-model/localization.md) section of the documentation. | ||
### Complex State Management | ||
The store module provides a global state management based on declarative model definitions with built-in support for async external storages, relations, offline caching, and many more. It follows the declarative architecture to simplify the process of defining and using data structures: | ||
```javascript | ||
import { define, store, html } from "hybrids"; | ||
@@ -87,3 +70,3 @@ | ||
[store.connect] : { | ||
get: id => fetch(`/users/${id}`).then(res => res.json()), | ||
get: id => fetch(`/users/${id}`).then(...), | ||
}, | ||
@@ -93,3 +76,3 @@ }; | ||
define({ | ||
tag: "my-user-details", | ||
tag: "user-details", | ||
user: store(User), | ||
@@ -110,3 +93,3 @@ render: ({ user }) => html` | ||
```html | ||
<my-user-details user="2"></my-user-details> | ||
<user-details user="2"></user-details> | ||
``` | ||
@@ -116,5 +99,5 @@ | ||
### Structural Client-Side Routing | ||
### App-like Routing | ||
The router module provides a global navigation system for client-side applications. Rather than just matching URLs with the corresponding components, it depends on a tree-like structure of views, which have their own routing configuration in the component definition. It makes the URLs optional, have out-the-box support for dialogs, protected views, and many more. | ||
Rather than just matching URLs with the corresponding components, the router depends on a tree-like structure of views, which have their own routing configuration. It makes the URLs optional, have out-the-box support for dialogs, protected views, and many more. | ||
@@ -124,11 +107,25 @@ ```javascript | ||
import Home from "./views/Home.js"; | ||
import Details from "./details.js"; | ||
const Home = define({ | ||
[router.connect]: { stack: [Details, ...] }, | ||
tag: "app-home", | ||
content: () => html` | ||
<template layout="column"> | ||
<h1>Home</h1> | ||
<nav layout="row gap"> | ||
<a href="${router.url(Details)}">Details</a> | ||
</nav> | ||
... | ||
</template> | ||
`, | ||
}); | ||
export define({ | ||
tag: "my-app", | ||
views: router(Home), | ||
content: ({ views }) => html` | ||
<my-app-layout> | ||
${views} | ||
</my-app-layout> | ||
tag: "app-router", | ||
stack: router(Home), | ||
content: ({ stack }) => html` | ||
<template layout="column"> | ||
${stack} | ||
</template> | ||
`, | ||
@@ -139,3 +136,3 @@ }); | ||
```html | ||
<my-app></my-app> | ||
<app-router></app-router> | ||
``` | ||
@@ -145,6 +142,51 @@ | ||
### Localization | ||
It supports automatic translation of the component's content, which makes translation seamless and easy to integrate. Additionally, it provides a way to add dynamic messages with plural forms, HTML content, or use messages outside of the template context. Also, it comes with handy CLI tool to extract messages from the source code! | ||
```javascript | ||
import { define, html, localize } from "hybrids"; | ||
export default define({ | ||
tag: "my-element", | ||
name: "", | ||
render: ({ name }) => html` | ||
<div>Hello ${name}!</div> | ||
`, | ||
}); | ||
localize("pl", { | ||
"Hello ${0}!": { | ||
message: "Witaj ${0}!", | ||
}, | ||
}); | ||
``` | ||
You can read more in the [Localization](/component-model/localization.md) section. | ||
### Layout Engine | ||
Create CSS layouts in-place in templates, even without using Shadow DOM, but still keeping the encapsulation of the component's styles: | ||
```javascript | ||
define({ | ||
tag: "app-home-view", | ||
content: () => html` | ||
<template layout="column center gap:2"> | ||
<div layout="grow grid:1|max"> | ||
<h1>Home</h1> | ||
... | ||
</div> | ||
<footer layout@768px="hidden">...</footer> | ||
</template> | ||
` | ||
}); | ||
``` | ||
You can read more in the [Layout Engine](/component-model/layout-engine.md) section. | ||
## Community | ||
* Follow on [Twitter](https://twitter.com/hybridsjs) | ||
* Chat on [Gitter](https://gitter.im/hybridsjs) | ||
Do you need help? Something went wrong? Feel free to create [an issue](https://github.com/hybridsjs/hybrids/issues/new) in the github repository or join the [Gitter](https://gitter.im/hybridsjs/hybrids) channel. | ||
@@ -151,0 +193,0 @@ ## License |
@@ -18,6 +18,6 @@ # Usage | ||
tag: "my-app", | ||
views: router(Home), | ||
content: ({ views }) => html` | ||
stack: router(Home), | ||
content: ({ stack }) => html` | ||
<my-app-layout> | ||
${views} | ||
${stack} | ||
</my-app-layout> | ||
@@ -35,3 +35,3 @@ `, | ||
* **arguments**: | ||
* `views` - a defined component or an array of defined components. You can wrap `views` in a function to avoid using imports from uninitialized ES modules | ||
* `views` - a defined component or an array of defined components. You can wrap `views` in a function to avoid uninitialized ES modules issue | ||
* `options` - an object with following options: | ||
@@ -43,7 +43,9 @@ * `url` - a string base URL used for views without own `url` option, defaults to current URL | ||
### `views` | ||
### Arguments | ||
#### `views` | ||
Views passed to the router factory create the roots of the view structures. Usually, there is only one root view, but you can pass a list of them (navigating between roots always replaces the whole stack). You can find a deeper explanation of the view concept in the [View](/router/view.md) section. | ||
### `options.url` | ||
#### `options.url` | ||
@@ -60,3 +62,3 @@ If your application uses a mixed approach - views with and without URLs, you should specify a base URL to avoid not deterministic behavior of the router for views without the URL. Otherwise, the router will use an entry point as a base URL (which can be different according to the use case). | ||
### `options.params` | ||
#### `options.params` | ||
@@ -86,3 +88,3 @@ Regardless of the explicit parameters when navigating to the view, you can specify an array of properties of the component, which are passed to every view as a parameter. They bypass the URL generation, so they are set by the reference, and they are not included in the URL. | ||
### Nested Routers | ||
## Nested Routers | ||
@@ -111,3 +113,3 @@ For complex layouts, the router factory can be used inside of the views already connected to the parent router. This feature differs from setting views in the `stack` option of the view. The nested router displays content inside of the host view as content, not a separate view in the stack. | ||
### Events | ||
## Events | ||
@@ -125,3 +127,3 @@ The router dispatches the `navigate` event on the host element, which can be used for the external purposes: | ||
## Navigating | ||
## Navigation | ||
@@ -325,2 +327,2 @@ The router provides a set of methods to navigate to the views. Generally, those methods generate an URL instance, which can be used in anchors as `href` attribute and forms as an `action` attribute. | ||
if (import.meta.env.DEV) router.debug(); | ||
``` | ||
``` |
{ | ||
"name": "hybrids", | ||
"version": "8.1.9", | ||
"version": "8.1.10", | ||
"description": "A JavaScript framework for creating fully-featured web applications, components libraries, and single web components with unique declarative and functional architecture", | ||
"type": "module", | ||
"sideEffects": false, | ||
"main": "./src/index.js", | ||
"module": "./src/index.js", | ||
"exports": "./src/index.js", | ||
"types": "types/index.d.ts", | ||
"bin": "./scripts/cli.js", | ||
"bin": "./cli/index.js", | ||
"sideEffects": false, | ||
"homepage": "https://hybrids.js.org", | ||
@@ -27,2 +25,5 @@ "repository": "https://github.com/hybridsjs/hybrids", | ||
], | ||
"engines": { | ||
"node": ">=18.0.0" | ||
}, | ||
"scripts": { | ||
@@ -33,4 +34,5 @@ "karma": "karma start karma.conf.cjs", | ||
"lint": "eslint ./src", | ||
"test": "npm run lint && npm run karma", | ||
"test": "npm run test:cli && npm run lint && npm run karma", | ||
"test:coverage": "rm -rf ./coverage && NODE_ENV=coverage npm run karma", | ||
"test:cli": "node ./cli/test.js", | ||
"release": "npm run test && standard-version -a" | ||
@@ -37,0 +39,0 @@ }, |
150
README.md
<center> | ||
<h1> | ||
<img alt="" src="https://raw.githubusercontent.com/hybridsjs/hybrids/main/docs/assets/hybrids-full-logo.svg?sanitize=true" align="center"> | ||
<h1 align="center"> | ||
<img alt="hybrids" src="https://raw.githubusercontent.com/hybridsjs/hybrids/main/docs/assets/hybrids-full-logo.svg?sanitize=true"> | ||
</h1> | ||
</center> | ||
[![build status](https://github.com/hybridsjs/hybrids/actions/workflows/test.yml/badge.svg)](https://github.com/hybridsjs/hybrids/actions/workflows/test.yml?query=branch%3Amain) | ||
[![coverage status](https://img.shields.io/coveralls/github/hybridsjs/hybrids.svg?style=flat)](https://coveralls.io/github/hybridsjs/hybrids?branch=main) | ||
[![coverage status](https://coveralls.io/repos/github/hybridsjs/hybrids/badge.svg?branch=main)](https://coveralls.io/github/hybridsjs/hybrids?branch=main) | ||
[![npm version](https://img.shields.io/npm/v/hybrids.svg?style=flat)](https://www.npmjs.com/package/hybrids) | ||
**hybrids** is a JavaScript UI framework for creating fully-featured web applications, components libraries, or single web components with unique mixed declarative and functional architecture. | ||
> An extraordinary JavaScript framework for creating client-side web applications, UI components libraries, or single web components with unique mixed declarative and functional architecture | ||
The main goal of the framework is to provide a complete set of tools for the web platform - everything without external dependencies. It supports building UI components, managing complex states, creating app flows with client-side routing, and localizing its content for the worldwide markets. All of the parts follow the same unique concepts making it easy to understand and use! | ||
**hybrids** provides a complete set of tools for the web platform - everything without external dependencies: | ||
* **Component Model** based on plain objects and pure functions | ||
* **Global State Management** with external storages, offline caching, relations, and more | ||
* **App-like Routing** based on the graph structure of views | ||
* **Localization** with automatic translation of the templates content | ||
* **Layout Engine** making UI layouts development much faster | ||
* **Hot Module Replacement** support and other DX features | ||
### Documentation | ||
The project documentation is available at the [hybrids.js.org](https://hybrids.js.org) site. | ||
## Quick Look | ||
### The Simplest Structure | ||
### Component Model | ||
The component model is based on plain objects and pure functions*, still using the [Web Components API](https://developer.mozilla.org/en-US/docs/Web/Web_Components) under the hood: | ||
It's based on plain objects and pure functions*, still using the [Web Components API](https://developer.mozilla.org/en-US/docs/Web/Web_Components) under the hood: | ||
@@ -48,33 +57,9 @@ ```javascript | ||
You can read more in the [Component Model](https://hybrids.js.org/#/component-model/definition.md) section of the documentation. | ||
You can read more in the [Component Model](https://hybrids.js.org/#/component-model/definition.md) section. | ||
### Seamless Localization | ||
### Global State Management | ||
Built-in support for automatic translation of the component's content makes translation seamless and easy to integrate. Additionally, the framework provides a way to add dynamic messages with plural forms, HTML content, or use messages outside of the template context. Also, it comes with handy CLI tool to extract messages from the source code! | ||
A global state management uses declarative model definitions with support for async external storages, relations, offline caching, and many more: | ||
```javascript | ||
import { define, html, localize } from "hybrids"; | ||
export default define({ | ||
tag: "my-element", | ||
name: "", | ||
render: ({ name }) => html` | ||
<div>Hello ${name}!</div> | ||
`, | ||
}); | ||
localize("pl", { | ||
"Hello ${0}!": { | ||
message: "Witaj ${0}!", | ||
}, | ||
}); | ||
``` | ||
You can read more in the [Localization](https://hybrids.js.org/#/component-model/localization.md) section of the documentation. | ||
### Complex State Management | ||
The store module provides a global state management based on declarative model definitions with built-in support for async external storages, relations, offline caching, and many more. It follows the declarative architecture to simplify the process of defining and using data structures: | ||
```javascript | ||
import { define, store, html } from "hybrids"; | ||
@@ -87,3 +72,3 @@ | ||
[store.connect] : { | ||
get: id => fetch(`/users/${id}`).then(res => res.json()), | ||
get: id => fetch(`/users/${id}`).then(...), | ||
}, | ||
@@ -93,3 +78,3 @@ }; | ||
define({ | ||
tag: "my-user-details", | ||
tag: "user-details", | ||
user: store(User), | ||
@@ -110,10 +95,10 @@ render: ({ user }) => html` | ||
```html | ||
<my-user-details user="2"></my-user-details> | ||
<user-details user="2"></user-details> | ||
``` | ||
You can read more in the [Store](https://hybrids.js.org/#/store/usage.md) section of the documentation. | ||
You can read more in the [Store](https://hybrids.js.org/#/store/usage.md) section. | ||
### Structural Client-Side Routing | ||
### App-like Routing | ||
The router module provides a global navigation system for client-side applications. Rather than just matching URLs with the corresponding components, it depends on a tree-like structure of views, which have their own routing configuration in the component definition. It makes the URLs optional, have out-the-box support for dialogs, protected views, and many more. | ||
Rather than just matching URLs with the corresponding components, the router depends on a tree-like structure of views, which have their own routing configuration. It makes the URLs optional, have out-the-box support for dialogs, protected views, and many more. | ||
@@ -123,11 +108,25 @@ ```javascript | ||
import Home from "./views/Home.js"; | ||
import Details from "./details.js"; | ||
const Home = define({ | ||
[router.connect]: { stack: [Details, ...] }, | ||
tag: "app-home", | ||
content: () => html` | ||
<template layout="column"> | ||
<h1>Home</h1> | ||
<nav layout="row gap"> | ||
<a href="${router.url(Details)}">Details</a> | ||
</nav> | ||
... | ||
</template> | ||
`, | ||
}); | ||
export define({ | ||
tag: "my-app", | ||
views: router(Home), | ||
content: ({ views }) => html` | ||
<my-app-layout> | ||
${views} | ||
</my-app-layout> | ||
tag: "app-router", | ||
stack: router(Home), | ||
content: ({ stack }) => html` | ||
<template layout="column"> | ||
${stack} | ||
</template> | ||
`, | ||
@@ -138,15 +137,56 @@ }); | ||
```html | ||
<my-app></my-app> | ||
<app-router></app-router> | ||
``` | ||
You can read more in the [Router](https://hybrids.js.org/#/router/usage.md) section of the documentation. | ||
You can read more in the [Router](https://hybrids.js.org/#/router/usage.md) section. | ||
## Documentation | ||
### Localization | ||
The project documentation is available at the [hybrids.js.org](https://hybrids.js.org) site. | ||
It supports automatic translation of the component's content, which makes translation seamless and easy to integrate. Additionally, it provides a way to add dynamic messages with plural forms, HTML content, or use messages outside of the template context. Also, it comes with handy CLI tool to extract messages from the source code! | ||
```javascript | ||
import { define, html, localize } from "hybrids"; | ||
export default define({ | ||
tag: "my-element", | ||
name: "", | ||
render: ({ name }) => html` | ||
<div>Hello ${name}!</div> | ||
`, | ||
}); | ||
localize("pl", { | ||
"Hello ${0}!": { | ||
message: "Witaj ${0}!", | ||
}, | ||
}); | ||
``` | ||
You can read more in the [Localization](https://hybrids.js.org/#/component-model/localization.md) section of the documentation. | ||
### Layout Engine | ||
Create CSS layouts in-place in templates, even without using Shadow DOM, but still keeping the encapsulation of the component's styles: | ||
```javascript | ||
define({ | ||
tag: "app-home-view", | ||
content: () => html` | ||
<template layout="column center gap:2"> | ||
<div layout="grow grid:1|max"> | ||
<h1>Home</h1> | ||
... | ||
</div> | ||
<footer layout@768px="hidden">...</footer> | ||
</template> | ||
` | ||
}); | ||
``` | ||
You can read more in the [Layout Engine](https://hybrids.js.org/#/component-model/layout-engine.md) section of the documentation. | ||
## Community | ||
* Follow on [Twitter](https://twitter.com/hybridsjs) | ||
* Chat on [Gitter](https://gitter.im/hybridsjs) | ||
Do you need help? Something went wrong? Feel free to create [an issue](https://github.com/hybridsjs/hybrids/issues/new) in the github repository or join the [Gitter](https://gitter.im/hybridsjs/hybrids) channel. | ||
@@ -153,0 +193,0 @@ ## License |
@@ -54,31 +54,37 @@ import global from "./global.js"; | ||
} | ||
target.focus({ preventScroll: true }); | ||
} | ||
let restoreTimeout = null; | ||
function restoreLayout(target) { | ||
const activeEl = global.document.activeElement; | ||
focusElement( | ||
focusMap.get(target) || | ||
(rootRouter.contains(activeEl) ? activeEl : rootRouter), | ||
); | ||
clearTimeout(restoreTimeout); | ||
const map = scrollMap.get(target); | ||
if (map) { | ||
const config = configs.get(target); | ||
const state = global.history.state; | ||
const entry = state.find((e) => e.id === config.id); | ||
const clear = entry && entry.params.scrollToTop; | ||
restoreTimeout = setTimeout(() => { | ||
focusElement( | ||
focusMap.get(target) || | ||
(rootRouter.contains(activeEl) ? activeEl : rootRouter), | ||
); | ||
for (const [el, { left, top }] of map) { | ||
el.scrollLeft = clear ? 0 : left; | ||
el.scrollTop = clear ? 0 : top; | ||
const map = scrollMap.get(target); | ||
if (map) { | ||
const config = configs.get(target); | ||
const state = global.history.state; | ||
const entry = state.find((e) => e.id === config.id); | ||
const clear = entry && entry.params.scrollToTop; | ||
for (const [el, { left, top }] of map) { | ||
el.scrollLeft = clear ? 0 : left; | ||
el.scrollTop = clear ? 0 : top; | ||
} | ||
scrollMap.delete(target); | ||
} else { | ||
const rootEl = global.document.scrollingElement; | ||
rootEl.scrollLeft = 0; | ||
rootEl.scrollTop = 0; | ||
} | ||
scrollMap.delete(target); | ||
} else { | ||
const rootEl = global.document.scrollingElement; | ||
rootEl.scrollLeft = 0; | ||
rootEl.scrollTop = 0; | ||
} | ||
}); | ||
} | ||
@@ -288,3 +294,2 @@ | ||
const prevActiveEl = global.document.activeElement; | ||
const root = rootRouter; | ||
@@ -302,4 +307,2 @@ | ||
host.removeEventListener("keydown", goBackOnEscKey); | ||
focusElement(prevActiveEl); | ||
}; | ||
@@ -749,3 +752,6 @@ }); | ||
if (nextView === prevView) { | ||
if (offset === 0 && host === rootRouter && entry.params.scrollToTop) { | ||
if ( | ||
offset > 0 || | ||
(offset === 0 && host === rootRouter && entry.params.scrollToTop) | ||
) { | ||
restoreLayout(nextView); | ||
@@ -752,0 +758,0 @@ } |
@@ -7,3 +7,7 @@ import global from "../global.js"; | ||
// base | ||
block: (props, align) => ({ display: "block", "text-align": align }), | ||
block: (props, align) => ({ | ||
display: "block", | ||
"text-align": align, | ||
"box-sizing": "border-box", | ||
}), | ||
inline: ({ display }) => ({ | ||
@@ -20,2 +24,3 @@ display: `inline${display ? `-${display}` : ""}`, | ||
"flex-flow": `${type} ${wrap}`, | ||
"box-sizing": "border-box", | ||
}); | ||
@@ -47,2 +52,3 @@ return acc; | ||
"grid-auto-flow": `${autoFlow} ${dense && "dense"}`, | ||
"box-sizing": "border-box", | ||
}), | ||
@@ -115,3 +121,16 @@ area: (props, column = "", row = "") => ({ | ||
}, | ||
padding: (props, v1 = "1", v2, v3, v4) => { | ||
if (v1.match(/top|bottom|left|right/)) { | ||
return { | ||
[`padding-${v1}`]: dimension(v2 || "1"), | ||
}; | ||
} | ||
return { | ||
padding: `${dimension(v1)} ${dimension(v2)} ${dimension(v3)} ${dimension( | ||
v4, | ||
)}`, | ||
}; | ||
}, | ||
// position types | ||
@@ -228,17 +247,21 @@ absolute: { position: "absolute" }, | ||
const cssRules = Object.entries( | ||
tokens.split(" ").reduce((acc, token) => { | ||
const [id, ...args] = token.split(":"); | ||
const rule = rules[id]; | ||
tokens | ||
.replace(/\s+/g, " ") | ||
.trim() | ||
.split(" ") | ||
.reduce((acc, token) => { | ||
const [id, ...args] = token.split(":"); | ||
const rule = rules[id]; | ||
if (!rule) { | ||
throw TypeError(`Unsupported layout rule: '${id}'`); | ||
} | ||
if (!rule) { | ||
throw TypeError(`Unsupported layout rule: '${id}'`); | ||
} | ||
return Object.assign( | ||
acc, | ||
typeof rule === "function" | ||
? rule(acc, ...args.map((v) => (v.match(/--.*/) ? `var(${v})` : v))) | ||
: rule, | ||
); | ||
}, {}), | ||
return Object.assign( | ||
acc, | ||
typeof rule === "function" | ||
? rule(acc, ...args.map((v) => (v.match(/--.*/) ? `var(${v})` : v))) | ||
: rule, | ||
); | ||
}, {}), | ||
).reduce( | ||
@@ -245,0 +268,0 @@ (acc, [key, value]) => |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
457418
67
6945
190