@maz-ui/mcp 5.0.0-beta.5 → 5.0.0-beta.51

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 (164) hide show
  1. package/README.md +1 -1
  2. package/dist/mcp.d.mts +22 -9
  3. package/dist/mcp.d.ts +22 -9
  4. package/dist/mcp.mjs +160 -83
  5. package/docs/generated-docs/maz-avatar.doc.md +30 -30
  6. package/docs/generated-docs/maz-bottom-sheet.doc.md +16 -13
  7. package/docs/generated-docs/maz-btn.doc.md +21 -19
  8. package/docs/generated-docs/maz-checkbox.doc.md +16 -17
  9. package/docs/generated-docs/maz-circular-progress-bar.doc.md +1 -1
  10. package/docs/generated-docs/maz-code-highlight.doc.md +11 -0
  11. package/docs/generated-docs/maz-container.doc.md +1 -0
  12. package/docs/generated-docs/maz-date-picker.doc.md +41 -41
  13. package/docs/generated-docs/maz-drawer.doc.md +7 -8
  14. package/docs/generated-docs/maz-dropdown.doc.md +3 -0
  15. package/docs/generated-docs/maz-expand-animation.doc.md +4 -4
  16. package/docs/generated-docs/maz-fullscreen-loader.doc.md +5 -5
  17. package/docs/generated-docs/maz-gallery.doc.md +15 -15
  18. package/docs/generated-docs/maz-input-code.doc.md +16 -16
  19. package/docs/generated-docs/maz-input-phone-number.doc.md +43 -42
  20. package/docs/generated-docs/maz-input-price.doc.md +14 -14
  21. package/docs/generated-docs/maz-input-tags.doc.md +16 -16
  22. package/docs/generated-docs/maz-input.doc.md +33 -33
  23. package/docs/generated-docs/maz-lazy-img.doc.md +14 -14
  24. package/docs/generated-docs/maz-loading-bar.doc.md +4 -4
  25. package/docs/generated-docs/maz-markdown-editor.doc.md +65 -0
  26. package/docs/generated-docs/maz-popover.doc.md +1 -1
  27. package/docs/generated-docs/maz-pull-to-refresh.doc.md +39 -20
  28. package/docs/generated-docs/maz-radio-buttons.doc.md +17 -17
  29. package/docs/generated-docs/maz-radio.doc.md +16 -16
  30. package/docs/generated-docs/maz-reading-progress-bar.doc.md +4 -4
  31. package/docs/generated-docs/maz-select-country.doc.md +27 -26
  32. package/docs/generated-docs/maz-sidebar-content.doc.md +5 -0
  33. package/docs/generated-docs/maz-sidebar-footer.doc.md +5 -0
  34. package/docs/generated-docs/maz-sidebar-group.doc.md +11 -0
  35. package/docs/generated-docs/maz-sidebar-header.doc.md +5 -0
  36. package/docs/generated-docs/maz-sidebar-menu-button.doc.md +27 -0
  37. package/docs/generated-docs/maz-sidebar-menu-item.doc.md +5 -0
  38. package/docs/generated-docs/maz-sidebar-menu-sub.doc.md +16 -0
  39. package/docs/generated-docs/maz-sidebar-menu.doc.md +5 -0
  40. package/docs/generated-docs/maz-sidebar-separator.doc.md +0 -0
  41. package/docs/generated-docs/maz-sidebar-trigger.doc.md +5 -0
  42. package/docs/generated-docs/maz-sidebar.doc.md +36 -0
  43. package/docs/generated-docs/maz-slider.doc.md +1 -1
  44. package/docs/generated-docs/maz-spinner.doc.md +4 -4
  45. package/docs/generated-docs/maz-switch.doc.md +14 -14
  46. package/docs/generated-docs/maz-table-virtualizer.doc.md +20 -0
  47. package/docs/generated-docs/maz-table.doc.md +43 -37
  48. package/docs/generated-docs/maz-tabs-bar.doc.md +20 -9
  49. package/docs/generated-docs/maz-tabs.doc.md +6 -3
  50. package/docs/generated-docs/maz-textarea.doc.md +27 -25
  51. package/docs/generated-docs/maz-ticker.doc.md +1 -1
  52. package/docs/generated-docs/maz-timeline.doc.md +4 -4
  53. package/docs/generated-docs/maz-window-mockup.doc.md +23 -0
  54. package/docs/src/blog/v4.md +1 -1
  55. package/docs/src/blog/v5.md +5 -7
  56. package/docs/src/components/maz-avatar.md +52 -4
  57. package/docs/src/components/maz-bottom-sheet.md +300 -169
  58. package/docs/src/components/maz-btn.md +1 -1
  59. package/docs/src/components/maz-checklist.md +10 -10
  60. package/docs/src/components/maz-code-highlight.md +233 -0
  61. package/docs/src/components/maz-date-picker.md +55 -1
  62. package/docs/src/components/maz-dialog.md +46 -0
  63. package/docs/src/components/maz-dropdown.md +32 -16
  64. package/docs/src/components/maz-icon.md +16 -5
  65. package/docs/src/components/maz-input-phone-number.md +30 -0
  66. package/docs/src/components/maz-lazy-img.md +64 -0
  67. package/docs/src/components/maz-markdown-editor.md +369 -0
  68. package/docs/src/components/maz-pull-to-refresh.md +176 -17
  69. package/docs/src/components/maz-select-country.md +138 -1
  70. package/docs/src/components/maz-sidebar.md +719 -0
  71. package/docs/src/components/maz-table.md +156 -1
  72. package/docs/src/components/maz-tabs.md +110 -3
  73. package/docs/src/components/maz-textarea.md +58 -0
  74. package/docs/src/components/maz-timeline.md +60 -0
  75. package/docs/src/components/maz-window-mockup.md +249 -0
  76. package/docs/src/composables/use-drag.md +239 -0
  77. package/docs/src/composables/use-form-validator.md +297 -16
  78. package/docs/src/composables/use-pull-to-refresh.md +79 -0
  79. package/docs/src/composables/use-swipe.md +26 -11
  80. package/docs/src/directives/click-outside.md +8 -15
  81. package/docs/src/directives/fullscreen-img.md +1 -1
  82. package/docs/src/directives/lazy-img.md +44 -11
  83. package/docs/src/directives/tooltip.md +24 -1
  84. package/docs/src/directives/zoom-img.md +1 -1
  85. package/docs/src/ecosystem/eslint-config.md +95 -1
  86. package/docs/src/{guide/icons.md → ecosystem/icons/index.md} +1 -1
  87. package/docs/src/ecosystem/node/exec-promise.md +87 -0
  88. package/docs/src/ecosystem/node/index.md +53 -0
  89. package/docs/src/ecosystem/node/logger.md +146 -0
  90. package/docs/src/ecosystem/node/print-banner.md +93 -0
  91. package/docs/src/{guide → ecosystem}/nuxt.md +102 -47
  92. package/docs/src/{guide → ecosystem}/themes.md +152 -71
  93. package/docs/src/{guide → ecosystem}/translations.md +1 -1
  94. package/docs/src/ecosystem/utils/camel-case.md +31 -0
  95. package/docs/src/{helpers → ecosystem/utils}/capitalize.md +2 -3
  96. package/docs/src/ecosystem/utils/check-availability.md +79 -0
  97. package/docs/src/ecosystem/utils/cookie.md +80 -0
  98. package/docs/src/ecosystem/utils/debounce-callback.md +38 -0
  99. package/docs/src/ecosystem/utils/debounce-id.md +69 -0
  100. package/docs/src/ecosystem/utils/debounce.md +65 -0
  101. package/docs/src/ecosystem/utils/fetch-locale-ip.md +33 -0
  102. package/docs/src/ecosystem/utils/format-json.md +33 -0
  103. package/docs/src/ecosystem/utils/format-phone-number.md +37 -0
  104. package/docs/src/ecosystem/utils/get-browser-locale.md +29 -0
  105. package/docs/src/ecosystem/utils/get-error-message.md +39 -0
  106. package/docs/src/ecosystem/utils/idle-timeout.md +90 -0
  107. package/docs/src/ecosystem/utils/index.md +60 -0
  108. package/docs/src/ecosystem/utils/is-client.md +32 -0
  109. package/docs/src/ecosystem/utils/is-equal.md +38 -0
  110. package/docs/src/ecosystem/utils/is-server.md +31 -0
  111. package/docs/src/ecosystem/utils/is-standalone-mode.md +43 -0
  112. package/docs/src/ecosystem/utils/kebab-case.md +36 -0
  113. package/docs/src/ecosystem/utils/normalize-string.md +77 -0
  114. package/docs/src/ecosystem/utils/pascal-case.md +35 -0
  115. package/docs/src/ecosystem/utils/script-loader.md +77 -0
  116. package/docs/src/ecosystem/utils/sleep.md +59 -0
  117. package/docs/src/ecosystem/utils/snake-case.md +36 -0
  118. package/docs/src/ecosystem/utils/swipe-handler.md +91 -0
  119. package/docs/src/ecosystem/utils/textarea-autogrow.md +41 -0
  120. package/docs/src/ecosystem/utils/throttle-id.md +48 -0
  121. package/docs/src/ecosystem/utils/throttle.md +57 -0
  122. package/docs/src/ecosystem/utils/truthy-filter.md +31 -0
  123. package/docs/src/ecosystem/utils/types/deep-key-of.md +48 -0
  124. package/docs/src/ecosystem/utils/types/deep-partial.md +42 -0
  125. package/docs/src/ecosystem/utils/types/deep-required.md +39 -0
  126. package/docs/src/ecosystem/utils/types/flatten-object-keys.md +44 -0
  127. package/docs/src/ecosystem/utils/types/generic-instance-type.md +42 -0
  128. package/docs/src/ecosystem/utils/types/infer-maybe-ref.md +35 -0
  129. package/docs/src/ecosystem/utils/upper-first.md +32 -0
  130. package/docs/src/ecosystem/utils/user-visibility.md +69 -0
  131. package/docs/src/guide/getting-started.md +15 -13
  132. package/docs/src/guide/global-defaults.md +102 -0
  133. package/docs/src/guide/maz-ui-provider.md +6 -3
  134. package/docs/src/guide/migration-v4.md +13 -9
  135. package/docs/src/guide/migration-v5.md +211 -15
  136. package/docs/src/guide/resolvers.md +8 -8
  137. package/docs/src/guide/tailwind.md +4 -0
  138. package/docs/src/guide/vue.md +4 -4
  139. package/docs/src/index.md +13 -13
  140. package/docs/src/plugins/aos.md +1 -1
  141. package/package.json +11 -10
  142. package/docs/src/helpers/camel-case.md +0 -14
  143. package/docs/src/helpers/check-availability.md +0 -14
  144. package/docs/src/helpers/debounce-callback.md +0 -14
  145. package/docs/src/helpers/debounce-id.md +0 -14
  146. package/docs/src/helpers/debounce.md +0 -14
  147. package/docs/src/helpers/is-client.md +0 -14
  148. package/docs/src/helpers/is-equal.md +0 -14
  149. package/docs/src/helpers/is-standalone-mode.md +0 -14
  150. package/docs/src/helpers/kebab-case.md +0 -14
  151. package/docs/src/helpers/normalize-string.md +0 -14
  152. package/docs/src/helpers/pascal-case.md +0 -14
  153. package/docs/src/helpers/script-loader.md +0 -14
  154. package/docs/src/helpers/sleep.md +0 -14
  155. package/docs/src/helpers/snake-case.md +0 -14
  156. package/docs/src/helpers/throttle-id.md +0 -14
  157. package/docs/src/helpers/throttle.md +0 -14
  158. /package/docs/src/{guide → ecosystem/icons}/icon-set.md +0 -0
  159. /package/docs/src/{guide → ecosystem}/mcp.md +0 -0
  160. /package/docs/src/{helpers → ecosystem/utils}/country-code-to-unicode-flag.md +0 -0
  161. /package/docs/src/{helpers → ecosystem/utils}/currency.md +0 -0
  162. /package/docs/src/{helpers → ecosystem/utils}/date.md +0 -0
  163. /package/docs/src/{helpers → ecosystem/utils}/get-country-flag-url.md +0 -0
  164. /package/docs/src/{helpers → ecosystem/utils}/number.md +0 -0
