@lowdefy/docs-content 0.0.0-experimental-20260710073520

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.
Files changed (304) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +20 -0
  3. package/content/actions/callapi.md +66 -0
  4. package/content/actions/callmethod.md +41 -0
  5. package/content/actions/copytoclipboard.md +32 -0
  6. package/content/actions/displaymessage.md +53 -0
  7. package/content/actions/downloadcsv.md +89 -0
  8. package/content/actions/fetch.md +50 -0
  9. package/content/actions/geolocationcurrentposition.md +56 -0
  10. package/content/actions/link.md +104 -0
  11. package/content/actions/login.md +85 -0
  12. package/content/actions/logout.md +56 -0
  13. package/content/actions/pdfmake.md +304 -0
  14. package/content/actions/request.md +67 -0
  15. package/content/actions/reset.md +27 -0
  16. package/content/actions/resetvalidation.md +85 -0
  17. package/content/actions/scrollto.md +85 -0
  18. package/content/actions/setdarkmode.md +62 -0
  19. package/content/actions/setfocus.md +33 -0
  20. package/content/actions/setglobal.md +63 -0
  21. package/content/actions/setlocale.md +69 -0
  22. package/content/actions/setstate.md +70 -0
  23. package/content/actions/throw.md +72 -0
  24. package/content/actions/validate.md +87 -0
  25. package/content/actions/wait.md +24 -0
  26. package/content/agents/agent-endpoint-tools.md +190 -0
  27. package/content/agents/agent-mcp-tools.md +124 -0
  28. package/content/agents/agent-multi-agent.md +136 -0
  29. package/content/agents/agent-properties.md +174 -0
  30. package/content/agents/agent-server-hooks.md +336 -0
  31. package/content/agents/agentchat.md +515 -0
  32. package/content/agents/agentconversations.md +148 -0
  33. package/content/concepts/ai-agent-docs.md +190 -0
  34. package/content/concepts/cli.md +213 -0
  35. package/content/concepts/connections-and-requests.md +7 -0
  36. package/content/concepts/custom-html.md +3 -0
  37. package/content/concepts/custom-styling.md +161 -0
  38. package/content/concepts/events-and-actions.md +271 -0
  39. package/content/concepts/hosting-files.md +18 -0
  40. package/content/concepts/i18n.md +320 -0
  41. package/content/concepts/keyboard-shortcuts.md +218 -0
  42. package/content/concepts/layout-overview.md +478 -0
  43. package/content/concepts/lists.md +144 -0
  44. package/content/concepts/logger.md +43 -0
  45. package/content/concepts/lowdefy-schema.md +365 -0
  46. package/content/concepts/menus.md +144 -0
  47. package/content/concepts/module-authoring.md +564 -0
  48. package/content/concepts/modules.md +338 -0
  49. package/content/concepts/operators.md +45 -0
  50. package/content/concepts/overview.md +19 -0
  51. package/content/concepts/references-and-templates.md +207 -0
  52. package/content/concepts/secrets.md +24 -0
  53. package/content/concepts/selectors.md +143 -0
  54. package/content/connections/amazonredshift.md +176 -0
  55. package/content/connections/anthropic.md +232 -0
  56. package/content/connections/awss3.md +313 -0
  57. package/content/connections/azureblobstorage.md +133 -0
  58. package/content/connections/elasticsearch.md +371 -0
  59. package/content/connections/google.md +228 -0
  60. package/content/connections/googlecloudstorage.md +139 -0
  61. package/content/connections/googlesheet.md +313 -0
  62. package/content/connections/knex.md +206 -0
  63. package/content/connections/mariadb.md +177 -0
  64. package/content/connections/mcp.md +134 -0
  65. package/content/connections/mongodb.md +739 -0
  66. package/content/connections/mssql.md +191 -0
  67. package/content/connections/mysql.md +192 -0
  68. package/content/connections/openai-connection.md +228 -0
  69. package/content/connections/postgresql.md +200 -0
  70. package/content/connections/redis.md +116 -0
  71. package/content/connections/sendgridmail.md +94 -0
  72. package/content/connections/smtp.md +149 -0
  73. package/content/connections/sqlite.md +187 -0
  74. package/content/connections/stripe.md +115 -0
  75. package/content/container-blocks/affix.md +413 -0
  76. package/content/container-blocks/alert.md +937 -0
  77. package/content/container-blocks/badge.md +1222 -0
  78. package/content/container-blocks/box.md +1453 -0
  79. package/content/container-blocks/card.md +1200 -0
  80. package/content/container-blocks/carousel.md +2247 -0
  81. package/content/container-blocks/collapse.md +1335 -0
  82. package/content/container-blocks/configprovider.md +1070 -0
  83. package/content/container-blocks/confirmmodal.md +1159 -0
  84. package/content/container-blocks/content.md +597 -0
  85. package/content/container-blocks/descriptions.md +870 -0
  86. package/content/container-blocks/drawer.md +1379 -0
  87. package/content/container-blocks/dropdownmenu.md +643 -0
  88. package/content/container-blocks/flex.md +1510 -0
  89. package/content/container-blocks/footer.md +380 -0
  90. package/content/container-blocks/googlemaps.md +546 -0
  91. package/content/container-blocks/googlemapsheatmap.md +607 -0
  92. package/content/container-blocks/googlemapsscript.md +61 -0
  93. package/content/container-blocks/header.md +302 -0
  94. package/content/container-blocks/label.md +739 -0
  95. package/content/container-blocks/layout.md +604 -0
  96. package/content/container-blocks/masonry.md +1090 -0
  97. package/content/container-blocks/mobilemenu.md +1244 -0
  98. package/content/container-blocks/modal.md +1180 -0
  99. package/content/container-blocks/pageheadermenu.md +614 -0
  100. package/content/container-blocks/pagesidebarlayout.md +438 -0
  101. package/content/container-blocks/pagesidermenu.md +651 -0
  102. package/content/container-blocks/popover.md +1421 -0
  103. package/content/container-blocks/result.md +972 -0
  104. package/content/container-blocks/sider.md +1064 -0
  105. package/content/container-blocks/span.md +747 -0
  106. package/content/container-blocks/spinner.md +267 -0
  107. package/content/container-blocks/splitter.md +1735 -0
  108. package/content/container-blocks/tabs.md +1718 -0
  109. package/content/container-blocks/tooltip.md +1274 -0
  110. package/content/container-blocks/watermark.md +515 -0
  111. package/content/controls/for.md +103 -0
  112. package/content/controls/if.md +107 -0
  113. package/content/controls/log.md +50 -0
  114. package/content/controls/parallel.md +71 -0
  115. package/content/controls/parallel_for.md +36 -0
  116. package/content/controls/reject.md +56 -0
  117. package/content/controls/return.md +66 -0
  118. package/content/controls/set_state.md +98 -0
  119. package/content/controls/switch.md +90 -0
  120. package/content/controls/throw.md +79 -0
  121. package/content/controls/try.md +88 -0
  122. package/content/deployment/docker.md +149 -0
  123. package/content/deployment/node-server.md +27 -0
  124. package/content/deployment/vercel.md +101 -0
  125. package/content/display-blocks/aggrid.md +1459 -0
  126. package/content/display-blocks/anchor.md +336 -0
  127. package/content/display-blocks/avatar.md +1154 -0
  128. package/content/display-blocks/breadcrumb.md +517 -0
  129. package/content/display-blocks/button.md +758 -0
  130. package/content/display-blocks/calendar.md +156 -0
  131. package/content/display-blocks/dangeroushtml.md +314 -0
  132. package/content/display-blocks/dangerousmarkdown.md +423 -0
  133. package/content/display-blocks/diffgit.md +44 -0
  134. package/content/display-blocks/difflist.md +225 -0
  135. package/content/display-blocks/diffsidebyside.md +56 -0
  136. package/content/display-blocks/difftimeline.md +94 -0
  137. package/content/display-blocks/divider.md +406 -0
  138. package/content/display-blocks/download.md +60 -0
  139. package/content/display-blocks/dropdownbutton.md +661 -0
  140. package/content/display-blocks/echart.md +418 -0
  141. package/content/display-blocks/floatbutton.md +545 -0
  142. package/content/display-blocks/html.md +311 -0
  143. package/content/display-blocks/icon.md +717 -0
  144. package/content/display-blocks/img.md +479 -0
  145. package/content/display-blocks/markdown.md +520 -0
  146. package/content/display-blocks/markdownwithcode.md +730 -0
  147. package/content/display-blocks/menu.md +1123 -0
  148. package/content/display-blocks/message.md +941 -0
  149. package/content/display-blocks/notification.md +1410 -0
  150. package/content/display-blocks/paragraph.md +643 -0
  151. package/content/display-blocks/progress.md +818 -0
  152. package/content/display-blocks/qrcode.md +519 -0
  153. package/content/display-blocks/s3download.md +240 -0
  154. package/content/display-blocks/search.md +360 -0
  155. package/content/display-blocks/skeleton.md +272 -0
  156. package/content/display-blocks/skeletonavatar.md +222 -0
  157. package/content/display-blocks/skeletonbutton.md +245 -0
  158. package/content/display-blocks/skeletoninput.md +223 -0
  159. package/content/display-blocks/skeletonparagraph.md +201 -0
  160. package/content/display-blocks/statistic.md +485 -0
  161. package/content/display-blocks/steps.md +585 -0
  162. package/content/display-blocks/tag.md +620 -0
  163. package/content/display-blocks/title.md +654 -0
  164. package/content/display-blocks/tour.md +2359 -0
  165. package/content/input-blocks/autocomplete.md +786 -0
  166. package/content/input-blocks/buttonselector.md +964 -0
  167. package/content/input-blocks/checkboxselector.md +765 -0
  168. package/content/input-blocks/checkboxswitch.md +497 -0
  169. package/content/input-blocks/colorselector.md +884 -0
  170. package/content/input-blocks/daterangeselector.md +777 -0
  171. package/content/input-blocks/dateselector.md +693 -0
  172. package/content/input-blocks/datetimeselector.md +791 -0
  173. package/content/input-blocks/inputgallery.md +528 -0
  174. package/content/input-blocks/monthselector.md +717 -0
  175. package/content/input-blocks/multipleselector.md +1337 -0
  176. package/content/input-blocks/numberinput.md +855 -0
  177. package/content/input-blocks/pagination.md +679 -0
  178. package/content/input-blocks/paragraphinput.md +1664 -0
  179. package/content/input-blocks/passwordinput.md +480 -0
  180. package/content/input-blocks/phonenumberinput.md +688 -0
  181. package/content/input-blocks/radioselector.md +820 -0
  182. package/content/input-blocks/ratingslider.md +684 -0
  183. package/content/input-blocks/s3uploadbutton.md +384 -0
  184. package/content/input-blocks/s3uploaddragger.md +305 -0
  185. package/content/input-blocks/s3uploadphoto.md +288 -0
  186. package/content/input-blocks/segmentedselector.md +782 -0
  187. package/content/input-blocks/selector.md +1162 -0
  188. package/content/input-blocks/switch.md +552 -0
  189. package/content/input-blocks/textarea.md +714 -0
  190. package/content/input-blocks/textinput.md +639 -0
  191. package/content/input-blocks/tiptapinput.md +226 -0
  192. package/content/input-blocks/tiptapmentioninput.md +471 -0
  193. package/content/input-blocks/titleinput.md +1094 -0
  194. package/content/input-blocks/treeinput.md +144 -0
  195. package/content/input-blocks/treemultipleselector.md +162 -0
  196. package/content/input-blocks/treeselector.md +185 -0
  197. package/content/input-blocks/upload.md +149 -0
  198. package/content/input-blocks/uploaddragger.md +85 -0
  199. package/content/input-blocks/uploadphoto.md +84 -0
  200. package/content/input-blocks/weekselector.md +630 -0
  201. package/content/list-blocks/controlledlist.md +498 -0
  202. package/content/list-blocks/list.md +529 -0
  203. package/content/list-blocks/listselector.md +301 -0
  204. package/content/list-blocks/masonrylist.md +230 -0
  205. package/content/migration/upgrade-guide.md +106 -0
  206. package/content/migration/v4-to-v5.md +589 -0
  207. package/content/migration/v5-to-v6.md +36 -0
  208. package/content/operators/_actions.md +58 -0
  209. package/content/operators/_and.md +76 -0
  210. package/content/operators/_api.md +254 -0
  211. package/content/operators/_app.md +114 -0
  212. package/content/operators/_args.md +65 -0
  213. package/content/operators/_array.md +331 -0
  214. package/content/operators/_base64.md +49 -0
  215. package/content/operators/_boolean.md +33 -0
  216. package/content/operators/_build.md +166 -0
  217. package/content/operators/_change_case.md +357 -0
  218. package/content/operators/_date.md +415 -0
  219. package/content/operators/_dayjs.md +128 -0
  220. package/content/operators/_diff.md +61 -0
  221. package/content/operators/_divide.md +32 -0
  222. package/content/operators/_eq.md +52 -0
  223. package/content/operators/_event.md +86 -0
  224. package/content/operators/_function.md +52 -0
  225. package/content/operators/_get.md +92 -0
  226. package/content/operators/_global.md +86 -0
  227. package/content/operators/_gt.md +50 -0
  228. package/content/operators/_gte.md +50 -0
  229. package/content/operators/_hash.md +112 -0
  230. package/content/operators/_if.md +30 -0
  231. package/content/operators/_if_none.md +47 -0
  232. package/content/operators/_index.md +48 -0
  233. package/content/operators/_input.md +86 -0
  234. package/content/operators/_intl.md +135 -0
  235. package/content/operators/_item.md +166 -0
  236. package/content/operators/_js.md +113 -0
  237. package/content/operators/_json.md +120 -0
  238. package/content/operators/_jsonata.md +152 -0
  239. package/content/operators/_locale.md +65 -0
  240. package/content/operators/_location.md +40 -0
  241. package/content/operators/_log.md +22 -0
  242. package/content/operators/_lt.md +50 -0
  243. package/content/operators/_lte.md +50 -0
  244. package/content/operators/_math.md +407 -0
  245. package/content/operators/_media.md +83 -0
  246. package/content/operators/_menu.md +62 -0
  247. package/content/operators/_module.md +340 -0
  248. package/content/operators/_mql.md +95 -0
  249. package/content/operators/_ne.md +62 -0
  250. package/content/operators/_not.md +33 -0
  251. package/content/operators/_number.md +159 -0
  252. package/content/operators/_nunjucks.md +117 -0
  253. package/content/operators/_object.md +253 -0
  254. package/content/operators/_operator.md +33 -0
  255. package/content/operators/_or.md +67 -0
  256. package/content/operators/_product.md +45 -0
  257. package/content/operators/_random.md +90 -0
  258. package/content/operators/_ref.md +80 -0
  259. package/content/operators/_regex.md +69 -0
  260. package/content/operators/_request.md +35 -0
  261. package/content/operators/_request_details.md +29 -0
  262. package/content/operators/_secret.md +56 -0
  263. package/content/operators/_state.md +134 -0
  264. package/content/operators/_step.md +98 -0
  265. package/content/operators/_string.md +327 -0
  266. package/content/operators/_subtract.md +24 -0
  267. package/content/operators/_sum.md +45 -0
  268. package/content/operators/_switch.md +37 -0
  269. package/content/operators/_t.md +96 -0
  270. package/content/operators/_theme.md +65 -0
  271. package/content/operators/_type.md +78 -0
  272. package/content/operators/_uri.md +49 -0
  273. package/content/operators/_url_query.md +92 -0
  274. package/content/operators/_user.md +154 -0
  275. package/content/operators/_uuid.md +118 -0
  276. package/content/operators/_var.md +88 -0
  277. package/content/operators/_yaml.md +96 -0
  278. package/content/other/introduction.md +39 -0
  279. package/content/other/next-auth-providers.md +3 -0
  280. package/content/other/updatesession.md +26 -0
  281. package/content/plugins/plugins-actions.md +80 -0
  282. package/content/plugins/plugins-connections.md +98 -0
  283. package/content/plugins/plugins-dev.md +138 -0
  284. package/content/plugins/plugins-introduction.md +29 -0
  285. package/content/plugins/plugins-operators.md +71 -0
  286. package/content/testing/e2e-auth.md +108 -0
  287. package/content/testing/e2e-configuration.md +107 -0
  288. package/content/testing/e2e-getting-started.md +96 -0
  289. package/content/testing/e2e-introduction.md +53 -0
  290. package/content/testing/e2e-mocking.md +155 -0
  291. package/content/testing/e2e-writing-tests.md +214 -0
  292. package/content/tutorial/tutorial-actions-operators.md +222 -0
  293. package/content/tutorial/tutorial-add-blocks.md +86 -0
  294. package/content/tutorial/tutorial-create-page.md +57 -0
  295. package/content/tutorial/tutorial-display-data-page.md +181 -0
  296. package/content/tutorial/tutorial-next-steps.md +53 -0
  297. package/content/tutorial/tutorial-requests-sql.md +22 -0
  298. package/content/tutorial/tutorial-start.md +71 -0
  299. package/content/user-authentication/auth-providers.md +15 -0
  300. package/content/user-authentication/login-and-logout.md +122 -0
  301. package/content/user-authentication/users-introduction.md +31 -0
  302. package/index.json +2281 -0
  303. package/package.json +34 -0
  304. package/scripts/extractAgentDocs.js +130 -0
