twintrinsic 0.0.1
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/LICENSE +674 -0
- package/README.md +150 -0
- package/dist/App/App.svelte +54 -0
- package/dist/App/App.svelte.d.ts +65 -0
- package/dist/Section.svelte +25 -0
- package/dist/Section.svelte.d.ts +34 -0
- package/dist/actions/clickOutside.d.ts +9 -0
- package/dist/actions/clickOutside.js +19 -0
- package/dist/actions/index.d.ts +1 -0
- package/dist/actions/index.js +1 -0
- package/dist/components/Accordion/Accordion.svelte +75 -0
- package/dist/components/Accordion/Accordion.svelte.d.ts +39 -0
- package/dist/components/Accordion/AccordionItem.svelte +150 -0
- package/dist/components/Accordion/AccordionItem.svelte.d.ts +30 -0
- package/dist/components/App/App.story.md +8 -0
- package/dist/components/App/App.story.svelte +170 -0
- package/dist/components/App/App.story.svelte.d.ts +22 -0
- package/dist/components/App/App.svelte +77 -0
- package/dist/components/App/App.svelte.d.ts +66 -0
- package/dist/components/App/Split.svelte +346 -0
- package/dist/components/App/Split.svelte.d.ts +54 -0
- package/dist/components/App/index.d.ts +2 -0
- package/dist/components/App/index.js +3 -0
- package/dist/components/AppHeader/AppHeader.svelte +439 -0
- package/dist/components/AppHeader/AppHeader.svelte.d.ts +24 -0
- package/dist/components/Avatar/Avatar.svelte +300 -0
- package/dist/components/Avatar/Avatar.svelte.d.ts +48 -0
- package/dist/components/Avatar/AvatarGroup.svelte +185 -0
- package/dist/components/Avatar/AvatarGroup.svelte.d.ts +46 -0
- package/dist/components/Badge/Badge.svelte +186 -0
- package/dist/components/Badge/Badge.svelte.d.ts +51 -0
- package/dist/components/BottomBar/BottomBar.svelte +146 -0
- package/dist/components/BottomBar/BottomBar.svelte.d.ts +38 -0
- package/dist/components/Breadcrumb/Breadcrumb.svelte +77 -0
- package/dist/components/Breadcrumb/Breadcrumb.svelte.d.ts +42 -0
- package/dist/components/Breadcrumb/BreadcrumbItem.svelte +171 -0
- package/dist/components/Breadcrumb/BreadcrumbItem.svelte.d.ts +38 -0
- package/dist/components/Button/Button.svelte +252 -0
- package/dist/components/Button/Button.svelte.d.ts +80 -0
- package/dist/components/Button/ButtonGroup.svelte +127 -0
- package/dist/components/Button/ButtonGroup.svelte.d.ts +44 -0
- package/dist/components/Card/Card.svelte +152 -0
- package/dist/components/Card/Card.svelte.d.ts +55 -0
- package/dist/components/Carousel/Carousel.svelte +461 -0
- package/dist/components/Carousel/Carousel.svelte.d.ts +79 -0
- package/dist/components/Carousel/CarouselItem.svelte +149 -0
- package/dist/components/Carousel/CarouselItem.svelte.d.ts +35 -0
- package/dist/components/Chip/Chip.svelte +288 -0
- package/dist/components/Chip/Chip.svelte.d.ts +71 -0
- package/dist/components/Chip/ChipGroup.svelte +190 -0
- package/dist/components/Chip/ChipGroup.svelte.d.ts +71 -0
- package/dist/components/CodeBlock/CodeBlock.svelte +356 -0
- package/dist/components/CodeBlock/CodeBlock.svelte.d.ts +44 -0
- package/dist/components/CodeBlock/index.d.ts +1 -0
- package/dist/components/CodeBlock/index.js +1 -0
- package/dist/components/CodeBlockSpeed/CodeBlockSpeed.svelte +145 -0
- package/dist/components/CodeBlockSpeed/CodeBlockSpeed.svelte.d.ts +44 -0
- package/dist/components/CodeEditor/CodeEditor.svelte +229 -0
- package/dist/components/CodeEditor/CodeEditor.svelte.d.ts +23 -0
- package/dist/components/Combobox/Combobox.svelte +279 -0
- package/dist/components/Combobox/Combobox.svelte.d.ts +34 -0
- package/dist/components/Container/Container.svelte +45 -0
- package/dist/components/Container/Container.svelte.d.ts +36 -0
- package/dist/components/DataTable/DataTable.svelte +879 -0
- package/dist/components/DataTable/DataTable.svelte.d.ts +102 -0
- package/dist/components/Form/AutoComplete.svelte +357 -0
- package/dist/components/Form/AutoComplete.svelte.d.ts +73 -0
- package/dist/components/Form/Calendar.svelte +429 -0
- package/dist/components/Form/Calendar.svelte.d.ts +53 -0
- package/dist/components/Form/Checkbox.svelte +196 -0
- package/dist/components/Form/Checkbox.svelte.d.ts +50 -0
- package/dist/components/Form/ColorPicker.svelte +396 -0
- package/dist/components/Form/ColorPicker.svelte.d.ts +43 -0
- package/dist/components/Form/Combobox.svelte +645 -0
- package/dist/components/Form/Combobox.svelte.d.ts +93 -0
- package/dist/components/Form/Dropdown.svelte +773 -0
- package/dist/components/Form/Dropdown.svelte.d.ts +81 -0
- package/dist/components/Form/FileUpload.svelte +796 -0
- package/dist/components/Form/FileUpload.svelte.d.ts +78 -0
- package/dist/components/Form/FloatLabel.svelte +245 -0
- package/dist/components/Form/FloatLabel.svelte.d.ts +44 -0
- package/dist/components/Form/Form.svelte +281 -0
- package/dist/components/Form/Form.svelte.d.ts +54 -0
- package/dist/components/Form/FormField.svelte +218 -0
- package/dist/components/Form/FormField.svelte.d.ts +47 -0
- package/dist/components/Form/Input.svelte +340 -0
- package/dist/components/Form/Input.svelte.d.ts +79 -0
- package/dist/components/Form/InputSwitch.svelte +189 -0
- package/dist/components/Form/InputSwitch.svelte.d.ts +46 -0
- package/dist/components/Form/InvalidState.svelte +97 -0
- package/dist/components/Form/InvalidState.svelte.d.ts +37 -0
- package/dist/components/Form/Knob.svelte +537 -0
- package/dist/components/Form/Knob.svelte.d.ts +78 -0
- package/dist/components/Form/ListInput.svelte +469 -0
- package/dist/components/Form/ListInput.svelte.d.ts +70 -0
- package/dist/components/Form/Listbox.svelte +513 -0
- package/dist/components/Form/Listbox.svelte.d.ts +74 -0
- package/dist/components/Form/NumberInput.svelte +452 -0
- package/dist/components/Form/NumberInput.svelte.d.ts +82 -0
- package/dist/components/Form/Radio.svelte +192 -0
- package/dist/components/Form/Radio.svelte.d.ts +53 -0
- package/dist/components/Form/RadioGroup.svelte +155 -0
- package/dist/components/Form/RadioGroup.svelte.d.ts +48 -0
- package/dist/components/Form/Rating.svelte +380 -0
- package/dist/components/Form/Rating.svelte.d.ts +64 -0
- package/dist/components/Form/Select.svelte +436 -0
- package/dist/components/Form/Select.svelte.d.ts +49 -0
- package/dist/components/Form/SelectGroup.svelte +34 -0
- package/dist/components/Form/SelectGroup.svelte.d.ts +33 -0
- package/dist/components/Form/Slider.svelte +622 -0
- package/dist/components/Form/Slider.svelte.d.ts +73 -0
- package/dist/components/Form/Switch.svelte +192 -0
- package/dist/components/Form/Switch.svelte.d.ts +46 -0
- package/dist/components/Form/TextInput.svelte +274 -0
- package/dist/components/Form/TextInput.svelte.d.ts +74 -0
- package/dist/components/Form/Textarea.svelte +207 -0
- package/dist/components/Form/Textarea.svelte.d.ts +62 -0
- package/dist/components/Icon/Icon.svelte +140 -0
- package/dist/components/Icon/Icon.svelte.d.ts +25 -0
- package/dist/components/Icon/index.d.ts +1 -0
- package/dist/components/Icon/index.js +1 -0
- package/dist/components/Lazy/Lazy.svelte +158 -0
- package/dist/components/Lazy/Lazy.svelte.d.ts +42 -0
- package/dist/components/Masonry/Masonry.svelte +299 -0
- package/dist/components/Masonry/Masonry.svelte.d.ts +55 -0
- package/dist/components/Menu/Menu/Menu.svelte +65 -0
- package/dist/components/Menu/Menu/Menu.svelte.d.ts +17 -0
- package/dist/components/Menu/Menu/MenuItem.svelte +90 -0
- package/dist/components/Menu/Menu/MenuItem.svelte.d.ts +27 -0
- package/dist/components/Modal/Modal.svelte +334 -0
- package/dist/components/Modal/Modal.svelte.d.ts +55 -0
- package/dist/components/Panel/Card.svelte +141 -0
- package/dist/components/Panel/Card.svelte.d.ts +52 -0
- package/dist/components/Panel/Hero/Hero.story.md +9 -0
- package/dist/components/Panel/Hero/Hero.story.svelte +49 -0
- package/dist/components/Panel/Hero/Hero.story.svelte.d.ts +21 -0
- package/dist/components/Panel/Hero/Hero.svelte +24 -0
- package/dist/components/Panel/Hero/Hero.svelte.d.ts +32 -0
- package/dist/components/Panel/LazyPanel.svelte +110 -0
- package/dist/components/Panel/LazyPanel.svelte.d.ts +46 -0
- package/dist/components/Panel/Panel.svelte +205 -0
- package/dist/components/Panel/Panel.svelte.d.ts +23 -0
- package/dist/components/Progress/Progress.svelte +220 -0
- package/dist/components/Progress/Progress.svelte.d.ts +61 -0
- package/dist/components/Separator/Separator.svelte +109 -0
- package/dist/components/Separator/Separator.svelte.d.ts +35 -0
- package/dist/components/Sidebar/Sidebar.svelte +213 -0
- package/dist/components/Sidebar/Sidebar.svelte.d.ts +60 -0
- package/dist/components/Skeleton/Skeleton.svelte +170 -0
- package/dist/components/Skeleton/Skeleton.svelte.d.ts +48 -0
- package/dist/components/Stepper/Stepper.svelte +111 -0
- package/dist/components/Stepper/Stepper.svelte.d.ts +54 -0
- package/dist/components/Stepper/StepperStep.svelte +369 -0
- package/dist/components/Stepper/StepperStep.svelte.d.ts +63 -0
- package/dist/components/Table/Table.svelte +167 -0
- package/dist/components/Table/Table.svelte.d.ts +56 -0
- package/dist/components/Table/TableBody.svelte +41 -0
- package/dist/components/Table/TableBody.svelte.d.ts +33 -0
- package/dist/components/Table/TableCell.svelte +76 -0
- package/dist/components/Table/TableCell.svelte.d.ts +36 -0
- package/dist/components/Table/TableHead.svelte +41 -0
- package/dist/components/Table/TableHead.svelte.d.ts +32 -0
- package/dist/components/Table/TableHeader.svelte +148 -0
- package/dist/components/Table/TableHeader.svelte.d.ts +42 -0
- package/dist/components/Table/TableRow.svelte +99 -0
- package/dist/components/Table/TableRow.svelte.d.ts +40 -0
- package/dist/components/Tabs/Tab.svelte +145 -0
- package/dist/components/Tabs/Tab.svelte.d.ts +36 -0
- package/dist/components/Tabs/TabList.svelte +60 -0
- package/dist/components/Tabs/TabList.svelte.d.ts +32 -0
- package/dist/components/Tabs/TabPanel.svelte +118 -0
- package/dist/components/Tabs/TabPanel.svelte.d.ts +38 -0
- package/dist/components/Tabs/Tabs.svelte +287 -0
- package/dist/components/Tabs/Tabs.svelte.d.ts +50 -0
- package/dist/components/Tag/Tag.svelte +260 -0
- package/dist/components/Tag/Tag.svelte.d.ts +54 -0
- package/dist/components/Tag/TagGroup.svelte +147 -0
- package/dist/components/Tag/TagGroup.svelte.d.ts +62 -0
- package/dist/components/ThemeToggle/ThemeToggle.svelte +93 -0
- package/dist/components/ThemeToggle/ThemeToggle.svelte.d.ts +12 -0
- package/dist/components/Timeline/Timeline.svelte +144 -0
- package/dist/components/Timeline/Timeline.svelte.d.ts +48 -0
- package/dist/components/Timeline/TimelineItem.svelte +391 -0
- package/dist/components/Timeline/TimelineItem.svelte.d.ts +63 -0
- package/dist/components/Toast/Toast.svelte +313 -0
- package/dist/components/Toast/Toast.svelte.d.ts +44 -0
- package/dist/components/Toast/toastStore.d.ts +40 -0
- package/dist/components/Toast/toastStore.js +293 -0
- package/dist/components/Tooltip/Tooltip.svelte +282 -0
- package/dist/components/Tooltip/Tooltip.svelte.d.ts +55 -0
- package/dist/components/Tree/Tree.svelte +129 -0
- package/dist/components/Tree/Tree.svelte.d.ts +61 -0
- package/dist/components/Tree/TreeNode.svelte +332 -0
- package/dist/components/Tree/TreeNode.svelte.d.ts +55 -0
- package/dist/components/icons/TwintrinsicLogo.svelte +73 -0
- package/dist/components/icons/TwintrinsicLogo.svelte.d.ts +17 -0
- package/dist/components/icons/twintrinsic-source.svg +73 -0
- package/dist/components/icons/twintrinsic.svg +38 -0
- package/dist/docs/EventsTable.svelte +86 -0
- package/dist/docs/EventsTable.svelte.d.ts +27 -0
- package/dist/docs/PropsTable.svelte +103 -0
- package/dist/docs/PropsTable.svelte.d.ts +28 -0
- package/dist/docs/index.d.ts +2 -0
- package/dist/docs/index.js +2 -0
- package/dist/helpers/detectLanguage.d.ts +6 -0
- package/dist/helpers/detectLanguage.js +60 -0
- package/dist/helpers/index.d.ts +1 -0
- package/dist/helpers/index.js +1 -0
- package/dist/index.d.ts +86 -0
- package/dist/index.js +94 -0
- package/dist/twintrinsic.css +347 -0
- package/package.json +98 -0
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
@component
|
|
3
|
+
ChipGroup - A container for managing multiple Chip components.
|
|
4
|
+
Provides consistent spacing, layout options, and keyboard navigation.
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
```svelte
|
|
8
|
+
<ChipGroup>
|
|
9
|
+
<Chip>Chip 1</Chip>
|
|
10
|
+
<Chip>Chip 2</Chip>
|
|
11
|
+
<Chip>Chip 3</Chip>
|
|
12
|
+
</ChipGroup>
|
|
13
|
+
|
|
14
|
+
<ChipGroup variant="primary" removable>
|
|
15
|
+
<Chip>JavaScript</Chip>
|
|
16
|
+
<Chip>TypeScript</Chip>
|
|
17
|
+
<Chip>Svelte</Chip>
|
|
18
|
+
</ChipGroup>
|
|
19
|
+
|
|
20
|
+
<ChipGroup
|
|
21
|
+
items={['Red', 'Green', 'Blue']}
|
|
22
|
+
let:item
|
|
23
|
+
selectable
|
|
24
|
+
onselect={handleSelect}
|
|
25
|
+
>
|
|
26
|
+
<Chip>{item}</Chip>
|
|
27
|
+
</ChipGroup>
|
|
28
|
+
```
|
|
29
|
+
-->
|
|
30
|
+
<script>
|
|
31
|
+
import { setContext } from "svelte"
|
|
32
|
+
|
|
33
|
+
const {
|
|
34
|
+
/** @type {string} - Additional CSS classes */
|
|
35
|
+
class: className = "",
|
|
36
|
+
|
|
37
|
+
/** @type {string} - HTML id for accessibility */
|
|
38
|
+
id = crypto.randomUUID(),
|
|
39
|
+
|
|
40
|
+
/** @type {string} - Visual style variant passed to all chips */
|
|
41
|
+
variant = "default",
|
|
42
|
+
|
|
43
|
+
/** @type {string} - Size passed to all chips (sm, md, lg) */
|
|
44
|
+
size = "md",
|
|
45
|
+
|
|
46
|
+
/** @type {boolean} - Whether all chips are removable */
|
|
47
|
+
removable = false,
|
|
48
|
+
|
|
49
|
+
/** @type {boolean} - Whether all chips are clickable */
|
|
50
|
+
clickable = false,
|
|
51
|
+
|
|
52
|
+
/** @type {boolean} - Whether all chips are selectable */
|
|
53
|
+
selectable = false,
|
|
54
|
+
|
|
55
|
+
/** @type {boolean} - Whether multiple chips can be selected */
|
|
56
|
+
multiple = false,
|
|
57
|
+
|
|
58
|
+
/** @type {boolean} - Whether all chips are disabled */
|
|
59
|
+
disabled = false,
|
|
60
|
+
|
|
61
|
+
/** @type {boolean} - Whether all chips use outline style */
|
|
62
|
+
outline = false,
|
|
63
|
+
|
|
64
|
+
/** @type {string} - Direction of the chip group (horizontal, vertical) */
|
|
65
|
+
direction = "horizontal",
|
|
66
|
+
|
|
67
|
+
/** @type {Array} - Items to render as chips */
|
|
68
|
+
items = [],
|
|
69
|
+
|
|
70
|
+
/** @type {Array} - Selected items or indices */
|
|
71
|
+
selected = [],
|
|
72
|
+
|
|
73
|
+
/** @type {string} - ARIA label for the chip group */
|
|
74
|
+
ariaLabel = "Chip group",
|
|
75
|
+
|
|
76
|
+
/** @type {(event: CustomEvent) => void} - Select event handler */
|
|
77
|
+
onselect,
|
|
78
|
+
/** @type {(event: CustomEvent) => void} - Remove event handler */
|
|
79
|
+
onremove,
|
|
80
|
+
|
|
81
|
+
children,
|
|
82
|
+
} = $props()
|
|
83
|
+
|
|
84
|
+
// Component state
|
|
85
|
+
let selectedItems = $state(Array.isArray(selected) ? [...selected] : [])
|
|
86
|
+
|
|
87
|
+
// Update selected items when prop changes
|
|
88
|
+
$effect(() => {
|
|
89
|
+
selectedItems = Array.isArray(selected) ? [...selected] : []
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
// Provide context for child chips
|
|
93
|
+
$effect(() => {
|
|
94
|
+
setContext("chipGroup", {
|
|
95
|
+
variant,
|
|
96
|
+
size,
|
|
97
|
+
removable,
|
|
98
|
+
clickable,
|
|
99
|
+
selectable,
|
|
100
|
+
multiple,
|
|
101
|
+
disabled,
|
|
102
|
+
outline,
|
|
103
|
+
isSelected: (item) => selectedItems.includes(item),
|
|
104
|
+
toggleSelection: (item) => {
|
|
105
|
+
if (selectable) {
|
|
106
|
+
if (selectedItems.includes(item)) {
|
|
107
|
+
// Remove item if already selected
|
|
108
|
+
selectedItems = selectedItems.filter((i) => i !== item)
|
|
109
|
+
} else {
|
|
110
|
+
// Add item if not selected
|
|
111
|
+
if (multiple) {
|
|
112
|
+
selectedItems = [...selectedItems, item]
|
|
113
|
+
} else {
|
|
114
|
+
selectedItems = [item]
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
onselect?.(new CustomEvent("select", { detail: { selected: selectedItems } }))
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
})
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Handles removing a chip
|
|
125
|
+
* @param {number} index - Index of the chip to remove
|
|
126
|
+
*/
|
|
127
|
+
function handleRemove(index) {
|
|
128
|
+
if (items.length > 0) {
|
|
129
|
+
const newItems = [...items]
|
|
130
|
+
const removedItem = newItems.splice(index, 1)[0]
|
|
131
|
+
onremove?.(new CustomEvent("remove", { detail: { item: removedItem, index } }))
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
</script>
|
|
135
|
+
|
|
136
|
+
<div
|
|
137
|
+
{id}
|
|
138
|
+
class="
|
|
139
|
+
chip-group
|
|
140
|
+
chip-group-{direction}
|
|
141
|
+
{className}
|
|
142
|
+
"
|
|
143
|
+
role={selectable ? 'listbox' : 'group'}
|
|
144
|
+
aria-label={ariaLabel}
|
|
145
|
+
aria-multiselectable={selectable && multiple ? true : undefined}
|
|
146
|
+
>
|
|
147
|
+
{#if items.length > 0}
|
|
148
|
+
{#each items as item, index}
|
|
149
|
+
<div class="chip-group-item">
|
|
150
|
+
<svelte:component
|
|
151
|
+
this={children?.item}
|
|
152
|
+
{item}
|
|
153
|
+
{index}
|
|
154
|
+
variant={variant}
|
|
155
|
+
size={size}
|
|
156
|
+
removable={removable}
|
|
157
|
+
clickable={clickable || selectable}
|
|
158
|
+
disabled={disabled}
|
|
159
|
+
selected={selectedItems.includes(item)}
|
|
160
|
+
outline={outline}
|
|
161
|
+
onclick={() => selectable && !disabled && setContext('chipGroup').toggleSelection(item)}
|
|
162
|
+
onremove={() => handleRemove(index)}
|
|
163
|
+
/>
|
|
164
|
+
</div>
|
|
165
|
+
{/each}
|
|
166
|
+
{:else}
|
|
167
|
+
{@render children?.()}
|
|
168
|
+
{/if}
|
|
169
|
+
</div>
|
|
170
|
+
|
|
171
|
+
<style>
|
|
172
|
+
@reference "../../twintrinsic.css";
|
|
173
|
+
|
|
174
|
+
.chip-group {
|
|
175
|
+
@apply flex flex-wrap;
|
|
176
|
+
@apply gap-2;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.chip-group-horizontal {
|
|
180
|
+
@apply flex-row;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.chip-group-vertical {
|
|
184
|
+
@apply flex-col;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.chip-group-item {
|
|
188
|
+
@apply flex-none;
|
|
189
|
+
}
|
|
190
|
+
</style>
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
export default ChipGroup;
|
|
2
|
+
type ChipGroup = {
|
|
3
|
+
$on?(type: string, callback: (e: any) => void): () => void;
|
|
4
|
+
$set?(props: Partial<$$ComponentProps>): void;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* ChipGroup - A container for managing multiple Chip components.
|
|
8
|
+
* Provides consistent spacing, layout options, and keyboard navigation.
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* ```svelte
|
|
12
|
+
* <ChipGroup>
|
|
13
|
+
* <Chip>Chip 1</Chip>
|
|
14
|
+
* <Chip>Chip 2</Chip>
|
|
15
|
+
* <Chip>Chip 3</Chip>
|
|
16
|
+
* </ChipGroup>
|
|
17
|
+
*
|
|
18
|
+
* <ChipGroup variant="primary" removable>
|
|
19
|
+
* <Chip>JavaScript</Chip>
|
|
20
|
+
* <Chip>TypeScript</Chip>
|
|
21
|
+
* <Chip>Svelte</Chip>
|
|
22
|
+
* </ChipGroup>
|
|
23
|
+
*
|
|
24
|
+
* <ChipGroup
|
|
25
|
+
* items={['Red', 'Green', 'Blue']}
|
|
26
|
+
* let:item
|
|
27
|
+
* selectable
|
|
28
|
+
* onselect={handleSelect}
|
|
29
|
+
* >
|
|
30
|
+
* <Chip>{item}</Chip>
|
|
31
|
+
* </ChipGroup>
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
declare const ChipGroup: import("svelte").Component<{
|
|
35
|
+
class?: string;
|
|
36
|
+
id?: any;
|
|
37
|
+
variant?: string;
|
|
38
|
+
size?: string;
|
|
39
|
+
removable?: boolean;
|
|
40
|
+
clickable?: boolean;
|
|
41
|
+
selectable?: boolean;
|
|
42
|
+
multiple?: boolean;
|
|
43
|
+
disabled?: boolean;
|
|
44
|
+
outline?: boolean;
|
|
45
|
+
direction?: string;
|
|
46
|
+
items?: any[];
|
|
47
|
+
selected?: any[];
|
|
48
|
+
ariaLabel?: string;
|
|
49
|
+
onselect: any;
|
|
50
|
+
onremove: any;
|
|
51
|
+
children: any;
|
|
52
|
+
}, {}, "">;
|
|
53
|
+
type $$ComponentProps = {
|
|
54
|
+
class?: string;
|
|
55
|
+
id?: any;
|
|
56
|
+
variant?: string;
|
|
57
|
+
size?: string;
|
|
58
|
+
removable?: boolean;
|
|
59
|
+
clickable?: boolean;
|
|
60
|
+
selectable?: boolean;
|
|
61
|
+
multiple?: boolean;
|
|
62
|
+
disabled?: boolean;
|
|
63
|
+
outline?: boolean;
|
|
64
|
+
direction?: string;
|
|
65
|
+
items?: any[];
|
|
66
|
+
selected?: any[];
|
|
67
|
+
ariaLabel?: string;
|
|
68
|
+
onselect: any;
|
|
69
|
+
onremove: any;
|
|
70
|
+
children: any;
|
|
71
|
+
};
|
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
@component
|
|
3
|
+
CodeBlock - A component for displaying code snippets with syntax highlighting and copy functionality.
|
|
4
|
+
|
|
5
|
+
Features:
|
|
6
|
+
- Syntax highlighting with Prism.js
|
|
7
|
+
- Automatic language detection
|
|
8
|
+
- Dynamic language loading via Prism.js autoloader plugin
|
|
9
|
+
- Copy to clipboard functionality
|
|
10
|
+
- Support for multiple CDNs (unpkg, esm.sh, jsdelivr)
|
|
11
|
+
|
|
12
|
+
> NOTE: The slot needs to be outdented as far as possible so the child contents' first line isn't indented.
|
|
13
|
+
|
|
14
|
+
Usage:
|
|
15
|
+
```svelte
|
|
16
|
+
<CodeBlock language="javascript">
|
|
17
|
+
const hello = 'world';
|
|
18
|
+
console.log(hello);
|
|
19
|
+
</CodeBlock>
|
|
20
|
+
|
|
21
|
+
<CodeBlock>
|
|
22
|
+
<!-- Auto-detects language -->
|
|
23
|
+
const hello = 'world';
|
|
24
|
+
</CodeBlock>
|
|
25
|
+
|
|
26
|
+
<CodeBlock language="python" cdn="jsdelivr">
|
|
27
|
+
print('hello world')
|
|
28
|
+
</CodeBlock>
|
|
29
|
+
|
|
30
|
+
<CodeBlock cdn="esm.sh" languagesPath="https://custom.cdn/prismjs/components/">
|
|
31
|
+
<!-- Custom CDN and language path -->
|
|
32
|
+
const code = 'example';
|
|
33
|
+
</CodeBlock>
|
|
34
|
+
```
|
|
35
|
+
-->
|
|
36
|
+
<script lang="ts">
|
|
37
|
+
import Prism from "prismjs";
|
|
38
|
+
import { onDestroy, onMount } from "svelte";
|
|
39
|
+
import { detectLanguage } from "../../helpers";
|
|
40
|
+
// import "prism-svelte";
|
|
41
|
+
import "prismjs/plugins/autoloader/prism-autoloader";
|
|
42
|
+
|
|
43
|
+
const {
|
|
44
|
+
/** @type {string} - The language for syntax highlighting */
|
|
45
|
+
language = "",
|
|
46
|
+
/** @type {string} - Additional CSS classes */
|
|
47
|
+
class: className = "",
|
|
48
|
+
/** @type { "unpkg" | "esm.sh" | "jsdelivr" | string } - CDN to use for autoloader, or custom path to prism components folder*/
|
|
49
|
+
pluginSource = "unpkg",
|
|
50
|
+
/** @type {string[]} - List of plugin names (e.g., "autoloader") or full paths to load */
|
|
51
|
+
plugins = [],
|
|
52
|
+
/** @type {import('svelte').Snippet} - The code to display */
|
|
53
|
+
children = ""
|
|
54
|
+
} = $props()
|
|
55
|
+
|
|
56
|
+
let code = $state("")
|
|
57
|
+
let copied = $state(false)
|
|
58
|
+
let copyTimeout = $state()
|
|
59
|
+
let codeElement = $state()
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Get CDN URL for a plugin
|
|
64
|
+
* @param {string} plugin - Plugin name or full path
|
|
65
|
+
* @param {string} pluginSource - CDN name
|
|
66
|
+
* @returns {string} Full URL to plugin
|
|
67
|
+
*/
|
|
68
|
+
function getPluginUrl(plugin, pluginSource) {
|
|
69
|
+
// If it's a full path (contains :// or starts with /), return as-is
|
|
70
|
+
if (plugin.includes("://") || plugin.startsWith("/")) {
|
|
71
|
+
return plugin;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Otherwise, it's a plugin name - construct URL based on CDN
|
|
75
|
+
const pluginName = plugin.startsWith("prism-") ? plugin : `prism-${plugin}`;
|
|
76
|
+
|
|
77
|
+
switch (pluginSource) {
|
|
78
|
+
case "esm.sh":
|
|
79
|
+
return `https://esm.sh/prismjs@1/plugins/${plugin}/${pluginName}.min.js`;
|
|
80
|
+
case "jsdelivr":
|
|
81
|
+
return `https://cdn.jsdelivr.net/npm/prismjs@1/plugins/${plugin}/${pluginName}.min.js`;
|
|
82
|
+
case "unpkg":
|
|
83
|
+
default:
|
|
84
|
+
return `https://unpkg.com/prismjs@1/plugins/${plugin}/${pluginName}.min.js`;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Load plugins via script tags
|
|
90
|
+
* @param {string[]} pluginList - List of plugin names or paths
|
|
91
|
+
*/
|
|
92
|
+
async function loadPlugins(pluginList) {
|
|
93
|
+
for (const plugin of pluginList) {
|
|
94
|
+
const url = getPluginUrl(plugin, pluginSource);
|
|
95
|
+
await new Promise<void>((resolve, reject) => {
|
|
96
|
+
const script = document.createElement("script");
|
|
97
|
+
script.src = url;
|
|
98
|
+
script.onload = () => resolve();
|
|
99
|
+
script.onerror = () => reject(new Error(`Failed to load plugin: ${url}`));
|
|
100
|
+
document.head.appendChild(script);
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Get languages path for autoloader
|
|
107
|
+
* @param {string} pluginSource - CDN name or path to a custom cdn
|
|
108
|
+
* @returns {string} Path to language grammars
|
|
109
|
+
*/
|
|
110
|
+
function getLanguagesPath(pluginSource) {
|
|
111
|
+
|
|
112
|
+
switch (pluginSource) {
|
|
113
|
+
case "esm.sh":
|
|
114
|
+
return "https://esm.sh/prismjs@1/components/"
|
|
115
|
+
case "jsdelivr":
|
|
116
|
+
return "https://cdn.jsdelivr.net/npm/prismjs@1/components/"
|
|
117
|
+
case "unpkg":
|
|
118
|
+
return "https://unpkg.com/prismjs@1/components/"
|
|
119
|
+
default:
|
|
120
|
+
return pluginSource;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Initialize plugins and highlight code
|
|
125
|
+
onMount(async () => {
|
|
126
|
+
if (plugins.length > 0) {
|
|
127
|
+
await loadPlugins(plugins);
|
|
128
|
+
}
|
|
129
|
+
highlightCode()
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* determine the path to the language components based on the plugin source.
|
|
134
|
+
* @param {string} language - The language to determine the path for
|
|
135
|
+
* @returns {[string, boolean]} The path to the language components and whether to use minified files
|
|
136
|
+
*/
|
|
137
|
+
function determineComponentsDirectory(language) {
|
|
138
|
+
if(language === "svelte") {
|
|
139
|
+
switch (pluginSource) {
|
|
140
|
+
case "esm.sh":
|
|
141
|
+
return ["https://esm.sh/prism-svelte", true]
|
|
142
|
+
case "jsdelivr":
|
|
143
|
+
return ["https://cdn.jsdelivr.net/npm/prism-svelte", true]
|
|
144
|
+
case "unpkg":
|
|
145
|
+
return ["https://unpkg.com/prism-svelte", true]
|
|
146
|
+
default:
|
|
147
|
+
return [getLanguagesPath(pluginSource), false];
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return [getLanguagesPath(pluginSource), false];
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Highlight code with language detection
|
|
155
|
+
*/
|
|
156
|
+
async function highlightCode() {
|
|
157
|
+
if (!codeElement) return
|
|
158
|
+
|
|
159
|
+
code = codeElement.textContent || ""
|
|
160
|
+
|
|
161
|
+
// Auto-detect language if not specified
|
|
162
|
+
const detectedLang = language || detectLanguage(code);
|
|
163
|
+
|
|
164
|
+
const [languagesPath, isFullPath] = determineComponentsDirectory(detectedLang);
|
|
165
|
+
|
|
166
|
+
// If language not already loaded, load it
|
|
167
|
+
if (detectedLang && !Prism.languages[detectedLang]) {
|
|
168
|
+
if (isFullPath) {
|
|
169
|
+
// For full paths (like prism-svelte), load the script directly
|
|
170
|
+
await new Promise<void>((resolve, reject) => {
|
|
171
|
+
const script = document.createElement('script');
|
|
172
|
+
script.src = languagesPath;
|
|
173
|
+
script.onload = () => resolve();
|
|
174
|
+
script.onerror = () => reject(new Error(`Failed to load ${languagesPath}`));
|
|
175
|
+
document.head.appendChild(script);
|
|
176
|
+
});
|
|
177
|
+
} else if (Prism.plugins?.autoloader) {
|
|
178
|
+
// For standard paths, use autoloader with custom languages_path
|
|
179
|
+
Prism.plugins.autoloader.languages_path = languagesPath;
|
|
180
|
+
await new Promise<void>((resolve) => {
|
|
181
|
+
Prism.plugins.autoloader.loadLanguages(detectedLang, () => {
|
|
182
|
+
resolve()
|
|
183
|
+
})
|
|
184
|
+
})
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Highlight code
|
|
189
|
+
if (detectedLang) {
|
|
190
|
+
const grammar = Prism.languages[detectedLang]
|
|
191
|
+
if (grammar) {
|
|
192
|
+
const highlighted = Prism.highlight(code, grammar, detectedLang)
|
|
193
|
+
codeElement.innerHTML = highlighted
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Clean up copy timeout
|
|
199
|
+
onDestroy(() => {
|
|
200
|
+
if (copyTimeout) {
|
|
201
|
+
clearTimeout(copyTimeout)
|
|
202
|
+
}
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Copy code to clipboard
|
|
207
|
+
*/
|
|
208
|
+
async function copyCode() {
|
|
209
|
+
if (copied) return
|
|
210
|
+
|
|
211
|
+
try {
|
|
212
|
+
await navigator.clipboard.writeText(code)
|
|
213
|
+
copied = true
|
|
214
|
+
|
|
215
|
+
copyTimeout = setTimeout(() => {
|
|
216
|
+
copied = false
|
|
217
|
+
}, 2000)
|
|
218
|
+
} catch (error) {
|
|
219
|
+
console.error("Failed to copy code:", error)
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
</script>
|
|
223
|
+
|
|
224
|
+
<div class="code-block {className}">
|
|
225
|
+
<div class="code-header">
|
|
226
|
+
{#if language}
|
|
227
|
+
<div class="code-language">{language}</div>
|
|
228
|
+
{/if}
|
|
229
|
+
<button
|
|
230
|
+
type="button"
|
|
231
|
+
class="code-copy"
|
|
232
|
+
onclick={copyCode}
|
|
233
|
+
aria-label={copied ? 'Copied!' : 'Copy code'}
|
|
234
|
+
>
|
|
235
|
+
{#if copied}
|
|
236
|
+
<svg viewBox="0 0 24 24" width="16" height="16">
|
|
237
|
+
<path
|
|
238
|
+
fill="currentColor"
|
|
239
|
+
d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"
|
|
240
|
+
/>
|
|
241
|
+
</svg>
|
|
242
|
+
<span>Copied!</span>
|
|
243
|
+
{:else}
|
|
244
|
+
<svg viewBox="0 0 24 24" width="16" height="16">
|
|
245
|
+
<path
|
|
246
|
+
fill="currentColor"
|
|
247
|
+
d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"
|
|
248
|
+
/>
|
|
249
|
+
</svg>
|
|
250
|
+
<span>Copy</span>
|
|
251
|
+
{/if}
|
|
252
|
+
</button>
|
|
253
|
+
</div>
|
|
254
|
+
|
|
255
|
+
<pre class="code-pre {plugins.join(' ')}"><code
|
|
256
|
+
bind:this={codeElement}
|
|
257
|
+
class="language-{language || 'javascript'}"
|
|
258
|
+
>{@render children?.()}</code></pre>
|
|
259
|
+
</div>
|
|
260
|
+
|
|
261
|
+
<style>
|
|
262
|
+
@reference '../../twintrinsic.css';
|
|
263
|
+
|
|
264
|
+
.code-block {
|
|
265
|
+
@apply relative my-4 rounded-lg overflow-hidden;
|
|
266
|
+
@apply bg-surface border border-border;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.code-header {
|
|
270
|
+
@apply flex items-center justify-between px-4 py-2;
|
|
271
|
+
@apply bg-surface border-b border-border;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.code-language {
|
|
275
|
+
@apply text-xs font-mono text-muted;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.code-copy {
|
|
279
|
+
@apply flex items-center gap-2 px-2 py-1;
|
|
280
|
+
@apply text-xs font-medium text-muted;
|
|
281
|
+
@apply rounded hover:bg-hover;
|
|
282
|
+
@apply transition-colors duration-150;
|
|
283
|
+
@apply focus:outline-none focus:ring-2 focus:ring-primary/50;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.code-pre {
|
|
287
|
+
@apply m-0 p-4 overflow-x-auto;
|
|
288
|
+
@apply font-mono text-sm;
|
|
289
|
+
@apply bg-surface dark:bg-surface;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
:global(.code-pre .token.comment),
|
|
293
|
+
:global(.code-pre .token.prolog),
|
|
294
|
+
:global(.code-pre .token.doctype),
|
|
295
|
+
:global(.code-pre .token.cdata) {
|
|
296
|
+
@apply text-muted dark:text-muted;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
:global(.code-pre .token.punctuation) {
|
|
300
|
+
@apply text-primary-600 dark:text-primary-400;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
:global(.code-pre .token.property),
|
|
304
|
+
:global(.code-pre .token.tag),
|
|
305
|
+
:global(.code-pre .token.boolean),
|
|
306
|
+
:global(.code-pre .token.number),
|
|
307
|
+
:global(.code-pre .token.constant),
|
|
308
|
+
:global(.code-pre .token.symbol) {
|
|
309
|
+
@apply text-primary-700 dark:text-primary-300;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
:global(.code-pre .token.selector),
|
|
313
|
+
:global(.code-pre .token.attr-name),
|
|
314
|
+
:global(.code-pre .token.string),
|
|
315
|
+
:global(.code-pre .token.char),
|
|
316
|
+
:global(.code-pre .token.builtin) {
|
|
317
|
+
@apply text-success;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
:global(.code-pre .token.operator),
|
|
321
|
+
:global(.code-pre .token.entity),
|
|
322
|
+
:global(.code-pre .token.url),
|
|
323
|
+
:global(.code-pre .language-css .token.string),
|
|
324
|
+
:global(.code-pre .style .token.string) {
|
|
325
|
+
@apply text-warning;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
:global(.code-pre .token.atrule),
|
|
329
|
+
:global(.code-pre .token.attr-value),
|
|
330
|
+
:global(.code-pre .token.keyword) {
|
|
331
|
+
@apply text-info;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
:global(.code-pre .token.function),
|
|
335
|
+
:global(.code-pre .token.class-name) {
|
|
336
|
+
@apply text-error;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
:global(.code-pre .token.regex),
|
|
340
|
+
:global(.code-pre .token.important) {
|
|
341
|
+
@apply text-warning;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
:global(.code-pre .token.important),
|
|
345
|
+
:global(.code-pre .token.bold) {
|
|
346
|
+
@apply font-bold;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
:global(.code-pre .token.italic) {
|
|
350
|
+
@apply italic;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
:global(.code-pre .token.entity) {
|
|
354
|
+
@apply cursor-help;
|
|
355
|
+
}
|
|
356
|
+
</style>
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import "prismjs/plugins/autoloader/prism-autoloader";
|
|
2
|
+
/**
|
|
3
|
+
* CodeBlock - A component for displaying code snippets with syntax highlighting and copy functionality.
|
|
4
|
+
*
|
|
5
|
+
* Features:
|
|
6
|
+
* - Syntax highlighting with Prism.js
|
|
7
|
+
* - Automatic language detection
|
|
8
|
+
* - Dynamic language loading via Prism.js autoloader plugin
|
|
9
|
+
* - Copy to clipboard functionality
|
|
10
|
+
* - Support for multiple CDNs (unpkg, esm.sh, jsdelivr)
|
|
11
|
+
*
|
|
12
|
+
* > NOTE: The slot needs to be outdented as far as possible so the child contents' first line isn't indented.
|
|
13
|
+
*
|
|
14
|
+
* Usage:
|
|
15
|
+
* ```svelte
|
|
16
|
+
* <CodeBlock language="javascript">
|
|
17
|
+
* const hello = 'world';
|
|
18
|
+
* console.log(hello);
|
|
19
|
+
* </CodeBlock>
|
|
20
|
+
*
|
|
21
|
+
* <CodeBlock>
|
|
22
|
+
* <!-- Auto-detects language -->
|
|
23
|
+
* const hello = 'world';
|
|
24
|
+
* </CodeBlock>
|
|
25
|
+
*
|
|
26
|
+
* <CodeBlock language="python" cdn="jsdelivr">
|
|
27
|
+
* print('hello world')
|
|
28
|
+
* </CodeBlock>
|
|
29
|
+
*
|
|
30
|
+
* <CodeBlock cdn="esm.sh" languagesPath="https://custom.cdn/prismjs/components/">
|
|
31
|
+
* <!-- Custom CDN and language path -->
|
|
32
|
+
* const code = 'example';
|
|
33
|
+
* </CodeBlock>
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
declare const CodeBlock: import("svelte").Component<{
|
|
37
|
+
language?: string;
|
|
38
|
+
class?: string;
|
|
39
|
+
pluginSource?: string;
|
|
40
|
+
plugins?: any[];
|
|
41
|
+
children?: string;
|
|
42
|
+
}, {}, "">;
|
|
43
|
+
type CodeBlock = ReturnType<typeof CodeBlock>;
|
|
44
|
+
export default CodeBlock;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as CodeBlock } from "./CodeBlock.svelte";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as CodeBlock } from "./CodeBlock.svelte";
|