@mieweb/ui 0.9.0-dev.0 → 0.9.0-dev.1

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 (31) hide show
  1. package/dist/{chunk-WIAQQNFU.cjs → chunk-2A2FLQJC.cjs} +1138 -12
  2. package/dist/chunk-2A2FLQJC.cjs.map +1 -0
  3. package/dist/{chunk-5BVFVXHN.cjs → chunk-5VXRKOPR.cjs} +16 -525
  4. package/dist/chunk-5VXRKOPR.cjs.map +1 -0
  5. package/dist/{chunk-O6GJ4IYS.js → chunk-IF3X2WZP.js} +16 -521
  6. package/dist/chunk-IF3X2WZP.js.map +1 -0
  7. package/dist/{chunk-22CYDCXA.js → chunk-KATEJG2F.js} +1137 -13
  8. package/dist/chunk-KATEJG2F.js.map +1 -0
  9. package/dist/{chunk-FQBTGS3E.cjs → chunk-O425FKDI.cjs} +563 -55
  10. package/dist/chunk-O425FKDI.cjs.map +1 -0
  11. package/dist/{chunk-MXQ7J4BB.js → chunk-RPG2ZP2T.js} +557 -53
  12. package/dist/chunk-RPG2ZP2T.js.map +1 -0
  13. package/dist/components/SuperChat/index.cjs +36 -17
  14. package/dist/components/SuperChat/index.cjs.map +1 -1
  15. package/dist/components/SuperChat/index.d.cts +16 -3
  16. package/dist/components/SuperChat/index.d.ts +16 -3
  17. package/dist/components/SuperChat/index.js +31 -12
  18. package/dist/components/SuperChat/index.js.map +1 -1
  19. package/dist/components/SuperChat/plugins/index.cjs +3 -3
  20. package/dist/components/SuperChat/plugins/index.js +2 -2
  21. package/dist/index.cjs +820 -1930
  22. package/dist/index.cjs.map +1 -1
  23. package/dist/index.js +663 -1780
  24. package/dist/index.js.map +1 -1
  25. package/package.json +1 -1
  26. package/dist/chunk-22CYDCXA.js.map +0 -1
  27. package/dist/chunk-5BVFVXHN.cjs.map +0 -1
  28. package/dist/chunk-FQBTGS3E.cjs.map +0 -1
  29. package/dist/chunk-MXQ7J4BB.js.map +0 -1
  30. package/dist/chunk-O6GJ4IYS.js.map +0 -1
  31. package/dist/chunk-WIAQQNFU.cjs.map +0 -1
@@ -1,8 +1,7 @@
1
1
  import { cn } from './chunk-TQONQSJO.js';
2
2
  import { useAnchoredPosition } from './chunk-WSNMQQ4P.js';
3
- import * as React3 from 'react';
3
+ import * as React from 'react';
4
4
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
5
- import { cva } from 'class-variance-authority';
6
5
  import { createPortal } from 'react-dom';
7
6
 
