react-matchings 0.0.1 → 0.0.3

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Fares Galal
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1 +1,658 @@
1
+ # react-matchings
1
2
 
3
+ A React component for interactive question-answer matching. Create engaging quiz and assessment interfaces where users can drag and drop connections between questions and answers.
4
+
5
+ ## Features
6
+
7
+ - 🎯 **Drag and Drop Interface** - Intuitive drag-and-drop matching experience
8
+ - 🎨 **Highly Customizable** - Customize colors, styling, and behavior through props
9
+ - ♿ **Accessible** - Built with accessibility in mind
10
+ - 🎭 **Dynamic Styling** - Apply conditional styles based on component state
11
+ - 📱 **Responsive** - Works across different screen sizes
12
+ - 🎪 **Interactive Feedback** - Visual feedback during dragging and matching
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install react-matchings
18
+ ```
19
+
20
+ ```bash
21
+ yarn add react-matchings
22
+ ```
23
+
24
+ ```bash
25
+ pnpm add react-matchings
26
+ ```
27
+
28
+ ## Basic Usage
29
+
30
+ First, import the component and its CSS:
31
+
32
+ ```tsx
33
+ import { Matching } from "react-matchings";
34
+ import "react-matchings/dist/index.css";
35
+
36
+ function App() {
37
+ const questions = [
38
+ { id: 1, text: "What is React?" },
39
+ { id: 2, text: "What is TypeScript?" },
40
+ { id: 3, text: "What is JavaScript?" },
41
+ ];
42
+
43
+ const answers = [
44
+ { id: 1, text: "A JavaScript library for building UIs" },
45
+ { id: 2, text: "A typed superset of JavaScript" },
46
+ { id: 3, text: "A programming language" },
47
+ ];
48
+
49
+ const handleMatchChange = (matches) => {
50
+ console.log("Current matches:", matches);
51
+ // matches format: [{ questionId: 1, answerId: 1 }, ...]
52
+ };
53
+
54
+ return (
55
+ <Matching
56
+ questions={questions}
57
+ answers={answers}
58
+ onChange={handleMatchChange}
59
+ />
60
+ );
61
+ }
62
+ ```
63
+
64
+ ## Props
65
+
66
+ ### Required Props
67
+
68
+ #### `questions`
69
+
70
+ Array of question objects to display on the left side.
71
+
72
+ **Type:** `{ id: number; text: string }[]`
73
+
74
+ **Example:**
75
+
76
+ ```tsx
77
+ const questions = [
78
+ { id: 1, text: "Capital of France?" },
79
+ { id: 2, text: "Capital of Japan?" },
80
+ { id: 3, text: "Capital of Australia?" },
81
+ ];
82
+ ```
83
+
84
+ ---
85
+
86
+ #### `answers`
87
+
88
+ Array of answer objects to display on the right side.
89
+
90
+ **Type:** `{ id: number; text: string }[]`
91
+
92
+ **Example:**
93
+
94
+ ```tsx
95
+ const answers = [
96
+ { id: 1, text: "Paris" },
97
+ { id: 2, text: "Tokyo" },
98
+ { id: 3, text: "Canberra" },
99
+ ];
100
+ ```
101
+
102
+ **Note:** The number of questions and answers don't need to match. Users can connect any question to any answer.
103
+
104
+ ---
105
+
106
+ #### `onChange`
107
+
108
+ Callback function that is called whenever the matches change.
109
+
110
+ **Type:** `(matches: { questionId: number | string; answerId: number | string }[]) => void`
111
+
112
+ **Example:**
113
+
114
+ ```tsx
115
+ const handleChange = (matches) => {
116
+ // matches is an array of connections
117
+ // Example: [{ questionId: 1, answerId: 2 }, { questionId: 2, answerId: 1 }]
118
+ console.log("Matches updated:", matches);
119
+ // Save to state, send to API, etc.
120
+ };
121
+
122
+ <Matching onChange={handleChange} ... />
123
+ ```
124
+
125
+ ---
126
+
127
+ ### Optional Props
128
+
129
+ #### `className`
130
+
131
+ Additional CSS classes to apply to the container element.
132
+
133
+ **Type:** `string`
134
+
135
+ **Default:** `undefined`
136
+
137
+ **Example:**
138
+
139
+ ```tsx
140
+ <Matching
141
+ className="my-8 p-6 border border-gray-300 rounded-lg"
142
+ questions={questions}
143
+ answers={answers}
144
+ onChange={handleChange}
145
+ />
146
+ ```
147
+
148
+ ---
149
+
150
+ #### `questionClassName`
151
+
152
+ Custom CSS classes for question buttons. Can be a string or a function that receives state.
153
+
154
+ **Type:** `string | ((state: { isMatched: boolean; isDragging: boolean }) => string)`
155
+
156
+ **Default:** `undefined`
157
+
158
+ **Example (string):**
159
+
160
+ ```tsx
161
+ <Matching
162
+ questionClassName="bg-blue-500 hover:bg-blue-600 text-white font-bold"
163
+ questions={questions}
164
+ answers={answers}
165
+ onChange={handleChange}
166
+ />
167
+ ```
168
+
169
+ **Example (function with state):**
170
+
171
+ ```tsx
172
+ <Matching
173
+ questionClassName={({ isMatched, isDragging }) => {
174
+ if (isDragging) return "bg-yellow-500 text-black";
175
+ if (isMatched) return "bg-green-500 text-white";
176
+ return "bg-gray-200 text-gray-800";
177
+ }}
178
+ questions={questions}
179
+ answers={answers}
180
+ onChange={handleChange}
181
+ />
182
+ ```
183
+
184
+ **State properties:**
185
+
186
+ - `isMatched`: `boolean` - Whether the question is currently matched to an answer
187
+ - `isDragging`: `boolean` - Whether the question is currently being dragged
188
+
189
+ ---
190
+
191
+ #### `answerClassName`
192
+
193
+ Custom CSS classes for answer buttons. Can be a string or a function that receives state.
194
+
195
+ **Type:** `string | ((state: { isMatched: boolean; isHovering: boolean }) => string)`
196
+
197
+ **Default:** `undefined`
198
+
199
+ **Example (string):**
200
+
201
+ ```tsx
202
+ <Matching
203
+ answerClassName="bg-purple-500 hover:bg-purple-600 text-white"
204
+ questions={questions}
205
+ answers={answers}
206
+ onChange={handleChange}
207
+ />
208
+ ```
209
+
210
+ **Example (function with state):**
211
+
212
+ ```tsx
213
+ <Matching
214
+ answerClassName={({ isMatched, isHovering }) => {
215
+ if (isHovering && !isMatched)
216
+ return "bg-yellow-300 border-2 border-yellow-500";
217
+ if (isMatched) return "bg-green-400 text-white font-semibold";
218
+ return "bg-gray-100 text-gray-700";
219
+ }}
220
+ questions={questions}
221
+ answers={answers}
222
+ onChange={handleChange}
223
+ />
224
+ ```
225
+
226
+ **State properties:**
227
+
228
+ - `isMatched`: `boolean` - Whether the answer is currently matched to a question
229
+ - `isHovering`: `boolean` - Whether a question is being dragged over this answer
230
+
231
+ ---
232
+
233
+ #### `lineClassName`
234
+
235
+ Custom CSS classes for the SVG container that draws the connecting lines.
236
+
237
+ **Type:** `string`
238
+
239
+ **Default:** `undefined`
240
+
241
+ **Example:**
242
+
243
+ ```tsx
244
+ <Matching
245
+ lineClassName="opacity-90"
246
+ questions={questions}
247
+ answers={answers}
248
+ onChange={handleChange}
249
+ />
250
+ ```
251
+
252
+ ---
253
+
254
+ #### `lineColor`
255
+
256
+ Color of the connecting lines.
257
+
258
+ **Type:** `string`
259
+
260
+ **Default:** `"black"`
261
+
262
+ **Example:**
263
+
264
+ ```tsx
265
+ <Matching
266
+ lineColor="#3b82f6" // blue
267
+ questions={questions}
268
+ answers={answers}
269
+ onChange={handleChange}
270
+ />
271
+
272
+ // Or use CSS color names
273
+ <Matching
274
+ lineColor="rgb(59, 130, 246)"
275
+ questions={questions}
276
+ answers={answers}
277
+ onChange={handleChange}
278
+ />
279
+ ```
280
+
281
+ ---
282
+
283
+ #### `circleColor`
284
+
285
+ Color of the circles at the ends of the connecting lines.
286
+
287
+ **Type:** `string`
288
+
289
+ **Default:** `"white"`
290
+
291
+ **Example:**
292
+
293
+ ```tsx
294
+ <Matching
295
+ circleColor="#f3f4f6" // light gray
296
+ questions={questions}
297
+ answers={answers}
298
+ onChange={handleChange}
299
+ />
300
+ ```
301
+
302
+ ---
303
+
304
+ #### `circleRadius`
305
+
306
+ Radius of the circles at the ends of the connecting lines, in pixels.
307
+
308
+ **Type:** `number`
309
+
310
+ **Default:** `8`
311
+
312
+ **Example:**
313
+
314
+ ```tsx
315
+ <Matching
316
+ circleRadius={12}
317
+ questions={questions}
318
+ answers={answers}
319
+ onChange={handleChange}
320
+ />
321
+ ```
322
+
323
+ ---
324
+
325
+ #### `offset`
326
+
327
+ Offset distance from the edges where lines connect, in pixels. Controls how far from the edge the connection points are.
328
+
329
+ **Type:** `number`
330
+
331
+ **Default:** `10`
332
+
333
+ **Example:**
334
+
335
+ ```tsx
336
+ <Matching
337
+ offset={15}
338
+ questions={questions}
339
+ answers={answers}
340
+ onChange={handleChange}
341
+ />
342
+ ```
343
+
344
+ ---
345
+
346
+ #### `disabled`
347
+
348
+ Whether the component is disabled. When disabled, users cannot create or remove matches.
349
+
350
+ **Type:** `boolean`
351
+
352
+ **Default:** `false`
353
+
354
+ **Example:**
355
+
356
+ ```tsx
357
+ const [isDisabled, setIsDisabled] = useState(false);
358
+
359
+ <Matching
360
+ disabled={isDisabled}
361
+ questions={questions}
362
+ answers={answers}
363
+ onChange={handleChange}
364
+ />
365
+
366
+ <button onClick={() => setIsDisabled(!isDisabled)}>
367
+ {isDisabled ? "Enable" : "Disable"} Matching
368
+ </button>
369
+ ```
370
+
371
+ ---
372
+
373
+ ## Complete Examples
374
+
375
+ ### Example 1: Basic Quiz Component
376
+
377
+ ```tsx
378
+ import { useState } from "react";
379
+ import { Matching } from "react-matchings";
380
+ import "react-matchings/dist/index.css";
381
+
382
+ function QuizApp() {
383
+ const questions = [
384
+ { id: 1, text: "What is the capital of France?" },
385
+ { id: 2, text: "What is the capital of Japan?" },
386
+ { id: 3, text: "What is the capital of Australia?" },
387
+ ];
388
+
389
+ const answers = [
390
+ { id: 1, text: "Paris" },
391
+ { id: 2, text: "Tokyo" },
392
+ { id: 3, text: "Canberra" },
393
+ ];
394
+
395
+ const [matches, setMatches] = useState([]);
396
+ const [submitted, setSubmitted] = useState(false);
397
+
398
+ const handleSubmit = () => {
399
+ setSubmitted(true);
400
+ // Check answers, calculate score, etc.
401
+ console.log("Submitted matches:", matches);
402
+ };
403
+
404
+ return (
405
+ <div className="p-8 max-w-4xl mx-auto">
406
+ <h1 className="text-2xl font-bold mb-6">Geography Quiz</h1>
407
+
408
+ <Matching
409
+ questions={questions}
410
+ answers={answers}
411
+ onChange={setMatches}
412
+ disabled={submitted}
413
+ />
414
+
415
+ <button
416
+ onClick={handleSubmit}
417
+ disabled={submitted || matches.length === 0}
418
+ className="mt-6 px-6 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 disabled:bg-gray-400"
419
+ >
420
+ Submit Answers
421
+ </button>
422
+ </div>
423
+ );
424
+ }
425
+ ```
426
+
427
+ ### Example 2: Custom Styled Component
428
+
429
+ ```tsx
430
+ import { Matching } from "react-matchings";
431
+ import "react-matchings/dist/index.css";
432
+
433
+ function StyledMatching() {
434
+ const questions = [
435
+ { id: 1, text: "Question 1" },
436
+ { id: 2, text: "Question 2" },
437
+ ];
438
+
439
+ const answers = [
440
+ { id: 1, text: "Answer 1" },
441
+ { id: 2, text: "Answer 2" },
442
+ ];
443
+
444
+ return (
445
+ <Matching
446
+ questions={questions}
447
+ answers={answers}
448
+ onChange={(matches) => console.log(matches)}
449
+ className="p-8 bg-gradient-to-br from-blue-50 to-purple-50 rounded-xl shadow-lg"
450
+ questionClassName={({ isMatched, isDragging }) => {
451
+ let base = "p-4 rounded-lg font-semibold transition-all duration-200 ";
452
+ if (isDragging)
453
+ base += "bg-yellow-400 text-yellow-900 shadow-lg scale-105";
454
+ else if (isMatched) base += "bg-green-500 text-white";
455
+ else base += "bg-blue-500 text-white hover:bg-blue-600";
456
+ return base;
457
+ }}
458
+ answerClassName={({ isMatched, isHovering }) => {
459
+ let base = "p-4 rounded-lg font-semibold transition-all duration-200 ";
460
+ if (isHovering && !isMatched)
461
+ base += "bg-yellow-300 text-yellow-900 border-2 border-yellow-500";
462
+ else if (isMatched) base += "bg-green-500 text-white";
463
+ else base += "bg-purple-500 text-white hover:bg-purple-600";
464
+ return base;
465
+ }}
466
+ lineColor="#8b5cf6"
467
+ circleColor="#e9d5ff"
468
+ circleRadius={10}
469
+ offset={12}
470
+ />
471
+ );
472
+ }
473
+ ```
474
+
475
+ ### Example 3: With Initial Matches
476
+
477
+ ```tsx
478
+ import { useState, useEffect } from "react";
479
+ import { Matching } from "react-matchings";
480
+ import "react-matchings/dist/index.css";
481
+
482
+ function MatchingWithInitialState() {
483
+ const questions = [
484
+ { id: 1, text: "React" },
485
+ { id: 2, text: "Vue" },
486
+ { id: 3, text: "Angular" },
487
+ ];
488
+
489
+ const answers = [
490
+ { id: 1, text: "Facebook" },
491
+ { id: 2, text: "Evan You" },
492
+ { id: 3, text: "Google" },
493
+ ];
494
+
495
+ const [matches, setMatches] = useState([]);
496
+
497
+ // Load initial matches (e.g., from localStorage or API)
498
+ useEffect(() => {
499
+ const savedMatches = localStorage.getItem("matches");
500
+ if (savedMatches) {
501
+ setMatches(JSON.parse(savedMatches));
502
+ }
503
+ }, []);
504
+
505
+ // Save matches when they change
506
+ const handleMatchChange = (newMatches) => {
507
+ setMatches(newMatches);
508
+ localStorage.setItem("matches", JSON.stringify(newMatches));
509
+ };
510
+
511
+ return (
512
+ <Matching
513
+ questions={questions}
514
+ answers={answers}
515
+ onChange={handleMatchChange}
516
+ />
517
+ );
518
+ }
519
+ ```
520
+
521
+ ### Example 4: Assessment with Validation
522
+
523
+ ```tsx
524
+ import { useState, useMemo } from "react";
525
+ import { Matching } from "react-matchings";
526
+ import "react-matchings/dist/index.css";
527
+
528
+ function AssessmentComponent() {
529
+ const questions = [
530
+ { id: 1, text: "Primary color" },
531
+ { id: 2, text: "Secondary color" },
532
+ { id: 3, text: "Tertiary color" },
533
+ ];
534
+
535
+ const answers = [
536
+ { id: 1, text: "Red, Blue, Yellow" },
537
+ { id: 2, text: "Orange, Green, Purple" },
538
+ { id: 3, text: "Red-Orange, Yellow-Green, Blue-Purple" },
539
+ ];
540
+
541
+ // Correct answers
542
+ const correctMatches = [
543
+ { questionId: 1, answerId: 1 },
544
+ { questionId: 2, answerId: 2 },
545
+ { questionId: 3, answerId: 3 },
546
+ ];
547
+
548
+ const [matches, setMatches] = useState([]);
549
+ const [showResults, setShowResults] = useState(false);
550
+
551
+ const score = useMemo(() => {
552
+ if (!showResults) return null;
553
+ const correct = matches.filter((match) =>
554
+ correctMatches.some(
555
+ (cm) =>
556
+ cm.questionId === match.questionId && cm.answerId === match.answerId
557
+ )
558
+ ).length;
559
+ return { correct, total: questions.length };
560
+ }, [matches, showResults]);
561
+
562
+ return (
563
+ <div className="p-8">
564
+ <Matching
565
+ questions={questions}
566
+ answers={answers}
567
+ onChange={setMatches}
568
+ disabled={showResults}
569
+ />
570
+
571
+ {showResults && score && (
572
+ <div className="mt-6 p-4 bg-gray-100 rounded">
573
+ <p className="text-lg font-semibold">
574
+ Score: {score.correct} / {score.total}
575
+ </p>
576
+ </div>
577
+ )}
578
+
579
+ <button
580
+ onClick={() => setShowResults(true)}
581
+ disabled={showResults || matches.length < questions.length}
582
+ className="mt-4 px-6 py-2 bg-blue-500 text-white rounded"
583
+ >
584
+ Check Answers
585
+ </button>
586
+ </div>
587
+ );
588
+ }
589
+ ```
590
+
591
+ ## How It Works
592
+
593
+ 1. **Drag to Connect**: Click and hold on a question, then drag to an answer and release to create a connection.
594
+
595
+ 2. **Remove Connection**: Click on a matched question to remove its connection.
596
+
597
+ 3. **Visual Feedback**:
598
+
599
+ - Dragging shows a dashed line following your cursor
600
+ - Matched items are visually distinguished
601
+ - Hovering over answers while dragging highlights them
602
+
603
+ 4. **State Management**: The `onChange` callback receives an array of all current matches whenever they change.
604
+
605
+ ## Styling
606
+
607
+ The component uses Tailwind CSS for styling. Make sure to import the CSS file:
608
+
609
+ ```tsx
610
+ import "react-matchings/dist/index.css";
611
+ ```
612
+
613
+ You can override default styles using the className props, or customize the colors using the color props.
614
+
615
+ ## TypeScript Support
616
+
617
+ This package includes TypeScript definitions. The component is fully typed:
618
+
619
+ ```tsx
620
+ import { Matching } from "react-matchings";
621
+
622
+ // Types are automatically inferred
623
+ const handleChange = (
624
+ matches: { questionId: number | string; answerId: number | string }[]
625
+ ) => {
626
+ // matches is properly typed
627
+ };
628
+ ```
629
+
630
+ ## Accessibility
631
+
632
+ The component includes accessibility features:
633
+
634
+ - Proper ARIA attributes (`aria-pressed`)
635
+ - Keyboard-friendly interactions
636
+ - Focus management
637
+ - Semantic HTML structure
638
+
639
+ ## Browser Support
640
+
641
+ Works in all modern browsers that support:
642
+
643
+ - React 18+
644
+ - CSS Grid
645
+ - SVG
646
+ - Drag and Drop API
647
+
648
+ ## License
649
+
650
+ MIT
651
+
652
+ ## Contributing
653
+
654
+ Contributions are welcome! Please feel free to submit a Pull Request.
655
+
656
+ ## Author
657
+
658
+ Fares Galal
package/dist/index.css CHANGED
@@ -1,2 +1,2 @@
1
1
  /*! tailwindcss v4.1.18 | MIT License | https://tailwindcss.com */
2
- @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-space-y-reverse:0;--tw-font-weight:initial;--tw-duration:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000}}}@layer theme{:root,:host{--font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-gray-500:oklch(55.1% .027 264.364);--color-gray-600:oklch(44.6% .03 256.802);--color-gray-700:oklch(37.3% .034 259.733);--color-gray-800:oklch(27.8% .033 256.848);--color-black:#000;--color-white:#fff;--spacing:.25rem;--font-weight-medium:500;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.absolute{position:absolute}.relative{position:relative}.z-10{z-index:10}.z-20{z-index:20}.grid{display:grid}.h-full{height:100%}.w-full{width:100%}.cursor-default{cursor:default}.cursor-pointer{cursor:pointer}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.gap-10{gap:calc(var(--spacing)*10)}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*3)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*3)*calc(1 - var(--tw-space-y-reverse)))}.rounded{border-radius:.25rem}.border-gray-500{border-color:var(--color-gray-500)}.border-gray-600{border-color:var(--color-gray-600)}.bg-black{background-color:var(--color-black)}.bg-gray-500{background-color:var(--color-gray-500)}.bg-gray-700{background-color:var(--color-gray-700)}.bg-gray-800{background-color:var(--color-gray-800)}.bg-none{background-image:none}.p-4{padding:calc(var(--spacing)*4)}.ps-7{padding-inline-start:calc(var(--spacing)*7)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.text-white{color:var(--color-white)}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-200{--tw-duration:.2s;transition-duration:.2s}.select-none{-webkit-user-select:none;user-select:none}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(2px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus\:ring-gray-500:focus{--tw-ring-color:var(--color-gray-500)}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}
2
+ @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1;--tw-space-y-reverse:0;--tw-border-style:solid;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-font-weight:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-duration:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-yellow-300:oklch(90.5% .182 98.111);--color-yellow-400:oklch(85.2% .199 91.936);--color-yellow-500:oklch(79.5% .184 86.047);--color-yellow-900:oklch(42.1% .095 57.708);--color-green-400:oklch(79.2% .209 151.711);--color-green-500:oklch(72.3% .219 149.579);--color-blue-50:oklch(97% .014 254.604);--color-blue-500:oklch(62.3% .214 259.815);--color-blue-600:oklch(54.6% .245 262.881);--color-purple-50:oklch(97.7% .014 308.299);--color-purple-500:oklch(62.7% .265 303.9);--color-purple-600:oklch(55.8% .288 302.321);--color-gray-100:oklch(96.7% .003 264.542);--color-gray-200:oklch(92.8% .006 264.531);--color-gray-300:oklch(87.2% .01 258.338);--color-gray-400:oklch(70.7% .022 261.325);--color-gray-500:oklch(55.1% .027 264.364);--color-gray-600:oklch(44.6% .03 256.802);--color-gray-700:oklch(37.3% .034 259.733);--color-gray-800:oklch(27.8% .033 256.848);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-4xl:56rem;--text-lg:1.125rem;--text-lg--line-height:calc(1.75/1.125);--text-2xl:1.5rem;--text-2xl--line-height:calc(2/1.5);--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--radius-lg:.5rem;--radius-xl:.75rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.absolute{position:absolute}.relative{position:relative}.z-10{z-index:10}.z-20{z-index:20}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.mx-auto{margin-inline:auto}.my-8{margin-block:calc(var(--spacing)*8)}.mt-4{margin-top:calc(var(--spacing)*4)}.mt-6{margin-top:calc(var(--spacing)*6)}.mb-6{margin-bottom:calc(var(--spacing)*6)}.grid{display:grid}.h-full{height:100%}.w-full{width:100%}.max-w-4xl{max-width:var(--container-4xl)}.scale-105{--tw-scale-x:105%;--tw-scale-y:105%;--tw-scale-z:105%;scale:var(--tw-scale-x)var(--tw-scale-y)}.cursor-default{cursor:default}.cursor-pointer{cursor:pointer}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.gap-10{gap:calc(var(--spacing)*10)}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*3)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*3)*calc(1 - var(--tw-space-y-reverse)))}.rounded{border-radius:.25rem}.rounded-lg{border-radius:var(--radius-lg)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-gray-300{border-color:var(--color-gray-300)}.border-gray-500{border-color:var(--color-gray-500)}.border-gray-600{border-color:var(--color-gray-600)}.border-yellow-500{border-color:var(--color-yellow-500)}.bg-black{background-color:var(--color-black)}.bg-blue-500{background-color:var(--color-blue-500)}.bg-gray-100{background-color:var(--color-gray-100)}.bg-gray-200{background-color:var(--color-gray-200)}.bg-gray-500{background-color:var(--color-gray-500)}.bg-gray-700{background-color:var(--color-gray-700)}.bg-gray-800{background-color:var(--color-gray-800)}.bg-green-400{background-color:var(--color-green-400)}.bg-green-500{background-color:var(--color-green-500)}.bg-purple-500{background-color:var(--color-purple-500)}.bg-yellow-300{background-color:var(--color-yellow-300)}.bg-yellow-400{background-color:var(--color-yellow-400)}.bg-yellow-500{background-color:var(--color-yellow-500)}.bg-gradient-to-br{--tw-gradient-position:to bottom right in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.bg-none{background-image:none}.from-blue-50{--tw-gradient-from:var(--color-blue-50);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-purple-50{--tw-gradient-to:var(--color-purple-50);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.p-4{padding:calc(var(--spacing)*4)}.p-6{padding:calc(var(--spacing)*6)}.p-8{padding:calc(var(--spacing)*8)}.px-6{padding-inline:calc(var(--spacing)*6)}.py-2{padding-block:calc(var(--spacing)*2)}.ps-7{padding-inline-start:calc(var(--spacing)*7)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.text-black{color:var(--color-black)}.text-gray-700{color:var(--color-gray-700)}.text-gray-800{color:var(--color-gray-800)}.text-white{color:var(--color-white)}.text-yellow-900{color:var(--color-yellow-900)}.opacity-90{opacity:.9}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a),0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-200{--tw-duration:.2s;transition-duration:.2s}.select-none{-webkit-user-select:none;user-select:none}@media (hover:hover){.hover\:bg-blue-600:hover{background-color:var(--color-blue-600)}.hover\:bg-purple-600:hover{background-color:var(--color-purple-600)}}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(2px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus\:ring-gray-500:focus{--tw-ring-color:var(--color-gray-500)}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.disabled\:bg-gray-400:disabled{background-color:var(--color-gray-400)}}@property --tw-scale-x{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-y{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-z{syntax:"*";inherits:false;initial-value:1}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-gradient-position{syntax:"*";inherits:false}@property --tw-gradient-from{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:"*";inherits:false}@property --tw-gradient-via-stops{syntax:"*";inherits:false}@property --tw-gradient-from-position{syntax:"<length-percentage>";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:"<length-percentage>";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:"<length-percentage>";inherits:false;initial-value:100%}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-duration{syntax:"*";inherits:false}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-matchings",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "A React component for matching questions and answers",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.js",
@@ -8,12 +8,13 @@
8
8
  "scripts": {
9
9
  "build": "tsup src/index.ts --format cjs,esm --dts && npm run build:css",
10
10
  "build:css": "npx tailwindcss -i ./src/index.css -o ./dist/index.css --minify",
11
+ "prepublishOnly": "npm run build",
11
12
  "test": "echo \"Error: no test specified\" && exit 1",
12
13
  "lint": "tsc"
13
14
  },
14
15
  "repository": {
15
16
  "type": "git",
16
- "url": "git+https://github.com/F-47/react-qa-matching.git"
17
+ "url": "git+https://github.com/F-47/react-matchings"
17
18
  },
18
19
  "keywords": [
19
20
  "react",