lupine.web 1.1.3 → 1.1.5

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 (41) hide show
  1. package/README.md +66 -3
  2. package/jsx-runtime/index.js +14 -14
  3. package/jsx-runtime/package.json +16 -16
  4. package/jsx-runtime/src/index.d.ts +2 -2
  5. package/package.json +53 -52
  6. package/src/core/bind-attributes.ts +61 -61
  7. package/src/core/bind-lang.ts +52 -52
  8. package/src/core/bind-links.ts +26 -16
  9. package/src/core/bind-meta.tsx +52 -52
  10. package/src/core/bind-ref.ts +51 -51
  11. package/src/core/bind-styles.ts +239 -239
  12. package/src/core/bind-theme.ts +53 -53
  13. package/src/core/camel-to-hyphens.ts +3 -3
  14. package/src/core/export-lupine.ts +80 -80
  15. package/src/core/index.ts +17 -17
  16. package/src/core/initialize.ts +116 -116
  17. package/src/core/mount-component.ts +72 -68
  18. package/src/core/page-loaded-events.ts +16 -16
  19. package/src/core/page-router.ts +180 -180
  20. package/src/core/render-component.ts +230 -233
  21. package/src/core/replace-innerhtml.ts +23 -23
  22. package/src/core/server-cookie.ts +24 -24
  23. package/src/global.d.ts +66 -66
  24. package/src/index.ts +14 -14
  25. package/src/jsx.ts +1044 -1043
  26. package/src/lib/cookie.ts +44 -44
  27. package/src/lib/debug-watch.ts +32 -32
  28. package/src/lib/index.ts +7 -7
  29. package/src/lib/is-frontend.ts +3 -3
  30. package/src/lib/logger.ts +55 -55
  31. package/src/lib/unique-id.ts +40 -40
  32. package/src/lib/web-config.ts +79 -77
  33. package/src/lib/web-env.ts +99 -99
  34. package/src/models/index.ts +4 -4
  35. package/src/models/json-props.ts +8 -8
  36. package/src/models/simple-storage-props.ts +9 -9
  37. package/src/models/theme-props.ts +7 -7
  38. package/src/models/to-client-delivery-props.ts +8 -8
  39. package/src/styles/css-styles.ts +814 -814
  40. package/src/styles/index.ts +4 -4
  41. package/tsconfig.json +113 -113
