@stanko/ctrls 0.4.2 → 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -313,7 +313,7 @@ Grid of radio buttons. Can be set to have between one and five columns.
313
313
  ```ts
314
314
  {
315
315
  // Mandatory
316
- items: Record<string, string>; // Map of radio items (key, value)
316
+ items: Record<string, string>; // Map of radio items (key -> value, value -> label)
317
317
 
318
318
  // Optional
319
319
  columns?: number; // default: 3
@@ -1,4 +1,4 @@
1
- import type { Ctrl, CtrlItemType, CtrlChangeHandler, CtrlConfig } from "./types";
1
+ import type { Ctrl, CtrlChangeHandler, CtrlConfig, CtrlItemType } from "./types";
2
2
  export declare class BooleanCtrl implements Ctrl<boolean> {
3
3
  type: CtrlItemType;
4
4
  id: string;
@@ -1,3 +1,4 @@
1
+ import { dom } from "../utils/dom";
1
2
  import { checkIcon } from "../utils/icons";
2
3
  import { toHtmlId } from "../utils/string-utils";
3
4
  export class BooleanCtrl {
@@ -17,11 +18,11 @@ export class BooleanCtrl {
17
18
  };
18
19
  this.buildUI = () => {
19
20
  const id = toHtmlId(this.id);
20
- const input = document.createElement("input");
21
- input.classList.add("ctrls__boolean-input");
22
- input.setAttribute("type", "checkbox");
23
- input.setAttribute("id", id);
24
- input.setAttribute("name", id);
21
+ const input = dom.input("ctrls__boolean-input", {
22
+ type: "checkbox",
23
+ id,
24
+ name: id,
25
+ });
25
26
  input.checked = this.value;
26
27
  input.addEventListener("change", () => {
27
28
  this.value = input.checked;
@@ -31,20 +32,18 @@ export class BooleanCtrl {
31
32
  this.value = input.checked;
32
33
  this.onInput(this);
33
34
  });
34
- const checkmark = document.createElement("span");
35
- checkmark.classList.add("ctrls__boolean-checkmark");
36
- checkmark.innerHTML = checkIcon;
37
- const right = document.createElement("div");
38
- right.classList.add("ctrls__control-right");
39
- right.appendChild(input);
40
- right.appendChild(checkmark);
41
- const label = document.createElement("span");
42
- label.textContent = this.label;
43
- label.classList.add("ctrls__control-label");
44
- const element = document.createElement("label");
45
- element.classList.add("ctrls__control", "ctrls__control--boolean");
46
- element.appendChild(label);
47
- element.appendChild(right);
35
+ const checkmark = dom.span("ctrls__boolean-checkmark", {
36
+ innerHTML: checkIcon,
37
+ });
38
+ const right = dom.div("ctrls__control-right", {
39
+ children: [input, checkmark],
40
+ });
41
+ const label = dom.span("ctrls__control-label", {
42
+ children: [this.label],
43
+ });
44
+ const element = dom.label("ctrls__control ctrls__control--boolean", {
45
+ children: [label, right],
46
+ });
48
47
  return {
49
48
  element,
50
49
  input,
@@ -1,5 +1,5 @@
1
1
  import DualRangeInput from "@stanko/dual-range-input";
2
- import type { Ctrl, CtrlChangeHandler, CtrlItemType, ConfigFor } from "./types";
2
+ import type { ConfigFor, Ctrl, CtrlChangeHandler, CtrlItemType } from "./types";
3
3
  export type DualRangeControlOptions = {
4
4
  min: number;
5
5
  max: number;
@@ -1,5 +1,6 @@
1
- import random from "../utils/random";
2
1
  import DualRangeInput from "@stanko/dual-range-input";
2
+ import { dom } from "../utils/dom";
3
+ import random from "../utils/random";
3
4
  import { roundToStep } from "../utils/round-to-step";
4
5
  import { toHtmlId } from "../utils/string-utils";
5
6
  export class DualRangeCtrl {
@@ -46,43 +47,41 @@ export class DualRangeCtrl {
46
47
  this.update(this.value);
47
48
  this.onInput(this);
48
49
  };
49
- const minInput = document.createElement("input");
50
- minInput.setAttribute("type", "range");
51
- minInput.setAttribute("name", `${id}-min`);
52
- minInput.setAttribute("id", `${id}-min`);
53
- minInput.setAttribute("min", min.toString());
54
- minInput.setAttribute("max", max.toString());
55
- minInput.setAttribute("step", step.toString());
56
- minInput.setAttribute("value", value.min.toString());
50
+ const minInput = dom.input("", {
51
+ type: "range",
52
+ name: `${id}-min`,
53
+ id: `${id}-min`,
54
+ min: min,
55
+ max: max,
56
+ step: step,
57
+ value: value.min,
58
+ });
57
59
  minInput.addEventListener("input", inputHandler);
58
60
  minInput.addEventListener("change", changeHandler);
59
- const maxInput = document.createElement("input");
60
- maxInput.setAttribute("type", "range");
61
- maxInput.setAttribute("name", `${id}-max`);
62
- maxInput.setAttribute("id", `${id}-max`);
63
- maxInput.setAttribute("min", min.toString());
64
- maxInput.setAttribute("max", max.toString());
65
- maxInput.setAttribute("step", step.toString());
66
- maxInput.setAttribute("value", value.max.toString());
61
+ const maxInput = dom.input("", {
62
+ type: "range",
63
+ name: `${id}-max`,
64
+ id: `${id}-max`,
65
+ min: min,
66
+ max: max,
67
+ step: step,
68
+ value: value.min,
69
+ });
67
70
  maxInput.addEventListener("input", inputHandler);
68
71
  maxInput.addEventListener("change", changeHandler);
69
- const inputWrapper = document.createElement("div");
70
- inputWrapper.classList.add("dual-range-input");
71
- inputWrapper.appendChild(minInput);
72
- inputWrapper.appendChild(maxInput);
73
- const right = document.createElement("div");
74
- right.classList.add("ctrls__control-right");
75
- right.appendChild(inputWrapper);
76
- const label = document.createElement("span");
77
- label.textContent = this.label;
78
- label.classList.add("ctrls__control-label");
79
- const valueSpan = document.createElement("span");
80
- valueSpan.classList.add("ctrls__control-value");
81
- label.appendChild(valueSpan);
82
- const element = document.createElement("div");
83
- element.classList.add("ctrls__control", "ctrls__control--dual-range");
84
- element.appendChild(label);
85
- element.appendChild(right);
72
+ const inputWrapper = dom.div("dual-range-input", {
73
+ children: [minInput, maxInput],
74
+ });
75
+ const right = dom.div("ctrls__control-right", {
76
+ children: [inputWrapper],
77
+ });
78
+ const valueSpan = dom.span("ctrls__control-value");
79
+ const label = dom.span("ctrls__control-label", {
80
+ children: [this.label, valueSpan],
81
+ });
82
+ const element = dom.div("ctrls__control ctrls__control--dual-range", {
83
+ children: [label, right],
84
+ });
86
85
  return {
87
86
  element,
88
87
  valueSpan,
@@ -1,4 +1,4 @@
1
- import type { Ctrl, CtrlChangeHandler, CtrlItemType, ConfigFor } from "./types";
1
+ import type { ConfigFor, Ctrl, CtrlChangeHandler, CtrlItemType } from "./types";
2
2
  export type Easing = [number, number, number, number];
3
3
  export declare class EasingCtrl implements Ctrl<Easing> {
4
4
  type: CtrlItemType;
@@ -1,5 +1,6 @@
1
- import random from "../utils/random";
2
1
  import BezierEasing from "bezier-easing";
2
+ import { dom } from "../utils/dom";
3
+ import random from "../utils/random";
3
4
  import { toHtmlId } from "../utils/string-utils";
4
5
  const easings = {
5
6
  EASE: [0.25, 0.1, 0.25, 1],
@@ -53,36 +54,27 @@ export class EasingCtrl {
53
54
  this.buildUI = () => {
54
55
  const { value } = this;
55
56
  const id = toHtmlId(this.id);
56
- const line1 = document.createElementNS("http://www.w3.org/2000/svg", "line");
57
- line1.setAttribute("class", "ctrls__easing-line ctrls__easing-line--1");
58
- line1.setAttribute("x1", "0");
59
- line1.setAttribute("y1", `${h}`);
60
- const line2 = document.createElementNS("http://www.w3.org/2000/svg", "line");
61
- line2.setAttribute("class", "ctrls__easing-line ctrls__easing-line--2");
62
- line2.setAttribute("x1", `${w}`);
63
- line2.setAttribute("y1", "0");
64
- const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
65
- path.setAttribute("class", "ctrls__easing-path");
66
- const borders = document.createElementNS("http://www.w3.org/2000/svg", "path");
67
- borders.classList.add("easing-borders");
68
- borders.setAttribute("d", `M 0 0 h ${w} M 0 ${h} h ${w}`);
69
- const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
70
- svg.setAttribute("viewBox", `0 0 ${w} ${h}`);
71
- svg.appendChild(borders);
72
- svg.appendChild(path);
73
- svg.appendChild(line1);
74
- svg.appendChild(line2);
75
- const handle1 = document.createElement("button");
76
- handle1.className = "ctrls__easing-handle ctrls__easing-handle--1";
77
- handle1.innerHTML = "";
78
- const handle2 = document.createElement("button");
79
- handle2.className = "ctrls__easing-handle ctrls__easing-handle--2";
80
- handle2.innerHTML = "";
81
- const control = document.createElement("div");
82
- control.className = "ctrls__easing";
83
- control.appendChild(svg);
84
- control.appendChild(handle1);
85
- control.appendChild(handle2);
57
+ const line1 = dom.line("ctrls__easing-line ctrls__easing-line--1", {
58
+ x1: 0,
59
+ y1: h,
60
+ });
61
+ const line2 = dom.line("ctrls__easing-line ctrls__easing-line--2", {
62
+ x1: w,
63
+ y1: 0,
64
+ });
65
+ const path = dom.path("ctrls__easing-path");
66
+ const borders = dom.path("easing-borders", {
67
+ d: `M 0 0 h ${w} M 0 ${h} h ${w}`,
68
+ });
69
+ const svg = dom.svg("", {
70
+ viewBox: `0 0 ${w} ${h}`,
71
+ children: [borders, path, line1, line2],
72
+ });
73
+ const handle1 = dom.button("ctrls__easing-handle ctrls__easing-handle--1");
74
+ const handle2 = dom.button("ctrls__easing-handle ctrls__easing-handle--2");
75
+ const control = dom.div("ctrls__easing", {
76
+ children: [svg, handle1, handle2],
77
+ });
86
78
  const addListeners = (handle, index) => {
87
79
  let dragging = false;
88
80
  let dragStart = { x: 0, y: 0 };
@@ -185,51 +177,51 @@ export class EasingCtrl {
185
177
  // Presets
186
178
  let presetButtons = null;
187
179
  if (Object.keys(this.presets).length > 0) {
188
- presetButtons = document.createElement("div");
189
- presetButtons.classList.add("ctrls__easing-buttons");
190
- for (const key of Object.keys(this.presets)) {
191
- const button = document.createElement("button");
192
- button.textContent = key.toLowerCase().replace("ease_", "");
180
+ const buttons = Object.keys(this.presets).map((key) => {
181
+ const button = dom.button("", {
182
+ // Remove EASE_ prefix and make it lowercase
183
+ // EASE_IN -> in
184
+ children: [key.toLowerCase().replace("ease_", "")],
185
+ });
193
186
  button.addEventListener("click", () => {
194
187
  this.value = this.presets[key];
195
188
  this.onChange(this);
196
189
  this.update();
197
190
  });
198
- presetButtons.appendChild(button);
199
- }
191
+ return button;
192
+ });
193
+ presetButtons = dom.div("ctrls__easing-buttons", {
194
+ children: buttons,
195
+ });
200
196
  }
201
- const ticks = document.createElementNS("http://www.w3.org/2000/svg", "svg");
202
- ticks.classList.add("ctrls__easing-ticks");
203
- ticks.setAttribute("viewBox", `0 0 ${w} 5`);
204
- ticks.setAttribute("preserveAspectRatio", "none");
205
197
  const tickCount = 30;
206
198
  const ticksElements = [];
207
199
  for (let i = 0; i < tickCount; i++) {
208
- const tick = document.createElementNS("http://www.w3.org/2000/svg", "line");
209
- tick.setAttribute("y1", "0");
210
- tick.setAttribute("y2", "5");
200
+ const tick = dom.line("", {
201
+ y1: 0,
202
+ y2: 5,
203
+ });
211
204
  ticksElements.push(tick);
212
- ticks.appendChild(tick);
213
205
  }
214
- const controlWrapper = document.createElement("div");
215
- controlWrapper.classList.add("ctrls__easing-wrapper");
216
- controlWrapper.appendChild(ticks);
217
- controlWrapper.appendChild(control);
218
- controlWrapper.setAttribute("id", id);
219
- const right = document.createElement("div");
220
- right.classList.add("ctrls__control-right");
221
- right.appendChild(controlWrapper);
222
- if (presetButtons) {
223
- right.appendChild(presetButtons);
224
- }
225
- const label = document.createElement("span");
226
- label.textContent = this.label;
227
- label.classList.add("ctrls__control-label");
228
- const element = document.createElement("div");
229
- element.classList.add("ctrls__control", "ctrls__control--easing");
230
- element.setAttribute("data-value", value.join(","));
231
- element.appendChild(label);
232
- element.appendChild(right);
206
+ const ticks = dom.svg("ctrls__easing-ticks", {
207
+ viewBox: `0 0 ${w} 5`,
208
+ preserveAspectRatio: "none",
209
+ children: ticksElements,
210
+ });
211
+ const controlWrapper = dom.div("ctrls__easing-wrapper", {
212
+ id,
213
+ children: [ticks, control],
214
+ });
215
+ const right = dom.div("ctrls__control-right", {
216
+ children: [controlWrapper, presetButtons],
217
+ });
218
+ const label = dom.div("ctrls__control-label", {
219
+ children: [this.label],
220
+ });
221
+ const element = dom.div("ctrls__control ctrls__control--easing", {
222
+ "data-value": value.join(","),
223
+ children: [label, right],
224
+ });
233
225
  return {
234
226
  element,
235
227
  ticks: ticksElements,
@@ -1,6 +1,6 @@
1
+ import { dom } from "../utils/dom";
2
+ import { deleteIcon } from "../utils/icons";
1
3
  import { toHtmlId } from "../utils/string-utils";
2
- import { dom } from "./dom";
3
- import { closeIcon } from "../utils/icons";
4
4
  const IMAGE_EXTENSIONS = ["jpg", "jpeg", "png", "gif", "webp", "svg+xml"];
5
5
  export class FileCtrl {
6
6
  constructor(config, onChange, onInput) {
@@ -17,13 +17,18 @@ export class FileCtrl {
17
17
  this.onChange(this);
18
18
  this.onInput(this);
19
19
  });
20
- const fakeInput = dom.label("ctrls__file-fake-input ctrls__btn ctrls__btn--sm", { for: id });
21
- fakeInput.innerHTML = "select file";
20
+ const fakeInput = dom.label("ctrls__file-fake-input ctrls__btn ctrls__btn--sm", {
21
+ for: id,
22
+ children: ["select file"],
23
+ });
22
24
  if (this.accept) {
23
- fakeInput.innerHTML += `<span>${this.accept}</span>`;
25
+ const acceptSpan = dom.span("", { children: [this.accept] });
26
+ fakeInput.append(acceptSpan);
24
27
  }
25
- const clearButton = dom.button("ctrls__file-clear ctrls__btn");
26
- clearButton.innerHTML = closeIcon;
28
+ const clearButton = dom.button("ctrls__file-clear ctrls__btn", {
29
+ innerHTML: deleteIcon,
30
+ "aria-label": "Clear file",
31
+ });
27
32
  clearButton.addEventListener("click", () => {
28
33
  if (input.files) {
29
34
  this.update(null);
@@ -31,21 +36,20 @@ export class FileCtrl {
31
36
  this.onInput(this);
32
37
  }
33
38
  });
34
- const top = dom.div("ctrls__file-top");
35
- top.append(input);
36
- top.append(fakeInput);
37
- top.append(clearButton);
39
+ const top = dom.div("ctrls__file-top", {
40
+ children: [input, fakeInput, clearButton],
41
+ });
38
42
  const preview = dom.div("ctrls__file-preview");
39
- const right = dom.div("ctrls__control-right");
40
- right.append(top);
41
- right.append(preview);
43
+ const right = dom.div("ctrls__control-right", {
44
+ children: [top, preview],
45
+ });
42
46
  const label = dom.label("ctrls__control-label", {
43
47
  for: id,
48
+ children: [this.label],
49
+ });
50
+ const element = dom.div("ctrls__control ctrls__control--file", {
51
+ children: [label, right],
44
52
  });
45
- label.textContent = this.label;
46
- const element = dom.div("ctrls__control ctrls__control--file");
47
- element.appendChild(label);
48
- element.appendChild(right);
49
53
  return {
50
54
  element,
51
55
  input,
@@ -55,20 +59,19 @@ export class FileCtrl {
55
59
  this.update = (file) => {
56
60
  this.value = file;
57
61
  if (file) {
58
- const item = document.createElement("figure");
59
- item.classList.add("ctrls__file-preview-item");
60
- if (IMAGE_EXTENSIONS.includes(file.type.split("/")[1])) {
61
- console.log(URL.createObjectURL(file), file);
62
- const img = document.createElement("img");
63
- img.src = URL.createObjectURL(file);
64
- img.alt = file.name;
65
- img.classList.add("ctrls__file-image");
66
- item.appendChild(img);
67
- }
68
- const label = document.createElement("figcaption");
69
- label.classList.add("ctrls__file-label");
70
- label.textContent = file.name;
71
- item.appendChild(label);
62
+ const isImage = IMAGE_EXTENSIONS.includes(file.type.split("/")[1]);
63
+ const img = isImage
64
+ ? dom.img("ctrls__file-image", {
65
+ src: URL.createObjectURL(file),
66
+ alt: file.name,
67
+ })
68
+ : "";
69
+ const label = dom.figcaption("ctrls__file-label", {
70
+ children: [file.name],
71
+ });
72
+ const item = dom.figure("ctrls__file-preview-item", {
73
+ children: [img, label],
74
+ });
72
75
  this.preview.replaceChildren(item);
73
76
  }
74
77
  else {
@@ -1,13 +1,13 @@
1
+ import { dom } from "../utils/dom";
1
2
  export const getHTMLControlElement = (config) => {
2
- const right = document.createElement("div");
3
- right.classList.add("ctrls__control-right");
4
- right.append(config.html);
5
- const label = document.createElement("label");
6
- label.textContent = config.label || config.name;
7
- label.classList.add("ctrls__control-label");
8
- const element = document.createElement("div");
9
- element.classList.add("ctrls__control", "ctrls__control--seed");
10
- element.appendChild(label);
11
- element.appendChild(right);
3
+ const right = dom.div("ctrls__control-right", {
4
+ children: [config.html],
5
+ });
6
+ const label = dom.label("ctrls__control-label", {
7
+ children: [config.label || config.name],
8
+ });
9
+ const element = dom.div("ctrls__control ctrls__control--seed", {
10
+ children: [label, right],
11
+ });
12
12
  return element;
13
13
  };
@@ -1,6 +1,7 @@
1
1
  import random from "../utils/random";
2
2
  import { toKebabCase } from "../utils/string-utils";
3
3
  import { getRandomString } from "../utils/get-random-string";
4
+ import { dom } from "../utils/dom";
4
5
  export class RadioCtrl {
5
6
  constructor(config, onChange, onInput) {
6
7
  this.type = "radio";
@@ -21,11 +22,12 @@ export class RadioCtrl {
21
22
  this.buildUI = () => {
22
23
  const { items, value } = this;
23
24
  const inputs = items.map((item) => {
24
- const input = document.createElement("input");
25
- input.setAttribute("type", "radio");
26
- input.setAttribute("name", this.htmlId);
27
- input.setAttribute("id", `${this.htmlId}-${toKebabCase(item.value)}`);
28
- input.setAttribute("value", item.value);
25
+ const input = dom.input("", {
26
+ type: "radio",
27
+ name: this.htmlId,
28
+ id: `${this.htmlId}-${toKebabCase(item.value)}`,
29
+ value: item.value,
30
+ });
29
31
  input.checked = item.value === value;
30
32
  input.addEventListener("change", () => {
31
33
  this.value = this.parse(input.value);
@@ -35,25 +37,24 @@ export class RadioCtrl {
35
37
  this.value = this.parse(input.value);
36
38
  this.onInput(this);
37
39
  });
38
- const label = document.createElement("span");
39
- label.textContent = item.label;
40
- const option = document.createElement("label");
41
- option.classList.add("ctrls__radio-label");
42
- option.appendChild(input);
43
- option.appendChild(label);
40
+ const label = dom.span("", {
41
+ children: [item.label],
42
+ });
43
+ const option = dom.label("ctrls__radio-label", {
44
+ children: [input, label],
45
+ });
44
46
  return option;
45
47
  });
46
- const right = document.createElement("div");
47
- right.classList.add("ctrls__control-right");
48
- right.style.gridTemplateColumns = `repeat(${this.columns}, 1fr)`;
49
- right.append(...inputs);
50
- const label = document.createElement("span");
51
- label.textContent = this.label;
52
- label.classList.add("ctrls__control-label");
53
- const element = document.createElement("div");
54
- element.classList.add("ctrls__control", "ctrls__control--radio");
55
- element.appendChild(label);
56
- element.appendChild(right);
48
+ const right = dom.div("ctrls__control-right", {
49
+ children: inputs,
50
+ style: `grid-template-columns: repeat(${this.columns}, 1fr);`,
51
+ });
52
+ const label = dom.span("ctrls__control-label", {
53
+ children: [this.label],
54
+ });
55
+ const element = dom.div("ctrls__control ctrls__control--radio", {
56
+ children: [label, right],
57
+ });
57
58
  return element;
58
59
  };
59
60
  this.update = (value) => {
@@ -69,10 +70,10 @@ export class RadioCtrl {
69
70
  next.checked = true;
70
71
  };
71
72
  this.items = [];
72
- Object.keys(config.items).forEach((key) => {
73
+ Object.entries(config.items).forEach(([label, value]) => {
73
74
  this.items.push({
74
- label: key,
75
- value: config.items[key],
75
+ label,
76
+ value,
76
77
  });
77
78
  });
78
79
  this.columns = config.columns || 3;
@@ -1,6 +1,7 @@
1
1
  import random from "../utils/random";
2
2
  import { roundToStep } from "../utils/round-to-step";
3
3
  import { toHtmlId } from "../utils/string-utils";
4
+ import { dom } from "../utils/dom";
4
5
  export class RangeCtrl {
5
6
  constructor(config, onChange, onInput) {
6
7
  this.type = "range";
@@ -21,15 +22,15 @@ export class RangeCtrl {
21
22
  this.buildUI = () => {
22
23
  const { min, max, step, value } = this;
23
24
  const id = toHtmlId(this.id);
24
- const input = document.createElement("input");
25
- input.classList.add("ctrls__range-input");
26
- input.setAttribute("type", "range");
27
- input.setAttribute("id", id);
28
- input.setAttribute("name", id);
29
- input.setAttribute("min", min.toString());
30
- input.setAttribute("max", max.toString());
31
- input.setAttribute("step", step.toString());
32
- input.setAttribute("value", value.toString());
25
+ const input = dom.input("ctrls__range-input", {
26
+ type: "range",
27
+ id,
28
+ name: id,
29
+ min,
30
+ max,
31
+ step,
32
+ value,
33
+ });
33
34
  input.addEventListener("input", () => {
34
35
  this.value = this.parse(input.value);
35
36
  this.update(this.value);
@@ -45,19 +46,16 @@ export class RangeCtrl {
45
46
  const percentage = ((value - min) / (max - min)) * 100;
46
47
  this.element.style.setProperty("--gradient-position", `${percentage.toFixed(2)}%`);
47
48
  });
48
- const right = document.createElement("div");
49
- right.classList.add("ctrls__control-right");
50
- right.append(input);
51
- const label = document.createElement("span");
52
- label.textContent = this.label;
53
- label.classList.add("ctrls__control-label");
54
- const valueSpan = document.createElement("span");
55
- valueSpan.classList.add("ctrls__control-value");
56
- label.appendChild(valueSpan);
57
- const element = document.createElement("label");
58
- element.classList.add("ctrls__control", "ctrls__control--range");
59
- element.appendChild(label);
60
- element.appendChild(right);
49
+ const right = dom.div("ctrls__control-right", {
50
+ children: [input],
51
+ });
52
+ const valueSpan = dom.span("ctrls__control-value");
53
+ const label = dom.span("ctrls__control-label", {
54
+ children: [this.label, valueSpan],
55
+ });
56
+ const element = dom.label("ctrls__control ctrls__control--range", {
57
+ children: [label, right],
58
+ });
61
59
  return {
62
60
  element,
63
61
  input,
@@ -1,6 +1,7 @@
1
1
  import generateSeed from "../utils/generate-seed";
2
2
  import { refreshIcon } from "../utils/icons";
3
3
  import { toHtmlId } from "../utils/string-utils";
4
+ import { dom } from "../utils/dom";
4
5
  export class SeedCtrl {
5
6
  constructor(config, onChange, onInput) {
6
7
  this.type = "seed";
@@ -22,12 +23,12 @@ export class SeedCtrl {
22
23
  this.buildUI = () => {
23
24
  const { value } = this;
24
25
  const id = toHtmlId(this.id);
25
- const input = document.createElement("input");
26
- input.classList.add("ctrls__seed-input");
27
- input.setAttribute("type", "text");
28
- input.setAttribute("value", value.toString());
29
- input.setAttribute("id", id);
30
- input.setAttribute("name", id);
26
+ const input = dom.input("ctrls__seed-input", {
27
+ type: "text",
28
+ value,
29
+ id,
30
+ name: id,
31
+ });
31
32
  input.addEventListener("change", () => {
32
33
  this.value = this.parse(input.value);
33
34
  this.onChange(this);
@@ -36,26 +37,24 @@ export class SeedCtrl {
36
37
  this.value = this.parse(input.value);
37
38
  this.onInput(this);
38
39
  });
39
- const reload = document.createElement("button");
40
- reload.innerHTML = refreshIcon;
41
- reload.classList.add("ctrls__seed-new-button", "ctrls__btn");
40
+ const reload = dom.button("ctrls__seed-new-button ctrls__btn", {
41
+ innerHTML: refreshIcon,
42
+ });
42
43
  reload.addEventListener("click", () => {
43
44
  this.value = this.getRandomValue();
44
45
  this.update();
45
46
  this.onChange(this);
46
47
  });
47
- const right = document.createElement("div");
48
- right.classList.add("ctrls__control-right");
49
- right.append(input);
50
- right.append(reload);
51
- const label = document.createElement("label");
52
- label.textContent = this.label;
53
- label.setAttribute("for", id);
54
- label.classList.add("ctrls__control-label");
55
- const element = document.createElement("div");
56
- element.classList.add("ctrls__control", "ctrls__control--seed");
57
- element.appendChild(label);
58
- element.appendChild(right);
48
+ const right = dom.div("ctrls__control-right", {
49
+ children: [input, reload],
50
+ });
51
+ const label = dom.label("ctrls__control-label", {
52
+ for: id,
53
+ children: [this.label],
54
+ });
55
+ const element = dom.div("ctrls__control ctrls__control--seed", {
56
+ children: [label, right],
57
+ });
59
58
  return {
60
59
  element,
61
60
  input,
@@ -11,6 +11,7 @@ import { FileCtrl } from "./ctrl-file";
11
11
  import Alea from "../utils/alea";
12
12
  import { chevronUpIcon, diceIcon } from "../utils/icons";
13
13
  import { getHTMLControlElement } from "./ctrl-html";
14
+ import { dom } from "../utils/dom";
14
15
  const controlMap = {
15
16
  boolean: BooleanCtrl,
16
17
  range: RangeCtrl,
@@ -41,26 +42,24 @@ export class Ctrls {
41
42
  // Processing configs and creating component instances and HTML elements
42
43
  configs.map((config) => {
43
44
  if (config.type === "group") {
44
- // Create group element
45
- const groupElement = document.createElement("div");
46
- groupElement.classList.add("ctrls__group");
47
- if (config.isCollapsed) {
48
- groupElement.classList.add("ctrls__group--hidden");
49
- }
50
- const groupTitle = document.createElement("button");
51
- groupTitle.classList.add("ctrls__group-title");
52
- groupTitle.innerHTML =
53
- (config.label || toSpaceCase(config.name)) + chevronUpIcon;
45
+ // Group title
46
+ const groupTitle = dom.button("ctrls__group-title", {
47
+ innerHTML: (config.label || toSpaceCase(config.name)) + chevronUpIcon,
48
+ });
54
49
  groupTitle.addEventListener("click", () => {
55
50
  groupTitle.parentElement?.classList.toggle("ctrls__group--hidden");
56
51
  });
57
- // Add title
58
- groupElement.append(groupTitle);
59
- config.controls.forEach((itemConfig) => {
52
+ const controlsElements = config.controls.map((itemConfig) => {
60
53
  const control = this.registerControl(itemConfig, onChangeControlHandler, onInputControlHandler, toCamelCase(config.name));
61
- // Add the control elements to the group element
62
- groupElement.append(control?.element);
54
+ return control.element;
63
55
  });
56
+ // Create group element
57
+ const groupElement = dom.div("ctrls__group", {
58
+ children: [groupTitle, ...controlsElements],
59
+ });
60
+ if (config.isCollapsed) {
61
+ groupElement.classList.add("ctrls__group--hidden");
62
+ }
64
63
  // Add the group element
65
64
  elements.push(groupElement);
66
65
  }
@@ -172,33 +171,30 @@ export class Ctrls {
172
171
  theme: "system",
173
172
  ...options,
174
173
  };
175
- // Main element
176
- this.element = document.createElement("div");
177
- this.element.classList.add("ctrls");
178
- this.element.classList.add(`ctrls--${this.options.theme}-theme`);
179
174
  // Title
175
+ let titleButton = null;
180
176
  if (this.options.title) {
181
- const titleButton = document.createElement("button");
182
- titleButton.classList.add("ctrls__title");
183
- titleButton.innerHTML = this.options.title + chevronUpIcon;
177
+ titleButton = dom.button("ctrls__title", {
178
+ innerHTML: this.options.title + chevronUpIcon,
179
+ });
184
180
  titleButton.addEventListener("click", this.toggleVisibility);
185
- this.element.appendChild(titleButton);
186
181
  }
187
- // Controls wrapper
188
- const controlsContainer = document.createElement("div");
189
- controlsContainer.classList.add("ctrls__controls");
190
- this.element.appendChild(controlsContainer);
191
- // Controls
192
- const controlElements = this.processControls(configs);
193
- controlsContainer.append(...controlElements);
194
182
  // Randomize button
183
+ let randomizeButton = null;
195
184
  if (this.options.showRandomizeButton) {
196
- const randomizeButton = document.createElement("button");
197
- randomizeButton.classList.add("ctrls__randomize", "ctrls__btn", "ctrls__btn--lg");
198
- randomizeButton.innerHTML = `Randomize ${diceIcon}`;
185
+ randomizeButton = dom.button("ctrls__randomize ctrls__btn ctrls__btn--lg", { innerHTML: `Randomize ${diceIcon}` });
199
186
  randomizeButton.addEventListener("click", this.randomize);
200
- controlsContainer.appendChild(randomizeButton);
201
187
  }
188
+ // Control elements
189
+ const controlElements = this.processControls(configs);
190
+ // Controls wrapper
191
+ const controlsContainer = dom.div("ctrls__controls", {
192
+ children: [...controlElements, randomizeButton],
193
+ });
194
+ // Main element
195
+ this.element = dom.div(`ctrls ctrls--${this.options.theme}-theme`, {
196
+ children: [titleButton, controlsContainer],
197
+ });
202
198
  // Append the Ctrls element to the provided parent element
203
199
  if (this.options.parent) {
204
200
  this.options.parent.appendChild(this.element);
package/dist/ctrls.css CHANGED
@@ -358,6 +358,7 @@
358
358
  .ctrls__controls {
359
359
  overflow: auto;
360
360
  display: grid;
361
+ padding: 0.25rem 0;
361
362
  scrollbar-width: thin;
362
363
  scrollbar-color: var(--ctrls-scrollbar-thumb-bg) transparent;
363
364
  }
@@ -372,13 +373,6 @@
372
373
  border-radius: var(--ctrls-radius);
373
374
  overflow: hidden;
374
375
  }
375
- .ctrls__group:only-child {
376
- margin: 0.5rem;
377
- }
378
-
379
- .ctrls__group + .ctrls__group {
380
- margin-top: 0.5rem;
381
- }
382
376
 
383
377
  .ctrls__group .ctrls__control {
384
378
  grid-template-columns: calc(var(--ctrls-label-width) - 0.5rem) minmax(0, 1fr);
@@ -398,9 +392,6 @@
398
392
  grid-template-columns: var(--ctrls-label-width) minmax(0, 1fr);
399
393
  align-items: center;
400
394
  }
401
- .ctrls__control:only-child {
402
- padding: 0.5rem;
403
- }
404
395
  .ctrls__control:hover {
405
396
  background: var(--ctrls-hover-bg);
406
397
  }
@@ -469,7 +460,7 @@
469
460
  }
470
461
 
471
462
  .ctrls__randomize {
472
- margin-block: 0.5rem;
463
+ margin-block: 0.25rem;
473
464
  }
474
465
  .ctrls__randomize:focus-visible svg, .ctrls__randomize:hover svg {
475
466
  transform: rotate(0.5turn);
@@ -1 +1 @@
1
- {"version":3,"sourceRoot":"","sources":["../node_modules/@stanko/dual-range-input/dist/index.css","../src/scss/_ctrls.scss"],"names":[],"mappings":"AAAA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;;;AAEF;EACE;;;AAEF;EACE;EACA;EACA;;;AAEF;EACE;;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAEF;EACE;;;AAEF;EACE;EACA;;;AAEF;EACE;EACA;;;AAEF;EACE;EACA;;;AAEF;EACE;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;;;AAEF;EACE;;;AAEF;EACE;EACA;EACA;;;AAEF;EACE;;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAEF;EACE;;;AAEF;EACE;EACA;;;AAEF;EACE;EACA;;;AAEF;EACE;EACA;;;;AC3IF;EACE;AAAA;AAAA;EAGA;EACA;EACA;EACA;EACA;EAGA;EACA;EAEA;EACA;EAGA;EACA;EACA;EACA;EACA;EACA;EAGA;EAGA;EACA;EACA;EACA;EAGA;EACA;EACA;EAGA;EAGA;EAEA;EACA;EAEA;EACA;EAGA;EAGA;EACA;EAEA;EACA;EAEA;EACA;EACA;EACA;EAGA;EACA;EAEA;EAEA;EACA;EAEA;EAGA;EAEA;EACA;;;AAgDF;EACE;IA5CA;IAEA;IACA;IAGA;IACA;IACA;IACA;IACA;IACA;IAGA;IAGA;IACA;IACA;IACA;IAGA;IACA;IACA;IAGA;IAGA;IACA;IAEA;IAGA;IAGA;;;AASF;EAjDE;EAEA;EACA;EAGA;EACA;EACA;EACA;EACA;EACA;EAGA;EAGA;EACA;EACA;EACA;EAGA;EACA;EACA;EAGA;EAGA;EACA;EAEA;EAGA;EAGA;;;AAeF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;AAAA;AAAA;EAGE;EACA;EACA;;AAGF;AAAA;EAEE;EACA;EACA;;AAGF;EACE;EACA;;AAGF;EACE;;;AAIJ;EACE;EACA;;;AAKF;AAAA;EAEE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,YACE;;AAGF;AAAA;AAAA;EAEE;EACA;;AAKF;AAAA;EACE;EACA;EACA;;AAGF;AAAA;EACE;EACA;;;AAIJ;EACE;;;AAKA;AAAA;EACE;;;AAMJ;EACE;EACA;EACA;EACA;;;AAGF;EACE;;;AAKF;EACE;EACA;EACA;EACA;;AAEA;EACE;;;AAIJ;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAKF;EACE;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EACE;;AAEA;EACE;;;AAKN;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;;;AAMF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,YACE;;AAIF;EAEE;;AAGF;EACE;EACA;EACA,YACE;;AAIJ;EACE;;;AAKJ;EACE;EACA;EACA;;AAEA;EAEE;EACA;EACA;;;AAKJ;EACE;EACA;EACA;EACA;EACA;EACA;;AAEA;EAEE;EACA;EACA;;;AAIJ;EACE;;AAIE;EACE;;AAGF;AAAA;AAAA;EAEE;;;AAON;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;;;AAKJ;EACE;EACA;EACA;;;AAIF;EACE;;;AAIF;EACE;;;AAIF;EACE;EACA;;;AAKF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;;;AAmCJ;EA5BE;EACA;EACA;EACA;EACA;EAEA;;;AA0BF;EAhCE;EACA;EACA;EACA;EACA;EAEA;;;AA8BF;EAtBE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAkBA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;;;AAKF;EAvDE;EACA;EACA;EACA;EACA;EAEA;;;AAqDF;EA7CE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAwCA;EACA;;;AAGF;EACE;EACA;;;AAKF;EAIE;;AAEA;EACE;;AAPJ;EAUE;EACA;EAEA;EACA;EACA;EAEA;EACA;EACA;EACA;EAEA;EACA;EACA;;AAEA;EACE;;;AAMJ;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA,YACE;EAGF;EACA;EACA;;AAEA;EAEE;EACA;EACA;;;AAIJ;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA;;;AAKF;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;;;AAIJ;EACE;EACA;;AAIE;EACE;;;AAON;EACE;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;;;AAIJ;EACE;EACA;;;AAGF;EACE;EACA;;AAEA;EACE;;AAKA;AAAA;AAAA;EAEE;EACA;;;AAKN;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;;;AAKF;EACE;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;;AAEA;AAAA;EAEE;EACA;EACA;;;AAIJ;EACE;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,YACE;;AAIF;EAEE;EACA;EACA;;;AAIJ;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EAEE;;AAEA;EACE;EACA","file":"ctrls.css"}
1
+ {"version":3,"sourceRoot":"","sources":["../node_modules/@stanko/dual-range-input/dist/index.css","../src/scss/_ctrls.scss"],"names":[],"mappings":"AAAA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;;;AAEF;EACE;;;AAEF;EACE;EACA;EACA;;;AAEF;EACE;;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAEF;EACE;;;AAEF;EACE;EACA;;;AAEF;EACE;EACA;;;AAEF;EACE;EACA;;;AAEF;EACE;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;;;AAEF;EACE;;;AAEF;EACE;EACA;EACA;;;AAEF;EACE;;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAEF;EACE;;;AAEF;EACE;EACA;;;AAEF;EACE;EACA;;;AAEF;EACE;EACA;;;;AC3IF;EACE;AAAA;AAAA;EAGA;EACA;EACA;EACA;EACA;EAGA;EACA;EAEA;EACA;EAGA;EACA;EACA;EACA;EACA;EACA;EAGA;EAGA;EACA;EACA;EACA;EAGA;EACA;EACA;EAGA;EAGA;EAEA;EACA;EAEA;EACA;EAGA;EAGA;EACA;EAEA;EACA;EAEA;EACA;EACA;EACA;EAGA;EACA;EAEA;EAEA;EACA;EAEA;EAGA;EAEA;EACA;;;AAgDF;EACE;IA5CA;IAEA;IACA;IAGA;IACA;IACA;IACA;IACA;IACA;IAGA;IAGA;IACA;IACA;IACA;IAGA;IACA;IACA;IAGA;IAGA;IACA;IAEA;IAGA;IAGA;;;AASF;EAjDE;EAEA;EACA;EAGA;EACA;EACA;EACA;EACA;EACA;EAGA;EAGA;EACA;EACA;EACA;EAGA;EACA;EACA;EAGA;EAGA;EACA;EAEA;EAGA;EAGA;;;AAeF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;AAAA;AAAA;EAGE;EACA;EACA;;AAGF;AAAA;EAEE;EACA;EACA;;AAGF;EACE;EACA;;AAGF;EACE;;;AAIJ;EACE;EACA;;;AAKF;AAAA;EAEE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,YACE;;AAGF;AAAA;AAAA;EAEE;EACA;;AAKF;AAAA;EACE;EACA;EACA;;AAGF;AAAA;EACE;EACA;;;AAIJ;EACE;;;AAKA;AAAA;EACE;;;AAMJ;EACE;EACA;EACA;EACA;EACA;;;AAGF;EACE;;;AAKF;EACE;EACA;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAKF;EACE;EACA;EACA;EACA;;AAEA;EACE;;AAEA;EACE;;;AAKN;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;;;AAMF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,YACE;;AAIF;EAEE;;AAGF;EACE;EACA;EACA,YACE;;AAIJ;EACE;;;AAKJ;EACE;EACA;EACA;;AAEA;EAEE;EACA;EACA;;;AAKJ;EACE;EACA;EACA;EACA;EACA;EACA;;AAEA;EAEE;EACA;EACA;;;AAIJ;EACE;;AAIE;EACE;;AAGF;AAAA;AAAA;EAEE;;;AAON;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;;;AAKJ;EACE;EACA;EACA;;;AAIF;EACE;;;AAIF;EACE;;;AAIF;EACE;EACA;;;AAKF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;;;AAmCJ;EA5BE;EACA;EACA;EACA;EACA;EAEA;;;AA0BF;EAhCE;EACA;EACA;EACA;EACA;EAEA;;;AA8BF;EAtBE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAkBA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;;;AAKF;EAvDE;EACA;EACA;EACA;EACA;EAEA;;;AAqDF;EA7CE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAwCA;EACA;;;AAGF;EACE;EACA;;;AAKF;EAIE;;AAEA;EACE;;AAPJ;EAUE;EACA;EAEA;EACA;EACA;EAEA;EACA;EACA;EACA;EAEA;EACA;EACA;;AAEA;EACE;;;AAMJ;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA,YACE;EAGF;EACA;EACA;;AAEA;EAEE;EACA;EACA;;;AAIJ;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA;;;AAKF;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;;;AAIJ;EACE;EACA;;AAIE;EACE;;;AAON;EACE;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;;;AAIJ;EACE;EACA;;;AAGF;EACE;EACA;;AAEA;EACE;;AAKA;AAAA;AAAA;EAEE;EACA;;;AAKN;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;;;AAKF;EACE;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;;AAEA;AAAA;EAEE;EACA;EACA;;;AAIJ;EACE;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,YACE;;AAIF;EAEE;EACA;EACA;;;AAIJ;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EAEE;;AAEA;EACE;EACA","file":"ctrls.css"}
@@ -0,0 +1,28 @@
1
+ type Attrs = {
2
+ [key: string]: unknown;
3
+ for?: string;
4
+ children?: (HTMLElement | SVGSVGElement | string | undefined | null)[];
5
+ innerHTML?: string;
6
+ };
7
+ type SVGAttrs = {
8
+ [key: string]: unknown;
9
+ for?: string;
10
+ children?: (SVGElement | string)[];
11
+ innerHTML?: string;
12
+ };
13
+ export declare const dom: {
14
+ div: (className?: string, attrs?: Attrs) => HTMLDivElement;
15
+ span: (className?: string, attrs?: Attrs) => HTMLSpanElement;
16
+ input: (className?: string, attrs?: Attrs) => HTMLInputElement;
17
+ label: (className?: string, attrs?: Attrs) => HTMLLabelElement;
18
+ button: (className?: string, attrs?: Attrs) => HTMLButtonElement;
19
+ img: (className?: string, attrs?: Attrs) => HTMLImageElement;
20
+ figure: (className?: string, attrs?: Attrs) => HTMLElement;
21
+ figcaption: (className?: string, attrs?: Attrs) => HTMLElement;
22
+ svg: (className?: string, attrs?: SVGAttrs) => SVGSVGElement;
23
+ path: (className?: string, attrs?: SVGAttrs) => SVGPathElement;
24
+ line: (className?: string, attrs?: SVGAttrs) => SVGLineElement;
25
+ circle: (className?: string, attrs?: SVGAttrs) => SVGCircleElement;
26
+ rect: (className?: string, attrs?: SVGAttrs) => SVGRectElement;
27
+ };
28
+ export {};
@@ -0,0 +1,61 @@
1
+ // ----- DOM ----- //
2
+ const el = (tag, className = "", attrs = {}) => {
3
+ const element = document.createElement(tag);
4
+ element.className = className;
5
+ // Add children and innerHTML and remove them from attrs
6
+ if (attrs.children) {
7
+ attrs.children
8
+ // Remove falsy children
9
+ .filter(Boolean)
10
+ .forEach((child) => {
11
+ element.append(child);
12
+ });
13
+ delete attrs.children;
14
+ }
15
+ else if (attrs.innerHTML) {
16
+ element.innerHTML = attrs.innerHTML;
17
+ delete attrs.innerHTML;
18
+ }
19
+ for (const [key, value] of Object.entries(attrs)) {
20
+ element.setAttribute(key, String(value));
21
+ }
22
+ return element;
23
+ };
24
+ // ----- SVG ----- //
25
+ const svgEl = (tag, className = "", attrs = {}) => {
26
+ const element = document.createElementNS("http://www.w3.org/2000/svg", tag);
27
+ // className is deprecated for SVG elements
28
+ element.classList.add(...className.split(" ").filter(Boolean));
29
+ // Add children and innerHTML and remove them from attrs
30
+ if (attrs.children) {
31
+ attrs.children.forEach((child) => {
32
+ element.append(child);
33
+ });
34
+ delete attrs.children;
35
+ }
36
+ else if (attrs.innerHTML) {
37
+ element.innerHTML = attrs.innerHTML;
38
+ delete attrs.innerHTML;
39
+ }
40
+ for (const [key, value] of Object.entries(attrs)) {
41
+ element.setAttribute(key, String(value));
42
+ }
43
+ return element;
44
+ };
45
+ // ----- API ----- //
46
+ export const dom = {
47
+ div: (className = "", attrs = {}) => el("div", className, attrs),
48
+ span: (className = "", attrs = {}) => el("span", className, attrs),
49
+ input: (className = "", attrs = {}) => el("input", className, attrs),
50
+ label: (className = "", attrs = {}) => el("label", className, attrs),
51
+ button: (className = "", attrs = {}) => el("button", className, attrs),
52
+ img: (className = "", attrs = {}) => el("img", className, attrs),
53
+ figure: (className = "", attrs = {}) => el("figure", className, attrs),
54
+ figcaption: (className = "", attrs = {}) => el("figcaption", className, attrs),
55
+ // SVG elements
56
+ svg: (className = "", attrs = {}) => svgEl("svg", className, attrs),
57
+ path: (className = "", attrs = {}) => svgEl("path", className, attrs),
58
+ line: (className = "", attrs = {}) => svgEl("line", className, attrs),
59
+ circle: (className = "", attrs = {}) => svgEl("circle", className, attrs),
60
+ rect: (className = "", attrs = {}) => svgEl("rect", className, attrs),
61
+ };
@@ -1,5 +1,5 @@
1
1
  export declare const checkIcon = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M20 6 9 17l-5-5\"/></svg>";
2
2
  export declare const refreshIcon = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8\"/><path d=\"M21 3v5h-5\"/><path d=\"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16\"/><path d=\"M8 16H3v5\"/></svg>";
3
3
  export declare const diceIcon = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect width=\"18\" height=\"18\" x=\"3\" y=\"3\" rx=\"2\" ry=\"2\" stroke-width=\"2\"/><path d=\"M16 8h.01\"/><path d=\"M8 8h.01\"/><path d=\"M8 16h.01\"/><path d=\"M16 16h.01\"/><path d=\"M12 12h.01\"/></svg>";
4
- export declare const closeIcon = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6\"/><path d=\"M3 6h18\"/><path d=\"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\"/></svg>";
4
+ export declare const deleteIcon = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6\"/><path d=\"M3 6h18\"/><path d=\"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\"/></svg>";
5
5
  export declare const chevronUpIcon = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"m18 15-6-6-6 6\"/></svg>";
@@ -2,5 +2,5 @@
2
2
  export const checkIcon = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>`;
