New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

hybrids

Package Overview
Dependencies
Maintainers
2
Versions
150
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

hybrids - npm Package Compare versions

Comparing version 7.0.0 to 7.0.1

docs/assets/prism.css

2

docs/_navbar.md

@@ -1,2 +0,2 @@

- [API Reference](/other/api-reference.md)
- [API Reference](/misc/api-reference.md)
- [Changelog](/CHANGELOG.md)

@@ -5,2 +5,10 @@ # Changelog

### [7.0.1](https://github.com/hybridsjs/hybrids/compare/v7.0.0...v7.0.1) (2021-12-16)
### Bug Fixes
* **define:** reflect back properties only for primitives ([398d92c](https://github.com/hybridsjs/hybrids/commit/398d92cbb1e459f24f40a165135f291e670ab205))
* **router:** scroll to top on push navigation on iOS ([8a99f68](https://github.com/hybridsjs/hybrids/commit/8a99f6863accefc5fca4dc1abe6aee3b6c53c795))
## [7.0.0](https://github.com/hybridsjs/hybrids/compare/v6.1.0...v7.0.0) (2021-12-08)

@@ -7,0 +15,0 @@

@@ -16,4 +16,2 @@ # Definition

## File Structure
The `define` function returns the passed definition object, so the following slick structure of the file is possible:

@@ -20,0 +18,0 @@

@@ -17,3 +17,3 @@ # Structure

If the property value is a `string`, `boolean`, `number` or `undefined`, the library creates a writable property with a default value (using [property descriptor](#descriptors) implicitly with the `value` option).
If the property value is a `string`, `boolean`, `number` or `undefined`, the library creates a writable property with a default value (using [property descriptor](#descriptor) implicitly with the `value` option).

@@ -33,8 +33,6 @@ Except for the `undefined`, the value type is protected and proper conversion is performed when a new value is set.

### Attributes
#### Attributes
All writable properties (not only primitives) use a corresponding dashed-cased attribute from the element for setting the initial value. Use the attribute only to define static values in the templates or the document, as the attribute changes are not being watched, and updating the attribute does not set the property.
Still, the attribute reflects the current value of the property. It allows using its value in CSS selectors in Shadow DOM, like `:host([first-name="John"])`.
Set static values in templates:

@@ -56,2 +54,4 @@

However, only properties set by the primitive or the `value` descriptor with `string`, `boolean` or `number` reflects back the current value of the property to the corresponding attribute. You can use this feature to create CSS selectors in Shadow DOM, like `:host([is-admin])`.
#### Booleans

@@ -81,3 +81,3 @@

If the property value is a function, the library creates a read-only property with the function as a getter (using [property descriptor](#descriptors) implicitly with `get` option), except a special behavior of the `render` and `content` properties described below.
If the property value is a function, the library creates a read-only property with the function as a getter (using [property descriptor](#descriptor) implicitly with `get` option), except a special behavior of the `render` and `content` properties described below.

@@ -99,3 +99,3 @@ The function is called with the custom element instance and last cached value of the property (read more in [`get and set`](#get-amp-set) section). Usually, the first argument is sufficient, which also can be destructured:

If the value of the `render` or `content` property is a function, the library creates a read-only property (using [property descriptor](#descriptors) implicitly with `get` and `observe` options), which returns a function for updating the Shadow DOM or content of the custom element.
If the value of the `render` or `content` property is a function, the library creates a read-only property (using [property descriptor](#descriptor) implicitly with `get` and `observe` options), which returns a function for updating the Shadow DOM or content of the custom element.

@@ -250,7 +250,7 @@ The function is called automatically when dependencies change, but it can also be called manually, by `el.render()` or `el.content()`.

> All writable properties (defined with `value` option, or with `set` method) support initial value from corresponding dashed-cased attribute described in [Attributes](#attributes) section of the primitive values
All writable properties (defined with `value` option, or with `set` method) support initial value from corresponding dashed-cased attribute described in [Attributes](#attributes) section of the primitive values.
### `value`
The `value` defines a writable property, which value type must be a `string`, `boolean`, `number` or `undefined`.
The `value` defines a writable property, which value type must be a `string`, `boolean`, `number` or `undefined`. The property uses the dashed-cased attribute for the initial value, and reflects back the value to attribute if the value is not a `undefined`.

@@ -257,0 +257,0 @@ ```javascript

@@ -15,3 +15,3 @@ # Getting Started

<script type="module">
import { html, define } from 'https://unpkg.com/hybrids@^5';
import { html, define } from 'https://unpkg.com/hybrids@^7';
...

@@ -18,0 +18,0 @@ </script>

@@ -11,3 +11,3 @@ <center>

A JavaScript framework for creating fully-featured web applications, components libraries, or single web components with unique declarative and functional architecture.
A JavaScript framework for creating fully-featured web applications, components libraries, and single web components with unique declarative and functional architecture.

@@ -38,2 +38,6 @@ ## Quick Look

```html
<simple-counter count="42"></simple-counter>
```
[![Edit <simple-counter> web component built with hybrids library](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/simple-counter-web-component-built-with-hybrids-library-co2ow?file=/src/SimpleCounter.js)

@@ -79,7 +83,11 @@

You can read more in the [Store](/store/overview.md) section of the documentation.
```html
<my-user-details user="2"></my-user-details>
```
You can read more in the [Store](/store/usage.md) section of the documentation.
### Router
The router 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 definitions.
The router 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.

@@ -102,2 +110,6 @@ ```javascript

```html
<my-app></my-app>
```
You can read more in the [Router](/router/usage.md) section of the documentation.

@@ -104,0 +116,0 @@

# Usage
The router 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 definitions.
The router 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.
## Factory
The router state is represented by the stack of views. If a user go deeper in the tree, the view is pushed to the stack. If the navigation goes up, the stack is cleared. However, the result stack array returns only the current view and dialogs (on the top of the current view). The rest of the views on the stack are kept in the memory with the current state, scroll positions and the last focused element.
```typescript
router(views: component | component[] | () => ..., options?: object): object
```
The stack of views is connected with the browser history, so the current stack and browser history is always in-sync. Because of the relations between the views, the router knows when to navigate forward or backward to reflect the structure.
* **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
* `options` - an object with following options:
* `url` - a string base URL used for views without own `url` option, defaults to current URL
* `params` - an array of property names of the element, which are passed to every view as a parameter
* **returns**:
* a hybrid property descriptor, which resolves to an array of elements
To start using the router, just add a property defined with the router factory to your main component of the application, and display the current stack of views:
Add a property defined with the router factory to your main component of the application to display the current stack of views:
```javascript

@@ -37,8 +27,24 @@ import { define, html, router } from "hybrids";

### Options
## Factory
#### `url`
```typescript
router(views: component | component[] | () => ..., options?: object): object
```
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.
* **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
* `options` - an object with following options:
* `url` - a string base URL used for views without own `url` option, defaults to current URL
* `params` - an array of property names of the element, which are passed to every view as a parameter
* **returns**:
* a hybrid property descriptor, which resolves to an array of elements
### `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.
### `url`
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).
```javascript

@@ -52,5 +58,5 @@ define({

#### `params`
### `params`
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 contain objects, and they are not included in the URL.
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.

@@ -78,14 +84,6 @@ ```javascript

### Stack
### Nested Routers
The current state of the router represents the stack of views. If users go deeper in the tree, the view is pushed to the stack. If the navigation goes backward, the stack is cleared. However, the result array returns only the current view and dialogs (on the top of the current view). The rest of the views on the stack are kept in the memory with the current state and scroll position of the DOM elements. Additionally, the router saves the last focused element, so it is restored when backward navigation is performed.
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.
The router connects the structure of the views with the browser history, so the current stack and browser history is always in-sync. Because of the relations between the views, the router knows when to navigate forward or backward to reflect the structure without the need to provide `navigate` or `redirect` methods.
> Views, which should be put on the stack and make forward navigation, are connected to the router by the `stack` option in the `[router.connect]` configuration object in the view definition
### Nesting
For complex app structures, 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.
```javascript

@@ -126,10 +124,12 @@ import { define, html, router } from "hybrids";

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 form elements as an `action` attribute.
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.
The component with the router listens to `click` and `submit` events, so when a user clicks on an anchor or submits the form, the router resolves the URL and navigates to the target view (going forward or backward in the history using the structure of views).
> The `submit` event does not cross the Shadow DOM boundary, so the recommended way is to use the `content` property in component definitions for the app structure
> The `submit` event does not cross the Shadow DOM boundary, so the recommended way is to use the `content` property in component definitions for the templates.
Besides specific parameters for the view, the router navigation methods support the `scrollToTop` option in the params, which clears the main scroll position of the view when it is navigated. As the views on the stack hold scroll positions, it might be useful, if you want to force the view to scroll to the top, but it is a parent view, and it might be already in the memory.
### `scrollToTop`
Besides specific parameters for the view, the router navigation methods support the `scrollToTop` option in the params, which clears the main scroll position of the view when it is navigated. As the views on the stack hold scroll positions, it might be useful, if you want to force the view to scroll to the top, but it is a parent view, which might be already in the memory. However, if the new view is pushed to the stack, the main vertical scroll position is cleared automatically, so you don't need to use this option then.
### `router.url()`

@@ -199,3 +199,3 @@

The `currentUrl` method generates an URL for the current view without using the definition explicitly. The parameters are the same as in the `url` method. It can be useful for reusable components, which then are used in multiple views, or for avoiding a need to create a reference to the definition in the module.
The `currentUrl` method generates an URL for the current view without using the definition explicitly. The parameters are the same as in the `url` method. It can be useful for reusable components, which are used in multiple views, or for avoiding a need to create a reference to the definition in the module.

@@ -215,2 +215,4 @@ ### `router.guardUrl()`

You can read more about the `guard` option in the [View](./view.md#guard) section.
### `router.resolve()`

@@ -260,3 +262,3 @@

The above dialog uses the `resolve` method when a user clicks on the `Yes` link. The router will navigate to the Users view only if the user model is successfully deleted. Otherwise, we can display an error message.
The above dialog uses the `resolve` method when a user clicks on the `Yes` link. The router will navigate to the Users view only if the user model is successfully deleted. Otherwise, the dialog displays an error message.

@@ -263,0 +265,0 @@ ### `router.active()`

@@ -25,3 +25,3 @@ # View

```typescript
[router.connect]: {
[router.connect]?: {
stack?: component[] | () => component[];

@@ -96,3 +96,3 @@ url?: string;

Besides the parameters from the `url` option, you can pass any writable property of the view when navigating to it. However, the URL in the address bar is only updated for those from the `url` option. This behavior allows deciding which parameters can be copied and used for the entry point of the application.
Besides the parameters from the `url` option, you can pass any writable property of the view when navigating to it. However, the URL in the address bar is only updated for those from the `url` option. This behavior allows deciding which parameters can be copied and used for the entry point of the application (all parameters are saved in the `history.state` object).

@@ -105,3 +105,3 @@ The matching algorithm goes from the roots of the view structures, going from right to left in their stacks. The first matched view is used.

Dialogs should be used for prompts, alerts, and messages displayed in the context of the parent view. As they don't exist standalone, the router protects from running the application with the dialog as an entry point and resolves the state to the parent view.
Dialogs should be used for prompts, alerts, and messages displayed in the context of the parent view. As they don't exist standalone, the router protects from running the application with the dialog as an entry point and resolves the state to the parent view (it clears out the stack to the top view).

@@ -191,5 +191,5 @@ ```javascript

When the router navigates to the view, which is already in the stack, it only updates the instance with the new parameters. It might have a different result than loading the view from scratch because the view might have some state, which is not updated.
When the router navigates to the view, which is already in the stack, it only updates the instance with the new parameters. It might have a different result than loading the view from scratch because the view might have some state, which is not updated. For example, the updated store model holds the previous state until the new one is ready.
For example, the updated store model holds the previous state until the new one is ready. In some cases, you might want to make a full reload of the view, still replacing the history entry. To do this, you can set the `replace` option to `true`.
In some cases, you might want to make a full reload of the view, still replacing the history entry. To do this, you can set the `replace` option to `true`.

@@ -217,10 +217,12 @@ ```javascript

The `guard` option allows specifying a function, which is called when the router is navigating to the view or children from the view's `stack`.
The `guard` option allows specifying a synchronous function, which is called when the router is navigating to the view or children from the view's `stack`.
If the user navigates directly to the view and a function returns a truthy value, the first view from the `stack` option is used, otherwise, the view itself is displayed (the `guard` can throw an error, or return falsy value).
If the user navigates directly to the view and a function returns a truthy value, the first view from the `stack` option is used. Otherwise, the view itself is displayed (the `guard` can throw an error, or return falsy value).
If the user navigates to the view from the stack, the guard function is also called, and if the condition is not met, the router navigates to the guarded view. However, the target view is saved in the history entry, so you can use the [`router.guardUrl()`](/router/usage.md#routerguardurl) method to generate the URL to the target view in guarded view content. There can be multiple guarded views on the path from the target view to the root. In that case, the router resolves guards from the deepest going up in the tree.
If the user navigates to the view from the stack, the guard function is also called, and if the condition is not met, the router navigates to the guarded view. However, the target view is saved in the history entry, so you can use the [`router.guardUrl()`](/router/usage.md#routerguardurl) method to generate the URL to the target view in guarded view content.
The `guard` function is only called while the navigation happens. The router does not call it when the view is rendered or updated. Because of that, it does not support the `host` argument, as the function is called outside of the element context. If the condition is related to some external APIs, the recommended way is to wrap it into the [store](/store/usage.md) model definition.
There can be multiple guarded views on the path from the target view to the root. In that case, the router resolves guards from the deepest going up in the tree.
The `guard` function is only called while the navigation happens. The router does not call it when the view is rendered or updated. Because of that, it does not support the `host` argument, as the function is called outside of the element context.
```javascript

@@ -254,2 +256,30 @@ import { define, html, router } from "hybrids";

To protect the application from the above example, in the main app component, the router factory should use the `Login` view as a root, instead of `Home`. The result views structure will have a new root node, which protects access to all of the stacked views.
To protect the application from the above example, in the main app component, the router factory should use the `Login` view as a root, instead of `Home`. The views structure will have a new root node, which protects access to all of the stacked views. The rest of the structure, including the `Home` view, is untouched, so the login feature is added on top of the existing application.
#### Async APIs
The function requires returning the value synchronously. If your guard function relates on async calls, you must wrap the main app element with the corresponding condition, which is displayed after the calls resolve:
```javascript
import { define, html } from "hybrids";
export const Session = {
...,
[store.connect]: {
get() => fetch("/me").then(res => res.json()),
set(id, values) => ...,
},
};
export default define({
tag: "my-async-app",
session: store(Session),
content: ({ session }) =>
store.ready(session) || store.error(session)
? html`<my-app></my-app>`
: html`<app-loader>...</app-loader>`
,
});
```
When the `session` is fetched for the first time, the `<app-loader>` will be displayed instead of `<my-app>`. After the session is ready or an error occurs, the app can be rendered, so the `guard` function can synchronously check if the session is ready.

@@ -32,9 +32,9 @@ # TypeScript

export default define({
export default define<MyElement>({
tag: "my-element",
user: store(User),
render: ({ user }) => html`
${store.ready(user) && ...}
${store.ready(user) && user.name}
`,
});
```
{
"name": "hybrids",
"version": "7.0.0",
"description": "The simplest way to create web components with plain objects and pure functions!",
"version": "7.0.1",
"description": "A JavaScript framework for creating fully-featured web applications, components libraries, and single web components with unique declarative and functional architecture",
"type": "module",

@@ -17,2 +17,4 @@ "sideEffects": false,

"keywords": [
"framework",
"web applications",
"web components",

@@ -25,5 +27,3 @@ "web-components",

"ui library",
"framework",
"pwa",
"functional"
"pwa"
],

@@ -30,0 +30,0 @@ "scripts": {

@@ -12,3 +12,3 @@

A JavaScript framework for creating fully-featured web applications, components libraries, or single web components with unique declarative and functional architecture.
A JavaScript framework for creating fully-featured web applications, components libraries, and single web components with unique declarative and functional architecture.

@@ -39,2 +39,6 @@ ## Quick Look

```html
<simple-counter count="42"></simple-counter>
```
[![Edit <simple-counter> web component built with hybrids library](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/simple-counter-web-component-built-with-hybrids-library-co2ow?file=/src/SimpleCounter.js)

@@ -80,7 +84,11 @@

You can read more in the [Store](https://hybrids.js.org/#/store/overview.md) section of the documentation.
```html
<my-user-details user="2"></my-user-details>
```
You can read more in the [Store](https://hybrids.js.org/#/store/usage.md) section of the documentation.
### Router
The router 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 definitions.
The router 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.

@@ -103,2 +111,6 @@ ```javascript

```html
<my-app></my-app>
```
You can read more in the [Router](https://hybrids.js.org/#/router/usage.md) section of the documentation.

@@ -105,0 +117,0 @@

@@ -99,3 +99,6 @@ import * as cache from "./cache.js";

const setAttr = (host, value) => {
if (!value && value !== 0) {
if (
(!value && value !== 0) ||
(typeof value === "object" && value.toString() === undefined)
) {
host.removeAttribute(attrName);

@@ -119,3 +122,6 @@ } else {

},
set: (host, value) => setAttr(host, transform(value)),
set:
type !== "undefined"
? (host, value) => setAttr(host, transform(value))
: (host, value) => value,
connect(host, _, invalidate) {

@@ -122,0 +128,0 @@ if (!host.hasAttribute(attrName) && host[key] === defaultValue) {

@@ -59,24 +59,21 @@ import { callbacksMap } from "./define.js";

const activeEl = document.activeElement;
const focusEl =
focusElement(
focusMap.get(target) ||
(rootRouter.contains(activeEl) ? activeEl : rootRouter);
(rootRouter.contains(activeEl) ? activeEl : rootRouter),
);
focusElement(focusEl);
const map = scrollMap.get(target);
if (map) {
Promise.resolve().then(() => {
const config = configs.get(target);
const state = window.history.state;
const entry = state.find(e => e.id === config.id);
const clear = entry && entry.params.scrollToTop;
const config = configs.get(target);
const state = window.history.state;
const entry = state.find(e => e.id === config.id);
const clear = entry && entry.params.scrollToTop;
map.forEach((pos, el) => {
el.scrollLeft = clear ? 0 : pos.left;
el.scrollTop = clear ? 0 : pos.top;
});
map.forEach((pos, el) => {
el.scrollLeft = clear ? 0 : pos.left;
el.scrollTop = clear ? 0 : pos.top;
});
scrollMap.delete(target);
});
scrollMap.delete(target);
} else {

@@ -83,0 +80,0 @@ const rootEl = document.scrollingElement;

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc