@up42/up-components 9.1.0 → 9.2.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/esm/index.js +268 -12
- package/dist/index.d.ts +40 -8
- package/package.json +6 -3
package/dist/esm/index.js
CHANGED
|
@@ -27,6 +27,7 @@ import MuiTablePagination$1 from '@mui/material/TablePagination';
|
|
|
27
27
|
import MuiTableSortLabel from '@mui/material/TableSortLabel';
|
|
28
28
|
import MuiTableFooter$1 from '@mui/material/TableFooter';
|
|
29
29
|
import { useSearchParams, useNavigate } from 'react-router';
|
|
30
|
+
import { isSchema } from 'yup';
|
|
30
31
|
|
|
31
32
|
var color$2 = {
|
|
32
33
|
gray0: "#FFFFFF",
|
|
@@ -6909,6 +6910,14 @@ const BasePopover = ({ open, onClose, anchorEl, header, children, footerInfo, pr
|
|
|
6909
6910
|
e.stopPropagation();
|
|
6910
6911
|
primaryButton?.onClick?.(e).then(handleClose);
|
|
6911
6912
|
};
|
|
6913
|
+
const handleSecondaryButtonClick = (e) => {
|
|
6914
|
+
e.stopPropagation();
|
|
6915
|
+
if (secondaryButton?.onClick) {
|
|
6916
|
+
void Promise.resolve(secondaryButton.onClick(e));
|
|
6917
|
+
return;
|
|
6918
|
+
}
|
|
6919
|
+
handleClose();
|
|
6920
|
+
};
|
|
6912
6921
|
const handleClose = () => {
|
|
6913
6922
|
onClose?.();
|
|
6914
6923
|
setPopoverAnchorEl(null);
|
|
@@ -6983,7 +6992,7 @@ const BasePopover = ({ open, onClose, anchorEl, header, children, footerInfo, pr
|
|
|
6983
6992
|
} },
|
|
6984
6993
|
footerInfo && footerInfo,
|
|
6985
6994
|
React__default.createElement(Box, { sx: { display: 'flex', gap: tokens.size.spacing.scale8, marginLeft: 'auto' } },
|
|
6986
|
-
secondaryButton && (React__default.createElement(Button, { variant: "outlined", size: "slim", ...secondaryButton, onClick:
|
|
6995
|
+
secondaryButton && (React__default.createElement(Button, { variant: "outlined", size: "slim", ...secondaryButton, onClick: handleSecondaryButtonClick }, secondaryButton.label)),
|
|
6987
6996
|
primaryButton && (React__default.createElement(Button, { variant: "contained", size: "slim", ...primaryButton, onClick: handlePrimaryButtonClick, ...(primaryButton.startIcon && { startIcon: React__default.createElement(Icon, { name: primaryButton.startIcon }) }) }, primaryButton.label)))))),
|
|
6988
6997
|
children))));
|
|
6989
6998
|
};
|
|
@@ -12049,22 +12058,39 @@ const DEFAULT_MARK_VALUES = [0, 2.5, 10, 30];
|
|
|
12049
12058
|
* Hook for GSD (Ground Sampling Distance) range slider with logarithmic scale.
|
|
12050
12059
|
* Handles conversion between linear slider values and logarithmic GSD values.
|
|
12051
12060
|
*/
|
|
12052
|
-
function useGsdSlider({ minValue, maxValue
|
|
12053
|
-
const
|
|
12054
|
-
|
|
12055
|
-
const
|
|
12056
|
-
const
|
|
12057
|
-
|
|
12058
|
-
|
|
12059
|
-
|
|
12061
|
+
function useGsdSlider({ minValue: minValueProp, maxValue: maxValueProp, markValues: markValuesProp = DEFAULT_MARK_VALUES, onChange, }) {
|
|
12062
|
+
const hasMarks = markValuesProp.length > 0;
|
|
12063
|
+
// If there are marks, use the prop mark values, otherwise use the default mark values
|
|
12064
|
+
const markValues = hasMarks ? markValuesProp : DEFAULT_MARK_VALUES;
|
|
12065
|
+
const minMarkValue = Math.min(...markValues);
|
|
12066
|
+
const maxMarkValue = Math.max(...markValues);
|
|
12067
|
+
// If there are marks, use the min and max mark values, otherwise use undefined
|
|
12068
|
+
const minGsd = hasMarks ? minMarkValue : undefined;
|
|
12069
|
+
const maxGsd = hasMarks ? maxMarkValue : undefined;
|
|
12070
|
+
// If the min or max value is not provided, use the min and max mark values
|
|
12071
|
+
const minSliderValue = minValueProp ?? minMarkValue;
|
|
12072
|
+
const maxSliderValue = maxValueProp ?? maxMarkValue;
|
|
12073
|
+
// Get the slider value from the min and max slider values
|
|
12074
|
+
const sliderValue = useMemo(() => [
|
|
12075
|
+
getSliderValueFromGsd(minSliderValue, minMarkValue, maxMarkValue),
|
|
12076
|
+
getSliderValueFromGsd(maxSliderValue, minMarkValue, maxMarkValue),
|
|
12077
|
+
], [minSliderValue, maxSliderValue, minMarkValue, maxMarkValue]);
|
|
12078
|
+
const marks = useMemo(() => {
|
|
12079
|
+
if (!hasMarks)
|
|
12080
|
+
return [];
|
|
12081
|
+
return markValuesProp.map((mark) => ({
|
|
12082
|
+
value: getSliderValueFromGsd(mark, minMarkValue, maxMarkValue),
|
|
12083
|
+
label: `${mark} m`,
|
|
12084
|
+
}));
|
|
12085
|
+
}, [hasMarks, markValuesProp, minMarkValue, maxMarkValue]);
|
|
12060
12086
|
const handleSliderChange = (_event, newValue) => {
|
|
12061
12087
|
if (newValue === undefined)
|
|
12062
12088
|
return;
|
|
12063
12089
|
const values = Array.isArray(newValue) ? newValue : [newValue, newValue];
|
|
12064
|
-
const [min, max] = values.map((v) => getGsdFromSliderValue(v,
|
|
12090
|
+
const [min, max] = values.map((v) => getGsdFromSliderValue(v, minMarkValue, maxMarkValue));
|
|
12065
12091
|
onChange(min, max);
|
|
12066
12092
|
};
|
|
12067
|
-
const scale = (n) => getGsdFromSliderValue(n,
|
|
12093
|
+
const scale = (n) => getGsdFromSliderValue(n, minMarkValue, maxMarkValue);
|
|
12068
12094
|
return {
|
|
12069
12095
|
sliderValue,
|
|
12070
12096
|
marks,
|
|
@@ -12195,4 +12221,234 @@ function useUrlParams(options = {}) {
|
|
|
12195
12221
|
};
|
|
12196
12222
|
}
|
|
12197
12223
|
|
|
12198
|
-
|
|
12224
|
+
/** Parse a comma-separated string into an array of strings. */
|
|
12225
|
+
function parseCommaSeparatedParam(value) {
|
|
12226
|
+
if (value === '') {
|
|
12227
|
+
return [];
|
|
12228
|
+
}
|
|
12229
|
+
const segments = value.split(',');
|
|
12230
|
+
const trimmedNonEmpty = segments.map((segment) => segment.trim()).filter(Boolean);
|
|
12231
|
+
return trimmedNonEmpty;
|
|
12232
|
+
}
|
|
12233
|
+
/** Get the default value for a Yup field. */
|
|
12234
|
+
function getDefaultValueForYupField(fieldDefinition) {
|
|
12235
|
+
const isYupSchema = isSchema(fieldDefinition);
|
|
12236
|
+
if (!isYupSchema) {
|
|
12237
|
+
return undefined;
|
|
12238
|
+
}
|
|
12239
|
+
const yupField = fieldDefinition;
|
|
12240
|
+
return yupField.getDefault();
|
|
12241
|
+
}
|
|
12242
|
+
/** Get the default values for a schema (`.default()` on each field). */
|
|
12243
|
+
function getDefaultValues(schema) {
|
|
12244
|
+
const objectSchema = schema;
|
|
12245
|
+
const { fields } = objectSchema;
|
|
12246
|
+
const defaultEntries = Object.keys(fields).map((fieldKey) => {
|
|
12247
|
+
const defaultForField = getDefaultValueForYupField(fields[fieldKey]);
|
|
12248
|
+
return [fieldKey, defaultForField];
|
|
12249
|
+
});
|
|
12250
|
+
const defaults = Object.fromEntries(defaultEntries);
|
|
12251
|
+
const castOptions = { stripUnknown: true };
|
|
12252
|
+
return schema.cast(defaults, castOptions);
|
|
12253
|
+
}
|
|
12254
|
+
/** Check if a field is an array and the value is a string. */
|
|
12255
|
+
function isArrayFieldWithStringFromUrl(fieldDefinition, paramValue) {
|
|
12256
|
+
const isYupSchema = isSchema(fieldDefinition);
|
|
12257
|
+
if (!isYupSchema || fieldDefinition.type !== 'array') {
|
|
12258
|
+
return false;
|
|
12259
|
+
}
|
|
12260
|
+
const valueIsString = typeof paramValue === 'string';
|
|
12261
|
+
return valueIsString;
|
|
12262
|
+
}
|
|
12263
|
+
/** Get the URL parameter name for a field. */
|
|
12264
|
+
function urlParamNameForField(fieldKey, urlKeyMap) {
|
|
12265
|
+
const mappedName = urlKeyMap?.[fieldKey];
|
|
12266
|
+
if (mappedName === undefined) {
|
|
12267
|
+
return fieldKey;
|
|
12268
|
+
}
|
|
12269
|
+
return mappedName;
|
|
12270
|
+
}
|
|
12271
|
+
/** Build a raw record of URL parameters from a schema and URL parameters. */
|
|
12272
|
+
function buildRawParamsFromUrl(schema, urlParams, urlKeyMap) {
|
|
12273
|
+
const objectSchema = schema;
|
|
12274
|
+
const { fields } = objectSchema;
|
|
12275
|
+
const presentFieldEntries = Object.keys(fields)
|
|
12276
|
+
.map((fieldKey) => {
|
|
12277
|
+
const searchParamKey = urlParamNameForField(fieldKey, urlKeyMap);
|
|
12278
|
+
const paramValue = urlParams[searchParamKey];
|
|
12279
|
+
if (paramValue === undefined) {
|
|
12280
|
+
return null;
|
|
12281
|
+
}
|
|
12282
|
+
const fieldDefinition = fields[fieldKey];
|
|
12283
|
+
const shouldSplitCommaSeparatedString = isArrayFieldWithStringFromUrl(fieldDefinition, paramValue);
|
|
12284
|
+
if (shouldSplitCommaSeparatedString) {
|
|
12285
|
+
const stringFromQuery = paramValue;
|
|
12286
|
+
const parsedList = parseCommaSeparatedParam(stringFromQuery);
|
|
12287
|
+
return [fieldKey, parsedList];
|
|
12288
|
+
}
|
|
12289
|
+
return [fieldKey, paramValue];
|
|
12290
|
+
})
|
|
12291
|
+
.filter((entry) => entry !== null);
|
|
12292
|
+
return Object.fromEntries(presentFieldEntries);
|
|
12293
|
+
}
|
|
12294
|
+
/** Validate a raw record of URL parameters against a schema. */
|
|
12295
|
+
function validateRawAgainstSchema(schema, raw) {
|
|
12296
|
+
const castOptions = { stripUnknown: true };
|
|
12297
|
+
try {
|
|
12298
|
+
const castedSchema = schema.cast(raw, castOptions);
|
|
12299
|
+
return schema.validateSync(castedSchema, castOptions);
|
|
12300
|
+
}
|
|
12301
|
+
catch {
|
|
12302
|
+
return null;
|
|
12303
|
+
}
|
|
12304
|
+
}
|
|
12305
|
+
/** Parse URL params into a validated filter object using the schema and optional URL key map. */
|
|
12306
|
+
function parseFromUrl(schema, urlParams, urlKeyMap) {
|
|
12307
|
+
const raw = buildRawParamsFromUrl(schema, urlParams, urlKeyMap);
|
|
12308
|
+
const validated = validateRawAgainstSchema(schema, raw);
|
|
12309
|
+
// If the validation failed, return the default values
|
|
12310
|
+
if (validated === null) {
|
|
12311
|
+
return getDefaultValues(schema);
|
|
12312
|
+
}
|
|
12313
|
+
return validated;
|
|
12314
|
+
}
|
|
12315
|
+
/** Check if two arrays of filter values are equal. */
|
|
12316
|
+
function arrayFilterValuesEqual(left, right) {
|
|
12317
|
+
const { length: leftLength } = left;
|
|
12318
|
+
const { length: rightLength } = right;
|
|
12319
|
+
if (leftLength !== rightLength) {
|
|
12320
|
+
return false;
|
|
12321
|
+
}
|
|
12322
|
+
return left.every((leftItem, index) => {
|
|
12323
|
+
const rightItem = right[index];
|
|
12324
|
+
return sameFilterValue(leftItem, rightItem);
|
|
12325
|
+
});
|
|
12326
|
+
}
|
|
12327
|
+
/** Check if two plain record of filter values are equal. */
|
|
12328
|
+
function plainRecordFilterValuesEqual(leftRecord, rightRecord) {
|
|
12329
|
+
const keySet = new Set([...Object.keys(leftRecord), ...Object.keys(rightRecord)]);
|
|
12330
|
+
const allKeys = [...keySet];
|
|
12331
|
+
return allKeys.every((key) => {
|
|
12332
|
+
const leftValue = leftRecord[key];
|
|
12333
|
+
const rightValue = rightRecord[key];
|
|
12334
|
+
return sameFilterValue(leftValue, rightValue);
|
|
12335
|
+
});
|
|
12336
|
+
}
|
|
12337
|
+
/** Deep value equality for filter field values (primitives, arrays, plain objects, Date). */
|
|
12338
|
+
function sameFilterValue(left, right) {
|
|
12339
|
+
// Check if the values are the same object
|
|
12340
|
+
if (Object.is(left, right)) {
|
|
12341
|
+
return true;
|
|
12342
|
+
}
|
|
12343
|
+
// Check if the values are null or undefined
|
|
12344
|
+
const leftIsNullish = left == null;
|
|
12345
|
+
const rightIsNullish = right == null;
|
|
12346
|
+
if (leftIsNullish || rightIsNullish) {
|
|
12347
|
+
const bothNullish = leftIsNullish && rightIsNullish;
|
|
12348
|
+
return bothNullish;
|
|
12349
|
+
}
|
|
12350
|
+
// Check if the values are arrays
|
|
12351
|
+
const leftIsArray = Array.isArray(left);
|
|
12352
|
+
const rightIsArray = Array.isArray(right);
|
|
12353
|
+
const bothAreArrays = leftIsArray && rightIsArray;
|
|
12354
|
+
if (bothAreArrays) {
|
|
12355
|
+
return arrayFilterValuesEqual(left, right);
|
|
12356
|
+
}
|
|
12357
|
+
// Check if the values are dates
|
|
12358
|
+
const leftIsDate = left instanceof Date;
|
|
12359
|
+
const rightIsDate = right instanceof Date;
|
|
12360
|
+
const bothAreDates = leftIsDate && rightIsDate;
|
|
12361
|
+
if (bothAreDates) {
|
|
12362
|
+
const leftTime = left.getTime();
|
|
12363
|
+
const rightTime = right.getTime();
|
|
12364
|
+
return leftTime === rightTime;
|
|
12365
|
+
}
|
|
12366
|
+
// Check if the values are objects
|
|
12367
|
+
const leftIsObject = typeof left === 'object';
|
|
12368
|
+
const rightIsObject = typeof right === 'object';
|
|
12369
|
+
const bothAreObjects = leftIsObject && rightIsObject;
|
|
12370
|
+
if (!bothAreObjects) {
|
|
12371
|
+
return false;
|
|
12372
|
+
}
|
|
12373
|
+
// Check if the values are plain records
|
|
12374
|
+
const leftRecord = left;
|
|
12375
|
+
const rightRecord = right;
|
|
12376
|
+
return plainRecordFilterValuesEqual(leftRecord, rightRecord);
|
|
12377
|
+
}
|
|
12378
|
+
/**
|
|
12379
|
+
* True when `draft` and `applied` match on every key in `schema`.
|
|
12380
|
+
* Unrelated URL search params do not appear on these snapshots, so this stays accurate when other code adds params.
|
|
12381
|
+
*/
|
|
12382
|
+
function areFilterSnapshotsEqual(schema, draft, applied) {
|
|
12383
|
+
const objectSchema = schema;
|
|
12384
|
+
const { fields } = objectSchema;
|
|
12385
|
+
const schemaFieldKeys = Object.keys(fields);
|
|
12386
|
+
return schemaFieldKeys.every((fieldKey) => {
|
|
12387
|
+
const filterKey = fieldKey;
|
|
12388
|
+
const draftValue = draft[filterKey];
|
|
12389
|
+
const appliedValue = applied[filterKey];
|
|
12390
|
+
return sameFilterValue(draftValue, appliedValue);
|
|
12391
|
+
});
|
|
12392
|
+
}
|
|
12393
|
+
|
|
12394
|
+
/**
|
|
12395
|
+
* Draft vs applied filter state: the UI edits `filters` (draft); `apply` writes to the URL via {@link useUrlParams}.
|
|
12396
|
+
* Applied filters are always derived from the current search string and validated with Yup.
|
|
12397
|
+
*
|
|
12398
|
+
* When the query string changes, the draft syncs from the URL only if **schema-defined** filter values changed.
|
|
12399
|
+
* Extra params from other features do not reset the draft or affect **`isDirty`** by themselves.
|
|
12400
|
+
*/
|
|
12401
|
+
function useFilterState(schema, options = {}) {
|
|
12402
|
+
const { urlKeyMap } = options;
|
|
12403
|
+
const { setParams, stringParams } = useUrlParams();
|
|
12404
|
+
const defaults = useMemo(() => getDefaultValues(schema), [schema]);
|
|
12405
|
+
const appliedFilters = useMemo(() => {
|
|
12406
|
+
const raw = searchParamsToObject(new URLSearchParams(stringParams));
|
|
12407
|
+
return parseFromUrl(schema, raw, urlKeyMap);
|
|
12408
|
+
}, [schema, stringParams, urlKeyMap]);
|
|
12409
|
+
const [draft, setDraft] = useState(() => parseFromUrl(schema, searchParamsToObject(new URLSearchParams(stringParams)), urlKeyMap));
|
|
12410
|
+
const draftRef = useRef(draft);
|
|
12411
|
+
draftRef.current = draft;
|
|
12412
|
+
const prevAppliedRef = useRef(null);
|
|
12413
|
+
useEffect(() => {
|
|
12414
|
+
const prevApplied = prevAppliedRef.current;
|
|
12415
|
+
if (prevApplied !== null && areFilterSnapshotsEqual(schema, prevApplied, appliedFilters)) {
|
|
12416
|
+
prevAppliedRef.current = appliedFilters;
|
|
12417
|
+
return;
|
|
12418
|
+
}
|
|
12419
|
+
prevAppliedRef.current = appliedFilters;
|
|
12420
|
+
draftRef.current = appliedFilters;
|
|
12421
|
+
setDraft(appliedFilters);
|
|
12422
|
+
}, [appliedFilters, schema]);
|
|
12423
|
+
const setFilter = useCallback((key, value) => {
|
|
12424
|
+
const next = { ...draftRef.current, [key]: value };
|
|
12425
|
+
draftRef.current = next;
|
|
12426
|
+
setDraft(next);
|
|
12427
|
+
}, []);
|
|
12428
|
+
const apply = useCallback(() => {
|
|
12429
|
+
const rawParams = searchParamsToObject(new URLSearchParams(stringParams));
|
|
12430
|
+
const nextParams = { ...rawParams };
|
|
12431
|
+
Object.keys(schema.fields).map((fieldKey) => {
|
|
12432
|
+
const mappedUrlKey = urlKeyMap?.[fieldKey];
|
|
12433
|
+
const urlKey = mappedUrlKey ?? fieldKey;
|
|
12434
|
+
const fieldValue = draftRef.current[fieldKey];
|
|
12435
|
+
nextParams[urlKey] = fieldValue;
|
|
12436
|
+
});
|
|
12437
|
+
setParams(nextParams);
|
|
12438
|
+
}, [schema, setParams, stringParams, urlKeyMap]);
|
|
12439
|
+
const reset = useCallback(() => {
|
|
12440
|
+
draftRef.current = defaults;
|
|
12441
|
+
setDraft(defaults);
|
|
12442
|
+
}, [defaults]);
|
|
12443
|
+
const isDirty = useMemo(() => !areFilterSnapshotsEqual(schema, draft, appliedFilters), [schema, draft, appliedFilters]);
|
|
12444
|
+
return {
|
|
12445
|
+
filters: draft,
|
|
12446
|
+
setFilter,
|
|
12447
|
+
apply,
|
|
12448
|
+
reset,
|
|
12449
|
+
isDirty,
|
|
12450
|
+
defaults,
|
|
12451
|
+
};
|
|
12452
|
+
}
|
|
12453
|
+
|
|
12454
|
+
export { ActionToolbar, Alert, Avatar, Badge, Banner, Button, Checkbox, CodeBlock, CodeInline, CodeSnippet, ContactBox, ControlButton, CopyButton, DataGrid, DateTime, Divider, DocumentationPopover, EditTagsButton, EmptyState, FeatureCard, FeatureCardHeader, FeatureCardHeaderActions, FeatureFlagCheckbox, FilterPopover, FindUsersButton, FormAutocomplete, FormCheckbox, FormDatePicker, FormDateRangePicker, FormDateRangePickerList, FormDateTimePicker, FormInput, FormRadio, FormSelect, FormSlider, FormSwitch, GridContainer, GridItem, Icon, Illustration, InfoCard, InfoModal, InfoPopover, Input, LearnMoreButton, Link, Loading, Logo, NotFound, PageContainer, PageHeader, PageHeaderV2, Popover, Radio, RoleBanner, Select, Slider, StatusLight, Switch, Tab, TabGroup, Table, TableBody, TableCell, TableContainer, TableFooter, TableHead, TablePagination, TableRow, TableSortLabel, Tabs, Tag, TagsList, ToggleButton, Typography, UpComponentsProvider, analytics, areFilterSnapshotsEqual, capitalize, copyToClipboard, formatDate, formatFileSize, formatNumber, generateQueryKey, objectToSearchParams, searchParamsToObject, theme, tokens, useAlert, useCursorPagination, useDebounce, useFilterState, useGsdSlider, useQueryParams, useRemotePagination, useToggle, useUrlParams, valueToString };
|
package/dist/index.d.ts
CHANGED
|
@@ -23,6 +23,7 @@ import { TableFooterProps as TableFooterProps$1 } from '@mui/material/TableFoote
|
|
|
23
23
|
import { DataGridPremiumProps } from '@mui/x-data-grid-premium';
|
|
24
24
|
export { GRID_DETAIL_PANEL_TOGGLE_COL_DEF, GRID_DETAIL_PANEL_TOGGLE_FIELD, GridCell, GridCellModes, GridCellModesModel, GridCellParams, GridColDef, GridColumnHeaderParams, GridEditCellProps, GridEditInputCell, GridFooter, GridInitialState, GridLoadingOverlay, GridNoRowsOverlay, GridPagination, GridPreProcessEditCellProps, GridRenderCellParams, GridRenderEditCellParams, GridRow, GridRowCount, GridRowId, GridRowParams, GridRowSelectionModel, GridRowsProp, GridSelectedRowCount, GridSortModel, GridTreeNodeWithRender, gridColumnDefinitionsSelector, gridColumnVisibilityModelSelector, gridDetailPanelExpandedRowIdsSelector, gridDetailPanelExpandedRowsContentCacheSelector, gridRowsLookupSelector, useGridApiContext, useGridApiRef, useGridSelector } from '@mui/x-data-grid-premium';
|
|
25
25
|
import { ToggleButtonProps as ToggleButtonProps$1 } from '@mui/material/ToggleButton';
|
|
26
|
+
import { AnyObjectSchema, InferType } from 'yup';
|
|
26
27
|
|
|
27
28
|
interface UpComponentsProviderProps extends Omit<ThemeProviderProps, 'theme'> {
|
|
28
29
|
licenseKey: string;
|
|
@@ -4696,7 +4697,8 @@ type PopoverProps = Omit<PopoverProps$1, 'content' | 'open' | 'onClose'> & {
|
|
|
4696
4697
|
*/
|
|
4697
4698
|
primaryButton?: PopoverButtonProps;
|
|
4698
4699
|
/**
|
|
4699
|
-
* Secondary button props (optional)
|
|
4700
|
+
* Secondary button props (optional).
|
|
4701
|
+
* If `onClick` is omitted, clicking the button only closes the popover. If `onClick` is set, it runs and the popover stays open unless you call `onClose`.
|
|
4700
4702
|
*/
|
|
4701
4703
|
secondaryButton?: PopoverButtonProps;
|
|
4702
4704
|
/**
|
|
@@ -11826,18 +11828,21 @@ declare const useDebounce: <T>(value: T, delay?: number) => T;
|
|
|
11826
11828
|
type UseGsdSliderProps = {
|
|
11827
11829
|
/**
|
|
11828
11830
|
* Minimum GSD value (meters). Controlled by parent.
|
|
11831
|
+
* When omitted, the range thumb uses the axis minimum (lowest mark used for the logarithm).
|
|
11829
11832
|
*/
|
|
11830
|
-
minValue
|
|
11833
|
+
minValue?: number;
|
|
11831
11834
|
/**
|
|
11832
11835
|
* Maximum GSD value (meters). Controlled by parent.
|
|
11836
|
+
* When omitted, the range thumb uses the axis maximum (highest mark used for the logarithm).
|
|
11833
11837
|
*/
|
|
11834
|
-
maxValue
|
|
11838
|
+
maxValue?: number;
|
|
11835
11839
|
/**
|
|
11836
11840
|
* Callback when the range changes.
|
|
11837
11841
|
*/
|
|
11838
11842
|
onChange: (minValue: number, maxValue: number) => void;
|
|
11839
11843
|
/**
|
|
11840
11844
|
* GSD values for the slider marks.
|
|
11845
|
+
* Pass an empty array if you want no marks and `minGsd` / `maxGsd` returned as `undefined` (axis still uses the default scale internally).
|
|
11841
11846
|
* @default [0, 2.5, 10, 30]
|
|
11842
11847
|
*/
|
|
11843
11848
|
markValues?: number[];
|
|
@@ -11846,7 +11851,7 @@ type UseGsdSliderProps = {
|
|
|
11846
11851
|
* Hook for GSD (Ground Sampling Distance) range slider with logarithmic scale.
|
|
11847
11852
|
* Handles conversion between linear slider values and logarithmic GSD values.
|
|
11848
11853
|
*/
|
|
11849
|
-
declare function useGsdSlider({ minValue, maxValue, onChange,
|
|
11854
|
+
declare function useGsdSlider({ minValue: minValueProp, maxValue: maxValueProp, markValues: markValuesProp, onChange, }: UseGsdSliderProps): {
|
|
11850
11855
|
sliderValue: [number, number];
|
|
11851
11856
|
marks: {
|
|
11852
11857
|
value: number;
|
|
@@ -11854,8 +11859,8 @@ declare function useGsdSlider({ minValue, maxValue, onChange, markValues }: UseG
|
|
|
11854
11859
|
}[];
|
|
11855
11860
|
handleSliderChange: (_event: unknown, newValue?: number | number[]) => void;
|
|
11856
11861
|
scale: (n: number) => number;
|
|
11857
|
-
minGsd: number;
|
|
11858
|
-
maxGsd: number;
|
|
11862
|
+
minGsd: number | undefined;
|
|
11863
|
+
maxGsd: number | undefined;
|
|
11859
11864
|
};
|
|
11860
11865
|
|
|
11861
11866
|
type CreateAlertProps = {
|
|
@@ -11963,5 +11968,32 @@ declare function valueToString(value: unknown): string;
|
|
|
11963
11968
|
*/
|
|
11964
11969
|
declare function objectToSearchParams<T extends ParamsObject = ParamsObject>(object: T): string;
|
|
11965
11970
|
|
|
11966
|
-
|
|
11967
|
-
|
|
11971
|
+
/** Maps internal filter keys to URL search-param names. */
|
|
11972
|
+
type UrlKeyMap<FilterSchema extends AnyObjectSchema> = Partial<Record<keyof InferType<FilterSchema>, string>>;
|
|
11973
|
+
/**
|
|
11974
|
+
* True when `draft` and `applied` match on every key in `schema`.
|
|
11975
|
+
* Unrelated URL search params do not appear on these snapshots, so this stays accurate when other code adds params.
|
|
11976
|
+
*/
|
|
11977
|
+
declare function areFilterSnapshotsEqual<FilterSchema extends AnyObjectSchema>(schema: FilterSchema, draft: InferType<FilterSchema>, applied: InferType<FilterSchema>): boolean;
|
|
11978
|
+
|
|
11979
|
+
type UseFilterStateOptions<FilterSchema extends AnyObjectSchema> = {
|
|
11980
|
+
urlKeyMap?: UrlKeyMap<FilterSchema>;
|
|
11981
|
+
};
|
|
11982
|
+
/**
|
|
11983
|
+
* Draft vs applied filter state: the UI edits `filters` (draft); `apply` writes to the URL via {@link useUrlParams}.
|
|
11984
|
+
* Applied filters are always derived from the current search string and validated with Yup.
|
|
11985
|
+
*
|
|
11986
|
+
* When the query string changes, the draft syncs from the URL only if **schema-defined** filter values changed.
|
|
11987
|
+
* Extra params from other features do not reset the draft or affect **`isDirty`** by themselves.
|
|
11988
|
+
*/
|
|
11989
|
+
declare function useFilterState<FilterSchema extends AnyObjectSchema>(schema: FilterSchema, options?: UseFilterStateOptions<FilterSchema>): {
|
|
11990
|
+
readonly filters: InferType<FilterSchema>;
|
|
11991
|
+
readonly setFilter: <K extends keyof InferType<FilterSchema>>(key: K, value: InferType<FilterSchema>[K]) => void;
|
|
11992
|
+
readonly apply: () => void;
|
|
11993
|
+
readonly reset: () => void;
|
|
11994
|
+
readonly isDirty: boolean;
|
|
11995
|
+
readonly defaults: InferType<FilterSchema>;
|
|
11996
|
+
};
|
|
11997
|
+
|
|
11998
|
+
export { ActionToolbar, Alert, Avatar, Badge, Banner, Button, Checkbox, CodeBlock, CodeInline, CodeSnippet, ContactBox, ControlButton, CopyButton, DataGrid, DateTime, Divider, DocumentationPopover, EditTagsButton, EmptyState, FeatureCard, FeatureCardHeader, FeatureCardHeaderActions, FeatureFlagCheckbox, FilterPopover, FindUsersButton, FormAutocomplete, FormCheckbox, FormDatePicker, FormDateRangePicker, FormDateRangePickerList, FormDateTimePicker, FormInput, FormRadio, FormSelect, FormSlider, FormSwitch, GridContainer, GridItem, Icon, Illustration, InfoCard, InfoModal, InfoPopover, Input, LearnMoreButton, Link, Loading, Logo, NotFound, PageContainer, PageHeader, PageHeaderV2, Popover, Radio, RoleBanner, Select, Slider, StatusLight, Switch, Tab, TabGroup, Table, TableBody, TableCell, TableContainer, TableFooter, TableHead, TablePagination, TableRow, TableSortLabel, Tabs, Tag, TagsList, ToggleButton, Typography, UpComponentsProvider, analytics, areFilterSnapshotsEqual, capitalize, copyToClipboard, formatDate, formatFileSize, formatNumber, generateQueryKey, objectToSearchParams, searchParamsToObject, theme, useAlert, useCursorPagination, useDebounce, useFilterState, useGsdSlider, useQueryParams, useRemotePagination, useToggle, useUrlParams, valueToString };
|
|
11999
|
+
export type { ActionToolbarProps, AlertProps, AnalyticsConfig, AvatarProps, BadgeProps, BannerProps, ButtonProps, CheckboxProps, CodeBlockProps, CodeInlineProps, CodeSnippetItemProps, CodeSnippetProps, ContactBoxProps, ControlButtonProps, CopyButtonProps, CreateAlertProps, CreateSnackbarProps, CursorPaginatedResponse, DateRange, DateTimeProps, DividerProps, DocumentationPopoverProps, EditTagsButtonProps, EmptyStateProps, FeatureCardHeaderActionsProps, FeatureCardHeaderProps, FeatureCardProps, FeatureFlagCheckboxProps, FilterPopoverProps, FindUsersButtonProps, FormAutocompleteMapper, FormAutocompleteProps, FormCheckboxProps, FormDatePickerDateType, FormDatePickerProps, FormDateRangePickerListProps, FormDateRangePickerProps, FormDateTimePickerProps, FormInputProps, FormRadioProps, FormSelectProps, FormSliderProps, FormSwitchProps, GridContainerProps, GridItemProps, IconAction, IconProps$1 as IconProps, IllustrationProps, InfoCardProps, InfoModalProps, InfoPopoverProps, InputProps, LearnMoreButtonProps, LinkProps, LoadingProps, LogoProps, MenuAction, NotFoundProps, PageContainerProps, PageHeaderProps, PageHeaderV2Props, PaginatedResponse, ParamsObject, PopoverProps, RadioProps, RemoveParamRules, RoleBannerProps, SearchParamObject, SelectProps, SliderProps$1 as SliderProps, StatusLightProps, SwitchProps, TabGroupProps, TabProps, TableBodyProps, TableCellProps, TableContainerProps, TableFooterProps, TableHeadProps, TablePaginationProps, TableProps, TableRowProps, TableSortLabelProps, TabsProps, TagItem, TagProps, TagsListProps, ToggleButtonProps, TypographyProps, UrlKeyMap, UseFilterStateOptions, UseGsdSliderProps, UseToggleResult };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@up42/up-components",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.2.0",
|
|
4
4
|
"description": "UP42 Component Library",
|
|
5
5
|
"author": "Axel Fuhrmann axel.fuhrmann@up42.com",
|
|
6
6
|
"license": "ISC",
|
|
@@ -81,6 +81,7 @@
|
|
|
81
81
|
"lint-staged": "^12.3.1",
|
|
82
82
|
"prettier": "^2.5.1",
|
|
83
83
|
"react": "^18.3.1",
|
|
84
|
+
"remark-gfm": "^4.0.1",
|
|
84
85
|
"rimraf": "^6.1.2",
|
|
85
86
|
"rollup": "^4.59.0",
|
|
86
87
|
"rollup-plugin-dts": "^6.1.0",
|
|
@@ -90,7 +91,8 @@
|
|
|
90
91
|
"typescript": "^4.5.4",
|
|
91
92
|
"vite": "^7.1.12",
|
|
92
93
|
"vite-plugin-svgr": "^4.2.0",
|
|
93
|
-
"vitest": "^3.2.4"
|
|
94
|
+
"vitest": "^3.2.4",
|
|
95
|
+
"yup": "^0.32.9"
|
|
94
96
|
},
|
|
95
97
|
"peerDependencies": {
|
|
96
98
|
"@emotion/react": "^11.7.1",
|
|
@@ -101,7 +103,8 @@
|
|
|
101
103
|
"dayjs": "^1.11.7",
|
|
102
104
|
"react": "^18.3.1",
|
|
103
105
|
"react-dom": "^18.3.1",
|
|
104
|
-
"react-router": "^7.12.0"
|
|
106
|
+
"react-router": "^7.12.0",
|
|
107
|
+
"yup": "^0.32.9"
|
|
105
108
|
},
|
|
106
109
|
"lint-staged": {
|
|
107
110
|
"*.{js,tsx,ts}": "eslint --cache --fix",
|