@aglyn/plugins-mui 1.0.0-beta.214 → 1.0.0-beta.216

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.
Files changed (59) hide show
  1. package/package.json +7 -7
  2. package/src/lib/components/collection-author-links.d.ts +41 -0
  3. package/src/lib/components/collection-author-links.js +135 -0
  4. package/src/lib/components/collection-author-links.js.map +1 -0
  5. package/src/lib/components/collection-author-profile.d.ts +67 -0
  6. package/src/lib/components/collection-author-profile.js +269 -0
  7. package/src/lib/components/collection-author-profile.js.map +1 -0
  8. package/src/lib/components/collection-categories.d.ts +52 -0
  9. package/src/lib/components/collection-categories.js +163 -0
  10. package/src/lib/components/collection-categories.js.map +1 -0
  11. package/src/lib/components/collection-common.d.ts +104 -0
  12. package/src/lib/components/collection-common.js +95 -0
  13. package/src/lib/components/collection-common.js.map +1 -0
  14. package/src/lib/components/collection-entries.d.ts +137 -0
  15. package/src/lib/components/collection-entries.js +358 -0
  16. package/src/lib/components/collection-entries.js.map +1 -0
  17. package/src/lib/components/collection-entry-author.d.ts +81 -0
  18. package/src/lib/components/collection-entry-author.js +259 -0
  19. package/src/lib/components/collection-entry-author.js.map +1 -0
  20. package/src/lib/components/collection-entry-body.d.ts +44 -0
  21. package/src/lib/components/collection-entry-body.js +328 -0
  22. package/src/lib/components/collection-entry-body.js.map +1 -0
  23. package/src/lib/components/collection-entry-meta.d.ts +88 -0
  24. package/src/lib/components/collection-entry-meta.js +331 -0
  25. package/src/lib/components/collection-entry-meta.js.map +1 -0
  26. package/src/lib/components/collection-presets.d.ts +18 -0
  27. package/src/lib/components/collection-presets.js +328 -0
  28. package/src/lib/components/collection-presets.js.map +1 -0
  29. package/src/lib/components/collection-related.d.ts +101 -0
  30. package/src/lib/components/collection-related.js +536 -0
  31. package/src/lib/components/collection-related.js.map +1 -0
  32. package/src/lib/components/collection-search-box.d.ts +92 -0
  33. package/src/lib/components/collection-search-box.js +334 -0
  34. package/src/lib/components/collection-search-box.js.map +1 -0
  35. package/src/lib/components/collection-search-fuse.d.ts +28 -0
  36. package/src/lib/components/collection-search-fuse.js +28 -0
  37. package/src/lib/components/collection-search-fuse.js.map +1 -0
  38. package/src/lib/components/collection-search.d.ts +62 -0
  39. package/src/lib/components/collection-search.js +140 -0
  40. package/src/lib/components/collection-search.js.map +1 -0
  41. package/src/lib/components/collection-share.d.ts +31 -0
  42. package/src/lib/components/collection-share.js +154 -0
  43. package/src/lib/components/collection-share.js.map +1 -0
  44. package/src/lib/components/collection.d.ts +19 -497
  45. package/src/lib/components/collection.js +19 -2982
  46. package/src/lib/components/collection.js.map +1 -1
  47. package/src/lib/components/image-list.d.ts +2 -2
  48. package/src/lib/components/image-list.js +4 -6
  49. package/src/lib/components/image-list.js.map +1 -1
  50. package/src/lib/components/theme-mode-switcher.js +19 -19
  51. package/src/lib/components/theme-mode-switcher.js.map +1 -1
  52. package/src/lib/element-tier.d.ts +9 -1
  53. package/src/lib/element-tier.js +12 -1
  54. package/src/lib/element-tier.js.map +1 -1
  55. package/src/lib/plugin.js +20 -12
  56. package/src/lib/plugin.js.map +1 -1
  57. package/src/lib/utils/to-count.d.ts +25 -0
  58. package/src/lib/utils/to-count.js +30 -0
  59. package/src/lib/utils/to-count.js.map +1 -0
