@elementor/wp-media 0.1.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.
@@ -0,0 +1,49 @@
1
+ import * as _tanstack_react_query from '@tanstack/react-query';
2
+
3
+ type Attachment = {
4
+ id: number;
5
+ url: string;
6
+ alt: string;
7
+ filename: string;
8
+ title: string;
9
+ mime: string;
10
+ type: string;
11
+ subtype: string;
12
+ uploadedTo: number;
13
+ filesize: {
14
+ inBytes: number;
15
+ humanReadable: string;
16
+ };
17
+ author: {
18
+ id: number;
19
+ name: string;
20
+ };
21
+ sizes: Record<string, {
22
+ width: number;
23
+ height: number;
24
+ url: string;
25
+ }>;
26
+ };
27
+
28
+ declare function useWpMediaAttachment(id: number | undefined): _tanstack_react_query.UseQueryResult<Attachment | null, Error>;
29
+
30
+ type OpenOptions = {
31
+ mode?: 'upload' | 'browse';
32
+ };
33
+ type Options = {
34
+ types: Array<'image'>;
35
+ title?: string;
36
+ } & ({
37
+ multiple: true;
38
+ selected: Array<number | undefined>;
39
+ onSelect: (val: Attachment[]) => void;
40
+ } | {
41
+ multiple: false;
42
+ selected: number | undefined;
43
+ onSelect: (val: Attachment) => void;
44
+ });
45
+ declare function useWpMediaFrame(options: Options): {
46
+ open: (openOptions?: OpenOptions) => void;
47
+ };
48
+
49
+ export { Attachment, useWpMediaAttachment, useWpMediaFrame };
@@ -0,0 +1,49 @@
1
+ import * as _tanstack_react_query from '@tanstack/react-query';
2
+
3
+ type Attachment = {
4
+ id: number;
5
+ url: string;
6
+ alt: string;
7
+ filename: string;
8
+ title: string;
9
+ mime: string;
10
+ type: string;
11
+ subtype: string;
12
+ uploadedTo: number;
13
+ filesize: {
14
+ inBytes: number;
15
+ humanReadable: string;
16
+ };
17
+ author: {
18
+ id: number;
19
+ name: string;
20
+ };
21
+ sizes: Record<string, {
22
+ width: number;
23
+ height: number;
24
+ url: string;
25
+ }>;
26
+ };
27
+
28
+ declare function useWpMediaAttachment(id: number | undefined): _tanstack_react_query.UseQueryResult<Attachment | null, Error>;
29
+
30
+ type OpenOptions = {
31
+ mode?: 'upload' | 'browse';
32
+ };
33
+ type Options = {
34
+ types: Array<'image'>;
35
+ title?: string;
36
+ } & ({
37
+ multiple: true;
38
+ selected: Array<number | undefined>;
39
+ onSelect: (val: Attachment[]) => void;
40
+ } | {
41
+ multiple: false;
42
+ selected: number | undefined;
43
+ onSelect: (val: Attachment) => void;
44
+ });
45
+ declare function useWpMediaFrame(options: Options): {
46
+ open: (openOptions?: OpenOptions) => void;
47
+ };
48
+
49
+ export { Attachment, useWpMediaAttachment, useWpMediaFrame };
package/dist/index.js ADDED
@@ -0,0 +1,140 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var src_exports = {};
22
+ __export(src_exports, {
23
+ useWpMediaAttachment: () => useWpMediaAttachment,
24
+ useWpMediaFrame: () => useWpMediaFrame
25
+ });
26
+ module.exports = __toCommonJS(src_exports);
27
+
28
+ // src/hooks/use-wp-media-attachment.ts
29
+ var import_query = require("@elementor/query");
30
+
31
+ // src/errors.ts
32
+ var import_utils = require("@elementor/utils");
33
+ var WpMediaNotAvailableError = (0, import_utils.createError)({
34
+ code: "wp_media_not_available",
35
+ message: "`wp.media` is not available, make sure the `media-model` handle is set in the dependencies array"
36
+ });
37
+
38
+ // src/media.ts
39
+ var wpMediaWindow = window;
40
+ var media_default = () => {
41
+ if (!wpMediaWindow.wp?.media) {
42
+ throw new WpMediaNotAvailableError();
43
+ }
44
+ return wpMediaWindow.wp.media;
45
+ };
46
+
47
+ // src/normalize.ts
48
+ function normalize(attachment) {
49
+ const { filesizeInBytes, filesizeHumanReadable, author, authorName, ...rest } = attachment;
50
+ return {
51
+ ...rest,
52
+ filesize: {
53
+ inBytes: filesizeInBytes,
54
+ humanReadable: filesizeHumanReadable
55
+ },
56
+ author: {
57
+ id: parseInt(author),
58
+ name: authorName
59
+ }
60
+ };
61
+ }
62
+
63
+ // src/hooks/use-wp-media-attachment.ts
64
+ function useWpMediaAttachment(id) {
65
+ return (0, import_query.useQuery)({
66
+ queryKey: ["wp-attachment", id],
67
+ queryFn: getAttachment,
68
+ enabled: !!id
69
+ });
70
+ }
71
+ async function getAttachment({ queryKey: [, id] }) {
72
+ if (!id) {
73
+ return null;
74
+ }
75
+ const model = media_default().attachment(id);
76
+ const wpAttachment = model.toJSON();
77
+ const isFetched = "url" in wpAttachment;
78
+ if (isFetched) {
79
+ return normalize(wpAttachment);
80
+ }
81
+ try {
82
+ return normalize(await model.fetch());
83
+ } catch (e) {
84
+ return null;
85
+ }
86
+ }
87
+
88
+ // src/hooks/use-wp-media-frame.ts
89
+ var import_react = require("react");
90
+ function useWpMediaFrame(options) {
91
+ const frame = (0, import_react.useRef)();
92
+ const open = (openOptions = {}) => {
93
+ cleanupFrame();
94
+ frame.current = createFrame({ ...options, ...openOptions });
95
+ frame.current?.open();
96
+ };
97
+ const cleanupFrame = () => {
98
+ frame.current?.detach();
99
+ frame.current?.remove();
100
+ };
101
+ (0, import_react.useEffect)(() => {
102
+ return () => {
103
+ cleanupFrame();
104
+ };
105
+ }, []);
106
+ return {
107
+ open
108
+ };
109
+ }
110
+ function createFrame({ onSelect, multiple, types, selected, title, mode = "browse" }) {
111
+ const frame = media_default()({
112
+ title,
113
+ multiple,
114
+ library: {
115
+ type: types
116
+ }
117
+ }).on("open", () => {
118
+ applyMode(frame, mode);
119
+ applySelection(frame, selected);
120
+ }).on("close", () => frame.detach()).on("insert select", () => select(frame, multiple, onSelect));
121
+ return frame;
122
+ }
123
+ function applyMode(frame, mode = "browse") {
124
+ frame.content.mode(mode);
125
+ }
126
+ function applySelection(frame, selected) {
127
+ const selectedAttachments = (typeof selected === "number" ? [selected] : selected)?.filter((id) => !!id).map((id) => media_default().attachment(id));
128
+ frame.state().get("selection").set(selectedAttachments || []);
129
+ }
130
+ function select(frame, multiple, onSelect) {
131
+ const attachments = frame.state().get("selection").toJSON().map(normalize);
132
+ const onSelectFn = onSelect;
133
+ onSelectFn(multiple ? attachments : attachments[0]);
134
+ }
135
+ // Annotate the CommonJS export names for ESM import in node:
136
+ 0 && (module.exports = {
137
+ useWpMediaAttachment,
138
+ useWpMediaFrame
139
+ });
140
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/hooks/use-wp-media-attachment.ts","../src/errors.ts","../src/media.ts","../src/normalize.ts","../src/hooks/use-wp-media-frame.ts"],"sourcesContent":["export type { Attachment } from './types/attachment';\n\nexport { default as useWpMediaAttachment } from './hooks/use-wp-media-attachment';\nexport { default as useWpMediaFrame } from './hooks/use-wp-media-frame';\n","import { useQuery } from '@elementor/query';\nimport media from '../media';\nimport normalize from '../normalize';\n\nexport default function useWpMediaAttachment( id: number | undefined ) {\n\treturn useQuery( {\n\t\tqueryKey: [ 'wp-attachment', id ],\n\t\tqueryFn: getAttachment,\n\t\tenabled: !! id,\n\t} );\n}\n\nasync function getAttachment( { queryKey: [ , id ] }: { queryKey: [ string, number | undefined ] } ) {\n\tif ( ! id ) {\n\t\treturn null;\n\t}\n\n\tconst model = media().attachment( id );\n\tconst wpAttachment = model.toJSON();\n\n\tconst isFetched = 'url' in wpAttachment;\n\n\tif ( isFetched ) {\n\t\treturn normalize( wpAttachment );\n\t}\n\n\ttry {\n\t\treturn normalize( await model.fetch() );\n\t} catch ( e ) {\n\t\treturn null;\n\t}\n}\n","import { createError } from '@elementor/utils';\n\nexport const WpMediaNotAvailableError = createError( {\n\tcode: 'wp_media_not_available',\n\tmessage: '`wp.media` is not available, make sure the `media-model` handle is set in the dependencies array',\n} );\n","import { WpMediaWindow } from './types/wp-media';\nimport { WpMediaNotAvailableError } from './errors';\n\nconst wpMediaWindow = window as unknown as WpMediaWindow;\n\nexport default () => {\n\tif ( ! wpMediaWindow.wp?.media ) {\n\t\tthrow new WpMediaNotAvailableError();\n\t}\n\n\treturn wpMediaWindow.wp.media;\n};\n","import { WpAttachmentJSON } from './types/wp-media';\nimport { Attachment } from './types/attachment';\n\nexport default function normalize( attachment: WpAttachmentJSON ): Attachment {\n\tconst { filesizeInBytes, filesizeHumanReadable, author, authorName, ...rest } = attachment;\n\n\treturn {\n\t\t...rest,\n\t\tfilesize: {\n\t\t\tinBytes: filesizeInBytes,\n\t\t\thumanReadable: filesizeHumanReadable,\n\t\t},\n\t\tauthor: {\n\t\t\tid: parseInt( author ),\n\t\t\tname: authorName,\n\t\t},\n\t};\n}\n","import { useEffect, useRef } from 'react';\nimport normalize from '../normalize';\nimport { MediaFrame } from '../types/wp-media';\nimport { Attachment } from '../types/attachment';\nimport media from '../media';\n\ntype OpenOptions = {\n\tmode?: 'upload' | 'browse';\n};\n\ntype Options = {\n\ttypes: Array< 'image' >;\n\ttitle?: string;\n} & (\n\t| {\n\t\t\tmultiple: true;\n\t\t\tselected: Array< number | undefined >;\n\t\t\tonSelect: ( val: Attachment[] ) => void;\n\t }\n\t| {\n\t\t\tmultiple: false;\n\t\t\tselected: number | undefined;\n\t\t\tonSelect: ( val: Attachment ) => void;\n\t }\n);\n\nexport default function useWpMediaFrame( options: Options ) {\n\tconst frame = useRef< MediaFrame >();\n\n\tconst open = ( openOptions: OpenOptions = {} ) => {\n\t\tcleanupFrame();\n\n\t\tframe.current = createFrame( { ...options, ...openOptions } );\n\n\t\tframe.current?.open();\n\t};\n\n\tconst cleanupFrame = () => {\n\t\tframe.current?.detach();\n\t\tframe.current?.remove();\n\t};\n\n\tuseEffect( () => {\n\t\treturn () => {\n\t\t\tcleanupFrame();\n\t\t};\n\t}, [] );\n\n\treturn {\n\t\topen,\n\t};\n}\n\nfunction createFrame( { onSelect, multiple, types, selected, title, mode = 'browse' }: Options & OpenOptions ) {\n\tconst frame: MediaFrame = media()( {\n\t\ttitle,\n\t\tmultiple,\n\t\tlibrary: {\n\t\t\ttype: types,\n\t\t},\n\t} )\n\t\t.on( 'open', () => {\n\t\t\tapplyMode( frame, mode );\n\t\t\tapplySelection( frame, selected );\n\t\t} )\n\t\t.on( 'close', () => frame.detach() )\n\t\t.on( 'insert select', () => select( frame, multiple, onSelect ) );\n\n\treturn frame;\n}\n\nfunction applyMode( frame: MediaFrame, mode: OpenOptions[ 'mode' ] = 'browse' ) {\n\tframe.content.mode( mode );\n}\n\nfunction applySelection( frame: MediaFrame, selected: number | undefined | Array< number | undefined > ) {\n\tconst selectedAttachments = ( typeof selected === 'number' ? [ selected ] : selected )\n\t\t?.filter( ( id ) => !! id )\n\t\t.map( ( id ) => media().attachment( id as number ) );\n\n\tframe\n\t\t.state()\n\t\t.get( 'selection' )\n\t\t.set( selectedAttachments || [] );\n}\n\nfunction select( frame: MediaFrame, multiple: boolean, onSelect: Options[ 'onSelect' ] ) {\n\tconst attachments = frame.state().get( 'selection' ).toJSON().map( normalize );\n\n\tconst onSelectFn = onSelect as ( val: Attachment | Attachment[] ) => void;\n\n\tonSelectFn( multiple ? attachments : attachments[ 0 ] );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,mBAAyB;;;ACAzB,mBAA4B;AAErB,IAAM,+BAA2B,0BAAa;AAAA,EACpD,MAAM;AAAA,EACN,SAAS;AACV,CAAE;;;ACFF,IAAM,gBAAgB;AAEtB,IAAO,gBAAQ,MAAM;AACpB,MAAK,CAAE,cAAc,IAAI,OAAQ;AAChC,UAAM,IAAI,yBAAyB;AAAA,EACpC;AAEA,SAAO,cAAc,GAAG;AACzB;;;ACRe,SAAR,UAA4B,YAA2C;AAC7E,QAAM,EAAE,iBAAiB,uBAAuB,QAAQ,YAAY,GAAG,KAAK,IAAI;AAEhF,SAAO;AAAA,IACN,GAAG;AAAA,IACH,UAAU;AAAA,MACT,SAAS;AAAA,MACT,eAAe;AAAA,IAChB;AAAA,IACA,QAAQ;AAAA,MACP,IAAI,SAAU,MAAO;AAAA,MACrB,MAAM;AAAA,IACP;AAAA,EACD;AACD;;;AHbe,SAAR,qBAAuC,IAAyB;AACtE,aAAO,uBAAU;AAAA,IAChB,UAAU,CAAE,iBAAiB,EAAG;AAAA,IAChC,SAAS;AAAA,IACT,SAAS,CAAC,CAAE;AAAA,EACb,CAAE;AACH;AAEA,eAAe,cAAe,EAAE,UAAU,CAAE,EAAE,EAAG,EAAE,GAAkD;AACpG,MAAK,CAAE,IAAK;AACX,WAAO;AAAA,EACR;AAEA,QAAM,QAAQ,cAAM,EAAE,WAAY,EAAG;AACrC,QAAM,eAAe,MAAM,OAAO;AAElC,QAAM,YAAY,SAAS;AAE3B,MAAK,WAAY;AAChB,WAAO,UAAW,YAAa;AAAA,EAChC;AAEA,MAAI;AACH,WAAO,UAAW,MAAM,MAAM,MAAM,CAAE;AAAA,EACvC,SAAU,GAAI;AACb,WAAO;AAAA,EACR;AACD;;;AI/BA,mBAAkC;AA0BnB,SAAR,gBAAkC,SAAmB;AAC3D,QAAM,YAAQ,qBAAqB;AAEnC,QAAM,OAAO,CAAE,cAA2B,CAAC,MAAO;AACjD,iBAAa;AAEb,UAAM,UAAU,YAAa,EAAE,GAAG,SAAS,GAAG,YAAY,CAAE;AAE5D,UAAM,SAAS,KAAK;AAAA,EACrB;AAEA,QAAM,eAAe,MAAM;AAC1B,UAAM,SAAS,OAAO;AACtB,UAAM,SAAS,OAAO;AAAA,EACvB;AAEA,8BAAW,MAAM;AAChB,WAAO,MAAM;AACZ,mBAAa;AAAA,IACd;AAAA,EACD,GAAG,CAAC,CAAE;AAEN,SAAO;AAAA,IACN;AAAA,EACD;AACD;AAEA,SAAS,YAAa,EAAE,UAAU,UAAU,OAAO,UAAU,OAAO,OAAO,SAAS,GAA2B;AAC9G,QAAM,QAAoB,cAAM,EAAG;AAAA,IAClC;AAAA,IACA;AAAA,IACA,SAAS;AAAA,MACR,MAAM;AAAA,IACP;AAAA,EACD,CAAE,EACA,GAAI,QAAQ,MAAM;AAClB,cAAW,OAAO,IAAK;AACvB,mBAAgB,OAAO,QAAS;AAAA,EACjC,CAAE,EACD,GAAI,SAAS,MAAM,MAAM,OAAO,CAAE,EAClC,GAAI,iBAAiB,MAAM,OAAQ,OAAO,UAAU,QAAS,CAAE;AAEjE,SAAO;AACR;AAEA,SAAS,UAAW,OAAmB,OAA8B,UAAW;AAC/E,QAAM,QAAQ,KAAM,IAAK;AAC1B;AAEA,SAAS,eAAgB,OAAmB,UAA6D;AACxG,QAAM,uBAAwB,OAAO,aAAa,WAAW,CAAE,QAAS,IAAI,WACzE,OAAQ,CAAE,OAAQ,CAAC,CAAE,EAAG,EACzB,IAAK,CAAE,OAAQ,cAAM,EAAE,WAAY,EAAa,CAAE;AAEpD,QACE,MAAM,EACN,IAAK,WAAY,EACjB,IAAK,uBAAuB,CAAC,CAAE;AAClC;AAEA,SAAS,OAAQ,OAAmB,UAAmB,UAAkC;AACxF,QAAM,cAAc,MAAM,MAAM,EAAE,IAAK,WAAY,EAAE,OAAO,EAAE,IAAK,SAAU;AAE7E,QAAM,aAAa;AAEnB,aAAY,WAAW,cAAc,YAAa,CAAE,CAAE;AACvD;","names":[]}
package/dist/index.mjs ADDED
@@ -0,0 +1,112 @@
1
+ // src/hooks/use-wp-media-attachment.ts
2
+ import { useQuery } from "@elementor/query";
3
+
4
+ // src/errors.ts
5
+ import { createError } from "@elementor/utils";
6
+ var WpMediaNotAvailableError = createError({
7
+ code: "wp_media_not_available",
8
+ message: "`wp.media` is not available, make sure the `media-model` handle is set in the dependencies array"
9
+ });
10
+
11
+ // src/media.ts
12
+ var wpMediaWindow = window;
13
+ var media_default = () => {
14
+ if (!wpMediaWindow.wp?.media) {
15
+ throw new WpMediaNotAvailableError();
16
+ }
17
+ return wpMediaWindow.wp.media;
18
+ };
19
+
20
+ // src/normalize.ts
21
+ function normalize(attachment) {
22
+ const { filesizeInBytes, filesizeHumanReadable, author, authorName, ...rest } = attachment;
23
+ return {
24
+ ...rest,
25
+ filesize: {
26
+ inBytes: filesizeInBytes,
27
+ humanReadable: filesizeHumanReadable
28
+ },
29
+ author: {
30
+ id: parseInt(author),
31
+ name: authorName
32
+ }
33
+ };
34
+ }
35
+
36
+ // src/hooks/use-wp-media-attachment.ts
37
+ function useWpMediaAttachment(id) {
38
+ return useQuery({
39
+ queryKey: ["wp-attachment", id],
40
+ queryFn: getAttachment,
41
+ enabled: !!id
42
+ });
43
+ }
44
+ async function getAttachment({ queryKey: [, id] }) {
45
+ if (!id) {
46
+ return null;
47
+ }
48
+ const model = media_default().attachment(id);
49
+ const wpAttachment = model.toJSON();
50
+ const isFetched = "url" in wpAttachment;
51
+ if (isFetched) {
52
+ return normalize(wpAttachment);
53
+ }
54
+ try {
55
+ return normalize(await model.fetch());
56
+ } catch (e) {
57
+ return null;
58
+ }
59
+ }
60
+
61
+ // src/hooks/use-wp-media-frame.ts
62
+ import { useEffect, useRef } from "react";
63
+ function useWpMediaFrame(options) {
64
+ const frame = useRef();
65
+ const open = (openOptions = {}) => {
66
+ cleanupFrame();
67
+ frame.current = createFrame({ ...options, ...openOptions });
68
+ frame.current?.open();
69
+ };
70
+ const cleanupFrame = () => {
71
+ frame.current?.detach();
72
+ frame.current?.remove();
73
+ };
74
+ useEffect(() => {
75
+ return () => {
76
+ cleanupFrame();
77
+ };
78
+ }, []);
79
+ return {
80
+ open
81
+ };
82
+ }
83
+ function createFrame({ onSelect, multiple, types, selected, title, mode = "browse" }) {
84
+ const frame = media_default()({
85
+ title,
86
+ multiple,
87
+ library: {
88
+ type: types
89
+ }
90
+ }).on("open", () => {
91
+ applyMode(frame, mode);
92
+ applySelection(frame, selected);
93
+ }).on("close", () => frame.detach()).on("insert select", () => select(frame, multiple, onSelect));
94
+ return frame;
95
+ }
96
+ function applyMode(frame, mode = "browse") {
97
+ frame.content.mode(mode);
98
+ }
99
+ function applySelection(frame, selected) {
100
+ const selectedAttachments = (typeof selected === "number" ? [selected] : selected)?.filter((id) => !!id).map((id) => media_default().attachment(id));
101
+ frame.state().get("selection").set(selectedAttachments || []);
102
+ }
103
+ function select(frame, multiple, onSelect) {
104
+ const attachments = frame.state().get("selection").toJSON().map(normalize);
105
+ const onSelectFn = onSelect;
106
+ onSelectFn(multiple ? attachments : attachments[0]);
107
+ }
108
+ export {
109
+ useWpMediaAttachment,
110
+ useWpMediaFrame
111
+ };
112
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hooks/use-wp-media-attachment.ts","../src/errors.ts","../src/media.ts","../src/normalize.ts","../src/hooks/use-wp-media-frame.ts"],"sourcesContent":["import { useQuery } from '@elementor/query';\nimport media from '../media';\nimport normalize from '../normalize';\n\nexport default function useWpMediaAttachment( id: number | undefined ) {\n\treturn useQuery( {\n\t\tqueryKey: [ 'wp-attachment', id ],\n\t\tqueryFn: getAttachment,\n\t\tenabled: !! id,\n\t} );\n}\n\nasync function getAttachment( { queryKey: [ , id ] }: { queryKey: [ string, number | undefined ] } ) {\n\tif ( ! id ) {\n\t\treturn null;\n\t}\n\n\tconst model = media().attachment( id );\n\tconst wpAttachment = model.toJSON();\n\n\tconst isFetched = 'url' in wpAttachment;\n\n\tif ( isFetched ) {\n\t\treturn normalize( wpAttachment );\n\t}\n\n\ttry {\n\t\treturn normalize( await model.fetch() );\n\t} catch ( e ) {\n\t\treturn null;\n\t}\n}\n","import { createError } from '@elementor/utils';\n\nexport const WpMediaNotAvailableError = createError( {\n\tcode: 'wp_media_not_available',\n\tmessage: '`wp.media` is not available, make sure the `media-model` handle is set in the dependencies array',\n} );\n","import { WpMediaWindow } from './types/wp-media';\nimport { WpMediaNotAvailableError } from './errors';\n\nconst wpMediaWindow = window as unknown as WpMediaWindow;\n\nexport default () => {\n\tif ( ! wpMediaWindow.wp?.media ) {\n\t\tthrow new WpMediaNotAvailableError();\n\t}\n\n\treturn wpMediaWindow.wp.media;\n};\n","import { WpAttachmentJSON } from './types/wp-media';\nimport { Attachment } from './types/attachment';\n\nexport default function normalize( attachment: WpAttachmentJSON ): Attachment {\n\tconst { filesizeInBytes, filesizeHumanReadable, author, authorName, ...rest } = attachment;\n\n\treturn {\n\t\t...rest,\n\t\tfilesize: {\n\t\t\tinBytes: filesizeInBytes,\n\t\t\thumanReadable: filesizeHumanReadable,\n\t\t},\n\t\tauthor: {\n\t\t\tid: parseInt( author ),\n\t\t\tname: authorName,\n\t\t},\n\t};\n}\n","import { useEffect, useRef } from 'react';\nimport normalize from '../normalize';\nimport { MediaFrame } from '../types/wp-media';\nimport { Attachment } from '../types/attachment';\nimport media from '../media';\n\ntype OpenOptions = {\n\tmode?: 'upload' | 'browse';\n};\n\ntype Options = {\n\ttypes: Array< 'image' >;\n\ttitle?: string;\n} & (\n\t| {\n\t\t\tmultiple: true;\n\t\t\tselected: Array< number | undefined >;\n\t\t\tonSelect: ( val: Attachment[] ) => void;\n\t }\n\t| {\n\t\t\tmultiple: false;\n\t\t\tselected: number | undefined;\n\t\t\tonSelect: ( val: Attachment ) => void;\n\t }\n);\n\nexport default function useWpMediaFrame( options: Options ) {\n\tconst frame = useRef< MediaFrame >();\n\n\tconst open = ( openOptions: OpenOptions = {} ) => {\n\t\tcleanupFrame();\n\n\t\tframe.current = createFrame( { ...options, ...openOptions } );\n\n\t\tframe.current?.open();\n\t};\n\n\tconst cleanupFrame = () => {\n\t\tframe.current?.detach();\n\t\tframe.current?.remove();\n\t};\n\n\tuseEffect( () => {\n\t\treturn () => {\n\t\t\tcleanupFrame();\n\t\t};\n\t}, [] );\n\n\treturn {\n\t\topen,\n\t};\n}\n\nfunction createFrame( { onSelect, multiple, types, selected, title, mode = 'browse' }: Options & OpenOptions ) {\n\tconst frame: MediaFrame = media()( {\n\t\ttitle,\n\t\tmultiple,\n\t\tlibrary: {\n\t\t\ttype: types,\n\t\t},\n\t} )\n\t\t.on( 'open', () => {\n\t\t\tapplyMode( frame, mode );\n\t\t\tapplySelection( frame, selected );\n\t\t} )\n\t\t.on( 'close', () => frame.detach() )\n\t\t.on( 'insert select', () => select( frame, multiple, onSelect ) );\n\n\treturn frame;\n}\n\nfunction applyMode( frame: MediaFrame, mode: OpenOptions[ 'mode' ] = 'browse' ) {\n\tframe.content.mode( mode );\n}\n\nfunction applySelection( frame: MediaFrame, selected: number | undefined | Array< number | undefined > ) {\n\tconst selectedAttachments = ( typeof selected === 'number' ? [ selected ] : selected )\n\t\t?.filter( ( id ) => !! id )\n\t\t.map( ( id ) => media().attachment( id as number ) );\n\n\tframe\n\t\t.state()\n\t\t.get( 'selection' )\n\t\t.set( selectedAttachments || [] );\n}\n\nfunction select( frame: MediaFrame, multiple: boolean, onSelect: Options[ 'onSelect' ] ) {\n\tconst attachments = frame.state().get( 'selection' ).toJSON().map( normalize );\n\n\tconst onSelectFn = onSelect as ( val: Attachment | Attachment[] ) => void;\n\n\tonSelectFn( multiple ? attachments : attachments[ 0 ] );\n}\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@elementor/wp-media",
3
+ "description": "An adapter for WordPress' media utils",
4
+ "version": "0.1.0",
5
+ "private": false,
6
+ "author": "Elementor Team",
7
+ "homepage": "https://elementor.com/",
8
+ "license": "GPL-3.0-or-later",
9
+ "main": "dist/index.js",
10
+ "module": "dist/index.mjs",
11
+ "types": "dist/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "import": "./dist/index.mjs",
15
+ "require": "./dist/index.js",
16
+ "types": "./dist/index.d.ts"
17
+ },
18
+ "./package.json": "./package.json"
19
+ },
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/elementor/elementor-packages.git",
23
+ "directory": "packages/libs/wp-media"
24
+ },
25
+ "bugs": {
26
+ "url": "https://github.com/elementor/elementor-packages/issues"
27
+ },
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
31
+ "files": [
32
+ "README.md",
33
+ "CHANGELOG.md",
34
+ "/dist",
35
+ "/src",
36
+ "!**/__tests__"
37
+ ],
38
+ "scripts": {
39
+ "build": "tsup --config=../../tsup.build.ts",
40
+ "dev": "tsup --config=../../tsup.dev.ts"
41
+ },
42
+ "dependencies": {
43
+ "@elementor/query": "^0.2.2",
44
+ "@elementor/utils": "^0.2.1"
45
+ },
46
+ "peerDependencies": {
47
+ "react": "^18.3.1"
48
+ },
49
+ "gitHead": "a3d9694582a79d4a5ab51276030a24cf3736dca9"
50
+ }
package/src/errors.ts ADDED
@@ -0,0 +1,6 @@
1
+ import { createError } from '@elementor/utils';
2
+
3
+ export const WpMediaNotAvailableError = createError( {
4
+ code: 'wp_media_not_available',
5
+ message: '`wp.media` is not available, make sure the `media-model` handle is set in the dependencies array',
6
+ } );
@@ -0,0 +1,32 @@
1
+ import { useQuery } from '@elementor/query';
2
+ import media from '../media';
3
+ import normalize from '../normalize';
4
+
5
+ export default function useWpMediaAttachment( id: number | undefined ) {
6
+ return useQuery( {
7
+ queryKey: [ 'wp-attachment', id ],
8
+ queryFn: getAttachment,
9
+ enabled: !! id,
10
+ } );
11
+ }
12
+
13
+ async function getAttachment( { queryKey: [ , id ] }: { queryKey: [ string, number | undefined ] } ) {
14
+ if ( ! id ) {
15
+ return null;
16
+ }
17
+
18
+ const model = media().attachment( id );
19
+ const wpAttachment = model.toJSON();
20
+
21
+ const isFetched = 'url' in wpAttachment;
22
+
23
+ if ( isFetched ) {
24
+ return normalize( wpAttachment );
25
+ }
26
+
27
+ try {
28
+ return normalize( await model.fetch() );
29
+ } catch ( e ) {
30
+ return null;
31
+ }
32
+ }
@@ -0,0 +1,93 @@
1
+ import { useEffect, useRef } from 'react';
2
+ import normalize from '../normalize';
3
+ import { MediaFrame } from '../types/wp-media';
4
+ import { Attachment } from '../types/attachment';
5
+ import media from '../media';
6
+
7
+ type OpenOptions = {
8
+ mode?: 'upload' | 'browse';
9
+ };
10
+
11
+ type Options = {
12
+ types: Array< 'image' >;
13
+ title?: string;
14
+ } & (
15
+ | {
16
+ multiple: true;
17
+ selected: Array< number | undefined >;
18
+ onSelect: ( val: Attachment[] ) => void;
19
+ }
20
+ | {
21
+ multiple: false;
22
+ selected: number | undefined;
23
+ onSelect: ( val: Attachment ) => void;
24
+ }
25
+ );
26
+
27
+ export default function useWpMediaFrame( options: Options ) {
28
+ const frame = useRef< MediaFrame >();
29
+
30
+ const open = ( openOptions: OpenOptions = {} ) => {
31
+ cleanupFrame();
32
+
33
+ frame.current = createFrame( { ...options, ...openOptions } );
34
+
35
+ frame.current?.open();
36
+ };
37
+
38
+ const cleanupFrame = () => {
39
+ frame.current?.detach();
40
+ frame.current?.remove();
41
+ };
42
+
43
+ useEffect( () => {
44
+ return () => {
45
+ cleanupFrame();
46
+ };
47
+ }, [] );
48
+
49
+ return {
50
+ open,
51
+ };
52
+ }
53
+
54
+ function createFrame( { onSelect, multiple, types, selected, title, mode = 'browse' }: Options & OpenOptions ) {
55
+ const frame: MediaFrame = media()( {
56
+ title,
57
+ multiple,
58
+ library: {
59
+ type: types,
60
+ },
61
+ } )
62
+ .on( 'open', () => {
63
+ applyMode( frame, mode );
64
+ applySelection( frame, selected );
65
+ } )
66
+ .on( 'close', () => frame.detach() )
67
+ .on( 'insert select', () => select( frame, multiple, onSelect ) );
68
+
69
+ return frame;
70
+ }
71
+
72
+ function applyMode( frame: MediaFrame, mode: OpenOptions[ 'mode' ] = 'browse' ) {
73
+ frame.content.mode( mode );
74
+ }
75
+
76
+ function applySelection( frame: MediaFrame, selected: number | undefined | Array< number | undefined > ) {
77
+ const selectedAttachments = ( typeof selected === 'number' ? [ selected ] : selected )
78
+ ?.filter( ( id ) => !! id )
79
+ .map( ( id ) => media().attachment( id as number ) );
80
+
81
+ frame
82
+ .state()
83
+ .get( 'selection' )
84
+ .set( selectedAttachments || [] );
85
+ }
86
+
87
+ function select( frame: MediaFrame, multiple: boolean, onSelect: Options[ 'onSelect' ] ) {
88
+ const attachments = frame.state().get( 'selection' ).toJSON().map( normalize );
89
+
90
+ const onSelectFn = onSelect as ( val: Attachment | Attachment[] ) => void;
91
+
92
+ onSelectFn( multiple ? attachments : attachments[ 0 ] );
93
+ }
package/src/index.ts ADDED
@@ -0,0 +1,4 @@
1
+ export type { Attachment } from './types/attachment';
2
+
3
+ export { default as useWpMediaAttachment } from './hooks/use-wp-media-attachment';
4
+ export { default as useWpMediaFrame } from './hooks/use-wp-media-frame';
package/src/media.ts ADDED
@@ -0,0 +1,12 @@
1
+ import { WpMediaWindow } from './types/wp-media';
2
+ import { WpMediaNotAvailableError } from './errors';
3
+
4
+ const wpMediaWindow = window as unknown as WpMediaWindow;
5
+
6
+ export default () => {
7
+ if ( ! wpMediaWindow.wp?.media ) {
8
+ throw new WpMediaNotAvailableError();
9
+ }
10
+
11
+ return wpMediaWindow.wp.media;
12
+ };
@@ -0,0 +1,18 @@
1
+ import { WpAttachmentJSON } from './types/wp-media';
2
+ import { Attachment } from './types/attachment';
3
+
4
+ export default function normalize( attachment: WpAttachmentJSON ): Attachment {
5
+ const { filesizeInBytes, filesizeHumanReadable, author, authorName, ...rest } = attachment;
6
+
7
+ return {
8
+ ...rest,
9
+ filesize: {
10
+ inBytes: filesizeInBytes,
11
+ humanReadable: filesizeHumanReadable,
12
+ },
13
+ author: {
14
+ id: parseInt( author ),
15
+ name: authorName,
16
+ },
17
+ };
18
+ }
@@ -0,0 +1,27 @@
1
+ export type Attachment = {
2
+ id: number;
3
+ url: string;
4
+ alt: string;
5
+ filename: string;
6
+ title: string;
7
+ mime: string;
8
+ type: string;
9
+ subtype: string;
10
+ uploadedTo: number;
11
+ filesize: {
12
+ inBytes: number;
13
+ humanReadable: string;
14
+ };
15
+ author: {
16
+ id: number;
17
+ name: string;
18
+ };
19
+ sizes: Record<
20
+ string,
21
+ {
22
+ width: number;
23
+ height: number;
24
+ url: string;
25
+ }
26
+ >;
27
+ };