@xtia/jel 0.2.2 → 0.3.1

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
@@ -5,9 +5,12 @@ Jel is a thin layer over the DOM to simplify element structure creation, manipul
5
5
 
6
6
  See [demo/index.ts](https://github.com/tiadrop/jel-ts/blob/main/demo/index.ts) for example operation. Compare with [resulting page](https://aleta.codes/jel-ts-demo/).
7
7
 
8
- ## `$` basic use:
8
+ ## `$` Basic Use:
9
9
 
10
10
  `$.[tagname](details)` produces an element of `<tagname>`. `details` can be content of various types or a descriptor object.
11
+ ```
12
+ $ npm i @xtia/jel
13
+ ```
11
14
 
12
15
  ```ts
13
16
  import { $ } from "@xtia/jel";
@@ -44,4 +47,85 @@ body.append([
44
47
  )
45
48
  ])
46
49
 
50
+ ```
51
+
52
+ ## `DOMContent`
53
+
54
+ Content can be string, Text, HTMLElement, JelEntity or arbitrarily nested array of content. Typing as DOMContent where possible enables flexibility.
55
+
56
+ ```ts
57
+ function showDialogue(content: DOMContent) => {
58
+ const element = $.div({
59
+ classes: "dialogue",
60
+ content: [
61
+ content,
62
+ $.div({
63
+ classes: "buttons",
64
+ // content: [...]
65
+ })
66
+ ]
67
+ });
68
+ // ...
69
+ }
70
+
71
+ interface Job {
72
+ name: string;
73
+ completionMessage: DOMContent;
74
+ }
75
+
76
+ showDialogue("Hello, world");
77
+ showDialogue(["Hello, ", $.i("world")]);
78
+ showDialogue([
79
+ $.h2(`${job.name} Complete`),
80
+ $.p(job.completionMessage),
81
+ ]);
82
+ ```
83
+
84
+ ## `ElementClassDescriptor`
85
+
86
+ Element classes can be specified as string, `{ [className]: boolean }` and arbitrarily nested array thereof.
87
+
88
+ ```ts
89
+ function renderFancyButton(
90
+ caption: DOMContent,
91
+ onClick: () => void,
92
+ classes: ElementClassDescriptor = []
93
+ ) {
94
+ return $.button({
95
+ content: caption,
96
+ classes: ["fancy-button", classes],
97
+ // ...
98
+ });
99
+ }
100
+
101
+ function showDialogue(content: DOMContent, danger: boolean = false) {
102
+ const element = $.div({
103
+ // ...
104
+ classes: "dialogue",
105
+ content: [
106
+ content,
107
+ renderFancyButton("OK", close, ["ok-button", { danger }]),
108
+ ]
109
+ });
110
+ // ...
111
+ }
112
+ ```
113
+
114
+ ## Jel-Wrapped Elements
115
+
116
+ Jel wraps its elements in an interface for common operations plus an `append()` method that accepts `DOMContent`.
117
+
118
+ For other operations the element is accessible via `ent.element`:
119
+
120
+ ```ts
121
+ const div = $.div();
122
+ div.element.requestFullscreen();
123
+ ```
124
+
125
+ ## Shorthand
126
+
127
+ If you need an element with just a class, id and/or content you can use `tag#id.classes` notation, ie `$("div#someId.class1.class2", content?)`.
128
+
129
+ ```ts
130
+ showDialogue(["Hello ", $("span.green", "world")]);
47
131
  ```
package/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export type ElementClassSpec = string | Record<string, boolean> | ElementClassSpec[];
1
+ export type ElementClassDescriptor = string | Record<string, boolean> | ElementClassDescriptor[];
2
2
  export type DOMContent = number | null | string | Element | JelEntity<object, any> | Text | DOMContent[];
3
3
  export type DomEntity<T extends HTMLElement> = JelEntity<ElementAPI<T>, HTMLElementEventMap>;
4
4
  type JelConstructor<Spec, API, EventDataMap> = (spec?: Partial<Spec & CommonOptions<EventDataMap>>) => JelEntity<API, EventDataMap>;
@@ -11,17 +11,18 @@ type JelEntity<API, EventDataMap> = API & {
11
11
  on<E extends keyof EventDataMap>(eventId: E, handler: (this: JelEntity<API, EventDataMap>, data: EventDataMap[E]) => void): void;
12
12
  readonly [componentDataSymbol]: JelComponentData;
13
13
  };
14
- type Styles = Partial<{
15
- [key in keyof CSSStyleDeclaration]: string | number;
16
- }> & Record<`--${string}`, string | number>;
14
+ type StylesDescriptor = Partial<{
15
+ [key in keyof CSSStyleDeclaration]: CSSValue;
16
+ }>;
17
17
  interface ElementDescriptor {
18
- classes?: ElementClassSpec;
18
+ classes?: ElementClassDescriptor;
19
19
  content?: DOMContent;
20
20
  attribs?: Record<string, string | number | boolean>;
21
21
  on?: Partial<{
22
22
  [E in keyof HTMLElementEventMap]: (event: HTMLElementEventMap[E]) => void;
23
23
  }>;
24
- style?: Styles;
24
+ style?: StylesDescriptor;
25
+ cssVariables?: Record<string, CSSValue>;
25
26
  }
26
27
  type DomHelper = ((<T extends keyof HTMLElementTagNameMap>(tagName: T, descriptor: ElementDescriptor) => DomEntity<HTMLElementTagNameMap[T]>) & (<T extends keyof HTMLElementTagNameMap>(selector: `${T}#${string}`, content?: DOMContent) => DomEntity<HTMLElementTagNameMap[T]>) & (<T extends keyof HTMLElementTagNameMap>(selector: `${T}.${string}`, content?: DOMContent) => DomEntity<HTMLElementTagNameMap[T]>) & (<T extends keyof HTMLElementTagNameMap>(selector: T, content?: DOMContent) => DomEntity<HTMLElementTagNameMap[T]>) & (<T extends HTMLElement>(element: T) => DomEntity<T>) & {
27
28
  [T in keyof HTMLElementTagNameMap]: (descriptor: ElementDescriptor) => DomEntity<HTMLElementTagNameMap[T]>;
@@ -31,6 +32,7 @@ type DomHelper = ((<T extends keyof HTMLElementTagNameMap>(tagName: T, descripto
31
32
  type JelComponentData = {
32
33
  dom: DOMContent;
33
34
  };
35
+ type CSSValue = string | number;
34
36
  type ElementAPI<T extends HTMLElement> = {
35
37
  readonly element: T;
36
38
  content: DOMContent;
@@ -38,12 +40,28 @@ type ElementAPI<T extends HTMLElement> = {
38
40
  attribs: {
39
41
  [key: string]: string | null;
40
42
  };
41
- style: CSSStyleDeclaration;
43
+ style: StylesDescriptor & ((styles: StylesDescriptor) => void);
42
44
  innerHTML: string;
45
+ setCSSVariable(table: Record<string, CSSValue>): void;
46
+ setCSSVariable(variableName: string, value: CSSValue): void;
43
47
  qsa(selector: string): DomEntity<any>[];
44
48
  append(...content: DOMContent[]): void;
45
49
  remove(): void;
46
- };
50
+ getRect(): DOMRect;
51
+ focus(): void;
52
+ blur(): void;
53
+ } & (T extends HTMLInputElement ? {
54
+ value: string;
55
+ select(): void;
56
+ } : T extends HTMLCanvasElement ? {
57
+ width: number;
58
+ height: number;
59
+ getContext(contextId: "2d", options?: CanvasRenderingContext2DSettings): CanvasRenderingContext2D | null;
60
+ getContext(contextId: "bitmaprenderer", options?: ImageBitmapRenderingContextSettings): ImageBitmapRenderingContext | null;
61
+ getContext(contextId: "webgl", options?: WebGLContextAttributes): WebGLRenderingContext | null;
62
+ getContext(contextId: "webgl2", options?: WebGLContextAttributes): WebGL2RenderingContext | null;
63
+ getContext(contextId: string, options?: any): RenderingContext | null;
64
+ } : {});
47
65
  type OptionalKeys<T> = {
48
66
  [K in keyof T]-?: {} extends Pick<T, K> ? K : never;
49
67
  }[keyof T];
package/index.js CHANGED
@@ -13,6 +13,22 @@ var __assign = (this && this.__assign) || function () {
13
13
  Object.defineProperty(exports, "__esModule", { value: true });
14
14
  exports.$ = void 0;
15
15
  exports.definePart = definePart;
16
+ var elementProxy = {
17
+ get: function (style, prop) {
18
+ return style[prop];
19
+ },
20
+ set: function (style, prop, value) {
21
+ style[prop] = value;
22
+ return true;
23
+ },
24
+ apply: function (style, _, _a) {
25
+ var styles = _a[0];
26
+ Object.entries(styles).forEach(function (_a) {
27
+ var prop = _a[0], val = _a[1];
28
+ return style[prop] = val;
29
+ });
30
+ },
31
+ };
16
32
  function createElement(tag, descriptor) {
17
33
  if (descriptor === void 0) { descriptor = {}; }
18
34
  if (isContent(descriptor))
@@ -47,12 +63,13 @@ function createElement(tag, descriptor) {
47
63
  if (descriptor.style) {
48
64
  Object.entries(descriptor.style).forEach(function (_a) {
49
65
  var prop = _a[0], val = _a[1];
50
- if (/\-/.test(prop)) {
51
- ent.element.style.setProperty(prop, val.toString());
52
- }
53
- else {
54
- ent.element.style[prop] = val;
55
- }
66
+ ent.element.style[prop] = val;
67
+ });
68
+ }
69
+ if (descriptor.cssVariables) {
70
+ Object.entries(descriptor.cssVariables).forEach(function (_a) {
71
+ var prop = _a[0], val = _a[1];
72
+ ent.element.style.setProperty("--" + prop, val);
56
73
  });
57
74
  }
58
75
  if (descriptor.on) {
@@ -112,7 +129,13 @@ var attribsProxy = {
112
129
  set: function (element, key, value) {
113
130
  element.setAttribute(key, value);
114
131
  return true;
115
- }
132
+ },
133
+ has: function (element, key) {
134
+ return element.hasAttribute(key);
135
+ },
136
+ ownKeys: function (element) {
137
+ return element.getAttributeNames();
138
+ },
116
139
  };
117
140
  var recursiveAppend = function (parent, c) {
118
141
  if (c === null)
@@ -156,10 +179,35 @@ function getWrappedElement(element) {
156
179
  _a.remove = function () {
157
180
  element.remove();
158
181
  },
182
+ _a.setCSSVariable = function (variableNameOrTable, value) {
183
+ if (typeof variableNameOrTable == "object") {
184
+ Object.entries(variableNameOrTable).forEach(function (_a) {
185
+ var k = _a[0], v = _a[1];
186
+ element.style.setProperty("--" + k, v);
187
+ });
188
+ return;
189
+ }
190
+ element.style.setProperty("--" + variableNameOrTable, value);
191
+ },
159
192
  _a.classes = element.classList,
160
193
  _a.qsa = function (selector) {
161
194
  return [].slice.call(element.querySelectorAll(selector)).map(function (el) { return getWrappedElement(el); });
162
195
  },
196
+ _a.getRect = function () {
197
+ return element.getBoundingClientRect();
198
+ },
199
+ _a.focus = function () {
200
+ element.focus();
201
+ },
202
+ _a.blur = function () {
203
+ element.blur();
204
+ },
205
+ _a.select = function () {
206
+ element.select();
207
+ },
208
+ _a.getContext = function (mode, options) {
209
+ return element.getContext(mode, options);
210
+ },
163
211
  Object.defineProperty(_a, "content", {
164
212
  get: function () {
165
213
  return [].slice.call(element.children).map(function (child) {
@@ -186,7 +234,27 @@ function getWrappedElement(element) {
186
234
  enumerable: false,
187
235
  configurable: true
188
236
  }),
189
- _a.style = element.style,
237
+ Object.defineProperty(_a, "value", {
238
+ get: function () {
239
+ return element.value;
240
+ },
241
+ set: function (v) {
242
+ element.value = v;
243
+ },
244
+ enumerable: false,
245
+ configurable: true
246
+ }),
247
+ Object.defineProperty(_a, "width", {
248
+ get: function () {
249
+ return element.width;
250
+ },
251
+ set: function (v) {
252
+ element.width = v;
253
+ },
254
+ enumerable: false,
255
+ configurable: true
256
+ }),
257
+ _a.style = new Proxy(element.style, elementProxy),
190
258
  _a);
191
259
  elementWrapCache.set(element, domEntity_1);
192
260
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xtia/jel",
3
- "version": "0.2.2",
3
+ "version": "0.3.1",
4
4
  "repository": {
5
5
  "url": "https://github.com/tiadrop/jel-ts",
6
6
  "type": "github"