@rslsp1/fa-app-tools 1.2.1 → 1.2.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.d.mts CHANGED
@@ -445,6 +445,6 @@ declare function buildLoopInstruction(rounds: Array<{
445
445
  declare function autoLabel(index: number): string;
446
446
  declare function buildReferenceImageMediaIds(images: SelectedLabImage[]): string[];
447
447
 
448
- declare const LIB_VERSION = "1.2.1";
448
+ declare const LIB_VERSION = "1.2.2";
449
449
 
450
450
  export { AvatarArchitectApp, type AvatarArchitectAppProps, CollapsibleCard, CompactDropdown, type ExtractedCharacter, FaToolsBadge, type FlowSdk, GLOBAL_STYLES, type Generation, HistoryPanel, InspectPanel, LIB_VERSION, LabBlend, LabCompare, type LabFrame, LabImagePicker, type LabItem, LabLoop, LabRemix, type LabServices, LabsTab, ListView, type MediaItem, MediaLibrary, PillButton, type ProjectMeta, type ProjectSettings, ProjectSyncTab, PromptTab, SectionLabel, type SelectedLabImage, type SelectedTag, SetupPanel, type SyncDiff, TagManagerPanel, type TagOption, type WorkspaceTags, autoLabel, buildBlendInstruction, buildCompareInstruction, buildFallbackPrompt, buildGenerationPrompt, buildImageGenerationOptions, buildLoopInstruction, buildPromptTabPayload, buildReferenceImageMediaIds, buildRemixInstruction, buildScanInstruction, cleanAiResponse, createFlowServices, exportProjectToZip, formatTreeToMarkdown, frameToGeneration, getFormattedTimestamp, groupGenerationsToLabItems, importProjectFromZip, injectXMPMetadata, interpretSdkError, parsePromptFile, parsePromptResponse, useKeyboardNavigation, useOnClickOutside };
package/dist/index.d.ts CHANGED
@@ -445,6 +445,6 @@ declare function buildLoopInstruction(rounds: Array<{
445
445
  declare function autoLabel(index: number): string;
446
446
  declare function buildReferenceImageMediaIds(images: SelectedLabImage[]): string[];
447
447
 
448
- declare const LIB_VERSION = "1.2.1";
448
+ declare const LIB_VERSION = "1.2.2";
449
449
 
450
450
  export { AvatarArchitectApp, type AvatarArchitectAppProps, CollapsibleCard, CompactDropdown, type ExtractedCharacter, FaToolsBadge, type FlowSdk, GLOBAL_STYLES, type Generation, HistoryPanel, InspectPanel, LIB_VERSION, LabBlend, LabCompare, type LabFrame, LabImagePicker, type LabItem, LabLoop, LabRemix, type LabServices, LabsTab, ListView, type MediaItem, MediaLibrary, PillButton, type ProjectMeta, type ProjectSettings, ProjectSyncTab, PromptTab, SectionLabel, type SelectedLabImage, type SelectedTag, SetupPanel, type SyncDiff, TagManagerPanel, type TagOption, type WorkspaceTags, autoLabel, buildBlendInstruction, buildCompareInstruction, buildFallbackPrompt, buildGenerationPrompt, buildImageGenerationOptions, buildLoopInstruction, buildPromptTabPayload, buildReferenceImageMediaIds, buildRemixInstruction, buildScanInstruction, cleanAiResponse, createFlowServices, exportProjectToZip, formatTreeToMarkdown, frameToGeneration, getFormattedTimestamp, groupGenerationsToLabItems, importProjectFromZip, injectXMPMetadata, interpretSdkError, parsePromptFile, parsePromptResponse, useKeyboardNavigation, useOnClickOutside };
package/dist/index.js CHANGED
@@ -740,31 +740,32 @@ var import_react8 = require("motion/react");
740
740
  var import_jsx_runtime7 = require("react/jsx-runtime");
741
741
  var SetupPanel = ({ onWorkspaceImport, buildInfo }) => {
742
742
  const workspaceInputRef = (0, import_react7.useRef)(null);
743
- const [urlInput, setUrlInput] = (0, import_react7.useState)("");
744
- const [urlStatus, setUrlStatus] = (0, import_react7.useState)("idle");
745
- const [urlThumb, setUrlThumb] = (0, import_react7.useState)(null);
746
- const [urlError, setUrlError] = (0, import_react7.useState)(null);
747
- const handleUrlTest = async () => {
748
- if (!urlInput.trim()) return;
749
- setUrlStatus("loading");
750
- setUrlThumb(null);
751
- setUrlError(null);
743
+ const blobTestInputRef = (0, import_react7.useRef)(null);
744
+ const [blobStatus, setBlobStatus] = (0, import_react7.useState)("idle");
745
+ const [blobThumb, setBlobThumb] = (0, import_react7.useState)(null);
746
+ const [blobError, setBlobError] = (0, import_react7.useState)(null);
747
+ const handleBlobTest = async (file) => {
748
+ setBlobStatus("loading");
749
+ setBlobThumb(null);
750
+ setBlobError(null);
751
+ const blobUrl = URL.createObjectURL(file);
752
752
  try {
753
- const res = await fetch(urlInput.trim());
753
+ const res = await fetch(blobUrl);
754
754
  if (!res.ok) throw new Error(`HTTP ${res.status} ${res.statusText}`);
755
755
  const blob = await res.blob();
756
- const mimeType = blob.type || "image/jpeg";
757
756
  const dataUrl = await new Promise((resolve, reject) => {
758
757
  const reader = new FileReader();
759
758
  reader.onload = () => resolve(reader.result);
760
759
  reader.onerror = () => reject(new Error("FileReader failed"));
761
760
  reader.readAsDataURL(blob);
762
761
  });
763
- setUrlThumb(dataUrl);
764
- setUrlStatus("ok");
762
+ setBlobThumb(dataUrl);
763
+ setBlobStatus("ok");
765
764
  } catch (e) {
766
- setUrlError(e.message || String(e));
767
- setUrlStatus("error");
765
+ setBlobError(e.message || String(e));
766
+ setBlobStatus("error");
767
+ } finally {
768
+ URL.revokeObjectURL(blobUrl);
768
769
  }
769
770
  };
770
771
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react8.motion.div, { initial: { opacity: 0 }, animate: { opacity: 1 }, className: "absolute inset-0 p-6 flex flex-col gap-10 overflow-y-auto", children: [
@@ -782,40 +783,42 @@ var SetupPanel = ({ onWorkspaceImport, buildInfo }) => {
782
783
  ] }),
783
784
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-col gap-3", children: [
784
785
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-col gap-1", children: [
785
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SectionLabel, { children: "URL-Fetch Test" }),
786
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "text-[9px] text-white/30 px-2 italic", children: "Pr\xFCft ob externe URLs als Bild geladen werden k\xF6nnen." })
786
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SectionLabel, { children: "blob: URL Test" }),
787
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "text-[9px] text-white/30 px-2 italic", children: "Testet ob fetch() auf blob: URLs funktioniert \u2014 lokale Datei \u2192 createObjectURL \u2192 fetch \u2192 base64." })
787
788
  ] }),
