@algorithm-shift/design-system 1.2.969 → 1.2.971

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.mjs CHANGED
@@ -27792,14 +27792,46 @@ function useLazyDropdown(config) {
27792
27792
  };
27793
27793
  });
27794
27794
  }, []);
27795
+ function extractAndEnforceUrlParams(apiUrl, enforceStrict) {
27796
+ const urlObj = new URL(
27797
+ apiUrl,
27798
+ typeof window !== "undefined" ? window.location.origin : "http://localhost"
27799
+ );
27800
+ const cleaned = {};
27801
+ let hasEmpty = false;
27802
+ const baseUrl = urlObj.origin + urlObj.pathname;
27803
+ urlObj.searchParams.forEach((value, key) => {
27804
+ const isEmpty = value === "" || value === void 0 || value === null;
27805
+ if (isEmpty) {
27806
+ hasEmpty = true;
27807
+ if (enforceStrict) return;
27808
+ return;
27809
+ }
27810
+ cleaned[key] = value;
27811
+ });
27812
+ return {
27813
+ baseUrl,
27814
+ shouldAbort: enforceStrict && hasEmpty,
27815
+ params: cleaned
27816
+ };
27817
+ }
27795
27818
  const fetchApiData = useCallback2(async (pageNum, term) => {
27796
27819
  if (!configRef.current.apiUrl) return [];
27797
27820
  const limit = PAGE_SIZE;
27798
27821
  const params = { page: pageNum, limit };
27799
27822
  if (term) params[configRef.current.dataLabel ? `${configRef.current.dataLabel}[ilike]` : "search[ilike]"] = term;
27823
+ const { baseUrl, shouldAbort, params: urlParams } = extractAndEnforceUrlParams(
27824
+ configRef.current.apiUrl,
27825
+ configRef.current.enforceStrictQueryParams ?? false
27826
+ );
27827
+ if (shouldAbort) {
27828
+ setLoading(false);
27829
+ return [];
27830
+ }
27831
+ const finalParams = { ...urlParams, ...params };
27800
27832
  const axiosClient = configRef.current.axiosInstance ?? axios;
27801
- const res = await axiosClient.get(configRef.current.apiUrl, {
27802
- params,
27833
+ const res = await axiosClient.get(baseUrl, {
27834
+ params: finalParams,
27803
27835
  withCredentials: true
27804
27836
  });
27805
27837
  if (res.data?.success && Array.isArray(res.data.data)) {
@@ -27862,8 +27894,17 @@ function useLazyDropdown(config) {
27862
27894
  [`${configRef.current.dataKey}[in]`]: configRef.current.value.join(",")
27863
27895
  };
27864
27896
  }
27865
- const res = await axiosClient.get(configRef.current.apiUrl, {
27866
- params,
27897
+ const { baseUrl, shouldAbort, params: urlParams } = extractAndEnforceUrlParams(
27898
+ configRef.current.apiUrl,
27899
+ configRef.current.enforceStrictQueryParams ?? false
27900
+ );
27901
+ if (shouldAbort) {
27902
+ setLoading(false);
27903
+ return;
27904
+ }
27905
+ const finalParams = { ...urlParams, ...params };
27906
+ const res = await axiosClient.get(baseUrl, {
27907
+ params: finalParams,
27867
27908
  withCredentials: true
27868
27909
  });
27869
27910
  if (res.data?.success && Array.isArray(res.data.data) && res.data.data.length > 0) {
@@ -27916,6 +27957,32 @@ function useLazyDropdown(config) {
27916
27957
  if (debounceTimer.current) clearTimeout(debounceTimer.current);
27917
27958
  };
27918
27959
  }, []);
27960
+ const createNewOption = async (label) => {
27961
+ if (!configRef.current.apiUrl) return null;
27962
+ const axiosClient = configRef.current.axiosInstance ?? axios;
27963
+ const apiUrl = configRef.current.apiUrl;
27964
+ const urlObj = new URL(
27965
+ apiUrl,
27966
+ typeof window !== "undefined" ? window.location.origin : "http://localhost"
27967
+ );
27968
+ const queryParams = {};
27969
+ urlObj.searchParams.forEach((value, key) => {
27970
+ queryParams[key] = value;
27971
+ });
27972
+ const body = {
27973
+ ...queryParams,
27974
+ [configRef.current.dataLabel]: label
27975
+ };
27976
+ const res = await axiosClient.post(urlObj.origin + urlObj.pathname, body, {
27977
+ withCredentials: true
27978
+ });
27979
+ if (res.data?.success && Array.isArray(res.data.data) && res.data.data.length > 0) {
27980
+ const fetched = transformToOptions(res.data.data);
27981
+ setOptions((prev) => uniqueOptions([...fetched, ...prev]));
27982
+ return fetched[0];
27983
+ }
27984
+ return null;
27985
+ };
27919
27986
  return {
27920
27987
  options,
27921
27988
  loading,
@@ -27923,7 +27990,8 @@ function useLazyDropdown(config) {
27923
27990
  loadMore,
27924
27991
  search,
27925
27992
  reset,
27926
- loadPage
27993
+ loadPage,
27994
+ createNewOption
27927
27995
  };
27928
27996
  }
27929
27997
 
@@ -27944,7 +28012,8 @@ function LazySelectDropdown({
27944
28012
  dataKey = "id",
27945
28013
  dataLabel = "name",
27946
28014
  errorMessage,
27947
- axiosInstance
28015
+ axiosInstance,
28016
+ enableAddNewOption = false
27948
28017
  }) {
27949
28018
  const [isOpen, setIsOpen] = useState5(false);
27950
28019
  const [searchTerm, setSearchTerm] = useState5("");
@@ -27957,7 +28026,8 @@ function LazySelectDropdown({
27957
28026
  loadMore,
27958
28027
  search,
27959
28028
  reset,
27960
- loadPage
28029
+ loadPage,
28030
+ createNewOption
27961
28031
  } = useLazyDropdown({
27962
28032
  enabled: true,
27963
28033
  dataSource: source || "",
@@ -28015,6 +28085,15 @@ function LazySelectDropdown({
28015
28085
  reset();
28016
28086
  search("");
28017
28087
  };
28088
+ const handleAddNewOption = async (newOption) => {
28089
+ const option = await createNewOption(newOption);
28090
+ if (option) {
28091
+ onChange?.(option.value, id || "");
28092
+ setIsOpen(false);
28093
+ setSearchTerm("");
28094
+ reset();
28095
+ }
28096
+ };
28018
28097
  return /* @__PURE__ */ jsxs18("div", { ref: dropdownRef, className: "relative w-full", children: [
28019
28098
  /* @__PURE__ */ jsx36(
28020
28099
  "input",
@@ -28084,7 +28163,19 @@ function LazySelectDropdown({
28084
28163
  ] }) : "Scroll for more..."
28085
28164
  }
28086
28165
  )
28087
- ] }) : /* @__PURE__ */ jsx36("div", { className: "px-3 py-4 text-sm text-center text-gray-500", children: searchTerm ? `No results for "${searchTerm}"` : "No options available" })
28166
+ ] }) : /* @__PURE__ */ jsxs18("div", { className: "px-3 py-4 text-sm text-center text-gray-500", children: [
28167
+ searchTerm ? `No results for "${searchTerm}"` : "No options available",
28168
+ enableAddNewOption && searchTerm && /* @__PURE__ */ jsx36(
28169
+ "div",
28170
+ {
28171
+ onClick: () => {
28172
+ handleAddNewOption(searchTerm);
28173
+ },
28174
+ className: "mt-2 px-3 py-2 bg-green-50 hover:bg-green-100 cursor-pointer text-green-700 rounded text-sm",
28175
+ children: `Add "${searchTerm}"`
28176
+ }
28177
+ )
28178
+ ] })
28088
28179
  }
28089
28180
  ) })
28090
28181
  ] });
