@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.js CHANGED
@@ -27887,14 +27887,46 @@ function useLazyDropdown(config) {
27887
27887
  };
27888
27888
  });
27889
27889
  }, []);
27890
+ function extractAndEnforceUrlParams(apiUrl, enforceStrict) {
27891
+ const urlObj = new URL(
27892
+ apiUrl,
27893
+ typeof window !== "undefined" ? window.location.origin : "http://localhost"
27894
+ );
27895
+ const cleaned = {};
27896
+ let hasEmpty = false;
27897
+ const baseUrl = urlObj.origin + urlObj.pathname;
27898
+ urlObj.searchParams.forEach((value, key) => {
27899
+ const isEmpty = value === "" || value === void 0 || value === null;
27900
+ if (isEmpty) {
27901
+ hasEmpty = true;
27902
+ if (enforceStrict) return;
27903
+ return;
27904
+ }
27905
+ cleaned[key] = value;
27906
+ });
27907
+ return {
27908
+ baseUrl,
27909
+ shouldAbort: enforceStrict && hasEmpty,
27910
+ params: cleaned
27911
+ };
27912
+ }
27890
27913
  const fetchApiData = (0, import_react19.useCallback)(async (pageNum, term) => {
27891
27914
  if (!configRef.current.apiUrl) return [];
27892
27915
  const limit = PAGE_SIZE;
27893
27916
  const params = { page: pageNum, limit };
27894
27917
  if (term) params[configRef.current.dataLabel ? `${configRef.current.dataLabel}[ilike]` : "search[ilike]"] = term;
27918
+ const { baseUrl, shouldAbort, params: urlParams } = extractAndEnforceUrlParams(
27919
+ configRef.current.apiUrl,
27920
+ configRef.current.enforceStrictQueryParams ?? false
27921
+ );
27922
+ if (shouldAbort) {
27923
+ setLoading(false);
27924
+ return [];
27925
+ }
27926
+ const finalParams = { ...urlParams, ...params };
27895
27927
  const axiosClient = configRef.current.axiosInstance ?? import_axios.default;
27896
- const res = await axiosClient.get(configRef.current.apiUrl, {
27897
- params,
27928
+ const res = await axiosClient.get(baseUrl, {
27929
+ params: finalParams,
27898
27930
  withCredentials: true
27899
27931
  });
27900
27932
  if (res.data?.success && Array.isArray(res.data.data)) {
@@ -27957,8 +27989,17 @@ function useLazyDropdown(config) {
27957
27989
  [`${configRef.current.dataKey}[in]`]: configRef.current.value.join(",")
27958
27990
  };
27959
27991
  }
27960
- const res = await axiosClient.get(configRef.current.apiUrl, {
27961
- params,
27992
+ const { baseUrl, shouldAbort, params: urlParams } = extractAndEnforceUrlParams(
27993
+ configRef.current.apiUrl,
27994
+ configRef.current.enforceStrictQueryParams ?? false
27995
+ );
27996
+ if (shouldAbort) {
27997
+ setLoading(false);
27998
+ return;
27999
+ }
28000
+ const finalParams = { ...urlParams, ...params };
28001
+ const res = await axiosClient.get(baseUrl, {
28002
+ params: finalParams,
27962
28003
  withCredentials: true
27963
28004
  });
27964
28005
  if (res.data?.success && Array.isArray(res.data.data) && res.data.data.length > 0) {
@@ -28011,6 +28052,32 @@ function useLazyDropdown(config) {
28011
28052
  if (debounceTimer.current) clearTimeout(debounceTimer.current);
28012
28053
  };
28013
28054
  }, []);
28055
+ const createNewOption = async (label) => {
28056
+ if (!configRef.current.apiUrl) return null;
28057
+ const axiosClient = configRef.current.axiosInstance ?? import_axios.default;
28058
+ const apiUrl = configRef.current.apiUrl;
28059
+ const urlObj = new URL(
28060
+ apiUrl,
28061
+ typeof window !== "undefined" ? window.location.origin : "http://localhost"
28062
+ );
28063
+ const queryParams = {};
28064
+ urlObj.searchParams.forEach((value, key) => {
28065
+ queryParams[key] = value;
28066
+ });
28067
+ const body = {
28068
+ ...queryParams,
28069
+ [configRef.current.dataLabel]: label
28070
+ };
28071
+ const res = await axiosClient.post(urlObj.origin + urlObj.pathname, body, {
28072
+ withCredentials: true
28073
+ });
28074
+ if (res.data?.success && Array.isArray(res.data.data) && res.data.data.length > 0) {
28075
+ const fetched = transformToOptions(res.data.data);
28076
+ setOptions((prev) => uniqueOptions([...fetched, ...prev]));
28077
+ return fetched[0];
28078
+ }
28079
+ return null;
28080
+ };
28014
28081
  return {
28015
28082
  options,
28016
28083
  loading,
@@ -28018,7 +28085,8 @@ function useLazyDropdown(config) {
28018
28085
  loadMore,
28019
28086
  search,
28020
28087
  reset,
28021
- loadPage
28088
+ loadPage,
28089
+ createNewOption
28022
28090
  };
28023
28091
  }
28024
28092
 
@@ -28039,7 +28107,8 @@ function LazySelectDropdown({
28039
28107
  dataKey = "id",
28040
28108
  dataLabel = "name",
28041
28109
  errorMessage,
28042
- axiosInstance
28110
+ axiosInstance,
28111
+ enableAddNewOption = false
28043
28112
  }) {
28044
28113
  const [isOpen, setIsOpen] = (0, import_react20.useState)(false);
28045
28114
  const [searchTerm, setSearchTerm] = (0, import_react20.useState)("");
@@ -28052,7 +28121,8 @@ function LazySelectDropdown({
28052
28121
  loadMore,
28053
28122
  search,
28054
28123
  reset,
28055
- loadPage
28124
+ loadPage,
28125
+ createNewOption
28056
28126
  } = useLazyDropdown({
28057
28127
  enabled: true,
28058
28128
  dataSource: source || "",
@@ -28110,6 +28180,15 @@ function LazySelectDropdown({
28110
28180
  reset();
28111
28181
  search("");
28112
28182
  };
28183
+ const handleAddNewOption = async (newOption) => {
28184
+ const option = await createNewOption(newOption);
28185
+ if (option) {
28186
+ onChange?.(option.value, id || "");
28187
+ setIsOpen(false);
28188
+ setSearchTerm("");
28189
+ reset();
28190
+ }
28191
+ };
28113
28192
  return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { ref: dropdownRef, className: "relative w-full", children: [
28114
28193
  /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
28115
28194
  "input",
@@ -28179,7 +28258,19 @@ function LazySelectDropdown({
28179
28258
  ] }) : "Scroll for more..."
28180
28259
  }
28181
28260
  )
28182
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "px-3 py-4 text-sm text-center text-gray-500", children: searchTerm ? `No results for "${searchTerm}"` : "No options available" })
28261
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "px-3 py-4 text-sm text-center text-gray-500", children: [
28262
+ searchTerm ? `No results for "${searchTerm}"` : "No options available",
28263
+ enableAddNewOption && searchTerm && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
28264
+ "div",
28265
+ {
28266
+ onClick: () => {
28267
+ handleAddNewOption(searchTerm);
28268
+ },
28269
+ className: "mt-2 px-3 py-2 bg-green-50 hover:bg-green-100 cursor-pointer text-green-700 rounded text-sm",
28270
+ children: `Add "${searchTerm}"`
28271
+ }
28272
+ )
28273
+ ] })
28183
28274
  }
28184
28275
  ) })
