@momentumcms/admin 0.1.9 → 0.2.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/fesm2022/momentumcms-admin-array-field.component-CT5NlIEv.mjs +316 -0
- package/fesm2022/momentumcms-admin-array-field.component-CT5NlIEv.mjs.map +1 -0
- package/fesm2022/momentumcms-admin-blocks-field.component-Cz7HmuBK.mjs +362 -0
- package/fesm2022/momentumcms-admin-blocks-field.component-Cz7HmuBK.mjs.map +1 -0
- package/fesm2022/momentumcms-admin-collapsible-field.component-CtwrGQvg.mjs +120 -0
- package/fesm2022/momentumcms-admin-collapsible-field.component-CtwrGQvg.mjs.map +1 -0
- package/fesm2022/{momentumcms-admin-global-edit.page-DFDV-uh3.mjs → momentumcms-admin-global-edit.page-BBUtWCSl.mjs} +2 -2
- package/fesm2022/{momentumcms-admin-global-edit.page-DFDV-uh3.mjs.map → momentumcms-admin-global-edit.page-BBUtWCSl.mjs.map} +1 -1
- package/fesm2022/momentumcms-admin-group-field.component-BZeG8Oqy.mjs +184 -0
- package/fesm2022/momentumcms-admin-group-field.component-BZeG8Oqy.mjs.map +1 -0
- package/fesm2022/{momentumcms-admin-momentumcms-admin-z82jXEsP.mjs → momentumcms-admin-momentumcms-admin-o0FbJXZN.mjs} +9688 -12241
- package/fesm2022/momentumcms-admin-momentumcms-admin-o0FbJXZN.mjs.map +1 -0
- package/fesm2022/momentumcms-admin-relationship-field.component-BuxtRs2_.mjs +473 -0
- package/fesm2022/momentumcms-admin-relationship-field.component-BuxtRs2_.mjs.map +1 -0
- package/fesm2022/momentumcms-admin-rich-text-field.component-DKQ6pwp7.mjs +813 -0
- package/fesm2022/momentumcms-admin-rich-text-field.component-DKQ6pwp7.mjs.map +1 -0
- package/fesm2022/momentumcms-admin-row-field.component-ks3FXd4B.mjs +98 -0
- package/fesm2022/momentumcms-admin-row-field.component-ks3FXd4B.mjs.map +1 -0
- package/fesm2022/momentumcms-admin-tabs-field.component-mZ4dpZoD.mjs +189 -0
- package/fesm2022/momentumcms-admin-tabs-field.component-mZ4dpZoD.mjs.map +1 -0
- package/fesm2022/momentumcms-admin.mjs +1 -1
- package/package.json +1 -1
- package/types/momentumcms-admin.d.ts +79 -13
- package/fesm2022/momentumcms-admin-momentumcms-admin-z82jXEsP.mjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"momentumcms-admin-rich-text-field.component-DKQ6pwp7.mjs","sources":["../../../../libs/admin/src/lib/widgets/entity-form/field-renderers/rich-text-field.component.ts"],"sourcesContent":["import {\n\tafterNextRender,\n\tChangeDetectionStrategy,\n\tComponent,\n\tcomputed,\n\tDestroyRef,\n\teffect,\n\tElementRef,\n\tinject,\n\tinput,\n\tsignal,\n\tviewChild,\n} from '@angular/core';\nimport { McmsFormField } from '@momentumcms/ui';\nimport type { ValidationError } from '@momentumcms/ui';\nimport { humanizeFieldName } from '@momentumcms/core';\nimport type { Field } from '@momentumcms/core';\nimport type { EntityFormMode } from '../entity-form.types';\nimport { getFieldNodeState } from '../entity-form.types';\nimport { Editor } from '@tiptap/core';\nimport StarterKit from '@tiptap/starter-kit';\nimport Underline from '@tiptap/extension-underline';\nimport Link from '@tiptap/extension-link';\nimport Placeholder from '@tiptap/extension-placeholder';\n\n/**\n * Rich text field renderer using TipTap editor.\n * Provides a toolbar with formatting options and stores content as HTML.\n *\n * Uses Angular Signal Forms bridge pattern: reads/writes value via\n * a FieldTree node's FieldState rather than event-based I/O.\n */\n@Component({\n\tselector: 'mcms-rich-text-field-renderer',\n\timports: [McmsFormField],\n\tchangeDetection: ChangeDetectionStrategy.OnPush,\n\thost: { class: 'block' },\n\ttemplate: `\n\t\t<mcms-form-field\n\t\t\t[id]=\"fieldId()\"\n\t\t\t[required]=\"required()\"\n\t\t\t[disabled]=\"isDisabled()\"\n\t\t\t[errors]=\"touchedErrors()\"\n\t\t>\n\t\t\t<span mcmsLabel>{{ label() }}</span>\n\n\t\t\t@if (!isDisabled()) {\n\t\t\t\t<div\n\t\t\t\t\tclass=\"rounded-md border border-input bg-background focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2\"\n\t\t\t\t>\n\t\t\t\t\t<!-- Toolbar -->\n\t\t\t\t\t<div\n\t\t\t\t\t\tclass=\"flex flex-wrap items-center gap-0.5 border-b border-input px-1 py-1\"\n\t\t\t\t\t\trole=\"toolbar\"\n\t\t\t\t\t\t[attr.aria-label]=\"label() + ' formatting'\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclass=\"inline-flex h-8 w-8 items-center justify-center rounded text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground\"\n\t\t\t\t\t\t\t[class.bg-accent]=\"isBold()\"\n\t\t\t\t\t\t\t[class.text-accent-foreground]=\"isBold()\"\n\t\t\t\t\t\t\ttitle=\"Bold (Ctrl+B)\"\n\t\t\t\t\t\t\taria-label=\"Bold\"\n\t\t\t\t\t\t\t[attr.aria-pressed]=\"isBold()\"\n\t\t\t\t\t\t\t(click)=\"toggleBold()\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<svg\n\t\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\t\tclass=\"h-4 w-4\"\n\t\t\t\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\t\t\tstroke-width=\"3\"\n\t\t\t\t\t\t\t\tstroke-linecap=\"round\"\n\t\t\t\t\t\t\t\tstroke-linejoin=\"round\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<path d=\"M6 4h8a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z\" />\n\t\t\t\t\t\t\t\t<path d=\"M6 12h9a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z\" />\n\t\t\t\t\t\t\t</svg>\n\t\t\t\t\t\t</button>\n\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclass=\"inline-flex h-8 w-8 items-center justify-center rounded text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground\"\n\t\t\t\t\t\t\t[class.bg-accent]=\"isItalic()\"\n\t\t\t\t\t\t\t[class.text-accent-foreground]=\"isItalic()\"\n\t\t\t\t\t\t\ttitle=\"Italic (Ctrl+I)\"\n\t\t\t\t\t\t\taria-label=\"Italic\"\n\t\t\t\t\t\t\t[attr.aria-pressed]=\"isItalic()\"\n\t\t\t\t\t\t\t(click)=\"toggleItalic()\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<svg\n\t\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\t\tclass=\"h-4 w-4\"\n\t\t\t\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\t\t\tstroke-width=\"2\"\n\t\t\t\t\t\t\t\tstroke-linecap=\"round\"\n\t\t\t\t\t\t\t\tstroke-linejoin=\"round\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<line x1=\"19\" y1=\"4\" x2=\"10\" y2=\"4\" />\n\t\t\t\t\t\t\t\t<line x1=\"14\" y1=\"20\" x2=\"5\" y2=\"20\" />\n\t\t\t\t\t\t\t\t<line x1=\"15\" y1=\"4\" x2=\"9\" y2=\"20\" />\n\t\t\t\t\t\t\t</svg>\n\t\t\t\t\t\t</button>\n\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclass=\"inline-flex h-8 w-8 items-center justify-center rounded text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground\"\n\t\t\t\t\t\t\t[class.bg-accent]=\"isUnderline()\"\n\t\t\t\t\t\t\t[class.text-accent-foreground]=\"isUnderline()\"\n\t\t\t\t\t\t\ttitle=\"Underline (Ctrl+U)\"\n\t\t\t\t\t\t\taria-label=\"Underline\"\n\t\t\t\t\t\t\t[attr.aria-pressed]=\"isUnderline()\"\n\t\t\t\t\t\t\t(click)=\"toggleUnderline()\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<svg\n\t\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\t\tclass=\"h-4 w-4\"\n\t\t\t\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\t\t\tstroke-width=\"2\"\n\t\t\t\t\t\t\t\tstroke-linecap=\"round\"\n\t\t\t\t\t\t\t\tstroke-linejoin=\"round\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<path d=\"M6 3v7a6 6 0 0 0 6 6 6 6 0 0 0 6-6V3\" />\n\t\t\t\t\t\t\t\t<line x1=\"4\" y1=\"21\" x2=\"20\" y2=\"21\" />\n\t\t\t\t\t\t\t</svg>\n\t\t\t\t\t\t</button>\n\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclass=\"inline-flex h-8 w-8 items-center justify-center rounded text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground\"\n\t\t\t\t\t\t\t[class.bg-accent]=\"isStrike()\"\n\t\t\t\t\t\t\t[class.text-accent-foreground]=\"isStrike()\"\n\t\t\t\t\t\t\ttitle=\"Strikethrough\"\n\t\t\t\t\t\t\taria-label=\"Strikethrough\"\n\t\t\t\t\t\t\t[attr.aria-pressed]=\"isStrike()\"\n\t\t\t\t\t\t\t(click)=\"toggleStrike()\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<svg\n\t\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\t\tclass=\"h-4 w-4\"\n\t\t\t\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\t\t\tstroke-width=\"2\"\n\t\t\t\t\t\t\t\tstroke-linecap=\"round\"\n\t\t\t\t\t\t\t\tstroke-linejoin=\"round\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<path d=\"M16 4H9a3 3 0 0 0-2.83 4\" />\n\t\t\t\t\t\t\t\t<path d=\"M14 12a4 4 0 0 1 0 8H6\" />\n\t\t\t\t\t\t\t\t<line x1=\"4\" y1=\"12\" x2=\"20\" y2=\"12\" />\n\t\t\t\t\t\t\t</svg>\n\t\t\t\t\t\t</button>\n\n\t\t\t\t\t\t<div class=\"mx-1 h-6 w-px bg-border\" role=\"separator\"></div>\n\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclass=\"inline-flex h-8 w-8 items-center justify-center rounded text-sm font-bold transition-colors hover:bg-accent hover:text-accent-foreground\"\n\t\t\t\t\t\t\t[class.bg-accent]=\"isHeading1()\"\n\t\t\t\t\t\t\t[class.text-accent-foreground]=\"isHeading1()\"\n\t\t\t\t\t\t\ttitle=\"Heading 1\"\n\t\t\t\t\t\t\taria-label=\"Heading 1\"\n\t\t\t\t\t\t\t[attr.aria-pressed]=\"isHeading1()\"\n\t\t\t\t\t\t\t(click)=\"toggleHeading(1)\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tH1\n\t\t\t\t\t\t</button>\n\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclass=\"inline-flex h-8 w-8 items-center justify-center rounded text-sm font-bold transition-colors hover:bg-accent hover:text-accent-foreground\"\n\t\t\t\t\t\t\t[class.bg-accent]=\"isHeading2()\"\n\t\t\t\t\t\t\t[class.text-accent-foreground]=\"isHeading2()\"\n\t\t\t\t\t\t\ttitle=\"Heading 2\"\n\t\t\t\t\t\t\taria-label=\"Heading 2\"\n\t\t\t\t\t\t\t[attr.aria-pressed]=\"isHeading2()\"\n\t\t\t\t\t\t\t(click)=\"toggleHeading(2)\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tH2\n\t\t\t\t\t\t</button>\n\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclass=\"inline-flex h-8 w-8 items-center justify-center rounded text-sm font-bold transition-colors hover:bg-accent hover:text-accent-foreground\"\n\t\t\t\t\t\t\t[class.bg-accent]=\"isHeading3()\"\n\t\t\t\t\t\t\t[class.text-accent-foreground]=\"isHeading3()\"\n\t\t\t\t\t\t\ttitle=\"Heading 3\"\n\t\t\t\t\t\t\taria-label=\"Heading 3\"\n\t\t\t\t\t\t\t[attr.aria-pressed]=\"isHeading3()\"\n\t\t\t\t\t\t\t(click)=\"toggleHeading(3)\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tH3\n\t\t\t\t\t\t</button>\n\n\t\t\t\t\t\t<div class=\"mx-1 h-6 w-px bg-border\" role=\"separator\"></div>\n\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclass=\"inline-flex h-8 w-8 items-center justify-center rounded text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground\"\n\t\t\t\t\t\t\t[class.bg-accent]=\"isBulletList()\"\n\t\t\t\t\t\t\t[class.text-accent-foreground]=\"isBulletList()\"\n\t\t\t\t\t\t\ttitle=\"Bullet List\"\n\t\t\t\t\t\t\taria-label=\"Bullet list\"\n\t\t\t\t\t\t\t[attr.aria-pressed]=\"isBulletList()\"\n\t\t\t\t\t\t\t(click)=\"toggleBulletList()\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<svg\n\t\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\t\tclass=\"h-4 w-4\"\n\t\t\t\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\t\t\tstroke-width=\"2\"\n\t\t\t\t\t\t\t\tstroke-linecap=\"round\"\n\t\t\t\t\t\t\t\tstroke-linejoin=\"round\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<line x1=\"8\" y1=\"6\" x2=\"21\" y2=\"6\" />\n\t\t\t\t\t\t\t\t<line x1=\"8\" y1=\"12\" x2=\"21\" y2=\"12\" />\n\t\t\t\t\t\t\t\t<line x1=\"8\" y1=\"18\" x2=\"21\" y2=\"18\" />\n\t\t\t\t\t\t\t\t<line x1=\"3\" y1=\"6\" x2=\"3.01\" y2=\"6\" />\n\t\t\t\t\t\t\t\t<line x1=\"3\" y1=\"12\" x2=\"3.01\" y2=\"12\" />\n\t\t\t\t\t\t\t\t<line x1=\"3\" y1=\"18\" x2=\"3.01\" y2=\"18\" />\n\t\t\t\t\t\t\t</svg>\n\t\t\t\t\t\t</button>\n\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclass=\"inline-flex h-8 w-8 items-center justify-center rounded text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground\"\n\t\t\t\t\t\t\t[class.bg-accent]=\"isOrderedList()\"\n\t\t\t\t\t\t\t[class.text-accent-foreground]=\"isOrderedList()\"\n\t\t\t\t\t\t\ttitle=\"Numbered List\"\n\t\t\t\t\t\t\taria-label=\"Numbered list\"\n\t\t\t\t\t\t\t[attr.aria-pressed]=\"isOrderedList()\"\n\t\t\t\t\t\t\t(click)=\"toggleOrderedList()\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<svg\n\t\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\t\tclass=\"h-4 w-4\"\n\t\t\t\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\t\t\tstroke-width=\"2\"\n\t\t\t\t\t\t\t\tstroke-linecap=\"round\"\n\t\t\t\t\t\t\t\tstroke-linejoin=\"round\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<line x1=\"10\" y1=\"6\" x2=\"21\" y2=\"6\" />\n\t\t\t\t\t\t\t\t<line x1=\"10\" y1=\"12\" x2=\"21\" y2=\"12\" />\n\t\t\t\t\t\t\t\t<line x1=\"10\" y1=\"18\" x2=\"21\" y2=\"18\" />\n\t\t\t\t\t\t\t\t<path d=\"M4 6h1v4\" />\n\t\t\t\t\t\t\t\t<path d=\"M4 10h2\" />\n\t\t\t\t\t\t\t\t<path d=\"M6 18H4c0-1 2-2 2-3s-1-1.5-2-1\" />\n\t\t\t\t\t\t\t</svg>\n\t\t\t\t\t\t</button>\n\n\t\t\t\t\t\t<div class=\"mx-1 h-6 w-px bg-border\" role=\"separator\"></div>\n\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclass=\"inline-flex h-8 w-8 items-center justify-center rounded text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground\"\n\t\t\t\t\t\t\t[class.bg-accent]=\"isBlockquote()\"\n\t\t\t\t\t\t\t[class.text-accent-foreground]=\"isBlockquote()\"\n\t\t\t\t\t\t\ttitle=\"Blockquote\"\n\t\t\t\t\t\t\taria-label=\"Blockquote\"\n\t\t\t\t\t\t\t[attr.aria-pressed]=\"isBlockquote()\"\n\t\t\t\t\t\t\t(click)=\"toggleBlockquote()\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<svg aria-hidden=\"true\" class=\"h-4 w-4\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n\t\t\t\t\t\t\t\t<path\n\t\t\t\t\t\t\t\t\td=\"M4.583 17.321C3.553 16.227 3 15 3 13.011c0-3.5 2.457-6.637 6.03-8.188l.893 1.378c-3.335 1.804-3.987 4.145-4.247 5.621.537-.278 1.24-.375 1.929-.311 1.804.167 3.226 1.648 3.226 3.489a3.5 3.5 0 01-3.5 3.5c-1.073 0-2.099-.49-2.748-1.179zm10 0C13.553 16.227 13 15 13 13.011c0-3.5 2.457-6.637 6.03-8.188l.893 1.378c-3.335 1.804-3.987 4.145-4.247 5.621.537-.278 1.24-.375 1.929-.311 1.804.167 3.226 1.648 3.226 3.489a3.5 3.5 0 01-3.5 3.5c-1.073 0-2.099-.49-2.748-1.179z\"\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</svg>\n\t\t\t\t\t\t</button>\n\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclass=\"inline-flex h-8 w-8 items-center justify-center rounded text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground\"\n\t\t\t\t\t\t\t[class.bg-accent]=\"isCodeBlock()\"\n\t\t\t\t\t\t\t[class.text-accent-foreground]=\"isCodeBlock()\"\n\t\t\t\t\t\t\ttitle=\"Code Block\"\n\t\t\t\t\t\t\taria-label=\"Code block\"\n\t\t\t\t\t\t\t[attr.aria-pressed]=\"isCodeBlock()\"\n\t\t\t\t\t\t\t(click)=\"toggleCodeBlock()\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<svg\n\t\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\t\tclass=\"h-4 w-4\"\n\t\t\t\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\t\t\tstroke-width=\"2\"\n\t\t\t\t\t\t\t\tstroke-linecap=\"round\"\n\t\t\t\t\t\t\t\tstroke-linejoin=\"round\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<polyline points=\"16 18 22 12 16 6\" />\n\t\t\t\t\t\t\t\t<polyline points=\"8 6 2 12 8 18\" />\n\t\t\t\t\t\t\t</svg>\n\t\t\t\t\t\t</button>\n\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclass=\"inline-flex h-8 w-8 items-center justify-center rounded text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground\"\n\t\t\t\t\t\t\ttitle=\"Horizontal Rule\"\n\t\t\t\t\t\t\taria-label=\"Horizontal rule\"\n\t\t\t\t\t\t\t(click)=\"insertHorizontalRule()\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<svg\n\t\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\t\tclass=\"h-4 w-4\"\n\t\t\t\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\t\t\tstroke-width=\"2\"\n\t\t\t\t\t\t\t\tstroke-linecap=\"round\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<line x1=\"3\" y1=\"12\" x2=\"21\" y2=\"12\" />\n\t\t\t\t\t\t\t</svg>\n\t\t\t\t\t\t</button>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<!-- Editor content area -->\n\t\t\t\t\t<div\n\t\t\t\t\t\t#editorElement\n\t\t\t\t\t\tclass=\"tiptap-editor prose prose-sm dark:prose-invert max-w-none px-3 py-2\"\n\t\t\t\t\t\tdata-testid=\"rich-text-editor\"\n\t\t\t\t\t></div>\n\t\t\t\t</div>\n\t\t\t} @else {\n\t\t\t\t<!-- Read-only view -->\n\t\t\t\t<div\n\t\t\t\t\tclass=\"prose prose-sm dark:prose-invert max-w-none rounded-md border border-input bg-muted/50 px-3 py-2\"\n\t\t\t\t\t[innerHTML]=\"stringValue()\"\n\t\t\t\t></div>\n\t\t\t}\n\t\t</mcms-form-field>\n\t`,\n\tstyles: `\n\t\t:host ::ng-deep .tiptap-editor {\n\t\t\tmin-height: 200px;\n\t\t\toutline: none;\n\t\t}\n\n\t\t:host ::ng-deep .tiptap-editor .ProseMirror {\n\t\t\toutline: none;\n\t\t\tmin-height: 200px;\n\t\t}\n\n\t\t:host ::ng-deep .tiptap-editor .ProseMirror p.is-editor-empty:first-child::before {\n\t\t\tcontent: attr(data-placeholder);\n\t\t\tfloat: left;\n\t\t\tcolor: hsl(var(--mcms-muted-foreground));\n\t\t\tpointer-events: none;\n\t\t\theight: 0;\n\t\t}\n\n\t\t:host ::ng-deep .tiptap-editor .ProseMirror h1 {\n\t\t\tfont-size: 1.5em;\n\t\t\tfont-weight: 700;\n\t\t\tmargin: 0.5em 0;\n\t\t}\n\n\t\t:host ::ng-deep .tiptap-editor .ProseMirror h2 {\n\t\t\tfont-size: 1.25em;\n\t\t\tfont-weight: 600;\n\t\t\tmargin: 0.5em 0;\n\t\t}\n\n\t\t:host ::ng-deep .tiptap-editor .ProseMirror h3 {\n\t\t\tfont-size: 1.1em;\n\t\t\tfont-weight: 600;\n\t\t\tmargin: 0.5em 0;\n\t\t}\n\n\t\t:host ::ng-deep .tiptap-editor .ProseMirror ul {\n\t\t\tlist-style: disc;\n\t\t\tpadding-left: 1.5em;\n\t\t}\n\n\t\t:host ::ng-deep .tiptap-editor .ProseMirror ol {\n\t\t\tlist-style: decimal;\n\t\t\tpadding-left: 1.5em;\n\t\t}\n\n\t\t:host ::ng-deep .tiptap-editor .ProseMirror blockquote {\n\t\t\tborder-left: 3px solid hsl(var(--mcms-border));\n\t\t\tpadding-left: 1em;\n\t\t\tmargin-left: 0;\n\t\t\tcolor: hsl(var(--mcms-muted-foreground));\n\t\t}\n\n\t\t:host ::ng-deep .tiptap-editor .ProseMirror pre {\n\t\t\tbackground: hsl(var(--mcms-muted));\n\t\t\tborder-radius: 0.375rem;\n\t\t\tpadding: 0.75em;\n\t\t\tfont-family: monospace;\n\t\t\tfont-size: 0.875em;\n\t\t}\n\n\t\t:host ::ng-deep .tiptap-editor .ProseMirror code {\n\t\t\tbackground: hsl(var(--mcms-muted));\n\t\t\tborder-radius: 0.25rem;\n\t\t\tpadding: 0.125em 0.25em;\n\t\t\tfont-size: 0.875em;\n\t\t}\n\n\t\t:host ::ng-deep .tiptap-editor .ProseMirror hr {\n\t\t\tborder: none;\n\t\t\tborder-top: 1px solid hsl(var(--mcms-border));\n\t\t\tmargin: 1em 0;\n\t\t}\n\n\t\t:host ::ng-deep .tiptap-editor .ProseMirror a {\n\t\t\tcolor: hsl(var(--mcms-primary));\n\t\t\ttext-decoration: underline;\n\t\t}\n\n\t\t:host ::ng-deep .tiptap-editor .ProseMirror p {\n\t\t\tmargin: 0.25em 0;\n\t\t}\n\t`,\n})\nexport class RichTextFieldRenderer {\n\tprivate readonly destroyRef = inject(DestroyRef);\n\n\t/** Field definition */\n\treadonly field = input.required<Field>();\n\n\t/** Signal forms FieldTree node for this field */\n\treadonly formNode = input<unknown>(null);\n\n\t/** Form mode */\n\treadonly mode = input<EntityFormMode>('create');\n\n\t/** Field path */\n\treadonly path = input.required<string>();\n\n\t/** Bridge: extract FieldState from formNode */\n\tprivate readonly nodeState = computed(() => getFieldNodeState(this.formNode()));\n\n\t/** Editor container element */\n\treadonly editorRef = viewChild<ElementRef<HTMLElement>>('editorElement');\n\n\t/** TipTap editor instance */\n\tprivate editor: Editor | null = null;\n\n\t/** Whether we're currently updating from external value (prevents feedback loops) */\n\tprivate updatingFromExternal = false;\n\n\t/** Whether the editor has been initialized (browser only) */\n\treadonly editorReady = signal(false);\n\n\t/** Toolbar state signals */\n\treadonly isBold = signal(false);\n\treadonly isItalic = signal(false);\n\treadonly isUnderline = signal(false);\n\treadonly isStrike = signal(false);\n\treadonly isHeading1 = signal(false);\n\treadonly isHeading2 = signal(false);\n\treadonly isHeading3 = signal(false);\n\treadonly isBulletList = signal(false);\n\treadonly isOrderedList = signal(false);\n\treadonly isBlockquote = signal(false);\n\treadonly isCodeBlock = signal(false);\n\n\t/** Unique field ID */\n\treadonly fieldId = computed(() => `field-${this.path().replace(/\\./g, '-')}`);\n\n\t/** Computed label */\n\treadonly label = computed(() => this.field().label || humanizeFieldName(this.field().name));\n\n\t/** Whether the field is required */\n\treadonly required = computed(() => this.field().required ?? false);\n\n\t/** Whether the field is disabled */\n\treadonly isDisabled = computed(() => {\n\t\treturn this.mode() === 'view' || (this.field().admin?.readOnly ?? false);\n\t});\n\n\t/** String value from FieldState */\n\treadonly stringValue = computed(() => {\n\t\tconst state = this.nodeState();\n\t\tif (!state) return '';\n\t\tconst val = state.value();\n\t\treturn val === null || val === undefined ? '' : String(val);\n\t});\n\n\t/** Validation errors shown only when field is touched */\n\treadonly touchedErrors = computed((): readonly ValidationError[] => {\n\t\tconst state = this.nodeState();\n\t\tif (!state || !state.touched()) return [];\n\t\treturn state.errors().map((e) => ({ kind: e.kind, message: e.message }));\n\t});\n\n\tconstructor() {\n\t\t// Mount editor after first browser render (SSR-safe).\n\t\tafterNextRender(() => {\n\t\t\tthis.mountEditor();\n\t\t});\n\n\t\t// Sync external value changes into the editor\n\t\teffect(() => {\n\t\t\tconst val = this.stringValue();\n\t\t\tif (this.editor && !this.editor.isDestroyed) {\n\t\t\t\tconst currentHtml = this.editor.getHTML();\n\t\t\t\tif (val !== currentHtml && !(val === '' && currentHtml === '<p></p>')) {\n\t\t\t\t\tthis.updatingFromExternal = true;\n\t\t\t\t\tthis.editor.commands.setContent(val || '', { emitUpdate: false });\n\t\t\t\t\tthis.updatingFromExternal = false;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tthis.destroyRef.onDestroy(() => {\n\t\t\tthis.editor?.destroy();\n\t\t\tthis.editor = null;\n\t\t});\n\t}\n\n\t/**\n\t * Handle blur from editor.\n\t */\n\tonBlur(): void {\n\t\tconst state = this.nodeState();\n\t\tif (state) state.markAsTouched();\n\t}\n\n\tprivate mountEditor(): void {\n\t\tconst el = this.editorRef();\n\t\tif (!el || this.isDisabled() || this.editor) return;\n\n\t\tthis.editor = new Editor({\n\t\t\telement: el.nativeElement,\n\t\t\teditorProps: {\n\t\t\t\tattributes: {\n\t\t\t\t\trole: 'textbox',\n\t\t\t\t\t'aria-multiline': 'true',\n\t\t\t\t\t'aria-label': this.label() + ' editor',\n\t\t\t\t},\n\t\t\t},\n\t\t\textensions: [\n\t\t\t\tStarterKit.configure({\n\t\t\t\t\theading: { levels: [1, 2, 3] },\n\t\t\t\t}),\n\t\t\t\tUnderline,\n\t\t\t\tLink.configure({\n\t\t\t\t\topenOnClick: false,\n\t\t\t\t\tHTMLAttributes: {\n\t\t\t\t\t\trel: 'noopener noreferrer nofollow',\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t\tPlaceholder.configure({\n\t\t\t\t\tplaceholder: this.field().admin?.placeholder || 'Start writing...',\n\t\t\t\t}),\n\t\t\t],\n\t\t\tcontent: this.stringValue() || '',\n\t\t\teditable: true,\n\t\t\tonUpdate: ({ editor }) => {\n\t\t\t\tif (!this.updatingFromExternal) {\n\t\t\t\t\tconst html = editor.getHTML();\n\t\t\t\t\tconst value = html === '<p></p>' ? '' : html;\n\t\t\t\t\tconst state = this.nodeState();\n\t\t\t\t\tif (state) state.value.set(value);\n\t\t\t\t}\n\t\t\t},\n\t\t\tonSelectionUpdate: ({ editor }) => {\n\t\t\t\tthis.updateToolbarState(editor);\n\t\t\t},\n\t\t\tonTransaction: ({ editor }) => {\n\t\t\t\tthis.updateToolbarState(editor);\n\t\t\t},\n\t\t\tonBlur: () => {\n\t\t\t\tthis.onBlur();\n\t\t\t},\n\t\t});\n\n\t\tthis.editorReady.set(true);\n\t}\n\n\tprivate updateToolbarState(editor: Editor): void {\n\t\tthis.isBold.set(editor.isActive('bold'));\n\t\tthis.isItalic.set(editor.isActive('italic'));\n\t\tthis.isUnderline.set(editor.isActive('underline'));\n\t\tthis.isStrike.set(editor.isActive('strike'));\n\t\tthis.isHeading1.set(editor.isActive('heading', { level: 1 }));\n\t\tthis.isHeading2.set(editor.isActive('heading', { level: 2 }));\n\t\tthis.isHeading3.set(editor.isActive('heading', { level: 3 }));\n\t\tthis.isBulletList.set(editor.isActive('bulletList'));\n\t\tthis.isOrderedList.set(editor.isActive('orderedList'));\n\t\tthis.isBlockquote.set(editor.isActive('blockquote'));\n\t\tthis.isCodeBlock.set(editor.isActive('codeBlock'));\n\t}\n\n\ttoggleBold(): void {\n\t\tthis.editor?.chain().focus().toggleBold().run();\n\t}\n\n\ttoggleItalic(): void {\n\t\tthis.editor?.chain().focus().toggleItalic().run();\n\t}\n\n\ttoggleUnderline(): void {\n\t\tthis.editor?.chain().focus().toggleUnderline().run();\n\t}\n\n\ttoggleStrike(): void {\n\t\tthis.editor?.chain().focus().toggleStrike().run();\n\t}\n\n\ttoggleHeading(level: 1 | 2 | 3): void {\n\t\tthis.editor?.chain().focus().toggleHeading({ level }).run();\n\t}\n\n\ttoggleBulletList(): void {\n\t\tthis.editor?.chain().focus().toggleBulletList().run();\n\t}\n\n\ttoggleOrderedList(): void {\n\t\tthis.editor?.chain().focus().toggleOrderedList().run();\n\t}\n\n\ttoggleBlockquote(): void {\n\t\tthis.editor?.chain().focus().toggleBlockquote().run();\n\t}\n\n\ttoggleCodeBlock(): void {\n\t\tthis.editor?.chain().focus().toggleCodeBlock().run();\n\t}\n\n\tinsertHorizontalRule(): void {\n\t\tthis.editor?.chain().focus().setHorizontalRule().run();\n\t}\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { input, computed, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
+
import { b as getSubNode, F as FieldRenderer } from './momentumcms-admin-momentumcms-admin-o0FbJXZN.mjs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Row layout field renderer.
|
|
7
|
+
*
|
|
8
|
+
* Displays child fields side-by-side in a horizontal row.
|
|
9
|
+
* This is a layout-only field; it does not store data itself.
|
|
10
|
+
* Child field FieldTree nodes are looked up from the root formTree
|
|
11
|
+
* using flat field names.
|
|
12
|
+
*/
|
|
13
|
+
class RowFieldRenderer {
|
|
14
|
+
/** Field definition (must be a RowField) */
|
|
15
|
+
field = input.required(...(ngDevMode ? [{ debugName: "field" }] : []));
|
|
16
|
+
/** Root signal forms FieldTree (for looking up child field nodes) */
|
|
17
|
+
formTree = input(null, ...(ngDevMode ? [{ debugName: "formTree" }] : []));
|
|
18
|
+
/** Form model data (for condition evaluation and relationship filterOptions) */
|
|
19
|
+
formModel = input({}, ...(ngDevMode ? [{ debugName: "formModel" }] : []));
|
|
20
|
+
/** Form mode */
|
|
21
|
+
mode = input('create', ...(ngDevMode ? [{ debugName: "mode" }] : []));
|
|
22
|
+
/** Field path (unused for layout fields, kept for interface consistency) */
|
|
23
|
+
path = input.required(...(ngDevMode ? [{ debugName: "path" }] : []));
|
|
24
|
+
/** Computed label */
|
|
25
|
+
label = computed(() => this.field().label || '', ...(ngDevMode ? [{ debugName: "label" }] : []));
|
|
26
|
+
/** Computed description */
|
|
27
|
+
description = computed(() => this.field().description || '', ...(ngDevMode ? [{ debugName: "description" }] : []));
|
|
28
|
+
/** Child fields */
|
|
29
|
+
subFields = computed(() => {
|
|
30
|
+
const f = this.field();
|
|
31
|
+
if (f.type === 'row') {
|
|
32
|
+
return f.fields.filter((sf) => !sf.admin?.hidden);
|
|
33
|
+
}
|
|
34
|
+
return [];
|
|
35
|
+
}, ...(ngDevMode ? [{ debugName: "subFields" }] : []));
|
|
36
|
+
/** CSS grid columns: equal width for each child */
|
|
37
|
+
gridColumns = computed(() => {
|
|
38
|
+
const count = this.subFields().length;
|
|
39
|
+
return `repeat(${count}, 1fr)`;
|
|
40
|
+
}, ...(ngDevMode ? [{ debugName: "gridColumns" }] : []));
|
|
41
|
+
/** Get a FieldTree sub-node for a child field (flat path from root tree) */
|
|
42
|
+
getChildFormNode(fieldName) {
|
|
43
|
+
return getSubNode(this.formTree(), fieldName);
|
|
44
|
+
}
|
|
45
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: RowFieldRenderer, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
46
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: RowFieldRenderer, isStandalone: true, selector: "mcms-row-field-renderer", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, formTree: { classPropertyName: "formTree", publicName: "formTree", isSignal: true, isRequired: false, transformFunction: null }, formModel: { classPropertyName: "formModel", publicName: "formModel", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, path: { classPropertyName: "path", publicName: "path", isSignal: true, isRequired: true, transformFunction: null } }, host: { classAttribute: "block" }, ngImport: i0, template: `
|
|
47
|
+
@if (label()) {
|
|
48
|
+
<h3 class="text-sm font-medium text-foreground mb-3">{{ label() }}</h3>
|
|
49
|
+
}
|
|
50
|
+
@if (description()) {
|
|
51
|
+
<p class="text-sm text-muted-foreground mb-3">{{ description() }}</p>
|
|
52
|
+
}
|
|
53
|
+
<div class="grid gap-4" [style.grid-template-columns]="gridColumns()">
|
|
54
|
+
@for (subField of subFields(); track subField.name) {
|
|
55
|
+
<mcms-field-renderer
|
|
56
|
+
[field]="subField"
|
|
57
|
+
[formNode]="getChildFormNode(subField.name)"
|
|
58
|
+
[formTree]="formTree()"
|
|
59
|
+
[formModel]="formModel()"
|
|
60
|
+
[mode]="mode()"
|
|
61
|
+
[path]="subField.name"
|
|
62
|
+
/>
|
|
63
|
+
}
|
|
64
|
+
</div>
|
|
65
|
+
`, isInline: true, dependencies: [{ kind: "component", type: FieldRenderer, selector: "mcms-field-renderer", inputs: ["field", "formNode", "formTree", "formModel", "mode", "path"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
66
|
+
}
|
|
67
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: RowFieldRenderer, decorators: [{
|
|
68
|
+
type: Component,
|
|
69
|
+
args: [{
|
|
70
|
+
selector: 'mcms-row-field-renderer',
|
|
71
|
+
imports: [FieldRenderer],
|
|
72
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
73
|
+
host: { class: 'block' },
|
|
74
|
+
template: `
|
|
75
|
+
@if (label()) {
|
|
76
|
+
<h3 class="text-sm font-medium text-foreground mb-3">{{ label() }}</h3>
|
|
77
|
+
}
|
|
78
|
+
@if (description()) {
|
|
79
|
+
<p class="text-sm text-muted-foreground mb-3">{{ description() }}</p>
|
|
80
|
+
}
|
|
81
|
+
<div class="grid gap-4" [style.grid-template-columns]="gridColumns()">
|
|
82
|
+
@for (subField of subFields(); track subField.name) {
|
|
83
|
+
<mcms-field-renderer
|
|
84
|
+
[field]="subField"
|
|
85
|
+
[formNode]="getChildFormNode(subField.name)"
|
|
86
|
+
[formTree]="formTree()"
|
|
87
|
+
[formModel]="formModel()"
|
|
88
|
+
[mode]="mode()"
|
|
89
|
+
[path]="subField.name"
|
|
90
|
+
/>
|
|
91
|
+
}
|
|
92
|
+
</div>
|
|
93
|
+
`,
|
|
94
|
+
}]
|
|
95
|
+
}], propDecorators: { field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }], formTree: [{ type: i0.Input, args: [{ isSignal: true, alias: "formTree", required: false }] }], formModel: [{ type: i0.Input, args: [{ isSignal: true, alias: "formModel", required: false }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], path: [{ type: i0.Input, args: [{ isSignal: true, alias: "path", required: true }] }] } });
|
|
96
|
+
|
|
97
|
+
export { RowFieldRenderer };
|
|
98
|
+
//# sourceMappingURL=momentumcms-admin-row-field.component-ks3FXd4B.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"momentumcms-admin-row-field.component-ks3FXd4B.mjs","sources":["../../../../libs/admin/src/lib/widgets/entity-form/field-renderers/row-field.component.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';\nimport type { Field } from '@momentumcms/core';\nimport type { EntityFormMode } from '../entity-form.types';\nimport { getSubNode } from '../entity-form.types';\nimport { FieldRenderer } from './field-renderer.component';\n\n/**\n * Row layout field renderer.\n *\n * Displays child fields side-by-side in a horizontal row.\n * This is a layout-only field; it does not store data itself.\n * Child field FieldTree nodes are looked up from the root formTree\n * using flat field names.\n */\n@Component({\n\tselector: 'mcms-row-field-renderer',\n\timports: [FieldRenderer],\n\tchangeDetection: ChangeDetectionStrategy.OnPush,\n\thost: { class: 'block' },\n\ttemplate: `\n\t\t@if (label()) {\n\t\t\t<h3 class=\"text-sm font-medium text-foreground mb-3\">{{ label() }}</h3>\n\t\t}\n\t\t@if (description()) {\n\t\t\t<p class=\"text-sm text-muted-foreground mb-3\">{{ description() }}</p>\n\t\t}\n\t\t<div class=\"grid gap-4\" [style.grid-template-columns]=\"gridColumns()\">\n\t\t\t@for (subField of subFields(); track subField.name) {\n\t\t\t\t<mcms-field-renderer\n\t\t\t\t\t[field]=\"subField\"\n\t\t\t\t\t[formNode]=\"getChildFormNode(subField.name)\"\n\t\t\t\t\t[formTree]=\"formTree()\"\n\t\t\t\t\t[formModel]=\"formModel()\"\n\t\t\t\t\t[mode]=\"mode()\"\n\t\t\t\t\t[path]=\"subField.name\"\n\t\t\t\t/>\n\t\t\t}\n\t\t</div>\n\t`,\n})\nexport class RowFieldRenderer {\n\t/** Field definition (must be a RowField) */\n\treadonly field = input.required<Field>();\n\n\t/** Root signal forms FieldTree (for looking up child field nodes) */\n\treadonly formTree = input<unknown>(null);\n\n\t/** Form model data (for condition evaluation and relationship filterOptions) */\n\treadonly formModel = input<Record<string, unknown>>({});\n\n\t/** Form mode */\n\treadonly mode = input<EntityFormMode>('create');\n\n\t/** Field path (unused for layout fields, kept for interface consistency) */\n\treadonly path = input.required<string>();\n\n\t/** Computed label */\n\treadonly label = computed(() => this.field().label || '');\n\n\t/** Computed description */\n\treadonly description = computed(() => this.field().description || '');\n\n\t/** Child fields */\n\treadonly subFields = computed((): Field[] => {\n\t\tconst f = this.field();\n\t\tif (f.type === 'row') {\n\t\t\treturn f.fields.filter((sf) => !sf.admin?.hidden);\n\t\t}\n\t\treturn [];\n\t});\n\n\t/** CSS grid columns: equal width for each child */\n\treadonly gridColumns = computed((): string => {\n\t\tconst count = this.subFields().length;\n\t\treturn `repeat(${count}, 1fr)`;\n\t});\n\n\t/** Get a FieldTree sub-node for a child field (flat path from root tree) */\n\tgetChildFormNode(fieldName: string): unknown {\n\t\treturn getSubNode(this.formTree(), fieldName);\n\t}\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, input, signal, effect, untracked, computed, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
+
import { Router, ActivatedRoute } from '@angular/router';
|
|
4
|
+
import { Tabs, TabsList, TabsTrigger, TabsContent } from '@momentumcms/ui';
|
|
5
|
+
import { isNamedTab } from '@momentumcms/core';
|
|
6
|
+
import { b as getSubNode, F as FieldRenderer } from './momentumcms-admin-momentumcms-admin-o0FbJXZN.mjs';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Tabs layout field renderer.
|
|
10
|
+
*
|
|
11
|
+
* Organizes child fields into tabbed sections. This is a layout-only field;
|
|
12
|
+
* it does not store data itself. Child field FieldTree nodes are looked up
|
|
13
|
+
* from the root formTree using flat field names.
|
|
14
|
+
*
|
|
15
|
+
* The selected tab is persisted as a URL query parameter (keyed by field name)
|
|
16
|
+
* so it survives page refreshes.
|
|
17
|
+
*/
|
|
18
|
+
class TabsFieldRenderer {
|
|
19
|
+
router = inject(Router);
|
|
20
|
+
route = inject(ActivatedRoute);
|
|
21
|
+
/** Field definition (must be a TabsField) */
|
|
22
|
+
field = input.required(...(ngDevMode ? [{ debugName: "field" }] : []));
|
|
23
|
+
/** Root signal forms FieldTree (for looking up child field nodes) */
|
|
24
|
+
formTree = input(null, ...(ngDevMode ? [{ debugName: "formTree" }] : []));
|
|
25
|
+
/** Form model data (for condition evaluation and relationship filterOptions) */
|
|
26
|
+
formModel = input({}, ...(ngDevMode ? [{ debugName: "formModel" }] : []));
|
|
27
|
+
/** Form mode */
|
|
28
|
+
mode = input('create', ...(ngDevMode ? [{ debugName: "mode" }] : []));
|
|
29
|
+
/** Field path (unused for layout fields, kept for interface consistency) */
|
|
30
|
+
path = input.required(...(ngDevMode ? [{ debugName: "path" }] : []));
|
|
31
|
+
/** Currently selected tab — defaults to first tab or URL query param */
|
|
32
|
+
selectedTab = signal('', ...(ngDevMode ? [{ debugName: "selectedTab" }] : []));
|
|
33
|
+
/** Skips URL sync for the initial tab selection (default or query param restore) */
|
|
34
|
+
skipNextSync = true;
|
|
35
|
+
constructor() {
|
|
36
|
+
// Initialize selected tab: prefer query param, then fall back to first tab
|
|
37
|
+
effect(() => {
|
|
38
|
+
const configs = this.tabConfigs();
|
|
39
|
+
if (this.selectedTab() === '' && configs.length > 0) {
|
|
40
|
+
const fieldName = untracked(() => this.field().name);
|
|
41
|
+
const queryTab = this.route.snapshot.queryParams[fieldName];
|
|
42
|
+
const tabLabels = new Set(configs.map((t) => t.label));
|
|
43
|
+
this.skipNextSync = true;
|
|
44
|
+
if (typeof queryTab === 'string' && tabLabels.has(queryTab)) {
|
|
45
|
+
this.selectedTab.set(queryTab);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
this.selectedTab.set(configs[0].label);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
// Sync tab changes to URL query params (skip initial selection)
|
|
53
|
+
effect(() => {
|
|
54
|
+
const tab = this.selectedTab();
|
|
55
|
+
const fieldName = this.field().name;
|
|
56
|
+
if (tab === '')
|
|
57
|
+
return;
|
|
58
|
+
if (this.skipNextSync) {
|
|
59
|
+
this.skipNextSync = false;
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
this.router.navigate([], {
|
|
63
|
+
queryParams: { [fieldName]: tab },
|
|
64
|
+
queryParamsHandling: 'merge',
|
|
65
|
+
replaceUrl: true,
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
/** Computed label */
|
|
70
|
+
label = computed(() => this.field().label || '', ...(ngDevMode ? [{ debugName: "label" }] : []));
|
|
71
|
+
/** Computed description */
|
|
72
|
+
description = computed(() => this.field().description || '', ...(ngDevMode ? [{ debugName: "description" }] : []));
|
|
73
|
+
/** Tab configurations from the field */
|
|
74
|
+
tabConfigs = computed(() => {
|
|
75
|
+
const f = this.field();
|
|
76
|
+
if (f.type === 'tabs') {
|
|
77
|
+
return f.tabs;
|
|
78
|
+
}
|
|
79
|
+
return [];
|
|
80
|
+
}, ...(ngDevMode ? [{ debugName: "tabConfigs" }] : []));
|
|
81
|
+
/** Get visible fields for a tab */
|
|
82
|
+
getTabFields(tab) {
|
|
83
|
+
return tab.fields.filter((f) => !f.admin?.hidden);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Get a FieldTree sub-node for a child field.
|
|
87
|
+
* Named tabs: look up the tab's nested node, then the field within it.
|
|
88
|
+
* Unnamed tabs: flat lookup from root tree (current behavior).
|
|
89
|
+
*/
|
|
90
|
+
getChildFormNode(tab, fieldName) {
|
|
91
|
+
if (isNamedTab(tab)) {
|
|
92
|
+
const tabNode = getSubNode(this.formTree(), tab.name);
|
|
93
|
+
return getSubNode(tabNode, fieldName);
|
|
94
|
+
}
|
|
95
|
+
return getSubNode(this.formTree(), fieldName);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Get the field path for a child field within a tab.
|
|
99
|
+
* Named tabs: returns nested path (e.g., 'seo.metaTitle').
|
|
100
|
+
* Unnamed tabs: returns flat field name (e.g., 'title').
|
|
101
|
+
*/
|
|
102
|
+
getFieldPath(tab, fieldName) {
|
|
103
|
+
if (isNamedTab(tab)) {
|
|
104
|
+
return `${tab.name}.${fieldName}`;
|
|
105
|
+
}
|
|
106
|
+
return fieldName;
|
|
107
|
+
}
|
|
108
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: TabsFieldRenderer, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
109
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: TabsFieldRenderer, isStandalone: true, selector: "mcms-tabs-field-renderer", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, formTree: { classPropertyName: "formTree", publicName: "formTree", isSignal: true, isRequired: false, transformFunction: null }, formModel: { classPropertyName: "formModel", publicName: "formModel", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, path: { classPropertyName: "path", publicName: "path", isSignal: true, isRequired: true, transformFunction: null } }, host: { classAttribute: "block" }, ngImport: i0, template: `
|
|
110
|
+
@if (label()) {
|
|
111
|
+
<h3 class="text-sm font-medium text-foreground mb-3">{{ label() }}</h3>
|
|
112
|
+
}
|
|
113
|
+
@if (description()) {
|
|
114
|
+
<p class="text-sm text-muted-foreground mb-3">{{ description() }}</p>
|
|
115
|
+
}
|
|
116
|
+
<mcms-tabs>
|
|
117
|
+
<mcms-tabs-list [(selectedTab)]="selectedTab">
|
|
118
|
+
@for (tab of tabConfigs(); track tab.label) {
|
|
119
|
+
<mcms-tabs-trigger [value]="tab.label">{{ tab.label }}</mcms-tabs-trigger>
|
|
120
|
+
}
|
|
121
|
+
</mcms-tabs-list>
|
|
122
|
+
@for (tab of tabConfigs(); track tab.label) {
|
|
123
|
+
<mcms-tabs-content [value]="tab.label">
|
|
124
|
+
@if (tab.description) {
|
|
125
|
+
<p class="text-sm text-muted-foreground mb-4">{{ tab.description }}</p>
|
|
126
|
+
}
|
|
127
|
+
<div class="space-y-4 pt-4">
|
|
128
|
+
@for (subField of getTabFields(tab); track subField.name) {
|
|
129
|
+
<mcms-field-renderer
|
|
130
|
+
[field]="subField"
|
|
131
|
+
[formNode]="getChildFormNode(tab, subField.name)"
|
|
132
|
+
[formTree]="formTree()"
|
|
133
|
+
[formModel]="formModel()"
|
|
134
|
+
[mode]="mode()"
|
|
135
|
+
[path]="getFieldPath(tab, subField.name)"
|
|
136
|
+
/>
|
|
137
|
+
}
|
|
138
|
+
</div>
|
|
139
|
+
</mcms-tabs-content>
|
|
140
|
+
}
|
|
141
|
+
</mcms-tabs>
|
|
142
|
+
`, isInline: true, dependencies: [{ kind: "component", type: Tabs, selector: "mcms-tabs", inputs: ["class"] }, { kind: "component", type: TabsList, selector: "mcms-tabs-list", inputs: ["orientation", "selectionMode", "selectedTab", "disabled", "wrap", "class"], outputs: ["selectedTabChange"] }, { kind: "component", type: TabsTrigger, selector: "mcms-tabs-trigger", inputs: ["value", "disabled", "class"] }, { kind: "component", type: TabsContent, selector: "mcms-tabs-content", inputs: ["value", "class"] }, { kind: "component", type: FieldRenderer, selector: "mcms-field-renderer", inputs: ["field", "formNode", "formTree", "formModel", "mode", "path"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
143
|
+
}
|
|
144
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: TabsFieldRenderer, decorators: [{
|
|
145
|
+
type: Component,
|
|
146
|
+
args: [{
|
|
147
|
+
selector: 'mcms-tabs-field-renderer',
|
|
148
|
+
imports: [Tabs, TabsList, TabsTrigger, TabsContent, FieldRenderer],
|
|
149
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
150
|
+
host: { class: 'block' },
|
|
151
|
+
template: `
|
|
152
|
+
@if (label()) {
|
|
153
|
+
<h3 class="text-sm font-medium text-foreground mb-3">{{ label() }}</h3>
|
|
154
|
+
}
|
|
155
|
+
@if (description()) {
|
|
156
|
+
<p class="text-sm text-muted-foreground mb-3">{{ description() }}</p>
|
|
157
|
+
}
|
|
158
|
+
<mcms-tabs>
|
|
159
|
+
<mcms-tabs-list [(selectedTab)]="selectedTab">
|
|
160
|
+
@for (tab of tabConfigs(); track tab.label) {
|
|
161
|
+
<mcms-tabs-trigger [value]="tab.label">{{ tab.label }}</mcms-tabs-trigger>
|
|
162
|
+
}
|
|
163
|
+
</mcms-tabs-list>
|
|
164
|
+
@for (tab of tabConfigs(); track tab.label) {
|
|
165
|
+
<mcms-tabs-content [value]="tab.label">
|
|
166
|
+
@if (tab.description) {
|
|
167
|
+
<p class="text-sm text-muted-foreground mb-4">{{ tab.description }}</p>
|
|
168
|
+
}
|
|
169
|
+
<div class="space-y-4 pt-4">
|
|
170
|
+
@for (subField of getTabFields(tab); track subField.name) {
|
|
171
|
+
<mcms-field-renderer
|
|
172
|
+
[field]="subField"
|
|
173
|
+
[formNode]="getChildFormNode(tab, subField.name)"
|
|
174
|
+
[formTree]="formTree()"
|
|
175
|
+
[formModel]="formModel()"
|
|
176
|
+
[mode]="mode()"
|
|
177
|
+
[path]="getFieldPath(tab, subField.name)"
|
|
178
|
+
/>
|
|
179
|
+
}
|
|
180
|
+
</div>
|
|
181
|
+
</mcms-tabs-content>
|
|
182
|
+
}
|
|
183
|
+
</mcms-tabs>
|
|
184
|
+
`,
|
|
185
|
+
}]
|
|
186
|
+
}], ctorParameters: () => [], propDecorators: { field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }], formTree: [{ type: i0.Input, args: [{ isSignal: true, alias: "formTree", required: false }] }], formModel: [{ type: i0.Input, args: [{ isSignal: true, alias: "formModel", required: false }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], path: [{ type: i0.Input, args: [{ isSignal: true, alias: "path", required: true }] }] } });
|
|
187
|
+
|
|
188
|
+
export { TabsFieldRenderer };
|
|
189
|
+
//# sourceMappingURL=momentumcms-admin-tabs-field.component-mZ4dpZoD.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"momentumcms-admin-tabs-field.component-mZ4dpZoD.mjs","sources":["../../../../libs/admin/src/lib/widgets/entity-form/field-renderers/tabs-field.component.ts"],"sourcesContent":["import {\n\tChangeDetectionStrategy,\n\tComponent,\n\tcomputed,\n\teffect,\n\tinject,\n\tinput,\n\tsignal,\n\tuntracked,\n} from '@angular/core';\nimport { ActivatedRoute, Router } from '@angular/router';\nimport { Tabs, TabsList, TabsTrigger, TabsContent } from '@momentumcms/ui';\nimport type { Field, TabConfig } from '@momentumcms/core';\nimport { isNamedTab } from '@momentumcms/core';\nimport type { EntityFormMode } from '../entity-form.types';\nimport { getSubNode } from '../entity-form.types';\nimport { FieldRenderer } from './field-renderer.component';\n\n/**\n * Tabs layout field renderer.\n *\n * Organizes child fields into tabbed sections. This is a layout-only field;\n * it does not store data itself. Child field FieldTree nodes are looked up\n * from the root formTree using flat field names.\n *\n * The selected tab is persisted as a URL query parameter (keyed by field name)\n * so it survives page refreshes.\n */\n@Component({\n\tselector: 'mcms-tabs-field-renderer',\n\timports: [Tabs, TabsList, TabsTrigger, TabsContent, FieldRenderer],\n\tchangeDetection: ChangeDetectionStrategy.OnPush,\n\thost: { class: 'block' },\n\ttemplate: `\n\t\t@if (label()) {\n\t\t\t<h3 class=\"text-sm font-medium text-foreground mb-3\">{{ label() }}</h3>\n\t\t}\n\t\t@if (description()) {\n\t\t\t<p class=\"text-sm text-muted-foreground mb-3\">{{ description() }}</p>\n\t\t}\n\t\t<mcms-tabs>\n\t\t\t<mcms-tabs-list [(selectedTab)]=\"selectedTab\">\n\t\t\t\t@for (tab of tabConfigs(); track tab.label) {\n\t\t\t\t\t<mcms-tabs-trigger [value]=\"tab.label\">{{ tab.label }}</mcms-tabs-trigger>\n\t\t\t\t}\n\t\t\t</mcms-tabs-list>\n\t\t\t@for (tab of tabConfigs(); track tab.label) {\n\t\t\t\t<mcms-tabs-content [value]=\"tab.label\">\n\t\t\t\t\t@if (tab.description) {\n\t\t\t\t\t\t<p class=\"text-sm text-muted-foreground mb-4\">{{ tab.description }}</p>\n\t\t\t\t\t}\n\t\t\t\t\t<div class=\"space-y-4 pt-4\">\n\t\t\t\t\t\t@for (subField of getTabFields(tab); track subField.name) {\n\t\t\t\t\t\t\t<mcms-field-renderer\n\t\t\t\t\t\t\t\t[field]=\"subField\"\n\t\t\t\t\t\t\t\t[formNode]=\"getChildFormNode(tab, subField.name)\"\n\t\t\t\t\t\t\t\t[formTree]=\"formTree()\"\n\t\t\t\t\t\t\t\t[formModel]=\"formModel()\"\n\t\t\t\t\t\t\t\t[mode]=\"mode()\"\n\t\t\t\t\t\t\t\t[path]=\"getFieldPath(tab, subField.name)\"\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t}\n\t\t\t\t\t</div>\n\t\t\t\t</mcms-tabs-content>\n\t\t\t}\n\t\t</mcms-tabs>\n\t`,\n})\nexport class TabsFieldRenderer {\n\tprivate readonly router = inject(Router);\n\tprivate readonly route = inject(ActivatedRoute);\n\n\t/** Field definition (must be a TabsField) */\n\treadonly field = input.required<Field>();\n\n\t/** Root signal forms FieldTree (for looking up child field nodes) */\n\treadonly formTree = input<unknown>(null);\n\n\t/** Form model data (for condition evaluation and relationship filterOptions) */\n\treadonly formModel = input<Record<string, unknown>>({});\n\n\t/** Form mode */\n\treadonly mode = input<EntityFormMode>('create');\n\n\t/** Field path (unused for layout fields, kept for interface consistency) */\n\treadonly path = input.required<string>();\n\n\t/** Currently selected tab — defaults to first tab or URL query param */\n\treadonly selectedTab = signal('');\n\n\t/** Skips URL sync for the initial tab selection (default or query param restore) */\n\tprivate skipNextSync = true;\n\n\tconstructor() {\n\t\t// Initialize selected tab: prefer query param, then fall back to first tab\n\t\teffect(() => {\n\t\t\tconst configs = this.tabConfigs();\n\t\t\tif (this.selectedTab() === '' && configs.length > 0) {\n\t\t\t\tconst fieldName = untracked(() => this.field().name);\n\t\t\t\tconst queryTab = this.route.snapshot.queryParams[fieldName];\n\t\t\t\tconst tabLabels = new Set(configs.map((t) => t.label));\n\n\t\t\t\tthis.skipNextSync = true;\n\t\t\t\tif (typeof queryTab === 'string' && tabLabels.has(queryTab)) {\n\t\t\t\t\tthis.selectedTab.set(queryTab);\n\t\t\t\t} else {\n\t\t\t\t\tthis.selectedTab.set(configs[0].label);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t// Sync tab changes to URL query params (skip initial selection)\n\t\teffect(() => {\n\t\t\tconst tab = this.selectedTab();\n\t\t\tconst fieldName = this.field().name;\n\t\t\tif (tab === '') return;\n\n\t\t\tif (this.skipNextSync) {\n\t\t\t\tthis.skipNextSync = false;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.router.navigate([], {\n\t\t\t\tqueryParams: { [fieldName]: tab },\n\t\t\t\tqueryParamsHandling: 'merge',\n\t\t\t\treplaceUrl: true,\n\t\t\t});\n\t\t});\n\t}\n\n\t/** Computed label */\n\treadonly label = computed(() => this.field().label || '');\n\n\t/** Computed description */\n\treadonly description = computed(() => this.field().description || '');\n\n\t/** Tab configurations from the field */\n\treadonly tabConfigs = computed((): TabConfig[] => {\n\t\tconst f = this.field();\n\t\tif (f.type === 'tabs') {\n\t\t\treturn f.tabs;\n\t\t}\n\t\treturn [];\n\t});\n\n\t/** Get visible fields for a tab */\n\tgetTabFields(tab: TabConfig): Field[] {\n\t\treturn tab.fields.filter((f) => !f.admin?.hidden);\n\t}\n\n\t/**\n\t * Get a FieldTree sub-node for a child field.\n\t * Named tabs: look up the tab's nested node, then the field within it.\n\t * Unnamed tabs: flat lookup from root tree (current behavior).\n\t */\n\tgetChildFormNode(tab: TabConfig, fieldName: string): unknown {\n\t\tif (isNamedTab(tab)) {\n\t\t\tconst tabNode = getSubNode(this.formTree(), tab.name);\n\t\t\treturn getSubNode(tabNode, fieldName);\n\t\t}\n\t\treturn getSubNode(this.formTree(), fieldName);\n\t}\n\n\t/**\n\t * Get the field path for a child field within a tab.\n\t * Named tabs: returns nested path (e.g., 'seo.metaTitle').\n\t * Unnamed tabs: returns flat field name (e.g., 'title').\n\t */\n\tgetFieldPath(tab: TabConfig, fieldName: string): string {\n\t\tif (isNamedTab(tab)) {\n\t\t\treturn `${tab.name}.${fieldName}`;\n\t\t}\n\t\treturn fieldName;\n\t}\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { A as AdminShellComponent,
|
|
1
|
+
export { A as AdminShellComponent, f as AdminSidebarWidget, B as BlockEditDialog, h as BlockInserterComponent, j as BlockWrapperComponent, C as CheckboxFieldRenderer, k as CollectionAccessService, l as CollectionCardWidget, m as CollectionEditPage, o as CollectionListPage, p as CollectionViewPage, D as DashboardPage, q as DateFieldRenderer, E as EntityFormWidget, r as EntityListWidget, d as EntitySheetService, s as EntityViewWidget, t as FeedbackService, F as FieldRenderer, u as FieldRendererRegistry, v as ForgotPasswordFormComponent, w as ForgotPasswordPage, L as LivePreviewComponent, x as LoginPage, M as MOMENTUM_API, y as MOMENTUM_API_CONTEXT, z as McmsThemeService, G as MediaLibraryPage, H as MediaPickerDialog, I as MediaPreviewComponent, J as MomentumApiService, K as MomentumAuthService, N as NumberFieldRenderer, P as PublishControlsWidget, R as ResetPasswordFormComponent, O as ResetPasswordPage, S as SHEET_QUERY_PARAMS, Q as SKIP_AUTO_TOAST, T as SelectFieldRenderer, U as SetupPage, V as TextFieldRenderer, W as UploadFieldRenderer, X as UploadService, Y as VersionHistoryWidget, Z as VersionService, _ as VisualBlockEditorComponent, $ as adminGuard, a0 as authGuard, a1 as collectionAccessGuard, a2 as crudToastInterceptor, a as getFieldNodeState, b as getSubNode, e as getTitleField, a3 as guestGuard, a4 as injectHasAnyRole, a5 as injectHasRole, a6 as injectIsAdmin, a7 as injectIsAuthenticated, a8 as injectMomentumAPI, a9 as injectTypedMomentumAPI, aa as injectUser, ab as injectUserRole, ac as injectVersionService, ad as momentumAdminRoutes, ae as provideFieldRenderer, af as provideMomentumAPI, ag as provideMomentumFieldRenderers, ah as setupGuard, ai as unsavedChangesGuard } from './momentumcms-admin-momentumcms-admin-o0FbJXZN.mjs';
|
|
2
2
|
//# sourceMappingURL=momentumcms-admin.mjs.map
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Routes, CanActivateFn, CanDeactivateFn } from '@angular/router';
|
|
2
2
|
import * as _angular_core from '@angular/core';
|
|
3
|
-
import { Type, InjectionToken, Signal, Provider, OnInit, WritableSignal, ElementRef } from '@angular/core';
|
|
4
|
-
import { CollectionConfig, GlobalConfig, PluginAdminRouteDescriptor, MomentumPlugin, MomentumConfig, MediaDocument, AdminConfig, Field, DocumentStatus as DocumentStatus$1, BlockConfig, UploadField } from '@momentumcms/core';
|
|
3
|
+
import { Type, InjectionToken, Signal, Provider, OnInit, WritableSignal, ElementRef, makeEnvironmentProviders } from '@angular/core';
|
|
4
|
+
import { CollectionConfig, GlobalConfig, PluginAdminRouteDescriptor, MomentumPlugin, MomentumConfig, MomentumAdminConfig, MediaDocument, AdminConfig, Field, DocumentStatus as DocumentStatus$1, BlockConfig, UploadField } from '@momentumcms/core';
|
|
5
5
|
import { HttpContextToken, HttpInterceptorFn } from '@angular/common/http';
|
|
6
6
|
import { Observable } from 'rxjs';
|
|
7
7
|
import { DataTableColumn, DataTableSort, DataTableRowAction, DataTableRowActionEvent, FieldDisplayType, FieldDisplayFieldMeta, FieldDisplayNumberFormat, FieldDisplayDateFormat, PopoverTrigger, ValidationError, SelectOption } from '@momentumcms/ui';
|
|
@@ -95,6 +95,7 @@ interface MomentumAdminRouteData {
|
|
|
95
95
|
* ```
|
|
96
96
|
*/
|
|
97
97
|
declare function momentumAdminRoutes(config: MomentumConfig): Routes;
|
|
98
|
+
declare function momentumAdminRoutes(adminConfig: MomentumAdminConfig): Routes;
|
|
98
99
|
declare function momentumAdminRoutes(options: MomentumAdminOptions): Routes;
|
|
99
100
|
|
|
100
101
|
/**
|
|
@@ -1446,13 +1447,13 @@ declare class McmsThemeService {
|
|
|
1446
1447
|
*
|
|
1447
1448
|
* @example
|
|
1448
1449
|
* ```typescript
|
|
1449
|
-
* import type {
|
|
1450
|
+
* import type { AuthUser } from './generated/momentum.types';
|
|
1450
1451
|
* import { injectUser } from '@momentumcms/admin';
|
|
1451
1452
|
*
|
|
1452
1453
|
* @Component({...})
|
|
1453
1454
|
* export class MyComponent {
|
|
1454
1455
|
* // Typed user from your generated types
|
|
1455
|
-
* readonly user = injectUser<
|
|
1456
|
+
* readonly user = injectUser<AuthUser>();
|
|
1456
1457
|
*
|
|
1457
1458
|
* // Or use convenience functions
|
|
1458
1459
|
* readonly isAdmin = injectIsAdmin();
|
|
@@ -1485,11 +1486,11 @@ interface BaseUser {
|
|
|
1485
1486
|
*
|
|
1486
1487
|
* @example
|
|
1487
1488
|
* ```typescript
|
|
1488
|
-
* import type {
|
|
1489
|
+
* import type { AuthUser } from './generated/momentum.types';
|
|
1489
1490
|
*
|
|
1490
1491
|
* @Component({...})
|
|
1491
1492
|
* export class ProfileComponent {
|
|
1492
|
-
* readonly user = injectUser<
|
|
1493
|
+
* readonly user = injectUser<AuthUser>();
|
|
1493
1494
|
*
|
|
1494
1495
|
* constructor() {
|
|
1495
1496
|
* effect(() => {
|
|
@@ -3035,7 +3036,7 @@ declare class MediaPreviewComponent {
|
|
|
3035
3036
|
/** Image URL for preview */
|
|
3036
3037
|
readonly imageUrl: _angular_core.Signal<string>;
|
|
3037
3038
|
/** Icon name based on media type */
|
|
3038
|
-
readonly iconName: _angular_core.Signal<"<svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" aria-hidden=\"true\" data-slot=\"icon\" style=\"stroke-width:var(--ng-icon__stroke-width, 1.5)\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M3.375 19.5h17.25m-17.25 0a1.125 1.125 0 0 1-1.125-1.125M3.375 19.5h1.5C5.496 19.5 6 18.996 6 18.375m-3.75 0V5.625m0 12.75v-1.5c0-.621.504-1.125 1.125-1.125m18.375 2.625V5.625m0 12.75c0 .621-.504 1.125-1.125 1.125m1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125m0 3.75h-1.5A1.125 1.125 0 0 1 18 18.375M20.625 4.5H3.375m17.25 0c.621 0 1.125.504 1.125 1.125M20.625 4.5h-1.5C18.504 4.5 18 5.004 18 5.625m3.75 0v1.5c0 .621-.504 1.125-1.125 1.125M3.375 4.5c-.621 0-1.125.504-1.125 1.125M3.375 4.5h1.5C5.496 4.5 6 5.004 6 5.625m-3.75 0v1.5c0 .621.504 1.125 1.125 1.125m0 0h1.5m-1.5 0c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125m1.5-3.75C5.496 8.25 6 7.746 6 7.125v-1.5M4.875 8.25C5.496 8.25 6 8.754 6 9.375v1.5m0-5.25v5.25m0-5.25C6 5.004 6.504 4.5 7.125 4.5h9.75c.621 0 1.125.504 1.125 1.125m1.125 2.625h1.5m-1.5 0A1.125 1.125 0 0 1 18 7.125v-1.5m1.125 2.625c-.621 0-1.125.504-1.125 1.125v1.5m2.625-2.625c.621 0 1.125.504 1.125 1.125v1.5c0 .621-.504 1.125-1.125 1.125M18 5.625v5.25M7.125 12h9.75m-9.75 0A1.125 1.125 0 0 1 6 10.875M7.125 12C6.504 12 6 12.504 6 13.125m0-2.25C6 11.496 5.496 12 4.875 12M18 10.875c0 .621-.504 1.125-1.125 1.125M18 10.875c0 .621.504 1.125 1.125 1.125m-2.25 0c.621 0 1.125.504 1.125 1.125m-12 5.25v-5.25m0 5.25c0 .621.504 1.125 1.125 1.125h9.75c.621 0 1.125-.504 1.125-1.125m-12 0v-1.5c0-.621-.504-1.125-1.125-1.125M18 18.375v-5.25m0 5.25v-1.5c0-.621.504-1.125 1.125-1.125M18 13.125v1.5c0 .621.504 1.125 1.125 1.125M18 13.125c0-.621.504-1.125 1.125-1.125M6 13.125v1.5c0 .621-.504 1.125-1.125 1.125M6 13.125C6 12.504 5.496 12 4.875 12m-1.5 0h1.5m-1.5 0c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125M19.125 12h1.5m0 0c.621 0 1.125.504 1.125 1.125v1.5c0 .621-.504 1.125-1.125 1.125m-17.25 0h1.5m14.25 0h1.5\"></path></svg>" | "<svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" aria-hidden=\"true\" data-slot=\"icon\" style=\"stroke-width:var(--ng-icon__stroke-width, 1.5)\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"m9 9 10.5-3m0 6.553v3.75a2.25 2.25 0 0 1-1.632 2.163l-1.32.377a1.803 1.803 0 1 1-.99-3.467l2.31-.66a2.25 2.25 0 0 0 1.632-2.163Zm0 0V2.25L9 5.25v10.303m0 0v3.75a2.25 2.25 0 0 1-1.632 2.163l-1.32.377a1.803 1.803 0 0 1-.99-3.467l2.31-.66A2.25 2.25 0 0 0 9 15.553Z\"></path></svg>" | "<svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" aria-hidden=\"true\" data-slot=\"icon\" style=\"stroke-width:var(--ng-icon__stroke-width, 1.5)\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"
|
|
3039
|
+
readonly iconName: _angular_core.Signal<"<svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" aria-hidden=\"true\" data-slot=\"icon\" style=\"stroke-width:var(--ng-icon__stroke-width, 1.5)\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"m2.25 15.75 5.159-5.159a2.25 2.25 0 0 1 3.182 0l5.159 5.159m-1.5-1.5 1.409-1.409a2.25 2.25 0 0 1 3.182 0l2.909 2.909m-18 3.75h16.5a1.5 1.5 0 0 0 1.5-1.5V6a1.5 1.5 0 0 0-1.5-1.5H3.75A1.5 1.5 0 0 0 2.25 6v12a1.5 1.5 0 0 0 1.5 1.5Zm10.5-11.25h.008v.008h-.008V8.25Zm.375 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Z\"></path></svg>" | "<svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" aria-hidden=\"true\" data-slot=\"icon\" style=\"stroke-width:var(--ng-icon__stroke-width, 1.5)\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m2.25 0H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z\"></path></svg>" | "<svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" aria-hidden=\"true\" data-slot=\"icon\" style=\"stroke-width:var(--ng-icon__stroke-width, 1.5)\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m0 12.75h7.5m-7.5 3H12M10.5 2.25H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z\"></path></svg>" | "<svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" aria-hidden=\"true\" data-slot=\"icon\" style=\"stroke-width:var(--ng-icon__stroke-width, 1.5)\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M3.375 19.5h17.25m-17.25 0a1.125 1.125 0 0 1-1.125-1.125M3.375 19.5h1.5C5.496 19.5 6 18.996 6 18.375m-3.75 0V5.625m0 12.75v-1.5c0-.621.504-1.125 1.125-1.125m18.375 2.625V5.625m0 12.75c0 .621-.504 1.125-1.125 1.125m1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125m0 3.75h-1.5A1.125 1.125 0 0 1 18 18.375M20.625 4.5H3.375m17.25 0c.621 0 1.125.504 1.125 1.125M20.625 4.5h-1.5C18.504 4.5 18 5.004 18 5.625m3.75 0v1.5c0 .621-.504 1.125-1.125 1.125M3.375 4.5c-.621 0-1.125.504-1.125 1.125M3.375 4.5h1.5C5.496 4.5 6 5.004 6 5.625m-3.75 0v1.5c0 .621.504 1.125 1.125 1.125m0 0h1.5m-1.5 0c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125m1.5-3.75C5.496 8.25 6 7.746 6 7.125v-1.5M4.875 8.25C5.496 8.25 6 8.754 6 9.375v1.5m0-5.25v5.25m0-5.25C6 5.004 6.504 4.5 7.125 4.5h9.75c.621 0 1.125.504 1.125 1.125m1.125 2.625h1.5m-1.5 0A1.125 1.125 0 0 1 18 7.125v-1.5m1.125 2.625c-.621 0-1.125.504-1.125 1.125v1.5m2.625-2.625c.621 0 1.125.504 1.125 1.125v1.5c0 .621-.504 1.125-1.125 1.125M18 5.625v5.25M7.125 12h9.75m-9.75 0A1.125 1.125 0 0 1 6 10.875M7.125 12C6.504 12 6 12.504 6 13.125m0-2.25C6 11.496 5.496 12 4.875 12M18 10.875c0 .621-.504 1.125-1.125 1.125M18 10.875c0 .621.504 1.125 1.125 1.125m-2.25 0c.621 0 1.125.504 1.125 1.125m-12 5.25v-5.25m0 5.25c0 .621.504 1.125 1.125 1.125h9.75c.621 0 1.125-.504 1.125-1.125m-12 0v-1.5c0-.621-.504-1.125-1.125-1.125M18 18.375v-5.25m0 5.25v-1.5c0-.621.504-1.125 1.125-1.125M18 13.125v1.5c0 .621.504 1.125 1.125 1.125M18 13.125c0-.621.504-1.125 1.125-1.125M6 13.125v1.5c0 .621-.504 1.125-1.125 1.125M6 13.125C6 12.504 5.496 12 4.875 12m-1.5 0h1.5m-1.5 0c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125M19.125 12h1.5m0 0c.621 0 1.125.504 1.125 1.125v1.5c0 .621-.504 1.125-1.125 1.125m-17.25 0h1.5m14.25 0h1.5\"></path></svg>" | "<svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" aria-hidden=\"true\" data-slot=\"icon\" style=\"stroke-width:var(--ng-icon__stroke-width, 1.5)\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"m9 9 10.5-3m0 6.553v3.75a2.25 2.25 0 0 1-1.632 2.163l-1.32.377a1.803 1.803 0 1 1-.99-3.467l2.31-.66a2.25 2.25 0 0 0 1.632-2.163Zm0 0V2.25L9 5.25v10.303m0 0v3.75a2.25 2.25 0 0 1-1.632 2.163l-1.32.377a1.803 1.803 0 0 1-.99-3.467l2.31-.66A2.25 2.25 0 0 0 9 15.553Z\"></path></svg>" | "<svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" aria-hidden=\"true\" data-slot=\"icon\" style=\"stroke-width:var(--ng-icon__stroke-width, 1.5)\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"m20.25 7.5-.625 10.632a2.25 2.25 0 0 1-2.247 2.118H6.622a2.25 2.25 0 0 1-2.247-2.118L3.75 7.5M10 11.25h4M3.375 7.5h17.25c.621 0 1.125-.504 1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125H3.375c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125Z\"></path></svg>">;
|
|
3039
3040
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<MediaPreviewComponent, never>;
|
|
3040
3041
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<MediaPreviewComponent, "mcms-media-preview", never, { "media": { "alias": "media"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "class": { "alias": "class"; "required": false; "isSignal": true; }; "rounded": { "alias": "rounded"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
3041
3042
|
}
|
|
@@ -3266,12 +3267,63 @@ declare class BlockEditDialog {
|
|
|
3266
3267
|
}
|
|
3267
3268
|
|
|
3268
3269
|
/**
|
|
3269
|
-
*
|
|
3270
|
+
* Registry for field renderer components.
|
|
3270
3271
|
*
|
|
3271
|
-
*
|
|
3272
|
-
*
|
|
3272
|
+
* Maps field type names (e.g., 'text', 'number', 'blocks') to lazy component loaders.
|
|
3273
|
+
* Eliminates static imports and enables custom field types via `provideFieldRenderer()`.
|
|
3274
|
+
*
|
|
3275
|
+
* Built-in renderers are registered via `provideMomentumFieldRenderers()` in app bootstrap.
|
|
3276
|
+
*/
|
|
3277
|
+
declare class FieldRendererRegistry {
|
|
3278
|
+
private readonly renderers;
|
|
3279
|
+
/** Register a lazy loader for a field type. Later registrations override earlier ones. */
|
|
3280
|
+
register(type: string, loader: () => Promise<Type<unknown>>): void;
|
|
3281
|
+
/** Get the lazy loader for a field type. Returns undefined if not registered. */
|
|
3282
|
+
get(type: string): (() => Promise<Type<unknown>>) | undefined;
|
|
3283
|
+
/** Check if a field type has a registered renderer. */
|
|
3284
|
+
has(type: string): boolean;
|
|
3285
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<FieldRendererRegistry, never>;
|
|
3286
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<FieldRendererRegistry>;
|
|
3287
|
+
}
|
|
3288
|
+
|
|
3289
|
+
/**
|
|
3290
|
+
* Register all built-in Momentum CMS field renderers.
|
|
3291
|
+
*
|
|
3292
|
+
* Call this in your app's `providers` array (e.g., `app.config.ts`):
|
|
3293
|
+
* ```typescript
|
|
3294
|
+
* export const appConfig: ApplicationConfig = {
|
|
3295
|
+
* providers: [
|
|
3296
|
+
* provideMomentumFieldRenderers(),
|
|
3297
|
+
* ],
|
|
3298
|
+
* };
|
|
3299
|
+
* ```
|
|
3300
|
+
*/
|
|
3301
|
+
declare function provideMomentumFieldRenderers(): ReturnType<typeof makeEnvironmentProviders>;
|
|
3302
|
+
/**
|
|
3303
|
+
* Register a custom field renderer for a specific field type.
|
|
3304
|
+
*
|
|
3305
|
+
* ```typescript
|
|
3306
|
+
* export const appConfig: ApplicationConfig = {
|
|
3307
|
+
* providers: [
|
|
3308
|
+
* provideMomentumFieldRenderers(),
|
|
3309
|
+
* provideFieldRenderer('color', () =>
|
|
3310
|
+
* import('./renderers/color-field.component').then(m => m.ColorFieldRenderer)
|
|
3311
|
+
* ),
|
|
3312
|
+
* ],
|
|
3313
|
+
* };
|
|
3314
|
+
* ```
|
|
3315
|
+
*/
|
|
3316
|
+
declare function provideFieldRenderer(type: string, loader: () => Promise<Type<unknown>>): ReturnType<typeof makeEnvironmentProviders>;
|
|
3317
|
+
|
|
3318
|
+
/**
|
|
3319
|
+
* Dynamic field renderer that resolves components lazily from the registry.
|
|
3320
|
+
*
|
|
3321
|
+
* Uses `NgComponentOutlet` to render the appropriate field renderer component
|
|
3322
|
+
* based on the field type, resolved from `FieldRendererRegistry`.
|
|
3323
|
+
* Falls back to the `text` renderer for unknown types.
|
|
3273
3324
|
*/
|
|
3274
3325
|
declare class FieldRenderer {
|
|
3326
|
+
private readonly registry;
|
|
3275
3327
|
/** Field definition */
|
|
3276
3328
|
readonly field: _angular_core.InputSignal<Field>;
|
|
3277
3329
|
/** Signal forms FieldTree node for this field */
|
|
@@ -3284,8 +3336,22 @@ declare class FieldRenderer {
|
|
|
3284
3336
|
readonly mode: _angular_core.InputSignal<EntityFormMode>;
|
|
3285
3337
|
/** Field path (for nested fields) */
|
|
3286
3338
|
readonly path: _angular_core.InputSignal<string>;
|
|
3287
|
-
/**
|
|
3288
|
-
readonly
|
|
3339
|
+
/** Resolved component type, set after lazy loading completes */
|
|
3340
|
+
readonly resolvedComponent: _angular_core.WritableSignal<Type<unknown> | null>;
|
|
3341
|
+
/** Error from lazy loading failure */
|
|
3342
|
+
readonly loadError: _angular_core.WritableSignal<Error | null>;
|
|
3343
|
+
/** Registry key: 'blocks-visual' when blocks field has visual editor, otherwise field.type */
|
|
3344
|
+
readonly registryKey: _angular_core.Signal<"number" | "slug" | "email" | "text" | "textarea" | "richText" | "date" | "checkbox" | "select" | "radio" | "password" | "upload" | "relationship" | "array" | "group" | "blocks" | "json" | "point" | "tabs" | "collapsible" | "row" | "blocks-visual">;
|
|
3345
|
+
/** Inputs to pass to the dynamically loaded component via NgComponentOutlet */
|
|
3346
|
+
readonly rendererInputs: _angular_core.Signal<{
|
|
3347
|
+
field: Field;
|
|
3348
|
+
formNode: unknown;
|
|
3349
|
+
formTree: unknown;
|
|
3350
|
+
formModel: Record<string, unknown>;
|
|
3351
|
+
mode: EntityFormMode;
|
|
3352
|
+
path: string;
|
|
3353
|
+
}>;
|
|
3354
|
+
constructor();
|
|
3289
3355
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<FieldRenderer, never>;
|
|
3290
3356
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<FieldRenderer, "mcms-field-renderer", never, { "field": { "alias": "field"; "required": true; "isSignal": true; }; "formNode": { "alias": "formNode"; "required": false; "isSignal": true; }; "formTree": { "alias": "formTree"; "required": false; "isSignal": true; }; "formModel": { "alias": "formModel"; "required": false; "isSignal": true; }; "mode": { "alias": "mode"; "required": false; "isSignal": true; }; "path": { "alias": "path"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
3291
3357
|
}
|
|
@@ -3702,5 +3768,5 @@ declare class MediaPickerDialog {
|
|
|
3702
3768
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<MediaPickerDialog, "mcms-media-picker-dialog", never, {}, {}, never, never, true, never>;
|
|
3703
3769
|
}
|
|
3704
3770
|
|
|
3705
|
-
export { AdminShellComponent, AdminSidebarWidget, BlockEditDialog, BlockInserterComponent, BlockWrapperComponent, CheckboxFieldRenderer, CollectionAccessService, CollectionCardWidget, CollectionEditPage, CollectionListPage, CollectionViewPage, DashboardPage, DateFieldRenderer, EntityFormWidget, EntityListWidget, EntitySheetService, EntityViewWidget, FeedbackService, FieldRenderer, ForgotPasswordFormComponent, ForgotPasswordPage, LivePreviewComponent, LoginPage, MOMENTUM_API, MOMENTUM_API_CONTEXT, McmsThemeService, MediaLibraryPage, MediaPickerDialog, MediaPreviewComponent, MomentumApiService, MomentumAuthService, NumberFieldRenderer, PublishControlsWidget, ResetPasswordFormComponent, ResetPasswordPage, SHEET_QUERY_PARAMS, SKIP_AUTO_TOAST, SelectFieldRenderer, SetupPage, TextFieldRenderer, UploadFieldRenderer, UploadService, VersionHistoryWidget, VersionService, VisualBlockEditorComponent, adminGuard, authGuard, collectionAccessGuard, crudToastInterceptor, getFieldNodeState, getSubNode, getTitleField, guestGuard, injectHasAnyRole, injectHasRole, injectIsAdmin, injectIsAuthenticated, injectMomentumAPI, injectTypedMomentumAPI, injectUser, injectUserRole, injectVersionService, momentumAdminRoutes, provideMomentumAPI, setupGuard, unsavedChangesGuard };
|
|
3771
|
+
export { AdminShellComponent, AdminSidebarWidget, BlockEditDialog, BlockInserterComponent, BlockWrapperComponent, CheckboxFieldRenderer, CollectionAccessService, CollectionCardWidget, CollectionEditPage, CollectionListPage, CollectionViewPage, DashboardPage, DateFieldRenderer, EntityFormWidget, EntityListWidget, EntitySheetService, EntityViewWidget, FeedbackService, FieldRenderer, FieldRendererRegistry, ForgotPasswordFormComponent, ForgotPasswordPage, LivePreviewComponent, LoginPage, MOMENTUM_API, MOMENTUM_API_CONTEXT, McmsThemeService, MediaLibraryPage, MediaPickerDialog, MediaPreviewComponent, MomentumApiService, MomentumAuthService, NumberFieldRenderer, PublishControlsWidget, ResetPasswordFormComponent, ResetPasswordPage, SHEET_QUERY_PARAMS, SKIP_AUTO_TOAST, SelectFieldRenderer, SetupPage, TextFieldRenderer, UploadFieldRenderer, UploadService, VersionHistoryWidget, VersionService, VisualBlockEditorComponent, adminGuard, authGuard, collectionAccessGuard, crudToastInterceptor, getFieldNodeState, getSubNode, getTitleField, guestGuard, injectHasAnyRole, injectHasRole, injectIsAdmin, injectIsAuthenticated, injectMomentumAPI, injectTypedMomentumAPI, injectUser, injectUserRole, injectVersionService, momentumAdminRoutes, provideFieldRenderer, provideMomentumAPI, provideMomentumFieldRenderers, setupGuard, unsavedChangesGuard };
|
|
3706
3772
|
export type { AdminBranding, AdminNavItem, AdminNavSection, AdminPluginRoute, AdminUser, AuthResult, AuthSession, AuthUser, BaseUser, BlockEditDialogData, BlockItem, BreadcrumbItem, CollectionPermissions, CollectionWithCount, DeleteResult, DeviceSize, DocumentStatus, DocumentVersionParsed, DraftSaveResult, Entity, EntityAction, EntityFormMode, EntityListActionEvent, EntityListBulkActionEvent, EntityListColumn, EntityListFindResult, EntitySheetResult, EntityViewActionEvent, EntityViewFieldConfig, FieldNodeState, FindByIdOptions, FindOptions, FindResult, HasUnsavedChanges, McmsTheme, MediaPickerDialogData, MediaPickerResult, MediaPreviewData, MomentumAPIContext, MomentumAPIServer, MomentumAdminBranding, MomentumAdminOptions, MomentumAdminRouteData, MomentumClientAPI, MomentumCollectionAPI, PublishResult, RestoreResult, RestoreVersionOptions, SetupStatus, StatusResult, TypedCollectionAPI, TypedFindByIdOptions, TypedFindOptions, TypedMomentumClientAPI, UploadProgress, UserContext, VersionFindOptions, VersionQueryResult, VisualEditorState };
|