@nascentdigital/funnel-editor 4.5.6 → 4.6.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 (136) hide show
  1. package/dist/collection/hooks/CollectionController.d.ts +1 -1
  2. package/dist/core/components/ColorModeToggle.js +6 -4
  3. package/dist/core/components/Header.js +3 -2
  4. package/dist/core/components/UserEditor.d.ts +2 -2
  5. package/dist/core/components/feedback/Badge.d.ts +2 -1
  6. package/dist/core/components/feedback/Badge.js +4 -3
  7. package/dist/core/components/fields/DynamicPagesEditor.js +7 -6
  8. package/dist/core/components/fields/EmptyFieldCard.js +4 -4
  9. package/dist/core/components/fields/FieldCardLayout.js +5 -5
  10. package/dist/core/components/fields/FieldHeader.js +3 -2
  11. package/dist/core/components/fields/FieldsPanel.js +4 -4
  12. package/dist/core/components/fields/FormEditor.js +5 -4
  13. package/dist/core/components/fields/asset/AssetEditor.d.ts +3 -2
  14. package/dist/core/components/fields/asset/AssetEditor.js +1 -1
  15. package/dist/core/components/fields/asset/AssetUploader.d.ts +3 -2
  16. package/dist/core/components/fields/asset/AssetUploader.js +1 -1
  17. package/dist/core/components/fields/collection/CollectionCard.js +1 -11
  18. package/dist/core/components/fields/collection/CollectionPicker.js +3 -2
  19. package/dist/core/components/fields/collection/previews/index.d.ts +0 -1
  20. package/dist/core/components/fields/collection/previews/index.js +0 -1
  21. package/dist/core/components/fields/embed/EmbeddedVideoEditor.d.ts +2 -2
  22. package/dist/core/components/fields/factories/AssetFactory.d.ts +1 -1
  23. package/dist/core/components/fields/factories/CollectionFactory.d.ts +1 -1
  24. package/dist/core/components/fields/factories/EmbeddedVideoFactory.d.ts +2 -2
  25. package/dist/core/components/fields/factories/FieldValueFactory.d.ts +1 -1
  26. package/dist/core/components/fields/factories/FieldValueFactory.js +1 -1
  27. package/dist/core/components/fields/factories/LinkFactory.d.ts +2 -2
  28. package/dist/core/components/fields/factories/TextFactory.d.ts +2 -2
  29. package/dist/core/components/fields/form/FormFieldEditor.d.ts +3 -2
  30. package/dist/core/components/fields/index.d.ts +1 -0
  31. package/dist/core/components/fields/index.js +1 -0
  32. package/dist/core/components/fields/link/LinkEditor.d.ts +2 -2
  33. package/dist/core/components/fields/link/LinkEditor.js +4 -0
  34. package/dist/core/components/fields/list/CreateFieldButton.d.ts +1 -1
  35. package/dist/core/components/fields/list/CreateFieldButton.js +4 -5
  36. package/dist/core/components/fields/list/CreateFieldCard.js +4 -4
  37. package/dist/core/components/fields/page/PagePicker.js +4 -2
  38. package/dist/core/components/fields/richtext/FloatingToolbarPlugin.js +3 -2
  39. package/dist/core/components/fields/richtext/LinkEditor.js +17 -4
  40. package/dist/core/components/fields/richtext/LinkPopup.js +11 -7
  41. package/dist/core/components/interaction/AvatarButton.d.ts +2 -1
  42. package/dist/core/components/interaction/AvatarButton.js +3 -2
  43. package/dist/core/components/interaction/Button.d.ts +2 -0
  44. package/dist/core/components/interaction/Button.js +3 -2
  45. package/dist/core/components/interaction/Combobox.js +2 -2
  46. package/dist/core/components/interaction/IconButton.d.ts +2 -0
  47. package/dist/core/components/interaction/IconButton.js +3 -2
  48. package/dist/core/components/interaction/IconLink.d.ts +1 -1
  49. package/dist/core/components/interaction/MiniEditor.d.ts +3 -2
  50. package/dist/core/components/interaction/MiniEditor.js +7 -5
  51. package/dist/core/components/interaction/Popup.d.ts +20 -15
  52. package/dist/core/components/interaction/Popup.js +63 -66
  53. package/dist/core/components/interaction/QuickInput.js +2 -0
  54. package/dist/core/components/interaction/QuickPicker.d.ts +1 -0
  55. package/dist/core/components/interaction/QuickPicker.js +5 -5
  56. package/dist/core/components/interaction/Tabs.d.ts +5 -1
  57. package/dist/core/components/interaction/Tabs.js +18 -8
  58. package/dist/core/components/interaction/menu/useMenuController.d.ts +2 -2
  59. package/dist/core/components/interaction/table/TableItem.d.ts +2 -1
  60. package/dist/core/components/interaction/table/TableItem.js +5 -3
  61. package/dist/core/components/layout/InfoPanel.js +4 -2
  62. package/dist/core/components/visuals/Icon.d.ts +1 -1
  63. package/dist/core/components/visuals/Icon.js +6 -0
  64. package/dist/core/components/visuals/index.d.ts +0 -1
  65. package/dist/core/components/visuals/index.js +0 -1
  66. package/dist/core/domain/Block.d.ts +4 -0
  67. package/dist/core/domain/Block.js +7 -0
  68. package/dist/core/domain/BlockConfiguration.d.ts +11 -3
  69. package/dist/core/domain/BlockConfiguration.js +77 -14
  70. package/dist/core/domain/CollectionBrowser.d.ts +2 -2
  71. package/dist/core/domain/CollectionFieldProxy.d.ts +7 -2
  72. package/dist/core/domain/CollectionFieldProxy.js +55 -66
  73. package/dist/core/domain/SectionBlock.d.ts +5 -0
  74. package/dist/core/domain/SectionBlock.js +15 -0
  75. package/dist/core/hooks/useBlockConfiguration.d.ts +7 -1
  76. package/dist/core/hooks/useBlockConfiguration.js +8 -1
  77. package/dist/core/hooks/usePage.d.ts +2 -2
  78. package/dist/core/hooks/usePage.js +5 -4
  79. package/dist/core/repository/CollectionRepository.js +1 -1
  80. package/dist/core/repository/CollectionSerializer.d.ts +3 -2
  81. package/dist/core/repository/CollectionSerializer.js +12 -7
  82. package/dist/core/repository/PageRepository.js +2 -2
  83. package/dist/core/repository/PageSerializer.d.ts +5 -3
  84. package/dist/core/repository/PageSerializer.js +10 -11
  85. package/dist/explore/components/CreateCollectionDialog.d.ts +2 -3
  86. package/dist/explore/components/CreateCollectionDialog.js +1 -1
  87. package/dist/explore/components/CreatePageDialog.d.ts +3 -3
  88. package/dist/explore/components/CreatePageDialog.js +2 -2
  89. package/dist/explore/screens/CollectionExplorer.js +4 -4
  90. package/dist/explore/screens/PageExplorer.js +4 -4
  91. package/dist/page/components/BlockEditor.js +10 -2
  92. package/dist/page/components/config/BlockConfigButton.d.ts +8 -0
  93. package/dist/page/components/config/BlockConfigButton.js +320 -0
  94. package/dist/page/components/config/BlockConfigurationProvider.d.ts +8 -0
  95. package/dist/page/components/config/BlockConfigurationProvider.js +17 -0
  96. package/dist/page/components/config/LegacyBlockPreview.d.ts +8 -0
  97. package/dist/page/components/config/{BlockPreview.js → LegacyBlockPreview.js} +30 -40
  98. package/dist/page/components/config/index.d.ts +3 -1
  99. package/dist/page/components/config/index.js +3 -1
  100. package/dist/page/components/index.d.ts +1 -1
  101. package/dist/page/components/index.js +1 -1
  102. package/dist/page/components/nav/NavSection.js +4 -3
  103. package/dist/page/components/panels/BlockConfigPanel.d.ts +1 -0
  104. package/dist/page/components/panels/BlockConfigPanel.js +25 -0
  105. package/dist/page/components/{PageStatus.d.ts → panels/PageStatus.d.ts} +3 -3
  106. package/dist/page/components/{PageStatus.js → panels/PageStatus.js} +10 -14
  107. package/dist/page/components/panels/index.d.ts +2 -0
  108. package/dist/page/components/{status → panels}/index.js +2 -1
  109. package/dist/page/hooks/PageController.d.ts +2 -2
  110. package/dist/page/screens/PageEditor.js +8 -1
  111. package/dist/styles/index.css +174 -56
  112. package/dist/styles/tailwind.js +7 -3
  113. package/dist/users/screens/UserExplorer.js +7 -6
  114. package/package.json +3 -2
  115. package/dist/core/components/fields/collection/previews/ClientPreview.d.ts +0 -10
  116. package/dist/core/components/fields/collection/previews/ClientPreview.js +0 -29
  117. package/dist/core/components/visuals/SkeletonLayout.d.ts +0 -9
  118. package/dist/core/components/visuals/SkeletonLayout.js +0 -429
  119. package/dist/page/components/config/BlockConfig.d.ts +0 -8
  120. package/dist/page/components/config/BlockConfig.js +0 -28
  121. package/dist/page/components/config/BlockConfigEditor.d.ts +0 -9
  122. package/dist/page/components/config/BlockConfigEditor.js +0 -114
  123. package/dist/page/components/config/BlockPreview.d.ts +0 -10
  124. package/dist/page/components/config/BlockView.d.ts +0 -4
  125. package/dist/page/components/config/BlockView.js +0 -9
  126. package/dist/page/components/config/LegacyBlockConfigEditor.d.ts +0 -9
  127. package/dist/page/components/config/LegacyBlockConfigEditor.js +0 -27
  128. package/dist/page/components/config/ListPanelEditor.d.ts +0 -8
  129. package/dist/page/components/config/ListPanelEditor.js +0 -89
  130. package/dist/page/components/config/MessagePanelEditor.d.ts +0 -8
  131. package/dist/page/components/config/MessagePanelEditor.js +0 -17
  132. package/dist/page/components/config/VisualPanelEditor.d.ts +0 -8
  133. package/dist/page/components/config/VisualPanelEditor.js +0 -76
  134. package/dist/page/components/status/index.d.ts +0 -1
  135. /package/dist/page/components/{status → panels}/AutoSave.d.ts +0 -0
  136. /package/dist/page/components/{status → panels}/AutoSave.js +0 -0
