cdui-js 1.0.23 → 1.0.24

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.
package/css/all.css CHANGED
@@ -7,9 +7,8 @@
7
7
  @import url(button.css);
8
8
  @import url(textbox.css);
9
9
  @import url(popup.css);
10
- @import url(combobox.css);
11
10
  @import url(datewidget.css);
12
- @import url(datepicker.css);
11
+ @import url(dropdown.css);
13
12
  @import url(mobile-datepicker.css);
14
13
  @import url(form.css);
15
14
  @import url(carousel.css);
@@ -47,6 +47,7 @@
47
47
  width: 25%;
48
48
  height: 25%;
49
49
  cursor: pointer;
50
+ z-index: 1;
50
51
  }
51
52
 
52
53
  .datewidget-item.disabled {
@@ -1,18 +1,13 @@
1
+ .combobox,
1
2
  .datepicker {
2
- position: relative;
3
- width: 100px;
4
- height: 32px;
5
- overflow: visible;
6
- }
7
-
8
- .datepicker-host {
9
3
  display: flex;
10
4
  justify-content: center;
11
5
  align-items: center;
12
- width: 100%;
13
- height: 100%;
6
+ width: 120px;
7
+ height: 32px;
14
8
  }
15
9
 
10
+ .combobox-input,
16
11
  .datepicker-input {
17
12
  flex: auto;
18
13
  width: 100%;
@@ -26,7 +21,8 @@
26
21
  font-size: inherit;
27
22
  }
28
23
 
29
- .datepicker-host > .icon {
24
+ .combobox-icon,
25
+ .datepicker-icon {
30
26
  display: flex;
31
27
  justify-items: center;
32
28
  align-items: center;
package/css/popup.css CHANGED
@@ -1,33 +1,52 @@
1
1
  .popup {
2
- position: absolute;
3
- top: calc(100% + 4px);
4
- left: -1px;
5
- z-index: 100;
6
- /* 不允许内边距,否则动画的高度不能小于内边距 */
2
+ position: fixed;
3
+ z-index: 9;
4
+ /* 不允许边框和内边距,否则动画的高度不能小于内边距 */
5
+ border: none !important;
7
6
  padding: 0 !important;
8
7
  will-change: height;
9
8
  transition: height 0.2s linear;
10
9
  overflow: hidden;
11
10
  }
12
11
 
13
- .popup-top {
14
- top: auto;
15
- bottom: calc(100% + 4px);
12
+ .popup-fixed-left,
13
+ .popup-fixed-right {
14
+ display: flex;
15
+ align-items: center;
16
+ top: 0;
17
+ height: 100%;
18
+ }
19
+
20
+ .popup-fixed-left > *,
21
+ .popup-fixed-right > * {
22
+ height: 100 !important;
16
23
  }
17
24
 
18
- .popup-right {
19
- left: auto;
25
+ .popup-fixed-left {
26
+ left: 0;
27
+ }
28
+
29
+ .popup-fixed-right {
20
30
  right: 0;
21
31
  }
22
32
 
23
- .le-480 .popup {
24
- position: fixed;
25
- top: auto;
26
- bottom: 0;
27
- left: -1px;
28
- right: -1px;
33
+ .popup-fixed-top,
34
+ .popup-fixed-bottom {
35
+ display: flex;
36
+ justify-content: center;
37
+ left: 0;
38
+ width: 100%;
39
+ }
40
+
41
+ .popup-fixed-top > *,
42
+ .popup-fixed-bottom > * {
29
43
  width: 100% !important;
30
- max-width: 100% !important;
31
- max-height: 80%;
32
- border-radius: 12px 12px 0 0;
44
+ }
45
+
46
+ .popup-fixed-top {
47
+ top: 0;
48
+ }
49
+
50
+ .popup-fixed-bottom {
51
+ bottom: 0;
33
52
  }
package/demo/css/css.md CHANGED
@@ -283,18 +283,19 @@
283
283
 
284
284
  # combobox 下拉框
285
285
 
286
- .combobox { border: 1px solid #e4e4e4; background: white; }
286
+ .combobox { border: 1px solid #e4e4e4; background: #ffffff; }
287
287
  .combobox:has(.combobox-input:focus) { border: 1px solid #1b212d; }
288
+ .combobox-popup { border: 1px solid #e4e4e4; background: #ffffff; }
288
289
 
289
290
 
290
291
  # canlendar monthwidget yearwidget 日历 年月 年
291
292
 
292
- .datewidget { border: 1px solid #e4e4e4; }
293
+ .datewidget { border: 1px solid #e4e4e4; background: #ffffff; }
293
294
  .datewidget-header > .icon { stroke: #1b212d; }
294
295
  .datewidget-item.disabled { color: #e4e4e4; }
295
296
  .datewidget-item.prev-block, .datewidget-item.next-block { color: #888f97; }
296
297
  .datewidget-item.today::before { background: #f5f5f5; }
297
- .datewidget-item.selected { color: white; }
298
+ .datewidget-item.selected { color: #ffffff; }
298
299
  .datewidget-item.selected::before { background: #ff4000; }
299
300
 
300
301
  .canlendar-weeks > span { color: #888f97; }
@@ -302,17 +303,12 @@
302
303
 
303
304
  # datepicker 日期选择
304
305
 
305
- .datepicker { border: 1px solid #e4e4e4; background: white; }
306
+ .datepicker { border: 1px solid #e4e4e4; background: #ffffff; }
306
307
  .datepicker:has(.datepicker-input:focus) { border: 1px solid #1b212d; }
307
308
 
308
309
 
309
- # popup 弹出层
310
-
311
- .popup { border: 1px solid #e4e4e4; background: white; }
312
-
313
-
314
310
  # carousel 轮播
315
311
 
316
312
  .carousel-backward, .carousel-forward { background: rgba(255, 255, 255, 0.1); }
317
313
  .carousel-dot { background: rgba(65, 72, 90, 1); }
318
- .carousel-dot.selected { background: white; }
314
+ .carousel-dot.selected { background: #ffffff; }
package/demo/src/App.tsx CHANGED
@@ -1,9 +1,31 @@
1
+ import { showPopup } from '../../src/popup';
1
2
  import { CanlendarPage } from './pages/Canlendar';
2
3
  import { CarouselPage } from './pages/Carousel';
3
4
  import { ComboBoxPage } from './pages/ComboBox';
4
5
  import { DatePickerPage } from './pages/DatePicker';
5
6
  import { FormPage } from './pages/Form';
6
7
 
8
+ let objects = [];
9
+ for (let i = 0; i < 1000000; i++) {
10
+ objects[i] = {};
11
+ }
12
+
13
+ let map = new WeakMap();
14
+ let now = performance.now();
15
+
16
+ for (let i = 0; i < 1000000; i++) {
17
+ map.set(objects[i], i);
18
+ }
19
+
20
+ console.log(performance.now() - now);
21
+
22
+ const openDropdown = (align: HTMLElement) => {
23
+ const popup = showPopup(<div style={{ padding: '100px 0', background: 'silver' }}>11111111111111111111</div>, {
24
+ align,
25
+ transition: true,
26
+ });
27
+ };
28
+
7
29
  export const App = () => {
8
30
  return (
9
31
  <div style={{ 'min-height': '100%' }}>
@@ -909,27 +909,25 @@ body { stroke: #A2A7AD; fill: #A2A7AD; }
909
909
  .textbox:focus { border: 1px solid #1b212d; }
910
910
 
911
911
 
912
- .combobox { border: 1px solid #e4e4e4; background: white; }
912
+ .combobox { border: 1px solid #e4e4e4; background: #ffffff; }
913
913
  .combobox:has(.combobox-input:focus) { border: 1px solid #1b212d; }
914
+ .combobox-popup { border: 1px solid #e4e4e4; background: #ffffff; }
914
915
 
915
916
 
916
- .datewidget { border: 1px solid #e4e4e4; }
917
+ .datewidget { border: 1px solid #e4e4e4; background: #ffffff; }
917
918
  .datewidget-header > .icon { stroke: #1b212d; }
918
919
  .datewidget-item.disabled { color: #e4e4e4; }
919
920
  .datewidget-item.prev-block, .datewidget-item.next-block { color: #888f97; }
920
921
  .datewidget-item.today::before { background: #f5f5f5; }
921
- .datewidget-item.selected { color: white; }
922
+ .datewidget-item.selected { color: #ffffff; }
922
923
  .datewidget-item.selected::before { background: #ff4000; }
923
924
  .canlendar-weeks > span { color: #888f97; }
924
925
 
925
926
 
926
- .datepicker { border: 1px solid #e4e4e4; background: white; }
927
+ .datepicker { border: 1px solid #e4e4e4; background: #ffffff; }
927
928
  .datepicker:has(.datepicker-input:focus) { border: 1px solid #1b212d; }
928
929
 
929
930
 
930
- .popup { border: 1px solid #e4e4e4; background: white; }
931
-
932
-
933
931
  .carousel-backward, .carousel-forward { background: rgba(255, 255, 255, 0.1); }
934
932
  .carousel-dot { background: rgba(65, 72, 90, 1); }
935
- .carousel-dot.selected { background: white; }
933
+ .carousel-dot.selected { background: #ffffff; }
@@ -7,7 +7,7 @@ export const CanlendarPage = () => {
7
7
  <div>
8
8
  <Canlendar
9
9
  value={new Date()}
10
- onchange={(event) => {
10
+ onchange={(event) => {debugger
11
11
  console.log(event.detail);
12
12
  }}
13
13
  ></Canlendar>
@@ -1,8 +1,9 @@
1
- import { reactive } from '../../../src';
1
+ import { reactive } from '../../../src/reactive';
2
+ import { PopupApi } from '../../../src/popup';
2
3
  import { ComboBox } from '../../../src/components/ComboBox';
3
4
 
4
5
  export const ComboBoxPage = () => {
5
- let combobox;
6
+ let combobox: PopupApi;
6
7
 
7
8
  const state = reactive({
8
9
  value: '111',
@@ -10,18 +11,20 @@ export const ComboBoxPage = () => {
10
11
 
11
12
  return (
12
13
  <ComboBox
13
- api={(api) => (combobox = api)}
14
14
  value={state.value}
15
- popup={{
16
- style: { width: '200px', padding: '8px 0' },
17
- onclick: (event) => {
18
- state.value = event.target.textContent;
19
- combobox.closePopup();
20
- },
21
- }}
22
- >
23
- <div>111</div>
24
- <div>222</div>
25
- </ComboBox>
15
+ api={(api) => (combobox = api)}
16
+ popup={() => (
17
+ <div
18
+ style={{ width: '200px', padding: '8px 0' }}
19
+ onclick={(event) => {
20
+ state.value = event.target.textContent;
21
+ combobox.closePopup();
22
+ }}
23
+ >
24
+ <div>111</div>
25
+ <div>222</div>
26
+ </div>
27
+ )}
28
+ ></ComboBox>
26
29
  );
27
30
  };
@@ -1,5 +1,10 @@
1
+ import { reactive } from '../../../src/reactive';
1
2
  import { DatePicker } from '../../../src/components/DatePicker';
2
3
 
3
4
  export const DatePickerPage = () => {
4
- return <DatePicker></DatePicker>;
5
+ let state = reactive({
6
+ value: null,
7
+ });
8
+
9
+ return <DatePicker value={state.value} onchange={(event) => (state.value = event.detail)}></DatePicker>;
5
10
  };
@@ -33,16 +33,18 @@ export const FormPage = () => {
33
33
  <ComboBox
34
34
  api={(api) => (combobox = api)}
35
35
  value={state.b}
36
- popup={{
37
- onclick: (event) => {
38
- state.b = +event.target.textContent;
39
- combobox.closePopup();
40
- },
41
- }}
42
- >
43
- <div>1</div>
44
- <div>2</div>
45
- </ComboBox>
36
+ popup={() => (
37
+ <div
38
+ onclick={(event) => {
39
+ state.b = +event.target.textContent;
40
+ combobox.closePopup();
41
+ }}
42
+ >
43
+ <div>1</div>
44
+ <div>2</div>
45
+ </div>
46
+ )}
47
+ ></ComboBox>
46
48
  );
47
49
  },
48
50
  },
@@ -51,65 +53,69 @@ export const FormPage = () => {
51
53
  b: 2,
52
54
 
53
55
  form: {
54
- username: ''
55
- }
56
+ username: '',
57
+ },
56
58
  });
57
59
 
58
60
  let form: FormApi;
59
61
 
60
- let form2: FormApi
62
+ let form2: FormApi;
61
63
 
62
64
  return (
63
65
  <>
64
- <Form data={state} rules={{}} align={state.align} labelWidth={state.labelWidth} api={(api) => (form = api)}>
65
- <For each={state.items}>
66
- {(item) => (
67
- <FormItem field={item.field} label={item.label} required={item.required}>
68
- <div>
69
- <item.Input></item.Input>
70
- </div>
71
- </FormItem>
72
- )}
73
- </For>
74
- <div>{`a: ${state.a} b: ${state.b}`}</div>
66
+ <Form data={state} rules={{}} align={state.align} labelWidth={state.labelWidth} api={(api) => (form = api)}>
67
+ <For each={state.items}>
68
+ {(item) => (
69
+ <FormItem field={item.field} label={item.label} required={item.required}>
70
+ <div>
71
+ <item.Input></item.Input>
72
+ </div>
73
+ </FormItem>
74
+ )}
75
+ </For>
76
+ <div>{`a: ${state.a} b: ${state.b}`}</div>
77
+ <button
78
+ type="button"
79
+ onclick={() =>
80
+ state.items.push({
81
+ field: '?',
82
+ label: '???',
83
+ required: false,
84
+ labelWidth: '100px',
85
+ Input: () => <TextBox></TextBox>,
86
+ })
87
+ }
88
+ >
89
+ append
90
+ </button>
91
+ <button type="button" onclick={() => (state.align = state.align === 'left' ? 'top' : 'left')}>
92
+ align
93
+ </button>
94
+ <button type="button" onclick={() => (state.labelWidth = parseInt(state.labelWidth) + 10 + 'px')}>
95
+ labelWidth
96
+ </button>
97
+ <button type="button" onclick={() => form.validate()}>
98
+ validate
99
+ </button>
100
+ <button type="button" onclick={() => form.clearErrors()}>
101
+ clearErrors
102
+ </button>
103
+ </Form>
104
+
105
+ <Form data={state.form} rules={{}} api={(api) => (form2 = api)}>
106
+ <FormItem label="username" required field="username">
107
+ <input value={state.form.username} onchange={(e) => (state.form.username = e.target.value)} />
108
+ </FormItem>
109
+ </Form>
110
+
75
111
  <button
76
- type="button"
77
- onclick={() =>
78
- state.items.push({
79
- field: '?',
80
- label: '???',
81
- required: false,
82
- labelWidth: '100px',
83
- Input: () => <TextBox></TextBox>,
84
- })
85
- }
112
+ onclick={async () => {
113
+ const valid = await form2.validate();
114
+ console.log(valid);
115
+ }}
86
116
  >
87
- append
88
- </button>
89
- <button type="button" onclick={() => (state.align = state.align === 'left' ? 'top' : 'left')}>
90
- align
91
- </button>
92
- <button type="button" onclick={() => (state.labelWidth = parseInt(state.labelWidth) + 10 + 'px')}>
93
- labelWidth
117
+ click
94
118
  </button>
95
- <button type="button" onclick={() => form.validate()}>
96
- validate
97
- </button>
98
- <button type="button" onclick={() => form.clearErrors()}>
99
- clearErrors
100
- </button>
101
- </Form>
102
-
103
- <Form data={state.form} rules={{}} api={(api) => (form2 = api)}>
104
- <FormItem label="username" required field='username'>
105
- <input value={state.form.username} onchange={e => state.form.username = e.target.value} />
106
- </FormItem>
107
- </Form>
108
-
109
- <button onclick={async() => {
110
- const valid = await form2.validate()
111
- console.log(valid)
112
- }}>click</button>
113
119
  </>
114
120
  );
115
121
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cdui-js",
3
- "version": "1.0.23",
3
+ "version": "1.0.24",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
6
6
  "bin": {
@@ -1,43 +1,49 @@
1
1
  import { JSX } from '../jsx';
2
2
  import { combineClass, omitProps, useContext, watch } from '../reactive';
3
3
  import { disableAutoCloseEvent } from '../dom';
4
- import { Popup, PopupApi, PopupProps } from './Popup';
4
+ import { PopupApi, initDropdown } from '../popup';
5
+
5
6
  import { FormItemContext } from './provider';
6
7
 
7
- const OMIT_PROPS = ['class', 'value', 'readonly', 'popupOnFocus', 'popup', 'onPopup', 'api', 'children'] as const;
8
+ const OMIT_PROPS = ['class', 'value', 'format', /*'readonly', */ 'popup', 'popupOnFocus', 'api'] as const;
8
9
 
9
10
  /**
10
11
  * 下拉框组件
11
12
  */
12
13
  export const ComboBox = (
13
- props?: JSX.HTMLAttributes<never> &
14
- PopupProps & {
15
- /**
16
- * 值
17
- */
18
- value?: any;
19
- /**
20
- * 值样式
21
- *
22
- * @param value 当前值
23
- */
24
- format?(value: any): string;
25
- /**
26
- * 是否只读
27
- */
28
- readonly?: boolean;
29
- /**
30
- * 获取焦点时是否自动弹出
31
- */
32
- popupOnFocus?: boolean;
33
- /**
34
- * 弹出层属性
35
- */
36
- popup?: Omit<JSX.HTMLAttributes<never>, 'children'>;
37
- },
14
+ props?: Omit<JSX.HTMLAttributes<never>, 'children'> & {
15
+ /**
16
+ * 弹出层
17
+ */
18
+ popup: () => JSX.Element;
19
+ /**
20
+ * 值
21
+ */
22
+ value?: any;
23
+ /**
24
+ * 值样式
25
+ *
26
+ * @param value 当前值
27
+ */
28
+ format?(value: any): string;
29
+ // /**
30
+ // * 是否只读
31
+ // */
32
+ // readonly?: boolean;
33
+ /**
34
+ * 获取焦点时是否自动弹出
35
+ */
36
+ popupOnFocus?: boolean;
37
+ /**
38
+ * 值变更事件
39
+ */
40
+ onchange?: (event: CustomEvent<Date>) => void;
41
+ /**
42
+ * 外部调用接口
43
+ */
44
+ api: (api: PopupApi) => void;
45
+ },
38
46
  ) => {
39
- let popup: PopupApi;
40
-
41
47
  const formItem = useContext(FormItemContext);
42
48
 
43
49
  const initFormItem = (dom: HTMLInputElement) => {
@@ -49,31 +55,29 @@ export const ComboBox = (
49
55
  formItem.init(dom);
50
56
  };
51
57
 
58
+ let api: PopupApi;
59
+
52
60
  return (
53
- <div class={combineClass('combobox', props.class)} {...omitProps(props, OMIT_PROPS)}>
54
- <div class="combobox-host" {...disableAutoCloseEvent}>
55
- <input
56
- ref={formItem && initFormItem}
57
- class="combobox-input"
58
- value={props.format ? props.format(props.value) : '' + (props.value || '')}
59
- readonly={props.readonly}
60
- onfocus={() => props.popupOnFocus && popup.openPopup()}
61
- onclick={() => props.readonly && !props.popupOnFocus && popup.togglePopup()}
62
- ></input>
63
- <svg class="icon icon-s" aria-hidden={true} onclick={() => popup.togglePopup()}>
64
- <use href="#icon-dropdown"></use>
65
- </svg>
66
- </div>
67
- <Popup
68
- api={(api) => {
69
- popup = api;
70
- props.api && props.api(popup);
71
- }}
72
- onPopup={props.onPopup}
73
- {...props.popup}
74
- >
75
- {props.children}
76
- </Popup>
61
+ <div
62
+ ref={(dom) => {
63
+ api = initDropdown(dom, () => <div class="combobox-popup">{props.popup()}</div>);
64
+ props.api && props.api(api);
65
+ }}
66
+ class={combineClass('combobox', props.class)}
67
+ {...disableAutoCloseEvent}
68
+ {...omitProps(props, OMIT_PROPS)}
69
+ >
70
+ <input
71
+ ref={formItem && initFormItem}
72
+ class="combobox-input"
73
+ value={props.format ? props.format(props.value) : '' + (props.value || '')}
74
+ readonly={true}
75
+ onfocus={() => props.popupOnFocus && api.openPopup()}
76
+ onclick={() => !props.popupOnFocus && api.togglePopup()}
77
+ ></input>
78
+ <svg class="combobox-icon icon icon-s" aria-hidden={true} onclick={() => api.togglePopup()}>
79
+ <use href="#icon-dropdown"></use>
80
+ </svg>
77
81
  </div>
78
82
  );
79
83
  };