@lowdefy/blocks-antd 5.0.0 → 5.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/dist/blocks/AutoComplete/AutoComplete.js +6 -0
- package/dist/blocks/AutoComplete/meta.js +1 -0
- package/dist/blocks/Calendar/Calendar.js +60 -18
- package/dist/blocks/Calendar/meta.js +1 -1
- package/dist/blocks/Drawer/Drawer.js +2 -0
- package/dist/blocks/Drawer/meta.js +2 -1
- package/dist/blocks/Menu/Menu.js +6 -3
- package/dist/blocks/MobileMenu/MobileMenu.js +16 -3
- package/dist/blocks/MobileMenu/meta.js +32 -1
- package/dist/blocks/MultipleSelector/MultipleSelector.js +9 -2
- package/dist/blocks/MultipleSelector/meta.js +1 -0
- package/dist/blocks/PageSidebarLayout/PageSidebarLayout.js +511 -0
- package/dist/blocks/PageSidebarLayout/e2e.js +34 -0
- package/dist/blocks/PageSidebarLayout/meta.js +516 -0
- package/dist/blocks/PageSiderMenu/PageSiderMenu.js +39 -6
- package/dist/blocks/PageSiderMenu/meta.js +10 -0
- package/dist/blocks/Selector/Selector.js +6 -0
- package/dist/blocks/Selector/meta.js +1 -0
- package/dist/blocks/Sider/Sider.js +10 -0
- package/dist/blocks.js +1 -0
- package/dist/metas.js +1 -0
- package/package.json +7 -7
|
@@ -40,10 +40,16 @@ const AutoCompleteInput = ({ blockId, classNames = {}, components, events, loadi
|
|
|
40
40
|
backfill: properties.backfill,
|
|
41
41
|
variant: properties.bordered === false ? 'borderless' : properties.variant,
|
|
42
42
|
className: classNames.element,
|
|
43
|
+
classNames: {
|
|
44
|
+
content: classNames.selector
|
|
45
|
+
},
|
|
43
46
|
style: {
|
|
44
47
|
width: '100%',
|
|
45
48
|
...styles.element
|
|
46
49
|
},
|
|
50
|
+
styles: {
|
|
51
|
+
content: styles.selector
|
|
52
|
+
},
|
|
47
53
|
defaultOpen: properties.defaultOpen,
|
|
48
54
|
disabled: properties.disabled || loading,
|
|
49
55
|
placeholder: properties.placeholder ?? 'Type or select item',
|
|
@@ -23,6 +23,7 @@ export default {
|
|
|
23
23
|
valueType: 'string',
|
|
24
24
|
cssKeys: {
|
|
25
25
|
element: 'The AutoComplete element.',
|
|
26
|
+
selector: 'The inner value container of the AutoComplete (antd `content` semantic slot).',
|
|
26
27
|
label: 'The AutoComplete label.',
|
|
27
28
|
extra: 'The AutoComplete extra content.',
|
|
28
29
|
feedback: 'The AutoComplete validation feedback.',
|
|
@@ -22,21 +22,58 @@ import withTheme from '../withTheme.js';
|
|
|
22
22
|
import disabledDate from '../../disabledDate.js';
|
|
23
23
|
dayjs.extend(utc);
|
|
24
24
|
function buildDateMap(dateCellData) {
|
|
25
|
-
if (!type.isArray(dateCellData)) return {
|
|
25
|
+
if (!type.isArray(dateCellData)) return {
|
|
26
|
+
map: {},
|
|
27
|
+
earliest: undefined
|
|
28
|
+
};
|
|
26
29
|
const map = {};
|
|
30
|
+
let earliest;
|
|
27
31
|
dateCellData.forEach((item)=>{
|
|
28
32
|
if (type.isNone(item?.date)) return;
|
|
29
|
-
const
|
|
33
|
+
const parsed = dayjs(item.date);
|
|
34
|
+
if (!parsed.isValid()) return;
|
|
35
|
+
const key = parsed.format('YYYY-MM-DD');
|
|
30
36
|
if (!map[key]) map[key] = [];
|
|
31
37
|
map[key].push(item);
|
|
38
|
+
if (!earliest || parsed.isBefore(earliest)) earliest = parsed;
|
|
32
39
|
});
|
|
33
|
-
return
|
|
40
|
+
return {
|
|
41
|
+
map,
|
|
42
|
+
earliest
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
// Pick a default month to open on when `value` is unset: earliest event date
|
|
46
|
+
// from dateCellData, or the earliest specific disabled date, or the min of a
|
|
47
|
+
// disabledDates range. Without this, a calendar whose data lives in a past or
|
|
48
|
+
// future month opens on "today" and shows nothing, confusing the user.
|
|
49
|
+
function pickDefaultValue({ earliestCellData, disabledDates }) {
|
|
50
|
+
if (earliestCellData) return earliestCellData;
|
|
51
|
+
if (type.isObject(disabledDates)) {
|
|
52
|
+
if (type.isArray(disabledDates.dates) && disabledDates.dates.length > 0) {
|
|
53
|
+
let earliest;
|
|
54
|
+
disabledDates.dates.forEach((d)=>{
|
|
55
|
+
const parsed = dayjs(d);
|
|
56
|
+
if (parsed.isValid() && (!earliest || parsed.isBefore(earliest))) earliest = parsed;
|
|
57
|
+
});
|
|
58
|
+
if (earliest) return earliest;
|
|
59
|
+
}
|
|
60
|
+
if (!type.isNone(disabledDates.min)) {
|
|
61
|
+
const parsed = dayjs(disabledDates.min);
|
|
62
|
+
if (parsed.isValid()) return parsed;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return undefined;
|
|
34
66
|
}
|
|
35
67
|
const CalendarBlock = ({ blockId, classNames = {}, events, methods, properties, styles = {}, value })=>{
|
|
36
|
-
const dateMap = buildDateMap(properties.dateCellData);
|
|
68
|
+
const { map: dateMap, earliest: earliestCellData } = buildDateMap(properties.dateCellData);
|
|
37
69
|
const hasDateData = Object.keys(dateMap).length > 0;
|
|
38
|
-
|
|
39
|
-
|
|
70
|
+
const defaultPanel = pickDefaultValue({
|
|
71
|
+
earliestCellData,
|
|
72
|
+
disabledDates: properties.disabledDates
|
|
73
|
+
});
|
|
74
|
+
return /*#__PURE__*/ React.createElement("div", {
|
|
75
|
+
id: blockId
|
|
76
|
+
}, /*#__PURE__*/ React.createElement(Calendar, {
|
|
40
77
|
className: classNames.element,
|
|
41
78
|
style: styles.element,
|
|
42
79
|
fullscreen: properties.fullscreen !== false,
|
|
@@ -47,21 +84,24 @@ const CalendarBlock = ({ blockId, classNames = {}, events, methods, properties,
|
|
|
47
84
|
dayjs(properties.validRange[1])
|
|
48
85
|
] : undefined,
|
|
49
86
|
value: type.isDate(value) ? dayjs(value) : undefined,
|
|
87
|
+
defaultValue: !type.isDate(value) ? defaultPanel : undefined,
|
|
50
88
|
onSelect: (date, selectInfo)=>{
|
|
51
89
|
// Wrap with our dayjs — antd v6's internal dayjs may lack the utc plugin.
|
|
52
90
|
const d = dayjs(date);
|
|
53
91
|
const val = d.toDate();
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
92
|
+
const source = selectInfo?.source ?? 'date';
|
|
93
|
+
// Only fire for date cell clicks — year/month panel navigation emits
|
|
94
|
+
// onSelect too but shouldn't push a value through the event chain.
|
|
95
|
+
if (source !== 'date' && source !== 'customize') return;
|
|
96
|
+
methods.setValue(val);
|
|
97
|
+
methods.triggerEvent({
|
|
98
|
+
name: 'onSelect',
|
|
99
|
+
event: {
|
|
100
|
+
value: val,
|
|
101
|
+
date: d.format('YYYY-MM-DD'),
|
|
102
|
+
source
|
|
103
|
+
}
|
|
104
|
+
});
|
|
65
105
|
},
|
|
66
106
|
onChange: (date)=>{
|
|
67
107
|
const d = dayjs(date);
|
|
@@ -90,6 +130,8 @@ const CalendarBlock = ({ blockId, classNames = {}, events, methods, properties,
|
|
|
90
130
|
if (info.type !== 'date') return info.originNode;
|
|
91
131
|
const key = dayjs(current).format('YYYY-MM-DD');
|
|
92
132
|
const items = dateMap[key];
|
|
133
|
+
// cellRender output is appended to the default date cell — return
|
|
134
|
+
// null for days with no events to avoid double-rendering the date.
|
|
93
135
|
if (!items) return null;
|
|
94
136
|
return /*#__PURE__*/ React.createElement("ul", {
|
|
95
137
|
className: "ant-picker-calendar-events",
|
|
@@ -106,6 +148,6 @@ const CalendarBlock = ({ blockId, classNames = {}, events, methods, properties,
|
|
|
106
148
|
text: item.content
|
|
107
149
|
}))));
|
|
108
150
|
} : undefined
|
|
109
|
-
});
|
|
151
|
+
}));
|
|
110
152
|
};
|
|
111
153
|
export default withTheme('Calendar', withBlockDefaults(CalendarBlock));
|
|
@@ -112,6 +112,7 @@ const DrawerBlock = ({ blockId, classNames = {}, content, properties, methods, r
|
|
|
112
112
|
id: blockId,
|
|
113
113
|
closable: properties.closable,
|
|
114
114
|
extra: content.extra && content.extra(),
|
|
115
|
+
footer: content.footer && content.footer(),
|
|
115
116
|
getContainer: properties.getContainer,
|
|
116
117
|
mask: properties.mask,
|
|
117
118
|
maskClosable: properties.maskClosable,
|
|
@@ -145,6 +146,7 @@ const DrawerBlock = ({ blockId, classNames = {}, content, properties, methods, r
|
|
|
145
146
|
styles: {
|
|
146
147
|
header: styles.header,
|
|
147
148
|
body: styles.body,
|
|
149
|
+
footer: styles.footer,
|
|
148
150
|
mask: styles.mask,
|
|
149
151
|
wrapper: styles.wrapper,
|
|
150
152
|
content: styles.content
|
package/dist/blocks/Menu/Menu.js
CHANGED
|
@@ -12,9 +12,10 @@
|
|
|
12
12
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
|
-
*/ import React, { useCallback } from 'react';
|
|
16
|
-
import { Menu } from 'antd';
|
|
15
|
+
*/ import React, { useCallback, useContext } from 'react';
|
|
16
|
+
import { Layout, Menu } from 'antd';
|
|
17
17
|
import { type, get } from '@lowdefy/helpers';
|
|
18
|
+
const SiderContext = Layout._InternalSiderContext;
|
|
18
19
|
import { withBlockDefaults } from '@lowdefy/block-utils';
|
|
19
20
|
import withTheme from '../withTheme.js';
|
|
20
21
|
import useItemShortcuts from '../useItemShortcuts.js';
|
|
@@ -133,6 +134,8 @@ function MenuComp({ blockId, classNames = {}, components: { Icon, Link, Shortcut
|
|
|
133
134
|
}
|
|
134
135
|
const menu = getDefaultMenu(menus, properties.menuId, properties.links);
|
|
135
136
|
const theme = properties.theme;
|
|
137
|
+
const { siderCollapsed } = useContext(SiderContext) ?? {};
|
|
138
|
+
const isCollapsed = properties.collapsed === true || siderCollapsed === true;
|
|
136
139
|
const items = buildMenuItems({
|
|
137
140
|
links: menu,
|
|
138
141
|
events,
|
|
@@ -185,7 +188,7 @@ function MenuComp({ blockId, classNames = {}, components: { Icon, Link, Shortcut
|
|
|
185
188
|
mode: properties.mode,
|
|
186
189
|
selectable: true,
|
|
187
190
|
theme: theme,
|
|
188
|
-
defaultOpenKeys: properties.defaultOpenKeys ?? (properties.mode === 'inline' &&
|
|
191
|
+
defaultOpenKeys: properties.defaultOpenKeys ?? (properties.mode === 'inline' && !isCollapsed && [
|
|
189
192
|
(menu.find((link)=>(link.links || []).map((subLink)=>subLink.links ? subLink.links.map((subSubLink)=>subSubLink.pageId) : [
|
|
190
193
|
subLink.pageId
|
|
191
194
|
]).flat().some((link)=>(properties.selectedKeys ?? [
|
|
@@ -18,7 +18,8 @@ import { withBlockDefaults } from '@lowdefy/block-utils';
|
|
|
18
18
|
import Button from '../Button/Button.js';
|
|
19
19
|
import Drawer from '../Drawer/Drawer.js';
|
|
20
20
|
import Menu from '../Menu/Menu.js';
|
|
21
|
-
|
|
21
|
+
import { getDarkMode } from '../headerActions.js';
|
|
22
|
+
const MobileMenu = ({ basePath, blockId, classNames = {}, components, content, events, methods, menus, pageId, properties, rename, styles = {} })=>{
|
|
22
23
|
const [openState, setOpen] = useState(false);
|
|
23
24
|
useEffect(()=>{
|
|
24
25
|
methods.registerMethod(get(rename, 'methods.toggleOpen', {
|
|
@@ -88,7 +89,18 @@ const MobileMenu = ({ basePath, blockId, classNames = {}, components, events, me
|
|
|
88
89
|
default: 'toggleOpen'
|
|
89
90
|
})](),
|
|
90
91
|
content: {
|
|
91
|
-
|
|
92
|
+
extra: properties.logo ? ()=>/*#__PURE__*/ React.createElement("div", {
|
|
93
|
+
style: {
|
|
94
|
+
flex: '1 0 auto'
|
|
95
|
+
}
|
|
96
|
+
}, /*#__PURE__*/ React.createElement(components.Link, {
|
|
97
|
+
home: true
|
|
98
|
+
}, /*#__PURE__*/ React.createElement("img", {
|
|
99
|
+
src: properties.logo?.srcMobile ?? properties.logo?.src ?? `${basePath}/logo-square-${getDarkMode() ? 'dark' : 'light'}-theme.png`,
|
|
100
|
+
alt: properties.logo?.alt ?? 'Lowdefy',
|
|
101
|
+
style: properties.logo?.style
|
|
102
|
+
}))) : undefined,
|
|
103
|
+
content: ()=>/*#__PURE__*/ React.createElement(React.Fragment, null, /*#__PURE__*/ React.createElement(Menu, {
|
|
92
104
|
basePath: basePath,
|
|
93
105
|
components: components,
|
|
94
106
|
blockId: `${blockId}_menu`,
|
|
@@ -113,7 +125,8 @@ const MobileMenu = ({ basePath, blockId, classNames = {}, components, events, me
|
|
|
113
125
|
onSelect: 'onMenuItemSelect'
|
|
114
126
|
}
|
|
115
127
|
}
|
|
116
|
-
})
|
|
128
|
+
}), content?.drawerContent && content.drawerContent()),
|
|
129
|
+
footer: content?.drawerFooter ? ()=>content.drawerFooter() : undefined
|
|
117
130
|
}
|
|
118
131
|
}));
|
|
119
132
|
};
|
|
@@ -13,12 +13,16 @@
|
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ export default {
|
|
16
|
-
category: '
|
|
16
|
+
category: 'container',
|
|
17
17
|
icons: [
|
|
18
18
|
'AiOutlineMenuUnfold',
|
|
19
19
|
'AiOutlineMenuFold'
|
|
20
20
|
],
|
|
21
21
|
valueType: null,
|
|
22
|
+
slots: {
|
|
23
|
+
drawerContent: 'Additional content below the menu in the drawer.',
|
|
24
|
+
drawerFooter: 'Footer content in the drawer.'
|
|
25
|
+
},
|
|
22
26
|
cssKeys: {
|
|
23
27
|
element: 'The MobileMenu element.'
|
|
24
28
|
},
|
|
@@ -48,6 +52,33 @@
|
|
|
48
52
|
displayType: 'yaml'
|
|
49
53
|
}
|
|
50
54
|
},
|
|
55
|
+
logo: {
|
|
56
|
+
type: 'object',
|
|
57
|
+
description: 'Logo settings for the mobile menu drawer header.',
|
|
58
|
+
additionalProperties: false,
|
|
59
|
+
properties: {
|
|
60
|
+
src: {
|
|
61
|
+
type: 'string',
|
|
62
|
+
description: 'Logo source url.'
|
|
63
|
+
},
|
|
64
|
+
srcMobile: {
|
|
65
|
+
type: 'string',
|
|
66
|
+
description: 'Mobile logo source url.'
|
|
67
|
+
},
|
|
68
|
+
alt: {
|
|
69
|
+
type: 'string',
|
|
70
|
+
default: 'Lowdefy',
|
|
71
|
+
description: 'Logo alternative text.'
|
|
72
|
+
},
|
|
73
|
+
style: {
|
|
74
|
+
type: 'object',
|
|
75
|
+
description: 'Css style object to apply to logo.',
|
|
76
|
+
docs: {
|
|
77
|
+
displayType: 'yaml'
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
},
|
|
51
82
|
menuId: {
|
|
52
83
|
type: 'string',
|
|
53
84
|
description: 'App menu id used to get menu links.'
|
|
@@ -41,7 +41,7 @@ const tagRender = (props, option, methods, components)=>{
|
|
|
41
41
|
}
|
|
42
42
|
});
|
|
43
43
|
};
|
|
44
|
-
const MultipleSelector = ({ blockId, classNames = {}, components: { Icon }, events, loading, methods, properties, required, styles = {}, validation, value })=>{
|
|
44
|
+
const MultipleSelector = ({ blockId, classNames = {}, components: { Icon, ShortcutBadge }, events, loading, methods, properties, required, styles = {}, validation, value })=>{
|
|
45
45
|
const [fetchState, setFetch] = useState(false);
|
|
46
46
|
const [elementId] = useState((0 | Math.random() * 9e2) + 1e2);
|
|
47
47
|
const uniqueValueOptions = getUniqueValues(properties.options ?? []);
|
|
@@ -73,15 +73,22 @@ const MultipleSelector = ({ blockId, classNames = {}, components: { Icon }, even
|
|
|
73
73
|
autoFocus: properties.autoFocus,
|
|
74
74
|
variant: properties.bordered === false ? 'borderless' : properties.variant,
|
|
75
75
|
className: classNames.element,
|
|
76
|
+
classNames: {
|
|
77
|
+
content: classNames.selector
|
|
78
|
+
},
|
|
76
79
|
style: {
|
|
77
80
|
width: '100%',
|
|
78
81
|
...styles.element
|
|
79
82
|
},
|
|
83
|
+
styles: {
|
|
84
|
+
content: styles.selector
|
|
85
|
+
},
|
|
80
86
|
disabled: properties.disabled || loading,
|
|
81
87
|
getPopupContainer: ()=>document.getElementById(`${blockId}_${elementId}_popup`),
|
|
82
88
|
mode: "multiple",
|
|
83
89
|
tagRender: properties.renderTags && ((props)=>tagRender(props, uniqueValueOptions[props.value], methods, {
|
|
84
|
-
Icon
|
|
90
|
+
Icon,
|
|
91
|
+
ShortcutBadge
|
|
85
92
|
})),
|
|
86
93
|
maxTagCount: properties.maxTagCount,
|
|
87
94
|
notFoundContent: fetchState ? properties.loadingPlaceholder || 'Loading' : properties.notFoundContent || 'Not found',
|
|
@@ -27,6 +27,7 @@ export default {
|
|
|
27
27
|
valueType: 'array',
|
|
28
28
|
cssKeys: {
|
|
29
29
|
element: 'The MultipleSelector element.',
|
|
30
|
+
selector: 'The inner tag/value container of the MultipleSelector (antd `content` semantic slot). Use for capping the tag area height and enabling internal scroll.',
|
|
30
31
|
clearIcon: 'The clear icon in the MultipleSelector.',
|
|
31
32
|
label: 'The MultipleSelector label.',
|
|
32
33
|
extra: 'The MultipleSelector extra content.',
|