Socket
Socket
Sign inDemoInstall

solenya

Package Overview
Dependencies
Maintainers
1
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

solenya - npm Package Compare versions

Comparing version 1.2.6 to 1.2.7

language-interop-complexity.png

213

dist/html.d.ts

@@ -1,112 +0,115 @@

import { VElement, VAttributes, VNode } from './dom';
import { VElement, VAttributes, VNode, VLifecycle } from './dom';
import { types } from 'typestyle';
import { NestedCSSProperties } from 'typestyle/lib/types';
export declare type HAttributeValue = undefined | string | number | ((ev: any) => any) | NestedCSSProperties;
export interface HAttributes extends VAttributes, KnownHtmlAttributes {
[key: string]: any;
[key: string]: HAttributeValue;
}
export declare type HValue = VNode | HAttributes | null | undefined;
export declare type HValue = VNode | HAttributes | VLifecycle | null | undefined;
export declare type HValues = HValue | VNode[];
/** Merges two attribute structures, where style structures are converted to classes using style style,
* classes are combined, and lifecycle hooks are combined. */
export declare function mergeAttrs(dominant: HAttributes | undefined, recessive: HAttributes | undefined): HAttributes | undefined;
export declare function h(tag: string, ...values: HValue[]): VElement;
export declare function a(...values: HValue[]): VElement;
export declare function abbr(...values: HValue[]): VElement;
export declare function address(...values: HValue[]): VElement;
export declare function area(...values: HValue[]): VElement;
export declare function article(...values: HValue[]): VElement;
export declare function aside(...values: HValue[]): VElement;
export declare function audio(...values: HValue[]): VElement;
export declare function b(...values: HValue[]): VElement;
export declare function bdi(...values: HValue[]): VElement;
export declare function bdo(...values: HValue[]): VElement;
export declare function blockquote(...values: HValue[]): VElement;
export declare function br(...values: HValue[]): VElement;
export declare function button(...values: HValue[]): VElement;
export declare function canvas(...values: HValue[]): VElement;
export declare function caption(...values: HValue[]): VElement;
export declare function cite(...values: HValue[]): VElement;
export declare function code(...values: HValue[]): VElement;
export declare function col(...values: HValue[]): VElement;
export declare function colgroup(...values: HValue[]): VElement;
export declare function data(...values: HValue[]): VElement;
export declare function datalist(...values: HValue[]): VElement;
export declare function dd(...values: HValue[]): VElement;
export declare function del(...values: HValue[]): VElement;
export declare function details(...values: HValue[]): VElement;
export declare function dfn(...values: HValue[]): VElement;
export declare function dialog(...values: HValue[]): VElement;
export declare function div(...values: HValue[]): VElement;
export declare function dl(...values: HValue[]): VElement;
export declare function dt(...values: HValue[]): VElement;
export declare function em(...values: HValue[]): VElement;
export declare function embed(...values: HValue[]): VElement;
export declare function fieldset(...values: HValue[]): VElement;
export declare function figcaption(...values: HValue[]): VElement;
export declare function figure(...values: HValue[]): VElement;
export declare function footer(...values: HValue[]): VElement;
export declare function form(...values: HValue[]): VElement;
export declare function h1(...values: HValue[]): VElement;
export declare function h2(...values: HValue[]): VElement;
export declare function h3(...values: HValue[]): VElement;
export declare function h4(...values: HValue[]): VElement;
export declare function h5(...values: HValue[]): VElement;
export declare function h6(...values: HValue[]): VElement;
export declare function header(...values: HValue[]): VElement;
export declare function hr(...values: HValue[]): VElement;
export declare function i(...values: HValue[]): VElement;
export declare function iframe(...values: HValue[]): VElement;
export declare function img(...values: HValue[]): VElement;
export declare function input(...values: HValue[]): VElement;
export declare function ins(...values: HValue[]): VElement;
export declare function kbd(...values: HValue[]): VElement;
export declare function label(...values: HValue[]): VElement;
export declare function legend(...values: HValue[]): VElement;
export declare function li(...values: HValue[]): VElement;
export declare function main(...values: HValue[]): VElement;
export declare function map(...values: HValue[]): VElement;
export declare function mark(...values: HValue[]): VElement;
export declare function menu(...values: HValue[]): VElement;
export declare function menuitem(...values: HValue[]): VElement;
export declare function meter(...values: HValue[]): VElement;
export declare function nav(...values: HValue[]): VElement;
export declare function object(...values: HValue[]): VElement;
export declare function ol(...values: HValue[]): VElement;
export declare function optgroup(...values: HValue[]): VElement;
export declare function option(...values: HValue[]): VElement;
export declare function output(...values: HValue[]): VElement;
export declare function p(...values: HValue[]): VElement;
export declare function param(...values: HValue[]): VElement;
export declare function pre(...values: HValue[]): VElement;
export declare function progress(...values: HValue[]): VElement;
export declare function q(...values: HValue[]): VElement;
export declare function rp(...values: HValue[]): VElement;
export declare function rt(...values: HValue[]): VElement;
export declare function rtc(...values: HValue[]): VElement;
export declare function ruby(...values: HValue[]): VElement;
export declare function s(...values: HValue[]): VElement;
export declare function samp(...values: HValue[]): VElement;
export declare function section(...values: HValue[]): VElement;
export declare function select(...values: HValue[]): VElement;
export declare function small(...values: HValue[]): VElement;
export declare function source(...values: HValue[]): VElement;
export declare function span(...values: HValue[]): VElement;
export declare function strong(...values: HValue[]): VElement;
export declare function sub(...values: HValue[]): VElement;
export declare function summary(...values: HValue[]): VElement;
export declare function sup(...values: HValue[]): VElement;
export declare function svg(...values: HValue[]): VElement;
export declare function table(...values: HValue[]): VElement;
export declare function tbody(...values: HValue[]): VElement;
export declare function td(...values: HValue[]): VElement;
export declare function textarea(...values: HValue[]): VElement;
export declare function tfoot(...values: HValue[]): VElement;
export declare function th(...values: HValue[]): VElement;
export declare function thead(...values: HValue[]): VElement;
export declare function time(...values: HValue[]): VElement;
export declare function tr(...values: HValue[]): VElement;
export declare function track(...values: HValue[]): VElement;
export declare function u(...values: HValue[]): VElement;
export declare function ul(...values: HValue[]): VElement;
export declare function video(...values: HValue[]): VElement;
export declare function vvar(...values: HValue[]): VElement;
export declare function wbr(...values: HValue[]): VElement;
export declare function h(tag: string, ...values: HValues[]): VElement;
export declare function a(...values: HValues[]): VElement;
export declare function abbr(...values: HValues[]): VElement;
export declare function address(...values: HValues[]): VElement;
export declare function area(...values: HValues[]): VElement;
export declare function article(...values: HValues[]): VElement;
export declare function aside(...values: HValues[]): VElement;
export declare function audio(...values: HValues[]): VElement;
export declare function b(...values: HValues[]): VElement;
export declare function bdi(...values: HValues[]): VElement;
export declare function bdo(...values: HValues[]): VElement;
export declare function blockquote(...values: HValues[]): VElement;
export declare function br(...values: HValues[]): VElement;
export declare function button(...values: HValues[]): VElement;
export declare function canvas(...values: HValues[]): VElement;
export declare function caption(...values: HValues[]): VElement;
export declare function cite(...values: HValues[]): VElement;
export declare function code(...values: HValues[]): VElement;
export declare function col(...values: HValues[]): VElement;
export declare function colgroup(...values: HValues[]): VElement;
export declare function data(...values: HValues[]): VElement;
export declare function datalist(...values: HValues[]): VElement;
export declare function dd(...values: HValues[]): VElement;
export declare function del(...values: HValues[]): VElement;
export declare function details(...values: HValues[]): VElement;
export declare function dfn(...values: HValues[]): VElement;
export declare function dialog(...values: HValues[]): VElement;
export declare function div(...values: HValues[]): VElement;
export declare function dl(...values: HValues[]): VElement;
export declare function dt(...values: HValues[]): VElement;
export declare function em(...values: HValues[]): VElement;
export declare function embed(...values: HValues[]): VElement;
export declare function fieldset(...values: HValues[]): VElement;
export declare function figcaption(...values: HValues[]): VElement;
export declare function figure(...values: HValues[]): VElement;
export declare function footer(...values: HValues[]): VElement;
export declare function form(...values: HValues[]): VElement;
export declare function h1(...values: HValues[]): VElement;
export declare function h2(...values: HValues[]): VElement;
export declare function h3(...values: HValues[]): VElement;
export declare function h4(...values: HValues[]): VElement;
export declare function h5(...values: HValues[]): VElement;
export declare function h6(...values: HValues[]): VElement;
export declare function header(...values: HValues[]): VElement;
export declare function hr(...values: HValues[]): VElement;
export declare function i(...values: HValues[]): VElement;
export declare function iframe(...values: HValues[]): VElement;
export declare function img(...values: HValues[]): VElement;
export declare function input(...values: HValues[]): VElement;
export declare function ins(...values: HValues[]): VElement;
export declare function kbd(...values: HValues[]): VElement;
export declare function label(...values: HValues[]): VElement;
export declare function legend(...values: HValues[]): VElement;
export declare function li(...values: HValues[]): VElement;
export declare function main(...values: HValues[]): VElement;
export declare function map(...values: HValues[]): VElement;
export declare function mark(...values: HValues[]): VElement;
export declare function menu(...values: HValues[]): VElement;
export declare function menuitem(...values: HValues[]): VElement;
export declare function meter(...values: HValues[]): VElement;
export declare function nav(...values: HValues[]): VElement;
export declare function object(...values: HValues[]): VElement;
export declare function ol(...values: HValues[]): VElement;
export declare function optgroup(...values: HValues[]): VElement;
export declare function option(...values: HValues[]): VElement;
export declare function output(...values: HValues[]): VElement;
export declare function p(...values: HValues[]): VElement;
export declare function param(...values: HValues[]): VElement;
export declare function pre(...values: HValues[]): VElement;
export declare function progress(...values: HValues[]): VElement;
export declare function q(...values: HValues[]): VElement;
export declare function rp(...values: HValues[]): VElement;
export declare function rt(...values: HValues[]): VElement;
export declare function rtc(...values: HValues[]): VElement;
export declare function ruby(...values: HValues[]): VElement;
export declare function s(...values: HValues[]): VElement;
export declare function samp(...values: HValues[]): VElement;
export declare function section(...values: HValues[]): VElement;
export declare function select(...values: HValues[]): VElement;
export declare function small(...values: HValues[]): VElement;
export declare function source(...values: HValues[]): VElement;
export declare function span(...values: HValues[]): VElement;
export declare function strong(...values: HValues[]): VElement;
export declare function sub(...values: HValues[]): VElement;
export declare function summary(...values: HValues[]): VElement;
export declare function sup(...values: HValues[]): VElement;
export declare function svg(...values: HValues[]): VElement;
export declare function table(...values: HValues[]): VElement;
export declare function tbody(...values: HValues[]): VElement;
export declare function td(...values: HValues[]): VElement;
export declare function textarea(...values: HValues[]): VElement;
export declare function tfoot(...values: HValues[]): VElement;
export declare function th(...values: HValues[]): VElement;
export declare function thead(...values: HValues[]): VElement;
export declare function time(...values: HValues[]): VElement;
export declare function tr(...values: HValues[]): VElement;
export declare function track(...values: HValues[]): VElement;
export declare function u(...values: HValues[]): VElement;
export declare function ul(...values: HValues[]): VElement;
export declare function video(...values: HValues[]): VElement;
export declare function vvar(...values: HValues[]): VElement;
export declare function wbr(...values: HValues[]): VElement;
export interface KnownHtmlAttributes {

@@ -113,0 +116,0 @@ accept?: string;

@@ -57,4 +57,6 @@ "use strict";

attrs = mergeAttrsMutate(attrs, head);
values = values.slice(1);
values.shift();
}
else if (head == null)
values.shift();
else

