@axinom/mosaic-ui 0.65.0-rc.1 → 0.65.0-rc.11

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 (36) hide show
  1. package/dist/components/Explorer/BulkEdit/useBulkEdit.d.ts +2 -1
  2. package/dist/components/Explorer/BulkEdit/useBulkEdit.d.ts.map +1 -1
  3. package/dist/components/Explorer/Explorer.d.ts.map +1 -1
  4. package/dist/components/Filters/Filter/Filter.d.ts +10 -0
  5. package/dist/components/Filters/Filter/Filter.d.ts.map +1 -1
  6. package/dist/components/Filters/Filters.model.d.ts +9 -1
  7. package/dist/components/Filters/Filters.model.d.ts.map +1 -1
  8. package/dist/components/Filters/SelectionTypes/SearcheableOptionsFilter/helpers.d.ts +4 -0
  9. package/dist/components/Filters/SelectionTypes/SearcheableOptionsFilter/helpers.d.ts.map +1 -0
  10. package/dist/components/List/ListRow/Renderers/TagsRenderer/TagsRenderer.d.ts +3 -0
  11. package/dist/components/List/ListRow/Renderers/TagsRenderer/TagsRenderer.d.ts.map +1 -0
  12. package/dist/components/List/ListRow/Renderers/index.d.ts +1 -0
  13. package/dist/components/List/ListRow/Renderers/index.d.ts.map +1 -1
  14. package/dist/components/Loaders/ImageLoader/ImageLoader.d.ts.map +1 -1
  15. package/dist/components/Utils/Postgraphile/CreateConnectionRenderer.d.ts +3 -2
  16. package/dist/components/Utils/Postgraphile/CreateConnectionRenderer.d.ts.map +1 -1
  17. package/dist/index.es.js +4 -4
  18. package/dist/index.es.js.map +1 -1
  19. package/dist/index.js +4 -4
  20. package/dist/index.js.map +1 -1
  21. package/package.json +2 -2
  22. package/src/components/Explorer/BulkEdit/useBulkEdit.tsx +9 -3
  23. package/src/components/Explorer/Explorer.tsx +1 -0
  24. package/src/components/Explorer/QuickEdit/useQuickEdit.tsx +1 -1
  25. package/src/components/Filters/Filter/Filter.tsx +17 -1
  26. package/src/components/Filters/Filters.model.ts +9 -1
  27. package/src/components/Filters/SelectionTypes/SearcheableOptionsFilter/helpers.ts +24 -0
  28. package/src/components/List/List.stories.tsx +19 -1
  29. package/src/components/List/ListRow/Renderers/TagsRenderer/TagsRenderer.scss +25 -0
  30. package/src/components/List/ListRow/Renderers/TagsRenderer/TagsRenderer.spec.tsx +153 -0
  31. package/src/components/List/ListRow/Renderers/TagsRenderer/TagsRenderer.tsx +133 -0
  32. package/src/components/List/ListRow/Renderers/index.ts +1 -0
  33. package/src/components/Loaders/ImageLoader/ImageLoader.tsx +4 -1
  34. package/src/components/Utils/Postgraphile/CreateConnectionRenderer.spec.ts +259 -0
  35. package/src/components/Utils/Postgraphile/{CreateConnectionRenderer.ts → CreateConnectionRenderer.tsx} +18 -3
  36. package/src/styles/variables.scss +2 -0