@@ -1,51 +1,51 @@
1
- import { VNode } from '../jsx';
2
- import { mountInnerComponent, mountOuterComponent } from './mount-component';
3
- import { replaceInnerhtml } from './replace-innerhtml';
4
-
5
- export const bindRef = (type: any, newProps: any, el: Element) => {
6
- // console.log('========', newProps, el);
7
- const id = newProps._id;
8
- // newProps["ref"].id = id; // this is set at bindAttributes
9
- newProps['ref'].current = el;
10
- if (newProps['ref'].onLoad) {
11
- // setTimeout(() => newProps['ref'].onLoad(el), 0);
12
- // Promise.resolve().then(fn) will be called in the end of current event loop (quicker than setTimeout)
13
- const defer = Promise.prototype.then.bind(Promise.resolve());
14
- defer(() => newProps['ref'].onLoad(el));
15
- }
16
- if (newProps['ref'].onUnload) {
17
- (el as any)._lj = (el as any)._lj || {};
18
- (el as any)._lj.onUnload = async () => {
19
- await newProps['ref'].onUnload(el);
20
- };
21
- }
22
-
23
- /**
24
- * ref.$('selector')
25
- * @param selector
26
- * @returns Element
27
- */
28
- newProps['ref'].$ = (selector: string) => {
29
- if (selector.startsWith('&')) {
30
- return el.querySelector(`.${id}${selector.substring(1).replace(/&/g, id)}`);
31
- }
32
- return el.querySelector(`.${id} ${selector.replace(/&/g, id)}`);
33
- };
34
- newProps['ref'].$all = (selector: string) => {
35
- if (selector.startsWith('&')) {
36
- return el.querySelectorAll(`.${id}${selector.substring(1).replace(/&/g, id)}`);
37
- }
38
- return el.querySelectorAll(`.${id} ${selector.replace(/&/g, id)}`);
39
- };
40
-
41
- newProps['ref'].mountInnerComponent = async (content: string | VNode<any>) => {
42
- if (typeof content === 'object' && content.type && content.props) {
43
- await mountInnerComponent(el, content);
44
- } else {
45
- await replaceInnerhtml(el, content as string);
46
- }
47
- };
48
- newProps['ref'].mountOuterComponent = async (content: VNode<any>) => {
49
- await mountOuterComponent(el, content);
50
- };
51
- };
1
+ import { VNode } from '../jsx';
2
+ import { mountInnerComponent, mountOuterComponent } from './mount-component';
3
+ import { replaceInnerhtml } from './replace-innerhtml';
4
+
5
+ export const bindRef = (type: any, newProps: any, el: Element) => {
6
+ // console.log('========', newProps, el);
7
+ const id = newProps._id;
8
+ // newProps["ref"].id = id; // this is set at bindAttributes
9
+ newProps['ref'].current = el;
10
+ if (newProps['ref'].onLoad) {
11
+ // setTimeout(() => newProps['ref'].onLoad(el), 0);
12
+ // Promise.resolve().then(fn) will be called in the end of current event loop (quicker than setTimeout)
13
+ const defer = Promise.prototype.then.bind(Promise.resolve());
14
+ defer(() => newProps['ref'].onLoad(el));
15
+ }
16
+ if (newProps['ref'].onUnload) {
17
+ (el as any)._lj = (el as any)._lj || {};
18
+ (el as any)._lj.onUnload = async () => {
19
+ await newProps['ref'].onUnload(el);
20
+ };
21
+ }
22
+
23
+ /**
24
+ * ref.$('selector')
25
+ * @param selector
26
+ * @returns Element
27
+ */
28
+ newProps['ref'].$ = (selector: string) => {
29
+ if (selector.startsWith('&')) {
30
+ return el.querySelector(`.${id}${selector.substring(1).replace(/&/g, id)}`);
31
+ }
32
+ return el.querySelector(`.${id} ${selector.replace(/&/g, id)}`);
33
+ };
34
+ newProps['ref'].$all = (selector: string) => {
35
+ if (selector.startsWith('&')) {
36
+ return el.querySelectorAll(`.${id}${selector.substring(1).replace(/&/g, id)}`);
37
+ }
38
+ return el.querySelectorAll(`.${id} ${selector.replace(/&/g, id)}`);
39
+ };
40
+
41
+ newProps['ref'].mountInnerComponent = async (content: string | VNode<any>) => {
42
+ if (typeof content === 'object' && content.type && content.props) {
43
+ await mountInnerComponent(el, content);
44
+ } else {
45
+ await replaceInnerhtml(el, content as string);
46
+ }
47
+ };
48
+ newProps['ref'].mountOuterComponent = async (content: VNode<any>) => {
49
+ await mountOuterComponent(el, content);
50
+ };
51
+ };
@@ -1,239 +1,239 @@
1
- import { uniqueIdGenerator } from 'lupine.components';
2
- import { CssProps } from '../jsx';
3
- import { getCurrentTheme, themeCookieName } from './bind-theme';
4
- import { camelToHyphens } from './camel-to-hyphens';
5
- // import { bindPageResetEvent } from './page-reset-events';
6
- import { bindPageLoadedEvent } from './page-loaded-events';
7
-
8
- const wrapCss = (className: string, cssText: string, mediaQuery?: string) => {
9
- // if (!className) {
10
- // console.warn(`No class name is provided for ${cssText}`);
11
- // }
12
- let cssTextWrap = className ? `${className}{${cssText}}` : cssText;
13
- if (mediaQuery) {
14
- cssTextWrap = `${mediaQuery}{${cssTextWrap}}`;
15
- }
16
- return cssTextWrap;
17
- };
18
-
19
- const processStyleValue = (style: CssProps) => {
20
- return Object.keys(style)
21
- .map((key) => key.trim())
22
- .map((key) => {
23
- const noOutput =
24
- (style[key] != null && typeof style[key] === 'object') ||
25
- typeof style[key] === 'undefined' ||
26
- style[key] === '';
27
- return noOutput ? '' : `${camelToHyphens(key)}:${style[key]};`;
28
- })
29
- .join('');
30
- };
31
-
32
- const updateOneBlock = (css: string[], cssTemp: string[], className: string, mediaQuery?: string) => {
33
- if (cssTemp.length > 0) {
34
- const cssText = wrapCss(className, cssTemp.join(''), mediaQuery);
35
- css.push(cssText);
36
- cssTemp.length = 0;
37
- }
38
- };
39
-
40
- const processStyleSub = (
41
- topUniqueClassName: string,
42
- classSelector: string,
43
- style: CssProps,
44
- mediaQuery?: string
45
- ): string[] => {
46
- const outClassName = classSelector
47
- .split(',')
48
- .map((key0) => key0.trim())
49
- .map((key0) => {
50
- return (key0.startsWith('&') ? `${classSelector}${key0.substring(1)}` : key0).replace(/&/g, topUniqueClassName);
51
- })
52
- .join(',');
53
- const css: string[] = [];
54
- const cssTemp: string[] = [];
55
- for (let i in style) {
56
- const value = style[i];
57
- if (value === null || typeof value !== 'object') {
58
- if (value !== '' && typeof value !== 'undefined') {
59
- if (!classSelector) {
60
- console.warn(`No className is defined for: ${camelToHyphens(i)}:${value};`);
61
- }
62
- cssTemp.push(`${camelToHyphens(i)}:${value};`);
63
- }
64
- } else {
65
- updateOneBlock(css, cssTemp, outClassName, mediaQuery);
66
-
67
- if (i.startsWith('@keyframes')) {
68
- const cssText = Object.keys(value)
69
- .map((stageKey) => stageKey + '{' + processStyleValue(value[stageKey] as CssProps) + '}')
70
- .join('');
71
- css.push(`${i}{${cssText}}`);
72
- } else if (i.startsWith('@media')) {
73
- const ret = processStyleSub(topUniqueClassName, classSelector, value, i);
74
- css.push(...ret);
75
- } else {
76
- // '&:hover, &.open': {
77
- // '>.d1, .d2': {...},
78
- // }, ==>
79
- // &:hover >.d1, &:hover >.d2, &.open >.d1, &.open .d2
80
-
81
- // '.aa': {
82
- // '&:hover': {...},
83
- // '.bb': {...},
84
- // }, ==>
85
- // .aa:hover, .aa .bb
86
- const newClassSelector = !classSelector
87
- ? i
88
- : classSelector
89
- .split(',')
90
- .map((key0) => key0.trim())
91
- .map((key0) => {
92
- return i
93
- .split(',')
94
- .map((key) => key.trim())
95
- .map((key) => {
96
- // not needed to "+" as them share same parents?
97
- // return key.split('+').map(key2 => key2.startsWith('&') ? key0 + key2.substring(1) : key0 + ' ' + key2).join('+');
98
- // return key.startsWith('&') ? key0 + key.substring(1) : key0 + ' ' + key;
99
- const newKey = key.startsWith('&') ? key0 + key.substring(1) : key0 + ' ' + key;
100
- return newKey.replace(/&/g, topUniqueClassName);
101
- })
102
- .join(',');
103
- })
104
- .join(',');
105
- const ret = processStyleSub(topUniqueClassName, newClassSelector, value, mediaQuery);
106
- css.push(...ret);
107
- }
108
- }
109
- }
110
- updateOneBlock(css, cssTemp, outClassName, mediaQuery);
111
- return css;
112
- };
113
- // topUniqueClassName is used to replace '&' in className, and '.' + topUniqueClassName is used as selector in styles ".xxx {}"
114
- export const processStyle = (topUniqueClassName: string, style: CssProps): string[] => {
115
- return processStyleSub(topUniqueClassName, topUniqueClassName ? `.${topUniqueClassName}` : '', style);
116
- };
117
-
118
- // mount-components has the same name `sty-`
119
- export const updateStyles = (topUniqueClassName: string, style: CssProps) => {
120
- const el = topUniqueClassName && document.querySelector(`.${topUniqueClassName}`);
121
- if (el) {
122
- const cssText = processStyle(topUniqueClassName, style).join('');
123
- // if the first child is style, then update it
124
- if (el.firstChild && el.firstChild.nodeName === 'STYLE') {
125
- (el.firstChild as any).innerHTML = cssText;
126
- } else {
127
- const style = document.createElement('style');
128
- style.innerHTML = cssText;
129
- // style.id = `sty-${selector}`; // sty means style, this is different from mount-components.renderComponent
130
- el.prepend(style);
131
- }
132
- } else {
133
- console.warn(`Can't find "${topUniqueClassName}" to update styles.`);
134
- }
135
- };
136
-
137
- const updateCssDom = (uniqueStyleId: string, cssText: string, cssDom: HTMLElement | null) => {
138
- if (!cssDom) {
139
- cssDom = document.createElement('style');
140
- cssDom.id = `sty-${uniqueStyleId}`;
141
- document.head.appendChild(cssDom);
142
- }
143
- cssDom.innerText = cssText;
144
- };
145
-
146
- /*
147
- If selectors in GlobalStyles have '&' at top level, then classSelector is needed, otherwise classSelector can be ''
148
- This is ok:
149
- {
150
- '.aa':{
151
- '&:hover': {...}
152
- }
153
- }
154
- This needs classSelector:
155
- {
156
- 'color': 'red', // will need and be put under .topUniqueClassName
157
- '&:hover': {...} // & will be replaced by .topUniqueClassName
158
- }
159
- Global styles including theme will not be updated once it's created.
160
- topUniqueClassName is a className or a tag name.
161
- classSelector is a selector used in styles ".xxx {}"
162
- For example, it can be like this for all elements:
163
- html { ... } or :root { ... }
164
-
165
- For themes like [data-theme="dark" i], the topUniqueClassName should be empty
166
- */
167
- export const globalStyleUniqueId = uniqueIdGenerator('g'); // g means global style
168
- const _globalStyleIds = new Map<CssProps, string>();
169
- export const getGlobalStylesId = (style: CssProps): string => {
170
- if (!_globalStyleIds.has(style)) {
171
- const id = globalStyleUniqueId();
172
- _globalStyleIds.set(style, id);
173
- }
174
- return _globalStyleIds.get(style)!;
175
- };
176
-
177
- const _globalStyle = new Map();
178
- export const bindGlobalStyle = (
179
- topUniqueClassName: string,
180
- style: CssProps,
181
- forceUpdate = false,
182
- noTopClassName = false
183
- ) => {
184
- if (typeof document !== 'undefined') {
185
- let cssDom = document.getElementById(`sty-${topUniqueClassName}`);
186
- if (forceUpdate || !cssDom) {
187
- updateCssDom(topUniqueClassName, processStyle(noTopClassName ? '' : topUniqueClassName, style).join(''), cssDom);
188
- }
189
- } else if (!_globalStyle.has(topUniqueClassName) || forceUpdate) {
190
- // don't overwrite it to have the same behavior as in the Browser
191
- _globalStyle.set(topUniqueClassName, { topUniqueClassName, noTopClassName, style });
192
- }
193
- };
194
-
195
- const generateThemeStyles = () => {
196
- const currentTheme = getCurrentTheme();
197
- const themeCss = [];
198
- for (let themeName in currentTheme.themes) {
199
- // i is for case-insensitive
200
- themeCss.push(
201
- ...processStyle('', {
202
- [`[data-theme="${themeName}" i]`]: currentTheme.themes[themeName],
203
- })
204
- );
205
- }
206
- return themeCss.join('\n');
207
- };
208
-
209
- if (typeof document !== 'undefined') {
210
- // Update theme in Browser when no SSR
211
- bindPageLoadedEvent(() => {
212
- const uniqueStyleId = themeCookieName;
213
- let cssDom = document.getElementById(`sty-${uniqueStyleId}`);
214
- if (!cssDom) {
215
- updateCssDom(uniqueStyleId, generateThemeStyles(), cssDom);
216
- }
217
- });
218
- }
219
-
220
- // can't clear global styles,because in index.tsx it is only loaded once, clear it it will be gone
221
- // const clearGlobalStyles = () => {
222
- // // reset unique id
223
- // _globalStyle.clear();
224
- // };
225
- // bindPageResetEvent(clearGlobalStyles);
226
-
227
- export const generateAllGlobalStyles = () => {
228
- const result = [];
229
-
230
- result.push(`<style id="sty-${themeCookieName}">${generateThemeStyles()}</style>`);
231
-
232
- for (let [uniqueStyleId, { topUniqueClassName, noTopClassName, style }] of _globalStyle) {
233
- const cssText = processStyle(noTopClassName ? '' : topUniqueClassName, style).join('');
234
- result.push(`<style id="sty-${uniqueStyleId}">${cssText}</style>`);
235
- }
236
-
237
- // clearGlobalStyles();
238
- return result.join('');
239
- };
1
+ import { uniqueIdGenerator } from 'lupine.components';
2
+ import { CssProps } from '../jsx';
3
+ import { getCurrentTheme, themeCookieName } from './bind-theme';
4
+ import { camelToHyphens } from './camel-to-hyphens';
5
+ // import { bindPageResetEvent } from './page-reset-events';
6
+ import { bindPageLoadedEvent } from './page-loaded-events';
7
+
8
+ const wrapCss = (className: string, cssText: string, mediaQuery?: string) => {
9
+ // if (!className) {
10
+ // console.warn(`No class name is provided for ${cssText}`);
11
+ // }
12
+ let cssTextWrap = className ? `${className}{${cssText}}` : cssText;
13
+ if (mediaQuery) {
14
+ cssTextWrap = `${mediaQuery}{${cssTextWrap}}`;
15
+ }
16
+ return cssTextWrap;
17
+ };
18
+
19
+ const processStyleValue = (style: CssProps) => {
20
+ return Object.keys(style)
21
+ .map((key) => key.trim())
22
+ .map((key) => {
23
+ const noOutput =
24
+ (style[key] != null && typeof style[key] === 'object') ||
25
+ typeof style[key] === 'undefined' ||
26
+ style[key] === '';
27
+ return noOutput ? '' : `${camelToHyphens(key)}:${style[key]};`;
28
+ })
29
+ .join('');
30
+ };
31
+
32
+ const updateOneBlock = (css: string[], cssTemp: string[], className: string, mediaQuery?: string) => {
33
+ if (cssTemp.length > 0) {
34
+ const cssText = wrapCss(className, cssTemp.join(''), mediaQuery);
35
+ css.push(cssText);
36
+ cssTemp.length = 0;
37
+ }
38
+ };
39
+
40
+ const processStyleSub = (
41
+ topUniqueClassName: string,
42
+ classSelector: string,
43
+ style: CssProps,
44
+ mediaQuery?: string
45
+ ): string[] => {
46
+ const outClassName = classSelector
47
+ .split(',')
48
+ .map((key0) => key0.trim())
49
+ .map((key0) => {
50
+ return (key0.startsWith('&') ? `${classSelector}${key0.substring(1)}` : key0).replace(/&/g, topUniqueClassName);
51
+ })
52
+ .join(',');
53
+ const css: string[] = [];
54
+ const cssTemp: string[] = [];
55
+ for (let i in style) {
56
+ const value = style[i];
57
+ if (value === null || typeof value !== 'object') {
58
+ if (value !== '' && typeof value !== 'undefined') {
59
+ if (!classSelector) {
60
+ console.warn(`No className is defined for: ${camelToHyphens(i)}:${value};`);
61
+ }
62
+ cssTemp.push(`${camelToHyphens(i)}:${value};`);
63
+ }
64
+ } else {
65
+ updateOneBlock(css, cssTemp, outClassName, mediaQuery);
66
+
67
+ if (i.startsWith('@keyframes')) {
68
+ const cssText = Object.keys(value)
69
+ .map((stageKey) => stageKey + '{' + processStyleValue(value[stageKey] as CssProps) + '}')
70
+ .join('');
71
+ css.push(`${i}{${cssText}}`);
72
+ } else if (i.startsWith('@media')) {
73
+ const ret = processStyleSub(topUniqueClassName, classSelector, value, i);
74
+ css.push(...ret);
75
+ } else {
76
+ // '&:hover, &.open': {
77
+ // '>.d1, .d2': {...},
78
+ // }, ==>
79
+ // &:hover >.d1, &:hover >.d2, &.open >.d1, &.open .d2
80
+
81
+ // '.aa': {
82
+ // '&:hover': {...},
83
+ // '.bb': {...},
84
+ // }, ==>
85
+ // .aa:hover, .aa .bb
86
+ const newClassSelector = !classSelector
87
+ ? i
88
+ : classSelector
89
+ .split(',')
90
+ .map((key0) => key0.trim())
91
+ .map((key0) => {
92
+ return i
93
+ .split(',')
94
+ .map((key) => key.trim())
95
+ .map((key) => {
96
+ // not needed to "+" as them share same parents?
97
+ // return key.split('+').map(key2 => key2.startsWith('&') ? key0 + key2.substring(1) : key0 + ' ' + key2).join('+');
98
+ // return key.startsWith('&') ? key0 + key.substring(1) : key0 + ' ' + key;
99
+ const newKey = key.startsWith('&') ? key0 + key.substring(1) : key0 + ' ' + key;
100
+ return newKey.replace(/&/g, topUniqueClassName);
101
+ })
102
+ .join(',');
103
+ })
104
+ .join(',');
105
+ const ret = processStyleSub(topUniqueClassName, newClassSelector, value, mediaQuery);
106
+ css.push(...ret);
107
+ }
108
+ }
109
+ }
110
+ updateOneBlock(css, cssTemp, outClassName, mediaQuery);
111
+ return css;
112
+ };
113
+ // topUniqueClassName is used to replace '&' in className, and '.' + topUniqueClassName is used as selector in styles ".xxx {}"
114
+ export const processStyle = (topUniqueClassName: string, style: CssProps): string[] => {
115
+ return processStyleSub(topUniqueClassName, topUniqueClassName ? `.${topUniqueClassName}` : '', style);
116
+ };
117
+
118
+ // mount-components has the same name `sty-`
119
+ export const updateStyles = (topUniqueClassName: string, style: CssProps) => {
120
+ const el = topUniqueClassName && document.querySelector(`.${topUniqueClassName}`);
121
+ if (el) {
122
+ const cssText = processStyle(topUniqueClassName, style).join('');
123
+ // if the first child is style, then update it
124
+ if (el.firstChild && el.firstChild.nodeName === 'STYLE') {
125
+ (el.firstChild as any).innerHTML = cssText;
126
+ } else {
127
+ const style = document.createElement('style');
128
+ style.innerHTML = cssText;
129
+ // style.id = `sty-${selector}`; // sty means style, this is different from mount-components.renderComponent
130
+ el.prepend(style);
131
+ }
132
+ } else {
133
+ console.warn(`Can't find "${topUniqueClassName}" to update styles.`);
134
+ }
135
+ };
136
+
137
+ const updateCssDom = (uniqueStyleId: string, cssText: string, cssDom: HTMLElement | null) => {
138
+ if (!cssDom) {
139
+ cssDom = document.createElement('style');
140
+ cssDom.id = `sty-${uniqueStyleId}`;
141
+ document.head.appendChild(cssDom);
142
+ }
143
+ cssDom.innerText = cssText;
144
+ };
145
+
146
+ /*
147
+ If selectors in GlobalStyles have '&' at top level, then classSelector is needed, otherwise classSelector can be ''
148
+ This is ok:
149
+ {
150
+ '.aa':{
151
+ '&:hover': {...}
152
+ }
153
+ }
154
+ This needs classSelector:
155
+ {
156
+ 'color': 'red', // will need and be put under .topUniqueClassName
157
+ '&:hover': {...} // & will be replaced by .topUniqueClassName
158
+ }
159
+ Global styles including theme will not be updated once it's created.
160
+ topUniqueClassName is a className or a tag name.
161
+ classSelector is a selector used in styles ".xxx {}"
162
+ For example, it can be like this for all elements:
163
+ html { ... } or :root { ... }
164
+
165
+ For themes like [data-theme="dark" i], the topUniqueClassName should be empty
166
+ */
167
+ export const globalStyleUniqueId = uniqueIdGenerator('g'); // g means global style
168
+ const _globalStyleIds = new Map<CssProps, string>();
169
+ export const getGlobalStylesId = (style: CssProps): string => {
170
+ if (!_globalStyleIds.has(style)) {
171
+ const id = globalStyleUniqueId();
172
+ _globalStyleIds.set(style, id);
173
+ }
174
+ return _globalStyleIds.get(style)!;
175
+ };
176
+
177
+ const _globalStyle = new Map();
178
+ export const bindGlobalStyle = (
179
+ topUniqueClassName: string,
180
+ style: CssProps,
181
+ forceUpdate = false,
182
+ noTopClassName = false
183
+ ) => {
184
+ if (typeof document !== 'undefined') {
185
+ let cssDom = document.getElementById(`sty-${topUniqueClassName}`);
186
+ if (forceUpdate || !cssDom) {
187
+ updateCssDom(topUniqueClassName, processStyle(noTopClassName ? '' : topUniqueClassName, style).join(''), cssDom);
188
+ }
189
+ } else if (!_globalStyle.has(topUniqueClassName) || forceUpdate) {
190
+ // don't overwrite it to have the same behavior as in the Browser
191
+ _globalStyle.set(topUniqueClassName, { topUniqueClassName, noTopClassName, style });
192
+ }
193
+ };
194
+
195
+ const generateThemeStyles = () => {
196
+ const currentTheme = getCurrentTheme();
197
+ const themeCss = [];
198
+ for (let themeName in currentTheme.themes) {
199
+ // i is for case-insensitive
200
+ themeCss.push(
201
+ ...processStyle('', {
202
+ [`[data-theme="${themeName}" i]`]: currentTheme.themes[themeName],
203
+ })
204
+ );
205
+ }
206
+ return themeCss.join('\n');
207
+ };
208
+
209
+ if (typeof document !== 'undefined') {
210
+ // Update theme in Browser when no SSR
211
+ bindPageLoadedEvent(() => {
212
+ const uniqueStyleId = themeCookieName;
213
+ let cssDom = document.getElementById(`sty-${uniqueStyleId}`);
214
+ if (!cssDom) {
215
+ updateCssDom(uniqueStyleId, generateThemeStyles(), cssDom);
216
+ }
217
+ });
218
+ }
219
+
220
+ // can't clear global styles,because in index.tsx it is only loaded once, clear it it will be gone
221
+ // const clearGlobalStyles = () => {
222
+ // // reset unique id
223
+ // _globalStyle.clear();
224
+ // };
225
+ // bindPageResetEvent(clearGlobalStyles);
226
+
227
+ export const generateAllGlobalStyles = () => {
228
+ const result = [];
229
+
230
+ result.push(`<style id="sty-${themeCookieName}">${generateThemeStyles()}</style>`);
231
+
232
+ for (let [uniqueStyleId, { topUniqueClassName, noTopClassName, style }] of _globalStyle) {
233
+ const cssText = processStyle(noTopClassName ? '' : topUniqueClassName, style).join('');
234
+ result.push(`<style id="sty-${uniqueStyleId}">${cssText}</style>`);
235
+ }
236
+
237
+ // clearGlobalStyles();
238
+ return result.join('');
239
+ };