@@ -61,0 +63,0 @@ break;

@@ -10,2 +10,2 @@ export { Component } from './component';

export { mergeNestedAttrs, InputProps, DatabindProps, StringBinding, commandLink, inputText, inputNumber, inputValue, inputRange, radioGroup, RadioGroupProps, RadioOption, selector, getPropertyKey, PropertyRef, SelectorProps, SelectOption, numberToInputString, inputStringToNumber, InputEditorProps, getPropertyValue, setPropertyValue, getBoundValue, setBoundValue, checkbox, CheckProps, inputTextArea, getFriendlyName, prefixId } from './widgets';
export { h, HValue, HAttributes, mergeAttrs, a, abbr, address, area, article, aside, audio, b, bdi, bdo, blockquote, br, button, canvas, caption, cite, code, col, colgroup, data, datalist, dd, del, details, dfn, dialog, div, dl, dt, em, embed, fieldset, figcaption, figure, footer, form, h1, h2, h3, h4, h5, h6, header, hr, i, iframe, img, input, ins, kbd, label, legend, li, main, map, mark, menu, menuitem, meter, nav, object, ol, optgroup, option, output, p, param, pre, progress, q, rp, rt, rtc, ruby, s, samp, section, select, small, source, span, strong, sub, summary, sup, svg, table, tbody, td, textarea, tfoot, th, thead, time, tr, track, u, ul, video, vvar, wbr } from './html';
export { h, HValue, HValues, HAttributes, mergeAttrs, a, abbr, address, area, article, aside, audio, b, bdi, bdo, blockquote, br, button, canvas, caption, cite, code, col, colgroup, data, datalist, dd, del, details, dfn, dialog, div, dl, dt, em, embed, fieldset, figcaption, figure, footer, form, h1, h2, h3, h4, h5, h6, header, hr, i, iframe, img, input, ins, kbd, label, legend, li, main, map, mark, menu, menuitem, meter, nav, object, ol, optgroup, option, output, p, param, pre, progress, q, rp, rt, rtc, ruby, s, samp, section, select, small, source, span, strong, sub, summary, sup, svg, table, tbody, td, textarea, tfoot, th, thead, time, tr, track, u, ul, video, vvar, wbr } from './html';