@@ -0,0 +1,259 @@
1
+ import { TagsRenderer } from '../../List';
2
+ import { createConnectionRenderer } from './CreateConnectionRenderer';
3
+
4
+ jest.mock('../../List', () => ({
5
+ TagsRenderer: jest.fn(),
6
+ }));
7
+
8
+ const mockTagsRenderer = TagsRenderer as jest.MockedFunction<
9
+ typeof TagsRenderer
10
+ >;
11
+
12
+ interface TestConnection {
13
+ nodes: { id: string; name: string }[];
14
+ }
15
+
16
+ interface StringConnection {
17
+ nodes: string[];
18
+ }
19
+
20
+ describe('createConnectionRenderer', () => {
21
+ beforeEach(() => {
22
+ jest.clearAllMocks();
23
+ });
24
+
25
+ describe('with renderAsTags = true (default)', () => {
26
+ it('should call TagsRenderer with mapped values when renderAsTags is true', () => {
27
+ const mockReturnValue = 'Mocked Tags JSX Element';
28
+ mockTagsRenderer.mockReturnValue(mockReturnValue as any);
29
+
30
+ const connection: TestConnection = {
31
+ nodes: [
32
+ { id: '1', name: 'Item 1' },
33
+ { id: '2', name: 'Item 2' },
34
+ ],
35
+ };
36
+
37
+ const selector = (item: { id: string; name: string }) => item.name;
38
+ const renderer = createConnectionRenderer<TestConnection>(selector);
39
+ const result = renderer(connection);
40
+
41
+ expect(mockTagsRenderer).toHaveBeenCalledWith(['Item 1', 'Item 2']);
42
+ expect(result).toBe(mockReturnValue);
43
+ });
44
+
45
+ it('should throw error when nodes is undefined', () => {
46
+ const connection = { nodes: undefined } as unknown as TestConnection;
47
+ const selector = (item: { id: string; name: string }) => item.name;
48
+ const renderer = createConnectionRenderer<TestConnection>(selector);
49
+
50
+ expect(() => renderer(connection)).toThrow();
51
+ expect(mockTagsRenderer).not.toHaveBeenCalled();
52
+ });
53
+
54
+ it('should throw error when value is null', () => {
55
+ const selector = (item: { id: string; name: string }) => item.name;
56
+ const renderer = createConnectionRenderer<TestConnection>(selector);
57
+
58
+ expect(() => renderer(null)).toThrow();
59
+ expect(mockTagsRenderer).not.toHaveBeenCalled();
60
+ });
61
+
62
+ it('should throw error when value is undefined', () => {
63
+ const selector = (item: { id: string; name: string }) => item.name;
64
+ const renderer = createConnectionRenderer<TestConnection>(selector);
65
+
66
+ expect(() => renderer(undefined)).toThrow();
67
+ expect(mockTagsRenderer).not.toHaveBeenCalled();
68
+ });
69
+
70
+ it('should call TagsRenderer with empty array when nodes is empty', () => {
71
+ const mockReturnValue = 'Empty Tags JSX Element';
72
+ mockTagsRenderer.mockReturnValue(mockReturnValue as any);
73
+
74
+ const connection: TestConnection = { nodes: [] };
75
+ const selector = (item: { id: string; name: string }) => item.name;
76
+ const renderer = createConnectionRenderer<TestConnection>(selector);
77
+ const result = renderer(connection);
78
+
79
+ expect(mockTagsRenderer).toHaveBeenCalledWith([]);
80
+ expect(result).toBe(mockReturnValue);
81
+ });
82
+ });
83
+
84
+ describe('with renderAsTags = false', () => {
85
+ it('should return comma-separated string using selector', () => {
86
+ const connection: TestConnection = {
87
+ nodes: [
88
+ { id: '1', name: 'Item 1' },
89
+ { id: '2', name: 'Item 2' },
90
+ { id: '3', name: 'Item 3' },
91
+ ],
92
+ };
93
+
94
+ const selector = (item: { id: string; name: string }) => item.name;
95
+ const renderer = createConnectionRenderer<TestConnection>(
96
+ selector,
97
+ false,
98
+ );
99
+ const result = renderer(connection);
100
+
101
+ expect(mockTagsRenderer).not.toHaveBeenCalled();
102
+ expect(result).toBe('Item 1, Item 2, Item 3');
103
+ });
104
+
105
+ it('should work with simple string arrays', () => {
106
+ const connection: StringConnection = {
107
+ nodes: ['apple', 'banana', 'cherry'],
108
+ };
109
+
110
+ const selector = (item: string) => item;
111
+ const renderer = createConnectionRenderer<StringConnection>(
112
+ selector,
113
+ false,
114
+ );
115
+ const result = renderer(connection);
116
+
117
+ expect(result).toBe('apple, banana, cherry');
118
+ });
119
+
120
+ it('should work with complex selector functions', () => {
121
+ const connection: TestConnection = {
122
+ nodes: [
123
+ { id: '1', name: 'Item 1' },
124
+ { id: '2', name: 'Item 2' },
125
+ ],
126
+ };
127
+
128
+ const selector = (item: { id: string; name: string }, index: number) =>
129
+ `${index + 1}. ${item.name} (${item.id})`;
130
+ const renderer = createConnectionRenderer<TestConnection>(
131
+ selector,
132
+ false,
133
+ );
134
+ const result = renderer(connection);
135
+
136
+ expect(result).toBe('1. Item 1 (1), 2. Item 2 (2)');
137
+ });
138
+
139
+ it('should return empty string when nodes array is empty', () => {
140
+ const connection: TestConnection = { nodes: [] };
141
+ const selector = (item: { id: string; name: string }) => item.name;
142
+ const renderer = createConnectionRenderer<TestConnection>(
143
+ selector,
144
+ false,
145
+ );
146
+ const result = renderer(connection);
147
+
148
+ expect(result).toBe('');
149
+ });
150
+
151
+ it('should handle selector returning different types', () => {
152
+ interface NumberConnection {
153
+ nodes: { id: number; value: number }[];
154
+ }
155
+ const connection: NumberConnection = {
156
+ nodes: [
157
+ { id: 1, value: 100 },
158
+ { id: 2, value: 200 },
159
+ ],
160
+ };
161
+
162
+ const selector = (item: { id: number; value: number }) => item.value;
163
+ const renderer = createConnectionRenderer<NumberConnection>(
164
+ selector,
165
+ false,
166
+ );
167
+ const result = renderer(connection);
168
+
169
+ expect(result).toBe('100, 200');
170
+ });
171
+
172
+ it('should throw error when connection.nodes is undefined and renderAsTags is false', () => {
173
+ const connection = { nodes: undefined } as unknown as TestConnection;
174
+ const selector = (item: { id: string; name: string }) => item.name;
175
+ const renderer = createConnectionRenderer<TestConnection>(
176
+ selector,
177
+ false,
178
+ );
179
+
180
+ expect(() => renderer(connection)).toThrow();
181
+ });
182
+ });
183
+
184
+ describe('edge cases', () => {
185
+ it('should handle nodes with special characters in comma-separated output', () => {
186
+ const connection: StringConnection = {
187
+ nodes: ['item, with comma', 'item with "quotes"', 'normal item'],
188
+ };
189
+
190
+ const selector = (item: string) => item;
191
+ const renderer = createConnectionRenderer<StringConnection>(
192
+ selector,
193
+ false,
194
+ );
195
+ const result = renderer(connection);
196
+
197
+ expect(result).toBe('item, with comma, item with "quotes", normal item');
198
+ });
199
+
200
+ it('should handle selector returning empty strings', () => {
201
+ const connection: TestConnection = {
202
+ nodes: [
203
+ { id: '1', name: '' },
204
+ { id: '2', name: 'Item 2' },
205
+ { id: '3', name: '' },
206
+ ],
207
+ };
208
+
209
+ const selector = (item: { id: string; name: string }) => item.name;
210
+ const renderer = createConnectionRenderer<TestConnection>(
211
+ selector,
212
+ false,
213
+ );
214
+ const result = renderer(connection);
215
+
216
+ expect(result).toBe(', Item 2, ');
217
+ });
218
+
219
+ it('should handle single node connection', () => {
220
+ const connection: TestConnection = {
221
+ nodes: [{ id: '1', name: 'Single Item' }],
222
+ };
223
+
224
+ const selector = (item: { id: string; name: string }) => item.name;
225
+ const renderer = createConnectionRenderer<TestConnection>(
226
+ selector,
227
+ false,
228
+ );
229
+ const result = renderer(connection);
230
+
231
+ expect(result).toBe('Single Item');
232
+ });
233
+ });
234
+
235
+ describe('type safety', () => {
236
+ it('should work with different connection node types', () => {
237
+ interface CustomConnection {
238
+ nodes: { customField: number; label: string }[];
239
+ }
240
+
241
+ const connection: CustomConnection = {
242
+ nodes: [
243
+ { customField: 42, label: 'Custom 1' },
244
+ { customField: 84, label: 'Custom 2' },
245
+ ],
246
+ };
247
+
248
+ const selector = (item: { customField: number; label: string }) =>
249
+ `${item.label}: ${item.customField}`;
250
+ const renderer = createConnectionRenderer<CustomConnection>(
251
+ selector,
252
+ false,
253
+ );
254
+ const result = renderer(connection);
255
+
256
+ expect(result).toBe('Custom 1: 42, Custom 2: 84');
257
+ });
258
+ });
259
+ });
@@ -1,8 +1,15 @@
1
+ import { ReactNode } from 'react';
2
+ import { TagsRenderer } from '../../List';
3
+
1
4
  interface Connection {
2
5
  nodes: unknown[];
3
6
  }
