sea-react-components 1.3.20 → 1.3.22

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.
Files changed (56) hide show
  1. package/dist/components/comments-container/comment-form/index.d.ts +20 -1
  2. package/dist/components/comments-container/comment-form/index.d.ts.map +1 -1
  3. package/dist/components/comments-container/comment-form/index.js +30 -4
  4. package/dist/components/comments-container/index.d.ts +3 -1
  5. package/dist/components/comments-container/index.d.ts.map +1 -1
  6. package/dist/components/comments-container/index.js +2 -2
  7. package/dist/components/jwt-checker/index.d.ts +5 -0
  8. package/dist/components/jwt-checker/index.d.ts.map +1 -0
  9. package/dist/components/jwt-checker/index.js +14 -0
  10. package/dist/components/jwt-token-checker/index.d.ts +1 -0
  11. package/dist/components/jwt-token-checker/index.d.ts.map +1 -0
  12. package/dist/components/jwt-token-checker/index.js +0 -0
  13. package/dist/components/searchable-select/index.js +1 -1
  14. package/dist/components/select/SelectChips.d.ts +9 -0
  15. package/dist/components/select/SelectChips.d.ts.map +1 -0
  16. package/dist/components/select/SelectChips.js +8 -0
  17. package/dist/components/select/SelectControl.d.ts +13 -0
  18. package/dist/components/select/SelectControl.d.ts.map +1 -0
  19. package/dist/components/select/SelectControl.js +12 -0
  20. package/dist/components/select/SelectDropdownContent.d.ts +23 -0
  21. package/dist/components/select/SelectDropdownContent.d.ts.map +1 -0
  22. package/dist/components/select/SelectDropdownContent.js +25 -0
  23. package/dist/components/select/SelectPlaceholder.d.ts +7 -0
  24. package/dist/components/select/SelectPlaceholder.d.ts.map +1 -0
  25. package/dist/components/select/SelectPlaceholder.js +4 -0
  26. package/dist/components/select/SelectTypes.d.ts +5 -0
  27. package/dist/components/select/SelectTypes.d.ts.map +1 -0
  28. package/dist/components/select/SelectTypes.js +1 -0
  29. package/dist/components/select/SelectView.d.ts +33 -0
  30. package/dist/components/select/SelectView.d.ts.map +1 -0
  31. package/dist/components/select/SelectView.js +16 -0
  32. package/dist/components/select/index.d.ts +5 -5
  33. package/dist/components/select/index.d.ts.map +1 -1
  34. package/dist/components/select/index.js +28 -64
  35. package/dist/components/select/useSelectPortal.d.ts +27 -0
  36. package/dist/components/select/useSelectPortal.d.ts.map +1 -0
  37. package/dist/components/select/useSelectPortal.js +110 -0
  38. package/dist/hooks/use-/index.d.ts +1 -0
  39. package/dist/hooks/use-/index.d.ts.map +1 -0
  40. package/dist/hooks/use-/index.js +0 -0
  41. package/dist/hooks/use-has-permission-access/index.d.ts.map +1 -1
  42. package/dist/hooks/use-has-permission-access/index.js +4 -0
  43. package/dist/hooks/use-interval/index.d.ts +2 -0
  44. package/dist/hooks/use-interval/index.d.ts.map +1 -0
  45. package/dist/hooks/use-interval/index.js +16 -0
  46. package/dist/hooks/use-token-watcher/index.d.ts +7 -0
  47. package/dist/hooks/use-token-watcher/index.d.ts.map +1 -0
  48. package/dist/hooks/use-token-watcher/index.js +23 -0
  49. package/dist/hooks/user-has-application-access/index.d.ts.map +1 -1
  50. package/dist/hooks/user-has-application-access/index.js +2 -0
  51. package/dist/tsconfig.tsbuildinfo +1 -1
  52. package/dist/utils/axios/index.d.ts.map +1 -1
  53. package/dist/utils/axios/index.js +3 -0
  54. package/dist/utils/cookie/index.d.ts.map +1 -1
  55. package/dist/utils/cookie/index.js +2 -0
  56. package/package.json +2 -2
@@ -1,3 +1,5 @@
1
+ import React from "react";
2
+ import { useFormik } from "formik";
1
3
  import { DTO } from "sea-platform-helpers";
2
4
  import * as Yup from "yup";
3
5
  export declare const createNewCommentValidation: () => Yup.ObjectSchema<{
@@ -5,6 +7,21 @@ export declare const createNewCommentValidation: () => Yup.ObjectSchema<{
5
7
  }, Yup.AnyObject, {
6
8
  description: undefined;
7
9
  }, "">;
10
+ type Values = {
11
+ objectId: string;
12
+ model: DTO.Comment.CommentSupportedModels;
13
+ description: string;
14
+ parentCommentId?: string;
15
+ };
16
+ export type CommentFormRenderProps = {
17
+ formik: ReturnType<typeof useFormik<Values>>;
18
+ isReplying: boolean;
19
+ isEditing: boolean;
20
+ replyOnComment?: DTO.Comment.IComment;
21
+ cancelReply: () => void;
22
+ cancelEdit: () => void;
23
+ handleKeyDown?: (e: React.KeyboardEvent<HTMLTextAreaElement>) => void;
24
+ };
8
25
  export type Props = {
9
26
  objectId: string;
10
27
  model: DTO.Comment.CommentSupportedModels;
@@ -15,6 +32,8 @@ export type Props = {
15
32
  setReplyOnComment: (comment: DTO.Comment.IComment | undefined) => void;
16
33
  onCreateCommentSuccess?: (comment: DTO.Comment.IComment) => void;
17
34
  onEditCommentSuccess?: (comment: DTO.Comment.IComment) => void;
35
+ renderForm?: (props: CommentFormRenderProps) => React.ReactNode;
18
36
  };
19
- export default function CommentForm({ objectId, model, commentsBaseUrl, commentToEdit, setCommentToEdit, replyOnComment, setReplyOnComment, onCreateCommentSuccess, onEditCommentSuccess, }: Props): import("react/jsx-runtime").JSX.Element;
37
+ export default function CommentForm({ objectId, model, commentsBaseUrl, commentToEdit, setCommentToEdit, replyOnComment, setReplyOnComment, onCreateCommentSuccess, onEditCommentSuccess, renderForm, }: Props): import("react/jsx-runtime").JSX.Element;
38
+ export {};
20
39
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/comments-container/comment-form/index.tsx"],"names":[],"mappings":"AAMA,OAAO,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAC;AAC3C,OAAO,KAAK,GAAG,MAAM,KAAK,CAAC;AAK3B,eAAO,MAAM,0BAA0B;;;;MAItC,CAAC;AASF,MAAM,MAAM,KAAK,GAAG;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,sBAAsB,CAAC;IAC1C,eAAe,EAAE,MAAM,CAAC;IAExB,aAAa,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;IACrC,gBAAgB,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,QAAQ,GAAG,SAAS,KAAK,IAAI,CAAC;IAEtE,cAAc,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;IACtC,iBAAiB,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,QAAQ,GAAG,SAAS,KAAK,IAAI,CAAC;IAEvE,sBAAsB,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,QAAQ,KAAK,IAAI,CAAC;IACjE,oBAAoB,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,QAAQ,KAAK,IAAI,CAAC;CAChE,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,EAClC,QAAQ,EACR,KAAK,EACL,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,iBAAiB,EACjB,sBAAsB,EACtB,oBAAoB,GACrB,EAAE,KAAK,2CA4GP"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/comments-container/comment-form/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,EAAiB,SAAS,EAAE,MAAM,QAAQ,CAAC;AAClD,OAAO,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAC;AAC3C,OAAO,KAAK,GAAG,MAAM,KAAK,CAAC;AAK3B,eAAO,MAAM,0BAA0B;;;;MAQtC,CAAC;AAEF,KAAK,MAAM,GAAG;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,sBAAsB,CAAC;IAC1C,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,MAAM,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;IAC7C,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,cAAc,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;IACtC,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,aAAa,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,mBAAmB,CAAC,KAAK,IAAI,CAAC;CACvE,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,sBAAsB,CAAC;IAC1C,eAAe,EAAE,MAAM,CAAC;IAExB,aAAa,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;IACrC,gBAAgB,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,QAAQ,GAAG,SAAS,KAAK,IAAI,CAAC;IAEtE,cAAc,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC;IACtC,iBAAiB,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,QAAQ,GAAG,SAAS,KAAK,IAAI,CAAC;IAEvE,sBAAsB,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,QAAQ,KAAK,IAAI,CAAC;IACjE,oBAAoB,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,QAAQ,KAAK,IAAI,CAAC;IAE/D,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,KAAK,CAAC,SAAS,CAAC;CACjE,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,EAClC,QAAQ,EACR,KAAK,EACL,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,iBAAiB,EACjB,sBAAsB,EACtB,oBAAoB,EACpB,UAAU,GACX,EAAE,KAAK,2CAsIP"}
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import Textarea from "../../textarea";
4
4
  import Button from "../../button";
5
5
  import { useFormik } from "formik";
@@ -9,10 +9,14 @@ import eventBus from "../comment-event-bus";
9
9
  import { COMMENT_EVENTS } from "../constants";
10
10
  export const createNewCommentValidation = () => {
11
11
  return Yup.object({
12
- description: Yup.string().min(3).max(1000).required("Required"),
12
+ description: Yup.string()
13
+ .trim()
14
+ .min(1, "Required")
15
+ .max(1000, "Must be at most 1000 characters")
16
+ .required("Required"),
13
17
  });
14
18
  };
15
- export default function CommentForm({ objectId, model, commentsBaseUrl, commentToEdit, setCommentToEdit, replyOnComment, setReplyOnComment, onCreateCommentSuccess, onEditCommentSuccess, }) {
19
+ export default function CommentForm({ objectId, model, commentsBaseUrl, commentToEdit, setCommentToEdit, replyOnComment, setReplyOnComment, onCreateCommentSuccess, onEditCommentSuccess, renderForm, }) {
16
20
  var _a;
17
21
  const initialValues = {
18
22
  model,
@@ -49,9 +53,31 @@ export default function CommentForm({ objectId, model, commentsBaseUrl, commentT
49
53
  onSubmit,
50
54
  enableReinitialize: true,
51
55
  });
56
+ const handleKeyDown = (e) => {
57
+ // If user pressed Ctrl+Enter (Windows/Linux) or Cmd+Enter (Mac)
58
+ if ((e.ctrlKey || e.metaKey) && e.key === "Enter") {
59
+ e.preventDefault(); // prevent new line
60
+ if (!formik.isSubmitting && formik.isValid) {
61
+ formik.submitForm();
62
+ }
63
+ }
64
+ };
65
+ const cancelReply = () => setReplyOnComment(undefined);
66
+ const cancelEdit = () => setCommentToEdit(undefined);
67
+ const renderProps = {
68
+ formik,
69
+ isReplying: Boolean(replyOnComment),
70
+ isEditing: Boolean(commentToEdit),
71
+ replyOnComment,
72
+ cancelReply,
73
+ cancelEdit,
74
+ handleKeyDown,
75
+ };
76
+ if (renderForm)
77
+ return _jsx(_Fragment, { children: renderForm(renderProps) });
52
78
  return (_jsxs("form", { onSubmit: formik.handleSubmit, className: "flex flex-col gap-3", children: [replyOnComment && (_jsxs("div", { className: "flex items-center justify-between bg-primary/5 px-3 py-2 rounded-lg border border-primary/10", children: [_jsxs("p", { className: "text-sm text-gray-700", children: ["Replying to", " ", _jsx("span", { className: "font-semibold text-primary", children: (_a = replyOnComment.account) === null || _a === void 0 ? void 0 : _a.name })] }), _jsx(Button, { type: "button", onClick: () => setReplyOnComment(undefined), className: "bg-transparent", children: _jsx("p", { className: "text-error hover:text-opacity-75 custom-animation", children: "Cancel" }) })] })), _jsx(Textarea, { name: "description", placeholder: commentToEdit
53
79
  ? "Edit your comment..."
54
80
  : replyOnComment
55
81
  ? "Write a reply..."
56
- : "Add a comment...", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.description, errorMessage: formik.touched.description ? formik.errors.description : "", className: "min-h-[80px]" }), _jsxs("div", { className: "flex justify-end gap-2 pt-1", children: [commentToEdit && (_jsx(Button, { type: "button", onClick: () => setCommentToEdit(undefined), className: "bg-transparent", children: _jsx("p", { className: "text-error hover:text-opacity-75 custom-animation", children: "Cancel" }) })), _jsx(Button, { type: "submit", loading: formik.isSubmitting, disabled: formik.isSubmitting || !formik.isValid, children: commentToEdit ? "Update Comment" : "Add Comment" })] })] }));
82
+ : "Add a comment...", onChange: formik.handleChange, onBlur: formik.handleBlur, value: formik.values.description, errorMessage: formik.touched.description ? formik.errors.description : "", className: "min-h-[80px]", onKeyDown: handleKeyDown }), _jsxs("div", { className: "flex justify-end gap-2 pt-1", children: [commentToEdit && (_jsx(Button, { type: "button", onClick: () => setCommentToEdit(undefined), className: "bg-transparent", children: _jsx("p", { className: "text-error hover:text-opacity-75 custom-animation", children: "Cancel" }) })), _jsx(Button, { type: "submit", loading: formik.isSubmitting, disabled: formik.isSubmitting || !formik.isValid, children: commentToEdit ? "Update Comment" : "Add Comment" })] })] }));
57
83
  }
