lupine.web 1.0.15 → 1.0.17

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 (78) hide show
  1. package/README.md +1 -1
  2. package/package.json +1 -5
  3. package/src/core/bind-lang.ts +6 -5
  4. package/src/core/bind-links.ts +2 -2
  5. package/src/core/bind-meta.tsx +52 -0
  6. package/src/core/bind-theme.ts +11 -9
  7. package/src/core/export-lupine.ts +64 -0
  8. package/src/core/index.ts +3 -1
  9. package/src/core/{core.ts → initialize.ts} +12 -79
  10. package/src/core/page-router.ts +3 -2
  11. package/src/core/server-cookie.ts +5 -3
  12. package/src/index.ts +2 -3
  13. package/src/lib/index.ts +2 -13
  14. package/src/lib/is-frontend.ts +3 -0
  15. package/src/models/index.ts +2 -0
  16. package/src/models/json-props.ts +8 -0
  17. package/src/models/theme-props.ts +7 -0
  18. package/src/{types → styles}/index.ts +0 -2
  19. package/src/assets/themes/base-themes.ts +0 -16
  20. package/src/assets/themes/dark-themes.ts +0 -85
  21. package/src/assets/themes/index.ts +0 -4
  22. package/src/assets/themes/light-themes.ts +0 -92
  23. package/src/assets/themes/shared-themes.ts +0 -50
  24. package/src/components/button-push-animation.tsx +0 -138
  25. package/src/components/button.tsx +0 -55
  26. package/src/components/drag-refresh.tsx +0 -110
  27. package/src/components/editable-label.tsx +0 -83
  28. package/src/components/float-window.tsx +0 -226
  29. package/src/components/grid.tsx +0 -18
  30. package/src/components/html-var.tsx +0 -41
  31. package/src/components/index.ts +0 -36
  32. package/src/components/input-with-title.tsx +0 -24
  33. package/src/components/link-item.tsx +0 -13
  34. package/src/components/link-list.tsx +0 -62
  35. package/src/components/menu-bar.tsx +0 -220
  36. package/src/components/menu-item-props.tsx +0 -10
  37. package/src/components/menu-sidebar.tsx +0 -289
  38. package/src/components/message-box.tsx +0 -44
  39. package/src/components/meta-data.tsx +0 -54
  40. package/src/components/meta-description.tsx +0 -19
  41. package/src/components/meta-title.tsx +0 -19
  42. package/src/components/modal.tsx +0 -29
  43. package/src/components/notice-message.tsx +0 -119
  44. package/src/components/paging-link.tsx +0 -100
  45. package/src/components/panel.tsx +0 -24
  46. package/src/components/popup-menu.tsx +0 -218
  47. package/src/components/progress.tsx +0 -91
  48. package/src/components/redirect.tsx +0 -19
  49. package/src/components/resizable-splitter.tsx +0 -129
  50. package/src/components/select-with-title.tsx +0 -37
  51. package/src/components/spinner.tsx +0 -100
  52. package/src/components/svg.tsx +0 -24
  53. package/src/components/tabs.tsx +0 -252
  54. package/src/components/text-glow.tsx +0 -36
  55. package/src/components/text-wave.tsx +0 -54
  56. package/src/components/theme-selector.tsx +0 -35
  57. package/src/components/toggle-base.tsx +0 -260
  58. package/src/components/toggle-switch.tsx +0 -156
  59. package/src/lib/date-utils.ts +0 -317
  60. package/src/lib/deep-merge.ts +0 -37
  61. package/src/lib/document-ready.ts +0 -36
  62. package/src/lib/dom/calculate-text-width.ts +0 -13
  63. package/src/lib/dom/download-stream.ts +0 -17
  64. package/src/lib/dom/download.ts +0 -12
  65. package/src/lib/dom/index.ts +0 -71
  66. package/src/lib/dynamical-load.ts +0 -138
  67. package/src/lib/format-bytes.ts +0 -11
  68. package/src/lib/lite-dom.ts +0 -227
  69. package/src/lib/message-hub.ts +0 -105
  70. package/src/lib/observable.ts +0 -188
  71. package/src/lib/promise-timeout.ts +0 -1
  72. package/src/lib/simple-storage.ts +0 -40
  73. package/src/lib/stop-propagation.ts +0 -7
  74. package/src/lib/upload-file.ts +0 -68
  75. package/src/types/css-types.ts +0 -17
  76. package/src/types/media-query.ts +0 -93
  77. /package/src/lib/{dom/cookie.ts → cookie.ts} +0 -0
  78. /package/src/{types → styles}/css-styles.ts +0 -0
