plain-design 1.0.0-beta.146 → 1.0.0-beta.148

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.
@@ -1,131 +1,144 @@
1
- import {designComponent, getComponentCls, mergeAttrs, onBeforeUnmount, PropType, reactive, RenderNode, useClasses, useRefs} from "@peryl/react-compose";
2
- import {ColorPanel} from "./ColorPanel";
3
- import {ColorSvPanel} from "./sub/ColorSvPanel";
4
- import {ColorHueSlider} from "./sub/ColorHueSlider";
5
- import {ColorAlphaSlider} from "./sub/ColorAlphaSlider";
6
- import {Input} from "../Input";
7
- import './color-picker.scss';
8
- import Color from "color";
9
- import {delay} from "@peryl/utils/delay";
10
- //@ts-ignore
11
- import opacityImage from './utils/opacity.png';
12
- import {Reference} from "../Reference";
13
- import {EditProps, useEdit} from "../../uses/useEdit";
14
- import {StyleProps, useStyle} from "../../uses/useStyle";
15
- import {createInputPopperAttrs} from "../../uses/createInputPopperAttrs";
16
- import {ColorPanelPublicPropOptions, renderColorButton} from "./utils/color-picker.utils";
17
- import {usePopperEditor} from "../usePopupEditor";
18
- import {iPopupUseOption} from "../usePopup/utils/popup.utils";
19
-
20
- export const ColorPicker = designComponent({
21
- name: '-color',
22
- expose: {
23
- ColorPanel,
24
- ColorSvPanel,
25
- ColorHueSlider,
26
- ColorAlphaSlider,
27
- },
28
- inheritPropsType: Input,
29
- props: {
30
- ...EditProps,
31
- ...StyleProps,
32
- ...ColorPanelPublicPropOptions,
33
- popperAttrs: { type: Object as PropType<iPopupUseOption> },
34
- type: { type: String },
35
- },
36
- emits: {
37
- onUpdateModelValue: (val?: string) => true,
38
- onBlur: (e: FocusEvent) => true,
39
- onFocus: (e: FocusEvent) => true,
40
- },
41
- scopeSlots: {
42
- default: (scope: { color?: string }) => {},
43
- },
44
- setup({ props, event: { emit }, scopeSlots }) {
45
-
46
- const { editComputed } = useEdit();
47
- const { styleComputed } = useStyle();
48
- const classes = useClasses(() => [getComponentCls('color-picker'),]);
49
- const { refs, onRef } = useRefs({ input: Input });
50
-
51
- const scopedSlotsRender = (() => {
52
- const state = reactive({
53
- el: null as null | HTMLElement
54
- });
55
- const render = (defaultRender: () => RenderNode) => {
56
- if (scopeSlots.default.isExist() || props.type === 'button') {
57
- const content = scopeSlots.default.isExist() ? scopeSlots.default({ color: model.value || props.defaultColor }) : renderColorButton({ size: styleComputed.value.size, value: model.value });
58
- return (<Reference onElementDetected={el => state.el = el}>{content}</Reference>);
59
- } else {
60
- return defaultRender();
61
- }
62
- };
63
- return { state, render };
64
- })();
65
-
66
- const popper = usePopperEditor({
67
- popperAttrs: () => ({
68
- offset: 1,
69
- noArrow: true,
70
- noPadding: true,
71
- ...props.popperAttrs,
72
- }),
73
- reference: () => !editComputed.value.editable ? null : (scopedSlotsRender.state.el || refs.input?.refs.el),
74
- popper: () => (
75
- <ColorPanel
76
- v-model={model.value}
77
- enableAlpha={props.enableAlpha}
78
- format={props.format}
79
- defaultColor={props.defaultColor}
80
- onChange={val => state.inputValue = val}
81
- onDblclickSvPanel={popper.methods.hide}
82
- onMouseDown={(e: any) => {
83
- if (e.target.nodeName === 'INPUT') {return;}
84
- delay().then(() => {refs.input?.focus();});
85
- }}
86
- />
87
- )
88
- });
89
-
90
- const { inputAttrs, state, model } = createInputPopperAttrs({
91
- getValue: () => props.modelValue,
92
- emitChange: emit.onUpdateModelValue,
93
- disableHideOnBlur: true,
94
- emit,
95
- popper,
96
- isValidInputValue: (val) => {
97
- if (!val) {return true;}
98
- try {
99
- Color(val);
100
- return true;
101
- } catch (e) {
102
- return false;
103
- }
104
- },
105
- });
106
-
107
- onBeforeUnmount(() => {popper.methods.dispose();});
108
-
109
- return {
110
- render: () => {
111
- return scopedSlotsRender.render(() =>
112
- <Input
113
- ref={onRef.input}
114
- {...mergeAttrs(
115
- { class: classes.value },
116
- inputAttrs.value,
117
- )}
118
- >
119
- {{
120
- prefix: () => (
121
- <div className="color-picker-tag" style={{ backgroundImage: `url(${opacityImage})` }}>
122
- <div className="color-picker-tag-inner" style={{ backgroundColor: model.value }}/>
123
- </div>
124
- )
125
- }}
126
- </Input>
127
- );
128
- }
129
- };
130
- },
131
- });
1
+ import {designComponent, getComponentCls, mergeAttrs, onBeforeUnmount, PropType, reactive, RenderNode, useClasses, useRefs} from "@peryl/react-compose";
2
+ import {ColorPanel} from "./ColorPanel";
3
+ import {ColorSvPanel} from "./sub/ColorSvPanel";
4
+ import {ColorHueSlider} from "./sub/ColorHueSlider";
5
+ import {ColorAlphaSlider} from "./sub/ColorAlphaSlider";
6
+ import {Input} from "../Input";
7
+ import './color-picker.scss';
8
+ import Color from "color";
9
+ import {delay} from "@peryl/utils/delay";
10
+ //@ts-ignore
11
+ import opacityImage from './utils/opacity.png';
12
+ import {Reference} from "../Reference";
13
+ import {EditProps, useEdit} from "../../uses/useEdit";
14
+ import {StyleProps, useStyle} from "../../uses/useStyle";
15
+ import {createInputPopperAttrs} from "../../uses/createInputPopperAttrs";
16
+ import {ColorPanelPublicPropOptions, renderColorButton} from "./utils/color-picker.utils";
17
+ import {usePopperEditor} from "../usePopupEditor";
18
+ import {iPopupUseOption} from "../usePopup/utils/popup.utils";
19
+
20
+ export const ColorPicker = designComponent({
21
+ name: '-color',
22
+ expose: {
23
+ ColorPanel,
24
+ ColorSvPanel,
25
+ ColorHueSlider,
26
+ ColorAlphaSlider,
27
+ },
28
+ inheritPropsType: Input,
29
+ props: {
30
+ ...EditProps,
31
+ ...StyleProps,
32
+ ...ColorPanelPublicPropOptions,
33
+ popperAttrs: { type: Object as PropType<iPopupUseOption> },
34
+ type: { type: String },
35
+ strict: { type: Boolean, default: true },
36
+ },
37
+ emits: {
38
+ onUpdateModelValue: (val?: string) => true,
39
+ onBlur: (e: FocusEvent) => true,
40
+ onFocus: (e: FocusEvent) => true,
41
+ },
42
+ scopeSlots: {
43
+ default: (scope: { color?: string }) => {},
44
+ },
45
+ setup({ props, event: { emit }, scopeSlots }) {
46
+
47
+ const { editComputed } = useEdit();
48
+ const { styleComputed } = useStyle();
49
+ const classes = useClasses(() => [getComponentCls('color-picker'),]);
50
+ const { refs, onRef } = useRefs({ input: Input });
51
+
52
+ const scopedSlotsRender = (() => {
53
+ const state = reactive({
54
+ el: null as null | HTMLElement
55
+ });
56
+ const render = (defaultRender: () => RenderNode) => {
57
+ if (scopeSlots.default.isExist() || props.type === 'button') {
58
+ const content = scopeSlots.default.isExist() ? scopeSlots.default({ color: model.value || props.defaultColor }) : renderColorButton({ size: styleComputed.value.size, value: model.value });
59
+ return (<Reference onElementDetected={el => state.el = el}>{content}</Reference>);
60
+ } else {
61
+ return defaultRender();
62
+ }
63
+ };
64
+ return { state, render };
65
+ })();
66
+
67
+ const popper = usePopperEditor({
68
+ popperAttrs: () => ({
69
+ offset: 1,
70
+ noArrow: true,
71
+ noPadding: true,
72
+ ...props.popperAttrs,
73
+ }),
74
+ reference: () => !editComputed.value.editable ? null : (scopedSlotsRender.state.el || refs.input?.refs.el),
75
+ popper: () => {
76
+ const validColorString = (() => {
77
+ try {
78
+ Color(model.value);
79
+ return model.value;
80
+ } catch (e) {
81
+ return undefined;
82
+ }
83
+ })();
84
+ return (
85
+ <ColorPanel
86
+ modelValue={validColorString}
87
+ onUpdateModelValue={val => model.value = val}
88
+ enableAlpha={props.enableAlpha}
89
+ format={props.format}
90
+ defaultColor={props.defaultColor}
91
+ onChange={val => state.inputValue = val}
92
+ onDblclickSvPanel={popper.methods.hide}
93
+ onMouseDown={(e: any) => {
94
+ if (e.target.nodeName === 'INPUT') {return;}
95
+ delay().then(() => {refs.input?.focus();});
96
+ }}
97
+ />
98
+ );
99
+ }
100
+ });
101
+
102
+ const { inputAttrs, state, model } = createInputPopperAttrs({
103
+ getValue: () => props.modelValue,
104
+ emitChange: emit.onUpdateModelValue,
105
+ disableHideOnBlur: true,
106
+ emit,
107
+ popper,
108
+ isValidInputValue: (val) => {
109
+ if (!props.strict) {return true;}
110
+ if (!val) {return true;}
111
+ try {
112
+ Color(val);
113
+ return true;
114
+ } catch (e) {
115
+ return false;
116
+ }
117
+ },
118
+ });
119
+
120
+ onBeforeUnmount(() => {popper.methods.dispose();});
121
+
122
+ return {
123
+ render: () => {
124
+ return scopedSlotsRender.render(() =>
125
+ <Input
126
+ ref={onRef.input}
127
+ {...mergeAttrs(
128
+ { class: classes.value },
129
+ inputAttrs.value,
130
+ )}
131
+ >
132
+ {{
133
+ prefix: () => (
134
+ <div className="color-picker-tag" style={{ backgroundImage: `url(${opacityImage})` }}>
135
+ <div className="color-picker-tag-inner" style={{ backgroundColor: model.value }}/>
136
+ </div>
137
+ )
138
+ }}
139
+ </Input>
140
+ );
141
+ }
142
+ };
143
+ },
144
+ });
@@ -97,5 +97,11 @@ export const IconExternal: Record<string, () => RenderNode> = {
97
97
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
98
98
  <path d="M8.99988 4.99976L16.0002 12L8.99988 18.9998V12.9998L2.9999 13.0001L2.99988 11.0001L8.99988 10.9998V4.99976ZM17.9999 18.9999L18 4.99993H20L19.9999 18.9999H17.9999Z"></path>
99
99
  </svg>
100
+ ),
101
+ 'ie-dropper': () => (
102
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
103
+ <path
104
+ d="M15.5355 2.80744C17.0976 1.24534 19.6303 1.24534 21.1924 2.80744C22.7545 4.36953 22.7545 6.90219 21.1924 8.46429L18.3638 11.2929L18.7175 11.6466C19.108 12.0371 19.108 12.6703 18.7175 13.0608C18.327 13.4513 17.6938 13.4513 17.3033 13.0608L16.9498 12.7073L10.7351 18.922C10.1767 19.4804 9.46547 19.861 8.6911 20.0159L6.93694 20.3667C6.54976 20.4442 6.19416 20.6345 5.91496 20.9137L4.92894 21.8997C4.53841 22.2902 3.90525 22.2902 3.51472 21.8997L2.10051 20.4855C1.70999 20.095 1.70999 19.4618 2.10051 19.0713L3.08653 18.0852C3.36574 17.806 3.55605 17.4504 3.63348 17.0633L3.98431 15.3091C4.13919 14.5347 4.51981 13.8235 5.07821 13.2651L11.2929 7.05045L10.9393 6.69686C10.5488 6.30634 10.5488 5.67317 10.9393 5.28265C11.3299 4.89212 11.963 4.89212 12.3535 5.28265L12.7069 5.63604L15.5355 2.80744ZM12.7071 8.46466L6.49242 14.6794C6.21322 14.9586 6.02291 15.3142 5.94548 15.7013L5.59464 17.4555C5.43977 18.2299 5.05915 18.9411 4.50075 19.4995C5.05915 18.9411 5.77035 18.5604 6.54471 18.4056L8.29887 18.0547C8.68605 17.9773 9.04165 17.787 9.32085 17.5078L15.5355 11.2931L12.7071 8.46466Z"></path>
105
+ </svg>
100
106
  )
