@ostack.tech/ui 0.3.4 → 0.4.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/ostack-ui.js +150 -116
- package/dist/ostack-ui.js.map +1 -1
- package/dist/types/components/FeedbackPopover/FeedbackPopover.d.ts +1 -1
- package/dist/types/index.d.ts +4 -1
- package/dist/types/utils/navigate.d.ts +16 -0
- package/dist/types/utils/useLocation.d.ts +30 -0
- package/dist/types/utils/useSearchParam.d.ts +26 -0
- package/dist/types/utils/useSearchParams.d.ts +20 -0
- package/package.json +1 -1
- package/dist/types/utils/locationUtils.d.ts +0 -85
package/dist/ostack-ui.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { forwardRef, createContext, useContext, useCallback, useRef, useEffect, useId, useMemo, useState, memo, isValidElement, cloneElement, Fragment, Children, useImperativeHandle, startTransition, useLayoutEffect as useLayoutEffect$1, createElement, useDeferredValue, useSyncExternalStore } from "react";
|
|
2
2
|
import { tinykeys } from "tinykeys";
|
|
3
|
-
import { shallow } from "zustand/shallow";
|
|
4
3
|
import fromExponential from "from-exponential";
|
|
5
4
|
import { isValid, isDate, addMonths, isAfter, isBefore, startOfMonth, setMonth, getYear, setYear, startOfYear, format, isSameYear, getMonth, max, min, lastDayOfMonth, parseISO, parse, isWithinInterval, isEqual } from "date-fns";
|
|
6
5
|
import { createStore, useStore, create } from "zustand";
|
|
6
|
+
import { shallow } from "zustand/shallow";
|
|
7
7
|
import { removeNumericFormat, numericFormatter, NumericFormat } from "react-number-format";
|
|
8
8
|
import { jsx, jsxs, Fragment as Fragment$1 } from "react/jsx-runtime";
|
|
9
9
|
import { faClose, faTriangleExclamation, faCircleExclamation, faCircleCheck, faCircleInfo, faChevronUp, faChevronDown, faRedo, faCircleQuestion, faSortDown, faSortUp, faAsterisk, faMinus, faCheck, faFilter, faArrowLeft, faArrowRight, faSearch, faChevronLeft, faChevronRight, faArrowUpRightFromSquare } from "@fortawesome/free-solid-svg-icons";
|
|
@@ -410,7 +410,7 @@ function useCreateDataTableContext({
|
|
|
410
410
|
onSelectedRowsChange,
|
|
411
411
|
disabledSelections
|
|
412
412
|
}) {
|
|
413
|
-
const
|
|
413
|
+
const listeners = useLatestValues({
|
|
414
414
|
onOffsetChange,
|
|
415
415
|
onLimitChange,
|
|
416
416
|
onSort,
|
|
@@ -499,11 +499,11 @@ function useCreateDataTableContext({
|
|
|
499
499
|
},
|
|
500
500
|
setOffset: (offset2) => {
|
|
501
501
|
set({ updateCounter: get().updateCounter + 1, _offset: offset2 });
|
|
502
|
-
|
|
502
|
+
listeners.onOffsetChange?.(offset2);
|
|
503
503
|
},
|
|
504
504
|
setLimit: (limit2) => {
|
|
505
505
|
set({ updateCounter: get().updateCounter + 1, limit: limit2 });
|
|
506
|
-
|
|
506
|
+
listeners.onLimitChange?.(limit2);
|
|
507
507
|
},
|
|
508
508
|
setFilter: (filter2) => {
|
|
509
509
|
if (get().offset() > 0) {
|
|
@@ -511,7 +511,7 @@ function useCreateDataTableContext({
|
|
|
511
511
|
}
|
|
512
512
|
set({ filter: filter2 });
|
|
513
513
|
get().actions.refresh(null);
|
|
514
|
-
|
|
514
|
+
listeners.onFilterChange?.(filter2);
|
|
515
515
|
},
|
|
516
516
|
setSort: (sortBy2, sortDirection2) => {
|
|
517
517
|
if (get().offset() > 0) {
|
|
@@ -519,7 +519,7 @@ function useCreateDataTableContext({
|
|
|
519
519
|
}
|
|
520
520
|
set({ sortBy: sortBy2, sortDirection: sortDirection2 });
|
|
521
521
|
get().actions.refresh();
|
|
522
|
-
|
|
522
|
+
listeners.onSort?.(sortBy2, sortDirection2);
|
|
523
523
|
},
|
|
524
524
|
selectRows: (keys) => {
|
|
525
525
|
const {
|
|
@@ -535,7 +535,7 @@ function useCreateDataTableContext({
|
|
|
535
535
|
}
|
|
536
536
|
if (selected) {
|
|
537
537
|
set({ selectedRows: [selectedRows2] });
|
|
538
|
-
|
|
538
|
+
listeners.onSelectedRowsChange?.(Array.from(selectedRows2).sort());
|
|
539
539
|
}
|
|
540
540
|
},
|
|
541
541
|
unselectRows: (keys) => {
|
|
@@ -551,7 +551,7 @@ function useCreateDataTableContext({
|
|
|
551
551
|
}
|
|
552
552
|
if (unselected) {
|
|
553
553
|
set({ selectedRows: [selectedRows2] });
|
|
554
|
-
|
|
554
|
+
listeners.onSelectedRowsChange?.(Array.from(selectedRows2).sort());
|
|
555
555
|
}
|
|
556
556
|
},
|
|
557
557
|
updateWindow: (offset2, limit2) => {
|
|
@@ -1180,14 +1180,31 @@ function unsetRef(ref, cleanupsRef) {
|
|
|
1180
1180
|
const LocalizationContext = createContext(null);
|
|
1181
1181
|
function useControllableState(initialValue, controlledValue) {
|
|
1182
1182
|
const [uncontrolledValue, setUncontrolledValue] = useState(initialValue);
|
|
1183
|
-
const
|
|
1183
|
+
const latest = useLatestValues({ controlledValue });
|
|
1184
1184
|
const setValue = useCallback(
|
|
1185
|
-
(nextValue) =>
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1185
|
+
(nextValue) => {
|
|
1186
|
+
const { controlledValue: controlledValue2 } = latest;
|
|
1187
|
+
if (controlledValue2 === void 0) {
|
|
1188
|
+
setUncontrolledValue(nextValue);
|
|
1189
|
+
} else if (typeof nextValue === "function") {
|
|
1190
|
+
setUncontrolledValue(
|
|
1191
|
+
nextValue(controlledValue2)
|
|
1192
|
+
);
|
|
1193
|
+
} else {
|
|
1194
|
+
setUncontrolledValue(controlledValue2);
|
|
1195
|
+
}
|
|
1196
|
+
},
|
|
1197
|
+
[latest]
|
|
1198
|
+
);
|
|
1199
|
+
return useMemo(
|
|
1200
|
+
() => [
|
|
1201
|
+
// See: https://github.com/typescript-eslint/typescript-eslint/issues/7842
|
|
1202
|
+
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
1203
|
+
controlledValue === void 0 ? uncontrolledValue : controlledValue,
|
|
1204
|
+
setValue
|
|
1205
|
+
],
|
|
1206
|
+
[controlledValue, setValue, uncontrolledValue]
|
|
1189
1207
|
);
|
|
1190
|
-
return [isControlled ? controlledValue : uncontrolledValue, setValue];
|
|
1191
1208
|
}
|
|
1192
1209
|
function LocalizationProvider({
|
|
1193
1210
|
defaultLocale,
|
|
@@ -10622,128 +10639,144 @@ function useKeyboardShortcut(keybinds, action, {
|
|
|
10622
10639
|
function ignoreFormControlsKeyboardShortcut(event) {
|
|
10623
10640
|
return event.target !== null && event.target instanceof HTMLElement && FORM_CONTROLS.includes(event.target.tagName);
|
|
10624
10641
|
}
|
|
10625
|
-
function
|
|
10626
|
-
|
|
10627
|
-
|
|
10628
|
-
|
|
10629
|
-
|
|
10630
|
-
|
|
10631
|
-
return useMemo(() => [location2, navigate], [location2]);
|
|
10642
|
+
function navigate(url, options) {
|
|
10643
|
+
history[options?.replace ? "replaceState" : "pushState"](
|
|
10644
|
+
options?.state,
|
|
10645
|
+
"",
|
|
10646
|
+
url
|
|
10647
|
+
);
|
|
10632
10648
|
}
|
|
10633
|
-
function
|
|
10634
|
-
|
|
10635
|
-
|
|
10636
|
-
|
|
10637
|
-
|
|
10638
|
-
const { pathname, search, hash } = latestValues.location;
|
|
10639
|
-
let newSearchParams = typeof nextSearchParams === "function" ? nextSearchParams(new URLSearchParams(search)) : nextSearchParams;
|
|
10640
|
-
if (!(newSearchParams instanceof URLSearchParams)) {
|
|
10641
|
-
newSearchParams = new URLSearchParams(newSearchParams);
|
|
10642
|
-
}
|
|
10643
|
-
navigate2(
|
|
10644
|
-
`${pathname}?${newSearchParams}${clearHash ? "" : hash}`,
|
|
10649
|
+
function useIntersectionObserver(element, onIntersectionEntryChange, options) {
|
|
10650
|
+
useEffect(() => {
|
|
10651
|
+
if (element !== null) {
|
|
10652
|
+
const observer = new IntersectionObserver(
|
|
10653
|
+
([e]) => onIntersectionEntryChange(e),
|
|
10645
10654
|
options
|
|
10646
10655
|
);
|
|
10647
|
-
|
|
10648
|
-
|
|
10649
|
-
|
|
10650
|
-
|
|
10651
|
-
() => [new URLSearchParams(location2.search), setSearchParams],
|
|
10652
|
-
[location2.search, setSearchParams]
|
|
10653
|
-
);
|
|
10654
|
-
}
|
|
10655
|
-
function useSearchParam(searchParam, defaultValue) {
|
|
10656
|
-
const [searchParams, setSearchParams] = useSearchParams();
|
|
10657
|
-
const searchParamValue = useMemo(
|
|
10658
|
-
() => searchParams.get(searchParam) ?? defaultValue,
|
|
10659
|
-
[defaultValue, searchParam, searchParams]
|
|
10660
|
-
);
|
|
10661
|
-
const setSearchParamValue = useCallback(
|
|
10662
|
-
(nextSearchParamValue, { clearDefaultValue, ...options } = {}) => {
|
|
10663
|
-
setSearchParams((prevSearchParams) => {
|
|
10664
|
-
const prevValue = prevSearchParams.get(searchParam) ?? defaultValue;
|
|
10665
|
-
const newValue = (typeof nextSearchParamValue === "function" ? nextSearchParamValue(prevValue) : nextSearchParamValue)?.toString();
|
|
10666
|
-
if (newValue == null || clearDefaultValue && newValue === defaultValue) {
|
|
10667
|
-
prevSearchParams.delete(searchParam);
|
|
10668
|
-
} else {
|
|
10669
|
-
prevSearchParams.set(searchParam, newValue);
|
|
10670
|
-
}
|
|
10671
|
-
return prevSearchParams;
|
|
10672
|
-
}, options);
|
|
10673
|
-
},
|
|
10674
|
-
[defaultValue, searchParam, setSearchParams]
|
|
10675
|
-
);
|
|
10676
|
-
return useMemo(
|
|
10677
|
-
() => [searchParamValue, setSearchParamValue],
|
|
10678
|
-
[searchParamValue, setSearchParamValue]
|
|
10679
|
-
);
|
|
10656
|
+
observer.observe(element);
|
|
10657
|
+
return () => observer.unobserve(element);
|
|
10658
|
+
}
|
|
10659
|
+
}, [element, onIntersectionEntryChange, options]);
|
|
10680
10660
|
}
|
|
10681
10661
|
const MONKEY_PATCHED_HISTORY = Symbol.for("ostack-ui.monkeyPatchedHistory");
|
|
10682
10662
|
const HISTORY_EVENT_TYPES = [
|
|
10683
10663
|
"popstate",
|
|
10684
10664
|
"hashchange",
|
|
10685
10665
|
// Events emitted by monkey-patched `pushState`/`replaceState` respectively
|
|
10686
|
-
"ostack-ui.
|
|
10687
|
-
"ostack-ui.
|
|
10666
|
+
"ostack-ui.pushState",
|
|
10667
|
+
"ostack-ui.replaceState"
|
|
10688
10668
|
];
|
|
10689
|
-
|
|
10690
|
-
function
|
|
10691
|
-
|
|
10692
|
-
|
|
10693
|
-
}
|
|
10669
|
+
let locationStore;
|
|
10670
|
+
function currentLocation() {
|
|
10671
|
+
const loc = window.location;
|
|
10672
|
+
return { pathname: loc.pathname, search: loc.search, hash: loc.hash };
|
|
10694
10673
|
}
|
|
10695
|
-
function
|
|
10696
|
-
|
|
10697
|
-
|
|
10698
|
-
|
|
10699
|
-
|
|
10700
|
-
|
|
10701
|
-
|
|
10702
|
-
|
|
10703
|
-
|
|
10704
|
-
|
|
10674
|
+
function createLocationStore() {
|
|
10675
|
+
return createStore((set, get) => ({
|
|
10676
|
+
location: currentLocation(),
|
|
10677
|
+
subscribers: 0,
|
|
10678
|
+
actions: {
|
|
10679
|
+
setCurrentLocation: () => {
|
|
10680
|
+
const newLocation = currentLocation();
|
|
10681
|
+
if (!shallow(get().location, newLocation)) {
|
|
10682
|
+
set({ location: newLocation });
|
|
10683
|
+
}
|
|
10684
|
+
},
|
|
10685
|
+
subscribe: () => {
|
|
10686
|
+
if (!globalThis[MONKEY_PATCHED_HISTORY]) {
|
|
10687
|
+
if (typeof history !== "undefined") {
|
|
10688
|
+
for (const fnName of ["pushState", "replaceState"]) {
|
|
10689
|
+
const evtName = `ostack-ui.${fnName}`;
|
|
10690
|
+
const originalFn = history[fnName];
|
|
10691
|
+
history[fnName] = function() {
|
|
10692
|
+
const result = originalFn.apply(this, arguments);
|
|
10693
|
+
dispatchEvent(new Event(evtName));
|
|
10694
|
+
return result;
|
|
10695
|
+
};
|
|
10696
|
+
}
|
|
10697
|
+
}
|
|
10698
|
+
globalThis[MONKEY_PATCHED_HISTORY] = true;
|
|
10699
|
+
}
|
|
10700
|
+
if (get().subscribers === 0) {
|
|
10701
|
+
get().actions.setCurrentLocation();
|
|
10702
|
+
for (const evtType of HISTORY_EVENT_TYPES) {
|
|
10703
|
+
addEventListener(evtType, get().actions.setCurrentLocation);
|
|
10704
|
+
}
|
|
10705
|
+
}
|
|
10706
|
+
set(({ subscribers }) => ({ subscribers: subscribers + 1 }));
|
|
10707
|
+
return () => {
|
|
10708
|
+
set(({ subscribers }) => ({ subscribers: subscribers - 1 }));
|
|
10709
|
+
if (get().subscribers === 0) {
|
|
10710
|
+
for (const evtType of HISTORY_EVENT_TYPES) {
|
|
10711
|
+
removeEventListener(evtType, get().actions.setCurrentLocation);
|
|
10712
|
+
}
|
|
10713
|
+
}
|
|
10705
10714
|
};
|
|
10706
10715
|
}
|
|
10707
10716
|
}
|
|
10708
|
-
|
|
10709
|
-
}
|
|
10710
|
-
if (listeners.size === 0) {
|
|
10711
|
-
for (const evtType of HISTORY_EVENT_TYPES) {
|
|
10712
|
-
addEventListener(evtType, handleHistoryEvent);
|
|
10713
|
-
}
|
|
10714
|
-
}
|
|
10715
|
-
listeners.add(listener);
|
|
10716
|
-
return () => {
|
|
10717
|
-
listeners.delete(listener);
|
|
10718
|
-
if (listeners.size === 0) {
|
|
10719
|
-
for (const evtType of HISTORY_EVENT_TYPES) {
|
|
10720
|
-
removeEventListener(evtType, handleHistoryEvent);
|
|
10721
|
-
}
|
|
10722
|
-
}
|
|
10723
|
-
};
|
|
10717
|
+
}));
|
|
10724
10718
|
}
|
|
10725
|
-
function
|
|
10726
|
-
|
|
10727
|
-
|
|
10719
|
+
function useLocation(selector) {
|
|
10720
|
+
locationStore ??= createLocationStore();
|
|
10721
|
+
useEffect(() => locationStore.getState().actions.subscribe(), []);
|
|
10722
|
+
return useStore(
|
|
10723
|
+
locationStore,
|
|
10724
|
+
({ location: location2 }) => selector ? selector(location2) : location2
|
|
10725
|
+
);
|
|
10728
10726
|
}
|
|
10729
|
-
function
|
|
10730
|
-
|
|
10731
|
-
|
|
10732
|
-
|
|
10733
|
-
|
|
10727
|
+
function useSearchParam(searchParam, defaultValue) {
|
|
10728
|
+
const searchParamValue = useLocation(
|
|
10729
|
+
(location2) => new URLSearchParams(location2.search).get(searchParam) ?? defaultValue
|
|
10730
|
+
);
|
|
10731
|
+
const latest = useLatestValues({ searchParam, defaultValue });
|
|
10732
|
+
const setSearchParamValue = useCallback(
|
|
10733
|
+
(nextSearchParamValue, { clearHash, clearDefaultValue, ...options } = {}) => {
|
|
10734
|
+
const { pathname, search, hash } = window.location;
|
|
10735
|
+
const { searchParam: searchParam2, defaultValue: defaultValue2 } = latest;
|
|
10736
|
+
const searchParams = new URLSearchParams(search);
|
|
10737
|
+
const prevValue = searchParams.get(searchParam2) ?? defaultValue2;
|
|
10738
|
+
const value = (typeof nextSearchParamValue === "function" ? nextSearchParamValue(prevValue) : nextSearchParamValue)?.toString();
|
|
10739
|
+
if (value == null || clearDefaultValue && value === defaultValue2) {
|
|
10740
|
+
searchParams.delete(searchParam2);
|
|
10741
|
+
} else {
|
|
10742
|
+
searchParams.set(searchParam2, value);
|
|
10743
|
+
}
|
|
10744
|
+
let searchParamsStr = searchParams.toString();
|
|
10745
|
+
searchParamsStr &&= `?${searchParamsStr}`;
|
|
10746
|
+
navigate(
|
|
10747
|
+
`${pathname}${searchParamsStr}${clearHash ? "" : hash}`,
|
|
10748
|
+
options
|
|
10749
|
+
);
|
|
10750
|
+
},
|
|
10751
|
+
[latest]
|
|
10752
|
+
);
|
|
10753
|
+
return useMemo(
|
|
10754
|
+
() => [searchParamValue, setSearchParamValue],
|
|
10755
|
+
[searchParamValue, setSearchParamValue]
|
|
10734
10756
|
);
|
|
10735
10757
|
}
|
|
10736
|
-
function
|
|
10737
|
-
|
|
10738
|
-
|
|
10739
|
-
|
|
10740
|
-
|
|
10758
|
+
function useSearchParams() {
|
|
10759
|
+
const locationSearch = useLocation((location2) => location2.search);
|
|
10760
|
+
const setSearchParams = useCallback(
|
|
10761
|
+
(nextSearchParams, { clearHash, ...options } = {}) => {
|
|
10762
|
+
const { pathname, search, hash } = window.location;
|
|
10763
|
+
let searchParams = typeof nextSearchParams === "function" ? nextSearchParams(new URLSearchParams(search)) : nextSearchParams;
|
|
10764
|
+
if (!(searchParams instanceof URLSearchParams)) {
|
|
10765
|
+
searchParams = new URLSearchParams(searchParams);
|
|
10766
|
+
}
|
|
10767
|
+
let searchParamsStr = searchParams.toString();
|
|
10768
|
+
searchParamsStr &&= `?${searchParamsStr}`;
|
|
10769
|
+
navigate(
|
|
10770
|
+
`${pathname}${searchParamsStr}${clearHash ? "" : hash}`,
|
|
10741
10771
|
options
|
|
10742
10772
|
);
|
|
10743
|
-
|
|
10744
|
-
|
|
10745
|
-
|
|
10746
|
-
|
|
10773
|
+
},
|
|
10774
|
+
[]
|
|
10775
|
+
);
|
|
10776
|
+
return useMemo(
|
|
10777
|
+
() => [new URLSearchParams(locationSearch), setSearchParams],
|
|
10778
|
+
[locationSearch, setSearchParams]
|
|
10779
|
+
);
|
|
10747
10780
|
}
|
|
10748
10781
|
export {
|
|
10749
10782
|
Alert,
|
|
@@ -10923,6 +10956,7 @@ export {
|
|
|
10923
10956
|
isNumericStringNegative,
|
|
10924
10957
|
matchAgainstFilter,
|
|
10925
10958
|
mergeAriaIds,
|
|
10959
|
+
navigate,
|
|
10926
10960
|
normalizeNumericString,
|
|
10927
10961
|
numericStringFloatToInt,
|
|
10928
10962
|
numericStringIntToFloat,
|