3
3
  export const refreshIcon = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"/><path d="M21 3v5h-5"/><path d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16"/><path d="M8 16H3v5"/></svg>`;
4
4
  export const diceIcon = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="18" x="3" y="3" rx="2" ry="2" stroke-width="2"/><path d="M16 8h.01"/><path d="M8 8h.01"/><path d="M8 16h.01"/><path d="M16 16h.01"/><path d="M12 12h.01"/></svg>`;
5
- export const closeIcon = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/><path d="M3 6h18"/><path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>`;
5
+ export const deleteIcon = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/><path d="M3 6h18"/><path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>`;
6
6
  export const chevronUpIcon = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m18 15-6-6-6 6"/></svg>`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stanko/ctrls",
3
- "version": "0.4.2",
3
+ "version": "0.4.4",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "test": "vitest",
@@ -10,7 +10,8 @@
10
10
  "build-lib": "rm -rf ./dist && tsc -p ./tsconfig-lib.json && npm run build-css",
11
11
  "parse-markdown": "node ./parse-markdown.js",
12
12
  "preview": "vite preview",
13
- "prepare": "cp ./pre-commit ./.git/hooks/pre-commit && chmod +x ./.git/hooks/pre-commit"
13
+ "prepare": "cp ./pre-commit ./.git/hooks/pre-commit && chmod +x ./.git/hooks/pre-commit",
14
+ "prepublish": "npm run build-lib"
14
15
  },
