@lowdefy/blocks-basic 0.0.0-experimental-20260927140906 → 0.0.0-experimental-20260928105334
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/Anchor/Anchor.js +1 -1
- package/dist/blocks/Anchor/gallery.yaml +14 -14
- package/dist/blocks/Anchor/meta.js +2 -2
- package/dist/blocks/Anchor/tests/Anchor.e2e.yaml +1 -1
- package/dist/blocks/Anchor/tests.yaml +6 -6
- package/dist/blocks/Box/gallery.yaml +9 -9
- package/dist/blocks/ClickableHtml/ClickableHtml.js +28 -7
- package/dist/blocks/ClickableHtml/gallery.yaml +0 -67
- package/dist/blocks/ClickableHtml/meta.js +1 -14
- package/dist/blocks/ClickableHtml/tests/ClickableHtml.e2e.yaml +0 -28
- package/dist/blocks/DangerousHtml/DangerousHtml.js +19 -19
- package/dist/blocks/DangerousHtml/meta.js +1 -13
- package/dist/blocks/Dynamic/meta.js +0 -4
- package/dist/blocks/Html/gallery.yaml +0 -28
- package/dist/blocks/Html/meta.js +1 -23
- package/dist/blocks/Html/tests/Html.e2e.yaml +0 -11
- package/dist/blocks/Icon/Icon.js +1 -21
- package/dist/blocks/Icon/gallery.yaml +64 -158
- package/dist/blocks/Icon/meta.js +4 -11
- package/dist/blocks/Icon/tests/Icon.e2e.yaml +3 -3
- package/dist/blocks/Icon/tests.yaml +7 -7
- package/dist/blocks/List/gallery.yaml +11 -11
- package/dist/blocks/Span/gallery.yaml +7 -7
- package/dist/blocks.js +0 -1
- package/dist/e2e.js +0 -1
- package/dist/metas.js +0 -1
- package/package.json +5 -8
- package/dist/blocks/PollingTimer/PollingTimer.js +0 -120
- package/dist/blocks/PollingTimer/e2e.js +0 -21
- package/dist/blocks/PollingTimer/gallery.yaml +0 -190
- package/dist/blocks/PollingTimer/meta.js +0 -61
- package/dist/blocks/PollingTimer/validateInterval.js +0 -21
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
properties:
|
|
69
69
|
title: Link with Icon
|
|
70
70
|
url: https://lowdefy.com
|
|
71
|
-
icon:
|
|
71
|
+
icon: AiOutlineLink
|
|
72
72
|
- id: icon_download
|
|
73
73
|
type: Anchor
|
|
74
74
|
layout:
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
properties:
|
|
77
77
|
title: Download
|
|
78
78
|
url: https://lowdefy.com
|
|
79
|
-
icon:
|
|
79
|
+
icon: AiOutlineDownload
|
|
80
80
|
- id: icon_external
|
|
81
81
|
type: Anchor
|
|
82
82
|
layout:
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
properties:
|
|
85
85
|
title: External Link
|
|
86
86
|
url: https://lowdefy.com
|
|
87
|
-
icon:
|
|
87
|
+
icon: AiOutlineExport
|
|
88
88
|
- id: icon_mail
|
|
89
89
|
type: Anchor
|
|
90
90
|
layout:
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
properties:
|
|
93
93
|
title: Send Email
|
|
94
94
|
url: https://lowdefy.com
|
|
95
|
-
icon:
|
|
95
|
+
icon: AiOutlineMail
|
|
96
96
|
- id: icon_github
|
|
97
97
|
type: Anchor
|
|
98
98
|
layout:
|
|
@@ -100,7 +100,7 @@
|
|
|
100
100
|
properties:
|
|
101
101
|
title: GitHub
|
|
102
102
|
url: https://github.com/lowdefy/lowdefy
|
|
103
|
-
icon:
|
|
103
|
+
icon: AiOutlineGithub
|
|
104
104
|
- id: icon_object
|
|
105
105
|
type: Anchor
|
|
106
106
|
layout:
|
|
@@ -109,7 +109,7 @@
|
|
|
109
109
|
title: Colored Icon
|
|
110
110
|
url: https://lowdefy.com
|
|
111
111
|
icon:
|
|
112
|
-
name:
|
|
112
|
+
name: AiOutlineHeart
|
|
113
113
|
color: '#ff4d4f'
|
|
114
114
|
|
|
115
115
|
- title: New Tab
|
|
@@ -130,7 +130,7 @@
|
|
|
130
130
|
title: External Docs
|
|
131
131
|
url: https://docs.lowdefy.com
|
|
132
132
|
newTab: true
|
|
133
|
-
icon:
|
|
133
|
+
icon: AiOutlineExport
|
|
134
134
|
|
|
135
135
|
- title: Disabled
|
|
136
136
|
blocks:
|
|
@@ -150,7 +150,7 @@
|
|
|
150
150
|
title: Disabled with Icon
|
|
151
151
|
url: https://lowdefy.com
|
|
152
152
|
disabled: true
|
|
153
|
-
icon:
|
|
153
|
+
icon: AiOutlineLock
|
|
154
154
|
- id: enabled_link
|
|
155
155
|
type: Anchor
|
|
156
156
|
layout:
|
|
@@ -159,7 +159,7 @@
|
|
|
159
159
|
title: Enabled Link
|
|
160
160
|
url: https://lowdefy.com
|
|
161
161
|
disabled: false
|
|
162
|
-
icon:
|
|
162
|
+
icon: AiOutlineUnlock
|
|
163
163
|
|
|
164
164
|
- title: Aria Label
|
|
165
165
|
blocks:
|
|
@@ -177,7 +177,7 @@
|
|
|
177
177
|
flex: 0 0 auto
|
|
178
178
|
properties:
|
|
179
179
|
url: https://lowdefy.com
|
|
180
|
-
icon:
|
|
180
|
+
icon: AiOutlineHome
|
|
181
181
|
ariaLabel: Go to home page
|
|
182
182
|
|
|
183
183
|
- title: Rel Attribute
|
|
@@ -209,7 +209,7 @@
|
|
|
209
209
|
properties:
|
|
210
210
|
title: Go Back
|
|
211
211
|
back: true
|
|
212
|
-
icon:
|
|
212
|
+
icon: AiOutlineArrowLeft
|
|
213
213
|
- id: nav_home
|
|
214
214
|
type: Anchor
|
|
215
215
|
layout:
|
|
@@ -217,7 +217,7 @@
|
|
|
217
217
|
properties:
|
|
218
218
|
title: Go Home
|
|
219
219
|
home: true
|
|
220
|
-
icon:
|
|
220
|
+
icon: AiOutlineHome
|
|
221
221
|
|
|
222
222
|
- title: Keyboard Shortcuts
|
|
223
223
|
blocks:
|
|
@@ -228,7 +228,7 @@
|
|
|
228
228
|
properties:
|
|
229
229
|
title: Documentation
|
|
230
230
|
url: https://docs.lowdefy.com
|
|
231
|
-
icon:
|
|
231
|
+
icon: AiOutlineBook
|
|
232
232
|
events:
|
|
233
233
|
onClick:
|
|
234
234
|
shortcut: mod+shift+d
|
|
@@ -313,4 +313,4 @@
|
|
|
313
313
|
properties:
|
|
314
314
|
title: Large Red Link
|
|
315
315
|
url: https://lowdefy.com
|
|
316
|
-
icon:
|
|
316
|
+
icon: AiOutlineHeart
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*/ export default {
|
|
16
16
|
category: 'display',
|
|
17
17
|
icons: [
|
|
18
|
-
'
|
|
18
|
+
'AiOutlineLoading3Quarters'
|
|
19
19
|
],
|
|
20
20
|
valueType: null,
|
|
21
21
|
cssKeys: {
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
'string',
|
|
66
66
|
'object'
|
|
67
67
|
],
|
|
68
|
-
description:
|
|
68
|
+
description: "Name of an React-Icon (See <a href='https://react-icons.github.io/react-icons/'>all icons</a>) or properties of an Icon block for anchor icon.",
|
|
69
69
|
docs: {
|
|
70
70
|
displayType: 'icon'
|
|
71
71
|
}
|
|
@@ -21,18 +21,18 @@
|
|
|
21
21
|
- id: properties.icon string
|
|
22
22
|
type: Anchor
|
|
23
23
|
properties:
|
|
24
|
-
icon:
|
|
24
|
+
icon: AiFillFire
|
|
25
25
|
- id: properties.icon object
|
|
26
26
|
type: Anchor
|
|
27
27
|
properties:
|
|
28
28
|
title: Click here
|
|
29
29
|
icon:
|
|
30
30
|
color: red
|
|
31
|
-
name:
|
|
31
|
+
name: AiFillRocket
|
|
32
32
|
- id: properties.icon and properties.title
|
|
33
33
|
type: Anchor
|
|
34
34
|
properties:
|
|
35
|
-
icon:
|
|
35
|
+
icon: AiOutlineLink
|
|
36
36
|
title: This is the anchor title
|
|
37
37
|
- id: properties.disabled
|
|
38
38
|
type: Anchor
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
- id: properties.icon, properties.title and properties.disabled
|
|
43
43
|
type: Anchor
|
|
44
44
|
properties:
|
|
45
|
-
icon:
|
|
45
|
+
icon: AiOutlineLink
|
|
46
46
|
title: This is the anchor title
|
|
47
47
|
disabled: true
|
|
48
48
|
- id: properties.url
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
type: Anchor
|
|
93
93
|
properties:
|
|
94
94
|
title: Click here
|
|
95
|
-
icon:
|
|
95
|
+
icon: AiOutlineLink
|
|
96
96
|
style:
|
|
97
97
|
color: green !important
|
|
98
98
|
fontSize: 8
|
|
@@ -103,7 +103,7 @@
|
|
|
103
103
|
loading: true
|
|
104
104
|
properties:
|
|
105
105
|
title: Click here
|
|
106
|
-
icon:
|
|
106
|
+
icon: AiOutlineLink
|
|
107
107
|
style:
|
|
108
108
|
color: green !important
|
|
109
109
|
fontSize: 8
|
|
@@ -896,7 +896,7 @@
|
|
|
896
896
|
layout:
|
|
897
897
|
flex: 0 0 auto
|
|
898
898
|
properties:
|
|
899
|
-
name:
|
|
899
|
+
name: AiOutlineRocket
|
|
900
900
|
size: 32
|
|
901
901
|
color: '#1677ff'
|
|
902
902
|
- id: box_feature_a_title
|
|
@@ -918,7 +918,7 @@
|
|
|
918
918
|
layout:
|
|
919
919
|
flex: 0 0 auto
|
|
920
920
|
properties:
|
|
921
|
-
name:
|
|
921
|
+
name: AiOutlineSafety
|
|
922
922
|
size: 32
|
|
923
923
|
color: '#52c41a'
|
|
924
924
|
- id: box_feature_b_title
|
|
@@ -940,7 +940,7 @@
|
|
|
940
940
|
layout:
|
|
941
941
|
flex: 0 0 auto
|
|
942
942
|
properties:
|
|
943
|
-
name:
|
|
943
|
+
name: AiOutlineApi
|
|
944
944
|
size: 32
|
|
945
945
|
color: '#722ed1'
|
|
946
946
|
- id: box_feature_c_title
|
|
@@ -1110,7 +1110,7 @@
|
|
|
1110
1110
|
layout:
|
|
1111
1111
|
flex: 0 0 auto
|
|
1112
1112
|
properties:
|
|
1113
|
-
name:
|
|
1113
|
+
name: AiOutlineCheckCircle
|
|
1114
1114
|
size: 20
|
|
1115
1115
|
color: '#52c41a'
|
|
1116
1116
|
- id: box_inbox_item_1_body
|
|
@@ -1147,7 +1147,7 @@
|
|
|
1147
1147
|
layout:
|
|
1148
1148
|
flex: 0 0 auto
|
|
1149
1149
|
properties:
|
|
1150
|
-
name:
|
|
1150
|
+
name: AiOutlineUserAdd
|
|
1151
1151
|
size: 20
|
|
1152
1152
|
color: '#1677ff'
|
|
1153
1153
|
- id: box_inbox_item_2_body
|
|
@@ -1184,7 +1184,7 @@
|
|
|
1184
1184
|
layout:
|
|
1185
1185
|
flex: 0 0 auto
|
|
1186
1186
|
properties:
|
|
1187
|
-
name:
|
|
1187
|
+
name: AiOutlineWarning
|
|
1188
1188
|
size: 20
|
|
1189
1189
|
color: '#faad14'
|
|
1190
1190
|
- id: box_inbox_item_3_body
|
|
@@ -1247,7 +1247,7 @@
|
|
|
1247
1247
|
layout:
|
|
1248
1248
|
flex: 0 0 auto
|
|
1249
1249
|
properties:
|
|
1250
|
-
name:
|
|
1250
|
+
name: AiOutlineDashboard
|
|
1251
1251
|
size: 16
|
|
1252
1252
|
color: '#1677ff'
|
|
1253
1253
|
- id: box_sidebar_text_dashboard
|
|
@@ -1274,7 +1274,7 @@
|
|
|
1274
1274
|
layout:
|
|
1275
1275
|
flex: 0 0 auto
|
|
1276
1276
|
properties:
|
|
1277
|
-
name:
|
|
1277
|
+
name: AiOutlineProject
|
|
1278
1278
|
size: 16
|
|
1279
1279
|
color: rgba(128, 128, 128, 0.7)
|
|
1280
1280
|
- id: box_sidebar_text_projects
|
|
@@ -1301,7 +1301,7 @@
|
|
|
1301
1301
|
layout:
|
|
1302
1302
|
flex: 0 0 auto
|
|
1303
1303
|
properties:
|
|
1304
|
-
name:
|
|
1304
|
+
name: AiOutlineSetting
|
|
1305
1305
|
size: 16
|
|
1306
1306
|
color: rgba(128, 128, 128, 0.7)
|
|
1307
1307
|
- id: box_sidebar_text_settings
|
|
@@ -14,12 +14,32 @@
|
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ import React from 'react';
|
|
16
16
|
import { withBlockDefaults, HtmlComponent } from '@lowdefy/block-utils';
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const ClickableHtml = ({ blockId, classNames, events, properties, methods, styles })
|
|
17
|
+
// dataset keys are camelCase (data-record-id → recordId); config authors
|
|
18
|
+
// write the attributes in kebab-case, so hand them back as snake_case.
|
|
19
|
+
function toSnakeCase(key) {
|
|
20
|
+
return key.replace(/[A-Z]/g, (match)=>`_${match.toLowerCase()}`);
|
|
21
|
+
}
|
|
22
|
+
const ClickableHtml = ({ blockId, classNames, events, properties, methods, styles })=>{
|
|
23
|
+
// Each clickable element names the event it fires in its data-event
|
|
24
|
+
// attribute (data-event="onEditClick" → events.onEditClick), so every
|
|
25
|
+
// target in the markup has its own action chain. Its other data-*
|
|
26
|
+
// attributes are the event object.
|
|
27
|
+
function onClick(clickEvent) {
|
|
28
|
+
const target = clickEvent.target.closest('[data-event]');
|
|
29
|
+
if (!target || !clickEvent.currentTarget.contains(target)) return;
|
|
30
|
+
const { event: name, ...data } = target.dataset;
|
|
31
|
+
if (!name) return;
|
|
32
|
+
clickEvent.preventDefault();
|
|
33
|
+
const event = {};
|
|
34
|
+
Object.keys(data).forEach((key)=>{
|
|
35
|
+
event[toSnakeCase(key)] = data[key];
|
|
36
|
+
});
|
|
37
|
+
methods.triggerEvent({
|
|
38
|
+
name,
|
|
39
|
+
event
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
return /*#__PURE__*/ React.createElement(HtmlComponent, {
|
|
23
43
|
div: true,
|
|
24
44
|
events: events,
|
|
25
45
|
html: properties.html,
|
|
@@ -27,6 +47,7 @@ const ClickableHtml = ({ blockId, classNames, events, properties, methods, style
|
|
|
27
47
|
methods: methods,
|
|
28
48
|
className: classNames?.element,
|
|
29
49
|
style: styles?.element,
|
|
30
|
-
|
|
50
|
+
onClick: onClick
|
|
31
51
|
});
|
|
52
|
+
};
|
|
32
53
|
export default withBlockDefaults(ClickableHtml);
|
|
@@ -111,70 +111,3 @@
|
|
|
111
111
|
type: SetState
|
|
112
112
|
params:
|
|
113
113
|
style_card_action: remove
|
|
114
|
-
|
|
115
|
-
- title: Clickable icons and a popover menu
|
|
116
|
-
blocks:
|
|
117
|
-
- id: row_actions
|
|
118
|
-
type: ClickableHtml
|
|
119
|
-
properties:
|
|
120
|
-
html: '<p>Invoice INV-042 <i data-icon="edit" data-event="onEdit" data-id="42" data-tooltip="Edit" style="cursor: pointer"></i> <span data-popover="more" style="cursor: pointer"><i data-icon="more-vertical"></i></span></p><div data-popover-content="more" hidden><p data-event="onDuplicate" data-id="42" style="cursor: pointer; margin: 0 0 8px"><i data-icon="copy"></i> Duplicate</p><p data-event="onDelete" data-id="42" style="cursor: pointer; margin: 0; color: var(--ant-color-error)"><i data-icon="delete"></i> Delete</p></div>'
|
|
121
|
-
events:
|
|
122
|
-
onEdit:
|
|
123
|
-
- id: set_edit
|
|
124
|
-
type: SetState
|
|
125
|
-
params:
|
|
126
|
-
row_actions_last: { _string.concat: ['edit ', { _event: id }] }
|
|
127
|
-
onDuplicate:
|
|
128
|
-
- id: set_duplicate
|
|
129
|
-
type: SetState
|
|
130
|
-
params:
|
|
131
|
-
row_actions_last: { _string.concat: ['duplicate ', { _event: id }] }
|
|
132
|
-
onDelete:
|
|
133
|
-
- id: set_delete
|
|
134
|
-
type: SetState
|
|
135
|
-
params:
|
|
136
|
-
row_actions_last: { _string.concat: ['delete ', { _event: id }] }
|
|
137
|
-
- id: row_actions_result
|
|
138
|
-
type: Html
|
|
139
|
-
properties:
|
|
140
|
-
html:
|
|
141
|
-
_string.concat:
|
|
142
|
-
- '<p>Last action: <code>'
|
|
143
|
-
- _state:
|
|
144
|
-
key: row_actions_last
|
|
145
|
-
default: 'none yet'
|
|
146
|
-
- '</code></p>'
|
|
147
|
-
|
|
148
|
-
- title: Confirm before an event
|
|
149
|
-
blocks:
|
|
150
|
-
- id: confirm_actions
|
|
151
|
-
type: ClickableHtml
|
|
152
|
-
properties:
|
|
153
|
-
html: '<p>INV-2026-0042 <i data-icon="delete" data-event="onDelete" data-id="42" data-tooltip="Delete" data-confirm="Delete invoice INV-2026-0042?" style="cursor: pointer; color: var(--ant-color-error)"></i> <span data-event="onArchive" data-id="42" data-confirm style="cursor: pointer; color: var(--ant-color-primary)">Archive</span></p>'
|
|
154
|
-
events:
|
|
155
|
-
onDelete:
|
|
156
|
-
- id: deleted
|
|
157
|
-
type: SetState
|
|
158
|
-
params:
|
|
159
|
-
confirm_last:
|
|
160
|
-
_string.concat:
|
|
161
|
-
- 'deleted '
|
|
162
|
-
- _event: id
|
|
163
|
-
onArchive:
|
|
164
|
-
- id: archived
|
|
165
|
-
type: SetState
|
|
166
|
-
params:
|
|
167
|
-
confirm_last:
|
|
168
|
-
_string.concat:
|
|
169
|
-
- 'archived '
|
|
170
|
-
- _event: id
|
|
171
|
-
- id: confirm_result
|
|
172
|
-
type: Html
|
|
173
|
-
properties:
|
|
174
|
-
html:
|
|
175
|
-
_string.concat:
|
|
176
|
-
- '<p>Last action: <code>'
|
|
177
|
-
- _state:
|
|
178
|
-
key: confirm_last
|
|
179
|
-
default: 'none yet'
|
|
180
|
-
- '</code></p>'
|
|
@@ -19,21 +19,8 @@
|
|
|
19
19
|
cssKeys: {
|
|
20
20
|
element: 'The Html element.'
|
|
21
21
|
},
|
|
22
|
-
hazards: [
|
|
23
|
-
{
|
|
24
|
-
id: 'html-style-stripped',
|
|
25
|
-
message: 'Content is sanitised with DOMPurify, so <style>, <script> and inline event handlers are removed before render. Clicks are wired through data-event attributes instead of inline handlers.',
|
|
26
|
-
see: 'display-blocks/clickablehtml'
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
id: 'clickable-html-confirm-destructive',
|
|
30
|
-
message: 'Add data-confirm="Delete this row?" to a data-event element whose event deletes or changes data, so a stray click cannot fire it. Only OK fires the event.',
|
|
31
|
-
see: 'concepts/html-attributes'
|
|
32
|
-
}
|
|
33
|
-
],
|
|
34
22
|
// Each clickable element names its event in a data-event attribute, so the
|
|
35
23
|
// event names this block fires are authored in its html.
|
|
36
|
-
dynamicEvents: true,
|
|
37
24
|
events: {
|
|
38
25
|
onTextSelection: 'Trigger action when text is selected and pass selected text to the event object.'
|
|
39
26
|
},
|
|
@@ -43,7 +30,7 @@
|
|
|
43
30
|
properties: {
|
|
44
31
|
html: {
|
|
45
32
|
type: 'string',
|
|
46
|
-
description: 'Content to be rendered as Html. An element with a data-event attribute fires the event it names when clicked (data-event="onEditClick" fires events.onEditClick), and its default browser action is prevented. The event object holds the element\'s other data-* attributes with snake_case keys, so data-event="onEditClick" data-record-id="42" gives { record_id: "42" }.
|
|
33
|
+
description: 'Content to be rendered as Html. An element with a data-event attribute fires the event it names when clicked (data-event="onEditClick" fires events.onEditClick), and its default browser action is prevented. The event object holds the element\'s other data-* attributes with snake_case keys, so data-event="onEditClick" data-record-id="42" gives { record_id: "42" }.',
|
|
47
34
|
docs: {
|
|
48
35
|
displayType: 'text-area'
|
|
49
36
|
}
|
|
@@ -67,31 +67,3 @@ blocks:
|
|
|
67
67
|
type: ClickableHtml
|
|
68
68
|
properties:
|
|
69
69
|
html: <p>Safe content</p><script>alert('xss')</script>
|
|
70
|
-
|
|
71
|
-
- id: clickable_confirm
|
|
72
|
-
type: ClickableHtml
|
|
73
|
-
properties:
|
|
74
|
-
html: '<button id="confirm_delete" data-event="onDelete" data-row-id="7" data-confirm="Delete row 7?">Delete</button> <button id="proto_event" data-event="__proto__">Proto</button>'
|
|
75
|
-
events:
|
|
76
|
-
onDelete:
|
|
77
|
-
- id: count_delete
|
|
78
|
-
type: SetState
|
|
79
|
-
params:
|
|
80
|
-
delete_count:
|
|
81
|
-
_sum:
|
|
82
|
-
- _state:
|
|
83
|
-
key: delete_count
|
|
84
|
-
default: 0
|
|
85
|
-
- 1
|
|
86
|
-
|
|
87
|
-
- id: clickable_confirm_result
|
|
88
|
-
type: Html
|
|
89
|
-
properties:
|
|
90
|
-
html:
|
|
91
|
-
_string.concat:
|
|
92
|
-
- '<span id="delete_count">'
|
|
93
|
-
- _json.stringify:
|
|
94
|
-
- _state:
|
|
95
|
-
key: delete_count
|
|
96
|
-
default: 0
|
|
97
|
-
- '</span>'
|
|
@@ -13,39 +13,39 @@
|
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ import React from 'react';
|
|
16
|
-
import
|
|
16
|
+
import DOMPurify from 'dompurify';
|
|
17
|
+
import { withBlockDefaults } from '@lowdefy/block-utils';
|
|
18
|
+
import { type } from '@lowdefy/helpers';
|
|
17
19
|
let DangerousHtml = class DangerousHtml extends React.Component {
|
|
18
|
-
warnOnOptionsChange() {
|
|
19
|
-
const { DOMPurifyOptions } = this.props.properties;
|
|
20
|
-
if (!this.warnedOptionsChange && JSON.stringify(DOMPurifyOptions) !== JSON.stringify(this.DOMPurifyOptions)) {
|
|
21
|
-
this.warnedOptionsChange = true;
|
|
22
|
-
console.warn(`DangerousHtml block "${this.props.blockId}": DOMPurifyOptions changed after mount and the change is ignored. The sanitizer options are fixed at the first render; write them as a literal, not from state.`);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
20
|
componentDidMount() {
|
|
26
|
-
this.
|
|
21
|
+
const htmlString = type.isNone(this.props.properties.html) ? '' : this.props.properties.html.toString();
|
|
22
|
+
this.div.innerHTML = DOMPurify.sanitize(htmlString, this.DOMPurifyOptions);
|
|
27
23
|
}
|
|
28
24
|
componentDidUpdate() {
|
|
29
|
-
this.
|
|
25
|
+
const htmlString = type.isNone(this.props.properties.html) ? '' : this.props.properties.html.toString();
|
|
26
|
+
this.div.innerHTML = DOMPurify.sanitize(htmlString, this.DOMPurifyOptions);
|
|
30
27
|
}
|
|
31
28
|
render() {
|
|
32
|
-
const { blockId, classNames,
|
|
33
|
-
return /*#__PURE__*/ React.createElement(
|
|
34
|
-
div: true,
|
|
35
|
-
html: properties.html,
|
|
29
|
+
const { blockId, classNames, styles } = this.props;
|
|
30
|
+
return /*#__PURE__*/ React.createElement("div", {
|
|
36
31
|
id: blockId,
|
|
32
|
+
"data-testid": blockId,
|
|
33
|
+
ref: (el)=>{
|
|
34
|
+
if (el) {
|
|
35
|
+
this.div = el;
|
|
36
|
+
}
|
|
37
|
+
},
|
|
37
38
|
className: classNames?.element,
|
|
38
|
-
sanitizeOptions: this.DOMPurifyOptions,
|
|
39
39
|
style: styles?.element
|
|
40
40
|
});
|
|
41
41
|
}
|
|
42
42
|
constructor(props){
|
|
43
43
|
super(props);
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
this.div = {
|
|
45
|
+
innerHTML: ''
|
|
46
|
+
};
|
|
47
|
+
// we do not revaluate DOMPurifyOptions improve options safety by not making options dynamic.
|
|
47
48
|
this.DOMPurifyOptions = props.properties.DOMPurifyOptions;
|
|
48
|
-
this.warnedOptionsChange = false;
|
|
49
49
|
}
|
|
50
50
|
};
|
|
51
51
|
export default withBlockDefaults(DangerousHtml);
|
|
@@ -19,25 +19,13 @@
|
|
|
19
19
|
cssKeys: {
|
|
20
20
|
element: 'The DangerousHtml element.'
|
|
21
21
|
},
|
|
22
|
-
hazards: [
|
|
23
|
-
{
|
|
24
|
-
id: 'dangerous-html-unsanitised',
|
|
25
|
-
message: 'Content is rendered without sanitising, so never pass caller-supplied or database HTML through it. Use Html for anything a user could have written.',
|
|
26
|
-
see: 'display-blocks/dangeroushtml'
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
id: 'dompurify-options-first-render',
|
|
30
|
-
message: 'DOMPurifyOptions is read once when the block mounts, so a value that changes after the first render has no effect. Set it statically or remount the block.',
|
|
31
|
-
see: 'display-blocks/dangeroushtml'
|
|
32
|
-
}
|
|
33
|
-
],
|
|
34
22
|
properties: {
|
|
35
23
|
type: 'object',
|
|
36
24
|
additionalProperties: false,
|
|
37
25
|
properties: {
|
|
38
26
|
html: {
|
|
39
27
|
type: 'string',
|
|
40
|
-
description: 'Content to be rendered as Html.
|
|
28
|
+
description: 'Content to be rendered as Html.',
|
|
41
29
|
docs: {
|
|
42
30
|
displayType: 'text-area'
|
|
43
31
|
}
|
|
@@ -38,10 +38,6 @@
|
|
|
38
38
|
type: 'object',
|
|
39
39
|
description: 'Static values passed to the endpoint payload as params. Operators are not allowed — read runtime values in the endpoint routine with _payload, _user or _secret.'
|
|
40
40
|
},
|
|
41
|
-
policy: {
|
|
42
|
-
type: 'string',
|
|
43
|
-
description: 'Id of a policies.dynamicBlocks entry in lowdefy.yaml. The resolved content must pass the policy on every page get. The endpoint returns stored content as config by reading the blocks of a ValidateDynamic step with the same policy. Replaces types: the policy lists are bundled.'
|
|
44
|
-
},
|
|
45
41
|
required: {
|
|
46
42
|
type: 'boolean',
|
|
47
43
|
default: false,
|
|
@@ -237,31 +237,3 @@
|
|
|
237
237
|
border: 1px solid var(--ant-color-border)
|
|
238
238
|
properties:
|
|
239
239
|
html: '<h4 style="margin: 0 0 8px 0;">Elevated Block</h4><p style="margin: 0;">Uses bg-elevated token for a surface that adapts to light and dark mode.</p>'
|
|
240
|
-
|
|
241
|
-
- title: Icons, tooltips and popovers
|
|
242
|
-
blocks:
|
|
243
|
-
- id: html_icons
|
|
244
|
-
type: Html
|
|
245
|
-
properties:
|
|
246
|
-
html: '<p><i data-icon="success" style="color: var(--ant-color-success)"></i> Saved <span data-tooltip="Saved to the cloud 2 minutes ago" style="text-decoration: underline dotted">just now</span></p><p><i data-icon="warning" style="color: var(--ant-color-warning)"></i> 3 fields need attention. <span data-popover="fields" style="color: var(--ant-color-primary); cursor: pointer">Which? <i data-icon="chevron-down"></i></span></p><div data-popover-content="fields" hidden><ul style="margin: 0; padding-left: 16px"><li>Email</li><li>Phone</li><li>Address</li></ul></div>'
|
|
247
|
-
|
|
248
|
-
- title: Links and status tags
|
|
249
|
-
blocks:
|
|
250
|
-
- id: html_links_tags
|
|
251
|
-
type: Html
|
|
252
|
-
properties:
|
|
253
|
-
html: '<p><a data-page-id="Button">Button</a> moved to <span data-tag="success">Released</span> · <a data-page-id="theming" data-url-query="section=icons">Theming</a> is <span data-tag="warning">In review</span> · <a href="https://ant.design" data-new-tab>Ant Design</a> <i data-icon="external-link"></i></p><p><span data-status="success">Online</span> <span data-status="processing">Syncing</span> <span data-status="error">Offline</span></p><p><span data-tag>Design</span> <span data-tag>Engineering</span> <span data-tag>Support</span> <span data-tag="purple">Beta</span> <span data-tag="#0f766e">Custom colour</span></p>'
|
|
254
|
-
|
|
255
|
-
- title: Dates, numbers, avatars and copy
|
|
256
|
-
blocks:
|
|
257
|
-
- id: html_time_format
|
|
258
|
-
type: Html
|
|
259
|
-
properties:
|
|
260
|
-
html: '<p><span data-avatar="Jane Doe"></span> Jane Doe updated the invoice <time datetime="2026-01-05T09:30:00Z" data-time="relative"></time> (<time datetime="2026-01-05T09:30:00Z" data-time="D MMM YYYY"></time>) · <span data-format="currency" data-currency="USD">1234.5</span> · <span data-format="percent" data-decimals="1">0.123</span> of target · <span data-format="bytes">1536000</span> attached</p><p>Invoice number <code data-copy>INV-2026-0042</code> · owner <img data-avatar="Sam Smith" src="" style="--lf-avatar-size: 32px"></p>'
|
|
261
|
-
|
|
262
|
-
- title: Truncation and text tone
|
|
263
|
-
blocks:
|
|
264
|
-
- id: html_truncate_tone
|
|
265
|
-
type: Html
|
|
266
|
-
properties:
|
|
267
|
-
html: '<div style="max-width: 320px"><div data-truncate><b>Quarterly report for the northern region, including every branch and its targets</b></div><div data-truncate="2" data-tone="secondary">The report covers revenue, costs and headcount for each branch, compares them with the same quarter last year, and lists the actions each branch manager agreed for the next quarter.</div><div><span data-tone="tertiary">Updated 3 days ago</span> · <span data-tone="success">On track</span> · <span data-tone="quaternary">—</span></div></div>'
|
package/dist/blocks/Html/meta.js
CHANGED
|
@@ -19,28 +19,6 @@
|
|
|
19
19
|
cssKeys: {
|
|
20
20
|
element: 'The Html element.'
|
|
21
21
|
},
|
|
22
|
-
hazards: [
|
|
23
|
-
{
|
|
24
|
-
id: 'html-style-stripped',
|
|
25
|
-
message: 'Content is sanitised with DOMPurify, so <style>, <script> and inline event handlers are removed before render. Use DangerousHtml for a trusted <style> block, or style the block through its style and class properties.',
|
|
26
|
-
see: 'display-blocks/html'
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
id: 'html-no-click-events',
|
|
30
|
-
message: 'Html fires no events from its markup: data-event attributes do nothing here. Use ClickableHtml for clickable elements, including icons.',
|
|
31
|
-
see: 'display-blocks/clickablehtml'
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
id: 'html-hardcoded-links',
|
|
35
|
-
message: 'Link to app pages with <a data-page-id="page-id" data-url-query="key=value">, not <a href="/page-id?key=value">. A hard-coded href reloads the whole app on click, ignores basePath and is not checked by the build. Use data-new-tab, not target="_blank", which sanitising removes.',
|
|
36
|
-
see: 'concepts/html-attributes'
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
id: 'html-inline-status-pills',
|
|
40
|
-
message: 'Show statuses with <span data-tag="success">Approved</span> or <span data-status="warning">Syncing</span>, not inline-styled pills or hex status colours. data-tag and data-status follow the theme and dark mode and match the ag-grid tag cells.',
|
|
41
|
-
see: 'concepts/html-attributes'
|
|
42
|
-
}
|
|
43
|
-
],
|
|
44
22
|
events: {
|
|
45
23
|
onTextSelection: 'Trigger action when text is selected and pass selected text to the event object.'
|
|
46
24
|
},
|
|
@@ -50,7 +28,7 @@
|
|
|
50
28
|
properties: {
|
|
51
29
|
html: {
|
|
52
30
|
type: 'string',
|
|
53
|
-
description: 'Content to be rendered as Html.
|
|
31
|
+
description: 'Content to be rendered as Html.',
|
|
54
32
|
docs: {
|
|
55
33
|
displayType: 'text-area'
|
|
56
34
|
}
|
|
@@ -54,14 +54,3 @@ blocks:
|
|
|
54
54
|
params:
|
|
55
55
|
selected_text:
|
|
56
56
|
_event: selectedText
|
|
57
|
-
|
|
58
|
-
- id: html_enhanced
|
|
59
|
-
type: Html
|
|
60
|
-
properties:
|
|
61
|
-
html: >-
|
|
62
|
-
<i id="enh_icon" data-icon="edit"></i>
|
|
63
|
-
<span id="enh_tooltip" data-tooltip="<img src=x onerror="window.tooltipXss=1">">Hover</span>
|
|
64
|
-
<span id="enh_popover" data-popover="more">More</span>
|
|
65
|
-
<div data-popover-content="more" hidden><b class="enh-popover-body">Popover body</b></div>
|
|
66
|
-
<a id="enh_page_link" data-page-id="clickablehtml" data-url-query="tab=a">Clickable</a>
|
|
67
|
-
<a id="enh_dot_link" href="/.//evil.example/x" data-link>Dot link</a>
|