@sensebox/flash-tool 0.1.0 → 1.0.0
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/basic-OBQD77DM.js +6 -0
- package/dist/basic-OBQD77DM.js.map +1 -0
- package/dist/basic-PDQS3NQS.cjs +6 -0
- package/dist/basic-PDQS3NQS.cjs.map +1 -0
- package/dist/index.cjs +514 -52
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +574 -112
- package/dist/index.js.map +1 -1
- package/dist/style.css +288 -11
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -190,12 +190,17 @@ var DEFAULT_FLASH_OPTIONS = {
|
|
|
190
190
|
eraseAll: false,
|
|
191
191
|
usingUsbOtg: true
|
|
192
192
|
};
|
|
193
|
+
var KNOWN_USB_DEVICES = {
|
|
194
|
+
"303a:81b8": "senseBox MCU-S2 (ESP32-S2)",
|
|
195
|
+
"303a:2": "senseBox MCU-S2 (ESP32-S2 bootloader)"
|
|
196
|
+
};
|
|
193
197
|
function labelForPort(port) {
|
|
194
198
|
var _a;
|
|
195
199
|
const info = _nullishCoalesce(((_a = port.getInfo) == null ? void 0 : _a.call(port)), () => ( {}));
|
|
196
200
|
const vendor = info.usbVendorId ? info.usbVendorId.toString(16).padStart(4, "0") : "????";
|
|
197
201
|
const product = info.usbProductId ? info.usbProductId.toString(16).padStart(4, "0") : "????";
|
|
198
|
-
|
|
202
|
+
const known = info.usbVendorId !== void 0 && info.usbProductId !== void 0 ? KNOWN_USB_DEVICES[`${info.usbVendorId.toString(16)}:${info.usbProductId.toString(16)}`] : void 0;
|
|
203
|
+
return known || `USB device (VID 0x${vendor} / PID 0x${product})`;
|
|
199
204
|
}
|
|
200
205
|
function useFlashDevice({
|
|
201
206
|
usbVendorId = DEFAULT_USB_VENDOR_ID,
|
|
@@ -222,10 +227,17 @@ function useFlashDevice({
|
|
|
222
227
|
filters: [{ usbVendorId }]
|
|
223
228
|
});
|
|
224
229
|
setPort(selectedPort);
|
|
225
|
-
setBootloaderPort(null);
|
|
226
230
|
setNeedsBootloaderPermission(false);
|
|
227
231
|
const label = labelForPort(selectedPort);
|
|
228
232
|
setDeviceLabel(label);
|
|
233
|
+
if (isRomBootloaderPort(selectedPort, usbVendorId)) {
|
|
234
|
+
setBootloaderPort(selectedPort);
|
|
235
|
+
appendLog(
|
|
236
|
+
"Board is already in bootloader mode - skipping reset.\n"
|
|
237
|
+
);
|
|
238
|
+
} else {
|
|
239
|
+
setBootloaderPort(null);
|
|
240
|
+
}
|
|
229
241
|
return selectedPort;
|
|
230
242
|
} catch (err) {
|
|
231
243
|
if ((err == null ? void 0 : err.name) !== "NotFoundError") {
|
|
@@ -233,7 +245,7 @@ function useFlashDevice({
|
|
|
233
245
|
}
|
|
234
246
|
return null;
|
|
235
247
|
}
|
|
236
|
-
}, [usbVendorId]);
|
|
248
|
+
}, [usbVendorId, appendLog]);
|
|
237
249
|
const disconnect = _react.useCallback.call(void 0, () => {
|
|
238
250
|
setPort(null);
|
|
239
251
|
setBootloaderPort(null);
|
|
@@ -391,7 +403,7 @@ function useFlashDevice({
|
|
|
391
403
|
var LOADERS = {
|
|
392
404
|
circuitpy: () => Promise.resolve().then(() => _interopRequireWildcard(require("./circuitpy-YPOEPYDE.cjs"))),
|
|
393
405
|
ota: () => Promise.resolve().then(() => _interopRequireWildcard(require("./ota-FYGBPZA7.cjs"))),
|
|
394
|
-
basic: () => Promise.resolve().then(() => _interopRequireWildcard(require("./basic-
|
|
406
|
+
basic: () => Promise.resolve().then(() => _interopRequireWildcard(require("./basic-PDQS3NQS.cjs"))),
|
|
395
407
|
standard: () => Promise.resolve().then(() => _interopRequireWildcard(require("./standard-N65QFGWL.cjs")))
|
|
396
408
|
};
|
|
397
409
|
var BUILTIN_FIRMWARE_TYPES = Object.keys(LOADERS);
|
|
@@ -410,15 +422,263 @@ async function loadBuiltinFirmware(type) {
|
|
|
410
422
|
return base64ToBytes(module.default);
|
|
411
423
|
}
|
|
412
424
|
|
|
425
|
+
// src/react/Dropdown.jsx
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
function Dropdown({
|
|
429
|
+
options,
|
|
430
|
+
value,
|
|
431
|
+
onChange,
|
|
432
|
+
disabled = false,
|
|
433
|
+
placeholder,
|
|
434
|
+
className,
|
|
435
|
+
"aria-label": ariaLabel
|
|
436
|
+
}) {
|
|
437
|
+
const [open, setOpen] = _react.useState.call(void 0, false);
|
|
438
|
+
const [activeIndex, setActiveIndex] = _react.useState.call(void 0, -1);
|
|
439
|
+
const rootRef = _react.useRef.call(void 0, null);
|
|
440
|
+
const triggerRef = _react.useRef.call(void 0, null);
|
|
441
|
+
const optionRefs = _react.useRef.call(void 0, []);
|
|
442
|
+
const selectedIndex = options.findIndex((option) => option.value === value);
|
|
443
|
+
const selected = selectedIndex >= 0 ? options[selectedIndex] : null;
|
|
444
|
+
_react.useEffect.call(void 0, () => {
|
|
445
|
+
if (disabled && open) setOpen(false);
|
|
446
|
+
}, [disabled, open]);
|
|
447
|
+
_react.useEffect.call(void 0, () => {
|
|
448
|
+
if (!open) return;
|
|
449
|
+
const onDocPointerDown = (event) => {
|
|
450
|
+
if (rootRef.current && !rootRef.current.contains(event.target)) {
|
|
451
|
+
setOpen(false);
|
|
452
|
+
}
|
|
453
|
+
};
|
|
454
|
+
document.addEventListener("pointerdown", onDocPointerDown);
|
|
455
|
+
return () => document.removeEventListener("pointerdown", onDocPointerDown);
|
|
456
|
+
}, [open]);
|
|
457
|
+
_react.useEffect.call(void 0, () => {
|
|
458
|
+
if (!open) return;
|
|
459
|
+
setActiveIndex(selectedIndex >= 0 ? selectedIndex : 0);
|
|
460
|
+
}, [open, selectedIndex]);
|
|
461
|
+
_react.useEffect.call(void 0, () => {
|
|
462
|
+
var _a;
|
|
463
|
+
if (!open || activeIndex < 0) return;
|
|
464
|
+
(_a = optionRefs.current[activeIndex]) == null ? void 0 : _a.focus();
|
|
465
|
+
}, [open, activeIndex]);
|
|
466
|
+
const commit = (index) => {
|
|
467
|
+
var _a;
|
|
468
|
+
const option = options[index];
|
|
469
|
+
if (!option || option.disabled) return;
|
|
470
|
+
onChange == null ? void 0 : onChange(option.value);
|
|
471
|
+
setOpen(false);
|
|
472
|
+
(_a = triggerRef.current) == null ? void 0 : _a.focus();
|
|
473
|
+
};
|
|
474
|
+
const handleTriggerKeyDown = (event) => {
|
|
475
|
+
if (disabled) return;
|
|
476
|
+
if (event.key === "Enter" || event.key === " " || event.key === "ArrowDown" || event.key === "ArrowUp") {
|
|
477
|
+
event.preventDefault();
|
|
478
|
+
setOpen(true);
|
|
479
|
+
}
|
|
480
|
+
};
|
|
481
|
+
const moveActive = (delta) => {
|
|
482
|
+
setActiveIndex((current) => {
|
|
483
|
+
const count = options.length;
|
|
484
|
+
let next = current;
|
|
485
|
+
for (let i = 0; i < count; i++) {
|
|
486
|
+
next = (next + delta + count) % count;
|
|
487
|
+
if (!options[next].disabled) return next;
|
|
488
|
+
}
|
|
489
|
+
return current;
|
|
490
|
+
});
|
|
491
|
+
};
|
|
492
|
+
const handleListKeyDown = (event) => {
|
|
493
|
+
var _a;
|
|
494
|
+
switch (event.key) {
|
|
495
|
+
case "ArrowDown":
|
|
496
|
+
event.preventDefault();
|
|
497
|
+
moveActive(1);
|
|
498
|
+
break;
|
|
499
|
+
case "ArrowUp":
|
|
500
|
+
event.preventDefault();
|
|
501
|
+
moveActive(-1);
|
|
502
|
+
break;
|
|
503
|
+
case "Home":
|
|
504
|
+
event.preventDefault();
|
|
505
|
+
setActiveIndex(0);
|
|
506
|
+
break;
|
|
507
|
+
case "End":
|
|
508
|
+
event.preventDefault();
|
|
509
|
+
setActiveIndex(options.length - 1);
|
|
510
|
+
break;
|
|
511
|
+
case "Enter":
|
|
512
|
+
case " ":
|
|
513
|
+
event.preventDefault();
|
|
514
|
+
commit(activeIndex);
|
|
515
|
+
break;
|
|
516
|
+
case "Escape":
|
|
517
|
+
event.preventDefault();
|
|
518
|
+
setOpen(false);
|
|
519
|
+
(_a = triggerRef.current) == null ? void 0 : _a.focus();
|
|
520
|
+
break;
|
|
521
|
+
case "Tab":
|
|
522
|
+
setOpen(false);
|
|
523
|
+
break;
|
|
524
|
+
default:
|
|
525
|
+
break;
|
|
526
|
+
}
|
|
527
|
+
};
|
|
528
|
+
return /* @__PURE__ */ _react2.default.createElement(
|
|
529
|
+
"div",
|
|
530
|
+
{
|
|
531
|
+
ref: rootRef,
|
|
532
|
+
className: `sbdropdown${open ? " sbdropdown--open" : ""}${disabled ? " sbdropdown--disabled" : ""}${className ? ` ${className}` : ""}`
|
|
533
|
+
},
|
|
534
|
+
/* @__PURE__ */ _react2.default.createElement(
|
|
535
|
+
"button",
|
|
536
|
+
{
|
|
537
|
+
ref: triggerRef,
|
|
538
|
+
type: "button",
|
|
539
|
+
className: "sbdropdown__trigger",
|
|
540
|
+
"aria-haspopup": "listbox",
|
|
541
|
+
"aria-expanded": open,
|
|
542
|
+
"aria-label": ariaLabel,
|
|
543
|
+
disabled,
|
|
544
|
+
onClick: () => setOpen((v) => !v),
|
|
545
|
+
onKeyDown: handleTriggerKeyDown
|
|
546
|
+
},
|
|
547
|
+
/* @__PURE__ */ _react2.default.createElement("span", { className: "sbdropdown__icon-slot" }, selected == null ? void 0 : selected.icon),
|
|
548
|
+
/* @__PURE__ */ _react2.default.createElement("span", { className: "sbdropdown__trigger-label" }, (selected == null ? void 0 : selected.label) || placeholder),
|
|
549
|
+
/* @__PURE__ */ _react2.default.createElement(IconChevron, { className: "sbdropdown__chevron" })
|
|
550
|
+
),
|
|
551
|
+
/* @__PURE__ */ _react2.default.createElement(
|
|
552
|
+
"ul",
|
|
553
|
+
{
|
|
554
|
+
className: "sbdropdown__menu",
|
|
555
|
+
role: "listbox",
|
|
556
|
+
"aria-label": ariaLabel,
|
|
557
|
+
onKeyDown: handleListKeyDown
|
|
558
|
+
},
|
|
559
|
+
options.map((option, index) => /* @__PURE__ */ _react2.default.createElement("li", { key: option.value, role: "presentation" }, /* @__PURE__ */ _react2.default.createElement(
|
|
560
|
+
"button",
|
|
561
|
+
{
|
|
562
|
+
ref: (el) => {
|
|
563
|
+
optionRefs.current[index] = el;
|
|
564
|
+
},
|
|
565
|
+
type: "button",
|
|
566
|
+
role: "option",
|
|
567
|
+
"aria-selected": option.value === value,
|
|
568
|
+
tabIndex: -1,
|
|
569
|
+
className: `sbdropdown__option${option.value === value ? " sbdropdown__option--selected" : ""}${index === activeIndex ? " sbdropdown__option--active" : ""}`,
|
|
570
|
+
disabled: option.disabled,
|
|
571
|
+
onClick: () => commit(index),
|
|
572
|
+
onMouseEnter: () => setActiveIndex(index)
|
|
573
|
+
},
|
|
574
|
+
/* @__PURE__ */ _react2.default.createElement("span", { className: "sbdropdown__icon-slot" }, option.icon),
|
|
575
|
+
/* @__PURE__ */ _react2.default.createElement("span", { className: "sbdropdown__option-label" }, option.label),
|
|
576
|
+
option.value === value && /* @__PURE__ */ _react2.default.createElement(IconCheck, { className: "sbdropdown__option-check" })
|
|
577
|
+
)))
|
|
578
|
+
)
|
|
579
|
+
);
|
|
580
|
+
}
|
|
581
|
+
function IconChevron({ className }) {
|
|
582
|
+
return /* @__PURE__ */ _react2.default.createElement(
|
|
583
|
+
"svg",
|
|
584
|
+
{
|
|
585
|
+
className,
|
|
586
|
+
viewBox: "0 0 10 6",
|
|
587
|
+
width: "10",
|
|
588
|
+
height: "6",
|
|
589
|
+
fill: "none",
|
|
590
|
+
stroke: "currentColor",
|
|
591
|
+
strokeWidth: "1.5",
|
|
592
|
+
strokeLinecap: "round",
|
|
593
|
+
strokeLinejoin: "round",
|
|
594
|
+
"aria-hidden": "true"
|
|
595
|
+
},
|
|
596
|
+
/* @__PURE__ */ _react2.default.createElement("path", { d: "M1 1l4 4 4-4" })
|
|
597
|
+
);
|
|
598
|
+
}
|
|
599
|
+
function IconCheck({ className }) {
|
|
600
|
+
return /* @__PURE__ */ _react2.default.createElement(
|
|
601
|
+
"svg",
|
|
602
|
+
{
|
|
603
|
+
className,
|
|
604
|
+
viewBox: "0 0 16 16",
|
|
605
|
+
width: "12",
|
|
606
|
+
height: "12",
|
|
607
|
+
fill: "none",
|
|
608
|
+
stroke: "currentColor",
|
|
609
|
+
strokeWidth: "2",
|
|
610
|
+
strokeLinecap: "round",
|
|
611
|
+
strokeLinejoin: "round",
|
|
612
|
+
"aria-hidden": "true"
|
|
613
|
+
},
|
|
614
|
+
/* @__PURE__ */ _react2.default.createElement("path", { d: "M3 8.5 6.5 12 13 4.5" })
|
|
615
|
+
);
|
|
616
|
+
}
|
|
617
|
+
Dropdown.propTypes = {
|
|
618
|
+
options: _proptypes2.default.arrayOf(
|
|
619
|
+
_proptypes2.default.shape({
|
|
620
|
+
value: _proptypes2.default.string.isRequired,
|
|
621
|
+
label: _proptypes2.default.node.isRequired,
|
|
622
|
+
icon: _proptypes2.default.node,
|
|
623
|
+
disabled: _proptypes2.default.bool
|
|
624
|
+
})
|
|
625
|
+
).isRequired,
|
|
626
|
+
value: _proptypes2.default.string,
|
|
627
|
+
onChange: _proptypes2.default.func,
|
|
628
|
+
disabled: _proptypes2.default.bool,
|
|
629
|
+
placeholder: _proptypes2.default.string,
|
|
630
|
+
className: _proptypes2.default.string,
|
|
631
|
+
"aria-label": _proptypes2.default.string
|
|
632
|
+
};
|
|
633
|
+
|
|
413
634
|
// src/react/FlashTool.jsx
|
|
414
635
|
var builtinFirmwareCache = /* @__PURE__ */ new Map();
|
|
415
636
|
var FIRMWARE_TYPES = ["circuitpy", "ota", "basic", "standard"];
|
|
637
|
+
var FIRMWARE_ALIASES = {
|
|
638
|
+
circuitpython: "circuitpy"
|
|
639
|
+
};
|
|
640
|
+
function resolveFirmwareType(value) {
|
|
641
|
+
if (!value) return void 0;
|
|
642
|
+
return FIRMWARE_ALIASES[value] || value;
|
|
643
|
+
}
|
|
416
644
|
var BUILTIN_FIRMWARE_FLASH_OVERRIDES = {
|
|
417
645
|
circuitpy: { address: 0, eraseAll: true },
|
|
418
646
|
ota: { address: 0, eraseAll: true },
|
|
419
647
|
basic: { address: 0, eraseAll: true },
|
|
420
648
|
standard: { address: 0, eraseAll: true }
|
|
421
649
|
};
|
|
650
|
+
var DEFAULT_FIRMWARE_DESCRIPTIONS = {
|
|
651
|
+
circuitpy: {
|
|
652
|
+
text: "Install CircuitPython on your senseBox now! For a more detailed tutorial, check out our",
|
|
653
|
+
linkText: "docs",
|
|
654
|
+
linkUrl: "https://docs.sensebox.de/docs/editors/circuitpython/circuitpython_esp32/?board=edus2"
|
|
655
|
+
},
|
|
656
|
+
ota: {
|
|
657
|
+
text: "Flashes the senseBox OTA firmware, which lets you update your senseBox wirelessly afterwards."
|
|
658
|
+
},
|
|
659
|
+
basic: {
|
|
660
|
+
text: "A minimal starter sketch - a good starting point for your own senseBox projects."
|
|
661
|
+
},
|
|
662
|
+
standard: {
|
|
663
|
+
text: "The TinyUF2 bootloader, ready to read out and upload data from your connected sensors."
|
|
664
|
+
}
|
|
665
|
+
};
|
|
666
|
+
var DEFAULT_FIRMWARE_DESCRIPTIONS_DE = {
|
|
667
|
+
circuitpy: {
|
|
668
|
+
text: "Installiere jetzt CircuitPython auf deiner senseBox! Ein ausf\xFChrliches Tutorial findest du in unserer",
|
|
669
|
+
linkText: "Dokumentation",
|
|
670
|
+
linkUrl: "https://docs.sensebox.de/docs/editors/circuitpython/circuitpython_esp32/?board=edus2"
|
|
671
|
+
},
|
|
672
|
+
ota: {
|
|
673
|
+
text: "Spielt die senseBox-OTA-Firmware auf, mit der du deine senseBox anschlie\xDFend drahtlos aktualisieren kannst."
|
|
674
|
+
},
|
|
675
|
+
basic: {
|
|
676
|
+
text: "Ein minimales Starter-Sketch - ein guter Ausgangspunkt f\xFCr eigene senseBox-Projekte."
|
|
677
|
+
},
|
|
678
|
+
standard: {
|
|
679
|
+
text: "Das Standard-senseBox-Sketch, bereit zum Auslesen und Hochladen von Daten deiner angeschlossenen Sensoren."
|
|
680
|
+
}
|
|
681
|
+
};
|
|
422
682
|
var DEFAULT_STRINGS = {
|
|
423
683
|
unsupported: "Web Serial is not supported in this browser.",
|
|
424
684
|
connect: "Connect board",
|
|
@@ -432,16 +692,26 @@ var DEFAULT_STRINGS = {
|
|
|
432
692
|
flash: "Upload",
|
|
433
693
|
flashing: "Uploading...",
|
|
434
694
|
done: "Upload complete",
|
|
695
|
+
newUpload: "Start new upload",
|
|
435
696
|
error: "Upload failed",
|
|
436
697
|
retry: "Retry",
|
|
437
698
|
disconnect: "Disconnect",
|
|
438
699
|
showLog: "Show log",
|
|
439
700
|
hideLog: "Hide log",
|
|
701
|
+
logPlaceholder: 'Click "Connect board" to see the log here.',
|
|
440
702
|
sketchLabel: "Sketch",
|
|
703
|
+
step1Title: "Connect your board",
|
|
704
|
+
step1Hint: "Plug in your senseBox, then pick it from the browser's device list.",
|
|
705
|
+
step2Title: "Enter bootloader mode",
|
|
706
|
+
step2Hint: "Put the board into upload mode.",
|
|
707
|
+
step2HintPermission: "Select the bootloader port the browser is asking for.",
|
|
708
|
+
step2Done: "Bootloader ready",
|
|
709
|
+
step3Title: "Upload firmware",
|
|
710
|
+
step3Hint: "Waiting for the previous steps to finish.",
|
|
441
711
|
firmwareCircuitpy: "CircuitPython",
|
|
442
712
|
firmwareOta: "senseBox OTA",
|
|
443
|
-
firmwareBasic: "
|
|
444
|
-
firmwareStandard: "
|
|
713
|
+
firmwareBasic: "senseBox:basic",
|
|
714
|
+
firmwareStandard: "TinyUF2",
|
|
445
715
|
help: "Help",
|
|
446
716
|
helpTitle: "How it works",
|
|
447
717
|
helpStep1: "Connect your senseBox",
|
|
@@ -450,15 +720,60 @@ var DEFAULT_STRINGS = {
|
|
|
450
720
|
helpStep4: "Start the upload",
|
|
451
721
|
helpClose: "Close"
|
|
452
722
|
};
|
|
723
|
+
var DEFAULT_STRINGS_DE = {
|
|
724
|
+
unsupported: "Web Serial wird von diesem Browser nicht unterst\xFCtzt.",
|
|
725
|
+
connect: "Board verbinden",
|
|
726
|
+
connecting: "Verbinde...",
|
|
727
|
+
connected: "senseBox verbunden",
|
|
728
|
+
prepare: "Upload vorbereiten",
|
|
729
|
+
preparing: "Bereite vor...",
|
|
730
|
+
grantPermission: "Bootloader-Port ausw\xE4hlen",
|
|
731
|
+
waitingForBinary: "Warte auf Firmware...",
|
|
732
|
+
loadingFirmware: "Firmware wird geladen...",
|
|
733
|
+
flash: "Hochladen",
|
|
734
|
+
flashing: "Wird hochgeladen...",
|
|
735
|
+
done: "Upload abgeschlossen",
|
|
736
|
+
newUpload: "Neuen Upload starten",
|
|
737
|
+
error: "Upload fehlgeschlagen",
|
|
738
|
+
retry: "Erneut versuchen",
|
|
739
|
+
disconnect: "Trennen",
|
|
740
|
+
showLog: "Protokoll anzeigen",
|
|
741
|
+
hideLog: "Protokoll ausblenden",
|
|
742
|
+
logPlaceholder: 'Klicke auf "Board verbinden", um das Protokoll hier zu sehen.',
|
|
743
|
+
sketchLabel: "Sketch",
|
|
744
|
+
step1Title: "Board verbinden",
|
|
745
|
+
step1Hint: "Schlie\xDFe deine senseBox an und w\xE4hle sie aus der Ger\xE4teliste des Browsers aus.",
|
|
746
|
+
step2Title: "Bootloader-Modus aktivieren",
|
|
747
|
+
step2Hint: "Versetze das Board in den Upload-Modus.",
|
|
748
|
+
step2HintPermission: "W\xE4hle den Bootloader-Port aus, nach dem der Browser fragt.",
|
|
749
|
+
step2Done: "Bootloader bereit",
|
|
750
|
+
step3Title: "Firmware hochladen",
|
|
751
|
+
step3Hint: "Warte auf die vorherigen Schritte.",
|
|
752
|
+
firmwareCircuitpy: "CircuitPython",
|
|
753
|
+
firmwareOta: "senseBox OTA",
|
|
754
|
+
firmwareBasic: "senseBox:basic",
|
|
755
|
+
firmwareStandard: "TinyUF2",
|
|
756
|
+
help: "Hilfe",
|
|
757
|
+
helpTitle: "So funktioniert's",
|
|
758
|
+
helpStep1: "Verbinde deine senseBox",
|
|
759
|
+
helpStep2: "W\xE4hle einen Sketch aus",
|
|
760
|
+
helpStep3: "Erteile deinem Browser die Berechtigung",
|
|
761
|
+
helpStep4: "Starte den Upload",
|
|
762
|
+
helpClose: "Schlie\xDFen"
|
|
763
|
+
};
|
|
453
764
|
function FlashTool({
|
|
454
765
|
binary,
|
|
455
766
|
firmwares,
|
|
767
|
+
firmware,
|
|
456
768
|
firmwareType,
|
|
457
769
|
defaultFirmwareType,
|
|
458
770
|
firmwareFlashOptions,
|
|
771
|
+
firmwareDescriptions,
|
|
459
772
|
usbVendorId,
|
|
460
773
|
flashOptions,
|
|
461
774
|
autoFlash = true,
|
|
775
|
+
expand = false,
|
|
776
|
+
language = "en",
|
|
462
777
|
strings,
|
|
463
778
|
className,
|
|
464
779
|
onConnected,
|
|
@@ -467,18 +782,25 @@ function FlashTool({
|
|
|
467
782
|
onError,
|
|
468
783
|
onFirmwareTypeChange
|
|
469
784
|
}) {
|
|
470
|
-
const merged = {
|
|
471
|
-
|
|
785
|
+
const merged = {
|
|
786
|
+
...language === "de" ? DEFAULT_STRINGS_DE : DEFAULT_STRINGS,
|
|
787
|
+
...strings
|
|
788
|
+
};
|
|
789
|
+
const [logOpen, setLogOpen] = _react2.default.useState(expand);
|
|
472
790
|
const [helpOpen, setHelpOpen] = _react2.default.useState(false);
|
|
473
791
|
const [busy, setBusy] = _react2.default.useState(null);
|
|
792
|
+
const lockedFirmwareType = resolveFirmwareType(firmwareType || firmware);
|
|
474
793
|
const [selectedType, setSelectedType] = _react2.default.useState(
|
|
475
|
-
|
|
794
|
+
lockedFirmwareType || defaultFirmwareType || FIRMWARE_TYPES[0]
|
|
476
795
|
);
|
|
477
|
-
const firmwareLocked = Boolean(
|
|
796
|
+
const firmwareLocked = Boolean(lockedFirmwareType);
|
|
478
797
|
const showFirmwarePicker = Boolean(firmwares) || !binary || firmwareLocked;
|
|
479
798
|
_react.useEffect.call(void 0, () => {
|
|
480
|
-
if (
|
|
481
|
-
}, [
|
|
799
|
+
if (lockedFirmwareType) setSelectedType(lockedFirmwareType);
|
|
800
|
+
}, [lockedFirmwareType]);
|
|
801
|
+
_react.useEffect.call(void 0, () => {
|
|
802
|
+
if (expand) setLogOpen(true);
|
|
803
|
+
}, [expand]);
|
|
482
804
|
_react.useEffect.call(void 0, () => {
|
|
483
805
|
if (!helpOpen) return;
|
|
484
806
|
const onKeyDown = (event) => {
|
|
@@ -552,16 +874,30 @@ function FlashTool({
|
|
|
552
874
|
const latestLogLine = _react2.default.useMemo(() => {
|
|
553
875
|
if (!log) return "";
|
|
554
876
|
const lines = log.split("\n").filter((line) => line.trim().length > 0);
|
|
555
|
-
|
|
877
|
+
const lastLine = lines[lines.length - 1] || "";
|
|
878
|
+
return lastLine.replace(/\s*\(\d+ ?%\)\s*$/, "");
|
|
556
879
|
}, [log]);
|
|
557
|
-
const
|
|
558
|
-
|
|
880
|
+
const activeFirmwareDescription = showFirmwarePicker ? {
|
|
881
|
+
...language === "de" ? DEFAULT_FIRMWARE_DESCRIPTIONS_DE[selectedType] : DEFAULT_FIRMWARE_DESCRIPTIONS[selectedType],
|
|
882
|
+
...firmwareDescriptions == null ? void 0 : firmwareDescriptions[selectedType]
|
|
883
|
+
} : null;
|
|
884
|
+
const handleFirmwareChange = (value) => {
|
|
559
885
|
setSelectedType(value);
|
|
560
886
|
onFirmwareTypeChange == null ? void 0 : onFirmwareTypeChange(value);
|
|
561
887
|
};
|
|
888
|
+
const firmwareOptions = FIRMWARE_TYPES.map((type) => ({
|
|
889
|
+
value: type,
|
|
890
|
+
label: merged[`firmware${type.charAt(0).toUpperCase()}${type.slice(1)}`],
|
|
891
|
+
icon: FIRMWARE_ICONS[type]
|
|
892
|
+
}));
|
|
562
893
|
const handleRetryFirmwareLoad = () => {
|
|
563
894
|
setBuiltinRetryToken((token) => token + 1);
|
|
564
895
|
};
|
|
896
|
+
const logRef = _react.useRef.call(void 0, null);
|
|
897
|
+
_react.useEffect.call(void 0, () => {
|
|
898
|
+
if (!logOpen || !logRef.current) return;
|
|
899
|
+
logRef.current.scrollTop = logRef.current.scrollHeight;
|
|
900
|
+
}, [log, logOpen]);
|
|
565
901
|
const prevConnected = _react.useRef.call(void 0, connected);
|
|
566
902
|
_react.useEffect.call(void 0, () => {
|
|
567
903
|
if (connected && !prevConnected.current) onConnected == null ? void 0 : onConnected(deviceLabel);
|
|
@@ -621,24 +957,20 @@ function FlashTool({
|
|
|
621
957
|
resetFlashState();
|
|
622
958
|
if (resolvedBinary) flash(resolvedBinary, flashOverrides);
|
|
623
959
|
};
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
className: "sbflash__label",
|
|
633
|
-
title: connected ? deviceLabel : void 0
|
|
634
|
-
},
|
|
635
|
-
connected ? merged.connected : merged.connect
|
|
636
|
-
)), /* @__PURE__ */ _react2.default.createElement("div", { className: "sbflash__field" }, /* @__PURE__ */ _react2.default.createElement("div", { className: "sbflash__field-head" }, /* @__PURE__ */ _react2.default.createElement("span", { className: "sbflash__field-label" }, merged.sketchLabel), /* @__PURE__ */ _react2.default.createElement("div", { className: "sbflash__icon-row" }, log && /* @__PURE__ */ _react2.default.createElement(
|
|
960
|
+
const flashComplete = status === "done";
|
|
961
|
+
const step1Status = flashComplete ? "done" : connected ? "done" : "active";
|
|
962
|
+
const step2Status = flashComplete ? "done" : !connected ? "pending" : bootloaderReady ? "done" : "active";
|
|
963
|
+
const step3Status = flashComplete ? "done" : !bootloaderReady ? "pending" : status === "error" ? "error" : "active";
|
|
964
|
+
const handleStartNew = () => {
|
|
965
|
+
resetFlashState();
|
|
966
|
+
};
|
|
967
|
+
return /* @__PURE__ */ _react2.default.createElement("div", { className: `sbflash ${className || ""}` }, /* @__PURE__ */ _react2.default.createElement("div", { className: "sbflash__field" }, /* @__PURE__ */ _react2.default.createElement("div", { className: "sbflash__field-head" }, /* @__PURE__ */ _react2.default.createElement("span", { className: "sbflash__field-label" }, merged.sketchLabel), /* @__PURE__ */ _react2.default.createElement("div", { className: "sbflash__icon-row" }, /* @__PURE__ */ _react2.default.createElement(
|
|
637
968
|
"button",
|
|
638
969
|
{
|
|
639
970
|
type: "button",
|
|
640
971
|
className: `sbflash__icon-button${logOpen ? " sbflash__icon-button--active" : ""}`,
|
|
641
|
-
onClick: () => setLogOpen((v) => !v),
|
|
972
|
+
onClick: () => !expand && setLogOpen((v) => !v),
|
|
973
|
+
disabled: expand,
|
|
642
974
|
"aria-pressed": logOpen,
|
|
643
975
|
"aria-label": logOpen ? merged.hideLog : merged.showLog,
|
|
644
976
|
title: logOpen ? merged.hideLog : merged.showLog
|
|
@@ -664,16 +996,16 @@ function FlashTool({
|
|
|
664
996
|
title: merged.help
|
|
665
997
|
},
|
|
666
998
|
/* @__PURE__ */ _react2.default.createElement(IconHelp, null)
|
|
667
|
-
))), showFirmwarePicker && /* @__PURE__ */ _react2.default.createElement(
|
|
668
|
-
|
|
999
|
+
))), showFirmwarePicker && /* @__PURE__ */ _react2.default.createElement(
|
|
1000
|
+
Dropdown,
|
|
669
1001
|
{
|
|
670
|
-
|
|
1002
|
+
options: firmwareOptions,
|
|
671
1003
|
value: selectedType,
|
|
672
1004
|
onChange: handleFirmwareChange,
|
|
673
|
-
disabled: firmwareLocked || status === "flashing"
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
)
|
|
1005
|
+
disabled: firmwareLocked || status === "flashing",
|
|
1006
|
+
"aria-label": merged.sketchLabel
|
|
1007
|
+
}
|
|
1008
|
+
), builtinError && /* @__PURE__ */ _react2.default.createElement("div", { className: "sbflash__field-error-row" }, /* @__PURE__ */ _react2.default.createElement("span", { className: "sbflash__field-error" }, builtinError), /* @__PURE__ */ _react2.default.createElement(
|
|
677
1009
|
"button",
|
|
678
1010
|
{
|
|
679
1011
|
type: "button",
|
|
@@ -681,7 +1013,15 @@ function FlashTool({
|
|
|
681
1013
|
onClick: handleRetryFirmwareLoad
|
|
682
1014
|
},
|
|
683
1015
|
merged.retry
|
|
684
|
-
))),
|
|
1016
|
+
)), (activeFirmwareDescription == null ? void 0 : activeFirmwareDescription.text) && /* @__PURE__ */ _react2.default.createElement("p", { className: "sbflash__field-description" }, activeFirmwareDescription.text, activeFirmwareDescription.linkUrl && /* @__PURE__ */ _react2.default.createElement(_react2.default.Fragment, null, " ", /* @__PURE__ */ _react2.default.createElement(
|
|
1017
|
+
"a",
|
|
1018
|
+
{
|
|
1019
|
+
href: activeFirmwareDescription.linkUrl,
|
|
1020
|
+
target: "_blank",
|
|
1021
|
+
rel: "noopener noreferrer"
|
|
1022
|
+
},
|
|
1023
|
+
activeFirmwareDescription.linkText || activeFirmwareDescription.linkUrl
|
|
1024
|
+
)))), helpOpen && _reactdom.createPortal.call(void 0,
|
|
685
1025
|
/* @__PURE__ */ _react2.default.createElement(
|
|
686
1026
|
"div",
|
|
687
1027
|
{
|
|
@@ -716,7 +1056,12 @@ function FlashTool({
|
|
|
716
1056
|
)
|
|
717
1057
|
),
|
|
718
1058
|
document.body
|
|
719
|
-
),
|
|
1059
|
+
), /* @__PURE__ */ _react2.default.createElement("ol", { className: "sbflash__stepper" }, /* @__PURE__ */ _react2.default.createElement("li", { className: `sbflash__step sbflash__step--${step1Status}` }, /* @__PURE__ */ _react2.default.createElement("span", { className: "sbflash__step-marker" }, /* @__PURE__ */ _react2.default.createElement("span", { className: "sbflash__step-index" }, step1Status === "done" ? /* @__PURE__ */ _react2.default.createElement(IconCheck2, null) : 1), /* @__PURE__ */ _react2.default.createElement(
|
|
1060
|
+
"span",
|
|
1061
|
+
{
|
|
1062
|
+
className: `sbflash__step-line${step1Status === "done" ? " sbflash__step-line--done" : ""}`
|
|
1063
|
+
}
|
|
1064
|
+
)), /* @__PURE__ */ _react2.default.createElement("div", { className: "sbflash__step-body" }, /* @__PURE__ */ _react2.default.createElement("span", { className: "sbflash__step-title" }, merged.step1Title), !connected && !flashComplete ? /* @__PURE__ */ _react2.default.createElement(_react2.default.Fragment, null, /* @__PURE__ */ _react2.default.createElement("span", { className: "sbflash__step-hint" }, merged.step1Hint), /* @__PURE__ */ _react2.default.createElement(
|
|
720
1065
|
"button",
|
|
721
1066
|
{
|
|
722
1067
|
type: "button",
|
|
@@ -725,7 +1070,12 @@ function FlashTool({
|
|
|
725
1070
|
disabled: busy === "connect"
|
|
726
1071
|
},
|
|
727
1072
|
busy === "connect" ? merged.connecting : merged.connect
|
|
728
|
-
), connected
|
|
1073
|
+
)) : /* @__PURE__ */ _react2.default.createElement("span", { className: "sbflash__step-detail", title: deviceLabel }, deviceLabel || merged.connected))), /* @__PURE__ */ _react2.default.createElement("li", { className: `sbflash__step sbflash__step--${step2Status}` }, /* @__PURE__ */ _react2.default.createElement("span", { className: "sbflash__step-marker" }, /* @__PURE__ */ _react2.default.createElement("span", { className: "sbflash__step-index" }, step2Status === "done" ? /* @__PURE__ */ _react2.default.createElement(IconCheck2, null) : 2), /* @__PURE__ */ _react2.default.createElement(
|
|
1074
|
+
"span",
|
|
1075
|
+
{
|
|
1076
|
+
className: `sbflash__step-line${step2Status === "done" ? " sbflash__step-line--done" : ""}`
|
|
1077
|
+
}
|
|
1078
|
+
)), /* @__PURE__ */ _react2.default.createElement("div", { className: "sbflash__step-body" }, /* @__PURE__ */ _react2.default.createElement("span", { className: "sbflash__step-title" }, merged.step2Title), step2Status === "active" && needsBootloaderPermission && /* @__PURE__ */ _react2.default.createElement(_react2.default.Fragment, null, /* @__PURE__ */ _react2.default.createElement("span", { className: "sbflash__step-hint" }, merged.step2HintPermission), /* @__PURE__ */ _react2.default.createElement(
|
|
729
1079
|
"button",
|
|
730
1080
|
{
|
|
731
1081
|
type: "button",
|
|
@@ -734,16 +1084,7 @@ function FlashTool({
|
|
|
734
1084
|
disabled: busy === "grant"
|
|
735
1085
|
},
|
|
736
1086
|
merged.grantPermission
|
|
737
|
-
),
|
|
738
|
-
"button",
|
|
739
|
-
{
|
|
740
|
-
type: "button",
|
|
741
|
-
className: "sbflash__button sbflash__button--secondary",
|
|
742
|
-
onClick: handlePrepare,
|
|
743
|
-
disabled: busy === "prepare" || status === "flashing"
|
|
744
|
-
},
|
|
745
|
-
busy === "prepare" ? merged.preparing : merged.prepare
|
|
746
|
-
), connected && bootloaderReady && status !== "flashing" && status !== "error" && /* @__PURE__ */ _react2.default.createElement(
|
|
1087
|
+
)), step2Status === "active" && !needsBootloaderPermission && /* @__PURE__ */ _react2.default.createElement(_react2.default.Fragment, null, /* @__PURE__ */ _react2.default.createElement("span", { className: "sbflash__step-hint" }, merged.step2Hint)), step2Status === "done" && /* @__PURE__ */ _react2.default.createElement("span", { className: "sbflash__step-detail" }, merged.step2Done), step2Status === "pending" && /* @__PURE__ */ _react2.default.createElement("span", { className: "sbflash__step-hint" }, merged.step2Hint))), /* @__PURE__ */ _react2.default.createElement("li", { className: `sbflash__step sbflash__step--${step3Status}` }, /* @__PURE__ */ _react2.default.createElement("span", { className: "sbflash__step-marker" }, /* @__PURE__ */ _react2.default.createElement("span", { className: "sbflash__step-index" }, step3Status === "done" ? /* @__PURE__ */ _react2.default.createElement(IconCheck2, null) : 3)), /* @__PURE__ */ _react2.default.createElement("div", { className: "sbflash__step-body" }, /* @__PURE__ */ _react2.default.createElement("span", { className: "sbflash__step-title" }, merged.step3Title), step3Status === "pending" && /* @__PURE__ */ _react2.default.createElement("span", { className: "sbflash__step-hint" }, merged.step3Hint), step3Status === "active" && status !== "flashing" && /* @__PURE__ */ _react2.default.createElement(
|
|
747
1088
|
"button",
|
|
748
1089
|
{
|
|
749
1090
|
type: "button",
|
|
@@ -758,7 +1099,15 @@ function FlashTool({
|
|
|
758
1099
|
className: "sbflash__progress-fill",
|
|
759
1100
|
style: { width: `${Math.min(100, progress)}%` }
|
|
760
1101
|
}
|
|
761
|
-
)), /* @__PURE__ */ _react2.default.createElement("span", { className: "sbflash__progress-value" }, progress, "%")), latestLogLine && /* @__PURE__ */ _react2.default.createElement("span", { className: "sbflash__progress-detail" }, latestLogLine)) : /* @__PURE__ */ _react2.default.createElement("div", { className: "sbflash__task" }, /* @__PURE__ */ _react2.default.createElement("span", { className: "sbflash__task-spinner" }), /* @__PURE__ */ _react2.default.createElement("span", { className: "sbflash__task-label" }, latestLogLine || merged.flashing))), status === "done" && /* @__PURE__ */ _react2.default.createElement("div", { className: "
|
|
1102
|
+
)), /* @__PURE__ */ _react2.default.createElement("span", { className: "sbflash__progress-value" }, progress, "%")), latestLogLine && /* @__PURE__ */ _react2.default.createElement("span", { className: "sbflash__progress-detail" }, latestLogLine)) : /* @__PURE__ */ _react2.default.createElement("div", { className: "sbflash__task" }, /* @__PURE__ */ _react2.default.createElement("span", { className: "sbflash__task-spinner" }), /* @__PURE__ */ _react2.default.createElement("span", { className: "sbflash__task-label" }, latestLogLine || merged.flashing))), status === "done" && /* @__PURE__ */ _react2.default.createElement("div", { className: "sbflash__done-banner", role: "status" }, /* @__PURE__ */ _react2.default.createElement("span", { className: "sbflash__done-icon" }, /* @__PURE__ */ _react2.default.createElement(IconCheck2, null)), /* @__PURE__ */ _react2.default.createElement("span", { className: "sbflash__done-text" }, merged.done), /* @__PURE__ */ _react2.default.createElement(
|
|
1103
|
+
"button",
|
|
1104
|
+
{
|
|
1105
|
+
type: "button",
|
|
1106
|
+
className: "sbflash__button sbflash__button--secondary",
|
|
1107
|
+
onClick: handleStartNew
|
|
1108
|
+
},
|
|
1109
|
+
merged.newUpload
|
|
1110
|
+
)), status === "error" && /* @__PURE__ */ _react2.default.createElement("div", { className: "sbflash__status sbflash__status--error" }, merged.error, /* @__PURE__ */ _react2.default.createElement(
|
|
762
1111
|
"button",
|
|
763
1112
|
{
|
|
764
1113
|
type: "button",
|
|
@@ -766,7 +1115,7 @@ function FlashTool({
|
|
|
766
1115
|
onClick: handleRetry
|
|
767
1116
|
},
|
|
768
1117
|
merged.retry
|
|
769
|
-
)),
|
|
1118
|
+
))))), logOpen && /* @__PURE__ */ _react2.default.createElement("pre", { className: "sbflash__log", ref: logRef }, log || merged.logPlaceholder));
|
|
770
1119
|
}
|
|
771
1120
|
function IconTerminal() {
|
|
772
1121
|
return /* @__PURE__ */ _react2.default.createElement(
|
|
@@ -787,6 +1136,23 @@ function IconTerminal() {
|
|
|
787
1136
|
/* @__PURE__ */ _react2.default.createElement("path", { d: "M8.5 11h3" })
|
|
788
1137
|
);
|
|
789
1138
|
}
|
|
1139
|
+
function IconCheck2() {
|
|
1140
|
+
return /* @__PURE__ */ _react2.default.createElement(
|
|
1141
|
+
"svg",
|
|
1142
|
+
{
|
|
1143
|
+
viewBox: "0 0 16 16",
|
|
1144
|
+
width: "11",
|
|
1145
|
+
height: "11",
|
|
1146
|
+
fill: "none",
|
|
1147
|
+
stroke: "currentColor",
|
|
1148
|
+
strokeWidth: "2",
|
|
1149
|
+
strokeLinecap: "round",
|
|
1150
|
+
strokeLinejoin: "round",
|
|
1151
|
+
"aria-hidden": "true"
|
|
1152
|
+
},
|
|
1153
|
+
/* @__PURE__ */ _react2.default.createElement("path", { d: "M3 8.5 6.5 12 13 4.5" })
|
|
1154
|
+
);
|
|
1155
|
+
}
|
|
790
1156
|
function IconDisconnect() {
|
|
791
1157
|
return /* @__PURE__ */ _react2.default.createElement(
|
|
792
1158
|
"svg",
|
|
@@ -824,6 +1190,85 @@ function IconHelp() {
|
|
|
824
1190
|
/* @__PURE__ */ _react2.default.createElement("circle", { cx: "8", cy: "11.5", r: "0.9", fill: "currentColor", stroke: "none" })
|
|
825
1191
|
);
|
|
826
1192
|
}
|
|
1193
|
+
function IconChip() {
|
|
1194
|
+
return /* @__PURE__ */ _react2.default.createElement(
|
|
1195
|
+
"svg",
|
|
1196
|
+
{
|
|
1197
|
+
viewBox: "0 0 16 16",
|
|
1198
|
+
width: "14",
|
|
1199
|
+
height: "14",
|
|
1200
|
+
fill: "none",
|
|
1201
|
+
stroke: "currentColor",
|
|
1202
|
+
strokeWidth: "1.4",
|
|
1203
|
+
strokeLinecap: "round",
|
|
1204
|
+
strokeLinejoin: "round",
|
|
1205
|
+
"aria-hidden": "true"
|
|
1206
|
+
},
|
|
1207
|
+
/* @__PURE__ */ _react2.default.createElement("rect", { x: "4", y: "4", width: "8", height: "8", rx: "1.2" }),
|
|
1208
|
+
/* @__PURE__ */ _react2.default.createElement("path", { d: "M6 1.5v2M10 1.5v2M6 12.5v2M10 12.5v2M1.5 6v-.01M1.5 10v-.01M14.5 6v-.01M14.5 10v-.01M1.5 6h2M1.5 10h2M12.5 6h2M12.5 10h2" })
|
|
1209
|
+
);
|
|
1210
|
+
}
|
|
1211
|
+
function IconCloud() {
|
|
1212
|
+
return /* @__PURE__ */ _react2.default.createElement(
|
|
1213
|
+
"svg",
|
|
1214
|
+
{
|
|
1215
|
+
viewBox: "0 0 16 16",
|
|
1216
|
+
width: "14",
|
|
1217
|
+
height: "14",
|
|
1218
|
+
fill: "none",
|
|
1219
|
+
stroke: "currentColor",
|
|
1220
|
+
strokeWidth: "1.4",
|
|
1221
|
+
strokeLinecap: "round",
|
|
1222
|
+
strokeLinejoin: "round",
|
|
1223
|
+
"aria-hidden": "true"
|
|
1224
|
+
},
|
|
1225
|
+
/* @__PURE__ */ _react2.default.createElement("path", { d: "M4.5 12.5A3 3 0 0 1 4 6.53 3.5 3.5 0 0 1 11 5.5a2.75 2.75 0 0 1 .5 5.46" }),
|
|
1226
|
+
/* @__PURE__ */ _react2.default.createElement("path", { d: "M6.5 12.5h5" }),
|
|
1227
|
+
/* @__PURE__ */ _react2.default.createElement("path", { d: "M8 9.5v5M6.25 12.25 8 14.5l1.75-2.25" })
|
|
1228
|
+
);
|
|
1229
|
+
}
|
|
1230
|
+
function IconBolt() {
|
|
1231
|
+
return /* @__PURE__ */ _react2.default.createElement(
|
|
1232
|
+
"svg",
|
|
1233
|
+
{
|
|
1234
|
+
viewBox: "0 0 16 16",
|
|
1235
|
+
width: "14",
|
|
1236
|
+
height: "14",
|
|
1237
|
+
fill: "none",
|
|
1238
|
+
stroke: "currentColor",
|
|
1239
|
+
strokeWidth: "1.4",
|
|
1240
|
+
strokeLinecap: "round",
|
|
1241
|
+
strokeLinejoin: "round",
|
|
1242
|
+
"aria-hidden": "true"
|
|
1243
|
+
},
|
|
1244
|
+
/* @__PURE__ */ _react2.default.createElement("path", { d: "M8.5 1.5 3 9h4l-1 5.5L13 7H9l-0.5-5.5Z" })
|
|
1245
|
+
);
|
|
1246
|
+
}
|
|
1247
|
+
function IconLayers() {
|
|
1248
|
+
return /* @__PURE__ */ _react2.default.createElement(
|
|
1249
|
+
"svg",
|
|
1250
|
+
{
|
|
1251
|
+
viewBox: "0 0 16 16",
|
|
1252
|
+
width: "14",
|
|
1253
|
+
height: "14",
|
|
1254
|
+
fill: "none",
|
|
1255
|
+
stroke: "currentColor",
|
|
1256
|
+
strokeWidth: "1.4",
|
|
1257
|
+
strokeLinecap: "round",
|
|
1258
|
+
strokeLinejoin: "round",
|
|
1259
|
+
"aria-hidden": "true"
|
|
1260
|
+
},
|
|
1261
|
+
/* @__PURE__ */ _react2.default.createElement("path", { d: "M8 1.75 14 5 8 8.25 2 5Z" }),
|
|
1262
|
+
/* @__PURE__ */ _react2.default.createElement("path", { d: "M2 8 8 11.25 14 8" }),
|
|
1263
|
+
/* @__PURE__ */ _react2.default.createElement("path", { d: "M2 11 8 14.25 14 11" })
|
|
1264
|
+
);
|
|
1265
|
+
}
|
|
1266
|
+
var FIRMWARE_ICONS = {
|
|
1267
|
+
circuitpy: /* @__PURE__ */ _react2.default.createElement(IconChip, null),
|
|
1268
|
+
ota: /* @__PURE__ */ _react2.default.createElement(IconCloud, null),
|
|
1269
|
+
basic: /* @__PURE__ */ _react2.default.createElement(IconBolt, null),
|
|
1270
|
+
standard: /* @__PURE__ */ _react2.default.createElement(IconLayers, null)
|
|
1271
|
+
};
|
|
827
1272
|
FlashTool.propTypes = {
|
|
828
1273
|
/** Already-compiled firmware image to flash. Ignored if `firmwares` is set. */
|
|
829
1274
|
binary: _proptypes2.default.instanceOf(Uint8Array),
|
|
@@ -834,19 +1279,36 @@ FlashTool.propTypes = {
|
|
|
834
1279
|
basic: _proptypes2.default.instanceOf(Uint8Array),
|
|
835
1280
|
standard: _proptypes2.default.instanceOf(Uint8Array)
|
|
836
1281
|
}),
|
|
1282
|
+
/** Same as `firmwareType`, but also accepts friendlier aliases (e.g. "circuitpython" for "circuitpy"). */
|
|
1283
|
+
firmware: _proptypes2.default.oneOf([
|
|
1284
|
+
...FIRMWARE_TYPES,
|
|
1285
|
+
...Object.keys(FIRMWARE_ALIASES)
|
|
1286
|
+
]),
|
|
837
1287
|
/** Locks the sketch dropdown to this value and disables it. One of "circuitpy" | "ota" | "basic" | "standard". */
|
|
838
1288
|
firmwareType: _proptypes2.default.oneOf(FIRMWARE_TYPES),
|
|
839
1289
|
/** Initial dropdown selection when `firmwareType` isn't set (dropdown stays interactive). */
|
|
840
1290
|
defaultFirmwareType: _proptypes2.default.oneOf(FIRMWARE_TYPES),
|
|
841
1291
|
/** Per-sketch overrides for the esptool flash step, keyed by firmware type. Merges over (and can override) the built-in CircuitPython defaults. */
|
|
842
1292
|
firmwareFlashOptions: _proptypes2.default.objectOf(_proptypes2.default.object),
|
|
1293
|
+
/** Per-sketch description shown under the sketch picker, keyed by firmware type: { text, linkText, linkUrl }. Merges over (and can override) the built-in defaults. */
|
|
1294
|
+
firmwareDescriptions: _proptypes2.default.objectOf(
|
|
1295
|
+
_proptypes2.default.shape({
|
|
1296
|
+
text: _proptypes2.default.string,
|
|
1297
|
+
linkText: _proptypes2.default.string,
|
|
1298
|
+
linkUrl: _proptypes2.default.string
|
|
1299
|
+
})
|
|
1300
|
+
),
|
|
843
1301
|
/** USB vendor id used to filter the device picker. Defaults to senseBox (0x303a). */
|
|
844
1302
|
usbVendorId: _proptypes2.default.number,
|
|
845
1303
|
/** Overrides for the esptool flash step (address, baudrate, flashMode, flashFreq, flashSize, eraseAll, usingUsbOtg). */
|
|
846
1304
|
flashOptions: _proptypes2.default.object,
|
|
847
1305
|
/** Start flashing automatically once the selected firmware and a connected device are both ready. */
|
|
848
1306
|
autoFlash: _proptypes2.default.bool,
|
|
849
|
-
/**
|
|
1307
|
+
/** Keep the log/terminal view expanded by default and disable the button to collapse it. */
|
|
1308
|
+
expand: _proptypes2.default.bool,
|
|
1309
|
+
/** UI language for the built-in strings. "de" uses the built-in German translation. */
|
|
1310
|
+
language: _proptypes2.default.oneOf(["en", "de"]),
|
|
1311
|
+
/** Overrides for the built-in UI strings (applied on top of `language`). */
|
|
850
1312
|
strings: _proptypes2.default.object,
|
|
851
1313
|
className: _proptypes2.default.string,
|
|
852
1314
|
onConnected: _proptypes2.default.func,
|