4
7
 
5
- type SelectorFunction<T> = (value: T, index: number, array: T[]) => unknown;
8
+ export type SelectorFunction<T> = (
9
+ value: T,
10
+ index: number,
11
+ array: T[],
12
+ ) => unknown;
6
13
 
7
14
  /**
8
15
  * Creates a renderer that will loop through each `node` on the value,
@@ -12,10 +19,18 @@ type SelectorFunction<T> = (value: T, index: number, array: T[]) => unknown;
12
19
  */
13
20
  export function createConnectionRenderer<T extends Connection>(
14
21
  selector: SelectorFunction<T['nodes'][number]>,
15
- ): (val: unknown) => string {
16
- return (val: unknown): string => {
22
+ renderAsTags = true,
23
+ ): (val: unknown) => string | ReactNode {
24
+ const ConnectionRenderer = (val: unknown): string | ReactNode => {
17
25
  const value = val as T;
18
26
 
27
+ if (renderAsTags) {
28
+ return TagsRenderer(value.nodes.map(selector));
29
+ }
30
+
19
31
  return value.nodes.map(selector).join(', ');
20
32
  };
33
+
34
+ ConnectionRenderer.displayName = 'ConnectionRenderer';
35
+ return ConnectionRenderer;
21
36
  }
@@ -61,6 +61,8 @@ $explorer-list-row-border: 1px solid $light-gray;
61
61
  /* List vars */
62
62
 
63
63
  $list-paddings: 0px 5px 0px 5px;
64
+ $list-tag-background-color: $light-gray-2;
65
+ $list-tag-overflow-background-color: $dark-gray;
64
66
 
65
67
  /* Filter vars */
66
68
  $filter-background-color: white;