intelliwaketssveltekitv25 1.0.81 → 1.0.83
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/INTEGRATION.md +574 -0
- package/README.md +199 -45
- package/dist/ArrayTable.stories.js +215 -0
- package/dist/ArrayTable.svelte +46 -0
- package/dist/ArrayTable.svelte.d.ts +44 -0
- package/dist/DropDown.stories.d.ts +96 -0
- package/dist/DropDown.stories.js +192 -0
- package/dist/DropDown.svelte +32 -0
- package/dist/DropDown.svelte.d.ts +30 -0
- package/dist/InputNumber.stories.d.ts +122 -0
- package/dist/InputNumber.stories.js +186 -0
- package/dist/InputNumber.svelte +52 -0
- package/dist/InputNumber.svelte.d.ts +27 -0
- package/dist/Modal.stories.d.ts +114 -0
- package/dist/Modal.stories.js +139 -0
- package/dist/Modal.svelte +34 -3
- package/dist/Modal.svelte.d.ts +35 -3
- package/dist/MultiSelect.stories.js +338 -0
- package/dist/MultiSelect.svelte +81 -0
- package/dist/MultiSelect.svelte.d.ts +38 -0
- package/dist/Switch.stories.d.ts +81 -0
- package/dist/Switch.stories.js +99 -0
- package/dist/Switch.svelte +40 -0
- package/dist/Switch.svelte.d.ts +26 -0
- package/dist/TextArea.stories.d.ts +180 -0
- package/dist/TextArea.stories.js +216 -0
- package/dist/TextArea.svelte +32 -0
- package/dist/TextArea.svelte.d.ts +24 -0
- package/dist/app.css +1 -1
- package/docs/DateRangePicker.md +272 -0
- package/docs/DisplayHTML.md +249 -0
- package/docs/DropDown.md +269 -0
- package/docs/Functions.md +796 -0
- package/docs/Home.md +109 -0
- package/docs/Icon.md +203 -0
- package/docs/Importer.md +328 -0
- package/docs/ImporterAnalysis.md +249 -0
- package/docs/ImporterLoad.md +288 -0
- package/docs/InputNumber.md +159 -0
- package/docs/Integration.md +215 -0
- package/docs/Modal.md +207 -0
- package/docs/MultiSelect.md +304 -0
- package/docs/Paginator.md +332 -0
- package/docs/Search.md +364 -0
- package/docs/SlideDown.md +358 -0
- package/docs/Svelte-5-Patterns.md +364 -0
- package/docs/Switch.md +107 -0
- package/docs/TabHeader.md +333 -0
- package/docs/TabHref.md +370 -0
- package/docs/TextArea.md +118 -0
- package/docs/_Sidebar.md +38 -0
- package/llms.txt +113 -0
- package/package.json +7 -2
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
# DateRangePicker Component
|
|
2
|
+
|
|
3
|
+
**Purpose:** Select predefined or custom date ranges with calendar interface
|
|
4
|
+
|
|
5
|
+
**When to Use:**
|
|
6
|
+
- Filter reports by date range (Today, Last 7 Days, This Month, etc.)
|
|
7
|
+
- Allow custom date range selection
|
|
8
|
+
- Integrate with SvelteKit's `invalidate()` for data refresh
|
|
9
|
+
- Persist date range selection in cookies
|
|
10
|
+
|
|
11
|
+
## Key Props
|
|
12
|
+
|
|
13
|
+
- `dateRange: TDateRangeString` ($bindable, required) - Current date range
|
|
14
|
+
- `dateRanges?: TDateRangeString[]` - Available preset ranges (default: `DefaultRangeStringsReport()`)
|
|
15
|
+
- `allowCustom?: boolean` (default: true) - Enable custom date range selection
|
|
16
|
+
- `show?: boolean` ($bindable, default: false) - Control dropdown open state
|
|
17
|
+
- `fyMonthsAdjust?: number | null` - Fiscal year month adjustment
|
|
18
|
+
- `controlClass?: string` - CSS classes for dropdown wrapper
|
|
19
|
+
- `toggleClass?: string` - CSS classes for toggle button
|
|
20
|
+
- `bodyClass?: string` - CSS classes for dropdown body
|
|
21
|
+
- `setCookieName?: string` - Cookie name to persist selection
|
|
22
|
+
- `invalidate?: string | string[] | 'All' | 'app:All' | null` - SvelteKit invalidation targets
|
|
23
|
+
- `onchange?: (dateRange: TDateRangeString) => void` - Callback when range changes
|
|
24
|
+
|
|
25
|
+
## TDateRangeString Interface
|
|
26
|
+
|
|
27
|
+
Date ranges have the following structure:
|
|
28
|
+
```typescript
|
|
29
|
+
interface TDateRangeString {
|
|
30
|
+
name: string // Display name
|
|
31
|
+
start: string // Start date (ISO format or date string)
|
|
32
|
+
end: string // End date (ISO format or date string)
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Default Ranges
|
|
37
|
+
|
|
38
|
+
The component includes these preset ranges (via `DefaultRangeStringsReport()`):
|
|
39
|
+
- Today
|
|
40
|
+
- Yesterday
|
|
41
|
+
- Last 7 Days
|
|
42
|
+
- Last 14 Days
|
|
43
|
+
- Last 30 Days
|
|
44
|
+
- This Week
|
|
45
|
+
- Last Week
|
|
46
|
+
- This Month
|
|
47
|
+
- Last Month
|
|
48
|
+
- This Quarter
|
|
49
|
+
- Last Quarter
|
|
50
|
+
- This Year
|
|
51
|
+
- Last Year
|
|
52
|
+
- Custom (if `allowCustom` is true)
|
|
53
|
+
|
|
54
|
+
## Usage Examples
|
|
55
|
+
|
|
56
|
+
```svelte
|
|
57
|
+
<script>
|
|
58
|
+
import { DateRangePicker } from 'intelliwaketssveltekitv25';
|
|
59
|
+
import { DefaultRangeStringsReport } from 'intelliwaketssveltekitv25';
|
|
60
|
+
|
|
61
|
+
let dateRange = $state(DefaultRangeStringsReport()[0]); // Today
|
|
62
|
+
</script>
|
|
63
|
+
|
|
64
|
+
<!-- Basic usage -->
|
|
65
|
+
<DateRangePicker bind:dateRange />
|
|
66
|
+
|
|
67
|
+
<!-- With SvelteKit invalidation -->
|
|
68
|
+
<DateRangePicker
|
|
69
|
+
bind:dateRange
|
|
70
|
+
invalidate="app:loadData"
|
|
71
|
+
/>
|
|
72
|
+
|
|
73
|
+
<!-- Multiple invalidation targets -->
|
|
74
|
+
<DateRangePicker
|
|
75
|
+
bind:dateRange
|
|
76
|
+
invalidate={['app:reports', 'app:charts']}
|
|
77
|
+
/>
|
|
78
|
+
|
|
79
|
+
<!-- Invalidate all -->
|
|
80
|
+
<DateRangePicker
|
|
81
|
+
bind:dateRange
|
|
82
|
+
invalidate="All"
|
|
83
|
+
/>
|
|
84
|
+
|
|
85
|
+
<!-- Custom date ranges -->
|
|
86
|
+
<DateRangePicker
|
|
87
|
+
bind:dateRange
|
|
88
|
+
dateRanges={[
|
|
89
|
+
{ name: 'Today', start: 'today', end: 'today' },
|
|
90
|
+
{ name: 'This Week', start: 'startOfWeek', end: 'today' },
|
|
91
|
+
{ name: 'Last 30 Days', start: '-30', end: 'today' }
|
|
92
|
+
]}
|
|
93
|
+
/>
|
|
94
|
+
|
|
95
|
+
<!-- Persist in cookies -->
|
|
96
|
+
<DateRangePicker
|
|
97
|
+
bind:dateRange
|
|
98
|
+
setCookieName="reportDateRange"
|
|
99
|
+
/>
|
|
100
|
+
|
|
101
|
+
<!-- Without custom range option -->
|
|
102
|
+
<DateRangePicker
|
|
103
|
+
bind:dateRange
|
|
104
|
+
allowCustom={false}
|
|
105
|
+
/>
|
|
106
|
+
|
|
107
|
+
<!-- With callback -->
|
|
108
|
+
<DateRangePicker
|
|
109
|
+
bind:dateRange
|
|
110
|
+
onchange={(range) => {
|
|
111
|
+
console.log('Date range changed:', range);
|
|
112
|
+
fetchData(range.start, range.end);
|
|
113
|
+
}}
|
|
114
|
+
/>
|
|
115
|
+
|
|
116
|
+
<!-- Fiscal year adjustment (e.g., fiscal year starts in July) -->
|
|
117
|
+
<DateRangePicker
|
|
118
|
+
bind:dateRange
|
|
119
|
+
fyMonthsAdjust={6}
|
|
120
|
+
/>
|
|
121
|
+
|
|
122
|
+
<!-- Controlled open state -->
|
|
123
|
+
<DateRangePicker
|
|
124
|
+
bind:dateRange
|
|
125
|
+
bind:show={isOpen}
|
|
126
|
+
/>
|
|
127
|
+
<button onclick={() => isOpen = !isOpen}>
|
|
128
|
+
Toggle Date Picker
|
|
129
|
+
</button>
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Custom Date Range Selection
|
|
133
|
+
|
|
134
|
+
When `allowCustom` is true (default), users can:
|
|
135
|
+
1. Click "Custom" from the preset list
|
|
136
|
+
2. Use the calendar interface to select start and end dates
|
|
137
|
+
3. Click between dates to toggle which date is being modified
|
|
138
|
+
4. Cancel or Apply the custom range
|
|
139
|
+
|
|
140
|
+
```svelte
|
|
141
|
+
<script>
|
|
142
|
+
let dateRange = $state({
|
|
143
|
+
name: 'Custom',
|
|
144
|
+
start: '2024-01-01',
|
|
145
|
+
end: '2024-12-31'
|
|
146
|
+
});
|
|
147
|
+
</script>
|
|
148
|
+
|
|
149
|
+
<DateRangePicker bind:dateRange />
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Integration with SvelteKit
|
|
153
|
+
|
|
154
|
+
### With `invalidate()`
|
|
155
|
+
```svelte
|
|
156
|
+
<script>
|
|
157
|
+
import { DateRangePicker } from 'intelliwaketssveltekitv25';
|
|
158
|
+
import { invalidate } from '$app/navigation';
|
|
159
|
+
|
|
160
|
+
export let data;
|
|
161
|
+
|
|
162
|
+
let dateRange = $state(data.dateRange);
|
|
163
|
+
</script>
|
|
164
|
+
|
|
165
|
+
<!-- Automatically invalidates and refetches -->
|
|
166
|
+
<DateRangePicker
|
|
167
|
+
bind:dateRange
|
|
168
|
+
invalidate="app:reports"
|
|
169
|
+
/>
|
|
170
|
+
|
|
171
|
+
<!-- +page.server.ts -->
|
|
172
|
+
<script>
|
|
173
|
+
export const load = async ({ depends, url }) => {
|
|
174
|
+
depends('app:reports');
|
|
175
|
+
|
|
176
|
+
const dateRange = getDateRangeFromQuery(url);
|
|
177
|
+
const reports = await fetchReports(dateRange);
|
|
178
|
+
|
|
179
|
+
return { reports, dateRange };
|
|
180
|
+
};
|
|
181
|
+
</script>
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### With Cookie Persistence
|
|
185
|
+
```svelte
|
|
186
|
+
<DateRangePicker
|
|
187
|
+
bind:dateRange
|
|
188
|
+
setCookieName="dashboardDateRange"
|
|
189
|
+
invalidate="app:dashboard"
|
|
190
|
+
/>
|
|
191
|
+
|
|
192
|
+
<!-- Date range is automatically saved to cookie and restored on page load -->
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Common Patterns
|
|
196
|
+
|
|
197
|
+
### Report Filtering
|
|
198
|
+
```svelte
|
|
199
|
+
<script>
|
|
200
|
+
let dateRange = $state({ name: 'Last 30 Days', start: '-30', end: 'today' });
|
|
201
|
+
let reportData = $derived(filterReportByDates(allData, dateRange));
|
|
202
|
+
</script>
|
|
203
|
+
|
|
204
|
+
<DateRangePicker bind:dateRange />
|
|
205
|
+
|
|
206
|
+
<table>
|
|
207
|
+
{#each reportData as item}
|
|
208
|
+
<tr>...</tr>
|
|
209
|
+
{/each}
|
|
210
|
+
</table>
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Dashboard with Multiple Widgets
|
|
214
|
+
```svelte
|
|
215
|
+
<script>
|
|
216
|
+
let dateRange = $state(DefaultRangeStringsReport()[0]);
|
|
217
|
+
</script>
|
|
218
|
+
|
|
219
|
+
<DateRangePicker
|
|
220
|
+
bind:dateRange
|
|
221
|
+
setCookieName="dashboardRange"
|
|
222
|
+
invalidate="All"
|
|
223
|
+
/>
|
|
224
|
+
|
|
225
|
+
<SalesChart {dateRange} />
|
|
226
|
+
<RevenueTable {dateRange} />
|
|
227
|
+
<MetricsGrid {dateRange} />
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## Common Mistakes
|
|
231
|
+
|
|
232
|
+
- ❌ Not using `bind:dateRange` for two-way binding
|
|
233
|
+
✅ Correct: `<DateRangePicker bind:dateRange />`
|
|
234
|
+
|
|
235
|
+
- ❌ Using raw date objects instead of TDateRangeString
|
|
236
|
+
✅ Correct: `{ name: 'Today', start: 'today', end: 'today' }`
|
|
237
|
+
|
|
238
|
+
- ❌ Forgetting to import `DefaultRangeStringsReport` for preset ranges
|
|
239
|
+
✅ Correct: `import { DefaultRangeStringsReport } from 'intelliwaketssveltekitv25'`
|
|
240
|
+
|
|
241
|
+
- ❌ Not handling the invalidate effect on data loads
|
|
242
|
+
✅ Correct: Use `depends()` in load functions or provide `invalidate` prop
|
|
243
|
+
|
|
244
|
+
## Related Components
|
|
245
|
+
|
|
246
|
+
- **Calendar** - Used internally for custom date selection
|
|
247
|
+
- **DropDownControl** - Dropdown mechanism
|
|
248
|
+
- **ListGroupItems** - Preset range list
|
|
249
|
+
- **DateRangeFunctions** - Utilities: `DefaultRangeStringsReport()`, `CustomRangeName`
|
|
250
|
+
- **Cookie** - Cookie persistence via `CookieCreate()`
|
|
251
|
+
|
|
252
|
+
## Date Range Functions
|
|
253
|
+
|
|
254
|
+
### DefaultRangeStringsReport(fyMonthsAdjust?)
|
|
255
|
+
Returns array of standard date ranges for reporting.
|
|
256
|
+
|
|
257
|
+
### CustomRangeName
|
|
258
|
+
Constant for "Custom" range name (exported from `DateRangeFunctions`).
|
|
259
|
+
|
|
260
|
+
## Styling
|
|
261
|
+
|
|
262
|
+
The component uses:
|
|
263
|
+
- `inputControl` class for the toggle button
|
|
264
|
+
- Calendar icon (inline SVG)
|
|
265
|
+
- `border-b-secondary-light` for active date indicator
|
|
266
|
+
- Standard button classes (`btnLink`) for Cancel/Apply
|
|
267
|
+
|
|
268
|
+
## Accessibility
|
|
269
|
+
|
|
270
|
+
- Calendar date selection is keyboard navigable
|
|
271
|
+
- Toggle shows current range or formatted custom dates
|
|
272
|
+
- Visual indicator shows which date (start/end) is being modified
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
# DisplayHTML Component
|
|
2
|
+
|
|
3
|
+
**Purpose:** Safely render text, HTML, or Svelte snippets with automatic URL link conversion
|
|
4
|
+
|
|
5
|
+
**When to Use:**
|
|
6
|
+
- Display user-generated content that may contain HTML
|
|
7
|
+
- Automatically convert URLs to clickable links
|
|
8
|
+
- Render dynamic content from database fields
|
|
9
|
+
- Display formatted text with HTML tags
|
|
10
|
+
- Conditionally render Svelte snippets
|
|
11
|
+
|
|
12
|
+
## Key Props
|
|
13
|
+
|
|
14
|
+
- `value: string | null | undefined | Snippet` (required) - Content to display
|
|
15
|
+
- `anchorClasses?: string` (default: '') - CSS classes for auto-generated anchor links
|
|
16
|
+
- `noLinkReplace?: boolean` (default: false) - Disable automatic URL-to-link conversion
|
|
17
|
+
- `hidden?: boolean` - Hide the component
|
|
18
|
+
|
|
19
|
+
## Features
|
|
20
|
+
|
|
21
|
+
### Automatic Link Conversion
|
|
22
|
+
By default, the component automatically converts plain URLs in text to clickable anchor links:
|
|
23
|
+
```
|
|
24
|
+
"Visit https://example.com" → "Visit <a href="https://example.com">https://example.com</a>"
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### HTML Detection
|
|
28
|
+
The component intelligently detects HTML content and renders it using `{@html}` when needed, while rendering plain text normally.
|
|
29
|
+
|
|
30
|
+
### Snippet Support
|
|
31
|
+
Pass Svelte snippets as the `value` for dynamic component rendering.
|
|
32
|
+
|
|
33
|
+
### Text-to-HTML Conversion
|
|
34
|
+
Converts newlines to `<br>` tags for proper text formatting.
|
|
35
|
+
|
|
36
|
+
## Usage Examples
|
|
37
|
+
|
|
38
|
+
```svelte
|
|
39
|
+
<script>
|
|
40
|
+
import { DisplayHTML } from 'intelliwaketssveltekitv25';
|
|
41
|
+
|
|
42
|
+
let plainText = 'Hello, world!';
|
|
43
|
+
let htmlContent = '<strong>Bold text</strong> and <em>italic text</em>';
|
|
44
|
+
let textWithUrl = 'Visit our site at https://example.com for more info';
|
|
45
|
+
let multilineText = 'Line 1\nLine 2\nLine 3';
|
|
46
|
+
</script>
|
|
47
|
+
|
|
48
|
+
<!-- Plain text -->
|
|
49
|
+
<DisplayHTML value={plainText} />
|
|
50
|
+
<!-- Output: Hello, world! -->
|
|
51
|
+
|
|
52
|
+
<!-- HTML content -->
|
|
53
|
+
<DisplayHTML value={htmlContent} />
|
|
54
|
+
<!-- Output: Bold text and italic text (rendered) -->
|
|
55
|
+
|
|
56
|
+
<!-- Text with URL (auto-converted to link) -->
|
|
57
|
+
<DisplayHTML value={textWithUrl} />
|
|
58
|
+
<!-- Output: Visit our site at <a href="https://example.com">https://example.com</a> for more info -->
|
|
59
|
+
|
|
60
|
+
<!-- Disable link conversion -->
|
|
61
|
+
<DisplayHTML value={textWithUrl} noLinkReplace />
|
|
62
|
+
<!-- Output: Visit our site at https://example.com for more info (plain text) -->
|
|
63
|
+
|
|
64
|
+
<!-- Styled links -->
|
|
65
|
+
<DisplayHTML
|
|
66
|
+
value={textWithUrl}
|
|
67
|
+
anchorClasses="text-blue-600 hover:underline"
|
|
68
|
+
/>
|
|
69
|
+
|
|
70
|
+
<!-- Conditional display -->
|
|
71
|
+
<DisplayHTML value={description} hidden={!showDescription} />
|
|
72
|
+
|
|
73
|
+
<!-- With Svelte snippet -->
|
|
74
|
+
<DisplayHTML value={mySnippet} />
|
|
75
|
+
|
|
76
|
+
<!-- Null-safe (won't render if null/undefined) -->
|
|
77
|
+
<DisplayHTML value={maybeNull} />
|
|
78
|
+
|
|
79
|
+
<!-- Multiline text (newlines converted to <br>) -->
|
|
80
|
+
<DisplayHTML value={multilineText} />
|
|
81
|
+
<!-- Output:
|
|
82
|
+
Line 1<br>
|
|
83
|
+
Line 2<br>
|
|
84
|
+
Line 3
|
|
85
|
+
-->
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Real-World Examples
|
|
89
|
+
|
|
90
|
+
### User Comments
|
|
91
|
+
```svelte
|
|
92
|
+
<script>
|
|
93
|
+
let comment = $state('Check out https://example.com - it's great!');
|
|
94
|
+
</script>
|
|
95
|
+
|
|
96
|
+
<DisplayHTML
|
|
97
|
+
value={comment}
|
|
98
|
+
anchorClasses="text-blue-500 hover:underline"
|
|
99
|
+
/>
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Product Description
|
|
103
|
+
```svelte
|
|
104
|
+
<script>
|
|
105
|
+
export let data;
|
|
106
|
+
let product = data.product;
|
|
107
|
+
</script>
|
|
108
|
+
|
|
109
|
+
<h2>{product.name}</h2>
|
|
110
|
+
<DisplayHTML value={product.descriptionHTML} />
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Dynamic Content from Database
|
|
114
|
+
```svelte
|
|
115
|
+
<script>
|
|
116
|
+
// Database field may contain HTML or plain text
|
|
117
|
+
let content = $state(data.content); // Could be "<p>HTML</p>" or "Plain text"
|
|
118
|
+
</script>
|
|
119
|
+
|
|
120
|
+
<DisplayHTML value={content} />
|
|
121
|
+
<!-- Automatically handles both cases -->
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Email Body Display
|
|
125
|
+
```svelte
|
|
126
|
+
<script>
|
|
127
|
+
let emailBody = $state(email.body);
|
|
128
|
+
</script>
|
|
129
|
+
|
|
130
|
+
<div class="email-content">
|
|
131
|
+
<DisplayHTML
|
|
132
|
+
value={emailBody}
|
|
133
|
+
anchorClasses="text-blue-600 underline"
|
|
134
|
+
/>
|
|
135
|
+
</div>
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Conditional Rendering with Snippets
|
|
139
|
+
```svelte
|
|
140
|
+
<script>
|
|
141
|
+
let useCustomRender = $state(true);
|
|
142
|
+
</script>
|
|
143
|
+
|
|
144
|
+
{#snippet customContent()}
|
|
145
|
+
<div class="custom">
|
|
146
|
+
Custom rendered content
|
|
147
|
+
</div>
|
|
148
|
+
{/snippet}
|
|
149
|
+
|
|
150
|
+
<DisplayHTML value={useCustomRender ? customContent : 'Plain text'} />
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Security Considerations
|
|
154
|
+
|
|
155
|
+
**Important:** This component uses `{@html}` to render HTML content. Only use it with **trusted content**. Never pass unsanitized user input directly without server-side sanitization.
|
|
156
|
+
|
|
157
|
+
### Safe Usage
|
|
158
|
+
```svelte
|
|
159
|
+
<!-- ✅ SAFE: Content from your database (sanitized on server) -->
|
|
160
|
+
<DisplayHTML value={product.description} />
|
|
161
|
+
|
|
162
|
+
<!-- ✅ SAFE: Static content you control -->
|
|
163
|
+
<DisplayHTML value="<strong>Our Policy</strong>" />
|
|
164
|
+
|
|
165
|
+
<!-- ❌ UNSAFE: Raw user input without sanitization -->
|
|
166
|
+
<DisplayHTML value={userInput} />
|
|
167
|
+
<!-- Should be: -->
|
|
168
|
+
<DisplayHTML value={sanitizedUserInput} />
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Sanitization Example (Server-side)
|
|
172
|
+
```typescript
|
|
173
|
+
// +page.server.ts
|
|
174
|
+
import DOMPurify from 'isomorphic-dompurify';
|
|
175
|
+
|
|
176
|
+
export const load = async () => {
|
|
177
|
+
const rawContent = await db.content.get();
|
|
178
|
+
const sanitizedContent = DOMPurify.sanitize(rawContent);
|
|
179
|
+
|
|
180
|
+
return {
|
|
181
|
+
content: sanitizedContent
|
|
182
|
+
};
|
|
183
|
+
};
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## Common Patterns
|
|
187
|
+
|
|
188
|
+
### Table Cell with Links
|
|
189
|
+
```svelte
|
|
190
|
+
<ArrayTable data={items} columns={[
|
|
191
|
+
{
|
|
192
|
+
title: 'Description',
|
|
193
|
+
cell: (item) => ({ snippet: () => (
|
|
194
|
+
<DisplayHTML
|
|
195
|
+
value={item.description}
|
|
196
|
+
anchorClasses="text-primary-main"
|
|
197
|
+
/>
|
|
198
|
+
)})
|
|
199
|
+
}
|
|
200
|
+
]} />
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Fallback Content
|
|
204
|
+
```svelte
|
|
205
|
+
<DisplayHTML value={content || 'No description available'} />
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Optional Display
|
|
209
|
+
```svelte
|
|
210
|
+
{#if showDetails}
|
|
211
|
+
<DisplayHTML value={details} />
|
|
212
|
+
{/if}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## Common Mistakes
|
|
216
|
+
|
|
217
|
+
- ❌ Passing raw user input without sanitization (XSS risk)
|
|
218
|
+
✅ Correct: Sanitize HTML content on the server before rendering
|
|
219
|
+
|
|
220
|
+
- ❌ Not using `noLinkReplace` when you don't want URL conversion
|
|
221
|
+
✅ Correct: Set `noLinkReplace={true}` for technical content with URLs
|
|
222
|
+
|
|
223
|
+
- ❌ Using this component when simple text rendering would suffice
|
|
224
|
+
✅ Correct: Use plain `{value}` for simple text, DisplayHTML only when needed
|
|
225
|
+
|
|
226
|
+
- ❌ Forgetting that `null` or `undefined` values won't render
|
|
227
|
+
✅ Correct: Provide fallback: `value={content || 'Default text'}`
|
|
228
|
+
|
|
229
|
+
## Related Functions
|
|
230
|
+
|
|
231
|
+
The component uses these utility functions from `@solidbasisventures/intelliwaketsfoundation`:
|
|
232
|
+
- **ReplaceLinks(html, classes)** - Converts URLs to anchor tags
|
|
233
|
+
- **TextToHTML(text)** - Converts plain text to HTML (newlines to `<br>`)
|
|
234
|
+
- **IncludesHTML(text)** - Detects if string contains HTML tags
|
|
235
|
+
|
|
236
|
+
## Props Reference
|
|
237
|
+
|
|
238
|
+
| Prop | Type | Default | Description |
|
|
239
|
+
|------|------|---------|-------------|
|
|
240
|
+
| `value` | `string \| null \| undefined \| Snippet` | (required) | Content to display |
|
|
241
|
+
| `anchorClasses` | `string` | `''` | CSS classes for auto-generated links |
|
|
242
|
+
| `noLinkReplace` | `boolean` | `false` | Skip URL-to-link conversion |
|
|
243
|
+
| `hidden` | `boolean` | `false` | Hide component |
|
|
244
|
+
|
|
245
|
+
## Performance Notes
|
|
246
|
+
|
|
247
|
+
- The component efficiently detects HTML vs plain text to minimize unnecessary `{@html}` usage
|
|
248
|
+
- Link replacement only occurs when `noLinkReplace` is false
|
|
249
|
+
- Snippet detection happens once via `$derived`
|