react-matchings 0.0.3 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/matching.tsx
2
- import { useEffect, useLayoutEffect, useRef, useState } from "react";
2
+ import { useCallback, useEffect, useRef, useState } from "react";
3
3
 
4
4
  // src/lib/utils.ts
5
5
  import { clsx } from "clsx";
@@ -13,90 +13,111 @@ import { jsx, jsxs } from "react/jsx-runtime";
13
13
  function Matching({
14
14
  questions,
15
15
  answers,
16
- onChange,
17
16
  className,
18
17
  questionClassName,
19
18
  answerClassName,
20
- lineClassName,
21
19
  lineColor = "black",
22
20
  circleColor = "white",
23
21
  circleRadius = 8,
24
22
  offset = 10,
25
- disabled
23
+ disabled,
24
+ onChange
26
25
  }) {
27
26
  const [matches, setMatches] = useState({});
27
+ const [lines, setLines] = useState([]);
28
28
  const [dragging, setDragging] = useState(null);
29
29
  const [dragLine, setDragLine] = useState(null);
30
- const [lines, setLines] = useState([]);
31
30
  const containerRef = useRef(null);
32
31
  const questionRefs = useRef({});
33
32
  const answerRefs = useRef({});
34
- const getElementCenter = (element, isAnswer = false) => {
35
- if (!element || !containerRef.current) return null;
36
- const rect = element.getBoundingClientRect();
37
- const containerRect = containerRef.current.getBoundingClientRect();
38
- return {
39
- x: isAnswer ? rect.left - containerRect.left + circleRadius + offset : rect.right - containerRect.left - circleRadius - offset,
40
- y: rect.top + rect.height / 2 - containerRect.top
41
- };
42
- };
33
+ const getElementCenter = useCallback(
34
+ (el, isAnswer = false) => {
35
+ if (!el || !containerRef.current) return null;
36
+ const rect = el.getBoundingClientRect();
37
+ const containerRect = containerRef.current.getBoundingClientRect();
38
+ return {
39
+ x: isAnswer ? rect.left - containerRect.left + circleRadius + offset : rect.right - containerRect.left - circleRadius - offset,
40
+ y: rect.top + rect.height / 2 - containerRect.top
41
+ };
42
+ },
43
+ [circleRadius, offset]
44
+ );
43
45
  const handleMouseDown = (qId) => {
44
46
  if (disabled) return;
45
47
  setDragging(qId);
46
48
  requestAnimationFrame(() => {
47
49
  const start = getElementCenter(questionRefs.current[qId]);
48
- if (start) {
49
- setDragLine({ start, end: start, questionId: qId });
50
- }
51
- });
52
- };
53
- const handleMouseMove = (e) => {
54
- if (!dragging || !containerRef.current) return;
55
- const containerRect = containerRef.current.getBoundingClientRect();
56
- const end = {
57
- x: e.clientX - containerRect.left,
58
- y: e.clientY - containerRect.top
59
- };
60
- setDragLine((prev) => {
61
- if (!prev) return null;
62
- return { ...prev, end };
50
+ if (start) setDragLine({ start, end: start, questionId: qId });
63
51
  });
64
52
  };
53
+ const handleMouseMove = useCallback(
54
+ (e) => {
55
+ if (!dragging || !containerRef.current) return;
56
+ const rect = containerRef.current.getBoundingClientRect();
57
+ setDragLine(
58
+ (prev) => prev ? {
59
+ ...prev,
60
+ end: { x: e.clientX - rect.left, y: e.clientY - rect.top }
61
+ } : null
62
+ );
63
+ },
64
+ [dragging]
65
+ );
65
66
  const handleMouseUp = (aId) => {
66
67
  if (dragging != null) {
67
- const newMatches = Object.fromEntries(
68
- Object.entries(matches).filter(([, ansId]) => ansId !== aId)
69
- );
70
- newMatches[dragging] = aId;
71
- setMatches(newMatches);
68
+ setMatches((prev) => {
69
+ const newMatches = { ...prev, [dragging]: aId };
70
+ if (onChange) {
71
+ queueMicrotask(
72
+ () => onChange(
73
+ Object.entries(newMatches).map(([qId, aId2]) => ({
74
+ questionId: Number(qId),
75
+ answerId: aId2
76
+ }))
77
+ )
78
+ );
79
+ }
80
+ return newMatches;
81
+ });
72
82
  }
73
83
  setDragging(null);
74
84
  setDragLine(null);
75
85
  };
76
- const handleGlobalMouseUp = () => {
77
- setDragging(null);
78
- setDragLine(null);
86
+ const removeMatch = (qId) => {
87
+ setMatches((prev) => {
88
+ const newMatches = { ...prev };
89
+ delete newMatches[qId];
90
+ if (onChange) {
91
+ queueMicrotask(
92
+ () => onChange(
93
+ Object.entries(newMatches).map(([qId2, aId]) => ({
94
+ questionId: Number(qId2),
95
+ answerId: aId
96
+ }))
97
+ )
98
+ );
99
+ }
100
+ return newMatches;
101
+ });
79
102
  };
80
103
  useEffect(() => {
104
+ if (!dragging) return;
105
+ const handleUp = () => {
106
+ setDragging(null);
107
+ setDragLine(null);
108
+ };
81
109
  document.addEventListener("mousemove", handleMouseMove);
82
- document.addEventListener("mouseup", handleGlobalMouseUp);
110
+ document.addEventListener("mouseup", handleUp);
83
111
  return () => {
84
112
  document.removeEventListener("mousemove", handleMouseMove);
85
- document.removeEventListener("mouseup", handleGlobalMouseUp);
113
+ document.removeEventListener("mouseup", handleUp);
86
114
  };
87
- }, [dragging]);
115
+ }, [dragging, handleMouseMove]);
88
116
  useEffect(() => {
89
- const connections = Object.entries(matches).map(([qId, aId]) => ({
90
- questionId: Number(qId),
91
- answerId: Number(aId)
92
- }));
93
- onChange(connections);
94
- }, [matches, onChange]);
95
- useLayoutEffect(() => {
96
117
  if (!containerRef.current) return;
97
118
  const newLines = Object.entries(matches).map(([qId, aId]) => {
98
119
  const startEl = questionRefs.current[Number(qId)];
99
- const endEl = answerRefs.current[aId];
120
+ const endEl = answerRefs.current[Number(aId)];
100
121
  if (!startEl || !endEl) return null;
101
122
  const start = getElementCenter(startEl, false);
102
123
  const end = getElementCenter(endEl, true);
@@ -104,147 +125,103 @@ function Matching({
104
125
  return { qId, aId: aId.toString(), start, end };
105
126
  }).filter(Boolean);
106
127
  setLines(newLines);
107
- }, [matches]);
108
- const removeMatch = (qId) => {
109
- if (disabled) return;
110
- const newMatches = { ...matches };
111
- delete newMatches[qId];
112
- setMatches(newMatches);
113
- };
128
+ }, [matches, getElementCenter]);
114
129
  return /* @__PURE__ */ jsxs(
115
130
  "div",
116
131
  {
132
+ className: cn("grid relative grid-cols-2 gap-10 select-none", className),
117
133
  ref: containerRef,
118
- className: cn(
119
- "relative grid grid-cols-2 gap-10 select-none bg-none",
120
- className
121
- ),
122
134
  children: [
123
- /* @__PURE__ */ jsxs(
124
- "svg",
125
- {
126
- className: cn(
127
- "absolute pointer-events-none z-20 w-full h-full",
128
- lineClassName
135
+ /* @__PURE__ */ jsxs("svg", { className: "absolute z-20 w-full h-full pointer-events-none", children: [
136
+ lines.map(({ qId, aId, start, end }) => /* @__PURE__ */ jsxs("g", { children: [
137
+ /* @__PURE__ */ jsx(
138
+ "line",
139
+ {
140
+ x1: start.x,
141
+ y1: start.y,
142
+ x2: end.x,
143
+ y2: end.y,
144
+ stroke: lineColor,
145
+ strokeWidth: 3,
146
+ strokeLinecap: "round"
147
+ }
148
+ ),
149
+ /* @__PURE__ */ jsx(
150
+ "circle",
151
+ {
152
+ cx: start.x,
153
+ cy: start.y,
154
+ r: circleRadius,
155
+ fill: circleColor
156
+ }
129
157
  ),
130
- children: [
131
- lines.map(({ qId, aId, start, end }) => /* @__PURE__ */ jsxs("g", { children: [
132
- /* @__PURE__ */ jsx(
133
- "line",
134
- {
135
- x1: start.x,
136
- y1: start.y,
137
- x2: end.x,
138
- y2: end.y,
139
- stroke: lineColor,
140
- strokeWidth: "3",
141
- strokeLinecap: "round"
142
- }
143
- ),
144
- /* @__PURE__ */ jsx(
145
- "circle",
146
- {
147
- cx: start.x,
148
- cy: start.y,
149
- r: circleRadius,
150
- fill: circleColor
151
- }
152
- ),
153
- /* @__PURE__ */ jsx("circle", { cx: end.x, cy: end.y, r: circleRadius, fill: circleColor })
154
- ] }, `${qId}-${aId}`)),
155
- dragLine && /* @__PURE__ */ jsxs("g", { children: [
156
- /* @__PURE__ */ jsx(
157
- "line",
158
- {
159
- x1: dragLine.start.x,
160
- y1: dragLine.start.y,
161
- x2: dragLine.end.x,
162
- y2: dragLine.end.y,
163
- stroke: lineColor,
164
- strokeWidth: "3",
165
- strokeDasharray: "5,5",
166
- strokeLinecap: "round"
167
- }
168
- ),
169
- /* @__PURE__ */ jsx(
170
- "circle",
171
- {
172
- cx: dragLine.start.x,
173
- cy: dragLine.start.y,
174
- r: circleRadius,
175
- fill: circleColor
176
- }
177
- ),
178
- /* @__PURE__ */ jsx(
179
- "circle",
180
- {
181
- cx: dragLine.end.x,
182
- cy: dragLine.end.y,
183
- r: circleRadius,
184
- fill: circleColor
185
- }
186
- )
187
- ] })
188
- ]
189
- }
190
- ),
191
- /* @__PURE__ */ jsx("div", { className: "space-y-3 relative z-10", children: questions.map((q) => {
158
+ /* @__PURE__ */ jsx("circle", { cx: end.x, cy: end.y, r: circleRadius, fill: circleColor })
159
+ ] }, `${qId}-${aId}`)),
160
+ dragLine && /* @__PURE__ */ jsxs("g", { children: [
161
+ /* @__PURE__ */ jsx(
162
+ "line",
163
+ {
164
+ x1: dragLine.start.x,
165
+ y1: dragLine.start.y,
166
+ x2: dragLine.end.x,
167
+ y2: dragLine.end.y,
168
+ stroke: lineColor,
169
+ strokeWidth: 3,
170
+ strokeDasharray: "5,5",
171
+ strokeLinecap: "round"
172
+ }
173
+ ),
174
+ /* @__PURE__ */ jsx(
175
+ "circle",
176
+ {
177
+ cx: dragLine.start.x,
178
+ cy: dragLine.start.y,
179
+ r: circleRadius,
180
+ fill: circleColor
181
+ }
182
+ ),
183
+ /* @__PURE__ */ jsx(
184
+ "circle",
185
+ {
186
+ cx: dragLine.end.x,
187
+ cy: dragLine.end.y,
188
+ r: circleRadius,
189
+ fill: circleColor
190
+ }
191
+ )
192
+ ] })
193
+ ] }),
194
+ /* @__PURE__ */ jsx("div", { className: "relative z-10 space-y-3", children: questions.map((q) => {
192
195
  const isMatched = matches[q.id] !== void 0;
193
196
  return /* @__PURE__ */ jsx(
194
197
  "button",
195
198
  {
199
+ ref: (el) => void (questionRefs.current[q.id] = el),
196
200
  type: "button",
197
- ref: (el) => {
198
- questionRefs.current[q.id] = el;
199
- },
200
- "aria-pressed": isMatched,
201
201
  onMouseDown: () => handleMouseDown(q.id),
202
202
  onClick: () => isMatched && removeMatch(q.id),
203
203
  className: cn(
204
- "p-4 rounded transition-all duration-200 bg-black text-white font-medium w-full focus:outline-none focus:ring-2 focus:ring-gray-500",
205
- dragging === q.id && "bg-gray-800 border-gray-600",
206
- isMatched && "bg-gray-700 border-gray-500",
207
- disabled ? "cursor-default bg-gray-500" : "cursor-pointer",
208
- typeof questionClassName === "function" ? questionClassName({
209
- isMatched,
210
- isDragging: dragging === q.id
211
- }) : questionClassName
204
+ "p-4 rounded bg-black text-white w-full font-medium focus:outline-none focus:ring-2 focus:ring-gray-500",
205
+ isMatched && "bg-gray-700",
206
+ questionClassName
212
207
  ),
213
208
  children: q.text
214
209
  },
215
210
  q.id
216
211
  );
217
212
  }) }),
218
- /* @__PURE__ */ jsx("div", { className: "space-y-3 relative z-10", children: answers.map((a) => {
219
- const matchedQuestion = Object.keys(matches).find(
220
- (qId) => matches[Number(qId)] === a.id
221
- );
222
- const isMatched = matchedQuestion !== void 0;
223
- const isHovering = dragging != null && dragLine != null;
213
+ /* @__PURE__ */ jsx("div", { className: "relative z-10 space-y-3", children: answers.map((a) => {
214
+ const isMatched = Object.values(matches).includes(a.id);
224
215
  return /* @__PURE__ */ jsx(
225
216
  "button",
226
217
  {
218
+ ref: (el) => void (answerRefs.current[a.id] = el),
227
219
  type: "button",
228
- ref: (el) => {
229
- answerRefs.current[a.id] = el;
230
- },
231
- "aria-pressed": isMatched,
232
220
  onMouseUp: () => handleMouseUp(a.id),
233
- onMouseEnter: () => {
234
- if (!dragging) return;
235
- const end = getElementCenter(answerRefs.current[a.id], true);
236
- if (!end) return;
237
- setDragLine((prev) => {
238
- if (!prev) return null;
239
- return { ...prev, end };
240
- });
241
- },
242
221
  className: cn(
243
- "p-4 ps-7 rounded transition-all duration-200 bg-black text-white font-medium w-full focus:outline-none focus:ring-2 focus:ring-gray-500",
244
- isHovering && !isMatched && "bg-gray-800 border-gray-600",
245
- isMatched && "bg-gray-700 border-gray-600",
246
- disabled ? "cursor-default bg-gray-500" : "cursor-pointer",
247
- typeof answerClassName === "function" ? answerClassName({ isMatched, isHovering }) : answerClassName
222
+ "p-4 rounded bg-black text-white w-full font-medium focus:outline-none focus:ring-2 focus:ring-gray-500",
223
+ isMatched && "bg-gray-700",
224
+ answerClassName
248
225
  ),
249
226
  children: a.text
250
227
  },
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/matching.tsx","../src/lib/utils.ts"],"sourcesContent":["import { useEffect, useLayoutEffect, useRef, useState } from \"react\";\r\nimport { cn } from \"./lib/utils\";\r\n\r\ntype TMatch = {\r\n questionId: number | string;\r\n answerId: number | string;\r\n};\r\n\r\ntype Props = {\r\n questions: { id: number; text: string }[];\r\n answers: { id: number; text: string }[];\r\n onChange: (matches: TMatch[]) => void;\r\n className?: string;\r\n questionClassName?:\r\n | string\r\n | ((state: { isMatched: boolean; isDragging: boolean }) => string);\r\n answerClassName?:\r\n | string\r\n | ((state: { isMatched: boolean; isHovering: boolean }) => string);\r\n lineClassName?: string;\r\n lineColor?: string;\r\n circleColor?: string;\r\n circleRadius?: number;\r\n offset?: number;\r\n disabled?: boolean;\r\n};\r\n\r\nfunction Matching({\r\n questions,\r\n answers,\r\n onChange,\r\n className,\r\n questionClassName,\r\n answerClassName,\r\n lineClassName,\r\n lineColor = \"black\",\r\n circleColor = \"white\",\r\n circleRadius = 8,\r\n offset = 10,\r\n disabled,\r\n}: Props) {\r\n const [matches, setMatches] = useState<Record<number, number>>({});\r\n const [dragging, setDragging] = useState<number | null>(null);\r\n const [dragLine, setDragLine] = useState<{\r\n start: { x: number; y: number };\r\n end: { x: number; y: number };\r\n questionId: number;\r\n } | null>(null);\r\n const [lines, setLines] = useState<\r\n {\r\n qId: string;\r\n aId: string;\r\n start: { x: number; y: number };\r\n end: { x: number; y: number };\r\n }[]\r\n >([]);\r\n\r\n const containerRef = useRef<HTMLDivElement | null>(null);\r\n const questionRefs = useRef<Record<number, HTMLElement | null>>({});\r\n const answerRefs = useRef<Record<number, HTMLElement | null>>({});\r\n\r\n const getElementCenter = (element: HTMLElement | null, isAnswer = false) => {\r\n if (!element || !containerRef.current) return null;\r\n const rect = element.getBoundingClientRect();\r\n const containerRect = containerRef.current.getBoundingClientRect();\r\n\r\n return {\r\n x: isAnswer\r\n ? rect.left - containerRect.left + circleRadius + offset\r\n : rect.right - containerRect.left - circleRadius - offset,\r\n y: rect.top + rect.height / 2 - containerRect.top,\r\n };\r\n };\r\n\r\n const handleMouseDown = (qId: number) => {\r\n if (disabled) return;\r\n setDragging(qId);\r\n\r\n requestAnimationFrame(() => {\r\n const start = getElementCenter(questionRefs.current[qId]);\r\n if (start) {\r\n setDragLine({ start, end: start, questionId: qId });\r\n }\r\n });\r\n };\r\n\r\n const handleMouseMove = (e: { clientX: number; clientY: number }) => {\r\n if (!dragging || !containerRef.current) return;\r\n const containerRect = containerRef.current.getBoundingClientRect();\r\n const end = {\r\n x: e.clientX - containerRect.left,\r\n y: e.clientY - containerRect.top,\r\n };\r\n setDragLine((prev) => {\r\n if (!prev) return null;\r\n return { ...prev, end };\r\n });\r\n };\r\n\r\n const handleMouseUp = (aId: number) => {\r\n if (dragging != null) {\r\n const newMatches = Object.fromEntries(\r\n Object.entries(matches).filter(([, ansId]) => ansId !== aId)\r\n );\r\n\r\n newMatches[dragging] = aId;\r\n setMatches(newMatches);\r\n }\r\n setDragging(null);\r\n setDragLine(null);\r\n };\r\n\r\n const handleGlobalMouseUp = () => {\r\n setDragging(null);\r\n setDragLine(null);\r\n };\r\n\r\n useEffect(() => {\r\n document.addEventListener(\"mousemove\", handleMouseMove);\r\n document.addEventListener(\"mouseup\", handleGlobalMouseUp);\r\n return () => {\r\n document.removeEventListener(\"mousemove\", handleMouseMove);\r\n document.removeEventListener(\"mouseup\", handleGlobalMouseUp);\r\n };\r\n }, [dragging]);\r\n\r\n useEffect(() => {\r\n const connections: TMatch[] = Object.entries(matches).map(([qId, aId]) => ({\r\n questionId: Number(qId),\r\n answerId: Number(aId),\r\n }));\r\n onChange(connections);\r\n }, [matches, onChange]);\r\n\r\n useLayoutEffect(() => {\r\n if (!containerRef.current) return;\r\n\r\n const newLines = Object.entries(matches)\r\n .map(([qId, aId]) => {\r\n const startEl = questionRefs.current[Number(qId)];\r\n const endEl = answerRefs.current[aId];\r\n if (!startEl || !endEl) return null;\r\n\r\n const start = getElementCenter(startEl, false);\r\n const end = getElementCenter(endEl, true);\r\n if (!start || !end) return null;\r\n\r\n return { qId, aId: aId.toString(), start, end };\r\n })\r\n .filter(Boolean) as {\r\n qId: string;\r\n aId: string;\r\n start: { x: number; y: number };\r\n end: { x: number; y: number };\r\n }[];\r\n\r\n setLines(newLines);\r\n }, [matches]);\r\n\r\n const removeMatch = (qId: number) => {\r\n if (disabled) return;\r\n const newMatches = { ...matches };\r\n delete newMatches[qId];\r\n setMatches(newMatches);\r\n };\r\n\r\n return (\r\n <div\r\n ref={containerRef}\r\n className={cn(\r\n \"relative grid grid-cols-2 gap-10 select-none bg-none\",\r\n className\r\n )}\r\n >\r\n <svg\r\n className={cn(\r\n \"absolute pointer-events-none z-20 w-full h-full\",\r\n lineClassName\r\n )}\r\n >\r\n {lines.map(({ qId, aId, start, end }) => (\r\n <g key={`${qId}-${aId}`}>\r\n <line\r\n x1={start.x}\r\n y1={start.y}\r\n x2={end.x}\r\n y2={end.y}\r\n stroke={lineColor}\r\n strokeWidth=\"3\"\r\n strokeLinecap=\"round\"\r\n />\r\n <circle\r\n cx={start.x}\r\n cy={start.y}\r\n r={circleRadius}\r\n fill={circleColor}\r\n />\r\n <circle cx={end.x} cy={end.y} r={circleRadius} fill={circleColor} />\r\n </g>\r\n ))}\r\n {dragLine && (\r\n <g>\r\n <line\r\n x1={dragLine.start.x}\r\n y1={dragLine.start.y}\r\n x2={dragLine.end.x}\r\n y2={dragLine.end.y}\r\n stroke={lineColor}\r\n strokeWidth=\"3\"\r\n strokeDasharray=\"5,5\"\r\n strokeLinecap=\"round\"\r\n />\r\n <circle\r\n cx={dragLine.start.x}\r\n cy={dragLine.start.y}\r\n r={circleRadius}\r\n fill={circleColor}\r\n />\r\n <circle\r\n cx={dragLine.end.x}\r\n cy={dragLine.end.y}\r\n r={circleRadius}\r\n fill={circleColor}\r\n />\r\n </g>\r\n )}\r\n </svg>\r\n <div className=\"space-y-3 relative z-10\">\r\n {questions.map((q) => {\r\n const isMatched = matches[q.id] !== undefined;\r\n return (\r\n <button\r\n key={q.id}\r\n type=\"button\"\r\n ref={(el) => {\r\n questionRefs.current[q.id] = el;\r\n }}\r\n aria-pressed={isMatched}\r\n onMouseDown={() => handleMouseDown(q.id)}\r\n onClick={() => isMatched && removeMatch(q.id)}\r\n className={cn(\r\n \"p-4 rounded transition-all duration-200 bg-black text-white font-medium w-full focus:outline-none focus:ring-2 focus:ring-gray-500\",\r\n dragging === q.id && \"bg-gray-800 border-gray-600\",\r\n isMatched && \"bg-gray-700 border-gray-500\",\r\n disabled ? \"cursor-default bg-gray-500\" : \"cursor-pointer\",\r\n typeof questionClassName === \"function\"\r\n ? questionClassName({\r\n isMatched,\r\n isDragging: dragging === q.id,\r\n })\r\n : questionClassName\r\n )}\r\n >\r\n {q.text}\r\n </button>\r\n );\r\n })}\r\n </div>\r\n <div className=\"space-y-3 relative z-10\">\r\n {answers.map((a) => {\r\n const matchedQuestion = Object.keys(matches).find(\r\n (qId) => matches[Number(qId)] === a.id\r\n );\r\n const isMatched = matchedQuestion !== undefined;\r\n const isHovering = dragging != null && dragLine != null;\r\n\r\n return (\r\n <button\r\n key={a.id}\r\n type=\"button\"\r\n ref={(el) => {\r\n answerRefs.current[a.id] = el;\r\n }}\r\n aria-pressed={isMatched}\r\n onMouseUp={() => handleMouseUp(a.id)}\r\n onMouseEnter={() => {\r\n if (!dragging) return;\r\n const end = getElementCenter(answerRefs.current[a.id], true);\r\n if (!end) return;\r\n setDragLine((prev) => {\r\n if (!prev) return null;\r\n return { ...prev, end };\r\n });\r\n }}\r\n className={cn(\r\n \"p-4 ps-7 rounded transition-all duration-200 bg-black text-white font-medium w-full focus:outline-none focus:ring-2 focus:ring-gray-500\",\r\n isHovering && !isMatched && \"bg-gray-800 border-gray-600\",\r\n isMatched && \"bg-gray-700 border-gray-600\",\r\n disabled ? \"cursor-default bg-gray-500\" : \"cursor-pointer\",\r\n typeof answerClassName === \"function\"\r\n ? answerClassName({ isMatched, isHovering })\r\n : answerClassName\r\n )}\r\n >\r\n {a.text}\r\n </button>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n );\r\n}\r\n\r\nexport { Matching };\r\n","import { clsx, type ClassValue } from \"clsx\";\r\nimport { twMerge } from \"tailwind-merge\";\r\n\r\nexport function cn(...inputs: ClassValue[]) {\r\n return twMerge(clsx(inputs));\r\n}\r\n"],"mappings":";AAAA,SAAS,WAAW,iBAAiB,QAAQ,gBAAgB;;;ACA7D,SAAS,YAA6B;AACtC,SAAS,eAAe;AAEjB,SAAS,MAAM,QAAsB;AAC1C,SAAO,QAAQ,KAAK,MAAM,CAAC;AAC7B;;;ADgLU,SACE,KADF;AA1JV,SAAS,SAAS;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,eAAe;AAAA,EACf,SAAS;AAAA,EACT;AACF,GAAU;AACR,QAAM,CAAC,SAAS,UAAU,IAAI,SAAiC,CAAC,CAAC;AACjE,QAAM,CAAC,UAAU,WAAW,IAAI,SAAwB,IAAI;AAC5D,QAAM,CAAC,UAAU,WAAW,IAAI,SAItB,IAAI;AACd,QAAM,CAAC,OAAO,QAAQ,IAAI,SAOxB,CAAC,CAAC;AAEJ,QAAM,eAAe,OAA8B,IAAI;AACvD,QAAM,eAAe,OAA2C,CAAC,CAAC;AAClE,QAAM,aAAa,OAA2C,CAAC,CAAC;AAEhE,QAAM,mBAAmB,CAAC,SAA6B,WAAW,UAAU;AAC1E,QAAI,CAAC,WAAW,CAAC,aAAa,QAAS,QAAO;AAC9C,UAAM,OAAO,QAAQ,sBAAsB;AAC3C,UAAM,gBAAgB,aAAa,QAAQ,sBAAsB;AAEjE,WAAO;AAAA,MACL,GAAG,WACC,KAAK,OAAO,cAAc,OAAO,eAAe,SAChD,KAAK,QAAQ,cAAc,OAAO,eAAe;AAAA,MACrD,GAAG,KAAK,MAAM,KAAK,SAAS,IAAI,cAAc;AAAA,IAChD;AAAA,EACF;AAEA,QAAM,kBAAkB,CAAC,QAAgB;AACvC,QAAI,SAAU;AACd,gBAAY,GAAG;AAEf,0BAAsB,MAAM;AAC1B,YAAM,QAAQ,iBAAiB,aAAa,QAAQ,GAAG,CAAC;AACxD,UAAI,OAAO;AACT,oBAAY,EAAE,OAAO,KAAK,OAAO,YAAY,IAAI,CAAC;AAAA,MACpD;AAAA,IACF,CAAC;AAAA,EACH;AAEA,QAAM,kBAAkB,CAAC,MAA4C;AACnE,QAAI,CAAC,YAAY,CAAC,aAAa,QAAS;AACxC,UAAM,gBAAgB,aAAa,QAAQ,sBAAsB;AACjE,UAAM,MAAM;AAAA,MACV,GAAG,EAAE,UAAU,cAAc;AAAA,MAC7B,GAAG,EAAE,UAAU,cAAc;AAAA,IAC/B;AACA,gBAAY,CAAC,SAAS;AACpB,UAAI,CAAC,KAAM,QAAO;AAClB,aAAO,EAAE,GAAG,MAAM,IAAI;AAAA,IACxB,CAAC;AAAA,EACH;AAEA,QAAM,gBAAgB,CAAC,QAAgB;AACrC,QAAI,YAAY,MAAM;AACpB,YAAM,aAAa,OAAO;AAAA,QACxB,OAAO,QAAQ,OAAO,EAAE,OAAO,CAAC,CAAC,EAAE,KAAK,MAAM,UAAU,GAAG;AAAA,MAC7D;AAEA,iBAAW,QAAQ,IAAI;AACvB,iBAAW,UAAU;AAAA,IACvB;AACA,gBAAY,IAAI;AAChB,gBAAY,IAAI;AAAA,EAClB;AAEA,QAAM,sBAAsB,MAAM;AAChC,gBAAY,IAAI;AAChB,gBAAY,IAAI;AAAA,EAClB;AAEA,YAAU,MAAM;AACd,aAAS,iBAAiB,aAAa,eAAe;AACtD,aAAS,iBAAiB,WAAW,mBAAmB;AACxD,WAAO,MAAM;AACX,eAAS,oBAAoB,aAAa,eAAe;AACzD,eAAS,oBAAoB,WAAW,mBAAmB;AAAA,IAC7D;AAAA,EACF,GAAG,CAAC,QAAQ,CAAC;AAEb,YAAU,MAAM;AACd,UAAM,cAAwB,OAAO,QAAQ,OAAO,EAAE,IAAI,CAAC,CAAC,KAAK,GAAG,OAAO;AAAA,MACzE,YAAY,OAAO,GAAG;AAAA,MACtB,UAAU,OAAO,GAAG;AAAA,IACtB,EAAE;AACF,aAAS,WAAW;AAAA,EACtB,GAAG,CAAC,SAAS,QAAQ,CAAC;AAEtB,kBAAgB,MAAM;AACpB,QAAI,CAAC,aAAa,QAAS;AAE3B,UAAM,WAAW,OAAO,QAAQ,OAAO,EACpC,IAAI,CAAC,CAAC,KAAK,GAAG,MAAM;AACnB,YAAM,UAAU,aAAa,QAAQ,OAAO,GAAG,CAAC;AAChD,YAAM,QAAQ,WAAW,QAAQ,GAAG;AACpC,UAAI,CAAC,WAAW,CAAC,MAAO,QAAO;AAE/B,YAAM,QAAQ,iBAAiB,SAAS,KAAK;AAC7C,YAAM,MAAM,iBAAiB,OAAO,IAAI;AACxC,UAAI,CAAC,SAAS,CAAC,IAAK,QAAO;AAE3B,aAAO,EAAE,KAAK,KAAK,IAAI,SAAS,GAAG,OAAO,IAAI;AAAA,IAChD,CAAC,EACA,OAAO,OAAO;AAOjB,aAAS,QAAQ;AAAA,EACnB,GAAG,CAAC,OAAO,CAAC;AAEZ,QAAM,cAAc,CAAC,QAAgB;AACnC,QAAI,SAAU;AACd,UAAM,aAAa,EAAE,GAAG,QAAQ;AAChC,WAAO,WAAW,GAAG;AACrB,eAAW,UAAU;AAAA,EACvB;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MAEA;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,WAAW;AAAA,cACT;AAAA,cACA;AAAA,YACF;AAAA,YAEC;AAAA,oBAAM,IAAI,CAAC,EAAE,KAAK,KAAK,OAAO,IAAI,MACjC,qBAAC,OACC;AAAA;AAAA,kBAAC;AAAA;AAAA,oBACC,IAAI,MAAM;AAAA,oBACV,IAAI,MAAM;AAAA,oBACV,IAAI,IAAI;AAAA,oBACR,IAAI,IAAI;AAAA,oBACR,QAAQ;AAAA,oBACR,aAAY;AAAA,oBACZ,eAAc;AAAA;AAAA,gBAChB;AAAA,gBACA;AAAA,kBAAC;AAAA;AAAA,oBACC,IAAI,MAAM;AAAA,oBACV,IAAI,MAAM;AAAA,oBACV,GAAG;AAAA,oBACH,MAAM;AAAA;AAAA,gBACR;AAAA,gBACA,oBAAC,YAAO,IAAI,IAAI,GAAG,IAAI,IAAI,GAAG,GAAG,cAAc,MAAM,aAAa;AAAA,mBAhB5D,GAAG,GAAG,IAAI,GAAG,EAiBrB,CACD;AAAA,cACA,YACC,qBAAC,OACC;AAAA;AAAA,kBAAC;AAAA;AAAA,oBACC,IAAI,SAAS,MAAM;AAAA,oBACnB,IAAI,SAAS,MAAM;AAAA,oBACnB,IAAI,SAAS,IAAI;AAAA,oBACjB,IAAI,SAAS,IAAI;AAAA,oBACjB,QAAQ;AAAA,oBACR,aAAY;AAAA,oBACZ,iBAAgB;AAAA,oBAChB,eAAc;AAAA;AAAA,gBAChB;AAAA,gBACA;AAAA,kBAAC;AAAA;AAAA,oBACC,IAAI,SAAS,MAAM;AAAA,oBACnB,IAAI,SAAS,MAAM;AAAA,oBACnB,GAAG;AAAA,oBACH,MAAM;AAAA;AAAA,gBACR;AAAA,gBACA;AAAA,kBAAC;AAAA;AAAA,oBACC,IAAI,SAAS,IAAI;AAAA,oBACjB,IAAI,SAAS,IAAI;AAAA,oBACjB,GAAG;AAAA,oBACH,MAAM;AAAA;AAAA,gBACR;AAAA,iBACF;AAAA;AAAA;AAAA,QAEJ;AAAA,QACA,oBAAC,SAAI,WAAU,2BACZ,oBAAU,IAAI,CAAC,MAAM;AACpB,gBAAM,YAAY,QAAQ,EAAE,EAAE,MAAM;AACpC,iBACE;AAAA,YAAC;AAAA;AAAA,cAEC,MAAK;AAAA,cACL,KAAK,CAAC,OAAO;AACX,6BAAa,QAAQ,EAAE,EAAE,IAAI;AAAA,cAC/B;AAAA,cACA,gBAAc;AAAA,cACd,aAAa,MAAM,gBAAgB,EAAE,EAAE;AAAA,cACvC,SAAS,MAAM,aAAa,YAAY,EAAE,EAAE;AAAA,cAC5C,WAAW;AAAA,gBACT;AAAA,gBACA,aAAa,EAAE,MAAM;AAAA,gBACrB,aAAa;AAAA,gBACb,WAAW,+BAA+B;AAAA,gBAC1C,OAAO,sBAAsB,aACzB,kBAAkB;AAAA,kBAChB;AAAA,kBACA,YAAY,aAAa,EAAE;AAAA,gBAC7B,CAAC,IACD;AAAA,cACN;AAAA,cAEC,YAAE;AAAA;AAAA,YArBE,EAAE;AAAA,UAsBT;AAAA,QAEJ,CAAC,GACH;AAAA,QACA,oBAAC,SAAI,WAAU,2BACZ,kBAAQ,IAAI,CAAC,MAAM;AAClB,gBAAM,kBAAkB,OAAO,KAAK,OAAO,EAAE;AAAA,YAC3C,CAAC,QAAQ,QAAQ,OAAO,GAAG,CAAC,MAAM,EAAE;AAAA,UACtC;AACA,gBAAM,YAAY,oBAAoB;AACtC,gBAAM,aAAa,YAAY,QAAQ,YAAY;AAEnD,iBACE;AAAA,YAAC;AAAA;AAAA,cAEC,MAAK;AAAA,cACL,KAAK,CAAC,OAAO;AACX,2BAAW,QAAQ,EAAE,EAAE,IAAI;AAAA,cAC7B;AAAA,cACA,gBAAc;AAAA,cACd,WAAW,MAAM,cAAc,EAAE,EAAE;AAAA,cACnC,cAAc,MAAM;AAClB,oBAAI,CAAC,SAAU;AACf,sBAAM,MAAM,iBAAiB,WAAW,QAAQ,EAAE,EAAE,GAAG,IAAI;AAC3D,oBAAI,CAAC,IAAK;AACV,4BAAY,CAAC,SAAS;AACpB,sBAAI,CAAC,KAAM,QAAO;AAClB,yBAAO,EAAE,GAAG,MAAM,IAAI;AAAA,gBACxB,CAAC;AAAA,cACH;AAAA,cACA,WAAW;AAAA,gBACT;AAAA,gBACA,cAAc,CAAC,aAAa;AAAA,gBAC5B,aAAa;AAAA,gBACb,WAAW,+BAA+B;AAAA,gBAC1C,OAAO,oBAAoB,aACvB,gBAAgB,EAAE,WAAW,WAAW,CAAC,IACzC;AAAA,cACN;AAAA,cAEC,YAAE;AAAA;AAAA,YA1BE,EAAE;AAAA,UA2BT;AAAA,QAEJ,CAAC,GACH;AAAA;AAAA;AAAA,EACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../src/matching.tsx","../src/lib/utils.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\r\nimport { cn } from \"./lib/utils\";\r\n\r\nexport type TMatch = {\r\n questionId: number;\r\n answerId: number;\r\n};\r\n\r\ntype Props = {\r\n questions: { id: number; text: string }[];\r\n answers: { id: number; text: string }[];\r\n className?: string;\r\n questionClassName?: string;\r\n answerClassName?: string;\r\n lineColor?: string;\r\n circleColor?: string;\r\n circleRadius?: number;\r\n offset?: number;\r\n disabled?: boolean;\r\n onChange?: (matches: TMatch[]) => void;\r\n};\r\n\r\ntype Line = {\r\n qId: string;\r\n aId: string;\r\n start: { x: number; y: number };\r\n end: { x: number; y: number };\r\n};\r\n\r\nexport function Matching({\r\n questions,\r\n answers,\r\n className,\r\n questionClassName,\r\n answerClassName,\r\n lineColor = \"black\",\r\n circleColor = \"white\",\r\n circleRadius = 8,\r\n offset = 10,\r\n disabled,\r\n onChange,\r\n}: Props) {\r\n const [matches, setMatches] = useState<Record<number, number>>({});\r\n const [lines, setLines] = useState<Line[]>([]);\r\n const [dragging, setDragging] = useState<number | null>(null);\r\n const [dragLine, setDragLine] = useState<{\r\n start: { x: number; y: number };\r\n end: { x: number; y: number };\r\n questionId: number;\r\n } | null>(null);\r\n\r\n const containerRef = useRef<HTMLDivElement | null>(null);\r\n const questionRefs = useRef<Record<number, HTMLButtonElement | null>>({});\r\n const answerRefs = useRef<Record<number, HTMLButtonElement | null>>({});\r\n\r\n const getElementCenter = useCallback(\r\n (el: HTMLElement | null, isAnswer = false) => {\r\n if (!el || !containerRef.current) return null;\r\n const rect = el.getBoundingClientRect();\r\n const containerRect = containerRef.current.getBoundingClientRect();\r\n return {\r\n x: isAnswer\r\n ? rect.left - containerRect.left + circleRadius + offset\r\n : rect.right - containerRect.left - circleRadius - offset,\r\n y: rect.top + rect.height / 2 - containerRect.top,\r\n };\r\n },\r\n [circleRadius, offset]\r\n );\r\n\r\n const handleMouseDown = (qId: number) => {\r\n if (disabled) return;\r\n setDragging(qId);\r\n requestAnimationFrame(() => {\r\n const start = getElementCenter(questionRefs.current[qId]);\r\n if (start) setDragLine({ start, end: start, questionId: qId });\r\n });\r\n };\r\n\r\n const handleMouseMove = useCallback(\r\n (e: MouseEvent) => {\r\n if (!dragging || !containerRef.current) return;\r\n const rect = containerRef.current.getBoundingClientRect();\r\n setDragLine((prev) =>\r\n prev\r\n ? {\r\n ...prev,\r\n end: { x: e.clientX - rect.left, y: e.clientY - rect.top },\r\n }\r\n : null\r\n );\r\n },\r\n [dragging]\r\n );\r\n\r\n const handleMouseUp = (aId: number) => {\r\n if (dragging != null) {\r\n setMatches((prev) => {\r\n const newMatches = { ...prev, [dragging]: aId };\r\n if (onChange) {\r\n // notify parent immediately on every change\r\n queueMicrotask(() =>\r\n onChange(\r\n Object.entries(newMatches).map(([qId, aId]) => ({\r\n questionId: Number(qId),\r\n answerId: aId,\r\n }))\r\n )\r\n );\r\n }\r\n return newMatches;\r\n });\r\n }\r\n setDragging(null);\r\n setDragLine(null);\r\n };\r\n\r\n const removeMatch = (qId: number) => {\r\n setMatches((prev) => {\r\n const newMatches = { ...prev };\r\n delete newMatches[qId];\r\n if (onChange) {\r\n queueMicrotask(() =>\r\n onChange(\r\n Object.entries(newMatches).map(([qId, aId]) => ({\r\n questionId: Number(qId),\r\n answerId: aId,\r\n }))\r\n )\r\n );\r\n }\r\n return newMatches;\r\n });\r\n };\r\n\r\n useEffect(() => {\r\n if (!dragging) return;\r\n const handleUp = () => {\r\n setDragging(null);\r\n setDragLine(null);\r\n };\r\n document.addEventListener(\"mousemove\", handleMouseMove);\r\n document.addEventListener(\"mouseup\", handleUp);\r\n return () => {\r\n document.removeEventListener(\"mousemove\", handleMouseMove);\r\n document.removeEventListener(\"mouseup\", handleUp);\r\n };\r\n }, [dragging, handleMouseMove]);\r\n\r\n useEffect(() => {\r\n if (!containerRef.current) return;\r\n\r\n const newLines: Line[] = Object.entries(matches)\r\n .map(([qId, aId]) => {\r\n const startEl = questionRefs.current[Number(qId)];\r\n const endEl = answerRefs.current[Number(aId)];\r\n if (!startEl || !endEl) return null;\r\n const start = getElementCenter(startEl, false);\r\n const end = getElementCenter(endEl, true);\r\n if (!start || !end) return null;\r\n return { qId, aId: aId.toString(), start, end };\r\n })\r\n .filter(Boolean) as Line[];\r\n\r\n setLines(newLines);\r\n }, [matches, getElementCenter]);\r\n\r\n return (\r\n <div\r\n className={cn(\"grid relative grid-cols-2 gap-10 select-none\", className)}\r\n ref={containerRef}\r\n >\r\n <svg className=\"absolute z-20 w-full h-full pointer-events-none\">\r\n {lines.map(({ qId, aId, start, end }) => (\r\n <g key={`${qId}-${aId}`}>\r\n <line\r\n x1={start.x}\r\n y1={start.y}\r\n x2={end.x}\r\n y2={end.y}\r\n stroke={lineColor}\r\n strokeWidth={3}\r\n strokeLinecap=\"round\"\r\n />\r\n <circle\r\n cx={start.x}\r\n cy={start.y}\r\n r={circleRadius}\r\n fill={circleColor}\r\n />\r\n <circle cx={end.x} cy={end.y} r={circleRadius} fill={circleColor} />\r\n </g>\r\n ))}\r\n {dragLine && (\r\n <g>\r\n <line\r\n x1={dragLine.start.x}\r\n y1={dragLine.start.y}\r\n x2={dragLine.end.x}\r\n y2={dragLine.end.y}\r\n stroke={lineColor}\r\n strokeWidth={3}\r\n strokeDasharray=\"5,5\"\r\n strokeLinecap=\"round\"\r\n />\r\n <circle\r\n cx={dragLine.start.x}\r\n cy={dragLine.start.y}\r\n r={circleRadius}\r\n fill={circleColor}\r\n />\r\n <circle\r\n cx={dragLine.end.x}\r\n cy={dragLine.end.y}\r\n r={circleRadius}\r\n fill={circleColor}\r\n />\r\n </g>\r\n )}\r\n </svg>\r\n\r\n <div className=\"relative z-10 space-y-3\">\r\n {questions.map((q) => {\r\n const isMatched = matches[q.id] !== undefined;\r\n return (\r\n <button\r\n key={q.id}\r\n ref={(el) => void (questionRefs.current[q.id] = el)}\r\n type=\"button\"\r\n onMouseDown={() => handleMouseDown(q.id)}\r\n onClick={() => isMatched && removeMatch(q.id)}\r\n className={cn(\r\n \"p-4 rounded bg-black text-white w-full font-medium focus:outline-none focus:ring-2 focus:ring-gray-500\",\r\n isMatched && \"bg-gray-700\",\r\n questionClassName\r\n )}\r\n >\r\n {q.text}\r\n </button>\r\n );\r\n })}\r\n </div>\r\n\r\n <div className=\"relative z-10 space-y-3\">\r\n {answers.map((a) => {\r\n const isMatched = Object.values(matches).includes(a.id);\r\n return (\r\n <button\r\n key={a.id}\r\n ref={(el) => void (answerRefs.current[a.id] = el)}\r\n type=\"button\"\r\n onMouseUp={() => handleMouseUp(a.id)}\r\n className={cn(\r\n \"p-4 rounded bg-black text-white w-full font-medium focus:outline-none focus:ring-2 focus:ring-gray-500\",\r\n isMatched && \"bg-gray-700\",\r\n answerClassName\r\n )}\r\n >\r\n {a.text}\r\n </button>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n );\r\n}\r\n","import { clsx, type ClassValue } from \"clsx\";\r\nimport { twMerge } from \"tailwind-merge\";\r\n\r\nexport function cn(...inputs: ClassValue[]) {\r\n return twMerge(clsx(inputs));\r\n}\r\n"],"mappings":"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","names":["aId","qId"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-matchings",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "description": "A React component for matching questions and answers",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.js",
package/src/index.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  import "./index.css";
2
2
  export { Matching } from "./matching";
3
+ export type { TMatch } from "./matching";