@aglyn/plugins-mui 1.0.0-beta.234 → 1.0.0-beta.236

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aglyn/plugins-mui",
3
- "version": "1.0.0-beta.234",
3
+ "version": "1.0.0-beta.236",
4
4
  "license": "Apache-2.0",
5
5
  "homepage": "https://aglyn.com",
6
6
  "repository": {
@@ -25,12 +25,12 @@
25
25
  "./package.json": "./package.json"
26
26
  },
27
27
  "dependencies": {
28
- "@aglyn/aglyn": "1.0.0-beta.234",
29
- "@aglyn/shared-data-enums": "1.0.0-beta.234",
30
- "@aglyn/shared-data-mdi": "1.0.0-beta.234",
31
- "@aglyn/shared-ui-jsx": "1.0.0-beta.234",
32
- "@aglyn/shared-ui-theme": "1.0.0-beta.234",
33
- "@aglyn/shared-util-vendor": "1.0.0-beta.234",
28
+ "@aglyn/aglyn": "1.0.0-beta.236",
29
+ "@aglyn/shared-data-enums": "1.0.0-beta.236",
30
+ "@aglyn/shared-data-mdi": "1.0.0-beta.236",
31
+ "@aglyn/shared-ui-jsx": "1.0.0-beta.236",
32
+ "@aglyn/shared-ui-theme": "1.0.0-beta.236",
33
+ "@aglyn/shared-util-vendor": "1.0.0-beta.236",
34
34
  "@swc/helpers": "0.5.23",
35
35
  "mobx": "^7.0.5",
36
36
  "mobx-react-lite": "^5.1.0"
@@ -16,6 +16,7 @@
16
16
  */
17
17
  import * as Aglyn from '@aglyn/aglyn';
18
18
  import { type AppBarProps } from '@mui/material/AppBar';
19
+ import { type Theme } from '@mui/material/styles';
19
20
  export interface AglynAppBarProps extends AppBarProps {
20
21
  /**
21
22
  * Compacts the bar's Toolbar Content to the dense height once the page
@@ -36,6 +37,25 @@ export interface AglynAppBarProps extends AppBarProps {
36
37
  */
37
38
  overHero?: boolean;
38
39
  }
40
+ /**
41
+ * Over a page that opens under the header, the bar lies on the photo. One
42
+ * rule the browser applies by what the page holds, so the server render, the
43
+ * published page and every page of a layout share one class, and a page
44
+ * without such a band is untouched.
45
+ */
46
+ export declare const overHeroSx: (theme: Theme) => {
47
+ "body:has([data-aglyn-under-header]) &": {
48
+ position: string;
49
+ top: string;
50
+ left: number;
51
+ right: number;
52
+ backgroundColor: string;
53
+ backgroundImage: string;
54
+ boxShadow: string;
55
+ borderBottom: number;
56
+ color: string;
57
+ };
58
+ };
39
59
  /**
40
60
  * MUI's AppBar behind the cleared-prop guard (AGL-1226).
41
61
  *
@@ -32,10 +32,14 @@ import { ID as toolbarId } from "./toolbar.js";
32
32
  * rule the browser applies by what the page holds, so the server render, the
33
33
  * published page and every page of a layout share one class, and a page
34
34
  * without such a band is untouched.
35
- */ const overHeroSx = (theme)=>({
35
+ */ export const overHeroSx = (theme)=>({
36
36
  [`body:has([${UNDER_HEADER_ATTRIBUTE}]) &`]: {
37
37
  position: 'absolute',
38
- top: 0,
38
+ // Below the owner's admin bar when one is up (the tenant publishes its
39
+ // live height on `<html>`), at the very top for everyone else. Absolute
40
+ // to the initial containing block, the bar's `<html>` margin never
41
+ // moves this header — the variable is what does (AGL-3660).
42
+ top: 'var(--aglyn-admin-bar-height, 0px)',
39
43
  left: 0,
40
44
  right: 0,
41
45
  backgroundColor: 'transparent',
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/app-bar.ts"],"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 { mdiPageLayoutHeader } from '@aglyn/shared-data-mdi'\nimport { ScrollReaction } from '@aglyn/shared-ui-jsx/components/scroll-reaction'\nimport MuiAppBar, { type AppBarProps } from '@mui/material/AppBar'\nimport { type SxProps, type Theme } from '@mui/material/styles'\nimport { createElement, forwardRef, type Ref } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport {\n applySemanticElement,\n semanticElementAttribute,\n semanticElementLabelAttribute,\n} from '../utils/element-picker'\nimport { FIELD_COLOR_ALT1, FIELD_POSITION } from '../constants/field-presets'\nimport { dropClearedProps } from '../utils/drop-cleared-props'\nimport { generatePresetId } from '../utils/generate-preset-id'\nimport { UNDER_HEADER_ATTRIBUTE } from './section'\nimport { ID as toolbarId } from './toolbar'\n\nexport interface AglynAppBarProps extends AppBarProps {\n /**\n * Compacts the bar's Toolbar Content to the dense height once the page\n * has scrolled, and back at the top. Meant for a pinned (sticky/fixed)\n * bar, where the full height costs the reader a band of every screen.\n */\n shrinkOnScroll?: boolean\n /**\n * Slides the bar up out of view while the visitor scrolls down, and back\n * the moment they scroll up. Meant for a pinned (sticky/fixed) bar.\n */\n hideOnScroll?: boolean\n /**\n * Sits over a photo hero (AGL-3660): on a page whose first band runs under\n * the header (a Section with `underHeader`), the bar lies over that band\n * with no background of its own and its words in white, and scrolls away\n * with it; on every other page it is the bar it always was.\n */\n overHero?: boolean\n}\n\n/**\n * Over a page that opens under the header, the bar lies on the photo. One\n * rule the browser applies by what the page holds, so the server render, the\n * published page and every page of a layout share one class, and a page\n * without such a band is untouched.\n */\nconst overHeroSx: SxProps<Theme> = (theme) => ({\n [`body:has([${UNDER_HEADER_ATTRIBUTE}]) &`]: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n backgroundColor: 'transparent',\n backgroundImage: 'none',\n boxShadow: 'none',\n borderBottom: 0,\n color: theme.palette.common.white,\n },\n})\n\nfunction withOverHeroSx(sx: AppBarProps['sx']): AppBarProps['sx'] {\n return [overHeroSx, ...(Array.isArray(sx) ? sx : [sx])] as AppBarProps['sx']\n}\n\n/** Scroll distance before a shrinking bar compacts. */\nconst SHRINK_THRESHOLD = 16\n/** Scroll distance before a hiding bar may slide away — past its own height. */\nconst HIDE_THRESHOLD = 120\n\n/**\n * Both scroll states ride data attributes, not a re-styled sx, so the\n * server render and every scroll position share one emotion class.\n */\nconst scrollSx: SxProps<Theme> = (theme) => ({\n transition: theme.transitions.create(['transform', 'box-shadow'], {\n duration: theme.transitions.duration.shorter,\n }),\n '& .MuiToolbar-root': {\n transition: theme.transitions.create('min-height', {\n duration: theme.transitions.duration.shorter,\n }),\n },\n '&[data-scrolled] .MuiToolbar-root': {\n // MUI's dense toolbar height.\n minHeight: theme.spacing(6),\n },\n '&[data-scroll-hidden]': {\n transform: 'translateY(-100%)',\n },\n})\n\nfunction withScrollSx(sx: AppBarProps['sx']): AppBarProps['sx'] {\n return [scrollSx, ...(Array.isArray(sx) ? sx : [sx])] as AppBarProps['sx']\n}\n\nfunction renderAppBar(props: AppBarProps, ref: Ref<HTMLElement>) {\n return createElement(MuiAppBar, {\n // Unset leaves MUI's own default, which is `header` — the banner\n // landmark every site's chrome depends on (AGL-2525). A resolver that\n // answered `div` for \"unset\" would have stripped it the moment the\n // picker appeared.\n ...applySemanticElement(dropClearedProps(props) as Record<string, unknown>),\n ref,\n })\n}\n\ninterface ScrollAwareAppBarProps extends AppBarProps {\n shrink: boolean\n hide: boolean\n}\n\n/**\n * Its own component so the scroll listeners exist only on a bar that asked\n * to react — a hook behind a prop check would break the rules of hooks.\n * `ScrollReaction` answers both questions: past the threshold (shrink),\n * and scrolling down rather than up (hide), which is what MUI's scroll\n * trigger means by hysteresis.\n */\nconst ScrollAwareAppBar = forwardRef<HTMLElement, ScrollAwareAppBarProps>(\n ({ shrink, hide, ...props }, ref) =>\n createElement(ScrollReaction, {\n threshold: SHRINK_THRESHOLD,\n withHysteresis: { threshold: HIDE_THRESHOLD },\n children: ({ activeWithHysteresis, activeWithoutHysteresis }) =>\n renderAppBar(\n {\n ...props,\n sx: withScrollSx(props.sx),\n ...({\n 'data-scrolled':\n shrink && activeWithoutHysteresis ? '' : undefined,\n 'data-scroll-hidden':\n hide && activeWithHysteresis ? '' : undefined,\n } as AppBarProps),\n },\n ref,\n ),\n }),\n)\nScrollAwareAppBar.displayName = 'AglynScrollAwareAppBar'\n\n/**\n * MUI's AppBar behind the cleared-prop guard (AGL-1226).\n *\n * It was exported raw, which left BOTH of its authorable attributes exposed:\n * `color` and `position` are each run through MUI's `capitalize`, so clearing\n * either one persists a null that throws during SSR and 500s the page. A\n * wrapper is the only place to intercept it, since the schema's props reach\n * MUI directly. `createElement` rather than JSX keeps this a `.ts` file.\n */\nconst AppBar = forwardRef<HTMLElement, AglynAppBarProps>(\n ({ shrinkOnScroll, hideOnScroll, overHero, ...rest }, ref) => {\n const props = overHero ? { ...rest, sx: withOverHeroSx(rest.sx) } : rest\n return shrinkOnScroll || hideOnScroll\n ? createElement(ScrollAwareAppBar, {\n ...props,\n shrink: Boolean(shrinkOnScroll),\n hide: Boolean(hideOnScroll),\n ref,\n })\n : renderAppBar(props, ref)\n },\n)\nAppBar.displayName = 'AglynAppBar'\n\n// Component ids are persisted in screen documents; keep the legacy ids.\nexport const ID: Aglyn.ComponentId = 'muiAppBar'\n\nexport const schema: Aglyn.ComponentSchema<AglynAppBarProps> = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'App Bar',\n description:\n 'The bar across the top of the site — put a Toolbar Content inside it.',\n category: Aglyn.ComponentCategory.NAVIGATION,\n icon: {\n path: mdiPageLayoutHeader.path,\n sx: { color: '#2196f3' },\n },\n attributes: [\n semanticElementAttribute('this bar'),\n semanticElementLabelAttribute(),\n FIELD_COLOR_ALT1,\n FIELD_POSITION,\n {\n name: 'shrinkOnScroll',\n description:\n 'Compacts the bar to the dense height once the page scrolls, and ' +\n 'restores it at the top. Pair with a Sticky or Fixed position.',\n component: Aglyn.FieldComponentType.SWITCH,\n label: 'Shrink when scrolled?',\n },\n {\n name: 'hideOnScroll',\n description:\n 'Slides the bar up out of view while the visitor scrolls down, and ' +\n 'back as soon as they scroll up. Pair with a Sticky or Fixed position.',\n component: Aglyn.FieldComponentType.SWITCH,\n label: 'Hide while scrolling down?',\n },\n {\n name: 'overHero',\n description:\n 'On a page whose first band is set to run under the header, the bar ' +\n 'sits over that photo with no background and white words. Other ' +\n 'pages keep the bar as it is.',\n component: Aglyn.FieldComponentType.SWITCH,\n label: 'Sit over a photo hero?',\n },\n ],\n}\n\nexport const presets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'App Bar',\n pluginId: BUNDLE_ID,\n description: 'An app bar preset with the app bar and toolbar content nodes',\n category: Aglyn.ComponentCategory.NAVIGATION,\n icon: schema.icon,\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n nodes: [\n {\n $id: null,\n componentId: toolbarId,\n pluginId: BUNDLE_ID,\n props: {},\n },\n ],\n },\n },\n]\n\nexport default AppBar\n"],"names":["Aglyn","mdiPageLayoutHeader","ScrollReaction","MuiAppBar","createElement","forwardRef","BUNDLE_ID","applySemanticElement","semanticElementAttribute","semanticElementLabelAttribute","FIELD_COLOR_ALT1","FIELD_POSITION","dropClearedProps","generatePresetId","UNDER_HEADER_ATTRIBUTE","ID","toolbarId","overHeroSx","theme","position","top","left","right","backgroundColor","backgroundImage","boxShadow","borderBottom","color","palette","common","white","withOverHeroSx","sx","Array","isArray","SHRINK_THRESHOLD","HIDE_THRESHOLD","scrollSx","transition","transitions","create","duration","shorter","minHeight","spacing","transform","withScrollSx","renderAppBar","props","ref","ScrollAwareAppBar","shrink","hide","threshold","withHysteresis","children","activeWithHysteresis","activeWithoutHysteresis","undefined","displayName","AppBar","shrinkOnScroll","hideOnScroll","overHero","rest","Boolean","schema","$id","pluginId","description","category","ComponentCategory","NAVIGATION","icon","path","attributes","name","component","FieldComponentType","SWITCH","label","presets","type","NodeType","PRESET","data","componentId","nodes"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/app-bar.ts"],"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 { mdiPageLayoutHeader } from '@aglyn/shared-data-mdi'\nimport { ScrollReaction } from '@aglyn/shared-ui-jsx/components/scroll-reaction'\nimport MuiAppBar, { type AppBarProps } from '@mui/material/AppBar'\nimport { type SxProps, type Theme } from '@mui/material/styles'\nimport { createElement, forwardRef, type Ref } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport {\n applySemanticElement,\n semanticElementAttribute,\n semanticElementLabelAttribute,\n} from '../utils/element-picker'\nimport { FIELD_COLOR_ALT1, FIELD_POSITION } from '../constants/field-presets'\nimport { dropClearedProps } from '../utils/drop-cleared-props'\nimport { generatePresetId } from '../utils/generate-preset-id'\nimport { UNDER_HEADER_ATTRIBUTE } from './section'\nimport { ID as toolbarId } from './toolbar'\n\nexport interface AglynAppBarProps extends AppBarProps {\n /**\n * Compacts the bar's Toolbar Content to the dense height once the page\n * has scrolled, and back at the top. Meant for a pinned (sticky/fixed)\n * bar, where the full height costs the reader a band of every screen.\n */\n shrinkOnScroll?: boolean\n /**\n * Slides the bar up out of view while the visitor scrolls down, and back\n * the moment they scroll up. Meant for a pinned (sticky/fixed) bar.\n */\n hideOnScroll?: boolean\n /**\n * Sits over a photo hero (AGL-3660): on a page whose first band runs under\n * the header (a Section with `underHeader`), the bar lies over that band\n * with no background of its own and its words in white, and scrolls away\n * with it; on every other page it is the bar it always was.\n */\n overHero?: boolean\n}\n\n/**\n * Over a page that opens under the header, the bar lies on the photo. One\n * rule the browser applies by what the page holds, so the server render, the\n * published page and every page of a layout share one class, and a page\n * without such a band is untouched.\n */\nexport const overHeroSx = (theme: Theme) => ({\n [`body:has([${UNDER_HEADER_ATTRIBUTE}]) &`]: {\n position: 'absolute',\n // Below the owner's admin bar when one is up (the tenant publishes its\n // live height on `<html>`), at the very top for everyone else. Absolute\n // to the initial containing block, the bar's `<html>` margin never\n // moves this header — the variable is what does (AGL-3660).\n top: 'var(--aglyn-admin-bar-height, 0px)',\n left: 0,\n right: 0,\n backgroundColor: 'transparent',\n backgroundImage: 'none',\n boxShadow: 'none',\n borderBottom: 0,\n color: theme.palette.common.white,\n },\n})\n\nfunction withOverHeroSx(sx: AppBarProps['sx']): AppBarProps['sx'] {\n return [overHeroSx, ...(Array.isArray(sx) ? sx : [sx])] as AppBarProps['sx']\n}\n\n/** Scroll distance before a shrinking bar compacts. */\nconst SHRINK_THRESHOLD = 16\n/** Scroll distance before a hiding bar may slide away — past its own height. */\nconst HIDE_THRESHOLD = 120\n\n/**\n * Both scroll states ride data attributes, not a re-styled sx, so the\n * server render and every scroll position share one emotion class.\n */\nconst scrollSx: SxProps<Theme> = (theme) => ({\n transition: theme.transitions.create(['transform', 'box-shadow'], {\n duration: theme.transitions.duration.shorter,\n }),\n '& .MuiToolbar-root': {\n transition: theme.transitions.create('min-height', {\n duration: theme.transitions.duration.shorter,\n }),\n },\n '&[data-scrolled] .MuiToolbar-root': {\n // MUI's dense toolbar height.\n minHeight: theme.spacing(6),\n },\n '&[data-scroll-hidden]': {\n transform: 'translateY(-100%)',\n },\n})\n\nfunction withScrollSx(sx: AppBarProps['sx']): AppBarProps['sx'] {\n return [scrollSx, ...(Array.isArray(sx) ? sx : [sx])] as AppBarProps['sx']\n}\n\nfunction renderAppBar(props: AppBarProps, ref: Ref<HTMLElement>) {\n return createElement(MuiAppBar, {\n // Unset leaves MUI's own default, which is `header` — the banner\n // landmark every site's chrome depends on (AGL-2525). A resolver that\n // answered `div` for \"unset\" would have stripped it the moment the\n // picker appeared.\n ...applySemanticElement(dropClearedProps(props) as Record<string, unknown>),\n ref,\n })\n}\n\ninterface ScrollAwareAppBarProps extends AppBarProps {\n shrink: boolean\n hide: boolean\n}\n\n/**\n * Its own component so the scroll listeners exist only on a bar that asked\n * to react — a hook behind a prop check would break the rules of hooks.\n * `ScrollReaction` answers both questions: past the threshold (shrink),\n * and scrolling down rather than up (hide), which is what MUI's scroll\n * trigger means by hysteresis.\n */\nconst ScrollAwareAppBar = forwardRef<HTMLElement, ScrollAwareAppBarProps>(\n ({ shrink, hide, ...props }, ref) =>\n createElement(ScrollReaction, {\n threshold: SHRINK_THRESHOLD,\n withHysteresis: { threshold: HIDE_THRESHOLD },\n children: ({ activeWithHysteresis, activeWithoutHysteresis }) =>\n renderAppBar(\n {\n ...props,\n sx: withScrollSx(props.sx),\n ...({\n 'data-scrolled':\n shrink && activeWithoutHysteresis ? '' : undefined,\n 'data-scroll-hidden':\n hide && activeWithHysteresis ? '' : undefined,\n } as AppBarProps),\n },\n ref,\n ),\n }),\n)\nScrollAwareAppBar.displayName = 'AglynScrollAwareAppBar'\n\n/**\n * MUI's AppBar behind the cleared-prop guard (AGL-1226).\n *\n * It was exported raw, which left BOTH of its authorable attributes exposed:\n * `color` and `position` are each run through MUI's `capitalize`, so clearing\n * either one persists a null that throws during SSR and 500s the page. A\n * wrapper is the only place to intercept it, since the schema's props reach\n * MUI directly. `createElement` rather than JSX keeps this a `.ts` file.\n */\nconst AppBar = forwardRef<HTMLElement, AglynAppBarProps>(\n ({ shrinkOnScroll, hideOnScroll, overHero, ...rest }, ref) => {\n const props = overHero ? { ...rest, sx: withOverHeroSx(rest.sx) } : rest\n return shrinkOnScroll || hideOnScroll\n ? createElement(ScrollAwareAppBar, {\n ...props,\n shrink: Boolean(shrinkOnScroll),\n hide: Boolean(hideOnScroll),\n ref,\n })\n : renderAppBar(props, ref)\n },\n)\nAppBar.displayName = 'AglynAppBar'\n\n// Component ids are persisted in screen documents; keep the legacy ids.\nexport const ID: Aglyn.ComponentId = 'muiAppBar'\n\nexport const schema: Aglyn.ComponentSchema<AglynAppBarProps> = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'App Bar',\n description:\n 'The bar across the top of the site — put a Toolbar Content inside it.',\n category: Aglyn.ComponentCategory.NAVIGATION,\n icon: {\n path: mdiPageLayoutHeader.path,\n sx: { color: '#2196f3' },\n },\n attributes: [\n semanticElementAttribute('this bar'),\n semanticElementLabelAttribute(),\n FIELD_COLOR_ALT1,\n FIELD_POSITION,\n {\n name: 'shrinkOnScroll',\n description:\n 'Compacts the bar to the dense height once the page scrolls, and ' +\n 'restores it at the top. Pair with a Sticky or Fixed position.',\n component: Aglyn.FieldComponentType.SWITCH,\n label: 'Shrink when scrolled?',\n },\n {\n name: 'hideOnScroll',\n description:\n 'Slides the bar up out of view while the visitor scrolls down, and ' +\n 'back as soon as they scroll up. Pair with a Sticky or Fixed position.',\n component: Aglyn.FieldComponentType.SWITCH,\n label: 'Hide while scrolling down?',\n },\n {\n name: 'overHero',\n description:\n 'On a page whose first band is set to run under the header, the bar ' +\n 'sits over that photo with no background and white words. Other ' +\n 'pages keep the bar as it is.',\n component: Aglyn.FieldComponentType.SWITCH,\n label: 'Sit over a photo hero?',\n },\n ],\n}\n\nexport const presets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'App Bar',\n pluginId: BUNDLE_ID,\n description: 'An app bar preset with the app bar and toolbar content nodes',\n category: Aglyn.ComponentCategory.NAVIGATION,\n icon: schema.icon,\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n nodes: [\n {\n $id: null,\n componentId: toolbarId,\n pluginId: BUNDLE_ID,\n props: {},\n },\n ],\n },\n },\n]\n\nexport default AppBar\n"],"names":["Aglyn","mdiPageLayoutHeader","ScrollReaction","MuiAppBar","createElement","forwardRef","BUNDLE_ID","applySemanticElement","semanticElementAttribute","semanticElementLabelAttribute","FIELD_COLOR_ALT1","FIELD_POSITION","dropClearedProps","generatePresetId","UNDER_HEADER_ATTRIBUTE","ID","toolbarId","overHeroSx","theme","position","top","left","right","backgroundColor","backgroundImage","boxShadow","borderBottom","color","palette","common","white","withOverHeroSx","sx","Array","isArray","SHRINK_THRESHOLD","HIDE_THRESHOLD","scrollSx","transition","transitions","create","duration","shorter","minHeight","spacing","transform","withScrollSx","renderAppBar","props","ref","ScrollAwareAppBar","shrink","hide","threshold","withHysteresis","children","activeWithHysteresis","activeWithoutHysteresis","undefined","displayName","AppBar","shrinkOnScroll","hideOnScroll","overHero","rest","Boolean","schema","$id","pluginId","description","category","ComponentCategory","NAVIGATION","icon","path","attributes","name","component","FieldComponentType","SWITCH","label","presets","type","NodeType","PRESET","data","componentId","nodes"],"mappings":"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"}
@@ -16,7 +16,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
16
16
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
17
  * See the License for the specific language governing permissions and
18
18
  * limitations under the License.
19
- */ import * as Aglyn from "@aglyn/aglyn";
19
+ */ import { advertisingConsentField } from "@aglyn/aglyn/app-utils/advertising-consent";
20
+ import * as Aglyn from "@aglyn/aglyn";
20
21
  import { buildBeginCheckoutParams, trackEventBeforeNavigation } from "@aglyn/aglyn/app-utils/analytics-events";
21
22
  import { mdiCartOutline } from "@aglyn/shared-data-mdi";
22
23
  import Alert from "@mui/material/Alert";
@@ -77,7 +78,7 @@ export const ID = 'product';
77
78
  productId
78
79
  }, coupon.trim() ? {
79
80
  couponCode: coupon.trim()
80
- } : {}))
81
+ } : {}, advertisingConsentField(hostId)))
81
82
  });