@@ -1,4 +1,5 @@
1
1
  import { DTO } from "sea-platform-helpers";
2
+ import { CommentFormRenderProps } from "./comment-form";
2
3
  export type Props = {
3
4
  commentsBaseUrl: string;
4
5
  objectId: string;
@@ -14,6 +15,7 @@ export type Props = {
14
15
  limit?: number;
15
16
  highlightCommentId?: string;
16
17
  }) => React.ReactNode;
18
+ renderForm?: (props: CommentFormRenderProps) => React.ReactNode;
17
19
  };
18
- export default function CommentsContainer({ commentsBaseUrl, objectId, model, limit, highlightCommentId, renderCommentItem, }: Props): import("react/jsx-runtime").JSX.Element;
20
+ export default function CommentsContainer({ commentsBaseUrl, objectId, model, limit, highlightCommentId, renderCommentItem, renderForm, }: Props): import("react/jsx-runtime").JSX.Element;
19
21
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/comments-container/index.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,GAAG,EAAa,MAAM,sBAAsB,CAAC;AAQtD,MAAM,MAAM,KAAK,GAAG;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,sBAAsB,CAAC;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAE5B,iBAAiB,CAAC,EAAE,CAClB,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,QAAQ,EAC7B,WAAW,EAAE;QACX,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,WAAW,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,QAAQ,GAAG,SAAS,KAAK,IAAI,CAAC;QACjE,cAAc,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,QAAQ,GAAG,SAAS,KAAK,IAAI,CAAC;QACpE,eAAe,EAAE,MAAM,CAAC;QACxB,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,kBAAkB,CAAC,EAAE,MAAM,CAAC;KAC7B,KACE,KAAK,CAAC,SAAS,CAAC;CACtB,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,iBAAiB,CAAC,EACxC,eAAe,EACf,QAAQ,EACR,KAAK,EACL,KAAU,EACV,kBAAkB,EAClB,iBAAiB,GAClB,EAAE,KAAK,2CAkDP"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/comments-container/index.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,GAAG,EAAa,MAAM,sBAAsB,CAAC;AAItD,OAAoB,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAIrE,MAAM,MAAM,KAAK,GAAG;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,sBAAsB,CAAC;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAE5B,iBAAiB,CAAC,EAAE,CAClB,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,QAAQ,EAC7B,WAAW,EAAE;QACX,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,WAAW,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,QAAQ,GAAG,SAAS,KAAK,IAAI,CAAC;QACjE,cAAc,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,QAAQ,GAAG,SAAS,KAAK,IAAI,CAAC;QACpE,eAAe,EAAE,MAAM,CAAC;QACxB,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,kBAAkB,CAAC,EAAE,MAAM,CAAC;KAC7B,KACE,KAAK,CAAC,SAAS,CAAC;IAErB,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,KAAK,CAAC,SAAS,CAAC;CACjE,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,iBAAiB,CAAC,EACxC,eAAe,EACf,QAAQ,EACR,KAAK,EACL,KAAU,EACV,kBAAkB,EAClB,iBAAiB,EACjB,UAAU,GACX,EAAE,KAAK,2CAmDP"}
@@ -7,7 +7,7 @@ import { jwtDecode } from "../../utils/jwt";
7
7
  import CommentForm from "./comment-form";
8
8
  import CommentsList from "./comments-list";
9
9
  import CommentItem from "./comment-item";
10
- export default function CommentsContainer({ commentsBaseUrl, objectId, model, limit = 10, highlightCommentId, renderCommentItem, }) {
10
+ export default function CommentsContainer({ commentsBaseUrl, objectId, model, limit = 10, highlightCommentId, renderCommentItem, renderForm, }) {
11
11
  const [accountId, setAccountId] = useState("");
12
12
  const [commentToEdit, setCommentToEdit] = useState();
13
13
  const [replyOnComment, setReplyOnComment] = useState();
@@ -23,5 +23,5 @@ export default function CommentsContainer({ commentsBaseUrl, objectId, model, li
23
23
  }, onEditCommentSuccess: () => {
24
24
  setCommentToEdit(undefined);
25
25
  setReplyOnComment(undefined);
26
- } }), _jsx(CommentsList, { editComment: setCommentToEdit, replyOnComment: setReplyOnComment, highlightCommentId: highlightCommentId, currentAccountId: accountId, commentsBaseUrl: commentsBaseUrl, objectId: objectId, limit: limit, renderCommentItem: renderCommentItem !== null && renderCommentItem !== void 0 ? renderCommentItem : ((comment, props) => (_jsx(CommentItem, { comment: comment, ...props }, comment.id))) })] }));
26
+ }, renderForm: renderForm }), _jsx(CommentsList, { editComment: setCommentToEdit, replyOnComment: setReplyOnComment, highlightCommentId: highlightCommentId, currentAccountId: accountId, commentsBaseUrl: commentsBaseUrl, objectId: objectId, limit: limit, renderCommentItem: renderCommentItem !== null && renderCommentItem !== void 0 ? renderCommentItem : ((comment, props) => (_jsx(CommentItem, { comment: comment, ...props }, comment.id))) })] }));
27
27
  }
