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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/package.json +7 -7
  2. package/src/lib/components/collection-author-links.d.ts +41 -0
  3. package/src/lib/components/collection-author-links.js +135 -0
  4. package/src/lib/components/collection-author-links.js.map +1 -0
  5. package/src/lib/components/collection-author-profile.d.ts +67 -0
  6. package/src/lib/components/collection-author-profile.js +269 -0
  7. package/src/lib/components/collection-author-profile.js.map +1 -0
  8. package/src/lib/components/collection-categories.d.ts +52 -0
  9. package/src/lib/components/collection-categories.js +163 -0
  10. package/src/lib/components/collection-categories.js.map +1 -0
  11. package/src/lib/components/collection-common.d.ts +104 -0
  12. package/src/lib/components/collection-common.js +95 -0
  13. package/src/lib/components/collection-common.js.map +1 -0
  14. package/src/lib/components/collection-entries.d.ts +137 -0
  15. package/src/lib/components/collection-entries.js +358 -0
  16. package/src/lib/components/collection-entries.js.map +1 -0
  17. package/src/lib/components/collection-entry-author.d.ts +81 -0
  18. package/src/lib/components/collection-entry-author.js +259 -0
  19. package/src/lib/components/collection-entry-author.js.map +1 -0
  20. package/src/lib/components/collection-entry-body.d.ts +44 -0
  21. package/src/lib/components/collection-entry-body.js +328 -0
  22. package/src/lib/components/collection-entry-body.js.map +1 -0
  23. package/src/lib/components/collection-entry-meta.d.ts +88 -0
  24. package/src/lib/components/collection-entry-meta.js +331 -0
  25. package/src/lib/components/collection-entry-meta.js.map +1 -0
  26. package/src/lib/components/collection-presets.d.ts +18 -0
  27. package/src/lib/components/collection-presets.js +328 -0
  28. package/src/lib/components/collection-presets.js.map +1 -0
  29. package/src/lib/components/collection-related.d.ts +101 -0
  30. package/src/lib/components/collection-related.js +536 -0
  31. package/src/lib/components/collection-related.js.map +1 -0
  32. package/src/lib/components/collection-search-box.d.ts +92 -0
  33. package/src/lib/components/collection-search-box.js +334 -0
  34. package/src/lib/components/collection-search-box.js.map +1 -0
  35. package/src/lib/components/collection-search-fuse.d.ts +28 -0
  36. package/src/lib/components/collection-search-fuse.js +28 -0
  37. package/src/lib/components/collection-search-fuse.js.map +1 -0
  38. package/src/lib/components/collection-search.d.ts +62 -0
  39. package/src/lib/components/collection-search.js +140 -0
  40. package/src/lib/components/collection-search.js.map +1 -0
  41. package/src/lib/components/collection-share.d.ts +31 -0
  42. package/src/lib/components/collection-share.js +154 -0
  43. package/src/lib/components/collection-share.js.map +1 -0
  44. package/src/lib/components/collection.d.ts +19 -497
  45. package/src/lib/components/collection.js +19 -2982
  46. package/src/lib/components/collection.js.map +1 -1
  47. package/src/lib/components/image-list.d.ts +2 -2
  48. package/src/lib/components/image-list.js +4 -6
  49. package/src/lib/components/image-list.js.map +1 -1
  50. package/src/lib/element-tier.d.ts +9 -1
  51. package/src/lib/element-tier.js +12 -1
  52. package/src/lib/element-tier.js.map +1 -1
  53. package/src/lib/plugin.js +20 -12
  54. package/src/lib/plugin.js.map +1 -1
  55. package/src/lib/utils/to-count.d.ts +25 -0
  56. package/src/lib/utils/to-count.js +30 -0
  57. package/src/lib/utils/to-count.js.map +1 -0