101
107
  };
@@ -0,0 +1,7 @@
1
+ import _icons from "@peryl/icon/dist/icons.json";
2
+ import {IconExternal} from "../Icon/icon.external";
3
+
4
+ export const DefaultIcons = [
5
+ ..._icons.map(i => `pi-${i}`),
6
+ ...Object.keys(IconExternal),
7
+ ];
@@ -0,0 +1,43 @@
1
+ @include comp(icon-picker-panel) {
2
+ height: 15em;
3
+ width: 24em;
4
+ overflow: hidden;
5
+ .icon-picker-row {
6
+ display: flex;
7
+ align-items: center;
8
+ }
9
+ .icon-picker-item {
10
+ width: 2.5em;
11
+ height: 2.5em;
12
+ margin: 0.25em;
13
+ display: flex;
14
+ align-items: center;
15
+ justify-content: center;
16
+ transition: all ease 300ms;
17
+ cursor: pointer;
18
+
19
+ &:hover {
20
+ background-color: plv(secondary-light-2);
21
+ }
22
+
23
+ &[data-selected=true] {
24
+ background-color: plv(primary-6);
25
+ color: plv(pbfc);
26
+ }
27
+ }
28
+
29
+ @include sizeMixin(icon-picker-panel, (font-size)) {
30
+ .icon-picker-item {
31
+ border-radius: $border-radius;
32
+ }
33
+ }
34
+ }
35
+
36
+ @include comp(icon-picker) {
37
+ .icon-picker-tag {
38
+ width: 2.5em;
39
+ display: flex;
40
+ align-items: center;
41
+ justify-content: center;
42
+ }
43
+ }
@@ -0,0 +1,189 @@
1
+ import {computed, designComponent, getComponentCls, mergeAttrs, onBeforeUnmount, PropType, reactive, RenderNode, useClassCache, useClasses, useRefs} from "@peryl/react-compose";
2
+ import {EditProps, useEdit} from "../../uses/useEdit";
3
+ import {StyleProps, useStyle} from "../../uses/useStyle";
4
+ import Input from "../Input";
5
+ import {Reference} from "../Reference";
6
+ import {usePopperEditor} from "../usePopupEditor";
7
+ import {createInputPopperAttrs} from "../../uses/createInputPopperAttrs";
8
+ import {iPopupUseOption} from "../usePopup/utils/popup.utils";
9
+ import {delay} from "@peryl/utils/delay";
10
+ import Icon from "../Icon";
11
+ import i18n from "../i18n";
12
+ import {chunk} from '@peryl/utils/chunk';
13
+ import './icon-picker.scss';
14
+ import VirtualList from "../VirtualList";
15
+ import {DefaultIcons} from "./DefaultIcons";
16
+
17
+ export const IconPicker = designComponent({
18
+ name: 'icon-picker',
19
+ inheritPropsType: Input,
20
+ props: {
21
+ ...EditProps,
22
+ ...StyleProps,
23
+ modelValue: { type: String },
24
+ popperAttrs: { type: Object as PropType<iPopupUseOption> },
25
+ placeholder: { type: String, default: () => i18n.$it('iconPicker.placeholder').d('请选择或者输入图标') },
26
+ iconList: { type: Array as PropType<string[]> },
27
+ },
28
+ emits: {
29
+ onUpdateModelValue: (val?: string) => true,
30
+ onBlur: (e: FocusEvent) => true,
31
+ onFocus: (e: FocusEvent) => true,
32
+ },
33
+ scopeSlots: {
34
+ default: (scope: { color?: string }) => {},
35
+ },
36
+ setup({ props, event: { emit }, scopeSlots }) {
37
+
38
+ const { editComputed } = useEdit();
39
+ const { styleComputed } = useStyle();
40
+ const classes = useClasses(() => [getComponentCls('icon-picker'),]);
41
+ const { refs, onRef } = useRefs({ input: Input });
42
+
43
+ const panelClasses = useClassCache(() => [
44
+ getComponentCls('icon-picker-panel'),
45
+ `icon-picker-panel-size-${styleComputed.value.size}`
46
+ ]);
47
+
48
+ const iconList = computed((): string[] => {
49
+ const list = props.iconList ?? DefaultIcons;
50
+ const filterText = filter.state.filterText?.trim();
51
+ if (!filterText?.length) {
52
+ return list;
53
+ }
54
+ return list.filter(i => i.indexOf(filterText) > -1);
55
+ });
56
+
57
+ const scopedSlotsRender = (() => {
58
+ const state = reactive({
59
+ el: null as null | HTMLElement
60
+ });
61
+ const render = (defaultRender: () => RenderNode) => {
62
+ if (scopeSlots.default.isExist()) {
63
+ const content = scopeSlots.default.isExist() ? scopeSlots.default({ color: model.value }) : null;
64
+ return (<Reference onElementDetected={el => state.el = el}>{content}</Reference>);
65
+ } else {
66
+ return defaultRender();
67
+ }
68
+ };
69
+ return { state, render };
70
+ })();
71
+
72
+ const filter = (() => {
73
+ const filterState = reactive({
74
+ isShow: false,
75
+ filterText: null as null | undefined | string,
76
+ });
77
+ return {
78
+ state: filterState
79
+ };
80
+ })();
81
+
82
+ const popper = usePopperEditor({
83
+ popperAttrs: () => ({
84
+ offset: 1,
85
+ noArrow: true,
86
+ noPadding: true,
87
+ ...props.popperAttrs,
88
+ }),
89
+ reference: () => !editComputed.value.editable ? null : (scopedSlotsRender.state.el || refs.input?.refs.el),
90
+ onShow: () => {
91
+ filter.state.isShow = true;
92
+ },
93
+ onHide: () => {
94
+ filter.state.isShow = false;
95
+ },
96
+ onClose: () => {
97
+ filter.state.filterText = null;
98
+ },
99
+ popper: () => {
100
+ return (
101
+ <div
102
+ className={panelClasses.value}
103
+ onMouseDown={(e: any) => {
104
+ delay().then(() => {refs.input?.focus();});
105
+ }}>
106
+ <VirtualList
107
+ data={chunk(iconList.value, 8)}
108
+ size={24}
109
+ dynamicSize
110
+ v-slots={{
111
+ default: ({ item: subList, vIndex, vid }) => {
112
+ return (
113
+ <div
114
+ data-vid={vid}
115
+ key={vIndex}
116
+ className="icon-picker-row"
117
+ >
118
+ {(subList as string[]).map(icon => (
119
+ <div
120
+ key={icon}
121
+ className="icon-picker-item"
122
+ data-selected={String(icon === model.value)}
123
+ onClick={() => {
124
+ model.value = icon;
125
+ state.inputValue = icon;
126
+ popper.methods.hide();
127
+ }}
128
+ >
129
+ {(icon.indexOf('ie-') === 0 || icon.indexOf('pi-') === 0) ?
130
+ (<Icon icon={icon}/>) :
131
+ (<span className={icon}/>)}
132
+ </div>
133
+ ))}
134
+ </div>
135
+ );
136
+ }
137
+ }}
138
+ />
139
+ </div>
140
+ );
141
+ }
142
+ });
143
+
144
+ const { inputAttrs, state, model } = createInputPopperAttrs({
145
+ getValue: () => props.modelValue,
146
+ emitChange: emit.onUpdateModelValue,
147
+ disableHideOnBlur: true,
148
+ emit,
149
+ popper,
150
+ handleInputChange: (val) => {
151
+ filter.state.filterText = val;
152
+ if (!filter.state.isShow) {popper.methods.show();}
153
+ },
154
+ });
155
+
156
+ onBeforeUnmount(() => {popper.methods.dispose();});
157
+
158
+ return {
159
+ render: () => {
160
+ return scopedSlotsRender.render(() =>
161
+ <Input
162
+ ref={onRef.input}
163
+ {...mergeAttrs(
164
+ {
165
+ class: classes.value,
166
+ placeholder: editComputed.value.placeholder
167
+ },
168
+ inputAttrs.value,
169
+ )}
170
+ >
171
+ {{
172
+ prefix: () => (
173
+ <div className="icon-picker-tag">
174
+ {!model.value ? <Icon icon="pi-question"/> : (
175
+ model.value.indexOf('ie-') === 0 || model.value.indexOf('pi-') === 0 ?
176
+ (<Icon icon={model.value}/>) :
177
+ (<span className={model.value}/>)
178
+ )}
179
+ </div>
180
+ )
181
+ }}
182
+ </Input>
183
+ );
184
+ }
185
+ };
186
+ },
187
+ });
188
+
189
+ export default IconPicker;
@@ -214,7 +214,7 @@ export function useVirtualList(
214
214
  if (!props.dynamicSize) {
215
215
  start = startIndex * props.size;
216
216
  } else {
217
- start = nodes.value[startIndex].start;
217
+ start = nodes.value[startIndex]?.start ?? 0;
218
218
  }
219
219
 
220
220
  if (!props.horizontal) {