@@ -28764,14 +28855,20 @@ function DateTimePicker({
28764
28855
  }, [date, mode]);
28765
28856
  const isInputDisabled = isDisabled || !isEditable;
28766
28857
  const [calendarMonthState, setCalendarMonthState] = React6.useState(() => {
28767
- return date ? new Date(date.getFullYear(), date.getMonth()) : new Date(year, 0);
28858
+ const currentMonth = (/* @__PURE__ */ new Date()).getMonth();
28859
+ return date ? new Date(date.getFullYear(), date.getMonth()) : new Date(year, currentMonth);
28768
28860
  });
28769
28861
  React6.useEffect(() => {
28770
28862
  setCalendarMonthState(new Date(year, calendarMonthState.getMonth()));
28771
28863
  }, [year]);
28864
+ const handleToday = () => {
28865
+ const today = /* @__PURE__ */ new Date();
28866
+ const selectedYearDate = new Date(year, today.getMonth(), today.getDate());
28867
+ updateDateTime(selectedYearDate);
28868
+ };
28772
28869
  return /* @__PURE__ */ jsxs24("div", { className: "flex flex-col", children: [
28773
28870
  /* @__PURE__ */ jsxs24(Popover, { children: [
28774
- /* @__PURE__ */ jsx45(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx45(
28871
+ /* @__PURE__ */ jsx45(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs24(
28775
28872
  Button,
28776
28873
  {
28777
28874
  type: "button",
@@ -28787,17 +28884,28 @@ function DateTimePicker({
28787
28884
  borderColor: props.errorMessage ? "#f87171" : style?.borderColor
28788
28885
  },
28789
28886
  disabled: isInputDisabled,
28790
- children: displayValue || placeholder
28887
+ children: [
28888
+ displayValue || placeholder,
28889
+ /* @__PURE__ */ jsx45(Calendar1, { className: "absolute right-2 top-2" })
28890
+ ]
28791
28891
  }
28792
28892
  ) }),
28793
- /* @__PURE__ */ jsx45(PopoverContent, { className: "w-auto text-sm p-2", align: "start", style: { fontSize: "0.75rem" }, children: /* @__PURE__ */ jsxs24("div", { className: "flex flex-col gap-1", children: [
28893
+ /* @__PURE__ */ jsx45(PopoverContent, { className: "w-auto text-sm p-2", align: "start", children: /* @__PURE__ */ jsxs24("div", { className: "flex flex-col gap-1", children: [
28794
28894
  (mode === "date" || mode === "datetime") && /* @__PURE__ */ jsxs24(Fragment16, { children: [
28795
28895
  /* @__PURE__ */ jsxs24("div", { className: "flex items-center justify-between gap-1", children: [
28796
- /* @__PURE__ */ jsx45("label", { className: "text-xs text-muted-foreground", children: "Year" }),
28896
+ /* @__PURE__ */ jsx45(
28897
+ "label",
28898
+ {
28899
+ className: "text-xs text-blue-600 font-bold cursor-pointer",
28900
+ role: "presentation",
28901
+ onClick: handleToday,
28902
+ children: "Today"
28903
+ }
28904
+ ),
28797
28905
  /* @__PURE__ */ jsx45(
28798
28906
  "select",
28799
28907
  {
28800
- className: "h-8 rounded border bg-background px-2 text-sm",
28908
+ className: "h-8 rounded border bg-background px-2 text-xs",
28801
28909
  value: year,
28802
28910
  onChange: (e) => setYear(Number(e.target.value)),
28803
28911
  disabled: isInputDisabled || isReadonly,
@@ -28818,7 +28926,8 @@ function DateTimePicker({
28818
28926
  if (maxDate && d > maxDate) return true;
28819
28927
  return false;
28820
28928
  },
28821
- initialFocus: true
28929
+ className: "p-[10px]",
28930
+ autoFocus: true
28822
28931
  }
28823
28932
  ) })
28824
28933
  ] }),
@@ -28827,7 +28936,7 @@ function DateTimePicker({
28827
28936
  /* @__PURE__ */ jsx45(
28828
28937
  "select",
28829
28938
  {
28830
- className: "h-8 rounded border bg-background px-2 text-sm",
28939
+ className: "h-8 rounded border bg-background px-2 text-xs",
28831
28940
  value: displayHours,
28832
28941
  onChange: handleHoursChange,
28833
28942
  disabled: isInputDisabled || isReadonly,
@@ -28838,7 +28947,7 @@ function DateTimePicker({
28838
28947
  /* @__PURE__ */ jsx45(
28839
28948
  "select",
28840
28949
  {
28841
- className: "h-8 rounded border bg-background px-2 text-sm",
28950
+ className: "h-8 rounded border bg-background px-2 text-xs",
28842
28951
  value: minutes,
28843
28952
  onChange: handleMinutesChange,
28844
28953
  disabled: isInputDisabled || isReadonly,
@@ -28851,7 +28960,7 @@ function DateTimePicker({
28851
28960
  /* @__PURE__ */ jsxs24(
28852
28961
  "select",
28853
28962
  {
28854
- className: "h-8 rounded border bg-background px-2 text-sm",
28963
+ className: "h-8 rounded border bg-background px-2 text-xs",
28855
28964
  value: amPm,
28856
28965
  onChange: handleAmPmChange,
28857
28966
  disabled: isInputDisabled || isReadonly,