@lowdefy/blocks-basic 0.0.0-experimental-20260927140906 → 0.0.0-experimental-20260928062533
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/meta.js +2 -0
- package/dist/blocks/ClickableHtml/ClickableHtml.js +3 -1
- package/dist/blocks/ClickableHtml/gallery.yaml +19 -0
- package/dist/blocks/ClickableHtml/meta.js +45 -2
- package/dist/blocks/ClickableHtml/tests/ClickableHtml.e2e.yaml +91 -0
- package/dist/blocks/ClickableHtml/tests.yaml +13 -0
- package/dist/blocks/Html/tests/Html.e2e.yaml +1 -0
- package/dist/blocks/Img/meta.js +2 -0
- package/package.json +5 -5
|
@@ -76,10 +76,12 @@
|
|
|
76
76
|
},
|
|
77
77
|
href: {
|
|
78
78
|
type: 'string',
|
|
79
|
+
urlKind: 'href',
|
|
79
80
|
description: 'The href to link to when the anchor link is clicked.'
|
|
80
81
|
},
|
|
81
82
|
url: {
|
|
82
83
|
type: 'string',
|
|
84
|
+
urlKind: 'url',
|
|
83
85
|
description: 'External url to link to when the anchor link is clicked.'
|
|
84
86
|
},
|
|
85
87
|
rel: {
|
|
@@ -18,8 +18,10 @@ import { withBlockDefaults, HtmlComponent } from '@lowdefy/block-utils';
|
|
|
18
18
|
// (data-event="onEditClick" → events.onEditClick), so every target in the
|
|
19
19
|
// markup has its own action chain. Its other data-* attributes are the event
|
|
20
20
|
// object. HtmlComponent finds the target, including inside data-popover
|
|
21
|
-
// content, and prevents the element's default action.
|
|
21
|
+
// content, and prevents the element's default action. Only the events listed
|
|
22
|
+
// in properties.dataEvents fire, since the markup can hold data.
|
|
22
23
|
const ClickableHtml = ({ blockId, classNames, events, properties, methods, styles })=>/*#__PURE__*/ React.createElement(HtmlComponent, {
|
|
24
|
+
dataEvents: properties.dataEvents,
|
|
23
25
|
div: true,
|
|
24
26
|
events: events,
|
|
25
27
|
html: properties.html,
|
|
@@ -16,6 +16,9 @@
|
|
|
16
16
|
- id: buttons_basic
|
|
17
17
|
type: ClickableHtml
|
|
18
18
|
properties:
|
|
19
|
+
dataEvents:
|
|
20
|
+
- onSmallClick
|
|
21
|
+
- onLargeClick
|
|
19
22
|
html: '<p>Pick a size: <button data-event="onSmallClick">Small</button> <button data-event="onLargeClick">Large</button></p>'
|
|
20
23
|
events:
|
|
21
24
|
onSmallClick:
|
|
@@ -44,6 +47,8 @@
|
|
|
44
47
|
- id: list_rows
|
|
45
48
|
type: ClickableHtml
|
|
46
49
|
properties:
|
|
50
|
+
dataEvents:
|
|
51
|
+
- onRowClick
|
|
47
52
|
html: '<ul style="list-style: none; padding: 0; margin: 0;"><li data-event="onRowClick" data-record-id="rec_1" style="padding: 8px; cursor: pointer; border-bottom: 1px solid var(--ant-color-border);">First record</li><li data-event="onRowClick" data-record-id="rec_2" style="padding: 8px; cursor: pointer; border-bottom: 1px solid var(--ant-color-border);">Second record</li><li data-event="onRowClick" data-record-id="rec_3" style="padding: 8px; cursor: pointer;">Third record</li></ul>'
|
|
48
53
|
events:
|
|
49
54
|
onRowClick:
|
|
@@ -69,6 +74,8 @@
|
|
|
69
74
|
- id: mixed_content
|
|
70
75
|
type: ClickableHtml
|
|
71
76
|
properties:
|
|
77
|
+
dataEvents:
|
|
78
|
+
- onCommentClick
|
|
72
79
|
html: '<p>This <a href="https://lowdefy.com" target="_blank">link</a> navigates normally, but <a href="#" data-event="onCommentClick" data-thread-id="t_9">this one</a> fires onCommentClick instead.</p>'
|
|
73
80
|
events:
|
|
74
81
|
onCommentClick:
|
|
@@ -99,6 +106,9 @@
|
|
|
99
106
|
border: 1px solid var(--ant-color-border)
|
|
100
107
|
background: var(--ant-color-bg-container)
|
|
101
108
|
properties:
|
|
109
|
+
dataEvents:
|
|
110
|
+
- onEditClick
|
|
111
|
+
- onRemoveClick
|
|
102
112
|
html: '<h4 style="margin: 0 0 8px 0;">Card</h4><p style="margin: 0 0 8px 0; color: var(--ant-color-text-secondary);">Yours to change or remove until tomorrow.</p><button data-event="onEditClick">Edit</button> <button data-event="onRemoveClick">Remove</button>'
|
|
103
113
|
events:
|
|
104
114
|
onEditClick:
|
|
@@ -117,6 +127,11 @@
|
|
|
117
127
|
- id: row_actions
|
|
118
128
|
type: ClickableHtml
|
|
119
129
|
properties:
|
|
130
|
+
dataEvents:
|
|
131
|
+
- onEdit
|
|
132
|
+
- onDuplicate
|
|
133
|
+
- name: onDelete
|
|
134
|
+
confirm: Delete invoice INV-042?
|
|
120
135
|
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
136
|
events:
|
|
122
137
|
onEdit:
|
|
@@ -150,6 +165,10 @@
|
|
|
150
165
|
- id: confirm_actions
|
|
151
166
|
type: ClickableHtml
|
|
152
167
|
properties:
|
|
168
|
+
dataEvents:
|
|
169
|
+
- name: onDelete
|
|
170
|
+
confirm: true
|
|
171
|
+
- onArchive
|
|
153
172
|
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
173
|
events:
|
|
155
174
|
onDelete:
|
|
@@ -25,9 +25,14 @@
|
|
|
25
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
26
|
see: 'display-blocks/clickablehtml'
|
|
27
27
|
},
|
|
28
|
+
{
|
|
29
|
+
id: 'clickable-html-data-events',
|
|
30
|
+
message: 'List every event the HTML fires in properties.dataEvents: a data-event whose name is not listed does nothing. HTML built from user or request data must escape that data, so the data cannot add data-event elements of its own: _nunjucks escapes {{ values }} unless they are marked safe, while _string.concat and _js do not escape.',
|
|
31
|
+
see: 'display-blocks/clickablehtml'
|
|
32
|
+
},
|
|
28
33
|
{
|
|
29
34
|
id: 'clickable-html-confirm-destructive',
|
|
30
|
-
message: '
|
|
35
|
+
message: 'Give an event that deletes or changes data confirm in dataEvents ({ name: onDelete, confirm: "Delete this row?" }), so every click on it asks first and only OK fires it. data-confirm="Delete this row?" on the element asks too, but only where the markup says so.',
|
|
31
36
|
see: 'concepts/html-attributes'
|
|
32
37
|
}
|
|
33
38
|
],
|
|
@@ -41,9 +46,47 @@
|
|
|
41
46
|
type: 'object',
|
|
42
47
|
additionalProperties: false,
|
|
43
48
|
properties: {
|
|
49
|
+
dataEvents: {
|
|
50
|
+
type: 'array',
|
|
51
|
+
description: 'The events the HTML may fire. A data-event whose name is not listed does nothing, and a click on it logs a console warning; with no dataEvents the HTML fires no events. List an event by name, or as { name, confirm } to make every click on it ask first.',
|
|
52
|
+
items: {
|
|
53
|
+
oneOf: [
|
|
54
|
+
{
|
|
55
|
+
type: 'string',
|
|
56
|
+
description: 'An event name, as written in data-event.'
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
type: 'object',
|
|
60
|
+
additionalProperties: false,
|
|
61
|
+
required: [
|
|
62
|
+
'name'
|
|
63
|
+
],
|
|
64
|
+
properties: {
|
|
65
|
+
name: {
|
|
66
|
+
type: 'string',
|
|
67
|
+
description: 'An event name, as written in data-event.'
|
|
68
|
+
},
|
|
69
|
+
confirm: {
|
|
70
|
+
oneOf: [
|
|
71
|
+
{
|
|
72
|
+
type: 'boolean',
|
|
73
|
+
description: 'Ask before the event fires, whatever the HTML says, with the element\'s data-confirm message or "Are you sure?".'
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
type: 'string',
|
|
77
|
+
minLength: 1,
|
|
78
|
+
description: 'Ask before the event fires, whatever the HTML says, with this message.'
|
|
79
|
+
}
|
|
80
|
+
]
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
]
|
|
85
|
+
}
|
|
86
|
+
},
|
|
44
87
|
html: {
|
|
45
88
|
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" }. Targets that are not links or buttons become keyboard focusable, and Enter or Space clicks them. A data-event inside popover content fires too, then closes the popover. A link with data-event fires the event and does not navigate. data-confirm="Delete this row?" on a data-event element asks first: only OK fires the event (bare data-confirm asks "Are you sure?"). All Html block attributes work too: data-icon, data-tooltip, data-popover, data-page-id links, data-new-tab, data-tag, data-status, data-time, data-format, data-avatar, data-copy, data-truncate and data-tone. See the HTML attributes docs page.',
|
|
89
|
+
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), if dataEvents lists it, 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" }. Targets that are not links or buttons become keyboard focusable, and Enter or Space clicks them. A data-event inside popover content fires too, then closes the popover. A link with data-event fires the event and does not navigate. data-confirm="Delete this row?" on a data-event element asks first: only OK fires the event (bare data-confirm asks "Are you sure?"). Escape user and request data in the HTML, so it cannot add data-event elements of its own. All Html block attributes work too: data-icon, data-tooltip, data-popover, data-page-id links, data-new-tab, data-tag, data-status, data-time, data-format, data-avatar, data-copy, data-truncate and data-tone. See the HTML attributes docs page.',
|
|
47
90
|
docs: {
|
|
48
91
|
displayType: 'text-area'
|
|
49
92
|
}
|
|
@@ -18,6 +18,9 @@ blocks:
|
|
|
18
18
|
- id: clickable_basic
|
|
19
19
|
type: ClickableHtml
|
|
20
20
|
properties:
|
|
21
|
+
dataEvents:
|
|
22
|
+
- onGreetClick
|
|
23
|
+
- onWaveClick
|
|
21
24
|
html: '<p>Hello <button data-event="onGreetClick" data-user-id="u_1">World</button> <button data-event="onWaveClick" data-user-id="u_2">Wave</button></p>'
|
|
22
25
|
events:
|
|
23
26
|
onGreetClick:
|
|
@@ -71,6 +74,8 @@ blocks:
|
|
|
71
74
|
- id: clickable_confirm
|
|
72
75
|
type: ClickableHtml
|
|
73
76
|
properties:
|
|
77
|
+
dataEvents:
|
|
78
|
+
- onDelete
|
|
74
79
|
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
80
|
events:
|
|
76
81
|
onDelete:
|
|
@@ -95,3 +100,89 @@ blocks:
|
|
|
95
100
|
key: delete_count
|
|
96
101
|
default: 0
|
|
97
102
|
- '</span>'
|
|
103
|
+
|
|
104
|
+
- id: clickable_allowlist
|
|
105
|
+
type: ClickableHtml
|
|
106
|
+
properties:
|
|
107
|
+
dataEvents:
|
|
108
|
+
- onListedClick
|
|
109
|
+
html: '<span id="listed_target" data-event="onListedClick">Listed</span> <span id="unlisted_target" data-event="onUnlistedClick">Unlisted</span>'
|
|
110
|
+
events:
|
|
111
|
+
onListedClick:
|
|
112
|
+
- id: set_listed
|
|
113
|
+
type: SetState
|
|
114
|
+
params:
|
|
115
|
+
allowlist_fired: listed
|
|
116
|
+
onUnlistedClick:
|
|
117
|
+
- id: set_unlisted
|
|
118
|
+
type: SetState
|
|
119
|
+
params:
|
|
120
|
+
allowlist_fired: unlisted
|
|
121
|
+
|
|
122
|
+
- id: clickable_declared_confirm
|
|
123
|
+
type: ClickableHtml
|
|
124
|
+
properties:
|
|
125
|
+
dataEvents:
|
|
126
|
+
- name: onRemove
|
|
127
|
+
confirm: Remove row 3?
|
|
128
|
+
html: '<button id="declared_remove" data-event="onRemove" data-row-id="3">Remove</button>'
|
|
129
|
+
events:
|
|
130
|
+
onRemove:
|
|
131
|
+
- id: set_removed
|
|
132
|
+
type: SetState
|
|
133
|
+
params:
|
|
134
|
+
removed_row:
|
|
135
|
+
_event: row_id
|
|
136
|
+
|
|
137
|
+
- id: clickable_refresh
|
|
138
|
+
type: ClickableHtml
|
|
139
|
+
properties:
|
|
140
|
+
dataEvents:
|
|
141
|
+
- onRefreshSoon
|
|
142
|
+
- onRefreshDelete
|
|
143
|
+
html:
|
|
144
|
+
_string.concat:
|
|
145
|
+
- '<button id="refresh_soon" data-event="onRefreshSoon">Refresh soon</button><p id="refresh_count">Refreshed '
|
|
146
|
+
- _state:
|
|
147
|
+
key: refresh_count
|
|
148
|
+
default: 0
|
|
149
|
+
- '</p><button id="refresh_delete" data-event="onRefreshDelete" data-id="5" data-confirm="Delete 5?">Delete</button> <span id="refresh_more" data-popover="more">More</span><div data-popover-content="more" hidden><span class="refresh-menu">Menu after '
|
|
150
|
+
- _state:
|
|
151
|
+
key: refresh_count
|
|
152
|
+
default: 0
|
|
153
|
+
- '</span></div>'
|
|
154
|
+
events:
|
|
155
|
+
onRefreshSoon:
|
|
156
|
+
- id: wait
|
|
157
|
+
type: Wait
|
|
158
|
+
params:
|
|
159
|
+
ms: 1000
|
|
160
|
+
- id: refresh
|
|
161
|
+
type: SetState
|
|
162
|
+
params:
|
|
163
|
+
refresh_count: 1
|
|
164
|
+
onRefreshDelete:
|
|
165
|
+
- id: set_refresh_deleted
|
|
166
|
+
type: SetState
|
|
167
|
+
params:
|
|
168
|
+
refresh_deleted:
|
|
169
|
+
_event: id
|
|
170
|
+
|
|
171
|
+
- id: clickable_events_result
|
|
172
|
+
type: Html
|
|
173
|
+
properties:
|
|
174
|
+
html:
|
|
175
|
+
_string.concat:
|
|
176
|
+
- '<span id="allowlist_fired">'
|
|
177
|
+
- _state:
|
|
178
|
+
key: allowlist_fired
|
|
179
|
+
default: ''
|
|
180
|
+
- '</span><span id="removed_row">'
|
|
181
|
+
- _state:
|
|
182
|
+
key: removed_row
|
|
183
|
+
default: ''
|
|
184
|
+
- '</span><span id="refresh_deleted">'
|
|
185
|
+
- _state:
|
|
186
|
+
key: refresh_deleted
|
|
187
|
+
default: ''
|
|
188
|
+
- '</span>'
|
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
- id: properties.html
|
|
17
17
|
type: ClickableHtml
|
|
18
18
|
properties:
|
|
19
|
+
dataEvents:
|
|
20
|
+
- onGoClick
|
|
19
21
|
html: |
|
|
20
22
|
<p>Plain markup <button data-event="onGoClick" data-item-id="1">Go</button></p>
|
|
21
23
|
- id: properties.html-no-events
|
|
@@ -26,6 +28,8 @@
|
|
|
26
28
|
- id: properties.html-bad-code
|
|
27
29
|
type: ClickableHtml
|
|
28
30
|
properties:
|
|
31
|
+
dataEvents:
|
|
32
|
+
- onOkClick
|
|
29
33
|
html: |
|
|
30
34
|
<button data-event="onOkClick" onclick="alert('inline handler stripped')">Ok</button>
|
|
31
35
|
<script>alert('script tag');</script>
|
|
@@ -33,3 +37,12 @@
|
|
|
33
37
|
type: ClickableHtml
|
|
34
38
|
properties:
|
|
35
39
|
html: 0
|
|
40
|
+
- id: properties.dataEvents
|
|
41
|
+
type: ClickableHtml
|
|
42
|
+
properties:
|
|
43
|
+
dataEvents:
|
|
44
|
+
- onEditClick
|
|
45
|
+
- name: onDeleteClick
|
|
46
|
+
confirm: Delete this row?
|
|
47
|
+
html: |
|
|
48
|
+
<p><button data-event="onEditClick">Edit</button> <button data-event="onDeleteClick">Delete</button></p>
|
|
@@ -65,3 +65,4 @@ blocks:
|
|
|
65
65
|
<div data-popover-content="more" hidden><b class="enh-popover-body">Popover body</b></div>
|
|
66
66
|
<a id="enh_page_link" data-page-id="clickablehtml" data-url-query="tab=a">Clickable</a>
|
|
67
67
|
<a id="enh_dot_link" href="/.//evil.example/x" data-link>Dot link</a>
|
|
68
|
+
<span id="enh_copy_long" data-copy="npm install lowdefy-package-with-a-long-name --save-dev">Install</span>
|
package/dist/blocks/Img/meta.js
CHANGED
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
properties: {
|
|
29
29
|
src: {
|
|
30
30
|
type: 'string',
|
|
31
|
+
urlKind: 'src',
|
|
31
32
|
description: 'The image URL.'
|
|
32
33
|
},
|
|
33
34
|
alt: {
|
|
@@ -69,6 +70,7 @@
|
|
|
69
70
|
},
|
|
70
71
|
srcSet: {
|
|
71
72
|
type: 'string',
|
|
73
|
+
urlKind: 'srcSet',
|
|
72
74
|
description: 'Possible image sources for the user agent to use, strings separated by commas.',
|
|
73
75
|
docs: {
|
|
74
76
|
displayType: 'text-area'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lowdefy/blocks-basic",
|
|
3
|
-
"version": "0.0.0-experimental-
|
|
3
|
+
"version": "0.0.0-experimental-20260928062533",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "Basic html Lowdefy blocks.",
|
|
6
6
|
"homepage": "https://lowdefy.com",
|
|
@@ -45,8 +45,8 @@
|
|
|
45
45
|
"dist/*"
|
|
46
46
|
],
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@lowdefy/block-utils": "0.0.0-experimental-
|
|
49
|
-
"@lowdefy/helpers": "0.0.0-experimental-
|
|
48
|
+
"@lowdefy/block-utils": "0.0.0-experimental-20260928062533",
|
|
49
|
+
"@lowdefy/helpers": "0.0.0-experimental-20260928062533",
|
|
50
50
|
"dompurify": "3.4.13"
|
|
51
51
|
},
|
|
52
52
|
"peerDependencies": {
|
|
@@ -54,8 +54,8 @@
|
|
|
54
54
|
"react-dom": ">=18"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
|
-
"@lowdefy/block-dev-e2e": "0.0.0-experimental-
|
|
58
|
-
"@lowdefy/e2e-utils": "0.0.0-experimental-
|
|
57
|
+
"@lowdefy/block-dev-e2e": "0.0.0-experimental-20260928062533",
|
|
58
|
+
"@lowdefy/e2e-utils": "0.0.0-experimental-20260928062533",
|
|
59
59
|
"@playwright/test": "1.59.1",
|
|
60
60
|
"@swc/cli": "0.8.1",
|
|
61
61
|
"@swc/core": "1.15.32",
|