788
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex gap-2", children: [
789
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
790
- "input",
791
- {
792
- value: urlInput,
793
- onChange: (e) => setUrlInput(e.target.value),
794
- onKeyDown: (e) => e.key === "Enter" && handleUrlTest(),
795
- placeholder: "https://example.com/image.jpg",
796
- className: "flex-1 bg-white/5 border border-white/10 rounded-xl px-3 py-2 text-[11px] text-white/80 outline-none focus:border-white/20 placeholder:text-white/20"
797
- }
798
- ),
799
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
800
- "button",
801
- {
802
- onClick: handleUrlTest,
803
- disabled: urlStatus === "loading" || !urlInput.trim(),
804
- className: "px-3 py-2 bg-white/10 hover:bg-white/15 border border-white/10 rounded-xl text-[11px] font-bold text-white/60 transition disabled:opacity-40 shrink-0",
805
- children: urlStatus === "loading" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "material-symbols-outlined text-[16px] animate-spin", children: "sync" }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "material-symbols-outlined text-[16px]", children: "download" })
789
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
790
+ PillButton,
791
+ {
792
+ variant: "outline",
793
+ icon: blobStatus === "loading" ? "sync" : "image_search",
794
+ onClick: () => blobTestInputRef.current?.click(),
795
+ children: "Bild w\xE4hlen & testen"
796
+ }
797
+ ),
798
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
799
+ "input",
800
+ {
801
+ ref: blobTestInputRef,
802
+ type: "file",
803
+ accept: "image/*",
804
+ className: "hidden",
805
+ onChange: (e) => {
806
+ const f = e.target.files?.[0];
807
+ if (f) handleBlobTest(f);
808
+ e.target.value = "";
806
809
  }
807
- )
808
- ] }),
809
- urlStatus === "ok" && urlThumb && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-col gap-2", children: [
810
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("img", { src: urlThumb, alt: "URL Test", className: "w-full max-h-48 object-contain rounded-xl border border-white/10 bg-black/40" }),
810
+ }
811
+ ),
812
+ blobStatus === "ok" && blobThumb && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-col gap-2", children: [
813
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("img", { src: blobThumb, alt: "blob test", className: "w-full max-h-48 object-contain rounded-xl border border-white/10 bg-black/40" }),
811
814
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("p", { className: "text-[10px] text-green-400 font-mono flex items-center gap-1", children: [
812
815
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "material-symbols-outlined text-[14px]", children: "check_circle" }),
813
- "Fetch erfolgreich"
816
+ "blob: fetch \u2713 \u2014 base64 erfolgreich"
814
817
  ] })