@@ -137,3 +137,3 @@ "use strict";

var id = exports.prefixId(props.prefix, exports.getPropertyKey(props.prop));
return (html_1.div({ id: id }, props.attrs, options.map(function (option) {
return (html_1.div.apply(void 0, [{ id: id }, props.attrs].concat(options.map(function (option) {
var checked = util_1.fuzzyEquals(option.value, exports.getBoundValue(props));

@@ -162,3 +162,3 @@ var optionId = id + "-" + option.value;

}, props.inputAttrs), html_1.label({ for: optionId }, props.labelAttrs, option.label), option.extraItem);
})));
}))));
}

@@ -165,0 +165,0 @@ exports.radioGroup = radioGroup;

{
"name": "solenya",
"version": "1.2.6",
"version": "1.2.7",
"author": "solenya",

@@ -5,0 +5,0 @@ "license": "MIT",

@@ -7,18 +7,15 @@ # Solenya

To manage complexity in a web application, we split it into modular chunks. It's helpful to think of common types of chunks, or "components", in terms of their statefulness:
Here's the [motivation](#motivation) for Solenya. But if you just want to learn it, you can skip that and just keep reading.
1) Objects with application state (i.e. a high level chunk of an application).
2) Pure functions that return a view (i.e. a stateless virtual dom node)
3) Objects with DOM state (i.e. essentially a web component)
Most web frameworks today focus on building components of type '2' and '3', but have a "figure it out yourself" stance when it comes to '1'. This lack of native support for type 1 components causes serious problems.
# Samples
The immediate strategy, which is really a lack of strategy, or upside-down strategy, is to use a type '3' component, an abstraction around an HTML DOM element, and then polute it with application logic. In code samples, and in small applications, we can get away with this dirty ad-hoc approach, but the approach doesn't scale.
* Live editable samples for learning solenya: https://stackblitz.com/edit/solenya-samples
* Same code as above, should you want to download from github & run locally: https://github.com/solenya-group/solenya-samples
* Live editable mix of solenya code snippets, experiments, and web apps: https://stackblitz.com/@solenya-group
* Github / npm supplemental solenya libraries: https://github.com/solenya-group
For this reason, many people eventually adopt the strategy of using a separate state management library. The problem here is that your type 1 component is fractured: there's the state management parts, the view parts, and then some boilerplate to connect the parts. Aside from being unpleasantly verbose, this hampers reusability.
# Contact
Solenya is designed for building high-level type '1' components. This means you can cleanly organise your application into meaningful, reusable, high-level chunks. So for example, you could have a component for a login, a component for a paged table, or a component for an address. And you can compose components to any scale: in fact your root component will represent your entire application.
Open a github issue, or email codingbenjamin@gmail.com.
Each component's view is a pure function of its state, so within each component we get a high degree of separation of the application logic/state and the view. In fact, for any solenya application, you can strip out its views, and the core structure of the application remains in tact. Writing a component means thinking about its state and state transitions first, and its views second. This approach makes solenya components innately serializable. So another way to think about solenya components is that they represent the serializable parts of your application, that you might want to load and save from and to local storage or the server. Anyway, time to see some code.
# First Code Sample