@@ -0,0 +1,271 @@
1
+ # Events and Actions
2
+
3
+ Blocks can define _events_ which the block can trigger when something happens on the page, like a button being clicked, an input's value being modified or a page being loaded. Some examples are `onClick` on a [`Button`](/Button) or `onMount` on a [`PageHeaderMenu`](/PageHeaderMenu) block.
4
+
5
+ All blocks implement `onMount` and `onMountAsync` events. These are useful for triggering actions when a block is mounted. For the `onMount` event, the block only mounts when the event action chain is completed, however, for the `onMountAsync` event, the block will mount as soon as possible while the event actions completes execution.
6
+
7
+ _Actions_ are tasks that can be executed, like calling a request, linking to a new page or changing a value in state. An array of actions can be defined for an event on a block. If that event gets triggered, those actions will execute sequentially.
8
+
9
+ The chain of actions will stop executing if the action raises a break condition, or if the action throws an unexpected error.
10
+
11
+ If a break condition was raised, the user will be shown an error message and no further actions will execute. If an unexpected error is thrown, the app will show an error screen and the error will be logged. To handle errors and break conditions, a `catch` action chain can be defined on the event to handle the error, as described below.
12
+
13
+ Actions which are `async: true` are an exception to the sequential rule of the actions chain. These actions will be executed asynchronously and the next actions in the chain will not wait for them to finish. If any `async: true` action throws an error, the chain will not be stopped and the event will still be completed successfully.
14
+
15
+ Each action has an `id`, unique to that action chain, and a `type` field which are required.
16
+
17
+ Actions can have a `params` field for specifying input parameters when executing the action. Operators used in action `params` will be evaluated right before the action is executed. Some events might have data relating to that event, such as what the new value of an input is, or the row that was clicked in a table. The `event` object can be used in the action using the [`_event`](/_event) operator. Some actions also return values which can be passed to succeeding actions in the same action chain using the [`_actions`](/_actions) operator.
18
+
19
+ Actions can also have a `skip` field. Operators in the `skip` field will be evaluated before an action is executed, and if the evaluated result is `true`, that action is skipped and the next action is executed.
20
+
21
+ ## Action Schema
22
+
23
+ The schema for a Lowdefy action is:
24
+
25
+ - `id: string`: __Required__ - An identifier for the action. It must be unique within the action chain it is defined in.
26
+ - `type: string`: __Required__ - The action type to be used. It must be a valid action type.
27
+ - `skip: boolean`: The test that determines whether the action will be skipped or not. This is usually written as operators which evaluates to a `true` or `false`. __Operators are evaluated__.
28
+ - `async: boolean`: This determines whether the action will be evaluated asynchronously. Operators are __not__ evaluated on `async`.
29
+ - `messages: object`: __Operators are evaluated__.
30
+ - `error: boolean | string`: If `boolean`, whether an error message should be displayed if the action throws an error. Error messages are shown by default. If a `string`, the error message to show to the user.
31
+ - `loading: boolean | string`: If `boolean`, whether a loading message should be displayed while the action is executing. Loading messages are not shown by default. If a `string`, the loading message to show to the user.
32
+ - `success: boolean | string`: If `boolean`, whether a success message should be displayed if the action completes successfully. Success messages are not shown by default. If a `string`, the success message to show to the user.
33
+ - `params: object`: The input passed to the action. __Operators are evaluated__.
34
+
35
+ ###### Events and actions definition example:
36
+ ```yaml
37
+ - id: block_with_actions
38
+ type: Block
39
+ properties:
40
+ # ...
41
+ events:
42
+ onEvent1:
43
+ - id: action1
44
+ type: ActionType1
45
+ skip:
46
+ # Operator expression that returns true if action should be skipped.
47
+ params:
48
+ # ...
49
+ - id: action2
50
+ type: ActionType2
51
+ onEvent2:
52
+ - id: action3
53
+ type: ActionType3
54
+ params:
55
+ # ...
56
+ ```
57
+ ## The actions object
58
+
59
+ When events are triggered, each completed action writes its response to the actions object under the action id object key. Thus all following actions in a event action list have access to the responses of all preceding actions in the same event list through the [`_actions`](/_actions) operator.
60
+
61
+ ## The event object
62
+
63
+ When events are triggered, they can provide a data object describing the event (e.g. a description of the clicked item or uploaded file). This data object can be accessed using the [`_event`](/_event) operator in an action definition.
64
+
65
+ The schema for passing actions to Lowdefy events is:
66
+ ```
67
+ (eventName: (action | control)[])
68
+ (eventName: {
69
+ shortcut?: string | string[],
70
+ debounce?: {
71
+ ms?: number,
72
+ immediate?: boolean,
73
+ },
74
+ try: (action | control)[],
75
+ catch?: (action | control)[],
76
+ })
77
+ ```
78
+
79
+ ## Catching action errors
80
+
81
+ If one action in the chain of event actions fails by throwing an error, the actions in the list following the failed action will not be executed. To handle any errors thrown by an action, Lowdefy event actions can be provided as lists of `try` and `catch` actions.
82
+
83
+ ###### Event try catch actions example for dealing with action errors:
84
+ ```yaml
85
+ - id: block_with_actions
86
+ type: Block
87
+ properties:
88
+ # ...
89
+ events:
90
+ onEvent1:
91
+ try:
92
+ - id: action1
93
+ type: ActionType1
94
+ params:
95
+ # ...
96
+ - id: action2
97
+ type: ActionType2
98
+ catch:
99
+ - id: unsuccessful
100
+ type: ActionType1
101
+ params:
102
+ # ...
103
+ ```
104
+
105
+ ## Control flow in action lists
106
+
107
+ An item in an action list is either an action (`id` and `type`) or a control. Action lists support the routine controls [`:if`](/:if), [`:switch`](/:switch) and [`:return`](/:return):
108
+
109
+ - [`:if`](/:if): Evaluates a condition and executes the `:then` action list if the result is truthy, else the optional `:else` action list.
110
+ - [`:switch`](/:switch): Evaluates `:case` conditions in order and executes the `:then` action list of the first truthy case — later cases are never evaluated. If no case matches, the optional `:default` action list is executed.
111
+ - [`:return`](/:return): Ends the whole event successfully. No further actions execute — not even in enclosing lists — and the event's `catch` actions do not run. A `:return` inside a `catch` list ends the remaining catch actions the same way, but the event keeps its error result.
112
+
113
+ Branch lists are action lists themselves, so controls can nest, and controls can be used in both `try` and `catch` action lists.
114
+
115
+ ###### Control flow example:
116
+ ```yaml
117
+ events:
118
+ onClick:
119
+ - id: validate
120
+ type: Validate
121
+ - :if:
122
+ _not:
123
+ _state: skip_reopen
124
+ :then:
125
+ - id: reopen_ticket
126
+ type: Request
127
+ params: reopen_ticket
128
+ - id: redirect
129
+ type: Link
130
+ params:
131
+ pageId: ticket-view
132
+ :else:
133
+ - id: show_blocked
134
+ type: DisplayMessage
135
+ params:
136
+ content: Ticket cannot be reopened.
137
+ status: warning
138
+ ```
139
+
140
+ Actions inside branches are ordinary actions — `skip`, `messages`, `async` and error behavior are unchanged. Actions the event does not execute for a control-flow reason — actions in an untaken branch, in an unmatched case, or after a `:return` — are recorded as skipped, so [`_actions`](/_actions) lookups like `_actions: my_action.skipped` keep working.
141
+
142
+ ### When to use which
143
+
144
+ - `skip` gates a single action.
145
+ - `:if` gates a group of consecutive actions with one condition.
146
+ - `:switch` replaces a chain of nested `:if`s over mutually exclusive alternatives.
147
+ - `:return` ends the event early — replacing the workaround of throwing an error in a `try` list.
148
+
149
+ Deep control nesting in an event is a sign the logic belongs in an [API routine](/lowdefy-api).
150
+
151
+ ### Routine controls in events
152
+
153
+ The control grammar is shared with [API routines](/lowdefy-api): where a control exists on both sides, the syntax and semantics match.
154
+
155
+ | Routine control | In events | Client answer |
156
+ | --- | --- | --- |
157
+ | `:if` | Yes | Same syntax and semantics as in routines. |
158
+ | `:switch` | Yes | First truthy `:case` wins; later cases are never evaluated; `:default` optional. |
159
+ | `:return` | Yes | Ends the event successfully — replaces the early-`Throw` workaround. |
160
+ | `:for`, `:parallel_for` | No | Loops belong in routines; move the iteration into an API endpoint. |
161
+ | `:parallel` | No | Parallelism belongs in routines; for fire-and-forget on the client, actions already take `async: true`. |
162
+ | `:try` / `:catch` / `:finally` | No | Events already scope errors with `try` / `catch` action lists. |
163
+ | `:set_state` | Already an action | [`SetState`](/SetState). Step-like controls exist server-side only because routines have no actions. |
164
+ | `:throw` | Already an action | [`Throw`](/Throw). |
165
+ | `:reject` | No client meaning | It maps a routine to a 4xx response; on the client, `Throw` covers aborts. |
166
+ | `:log` | No | Server logging concern; no client counterpart planned. |
167
+
168
+ ## Debouncing events
169
+
170
+ Event debouncing can be turned on by setting the `debounce` field on event objects. If `debounce.immediate` is `true`, leading edge debouncing or throttling will apply, else it will be debounced as trailing edge.
171
+
172
+ To control the debounce delay, set `debounce.ms` to the number of milliseconds to delay. The default delay is 300 milliseconds. If an event is triggered within that time, the event will not be triggered again. See [debounce vs throttling](https://redd.one/blog/debounce-vs-throttle) for a more detailed explanation.
173
+
174
+ ###### Event trailing edge debouncing example:
175
+ ```yaml
176
+ - id: block_with_actions
177
+ type: Block
178
+ properties:
179
+ # ...
180
+ events:
181
+ onEvent1:
182
+ debounce:
183
+ ms: 1000
184
+ try:
185
+ - id: action1
186
+ type: ActionType1
187
+ params:
188
+ # ...
189
+ - id: action2
190
+ type: ActionType2
191
+ ```
192
+
193
+ ###### Event throttling or leading edge debouncing example:
194
+ ```yaml
195
+ - id: block_with_actions
196
+ type: Block
197
+ properties:
198
+ # ...
199
+ events:
200
+ onEvent1:
201
+ debounce:
202
+ ms: 1000
203
+ immediate: true
204
+ try:
205
+ - id: action1
206
+ type: ActionType1
207
+ params:
208
+ # ...
209
+ - id: action2
210
+ type: ActionType2
211
+ ```
212
+
213
+ ## Keyboard Shortcuts
214
+
215
+ Events can be triggered by keyboard shortcuts. Add a `shortcut` property to an event to bind a key combination — when pressed, the event fires as if the user clicked the block. See the [Keyboard Shortcuts](/keyboard-shortcuts) page for the full shortcut format, common shortcuts, recipes, and more.
216
+
217
+ ```yaml
218
+ events:
219
+ onClick:
220
+ shortcut: mod+K
221
+ try:
222
+ - id: open_search
223
+ type: SetState
224
+ params:
225
+ searchOpen: true
226
+ ```
227
+
228
+ ## Page initialization events
229
+
230
+ The first blocks on a page, usually a [`container`](/container) type block, can define `onInit` and `onInitAsync` events. All blocks have `onMount` and `onMountAsync` events, that can be used to initialize the page or blocks.
231
+
232
+ The `onInit` event is triggered the first time a page is loaded. This event blocks page render, in other words, the page __will__ remain in a loading state, rendering only the progress bar, until all the actions have completed execution. It can be used to set up [`state`](/page-and-app-state). Actions that take a long time to execute, like `Request`, should be used sparingly here for a better user experience.
233
+
234
+ The `onInitAsync` event is triggered the first time a page loaded, but does not block page render. In other words, the page __will not__ remain in a loading state until all the actions have completed execution. This is a good place to execute non-blocking tasks or requests that might take longer to execute.
235
+
236
+ The `onMount` event is triggered every time a block is rendered on a page. This event can be used on any block, and causes the block and it's children to render in their loading state. It typically executes actions that should be run each time a block is loaded, like checking if an id is present in the [url query parameters](/_url_query), or fetching data for [`Selector`](/Selector) options using a [`Request`](/Request) action.
237
+
238
+ The `onMountAsync` event is triggered every time a block is mounted, but does not render the block in loading.
239
+
240
+ ## Action types
241
+
242
+ The following actions can be used:
243
+
244
+ - [`CallMethod`](/CallMethod) - Call a method defined by another block.
245
+ - [`Link`](/Link) - Link to another page.
246
+ - [`Message`](/Message) - Show a message to the user.
247
+ - [`Notification`](/Notification) - Show a notification to the user.
248
+ - [`Request`](/Request) - Call a request.
249
+ - [`Reset`](/Reset) - Reset the page validation and `state`.
250
+ - [`ScrollTo`](/ScrollTo) - Scroll to a point on the page.
251
+ - [`SetGlobal`](/SetGlobal) - Set a value to the `global` variable object.
252
+ - [`SetState`](/SetState) - Set a value to the page `state`.
253
+ - [`Validate`](/Validate) - Validate the inputs on the page.
254
+
255
+ See additional action type available under the Actions tab in the menu.
256
+
257
+ ## TLDR
258
+ - Events are triggered when something happens on a page, like clicking a button or loading a page.
259
+ - A list of actions are executed sequentially by a triggered event.
260
+ - If an action errors, the actions that follow are skipped.
261
+ - Actions that are `async: true` will not be executed sequentially nor stop the event if they error.
262
+ - Action errors can be handled by providing a list of `try` and `catch` actions to the event.
263
+ - Operators used in action `params` are evaluated right before the action is executed.
264
+ - The [`_actions`](/_actions) operator is available for sequential actions to use the values returned from preceding actions in the chain.
265
+ - Actions have a `skip` field that can be used to skip action execution.
266
+ - Action lists also support the [`:if`](/:if), [`:switch`](/:switch) and [`:return`](/:return) controls — `skip` gates one action, `:if` gates a group, `:switch` picks between alternatives, and `:return` ends the event early.
267
+ - Events support `shortcut` to bind keyboard shortcuts to the event. The shortcut fires the event when the key combination is pressed.
268
+ - The `onInit` event is triggered the first time a page is mounted and keeps the page in loading until all actions have finished.
269
+ - The `onInitAsync` event is triggered the first time a page is mounted and does not keep the page in loading.
270
+ - The `onMount` events is triggered the every time a block is mounted and keeps the block in loading until all actions have finished.
271
+ - The `onMountAsync` event is triggered the every time a block is mounted, after `onMount` has completed, and does not keep the block in loading.
@@ -0,0 +1,18 @@
1
+ # Hosting Files
2
+
3
+ A Lowdefy app provides a convenient method to host __public__ files under the `/*` app route. Add content to be hosted publicly by creating a folder named `public` in the root of a Lowdefy project folder, next to the `lowdefy.yaml` file. Place the public content in this folder to host this content with your app.
4
+
5
+ All content in this folder will be publicly accessible at `{{ APP_URL }}/{{ FILE_PATH_NAME }}`. For example, the logo at the top of this page is hosted at [`https://docs.lowdefy.com/logo-light-theme.png`](http://docs.lowdefy.com/logo-light-theme.png). Sub-folders inside the public folder are supported.
6
+
7
+ By default, the `public` folder of a Lowdefy app will serve some files which most apps need:
8
+ - `apple-touch-icon.png`: A 180x180px png image file to be used as the apple PWA icon.
9
+ - `icon-32.png`: A 32x32px png image file to be used as fallback favicon for some browsers.
10
+ - `icon-512.png`: A 512x512px png image icon.
11
+ - `icon.svg`: A svg image file which will be used as favicon if supported by browser.
12
+ - `logo-dark-theme.png`: A ~250x72px png image used as the header logo for [`PageHeaderMenu`](/PageHeaderMenu) and [`PageSiderMenu`](/PageSiderMenu) blocks on desktop in dark mode.
13
+ - `logo-light-theme.png`: A ~250x72px png image used as the header logo for `PageHeaderMenu` and `PageSiderMenu` blocks on desktop in light mode.
14
+ - `logo-square-dark-theme.png`: A ~125x125px png image used as the header logo for `PageHeaderMenu` and `PageSiderMenu` blocks on mobile in dark mode.
15
+ - `logo-square-light-theme.png`: A ~125x125px png image used as the header logo for `PageHeaderMenu` and `PageSiderMenu` blocks on mobile in light mode.
16
+ - `manifest.webmanifest`: The app [web manifest](https://developer.mozilla.org/en-US/docs/Web/Manifest).
17
+
18
+ Any of these files can be overwritten by replacing the file with a modified version. For example, to replace the logo inside the header of `PageSiderMenu` on all pages, add a ~250x72px logo inside the project folder at `/logo-light-theme.png`.
@@ -0,0 +1,320 @@
1
+ # Internationalization
2
+
3
+ Lowdefy ships first-class internationalization (i18n) for end-user apps. One config block at `config.i18n` wires up:
4
+
5
+ - **Antd component strings** — date pickers, pagination, modal buttons, table empty states, form validation messages — via Ant Design's [`ConfigProvider locale`](https://ant.design/docs/react/i18n).
6
+ - **dayjs date formatting** — `dayjs.locale()` is set automatically for the active locale.
7
+ - **App-author translations** — your own strings via the [`_t`](/_t) operator with [ICU MessageFormat](https://formatjs.io/docs/core-concepts/icu-syntax/) (interpolation, plural rules, gender, select).
8
+ - **Built-in framework strings** — engine and client defaults (e.g. `Loading`, `Success`, `This field is required`) that authors can override per-locale.
9
+ - **Server-rendered translations** — the API resolves `Accept-Language` so server-side requests honor the user's locale.
10
+
11
+ ## Configure
12
+
13
+ Declare your supported locales and message catalogs under `config.i18n`:
14
+
15
+ ```yaml
16
+ # lowdefy.yaml
17
+ config:
18
+ i18n:
19
+ defaultLocale: en-US
20
+ locales:
21
+ - { code: en-US, label: English, antd: en_US, dayjs: en }
22
+ - { code: de-DE, label: Deutsch, antd: de_DE, dayjs: de }
23
+ messages:
24
+ en-US:
25
+ _ref: i18n/en-US.json
26
+ de-DE:
27
+ _ref: i18n/de-DE.json
28
+ ```
29
+
30
+ **Per-locale fields:**
31
+ - `code` (required) — BCP 47 locale code (`en-US`, `de-DE`, `zh-CN`, ...).
32
+ - `label` — Human-readable name shown in language pickers.
33
+ - `antd` — Antd locale module name (e.g. `en_US`, `zh_CN`). Loaded dynamically from `antd/locale/{name}`.
34
+ - `dayjs` — Dayjs locale id (e.g. `en`, `zh-cn`).
35
+
36
+ **Top-level fields:**
37
+ - `defaultLocale` (required) — Locale used when no user preference and no browser match. Must appear in `locales`.
38
+ - `messages` — Translation catalogs keyed by locale code. Use inline maps or `_ref` to JSON files.
39
+
40
+ Only the locales you declare are bundled — antd and dayjs locale imports are codegen'd at build time, so you don't pay for locales you don't ship.
41
+
42
+ **Fallback is always `en-US`.** When a key isn't in the active locale, the lookup chain checks `en-US` next, then framework builtins, then the key string. Plugin and module authors should always ship `en-US` translations as a baseline so consumers in any locale see real English copy instead of raw keys when translations are incomplete.
43
+
44
+ ## Translate strings with `_t`
45
+
46
+ Use the [`_t`](/_t) operator anywhere in your config that accepts a string:
47
+
48
+ ```yaml
49
+ - id: greeting
50
+ type: Title
51
+ properties:
52
+ content:
53
+ _t: greeting
54
+ ```
55
+
56
+ With ICU MessageFormat values:
57
+
58
+ ```yaml
59
+ - id: cart
60
+ type: Paragraph
61
+ properties:
62
+ content:
63
+ _t:
64
+ key: cart.items
65
+ values:
66
+ count:
67
+ _state: itemCount
68
+ ```
69
+
70
+ Where `messages.en-US.cart.items: '{count, plural, one {# item} other {# items}}'`.
71
+
72
+ **Resolution order** (per `_t` call): active-locale message → `en-US` message → built-in framework message → key as last resort.
73
+
74
+ ## Switch language at runtime
75
+
76
+ Use the [`SetLocale`](/SetLocale) action and the [`_locale`](/_locale) operator to build a language picker:
77
+
78
+ ```yaml
79
+ - id: lang_picker
80
+ type: Selector
81
+ properties:
82
+ options:
83
+ _array.map:
84
+ on:
85
+ _locale: supported
86
+ callback:
87
+ _function:
88
+ value:
89
+ __args: 0.code
90
+ label:
91
+ __args: 0.label
92
+ value:
93
+ _locale: active
94
+ events:
95
+ onChange:
96
+ - id: switch
97
+ type: SetLocale
98
+ params:
99
+ locale:
100
+ _state: lang_picker
101
+ ```
102
+
103
+ `_locale: supported` returns `[{ code, label, antd, dayjs }, ...]`. Selector options must be an array of `{ value, label }` pairs, so the snippet above projects each locale onto that shape with `_array.map` + `_function`.
104
+
105
+ User preference persists to `localStorage`. Clear it (and fall back to browser/default) by passing `locale: auto`.
106
+
107
+ **Resolution at startup:**
108
+
109
+ 1. User preference in `localStorage` (`lowdefy_locale`)
110
+ 2. Browser `navigator.languages` best-fit against `config.i18n.locales`
111
+ 3. `config.i18n.defaultLocale`
112
+
113
+ ## Built-in language picker on page-shell blocks
114
+
115
+ The page-shell blocks ([`PageHeaderMenu`](/PageHeaderMenu), [`PageSidebarLayout`](/PageSidebarLayout), [`PageSiderMenu`](/PageSiderMenu)) expose a built-in `localeSelector` property — same shape as the existing `darkModeToggle`. Set it to `true` and a globe-icon dropdown appears in the page chrome alongside the dark-mode toggle. The dropdown lists the locales declared in `config.i18n.locales` and dispatches [`SetLocale`](/SetLocale) on selection. It renders nothing if `config.i18n` is not configured, so flipping the flag in apps that haven't set up i18n is a no-op.
116
+
117
+ ```yaml
118
+ - id: shell
119
+ type: PageHeaderMenu
120
+ properties:
121
+ darkModeToggle: true
122
+ localeSelector: true
123
+ menu:
124
+ links:
125
+ - label: Home
126
+ pageId: home
127
+ ```
128
+
129
+ ## Built-in framework strings
130
+
131
+ The framework emits a few user-visible strings (action loading toasts, validation summaries, popup-blocker warnings, the global error page). They live in a built-in catalog and surface as English by default. Override any of them by adding the same key under `config.i18n.messages.{locale}`:
132
+
133
+ ```yaml
134
+ config:
135
+ i18n:
136
+ defaultLocale: de-DE
137
+ locales:
138
+ - { code: de-DE, label: Deutsch, antd: de_DE, dayjs: de }
139
+ messages:
140
+ de-DE:
141
+ engine.action.loading: 'Laden'
142
+ engine.action.success: 'Erfolgreich'
143
+ engine.validation.fieldRequired: 'Pflichtfeld'
144
+ engine.validation.summary: '{count, plural, one {Eingabe hat # Validierungsfehler} other {Eingabe hat # Validierungsfehler}}'
145
+ client.popupBlocked: 'Ein Popup-Blocker verhindert das Öffnen der Seite.'
146
+ client.requestError: 'Anforderungsfehler'
147
+ errorPage.name: 'Fehler'
148
+ errorPage.message: 'Ein Fehler ist aufgetreten.'
149
+ errorPage.homeLink: 'Zurück zur Startseite'
150
+ ```
151
+
152
+ **Built-in keys you can override:**
153
+
154
+ | Key | English default | Where it surfaces |
155
+ |---|---|---|
156
+ | `engine.action.loading` | `Loading` | Default loading toast on actions |
157
+ | `engine.action.success` | `Success` | Default success toast on actions |
158
+ | `engine.validation.fieldRequired` | `This field is required` | Required-field validation message |
159
+ | `engine.validation.summary` | `Your input has {count} validation error(s)` | `Validate` action error summary (ICU plural) |
160
+ | `client.popupBlocked` | `A popup blocker may be preventing...` | Toast when `Link` to a new tab is blocked |
161
+ | `client.requestError` | `Request error` | Fallback when an API response has no message |
162
+ | `client.backAriaLabel` | `back` | Aria label on browser-back links |
163
+ | `client.shortcutThen` | `then` | Sequence shortcut badge separator |
164
+ | `errorPage.name` | `Error` | Full-page error fallback heading |
165
+ | `errorPage.message` | `An error has occurred.` | Full-page error fallback body |
166
+ | `errorPage.homeLink` | `Return to home page` | Full-page error fallback link |
167
+
168
+ ## Localizing block defaults
169
+
170
+ Antd's `ConfigProvider locale` automatically translates date-picker placeholders, modal `Ok`/`Cancel` buttons, table empty states, pagination labels, and form validation messages — no per-block work required. When a block exposes a Lowdefy-specific string (e.g. `ControlledList.noDataTitle`, `Search.placeholder`), thread `_t` through the property:
171
+
172
+ ```yaml
173
+ - id: items
174
+ type: ControlledList
175
+ properties:
176
+ noDataTitle:
177
+ _t: list.empty
178
+ ```
179
+
180
+ ## Server-side translations
181
+
182
+ Server-side actions and requests resolve the user's locale from the `Accept-Language` header. `_t` works the same in server contexts as on the client, with one difference: there's no `localStorage` on the server, so `Accept-Language` (and `defaultLocale`) determine the active locale per request.
183
+
184
+ ## Agents and AI chat UI
185
+
186
+ **The AgentChat block** (`@lowdefy/blocks-antd-x`) auto-localizes its framework-rendered strings via `methods.translate(key)` against the active locale. Builtin keys:
187
+
188
+ | Key | Default | Where |
189
+ |---|---|---|
190
+ | `agent.sender.placeholder` | `Type a message...` | Sender input placeholder |
191
+ | `agent.toolApproval.approve` / `.reject` | `Approve` / `Reject` | Tool-approval buttons |
192
+ | `agent.message.copy` / `.feedback` / `.regenerate` / `.delete` | English defaults | Message action menu |
193
+ | `agent.toolResult.completed` / `.completedNoData` | `Completed` / `Completed (no data)` | Tool result captions |
194
+ | `agent.toolResult.empty` / `.emptyList` | `Empty` / `Empty list` | Empty tool-result placeholders |
195
+ | `agent.toolResult.showMore` / `.showLess` | `Show more` / `Show less` | Collapsible long text |
196
+
197
+ Override per-locale via `config.i18n.messages.{locale}` — same mechanism as any other message.
198
+
199
+ **antd X built-in strings.** XProvider is wired at the app root with a merged antd + antd-X locale pack. antd X (`@ant-design/x@2.7.x`) ships only two upstream packs: `en_US` and `zh_CN`. Locales outside that set fall back to `en_US` for X-native strings (`New chat`, `Stop loading`, `Like`/`Dislike`, `OK`/`Cancel` on bubble edit). To override these in unsupported locales, set the framework's reference keys under `config.i18n.messages.{locale}`:
200
+
201
+ ```yaml
202
+ config:
203
+ i18n:
204
+ defaultLocale: de-DE
205
+ locales:
206
+ - { code: de-DE, label: Deutsch, antd: de_DE, dayjs: de }
207
+ messages:
208
+ de-DE:
209
+ agent.antdx.conversations.create: 'Neuer Chat'
210
+ agent.antdx.sender.stopLoading: 'Anhalten'
211
+ agent.antdx.bubble.editableOk: 'OK'
212
+ agent.antdx.bubble.editableCancel: 'Abbrechen'
213
+ agent.antdx.actions.feedbackLike: 'Gefällt mir'
214
+ agent.antdx.actions.feedbackDislike: 'Gefällt mir nicht'
215
+ ```
216
+
217
+ **Agent runtime errors.** HTTP 400/500 errors from the agent endpoint (`Only POST requests are supported.`, `Invalid agent path`, `Agent "X" does not exist.`, etc.) translate via `agent.runtime.*` keys against the request's `Accept-Language`. Server-side validation errors and stack traces stay in English (developer diagnostics).
218
+
219
+ **Agent config translation.** `agent.properties.instructions` passes through the operator parser at request time, so `_t:` works:
220
+
221
+ ```yaml
222
+ agents:
223
+ - id: assistant
224
+ type: AISDKAgent
225
+ connectionId: anthropic
226
+ properties:
227
+ agent:
228
+ model: claude-sonnet-4
229
+ instructions:
230
+ _t: agent.systemPrompt
231
+ ```
232
+
233
+ For `tools[].description` — describes when the model should call a tool — keep it static English in most cases. Translating tool descriptions can degrade tool-call accuracy on English-trained models.
234
+
235
+ **Hook payloads.** Agent hook endpoints (`onStart`, `onStepFinish`, `onFinish`, etc.) receive a payload that now includes `locale: <activeCode>`, so hook routines can return locale-aware follow-up messages.
236
+
237
+ **Built-in tool descriptions, console warnings, build errors, and the model's natural-language output stay English.** They're either model-facing (translation degrades model behavior), developer-facing (English is standard), or owned by the model.
238
+
239
+ ## From plugin code
240
+
241
+ `_t` is the YAML-config interface. The runtime equivalent for custom block and action plugins is `methods.translate(key, values)` — same lookup chain, same overrides. Plugin authors should never reach into `lowdefy._internal.t` directly; that's an engine-internal adapter. Use `methods.translate`:
242
+
243
+ ```js
244
+ // in @my-org/blocks-cool/src/blocks/CoolList/CoolList.js
245
+ function CoolList({ blockId, methods, properties }) {
246
+ const empty = methods.translate('blocks-cool.list.empty');
247
+ const greeting = methods.translate('blocks-cool.greeting', { name: properties.name });
248
+ // ...
249
+ }
250
+ ```
251
+
252
+ ```js
253
+ // in @my-org/actions-cool/src/actions/CoolAction.js
254
+ function CoolAction({ methods, params }) {
255
+ const ok = methods.translate('actions-cool.confirm.ok');
256
+ // ...
257
+ }
258
+ ```
259
+
260
+ ## Shipping default messages from a plugin package
261
+
262
+ Plugins can ship locale-keyed defaults so consumers see translated strings out-of-the-box. Add a `messages` JS module and register it under the package's `exports`:
263
+
264
+ ```js
265
+ // in @my-org/blocks-cool/src/messages.js
266
+ export default {
267
+ 'en-US': {
268
+ 'blocks-cool.list.empty': 'No items',
269
+ 'blocks-cool.list.loading': 'Loading data...',
270
+ },
271
+ 'de-DE': {
272
+ 'blocks-cool.list.empty': 'Keine Einträge',
273
+ 'blocks-cool.list.loading': 'Daten werden geladen...',
274
+ },
275
+ };
276
+ ```
277
+
278
+ ```json
279
+ // in @my-org/blocks-cool/package.json
280
+ {
281
+ "exports": {
282
+ "./types": "./dist/types.js",
283
+ "./messages": "./dist/messages.js"
284
+ }
285
+ }
286
+ ```
287
+
288
+ Namespace your keys with the package or org slug (`blocks-cool.*`) to avoid collisions with other plugins. Apps consume your defaults automatically — the build merges plugin manifests into the per-locale message catalog. App authors override individual keys via `config.i18n.messages.{locale}` like any other message.
289
+
290
+ **Merge precedence:**
291
+
292
+ | Tier | Source | Wins over |
293
+ |---|---|---|
294
+ | User app messages | `config.i18n.messages.{locale}` in `lowdefy.yaml` | everything below |
295
+ | Plugin messages | plugin's `./messages` export, locale-keyed | builtin |
296
+ | Framework builtins | the built-in catalog (English) | key |
297
+ | Key fallback | the lookup key itself | — |
298
+
299
+ ## Working with dates and numbers
300
+
301
+ **Date and number input blocks auto-localize their defaults when `config.i18n` is configured:**
302
+
303
+ - `DateSelector`, `DateRangeSelector`, `DateTimeSelector`, `MonthSelector` — the input/display `format` defaults to the active locale's date format (e.g. `DD.MM.YYYY` for `de-DE`, `MM/DD/YYYY` for `en-US`). Formats are derived at runtime via `Intl.DateTimeFormat` — no per-locale table to maintain.
304
+ - `NumberInput` — `decimalSeparator` defaults to the active locale's separator (e.g. `,` for `de-DE`, `.` for `en-US`), derived via `Intl.NumberFormat`.
305
+
306
+ Override per-block by setting `properties.format` or `properties.decimalSeparator` explicitly. When `config.i18n` isn't configured the legacy defaults (`YYYY-MM-DD`, `.`) apply so apps without i18n are unchanged.
307
+
308
+ Two complementary operators also format values per locale in YAML expressions:
309
+
310
+ - [`_intl`](/_intl) — wraps native `Intl.DateTimeFormat`/`Intl.NumberFormat`/etc. Pass an explicit `locale`, or omit it to use the user's default.
311
+ - [`_dayjs`](/_dayjs) and [`_date`](/_date) — dayjs-based date formatting. `dayjs.locale()` is set automatically by `useLocale`, so locale-aware tokens (`dddd`, `MMMM`, etc.) render in the active language.
312
+
313
+ **In custom block / action code**, read the active locale with `methods.getLocale()` and pair it with the `@lowdefy/helpers` utilities `getLocaleDateFormat`, `getLocaleDecimalSeparator`, `getLocaleGroupSeparator` to derive locale-aware defaults.
314
+
315
+ ## Reference
316
+
317
+ - [`_t`](/_t) — translate operator
318
+ - [`_locale`](/_locale) — read active/default/fallback/supported locale state
319
+ - [`SetLocale`](/SetLocale) — set the user's preferred locale
320
+ - [`_intl`](/_intl) — Intl-based date/number/list formatting