@aglyn/plugins-mui 1.0.0-beta.143
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +22 -0
- package/package.json +47 -0
- package/src/index.d.ts +21 -0
- package/src/index.js +22 -0
- package/src/index.js.map +1 -0
- package/src/lib/components/accordion.d.ts +96 -0
- package/src/lib/components/accordion.js +392 -0
- package/src/lib/components/accordion.js.map +1 -0
- package/src/lib/components/app-bar.d.ts +32 -0
- package/src/lib/components/app-bar.js +86 -0
- package/src/lib/components/app-bar.js.map +1 -0
- package/src/lib/components/blocks.d.ts +46 -0
- package/src/lib/components/blocks.js +1007 -0
- package/src/lib/components/blocks.js.map +1 -0
- package/src/lib/components/box.d.ts +47 -0
- package/src/lib/components/box.js +125 -0
- package/src/lib/components/box.js.map +1 -0
- package/src/lib/components/breadcrumbs.d.ts +44 -0
- package/src/lib/components/breadcrumbs.js +172 -0
- package/src/lib/components/breadcrumbs.js.map +1 -0
- package/src/lib/components/button.d.ts +89 -0
- package/src/lib/components/button.js +272 -0
- package/src/lib/components/button.js.map +1 -0
- package/src/lib/components/card.d.ts +61 -0
- package/src/lib/components/card.js +336 -0
- package/src/lib/components/card.js.map +1 -0
- package/src/lib/components/collection.d.ts +514 -0
- package/src/lib/components/collection.js +2999 -0
- package/src/lib/components/collection.js.map +1 -0
- package/src/lib/components/container.d.ts +42 -0
- package/src/lib/components/container.js +169 -0
- package/src/lib/components/container.js.map +1 -0
- package/src/lib/components/custom-html.d.ts +78 -0
- package/src/lib/components/custom-html.js +219 -0
- package/src/lib/components/custom-html.js.map +1 -0
- package/src/lib/components/data-table.d.ts +57 -0
- package/src/lib/components/data-table.js +216 -0
- package/src/lib/components/data-table.js.map +1 -0
- package/src/lib/components/document-root.d.ts +77 -0
- package/src/lib/components/document-root.js +118 -0
- package/src/lib/components/document-root.js.map +1 -0
- package/src/lib/components/drawer.d.ts +93 -0
- package/src/lib/components/drawer.js +566 -0
- package/src/lib/components/drawer.js.map +1 -0
- package/src/lib/components/function-controls.d.ts +66 -0
- package/src/lib/components/function-controls.js +207 -0
- package/src/lib/components/function-controls.js.map +1 -0
- package/src/lib/components/function-scope.d.ts +110 -0
- package/src/lib/components/function-scope.js +478 -0
- package/src/lib/components/function-scope.js.map +1 -0
- package/src/lib/components/function-widget.d.ts +75 -0
- package/src/lib/components/function-widget.js +307 -0
- package/src/lib/components/function-widget.js.map +1 -0
- package/src/lib/components/grid.d.ts +91 -0
- package/src/lib/components/grid.js +322 -0
- package/src/lib/components/grid.js.map +1 -0
- package/src/lib/components/icon.d.ts +54 -0
- package/src/lib/components/icon.js +163 -0
- package/src/lib/components/icon.js.map +1 -0
- package/src/lib/components/image-list.d.ts +58 -0
- package/src/lib/components/image-list.js +336 -0
- package/src/lib/components/image-list.js.map +1 -0
- package/src/lib/components/image.d.ts +154 -0
- package/src/lib/components/image.js +451 -0
- package/src/lib/components/image.js.map +1 -0
- package/src/lib/components/inline-text.d.ts +74 -0
- package/src/lib/components/inline-text.js +407 -0
- package/src/lib/components/inline-text.js.map +1 -0
- package/src/lib/components/language-switcher.d.ts +35 -0
- package/src/lib/components/language-switcher.js +179 -0
- package/src/lib/components/language-switcher.js.map +1 -0
- package/src/lib/components/layout-slot.d.ts +68 -0
- package/src/lib/components/layout-slot.js +192 -0
- package/src/lib/components/layout-slot.js.map +1 -0
- package/src/lib/components/link-box-accessible-name.d.ts +79 -0
- package/src/lib/components/link-box-accessible-name.js +158 -0
- package/src/lib/components/link-box-accessible-name.js.map +1 -0
- package/src/lib/components/link-box.d.ts +66 -0
- package/src/lib/components/link-box.js +212 -0
- package/src/lib/components/link-box.js.map +1 -0
- package/src/lib/components/list-item-text.d.ts +22 -0
- package/src/lib/components/list-item-text.js +86 -0
- package/src/lib/components/list-item-text.js.map +1 -0
- package/src/lib/components/list-item.d.ts +32 -0
- package/src/lib/components/list-item.js +127 -0
- package/src/lib/components/list-item.js.map +1 -0
- package/src/lib/components/list.d.ts +34 -0
- package/src/lib/components/list.js +108 -0
- package/src/lib/components/list.js.map +1 -0
- package/src/lib/components/markdown.d.ts +129 -0
- package/src/lib/components/markdown.js +853 -0
- package/src/lib/components/markdown.js.map +1 -0
- package/src/lib/components/nav-menu.d.ts +68 -0
- package/src/lib/components/nav-menu.js +683 -0
- package/src/lib/components/nav-menu.js.map +1 -0
- package/src/lib/components/pagination.d.ts +59 -0
- package/src/lib/components/pagination.js +243 -0
- package/src/lib/components/pagination.js.map +1 -0
- package/src/lib/components/paper.d.ts +47 -0
- package/src/lib/components/paper.js +202 -0
- package/src/lib/components/paper.js.map +1 -0
- package/src/lib/components/plugin-frame.d.ts +64 -0
- package/src/lib/components/plugin-frame.js +335 -0
- package/src/lib/components/plugin-frame.js.map +1 -0
- package/src/lib/components/plugin.d.ts +95 -0
- package/src/lib/components/plugin.js +304 -0
- package/src/lib/components/plugin.js.map +1 -0
- package/src/lib/components/product.d.ts +40 -0
- package/src/lib/components/product.js +287 -0
- package/src/lib/components/product.js.map +1 -0
- package/src/lib/components/reusable-instance.d.ts +57 -0
- package/src/lib/components/reusable-instance.js +126 -0
- package/src/lib/components/reusable-instance.js.map +1 -0
- package/src/lib/components/screen-link.d.ts +85 -0
- package/src/lib/components/screen-link.js +324 -0
- package/src/lib/components/screen-link.js.map +1 -0
- package/src/lib/components/search-box.d.ts +41 -0
- package/src/lib/components/search-box.js +125 -0
- package/src/lib/components/search-box.js.map +1 -0
- package/src/lib/components/section.d.ts +56 -0
- package/src/lib/components/section.js +132 -0
- package/src/lib/components/section.js.map +1 -0
- package/src/lib/components/stack.d.ts +55 -0
- package/src/lib/components/stack.js +309 -0
- package/src/lib/components/stack.js.map +1 -0
- package/src/lib/components/tabs.d.ts +288 -0
- package/src/lib/components/tabs.js +788 -0
- package/src/lib/components/tabs.js.map +1 -0
- package/src/lib/components/theme-mode-switcher.d.ts +38 -0
- package/src/lib/components/theme-mode-switcher.js +168 -0
- package/src/lib/components/theme-mode-switcher.js.map +1 -0
- package/src/lib/components/toolbar.d.ts +37 -0
- package/src/lib/components/toolbar.js +117 -0
- package/src/lib/components/toolbar.js.map +1 -0
- package/src/lib/components/typography.d.ts +33 -0
- package/src/lib/components/typography.js +433 -0
- package/src/lib/components/typography.js.map +1 -0
- package/src/lib/components/video-lightbox-controls.d.ts +131 -0
- package/src/lib/components/video-lightbox-controls.js +536 -0
- package/src/lib/components/video-lightbox-controls.js.map +1 -0
- package/src/lib/components/video-lightbox.d.ts +60 -0
- package/src/lib/components/video-lightbox.js +247 -0
- package/src/lib/components/video-lightbox.js.map +1 -0
- package/src/lib/components/video-playback-beacon.d.ts +80 -0
- package/src/lib/components/video-playback-beacon.js +128 -0
- package/src/lib/components/video-playback-beacon.js.map +1 -0
- package/src/lib/components/video-player-frame.d.ts +58 -0
- package/src/lib/components/video-player-frame.js +51 -0
- package/src/lib/components/video-player-frame.js.map +1 -0
- package/src/lib/components/video.d.ts +220 -0
- package/src/lib/components/video.js +874 -0
- package/src/lib/components/video.js.map +1 -0
- package/src/lib/constants/bundle-common.d.ts +17 -0
- package/src/lib/constants/bundle-common.js +18 -0
- package/src/lib/constants/bundle-common.js.map +1 -0
- package/src/lib/constants/field-presets.d.ts +93 -0
- package/src/lib/constants/field-presets.js +248 -0
- package/src/lib/constants/field-presets.js.map +1 -0
- package/src/lib/plugin.d.ts +80 -0
- package/src/lib/plugin.js +599 -0
- package/src/lib/plugin.js.map +1 -0
- package/src/lib/utils/author-html-label.d.ts +73 -0
- package/src/lib/utils/author-html-label.js +89 -0
- package/src/lib/utils/author-html-label.js.map +1 -0
- package/src/lib/utils/drop-cleared-props.d.ts +18 -0
- package/src/lib/utils/drop-cleared-props.js +74 -0
- package/src/lib/utils/drop-cleared-props.js.map +1 -0
- package/src/lib/utils/element-picker.d.ts +99 -0
- package/src/lib/utils/element-picker.js +140 -0
- package/src/lib/utils/element-picker.js.map +1 -0
- package/src/lib/utils/generate-preset-id.d.ts +19 -0
- package/src/lib/utils/generate-preset-id.js +25 -0
- package/src/lib/utils/generate-preset-id.js.map +1 -0
- package/src/lib/utils/link-target-props.d.ts +53 -0
- package/src/lib/utils/link-target-props.js +53 -0
- package/src/lib/utils/link-target-props.js.map +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/blocks.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 {\n mdiBullhorn,\n mdiCurrencyUsd,\n mdiFacebook,\n mdiFormatQuoteClose,\n mdiGestureTapButton,\n mdiGithub,\n mdiHelpCircle,\n mdiImage as mdiImageIcon,\n mdiImageText,\n mdiInstagram,\n mdiLinkedin,\n mdiPageLayoutFooter,\n mdiPageLayoutHeader,\n mdiPlayCircle,\n mdiRocketLaunchOutline,\n mdiTwitter,\n mdiViewGridOutline,\n mdiYoutube,\n} from '@aglyn/shared-data-mdi'\nimport { AppLink, MdiIcon } from '@aglyn/shared-ui-jsx'\nimport Box from '@mui/material/Box'\nimport IconButton from '@mui/material/IconButton'\nimport Stack from '@mui/material/Stack'\nimport { forwardRef, useContext } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport { generatePresetId } from '../utils/generate-preset-id'\n\n// Component ids are persisted in screen documents; never rename.\nexport const VIDEO_EMBED_ID: Aglyn.ComponentId = 'videoEmbed'\nexport const SOCIAL_LINKS_ID: Aglyn.ComponentId = 'socialLinks'\n\n/* ── Video embed ─────────────────────────────────────────────────────────── */\n\nexport interface VideoEmbedProps {\n /** YouTube or Vimeo video URL. */\n url?: string\n /** CSS height (default 315px, 16:9-ish with full width). */\n height?: string\n}\n\n/**\n * Builds the embed src from a PARSED video id — the raw user URL is never\n * placed in the iframe, so only youtube-nocookie/vimeo player origins can\n * ever load (block-library security posture).\n */\nexport function parseVideoEmbedSrc(url: string): string | null {\n try {\n const parsed = new URL(url.trim())\n const host = parsed.hostname.replace(/^www\\./, '')\n if (host === 'youtu.be') {\n const id = parsed.pathname.slice(1)\n return /^[\\w-]{6,20}$/.test(id)\n ? `https://www.youtube-nocookie.com/embed/${id}`\n : null\n }\n if (host === 'youtube.com' || host === 'm.youtube.com') {\n const id =\n parsed.searchParams.get('v') ??\n (parsed.pathname.startsWith('/embed/')\n ? parsed.pathname.split('/')[2]\n : parsed.pathname.startsWith('/shorts/')\n ? parsed.pathname.split('/')[2]\n : '')\n return id && /^[\\w-]{6,20}$/.test(id)\n ? `https://www.youtube-nocookie.com/embed/${id}`\n : null\n }\n if (host === 'vimeo.com' || host === 'player.vimeo.com') {\n const id = parsed.pathname.split('/').find((part) => /^\\d{6,}$/.test(part))\n return id ? `https://player.vimeo.com/video/${id}` : null\n }\n } catch {\n /* invalid URL */\n }\n return null\n}\n\nconst VideoEmbed = forwardRef<HTMLDivElement, VideoEmbedProps>(\n (props, ref) => {\n const { url, height, ...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 const { suppressNavigation } = useContext(Aglyn.ScreenLinkContext)\n const src = url ? parseVideoEmbedSrc(url) : null\n if (!src) {\n // The hint is for the author, so only editing surfaces draw it; a\n // published page renders the bare element.\n if (!suppressNavigation) return <Box ref={ref} {...rest} />\n return (\n <Box\n ref={ref}\n {...rest}\n sx={[\n {\n width: '100%',\n height: height || 315,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\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 {'Video — paste a YouTube or Vimeo URL'}\n </Box>\n )\n }\n return (\n <Box\n ref={ref}\n component=\"iframe\"\n src={src}\n title=\"Embedded video\"\n loading=\"lazy\"\n allow=\"accelerometer; encrypted-media; picture-in-picture\"\n allowFullScreen\n sandbox=\"allow-scripts allow-same-origin allow-presentation allow-popups\"\n {...rest}\n sx={[\n {\n display: 'block',\n width: '100%',\n height: height || 315,\n border: 0,\n },\n ...nodeSx,\n ]}\n />\n )\n },\n)\nVideoEmbed.displayName = 'AglynVideoEmbed'\n\nexport const videoEmbedSchema: Aglyn.ComponentSchema<VideoEmbedProps> = {\n $id: VIDEO_EMBED_ID,\n pluginId: BUNDLE_ID,\n displayName: 'Video',\n description: \"Embeds a YouTube or Vimeo player from the video's URL.\",\n category: Aglyn.ComponentCategory.MEDIA,\n icon: { path: mdiPlayCircle.path, sx: { color: '#d32f2f' } },\n flags: { selfClosing: Aglyn.FEATURE_FLAG.ENABLED },\n attributes: [\n {\n name: 'url',\n description: 'YouTube or Vimeo video URL.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n label: 'Video URL',\n },\n {\n name: 'height',\n description: 'Height of the embed — a number plus a unit, e.g. 315px or 50vh.',\n component: Aglyn.FieldComponentType.CSS_DIMENSION,\n label: 'Height',\n },\n ],\n}\n\n/* ── Social links ────────────────────────────────────────────────────────── */\n\nexport interface SocialLinksProps {\n twitter?: string\n instagram?: string\n facebook?: string\n linkedin?: string\n youtube?: string\n github?: string\n}\n\nconst SOCIAL_NETWORKS: Array<{\n key: keyof SocialLinksProps\n label: string\n path: string\n}> = [\n { key: 'twitter', label: 'Twitter / X', path: mdiTwitter.path },\n { key: 'instagram', label: 'Instagram', path: mdiInstagram.path },\n { key: 'facebook', label: 'Facebook', path: mdiFacebook.path },\n { key: 'linkedin', label: 'LinkedIn', path: mdiLinkedin.path },\n { key: 'youtube', label: 'YouTube', path: mdiYoutube.path },\n { key: 'github', label: 'GitHub', path: mdiGithub.path },\n]\n\nconst SAFE_SOCIAL_HREF = /^https:\\/\\//i\n\nconst SocialLinks = forwardRef<HTMLDivElement, SocialLinksProps>(\n (props, ref) => {\n const { suppressNavigation } = useContext(Aglyn.ScreenLinkContext)\n // The profile fields are this element's data, not attributes of its row.\n // Spread onto the Stack, each would be written into the page's HTML as a\n // second copy of the URL, including a URL the filter below refuses.\n const rowProps: Record<string, unknown> = { ...props }\n for (const { key } of SOCIAL_NETWORKS) delete rowProps[key]\n const entries = SOCIAL_NETWORKS.map(({ key, label, path }) => ({\n key,\n label,\n path,\n href: props[key]?.trim(),\n })).filter(\n (entry) => entry.href && SAFE_SOCIAL_HREF.test(entry.href),\n )\n return (\n <Stack ref={ref} direction=\"row\" spacing={0.5} {...rowProps}>\n {entries.length ? (\n entries.map((entry) => (\n <AppLink\n key={entry.key}\n componentVariant=\"icon-button\"\n href={entry.href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n aria-label={entry.label}\n size=\"small\"\n >\n <MdiIcon path={entry.path} />\n </AppLink>\n ))\n ) : suppressNavigation ? (\n // Editing surfaces only: a visitor has no Attributes panel.\n <Box\n sx={{\n color: 'text.secondary',\n fontSize: 12,\n fontFamily: 'system-ui, sans-serif',\n p: 1,\n }}\n >\n {'Social links — add profile URLs in Attributes'}\n </Box>\n ) : null}\n </Stack>\n )\n },\n)\nSocialLinks.displayName = 'AglynSocialLinks'\n\nexport const socialLinksSchema: Aglyn.ComponentSchema<SocialLinksProps> = {\n $id: SOCIAL_LINKS_ID,\n pluginId: BUNDLE_ID,\n displayName: 'Social Links',\n description: 'A row of icon links to whichever social profiles you fill in.',\n category: Aglyn.ComponentCategory.NAVIGATION,\n icon: { path: mdiTwitter.path, sx: { color: '#1976d2' } },\n flags: { selfClosing: Aglyn.FEATURE_FLAG.ENABLED },\n attributes: SOCIAL_NETWORKS.map(({ key, label }) => ({\n name: key,\n description: `${label} profile URL (https).`,\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n label,\n })),\n}\n\n/* ── Section presets (composed from existing components) ────────────────── */\n\n/**\n * Preset styling is authored on the node's OWN `sx`, never inside `props`\n * (AGL-1346).\n *\n * Both records render — `Leaf` composes `(sx, props.sx, node.sx)` — but\n * only `node.sx` is the one the Styles panel writes, so a preset that put\n * its styling in `props.sx` authored values the panel could display but no\n * click could ever change or clear. The renderer composes `node.sx` LAST,\n * so moving a preset's styles here changes nothing about how a fresh\n * insert looks; it only makes them editable. Existing documents keep their\n * `props.sx` and still render from it.\n *\n * `plugin.spec.ts` holds every preset in this bundle to that rule.\n */\nconst text = (variant: string, children: string, extra?: object) => {\n const { sx, ...props } = (extra ?? {}) as Record<string, unknown>\n return {\n $id: null,\n componentId: 'muiTypography',\n pluginId: BUNDLE_ID,\n props: { variant, children, ...props },\n ...(sx ? { sx } : {}),\n }\n}\n\nconst testimonialCard = (quote: string, name: string) => ({\n $id: null,\n componentId: 'muiStack',\n pluginId: BUNDLE_ID,\n props: { spacing: 1 },\n sx: {\n flex: 1,\n paddingTop: 3,\n paddingRight: 3,\n paddingBottom: 3,\n paddingLeft: 3,\n },\n nodes: [\n text('body1', `“${quote}”`),\n text('subtitle2', `— ${name}`),\n ],\n})\n\nconst pricingColumn = (\n tier: string,\n price: string,\n features: string[],\n highlighted?: boolean,\n) => ({\n $id: null,\n componentId: 'muiStack',\n pluginId: BUNDLE_ID,\n props: { spacing: 1 },\n sx: {\n flex: 1,\n paddingTop: 3,\n paddingRight: 3,\n paddingBottom: 3,\n paddingLeft: 3,\n alignItems: 'center',\n ...(highlighted && {\n border: '2px solid',\n borderColor: 'primary.main',\n borderRadius: 2,\n }),\n },\n nodes: [\n text('h5', tier),\n text('h3', price),\n ...features.map((feature) => text('body2', feature)),\n {\n $id: null,\n componentId: 'muiButton',\n pluginId: BUNDLE_ID,\n props: {\n variant: highlighted ? 'contained' : 'outlined',\n children: 'Choose plan',\n },\n },\n ],\n})\n\nconst faqItem = (question: string, answer: string) => [\n text('subtitle1', question),\n text('body2', answer, { gutterBottom: true }),\n]\n\n/** Screen link with the visible-on-any-surface nav defaults (AGL-539). */\nconst navLink = (label: string) => ({\n $id: null,\n componentId: 'muiScreenLink',\n pluginId: BUNDLE_ID,\n props: { children: label, color: 'inherit' },\n})\n\nconst featureColumn = (title: string, body: string) => ({\n $id: null,\n componentId: 'muiStack',\n pluginId: BUNDLE_ID,\n props: { spacing: 1 },\n sx: {\n flex: 1,\n minWidth: 220,\n paddingTop: 2,\n paddingRight: 2,\n paddingBottom: 2,\n paddingLeft: 2,\n },\n nodes: [text('h5', title), text('body1', body)],\n})\n\n/**\n * A section block's outer band, with its content held to a readable width\n * (AGL-2544).\n *\n * These presets used to be a bare `muiStack` dropped straight into\n * `Document`, so every one of them rendered edge to edge: a Feature Grid ran\n * the full viewport while the page's prose sat at 900px, and the FAQ — which\n * had `maxWidth` but no auto margins — hugged the left edge. That is the\n * result of the documented happy path on a fresh screen, with no misuse, and\n * a subscriber has no reason to suspect the block needs wrapping.\n *\n * The band and the content are separated rather than the whole thing being\n * wrapped, because a CTA or hero genuinely wants a full-bleed background with\n * contained content — wrapping the outer node would take that away to fix the\n * width. So `bandSx` (padding, background) stays outside and the Container\n * goes within it.\n *\n * `layout` moves a row block's own direction onto an inner Stack: dropping a\n * Container between a `direction: 'row'` Stack and its columns would leave\n * the Container as the single flex child and collapse the row.\n */\nconst section = ({\n bandSx,\n layout,\n layoutSx,\n maxWidth = 'lg',\n nodes,\n}: {\n bandSx?: Record<string, unknown>\n layout?: Record<string, unknown>\n layoutSx?: Record<string, unknown>\n maxWidth?: string\n nodes: unknown[]\n}) => ({\n $id: null,\n componentId: 'muiStack',\n pluginId: BUNDLE_ID,\n props: {},\n ...(bandSx ? { sx: bandSx } : {}),\n nodes: [\n {\n $id: null,\n componentId: 'muiContainer',\n pluginId: BUNDLE_ID,\n props: { maxWidth },\n nodes:\n layout || layoutSx\n ? [\n {\n $id: null,\n componentId: 'muiStack',\n pluginId: BUNDLE_ID,\n props: layout ?? {},\n ...(layoutSx ? { sx: layoutSx } : {}),\n nodes,\n },\n ]\n : nodes,\n },\n ],\n})\n\nexport const blockPresets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(VIDEO_EMBED_ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Video',\n pluginId: BUNDLE_ID,\n description: 'Embedded YouTube or Vimeo video',\n category: Aglyn.ComponentCategory.MEDIA,\n icon: { path: mdiPlayCircle.path, sx: { color: '#d32f2f' } },\n data: {\n $id: null,\n componentId: VIDEO_EMBED_ID,\n pluginId: BUNDLE_ID,\n props: {},\n },\n },\n {\n $id: generatePresetId(SOCIAL_LINKS_ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Social Links',\n pluginId: BUNDLE_ID,\n description: 'Icon links to social profiles',\n category: Aglyn.ComponentCategory.NAVIGATION,\n icon: { path: mdiTwitter.path, sx: { color: '#1976d2' } },\n data: {\n $id: null,\n componentId: SOCIAL_LINKS_ID,\n pluginId: BUNDLE_ID,\n props: {},\n },\n },\n {\n $id: generatePresetId('muiStack', 'gallery'),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Image Gallery',\n pluginId: BUNDLE_ID,\n description: 'Three-across image row',\n category: Aglyn.ComponentCategory.BLOCKS,\n icon: { path: mdiImageIcon.path, sx: { color: '#7b1fa2' } },\n data: {\n $id: null,\n componentId: 'muiStack',\n pluginId: BUNDLE_ID,\n props: { direction: 'row', spacing: 2 },\n sx: { paddingTop: 4, paddingBottom: 4 },\n nodes: [1, 2, 3].map((index) => ({\n $id: null,\n componentId: 'image',\n pluginId: BUNDLE_ID,\n props: { alt: `Gallery image ${index}`, height: '240px' },\n })),\n },\n },\n {\n $id: generatePresetId('muiStack', 'testimonials'),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Testimonials',\n pluginId: BUNDLE_ID,\n description: 'Three customer quotes',\n category: Aglyn.ComponentCategory.BLOCKS,\n icon: { path: mdiFormatQuoteClose.path, sx: { color: '#0288d1' } },\n data: {\n $id: null,\n componentId: 'muiStack',\n pluginId: BUNDLE_ID,\n props: { direction: 'row', spacing: 2 },\n sx: { paddingTop: 4, paddingBottom: 4 },\n nodes: [\n testimonialCard(\n 'Exactly what our team needed to ship the site fast.',\n 'Customer One',\n ),\n testimonialCard(\n 'The editor is a joy — we update pages in minutes.',\n 'Customer Two',\n ),\n testimonialCard(\n 'Best decision we made for our online presence.',\n 'Customer Three',\n ),\n ],\n },\n },\n {\n $id: generatePresetId('muiStack', 'pricing'),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Pricing Table',\n pluginId: BUNDLE_ID,\n description: 'Three plan columns with features and CTAs',\n category: Aglyn.ComponentCategory.BLOCKS,\n icon: { path: mdiCurrencyUsd.path, sx: { color: '#2e7d32' } },\n data: {\n $id: null,\n componentId: 'muiStack',\n pluginId: BUNDLE_ID,\n props: { direction: 'row', spacing: 2 },\n sx: { paddingTop: 4, paddingBottom: 4 },\n nodes: [\n pricingColumn('Basic', '$9', ['One project', 'Email support']),\n pricingColumn(\n 'Pro',\n '$29',\n ['Five projects', 'Priority support', 'Analytics'],\n true,\n ),\n pricingColumn('Team', '$79', [\n 'Unlimited projects',\n 'Dedicated support',\n 'SSO',\n ]),\n ],\n },\n },\n {\n $id: generatePresetId('muiStack', 'faq'),\n type: Aglyn.NodeType.PRESET,\n displayName: 'FAQ',\n pluginId: BUNDLE_ID,\n description: 'Question and answer list',\n category: Aglyn.ComponentCategory.BLOCKS,\n icon: { path: mdiHelpCircle.path, sx: { color: '#f57c00' } },\n data: section({\n bandSx: { paddingTop: 4, paddingBottom: 4 },\n // `md`, not the old bare `maxWidth: 720`. The width was never the\n // defect — the missing auto margins were, which is why this block\n // rendered hard against the left viewport edge.\n maxWidth: 'md',\n layout: { spacing: 1 },\n nodes: [\n text('h4', 'Frequently asked questions', { gutterBottom: true }),\n ...faqItem(\n 'How do I get started?',\n 'Answer the question in a sentence or two so visitors keep reading.',\n ),\n ...faqItem(\n 'Can I change plans later?',\n 'Yes — describe how flexible your offering is.',\n ),\n ...faqItem(\n 'Do you offer support?',\n 'Tell visitors how and when they can reach you.',\n ),\n ],\n }),\n },\n {\n $id: generatePresetId('muiStack', 'announcement'),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Announcement Bar',\n pluginId: BUNDLE_ID,\n description: 'Accent strip with a message and link',\n category: Aglyn.ComponentCategory.BLOCKS,\n icon: { path: mdiBullhorn.path, sx: { color: '#c2185b' } },\n data: {\n $id: null,\n componentId: 'muiStack',\n pluginId: BUNDLE_ID,\n props: { direction: 'row', spacing: 2 },\n sx: {\n paddingTop: 1,\n paddingBottom: 1,\n paddingLeft: 2,\n paddingRight: 2,\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: 'primary.main',\n color: 'primary.contrastText',\n },\n nodes: [\n text('body2', 'Big news — announce a launch, sale, or update here.'),\n {\n $id: null,\n componentId: 'muiScreenLink',\n pluginId: BUNDLE_ID,\n props: { children: 'Learn more', size: 'small', color: 'inherit' },\n },\n ],\n },\n },\n // ── Composed page sections (AGL-539) ──────────────────────────────────\n // The pieces every real site needs, insertable without raw-JSON\n // authoring. Node shapes mirror apps/console starter templates; only\n // persisted component ids are referenced.\n {\n $id: generatePresetId('muiAppBar', 'navbar'),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Nav Bar',\n pluginId: BUNDLE_ID,\n description: 'Header bar with brand text and screen links',\n category: Aglyn.ComponentCategory.BLOCKS,\n icon: { path: mdiPageLayoutHeader.path, sx: { color: '#1976d2' } },\n data: {\n $id: null,\n componentId: 'muiAppBar',\n pluginId: BUNDLE_ID,\n // Static so the bar sits in the page flow; switch the Position\n // attribute to Sticky/Fixed for a pinned header.\n props: { position: 'static' },\n nodes: [\n {\n $id: null,\n componentId: 'muiToolbar',\n pluginId: BUNDLE_ID,\n props: {},\n nodes: [\n text('h6', 'Your Brand', { sx: { flexGrow: 1 } }),\n {\n $id: null,\n componentId: 'muiStack',\n pluginId: BUNDLE_ID,\n props: { direction: 'row', spacing: 1 },\n nodes: [navLink('Home'), navLink('About'), navLink('Contact')],\n },\n ],\n },\n ],\n },\n },\n {\n $id: generatePresetId('muiStack', 'hero'),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Hero',\n pluginId: BUNDLE_ID,\n description: 'Centered headline, tagline, and call-to-action button',\n category: Aglyn.ComponentCategory.BLOCKS,\n icon: { path: mdiRocketLaunchOutline.path, sx: { color: '#f57c00' } },\n data: section({\n bandSx: {\n paddingTop: 10,\n paddingBottom: 10,\n paddingLeft: 4,\n paddingRight: 4,\n },\n layout: { spacing: 2 },\n layoutSx: { alignItems: 'center' },\n nodes: [\n text('h2', 'A headline that sells your idea', { align: 'center' }),\n text('h6', 'One clear sentence about the value you deliver.', {\n align: 'center',\n }),\n {\n $id: null,\n componentId: 'muiButton',\n pluginId: BUNDLE_ID,\n props: {\n variant: 'contained',\n size: 'large',\n children: 'Get started',\n },\n },\n ],\n }),\n },\n {\n $id: generatePresetId('muiStack', 'features'),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Feature Grid',\n pluginId: BUNDLE_ID,\n description: 'Three selling points in a wrapping row',\n category: Aglyn.ComponentCategory.BLOCKS,\n icon: { path: mdiViewGridOutline.path, sx: { color: '#2e7d32' } },\n data: section({\n bandSx: {\n paddingLeft: 4,\n paddingRight: 4,\n paddingTop: 6,\n paddingBottom: 6,\n },\n layout: { direction: 'row', spacing: 2 },\n layoutSx: { flexWrap: 'wrap' },\n nodes: [\n featureColumn('Fast', 'Explain the first reason customers pick you.'),\n featureColumn(\n 'Simple',\n 'Explain the second reason customers pick you.',\n ),\n featureColumn(\n 'Reliable',\n 'Explain the third reason customers pick you.',\n ),\n ],\n }),\n },\n {\n $id: generatePresetId('muiStack', 'imagetext'),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Image + Text',\n pluginId: BUNDLE_ID,\n description: 'Image beside a heading, copy, and link',\n category: Aglyn.ComponentCategory.BLOCKS,\n icon: { path: mdiImageText.path, sx: { color: '#7b1fa2' } },\n data: {\n $id: null,\n componentId: 'muiStack',\n pluginId: BUNDLE_ID,\n props: { direction: 'row', spacing: 4 },\n sx: {\n paddingLeft: 4,\n paddingRight: 4,\n paddingTop: 6,\n paddingBottom: 6,\n alignItems: 'center',\n flexWrap: 'wrap',\n },\n nodes: [\n {\n $id: null,\n componentId: 'muiStack',\n pluginId: BUNDLE_ID,\n props: {},\n sx: { flex: 1, minWidth: 280 },\n nodes: [\n {\n $id: null,\n componentId: 'image',\n pluginId: BUNDLE_ID,\n props: { alt: 'Feature image', height: '320px' },\n },\n ],\n },\n {\n $id: null,\n componentId: 'muiStack',\n pluginId: BUNDLE_ID,\n props: { spacing: 2 },\n sx: { flex: 1, minWidth: 280 },\n nodes: [\n text('h4', 'Show, then tell'),\n text(\n 'body1',\n 'Pair a strong visual with a short paragraph that explains ' +\n 'what visitors are looking at and why it matters.',\n ),\n {\n $id: null,\n componentId: 'muiButton',\n pluginId: BUNDLE_ID,\n props: { variant: 'outlined', children: 'Learn more' },\n },\n ],\n },\n ],\n },\n },\n {\n $id: generatePresetId('muiStack', 'cta'),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Call to Action',\n pluginId: BUNDLE_ID,\n description: 'Accent band with a heading and button',\n category: Aglyn.ComponentCategory.BLOCKS,\n icon: { path: mdiGestureTapButton.path, sx: { color: '#c2185b' } },\n data: section({\n // The accent band stays full-bleed — that is the point of a CTA —\n // while its content is held to the page's width inside it.\n bandSx: {\n paddingTop: 8,\n paddingBottom: 8,\n paddingLeft: 4,\n paddingRight: 4,\n backgroundColor: 'primary.main',\n color: 'primary.contrastText',\n },\n maxWidth: 'md',\n layout: { spacing: 2 },\n layoutSx: { alignItems: 'center' },\n nodes: [\n text('h4', 'Ready to get started?', { align: 'center' }),\n text('body1', 'Tell visitors the one thing to do next.', {\n align: 'center',\n }),\n {\n $id: null,\n componentId: 'muiButton',\n pluginId: BUNDLE_ID,\n props: {\n variant: 'contained',\n color: 'primary',\n size: 'large',\n children: 'Get started',\n },\n },\n ],\n }),\n },\n // Contact Section moved to @aglyn/plugins-forms (AGL-395): a preset that\n // places `form` nodes has to stamp them with the bundle that registers\n // them, and this one is the only block preset that does.\n {\n $id: generatePresetId('section', 'footer'),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Footer',\n pluginId: BUNDLE_ID,\n description: 'Semantic footer with brand, links, social, and copyright',\n category: Aglyn.ComponentCategory.BLOCKS,\n icon: { path: mdiPageLayoutFooter.path, sx: { color: '#455a64' } },\n data: {\n $id: null,\n componentId: 'section',\n pluginId: BUNDLE_ID,\n props: { element: 'footer', ariaLabel: 'Site footer' },\n sx: {\n paddingLeft: 4,\n paddingRight: 4,\n paddingTop: 6,\n paddingBottom: 6,\n borderTop: 1,\n borderColor: 'divider',\n },\n nodes: [\n {\n $id: null,\n componentId: 'muiStack',\n pluginId: BUNDLE_ID,\n props: { spacing: 2 },\n nodes: [\n {\n $id: null,\n componentId: 'muiStack',\n pluginId: BUNDLE_ID,\n props: { direction: 'row', spacing: 2 },\n sx: {\n justifyContent: 'space-between',\n alignItems: 'center',\n flexWrap: 'wrap',\n },\n nodes: [\n text('h6', 'Your Brand'),\n {\n $id: null,\n componentId: 'muiStack',\n pluginId: BUNDLE_ID,\n props: { direction: 'row', spacing: 1 },\n nodes: [\n navLink('Home'),\n navLink('About'),\n navLink('Contact'),\n ],\n },\n ],\n },\n {\n $id: null,\n componentId: SOCIAL_LINKS_ID,\n pluginId: BUNDLE_ID,\n props: {},\n },\n text(\n 'caption',\n '© Your Company. All rights reserved.',\n { color: 'text.secondary' },\n ),\n ],\n },\n ],\n },\n },\n]\n\nexport { SocialLinks, VideoEmbed }\nexport default VideoEmbed\n"],"names":["Aglyn","mdiBullhorn","mdiCurrencyUsd","mdiFacebook","mdiFormatQuoteClose","mdiGestureTapButton","mdiGithub","mdiHelpCircle","mdiImage","mdiImageIcon","mdiImageText","mdiInstagram","mdiLinkedin","mdiPageLayoutFooter","mdiPageLayoutHeader","mdiPlayCircle","mdiRocketLaunchOutline","mdiTwitter","mdiViewGridOutline","mdiYoutube","AppLink","MdiIcon","Box","Stack","forwardRef","useContext","BUNDLE_ID","generatePresetId","VIDEO_EMBED_ID","SOCIAL_LINKS_ID","parseVideoEmbedSrc","url","parsed","URL","trim","host","hostname","replace","id","pathname","slice","test","searchParams","get","startsWith","split","find","part","VideoEmbed","props","ref","height","rest","nodeSx","Array","isArray","suppressNavigation","ScreenLinkContext","src","sx","width","display","alignItems","justifyContent","border","borderColor","color","fontSize","fontFamily","component","title","loading","allow","allowFullScreen","sandbox","displayName","videoEmbedSchema","$id","pluginId","description","category","ComponentCategory","MEDIA","icon","path","flags","selfClosing","FEATURE_FLAG","ENABLED","attributes","name","FieldComponentType","TEXT_FIELD","label","CSS_DIMENSION","SOCIAL_NETWORKS","key","SAFE_SOCIAL_HREF","SocialLinks","rowProps","entries","map","href","filter","entry","direction","spacing","length","componentVariant","target","rel","aria-label","size","p","socialLinksSchema","NAVIGATION","text","variant","children","extra","componentId","testimonialCard","quote","flex","paddingTop","paddingRight","paddingBottom","paddingLeft","nodes","pricingColumn","tier","price","features","highlighted","borderRadius","feature","faqItem","question","answer","gutterBottom","navLink","featureColumn","body","minWidth","section","bandSx","layout","layoutSx","maxWidth","blockPresets","type","NodeType","PRESET","data","BLOCKS","index","alt","backgroundColor","position","flexGrow","align","flexWrap","element","ariaLabel","borderTop"],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
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 ReactNode } from 'react';
|
|
19
|
+
export declare const ID: Aglyn.ComponentId;
|
|
20
|
+
/**
|
|
21
|
+
* Elements Box may render as. Deliberately *not* the landmark set —
|
|
22
|
+
* section/article/nav/header/footer/main belong to the Section element,
|
|
23
|
+
* which also exposes the accessible-name field a landmark needs. Box owns
|
|
24
|
+
* the generic wrappers that carry no document outline.
|
|
25
|
+
*
|
|
26
|
+
* An allow-list rather than a free-text field: `component` is persisted
|
|
27
|
+
* and rendered verbatim, so a typed value would let an author put
|
|
28
|
+
* `script`/`iframe` into every visitor's page.
|
|
29
|
+
*/
|
|
30
|
+
export declare const BOX_ELEMENTS: readonly ["div", "span", "p", "figure", "figcaption", "blockquote", "pre"];
|
|
31
|
+
export type BoxElement = (typeof BOX_ELEMENTS)[number];
|
|
32
|
+
export interface BoxElementProps {
|
|
33
|
+
/** The DOM element rendered; defaults to `div`. */
|
|
34
|
+
component?: BoxElement;
|
|
35
|
+
children?: ReactNode;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* The plain styling primitive (https://mui.com/material-ui/react-box/):
|
|
39
|
+
* a wrapper with no opinions of its own, sized/spaced/coloured entirely
|
|
40
|
+
* from the styles panel's `sx`. Use it when the grouping is purely
|
|
41
|
+
* visual; use Section when the grouping means something in the document
|
|
42
|
+
* outline.
|
|
43
|
+
*/
|
|
44
|
+
declare const BoxElement: import("react").ForwardRefExoticComponent<BoxElementProps & import("react").RefAttributes<HTMLElement>>;
|
|
45
|
+
export declare const schema: Aglyn.ComponentSchema<BoxElementProps>;
|
|
46
|
+
export declare const presets: Aglyn.PresetSchema[];
|
|
47
|
+
export default BoxElement;
|
|
@@ -0,0 +1,125 @@
|
|
|
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 } 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 { mdiSquareOutline } from "@aglyn/shared-data-mdi";
|
|
21
|
+
import MuiBox from "@mui/material/Box";
|
|
22
|
+
import { forwardRef } from "react";
|
|
23
|
+
import { BUNDLE_ID } from "../constants/bundle-common.js";
|
|
24
|
+
import { generatePresetId } from "../utils/generate-preset-id.js";
|
|
25
|
+
// Component ids are persisted in screen documents; never rename.
|
|
26
|
+
export const ID = 'muiBox';
|
|
27
|
+
/**
|
|
28
|
+
* Elements Box may render as. Deliberately *not* the landmark set —
|
|
29
|
+
* section/article/nav/header/footer/main belong to the Section element,
|
|
30
|
+
* which also exposes the accessible-name field a landmark needs. Box owns
|
|
31
|
+
* the generic wrappers that carry no document outline.
|
|
32
|
+
*
|
|
33
|
+
* An allow-list rather than a free-text field: `component` is persisted
|
|
34
|
+
* and rendered verbatim, so a typed value would let an author put
|
|
35
|
+
* `script`/`iframe` into every visitor's page.
|
|
36
|
+
*/ export const BOX_ELEMENTS = [
|
|
37
|
+
'div',
|
|
38
|
+
'span',
|
|
39
|
+
'p',
|
|
40
|
+
'figure',
|
|
41
|
+
'figcaption',
|
|
42
|
+
'blockquote',
|
|
43
|
+
'pre'
|
|
44
|
+
];
|
|
45
|
+
/**
|
|
46
|
+
* The plain styling primitive (https://mui.com/material-ui/react-box/):
|
|
47
|
+
* a wrapper with no opinions of its own, sized/spaced/coloured entirely
|
|
48
|
+
* from the styles panel's `sx`. Use it when the grouping is purely
|
|
49
|
+
* visual; use Section when the grouping means something in the document
|
|
50
|
+
* outline.
|
|
51
|
+
*/ const BoxElement = /*#__PURE__*/ forwardRef((props, ref)=>{
|
|
52
|
+
const { component, children } = props, rest = _object_without_properties_loose(props, [
|
|
53
|
+
"component",
|
|
54
|
+
"children"
|
|
55
|
+
]);
|
|
56
|
+
const element = BOX_ELEMENTS.includes(component) ? component : 'div';
|
|
57
|
+
return /*#__PURE__*/ _jsx(MuiBox, _extends({
|
|
58
|
+
ref: ref,
|
|
59
|
+
component: element
|
|
60
|
+
}, rest, {
|
|
61
|
+
children: children
|
|
62
|
+
}));
|
|
63
|
+
});
|
|
64
|
+
BoxElement.displayName = 'AglynBox';
|
|
65
|
+
export const schema = {
|
|
66
|
+
$id: ID,
|
|
67
|
+
pluginId: BUNDLE_ID,
|
|
68
|
+
displayName: 'Box',
|
|
69
|
+
description: 'Generic container with no styling of its own — style it from the ' + 'styles panel.',
|
|
70
|
+
category: Aglyn.ComponentCategory.LAYOUT,
|
|
71
|
+
icon: {
|
|
72
|
+
path: mdiSquareOutline.path,
|
|
73
|
+
sx: {
|
|
74
|
+
color: '#2196f3'
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
attributes: [
|
|
78
|
+
{
|
|
79
|
+
name: 'component',
|
|
80
|
+
label: 'Component',
|
|
81
|
+
description: 'The DOM element this box renders as. For landmarks ' + '(section, article, nav, header, footer, main) use the Section ' + 'element instead — it also names the landmark for screen readers.',
|
|
82
|
+
component: Aglyn.FieldComponentType.SELECT,
|
|
83
|
+
options: BOX_ELEMENTS.map((value)=>({
|
|
84
|
+
value,
|
|
85
|
+
label: value
|
|
86
|
+
}))
|
|
87
|
+
}
|
|
88
|
+
]
|
|
89
|
+
};
|
|
90
|
+
export const presets = [
|
|
91
|
+
{
|
|
92
|
+
$id: generatePresetId(ID),
|
|
93
|
+
type: Aglyn.NodeType.PRESET,
|
|
94
|
+
displayName: 'Box',
|
|
95
|
+
pluginId: BUNDLE_ID,
|
|
96
|
+
description: 'Generic container you style yourself',
|
|
97
|
+
category: Aglyn.ComponentCategory.LAYOUT,
|
|
98
|
+
icon: schema.icon,
|
|
99
|
+
data: {
|
|
100
|
+
$id: null,
|
|
101
|
+
componentId: ID,
|
|
102
|
+
pluginId: BUNDLE_ID,
|
|
103
|
+
// Ships with padding and a visible outline: an empty, zero-height
|
|
104
|
+
// div is dropped onto the canvas and appears to have done nothing.
|
|
105
|
+
props: {
|
|
106
|
+
component: 'div'
|
|
107
|
+
},
|
|
108
|
+
// On the node's own sx, not in props (AGL-1346): the Styles panel
|
|
109
|
+
// edits `node.sx`, so an outline authored in `props.sx` was one no
|
|
110
|
+
// click could remove.
|
|
111
|
+
sx: {
|
|
112
|
+
paddingTop: 2,
|
|
113
|
+
paddingRight: 2,
|
|
114
|
+
paddingBottom: 2,
|
|
115
|
+
paddingLeft: 2,
|
|
116
|
+
border: '1px solid',
|
|
117
|
+
borderColor: 'divider',
|
|
118
|
+
borderRadius: 1
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
];
|
|
123
|
+
export default BoxElement;
|
|
124
|
+
|
|
125
|
+
//# sourceMappingURL=box.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/box.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 { mdiSquareOutline } from '@aglyn/shared-data-mdi'\nimport MuiBox from '@mui/material/Box'\nimport { forwardRef, type ReactNode } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport { generatePresetId } from '../utils/generate-preset-id'\n\n// Component ids are persisted in screen documents; never rename.\nexport const ID: Aglyn.ComponentId = 'muiBox'\n\n/**\n * Elements Box may render as. Deliberately *not* the landmark set —\n * section/article/nav/header/footer/main belong to the Section element,\n * which also exposes the accessible-name field a landmark needs. Box owns\n * the generic wrappers that carry no document outline.\n *\n * An allow-list rather than a free-text field: `component` is persisted\n * and rendered verbatim, so a typed value would let an author put\n * `script`/`iframe` into every visitor's page.\n */\nexport const BOX_ELEMENTS = [\n 'div',\n 'span',\n 'p',\n 'figure',\n 'figcaption',\n 'blockquote',\n 'pre',\n] as const\nexport type BoxElement = (typeof BOX_ELEMENTS)[number]\n\nexport interface BoxElementProps {\n /** The DOM element rendered; defaults to `div`. */\n component?: BoxElement\n children?: ReactNode\n}\n\n/**\n * The plain styling primitive (https://mui.com/material-ui/react-box/):\n * a wrapper with no opinions of its own, sized/spaced/coloured entirely\n * from the styles panel's `sx`. Use it when the grouping is purely\n * visual; use Section when the grouping means something in the document\n * outline.\n */\nconst BoxElement = forwardRef<HTMLElement, BoxElementProps>((props, ref) => {\n const { component, children, ...rest } = props\n const element = BOX_ELEMENTS.includes(component as BoxElement)\n ? (component as BoxElement)\n : 'div'\n return (\n <MuiBox ref={ref} component={element} {...rest}>\n {children}\n </MuiBox>\n )\n})\nBoxElement.displayName = 'AglynBox'\n\nexport const schema: Aglyn.ComponentSchema<BoxElementProps> = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'Box',\n description:\n 'Generic container with no styling of its own — style it from the ' +\n 'styles panel.',\n category: Aglyn.ComponentCategory.LAYOUT,\n icon: { path: mdiSquareOutline.path, sx: { color: '#2196f3' } },\n attributes: [\n {\n name: 'component',\n label: 'Component',\n description:\n 'The DOM element this box renders as. For landmarks ' +\n '(section, article, nav, header, footer, main) use the Section ' +\n 'element instead — it also names the landmark for screen readers.',\n component: Aglyn.FieldComponentType.SELECT,\n options: BOX_ELEMENTS.map((value) => ({ value, label: value })),\n },\n ],\n}\n\nexport const presets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Box',\n pluginId: BUNDLE_ID,\n description: 'Generic container you style yourself',\n category: Aglyn.ComponentCategory.LAYOUT,\n icon: schema.icon,\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n // Ships with padding and a visible outline: an empty, zero-height\n // div is dropped onto the canvas and appears to have done nothing.\n props: { component: 'div' },\n // On the node's own sx, not in props (AGL-1346): the Styles panel\n // edits `node.sx`, so an outline authored in `props.sx` was one no\n // click could remove.\n sx: {\n paddingTop: 2,\n paddingRight: 2,\n paddingBottom: 2,\n paddingLeft: 2,\n border: '1px solid',\n borderColor: 'divider',\n borderRadius: 1,\n },\n },\n },\n]\n\nexport default BoxElement\n"],"names":["Aglyn","mdiSquareOutline","MuiBox","forwardRef","BUNDLE_ID","generatePresetId","ID","BOX_ELEMENTS","BoxElement","props","ref","component","children","rest","element","includes","displayName","schema","$id","pluginId","description","category","ComponentCategory","LAYOUT","icon","path","sx","color","attributes","name","label","FieldComponentType","SELECT","options","map","value","presets","type","NodeType","PRESET","data","componentId","paddingTop","paddingRight","paddingBottom","paddingLeft","border","borderColor","borderRadius"],"mappings":";;;AAAA;;;;;;;;;;;;;;;CAeC,GAED,YAAYA,WAAW,eAAc;AACrC,SAASC,gBAAgB,QAAQ,yBAAwB;AACzD,OAAOC,YAAY,oBAAmB;AACtC,SAASC,UAAU,QAAwB,QAAO;AAClD,SAASC,SAAS,QAAQ,gCAA4B;AACtD,SAASC,gBAAgB,QAAQ,iCAA6B;AAE9D,iEAAiE;AACjE,OAAO,MAAMC,KAAwB,SAAQ;AAE7C;;;;;;;;;CASC,GACD,OAAO,MAAMC,eAAe;IAC1B;IACA;IACA;IACA;IACA;IACA;IACA;CACD,CAAS;AASV;;;;;;CAMC,GACD,MAAMC,2BAAaL,WAAyC,CAACM,OAAOC;IAClE,MAAM,EAAEC,SAAS,EAAEC,QAAQ,EAAW,GAAGH,OAATI,wCAASJ;;;;IACzC,MAAMK,UAAUP,aAAaQ,QAAQ,CAACJ,aACjCA,YACD;IACJ,qBACE,KAACT;QAAOQ,KAAKA;QAAKC,WAAWG;OAAaD;kBACvCD;;AAGP;AACAJ,WAAWQ,WAAW,GAAG;AAEzB,OAAO,MAAMC,SAAiD;IAC5DC,KAAKZ;IACLa,UAAUf;IACVY,aAAa;IACbI,aACE,sEACA;IACFC,UAAUrB,MAAMsB,iBAAiB,CAACC,MAAM;IACxCC,MAAM;QAAEC,MAAMxB,iBAAiBwB,IAAI;QAAEC,IAAI;YAAEC,OAAO;QAAU;IAAE;IAC9DC,YAAY;QACV;YACEC,MAAM;YACNC,OAAO;YACPV,aACE,wDACA,mEACA;YACFT,WAAWX,MAAM+B,kBAAkB,CAACC,MAAM;YAC1CC,SAAS1B,aAAa2B,GAAG,CAAC,CAACC,QAAW,CAAA;oBAAEA;oBAAOL,OAAOK;gBAAM,CAAA;QAC9D;KACD;AACH,EAAC;AAED,OAAO,MAAMC,UAAgC;IAC3C;QACElB,KAAKb,iBAAiBC;QACtB+B,MAAMrC,MAAMsC,QAAQ,CAACC,MAAM;QAC3BvB,aAAa;QACbG,UAAUf;QACVgB,aAAa;QACbC,UAAUrB,MAAMsB,iBAAiB,CAACC,MAAM;QACxCC,MAAMP,OAAOO,IAAI;QACjBgB,MAAM;YACJtB,KAAK;YACLuB,aAAanC;YACba,UAAUf;YACV,kEAAkE;YAClE,mEAAmE;YACnEK,OAAO;gBAAEE,WAAW;YAAM;YAC1B,kEAAkE;YAClE,mEAAmE;YACnE,sBAAsB;YACtBe,IAAI;gBACFgB,YAAY;gBACZC,cAAc;gBACdC,eAAe;gBACfC,aAAa;gBACbC,QAAQ;gBACRC,aAAa;gBACbC,cAAc;YAChB;QACF;IACF;CACD,CAAA;AAED,eAAexC,WAAU"}
|
|
@@ -0,0 +1,44 @@
|
|
|
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 ReactNode } from 'react';
|
|
19
|
+
export declare const ID: Aglyn.ComponentId;
|
|
20
|
+
export interface BreadcrumbsElementProps {
|
|
21
|
+
/** Text drawn between crumbs; defaults to `/`. */
|
|
22
|
+
separator?: string;
|
|
23
|
+
/** Collapse into an ellipsis above this many crumbs. */
|
|
24
|
+
maxItems?: number | string;
|
|
25
|
+
itemsBeforeCollapse?: number | string;
|
|
26
|
+
itemsAfterCollapse?: number | string;
|
|
27
|
+
/** Accessible name of the ellipsis button. */
|
|
28
|
+
expandText?: string;
|
|
29
|
+
/** Accessible name of the navigation landmark. */
|
|
30
|
+
ariaLabel?: string;
|
|
31
|
+
children?: ReactNode;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Breadcrumb trail (https://mui.com/material-ui/react-breadcrumbs/).
|
|
35
|
+
*
|
|
36
|
+
* MUI renders a `nav` and inserts the separators between whatever
|
|
37
|
+
* children it is given, so the crumbs themselves are ordinary Screen
|
|
38
|
+
* Links — the trail stays rename-safe for free, and the last crumb can
|
|
39
|
+
* be plain Typography for the current page.
|
|
40
|
+
*/
|
|
41
|
+
declare const BreadcrumbsElement: import("react").ForwardRefExoticComponent<BreadcrumbsElementProps & import("react").RefAttributes<HTMLElement>>;
|
|
42
|
+
export declare const schema: Aglyn.ComponentSchema<BreadcrumbsElementProps>;
|
|
43
|
+
export declare const presets: Aglyn.PresetSchema[];
|
|
44
|
+
export default BreadcrumbsElement;
|
|
@@ -0,0 +1,172 @@
|
|
|
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 } 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 { mdiSlashForward } from "@aglyn/shared-data-mdi";
|
|
21
|
+
import MuiBreadcrumbs from "@mui/material/Breadcrumbs";
|
|
22
|
+
import { forwardRef } from "react";
|
|
23
|
+
import { BUNDLE_ID } from "../constants/bundle-common.js";
|
|
24
|
+
import { generatePresetId } from "../utils/generate-preset-id.js";
|
|
25
|
+
// Component ids are persisted in screen documents; never rename.
|
|
26
|
+
export const ID = 'muiBreadcrumbs';
|
|
27
|
+
function toCount(value) {
|
|
28
|
+
if (value == null || value === '') return undefined;
|
|
29
|
+
const parsed = Number(value);
|
|
30
|
+
if (!Number.isFinite(parsed) || parsed < 1) return undefined;
|
|
31
|
+
return Math.round(parsed);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Breadcrumb trail (https://mui.com/material-ui/react-breadcrumbs/).
|
|
35
|
+
*
|
|
36
|
+
* MUI renders a `nav` and inserts the separators between whatever
|
|
37
|
+
* children it is given, so the crumbs themselves are ordinary Screen
|
|
38
|
+
* Links — the trail stays rename-safe for free, and the last crumb can
|
|
39
|
+
* be plain Typography for the current page.
|
|
40
|
+
*/ const BreadcrumbsElement = /*#__PURE__*/ forwardRef((props, ref)=>{
|
|
41
|
+
const { separator, maxItems, itemsBeforeCollapse, itemsAfterCollapse, expandText, ariaLabel, children } = props, rest = _object_without_properties_loose(props, [
|
|
42
|
+
"separator",
|
|
43
|
+
"maxItems",
|
|
44
|
+
"itemsBeforeCollapse",
|
|
45
|
+
"itemsAfterCollapse",
|
|
46
|
+
"expandText",
|
|
47
|
+
"ariaLabel",
|
|
48
|
+
"children"
|
|
49
|
+
]);
|
|
50
|
+
return /*#__PURE__*/ _jsx(MuiBreadcrumbs, _extends({
|
|
51
|
+
ref: ref,
|
|
52
|
+
// A blank separator would collapse the trail into run-on text.
|
|
53
|
+
separator: separator || '/',
|
|
54
|
+
maxItems: toCount(maxItems),
|
|
55
|
+
itemsBeforeCollapse: toCount(itemsBeforeCollapse),
|
|
56
|
+
itemsAfterCollapse: toCount(itemsAfterCollapse),
|
|
57
|
+
expandText: expandText || undefined,
|
|
58
|
+
"aria-label": ariaLabel || 'Breadcrumb'
|
|
59
|
+
}, rest, {
|
|
60
|
+
children: children
|
|
61
|
+
}));
|
|
62
|
+
});
|
|
63
|
+
BreadcrumbsElement.displayName = 'AglynBreadcrumbs';
|
|
64
|
+
/** The collapse tuning only matters once a max is set. */ const COLLAPSING = {
|
|
65
|
+
when: 'maxItems',
|
|
66
|
+
isNotEmpty: true
|
|
67
|
+
};
|
|
68
|
+
export const schema = {
|
|
69
|
+
$id: ID,
|
|
70
|
+
pluginId: BUNDLE_ID,
|
|
71
|
+
displayName: 'Breadcrumbs',
|
|
72
|
+
description: 'Trail showing where a page sits. Fill it with Screen Links so it ' + 'survives slug changes.',
|
|
73
|
+
category: Aglyn.ComponentCategory.NAVIGATION,
|
|
74
|
+
icon: {
|
|
75
|
+
path: mdiSlashForward.path,
|
|
76
|
+
sx: {
|
|
77
|
+
color: '#2196f3'
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
attributes: [
|
|
81
|
+
{
|
|
82
|
+
name: 'separator',
|
|
83
|
+
label: 'Separator',
|
|
84
|
+
description: 'Text drawn between crumbs, e.g. / or ›. Default /.',
|
|
85
|
+
component: Aglyn.FieldComponentType.TEXT_FIELD
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
name: 'maxItems',
|
|
89
|
+
label: 'Collapse above',
|
|
90
|
+
description: 'Collapse the middle of the trail into an ellipsis once there ' + 'are more crumbs than this. Blank never collapses.',
|
|
91
|
+
component: Aglyn.FieldComponentType.TEXT_FIELD,
|
|
92
|
+
type: 'number'
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
name: 'itemsBeforeCollapse',
|
|
96
|
+
label: 'Keep at start',
|
|
97
|
+
description: 'Crumbs kept before the ellipsis. Default 1.',
|
|
98
|
+
component: Aglyn.FieldComponentType.TEXT_FIELD,
|
|
99
|
+
type: 'number',
|
|
100
|
+
condition: COLLAPSING
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
name: 'itemsAfterCollapse',
|
|
104
|
+
label: 'Keep at end',
|
|
105
|
+
description: 'Crumbs kept after the ellipsis. Default 1.',
|
|
106
|
+
component: Aglyn.FieldComponentType.TEXT_FIELD,
|
|
107
|
+
type: 'number',
|
|
108
|
+
condition: COLLAPSING
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
name: 'expandText',
|
|
112
|
+
label: 'Expand button label',
|
|
113
|
+
description: 'Accessible name of the ellipsis button. Default "Show path".',
|
|
114
|
+
component: Aglyn.FieldComponentType.TEXT_FIELD,
|
|
115
|
+
condition: COLLAPSING
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
name: 'ariaLabel',
|
|
119
|
+
label: 'Accessible label',
|
|
120
|
+
description: 'Names the navigation landmark for screen readers. Default ' + '"Breadcrumb".',
|
|
121
|
+
component: Aglyn.FieldComponentType.TEXT_FIELD
|
|
122
|
+
}
|
|
123
|
+
]
|
|
124
|
+
};
|
|
125
|
+
const crumb = (label)=>({
|
|
126
|
+
$id: null,
|
|
127
|
+
componentId: 'muiScreenLink',
|
|
128
|
+
pluginId: BUNDLE_ID,
|
|
129
|
+
// Text links, not buttons: a breadcrumb rendered as a button gets
|
|
130
|
+
// button typography and the wrong role for assistive tech (AGL-1195).
|
|
131
|
+
props: {
|
|
132
|
+
children: label,
|
|
133
|
+
renderAs: 'link',
|
|
134
|
+
color: 'inherit'
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
export const presets = [
|
|
138
|
+
{
|
|
139
|
+
$id: generatePresetId(ID),
|
|
140
|
+
type: Aglyn.NodeType.PRESET,
|
|
141
|
+
displayName: 'Breadcrumbs',
|
|
142
|
+
pluginId: BUNDLE_ID,
|
|
143
|
+
description: 'Two links and the current page',
|
|
144
|
+
category: Aglyn.ComponentCategory.NAVIGATION,
|
|
145
|
+
icon: schema.icon,
|
|
146
|
+
data: {
|
|
147
|
+
$id: null,
|
|
148
|
+
componentId: ID,
|
|
149
|
+
pluginId: BUNDLE_ID,
|
|
150
|
+
props: {},
|
|
151
|
+
nodes: [
|
|
152
|
+
crumb('Home'),
|
|
153
|
+
crumb('Section'),
|
|
154
|
+
{
|
|
155
|
+
// The current page is not a link — linking a page to itself is
|
|
156
|
+
// the classic breadcrumb accessibility mistake.
|
|
157
|
+
$id: null,
|
|
158
|
+
componentId: 'muiTypography',
|
|
159
|
+
pluginId: BUNDLE_ID,
|
|
160
|
+
props: {
|
|
161
|
+
variant: 'body2',
|
|
162
|
+
color: 'text.primary',
|
|
163
|
+
children: 'Current page'
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
]
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
];
|
|
170
|
+
export default BreadcrumbsElement;
|
|
171
|
+
|
|
172
|
+
//# sourceMappingURL=breadcrumbs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/breadcrumbs.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 { mdiSlashForward } from '@aglyn/shared-data-mdi'\nimport MuiBreadcrumbs from '@mui/material/Breadcrumbs'\nimport { forwardRef, type ReactNode } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport { generatePresetId } from '../utils/generate-preset-id'\n\n// Component ids are persisted in screen documents; never rename.\nexport const ID: Aglyn.ComponentId = 'muiBreadcrumbs'\n\nexport interface BreadcrumbsElementProps {\n /** Text drawn between crumbs; defaults to `/`. */\n separator?: string\n /** Collapse into an ellipsis above this many crumbs. */\n maxItems?: number | string\n itemsBeforeCollapse?: number | string\n itemsAfterCollapse?: number | string\n /** Accessible name of the ellipsis button. */\n expandText?: string\n /** Accessible name of the navigation landmark. */\n ariaLabel?: string\n children?: ReactNode\n}\n\nfunction toCount(value: unknown): number | undefined {\n if (value == null || value === '') return undefined\n const parsed = Number(value)\n if (!Number.isFinite(parsed) || parsed < 1) return undefined\n return Math.round(parsed)\n}\n\n/**\n * Breadcrumb trail (https://mui.com/material-ui/react-breadcrumbs/).\n *\n * MUI renders a `nav` and inserts the separators between whatever\n * children it is given, so the crumbs themselves are ordinary Screen\n * Links — the trail stays rename-safe for free, and the last crumb can\n * be plain Typography for the current page.\n */\nconst BreadcrumbsElement = forwardRef<\n HTMLElement,\n BreadcrumbsElementProps\n>((props, ref) => {\n const {\n separator,\n maxItems,\n itemsBeforeCollapse,\n itemsAfterCollapse,\n expandText,\n ariaLabel,\n children,\n ...rest\n } = props\n return (\n <MuiBreadcrumbs\n ref={ref}\n // A blank separator would collapse the trail into run-on text.\n separator={separator || '/'}\n maxItems={toCount(maxItems)}\n itemsBeforeCollapse={toCount(itemsBeforeCollapse)}\n itemsAfterCollapse={toCount(itemsAfterCollapse)}\n expandText={expandText || undefined}\n aria-label={ariaLabel || 'Breadcrumb'}\n {...rest}\n >\n {children}\n </MuiBreadcrumbs>\n )\n})\nBreadcrumbsElement.displayName = 'AglynBreadcrumbs'\n\n/** The collapse tuning only matters once a max is set. */\nconst COLLAPSING = { when: 'maxItems', isNotEmpty: true }\n\nexport const schema: Aglyn.ComponentSchema<BreadcrumbsElementProps> = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'Breadcrumbs',\n description:\n 'Trail showing where a page sits. Fill it with Screen Links so it ' +\n 'survives slug changes.',\n category: Aglyn.ComponentCategory.NAVIGATION,\n icon: { path: mdiSlashForward.path, sx: { color: '#2196f3' } },\n attributes: [\n {\n name: 'separator',\n label: 'Separator',\n description: 'Text drawn between crumbs, e.g. / or ›. Default /.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n },\n {\n name: 'maxItems',\n label: 'Collapse above',\n description:\n 'Collapse the middle of the trail into an ellipsis once there ' +\n 'are more crumbs than this. Blank never collapses.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n type: 'number',\n },\n {\n name: 'itemsBeforeCollapse',\n label: 'Keep at start',\n description: 'Crumbs kept before the ellipsis. Default 1.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n type: 'number',\n condition: COLLAPSING,\n },\n {\n name: 'itemsAfterCollapse',\n label: 'Keep at end',\n description: 'Crumbs kept after the ellipsis. Default 1.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n type: 'number',\n condition: COLLAPSING,\n },\n {\n name: 'expandText',\n label: 'Expand button label',\n description:\n 'Accessible name of the ellipsis button. Default \"Show path\".',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n condition: COLLAPSING,\n },\n {\n name: 'ariaLabel',\n label: 'Accessible label',\n description:\n 'Names the navigation landmark for screen readers. Default ' +\n '\"Breadcrumb\".',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n },\n ],\n}\n\nconst crumb = (label: string) => ({\n $id: null,\n componentId: 'muiScreenLink',\n pluginId: BUNDLE_ID,\n // Text links, not buttons: a breadcrumb rendered as a button gets\n // button typography and the wrong role for assistive tech (AGL-1195).\n props: { children: label, renderAs: 'link', color: 'inherit' },\n})\n\nexport const presets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Breadcrumbs',\n pluginId: BUNDLE_ID,\n description: 'Two links and the current page',\n category: Aglyn.ComponentCategory.NAVIGATION,\n icon: schema.icon,\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: {},\n nodes: [\n crumb('Home'),\n crumb('Section'),\n {\n // The current page is not a link — linking a page to itself is\n // the classic breadcrumb accessibility mistake.\n $id: null,\n componentId: 'muiTypography',\n pluginId: BUNDLE_ID,\n props: {\n variant: 'body2',\n color: 'text.primary',\n children: 'Current page',\n },\n },\n ],\n },\n },\n]\n\nexport default BreadcrumbsElement\n"],"names":["Aglyn","mdiSlashForward","MuiBreadcrumbs","forwardRef","BUNDLE_ID","generatePresetId","ID","toCount","value","undefined","parsed","Number","isFinite","Math","round","BreadcrumbsElement","props","ref","separator","maxItems","itemsBeforeCollapse","itemsAfterCollapse","expandText","ariaLabel","children","rest","aria-label","displayName","COLLAPSING","when","isNotEmpty","schema","$id","pluginId","description","category","ComponentCategory","NAVIGATION","icon","path","sx","color","attributes","name","label","component","FieldComponentType","TEXT_FIELD","type","condition","crumb","componentId","renderAs","presets","NodeType","PRESET","data","nodes","variant"],"mappings":";;;AAAA;;;;;;;;;;;;;;;CAeC,GAED,YAAYA,WAAW,eAAc;AACrC,SAASC,eAAe,QAAQ,yBAAwB;AACxD,OAAOC,oBAAoB,4BAA2B;AACtD,SAASC,UAAU,QAAwB,QAAO;AAClD,SAASC,SAAS,QAAQ,gCAA4B;AACtD,SAASC,gBAAgB,QAAQ,iCAA6B;AAE9D,iEAAiE;AACjE,OAAO,MAAMC,KAAwB,iBAAgB;AAgBrD,SAASC,QAAQC,KAAc;IAC7B,IAAIA,SAAS,QAAQA,UAAU,IAAI,OAAOC;IAC1C,MAAMC,SAASC,OAAOH;IACtB,IAAI,CAACG,OAAOC,QAAQ,CAACF,WAAWA,SAAS,GAAG,OAAOD;IACnD,OAAOI,KAAKC,KAAK,CAACJ;AACpB;AAEA;;;;;;;CAOC,GACD,MAAMK,mCAAqBZ,WAGzB,CAACa,OAAOC;IACR,MAAM,EACJC,SAAS,EACTC,QAAQ,EACRC,mBAAmB,EACnBC,kBAAkB,EAClBC,UAAU,EACVC,SAAS,EACTC,QAAQ,EAET,GAAGR,OADCS,wCACDT;;;;;;;;;IACJ,qBACE,KAACd;QACCe,KAAKA;QACL,+DAA+D;QAC/DC,WAAWA,aAAa;QACxBC,UAAUZ,QAAQY;QAClBC,qBAAqBb,QAAQa;QAC7BC,oBAAoBd,QAAQc;QAC5BC,YAAYA,cAAcb;QAC1BiB,cAAYH,aAAa;OACrBE;kBAEHD;;AAGP;AACAT,mBAAmBY,WAAW,GAAG;AAEjC,wDAAwD,GACxD,MAAMC,aAAa;IAAEC,MAAM;IAAYC,YAAY;AAAK;AAExD,OAAO,MAAMC,SAAyD;IACpEC,KAAK1B;IACL2B,UAAU7B;IACVuB,aAAa;IACbO,aACE,sEACA;IACFC,UAAUnC,MAAMoC,iBAAiB,CAACC,UAAU;IAC5CC,MAAM;QAAEC,MAAMtC,gBAAgBsC,IAAI;QAAEC,IAAI;YAAEC,OAAO;QAAU;IAAE;IAC7DC,YAAY;QACV;YACEC,MAAM;YACNC,OAAO;YACPV,aAAa;YACbW,WAAW7C,MAAM8C,kBAAkB,CAACC,UAAU;QAChD;QACA;YACEJ,MAAM;YACNC,OAAO;YACPV,aACE,kEACA;YACFW,WAAW7C,MAAM8C,kBAAkB,CAACC,UAAU;YAC9CC,MAAM;QACR;QACA;YACEL,MAAM;YACNC,OAAO;YACPV,aAAa;YACbW,WAAW7C,MAAM8C,kBAAkB,CAACC,UAAU;YAC9CC,MAAM;YACNC,WAAWrB;QACb;QACA;YACEe,MAAM;YACNC,OAAO;YACPV,aAAa;YACbW,WAAW7C,MAAM8C,kBAAkB,CAACC,UAAU;YAC9CC,MAAM;YACNC,WAAWrB;QACb;QACA;YACEe,MAAM;YACNC,OAAO;YACPV,aACE;YACFW,WAAW7C,MAAM8C,kBAAkB,CAACC,UAAU;YAC9CE,WAAWrB;QACb;QACA;YACEe,MAAM;YACNC,OAAO;YACPV,aACE,+DACA;YACFW,WAAW7C,MAAM8C,kBAAkB,CAACC,UAAU;QAChD;KACD;AACH,EAAC;AAED,MAAMG,QAAQ,CAACN,QAAmB,CAAA;QAChCZ,KAAK;QACLmB,aAAa;QACblB,UAAU7B;QACV,kEAAkE;QAClE,sEAAsE;QACtEY,OAAO;YAAEQ,UAAUoB;YAAOQ,UAAU;YAAQX,OAAO;QAAU;IAC/D,CAAA;AAEA,OAAO,MAAMY,UAAgC;IAC3C;QACErB,KAAK3B,iBAAiBC;QACtB0C,MAAMhD,MAAMsD,QAAQ,CAACC,MAAM;QAC3B5B,aAAa;QACbM,UAAU7B;QACV8B,aAAa;QACbC,UAAUnC,MAAMoC,iBAAiB,CAACC,UAAU;QAC5CC,MAAMP,OAAOO,IAAI;QACjBkB,MAAM;YACJxB,KAAK;YACLmB,aAAa7C;YACb2B,UAAU7B;YACVY,OAAO,CAAC;YACRyC,OAAO;gBACLP,MAAM;gBACNA,MAAM;gBACN;oBACE,+DAA+D;oBAC/D,gDAAgD;oBAChDlB,KAAK;oBACLmB,aAAa;oBACblB,UAAU7B;oBACVY,OAAO;wBACL0C,SAAS;wBACTjB,OAAO;wBACPjB,UAAU;oBACZ;gBACF;aACD;QACH;IACF;CACD,CAAA;AAED,eAAeT,mBAAkB"}
|
|
@@ -0,0 +1,89 @@
|
|
|
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 ButtonProps } from '@mui/material/Button';
|
|
19
|
+
import { type LinkTargetChoice } from '../utils/link-target-props';
|
|
20
|
+
export declare const ID: Aglyn.ComponentId;
|
|
21
|
+
export interface LinkableButtonProps extends ButtonProps {
|
|
22
|
+
/** Target screen id; resolved from the routing map (AGL-139). */
|
|
23
|
+
screenId?: string;
|
|
24
|
+
/** External URL, used only when no `screenId` is set. */
|
|
25
|
+
href?: string;
|
|
26
|
+
/** mdi icon id rendered before the label (AGL-146). */
|
|
27
|
+
startIconId?: string;
|
|
28
|
+
/** mdi icon id rendered after the label (AGL-146). */
|
|
29
|
+
endIconId?: string;
|
|
30
|
+
/** Resolved SVG path for `startIconId`, stored at author time (AGL-1212). */
|
|
31
|
+
startIconPath?: string;
|
|
32
|
+
/** Resolved SVG path for `endIconId`, stored at author time (AGL-1212). */
|
|
33
|
+
endIconPath?: string;
|
|
34
|
+
/**
|
|
35
|
+
* What the LINK MODE announces as (AGL-1426). Persisted in screen
|
|
36
|
+
* documents; never rename, and `undefined` must keep meaning `'button'` —
|
|
37
|
+
* every button authored before this existed is one.
|
|
38
|
+
*
|
|
39
|
+
* - `'button'` (or unset) — `<a role="button">` with the button's look.
|
|
40
|
+
* - `'linkButton'` — a plain `<a>` with NO role, keeping the button's
|
|
41
|
+
* `variant`/`size`/`fullWidth`. Appearance without semantics.
|
|
42
|
+
*
|
|
43
|
+
* There is no `'link'` value here: a plain text link is `muiScreenLink`'s
|
|
44
|
+
* job, and this component's whole purpose is the button styling.
|
|
45
|
+
*/
|
|
46
|
+
renderAs?: 'button' | 'linkButton';
|
|
47
|
+
/**
|
|
48
|
+
* Where LINK MODE opens. Persisted in screen documents; never rename a
|
|
49
|
+
* value, and `undefined` must keep meaning `'_self'`. Inert on a button
|
|
50
|
+
* with nothing to point at — that is a real `<button>`, which has no
|
|
51
|
+
* browsing context to choose.
|
|
52
|
+
*/
|
|
53
|
+
target?: LinkTargetChoice;
|
|
54
|
+
/** Window name used only when `target` is `'custom'`. */
|
|
55
|
+
targetName?: string;
|
|
56
|
+
/**
|
|
57
|
+
* Sanitized emphasis markup for the label, written by the inline editor's
|
|
58
|
+
* rich mode (AGL-2557). `children` keeps the plain-text reading of it, and
|
|
59
|
+
* is what every surface that cannot render markup falls back to.
|
|
60
|
+
*/
|
|
61
|
+
html?: string;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Button with optional link mode (AGL-139): a screen id or external URL
|
|
65
|
+
* renders through AppLink exactly like the Screen Link component —
|
|
66
|
+
* degrading to a plain button in the besigner/preview and when the id
|
|
67
|
+
* doesn't resolve.
|
|
68
|
+
*
|
|
69
|
+
* Resolution (id-vs-URL precedence, protocol hardening) is `useLinkTarget`
|
|
70
|
+
* so a `Link`-typed component prop bound into EITHER field resolves the
|
|
71
|
+
* same way here as in Screen Link, Link Box and Image (AGL-1335).
|
|
72
|
+
*
|
|
73
|
+
* `renderAs="linkButton"` splits appearance from semantics in that link mode
|
|
74
|
+
* (AGL-1426), the same split `screen-link.tsx` got in AGL-1347. The 12 chips
|
|
75
|
+
* in "Dig in, or just say hello" on `aglyn.com/` are Buttons, not Screen
|
|
76
|
+
* Links: docs URLs, `mailto:` and social profiles, every one of them purely
|
|
77
|
+
* navigating, and every one announcing as a button — which tells a
|
|
78
|
+
* screen-reader user to expect an action and costs them the link list and
|
|
79
|
+
* the open-in-new-tab affordance. This mode keeps the `variant`/`size`/
|
|
80
|
+
* `fullWidth` pixels and drops the role, exactly as MUI's own
|
|
81
|
+
* `Button component={Link}` does.
|
|
82
|
+
*
|
|
83
|
+
* It only touches the link branch. A Button with no link target is a genuine
|
|
84
|
+
* `<button>` whose role is correct, so the value is inert there.
|
|
85
|
+
*/
|
|
86
|
+
declare const LinkableButton: import("react").ForwardRefExoticComponent<Omit<LinkableButtonProps, "ref"> & import("react").RefAttributes<any>>;
|
|
87
|
+
export declare const schema: Aglyn.ComponentSchema<LinkableButtonProps>;
|
|
88
|
+
export declare const presets: Aglyn.PresetSchema[];
|
|
89
|
+
export default LinkableButton;
|