@@ -53,37 +50,21 @@

# Samples
# Dependencies
* Live Editable Code Samples: https://stackblitz.com/edit/solenya-samples
* Github Samples: https://github.com/solenya-group/solenya-samples
Solenya is small: see and understand the source code for yourself. Its power comes from its simplicity, composability, and integration with other great libraries.
# Comparison Table
In the following diagram, higher layers have a dependency on lower layers.
Solenya simplifies many aspects of writing a web application.
![solenya flow diagram](solenya-layers.png "Solenya Layers")
| What | Simple Way | Complicated Way |
|-|-|-|
| State Management | Intrinsic to design | Separate state manager library w/ tons of boilerplate
| Type Checking | Just use Typescript. Implicit testing, great tooling, and eased refactoring | Extra testing & tooling to compensate for not using static typing, and painful refactoring
| Rendering HTML | Just use typescript. No templating language required. You don't need a templating language if your programming language is expressive | Yet another templating language, with ad-hoc constructs reinventing language features for looping, conditionals, etc. lacking the consistency and generality of an actual programmming language. The root of the problem: embedding a programming language in structureless strings is inherently more complex than embedding structureless strings in a programming language.
| CSS | Just use typescript. Style with `typestyle`. (Yes, you can also still easily reference ordinary css.) | Unmanageable stylesheets, where you can't easily rename, refactor, parameterize, etc. The root of the problem is your styles are expressed in a language that's simplistic and excessively decoupled from your view.
| Paradigm | Use both functional and OO, using pure functions rather than side-effecting functions where possible | Only use the functional approach, even if it means turning walking into gymanastics. Reducers, higher-order-components, functional lensing, boilerplate
| Updating the DOM | Output a virtual DOM tree as a pure function of your object model | Manually manipulate the DOM on a case-by-case basis
| Serialization | Intrinsic to design. Time travel debugging, hot module reloading, transactions, undo/redo all use the same single mechanism | Separate serialization library w/ bridge code to components
| Async | Call any async function, then update component state synchronously | Either force synchronous actions where asynchronous actions are required, or force asynchronous actions when synchronous actions suffice (the latter is characteristic of functional reactive programming frameworks). |
| Configuration | None | Custom file types, global configuration settings |
The 3rd party libraries Solenya has a dependency on are:
# Integration with Existing Libraries
* `typestyle` is used to express css styles in typescript
* `class-validator` is used by the solenya validator
* `class-tranformer` is used to serialize solenya components
* `history` is used by the solenya router
* *web-animations (polyfill: `web-animations-js`) is used by the solenya-animation package, though you can also use any other 3rd party animation library
Solenya is small: see and understand the source code for yourself. Its power comes from its simplicity, and its integration as well as intended use with many other great libraries:
All dependencies between npm packages are **peer dependencies**.
* A virtual DOM based on Ultradom *(forked)*
* typestyle *(dependency)*
* typescript & reflect-metadata for reflection *(dependency)*
* class-tranformer for serialization *(dependency)*
* class-validator is used by solenya validation *(dependency)*
* mjackson/history is used by the solenya router *(dependency)*
* any animation API using vdom hooks *(as in samples)*
* any css framework like bootstrap *(as in samples)*
* webpack for hot reloading *(as in samples)*
* lodash for great utility functions like debouncing *(as in samples)*
`Solenya` works with all major browsers, including IE11 if you install the `es6-shim`.

@@ -94,9 +75,11 @@ # Installation

