ssovee-os-web-ui 0.1.99 → 0.1.101

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/README.md CHANGED
@@ -84,6 +84,47 @@ Use `theme="vs-dark"` for a dark editor. The component also accepts Monaco `lang
84
84
 
85
85
  The component supports `toolbar`, `plugins`, `fullWidth`, `error`, and `disabled` props for common form usage.
86
86
 
87
+ ### RichEditor
88
+
89
+ `RichEditor` is a controlled rich-text editor that returns the edited content as HTML. Set `isDarkTheme` when the surrounding app uses the dark theme:
90
+
91
+ ```tsx
92
+ import { useState } from "react";
93
+ import { RichEditor } from "ssovee-os-web-ui";
94
+
95
+ export function NoteEditor() {
96
+ const [content, setContent] = useState("<p>Write a note...</p>");
97
+
98
+ return (
99
+ <RichEditor
100
+ content={content}
101
+ onChange={setContent}
102
+ isDarkTheme
103
+ />
104
+ );
105
+ }
106
+ ```
107
+
108
+ ### PreviewComponent
109
+
110
+ `PreviewComponent` previews a file from base64 data supplied by the host application. Pass either raw base64 or a complete data URL along with the original file name. Image files, PDFs, text files, and JSON are supported.
111
+
112
+ ```tsx
113
+ import { PreviewComponent } from "ssovee-os-web-ui";
114
+
115
+ export function FilePreview({ fileName, base64 }: { fileName: string; base64: string }) {
116
+ return (
117
+ <PreviewComponent
118
+ fileName={fileName}
119
+ base64={base64}
120
+ className="h-96"
121
+ />
122
+ );
123
+ }
124
+ ```
125
+
126
+ Supported image extensions include `avif`, `bmp`, `gif`, `jpg`, `jpeg`, `png`, `svg`, and `webp`. Supported text extensions include `css`, `csv`, `html`, `js`, `jsx`, `md`, `ts`, `tsx`, `txt`, `xml`, `yaml`, and `yml`.
127
+
87
128
  ## Window components
88
129
 
89
130
  ### Simple window
@@ -207,6 +248,8 @@ The package exports these components and types for external use:
207
248
  - `Input`
208
249
  - `TextArea`
209
250
  - `CodeEditor`
251
+ - `RichEditor`
252
+ - `PreviewComponent` (also available as `FilePreview`)
210
253
  - `Select`
211
254
  - `SelectOption`
212
255
  - `Checkbox`
package/dist/index.cjs CHANGED
@@ -354,7 +354,7 @@ var RichEditor = ({ content, onChange, isDarkTheme }) => {
354
354
  }
355
355
  }, [content, editor]);
356
356
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
357
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 flex flex-wrap items-center gap-1 border-b border-primary pb-2 text-neutral-500 [&_button]:text-neutral-500", children: [
357
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 flex flex-wrap items-center gap-1 border-b border-primary pb-2", children: [
358
358
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-0.5", children: [
359
359
  /* @__PURE__ */ jsxRuntime.jsx(Button_default, { type: "button", variant: editor?.isActive("bold") ? "primary" : "ghost", size: "sm", onClick: () => editor?.chain().focus().toggleBold().run(), "aria-label": "Bold text", title: "Bold", children: /* @__PURE__ */ jsxRuntime.jsx("strong", { children: "B" }) }),
360
360
  /* @__PURE__ */ jsxRuntime.jsx(Button_default, { type: "button", variant: editor?.isActive("italic") ? "primary" : "ghost", size: "sm", onClick: () => editor?.chain().focus().toggleItalic().run(), "aria-label": "Italic text", title: "Italic", children: /* @__PURE__ */ jsxRuntime.jsx("em", { children: "I" }) }),
@@ -385,7 +385,7 @@ var RichEditor = ({ content, onChange, isDarkTheme }) => {
385
385
  react$1.EditorContent,
386
386
  {
387
387
  editor,
388
- className: `mt-4 min-h-52 rounded-md border border-primary p-3 text-sm leading-6 text-neutral-500 outline-none transition-colors focus-within:border-brand-color [&_.ProseMirror]:min-h-44 [&_.ProseMirror]:rounded-md [&_.ProseMirror]:border [&_.ProseMirror]:border-brand-color [&_.ProseMirror]:outline-none [&_.ProseMirror_p]:my-2 [&_.ProseMirror_h1]:my-3 [&_.ProseMirror_h1]:text-2xl [&_.ProseMirror_h1]:font-bold [&_.ProseMirror_h2]:my-3 [&_.ProseMirror_h2]:text-xl [&_.ProseMirror_h2]:font-bold [&_.ProseMirror_h3]:my-3 [&_.ProseMirror_h3]:text-lg [&_.ProseMirror_h3]:font-bold [&_.ProseMirror_ul]:my-2 [&_.ProseMirror_ul]:list-disc [&_.ProseMirror_ul]:pl-6 [&_.ProseMirror_ol]:my-2 [&_.ProseMirror_ol]:list-decimal [&_.ProseMirror_ol]:pl-6 [&_.ProseMirror_blockquote]:my-3 [&_.ProseMirror_blockquote]:border-l-4 [&_.ProseMirror_blockquote]:border-brand-color [&_.ProseMirror_blockquote]:pl-4 [&_.ProseMirror_pre]:my-3 [&_.ProseMirror_pre]:overflow-x-auto [&_.ProseMirror_pre]:rounded [&_.ProseMirror_pre]:bg-surface-3 [&_.ProseMirror_pre]:p-3 ${editorTheme === "vs-dark" ? "bg-primary" : "bg-secondary"}`
388
+ className: `mt-4 min-h-52 rounded-md border border-brand-color p-3 text-sm leading-6 text-neutral-500 outline-none transition-colors focus-within:border-brand-color [&_.ProseMirror]:min-h-44 [&_.ProseMirror]:outline-none [&_.ProseMirror_p]:my-2 [&_.ProseMirror_h1]:my-3 [&_.ProseMirror_h1]:text-2xl [&_.ProseMirror_h1]:font-bold [&_.ProseMirror_h2]:my-3 [&_.ProseMirror_h2]:text-xl [&_.ProseMirror_h2]:font-bold [&_.ProseMirror_h3]:my-3 [&_.ProseMirror_h3]:text-lg [&_.ProseMirror_h3]:font-bold [&_.ProseMirror_ul]:my-2 [&_.ProseMirror_ul]:list-disc [&_.ProseMirror_ul]:pl-6 [&_.ProseMirror_ol]:my-2 [&_.ProseMirror_ol]:list-decimal [&_.ProseMirror_ol]:pl-6 [&_.ProseMirror_blockquote]:my-3 [&_.ProseMirror_blockquote]:border-l-4 [&_.ProseMirror_blockquote]:border-brand-color [&_.ProseMirror_blockquote]:pl-4 [&_.ProseMirror_pre]:my-3 [&_.ProseMirror_pre]:overflow-x-auto [&_.ProseMirror_pre]:rounded [&_.ProseMirror_pre]:bg-surface-3 [&_.ProseMirror_pre]:p-3 ${editorTheme === "vs-dark" ? "bg-primary" : "bg-secondary"}`
389
389
  }
390
390
  )
391
391
  ] });
@@ -2318,6 +2318,67 @@ var Tabs = ({
2318
2318
  ] });
2319
2319
  };
2320
2320
  var Tabs_default = Tabs;
2321
+ var imageExtensions = /\.(avif|bmp|gif|jpe?g|png|svg|webp)$/i;
2322
+ var textExtensions = /\.(css|csv|html?|js|jsx|md|mjs|ts|tsx|txt|xml|yaml|yml)$/i;
2323
+ var getPreviewType = (fileName) => {
2324
+ if (/\.pdf$/i.test(fileName)) return "pdf";
2325
+ if (/\.json$/i.test(fileName)) return "json";
2326
+ if (imageExtensions.test(fileName)) return "image";
2327
+ if (textExtensions.test(fileName) || !fileName.includes(".")) return "text";
2328
+ return "unsupported";
2329
+ };
2330
+ var getMimeType = (fileName) => {
2331
+ const extension = fileName.split(".").pop()?.toLowerCase();
2332
+ const mimeTypes = {
2333
+ avif: "image/avif",
2334
+ bmp: "image/bmp",
2335
+ gif: "image/gif",
2336
+ jpeg: "image/jpeg",
2337
+ jpg: "image/jpeg",
2338
+ png: "image/png",
2339
+ svg: "image/svg+xml",
2340
+ webp: "image/webp",
2341
+ pdf: "application/pdf"
2342
+ };
2343
+ return mimeTypes[extension ?? ""] ?? "application/octet-stream";
2344
+ };
2345
+ var toDataUrl = (base64, fileName) => {
2346
+ if (base64.trim().startsWith("data:")) return base64;
2347
+ return `data:${getMimeType(fileName)};base64,${base64}`;
2348
+ };
2349
+ var decodeBase64 = (base64) => {
2350
+ const value = base64.includes(",") ? base64.slice(base64.indexOf(",") + 1) : base64;
2351
+ const bytes = Uint8Array.from(atob(value), (character) => character.charCodeAt(0));
2352
+ return new TextDecoder().decode(bytes);
2353
+ };
2354
+ var PreviewComponent = ({ fileName, base64, className }) => {
2355
+ const previewType = getPreviewType(fileName);
2356
+ const dataUrl = toDataUrl(base64, fileName);
2357
+ if (previewType === "image") {
2358
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex h-full min-h-48 w-full items-center justify-center overflow-auto", className), children: /* @__PURE__ */ jsxRuntime.jsx("img", { src: dataUrl, alt: fileName, className: "max-h-full max-w-full object-contain" }) });
2359
+ }
2360
+ if (previewType === "pdf") {
2361
+ return /* @__PURE__ */ jsxRuntime.jsx("iframe", { title: fileName, src: dataUrl, className: cn("h-full min-h-96 w-full border-0", className) });
2362
+ }
2363
+ if (previewType === "text" || previewType === "json") {
2364
+ let content;
2365
+ try {
2366
+ content = decodeBase64(base64);
2367
+ if (previewType === "json") {
2368
+ content = JSON.stringify(JSON.parse(content), null, 2);
2369
+ }
2370
+ } catch {
2371
+ content = "Unable to preview this file.";
2372
+ }
2373
+ return /* @__PURE__ */ jsxRuntime.jsx("pre", { className: cn("h-full min-h-48 w-full overflow-auto whitespace-pre-wrap break-words p-4 text-left", className), children: /* @__PURE__ */ jsxRuntime.jsx("code", { children: content }) });
2374
+ }
2375
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex min-h-48 items-center justify-center p-4 text-center", className), children: /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
2376
+ "Preview is not available for ",
2377
+ fileName,
2378
+ "."
2379
+ ] }) });
2380
+ };
2381
+ var PreviewComponent_default = PreviewComponent;
2321
2382
  var DEFAULT_BACKGROUND = "/wallpaper/Wallpaper3.webp";
2322
2383
  var DEFAULT_MOCK_USER = {
2323
2384
  id: "dev-user",
@@ -3520,6 +3581,7 @@ exports.Checkbox = Checkbox_default;
3520
3581
  exports.CodeEditor = CodeEditor_default;
3521
3582
  exports.Divider = Divider_default;
3522
3583
  exports.Dropdown = Dropdown_default;
3584
+ exports.FilePreview = PreviewComponent_default;
3523
3585
  exports.FileUpload = FileUpload_default;
3524
3586
  exports.ImageWithPlaceholder = ImageWithPlaceholder_default;
3525
3587
  exports.Input = Input_default;
@@ -3527,6 +3589,7 @@ exports.Loading = Loading_default;
3527
3589
  exports.Modal = Modal_default;
3528
3590
  exports.Pagination = Pagination_default;
3529
3591
  exports.PluginPlayground = PluginPlayground;
3592
+ exports.PreviewComponent = PreviewComponent_default;
3530
3593
  exports.Progress = Progress_default;
3531
3594
  exports.Radio = Radio_default;
3532
3595
  exports.RichEditor = RichEditor_default;