@@ -0,0 +1,5 @@
1
+ export type Props = {
2
+ delay?: number;
3
+ };
4
+ export default function JWTChecker({ delay }: Props): import("react/jsx-runtime").JSX.Element;
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/jwt-checker/index.tsx"],"names":[],"mappings":"AAKA,MAAM,MAAM,KAAK,GAAG;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AACF,MAAM,CAAC,OAAO,UAAU,UAAU,CAAC,EAAE,KAAY,EAAE,EAAE,KAAK,2CAOzD"}
@@ -0,0 +1,14 @@
1
+ "use client";
2
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
3
+ import { CONSTANTS } from "sea-platform-helpers";
4
+ import { useInterval } from "../../hooks/use-interval";
5
+ import { getCookie } from "../../utils/cookie";
6
+ export default function JWTChecker({ delay = 2000 }) {
7
+ useInterval(() => {
8
+ const jwt = getCookie(CONSTANTS.JWT.JWTCookieKey);
9
+ console.log("JWTChecker - current JWT:", jwt);
10
+ if (!jwt)
11
+ window.location.reload();
12
+ }, delay);
13
+ return _jsx(_Fragment, {});
14
+ }
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/jwt-token-checker/index.tsx"],"names":[],"mappings":""}
File without changes
@@ -18,7 +18,7 @@ export default function SearchableSelect({ getItems, getLabel, getValue, ...prop
18
18
  return () => {
19
19
  active = false; // cancel stale promises
20
20
  };
21
- }, [query, memoGetItems]);
21
+ }, [query]);
22
22
  // --- Memoize mapped options ---
