@aglyn/aglyn 1.0.0-beta.296 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/package.json +11 -11
  2. package/src/lib/app-utils/compose-reusable-components.d.ts +22 -0
  3. package/src/lib/app-utils/compose-reusable-components.js +94 -32
  4. package/src/lib/app-utils/compose-reusable-components.js.map +1 -1
  5. package/src/lib/app-utils/contacts.d.ts +11 -0
  6. package/src/lib/app-utils/contacts.js +10 -0
  7. package/src/lib/app-utils/contacts.js.map +1 -1
  8. package/src/lib/app-utils/crm.d.ts +50 -19
  9. package/src/lib/app-utils/crm.js +37 -22
  10. package/src/lib/app-utils/crm.js.map +1 -1
  11. package/src/lib/app-utils/default-site.d.ts +10 -3
  12. package/src/lib/app-utils/default-site.js +82 -6
  13. package/src/lib/app-utils/default-site.js.map +1 -1
  14. package/src/lib/app-utils/docs-help-sections.generated.js +11 -1
  15. package/src/lib/app-utils/docs-help-sections.generated.js.map +1 -1
  16. package/src/lib/app-utils/docs-help.generated.d.ts +5 -5
  17. package/src/lib/app-utils/docs-help.generated.js +23 -0
  18. package/src/lib/app-utils/docs-help.generated.js.map +1 -1
  19. package/src/lib/app-utils/docs-index.generated.js +45 -17
  20. package/src/lib/app-utils/docs-index.generated.js.map +1 -1
  21. package/src/lib/app-utils/host-tokens.d.ts +7 -0
  22. package/src/lib/app-utils/host-tokens.js +27 -4
  23. package/src/lib/app-utils/host-tokens.js.map +1 -1
  24. package/src/lib/app-utils/node-definition-sanitizer.js +5 -1
  25. package/src/lib/app-utils/node-definition-sanitizer.js.map +1 -1
  26. package/src/lib/app-utils/server.d.ts +1 -0
  27. package/src/lib/app-utils/server.js +1 -0
  28. package/src/lib/app-utils/server.js.map +1 -1
  29. package/src/lib/app-utils/site-brand-files.d.ts +87 -0
  30. package/src/lib/app-utils/site-brand-files.js +157 -0
  31. package/src/lib/app-utils/site-brand-files.js.map +1 -0
  32. package/src/lib/app-utils/site-starter-nodes.js +1 -0
  33. package/src/lib/app-utils/site-starter-nodes.js.map +1 -1
  34. package/src/lib/app-utils/site-starter-pick.d.ts +2 -2
  35. package/src/lib/app-utils/site-starter-pick.js +2 -2
  36. package/src/lib/app-utils/site-starter-pick.js.map +1 -1
  37. package/src/lib/app-utils/version-draft.d.ts +30 -0
  38. package/src/lib/app-utils/version-draft.js +24 -0
  39. package/src/lib/app-utils/version-draft.js.map +1 -1
  40. package/src/lib/plugin-manager/feature-plugins.d.ts +36 -2
  41. package/src/lib/plugin-manager/feature-plugins.js.map +1 -1
  42. package/src/lib/plugin-manager/plugin-jobs.d.ts +14 -0
  43. package/src/lib/plugin-manager/plugin-jobs.js +30 -7
  44. package/src/lib/plugin-manager/plugin-jobs.js.map +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aglyn/aglyn",
3
- "version": "1.0.0-beta.296",
3
+ "version": "1.1.0",
4
4
  "license": "Apache-2.0",
5
5
  "homepage": "https://aglyn.com",
6
6
  "repository": {
@@ -37,16 +37,16 @@
37
37
  "./package.json": "./package.json"
38
38
  },