@@ -0,0 +1,369 @@
1
+ ---
2
+ title: MazMarkdownEditor
3
+ description: MazMarkdownEditor is a GitHub-style markdown editor with Write/Preview/Split tabs, a configurable formatting toolbar, optional line numbers, and a sanitized preview. It shares the same states, labels and theming as MazTextarea, is SSR-friendly, and supports custom renderers.
4
+ ---
5
+
6
+ # {{ $frontmatter.title }}
7
+
8
+ {{ $frontmatter.description }}
9
+
10
+ <!--@include: ./../../.vitepress/mixins/getting-started.md-->
11
+
12
+ ## Installation requirement
13
+
14
+ The preview relies on [`marked`](https://marked.js.org) for parsing and [`dompurify`](https://github.com/cure53/DOMPurify) for sanitization. Both are loaded lazily (only when the preview is rendered), so install them in your project:
15
+
16
+ ::: code-group
17
+
18
+ ```bash [pnpm]
19
+ pnpm add marked dompurify
20
+ ```
21
+
22
+ ```bash [npm]
23
+ npm install marked dompurify
24
+ ```
25
+
26
+ ```bash [yarn]
27
+ yarn add marked dompurify
28
+ ```
29
+
30
+ :::
31
+
32
+ If they are not installed, the preview falls back to a safe, escaped plain-text block. You can also provide your own renderer with the [`renderFunction`](#custom-renderer) prop to avoid these dependencies entirely.
33
+
34
+ ## Basic usage
35
+
36
+ The component exposes a `v-model` bound to the raw markdown string and two tabs: **Write** (textarea) and **Preview** (rendered, sanitized HTML).
37
+
38
+ <ComponentDemo>
39
+ <MazMarkdownEditor v-model="basic" placeholder="markdown goes here" />
40
+
41
+ <template #code>
42
+
43
+ ```vue
44
+ <template>
45
+ <MazMarkdownEditor v-model="content" />
46
+ </template>
47
+
48
+ <script lang="ts" setup>
49
+ import { ref } from 'vue'
50
+ import MazMarkdownEditor from 'maz-ui/components/MazMarkdownEditor'
51
+
52
+ const content = ref('# Hello maz-ui\n\nThis is **markdown** with a [link](https://maz-ui.com).')
53
+ </script>
54
+ ```
55
+
56
+ </template>
57
+ </ComponentDemo>
58
+
59
+ ## Toolbar
60
+
61
+ The formatting toolbar is opt-in. Set `toolbar` to `true` to display the full toolbar. Buttons act on the current textarea selection and preserve the native undo/redo history (`Cmd/Ctrl + Z`).
62
+
63
+ <ComponentDemo>
64
+ <MazMarkdownEditor v-model="withToolbar" toolbar />
65
+
66
+ <template #code>
67
+
68
+ ```vue
69
+ <template>
70
+ <MazMarkdownEditor v-model="content" toolbar />
71
+ </template>
72
+
73
+ <script lang="ts" setup>
74
+ import { ref } from 'vue'
75
+ import MazMarkdownEditor from 'maz-ui/components/MazMarkdownEditor'
76
+
77
+ const content = ref('Select some text and click **Bold**.')
78
+ </script>
79
+ ```
80
+
81
+ </template>
82
+ </ComponentDemo>
83
+
84
+ ### Available actions
85
+
86
+ The full toolbar exposes the following action keys:
87
+
88
+ | Key | Result |
89
+ | --- | --- |
90
+ | `heading` | Heading dropdown (`#`, `##`, `###`) |
91
+ | `bold` | `**bold**` |
92
+ | `italic` | `_italic_` |
93
+ | `strikethrough` | `~~strikethrough~~` |
94
+ | `quote` | `> quote` |
95
+ | `code` | `` `inline code` `` |
96
+ | `codeBlock` | fenced ` ``` ` code block |
97
+ | `link` | `[text](url)` |
98
+ | `image` | `![alt](url)` |
99
+ | `bulletList` | `- item` |
100
+ | `orderedList` | `1. item` |
101
+ | `checkList` | `- [ ] task` |
102
+ | `table` | markdown table skeleton |
103
+
104
+ ### Configure the toolbar
105
+
106
+ Pass an **ordered array of action keys** to display only a subset (and control their order):
107
+
108
+ <ComponentDemo>
109
+ <MazMarkdownEditor v-model="withToolbarConfig" :toolbar="['heading', 'bold', 'italic', 'link', 'codeBlock']" />
110
+
111
+ <template #code>
112
+
113
+ ```vue
114
+ <template>
115
+ <MazMarkdownEditor
116
+ v-model="content"
117
+ :toolbar="['heading', 'bold', 'italic', 'link', 'codeBlock']"
118
+ />
119
+ </template>
120
+ ```
121
+
122
+ </template>
123
+ </ComponentDemo>
124
+
125
+ ## Keyboard shortcuts
126
+
127
+ Classic markdown shortcuts are enabled by default and work whenever the textarea is focused. They preserve the native undo/redo history. The toolbar buttons also display their shortcut in the tooltip. Use `mod` for `Cmd` on macOS and `Ctrl` elsewhere.
128
+
129
+ | Shortcut | Action |
130
+ | --- | --- |
131
+ | `mod + B` | Bold |
132
+ | `mod + I` | Italic |
133
+ | `mod + Shift + X` | Strikethrough |
134
+ | `mod + K` | Link |
135
+ | `mod + E` | Inline code |
136
+ | `mod + Shift + E` | Code block |
137
+ | `mod + Shift + .` | Quote |
138
+ | `mod + Shift + 8` | Bulleted list |
139
+ | `mod + Shift + 7` | Numbered list |
140
+ | `mod + Shift + L` | Task list |
141
+ | `mod + Alt + 1/2/3` | Heading 1/2/3 |
142
+
143
+ Disable them with `:shortcuts="false"`:
144
+
145
+ ```vue
146
+ <template>
147
+ <MazMarkdownEditor v-model="content" toolbar :shortcuts="false" />
148
+ </template>
149
+ ```
150
+
151
+ ::: tip
152
+ Image and table insertions have no default shortcut (to avoid clashing with browser shortcuts). Use the toolbar buttons or the `toolbar` slot helpers for those.
153
+ :::
154
+
155
+ ## List continuation
156
+
157
+ Pressing <kbd>Enter</kbd> inside a list automatically inserts the next marker, just like a desktop markdown editor:
158
+
159
+ - Bulleted lists (`-`, `*`, `+`) repeat the marker.
160
+ - Numbered lists increment the index (`1.` → `2.`).
161
+ - Task lists insert a fresh unchecked box (`- [ ] `).
162
+ - Indentation is preserved.
163
+
164
+ Pressing <kbd>Enter</kbd> again on an empty item removes the marker and exits the list. This works out of the box, no configuration required.
165
+
166
+ ## Label & assistive text
167
+
168
+ Like `MazTextarea`, the editor supports a static `top-label` (or `label`), the `required` asterisk and an `assistive-text` displayed below the editor.
169
+
170
+ <ComponentDemo>
171
+ <MazMarkdownEditor
172
+ v-model="withLabel"
173
+ top-label="Description"
174
+ placeholder="Markdown goes here"
175
+ assistive-text="Markdown is supported"
176
+ required
177
+ />
178
+
179
+ <template #code>
180
+
181
+ ```vue
182
+ <template>
183
+ <MazMarkdownEditor
184
+ v-model="content"
185
+ top-label="Description"
186
+ assistive-text="Markdown is supported"
187
+ required
188
+ />
189
+ </template>
190
+ ```
191
+
192
+ </template>
193
+ </ComponentDemo>
194
+
195
+ ## States
196
+
197
+ Use `error`, `success`, `warning`, `disabled` and `readonly` to reflect validation states, consistent with the other form components.
198
+
199
+ <ComponentDemo>
200
+ <div class="maz:flex maz:flex-col maz:gap-4">
201
+ <MazMarkdownEditor v-model="stateError" error assistive-text="This field has an error" />
202
+ <MazMarkdownEditor v-model="stateSuccess" success assistive-text="Looks good!" />
203
+ <MazMarkdownEditor v-model="stateDisabled" disabled />
204
+ </div>
205
+
206
+ <template #code>
207
+
208
+ ```vue
209
+ <template>
210
+ <MazMarkdownEditor v-model="content" error assistive-text="This field has an error" />
211
+ <MazMarkdownEditor v-model="content" success assistive-text="Looks good!" />
212
+ <MazMarkdownEditor v-model="content" disabled />
213
+ </template>
214
+ ```
215
+
216
+ </template>
217
+ </ComponentDemo>
218
+
219
+ ## Split mode
220
+
221
+ A third tab displays the editor and the preview side by side. Switch to it from the toolbar tabs, or control it with `v-model:mode` (`'write' | 'preview' | 'split'`). On small screens the two panes stack vertically.
222
+
223
+ <ComponentDemo>
224
+ <MazMarkdownEditor v-model="splitContent" mode="split" />
225
+
226
+ <template #code>
227
+
228
+ ```vue
229
+ <template>
230
+ <MazMarkdownEditor v-model="content" mode="split" />
231
+ </template>
232
+
233
+ <script lang="ts" setup>
234
+ import { ref } from 'vue'
235
+ import MazMarkdownEditor from 'maz-ui/components/MazMarkdownEditor'
236
+
237
+ const content = ref('# Split view\n\nType on the left, see the **preview** on the right.')
238
+ </script>
239
+ ```
240
+
241
+ </template>
242
+ </ComponentDemo>
243
+
244
+ ## Line numbers
245
+
246
+ Enable the `line-numbers` prop to display a gutter on the left of the editor. Numbers reflect logical lines and stay in sync with the textarea scroll.
247
+
248
+ <ComponentDemo>
249
+ <MazMarkdownEditor v-model="lineNumbersContent" line-numbers />
250
+
251
+ <template #code>
252
+
253
+ ```vue
254
+ <template>
255
+ <MazMarkdownEditor v-model="content" line-numbers />
256
+ </template>
257
+ ```
258
+
259
+ </template>
260
+ </ComponentDemo>
261
+
262
+ ## Custom renderer {#custom-renderer}
263
+
264
+ Provide a `render-function` to use your own markdown engine (e.g. `markdown-it`, a Nuxt Content renderer, or a server-side pipeline). It receives the raw markdown and returns an HTML string (sync or async). The result is still sanitized when `sanitize` is enabled.
265
+
266
+ <ComponentDemo>
267
+ <MazMarkdownEditor v-model="customRender" :render-function="upperCaseRenderer" />
268
+
269
+ <template #code>
270
+
271
+ ```vue
272
+ <template>
273
+ <MazMarkdownEditor v-model="content" :render-function="renderer" />
274
+ </template>
275
+
276
+ <script lang="ts" setup>
277
+ import { ref } from 'vue'
278
+ import MazMarkdownEditor from 'maz-ui/components/MazMarkdownEditor'
279
+
280
+ const content = ref('Rendered by a custom function')
281
+
282
+ function renderer(markdown: string) {
283
+ return `<p>${markdown.toUpperCase()}</p>`
284
+ }
285
+ </script>
286
+ ```
287
+
288
+ </template>
289
+ </ComponentDemo>
290
+
291
+ ## Sanitization
292
+
293
+ By default, the rendered HTML is sanitized with DOMPurify to prevent XSS. Disabling it (`:sanitize="false"`) renders the raw output of the renderer; only do this when the markdown source is fully trusted.
294
+
295
+ ```vue
296
+ <template>
297
+ <!-- Trusted content only -->
298
+ <MazMarkdownEditor v-model="content" :sanitize="false" />
299
+ </template>
300
+ ```
301
+
302
+ ## Controlled mode
303
+
304
+ The active tab is available through `v-model:mode` (`'write' | 'preview' | 'split'`).
305
+
306
+ ```vue
307
+ <template>
308
+ <MazMarkdownEditor v-model="content" v-model:mode="mode" />
309
+ <p>Current tab: {{ mode }}</p>
310
+ </template>
311
+
312
+ <script lang="ts" setup>
313
+ import { ref } from 'vue'
314
+ import MazMarkdownEditor from 'maz-ui/components/MazMarkdownEditor'
315
+
316
+ const content = ref('')
317
+ const mode = ref<'write' | 'preview' | 'split'>('write')
318
+ </script>
319
+ ```
320
+
321
+ ## Custom translations
322
+
323
+ The tab labels, the empty-preview text and the toolbar button labels come from the `@maz-ui/translations` package (`markdownEditor.*`). You can override any key per-instance with the `translations` prop without touching the global locale:
324
+
325
+ <ComponentDemo>
326
+ <MazMarkdownEditor
327
+ v-model="translated"
328
+ toolbar
329
+ :translations="{ write: 'Édition', preview: 'Aperçu', emptyPreview: 'Rien à afficher' }"
330
+ />
331
+
332
+ <template #code>
333
+
334
+ ```vue
335
+ <template>
336
+ <MazMarkdownEditor
337
+ v-model="content"
338
+ toolbar
339
+ :translations="{ write: 'Édition', preview: 'Aperçu', emptyPreview: 'Rien à afficher' }"
340
+ />
341
+ </template>
342
+ ```
343
+
344
+ </template>
345
+ </ComponentDemo>
346
+
347
+ For app-wide translations, set up the [maz-ui translations plugin](/translations) and the component will pick up your locale automatically.
348
+
349
+ <script lang="ts" setup>
350
+ import { ref } from 'vue'
351
+
352
+ const basic = ref('# Hello maz-ui\n\nThis is **markdown** with a [link](https://maz-ui.com).')
353
+ const withToolbar = ref('Select some text and click **Bold**.')
354
+ const withToolbarConfig = ref('Only a few buttons here.')
355
+ const splitContent = ref('# Split view\n\nType on the left, see the **preview** on the right.')
356
+ const lineNumbersContent = ref('Line one\nLine two\nLine three')
357
+ const withLabel = ref('')
358
+ const stateError = ref('Invalid content')
359
+ const stateSuccess = ref('Valid content')
360
+ const stateDisabled = ref('Disabled editor')
361
+ const customRender = ref('Rendered by a custom function')
362
+ const translated = ref('Localized **markdown** editor.')
363
+
364
+ function upperCaseRenderer(markdown: string) {
365
+ return `<p>${markdown.toUpperCase()}</p>`
366
+ }
367
+ </script>
368
+
369
+ <!--@include: ./../../.vitepress/generated-docs/maz-markdown-editor.doc.md-->
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  title: MazPullToRefresh
3
- description: MazPullToRefresh is a standalone component to add pull to refresh feature
3
+ description: MazPullToRefresh adds a native-feeling pull to refresh gesture to your app or to any scroll container, with a progress ring, haptic feedback and translated, accessible feedback.
4
4
  ---
5
5
 
6
6
  # {{ $frontmatter.title }}
@@ -9,41 +9,200 @@ description: MazPullToRefresh is a standalone component to add pull to refresh f
9
9
 
10
10
  <!--@include: ./../../.vitepress/mixins/getting-started.md-->
11
11
 
12
+ ## Key Features
13
+
14
+ - Works on the window **and on any scroll container**: the closest scrollable ancestor is detected automatically, so it fits app shells with a fixed layout and a scrolling `<main>`
15
+ - Starts only when the container is scrolled to the top, never in the middle of a list
16
+ - Rubber band resistance beyond the trigger distance, and a progress ring that fills while pulling
17
+ - Ignores horizontal swipes and multi-touch gestures, and prevents the native bounce (and the browser's own pull to refresh) while pulling
18
+ - Haptic feedback when the trigger distance is reached (devices supporting `navigator.vibrate`)
19
+ - Texts from [@maz-ui/translations](./../ecosystem/translations.md), overridable with the `translations` prop or the slots
20
+ - Accessible: the refresh is announced to screen readers, `aria-busy` is set while refreshing, and `refresh()` is exposed for a button usable with a keyboard or a mouse
21
+ - Optional `standalone-mode` to enable it only in an installed PWA (browsers already have their own pull to refresh)
22
+ - Built on the headless [usePullToRefresh](./../composables/use-pull-to-refresh.md) composable
23
+
12
24
  ## Demo
13
25
 
14
- ![MazPullToRefresh](/img/maz-pull-to-refresh.gif)
26
+ <div class="maz:flex maz:flex-col maz:items-center maz:gap-3 vp-raw">
27
+ <p class="maz:text-sm maz:text-muted">
28
+ Pull down inside the box on a touch device (or with the touch emulation of your browser's device toolbar).
29
+ </p>
30
+ <div class="maz:h-80 maz:w-full maz:max-w-sm maz:overflow-y-auto maz:rounded-lg maz:border maz:border-divider maz:bg-container">
31
+ <MazPullToRefresh ref="demo" :on-refresh="refreshDemo">
32
+ <ul class="maz:m-0 maz:list-none maz:p-0">
33
+ <li v-for="item in items" :key="item" class="maz:border-b maz:border-divider maz:px-4 maz:py-3">
34
+ {{ item }}
35
+ </li>
36
+ </ul>
37
+ </MazPullToRefresh>
38
+ </div>
39
+ <MazBtn size="sm" :loading="demo?.isRefreshing" @click="demo?.refresh()">
40
+ Refresh ({{ refreshCount }})
41
+ </MazBtn>
42
+ </div>
43
+
44
+ <script lang="ts" setup>
45
+ import { ref, useTemplateRef } from 'vue'
46
+
47
+ const demo = useTemplateRef('demo')
48
+ const refreshCount = ref(0)
49
+ const items = ref(Array.from({ length: 20 }, (_, index) => `Item ${index + 1}`))
50
+
51
+ async function refreshDemo() {
52
+ await new Promise(resolve => setTimeout(resolve, 1000))
53
+ refreshCount.value++
54
+ items.value = [`New item ${refreshCount.value}`, ...items.value]
55
+ }
56
+ </script>
15
57
 
16
58
  ## Basic usage
17
59
 
18
- Wrap your app inside this component
60
+ Wrap your app (or a page) inside the component and give it the function that reloads your data. The spinner stays visible until the returned promise settles.
19
61
 
20
62
  ```vue
21
63
  <script lang="ts" setup>
22
64
  import MazPullToRefresh from 'maz-ui/components/MazPullToRefresh'
23
65
 
24
- async function pullToRefreshAction() {
25
- // do promise or just `window.location.reload()`
66
+ async function refresh() {
67
+ await fetchData()
26
68
  }
27
69
  </script>
28
70
 
71
+ <template>
72
+ <MazPullToRefresh :on-refresh="refresh">
73
+ <main>App content</main>
74
+ </MazPullToRefresh>
75
+ </template>
76
+ ```
77
+
78
+ With Nuxt, `refreshNuxtData` reloads every `useFetch` / `useAsyncData` of the page:
79
+
80
+ ```vue
81
+ <template>
82
+ <MazPullToRefresh :on-refresh="() => refreshNuxtData()" standalone-mode>
83
+ <NuxtPage />
84
+ </MazPullToRefresh>
85
+ </template>
86
+ ```
87
+
88
+ ## Inside a scroll container
89
+
90
+ The pull can only start when its scroll container is at the top. By default, the component uses its **closest scrollable ancestor** (`overflow-y: auto | scroll`), or the window if there is none. Typical app shells with a fixed layout and a scrolling `<main>` work without configuration:
91
+
92
+ ```vue
93
+ <template>
94
+ <div class="app-shell maz:fixed maz:inset-0 maz:flex maz:flex-col">
95
+ <header>…</header>
96
+ <main class="maz:flex-1 maz:overflow-y-auto">
97
+ <MazPullToRefresh :on-refresh="refresh">
98
+ <slot />
99
+ </MazPullToRefresh>
100
+ </main>
101
+ </div>
102
+ </template>
103
+ ```
104
+
105
+ Use `container-selector` when the scroll container is not an ancestor of the component:
106
+
107
+ ```vue
108
+ <template>
109
+ <MazPullToRefresh container-selector="#page-scroller" :on-refresh="refresh">
110
+ …
111
+ </MazPullToRefresh>
112
+ </template>
113
+ ```
114
+
115
+ ## Installed apps only
116
+
117
+ Browsers already provide their own pull to refresh. With `standalone-mode`, the component is only active when the app runs as an installed PWA (`display-mode: standalone`):
118
+
119
+ ```vue
120
+ <template>
121
+ <MazPullToRefresh standalone-mode :on-refresh="refresh">
122
+ …
123
+ </MazPullToRefresh>
124
+ </template>
125
+ ```
126
+
127
+ ## Tuning the gesture
128
+
129
+ | Prop | Default | Effect |
130
+ | -------------- | ---------------- | --------------------------------------------------------------------------------------- |
131
+ | `distance` | `80` | Pull distance (px, after resistance) needed to trigger a refresh |
132
+ | `max-distance` | `distance * 1.6` | Upper bound of the rubber band beyond `distance` |
133
+ | `resistance` | `0.5` | Ratio between the finger movement and the pull distance (lower is stiffer) |
134
+ | `min-duration` | `400` | Minimum duration (ms) of the refreshing state, so fast refreshes still show the feedback |
135
+ | `haptic` | `true` | Short vibration when `distance` is reached |
136
+
137
+ ## Customize the indicator
138
+
139
+ The three states have their own slot. Each one receives the pull `progress` (0 to 1) and the current `distance` in px.
140
+
141
+ ```vue
142
+ <template>
143
+ <MazPullToRefresh :on-refresh="refresh" header-class="maz:bg-surface-600">
144
+ <template #pull-before="{ progress }">
145
+ <span>{{ Math.round(progress * 100) }}%</span>
146
+ </template>
147
+ <template #pull-ready>
148
+ <span>Let go!</span>
149
+ </template>
150
+ <template #pull-loading>
151
+ <MazSpinner color="secondary" />
152
+ </template>
153
+
154
+ <main>App content</main>
155
+ </MazPullToRefresh>
156
+ </template>
157
+ ```
158
+
159
+ `spinner-color` sets the color of the progress ring, the ready arrow and the default spinner (`primary` by default).
160
+
161
+ ## Translations
162
+
163
+ Texts come from [@maz-ui/translations](./../ecosystem/translations.md) (`pullToRefresh.pull`, `pullToRefresh.release`, `pullToRefresh.refreshing`). Override them per instance with the `translations` prop:
164
+
165
+ ```vue
29
166
  <template>
30
167
  <MazPullToRefresh
31
- header-class="maz:bg-bg-dark maz:text-foreground-light"
32
- class="maz:flex maz:min-h-screen maz:w-full maz:flex-col"
33
- :action="pullToRefreshAction"
34
- spinner-color="contrast"
35
- standalone-mode
36
- :disabled="false"
168
+ :on-refresh="refresh"
169
+ :translations="{ pull: 'Swipe down', release: 'Release', refreshing: 'Updating…' }"
37
170
  >
38
- <div>
39
- App Content
40
- </div>
171
+ …
172
+ </MazPullToRefresh>
173
+ </template>
174
+ ```
175
+
176
+ ## Accessibility
177
+
178
+ The gesture is touch only. To give keyboard and mouse users the same action, call the exposed `refresh()` from a button: the indicator and the events behave exactly as with the gesture.
179
+
180
+ ```vue
181
+ <script lang="ts" setup>
182
+ import { useTemplateRef } from 'vue'
183
+
184
+ const pullToRefresh = useTemplateRef('pullToRefresh')
185
+ </script>
186
+
187
+ <template>
188
+ <MazBtn :loading="pullToRefresh?.isRefreshing" @click="pullToRefresh?.refresh()">
189
+ Refresh
190
+ </MazBtn>
191
+
192
+ <MazPullToRefresh ref="pullToRefresh" :on-refresh="refresh">
193
+ …
41
194
  </MazPullToRefresh>
42
195
  </template>
43
196
  ```
44
197
 
45
- ::: warning
46
- More documentation to come
47
- :::
198
+ While refreshing, the root element has `aria-busy="true"` and the refreshing text is announced through a polite live region. The visual indicator is hidden from assistive technologies.
199
+
200
+ ## Events
201
+
202
+ The events follow the life of a refresh: `start`, then `loaded` and `response` (with the value resolved by `on-refresh`) or `error`, and always `finish`. An error thrown by `on-refresh` is emitted, never thrown again.
203
+
204
+ ## Headless usage
205
+
206
+ Need a different indicator, or a gesture on an element without wrapping it? Use the [usePullToRefresh](./../composables/use-pull-to-refresh.md) composable.
48
207
 
49
208
  <!--@include: ./../../.vitepress/generated-docs/maz-pull-to-refresh.doc.md-->