@marianmeres/stuic 2.33.2 → 2.36.0
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/components/Collapsible/Collapsible.svelte +103 -0
- package/dist/components/Collapsible/Collapsible.svelte.d.ts +26 -0
- package/dist/components/Collapsible/README.md +81 -0
- package/dist/components/Collapsible/index.d.ts +1 -0
- package/dist/components/Collapsible/index.js +1 -0
- package/dist/components/Input/_internal/InputWrap.svelte +17 -1
- package/dist/components/Input/_internal/InputWrap.svelte.d.ts +3 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
|
|
4
|
+
export interface Props {
|
|
5
|
+
/** Content to display */
|
|
6
|
+
children: Snippet;
|
|
7
|
+
/** Number of lines to show when collapsed (default: 1) */
|
|
8
|
+
lines?: number;
|
|
9
|
+
/** Expanded state (bindable) */
|
|
10
|
+
expanded?: boolean;
|
|
11
|
+
/** Collapsed indicator character (default: "↓") */
|
|
12
|
+
collapsedIndicator?: string;
|
|
13
|
+
/** Expanded indicator character (default: "↑") */
|
|
14
|
+
expandedIndicator?: string;
|
|
15
|
+
/** Container class */
|
|
16
|
+
class?: string;
|
|
17
|
+
/** Content wrapper class */
|
|
18
|
+
classContent?: string;
|
|
19
|
+
/** Toggle button class */
|
|
20
|
+
classToggle?: string;
|
|
21
|
+
/** Opacity class for toggle button (default: "opacity-70") */
|
|
22
|
+
toggleOpacity?: string;
|
|
23
|
+
/** Bind reference to container element */
|
|
24
|
+
el?: HTMLDivElement;
|
|
25
|
+
}
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
<script lang="ts">
|
|
29
|
+
import { twMerge } from "../../utils/tw-merge.js";
|
|
30
|
+
|
|
31
|
+
let {
|
|
32
|
+
children,
|
|
33
|
+
lines = 1,
|
|
34
|
+
expanded = $bindable(false),
|
|
35
|
+
collapsedIndicator = "↓",
|
|
36
|
+
expandedIndicator = "↑",
|
|
37
|
+
class: classProp,
|
|
38
|
+
classContent,
|
|
39
|
+
classToggle,
|
|
40
|
+
toggleOpacity = "opacity-75",
|
|
41
|
+
el = $bindable(),
|
|
42
|
+
}: Props = $props();
|
|
43
|
+
|
|
44
|
+
let contentEl: HTMLDivElement | undefined;
|
|
45
|
+
let containerWidth = $state(0);
|
|
46
|
+
let needsCollapse = $state(false);
|
|
47
|
+
|
|
48
|
+
$effect(() => {
|
|
49
|
+
// Only measure when collapsed (line-clamp applied) to detect if truncation is needed
|
|
50
|
+
// containerWidth dependency ensures re-measurement on resize
|
|
51
|
+
if (contentEl && !expanded && containerWidth) {
|
|
52
|
+
needsCollapse = contentEl.scrollHeight > contentEl.clientHeight;
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// normalize, range validation
|
|
57
|
+
let _lines = $derived.by(() => {
|
|
58
|
+
const l = Math.abs(lines);
|
|
59
|
+
return l > 10 ? 10 : l;
|
|
60
|
+
});
|
|
61
|
+
</script>
|
|
62
|
+
|
|
63
|
+
<div
|
|
64
|
+
bind:this={el}
|
|
65
|
+
bind:clientWidth={containerWidth}
|
|
66
|
+
class={twMerge("stuic-collapsible", classProp)}
|
|
67
|
+
>
|
|
68
|
+
<div class="flex items-end">
|
|
69
|
+
<div
|
|
70
|
+
bind:this={contentEl}
|
|
71
|
+
class={twMerge("flex-1", !expanded && `line-clamp-${_lines}`, classContent)}
|
|
72
|
+
>
|
|
73
|
+
{@render children()}
|
|
74
|
+
</div>
|
|
75
|
+
{#if needsCollapse}
|
|
76
|
+
<button
|
|
77
|
+
type="button"
|
|
78
|
+
class={twMerge(
|
|
79
|
+
toggleOpacity,
|
|
80
|
+
"hover:opacity-100 cursor-pointer px-2 py-1 -my-1 -mr-2",
|
|
81
|
+
classToggle
|
|
82
|
+
)}
|
|
83
|
+
onclick={() => (expanded = !expanded)}
|
|
84
|
+
>
|
|
85
|
+
{expanded ? expandedIndicator : collapsedIndicator}
|
|
86
|
+
</button>
|
|
87
|
+
{/if}
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
|
|
91
|
+
<!--
|
|
92
|
+
DO NOT REMOVE: Food for TW compiler
|
|
93
|
+
line-clamp-1
|
|
94
|
+
line-clamp-2
|
|
95
|
+
line-clamp-3
|
|
96
|
+
line-clamp-4
|
|
97
|
+
line-clamp-5
|
|
98
|
+
line-clamp-6
|
|
99
|
+
line-clamp-7
|
|
100
|
+
line-clamp-8
|
|
101
|
+
line-clamp-9
|
|
102
|
+
line-clamp-10
|
|
103
|
+
-->
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
2
|
+
export interface Props {
|
|
3
|
+
/** Content to display */
|
|
4
|
+
children: Snippet;
|
|
5
|
+
/** Number of lines to show when collapsed (default: 1) */
|
|
6
|
+
lines?: number;
|
|
7
|
+
/** Expanded state (bindable) */
|
|
8
|
+
expanded?: boolean;
|
|
9
|
+
/** Collapsed indicator character (default: "↓") */
|
|
10
|
+
collapsedIndicator?: string;
|
|
11
|
+
/** Expanded indicator character (default: "↑") */
|
|
12
|
+
expandedIndicator?: string;
|
|
13
|
+
/** Container class */
|
|
14
|
+
class?: string;
|
|
15
|
+
/** Content wrapper class */
|
|
16
|
+
classContent?: string;
|
|
17
|
+
/** Toggle button class */
|
|
18
|
+
classToggle?: string;
|
|
19
|
+
/** Opacity class for toggle button (default: "opacity-70") */
|
|
20
|
+
toggleOpacity?: string;
|
|
21
|
+
/** Bind reference to container element */
|
|
22
|
+
el?: HTMLDivElement;
|
|
23
|
+
}
|
|
24
|
+
declare const Collapsible: import("svelte").Component<Props, {}, "el" | "expanded">;
|
|
25
|
+
type Collapsible = ReturnType<typeof Collapsible>;
|
|
26
|
+
export default Collapsible;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Collapsible
|
|
2
|
+
|
|
3
|
+
A component that truncates content to a specified number of lines with an expand/collapse toggle. Automatically detects if truncation is needed and only shows the toggle when content overflows.
|
|
4
|
+
|
|
5
|
+
## Props
|
|
6
|
+
|
|
7
|
+
| Prop | Type | Default | Description |
|
|
8
|
+
| -------------------- | --------------- | ------------- | ------------------------------------------------ |
|
|
9
|
+
| `children` | `Snippet` | - | Content to display |
|
|
10
|
+
| `lines` | `number` | `1` | Number of lines to show when collapsed |
|
|
11
|
+
| `expanded` | `boolean` | `false` | Expanded state (bindable) |
|
|
12
|
+
| `collapsedIndicator` | `string` | `"↓"` | Character/text shown when collapsed |
|
|
13
|
+
| `expandedIndicator` | `string` | `"↑"` | Character/text shown when expanded |
|
|
14
|
+
| `class` | `string` | - | Container element class |
|
|
15
|
+
| `classContent` | `string` | - | Content wrapper class |
|
|
16
|
+
| `classToggle` | `string` | - | Toggle button class |
|
|
17
|
+
| `toggleOpacity` | `string` | `"opacity-70"`| Opacity class for toggle button |
|
|
18
|
+
| `el` | `HTMLDivElement`| - | Bind reference to container element |
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
### Basic Usage
|
|
23
|
+
|
|
24
|
+
```svelte
|
|
25
|
+
<script>
|
|
26
|
+
import { Collapsible } from 'stuic';
|
|
27
|
+
</script>
|
|
28
|
+
|
|
29
|
+
<Collapsible>
|
|
30
|
+
This is a long text that will be truncated to one line with an ellipsis
|
|
31
|
+
and a toggle button to expand it.
|
|
32
|
+
</Collapsible>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Multiple Lines
|
|
36
|
+
|
|
37
|
+
```svelte
|
|
38
|
+
<Collapsible lines={3}>
|
|
39
|
+
This content will be truncated to 3 lines before showing the expand toggle.
|
|
40
|
+
Add more content here to see the effect.
|
|
41
|
+
</Collapsible>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Custom Indicators
|
|
45
|
+
|
|
46
|
+
```svelte
|
|
47
|
+
<Collapsible collapsedIndicator="▼" expandedIndicator="▲">
|
|
48
|
+
Content with custom expand/collapse indicators.
|
|
49
|
+
</Collapsible>
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Controlled State
|
|
53
|
+
|
|
54
|
+
```svelte
|
|
55
|
+
<script>
|
|
56
|
+
import { Collapsible } from 'stuic';
|
|
57
|
+
|
|
58
|
+
let expanded = $state(false);
|
|
59
|
+
</script>
|
|
60
|
+
|
|
61
|
+
<button onclick={() => expanded = !expanded}>
|
|
62
|
+
Toggle externally
|
|
63
|
+
</button>
|
|
64
|
+
|
|
65
|
+
<Collapsible bind:expanded>
|
|
66
|
+
This collapsible can be controlled from outside.
|
|
67
|
+
</Collapsible>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Custom Styling
|
|
71
|
+
|
|
72
|
+
```svelte
|
|
73
|
+
<Collapsible
|
|
74
|
+
class="bg-gray-100 p-4 rounded"
|
|
75
|
+
classContent="text-sm text-gray-600"
|
|
76
|
+
classToggle="text-blue-500 font-bold"
|
|
77
|
+
toggleOpacity="opacity-100"
|
|
78
|
+
>
|
|
79
|
+
Styled collapsible content.
|
|
80
|
+
</Collapsible>
|
|
81
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Collapsible, type Props as CollapsibleProps, } from "./Collapsible.svelte";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Collapsible, } from "./Collapsible.svelte";
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { slide } from "svelte/transition";
|
|
4
4
|
import type { ValidationResult } from "../../../actions/validate.svelte.js";
|
|
5
5
|
import { twMerge } from "../../../utils/tw-merge.js";
|
|
6
|
+
import { Collapsible } from "../../Collapsible/index.js";
|
|
6
7
|
import Thc, { isTHCNotEmpty, type THC } from "../../Thc/Thc.svelte";
|
|
7
8
|
|
|
8
9
|
type SnippetWithId = Snippet<[{ id: string }]>;
|
|
@@ -33,8 +34,11 @@
|
|
|
33
34
|
classInputBoxWrap?: string;
|
|
34
35
|
classInputBoxWrapInvalid?: string;
|
|
35
36
|
classDescBox?: string;
|
|
37
|
+
classDescBoxToggle?: string;
|
|
36
38
|
classBelowBox?: string;
|
|
37
39
|
classValidationBox?: string;
|
|
40
|
+
descriptionCollapsible?: boolean;
|
|
41
|
+
descriptionDefaultExpanded?: boolean;
|
|
38
42
|
style?: string;
|
|
39
43
|
}
|
|
40
44
|
let {
|
|
@@ -64,8 +68,11 @@
|
|
|
64
68
|
classInputBoxWrap,
|
|
65
69
|
classInputBoxWrapInvalid,
|
|
66
70
|
classDescBox,
|
|
71
|
+
classDescBoxToggle,
|
|
67
72
|
classBelowBox,
|
|
68
73
|
classValidationBox,
|
|
74
|
+
descriptionCollapsible = true,
|
|
75
|
+
descriptionDefaultExpanded = false,
|
|
69
76
|
style,
|
|
70
77
|
}: Props = $props();
|
|
71
78
|
|
|
@@ -214,7 +221,16 @@
|
|
|
214
221
|
classDescBox
|
|
215
222
|
)}
|
|
216
223
|
>
|
|
217
|
-
{
|
|
224
|
+
{#if descriptionCollapsible}
|
|
225
|
+
<Collapsible
|
|
226
|
+
expanded={descriptionDefaultExpanded}
|
|
227
|
+
classToggle={classDescBoxToggle}
|
|
228
|
+
>
|
|
229
|
+
{@render snippetOrThc({ id, value: description })}
|
|
230
|
+
</Collapsible>
|
|
231
|
+
{:else}
|
|
232
|
+
{@render snippetOrThc({ id, value: description })}
|
|
233
|
+
{/if}
|
|
218
234
|
</div>
|
|
219
235
|
{/if}
|
|
220
236
|
|
|
@@ -28,8 +28,11 @@ interface Props {
|
|
|
28
28
|
classInputBoxWrap?: string;
|
|
29
29
|
classInputBoxWrapInvalid?: string;
|
|
30
30
|
classDescBox?: string;
|
|
31
|
+
classDescBoxToggle?: string;
|
|
31
32
|
classBelowBox?: string;
|
|
32
33
|
classValidationBox?: string;
|
|
34
|
+
descriptionCollapsible?: boolean;
|
|
35
|
+
descriptionDefaultExpanded?: boolean;
|
|
33
36
|
style?: string;
|
|
34
37
|
}
|
|
35
38
|
declare const InputWrap: import("svelte").Component<Props, {}, "">;
|
package/dist/index.d.ts
CHANGED
|
@@ -28,6 +28,7 @@ export * from "./components/AvatarInitials/index.js";
|
|
|
28
28
|
export * from "./components/Backdrop/index.js";
|
|
29
29
|
export * from "./components/Button/index.js";
|
|
30
30
|
export * from "./components/ButtonGroupRadio/index.js";
|
|
31
|
+
export * from "./components/Collapsible/index.js";
|
|
31
32
|
export * from "./components/ColorScheme/index.js";
|
|
32
33
|
export * from "./components/CommandMenu/index.js";
|
|
33
34
|
export * from "./components/DismissibleMessage/index.js";
|
package/dist/index.js
CHANGED
|
@@ -29,6 +29,7 @@ export * from "./components/AvatarInitials/index.js";
|
|
|
29
29
|
export * from "./components/Backdrop/index.js";
|
|
30
30
|
export * from "./components/Button/index.js";
|
|
31
31
|
export * from "./components/ButtonGroupRadio/index.js";
|
|
32
|
+
export * from "./components/Collapsible/index.js";
|
|
32
33
|
export * from "./components/ColorScheme/index.js";
|
|
33
34
|
export * from "./components/CommandMenu/index.js";
|
|
34
35
|
export * from "./components/DismissibleMessage/index.js";
|