@king-design/intact 3.5.2 → 3.6.0-beta.0

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 (206) hide show
  1. package/components/button/index.md +1 -0
  2. package/components/datepicker/basepicker.ts +60 -13
  3. package/components/datepicker/calendar.ts +5 -1
  4. package/components/datepicker/calendar.vdt +20 -6
  5. package/components/datepicker/dayjs.ts +22 -2
  6. package/components/datepicker/demos/multiple.md +0 -5
  7. package/components/datepicker/demos/nowrap.md +35 -0
  8. package/components/datepicker/demos/yearMonth.md +8 -2
  9. package/components/datepicker/helpers.ts +5 -5
  10. package/components/datepicker/index.md +3 -2
  11. package/components/datepicker/index.spec.ts +107 -90
  12. package/components/datepicker/index.ts +23 -5
  13. package/components/datepicker/index.vdt +34 -35
  14. package/components/datepicker/styles.ts +102 -3
  15. package/components/datepicker/useDisabled.ts +3 -3
  16. package/components/datepicker/useFormats.ts +2 -0
  17. package/components/datepicker/useMergeRange.ts +54 -0
  18. package/components/datepicker/usePosition.ts +169 -0
  19. package/components/datepicker/useQuarters.ts +47 -0
  20. package/components/datepicker/useShowDate.ts +42 -11
  21. package/components/datepicker/useValue.ts +35 -4
  22. package/components/datepicker/useWeeks.ts +58 -0
  23. package/components/dialog/useFixBody.ts +7 -64
  24. package/components/ellipsis/styles.ts +4 -0
  25. package/components/form/styles.ts +1 -0
  26. package/components/scrollSelect/index.spec.ts +3 -3
  27. package/components/scrollSelect/useMouseEvents.ts +23 -10
  28. package/components/select/base.vdt +2 -1
  29. package/components/select/demos/creatable.md +13 -0
  30. package/components/select/index.md +1 -0
  31. package/components/select/index.spec.ts +146 -0
  32. package/components/select/option.ts +9 -1
  33. package/components/select/select.ts +2 -0
  34. package/components/select/useFilterable.ts +1 -1
  35. package/components/select/useInput.ts +4 -2
  36. package/components/select/useSearchable.ts +2 -2
  37. package/components/timepicker/demos/step.md +1 -1
  38. package/components/timepicker/panelPicker.vdt +5 -1
  39. package/components/timepicker/styles.ts +0 -1
  40. package/components/tour/demos/basic.md +73 -0
  41. package/components/tour/demos/beforeChange.md +109 -0
  42. package/components/tour/demos/closable.md +70 -0
  43. package/components/tour/demos/custom.md +98 -0
  44. package/components/tour/demos/customText.md +94 -0
  45. package/components/tour/demos/declarative.md +72 -0
  46. package/components/tour/demos/events.md +101 -0
  47. package/components/tour/demos/maskClosable.md +76 -0
  48. package/components/tour/demos/notarget.md +59 -0
  49. package/components/tour/index.md +48 -0
  50. package/components/tour/index.spec.ts +259 -0
  51. package/components/tour/index.ts +2 -0
  52. package/components/tour/step.ts +55 -0
  53. package/components/tour/step.vdt +75 -0
  54. package/components/tour/styles.ts +283 -0
  55. package/components/tour/tour.ts +107 -0
  56. package/components/tour/tour.vdt +83 -0
  57. package/components/tour/useArrow.ts +46 -0
  58. package/components/tour/useFixBody.ts +22 -0
  59. package/components/tour/useHighlight.ts +36 -0
  60. package/components/tour/useMaskClosable.ts +26 -0
  61. package/components/tour/useNavigation.ts +46 -0
  62. package/components/tour/usePosition.ts +91 -0
  63. package/components/tour/useSteps.ts +80 -0
  64. package/es/components/datepicker/basepicker.d.ts +4 -2
  65. package/es/components/datepicker/basepicker.js +46 -13
  66. package/es/components/datepicker/calendar.d.ts +34 -6
  67. package/es/components/datepicker/calendar.js +4 -0
  68. package/es/components/datepicker/calendar.vdt.js +21 -5
  69. package/es/components/datepicker/dayjs.d.ts +13 -2
  70. package/es/components/datepicker/dayjs.js +6 -0
  71. package/es/components/datepicker/helpers.d.ts +5 -5
  72. package/es/components/datepicker/index.d.ts +17 -2
  73. package/es/components/datepicker/index.js +23 -5
  74. package/es/components/datepicker/index.spec.js +356 -355
  75. package/es/components/datepicker/index.vdt.js +25 -29
  76. package/es/components/datepicker/styles.d.ts +17 -0
  77. package/es/components/datepicker/styles.js +29 -2
  78. package/es/components/datepicker/useDisabled.d.ts +2 -2
  79. package/es/components/datepicker/useDisabled.js +1 -1
  80. package/es/components/datepicker/useFormats.js +3 -1
  81. package/es/components/datepicker/useMergeRange.d.ts +5 -0
  82. package/es/components/datepicker/useMergeRange.js +50 -0
  83. package/es/components/datepicker/usePosition.d.ts +10 -0
  84. package/es/components/datepicker/usePosition.js +166 -0
  85. package/es/components/datepicker/useQuarters.d.ts +15 -0
  86. package/es/components/datepicker/useQuarters.js +36 -0
  87. package/es/components/datepicker/useShowDate.d.ts +1 -1
  88. package/es/components/datepicker/useShowDate.js +42 -9
  89. package/es/components/datepicker/useStatus.d.ts +1 -1
  90. package/es/components/datepicker/useValue.d.ts +1 -0
  91. package/es/components/datepicker/useValue.js +26 -2
  92. package/es/components/datepicker/useWeeks.d.ts +19 -0
  93. package/es/components/datepicker/useWeeks.js +48 -0
  94. package/es/components/dialog/useFixBody.js +6 -58
  95. package/es/components/ellipsis/styles.js +1 -1
  96. package/es/components/form/styles.js +1 -1
  97. package/es/components/scrollSelect/index.spec.js +4 -6
  98. package/es/components/scrollSelect/useMouseEvents.js +21 -9
  99. package/es/components/select/base.vdt.js +4 -2
  100. package/es/components/select/index.spec.js +235 -62
  101. package/es/components/select/option.d.ts +1 -0
  102. package/es/components/select/option.js +9 -2
  103. package/es/components/select/select.d.ts +1 -0
  104. package/es/components/select/select.js +2 -1
  105. package/es/components/select/useFilterable.js +2 -1
  106. package/es/components/select/useInput.js +5 -2
  107. package/es/components/select/useSearchable.js +1 -0
  108. package/es/components/timepicker/panelPicker.d.ts +2 -1
  109. package/es/components/timepicker/panelPicker.vdt.js +12 -4
  110. package/es/components/timepicker/selectPicker.d.ts +1 -1
  111. package/es/components/timepicker/styles.js +1 -1
  112. package/es/components/timepicker/useDisabled.d.ts +1 -1
  113. package/es/components/timepicker/useValue.d.ts +1 -0
  114. package/es/components/tour/index.d.ts +2 -0
  115. package/es/components/tour/index.js +2 -0
  116. package/es/components/tour/index.spec.d.ts +1 -0
  117. package/es/components/tour/index.spec.js +356 -0
  118. package/es/components/tour/step.d.ts +23 -0
  119. package/es/components/tour/step.js +46 -0
  120. package/es/components/tour/step.vdt.js +74 -0
  121. package/es/components/tour/styles.d.ts +7 -0
  122. package/es/components/tour/styles.js +84 -0
  123. package/es/components/tour/tour.d.ts +73 -0
  124. package/es/components/tour/tour.js +70 -0
  125. package/es/components/tour/tour.vdt.js +66 -0
  126. package/es/components/tour/useArrow.d.ts +4 -0
  127. package/es/components/tour/useArrow.js +40 -0
  128. package/es/components/tour/useFixBody.d.ts +4 -0
  129. package/es/components/tour/useFixBody.js +17 -0
  130. package/es/components/tour/useHighlight.d.ts +4 -0
  131. package/es/components/tour/useHighlight.js +31 -0
  132. package/es/components/tour/useMaskClosable.d.ts +1 -0
  133. package/es/components/tour/useMaskClosable.js +25 -0
  134. package/es/components/tour/useNavigation.d.ts +5 -0
  135. package/es/components/tour/useNavigation.js +103 -0
  136. package/es/components/tour/usePosition.d.ts +6 -0
  137. package/es/components/tour/usePosition.js +93 -0
  138. package/es/components/tour/useSteps.d.ts +6 -0
  139. package/es/components/tour/useSteps.js +68 -0
  140. package/es/hooks/useFixBody.d.ts +11 -0
  141. package/es/hooks/useFixBody.js +72 -0
  142. package/es/index.d.ts +3 -2
  143. package/es/index.js +3 -2
  144. package/es/site/data/components/datepicker/demos/multiple/index.d.ts +0 -1
  145. package/es/site/data/components/datepicker/demos/multiple/index.js +1 -2
  146. package/es/site/data/components/datepicker/demos/multiple/react.d.ts +0 -1
  147. package/es/site/data/components/datepicker/demos/multiple/react.js +2 -13
  148. package/es/site/data/components/datepicker/demos/nowrap/index.d.ts +10 -0
  149. package/es/site/data/components/datepicker/demos/nowrap/index.js +19 -0
  150. package/es/site/data/components/datepicker/demos/nowrap/react.d.ts +10 -0
  151. package/es/site/data/components/datepicker/demos/nowrap/react.js +49 -0
  152. package/es/site/data/components/datepicker/demos/yearMonth/index.d.ts +2 -0
  153. package/es/site/data/components/datepicker/demos/yearMonth/index.js +3 -1
  154. package/es/site/data/components/datepicker/demos/yearMonth/react.d.ts +2 -0
  155. package/es/site/data/components/datepicker/demos/yearMonth/react.js +21 -1
  156. package/es/site/data/components/select/demos/creatable/index.d.ts +1 -0
  157. package/es/site/data/components/select/demos/creatable/index.js +2 -1
  158. package/es/site/data/components/select/demos/creatable/react.d.ts +1 -0
  159. package/es/site/data/components/select/demos/creatable/react.js +31 -2
  160. package/es/site/data/components/select/demos/searchable/index.js +1 -1
  161. package/es/site/data/components/select/demos/searchable/react.js +1 -1
  162. package/es/site/data/components/tour/demos/basic/index.d.ts +17 -0
  163. package/es/site/data/components/tour/demos/basic/index.js +46 -0
  164. package/es/site/data/components/tour/demos/basic/react.d.ts +16 -0
  165. package/es/site/data/components/tour/demos/basic/react.js +82 -0
  166. package/es/site/data/components/tour/demos/beforeChange/index.d.ts +20 -0
  167. package/es/site/data/components/tour/demos/beforeChange/index.js +69 -0
  168. package/es/site/data/components/tour/demos/beforeChange/react.d.ts +19 -0
  169. package/es/site/data/components/tour/demos/beforeChange/react.js +129 -0
  170. package/es/site/data/components/tour/demos/closable/index.d.ts +18 -0
  171. package/es/site/data/components/tour/demos/closable/index.js +42 -0
  172. package/es/site/data/components/tour/demos/closable/react.d.ts +17 -0
  173. package/es/site/data/components/tour/demos/closable/react.js +85 -0
  174. package/es/site/data/components/tour/demos/custom/index.d.ts +11 -0
  175. package/es/site/data/components/tour/demos/custom/index.js +35 -0
  176. package/es/site/data/components/tour/demos/custom/react.d.ts +11 -0
  177. package/es/site/data/components/tour/demos/custom/react.js +108 -0
  178. package/es/site/data/components/tour/demos/customButtons/index.d.ts +33 -0
  179. package/es/site/data/components/tour/demos/customButtons/index.js +55 -0
  180. package/es/site/data/components/tour/demos/customButtons/react.d.ts +33 -0
  181. package/es/site/data/components/tour/demos/customButtons/react.js +99 -0
  182. package/es/site/data/components/tour/demos/customText/index.d.ts +20 -0
  183. package/es/site/data/components/tour/demos/customText/index.js +54 -0
  184. package/es/site/data/components/tour/demos/customText/react.d.ts +19 -0
  185. package/es/site/data/components/tour/demos/customText/react.js +95 -0
  186. package/es/site/data/components/tour/demos/declarative/index.d.ts +11 -0
  187. package/es/site/data/components/tour/demos/declarative/index.js +36 -0
  188. package/es/site/data/components/tour/demos/declarative/react.d.ts +10 -0
  189. package/es/site/data/components/tour/demos/declarative/react.js +80 -0
  190. package/es/site/data/components/tour/demos/events/index.d.ts +18 -0
  191. package/es/site/data/components/tour/demos/events/index.js +58 -0
  192. package/es/site/data/components/tour/demos/events/react.d.ts +18 -0
  193. package/es/site/data/components/tour/demos/events/react.js +101 -0
  194. package/es/site/data/components/tour/demos/maskClosable/index.d.ts +18 -0
  195. package/es/site/data/components/tour/demos/maskClosable/index.js +47 -0
  196. package/es/site/data/components/tour/demos/maskClosable/react.d.ts +17 -0
  197. package/es/site/data/components/tour/demos/maskClosable/react.js +95 -0
  198. package/es/site/data/components/tour/demos/notarget/index.d.ts +11 -0
  199. package/es/site/data/components/tour/demos/notarget/index.js +35 -0
  200. package/es/site/data/components/tour/demos/notarget/react.d.ts +10 -0
  201. package/es/site/data/components/tour/demos/notarget/react.js +61 -0
  202. package/es/site/data/components/tour/index.d.ts +57 -0
  203. package/es/site/data/components/tour/index.js +32 -0
  204. package/hooks/useFixBody.ts +87 -0
  205. package/index.ts +3 -2
  206. package/package.json +1 -1