28185
28276
  ] });
@@ -28859,14 +28950,20 @@ function DateTimePicker({
28859
28950
  }, [date, mode]);
28860
28951
  const isInputDisabled = isDisabled || !isEditable;
28861
28952
  const [calendarMonthState, setCalendarMonthState] = React6.useState(() => {
28862
- return date ? new Date(date.getFullYear(), date.getMonth()) : new Date(year, 0);
28953
+ const currentMonth = (/* @__PURE__ */ new Date()).getMonth();
28954
+ return date ? new Date(date.getFullYear(), date.getMonth()) : new Date(year, currentMonth);
28863
28955
  });
28864
28956
  React6.useEffect(() => {
28865
28957
  setCalendarMonthState(new Date(year, calendarMonthState.getMonth()));
28866
28958
  }, [year]);
28959
+ const handleToday = () => {
28960
+ const today = /* @__PURE__ */ new Date();
28961
+ const selectedYearDate = new Date(year, today.getMonth(), today.getDate());
28962
+ updateDateTime(selectedYearDate);
28963
+ };
28867
28964
  return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex flex-col", children: [
28868
28965
  /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(Popover, { children: [
28869
- /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
28966
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
28870
28967
  Button,
28871
28968
  {
28872
28969
  type: "button",
@@ -28882,17 +28979,28 @@ function DateTimePicker({
28882
28979
  borderColor: props.errorMessage ? "#f87171" : style?.borderColor
28883
28980
  },
28884
28981
  disabled: isInputDisabled,
28885
- children: displayValue || placeholder
28982
+ children: [
28983
+ displayValue || placeholder,
28984
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Calendar1, { className: "absolute right-2 top-2" })
28985
+ ]
28886
28986
  }
28887
28987
  ) }),
