@elementor/menus 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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ # @elementor/menus
2
+
3
+ ## 0.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 66df921: Extract menus logic into a dedicated package
package/README.md ADDED
@@ -0,0 +1,5 @@
1
+ # Menus
2
+
3
+ > [!WARNING]
4
+ > Please refrain from accessing or depending on functions and variables starting with double underscores, as they are subject to change without notice.
5
+ > Naming convention involving double underscores (`__`) as a prefix to indicate that a function or variable is meant for internal use and should not be accessed or relied upon by third-party developers.
@@ -0,0 +1,42 @@
1
+ import { ComponentType, ComponentPropsWithoutRef } from 'react';
2
+
3
+ type Components = Record<string, ComponentType<any>>;
4
+ type MenuGroups<TGroups extends string> = TGroups | 'default';
5
+
6
+ type UseMenuItems<TGroups extends string> = () => GroupedMenuItems<TGroups>;
7
+ type GroupedMenuItems<TGroups extends string> = Record<MenuGroups<TGroups>, Array<{
8
+ id: string;
9
+ MenuItem: ComponentType;
10
+ }>>;
11
+
12
+ type RegisterItem<TGroups extends string, TComponent extends ComponentType> = (args: {
13
+ id: string;
14
+ group?: MenuGroups<TGroups>;
15
+ priority?: number;
16
+ overwrite?: boolean;
17
+ } & Props<ComponentPropsWithoutRef<TComponent>>) => void;
18
+ type Props<TProps extends object> = unknown extends TProps ? NoProps : PropsOrUseProps<TProps>;
19
+ type NoProps = {
20
+ props?: never;
21
+ useProps?: never;
22
+ };
23
+ type PropsOrUseProps<TProps extends object> = {
24
+ props: TProps;
25
+ useProps?: never;
26
+ } | {
27
+ useProps: () => TProps;
28
+ props?: never;
29
+ };
30
+
31
+ type Menu<TComponents extends Components, TGroups extends string> = {
32
+ useMenuItems: UseMenuItems<TGroups>;
33
+ } & RegisterFns<TGroups, TComponents>;
34
+ declare function createMenu<TComponents extends Components, TGroups extends string = 'default'>({ groups, components, }: {
35
+ groups?: TGroups[];
36
+ components: TComponents;
37
+ }): Menu<TComponents, TGroups>;
38
+ type RegisterFns<TGroups extends string, TComponents extends Components> = {
39
+ [K in keyof TComponents as `register${Capitalize<K & string>}`]: RegisterItem<TGroups, TComponents[K]>;
40
+ };
41
+
42
+ export { type Components, type Menu, createMenu };
@@ -0,0 +1,42 @@
1
+ import { ComponentType, ComponentPropsWithoutRef } from 'react';
2
+
3
+ type Components = Record<string, ComponentType<any>>;
4
+ type MenuGroups<TGroups extends string> = TGroups | 'default';
5
+
6
+ type UseMenuItems<TGroups extends string> = () => GroupedMenuItems<TGroups>;
7
+ type GroupedMenuItems<TGroups extends string> = Record<MenuGroups<TGroups>, Array<{
8
+ id: string;
9
+ MenuItem: ComponentType;
10
+ }>>;
11
+
12
+ type RegisterItem<TGroups extends string, TComponent extends ComponentType> = (args: {
13
+ id: string;
14
+ group?: MenuGroups<TGroups>;
15
+ priority?: number;
16
+ overwrite?: boolean;
17
+ } & Props<ComponentPropsWithoutRef<TComponent>>) => void;
18
+ type Props<TProps extends object> = unknown extends TProps ? NoProps : PropsOrUseProps<TProps>;
19
+ type NoProps = {
20
+ props?: never;
21
+ useProps?: never;
22
+ };
23
+ type PropsOrUseProps<TProps extends object> = {
24
+ props: TProps;
25
+ useProps?: never;
26
+ } | {
27
+ useProps: () => TProps;
28
+ props?: never;
29
+ };
30
+
31
+ type Menu<TComponents extends Components, TGroups extends string> = {
32
+ useMenuItems: UseMenuItems<TGroups>;
33
+ } & RegisterFns<TGroups, TComponents>;
34
+ declare function createMenu<TComponents extends Components, TGroups extends string = 'default'>({ groups, components, }: {
35
+ groups?: TGroups[];
36
+ components: TComponents;
37
+ }): Menu<TComponents, TGroups>;
38
+ type RegisterFns<TGroups extends string, TComponents extends Components> = {
39
+ [K in keyof TComponents as `register${Capitalize<K & string>}`]: RegisterItem<TGroups, TComponents[K]>;
40
+ };
41
+
42
+ export { type Components, type Menu, createMenu };
package/dist/index.js ADDED
@@ -0,0 +1,121 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var src_exports = {};
32
+ __export(src_exports, {
33
+ createMenu: () => createMenu
34
+ });
35
+ module.exports = __toCommonJS(src_exports);
36
+
37
+ // src/create-menu.ts
38
+ var import_locations = require("@elementor/locations");
39
+
40
+ // src/create-use-menu-items.ts
41
+ var import_react = require("react");
42
+ function createUseMenuItems(locations) {
43
+ return () => {
44
+ return (0, import_react.useMemo)(() => {
45
+ return Object.entries(locations).reduce((carry, [groupName, location]) => {
46
+ const items = location.getInjections().map((injection) => ({
47
+ id: injection.id,
48
+ MenuItem: injection.component
49
+ }));
50
+ return {
51
+ ...carry,
52
+ [groupName]: items
53
+ };
54
+ }, {});
55
+ }, []);
56
+ };
57
+ }
58
+
59
+ // src/create-register-item.tsx
60
+ var React = __toESM(require("react"));
61
+ function createRegisterItem(locations, component) {
62
+ return ({ id, group = "default", priority = 10, overwrite = false, props: _props, useProps: _useProps }) => {
63
+ if (!(group in locations)) {
64
+ return;
65
+ }
66
+ const Component = component;
67
+ const useProps = _useProps || (() => _props);
68
+ const InjectedComponent = () => {
69
+ const props = useProps();
70
+ return /* @__PURE__ */ React.createElement(Component, { ...props });
71
+ };
72
+ locations[group].inject({
73
+ id,
74
+ component: InjectedComponent,
75
+ options: {
76
+ priority,
77
+ overwrite
78
+ }
79
+ });
80
+ };
81
+ }
82
+
83
+ // src/create-menu.ts
84
+ function createMenu({
85
+ groups = [],
86
+ components
87
+ }) {
88
+ const locations = createLocations([...groups, "default"]);
89
+ const registerFns = createRegisterFns(locations, components);
90
+ const useMenuItems = createUseMenuItems(locations);
91
+ return {
92
+ useMenuItems,
93
+ ...registerFns
94
+ };
95
+ }
96
+ function createLocations(groups) {
97
+ return groups.reduce((acc, group) => {
98
+ acc[group] = (0, import_locations.createLocation)();
99
+ return acc;
100
+ }, {});
101
+ }
102
+ function createRegisterFns(locations, components) {
103
+ return Object.entries(components).reduce(
104
+ (acc, [key, component]) => {
105
+ const name = `register${capitalize(key)}`;
106
+ return {
107
+ ...acc,
108
+ [name]: createRegisterItem(locations, component)
109
+ };
110
+ },
111
+ {}
112
+ );
113
+ }
114
+ function capitalize(str) {
115
+ return str.charAt(0).toUpperCase() + str.slice(1);
116
+ }
117
+ // Annotate the CommonJS export names for ESM import in node:
118
+ 0 && (module.exports = {
119
+ createMenu
120
+ });
121
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/create-menu.ts","../src/create-use-menu-items.ts","../src/create-register-item.tsx"],"sourcesContent":["export { createMenu, type Menu } from './create-menu';\nexport { type Components } from './types';\n","import { createLocation } from '@elementor/locations';\nimport { Components, LocationsMap, MenuGroups } from './types';\nimport { createUseMenuItems, UseMenuItems } from './create-use-menu-items';\nimport { createRegisterItem, RegisterItem } from './create-register-item';\n\nexport type Menu< TComponents extends Components, TGroups extends string > = {\n\tuseMenuItems: UseMenuItems< TGroups >;\n} & RegisterFns< TGroups, TComponents >;\n\nexport function createMenu< TComponents extends Components, TGroups extends string = 'default' >( {\n\tgroups = [],\n\tcomponents,\n}: {\n\tgroups?: TGroups[];\n\tcomponents: TComponents;\n} ): Menu< TComponents, TGroups > {\n\tconst locations = createLocations< MenuGroups< TGroups > >( [ ...groups, 'default' ] );\n\n\tconst registerFns = createRegisterFns( locations, components );\n\tconst useMenuItems = createUseMenuItems( locations );\n\n\treturn {\n\t\tuseMenuItems,\n\t\t...registerFns,\n\t};\n}\n\nfunction createLocations< TGroups extends string >( groups: TGroups[] ) {\n\treturn groups.reduce( ( acc, group ) => {\n\t\tacc[ group ] = createLocation();\n\n\t\treturn acc;\n\t}, {} as LocationsMap< TGroups > );\n}\n\ntype RegisterFns< TGroups extends string, TComponents extends Components > = {\n\t[ K in keyof TComponents as `register${ Capitalize< K & string > }` ]: RegisterItem< TGroups, TComponents[ K ] >;\n};\n\nfunction createRegisterFns< TGroups extends string, TComponents extends Components >(\n\tlocations: LocationsMap< MenuGroups< TGroups > >,\n\tcomponents: TComponents\n) {\n\treturn Object.entries( components ).reduce(\n\t\t( acc, [ key, component ] ) => {\n\t\t\tconst name = `register${ capitalize( key ) }`;\n\n\t\t\treturn {\n\t\t\t\t...acc,\n\t\t\t\t[ name ]: createRegisterItem( locations, component ),\n\t\t\t};\n\t\t},\n\t\t{} as RegisterFns< TGroups, TComponents >\n\t);\n}\n\nfunction capitalize( str: string ) {\n\treturn str.charAt( 0 ).toUpperCase() + str.slice( 1 );\n}\n","import { ComponentType, useMemo } from 'react';\nimport { LocationsMap, MenuGroups } from './types';\n\nexport type UseMenuItems< TGroups extends string > = () => GroupedMenuItems< TGroups >;\n\ntype GroupedMenuItems< TGroups extends string > = Record<\n\tMenuGroups< TGroups >,\n\tArray< {\n\t\tid: string;\n\t\tMenuItem: ComponentType;\n\t} >\n>;\n\nexport function createUseMenuItems< TGroups extends string >(\n\tlocations: LocationsMap< MenuGroups< TGroups > >\n): UseMenuItems< TGroups > {\n\treturn () => {\n\t\t// Normalize the injections groups to an object with the groups as keys.\n\t\treturn useMemo( () => {\n\t\t\treturn Object.entries( locations ).reduce( ( carry, [ groupName, location ] ) => {\n\t\t\t\tconst items = location.getInjections().map( ( injection ) => ( {\n\t\t\t\t\tid: injection.id,\n\t\t\t\t\tMenuItem: injection.component,\n\t\t\t\t} ) );\n\n\t\t\t\treturn {\n\t\t\t\t\t...carry,\n\t\t\t\t\t[ groupName ]: items,\n\t\t\t\t};\n\t\t\t}, {} as GroupedMenuItems< TGroups > );\n\t\t}, [] );\n\t};\n}\n","import * as React from 'react';\nimport { ComponentPropsWithoutRef, ComponentType } from 'react';\nimport { LocationsMap, MenuGroups } from './types';\n\nexport type RegisterItem< TGroups extends string, TComponent extends ComponentType > = (\n\targs: {\n\t\tid: string;\n\t\tgroup?: MenuGroups< TGroups >;\n\t\tpriority?: number;\n\t\toverwrite?: boolean;\n\t} & Props< ComponentPropsWithoutRef< TComponent > >\n) => void;\n\ntype Props< TProps extends object > = unknown extends TProps ? NoProps : PropsOrUseProps< TProps >;\n\ntype NoProps = { props?: never; useProps?: never };\n\ntype PropsOrUseProps< TProps extends object > =\n\t| { props: TProps; useProps?: never }\n\t| {\n\t\t\tuseProps: () => TProps;\n\t\t\tprops?: never;\n\t };\n\nexport function createRegisterItem< TGroups extends string, TComponent extends ComponentType >(\n\tlocations: LocationsMap< MenuGroups< TGroups > >,\n\tcomponent: TComponent\n): RegisterItem< TGroups, TComponent > {\n\treturn ( { id, group = 'default', priority = 10, overwrite = false, props: _props, useProps: _useProps } ) => {\n\t\tif ( ! ( group in locations ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst Component = component as ComponentType;\n\t\tconst useProps = _useProps || ( () => _props );\n\n\t\tconst InjectedComponent = () => {\n\t\t\tconst props = useProps();\n\n\t\t\treturn <Component { ...props } />;\n\t\t};\n\n\t\tlocations[ group ].inject( {\n\t\t\tid,\n\t\t\tcomponent: InjectedComponent,\n\t\t\toptions: {\n\t\t\t\tpriority,\n\t\t\t\toverwrite,\n\t\t\t},\n\t\t} );\n\t};\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,uBAA+B;;;ACA/B,mBAAuC;AAahC,SAAS,mBACf,WAC0B;AAC1B,SAAO,MAAM;AAEZ,eAAO,sBAAS,MAAM;AACrB,aAAO,OAAO,QAAS,SAAU,EAAE,OAAQ,CAAE,OAAO,CAAE,WAAW,QAAS,MAAO;AAChF,cAAM,QAAQ,SAAS,cAAc,EAAE,IAAK,CAAE,eAAiB;AAAA,UAC9D,IAAI,UAAU;AAAA,UACd,UAAU,UAAU;AAAA,QACrB,EAAI;AAEJ,eAAO;AAAA,UACN,GAAG;AAAA,UACH,CAAE,SAAU,GAAG;AAAA,QAChB;AAAA,MACD,GAAG,CAAC,CAAiC;AAAA,IACtC,GAAG,CAAC,CAAE;AAAA,EACP;AACD;;;AChCA,YAAuB;AAwBhB,SAAS,mBACf,WACA,WACsC;AACtC,SAAO,CAAE,EAAE,IAAI,QAAQ,WAAW,WAAW,IAAI,YAAY,OAAO,OAAO,QAAQ,UAAU,UAAU,MAAO;AAC7G,QAAK,EAAI,SAAS,YAAc;AAC/B;AAAA,IACD;AAEA,UAAM,YAAY;AAClB,UAAM,WAAW,cAAe,MAAM;AAEtC,UAAM,oBAAoB,MAAM;AAC/B,YAAM,QAAQ,SAAS;AAEvB,aAAO,oCAAC,aAAY,GAAG,OAAQ;AAAA,IAChC;AAEA,cAAW,KAAM,EAAE,OAAQ;AAAA,MAC1B;AAAA,MACA,WAAW;AAAA,MACX,SAAS;AAAA,QACR;AAAA,QACA;AAAA,MACD;AAAA,IACD,CAAE;AAAA,EACH;AACD;;;AF1CO,SAAS,WAAkF;AAAA,EACjG,SAAS,CAAC;AAAA,EACV;AACD,GAGkC;AACjC,QAAM,YAAY,gBAA0C,CAAE,GAAG,QAAQ,SAAU,CAAE;AAErF,QAAM,cAAc,kBAAmB,WAAW,UAAW;AAC7D,QAAM,eAAe,mBAAoB,SAAU;AAEnD,SAAO;AAAA,IACN;AAAA,IACA,GAAG;AAAA,EACJ;AACD;AAEA,SAAS,gBAA2C,QAAoB;AACvE,SAAO,OAAO,OAAQ,CAAE,KAAK,UAAW;AACvC,QAAK,KAAM,QAAI,iCAAe;AAE9B,WAAO;AAAA,EACR,GAAG,CAAC,CAA6B;AAClC;AAMA,SAAS,kBACR,WACA,YACC;AACD,SAAO,OAAO,QAAS,UAAW,EAAE;AAAA,IACnC,CAAE,KAAK,CAAE,KAAK,SAAU,MAAO;AAC9B,YAAM,OAAO,WAAY,WAAY,GAAI,CAAE;AAE3C,aAAO;AAAA,QACN,GAAG;AAAA,QACH,CAAE,IAAK,GAAG,mBAAoB,WAAW,SAAU;AAAA,MACpD;AAAA,IACD;AAAA,IACA,CAAC;AAAA,EACF;AACD;AAEA,SAAS,WAAY,KAAc;AAClC,SAAO,IAAI,OAAQ,CAAE,EAAE,YAAY,IAAI,IAAI,MAAO,CAAE;AACrD;","names":[]}
package/dist/index.mjs ADDED
@@ -0,0 +1,84 @@
1
+ // src/create-menu.ts
2
+ import { createLocation } from "@elementor/locations";
3
+
4
+ // src/create-use-menu-items.ts
5
+ import { useMemo } from "react";
6
+ function createUseMenuItems(locations) {
7
+ return () => {
8
+ return useMemo(() => {
9
+ return Object.entries(locations).reduce((carry, [groupName, location]) => {
10
+ const items = location.getInjections().map((injection) => ({
11
+ id: injection.id,
12
+ MenuItem: injection.component
13
+ }));
14
+ return {
15
+ ...carry,
16
+ [groupName]: items
17
+ };
18
+ }, {});
19
+ }, []);
20
+ };
21
+ }
22
+
23
+ // src/create-register-item.tsx
24
+ import * as React from "react";
25
+ function createRegisterItem(locations, component) {
26
+ return ({ id, group = "default", priority = 10, overwrite = false, props: _props, useProps: _useProps }) => {
27
+ if (!(group in locations)) {
28
+ return;
29
+ }
30
+ const Component = component;
31
+ const useProps = _useProps || (() => _props);
32
+ const InjectedComponent = () => {
33
+ const props = useProps();
34
+ return /* @__PURE__ */ React.createElement(Component, { ...props });
35
+ };
36
+ locations[group].inject({
37
+ id,
38
+ component: InjectedComponent,
39
+ options: {
40
+ priority,
41
+ overwrite
42
+ }
43
+ });
44
+ };
45
+ }
46
+
47
+ // src/create-menu.ts
48
+ function createMenu({
49
+ groups = [],
50
+ components
51
+ }) {
52
+ const locations = createLocations([...groups, "default"]);
53
+ const registerFns = createRegisterFns(locations, components);
54
+ const useMenuItems = createUseMenuItems(locations);
55
+ return {
56
+ useMenuItems,
57
+ ...registerFns
58
+ };
59
+ }
60
+ function createLocations(groups) {
61
+ return groups.reduce((acc, group) => {
62
+ acc[group] = createLocation();
63
+ return acc;
64
+ }, {});
65
+ }
66
+ function createRegisterFns(locations, components) {
67
+ return Object.entries(components).reduce(
68
+ (acc, [key, component]) => {
69
+ const name = `register${capitalize(key)}`;
70
+ return {
71
+ ...acc,
72
+ [name]: createRegisterItem(locations, component)
73
+ };
74
+ },
75
+ {}
76
+ );
77
+ }
78
+ function capitalize(str) {
79
+ return str.charAt(0).toUpperCase() + str.slice(1);
80
+ }
81
+ export {
82
+ createMenu
83
+ };
84
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/create-menu.ts","../src/create-use-menu-items.ts","../src/create-register-item.tsx"],"sourcesContent":["import { createLocation } from '@elementor/locations';\nimport { Components, LocationsMap, MenuGroups } from './types';\nimport { createUseMenuItems, UseMenuItems } from './create-use-menu-items';\nimport { createRegisterItem, RegisterItem } from './create-register-item';\n\nexport type Menu< TComponents extends Components, TGroups extends string > = {\n\tuseMenuItems: UseMenuItems< TGroups >;\n} & RegisterFns< TGroups, TComponents >;\n\nexport function createMenu< TComponents extends Components, TGroups extends string = 'default' >( {\n\tgroups = [],\n\tcomponents,\n}: {\n\tgroups?: TGroups[];\n\tcomponents: TComponents;\n} ): Menu< TComponents, TGroups > {\n\tconst locations = createLocations< MenuGroups< TGroups > >( [ ...groups, 'default' ] );\n\n\tconst registerFns = createRegisterFns( locations, components );\n\tconst useMenuItems = createUseMenuItems( locations );\n\n\treturn {\n\t\tuseMenuItems,\n\t\t...registerFns,\n\t};\n}\n\nfunction createLocations< TGroups extends string >( groups: TGroups[] ) {\n\treturn groups.reduce( ( acc, group ) => {\n\t\tacc[ group ] = createLocation();\n\n\t\treturn acc;\n\t}, {} as LocationsMap< TGroups > );\n}\n\ntype RegisterFns< TGroups extends string, TComponents extends Components > = {\n\t[ K in keyof TComponents as `register${ Capitalize< K & string > }` ]: RegisterItem< TGroups, TComponents[ K ] >;\n};\n\nfunction createRegisterFns< TGroups extends string, TComponents extends Components >(\n\tlocations: LocationsMap< MenuGroups< TGroups > >,\n\tcomponents: TComponents\n) {\n\treturn Object.entries( components ).reduce(\n\t\t( acc, [ key, component ] ) => {\n\t\t\tconst name = `register${ capitalize( key ) }`;\n\n\t\t\treturn {\n\t\t\t\t...acc,\n\t\t\t\t[ name ]: createRegisterItem( locations, component ),\n\t\t\t};\n\t\t},\n\t\t{} as RegisterFns< TGroups, TComponents >\n\t);\n}\n\nfunction capitalize( str: string ) {\n\treturn str.charAt( 0 ).toUpperCase() + str.slice( 1 );\n}\n","import { ComponentType, useMemo } from 'react';\nimport { LocationsMap, MenuGroups } from './types';\n\nexport type UseMenuItems< TGroups extends string > = () => GroupedMenuItems< TGroups >;\n\ntype GroupedMenuItems< TGroups extends string > = Record<\n\tMenuGroups< TGroups >,\n\tArray< {\n\t\tid: string;\n\t\tMenuItem: ComponentType;\n\t} >\n>;\n\nexport function createUseMenuItems< TGroups extends string >(\n\tlocations: LocationsMap< MenuGroups< TGroups > >\n): UseMenuItems< TGroups > {\n\treturn () => {\n\t\t// Normalize the injections groups to an object with the groups as keys.\n\t\treturn useMemo( () => {\n\t\t\treturn Object.entries( locations ).reduce( ( carry, [ groupName, location ] ) => {\n\t\t\t\tconst items = location.getInjections().map( ( injection ) => ( {\n\t\t\t\t\tid: injection.id,\n\t\t\t\t\tMenuItem: injection.component,\n\t\t\t\t} ) );\n\n\t\t\t\treturn {\n\t\t\t\t\t...carry,\n\t\t\t\t\t[ groupName ]: items,\n\t\t\t\t};\n\t\t\t}, {} as GroupedMenuItems< TGroups > );\n\t\t}, [] );\n\t};\n}\n","import * as React from 'react';\nimport { ComponentPropsWithoutRef, ComponentType } from 'react';\nimport { LocationsMap, MenuGroups } from './types';\n\nexport type RegisterItem< TGroups extends string, TComponent extends ComponentType > = (\n\targs: {\n\t\tid: string;\n\t\tgroup?: MenuGroups< TGroups >;\n\t\tpriority?: number;\n\t\toverwrite?: boolean;\n\t} & Props< ComponentPropsWithoutRef< TComponent > >\n) => void;\n\ntype Props< TProps extends object > = unknown extends TProps ? NoProps : PropsOrUseProps< TProps >;\n\ntype NoProps = { props?: never; useProps?: never };\n\ntype PropsOrUseProps< TProps extends object > =\n\t| { props: TProps; useProps?: never }\n\t| {\n\t\t\tuseProps: () => TProps;\n\t\t\tprops?: never;\n\t };\n\nexport function createRegisterItem< TGroups extends string, TComponent extends ComponentType >(\n\tlocations: LocationsMap< MenuGroups< TGroups > >,\n\tcomponent: TComponent\n): RegisterItem< TGroups, TComponent > {\n\treturn ( { id, group = 'default', priority = 10, overwrite = false, props: _props, useProps: _useProps } ) => {\n\t\tif ( ! ( group in locations ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst Component = component as ComponentType;\n\t\tconst useProps = _useProps || ( () => _props );\n\n\t\tconst InjectedComponent = () => {\n\t\t\tconst props = useProps();\n\n\t\t\treturn <Component { ...props } />;\n\t\t};\n\n\t\tlocations[ group ].inject( {\n\t\t\tid,\n\t\t\tcomponent: InjectedComponent,\n\t\t\toptions: {\n\t\t\t\tpriority,\n\t\t\t\toverwrite,\n\t\t\t},\n\t\t} );\n\t};\n}\n"],"mappings":";AAAA,SAAS,sBAAsB;;;ACA/B,SAAwB,eAAe;AAahC,SAAS,mBACf,WAC0B;AAC1B,SAAO,MAAM;AAEZ,WAAO,QAAS,MAAM;AACrB,aAAO,OAAO,QAAS,SAAU,EAAE,OAAQ,CAAE,OAAO,CAAE,WAAW,QAAS,MAAO;AAChF,cAAM,QAAQ,SAAS,cAAc,EAAE,IAAK,CAAE,eAAiB;AAAA,UAC9D,IAAI,UAAU;AAAA,UACd,UAAU,UAAU;AAAA,QACrB,EAAI;AAEJ,eAAO;AAAA,UACN,GAAG;AAAA,UACH,CAAE,SAAU,GAAG;AAAA,QAChB;AAAA,MACD,GAAG,CAAC,CAAiC;AAAA,IACtC,GAAG,CAAC,CAAE;AAAA,EACP;AACD;;;AChCA,YAAY,WAAW;AAwBhB,SAAS,mBACf,WACA,WACsC;AACtC,SAAO,CAAE,EAAE,IAAI,QAAQ,WAAW,WAAW,IAAI,YAAY,OAAO,OAAO,QAAQ,UAAU,UAAU,MAAO;AAC7G,QAAK,EAAI,SAAS,YAAc;AAC/B;AAAA,IACD;AAEA,UAAM,YAAY;AAClB,UAAM,WAAW,cAAe,MAAM;AAEtC,UAAM,oBAAoB,MAAM;AAC/B,YAAM,QAAQ,SAAS;AAEvB,aAAO,oCAAC,aAAY,GAAG,OAAQ;AAAA,IAChC;AAEA,cAAW,KAAM,EAAE,OAAQ;AAAA,MAC1B;AAAA,MACA,WAAW;AAAA,MACX,SAAS;AAAA,QACR;AAAA,QACA;AAAA,MACD;AAAA,IACD,CAAE;AAAA,EACH;AACD;;;AF1CO,SAAS,WAAkF;AAAA,EACjG,SAAS,CAAC;AAAA,EACV;AACD,GAGkC;AACjC,QAAM,YAAY,gBAA0C,CAAE,GAAG,QAAQ,SAAU,CAAE;AAErF,QAAM,cAAc,kBAAmB,WAAW,UAAW;AAC7D,QAAM,eAAe,mBAAoB,SAAU;AAEnD,SAAO;AAAA,IACN;AAAA,IACA,GAAG;AAAA,EACJ;AACD;AAEA,SAAS,gBAA2C,QAAoB;AACvE,SAAO,OAAO,OAAQ,CAAE,KAAK,UAAW;AACvC,QAAK,KAAM,IAAI,eAAe;AAE9B,WAAO;AAAA,EACR,GAAG,CAAC,CAA6B;AAClC;AAMA,SAAS,kBACR,WACA,YACC;AACD,SAAO,OAAO,QAAS,UAAW,EAAE;AAAA,IACnC,CAAE,KAAK,CAAE,KAAK,SAAU,MAAO;AAC9B,YAAM,OAAO,WAAY,WAAY,GAAI,CAAE;AAE3C,aAAO;AAAA,QACN,GAAG;AAAA,QACH,CAAE,IAAK,GAAG,mBAAoB,WAAW,SAAU;AAAA,MACpD;AAAA,IACD;AAAA,IACA,CAAC;AAAA,EACF;AACD;AAEA,SAAS,WAAY,KAAc;AAClC,SAAO,IAAI,OAAQ,CAAE,EAAE,YAAY,IAAI,IAAI,MAAO,CAAE;AACrD;","names":[]}
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@elementor/menus",
3
+ "description": "Add a menus registration mechanism for you React application",
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/menus"
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/locations": "^0.7.5"
44
+ },
45
+ "peerDependencies": {
46
+ "react": "^18.3.1"
47
+ }
48
+ }
@@ -0,0 +1,59 @@
1
+ import { createLocation } from '@elementor/locations';
2
+ import { Components, LocationsMap, MenuGroups } from './types';
3
+ import { createUseMenuItems, UseMenuItems } from './create-use-menu-items';
4
+ import { createRegisterItem, RegisterItem } from './create-register-item';
5
+
6
+ export type Menu< TComponents extends Components, TGroups extends string > = {
7
+ useMenuItems: UseMenuItems< TGroups >;
8
+ } & RegisterFns< TGroups, TComponents >;
9
+
10
+ export function createMenu< TComponents extends Components, TGroups extends string = 'default' >( {
11
+ groups = [],
12
+ components,
13
+ }: {
14
+ groups?: TGroups[];
15
+ components: TComponents;
16
+ } ): Menu< TComponents, TGroups > {
17
+ const locations = createLocations< MenuGroups< TGroups > >( [ ...groups, 'default' ] );
18
+
19
+ const registerFns = createRegisterFns( locations, components );
20
+ const useMenuItems = createUseMenuItems( locations );
21
+
22
+ return {
23
+ useMenuItems,
24
+ ...registerFns,
25
+ };
26
+ }
27
+
28
+ function createLocations< TGroups extends string >( groups: TGroups[] ) {
29
+ return groups.reduce( ( acc, group ) => {
30
+ acc[ group ] = createLocation();
31
+
32
+ return acc;
33
+ }, {} as LocationsMap< TGroups > );
34
+ }
35
+
36
+ type RegisterFns< TGroups extends string, TComponents extends Components > = {
37
+ [ K in keyof TComponents as `register${ Capitalize< K & string > }` ]: RegisterItem< TGroups, TComponents[ K ] >;
38
+ };
39
+
40
+ function createRegisterFns< TGroups extends string, TComponents extends Components >(
41
+ locations: LocationsMap< MenuGroups< TGroups > >,
42
+ components: TComponents
43
+ ) {
44
+ return Object.entries( components ).reduce(
45
+ ( acc, [ key, component ] ) => {
46
+ const name = `register${ capitalize( key ) }`;
47
+
48
+ return {
49
+ ...acc,
50
+ [ name ]: createRegisterItem( locations, component ),
51
+ };
52
+ },
53
+ {} as RegisterFns< TGroups, TComponents >
54
+ );
55
+ }
56
+
57
+ function capitalize( str: string ) {
58
+ return str.charAt( 0 ).toUpperCase() + str.slice( 1 );
59
+ }
@@ -0,0 +1,52 @@
1
+ import * as React from 'react';
2
+ import { ComponentPropsWithoutRef, ComponentType } from 'react';
3
+ import { LocationsMap, MenuGroups } from './types';
4
+
5
+ export type RegisterItem< TGroups extends string, TComponent extends ComponentType > = (
6
+ args: {
7
+ id: string;
8
+ group?: MenuGroups< TGroups >;
9
+ priority?: number;
10
+ overwrite?: boolean;
11
+ } & Props< ComponentPropsWithoutRef< TComponent > >
12
+ ) => void;
13
+
14
+ type Props< TProps extends object > = unknown extends TProps ? NoProps : PropsOrUseProps< TProps >;
15
+
16
+ type NoProps = { props?: never; useProps?: never };
17
+
18
+ type PropsOrUseProps< TProps extends object > =
19
+ | { props: TProps; useProps?: never }
20
+ | {
21
+ useProps: () => TProps;
22
+ props?: never;
23
+ };
24
+
25
+ export function createRegisterItem< TGroups extends string, TComponent extends ComponentType >(
26
+ locations: LocationsMap< MenuGroups< TGroups > >,
27
+ component: TComponent
28
+ ): RegisterItem< TGroups, TComponent > {
29
+ return ( { id, group = 'default', priority = 10, overwrite = false, props: _props, useProps: _useProps } ) => {
30
+ if ( ! ( group in locations ) ) {
31
+ return;
32
+ }
33
+
34
+ const Component = component as ComponentType;
35
+ const useProps = _useProps || ( () => _props );
36
+
37
+ const InjectedComponent = () => {
38
+ const props = useProps();
39
+
40
+ return <Component { ...props } />;
41
+ };
42
+
43
+ locations[ group ].inject( {
44
+ id,
45
+ component: InjectedComponent,
46
+ options: {
47
+ priority,
48
+ overwrite,
49
+ },
50
+ } );
51
+ };
52
+ }
@@ -0,0 +1,33 @@
1
+ import { ComponentType, useMemo } from 'react';
2
+ import { LocationsMap, MenuGroups } from './types';
3
+
4
+ export type UseMenuItems< TGroups extends string > = () => GroupedMenuItems< TGroups >;
5
+
6
+ type GroupedMenuItems< TGroups extends string > = Record<
7
+ MenuGroups< TGroups >,
8
+ Array< {
9
+ id: string;
10
+ MenuItem: ComponentType;
11
+ } >
12
+ >;
13
+
14
+ export function createUseMenuItems< TGroups extends string >(
15
+ locations: LocationsMap< MenuGroups< TGroups > >
16
+ ): UseMenuItems< TGroups > {
17
+ return () => {
18
+ // Normalize the injections groups to an object with the groups as keys.
19
+ return useMemo( () => {
20
+ return Object.entries( locations ).reduce( ( carry, [ groupName, location ] ) => {
21
+ const items = location.getInjections().map( ( injection ) => ( {
22
+ id: injection.id,
23
+ MenuItem: injection.component,
24
+ } ) );
25
+
26
+ return {
27
+ ...carry,
28
+ [ groupName ]: items,
29
+ };
30
+ }, {} as GroupedMenuItems< TGroups > );
31
+ }, [] );
32
+ };
33
+ }
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export { createMenu, type Menu } from './create-menu';
2
+ export { type Components } from './types';
package/src/types.ts ADDED
@@ -0,0 +1,9 @@
1
+ import { Location } from '@elementor/locations';
2
+ import { ComponentType } from 'react';
3
+
4
+ export type LocationsMap< TGroups extends string > = Record< TGroups, Location >;
5
+
6
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Required for TS to infer the props properly.
7
+ export type Components = Record< string, ComponentType< any > >;
8
+
9
+ export type MenuGroups< TGroups extends string > = TGroups | 'default';