├── css
├── components
│ ├── Flow.css
│ ├── Comment.css
│ ├── Image.css
│ ├── Grid.css
│ ├── Line.css
│ ├── Clone.css
│ ├── Go.css
│ ├── Spread.css
│ ├── Cluster.css
│ ├── Box.css
│ ├── Screen.css
│ ├── Sidebar.css
│ ├── Stack.css
│ ├── Center.css
│ ├── Textarea.css
│ ├── Input.css
│ ├── Select.css
│ ├── Text.css
│ ├── Checkbox.css
│ ├── Drawer.css
│ ├── Radios.css
│ └── Progress.css
├── lib
│ ├── utilities.css
│ ├── variables.css
│ └── base.css
└── styles.css
├── docs
├── css
│ ├── components
│ │ ├── Flow.css
│ │ ├── Comment.css
│ │ ├── Image.css
│ │ ├── Grid.css
│ │ ├── Line.css
│ │ ├── Clone.css
│ │ ├── Go.css
│ │ ├── Spread.css
│ │ ├── Cluster.css
│ │ ├── Box.css
│ │ ├── Screen.css
│ │ ├── Sidebar.css
│ │ ├── Stack.css
│ │ ├── Center.css
│ │ ├── Textarea.css
│ │ ├── Input.css
│ │ ├── Select.css
│ │ ├── Text.css
│ │ ├── Checkbox.css
│ │ ├── Drawer.css
│ │ ├── Radios.css
│ │ └── Progress.css
│ ├── lib
│ │ ├── utilities.css
│ │ ├── variables.css
│ │ └── base.css
│ └── styles.css
├── js
│ ├── utilities
│ │ ├── textSample.test.js
│ │ ├── ratioHeight.js
│ │ ├── ratioHeight.test.js
│ │ ├── separateNodes.js
│ │ ├── rangeToNum.js
│ │ ├── rangeToNum.test.js
│ │ ├── wordsSample.test.js
│ │ ├── dataFromForm.js
│ │ ├── actions.js
│ │ ├── parser.js
│ │ ├── wordsSample.js
│ │ └── textSample.js
│ ├── data.js
│ ├── components
│ │ ├── Text.js
│ │ ├── Clone.js
│ │ ├── Input.js
│ │ ├── Textarea.js
│ │ ├── Go.js
│ │ ├── Center.js
│ │ ├── Checkbox.js
│ │ ├── Output.js
│ │ ├── Progress.js
│ │ ├── Screen.js
│ │ ├── Box.js
│ │ ├── Words.js
│ │ ├── Grid.js
│ │ ├── Select.js
│ │ ├── Icon.js
│ │ ├── Cluster.js
│ │ ├── Radios.js
│ │ ├── Spread.js
│ │ ├── Model.js
│ │ ├── Sidebar.js
│ │ ├── Image.js
│ │ ├── Stack.js
│ │ ├── Drawer.js
│ │ ├── Line.js
│ │ ├── Comment.js
│ │ └── Flow.js
│ ├── houdini
│ │ └── image-cross.js
│ └── app.js
├── icons
│ ├── tick.svg
│ ├── cross.svg
│ ├── arrow-left.svg
│ ├── arrow-right.svg
│ ├── plus.svg
│ └── triangle-down.svg
└── index.html
├── js
├── utilities
│ ├── textSample.test.js
│ ├── ratioHeight.js
│ ├── ratioHeight.test.js
│ ├── separateNodes.js
│ ├── rangeToNum.js
│ ├── rangeToNum.test.js
│ ├── wordsSample.test.js
│ ├── dataFromForm.js
│ ├── actions.js
│ ├── parser.js
│ ├── wordsSample.js
│ └── textSample.js
├── data.js
├── components
│ ├── Text.js
│ ├── Center.js
│ ├── Clone.js
│ ├── Input.js
│ ├── Textarea.js
│ ├── Go.js
│ ├── Checkbox.js
│ ├── Output.js
│ ├── Progress.js
│ ├── Screen.js
│ ├── Box.js
│ ├── Words.js
│ ├── Grid.js
│ ├── Select.js
│ ├── Icon.js
│ ├── Cluster.js
│ ├── Radios.js
│ ├── Spread.js
│ ├── Model.js
│ ├── Sidebar.js
│ ├── Stack.js
│ ├── Image.js
│ ├── Drawer.js
│ ├── Line.js
│ ├── Comment.js
│ └── Flow.js
├── houdini
│ └── image-cross.js
└── app.js
├── logo.png
├── .babelrc
├── split_screen.png
├── icons
├── tick.svg
├── cross.svg
├── arrow-left.svg
├── arrow-right.svg
├── plus.svg
└── triangle-down.svg
├── index.html
├── package.json
├── logo.svg
├── .gitignore
├── demo.html
├── editor.html
└── README.md
/css/components/Flow.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/css/components/Comment.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/css/components/Image.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/css/components/Flow.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/css/components/Comment.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/css/components/Image.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/js/utilities/textSample.test.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/js/utilities/textSample.test.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/css/components/Grid.css:
--------------------------------------------------------------------------------
1 | g-rid {
2 | display: grid;
3 | }
--------------------------------------------------------------------------------
/css/components/Line.css:
--------------------------------------------------------------------------------
1 | l-ine {
2 | display: block;
3 | }
--------------------------------------------------------------------------------
/css/components/Clone.css:
--------------------------------------------------------------------------------
1 | c-lone {
2 | display: block;
3 | }
--------------------------------------------------------------------------------
/css/components/Go.css:
--------------------------------------------------------------------------------
1 | g-o {
2 | display: inline-block;
3 | }
--------------------------------------------------------------------------------
/css/components/Spread.css:
--------------------------------------------------------------------------------
1 | s-pread {
2 | display: block;
3 | }
--------------------------------------------------------------------------------
/docs/css/components/Grid.css:
--------------------------------------------------------------------------------
1 | g-rid {
2 | display: grid;
3 | }
--------------------------------------------------------------------------------
/docs/css/components/Line.css:
--------------------------------------------------------------------------------
1 | l-ine {
2 | display: block;
3 | }
--------------------------------------------------------------------------------
/css/components/Cluster.css:
--------------------------------------------------------------------------------
1 | c-luster {
2 | display: block;
3 | }
--------------------------------------------------------------------------------
/docs/css/components/Clone.css:
--------------------------------------------------------------------------------
1 | c-lone {
2 | display: block;
3 | }
--------------------------------------------------------------------------------
/docs/css/components/Go.css:
--------------------------------------------------------------------------------
1 | g-o {
2 | display: inline-block;
3 | }
--------------------------------------------------------------------------------
/docs/css/components/Spread.css:
--------------------------------------------------------------------------------
1 | s-pread {
2 | display: block;
3 | }
--------------------------------------------------------------------------------
/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Heydon/bruck/HEAD/logo.png
--------------------------------------------------------------------------------
/docs/css/components/Cluster.css:
--------------------------------------------------------------------------------
1 | c-luster {
2 | display: block;
3 | }
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "env"
4 | ],
5 | "plugins": []
6 | }
--------------------------------------------------------------------------------
/css/components/Box.css:
--------------------------------------------------------------------------------
1 | b-ox {
2 | display: block;
3 | overflow: hidden;
4 | }
--------------------------------------------------------------------------------
/split_screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Heydon/bruck/HEAD/split_screen.png
--------------------------------------------------------------------------------
/css/components/Screen.css:
--------------------------------------------------------------------------------
1 | s-creen {
2 | display: block;
3 | min-height: 100vh;
4 | }
--------------------------------------------------------------------------------
/css/components/Sidebar.css:
--------------------------------------------------------------------------------
1 | s-idebar {
2 | display: block;
3 | overflow: hidden;
4 | }
--------------------------------------------------------------------------------
/css/components/Stack.css:
--------------------------------------------------------------------------------
1 | s-tack {
2 | display: grid;
3 | align-content: start;
4 | }
--------------------------------------------------------------------------------
/docs/css/components/Box.css:
--------------------------------------------------------------------------------
1 | b-ox {
2 | display: block;
3 | overflow: hidden;
4 | }
--------------------------------------------------------------------------------
/docs/css/components/Screen.css:
--------------------------------------------------------------------------------
1 | s-creen {
2 | display: block;
3 | min-height: 100vh;
4 | }
--------------------------------------------------------------------------------
/docs/css/components/Sidebar.css:
--------------------------------------------------------------------------------
1 | s-idebar {
2 | display: block;
3 | overflow: hidden;
4 | }
--------------------------------------------------------------------------------
/docs/css/components/Stack.css:
--------------------------------------------------------------------------------
1 | s-tack {
2 | display: grid;
3 | align-content: start;
4 | }
--------------------------------------------------------------------------------
/css/components/Center.css:
--------------------------------------------------------------------------------
1 | c-enter {
2 | display: block;
3 | margin-left: auto;
4 | margin-right: auto;
5 | }
--------------------------------------------------------------------------------
/css/components/Textarea.css:
--------------------------------------------------------------------------------
1 | t-extarea textarea {
2 | width: 100%;
3 | min-height: calc(var(--s1) * 4);
4 | }
--------------------------------------------------------------------------------
/docs/css/components/Center.css:
--------------------------------------------------------------------------------
1 | c-enter {
2 | display: block;
3 | margin-left: auto;
4 | margin-right: auto;
5 | }
--------------------------------------------------------------------------------
/docs/css/components/Textarea.css:
--------------------------------------------------------------------------------
1 | t-extarea textarea {
2 | width: 100%;
3 | min-height: calc(var(--s1) * 4);
4 | }
--------------------------------------------------------------------------------
/icons/tick.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/css/components/Input.css:
--------------------------------------------------------------------------------
1 | i-nput {
2 | display: block;
3 | }
4 |
5 | i-nput input {
6 | margin-top: var(--s-4);
7 | width: 100%;
8 | }
--------------------------------------------------------------------------------
/docs/icons/tick.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/css/components/Input.css:
--------------------------------------------------------------------------------
1 | i-nput {
2 | display: block;
3 | }
4 |
5 | i-nput input {
6 | margin-top: var(--s-4);
7 | width: 100%;
8 | }
--------------------------------------------------------------------------------
/icons/cross.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/icons/cross.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/icons/arrow-left.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/icons/arrow-left.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/icons/arrow-right.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/icons/arrow-right.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/icons/plus.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/icons/plus.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/icons/triangle-down.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/js/utilities/ratioHeight.js:
--------------------------------------------------------------------------------
1 | export default function ratioHeight(r) {
2 | const nums = r.split(':').map(num => parseInt(num));
3 | return (nums[0] / nums[1]) * 100;
4 | }
--------------------------------------------------------------------------------
/docs/icons/triangle-down.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/js/utilities/ratioHeight.js:
--------------------------------------------------------------------------------
1 | export default function ratioHeight(r) {
2 | const nums = r.split(':').map(num => parseInt(num));
3 | return (nums[0] / nums[1]) * 100;
4 | }
--------------------------------------------------------------------------------
/js/utilities/ratioHeight.test.js:
--------------------------------------------------------------------------------
1 | import ratioHeight from './ratioHeight.js'
2 |
3 | test('returns ratio expressed as a percentage', () => {
4 | const ratio = ratioHeight('6:9');
5 | expect(ratio).toBeCloseTo(66.666);
6 | });
--------------------------------------------------------------------------------
/docs/js/utilities/ratioHeight.test.js:
--------------------------------------------------------------------------------
1 | import ratioHeight from './ratioHeight.js'
2 |
3 | test('returns ratio expressed as a percentage', () => {
4 | const ratio = ratioHeight('6:9');
5 | expect(ratio).toBeCloseTo(66.666);
6 | });
--------------------------------------------------------------------------------
/js/utilities/separateNodes.js:
--------------------------------------------------------------------------------
1 | export default function separateNodes(nodes, HTMLstring) {
2 | const elems = Array.from(nodes);
3 | elems.map((elem, i) => i > 0
4 | ? elem.insertAdjacentHTML('beforebegin', HTMLstring)
5 | : elem
6 | );
7 | }
--------------------------------------------------------------------------------
/docs/js/data.js:
--------------------------------------------------------------------------------
1 | export default {
2 | names: [
3 | {
4 | firstName: 'Heydon',
5 | lastName: 'Pickering'
6 | },
7 | {
8 | firstName: 'Hulk',
9 | lastName: 'Hogan'
10 | }
11 | ],
12 | thing: 'word'
13 | }
--------------------------------------------------------------------------------
/docs/js/utilities/separateNodes.js:
--------------------------------------------------------------------------------
1 | export default function separateNodes(nodes, HTMLstring) {
2 | const elems = Array.from(nodes);
3 | elems.map((elem, i) => i > 0
4 | ? elem.insertAdjacentHTML('beforebegin', HTMLstring)
5 | : elem
6 | );
7 | }
--------------------------------------------------------------------------------
/js/utilities/rangeToNum.js:
--------------------------------------------------------------------------------
1 | export default function rangeToNum(range) {
2 | if (!range.includes(',')) {
3 | return parseInt(range);
4 | }
5 | const rangeArr = range.split(',').map(i => parseInt(i));
6 | const num = Math.floor(Math.random() * (rangeArr[1] - rangeArr[0] + 1)) + rangeArr[0];
7 | return num;
8 | }
--------------------------------------------------------------------------------
/docs/js/utilities/rangeToNum.js:
--------------------------------------------------------------------------------
1 | export default function rangeToNum(range) {
2 | if (!range.includes(',')) {
3 | return parseInt(range);
4 | }
5 | const rangeArr = range.split(',').map(i => parseInt(i));
6 | const num = Math.floor(Math.random() * (rangeArr[1] - rangeArr[0] + 1)) + rangeArr[0];
7 | return num;
8 | }
--------------------------------------------------------------------------------
/js/data.js:
--------------------------------------------------------------------------------
1 | export default {
2 | names: [
3 | {
4 | firstName: 'Heydon',
5 | lastName: 'Pickering'
6 | },
7 | {
8 | firstName: 'Hulk',
9 | lastName: 'Hogan'
10 | },
11 | {
12 | firstName: 'Lara',
13 | lastName: 'Hogan'
14 | },
15 | {
16 | firstName: 'Paul',
17 | lastName: 'Hogan'
18 | }
19 | ]
20 | }
--------------------------------------------------------------------------------
/js/utilities/rangeToNum.test.js:
--------------------------------------------------------------------------------
1 | import rangeToNum from './rangeToNum.js'
2 |
3 | test('returns number between two other numbers (inclusive)', () => {
4 | const num = rangeToNum('2,8');
5 | expect(num).toBeLessThan(9);
6 | expect(num).toBeGreaterThan(1);
7 | });
8 |
9 | test('returns number', () => {
10 | const num = rangeToNum('8');
11 | expect(num).toBe(8);
12 | });
--------------------------------------------------------------------------------
/docs/js/utilities/rangeToNum.test.js:
--------------------------------------------------------------------------------
1 | import rangeToNum from './rangeToNum.js'
2 |
3 | test('returns number between two other numbers (inclusive)', () => {
4 | const num = rangeToNum('2,8');
5 | expect(num).toBeLessThan(9);
6 | expect(num).toBeGreaterThan(1);
7 | });
8 |
9 | test('returns number', () => {
10 | const num = rangeToNum('8');
11 | expect(num).toBe(8);
12 | });
--------------------------------------------------------------------------------
/js/components/Text.js:
--------------------------------------------------------------------------------
1 | // https://github.com/Heydon/bruck#t-ext
2 |
3 | import textSample from '../utilities/textSample.js';
4 |
5 | export default class Text extends HTMLElement {
6 | constructor() {
7 | super();
8 | const range = this.getAttribute('words') || '15,20';
9 | const text = textSample(range);
10 | this.innerHTML = `
${text}
`;
11 | }
12 | }
13 |
14 | customElements.define('t-ext', Text);
--------------------------------------------------------------------------------
/docs/js/components/Text.js:
--------------------------------------------------------------------------------
1 | // https://github.com/Heydon/bruck#t-ext
2 |
3 | import textSample from '../utilities/textSample.js';
4 |
5 | export default class Text extends HTMLElement {
6 | constructor() {
7 | super();
8 | const range = this.getAttribute('words') || '15,20';
9 | const text = textSample(range);
10 | this.innerHTML = `${text}
`;
11 | }
12 | }
13 |
14 | customElements.define('t-ext', Text);
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Bruck
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/css/components/Select.css:
--------------------------------------------------------------------------------
1 | s-elect {
2 | display: block;
3 | }
4 |
5 | .s-elect-wrap {
6 | position: relative;
7 | }
8 |
9 | s-elect select {
10 | -webkit-appearance: none;
11 | -moz-appearance: none;
12 | appearance: none;
13 | width: 100%;
14 | padding-right: 2rem;
15 | }
16 |
17 | s-elect i-con {
18 | position: absolute;
19 | right: 0.5rem;
20 | top: 50%;
21 | transform: translateY(-50%);
22 | pointer-events: none;
23 | }
24 |
25 |
--------------------------------------------------------------------------------
/js/utilities/wordsSample.test.js:
--------------------------------------------------------------------------------
1 | import wordsSample from './wordsSample.js'
2 |
3 | test('returns an array', () => {
4 | const sample = wordsSample('10,20');
5 | expect(Array.isArray(sample)).toBe(true);
6 | });
7 |
8 | test('returned array length to be between 10 and 20', () => {
9 | const sample = wordsSample('10,20');
10 | console.log(sample.length);
11 | expect(sample.length).toBeLessThan(21);
12 | expect(sample.length).toBeGreaterThan(9);
13 | });
--------------------------------------------------------------------------------
/css/lib/utilities.css:
--------------------------------------------------------------------------------
1 | /* Invert the colors of the component or element */
2 | .u-invert {
3 | filter: invert(100%);
4 | background-color: var(--color-light);
5 | }
6 |
7 | /* text alignment (affects children too) */
8 | .u-text-center {
9 | text-align: center;
10 | }
11 |
12 | .u-text-left {
13 | text-align: left;
14 | }
15 |
16 | .u-text-right {
17 | text-align: right;
18 | }
19 |
20 | /* rounded edges */
21 | .u-rounded {
22 | border-radius: 50%;
23 | }
--------------------------------------------------------------------------------
/docs/css/components/Select.css:
--------------------------------------------------------------------------------
1 | s-elect {
2 | display: block;
3 | }
4 |
5 | .s-elect-wrap {
6 | position: relative;
7 | }
8 |
9 | s-elect select {
10 | -webkit-appearance: none;
11 | -moz-appearance: none;
12 | appearance: none;
13 | width: 100%;
14 | padding-right: 2rem;
15 | }
16 |
17 | s-elect i-con {
18 | position: absolute;
19 | right: 0.5rem;
20 | top: 50%;
21 | transform: translateY(-50%);
22 | pointer-events: none;
23 | }
24 |
25 |
--------------------------------------------------------------------------------
/docs/js/utilities/wordsSample.test.js:
--------------------------------------------------------------------------------
1 | import wordsSample from './wordsSample.js'
2 |
3 | test('returns an array', () => {
4 | const sample = wordsSample('10,20');
5 | expect(Array.isArray(sample)).toBe(true);
6 | });
7 |
8 | test('returned array length to be between 10 and 20', () => {
9 | const sample = wordsSample('10,20');
10 | console.log(sample.length);
11 | expect(sample.length).toBeLessThan(21);
12 | expect(sample.length).toBeGreaterThan(9);
13 | });
--------------------------------------------------------------------------------
/docs/css/lib/utilities.css:
--------------------------------------------------------------------------------
1 | /* Invert the colors of the component or element */
2 | .u-invert {
3 | filter: invert(100%);
4 | background-color: var(--color-light);
5 | }
6 |
7 | /* text alignment (affects children too) */
8 | .u-text-center {
9 | text-align: center;
10 | }
11 |
12 | .u-text-left {
13 | text-align: left;
14 | }
15 |
16 | .u-text-right {
17 | text-align: right;
18 | }
19 |
20 | /* rounded edges */
21 | .u-rounded {
22 | border-radius: 50%;
23 | }
--------------------------------------------------------------------------------
/css/components/Text.css:
--------------------------------------------------------------------------------
1 | t-ext {
2 | display: block;
3 | }
4 |
5 | t-ext span {
6 | display: inline-block;
7 | color: transparent;
8 | position: relative;
9 | pointer-events: none;
10 | }
11 |
12 | t-ext span::before {
13 | content: '';
14 | position: absolute;
15 | left: 0;
16 | right: 0;
17 | top: calc(50% - (var(--border-thin) / 2));
18 | bottom: calc(50% - (var(--border-thin) / 2));
19 | background-color: var(--color-dark);
20 | pointer-events: none;
21 | }
--------------------------------------------------------------------------------
/docs/css/components/Text.css:
--------------------------------------------------------------------------------
1 | t-ext {
2 | display: block;
3 | }
4 |
5 | t-ext span {
6 | display: inline-block;
7 | color: transparent;
8 | position: relative;
9 | pointer-events: none;
10 | }
11 |
12 | t-ext span::before {
13 | content: '';
14 | position: absolute;
15 | left: 0;
16 | right: 0;
17 | top: calc(50% - (var(--border-thin) / 2));
18 | bottom: calc(50% - (var(--border-thin) / 2));
19 | background-color: var(--color-dark);
20 | pointer-events: none;
21 | }
--------------------------------------------------------------------------------
/css/components/Checkbox.css:
--------------------------------------------------------------------------------
1 | c-heckbox .checkbox-check {
2 | display: inline-block;
3 | width: 1.5rem;
4 | height: 1.5rem;
5 | line-height: 1.25;
6 | border: var(--border-thin) solid;
7 | text-align: center;
8 | }
9 |
10 | c-heckbox i-con {
11 | visibility: hidden;
12 | }
13 |
14 | c-heckbox svg {
15 | vertical-align: 0;
16 | }
17 |
18 | c-heckbox :focus + .checkbox-label .checkbox-check {
19 | outline: var(--outline);
20 | }
21 |
22 | c-heckbox :checked + .checkbox-label i-con {
23 | visibility: visible;
24 | }
--------------------------------------------------------------------------------
/docs/css/components/Checkbox.css:
--------------------------------------------------------------------------------
1 | c-heckbox .checkbox-check {
2 | display: inline-block;
3 | width: 1.5rem;
4 | height: 1.5rem;
5 | line-height: 1.25;
6 | border: var(--border-thin) solid;
7 | text-align: center;
8 | }
9 |
10 | c-heckbox i-con {
11 | visibility: hidden;
12 | }
13 |
14 | c-heckbox svg {
15 | vertical-align: 0;
16 | }
17 |
18 | c-heckbox :focus + .checkbox-label .checkbox-check {
19 | outline: var(--outline);
20 | }
21 |
22 | c-heckbox :checked + .checkbox-label i-con {
23 | visibility: visible;
24 | }
--------------------------------------------------------------------------------
/css/components/Drawer.css:
--------------------------------------------------------------------------------
1 | d-rawer {
2 | display: block;
3 | padding: var(--s1);
4 | border-width: var(--border-thin);
5 | }
6 |
7 | d-rawer .handle {
8 | all: inherit;
9 | font-size: var(--s1);
10 | width: 100%;
11 | display: flex;
12 | justify-content: space-between;
13 | }
14 |
15 | d-rawer .handle:focus {
16 | outline: var(--outline);
17 | }
18 |
19 | d-rawer .content {
20 | margin-top: var(--s1);
21 | }
22 |
23 | d-rawer .handle[aria-expanded="true"] .v {
24 | display: none;
25 | }
26 |
27 | d-rawer + d-rawer {
28 | border-top: 0;
29 | }
--------------------------------------------------------------------------------
/docs/css/components/Drawer.css:
--------------------------------------------------------------------------------
1 | d-rawer {
2 | display: block;
3 | padding: var(--s1);
4 | border-width: var(--border-thin);
5 | }
6 |
7 | d-rawer .handle {
8 | all: inherit;
9 | font-size: var(--s1);
10 | width: 100%;
11 | display: flex;
12 | justify-content: space-between;
13 | }
14 |
15 | d-rawer .handle:focus {
16 | outline: var(--outline);
17 | }
18 |
19 | d-rawer .content {
20 | margin-top: var(--s1);
21 | }
22 |
23 | d-rawer .handle[aria-expanded="true"] .v {
24 | display: none;
25 | }
26 |
27 | d-rawer + d-rawer {
28 | border-top: 0;
29 | }
--------------------------------------------------------------------------------
/js/utilities/dataFromForm.js:
--------------------------------------------------------------------------------
1 | export default function dataFromForm(form) {
2 | const data = new FormData(form);
3 | const values = {};
4 | for (let [key, value] of data.entries()) {
5 | let proxy = document.createElement('span');
6 | proxy.innerHTML = value;
7 | let text = proxy.textContent;
8 | if (values[key]) {
9 | if (!(values[key] instanceof Array)) {
10 | values[key] = new Array(values[key]);
11 | }
12 | values[key].push(text);
13 | } else {
14 | values[key] = text;
15 | }
16 | }
17 | return values;
18 | }
--------------------------------------------------------------------------------
/docs/js/utilities/dataFromForm.js:
--------------------------------------------------------------------------------
1 | export default function dataFromForm(form) {
2 | const data = new FormData(form);
3 | const values = {};
4 | for (let [key, value] of data.entries()) {
5 | let proxy = document.createElement('span');
6 | proxy.innerHTML = value;
7 | let text = proxy.textContent;
8 | if (values[key]) {
9 | if (!(values[key] instanceof Array)) {
10 | values[key] = new Array(values[key]);
11 | }
12 | values[key].push(text);
13 | } else {
14 | values[key] = text;
15 | }
16 | }
17 | return values;
18 | }
--------------------------------------------------------------------------------
/js/houdini/image-cross.js:
--------------------------------------------------------------------------------
1 | class CrossPainter {
2 | static get inputProperties() {
3 | return ['--border-thin', '--color-dark'];
4 | }
5 |
6 | paint(ctx, size, props) {
7 | ctx.lineWidth = props.get('--border-thin').value;
8 | ctx.strokeStyle = props.get('--color-dark').toString();
9 | ctx.beginPath();
10 | ctx.moveTo(0, 0);
11 | ctx.lineTo(size.width, size.height);
12 | ctx.stroke();
13 | ctx.beginPath();
14 | ctx.moveTo(size.width, 0);
15 | ctx.lineTo(0, size.height);
16 | ctx.stroke();
17 | }
18 | }
19 |
20 | registerPaint('image-cross', CrossPainter);
--------------------------------------------------------------------------------
/docs/js/houdini/image-cross.js:
--------------------------------------------------------------------------------
1 | class CrossPainter {
2 | static get inputProperties() {
3 | return ['--border-thin', '--color-dark'];
4 | }
5 |
6 | paint(ctx, size, props) {
7 | ctx.lineWidth = props.get('--border-thin').value;
8 | ctx.strokeStyle = props.get('--color-dark').toString();
9 | ctx.beginPath();
10 | ctx.moveTo(0, 0);
11 | ctx.lineTo(size.width, size.height);
12 | ctx.stroke();
13 | ctx.beginPath();
14 | ctx.moveTo(size.width, 0);
15 | ctx.lineTo(0, size.height);
16 | ctx.stroke();
17 | }
18 | }
19 |
20 | registerPaint('image-cross', CrossPainter);
--------------------------------------------------------------------------------
/css/components/Radios.css:
--------------------------------------------------------------------------------
1 | r-adios label {
2 | font-weight: normal;
3 | }
4 |
5 | r-adios label + label {
6 | margin-top: var(--s-1);
7 | margin-bottom: 0;
8 | }
9 |
10 | r-adios .radio-radio {
11 | display: inline-block;
12 | width: 1.5rem;
13 | height: 1.5rem;
14 | border: var(--border-thin) solid;
15 | border-radius: 50%;
16 | vertical-align: middle;
17 | }
18 |
19 | r-adios :focus + .radio-label .radio-radio {
20 | outline: var(--outline);
21 | }
22 |
23 | r-adios :checked + .radio-label .radio-radio {
24 | background-color: var(--color-dark);
25 | box-shadow: inset 0 0 0 0.25rem var(--color-light);
26 | }
--------------------------------------------------------------------------------
/docs/css/components/Radios.css:
--------------------------------------------------------------------------------
1 | r-adios label {
2 | font-weight: normal;
3 | }
4 |
5 | r-adios label + label {
6 | margin-top: var(--s-1);
7 | margin-bottom: 0;
8 | }
9 |
10 | r-adios .radio-radio {
11 | display: inline-block;
12 | width: 1.5rem;
13 | height: 1.5rem;
14 | border: var(--border-thin) solid;
15 | border-radius: 50%;
16 | vertical-align: middle;
17 | }
18 |
19 | r-adios :focus + .radio-label .radio-radio {
20 | outline: var(--outline);
21 | }
22 |
23 | r-adios :checked + .radio-label .radio-radio {
24 | background-color: var(--color-dark);
25 | box-shadow: inset 0 0 0 0.25rem var(--color-light);
26 | }
--------------------------------------------------------------------------------
/js/components/Center.js:
--------------------------------------------------------------------------------
1 | // https://github.com/Heydon/bruck#c-enter
2 |
3 | export default class Center extends HTMLElement {
4 | constructor() {
5 | super();
6 | this.maxWidth = this.getAttribute('maxWidth') || 'var(--measure)';
7 |
8 | const tmpl = document.createElement('template');
9 | tmpl.innerHTML = `
10 |
15 |
16 | `;
17 |
18 | this.attachShadow({ mode: 'open' });
19 | this.shadowRoot.appendChild(tmpl.content.cloneNode(true));
20 | }
21 | }
22 |
23 | customElements.define('c-enter', Center);
--------------------------------------------------------------------------------
/js/components/Clone.js:
--------------------------------------------------------------------------------
1 | // https://github.com/Heydon/bruck#c-lone
2 |
3 | export default class Clone extends HTMLElement {
4 | constructor() {
5 | super();
6 | this.of = this.getAttribute('of');
7 | if (!this.of) {
8 | console.error('Each element must have an `of` attribute pointing to a id.');
9 | return;
10 | }
11 | this.template = document.getElementById(this.of);
12 | Promise.all([
13 | customElements.whenDefined('g-rid'),
14 | customElements.whenDefined('s-tack')
15 | ]).then(() => {
16 | this.appendChild(this.template.content.cloneNode(true));
17 | });
18 | }
19 | }
20 |
21 | customElements.define('c-lone', Clone);
--------------------------------------------------------------------------------
/docs/js/components/Clone.js:
--------------------------------------------------------------------------------
1 | // https://github.com/Heydon/bruck#c-lone
2 |
3 | export default class Clone extends HTMLElement {
4 | constructor() {
5 | super();
6 | this.of = this.getAttribute('of');
7 | if (!this.of) {
8 | console.error('Each element must have an `of` attribute pointing to a id.');
9 | return;
10 | }
11 | this.template = document.getElementById(this.of);
12 | Promise.all([
13 | customElements.whenDefined('g-rid'),
14 | customElements.whenDefined('s-tack')
15 | ]).then(() => {
16 | this.appendChild(this.template.content.cloneNode(true));
17 | });
18 | }
19 | }
20 |
21 | customElements.define('c-lone', Clone);
--------------------------------------------------------------------------------
/js/components/Input.js:
--------------------------------------------------------------------------------
1 | // https://github.com/Heydon/bruck#i-nput
2 |
3 | export default class Input extends HTMLElement {
4 | constructor() {
5 | super();
6 | this.name = this.getAttribute('name');
7 | if (!this.name) {
8 | console.error('Each component must have a unique `name` attribute');
9 | return;
10 | }
11 | this.label = this.getAttribute('label') || 'Text';
12 | this.value = this.getAttribute('value') || null;
13 | this.innerHTML = `
14 |
15 |
16 | `;
17 | }
18 | }
19 |
20 | customElements.define('i-nput', Input);
--------------------------------------------------------------------------------
/docs/js/components/Input.js:
--------------------------------------------------------------------------------
1 | // https://github.com/Heydon/bruck#i-nput
2 |
3 | export default class Input extends HTMLElement {
4 | constructor() {
5 | super();
6 | this.name = this.getAttribute('name');
7 | if (!this.name) {
8 | console.error('Each component must have a unique `name` attribute');
9 | return;
10 | }
11 | this.label = this.getAttribute('label') || 'Text';
12 | this.value = this.getAttribute('value') || null;
13 | this.innerHTML = `
14 |
15 |
16 | `;
17 | }
18 | }
19 |
20 | customElements.define('i-nput', Input);
--------------------------------------------------------------------------------
/js/components/Textarea.js:
--------------------------------------------------------------------------------
1 | // https://github.com/Heydon/bruck#t-extarea
2 |
3 | export default class Textarea extends HTMLElement {
4 | constructor() {
5 | super();
6 | this.name = this.getAttribute('name');
7 | if (!this.name) {
8 | console.error('Each component must have a unique `name` attribute');
9 | return;
10 | }
11 | this.label = this.getAttribute('label') || 'Text box';
12 | this.value = this.getAttribute('value') || null;
13 | this.innerHTML = `
14 |
15 |
16 | `;
17 | }
18 | }
19 |
20 | customElements.define('t-extarea', Textarea);
--------------------------------------------------------------------------------
/docs/js/components/Textarea.js:
--------------------------------------------------------------------------------
1 | // https://github.com/Heydon/bruck#t-extarea
2 |
3 | export default class Textarea extends HTMLElement {
4 | constructor() {
5 | super();
6 | this.name = this.getAttribute('name');
7 | if (!this.name) {
8 | console.error('Each component must have a unique `name` attribute');
9 | return;
10 | }
11 | this.label = this.getAttribute('label') || 'Text box';
12 | this.value = this.getAttribute('value') || null;
13 | this.innerHTML = `
14 |
15 |
16 | `;
17 | }
18 | }
19 |
20 | customElements.define('t-extarea', Textarea);
--------------------------------------------------------------------------------
/css/styles.css:
--------------------------------------------------------------------------------
1 | /* lib */
2 | @import 'lib/variables.css';
3 | @import 'lib/base.css';
4 | @import 'lib/utilities.css';
5 |
6 | /* components */
7 | @import 'components/Image.css';
8 | @import 'components/Text.css';
9 | @import 'components/Box.css';
10 | @import 'components/Grid.css';
11 | @import 'components/Stack.css';
12 | @import 'components/Spread.css';
13 | @import 'components/Cluster.css';
14 | @import 'components/Center.css';
15 | @import 'components/Progress.css';
16 | @import 'components/Screen.css';
17 | @import 'components/Drawer.css';
18 | @import 'components/Go.css';
19 | @import 'components/Comment.css';
20 | @import 'components/Input.css';
21 | @import 'components/Textarea.css';
22 | @import 'components/Select.css';
23 | @import 'components/Radios.css';
24 | @import 'components/Checkbox.css';
--------------------------------------------------------------------------------
/docs/css/styles.css:
--------------------------------------------------------------------------------
1 | /* lib */
2 | @import 'lib/variables.css';
3 | @import 'lib/base.css';
4 | @import 'lib/utilities.css';
5 |
6 | /* components */
7 | @import 'components/Image.css';
8 | @import 'components/Text.css';
9 | @import 'components/Box.css';
10 | @import 'components/Grid.css';
11 | @import 'components/Stack.css';
12 | @import 'components/Spread.css';
13 | @import 'components/Cluster.css';
14 | @import 'components/Center.css';
15 | @import 'components/Progress.css';
16 | @import 'components/Screen.css';
17 | @import 'components/Drawer.css';
18 | @import 'components/Go.css';
19 | @import 'components/Comment.css';
20 | @import 'components/Input.css';
21 | @import 'components/Textarea.css';
22 | @import 'components/Select.css';
23 | @import 'components/Radios.css';
24 | @import 'components/Checkbox.css';
--------------------------------------------------------------------------------
/js/components/Go.js:
--------------------------------------------------------------------------------
1 | // https://github.com/Heydon/bruck#g-o
2 |
3 | export default class Go extends HTMLElement {
4 | constructor() {
5 | super();
6 | this.screenId = this.getAttribute('to');
7 | this.screen = document.getElementById(this.screenId);
8 |
9 | if (!this.screenId || !this.screen) {
10 | console.error('Each element needs a `to` attribute pointing to an existing element\'s `id`.');
11 | return;
12 | }
13 |
14 | const link = document.createElement('a');
15 | link.href = `#${this.screenId}`;
16 | link.classList.add('u-cta');
17 | link.innerHTML = this.innerHTML;
18 | link.innerHTML += `
19 |
20 | `;
21 | this.innerHTML = null;
22 | this.appendChild(link);
23 | }
24 | }
25 |
26 | customElements.define('g-o', Go);
--------------------------------------------------------------------------------
/docs/js/components/Go.js:
--------------------------------------------------------------------------------
1 | // https://github.com/Heydon/bruck#g-o
2 |
3 | export default class Go extends HTMLElement {
4 | constructor() {
5 | super();
6 | this.screenId = this.getAttribute('to');
7 | this.screen = document.getElementById(this.screenId);
8 |
9 | if (!this.screenId || !this.screen) {
10 | console.error('Each element needs a `to` attribute pointing to an existing element\'s `id`.');
11 | return;
12 | }
13 |
14 | const link = document.createElement('a');
15 | link.href = `#${this.screenId}`;
16 | link.classList.add('u-cta');
17 | link.innerHTML = this.innerHTML;
18 | link.innerHTML += `
19 |
20 | `;
21 | this.innerHTML = null;
22 | this.appendChild(link);
23 | }
24 | }
25 |
26 | customElements.define('g-o', Go);
--------------------------------------------------------------------------------
/docs/js/components/Center.js:
--------------------------------------------------------------------------------
1 | /*
2 | Usage:
3 |
4 | Child
5 | Child
6 |
7 |
8 | Attributes:
9 | - maxWidth: [CSS width value] (default: var(--measure))
10 | */
11 |
12 | export default class Center extends HTMLElement {
13 | constructor() {
14 | super();
15 | this.maxWidth = this.getAttribute('maxWidth') || 'var(--measure)';
16 |
17 | const tmpl = document.createElement('template');
18 | tmpl.innerHTML = `
19 |
24 |
25 | `;
26 |
27 | this.attachShadow({ mode: 'open' });
28 | this.shadowRoot.appendChild(tmpl.content.cloneNode(true));
29 | }
30 | }
31 |
32 | customElements.define('c-enter', Center);
--------------------------------------------------------------------------------
/js/utilities/actions.js:
--------------------------------------------------------------------------------
1 | export default {
2 | flowNext(trigger) {
3 | const flow = trigger.closest('f-low');
4 | if (flow) {
5 | flow.next();
6 | }
7 | },
8 | flowPrev(trigger) {
9 | const flow = trigger.closest('f-low');
10 | if (flow) {
11 | flow.prev();
12 | }
13 | },
14 | flowGoTo(trigger, index) {
15 | const flow = trigger.closest('f-low');
16 | if (flow && index > -1) {
17 | flow.goTo(index - 1);
18 | }
19 | },
20 | show(id) {
21 | const elem = document.getElementById(id);
22 | if (elem) {
23 | elem.hidden = false;
24 | }
25 | },
26 | Hide(id) {
27 | const elem = document.getElementById(id);
28 | if (elem) {
29 | elem.hidden = true;
30 | }
31 | },
32 | showHide(id) {
33 | const elem = document.getElementById(id);
34 | if (elem) {
35 | elem.hidden = !elem.hidden;
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/docs/js/utilities/actions.js:
--------------------------------------------------------------------------------
1 | export default {
2 | flowNext(trigger) {
3 | const flow = trigger.closest('f-low');
4 | if (flow) {
5 | flow.next();
6 | }
7 | },
8 | flowPrev(trigger) {
9 | const flow = trigger.closest('f-low');
10 | if (flow) {
11 | flow.prev();
12 | }
13 | },
14 | flowGoTo(trigger, index) {
15 | const flow = trigger.closest('f-low');
16 | if (flow && index > -1) {
17 | flow.goTo(index - 1);
18 | }
19 | },
20 | show(id) {
21 | const elem = document.getElementById(id);
22 | if (elem) {
23 | elem.hidden = false;
24 | }
25 | },
26 | Hide(id) {
27 | const elem = document.getElementById(id);
28 | if (elem) {
29 | elem.hidden = true;
30 | }
31 | },
32 | showHide(id) {
33 | const elem = document.getElementById(id);
34 | if (elem) {
35 | elem.hidden = !elem.hidden;
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/js/components/Checkbox.js:
--------------------------------------------------------------------------------
1 | // https://github.com/Heydon/bruck#c-heckbox
2 |
3 | export default class Checkbox extends HTMLElement {
4 | constructor() {
5 | super();
6 | this.name = this.getAttribute('name');
7 | if (!this.name) {
8 | console.error('Each component must have a unique `name` attribute');
9 | return;
10 | }
11 | this.label = this.getAttribute('label') || 'Check';
12 | this.checked = this.hasAttribute('checked') ? `checked="checked"` : '';
13 |
14 | this.innerHTML = `
15 |
24 | `;
25 | }
26 | }
27 |
28 | customElements.define('c-heckbox', Checkbox);
--------------------------------------------------------------------------------
/js/components/Output.js:
--------------------------------------------------------------------------------
1 | // https://github.com/Heydon/bruck#o-utput
2 |
3 | import parser from '../utilities/parser.js';
4 |
5 | export default class Output extends HTMLElement {
6 | constructor() {
7 | super();
8 | this.property = this.getAttribute('property');
9 | if (!this.property || this.property === 'all') {
10 | console.error('Each component must have a `property` attribute that corresponds to a property name on the global data object. The string \'all\' is reserved.');
11 | return;
12 | }
13 | this.template = this.innerHTML;
14 | this.innerHTML = '';
15 |
16 | window.addEventListener('stored', e => {
17 | if (e.detail.property === this.property || 'all') {
18 | this.innerHTML = parser(
19 | this.template,
20 | window.data[this.property]
21 | );
22 | }
23 | })
24 | }
25 | }
26 |
27 | customElements.define('o-utput', Output);
--------------------------------------------------------------------------------
/docs/js/components/Checkbox.js:
--------------------------------------------------------------------------------
1 | // https://github.com/Heydon/bruck#c-heckbox
2 |
3 | export default class Checkbox extends HTMLElement {
4 | constructor() {
5 | super();
6 | this.name = this.getAttribute('name');
7 | if (!this.name) {
8 | console.error('Each component must have a unique `name` attribute');
9 | return;
10 | }
11 | this.label = this.getAttribute('label') || 'Check';
12 | this.checked = this.hasAttribute('checked') ? `checked="checked"` : '';
13 |
14 | this.innerHTML = `
15 |
24 | `;
25 | }
26 | }
27 |
28 | customElements.define('c-heckbox', Checkbox);
--------------------------------------------------------------------------------
/docs/js/components/Output.js:
--------------------------------------------------------------------------------
1 | // https://github.com/Heydon/bruck#o-utput
2 |
3 | import parser from '../utilities/parser.js';
4 |
5 | export default class Output extends HTMLElement {
6 | constructor() {
7 | super();
8 | this.property = this.getAttribute('property');
9 | if (!this.property || this.property === 'all') {
10 | console.error('Each component must have a `property` attribute that corresponds to a property name on the global data object. The string \'all\' is reserved.');
11 | return;
12 | }
13 | this.template = this.innerHTML;
14 | this.innerHTML = '';
15 |
16 | window.addEventListener('stored', e => {
17 | if (e.detail.property === this.property || 'all') {
18 | this.innerHTML = parser(
19 | this.template,
20 | window.data[this.property]
21 | );
22 | }
23 | })
24 | }
25 | }
26 |
27 | customElements.define('o-utput', Output);
--------------------------------------------------------------------------------
/js/utilities/parser.js:
--------------------------------------------------------------------------------
1 | export default function (html, options) {
2 | var re = /{{%(.+?)%}}/g,
3 | reExp = /(^( )?(var|if|for|else|switch|case|break|{|}|;))(.*)?/g,
4 | code = 'with(obj) { var r=[];\n',
5 | cursor = 0,
6 | result,
7 | match;
8 | var add = function (line, js) {
9 | js ? (code += line.match(reExp) ? line + '\n' : 'r.push(' + line + ');\n') :
10 | (code += line != '' ? 'r.push("' + line.replace(/"/g, '\\"') + '");\n' : '');
11 | return add;
12 | }
13 | while (match = re.exec(html)) {
14 | add(html.slice(cursor, match.index))(match[1], true);
15 | cursor = match.index + match[0].length;
16 | }
17 | add(html.substr(cursor, html.length - cursor));
18 | code = (code + 'return r.join(""); }').replace(/[\r\t\n]/g, ' ');
19 | try { result = new Function('obj', code).apply(options, [options]); }
20 | catch (err) { console.error("'" + err.message + "'", " in \n\nCode:\n", code, "\n"); }
21 | return result;
22 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bruck",
3 | "version": "0.0.1",
4 | "description": "A web components-based accessible prototyping tool",
5 | "main": "index.html",
6 | "scripts": {
7 | "test": "jest",
8 | "serve": "http-server . -c-0",
9 | "build": "mkdir -p docs && cp editor.html docs/index.html && cp -r css icons js docs/"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "git+https://github.com/Heydon/bruck.git"
14 | },
15 | "author": "Heydon Pickering (http://www.heydonworks.com)",
16 | "license": "ISC",
17 | "bugs": {
18 | "url": "https://github.com/Heydon/bruck/issues"
19 | },
20 | "homepage": "https://github.com/Heydon/bruck#readme",
21 | "dependencies": {},
22 | "devDependencies": {
23 | "@babel/core": "^7.1.6",
24 | "babel-core": "^7.0.0-bridge.0",
25 | "babel-jest": "^23.6.0",
26 | "babel-preset-env": "^1.7.0",
27 | "regenerator-runtime": "^0.13.1"
28 | }
29 | }
--------------------------------------------------------------------------------
/docs/js/utilities/parser.js:
--------------------------------------------------------------------------------
1 | export default function (html, options) {
2 | var re = /{{%(.+?)%}}/g,
3 | reExp = /(^( )?(var|if|for|else|switch|case|break|{|}|;))(.*)?/g,
4 | code = 'with(obj) { var r=[];\n',
5 | cursor = 0,
6 | result,
7 | match;
8 | var add = function (line, js) {
9 | js ? (code += line.match(reExp) ? line + '\n' : 'r.push(' + line + ');\n') :
10 | (code += line != '' ? 'r.push("' + line.replace(/"/g, '\\"') + '");\n' : '');
11 | return add;
12 | }
13 | while (match = re.exec(html)) {
14 | add(html.slice(cursor, match.index))(match[1], true);
15 | cursor = match.index + match[0].length;
16 | }
17 | add(html.substr(cursor, html.length - cursor));
18 | code = (code + 'return r.join(""); }').replace(/[\r\t\n]/g, ' ');
19 | try { result = new Function('obj', code).apply(options, [options]); }
20 | catch (err) { console.error("'" + err.message + "'", " in \n\nCode:\n", code, "\n"); }
21 | return result;
22 | }
--------------------------------------------------------------------------------
/logo.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/js/components/Progress.js:
--------------------------------------------------------------------------------
1 | // https://github.com/Heydon/bruck#p-rogress
2 |
3 | export default class Progress extends HTMLElement {
4 | constructor() {
5 | super();
6 | const stepsAttr = this.getAttribute('steps');
7 | if (!stepsAttr || !stepsAttr.includes(',')) {
8 | console.error('Each element must have a steps property containing a comma separated list of step labels');
9 | return;
10 | }
11 |
12 | this.steps = stepsAttr.replace(/,\s*/g, ',').split(',');
13 | this.current = this.steps.indexOf(this.getAttribute('current')) + 1 || 1;
14 | this.items = this.steps.map((s, i) => `${s}`);
15 |
16 | this.innerHTML = `
17 |
18 | ${this.items.join('')}
19 |
20 | `;
21 | }
22 |
23 | connectedCallback() {
24 | this.setAttribute('role', 'group');
25 | this.setAttribute('aria-label', `Progress indicator of ${this.steps.length} steps`);
26 | }
27 | }
28 |
29 | customElements.define('p-rogress', Progress);
--------------------------------------------------------------------------------
/docs/js/components/Progress.js:
--------------------------------------------------------------------------------
1 | // https://github.com/Heydon/bruck#p-rogress
2 |
3 | export default class Progress extends HTMLElement {
4 | constructor() {
5 | super();
6 | const stepsAttr = this.getAttribute('steps');
7 | if (!stepsAttr || !stepsAttr.includes(',')) {
8 | console.error('Each element must have a steps property containing a comma separated list of step labels');
9 | return;
10 | }
11 |
12 | this.steps = stepsAttr.replace(/,\s*/g, ',').split(',');
13 | this.current = this.steps.indexOf(this.getAttribute('current')) + 1 || 1;
14 | this.items = this.steps.map((s, i) => `${s}`);
15 |
16 | this.innerHTML = `
17 |
18 | ${this.items.join('')}
19 |
20 | `;
21 | }
22 |
23 | connectedCallback() {
24 | this.setAttribute('role', 'group');
25 | this.setAttribute('aria-label', `Progress indicator of ${this.steps.length} steps`);
26 | }
27 | }
28 |
29 | customElements.define('p-rogress', Progress);
--------------------------------------------------------------------------------
/js/components/Screen.js:
--------------------------------------------------------------------------------
1 | // https://github.com/Heydon/bruck#s-creen
2 |
3 | export default class Screen extends HTMLElement {
4 | constructor() {
5 | super();
6 | this.id = this.getAttribute('id');
7 | if (!this.id) {
8 | console.error('Every element needs a unique id attribute.');
9 | return;
10 | }
11 | this.label = this.getAttribute('label') || this.id;
12 |
13 | this.setAttribute('role', 'document');
14 | this.setAttribute('aria-label', this.label);
15 | this.setAttribute('tabindex', '-1');
16 | this.hidden = true;
17 |
18 | this.change = () => {
19 | if (this.getAttribute('current')) {
20 | this.hidden = false;
21 | document.title = this.label;
22 | this.focus();
23 | } else {
24 | this.hidden = true;
25 | }
26 | }
27 | }
28 |
29 | static get observedAttributes() {
30 | return ['current'];
31 | }
32 |
33 | attributeChangedCallback(name) {
34 | if (name === 'current') {
35 | this.change();
36 | }
37 | }
38 | }
39 |
40 | customElements.define('s-creen', Screen);
--------------------------------------------------------------------------------
/css/components/Progress.css:
--------------------------------------------------------------------------------
1 | p-rogress ol {
2 | display: flex;
3 | list-style: none;
4 | margin: 0;
5 | }
6 |
7 | p-rogress li {
8 | flex: 1 0 auto;
9 | text-align: center;
10 | position: relative;
11 | }
12 |
13 | p-rogress li::before {
14 | content: '';
15 | display: inline-block;
16 | width: 1rem;
17 | height: 1rem;
18 | border-radius: 50%;
19 | border: 0.25rem solid;
20 | background-color: var(--color-dark);
21 | position: relative;
22 | z-index: 1;
23 | }
24 |
25 | p-rogress [aria-current] {
26 | font-weight: bold;
27 | }
28 |
29 | p-rogress [aria-current]::before {
30 | background-color: var(--color-light);
31 | }
32 |
33 | p-rogress span {
34 | display: block;
35 | padding: 0 0.5rem;
36 | }
37 |
38 | p-rogress li::after {
39 | content: '';
40 | position: absolute;
41 | left: 0;
42 | right: 0;
43 | top: 0.5rem;
44 | height: 0.25rem;
45 | transform: translateY(-50%);
46 | background-color: var(--color-dark);
47 | }
48 |
49 | p-rogress li:first-child::after {
50 | left: 50%;
51 | }
52 |
53 | p-rogress li:last-child::after {
54 | right: 50%;
55 | }
--------------------------------------------------------------------------------
/docs/js/components/Screen.js:
--------------------------------------------------------------------------------
1 | // https://github.com/Heydon/bruck#s-creen
2 |
3 | export default class Screen extends HTMLElement {
4 | constructor() {
5 | super();
6 | this.id = this.getAttribute('id');
7 | if (!this.id) {
8 | console.error('Every element needs a unique id attribute.');
9 | return;
10 | }
11 | this.label = this.getAttribute('label') || this.id;
12 |
13 | this.setAttribute('role', 'document');
14 | this.setAttribute('aria-label', this.label);
15 | this.setAttribute('tabindex', '-1');
16 | this.hidden = true;
17 |
18 | this.change = () => {
19 | if (this.getAttribute('current')) {
20 | this.hidden = false;
21 | document.title = this.label;
22 | this.focus();
23 | } else {
24 | this.hidden = true;
25 | }
26 | }
27 | }
28 |
29 | static get observedAttributes() {
30 | return ['current'];
31 | }
32 |
33 | attributeChangedCallback(name) {
34 | if (name === 'current') {
35 | this.change();
36 | }
37 | }
38 | }
39 |
40 | customElements.define('s-creen', Screen);
--------------------------------------------------------------------------------
/docs/css/components/Progress.css:
--------------------------------------------------------------------------------
1 | p-rogress ol {
2 | display: flex;
3 | list-style: none;
4 | margin: 0;
5 | }
6 |
7 | p-rogress li {
8 | flex: 1 0 auto;
9 | text-align: center;
10 | position: relative;
11 | }
12 |
13 | p-rogress li::before {
14 | content: '';
15 | display: inline-block;
16 | width: 1rem;
17 | height: 1rem;
18 | border-radius: 50%;
19 | border: 0.25rem solid;
20 | background-color: var(--color-dark);
21 | position: relative;
22 | z-index: 1;
23 | }
24 |
25 | p-rogress [aria-current] {
26 | font-weight: bold;
27 | }
28 |
29 | p-rogress [aria-current]::before {
30 | background-color: var(--color-light);
31 | }
32 |
33 | p-rogress span {
34 | display: block;
35 | padding: 0 0.5rem;
36 | }
37 |
38 | p-rogress li::after {
39 | content: '';
40 | position: absolute;
41 | left: 0;
42 | right: 0;
43 | top: 0.5rem;
44 | height: 0.25rem;
45 | transform: translateY(-50%);
46 | background-color: var(--color-dark);
47 | }
48 |
49 | p-rogress li:first-child::after {
50 | left: 50%;
51 | }
52 |
53 | p-rogress li:last-child::after {
54 | right: 50%;
55 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (https://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directories
36 | node_modules/
37 | jspm_packages/
38 |
39 | # TypeScript v1 declaration files
40 | typings/
41 |
42 | # Optional npm cache directory
43 | .npm
44 |
45 | # Optional eslint cache
46 | .eslintcache
47 |
48 | # Optional REPL history
49 | .node_repl_history
50 |
51 | # Output of 'npm pack'
52 | *.tgz
53 |
54 | # Yarn Integrity file
55 | .yarn-integrity
56 |
57 | # dotenv environment variables file
58 | .env
59 |
60 | # next.js build output
61 | .next
62 |
--------------------------------------------------------------------------------
/js/components/Box.js:
--------------------------------------------------------------------------------
1 | // https://github.com/Heydon/bruck#b-ox
2 |
3 | export default class Box extends HTMLElement {
4 | constructor() {
5 | super();
6 | this.pad = this.getAttribute('pad') || 1;
7 | this.border = this.hasAttribute('border');
8 | this.maxWidth = this.getAttribute('maxWidth') || 'none';
9 |
10 | const tmpl = document.createElement('template');
11 | tmpl.innerHTML = `
12 |
19 |
20 | `;
21 |
22 | this.attachShadow({ mode: 'open' });
23 | this.shadowRoot.appendChild(tmpl.content.cloneNode(true));
24 | }
25 |
26 | connectedCallback() {
27 | if (this.repeat > 0) {
28 | this.content = this.innerHTML;
29 | for (let i = 1; i < this.repeat; i++) {
30 | this.innerHTML += this.content;
31 | }
32 | }
33 |
34 | const childAmount = this.children.length;
35 | this.setAttribute('role', 'group');
36 | this.setAttribute('aria-label', `${this.border ? 'Bordered' : ''} box containing ${childAmount} elements`);
37 | }
38 | }
39 |
40 | customElements.define('b-ox', Box);
--------------------------------------------------------------------------------
/js/components/Words.js:
--------------------------------------------------------------------------------
1 | // https://github.com/Heydon/bruck#w-ords
2 |
3 | import wordsSample from '../utilities/wordsSample.js';
4 | import rangeToNum from '../utilities/rangeToNum.js';
5 |
6 | export default class Words extends HTMLElement {
7 | constructor() {
8 | super();
9 | const count = this.getAttribute('count') || '2,3';
10 | const sentence = this.hasAttribute('sentence');
11 | const capitalize = this.hasAttribute('capitalize');
12 | this.repeat = this.getAttribute('repeat') || undefined;
13 |
14 | this.generate = () => {
15 | let words = wordsSample(count);
16 | if (capitalize) {
17 | words = words.map(w => w.charAt(0).toUpperCase() + w.slice(1));
18 | }
19 | if (sentence) {
20 | words[0] = words[0].charAt(0).toUpperCase() + words[0].slice(1);
21 | words[0].toUpperCase();
22 | words[words.length - 1] += '. ';
23 | }
24 | return words.join(' ');
25 | }
26 |
27 | const num = !this.repeat ? 1 : rangeToNum(this.repeat);
28 | Promise.all([
29 | customElements.whenDefined('g-rid'),
30 | customElements.whenDefined('s-tack')
31 | ]).then(() => {
32 | for (let i = 0; i < num; i++) {
33 | this.innerHTML += this.generate();
34 | }
35 | });
36 | }
37 | }
38 |
39 | customElements.define('w-ords', Words);
--------------------------------------------------------------------------------
/docs/js/components/Box.js:
--------------------------------------------------------------------------------
1 | // https://github.com/Heydon/bruck#b-ox
2 |
3 | export default class Box extends HTMLElement {
4 | constructor() {
5 | super();
6 | this.pad = this.getAttribute('pad') || 1;
7 | this.border = this.hasAttribute('border');
8 | this.maxWidth = this.getAttribute('maxWidth') || 'none';
9 |
10 | const tmpl = document.createElement('template');
11 | tmpl.innerHTML = `
12 |
19 |
20 | `;
21 |
22 | this.attachShadow({ mode: 'open' });
23 | this.shadowRoot.appendChild(tmpl.content.cloneNode(true));
24 | }
25 |
26 | connectedCallback() {
27 | if (this.repeat > 0) {
28 | this.content = this.innerHTML;
29 | for (let i = 1; i < this.repeat; i++) {
30 | this.innerHTML += this.content;
31 | }
32 | }
33 |
34 | const childAmount = this.children.length;
35 | this.setAttribute('role', 'group');
36 | this.setAttribute('aria-label', `${this.border ? 'Bordered' : ''} box containing ${childAmount} elements`);
37 | }
38 | }
39 |
40 | customElements.define('b-ox', Box);
--------------------------------------------------------------------------------
/docs/js/components/Words.js:
--------------------------------------------------------------------------------
1 | // https://github.com/Heydon/bruck#w-ords
2 |
3 | import wordsSample from '../utilities/wordsSample.js';
4 | import rangeToNum from '../utilities/rangeToNum.js';
5 |
6 | export default class Words extends HTMLElement {
7 | constructor() {
8 | super();
9 | const count = this.getAttribute('count') || '2,3';
10 | const sentence = this.hasAttribute('sentence');
11 | const capitalize = this.hasAttribute('capitalize');
12 | this.repeat = this.getAttribute('repeat') || undefined;
13 |
14 | this.generate = () => {
15 | let words = wordsSample(count);
16 | if (capitalize) {
17 | words = words.map(w => w.charAt(0).toUpperCase() + w.slice(1));
18 | }
19 | if (sentence) {
20 | words[0] = words[0].charAt(0).toUpperCase() + words[0].slice(1);
21 | words[0].toUpperCase();
22 | words[words.length - 1] += '. ';
23 | }
24 | return words.join(' ');
25 | }
26 |
27 | const num = !this.repeat ? 1 : rangeToNum(this.repeat);
28 | Promise.all([
29 | customElements.whenDefined('g-rid'),
30 | customElements.whenDefined('s-tack')
31 | ]).then(() => {
32 | for (let i = 0; i < num; i++) {
33 | this.innerHTML += this.generate();
34 | }
35 | });
36 | }
37 | }
38 |
39 | customElements.define('w-ords', Words);
--------------------------------------------------------------------------------
/js/components/Grid.js:
--------------------------------------------------------------------------------
1 | // https://github.com/Heydon/bruck#g-rid
2 |
3 | import rangeToNum from '../utilities/rangeToNum.js';
4 |
5 | export default class Grid extends HTMLElement {
6 | constructor() {
7 | super();
8 | this.itemWidth = this.getAttribute('itemWidth') || '15rem';
9 | this.gap = this.getAttribute('gap') || '1';
10 | this.times = this.getAttribute('repeat') || undefined;
11 | this.content = this.innerHTML;
12 |
13 | this.attachShadow({ mode: 'open' });
14 | this.shadowRoot.innerHTML = `
15 |
22 |
23 | `;
24 |
25 | if (this.times) {
26 | customElements.whenDefined('s-tack').then(() => {
27 | const count = rangeToNum(this.times);
28 | for (let i = 1; i < count; i++) {
29 | this.innerHTML += this.content;
30 | }
31 | });
32 | }
33 | }
34 |
35 | connectedCallback() {
36 | const childAmount = this.children.length;
37 | this.setAttribute('role', 'group');
38 | this.setAttribute('aria-label', `Grid of ${childAmount} items, each ${this.itemWidth} wide.`);
39 | }
40 | }
41 |
42 | customElements.define('g-rid', Grid);
--------------------------------------------------------------------------------
/docs/js/components/Grid.js:
--------------------------------------------------------------------------------
1 | // https://github.com/Heydon/bruck#g-rid
2 |
3 | import rangeToNum from '../utilities/rangeToNum.js';
4 |
5 | export default class Grid extends HTMLElement {
6 | constructor() {
7 | super();
8 | this.itemWidth = this.getAttribute('itemWidth') || '15rem';
9 | this.gap = this.getAttribute('gap') || '1';
10 | this.times = this.getAttribute('repeat') || undefined;
11 | this.content = this.innerHTML;
12 |
13 | this.attachShadow({ mode: 'open' });
14 | this.shadowRoot.innerHTML = `
15 |
22 |
23 | `;
24 |
25 | if (this.times) {
26 | customElements.whenDefined('s-tack').then(() => {
27 | const count = rangeToNum(this.times);
28 | for (let i = 1; i < count; i++) {
29 | this.innerHTML += this.content;
30 | }
31 | });
32 | }
33 | }
34 |
35 | connectedCallback() {
36 | const childAmount = this.children.length;
37 | this.setAttribute('role', 'group');
38 | this.setAttribute('aria-label', `Grid of ${childAmount} items, each ${this.itemWidth} wide.`);
39 | }
40 | }
41 |
42 | customElements.define('g-rid', Grid);
--------------------------------------------------------------------------------
/js/components/Select.js:
--------------------------------------------------------------------------------
1 | // https://github.com/Heydon/bruck#s-elect
2 |
3 | export default class Select extends HTMLElement {
4 | constructor() {
5 | super();
6 | this.name = this.getAttribute('name');
7 | if (!this.name) {
8 | console.error('Each component must have a unique `name` attribute');
9 | return;
10 | }
11 | this.options = this.getAttribute('options').replace(/,\s*/g, ',').split(',');
12 | if (!this.options) {
13 | console.error('Each component must have an `options` attribute containing a comma-separated list of `;
22 | });
23 |
24 | this.innerHTML = `
25 |
26 |
27 |
30 |
31 |
32 | `;
33 | }
34 | }
35 |
36 | customElements.define('s-elect', Select);
--------------------------------------------------------------------------------
/docs/js/components/Select.js:
--------------------------------------------------------------------------------
1 | // https://github.com/Heydon/bruck#s-elect
2 |
3 | export default class Select extends HTMLElement {
4 | constructor() {
5 | super();
6 | this.name = this.getAttribute('name');
7 | if (!this.name) {
8 | console.error('Each component must have a unique `name` attribute');
9 | return;
10 | }
11 | this.options = this.getAttribute('options').replace(/,\s*/g, ',').split(',');
12 | if (!this.options) {
13 | console.error('Each component must have an `options` attribute containing a comma-separated list of `;
22 | });
23 |
24 | this.innerHTML = `
25 |
26 |
27 |
30 |
31 |
32 | `;
33 | }
34 | }
35 |
36 | customElements.define('s-elect', Select);
--------------------------------------------------------------------------------
/js/components/Icon.js:
--------------------------------------------------------------------------------
1 | // https://github.com/Heydon/bruck#i-con
2 |
3 | export default class Icon extends HTMLElement {
4 | constructor() {
5 | super();
6 | this.name = this.getAttribute('name');
7 | if (!this.name) {
8 | console.error('Each component needs a name attribute');
9 | return;
10 | }
11 |
12 | this.label = this.getAttribute('label') || undefined;
13 |
14 | this.attachShadow({ mode: 'open' });
15 | this.shadowRoot.innerHTML = `
16 |
32 | `;
33 |
34 | fetch(`./icons/${this.name}.svg`)
35 | .then(res => {
36 | res.text()
37 | .then(svg => {
38 | this.shadowRoot.innerHTML += svg;
39 | if (this.label) {
40 | const image = this.shadowRoot.querySelector('svg');
41 | image.setAttribute('role', 'img');
42 | image.setAttribute('aria-label', this.label);
43 | }
44 | });
45 | });
46 | }
47 | }
48 |
49 | customElements.define('i-con', Icon);
--------------------------------------------------------------------------------
/docs/js/components/Icon.js:
--------------------------------------------------------------------------------
1 | // https://github.com/Heydon/bruck#i-con
2 |
3 | export default class Icon extends HTMLElement {
4 | constructor() {
5 | super();
6 | this.name = this.getAttribute('name');
7 | if (!this.name) {
8 | console.error('Each component needs a name attribute');
9 | return;
10 | }
11 |
12 | this.label = this.getAttribute('label') || undefined;
13 |
14 | this.attachShadow({ mode: 'open' });
15 | this.shadowRoot.innerHTML = `
16 |
32 | `;
33 |
34 | fetch(`./icons/${this.name}.svg`)
35 | .then(res => {
36 | res.text()
37 | .then(svg => {
38 | this.shadowRoot.innerHTML += svg;
39 | if (this.label) {
40 | const image = this.shadowRoot.querySelector('svg');
41 | image.setAttribute('role', 'img');
42 | image.setAttribute('aria-label', this.label);
43 | }
44 | });
45 | });
46 | }
47 | }
48 |
49 | customElements.define('i-con', Icon);
--------------------------------------------------------------------------------
/js/components/Cluster.js:
--------------------------------------------------------------------------------
1 | // https://github.com/Heydon/bruck#c-luster
2 |
3 | export default class Cluster extends HTMLElement {
4 | constructor() {
5 | super();
6 | this.gap = this.getAttribute('gap') || '1';
7 | const alignMap = {
8 | top: 'flex-start',
9 | bottom: 'flex-end',
10 | center: 'center'
11 | };
12 | this.align = alignMap[this.getAttribute('align')] || 'center';
13 |
14 | const tmpl = document.createElement('template');
15 | tmpl.innerHTML = `
16 |
30 |
31 |
32 |
33 | `;
34 |
35 | this.attachShadow({ mode: 'open' });
36 | this.shadowRoot.appendChild(tmpl.content.cloneNode(true));
37 | }
38 |
39 | connectedCallback() {
40 | const childAmount = this.children.length;
41 | this.setAttribute('role', 'group');
42 | this.setAttribute('aria-label', `Set of ${childAmount} centrally grouped elements`);
43 | }
44 | }
45 |
46 | customElements.define('c-luster', Cluster);
--------------------------------------------------------------------------------
/docs/js/components/Cluster.js:
--------------------------------------------------------------------------------
1 | // https://github.com/Heydon/bruck#c-luster
2 |
3 | export default class Cluster extends HTMLElement {
4 | constructor() {
5 | super();
6 | this.gap = this.getAttribute('gap') || '1';
7 | const alignMap = {
8 | top: 'flex-start',
9 | bottom: 'flex-end',
10 | center: 'center'
11 | };
12 | this.align = alignMap[this.getAttribute('align')] || 'center';
13 |
14 | const tmpl = document.createElement('template');
15 | tmpl.innerHTML = `
16 |
30 |
31 |
32 |
33 | `;
34 |
35 | this.attachShadow({ mode: 'open' });
36 | this.shadowRoot.appendChild(tmpl.content.cloneNode(true));
37 | }
38 |
39 | connectedCallback() {
40 | const childAmount = this.children.length;
41 | this.setAttribute('role', 'group');
42 | this.setAttribute('aria-label', `Set of ${childAmount} centrally grouped elements`);
43 | }
44 | }
45 |
46 | customElements.define('c-luster', Cluster);
--------------------------------------------------------------------------------
/js/components/Radios.js:
--------------------------------------------------------------------------------
1 | // https://github.com/Heydon/bruck#r-adios
2 |
3 | export default class Radios extends HTMLElement {
4 | constructor() {
5 | super();
6 | this.name = this.getAttribute('name');
7 | if (!this.name) {
8 | console.error('Each component must have a unique `name` attribute');
9 | return;
10 | }
11 | this.options = this.getAttribute('options').replace(/,\s*/g, ',').split(',');
12 | if (!this.options) {
13 | console.error('Each component must have an `options` attribute containing a comma-separated list of radio button labels');
14 | return;
15 | }
16 | this.legend = this.getAttribute('legend') || 'Choose';
17 | this.checked = this.options.indexOf(this.getAttribute('checked')) + 1 || -1;
18 |
19 | this.checkboxes = this.options.map((o, i) => {
20 | let checked = i === this.checked - 1 ? `checked="checked"` : '';
21 | return `
22 |
30 | `;
31 | });
32 |
33 | this.innerHTML = `
34 |
38 | `;
39 | }
40 | }
41 |
42 | customElements.define('r-adios', Radios);
--------------------------------------------------------------------------------
/docs/js/components/Radios.js:
--------------------------------------------------------------------------------
1 | // https://github.com/Heydon/bruck#r-adios
2 |
3 | export default class Radios extends HTMLElement {
4 | constructor() {
5 | super();
6 | this.name = this.getAttribute('name');
7 | if (!this.name) {
8 | console.error('Each component must have a unique `name` attribute');
9 | return;
10 | }
11 | this.options = this.getAttribute('options').replace(/,\s*/g, ',').split(',');
12 | if (!this.options) {
13 | console.error('Each component must have an `options` attribute containing a comma-separated list of radio button labels');
14 | return;
15 | }
16 | this.legend = this.getAttribute('legend') || 'Choose';
17 | this.checked = this.options.indexOf(this.getAttribute('checked')) + 1 || -1;
18 |
19 | this.checkboxes = this.options.map((o, i) => {
20 | let checked = i === this.checked - 1 ? `checked="checked"` : '';
21 | return `
22 |
30 | `;
31 | });
32 |
33 | this.innerHTML = `
34 |
38 | `;
39 | }
40 | }
41 |
42 | customElements.define('r-adios', Radios);
--------------------------------------------------------------------------------
/js/components/Spread.js:
--------------------------------------------------------------------------------
1 | // https://github.com/Heydon/bruck#s-pread
2 |
3 | export default class Spread extends HTMLElement {
4 | constructor() {
5 | super();
6 | this.gap = this.getAttribute('gap') || '1';
7 | this.spaces = this.getAttribute('spaces') === 'around' ? 'around' : 'between';
8 | const alignMap = {
9 | top: 'flex-start',
10 | bottom: 'flex-end',
11 | center: 'center'
12 | };
13 | this.align = alignMap[this.getAttribute('align')] || 'center';
14 |
15 | const tmpl = document.createElement('template');
16 | tmpl.innerHTML = `
17 |
31 |
32 |
33 |
34 | `;
35 |
36 | this.attachShadow({ mode: 'open' });
37 | this.shadowRoot.appendChild(tmpl.content.cloneNode(true));
38 | }
39 |
40 | connectedCallback() {
41 | const childAmount = this.children.length;
42 | this.setAttribute('role', 'group');
43 | this.setAttribute('aria-label', `Distributed row of ${childAmount} items`);
44 | }
45 | }
46 |
47 | customElements.define('s-pread', Spread);
--------------------------------------------------------------------------------
/docs/js/components/Spread.js:
--------------------------------------------------------------------------------
1 | // https://github.com/Heydon/bruck#s-pread
2 |
3 | export default class Spread extends HTMLElement {
4 | constructor() {
5 | super();
6 | this.gap = this.getAttribute('gap') || '1';
7 | this.spaces = this.getAttribute('spaces') === 'around' ? 'around' : 'between';
8 | const alignMap = {
9 | top: 'flex-start',
10 | bottom: 'flex-end',
11 | center: 'center'
12 | };
13 | this.align = alignMap[this.getAttribute('align')] || 'center';
14 |
15 | const tmpl = document.createElement('template');
16 | tmpl.innerHTML = `
17 |
31 |
32 |
33 |
34 | `;
35 |
36 | this.attachShadow({ mode: 'open' });
37 | this.shadowRoot.appendChild(tmpl.content.cloneNode(true));
38 | }
39 |
40 | connectedCallback() {
41 | const childAmount = this.children.length;
42 | this.setAttribute('role', 'group');
43 | this.setAttribute('aria-label', `Distributed row of ${childAmount} items`);
44 | }
45 | }
46 |
47 | customElements.define('s-pread', Spread);
--------------------------------------------------------------------------------
/js/components/Model.js:
--------------------------------------------------------------------------------
1 | // https://github.com/Heydon/bruck#m-odel
2 |
3 | import dataFromForm from '../utilities/dataFromForm.js';
4 |
5 | export default class Model extends HTMLElement {
6 | constructor() {
7 | super();
8 | this.property = this.getAttribute('property');
9 | if (!this.property || this.property === 'all') {
10 | console.error('Each component must have a unique `property` attribute representing a property on the global data object. The string \'all\' is reserved.');
11 | return;
12 | }
13 | this.form = this.querySelector('form');
14 | if (!this.form) {
15 | console.error('Each component must have a