28888
- /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(PopoverContent, { className: "w-auto text-sm p-2", align: "start", style: { fontSize: "0.75rem" }, children: /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex flex-col gap-1", children: [
28988
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(PopoverContent, { className: "w-auto text-sm p-2", align: "start", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex flex-col gap-1", children: [
28889
28989
  (mode === "date" || mode === "datetime") && /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(import_jsx_runtime45.Fragment, { children: [
28890
28990
  /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex items-center justify-between gap-1", children: [
28891
- /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("label", { className: "text-xs text-muted-foreground", children: "Year" }),
28991
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
28992
+ "label",
28993
+ {
28994
+ className: "text-xs text-blue-600 font-bold cursor-pointer",
28995
+ role: "presentation",
28996
+ onClick: handleToday,
28997
+ children: "Today"
28998
+ }
28999
+ ),
28892
29000
  /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
28893
29001
  "select",
28894
29002
  {
28895
- className: "h-8 rounded border bg-background px-2 text-sm",
29003
+ className: "h-8 rounded border bg-background px-2 text-xs",
28896
29004
  value: year,
28897
29005
  onChange: (e) => setYear(Number(e.target.value)),
28898
29006
  disabled: isInputDisabled || isReadonly,
@@ -28913,7 +29021,8 @@ function DateTimePicker({
28913
29021
  if (maxDate && d > maxDate) return true;
28914
29022
  return false;
28915
29023
  },
28916
- initialFocus: true
29024
+ className: "p-[10px]",
29025
+ autoFocus: true
28917
29026
  }
28918
29027
  ) })
28919
29028
  ] }),
@@ -28922,7 +29031,7 @@ function DateTimePicker({
28922
29031
  /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
28923
29032
  "select",
28924
29033
  {
28925
- className: "h-8 rounded border bg-background px-2 text-sm",
29034
+ className: "h-8 rounded border bg-background px-2 text-xs",
28926
29035
  value: displayHours,
28927
29036
  onChange: handleHoursChange,
28928
29037
  disabled: isInputDisabled || isReadonly,
@@ -28933,7 +29042,7 @@ function DateTimePicker({
28933
29042
  /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
28934
29043
  "select",
28935
29044
  {
28936
- className: "h-8 rounded border bg-background px-2 text-sm",
29045
+ className: "h-8 rounded border bg-background px-2 text-xs",
28937
29046
  value: minutes,
28938
29047
  onChange: handleMinutesChange,
28939
29048
  disabled: isInputDisabled || isReadonly,
@@ -28946,7 +29055,7 @@ function DateTimePicker({
28946
29055
  /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
28947
29056
  "select",
28948
29057
  {
28949
- className: "h-8 rounded border bg-background px-2 text-sm",
29058
+ className: "h-8 rounded border bg-background px-2 text-xs",
28950
29059
  value: amPm,
28951
29060
  onChange: handleAmPmChange,
28952
29061
  disabled: isInputDisabled || isReadonly,