82
83
  const payload = await response.json().catch(()=>({}));
83
84
  if (response.ok && (payload == null ? void 0 : payload.url)) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/product.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 buildBeginCheckoutParams,\n trackEventBeforeNavigation,\n} from '@aglyn/aglyn/app-utils/analytics-events'\nimport { mdiCartOutline } from '@aglyn/shared-data-mdi'\nimport Alert from '@mui/material/Alert'\nimport Button from '@mui/material/Button'\nimport Card from '@mui/material/Card'\nimport CardContent from '@mui/material/CardContent'\nimport CardMedia from '@mui/material/CardMedia'\nimport TextField from '@mui/material/TextField'\nimport Typography from '@mui/material/Typography'\nimport { forwardRef, useCallback, useState } 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 = 'product'\n\nexport interface ProductProps {\n /** Id of the product doc under hosts/{hostId}/products. */\n productId?: string\n name?: string\n /** Display price; the charge always uses the product doc's price. */\n priceUsd?: string\n description?: string\n imageUrl?: string\n buyLabel?: string\n /** Shows a coupon-code input above the buy button (AGL-96). */\n showCoupon?: boolean\n}\n\n/**\n * Commerce Starter product block (AGL-90): displays from its own props,\n * but Buy posts {hostId, productId} to the tenant's /api/commerce/checkout,\n * which prices from the server-side product doc — canvas props can't forge\n * a charge. Inert without SiteContext (besigner canvas/preview).\n */\nconst Product = forwardRef<HTMLDivElement, ProductProps>((props, ref) => {\n const {\n productId,\n name,\n priceUsd,\n description,\n imageUrl: storedImageUrl,\n buyLabel,\n showCoupon,\n ...rest\n } = props\n const { hostId } = Aglyn.useSite()\n const siteFetch = Aglyn.useSiteFetch()\n // A media-picker target, so it can hold a media reference (AGL-1215) as\n // well as any URL form that predates it. `siteRelativeMediaSrc` rather\n // than the bare resolver (AGL-1726): one of those older forms is an\n // absolute `https://{subdomain}.aglyn.app/api/media/cdn/…`, which on a\n // white-label storefront names our platform in the customer's page source\n // and fetches cross-origin from their own domain.\n const imageUrl = Aglyn.siteRelativeMediaSrc(storedImageUrl, { hostId })\n const [status, setStatus] = useState<'idle' | 'sending' | 'error'>('idle')\n const [coupon, setCoupon] = useState('')\n const [message, setMessage] = useState('')\n const soldOut = message === 'Sold out'\n\n const handleBuy = useCallback(async () => {\n if (!hostId || !productId || status === 'sending') return\n setStatus('sending')\n setMessage('')\n try {\n const response = await siteFetch('/api/commerce/checkout', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n hostId,\n productId,\n ...(coupon.trim() ? { couponCode: coupon.trim() } : {}),\n }),\n })\n const payload = await response.json().catch(() => ({}))\n if (response.ok && payload?.url) {\n // The Starter block's `begin_checkout`. It takes real money through\n // Stripe and reported nothing, so a site built from this block alone\n // showed GA4 a `purchase` with no checkout step in front of it — which\n // reads as a 0% checkout rate rather than as an unmeasured path.\n //\n // Fired only after the server has ACCEPTED the request and returned a\n // session url, never on the click: a count inflated by sold-out\n // products and rejected coupons describes attempts, not checkouts.\n //\n // `value` is the price the SHOPPER SAW, which is the block's own prop.\n // The charge is priced server-side from the product doc — an author\n // who edits one without the other has a storefront that lies to\n // shoppers before it lies to GA — and an unparseable or absent price\n // reports no event at all, because a `value: 0` on a real sale is a\n // worse number than a missing one.\n const shownPrice = Number(priceUsd)\n if (Number.isFinite(shownPrice) && shownPrice > 0) {\n await trackEventBeforeNavigation(\n 'begin_checkout',\n buildBeginCheckoutParams({\n items: [\n {\n item_id: productId,\n item_name: name || 'Product',\n price: shownPrice,\n quantity: 1,\n },\n ],\n }),\n )\n }\n window.location.assign(payload.url)\n return\n }\n // Server messages are visitor-safe (AGL-96): \"Sold out\", \"Invalid\n // or expired coupon\", etc.\n setMessage(String(payload?.error ?? ''))\n setStatus('error')\n } catch {\n setStatus('error')\n }\n }, [hostId, productId, status, coupon, siteFetch])\n\n return (\n <Card ref={ref} variant=\"outlined\" sx={{ maxWidth: 360 }} {...rest}>\n {imageUrl ? (\n <CardMedia\n component=\"img\"\n image={imageUrl}\n alt={name ?? ''}\n sx={{ height: 200, objectFit: 'cover' }}\n // Deferred (AGL-2486). A Product card is a 360px-wide card dropped\n // into a page; it is never the page's lead image, and before this\n // it carried no loading hint at all — i.e. EAGER at default\n // priority, outranking the `lazy` + `low` Image elements in the\n // section the reader was actually looking at.\n {...Aglyn.DEFERRED_IMAGE_ATTRIBUTES}\n />\n ) : null}\n <CardContent>\n <Typography variant=\"h6\">{name || 'Product name'}</Typography>\n {priceUsd ? (\n <Typography variant=\"subtitle1\" color=\"text.secondary\">\n {`$${priceUsd}`}\n </Typography>\n ) : null}\n {description ? (\n <Typography variant=\"body2\" sx={{ mt: 1 }}>\n {description}\n </Typography>\n ) : null}\n {status === 'error' ? (\n <Alert severity={soldOut ? 'info' : 'error'} sx={{ mt: 1 }}>\n {message || 'Checkout is unavailable right now.'}\n </Alert>\n ) : null}\n {showCoupon && !soldOut ? (\n <TextField\n size=\"small\"\n fullWidth\n label=\"Coupon code\"\n value={coupon}\n onChange={(event) => setCoupon(event.target.value)}\n sx={{ mt: 1.5 }}\n />\n ) : null}\n <Button\n variant=\"contained\"\n color=\"primary\"\n sx={{ mt: 2 }}\n disabled={status === 'sending' || soldOut}\n onClick={handleBuy}\n fullWidth\n >\n {soldOut\n ? 'Sold out'\n : status === 'sending'\n ? 'Redirecting…'\n : buyLabel || 'Buy now'}\n </Button>\n </CardContent>\n </Card>\n )\n})\nProduct.displayName = 'AglynProduct'\n\nexport const schema: Aglyn.ComponentSchema<ProductProps> = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'Product',\n description: 'A single product card with a buy button, priced on the server.',\n category: Aglyn.ComponentCategory.COMMERCE,\n icon: { path: mdiCartOutline.path, sx: { color: '#2e7d32' } },\n flags: { selfClosing: Aglyn.FEATURE_FLAG.ENABLED },\n attributes: [\n {\n name: 'productId',\n description:\n 'Product id from the Products card on the host dashboard — the ' +\n 'charge uses that product’s price.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n label: 'Product id',\n },\n {\n name: 'name',\n description: 'Displayed product name.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n label: 'Name',\n },\n {\n name: 'priceUsd',\n description: 'Displayed price (the charge uses the product doc).',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n label: 'Price (USD)',\n },\n {\n name: 'description',\n description: 'Short product description.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n label: 'Description',\n },\n {\n name: 'imageUrl',\n description: 'Product image URL (copy from the Media library).',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n label: 'Image URL',\n },\n {\n name: 'buyLabel',\n description: 'Buy button label.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n label: 'Button label',\n },\n {\n name: 'showCoupon',\n label: 'Show coupon field',\n description:\n 'Adds a coupon-code input; codes are managed on the Products card.',\n component: Aglyn.FieldComponentType.CHECKBOX,\n },\n ],\n}\n\nexport const presets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Product',\n pluginId: BUNDLE_ID,\n description: 'Product card with a Stripe Checkout buy button',\n category: Aglyn.ComponentCategory.COMMERCE,\n icon: { path: mdiCartOutline.path, sx: { color: '#2e7d32' } },\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: {\n name: 'My product',\n priceUsd: '25',\n description: 'A short description of what the buyer gets.',\n buyLabel: 'Buy now',\n },\n },\n },\n]\n\nexport default Product\n"],"names":["Aglyn","buildBeginCheckoutParams","trackEventBeforeNavigation","mdiCartOutline","Alert","Button","Card","CardContent","CardMedia","TextField","Typography","forwardRef","useCallback","useState","BUNDLE_ID","generatePresetId","ID","Product","props","ref","productId","name","priceUsd","description","imageUrl","storedImageUrl","buyLabel","showCoupon","rest","hostId","useSite","siteFetch","useSiteFetch","siteRelativeMediaSrc","status","setStatus","coupon","setCoupon","message","setMessage","soldOut","handleBuy","response","method","headers","body","JSON","stringify","trim","couponCode","payload","json","catch","ok","url","shownPrice","Number","isFinite","items","item_id","item_name","price","quantity","window","location","assign","String","error","variant","sx","maxWidth","component","image","alt","height","objectFit","DEFERRED_IMAGE_ATTRIBUTES","color","mt","severity","size","fullWidth","label","value","onChange","event","target","disabled","onClick","displayName","schema","$id","pluginId","category","ComponentCategory","COMMERCE","icon","path","flags","selfClosing","FEATURE_FLAG","ENABLED","attributes","FieldComponentType","TEXT_FIELD","CHECKBOX","presets","type","NodeType","PRESET","data","componentId"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/product.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 { advertisingConsentField } from '@aglyn/aglyn/app-utils/advertising-consent'\nimport * as Aglyn from '@aglyn/aglyn'\nimport {\n buildBeginCheckoutParams,\n trackEventBeforeNavigation,\n} from '@aglyn/aglyn/app-utils/analytics-events'\nimport { mdiCartOutline } from '@aglyn/shared-data-mdi'\nimport Alert from '@mui/material/Alert'\nimport Button from '@mui/material/Button'\nimport Card from '@mui/material/Card'\nimport CardContent from '@mui/material/CardContent'\nimport CardMedia from '@mui/material/CardMedia'\nimport TextField from '@mui/material/TextField'\nimport Typography from '@mui/material/Typography'\nimport { forwardRef, useCallback, useState } 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 = 'product'\n\nexport interface ProductProps {\n /** Id of the product doc under hosts/{hostId}/products. */\n productId?: string\n name?: string\n /** Display price; the charge always uses the product doc's price. */\n priceUsd?: string\n description?: string\n imageUrl?: string\n buyLabel?: string\n /** Shows a coupon-code input above the buy button (AGL-96). */\n showCoupon?: boolean\n}\n\n/**\n * Commerce Starter product block (AGL-90): displays from its own props,\n * but Buy posts {hostId, productId} to the tenant's /api/commerce/checkout,\n * which prices from the server-side product doc — canvas props can't forge\n * a charge. Inert without SiteContext (besigner canvas/preview).\n */\nconst Product = forwardRef<HTMLDivElement, ProductProps>((props, ref) => {\n const {\n productId,\n name,\n priceUsd,\n description,\n imageUrl: storedImageUrl,\n buyLabel,\n showCoupon,\n ...rest\n } = props\n const { hostId } = Aglyn.useSite()\n const siteFetch = Aglyn.useSiteFetch()\n // A media-picker target, so it can hold a media reference (AGL-1215) as\n // well as any URL form that predates it. `siteRelativeMediaSrc` rather\n // than the bare resolver (AGL-1726): one of those older forms is an\n // absolute `https://{subdomain}.aglyn.app/api/media/cdn/…`, which on a\n // white-label storefront names our platform in the customer's page source\n // and fetches cross-origin from their own domain.\n const imageUrl = Aglyn.siteRelativeMediaSrc(storedImageUrl, { hostId })\n const [status, setStatus] = useState<'idle' | 'sending' | 'error'>('idle')\n const [coupon, setCoupon] = useState('')\n const [message, setMessage] = useState('')\n const soldOut = message === 'Sold out'\n\n const handleBuy = useCallback(async () => {\n if (!hostId || !productId || status === 'sending') return\n setStatus('sending')\n setMessage('')\n try {\n const response = await siteFetch('/api/commerce/checkout', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n hostId,\n productId,\n ...(coupon.trim() ? { couponCode: coupon.trim() } : {}),\n // The visitor's advertising consent and the vendors' browser ids, only\n // where that consent grants advertising (AGL-3694); absent otherwise.\n ...advertisingConsentField(hostId),\n }),\n })\n const payload = await response.json().catch(() => ({}))\n if (response.ok && payload?.url) {\n // The Starter block's `begin_checkout`. It takes real money through\n // Stripe and reported nothing, so a site built from this block alone\n // showed GA4 a `purchase` with no checkout step in front of it — which\n // reads as a 0% checkout rate rather than as an unmeasured path.\n //\n // Fired only after the server has ACCEPTED the request and returned a\n // session url, never on the click: a count inflated by sold-out\n // products and rejected coupons describes attempts, not checkouts.\n //\n // `value` is the price the SHOPPER SAW, which is the block's own prop.\n // The charge is priced server-side from the product doc — an author\n // who edits one without the other has a storefront that lies to\n // shoppers before it lies to GA — and an unparseable or absent price\n // reports no event at all, because a `value: 0` on a real sale is a\n // worse number than a missing one.\n const shownPrice = Number(priceUsd)\n if (Number.isFinite(shownPrice) && shownPrice > 0) {\n await trackEventBeforeNavigation(\n 'begin_checkout',\n buildBeginCheckoutParams({\n items: [\n {\n item_id: productId,\n item_name: name || 'Product',\n price: shownPrice,\n quantity: 1,\n },\n ],\n }),\n )\n }\n window.location.assign(payload.url)\n return\n }\n // Server messages are visitor-safe (AGL-96): \"Sold out\", \"Invalid\n // or expired coupon\", etc.\n setMessage(String(payload?.error ?? ''))\n setStatus('error')\n } catch {\n setStatus('error')\n }\n }, [hostId, productId, status, coupon, siteFetch])\n\n return (\n <Card ref={ref} variant=\"outlined\" sx={{ maxWidth: 360 }} {...rest}>\n {imageUrl ? (\n <CardMedia\n component=\"img\"\n image={imageUrl}\n alt={name ?? ''}\n sx={{ height: 200, objectFit: 'cover' }}\n // Deferred (AGL-2486). A Product card is a 360px-wide card dropped\n // into a page; it is never the page's lead image, and before this\n // it carried no loading hint at all — i.e. EAGER at default\n // priority, outranking the `lazy` + `low` Image elements in the\n // section the reader was actually looking at.\n {...Aglyn.DEFERRED_IMAGE_ATTRIBUTES}\n />\n ) : null}\n <CardContent>\n <Typography variant=\"h6\">{name || 'Product name'}</Typography>\n {priceUsd ? (\n <Typography variant=\"subtitle1\" color=\"text.secondary\">\n {`$${priceUsd}`}\n </Typography>\n ) : null}\n {description ? (\n <Typography variant=\"body2\" sx={{ mt: 1 }}>\n {description}\n </Typography>\n ) : null}\n {status === 'error' ? (\n <Alert severity={soldOut ? 'info' : 'error'} sx={{ mt: 1 }}>\n {message || 'Checkout is unavailable right now.'}\n </Alert>\n ) : null}\n {showCoupon && !soldOut ? (\n <TextField\n size=\"small\"\n fullWidth\n label=\"Coupon code\"\n value={coupon}\n onChange={(event) => setCoupon(event.target.value)}\n sx={{ mt: 1.5 }}\n />\n ) : null}\n <Button\n variant=\"contained\"\n color=\"primary\"\n sx={{ mt: 2 }}\n disabled={status === 'sending' || soldOut}\n onClick={handleBuy}\n fullWidth\n >\n {soldOut\n ? 'Sold out'\n : status === 'sending'\n ? 'Redirecting…'\n : buyLabel || 'Buy now'}\n </Button>\n </CardContent>\n </Card>\n )\n})\nProduct.displayName = 'AglynProduct'\n\nexport const schema: Aglyn.ComponentSchema<ProductProps> = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'Product',\n description: 'A single product card with a buy button, priced on the server.',\n category: Aglyn.ComponentCategory.COMMERCE,\n icon: { path: mdiCartOutline.path, sx: { color: '#2e7d32' } },\n flags: { selfClosing: Aglyn.FEATURE_FLAG.ENABLED },\n attributes: [\n {\n name: 'productId',\n description:\n 'Product id from the Products card on the host dashboard — the ' +\n 'charge uses that product’s price.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n label: 'Product id',\n },\n {\n name: 'name',\n description: 'Displayed product name.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n label: 'Name',\n },\n {\n name: 'priceUsd',\n description: 'Displayed price (the charge uses the product doc).',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n label: 'Price (USD)',\n },\n {\n name: 'description',\n description: 'Short product description.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n label: 'Description',\n },\n {\n name: 'imageUrl',\n description: 'Product image URL (copy from the Media library).',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n label: 'Image URL',\n },\n {\n name: 'buyLabel',\n description: 'Buy button label.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n label: 'Button label',\n },\n {\n name: 'showCoupon',\n label: 'Show coupon field',\n description:\n 'Adds a coupon-code input; codes are managed on the Products card.',\n component: Aglyn.FieldComponentType.CHECKBOX,\n },\n ],\n}\n\nexport const presets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Product',\n pluginId: BUNDLE_ID,\n description: 'Product card with a Stripe Checkout buy button',\n category: Aglyn.ComponentCategory.COMMERCE,\n icon: { path: mdiCartOutline.path, sx: { color: '#2e7d32' } },\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: {\n name: 'My product',\n priceUsd: '25',\n description: 'A short description of what the buyer gets.',\n buyLabel: 'Buy now',\n },\n },\n },\n]\n\nexport default Product\n"],"names":["advertisingConsentField","Aglyn","buildBeginCheckoutParams","trackEventBeforeNavigation","mdiCartOutline","Alert","Button","Card","CardContent","CardMedia","TextField","Typography","forwardRef","useCallback","useState","BUNDLE_ID","generatePresetId","ID","Product","props","ref","productId","name","priceUsd","description","imageUrl","storedImageUrl","buyLabel","showCoupon","rest","hostId","useSite","siteFetch","useSiteFetch","siteRelativeMediaSrc","status","setStatus","coupon","setCoupon","message","setMessage","soldOut","handleBuy","response","method","headers","body","JSON","stringify","trim","couponCode","payload","json","catch","ok","url","shownPrice","Number","isFinite","items","item_id","item_name","price","quantity","window","location","assign","String","error","variant","sx","maxWidth","component","image","alt","height","objectFit","DEFERRED_IMAGE_ATTRIBUTES","color","mt","severity","size","fullWidth","label","value","onChange","event","target","disabled","onClick","displayName","schema","$id","pluginId","category","ComponentCategory","COMMERCE","icon","path","flags","selfClosing","FEATURE_FLAG","ENABLED","attributes","FieldComponentType","TEXT_FIELD","CHECKBOX","presets","type","NodeType","PRESET","data","componentId"],"mappings":"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"}