@@ -14,22 +14,24 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
14
14
  return (mod && mod.__esModule) ? mod : { "default": mod };
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.animations = void 0;
18
17
  exports.Popup = Popup;
19
- exports.getPopupPlacement = getPopupPlacement;
20
18
  const jsx_runtime_1 = require("react/jsx-runtime");
21
19
  const funnel_core_1 = require("@nascentdigital/funnel-core");
20
+ const funnel_ui_1 = require("@nascentdigital/funnel-ui");
22
21
  const client_1 = require("@nascentdigital/funnel-ui/client");
23
22
  const classnames_1 = __importDefault(require("classnames"));
24
23
  const framer_motion_1 = require("framer-motion");
25
24
  const react_1 = require("react");
26
25
  const react_dom_1 = require("react-dom");
26
+ const Animate_1 = require("./Animate");
27
27
  // component
28
28
  function Popup(_a) {
29
- var _b;
30
- var { className, style = {}, anchor, placement, anchorOffset, viewportPadding, animation = 'in-out', backdrop = 'none', disabled = false, disableDismiss = false, disableOverlay = false, open = false, onOpened: onOpenedRaw = funnel_core_1.Fn.NoOp, onClose = funnel_core_1.Fn.NoOp, onClosed: onClosedRaw = funnel_core_1.Fn.NoOp, onKeyDown: onKeyDownRaw, children } = _a, props = __rest(_a, ["className", "style", "anchor", "placement", "anchorOffset", "viewportPadding", "animation", "backdrop", "disabled", "disableDismiss", "disableOverlay", "open", "onOpened", "onClose", "onClosed", "onKeyDown", "children"]);
29
+ var { className, style = {}, anchor, anchorOffset, placement = 'bottom', viewportPadding, animation = 'in-out', backdrop = 'none', disabled = false, disableDismiss = false, disableOverlay = false, open = false, onOpened: onOpenedRaw = funnel_core_1.Fn.NoOp, onClose = funnel_core_1.Fn.NoOp, onClosed: onClosedRaw = funnel_core_1.Fn.NoOp, onKeyDown: onKeyDownRaw, children } = _a, props = __rest(_a, ["className", "style", "anchor", "anchorOffset", "placement", "viewportPadding", "animation", "backdrop", "disabled", "disableDismiss", "disableOverlay", "open", "onOpened", "onClose", "onClosed", "onKeyDown", "children"]);
31
30
  // bind context
32
31
  const id = (0, react_1.useId)();
32
+ const anchorId = typeof anchor === 'string'
33
+ ? anchor
34
+ : id;
33
35
  const [contentRef, contentElement] = (0, client_1.useRefElement)();
34
36
  const openRef = (0, react_1.useRef)(open);
35
37
  openRef.current = open;
@@ -37,8 +39,6 @@ function Popup(_a) {
37
39
  onOpenedRef.current = onOpenedRaw;
38
40
  const onClosedRef = (0, react_1.useRef)(onClosedRaw);
39
41
  onClosedRef.current = onClosedRaw;
40
- // re-render on window size change
41
- (0, client_1.useViewportSize)();
42
42
  // lock tab focus
43
43
  (0, react_1.useEffect)(() => {
44
44
  // lock when opened
@@ -71,7 +71,7 @@ function Popup(_a) {
71
71
  }
72
72
  };
73
73
  const onAnimationComplete = (definition) => {
74
- if (definition === 'visible') {
74
+ if (definition === 'animate') {
75
75
  onOpenedRef.current();
76
76
  }
77
77
  else if (definition === 'exit') {
@@ -89,72 +89,69 @@ function Popup(_a) {
89
89
  }
90
90
  };
91
91
  // render
92
- const popupPlacement = getPopupPlacement({
93
- contentElement,
94
- anchor,
95
- anchorOffset,
96
- placement,
97
- viewportPadding
98
- });
99
- return ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: (0, react_dom_1.createPortal)((0, jsx_runtime_1.jsx)(framer_motion_1.AnimatePresence, { children: open &&
100
- (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: (0, jsx_runtime_1.jsxs)(framer_motion_1.motion.div, { id: id, className: (0, classnames_1.default)(popupPlacement.containerClassName, 'fixed inset-0 z-popup', {
101
- 'pointer-events-none': disableOverlay
102
- }), variants: exports.animations, initial: animation !== 'out' ? 'hidden' : 'visible', animate: "visible", exit: animation !== 'in' ? 'exit' : 'visible', onAnimationComplete: definition => onAnimationComplete(definition), onClick: disableDismiss ? undefined : onBackdropClick, children: [backdrop !== 'none' &&
103
- (0, jsx_runtime_1.jsx)(framer_motion_1.motion.div, { className: (0, classnames_1.default)('fixed inset-0 z-backdrop', {
104
- 'backdrop-blur-[9px] bg-glass/backdrop will-change-[backdrop-filter]': backdrop === 'glass'
105
- }) }, "backdrop"), (0, jsx_runtime_1.jsx)("div", Object.assign({}, props, { ref: contentRef, style: Object.assign(Object.assign({}, style), ((_b = popupPlacement.style) !== null && _b !== void 0 ? _b : {})), className: (0, classnames_1.default)(className, popupPlacement.className, 'pointer-events-auto'), onKeyDown: onKeyDown, children: children }))] }, id) }) }), document.body) }));
92
+ const { popupContainerClassName, popupClassName } = getPopupClassNames({ anchor, anchorId, anchorOffset, placement });
93
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [anchor && typeof anchor !== 'string' &&
94
+ (0, jsx_runtime_1.jsx)(Popup.AnchorElement, { tag: "div", anchorId: anchorId, children: anchor }), (0, react_dom_1.createPortal)((0, jsx_runtime_1.jsx)(framer_motion_1.AnimatePresence, { mode: "wait", children: open &&
95
+ (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: (0, jsx_runtime_1.jsxs)(framer_motion_1.motion.div, { id: id, className: (0, classnames_1.default)(popupContainerClassName, 'fixed inset-0 z-popup', {
96
+ 'pointer-events-none': disableOverlay
97
+ }), variants: Animate_1.Animate.Variants.fade, initial: animation !== 'out' ? 'initial' : 'animate', animate: "animate", exit: animation !== 'in' ? 'exit' : 'animate', onAnimationComplete: definition => onAnimationComplete(definition), onClick: disableDismiss ? undefined : onBackdropClick, children: [backdrop !== 'none' &&
98
+ (0, jsx_runtime_1.jsx)(framer_motion_1.motion.div, { className: (0, classnames_1.default)('fixed inset-0 z-backdrop', {
99
+ 'backdrop-blur-[9px] bg-glass/backdrop will-change-[backdrop-filter]': backdrop === 'glass'
100
+ }) }, "backdrop"), (0, jsx_runtime_1.jsx)("div", Object.assign({}, props, { ref: contentRef, className: (0, classnames_1.default)(className, popupClassName, 'pointer-events-auto'), style: anchor
101
+ ? Popup.getAnchorStyle(anchorId, { margin: `${anchorOffset !== null && anchorOffset !== void 0 ? anchorOffset : 0}px` })
102
+ : undefined, onKeyDown: onKeyDown, children: children }))] }, id) }) }), document.body)] }));
106
103
  }
