@htmlplus/element 0.4.2 → 0.4.3

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.
@@ -1,56 +1,60 @@
1
1
  import { camelCase, paramCase } from 'change-case';
2
2
  import * as CONSTANTS from '../../constants/index.js';
3
- import { call, getMembers, isServer, parseValue, request } from '../utils/index.js';
3
+ import { call, getMembersKey, getMemberType, isServer, parseValue, request } from '../utils/index.js';
4
4
  import * as uhtml from '../vendor/uhtml.js';
5
5
  export function Element(tag) {
6
6
  return function (constructor) {
7
7
  if (isServer())
8
8
  return;
9
- const members = getMembers(constructor);
9
+ if (customElements.get(tag))
10
+ return;
11
+ const instances = new Map();
10
12
  class Plus extends HTMLElement {
11
13
  constructor() {
12
14
  super();
13
15
  this.attachShadow({ mode: 'open' });
14
16
  // TODO
15
- this.plus = new constructor();
16
- this.plus[CONSTANTS.API_HOST] = () => this;
17
- this.plus['uhtml'] = uhtml;
18
- this.plus[CONSTANTS.API_STATUS] = 'initialize';
17
+ const instance = new constructor();
18
+ instances.set(this, instance);
19
+ instance[CONSTANTS.API_HOST] = () => this;
20
+ instance['uhtml'] = uhtml;
21
+ instance[CONSTANTS.API_STATUS] = 'initialize';
19
22
  }
20
23
  static get observedAttributes() {
21
- return Object.keys(members)
22
- .filter((key) => members[key][0] != CONSTANTS.TYPE_FUNCTION)
23
- .map((key) => paramCase(key));
24
+ // TODO: ignore functions
25
+ return getMembersKey(constructor).map((key) => paramCase(key));
24
26
  }
25
27
  adoptedCallback() {
26
- call(this.plus, CONSTANTS.LIFECYCLE_ADOPTED);
28
+ const instance = instances.get(this);
29
+ call(instance, CONSTANTS.LIFECYCLE_ADOPTED);
27
30
  }
28
31
  // TODO
29
32
  attributeChangedCallback(name, prev, next) {
33
+ const instance = instances.get(this);
30
34
  const key = camelCase(name);
31
- const [type] = members[key];
35
+ const type = getMemberType(instance, key);
32
36
  const parsed = parseValue(next, type);
33
- this.plus[key] = parsed;
37
+ instance[key] = parsed;
34
38
  }
35
39
  connectedCallback() {
36
- this.plus[CONSTANTS.API_STATUS] = 'connected';
37
- call(this.plus, CONSTANTS.LIFECYCLE_CONNECTED);
38
- request(this.plus)
40
+ const instance = instances.get(this);
41
+ instance[CONSTANTS.API_STATUS] = 'connected';
42
+ call(instance, CONSTANTS.LIFECYCLE_CONNECTED);
43
+ request(instance)
39
44
  .then(() => {
40
- this.plus[CONSTANTS.API_STATUS] = 'loaded';
41
- call(this.plus, CONSTANTS.LIFECYCLE_LOADED);
45
+ instance[CONSTANTS.API_STATUS] = 'loaded';
46
+ call(instance, CONSTANTS.LIFECYCLE_LOADED);
42
47
  })
43
48
  .catch((error) => {
44
49
  throw error;
45
50
  });
46
51
  }
47
52
  disconnectedCallback() {
48
- this.plus[CONSTANTS.API_STATUS] = 'disconnected';
49
- call(this.plus, CONSTANTS.LIFECYCLE_DISCONNECTED);
53
+ const instance = instances.get(this);
54
+ instance[CONSTANTS.API_STATUS] = 'disconnected';
55
+ call(instance, CONSTANTS.LIFECYCLE_DISCONNECTED);
50
56
  }
51
57
  }
52
- if (customElements.get(tag))
53
- return;
54
58
  customElements.define(tag, Plus);
55
59
  };
56
60
  }
