@excom/neutron 0.1.0

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.
Files changed (63) hide show
  1. package/.rush/temp/chunked-rush-logs/neutron.apply-exports.chunks.jsonl +1 -0
  2. package/.rush/temp/chunked-rush-logs/neutron.build_package-metas.chunks.jsonl +1 -0
  3. package/.rush/temp/operation/apply-exports/all.log +1 -0
  4. package/.rush/temp/operation/apply-exports/log-chunks.jsonl +1 -0
  5. package/.rush/temp/operation/apply-exports/state.json +3 -0
  6. package/.rush/temp/operation/build_package-metas/all.log +1 -0
  7. package/.rush/temp/operation/build_package-metas/log-chunks.jsonl +1 -0
  8. package/.rush/temp/operation/build_package-metas/state.json +3 -0
  9. package/.rush/temp/shrinkwrap-deps.json +3 -0
  10. package/config/rig.json +6 -0
  11. package/index.ts +9 -0
  12. package/package.json +45 -0
  13. package/rush-logs/neutron.apply-exports.cache.log +1 -0
  14. package/rush-logs/neutron.apply-exports.log +1 -0
  15. package/rush-logs/neutron.build_package-metas.cache.log +1 -0
  16. package/rush-logs/neutron.build_package-metas.log +1 -0
  17. package/src/command.ts +102 -0
  18. package/src/common-element.ts +377 -0
  19. package/src/constants.ts +101 -0
  20. package/src/devtools-hook.ts +93 -0
  21. package/src/lifecycle-configs.ts +304 -0
  22. package/src/neutron-element.ts +72 -0
  23. package/src/neutron-error.ts +6 -0
  24. package/src/neutron-internal.ts +550 -0
  25. package/src/neutron.ts +36 -0
  26. package/src/types/effect.types.ts +104 -0
  27. package/src/types/element.types.ts +263 -0
  28. package/src/types/index.ts +4 -0
  29. package/src/types/new.types.ts +159 -0
  30. package/src/types/shared.types.ts +25 -0
  31. package/src/utils/effect.ts +357 -0
  32. package/src/utils/element.ts +382 -0
  33. package/src/utils/index.ts +2 -0
  34. package/support/docs/COMMANDS.md +58 -0
  35. package/support/docs/COMPOSE.md +32 -0
  36. package/support/docs/DEBUG.md +11 -0
  37. package/support/docs/DEFINE.md +20 -0
  38. package/support/docs/EFFECTS.md +49 -0
  39. package/support/docs/EVENTS.md +57 -0
  40. package/support/docs/LIFECYCLES.md +69 -0
  41. package/support/docs/METHODS.md +49 -0
  42. package/support/docs/PROMISE_PROPS.md +29 -0
  43. package/support/docs/PROPS.md +64 -0
  44. package/support/docs/PROP_REACTIONS.md +35 -0
  45. package/support/docs/PROVISION.md +31 -0
  46. package/support/docs/README.md +118 -0
  47. package/support/docs/RECOMPOSE.md +70 -0
  48. package/support/docs/TYPESCRIPT.md +51 -0
  49. package/support/docs-sections.json +42 -0
  50. package/support/package-meta.json +129 -0
  51. package/support/tests/commands.test.ts +330 -0
  52. package/support/tests/common-element.test.ts +342 -0
  53. package/support/tests/devtools-hook.test.ts +209 -0
  54. package/support/tests/devtools-renderer.test.ts +125 -0
  55. package/support/tests/effects.test.ts +253 -0
  56. package/support/tests/element-config.test.ts +331 -0
  57. package/support/tests/entry.test.ts +68 -0
  58. package/support/tests/lifecycles.test.ts +489 -0
  59. package/support/tests/loop-guard.test.ts +162 -0
  60. package/support/tests/neutron.test.ts +1286 -0
  61. package/support/tests/recompose.test.ts +129 -0
  62. package/support/tests/utils.test.ts +75 -0
  63. package/tsconfig.json +5 -0
