@lowdefy/blocks-antd 5.1.0 → 5.2.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/dist/blocks/ControlledList/ControlledList.js +40 -15
- package/dist/blocks/ControlledList/meta.js +6 -2
- package/dist/blocks/ControlledList/style.module.css +35 -0
- package/dist/blocks/DropdownButton/DropdownButton.js +13 -5
- package/dist/blocks/DropdownButton/meta.js +3 -3
- package/dist/blocks/PageSidebarLayout/PageSidebarLayout.js +12 -6
- package/dist/blocks/PageSidebarLayout/meta.js +10 -0
- package/dist/blocks/headerActions.js +131 -28
- package/package.json +6 -6
|
@@ -15,10 +15,11 @@
|
|
|
15
15
|
*/ import React, { useEffect } from 'react';
|
|
16
16
|
import { get } from '@lowdefy/helpers';
|
|
17
17
|
import { List, Typography } from 'antd';
|
|
18
|
-
import { withBlockDefaults } from '@lowdefy/block-utils';
|
|
18
|
+
import { cn, withBlockDefaults } from '@lowdefy/block-utils';
|
|
19
19
|
import Button from '../Button/Button.js';
|
|
20
20
|
import withTheme from '../withTheme.js';
|
|
21
|
-
|
|
21
|
+
import './style.module.css';
|
|
22
|
+
const ControlledListBlock = ({ blockId, classNames = {}, components: { Icon, Link, ShortcutBadge }, events, list, methods, properties, styles = {}, value = [] })=>{
|
|
22
23
|
useEffect(()=>{
|
|
23
24
|
methods.registerMethod('moveItemDown', methods.moveItemDown);
|
|
24
25
|
methods.registerMethod('moveItemUp', methods.moveItemUp);
|
|
@@ -31,6 +32,38 @@ const ControlledListBlock = ({ blockId, classNames = {}, components: { Icon, Lin
|
|
|
31
32
|
methods.pushItem({});
|
|
32
33
|
}
|
|
33
34
|
}
|
|
35
|
+
const addItemToFront = ()=>{
|
|
36
|
+
methods.unshiftItem();
|
|
37
|
+
methods.triggerEvent({
|
|
38
|
+
name: 'onAdd',
|
|
39
|
+
event: {
|
|
40
|
+
index: 0,
|
|
41
|
+
item: undefined
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
const addItemToBack = ()=>{
|
|
46
|
+
const index = value.length;
|
|
47
|
+
methods.pushItem();
|
|
48
|
+
methods.triggerEvent({
|
|
49
|
+
name: 'onAdd',
|
|
50
|
+
event: {
|
|
51
|
+
index,
|
|
52
|
+
item: undefined
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
const removeItemAt = (index)=>{
|
|
57
|
+
const item = value[index];
|
|
58
|
+
methods.removeItem(index);
|
|
59
|
+
methods.triggerEvent({
|
|
60
|
+
name: 'onRemove',
|
|
61
|
+
event: {
|
|
62
|
+
index,
|
|
63
|
+
item
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
};
|
|
34
67
|
return /*#__PURE__*/ React.createElement(List, {
|
|
35
68
|
id: blockId,
|
|
36
69
|
className: classNames.element,
|
|
@@ -61,7 +94,7 @@ const ControlledListBlock = ({ blockId, classNames = {}, components: { Icon, Lin
|
|
|
61
94
|
type: 'default',
|
|
62
95
|
...properties.addItemButton
|
|
63
96
|
},
|
|
64
|
-
onClick:
|
|
97
|
+
onClick: addItemToFront
|
|
65
98
|
})),
|
|
66
99
|
footer: !properties.addToFront && !properties.hideAddButton && /*#__PURE__*/ React.createElement("div", {
|
|
67
100
|
style: {
|
|
@@ -86,7 +119,7 @@ const ControlledListBlock = ({ blockId, classNames = {}, components: { Icon, Lin
|
|
|
86
119
|
type: 'dashed',
|
|
87
120
|
...properties.addItemButton
|
|
88
121
|
},
|
|
89
|
-
onClick:
|
|
122
|
+
onClick: addItemToBack
|
|
90
123
|
})),
|
|
91
124
|
bordered: true,
|
|
92
125
|
locale: {
|
|
@@ -102,24 +135,16 @@ const ControlledListBlock = ({ blockId, classNames = {}, components: { Icon, Lin
|
|
|
102
135
|
extra: !properties.hideRemoveButton && list.length > (properties.minItems ?? 0) && [
|
|
103
136
|
// eslint-disable-next-line react/jsx-key
|
|
104
137
|
/*#__PURE__*/ React.createElement("span", {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
fontSize: properties.size === 'small' ? 16 : properties.size === 'large' ? 20 : 18
|
|
108
|
-
}
|
|
138
|
+
className: cn('lf-controlled-list-remove', classNames.removeIcon),
|
|
139
|
+
style: styles.removeIcon
|
|
109
140
|
}, /*#__PURE__*/ React.createElement(Icon, {
|
|
110
141
|
blockId: `${blockId}_${i}_remove_icon`,
|
|
111
|
-
classNames: {
|
|
112
|
-
element: classNames.removeIcon
|
|
113
|
-
},
|
|
114
142
|
events: events,
|
|
115
143
|
properties: {
|
|
116
144
|
name: 'AiOutlineMinusCircle',
|
|
117
145
|
...properties.removeItemIcon
|
|
118
146
|
},
|
|
119
|
-
|
|
120
|
-
element: styles.removeIcon
|
|
121
|
-
},
|
|
122
|
-
onClick: ()=>methods.removeItem(i)
|
|
147
|
+
onClick: ()=>removeItemAt(i)
|
|
123
148
|
}))
|
|
124
149
|
]
|
|
125
150
|
}, item.content && item.content({
|
|
@@ -22,12 +22,16 @@
|
|
|
22
22
|
slots: {
|
|
23
23
|
content: 'Blocks rendered for each list item.'
|
|
24
24
|
},
|
|
25
|
+
events: {
|
|
26
|
+
onAdd: 'Triggered after a new item is added via the add button. The event payload is `{ index, item }`, where `item` is the newly added value (`undefined` for an empty row).',
|
|
27
|
+
onRemove: 'Triggered after an item is removed via the remove icon. The event payload is `{ index, item }`, where `item` is the removed value captured before removal.'
|
|
28
|
+
},
|
|
25
29
|
cssKeys: {
|
|
26
30
|
element: 'The ControlledList element.',
|
|
27
31
|
header: 'The ControlledList header.',
|
|
28
32
|
footer: 'The ControlledList footer.',
|
|
29
33
|
item: 'The ControlledList item.',
|
|
30
|
-
removeIcon: 'The remove
|
|
34
|
+
removeIcon: 'The remove-item icon wrapper. Defaults to the antd error color at `fontSizeLG`; override `color`, `font-size`, or spacing here.'
|
|
31
35
|
},
|
|
32
36
|
properties: {
|
|
33
37
|
type: 'object',
|
|
@@ -69,7 +73,7 @@
|
|
|
69
73
|
'string',
|
|
70
74
|
'object'
|
|
71
75
|
],
|
|
72
|
-
description: 'Custom remove item icon properties.',
|
|
76
|
+
description: 'Custom remove item icon properties. Defaults to `AiOutlineMinusCircle` at a standard size with the antd error color inherited from the icon wrapper — override via `class.removeIcon` / `style.removeIcon` for visual tweaks, or via this property to change the icon name itself.',
|
|
73
77
|
docs: {
|
|
74
78
|
displayType: 'icon'
|
|
75
79
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
@layer components {
|
|
18
|
+
:global(.lf-controlled-list-remove) {
|
|
19
|
+
display: inline-flex;
|
|
20
|
+
align-items: center;
|
|
21
|
+
padding-left: var(--ant-padding-xs);
|
|
22
|
+
font-size: var(--ant-font-size-lg);
|
|
23
|
+
color: var(--ant-color-error);
|
|
24
|
+
cursor: pointer;
|
|
25
|
+
transition: color 0.2s;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
:global(.lf-controlled-list-remove:hover) {
|
|
29
|
+
color: var(--ant-color-error-hover);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
:global(.lf-controlled-list-remove:active) {
|
|
33
|
+
color: var(--ant-color-error-active);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -62,10 +62,12 @@ function DropdownButtonBlock({ blockId, classNames = {}, components: { Icon, Sho
|
|
|
62
62
|
key: `divider-${i}`
|
|
63
63
|
};
|
|
64
64
|
}
|
|
65
|
+
const eventShortcut = item.eventName ? events[item.eventName]?.shortcut : undefined;
|
|
66
|
+
const itemShortcut = eventShortcut ?? item.shortcut;
|
|
65
67
|
return {
|
|
66
68
|
key: item.eventName ?? `item-${i}`,
|
|
67
|
-
label: /*#__PURE__*/ React.createElement("span", null, item.title,
|
|
68
|
-
shortcut:
|
|
69
|
+
label: /*#__PURE__*/ React.createElement("span", null, item.title, itemShortcut && /*#__PURE__*/ React.createElement(ShortcutBadge, {
|
|
70
|
+
shortcut: itemShortcut
|
|
69
71
|
})),
|
|
70
72
|
icon: item.icon ? /*#__PURE__*/ React.createElement(Icon, {
|
|
71
73
|
blockId: `${blockId}_icon_${i}`,
|
|
@@ -82,7 +84,10 @@ function DropdownButtonBlock({ blockId, classNames = {}, components: { Icon, Sho
|
|
|
82
84
|
disabled: item.disabled
|
|
83
85
|
};
|
|
84
86
|
});
|
|
85
|
-
|
|
87
|
+
// Item-level shortcut fallback for items that declare `shortcut` on properties
|
|
88
|
+
// rather than via `events.<eventName>.shortcut`. Skip items whose event already
|
|
89
|
+
// owns the shortcut — the framework-level shortcut manager handles those.
|
|
90
|
+
const propertyShortcutItems = (properties.items ?? []).filter((item)=>item.shortcut && item.eventName && !item.disabled && !events[item.eventName]?.shortcut).map((item)=>({
|
|
86
91
|
key: item.eventName,
|
|
87
92
|
shortcut: item.shortcut
|
|
88
93
|
}));
|
|
@@ -94,12 +99,13 @@ function DropdownButtonBlock({ blockId, classNames = {}, components: { Icon, Sho
|
|
|
94
99
|
methods
|
|
95
100
|
]);
|
|
96
101
|
useItemShortcuts({
|
|
97
|
-
items:
|
|
102
|
+
items: propertyShortcutItems,
|
|
98
103
|
onMatch: onShortcutMatch
|
|
99
104
|
});
|
|
100
105
|
const onClickActionName = get(rename, 'events.onClick', {
|
|
101
106
|
default: 'onClick'
|
|
102
107
|
});
|
|
108
|
+
const onClickShortcut = events[onClickActionName]?.shortcut;
|
|
103
109
|
const dropdownProps = {
|
|
104
110
|
menu: {
|
|
105
111
|
items,
|
|
@@ -162,7 +168,9 @@ function DropdownButtonBlock({ blockId, classNames = {}, components: { Icon, Sho
|
|
|
162
168
|
onClick: ()=>methods.triggerEvent({
|
|
163
169
|
name: onClickActionName
|
|
164
170
|
})
|
|
165
|
-
}, properties.title
|
|
171
|
+
}, properties.title, onClickShortcut && /*#__PURE__*/ React.createElement(ShortcutBadge, {
|
|
172
|
+
shortcut: onClickShortcut
|
|
173
|
+
})), /*#__PURE__*/ React.createElement(Dropdown, dropdownProps, /*#__PURE__*/ React.createElement(Button, {
|
|
166
174
|
color: resolvedColor,
|
|
167
175
|
variant: variant,
|
|
168
176
|
type: buttonType,
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
arrow: 'Dropdown arrow indicator.'
|
|
27
27
|
},
|
|
28
28
|
events: {
|
|
29
|
-
onClick: 'Trigger action when the button is clicked (split mode).',
|
|
29
|
+
onClick: 'Trigger action when the button is clicked (split mode). Renders a shortcut badge when a shortcut is configured on the event.',
|
|
30
30
|
onOpenChange: 'Trigger action when dropdown opens or closes.'
|
|
31
31
|
},
|
|
32
32
|
properties: {
|
|
@@ -162,7 +162,7 @@
|
|
|
162
162
|
},
|
|
163
163
|
items: {
|
|
164
164
|
type: 'array',
|
|
165
|
-
description: 'Menu items. Each with an eventName that triggers a named event.',
|
|
165
|
+
description: 'Menu items. Each with an eventName that triggers a named event. Keyboard shortcuts can be configured via the standard `events.<eventName>.shortcut` schema (preferred) or via the item-level `shortcut` property — both render a badge next to the item label. The event-level shortcut takes precedence when both are set.',
|
|
166
166
|
items: {
|
|
167
167
|
type: 'object',
|
|
168
168
|
properties: {
|
|
@@ -201,7 +201,7 @@
|
|
|
201
201
|
},
|
|
202
202
|
shortcut: {
|
|
203
203
|
type: 'string',
|
|
204
|
-
description: 'Keyboard shortcut. Binds the key and renders the badge.'
|
|
204
|
+
description: 'Keyboard shortcut. Binds the key and renders the badge. Prefer configuring this via `events.<eventName>.shortcut` to follow the standard Lowdefy event schema — the event-level shortcut takes precedence when both are set.'
|
|
205
205
|
}
|
|
206
206
|
}
|
|
207
207
|
}
|
|
@@ -126,7 +126,11 @@ const PageSidebarLayout = ({ basePath, blockId, classNames = {}, components: { I
|
|
|
126
126
|
styles: {
|
|
127
127
|
element: mergeObjects([
|
|
128
128
|
{
|
|
129
|
-
borderInlineEnd: '1px solid var(--ant-color-border)'
|
|
129
|
+
borderInlineEnd: '1px solid var(--ant-color-border)',
|
|
130
|
+
position: 'sticky',
|
|
131
|
+
top: 0,
|
|
132
|
+
height: '100vh',
|
|
133
|
+
alignSelf: 'flex-start'
|
|
130
134
|
},
|
|
131
135
|
styles.sider
|
|
132
136
|
])
|
|
@@ -231,17 +235,18 @@ const PageSidebarLayout = ({ basePath, blockId, classNames = {}, components: { I
|
|
|
231
235
|
style: {
|
|
232
236
|
position: 'sticky',
|
|
233
237
|
bottom: 0,
|
|
234
|
-
background: 'var(--ant-color-bg-container)',
|
|
235
|
-
padding:
|
|
238
|
+
background: 'linear-gradient(to bottom, transparent 0%, color-mix(in srgb, var(--ant-color-bg-container) 85%, transparent) 32px, color-mix(in srgb, var(--ant-color-bg-container) 95%, transparent) 100%)',
|
|
239
|
+
padding: '40px 8px 8px',
|
|
236
240
|
display: 'flex',
|
|
237
241
|
flexDirection: 'column',
|
|
238
|
-
alignItems: 'center'
|
|
242
|
+
alignItems: 'center',
|
|
243
|
+
gap: 8
|
|
239
244
|
}
|
|
240
245
|
}, renderHeaderActions({
|
|
241
246
|
blockId,
|
|
242
247
|
classNames: {
|
|
243
248
|
...classNames,
|
|
244
|
-
headerActions: classNames.headerActions ?? 'flex flex-col items-center gap-4 py-4'
|
|
249
|
+
headerActions: classNames.headerActions ?? (openSiderState ? 'flex flex-col items-stretch gap-1 w-full' : 'flex flex-col items-center gap-4 py-4')
|
|
245
250
|
},
|
|
246
251
|
styles,
|
|
247
252
|
properties,
|
|
@@ -252,7 +257,8 @@ const PageSidebarLayout = ({ basePath, blockId, classNames = {}, components: { I
|
|
|
252
257
|
Link,
|
|
253
258
|
ShortcutBadge
|
|
254
259
|
},
|
|
255
|
-
iconsColor: properties.iconsColor
|
|
260
|
+
iconsColor: properties.iconsColor,
|
|
261
|
+
expanded: openSiderState
|
|
256
262
|
}), /*#__PURE__*/ React.createElement(Link, {
|
|
257
263
|
home: true
|
|
258
264
|
}, /*#__PURE__*/ React.createElement("img", {
|
|
@@ -255,6 +255,11 @@ export default {
|
|
|
255
255
|
description: 'Notification bell icon with badge. Shown in the sider on desktop and the mobile header on small screens. Renders when configured. Use the link property to navigate when clicked.',
|
|
256
256
|
additionalProperties: false,
|
|
257
257
|
properties: {
|
|
258
|
+
title: {
|
|
259
|
+
type: 'string',
|
|
260
|
+
default: 'Notifications',
|
|
261
|
+
description: 'Label shown next to the bell icon when the sider is expanded. Hidden on mobile header and collapsed sider.'
|
|
262
|
+
},
|
|
258
263
|
link: {
|
|
259
264
|
type: 'object',
|
|
260
265
|
description: 'Link to navigate to when the notification bell is clicked.',
|
|
@@ -321,6 +326,11 @@ export default {
|
|
|
321
326
|
description: 'Profile avatar with optional dropdown menu. Shown in the sider on desktop and the mobile header on small screens. Renders when configured. Use with the _user operator to populate from the authenticated user.',
|
|
322
327
|
additionalProperties: false,
|
|
323
328
|
properties: {
|
|
329
|
+
title: {
|
|
330
|
+
type: 'string',
|
|
331
|
+
default: 'Profile',
|
|
332
|
+
description: 'Label shown next to the avatar when the sider is expanded. Hidden on mobile header and collapsed sider.'
|
|
333
|
+
},
|
|
324
334
|
avatar: {
|
|
325
335
|
type: 'object',
|
|
326
336
|
description: 'Avatar display properties.',
|
|
@@ -28,7 +28,73 @@ function getDarkModeIcon() {
|
|
|
28
28
|
if (pref === 'light') return 'AiOutlineSun';
|
|
29
29
|
return 'AiOutlineLaptop';
|
|
30
30
|
}
|
|
31
|
-
function
|
|
31
|
+
function getDarkModeLabel() {
|
|
32
|
+
const pref = getDarkModePreference();
|
|
33
|
+
if (pref === 'dark') return 'Dark mode';
|
|
34
|
+
if (pref === 'light') return 'Light mode';
|
|
35
|
+
return 'System';
|
|
36
|
+
}
|
|
37
|
+
// Wraps a header action row for the expanded sider. Icon cell has a fixed
|
|
38
|
+
// basis so bell / avatar / sun share a vertical line regardless of their
|
|
39
|
+
// own intrinsic size; label fills the remaining width. Row gets a subtle
|
|
40
|
+
// hover background so it reads as interactive (matches menu items above).
|
|
41
|
+
const EXPANDED_ROW_BASE = {
|
|
42
|
+
display: 'flex',
|
|
43
|
+
alignItems: 'center',
|
|
44
|
+
gap: 12,
|
|
45
|
+
padding: '8px 12px',
|
|
46
|
+
width: '100%',
|
|
47
|
+
borderRadius: 6,
|
|
48
|
+
transition: 'background 0.15s'
|
|
49
|
+
};
|
|
50
|
+
const EXPANDED_ROW_BUTTON_RESET = {
|
|
51
|
+
background: 'transparent',
|
|
52
|
+
border: 'none',
|
|
53
|
+
textAlign: 'left',
|
|
54
|
+
font: 'inherit',
|
|
55
|
+
color: 'inherit'
|
|
56
|
+
};
|
|
57
|
+
function ExpandedRow({ children, label, className, style, onClick }) {
|
|
58
|
+
// `onClick` is only used when the row stands alone as the click target
|
|
59
|
+
// (e.g., dark-mode toggle). Notifications wraps this in a <Link> and
|
|
60
|
+
// profile wraps it in a <Dropdown> — in those cases interactivity comes
|
|
61
|
+
// from the parent, but the row should still hover-highlight.
|
|
62
|
+
const Tag = onClick ? 'button' : 'div';
|
|
63
|
+
const [hover, setHover] = React.useState(false);
|
|
64
|
+
const rowStyle = {
|
|
65
|
+
...EXPANDED_ROW_BASE,
|
|
66
|
+
cursor: 'pointer',
|
|
67
|
+
...onClick ? EXPANDED_ROW_BUTTON_RESET : null,
|
|
68
|
+
...hover ? {
|
|
69
|
+
background: 'color-mix(in srgb, var(--ant-color-text) 6%, transparent)'
|
|
70
|
+
} : null,
|
|
71
|
+
...style
|
|
72
|
+
};
|
|
73
|
+
return /*#__PURE__*/ React.createElement(Tag, {
|
|
74
|
+
type: onClick ? 'button' : undefined,
|
|
75
|
+
className: className,
|
|
76
|
+
style: rowStyle,
|
|
77
|
+
onClick: onClick,
|
|
78
|
+
onMouseEnter: ()=>setHover(true),
|
|
79
|
+
onMouseLeave: ()=>setHover(false)
|
|
80
|
+
}, /*#__PURE__*/ React.createElement("span", {
|
|
81
|
+
style: {
|
|
82
|
+
display: 'inline-flex',
|
|
83
|
+
alignItems: 'center',
|
|
84
|
+
justifyContent: 'center',
|
|
85
|
+
flex: '0 0 24px',
|
|
86
|
+
lineHeight: 1
|
|
87
|
+
}
|
|
88
|
+
}, children), /*#__PURE__*/ React.createElement("span", {
|
|
89
|
+
style: {
|
|
90
|
+
flex: 1,
|
|
91
|
+
minWidth: 0,
|
|
92
|
+
overflow: 'hidden',
|
|
93
|
+
textOverflow: 'ellipsis'
|
|
94
|
+
}
|
|
95
|
+
}, label));
|
|
96
|
+
}
|
|
97
|
+
function renderNotifications({ blockId, classNames, styles, properties, events, Icon, Link, iconsColor, expanded }) {
|
|
32
98
|
if (type.isNone(properties.notifications)) return null;
|
|
33
99
|
const notif = properties.notifications;
|
|
34
100
|
const badge = /*#__PURE__*/ React.createElement(Badge, {
|
|
@@ -55,6 +121,26 @@ function renderNotifications({ blockId, classNames, styles, properties, events,
|
|
|
55
121
|
}
|
|
56
122
|
}));
|
|
57
123
|
const link = notif.link;
|
|
124
|
+
if (expanded) {
|
|
125
|
+
const row = /*#__PURE__*/ React.createElement(ExpandedRow, {
|
|
126
|
+
className: classNames.notifications,
|
|
127
|
+
style: styles.notifications,
|
|
128
|
+
label: notif.title ?? 'Notifications'
|
|
129
|
+
}, badge);
|
|
130
|
+
if (link) {
|
|
131
|
+
return /*#__PURE__*/ React.createElement(Link, {
|
|
132
|
+
id: `${blockId}_notifications_link`,
|
|
133
|
+
pageId: link.pageId,
|
|
134
|
+
url: link.url,
|
|
135
|
+
newTab: link.newTab,
|
|
136
|
+
style: {
|
|
137
|
+
display: 'block',
|
|
138
|
+
color: 'inherit'
|
|
139
|
+
}
|
|
140
|
+
}, row);
|
|
141
|
+
}
|
|
142
|
+
return row;
|
|
143
|
+
}
|
|
58
144
|
if (link) {
|
|
59
145
|
return /*#__PURE__*/ React.createElement(Link, {
|
|
60
146
|
id: `${blockId}_notifications_link`,
|
|
@@ -76,7 +162,7 @@ function renderNotifications({ blockId, classNames, styles, properties, events,
|
|
|
76
162
|
}
|
|
77
163
|
}, badge);
|
|
78
164
|
}
|
|
79
|
-
function renderProfile({ blockId, classNames, styles, properties, methods, events, Icon, Link, ShortcutBadge }) {
|
|
165
|
+
function renderProfile({ blockId, classNames, styles, properties, methods, events, Icon, Link, ShortcutBadge, expanded }) {
|
|
80
166
|
if (type.isNone(properties.profile)) return null;
|
|
81
167
|
const prof = properties.profile;
|
|
82
168
|
const avatarProps = prof.avatar ?? {};
|
|
@@ -99,12 +185,17 @@ function renderProfile({ blockId, classNames, styles, properties, methods, event
|
|
|
99
185
|
}
|
|
100
186
|
})
|
|
101
187
|
}, avatarProps.content);
|
|
188
|
+
const trigger = expanded ? /*#__PURE__*/ React.createElement(ExpandedRow, {
|
|
189
|
+
className: classNames.profile,
|
|
190
|
+
style: styles.profile,
|
|
191
|
+
label: prof.title ?? 'Profile'
|
|
192
|
+
}, avatar) : /*#__PURE__*/ React.createElement("div", {
|
|
193
|
+
className: classNames.profile,
|
|
194
|
+
style: styles.profile
|
|
195
|
+
}, avatar);
|
|
102
196
|
const links = prof.links ?? [];
|
|
103
197
|
if (links.length === 0) {
|
|
104
|
-
return
|
|
105
|
-
className: classNames.profile,
|
|
106
|
-
style: styles.profile
|
|
107
|
-
}, avatar);
|
|
198
|
+
return trigger;
|
|
108
199
|
}
|
|
109
200
|
const items = buildMenuItems({
|
|
110
201
|
links,
|
|
@@ -119,10 +210,8 @@ function renderProfile({ blockId, classNames, styles, properties, methods, event
|
|
|
119
210
|
});
|
|
120
211
|
const linkMap = flattenLinks(links);
|
|
121
212
|
return /*#__PURE__*/ React.createElement(Dropdown, {
|
|
122
|
-
className: classNames.profile,
|
|
123
213
|
style: {
|
|
124
|
-
cursor: 'pointer'
|
|
125
|
-
...styles.profile
|
|
214
|
+
cursor: 'pointer'
|
|
126
215
|
},
|
|
127
216
|
menu: {
|
|
128
217
|
items,
|
|
@@ -139,10 +228,11 @@ function renderProfile({ blockId, classNames, styles, properties, methods, event
|
|
|
139
228
|
});
|
|
140
229
|
}
|
|
141
230
|
},
|
|
231
|
+
// Row-style trigger (expanded) expects click; small avatar (collapsed) uses hover.
|
|
142
232
|
trigger: [
|
|
143
|
-
prof.trigger ?? 'hover'
|
|
233
|
+
prof.trigger ?? (expanded ? 'click' : 'hover')
|
|
144
234
|
],
|
|
145
|
-
placement: prof.placement ?? 'bottomRight',
|
|
235
|
+
placement: prof.placement ?? (expanded ? 'topRight' : 'bottomRight'),
|
|
146
236
|
arrow: prof.arrow,
|
|
147
237
|
popupClassName: classNames.profileMenu,
|
|
148
238
|
popupStyle: styles.profileMenu,
|
|
@@ -152,20 +242,10 @@ function renderProfile({ blockId, classNames, styles, properties, methods, event
|
|
|
152
242
|
open
|
|
153
243
|
}
|
|
154
244
|
})
|
|
155
|
-
}, /*#__PURE__*/ React.createElement("div", null,
|
|
245
|
+
}, /*#__PURE__*/ React.createElement("div", null, trigger));
|
|
156
246
|
}
|
|
157
|
-
function renderDarkModeToggle({ blockId, classNames, styles, methods, events, Icon, iconsColor }) {
|
|
158
|
-
|
|
159
|
-
className: classNames.darkModeToggle,
|
|
160
|
-
style: {
|
|
161
|
-
cursor: 'pointer',
|
|
162
|
-
lineHeight: 1,
|
|
163
|
-
...styles.darkModeToggle
|
|
164
|
-
},
|
|
165
|
-
onClick: ()=>methods.triggerEvent({
|
|
166
|
-
name: '__toggleDarkMode'
|
|
167
|
-
})
|
|
168
|
-
}, /*#__PURE__*/ React.createElement(Icon, {
|
|
247
|
+
function renderDarkModeToggle({ blockId, classNames, styles, methods, events, Icon, iconsColor, expanded }) {
|
|
248
|
+
const icon = /*#__PURE__*/ React.createElement(Icon, {
|
|
169
249
|
blockId: `${blockId}_dark_mode_toggle_icon`,
|
|
170
250
|
events: events,
|
|
171
251
|
properties: {
|
|
@@ -177,9 +257,30 @@ function renderDarkModeToggle({ blockId, classNames, styles, methods, events, Ic
|
|
|
177
257
|
color: iconsColor
|
|
178
258
|
}
|
|
179
259
|
}
|
|
180
|
-
})
|
|
260
|
+
});
|
|
261
|
+
if (expanded) {
|
|
262
|
+
return /*#__PURE__*/ React.createElement(ExpandedRow, {
|
|
263
|
+
className: classNames.darkModeToggle,
|
|
264
|
+
style: styles.darkModeToggle,
|
|
265
|
+
label: getDarkModeLabel(),
|
|
266
|
+
onClick: ()=>methods.triggerEvent({
|
|
267
|
+
name: '__toggleDarkMode'
|
|
268
|
+
})
|
|
269
|
+
}, icon);
|
|
270
|
+
}
|
|
271
|
+
return /*#__PURE__*/ React.createElement("div", {
|
|
272
|
+
className: classNames.darkModeToggle,
|
|
273
|
+
style: {
|
|
274
|
+
cursor: 'pointer',
|
|
275
|
+
lineHeight: 1,
|
|
276
|
+
...styles.darkModeToggle
|
|
277
|
+
},
|
|
278
|
+
onClick: ()=>methods.triggerEvent({
|
|
279
|
+
name: '__toggleDarkMode'
|
|
280
|
+
})
|
|
281
|
+
}, icon);
|
|
181
282
|
}
|
|
182
|
-
function renderHeaderActions({ blockId, classNames = {}, styles = {}, properties, methods, events, components: { Icon, Link, ShortcutBadge }, iconsColor }) {
|
|
283
|
+
function renderHeaderActions({ blockId, classNames = {}, styles = {}, properties, methods, events, components: { Icon, Link, ShortcutBadge }, iconsColor, expanded = false }) {
|
|
183
284
|
const hasNotifications = !type.isNone(properties.notifications);
|
|
184
285
|
const hasProfile = !type.isNone(properties.profile);
|
|
185
286
|
const hasDarkMode = properties.darkModeToggle;
|
|
@@ -194,10 +295,12 @@ function renderHeaderActions({ blockId, classNames = {}, styles = {}, properties
|
|
|
194
295
|
Icon,
|
|
195
296
|
Link,
|
|
196
297
|
ShortcutBadge,
|
|
197
|
-
iconsColor
|
|
298
|
+
iconsColor,
|
|
299
|
+
expanded
|
|
198
300
|
};
|
|
301
|
+
const defaultClassName = expanded ? 'flex flex-col items-stretch gap-1 w-full' : 'flex items-center gap-4 ml-4';
|
|
199
302
|
return /*#__PURE__*/ React.createElement("div", {
|
|
200
|
-
className: classNames.headerActions ??
|
|
303
|
+
className: classNames.headerActions ?? defaultClassName,
|
|
201
304
|
style: styles.headerActions
|
|
202
305
|
}, hasNotifications && renderNotifications(ctx), hasProfile && renderProfile(ctx), hasDarkMode && renderDarkModeToggle(ctx));
|
|
203
306
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lowdefy/blocks-antd",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.2.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "Lowdefy Ant Design Blocks",
|
|
6
6
|
"homepage": "https://lowdefy.com",
|
|
@@ -45,8 +45,8 @@
|
|
|
45
45
|
],
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"@ant-design/icons": "6.1.0",
|
|
48
|
-
"@lowdefy/block-utils": "5.
|
|
49
|
-
"@lowdefy/helpers": "5.
|
|
48
|
+
"@lowdefy/block-utils": "5.2.0",
|
|
49
|
+
"@lowdefy/helpers": "5.2.0",
|
|
50
50
|
"@rc-component/motion": "1.3.1",
|
|
51
51
|
"classnames": "2.3.2",
|
|
52
52
|
"dayjs": "1.11.19",
|
|
@@ -58,9 +58,9 @@
|
|
|
58
58
|
"react-dom": ">=18"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
|
-
"@lowdefy/block-dev-e2e": "5.
|
|
62
|
-
"@lowdefy/e2e-utils": "5.
|
|
63
|
-
"@lowdefy/node-utils": "5.
|
|
61
|
+
"@lowdefy/block-dev-e2e": "5.2.0",
|
|
62
|
+
"@lowdefy/e2e-utils": "5.2.0",
|
|
63
|
+
"@lowdefy/node-utils": "5.2.0",
|
|
64
64
|
"@playwright/test": "1.50.1",
|
|
65
65
|
"@swc/cli": "0.8.0",
|
|
66
66
|
"@swc/core": "1.15.18",
|