@brftech/filex-react 0.40.0 → 0.41.1

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
@@ -33,23 +33,27 @@ export function App() {
33
33
  auth: { kind: 'bearer', token: '<jwt>' },
34
34
  locale: 'tr',
35
35
  theme: 'auto',
36
- // The navigation panel (Upload · Recent / Starred / Shared with me /
37
- // Trash · storages) and the chrome preset. Both are ordinary config
38
- // keys — there is no React-specific switch for either.
36
+ // The navigation panel (the "+ New" menu · Home / Shared with me /
37
+ // Recent / Starred / Trash · tags · storages) and how much of the
38
+ // explorer to draw. Both are ordinary config keys — there is no
39
+ // React-specific switch for either.
39
40
  sideNav: true,
40
41
  connections: true,
41
- // 'standard' (default) · 'simple' (one pane, list/grid only, no tab
42
- // strip) · 'drive' (that, plus the Drive-shaped shell: a "+ New" menu,
43
- // one header search field with its ⌘K palette hint, a
44
- // Type/Modified/Size filter row, Folders/Files sections in grid, and
45
- // Details/Activity in the info panel).
46
- uiProfile: 'drive',
42
+ // How much of the explorer to put on screen — a reduction, and only
43
+ // that. Two values: 'standard' (default) and 'simple' (one pane,
44
+ // list/grid only, no tab strip, no split pane). Anything else resolves
45
+ // to 'standard' with one console line naming it — the 'drive' profile
46
+ // was removed after v0.40.0; pass 'simple' instead. It does NOT decide
47
+ // the look: the "+ New" menu, the header search field with its ⌘K hint,
48
+ // the filter row, the Folders/Files sections and Details/Activity are
49
+ // what every embed draws now, with no string passed.
50
+ uiProfile: 'simple',
47
51
  }}
48
- onError={(e) => console.error(e.detail)}
49
- onShareCreated={(e) => navigator.clipboard.writeText(e.detail.url)}
50
- onFileOpened={(e) => console.log('opened', e.detail.basename)}
51
- onUploadProgress={(e) => console.log(e.detail.percent + '%')}
52
- onSelectionChange={(e) => console.log(e.detail.length, 'selected')}
52
+ onError={(e) => console.error(e.detail[0].message)}
53
+ onShareCreated={(e) => navigator.clipboard.writeText(e.detail[0].url)}
54
+ onFileOpened={(e) => console.log('opened', e.detail[0].basename)}
55
+ onUploadProgress={(e) => console.log(e.detail[0].percent + '%')}
56
+ onSelectionChange={(e) => console.log(e.detail[0].length, 'selected')}
53
57
  />
54
58
  );
55
59
  }