@@ -0,0 +1,263 @@
1
+ import type { CommandArgs, TCommandEvent } from "../command";
2
+ import type { NeutronInternal as TNeutronInternal } from "../neutron-internal";
3
+ import { Effector } from "./effect.types";
4
+ import { AnyFunction, PickGlobalElement } from "./shared.types";
5
+ import type { TokenList } from "@excom/kit-utils";
6
+
7
+ /** Neutron `emit` defaults. Intersect with `{ type; detail }` for element events. */
8
+ export type TEvent = CustomEvent & {
9
+ bubbles: true;
10
+ cancelable: true;
11
+ composed: true;
12
+ };
13
+
14
+ export interface NativeNElement extends HTMLElement {
15
+ // stub `_n_` for native / non-Neutron hosts
16
+ _n_: {
17
+ element: NativeNElement;
18
+ ctr?: typeof TNeutronInternal;
19
+ debug?: TNeutronInternal["debug"];
20
+ eventListeners: TNeutronInternal["eventListeners"];
21
+ disconnectedEventListeners: TNeutronInternal["disconnectedEventListeners"];
22
+ broadcastListeners: TNeutronInternal["broadcastListeners"];
23
+ disconnectedBroadcastListeners: TNeutronInternal["disconnectedBroadcastListeners"];
24
+ };
25
+ }
26
+
27
+ export type NEvent<CT, T, E extends Event = CustomEvent> = Omit<
28
+ E,
29
+ "currentTarget" | "target"
30
+ > & {
31
+ currentTarget: CT;
32
+ target: T;
33
+ };
34
+
35
+ export interface SuperAddEventListenerOptions extends AddEventListenerOptions {
36
+ target?: EventTarget;
37
+ }
38
+
39
+ export type EventListenerArgs<Fn = EventListener> = [
40
+ string,
41
+ Fn,
42
+ SuperAddEventListenerOptions?,
43
+ ];
44
+
45
+ export type NCustomEventInit = CustomEventInit & {
46
+ target?: HTMLElement;
47
+ };
48
+
49
+ export type EmitArgs = [string, NCustomEventInit?];
50
+
51
+ export type GlobalEventMap = GlobalEventHandlersEventMap &
52
+ WindowEventHandlersEventMap &
53
+ ElementEventMap;
54
+
55
+ export type PickGlobalEvent<EventName> = EventName extends keyof GlobalEventMap
56
+ ? GlobalEventMap[EventName]
57
+ : CustomEvent;
58
+
59
+ export interface TCommonElementListeners {
60
+ addListener<EventName extends keyof GlobalEventMap | string>(
61
+ name: EventName,
62
+ listener: (event: PickGlobalEvent<EventName>) => any,
63
+ opts?: SuperAddEventListenerOptions
64
+ ): void;
65
+ addBroadcastListener<EventName extends keyof GlobalEventMap | string>(
66
+ name: EventName,
67
+ listener: (event: PickGlobalEvent<EventName>) => any,
68
+ opts?: AddEventListenerOptions
69
+ ): void;
70
+ removeListener(
71
+ /* `Function` is enough here; a tighter listener type does not help. */
72
+ ...args: [string, Function, SuperAddEventListenerOptions?]
73
+ ): void;
74
+ removeBroadcastListener(
75
+ ...args: [string, Function, AddEventListenerOptions?]
76
+ ): void;
77
+ addListeners<EventName extends keyof GlobalEventMap | string>(
78
+ ...args: [
79
+ EventName,
80
+ (event: PickGlobalEvent<EventName>) => any,
81
+ SuperAddEventListenerOptions?,
82
+ ][]
83
+ ): void;
84
+ addBroadcastListeners<EventName extends keyof GlobalEventMap | string>(
85
+ ...args: [
86
+ EventName,
87
+ (event: PickGlobalEvent<EventName>) => any,
88
+ AddEventListenerOptions?,
89
+ ][]
90
+ ): void;
91
+ removeListeners(
92
+ ...args: [string, Function, SuperAddEventListenerOptions?][]
93
+ ): void;
94
+ removeBroadcastListeners(
95
+ ...args: [string, Function, AddEventListenerOptions?][]
96
+ ): void;
97
+ toggleListeners<EventName extends keyof GlobalEventMap | string>(
98
+ ...args: [
99
+ EventName,
100
+ (event: PickGlobalEvent<EventName>) => any,
101
+ boolean,
102
+ SuperAddEventListenerOptions?,
103
+ ][]
104
+ ): void;
105
+ toggleBroadcastListeners<EventName extends keyof GlobalEventMap | string>(
106
+ ...args: [
107
+ EventName,
108
+ (event: PickGlobalEvent<EventName>) => any,
109
+ boolean,
110
+ AddEventListenerOptions?,
111
+ ][]
112
+ ): void;
113
+ }
114
+
115
+ export interface TCommonElementOther {
116
+ removeAllListeners(): void;
117
+ removeAllBroadcastListeners(): void;
118
+ internal_disconnectEventListeners(): void;
119
+ internal_reconnectEventListeners(): void;
120
+ emit(...args: EmitArgs): CustomEvent;
121
+ emits(...args: EmitArgs[]): CustomEvent;
122
+ broadcast(...args: EmitArgs): CustomEvent;
123
+ broadcasts(...args: EmitArgs[]): CustomEvent;
124
+ command(...args: CommandArgs): TCommandEvent | null;
125
+ commands(...args: CommandArgs[]): (TCommandEvent | null)[];
126
+ }
127
+
128
+ export type PickRenderRootTag<Conf extends OptsConfig> =
129
+ Conf["renderRoot"] extends ConfigRenderRoot
130
+ ? PickGlobalElement<Conf["renderRoot"]["tag"]>
131
+ : never;
132
+
133
+ export type MapPropType<
134
+ T extends abstract new (...args: any) => any,
135
+ DefaultValue extends (...args: any) => any = () => null,
136
+ > = T extends typeof String
137
+ ? string | ReturnType<DefaultValue>
138
+ : T extends typeof Number
139
+ ? number | ReturnType<DefaultValue>
140
+ : T extends typeof Boolean
141
+ ? boolean
142
+ : T extends typeof TokenList
143
+ ? string[] | ReturnType<DefaultValue>
144
+ : InstanceType<T> | ReturnType<DefaultValue>;
145
+
146
+ export type PropTypeKey =
147
+ | typeof String
148
+ | typeof Number
149
+ | typeof Boolean
150
+ | typeof TokenList;
151
+
152
+ export interface OptsPropConfig {
153
+ type: PropTypeKey | Function;
154
+ notify?: "attr" | "prop" | false;
155
+ attr?: false | string;
156
+ prop?: string;
157
+ defaultValue?: () => any;
158
+ isValid?: null | ((value: any) => boolean);
159
+ get?: (
160
+ element: HTMLElement,
161
+ propStore: Record<string, unknown>,
162
+ propConfig: PropConfig
163
+ ) => unknown;
164
+ set?: (
165
+ element: HTMLElement,
166
+ propStore: Record<string, unknown>,
167
+ propConfig: PropConfig,
168
+ value: unknown
169
+ ) => void;
170
+ serialize?: (value?: unknown) => unknown;
171
+ deserialize?: (value?: unknown) => unknown;
172
+ store?: "default" | "weak";
173
+ /* TODO
174
+ * https://developer.mozilla.org/en-US/docs/Web/API/CustomStateSet
175
+ * When `element.matches()` understands custom state, add
176
+ * `{ as: "attr" | "state" }` so a prop can toggle `internals`
177
+ * (e.g. `super-input:state(invalid)`).
178
+ */
179
+ }
180
+
181
+ export type PropConfig = Required<OptsPropConfig>;
182
+
183
+ export type DefaultProps = {
184
+ isMounted: boolean;
185
+ isMoving: boolean;
186
+ isAdopted: boolean;
187
+ wasMounted: boolean;
188
+ };
189
+ export type DefaultPropName =
190
+ | "isMounted"
191
+ | "isAdopted"
192
+ | "wasMounted"
193
+ | "isMoving"
194
+ | "renderRoot";
195
+ export type DefaultPropsConfig = Record<DefaultPropName, OptsPropConfig>;
196
+ export interface DefaultConfig {
197
+ props: DefaultPropsConfig;
198
+ }
199
+
200
+ // Author-facing `Neutron({ ... })` options
201
+ export interface OptsConfig {
202
+ tag: string;
203
+ props: Record<string, PropTypeKey | OptsPropConfig | Function>;
204
+ reflectDefaultProps?: DefaultPropName[];
205
+ renderRoot?: ConfigRenderRoot;
206
+ events?: EventsConfig;
207
+ broadcasts?: EventsConfig;
208
+ definitionOpts?: ElementDefinitionOptions;
209
+ methods?: [string, AnyFunction][];
210
+ lifecycles?: Lifecycles<[string[], AnyFunction]>;
211
+ }
212
+ export type BuiltConfig = {
213
+ tag: string;
214
+ props: Record<string, PropConfig>;
215
+ reflectDefaultProps: DefaultPropName[];
216
+ renderRoot?: ConfigRenderRoot;
217
+ events: EventsConfig;
218
+ broadcasts: EventsConfig;
219
+ definitionOpts?: ElementDefinitionOptions;
220
+ methods: [string, AnyFunction][];
221
+ lifecycles: Lifecycles<[string[], AnyFunction]>;
222
+ };
223
+ export interface RuntimeConfig {
224
+ tag: string;
225
+ props: Record<string, PropConfig>;
226
+ reflectDefaultProps: DefaultPropName[];
227
+ renderRoot?: ConfigRenderRoot;
228
+ events: EventsConfig;
229
+ broadcasts: EventsConfig;
230
+ definitionOpts?: ElementDefinitionOptions;
231
+ methods: [string, Effector<any, any>][];
232
+ lifecycles: Lifecycles<[string[], Effector<any, any>]>;
233
+ }
234
+
235
+ export interface Lifecycles<T> {
236
+ constructed: T[];
237
+ connected: T[];
238
+ adopted: T[];
239
+ disconnected: T[];
240
+ error: T[];
241
+ promiseResolved: T[];
242
+ promiseRejected: T[];
243
+ broadcast: T[];
244
+ event: T[];
245
+ eventDefault: T[];
246
+ command: T[];
247
+ effect: T[];
248
+ propUnset: T[];
249
+ propSet: T[];
250
+ propChanged: T[];
251
+ }
252
+
253
+ export type ConfigRenderRoot = {
254
+ tag: keyof HTMLElementTagNameMap;
255
+ shadow?: ShadowRootMode;
256
+ defaultSlots?: boolean;
257
+ };
258
+
259
+ export interface EventsConfig {
260
+ [eventType: string]: {
261
+ prefixWithTag?: boolean;
262
+ };
263
+ }
@@ -0,0 +1,4 @@
1
+ export * from "./effect.types";
2
+ export * from "./element.types";
3
+ export * from "./new.types";
4
+ export * from "./shared.types";
@@ -0,0 +1,159 @@
1
+ import type { TCommandEvent } from "../command";
2
+ import type { BROADCAST_CHANNEL } from "../common-element";
3
+ import type { NeutronElement as TNeutronElement } from "../neutron-element";
4
+ import type { NeutronInternal as TNeutronInternal } from "../neutron-internal";
5
+ import { Effect, Effector } from "./effect.types";
6
+ import type {
7
+ BuiltConfig,
8
+ MapPropType,
9
+ NEvent,
10
+ OptsConfig,
11
+ OptsPropConfig,
12
+ PropTypeKey,
13
+ } from "./element.types";
14
+ import {
15
+ AnyFunction,
16
+ Constructor,
17
+ GuaranteedField,
18
+ NullField,
19
+ } from "./shared.types";
20
+
21
+ export type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;
22
+
23
+ export type PropsConfigObj = Record<
24
+ string,
25
+ PropTypeKey | OptsPropConfig | Function
26
+ >;
27
+
28
+ export type ElementProps<P extends PropsConfigObj> = {
29
+ [Name in keyof P]: P[Name] extends OptsPropConfig
30
+ ? P[Name]["type"] extends Constructor
31
+ ? P[Name]["defaultValue"] extends Function
32
+ ? MapPropType<P[Name]["type"], P[Name]["defaultValue"]>
33
+ : MapPropType<P[Name]["type"]>
34
+ : never
35
+ : P[Name] extends Constructor
36
+ ? MapPropType<P[Name]>
37
+ : never;
38
+ };
39
+
40
+ export type BuildProps<P extends PropsConfigObj, CT> = CT extends {}
41
+ ? Omit<ElementProps<P>, keyof CT> & CT
42
+ : ElementProps<P>;
43
+
44
+ declare const __customElement: unique symbol;
45
+
46
+ export type CustomElement<Props> = TNeutronElement &
47
+ Props & { readonly [__customElement]?: Props };
48
+
49
+ export interface ElementBuilder<
50
+ Conf extends OptsConfig,
51
+ CT,
52
+ Props = BuildProps<Conf["props"], CT>,
53
+ CE = CustomElement<Props>,
54
+ > {
55
+ CustomElement: CE;
56
+ Props: Props;
57
+ Config: Conf;
58
+ CustomTypes: CT;
59
+ builtConfig: BuiltConfig;
60
+ /**
61
+ * Type-only: merge `T` into the element type up front, so methods in a
62
+ * single `defineMethods({...})` can reference each other through
63
+ * `element`. Runtime no-op.
64
+ */
65
+ withTypes<T>(): ElementBuilder<Conf, CT & T>;
66
+ defineMethods: <
67
+ FnObj extends Record<string, Effector<CE, Effect<Props>>>,
68
+ MethodSignatures = {
69
+ [Name in keyof FnObj]: <
70
+ RestArgs extends any[] = Parameters<FnObj[Name]> extends [
71
+ any,
72
+ ...infer Rest,
73
+ ]
74
+ ? Rest
75
+ : never,
76
+ >(
77
+ ...args: RestArgs
78
+ ) => ReturnType<FnObj[Name]> extends { returns: infer T } ? T : never;
79
+ },
80
+ >(
81
+ methods: FnObj
82
+ ) => ElementBuilder<Conf, CT & MethodSignatures>;
83
+ onConstructed(fn: Effector<CE, Effect<Props>>): this;
84
+ offConstructed(fn: AnyFunction): this;
85
+ onConnected(fn: Effector<CE, Effect<Props>>): this;
86
+ offConnected(fn: AnyFunction): this;
87
+ onDisconnected(fn: Effector<CE, Effect<Props>>): this;
88
+ offDisconnected(fn: AnyFunction): this;
89
+ onAdopted(fn: Effector<CE, Effect<Props>>): this;
90
+ offAdopted(fn: AnyFunction): this;
91
+ onError(fn: Effector<CE, Effect<Props>, [Error]>): this;
92
+ offError(fn: AnyFunction): this;
93
+ onPropSet<Name extends keyof Props & keyof CE>(
94
+ name: Name,
95
+ fn: Effector<GuaranteedField<CE, Name>, Effect<Props>, [Partial<Props>]>
96
+ ): this;
97
+ offPropSet(name: keyof Props, fn: AnyFunction): this;
98
+ onPropUnset<Name extends keyof Props & keyof CE>(
99
+ name: Name,
100
+ fn: Effector<NullField<CE, Name>, Effect<Props>, [Partial<Props>]>
101
+ ): this;
102
+ offPropUnset(name: keyof Props, fn: AnyFunction): this;
103
+ onPropChanged(
104
+ name: keyof Props | (keyof Props)[],
105
+ fn: Effector<CE, Effect<Props>, [Partial<Props>]>
106
+ ): this;
107
+ offPropChanged(name: keyof Props, fn: AnyFunction): this;
108
+ onEffect(
109
+ name: (keyof Props)[],
110
+ fn: Effector<CE, Effect<Props>, [Partial<Props>]>
111
+ ): this;
112
+ offEffect(name: (keyof Props)[], fn: AnyFunction): this;
113
+ onPromiseResolved<Name extends keyof Props>(
114
+ name: Name,
115
+ fn: Effector<CE, Effect<Props>, [Record<Name, UnwrapPromise<Props[Name]>>]>
116
+ ): this;
117
+ offPromiseResolved(name: keyof Props, fn: AnyFunction): this;
118
+ onPromiseRejected<Name extends keyof Props>(
119
+ name: Name,
120
+ fn: Effector<CE, Effect<Props>, [Record<Name, Error>]>
121
+ ): this;
122
+ offPromiseRejected(name: keyof Props, fn: AnyFunction): this;
123
+ onBroadcast(
124
+ name: string,
125
+ fn: Effector<
126
+ CE,
127
+ Effect<Props>,
128
+ [
129
+ NEvent<
130
+ typeof BROADCAST_CHANNEL | null,
131
+ typeof BROADCAST_CHANNEL,
132
+ CustomEvent
133
+ >,
134
+ ]
135
+ >
136
+ ): this;
137
+ offBroadcast(name: string, fn: AnyFunction): this;
138
+ onEvent(
139
+ name: string,
140
+ fn: Effector<CE, Effect<Props>, [NEvent<CE, Element | null, CustomEvent>]>
141
+ ): this;
142
+ offEvent(name: string, fn: AnyFunction): this;
143
+ onEventDefault(
144
+ name: string,
145
+ fn: Effector<CE, Effect<Props>, [NEvent<Element | null, CE, CustomEvent>]>
146
+ ): this;
147
+ offEventDefault(name: string, fn: AnyFunction): this;
148
+ /**
149
+ * Handle a `command` event whose `command` is one of `name` (custom
150
+ * commands only: `--verb`). Runs after the dispatch, in a microtask,
151
+ * unless a listener called `preventDefault()`.
152
+ */
153
+ onCommand(
154
+ name: string | string[],
155
+ fn: Effector<CE, Effect<Props>, [NEvent<CE, CE, TCommandEvent>]>
156
+ ): this;
157
+ offCommand(name: string | string[], fn: AnyFunction): this;
158
+ define: typeof TNeutronInternal.define;
159
+ }
@@ -0,0 +1,25 @@
1
+ export type GuaranteedFields<T> = {
2
+ [P in keyof T]: NonNullable<T[P]>;
3
+ };
4
+
5
+ export type GuaranteedField<T, K extends keyof T> = T &
6
+ GuaranteedFields<Pick<T, K>>;
7
+
8
+ export type NullFields<T> = {
9
+ [P in keyof T]: null;
10
+ };
11
+ export type NullField<T, K extends keyof T> = T & NullFields<Pick<T, K>>;
12
+
13
+ export type AnyFunction<Args extends any[] = any[], R = any> = (
14
+ ...args: Args
15
+ ) => R;
16
+
17
+ export type Obj<U = {}> = Record<string, any> & U;
18
+
19
+ export type PickGlobalElement<Tag> = Tag extends keyof HTMLElementTagNameMap
20
+ ? HTMLElementTagNameMap[Tag]
21
+ : HTMLElement;
22
+
23
+ export type Constructor = abstract new (...args: any) => any;
24
+
25
+ export type ConstructorType<T> = new (...args: any) => T;