@lowdefy/blocks-aggrid 5.4.0 → 5.5.1
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/ag-grid-antd.module.css +10 -0
- package/dist/blocks/AgGridAlpine/meta.js +2 -525
- package/dist/blocks/AgGridBalham/meta.js +2 -525
- package/dist/blocks/AgGridInputAlpine/meta.js +2 -427
- package/dist/blocks/AgGridInputBalham/meta.js +2 -427
- package/dist/blocks/AgGridInputMaterial/meta.js +2 -427
- package/dist/blocks/AgGridMaterial/meta.js +2 -525
- package/dist/cellRenderers/ParagraphInputCell.js +76 -0
- package/dist/cellRenderers/SelectorCell.js +192 -0
- package/dist/cellRenderers/SwitchCell.js +74 -0
- package/dist/cellRenderers/TextInputCell.js +66 -0
- package/dist/cellRenderers/index.js +10 -1
- package/dist/createDisplayMeta.js +736 -0
- package/dist/createInputMeta.js +447 -0
- package/package.json +6 -5
|
@@ -0,0 +1,192 @@
|
|
|
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
|
+
*/ import React, { useMemo } from 'react';
|
|
16
|
+
import { ConfigProvider, Select, Tag } from 'antd';
|
|
17
|
+
import { renderHtml } from '@lowdefy/block-utils';
|
|
18
|
+
import { get, type } from '@lowdefy/helpers';
|
|
19
|
+
import getSelectorOptions from '@lowdefy/blocks-antd/getSelectorOptions.js';
|
|
20
|
+
import getSelectedIndex from '@lowdefy/blocks-antd/getSelectedIndex.js';
|
|
21
|
+
import getContrastTextColor from '@lowdefy/blocks-antd/getContrastTextColor.js';
|
|
22
|
+
import getOptionColorStyle from '@lowdefy/blocks-antd/getOptionColorStyle.js';
|
|
23
|
+
import NullCell from './NullCell.js';
|
|
24
|
+
const Option = Select.Option;
|
|
25
|
+
// Maps an option index (the antd value) back to the real option value, the same way the
|
|
26
|
+
// Selector / MultipleSelector blocks do.
|
|
27
|
+
function indexToValue(options, index) {
|
|
28
|
+
const opt = options[index];
|
|
29
|
+
return type.isPrimitive(opt) ? opt : opt.value;
|
|
30
|
+
}
|
|
31
|
+
// Keep the dropdown open when clicking a tag's close icon.
|
|
32
|
+
function preventMouseDown(e) {
|
|
33
|
+
e.preventDefault();
|
|
34
|
+
e.stopPropagation();
|
|
35
|
+
}
|
|
36
|
+
function SelectorCell(params) {
|
|
37
|
+
const { value, data, cellConfig, methods } = params;
|
|
38
|
+
const multiple = cellConfig?.type === 'multipleSelector';
|
|
39
|
+
// Reuse the block option-normalisation util. Static options only (no per-cell `setData`),
|
|
40
|
+
// so call the pure helper directly rather than the block's `useSelectorOptions` hook.
|
|
41
|
+
const options = useMemo(()=>getSelectorOptions({
|
|
42
|
+
properties: cellConfig ?? {}
|
|
43
|
+
}), [
|
|
44
|
+
cellConfig
|
|
45
|
+
]);
|
|
46
|
+
if (!type.isArray(options) || options.length === 0) return /*#__PURE__*/ React.createElement(NullCell, null);
|
|
47
|
+
// Display grid is one-way: drive the displayed value from the cell value. The chosen value is
|
|
48
|
+
// written back into ag-grid's own row node (not the Lowdefy block value) for immediate feedback
|
|
49
|
+
// that survives re-renders; the app persists via the event chain.
|
|
50
|
+
const selected = getSelectedIndex(value, options, {
|
|
51
|
+
properties: cellConfig,
|
|
52
|
+
multiple
|
|
53
|
+
});
|
|
54
|
+
// Variant handling mirrors the Selector / MultipleSelector blocks: `solid` is not a real antd
|
|
55
|
+
// Select variant — render an outlined frame and (for single-select) fill it via ConfigProvider;
|
|
56
|
+
// `bordered: false` maps to the borderless variant.
|
|
57
|
+
const isSolid = cellConfig.variant === 'solid';
|
|
58
|
+
let antdVariant = cellConfig.variant;
|
|
59
|
+
if (isSolid) antdVariant = 'outlined';
|
|
60
|
+
if (cellConfig.bordered === false) antdVariant = 'borderless';
|
|
61
|
+
const isOutline = antdVariant === 'outlined';
|
|
62
|
+
// Single-select: tint the whole control with the selected option's colour.
|
|
63
|
+
const selectedOption = multiple || type.isNone(selected) ? undefined : options[selected];
|
|
64
|
+
const selectedColor = type.isObject(selectedOption) ? selectedOption.color : undefined;
|
|
65
|
+
let selectTheme;
|
|
66
|
+
if (selectedColor) {
|
|
67
|
+
const token = {
|
|
68
|
+
colorPrimary: selectedColor,
|
|
69
|
+
colorBorder: selectedColor
|
|
70
|
+
};
|
|
71
|
+
if (isSolid) token.colorBgContainer = selectedColor;
|
|
72
|
+
selectTheme = {
|
|
73
|
+
token
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function onChange(index) {
|
|
77
|
+
let newValue;
|
|
78
|
+
if (multiple) {
|
|
79
|
+
newValue = (type.isArray(index) ? index : []).map((i)=>indexToValue(options, i));
|
|
80
|
+
} else {
|
|
81
|
+
newValue = type.isNone(index) ? undefined : indexToValue(options, index);
|
|
82
|
+
}
|
|
83
|
+
const colId = params.column?.getColId?.();
|
|
84
|
+
if (params.node && colId) params.node.setDataValue(colId, newValue);
|
|
85
|
+
if (type.isString(cellConfig.eventName)) {
|
|
86
|
+
methods?.triggerEvent?.({
|
|
87
|
+
name: cellConfig.eventName,
|
|
88
|
+
event: {
|
|
89
|
+
row: data,
|
|
90
|
+
value,
|
|
91
|
+
newValue
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// Colour the selected label (single-select), following the block: solid fill → contrast text.
|
|
97
|
+
function labelRender(labelProps) {
|
|
98
|
+
const opt = options[labelProps.value];
|
|
99
|
+
const color = type.isPrimitive(opt) ? undefined : opt?.color;
|
|
100
|
+
if (type.isNone(color)) return labelProps.label;
|
|
101
|
+
const textColor = isSolid ? getContrastTextColor(color) ?? '#fff' : color;
|
|
102
|
+
return /*#__PURE__*/ React.createElement("span", {
|
|
103
|
+
style: {
|
|
104
|
+
color: textColor
|
|
105
|
+
}
|
|
106
|
+
}, labelProps.label);
|
|
107
|
+
}
|
|
108
|
+
// Colour the selected tags (multi-select), following the block: a hex colour gets an explicit
|
|
109
|
+
// solid/outlined style (dark-mode safe), an antd preset name is handed to antd's Tag `color`.
|
|
110
|
+
function tagRender(tagProps) {
|
|
111
|
+
const { label, value: idx, closable, onClose } = tagProps;
|
|
112
|
+
const opt = options[idx];
|
|
113
|
+
const color = type.isPrimitive(opt) ? undefined : opt?.color;
|
|
114
|
+
const contrast = type.isNone(color) ? undefined : getContrastTextColor(color);
|
|
115
|
+
const colorStyle = contrast ? getOptionColorStyle({
|
|
116
|
+
color,
|
|
117
|
+
isOutline
|
|
118
|
+
}) : {};
|
|
119
|
+
return /*#__PURE__*/ React.createElement(Tag, {
|
|
120
|
+
closable: closable,
|
|
121
|
+
onClose: onClose,
|
|
122
|
+
onMouseDown: preventMouseDown,
|
|
123
|
+
color: contrast || type.isNone(color) ? undefined : color,
|
|
124
|
+
style: {
|
|
125
|
+
marginInlineEnd: 4,
|
|
126
|
+
...colorStyle
|
|
127
|
+
}
|
|
128
|
+
}, label);
|
|
129
|
+
}
|
|
130
|
+
const hasColouredOptions = options.some((opt)=>!type.isPrimitive(opt) && opt.color);
|
|
131
|
+
return(// The wrapper must fill the cell — the antd cell layout is flex, so without an explicit width
|
|
132
|
+
// the Select shrinks to its content instead of spanning the column. Synthetic stopPropagation
|
|
133
|
+
// keeps a stray click from bubbling within React; ag-grid uses native listeners, so a grid that
|
|
134
|
+
// also wires onCellClick / onRowClick may still see selector clicks (same as the buttons cell).
|
|
135
|
+
/*#__PURE__*/ React.createElement("div", {
|
|
136
|
+
style: {
|
|
137
|
+
width: '100%'
|
|
138
|
+
},
|
|
139
|
+
onClick: (e)=>e.stopPropagation()
|
|
140
|
+
}, /*#__PURE__*/ React.createElement(ConfigProvider, {
|
|
141
|
+
theme: selectTheme
|
|
142
|
+
}, /*#__PURE__*/ React.createElement(Select, {
|
|
143
|
+
style: {
|
|
144
|
+
width: '100%',
|
|
145
|
+
minWidth: 'min(150px, 100%)'
|
|
146
|
+
},
|
|
147
|
+
size: cellConfig.size ?? 'small',
|
|
148
|
+
variant: antdVariant,
|
|
149
|
+
mode: multiple ? 'multiple' : undefined,
|
|
150
|
+
value: selected,
|
|
151
|
+
onChange: onChange,
|
|
152
|
+
allowClear: cellConfig.allowClear !== false,
|
|
153
|
+
showSearch: get(cellConfig, 'showSearch', {
|
|
154
|
+
default: true
|
|
155
|
+
}),
|
|
156
|
+
showArrow: cellConfig.showArrow,
|
|
157
|
+
autoFocus: cellConfig.autoFocus,
|
|
158
|
+
maxTagCount: cellConfig.maxTagCount,
|
|
159
|
+
autoClearSearchValue: cellConfig.autoClearSearchValue,
|
|
160
|
+
placeholder: cellConfig.placeholder,
|
|
161
|
+
disabled: cellConfig.disabled === true,
|
|
162
|
+
labelRender: multiple ? undefined : labelRender,
|
|
163
|
+
tagRender: multiple && hasColouredOptions ? tagRender : undefined,
|
|
164
|
+
// Render the dropdown to the body so it is not clipped by the ag-grid cell.
|
|
165
|
+
getPopupContainer: ()=>document.body,
|
|
166
|
+
filterOption: (input, option)=>(option.filterstring || option.children.props.html || '').toLowerCase().indexOf(input.toLowerCase()) >= 0
|
|
167
|
+
}, options.map((opt, i)=>type.isPrimitive(opt) ? /*#__PURE__*/ React.createElement(Option, {
|
|
168
|
+
key: i,
|
|
169
|
+
value: `${i}`
|
|
170
|
+
}, renderHtml({
|
|
171
|
+
html: `${opt}`,
|
|
172
|
+
methods
|
|
173
|
+
})) : /*#__PURE__*/ React.createElement(Option, {
|
|
174
|
+
key: i,
|
|
175
|
+
value: `${i}`,
|
|
176
|
+
disabled: opt.disabled,
|
|
177
|
+
filterstring: opt.filterString,
|
|
178
|
+
style: {
|
|
179
|
+
...opt.style,
|
|
180
|
+
...opt.color ? {
|
|
181
|
+
color: opt.color
|
|
182
|
+
} : {}
|
|
183
|
+
}
|
|
184
|
+
}, type.isNone(opt.label) ? renderHtml({
|
|
185
|
+
html: `${opt.value}`,
|
|
186
|
+
methods
|
|
187
|
+
}) : renderHtml({
|
|
188
|
+
html: opt.label,
|
|
189
|
+
methods
|
|
190
|
+
})))))));
|
|
191
|
+
}
|
|
192
|
+
export default SelectorCell;
|
|
@@ -0,0 +1,74 @@
|
|
|
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
|
+
*/ import React from 'react';
|
|
16
|
+
import { ConfigProvider, Switch } from 'antd';
|
|
17
|
+
import { serializer, type } from '@lowdefy/helpers';
|
|
18
|
+
function normaliseIcon(icon) {
|
|
19
|
+
const copy = serializer.copy(icon);
|
|
20
|
+
return type.isString(copy) ? {
|
|
21
|
+
name: copy
|
|
22
|
+
} : copy;
|
|
23
|
+
}
|
|
24
|
+
function SwitchCell(params) {
|
|
25
|
+
const { value, data, cellConfig, methods, components } = params;
|
|
26
|
+
const Icon = components?.Icon;
|
|
27
|
+
function onChange(newValue) {
|
|
28
|
+
const colId = params.column?.getColId?.();
|
|
29
|
+
if (params.node && colId) params.node.setDataValue(colId, newValue);
|
|
30
|
+
if (type.isString(cellConfig.eventName)) {
|
|
31
|
+
methods?.triggerEvent?.({
|
|
32
|
+
name: cellConfig.eventName,
|
|
33
|
+
event: {
|
|
34
|
+
row: data,
|
|
35
|
+
value,
|
|
36
|
+
newValue
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const checkedIcon = normaliseIcon(cellConfig.checkedIcon);
|
|
42
|
+
const uncheckedIcon = normaliseIcon(cellConfig.uncheckedIcon);
|
|
43
|
+
function children(text, icon, key) {
|
|
44
|
+
if (!type.isNone(text)) return /*#__PURE__*/ React.createElement("span", null, text);
|
|
45
|
+
if (icon && Icon) return /*#__PURE__*/ React.createElement(Icon, {
|
|
46
|
+
blockId: `switchcell_${key}`,
|
|
47
|
+
events: {},
|
|
48
|
+
properties: icon
|
|
49
|
+
});
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
const switchEl = /*#__PURE__*/ React.createElement(Switch, {
|
|
53
|
+
checked: !!value,
|
|
54
|
+
size: cellConfig.size ?? 'small',
|
|
55
|
+
disabled: cellConfig.disabled === true,
|
|
56
|
+
autoFocus: cellConfig.autoFocus,
|
|
57
|
+
checkedChildren: children(cellConfig.checkedText, checkedIcon, 'checked'),
|
|
58
|
+
unCheckedChildren: children(cellConfig.uncheckedText, uncheckedIcon, 'unchecked'),
|
|
59
|
+
onChange: onChange
|
|
60
|
+
});
|
|
61
|
+
return(// Synthetic stopPropagation keeps a stray click from bubbling within React (see SelectorCell).
|
|
62
|
+
/*#__PURE__*/ React.createElement("div", {
|
|
63
|
+
onClick: (e)=>e.stopPropagation()
|
|
64
|
+
}, cellConfig.color ? /*#__PURE__*/ React.createElement(ConfigProvider, {
|
|
65
|
+
theme: {
|
|
66
|
+
components: {
|
|
67
|
+
Switch: {
|
|
68
|
+
colorPrimary: cellConfig.color
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}, switchEl) : switchEl));
|
|
73
|
+
}
|
|
74
|
+
export default SwitchCell;
|
|
@@ -0,0 +1,66 @@
|
|
|
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
|
+
*/ import React, { useState, useEffect } from 'react';
|
|
16
|
+
import { Input } from 'antd';
|
|
17
|
+
import { type } from '@lowdefy/helpers';
|
|
18
|
+
function TextInputCell(params) {
|
|
19
|
+
const { value, data, cellConfig, methods } = params;
|
|
20
|
+
// Keep the typed text local: firing the change event per keystroke would re-render the grid,
|
|
21
|
+
// remount the cell and lose focus. Commit once on blur / Enter instead. Resync when the row
|
|
22
|
+
// value changes externally (e.g. after the app persists).
|
|
23
|
+
const [text, setText] = useState(value ?? '');
|
|
24
|
+
useEffect(()=>setText(value ?? ''), [
|
|
25
|
+
value
|
|
26
|
+
]);
|
|
27
|
+
function commit() {
|
|
28
|
+
if ((value ?? '') === text) return;
|
|
29
|
+
const colId = params.column?.getColId?.();
|
|
30
|
+
if (params.node && colId) params.node.setDataValue(colId, text);
|
|
31
|
+
if (type.isString(cellConfig.eventName)) {
|
|
32
|
+
methods?.triggerEvent?.({
|
|
33
|
+
name: cellConfig.eventName,
|
|
34
|
+
event: {
|
|
35
|
+
row: data,
|
|
36
|
+
value,
|
|
37
|
+
newValue: text
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return(// Width fills the cell; synthetic stopPropagation keeps clicks from bubbling (see SelectorCell).
|
|
43
|
+
/*#__PURE__*/ React.createElement("div", {
|
|
44
|
+
style: {
|
|
45
|
+
width: '100%'
|
|
46
|
+
},
|
|
47
|
+
onClick: (e)=>e.stopPropagation()
|
|
48
|
+
}, /*#__PURE__*/ React.createElement(Input, {
|
|
49
|
+
style: {
|
|
50
|
+
width: '100%'
|
|
51
|
+
},
|
|
52
|
+
size: cellConfig.size ?? 'small',
|
|
53
|
+
value: text,
|
|
54
|
+
onChange: (e)=>setText(e.target.value),
|
|
55
|
+
onBlur: commit,
|
|
56
|
+
onPressEnter: commit,
|
|
57
|
+
allowClear: cellConfig.allowClear,
|
|
58
|
+
placeholder: cellConfig.placeholder,
|
|
59
|
+
maxLength: cellConfig.maxLength,
|
|
60
|
+
showCount: cellConfig.showCount,
|
|
61
|
+
variant: cellConfig.bordered === false ? 'borderless' : cellConfig.variant,
|
|
62
|
+
type: cellConfig.inputType,
|
|
63
|
+
disabled: cellConfig.disabled === true
|
|
64
|
+
})));
|
|
65
|
+
}
|
|
66
|
+
export default TextInputCell;
|
|
@@ -20,6 +20,10 @@ import BooleanCell from './BooleanCell.js';
|
|
|
20
20
|
import ProgressCell from './ProgressCell.js';
|
|
21
21
|
import NumberCell from './NumberCell.js';
|
|
22
22
|
import ButtonsCell from './ButtonsCell.js';
|
|
23
|
+
import SelectorCell from './SelectorCell.js';
|
|
24
|
+
import SwitchCell from './SwitchCell.js';
|
|
25
|
+
import TextInputCell from './TextInputCell.js';
|
|
26
|
+
import ParagraphInputCell from './ParagraphInputCell.js';
|
|
23
27
|
const CELL_RENDERERS = {
|
|
24
28
|
tag: TagCell,
|
|
25
29
|
avatar: AvatarCell,
|
|
@@ -28,7 +32,12 @@ const CELL_RENDERERS = {
|
|
|
28
32
|
boolean: BooleanCell,
|
|
29
33
|
progress: ProgressCell,
|
|
30
34
|
number: NumberCell,
|
|
31
|
-
buttons: ButtonsCell
|
|
35
|
+
buttons: ButtonsCell,
|
|
36
|
+
selector: SelectorCell,
|
|
37
|
+
multipleSelector: SelectorCell,
|
|
38
|
+
switch: SwitchCell,
|
|
39
|
+
textInput: TextInputCell,
|
|
40
|
+
paragraphInput: ParagraphInputCell
|
|
32
41
|
};
|
|
33
42
|
function getCellRenderer(type) {
|
|
34
43
|
return CELL_RENDERERS[type];
|