@@ -0,0 +1,140 @@
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 { mdiMagnify } from "@aglyn/shared-data-mdi";
21
+ import Box from "@mui/material/Box";
22
+ import MuiStack from "@mui/material/Stack";
23
+ import { forwardRef, useContext } from "react";
24
+ import { BUNDLE_ID } from "../constants/bundle-common.js";
25
+ import { SuggestSearchBox, useEntryFuse } from "./collection-search-box.js";
26
+ // Persisted component id (AGL-551/582); the compose pipeline references it
27
+ // through the @aglyn/aglyn constant. Never rename.
28
+ export const SEARCH_ID = Aglyn.COLLECTION_SEARCH_COMPONENT_ID;
29
+ /**
30
+ * A search box for a collection that lives where the author puts it
31
+ * (AGL-1516, Figma 494:1220).
32
+ *
33
+ * The entries block has had a search box since AGL-1516's first half, and it
34
+ * renders inside that block — first child of its own stack. The frame puts
35
+ * the field in the listing's TOOLBAR: category pills on the left, search and
36
+ * RSS on the right, one row. That was unbuildable, and unbuildable in both
37
+ * directions — a block's own child cannot be lifted out of it, and the pills
38
+ * cannot be moved in, because every child of an entries block is cloned once
39
+ * per entry. Three passes of authoring hit the same wall.
40
+ *
41
+ * So the field became its own block. It searches the collection the listing
42
+ * beside it is drawn from, and answers with the suggestion panel (496:1218)
43
+ * — the only behaviour a standalone box can honestly have, since it owns no
44
+ * cards to hide. Enter submits to the site-wide results page, so the box
45
+ * works with no JavaScript at all.
46
+ *
47
+ * Inert on editing surfaces, like Category Pills: the besigner has no index
48
+ * to search, and a field that answered there would be answering about
49
+ * nothing.
50
+ */ const CollectionSearch = /*#__PURE__*/ forwardRef((props, ref)=>{
51
+ // Compose-time and search-only attributes: strip so they never hit the
52
+ // DOM.
53
+ const { collectionSlug, searchPlaceholder, searchIndex, searchTotal, searchCapped } = props, rest = _object_without_properties_loose(props, [
54
+ "collectionSlug",
55
+ "searchPlaceholder",
56
+ "searchIndex",
57
+ "searchTotal",
58
+ "searchCapped"
59
+ ]);
60
+ // Node styles ride the renderer-merged sx; recompose (stack.ts pattern).
61
+ const nodeSx = Array.isArray(props['sx']) ? props['sx'] : [
62
+ props['sx']
63
+ ];
64
+ const { suppressNavigation } = useContext(Aglyn.ScreenLinkContext);
65
+ const { fuzzy, requestFuzzy } = useEntryFuse(searchIndex);
66
+ if (!suppressNavigation && !(searchIndex == null ? void 0 : searchIndex.length)) {
67
+ // Nothing stamped on a live surface: an unknown collection, an empty
68
+ // one, or a page composed before this block existed. Renders NOTHING
69
+ // rather than a field that can only ever answer "no matches" — that
70
+ // answer would read as a fact about the reader's query instead of
71
+ // about the absent index behind it.
72
+ return /*#__PURE__*/ _jsx(Box, _extends({
73
+ ref: ref
74
+ }, rest));
75
+ }
76
+ return /*#__PURE__*/ _jsx(MuiStack, _extends({
77
+ ref: ref
78
+ }, rest, {
79
+ sx: [
80
+ {
81
+ alignItems: 'flex-end'
82
+ },
83
+ ...nodeSx
84
+ ],
85
+ children: /*#__PURE__*/ _jsx(SuggestSearchBox, _extends({
86
+ fuzzy: fuzzy,
87
+ requestFuzzy: requestFuzzy
88
+ }, searchIndex ? {
89
+ items: searchIndex
90
+ } : {}, searchPlaceholder === undefined ? {} : {
91
+ placeholder: searchPlaceholder
92
+ }, suppressNavigation ? {
93
+ inert: true
94
+ } : {}, {
95
+ // The honest miss for THIS box. It searched one bounded read of the
96
+ // collection — never "the collection", and on a category route not
97
+ // even the whole of it, because the source arrives filtered. So it
98
+ // reports the number it actually looked through, and says plainly
99
+ // when that number was a ceiling rather than a total.
100
+ emptyText: (text)=>{
101
+ var _ref, _ref1;
102
+ return searchCapped ? `No matches for “${text}” in the ${(_ref = searchIndex == null ? void 0 : searchIndex.length) != null ? _ref : 0} ` + 'entries searched here — the collection holds more, which ' + 'this box has not read.' : `No matches for “${text}” in the ${(_ref1 = searchIndex == null ? void 0 : searchIndex.length) != null ? _ref1 : 0} ` + 'entries searched here.';
103
+ }
104
+ }))
105
+ }));
106
+ });
107
+ CollectionSearch.displayName = 'AglynCollectionSearch';
108
+ export const collectionSearchSchema = {
109
+ $id: SEARCH_ID,
110
+ pluginId: BUNDLE_ID,
111
+ displayName: 'Collection Search',
112
+ description: 'A search box for a content collection, with a suggestions dropdown.',
113
+ category: Aglyn.ComponentCategory.NAVIGATION,
114
+ icon: {
115
+ path: mdiMagnify.path,
116
+ sx: {
117
+ color: 'secondary.main'
118
+ }
119
+ },
120
+ flags: {
121
+ selfClosing: Aglyn.FEATURE_FLAG.ENABLED
122
+ },
123
+ attributes: [
124
+ {
125
+ name: 'collectionSlug',
126
+ label: 'Collection slug',
127
+ description: 'Content collection this box searches (e.g. "blog"). Leave blank ' + 'on a list-template screen to use the collection from the URL.',
128
+ component: Aglyn.FieldComponentType.TEXT_FIELD
129
+ },
130
+ {
131
+ name: 'searchPlaceholder',
132
+ label: 'Search placeholder',
133
+ description: 'Hint text inside this box. Blank shows "Search posts…", which is ' + 'worth changing when the collection is not posts.',
134
+ component: Aglyn.FieldComponentType.TEXT_FIELD
135
+ }
136
+ ]
137
+ };
138
+ export { CollectionSearch };
139
+
140
+ //# sourceMappingURL=collection-search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/collection-search.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 { mdiMagnify } from '@aglyn/shared-data-mdi'\nimport Box from '@mui/material/Box'\nimport MuiStack, { type StackProps } from '@mui/material/Stack'\nimport { forwardRef, useContext } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport { SuggestSearchBox, useEntryFuse } from './collection-search-box'\n\n// Persisted component id (AGL-551/582); the compose pipeline references it\n// through the @aglyn/aglyn constant. Never rename.\nexport const SEARCH_ID: Aglyn.ComponentId = Aglyn.COLLECTION_SEARCH_COMPONENT_ID\n\nexport interface CollectionSearchProps extends StackProps {\n /**\n * Collection whose entries this box searches (compose-time). Blank = the\n * collection routed by the current URL on list-template screens.\n */\n collectionSlug?: string\n /** Hint text inside the box (blank = \"Search posts…\"). */\n searchPlaceholder?: string\n /**\n * Server-stamped matchable text per entry (`expandCollectionSearch`);\n * never set by hand.\n */\n searchIndex?: Aglyn.CollectionEntrySearchItem[]\n /** How many entries the index was drawn from; never set by hand. */\n searchTotal?: number\n /** Whether that read reached its bound; never set by hand. */\n searchCapped?: boolean\n}\n\n/**\n * A search box for a collection that lives where the author puts it\n * (AGL-1516, Figma 494:1220).\n *\n * The entries block has had a search box since AGL-1516's first half, and it\n * renders inside that block — first child of its own stack. The frame puts\n * the field in the listing's TOOLBAR: category pills on the left, search and\n * RSS on the right, one row. That was unbuildable, and unbuildable in both\n * directions — a block's own child cannot be lifted out of it, and the pills\n * cannot be moved in, because every child of an entries block is cloned once\n * per entry. Three passes of authoring hit the same wall.\n *\n * So the field became its own block. It searches the collection the listing\n * beside it is drawn from, and answers with the suggestion panel (496:1218)\n * — the only behaviour a standalone box can honestly have, since it owns no\n * cards to hide. Enter submits to the site-wide results page, so the box\n * works with no JavaScript at all.\n *\n * Inert on editing surfaces, like Category Pills: the besigner has no index\n * to search, and a field that answered there would be answering about\n * nothing.\n */\nconst CollectionSearch = forwardRef<HTMLDivElement, CollectionSearchProps>(\n (props, ref) => {\n // Compose-time and search-only attributes: strip so they never hit the\n // DOM.\n const {\n collectionSlug,\n searchPlaceholder,\n searchIndex,\n searchTotal,\n searchCapped,\n ...rest\n } = 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 { fuzzy, requestFuzzy } = useEntryFuse(searchIndex)\n if (!suppressNavigation && !searchIndex?.length) {\n // Nothing stamped on a live surface: an unknown collection, an empty\n // one, or a page composed before this block existed. Renders NOTHING\n // rather than a field that can only ever answer \"no matches\" — that\n // answer would read as a fact about the reader's query instead of\n // about the absent index behind it.\n return <Box ref={ref} {...rest} />\n }\n return (\n <MuiStack ref={ref} {...rest} sx={[{ alignItems: 'flex-end' }, ...nodeSx]}>\n <SuggestSearchBox\n fuzzy={fuzzy}\n requestFuzzy={requestFuzzy}\n {...(searchIndex ? { items: searchIndex } : {})}\n {...(searchPlaceholder === undefined\n ? {}\n : { placeholder: searchPlaceholder })}\n {...(suppressNavigation ? { inert: true } : {})}\n // The honest miss for THIS box. It searched one bounded read of the\n // collection — never \"the collection\", and on a category route not\n // even the whole of it, because the source arrives filtered. So it\n // reports the number it actually looked through, and says plainly\n // when that number was a ceiling rather than a total.\n emptyText={(text) =>\n searchCapped\n ? `No matches for “${text}” in the ${searchIndex?.length ?? 0} ` +\n 'entries searched here — the collection holds more, which ' +\n 'this box has not read.'\n : `No matches for “${text}” in the ${searchIndex?.length ?? 0} ` +\n 'entries searched here.'\n }\n />\n </MuiStack>\n )\n },\n)\nCollectionSearch.displayName = 'AglynCollectionSearch'\n\nexport const collectionSearchSchema: Aglyn.ComponentSchema<CollectionSearchProps> =\n {\n $id: SEARCH_ID,\n pluginId: BUNDLE_ID,\n displayName: 'Collection Search',\n description:\n 'A search box for a content collection, with a suggestions dropdown.',\n category: Aglyn.ComponentCategory.NAVIGATION,\n icon: { path: mdiMagnify.path, sx: { color: 'secondary.main' } },\n flags: { selfClosing: Aglyn.FEATURE_FLAG.ENABLED },\n attributes: [\n {\n name: 'collectionSlug',\n label: 'Collection slug',\n description:\n 'Content collection this box searches (e.g. \"blog\"). Leave blank ' +\n 'on a list-template screen to use the collection from the URL.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n },\n {\n name: 'searchPlaceholder',\n label: 'Search placeholder',\n description:\n 'Hint text inside this box. Blank shows \"Search posts…\", which is ' +\n 'worth changing when the collection is not posts.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n },\n // `searchIndex`, `searchTotal` and `searchCapped` are deliberately NOT\n // attributes: all three are server-stamped facts about a read, and an\n // author who could edit them could make the box lie about its own\n // reach.\n ],\n }\n\nexport { CollectionSearch }\n"],"names":["Aglyn","mdiMagnify","Box","MuiStack","forwardRef","useContext","BUNDLE_ID","SuggestSearchBox","useEntryFuse","SEARCH_ID","COLLECTION_SEARCH_COMPONENT_ID","CollectionSearch","props","ref","collectionSlug","searchPlaceholder","searchIndex","searchTotal","searchCapped","rest","nodeSx","Array","isArray","suppressNavigation","ScreenLinkContext","fuzzy","requestFuzzy","length","sx","alignItems","items","undefined","placeholder","inert","emptyText","text","displayName","collectionSearchSchema","$id","pluginId","description","category","ComponentCategory","NAVIGATION","icon","path","color","flags","selfClosing","FEATURE_FLAG","ENABLED","attributes","name","label","component","FieldComponentType","TEXT_FIELD"],"mappings":";;;AAAA;;;;;;;;;;;;;;;CAeC,GAED,YAAYA,WAAW,eAAc;AACrC,SAASC,UAAU,QAAQ,yBAAwB;AACnD,OAAOC,SAAS,oBAAmB;AACnC,OAAOC,cAAmC,sBAAqB;AAC/D,SAASC,UAAU,EAAEC,UAAU,QAAQ,QAAO;AAC9C,SAASC,SAAS,QAAQ,gCAA4B;AACtD,SAASC,gBAAgB,EAAEC,YAAY,QAAQ,6BAAyB;AAExE,2EAA2E;AAC3E,mDAAmD;AACnD,OAAO,MAAMC,YAA+BT,MAAMU,8BAA8B,CAAA;AAqBhF;;;;;;;;;;;;;;;;;;;;;CAqBC,GACD,MAAMC,iCAAmBP,WACvB,CAACQ,OAAOC;IACN,uEAAuE;IACvE,OAAO;IACP,MAAM,EACJC,cAAc,EACdC,iBAAiB,EACjBC,WAAW,EACXC,WAAW,EACXC,YAAY,EAEb,GAAGN,OADCO,wCACDP;;;;;;;IACJ,yEAAyE;IACzE,MAAMQ,SAASC,MAAMC,OAAO,CAACV,KAAK,CAAC,KAAK,IAAIA,KAAK,CAAC,KAAK,GAAG;QAACA,KAAK,CAAC,KAAK;KAAC;IACvE,MAAM,EAAEW,kBAAkB,EAAE,GAAGlB,WAAWL,MAAMwB,iBAAiB;IACjE,MAAM,EAAEC,KAAK,EAAEC,YAAY,EAAE,GAAGlB,aAAaQ;IAC7C,IAAI,CAACO,sBAAsB,EAACP,+BAAAA,YAAaW,MAAM,GAAE;QAC/C,qEAAqE;QACrE,qEAAqE;QACrE,oEAAoE;QACpE,kEAAkE;QAClE,oCAAoC;QACpC,qBAAO,KAACzB;YAAIW,KAAKA;WAASM;IAC5B;IACA,qBACE,KAAChB;QAASU,KAAKA;OAASM;QAAMS,IAAI;YAAC;gBAAEC,YAAY;YAAW;eAAMT;SAAO;kBACvE,cAAA,KAACb;YACCkB,OAAOA;YACPC,cAAcA;WACTV,cAAc;YAAEc,OAAOd;QAAY,IAAI,CAAC,GACxCD,sBAAsBgB,YACvB,CAAC,IACD;YAAEC,aAAajB;QAAkB,GAChCQ,qBAAqB;YAAEU,OAAO;QAAK,IAAI,CAAC;YAC7C,oEAAoE;YACpE,mEAAmE;YACnE,mEAAmE;YACnE,kEAAkE;YAClE,sDAAsD;YACtDC,WAAW,CAACC;;uBACVjB,eACI,CAAC,gBAAgB,EAAEiB,KAAK,SAAS,UAAEnB,+BAAAA,YAAaW,MAAM,mBAAI,EAAE,CAAC,CAAC,GAC9D,8DACA,2BACA,CAAC,gBAAgB,EAAEQ,KAAK,SAAS,WAAEnB,+BAAAA,YAAaW,MAAM,oBAAI,EAAE,CAAC,CAAC,GAC9D;;;;AAKd;AAEFhB,iBAAiByB,WAAW,GAAG;AAE/B,OAAO,MAAMC,yBACX;IACEC,KAAK7B;IACL8B,UAAUjC;IACV8B,aAAa;IACbI,aACE;IACFC,UAAUzC,MAAM0C,iBAAiB,CAACC,UAAU;IAC5CC,MAAM;QAAEC,MAAM5C,WAAW4C,IAAI;QAAEjB,IAAI;YAAEkB,OAAO;QAAiB;IAAE;IAC/DC,OAAO;QAAEC,aAAahD,MAAMiD,YAAY,CAACC,OAAO;IAAC;IACjDC,YAAY;QACV;YACEC,MAAM;YACNC,OAAO;YACPb,aACE,qEACA;YACFc,WAAWtD,MAAMuD,kBAAkB,CAACC,UAAU;QAChD;QACA;YACEJ,MAAM;YACNC,OAAO;YACPb,aACE,sEACA;YACFc,WAAWtD,MAAMuD,kBAAkB,CAACC,UAAU;QAChD;KAKD;AACH,EAAC;AAEH,SAAS7C,gBAAgB,GAAE"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import * as Aglyn from '@aglyn/aglyn';
18
+ import { type StackProps } from '@mui/material/Stack';
19
+ export declare const SHARE_ID: Aglyn.ComponentId;
20
+ export interface CollectionShareProps extends StackProps {
21
+ /** Heading before the buttons; empty string hides it. */
22
+ heading?: string;
23
+ }
24
+ /**
25
+ * Share buttons for the CURRENT page URL (AGL-582): X, LinkedIn, Facebook,
26
+ * and copy-link. Pure client behavior — the URL is read at click time so
27
+ * SSR and besigner renders stay markup-identical; editing surfaces no-op.
28
+ */
29
+ declare const CollectionShare: import("react").ForwardRefExoticComponent<Omit<CollectionShareProps, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
30
+ export declare const collectionShareSchema: Aglyn.ComponentSchema<CollectionShareProps>;
31
+ export { CollectionShare };
@@ -0,0 +1,154 @@
1
+ import { _ as _extends } from "@swc/helpers/_/_extends";
2
+ import { _ as _object_without_properties_loose } from "@swc/helpers/_/_object_without_properties_loose";
3
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
4
+ /**
5
+ * @license
6
+ * Copyright 2026 Aglyn LLC
7
+ *
8
+ * Licensed under the Apache License, Version 2.0 (the "License");
9
+ * you may not use this file except in compliance with the License.
10
+ * You may obtain a copy of the License at
11
+ *
12
+ * http://www.apache.org/licenses/LICENSE-2.0
13
+ *
14
+ * Unless required by applicable law or agreed to in writing, software
15
+ * distributed under the License is distributed on an "AS IS" BASIS,
16
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ * See the License for the specific language governing permissions and
18
+ * limitations under the License.
19
+ */ import * as Aglyn from "@aglyn/aglyn";
20
+ import { mdiContentCopy, mdiFacebook, mdiLinkedin, mdiShareVariant, mdiTwitter } from "@aglyn/shared-data-mdi";
21
+ import { MdiIcon } from "@aglyn/shared-ui-jsx";
22
+ import IconButton from "@mui/material/IconButton";
23
+ import MuiStack from "@mui/material/Stack";
24
+ import Typography from "@mui/material/Typography";
25
+ import { forwardRef, useContext, useState } from "react";
26
+ import { BUNDLE_ID } from "../constants/bundle-common.js";
27
+ // Persisted component id (AGL-551/582); the compose pipeline references it
28
+ // through the @aglyn/aglyn constant. Never rename.
29
+ export const SHARE_ID = Aglyn.COLLECTION_SHARE_COMPONENT_ID;
30
+ const SHARE_TARGETS = [
31
+ {
32
+ label: 'Share on X',
33
+ path: mdiTwitter.path,
34
+ href: (url)=>`https://twitter.com/intent/tweet?url=${encodeURIComponent(url)}`
35
+ },
36
+ {
37
+ label: 'Share on LinkedIn',
38
+ path: mdiLinkedin.path,
39
+ href: (url)=>'https://www.linkedin.com/sharing/share-offsite/?url=' + encodeURIComponent(url)
40
+ },
41
+ {
42
+ label: 'Share on Facebook',
43
+ path: mdiFacebook.path,
44
+ href: (url)=>`https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(url)}`
45
+ }
46
+ ];
47
+ /**
48
+ * Share buttons for the CURRENT page URL (AGL-582): X, LinkedIn, Facebook,
49
+ * and copy-link. Pure client behavior — the URL is read at click time so
50
+ * SSR and besigner renders stay markup-identical; editing surfaces no-op.
51
+ */ const CollectionShare = /*#__PURE__*/ forwardRef((props, ref)=>{
52
+ const { heading } = props, rest = _object_without_properties_loose(props, [
53
+ "heading"
54
+ ]);
55
+ // Node styles ride the renderer-merged sx; recompose (stack.ts pattern).
56
+ const nodeSx = Array.isArray(props['sx']) ? props['sx'] : [
57
+ props['sx']
58
+ ];
59
+ const { suppressNavigation } = useContext(Aglyn.ScreenLinkContext);
60
+ const [copied, setCopied] = useState(false);
61
+ const title = heading != null ? heading : 'Share';
62
+ const open = (buildHref)=>()=>{
63
+ if (suppressNavigation || typeof window === 'undefined') return;
64
+ window.open(buildHref(window.location.href), '_blank', 'noopener,noreferrer');
65
+ };
66
+ const copy = async ()=>{
67
+ if (suppressNavigation || typeof window === 'undefined') return;
68
+ try {
69
+ await navigator.clipboard.writeText(window.location.href);
70
+ setCopied(true);
71
+ setTimeout(()=>setCopied(false), 2000);
72
+ } catch (unused) {
73
+ // Clipboard unavailable (permissions, http) — silently skip.
74
+ }
75
+ };
76
+ return /*#__PURE__*/ _jsxs(MuiStack, _extends({
77
+ ref: ref,
78
+ direction: "row",
79
+ spacing: 0.5
80
+ }, rest, {
81
+ // MERGE, never replace (AGL-1450) — see collection-entry-meta.tsx.
82
+ sx: [
83
+ {
84
+ alignItems: 'center'
85
+ },
86
+ ...nodeSx
87
+ ],
88
+ children: [
89
+ title ? // `component="p"` because this labels a row of buttons; it is not a
90
+ // section heading (AGL-2486). MUI's `defaultVariantMapping` sends
91
+ // `subtitle2` to `<h6>`, so without this the Share Bar puts a level-6
92
+ // heading into the document outline of every page carrying it. On a
93
+ // blog post the nearest preceding heading is an `h2`, which makes it
94
+ // a skipped level and a `heading-order` failure.
95
+ //
96
+ // Said here rather than as a theme-wide `variantMapping` override: a
97
+ // default would silently change the element under every `subtitle2`
98
+ // in the codebase, including surfaces where an `h6` is correct.
99
+ /*#__PURE__*/ _jsx(Typography, {
100
+ component: "p",
101
+ variant: "subtitle2",
102
+ sx: {
103
+ mr: 1
104
+ },
105
+ children: title
106
+ }) : null,
107
+ SHARE_TARGETS.map((target)=>/*#__PURE__*/ _jsx(IconButton, {
108
+ "aria-label": target.label,
109
+ size: "small",
110
+ onClick: open(target.href),
111
+ children: /*#__PURE__*/ _jsx(MdiIcon, {
112
+ path: target.path
113
+ })
114
+ }, target.label)),
115
+ /*#__PURE__*/ _jsx(IconButton, {
116
+ "aria-label": copied ? 'Link copied' : 'Copy link',
117
+ size: "small",
118
+ color: copied ? 'success' : 'default',
119
+ onClick: copy,
120
+ children: /*#__PURE__*/ _jsx(MdiIcon, {
121
+ path: mdiContentCopy.path
122
+ })
123
+ })
124
+ ]
125
+ }));
126
+ });
127
+ CollectionShare.displayName = 'AglynCollectionShare';
128
+ export const collectionShareSchema = {
129
+ $id: SHARE_ID,
130
+ pluginId: BUNDLE_ID,
131
+ displayName: 'Share Bar',
132
+ description: 'Share buttons for the current page, plus a copy link.',
133
+ category: Aglyn.ComponentCategory.NAVIGATION,
134
+ icon: {
135
+ path: mdiShareVariant.path,
136
+ sx: {
137
+ color: 'secondary.main'
138
+ }
139
+ },
140
+ flags: {
141
+ selfClosing: Aglyn.FEATURE_FLAG.ENABLED
142
+ },
143
+ attributes: [
144
+ {
145
+ name: 'heading',
146
+ label: 'Heading',
147
+ description: 'Text before the buttons (blank hides it).',
148
+ component: Aglyn.FieldComponentType.TEXT_FIELD
149
+ }
150
+ ]
151
+ };
152
+ export { CollectionShare };
153
+
154
+ //# sourceMappingURL=collection-share.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/mui/src/lib/components/collection-share.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 mdiContentCopy,\n mdiFacebook,\n mdiLinkedin,\n mdiShareVariant,\n mdiTwitter,\n} from '@aglyn/shared-data-mdi'\nimport { MdiIcon } from '@aglyn/shared-ui-jsx'\nimport IconButton from '@mui/material/IconButton'\nimport MuiStack, { type StackProps } from '@mui/material/Stack'\nimport Typography from '@mui/material/Typography'\nimport { forwardRef, useContext, useState } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\n\n// Persisted component id (AGL-551/582); the compose pipeline references it\n// through the @aglyn/aglyn constant. Never rename.\nexport const SHARE_ID: Aglyn.ComponentId = Aglyn.COLLECTION_SHARE_COMPONENT_ID\n\nexport interface CollectionShareProps extends StackProps {\n /** Heading before the buttons; empty string hides it. */\n heading?: string\n}\n\nconst SHARE_TARGETS = [\n {\n label: 'Share on X',\n path: mdiTwitter.path,\n href: (url: string) =>\n `https://twitter.com/intent/tweet?url=${encodeURIComponent(url)}`,\n },\n {\n label: 'Share on LinkedIn',\n path: mdiLinkedin.path,\n href: (url: string) =>\n 'https://www.linkedin.com/sharing/share-offsite/?url=' +\n encodeURIComponent(url),\n },\n {\n label: 'Share on Facebook',\n path: mdiFacebook.path,\n href: (url: string) =>\n `https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(url)}`,\n },\n]\n\n/**\n * Share buttons for the CURRENT page URL (AGL-582): X, LinkedIn, Facebook,\n * and copy-link. Pure client behavior — the URL is read at click time so\n * SSR and besigner renders stay markup-identical; editing surfaces no-op.\n */\nconst CollectionShare = forwardRef<HTMLDivElement, CollectionShareProps>(\n (props, ref) => {\n const { heading, ...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 [copied, setCopied] = useState(false)\n const title = heading ?? 'Share'\n const open = (buildHref: (url: string) => string) => () => {\n if (suppressNavigation || typeof window === 'undefined') return\n window.open(\n buildHref(window.location.href),\n '_blank',\n 'noopener,noreferrer',\n )\n }\n const copy = async () => {\n if (suppressNavigation || typeof window === 'undefined') return\n try {\n await navigator.clipboard.writeText(window.location.href)\n setCopied(true)\n setTimeout(() => setCopied(false), 2000)\n } catch {\n // Clipboard unavailable (permissions, http) — silently skip.\n }\n }\n return (\n <MuiStack\n ref={ref}\n direction=\"row\"\n spacing={0.5}\n {...rest}\n // MERGE, never replace (AGL-1450) — see collection-entry-meta.tsx.\n sx={[{ alignItems: 'center' }, ...nodeSx]}\n >\n {title ? (\n // `component=\"p\"` because this labels a row of buttons; it is not a\n // section heading (AGL-2486). MUI's `defaultVariantMapping` sends\n // `subtitle2` to `<h6>`, so without this the Share Bar puts a level-6\n // heading into the document outline of every page carrying it. On a\n // blog post the nearest preceding heading is an `h2`, which makes it\n // a skipped level and a `heading-order` failure.\n //\n // Said here rather than as a theme-wide `variantMapping` override: a\n // default would silently change the element under every `subtitle2`\n // in the codebase, including surfaces where an `h6` is correct.\n <Typography component=\"p\" variant=\"subtitle2\" sx={{ mr: 1 }}>\n {title}\n </Typography>\n ) : null}\n {SHARE_TARGETS.map((target) => (\n <IconButton\n key={target.label}\n aria-label={target.label}\n size=\"small\"\n onClick={open(target.href)}\n >\n <MdiIcon path={target.path} />\n </IconButton>\n ))}\n <IconButton\n aria-label={copied ? 'Link copied' : 'Copy link'}\n size=\"small\"\n color={copied ? 'success' : 'default'}\n onClick={copy}\n >\n <MdiIcon path={mdiContentCopy.path} />\n </IconButton>\n </MuiStack>\n )\n },\n)\nCollectionShare.displayName = 'AglynCollectionShare'\n\nexport const collectionShareSchema: Aglyn.ComponentSchema<CollectionShareProps> =\n {\n $id: SHARE_ID,\n pluginId: BUNDLE_ID,\n displayName: 'Share Bar',\n description: 'Share buttons for the current page, plus a copy link.',\n category: Aglyn.ComponentCategory.NAVIGATION,\n icon: { path: mdiShareVariant.path, sx: { color: 'secondary.main' } },\n flags: { selfClosing: Aglyn.FEATURE_FLAG.ENABLED },\n attributes: [\n {\n name: 'heading',\n label: 'Heading',\n description: 'Text before the buttons (blank hides it).',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n },\n ],\n }\n\nexport { CollectionShare }\n"],"names":["Aglyn","mdiContentCopy","mdiFacebook","mdiLinkedin","mdiShareVariant","mdiTwitter","MdiIcon","IconButton","MuiStack","Typography","forwardRef","useContext","useState","BUNDLE_ID","SHARE_ID","COLLECTION_SHARE_COMPONENT_ID","SHARE_TARGETS","label","path","href","url","encodeURIComponent","CollectionShare","props","ref","heading","rest","nodeSx","Array","isArray","suppressNavigation","ScreenLinkContext","copied","setCopied","title","open","buildHref","window","location","copy","navigator","clipboard","writeText","setTimeout","direction","spacing","sx","alignItems","component","variant","mr","map","target","aria-label","size","onClick","color","displayName","collectionShareSchema","$id","pluginId","description","category","ComponentCategory","NAVIGATION","icon","flags","selfClosing","FEATURE_FLAG","ENABLED","attributes","name","FieldComponentType","TEXT_FIELD"],"mappings":"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"}