39
39
  "dependencies": {
40
- "@aglyn/shared-data-enums": "1.0.0-beta.296",
41
- "@aglyn/shared-data-mdi": "1.0.0-beta.296",
42
- "@aglyn/shared-data-types": "1.0.0-beta.296",
43
- "@aglyn/shared-util-email": "1.0.0-beta.296",
44
- "@aglyn/shared-util-first-touch": "1.0.0-beta.296",
45
- "@aglyn/shared-util-http": "1.0.0-beta.296",
46
- "@aglyn/shared-util-logger": "1.0.0-beta.296",
47
- "@aglyn/shared-util-timestamp": "1.0.0-beta.296",
48
- "@aglyn/shared-util-tools": "1.0.0-beta.296",
49
- "@aglyn/shared-util-vendor": "1.0.0-beta.296",
40
+ "@aglyn/shared-data-enums": "1.1.0",
41
+ "@aglyn/shared-data-mdi": "1.1.0",
42
+ "@aglyn/shared-data-types": "1.1.0",
43
+ "@aglyn/shared-util-email": "1.1.0",
44
+ "@aglyn/shared-util-first-touch": "1.1.0",
45
+ "@aglyn/shared-util-http": "1.1.0",
46
+ "@aglyn/shared-util-logger": "1.1.0",
47
+ "@aglyn/shared-util-timestamp": "1.1.0",
48
+ "@aglyn/shared-util-tools": "1.1.0",
49
+ "@aglyn/shared-util-vendor": "1.1.0",
50
50
  "@data-driven-forms/react-form-renderer": "^4.2.0",
51
51
  "@msgpack/msgpack": "^3.1.3",
52
52
  "@types/unist": "^3.0.3",
@@ -15,6 +15,7 @@
15
15
  * limitations under the License.
16
16
  */
17
17
  import type { AglynNodeSchema, NodeId, ReusableComponentIcon, ReusableComponentProp } from '../foundation';
18
+ import { type HostTokenSource } from './host-tokens';
18
19
  export * from './reusable-component-keys';
19
20
  export * from './reusable-prop-values';
20
21
  /**
@@ -413,6 +414,17 @@ formatted?: Readonly<Record<string, unknown>> | null): NormalizedNodes<N>;
413
414
  * what keeps the component editor showing the parts a page will hide.
414
415
  */
415
416
  export declare function isNodeHiddenByDirective(props: unknown): boolean;
417
+ /**
418
+ * Whether the site's own values hide this node (AGL-4119): `hideIf` or
419
+ * `hideUnless` bound to a `{{host.*}}` token, read against `host`. A header
420
+ * shows the logo when the site has one and the name when it does not, and
421
+ * each carries the directive that says so.
422
+ *
423
+ * Only a directive naming a host token is read. A directive with a literal
424
+ * value on an ordinary page's own node stays as inert as it has always been
425
+ * ({@link isNodeHiddenByDirective} says why it is the graft that reads those).
426
+ */
427
+ export declare function isNodeHiddenByHost(props: unknown, host: HostTokenSource | null | undefined): boolean;
416
428
  /**
417
429
  * Drops every node under `rootId` whose props ask to be hidden, along with
418
430
  * its whole subtree and its entry in its parent's child list, and strips
@@ -433,6 +445,16 @@ export declare function isNodeHiddenByDirective(props: unknown): boolean;
433
445
  * overwhelmingly common case costs one scan and allocates nothing.
434
446
  */
435
447
  export declare function pruneHiddenNodes<N extends AglynNodeSchema = AglynNodeSchema>(nodes: NormalizedNodes<N>, rootId: NodeId): NormalizedNodes<N>;
448
+ /**
449
+ * {@link pruneHiddenNodes} for the directives bound to a `{{host.*}}` token
450
+ * (AGL-4119), once the site is known: over the composed tree, ahead of the
451
+ * host tokens themselves, by every surface that fills those in. What a page
452
+ * hides for itself has been pruned by then.
453
+ *
454
+ * Returns the input unchanged when no node names one, which is every page of
455
+ * a site whose layout does not.
456
+ */
457
+ export declare function pruneHostHiddenNodes<N extends AglynNodeSchema = AglynNodeSchema>(nodes: NormalizedNodes<N>, host: HostTokenSource | null | undefined, rootId?: NodeId): NormalizedNodes<N>;
436
458
  /**
437
459
  * Expands reusable-component instance nodes (componentId
438
460
  * {@link REUSABLE_INSTANCE_COMPONENT_ID}, `props.refId` → definition id) by
@@ -17,10 +17,12 @@ import { _ as _object_without_properties_loose } from "@swc/helpers/_/_object_wi
17
17
  * limitations under the License.
18
18
  */ // By path: the naming rule alone, without the icon catalog's loader beside it.
19
19
  import { iconPathPropName } from "@aglyn/shared-data-mdi/utils/icon-path-prop-name";
20
+ import { CANVAS_ROOT_ELEMENT_ID } from "../foundation/constants/canvas.js";
20
21
  import { reusablePropValueClass } from "../foundation/definitions/property-kinds.js";
21
22
  import { COMPONENT_NODE_ID_PREFIX, COMPONENT_PROP_TOKEN_PREFIX, INSTANCE_CARRIED_NODE_FIELDS, INSTANCE_CARRIED_PROPS, NODE_HIDE_IF_PROP, NODE_HIDE_UNLESS_PROP, REUSABLE_INSTANCE_COMPONENT_ID, REUSABLE_INSTANCE_PROP_HTML_KEY, REUSABLE_INSTANCE_PROP_VALUES_KEY, STYLE_OVERRIDES_ROOT_KEY } from "./reusable-component-keys.js";
22
23
  import { REPEAT_DIRECTIVE_PROPS, REPEAT_SELF_PROP, repeatKey, withoutRepeatDirective } from "./expand-repeatables.js";
23
24
  import { FORM_COMPONENT_ID, FORM_ID_PROP } from "./forms.js";
25
+ import { hostTokensIn, resolveHostTokens } from "./host-tokens.js";
24
26
  /** The Form's after-submit reveal target: a node id (`form.tsx`). */ const FORM_REVEAL_NODE_PROP = 'revealNodeId';
25
27
  import { mergeNodeSx } from "./merge-node-sx.js";
26
28
  import { hasUrlScheme, isSafeNodeUrl, NODE_URL_PROPS } from "./node-url-policy.js";
@@ -823,48 +825,62 @@ function hasVisibilityDirective(props) {
823
825
  const bag = props;
824
826
  return NODE_HIDE_IF_PROP in bag || NODE_HIDE_UNLESS_PROP in bag;
825
827
  }
828
+ /** A directive bound to the site's own values, like `{{host.logo}}`. */ function namesHostToken(value) {
829
+ return typeof value === 'string' && hostTokensIn(value).length > 0;
830
+ }
831
+ /**
832
+ * Whether the site's own values hide this node (AGL-4119): `hideIf` or
833
+ * `hideUnless` bound to a `{{host.*}}` token, read against `host`. A header
834
+ * shows the logo when the site has one and the name when it does not, and
835
+ * each carries the directive that says so.
836
+ *
837
+ * Only a directive naming a host token is read. A directive with a literal
838
+ * value on an ordinary page's own node stays as inert as it has always been
839
+ * ({@link isNodeHiddenByDirective} says why it is the graft that reads those).
840
+ */ export function isNodeHiddenByHost(props, host) {
841
+ if (!props || typeof props !== 'object' || Array.isArray(props)) return false;
842
+ const bag = props;
843
+ const hideIf = bag[NODE_HIDE_IF_PROP];
844
+ const hideUnless = bag[NODE_HIDE_UNLESS_PROP];
845
+ if (namesHostToken(hideIf) && readYesNoValue(resolveHostTokens(String(hideIf), host)) === true) {
846
+ return true;
847
+ }
848
+ return namesHostToken(hideUnless) && readYesNoValue(resolveHostTokens(String(hideUnless), host)) === false;
849
+ }
826
850
  /**
827
851
  * The node minus its visibility directives — they are compose-time
828
852
  * instructions, and `Leaf` spreads whatever survives onto the component,
829
853
  * so leaving them would put `hideif="…"` on the DOM of every node that
830
854
  * declared one and stayed.
855
+ *
856
+ * One bound to a `{{host.*}}` token stays: the site's values fill in later,
857
+ * and {@link pruneHostHiddenNodes} reads it then.
831
858
  */ function withoutVisibilityDirectives(node) {
832
859
  if (!hasVisibilityDirective(node == null ? void 0 : node.props)) return node;
833
860
  const props = _extends({}, node.props);
834
- delete props[NODE_HIDE_IF_PROP];
835
- delete props[NODE_HIDE_UNLESS_PROP];
861
+ if (!namesHostToken(props[NODE_HIDE_IF_PROP])) delete props[NODE_HIDE_IF_PROP];
862
+ if (!namesHostToken(props[NODE_HIDE_UNLESS_PROP])) delete props[NODE_HIDE_UNLESS_PROP];
836
863
  return _extends({}, node, {
837
864
  props: props
838
865
  });
839
866
  }
840
- /**
841
- * Drops every node under `rootId` whose props ask to be hidden, along with
842
- * its whole subtree and its entry in its parent's child list, and strips
843
- * the directives off everything that survives (AGL-1314).
844
- *
845
- * Structural rather than a `display: none`: an instance can already hide a
846
- * leaf with a per-leaf style override (AGL-1332), but that still ships the
847
- * markup, still fetches the image, still leaves the grid column, and still
848
- * leaves the control in the tab order. "This page has no mockup" is a
849
- * statement about the tree, so it is made in the tree.
850
- *
851
- * `rootId` itself is never dropped. The graft below wires the instance
852
- * node's single child to the definition root by id, so a self-hiding root
853
- * would leave a dangling reference; a component that should not appear at
854
- * all is a decision for the page that placed it, not for the definition.
855
- *
856
- * Returns the input unchanged when no node carries a directive, so the
857
- * overwhelmingly common case costs one scan and allocates nothing.
858
- */ export function pruneHiddenNodes(nodes, rootId) {
859
- if (!nodes) return nodes;
860
- let sawDirective = false;
861
- for (const node of Object.values(nodes)){
862
- if (hasVisibilityDirective(node == null ? void 0 : node.props)) {
863
- sawDirective = true;
864
- break;
865
- }
867
+ /** The node minus the directives bound to a `{{host.*}}` token, now they have been read. */ function withoutHostDirectives(node) {
868
+ const bag = node == null ? void 0 : node.props;
869
+ if (!bag || !(namesHostToken(bag[NODE_HIDE_IF_PROP]) || namesHostToken(bag[NODE_HIDE_UNLESS_PROP]))) {
870
+ return node;
866
871
  }
867
- if (!sawDirective) return nodes;
872
+ const props = _extends({}, bag);
873
+ if (namesHostToken(props[NODE_HIDE_IF_PROP])) delete props[NODE_HIDE_IF_PROP];
874
+ if (namesHostToken(props[NODE_HIDE_UNLESS_PROP])) delete props[NODE_HIDE_UNLESS_PROP];
875
+ return _extends({}, node, {
876
+ props: props
877
+ });
878
+ }
879
+ /**
880
+ * Drops every node under `rootId` that `isHidden` answers for, along with its
881
+ * subtree and its entry in its parent's child list, and hands every survivor
882
+ * to `keep`. The walk both prunes below share.
883
+ */ function pruneNodes(nodes, rootId, isHidden, keep) {
868
884
  const hidden = new Set();
869
885
  const seen = new Set();
870
886
  const walk = (id)=>{
@@ -875,9 +891,8 @@ function hasVisibilityDirective(props) {
875
891
  seen.add(id);
876
892
  const children = Array.isArray(node.nodes) ? node.nodes : [];
877
893
  for (const childId of children){
878
- var _nodes_childId;
879
894
  if (typeof childId !== 'string' || !nodes[childId]) continue;
880
- if (isNodeHiddenByDirective((_nodes_childId = nodes[childId]) == null ? void 0 : _nodes_childId.props)) {
895
+ if (isHidden(nodes[childId])) {
881
896
  hidden.add(childId);
882
897
  for (const descendant of collectDescendantIds(nodes, childId)){
883
898
  hidden.add(descendant);
@@ -891,7 +906,7 @@ function hasVisibilityDirective(props) {
891
906
  const next = {};
892
907
  for (const [id, node] of Object.entries(nodes)){
893
908
  if (hidden.has(id)) continue;
894
- const kept = withoutVisibilityDirectives(node);
909
+ const kept = keep(node);
895
910
  const children = Array.isArray(kept == null ? void 0 : kept.nodes) ? kept.nodes : null;
896
911
  const survivors = children && children.some((childId)=>hidden.has(childId)) ? children.filter((childId)=>!hidden.has(childId)) : null;
897
912
  next[id] = survivors ? _extends({}, kept, {
@@ -900,6 +915,53 @@ function hasVisibilityDirective(props) {
900
915
  }
901
916
  return next;
902
917
  }
918
+ /**
919
+ * Drops every node under `rootId` whose props ask to be hidden, along with
920
+ * its whole subtree and its entry in its parent's child list, and strips
921
+ * the directives off everything that survives (AGL-1314).
922
+ *
923
+ * Structural rather than a `display: none`: an instance can already hide a
924
+ * leaf with a per-leaf style override (AGL-1332), but that still ships the
925
+ * markup, still fetches the image, still leaves the grid column, and still
926
+ * leaves the control in the tab order. "This page has no mockup" is a
927
+ * statement about the tree, so it is made in the tree.
928
+ *
929
+ * `rootId` itself is never dropped. The graft below wires the instance
930
+ * node's single child to the definition root by id, so a self-hiding root
931
+ * would leave a dangling reference; a component that should not appear at
932
+ * all is a decision for the page that placed it, not for the definition.
933
+ *
934
+ * Returns the input unchanged when no node carries a directive, so the
935
+ * overwhelmingly common case costs one scan and allocates nothing.
936
+ */ export function pruneHiddenNodes(nodes, rootId) {
937
+ if (!nodes) return nodes;
938
+ let sawDirective = false;
939
+ for (const node of Object.values(nodes)){
940
+ if (hasVisibilityDirective(node == null ? void 0 : node.props)) {
941
+ sawDirective = true;
942
+ break;
943
+ }
944
+ }
945
+ if (!sawDirective) return nodes;
946
+ return pruneNodes(nodes, rootId, (node)=>isNodeHiddenByDirective(node == null ? void 0 : node.props), withoutVisibilityDirectives);
947
+ }
948
+ /**
949
+ * {@link pruneHiddenNodes} for the directives bound to a `{{host.*}}` token
950
+ * (AGL-4119), once the site is known: over the composed tree, ahead of the
951
+ * host tokens themselves, by every surface that fills those in. What a page
952
+ * hides for itself has been pruned by then.
953
+ *
954
+ * Returns the input unchanged when no node names one, which is every page of
955
+ * a site whose layout does not.
956
+ */ export function pruneHostHiddenNodes(nodes, host, rootId = CANVAS_ROOT_ELEMENT_ID) {
957
+ if (!nodes) return nodes;
958
+ const named = Object.values(nodes).some((node)=>{
959
+ const bag = node == null ? void 0 : node.props;
960
+ return Boolean(bag && (namesHostToken(bag[NODE_HIDE_IF_PROP]) || namesHostToken(bag[NODE_HIDE_UNLESS_PROP])));
961
+ });
962
+ if (!named) return nodes;
963
+ return pruneNodes(nodes, rootId, (node)=>isNodeHiddenByHost(node == null ? void 0 : node.props, host), withoutHostDirectives);
964
+ }
903
965
  /**
904
966
  * Expands reusable-component instance nodes (componentId
905
967
  * {@link REUSABLE_INSTANCE_COMPONENT_ID}, `props.refId` → definition id) by