@central-design-system/components 3.0.0-alpha.3 → 3.0.0-alpha.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@central-design-system/components",
3
- "version": "3.0.0-alpha.3",
3
+ "version": "3.0.0-alpha.4",
4
4
  "description": "Central Design System on the Vue 3.0 and TypeScript",
5
5
  "author": "magersoft",
6
6
  "license": "ISC",
@@ -19,6 +19,7 @@
19
19
  },
20
20
  "files": [
21
21
  "dist",
22
+ "src/utils",
22
23
  "src/scss",
23
24
  "nuxt.js"
24
25
  ],
@@ -30,7 +31,7 @@
30
31
  "publish:alpha": "npm publish --tag next"
31
32
  },
32
33
  "peerDependencies": {
33
- "vue": "3.2.47"
34
+ "vue": "^3.2.0"
34
35
  },
35
36
  "devDependencies": {
36
37
  "@types/node": "16.18.3",
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Automatically generated by CDS CLI
3
- * Generated on 5/22/2023, 12:52:07 PM
3
+ * Generated on 5/22/2023, 2:54:43 PM
4
4
  **/
5
5
 
6
6
  /**
@@ -0,0 +1,59 @@
1
+ import { pick, isObject, mergeDeep, getNestedValue, getObjectValueByPath, getPropertyFromItem } from '../helpers';
2
+ import {
3
+ mockHelpersIsObject,
4
+ mockHelpersMergeDeep,
5
+ mockHelpersGetNestedValue,
6
+ mockHelpersGetObjectValueByPath,
7
+ mockHelpersGetPropertyFromItem,
8
+ mockHelpersPick
9
+ } from './mocks/helper.mock';
10
+
11
+ describe('isObject', () => {
12
+ mockHelpersIsObject.forEach(({ name, initial, expected }) => {
13
+ it(name, () => {
14
+ expect(isObject(initial)).toEqual(expected);
15
+ });
16
+ });
17
+ });
18
+
19
+ describe('mergeDeep', () => {
20
+ mockHelpersMergeDeep.forEach(({ name, initial, expected }) => {
21
+ it(name, () => {
22
+ expect(mergeDeep(initial.source, initial.target, initial.arrayFn)).toEqual(expected);
23
+ });
24
+ });
25
+ });
26
+
27
+ describe('getNestedValue', () => {
28
+ mockHelpersGetNestedValue.forEach(({ name, initial, expected }) => {
29
+ it(name, () => {
30
+ expect(getNestedValue(initial.obj, initial.path, initial.fallback)).toEqual(expected);
31
+ });
32
+ });
33
+ });
34
+
35
+ describe('getObjectValueByPath', () => {
36
+ mockHelpersGetObjectValueByPath.forEach(({ name, initial, expected }) => {
37
+ it(name, () => {
38
+ expect(getObjectValueByPath(initial.obj, initial.path, initial.fallback)).toEqual(expected);
39
+ });
40
+ });
41
+ });
42
+
43
+ describe('getPropertyFromItem', () => {
44
+ mockHelpersGetPropertyFromItem.forEach(({ name, initial, expected }) => {
45
+ it(name, () => {
46
+ expect(getPropertyFromItem(initial.item, initial.property, initial.fallback)).toEqual(expected);
47
+ });
48
+ });
49
+ });
50
+
51
+ describe('pick', () => {
52
+ mockHelpersPick.forEach(({ name, initial, expected }) => {
53
+ it(name, () => {
54
+ const [yes, no] = pick(initial.obj, initial.paths);
55
+ expect(yes).toEqual(expected.yes);
56
+ expect(no).toEqual(expected.no);
57
+ });
58
+ });
59
+ });
@@ -0,0 +1,362 @@
1
+ import type { IMockDataProvider } from '@/types/vitest';
2
+ import type { SelectItemKey } from '@components/utils';
3
+
4
+ export const mockHelpersIsObject: IMockDataProvider[] = [
5
+ {
6
+ name: 'returns true for objects',
7
+ initial: {},
8
+ expected: true
9
+ },
10
+ {
11
+ name: 'returns true for objects with value',
12
+ initial: { a: 'foo' },
13
+ expected: true
14
+ },
15
+ {
16
+ name: 'returns false for null',
17
+ initial: null,
18
+ expected: false
19
+ },
20
+ {
21
+ name: 'returns false for undefined',
22
+ initial: undefined,
23
+ expected: false
24
+ },
25
+ {
26
+ name: 'returns false for empty array',
27
+ initial: [],
28
+ expected: false
29
+ },
30
+ {
31
+ name: 'returns false for string',
32
+ initial: 'str',
33
+ expected: false
34
+ },
35
+ {
36
+ name: 'returns false for number',
37
+ initial: 42,
38
+ expected: false
39
+ },
40
+ {
41
+ name: 'returns false for boolean',
42
+ initial: true,
43
+ expected: false
44
+ },
45
+ {
46
+ name: 'returns false for function',
47
+ initial: () => {},
48
+ expected: false
49
+ }
50
+ ];
51
+
52
+ type TMockHelpersMergeDeepInitial = {
53
+ source?: Record<string, any>;
54
+ target?: Record<string, any>;
55
+ arrayFn?: (a: unknown[], b: unknown[]) => unknown[];
56
+ };
57
+ export const mockHelpersMergeDeep: IMockDataProvider<TMockHelpersMergeDeepInitial>[] = [
58
+ {
59
+ name: 'should be merges empty objects',
60
+ initial: {},
61
+ expected: {}
62
+ },
63
+ {
64
+ name: 'should be merges simple objects',
65
+ initial: {
66
+ source: { a: 'foo' },
67
+ target: { b: 'bar' }
68
+ },
69
+ expected: {
70
+ a: 'foo',
71
+ b: 'bar'
72
+ }
73
+ },
74
+ {
75
+ name: 'should be deeply merges nested objects',
76
+ initial: {
77
+ source: {
78
+ a: {
79
+ b: {
80
+ c: 'foo'
81
+ }
82
+ }
83
+ },
84
+ target: {
85
+ a: {
86
+ b: {
87
+ c: 'foo',
88
+ d: 'bar'
89
+ }
90
+ }
91
+ }
92
+ },
93
+ expected: {
94
+ a: {
95
+ b: {
96
+ c: 'foo',
97
+ d: 'bar'
98
+ }
99
+ }
100
+ }
101
+ },
102
+ {
103
+ name: 'should be uses custom arrayFn to merge arrays',
104
+ initial: {
105
+ source: {
106
+ a: [
107
+ {
108
+ a: 'foo'
109
+ }
110
+ ]
111
+ },
112
+ target: {
113
+ a: [
114
+ {
115
+ b: 'bar'
116
+ }
117
+ ]
118
+ },
119
+ arrayFn: (a, b) => a.concat(b)
120
+ },
121
+ expected: {
122
+ a: [{ a: 'foo' }, { b: 'bar' }]
123
+ }
124
+ }
125
+ ];
126
+
127
+ type TMockHelpersGetNestedValueInitial = {
128
+ obj?: Record<string, any>;
129
+ path: (string | number)[];
130
+ fallback?: any;
131
+ };
132
+ export const mockHelpersGetNestedValue: IMockDataProvider<TMockHelpersGetNestedValueInitial>[] = [
133
+ {
134
+ name: 'should return nested value when path is valid',
135
+ initial: {
136
+ obj: { a: { b: { c: 'x' } } },
137
+ path: ['a', 'b', 'c']
138
+ },
139
+ expected: 'x'
140
+ },
141
+ {
142
+ name: 'should return fallback when path is invalid',
143
+ initial: {
144
+ obj: { a: 'x' },
145
+ path: ['a', 'b', 'd'],
146
+ fallback: 'y'
147
+ },
148
+ expected: 'y'
149
+ },
150
+ {
151
+ name: 'should return fallback when obj is undefined',
152
+ initial: {
153
+ obj: undefined,
154
+ path: ['a', 'b', 'd'],
155
+ fallback: 'y'
156
+ },
157
+ expected: 'y'
158
+ },
159
+ {
160
+ name: 'should return obj when path is empty array',
161
+ initial: {
162
+ obj: {},
163
+ path: []
164
+ },
165
+ expected: {}
166
+ },
167
+ {
168
+ name: 'should return obj with fallback if provided and path is empty array',
169
+ initial: {
170
+ obj: undefined,
171
+ path: [],
172
+ fallback: 'y'
173
+ },
174
+ expected: 'y'
175
+ }
176
+ ];
177
+
178
+ type TMockHelpersGetObjectValueByPathInitial = {
179
+ obj?: Record<string, any> | any;
180
+ path: string;
181
+ fallback?: any;
182
+ };
183
+ export const mockHelpersGetObjectValueByPath: IMockDataProvider<TMockHelpersGetObjectValueByPathInitial>[] = [
184
+ {
185
+ name: 'should return nested value when path is valid',
186
+ initial: {
187
+ obj: { a: { b: { c: 'x' } } },
188
+ path: 'a.b.c'
189
+ },
190
+ expected: 'x'
191
+ },
192
+ {
193
+ name: 'should handles indexed arrays',
194
+ initial: {
195
+ obj: { users: [{ name: 'Jane' }, { name: 'John' }] },
196
+ path: 'users[1].name'
197
+ },
198
+ expected: 'John'
199
+ },
200
+ {
201
+ name: 'should return fallback when path is invalid',
202
+ initial: {
203
+ obj: { a: 'x' },
204
+ path: 'a.b.d'
205
+ },
206
+ expected: undefined
207
+ },
208
+ {
209
+ name: 'should return fallback when obj is undefined',
210
+ initial: {
211
+ obj: undefined,
212
+ path: 'a.b.d',
213
+ fallback: 'y'
214
+ },
215
+ expected: 'y'
216
+ },
217
+ {
218
+ name: 'should return undefined when path is empty string',
219
+ initial: {
220
+ obj: {},
221
+ path: ''
222
+ },
223
+ expected: undefined
224
+ },
225
+ {
226
+ name: 'should return obj with fallback if provided and path is empty string',
227
+ initial: {
228
+ obj: undefined,
229
+ path: '',
230
+ fallback: 'y'
231
+ },
232
+ expected: 'y'
233
+ },
234
+ {
235
+ name: "should return obj[path] if it isn't undefined",
236
+ initial: {
237
+ obj: { firstKey: 'value' },
238
+ path: 'firstKey',
239
+ fallback: 'fallbackValue'
240
+ },
241
+ expected: 'value'
242
+ },
243
+ {
244
+ name: 'should return fallback in case of invalid input data',
245
+ initial: {
246
+ obj: null,
247
+ path: null as any,
248
+ fallback: 5
249
+ },
250
+ expected: 5
251
+ }
252
+ ];
253
+
254
+ type TMockHelpersGetPropertyFromItem = {
255
+ item: any;
256
+ property: SelectItemKey;
257
+ fallback?: any;
258
+ };
259
+ export const mockHelpersGetPropertyFromItem: IMockDataProvider<TMockHelpersGetPropertyFromItem>[] = [
260
+ {
261
+ name: 'should return the item if property is null',
262
+ initial: {
263
+ item: 'item',
264
+ property: null as any,
265
+ fallback: 'fallback'
266
+ },
267
+ expected: 'item'
268
+ },
269
+ {
270
+ name: 'should return the item if property is undefined',
271
+ initial: {
272
+ item: undefined,
273
+ property: null as any,
274
+ fallback: 'fallback'
275
+ },
276
+ expected: 'fallback'
277
+ },
278
+ {
279
+ name: 'should return the fallback if item is not an object',
280
+ initial: {
281
+ item: 1,
282
+ property: 'path',
283
+ fallback: 'fallback'
284
+ },
285
+ expected: 'fallback'
286
+ },
287
+ {
288
+ name: 'should return the correct value for a string property',
289
+ initial: {
290
+ item: { path: 'value' },
291
+ property: 'path'
292
+ },
293
+ expected: 'value'
294
+ },
295
+ {
296
+ name: 'should return the correct value for an array property and fallback when not found',
297
+ initial: {
298
+ item: { path: { subpath: 'value' } },
299
+ property: ['path', 'subpath'],
300
+ fallback: 'fallback'
301
+ },
302
+ expected: 'value'
303
+ },
304
+ {
305
+ name: 'should return the correct value for a function property',
306
+ initial: {
307
+ item: { path: 'value' },
308
+ property: (item: any) => item.path,
309
+ fallback: 'fallback'
310
+ },
311
+ expected: 'value'
312
+ },
313
+ {
314
+ name: 'should return the fallback if the function returns undefined',
315
+ initial: {
316
+ item: { path: 'value' },
317
+ property: () => undefined,
318
+ fallback: 'fallback'
319
+ },
320
+ expected: 'fallback'
321
+ }
322
+ ];
323
+
324
+ type TMockHelpersPick = {
325
+ obj: Record<string, any>;
326
+ paths: string[] | RegExp[] | any[];
327
+ };
328
+ export const mockHelpersPick: IMockDataProvider<TMockHelpersPick>[] = [
329
+ {
330
+ name: 'should correctly selects specified properties and returns both picked and unpicked objects',
331
+ initial: {
332
+ obj: { a: 1, b: 2, c: 3 },
333
+ paths: ['a', 'c']
334
+ },
335
+ expected: {
336
+ yes: { a: 1, c: 3 },
337
+ no: { b: 2 }
338
+ }
339
+ },
340
+ {
341
+ name: 'should correctly selects specified properties using regex',
342
+ initial: {
343
+ obj: { a: 1, b: 2, c: 3 },
344
+ paths: [/^[ab]$/]
345
+ },
346
+ expected: {
347
+ yes: { a: 1, b: 2 },
348
+ no: { c: 3 }
349
+ }
350
+ },
351
+ {
352
+ name: 'should returns empty objects for non-existing properties',
353
+ initial: {
354
+ obj: { a: 1, b: 2, c: 3 },
355
+ paths: ['x', 'y', 'z']
356
+ },
357
+ expected: {
358
+ yes: {},
359
+ no: { a: 1, b: 2, c: 3 }
360
+ }
361
+ }
362
+ ];
@@ -0,0 +1,88 @@
1
+ import { IMockDataProvider } from '@/types/vitest';
2
+ import { ComponentObjectPropsOptions } from '@components/shims-vue';
3
+
4
+ export const mockPropFactory: IMockDataProvider<
5
+ { props: ComponentObjectPropsOptions; source: string; defaults?: any },
6
+ ComponentObjectPropsOptions
7
+ >[] = [
8
+ {
9
+ name: 'propFactory',
10
+ initial: {
11
+ props: {
12
+ foo: String,
13
+ bar: Array
14
+ },
15
+ source: 'props'
16
+ },
17
+ expected: {
18
+ foo: {
19
+ source: 'props',
20
+ type: String
21
+ },
22
+ bar: {
23
+ source: 'props',
24
+ type: Array
25
+ }
26
+ }
27
+ },
28
+ {
29
+ name: 'propFactory',
30
+ initial: {
31
+ props: {
32
+ test: {
33
+ type: String,
34
+ default: ''
35
+ }
36
+ },
37
+ source: 'test'
38
+ },
39
+ expected: {
40
+ test: {
41
+ source: 'test',
42
+ type: String,
43
+ default: ''
44
+ }
45
+ }
46
+ },
47
+ {
48
+ name: 'propFactory',
49
+ initial: {
50
+ props: {
51
+ bar: {
52
+ type: Object,
53
+ default: {}
54
+ }
55
+ },
56
+ source: 'bar'
57
+ },
58
+ expected: {
59
+ bar: {
60
+ source: 'bar',
61
+ type: Object,
62
+ default: {}
63
+ }
64
+ }
65
+ },
66
+ {
67
+ name: 'propFactory',
68
+ initial: {
69
+ props: {
70
+ foo: {
71
+ type: String,
72
+ default: undefined
73
+ }
74
+ },
75
+ source: 'foo',
76
+ defaults: {
77
+ foo: 'string'
78
+ }
79
+ },
80
+ expected: {
81
+ foo: {
82
+ default: 'string',
83
+ source: 'foo',
84
+ type: String
85
+ }
86
+ }
87
+ }
88
+ ];
@@ -0,0 +1,9 @@
1
+ import { propsFactory } from '../propsFactory';
2
+ import { mockPropFactory } from './mocks/propFactory.mock';
3
+
4
+ describe('propFactory.ts', () => {
5
+ it.each(mockPropFactory)('should be props', ({ initial, expected }) => {
6
+ const makeProps = propsFactory(initial.props, initial.source);
7
+ expect(makeProps(initial.defaults)).toEqual(expected);
8
+ });
9
+ });
@@ -0,0 +1,76 @@
1
+ import { includes } from './';
2
+
3
+ const block = ['top', 'bottom'] as const;
4
+ const inline = ['start', 'end', 'left', 'right'] as const;
5
+ type Tblock = typeof block[number];
6
+ type Tinline = typeof inline[number];
7
+ export type TAnchor =
8
+ | Tblock
9
+ | Tinline
10
+ | 'center'
11
+ | 'center center'
12
+ | `${Tblock} ${Tinline | 'center'}`
13
+ | `${Tinline} ${Tblock | 'center'}`;
14
+ export type ParsedAnchor =
15
+ | { side: 'center'; align: 'center' }
16
+ | { side: Tblock; align: 'left' | 'right' | 'center' }
17
+ | { side: 'left' | 'right'; align: Tblock | 'center' };
18
+
19
+ /** Parse a raw anchor string into an object */
20
+ export function parseAnchor(anchor: TAnchor) {
21
+ const anchorArr = anchor.split(' ') as [Tblock | Tinline | 'center', Tblock | Tinline | 'center' | undefined];
22
+ const side = anchorArr[0];
23
+ let align = anchorArr[1];
24
+
25
+ if (!align) {
26
+ align = includes(block, side) ? 'start' : includes(inline, side) ? 'top' : 'center';
27
+ }
28
+
29
+ return {
30
+ side: toPhysical(side),
31
+ align: toPhysical(align)
32
+ } as ParsedAnchor;
33
+ }
34
+
35
+ export function toPhysical(str: 'center' | Tblock | Tinline) {
36
+ if (str === 'start') return 'left';
37
+ if (str === 'end') return 'right';
38
+ return str;
39
+ }
40
+
41
+ export function flipSide(anchor: ParsedAnchor) {
42
+ return {
43
+ side: {
44
+ center: 'center',
45
+ top: 'bottom',
46
+ bottom: 'top',
47
+ left: 'right',
48
+ right: 'left'
49
+ }[anchor.side],
50
+ align: anchor.align
51
+ } as ParsedAnchor;
52
+ }
53
+
54
+ export function flipAlign(anchor: ParsedAnchor) {
55
+ return {
56
+ side: anchor.side,
57
+ align: {
58
+ center: 'center',
59
+ top: 'bottom',
60
+ bottom: 'top',
61
+ left: 'right',
62
+ right: 'left'
63
+ }[anchor.align]
64
+ } as ParsedAnchor;
65
+ }
66
+
67
+ export function flipCorner(anchor: ParsedAnchor) {
68
+ return {
69
+ side: anchor.align,
70
+ align: anchor.side
71
+ } as ParsedAnchor;
72
+ }
73
+
74
+ export function getAxis(anchor: ParsedAnchor) {
75
+ return includes(block, anchor.side) ? 'y' : 'x';
76
+ }
@@ -0,0 +1,62 @@
1
+ import { Box } from './box';
2
+
3
+ /** @see https://stackoverflow.com/a/57876601/2074736 */
4
+ export function nullifyTransforms(el: HTMLElement): Box {
5
+ const rect = el.getBoundingClientRect();
6
+ const style = getComputedStyle(el);
7
+ const tx = style.transform;
8
+
9
+ if (tx) {
10
+ let ta, sx, sy, dx, dy;
11
+ if (tx.startsWith('matrix3d(')) {
12
+ ta = tx.slice(9, -1).split(/, /);
13
+ sx = +ta[0];
14
+ sy = +ta[5];
15
+ dx = +ta[12];
16
+ dy = +ta[13];
17
+ } else if (tx.startsWith('matrix(')) {
18
+ ta = tx.slice(7, -1).split(/, /);
19
+ sx = +ta[0];
20
+ sy = +ta[3];
21
+ dx = +ta[4];
22
+ dy = +ta[5];
23
+ } else {
24
+ return new Box(rect);
25
+ }
26
+
27
+ const to = style.transformOrigin;
28
+ const x = rect.x - dx - (1 - sx) * parseFloat(to);
29
+ const y = rect.y - dy - (1 - sy) * parseFloat(to.slice(to.indexOf(' ') + 1));
30
+ const w = sx ? rect.width / sx : el.offsetWidth + 1;
31
+ const h = sy ? rect.height / sy : el.offsetHeight + 1;
32
+
33
+ return new Box({ x, y, width: w, height: h });
34
+ } else {
35
+ return new Box(rect);
36
+ }
37
+ }
38
+
39
+ export function animate(
40
+ el: Element,
41
+ keyframes: Keyframe[] | PropertyIndexedKeyframes | null,
42
+ options?: number | KeyframeAnimationOptions
43
+ ) {
44
+ if (typeof el.animate === 'undefined') return { finished: Promise.resolve() };
45
+
46
+ let animation: Animation;
47
+ try {
48
+ animation = el.animate(keyframes, options);
49
+ } catch (err) {
50
+ return { finished: Promise.resolve() };
51
+ }
52
+
53
+ if (typeof animation.finished === 'undefined') {
54
+ (animation as any).finished = new Promise((resolve) => {
55
+ animation.onfinish = () => {
56
+ resolve(animation);
57
+ };
58
+ });
59
+ }
60
+
61
+ return animation;
62
+ }