@janrankenhohn/react-thumbnail-list 0.8.0 → 1.0.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.
- package/dist/index.esm.js +1372 -449
- package/dist/index.js +1365 -442
- package/dist/types/src/components/DropdownInput.d.ts +26 -0
- package/dist/types/src/components/EllipsisContainer.d.ts +15 -0
- package/dist/types/src/components/ThumbnailList.d.ts +46 -0
- package/dist/types/src/components/ThumbnailListFilterTag.d.ts +25 -0
- package/dist/types/src/components/ThumbnailListFilterTags.d.ts +44 -0
- package/dist/types/src/components/ThumbnailListHeader.d.ts +33 -0
- package/dist/types/src/components/ThumbnailListHeaderSort.d.ts +30 -0
- package/dist/types/src/components/ThumbnailListItem.d.ts +11 -0
- package/dist/types/src/components/ThumbnailListItemContext.d.ts +61 -0
- package/dist/types/src/components/ThumbnailListItemInfoLabel.d.ts +14 -0
- package/dist/types/src/components/ThumbnailListItemTitle.d.ts +15 -0
- package/dist/types/src/components/ThumbnailListItemType.d.ts +20 -0
- package/dist/types/src/components/ThumbnailListMainContent.d.ts +24 -0
- package/dist/types/src/components/ThumbnailListSearchField.d.ts +3 -0
- package/dist/types/src/config/ThumbnailListConfiguration.d.ts +23 -0
- package/dist/types/src/hooks/useFilteredThumbnailListItems.d.ts +23 -0
- package/dist/types/src/hooks/usePagedThumbnailListItems.d.ts +29 -0
- package/dist/types/src/hooks/useSortedThumbnailListItems.d.ts +29 -0
- package/dist/types/src/hooks/useTagFilteredThumbnailListItems.d.ts +51 -0
- package/dist/types/src/hooks/useWithLoading.d.ts +22 -0
- package/dist/types/src/index.d.ts +5 -0
- package/dist/types/src/interfaces/ThumbnailListItemInterface.d.ts +21 -0
- package/dist/types/src/stories/Button.d.ts +15 -0
- package/dist/types/src/stories/Header.d.ts +12 -0
- package/dist/types/src/stories/Page.d.ts +3 -0
- package/dist/types/src/tests/mocks/MockListItems.d.ts +41 -0
- package/dist/types/src/types/AlignType.d.ts +7 -0
- package/dist/types/src/types/BreakpointType.d.ts +25 -0
- package/dist/types/src/utils/arrayHelper.d.ts +26 -0
- package/dist/types/src/utils/logHelper.d.ts +24 -0
- package/dist/types/vitest.setup.d.ts +1 -0
- package/package.json +103 -86
package/dist/index.esm.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { jsx,
|
|
1
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
2
|
import { styled as styled$2, Box, Typography, Card, CardActionArea, Stack as Stack$1, Grid, LinearProgress, FormControl, TextField, InputAdornment, IconButton, useTheme as useTheme$2, useMediaQuery, Chip, Tooltip, InputLabel, Select, MenuItem, Menu } from '@mui/material';
|
|
3
3
|
import * as React from 'react';
|
|
4
|
-
import React__default, { createContext, useContext, useMemo, useState,
|
|
4
|
+
import React__default, { createContext, useContext, useMemo, useState, useEffect, Children } from 'react';
|
|
5
5
|
import emStyled from '@emotion/styled';
|
|
6
6
|
import { ThemeContext } from '@emotion/react';
|
|
7
7
|
import SearchIcon from '@mui/icons-material/Search';
|
|
@@ -9,7 +9,24 @@ import ClearIcon from '@mui/icons-material/Clear';
|
|
|
9
9
|
import SwapVertIcon from '@mui/icons-material/SwapVert';
|
|
10
10
|
import SortIcon from '@mui/icons-material/Sort';
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* React context for sharing thumbnail list state across components.
|
|
14
|
+
* Provides access to items, sorting, filtering, and search functionality.
|
|
15
|
+
*/
|
|
12
16
|
const ThumbnailListItemContext = createContext(undefined);
|
|
17
|
+
/**
|
|
18
|
+
* React hook to access the ThumbnailList context.
|
|
19
|
+
* Must be used within a ThumbnailList component tree.
|
|
20
|
+
*
|
|
21
|
+
* @template T - The type of items in the list
|
|
22
|
+
* @returns {ThumbnailListItemContextType<T>} The context values
|
|
23
|
+
* @throws {Error} Throws error if used outside of ThumbnailList provider
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```tsx
|
|
27
|
+
* const { items, setSearchTerm, sortAscending } = useThumbnailListItemContext();
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
13
30
|
const useThumbnailListItemContext = () => {
|
|
14
31
|
const context = useContext(ThumbnailListItemContext);
|
|
15
32
|
if (!context) {
|
|
@@ -18,100 +35,543 @@ const useThumbnailListItemContext = () => {
|
|
|
18
35
|
return context;
|
|
19
36
|
};
|
|
20
37
|
|
|
38
|
+
const StyledEllipsisContainer = styled$2('div')(({ theme, lineClamp }) => ({
|
|
39
|
+
[theme.breakpoints.up('xs')]: {
|
|
40
|
+
overflow: 'hidden',
|
|
41
|
+
display: '-webkit-box',
|
|
42
|
+
WebkitLineClamp: lineClamp.xs.toString(),
|
|
43
|
+
WebkitBoxOrient: 'vertical',
|
|
44
|
+
},
|
|
45
|
+
[theme.breakpoints.up('sm')]: {
|
|
46
|
+
overflow: 'hidden',
|
|
47
|
+
display: '-webkit-box',
|
|
48
|
+
WebkitLineClamp: lineClamp.sm.toString(),
|
|
49
|
+
WebkitBoxOrient: 'vertical',
|
|
50
|
+
},
|
|
51
|
+
}));
|
|
21
52
|
/**
|
|
22
|
-
* Creates
|
|
53
|
+
* Creates ellipsis text with webkit css styles
|
|
23
54
|
* @param props lineClamp: lines till ellipses
|
|
24
55
|
* @returns component
|
|
25
56
|
*/
|
|
26
57
|
function EllipsisContainer(props) {
|
|
27
|
-
|
|
28
|
-
[p.theme.breakpoints.up('xs')]: {
|
|
29
|
-
overflow: 'hidden',
|
|
30
|
-
display: '-webkit-box',
|
|
31
|
-
WebkitLineClamp: props.lineClamp.xs.toString() /* number of lines to show */,
|
|
32
|
-
WebkitBoxOrient: 'vertical',
|
|
33
|
-
},
|
|
34
|
-
[p.theme.breakpoints.up('sm')]: {
|
|
35
|
-
overflow: 'hidden',
|
|
36
|
-
display: '-webkit-box',
|
|
37
|
-
WebkitLineClamp: props.lineClamp.sm.toString() /* number of lines to show */,
|
|
38
|
-
WebkitBoxOrient: 'vertical' /* number of lines to show */,
|
|
39
|
-
},
|
|
40
|
-
}));
|
|
41
|
-
return jsx(EllipsisContainer, { children: props.children });
|
|
58
|
+
return jsx(StyledEllipsisContainer, { lineClamp: props.lineClamp, children: props.children });
|
|
42
59
|
}
|
|
43
60
|
|
|
44
61
|
/**
|
|
45
|
-
* WARNING: Don't import this directly.
|
|
46
|
-
*
|
|
62
|
+
* WARNING: Don't import this directly. It's imported by the code generated by
|
|
63
|
+
* `@mui/interal-babel-plugin-minify-errors`. Make sure to always use string literals in `Error`
|
|
64
|
+
* constructors to ensure the plugin works as expected. Supported patterns include:
|
|
65
|
+
* throw new Error('My message');
|
|
66
|
+
* throw new Error(`My message: ${foo}`);
|
|
67
|
+
* throw new Error(`My message: ${foo}` + 'another string');
|
|
68
|
+
* ...
|
|
47
69
|
* @param {number} code
|
|
48
70
|
*/
|
|
49
|
-
function formatMuiErrorMessage(code) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
71
|
+
function formatMuiErrorMessage(code, ...args) {
|
|
72
|
+
const url = new URL(`https://mui.com/production-error/?code=${code}`);
|
|
73
|
+
args.forEach(arg => url.searchParams.append('args[]', arg));
|
|
74
|
+
return `Minified MUI error #${code}; visit ${url} for the full message.`;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/* eslint-disable */
|
|
78
|
+
// Inspired by https://github.com/garycourt/murmurhash-js
|
|
79
|
+
// Ported from https://github.com/aappleby/smhasher/blob/61a0530f28277f2e850bfc39600ce61d02b518de/src/MurmurHash2.cpp#L37-L86
|
|
80
|
+
function murmur2(str) {
|
|
81
|
+
// 'm' and 'r' are mixing constants generated offline.
|
|
82
|
+
// They're not really 'magic', they just happen to work well.
|
|
83
|
+
// const m = 0x5bd1e995;
|
|
84
|
+
// const r = 24;
|
|
85
|
+
// Initialize the hash
|
|
86
|
+
var h = 0; // Mix 4 bytes at a time into the hash
|
|
87
|
+
|
|
88
|
+
var k,
|
|
89
|
+
i = 0,
|
|
90
|
+
len = str.length;
|
|
91
|
+
|
|
92
|
+
for (; len >= 4; ++i, len -= 4) {
|
|
93
|
+
k = str.charCodeAt(i) & 0xff | (str.charCodeAt(++i) & 0xff) << 8 | (str.charCodeAt(++i) & 0xff) << 16 | (str.charCodeAt(++i) & 0xff) << 24;
|
|
94
|
+
k =
|
|
95
|
+
/* Math.imul(k, m): */
|
|
96
|
+
(k & 0xffff) * 0x5bd1e995 + ((k >>> 16) * 0xe995 << 16);
|
|
97
|
+
k ^=
|
|
98
|
+
/* k >>> r: */
|
|
99
|
+
k >>> 24;
|
|
100
|
+
h =
|
|
101
|
+
/* Math.imul(k, m): */
|
|
102
|
+
(k & 0xffff) * 0x5bd1e995 + ((k >>> 16) * 0xe995 << 16) ^
|
|
103
|
+
/* Math.imul(h, m): */
|
|
104
|
+
(h & 0xffff) * 0x5bd1e995 + ((h >>> 16) * 0xe995 << 16);
|
|
105
|
+
} // Handle the last few bytes of the input array
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
switch (len) {
|
|
109
|
+
case 3:
|
|
110
|
+
h ^= (str.charCodeAt(i + 2) & 0xff) << 16;
|
|
111
|
+
|
|
112
|
+
case 2:
|
|
113
|
+
h ^= (str.charCodeAt(i + 1) & 0xff) << 8;
|
|
114
|
+
|
|
115
|
+
case 1:
|
|
116
|
+
h ^= str.charCodeAt(i) & 0xff;
|
|
117
|
+
h =
|
|
118
|
+
/* Math.imul(h, m): */
|
|
119
|
+
(h & 0xffff) * 0x5bd1e995 + ((h >>> 16) * 0xe995 << 16);
|
|
120
|
+
} // Do a few final mixes of the hash to ensure the last few
|
|
121
|
+
// bytes are well-incorporated.
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
h ^= h >>> 13;
|
|
125
|
+
h =
|
|
126
|
+
/* Math.imul(h, m): */
|
|
127
|
+
(h & 0xffff) * 0x5bd1e995 + ((h >>> 16) * 0xe995 << 16);
|
|
128
|
+
return ((h ^ h >>> 15) >>> 0).toString(36);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
var unitlessKeys = {
|
|
132
|
+
animationIterationCount: 1,
|
|
133
|
+
aspectRatio: 1,
|
|
134
|
+
borderImageOutset: 1,
|
|
135
|
+
borderImageSlice: 1,
|
|
136
|
+
borderImageWidth: 1,
|
|
137
|
+
boxFlex: 1,
|
|
138
|
+
boxFlexGroup: 1,
|
|
139
|
+
boxOrdinalGroup: 1,
|
|
140
|
+
columnCount: 1,
|
|
141
|
+
columns: 1,
|
|
142
|
+
flex: 1,
|
|
143
|
+
flexGrow: 1,
|
|
144
|
+
flexPositive: 1,
|
|
145
|
+
flexShrink: 1,
|
|
146
|
+
flexNegative: 1,
|
|
147
|
+
flexOrder: 1,
|
|
148
|
+
gridRow: 1,
|
|
149
|
+
gridRowEnd: 1,
|
|
150
|
+
gridRowSpan: 1,
|
|
151
|
+
gridRowStart: 1,
|
|
152
|
+
gridColumn: 1,
|
|
153
|
+
gridColumnEnd: 1,
|
|
154
|
+
gridColumnSpan: 1,
|
|
155
|
+
gridColumnStart: 1,
|
|
156
|
+
msGridRow: 1,
|
|
157
|
+
msGridRowSpan: 1,
|
|
158
|
+
msGridColumn: 1,
|
|
159
|
+
msGridColumnSpan: 1,
|
|
160
|
+
fontWeight: 1,
|
|
161
|
+
lineHeight: 1,
|
|
162
|
+
opacity: 1,
|
|
163
|
+
order: 1,
|
|
164
|
+
orphans: 1,
|
|
165
|
+
scale: 1,
|
|
166
|
+
tabSize: 1,
|
|
167
|
+
widows: 1,
|
|
168
|
+
zIndex: 1,
|
|
169
|
+
zoom: 1,
|
|
170
|
+
WebkitLineClamp: 1,
|
|
171
|
+
// SVG-related properties
|
|
172
|
+
fillOpacity: 1,
|
|
173
|
+
floodOpacity: 1,
|
|
174
|
+
stopOpacity: 1,
|
|
175
|
+
strokeDasharray: 1,
|
|
176
|
+
strokeDashoffset: 1,
|
|
177
|
+
strokeMiterlimit: 1,
|
|
178
|
+
strokeOpacity: 1,
|
|
179
|
+
strokeWidth: 1
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
function memoize$1(fn) {
|
|
183
|
+
var cache = Object.create(null);
|
|
184
|
+
return function (arg) {
|
|
185
|
+
if (cache[arg] === undefined) cache[arg] = fn(arg);
|
|
186
|
+
return cache[arg];
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
var hyphenateRegex = /[A-Z]|^ms/g;
|
|
191
|
+
var animationRegex = /_EMO_([^_]+?)_([^]*?)_EMO_/g;
|
|
192
|
+
|
|
193
|
+
var isCustomProperty = function isCustomProperty(property) {
|
|
194
|
+
return property.charCodeAt(1) === 45;
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
var isProcessableValue = function isProcessableValue(value) {
|
|
198
|
+
return value != null && typeof value !== 'boolean';
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
var processStyleName = /* #__PURE__ */memoize$1(function (styleName) {
|
|
202
|
+
return isCustomProperty(styleName) ? styleName : styleName.replace(hyphenateRegex, '-$&').toLowerCase();
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
var processStyleValue = function processStyleValue(key, value) {
|
|
206
|
+
switch (key) {
|
|
207
|
+
case 'animation':
|
|
208
|
+
case 'animationName':
|
|
209
|
+
{
|
|
210
|
+
if (typeof value === 'string') {
|
|
211
|
+
return value.replace(animationRegex, function (match, p1, p2) {
|
|
212
|
+
cursor = {
|
|
213
|
+
name: p1,
|
|
214
|
+
styles: p2,
|
|
215
|
+
next: cursor
|
|
216
|
+
};
|
|
217
|
+
return p1;
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (unitlessKeys[key] !== 1 && !isCustomProperty(key) && typeof value === 'number' && value !== 0) {
|
|
224
|
+
return value + 'px';
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return value;
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
function handleInterpolation(mergedProps, registered, interpolation) {
|
|
231
|
+
if (interpolation == null) {
|
|
232
|
+
return '';
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
var componentSelector = interpolation;
|
|
236
|
+
|
|
237
|
+
if (componentSelector.__emotion_styles !== undefined) {
|
|
238
|
+
|
|
239
|
+
return componentSelector;
|
|
59
240
|
}
|
|
60
|
-
|
|
61
|
-
|
|
241
|
+
|
|
242
|
+
switch (typeof interpolation) {
|
|
243
|
+
case 'boolean':
|
|
244
|
+
{
|
|
245
|
+
return '';
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
case 'object':
|
|
249
|
+
{
|
|
250
|
+
var keyframes = interpolation;
|
|
251
|
+
|
|
252
|
+
if (keyframes.anim === 1) {
|
|
253
|
+
cursor = {
|
|
254
|
+
name: keyframes.name,
|
|
255
|
+
styles: keyframes.styles,
|
|
256
|
+
next: cursor
|
|
257
|
+
};
|
|
258
|
+
return keyframes.name;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
var serializedStyles = interpolation;
|
|
262
|
+
|
|
263
|
+
if (serializedStyles.styles !== undefined) {
|
|
264
|
+
var next = serializedStyles.next;
|
|
265
|
+
|
|
266
|
+
if (next !== undefined) {
|
|
267
|
+
// not the most efficient thing ever but this is a pretty rare case
|
|
268
|
+
// and there will be very few iterations of this generally
|
|
269
|
+
while (next !== undefined) {
|
|
270
|
+
cursor = {
|
|
271
|
+
name: next.name,
|
|
272
|
+
styles: next.styles,
|
|
273
|
+
next: cursor
|
|
274
|
+
};
|
|
275
|
+
next = next.next;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
var styles = serializedStyles.styles + ";";
|
|
280
|
+
return styles;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return createStringFromObject(mergedProps, registered, interpolation);
|
|
284
|
+
}
|
|
285
|
+
} // finalize string values (regular strings and functions interpolated into css calls)
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
var asString = interpolation;
|
|
289
|
+
|
|
290
|
+
{
|
|
291
|
+
return asString;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function createStringFromObject(mergedProps, registered, obj) {
|
|
296
|
+
var string = '';
|
|
297
|
+
|
|
298
|
+
if (Array.isArray(obj)) {
|
|
299
|
+
for (var i = 0; i < obj.length; i++) {
|
|
300
|
+
string += handleInterpolation(mergedProps, registered, obj[i]) + ";";
|
|
301
|
+
}
|
|
302
|
+
} else {
|
|
303
|
+
for (var key in obj) {
|
|
304
|
+
var value = obj[key];
|
|
305
|
+
|
|
306
|
+
if (typeof value !== 'object') {
|
|
307
|
+
var asString = value;
|
|
308
|
+
|
|
309
|
+
if (isProcessableValue(asString)) {
|
|
310
|
+
string += processStyleName(key) + ":" + processStyleValue(key, asString) + ";";
|
|
311
|
+
}
|
|
312
|
+
} else {
|
|
313
|
+
|
|
314
|
+
if (Array.isArray(value) && typeof value[0] === 'string' && (registered == null)) {
|
|
315
|
+
for (var _i = 0; _i < value.length; _i++) {
|
|
316
|
+
if (isProcessableValue(value[_i])) {
|
|
317
|
+
string += processStyleName(key) + ":" + processStyleValue(key, value[_i]) + ";";
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
} else {
|
|
321
|
+
var interpolated = handleInterpolation(mergedProps, registered, value);
|
|
322
|
+
|
|
323
|
+
switch (key) {
|
|
324
|
+
case 'animation':
|
|
325
|
+
case 'animationName':
|
|
326
|
+
{
|
|
327
|
+
string += processStyleName(key) + ":" + interpolated + ";";
|
|
328
|
+
break;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
default:
|
|
332
|
+
{
|
|
333
|
+
|
|
334
|
+
string += key + "{" + interpolated + "}";
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
return string;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
var labelPattern = /label:\s*([^\s;{]+)\s*(;|$)/g; // this is the cursor for keyframes
|
|
346
|
+
// keyframes are stored on the SerializedStyles object as a linked list
|
|
347
|
+
|
|
348
|
+
var cursor;
|
|
349
|
+
function serializeStyles(args, registered, mergedProps) {
|
|
350
|
+
if (args.length === 1 && typeof args[0] === 'object' && args[0] !== null && args[0].styles !== undefined) {
|
|
351
|
+
return args[0];
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
var stringMode = true;
|
|
355
|
+
var styles = '';
|
|
356
|
+
cursor = undefined;
|
|
357
|
+
var strings = args[0];
|
|
358
|
+
|
|
359
|
+
if (strings == null || strings.raw === undefined) {
|
|
360
|
+
stringMode = false;
|
|
361
|
+
styles += handleInterpolation(mergedProps, registered, strings);
|
|
362
|
+
} else {
|
|
363
|
+
var asTemplateStringsArr = strings;
|
|
364
|
+
|
|
365
|
+
styles += asTemplateStringsArr[0];
|
|
366
|
+
} // we start at 1 since we've already handled the first arg
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
for (var i = 1; i < args.length; i++) {
|
|
370
|
+
styles += handleInterpolation(mergedProps, registered, args[i]);
|
|
371
|
+
|
|
372
|
+
if (stringMode) {
|
|
373
|
+
var templateStringsArr = strings;
|
|
374
|
+
|
|
375
|
+
styles += templateStringsArr[i];
|
|
376
|
+
}
|
|
377
|
+
} // using a global regex with .exec is stateful so lastIndex has to be reset each time
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
labelPattern.lastIndex = 0;
|
|
381
|
+
var identifierName = '';
|
|
382
|
+
var match; // https://esbench.com/bench/5b809c2cf2949800a0f61fb5
|
|
383
|
+
|
|
384
|
+
while ((match = labelPattern.exec(styles)) !== null) {
|
|
385
|
+
identifierName += '-' + match[1];
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
var name = murmur2(styles) + identifierName;
|
|
389
|
+
|
|
390
|
+
return {
|
|
391
|
+
name: name,
|
|
392
|
+
styles: styles,
|
|
393
|
+
next: cursor
|
|
394
|
+
};
|
|
62
395
|
}
|
|
63
396
|
|
|
64
397
|
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
|
|
65
398
|
|
|
66
399
|
/**
|
|
67
|
-
* @mui/styled-engine
|
|
400
|
+
* @mui/styled-engine v6.5.0
|
|
68
401
|
*
|
|
69
402
|
* @license MIT
|
|
70
403
|
* This source code is licensed under the MIT license found in the
|
|
71
404
|
* LICENSE file in the root directory of this source tree.
|
|
72
405
|
*/
|
|
406
|
+
/* eslint-disable no-underscore-dangle */
|
|
73
407
|
function styled$1(tag, options) {
|
|
74
408
|
const stylesFactory = emStyled(tag, options);
|
|
75
409
|
return stylesFactory;
|
|
76
410
|
}
|
|
77
411
|
|
|
78
412
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
79
|
-
|
|
413
|
+
function internal_mutateStyles(tag, processor) {
|
|
80
414
|
// Emotion attaches all the styles as `__emotion_styles`.
|
|
81
415
|
// Ref: https://github.com/emotion-js/emotion/blob/16d971d0da229596d6bcc39d282ba9753c9ee7cf/packages/styled/src/base.js#L186
|
|
82
416
|
if (Array.isArray(tag.__emotion_styles)) {
|
|
83
417
|
tag.__emotion_styles = processor(tag.__emotion_styles);
|
|
84
418
|
}
|
|
85
|
-
}
|
|
419
|
+
}
|
|
86
420
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
target[key] = source[key];
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
return target;
|
|
98
|
-
};
|
|
99
|
-
return _extends.apply(this, arguments);
|
|
421
|
+
// Emotion only accepts an array, but we want to avoid allocations
|
|
422
|
+
const wrapper = [];
|
|
423
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
424
|
+
function internal_serializeStyles(styles) {
|
|
425
|
+
wrapper[0] = styles;
|
|
426
|
+
return serializeStyles(wrapper);
|
|
100
427
|
}
|
|
101
428
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
429
|
+
var reactIs = {exports: {}};
|
|
430
|
+
|
|
431
|
+
var reactIs_production = {};
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* @license React
|
|
435
|
+
* react-is.production.js
|
|
436
|
+
*
|
|
437
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
438
|
+
*
|
|
439
|
+
* This source code is licensed under the MIT license found in the
|
|
440
|
+
* LICENSE file in the root directory of this source tree.
|
|
441
|
+
*/
|
|
442
|
+
|
|
443
|
+
var hasRequiredReactIs_production;
|
|
444
|
+
|
|
445
|
+
function requireReactIs_production () {
|
|
446
|
+
if (hasRequiredReactIs_production) return reactIs_production;
|
|
447
|
+
hasRequiredReactIs_production = 1;
|
|
448
|
+
var REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element"),
|
|
449
|
+
REACT_PORTAL_TYPE = Symbol.for("react.portal"),
|
|
450
|
+
REACT_FRAGMENT_TYPE = Symbol.for("react.fragment"),
|
|
451
|
+
REACT_STRICT_MODE_TYPE = Symbol.for("react.strict_mode"),
|
|
452
|
+
REACT_PROFILER_TYPE = Symbol.for("react.profiler"),
|
|
453
|
+
REACT_CONSUMER_TYPE = Symbol.for("react.consumer"),
|
|
454
|
+
REACT_CONTEXT_TYPE = Symbol.for("react.context"),
|
|
455
|
+
REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"),
|
|
456
|
+
REACT_SUSPENSE_TYPE = Symbol.for("react.suspense"),
|
|
457
|
+
REACT_SUSPENSE_LIST_TYPE = Symbol.for("react.suspense_list"),
|
|
458
|
+
REACT_MEMO_TYPE = Symbol.for("react.memo"),
|
|
459
|
+
REACT_LAZY_TYPE = Symbol.for("react.lazy"),
|
|
460
|
+
REACT_VIEW_TRANSITION_TYPE = Symbol.for("react.view_transition"),
|
|
461
|
+
REACT_CLIENT_REFERENCE = Symbol.for("react.client.reference");
|
|
462
|
+
function typeOf(object) {
|
|
463
|
+
if ("object" === typeof object && null !== object) {
|
|
464
|
+
var $$typeof = object.$$typeof;
|
|
465
|
+
switch ($$typeof) {
|
|
466
|
+
case REACT_ELEMENT_TYPE:
|
|
467
|
+
switch (((object = object.type), object)) {
|
|
468
|
+
case REACT_FRAGMENT_TYPE:
|
|
469
|
+
case REACT_PROFILER_TYPE:
|
|
470
|
+
case REACT_STRICT_MODE_TYPE:
|
|
471
|
+
case REACT_SUSPENSE_TYPE:
|
|
472
|
+
case REACT_SUSPENSE_LIST_TYPE:
|
|
473
|
+
case REACT_VIEW_TRANSITION_TYPE:
|
|
474
|
+
return object;
|
|
475
|
+
default:
|
|
476
|
+
switch (((object = object && object.$$typeof), object)) {
|
|
477
|
+
case REACT_CONTEXT_TYPE:
|
|
478
|
+
case REACT_FORWARD_REF_TYPE:
|
|
479
|
+
case REACT_LAZY_TYPE:
|
|
480
|
+
case REACT_MEMO_TYPE:
|
|
481
|
+
return object;
|
|
482
|
+
case REACT_CONSUMER_TYPE:
|
|
483
|
+
return object;
|
|
484
|
+
default:
|
|
485
|
+
return $$typeof;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
case REACT_PORTAL_TYPE:
|
|
489
|
+
return $$typeof;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
reactIs_production.ContextConsumer = REACT_CONSUMER_TYPE;
|
|
494
|
+
reactIs_production.ContextProvider = REACT_CONTEXT_TYPE;
|
|
495
|
+
reactIs_production.Element = REACT_ELEMENT_TYPE;
|
|
496
|
+
reactIs_production.ForwardRef = REACT_FORWARD_REF_TYPE;
|
|
497
|
+
reactIs_production.Fragment = REACT_FRAGMENT_TYPE;
|
|
498
|
+
reactIs_production.Lazy = REACT_LAZY_TYPE;
|
|
499
|
+
reactIs_production.Memo = REACT_MEMO_TYPE;
|
|
500
|
+
reactIs_production.Portal = REACT_PORTAL_TYPE;
|
|
501
|
+
reactIs_production.Profiler = REACT_PROFILER_TYPE;
|
|
502
|
+
reactIs_production.StrictMode = REACT_STRICT_MODE_TYPE;
|
|
503
|
+
reactIs_production.Suspense = REACT_SUSPENSE_TYPE;
|
|
504
|
+
reactIs_production.SuspenseList = REACT_SUSPENSE_LIST_TYPE;
|
|
505
|
+
reactIs_production.isContextConsumer = function (object) {
|
|
506
|
+
return typeOf(object) === REACT_CONSUMER_TYPE;
|
|
507
|
+
};
|
|
508
|
+
reactIs_production.isContextProvider = function (object) {
|
|
509
|
+
return typeOf(object) === REACT_CONTEXT_TYPE;
|
|
510
|
+
};
|
|
511
|
+
reactIs_production.isElement = function (object) {
|
|
512
|
+
return (
|
|
513
|
+
"object" === typeof object &&
|
|
514
|
+
null !== object &&
|
|
515
|
+
object.$$typeof === REACT_ELEMENT_TYPE
|
|
516
|
+
);
|
|
517
|
+
};
|
|
518
|
+
reactIs_production.isForwardRef = function (object) {
|
|
519
|
+
return typeOf(object) === REACT_FORWARD_REF_TYPE;
|
|
520
|
+
};
|
|
521
|
+
reactIs_production.isFragment = function (object) {
|
|
522
|
+
return typeOf(object) === REACT_FRAGMENT_TYPE;
|
|
523
|
+
};
|
|
524
|
+
reactIs_production.isLazy = function (object) {
|
|
525
|
+
return typeOf(object) === REACT_LAZY_TYPE;
|
|
526
|
+
};
|
|
527
|
+
reactIs_production.isMemo = function (object) {
|
|
528
|
+
return typeOf(object) === REACT_MEMO_TYPE;
|
|
529
|
+
};
|
|
530
|
+
reactIs_production.isPortal = function (object) {
|
|
531
|
+
return typeOf(object) === REACT_PORTAL_TYPE;
|
|
532
|
+
};
|
|
533
|
+
reactIs_production.isProfiler = function (object) {
|
|
534
|
+
return typeOf(object) === REACT_PROFILER_TYPE;
|
|
535
|
+
};
|
|
536
|
+
reactIs_production.isStrictMode = function (object) {
|
|
537
|
+
return typeOf(object) === REACT_STRICT_MODE_TYPE;
|
|
538
|
+
};
|
|
539
|
+
reactIs_production.isSuspense = function (object) {
|
|
540
|
+
return typeOf(object) === REACT_SUSPENSE_TYPE;
|
|
541
|
+
};
|
|
542
|
+
reactIs_production.isSuspenseList = function (object) {
|
|
543
|
+
return typeOf(object) === REACT_SUSPENSE_LIST_TYPE;
|
|
544
|
+
};
|
|
545
|
+
reactIs_production.isValidElementType = function (type) {
|
|
546
|
+
return "string" === typeof type ||
|
|
547
|
+
"function" === typeof type ||
|
|
548
|
+
type === REACT_FRAGMENT_TYPE ||
|
|
549
|
+
type === REACT_PROFILER_TYPE ||
|
|
550
|
+
type === REACT_STRICT_MODE_TYPE ||
|
|
551
|
+
type === REACT_SUSPENSE_TYPE ||
|
|
552
|
+
type === REACT_SUSPENSE_LIST_TYPE ||
|
|
553
|
+
("object" === typeof type &&
|
|
554
|
+
null !== type &&
|
|
555
|
+
(type.$$typeof === REACT_LAZY_TYPE ||
|
|
556
|
+
type.$$typeof === REACT_MEMO_TYPE ||
|
|
557
|
+
type.$$typeof === REACT_CONTEXT_TYPE ||
|
|
558
|
+
type.$$typeof === REACT_CONSUMER_TYPE ||
|
|
559
|
+
type.$$typeof === REACT_FORWARD_REF_TYPE ||
|
|
560
|
+
type.$$typeof === REACT_CLIENT_REFERENCE ||
|
|
561
|
+
void 0 !== type.getModuleId))
|
|
562
|
+
? true
|
|
563
|
+
: false;
|
|
564
|
+
};
|
|
565
|
+
reactIs_production.typeOf = typeOf;
|
|
566
|
+
return reactIs_production;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
{
|
|
570
|
+
reactIs.exports = requireReactIs_production();
|
|
113
571
|
}
|
|
114
572
|
|
|
573
|
+
var reactIsExports = reactIs.exports;
|
|
574
|
+
|
|
115
575
|
// https://github.com/sindresorhus/is-plain-obj/blob/main/index.js
|
|
116
576
|
function isPlainObject(item) {
|
|
117
577
|
if (typeof item !== 'object' || item === null) {
|
|
@@ -121,7 +581,7 @@ function isPlainObject(item) {
|
|
|
121
581
|
return (prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null) && !(Symbol.toStringTag in item) && !(Symbol.iterator in item);
|
|
122
582
|
}
|
|
123
583
|
function deepClone(source) {
|
|
124
|
-
if (!isPlainObject(source)) {
|
|
584
|
+
if (/*#__PURE__*/React.isValidElement(source) || reactIsExports.isValidElementType(source) || !isPlainObject(source)) {
|
|
125
585
|
return source;
|
|
126
586
|
}
|
|
127
587
|
const output = {};
|
|
@@ -130,17 +590,38 @@ function deepClone(source) {
|
|
|
130
590
|
});
|
|
131
591
|
return output;
|
|
132
592
|
}
|
|
593
|
+
|
|
594
|
+
/**
|
|
595
|
+
* Merge objects deeply.
|
|
596
|
+
* It will shallow copy React elements.
|
|
597
|
+
*
|
|
598
|
+
* If `options.clone` is set to `false` the source object will be merged directly into the target object.
|
|
599
|
+
*
|
|
600
|
+
* @example
|
|
601
|
+
* ```ts
|
|
602
|
+
* deepmerge({ a: { b: 1 }, d: 2 }, { a: { c: 2 }, d: 4 });
|
|
603
|
+
* // => { a: { b: 1, c: 2 }, d: 4 }
|
|
604
|
+
* ````
|
|
605
|
+
*
|
|
606
|
+
* @param target The target object.
|
|
607
|
+
* @param source The source object.
|
|
608
|
+
* @param options The merge options.
|
|
609
|
+
* @param options.clone Set to `false` to merge the source object directly into the target object.
|
|
610
|
+
* @returns The merged object.
|
|
611
|
+
*/
|
|
133
612
|
function deepmerge(target, source, options = {
|
|
134
613
|
clone: true
|
|
135
614
|
}) {
|
|
136
|
-
const output = options.clone ?
|
|
615
|
+
const output = options.clone ? {
|
|
616
|
+
...target
|
|
617
|
+
} : target;
|
|
137
618
|
if (isPlainObject(target) && isPlainObject(source)) {
|
|
138
619
|
Object.keys(source).forEach(key => {
|
|
620
|
+
if (/*#__PURE__*/React.isValidElement(source[key]) || reactIsExports.isValidElementType(source[key])) {
|
|
621
|
+
output[key] = source[key];
|
|
622
|
+
} else if (isPlainObject(source[key]) &&
|
|
139
623
|
// Avoid prototype pollution
|
|
140
|
-
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
|
-
if (isPlainObject(source[key]) && key in target && isPlainObject(target[key])) {
|
|
624
|
+
Object.prototype.hasOwnProperty.call(target, key) && isPlainObject(target[key])) {
|
|
144
625
|
// Since `output` is a clone of `target` and we have narrowed `target` in this block we can cast to the same type.
|
|
145
626
|
output[key] = deepmerge(target[key], source[key], options);
|
|
146
627
|
} else if (options.clone) {
|
|
@@ -153,7 +634,8 @@ function deepmerge(target, source, options = {
|
|
|
153
634
|
return output;
|
|
154
635
|
}
|
|
155
636
|
|
|
156
|
-
|
|
637
|
+
// Sorted ASC by size. That's important.
|
|
638
|
+
// It can't be configured as it's used statically for propTypes.
|
|
157
639
|
const sortBreakpointsValues = values => {
|
|
158
640
|
const breakpointsAsArray = Object.keys(values).map(key => ({
|
|
159
641
|
key,
|
|
@@ -162,32 +644,33 @@ const sortBreakpointsValues = values => {
|
|
|
162
644
|
// Sort in ascending order
|
|
163
645
|
breakpointsAsArray.sort((breakpoint1, breakpoint2) => breakpoint1.val - breakpoint2.val);
|
|
164
646
|
return breakpointsAsArray.reduce((acc, obj) => {
|
|
165
|
-
return
|
|
647
|
+
return {
|
|
648
|
+
...acc,
|
|
166
649
|
[obj.key]: obj.val
|
|
167
|
-
}
|
|
650
|
+
};
|
|
168
651
|
}, {});
|
|
169
652
|
};
|
|
170
653
|
|
|
171
654
|
// Keep in mind that @media is inclusive by the CSS specification.
|
|
172
655
|
function createBreakpoints(breakpoints) {
|
|
173
656
|
const {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
657
|
+
// The breakpoint **start** at this value.
|
|
658
|
+
// For instance with the first breakpoint xs: [xs, sm).
|
|
659
|
+
values = {
|
|
660
|
+
xs: 0,
|
|
661
|
+
// phone
|
|
662
|
+
sm: 600,
|
|
663
|
+
// tablet
|
|
664
|
+
md: 900,
|
|
665
|
+
// small laptop
|
|
666
|
+
lg: 1200,
|
|
667
|
+
// desktop
|
|
668
|
+
xl: 1536 // large screen
|
|
669
|
+
},
|
|
670
|
+
unit = 'px',
|
|
671
|
+
step = 5,
|
|
672
|
+
...other
|
|
673
|
+
} = breakpoints;
|
|
191
674
|
const sortedValues = sortBreakpointsValues(values);
|
|
192
675
|
const keys = Object.keys(sortedValues);
|
|
193
676
|
function up(key) {
|
|
@@ -219,7 +702,7 @@ function createBreakpoints(breakpoints) {
|
|
|
219
702
|
}
|
|
220
703
|
return between(key, keys[keys.indexOf(key) + 1]).replace('@media', '@media not all and');
|
|
221
704
|
}
|
|
222
|
-
return
|
|
705
|
+
return {
|
|
223
706
|
keys,
|
|
224
707
|
values: sortedValues,
|
|
225
708
|
up,
|
|
@@ -227,8 +710,75 @@ function createBreakpoints(breakpoints) {
|
|
|
227
710
|
between,
|
|
228
711
|
only,
|
|
229
712
|
not,
|
|
230
|
-
unit
|
|
231
|
-
|
|
713
|
+
unit,
|
|
714
|
+
...other
|
|
715
|
+
};
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
/**
|
|
719
|
+
* For using in `sx` prop to sort the breakpoint from low to high.
|
|
720
|
+
* Note: this function does not work and will not support multiple units.
|
|
721
|
+
* e.g. input: { '@container (min-width:300px)': '1rem', '@container (min-width:40rem)': '2rem' }
|
|
722
|
+
* output: { '@container (min-width:40rem)': '2rem', '@container (min-width:300px)': '1rem' } // since 40 < 300 eventhough 40rem > 300px
|
|
723
|
+
*/
|
|
724
|
+
function sortContainerQueries(theme, css) {
|
|
725
|
+
if (!theme.containerQueries) {
|
|
726
|
+
return css;
|
|
727
|
+
}
|
|
728
|
+
const sorted = Object.keys(css).filter(key => key.startsWith('@container')).sort((a, b) => {
|
|
729
|
+
const regex = /min-width:\s*([0-9.]+)/;
|
|
730
|
+
return +(a.match(regex)?.[1] || 0) - +(b.match(regex)?.[1] || 0);
|
|
731
|
+
});
|
|
732
|
+
if (!sorted.length) {
|
|
733
|
+
return css;
|
|
734
|
+
}
|
|
735
|
+
return sorted.reduce((acc, key) => {
|
|
736
|
+
const value = css[key];
|
|
737
|
+
delete acc[key];
|
|
738
|
+
acc[key] = value;
|
|
739
|
+
return acc;
|
|
740
|
+
}, {
|
|
741
|
+
...css
|
|
742
|
+
});
|
|
743
|
+
}
|
|
744
|
+
function isCqShorthand(breakpointKeys, value) {
|
|
745
|
+
return value === '@' || value.startsWith('@') && (breakpointKeys.some(key => value.startsWith(`@${key}`)) || !!value.match(/^@\d/));
|
|
746
|
+
}
|
|
747
|
+
function getContainerQuery(theme, shorthand) {
|
|
748
|
+
const matches = shorthand.match(/^@([^/]+)?\/?(.+)?$/);
|
|
749
|
+
if (!matches) {
|
|
750
|
+
return null;
|
|
751
|
+
}
|
|
752
|
+
const [, containerQuery, containerName] = matches;
|
|
753
|
+
const value = Number.isNaN(+containerQuery) ? containerQuery || 0 : +containerQuery;
|
|
754
|
+
return theme.containerQueries(containerName).up(value);
|
|
755
|
+
}
|
|
756
|
+
function cssContainerQueries(themeInput) {
|
|
757
|
+
const toContainerQuery = (mediaQuery, name) => mediaQuery.replace('@media', name ? `@container ${name}` : '@container');
|
|
758
|
+
function attachCq(node, name) {
|
|
759
|
+
node.up = (...args) => toContainerQuery(themeInput.breakpoints.up(...args), name);
|
|
760
|
+
node.down = (...args) => toContainerQuery(themeInput.breakpoints.down(...args), name);
|
|
761
|
+
node.between = (...args) => toContainerQuery(themeInput.breakpoints.between(...args), name);
|
|
762
|
+
node.only = (...args) => toContainerQuery(themeInput.breakpoints.only(...args), name);
|
|
763
|
+
node.not = (...args) => {
|
|
764
|
+
const result = toContainerQuery(themeInput.breakpoints.not(...args), name);
|
|
765
|
+
if (result.includes('not all and')) {
|
|
766
|
+
// `@container` does not work with `not all and`, so need to invert the logic
|
|
767
|
+
return result.replace('not all and ', '').replace('min-width:', 'width<').replace('max-width:', 'width>').replace('and', 'or');
|
|
768
|
+
}
|
|
769
|
+
return result;
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
const node = {};
|
|
773
|
+
const containerQueries = name => {
|
|
774
|
+
attachCq(node, name);
|
|
775
|
+
return node;
|
|
776
|
+
};
|
|
777
|
+
attachCq(containerQueries);
|
|
778
|
+
return {
|
|
779
|
+
...themeInput,
|
|
780
|
+
containerQueries
|
|
781
|
+
};
|
|
232
782
|
}
|
|
233
783
|
|
|
234
784
|
const shape = {
|
|
@@ -263,6 +813,17 @@ const defaultBreakpoints = {
|
|
|
263
813
|
keys: ['xs', 'sm', 'md', 'lg', 'xl'],
|
|
264
814
|
up: key => `@media (min-width:${values[key]}px)`
|
|
265
815
|
};
|
|
816
|
+
const defaultContainerQueries = {
|
|
817
|
+
containerQueries: containerName => ({
|
|
818
|
+
up: key => {
|
|
819
|
+
let result = typeof key === 'number' ? key : values[key] || key;
|
|
820
|
+
if (typeof result === 'number') {
|
|
821
|
+
result = `${result}px`;
|
|
822
|
+
}
|
|
823
|
+
return containerName ? `@container ${containerName} (min-width:${result})` : `@container (min-width:${result})`;
|
|
824
|
+
}
|
|
825
|
+
})
|
|
826
|
+
};
|
|
266
827
|
function handleBreakpoints(props, propValue, styleFromPropValue) {
|
|
267
828
|
const theme = props.theme || {};
|
|
268
829
|
if (Array.isArray(propValue)) {
|
|
@@ -275,8 +836,14 @@ function handleBreakpoints(props, propValue, styleFromPropValue) {
|
|
|
275
836
|
if (typeof propValue === 'object') {
|
|
276
837
|
const themeBreakpoints = theme.breakpoints || defaultBreakpoints;
|
|
277
838
|
return Object.keys(propValue).reduce((acc, breakpoint) => {
|
|
839
|
+
if (isCqShorthand(themeBreakpoints.keys, breakpoint)) {
|
|
840
|
+
const containerKey = getContainerQuery(theme.containerQueries ? theme : defaultContainerQueries, breakpoint);
|
|
841
|
+
if (containerKey) {
|
|
842
|
+
acc[containerKey] = styleFromPropValue(propValue[breakpoint], breakpoint);
|
|
843
|
+
}
|
|
844
|
+
}
|
|
278
845
|
// key is breakpoint
|
|
279
|
-
if (Object.keys(themeBreakpoints.values || values).
|
|
846
|
+
else if (Object.keys(themeBreakpoints.values || values).includes(breakpoint)) {
|
|
280
847
|
const mediaKey = themeBreakpoints.up(breakpoint);
|
|
281
848
|
acc[mediaKey] = styleFromPropValue(propValue[breakpoint], breakpoint);
|
|
282
849
|
} else {
|
|
@@ -290,8 +857,7 @@ function handleBreakpoints(props, propValue, styleFromPropValue) {
|
|
|
290
857
|
return output;
|
|
291
858
|
}
|
|
292
859
|
function createEmptyBreakpointObject(breakpointsInput = {}) {
|
|
293
|
-
|
|
294
|
-
const breakpointsInOrder = (_breakpointsInput$key = breakpointsInput.keys) == null ? void 0 : _breakpointsInput$key.reduce((acc, key) => {
|
|
860
|
+
const breakpointsInOrder = breakpointsInput.keys?.reduce((acc, key) => {
|
|
295
861
|
const breakpointStyleKey = breakpointsInput.up(key);
|
|
296
862
|
acc[breakpointStyleKey] = {};
|
|
297
863
|
return acc;
|
|
@@ -495,22 +1061,32 @@ const marginKeys = ['m', 'mt', 'mr', 'mb', 'ml', 'mx', 'my', 'margin', 'marginTo
|
|
|
495
1061
|
const paddingKeys = ['p', 'pt', 'pr', 'pb', 'pl', 'px', 'py', 'padding', 'paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft', 'paddingX', 'paddingY', 'paddingInline', 'paddingInlineStart', 'paddingInlineEnd', 'paddingBlock', 'paddingBlockStart', 'paddingBlockEnd'];
|
|
496
1062
|
[...marginKeys, ...paddingKeys];
|
|
497
1063
|
function createUnaryUnit(theme, themeKey, defaultValue, propName) {
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
1064
|
+
const themeSpacing = getPath(theme, themeKey, true) ?? defaultValue;
|
|
1065
|
+
if (typeof themeSpacing === 'number' || typeof themeSpacing === 'string') {
|
|
1066
|
+
return val => {
|
|
1067
|
+
if (typeof val === 'string') {
|
|
1068
|
+
return val;
|
|
1069
|
+
}
|
|
1070
|
+
if (typeof themeSpacing === 'string') {
|
|
1071
|
+
return `calc(${val} * ${themeSpacing})`;
|
|
504
1072
|
}
|
|
505
|
-
return themeSpacing *
|
|
1073
|
+
return themeSpacing * val;
|
|
506
1074
|
};
|
|
507
1075
|
}
|
|
508
1076
|
if (Array.isArray(themeSpacing)) {
|
|
509
|
-
return
|
|
510
|
-
if (typeof
|
|
511
|
-
return
|
|
1077
|
+
return val => {
|
|
1078
|
+
if (typeof val === 'string') {
|
|
1079
|
+
return val;
|
|
1080
|
+
}
|
|
1081
|
+
const abs = Math.abs(val);
|
|
1082
|
+
const transformed = themeSpacing[abs];
|
|
1083
|
+
if (val >= 0) {
|
|
1084
|
+
return transformed;
|
|
512
1085
|
}
|
|
513
|
-
|
|
1086
|
+
if (typeof transformed === 'number') {
|
|
1087
|
+
return -transformed;
|
|
1088
|
+
}
|
|
1089
|
+
return `-${transformed}`;
|
|
514
1090
|
};
|
|
515
1091
|
}
|
|
516
1092
|
if (typeof themeSpacing === 'function') {
|
|
@@ -525,15 +1101,7 @@ function getValue(transformer, propValue) {
|
|
|
525
1101
|
if (typeof propValue === 'string' || propValue == null) {
|
|
526
1102
|
return propValue;
|
|
527
1103
|
}
|
|
528
|
-
|
|
529
|
-
const transformed = transformer(abs);
|
|
530
|
-
if (propValue >= 0) {
|
|
531
|
-
return transformed;
|
|
532
|
-
}
|
|
533
|
-
if (typeof transformed === 'number') {
|
|
534
|
-
return -transformed;
|
|
535
|
-
}
|
|
536
|
-
return `-${transformed}`;
|
|
1104
|
+
return transformer(propValue);
|
|
537
1105
|
}
|
|
538
1106
|
function getStyleFromPropValue(cssProperties, transformer) {
|
|
539
1107
|
return propValue => cssProperties.reduce((acc, cssProperty) => {
|
|
@@ -544,7 +1112,7 @@ function getStyleFromPropValue(cssProperties, transformer) {
|
|
|
544
1112
|
function resolveCssProperty(props, keys, prop, transformer) {
|
|
545
1113
|
// Using a hash computation over an array iteration could be faster, but with only 28 items,
|
|
546
1114
|
// it's doesn't worth the bundle size.
|
|
547
|
-
if (keys.
|
|
1115
|
+
if (!keys.includes(prop)) {
|
|
548
1116
|
return null;
|
|
549
1117
|
}
|
|
550
1118
|
const cssProperties = getCssProperties(prop);
|
|
@@ -570,18 +1138,17 @@ padding.filterProps = paddingKeys;
|
|
|
570
1138
|
// The different signatures imply different meaning for their arguments that can't be expressed structurally.
|
|
571
1139
|
// We express the difference with variable names.
|
|
572
1140
|
|
|
573
|
-
function createSpacing(spacingInput = 8
|
|
1141
|
+
function createSpacing(spacingInput = 8,
|
|
1142
|
+
// Material Design layouts are visually balanced. Most measurements align to an 8dp grid, which aligns both spacing and the overall layout.
|
|
1143
|
+
// Smaller components, such as icons, can align to a 4dp grid.
|
|
1144
|
+
// https://m2.material.io/design/layout/understanding-layout.html
|
|
1145
|
+
transform = createUnarySpacing({
|
|
1146
|
+
spacing: spacingInput
|
|
1147
|
+
})) {
|
|
574
1148
|
// Already transformed.
|
|
575
1149
|
if (spacingInput.mui) {
|
|
576
1150
|
return spacingInput;
|
|
577
1151
|
}
|
|
578
|
-
|
|
579
|
-
// Material Design layouts are visually balanced. Most measurements align to an 8dp grid, which aligns both spacing and the overall layout.
|
|
580
|
-
// Smaller components, such as icons, can align to a 4dp grid.
|
|
581
|
-
// https://m2.material.io/design/layout/understanding-layout.html
|
|
582
|
-
const transform = createUnarySpacing({
|
|
583
|
-
spacing: spacingInput
|
|
584
|
-
});
|
|
585
1152
|
const spacing = (...argsInput) => {
|
|
586
1153
|
const args = argsInput.length === 0 ? [1] : argsInput;
|
|
587
1154
|
return args.map(argument => {
|
|
@@ -765,14 +1332,13 @@ const width = style$2({
|
|
|
765
1332
|
const maxWidth = props => {
|
|
766
1333
|
if (props.maxWidth !== undefined && props.maxWidth !== null) {
|
|
767
1334
|
const styleFromPropValue = propValue => {
|
|
768
|
-
|
|
769
|
-
const breakpoint = ((_props$theme = props.theme) == null || (_props$theme = _props$theme.breakpoints) == null || (_props$theme = _props$theme.values) == null ? void 0 : _props$theme[propValue]) || values[propValue];
|
|
1335
|
+
const breakpoint = props.theme?.breakpoints?.values?.[propValue] || values[propValue];
|
|
770
1336
|
if (!breakpoint) {
|
|
771
1337
|
return {
|
|
772
1338
|
maxWidth: sizingTransform(propValue)
|
|
773
1339
|
};
|
|
774
1340
|
}
|
|
775
|
-
if (
|
|
1341
|
+
if (props.theme?.breakpoints?.unit !== 'px') {
|
|
776
1342
|
return {
|
|
777
1343
|
maxWidth: `${breakpoint}${props.theme.breakpoints.unit}`
|
|
778
1344
|
};
|
|
@@ -1081,6 +1647,9 @@ const defaultSxConfig = {
|
|
|
1081
1647
|
},
|
|
1082
1648
|
boxSizing: {},
|
|
1083
1649
|
// typography
|
|
1650
|
+
font: {
|
|
1651
|
+
themeKey: 'font'
|
|
1652
|
+
},
|
|
1084
1653
|
fontFamily: {
|
|
1085
1654
|
themeKey: 'typography'
|
|
1086
1655
|
},
|
|
@@ -1161,15 +1730,15 @@ function unstable_createStyleFunctionSx() {
|
|
|
1161
1730
|
return handleBreakpoints(props, val, styleFromPropValue);
|
|
1162
1731
|
}
|
|
1163
1732
|
function styleFunctionSx(props) {
|
|
1164
|
-
var _theme$unstable_sxCon;
|
|
1165
1733
|
const {
|
|
1166
1734
|
sx,
|
|
1167
|
-
theme = {}
|
|
1735
|
+
theme = {},
|
|
1736
|
+
nested
|
|
1168
1737
|
} = props || {};
|
|
1169
1738
|
if (!sx) {
|
|
1170
1739
|
return null; // Emotion & styled-components will neglect null
|
|
1171
1740
|
}
|
|
1172
|
-
const config =
|
|
1741
|
+
const config = theme.unstable_sxConfig ?? defaultSxConfig;
|
|
1173
1742
|
|
|
1174
1743
|
/*
|
|
1175
1744
|
* Receive `sxInput` as object or callback
|
|
@@ -1205,7 +1774,8 @@ function unstable_createStyleFunctionSx() {
|
|
|
1205
1774
|
if (objectsHaveSameKeys(breakpointsValues, value)) {
|
|
1206
1775
|
css[styleKey] = styleFunctionSx({
|
|
1207
1776
|
sx: value,
|
|
1208
|
-
theme
|
|
1777
|
+
theme,
|
|
1778
|
+
nested: true
|
|
1209
1779
|
});
|
|
1210
1780
|
} else {
|
|
1211
1781
|
css = merge(css, breakpointsValues);
|
|
@@ -1216,7 +1786,12 @@ function unstable_createStyleFunctionSx() {
|
|
|
1216
1786
|
}
|
|
1217
1787
|
}
|
|
1218
1788
|
});
|
|
1219
|
-
|
|
1789
|
+
if (!nested && theme.modularCssLayers) {
|
|
1790
|
+
return {
|
|
1791
|
+
'@layer sx': sortContainerQueries(theme, removeUnusedBreakpoints(breakpointsKeys, css))
|
|
1792
|
+
};
|
|
1793
|
+
}
|
|
1794
|
+
return sortContainerQueries(theme, removeUnusedBreakpoints(breakpointsKeys, css));
|
|
1220
1795
|
}
|
|
1221
1796
|
return Array.isArray(sx) ? sx.map(traverse) : traverse(sx);
|
|
1222
1797
|
}
|
|
@@ -1229,15 +1804,19 @@ styleFunctionSx.filterProps = ['sx'];
|
|
|
1229
1804
|
* A universal utility to style components with multiple color modes. Always use it from the theme object.
|
|
1230
1805
|
* It works with:
|
|
1231
1806
|
* - [Basic theme](https://mui.com/material-ui/customization/dark-mode/)
|
|
1232
|
-
* - [CSS theme variables](https://mui.com/material-ui/
|
|
1807
|
+
* - [CSS theme variables](https://mui.com/material-ui/customization/css-theme-variables/overview/)
|
|
1233
1808
|
* - Zero-runtime engine
|
|
1234
1809
|
*
|
|
1235
1810
|
* Tips: Use an array over object spread and place `theme.applyStyles()` last.
|
|
1236
1811
|
*
|
|
1812
|
+
* With the styled function:
|
|
1237
1813
|
* ✅ [{ background: '#e5e5e5' }, theme.applyStyles('dark', { background: '#1c1c1c' })]
|
|
1238
|
-
*
|
|
1239
1814
|
* 🚫 { background: '#e5e5e5', ...theme.applyStyles('dark', { background: '#1c1c1c' })}
|
|
1240
1815
|
*
|
|
1816
|
+
* With the sx prop:
|
|
1817
|
+
* ✅ [{ background: '#e5e5e5' }, theme => theme.applyStyles('dark', { background: '#1c1c1c' })]
|
|
1818
|
+
* 🚫 { background: '#e5e5e5', ...theme => theme.applyStyles('dark', { background: '#1c1c1c' })}
|
|
1819
|
+
*
|
|
1241
1820
|
* @example
|
|
1242
1821
|
* 1. using with `styled`:
|
|
1243
1822
|
* ```jsx
|
|
@@ -1253,9 +1832,9 @@ styleFunctionSx.filterProps = ['sx'];
|
|
|
1253
1832
|
* @example
|
|
1254
1833
|
* 2. using with `sx` prop:
|
|
1255
1834
|
* ```jsx
|
|
1256
|
-
* <Box sx={
|
|
1835
|
+
* <Box sx={[
|
|
1257
1836
|
* { background: '#e5e5e5' },
|
|
1258
|
-
* theme.applyStyles('dark', {
|
|
1837
|
+
* theme => theme.applyStyles('dark', {
|
|
1259
1838
|
* background: '#1c1c1c',
|
|
1260
1839
|
* color: '#fff',
|
|
1261
1840
|
* }),
|
|
@@ -1286,10 +1865,19 @@ styleFunctionSx.filterProps = ['sx'];
|
|
|
1286
1865
|
function applyStyles(key, styles) {
|
|
1287
1866
|
// @ts-expect-error this is 'any' type
|
|
1288
1867
|
const theme = this;
|
|
1289
|
-
if (theme.vars
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1868
|
+
if (theme.vars) {
|
|
1869
|
+
if (!theme.colorSchemes?.[key] || typeof theme.getColorSchemeSelector !== 'function') {
|
|
1870
|
+
return {};
|
|
1871
|
+
}
|
|
1872
|
+
// If CssVarsProvider is used as a provider, returns '*:where({selector}) &'
|
|
1873
|
+
let selector = theme.getColorSchemeSelector(key);
|
|
1874
|
+
if (selector === '&') {
|
|
1875
|
+
return styles;
|
|
1876
|
+
}
|
|
1877
|
+
if (selector.includes('data-') || selector.includes('.')) {
|
|
1878
|
+
// '*' is required as a workaround for Emotion issue (https://github.com/emotion-js/emotion/issues/2836)
|
|
1879
|
+
selector = `*:where(${selector.replace(/\s*&$/, '')}) &`;
|
|
1880
|
+
}
|
|
1293
1881
|
return {
|
|
1294
1882
|
[selector]: styles
|
|
1295
1883
|
};
|
|
@@ -1300,15 +1888,14 @@ function applyStyles(key, styles) {
|
|
|
1300
1888
|
return {};
|
|
1301
1889
|
}
|
|
1302
1890
|
|
|
1303
|
-
const _excluded$3 = ["breakpoints", "palette", "spacing", "shape"];
|
|
1304
1891
|
function createTheme(options = {}, ...args) {
|
|
1305
1892
|
const {
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1893
|
+
breakpoints: breakpointsInput = {},
|
|
1894
|
+
palette: paletteInput = {},
|
|
1895
|
+
spacing: spacingInput,
|
|
1896
|
+
shape: shapeInput = {},
|
|
1897
|
+
...other
|
|
1898
|
+
} = options;
|
|
1312
1899
|
const breakpoints = createBreakpoints(breakpointsInput);
|
|
1313
1900
|
const spacing = createSpacing(spacingInput);
|
|
1314
1901
|
let muiTheme = deepmerge({
|
|
@@ -1316,15 +1903,23 @@ function createTheme(options = {}, ...args) {
|
|
|
1316
1903
|
direction: 'ltr',
|
|
1317
1904
|
components: {},
|
|
1318
1905
|
// Inject component definitions.
|
|
1319
|
-
palette:
|
|
1320
|
-
mode: 'light'
|
|
1321
|
-
|
|
1906
|
+
palette: {
|
|
1907
|
+
mode: 'light',
|
|
1908
|
+
...paletteInput
|
|
1909
|
+
},
|
|
1322
1910
|
spacing,
|
|
1323
|
-
shape:
|
|
1911
|
+
shape: {
|
|
1912
|
+
...shape,
|
|
1913
|
+
...shapeInput
|
|
1914
|
+
}
|
|
1324
1915
|
}, other);
|
|
1916
|
+
muiTheme = cssContainerQueries(muiTheme);
|
|
1325
1917
|
muiTheme.applyStyles = applyStyles;
|
|
1326
1918
|
muiTheme = args.reduce((acc, argument) => deepmerge(acc, argument), muiTheme);
|
|
1327
|
-
muiTheme.unstable_sxConfig =
|
|
1919
|
+
muiTheme.unstable_sxConfig = {
|
|
1920
|
+
...defaultSxConfig,
|
|
1921
|
+
...other?.unstable_sxConfig
|
|
1922
|
+
};
|
|
1328
1923
|
muiTheme.unstable_sx = function sx(props) {
|
|
1329
1924
|
return styleFunctionSx({
|
|
1330
1925
|
sx: props,
|
|
@@ -1334,12 +1929,12 @@ function createTheme(options = {}, ...args) {
|
|
|
1334
1929
|
return muiTheme;
|
|
1335
1930
|
}
|
|
1336
1931
|
|
|
1337
|
-
function isObjectEmpty(obj) {
|
|
1932
|
+
function isObjectEmpty$1(obj) {
|
|
1338
1933
|
return Object.keys(obj).length === 0;
|
|
1339
1934
|
}
|
|
1340
1935
|
function useTheme$1(defaultTheme = null) {
|
|
1341
1936
|
const contextTheme = React.useContext(ThemeContext);
|
|
1342
|
-
return !contextTheme || isObjectEmpty(contextTheme) ? defaultTheme : contextTheme;
|
|
1937
|
+
return !contextTheme || isObjectEmpty$1(contextTheme) ? defaultTheme : contextTheme;
|
|
1343
1938
|
}
|
|
1344
1939
|
|
|
1345
1940
|
const systemDefaultTheme$1 = createTheme();
|
|
@@ -1347,14 +1942,12 @@ function useTheme(defaultTheme = systemDefaultTheme$1) {
|
|
|
1347
1942
|
return useTheme$1(defaultTheme);
|
|
1348
1943
|
}
|
|
1349
1944
|
|
|
1350
|
-
const _excluded$2 = ["sx"];
|
|
1351
1945
|
const splitProps = props => {
|
|
1352
|
-
var _props$theme$unstable, _props$theme;
|
|
1353
1946
|
const result = {
|
|
1354
1947
|
systemProps: {},
|
|
1355
1948
|
otherProps: {}
|
|
1356
1949
|
};
|
|
1357
|
-
const config =
|
|
1950
|
+
const config = props?.theme?.unstable_sxConfig ?? defaultSxConfig;
|
|
1358
1951
|
Object.keys(props).forEach(prop => {
|
|
1359
1952
|
if (config[prop]) {
|
|
1360
1953
|
result.systemProps[prop] = props[prop];
|
|
@@ -1366,9 +1959,9 @@ const splitProps = props => {
|
|
|
1366
1959
|
};
|
|
1367
1960
|
function extendSxProp(props) {
|
|
1368
1961
|
const {
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1962
|
+
sx: inSx,
|
|
1963
|
+
...other
|
|
1964
|
+
} = props;
|
|
1372
1965
|
const {
|
|
1373
1966
|
systemProps,
|
|
1374
1967
|
otherProps
|
|
@@ -1382,14 +1975,21 @@ function extendSxProp(props) {
|
|
|
1382
1975
|
if (!isPlainObject(result)) {
|
|
1383
1976
|
return systemProps;
|
|
1384
1977
|
}
|
|
1385
|
-
return
|
|
1978
|
+
return {
|
|
1979
|
+
...systemProps,
|
|
1980
|
+
...result
|
|
1981
|
+
};
|
|
1386
1982
|
};
|
|
1387
1983
|
} else {
|
|
1388
|
-
finalSx =
|
|
1984
|
+
finalSx = {
|
|
1985
|
+
...systemProps,
|
|
1986
|
+
...inSx
|
|
1987
|
+
};
|
|
1389
1988
|
}
|
|
1390
|
-
return
|
|
1989
|
+
return {
|
|
1990
|
+
...otherProps,
|
|
1391
1991
|
sx: finalSx
|
|
1392
|
-
}
|
|
1992
|
+
};
|
|
1393
1993
|
}
|
|
1394
1994
|
|
|
1395
1995
|
const defaultGenerator = componentName => componentName;
|
|
@@ -1430,90 +2030,122 @@ function generateUtilityClass(componentName, slot, globalStatePrefix = 'Mui') {
|
|
|
1430
2030
|
return globalStateClass ? `${globalStatePrefix}-${globalStateClass}` : `${ClassNameGenerator.generate(componentName)}-${slot}`;
|
|
1431
2031
|
}
|
|
1432
2032
|
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
2033
|
+
function preprocessStyles(input) {
|
|
2034
|
+
const {
|
|
2035
|
+
variants,
|
|
2036
|
+
...style
|
|
2037
|
+
} = input;
|
|
2038
|
+
const result = {
|
|
2039
|
+
variants,
|
|
2040
|
+
style: internal_serializeStyles(style),
|
|
2041
|
+
isProcessed: true
|
|
2042
|
+
};
|
|
1439
2043
|
|
|
1440
|
-
//
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
2044
|
+
// Not supported on styled-components
|
|
2045
|
+
if (result.style === style) {
|
|
2046
|
+
return result;
|
|
2047
|
+
}
|
|
2048
|
+
if (variants) {
|
|
2049
|
+
variants.forEach(variant => {
|
|
2050
|
+
if (typeof variant.style !== 'function') {
|
|
2051
|
+
variant.style = internal_serializeStyles(variant.style);
|
|
2052
|
+
}
|
|
2053
|
+
});
|
|
2054
|
+
}
|
|
2055
|
+
return result;
|
|
1447
2056
|
}
|
|
1448
2057
|
|
|
2058
|
+
/* eslint-disable no-underscore-dangle */
|
|
2059
|
+
/* eslint-disable no-labels */
|
|
2060
|
+
/* eslint-disable no-lone-blocks */
|
|
2061
|
+
|
|
2062
|
+
const systemDefaultTheme = createTheme();
|
|
2063
|
+
|
|
1449
2064
|
// Update /system/styled/#api in case if this changes
|
|
1450
2065
|
function shouldForwardProp(prop) {
|
|
1451
2066
|
return prop !== 'ownerState' && prop !== 'theme' && prop !== 'sx' && prop !== 'as';
|
|
1452
2067
|
}
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
2068
|
+
function shallowLayer(serialized, layerName) {
|
|
2069
|
+
if (layerName && serialized && typeof serialized === 'object' && serialized.styles && !serialized.styles.startsWith('@layer') // only add the layer if it is not already there.
|
|
2070
|
+
) {
|
|
2071
|
+
serialized.styles = `@layer ${layerName}{${String(serialized.styles)}}`;
|
|
1457
2072
|
}
|
|
1458
|
-
return
|
|
1459
|
-
};
|
|
1460
|
-
function resolveTheme({
|
|
1461
|
-
defaultTheme,
|
|
1462
|
-
theme,
|
|
1463
|
-
themeId
|
|
1464
|
-
}) {
|
|
1465
|
-
return isEmpty(theme) ? defaultTheme : theme[themeId] || theme;
|
|
2073
|
+
return serialized;
|
|
1466
2074
|
}
|
|
1467
2075
|
function defaultOverridesResolver(slot) {
|
|
1468
2076
|
if (!slot) {
|
|
1469
2077
|
return null;
|
|
1470
2078
|
}
|
|
1471
|
-
return (
|
|
2079
|
+
return (_props, styles) => styles[slot];
|
|
2080
|
+
}
|
|
2081
|
+
function attachTheme(props, themeId, defaultTheme) {
|
|
2082
|
+
props.theme = isObjectEmpty(props.theme) ? defaultTheme : props.theme[themeId] || props.theme;
|
|
1472
2083
|
}
|
|
1473
|
-
function
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
2084
|
+
function processStyle(props, style, layerName) {
|
|
2085
|
+
/*
|
|
2086
|
+
* Style types:
|
|
2087
|
+
* - null/undefined
|
|
2088
|
+
* - string
|
|
2089
|
+
* - CSS style object: { [cssKey]: [cssValue], variants }
|
|
2090
|
+
* - Processed style object: { style, variants, isProcessed: true }
|
|
2091
|
+
* - Array of any of the above
|
|
2092
|
+
*/
|
|
2093
|
+
|
|
2094
|
+
const resolvedStyle = typeof style === 'function' ? style(props) : style;
|
|
2095
|
+
if (Array.isArray(resolvedStyle)) {
|
|
2096
|
+
return resolvedStyle.flatMap(subStyle => processStyle(props, subStyle, layerName));
|
|
1485
2097
|
}
|
|
1486
|
-
if (
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
2098
|
+
if (Array.isArray(resolvedStyle?.variants)) {
|
|
2099
|
+
let rootStyle;
|
|
2100
|
+
if (resolvedStyle.isProcessed) {
|
|
2101
|
+
rootStyle = layerName ? shallowLayer(resolvedStyle.style, layerName) : resolvedStyle.style;
|
|
2102
|
+
} else {
|
|
2103
|
+
const {
|
|
2104
|
+
variants,
|
|
2105
|
+
...otherStyles
|
|
2106
|
+
} = resolvedStyle;
|
|
2107
|
+
rootStyle = layerName ? shallowLayer(internal_serializeStyles(otherStyles), layerName) : otherStyles;
|
|
2108
|
+
}
|
|
2109
|
+
return processStyleVariants(props, resolvedStyle.variants, [rootStyle], layerName);
|
|
2110
|
+
}
|
|
2111
|
+
if (resolvedStyle?.isProcessed) {
|
|
2112
|
+
return layerName ? shallowLayer(internal_serializeStyles(resolvedStyle.style), layerName) : resolvedStyle.style;
|
|
2113
|
+
}
|
|
2114
|
+
return layerName ? shallowLayer(internal_serializeStyles(resolvedStyle), layerName) : resolvedStyle;
|
|
2115
|
+
}
|
|
2116
|
+
function processStyleVariants(props, variants, results = [], layerName = undefined) {
|
|
2117
|
+
let mergedState; // We might not need it, initialized lazily
|
|
2118
|
+
|
|
2119
|
+
variantLoop: for (let i = 0; i < variants.length; i += 1) {
|
|
2120
|
+
const variant = variants[i];
|
|
2121
|
+
if (typeof variant.props === 'function') {
|
|
2122
|
+
mergedState ??= {
|
|
2123
|
+
...props,
|
|
2124
|
+
...props.ownerState,
|
|
2125
|
+
ownerState: props.ownerState
|
|
2126
|
+
};
|
|
2127
|
+
if (!variant.props(mergedState)) {
|
|
2128
|
+
continue;
|
|
1504
2129
|
}
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
2130
|
+
} else {
|
|
2131
|
+
for (const key in variant.props) {
|
|
2132
|
+
if (props[key] !== variant.props[key] && props.ownerState?.[key] !== variant.props[key]) {
|
|
2133
|
+
continue variantLoop;
|
|
1508
2134
|
}
|
|
1509
|
-
result.push(typeof variant.style === 'function' ? variant.style(_extends({
|
|
1510
|
-
ownerState
|
|
1511
|
-
}, props, ownerState)) : variant.style);
|
|
1512
2135
|
}
|
|
1513
|
-
}
|
|
1514
|
-
|
|
2136
|
+
}
|
|
2137
|
+
if (typeof variant.style === 'function') {
|
|
2138
|
+
mergedState ??= {
|
|
2139
|
+
...props,
|
|
2140
|
+
...props.ownerState,
|
|
2141
|
+
ownerState: props.ownerState
|
|
2142
|
+
};
|
|
2143
|
+
results.push(layerName ? shallowLayer(internal_serializeStyles(variant.style(mergedState)), layerName) : variant.style(mergedState));
|
|
2144
|
+
} else {
|
|
2145
|
+
results.push(layerName ? shallowLayer(internal_serializeStyles(variant.style), layerName) : variant.style);
|
|
2146
|
+
}
|
|
1515
2147
|
}
|
|
1516
|
-
return
|
|
2148
|
+
return results;
|
|
1517
2149
|
}
|
|
1518
2150
|
function createStyled(input = {}) {
|
|
1519
2151
|
const {
|
|
@@ -1522,28 +2154,24 @@ function createStyled(input = {}) {
|
|
|
1522
2154
|
rootShouldForwardProp = shouldForwardProp,
|
|
1523
2155
|
slotShouldForwardProp = shouldForwardProp
|
|
1524
2156
|
} = input;
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
};
|
|
1533
|
-
systemSx.__mui_systemSx = true;
|
|
1534
|
-
return (tag, inputOptions = {}) => {
|
|
1535
|
-
// Filter out the `sx` style function from the previous styled component to prevent unnecessary styles generated by the composite components.
|
|
1536
|
-
internal_processStyles(tag, styles => styles.filter(style => !(style != null && style.__mui_systemSx)));
|
|
2157
|
+
function styleAttachTheme(props) {
|
|
2158
|
+
attachTheme(props, themeId, defaultTheme);
|
|
2159
|
+
}
|
|
2160
|
+
const styled = (tag, inputOptions = {}) => {
|
|
2161
|
+
// If `tag` is already a styled component, filter out the `sx` style function
|
|
2162
|
+
// to prevent unnecessary styles generated by the composite components.
|
|
2163
|
+
internal_mutateStyles(tag, styles => styles.filter(style => style !== styleFunctionSx));
|
|
1537
2164
|
const {
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
2165
|
+
name: componentName,
|
|
2166
|
+
slot: componentSlot,
|
|
2167
|
+
skipVariantsResolver: inputSkipVariantsResolver,
|
|
2168
|
+
skipSx: inputSkipSx,
|
|
2169
|
+
// TODO v6: remove `lowercaseFirstLetter()` in the next major release
|
|
2170
|
+
// For more details: https://github.com/mui/material-ui/pull/37908
|
|
2171
|
+
overridesResolver = defaultOverridesResolver(lowercaseFirstLetter(componentSlot)),
|
|
2172
|
+
...options
|
|
2173
|
+
} = inputOptions;
|
|
2174
|
+
const layerName = componentName && componentName.startsWith('Mui') || !!componentSlot ? 'components' : 'custom';
|
|
1547
2175
|
|
|
1548
2176
|
// if skipVariantsResolver option is defined, take the value, otherwise, true for root and false for other slots.
|
|
1549
2177
|
const skipVariantsResolver = inputSkipVariantsResolver !== undefined ? inputSkipVariantsResolver :
|
|
@@ -1551,7 +2179,6 @@ function createStyled(input = {}) {
|
|
|
1551
2179
|
// For more details: https://github.com/mui/material-ui/pull/37908
|
|
1552
2180
|
componentSlot && componentSlot !== 'Root' && componentSlot !== 'root' || false;
|
|
1553
2181
|
const skipSx = inputSkipSx || false;
|
|
1554
|
-
let label;
|
|
1555
2182
|
let shouldForwardPropOption = shouldForwardProp;
|
|
1556
2183
|
|
|
1557
2184
|
// TODO v6: remove `Root` in the next major release
|
|
@@ -1565,74 +2192,96 @@ function createStyled(input = {}) {
|
|
|
1565
2192
|
// for string (html) tag, preserve the behavior in emotion & styled-components.
|
|
1566
2193
|
shouldForwardPropOption = undefined;
|
|
1567
2194
|
}
|
|
1568
|
-
const defaultStyledResolver = styled$1(tag,
|
|
2195
|
+
const defaultStyledResolver = styled$1(tag, {
|
|
1569
2196
|
shouldForwardProp: shouldForwardPropOption,
|
|
1570
|
-
label
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
//
|
|
1575
|
-
//
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
themeId
|
|
1582
|
-
})
|
|
1583
|
-
}));
|
|
2197
|
+
label: generateStyledLabel(),
|
|
2198
|
+
...options
|
|
2199
|
+
});
|
|
2200
|
+
const transformStyle = style => {
|
|
2201
|
+
// - On the server Emotion doesn't use React.forwardRef for creating components, so the created
|
|
2202
|
+
// component stays as a function. This condition makes sure that we do not interpolate functions
|
|
2203
|
+
// which are basically components used as a selectors.
|
|
2204
|
+
// - `style` could be a styled component from a babel plugin for component selectors, This condition
|
|
2205
|
+
// makes sure that we do not interpolate them.
|
|
2206
|
+
if (style.__emotion_real === style) {
|
|
2207
|
+
return style;
|
|
1584
2208
|
}
|
|
1585
|
-
|
|
2209
|
+
if (typeof style === 'function') {
|
|
2210
|
+
return function styleFunctionProcessor(props) {
|
|
2211
|
+
return processStyle(props, style, props.theme.modularCssLayers ? layerName : undefined);
|
|
2212
|
+
};
|
|
2213
|
+
}
|
|
2214
|
+
if (isPlainObject(style)) {
|
|
2215
|
+
const serialized = preprocessStyles(style);
|
|
2216
|
+
return function styleObjectProcessor(props) {
|
|
2217
|
+
if (!serialized.variants) {
|
|
2218
|
+
return props.theme.modularCssLayers ? shallowLayer(serialized.style, layerName) : serialized.style;
|
|
2219
|
+
}
|
|
2220
|
+
return processStyle(props, serialized, props.theme.modularCssLayers ? layerName : undefined);
|
|
2221
|
+
};
|
|
2222
|
+
}
|
|
2223
|
+
return style;
|
|
1586
2224
|
};
|
|
1587
|
-
const muiStyledResolver = (
|
|
1588
|
-
|
|
1589
|
-
const
|
|
2225
|
+
const muiStyledResolver = (...expressionsInput) => {
|
|
2226
|
+
const expressionsHead = [];
|
|
2227
|
+
const expressionsBody = expressionsInput.map(transformStyle);
|
|
2228
|
+
const expressionsTail = [];
|
|
2229
|
+
|
|
2230
|
+
// Preprocess `props` to set the scoped theme value.
|
|
2231
|
+
// This must run before any other expression.
|
|
2232
|
+
expressionsHead.push(styleAttachTheme);
|
|
1590
2233
|
if (componentName && overridesResolver) {
|
|
1591
|
-
|
|
1592
|
-
const theme =
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
}));
|
|
1596
|
-
if (!theme.components || !theme.components[componentName] || !theme.components[componentName].styleOverrides) {
|
|
2234
|
+
expressionsTail.push(function styleThemeOverrides(props) {
|
|
2235
|
+
const theme = props.theme;
|
|
2236
|
+
const styleOverrides = theme.components?.[componentName]?.styleOverrides;
|
|
2237
|
+
if (!styleOverrides) {
|
|
1597
2238
|
return null;
|
|
1598
2239
|
}
|
|
1599
|
-
const styleOverrides = theme.components[componentName].styleOverrides;
|
|
1600
2240
|
const resolvedStyleOverrides = {};
|
|
2241
|
+
|
|
1601
2242
|
// TODO: v7 remove iteration and use `resolveStyleArg(styleOverrides[slot])` directly
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
});
|
|
2243
|
+
// eslint-disable-next-line guard-for-in
|
|
2244
|
+
for (const slotKey in styleOverrides) {
|
|
2245
|
+
resolvedStyleOverrides[slotKey] = processStyle(props, styleOverrides[slotKey], props.theme.modularCssLayers ? 'theme' : undefined);
|
|
2246
|
+
}
|
|
1607
2247
|
return overridesResolver(props, resolvedStyleOverrides);
|
|
1608
2248
|
});
|
|
1609
2249
|
}
|
|
1610
2250
|
if (componentName && !skipVariantsResolver) {
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
const
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
}
|
|
1617
|
-
|
|
1618
|
-
return processStyleArg({
|
|
1619
|
-
variants: themeVariants
|
|
1620
|
-
}, _extends({}, props, {
|
|
1621
|
-
theme
|
|
1622
|
-
}));
|
|
2251
|
+
expressionsTail.push(function styleThemeVariants(props) {
|
|
2252
|
+
const theme = props.theme;
|
|
2253
|
+
const themeVariants = theme?.components?.[componentName]?.variants;
|
|
2254
|
+
if (!themeVariants) {
|
|
2255
|
+
return null;
|
|
2256
|
+
}
|
|
2257
|
+
return processStyleVariants(props, themeVariants, [], props.theme.modularCssLayers ? 'theme' : undefined);
|
|
1623
2258
|
});
|
|
1624
2259
|
}
|
|
1625
2260
|
if (!skipSx) {
|
|
1626
|
-
|
|
2261
|
+
expressionsTail.push(styleFunctionSx);
|
|
1627
2262
|
}
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
2263
|
+
|
|
2264
|
+
// This function can be called as a tagged template, so the first argument would contain
|
|
2265
|
+
// CSS `string[]` values.
|
|
2266
|
+
if (Array.isArray(expressionsBody[0])) {
|
|
2267
|
+
const inputStrings = expressionsBody.shift();
|
|
2268
|
+
|
|
2269
|
+
// We need to add placeholders in the tagged template for the custom functions we have
|
|
2270
|
+
// possibly added (attachTheme, overrides, variants, and sx).
|
|
2271
|
+
const placeholdersHead = new Array(expressionsHead.length).fill('');
|
|
2272
|
+
const placeholdersTail = new Array(expressionsTail.length).fill('');
|
|
2273
|
+
let outputStrings;
|
|
2274
|
+
// prettier-ignore
|
|
2275
|
+
{
|
|
2276
|
+
outputStrings = [...placeholdersHead, ...inputStrings, ...placeholdersTail];
|
|
2277
|
+
outputStrings.raw = [...placeholdersHead, ...inputStrings.raw, ...placeholdersTail];
|
|
2278
|
+
}
|
|
2279
|
+
|
|
2280
|
+
// The only case where we put something before `attachTheme`
|
|
2281
|
+
expressionsHead.unshift(outputStrings);
|
|
1634
2282
|
}
|
|
1635
|
-
const
|
|
2283
|
+
const expressions = [...expressionsHead, ...expressionsBody, ...expressionsTail];
|
|
2284
|
+
const Component = defaultStyledResolver(...expressions);
|
|
1636
2285
|
if (tag.muiName) {
|
|
1637
2286
|
Component.muiName = tag.muiName;
|
|
1638
2287
|
}
|
|
@@ -1643,41 +2292,78 @@ function createStyled(input = {}) {
|
|
|
1643
2292
|
}
|
|
1644
2293
|
return muiStyledResolver;
|
|
1645
2294
|
};
|
|
2295
|
+
return styled;
|
|
2296
|
+
}
|
|
2297
|
+
function generateStyledLabel(componentName, componentSlot) {
|
|
2298
|
+
let label;
|
|
2299
|
+
return label;
|
|
2300
|
+
}
|
|
2301
|
+
function isObjectEmpty(object) {
|
|
2302
|
+
// eslint-disable-next-line
|
|
2303
|
+
for (const _ in object) {
|
|
2304
|
+
return false;
|
|
2305
|
+
}
|
|
2306
|
+
return true;
|
|
2307
|
+
}
|
|
2308
|
+
|
|
2309
|
+
// https://github.com/emotion-js/emotion/blob/26ded6109fcd8ca9875cc2ce4564fee678a3f3c5/packages/styled/src/utils.js#L40
|
|
2310
|
+
function isStringTag(tag) {
|
|
2311
|
+
return typeof tag === 'string' &&
|
|
2312
|
+
// 96 is one less than the char code
|
|
2313
|
+
// for "a" so this is checking that
|
|
2314
|
+
// it's a lowercase character
|
|
2315
|
+
tag.charCodeAt(0) > 96;
|
|
2316
|
+
}
|
|
2317
|
+
function lowercaseFirstLetter(string) {
|
|
2318
|
+
if (!string) {
|
|
2319
|
+
return string;
|
|
2320
|
+
}
|
|
2321
|
+
return string.charAt(0).toLowerCase() + string.slice(1);
|
|
1646
2322
|
}
|
|
1647
2323
|
|
|
1648
2324
|
const styled = createStyled();
|
|
1649
2325
|
|
|
1650
2326
|
/**
|
|
1651
2327
|
* Add keys, values of `defaultProps` that does not exist in `props`
|
|
1652
|
-
* @param
|
|
1653
|
-
* @param
|
|
1654
|
-
* @returns
|
|
2328
|
+
* @param defaultProps
|
|
2329
|
+
* @param props
|
|
2330
|
+
* @returns resolved props
|
|
1655
2331
|
*/
|
|
1656
2332
|
function resolveProps(defaultProps, props) {
|
|
1657
|
-
const output =
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
const
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
} else if (
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
output[propName]
|
|
1675
|
-
}
|
|
2333
|
+
const output = {
|
|
2334
|
+
...props
|
|
2335
|
+
};
|
|
2336
|
+
for (const key in defaultProps) {
|
|
2337
|
+
if (Object.prototype.hasOwnProperty.call(defaultProps, key)) {
|
|
2338
|
+
const propName = key;
|
|
2339
|
+
if (propName === 'components' || propName === 'slots') {
|
|
2340
|
+
output[propName] = {
|
|
2341
|
+
...defaultProps[propName],
|
|
2342
|
+
...output[propName]
|
|
2343
|
+
};
|
|
2344
|
+
} else if (propName === 'componentsProps' || propName === 'slotProps') {
|
|
2345
|
+
const defaultSlotProps = defaultProps[propName];
|
|
2346
|
+
const slotProps = props[propName];
|
|
2347
|
+
if (!slotProps) {
|
|
2348
|
+
output[propName] = defaultSlotProps || {};
|
|
2349
|
+
} else if (!defaultSlotProps) {
|
|
2350
|
+
output[propName] = slotProps;
|
|
2351
|
+
} else {
|
|
2352
|
+
output[propName] = {
|
|
2353
|
+
...slotProps
|
|
2354
|
+
};
|
|
2355
|
+
for (const slotKey in defaultSlotProps) {
|
|
2356
|
+
if (Object.prototype.hasOwnProperty.call(defaultSlotProps, slotKey)) {
|
|
2357
|
+
const slotPropName = slotKey;
|
|
2358
|
+
output[propName][slotPropName] = resolveProps(defaultSlotProps[slotPropName], slotProps[slotPropName]);
|
|
2359
|
+
}
|
|
2360
|
+
}
|
|
2361
|
+
}
|
|
2362
|
+
} else if (output[propName] === undefined) {
|
|
2363
|
+
output[propName] = defaultProps[propName];
|
|
1676
2364
|
}
|
|
1677
|
-
} else if (output[propName] === undefined) {
|
|
1678
|
-
output[propName] = defaultProps[propName];
|
|
1679
2365
|
}
|
|
1680
|
-
}
|
|
2366
|
+
}
|
|
1681
2367
|
return output;
|
|
1682
2368
|
}
|
|
1683
2369
|
|
|
@@ -1703,37 +2389,67 @@ function useThemeProps({
|
|
|
1703
2389
|
if (themeId) {
|
|
1704
2390
|
theme = theme[themeId] || theme;
|
|
1705
2391
|
}
|
|
1706
|
-
|
|
2392
|
+
return getThemeProps({
|
|
1707
2393
|
theme,
|
|
1708
2394
|
name,
|
|
1709
2395
|
props
|
|
1710
2396
|
});
|
|
1711
|
-
return mergedProps;
|
|
1712
2397
|
}
|
|
1713
2398
|
|
|
2399
|
+
/* eslint no-restricted-syntax: 0, prefer-template: 0, guard-for-in: 0
|
|
2400
|
+
---
|
|
2401
|
+
These rules are preventing the performance optimizations below.
|
|
2402
|
+
*/
|
|
2403
|
+
|
|
2404
|
+
/**
|
|
2405
|
+
* Compose classes from multiple sources.
|
|
2406
|
+
*
|
|
2407
|
+
* @example
|
|
2408
|
+
* ```tsx
|
|
2409
|
+
* const slots = {
|
|
2410
|
+
* root: ['root', 'primary'],
|
|
2411
|
+
* label: ['label'],
|
|
2412
|
+
* };
|
|
2413
|
+
*
|
|
2414
|
+
* const getUtilityClass = (slot) => `MuiButton-${slot}`;
|
|
2415
|
+
*
|
|
2416
|
+
* const classes = {
|
|
2417
|
+
* root: 'my-root-class',
|
|
2418
|
+
* };
|
|
2419
|
+
*
|
|
2420
|
+
* const output = composeClasses(slots, getUtilityClass, classes);
|
|
2421
|
+
* // {
|
|
2422
|
+
* // root: 'MuiButton-root MuiButton-primary my-root-class',
|
|
2423
|
+
* // label: 'MuiButton-label',
|
|
2424
|
+
* // }
|
|
2425
|
+
* ```
|
|
2426
|
+
*
|
|
2427
|
+
* @param slots a list of classes for each possible slot
|
|
2428
|
+
* @param getUtilityClass a function to resolve the class based on the slot name
|
|
2429
|
+
* @param classes the input classes from props
|
|
2430
|
+
* @returns the resolved classes for all slots
|
|
2431
|
+
*/
|
|
1714
2432
|
function composeClasses(slots, getUtilityClass, classes = undefined) {
|
|
1715
2433
|
const output = {};
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
acc.push(classes[key]);
|
|
2434
|
+
for (const slotName in slots) {
|
|
2435
|
+
const slot = slots[slotName];
|
|
2436
|
+
let buffer = '';
|
|
2437
|
+
let start = true;
|
|
2438
|
+
for (let i = 0; i < slot.length; i += 1) {
|
|
2439
|
+
const value = slot[i];
|
|
2440
|
+
if (value) {
|
|
2441
|
+
buffer += (start === true ? '' : ' ') + getUtilityClass(value);
|
|
2442
|
+
start = false;
|
|
2443
|
+
if (classes && classes[value]) {
|
|
2444
|
+
buffer += ' ' + classes[value];
|
|
1728
2445
|
}
|
|
1729
2446
|
}
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
}
|
|
2447
|
+
}
|
|
2448
|
+
output[slotName] = buffer;
|
|
2449
|
+
}
|
|
1733
2450
|
return output;
|
|
1734
2451
|
}
|
|
1735
2452
|
|
|
1736
|
-
const _excluded = ["component", "direction", "spacing", "divider", "children", "className", "useFlexGap"];
|
|
1737
2453
|
const defaultTheme = createTheme();
|
|
1738
2454
|
// widening Theme to any so that the consumer can own the theme structure.
|
|
1739
2455
|
const defaultCreateStyledComponent = styled('div', {
|
|
@@ -1761,7 +2477,7 @@ function joinChildren(children, separator) {
|
|
|
1761
2477
|
return childrenArray.reduce((output, child, index) => {
|
|
1762
2478
|
output.push(child);
|
|
1763
2479
|
if (index < childrenArray.length - 1) {
|
|
1764
|
-
output.push(
|
|
2480
|
+
output.push(/*#__PURE__*/React.cloneElement(separator, {
|
|
1765
2481
|
key: `separator-${index}`
|
|
1766
2482
|
}));
|
|
1767
2483
|
}
|
|
@@ -1780,17 +2496,18 @@ const style = ({
|
|
|
1780
2496
|
ownerState,
|
|
1781
2497
|
theme
|
|
1782
2498
|
}) => {
|
|
1783
|
-
let styles =
|
|
2499
|
+
let styles = {
|
|
1784
2500
|
display: 'flex',
|
|
1785
|
-
flexDirection: 'column'
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
2501
|
+
flexDirection: 'column',
|
|
2502
|
+
...handleBreakpoints({
|
|
2503
|
+
theme
|
|
2504
|
+
}, resolveBreakpointValues({
|
|
2505
|
+
values: ownerState.direction,
|
|
2506
|
+
breakpoints: theme.breakpoints.values
|
|
2507
|
+
}), propValue => ({
|
|
2508
|
+
flexDirection: propValue
|
|
2509
|
+
}))
|
|
2510
|
+
};
|
|
1794
2511
|
if (ownerState.spacing) {
|
|
1795
2512
|
const transformer = createUnarySpacing(theme);
|
|
1796
2513
|
const base = Object.keys(theme.breakpoints.values).reduce((acc, breakpoint) => {
|
|
@@ -1858,29 +2575,29 @@ function createStack(options = {}) {
|
|
|
1858
2575
|
const themeProps = useThemeProps(inProps);
|
|
1859
2576
|
const props = extendSxProp(themeProps); // `color` type conflicts with html color attribute.
|
|
1860
2577
|
const {
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
2578
|
+
component = 'div',
|
|
2579
|
+
direction = 'column',
|
|
2580
|
+
spacing = 0,
|
|
2581
|
+
divider,
|
|
2582
|
+
children,
|
|
2583
|
+
className,
|
|
2584
|
+
useFlexGap = false,
|
|
2585
|
+
...other
|
|
2586
|
+
} = props;
|
|
1870
2587
|
const ownerState = {
|
|
1871
2588
|
direction,
|
|
1872
2589
|
spacing,
|
|
1873
2590
|
useFlexGap
|
|
1874
2591
|
};
|
|
1875
2592
|
const classes = useUtilityClasses();
|
|
1876
|
-
return /*#__PURE__*/jsx(StackRoot,
|
|
2593
|
+
return /*#__PURE__*/jsx(StackRoot, {
|
|
1877
2594
|
as: component,
|
|
1878
2595
|
ownerState: ownerState,
|
|
1879
2596
|
ref: ref,
|
|
1880
|
-
className: clsx(classes.root, className)
|
|
1881
|
-
|
|
2597
|
+
className: clsx(classes.root, className),
|
|
2598
|
+
...other,
|
|
1882
2599
|
children: divider ? joinChildren(children, divider) : children
|
|
1883
|
-
})
|
|
2600
|
+
});
|
|
1884
2601
|
});
|
|
1885
2602
|
return Stack;
|
|
1886
2603
|
}
|
|
@@ -1899,26 +2616,58 @@ function createStack(options = {}) {
|
|
|
1899
2616
|
*/
|
|
1900
2617
|
const Stack = createStack();
|
|
1901
2618
|
|
|
2619
|
+
const StyledCardContent = styled$2('div')((p) => ({
|
|
2620
|
+
[p.theme.breakpoints.up('xs')]: {
|
|
2621
|
+
padding: p.theme.spacing(1),
|
|
2622
|
+
flex: '1 0 auto',
|
|
2623
|
+
'&:last-child': { paddingBottom: 0 },
|
|
2624
|
+
overflow: 'hidden',
|
|
2625
|
+
},
|
|
2626
|
+
}));
|
|
2627
|
+
/**
|
|
2628
|
+
* Component that displays the title and subtitle of a thumbnail list item.
|
|
2629
|
+
* Text is automatically truncated with ellipsis when it exceeds the available space.
|
|
2630
|
+
* The number of visible lines adjusts based on screen size.
|
|
2631
|
+
*
|
|
2632
|
+
* @param {Object} props - Component props
|
|
2633
|
+
* @param {string} props.title - Primary title text displayed in bold
|
|
2634
|
+
* @param {ReactNode} props.subTitle - Secondary text displayed below the title
|
|
2635
|
+
* @returns {JSX.Element} The rendered title section with ellipsis overflow handling
|
|
2636
|
+
*/
|
|
1902
2637
|
function ThumbnailListItemTitle(props) {
|
|
1903
|
-
|
|
1904
|
-
[p.theme.breakpoints.up('xs')]: {
|
|
1905
|
-
padding: p.theme.spacing(1),
|
|
1906
|
-
flex: '1 0 auto',
|
|
1907
|
-
'&:last-child': { paddingBottom: 0 },
|
|
1908
|
-
overflow: 'hidden',
|
|
1909
|
-
},
|
|
1910
|
-
}));
|
|
1911
|
-
return (jsx(Fragment, { children: jsx(Box, { children: jsxs(StyledCardContent, { children: [jsx(EllipsisContainer, { lineClamp: { xs: 1, sm: 2 }, children: jsx(Typography, { variant: "subtitle2", sx: { fontWeight: 'bold' }, children: props.title }) }), jsx(Stack, { direction: "row", gap: 1, children: jsx(EllipsisContainer, { lineClamp: { xs: 1, sm: 2 }, children: jsx(Typography, { variant: "subtitle2", sx: { fontSize: '0.84rem' }, color: "text.secondary", children: props.subTitle }) }) })] }) }) }));
|
|
2638
|
+
return (jsx(Box, { children: jsxs(StyledCardContent, { children: [jsx(EllipsisContainer, { lineClamp: { xs: 1, sm: 2 }, children: jsx(Typography, { variant: "subtitle2", sx: { fontWeight: 'bold' }, children: props.title }) }), jsx(Stack, { direction: "row", gap: 1, children: jsx(EllipsisContainer, { lineClamp: { xs: 1, sm: 2 }, children: jsx(Typography, { variant: "subtitle2", sx: { fontSize: '0.84rem' }, color: "text.secondary", children: props.subTitle }) }) })] }) }));
|
|
1912
2639
|
}
|
|
1913
2640
|
|
|
1914
|
-
|
|
1915
|
-
|
|
2641
|
+
/**
|
|
2642
|
+
* Width percentage for thumbnail image in list items.
|
|
2643
|
+
* Value based on golden ratio proportion for optimal visual balance.
|
|
2644
|
+
*/
|
|
2645
|
+
const THUMBNAIL_IMAGE_WIDTH = '38.2%';
|
|
2646
|
+
/**
|
|
2647
|
+
* Individual thumbnail list item component displaying an image, title, subtitle, and optional label.
|
|
2648
|
+
* The component is memoized to prevent unnecessary re-renders.
|
|
2649
|
+
*
|
|
2650
|
+
* @param {ThumbnailListItemProps} props - Component props
|
|
2651
|
+
* @param {string} props.id - Unique identifier for the item
|
|
2652
|
+
* @param {string} props.thumbnailUrl - URL of the thumbnail image
|
|
2653
|
+
* @param {string} props.title - Primary title text
|
|
2654
|
+
* @param {ReactNode} props.subTitle - Secondary text displayed below title
|
|
2655
|
+
* @param {ReactNode} props.infoLabel - Additional label content displayed on the right
|
|
2656
|
+
* @param {function} [props.onClick] - Optional click handler that receives the item id
|
|
2657
|
+
* @returns {JSX.Element} The rendered thumbnail item as a Material-UI Card
|
|
2658
|
+
*/
|
|
2659
|
+
const ThumbnailListItem$1 = (props) => {
|
|
2660
|
+
return (jsx(Card, { sx: { display: 'flex' }, children: jsx(CardActionArea, { disabled: !props.onClick, onClick: props.onClick ? () => props.onClick(props.id) : undefined, "aria-label": props.onClick ? `View ${props.title}` : undefined, children: jsxs(Stack$1, { direction: "row", width: "100%", children: [jsx(Box, { component: "img", src: props.thumbnailUrl, width: THUMBNAIL_IMAGE_WIDTH, alt: props.title, sx: { objectFit: 'cover', height: '100%' } }), jsxs(Stack$1, { direction: "row", justifyContent: "space-between", flex: 1, gap: 1, children: [jsx(ThumbnailListItemTitle, { title: props.title, subTitle: props.subTitle }), props.infoLabel] })] }) }) }));
|
|
1916
2661
|
};
|
|
1917
|
-
var ThumbnailListItem
|
|
2662
|
+
var ThumbnailListItem = React__default.memo(ThumbnailListItem$1);
|
|
1918
2663
|
|
|
2664
|
+
/**
|
|
2665
|
+
* Padding percentage used to create responsive card height with fixed aspect ratio.
|
|
2666
|
+
* This percentage ensures consistent card dimensions across different screen sizes.
|
|
2667
|
+
*/
|
|
2668
|
+
const CARD_ASPECT_RATIO_PADDING = '27.75%';
|
|
1919
2669
|
const RatioWrapper = styled$2('div')(() => ({
|
|
1920
|
-
|
|
1921
|
-
paddingTop: '27.75%', // 9 / 16 = 0.5625
|
|
2670
|
+
paddingTop: CARD_ASPECT_RATIO_PADDING,
|
|
1922
2671
|
position: 'relative',
|
|
1923
2672
|
width: '100%',
|
|
1924
2673
|
'& > *': {
|
|
@@ -1929,17 +2678,30 @@ const RatioWrapper = styled$2('div')(() => ({
|
|
|
1929
2678
|
bottom: 0,
|
|
1930
2679
|
},
|
|
1931
2680
|
}));
|
|
1932
|
-
|
|
2681
|
+
/**
|
|
2682
|
+
* Main content area that displays the grid of thumbnail items.
|
|
2683
|
+
* Handles responsive layout with Material-UI Grid and shows a loading indicator.
|
|
2684
|
+
*
|
|
2685
|
+
* @param {ThumbnailListMainContentProps} props - Component props
|
|
2686
|
+
* @param {BreakpointType} [props.muiBreakpoints={ xs: 12, sm: 6, md: 6, lg: 4, xl: 3 }] - Grid column spans for different screen sizes
|
|
2687
|
+
* @param {number} [props.spacing=2] - Spacing between grid items
|
|
2688
|
+
* @returns {JSX.Element} The rendered grid of thumbnail items with loading indicator
|
|
2689
|
+
*
|
|
2690
|
+
* @example
|
|
2691
|
+
* ```tsx
|
|
2692
|
+
* <ThumbnailList.MainContent
|
|
2693
|
+
* spacing={3}
|
|
2694
|
+
* muiBreakpoints={{ xs: 12, sm: 6, md: 4, lg: 3, xl: 2 }}
|
|
2695
|
+
* />
|
|
2696
|
+
* ```
|
|
2697
|
+
*/
|
|
2698
|
+
function ThumbnailListMainContent({ spacing = 2, muiBreakpoints = { xs: 12, sm: 6, md: 6, lg: 4, xl: 3 }, }) {
|
|
1933
2699
|
const { items, isLoading } = useThumbnailListItemContext();
|
|
1934
2700
|
const memoizedItems = useMemo(() => {
|
|
1935
|
-
return items.map((item) => (jsx(Grid, { item: true, xs:
|
|
1936
|
-
}, [items,
|
|
1937
|
-
return (jsxs(Fragment, { children: [jsx(Box, { sx: { mt: 0.75, mb: 0.75 }, children: jsx(LinearProgress, { sx: { opacity: isLoading ? 1 : 0 } }) }), jsx(Grid, { container: true, spacing:
|
|
2701
|
+
return items.map((item) => (jsx(Grid, { item: true, xs: muiBreakpoints.xs, sm: muiBreakpoints.sm, md: muiBreakpoints.md, lg: muiBreakpoints.lg, xl: muiBreakpoints.xl, children: jsx(RatioWrapper, { children: jsx(ThumbnailListItem, { id: item.id, thumbnailUrl: item.thumbnailUrl, title: item.title, subTitle: item.subTitle, infoLabel: item.label, onClick: item.onClick }) }) }, item.id)));
|
|
2702
|
+
}, [items, muiBreakpoints]);
|
|
2703
|
+
return (jsxs(Fragment, { children: [jsx(Box, { sx: { mt: 0.75, mb: 0.75 }, children: jsx(LinearProgress, { sx: { opacity: isLoading ? 1 : 0 } }) }), jsx(Grid, { container: true, spacing: spacing, children: memoizedItems })] }));
|
|
1938
2704
|
}
|
|
1939
|
-
ThumbnailListMainContent.defaultProps = {
|
|
1940
|
-
spacing: 2,
|
|
1941
|
-
muiBreakpoints: { xs: 12, sm: 6, md: 6, lg: 4, xl: 3 },
|
|
1942
|
-
};
|
|
1943
2705
|
|
|
1944
2706
|
/**
|
|
1945
2707
|
* Generic method that sorts an array of items based on an item key
|
|
@@ -1970,14 +2732,48 @@ function compareValues(a, b) {
|
|
|
1970
2732
|
return a < b ? -1 : a > b ? 1 : 0;
|
|
1971
2733
|
}
|
|
1972
2734
|
}
|
|
2735
|
+
/**
|
|
2736
|
+
* Filters an array of items based on a tag property and optional condition function.
|
|
2737
|
+
* If no condition is provided, items are filtered based on the truthiness of the tag value.
|
|
2738
|
+
*
|
|
2739
|
+
* @template T - The type of items in the array
|
|
2740
|
+
* @param {T[]} array - The array to filter
|
|
2741
|
+
* @param {keyof T} tagType - The property key to use for filtering
|
|
2742
|
+
* @param {ConditionFunction<T[keyof T]>} [condition] - Optional condition function to apply to tag values
|
|
2743
|
+
* @returns {T[]} A new array containing only items that pass the filter
|
|
2744
|
+
*/
|
|
1973
2745
|
function filterByTag(array, tagType, condition) {
|
|
1974
2746
|
const filteredArray = array.filter((item) => {
|
|
1975
2747
|
const tagValue = item[tagType];
|
|
1976
2748
|
return condition ? condition(tagValue) : !!tagValue;
|
|
1977
2749
|
});
|
|
1978
|
-
return
|
|
2750
|
+
return filteredArray;
|
|
1979
2751
|
}
|
|
1980
2752
|
|
|
2753
|
+
/**
|
|
2754
|
+
* React hook that filters thumbnail list items based on a tag property and optional condition.
|
|
2755
|
+
* Special case: when tag is 'id', returns all items without filtering.
|
|
2756
|
+
*
|
|
2757
|
+
* @template T - The type of items in the array
|
|
2758
|
+
* @param {UseTagFilteredThumbnailListItemsProps<T>} props - Hook configuration
|
|
2759
|
+
* @param {T[]} props.allItems - Array of all items to filter
|
|
2760
|
+
* @param {string} props.initialTag - Initial property key to filter by
|
|
2761
|
+
* @param {ConditionFunction<T[keyof T]>} [props.initialCondition] - Optional initial filter condition
|
|
2762
|
+
* @returns {Object} Hook return values
|
|
2763
|
+
* @returns {Object} returns.tagAndCondition - Current tag and condition configuration
|
|
2764
|
+
* @returns {function} returns.setTagAndCondition - Function to update both tag and condition
|
|
2765
|
+
* @returns {T[]} returns.tagFilteredItems - Filtered array of items
|
|
2766
|
+
* @returns {function} returns.setTagWithCondition - Helper function to set tag with condition
|
|
2767
|
+
*
|
|
2768
|
+
* @example
|
|
2769
|
+
* ```tsx
|
|
2770
|
+
* const { tagFilteredItems, setTagAndCondition } = useTagFilteredThumbnailListItems({
|
|
2771
|
+
* allItems: items,
|
|
2772
|
+
* initialTag: 'status',
|
|
2773
|
+
* initialCondition: (val) => val === 'active'
|
|
2774
|
+
* });
|
|
2775
|
+
* ```
|
|
2776
|
+
*/
|
|
1981
2777
|
const useTagFilteredThumbnailListItems = ({ allItems, initialTag, initialCondition, }) => {
|
|
1982
2778
|
const [tagAndCondition, setTagAndCondition] = useState({ tag: initialTag, condition: initialCondition });
|
|
1983
2779
|
const setTagWithCondition = (t, c) => {
|
|
@@ -1998,33 +2794,68 @@ const useTagFilteredThumbnailListItems = ({ allItems, initialTag, initialConditi
|
|
|
1998
2794
|
};
|
|
1999
2795
|
|
|
2000
2796
|
/**
|
|
2001
|
-
*
|
|
2002
|
-
*
|
|
2003
|
-
*
|
|
2004
|
-
* @
|
|
2797
|
+
* React hook that filters thumbnail list items based on a search term.
|
|
2798
|
+
* Performs case-insensitive search against item titles and memoizes results for performance.
|
|
2799
|
+
*
|
|
2800
|
+
* @param {ThumbnailListItemInterface[]} allItems - Array of all items to filter
|
|
2801
|
+
* @param {string} [initialSearchTerm=''] - Initial search term value
|
|
2802
|
+
* @returns {Object} Hook return values
|
|
2803
|
+
* @returns {string} returns.searchTerm - Current search term
|
|
2804
|
+
* @returns {function} returns.setSearchTerm - Function to update the search term
|
|
2805
|
+
* @returns {ThumbnailListItemInterface[]} returns.filteredItems - Items matching the search term
|
|
2806
|
+
*
|
|
2807
|
+
* @example
|
|
2808
|
+
* ```tsx
|
|
2809
|
+
* const { searchTerm, setSearchTerm, filteredItems } = useFilteredThumbnailListItems(items);
|
|
2810
|
+
* ```
|
|
2005
2811
|
*/
|
|
2006
2812
|
const useFilteredThumbnailListItems = (allItems, initialSearchTerm = '') => {
|
|
2007
2813
|
const [searchTerm, setSearchTerm] = useState(initialSearchTerm);
|
|
2008
2814
|
const filteredItems = useMemo(() => {
|
|
2009
|
-
const filtered =
|
|
2815
|
+
const filtered = allItems.filter((item) => item.title.toLowerCase().includes(searchTerm.toLowerCase()));
|
|
2010
2816
|
return filtered;
|
|
2011
2817
|
}, [allItems, searchTerm]);
|
|
2012
2818
|
return { searchTerm, setSearchTerm, filteredItems };
|
|
2013
2819
|
};
|
|
2014
2820
|
|
|
2821
|
+
/**
|
|
2822
|
+
* React hook that provides sorting functionality for thumbnail list items.
|
|
2823
|
+
* Sorts items by a specified property key and supports ascending/descending order.
|
|
2824
|
+
*
|
|
2825
|
+
* @template T - The type of items in the array
|
|
2826
|
+
* @param {T[]} allItems - Array of all items to sort
|
|
2827
|
+
* @param {string} initialSortBy - Initial property key to sort by
|
|
2828
|
+
* @param {boolean} initialSortAscending - Whether to initially sort in ascending order
|
|
2829
|
+
* @returns {Object} Hook return values
|
|
2830
|
+
* @returns {string} returns.sortBy - Current sort property key
|
|
2831
|
+
* @returns {boolean} returns.sortAscending - Current sort direction (true for ascending)
|
|
2832
|
+
* @returns {function} returns.setSortBy - Function to change the sort property
|
|
2833
|
+
* @returns {function} returns.setSortAscending - Function to change the sort direction
|
|
2834
|
+
* @returns {T[]} returns.sortedItems - Sorted array of items
|
|
2835
|
+
*
|
|
2836
|
+
* @example
|
|
2837
|
+
* ```tsx
|
|
2838
|
+
* const { sortBy, sortAscending, setSortBy, setSortAscending, sortedItems } =
|
|
2839
|
+
* useSortedThumbnailListItems(items, 'title', true);
|
|
2840
|
+
* ```
|
|
2841
|
+
*/
|
|
2015
2842
|
const useSortedThumbnailListItems = (allItems, initialSortBy, initialSortAscending) => {
|
|
2016
2843
|
const [sortBy, setSortBy] = useState(initialSortBy);
|
|
2017
2844
|
const [sortAscending, setSortAscending] = useState(initialSortAscending);
|
|
2018
2845
|
const sortedItems = useMemo(() => {
|
|
2019
2846
|
let sorted = orderByArray(allItems, sortBy);
|
|
2020
2847
|
if (!sortAscending) {
|
|
2021
|
-
sorted = sorted.reverse();
|
|
2848
|
+
sorted = [...sorted].reverse();
|
|
2022
2849
|
}
|
|
2023
2850
|
return sorted;
|
|
2024
2851
|
}, [allItems, sortBy, sortAscending]);
|
|
2025
2852
|
return { sortBy, sortAscending, setSortBy, setSortAscending, sortedItems };
|
|
2026
2853
|
};
|
|
2027
2854
|
|
|
2855
|
+
/**
|
|
2856
|
+
* Default configuration values for ThumbnailList.
|
|
2857
|
+
* Items are sorted by 'id' in ascending order by default.
|
|
2858
|
+
*/
|
|
2028
2859
|
const defaultConfiguration = {
|
|
2029
2860
|
sortBy: 'id',
|
|
2030
2861
|
sortAscending: true,
|
|
@@ -2043,7 +2874,7 @@ var lodash = {exports: {}};
|
|
|
2043
2874
|
*/
|
|
2044
2875
|
lodash.exports;
|
|
2045
2876
|
|
|
2046
|
-
(function (module, exports) {
|
|
2877
|
+
(function (module, exports$1) {
|
|
2047
2878
|
(function() {
|
|
2048
2879
|
|
|
2049
2880
|
/** Used as a safe reference for `undefined` in pre-ES5 environments. */
|
|
@@ -2474,7 +3305,7 @@ lodash.exports;
|
|
|
2474
3305
|
var root = freeGlobal || freeSelf || Function('return this')();
|
|
2475
3306
|
|
|
2476
3307
|
/** Detect free variable `exports`. */
|
|
2477
|
-
var freeExports = exports && !exports.nodeType && exports;
|
|
3308
|
+
var freeExports = exports$1 && !exports$1.nodeType && exports$1;
|
|
2478
3309
|
|
|
2479
3310
|
/** Detect free variable `module`. */
|
|
2480
3311
|
var freeModule = freeExports && 'object' == 'object' && module && !module.nodeType && module;
|
|
@@ -7489,7 +8320,7 @@ lodash.exports;
|
|
|
7489
8320
|
bitmask &= ~(isCurry ? WRAP_PARTIAL_RIGHT_FLAG : WRAP_PARTIAL_FLAG);
|
|
7490
8321
|
|
|
7491
8322
|
if (!(bitmask & WRAP_CURRY_BOUND_FLAG)) {
|
|
7492
|
-
bitmask &=
|
|
8323
|
+
bitmask &= -4;
|
|
7493
8324
|
}
|
|
7494
8325
|
var newData = [
|
|
7495
8326
|
func, bitmask, thisArg, newPartials, newHolders, newPartialsRight,
|
|
@@ -7592,7 +8423,7 @@ lodash.exports;
|
|
|
7592
8423
|
}
|
|
7593
8424
|
var length = partials ? partials.length : 0;
|
|
7594
8425
|
if (!length) {
|
|
7595
|
-
bitmask &=
|
|
8426
|
+
bitmask &= -97;
|
|
7596
8427
|
partials = holders = undefined$1;
|
|
7597
8428
|
}
|
|
7598
8429
|
ary = ary === undefined$1 ? ary : nativeMax(toInteger(ary), 0);
|
|
@@ -7625,7 +8456,7 @@ lodash.exports;
|
|
|
7625
8456
|
: nativeMax(newData[9] - length, 0);
|
|
7626
8457
|
|
|
7627
8458
|
if (!arity && bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG)) {
|
|
7628
|
-
bitmask &=
|
|
8459
|
+
bitmask &= -25;
|
|
7629
8460
|
}
|
|
7630
8461
|
if (!bitmask || bitmask == WRAP_BIND_FLAG) {
|
|
7631
8462
|
var result = createBind(func, bitmask, thisArg);
|
|
@@ -19235,91 +20066,166 @@ lodash.exports;
|
|
|
19235
20066
|
|
|
19236
20067
|
var lodashExports = lodash.exports;
|
|
19237
20068
|
|
|
19238
|
-
|
|
20069
|
+
/**
|
|
20070
|
+
* Search field component for filtering thumbnail list items.
|
|
20071
|
+
* Includes a search icon, text input, and clear button. Search is debounced for performance.
|
|
20072
|
+
* The component is memoized to prevent unnecessary re-renders.
|
|
20073
|
+
*
|
|
20074
|
+
* @returns {JSX.Element} The rendered search field with icons and clear functionality
|
|
20075
|
+
*
|
|
20076
|
+
* @example
|
|
20077
|
+
* ```tsx
|
|
20078
|
+
* <ThumbnailList.Header>
|
|
20079
|
+
* <ThumbnailList.Header.SearchField />
|
|
20080
|
+
* </ThumbnailList.Header>
|
|
20081
|
+
* ```
|
|
20082
|
+
*/
|
|
20083
|
+
const ThumbnailListSearchField$1 = () => {
|
|
19239
20084
|
const [input, setInput] = useState('');
|
|
19240
20085
|
const [showClearIcon, setShowClearIcon] = useState('hidden');
|
|
19241
20086
|
const { setSearchTerm } = useThumbnailListItemContext();
|
|
20087
|
+
// Create debounced function that's stable across renders unless setSearchTerm changes
|
|
20088
|
+
const debouncedSetSearchTerm = useMemo(() => lodashExports.debounce((value) => setSearchTerm(value), 250), [setSearchTerm]);
|
|
19242
20089
|
const handleChange = (value) => {
|
|
19243
20090
|
setInput(value);
|
|
19244
20091
|
setShowClearIcon(value === '' ? 'hidden' : '');
|
|
19245
20092
|
};
|
|
19246
|
-
const debouncedSetSearchTerm = useCallback(lodashExports.debounce(setSearchTerm, 50), []);
|
|
19247
20093
|
useEffect(() => {
|
|
19248
20094
|
debouncedSetSearchTerm(input);
|
|
19249
20095
|
return () => {
|
|
19250
20096
|
debouncedSetSearchTerm.cancel();
|
|
19251
20097
|
};
|
|
19252
20098
|
}, [input, debouncedSetSearchTerm]);
|
|
19253
|
-
return (jsx(Box, { sx: { marginLeft: 'auto' }, children: jsx(FormControl, { children: jsx(TextField, { fullWidth: true, value: input, size: "small", variant: "outlined", onChange: (event) => handleChange(event.target.value), InputProps: {
|
|
20099
|
+
return (jsx(Box, { sx: { marginLeft: 'auto' }, children: jsx(FormControl, { children: jsx(TextField, { fullWidth: true, value: input, size: "small", variant: "outlined", onChange: (event) => handleChange(event.target.value), "aria-label": "Search thumbnails", InputProps: {
|
|
19254
20100
|
startAdornment: (jsx(InputAdornment, { position: "start", children: jsx(SearchIcon, {}) })),
|
|
19255
|
-
endAdornment: (jsx(InputAdornment, { position: "end", children: jsx(IconButton, { onClick: () => handleChange(''), sx: { visibility: showClearIcon, padding: 0 }, children: jsx(ClearIcon, {}) }) })),
|
|
20101
|
+
endAdornment: (jsx(InputAdornment, { position: "end", children: jsx(IconButton, { onClick: () => handleChange(''), sx: { visibility: showClearIcon, padding: 0 }, "aria-label": "Clear search", children: jsx(ClearIcon, {}) }) })),
|
|
19256
20102
|
} }) }) }));
|
|
19257
20103
|
};
|
|
19258
|
-
ThumbnailListSearchField
|
|
19259
|
-
align: 'start',
|
|
19260
|
-
};
|
|
19261
|
-
var ThumbnailListSearchField$1 = React__default.memo(ThumbnailListSearchField);
|
|
20104
|
+
var ThumbnailListSearchField = React__default.memo(ThumbnailListSearchField$1);
|
|
19262
20105
|
|
|
20106
|
+
/**
|
|
20107
|
+
* Individual filter tag component that displays as either a chip or icon button.
|
|
20108
|
+
* Automatically collapses to icon-only view on smaller screens if an icon is provided.
|
|
20109
|
+
*
|
|
20110
|
+
* @param {ThumbnailListFilterTagProps} props - Component props
|
|
20111
|
+
* @param {string} props.label - Display text for the tag
|
|
20112
|
+
* @param {string} props.value - Value passed to the callback when clicked
|
|
20113
|
+
* @param {'filled' | 'outlined'} props.variant - Visual style of the chip (filled for active, outlined for inactive)
|
|
20114
|
+
* @param {Breakpoint} [props.collapseBreakpoint] - Screen size below which the chip shows as an icon
|
|
20115
|
+
* @param {ReactNode} [props.icon] - Optional icon to display in collapsed mode
|
|
20116
|
+
* @param {function} [props.onClickCallback] - Callback function triggered when tag is clicked
|
|
20117
|
+
* @returns {JSX.Element} The rendered filter tag as a Chip or IconButton
|
|
20118
|
+
*/
|
|
19263
20119
|
function ThumbnailListFilterTag(props) {
|
|
19264
20120
|
const theme = useTheme$2();
|
|
20121
|
+
const isAboveBreakpoint = useMediaQuery(theme.breakpoints.up(props.collapseBreakpoint ?? 0));
|
|
19265
20122
|
const handleOnClick = (value) => {
|
|
19266
20123
|
if (props.onClickCallback) {
|
|
19267
20124
|
props.onClickCallback(value);
|
|
19268
20125
|
}
|
|
19269
20126
|
};
|
|
19270
|
-
return
|
|
20127
|
+
return isAboveBreakpoint || !props.icon ? (jsx(Chip, { label: props.label, variant: props.variant, onClick: props.onClickCallback ? () => handleOnClick(props.value) : undefined })) : (jsx(Tooltip, { title: props.label, children: jsx(IconButton, { onClick: props.onClickCallback ? () => handleOnClick(props.value) : undefined, children: props.icon }) }));
|
|
19271
20128
|
}
|
|
19272
20129
|
|
|
19273
|
-
|
|
20130
|
+
/**
|
|
20131
|
+
* Container component that renders multiple filter tag buttons.
|
|
20132
|
+
* Each tag can filter items based on a specific property and optional condition function.
|
|
20133
|
+
*
|
|
20134
|
+
* @template T - The type of items in the list
|
|
20135
|
+
* @param {ThumbnailListFilterTagsProps<T>} props - Component props
|
|
20136
|
+
* @param {ThumbnailListItemTagType<T>[]} props.tags - Array of tag configurations
|
|
20137
|
+
* @param {Breakpoint} [props.muiCollapseBreakpoint='md'] - Breakpoint at which tags collapse to icons
|
|
20138
|
+
* @returns {JSX.Element} The rendered collection of filter tags
|
|
20139
|
+
*
|
|
20140
|
+
* @example
|
|
20141
|
+
* ```tsx
|
|
20142
|
+
* <ThumbnailList.Header.FilterTags
|
|
20143
|
+
* tags={[
|
|
20144
|
+
* { label: 'Active', key: 'status', condition: (val) => val === 'active' },
|
|
20145
|
+
* { label: 'Archived', key: 'status', condition: (val) => val === 'archived' }
|
|
20146
|
+
* ]}
|
|
20147
|
+
* />
|
|
20148
|
+
* ```
|
|
20149
|
+
*/
|
|
20150
|
+
function ThumbnailListFilterTags({ tags, muiCollapseBreakpoint = 'md', }) {
|
|
19274
20151
|
const { tagFilterCallback, tagAndCondition } = useThumbnailListItemContext();
|
|
19275
|
-
return (jsx(Fragment, { children:
|
|
19276
|
-
|
|
20152
|
+
return (jsx(Fragment, { children: tags.map((tag, index) => {
|
|
20153
|
+
const isActive = tagAndCondition.tag === tag.key.toString() && tagAndCondition.condition === tag.condition;
|
|
20154
|
+
return (jsx(ThumbnailListFilterTag, { label: tag.label, value: tag.key.toString(), variant: isActive ? 'filled' : 'outlined', collapseBreakpoint: muiCollapseBreakpoint, onClickCallback: (value) => tagFilterCallback({ tag: value, condition: tag.condition }), icon: tag.icon }, `${index}_${tag.key.toString()}`));
|
|
19277
20155
|
}) }));
|
|
19278
20156
|
}
|
|
19279
|
-
ThumbnailListFilterTags.defaultProps = {
|
|
19280
|
-
align: 'start',
|
|
19281
|
-
muiCollapseBreakpoint: 'md',
|
|
19282
|
-
};
|
|
19283
20157
|
|
|
19284
20158
|
/**
|
|
19285
20159
|
* Displays a generic MUI select dropdown.
|
|
19286
|
-
*
|
|
20160
|
+
* Optional collapses to a sort icon at a certain breakpoint
|
|
19287
20161
|
* @param props.label Select Label
|
|
19288
20162
|
* @param props.width * Width of the input field
|
|
19289
20163
|
* @param props.collapseBreakPoint * MUI breakpoint after that the select will collapse to the sort icon
|
|
19290
20164
|
* @param props.onChangeCallback * Callback function that gets triggered once a item is selected
|
|
19291
20165
|
* @param props.items * Array of items (name-value-pairs) that will be the select options
|
|
19292
|
-
* @returns
|
|
20166
|
+
* @returns Dropdown Input Component
|
|
19293
20167
|
*/
|
|
19294
20168
|
function DropdownInput(props) {
|
|
19295
20169
|
const [value, setValue] = useState(props.defaultValue ?? '');
|
|
19296
20170
|
const theme = useTheme$2();
|
|
20171
|
+
const isAboveBreakpoint = useMediaQuery(theme.breakpoints.up(props.collapseBreakpoint ?? 0));
|
|
19297
20172
|
const [anchorEl, setAnchorEl] = useState(null);
|
|
19298
20173
|
const handleChange = (value, name) => {
|
|
19299
20174
|
setValue(value);
|
|
19300
20175
|
setAnchorEl(null);
|
|
19301
20176
|
props.onChangeCallback(value, name);
|
|
19302
20177
|
};
|
|
19303
|
-
return (jsxs(Fragment, { children: [
|
|
20178
|
+
return (jsxs(Fragment, { children: [isAboveBreakpoint ? (jsxs(FormControl, { sx: { width: props.width, textAlign: 'start' }, children: [jsx(InputLabel, { size: "small", children: props.label }), jsx(Select, { value: value, size: "small", label: props.label, onChange: (event) => handleChange(event.target.value, event.target.name), children: props.items.map((item) => {
|
|
19304
20179
|
return (jsx(MenuItem, { value: item.value, children: item.name }, item.value));
|
|
19305
|
-
}) })] })) : (jsx(IconButton
|
|
19306
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
19307
|
-
, {
|
|
19308
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
19309
|
-
onClick: (event) => setAnchorEl(event.currentTarget), children: props.icon })), jsx(Menu, { anchorEl: anchorEl, open: Boolean(anchorEl), onClose: () => setAnchorEl(null), children: props.items.map((item) => (jsx(MenuItem, { onClick: () => handleChange(item.value), children: item.name }, item.value))) })] }));
|
|
20180
|
+
}) })] })) : (jsx(IconButton, { onClick: (event) => setAnchorEl(event.currentTarget), children: props.icon })), jsx(Menu, { anchorEl: anchorEl, open: Boolean(anchorEl), onClose: () => setAnchorEl(null), children: props.items.map((item) => (jsx(MenuItem, { onClick: () => handleChange(item.value), children: item.name }, item.value))) })] }));
|
|
19310
20181
|
}
|
|
19311
20182
|
|
|
19312
|
-
|
|
20183
|
+
/**
|
|
20184
|
+
* Sort control component that provides sorting functionality for the thumbnail list.
|
|
20185
|
+
* Includes a toggle button for ascending/descending order and a dropdown to select the sort field.
|
|
20186
|
+
*
|
|
20187
|
+
* @template T - The type of items in the list
|
|
20188
|
+
* @param {ThumbnailListHeaderSortProps<T>} props - Component props
|
|
20189
|
+
* @param {Array<{label: string, key: keyof T}>} props.items - Array of sortable field options
|
|
20190
|
+
* @param {Breakpoint} [props.muiBreakpoint='md'] - Breakpoint at which the dropdown collapses to an icon
|
|
20191
|
+
* @returns {JSX.Element} The rendered sort controls with ascending/descending toggle and field selector
|
|
20192
|
+
*
|
|
20193
|
+
* @example
|
|
20194
|
+
* ```tsx
|
|
20195
|
+
* <ThumbnailList.Header.Sort
|
|
20196
|
+
* items={[
|
|
20197
|
+
* { label: 'Title', key: 'title' },
|
|
20198
|
+
* { label: 'Date', key: 'date' }
|
|
20199
|
+
* ]}
|
|
20200
|
+
* />
|
|
20201
|
+
* ```
|
|
20202
|
+
*/
|
|
20203
|
+
function ThumbnailListHeaderSort({ items, muiBreakpoint = 'md', }) {
|
|
19313
20204
|
const { setSortAscending, sortAscending, setSortBy, sortBy } = useThumbnailListItemContext();
|
|
19314
|
-
return (jsx(Fragment, { children: jsxs(Box, { sx: { minWidth: '80px' }, children: [jsx(Tooltip, { title: "asc/desc", children: jsx(IconButton, { onClick: () => setSortAscending(!sortAscending), children: jsx(SwapVertIcon, {}) }) }), jsx(DropdownInput, { width: "130px", collapseBreakpoint:
|
|
20205
|
+
return (jsx(Fragment, { children: jsxs(Box, { sx: { minWidth: '80px' }, children: [jsx(Tooltip, { title: "asc/desc", children: jsx(IconButton, { onClick: () => setSortAscending(!sortAscending), "aria-label": sortAscending ? "Sort descending" : "Sort ascending", children: jsx(SwapVertIcon, {}) }) }), jsx(DropdownInput, { width: "130px", collapseBreakpoint: muiBreakpoint, label: 'sort', defaultValue: sortBy, icon: jsx(Tooltip, { title: 'sort', children: jsx(SortIcon, {}) }), items: items.map((i) => {
|
|
19315
20206
|
return { name: i.label, value: i.key.toString() };
|
|
19316
20207
|
}), onChangeCallback: (value) => setSortBy(value) })] }) }));
|
|
19317
20208
|
}
|
|
19318
|
-
ThumbnailListHeaderSort.defaultProps = {
|
|
19319
|
-
align: 'start',
|
|
19320
|
-
muiBreakpoint: 'md',
|
|
19321
|
-
};
|
|
19322
20209
|
|
|
20210
|
+
/**
|
|
20211
|
+
* Header component for the ThumbnailList that arranges child components horizontally.
|
|
20212
|
+
* Child components can be aligned to 'start' or 'end' using their align prop.
|
|
20213
|
+
*
|
|
20214
|
+
* This component uses a compound component pattern with SearchField, FilterTags, and Sort sub-components.
|
|
20215
|
+
*
|
|
20216
|
+
* @param {ThumbnailListHeaderProps} props - Component props
|
|
20217
|
+
* @param {ReactNode} props.children - Child components to display in the header
|
|
20218
|
+
* @param {'start' | 'center' | 'end' | 'space-between'} [props.justifyContent='space-between'] - Flex justification for header layout
|
|
20219
|
+
* @returns {JSX.Element} The rendered header component
|
|
20220
|
+
*
|
|
20221
|
+
* @example
|
|
20222
|
+
* ```tsx
|
|
20223
|
+
* <ThumbnailList.Header>
|
|
20224
|
+
* <ThumbnailList.Header.SearchField />
|
|
20225
|
+
* <ThumbnailList.Header.Sort items={sortOptions} />
|
|
20226
|
+
* </ThumbnailList.Header>
|
|
20227
|
+
* ```
|
|
20228
|
+
*/
|
|
19323
20229
|
const ThumbnailListHeader = function (props) {
|
|
19324
20230
|
const startAlignedItems = [];
|
|
19325
20231
|
const endAlignedItems = [];
|
|
@@ -19335,17 +20241,34 @@ const ThumbnailListHeader = function (props) {
|
|
|
19335
20241
|
}
|
|
19336
20242
|
}
|
|
19337
20243
|
});
|
|
19338
|
-
return (
|
|
20244
|
+
return (jsxs(Stack$1, { direction: "row", alignItems: "center", justifyContent: props.justifyContent ?? 'space-between', gap: 2, children: [jsx(Stack$1, { direction: "row", alignItems: "center", gap: 2, justifyContent: "start", children: startAlignedItems }), endAlignedItems] }));
|
|
19339
20245
|
};
|
|
19340
|
-
ThumbnailListHeader.SearchField = ThumbnailListSearchField
|
|
20246
|
+
ThumbnailListHeader.SearchField = ThumbnailListSearchField;
|
|
19341
20247
|
ThumbnailListHeader.FilterTags = ThumbnailListFilterTags;
|
|
19342
20248
|
ThumbnailListHeader.Sort = ThumbnailListHeaderSort;
|
|
19343
20249
|
|
|
19344
20250
|
/**
|
|
19345
|
-
* Main
|
|
19346
|
-
*
|
|
19347
|
-
*
|
|
19348
|
-
*
|
|
20251
|
+
* Main ThumbnailList component that displays a list of items with thumbnails.
|
|
20252
|
+
* Provides context for child components and manages state for sorting, filtering, and searching.
|
|
20253
|
+
*
|
|
20254
|
+
* This component uses a compound component pattern with Header and MainContent sub-components.
|
|
20255
|
+
*
|
|
20256
|
+
* @template T - The type of items in the list (must extend ThumbnailListItemInterface)
|
|
20257
|
+
* @param {ThumbnailListProps<T>} props - Component props
|
|
20258
|
+
* @param {ReactNode} props.children - Child components (typically Header and MainContent)
|
|
20259
|
+
* @param {T[]} props.items - Array of items to display in the list
|
|
20260
|
+
* @param {ThumbnailListConfigurationInterface<T>} [props.config] - Optional configuration for sorting and filtering
|
|
20261
|
+
* @returns {JSX.Element} The rendered ThumbnailList component with context provider
|
|
20262
|
+
*
|
|
20263
|
+
* @example
|
|
20264
|
+
* ```tsx
|
|
20265
|
+
* <ThumbnailList items={items} config={{ sortBy: 'title', sortAscending: true }}>
|
|
20266
|
+
* <ThumbnailList.Header>
|
|
20267
|
+
* <ThumbnailList.Header.SearchField />
|
|
20268
|
+
* </ThumbnailList.Header>
|
|
20269
|
+
* <ThumbnailList.MainContent />
|
|
20270
|
+
* </ThumbnailList>
|
|
20271
|
+
* ```
|
|
19349
20272
|
*/
|
|
19350
20273
|
function ThumbnailList(props) {
|
|
19351
20274
|
const combinedConfig = {
|
|
@@ -19356,20 +20279,20 @@ function ThumbnailList(props) {
|
|
|
19356
20279
|
const { sortedItems, setSortBy, setSortAscending, sortAscending } = useSortedThumbnailListItems(listItems, combinedConfig.sortBy.toString(), combinedConfig.sortAscending);
|
|
19357
20280
|
const { tagFilteredItems, setTagAndCondition, tagAndCondition } = useTagFilteredThumbnailListItems({ allItems: sortedItems, initialTag: combinedConfig.tag.toString() });
|
|
19358
20281
|
const { setSearchTerm, filteredItems } = useFilteredThumbnailListItems(tagFilteredItems);
|
|
19359
|
-
return (jsx(
|
|
19360
|
-
|
|
19361
|
-
|
|
19362
|
-
|
|
19363
|
-
|
|
19364
|
-
|
|
19365
|
-
|
|
19366
|
-
|
|
19367
|
-
|
|
19368
|
-
|
|
19369
|
-
|
|
19370
|
-
|
|
19371
|
-
|
|
19372
|
-
|
|
20282
|
+
return (jsx(ThumbnailListItemContext.Provider, { value: {
|
|
20283
|
+
items: filteredItems,
|
|
20284
|
+
setItems: setListItems,
|
|
20285
|
+
originalItems: listItems,
|
|
20286
|
+
setOriginalItems: setListItems,
|
|
20287
|
+
tagFilterCallback: setTagAndCondition,
|
|
20288
|
+
tagAndCondition: tagAndCondition,
|
|
20289
|
+
setSearchTerm: setSearchTerm,
|
|
20290
|
+
setSortAscending: setSortAscending,
|
|
20291
|
+
sortAscending: sortAscending,
|
|
20292
|
+
setSortBy: setSortBy,
|
|
20293
|
+
sortBy: combinedConfig.sortBy.toString(),
|
|
20294
|
+
isLoading: combinedConfig.isLoading ?? false,
|
|
20295
|
+
}, children: jsx(Stack$1, { direction: "column", sx: { width: '100%', minWidth: '350px' }, children: props.children }) }));
|
|
19373
20296
|
}
|
|
19374
20297
|
ThumbnailList.MainContent = ThumbnailListMainContent;
|
|
19375
20298
|
ThumbnailList.Header = ThumbnailListHeader;
|