@@ -0,0 +1,328 @@
1
+ import { _ as _extends } from "@swc/helpers/_/_extends";
2
+ import { _ as _object_without_properties_loose } from "@swc/helpers/_/_object_without_properties_loose";
3
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
4
+ /**
5
+ * @license
6
+ * Copyright 2026 Aglyn LLC
7
+ *
8
+ * Licensed under the Apache License, Version 2.0 (the "License");
9
+ * you may not use this file except in compliance with the License.
10
+ * You may obtain a copy of the License at
11
+ *
12
+ * http://www.apache.org/licenses/LICENSE-2.0
13
+ *
14
+ * Unless required by applicable law or agreed to in writing, software
15
+ * distributed under the License is distributed on an "AS IS" BASIS,
16
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ * See the License for the specific language governing permissions and
18
+ * limitations under the License.
19
+ */ import * as Aglyn from "@aglyn/aglyn";
20
+ import { mdiTextLong } from "@aglyn/shared-data-mdi";
21
+ import { AppLink } from "@aglyn/shared-ui-jsx";
22
+ import Box from "@mui/material/Box";
23
+ import MuiLink from "@mui/material/Link";
24
+ import Typography from "@mui/material/Typography";
25
+ import { forwardRef, useContext, useMemo } from "react";
26
+ import { BUNDLE_ID } from "../constants/bundle-common.js";
27
+ import { UNRESOLVED_TOKEN } from "./collection-common.js";
28
+ // Persisted component id (AGL-551/582); the compose pipeline references it
29
+ // through the @aglyn/aglyn constant. Never rename.
30
+ export const ENTRY_BODY_ID = Aglyn.COLLECTION_ENTRY_BODY_COMPONENT_ID;
31
+ const renderInlines = (inlines, links)=>inlines.map((item, index)=>{
32
+ if (item.type === 'bold') return /*#__PURE__*/ _jsx("strong", {
33
+ children: item.text
34
+ }, index);
35
+ if (item.type === 'italic') return /*#__PURE__*/ _jsx("em", {
36
+ children: item.text
37
+ }, index);
38
+ if (item.type !== 'link') return /*#__PURE__*/ _jsx("span", {
39
+ children: item.text
40
+ }, index);
41
+ // Internal paths route through AppLink for client-side navigation
42
+ // (AGL-582); external links stay plain anchors. Editing surfaces render
43
+ // the link look without an href so clicks never navigate. A target named
44
+ // by REFERENCE resolves against the routing map first (AGL-3118), and one
45
+ // whose entry, listing or screen is gone renders as the words alone —
46
+ // never as an anchor holding the stored value.
47
+ const link = Aglyn.resolveMarkdownLink(item.href, links);
48
+ if (link.kind === 'text') return /*#__PURE__*/ _jsx("span", {
49
+ children: item.text
50
+ }, index);
51
+ if (link.kind === 'inert') {
52
+ return /*#__PURE__*/ _jsx(MuiLink, {
53
+ component: "span",
54
+ sx: {
55
+ cursor: 'default'
56
+ },
57
+ children: item.text
58
+ }, index);
59
+ }
60
+ return link.kind === 'internal' ? /*#__PURE__*/ _jsx(AppLink, {
61
+ href: link.href,
62
+ children: item.text
63
+ }, index) : /*#__PURE__*/ _jsx(MuiLink, {
64
+ href: link.href,
65
+ children: item.text
66
+ }, index);
67
+ });
68
+ /**
69
+ * Renders a content entry's markdown-lite body as themed MUI elements
70
+ * (AGL-551): headings, paragraphs, lists, and images pick up the site
71
+ * theme's typography instead of the old unthemed article HTML. Parsing is
72
+ * pure, so the full body server-renders (SEO keeps the article text).
73
+ */ const CollectionEntryBody = /*#__PURE__*/ forwardRef((props, ref)=>{
74
+ // `intrinsicSizes` is destructured out rather than left in `rest`: `rest` is
75
+ // spread onto a Box, and a composition-stamped object would reach the DOM as
76
+ // an attribute React has no idea what to do with.
77
+ const { markdown, intrinsicSizes } = props, rest = _object_without_properties_loose(props, [
78
+ "markdown",
79
+ "intrinsicSizes"
80
+ ]);
81
+ // Node styles ride the renderer-merged sx; recompose (stack.ts pattern).
82
+ const nodeSx = Array.isArray(props['sx']) ? props['sx'] : [
83
+ props['sx']
84
+ ];
85
+ // The routing map travels with the suppression flag: both decide what a
86
+ // link in this body renders as (AGL-3118).
87
+ const { suppressNavigation, screens } = useContext(Aglyn.ScreenLinkContext);
88
+ const links = useMemo(()=>({
89
+ suppressNavigation,
90
+ screens
91
+ }), [
92
+ suppressNavigation,
93
+ screens
94
+ ]);
95
+ // The site being rendered, for image blocks (AGL-1686) — read once here
96
+ // because hooks cannot run inside the block map below.
97
+ const { hostId } = Aglyn.useSite();
98
+ const source = (markdown != null ? markdown : '').trim();
99
+ const unresolved = !source || UNRESOLVED_TOKEN.test(source);
100
+ const blocks = useMemo(()=>unresolved ? [] : Aglyn.parseMarkdownLite(source), [
101
+ source,
102
+ unresolved
103
+ ]);
104
+ // Heading anchors, on the same terms as the Markdown element (AGL-1162).
105
+ // Without them a blog article could not carry an "On this page" aside at
106
+ // all: the Table of Contents element emits `#slug` links, and there was
107
+ // nothing on this page for them to land on.
108
+ const slugs = useMemo(()=>Aglyn.markdownHeadingSlugs(blocks), [
109
+ blocks
110
+ ]);
111
+ if (unresolved) {
112
+ // Editing surfaces get an affordance; the published site renders
113
+ // nothing rather than a literal token.
114
+ if (!suppressNavigation) return /*#__PURE__*/ _jsx(Box, _extends({
115
+ ref: ref
116
+ }, rest));
117
+ return /*#__PURE__*/ _jsx(Box, _extends({
118
+ ref: ref
119
+ }, rest, {
120
+ sx: [
121
+ {
122
+ p: 2,
123
+ border: '1px dashed',
124
+ borderColor: 'divider',
125
+ color: 'text.secondary',
126
+ fontSize: 12,
127
+ fontFamily: 'system-ui, sans-serif'
128
+ },
129
+ ...nodeSx
130
+ ],
131
+ children: 'Entry body — the {{entry.body}} markdown renders here'
132
+ }));
133
+ }
134
+ return /*#__PURE__*/ _jsx(Box, _extends({
135
+ ref: ref
136
+ }, rest, {
137
+ children: blocks.map((block, index)=>{
138
+ if (block.type === 'heading') {
139
+ return /*#__PURE__*/ _jsx(Typography, {
140
+ id: slugs[index],
141
+ variant: block.level === 2 ? 'h4' : 'h5',
142
+ component: block.level === 2 ? 'h2' : 'h3',
143
+ gutterBottom: true,
144
+ sx: {
145
+ scrollMarginTop: `${Aglyn.HEADING_ANCHOR_SCROLL_MARGIN}px`
146
+ },
147
+ children: renderInlines(block.inlines, links)
148
+ }, index);
149
+ }
150
+ if (block.type === 'image') {
151
+ return /*#__PURE__*/ _jsx(Box, _extends({
152
+ component: "img"
153
+ }, Aglyn.mediaBodyImageAttributes({
154
+ src: block.src,
155
+ hostId,
156
+ size: intrinsicSizes == null ? void 0 : intrinsicSizes[block.src]
157
+ }), {
158
+ alt: block.alt,
159
+ // Paired with the `width`/`height` above — see the Markdown
160
+ // element's copy of this: without it the height hint outlives
161
+ // the `maxWidth` cap and squashes the picture.
162
+ sx: {
163
+ maxWidth: '100%',
164
+ height: 'auto',
165
+ borderRadius: 1,
166
+ my: 1
167
+ }
168
+ }, Aglyn.DEFERRED_IMAGE_ATTRIBUTES), index);
169
+ }
170
+ if (block.type === 'list') {
171
+ return /*#__PURE__*/ _jsx(Box, {
172
+ component: "ul",
173
+ sx: {
174
+ lineHeight: 1.7,
175
+ pl: 3
176
+ },
177
+ children: block.items.map((item, itemIndex)=>/*#__PURE__*/ _jsx("li", {
178
+ children: renderInlines(item, links)
179
+ }, itemIndex))
180
+ }, index);
181
+ }
182
+ // A numbered list (AGL-1320) — a real `<ol>`, so the markers are the
183
+ // browser's and `start` survives: a notice that resumes at 7 has to
184
+ // read as 7 for the enumeration to mean anything.
185
+ if (block.type === 'orderedList') {
186
+ return /*#__PURE__*/ _jsx(Box, {
187
+ component: "ol",
188
+ start: block.start,
189
+ sx: {
190
+ lineHeight: 1.7,
191
+ pl: 3
192
+ },
193
+ children: block.items.map((item, itemIndex)=>/*#__PURE__*/ _jsx("li", {
194
+ children: renderInlines(item, links)
195
+ }, itemIndex))
196
+ }, index);
197
+ }
198
+ // Code blocks and tables (AGL-974). Both scroll rather than wrap:
199
+ // a wrapped code line or a squeezed table column loses the very
200
+ // structure that made the block worth writing.
201
+ if (block.type === 'code') {
202
+ return /*#__PURE__*/ _jsx(Box, {
203
+ component: "pre",
204
+ sx: {
205
+ my: 2,
206
+ p: 2,
207
+ overflowX: 'auto',
208
+ borderRadius: 1,
209
+ bgcolor: 'action.hover',
210
+ fontFamily: 'monospace',
211
+ fontSize: 14
212
+ },
213
+ children: /*#__PURE__*/ _jsx("code", {
214
+ children: block.text
215
+ })
216
+ }, index);
217
+ }
218
+ if (block.type === 'table') {
219
+ return /*#__PURE__*/ _jsx(Box, {
220
+ sx: {
221
+ my: 2,
222
+ overflowX: 'auto'
223
+ },
224
+ children: /*#__PURE__*/ _jsxs(Box, {
225
+ component: "table",
226
+ sx: {
227
+ borderCollapse: 'collapse',
228
+ width: '100%',
229
+ '& th, & td': {
230
+ border: '1px solid',
231
+ borderColor: 'divider',
232
+ px: 1.5,
233
+ py: 1
234
+ },
235
+ '& th': {
236
+ bgcolor: 'action.hover'
237
+ }
238
+ },
239
+ children: [
240
+ /*#__PURE__*/ _jsx("thead", {
241
+ children: /*#__PURE__*/ _jsx("tr", {
242
+ children: block.header.map((cell, cellIndex)=>{
243
+ var _block_align_cellIndex;
244
+ return /*#__PURE__*/ _jsx("th", {
245
+ style: {
246
+ textAlign: (_block_align_cellIndex = block.align[cellIndex]) != null ? _block_align_cellIndex : 'left'
247
+ },
248
+ children: renderInlines(cell, links)
249
+ }, cellIndex);
250
+ })
251
+ })
252
+ }),
253
+ /*#__PURE__*/ _jsx("tbody", {
254
+ children: block.rows.map((row, rowIndex)=>/*#__PURE__*/ _jsx("tr", {
255
+ children: row.map((cell, cellIndex)=>{
256
+ var _block_align_cellIndex;
257
+ return /*#__PURE__*/ _jsx("td", {
258
+ style: {
259
+ textAlign: (_block_align_cellIndex = block.align[cellIndex]) != null ? _block_align_cellIndex : 'left'
260
+ },
261
+ children: renderInlines(cell, links)
262
+ }, cellIndex);
263
+ })
264
+ }, rowIndex))
265
+ })
266
+ ]
267
+ })
268
+ }, index);
269
+ }
270
+ // The article template's pull-quote (AGL-1315, Figma 170:225):
271
+ // larger italic prose behind a left accent. Palette tokens only, so
272
+ // it follows the site theme in both modes.
273
+ if (block.type === 'quote') {
274
+ return /*#__PURE__*/ _jsx(Typography, {
275
+ component: "blockquote",
276
+ sx: {
277
+ my: 3,
278
+ mx: 0,
279
+ pl: 2.5,
280
+ borderLeft: '3px solid',
281
+ borderColor: 'primary.main',
282
+ fontStyle: 'italic',
283
+ fontSize: '1.25em',
284
+ lineHeight: 1.6,
285
+ color: 'text.primary'
286
+ },
287
+ children: renderInlines(block.inlines, links)
288
+ }, index);
289
+ }
290
+ return /*#__PURE__*/ _jsx(Typography, {
291
+ variant: "body1",
292
+ sx: {
293
+ lineHeight: 1.7
294
+ },
295
+ gutterBottom: true,
296
+ children: renderInlines(block.inlines, links)
297
+ }, index);
298
+ })
299
+ }));
300
+ });
301
+ CollectionEntryBody.displayName = 'AglynCollectionEntryBody';
302
+ export const collectionEntryBodySchema = {
303
+ $id: ENTRY_BODY_ID,
304
+ pluginId: BUNDLE_ID,
305
+ displayName: 'Entry Body',
306
+ description: "The current entry's markdown body, on an entry template.",
307
+ category: Aglyn.ComponentCategory.TEXT,
308
+ icon: {
309
+ path: mdiTextLong.path,
310
+ sx: {
311
+ color: 'secondary.main'
312
+ }
313
+ },
314
+ flags: {
315
+ selfClosing: Aglyn.FEATURE_FLAG.ENABLED
316
+ },
317
+ attributes: [
318
+ {
319
+ name: 'markdown',
320
+ label: 'Markdown',
321
+ description: 'Markdown-lite content. Keep {{entry.body}} on entry-template ' + "screens so each entry's body renders here.",
322
+ component: Aglyn.FieldComponentType.TEXT_FIELD
323
+ }
324
+ ]
325
+ };
326
+ export { CollectionEntryBody };
327
+
328
+ //# sourceMappingURL=collection-entry-body.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/collection-entry-body.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as Aglyn from '@aglyn/aglyn'\nimport { mdiTextLong } from '@aglyn/shared-data-mdi'\nimport { AppLink } from '@aglyn/shared-ui-jsx'\nimport Box from '@mui/material/Box'\nimport MuiLink from '@mui/material/Link'\nimport Typography from '@mui/material/Typography'\nimport type { ReactNode } from 'react'\nimport { forwardRef, useContext, useMemo } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport { UNRESOLVED_TOKEN } from './collection-common'\n\n// Persisted component id (AGL-551/582); the compose pipeline references it\n// through the @aglyn/aglyn constant. Never rename.\nexport const ENTRY_BODY_ID: Aglyn.ComponentId =\n Aglyn.COLLECTION_ENTRY_BODY_COMPONENT_ID\n\nexport interface CollectionEntryBodyProps {\n /**\n * Markdown-lite source. On entry-template screens `{{entry.body}}`\n * resolves to the rendered entry's body at compose time.\n */\n markdown?: string\n /**\n * The pixel pair of each library image this body names, keyed by the target\n * as the body writes it, stamped by the composition from the assets' DAM\n * records (AGL-3149) — never set by hand, and never on the template, where\n * `markdown` is still the `{{entry.body}}` token and names no asset.\n */\n intrinsicSizes?: Record<string, { width: number; height: number }>\n}\n\nconst renderInlines = (\n inlines: Aglyn.MarkdownInline[],\n links: { suppressNavigation?: boolean; screens?: Aglyn.ScreenRouteMap },\n): ReactNode[] =>\n inlines.map((item, index) => {\n if (item.type === 'bold') return <strong key={index}>{item.text}</strong>\n if (item.type === 'italic') return <em key={index}>{item.text}</em>\n if (item.type !== 'link') return <span key={index}>{item.text}</span>\n // Internal paths route through AppLink for client-side navigation\n // (AGL-582); external links stay plain anchors. Editing surfaces render\n // the link look without an href so clicks never navigate. A target named\n // by REFERENCE resolves against the routing map first (AGL-3118), and one\n // whose entry, listing or screen is gone renders as the words alone —\n // never as an anchor holding the stored value.\n const link = Aglyn.resolveMarkdownLink(item.href, links)\n if (link.kind === 'text') return <span key={index}>{item.text}</span>\n if (link.kind === 'inert') {\n return (\n <MuiLink key={index} component=\"span\" sx={{ cursor: 'default' }}>\n {item.text}\n </MuiLink>\n )\n }\n return link.kind === 'internal' ? (\n <AppLink key={index} href={link.href}>\n {item.text}\n </AppLink>\n ) : (\n <MuiLink key={index} href={link.href}>\n {item.text}\n </MuiLink>\n )\n })\n\n/**\n * Renders a content entry's markdown-lite body as themed MUI elements\n * (AGL-551): headings, paragraphs, lists, and images pick up the site\n * theme's typography instead of the old unthemed article HTML. Parsing is\n * pure, so the full body server-renders (SEO keeps the article text).\n */\nconst CollectionEntryBody = forwardRef<\n HTMLDivElement,\n CollectionEntryBodyProps\n>((props, ref) => {\n // `intrinsicSizes` is destructured out rather than left in `rest`: `rest` is\n // spread onto a Box, and a composition-stamped object would reach the DOM as\n // an attribute React has no idea what to do with.\n const { markdown, intrinsicSizes, ...rest } = props\n // Node styles ride the renderer-merged sx; recompose (stack.ts pattern).\n const nodeSx = Array.isArray(props['sx']) ? props['sx'] : [props['sx']]\n // The routing map travels with the suppression flag: both decide what a\n // link in this body renders as (AGL-3118).\n const { suppressNavigation, screens } = useContext(Aglyn.ScreenLinkContext)\n const links = useMemo(\n () => ({ suppressNavigation, screens }),\n [suppressNavigation, screens],\n )\n // The site being rendered, for image blocks (AGL-1686) — read once here\n // because hooks cannot run inside the block map below.\n const { hostId } = Aglyn.useSite()\n const source = (markdown ?? '').trim()\n const unresolved = !source || UNRESOLVED_TOKEN.test(source)\n const blocks = useMemo(\n () => (unresolved ? [] : Aglyn.parseMarkdownLite(source)),\n [source, unresolved],\n )\n // Heading anchors, on the same terms as the Markdown element (AGL-1162).\n // Without them a blog article could not carry an \"On this page\" aside at\n // all: the Table of Contents element emits `#slug` links, and there was\n // nothing on this page for them to land on.\n const slugs = useMemo(() => Aglyn.markdownHeadingSlugs(blocks), [blocks])\n if (unresolved) {\n // Editing surfaces get an affordance; the published site renders\n // nothing rather than a literal token.\n if (!suppressNavigation) return <Box ref={ref} {...rest} />\n return (\n <Box\n ref={ref}\n {...rest}\n sx={[\n {\n p: 2,\n border: '1px dashed',\n borderColor: 'divider',\n color: 'text.secondary',\n fontSize: 12,\n fontFamily: 'system-ui, sans-serif',\n },\n ...nodeSx,\n ]}\n >\n {'Entry body — the {{entry.body}} markdown renders here'}\n </Box>\n )\n }\n return (\n <Box ref={ref} {...rest}>\n {blocks.map((block, index) => {\n if (block.type === 'heading') {\n return (\n <Typography\n key={index}\n id={slugs[index]}\n variant={block.level === 2 ? 'h4' : 'h5'}\n component={block.level === 2 ? 'h2' : 'h3'}\n gutterBottom\n sx={{\n scrollMarginTop: `${Aglyn.HEADING_ANCHOR_SCROLL_MARGIN}px`,\n }}\n >\n {renderInlines(block.inlines, links)}\n </Typography>\n )\n }\n if (block.type === 'image') {\n return (\n <Box\n key={index}\n component=\"img\"\n // Resolved like the related cover image in collection-related.tsx\n // (AGL-1686): a body image is the same kind of asset and\n // has no reason to be stored in a more fragile form.\n //\n // And sized like one too, as of AGL-3149: the same call gives\n // the Markdown element's body images their candidate list and\n // intrinsic pair, so the two bodies cannot disagree about how a\n // picture in prose is delivered.\n {...Aglyn.mediaBodyImageAttributes({\n src: block.src,\n hostId,\n size: intrinsicSizes?.[block.src],\n })}\n alt={block.alt}\n // Paired with the `width`/`height` above — see the Markdown\n // element's copy of this: without it the height hint outlives\n // the `maxWidth` cap and squashes the picture.\n sx={{ maxWidth: '100%', height: 'auto', borderRadius: 1, my: 1 }}\n // An image inside an entry body is below the fold by\n // construction — the title, byline and opening paragraphs are\n // above it. This one carried no loading hint at all, so it was\n // fetched EAGERLY, at default priority, competing with the\n // entry's own cover (AGL-2486).\n {...Aglyn.DEFERRED_IMAGE_ATTRIBUTES}\n />\n )\n }\n if (block.type === 'list') {\n return (\n <Box key={index} component=\"ul\" sx={{ lineHeight: 1.7, pl: 3 }}>\n {block.items.map((item, itemIndex) => (\n <li key={itemIndex}>\n {renderInlines(item, links)}\n </li>\n ))}\n </Box>\n )\n }\n // A numbered list (AGL-1320) — a real `<ol>`, so the markers are the\n // browser's and `start` survives: a notice that resumes at 7 has to\n // read as 7 for the enumeration to mean anything.\n if (block.type === 'orderedList') {\n return (\n <Box\n key={index}\n component=\"ol\"\n start={block.start}\n sx={{ lineHeight: 1.7, pl: 3 }}\n >\n {block.items.map((item, itemIndex) => (\n <li key={itemIndex}>\n {renderInlines(item, links)}\n </li>\n ))}\n </Box>\n )\n }\n // Code blocks and tables (AGL-974). Both scroll rather than wrap:\n // a wrapped code line or a squeezed table column loses the very\n // structure that made the block worth writing.\n if (block.type === 'code') {\n return (\n <Box\n key={index}\n component=\"pre\"\n sx={{\n my: 2,\n p: 2,\n overflowX: 'auto',\n borderRadius: 1,\n bgcolor: 'action.hover',\n fontFamily: 'monospace',\n fontSize: 14,\n }}\n >\n <code>{block.text}</code>\n </Box>\n )\n }\n if (block.type === 'table') {\n return (\n <Box key={index} sx={{ my: 2, overflowX: 'auto' }}>\n <Box\n component=\"table\"\n sx={{\n borderCollapse: 'collapse',\n width: '100%',\n '& th, & td': {\n border: '1px solid',\n borderColor: 'divider',\n px: 1.5,\n py: 1,\n },\n '& th': { bgcolor: 'action.hover' },\n }}\n >\n <thead>\n <tr>\n {block.header.map((cell, cellIndex) => (\n <th\n key={cellIndex}\n style={{ textAlign: block.align[cellIndex] ?? 'left' }}\n >\n {renderInlines(cell, links)}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {block.rows.map((row, rowIndex) => (\n <tr key={rowIndex}>\n {row.map((cell, cellIndex) => (\n <td\n key={cellIndex}\n style={{\n textAlign: block.align[cellIndex] ?? 'left',\n }}\n >\n {renderInlines(cell, links)}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </Box>\n </Box>\n )\n }\n // The article template's pull-quote (AGL-1315, Figma 170:225):\n // larger italic prose behind a left accent. Palette tokens only, so\n // it follows the site theme in both modes.\n if (block.type === 'quote') {\n return (\n <Typography\n key={index}\n component=\"blockquote\"\n sx={{\n my: 3,\n mx: 0,\n pl: 2.5,\n borderLeft: '3px solid',\n borderColor: 'primary.main',\n fontStyle: 'italic',\n fontSize: '1.25em',\n lineHeight: 1.6,\n color: 'text.primary',\n }}\n >\n {renderInlines(block.inlines, links)}\n </Typography>\n )\n }\n return (\n <Typography\n key={index}\n variant=\"body1\"\n sx={{ lineHeight: 1.7 }}\n gutterBottom\n >\n {renderInlines(block.inlines, links)}\n </Typography>\n )\n })}\n </Box>\n )\n})\nCollectionEntryBody.displayName = 'AglynCollectionEntryBody'\n\nexport const collectionEntryBodySchema: Aglyn.ComponentSchema<CollectionEntryBodyProps> =\n {\n $id: ENTRY_BODY_ID,\n pluginId: BUNDLE_ID,\n displayName: 'Entry Body',\n description: \"The current entry's markdown body, on an entry template.\",\n category: Aglyn.ComponentCategory.TEXT,\n icon: { path: mdiTextLong.path, sx: { color: 'secondary.main' } },\n flags: { selfClosing: Aglyn.FEATURE_FLAG.ENABLED },\n attributes: [\n {\n name: 'markdown',\n label: 'Markdown',\n description:\n 'Markdown-lite content. Keep {{entry.body}} on entry-template ' +\n \"screens so each entry's body renders here.\",\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n },\n ],\n }\n\nexport { CollectionEntryBody }\n"],"names":["Aglyn","mdiTextLong","AppLink","Box","MuiLink","Typography","forwardRef","useContext","useMemo","BUNDLE_ID","UNRESOLVED_TOKEN","ENTRY_BODY_ID","COLLECTION_ENTRY_BODY_COMPONENT_ID","renderInlines","inlines","links","map","item","index","type","strong","text","em","span","link","resolveMarkdownLink","href","kind","component","sx","cursor","CollectionEntryBody","props","ref","markdown","intrinsicSizes","rest","nodeSx","Array","isArray","suppressNavigation","screens","ScreenLinkContext","hostId","useSite","source","trim","unresolved","test","blocks","parseMarkdownLite","slugs","markdownHeadingSlugs","p","border","borderColor","color","fontSize","fontFamily","block","id","variant","level","gutterBottom","scrollMarginTop","HEADING_ANCHOR_SCROLL_MARGIN","mediaBodyImageAttributes","src","size","alt","maxWidth","height","borderRadius","my","DEFERRED_IMAGE_ATTRIBUTES","lineHeight","pl","items","itemIndex","li","start","overflowX","bgcolor","code","borderCollapse","width","px","py","thead","tr","header","cell","cellIndex","th","style","textAlign","align","tbody","rows","row","rowIndex","td","mx","borderLeft","fontStyle","displayName","collectionEntryBodySchema","$id","pluginId","description","category","ComponentCategory","TEXT","icon","path","flags","selfClosing","FEATURE_FLAG","ENABLED","attributes","name","label","FieldComponentType","TEXT_FIELD"],"mappings":"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"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import * as Aglyn from '@aglyn/aglyn';
18
+ import { type StackProps } from '@mui/material/Stack';
19
+ export declare const ENTRY_META_ID: Aglyn.ComponentId;
20
+ export interface CollectionEntryMetaProps extends StackProps {
21
+ /**
22
+ * Published date. Server-filled from the routed entry on entry templates
23
+ * (`expandCollectionEntryMeta`, AGL-1385); set it — or bind
24
+ * `{{entry.date}}` — only to override.
25
+ */
26
+ date?: string;
27
+ /**
28
+ * How {@link date} reads when the server fills it in (AGL-1459) — a
29
+ * COMPOSE-TIME prop, like Related Posts' `limit`: it is answered where the
30
+ * timestamp still exists (`expandCollectionEntryMeta`) and never reaches the
31
+ * DOM. Blank, or `default`, is the locale date the block has always emitted.
32
+ */
33
+ dateFormat?: Aglyn.CollectionEntryDateFormat;
34
+ /**
35
+ * Byline (AGL-1459). Server-filled from the entry's own author on entry
36
+ * templates, exactly like {@link date}; set it — or bind `{{entry.author}}`
37
+ * — only to override.
38
+ */
39
+ author?: string;
40
+ /** Category; server-filled, or bind `{{entry.category}}` to override. */
41
+ category?: string;
42
+ /** Comma-joined tags; server-filled, or bind `{{entry.tags}}`. */
43
+ tags?: string;
44
+ /**
45
+ * Round avatar shown before the byline (AGL-1459) — a media-picker target,
46
+ * so it holds a media reference (AGL-1215) as well as any URL form.
47
+ *
48
+ * A block-level pick, deliberately, and NOT a per-author image: entries
49
+ * carry an author NAME (`authorName`) and no portrait field, so a per-author
50
+ * avatar would need a schema decision on the entry model plus an editor
51
+ * field to fill it. Until then this is the site's brand mark, chosen once on
52
+ * the template — which is what the article frame actually asks for. Left
53
+ * unset it renders nothing at all, never a broken image.
54
+ */
55
+ avatarImage?: string;
56
+ showDate?: boolean;
57
+ showAuthor?: boolean;
58
+ /**
59
+ * Where the byline's NAME links — the author's page on this site
60
+ * (AGL-2519). Server-filled from the routed entry's author, like the
61
+ * avatar beside it; blank renders the name as plain text.
62
+ *
63
+ * Distinct from the author's own `url`, which the Entry Author card offers
64
+ * as a link row: this is "everything they wrote here", that is "their
65
+ * site", and a byline that conflated them would send a reader off-site from
66
+ * every article.
67
+ */
68
+ authorPageUrl?: string;
69
+ /** Off leaves the byline as plain text even when the author has a page. */
70
+ linkAuthor?: boolean;
71
+ showCategory?: boolean;
72
+ showTags?: boolean;
73
+ showAvatar?: boolean;
74
+ }
75
+ /**
76
+ * "{{entry.date}} · {{entry.category}}" meta line plus tag chips
77
+ * (AGL-582). Values arrive through entry tokens on entry renders; on other
78
+ * surfaces unresolved tokens collapse to nothing instead of leaking.
79
+ *
80
+ * On an entry template the tenant now also FILLS the three values from the
81
+ * routed entry when nothing is bound (`expandCollectionEntryMeta`, AGL-1385).
82
+ * Before that, a block dragged from the palette rather than dropped as the
83
+ * preset had no values at all — three "Show" switches gating nothing — and
84
+ * rendered as the empty `<Box>` below, at height 0.
85
+ */
86
+ declare const CollectionEntryMeta: import("react").ForwardRefExoticComponent<Omit<CollectionEntryMetaProps, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
87
+ export declare const collectionEntryMetaSchema: Aglyn.ComponentSchema<CollectionEntryMetaProps>;
88
+ export { CollectionEntryMeta };