directus-extension-polymorphic-reference 1.3.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 wigandt.tech
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,90 @@
1
+ # Directus Polymorphic Reference
2
+
3
+ A Directus **bundle** for polymorphic references — a target *collection* plus a *primary key*, like Laravel's `morphTo`. It turns a pair of plain columns (`entity_type` + `entity_id`) into a searchable, navigable relational field, with the target collection resolved at runtime.
4
+
5
+ Think of a `comments` collection whose rows can belong to **either** `articles`, `products`, or `pages`:
6
+
7
+ ![Data model: one collection referencing many via entity_type + entity_id](docs/images/data-model.svg)
8
+
9
+ ```
10
+ comments
11
+ ├─ id
12
+ ├─ body
13
+ ├─ entity_type = "products" ← which collection this comment belongs to
14
+ └─ entity_id = "8f3a1c…" ← the primary key within that collection
15
+ ```
16
+
17
+ `entity_type` + `entity_id` together point at one record — but Directus has no native field for that. This bundle adds it.
18
+
19
+ ## What's in the bundle
20
+
21
+ | Entry | Type | Use it for |
22
+ | --- | --- | --- |
23
+ | **Polymorphic Reference** | Interface | The `entity_id` field — a searchable dropdown that lists records from the collection named in `entity_type`, writes the chosen primary key, and links out to the record. |
24
+ | **Collection Select** | Interface | The `entity_type` field — a dropdown that lists all collections dynamically, so you never maintain a hardcoded choices list. |
25
+ | **Polymorphic Reference** | Display | The `entity_id` column in list/table layouts — renders the templated label (text is plain; a small launch icon links to the record). |
26
+
27
+ ## Setup
28
+
29
+ ![Setup in three steps](docs/images/setup-flow.svg)
30
+
31
+ ### 1. `entity_type` → **Collection Select** interface
32
+
33
+ Settings → Data Model → your collection → field `entity_type` → Interface → **Collection Select**.
34
+
35
+ - **Include system collections**: off (hides `directus_*`)
36
+ - Stores the technical collection name (`articles`, `products`, …) — exactly what the reference resolves against.
37
+
38
+ ### 2. `entity_id` → **Polymorphic Reference** interface (detail view)
39
+
40
+ ![Interface field states: empty, selected, and open dropdown](docs/images/field-states.svg)
41
+
42
+ Field `entity_id` → Interface → **Polymorphic Reference**.
43
+
44
+ - **Collection** (`collectionField`): `entity_type` — the sibling field holding the target collection name.
45
+ - **Display Templates per Collection**: one row per possible collection; click together which fields to show, e.g.
46
+ - `articles` → `{{ title }}`
47
+ - `products` → `{{ name }} ({{ sku }})`
48
+ - **Item Link**: shows a launch icon that opens the selected record.
49
+ - **Placeholder** / **Limit**: optional.
50
+
51
+ You get a native-style relational control: click the field, search, pick a record (its primary key is written to `entity_id`), open it via the launch icon, or clear the selection.
52
+
53
+ ### 3. `entity_id` → **Polymorphic Reference** display (list/table)
54
+
55
+ In a list layout, set the `entity_id` column's display to **Polymorphic Reference**.
56
+
57
+ - **Collection** (`collectionField`): `entity_type`
58
+ - **Item Link** + **Display Templates per Collection** as above.
59
+
60
+ Because a Directus display only receives the value of its own field, the display looks the row up by `entity_id == value` to read `entity_type`, then renders the label. The text is plain; only the launch icon links to the record.
61
+
62
+ ## Why an interface for the detail view?
63
+
64
+ A Directus **display** only ever receives the value of *its own* field — it has no direct access to sibling columns of the same row (verified against `render-display.vue` and `adjust-fields-for-displays.ts` in core). The display works around this with an extra lookup; the **interface** runs inside the item form and can `inject('values')`, so it reads `entity_type` directly — which is why it's the right tool for editing in the detail view.
65
+
66
+ ## Per-collection templates
67
+
68
+ The interface and the display both expose a `Display Template` repeater. Each row binds a `system-display-template` editor to the collection chosen in that same row (via `collectionField`), giving the familiar Directus "click the fields you want to show" experience — per target collection. When no row matches the resolved collection, the raw primary key is shown. Only the fields referenced by the matched template are fetched.
69
+
70
+ ## System collections
71
+
72
+ Links and lookups are mapped for `directus_users`, `directus_files`, `directus_roles`. Other `directus_*` collections render without a link (they have no Content-module route); regular collections link to `/content/<collection>/<id>`.
73
+
74
+ ## Internationalization
75
+
76
+ UI labels and runtime strings use Directus' own translation keys (`$t:` for option labels, `useI18n()` core keys in components — `collection`, `source`, `format`, `limit`, `placeholder`, `display_template`, `item_link`, `show_link_to_item`, `search`, `no_items`, `open`, `deselect`, `select_an_item`, …), so the bulk of the UI is localized in every language Directus ships. A few help notes and choice labels that have no core equivalent default to English.
77
+
78
+ ## Development
79
+
80
+ ```bash
81
+ npm install
82
+ npm run dev # watch build
83
+ npm run build # production build → dist/
84
+ ```
85
+
86
+ Then drop `dist/` into your Directus `extensions/<name>/` folder, or `npm run link` for local development. Requires Directus host `^11`.
87
+
88
+ ## License
89
+
90
+ MIT
package/dist/api.js ADDED
@@ -0,0 +1 @@
1
+ const o=[],t=[],c=[];export{t as endpoints,o as hooks,c as operations};
package/dist/app.js ADDED
@@ -0,0 +1 @@
1
+ import{useApi as e,useStores as t,defineInterface as l,defineDisplay as n}from"@directus/extensions-sdk";import{ref as a,watch as i,unref as o,defineComponent as r,inject as c,computed as s,resolveComponent as d,resolveDirective as u,openBlock as p,createBlock as f,createElementBlock as m,Fragment as v,createCommentVNode as h,createVNode as y,withCtx as g,createTextVNode as b,toDisplayString as _,createElementVNode as w,renderList as k,normalizeClass as S,withDirectives as x,withModifiers as $}from"vue";import{useI18n as F}from"vue-i18n";function C(e){if(!e)return[];const t=[];for(const l of e.matchAll(/\{\{\s*([\w.]+)\s*\}\}/g)){const e=l[1];e&&!t.includes(e)&&t.push(e)}return t}function A(e,t){return e.replace(/\{\{\s*([\w.]+)\s*\}\}/g,(e,l)=>{const n=l.split(".").reduce((e,t)=>null==e?e:e[t],t);return null==n?"":String(n)}).trim()}function I(e){return e.startsWith("directus_")?`/${e.slice(9)}`:`/items/${e}`}function L(e,t){return t&&Array.isArray(e)?e.find(e=>e?.collection===t)?.template??null:null}function T(t){const l=e(),n=a(null),r=a(!1),c=a(null);let s=0;return i([t.collection,t.primaryKey,t.template],async function(){const e=++s,a=o(t.collection),i=o(t.primaryKey),d=o(t.template);if(!a||null==i||""===i)return n.value=null,void(c.value=null);if(!d)return n.value=String(i),void(c.value=null);const u=C(d);r.value=!0,c.value=null;try{const t=await l.get(function(e,t){return`${I(e)}/${encodeURIComponent(String(t))}`}(a,i),{params:u.length?{fields:u.join(",")}:{}});if(e!==s)return;const o=A(d,t.data?.data??{});n.value=o||String(i)}catch(t){if(e!==s)return;c.value=t,n.value=String(i)}finally{e===s&&(r.value=!1)}},{immediate:!0}),{label:n,loading:r,error:c}}const j=["onClick"],B={class:"prf-content"},R={key:0,class:"prf-label"},K={key:1,class:"prf-placeholder"},N={class:"prf-actions"},P={class:"prf-dropdown"},U={class:"prf-search"},O={class:"prf-results"};var D=r({__name:"interface",props:{value:{},collectionField:{default:"entity"},templates:{default:null},enableLink:{type:Boolean,default:!0},placeholder:{default:""},resultLimit:{default:25},disabled:{type:Boolean,default:!1}},emits:["input"],setup(l,{emit:n}){const r=l,D=n,{t:E}=F(),V=e(),{useFieldsStore:W}=t(),q=W(),J=c("values",a({})),M=s(()=>{const e=r.collectionField||"entity",t=J.value?.[e];return"string"==typeof t&&t.length>0?t:null}),z=s(()=>r.value??null),G=s(()=>L(r.templates,M.value)),H=s(()=>M.value?q.getPrimaryKeyFieldForCollection(M.value)?.field??"id":"id"),{label:Q,loading:X}=T({collection:M,primaryKey:z,template:G}),Y=s(()=>null!=M.value&&null!=r.value&&""!==r.value),Z=s(()=>Y.value?function(e,t){const l=encodeURIComponent(String(t));switch(e){case"directus_users":return`/users/${l}`;case"directus_files":return`/files/${l}`;case"directus_roles":return`/settings/roles/${l}`}return e.startsWith("directus_")?null:`/content/${e}/${l}`}(M.value,r.value):null),ee=s(()=>Q.value||(null!=r.value?String(r.value):""));function te(e){return G.value&&A(G.value,e)||String(e[H.value])}const le=a(""),ne=a([]),ae=a(!1);let ie,oe=0;async function re(){const e=M.value;if(!e)return void(ne.value=[]);const t=++oe;ae.value=!0;try{const l=Array.from(new Set([H.value,...C(G.value)])).filter(Boolean),n=await V.get(I(e),{params:{limit:r.resultLimit,fields:l.join(","),...le.value?{search:le.value}:{}}});if(t!==oe)return;ne.value=n.data?.data??[]}catch{if(t!==oe)return;ne.value=[]}finally{t===oe&&(ae.value=!1)}}function ce(e){le.value=e,ie&&clearTimeout(ie),ie=setTimeout(re,250)}function se(){D("input",null)}return i(M,()=>{ne.value=[],le.value=""}),(e,t)=>{const n=d("v-skeleton-loader"),a=d("v-notice"),i=d("v-icon"),r=d("router-link"),c=d("v-input"),s=d("v-divider"),F=d("v-progress-linear"),C=d("v-list-item-content"),A=d("v-list-item"),I=d("v-list"),L=d("v-menu"),T=u("tooltip");return o(X)?(p(),f(n,{key:0,type:"input"})):M.value?(p(),f(L,{key:2,attached:"",disabled:l.disabled,"onUpdate:modelValue":t[1]||(t[1]=e=>e&&void(0===ne.value.length&&re()))},{activator:g(({toggle:e,active:n})=>[w("div",{class:S(["prf-field",{"prf-field--active":n,"prf-field--disabled":l.disabled}]),onClick:t=>!l.disabled&&e()},[w("div",B,[Y.value?(p(),m("span",R,_(ee.value),1)):(p(),m("span",K,_(l.placeholder||o(E)("select_an_item")),1))]),w("div",N,[Y.value&&l.enableLink&&Z.value?x((p(),f(r,{key:0,to:Z.value,class:"prf-action",onClick:t[0]||(t[0]=$(()=>{},["stop"]))},{default:g(()=>[y(i,{name:"launch"})]),_:1},8,["to"])),[[T,o(E)("open")]]):h("v-if",!0),Y.value&&!l.disabled?x((p(),f(i,{key:1,class:"prf-action",name:"close",clickable:"",onClick:$(se,["stop"])},null,512)),[[T,o(E)("deselect")]]):h("v-if",!0),y(i,{class:S(["prf-action prf-chevron",{"prf-chevron--active":n}]),name:"expand_more"},null,8,["class"])])],10,j)]),default:g(()=>[w("div",P,[w("div",U,[y(c,{"model-value":le.value,small:"",autofocus:"",placeholder:o(E)("search"),"onUpdate:modelValue":ce},{prepend:g(()=>[y(i,{name:"search",small:""})]),_:1},8,["model-value","placeholder"])]),y(s),w("div",O,[ae.value?(p(),f(F,{key:0,indeterminate:""})):h("v-if",!0),y(I,null,{default:g(()=>[ne.value.length?(p(!0),m(v,{key:0},k(ne.value,e=>(p(),f(A,{key:String(e[H.value]),clickable:"",active:String(e[H.value])===String(l.value),onClick:t=>function(e){D("input",e[H.value]??null)}(e)},{default:g(()=>[y(C,null,{default:g(()=>[b(_(te(e)),1)]),_:2},1024)]),_:2},1032,["active","onClick"]))),128)):ae.value?h("v-if",!0):(p(),f(A,{key:1,disabled:""},{default:g(()=>[y(C,null,{default:g(()=>[b(_(o(E)("no_items")),1)]),_:1})]),_:1}))]),_:1})])])]),_:1},8,["disabled"])):(p(),m(v,{key:1},[h(" No entity chosen yet → nothing to select against "),y(a,{type:"info"},{default:g(()=>[b(_(o(E)("select_an_item")),1)]),_:1})],2112))}}}),E=[],V=[];function W(e,t){if(e&&"undefined"!=typeof document){var l,n=!0===t.prepend?"prepend":"append",a=!0===t.singleTag,i="string"==typeof t.container?document.querySelector(t.container):document.getElementsByTagName("head")[0];if(a){var o=E.indexOf(i);-1===o&&(o=E.push(i)-1,V[o]={}),l=V[o]&&V[o][n]?V[o][n]:V[o][n]=r()}else l=r();65279===e.charCodeAt(0)&&(e=e.substring(1)),l.styleSheet?l.styleSheet.cssText+=e:l.appendChild(document.createTextNode(e))}function r(){var e=document.createElement("style");if(e.setAttribute("type","text/css"),t.attributes)for(var l=Object.keys(t.attributes),a=0;a<l.length;a++)e.setAttribute(l[a],t.attributes[l[a]]);var o="prepend"===n?"afterbegin":"beforeend";return i.insertAdjacentElement(o,e),e}}W("\n.prf-field[data-v-b7e9d9e8] {\n\tdisplay: flex;\n\talign-items: center;\n\twidth: 100%;\n\theight: var(--theme--form--field--input--height, 60px);\n\tpadding: 0 8px 0 var(--theme--form--field--input--padding, 16px);\n\tcolor: var(--theme--form--field--input--foreground);\n\tbackground-color: var(--theme--form--field--input--background);\n\tborder: var(--theme--border-width, 2px) solid var(--theme--form--field--input--border-color);\n\tborder-radius: var(--theme--border-radius);\n\tcursor: pointer;\n\ttransition: border-color var(--fast, 150ms) var(--transition, ease);\n}\n.prf-field[data-v-b7e9d9e8]:hover {\n\tborder-color: var(--theme--form--field--input--border-color-hover);\n}\n.prf-field--active[data-v-b7e9d9e8] {\n\tborder-color: var(--theme--primary);\n}\n.prf-field--disabled[data-v-b7e9d9e8] {\n\tcursor: not-allowed;\n\tbackground-color: var(--theme--form--field--input--background-subdued);\n}\n.prf-content[data-v-b7e9d9e8] {\n\tflex: 1 1 auto;\n\tmin-width: 0;\n\tdisplay: flex;\n\talign-items: center;\n}\n.prf-label[data-v-b7e9d9e8] {\n\toverflow: hidden;\n\twhite-space: nowrap;\n\ttext-overflow: ellipsis;\n}\n.prf-placeholder[data-v-b7e9d9e8] {\n\tcolor: var(--theme--foreground-subdued);\n}\n.prf-actions[data-v-b7e9d9e8] {\n\tflex: 0 0 auto;\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 4px;\n\tcolor: var(--theme--foreground-subdued);\n}\n.prf-action[data-v-b7e9d9e8] {\n\tdisplay: inline-flex;\n\tcolor: inherit;\n\ttransition: color var(--fast, 150ms) var(--transition, ease);\n}\n.prf-action[data-v-b7e9d9e8]:hover {\n\tcolor: var(--theme--primary);\n}\n.prf-chevron[data-v-b7e9d9e8] {\n\ttransition: transform var(--fast, 150ms) var(--transition, ease);\n}\n.prf-chevron--active[data-v-b7e9d9e8] {\n\ttransform: rotate(180deg);\n}\n.prf-dropdown[data-v-b7e9d9e8] {\n\tbackground-color: var(--theme--background);\n}\n.prf-search[data-v-b7e9d9e8] {\n\tpadding: 8px;\n}\n.prf-results[data-v-b7e9d9e8] {\n\tmax-height: 260px;\n\toverflow-y: auto;\n}\n",{});var q=(e,t)=>{const l=e.__vccOpts||e;for(const[e,n]of t)l[e]=n;return l},J=l({id:"polymorphic-reference-interface",name:"Polymorphic Reference",icon:"merge_type",description:"Select and navigate a polymorphic (collection + id) reference. The target collection comes from a sibling field (like Laravel morphTo); pick a record from it via a searchable dropdown.",component:q(D,[["__scopeId","data-v-b7e9d9e8"]]),types:["string","uuid","integer","bigInteger"],group:"relational",options:[{field:"collectionField",name:"$t:collection",type:"string",meta:{width:"half",interface:"input",note:'Name of the sibling field on this item that stores the target collection (e.g. "entity").',options:{placeholder:"entity"}},schema:{default_value:"entity"}},{field:"enableLink",name:"$t:item_link",type:"boolean",meta:{width:"full",interface:"boolean",options:{label:"$t:show_link_to_item"}},schema:{default_value:!0}},{field:"placeholder",name:"$t:placeholder",type:"string",meta:{width:"half",interface:"input",options:{placeholder:"$t:select_an_item"}}},{field:"resultLimit",name:"$t:limit",type:"integer",meta:{width:"half",interface:"input",note:"Max number of records loaded into the dropdown per search."},schema:{default_value:25}},{field:"templates",name:"$t:display_template",type:"json",meta:{width:"full",interface:"list",note:"For each possible target collection, click together which fields to show. Falls back to the raw ID when no template matches.",options:{addLabel:"Add collection template",template:"{{ collection }}",fields:[{field:"collection",name:"$t:collection",type:"string",meta:{width:"half",interface:"system-collection",options:{includeSystem:!0}}},{field:"template",name:"$t:display_template",type:"string",meta:{width:"half",interface:"system-display-template",options:{collectionField:"collection"}}}]}}}]});const M={class:"polymorphic-reference-display"},z={key:1,class:"empty"},G={key:2};var H=r({__name:"display",props:{value:{},collectionField:{default:"entity"},templates:{default:null},collection:{},field:{}},setup(t){const l=t,n=e(),r=a(null),c=s(()=>l.value??null);let u=0;i(()=>[l.value,l.collection,l.field,l.collectionField],async function(){const e=++u;if(null==l.value||""===l.value||!l.collection||!l.field)return void(r.value=null);const t=l.collectionField||"entity";try{const a=await n.get(I(l.collection),{params:{filter:JSON.stringify({[l.field]:{_eq:l.value}}),fields:t,limit:1}});if(e!==u)return;const i=(a.data?.data??[])[0],o=i?.[t];r.value="string"==typeof o&&o.length>0?o:null}catch{if(e!==u)return;r.value=null}},{immediate:!0});const v=s(()=>L(l.templates,r.value)),{label:h,loading:y}=T({collection:r,primaryKey:c,template:v}),g=s(()=>null!=r.value&&null!=c.value&&""!==c.value),b=s(()=>h.value||(null!=c.value?String(c.value):""));return(e,t)=>{const l=d("v-skeleton-loader");return p(),m("span",M,[o(y)?(p(),f(l,{key:0,type:"text"})):g.value?(p(),m("span",G,_(b.value),1)):(p(),m("span",z,"--"))])}}});W("\n.polymorphic-reference-display[data-v-5d89a461] {\n\tdisplay: inline-flex;\n\talign-items: center;\n}\n.empty[data-v-5d89a461] {\n\tcolor: var(--theme--foreground-subdued);\n}\n",{});var Q=n({id:"polymorphic-reference-display",name:"Polymorphic Reference",icon:"merge_type",description:"Render a polymorphic (collection + id) reference as a navigable, templated link in list/table columns. The target collection is read from a sibling column on the same row.",component:q(H,[["__scopeId","data-v-5d89a461"]]),types:["string","uuid","integer","bigInteger"],options:[{field:"collectionField",name:"$t:collection",type:"string",meta:{width:"half",interface:"input",note:'Sibling field on the same row that holds the target collection name (e.g. "entity").',options:{placeholder:"entity"}},schema:{default_value:"entity"}},{field:"templates",name:"$t:display_template",type:"json",meta:{width:"full",interface:"list",note:"For each possible target collection, click together which fields to show. Falls back to the raw ID when no template matches.",options:{addLabel:"Add collection template",template:"{{ collection }}",fields:[{field:"collection",name:"$t:collection",type:"string",meta:{width:"half",interface:"system-collection",options:{includeSystem:!0}}},{field:"template",name:"$t:display_template",type:"string",meta:{width:"half",interface:"system-display-template",options:{collectionField:"collection"}}}]}}}]}),X=r({__name:"collection-select",props:{value:{default:null},includeSystem:{type:Boolean,default:!1},placeholder:{default:""},disabled:{type:Boolean,default:!1}},emits:["input"],setup(e,{emit:l}){const n=e,a=l,{t:i}=F(),{useCollectionsStore:r}=t(),c=r(),u=s(()=>c.collections.filter(e=>null!=e.schema).filter(e=>n.includeSystem||!String(e.collection).startsWith("directus_")).map(e=>({text:e.name||e.collection,value:e.collection,icon:e.meta?.icon??void 0})).sort((e,t)=>e.text.localeCompare(t.text)));return(t,l)=>{const n=d("v-select");return p(),f(n,{"model-value":e.value,items:u.value,placeholder:e.placeholder||o(i)("select_an_item"),disabled:e.disabled,"item-icon":"icon","show-deselect":"","onUpdate:modelValue":l[0]||(l[0]=e=>a("input",e))},null,8,["model-value","items","placeholder","disabled"])}}});const Y=[J,l({id:"polymorphic-collection-select",name:"Collection Select",icon:"list_alt",description:"Dropdown that lists all collections dynamically — store a collection name without maintaining a static choices list. Pairs with the Polymorphic Reference interface.",component:X,types:["string"],group:"selection",options:[{field:"includeSystem",name:"Include system collections",type:"boolean",meta:{width:"half",interface:"boolean",options:{label:"Show directus_* collections too"}},schema:{default_value:!1}},{field:"placeholder",name:"$t:placeholder",type:"string",meta:{width:"half",interface:"input"}}]})],Z=[Q],ee=[],te=[],le=[],ne=[],ae=[];export{Z as displays,Y as interfaces,ee as layouts,te as modules,ae as operations,le as panels,ne as themes};
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "directus-extension-polymorphic-reference",
3
+ "description": "Resolve polymorphic (collection + id) references into navigable, templated links — Laravel-style morphTo for Directus. Ships an interface (reads the collection from a sibling field) and a display (for self-describing values).",
4
+ "version": "1.3.0",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "wigandt.tech",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/wigandt-tech/directus-extension-polymorphic-reference.git"
11
+ },
12
+ "homepage": "https://github.com/wigandt-tech/directus-extension-polymorphic-reference#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/wigandt-tech/directus-extension-polymorphic-reference/issues"
15
+ },
16
+ "keywords": [
17
+ "directus",
18
+ "directus-extension",
19
+ "directus-custom-bundle",
20
+ "directus-extension-bundle",
21
+ "interface",
22
+ "display",
23
+ "polymorphic",
24
+ "morph",
25
+ "relation",
26
+ "m2a"
27
+ ],
28
+ "directus:extension": {
29
+ "host": "^11.0.0",
30
+ "type": "bundle",
31
+ "path": {
32
+ "app": "dist/app.js",
33
+ "api": "dist/api.js"
34
+ },
35
+ "entries": [
36
+ {
37
+ "type": "interface",
38
+ "name": "polymorphic-reference-interface",
39
+ "source": "src/interface/index.ts"
40
+ },
41
+ {
42
+ "type": "display",
43
+ "name": "polymorphic-reference-display",
44
+ "source": "src/display/index.ts"
45
+ },
46
+ {
47
+ "type": "interface",
48
+ "name": "polymorphic-collection-select",
49
+ "source": "src/collection-select/index.ts"
50
+ }
51
+ ]
52
+ },
53
+ "files": [
54
+ "dist"
55
+ ],
56
+ "scripts": {
57
+ "build": "directus-extension build",
58
+ "prepare": "directus-extension build",
59
+ "dev": "directus-extension build -w --no-minify",
60
+ "link": "directus-extension link",
61
+ "add": "directus-extension add"
62
+ },
63
+ "devDependencies": {
64
+ "@directus/extensions-sdk": "^17.0.0",
65
+ "typescript": "^5.5.0",
66
+ "vue": "^3.4.0"
67
+ }
68
+ }