107
- // helpers
108
- exports.animations = {
109
- hidden: {
110
- opacity: 0
111
- },
112
- visible: {
113
- opacity: 1,
114
- transition: {
115
- ease: 'easeIn',
116
- duration: 0.3,
117
- when: 'beforeChildren'
118
- }
119
- },
120
- exit: {
121
- opacity: 0,
122
- transition: {
123
- ease: 'easeIn',
124
- duration: 0.15,
125
- bounce: 0,
126
- when: 'afterChildren'
127
- }
104
+ // extension
105
+ (function (Popup) {
106
+ // anchor helpers
107
+ Popup.anchorClassName = 'anchor/[--nd-popup-anchor]';
108
+ function getAnchorStyle(anchorId, styles = {}) {
109
+ return Object.assign(Object.assign({}, styles), { '--nd-popup-anchor': normalizeAnchorId(anchorId) });
128
110
  }
129
- };
130
- function getPopupPlacement({ anchor, anchorOffset = 0, placement = 'bottom', viewportPadding = 16, contentElement }) {
131
- // center if there's no anchor
132
- const anchorRect = funnel_core_1.Browser.getElementRect(anchor);
133
- if (!anchorRect || !contentElement) {
111
+ Popup.getAnchorStyle = getAnchorStyle;
112
+ function getAnchorFrame(frame) {
113
+ return frame && {
114
+ left: `${frame.left}px`,
115
+ top: `${frame.top}px`,
116
+ width: `${frame.width}px`,
117
+ height: `${frame.height}px`
118
+ };
119
+ }
120
+ Popup.getAnchorFrame = getAnchorFrame;
121
+ // container
122
+ function AnchorElement(_a) {
123
+ var { anchorId, tag, className, style } = _a, props = __rest(_a, ["anchorId", "tag", "className", "style"]);
124
+ // render
125
+ return ((0, jsx_runtime_1.jsx)(funnel_ui_1.HTMLContainer, Object.assign({ tag: tag, className: (0, classnames_1.default)(className, Popup.anchorClassName), style: getAnchorStyle(normalizeAnchorId(anchorId), style) }, props)));
126
+ }
127
+ Popup.AnchorElement = AnchorElement;
128
+ })(Popup || (exports.Popup = Popup = {}));
129
+ // helpers
130
+ function normalizeAnchorId(anchorId) {
131
+ return anchorId.startsWith('--')
132
+ ? anchorId
133
+ : `--${anchorId}`;
134
+ }
135
+ function getPopupClassNames({ anchor, placement }) {
136
+ // return anchor classes (via tailwind anchor plugin)
137
+ if (anchor) {
134
138
  return {
135
- containerClassName: 'flex flex-col justify-end items-center sm:justify-center',
136
- className: 'z-dialog'
139
+ popupContainerClassName: '',
140
+ popupClassName: (0, classnames_1.default)('!fixed anchored/[--nd-popup-anchor] z-dialog', {
141
+ 'anchored-top': placement === 'top',
142
+ 'anchored-top-span-right': placement === 'top-start',
143
+ 'anchored-bottom': placement === 'bottom',
144
+ 'anchored-left': placement === 'left',
145
+ 'anchored-right': placement === 'right',
146
+ 'anchored-bottom-span-left': placement === 'bottom-end'
147
+ })
137
148
  };
138
149
  }
139
- // or place absolutely
150
+ // or treat as modal if there's no anchor
140
151
  else {
141
- // resolve placement args
142
- const containerRect = new funnel_core_1.Rect(0, 0, window.innerWidth, window.innerHeight);
143
- const popupFrame = funnel_core_1.Placement.forContent({
144
- containerRect,
145
- containerPadding: viewportPadding,
146
- anchorRect,
147
- anchorOffset,
148
- placement,
149
- contentSize: {
150
- width: contentElement.offsetWidth,
151
- height: contentElement.offsetHeight
152
- }
153
- });
154
- // set style to frame
155
152
  return {
156
- className: 'absolute z-dialog',
157
- style: popupFrame
153
+ popupContainerClassName: 'flex flex-col justify-end items-center sm:justify-center',
154
+ popupClassName: 'z-dialog'
158
155
  };
159
156
  }
160
157
  }
@@ -54,6 +54,7 @@ exports.QuickInput = (0, react_1.forwardRef)(function QuickInput(_, ref) {
54
54
  setSchema(schema);
55
55
  setInitialValue(initialValue);
56
56
  setPopupProps(popupProps);
57
+ console.debug('[QuickInput] opening editor with', popupProps);
57
58
  // create/set deferral
58
59
  const deferral = new funnel_core_1.Deferral();
59
60
  setDeferral(deferral);
@@ -61,6 +62,7 @@ exports.QuickInput = (0, react_1.forwardRef)(function QuickInput(_, ref) {
61
62
  const result = await deferral.promise;
62
63
  // clear deferral
63
64
  setDeferral(undefined);
65
+ console.debug('[QuickInput] closing editor with', popupProps);
64
66
  // return deferral
65
67
  return result;
66
68
  },
@@ -5,6 +5,7 @@ export declare const QuickPicker: import("react").ForwardRefExoticComponent<Quic
5
5
  export declare namespace QuickPicker {
6
6
  type Item<TId extends string> = {
7
7
  id: TId;
8
+ label: string;
8
9
  };
9
10
  type ItemVariant = 'card';
10
11
  type Props<TId extends string, TItem extends Item<TId>> = {
@@ -92,8 +92,8 @@ exports.QuickPicker = (0, react_1.forwardRef)(function QuickPicker({ variant, ti
92
92
  'opacity-none': !opened,
93
93
  'opacity-full': opened
94
94
  }), animation: "out", open: !!deferral, onOpened: () => setOpened(true), onClose: onClose, onClosed: () => setOpened(false), children: [(0, jsx_runtime_1.jsxs)("section", { className: "px-l8", children: [(0, jsx_runtime_1.jsx)("h3", { className: "heading-sm text-content-primary", children: title }), description &&
95
- (0, jsx_runtime_1.jsx)("p", { className: "body-sm text-content-secondary", children: description })] }), (0, jsx_runtime_1.jsx)("section", { className: (0, classnames_1.default)({
96
- 'flex flex-wrap gap-l5 items-center px-l8 pb-l8 overflow-y-scroll': variant === 'card',
95
+ (0, jsx_runtime_1.jsx)("p", { className: "body-sm text-content-secondary", children: description })] }), (0, jsx_runtime_1.jsx)("section", { className: (0, classnames_1.default)('px-l8 pb-l8 overflow-y-scroll scrollbar-thin scroller-edge', {
96
+ 'flex flex-wrap gap-l5 items-center ': variant === 'card',
97
97
  'w-[288px]': variant === 'card' && items.length < 4,
98
98
  'w-[372px] max-h-[213px]': variant === 'card' && items.length >= 4
99
99
  }), children: items.map(item => renderCard({
@@ -104,7 +104,7 @@ exports.QuickPicker = (0, react_1.forwardRef)(function QuickPicker({ variant, ti
104
104
  })) })] })));
105
105
  });
106
106
  function renderCard({ item, content, selected, onSelect }) {
107
- return ((0, jsx_runtime_1.jsx)("div", { className: (0, classnames_1.default)('FieldCard w-[72px] h-[55px]', {
108
- 'FieldCard-selected': selected
109
- }), onClick: () => onSelect(item.id), children: content }, item.id));
107
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "group flex flex-col items-center gap-l2 shrink-0 cursor-pointer", onClick: () => onSelect(item.id), children: [(0, jsx_runtime_1.jsx)("div", { className: (0, classnames_1.default)('FieldCard w-[72px] h-[55px] group-hover:FieldCard-hover group-active:FieldCard-press', {
108
+ 'FieldCard-selected': selected
109
+ }), children: content }), (0, jsx_runtime_1.jsx)("span", { className: (0, classnames_1.default)('label-xxs text-content-tertiary interpolate-fast pointer-events-none', 'group-hover:text-content-secondary group-active:text-content-primary'), children: item.label })] }, item.id));
110
110
  }
@@ -1,7 +1,9 @@
1
1
  import { Callback } from '@nascentdigital/funnel-core';
2
2
  import { Icon } from '../visuals';
3
- export declare function Tabs<TId extends string>({ className, items, selectedItem, onSelect }: Tabs.Props<TId>): import("react/jsx-runtime").JSX.Element;
3
+ export declare function Tabs<TId extends string>({ className, variant, size, items, selectedItem, onSelect }: Tabs.Props<TId>): import("react/jsx-runtime").JSX.Element;
4
4
  export declare namespace Tabs {
5
+ type Variant = 'underlined' | 'highlighted';
6
+ type Size = 'md' | 'sm';
5
7
  type Item<TId extends string = string> = {
6
8
  id: TId;
7
9
  label: string;
@@ -9,6 +11,8 @@ export declare namespace Tabs {
9
11
  };
10
12
  type Props<TId extends string = string> = {
11
13
  className?: string;
14
+ variant?: Variant;
15
+ size?: Size;
12
16
  items: ReadonlyArray<Item<TId>>;
13
17
  selectedItem: TId;
14
18
  onSelect?: Callback<TId>;
@@ -10,15 +10,25 @@ const classnames_1 = __importDefault(require("classnames"));
10
10
  const framer_motion_1 = require("framer-motion");
11
11
  const visuals_1 = require("../visuals");
12
12
  // component
13
- function Tabs({ className, items, selectedItem, onSelect = funnel_core_1.Fn.NoOp }) {
13
+ function Tabs({ className, variant = 'underlined', size = 'md', items, selectedItem, onSelect = funnel_core_1.Fn.NoOp }) {
14
14
  // render
15
- return ((0, jsx_runtime_1.jsx)("nav", { className: (0, classnames_1.default)(className), children: (0, jsx_runtime_1.jsx)("ul", { className: "grid auto-cols-fr grid-flow-col items-center", children: items.map(item => (0, jsx_runtime_1.jsxs)("li", { className: (0, classnames_1.default)('group relative border-b border-solid border-content-tertiary cursor-pointer interpolate', {
15
+ return ((0, jsx_runtime_1.jsx)("nav", { className: (0, classnames_1.default)(className), children: (0, jsx_runtime_1.jsx)("ul", { className: (0, classnames_1.default)('grid auto-cols-fr grid-flow-col items-center cursor-pointer', {
16
+ 'rounded-lg bg-surface-placeholder-raised p-l1': variant === 'highlighted',
17
+ }), children: items.map(item => (0, jsx_runtime_1.jsxs)("li", { className: (0, classnames_1.default)('group relative interpolate', {
18
+ 'border-b border-solid border-content-tertiary': variant === 'underlined',
16
19
  'pointer-events-none': item.id === selectedItem,
17
- 'hover:border-content-secondary active:border-content-tertiary': item.id !== selectedItem
18
- }), onClick: () => onSelect(item.id), children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex justify-center items-center gap-l6", children: [item.icon &&
19
- (0, jsx_runtime_1.jsx)(visuals_1.Icon, { variant: item.icon, size: "nav" }), (0, jsx_runtime_1.jsx)("span", { className: (0, classnames_1.default)('inline-block label-sm py-l6 interpolate', {
20
+ 'hover:border-content-secondary active:border-content-tertiary': item.id !== selectedItem,
21
+ }), onClick: () => onSelect(item.id), children: [(0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)('flex justify-center items-center gap-l6', {
22
+ 'relative z-supersurface': variant === 'highlighted'
23
+ }), children: [item.icon &&
24
+ (0, jsx_runtime_1.jsx)(visuals_1.Icon, { variant: item.icon, size: "nav" }), (0, jsx_runtime_1.jsx)("span", { className: (0, classnames_1.default)('inline-block interpolate', {
20
25
  'text-content-primary': item.id === selectedItem,
21
- 'text-content-secondary group-hover:text-content-primary group-active:text-content-tertiary': item.id !== selectedItem
22
- }), children: item.label })] }), item.id === selectedItem &&
23
- (0, jsx_runtime_1.jsx)(framer_motion_1.motion.span, { id: "underline", layoutId: "underline", className: "absolute inset-x-0 -bottom-px block divider border-b-2 border-ix-primary -mb-px z-supersurface" })] }, item.id)) }) }));
26
+ 'text-content-secondary group-hover:text-content-primary group-active:text-content-tertiary': item.id !== selectedItem,
27
+ 'py-l6 label-md': variant === 'underlined' && size === 'md',
28
+ 'py-l3 label-xs': variant === 'underlined' && size === 'sm',
29
+ 'py-l3 label-md': variant === 'highlighted' && size === 'md',
30
+ 'py-l2 label-xs': variant === 'highlighted' && size === 'sm'
31
+ }), children: item.label })] }), variant === 'underlined' && item.id === selectedItem &&
32
+ (0, jsx_runtime_1.jsx)(framer_motion_1.motion.span, { id: "underline", layoutId: "underline", className: "absolute inset-x-0 -bottom-px block divider border-b-2 border-ix-primary -mb-px z-supersurface" }), variant === 'highlighted' && item.id === selectedItem &&
33
+ (0, jsx_runtime_1.jsx)(framer_motion_1.motion.span, { layoutId: "active-tab", className: "absolute z-surface inset-0 bg-surface-placeholder rounded-lg" })] }, item.id)) }) }));
24
34
  }
@@ -11,12 +11,12 @@ export declare class MenuController<TItemId extends string, TContext = any> {
11
11
  set items(items: ReadonlyArray<MenuItem<TItemId>> | undefined);
12
12
  get selectedItem(): TItemId | undefined;
13
13
  set selectedItem(item: TItemId | undefined);
14
- get anchor(): HTMLElement | undefined;
14
+ get anchor(): string | undefined;
15
15
  private _context?;
16
16
  get context(): TContext | undefined;
17
17
  get changed$(): Observable<Date>;
18
18
  get isOpen(): boolean;
19
- open(anchor: HTMLElement, context?: TContext): void;
19
+ open(anchor: string, context?: TContext): void;
20
20
  close(): void;
21
21
  private raiseChange;
22
22
  }
@@ -1,10 +1,11 @@
1
1
  import { Callback } from '@nascentdigital/funnel-core';
2
2
  import { MouseEvent, PropsWithChildren, ReactNode } from 'react';
3
3
  import { Icon } from '../../visuals';
4
- export declare function TableItem({ className, nested, details, iconLeft, iconRight, disabled, onClick, children }: TableItem.Props): import("react/jsx-runtime").JSX.Element;
4
+ export declare function TableItem({ className, anchorId, nested, details, iconLeft, iconRight, disabled, onClick, children }: TableItem.Props): import("react/jsx-runtime").JSX.Element;
5
5
  export declare namespace TableItem {
6
6
  type Props = PropsWithChildren & {
7
7
  className?: string;
8
+ anchorId?: string;
8
9
  nested?: boolean;
9
10
  details?: ReactNode;
10
11
  iconLeft?: Icon.Variant | ReactNode;
@@ -8,8 +8,9 @@ const jsx_runtime_1 = require("react/jsx-runtime");
8
8
  const funnel_core_1 = require("@nascentdigital/funnel-core");
9
9
  const classnames_1 = __importDefault(require("classnames"));
10
10
  const visuals_1 = require("../../visuals");
11
+ const interaction_1 = require("../../interaction");
11
12
  // component
12
- function TableItem({ className, nested = false, details, iconLeft, iconRight, disabled = false, onClick, children }) {
13
+ function TableItem({ className, anchorId, nested = false, details, iconLeft, iconRight, disabled = false, onClick, children }) {
13
14
  // render
14
15
  const labelOnly = !details && !iconRight;
15
16
  const interactive = !!onClick;
@@ -17,8 +18,9 @@ function TableItem({ className, nested = false, details, iconLeft, iconRight, di
17
18
  'bg-surface1': !nested,
18
19
  'bg-transparent': nested,
19
20
  'interactive-disabled': !interactive && !disabled,
20
- 'bg-ix-disabled/tint1 pointer-events-none': disabled
21
- }), tabIndex: 0, onClick: onClick, children: [(0, jsx_runtime_1.jsx)("div", { className: "interactive-tint" }), (0, jsx_runtime_1.jsxs)("div", { className: "flex-1 flex items-center", children: [(0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)('flex-1 flex items-center gap-l3 py-l5'), children: [visuals_1.Icon.Variant.filter(iconLeft)
21
+ 'bg-ix-disabled/tint1 pointer-events-none': disabled,
22
+ [interaction_1.Popup.anchorClassName]: !!anchorId
23
+ }), style: anchorId ? interaction_1.Popup.getAnchorStyle(anchorId) : undefined, tabIndex: 0, onClick: onClick, children: [(0, jsx_runtime_1.jsx)("div", { className: "interactive-tint" }), (0, jsx_runtime_1.jsxs)("div", { className: "flex-1 flex items-center", children: [(0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)('flex-1 flex items-center gap-l3 py-l5'), children: [visuals_1.Icon.Variant.filter(iconLeft)
22
24
  ?
23
25
  (0, jsx_runtime_1.jsx)(visuals_1.Icon, { className: (0, classnames_1.default)({
24
26
  'text-content-secondary': !disabled,
@@ -19,6 +19,7 @@ const jsx_runtime_1 = require("react/jsx-runtime");
19
19
  const funnel_core_1 = require("@nascentdigital/funnel-core");
20
20
  const funnel_ui_1 = require("@nascentdigital/funnel-ui");
21
21
  const classnames_1 = __importDefault(require("classnames"));
22
+ const react_1 = require("react");
22
23
  const feedback_1 = require("../feedback");
23
24
  const interaction_1 = require("../interaction");
24
25
  // component
@@ -26,10 +27,11 @@ function InfoPanel(_a) {
26
27
  var { className, contentClassName, title, caption, status, menu: menuItems, onMenuSelect = funnel_core_1.Fn.NoOp, children } = _a, props = __rest(_a, ["className", "contentClassName", "title", "caption", "status", "menu", "onMenuSelect", "children"]);
27
28
  // bind refs
28
29
  const menu = (0, interaction_1.useMenuController)(menuItems);
30
+ const anchorId = (0, react_1.useId)();
29
31
  // helpers
30
32
  const onMenuOpen = (e) => {
31
33
  // open menu
32
- menu.open(e.currentTarget);
34
+ menu.open(anchorId);
33
35
  };
34
36
  const onMenuClick = (menuId) => {
35
37
  // close menu
@@ -40,7 +42,7 @@ function InfoPanel(_a) {
40
42
  // render
41
43
  return ((0, jsx_runtime_1.jsxs)("section", { className: (0, classnames_1.default)(className, 'flex flex-col p-l7', 'bg-surface1 rounded-xxl'), children: [(0, jsx_runtime_1.jsxs)("div", { className: "shrink-0 flex items-center gap-l4", children: [status &&
42
44
  (0, jsx_runtime_1.jsx)(feedback_1.StatusIcon, { variant: status, size: "md" }), (0, jsx_runtime_1.jsx)("h3", { className: "flex-1 heading-sm text-content-primary ellipsis", children: title }), menu &&
43
- (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(interaction_1.IconButton, { className: "shrink-0", icon: "EllipsisVertical", onClick: onMenuOpen }), (0, jsx_runtime_1.jsx)(interaction_1.Menu, { controller: menu, onItemClick: onMenuClick })] })] }), caption &&
45
+ (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(interaction_1.IconButton, { anchorId: anchorId, className: "shrink-0", icon: "EllipsisVertical", onClick: onMenuOpen }), (0, jsx_runtime_1.jsx)(interaction_1.Menu, { controller: menu, onItemClick: onMenuClick })] })] }), caption &&
44
46
  (0, jsx_runtime_1.jsx)(funnel_ui_1.Markup, { className: (0, classnames_1.default)('markup-caption mt-l6', {
45
47
  'text-destructive-content bg-destructive/tint0 p-l5 rounded-md': status === 'error'
46
48
  }), markdown: caption }), (0, jsx_runtime_1.jsx)("div", { className: (0, classnames_1.default)(contentClassName), children: children })] }));
@@ -6,7 +6,7 @@ export declare namespace Icon {
6
6
  size?: Size;
7
7
  };
8
8
  type Size = 'xl' | 'lg' | 'md' | 'sm' | 'xs' | 'xxs' | 'nav' | 'card' | Sizing;
9
- type Variant = 'Archive' | 'ArrowLeft' | 'ArrowRight' | 'ArrowLeftRight' | 'Atom' | 'Blocks' | 'Bold' | 'Check' | 'ChevronDown' | 'ChevronRight' | 'ChevronUp' | 'Circle' | 'CircleAlert' | 'CircleCheck' | 'CircleCheckBig' | 'CirclePlus' | 'CircleQuestionMark' | 'CloudCheck' | 'CloudUpload' | 'CornerDownRight' | 'EllipsisVertical' | 'Eye' | 'EyeOff' | 'File' | 'FileDown' | 'FilePlusCorner' | 'FileSearchCorner' | 'Goal' | 'Globe' | 'GripVertical' | 'HatGlasses' | 'History' | 'Highlighter' | 'Image' | 'ImageDown' | 'Info' | 'Italic' | 'Layers' | 'LayoutTemplate' | 'Link' | 'Link2' | 'List' | 'ListChecks' | 'ListIndentDecrease' | 'ListIndentIncrease' | 'ListOrdered' | 'Lock' | 'LockOpen' | 'Mail' | 'MessageSquareQuote' | 'Minus' | 'MonitorCog' | 'Moon' | 'NotebookPen' | 'Pencil' | 'Pin' | 'Plus' | 'Redo' | 'RefreshCw' | 'RotateCcw' | 'RotateCw' | 'SearchCode' | 'Settings' | 'SquarePlay' | 'Star' | 'Strikethrough' | 'Subscript' | 'Sun' | 'Superscript' | 'TextAlignStart' | 'Trash' | 'TriangleAlert' | 'Trophy' | 'Underline' | 'Undo' | 'Upload' | 'UserRound' | 'X';
9
+ type Variant = 'Archive' | 'ArrowLeft' | 'ArrowRight' | 'ArrowLeftRight' | 'Atom' | 'Blocks' | 'Bold' | 'Check' | 'ChevronDown' | 'ChevronRight' | 'ChevronUp' | 'Circle' | 'CircleAlert' | 'CircleCheck' | 'CircleCheckBig' | 'CirclePlus' | 'CircleQuestionMark' | 'CloudCheck' | 'CloudUpload' | 'CornerDownRight' | 'EllipsisVertical' | 'Eye' | 'EyeOff' | 'File' | 'FileDown' | 'FilePlusCorner' | 'FileSearchCorner' | 'Goal' | 'Globe' | 'GripVertical' | 'HatGlasses' | 'History' | 'Highlighter' | 'Image' | 'ImageDown' | 'Info' | 'Italic' | 'Layers' | 'LayoutTemplate' | 'Link' | 'Link2' | 'List' | 'ListChecks' | 'ListIndentDecrease' | 'ListIndentIncrease' | 'ListOrdered' | 'Lock' | 'LockOpen' | 'Mail' | 'MessageSquareQuote' | 'Minus' | 'Monitor' | 'MonitorCog' | 'Moon' | 'NotebookPen' | 'Pencil' | 'Pin' | 'Plus' | 'Redo' | 'RefreshCw' | 'RotateCcw' | 'RotateCw' | 'SearchCode' | 'Settings' | 'Smartphone' | 'SquarePlay' | 'Star' | 'Strikethrough' | 'Subscript' | 'Sun' | 'Superscript' | 'TextAlignStart' | 'Trash' | 'TriangleAlert' | 'Trophy' | 'Underline' | 'Undo' | 'Upload' | 'UserRound' | 'X';
10
10
  namespace Variant {
11
11
  function filter(value: any): value is Variant;
12
12
  }
@@ -69,6 +69,7 @@ function Icon({ className, variant, size: sizing = 'md' }) {
69
69
  'Mail',
70
70
  'MessageSquareQuote',
71
71
  'Minus',
72
+ 'Monitor',
72
73
  'MonitorCog',
73
74
  'Moon',
74
75
  'NotebookPen',
@@ -81,6 +82,7 @@ function Icon({ className, variant, size: sizing = 'md' }) {
81
82
  'RotateCw',
82
83
  'SearchCode',
83
84
  'Settings',
85
+ 'Smartphone',
84
86
  'SquarePlay',
85
87
  'Star',
86
88
  'Strikethrough',
@@ -211,6 +213,8 @@ function getIcon(variant) {
211
213
  return lucide_react_1.MessageSquareQuote;
212
214
  case 'Minus':
213
215
  return lucide_react_1.Minus;
216
+ case 'Monitor':
217
+ return lucide_react_1.Monitor;
214
218
  case 'MonitorCog':
215
219
  return lucide_react_1.MonitorCog;
216
220
  case 'Moon':
@@ -235,6 +239,8 @@ function getIcon(variant) {
235
239
  return lucide_react_1.SearchCode;
236
240
  case 'Settings':
237
241
  return lucide_react_1.Settings;
242
+ case 'Smartphone':
243
+ return lucide_react_1.Smartphone;
238
244
  case 'SquarePlay':
239
245
  return lucide_react_1.SquarePlay;
240
246
  case 'Star':
@@ -2,4 +2,3 @@ export * from './BlockIcon';
2
2
  export * from './Icon';
3
3
  export * from './Illustration';
4
4
  export * from './Logo';
5
- export * from './SkeletonLayout';
@@ -18,4 +18,3 @@ __exportStar(require("./BlockIcon"), exports);
18
18
  __exportStar(require("./Icon"), exports);
19
19
  __exportStar(require("./Illustration"), exports);
20
20
  __exportStar(require("./Logo"), exports);
21
- __exportStar(require("./SkeletonLayout"), exports);
@@ -8,6 +8,10 @@ export declare class Block<TBlock extends Schema.Block = Schema.Block> extends I
8
8
  readonly config: ReadonlyArray<FieldModel.Config>;
9
9
  readonly fields: ReadonlyArray<FieldModel>;
10
10
  readonly nameField: Field<Schema.TextField>;
11
+ readonly messageFields: ReadonlyArray<FieldModel>;
12
+ readonly visualFields: ReadonlyArray<FieldModel>;
13
+ readonly listsFields: ReadonlyArray<FieldModel>;
14
+ readonly extendedFields: ReadonlyArray<FieldModel>;
11
15
  private _modifiedOn?;
12
16
  private _savingOn?;
13
17
  constructor(args: Block.ConstructorArgs<TBlock>);
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Block = void 0;
4
4
  const funnel_core_1 = require("@nascentdigital/funnel-core");
5
+ const funnel_ui_1 = require("@nascentdigital/funnel-ui");
5
6
  const rxjs_1 = require("rxjs");
6
7
  const BlockConfiguration_1 = require("./BlockConfiguration");
7
8
  const ItemBase_1 = require("./ItemBase");
@@ -31,6 +32,12 @@ class Block extends ItemBase_1.ItemBase {
31
32
  publishedValue: undefined,
32
33
  required: true
33
34
  });
35
+ // group fields
36
+ const messageKeys = Object.keys(funnel_ui_1.MessagePanel.Fields.getSchema());
37
+ this.messageFields = this.fields.filter(field => messageKeys.includes(field.id));
38
+ this.visualFields = this.fields.filter(field => field.id === 'visual');
39
+ this.listsFields = this.fields.filter(field => field.id === 'list');
40
+ this.extendedFields = this.fields.filter(field => !messageKeys.includes(field.id) && field.id !== 'visual' && field.id !== 'list');
34
41
  // listen to field changes
35
42
  this.eventBus.events$
36
43
  .pipe((0, rxjs_1.filter)(funnel_core_1.Field.Event.filter), (0, rxjs_1.filter)(event => (event.type === 'changed' || event.type === 'reset')
@@ -8,28 +8,34 @@ export declare class BlockConfiguration {
8
8
  readonly assetStore: IAssetStore;
9
9
  readonly sectionBlock?: SectionBlock;
10
10
  readonly block: Block;
11
- readonly fields: ReadonlyArray<FieldModel.Config>;
11
+ private _fields;
12
12
  private _editableFields;
13
+ private _scope;
13
14
  private _layout?;
14
15
  private _slotState;
15
16
  private _defaultConfig?;
16
17
  private _isConfigInDefault?;
17
18
  constructor({ block: blockOrSectionBlock, assetStore }: BlockConfiguration.ConstructorArgs);
19
+ get fields(): ReadonlyArray<FieldModel.Config>;
18
20
  get editableFields(): ReadonlyArray<FieldModel.Config>;
19
21
  set editableFields(fields: ReadonlyArray<FieldModel.Config>);
22
+ get scope(): BlockConfiguration.Scope;
23
+ set scope(scope: BlockConfiguration.Scope);
20
24
  get blocksFields(): FieldModel.Config[];
21
25
  get blockFieldData(): Schema.Block.Data.ForFields<Schema.Fields>;
22
26
  get desktopFields(): FieldModel.Config[];
23
- get mobileFields(): never[];
27
+ get mobileFields(): FieldModel.Config[];
24
28
  get nameField(): FieldModel.Config | undefined;
25
29
  get themeField(): FieldModel.Config | undefined;
26
30
  get layoutField(): Field<Schema.EnumField<Schema.EnumField.Options<PanelLayout>>> | undefined;
27
31
  get slotState(): Readonly<BlockConfiguration.SlotState>;
28
32
  gotToNextSlot(): void;
29
33
  gotToPreviousSlot(): void;
34
+ get hasPanels(): boolean;
30
35
  get messageFields(): Record<keyof MessagePanel.Config.Keys<'message'>, FieldModel.Config | undefined>;
31
36
  get listFields(): Record<keyof ListPanel.Config.Keys<'list'>, FieldModel.Config | undefined>;
32
37
  get visualFields(): Record<keyof VisualPanel.Config.Keys<'visual'>, FieldModel.Config | undefined>;
38
+ get extendedFields(): Record<string, FieldModel.Config>;
33
39
  get layout(): BlockLayout | undefined;
34
40
  get events$(): import("rxjs").Observable<EventBus.Event<string, string>>;
35
41
  get valid(): boolean;
@@ -38,12 +44,14 @@ export declare class BlockConfiguration {
38
44
  getFieldData(fieldId: string): Schema.Field.LinkedData | undefined;
39
45
  getEditableField(fieldId: string): FieldModel.Config | undefined;
40
46
  save(): void;
41
- reset(): void;
47
+ resetToDefault(): void;
42
48
  get isConfigInDefault(): boolean | undefined;
43
49
  sync(): void;
50
+ reset(): void;
44
51
  private raiseEvent;
45
52
  }
46
53
  export declare namespace BlockConfiguration {
54
+ type Scope = 'desktop' | 'mobile';
47
55
  type SlotState = {
48
56
  field?: Field<Schema.EnumField<Schema.EnumField.Options<SlotVariation>>>;
49
57
  options: ReadonlyArray<SlotVariation>;