815
818
  ] }),
816
- urlStatus === "error" && urlError && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("p", { className: "text-[10px] text-red-400 font-mono flex items-start gap-1", children: [
819
+ blobStatus === "error" && blobError && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("p", { className: "text-[10px] text-red-400 font-mono flex items-start gap-1", children: [
817
820
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "material-symbols-outlined text-[14px] shrink-0", children: "error" }),
818
- urlError
821
+ blobError
819
822
  ] })
820
823
  ] }),
821
824
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "mt-auto p-4 bg-white/5 rounded-2xl border border-white/5 flex flex-col gap-2 opacity-50", children: [
@@ -4177,7 +4180,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
4177
4180
  }
4178
4181
 
4179
4182
  // src/index.ts
4180
- var LIB_VERSION = "1.2.1";
4183
+ var LIB_VERSION = "1.2.2";
4181
4184
  // Annotate the CommonJS export names for ESM import in node:
4182
4185
  0 && (module.exports = {
4183
4186
  AvatarArchitectApp,
package/dist/index.mjs CHANGED
@@ -658,31 +658,32 @@ import { motion as motion3 } from "motion/react";
658
658
  import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
659
659
  var SetupPanel = ({ onWorkspaceImport, buildInfo }) => {
660
660
  const workspaceInputRef = useRef2(null);
661
- const [urlInput, setUrlInput] = useState2("");
662
- const [urlStatus, setUrlStatus] = useState2("idle");
663
- const [urlThumb, setUrlThumb] = useState2(null);
664
- const [urlError, setUrlError] = useState2(null);
665
- const handleUrlTest = async () => {
666
- if (!urlInput.trim()) return;
667
- setUrlStatus("loading");
668
- setUrlThumb(null);
669
- setUrlError(null);
661
+ const blobTestInputRef = useRef2(null);
662
+ const [blobStatus, setBlobStatus] = useState2("idle");
663
+ const [blobThumb, setBlobThumb] = useState2(null);
664
+ const [blobError, setBlobError] = useState2(null);
665
+ const handleBlobTest = async (file) => {
666
+ setBlobStatus("loading");
667
+ setBlobThumb(null);
668
+ setBlobError(null);
669
+ const blobUrl = URL.createObjectURL(file);
670
670
  try {
671
- const res = await fetch(urlInput.trim());
671
+ const res = await fetch(blobUrl);
672
672
  if (!res.ok) throw new Error(`HTTP ${res.status} ${res.statusText}`);
673
673
  const blob = await res.blob();
674
- const mimeType = blob.type || "image/jpeg";
675
674
  const dataUrl = await new Promise((resolve, reject) => {
676
675
  const reader = new FileReader();
677
676
  reader.onload = () => resolve(reader.result);
678
677
  reader.onerror = () => reject(new Error("FileReader failed"));
679
678
  reader.readAsDataURL(blob);
680
679
  });
681
- setUrlThumb(dataUrl);
682
- setUrlStatus("ok");
680
+ setBlobThumb(dataUrl);
681
+ setBlobStatus("ok");
683
682
  } catch (e) {
684
- setUrlError(e.message || String(e));
685
- setUrlStatus("error");
683
+ setBlobError(e.message || String(e));
684
+ setBlobStatus("error");
685
+ } finally {
686
+ URL.revokeObjectURL(blobUrl);
686
687
  }
687
688
  };
688
689
  return /* @__PURE__ */ jsxs5(motion3.div, { initial: { opacity: 0 }, animate: { opacity: 1 }, className: "absolute inset-0 p-6 flex flex-col gap-10 overflow-y-auto", children: [
@@ -700,40 +701,42 @@ var SetupPanel = ({ onWorkspaceImport, buildInfo }) => {
700
701
  ] }),
701
702
  /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-3", children: [
702
703
  /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-1", children: [
703
- /* @__PURE__ */ jsx7(SectionLabel, { children: "URL-Fetch Test" }),
704
- /* @__PURE__ */ jsx7("p", { className: "text-[9px] text-white/30 px-2 italic", children: "Pr\xFCft ob externe URLs als Bild geladen werden k\xF6nnen." })
704
+ /* @__PURE__ */ jsx7(SectionLabel, { children: "blob: URL Test" }),
705
+ /* @__PURE__ */ jsx7("p", { className: "text-[9px] text-white/30 px-2 italic", children: "Testet ob fetch() auf blob: URLs funktioniert \u2014 lokale Datei \u2192 createObjectURL \u2192 fetch \u2192 base64." })
705
706
  ] }),
706
- /* @__PURE__ */ jsxs5("div", { className: "flex gap-2", children: [
707
- /* @__PURE__ */ jsx7(
708
- "input",
709
- {
710
- value: urlInput,
711
- onChange: (e) => setUrlInput(e.target.value),
712
- onKeyDown: (e) => e.key === "Enter" && handleUrlTest(),
713
- placeholder: "https://example.com/image.jpg",
714
- className: "flex-1 bg-white/5 border border-white/10 rounded-xl px-3 py-2 text-[11px] text-white/80 outline-none focus:border-white/20 placeholder:text-white/20"
715
- }
716
- ),
717
- /* @__PURE__ */ jsx7(
718
- "button",
719
- {
720
- onClick: handleUrlTest,
721
- disabled: urlStatus === "loading" || !urlInput.trim(),
722
- className: "px-3 py-2 bg-white/10 hover:bg-white/15 border border-white/10 rounded-xl text-[11px] font-bold text-white/60 transition disabled:opacity-40 shrink-0",
723
- children: urlStatus === "loading" ? /* @__PURE__ */ jsx7("span", { className: "material-symbols-outlined text-[16px] animate-spin", children: "sync" }) : /* @__PURE__ */ jsx7("span", { className: "material-symbols-outlined text-[16px]", children: "download" })
707
+ /* @__PURE__ */ jsx7(
708
+ PillButton,
709
+ {
710
+ variant: "outline",
711
+ icon: blobStatus === "loading" ? "sync" : "image_search",
712
+ onClick: () => blobTestInputRef.current?.click(),
713
+ children: "Bild w\xE4hlen & testen"
714
+ }
715
+ ),
716
+ /* @__PURE__ */ jsx7(
717
+ "input",
718
+ {
719
+ ref: blobTestInputRef,
720
+ type: "file",
721
+ accept: "image/*",
722
+ className: "hidden",
723
+ onChange: (e) => {
724
+ const f = e.target.files?.[0];
725
+ if (f) handleBlobTest(f);
726
+ e.target.value = "";
724
727
  }
725
- )
726
- ] }),
727
- urlStatus === "ok" && urlThumb && /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-2", children: [
728
- /* @__PURE__ */ jsx7("img", { src: urlThumb, alt: "URL Test", className: "w-full max-h-48 object-contain rounded-xl border border-white/10 bg-black/40" }),
728
+ }
729
+ ),
730
+ blobStatus === "ok" && blobThumb && /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-2", children: [
731
+ /* @__PURE__ */ jsx7("img", { src: blobThumb, alt: "blob test", className: "w-full max-h-48 object-contain rounded-xl border border-white/10 bg-black/40" }),
729
732
  /* @__PURE__ */ jsxs5("p", { className: "text-[10px] text-green-400 font-mono flex items-center gap-1", children: [
730
733
  /* @__PURE__ */ jsx7("span", { className: "material-symbols-outlined text-[14px]", children: "check_circle" }),
731
- "Fetch erfolgreich"
734
+ "blob: fetch \u2713 \u2014 base64 erfolgreich"
732
735
  ] })
733
736
  ] }),