23
23
  const mappedOptions = useMemo(() => options.map((item) => ({
24
24
  label: memoGetLabel(item),
@@ -0,0 +1,9 @@
1
+ import type { SelectOption } from "./SelectTypes";
2
+ export type SelectChipsProps<T> = {
3
+ name: string;
4
+ selectedOptions: SelectOption<T>[];
5
+ disabled: boolean;
6
+ onRemove: (option: SelectOption<T>) => void;
7
+ };
8
+ export default function SelectChips<T>({ name, selectedOptions, disabled, onRemove, }: SelectChipsProps<T>): import("react/jsx-runtime").JSX.Element;
9
+ //# sourceMappingURL=SelectChips.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SelectChips.d.ts","sourceRoot":"","sources":["../../../src/components/select/SelectChips.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAAI;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;IACnC,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;CAC7C,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,CAAC,EAAE,EACrC,IAAI,EACJ,eAAe,EACf,QAAQ,EACR,QAAQ,GACT,EAAE,gBAAgB,CAAC,CAAC,CAAC,2CAwBrB"}
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Icon } from "@iconify/react";
3
+ export default function SelectChips({ name, selectedOptions, disabled, onRemove, }) {
4
+ return (_jsx("div", { className: "flex flex-wrap gap-2", id: name, children: selectedOptions.map((o, i) => (_jsxs("div", { className: "bg-primary bg-opacity-50 px-2 py-1 rounded-2xl flex items-center gap-1", children: [_jsx("span", { className: "text-black text-sm", children: o.label }), !disabled && (_jsx("button", { type: "button", onClick: (e) => {
5
+ e.stopPropagation();
6
+ onRemove(o);
7
+ }, children: _jsx(Icon, { icon: "line-md:close-small", className: "w-4 h-4" }) }))] }, `${name}-${i}`))) }));
8
+ }
@@ -0,0 +1,13 @@
1
+ import React from "react";
2
+ export type SelectControlProps = {
3
+ disabled: boolean;
4
+ errorMessage?: string | boolean;
5
+ isOpen: boolean;
6
+ buttonClassName?: string;
7
+ onToggle: () => void;
8
+ leftContent: React.ReactNode;
9
+ showClear: boolean;
10
+ onClear: (e: React.MouseEvent) => void;
11
+ };
12
+ export default function SelectControl({ disabled, errorMessage, isOpen, buttonClassName, onToggle, leftContent, showClear, onClear, }: SelectControlProps): import("react/jsx-runtime").JSX.Element;
13
+ //# sourceMappingURL=SelectControl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SelectControl.d.ts","sourceRoot":"","sources":["../../../src/components/select/SelectControl.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAChC,MAAM,EAAE,OAAO,CAAC;IAChB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,WAAW,EAAE,KAAK,CAAC,SAAS,CAAC;IAC7B,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,KAAK,IAAI,CAAC;CACxC,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,EACpC,QAAQ,EACR,YAAY,EACZ,MAAM,EACN,eAAe,EACf,QAAQ,EACR,WAAW,EACX,SAAS,EACT,OAAO,GACR,EAAE,kBAAkB,2CAuCpB"}
@@ -0,0 +1,12 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import clsx from "clsx";
3
+ import { Icon } from "@iconify/react";
4
+ export default function SelectControl({ disabled, errorMessage, isOpen, buttonClassName, onToggle, leftContent, showClear, onClear, }) {
5
+ return (_jsxs("div", { onClick: () => !disabled && onToggle(), className: clsx("text-text flex items-center justify-between gap-2 px-3 py-2 rounded-md border-0.5 hover:border-primary transition-all", disabled
6
+ ? "bg-gray-100 text-gray-400 cursor-not-allowed"
7
+ : "bg-white cursor-pointer", errorMessage
8
+ ? "border-error"
9
+ : isOpen
10
+ ? "border-primary"
11
+ : "border-gray-200", buttonClassName), children: [leftContent, _jsxs("div", { className: "flex items-center gap-1", children: [!disabled && showClear && (_jsx("button", { type: "button", onClick: onClear, title: "Clear selection", className: "text-gray-500 hover:text-primary", children: _jsx(Icon, { icon: "line-md:close-small", className: "w-5 h-5" }) })), _jsx(Icon, { icon: "iconamoon:arrow-down-2", className: clsx("transition-transform duration-200", isOpen && "rotate-180") })] })] }));
12
+ }
@@ -0,0 +1,23 @@
1
+ import React, { ChangeEvent } from "react";
2
+ import { MenuPosition } from "./useSelectPortal";
3
+ import type { SelectOption } from "./SelectTypes";
4
+ export type SelectDropdownContentProps<T> = {
5
+ usePortal: boolean;
6
+ dropdownClassName?: string;
7
+ animate: boolean;
8
+ menuPos: MenuPosition;
9
+ isSearchable: boolean;
10
+ search: string;
11
+ onChangeSearchInput: (e: ChangeEvent<HTMLInputElement>) => void;
12
+ filteredOptions: SelectOption<T>[];
13
+ selectedOptions: SelectOption<T>[];
14
+ name: string;
15
+ onOptionClick: (option: SelectOption<T>) => void;
16
+ onStopClick?: (e: React.MouseEvent) => void;
17
+ };
18
+ declare function BaseSelectDropdownContent<T>({ usePortal, dropdownClassName, animate, menuPos, isSearchable, search, onChangeSearchInput, filteredOptions, selectedOptions, name, onOptionClick, onStopClick, }: SelectDropdownContentProps<T>, ref: React.ForwardedRef<HTMLDivElement>): import("react/jsx-runtime").JSX.Element;
19
+ declare const SelectDropdownContent: <T>(p: SelectDropdownContentProps<T> & {
20
+ ref?: React.ForwardedRef<HTMLDivElement>;
21
+ }) => ReturnType<typeof BaseSelectDropdownContent>;
22
+ export default SelectDropdownContent;
23
+ //# sourceMappingURL=SelectDropdownContent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SelectDropdownContent.d.ts","sourceRoot":"","sources":["../../../src/components/select/SelectDropdownContent.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,WAAW,EAAc,MAAM,OAAO,CAAC;AAGvD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,MAAM,MAAM,0BAA0B,CAAC,CAAC,IAAI;IAC1C,SAAS,EAAE,OAAO,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,YAAY,CAAC;IACtB,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,mBAAmB,EAAE,CAAC,CAAC,EAAE,WAAW,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;IAChE,eAAe,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;IACnC,eAAe,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IACjD,WAAW,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,KAAK,IAAI,CAAC;CAC7C,CAAC;AAEF,iBAAS,yBAAyB,CAAC,CAAC,EAClC,EACE,SAAS,EACT,iBAAiB,EACjB,OAAO,EACP,OAAO,EACP,YAAY,EACZ,MAAM,EACN,mBAAmB,EACnB,eAAe,EACf,eAAe,EACf,IAAI,EACJ,aAAa,EACb,WAAW,GACZ,EAAE,0BAA0B,CAAC,CAAC,CAAC,EAChC,GAAG,EAAE,KAAK,CAAC,YAAY,CAAC,cAAc,CAAC,2CAsExC;AAED,QAAA,MAAM,qBAAqB,EAA4C,CAAC,CAAC,EACvE,CAAC,EAAE,0BAA0B,CAAC,CAAC,CAAC,GAAG;IACjC,GAAG,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC,cAAc,CAAC,CAAC;CAC1C,KACE,UAAU,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAElD,eAAe,qBAAqB,CAAC"}
@@ -0,0 +1,25 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { forwardRef } from "react";
3
+ import clsx from "clsx";
4
+ import { Icon } from "@iconify/react";
5
+ function BaseSelectDropdownContent({ usePortal, dropdownClassName, animate, menuPos, isSearchable, search, onChangeSearchInput, filteredOptions, selectedOptions, name, onOptionClick, onStopClick, }, ref) {
6
+ return (_jsxs("div", { className: clsx("bg-white border border-gray-200 rounded-md shadow-lg overflow-auto transition-all duration-200 ease-out", animate
7
+ ? "opacity-100 translate-y-0 scale-100"
8
+ : menuPos.placement === "bottom"
9
+ ? "opacity-0 -translate-y-1 scale-95"
10
+ : "opacity-0 translate-y-1 scale-95", menuPos.placement === "bottom" ? "origin-top" : "origin-bottom", dropdownClassName), onClick: onStopClick, style: usePortal
11
+ ? {
12
+ position: "fixed",
13
+ zIndex: 60,
14
+ left: menuPos.left,
15
+ top: menuPos.top,
16
+ width: menuPos.width,
17
+ maxHeight: menuPos.maxHeight,
18
+ }
19
+ : undefined, ref: ref, children: [isSearchable && (_jsxs("div", { className: "sticky top-0 bg-white border-b border-gray-100 px-2 py-1 flex items-center gap-2", children: [_jsx(Icon, { icon: "mdi:magnify", className: "text-gray-500 w-5 h-5" }), _jsx("input", { type: "text", placeholder: "Search...", value: search, onChange: onChangeSearchInput, className: "w-full outline-none text-sm bg-transparent py-1" })] })), filteredOptions.length > 0 ? (filteredOptions.map((o, i) => {
20
+ const isSelected = selectedOptions.some((s) => Object.is(s.value, o.value));
21
+ return (_jsxs("div", { onClick: () => onOptionClick(o), className: clsx("mx-1 px-3 py-2 cursor-pointer flex items-center gap-2 rounded text-sm hover:text-primary hover:bg-primary/20", isSelected && "bg-primary/10 text-primary"), children: [isSelected ? (_jsx(Icon, { icon: "mdi:check", className: "w-4 h-4 text-primary" })) : (_jsx("div", { className: "w-4 h-4" })), o.label] }, `${name}-option-${i}`));
22
+ })) : (_jsx("div", { className: "px-3 py-2 text-gray-400 text-sm", children: "No results" }))] }));
23
+ }
24
+ const SelectDropdownContent = forwardRef(BaseSelectDropdownContent);
25
+ export default SelectDropdownContent;
@@ -0,0 +1,7 @@
1
+ import React from "react";
2
+ export type SelectPlaceHolderProps = {
3
+ placeholder: string;
4
+ IconPlaceholderLeft?: React.ReactNode;
5
+ };
6
+ export default function SelectPlaceHolder({ placeholder, IconPlaceholderLeft, }: SelectPlaceHolderProps): import("react/jsx-runtime").JSX.Element;
7
+ //# sourceMappingURL=SelectPlaceholder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SelectPlaceholder.d.ts","sourceRoot":"","sources":["../../../src/components/select/SelectPlaceholder.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,MAAM,sBAAsB,GAAG;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CACvC,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,iBAAiB,CAAC,EACxC,WAAW,EACX,mBAAmB,GACpB,EAAE,sBAAsB,2CAOxB"}
@@ -0,0 +1,4 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ export default function SelectPlaceHolder({ placeholder, IconPlaceholderLeft, }) {
3
+ return (_jsxs("div", { className: "flex gap-2 items-center overflow-hidden", children: [IconPlaceholderLeft, _jsx("p", { className: "text-gray-500 truncate line-clamp-1", children: placeholder })] }));
4
+ }
@@ -0,0 +1,5 @@
1
+ export type SelectOption<T> = {
2
+ value: T;
3
+ label: React.ReactNode;
4
+ };
5
+ //# sourceMappingURL=SelectTypes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SelectTypes.d.ts","sourceRoot":"","sources":["../../../src/components/select/SelectTypes.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI;IAC5B,KAAK,EAAE,CAAC,CAAC;IACT,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;CACxB,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,33 @@
1
+ import React, { ChangeEvent } from "react";
2
+ import type { SelectOption } from "./SelectTypes";
3
+ import type { MenuPosition } from "./useSelectPortal";
4
+ export type SelectViewProps<T> = {
5
+ label?: string;
6
+ required?: boolean;
7
+ errorMessage?: string | boolean;
8
+ containerRef: React.RefObject<HTMLDivElement>;
9
+ menuRef: React.RefObject<HTMLDivElement>;
10
+ disabled: boolean;
11
+ isOpen: boolean;
12
+ buttonClassName?: string;
13
+ onToggle: () => void;
14
+ multiselect: boolean;
15
+ selectedOptions: SelectOption<T>[];
16
+ placeholder: string;
17
+ IconPlaceholderLeft?: React.ReactNode;
18
+ onClear: (e: React.MouseEvent) => void;
19
+ name: string;
20
+ show: boolean;
21
+ usePortal: boolean;
22
+ dropdownClassName?: string;
23
+ animate: boolean;
24
+ menuPos: MenuPosition;
25
+ isSearchable: boolean;
26
+ search: string;
27
+ onChangeSearchInput: (e: ChangeEvent<HTMLInputElement>) => void;
28
+ filteredOptions: SelectOption<T>[];
29
+ onOptionClick: (o: SelectOption<T>) => void;
30
+ desiredMax: number;
31
+ };
32
+ export default function SelectView<T>({ label, required, errorMessage, containerRef, menuRef, disabled, isOpen, buttonClassName, onToggle, multiselect, selectedOptions, placeholder, IconPlaceholderLeft, onClear, name, show, usePortal, dropdownClassName, animate, menuPos, isSearchable, search, onChangeSearchInput, filteredOptions, onOptionClick, desiredMax, }: SelectViewProps<T>): import("react/jsx-runtime").JSX.Element;
33
+ //# sourceMappingURL=SelectView.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SelectView.d.ts","sourceRoot":"","sources":["../../../src/components/select/SelectView.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAO3C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD,MAAM,MAAM,eAAe,CAAC,CAAC,IAAI;IAE/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAGhC,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;IAC9C,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;IAGzC,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,eAAe,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACtC,OAAO,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,KAAK,IAAI,CAAC;IAGvC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,YAAY,CAAC;IACtB,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,mBAAmB,EAAE,CAAC,CAAC,EAAE,WAAW,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;IAChE,eAAe,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;IACnC,aAAa,EAAE,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IAC5C,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,UAAU,CAAC,CAAC,EAAE,EACpC,KAAK,EACL,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,OAAO,EACP,QAAQ,EACR,MAAM,EACN,eAAe,EACf,QAAQ,EACR,WAAW,EACX,eAAe,EACf,WAAW,EACX,mBAAmB,EACnB,OAAO,EACP,IAAI,EACJ,IAAI,EACJ,SAAS,EACT,iBAAiB,EACjB,OAAO,EACP,OAAO,EACP,YAAY,EACZ,MAAM,EACN,mBAAmB,EACnB,eAAe,EACf,aAAa,EACb,UAAU,GACX,EAAE,eAAe,CAAC,CAAC,CAAC,2CA2FpB"}
@@ -0,0 +1,16 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { createPortal } from "react-dom";
4
+ import clsx from "clsx";
5
+ import SelectControl from "./SelectControl";
6
+ import SelectPlaceHolder from "./SelectPlaceholder";
7
+ import SelectChips from "./SelectChips";
8
+ import SelectDropdownContent from "./SelectDropdownContent";
9
+ export default function SelectView({ label, required, errorMessage, containerRef, menuRef, disabled, isOpen, buttonClassName, onToggle, multiselect, selectedOptions, placeholder, IconPlaceholderLeft, onClear, name, show, usePortal, dropdownClassName, animate, menuPos, isSearchable, search, onChangeSearchInput, filteredOptions, onOptionClick, desiredMax, }) {
10
+ const leftContent = multiselect ? (selectedOptions.length ? (_jsx(SelectChips, { name: name, selectedOptions: selectedOptions, disabled: disabled, onRemove: (o) => onOptionClick(o) })) : (_jsx(SelectPlaceHolder, { placeholder: placeholder, IconPlaceholderLeft: IconPlaceholderLeft }))) : selectedOptions[0] ? (_jsx("div", { className: "text-text truncate line-clamp-1", children: selectedOptions[0].label })) : (_jsx(SelectPlaceHolder, { placeholder: placeholder, IconPlaceholderLeft: IconPlaceholderLeft }));
11
+ const dropdownEl = (_jsx(SelectDropdownContent, { ref: menuRef, usePortal: usePortal, dropdownClassName: dropdownClassName, animate: animate, menuPos: menuPos, isSearchable: isSearchable, search: search, onChangeSearchInput: onChangeSearchInput, filteredOptions: filteredOptions, selectedOptions: selectedOptions, name: name, onOptionClick: onOptionClick, onStopClick: (e) => e.stopPropagation() }));
12
+ return (_jsxs("div", { className: "flex flex-col gap-1", children: [label && (_jsxs("label", { htmlFor: name, className: "pl-1 text-sm text-foreground font-medium mb-2", children: [label, " ", required && _jsx("span", { className: "font-bold", children: "*" })] })), _jsxs("div", { ref: containerRef, className: "relative w-full", children: [_jsx(SelectControl, { disabled: disabled, errorMessage: errorMessage, isOpen: isOpen, buttonClassName: buttonClassName, onToggle: onToggle, leftContent: leftContent, showClear: !disabled &&
13
+ (multiselect ? selectedOptions.length > 0 : !!selectedOptions[0]), onClear: onClear }), show &&
14
+ !disabled &&
15
+ (usePortal ? (createPortal(dropdownEl, document.body)) : (_jsx("div", { className: clsx("absolute left-0 mt-1 z-50 max-w-[360px] min-w-[260px] w-full"), style: { maxHeight: desiredMax }, children: dropdownEl })))] }), errorMessage && (_jsx("p", { className: "pl-1 text-sm text-error", children: errorMessage }))] }));
16
+ }
@@ -1,8 +1,6 @@
1
1
  import React from "react";
2
- export type SelectOption<T> = {
3
- value: T;
4
- label: React.ReactNode;
5
- };
2
+ import type { SelectOption } from "./SelectTypes";
3
+ export type { SelectOption } from "./SelectTypes";
6
4
  export type Props<T> = {
7
5
  name: string;
8
6
  options: SelectOption<T>[];
@@ -21,6 +19,8 @@ export type Props<T> = {
21
19
  onRemove?: () => void;
22
20
  searchDebounceTimeout?: number;
23
21
  isRemote?: boolean;
22
+ usePortal?: boolean;
23
+ dropdownClassName?: string;
24
24
  };
25
- export default function Select<T>({ name, options, values, setValues, errorMessage, buttonClassName, placeholder, multiselect, disabled, label, isSearchable, required, IconPlaceholderLeft, onChangeSearchInput, onRemove, searchDebounceTimeout, isRemote, }: Props<T>): import("react/jsx-runtime").JSX.Element;
25
+ export default function Select<T>({ name, options, values, setValues, errorMessage, buttonClassName, placeholder, multiselect, disabled, label, isSearchable, required, IconPlaceholderLeft, onChangeSearchInput, onRemove, searchDebounceTimeout, isRemote, usePortal, dropdownClassName, }: Props<T>): import("react/jsx-runtime").JSX.Element;
26
26
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/select/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAON,MAAM,OAAO,CAAC;AAKf,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI;IAC5B,KAAK,EAAE,CAAC,CAAC;IACT,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,KAAK,CAAC,CAAC,IAAI;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;IAE3B,MAAM,EAAE,CAAC,EAAE,CAAC;IACZ,SAAS,EAAE,CAAC,SAAS,EAAE,CAAC,EAAE,KAAK,IAAI,CAAC;IAEpC,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAChC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mBAAmB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACtC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,mBAAmB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAGF,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,CAAC,EAAE,EAChC,IAAI,EACJ,OAAO,EACP,MAAM,EACN,SAAS,EACT,YAAY,EACZ,eAAe,EACf,WAAyB,EACzB,WAAmB,EACnB,QAAgB,EAChB,KAAK,EACL,YAAoB,EACpB,QAAgB,EAChB,mBAAmB,EACnB,mBAAmB,EACnB,QAAQ,EACR,qBAA2B,EAC3B,QAAgB,GACjB,EAAE,KAAK,CAAC,CAAC,CAAC,2CA6RV"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/select/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAON,MAAM,OAAO,CAAC;AAGf,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAGlD,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,MAAM,MAAM,KAAK,CAAC,CAAC,IAAI;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;IAE3B,MAAM,EAAE,CAAC,EAAE,CAAC;IACZ,SAAS,EAAE,CAAC,SAAS,EAAE,CAAC,EAAE,KAAK,IAAI,CAAC;IAEpC,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAChC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mBAAmB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACtC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,mBAAmB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAC;IAGnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,CAAC,EAAE,EAChC,IAAI,EACJ,OAAO,EACP,MAAM,EACN,SAAS,EACT,YAAY,EACZ,eAAe,EACf,WAAyB,EACzB,WAAmB,EACnB,QAAgB,EAChB,KAAK,EACL,YAAoB,EACpB,QAAgB,EAChB,mBAAmB,EACnB,mBAAmB,EACnB,QAAQ,EACR,qBAA2B,EAC3B,QAAgB,EAChB,SAAgB,EAChB,iBAAiB,GAClB,EAAE,KAAK,CAAC,CAAC,CAAC,2CAqIV"}
@@ -1,46 +1,46 @@
1
1
  "use client";
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import { useState, useRef, useEffect, useMemo, } from "react";
4
- import { Icon } from "@iconify/react";
5
- import clsx from "clsx";
6
- // ---------- Component ----------
7
- export default function Select({ name, options, values, setValues, errorMessage, buttonClassName, placeholder = "Select...", multiselect = false, disabled = false, label, isSearchable = false, required = false, IconPlaceholderLeft, onChangeSearchInput, onRemove, searchDebounceTimeout = 500, isRemote = false, }) {
4
+ import { useSelectPortal } from "./useSelectPortal";
5
+ import SelectView from "./SelectView";
6
+ export default function Select({ name, options, values, setValues, errorMessage, buttonClassName, placeholder = "Select...", multiselect = false, disabled = false, label, isSearchable = false, required = false, IconPlaceholderLeft, onChangeSearchInput, onRemove, searchDebounceTimeout = 500, isRemote = false, usePortal = true, dropdownClassName, }) {
8
7
  const [isOpen, setIsOpen] = useState(false);
9
- const [show, setShow] = useState(false);
10
- const [animate, setAnimate] = useState(false);
11
8
  const [search, setSearch] = useState("");
12
9
  const [selectedCache, setSelectedCache] = useState([]);
13
10
  const containerRef = useRef(null);
14
- // ---------- Debounced Search ----------
11
+ const menuRef = useRef(null);
12
+ const { show, animate, menuPos, desiredMax } = useSelectPortal({
13
+ isOpen,
14
+ usePortal,
15
+ containerRef,
16
+ menuRef,
17
+ heightDeps: [search, options.length, selectedCache.length],
18
+ });
19
+ // Debounced remote search trigger
15
20
  useEffect(() => {
16
21
  if (!onChangeSearchInput)
17
22
  return;
18
23
  const timeout = setTimeout(() => onChangeSearchInput(search), searchDebounceTimeout);
19
24
  return () => clearTimeout(timeout);
20
25
  }, [search, onChangeSearchInput, searchDebounceTimeout]);
21
- const handleSearchInputChange = (e) => {
22
- setSearch(e.target.value);
23
- };
24
- // ---------- Derived Values ----------
26
+ const handleSearchInputChange = (e) => setSearch(e.target.value);
27
+ // Derived values
25
28
  const mergedOptions = useMemo(() => [
26
29
  ...options,
27
30
  ...selectedCache.filter((cached) => !options.some((o) => Object.is(o.value, cached.value))),
28
31
  ], [options, selectedCache]);
29
32
  const selectedOptions = useMemo(() => mergedOptions.filter((o) => values.some((v) => Object.is(v, o.value))), [mergedOptions, values]);
30
33
  const filteredOptions = useMemo(() => {
31
- // Case 1: Not searchable => just return options
32
34
  if (!isSearchable)
33
35
  return mergedOptions;
34
- // Case 2: Remote mode => skip local filtering (server handles it)
35
36
  if (isRemote)
36
37
  return mergedOptions;
37
- // Case 3: Local filtering
38
38
  if (!search.trim())
39
39
  return mergedOptions;
40
40
  const lower = search.toLowerCase();
41
41
  return mergedOptions.filter((o) => String(o.label).toLowerCase().includes(lower));
42
42
  }, [isSearchable, mergedOptions, search, isRemote]);
43
- // ---------- Selection Logic ----------
43
+ // Selection logic
44
44
  const toggleOption = (option) => {
45
45
  if (disabled)
46
46
  return;
@@ -61,12 +61,6 @@ export default function Select({ name, options, values, setValues, errorMessage,
61
61
  }
62
62
  setValues(updatedValues);
63
63
  };
64
- const removeSelected = (option) => {
65
- if (disabled)
66
- return;
67
- setValues(values.filter((v) => !Object.is(v, option.value)));
68
- setSelectedCache((prev) => prev.filter((s) => !Object.is(s.value, option.value)));
69
- };
70
64
  const handleClear = (e) => {
71
65
  e.stopPropagation();
72
66
  if (disabled)
@@ -75,50 +69,20 @@ export default function Select({ name, options, values, setValues, errorMessage,
75
69
  setSelectedCache([]);
76
70
  onRemove === null || onRemove === void 0 ? void 0 : onRemove();
77
71
  };
78
- // ---------- Dropdown Visibility ----------
72
+ // Click outside
79
73
  useEffect(() => {
80
- const handleClickOutside = (e) => {
81
- if (containerRef.current &&
82
- !containerRef.current.contains(e.target)) {
74
+ const onDocMouseDown = (e) => {
75
+ const target = e.target;
76
+ const inTrigger = containerRef.current && containerRef.current.contains(target);
77
+ const inMenu = menuRef.current && menuRef.current.contains(target);
78
+ if (!inTrigger && !inMenu)
83
79
  setIsOpen(false);
84
- }
85
80
  };
86
- document.addEventListener("mousedown", handleClickOutside);
87
- return () => document.removeEventListener("mousedown", handleClickOutside);
81
+ document.addEventListener("mousedown", onDocMouseDown);
82
+ return () => document.removeEventListener("mousedown", onDocMouseDown);
88
83
  }, []);
89
- useEffect(() => {
90
- if (isOpen) {
91
- setShow(true);
92
- requestAnimationFrame(() => setAnimate(true));
93
- }
94
- else {
95
- setAnimate(false);
96
- const timeout = setTimeout(() => setShow(false), 200);
97
- return () => clearTimeout(timeout);
98
- }
99
- }, [isOpen]);
100
- // ---------- Render ----------
101
- const renderSelectedChips = () => selectedOptions.map((o, i) => (_jsxs("div", { className: "bg-primary bg-opacity-50 px-2 py-1 rounded-2xl flex items-center gap-1", children: [_jsx("span", { className: "text-black text-sm", children: o.label }), !disabled && (_jsx("button", { type: "button", onClick: (e) => {
102
- e.stopPropagation();
103
- removeSelected(o);
104
- }, children: _jsx(Icon, { icon: "line-md:close-small", className: "w-4 h-4" }) }))] }, `${name}-${i}`)));
105
- const renderPlaceholder = () => (_jsxs("div", { className: "flex gap-2 items-center overflow-hidden", children: [IconPlaceholderLeft, _jsx("p", { className: "text-gray-500 truncate line-clamp-1", children: placeholder })] }));
106
- return (_jsxs("div", { className: "flex flex-col gap-1", children: [label && (_jsxs("label", { htmlFor: name, className: "pl-1 text-sm text-foreground font-medium mb-2", children: [label, " ", required && _jsx("span", { className: "font-bold", children: "*" })] })), _jsxs("div", { ref: containerRef, className: "relative w-full", children: [_jsxs("div", { onClick: () => !disabled && setIsOpen((o) => !o), className: clsx("text-text flex items-center justify-between gap-2 px-3 py-2 rounded-md border-0.5 hover:border-primary transition-all", disabled
107
- ? "bg-gray-100 text-gray-400 cursor-not-allowed"
108
- : "bg-white cursor-pointer", errorMessage
109
- ? "border-error"
110
- : isOpen
111
- ? "border-primary"
112
- : "border-gray-200", buttonClassName), children: [multiselect ? (selectedOptions.length ? (_jsx("div", { className: "flex flex-wrap gap-2", id: name, children: renderSelectedChips() })) : (renderPlaceholder())) : selectedOptions[0] ? (_jsx("div", { className: "text-text truncate line-clamp-1", children: selectedOptions[0].label })) : (renderPlaceholder()), _jsxs("div", { className: "flex items-center gap-1", children: [!disabled &&
113
- (multiselect
114
- ? selectedOptions.length > 0
115
- : !!selectedOptions[0]) && (_jsx("button", { type: "button", onClick: handleClear, title: "Clear selection", className: "text-gray-500 hover:text-primary", children: _jsx(Icon, { icon: "line-md:close-small", className: "w-5 h-5" }) })), _jsx(Icon, { icon: "iconamoon:arrow-down-2", className: clsx("transition-transform duration-200", isOpen && "rotate-180") })] })] }), show && !disabled && (_jsxs("div", { className: clsx("absolute left-0 mt-1 z-50 bg-white border border-gray-200 rounded-md shadow-lg max-h-64 overflow-auto max-w-[360px] min-w-[260px] w-full transition-all duration-200 ease-out", animate
116
- ? "opacity-100 translate-y-0 scale-100"
117
- : "opacity-0 -translate-y-1 scale-95"), children: [isSearchable && (_jsxs("div", { className: "sticky top-0 bg-white border-b border-gray-100 px-2 py-1 flex items-center gap-2", onClick: (e) => e.stopPropagation(), children: [_jsx(Icon, { icon: "mdi:magnify", className: "text-gray-500 w-5 h-5" }), _jsx("input", { type: "text", placeholder: "Search...", value: search, onChange: handleSearchInputChange, className: "w-full outline-none text-sm bg-transparent py-1" })] })), filteredOptions.length > 0 ? (filteredOptions.map((o, i) => {
118
- const isSelected = selectedOptions.some((s) => Object.is(s.value, o.value));
119
- return (_jsxs("div", { onClick: () => {
120
- setSearch("");
121
- toggleOption(o);
122
- }, className: clsx("mx-1 px-3 py-2 cursor-pointer flex items-center gap-2 rounded text-sm hover:text-primary hover:bg-primary/20", isSelected && "bg-primary/10 text-primary"), children: [isSelected ? (_jsx(Icon, { icon: "mdi:check", className: "w-4 h-4 text-primary" })) : (_jsx("div", { className: "w-4 h-4" })), o.label] }, `${name}-option-${i}`));
123
- })) : (_jsx("div", { className: "px-3 py-2 text-gray-400 text-sm", children: "No results" }))] }))] }), errorMessage && (_jsx("p", { className: "pl-1 text-sm text-error", children: errorMessage }))] }));
84
+ return (_jsx(SelectView, { label: label, required: required, errorMessage: errorMessage, containerRef: containerRef, menuRef: menuRef, disabled: disabled, isOpen: isOpen, buttonClassName: buttonClassName, onToggle: () => setIsOpen((o) => !o), multiselect: multiselect, selectedOptions: selectedOptions, placeholder: placeholder, IconPlaceholderLeft: IconPlaceholderLeft, onClear: handleClear, name: name, show: show, usePortal: usePortal, dropdownClassName: dropdownClassName, animate: animate, menuPos: menuPos, isSearchable: isSearchable, search: search, onChangeSearchInput: handleSearchInputChange, filteredOptions: filteredOptions, onOptionClick: (o) => {
85
+ setSearch("");
86
+ toggleOption(o);
87
+ }, desiredMax: desiredMax }));
124
88
  }
@@ -0,0 +1,27 @@
1
+ export type MenuPosition = {
2
+ left: number;
3
+ top: number;
4
+ width: number;
5
+ maxHeight: number;
6
+ placement: "top" | "bottom";
7
+ };
8
+ export declare const DEFAULT_GAP = 4;
9
+ export declare const DEFAULT_DESIRED_MAX = 256;
10
+ export declare function useSelectPortal(params: {
11
+ isOpen: boolean;
12
+ usePortal: boolean;
13
+ containerRef: React.RefObject<HTMLDivElement>;
14
+ menuRef: React.RefObject<HTMLDivElement>;
15
+ heightDeps?: unknown[];
16
+ gap?: number;
17
+ desiredMax?: number;
18
+ scrollDebounceMs?: number;
19
+ }): {
20
+ readonly show: boolean;
21
+ readonly animate: boolean;
22
+ readonly menuPos: MenuPosition;
23
+ readonly updateMenuPosition: () => void;
24
+ readonly gap: number;
25
+ readonly desiredMax: number;
26
+ };
27
+ //# sourceMappingURL=useSelectPortal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSelectPortal.d.ts","sourceRoot":"","sources":["../../../src/components/select/useSelectPortal.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,KAAK,GAAG,QAAQ,CAAC;CAC7B,CAAC;AAEF,eAAO,MAAM,WAAW,IAAI,CAAC;AAC7B,eAAO,MAAM,mBAAmB,MAAM,CAAC;AAKvC,wBAAgB,eAAe,CAAC,MAAM,EAAE;IACtC,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;IAC9C,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;IACzC,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC;IACvB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;;;;;;;EAiIA"}
@@ -0,0 +1,110 @@
1
+ import { useCallback, useEffect, useLayoutEffect, useRef, useState, } from "react";
2
+ export const DEFAULT_GAP = 4;
3
+ export const DEFAULT_DESIRED_MAX = 256; // px
4
+ const clamp = (val, min, max) => Math.max(min, Math.min(val, max));
5
+ export function useSelectPortal(params) {
6
+ const { isOpen, usePortal, containerRef, menuRef, heightDeps = [], gap = DEFAULT_GAP, desiredMax = DEFAULT_DESIRED_MAX, scrollDebounceMs = 120, } = params;
7
+ const [show, setShow] = useState(false);
8
+ const [animate, setAnimate] = useState(false);
9
+ const [menuPos, setMenuPos] = useState({
10
+ left: 0,
11
+ top: 0,
12
+ width: 0,
13
+ maxHeight: desiredMax,
14
+ placement: "bottom",
15
+ });
16
+ const scrollEndTimerRef = useRef(null);
17
+ const updateMenuPosition = useCallback(() => {
18
+ const trigger = containerRef.current;
19
+ if (!trigger)
20
+ return;
21
+ const rect = trigger.getBoundingClientRect();
22
+ const vw = window.innerWidth;
23
+ const vh = window.innerHeight;
24
+ const spaceBelow = vh - rect.bottom;
25
+ const spaceAbove = rect.top;
26
+ const shouldFlip = spaceBelow < 160 && spaceAbove > spaceBelow;
27
+ const placement = shouldFlip ? "top" : "bottom";
28
+ const maxHeight = Math.min(desiredMax, Math.max((shouldFlip ? spaceAbove : spaceBelow) - gap, 120));
29
+ const width = rect.width;
30
+ const rawLeft = usePortal ? rect.left : rect.left + window.scrollX;
31
+ const left = clamp(rawLeft, 8, vw - width - 8);
32
+ const top = shouldFlip
33
+ ? usePortal
34
+ ? rect.top - gap - maxHeight
35
+ : rect.top + window.scrollY - gap - maxHeight
36
+ : usePortal
37
+ ? rect.bottom + gap
38
+ : rect.bottom + window.scrollY + gap;
39
+ setMenuPos({ left, top, width, maxHeight, placement });
40
+ }, [containerRef, usePortal, gap, desiredMax]);
41
+ // Refine top when placement is top (after actual height known)
42
+ useLayoutEffect(() => {
43
+ if (!isOpen)
44
+ return;
45
+ if (!menuRef.current || menuPos.placement !== "top")
46
+ return;
47
+ const trigger = containerRef.current;
48
+ if (!trigger)
49
+ return;
50
+ const rect = trigger.getBoundingClientRect();
51
+ const actualHeight = menuRef.current.offsetHeight || menuPos.maxHeight;
52
+ const correctedTop = usePortal
53
+ ? rect.top - gap - actualHeight
54
+ : rect.top + window.scrollY - gap - actualHeight;
55
+ if (Math.abs(correctedTop - menuPos.top) > 1) {
56
+ setMenuPos((prev) => ({ ...prev, top: correctedTop }));
57
+ }
58
+ // include values that change height so we re-evaluate when content changes
59
+ // eslint-disable-next-line react-hooks/exhaustive-deps
60
+ }, [
61
+ isOpen,
62
+ usePortal,
63
+ menuPos.placement,
64
+ menuPos.top,
65
+ menuPos.maxHeight,
66
+ containerRef,
67
+ menuRef,
68
+ gap,
69
+ ...heightDeps,
70
+ ]);
71
+ // Open/close lifecycle + resize/scroll handling
72
+ useEffect(() => {
73
+ if (isOpen) {
74
+ setShow(true);
75
+ updateMenuPosition();
76
+ const onResize = () => updateMenuPosition();
77
+ const onAnyScroll = () => {
78
+ if (scrollEndTimerRef.current)
79
+ window.clearTimeout(scrollEndTimerRef.current);
80
+ scrollEndTimerRef.current = window.setTimeout(() => {
81
+ updateMenuPosition();
82
+ }, scrollDebounceMs);
83
+ };
84
+ window.addEventListener("resize", onResize);
85
+ document.addEventListener("scroll", onAnyScroll, true);
86
+ requestAnimationFrame(() => setAnimate(true));
87
+ return () => {
88
+ window.removeEventListener("resize", onResize);
89
+ document.removeEventListener("scroll", onAnyScroll, true);
90
+ if (scrollEndTimerRef.current) {
91
+ window.clearTimeout(scrollEndTimerRef.current);
92
+ scrollEndTimerRef.current = null;
93
+ }
94
+ };
95
+ }
96
+ else {
97
+ setAnimate(false);
98
+ const t = setTimeout(() => setShow(false), 200);
99
+ return () => clearTimeout(t);
100
+ }
101
+ }, [isOpen, updateMenuPosition, scrollDebounceMs]);
102
+ return {
103
+ show,
104
+ animate,
105
+ menuPos,
106
+ updateMenuPosition,
107
+ gap,
108
+ desiredMax,
109
+ };
110
+ }
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-/index.tsx"],"names":[],"mappings":""}
File without changes
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-has-permission-access/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAIjD,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,SAAS,CAAC,UAAU,CAAC,cAAc,GAC9C,OAAO,CAOT;AAED,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,SAAS,CAAC,UAAU,CAAC,cAAc,EAAE,GACjD,OAAO,CAST"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-has-permission-access/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAIjD,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,SAAS,CAAC,UAAU,CAAC,cAAc,GAC9C,OAAO,CAQT;AAED,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,SAAS,CAAC,UAAU,CAAC,cAAc,EAAE,GACjD,OAAO,CAUT"}
@@ -5,12 +5,16 @@ import { jwtDecode } from "../../utils/jwt";
5
5
  export function useHasPermission(permission) {
6
6
  var _a, _b;
7
7
  const accessToken = getCookie(CONSTANTS.JWT.JWTCookieKey);
8
+ if (!accessToken || accessToken === undefined)
9
+ return false;
8
10
  const payload = jwtDecode(accessToken);
9
11
  return (_b = (_a = payload === null || payload === void 0 ? void 0 : payload.permissionKeys) === null || _a === void 0 ? void 0 : _a.includes(permission)) !== null && _b !== void 0 ? _b : false;
10
12
  }
11
13
  export function useHasOneOfPermissions(permissions) {
12
14
  var _a, _b;
13
15
  const accessToken = getCookie(CONSTANTS.JWT.JWTCookieKey);
16
+ if (!accessToken || accessToken === undefined)
17
+ return false;
14
18
  const payload = jwtDecode(accessToken);
15
19
  return ((_b = (_a = payload === null || payload === void 0 ? void 0 : payload.permissionKeys) === null || _a === void 0 ? void 0 : _a.some((item) => permissions.includes(item))) !== null && _b !== void 0 ? _b : false);
16
20
  }
@@ -0,0 +1,2 @@
1
+ export declare function useInterval(callback: () => void, delay: number | null): void;
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-interval/index.tsx"],"names":[],"mappings":"AAGA,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,QAcrE"}
@@ -0,0 +1,16 @@
1
+ "use client";
2
+ import { useEffect, useRef } from "react";
3
+ export function useInterval(callback, delay) {
4
+ const savedCallback = useRef(callback);
5
+ // Remember the latest callback
6
+ useEffect(() => {
7
+ savedCallback.current = callback;
8
+ }, [callback]);
9
+ // Set up the interval
10
+ useEffect(() => {
11
+ if (delay === null)
12
+ return; // allow pausing
13
+ const id = setInterval(() => savedCallback.current(), delay);
14
+ return () => clearInterval(id);
15
+ }, [delay]);
16
+ }
@@ -0,0 +1,7 @@
1
+ type Options = {
2
+ interval?: number;
3
+ onTokenMissing: () => void;
4
+ };
5
+ export declare function useTokenWatcher({ interval, onTokenMissing }: Options): void;
6
+ export {};
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hooks/use-token-watcher/index.tsx"],"names":[],"mappings":"AAKA,KAAK,OAAO,GAAG;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,IAAI,CAAC;CAC5B,CAAC;AAEF,wBAAgB,eAAe,CAAC,EAAE,QAAe,EAAE,cAAc,EAAE,EAAE,OAAO,QAoB3E"}
@@ -0,0 +1,23 @@
1
+ "use client";
2
+ import { useEffect } from "react";
3
+ import { CONSTANTS } from "sea-platform-helpers";
4
+ import { getCookie } from "../../utils/cookie";
5
+ export function useTokenWatcher({ interval = 3000, onTokenMissing }) {
6
+ useEffect(() => {
7
+ let lastToken = getCookie(CONSTANTS.JWT.JWTCookieKey);
8
+ const id = setInterval(() => {
9
+ console.log("Watching the token");
10
+ const currentToken = getCookie(CONSTANTS.JWT.JWTCookieKey);
11
+ console.log({
12
+ lastToken,
13
+ currentToken,
14
+ });
15
+ if (!currentToken && lastToken) {
16
+ console.log("[MustAuth] Token disappeared — triggering noTokenHandler");
17
+ onTokenMissing();
18
+ }
19
+ lastToken = currentToken;
20
+ }, interval);
21
+ return () => clearInterval(id);
22
+ }, [onTokenMissing, interval]);
23
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hooks/user-has-application-access/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAIjD,wBAAgB,uBAAuB,CACrC,cAAc,EAAE,SAAS,CAAC,WAAW,CAAC,eAAe,GACpD,OAAO,CAOT"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hooks/user-has-application-access/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAIjD,wBAAgB,uBAAuB,CACrC,cAAc,EAAE,SAAS,CAAC,WAAW,CAAC,eAAe,GACpD,OAAO,CAST"}
@@ -5,6 +5,8 @@ import { jwtDecode } from "../../utils/jwt";
5
5
  export function useHasApplicationAccess(applicationKey) {
6
6
  var _a, _b;
7
7
  const accessToken = getCookie(CONSTANTS.JWT.JWTCookieKey);
8
+ if (!accessToken || accessToken === undefined)
9
+ return false;
8
10
  const payload = jwtDecode(accessToken);
9
11
  return (_b = (_a = payload.applicationKeys) === null || _a === void 0 ? void 0 : _a.includes(applicationKey)) !== null && _b !== void 0 ? _b : false;
10
12
  }
@@ -1 +1 @@
1
- {"root":["../src/index.ts","../src/hoc/can-access-application/index.tsx","../src/hoc/with-authorization/index.tsx","../src/components/accordion/index.tsx","../src/components/activity-message/index.tsx","../src/components/alert/index.tsx","../src/components/auto-complete/auto-complete-context.tsx","../src/components/auto-complete/auto-complete-dropdown.tsx","../src/components/auto-complete/auto-complete-input.tsx","../src/components/auto-complete/auto-complete-selected.tsx","../src/components/auto-complete/auto-complete.tsx","../src/components/auto-complete/index.tsx","../src/components/auto-complete/use-autocomplete.ts","../src/components/auto-complete-input/index.tsx","../src/components/avatar/index.tsx","../src/components/badge/index.tsx","../src/components/breadcrumb/index.tsx","../src/components/break-line/index.tsx","../src/components/button/index.tsx","../src/components/calendar/index.tsx","../src/components/cards-list/index.tsx","../src/components/carousel/index.tsx","../src/components/checkbox/index.tsx","../src/components/color-picker/index.tsx","../src/components/comments-container/index.tsx","../src/components/comments-container/comment-event-bus/index.ts","../src/components/comments-container/comment-form/index.tsx","../src/components/comments-container/comment-item/index.tsx","../src/components/comments-container/comments-list/index.tsx","../src/components/comments-container/constants/index.ts","../src/components/comments-container/use-comments/index.tsx","../src/components/confirm/index.tsx","../src/components/count-down/index.tsx","../src/components/day-calendar/index.tsx","../src/components/drawer/index.tsx","../src/components/editable-text/index.tsx","../src/components/expandable-text/index.tsx","../src/components/file-input/index.tsx","../src/components/file-input/components/file-item/index.tsx","../src/components/firebase-token-handler/index.tsx","../src/components/icon/index.tsx","../src/components/input/index.tsx","../src/components/item-not-found/index.tsx","../src/components/list-item/index.tsx","../src/components/list-item/components/page-button/index.tsx","../src/components/list-item/components/pagination/index.tsx","../src/components/loader/index.tsx","../src/components/menu/index.tsx","../src/components/menu/menu-item/index.tsx","../src/components/modal/index.tsx","../src/components/month-calendar/index.tsx","../src/components/native-menu/index.tsx","../src/components/native-menu/native-menu-item/index.tsx","../src/components/not-authorized/index.tsx","../src/components/notifications-menu/index.tsx","../src/components/otp-input/index.tsx","../src/components/paper/index.tsx","../src/components/progress-bar/index.tsx","../src/components/radio-button/index.tsx","../src/components/search-input/index.tsx","../src/components/searchable-select/index.tsx","../src/components/select/index.tsx","../src/components/skeleton/index.tsx","../src/components/stacked-avatars/index.tsx","../src/components/tab/index.tsx","../src/components/table/index.tsx","../src/components/text-editor/index.tsx","../src/components/text-editor/components/toolbar/index.tsx","../src/components/text-editor/utils/index.ts","../src/components/textarea/index.tsx","../src/components/toggle/index.tsx","../src/components/tooltip/index.tsx","../src/components/tree-checkbox/index.tsx","../src/components/tree-checkbox/components/tree-checkbox-item/index.tsx","../src/components/tree-checkbox/utils/index.ts","../src/components/week-calendar/index.tsx","../src/constants/index.ts","../src/hooks/list-items-hook/types.ts","../src/hooks/list-items-hook/usebulkactions.ts","../src/hooks/list-items-hook/usefilters.ts","../src/hooks/list-items-hook/usepagination.ts","../src/hooks/use-has-permission-access/index.ts","../src/hooks/user-has-application-access/index.ts","../src/middleware/must-auth/index.tsx","../src/utils/auth-axios/index.ts","../src/utils/axios/index.ts","../src/utils/color/index.ts","../src/utils/cookie/index.ts","../src/utils/device/index.ts","../src/utils/file/index.ts","../src/utils/firebase-client/firebase.ts","../src/utils/firebase-client/index.ts","../src/utils/firebase-client/types.ts","../src/utils/jwt/index.ts","../src/utils/notification-localstorage/index.ts","../src/utils/validation/index.ts"],"version":"5.6.3"}
1
+ {"root":["../src/index.ts","../src/hoc/can-access-application/index.tsx","../src/hoc/with-authorization/index.tsx","../src/components/accordion/index.tsx","../src/components/activity-message/index.tsx","../src/components/alert/index.tsx","../src/components/auto-complete/auto-complete-context.tsx","../src/components/auto-complete/auto-complete-dropdown.tsx","../src/components/auto-complete/auto-complete-input.tsx","../src/components/auto-complete/auto-complete-selected.tsx","../src/components/auto-complete/auto-complete.tsx","../src/components/auto-complete/index.tsx","../src/components/auto-complete/use-autocomplete.ts","../src/components/auto-complete-input/index.tsx","../src/components/avatar/index.tsx","../src/components/badge/index.tsx","../src/components/breadcrumb/index.tsx","../src/components/break-line/index.tsx","../src/components/button/index.tsx","../src/components/calendar/index.tsx","../src/components/cards-list/index.tsx","../src/components/carousel/index.tsx","../src/components/checkbox/index.tsx","../src/components/color-picker/index.tsx","../src/components/comments-container/index.tsx","../src/components/comments-container/comment-event-bus/index.ts","../src/components/comments-container/comment-form/index.tsx","../src/components/comments-container/comment-item/index.tsx","../src/components/comments-container/comments-list/index.tsx","../src/components/comments-container/constants/index.ts","../src/components/comments-container/use-comments/index.tsx","../src/components/confirm/index.tsx","../src/components/count-down/index.tsx","../src/components/day-calendar/index.tsx","../src/components/drawer/index.tsx","../src/components/editable-text/index.tsx","../src/components/expandable-text/index.tsx","../src/components/file-input/index.tsx","../src/components/file-input/components/file-item/index.tsx","../src/components/firebase-token-handler/index.tsx","../src/components/icon/index.tsx","../src/components/input/index.tsx","../src/components/item-not-found/index.tsx","../src/components/list-item/index.tsx","../src/components/list-item/components/page-button/index.tsx","../src/components/list-item/components/pagination/index.tsx","../src/components/loader/index.tsx","../src/components/menu/index.tsx","../src/components/menu/menu-item/index.tsx","../src/components/modal/index.tsx","../src/components/month-calendar/index.tsx","../src/components/native-menu/index.tsx","../src/components/native-menu/native-menu-item/index.tsx","../src/components/not-authorized/index.tsx","../src/components/notifications-menu/index.tsx","../src/components/otp-input/index.tsx","../src/components/paper/index.tsx","../src/components/progress-bar/index.tsx","../src/components/radio-button/index.tsx","../src/components/search-input/index.tsx","../src/components/searchable-select/index.tsx","../src/components/select/selectchips.tsx","../src/components/select/selectcontrol.tsx","../src/components/select/selectdropdowncontent.tsx","../src/components/select/selectplaceholder.tsx","../src/components/select/selecttypes.ts","../src/components/select/selectview.tsx","../src/components/select/index.tsx","../src/components/select/useselectportal.ts","../src/components/skeleton/index.tsx","../src/components/stacked-avatars/index.tsx","../src/components/tab/index.tsx","../src/components/table/index.tsx","../src/components/text-editor/index.tsx","../src/components/text-editor/components/toolbar/index.tsx","../src/components/text-editor/utils/index.ts","../src/components/textarea/index.tsx","../src/components/toggle/index.tsx","../src/components/tooltip/index.tsx","../src/components/tree-checkbox/index.tsx","../src/components/tree-checkbox/components/tree-checkbox-item/index.tsx","../src/components/tree-checkbox/utils/index.ts","../src/components/week-calendar/index.tsx","../src/constants/index.ts","../src/hooks/list-items-hook/types.ts","../src/hooks/list-items-hook/usebulkactions.ts","../src/hooks/list-items-hook/usefilters.ts","../src/hooks/list-items-hook/usepagination.ts","../src/hooks/use-has-permission-access/index.ts","../src/hooks/user-has-application-access/index.ts","../src/middleware/must-auth/index.tsx","../src/utils/auth-axios/index.ts","../src/utils/axios/index.ts","../src/utils/color/index.ts","../src/utils/cookie/index.ts","../src/utils/device/index.ts","../src/utils/file/index.ts","../src/utils/firebase-client/firebase.ts","../src/utils/firebase-client/index.ts","../src/utils/firebase-client/types.ts","../src/utils/jwt/index.ts","../src/utils/notification-localstorage/index.ts","../src/utils/validation/index.ts"],"version":"5.6.3"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/axios/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAoC,MAAM,OAAO,CAAC;AAKzD,KAAK,YAAY,GAAG;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,OAAO,CAAC,EAAE,cAAc,GAAG,QAAQ,CAAC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,eAAO,MAAM,cAAc,YAChB,MAAM,YACN,YAAY,kCA6DtB,CAAC;AAEF,eAAe,KAAK,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/axios/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAoC,MAAM,OAAO,CAAC;AAKzD,KAAK,YAAY,GAAG;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,OAAO,CAAC,EAAE,cAAc,GAAG,QAAQ,CAAC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,eAAO,MAAM,cAAc,YAChB,MAAM,YACN,YAAY,kCAiEtB,CAAC;AAEF,eAAe,KAAK,CAAC"}
@@ -43,6 +43,9 @@ export const createInstance = (baseURL, options = {
43
43
  ].includes(message)) {
44
44
  console.log("Unauthenticated or invalid input - logging out");
45
45
  removeCookie(options.JWTTokenKey);
46
+ setTimeout(() => {
47
+ window.location.reload();
48
+ }, 2000);
46
49
  }
47
50
  return Promise.reject((_d = error.response) === null || _d === void 0 ? void 0 : _d.data);
48
51
  });
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/cookie/index.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,SAAS,SAAU,MAAM,KAAG,MAAM,GAAG,SAMjD,CAAC;AAEF,eAAO,MAAM,SAAS,SACd,MAAM,SACL,MAAM,YACH;IACR,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;CACtC,KACA,IAiBF,CAAC;AAEF,eAAO,MAAM,YAAY,SAAU,MAAM,KAAG,IAa3C,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/cookie/index.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,SAAS,SAAU,MAAM,KAAG,MAAM,GAAG,SAMjD,CAAC;AAEF,eAAO,MAAM,SAAS,SACd,MAAM,SACL,MAAM,YACH;IACR,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;CACtC,KACA,IAiBF,CAAC;AAEF,eAAO,MAAM,YAAY,SAAU,MAAM,KAAG,IAiB3C,CAAC"}
@@ -26,9 +26,11 @@ export const setCookie = (name, value, options) => {
26
26
  document.cookie = cookie;
27
27
  };
28
28
  export const removeCookie = (name) => {
29
+ console.log("removeCookie: ", name);
29
30
  // Try removing it for all common scopes
30
31
  const domains = [window.location.hostname, `.${window.location.hostname}`];
31
32
  const paths = ["/", ""];
33
+ console.log({ domains, paths });
32
34
  domains.forEach((domain) => {
33
35
  paths.forEach((path) => {
34
36
  document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=${path}; domain=${domain};`;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "sea-react-components",
3
3
  "description": "SEA react components library",
4
- "version": "1.3.20",
4
+ "version": "1.3.22",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
7
7
  "build": "tsc --build && npx postcss src/styles.css -o dist/styles.css && npx postcss src/components/text-editor/style.css -o dist/components/text-editor/style.css",
@@ -48,7 +48,7 @@
48
48
  "jwt-decode": "^4.0.0",
49
49
  "lowlight": "^3.3.0",
50
50
  "react-dom": "^18.3.1",
51
- "sea-platform-helpers": "^1.5.18",
51
+ "sea-platform-helpers": "^1.5.19",
52
52
  "sea-react-components": "file:",
53
53
  "uuid": "^13.0.0",
54
54
  "yup": "^1.5.0"