15
16
  "types": "./dist/ctrls/index.d.ts",
16
17
  "main": "./dist/ctrls/index.js",
@@ -1,12 +0,0 @@
1
- type Attrs = Record<string, string | number> & {
2
- for?: string;
3
- };
4
- export declare const dom: {
5
- el: <T extends keyof HTMLElementTagNameMap>(tag: T, className?: string, attrs?: Attrs) => HTMLElementTagNameMap[T];
6
- div: (className?: string, attrs?: Attrs) => HTMLDivElement;
7
- span: (className?: string, attrs?: Attrs) => HTMLSpanElement;
8
- input: (className?: string, attrs?: Attrs) => HTMLInputElement;
9
- label: (className?: string, attrs?: Attrs) => HTMLLabelElement;
10
- button: (className?: string, attrs?: Attrs) => HTMLButtonElement;
11
- };
12
- export {};
package/dist/ctrls/dom.js DELETED
@@ -1,16 +0,0 @@
1
- const el = (tag, className = "", attrs = {}) => {
2
- const element = document.createElement(tag);
3
- element.className = className;
4
- for (const [key, value] of Object.entries(attrs)) {
5
- element.setAttribute(key, value.toString());
6
- }
7
- return element;
8
- };
9
- export const dom = {
10
- el,
11
- div: (className = "", attrs = {}) => el("div", className, attrs),
12
- span: (className = "", attrs = {}) => el("span", className, attrs),
13
- input: (className = "", attrs = {}) => el("input", className, attrs),
14
- label: (className = "", attrs = {}) => el("label", className, attrs),
15
- button: (className = "", attrs = {}) => el("button", className, attrs),
16
- };