Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified .DS_Store
Binary file not shown.
5 changes: 5 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
dist/

*.html
*.js
package-lock.json
5 changes: 5 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"trailingComma": "all",
"useTabs": true,
"tabWidth": 4
}
39 changes: 29 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,58 @@ A UI component set for the web.

## For developers

Wireframe is delivered as three files:
Wireframe exists as three files:

- A stylesheet containing all css components
- A javascript module exporting all web components
- A json file with template elements for SSR (strings)

All components are RTL (right-to-left) compatible.

## For designers

`Wireframe` is named after the process of drafting lo-fi user interfaces with pen and paper. It's also a reference to the polygon meshes found in graphics programming.

`Wireframe` is an aesthetically concise UI language. Components must differentiate themselves
from text and each other. Their functionality is telegraphed by their visual accent.

Creature comforts like shadows, gradients, and expanding circles ultimately are designed for
other designers (and promotions). They do nothing of signifigance for the user.

Consider `wireframe` a love letter to my former colleagues at Material Design.

## CSS components

A single css stylesheet includes the following components:

- button
- primary button
- destructive button
- checkbox
- meter
- number inputs
- number
- phone
- time
- date
- datetime-local
- number
- phone
- time
- date
- datetime-local
- progress
- radio
- slider
- switch
- textarea
- text inputs
- text
- password
- email
- url
- text
- password
- email
- url

- :focus ring

## Web components

The following web components are available:

- inline movement

## License
Expand Down
12 changes: 6 additions & 6 deletions bundle/src/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,23 @@

import * as fs from "fs";
import * as path from "path";
import { bundle } from 'lightningcss';
import { bundle } from "lightningcss";

let originCssPathInput = process.argv[2];
let targetCssPathInput = process.argv[3];

let cwd = process.cwd();

// odd way of handling this ../../../ for two dirs / and a file
let originCssPath = path.join(cwd, originCssPathInput);
let filename = path.join(cwd, originCssPathInput);
let targetCssPath = path.join(cwd, targetCssPathInput);

let { code, map } = bundle({
filename: originCssPath,
let { code } = bundle({
filename,
});

try {
fs.writeFileSync(targetCssPath, code);
fs.writeFileSync(targetCssPath, code);
} catch (err) {
console.error(err);
console.error(err);
}
1 change: 1 addition & 0 deletions bundle/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"types": ["node"],
"rootDir": "./src",
"outDir": "./dist"
}
Expand Down
1 change: 1 addition & 0 deletions components/src/component_templates.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
75 changes: 43 additions & 32 deletions components/src/inline_movement.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,19 @@
// https://developer.mozilla.org/en-US/docs/Web/Accessibility/Guides/Keyboard-navigable_JavaScript_widgets#using_tabindex

// correlates to start and end

// get bounding rectangle of first and last child
// determine directionality

export const shadowDom = `<slot></slot>`;
export const template = `<template>
${shadowDom}
<template>`;
// https://www.w3.org/WAI/ARIA/apg/patterns/toolbar/

let templateEl = document.createElement("template");
templateEl.setHTMLUnsafe(shadowDom);
templateEl.setHTMLUnsafe("<slot></slot>");

// You don't need a DSD template because interactivity needs JS.
// So a slot will load when the component will load.
//

export class InlineMovement extends HTMLElement {
#slot = getSlotElement(this);
#mapped = new WeakSet<EventTarget>(this.#slot?.assignedElements() ?? []);
#boundOnSlotChange = this.#onSlotChange.bind(this);
#boundOnClick = this.#onClick.bind(this);
#boundOnKey = this.#onKey.bind(this);
#computedStyle = window.getComputedStyle(this);
#slot = getSlotElement(this);
#mapped = new WeakSet<EventTarget>(this.#slot?.assignedElements() ?? []);

connectedCallback() {
this.#slot?.addEventListener("slotchange", this.#boundOnSlotChange);
Expand All @@ -39,10 +33,18 @@ export class InlineMovement extends HTMLElement {

#onKey(event: KeyboardEvent) {
if (event.defaultPrevented) return;
if (event.shiftKey) return;
if (event.shiftKey || event.altKey) return;

if (handleBigJumps(event, this.#slot)) return;
if (handleArrows(event, this.#slot, this.#mapped, this.#computedStyle)) return;
if (
handleArrows(
event,
this.#slot,
this.#mapped,
window.getComputedStyle(this),
)
)
return;
}

#onClick(event: PointerEvent) {
Expand All @@ -58,19 +60,13 @@ export class InlineMovement extends HTMLElement {
setNegativeTabIndices(this.#slot);
focusOnElement(node);
return;
};
}
}
}

function getSlotElement(el: HTMLElement): HTMLSlotElement | null {
let internals = el.attachInternals();
let ssr = null !== internals.shadowRoot;
let shadowRoot = internals.shadowRoot
? internals.shadowRoot
: el.attachShadow({ mode: "closed" });

if (!ssr)
shadowRoot.appendChild(document.importNode(templateEl.content, true));
let shadowRoot = el.attachShadow({ mode: "closed" });
shadowRoot.appendChild(templateEl.content.cloneNode(true));

return shadowRoot.querySelector("slot");
}
Expand All @@ -88,20 +84,28 @@ function focusOnElement(sibling: HTMLElement) {
sibling.focus();
}

function handleBigJumps(event: KeyboardEvent, slot: HTMLSlotElement | null): boolean {
function handleBigJumps(
event: KeyboardEvent,
slot: HTMLSlotElement | null,
): boolean {
if ("Home" !== event.key && "End" !== event.key) return false;

let bigJump = getFirstOrLast(event, slot);
if (bigJump instanceof HTMLElement) {
event.preventDefault();
setNegativeTabIndices(slot);
focusOnElement(bigJump);
event.preventDefault();
setNegativeTabIndices(slot);
focusOnElement(bigJump);
}

return true;
}

function handleArrows(event: KeyboardEvent, slot: HTMLSlotElement | null, mapped: WeakSet<EventTarget>, computedStyle: CSSStyleDeclaration) {
function handleArrows(
event: KeyboardEvent,
slot: HTMLSlotElement | null,
mapped: WeakSet<EventTarget>,
computedStyle: CSSStyleDeclaration,
) {
if (event.key !== "ArrowLeft" && event.key !== "ArrowRight") return false;

for (let node of event.composedPath()) {
Expand All @@ -120,15 +124,22 @@ function handleArrows(event: KeyboardEvent, slot: HTMLSlotElement | null, mapped
return true;
}

function getFirstOrLast(event: KeyboardEvent, slot: HTMLSlotElement | null): Element | undefined {
function getFirstOrLast(
event: KeyboardEvent,
slot: HTMLSlotElement | null,
): Element | undefined {
if (!slot) return;

let elements = slot.assignedElements();
if ("Home" === event.key) return elements[0];
if ("End" === event.key) return elements[elements.length - 1];
}

function getSibling(event: KeyboardEvent, node: EventTarget, computedStyle: CSSStyleDeclaration): Element | null | undefined {
function getSibling(
event: KeyboardEvent,
node: EventTarget,
computedStyle: CSSStyleDeclaration,
): Element | null | undefined {
if (!(node instanceof HTMLElement)) return;

let prev = node.previousElementSibling;
Expand Down
2 changes: 1 addition & 1 deletion components/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
"rootDir": "./src",
"outDir": "./dist"
}
}
}
113 changes: 0 additions & 113 deletions demo/css_component_demo/index.html

This file was deleted.

11 changes: 0 additions & 11 deletions demo/css_component_demo/mod.css

This file was deleted.

Loading