8
7
  function getFileType(mimeType) {
@@ -249,7 +248,7 @@ function AttachmentPreviewItem({
249
248
  );
250
249
  }
251
250
  AttachmentPreviewItem.displayName = "AttachmentPreviewItem";
252
- var AttachmentPicker = React3.forwardRef(
251
+ var AttachmentPicker = React.forwardRef(
253
252
  ({
254
253
  onFilesSelected,
255
254
  acceptedTypes = ["image/*", "video/*", ".pdf", ".doc", ".docx"],
@@ -262,8 +261,8 @@ var AttachmentPicker = React3.forwardRef(
262
261
  className,
263
262
  children
264
263
  }, ref) => {
265
- const inputRef = React3.useRef(null);
266
- React3.useImperativeHandle(ref, () => inputRef.current);
264
+ const inputRef = React.useRef(null);
265
+ React.useImperativeHandle(ref, () => inputRef.current);
267
266
  const handleClick = () => {
268
267
  inputRef.current?.click();
269
268
  };
@@ -356,8 +355,8 @@ function DragDropZone({
356
355
  children,
357
356
  className
358
357
  }) {
359
- const [isDragging, setIsDragging] = React3.useState(false);
360
- const dragCounterRef = React3.useRef(0);
358
+ const [isDragging, setIsDragging] = React.useState(false);
359
+ const dragCounterRef = React.useRef(0);
361
360
  const handleDragEnter = (event) => {
362
361
  event.preventDefault();
363
362
  event.stopPropagation();
@@ -459,7 +458,7 @@ function CameraButton({
459
458
  disabled = false,
460
459
  className
461
460
  }) {
462
- const inputRef = React3.useRef(null);
461
+ const inputRef = React.useRef(null);
463
462
  const handleClick = () => {
464
463
  inputRef.current?.click();
465
464
  };
@@ -551,14 +550,14 @@ function useMentionAutocomplete({
551
550
  textareaRef
552
551
  }) {
553
552
  const enabled = !!options && options.length > 0;
554
- const [mention, setMention] = React3.useState(null);
555
- const [highlight, setHighlight] = React3.useState(0);
556
- const listId = React3.useId();
557
- const optionId = React3.useCallback(
553
+ const [mention, setMention] = React.useState(null);
554
+ const [highlight, setHighlight] = React.useState(0);
555
+ const listId = React.useId();
556
+ const optionId = React.useCallback(
558
557
  (index) => `${listId}-option-${index}`,
559
558
  [listId]
560
559
  );
561
- const suggestions = React3.useMemo(() => {
560
+ const suggestions = React.useMemo(() => {
562
561
  if (!mention || !options) return [];
563
562
  const q = mention.query.toLowerCase();
564
563
  return options.filter((o) => o.label.toLowerCase().includes(q));
@@ -575,7 +574,7 @@ function useMentionAutocomplete({
575
574
  });
576
575
  const clampedHighlight = menuOpen ? Math.min(highlight, suggestions.length - 1) : -1;
577
576
  const activeOptionId = menuOpen ? optionId(clampedHighlight) : void 0;
578
- const sync = React3.useCallback(
577
+ const sync = React.useCallback(
579
578
  (nextValue, caret) => {
580
579
  if (!enabled) return;
581
580
  setMention(activeMentionQuery(nextValue, caret));
@@ -700,511 +699,7 @@ function MentionMenu({
700
699
  );
701
700
  }
702
701
  MentionMenu.displayName = "MentionMenu";
703
- function isFileAccepted(file, accepted) {
704
- if (!accepted || accepted.length === 0) return true;
705
- const mime = file.type;
706
- const name = file.name.toLowerCase();
707
- return accepted.some((token) => {
708
- if (token.startsWith(".")) return name.endsWith(token.toLowerCase());
709
- if (token.endsWith("/*")) return mime.startsWith(token.slice(0, -1));
710
- if (token.includes("/")) return mime === token;
711
- return false;
712
- });
713
- }
714
- function CharacterCounter({
715
- current,
716
- max,
717
- showWarningAt = 0.9,
718
- className
719
- }) {
720
- const percentage = current / max;
721
- const isWarning = percentage >= showWarningAt && percentage < 1;
722
- const isOver = current > max;
723
- return /* @__PURE__ */ jsxs(
724
- "span",
725
- {
726
- className: cn(
727
- "text-xs tabular-nums",
728
- isOver ? "font-medium text-red-700 dark:text-red-400" : isWarning ? "text-amber-700 dark:text-amber-400" : "text-neutral-600 dark:text-neutral-400",
729
- className
730
- ),
731
- "aria-live": "polite",
732
- "aria-label": `${current} of ${max} characters`,
733
- children: [
734
- current,
735
- "/",
736
- max
737
- ]
738
- }
739
- );
740
- }
741
- CharacterCounter.displayName = "CharacterCounter";
742
- var sendButtonVariants = cva(
743
- [
744
- "inline-flex items-center justify-center",
745
- "rounded-full p-3 self-start",
746
- "transition-all duration-200",
747
- "focus:outline-none focus:ring-2 focus:ring-primary-500",
748
- "disabled:opacity-50 disabled:cursor-not-allowed"
749
- ],
750
- {
751
- variants: {
752
- variant: {
753
- primary: [
754
- "bg-primary-800 text-white",
755
- "hover:bg-primary-900",
756
- "active:scale-95"
757
- ],
758
- subtle: [
759
- "bg-transparent text-primary-800",
760
- "hover:bg-primary-50 dark:hover:bg-primary-900/20"
761
- ]
762
- },
763
- canSend: {
764
- true: "",
765
- false: "opacity-50 cursor-not-allowed"
766
- }
767
- },
768
- defaultVariants: {
769
- variant: "primary",
770
- canSend: false
771
- }
772
- }
773
- );
774
- var SendButton = React3.forwardRef(
775
- ({ className, variant, canSend, isLoading, disabled, ...props }, ref) => {
776
- return /* @__PURE__ */ jsx(
777
- "button",
778
- {
779
- ref,
780
- type: "submit",
781
- disabled: disabled || !canSend || isLoading,
782
- "data-slot": "composer-send-button",
783
- className: cn(sendButtonVariants({ variant, canSend }), className),
784
- "aria-label": isLoading ? "Sending message" : "Send message",
785
- ...props,
786
- children: isLoading ? /* @__PURE__ */ jsxs(
787
- "svg",
788
- {
789
- "aria-hidden": "true",
790
- className: "h-5 w-5 animate-spin",
791
- fill: "none",
792
- viewBox: "0 0 24 24",
793
- children: [
794
- /* @__PURE__ */ jsx(
795
- "circle",
796
- {
797
- className: "opacity-25",
798
- cx: "12",
799
- cy: "12",
800
- r: "10",
801
- stroke: "currentColor",
802
- strokeWidth: "4"
803
- }
804
- ),
805
- /* @__PURE__ */ jsx(
806
- "path",
807
- {
808
- className: "opacity-75",
809
- fill: "currentColor",
810
- d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
811
- }
812
- )
813
- ]
814
- }
815
- ) : /* @__PURE__ */ jsx(
816
- "svg",
817
- {
818
- "aria-hidden": "true",
819
- className: "h-5 w-5",
820
- fill: "none",
821
- viewBox: "0 0 24 24",
822
- stroke: "currentColor",
823
- children: /* @__PURE__ */ jsx(
824
- "path",
825
- {
826
- strokeLinecap: "round",
827
- strokeLinejoin: "round",
828
- strokeWidth: 2,
829
- d: "M12 19l9 2-9-18-9 18 9-2zm0 0v-8"
830
- }
831
- )
832
- }
833
- )
834
- }
835
- );
836
- }
837
- );
838
- SendButton.displayName = "SendButton";
839
- var MessageComposer = React3.forwardRef(
840
- ({
841
- onSend,
842
- onTypingStart,
843
- onTypingStop,
844
- value: controlledValue,
845
- onValueChange,
846
- placeholder = "Type a message...",
847
- maxLength = 1600,
848
- showCharacterCount = false,
849
- disabled = false,
850
- isSending = false,
851
- showAttachmentPicker = true,
852
- showCameraButton = false,
853
- acceptedFileTypes = ["image/*", "video/*", ".pdf", ".doc", ".docx"],
854
- maxFileSize = 25 * 1024 * 1024,
855
- maxAttachments = 10,
856
- onError,
857
- autoFocus = false,
858
- replyTo = null,
859
- onCancelReply,
860
- variant = "default",
861
- inputTrailing,
862
- mentionOptions,
863
- className
864
- }, ref) => {
865
- const textareaRef = React3.useRef(null);
866
- const [internalContent, setInternalContent] = React3.useState("");
867
- const isControlled = controlledValue !== void 0;
868
- const content = isControlled ? controlledValue : internalContent;
869
- const setContent = React3.useCallback(
870
- (val) => {
871
- if (isControlled) {
872
- const newVal = typeof val === "function" ? val(controlledValue) : val;
873
- onValueChange?.(newVal);
874
- } else {
875
- setInternalContent(val);
876
- }
877
- },
878
- [isControlled, controlledValue, onValueChange]
879
- );
880
- const [attachments, setAttachments] = React3.useState(
881
- []
882
- );
883
- const [isTyping, setIsTyping] = React3.useState(false);
884
- const typingTimeoutRef = React3.useRef(null);
885
- React3.useImperativeHandle(ref, () => textareaRef.current);
886
- React3.useEffect(() => {
887
- const textarea = textareaRef.current;
888
- if (textarea) {
889
- textarea.style.height = "auto";
890
- textarea.style.height = `${Math.min(textarea.scrollHeight, 150)}px`;
891
- }
892
- }, [content]);
893
- React3.useEffect(() => {
894
- if (content.length > 0 && !isTyping) {
895
- setIsTyping(true);
896
- onTypingStart?.();
897
- }
898
- if (typingTimeoutRef.current) {
899
- clearTimeout(typingTimeoutRef.current);
900
- }
901
- typingTimeoutRef.current = setTimeout(() => {
902
- if (isTyping) {
903
- setIsTyping(false);
904
- onTypingStop?.();
905
- }
906
- }, 2e3);
907
- return () => {
908
- if (typingTimeoutRef.current) {
909
- clearTimeout(typingTimeoutRef.current);
910
- }
911
- };
912
- }, [content, isTyping, onTypingStart, onTypingStop]);
913
- React3.useEffect(() => {
914
- if (autoFocus) {
915
- textareaRef.current?.focus();
916
- }
917
- }, [autoFocus]);
918
- React3.useEffect(() => {
919
- if (replyTo) {
920
- textareaRef.current?.focus();
921
- }
922
- }, [replyTo]);
923
- const mention = useMentionAutocomplete({
924
- options: mentionOptions,
925
- value: content,
926
- setValue: setContent,
927
- textareaRef
928
- });
929
- const canSend = (content.trim().length > 0 || attachments.length > 0) && content.length <= maxLength && !disabled && !isSending;
930
- const handleSubmit = async (event) => {
931
- event.preventDefault();
932
- if (!canSend) return;
933
- const message = {
934
- content: content.trim(),
935
- attachments: attachments.map((a) => a.file),
936
- replyToId: replyTo?.id
937
- };
938
- setContent("");
939
- setAttachments([]);
940
- setIsTyping(false);
941
- onTypingStop?.();
942
- try {
943
- await onSend(message);
944
- } catch {
945
- setContent(message.content);
946
- onError?.("Failed to send message");
947
- }
948
- };
949
- const handleKeyDown = (event) => {
950
- if (mention.handleKeyDown(event)) return;
951
- if (event.key === "Enter" && !event.shiftKey) {
952
- event.preventDefault();
953
- if (canSend) {
954
- handleSubmit(event);
955
- }
956
- }
957
- };
958
- const handleFilesSelected = (files) => {
959
- const remainingSlots = maxAttachments - attachments.length;
960
- const filesToAdd = files.slice(0, remainingSlots);
961
- if (files.length > remainingSlots) {
962
- onError?.(`Maximum ${maxAttachments} attachments allowed`);
963
- }
964
- const newAttachments = filesToAdd.map((file) => {
965
- const type = getFileType(file.type);
966
- let previewUrl;
967
- if (type === "image" || type === "video") {
968
- previewUrl = URL.createObjectURL(file);
969
- }
970
- return {
971
- id: generateAttachmentId(),
972
- file,
973
- previewUrl,
974
- type,
975
- state: "pending"
976
- };
977
- });
978
- setAttachments((prev) => [...prev, ...newAttachments]);
979
- };
980
- const handlePaste = (event) => {
981
- if (!showAttachmentPicker || disabled) return;
982
- const pasted = Array.from(event.clipboardData.items).filter((item) => item.kind === "file").map((item) => item.getAsFile()).filter((f) => f !== null).filter((f) => isFileAccepted(f, acceptedFileTypes));
983
- if (pasted.length === 0) return;
984
- event.preventDefault();
985
- handleFilesSelected(pasted);
986
- };
987
- const handleRemoveAttachment = (attachmentId) => {
988
- setAttachments((prev) => {
989
- const attachment = prev.find((a) => a.id === attachmentId);
990
- if (attachment?.previewUrl) {
991
- URL.revokeObjectURL(attachment.previewUrl);
992
- }
993
- return prev.filter((a) => a.id !== attachmentId);
994
- });
995
- };
996
- React3.useEffect(() => {
997
- const currentAttachments = attachments;
998
- return () => {
999
- currentAttachments.forEach((a) => {
1000
- if (a.previewUrl) {
1001
- URL.revokeObjectURL(a.previewUrl);
1002
- }
1003
- });
1004
- };
1005
- }, [attachments]);
1006
- return /* @__PURE__ */ jsx(
1007
- DragDropZone,
1008
- {
1009
- onFilesDropped: handleFilesSelected,
1010
- acceptedTypes: acceptedFileTypes,
1011
- maxFileSize,
1012
- maxFiles: maxAttachments - attachments.length,
1013
- disabled: disabled || attachments.length >= maxAttachments,
1014
- onError,
1015
- className: cn("w-full", className),
1016
- children: /* @__PURE__ */ jsxs(
1017
- "form",
1018
- {
1019
- onSubmit: handleSubmit,
1020
- "data-slot": "message-composer",
1021
- className: "w-full",
1022
- children: [
1023
- replyTo && /* @__PURE__ */ jsxs(
1024
- "div",
1025
- {
1026
- "data-slot": "composer-reply-preview",
1027
- className: cn(
1028
- "flex items-center gap-2 px-4 py-2",
1029
- "bg-neutral-50 dark:bg-neutral-800/50",
1030
- "border-primary-500 border-s-4"
1031
- ),
1032
- children: [
1033
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
1034
- /* @__PURE__ */ jsxs("span", { className: "text-primary-800 dark:text-primary-400 text-xs font-medium", children: [
1035
- "Replying to ",
1036
- replyTo.senderName
1037
- ] }),
1038
- /* @__PURE__ */ jsx("p", { className: "truncate text-sm text-neutral-600 dark:text-neutral-300", children: replyTo.content })
1039
- ] }),
1040
- /* @__PURE__ */ jsx(
1041
- "button",
1042
- {
1043
- type: "button",
1044
- onClick: onCancelReply,
1045
- className: cn(
1046
- "shrink-0 rounded p-1",
1047
- "text-neutral-500 hover:text-neutral-700",
1048
- "dark:text-neutral-400 dark:hover:text-neutral-200",
1049
- "focus:ring-primary-500 focus:ring-2 focus:outline-none"
1050
- ),
1051
- "aria-label": "Cancel reply",
1052
- children: /* @__PURE__ */ jsx(
1053
- "svg",
1054
- {
1055
- "aria-hidden": "true",
1056
- className: "h-4 w-4",
1057
- fill: "none",
1058
- viewBox: "0 0 24 24",
1059
- stroke: "currentColor",
1060
- children: /* @__PURE__ */ jsx(
1061
- "path",
1062
- {
1063
- strokeLinecap: "round",
1064
- strokeLinejoin: "round",
1065
- strokeWidth: 2,
1066
- d: "M6 18L18 6M6 6l12 12"
1067
- }
1068
- )
1069
- }
1070
- )
1071
- }
1072
- )
1073
- ]
1074
- }
1075
- ),
1076
- attachments.length > 0 && /* @__PURE__ */ jsx(
1077
- "div",
1078
- {
1079
- "data-slot": "composer-attachments",
1080
- className: cn(
1081
- "flex flex-wrap gap-2 p-3",
1082
- "border-t border-neutral-200 dark:border-neutral-700"
1083
- ),
1084
- children: attachments.map((attachment) => /* @__PURE__ */ jsx(
1085
- AttachmentPreviewItem,
1086
- {
1087
- attachment,
1088
- onRemove: () => handleRemoveAttachment(attachment.id)
1089
- },
1090
- attachment.id
1091
- ))
1092
- }
1093
- ),
1094
- /* @__PURE__ */ jsxs(
1095
- "div",
1096
- {
1097
- "data-slot": "composer-input-area",
1098
- className: cn(
1099
- "flex items-center gap-2 p-3",
1100
- "bg-white dark:bg-neutral-900",
1101
- variant === "default" && "border-t border-neutral-200 dark:border-neutral-700"
1102
- ),
1103
- children: [
1104
- showAttachmentPicker && /* @__PURE__ */ jsx(
1105
- AttachmentPicker,
1106
- {
1107
- onFilesSelected: handleFilesSelected,
1108
- acceptedTypes: acceptedFileTypes,
1109
- maxFileSize,
1110
- maxFiles: maxAttachments - attachments.length,
1111
- disabled: disabled || attachments.length >= maxAttachments,
1112
- onError
1113
- }
1114
- ),
1115
- showCameraButton && /* @__PURE__ */ jsx(
1116
- CameraButton,
1117
- {
1118
- onCapture: (file) => handleFilesSelected([file]),
1119
- disabled: disabled || attachments.length >= maxAttachments
1120
- }
1121
- ),
1122
- /* @__PURE__ */ jsxs(
1123
- "div",
1124
- {
1125
- "data-slot": "composer-input-wrapper",
1126
- className: "relative flex-1",
1127
- ref: mention.anchorRef,
1128
- children: [
1129
- /* @__PURE__ */ jsx(MentionMenu, { mention }),
1130
- /* @__PURE__ */ jsx(
1131
- "textarea",
1132
- {
1133
- ref: textareaRef,
1134
- "data-slot": "composer-input",
1135
- value: content,
1136
- onChange: (e) => {
1137
- setContent(e.target.value);
1138
- mention.sync(
1139
- e.target.value,
1140
- e.target.selectionStart ?? e.target.value.length
1141
- );
1142
- },
1143
- onClick: (e) => {
1144
- const el = e.currentTarget;
1145
- mention.sync(el.value, el.selectionStart ?? el.value.length);
1146
- },
1147
- onKeyDown: handleKeyDown,
1148
- onPaste: handlePaste,
1149
- placeholder,
1150
- disabled: disabled || isSending,
1151
- rows: 1,
1152
- className: cn(
1153
- "w-full resize-none rounded-2xl py-2.5",
1154
- inputTrailing ? "ps-4 pe-10" : "px-4",
1155
- "bg-neutral-100 dark:bg-neutral-800",
1156
- "text-neutral-900 dark:text-neutral-100",
1157
- "placeholder:text-neutral-400 dark:placeholder:text-neutral-500",
1158
- "focus:ring-primary-500 focus:ring-2 focus:outline-none",
1159
- "disabled:cursor-not-allowed disabled:opacity-50",
1160
- "transition-colors",
1161
- "max-h-[150px]"
1162
- ),
1163
- "aria-label": "Message",
1164
- "aria-describedby": showCharacterCount ? "char-count" : void 0,
1165
- ...mention.inputProps
1166
- }
1167
- ),
1168
- inputTrailing && /* @__PURE__ */ jsx(
1169
- "div",
1170
- {
1171
- "data-slot": "composer-input-trailing",
1172
- className: "pointer-events-none absolute end-1 top-0 flex h-[44px] items-center [&>*]:pointer-events-auto",
1173
- children: inputTrailing
1174
- }
1175
- ),
1176
- showCharacterCount && /* @__PURE__ */ jsx(
1177
- "div",
1178
- {
1179
- "data-slot": "composer-char-count",
1180
- id: "char-count",
1181
- className: "absolute end-3 bottom-1.5",
1182
- children: /* @__PURE__ */ jsx(CharacterCounter, { current: content.length, max: maxLength })
1183
- }
1184
- )
1185
- ]
1186
- }
1187
- ),
1188
- /* @__PURE__ */ jsx(
1189
- SendButton,
1190
- {
1191
- canSend,
1192
- isLoading: isSending,
1193
- disabled
1194
- }
1195
- )
1196
- ]
1197
- }
1198
- )
1199
- ]
1200
- }
1201
- )
1202
- }
1203
- );
1204
- }
1205
- );
1206
- MessageComposer.displayName = "MessageComposer";
1207
702
 
1208
- export { AttachmentPicker, AttachmentPreviewItem, CameraButton, CharacterCounter, DragDropZone, MentionMenu, MessageComposer, SendButton, generateAttachmentId, getFileType, sendButtonVariants, useMentionAutocomplete, validateFile };
1209
- //# sourceMappingURL=chunk-O6GJ4IYS.js.map
1210
- //# sourceMappingURL=chunk-O6GJ4IYS.js.map
703
+ export { AttachmentPicker, AttachmentPreviewItem, CameraButton, DragDropZone, MentionMenu, generateAttachmentId, getFileType, useMentionAutocomplete, validateFile };
704
+ //# sourceMappingURL=chunk-IF3X2WZP.js.map
705
+ //# sourceMappingURL=chunk-IF3X2WZP.js.map