Depending on your npm setup, you may have to explicitly install the peer dependencies listed above.
# Table of Contents
- [Solenya](#solenya)
- [Samples](#samples)
- [Contact](#contact)
- [First Code Sample](#first-code-sample)
- [Samples](#samples)
- [Comparison Table](#comparison-table)
- [Integration with Existing Libraries](#integration-with-existing-libraries)
- [Dependencies](#dependencies)
- [Installation](#installation)

@@ -138,2 +121,7 @@ - [State, View and Updates](#state-view-and-updates)

* [Data Labels](#data-labels)
- [Merging Attributes](#merging-attributes)
- [Motivation](#motivation)
* [Simplicity](#Simplicity)
* [Everything expressed in a single, powerful language](#everything-expressed-in-a-single-powerful-language)
* [Intrinsic State Management](#intrinsic-state-management)
- [API Reference](#api-reference)

@@ -389,3 +377,3 @@ * [Component Class API](#component-class-api)

Minimially, all inputs will have an optional `attrs` type. More complex input types have many other properties. Some of these properties specify nested attribues. You can use the `mergeAttrs` and `mergeNestedAttrs` helper functions to merge attributes. `mergeNestedAttrs` takes several objects, scans for properties on those objects whose name ends with `attrs`, and then calls through to `mergeAttrs` to merge those attributes and styles. This makes it much easier to write reusable and chainable helper functions.
Minimially, all inputs will have an optional `attrs` type. More complex input types have many other properties, including nested attributes, which can be merged together as explained in the merging section.

@@ -794,3 +782,3 @@ In the above example, there's clearly boilerplate. In the next section, you'll notice you can easily write your own `inputUnit` higher-level function that generalizes the concept of an input with a label and validation.

Let's combine the concepts in the previous sections to shuffle an array, where each element gracefully moves to its new position each time the array is updated. We can use lodash's shuffle function to perform the `shuffle`, and our own `slideChildren` function to perform the animation. We'll need to make sure each item in the array has a unique `key`, so that the patcher knows to reuse each child element.
Let's combine the concepts in the previous sections to shuffle an array, where each element gracefully moves to its new position each time the array is updated. We can use lodash's shuffle function to perform the `shuffle`, and our own `transitionChildren` function to perform the animation. We'll need to make sure each item in the array has a unique `key`, so that the patcher knows to reuse each child element.

@@ -805,3 +793,3 @@ ```typescript

myButton ({ onclick: () => this.shuffle () }, "shuffle"),
ul (slideChildren(), this.items.map (n => li ({ key: n }, n)))
ul (transitionChildren(), this.items.map (n => li ({ key: n }, n)))
)

@@ -815,13 +803,13 @@ }

```
We can implement `slideChildren` using the [FLIP](https://aerotwist.com/blog/flip-your-animations/) technique:
We can implement `transitionChildren` using the [FLIP](https://aerotwist.com/blog/flip-your-animations/) technique:
```typescript
export function slideChildren () : VLifecycle
export function transitionChildren () : VLifecycle
{
return {
onBeforeUpdate (el) {
let els = el["state_slideChildren"] = Array.from(el.childNodes).map(c => (c as HTMLElement))
let els = el["state_transitionChildren"] = Array.from(el.childNodes).map(c => (c as HTMLElement))
els.forEach (c => measure(c))
},
onUpdated (el) {
let els = el["state_slideChildren"] as HTMLElement[]
let els = el["state_transitionChildren"] as HTMLElement[]
els.forEach (c => flip (c))

@@ -1034,2 +1022,109 @@ }

# Merging Attributes
Solenya provides merging functions to make it easier to write reusable and chainable helper functions.
By default, calling an element function prefixed with multiple attribute objects merges those attributes. For example:
```typescript
div ({x:1}, {y:2}) // this
div ({x:1, y:2}) // becomes this
```
You can also use the `mergeAttrs` and `mergeNestedAttrs` helper functions to explicitly merge attributes. `mergeNestedAttrs` takes several objects, scans for properties on those objects whose name ends with `attrs`, and then calls through to `mergeAttrs` to merge those attributes and styles.
Let's suppose we create a resuable `myInputText` that customises `inputText` as follows:
```typescript
export const myInputText = (props: InputEditorProps<string|undefined>) =>
inputText (mergeNestedAttrs (props, { attrs: {
type: "text",
class: "form-control"
}}))
```
Calling:
```typescript
myInputText ({target: this, prop: () => this.email, attrs: {
type: "email",
class: "special"
}})
````
Outputs:
```html
<input
type="email"
class="special form-control"
...
/>
```
Occasionally you'll get a merge collision. Solenya favors the attribute that comes first. This is the opposite behaviour of the spread operator, and for good reason: as a callee writing a reusable function you want the caller's attribute object to come first, take precedence, and drive type inference.
# Motivation
## Simplicity
*Simplicity* is a deeply important quality of code, and as such, has become a superlative in programming. Superlatives work on us because we naturally want to believe great things about ourselves: *my* code is simple. But of course, *your* code is complicated, and now simplicity is not objective, but subjective. This subjectivity is exacerbated by the restricted environment of the coding islands we live on. Of course code can be simple when it ignores critical concerns of a larger world.
But to abandon an objective meaning of 'simple' is to abandon being a good programmer, or to think so provincially that such meanings are never contemplated. Because the side-effects of complexity are costly code bases defended by programmers who's actual talent is politics.
Something is 'simple' if it's smaller. A system that has 1 thing in it is simpler than a system that has 2 things in it. Simplicity must be coupled with Occam's razor - that out of several *comparably powerful* alternatives, we should pick the simplest one.
Solenya is simple because it:
* Reduces the number or languages to get the job done
* Removes the need for an extra bolt-on state manager
without sacrificing any power.
## Everything expressed in a single, powerful language
Solenya, in part thanks to the excellent `typestyle` library, uses typescript to express everything, including HTML and CSS. This substantially reduces complexity.
![Language Interop Complexity](language-interop-complexity.png "Language Interop Complexity")
In comparison, most front end frameworks, despite putatively being "unified" development models, encourage development in 3 different languages: Javascript for application code, HTML for UI, and CSS for styling. This slows development down immeasurably, due to:
* Limited abstractions in the languages
* HTML and CSS are in reality used as impoverished unwieldy programming languages
* Limited interop between languages
* You can't for example parameterise some CSS style with an instance of a typescript class
* Using multiple of anything, when a single thing will do
* Especially when that thing is an entire language
Rather than addressing the root of the problem, populist solutions appeal to developer tradition, doubling down on the flawed approach with more ad-hoc abstractions. "New" slightly-less-impoverished languages are built on top of the impoverished languages. Yet-another-template language reinventing looping constructs, or a layer of top of CSS where we're thrilled we get a feature like... variables.
Another excuse for using 3 languages rather than 1 is the misnomer that this helps separate concerns. Separation of languages != separation of concerns. In fact, the worst thing you can do if you care about separating concerns is to attempt to do so with a language lacking abstractions that make such separations possible. This is why css code bases (and scss) are littered with repetition, with tooling-invisible two-way dependencies with their accompanying code and HTML.
### Static Typing
Solenya was built from the ground-up to take advantage of static typing.
Static typing gives you: the best possible testing for free, where the compiler constrains the possible values of your variables. Great tooling. Free documentation. It makes other people's code much easier to understand. And it makes your own code easier to understand as and when you refactor it.
It's easier to scale a large code base with static typing. It's why Facebook developed their own statically typed version of PHP. It's why Typescript exists. And the tax of static typing in modern languages is really low, thanks to type inference. There's increasingly few excuses for eschewing compile-time types!
### Embracing both OO and Functional Approaches
Typescript, as well as other languages like F#, do a brilliant job of leveraging both the OO and functional paradigms. Solenya, being written in and for Typescript, takes full advantage of this.
Unfortunately, some of the alternatives to the big frameworks are anti-OO frameworks. Their tenets? That state mutation is always wrong. That coupling functions and data is always wrong. Yet their own code demonstrates rampant DRY violations and convoluted higher-order write-only functions. You know, the functions that return functions that return functions that return functions, where oh, yes, well the 2nd innermost function actually did store state. Good luck debugging that.
## Intrinsic State Management
To manage complexity in a web application, we split it into modular chunks. It's helpful to think of common types of chunks, or "components", in terms of their statefulness:
1. Objects with application state (i.e. a high level chunk of an application).
2. Pure functions that return a view (i.e. a stateless virtual dom node)
3. Objects with DOM state (i.e. essentially a web component)
Most web frameworks today focus on building components of type '2' and '3', not type '1' components - but this causes serious problems.
The immediate strategy, which is really a lack of strategy, or upside-down strategy, is to use a type '3' component, an abstraction around an HTML DOM element, and then polute it with application logic. In code samples, and in small applications, we can get away with this dirty ad-hoc approach, but the approach doesn't scale.
For this reason, many people eventually adopt the strategy of using a separate state management library to get their type '1' components. But now you've got two separate component models to deal with and integrate.
Solenya is designed from the start for building high-level type '1' components. This means you can cleanly organise your application into meaningful, reusable, high-level chunks. So for example, you could have a component for a login, a component for a paged table, or a component for an address. And you can compose components to any scale: in fact your root component will represent your entire application.
Each component's view is a pure function of its state, so within each component we get a high degree of separation of the application logic/state and the view. In fact, for any solenya application, you can strip out its views, and the core structure of the application remains in tact. Writing a component means thinking about its state and state transitions first, and its views second. This approach makes solenya components innately serializable. So another way to think about solenya components is that they represent the serializable parts of your application, that you might want to load and save from and to local storage or the server.
# API Reference

@@ -1074,5 +1169,2 @@

updated (payload: any) : void
/** A convenient shortcut to update a component property; wraps property change in update */
updateProperty (payload: KeyValue)
```

@@ -1079,0 +1171,0 @@

import { createVElement, VElement, VAttributes, VNode, VLifecycle, isVElement, merge } from './dom'
import { combineLifecycles } from './lifecycle'
import { style, types } from 'typestyle'
import { NestedCSSProperties } from 'typestyle/lib/types'
export type HAttributeValue = undefined | string | number | ((ev:any) => any) | NestedCSSProperties
export interface HAttributes extends VAttributes, KnownHtmlAttributes {
[key: string] : any
[key: string] : HAttributeValue
}
export type HValue = VNode | HAttributes | null | undefined
export type HValue = VNode | HAttributes | VLifecycle | null | undefined
export type HValues = HValue | VNode[]
function typeStyleize (attrs?: HAttributes) {

@@ -39,3 +44,3 @@ if (attrs && typeof (attrs.style) === 'object') {

dominant = combineLifecycles (dominant, recessive)
dominant = <HAttributes> combineLifecycles (dominant, recessive)
dominant = <HAttributes> merge (dominant, recessive)

@@ -50,3 +55,3 @@

export function h (tag: string, ...values: HValue[]): VElement
export function h (tag: string, ...values: HValues[]): VElement
{

@@ -58,4 +63,6 @@ var attrs: HAttributes | undefined

attrs = mergeAttrsMutate (attrs, head)
values = values.slice(1)
values.shift()
}
else if (head == null)
values.shift()
else

@@ -68,403 +75,403 @@ break

export function a(...values: HValue[]) {
export function a(...values: HValues[]) {
return h("a", ...values)
}
export function abbr(...values: HValue[]) {
export function abbr(...values: HValues[]) {
return h("abbr", ...values)
}
export function address(...values: HValue[]) {
export function address(...values: HValues[]) {
return h("address", ...values)
}
export function area(...values: HValue[]) {
export function area(...values: HValues[]) {
return h("area", ...values)
}
export function article(...values: HValue[]) {
export function article(...values: HValues[]) {
return h("article", ...values)
}
export function aside(...values: HValue[]) {
export function aside(...values: HValues[]) {
return h("aside", ...values)
}
export function audio(...values: HValue[]) {
export function audio(...values: HValues[]) {
return h("audio", ...values)
}
export function b(...values: HValue[]) {
export function b(...values: HValues[]) {
return h("b", ...values)
}
export function bdi(...values: HValue[]) {
export function bdi(...values: HValues[]) {
return h("bdi", ...values)
}
export function bdo(...values: HValue[]) {
export function bdo(...values: HValues[]) {
return h("bdo", ...values)
}
export function blockquote(...values: HValue[]) {
export function blockquote(...values: HValues[]) {
return h("blockquote", ...values)
}
export function br(...values: HValue[]) {
export function br(...values: HValues[]) {
return h("br", ...values)
}
export function button(...values: HValue[]) {
export function button(...values: HValues[]) {
return h("button", ...values)
}
export function canvas(...values: HValue[]) {
export function canvas(...values: HValues[]) {
return h("canvas", ...values)
}
export function caption(...values: HValue[]) {
export function caption(...values: HValues[]) {
return h("caption", ...values)
}
export function cite(...values: HValue[]) {
export function cite(...values: HValues[]) {
return h("cite", ...values)
}
export function code(...values: HValue[]) {
export function code(...values: HValues[]) {
return h("code", ...values)
}
export function col(...values: HValue[]) {
export function col(...values: HValues[]) {
return h("col", ...values)
}
export function colgroup(...values: HValue[]) {
export function colgroup(...values: HValues[]) {
return h("colgroup", ...values)
}
export function data(...values: HValue[]) {
export function data(...values: HValues[]) {
return h("data", ...values)
}
export function datalist(...values: HValue[]) {
export function datalist(...values: HValues[]) {
return h("datalist", ...values)
}
export function dd(...values: HValue[]) {
export function dd(...values: HValues[]) {
return h("dd", ...values)
}
export function del(...values: HValue[]) {
export function del(...values: HValues[]) {
return h("del", ...values)
}
export function details(...values: HValue[]) {
export function details(...values: HValues[]) {
return h("details", ...values)
}
export function dfn(...values: HValue[]) {
export function dfn(...values: HValues[]) {
return h("dfn", ...values)
}
export function dialog(...values: HValue[]) {
export function dialog(...values: HValues[]) {
return h("dialog", ...values)
}
export function div(...values: HValue[]) {
export function div(...values: HValues[]) {
return h("div", ...values)
}
export function dl(...values: HValue[]) {
export function dl(...values: HValues[]) {
return h("dl", ...values)
}
export function dt(...values: HValue[]) {
export function dt(...values: HValues[]) {
return h("dt", ...values)
}
export function em(...values: HValue[]) {
export function em(...values: HValues[]) {
return h("em", ...values)
}
export function embed(...values: HValue[]) {
export function embed(...values: HValues[]) {
return h("embed", ...values)
}
export function fieldset(...values: HValue[]) {
export function fieldset(...values: HValues[]) {
return h("fieldset", ...values)
}
export function figcaption(...values: HValue[]) {
export function figcaption(...values: HValues[]) {
return h("figcaption", ...values)
}
export function figure(...values: HValue[]) {
export function figure(...values: HValues[]) {
return h("figure", ...values)
}
export function footer(...values: HValue[]) {
export function footer(...values: HValues[]) {
return h("footer", ...values)
}
export function form(...values: HValue[]) {
export function form(...values: HValues[]) {
return h("form", ...values)
}
export function h1(...values: HValue[]) {
export function h1(...values: HValues[]) {
return h("h1", ...values)
}
export function h2(...values: HValue[]) {
export function h2(...values: HValues[]) {
return h("h2", ...values)
}
export function h3(...values: HValue[]) {
export function h3(...values: HValues[]) {
return h("h3", ...values)
}
export function h4(...values: HValue[]) {
export function h4(...values: HValues[]) {
return h("h4", ...values)
}
export function h5(...values: HValue[]) {
export function h5(...values: HValues[]) {
return h("h5", ...values)
}
export function h6(...values: HValue[]) {
export function h6(...values: HValues[]) {
return h("h6", ...values)
}
export function header(...values: HValue[]) {
export function header(...values: HValues[]) {
return h("header", ...values)
}
export function hr(...values: HValue[]) {
export function hr(...values: HValues[]) {
return h("hr", ...values)
}
export function i(...values: HValue[]) {
export function i(...values: HValues[]) {
return h("i", ...values)
}
export function iframe(...values: HValue[]) {
export function iframe(...values: HValues[]) {
return h("iframe", ...values)
}
export function img(...values: HValue[]) {
export function img(...values: HValues[]) {
return h("img", ...values)
}
export function input(...values: HValue[]) {
export function input(...values: HValues[]) {
return h("input", ...values)
}
export function ins(...values: HValue[]) {
export function ins(...values: HValues[]) {
return h("ins", ...values)
}
export function kbd(...values: HValue[]) {
export function kbd(...values: HValues[]) {
return h("kbd", ...values)
}
export function label(...values: HValue[]) {
export function label(...values: HValues[]) {
return h("label", ...values)
}
export function legend(...values: HValue[]) {
export function legend(...values: HValues[]) {
return h("legend", ...values)
}
export function li(...values: HValue[]) {
export function li(...values: HValues[]) {
return h("li", ...values)
}
export function main(...values: HValue[]) {
export function main(...values: HValues[]) {
return h("main", ...values)
}
export function map(...values: HValue[]) {
export function map(...values: HValues[]) {
return h("map", ...values)
}
export function mark(...values: HValue[]) {
export function mark(...values: HValues[]) {
return h("mark", ...values)
}
export function menu(...values: HValue[]) {
export function menu(...values: HValues[]) {
return h("menu", ...values)
}
export function menuitem(...values: HValue[]) {
export function menuitem(...values: HValues[]) {
return h("menuitem", ...values)
}
export function meter(...values: HValue[]) {
export function meter(...values: HValues[]) {
return h("meter", ...values)
}
export function nav(...values: HValue[]) {
export function nav(...values: HValues[]) {
return h("nav", ...values)
}
export function object(...values: HValue[]) {
export function object(...values: HValues[]) {
return h("object", ...values)
}
export function ol(...values: HValue[]) {
export function ol(...values: HValues[]) {
return h("ol", ...values)
}
export function optgroup(...values: HValue[]) {
export function optgroup(...values: HValues[]) {
return h("optgroup", ...values)
}
export function option(...values: HValue[]) {
export function option(...values: HValues[]) {
return h("option", ...values)
}
export function output(...values: HValue[]) {
export function output(...values: HValues[]) {
return h("output", ...values)
}
export function p(...values: HValue[]) {
export function p(...values: HValues[]) {
return h("p", ...values)
}
export function param(...values: HValue[]) {
export function param(...values: HValues[]) {
return h("param", ...values)
}
export function pre(...values: HValue[]) {
export function pre(...values: HValues[]) {
return h("pre", ...values)
}
export function progress(...values: HValue[]) {
export function progress(...values: HValues[]) {
return h("progress", ...values)
}
export function q(...values: HValue[]) {
export function q(...values: HValues[]) {
return h("q", ...values)
}
export function rp(...values: HValue[]) {
export function rp(...values: HValues[]) {
return h("rp", ...values)
}
export function rt(...values: HValue[]) {
export function rt(...values: HValues[]) {
return h("rt", ...values)
}
export function rtc(...values: HValue[]) {
export function rtc(...values: HValues[]) {
return h("rtc", ...values)
}
export function ruby(...values: HValue[]) {
export function ruby(...values: HValues[]) {
return h("ruby", ...values)
}
export function s(...values: HValue[]) {
export function s(...values: HValues[]) {
return h("s", ...values)
}
export function samp(...values: HValue[]) {
export function samp(...values: HValues[]) {
return h("samp", ...values)
}
export function section(...values: HValue[]) {
export function section(...values: HValues[]) {
return h("section", ...values)
}
export function select(...values: HValue[]) {
export function select(...values: HValues[]) {
return h("select", ...values)
}
export function small(...values: HValue[]) {
export function small(...values: HValues[]) {
return h("small", ...values)
}
export function source(...values: HValue[]) {
export function source(...values: HValues[]) {
return h("source", ...values)
}
export function span(...values: HValue[]) {
export function span(...values: HValues[]) {
return h("span", ...values)
}
export function strong(...values: HValue[]) {
export function strong(...values: HValues[]) {
return h("strong", ...values)
}
export function sub(...values: HValue[]) {
export function sub(...values: HValues[]) {
return h("sub", ...values)
}
export function summary(...values: HValue[]) {
export function summary(...values: HValues[]) {
return h("summary", ...values)
}
export function sup(...values: HValue[]) {
export function sup(...values: HValues[]) {
return h("sup", ...values)
}
export function svg(...values: HValue[]) {
export function svg(...values: HValues[]) {
return h("svg", ...values)
}
export function table(...values: HValue[]) {
export function table(...values: HValues[]) {
return h("table", ...values)
}
export function tbody(...values: HValue[]) {
export function tbody(...values: HValues[]) {
return h("tbody", ...values)
}
export function td(...values: HValue[]) {
export function td(...values: HValues[]) {
return h("td", ...values)
}
export function textarea(...values: HValue[]) {
export function textarea(...values: HValues[]) {
return h("textarea", ...values)
}
export function tfoot(...values: HValue[]) {
export function tfoot(...values: HValues[]) {
return h("tfoot", ...values)
}
export function th(...values: HValue[]) {
export function th(...values: HValues[]) {
return h("th", ...values)
}
export function thead(...values: HValue[]) {
export function thead(...values: HValues[]) {
return h("thead", ...values)
}
export function time(...values: HValue[]) {
export function time(...values: HValues[]) {
return h("time", ...values)
}
export function tr(...values: HValue[]) {
export function tr(...values: HValues[]) {
return h("tr", ...values)
}
export function track(...values: HValue[]) {
export function track(...values: HValues[]) {
return h("track", ...values)
}
export function u(...values: HValue[]) {
export function u(...values: HValues[]) {
return h("u", ...values)
}
export function ul(...values: HValue[]) {
export function ul(...values: HValues[]) {
return h("ul", ...values)
}
export function video(...values: HValue[]) {
export function video(...values: HValues[]) {
return h("video", ...values)
}
export function vvar(...values: HValue[]) {
export function vvar(...values: HValues[]) {
return h("vvar", ...values)
}
export function wbr(...values: HValue[]) {
export function wbr(...values: HValues[]) {
return h("wbr", ...values)

@@ -471,0 +478,0 @@ }

@@ -13,4 +13,4 @@ export { Component } from './component'

export {
h, HValue, HAttributes, mergeAttrs,
h, HValue, HValues, HAttributes, mergeAttrs,
a,abbr,address,area,article,aside,audio,b,bdi,bdo,blockquote,br,button,canvas,caption,cite,code,col,colgroup,data,datalist,dd,del,details,dfn,dialog,div,dl,dt,em,embed,fieldset,figcaption,figure,footer,form,h1,h2,h3,h4,h5,h6,header,hr,i,iframe,img,input,ins,kbd,label,legend,li,main,map,mark,menu,menuitem,meter,nav,object,ol,optgroup,option,output,p,param,pre,progress,q,rp,rt,rtc,ruby,s,samp,section,select,small,source,span,strong,sub,summary,sup,svg,table,tbody,td,textarea,tfoot,th,thead,time,tr,track,u,ul,video,vvar,wbr
} from './html'

@@ -199,3 +199,3 @@ import { Component } from './component'

div ({ id: id }, props.attrs,
options.map(option => {
...options.map(option => {
const checked = fuzzyEquals (option.value, getBoundValue (props))

@@ -202,0 +202,0 @@ const optionId = id+"-"+option.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

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