lupine.web 1.0.14

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 (94) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +3 -0
  3. package/jsx-runtime/index.js +14 -0
  4. package/jsx-runtime/package.json +16 -0
  5. package/jsx-runtime/src/index.d.ts +2 -0
  6. package/package.json +51 -0
  7. package/src/assets/themes/base-themes.ts +16 -0
  8. package/src/assets/themes/dark-themes.ts +85 -0
  9. package/src/assets/themes/index.ts +4 -0
  10. package/src/assets/themes/light-themes.ts +92 -0
  11. package/src/assets/themes/shared-themes.ts +50 -0
  12. package/src/components/button-push-animation.tsx +138 -0
  13. package/src/components/button.tsx +55 -0
  14. package/src/components/drag-refresh.tsx +110 -0
  15. package/src/components/editable-label.tsx +83 -0
  16. package/src/components/float-window.tsx +226 -0
  17. package/src/components/grid.tsx +18 -0
  18. package/src/components/html-var.tsx +41 -0
  19. package/src/components/index.ts +36 -0
  20. package/src/components/input-with-title.tsx +24 -0
  21. package/src/components/link-item.tsx +13 -0
  22. package/src/components/link-list.tsx +62 -0
  23. package/src/components/menu-bar.tsx +220 -0
  24. package/src/components/menu-item-props.tsx +10 -0
  25. package/src/components/menu-sidebar.tsx +289 -0
  26. package/src/components/message-box.tsx +44 -0
  27. package/src/components/meta-data.tsx +54 -0
  28. package/src/components/meta-description.tsx +19 -0
  29. package/src/components/meta-title.tsx +19 -0
  30. package/src/components/modal.tsx +29 -0
  31. package/src/components/notice-message.tsx +119 -0
  32. package/src/components/paging-link.tsx +100 -0
  33. package/src/components/panel.tsx +24 -0
  34. package/src/components/popup-menu.tsx +218 -0
  35. package/src/components/progress.tsx +91 -0
  36. package/src/components/redirect.tsx +19 -0
  37. package/src/components/resizable-splitter.tsx +129 -0
  38. package/src/components/select-with-title.tsx +37 -0
  39. package/src/components/spinner.tsx +100 -0
  40. package/src/components/svg.tsx +24 -0
  41. package/src/components/tabs.tsx +252 -0
  42. package/src/components/text-glow.tsx +36 -0
  43. package/src/components/text-wave.tsx +54 -0
  44. package/src/components/theme-selector.tsx +35 -0
  45. package/src/components/toggle-base.tsx +260 -0
  46. package/src/components/toggle-switch.tsx +156 -0
  47. package/src/core/bind-attributes.ts +58 -0
  48. package/src/core/bind-lang.ts +51 -0
  49. package/src/core/bind-links.ts +16 -0
  50. package/src/core/bind-ref.ts +33 -0
  51. package/src/core/bind-styles.ts +180 -0
  52. package/src/core/bind-theme.ts +51 -0
  53. package/src/core/camel-to-hyphens.ts +3 -0
  54. package/src/core/core.ts +179 -0
  55. package/src/core/index.ts +15 -0
  56. package/src/core/mount-components.ts +259 -0
  57. package/src/core/page-loaded-events.ts +16 -0
  58. package/src/core/page-router.ts +170 -0
  59. package/src/core/replace-innerhtml.ts +10 -0
  60. package/src/core/server-cookie.ts +22 -0
  61. package/src/core/web-version.ts +12 -0
  62. package/src/global.d.ts +66 -0
  63. package/src/index.ts +15 -0
  64. package/src/jsx.ts +1041 -0
  65. package/src/lib/date-utils.ts +317 -0
  66. package/src/lib/debug-watch.ts +31 -0
  67. package/src/lib/deep-merge.ts +37 -0
  68. package/src/lib/document-ready.ts +36 -0
  69. package/src/lib/dom/calculate-text-width.ts +13 -0
  70. package/src/lib/dom/cookie.ts +41 -0
  71. package/src/lib/dom/download-stream.ts +17 -0
  72. package/src/lib/dom/download.ts +12 -0
  73. package/src/lib/dom/index.ts +71 -0
  74. package/src/lib/dynamical-load.ts +138 -0
  75. package/src/lib/format-bytes.ts +11 -0
  76. package/src/lib/index.ts +17 -0
  77. package/src/lib/lite-dom.ts +227 -0
  78. package/src/lib/logger.ts +55 -0
  79. package/src/lib/message-hub.ts +105 -0
  80. package/src/lib/observable.ts +188 -0
  81. package/src/lib/promise-timeout.ts +1 -0
  82. package/src/lib/simple-storage.ts +40 -0
  83. package/src/lib/stop-propagation.ts +7 -0
  84. package/src/lib/unique-id.ts +39 -0
  85. package/src/lib/upload-file.ts +68 -0
  86. package/src/lib/web-env.ts +98 -0
  87. package/src/models/index.ts +2 -0
  88. package/src/models/simple-storage-props.ts +9 -0
  89. package/src/models/to-client-delivery-props.ts +8 -0
  90. package/src/types/css-styles.ts +814 -0
  91. package/src/types/css-types.ts +17 -0
  92. package/src/types/index.ts +6 -0
  93. package/src/types/media-query.ts +93 -0
  94. package/tsconfig.json +113 -0
