native-document 1.0.94 → 1.0.98

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 (52) hide show
  1. package/{src/devtools/hrm → devtools}/ComponentRegistry.js +2 -2
  2. package/devtools/index.js +8 -0
  3. package/{src/devtools/plugin.js → devtools/plugin/dev-tools-plugin.js} +2 -2
  4. package/{src/devtools/hrm/nd-vite-hot-reload.js → devtools/transformers/nd-vite-devtools.js} +16 -6
  5. package/devtools/transformers/src/transformComponentForHrm.js +74 -0
  6. package/devtools/transformers/src/transformJsFile.js +9 -0
  7. package/devtools/transformers/src/utils.js +79 -0
  8. package/devtools/widget/Widget.js +48 -0
  9. package/devtools/widget/widget.css +81 -0
  10. package/devtools/widget.js +23 -0
  11. package/dist/native-document.components.min.js +2441 -1191
  12. package/dist/native-document.dev.js +2710 -1359
  13. package/dist/native-document.dev.js.map +1 -1
  14. package/dist/native-document.devtools.min.js +1 -1
  15. package/dist/native-document.min.js +1 -1
  16. package/docs/cache.md +1 -1
  17. package/docs/core-concepts.md +1 -1
  18. package/docs/native-document-element.md +51 -15
  19. package/docs/observables.md +310 -306
  20. package/docs/state-management.md +198 -193
  21. package/index.def.js +762 -26
  22. package/package.json +1 -1
  23. package/readme.md +1 -1
  24. package/src/core/data/ObservableChecker.js +2 -0
  25. package/src/core/data/ObservableItem.js +97 -0
  26. package/src/core/data/ObservableObject.js +182 -0
  27. package/src/core/data/Store.js +364 -34
  28. package/src/core/data/observable-helpers/object.js +2 -166
  29. package/src/core/elements/anchor.js +28 -20
  30. package/src/core/elements/control/for-each.js +1 -1
  31. package/src/core/utils/formatters.js +91 -0
  32. package/src/core/utils/localstorage.js +57 -0
  33. package/src/core/utils/validator.js +0 -2
  34. package/src/core/wrappers/DocumentObserver.js +102 -31
  35. package/src/core/wrappers/ElementCreator.js +5 -0
  36. package/src/core/wrappers/NDElement.js +32 -1
  37. package/src/core/wrappers/prototypes/nd-element.transition.extensions.js +83 -0
  38. package/src/devtools.js +9 -0
  39. package/src/fetch/NativeFetch.js +5 -2
  40. package/types/elements.d.ts +580 -2
  41. package/types/nd-element.d.ts +6 -0
  42. package/types/observable.d.ts +71 -15
  43. package/types/plugins-manager.d.ts +1 -1
  44. package/types/store.d.ts +33 -6
  45. package/hrm.js +0 -7
  46. package/src/devtools/app/App.js +0 -66
  47. package/src/devtools/app/app.css +0 -0
  48. package/src/devtools/hrm/transformComponent.js +0 -129
  49. package/src/devtools/index.js +0 -18
  50. package/src/devtools/widget/DevToolsWidget.js +0 -26
  51. /package/{src/devtools/hrm → devtools/transformers/templates}/hrm.hook.template.js +0 -0
  52. /package/{src/devtools/hrm → devtools/transformers/templates}/hrm.orbservable.hook.template.js +0 -0