@@ -1,252 +0,0 @@
1
- import { mountComponents, mountSelfComponents } from '../core';
2
- import { RefProps, VNode } from '../jsx';
3
- import { stopPropagation } from '../lib';
4
-
5
- export type TabsUpdateProps = {
6
- updateTitle?: (index: number, title: string) => void;
7
- updateIndex?: (index: number) => void;
8
- newPage?: (title: string, page: VNode<any>, index?: number) => Promise<void>;
9
- removePage?: (index: number) => void;
10
- indexChanged?: (index: number) => void;
11
- getIndex?: () => number;
12
- getCount?: () => number;
13
- findAndActivate?: (title: string) => boolean;
14
- };
15
-
16
- export type TabsPageProps = { title: string; page: VNode<any> };
17
-
18
- export type TabsProps = {
19
- pages: TabsPageProps[];
20
- defaultIndex?: number;
21
- topClassName?: string;
22
- pagePadding?: string;
23
- refUpdate?: TabsUpdateProps;
24
- };
25
- // For CSS or query selectors, please pay attention to that Tabs can be nested
26
- export const Tabs = ({ pages, defaultIndex, topClassName, pagePadding, refUpdate }: TabsProps) => {
27
- const ref: RefProps = {};
28
- let newIndex = typeof defaultIndex === 'number' ? defaultIndex : 0;
29
- const clearIndex = () => {
30
- const header = ref.$(`.tabs[data-refid=${ref.id}] > div > .tab.active`);
31
- header && header.classList.remove('active');
32
- const page = ref.$(`.pages[data-refid=${ref.id}] > .page.active`);
33
- page && page.classList.remove('active');
34
- };
35
- const updateIndex = (index: number) => {
36
- clearIndex();
37
- const doms = ref.$all(`.tabs[data-refid=${ref.id}] > div > .tab`);
38
- if (index >= 0 && index < doms.length) {
39
- doms[index].classList.add('active');
40
- const pages = ref.$all(`.pages[data-refid=${ref.id}] > .page`);
41
- pages[index].classList.add('active');
42
- refUpdate?.indexChanged && refUpdate?.indexChanged(index);
43
- }
44
- };
45
- const removePage = (index: number) => {
46
- const doms = ref.$all(`.tabs[data-refid=${ref.id}] > div > .tab`);
47
- if (index >= 0 && index < doms.length) {
48
- const newIndex = index === doms.length - 1 ? index - 1 : index;
49
- const isAct = doms[index].classList.contains('active');
50
- doms[index].parentNode.remove();
51
- const pages = ref.$all(`.pages[data-refid=${ref.id}] > .page`);
52
- pages[index].remove();
53
-
54
- if (isAct) {
55
- updateIndex(newIndex);
56
- }
57
- }
58
- };
59
- const removePageFromX = (event: any) => {
60
- stopPropagation(event);
61
-
62
- const tab = event.target.parentNode;
63
- const index = Array.prototype.indexOf.call(tab.parentNode.parentNode.children, tab.parentNode);
64
- removePage(index);
65
- };
66
-
67
- const newPage = async (title: string, page: VNode<any>, index?: number) => {
68
- const allTabs = ref.$all(`.tabs[data-refid=${ref.id}] > div > .tab`);
69
- let newPageIndex = allTabs.length;
70
- if (typeof index === 'number' && index >= 0 && index < allTabs.length) {
71
- newPageIndex = index;
72
- }
73
-
74
- clearIndex();
75
- const newTab2 = createTabHeader(title, ' active');
76
- const newTab = document.createElement('div');
77
-
78
- const newPage = document.createElement('div');
79
- newPage.className = 'page';
80
- if (newPageIndex === allTabs.length) {
81
- ref.$(`.tabs[data-refid=${ref.id}]`).appendChild(newTab);
82
- ref.$(`.pages[data-refid=${ref.id}]`).appendChild(newPage);
83
- } else {
84
- ref.$(`.tabs[data-refid=${ref.id}]`).insertBefore(newTab, allTabs[newPageIndex]);
85
- const pages = ref.$all(`.pages[data-refid=${ref.id}] > .page`);
86
- ref.$(`.pages[data-refid=${ref.id}]`).insertBefore(newPage, pages[newPageIndex]);
87
- }
88
-
89
- await mountComponents(newTab, newTab2);
90
- await mountComponents(newPage, page);
91
- updateIndex(newPageIndex);
92
- };
93
- const createTabHeader = (title: string, className: string) => {
94
- return (
95
- <div onClick={onTabClick} class={'tab' + className}>
96
- {title}
97
- <span class='modal-close' onClick={removePageFromX}>
98
- ×
99
- </span>
100
- </div>
101
- );
102
- };
103
- const onTabClick = (event: any) => {
104
- stopPropagation(event);
105
-
106
- const tab = event.target;
107
- const index = Array.prototype.indexOf.call(tab.parentNode.parentNode.children, tab.parentNode);
108
- updateIndex(index);
109
- };
110
- const flashTitle = (index: number) => {
111
- const doms = ref.$all(`.tabs[data-refid=${ref.id}] > div > .tab`);
112
- if (index >= 0 && index < doms.length) {
113
- doms[index].classList.add('flash');
114
- setTimeout(() => {
115
- doms[index].classList.remove('flash');
116
- }, 1000);
117
- }
118
- };
119
- if (refUpdate) {
120
- refUpdate.updateTitle = (index: number, title: string) => {
121
- const doms = ref.$all(`.tabs[data-refid=${ref.id}] > div > .tab`);
122
- if (index >= 0 && index < doms.length) {
123
- doms[index].innerHTML = title;
124
- }
125
- };
126
- refUpdate.updateIndex = updateIndex;
127
- refUpdate.removePage = removePage;
128
- refUpdate.newPage = newPage;
129
- refUpdate.getIndex = () => {
130
- const header = ref.$(`.tabs[data-refid=${ref.id}] > div > .tab.active`);
131
- return header ? Array.prototype.indexOf.call(header.parentNode.parentNode.children, header.parentNode) : -1;
132
- };
133
- refUpdate.getCount = () => {
134
- const doms = ref.$all(`.tabs[data-refid=${ref.id}] > div > .tab`);
135
- return doms.length;
136
- };
137
- refUpdate.findAndActivate = (title: string) => {
138
- const doms = ref.$all(`.tabs[data-refid=${ref.id}] > div > .tab`);
139
- for (let i = 0; i < doms.length; i++) {
140
- if (doms[i].innerText === title) {
141
- updateIndex(i);
142
- flashTitle(i);
143
- return true;
144
- }
145
- }
146
- return false;
147
- };
148
- }
149
-
150
- // pay attention to nest tabs
151
- const newCss: any = {
152
- display: 'flex',
153
- 'flex-direction': 'column',
154
- width: '100%',
155
- height: '100%',
156
- // border: 'solid 1px grey',
157
- '&:not(:has(.pages .page))': {
158
- // hide tabs when there is no tabs (not need to show borders)
159
- display: 'none',
160
- },
161
- '> .tabs': {
162
- display: 'flex',
163
- height: 'auto',
164
- 'border-bottom': '1px solid grey',
165
- '> div > .tab': {
166
- padding: '2px 3px',
167
- width: 'auto',
168
- 'font-size': 'smaller',
169
- 'text-overflow': 'ellipsis',
170
- overflow: 'hidden',
171
- 'white-space': 'nowrap',
172
- margin: '1px 1px 0 1px',
173
- cursor: 'pointer',
174
- position: 'relative',
175
- // transition: 'all 1s',
176
- 'border-top-right-radius': '4px',
177
- 'border-top-left-radius': '4px',
178
- 'border-top': 'solid 1px var(--primary-border-color)',
179
- 'border-left': 'solid 1px var(--primary-border-color)',
180
- 'border-right': 'solid 1px var(--primary-border-color)',
181
- // 'border-bottom': '2px solid transparent',
182
- color: 'var(--activatable-color-normal)',
183
- backgroundColor: 'var(--activatable-bg-color-normal)',
184
- },
185
- '> div > .tab:hover': {
186
- padding: '3px 3px 1px 3px',
187
- // color: 'var(--activatable-color-hover)',
188
- // backgroundColor: 'var(--activatable-bg-color-hover)',
189
- },
190
- '> div > .tab.flash': {
191
- backgroundColor: 'red',
192
- },
193
- '> div > .active': {
194
- // 'border-bottom': '2px solid red',
195
- color: 'var(--activatable-color-selected)',
196
- backgroundColor: 'var(--activatable-bg-color-selected)',
197
- marginBottom: '-1px',
198
- borderBottom: '1px solid #FFFFFF00',
199
- },
200
- '> div > .tab > .modal-close': {
201
- display: 'none',
202
- float: 'right',
203
- fontSize: '12px',
204
- fontWeight: 'bold',
205
- cursor: 'pointer',
206
- position: 'absolute',
207
- top: '-4px',
208
- right: '1px',
209
- },
210
- '> div > .tab:hover > .modal-close': {
211
- display: 'inline-block',
212
- color: '#ff0000',
213
- },
214
- },
215
- '> .pages': {
216
- display: 'flex',
217
- flex: '1',
218
- position: 'relative',
219
- '> .page': {
220
- display: 'none',
221
- position: 'absolute',
222
- padding: pagePadding || '0px',
223
- overflow: 'auto',
224
- width: '100%',
225
- maxWidth: '100%',
226
- height: '100%',
227
- overflowX: 'auto',
228
- overflowY: 'auto',
229
- },
230
- '> .active': {
231
- display: 'inline-block',
232
- },
233
- },
234
- };
235
-
236
- return (
237
- <div ref={ref} css={newCss} class={'tabs-box' + (topClassName ? ' ' + topClassName : '')}>
238
- <div class='tabs' data-refid={ref}>
239
- {pages.map((i, index) => {
240
- const className = index === newIndex ? ' active' : '';
241
- return <div>{createTabHeader(i.title, className)}</div>;
242
- })}
243
- </div>
244
- <div class='pages' data-refid={ref}>
245
- {pages.map((i, index) => {
246
- const className = index === newIndex ? ' active' : '';
247
- return <div class={'page' + className}>{i.page}</div>;
248
- })}
249
- </div>
250
- </div>
251
- );
252
- };
@@ -1,36 +0,0 @@
1
- import { CssProps } from '../jsx';
2
-
3
- export type TextGlowProps = {
4
- text: string;
5
- color?: string;
6
- padding?: string;
7
- fontSize?: string;
8
- fontWeight?: string;
9
- };
10
- export const TextGlow = (props: TextGlowProps) => {
11
- const css: CssProps = {
12
- width: `100%`,
13
- height: `100%`,
14
- textAlign: 'center',
15
- color: props.color || '#22b8ff',
16
- padding: props.padding || '10px',
17
- fontSize: props.fontSize || '30px',
18
- fontWeight: props.fontWeight || '500',
19
- '.text-glow': {
20
- animation: 'text-glow-a 1.5s infinite alternate',
21
- },
22
- '@keyframes text-glow-a': {
23
- '0%': {
24
- textShadow: '0 0 5px #ff005e, 0 0 10px #ff005e, 0 0 20px #ff005e, 0 0 40px #ff005e, 0 0 80px #ff005e',
25
- },
26
- '100%': {
27
- textShadow: '0 0 10px #00d4ff, 0 0 20px #00d4ff, 0 0 40px #00d4ff, 0 0 80px #00d4ff, 0 0 160px #00d4ff',
28
- },
29
- },
30
- };
31
- return (
32
- <div css={css} class='text-glow-top'>
33
- <div class='text-glow'>{props.text}</div>
34
- </div>
35
- );
36
- };
@@ -1,54 +0,0 @@
1
- import { CssProps } from "../jsx";
2
-
3
- export type TextLoadingProps = {
4
- text: string;
5
- color?: string;
6
- padding?: string;
7
- fontSize?: string;
8
- fontWeight?: string;
9
- };
10
- export const TextWave = (props: TextLoadingProps) => {
11
- const cssMap: CssProps = {};
12
- props.text.split('').forEach((char, index) => {
13
- cssMap[`.span${index}`] = { animationDelay: `${index * 0.1}s` };
14
- });
15
- const css: CssProps = {
16
- width: `100%`,
17
- height: `100%`,
18
- textAlign: 'center',
19
- color: props.color || '#22b8ff',
20
- padding: props.padding || '10px',
21
- fontSize: props.fontSize || '20px',
22
- fontWeight: props.fontWeight,
23
- textShadow: '1px -1px #ffffff, -2px 2px #999, -6px 7px 3px #131f5be6',
24
- '.text-loading.wave-animetion span': {
25
- display: 'inline-block',
26
- padding: '0 4px',
27
- animation: 'wave-text 1s ease-in-out infinite',
28
- },
29
- '.text-loading.wave-animetion': {
30
- marginTop: '0.6em',
31
- ...cssMap,
32
- },
33
- '@keyframes wave-text': {
34
- '0%': {
35
- transform: 'translateY(0em)',
36
- },
37
- '60%': {
38
- transform: 'translateY(-0.6em)',
39
- },
40
- '100%': {
41
- transform: 'translateY(0em)',
42
- },
43
- },
44
- };
45
- return (
46
- <div css={css} class='text-loading-top'>
47
- <div class='text-loading wave-animetion'>
48
- {props.text.split('').map((char, index) => (
49
- <span class={`span${index}`}>{char}</span>
50
- ))}
51
- </div>
52
- </div>
53
- );
54
- };
@@ -1,35 +0,0 @@
1
- import { bindGlobalStyles, getCurrentTheme, updateTheme } from '../core';
2
- import { CssProps } from '../jsx';
3
- import { ContentPosition } from '../types';
4
- import { PopupMenu } from './popup-menu';
5
-
6
- export type ThemeSelectorProps = {
7
- className?: string;
8
- contentPosition?: ContentPosition;
9
- css?: CssProps;
10
- };
11
-
12
- export const ThemeSelector = ({ className, css }: ThemeSelectorProps) => {
13
- const newCss: CssProps = {
14
- display: 'flex',
15
- flexDirection: 'column',
16
- alignSelf: 'end',
17
- // justifyContent: ContentPosition.center,
18
- ...css,
19
- };
20
-
21
- bindGlobalStyles('theme-switch', '.theme-switch', newCss);
22
- const handleSelected = (themeName: string) => {
23
- updateTheme(themeName);
24
- };
25
- const currentTheme = getCurrentTheme();
26
- const list = [];
27
- for (let themeName in currentTheme.themes) {
28
- list.push(themeName);
29
- }
30
- return (
31
- <div css={newCss} class={['theme-switch', className].join(' ')} title='Select theme'>
32
- <PopupMenu list={list} defaultValue={currentTheme.themeName} handleSelected={handleSelected}></PopupMenu>
33
- </div>
34
- );
35
- };
@@ -1,260 +0,0 @@
1
- import { CssProps, RefProps, VNode } from 'lupine.web';
2
-
3
- export const PlayButtonSize = {
4
- Small: { w: 50, h: 50 },
5
- Medium: { w: 70, h: 70 },
6
- Large: { w: 90, h: 90 },
7
- };
8
- export type PlayButtonSizeProps = {
9
- w: number;
10
- h: number;
11
- };
12
- export type PlayButtonProps = {
13
- size: PlayButtonSizeProps;
14
- disabled?: boolean;
15
- checked?: boolean;
16
- onClick?: (checked: boolean) => void;
17
- hook?: ToggleBaseHookProps;
18
- };
19
- export const PlayButton = (props: PlayButtonProps) => {
20
- const css: CssProps = {
21
- width: `100%`,
22
- height: `100%`,
23
- borderRadius: '50%',
24
- backgroundColor: '#3b29cc',
25
- display: 'flex',
26
- alignItems: 'center',
27
- justifyContent: 'center',
28
- '.play-icon': {
29
- width: '50%',
30
- height: '50%',
31
- transition: 'all 0.2s ease-in-out',
32
- backgroundColor: '#fff',
33
- cursor: 'pointer',
34
- },
35
- '&.toggle-off .play-icon': {
36
- clipPath: 'polygon(20% 0, 20% 100%, 90% 50%, 90% 50%, 90% 50%, 90% 50%, 90% 50%, 90% 50%, 90% 50%)',
37
- translate: '6% 0',
38
- },
39
- '&.toggle-on .play-icon': {
40
- clipPath: 'polygon(0 0, 0 100%, 33.33% 100%, 33.33% 0, 66.66% 0, 100% 0, 100% 100%, 66.66% 100%, 66.66% 0)',
41
- translate: '0 0',
42
- },
43
- '&.disabled': {
44
- cursor: 'not-allowed',
45
- backgroundColor: '#5d578b',
46
- },
47
- };
48
- return (
49
- <ToggleBase {...props}>
50
- <ToggleWaveFrame>
51
- <div
52
- css={css}
53
- class={`toggle-button-component toggle-placeholder ${props.checked ? 'toggle-on' : 'toggle-off'}${
54
- props.disabled ? ' disabled' : ''
55
- }`}
56
- >
57
- <div class='play-icon'></div>
58
- </div>
59
- </ToggleWaveFrame>
60
- </ToggleBase>
61
- );
62
- };
63
-
64
- export type ToggleButtonProps = {
65
- size: ToggleBaseSizeProps;
66
- onText: string;
67
- offText: string;
68
- disabled?: boolean;
69
- checked?: boolean;
70
- onClick?: (checked: boolean) => void;
71
- hook?: ToggleBaseHookProps;
72
- };
73
- export const ToggleButton = (props: ToggleButtonProps) => {
74
- const css: CssProps = {
75
- // width: `${props.size + 5}px`,
76
- // height: `${props.size + 5}px`,
77
- '&.disabled': {
78
- cursor: 'not-allowed',
79
- },
80
- '&.toggle-on .on, &.toggle-off .off': {
81
- display: 'block',
82
- },
83
- '&.toggle-on .off, &.toggle-off .on': {
84
- display: 'none',
85
- },
86
- };
87
- return (
88
- <ToggleBase {...props}>
89
- <div
90
- css={css}
91
- class={`toggle-button-component toggle-placeholder ${props.checked ? 'toggle-on' : 'toggle-off'}${
92
- props.disabled ? ' disabled' : ''
93
- }`}
94
- >
95
- <div class='on'>{props.onText}</div>
96
- <div class='off'>{props.offText}</div>
97
- </div>
98
- </ToggleBase>
99
- );
100
- };
101
-
102
- export type ToggleWaveFrameProps = {
103
- children: VNode<any>;
104
- };
105
- export const ToggleWaveFrame = (props: ToggleWaveFrameProps) => {
106
- const css: CssProps = {
107
- width: `100%`,
108
- height: `100%`,
109
- '@keyframes pulse-border': {
110
- '0%': {
111
- transform: 'scale(0.6)',
112
- opacity: 1,
113
- },
114
- '100%': {
115
- transform: 'scale(1)',
116
- opacity: 0,
117
- },
118
- },
119
- '.toggle-waves': {
120
- position: 'absolute',
121
- width: `100%`,
122
- height: `100%`,
123
- top: '-0',
124
- left: '0',
125
- borderRadius: '50%',
126
- backgroundColor: '#eb205580',
127
- opacity: 0,
128
- zIndex: -1,
129
- animation: 'pulse-border 3s ease-in-out infinite',
130
- },
131
- '.toggle-waves-1': {
132
- '-webkit-animation-delay': '0s',
133
- 'animation-delay': '0s',
134
- },
135
-
136
- '.toggle-waves-2': {
137
- '-webkit-animation-delay': '1s',
138
- 'animation-delay': '1s',
139
- },
140
-
141
- '.toggle-waves-3': {
142
- '-webkit-animation-delay': '2s',
143
- 'animation-delay': '2s',
144
- },
145
- '.toggle-waves-box': {
146
- width: `100%`,
147
- height: `100%`,
148
- padding: `18%`,
149
- },
150
- '&.disabled .toggle-waves': {
151
- backgroundColor: '#5d578b',
152
- },
153
- };
154
- return (
155
- <div css={css} class='toggle-waves-box toggle-placeholder'>
156
- <div class='toggle-waves toggle-waves-1'></div>
157
- <div class='toggle-waves toggle-waves-2'></div>
158
- <div class='toggle-waves toggle-waves-3'></div>
159
- <div class='toggle-waves-box'>{props.children}</div>
160
- </div>
161
- );
162
- };
163
-
164
- export const ToggleBaseSize = {
165
- Small: { w: 30, h: 30 },
166
- Medium: { w: 50, h: 50 },
167
- Large: { w: 70, h: 70 },
168
- };
169
- export type ToggleBaseSizeProps = {
170
- w: number | string;
171
- h: number | string;
172
- };
173
- export type ToggleBaseHookProps = {
174
- setChecked?: (checked: boolean) => void;
175
- getChecked?: () => boolean;
176
- setEnabled?: (enabled: boolean) => void;
177
- getEnabled?: () => boolean;
178
- };
179
- export type ToggleBaseProps = {
180
- size: ToggleBaseSizeProps;
181
- disabled?: boolean;
182
- checked?: boolean;
183
- onClick?: (checked: boolean) => void;
184
- hook?: ToggleBaseHookProps;
185
- children: VNode<any>;
186
- };
187
- export const ToggleBase = (props: ToggleBaseProps) => {
188
- const applyToggle = (checked: boolean, disabled: boolean) => {
189
- const childDom = ref.$all('.toggle-base-container .toggle-placeholder');
190
- childDom.forEach((dom: HTMLElement) => {
191
- dom.classList.toggle('toggle-on', checked);
192
- dom.classList.toggle('toggle-off', !checked);
193
- dom.classList.toggle('disabled', disabled);
194
- });
195
- };
196
- let disabled = props.disabled || false;
197
- const ref: RefProps = {
198
- onLoad: async (el: Element) => {
199
- applyToggle(props.checked || false, disabled);
200
- },
201
- };
202
- const onClick = (e: MouseEvent) => {
203
- if (disabled) {
204
- return;
205
- }
206
-
207
- const checked = (e.target as HTMLInputElement).checked;
208
- applyToggle(checked, disabled);
209
- if (props.onClick) {
210
- props.onClick(checked);
211
- }
212
- };
213
- if (props.hook) {
214
- props.hook.setChecked = (checked: boolean) => {
215
- (ref.$('input.toggle-base-checkbox') as HTMLInputElement).checked = checked;
216
- applyToggle(checked, disabled);
217
- };
218
- props.hook.getChecked = () => {
219
- return (ref.$('input.toggle-base-checkbox') as HTMLInputElement).checked;
220
- };
221
- props.hook.setEnabled = (enabled: boolean) => {
222
- disabled = !enabled;
223
- const dom = ref.$('input.toggle-base-checkbox') as HTMLInputElement;
224
- dom.disabled = disabled;
225
- applyToggle(dom.checked, disabled);
226
- };
227
- props.hook.getEnabled = () => {
228
- return !disabled;
229
- };
230
- }
231
-
232
- const css: CssProps = {
233
- width: `${typeof props.size.w === 'number' ? props.size.w + 'px' : props.size.w}`,
234
- height: `${typeof props.size.h === 'number' ? props.size.h + 'px' : props.size.h}`,
235
- '.toggle-base-box, .toggle-base-container': {
236
- position: 'relative',
237
- width: `100%`,
238
- height: `100%`,
239
- },
240
- '.toggle-base-checkbox': {
241
- opacity: 0,
242
- position: 'absolute',
243
- pointerEvents: 'none',
244
- },
245
- };
246
- return (
247
- <div ref={ref} css={css} class='toggle-base-component'>
248
- <label class='toggle-base-box'>
249
- <div class='toggle-base-container'>{props.children}</div>
250
- <input
251
- type='checkbox'
252
- class='toggle-base-checkbox'
253
- checked={props.checked || false}
254
- disabled={disabled}
255
- onClick={onClick}
256
- />
257
- </label>
258
- </div>
259
- );
260
- };