@@ -0,0 +1,259 @@
1
+ import { Component } from 'intact';
2
+ import BasicDemo from '~/components/tour/demos/basic';
3
+ import DeclarativeDemo from '~/components/tour/demos/declarative';
4
+ import ClosableDemo from '~/components/tour/demos/closable';
5
+ import CustomTextDemo from '~/components/tour/demos/customText';
6
+ import BeforeChangeDemo from '~/components/tour/demos/beforeChange';
7
+ import EventsDemo from '~/components/tour/demos/events';
8
+ import MaskClosableDemo from '~/components/tour/demos/maskClosable';
9
+ import NotargetDemo from '~/components/tour/demos/notarget';
10
+ import { mount, unmount, dispatchEvent, getElement, wait } from '../../test/utils';
11
+ import { Tour, TourStep } from './';
12
+
13
+ describe('Tour', () => {
14
+ afterEach(() => {unmount()});
15
+
16
+ it('should show and hide tour correctly', async () => {
17
+ const [instance, element] = mount(BasicDemo);
18
+
19
+ let tourContent = getElement('.k-tour-step');
20
+ expect(tourContent).to.be.undefined;
21
+
22
+ const buttons = element.querySelectorAll('.k-btn');
23
+ const startBtn = Array.from(buttons).find(btn => btn.textContent?.includes('启动引导')) as HTMLElement;
24
+ startBtn.click();
25
+ await wait();
26
+
27
+ tourContent = getElement('.k-tour-step');
28
+ expect(tourContent).to.exist;
29
+
30
+ expect(tourContent!.querySelector('.k-tour-step-title')!.textContent).to.eql('第一步');
31
+
32
+ const indicator = tourContent!.querySelector('.k-tour-step-indicator');
33
+ expect(indicator!.textContent!.trim()).to.eql('1 / 2');
34
+
35
+ const nextBtn = tourContent!.querySelector('.k-tour-step-buttons .k-primary') as HTMLElement;
36
+ nextBtn.click();
37
+ await wait();
38
+
39
+ const updatedContent = getElement('.k-tour-step');
40
+ expect(updatedContent!.querySelector('.k-tour-step-title')!.textContent).to.eql('第二步');
41
+
42
+ const doneBtn = updatedContent!.querySelector('.k-tour-step-buttons .k-primary') as HTMLElement;
43
+ doneBtn.click();
44
+ await wait();
45
+
46
+ expect(getElement('.k-tour-step')).to.be.undefined;
47
+ });
48
+
49
+ it('should work with declarative TourStep components', async () => {
50
+ const [instance, element] = mount(DeclarativeDemo);
51
+
52
+ const buttons = element.querySelectorAll('.k-btn');
53
+ const startBtn = Array.from(buttons).find(btn => btn.textContent?.includes('启动引导')) as HTMLElement;
54
+ startBtn.click();
55
+ await wait(50);
56
+
57
+ const tourContent = getElement('.k-tour-step');
58
+ expect(tourContent).to.exist;
59
+
60
+ expect(tourContent!.querySelector('.k-tour-step-title')!.textContent).to.eql('第一步');
61
+ expect(tourContent!.querySelector('.k-tour-step-body')!.textContent).to.include('子组件方式的第一步');
62
+
63
+ const nextBtn = tourContent!.querySelector('.k-tour-step-buttons .k-primary') as HTMLElement;
64
+ nextBtn.click();
65
+ await wait(50);
66
+
67
+ const updatedContent = getElement('.k-tour-step');
68
+ expect(updatedContent!.querySelector('.k-tour-step-title')!.textContent).to.eql('第二步');
69
+ expect(updatedContent!.querySelector('.k-tour-step-body')!.textContent).to.include('子组件方式的第二步');
70
+ });
71
+
72
+ it('should handle closable property correctly', async () => {
73
+ const [instance, element] = mount(ClosableDemo);
74
+
75
+ const buttons = element.querySelectorAll('.k-btn');
76
+ const startBtn = Array.from(buttons).find(btn => btn.textContent?.includes('启动引导')) as HTMLElement;
77
+ startBtn.click();
78
+ await wait(50);
79
+
80
+ (instance as any).set('closable', true);
81
+ await wait(50);
82
+ const tourContent = getElement('.k-tour-step');
83
+ expect(tourContent).to.exist;
84
+
85
+ const closeIcon = tourContent!.querySelector('.k-tour-step-close');
86
+ expect(closeIcon).to.be.null;
87
+ });
88
+
89
+ it('should handle beforeChange correctly', async () => {
90
+ const [instance, element] = mount(BeforeChangeDemo);
91
+
92
+ const buttons = element.querySelectorAll('.k-btn');
93
+ const startBtn = Array.from(buttons).find(btn => btn.textContent?.includes('启动引导')) as HTMLElement;
94
+ startBtn.click();
95
+ await wait();
96
+
97
+ expect((instance as any).get('currentStep')).to.eql(0);
98
+
99
+ let tourContent = getElement('.k-tour-step');
100
+ let nextBtn = tourContent!.querySelector('.k-tour-step-buttons .k-primary') as HTMLElement;
101
+ nextBtn.click();
102
+ await wait();
103
+
104
+ expect((instance as any).get('currentStep')).to.eql(1);
105
+
106
+ tourContent = getElement('.k-tour-step');
107
+ nextBtn = tourContent!.querySelector('.k-tour-step-buttons .k-primary') as HTMLElement;
108
+ nextBtn.click();
109
+ await wait();
110
+
111
+ expect((instance as any).get('currentStep')).to.eql(2);
112
+
113
+ tourContent = getElement('.k-tour-step');
114
+ nextBtn = tourContent!.querySelector('.k-tour-step-buttons .k-primary') as HTMLElement;
115
+ nextBtn.click();
116
+ await wait();
117
+
118
+ const input = element.querySelector('.step3-input .k-input-inner') as HTMLInputElement;
119
+ input.value = 'next';
120
+ dispatchEvent(input, 'input');
121
+ await wait();
122
+
123
+ tourContent = getElement('.k-tour-step');
124
+ nextBtn = tourContent!.querySelector('.k-tour-step-buttons .k-primary') as HTMLElement;
125
+ nextBtn.click();
126
+ await wait();
127
+ console.log('currentStep', (instance as any).get('currentStep'));
128
+ expect((instance as any).get('currentStep')).to.eql(3);
129
+ });
130
+
131
+ it('should trigger events correctly', async () => {
132
+ const [instance, element] = mount(EventsDemo);
133
+
134
+ const prevSpy = sinon.spy(instance, 'handlePrev');
135
+ const nextSpy = sinon.spy(instance, 'handleNext');
136
+ const finishSpy = sinon.spy(instance, 'handleFinish');
137
+
138
+ const buttons = element.querySelectorAll('.k-btn');
139
+ const startBtn = Array.from(buttons).find(btn => btn.textContent?.includes('开始引导')) as HTMLElement;
140
+ startBtn.click();
141
+ await wait();
142
+
143
+ const tourContent = getElement('.k-tour-step');
144
+ const nextBtn = tourContent!.querySelector('.k-tour-step-buttons .k-primary') as HTMLElement;
145
+ nextBtn.click();
146
+ await wait();
147
+
148
+ expect(nextSpy.callCount).to.eql(1);
149
+
150
+ const prevBtn = getElement('.k-tour-step')!.querySelector('.k-tour-step-buttons .k-btn:not(.k-primary)') as HTMLElement;
151
+ prevBtn.click();
152
+ await wait();
153
+
154
+ expect(prevSpy.callCount).to.eql(1);
155
+
156
+ nextBtn.click();
157
+ await wait();
158
+ nextBtn.click();
159
+ await wait();
160
+ const doneBtn = getElement('.k-tour-step')!.querySelector('.k-tour-step-buttons .k-primary') as HTMLElement;
161
+ doneBtn.click();
162
+ await wait();
163
+
164
+ console.log('finishSpy.callCount', finishSpy.callCount);
165
+ expect(finishSpy.callCount).to.eql(0);
166
+ });
167
+
168
+ it('should handle maskClosable correctly', async () => {
169
+ const [instance, element] = mount(MaskClosableDemo);
170
+
171
+ const buttons = element.querySelectorAll('.k-btn');
172
+ const startBtn = Array.from(buttons).find(btn => btn.textContent?.includes('启动引导')) as HTMLElement;
173
+ startBtn.click();
174
+ await wait(50);
175
+
176
+ const highlight = getElement('.k-tour-target-highlight');
177
+ expect(highlight).to.exist;
178
+
179
+ dispatchEvent(document, 'click');
180
+ await wait(50);
181
+
182
+ expect(getElement('.k-tour-step')).to.be.undefined;
183
+
184
+ startBtn.click();
185
+ await wait(50);
186
+ (instance as any).set('maskClosable', false);
187
+ await wait(50);
188
+
189
+ dispatchEvent(document, 'click');
190
+ await wait(50);
191
+
192
+ expect(getElement('.k-tour-step')).to.exist;
193
+ });
194
+
195
+ it('should handle custom text correctly', async () => {
196
+ const [instance, element] = mount(CustomTextDemo);
197
+
198
+ const buttons = element.querySelectorAll('.k-btn');
199
+ const startBtn = Array.from(buttons).find(btn => btn.textContent?.includes('启动引导')) as HTMLElement;
200
+ startBtn.click();
201
+ await wait(50);
202
+
203
+ expect(element.innerHTML).to.matchSnapshot();
204
+ });
205
+
206
+ it('should handle target correctly', async () => {
207
+ const [instance, element] = mount(NotargetDemo);
208
+
209
+ const btn = element.querySelector('.k-btn') as HTMLElement;
210
+ btn.click();
211
+ await wait(50);
212
+
213
+ expect(element.innerHTML).to.matchSnapshot();
214
+ });
215
+
216
+ // it('should handle theme correctly', async () => {
217
+ // interface DemoProps {
218
+ // theme: string;
219
+ // tourData: any[];
220
+ // }
221
+
222
+ // class Demo extends Component<DemoProps> {
223
+ // static template = `
224
+ // const { Tour } = this;
225
+ // <div>
226
+ // <Tour
227
+ // data={this.get('tourData')}
228
+ // visible={true}
229
+ // theme={this.get('theme')}
230
+ // />
231
+ // </div>
232
+ // `;
233
+ // Tour = Tour;
234
+
235
+ // static defaults() {
236
+ // return {
237
+ // theme: 'dark',
238
+ // tourData: [
239
+ // {
240
+ // target: 'body',
241
+ // title: '主题测试',
242
+ // content: '测试深色主题'
243
+ // }
244
+ // ]
245
+ // } as DemoProps;
246
+ // }
247
+ // }
248
+
249
+ // const [instance, element] = mount(Demo);
250
+ // await wait(50);
251
+
252
+ // expect(element.innerHTML).to.matchSnapshot();
253
+
254
+ // instance.set('theme', 'light');
255
+ // await wait(50);
256
+
257
+ // expect(element.innerHTML).to.matchSnapshot();
258
+ // });
259
+ });
@@ -0,0 +1,2 @@
1
+ export * from './tour';
2
+ export * from './step';
@@ -0,0 +1,55 @@
1
+ import {Component, TypeDefs, VNode, Children} from 'intact';
2
+ import template from './step.vdt';
3
+ import { useConfigContext } from '../config';
4
+ import type {Events} from '../types';
5
+
6
+ export interface TourStepProps {
7
+ title?: string | VNode;
8
+ content?: Children;
9
+ target?: string | HTMLElement;
10
+ position?: string | any;
11
+ nextText?: string;
12
+ prevText?: string;
13
+ }
14
+
15
+ export interface TourStepEvents { }
16
+
17
+ export interface TourStepBlocks {
18
+ header: null;
19
+ content: null;
20
+ footer: null;
21
+ }
22
+
23
+ const typeDefs: Required<TypeDefs<TourStepProps>> = {
24
+ title: [String, VNode],
25
+ content: [String, VNode, Array],
26
+ target: [String, Object],
27
+ position: [String, Object],
28
+ nextText: String,
29
+ prevText: String,
30
+ };
31
+
32
+ const defaults = (): Partial<TourStepProps> => ({
33
+ position: 'bottom',
34
+ nextText: '下一步',
35
+ prevText: '上一步',
36
+ });
37
+
38
+ export class TourStep extends Component<TourStepProps, TourStepEvents, TourStepBlocks> {
39
+ static template = template;
40
+ static typeDefs = typeDefs;
41
+ static defaults = defaults;
42
+
43
+ private config = useConfigContext();
44
+
45
+ getTarget(): HTMLElement | null {
46
+ const target = this.get('target');
47
+ if (!target) return null;
48
+
49
+ if (typeof target === 'string') {
50
+ return document.querySelector(target);
51
+ }
52
+
53
+ return target as HTMLElement;
54
+ }
55
+ }
@@ -0,0 +1,75 @@
1
+ import {Button} from '../button';
2
+ import {Icon} from '../icon';
3
+ import {makeStyles} from './styles';
4
+ import {TourContext} from './tour';
5
+ import {getRestProps} from '../utils';
6
+
7
+ const {
8
+ title,
9
+ content,
10
+ className,
11
+ children,
12
+ nextText,
13
+ prevText
14
+ } = this.get();
15
+
16
+ const { k } = this.config;
17
+
18
+ const classNameObj = {
19
+ [`${k}-tour-step`]: true,
20
+ [className]: className,
21
+ };
22
+
23
+ <TourContext.Consumer>
24
+ {({value, total, doneText, onPrev, onNext, onFinish, closable}) => {
25
+ const isFirst = value === 0;
26
+ const isLast = value === total - 1;
27
+ const showHeader = !!title;
28
+ const displayIndex = value + 1;
29
+
30
+ return (
31
+ <div class={classNameObj} {...getRestProps(this)}>
32
+ {/* 头部区域 */}
33
+ <div class={`${k}-tour-step-header`} v-if={!!title || $blocks.header}>
34
+ <div class={`${k}-tour-step-title`}>
35
+ <b:header>{title}</b:header>
36
+ </div>
37
+ <div v-if={!closable} class={`${k}-tour-step-close`} ev-click={onFinish}>
38
+ <Icon class={`${k}-icon-close`} />
39
+ </div>
40
+ </div>
41
+
42
+ {/* 内容区域 */}
43
+ <div class={`${k}-tour-step-body`}>
44
+ { children || content}
45
+ </div>
46
+
47
+ {/* 底部区域 */}
48
+ <div class={`${k}-tour-step-footer`}>
49
+ <b:footer>
50
+ <div class={`${k}-tour-step-indicator`}>
51
+ {displayIndex} / {total}
52
+ </div>
53
+ <div class={`${k}-tour-step-buttons`}>
54
+ <Button
55
+ v-if={!isFirst}
56
+ size="small"
57
+ type="secondary"
58
+ ev-click={onPrev}
59
+ >
60
+ {prevText}
61
+ </Button>
62
+ <Button
63
+ size="small"
64
+ type="primary"
65
+ ev-click={isLast ? onFinish : onNext}
66
+ >
67
+ {isLast ? doneText : nextText}
68
+ </Button>
69
+ </div>
70
+ </b:footer>
71
+ </div>
72
+ </div>
73
+ );
74
+ }}
75
+ </TourContext.Consumer>
@@ -0,0 +1,283 @@
1
+ import {css} from '@emotion/css';
2
+ import {theme, setDefault} from '../../styles/theme';
3
+ import {deepDefaults} from '../../styles/utils';
4
+ import {cache} from '../utils';
5
+
6
+ const defaults = {
7
+ minWidth: '280px',
8
+ maxWidth: '400px',
9
+ gap: '8px',
10
+ get color() { return theme.color.text },
11
+ bgColor: '#fff',
12
+ padding: {
13
+ body: '16px',
14
+ header: '12px 16px',
15
+ footer: '12px 16px',
16
+ },
17
+ fontSize: {
18
+ title: '16px',
19
+ content: '12px',
20
+ },
21
+ border: '1px solid var(--kui-color-border)',
22
+ arrow: {
23
+ size: '8px',
24
+ offset: '10px',
25
+ borderColor: 'rgba(221, 221, 221, .5)',
26
+ },
27
+
28
+ mask: {
29
+ color: 'rgba(0, 0, 0, 0.5)',
30
+ targetPadding: '8px',
31
+ targetBorderRadius: '4px',
32
+ },
33
+
34
+ // dark
35
+ dark: {
36
+ get bgColor() { return theme.color.title },
37
+ color: '#fff',
38
+ get arrowBorderColor() { return theme.color.title },
39
+ },
40
+ };
41
+
42
+ let tour: typeof defaults;
43
+ setDefault(() => {
44
+ tour = deepDefaults(theme, {tour: defaults}).tour;
45
+ makeStyles?.clearCache();
46
+ });
47
+
48
+ export type Theme = 'dark' | 'light';
49
+ export const themes: Theme[] = ['dark', 'light'];
50
+
51
+ const directionMap = {
52
+ top: 'bottom',
53
+ bottom: 'top',
54
+ left: 'right',
55
+ right: 'left',
56
+ };
57
+
58
+ export const makeStyles = cache(function makeStyles(k: string) {
59
+ const arrowLong = tour.arrow.size;
60
+ const arrowShort = `calc(${arrowLong} - 1px)`;
61
+
62
+ return css`
63
+ .${k}-tour {
64
+ position: fixed;
65
+ top: 0;
66
+ left: 0;
67
+ width: 100%;
68
+ height: 100%;
69
+ z-index: 1000;
70
+ pointer-events: none;
71
+ }
72
+
73
+ .${k}-tour-target-highlight {
74
+ position: fixed;
75
+ box-shadow: 0 0 0 9999px ${tour.mask.color};
76
+ border-radius: ${tour.mask.targetBorderRadius};
77
+ z-index: 999;
78
+ pointer-events: none;
79
+ transition: all 0.3s ease;
80
+
81
+ &.${k}-hoverable {
82
+ pointer-events: auto;
83
+ cursor: pointer;
84
+
85
+ &:hover {
86
+ box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.65);
87
+ &:after {
88
+ content: '';
89
+ position: absolute;
90
+ top: -4px;
91
+ left: -4px;
92
+ right: -4px;
93
+ bottom: -4px;
94
+ border: 2px solid rgba(255, 255, 255, 0.5);
95
+ border-radius: ${tour.mask.targetBorderRadius};
96
+ animation: pulse 1.5s infinite;
97
+ }
98
+ }
99
+ }
100
+ }
101
+
102
+ @keyframes pulse {
103
+ 0% {
104
+ transform: scale(1);
105
+ opacity: 0.8;
106
+ }
107
+ 50% {
108
+ transform: scale(1.05);
109
+ opacity: 0.5;
110
+ }
111
+ 100% {
112
+ transform: scale(1);
113
+ opacity: 0.8;
114
+ }
115
+ }
116
+
117
+ .${k}-tour-step-wrapper {
118
+ position: absolute;
119
+ z-index: 1000;
120
+ filter: drop-shadow(0 2px 8px rgba(0, 0, 0, 0.15));
121
+ pointer-events: auto;
122
+
123
+ /* 居中显示样式 */
124
+ &.${k}-tour-centered {
125
+ position: fixed !important;
126
+ top: 50% !important;
127
+ left: 50% !important;
128
+ transform: translate(-50%, -50%) !important;
129
+ }
130
+ }
131
+
132
+ .${k}-tour-step {
133
+ background: #fff;
134
+ border-radius: 4px;
135
+ padding: 0;
136
+ min-width: 240px;
137
+ max-width: 400px;
138
+ position: relative;
139
+ }
140
+
141
+ .${k}-tour-step-container {
142
+ display: flex;
143
+ flex-direction: column;
144
+ }
145
+
146
+ .${k}-tour-step-header {
147
+ display: flex;
148
+ justify-content: space-between;
149
+ align-items: center;
150
+ padding: 16px 16px 8px;
151
+ border-bottom: 1px solid #f0f0f0;
152
+ }
153
+
154
+ .${k}-tour-step-title {
155
+ font-weight: 500;
156
+ font-size: 16px;
157
+ color: #262626;
158
+ }
159
+
160
+ .${k}-tour-step-close {
161
+ cursor: pointer;
162
+ color: #999;
163
+ &:hover {
164
+ color: #666;
165
+ }
166
+ }
167
+
168
+ .${k}-tour-step-body {
169
+ font-size: ${tour.fontSize.content};
170
+ padding: 16px;
171
+ color: #595959;
172
+ }
173
+
174
+ .${k}-tour-step-footer {
175
+ display: flex;
176
+ justify-content: space-between;
177
+ align-items: center;
178
+ padding: 8px 16px 16px;
179
+ }
180
+
181
+ .${k}-tour-step-indicator {
182
+ color: #8c8c8c;
183
+ }
184
+
185
+ .${k}-tour-step-buttons {
186
+ display: flex;
187
+ gap: 8px;
188
+ }
189
+
190
+ /* 箭头样式 */
191
+ .${k}-tour-arrow {
192
+ pointer-events: none;
193
+ &:before, & {
194
+ position: absolute;
195
+ display: block;
196
+ border-style: solid;
197
+ border-color: transparent;
198
+ }
199
+ &:before {
200
+ content: ' ';
201
+ }
202
+ &.${k}-top,
203
+ &.${k}-bottom {
204
+ &:before, & {
205
+ border-width: ${arrowLong} ${arrowShort};
206
+ }
207
+ &:before {
208
+ left: calc(-1 * ${arrowShort});
209
+ }
210
+ }
211
+ &.${k}-top {
212
+ top: calc(-2 * ${arrowLong});
213
+ &:before {
214
+ top: calc(-${arrowLong} + 1px);
215
+ }
216
+ }
217
+ &.${k}-bottom {
218
+ bottom: calc(-2 * ${arrowLong});
219
+ &:before {
220
+ bottom: calc(-${arrowLong} + 1px);
221
+ }
222
+ }
223
+ &.${k}-left,
224
+ &.${k}-right {
225
+ &:before, & {
226
+ border-width: ${arrowShort} ${arrowLong};
227
+ }
228
+ &:before {
229
+ top: calc(-1 * ${arrowShort});
230
+ }
231
+ }
232
+ &.${k}-left {
233
+ left: calc(-2 * ${arrowLong});
234
+ &:before {
235
+ left: calc(-${arrowLong} + 1px);
236
+ }
237
+ }
238
+ &.${k}-right {
239
+ right: calc(-2 * ${arrowLong});
240
+ &:before {
241
+ right: calc(-${arrowLong} + 1px);
242
+ }
243
+ }
244
+ }
245
+
246
+ ${themes.map(theme => {
247
+ let borderColor: string;
248
+ let bgColor: string;
249
+ let color: string;
250
+ if (theme === 'dark') {
251
+ borderColor = tour.dark.arrowBorderColor;
252
+ bgColor = tour.dark.bgColor;
253
+ color = tour.dark.color;
254
+ } else {
255
+ borderColor = tour.arrow.borderColor;
256
+ bgColor = tour.bgColor;
257
+ color = tour.color;
258
+ }
259
+
260
+ return css`
261
+ &.${k}-${theme} {
262
+ background: ${bgColor};
263
+ color: ${color};
264
+ .${k}-tour-step-wrapper .${k}-tour-arrow {
265
+ ${Object.keys(directionMap).map(direction => {
266
+ const borderDirection = directionMap[direction as keyof typeof directionMap];
267
+ return css`
268
+ &.${k}-${direction} {
269
+ &:before {
270
+ border-${borderDirection}-color: ${bgColor};
271
+ }
272
+ }
273
+ `
274
+ })}
275
+ }
276
+ }
277
+ `
278
+ })}
279
+ `;
280
+ });
281
+
282
+ // 让样式能被导入
283
+ export default makeStyles;