@@ -1,15 +1,25 @@
1
- import { paramCase } from 'change-case';
2
- import { defineProperty, dispatch, host } from '../utils/index.js';
1
+ import { paramCase, pascalCase } from 'change-case';
2
+ import { defineProperty, getFramework, host } from '../utils/index.js';
3
3
  export function Event(options = {}) {
4
4
  return function (target, propertyKey) {
5
5
  defineProperty(target, propertyKey, {
6
6
  get() {
7
7
  return (detail) => {
8
8
  var _a;
9
+ const element = host(this);
10
+ const framework = getFramework(element);
9
11
  (_a = options.bubbles) !== null && _a !== void 0 ? _a : (options.bubbles = false);
10
- const name = paramCase(options.name || String(propertyKey));
12
+ let name = options.name || String(propertyKey);
13
+ switch (framework) {
14
+ case 'react':
15
+ name = pascalCase(name);
16
+ break;
17
+ default:
18
+ name = paramCase(name);
19
+ break;
20
+ }
11
21
  const event = new CustomEvent(name, Object.assign(Object.assign({}, options), { detail }));
12
- dispatch(host(this), event);
22
+ element.dispatchEvent(event);
13
23
  return event;
14
24
  };
15
25
  }
@@ -1,11 +1,11 @@
1
1
  import { paramCase } from 'change-case';
2
2
  import * as CONSTANTS from '../../constants/index.js';
3
- import { defineProperty, getMembers, host, parseValue, request, updateAttribute, appendToMethod } from '../utils/index.js';
3
+ import { defineProperty, getMemberType, host, parseValue, request, updateAttribute, appendToMethod } from '../utils/index.js';
4
4
  export function Property(options) {
5
5
  return function (target, propertyKey) {
6
6
  const name = String(propertyKey);
7
7
  const attribute = paramCase(name);
8
- const type = getMembers(target)[name][0];
8
+ const type = getMemberType(target, name);
9
9
  const values = new Map();
10
10
  function get() {
11
11
  return values.get(this);
@@ -1,2 +1 @@
1
- import { PlusElement } from '../../types/index.js';
2
- export declare const appendToMethod: (target: PlusElement, propertyKey: PropertyKey, handler: (this: any, args: Array<any>) => void) => void;
1
+ export declare const appendToMethod: (target: any, propertyKey: PropertyKey, handler: (this: any, args: Array<any>) => void) => void;
@@ -1,2 +1 @@
1
- import { PlusElement } from '../../types/index.js';
2
- export declare const call: (target: PlusElement, key: string, ...args: Array<any>) => any;
1
+ export declare const call: (target: any, key: string, ...args: Array<any>) => any;
@@ -1,10 +1,5 @@
1
1
  interface Options {
2
- event?: OptionsEvent;
3
2
  }
4
- interface OptionsEvent {
5
- dispatch?: (target: OptionsEventTarget, event: Event) => boolean;
6
- }
7
- declare type OptionsEventTarget = Window | Document | Element;
8
3
  export declare const getConfig: () => Options;
9
4
  export declare const setConfig: (config: Options) => void;
10
5
  export {};
@@ -1,4 +1,3 @@
1
- // TODO
2
1
  let options = {};
3
2
  export const getConfig = () => {
4
3
  return options;
@@ -0,0 +1 @@
1
+ export declare const getFramework: (target: HTMLElement) => string | undefined;
@@ -0,0 +1,12 @@
1
+ export const getFramework = (target) => {
2
+ const keys = Object.keys(target);
3
+ const has = (key) => keys.some((key) => key.startsWith(key));
4
+ if (has('__zone_symbol__'))
5
+ return 'angular';
6
+ if (has('__react'))
7
+ return 'react';
8
+ if (has('__svelte'))
9
+ return 'svelte';
10
+ if (has('__vnode'))
11
+ return 'vue';
12
+ };
@@ -0,0 +1,2 @@
1
+ import { PlusElement } from '../../types/index.js';
2
+ export declare const getMemberType: (target: PlusElement, key: string) => string;
@@ -0,0 +1,5 @@
1
+ import * as CONSTANTS from '../../constants/index.js';
2
+ export const getMemberType = (target, key) => {
3
+ var _a;
4
+ return (_a = (target.constructor[CONSTANTS.STATIC_MEMBERS] || target[CONSTANTS.STATIC_MEMBERS] || {})[key]) === null || _a === void 0 ? void 0 : _a[0];
5
+ };
@@ -0,0 +1,2 @@
1
+ import { PlusElement } from '../../types/index.js';
2
+ export declare const getMembersKey: (target: PlusElement) => string[];
@@ -0,0 +1,4 @@
1
+ import * as CONSTANTS from '../../constants/index.js';
2
+ export const getMembersKey = (target) => {
3
+ return Object.keys(target.constructor[CONSTANTS.STATIC_MEMBERS] || target[CONSTANTS.STATIC_MEMBERS] || {});
4
+ };
@@ -2,12 +2,15 @@ export * from './appendToMethod.js';
2
2
  export * from './call.js';
3
3
  export * from './config.js';
4
4
  export * from './defineProperty.js';
5
- export * from './event.js';
6
- export * from './getMembers.js';
5
+ export * from './getFramework.js';
6
+ export * from './getMembersKey.js';
7
+ export * from './getMemberType.js';
7
8
  export * from './getStyles.js';
8
9
  export * from './host.js';
9
10
  export * from './isEvent.js';
10
11
  export * from './isServer.js';
12
+ export * from './off.js';
13
+ export * from './on.js';
11
14
  export * from './parseValue.js';
12
15
  export * from './request.js';
13
16
  export * from './sync.js';
@@ -2,12 +2,15 @@ export * from './appendToMethod.js';
2
2
  export * from './call.js';
3
3
  export * from './config.js';
4
4
  export * from './defineProperty.js';
5
- export * from './event.js';
6
- export * from './getMembers.js';
5
+ export * from './getFramework.js';
6
+ export * from './getMembersKey.js';
7
+ export * from './getMemberType.js';
7
8
  export * from './getStyles.js';
8
9
  export * from './host.js';
9
10
  export * from './isEvent.js';
10
11
  export * from './isServer.js';
12
+ export * from './off.js';
13
+ export * from './on.js';
11
14
  export * from './parseValue.js';
12
15
  export * from './request.js';
13
16
  export * from './sync.js';
@@ -0,0 +1 @@
1
+ export declare const off: (target: Window | Document | Element, type: string, handler: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions) => void;
@@ -0,0 +1,3 @@
1
+ export const off = (target, type, handler, options) => {
2
+ target.removeEventListener(type, handler, options);
3
+ };
@@ -0,0 +1 @@
1
+ export declare const on: (target: Window | Document | Element, type: string, handler: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions) => void;
@@ -0,0 +1,3 @@
1
+ export const on = (target, type, handler, options) => {
2
+ target.addEventListener(type, handler, options);
3
+ };
@@ -11,10 +11,12 @@ export const request = (target, state) => {
11
11
  return run(state);
12
12
  run = task({
13
13
  canStart: (states, state) => {
14
- return /* hasChange */ true;
14
+ // TODO: hasChange
15
+ return true;
15
16
  },
16
17
  canRun: (states) => {
17
- return /* shouldUpdate */ true;
18
+ // TODO: shouldUpdate
19
+ return true;
18
20
  },
19
21
  run: (states) => {
20
22
  call(target, CONSTANTS.LIFECYCLE_UPDATE, states);
@@ -1,5 +1,6 @@
1
- import { on, off } from './event.js';
2
1
  import { isEvent } from './isEvent.js';
2
+ import { off } from './off.js';
3
+ import { on } from './on.js';
3
4
  import { toEvent } from './toEvent.js';
4
5
  import { updateAttribute } from './updateAttribute.js';
5
6
  export const sync = (node) => {
@@ -1,5 +1,5 @@
1
1
  export const task = (options) => {
2
- let states, isPending, updatePromise;
2
+ let isPending, states, updatePromise;
3
3
  const run = (state) => {
4
4
  const newStates = Object.assign({}, states, state);
5
5
  if (options.canStart && !options.canStart(newStates, state))
@@ -4,6 +4,7 @@ import { print, visitor } from '../utils/index.js';
4
4
  const defaults = {
5
5
  typings: true
6
6
  };
7
+ // TODO: support {variable && jsxElement}
7
8
  export const customElement = (options) => {
8
9
  const name = 'customElement';
9
10
  options = Object.assign({}, defaults, options);
@@ -17,6 +18,17 @@ export const customElement = (options) => {
17
18
  path.node.body.body.unshift(t.classProperty(t.identifier('uhtml')));
18
19
  }
19
20
  });
21
+ // replace className
22
+ visitor(ast, {
23
+ JSXAttribute(path) {
24
+ if (path.node.name.name != 'className')
25
+ return;
26
+ const hasClass = path.parentPath.node.attributes.some((attribute) => attribute.name.name == 'class');
27
+ if (hasClass)
28
+ return path.remove();
29
+ path.replaceWith(t.jsxAttribute(t.jsxIdentifier('class'), path.node.value));
30
+ }
31
+ });
20
32
  // jsx to uhtml syntax
21
33
  visitor(ast, {
22
34
  JSXAttribute: {
@@ -105,7 +117,9 @@ export const customElement = (options) => {
105
117
  visitor(ast, {
106
118
  Program(path) {
107
119
  path.node.body.push(Object.assign(t.tsModuleDeclaration(t.identifier('global'), t.tsModuleBlock([
108
- t.tsInterfaceDeclaration(t.identifier(context.componentInterfaceName), null, [], t.tsInterfaceBody([
120
+ t.tsInterfaceDeclaration(t.identifier(context.componentInterfaceName), null, [
121
+ t.tSExpressionWithTypeArguments(t.identifier('HTMLElement')) // TODO
122
+ ], t.tsInterfaceBody([
109
123
  ...context.classProperties.map((property) => Object.assign(t.tSPropertySignature(property.key, property.typeAnnotation), {
110
124
  optional: property.optional,
111
125
  leadingComments: property.leadingComments
@@ -1,6 +1,3 @@
1
- /* eslint-disable */
2
- /* tslint:disable */
3
-
4
1
  /**************************************************
5
2
  * THIS FILE IS AUTO-GENERATED, DO NOT EDIT MANUALY
6
3
  **************************************************/
@@ -1,13 +1,9 @@
1
- /* eslint-disable */
2
- /* tslint:disable */
3
-
4
1
  /**************************************************
5
2
  * THIS FILE IS AUTO-GENERATED, DO NOT EDIT MANUALY
6
3
  **************************************************/
7
4
 
8
5
  import { proxy } from '../proxy';
9
6
 
10
- {{!-- import { {{importerComponent.root}} as Component } from '{{importerComponent.source}}'; --}}
11
7
  import '{{importerComponent.source}}';
12
8
  import type { {{importerComponentType.root}} as Type } from '{{importerComponentType.source}}';
13
9
 
@@ -159,13 +159,13 @@ const setEvent = (element: Element, name: string, handler: EventHandlerType) =>
159
159
 
160
160
  const previous = events[name];
161
161
 
162
- previous && element.removeEventListener(name, previous);
162
+ previous && element.removeEventListener(paramCase(name), previous);
163
163
 
164
164
  function callback(event: Event) {
165
165
  handler && handler.call(this, event);
166
166
  }
167
167
 
168
- element.addEventListener(name, (events[name] = callback));
168
+ element.addEventListener(paramCase(name), (events[name] = callback));
169
169
  };
170
170
 
171
171
  const setProps = <ElementType>(element: ElementType, props: PropsType<ElementType>, extra: ExtraType) => {
@@ -243,7 +243,7 @@ export const proxy = <ElementType, PropType>(
243
243
  Object.keys(events).forEach((name) => {
244
244
  const handler = events[name];
245
245
 
246
- (this.element as any).removeEventListener(name, handler);
246
+ (this.element as any).removeEventListener(paramCase(name), handler);
247
247
  });
248
248
 
249
249
  delete this.element['$events'];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@htmlplus/element",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
4
4
  "license": "MIT",
5
5
  "author": "Masood Abdolian <m.abdolian@gmail.com>",
6
6
  "description": "Compiler of HTMLPlus",
@@ -1,5 +0,0 @@
1
- declare type Target = Window | Document | Element;
2
- export declare const dispatch: (target: Target, event: Event) => boolean;
3
- export declare const on: (target: Target, type: string, handler: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions) => void;
4
- export declare const off: (target: Target, type: string, handler: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions) => void;
5
- export {};
@@ -1,11 +0,0 @@
1
- import { getConfig } from './config.js';
2
- export const dispatch = (target, event) => {
3
- var _a, _b;
4
- return ((_b = (_a = getConfig().event) === null || _a === void 0 ? void 0 : _a.dispatch) === null || _b === void 0 ? void 0 : _b.call(_a, target, event)) || target.dispatchEvent(event);
5
- };
6
- export const on = (target, type, handler, options) => {
7
- target.addEventListener(type, handler, options);
8
- };
9
- export const off = (target, type, handler, options) => {
10
- target.removeEventListener(type, handler, options);
11
- };
@@ -1,2 +0,0 @@
1
- import { PlusElement } from '../../types/index.js';
2
- export declare const getMembers: (target: PlusElement) => any;
@@ -1,5 +0,0 @@
1
- import * as CONSTANTS from '../../constants/index.js';
2
- export const getMembers = (target) => {
3
- var _a;
4
- return (_a = target.constructor[CONSTANTS.STATIC_MEMBERS]) !== null && _a !== void 0 ? _a : target[CONSTANTS.STATIC_MEMBERS];
5
- };