@@ -0,0 +1,188 @@
1
+ // inspired by rxjs
2
+
3
+ export class Subscription {
4
+ private _unsubscribe;
5
+ constructor(unsubscribe: () => void) {
6
+ this._unsubscribe = unsubscribe;
7
+ }
8
+ unsubscribe(): void {
9
+ if (this._unsubscribe) {
10
+ this._unsubscribe();
11
+ }
12
+ }
13
+ }
14
+
15
+ export class Observable<T> {
16
+ constructor() {}
17
+ subscribe(next?: (value: T) => void, error?: (error: any) => void, complete?: () => void): Subscription {
18
+ throw new Error('subscribe is not implemented');
19
+ }
20
+ }
21
+
22
+ export class Subject<T> extends Observable<T> {
23
+ private observers: {
24
+ next?: (value: T) => void;
25
+ error?: (error: any) => void;
26
+ complete?: () => void;
27
+ }[] = [];
28
+ private isStopped = false;
29
+ private _hasError = false;
30
+ private passLastMsgWhenSubscribe;
31
+ private lastSaved: { [key: string]: T } = {};
32
+
33
+ constructor(passLastMsgWhenSubscribe = false) {
34
+ super();
35
+ this.passLastMsgWhenSubscribe = passLastMsgWhenSubscribe;
36
+ }
37
+
38
+ next(value?: T) {
39
+ if (this.isStopped) {
40
+ throw new Error('Subject is closed');
41
+ }
42
+
43
+ const len = this.observers.length;
44
+ const copy = this.observers.slice();
45
+ for (let i = 0; i < len; i++) {
46
+ const item = copy[i].next;
47
+ if (typeof item !== 'undefined' && typeof value !== 'undefined') {
48
+ item(value);
49
+ }
50
+ }
51
+ if (this.passLastMsgWhenSubscribe) {
52
+ if (typeof value !== 'undefined') {
53
+ this.lastSaved['value'] = value;
54
+ }
55
+ }
56
+ }
57
+
58
+ error(err: any) {
59
+ if (this.isStopped) {
60
+ throw new Error('Subject is closed');
61
+ }
62
+
63
+ this._hasError = true;
64
+ this.isStopped = true;
65
+ const len = this.observers.length;
66
+ const copy = this.observers.slice();
67
+ for (let i = 0; i < len; i++) {
68
+ const item = copy[i].error;
69
+ if (typeof item !== 'undefined' && typeof err !== 'undefined') {
70
+ item(err);
71
+ }
72
+ }
73
+ this.observers.length = 0;
74
+ }
75
+
76
+ complete() {
77
+ if (this.isStopped) {
78
+ throw new Error('Subject is closed');
79
+ }
80
+
81
+ this.isStopped = true;
82
+ const copy = this.observers.slice();
83
+ const len = copy.length;
84
+ for (let i = 0; i < len; i++) {
85
+ const item = copy[i].complete;
86
+ if (typeof item !== 'undefined') {
87
+ item();
88
+ }
89
+ }
90
+ if (this.observers.length != len) {
91
+ console.warn(`Subscribe count changed from ${len} to ${this.observers.length}`);
92
+ }
93
+ this.observers.length = 0;
94
+ }
95
+
96
+ hasError() {
97
+ return this._hasError;
98
+ }
99
+
100
+ private unsubscribe(observer: {}) {
101
+ const index = this.observers.findIndex((item) => item === observer);
102
+ if (index > -1) {
103
+ this.observers.splice(index, 1);
104
+ }
105
+ }
106
+
107
+ subscribe(next?: (value: T) => void, error?: (error: any) => void, complete?: () => void): Subscription {
108
+ if (this.isStopped) {
109
+ throw new Error('Subject is stopped');
110
+ }
111
+
112
+ const observer = {
113
+ next,
114
+ error,
115
+ complete,
116
+ };
117
+ this.observers.push(observer);
118
+ if (this.passLastMsgWhenSubscribe) {
119
+ if (typeof observer.next !== 'undefined' && typeof this.lastSaved['value'] !== 'undefined') {
120
+ observer.next(this.lastSaved['value']);
121
+ }
122
+ }
123
+ const ret = new Subscription(() => {
124
+ this.unsubscribe(observer);
125
+ });
126
+ return ret;
127
+ }
128
+
129
+ asObservable(): Observable<T> {
130
+ return this as Observable<T>;
131
+ }
132
+ }
133
+
134
+ // /*[TEST-START]*/
135
+ // function TEST_sample() {
136
+ // const flag = new Subject(true);
137
+ // const observable1 = flag.asObservable();
138
+ // const unsubscribeA = observable1.subscribe(
139
+ // (next) => {
140
+ // console.log('A', next);
141
+ // },
142
+ // (error) => {
143
+ // console.log('A error:', error);
144
+ // }
145
+ // );
146
+ // const unsubscribeB = observable1.subscribe(
147
+ // (next) => {
148
+ // console.log('B', next);
149
+ // },
150
+ // (error) => {
151
+ // console.log('B error:', error);
152
+ // }
153
+ // );
154
+
155
+ // flag.next('test 1');
156
+ // unsubscribeA.unsubscribe();
157
+ // flag.next('test 2');
158
+ // flag.error('error 1');
159
+ // }
160
+ // TEST_sample();
161
+ /*[TEST-END]*/
162
+
163
+ // const flag: BehaviorSubject<Date>;
164
+ // getFlag(): Observable<Date> {
165
+ // return this.flag.asObservable();
166
+ // }
167
+ // setFlag(flag) {
168
+ // this.flag.next(flag);
169
+ // }
170
+
171
+ // getAll(): Observable<string[]> {
172
+ // this.labelsSubject = new ReplaySubject(1);
173
+ // this.http.get().subscribe(result => {
174
+ // this.labelsSubject.next(result);
175
+ // });
176
+
177
+ // return new Observable<string[]>(observer => {
178
+ // this.labelsSubject.subscribe(result => {
179
+ // observer.next(result);
180
+ // observer.complete();
181
+ // }, error => {
182
+ // observer.error(error);
183
+ // });
184
+ // });
185
+ // }
186
+
187
+ // getAll().subscribe(labels => labels.push(res));
188
+ // sub.unsubscribe()
@@ -0,0 +1 @@
1
+ export const promiseTimeout = (delayMs: number) => new Promise((resolve) => setTimeout(resolve, delayMs));
@@ -0,0 +1,40 @@
1
+ // This class is used by both BE and FE (cookie for SSR).
2
+ export class SimpleStorage {
3
+ private settings: { [key: string]: string } = {};
4
+
5
+ constructor(settings: { [key: string]: string }) {
6
+ this.settings = settings;
7
+ }
8
+
9
+ contains(key: string): boolean {
10
+ return key in this.settings;
11
+ }
12
+ set(key: string, value: string) {
13
+ return (this.settings[key] = value);
14
+ }
15
+ get(key: string, defaultValue: string): string {
16
+ return key in this.settings ? this.settings[key] : defaultValue;
17
+ }
18
+ getInt(key: string, defaultValue: number): number {
19
+ if (key in this.settings) {
20
+ const i = parseInt(this.settings[key]);
21
+ if (!isNaN(i)) {
22
+ return i;
23
+ }
24
+ }
25
+ return defaultValue;
26
+ }
27
+ getBoolean(key: string, defaultValue: boolean): boolean {
28
+ return key in this.settings
29
+ ? this.settings[key] === '1' || this.settings[key].toLowerCase() === 'true'
30
+ : defaultValue;
31
+ }
32
+ getJson(key: string, defaultValue: object): object {
33
+ if (key in this.settings) {
34
+ try {
35
+ return JSON.parse(this.settings[key]);
36
+ } catch (error) {}
37
+ }
38
+ return defaultValue;
39
+ }
40
+ }
@@ -0,0 +1,7 @@
1
+ export const stopPropagation = (event: any) => {
2
+ if (!event) return;
3
+ if (event.stopPropagation) event.stopPropagation();
4
+ if (event.preventDefault) event.preventDefault();
5
+ event.cancelBubble = true;
6
+ event.returnValue = false;
7
+ };
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Sample:
3
+ * const domUniqueId = uniqueIdGenerator('lj');
4
+ * const id1 = domUniqueId();
5
+ * const id2 = domUniqueId();
6
+ * @param preKey
7
+ * @returns A function to generate Unique Ids
8
+ */
9
+ // export function uniqueIdGenerator2(preKey: string) {
10
+ // let count = 0;
11
+ // let diff = '';
12
+ // return function (reset = false): string {
13
+ // if (reset) {
14
+ // count = 0;
15
+ // diff = '';
16
+ // }
17
+ // if (count > 9999999999999999) {
18
+ // count = 0;
19
+ // diff = Math.round(new Date().getTime() / 1000).toString(36) + '-';
20
+ // }
21
+ // count++;
22
+ // return `${preKey}${diff}${count.toString(36)}`;
23
+ // };
24
+ // }
25
+
26
+ export function uniqueIdGenerator(preKey: string) {
27
+ let count = 0;
28
+ let lastKey = Math.round(new Date().getTime() / 1000).toString(36);
29
+ return function (): string {
30
+ const key = Math.round(new Date().getTime() / 1000).toString(36);
31
+ if (key !== lastKey) {
32
+ count = 0;
33
+ lastKey = key;
34
+ } else {
35
+ count++;
36
+ }
37
+ return `${preKey}${lastKey}${count.toString(36)}`;
38
+ };
39
+ }
@@ -0,0 +1,68 @@
1
+ const _saveChunkSize = {
2
+ size: 1024 * 500,
3
+ };
4
+ export const setChunkSize = (chunkSize: number) => {
5
+ _saveChunkSize.size = chunkSize;
6
+ };
7
+ export const getChunkSize = () => {
8
+ return _saveChunkSize.size;
9
+ };
10
+ export const checkUploadedFileSize = async (uploadUrl: string) => {
11
+ const response = await fetch(uploadUrl + '?check-size=1', {
12
+ method: 'POST',
13
+ });
14
+ const json = await response.json();
15
+ return json && json.size ? json.size : 0;
16
+ };
17
+
18
+ // should return { chunkNumber: number }
19
+ export const uploadFileChunk = async (
20
+ chunk: any,
21
+ chunkNumber: number,
22
+ totalChunks: number,
23
+ uploadUrl: string,
24
+ key: string
25
+ ) => {
26
+ // this must be the FE so we can use fetch
27
+ let url = uploadUrl + (uploadUrl.indexOf('?') === -1 ? '?' : '');
28
+ url += `&chunkNumber=${chunkNumber.toString()}`;
29
+ url += `&totalChunks=${totalChunks.toString()}`;
30
+ if (key) {
31
+ url += `&key=${key}`;
32
+ }
33
+ const response = await fetch(url, {
34
+ method: 'POST',
35
+ body: chunk,
36
+ });
37
+ const json = await response.json();
38
+ return json;
39
+ };
40
+
41
+ export const uploadFile = async (
42
+ file: File,
43
+ uploadUrl: string,
44
+ progressFn?: (percentage: number, chunkNumber: number, totalChunks: number) => void,
45
+ chunkSize = _saveChunkSize.size
46
+ ) => {
47
+ // const uploadedSize = await checkUploadedFileSize(uploadUrl);
48
+ let key = '';
49
+ if (file.size <= chunkSize) {
50
+ return await uploadFileChunk(file, 0, 1, uploadUrl, key);
51
+ }
52
+
53
+ const totalChunks = Math.ceil(file.size / chunkSize);
54
+ for (let i = 0; i < totalChunks; i++) {
55
+ const start = i * chunkSize;
56
+ const end = Math.min((i + 1) * chunkSize, file.size);
57
+ const chunk = file.slice(start, end);
58
+ const uploaded = await uploadFileChunk(chunk, i, totalChunks, uploadUrl, key);
59
+ if (!uploaded || uploaded.chunkNumber === i.toString() || !uploaded.key) {
60
+ return false;
61
+ }
62
+ key = uploaded.key;
63
+ if (progressFn) {
64
+ progressFn(Math.round(((i + 1) / totalChunks) * 100) / 100, i, totalChunks);
65
+ }
66
+ }
67
+ return true;
68
+ };
@@ -0,0 +1,98 @@
1
+ // _webEnv is from process.env and _webSetting is from config.json (public and can be changed)
2
+ // _webEnv is for env variables used by the FE
3
+ // For SSR, the initWebEnv needs to be called from server side
4
+ const _webEnv: { [key: string]: string } = {};
5
+ let _webEnvInitialized = false;
6
+ function webEnv(key: string, defaultValue: number): number;
7
+ function webEnv(key: string, defaultValue: string): string;
8
+ function webEnv(key: string, defaultValue: boolean): boolean;
9
+ function webEnv(key: string, defaultValue: object): object;
10
+ function webEnv(key: string, defaultValue: any): any {
11
+ // for SSR, the webEnv should be initialized. But for the FE, it should be initialized by the webEnv script tag
12
+ if (!_webEnvInitialized) {
13
+ const json = document.querySelector('#web-env')?.textContent;
14
+ if (json) {
15
+ _webEnvInitialized = true;
16
+ initWebEnv(JSON.parse(json));
17
+ }
18
+ }
19
+
20
+ !_webEnvInitialized && console.warn('webEnv has not been initialized yet!');
21
+ if (typeof _webEnv[key] === 'undefined') {
22
+ return defaultValue;
23
+ }
24
+
25
+ if (typeof defaultValue === 'number') {
26
+ return Number.parseInt(_webEnv[key]!);
27
+ }
28
+ if (typeof defaultValue === 'boolean') {
29
+ return _webEnv[key]!.toLocaleLowerCase() === 'true' || _webEnv[key] === '1';
30
+ }
31
+ if (typeof defaultValue === 'object') {
32
+ if (typeof _webEnv[key] === 'object') {
33
+ return _webEnv[key];
34
+ }
35
+ try {
36
+ return JSON.parse(_webEnv[key]!);
37
+ } catch (error) {
38
+ console.error(`webEnv JSON.parse error: `, error);
39
+ }
40
+ return defaultValue;
41
+ }
42
+ return _webEnv[key] || defaultValue;
43
+ }
44
+ // this is only called from the server side for SSR
45
+ function initWebEnv(webEnv: { [key: string]: string }) {
46
+ Object.assign(_webEnv, webEnv);
47
+ _webEnvInitialized = true;
48
+ }
49
+
50
+ // _webSetting is for dynamic settings that can be changed without redeploying the app
51
+ // _webSetting is json format so the returning can be an object
52
+ const _webSetting: { [key: string]: string } = {};
53
+ let _webSettingInitialized = false;
54
+ function webSetting(key: string, defaultValue: number): number;
55
+ function webSetting(key: string, defaultValue: string): string;
56
+ function webSetting(key: string, defaultValue: boolean): boolean;
57
+ function webSetting(key: string, defaultValue: object): object;
58
+ function webSetting(key: string, defaultValue: any): any {
59
+ // for SSR, the webSetting should be initialized. But for the FE, it should be initialized by the webSetting script tag
60
+ if (!_webSettingInitialized) {
61
+ const json = document.querySelector('#web-setting')?.textContent;
62
+ if (json) {
63
+ _webSettingInitialized = true;
64
+ initWebSetting(JSON.parse(json));
65
+ }
66
+ }
67
+
68
+ !_webSettingInitialized && console.warn('webSetting has not been initialized yet!');
69
+ if (typeof _webSetting[key] === 'undefined') {
70
+ return defaultValue;
71
+ }
72
+
73
+ if (typeof defaultValue === 'number') {
74
+ return Number.parseInt(_webSetting[key]!);
75
+ }
76
+ if (typeof defaultValue === 'boolean') {
77
+ return _webSetting[key]!.toLocaleLowerCase() === 'true' || _webSetting[key] === '1';
78
+ }
79
+ if (typeof defaultValue === 'object') {
80
+ if (typeof _webSetting[key] === 'object') {
81
+ return _webSetting[key];
82
+ }
83
+ try {
84
+ return JSON.parse(_webSetting[key]!);
85
+ } catch (error) {
86
+ console.error(`webSetting JSON.parse error: `, error);
87
+ }
88
+ return defaultValue;
89
+ }
90
+ return _webSetting[key] || defaultValue;
91
+ }
92
+ // this is only called from the server side for SSR
93
+ function initWebSetting(webSetting: { [key: string]: string }) {
94
+ Object.assign(_webSetting, webSetting);
95
+ _webSettingInitialized = true;
96
+ }
97
+
98
+ export { initWebEnv, webEnv, initWebSetting, webSetting };
@@ -0,0 +1,2 @@
1
+ export * from './simple-storage-props';
2
+ export * from './to-client-delivery-props';
@@ -0,0 +1,9 @@
1
+ // This class is used by both BE and FE (cookie for SSR).
2
+ export interface ISimpleStorage {
3
+ contains(key: string): boolean;
4
+ set(key: string, value: string): void;
5
+ get(key: string, defaultValue: string): string;
6
+ getInt(key: string, defaultValue: number): number;
7
+ getBoolean(key: string, defaultValue: boolean): boolean;
8
+ getJson(key: string, defaultValue: object): object;
9
+ }
@@ -0,0 +1,8 @@
1
+ import { ISimpleStorage } from './simple-storage-props';
2
+
3
+ export interface IToClientDelivery {
4
+ getWebEnv(): { [k: string]: string };
5
+ getWebSetting(): { [k: string]: string };
6
+ getServerCookie(): ISimpleStorage;
7
+ // getLang(): { [k: string]: string };
8
+ }