svelte-comp 1.2.5 → 1.2.6
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/README.md +1 -1
- package/package.json +1 -1
- package/dist/App.svelte +0 -551
- package/dist/App.svelte.d.ts +0 -3
- package/dist/Container.svelte +0 -60
- package/dist/Container.svelte.d.ts +0 -12
- package/dist/app.css +0 -235
- package/dist/index.d.ts +0 -5
- package/dist/index.js +0 -6
- package/dist/lang.d.ts +0 -1081
- package/dist/lang.js +0 -1096
- package/dist/lib/Accordion.svelte +0 -155
- package/dist/lib/Accordion.svelte.d.ts +0 -40
- package/dist/lib/Button.svelte +0 -170
- package/dist/lib/Button.svelte.d.ts +0 -53
- package/dist/lib/Card.svelte +0 -103
- package/dist/lib/Card.svelte.d.ts +0 -42
- package/dist/lib/Carousel.svelte +0 -293
- package/dist/lib/Carousel.svelte.d.ts +0 -13
- package/dist/lib/CheckBox.svelte +0 -210
- package/dist/lib/CheckBox.svelte.d.ts +0 -53
- package/dist/lib/CodeView.svelte +0 -307
- package/dist/lib/CodeView.svelte.d.ts +0 -64
- package/dist/lib/ColorPicker.svelte +0 -161
- package/dist/lib/ColorPicker.svelte.d.ts +0 -40
- package/dist/lib/DatePicker.svelte +0 -170
- package/dist/lib/DatePicker.svelte.d.ts +0 -53
- package/dist/lib/Dialog.svelte +0 -235
- package/dist/lib/Dialog.svelte.d.ts +0 -58
- package/dist/lib/Field.svelte +0 -299
- package/dist/lib/Field.svelte.d.ts +0 -8
- package/dist/lib/FilePicker.svelte +0 -241
- package/dist/lib/FilePicker.svelte.d.ts +0 -52
- package/dist/lib/Form.svelte +0 -438
- package/dist/lib/Form.svelte.d.ts +0 -20
- package/dist/lib/Hamburger.svelte +0 -211
- package/dist/lib/Hamburger.svelte.d.ts +0 -52
- package/dist/lib/Menu.svelte +0 -623
- package/dist/lib/Menu.svelte.d.ts +0 -33
- package/dist/lib/PaginatedCard.svelte +0 -73
- package/dist/lib/PaginatedCard.svelte.d.ts +0 -11
- package/dist/lib/Pagination.svelte +0 -119
- package/dist/lib/Pagination.svelte.d.ts +0 -9
- package/dist/lib/PrimaryColorSelect.svelte +0 -113
- package/dist/lib/PrimaryColorSelect.svelte.d.ts +0 -9
- package/dist/lib/ProgressBar.svelte +0 -141
- package/dist/lib/ProgressBar.svelte.d.ts +0 -48
- package/dist/lib/ProgressCircle.svelte +0 -192
- package/dist/lib/ProgressCircle.svelte.d.ts +0 -39
- package/dist/lib/Radio.svelte +0 -189
- package/dist/lib/Radio.svelte.d.ts +0 -55
- package/dist/lib/SearchInput.svelte +0 -106
- package/dist/lib/SearchInput.svelte.d.ts +0 -13
- package/dist/lib/Select.svelte +0 -524
- package/dist/lib/Select.svelte.d.ts +0 -21
- package/dist/lib/Slider.svelte +0 -253
- package/dist/lib/Slider.svelte.d.ts +0 -56
- package/dist/lib/Splitter.svelte +0 -150
- package/dist/lib/Splitter.svelte.d.ts +0 -43
- package/dist/lib/Switch.svelte +0 -167
- package/dist/lib/Switch.svelte.d.ts +0 -42
- package/dist/lib/Table.svelte +0 -299
- package/dist/lib/Table.svelte.d.ts +0 -17
- package/dist/lib/Tabs.svelte +0 -213
- package/dist/lib/Tabs.svelte.d.ts +0 -48
- package/dist/lib/ThemeToggle.svelte +0 -127
- package/dist/lib/ThemeToggle.svelte.d.ts +0 -32
- package/dist/lib/TimePicker.svelte +0 -269
- package/dist/lib/TimePicker.svelte.d.ts +0 -48
- package/dist/lib/Toast.svelte +0 -226
- package/dist/lib/Toast.svelte.d.ts +0 -14
- package/dist/lib/Tooltip.svelte +0 -110
- package/dist/lib/Tooltip.svelte.d.ts +0 -40
- package/dist/lib/index.d.ts +0 -32
- package/dist/lib/index.js +0 -33
- package/dist/lib/lang.d.ts +0 -158
- package/dist/lib/lang.js +0 -150
- package/dist/lib/types/index.d.ts +0 -111
- package/dist/lib/types/index.js +0 -26
- package/dist/main.d.ts +0 -3
- package/dist/main.js +0 -7
- package/dist/styles.css +0 -232
- package/dist/utils/index.d.ts +0 -34
- package/dist/utils/index.js +0 -268
package/dist/lib/CodeView.svelte
DELETED
|
@@ -1,307 +0,0 @@
|
|
|
1
|
-
<!-- src/lib/CodeView.svelte -->
|
|
2
|
-
<script lang="ts">
|
|
3
|
-
/**
|
|
4
|
-
* @component CodeView
|
|
5
|
-
* @description CodeView is a small prism.js powered code block that supports syntax highlighting, optional editing, line numbers and active-line highlighting.
|
|
6
|
-
*
|
|
7
|
-
* @prop code {string} - Code content to render
|
|
8
|
-
* @default ""
|
|
9
|
-
*
|
|
10
|
-
* @prop language {Language} - Syntax highlighting language
|
|
11
|
-
* @options txt|html|css|js|json|python
|
|
12
|
-
* @default "txt"
|
|
13
|
-
*
|
|
14
|
-
* @prop title {string} - Title displayed above the code block
|
|
15
|
-
* @default "Code"
|
|
16
|
-
*
|
|
17
|
-
* @prop showCopyButton {boolean} - Shows the copy-to-clipboard button
|
|
18
|
-
* @default true
|
|
19
|
-
*
|
|
20
|
-
* @prop showLineNumbers {boolean} - Displays line numbers alongside the code
|
|
21
|
-
* @default false
|
|
22
|
-
*
|
|
23
|
-
* @prop editable {boolean} - Enables editable mode with a textarea overlay
|
|
24
|
-
* @default false
|
|
25
|
-
*
|
|
26
|
-
* @prop activeLine {boolean} - Highlights the current cursor line in editable mode
|
|
27
|
-
* @default false
|
|
28
|
-
*
|
|
29
|
-
* @prop sz {SizeKey} - Size preset affecting spacing and typography
|
|
30
|
-
* @options xs|sm|md|lg|xl
|
|
31
|
-
* @default md
|
|
32
|
-
*
|
|
33
|
-
* @prop class {string} - Extra classes applied to the root container
|
|
34
|
-
* @default ""
|
|
35
|
-
*
|
|
36
|
-
* @note Uses Prism for syntax highlighting; HTML/CSS/TXT grammars are bundled by default.
|
|
37
|
-
* @note Editable mode renders a transparent textarea above a highlighted code layer, mirroring real editors.
|
|
38
|
-
* @note Cursor-line highlight is overlaid using CSS variables and scroll-position tracking.
|
|
39
|
-
* @note Line numbers are fully scroll-synchronized with the editor content.
|
|
40
|
-
* @note Readonly mode shows static highlighted code, without textarea.
|
|
41
|
-
* @note Copy button writes the full code string to the clipboard.
|
|
42
|
-
* @note All sizing and spacing scale automatically with the shared `sz` token.
|
|
43
|
-
* @note Supports dark/light themes via existing design-token colors.
|
|
44
|
-
* @note Designed as a low-level editor component, not a full IDE replacement.
|
|
45
|
-
*/
|
|
46
|
-
import { type SizeKey, type Language, TEXT } from "./types";
|
|
47
|
-
import * as Prism from "prismjs";
|
|
48
|
-
import "prismjs/components/prism-markup";
|
|
49
|
-
import "prismjs/components/prism-css";
|
|
50
|
-
import "prismjs/components/prism-javascript";
|
|
51
|
-
import "prismjs/components/prism-json";
|
|
52
|
-
import "prismjs/components/prism-python";
|
|
53
|
-
import "prismjs/themes/prism.css";
|
|
54
|
-
import { cx } from "../utils";
|
|
55
|
-
|
|
56
|
-
type Props = {
|
|
57
|
-
code?: string;
|
|
58
|
-
language?: Language;
|
|
59
|
-
title?: string;
|
|
60
|
-
showCopyButton?: boolean;
|
|
61
|
-
showLineNumbers?: boolean;
|
|
62
|
-
editable?: boolean;
|
|
63
|
-
activeLine?: boolean;
|
|
64
|
-
sz?: SizeKey;
|
|
65
|
-
class?: string;
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
let {
|
|
69
|
-
code = $bindable(""),
|
|
70
|
-
language = "txt",
|
|
71
|
-
title = "Code",
|
|
72
|
-
showCopyButton = true,
|
|
73
|
-
showLineNumbers = false,
|
|
74
|
-
editable = false,
|
|
75
|
-
activeLine = false,
|
|
76
|
-
sz = "md",
|
|
77
|
-
class: externalClass = "",
|
|
78
|
-
}: Props = $props();
|
|
79
|
-
|
|
80
|
-
let textareaEl = $state<HTMLTextAreaElement | null>(null);
|
|
81
|
-
let gutterEl = $state<HTMLDivElement | null>(null);
|
|
82
|
-
let highlightEl = $state<HTMLDivElement | null>(null);
|
|
83
|
-
let copied = $state(false);
|
|
84
|
-
let activeLineIndex = $state(0);
|
|
85
|
-
let highlightScroll = $state(0);
|
|
86
|
-
let padTopPx = $state(12);
|
|
87
|
-
|
|
88
|
-
const lines = $derived(code.split("\n"));
|
|
89
|
-
|
|
90
|
-
const LINE_HEIGHT: Record<SizeKey, string> = {
|
|
91
|
-
xs: "leading-4",
|
|
92
|
-
sm: "leading-[1.1rem]",
|
|
93
|
-
md: "leading-[1.3rem]",
|
|
94
|
-
lg: "leading-[1.45rem]",
|
|
95
|
-
xl: "leading-7",
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
let lineHeightPx = $state(20);
|
|
99
|
-
|
|
100
|
-
function escapeHtml(x: string) {
|
|
101
|
-
return x.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function highlight(src: string, lang: Language) {
|
|
105
|
-
if (src === "") return "";
|
|
106
|
-
if (lang === "txt") return escapeHtml(src);
|
|
107
|
-
const key = lang === "html" ? "markup" : lang;
|
|
108
|
-
const grammar = Prism.languages[key];
|
|
109
|
-
return Prism.highlight(src, grammar, key);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const highlighted = $derived(highlight(code, language));
|
|
113
|
-
|
|
114
|
-
function updateActiveLine() {
|
|
115
|
-
if (!activeLine || !textareaEl) return;
|
|
116
|
-
const pos = textareaEl.selectionStart ?? 0;
|
|
117
|
-
const before = code.slice(0, pos);
|
|
118
|
-
activeLineIndex = before.split("\n").length - 1;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function syncScroll(event: Event) {
|
|
122
|
-
const el = event.currentTarget as HTMLElement;
|
|
123
|
-
if (gutterEl) gutterEl.scrollTop = el.scrollTop;
|
|
124
|
-
if (highlightEl) {
|
|
125
|
-
highlightEl.scrollTop = el.scrollTop;
|
|
126
|
-
highlightEl.scrollLeft = el.scrollLeft;
|
|
127
|
-
highlightScroll = el.scrollTop;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
$effect(() => {
|
|
132
|
-
void sz;
|
|
133
|
-
if (!textareaEl) return;
|
|
134
|
-
const styles = getComputedStyle(textareaEl);
|
|
135
|
-
const lh = Number.parseFloat(styles.lineHeight);
|
|
136
|
-
if (!Number.isNaN(lh)) lineHeightPx = lh;
|
|
137
|
-
const pt = Number.parseFloat(styles.paddingTop);
|
|
138
|
-
if (!Number.isNaN(pt)) padTopPx = pt;
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
async function copyToClipboard() {
|
|
142
|
-
await navigator.clipboard.writeText(code);
|
|
143
|
-
copied = true;
|
|
144
|
-
setTimeout(() => (copied = false), 1200);
|
|
145
|
-
}
|
|
146
|
-
</script>
|
|
147
|
-
|
|
148
|
-
<div
|
|
149
|
-
class={cx(
|
|
150
|
-
"cv-root w-full h-full min-h-0 flex flex-col border border-[var(--border-color-default)] bg-[var(--color-bg-surface)]",
|
|
151
|
-
"text-[var(--color-text-default)]",
|
|
152
|
-
externalClass
|
|
153
|
-
)}
|
|
154
|
-
>
|
|
155
|
-
{#if title}
|
|
156
|
-
<div
|
|
157
|
-
class={cx(
|
|
158
|
-
"px-3 py-1 bg-[var(--color-bg-muted)] font-semibold uppercase flex items-center justify-between",
|
|
159
|
-
TEXT[sz]
|
|
160
|
-
)}
|
|
161
|
-
>
|
|
162
|
-
<div>{title}</div>
|
|
163
|
-
|
|
164
|
-
{#if showCopyButton}
|
|
165
|
-
<button
|
|
166
|
-
onclick={copyToClipboard}
|
|
167
|
-
class={cx(
|
|
168
|
-
"px-3 py-0.5 text-xs rounded bg-[var(--color-primary)] text-white hover:opacity-[var(--opacity-hover)]",
|
|
169
|
-
"transition focus-visible:ring-2 focus-visible:ring-[var(--border-color-focus)] focus:outline-none"
|
|
170
|
-
)}
|
|
171
|
-
class:!bg-green-600={copied}
|
|
172
|
-
>
|
|
173
|
-
{copied ? "Copied" : "Copy"}
|
|
174
|
-
</button>
|
|
175
|
-
{/if}
|
|
176
|
-
</div>
|
|
177
|
-
{/if}
|
|
178
|
-
|
|
179
|
-
<div
|
|
180
|
-
class={cx(
|
|
181
|
-
"cv-body flex flex-1 min-h-0 font-mono",
|
|
182
|
-
TEXT[sz],
|
|
183
|
-
LINE_HEIGHT[sz]
|
|
184
|
-
)}
|
|
185
|
-
>
|
|
186
|
-
{#if showLineNumbers}
|
|
187
|
-
<div
|
|
188
|
-
bind:this={gutterEl}
|
|
189
|
-
class={cx(
|
|
190
|
-
"select-none px-3 py-[12px] border-r border-[var(--border-color-default)]",
|
|
191
|
-
"text-[var(--color-text-muted)] text-right overflow-hidden",
|
|
192
|
-
"cv-gutter bg-[var(--color-bg-surface)] tabular-nums h-full min-h-0"
|
|
193
|
-
)}
|
|
194
|
-
>
|
|
195
|
-
{#each lines as _, i (i)}
|
|
196
|
-
<div class={LINE_HEIGHT[sz]}>{i + 1}</div>
|
|
197
|
-
{/each}
|
|
198
|
-
</div>
|
|
199
|
-
{/if}
|
|
200
|
-
|
|
201
|
-
<div class="cv-editor relative flex-1 min-h-0">
|
|
202
|
-
<div
|
|
203
|
-
bind:this={highlightEl}
|
|
204
|
-
class={cx("cv-highlight cv-layer", TEXT[sz], LINE_HEIGHT[sz])}
|
|
205
|
-
class:cv-active-line={activeLine && editable}
|
|
206
|
-
style={activeLine && editable
|
|
207
|
-
? `--cv-line-height: ${lineHeightPx}px; --cv-active-line-top: ${padTopPx + activeLineIndex * lineHeightPx - highlightScroll}px;`
|
|
208
|
-
: undefined}
|
|
209
|
-
aria-hidden="true"
|
|
210
|
-
>
|
|
211
|
-
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
|
|
212
|
-
{@html highlighted}
|
|
213
|
-
</div>
|
|
214
|
-
|
|
215
|
-
<textarea
|
|
216
|
-
bind:this={textareaEl}
|
|
217
|
-
bind:value={code}
|
|
218
|
-
onscroll={syncScroll}
|
|
219
|
-
oninput={editable ? updateActiveLine : undefined}
|
|
220
|
-
onkeyup={editable ? updateActiveLine : undefined}
|
|
221
|
-
onclick={editable ? updateActiveLine : undefined}
|
|
222
|
-
onmouseup={editable ? updateActiveLine : undefined}
|
|
223
|
-
onfocus={editable ? updateActiveLine : undefined}
|
|
224
|
-
spellcheck="false"
|
|
225
|
-
readonly={!editable}
|
|
226
|
-
class={cx("cv-input cv-layer", TEXT[sz], LINE_HEIGHT[sz])}
|
|
227
|
-
></textarea>
|
|
228
|
-
</div>
|
|
229
|
-
</div>
|
|
230
|
-
</div>
|
|
231
|
-
|
|
232
|
-
<style>
|
|
233
|
-
.cv-layer {
|
|
234
|
-
position: absolute;
|
|
235
|
-
padding: 12px;
|
|
236
|
-
white-space: pre;
|
|
237
|
-
box-sizing: border-box;
|
|
238
|
-
font: inherit;
|
|
239
|
-
line-height: inherit;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
.cv-highlight {
|
|
243
|
-
--cv-active-color: color-mix(
|
|
244
|
-
in oklab,
|
|
245
|
-
var(--color-text-default) 16%,
|
|
246
|
-
transparent
|
|
247
|
-
);
|
|
248
|
-
inset: 0;
|
|
249
|
-
overflow: auto;
|
|
250
|
-
pointer-events: none;
|
|
251
|
-
color: var(--color-text-default);
|
|
252
|
-
background: transparent;
|
|
253
|
-
padding-bottom: 100px;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
.cv-active-line {
|
|
257
|
-
background-image: linear-gradient(
|
|
258
|
-
var(--cv-active-color),
|
|
259
|
-
var(--cv-active-color)
|
|
260
|
-
);
|
|
261
|
-
background-repeat: no-repeat;
|
|
262
|
-
background-size: 100% var(--cv-line-height);
|
|
263
|
-
background-position: 0 var(--cv-active-line-top);
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
.cv-input {
|
|
267
|
-
inset: 0;
|
|
268
|
-
color: transparent;
|
|
269
|
-
caret-color: var(--color-text-default);
|
|
270
|
-
outline: none;
|
|
271
|
-
resize: none;
|
|
272
|
-
overflow: auto;
|
|
273
|
-
border: none;
|
|
274
|
-
box-sizing: border-box;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
.cv-input:focus {
|
|
278
|
-
outline: none;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
.cv-input:focus-visible {
|
|
282
|
-
outline: none !important;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
/* Prism */
|
|
286
|
-
.token.comment {
|
|
287
|
-
color: oklch(0.937 0.019 256 / 0.45);
|
|
288
|
-
}
|
|
289
|
-
.token.punctuation {
|
|
290
|
-
color: oklch(0.726 0.051 239);
|
|
291
|
-
}
|
|
292
|
-
.token.tag {
|
|
293
|
-
color: oklch(0.725 0.192 338);
|
|
294
|
-
}
|
|
295
|
-
.token.attr-name {
|
|
296
|
-
color: oklch(0.747 0.157 254);
|
|
297
|
-
}
|
|
298
|
-
.token.attr-value {
|
|
299
|
-
color: oklch(0.835 0.181 139);
|
|
300
|
-
}
|
|
301
|
-
.token.string {
|
|
302
|
-
color: oklch(0.835 0.181 139);
|
|
303
|
-
}
|
|
304
|
-
.token.keyword {
|
|
305
|
-
color: oklch(0.701 0.206 27);
|
|
306
|
-
}
|
|
307
|
-
</style>
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @component CodeView
|
|
3
|
-
* @description CodeView is a small prism.js powered code block that supports syntax highlighting, optional editing, line numbers and active-line highlighting.
|
|
4
|
-
*
|
|
5
|
-
* @prop code {string} - Code content to render
|
|
6
|
-
* @default ""
|
|
7
|
-
*
|
|
8
|
-
* @prop language {Language} - Syntax highlighting language
|
|
9
|
-
* @options txt|html|css|js|json|python
|
|
10
|
-
* @default "txt"
|
|
11
|
-
*
|
|
12
|
-
* @prop title {string} - Title displayed above the code block
|
|
13
|
-
* @default "Code"
|
|
14
|
-
*
|
|
15
|
-
* @prop showCopyButton {boolean} - Shows the copy-to-clipboard button
|
|
16
|
-
* @default true
|
|
17
|
-
*
|
|
18
|
-
* @prop showLineNumbers {boolean} - Displays line numbers alongside the code
|
|
19
|
-
* @default false
|
|
20
|
-
*
|
|
21
|
-
* @prop editable {boolean} - Enables editable mode with a textarea overlay
|
|
22
|
-
* @default false
|
|
23
|
-
*
|
|
24
|
-
* @prop activeLine {boolean} - Highlights the current cursor line in editable mode
|
|
25
|
-
* @default false
|
|
26
|
-
*
|
|
27
|
-
* @prop sz {SizeKey} - Size preset affecting spacing and typography
|
|
28
|
-
* @options xs|sm|md|lg|xl
|
|
29
|
-
* @default md
|
|
30
|
-
*
|
|
31
|
-
* @prop class {string} - Extra classes applied to the root container
|
|
32
|
-
* @default ""
|
|
33
|
-
*
|
|
34
|
-
* @note Uses Prism for syntax highlighting; HTML/CSS/TXT grammars are bundled by default.
|
|
35
|
-
* @note Editable mode renders a transparent textarea above a highlighted code layer, mirroring real editors.
|
|
36
|
-
* @note Cursor-line highlight is overlaid using CSS variables and scroll-position tracking.
|
|
37
|
-
* @note Line numbers are fully scroll-synchronized with the editor content.
|
|
38
|
-
* @note Readonly mode shows static highlighted code, without textarea.
|
|
39
|
-
* @note Copy button writes the full code string to the clipboard.
|
|
40
|
-
* @note All sizing and spacing scale automatically with the shared `sz` token.
|
|
41
|
-
* @note Supports dark/light themes via existing design-token colors.
|
|
42
|
-
* @note Designed as a low-level editor component, not a full IDE replacement.
|
|
43
|
-
*/
|
|
44
|
-
import { type SizeKey, type Language } from "./types";
|
|
45
|
-
import "prismjs/components/prism-markup";
|
|
46
|
-
import "prismjs/components/prism-css";
|
|
47
|
-
import "prismjs/components/prism-javascript";
|
|
48
|
-
import "prismjs/components/prism-json";
|
|
49
|
-
import "prismjs/components/prism-python";
|
|
50
|
-
import "prismjs/themes/prism.css";
|
|
51
|
-
type Props = {
|
|
52
|
-
code?: string;
|
|
53
|
-
language?: Language;
|
|
54
|
-
title?: string;
|
|
55
|
-
showCopyButton?: boolean;
|
|
56
|
-
showLineNumbers?: boolean;
|
|
57
|
-
editable?: boolean;
|
|
58
|
-
activeLine?: boolean;
|
|
59
|
-
sz?: SizeKey;
|
|
60
|
-
class?: string;
|
|
61
|
-
};
|
|
62
|
-
declare const CodeView: import("svelte").Component<Props, {}, "code">;
|
|
63
|
-
type CodeView = ReturnType<typeof CodeView>;
|
|
64
|
-
export default CodeView;
|
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
<!-- src/lib/ColorPicker.svelte -->
|
|
2
|
-
<script lang="ts">
|
|
3
|
-
/**
|
|
4
|
-
* @component ColorPicker
|
|
5
|
-
* @description Accessible wrapper around the native `<input type="color">` with a trigger button and preview card.
|
|
6
|
-
*
|
|
7
|
-
* @prop value {string | null} - Selected color value (hex)
|
|
8
|
-
* @default null
|
|
9
|
-
*
|
|
10
|
-
* @prop label {string} - Label displayed above the control
|
|
11
|
-
*
|
|
12
|
-
* @prop placeholder {string} - Placeholder text when no color is chosen
|
|
13
|
-
*
|
|
14
|
-
* @prop disabled {boolean} - Disables all interactions
|
|
15
|
-
* @default false
|
|
16
|
-
*
|
|
17
|
-
* @prop clearable {boolean} - Shows a clear/reset button
|
|
18
|
-
* @default true
|
|
19
|
-
*
|
|
20
|
-
* @prop onChange {(value: string | null) => void} - Fired when the color changes
|
|
21
|
-
*
|
|
22
|
-
* @prop class {string} - Additional classes for the wrapper element
|
|
23
|
-
* @default ""
|
|
24
|
-
*
|
|
25
|
-
* @note Uses the new `HTMLInputElement.showPicker()` API when available; falls back to focusing/clicking the hidden input.
|
|
26
|
-
* @note Keeps the hidden color input in sync with controlled `value` through `$effect`.
|
|
27
|
-
* @note Preview swatch mirrors the current color and announces via `aria-label`.
|
|
28
|
-
* @note `clearable=false` hides the clear button; when `disabled`, pointer/keyboard handlers are skipped.
|
|
29
|
-
*/
|
|
30
|
-
import type { HTMLAttributes } from "svelte/elements";
|
|
31
|
-
import { getContext } from "svelte";
|
|
32
|
-
import Button from "./Button.svelte";
|
|
33
|
-
import { cx } from "../utils";
|
|
34
|
-
import { TEXTS } from "./lang";
|
|
35
|
-
|
|
36
|
-
type Props = HTMLAttributes<HTMLDivElement> & {
|
|
37
|
-
value?: string | null;
|
|
38
|
-
label?: string;
|
|
39
|
-
placeholder?: string;
|
|
40
|
-
disabled?: boolean;
|
|
41
|
-
clearable?: boolean;
|
|
42
|
-
onChange?: (value: string | null) => void;
|
|
43
|
-
class?: string;
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
let {
|
|
47
|
-
value = $bindable<string | null>(null),
|
|
48
|
-
label,
|
|
49
|
-
placeholder,
|
|
50
|
-
disabled = false,
|
|
51
|
-
clearable = true,
|
|
52
|
-
onChange,
|
|
53
|
-
class: externalClass = "",
|
|
54
|
-
...rest
|
|
55
|
-
}: Props = $props();
|
|
56
|
-
|
|
57
|
-
const langCtx =
|
|
58
|
-
getContext<{ value: keyof typeof TEXTS } | undefined>("lang") ?? null;
|
|
59
|
-
const langKey = $derived(langCtx?.value ?? "en");
|
|
60
|
-
const L = $derived(TEXTS[langKey].components.colorPicker);
|
|
61
|
-
|
|
62
|
-
const labelFinal = $derived(label ?? L.text);
|
|
63
|
-
const placeholderFinal = $derived(placeholder ?? L.placeholder);
|
|
64
|
-
|
|
65
|
-
let inputEl: HTMLInputElement;
|
|
66
|
-
|
|
67
|
-
const base = "inline-block w-full";
|
|
68
|
-
const pickerClass = $derived(cx(base, externalClass));
|
|
69
|
-
|
|
70
|
-
const hasValue = $derived(Boolean(value));
|
|
71
|
-
const previewColor = $derived(value ?? "transparent");
|
|
72
|
-
|
|
73
|
-
$effect(() => {
|
|
74
|
-
if (inputEl) {
|
|
75
|
-
inputEl.value = value || "#000000";
|
|
76
|
-
}
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
function openPicker() {
|
|
80
|
-
if (disabled) return;
|
|
81
|
-
if (typeof inputEl?.showPicker === "function") {
|
|
82
|
-
inputEl.showPicker();
|
|
83
|
-
} else {
|
|
84
|
-
inputEl?.focus();
|
|
85
|
-
inputEl?.click();
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function handleInput(event: Event) {
|
|
90
|
-
const target = event.target as HTMLInputElement;
|
|
91
|
-
const nextValue = target.value || null;
|
|
92
|
-
value = nextValue;
|
|
93
|
-
onChange?.(nextValue);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function clearSelection() {
|
|
97
|
-
if (!clearable) return;
|
|
98
|
-
value = null;
|
|
99
|
-
if (inputEl) {
|
|
100
|
-
inputEl.value = "#000000";
|
|
101
|
-
}
|
|
102
|
-
onChange?.(null);
|
|
103
|
-
}
|
|
104
|
-
</script>
|
|
105
|
-
|
|
106
|
-
<div class={pickerClass} {...rest}>
|
|
107
|
-
<div class="text-md font-medium mb-2 [color:var(--color-text-default)]">
|
|
108
|
-
{labelFinal}:
|
|
109
|
-
</div>
|
|
110
|
-
<div class="flex flex-wrap items-center gap-x-3 gap-y-2">
|
|
111
|
-
<Button onClick={openPicker} {disabled} sz="xs">
|
|
112
|
-
{L.color}
|
|
113
|
-
</Button>
|
|
114
|
-
|
|
115
|
-
{#if clearable}
|
|
116
|
-
<Button
|
|
117
|
-
onClick={clearSelection}
|
|
118
|
-
variant="danger"
|
|
119
|
-
disabled={!hasValue || disabled}
|
|
120
|
-
sz="xs"
|
|
121
|
-
>
|
|
122
|
-
{L.clear}
|
|
123
|
-
</Button>
|
|
124
|
-
{/if}
|
|
125
|
-
</div>
|
|
126
|
-
|
|
127
|
-
<input
|
|
128
|
-
bind:this={inputEl}
|
|
129
|
-
type="color"
|
|
130
|
-
{disabled}
|
|
131
|
-
class="invisible absolute w-px h-px"
|
|
132
|
-
onchange={handleInput}
|
|
133
|
-
value="#000000"
|
|
134
|
-
/>
|
|
135
|
-
|
|
136
|
-
<div
|
|
137
|
-
class="mt-3 p-4 border border-dashed border-[var(--border-color-default)] rounded-[var(--radius-md)] bg-[var(--color-bg-surface)] flex items-center justify-between gap-3"
|
|
138
|
-
aria-live="polite"
|
|
139
|
-
>
|
|
140
|
-
<div>
|
|
141
|
-
<p
|
|
142
|
-
class="text-xs uppercase tracking-wide [color:var(--color-text-muted)]"
|
|
143
|
-
>
|
|
144
|
-
{L.selectedColor}
|
|
145
|
-
</p>
|
|
146
|
-
<p class="text-sm font-semibold mt-1 [color:var(--color-text-default)]">
|
|
147
|
-
{#if hasValue}
|
|
148
|
-
{value}
|
|
149
|
-
{:else}
|
|
150
|
-
{placeholderFinal}
|
|
151
|
-
{/if}
|
|
152
|
-
</p>
|
|
153
|
-
</div>
|
|
154
|
-
|
|
155
|
-
<div
|
|
156
|
-
class="w-12 h-12 rounded-[var(--radius-sm)] border border-[var(--border-color-default)] shadow-inner"
|
|
157
|
-
aria-label={hasValue ? `Preview of ${value}` : "No color selected"}
|
|
158
|
-
style={`background:${previewColor}`}
|
|
159
|
-
></div>
|
|
160
|
-
</div>
|
|
161
|
-
</div>
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @component ColorPicker
|
|
3
|
-
* @description Accessible wrapper around the native `<input type="color">` with a trigger button and preview card.
|
|
4
|
-
*
|
|
5
|
-
* @prop value {string | null} - Selected color value (hex)
|
|
6
|
-
* @default null
|
|
7
|
-
*
|
|
8
|
-
* @prop label {string} - Label displayed above the control
|
|
9
|
-
*
|
|
10
|
-
* @prop placeholder {string} - Placeholder text when no color is chosen
|
|
11
|
-
*
|
|
12
|
-
* @prop disabled {boolean} - Disables all interactions
|
|
13
|
-
* @default false
|
|
14
|
-
*
|
|
15
|
-
* @prop clearable {boolean} - Shows a clear/reset button
|
|
16
|
-
* @default true
|
|
17
|
-
*
|
|
18
|
-
* @prop onChange {(value: string | null) => void} - Fired when the color changes
|
|
19
|
-
*
|
|
20
|
-
* @prop class {string} - Additional classes for the wrapper element
|
|
21
|
-
* @default ""
|
|
22
|
-
*
|
|
23
|
-
* @note Uses the new `HTMLInputElement.showPicker()` API when available; falls back to focusing/clicking the hidden input.
|
|
24
|
-
* @note Keeps the hidden color input in sync with controlled `value` through `$effect`.
|
|
25
|
-
* @note Preview swatch mirrors the current color and announces via `aria-label`.
|
|
26
|
-
* @note `clearable=false` hides the clear button; when `disabled`, pointer/keyboard handlers are skipped.
|
|
27
|
-
*/
|
|
28
|
-
import type { HTMLAttributes } from "svelte/elements";
|
|
29
|
-
type Props = HTMLAttributes<HTMLDivElement> & {
|
|
30
|
-
value?: string | null;
|
|
31
|
-
label?: string;
|
|
32
|
-
placeholder?: string;
|
|
33
|
-
disabled?: boolean;
|
|
34
|
-
clearable?: boolean;
|
|
35
|
-
onChange?: (value: string | null) => void;
|
|
36
|
-
class?: string;
|
|
37
|
-
};
|
|
38
|
-
declare const ColorPicker: import("svelte").Component<Props, {}, "value">;
|
|
39
|
-
type ColorPicker = ReturnType<typeof ColorPicker>;
|
|
40
|
-
export default ColorPicker;
|