@@ -57,7 +61,66 @@ export function App() {
57
61
 
58
62
  The `config` prop accepts the full `ExplorerConfig` (re-exported from
59
63
  `@brftech/filex-core` for convenience). Event handlers receive native
60
- `CustomEvent`s — payload is on `event.detail`.
64
+ `CustomEvent`s, and ⚠ **the payload is `event.detail[0]`**: the underlying custom
65
+ element dispatches each emit with `detail` set to the emit's argument list, so
66
+ `event.detail.url` is `undefined`. The exported `Filex*Detail` types describe
67
+ that first element.
68
+
69
+ ## Styles
70
+
71
+ **There is no CSS import.** The snippet above is the whole of it: this package
72
+ has no stylesheet of its own and you do not need one from anywhere else.
73
+
74
+ `@brftech/filex-react` wraps the `<filex-explorer>` element from
75
+ [`@brftech/filex`](https://www.npmjs.com/package/@brftech/filex), whose bundle
76
+ carries the explorer's stylesheet *inside the JavaScript* and appends it to
77
+ `<head>` once, the first time an element mounts. The sheet is
78
+ `@brftech/filex-core`'s, byte for byte, so a React page and a Vue page render
79
+ the same explorer — the Vue wrapper is the only one that imports a
80
+ `style.css`, because mounting an SFC runs no registration step that could
81
+ inject it.
82
+
83
+ The look is the `--fe-*` custom properties. Set them on any scope above the
84
+ component — `:root`, a wrapper `div` — and the explorer follows:
85
+
86
+ ```css
87
+ :root {
88
+ --fe-primary: #2b7a41;
89
+ --fe-radius: 10px;
90
+ }
91
+ ```
92
+
93
+ Light/dark follows `config.theme` (`'light'` / `'dark'` / `'auto'`, and `auto`
94
+ reads the host's `prefers-color-scheme`). The shipped palettes are in
95
+ [`docs/INTEGRATION.md`](https://github.com/BRF-Tech/filex/blob/main/docs/INTEGRATION.md#themes).
96
+
97
+ > ⚠ The product mark in the top bar comes from `config.brand`
98
+ > (`{ name, markUrl }`), not from a slot. A host that mounts a custom element
99
+ > cannot fill a slot inside it — that is a Vue custom-element limitation, not
100
+ > an oversight — so the config entry is the door.
101
+
102
+ ## Bundler note
103
+
104
+ The rich viewers (Monaco, Mermaid, epub, xlsx, CodeMirror, …) are **optional**
105
+ and reached through dynamic imports that are caught, so a build without them
106
+ simply shows the plain viewer. A bundler, however, refuses to resolve an
107
+ import it cannot find, so `vite build` stops with
108
+ `Rollup failed to resolve import "monaco-editor"` unless you either install the
109
+ ones you want or tell it they are external:
110
+
111
+ ```js
112
+ // vite.config.js
113
+ export default {
114
+ build: {
115
+ rollupOptions: {
116
+ external: [
117
+ 'monaco-editor', 'jszip', 'mermaid', 'epubjs', 'xlsx',
118
+ '@google/model-viewer', 'codemirror', /^@codemirror\//,
119
+ ],
120
+ },
121
+ },
122
+ };
123
+ ```
61
124
 
62
125
  ## Build
63
126
 
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("react"),a=require("@lit/react");require("@brftech/filex");function l(e){const r=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e){for(const t in e)if(t!=="default"){const n=Object.getOwnPropertyDescriptor(e,t);Object.defineProperty(r,t,n.get?n:{enumerable:!0,get:()=>e[t]})}}return r.default=e,Object.freeze(r)}const c=l(o),s=typeof customElements<"u"&&customElements.get("filex-explorer")||class{},i=a.createComponent({react:c,tagName:"filex-explorer",elementClass:s,events:{onError:"error",onShareCreated:"share-created",onFileOpened:"file-opened",onUploadProgress:"upload-progress",onSelectionChange:"selection-change"}});exports.FileManager=i;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("react"),a=require("@lit/react");require("@brftech/filex");function s(t){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(t){for(const n in t)if(n!=="default"){const r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r.get?r:{enumerable:!0,get:()=>t[n]})}}return e.default=t,Object.freeze(e)}const l=s(o),i=["config","apiBase","endpoint","locale","theme","timeZone","trashVisible","sidenav","connections","uiProfile"];function c(){var n;const t=typeof customElements<"u"?customElements.get("filex-explorer"):void 0,e=(n=t==null?void 0:t.def)==null?void 0:n.props;if(Array.isArray(e)&&e.length)return e;if(e&&typeof e=="object"){const r=Object.keys(e);if(r.length)return r}return i}function u(){const t=typeof HTMLElement<"u"?HTMLElement:class{};class e extends t{}for(const n of c())n in e.prototype||Object.defineProperty(e.prototype,n,{value:void 0,writable:!0,configurable:!0,enumerable:!1});return e}const p=u(),f=a.createComponent({react:l,tagName:"filex-explorer",elementClass:p,displayName:"FileManager",events:{onError:"error",onShareCreated:"share-created",onFileOpened:"file-opened",onUploadProgress:"upload-progress",onSelectionChange:"selection-change"}});exports.FileManager=f;
2
2
  //# sourceMappingURL=filex-react.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"filex-react.cjs","sources":["../src/index.ts"],"sourcesContent":["/**\n * @brftech/filex-react — React adapter around the `<filex-explorer>`\n * Web Component.\n *\n * Uses `@lit/react`'s `createComponent` to map element attributes /\n * properties / events into idiomatic React props (camelCased event\n * handlers like `onError`, real prop assignment for the `config`\n * object, no need to imperatively reach for `.addEventListener`).\n *\n * Side-effect: importing this module also imports `@brftech/filex`\n * which registers the underlying custom element.\n */\n\nimport * as React from 'react';\nimport { createComponent } from '@lit/react';\nimport '@brftech/filex'; // side-effect: registers `<filex-explorer>`\nimport type { ExplorerConfig } from '@brftech/filex';\n\n/**\n * Resolve the registered class. We do this lazily inside a getter so\n * tree-shaking-time evaluation in some bundlers doesn't trip the\n * `customElements.get(…)` lookup before the side-effect import has run\n * (it has, but TS analysers can be jumpy). At runtime this evaluates\n * once at module load.\n */\nconst FilexElementClass =\n (typeof customElements !== 'undefined' && customElements.get('filex-explorer')) ||\n // Fallback for SSR — the element class is irrelevant on the server\n // because createComponent only renders the tag string. Provide an\n // empty class shim so types resolve.\n (class {} as unknown as CustomElementConstructor);\n\n/**\n * Idiomatic React component — used like a normal JSX tag with native\n * props.\n *\n * <FileManager\n * config={{ apiBase: 'https://files.example.com',\n * auth: { kind: 'bearer', token } }}\n * onError={(e) => console.error(e.detail)}\n * />\n */\nexport const FileManager = createComponent({\n react: React,\n tagName: 'filex-explorer',\n elementClass: FilexElementClass,\n events: {\n onError: 'error',\n onShareCreated: 'share-created',\n onFileOpened: 'file-opened',\n onUploadProgress: 'upload-progress',\n onSelectionChange: 'selection-change',\n },\n});\n\n/**\n * Re-export the config types so React consumers don't need a second\n * dependency on `@brftech/filex-core` just to type the `config` prop.\n */\nexport type {\n ExplorerConfig,\n AuthConfig,\n ThemeMode,\n LocaleCode,\n FileNode,\n ShareInfo,\n Capabilities,\n UploadInitResponse,\n UploadFinalizeResponse,\n ArchiveEntry,\n ViewMode,\n} from '@brftech/filex-core';\n\n/**\n * Helper-typed payloads the events carry — matches the SFC's emit\n * declarations so consumers get autocomplete on `event.detail`.\n */\nexport interface FilexErrorDetail {\n message: string;\n context?: unknown;\n}\n\nexport interface FilexShareCreatedDetail {\n path: string;\n url: string;\n pin: string | null;\n}\n\nexport interface FilexFileOpenedDetail {\n path: string;\n basename: string;\n}\n\nexport interface FilexUploadProgressDetail {\n uploadId: string;\n percent: number;\n done: boolean;\n}\n\nexport type FilexSelectionChangeDetail = Array<{\n path: string;\n basename: string;\n type: 'file' | 'dir';\n}>;\n"],"names":["FilexElementClass","FileManager","createComponent","React"],"mappings":"qbAyBMA,EACH,OAAO,eAAmB,KAAe,eAAe,IAAI,gBAAgB,GAI5E,KAAM,CAAC,EAYGC,EAAcC,EAAAA,gBAAgB,CACzC,MAAOC,EACP,QAAS,iBACT,aAAcH,EACd,OAAQ,CACN,QAAS,QACT,eAAgB,gBAChB,aAAc,cACd,iBAAkB,kBAClB,kBAAmB,kBAAA,CAEvB,CAAC"}
1
+ {"version":3,"file":"filex-react.cjs","sources":["../src/index.ts"],"sourcesContent":["/**\n * @brftech/filex-react — React adapter around the `<filex-explorer>`\n * Web Component.\n *\n * Uses `@lit/react`'s `createComponent` to map element attributes /\n * properties / events into idiomatic React props (camelCased event\n * handlers like `onError`, real prop assignment for the `config`\n * object, no need to imperatively reach for `.addEventListener`).\n *\n * Side-effect: importing this module also imports `@brftech/filex`\n * which registers the underlying custom element.\n */\n\nimport * as React from 'react';\nimport { createComponent } from '@lit/react';\nimport '@brftech/filex'; // side-effect: registers `<filex-explorer>`\nimport type { ExplorerConfig } from '@brftech/filex';\n\n/**\n * Property names `<filex-explorer>` accepts, taken from the component\n * definition the element was built from.\n *\n * ⚠⚠ This list is the entire bridge, and handing `createComponent` the\n * registered class instead of it is why this package did not work at all.\n * `createComponent` decides prop-by-prop with `k in elementClass.prototype`:\n * a name it finds there is ASSIGNED to the element (`node[k] = value`),\n * everything else is handed to `React.createElement` and lands as an\n * attribute. Vue's `defineCustomElement` defines its props on each\n * INSTANCE (`_resolveProps`, at connectedCallback), so the class prototype\n * carries nothing but `constructor` — measured 2026-09-13 in a real\n * browser: `Object.getOwnPropertyNames(cls.prototype)` is `['constructor']`.\n *\n * Every prop therefore took the attribute path, and `config` — an object —\n * was stringified by React on the way: the element ended up with\n * `config=\"[object Object]\"` and `el.config === '[object Object]'`. The\n * explorer never received a config, never mounted, and `<FileManager>`\n * rendered an empty page.\n *\n * The names come from `elementClass.def.props`, i.e. from the wrapper\n * component itself, so adding a prop to `@brftech/filex` cannot leave this\n * package one behind. FALLBACK_PROPS is only for an environment with no\n * custom-element registry (SSR) or a future Vue that stops exposing `def`;\n * `packages/react` is pinned to the wrapper's own list by\n * `web/tests/deploy/packageLook.test.ts`.\n */\nconst FALLBACK_PROPS = [\n 'config',\n 'apiBase',\n 'endpoint',\n 'locale',\n 'theme',\n 'timeZone',\n 'trashVisible',\n 'sidenav',\n 'connections',\n 'uiProfile',\n] as const;\n\nfunction elementPropNames(): readonly string[] {\n const registered =\n typeof customElements !== 'undefined'\n ? (customElements.get('filex-explorer') as\n | (CustomElementConstructor & { def?: { props?: unknown } })\n | undefined)\n : undefined;\n const declared = registered?.def?.props;\n if (Array.isArray(declared) && declared.length) return declared as string[];\n if (declared && typeof declared === 'object') {\n const keys = Object.keys(declared as Record<string, unknown>);\n if (keys.length) return keys;\n }\n return FALLBACK_PROPS;\n}\n\n/**\n * A stand-in class whose PROTOTYPE carries those names, which is the only\n * thing `createComponent` reads it for (that, and `.name` for the devtools\n * label — we pass `displayName` instead).\n *\n * It extends HTMLElement where there is one so the native properties keep\n * behaving exactly as they did: `id`, `title`, `hidden` and friends stay on\n * the property path, `style`/`className`/`children`/`ref` stay React's.\n * Nothing ever constructs it — an unregistered `class extends HTMLElement`\n * is only illegal to `new`, not to declare.\n */\nfunction propBridgeClass(): CustomElementConstructor {\n const Base = (\n typeof HTMLElement !== 'undefined' ? HTMLElement : class {}\n ) as CustomElementConstructor;\n class FilexExplorerProps extends Base {}\n for (const name of elementPropNames()) {\n if (name in FilexExplorerProps.prototype) continue;\n Object.defineProperty(FilexExplorerProps.prototype, name, {\n value: undefined,\n writable: true,\n configurable: true,\n enumerable: false,\n });\n }\n return FilexExplorerProps;\n}\n\nconst FilexElementClass = propBridgeClass();\n\n/**\n * Idiomatic React component — used like a normal JSX tag with native\n * props.\n *\n * <FileManager\n * config={{ apiBase: 'https://files.example.com',\n * auth: { kind: 'bearer', token } }}\n * onError={(e) => console.error(e.detail)}\n * />\n */\nexport const FileManager = createComponent({\n react: React,\n tagName: 'filex-explorer',\n elementClass: FilexElementClass,\n displayName: 'FileManager',\n events: {\n onError: 'error',\n onShareCreated: 'share-created',\n onFileOpened: 'file-opened',\n onUploadProgress: 'upload-progress',\n onSelectionChange: 'selection-change',\n },\n});\n\n/**\n * Re-export the config types so React consumers don't need a second\n * dependency on `@brftech/filex-core` just to type the `config` prop.\n */\nexport type {\n ExplorerConfig,\n AuthConfig,\n ThemeMode,\n LocaleCode,\n FileNode,\n ShareInfo,\n Capabilities,\n UploadInitResponse,\n UploadFinalizeResponse,\n ArchiveEntry,\n ViewMode,\n} from '@brftech/filex-core';\n\n/**\n * Helper-typed payloads the events carry — matches the SFC's emit\n * declarations so consumers get autocomplete on `event.detail`.\n */\nexport interface FilexErrorDetail {\n message: string;\n context?: unknown;\n}\n\nexport interface FilexShareCreatedDetail {\n path: string;\n url: string;\n pin: string | null;\n}\n\nexport interface FilexFileOpenedDetail {\n path: string;\n basename: string;\n}\n\nexport interface FilexUploadProgressDetail {\n uploadId: string;\n percent: number;\n done: boolean;\n}\n\nexport type FilexSelectionChangeDetail = Array<{\n path: string;\n basename: string;\n type: 'file' | 'dir';\n}>;\n"],"names":["FALLBACK_PROPS","elementPropNames","registered","declared","_a","keys","propBridgeClass","Base","FilexExplorerProps","name","FilexElementClass","FileManager","createComponent","React"],"mappings":"qbA6CMA,EAAiB,CACrB,SACA,UACA,WACA,SACA,QACA,WACA,eACA,UACA,cACA,WACF,EAEA,SAASC,GAAsC,OAC7C,MAAMC,EACJ,OAAO,eAAmB,IACrB,eAAe,IAAI,gBAAgB,EAGpC,OACAC,GAAWC,EAAAF,GAAA,YAAAA,EAAY,MAAZ,YAAAE,EAAiB,MAClC,GAAI,MAAM,QAAQD,CAAQ,GAAKA,EAAS,OAAQ,OAAOA,EACvD,GAAIA,GAAY,OAAOA,GAAa,SAAU,CAC5C,MAAME,EAAO,OAAO,KAAKF,CAAmC,EAC5D,GAAIE,EAAK,OAAQ,OAAOA,CAC1B,CACA,OAAOL,CACT,CAaA,SAASM,GAA4C,CACnD,MAAMC,EACJ,OAAO,YAAgB,IAAc,YAAc,KAAM,CAAA,EAE3D,MAAMC,UAA2BD,CAAK,CAAA,CACtC,UAAWE,KAAQR,IACbQ,KAAQD,EAAmB,WAC/B,OAAO,eAAeA,EAAmB,UAAWC,EAAM,CACxD,MAAO,OACP,SAAU,GACV,aAAc,GACd,WAAY,EAAA,CACb,EAEH,OAAOD,CACT,CAEA,MAAME,EAAoBJ,EAAA,EAYbK,EAAcC,EAAAA,gBAAgB,CACzC,MAAOC,EACP,QAAS,iBACT,aAAcH,EACd,YAAa,cACb,OAAQ,CACN,QAAS,QACT,eAAgB,gBAChB,aAAc,cACd,iBAAkB,kBAClB,kBAAmB,kBAAA,CAEvB,CAAC"}
@@ -1,14 +1,47 @@
1
- import * as e from "react";
2
- import { createComponent as o } from "@lit/react";
1
+ import * as r from "react";
2
+ import { createComponent as s } from "@lit/react";
3
3
  import "@brftech/filex";
4
- const r = typeof customElements < "u" && customElements.get("filex-explorer") || // Fallback for SSR — the element class is irrelevant on the server
5
- // because createComponent only renders the tag string. Provide an
6
- // empty class shim so types resolve.
7
- class {
8
- }, s = o({
9
- react: e,
4
+ const a = [
5
+ "config",
6
+ "apiBase",
7
+ "endpoint",
8
+ "locale",
9
+ "theme",
10
+ "timeZone",
11
+ "trashVisible",
12
+ "sidenav",
13
+ "connections",
14
+ "uiProfile"
15
+ ];
16
+ function i() {
17
+ var o;
18
+ const n = typeof customElements < "u" ? customElements.get("filex-explorer") : void 0, e = (o = n == null ? void 0 : n.def) == null ? void 0 : o.props;
19
+ if (Array.isArray(e) && e.length) return e;
20
+ if (e && typeof e == "object") {
21
+ const t = Object.keys(e);
22
+ if (t.length) return t;
23
+ }
24
+ return a;
25
+ }
26
+ function l() {
27
+ const n = typeof HTMLElement < "u" ? HTMLElement : class {
28
+ };
29
+ class e extends n {
30
+ }
31
+ for (const o of i())
32
+ o in e.prototype || Object.defineProperty(e.prototype, o, {
33
+ value: void 0,
34
+ writable: !0,
35
+ configurable: !0,
36
+ enumerable: !1
37
+ });
38
+ return e;
39
+ }
40
+ const c = l(), m = s({
41
+ react: r,
10
42
  tagName: "filex-explorer",
11
- elementClass: r,
43
+ elementClass: c,
44
+ displayName: "FileManager",
12
45
  events: {
13
46
  onError: "error",
14
47
  onShareCreated: "share-created",
@@ -18,6 +51,6 @@ class {
18
51
  }
19
52
  });
20
53
  export {
21
- s as FileManager
54
+ m as FileManager
22
55
  };
23
56
  //# sourceMappingURL=filex-react.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"filex-react.js","sources":["../src/index.ts"],"sourcesContent":["/**\n * @brftech/filex-react — React adapter around the `<filex-explorer>`\n * Web Component.\n *\n * Uses `@lit/react`'s `createComponent` to map element attributes /\n * properties / events into idiomatic React props (camelCased event\n * handlers like `onError`, real prop assignment for the `config`\n * object, no need to imperatively reach for `.addEventListener`).\n *\n * Side-effect: importing this module also imports `@brftech/filex`\n * which registers the underlying custom element.\n */\n\nimport * as React from 'react';\nimport { createComponent } from '@lit/react';\nimport '@brftech/filex'; // side-effect: registers `<filex-explorer>`\nimport type { ExplorerConfig } from '@brftech/filex';\n\n/**\n * Resolve the registered class. We do this lazily inside a getter so\n * tree-shaking-time evaluation in some bundlers doesn't trip the\n * `customElements.get(…)` lookup before the side-effect import has run\n * (it has, but TS analysers can be jumpy). At runtime this evaluates\n * once at module load.\n */\nconst FilexElementClass =\n (typeof customElements !== 'undefined' && customElements.get('filex-explorer')) ||\n // Fallback for SSR — the element class is irrelevant on the server\n // because createComponent only renders the tag string. Provide an\n // empty class shim so types resolve.\n (class {} as unknown as CustomElementConstructor);\n\n/**\n * Idiomatic React component — used like a normal JSX tag with native\n * props.\n *\n * <FileManager\n * config={{ apiBase: 'https://files.example.com',\n * auth: { kind: 'bearer', token } }}\n * onError={(e) => console.error(e.detail)}\n * />\n */\nexport const FileManager = createComponent({\n react: React,\n tagName: 'filex-explorer',\n elementClass: FilexElementClass,\n events: {\n onError: 'error',\n onShareCreated: 'share-created',\n onFileOpened: 'file-opened',\n onUploadProgress: 'upload-progress',\n onSelectionChange: 'selection-change',\n },\n});\n\n/**\n * Re-export the config types so React consumers don't need a second\n * dependency on `@brftech/filex-core` just to type the `config` prop.\n */\nexport type {\n ExplorerConfig,\n AuthConfig,\n ThemeMode,\n LocaleCode,\n FileNode,\n ShareInfo,\n Capabilities,\n UploadInitResponse,\n UploadFinalizeResponse,\n ArchiveEntry,\n ViewMode,\n} from '@brftech/filex-core';\n\n/**\n * Helper-typed payloads the events carry — matches the SFC's emit\n * declarations so consumers get autocomplete on `event.detail`.\n */\nexport interface FilexErrorDetail {\n message: string;\n context?: unknown;\n}\n\nexport interface FilexShareCreatedDetail {\n path: string;\n url: string;\n pin: string | null;\n}\n\nexport interface FilexFileOpenedDetail {\n path: string;\n basename: string;\n}\n\nexport interface FilexUploadProgressDetail {\n uploadId: string;\n percent: number;\n done: boolean;\n}\n\nexport type FilexSelectionChangeDetail = Array<{\n path: string;\n basename: string;\n type: 'file' | 'dir';\n}>;\n"],"names":["FilexElementClass","FileManager","createComponent","React"],"mappings":";;;AAyBA,MAAMA,IACH,OAAO,iBAAmB,OAAe,eAAe,IAAI,gBAAgB;AAAA;AAAA;AAI5E,MAAM;AAAC,GAYGC,IAAcC,EAAgB;AAAA,EACzC,OAAOC;AAAA,EACP,SAAS;AAAA,EACT,cAAcH;AAAA,EACd,QAAQ;AAAA,IACN,SAAS;AAAA,IACT,gBAAgB;AAAA,IAChB,cAAc;AAAA,IACd,kBAAkB;AAAA,IAClB,mBAAmB;AAAA,EAAA;AAEvB,CAAC;"}
1
+ {"version":3,"file":"filex-react.js","sources":["../src/index.ts"],"sourcesContent":["/**\n * @brftech/filex-react — React adapter around the `<filex-explorer>`\n * Web Component.\n *\n * Uses `@lit/react`'s `createComponent` to map element attributes /\n * properties / events into idiomatic React props (camelCased event\n * handlers like `onError`, real prop assignment for the `config`\n * object, no need to imperatively reach for `.addEventListener`).\n *\n * Side-effect: importing this module also imports `@brftech/filex`\n * which registers the underlying custom element.\n */\n\nimport * as React from 'react';\nimport { createComponent } from '@lit/react';\nimport '@brftech/filex'; // side-effect: registers `<filex-explorer>`\nimport type { ExplorerConfig } from '@brftech/filex';\n\n/**\n * Property names `<filex-explorer>` accepts, taken from the component\n * definition the element was built from.\n *\n * ⚠⚠ This list is the entire bridge, and handing `createComponent` the\n * registered class instead of it is why this package did not work at all.\n * `createComponent` decides prop-by-prop with `k in elementClass.prototype`:\n * a name it finds there is ASSIGNED to the element (`node[k] = value`),\n * everything else is handed to `React.createElement` and lands as an\n * attribute. Vue's `defineCustomElement` defines its props on each\n * INSTANCE (`_resolveProps`, at connectedCallback), so the class prototype\n * carries nothing but `constructor` — measured 2026-09-13 in a real\n * browser: `Object.getOwnPropertyNames(cls.prototype)` is `['constructor']`.\n *\n * Every prop therefore took the attribute path, and `config` — an object —\n * was stringified by React on the way: the element ended up with\n * `config=\"[object Object]\"` and `el.config === '[object Object]'`. The\n * explorer never received a config, never mounted, and `<FileManager>`\n * rendered an empty page.\n *\n * The names come from `elementClass.def.props`, i.e. from the wrapper\n * component itself, so adding a prop to `@brftech/filex` cannot leave this\n * package one behind. FALLBACK_PROPS is only for an environment with no\n * custom-element registry (SSR) or a future Vue that stops exposing `def`;\n * `packages/react` is pinned to the wrapper's own list by\n * `web/tests/deploy/packageLook.test.ts`.\n */\nconst FALLBACK_PROPS = [\n 'config',\n 'apiBase',\n 'endpoint',\n 'locale',\n 'theme',\n 'timeZone',\n 'trashVisible',\n 'sidenav',\n 'connections',\n 'uiProfile',\n] as const;\n\nfunction elementPropNames(): readonly string[] {\n const registered =\n typeof customElements !== 'undefined'\n ? (customElements.get('filex-explorer') as\n | (CustomElementConstructor & { def?: { props?: unknown } })\n | undefined)\n : undefined;\n const declared = registered?.def?.props;\n if (Array.isArray(declared) && declared.length) return declared as string[];\n if (declared && typeof declared === 'object') {\n const keys = Object.keys(declared as Record<string, unknown>);\n if (keys.length) return keys;\n }\n return FALLBACK_PROPS;\n}\n\n/**\n * A stand-in class whose PROTOTYPE carries those names, which is the only\n * thing `createComponent` reads it for (that, and `.name` for the devtools\n * label — we pass `displayName` instead).\n *\n * It extends HTMLElement where there is one so the native properties keep\n * behaving exactly as they did: `id`, `title`, `hidden` and friends stay on\n * the property path, `style`/`className`/`children`/`ref` stay React's.\n * Nothing ever constructs it — an unregistered `class extends HTMLElement`\n * is only illegal to `new`, not to declare.\n */\nfunction propBridgeClass(): CustomElementConstructor {\n const Base = (\n typeof HTMLElement !== 'undefined' ? HTMLElement : class {}\n ) as CustomElementConstructor;\n class FilexExplorerProps extends Base {}\n for (const name of elementPropNames()) {\n if (name in FilexExplorerProps.prototype) continue;\n Object.defineProperty(FilexExplorerProps.prototype, name, {\n value: undefined,\n writable: true,\n configurable: true,\n enumerable: false,\n });\n }\n return FilexExplorerProps;\n}\n\nconst FilexElementClass = propBridgeClass();\n\n/**\n * Idiomatic React component — used like a normal JSX tag with native\n * props.\n *\n * <FileManager\n * config={{ apiBase: 'https://files.example.com',\n * auth: { kind: 'bearer', token } }}\n * onError={(e) => console.error(e.detail)}\n * />\n */\nexport const FileManager = createComponent({\n react: React,\n tagName: 'filex-explorer',\n elementClass: FilexElementClass,\n displayName: 'FileManager',\n events: {\n onError: 'error',\n onShareCreated: 'share-created',\n onFileOpened: 'file-opened',\n onUploadProgress: 'upload-progress',\n onSelectionChange: 'selection-change',\n },\n});\n\n/**\n * Re-export the config types so React consumers don't need a second\n * dependency on `@brftech/filex-core` just to type the `config` prop.\n */\nexport type {\n ExplorerConfig,\n AuthConfig,\n ThemeMode,\n LocaleCode,\n FileNode,\n ShareInfo,\n Capabilities,\n UploadInitResponse,\n UploadFinalizeResponse,\n ArchiveEntry,\n ViewMode,\n} from '@brftech/filex-core';\n\n/**\n * Helper-typed payloads the events carry — matches the SFC's emit\n * declarations so consumers get autocomplete on `event.detail`.\n */\nexport interface FilexErrorDetail {\n message: string;\n context?: unknown;\n}\n\nexport interface FilexShareCreatedDetail {\n path: string;\n url: string;\n pin: string | null;\n}\n\nexport interface FilexFileOpenedDetail {\n path: string;\n basename: string;\n}\n\nexport interface FilexUploadProgressDetail {\n uploadId: string;\n percent: number;\n done: boolean;\n}\n\nexport type FilexSelectionChangeDetail = Array<{\n path: string;\n basename: string;\n type: 'file' | 'dir';\n}>;\n"],"names":["FALLBACK_PROPS","elementPropNames","registered","declared","_a","keys","propBridgeClass","Base","FilexExplorerProps","name","FilexElementClass","FileManager","createComponent","React"],"mappings":";;;AA6CA,MAAMA,IAAiB;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,SAASC,IAAsC;;AAC7C,QAAMC,IACJ,OAAO,iBAAmB,MACrB,eAAe,IAAI,gBAAgB,IAGpC,QACAC,KAAWC,IAAAF,KAAA,gBAAAA,EAAY,QAAZ,gBAAAE,EAAiB;AAClC,MAAI,MAAM,QAAQD,CAAQ,KAAKA,EAAS,OAAQ,QAAOA;AACvD,MAAIA,KAAY,OAAOA,KAAa,UAAU;AAC5C,UAAME,IAAO,OAAO,KAAKF,CAAmC;AAC5D,QAAIE,EAAK,OAAQ,QAAOA;AAAA,EAC1B;AACA,SAAOL;AACT;AAaA,SAASM,IAA4C;AACnD,QAAMC,IACJ,OAAO,cAAgB,MAAc,cAAc,MAAM;AAAA,EAAA;AAAA,EAE3D,MAAMC,UAA2BD,EAAK;AAAA,EAAA;AACtC,aAAWE,KAAQR;AACjB,IAAIQ,KAAQD,EAAmB,aAC/B,OAAO,eAAeA,EAAmB,WAAWC,GAAM;AAAA,MACxD,OAAO;AAAA,MACP,UAAU;AAAA,MACV,cAAc;AAAA,MACd,YAAY;AAAA,IAAA,CACb;AAEH,SAAOD;AACT;AAEA,MAAME,IAAoBJ,EAAA,GAYbK,IAAcC,EAAgB;AAAA,EACzC,OAAOC;AAAA,EACP,SAAS;AAAA,EACT,cAAcH;AAAA,EACd,aAAa;AAAA,EACb,QAAQ;AAAA,IACN,SAAS;AAAA,IACT,gBAAgB;AAAA,IAChB,cAAc;AAAA,IACd,kBAAkB;AAAA,IAClB,mBAAmB;AAAA,EAAA;AAEvB,CAAC;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brftech/filex-react",
3
- "version": "0.40.0",
3
+ "version": "0.41.1",
4
4
  "description": "filex React adapter — wraps <filex-explorer> for React idiom (props + camelCase event handlers)",
5
5
  "type": "module",
6
6
  "main": "./dist/filex-react.cjs",
@@ -19,8 +19,8 @@
19
19
  ],
20
20
  "dependencies": {
21
21
  "@lit/react": "^1.0.5",
22
- "@brftech/filex": "0.40.0",
23
- "@brftech/filex-core": "0.40.0"
22
+ "@brftech/filex": "0.41.1",
23
+ "@brftech/filex-core": "0.41.1"
24
24
  },
25
25
  "peerDependencies": {
26
26
  "react": "^18.0.0 || ^19.0.0",