@@ -33,6 +33,12 @@ export interface NDElement {
33
33
  mounted(callback: (node: HTMLElement) => void): this;
34
34
  unmounted(callback: (node: HTMLElement) => boolean | void): this;
35
35
 
36
+ beforeUnmount(id: string, callback: (this: NDElement, el: HTMLElement) => void | Promise<void>): this;
37
+ transition(transitionName: string): this;
38
+ transitionIn(transitionName: string): this;
39
+ transitionOut(transitionName: string): this;
40
+ animate(animationName: string): this;
41
+
36
42
  htmlElement(): HTMLElement;
37
43
  node(): HTMLElement;
38
44
  shadow(mode: ShadowMode, style?: string | null): this;
@@ -1,7 +1,47 @@
1
- import {FilterResult, PredicateMap} from "./filters/types";
1
+ import {FilterResult, PredicateMap} from "./filters";
2
2
 
3
3
  export type Unsubscribe = () => void;
4
4
 
5
+ export type FormatType = 'currency' | 'number' | 'percent' | 'date' | 'time' | 'datetime' | 'relative' | 'plural';
6
+
7
+ export interface FormatOptions {
8
+ // currency
9
+ currency?: string;
10
+ notation?: 'standard' | 'scientific' | 'engineering' | 'compact';
11
+ minimumFractionDigits?: number;
12
+ maximumFractionDigits?: number;
13
+ // percent
14
+ decimals?: number;
15
+ // date / datetime
16
+ dateStyle?: 'full' | 'long' | 'medium' | 'short';
17
+ format?: string;
18
+ // time / datetime
19
+ hour?: '2-digit' | 'numeric';
20
+ minute?: '2-digit' | 'numeric';
21
+ second?: '2-digit' | 'numeric';
22
+ // relative
23
+ unit?: 'day' | 'week' | 'month' | 'year' | 'hour' | 'minute' | 'second';
24
+ numeric?: 'always' | 'auto';
25
+ // plural
26
+ singular?: string;
27
+ plural?: string;
28
+ }
29
+
30
+ export interface FormattersStatic {
31
+ currency(value: number, locale: string, options?: FormatOptions): string;
32
+ number(value: number, locale: string, options?: FormatOptions): string;
33
+ percent(value: number, locale: string, options?: FormatOptions): string;
34
+ date(value: Date | number, locale: string, options?: FormatOptions): string;
35
+ time(value: Date | number, locale: string, options?: FormatOptions): string;
36
+ datetime(value: Date | number, locale: string, options?: FormatOptions): string;
37
+ relative(value: Date | number, locale: string, options?: FormatOptions): string;
38
+ plural(value: number, locale: string, options?: FormatOptions): string;
39
+ [key: string]: (value: any, locale: string, options?: FormatOptions) => string;
40
+ }
41
+
42
+ export declare const Formatters: FormattersStatic;
43
+
44
+
5
45
  // Observable system type definitions
6
46
  export interface ObservableItem<T = any> {
7
47
  readonly $currentValue: T;
@@ -22,12 +62,21 @@ export interface ObservableItem<T = any> {
22
62
  on(value: T, callback: ObservableItem<boolean> | ((isActive: boolean) => void)): () => void;
23
63
 
24
64
  check<U>(callback: (value: T) => U): ObservableChecker<U>;
25
- get<U>(callback: (value: T) => U): ObservableChecker<U>;
65
+ transform<U>(callback: (value: T) => U): ObservableChecker<U>;
66
+ is<U>(callback: (value: T) => U): ObservableChecker<U>;
67
+ select<U>(callback: (value: T) => U): ObservableChecker<U>;
68
+ pluck<U>(callback: (value: T) => U): ObservableChecker<U>;
69
+ format(type: FormatType | ((value: T) => string), options?: FormatOptions): ObservableItem<string>;
70
+ get(key: string | number): any;
26
71
  when(value: T): ObservableWhen<T>;
27
72
  off(value: T, callback?: Function): void;
28
73
  once(predicate: T | ((value: T) => boolean), callback: (value: T) => void): void;
29
74
  onCleanup(callback: () => void): void;
30
75
  intercept(callback: (newValue: T, currentValue: T) => T | undefined): this;
76
+ persist(key: string, options?: {
77
+ get?: (value: any) => T;
78
+ set?: (value: T) => any;
79
+ }): this;
31
80
  disconnectAll(): void;
32
81
 
33
82
  toString(): string;
@@ -103,35 +152,42 @@ export interface ObservableArray<T> extends ObservableItem<T[]> {
103
152
  whereEvery<K extends keyof T>(fields: K[], filter: FilterResult<T[K]>): ObservableArray<T>;
104
153
  }
105
154
 
106
- export type ObservableProxy<T extends Record<string, any>> = {
155
+ export type ObservableObject<T extends Record<string, any>> = ObservableItem<T> & {
156
+ readonly __$isObservableObject: true;
107
157
  readonly __isProxy__: true;
108
- readonly $value: T;
158
+ readonly $observables: { [K in keyof T]: ObservableItem<T[K]> };
109
159
  readonly configs: ObservableConfig | null;
160
+
161
+ $load(initialValue: Partial<T>): void;
110
162
  $val(): T;
111
163
  val(): T;
112
- $get(key: string): any;
113
164
  get(key: string): any;
114
- $clone(): ObservableProxy<T>;
115
- clone(): ObservableProxy<T>;
116
- $updateWith(values: Partial<T>): void;
117
- $set(values: Partial<T>): void;
165
+ $get(key: string): any;
118
166
  set(values: Partial<T>): void;
167
+ $set(values: Partial<T>): void;
168
+ $updateWith(values: Partial<T>): void;
169
+ update(values: Partial<T>): void;
119
170
  reset(): void;
171
+ clone(): ObservableObject<T>;
172
+ $clone(): ObservableObject<T>;
120
173
  keys(): string[];
174
+ $keys(): string[];
175
+ observables(): ObservableItem<any>[];
121
176
  } & {
122
177
  [K in keyof T]: T[K] extends (infer U)[]
123
178
  ? ObservableArray<U>
124
179
  : T[K] extends Record<string, any>
125
- ? ObservableProxy<T[K]>
180
+ ? ObservableObject<T[K]>
126
181
  : ObservableItem<T[K]>;
127
182
  };
128
183
 
184
+
129
185
  export interface BatchFunction<TArgs extends any[] = any[], TReturn = any> {
130
186
  (...args: TArgs): TReturn;
131
187
  readonly $observer: ObservableItem<number>;
132
188
  }
133
189
 
134
- export type ValidComputedDependencies = Array<ObservableItem | ObservableArray<any> | ObservableChecker | ObservableProxy<any>>;
190
+ export type ValidComputedDependencies = Array<ObservableItem | ObservableArray<any> | ObservableChecker | ObservableObject<any>>;
135
191
 
136
192
  export interface AutoCleanupOptions {
137
193
  interval?: number;
@@ -148,9 +204,9 @@ export interface ObservableStatic {
148
204
  <T>(value: T, configs?: ObservableConfig | null): ObservableItem<T>;
149
205
  array<T>(target: T[] | null, configs?: ObservableConfig | null): ObservableArray<T>;
150
206
 
151
- init<T extends Record<string, any>>(value: T, configs?: ObservableConfig | null): ObservableProxy<T>;
152
- object<T extends Record<string, any>>(value: T, configs?: ObservableConfig | null): ObservableProxy<T>;
153
- json<T extends Record<string, any>>(value: T, configs?: ObservableConfig | null): ObservableProxy<T>;
207
+ init<T extends Record<string, any>>(value: T, configs?: ObservableConfig | null): ObservableObject<T>;
208
+ object<T extends Record<string, any>>(value: T, configs?: ObservableConfig | null): ObservableObject<T>;
209
+ json<T extends Record<string, any>>(value: T, configs?: ObservableConfig | null): ObservableObject<T>;
154
210
 
155
211
  computed<T>(callback: () => T, dependencies?: ValidComputedDependencies | BatchFunction): ObservableItem<T>;
156
212
  computed<T>(callback: () => T, batchFunction?: BatchFunction): ObservableItem<T>;
@@ -165,5 +221,5 @@ export interface ObservableStatic {
165
221
  getById(id: number): ObservableItem | null;
166
222
  cleanup(observable: ObservableItem): void;
167
223
  autoCleanup(enable?: boolean, options?: AutoCleanupOptions): void;
168
- arrayOfObject<T extends Record<string, any>>(data: T[]): ObservableProxy<T>[];
224
+ arrayOfObject<T extends Record<string, any>>(data: T[]): ObservableObject<T>[];
169
225
  }
@@ -1,4 +1,4 @@
1
- import {NDElement} from "./elements";
1
+ import {NDElement} from "./nd-element";
2
2
  import {ObservableItem} from "./observable";
3
3
  import { Map} from "./polyfill";
4
4
 
package/types/store.d.ts CHANGED
@@ -1,12 +1,39 @@
1
- // Store system type definitions
2
1
  import { ObservableItem } from './observable';
3
- import {Set} from "./polyfill";
2
+ import { Set } from "./polyfill";
3
+
4
+ export type StoreGroupInstance = StoreStatic & {
5
+ readonly $name: string;
6
+ };
4
7
 
5
8
  export interface StoreStatic {
6
9
  create<T>(name: string, value: T): ObservableItem<T>;
7
- use<T>(name: string): ObservableItem<T>;
8
- follow<T>(name: string): ObservableItem<T>;
10
+ createResettable<T>(name: string, value: T): ObservableItem<T>;
11
+ createComposed<T>(
12
+ name: string,
13
+ computation: () => T,
14
+ dependencies: (string | ObservableItem<any>)[]
15
+ ): ObservableItem<T>;
16
+ createPersistent<T>(name: string, value: T, localStorageKey?: string): ObservableItem<T>;
17
+ createPersistentResettable<T>(name: string, value: T, localStorageKey?: string): ObservableItem<T>;
18
+
19
+ has(name: string): boolean;
9
20
  get<T>(name: string): ObservableItem<T> | null;
10
- getWithSubscribers<T>(name: string): { observer: ObservableItem<T>; subscribers: Set<ObservableItem<T>> } | undefined;
21
+ getWithSubscribers<T>(name: string): {
22
+ observer: ObservableItem<T>;
23
+ subscribers: Set<ObservableItem<T>>;
24
+ } | null;
25
+
26
+ use<T>(name: string): ObservableItem<T>;
27
+ follow<T>(name: string): Readonly<ObservableItem<T>>;
28
+
29
+ reset(name: string): void;
11
30
  delete(name: string): void;
12
- }
31
+
32
+ group(callback: (group: StoreGroupInstance) => void): StoreGroupInstance;
33
+ group(name: string, callback: (group: StoreGroupInstance) => void): StoreGroupInstance;
34
+
35
+ readonly [key: string]: ObservableItem<any> | unknown;
36
+ }
37
+
38
+ export declare const StoreFactory: () => StoreStatic;
39
+ export declare const Store: StoreStatic;
package/hrm.js DELETED
@@ -1,7 +0,0 @@
1
- import NdViteHotReload from "./src/devtools/hrm/nd-vite-hot-reload.js";
2
- import transformComponent from "./src/devtools/hrm/transformComponent.js";
3
-
4
- export {
5
- transformComponent,
6
- NdViteHotReload,
7
- };
@@ -1,66 +0,0 @@
1
- import {Div} from "../../../elements";
2
- import DevToolsWidget from "../../devtools/widget/DevToolsWidget";
3
-
4
- export default function App() {
5
-
6
-
7
- return Div(
8
- Div({ class: 'devtools-app-panel-wrapper pin-to-right' }, [
9
- DevToolsWidget,
10
- Div({ class: 'devtools-app-panel' }),
11
- Div('Gogo Panel')
12
- ]),
13
- ).nd.closedShadow(`
14
- .devtools-app-panel-wrapper {
15
- position: fixed;
16
- width: 0px;
17
- background: red;
18
- animate: .25s linear;
19
- }
20
- .devtools-app-panel-wrapper.pin-to-right {
21
- right: 0;
22
- top: 0;
23
- bottom: 0;
24
- }
25
- .devtools-app-panel-widget {
26
- position: fixed;
27
- background: rgba(0, 0, 0, 0.8);
28
- backdrop-filter: blur(5px);
29
- padding: 2px;
30
- width: 150px;
31
- height: 30px;
32
- border-radius: 5px;
33
- border: 1px solid black;
34
- z-index: 10000009;
35
- color: white;
36
- cursor: pointer;
37
- transform: translate(-50%, -50%);
38
- display: flex;
39
- justify-content: space-between;
40
- align-items: stretch;
41
- align-content: center;
42
- }
43
- .widget-button {
44
- width: 30px;
45
- padding: 2px;
46
- background: rgba(0, 0, 0, 0.8);
47
- border: 1px solid black;
48
- display: flex;
49
- justify-content: center;
50
- align-items: center;
51
- align-content: center;
52
- color: white;
53
- border-radius: 5px;
54
- cursor: pointer;
55
- font-size: .9rem;
56
- }
57
- .widget-label {
58
- font-weight: bold;
59
- font-size: 1.5rem;
60
- flex: 1;
61
- display: flex;
62
- justify-content: center;
63
- align-items: center;
64
- }
65
- `);
66
- }
File without changes
@@ -1,129 +0,0 @@
1
- import fs from 'node:fs';
2
- import path from 'node:path';
3
- // import { parse } from '@babel/parser';
4
- import MagicString from 'magic-string';
5
-
6
- import { fileURLToPath } from 'node:url';
7
- import { parse } from '@babel/parser';
8
- import { default as traverse } from '@babel/traverse';
9
-
10
- const __filename = fileURLToPath(import.meta.url);
11
- const __dirname = path.dirname(__filename);
12
-
13
- const renameImportedObservables = (content, match) => {
14
- let isObservableFound = false;
15
- let isObservableShortFound = false;
16
- const transformedContentArray = match.split(',').map(item => {
17
- let trimmed = item.trim();
18
-
19
- if (trimmed === 'Observable') {
20
- isObservableFound = true;
21
- return 'Observable as __OriginalObservable__';
22
- }
23
- if (trimmed === '$') {
24
- isObservableShortFound = true;
25
- return '$ as __$__';
26
- }
27
-
28
- return ` ${trimmed}`;
29
- });
30
- if(!isObservableFound && isObservableShortFound) {
31
- transformedContentArray.push('Observable as __OriginalObservable__')
32
- }
33
- const transformedContent = transformedContentArray.join(', ');
34
-
35
- return `import {${transformedContent} } from 'native-document'`;
36
- };
37
-
38
- function transformObservableImports(code, params) {
39
- const renameImportationCode = code.replace(/import\s+\{([^}]+?)\}\s+from\s+['"]native-document['"]/g, renameImportedObservables);
40
- const isRenamed = renameImportationCode !== code;
41
-
42
- const s = new MagicString(renameImportationCode);
43
- if(isRenamed) {
44
- //Todo: move this code outside the function
45
- const hrmObservableHookTemplate = fs.readFileSync(__dirname + '/hrm.orbservable.hook.template.js', 'utf8');
46
- s.append(template(
47
- hrmObservableHookTemplate,
48
- params ?? {}
49
- ));
50
- }
51
-
52
- return s.toString();
53
- }
54
-
55
- function transformObservableDeclarations(code) {
56
- const regex = /(const|let|var)\s+([\w$]+)\s*=\s*(\$|Observable)(\.(?:init|array|json))?\s*\(/g;
57
-
58
- return code.replace(regex, (match, varType, varName, caller, method) => {
59
- const obsName = method ? `${caller}${method}` : 'Observable';
60
- return `${varType} ${varName} = ${obsName}('${varName}', arguments[arguments.length - 1], `;
61
- });
62
- }
63
-
64
- function template(code, params) {
65
- let codeFormatted = code;
66
- for(const key in params) {
67
- codeFormatted = codeFormatted.replace(new RegExp("\\$\{"+key+"}", 'ig'), params[key]);
68
- }
69
- return codeFormatted;
70
- }
71
-
72
- export default function transformComponent(id, code, options) {
73
- let hasDefaultExport = false;
74
- let componentName = null;
75
- let exportStart = 0;
76
- let exportEnd = 0;
77
- // TODO: move this line outside the function
78
- const hrmHookTemplate = fs.readFileSync(__dirname + '/hrm.hook.template.js', 'utf8');
79
- const formattedCode = transformObservableDeclarations(
80
- transformObservableImports(code, { id, ...options }),
81
- );
82
- const s = new MagicString(formattedCode);
83
- const codeParsed = parse(formattedCode, {
84
- sourceType: 'module',
85
- plugins: []
86
- });
87
-
88
- traverse.default(codeParsed, {
89
- ExportDefaultDeclaration(path) {
90
- hasDefaultExport = true;
91
- const declaration = path.node.declaration;
92
-
93
- if (declaration.id) {
94
- componentName = declaration.id.name;
95
- } else if (declaration.type === 'Identifier') {
96
- componentName = declaration.name;
97
- } else {
98
- componentName = 'AnonymousComponent';
99
- }
100
-
101
- exportStart = path.node.start;
102
- exportEnd = path.node.end;
103
- },
104
- });
105
- if (!hasDefaultExport) {
106
- return null;
107
- }
108
-
109
- const originalExport = formattedCode.slice(exportStart, exportEnd);
110
- const hrmComponentName = `__HRM_${componentName}__`;
111
- const newExport = originalExport.replace(
112
- 'export default',
113
- `const ${hrmComponentName} =`
114
- );
115
- s.overwrite(exportStart, exportEnd, newExport);
116
-
117
- const hrmHookTemplateFormatted = template(hrmHookTemplate, {
118
- id
119
- });
120
-
121
- s.prepend('import ComponentRegistry from "native-document/src/devtools/hrm/ComponentRegistry";');
122
- s.append(`export default ComponentRegistry.register('${id}', ${hrmComponentName}, { preserveState: ${options.preserveState} });`);
123
- s.append(hrmHookTemplateFormatted);
124
-
125
- return {
126
- code: s.toString(),
127
- map: s.generateMap({ source: id, hires: true })
128
- };
129
- }
@@ -1,18 +0,0 @@
1
- import App from './app/App';
2
- import {DevToolsPlugin} from "./plugin";
3
-
4
- const Devtools = (function () {
5
-
6
- return {
7
- config() {
8
- console.log('devtool init configuratzion');
9
- },
10
- init() {
11
- const app = App();
12
- document.body.parentNode.appendChild(app.$element);
13
- },
14
- plugin: DevToolsPlugin
15
- }
16
- }());
17
-
18
- export default Devtools;
@@ -1,26 +0,0 @@
1
- import {Div, Button} from "../../../elements";
2
- import {DevToolService} from "../plugin";
3
-
4
- export default function DevToolsWidget() {
5
- let shouldFollowPointer = false;
6
- const setFullScreen = () => {
7
- alert('Move to full-screen');
8
- }
9
-
10
- const $element = Div({ class: 'devtools-app-panel-widget', style: 'left: 50%; top: 95%' }, [
11
- Div({ class: 'widget-label'}, DevToolService.createdObservable),
12
- Button({ class: 'widget-button' }, 'Full').nd.onClick(setFullScreen)
13
- ]);
14
-
15
- $element.nd
16
- .onStopMouseDown(() => shouldFollowPointer = true)
17
- .onMouseUp((event) => shouldFollowPointer = false);
18
-
19
- document.addEventListener('mousemove', (event) => {
20
- if(shouldFollowPointer) {
21
- $element.style = 'left: '+event.clientX+'px; top: '+event.clientY+'px';
22
- }
23
- });
24
-
25
- return $element;
26
- };