Releases: readymade-ui/readymade
3.1.0 The Bride Stripped Bare By Her Bachelors, Even
3.1.0
Readymade 3.1.0 The Bride Stripped Bare By Her Bachelors, Even breaks the glass, adding new features that allow UI controls to communicate over WebSocket, WebRTC Data Channel, and Touch OSC. This release also records a "Hello World" example at ~1Kb when built with Vite and esbuild.
@readymade/ui
- new:
RdDial
has similar interface toRdSlider
but action is limited to a rotary dial - new: documentation available at https://readymade-ui.github.io/readymade/#/lib
- feat:
RdControl
can now be set via attribute or viasetControl
method on all inputs in @readymade/ui - feat: provide CSS styles for
RdButton
viasetControl
. Any provided styles are bound to the internalHTMLButtonElement
@readymade/transmit
- feat:
Transmitter
is a newclass
for handlingWebRTC DataChannel
,WebSocket
andTouch OSC
communication.
Transmitter
is a Swiss-army knife for communicating over WebRTC DataChannel, WebSocket or Touch OSC.
Getting Started
npm install @readymade/transmit
yarn add @readymade/transmit
Import Transmitter
and instantiate with a configuration Object.
import { Transmitter, TransmitterConfig } from '@readymade/transmit';
const config: TransmitterConfig = {
sharedKey: 'lobby',
rtc: {
iceServers,
},
serverConfig: {
http: {
protocol: 'http',
hostname: 'localhost',
port: 4449,
},
ws: {
osc: {
protocol: 'ws',
hostname: 'localhost',
port: 4445,
},
signal: {
protocol: 'ws',
hostname: 'localhost',
port: 4446,
},
announce: {
protocol: 'ws',
hostname: 'localhost',
port: 4447,
},
message: {
protocol: 'ws',
hostname: 'localhost',
port: 4448,
},
},
},
onMessage,
onConnect,
}
const transmitter = new Transmitter(config);
Messages
When signal
and announce
servers are configured, the instance of Transmitter
will automatically attempt a handshake with a remote peer. If a peer is found, a WebRTC DataChannel peer to peer connection will open. To send a message over the data channel use the send
method.
transmitter.send({ message: 'ping' });
If you want to send messages over WebSocket, use sendSocketMessage
.
transmitter.sendSocketMessage({ message: 'ping' });
To send a message over TouchOSC, use sendTouchOSCMessage
, ensuring the data your are sending follows the OSC protocol. Below is an example of sending a OSC message with type definitions.
transmitter.sendTouchOSCMessage('/OSCQUERY/Left Controls/Flip H', [
{
type: 'i',
value: 1,
},
]);
To listen for messages, inject a callback into the configuration. In the above example, onMessage
would appear like so:
const onMessage = (message) => {
if (message.payload.event === 'ping') {
this.transmitter.send({ event: 'pong' });
}
};
To react to a peer to peer connection, bind an onConnect
callback to the configuration.
BREAKING CHANGES
RdControl
type definition in @readymade/ui has been updated to normalize types for all controls and make type definitions more specific per control. RdLegacyControl
is now exported which is the old type definition. The interface of all controls have been normalized, some properties are deprecated, while other shared properties are now moved to attributes
that are unique to each control.
Before
interface RdControl {
type: string;
name: string;
orient?: string;
min?: number | number[];
max?: number | number[];
isActive?: boolean;
placeSelf?: string;
transform?: string;
numberType?: 'int' | 'float';
}
After
interface RdControl<A> {
type?: string;
name: string;
isActive?: boolean;
hasUserInput?: boolean;
hasRemoteInput?: boolean;
currentValue?: number | string | Array<number> | Array<string> | boolean;
timeStamp?: Date | number;
attributes?: A;
}
For instance, in RdSlider
which is a custom element that has several unique attributes, the type definition is now:
interface RdSliderAttributes {
size?: string;
height?: number;
width?: number;
orient?: string;
min?: number | number[];
max?: number | number[];
position?: string;
x?: number;
y?: number;
snapToCenter?: boolean;
transform?: string;
numberType?: 'int' | 'float';
}
RdControl<RdSliderAttributes>;
The reason for this change is to support @readymade/transmit. Passing an event from custom element to BroadcastChannel
or any of the available channels in Transmitter
is much simpler when the API is normalized.
3.0.0 The Large Glass
Readymade 3.0.0 Large Glass brings project dependencies up to date, adds new features and introduces several bugfixes and enhancements.
@readymade/core
- new: class methods
get$
andgetAll$
shorthand forquerySelector
andquerySelectorAll
- new: class methods
wait$
andwaitAll$
wait for elements that match the selector to attach to DOM until match is made withPromise
like behavior. - new: basic Declarative Shadow DOM compatibility
- fix: possible issues with setting template and state
@readymade/dom
- fix: add
force
attribute toTemplateRepeater
to fix an issue where the repeated template would not append insideShadowDOM
- fix:
repeatr
could error when used inShadowDOM
@readymade/router
- feat: support for hash routing (experimental)
@readymade/ui
- new: configure joystick for int or float
- new: simulate a click on
RdButton
, making it controllable by another component - new:
RdButtonPad
displays a grid of buttons, delegates button events - new: add
channel
attribute set to the name of theBroadcastChannel
to pipe form control values to aBroadcastChannel
for dispatching to WebSocket, WebRTC, OSC - new: provide readymade-ui.css so users can get CSS Variables for styling components
- new:
RdRadioGroup
hasvertical
attribute which displays the group vertically instead of horizontally - fix:
RdButton
could display empty area where icon would be - fix:
RdButton
label was user-selectable, making touch devices hard to use - fix:
RdButton
was not dispatching submit event when type set to submit - fix:
RdSlider
positioning in iOS - fix: height scaled correctly for joystick
Project
- new: support SSR with vite
- new: upgrade cypress
- new: use yarn 4
BREAKING CHANGES
TemplateRepeater
TemplateRepeater
became unstable over time and no longer supports nested template bindings.
Where you had an example like this before:
<template id="object-repeater" items="item of items">
<ul class="is--large">
<li repeat="item" foo="{{item.index}}">{{item.title}}</li>
</ul>
</template>
the HTML should be updated so the HTML Template immediately wraps the content that is being looped over.
<ul class="is--large">
<template id="object-repeater" items="item of items">
<li repeat="item" foo="{{item.index}}">{{item.title}}</li>
</template>
</ul>
primr
primr
now scaffolds new projects with Vite 5 instead of parcel. Run npx primr my-app
to start a new Readymade project in a directory named my-app
.
Readymade UI
All CSS variables used to style Readymade UI Elements are now scoped. The stylesheet is now available in the root of the package.
Readymade is now built with a version of TypeScript that supports the proposed Decorator spec in ECMAScript. This project is still built with experimentalDecorators
so you shouldn't see any breaking changes until Readymade migrates to the new spec. The project is now built with typescript@~5.5.0
.
Readymade should support older versions of node>15
. The project is now built with node@20
and only actively tested with this version.
Legacy
This version of Readymade is named ofter the work of Marcel Duchamp, an installation named "The Bridge Stripped Bare By Her Bachelors, Even", often referred to as "The Large Glass". Considered by many one of Duchamp's finest works, art handlers dropped the installation, cracking the glass. When questioned about it, Marcel Duchamp said he liked the work even more now that it was cracked. The installation hangs in the Philadelphia Museum of Art.
2.0.0 Bicycle Wheel
- NEW @readymade/dom package includes a collection of readymade components that extend from native HTML elements
- NEW @readymade/router package features a client-side router for navigating between custom element based views
- NEW
Repeater
andTemplateRepeater
iterates over a data model and appends custom template to DOM - NEW ability to set Shadow DOM mode to 'open' or 'closed' in Component Decorator
- NEW
$state
property exposes component state, usegetState()
(or whatever method is bound toState
) as a best practice - NEW development and testing environment
- FIX performance related issues with using state
- FIX issues with state when custom elements are dynamically added to DOM
- FIX issue when using Readymade components with hot module reloading with Parcel
- FIX issues with server side rendering
BREAKING CHANGES
Several components that were previously exported from @readymade/core have been moved to the new @readymade/dom package. CustomElement
, PseudoElement
, and StructuralElement
remain in @readymade/core, while every other class is now exported from @readymade/dom. This change was made to cut down on library size when bundlers can't treeshake @readymade/core, as is the case with Parcel. Rollup and Webpack can treeshake @readymade/core. Another reason for this change is @skatejs/ssr, the only known package that can server-side Readymade components, can't interpret customized built-in elements and only supports components that extend from HTMLElement.
State will no longer automatically update after changing properties directly on the Component class. While this approach was convenient, it is much more performant not to track instances of the class but rather instances of state. State is now exposed as this.$state or by the getter used when declaring the @State decorator.
Several internal APIs were shifted around. Private APIs are prefixed with ɵ
. Public APIs are exposed with $
.
Readymade now requires node > 15.0.0 for server-side rendering due to EventTarget being shipped with the library.
Can works be made which are not 'of art'?
2.0.0-beta.0 contains several major improvements and changes from 1.2.0.
- NEW @readymade/dom package includes a collection of readymade components that extend from native HTML elements
- NEW @readymade/router package features a client-side router for navigating between custom element based views
- NEW Repeater and TemplateRepeater iterates over a data model and appends custom template to DOM
- NEW ability to set Shadow DOM mode to 'open' or 'closed' in Component Decorator
- NEW $state property exposes component state, use getState() (or whatever method is bound to State) as a best practice
- NEW development and testing environment
- FIX performance issues
- FIX issues with state when custom elements are dynamically added to DOM
BREAKING CHANGES
Several components that were previously exported from @readymade/core have been moved to the new @readymade/dom package. CustomElement, PseudoElement, and StructuralElement remain in @readymade/core, while every other class is now exported from @readymade/dom. This is to cut down on library size when bundlers can't treeshake @readymade/core, as is the case with Parcel. Rollup and Webpack should treeshake @readymade/core fine. Another reason for this change is @skatejs/ssr, the only known package that can server-side Readymade components, can't interpret anything but classes that extend from HTMLElement.
State will no longer automatically update after changing properties on the Component class. While this approach was convenient, it is much more performant not to track instances of the class but rather instances of state. State is now exposed as this.$state or by the getter used when declaring the @State decorator.
Several internal APIs were shifted around. Private APIs are prefixed with ɵ. Public APIs are exposed with $.
Releases from now on will include quotes from Marcel Duchamp.
1.2.0
1.1.1
- FIX issue that caused array values to not correctly update in some use cases
- ADD check for
no-attr
attribute on Elements to forego expensive change detection on attributes where not applicable
1.1.0
BREAKING CHANGES
This release introduces improvements to the Component interface and internal state. These changes may effect your usage of Readymade. Please read the following to understand how to update components built with Readymade.
- ADD automatic call to
customElements.define
in Component decorator - ADD
setState
now accepts string using dot, braket syntax to update deep values - FIX issues when updating state that is an Object
- FIX issues with updating state
Manual calls to customElements.define
are no longer required. Readymade will automatically call customElements.define
using the selector
property in the @Component
decorator.
To update to 1.1.0
:
npm install @readymade/core@^1.1.0
yarn upgrade @readymade/core@^1.1.0
For autonomous custom elements:
- Ensure the element has a
selector
defined in the@Component
decorator. - Remove any call to
customElements.define
in your code.
@Component({
selector: 'x-atom',
style: css`
:host {
display: flex;
}
`,
template: html`
<span>{{state}}</span>
`,
})
class AtomComponent extends CustomElement {
For customized built-in elements:
- Ensure the element has a
selector
defined in the@Component
decorator. - Ensure the element has a
custom
property defined in the@Component
decorator. - Remove any call to
customElements.define
in your code.
@Component({
selector: 'my-button',
custom: { extends: 'button'},
style: css`
:host {
cursor: pointer;
}
`,
template: html`
<span>{{model}}</span>
`,
})
class MyButtonComponent extends ButtonComponent {
IMPROVEMENTS
This release also fixes several issues when working with internal state.
Now its possible to define properties on state as Objects and Arrays.
export class TreeState {
public arrayModel = ['Node 1', 'Node 2', 'Node 3', 'Node 4', 'Node 5', 'Node 6', 'Node 7'];
public objectModel = {
foo: {
bar: {
baz: 'bbb',
},
},
};
}
After binding to state with the @State
decorator...
@State()
public getState() {
return new TreeState();
}
reference objects and arrays in the component's template
<x-node model="{{objectModel.foo.bar.baz}}"></x-node>
<x-node model="{{arrayModel[0]}}"></x-node>
and update deeply nested objects with setState
.
this.setState('objectModel.foo.bar', { baz: 'foo' } );
This represents a substantial improvement over the state mechanisms introduced in 1.0.0.
1.0.2
- FIX issues with server-side rendering components
1.0.1
- FIX issue that caused styles to display null in Dev Tools when style wasn't specified