@mostfeatured/dbi 0.2.13 → 0.2.15
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/src/types/Components/HTMLComponentsV2/index.d.ts +33 -1
- package/dist/src/types/Components/HTMLComponentsV2/index.d.ts.map +1 -1
- package/dist/src/types/Components/HTMLComponentsV2/index.js +408 -82
- package/dist/src/types/Components/HTMLComponentsV2/index.js.map +1 -1
- package/dist/src/types/Components/HTMLComponentsV2/parser.d.ts +52 -0
- package/dist/src/types/Components/HTMLComponentsV2/parser.d.ts.map +1 -1
- package/dist/src/types/Components/HTMLComponentsV2/parser.js +275 -0
- package/dist/src/types/Components/HTMLComponentsV2/parser.js.map +1 -1
- package/dist/src/types/Components/HTMLComponentsV2/svelteParser.d.ts +26 -0
- package/dist/src/types/Components/HTMLComponentsV2/svelteParser.d.ts.map +1 -1
- package/dist/src/types/Components/HTMLComponentsV2/svelteParser.js +509 -34
- package/dist/src/types/Components/HTMLComponentsV2/svelteParser.js.map +1 -1
- package/dist/src/types/Components/HTMLComponentsV2/svelteRenderer.d.ts +10 -0
- package/dist/src/types/Components/HTMLComponentsV2/svelteRenderer.d.ts.map +1 -1
- package/dist/src/types/Components/HTMLComponentsV2/svelteRenderer.js +76 -11
- package/dist/src/types/Components/HTMLComponentsV2/svelteRenderer.js.map +1 -1
- package/dist/test/index.js +76 -3
- package/dist/test/index.js.map +1 -1
- package/docs/ADVANCED_FEATURES.md +4 -0
- package/docs/API_REFERENCE.md +4 -0
- package/docs/CHAT_INPUT.md +4 -0
- package/docs/COMPONENTS.md +4 -0
- package/docs/EVENTS.md +4 -0
- package/docs/GETTING_STARTED.md +4 -0
- package/docs/LOCALIZATION.md +4 -0
- package/docs/README.md +4 -0
- package/docs/SVELTE_COMPONENTS.md +162 -6
- package/docs/llm/ADVANCED_FEATURES.txt +521 -0
- package/docs/llm/API_REFERENCE.txt +659 -0
- package/docs/llm/CHAT_INPUT.txt +514 -0
- package/docs/llm/COMPONENTS.txt +595 -0
- package/docs/llm/EVENTS.txt +449 -0
- package/docs/llm/GETTING_STARTED.txt +296 -0
- package/docs/llm/LOCALIZATION.txt +501 -0
- package/docs/llm/README.txt +193 -0
- package/docs/llm/SVELTE_COMPONENTS.txt +566 -0
- package/generated/svelte-dbi.d.ts +122 -0
- package/package.json +1 -1
- package/src/types/Components/HTMLComponentsV2/index.ts +466 -94
- package/src/types/Components/HTMLComponentsV2/parser.ts +317 -0
- package/src/types/Components/HTMLComponentsV2/svelteParser.ts +567 -35
- package/src/types/Components/HTMLComponentsV2/svelteRenderer.ts +91 -13
- package/test/index.ts +76 -3
- package/test/product-showcase.svelte +380 -24
- package/llm.txt +0 -1088
|
@@ -0,0 +1,566 @@
|
|
|
1
|
+
================================================================================
|
|
2
|
+
DBI - SVELTE COMPONENTS GUIDE - LLM REFERENCE DOCUMENT
|
|
3
|
+
================================================================================
|
|
4
|
+
|
|
5
|
+
DOCUMENT TYPE: Svelte 5 Integration Reference
|
|
6
|
+
PACKAGE: @mostfeatured/dbi
|
|
7
|
+
|
|
8
|
+
================================================================================
|
|
9
|
+
SECTION 1: OVERVIEW
|
|
10
|
+
================================================================================
|
|
11
|
+
|
|
12
|
+
DBI provides Svelte 5-based component system for Discord UI with Components V2.
|
|
13
|
+
|
|
14
|
+
KEY FEATURES:
|
|
15
|
+
- Svelte 5 Syntax with $props() runes
|
|
16
|
+
- Auto-Reactivity when data changes
|
|
17
|
+
- Lifecycle Hooks (onMount, onDestroy)
|
|
18
|
+
- Throttled Rendering to prevent API abuse
|
|
19
|
+
- Full TypeScript support
|
|
20
|
+
|
|
21
|
+
================================================================================
|
|
22
|
+
SECTION 2: QUICK START
|
|
23
|
+
================================================================================
|
|
24
|
+
|
|
25
|
+
STEP 1 - REGISTER SVELTE COMPONENT:
|
|
26
|
+
-----------------------------------
|
|
27
|
+
import { createDBI } from "@mostfeatured/dbi";
|
|
28
|
+
import path from "path";
|
|
29
|
+
|
|
30
|
+
dbi.register(({ HTMLComponentsV2 }) => {
|
|
31
|
+
HTMLComponentsV2({
|
|
32
|
+
name: "my-component",
|
|
33
|
+
mode: "svelte",
|
|
34
|
+
file: path.join(__dirname, "my-component.svelte"),
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
STEP 2 - CREATE SVELTE FILE:
|
|
39
|
+
----------------------------
|
|
40
|
+
<script>
|
|
41
|
+
let { count = 0 } = $props();
|
|
42
|
+
|
|
43
|
+
function increment() {
|
|
44
|
+
data.count++;
|
|
45
|
+
}
|
|
46
|
+
</script>
|
|
47
|
+
|
|
48
|
+
<components>
|
|
49
|
+
<text-display>Count: {count}</text-display>
|
|
50
|
+
<action-row>
|
|
51
|
+
<button style="Primary" handler={increment}>+1</button>
|
|
52
|
+
</action-row>
|
|
53
|
+
</components>
|
|
54
|
+
|
|
55
|
+
STEP 3 - SEND COMPONENT:
|
|
56
|
+
------------------------
|
|
57
|
+
ChatInput({
|
|
58
|
+
name: "counter",
|
|
59
|
+
description: "Interactive counter",
|
|
60
|
+
async onExecute({ interaction, dbi }) {
|
|
61
|
+
const component = dbi.interaction("my-component");
|
|
62
|
+
await component.send(interaction, {
|
|
63
|
+
data: { count: 0 }
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
================================================================================
|
|
69
|
+
SECTION 3: COMPONENT STRUCTURE
|
|
70
|
+
================================================================================
|
|
71
|
+
|
|
72
|
+
A DBI Svelte component has two parts:
|
|
73
|
+
|
|
74
|
+
SCRIPT BLOCK:
|
|
75
|
+
-------------
|
|
76
|
+
<script>
|
|
77
|
+
/// <reference types="@mostfeatured/dbi/svelte" />
|
|
78
|
+
import stuffs from "stuffs";
|
|
79
|
+
|
|
80
|
+
let {
|
|
81
|
+
products = [],
|
|
82
|
+
currentIndex = 0,
|
|
83
|
+
cart = [],
|
|
84
|
+
view = "browse",
|
|
85
|
+
} = $props();
|
|
86
|
+
|
|
87
|
+
function nextProduct() {
|
|
88
|
+
data.currentIndex = (currentIndex + 1) % products.length;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function addToCart(ctx) {
|
|
92
|
+
const product = products[currentIndex];
|
|
93
|
+
data.cart = [...cart, product];
|
|
94
|
+
ctx.interaction.reply({
|
|
95
|
+
content: "Added to cart!",
|
|
96
|
+
flags: ["Ephemeral"],
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
onMount(() => {
|
|
101
|
+
const interval = setInterval(() => {
|
|
102
|
+
data.elapsedTime += 1;
|
|
103
|
+
}, 1000);
|
|
104
|
+
return () => clearInterval(interval); // Cleanup
|
|
105
|
+
});
|
|
106
|
+
</script>
|
|
107
|
+
|
|
108
|
+
TEMPLATE BLOCK:
|
|
109
|
+
---------------
|
|
110
|
+
<components>
|
|
111
|
+
<container accent-color="5865F2">
|
|
112
|
+
<components>
|
|
113
|
+
<text-display>## Welcome!</text-display>
|
|
114
|
+
<action-row>
|
|
115
|
+
<button style="Primary" handler={nextProduct}>Next</button>
|
|
116
|
+
</action-row>
|
|
117
|
+
</components>
|
|
118
|
+
</container>
|
|
119
|
+
</components>
|
|
120
|
+
|
|
121
|
+
================================================================================
|
|
122
|
+
SECTION 4: PROPS AND REACTIVITY
|
|
123
|
+
================================================================================
|
|
124
|
+
|
|
125
|
+
DECLARING PROPS:
|
|
126
|
+
----------------
|
|
127
|
+
<script>
|
|
128
|
+
let {
|
|
129
|
+
count = 0,
|
|
130
|
+
items = [],
|
|
131
|
+
settings = { theme: "dark" },
|
|
132
|
+
} = $props();
|
|
133
|
+
</script>
|
|
134
|
+
|
|
135
|
+
THE DATA OBJECT:
|
|
136
|
+
----------------
|
|
137
|
+
Use global `data` object to update state. Changes trigger re-renders:
|
|
138
|
+
|
|
139
|
+
<script>
|
|
140
|
+
let { count = 0 } = $props();
|
|
141
|
+
|
|
142
|
+
function increment() {
|
|
143
|
+
data.count++; // Triggers auto-render
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function reset() {
|
|
147
|
+
data.count = 0;
|
|
148
|
+
}
|
|
149
|
+
</script>
|
|
150
|
+
|
|
151
|
+
REACTIVE UPDATES:
|
|
152
|
+
-----------------
|
|
153
|
+
The `data` object is a Proxy that:
|
|
154
|
+
1. Detects property changes
|
|
155
|
+
2. Automatically re-renders the component
|
|
156
|
+
3. Throttles updates (default: 250ms between renders)
|
|
157
|
+
|
|
158
|
+
<script>
|
|
159
|
+
let { items = [] } = $props();
|
|
160
|
+
|
|
161
|
+
function addItem(ctx) {
|
|
162
|
+
// Arrays must be reassigned to trigger reactivity
|
|
163
|
+
data.items = [...items, { name: "New Item" }];
|
|
164
|
+
}
|
|
165
|
+
</script>
|
|
166
|
+
|
|
167
|
+
================================================================================
|
|
168
|
+
SECTION 5: LIFECYCLE HOOKS
|
|
169
|
+
================================================================================
|
|
170
|
+
|
|
171
|
+
onMount:
|
|
172
|
+
--------
|
|
173
|
+
Runs when component is first sent. For timers, intervals, fetching data.
|
|
174
|
+
|
|
175
|
+
<script>
|
|
176
|
+
let { seconds = 0 } = $props();
|
|
177
|
+
|
|
178
|
+
onMount(() => {
|
|
179
|
+
console.log("Component mounted!");
|
|
180
|
+
|
|
181
|
+
const interval = setInterval(() => {
|
|
182
|
+
data.seconds++;
|
|
183
|
+
}, 1000);
|
|
184
|
+
|
|
185
|
+
// Return cleanup function (optional)
|
|
186
|
+
return () => {
|
|
187
|
+
clearInterval(interval);
|
|
188
|
+
console.log("Timer cleared!");
|
|
189
|
+
};
|
|
190
|
+
});
|
|
191
|
+
</script>
|
|
192
|
+
|
|
193
|
+
onDestroy:
|
|
194
|
+
----------
|
|
195
|
+
Runs when component is destroyed (via $unRef or manual destroy() call).
|
|
196
|
+
|
|
197
|
+
<script>
|
|
198
|
+
let timer;
|
|
199
|
+
|
|
200
|
+
onMount(() => {
|
|
201
|
+
timer = setInterval(() => data.count++, 1000);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
onDestroy(() => {
|
|
205
|
+
clearInterval(timer);
|
|
206
|
+
console.log("Component destroyed, cleanup complete!");
|
|
207
|
+
});
|
|
208
|
+
</script>
|
|
209
|
+
|
|
210
|
+
MANUAL DESTRUCTION:
|
|
211
|
+
-------------------
|
|
212
|
+
<script>
|
|
213
|
+
function handleClose() {
|
|
214
|
+
destroy(); // Runs onDestroy callbacks, removes ref
|
|
215
|
+
}
|
|
216
|
+
</script>
|
|
217
|
+
|
|
218
|
+
<components>
|
|
219
|
+
<action-row>
|
|
220
|
+
<button style="Danger" handler={handleClose}>Close</button>
|
|
221
|
+
</action-row>
|
|
222
|
+
</components>
|
|
223
|
+
|
|
224
|
+
================================================================================
|
|
225
|
+
SECTION 6: RENDER HELPERS
|
|
226
|
+
================================================================================
|
|
227
|
+
|
|
228
|
+
HELPER | DESCRIPTION
|
|
229
|
+
-------------------|--------------------------------------------------
|
|
230
|
+
render() | Force immediate render
|
|
231
|
+
update() | Update using interaction.update() - best for buttons
|
|
232
|
+
rerender() | Re-render using message.edit() - after reply/followUp
|
|
233
|
+
noRender() | Disable auto-render for current handler
|
|
234
|
+
setThrottle() | Set minimum interval between renders
|
|
235
|
+
lowPriorityUpdate()| Background update that yields to handler interactions
|
|
236
|
+
|
|
237
|
+
EXAMPLES:
|
|
238
|
+
---------
|
|
239
|
+
<script>
|
|
240
|
+
function forceUpdate() {
|
|
241
|
+
data.value = computeExpensiveValue();
|
|
242
|
+
render(); // Force immediate render
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
async function handleButton() {
|
|
246
|
+
data.count++;
|
|
247
|
+
await update(); // Uses interaction.update()
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
async function processData(ctx) {
|
|
251
|
+
await ctx.interaction.reply({ content: "Processing..." });
|
|
252
|
+
data.result = await fetchData();
|
|
253
|
+
await rerender(); // Uses message.edit()
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function backgroundTask() {
|
|
257
|
+
noRender(); // Don't update UI
|
|
258
|
+
data.internalState = calculate();
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// For timer that updates every second
|
|
262
|
+
setThrottle(1000);
|
|
263
|
+
|
|
264
|
+
// Low-priority update for intervals (won't conflict with button clicks)
|
|
265
|
+
onMount(() => {
|
|
266
|
+
const interval = setInterval(() => {
|
|
267
|
+
lowPriorityUpdate(() => {
|
|
268
|
+
data.seconds++;
|
|
269
|
+
});
|
|
270
|
+
}, 1000);
|
|
271
|
+
return () => clearInterval(interval);
|
|
272
|
+
});
|
|
273
|
+
</script>
|
|
274
|
+
|
|
275
|
+
================================================================================
|
|
276
|
+
SECTION 7: HTML ELEMENTS REFERENCE
|
|
277
|
+
================================================================================
|
|
278
|
+
|
|
279
|
+
LAYOUT COMPONENTS:
|
|
280
|
+
------------------
|
|
281
|
+
ELEMENT | DESCRIPTION
|
|
282
|
+
-----------------|--------------------------------------------------
|
|
283
|
+
<components> | Root wrapper for all Discord components
|
|
284
|
+
<action-row> | Container for buttons (max 5) or single select menu
|
|
285
|
+
<container> | Colored container with accent-color attribute
|
|
286
|
+
<section> | Section with components and optional accessory
|
|
287
|
+
<separator> | Visual divider between components
|
|
288
|
+
|
|
289
|
+
CONTAINER EXAMPLE:
|
|
290
|
+
<container accent-color="5865F2" spoiler>
|
|
291
|
+
<components>
|
|
292
|
+
<!-- Content -->
|
|
293
|
+
</components>
|
|
294
|
+
</container>
|
|
295
|
+
|
|
296
|
+
SECTION EXAMPLE:
|
|
297
|
+
<section>
|
|
298
|
+
<components>
|
|
299
|
+
<text-display>Main content</text-display>
|
|
300
|
+
</components>
|
|
301
|
+
<thumbnail url="https://example.com/image.png"></thumbnail>
|
|
302
|
+
</section>
|
|
303
|
+
|
|
304
|
+
SEPARATOR:
|
|
305
|
+
<separator divider spacing="2"></separator>
|
|
306
|
+
|
|
307
|
+
INTERACTIVE COMPONENTS:
|
|
308
|
+
-----------------------
|
|
309
|
+
BUTTON:
|
|
310
|
+
<button
|
|
311
|
+
style="Primary"
|
|
312
|
+
emoji="🚀"
|
|
313
|
+
handler={handleClick}
|
|
314
|
+
disabled
|
|
315
|
+
>
|
|
316
|
+
Click Me
|
|
317
|
+
</button>
|
|
318
|
+
|
|
319
|
+
BUTTON STYLES: Primary, Secondary, Success, Danger, Link, Premium
|
|
320
|
+
NOTE: Use `onclick` as alias for `handler`
|
|
321
|
+
|
|
322
|
+
STRING SELECT:
|
|
323
|
+
<string-select
|
|
324
|
+
placeholder="Choose an option..."
|
|
325
|
+
min-values="1"
|
|
326
|
+
max-values="3"
|
|
327
|
+
handler={handleSelect}
|
|
328
|
+
>
|
|
329
|
+
<option value="a" description="First option" emoji="1️⃣" default>
|
|
330
|
+
Option A
|
|
331
|
+
</option>
|
|
332
|
+
<option value="b" description="Second option">
|
|
333
|
+
Option B
|
|
334
|
+
</option>
|
|
335
|
+
</string-select>
|
|
336
|
+
|
|
337
|
+
OTHER SELECT MENUS:
|
|
338
|
+
<user-select placeholder="Select users..." handler={handleUsers}></user-select>
|
|
339
|
+
<role-select placeholder="Select roles..." handler={handleRoles}></role-select>
|
|
340
|
+
<channel-select placeholder="Select channels..." handler={handleChannels}></channel-select>
|
|
341
|
+
<mentionable-select placeholder="Select..." handler={handleMentionables}></mentionable-select>
|
|
342
|
+
|
|
343
|
+
DISPLAY COMPONENTS:
|
|
344
|
+
-------------------
|
|
345
|
+
TEXT DISPLAY:
|
|
346
|
+
<text-display>
|
|
347
|
+
## Heading
|
|
348
|
+
**Bold** and *italic* text
|
|
349
|
+
- List item 1
|
|
350
|
+
- List item 2
|
|
351
|
+
</text-display>
|
|
352
|
+
|
|
353
|
+
THUMBNAIL:
|
|
354
|
+
<thumbnail url="https://example.com/image.png"></thumbnail>
|
|
355
|
+
|
|
356
|
+
MEDIA GALLERY:
|
|
357
|
+
<media-gallery>
|
|
358
|
+
<item url="https://example.com/1.png" description="Image 1"></item>
|
|
359
|
+
<item url="https://example.com/2.png" spoiler></item>
|
|
360
|
+
</media-gallery>
|
|
361
|
+
|
|
362
|
+
FILE:
|
|
363
|
+
<file url="attachment://document.pdf" spoiler></file>
|
|
364
|
+
|
|
365
|
+
================================================================================
|
|
366
|
+
SECTION 8: MODAL COMPONENTS
|
|
367
|
+
================================================================================
|
|
368
|
+
|
|
369
|
+
MODAL DEFINITION:
|
|
370
|
+
-----------------
|
|
371
|
+
<components
|
|
372
|
+
type="modal"
|
|
373
|
+
id="feedback-modal"
|
|
374
|
+
title="Submit Feedback"
|
|
375
|
+
>
|
|
376
|
+
<field label="Rating" description="How would you rate?">
|
|
377
|
+
<string-select id="rating" placeholder="Select rating">
|
|
378
|
+
<option value="5">⭐⭐⭐⭐⭐ Excellent</option>
|
|
379
|
+
<option value="4">⭐⭐⭐⭐ Great</option>
|
|
380
|
+
<option value="3">⭐⭐⭐ Good</option>
|
|
381
|
+
</string-select>
|
|
382
|
+
</field>
|
|
383
|
+
<field label="Comments" description="Tell us more">
|
|
384
|
+
<text-input id="comments" style="Paragraph" placeholder="Your feedback..." />
|
|
385
|
+
</field>
|
|
386
|
+
</components>
|
|
387
|
+
|
|
388
|
+
TEXT INPUT:
|
|
389
|
+
-----------
|
|
390
|
+
<field label="Username" description="Enter display name">
|
|
391
|
+
<text-input
|
|
392
|
+
id="username"
|
|
393
|
+
placeholder="Enter your username"
|
|
394
|
+
style="Short"
|
|
395
|
+
min-length="3"
|
|
396
|
+
max-length="32"
|
|
397
|
+
required
|
|
398
|
+
/>
|
|
399
|
+
</field>
|
|
400
|
+
|
|
401
|
+
TEXT INPUT STYLES: Short, Paragraph
|
|
402
|
+
|
|
403
|
+
USING showModal():
|
|
404
|
+
------------------
|
|
405
|
+
<script>
|
|
406
|
+
async function openFeedbackModal(ctx) {
|
|
407
|
+
const { fields, interaction } = await showModal("feedback-modal");
|
|
408
|
+
|
|
409
|
+
const rating = fields.rating[0]; // string-select returns array
|
|
410
|
+
const comments = fields.comments; // text-input returns string
|
|
411
|
+
|
|
412
|
+
interaction.reply({
|
|
413
|
+
content: `Thanks for your ${rating}-star feedback!`,
|
|
414
|
+
flags: ["Ephemeral"]
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
</script>
|
|
418
|
+
|
|
419
|
+
MODAL FIELD RETURN TYPES:
|
|
420
|
+
-------------------------
|
|
421
|
+
COMPONENT | RETURN TYPE
|
|
422
|
+
--------------------|----------------------------------
|
|
423
|
+
text-input | string
|
|
424
|
+
string-select | string[]
|
|
425
|
+
user-select | string[] (user IDs)
|
|
426
|
+
role-select | string[] (role IDs)
|
|
427
|
+
channel-select | string[] (channel IDs)
|
|
428
|
+
mentionable-select | { values, users, roles }
|
|
429
|
+
file-upload | Attachment[]
|
|
430
|
+
|
|
431
|
+
================================================================================
|
|
432
|
+
SECTION 9: HANDLER FUNCTIONS
|
|
433
|
+
================================================================================
|
|
434
|
+
|
|
435
|
+
<script>
|
|
436
|
+
function handleButton(ctx) {
|
|
437
|
+
const { interaction } = ctx;
|
|
438
|
+
|
|
439
|
+
ctx.interaction.reply({
|
|
440
|
+
content: "Button clicked!",
|
|
441
|
+
flags: ["Ephemeral"],
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
const { dbi } = ctx; // DBI instance
|
|
445
|
+
const { locale } = ctx; // Locale helpers
|
|
446
|
+
const text = locale.user("greeting");
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// Handler without ctx - just updates data
|
|
450
|
+
function simpleHandler() {
|
|
451
|
+
data.count++;
|
|
452
|
+
// Auto-renders after handler completes
|
|
453
|
+
}
|
|
454
|
+
</script>
|
|
455
|
+
|
|
456
|
+
<components>
|
|
457
|
+
<action-row>
|
|
458
|
+
<button handler={handleButton}>With Context</button>
|
|
459
|
+
<button handler={simpleHandler}>Simple</button>
|
|
460
|
+
</action-row>
|
|
461
|
+
</components>
|
|
462
|
+
|
|
463
|
+
CONTEXT OBJECT:
|
|
464
|
+
---------------
|
|
465
|
+
PROPERTY | TYPE | DESCRIPTION
|
|
466
|
+
------------|--------------------------------|------------------------
|
|
467
|
+
interaction | ButtonInteraction/SelectMenu | Discord.js interaction
|
|
468
|
+
dbi | DBI | DBI instance
|
|
469
|
+
locale | object | Locale helpers
|
|
470
|
+
|
|
471
|
+
================================================================================
|
|
472
|
+
SECTION 10: USING EXTERNAL MODULES
|
|
473
|
+
================================================================================
|
|
474
|
+
|
|
475
|
+
<script>
|
|
476
|
+
import stuffs from "stuffs";
|
|
477
|
+
import lodash from "lodash";
|
|
478
|
+
import { someUtil } from "./utils";
|
|
479
|
+
|
|
480
|
+
function formatTime(seconds) {
|
|
481
|
+
return stuffs.formatSeconds(seconds);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
function sortItems() {
|
|
485
|
+
data.items = lodash.sortBy(items, "name");
|
|
486
|
+
}
|
|
487
|
+
</script>
|
|
488
|
+
|
|
489
|
+
Modules loaded via require() at runtime - must be installed in project.
|
|
490
|
+
|
|
491
|
+
================================================================================
|
|
492
|
+
SECTION 11: TYPE DEFINITIONS
|
|
493
|
+
================================================================================
|
|
494
|
+
|
|
495
|
+
Add type reference for IDE support:
|
|
496
|
+
|
|
497
|
+
<script>
|
|
498
|
+
/// <reference types="@mostfeatured/dbi/svelte" />
|
|
499
|
+
|
|
500
|
+
// Now you get autocomplete for:
|
|
501
|
+
// - render(), update(), rerender(), noRender(), setThrottle()
|
|
502
|
+
// - onMount(), onDestroy(), destroy()
|
|
503
|
+
// - ctx, data
|
|
504
|
+
// - All HTML elements
|
|
505
|
+
</script>
|
|
506
|
+
|
|
507
|
+
================================================================================
|
|
508
|
+
SECTION 12: API REFERENCE
|
|
509
|
+
================================================================================
|
|
510
|
+
|
|
511
|
+
COMPONENT CLASS METHODS:
|
|
512
|
+
------------------------
|
|
513
|
+
const component = dbi.interaction("my-component");
|
|
514
|
+
|
|
515
|
+
await component.send(interaction, { data: { count: 0 } });
|
|
516
|
+
await component.send(channel, { data: { count: 0 } });
|
|
517
|
+
component.destroy(refId);
|
|
518
|
+
component.destroyAll();
|
|
519
|
+
const json = component.toJSON({ data: { count: 0 } });
|
|
520
|
+
|
|
521
|
+
SEND OPTIONS:
|
|
522
|
+
-------------
|
|
523
|
+
{
|
|
524
|
+
data?: Record<string, any>; // Initial data
|
|
525
|
+
flags?: string[]; // Message flags
|
|
526
|
+
content?: string; // Text content
|
|
527
|
+
ephemeral?: boolean; // Ephemeral message
|
|
528
|
+
reply?: boolean; // Force reply
|
|
529
|
+
followUp?: boolean; // Use followUp instead
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
================================================================================
|
|
533
|
+
SECTION 13: BEST PRACTICES
|
|
534
|
+
================================================================================
|
|
535
|
+
|
|
536
|
+
1. Use $props() for initial state - destructure with defaults
|
|
537
|
+
2. Mutate `data` for updates - don't reassign entire data object
|
|
538
|
+
3. Return cleanup from onMount - prevents memory leaks
|
|
539
|
+
4. Use noRender() for background tasks - avoid unnecessary renders
|
|
540
|
+
5. Set appropriate throttle - match your update frequency
|
|
541
|
+
6. Use destroy() for cleanup - clean up timers when done
|
|
542
|
+
7. Add type reference - get full IDE support
|
|
543
|
+
|
|
544
|
+
================================================================================
|
|
545
|
+
SECTION 14: TROUBLESHOOTING
|
|
546
|
+
================================================================================
|
|
547
|
+
|
|
548
|
+
COMPONENT NOT UPDATING?
|
|
549
|
+
- Use data.property = value, not reassigning data
|
|
550
|
+
- Check that noRender() wasn't called earlier
|
|
551
|
+
|
|
552
|
+
TIMER KEEPS RUNNING AFTER MESSAGE DELETED?
|
|
553
|
+
- Return cleanup function from onMount
|
|
554
|
+
- Or use onDestroy to clear intervals
|
|
555
|
+
|
|
556
|
+
RATE LIMITED BY DISCORD?
|
|
557
|
+
- Increase throttle with setThrottle(500) or higher
|
|
558
|
+
- System automatically retries on rate limits (max 3)
|
|
559
|
+
|
|
560
|
+
IDE NOT SHOWING AUTOCOMPLETE?
|
|
561
|
+
- Add /// <reference types="@mostfeatured/dbi/svelte" /> at top
|
|
562
|
+
- Make sure @mostfeatured/dbi is installed
|
|
563
|
+
|
|
564
|
+
================================================================================
|
|
565
|
+
END OF DOCUMENT
|
|
566
|
+
================================================================================
|
|
@@ -107,6 +107,32 @@ declare global {
|
|
|
107
107
|
*/
|
|
108
108
|
function setThrottle(ms: number): void;
|
|
109
109
|
|
|
110
|
+
/**
|
|
111
|
+
* Low-priority update for background tasks like intervals.
|
|
112
|
+
* If a user interaction handler is currently running, the callback is executed
|
|
113
|
+
* but rendering is skipped (the handler's render will include these changes).
|
|
114
|
+
*
|
|
115
|
+
* Use this to prevent interval updates from conflicting with button clicks.
|
|
116
|
+
*
|
|
117
|
+
* @param callback - Function to execute that updates data
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* ```svelte
|
|
121
|
+
* onMount(() => {
|
|
122
|
+
* const interval = setInterval(() => {
|
|
123
|
+
* // If user clicks a button during this interval tick,
|
|
124
|
+
* // this update won't trigger a conflicting render
|
|
125
|
+
* lowPriorityUpdate(() => {
|
|
126
|
+
* data.elapsedTime += 1;
|
|
127
|
+
* });
|
|
128
|
+
* }, 1000);
|
|
129
|
+
*
|
|
130
|
+
* return () => clearInterval(interval);
|
|
131
|
+
* });
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
function lowPriorityUpdate(callback: () => void): void;
|
|
135
|
+
|
|
110
136
|
// ============================================
|
|
111
137
|
// LIFECYCLE HOOKS
|
|
112
138
|
// ============================================
|
|
@@ -183,6 +209,102 @@ declare global {
|
|
|
183
209
|
*/
|
|
184
210
|
function destroy(): void;
|
|
185
211
|
|
|
212
|
+
// ============================================
|
|
213
|
+
// MODAL HELPERS
|
|
214
|
+
// ============================================
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Modal submit response from showModal()
|
|
218
|
+
*/
|
|
219
|
+
interface ModalResponse {
|
|
220
|
+
/** Object containing text input values keyed by input id */
|
|
221
|
+
fields: Record<string, string>;
|
|
222
|
+
/** The Discord ModalSubmitInteraction */
|
|
223
|
+
interaction: import("discord.js").ModalSubmitInteraction;
|
|
224
|
+
/** Full execution context */
|
|
225
|
+
ctx: any;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Options for showModal()
|
|
230
|
+
*/
|
|
231
|
+
interface ShowModalOptions {
|
|
232
|
+
/**
|
|
233
|
+
* Timeout in milliseconds. After this time, the Promise will reject with a timeout error.
|
|
234
|
+
* - Default: 600000 (10 minutes)
|
|
235
|
+
* - Set to 0 for no timeout (unlimited wait)
|
|
236
|
+
*
|
|
237
|
+
* @example
|
|
238
|
+
* ```svelte
|
|
239
|
+
* // 1 minute timeout
|
|
240
|
+
* await showModal("my-modal", { timeout: 60000 });
|
|
241
|
+
*
|
|
242
|
+
* // No timeout (unlimited)
|
|
243
|
+
* await showModal("my-modal", { timeout: 0 });
|
|
244
|
+
* ```
|
|
245
|
+
*/
|
|
246
|
+
timeout?: number;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Shows a modal defined in the component and returns a Promise.
|
|
251
|
+
* Modals are defined using `<components type="modal" id="...">`.
|
|
252
|
+
*
|
|
253
|
+
* You can use it in two ways:
|
|
254
|
+
* 1. With `onsubmit` handler on the modal - Promise resolves but you handle in callback
|
|
255
|
+
* 2. Without `onsubmit` - await the Promise to get fields directly
|
|
256
|
+
*
|
|
257
|
+
* @param modalId - The id of the modal to show (from `<components type="modal" id="xxx">`)
|
|
258
|
+
* @returns Promise that resolves with { fields, interaction, ctx } when modal is submitted
|
|
259
|
+
*
|
|
260
|
+
* @example
|
|
261
|
+
* ```svelte
|
|
262
|
+
* <script>
|
|
263
|
+
* // Method 1: Using onsubmit handler
|
|
264
|
+
* async function openEditModal() {
|
|
265
|
+
* await showModal("edit-item");
|
|
266
|
+
* // Modal was shown, handler will be called on submit
|
|
267
|
+
* }
|
|
268
|
+
*
|
|
269
|
+
* function handleEditSubmit(ctx, fields) {
|
|
270
|
+
* data.itemName = fields.name;
|
|
271
|
+
* ctx.interaction.reply({ content: "Updated!", flags: ["Ephemeral"] });
|
|
272
|
+
* }
|
|
273
|
+
*
|
|
274
|
+
* // Method 2: Await response directly (no onsubmit needed)
|
|
275
|
+
* async function openReviewModal(ctx) {
|
|
276
|
+
* data.editingProduct = products[currentIndex];
|
|
277
|
+
* const { fields, interaction } = await showModal("review-modal");
|
|
278
|
+
*
|
|
279
|
+
* // Handle the response inline
|
|
280
|
+
* data.reviews = [...reviews, {
|
|
281
|
+
* rating: fields.rating,
|
|
282
|
+
* review: fields.review
|
|
283
|
+
* }];
|
|
284
|
+
*
|
|
285
|
+
* interaction.reply({ content: "Thanks for your review!", flags: ["Ephemeral"] });
|
|
286
|
+
* }
|
|
287
|
+
* </script>
|
|
288
|
+
*
|
|
289
|
+
* <components>
|
|
290
|
+
* <button onclick={openEditModal}>Edit (with handler)</button>
|
|
291
|
+
* <button onclick={openReviewModal}>Review (inline)</button>
|
|
292
|
+
* </components>
|
|
293
|
+
*
|
|
294
|
+
* <!-- With onsubmit handler -->
|
|
295
|
+
* <components type="modal" id="edit-item" title="Edit" onsubmit={handleEditSubmit}>
|
|
296
|
+
* <text-input id="name" label="Name" required />
|
|
297
|
+
* </components>
|
|
298
|
+
*
|
|
299
|
+
* <!-- Without onsubmit - use await to get response -->
|
|
300
|
+
* <components type="modal" id="review-modal" title="Review">
|
|
301
|
+
* <text-input id="rating" label="Rating (1-5)" required />
|
|
302
|
+
* <text-input id="review" label="Your Review" style="Paragraph" />
|
|
303
|
+
* </components>
|
|
304
|
+
* ```
|
|
305
|
+
*/
|
|
306
|
+
function showModal(modalId: string, options?: ShowModalOptions): Promise<ModalResponse>;
|
|
307
|
+
|
|
186
308
|
// ============================================
|
|
187
309
|
// REACTIVITY (Svelte 5 Runes)
|
|
188
310
|
// ============================================
|