734
- urlStatus === "error" && urlError && /* @__PURE__ */ jsxs5("p", { className: "text-[10px] text-red-400 font-mono flex items-start gap-1", children: [
737
+ blobStatus === "error" && blobError && /* @__PURE__ */ jsxs5("p", { className: "text-[10px] text-red-400 font-mono flex items-start gap-1", children: [
735
738
  /* @__PURE__ */ jsx7("span", { className: "material-symbols-outlined text-[14px] shrink-0", children: "error" }),
736
- urlError
739
+ blobError
737
740
  ] })
738
741
  ] }),
739
742
  /* @__PURE__ */ jsxs5("div", { className: "mt-auto p-4 bg-white/5 rounded-2xl border border-white/5 flex flex-col gap-2 opacity-50", children: [
@@ -4095,7 +4098,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
4095
4098
  }
4096
4099
 
4097
4100
  // src/index.ts
4098
- var LIB_VERSION = "1.2.1";
4101
+ var LIB_VERSION = "1.2.2";
4099
4102
  export {
4100
4103
  AvatarArchitectApp,
4101
4104
  CollapsibleCard,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rslsp1/fa-app-tools",
3
- "version": "1.2.1",
3
+ "version": "1.2.2",
4
4
  "description": "Shared tools and hooks for Fine Art flow apps",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",