@aglyn/aglyn 1.0.0 → 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.
- package/package.json +11 -11
- package/src/lib/app-utils/compose-reusable-components.d.ts +22 -0
- package/src/lib/app-utils/compose-reusable-components.js +94 -32
- package/src/lib/app-utils/compose-reusable-components.js.map +1 -1
- package/src/lib/app-utils/contacts.d.ts +11 -0
- package/src/lib/app-utils/contacts.js +10 -0
- package/src/lib/app-utils/contacts.js.map +1 -1
- package/src/lib/app-utils/crm.d.ts +50 -19
- package/src/lib/app-utils/crm.js +37 -22
- package/src/lib/app-utils/crm.js.map +1 -1
- package/src/lib/app-utils/default-site.d.ts +10 -3
- package/src/lib/app-utils/default-site.js +82 -6
- package/src/lib/app-utils/default-site.js.map +1 -1
- package/src/lib/app-utils/docs-help-sections.generated.js +11 -1
- package/src/lib/app-utils/docs-help-sections.generated.js.map +1 -1
- package/src/lib/app-utils/docs-help.generated.d.ts +5 -5
- package/src/lib/app-utils/docs-help.generated.js +23 -0
- package/src/lib/app-utils/docs-help.generated.js.map +1 -1
- package/src/lib/app-utils/docs-index.generated.js +43 -15
- package/src/lib/app-utils/docs-index.generated.js.map +1 -1
- package/src/lib/app-utils/host-tokens.d.ts +7 -0
- package/src/lib/app-utils/host-tokens.js +27 -4
- package/src/lib/app-utils/host-tokens.js.map +1 -1
- package/src/lib/app-utils/node-definition-sanitizer.js +5 -1
- package/src/lib/app-utils/node-definition-sanitizer.js.map +1 -1
- package/src/lib/app-utils/server.d.ts +1 -0
- package/src/lib/app-utils/server.js +1 -0
- package/src/lib/app-utils/server.js.map +1 -1
- package/src/lib/app-utils/site-brand-files.d.ts +87 -0
- package/src/lib/app-utils/site-brand-files.js +157 -0
- package/src/lib/app-utils/site-brand-files.js.map +1 -0
- package/src/lib/app-utils/site-starter-nodes.js +1 -0
- package/src/lib/app-utils/site-starter-nodes.js.map +1 -1
- package/src/lib/app-utils/site-starter-pick.d.ts +2 -2
- package/src/lib/app-utils/site-starter-pick.js +2 -2
- package/src/lib/app-utils/site-starter-pick.js.map +1 -1
- package/src/lib/plugin-manager/feature-plugins.d.ts +36 -2
- package/src/lib/plugin-manager/feature-plugins.js.map +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aglyn/aglyn",
|
|
3
|
-
"version": "1.
|
|
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.
|
|
41
|
-
"@aglyn/shared-data-mdi": "1.
|
|
42
|
-
"@aglyn/shared-data-types": "1.
|
|
43
|
-
"@aglyn/shared-util-email": "1.
|
|
44
|
-
"@aglyn/shared-util-first-touch": "1.
|
|
45
|
-
"@aglyn/shared-util-http": "1.
|
|
46
|
-
"@aglyn/shared-util-logger": "1.
|
|
47
|
-
"@aglyn/shared-util-timestamp": "1.
|
|
48
|
-
"@aglyn/shared-util-tools": "1.
|
|
49
|
-
"@aglyn/shared-util-vendor": "1.
|
|
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
|
-
|
|
842
|
-
|
|
843
|
-
|
|
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
|
-
|
|
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 (
|
|
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 =
|
|
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
|