@dcg-overseas/number-line 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,703 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import React, { useRef, useState, useCallback, useEffect, createContext, useContext, memo } from "react";
3
+ function useHistory() {
4
+ const stackRef = useRef([]);
5
+ const [stackLen, setStackLen] = useState(0);
6
+ const push = useCallback((op) => {
7
+ stackRef.current = [...stackRef.current, op];
8
+ setStackLen(stackRef.current.length);
9
+ }, []);
10
+ const undo = useCallback((strokes) => {
11
+ if (stackRef.current.length === 0) return { strokes: null, arcIndices: [] };
12
+ const op = stackRef.current[stackRef.current.length - 1];
13
+ stackRef.current = stackRef.current.slice(0, -1);
14
+ setStackLen(stackRef.current.length);
15
+ switch (op.type) {
16
+ case "add":
17
+ return {
18
+ strokes: strokes.filter((s) => !op.strokes.some((os) => os.id === s.id)),
19
+ arcIndices: []
20
+ };
21
+ case "delete":
22
+ return {
23
+ strokes: op.strokesBefore,
24
+ arcIndices: op.arcIndices
25
+ };
26
+ }
27
+ }, []);
28
+ const clear = useCallback(() => {
29
+ stackRef.current = [];
30
+ setStackLen(0);
31
+ }, []);
32
+ return { push, undo, clear, canUndo: stackLen > 0 };
33
+ }
34
+ function useDrawing() {
35
+ const [strokes, setStrokes] = useState([]);
36
+ const [tool, setTool] = useState("none");
37
+ const drawing = useRef(false);
38
+ const pointCount = useRef(0);
39
+ const currentD = useRef("");
40
+ const currentId = useRef("");
41
+ const toggleTool = useCallback((t) => {
42
+ setTool((prev) => {
43
+ if (prev === t) return "none";
44
+ return t;
45
+ });
46
+ setStrokes((prev) => prev.map((s) => ({ ...s, selected: false })));
47
+ }, []);
48
+ const startStroke = useCallback((x, y) => {
49
+ drawing.current = true;
50
+ pointCount.current = 1;
51
+ currentD.current = `M ${x} ${y}`;
52
+ currentId.current = `${Date.now()}-${Math.random()}`;
53
+ }, []);
54
+ const continueStroke = useCallback((x, y) => {
55
+ if (!drawing.current) return null;
56
+ pointCount.current++;
57
+ currentD.current += ` L ${x} ${y}`;
58
+ return {
59
+ id: currentId.current,
60
+ d: currentD.current,
61
+ selected: false
62
+ };
63
+ }, []);
64
+ const endStroke = useCallback(() => {
65
+ if (!drawing.current) return null;
66
+ drawing.current = false;
67
+ if (pointCount.current < 2) {
68
+ currentD.current = "";
69
+ pointCount.current = 0;
70
+ return null;
71
+ }
72
+ const stroke = {
73
+ id: currentId.current,
74
+ d: currentD.current,
75
+ selected: false
76
+ };
77
+ currentD.current = "";
78
+ pointCount.current = 0;
79
+ return stroke;
80
+ }, []);
81
+ const toggleSelect = useCallback((id) => {
82
+ setStrokes(
83
+ (prev) => prev.map((s) => s.id === id ? { ...s, selected: !s.selected } : s)
84
+ );
85
+ }, []);
86
+ const eraseStroke = useCallback((id) => {
87
+ setStrokes((prev) => prev.filter((s) => s.id !== id));
88
+ }, []);
89
+ const addStroke = useCallback((stroke) => {
90
+ setStrokes((prev) => [...prev, stroke]);
91
+ }, []);
92
+ const deleteSelected = useCallback(() => {
93
+ setStrokes((prev) => prev.filter((s) => !s.selected));
94
+ }, []);
95
+ const resetStrokes = useCallback(() => {
96
+ setStrokes([]);
97
+ }, []);
98
+ const restoreStrokes = useCallback((restored) => {
99
+ setStrokes(restored);
100
+ }, []);
101
+ return {
102
+ strokes,
103
+ tool,
104
+ toggleTool,
105
+ startStroke,
106
+ continueStroke,
107
+ endStroke,
108
+ toggleSelect,
109
+ eraseStroke,
110
+ addStroke,
111
+ deleteSelected,
112
+ resetStrokes,
113
+ restoreStrokes
114
+ };
115
+ }
116
+ function useContainerSize() {
117
+ const ref = useRef(null);
118
+ const [width, setWidth] = useState(600);
119
+ useEffect(() => {
120
+ const el = ref.current;
121
+ if (!el) return;
122
+ const ro = new ResizeObserver((entries) => {
123
+ var _a;
124
+ const w = (_a = entries[0]) == null ? void 0 : _a.contentRect.width;
125
+ if (w && w > 0) setWidth(w);
126
+ });
127
+ ro.observe(el);
128
+ const rect = el.getBoundingClientRect();
129
+ if (rect.width > 0) setWidth(rect.width);
130
+ return () => ro.disconnect();
131
+ }, []);
132
+ return { ref, width };
133
+ }
134
+ const NumberLineContext = createContext(null);
135
+ function useNumberLineContext() {
136
+ const ctx = useContext(NumberLineContext);
137
+ if (!ctx) throw new Error("Must be used inside <NumberLineProvider>");
138
+ return ctx;
139
+ }
140
+ const DESIGN_WIDTH = 1e3;
141
+ const DESIGN_HEIGHT = 200;
142
+ function NumberLineProvider({
143
+ min,
144
+ max,
145
+ groupSize,
146
+ groupCount,
147
+ tickStep,
148
+ arcColors,
149
+ children
150
+ }) {
151
+ const [selectedArcIndices, setSelectedArcIndices] = useState(/* @__PURE__ */ new Set());
152
+ const [deletedArcIndices, setDeletedArcIndices] = useState(/* @__PURE__ */ new Set());
153
+ const { ref: svgRef, width: containerWidth } = useContainerSize();
154
+ const history = useHistory();
155
+ const drawing = useDrawing();
156
+ const [liveStroke, setLiveStroke] = useState(null);
157
+ const svgPoint = useRef(null);
158
+ useEffect(() => {
159
+ setDeletedArcIndices(/* @__PURE__ */ new Set());
160
+ setSelectedArcIndices(/* @__PURE__ */ new Set());
161
+ }, [min, max, groupSize, groupCount]);
162
+ const getLocalCoords = useCallback(
163
+ (e) => {
164
+ const svg = svgRef.current;
165
+ if (!svg) return null;
166
+ const ctm = svg.getScreenCTM();
167
+ if (!ctm) return null;
168
+ if (!svgPoint.current) svgPoint.current = svg.createSVGPoint();
169
+ svgPoint.current.x = e.clientX;
170
+ svgPoint.current.y = e.clientY;
171
+ const pt = svgPoint.current.matrixTransform(ctm.inverse());
172
+ return [pt.x, pt.y];
173
+ },
174
+ [svgRef]
175
+ );
176
+ const onPointerDown = useCallback(
177
+ (e) => {
178
+ e.currentTarget.focus();
179
+ if (drawing.tool !== "pen") return;
180
+ e.currentTarget.setPointerCapture(e.pointerId);
181
+ const coords = getLocalCoords(e);
182
+ if (!coords) return;
183
+ drawing.startStroke(...coords);
184
+ },
185
+ [drawing, getLocalCoords]
186
+ );
187
+ const onPointerMove = useCallback(
188
+ (e) => {
189
+ if (drawing.tool !== "pen") return;
190
+ const coords = getLocalCoords(e);
191
+ if (!coords) return;
192
+ const live = drawing.continueStroke(...coords);
193
+ if (live) setLiveStroke(live);
194
+ },
195
+ [drawing, getLocalCoords]
196
+ );
197
+ const onPointerUp = useCallback(() => {
198
+ if (drawing.tool !== "pen") return;
199
+ const stroke = drawing.endStroke();
200
+ setLiveStroke(null);
201
+ if (stroke) {
202
+ drawing.addStroke(stroke);
203
+ history.push({ type: "add", strokes: [stroke] });
204
+ }
205
+ }, [drawing, history]);
206
+ const onStrokeClick = useCallback(
207
+ (id, e) => {
208
+ e.stopPropagation();
209
+ if (drawing.tool === "eraser") {
210
+ const target = drawing.strokes.find((s) => s.id === id);
211
+ if (target) {
212
+ const strokesBefore = drawing.strokes;
213
+ drawing.eraseStroke(id);
214
+ history.push({ type: "delete", strokesBefore, arcIndices: [] });
215
+ }
216
+ } else if (drawing.tool === "none") {
217
+ drawing.toggleSelect(id);
218
+ }
219
+ },
220
+ [drawing, history]
221
+ );
222
+ const onArcClick = useCallback(
223
+ (groupIndex, e) => {
224
+ e.stopPropagation();
225
+ if (drawing.tool === "eraser") {
226
+ const strokesBefore = drawing.strokes;
227
+ setDeletedArcIndices((prev) => /* @__PURE__ */ new Set([...prev, groupIndex]));
228
+ history.push({ type: "delete", strokesBefore, arcIndices: [groupIndex] });
229
+ } else if (drawing.tool === "none") {
230
+ setSelectedArcIndices((prev) => {
231
+ const next = new Set(prev);
232
+ if (next.has(groupIndex)) next.delete(groupIndex);
233
+ else next.add(groupIndex);
234
+ return next;
235
+ });
236
+ }
237
+ },
238
+ [drawing.tool, drawing.strokes, history]
239
+ );
240
+ const clearArcSelection = useCallback(() => setSelectedArcIndices(/* @__PURE__ */ new Set()), []);
241
+ const onDelete = useCallback(() => {
242
+ const strokesBefore = drawing.strokes;
243
+ const deletedStrokes = drawing.strokes.filter((s) => s.selected);
244
+ const deletedArcs = [...selectedArcIndices];
245
+ if (deletedStrokes.length === 0 && deletedArcs.length === 0) return;
246
+ if (deletedStrokes.length > 0) drawing.deleteSelected();
247
+ if (deletedArcs.length > 0) {
248
+ setDeletedArcIndices((prev) => /* @__PURE__ */ new Set([...prev, ...deletedArcs]));
249
+ setSelectedArcIndices(/* @__PURE__ */ new Set());
250
+ }
251
+ history.push({ type: "delete", strokesBefore, arcIndices: deletedArcs });
252
+ }, [drawing, history, selectedArcIndices]);
253
+ const onReset = useCallback(() => {
254
+ drawing.resetStrokes();
255
+ history.clear();
256
+ setDeletedArcIndices(/* @__PURE__ */ new Set());
257
+ setSelectedArcIndices(/* @__PURE__ */ new Set());
258
+ }, [drawing, history]);
259
+ const onUndo = useCallback(() => {
260
+ const result = history.undo(drawing.strokes);
261
+ if (result.strokes !== null) drawing.restoreStrokes(result.strokes);
262
+ if (result.arcIndices.length > 0) {
263
+ setDeletedArcIndices((prev) => {
264
+ const next = new Set(prev);
265
+ result.arcIndices.forEach((i) => next.delete(i));
266
+ return next;
267
+ });
268
+ }
269
+ }, [history, drawing]);
270
+ const onTogglePen = useCallback(
271
+ () => {
272
+ drawing.toggleTool("pen");
273
+ clearArcSelection();
274
+ },
275
+ [drawing, clearArcSelection]
276
+ );
277
+ const onToggleEraser = useCallback(
278
+ () => {
279
+ drawing.toggleTool("eraser");
280
+ clearArcSelection();
281
+ },
282
+ [drawing, clearArcSelection]
283
+ );
284
+ const canDelete = drawing.strokes.some((s) => s.selected) || selectedArcIndices.size > 0;
285
+ useEffect(() => {
286
+ setSelectedArcIndices(/* @__PURE__ */ new Set());
287
+ }, [drawing.tool]);
288
+ const keyHandlers = useRef({ toggleTool: drawing.toggleTool, clearArcSelection, canDelete, onDelete, onUndo });
289
+ keyHandlers.current = { toggleTool: drawing.toggleTool, clearArcSelection, canDelete, onDelete, onUndo };
290
+ useEffect(() => {
291
+ const svg = svgRef.current;
292
+ if (!svg) return;
293
+ const onKey = (e) => {
294
+ const h = keyHandlers.current;
295
+ if (e.key === "Escape") {
296
+ h.toggleTool("none");
297
+ h.clearArcSelection();
298
+ } else if ((e.key === "Delete" || e.key === "Backspace") && h.canDelete) {
299
+ e.preventDefault();
300
+ h.onDelete();
301
+ } else if (e.key === "z" && (e.ctrlKey || e.metaKey)) {
302
+ e.preventDefault();
303
+ h.onUndo();
304
+ }
305
+ };
306
+ svg.addEventListener("keydown", onKey);
307
+ return () => svg.removeEventListener("keydown", onKey);
308
+ }, [svgRef]);
309
+ const svgCursor = drawing.tool === "pen" ? "crosshair" : drawing.tool === "eraser" ? "cell" : "default";
310
+ return /* @__PURE__ */ jsx(
311
+ NumberLineContext.Provider,
312
+ {
313
+ value: {
314
+ svgRef,
315
+ viewWidth: DESIGN_WIDTH,
316
+ containerWidth,
317
+ svgCursor,
318
+ min,
319
+ max,
320
+ groupSize,
321
+ groupCount,
322
+ tickStep,
323
+ arcColors,
324
+ tool: drawing.tool,
325
+ strokes: drawing.strokes,
326
+ liveStroke,
327
+ selectedArcIndices,
328
+ deletedArcIndices,
329
+ onPointerDown,
330
+ onPointerMove,
331
+ onPointerUp,
332
+ onStrokeClick,
333
+ onArcClick,
334
+ canDelete,
335
+ canUndo: history.canUndo,
336
+ onTogglePen,
337
+ onToggleEraser,
338
+ onDelete,
339
+ onReset,
340
+ onUndo
341
+ },
342
+ children
343
+ }
344
+ );
345
+ }
346
+ function buildArcPath({ x1, x2, y, rx, ry }) {
347
+ return `M ${x1} ${y} A ${rx} ${ry} 0 0 1 ${x2} ${y}`;
348
+ }
349
+ function computeLabelStep(containerWidth, range) {
350
+ const maxLabels = Math.floor(containerWidth / 40);
351
+ if (maxLabels <= 0) return range;
352
+ const raw = range / maxLabels;
353
+ const candidates = [1, 2, 5, 10, 20, 25, 50, 100, 200, 500];
354
+ return candidates.find((c) => c >= raw) ?? candidates[candidates.length - 1];
355
+ }
356
+ const ARC_COLORS = [
357
+ "#7c3aed",
358
+ "#0891b2",
359
+ "#d97706",
360
+ "#be185d",
361
+ "#16a34a"
362
+ ];
363
+ const AxisLayer = React.memo(function AxisLayer2({
364
+ min,
365
+ max,
366
+ axisY,
367
+ padLeft,
368
+ padRight,
369
+ viewWidth,
370
+ containerWidth,
371
+ groupSize,
372
+ tickStep
373
+ }) {
374
+ const range = max - min;
375
+ if (range <= 0) return null;
376
+ const usable = viewWidth - padLeft - padRight;
377
+ const toX = (v) => padLeft + (v - min) / range * usable;
378
+ const step = Math.max(1, Math.round(tickStep));
379
+ const rawLabelStep = computeLabelStep(containerWidth, range);
380
+ const labelStep = Math.max(step, Math.ceil(rawLabelStep / step) * step);
381
+ const MAX_TICKS = 500;
382
+ const minorStep = Math.max(1, Math.ceil(range / MAX_TICKS));
383
+ const allTicks = [];
384
+ for (let v = min; v <= max; v += minorStep) allTicks.push(v);
385
+ return /* @__PURE__ */ jsxs("g", { className: "nl-axis-layer", children: [
386
+ /* @__PURE__ */ jsx(
387
+ "line",
388
+ {
389
+ x1: padLeft - 4,
390
+ y1: axisY,
391
+ x2: viewWidth - padRight,
392
+ y2: axisY,
393
+ stroke: "#374151",
394
+ strokeWidth: 2
395
+ }
396
+ ),
397
+ allTicks.map((v) => {
398
+ const x = toX(v);
399
+ const offset = v - min;
400
+ const isMajor = offset % step === 0;
401
+ const isGroupBoundary = groupSize > 0 && offset % groupSize === 0;
402
+ const showLabel = isMajor && offset % labelStep === 0;
403
+ const tickH = isGroupBoundary ? 10 : isMajor ? 7 : 4;
404
+ const strokeW = isGroupBoundary ? 1.5 : isMajor ? 1 : 0.5;
405
+ const color = isMajor ? "#374151" : "#9ca3af";
406
+ return /* @__PURE__ */ jsxs("g", { children: [
407
+ /* @__PURE__ */ jsx(
408
+ "line",
409
+ {
410
+ x1: x,
411
+ y1: axisY - tickH,
412
+ x2: x,
413
+ y2: axisY + tickH,
414
+ stroke: color,
415
+ strokeWidth: strokeW
416
+ }
417
+ ),
418
+ showLabel && /* @__PURE__ */ jsx(
419
+ "text",
420
+ {
421
+ x,
422
+ y: axisY + 22,
423
+ textAnchor: "middle",
424
+ fontSize: 11,
425
+ fill: "#374151",
426
+ pointerEvents: "none",
427
+ style: { userSelect: "none", WebkitUserSelect: "none" },
428
+ children: v
429
+ }
430
+ )
431
+ ] }, v);
432
+ })
433
+ ] });
434
+ });
435
+ const GroupArcsLayer = memo(function GroupArcsLayer2({
436
+ min,
437
+ max,
438
+ groupSize,
439
+ groupCount,
440
+ axisY,
441
+ padLeft,
442
+ padRight,
443
+ viewWidth,
444
+ arcMaxHeight,
445
+ tool,
446
+ selectedArcIndices,
447
+ deletedArcIndices,
448
+ onArcClick,
449
+ arcColors = ARC_COLORS
450
+ }) {
451
+ if (groupSize <= 0 || groupCount <= 0) return null;
452
+ const range = max - min;
453
+ const usable = viewWidth - padLeft - padRight;
454
+ const toX = (v) => padLeft + (v - min) / range * usable;
455
+ const arcs = [];
456
+ for (let g = 0; g < groupCount; g++) {
457
+ if (deletedArcIndices.has(g)) continue;
458
+ const start = min + g * groupSize;
459
+ const end = start + groupSize;
460
+ if (end > max) break;
461
+ const x1 = toX(start);
462
+ const x2 = toX(end);
463
+ const rx = (x2 - x1) / 2;
464
+ const ry = Math.min(rx * 0.7, arcMaxHeight);
465
+ const color = arcColors[g % arcColors.length];
466
+ const textY = axisY - ry - 6;
467
+ const arrowHeadH = 7;
468
+ const arrowHeadHW = 4;
469
+ const arcPath = buildArcPath({ x1, x2, y: axisY, rx, ry });
470
+ const isSelected = selectedArcIndices.has(g);
471
+ const hitCursor = tool === "eraser" ? "cell" : tool === "none" ? "pointer" : "default";
472
+ arcs.push(
473
+ /* @__PURE__ */ jsxs("g", { children: [
474
+ isSelected && /* @__PURE__ */ jsx(
475
+ "path",
476
+ {
477
+ d: arcPath,
478
+ fill: "none",
479
+ stroke: "rgba(0,0,0,0.15)",
480
+ strokeWidth: 14,
481
+ strokeLinecap: "round",
482
+ pointerEvents: "none"
483
+ }
484
+ ),
485
+ /* @__PURE__ */ jsx(
486
+ "path",
487
+ {
488
+ d: arcPath,
489
+ fill: "none",
490
+ stroke: isSelected ? "#1d4ed8" : color,
491
+ strokeWidth: isSelected ? 3 : 2,
492
+ pointerEvents: "none"
493
+ }
494
+ ),
495
+ /* @__PURE__ */ jsx(
496
+ "path",
497
+ {
498
+ d: arcPath,
499
+ fill: "none",
500
+ stroke: "transparent",
501
+ strokeWidth: 20,
502
+ strokeLinecap: "round",
503
+ pointerEvents: "stroke",
504
+ style: { cursor: hitCursor },
505
+ onPointerDown: (e) => {
506
+ if (tool === "eraser" || tool === "none") {
507
+ e.stopPropagation();
508
+ onArcClick(g, e);
509
+ }
510
+ }
511
+ }
512
+ ),
513
+ /* @__PURE__ */ jsx(
514
+ "text",
515
+ {
516
+ x: x2,
517
+ y: textY,
518
+ textAnchor: "middle",
519
+ fontSize: 10,
520
+ fill: isSelected ? "#1d4ed8" : color,
521
+ fontWeight: "600",
522
+ pointerEvents: "none",
523
+ style: { userSelect: "none", WebkitUserSelect: "none" },
524
+ children: end
525
+ }
526
+ ),
527
+ /* @__PURE__ */ jsx(
528
+ "line",
529
+ {
530
+ x1: x2,
531
+ y1: textY + 4,
532
+ x2,
533
+ y2: axisY - arrowHeadH,
534
+ stroke: isSelected ? "#1d4ed8" : color,
535
+ strokeWidth: 1.5,
536
+ pointerEvents: "none"
537
+ }
538
+ ),
539
+ /* @__PURE__ */ jsx(
540
+ "polygon",
541
+ {
542
+ points: `${x2},${axisY} ${x2 - arrowHeadHW},${axisY - arrowHeadH} ${x2 + arrowHeadHW},${axisY - arrowHeadH}`,
543
+ fill: isSelected ? "#1d4ed8" : color,
544
+ pointerEvents: "none"
545
+ }
546
+ )
547
+ ] }, g)
548
+ );
549
+ }
550
+ return /* @__PURE__ */ jsx("g", { className: "nl-arcs-layer", children: arcs });
551
+ });
552
+ function DrawingLayer({ strokes, liveStroke, tool, onStrokeClick }) {
553
+ return /* @__PURE__ */ jsxs("g", { className: "nl-drawing-layer", children: [
554
+ strokes.map((s) => /* @__PURE__ */ jsxs("g", { children: [
555
+ s.selected && /* @__PURE__ */ jsx(
556
+ "path",
557
+ {
558
+ d: s.d,
559
+ fill: "none",
560
+ stroke: "rgba(0,0,0,0.15)",
561
+ strokeWidth: 18,
562
+ strokeLinecap: "round",
563
+ strokeLinejoin: "round",
564
+ pointerEvents: "none"
565
+ }
566
+ ),
567
+ /* @__PURE__ */ jsx(
568
+ "path",
569
+ {
570
+ d: s.d,
571
+ fill: "none",
572
+ stroke: "transparent",
573
+ strokeWidth: tool === "eraser" ? 32 : 28,
574
+ strokeLinecap: "round",
575
+ strokeLinejoin: "round",
576
+ pointerEvents: "stroke",
577
+ style: { cursor: tool === "eraser" ? "cell" : tool === "none" ? "pointer" : "default" },
578
+ onPointerDown: (e) => {
579
+ if (tool === "eraser" || tool === "none") {
580
+ e.stopPropagation();
581
+ onStrokeClick(s.id, e);
582
+ }
583
+ }
584
+ }
585
+ ),
586
+ /* @__PURE__ */ jsx(
587
+ "path",
588
+ {
589
+ d: s.d,
590
+ fill: "none",
591
+ stroke: "#7c3aed",
592
+ strokeWidth: 2.5,
593
+ strokeLinecap: "round",
594
+ strokeLinejoin: "round",
595
+ pointerEvents: "none"
596
+ }
597
+ )
598
+ ] }, s.id)),
599
+ liveStroke && /* @__PURE__ */ jsx(
600
+ "path",
601
+ {
602
+ d: liveStroke.d,
603
+ fill: "none",
604
+ stroke: "#7c3aed",
605
+ strokeWidth: 2.5,
606
+ strokeLinecap: "round",
607
+ strokeLinejoin: "round",
608
+ pointerEvents: "none",
609
+ opacity: 0.7
610
+ }
611
+ )
612
+ ] });
613
+ }
614
+ const PAD_LEFT = 30;
615
+ const PAD_RIGHT = 40;
616
+ const AXIS_Y = 130;
617
+ const ARC_MAX_HEIGHT = 80;
618
+ function NumberLine({ className }) {
619
+ const {
620
+ svgRef,
621
+ containerWidth,
622
+ svgCursor,
623
+ min,
624
+ max,
625
+ groupSize,
626
+ groupCount,
627
+ tickStep,
628
+ arcColors,
629
+ tool,
630
+ strokes,
631
+ liveStroke,
632
+ selectedArcIndices,
633
+ deletedArcIndices,
634
+ onPointerDown,
635
+ onPointerMove,
636
+ onPointerUp,
637
+ onStrokeClick,
638
+ onArcClick
639
+ } = useNumberLineContext();
640
+ return /* @__PURE__ */ jsxs(
641
+ "svg",
642
+ {
643
+ ref: svgRef,
644
+ tabIndex: 0,
645
+ className: className ? `nl-svg ${className}` : "nl-svg",
646
+ viewBox: `0 0 ${DESIGN_WIDTH} ${DESIGN_HEIGHT}`,
647
+ preserveAspectRatio: "xMidYMid meet",
648
+ style: { width: "100%", height: "100%", display: "block", outline: "none", cursor: svgCursor, touchAction: "none" },
649
+ onPointerDown,
650
+ onPointerMove,
651
+ onPointerUp,
652
+ children: [
653
+ /* @__PURE__ */ jsx(
654
+ AxisLayer,
655
+ {
656
+ min,
657
+ max,
658
+ axisY: AXIS_Y,
659
+ padLeft: PAD_LEFT,
660
+ padRight: PAD_RIGHT,
661
+ viewWidth: DESIGN_WIDTH,
662
+ containerWidth,
663
+ groupSize,
664
+ tickStep
665
+ }
666
+ ),
667
+ /* @__PURE__ */ jsx(
668
+ GroupArcsLayer,
669
+ {
670
+ min,
671
+ max,
672
+ groupSize,
673
+ groupCount,
674
+ axisY: AXIS_Y,
675
+ padLeft: PAD_LEFT,
676
+ padRight: PAD_RIGHT,
677
+ viewWidth: DESIGN_WIDTH,
678
+ arcMaxHeight: ARC_MAX_HEIGHT,
679
+ tool,
680
+ selectedArcIndices,
681
+ deletedArcIndices,
682
+ onArcClick,
683
+ arcColors
684
+ }
685
+ ),
686
+ /* @__PURE__ */ jsx(
687
+ DrawingLayer,
688
+ {
689
+ strokes,
690
+ liveStroke,
691
+ tool,
692
+ onStrokeClick
693
+ }
694
+ )
695
+ ]
696
+ }
697
+ );
698
+ }
699
+ export {
700
+ NumberLine,
701
+ NumberLineProvider,
702
+ useNumberLineContext
703
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dcg-overseas/number-line",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Interactive number line component with group arcs and freehand drawing",
5
5
  "type": "module",
6
6
  "license": "MIT",