@urbicon-ui/blocks 6.34.0 → 6.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/README.md +11 -1
- package/dist/components/Calendar/CalendarHeader.svelte +32 -26
- package/dist/components/Calendar/CalendarMiniMonth.svelte +10 -10
- package/dist/components/Calendar/calendar.variants.js +19 -5
- package/dist/components/Chat/Chat/Chat.svelte +53 -0
- package/dist/components/Chat/Chat/Chat.svelte.d.ts +4 -0
- package/dist/components/Chat/Chat/chat.variants.d.ts +20 -0
- package/dist/components/Chat/Chat/chat.variants.js +15 -0
- package/dist/components/Chat/Chat/index.d.ts +47 -0
- package/dist/components/Chat/Chat/index.js +2 -0
- package/dist/components/Chat/ChatMessage/ChatMessage.svelte +342 -0
- package/dist/components/Chat/ChatMessage/ChatMessage.svelte.d.ts +4 -0
- package/dist/components/Chat/ChatMessage/chat-message.variants.d.ts +138 -0
- package/dist/components/Chat/ChatMessage/chat-message.variants.js +118 -0
- package/dist/components/Chat/ChatMessage/index.d.ts +102 -0
- package/dist/components/Chat/ChatMessage/index.js +2 -0
- package/dist/components/Chat/ChatMessageList/ChatMessageList.svelte +301 -0
- package/dist/components/Chat/ChatMessageList/ChatMessageList.svelte.d.ts +6 -0
- package/dist/components/Chat/ChatMessageList/chat-message-list.variants.d.ts +23 -0
- package/dist/components/Chat/ChatMessageList/chat-message-list.variants.js +32 -0
- package/dist/components/Chat/ChatMessageList/chat-scroll.d.ts +45 -0
- package/dist/components/Chat/ChatMessageList/chat-scroll.js +52 -0
- package/dist/components/Chat/ChatMessageList/index.d.ts +93 -0
- package/dist/components/Chat/ChatMessageList/index.js +3 -0
- package/dist/components/Chat/CitationChip/CitationChip.svelte +107 -0
- package/dist/components/Chat/CitationChip/CitationChip.svelte.d.ts +4 -0
- package/dist/components/Chat/CitationChip/citation-chip.variants.d.ts +40 -0
- package/dist/components/Chat/CitationChip/citation-chip.variants.js +42 -0
- package/dist/components/Chat/CitationChip/index.d.ts +69 -0
- package/dist/components/Chat/CitationChip/index.js +2 -0
- package/dist/components/Chat/CodeBlock/CodeBlock.svelte +120 -0
- package/dist/components/Chat/CodeBlock/CodeBlock.svelte.d.ts +4 -0
- package/dist/components/Chat/CodeBlock/code-block.variants.d.ts +40 -0
- package/dist/components/Chat/CodeBlock/code-block.variants.js +51 -0
- package/dist/components/Chat/CodeBlock/index.d.ts +55 -0
- package/dist/components/Chat/CodeBlock/index.js +2 -0
- package/dist/components/Chat/PromptInput/PromptInput.svelte +432 -0
- package/dist/components/Chat/PromptInput/PromptInput.svelte.d.ts +4 -0
- package/dist/components/Chat/PromptInput/index.d.ts +165 -0
- package/dist/components/Chat/PromptInput/index.js +2 -0
- package/dist/components/Chat/PromptInput/prompt-input.variants.d.ts +90 -0
- package/dist/components/Chat/PromptInput/prompt-input.variants.js +102 -0
- package/dist/components/Chat/ReasoningDisclosure/ReasoningDisclosure.svelte +107 -0
- package/dist/components/Chat/ReasoningDisclosure/ReasoningDisclosure.svelte.d.ts +4 -0
- package/dist/components/Chat/ReasoningDisclosure/index.d.ts +85 -0
- package/dist/components/Chat/ReasoningDisclosure/index.js +2 -0
- package/dist/components/Chat/ReasoningDisclosure/reasoning-disclosure.variants.d.ts +20 -0
- package/dist/components/Chat/ReasoningDisclosure/reasoning-disclosure.variants.js +31 -0
- package/dist/components/Chat/StreamingMarkdown/MdBlock.svelte +99 -0
- package/dist/components/Chat/StreamingMarkdown/MdBlock.svelte.d.ts +9 -0
- package/dist/components/Chat/StreamingMarkdown/MdInline.svelte +82 -0
- package/dist/components/Chat/StreamingMarkdown/MdInline.svelte.d.ts +9 -0
- package/dist/components/Chat/StreamingMarkdown/StreamingMarkdown.svelte +118 -0
- package/dist/components/Chat/StreamingMarkdown/StreamingMarkdown.svelte.d.ts +4 -0
- package/dist/components/Chat/StreamingMarkdown/index.d.ts +86 -0
- package/dist/components/Chat/StreamingMarkdown/index.js +2 -0
- package/dist/components/Chat/StreamingMarkdown/md-context.d.ts +58 -0
- package/dist/components/Chat/StreamingMarkdown/md-context.js +1 -0
- package/dist/components/Chat/StreamingMarkdown/streaming-markdown.variants.d.ts +145 -0
- package/dist/components/Chat/StreamingMarkdown/streaming-markdown.variants.js +73 -0
- package/dist/components/Chat/ToolCallCard/ToolCallCard.svelte +174 -0
- package/dist/components/Chat/ToolCallCard/ToolCallCard.svelte.d.ts +4 -0
- package/dist/components/Chat/ToolCallCard/index.d.ts +84 -0
- package/dist/components/Chat/ToolCallCard/index.js +2 -0
- package/dist/components/Chat/ToolCallCard/tool-call-card.variants.d.ts +38 -0
- package/dist/components/Chat/ToolCallCard/tool-call-card.variants.js +38 -0
- package/dist/components/Chat/chat.types.d.ts +82 -0
- package/dist/components/Chat/chat.types.js +7 -0
- package/dist/components/Chat/index.d.ts +22 -0
- package/dist/components/Chat/index.js +14 -0
- package/dist/components/Chat/markdown/blocks.d.ts +54 -0
- package/dist/components/Chat/markdown/blocks.js +462 -0
- package/dist/components/Chat/markdown/inline.d.ts +31 -0
- package/dist/components/Chat/markdown/inline.js +446 -0
- package/dist/components/Chat/markdown/repair.d.ts +23 -0
- package/dist/components/Chat/markdown/repair.js +337 -0
- package/dist/components/Chat/markdown/streaming-harness.d.ts +23 -0
- package/dist/components/Chat/markdown/streaming-harness.js +62 -0
- package/dist/components/Chat/markdown/types.d.ts +139 -0
- package/dist/components/Chat/markdown/types.js +13 -0
- package/dist/components/Chat/markdown/url-policy.d.ts +33 -0
- package/dist/components/Chat/markdown/url-policy.js +109 -0
- package/dist/components/FileUpload/FileUpload.svelte +52 -125
- package/dist/components/FileUpload/FileUpload.svelte.d.ts +1 -1
- package/dist/components/FileUpload/index.d.ts +2 -28
- package/dist/components/Planner/PlannerHeader.svelte +16 -13
- package/dist/components/Planner/planner.variants.js +14 -3
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.js +1 -0
- package/dist/i18n/index.d.ts +268 -382
- package/dist/i18n/index.js +83 -9
- package/dist/internal/core/CoreIconButton.svelte +66 -0
- package/dist/internal/core/CoreIconButton.svelte.d.ts +13 -0
- package/dist/internal/core/CoreSpinner.svelte +49 -0
- package/dist/internal/core/CoreSpinner.svelte.d.ts +8 -0
- package/dist/internal/core/spinner-geometry.d.ts +6 -0
- package/dist/internal/core/spinner-geometry.js +6 -0
- package/dist/mint/registry.d.ts +20 -2
- package/dist/mint/registry.js +20 -2
- package/dist/primitives/Badge/Badge.svelte +5 -5
- package/dist/primitives/Badge/badge.variants.js +17 -1
- package/dist/primitives/Button/Button.svelte +4 -2
- package/dist/primitives/Collapsible/Collapsible.svelte +5 -0
- package/dist/primitives/Dialog/Dialog.svelte +7 -5
- package/dist/primitives/Dialog/dialog.variants.d.ts +7 -0
- package/dist/primitives/Dialog/dialog.variants.js +17 -0
- package/dist/primitives/Drawer/Drawer.svelte +7 -5
- package/dist/primitives/Drawer/drawer.variants.d.ts +8 -0
- package/dist/primitives/Drawer/drawer.variants.js +17 -0
- package/dist/primitives/Spinner/Spinner.svelte +3 -1
- package/dist/primitives/SplitPane/SplitPane.svelte +293 -0
- package/dist/primitives/SplitPane/SplitPane.svelte.d.ts +4 -0
- package/dist/primitives/SplitPane/index.d.ts +88 -0
- package/dist/primitives/SplitPane/index.js +2 -0
- package/dist/primitives/SplitPane/split-pane.utils.d.ts +73 -0
- package/dist/primitives/SplitPane/split-pane.utils.js +94 -0
- package/dist/primitives/SplitPane/split-pane.variants.d.ts +40 -0
- package/dist/primitives/SplitPane/split-pane.variants.js +56 -0
- package/dist/primitives/Toast/Toaster.svelte +17 -2
- package/dist/primitives/index.d.ts +2 -0
- package/dist/primitives/index.js +1 -0
- package/dist/utils/file-intake.d.ts +78 -0
- package/dist/utils/file-intake.js +144 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/variants.js +44 -10
- package/package.json +4 -6
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
import WarningTriangleIconDefault from '../../icons/WarningTriangleIcon.svelte';
|
|
13
13
|
import DangerCircleIconDefault from '../../icons/DangerCircleIcon.svelte';
|
|
14
14
|
import { getBlocksConfig, resolveSlotClasses } from '../../provider';
|
|
15
|
-
import
|
|
15
|
+
// internal core, not the public component — keeps the public-to-public import graph clean (see internal/core/)
|
|
16
|
+
import CoreSpinner from '../../internal/core/CoreSpinner.svelte';
|
|
16
17
|
import type { ToastData, ToastProps } from './index';
|
|
17
18
|
|
|
18
19
|
const bt = useBlocksI18n();
|
|
@@ -220,7 +221,21 @@
|
|
|
220
221
|
transition:fly={flyParams()}
|
|
221
222
|
>
|
|
222
223
|
{#if toast.loading}
|
|
223
|
-
|
|
224
|
+
<!--
|
|
225
|
+
CoreSpinner instead of the public Spinner (see internal/core/).
|
|
226
|
+
Deliberate a11y delta: the old embedded Spinner emitted role="status" +
|
|
227
|
+
aria-live + an sr-only "Loading..." label — a live region NESTED inside
|
|
228
|
+
the toast's own role="alert" region. The core emits no semantics; the
|
|
229
|
+
toast region owns the announcement. `text-primary` pins the old look:
|
|
230
|
+
the public Spinner's intent DEFAULTED to primary, so the loading glyph
|
|
231
|
+
always rendered primary regardless of the toast intent (whether it
|
|
232
|
+
should follow the intent instead is logged in technical-debt.md). It
|
|
233
|
+
wins the color duel against the core's `text-current` by stylesheet
|
|
234
|
+
order (theme color utilities sort after keyword colors).
|
|
235
|
+
-->
|
|
236
|
+
<span class={slot('icon', toast.intent)}
|
|
237
|
+
><CoreSpinner size="sm" class="text-primary" /></span
|
|
238
|
+
>
|
|
224
239
|
{:else}
|
|
225
240
|
<IntentIcon class={slot('icon', toast.intent)} />
|
|
226
241
|
{/if}
|
|
@@ -55,6 +55,8 @@ export type { SliderMark, SliderProps } from './Slider/index.js';
|
|
|
55
55
|
export * from './Slider/index.js';
|
|
56
56
|
export type { SpinnerProps } from './Spinner/index.js';
|
|
57
57
|
export * from './Spinner/index.js';
|
|
58
|
+
export type { SplitPaneProps } from './SplitPane/index.js';
|
|
59
|
+
export * from './SplitPane/index.js';
|
|
58
60
|
export type { StepperProps, StepperStepProps } from './Stepper/index.js';
|
|
59
61
|
export * from './Stepper/index.js';
|
|
60
62
|
export type { TabItemProps, TabPanelProps, TabProps } from './Tab/index.js';
|
package/dist/primitives/index.js
CHANGED
|
@@ -29,6 +29,7 @@ export * from './Sidebar/index.js';
|
|
|
29
29
|
export * from './Skeleton/index.js';
|
|
30
30
|
export * from './Slider/index.js';
|
|
31
31
|
export * from './Spinner/index.js';
|
|
32
|
+
export * from './SplitPane/index.js';
|
|
32
33
|
export * from './Stepper/index.js';
|
|
33
34
|
export * from './Tab/index.js';
|
|
34
35
|
export * from './Textarea/index.js';
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
export type FileIntakeErrorCode = 'FILE_INVALID_TYPE' | 'FILE_TOO_LARGE' | 'FILE_TOO_SMALL' | 'TOO_MANY_FILES' | 'FILE_EXISTS' | 'CUSTOM';
|
|
2
|
+
export interface FileIntakeError {
|
|
3
|
+
/** Machine-readable error code. */
|
|
4
|
+
code: FileIntakeErrorCode;
|
|
5
|
+
/** Human-readable error message. */
|
|
6
|
+
message: string;
|
|
7
|
+
}
|
|
8
|
+
export type FileIntakeStatus = 'pending' | 'uploading' | 'complete' | 'error';
|
|
9
|
+
export interface FileIntakeEntry {
|
|
10
|
+
/** Unique identifier for this file entry. */
|
|
11
|
+
id: string;
|
|
12
|
+
/** The native File object. */
|
|
13
|
+
file: File;
|
|
14
|
+
/** Object URL for image previews (auto-generated, auto-revoked). */
|
|
15
|
+
preview?: string;
|
|
16
|
+
/** Upload progress 0–100. Undefined when not tracking. */
|
|
17
|
+
progress?: number;
|
|
18
|
+
/** Current lifecycle status. */
|
|
19
|
+
status: FileIntakeStatus;
|
|
20
|
+
/** Validation or upload errors. */
|
|
21
|
+
errors: FileIntakeError[];
|
|
22
|
+
}
|
|
23
|
+
export interface FileIntakeRejection {
|
|
24
|
+
/** The rejected file. */
|
|
25
|
+
file: File;
|
|
26
|
+
/** Why it was rejected. */
|
|
27
|
+
errors: FileIntakeError[];
|
|
28
|
+
}
|
|
29
|
+
/** Validation limits shared by every intake surface. */
|
|
30
|
+
export interface FileIntakeConstraints {
|
|
31
|
+
/** Accepted MIME types or file extensions (e.g. 'image/*', '.pdf'). */
|
|
32
|
+
accept?: string | string[];
|
|
33
|
+
/** Maximum number of files across the whole list. */
|
|
34
|
+
maxFiles?: number;
|
|
35
|
+
/** Maximum file size in bytes. */
|
|
36
|
+
maxFileSize?: number;
|
|
37
|
+
/** Minimum file size in bytes. */
|
|
38
|
+
minFileSize?: number;
|
|
39
|
+
/** Custom validation function. Return errors array or null. */
|
|
40
|
+
validate?: (file: File) => FileIntakeError[] | null;
|
|
41
|
+
}
|
|
42
|
+
/** Error-text factories — components inject their i18n/label source here. */
|
|
43
|
+
export interface FileIntakeMessages {
|
|
44
|
+
invalidType: (type: string) => string;
|
|
45
|
+
tooLarge: (formattedSize: string) => string;
|
|
46
|
+
tooSmall: (formattedSize: string) => string;
|
|
47
|
+
exists: () => string;
|
|
48
|
+
tooMany: (count: number) => string;
|
|
49
|
+
}
|
|
50
|
+
/** Does a picked/dropped file match the accept spec (`.ext`, `type/*`, exact MIME)? */
|
|
51
|
+
export declare function matchesAccept(file: File, accept: string | string[] | undefined): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Dragged-over feedback: do ALL items look acceptable? Extension patterns
|
|
54
|
+
* (`.pdf`) match permissively — file names are unavailable during dragenter,
|
|
55
|
+
* so a definitive verdict only exists for MIME patterns.
|
|
56
|
+
*/
|
|
57
|
+
export declare function dragItemsMatchAccept(items: Iterable<DataTransferItem>, accept: string | string[] | undefined): boolean;
|
|
58
|
+
/** Validate one file against the constraints and the existing list (duplicates). */
|
|
59
|
+
export declare function validateIntakeFile(file: File, existing: readonly FileIntakeEntry[], constraints: FileIntakeConstraints, messages: FileIntakeMessages): FileIntakeError[];
|
|
60
|
+
/**
|
|
61
|
+
* Split incoming files into accepted entries (id + pending status + image
|
|
62
|
+
* preview object-URL) and rejections. Files beyond the remaining `maxFiles`
|
|
63
|
+
* budget are rejected with `TOO_MANY_FILES` before any validation runs.
|
|
64
|
+
* The caller owns the returned entries — including revoking their previews
|
|
65
|
+
* (`revokeIntakePreviews`) when they leave the list.
|
|
66
|
+
*/
|
|
67
|
+
export declare function partitionIntake(incoming: readonly File[], existing: readonly FileIntakeEntry[], constraints: FileIntakeConstraints, messages: FileIntakeMessages, idPrefix?: string): {
|
|
68
|
+
accepted: FileIntakeEntry[];
|
|
69
|
+
rejected: FileIntakeRejection[];
|
|
70
|
+
};
|
|
71
|
+
/** Wrap a (pre-validated) file as a pending entry with id and image preview. */
|
|
72
|
+
export declare function createIntakeEntry(file: File, idPrefix?: string): FileIntakeEntry;
|
|
73
|
+
/** Revoke the preview object-URLs of the given entries (removal/teardown). */
|
|
74
|
+
export declare function revokeIntakePreviews(entries: Iterable<FileIntakeEntry>): void;
|
|
75
|
+
/** Human-readable file size (`1.5 MB`). Empty string for non-finite values. */
|
|
76
|
+
export declare function formatFileSize(bytes: number): string;
|
|
77
|
+
/** Is this file an image (drives preview object-URL creation)? */
|
|
78
|
+
export declare function isImageFile(file: File): boolean;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// Shared file-intake core — the pure logic behind FileUpload's dropzone and
|
|
2
|
+
// PromptInput's attachment strip: accept matching, validation, accepted/
|
|
3
|
+
// rejected partitioning, preview object-URL lifecycle, size formatting.
|
|
4
|
+
//
|
|
5
|
+
// Deliberately stateless functions, not a store class: both consumers keep
|
|
6
|
+
// their own `$state`/`$bindable` file lists (FileUpload's `bind:files` must
|
|
7
|
+
// stay the single source of truth there), and pure functions are node-testable
|
|
8
|
+
// without a DOM. Error texts are injected via `FileIntakeMessages` so each
|
|
9
|
+
// component keeps its own i18n/label wiring.
|
|
10
|
+
// ── Accept matching ──────────────────────────────────────────────────────────
|
|
11
|
+
function acceptList(accept) {
|
|
12
|
+
return Array.isArray(accept) ? accept : accept.split(',').map((t) => t.trim());
|
|
13
|
+
}
|
|
14
|
+
/** Does a picked/dropped file match the accept spec (`.ext`, `type/*`, exact MIME)? */
|
|
15
|
+
export function matchesAccept(file, accept) {
|
|
16
|
+
if (!accept)
|
|
17
|
+
return true;
|
|
18
|
+
return acceptList(accept).some((type) => {
|
|
19
|
+
if (type.startsWith('.'))
|
|
20
|
+
return file.name.toLowerCase().endsWith(type.toLowerCase());
|
|
21
|
+
if (type.endsWith('/*'))
|
|
22
|
+
return file.type.startsWith(type.replace('/*', '/'));
|
|
23
|
+
return file.type === type;
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Dragged-over feedback: do ALL items look acceptable? Extension patterns
|
|
28
|
+
* (`.pdf`) match permissively — file names are unavailable during dragenter,
|
|
29
|
+
* so a definitive verdict only exists for MIME patterns.
|
|
30
|
+
*/
|
|
31
|
+
export function dragItemsMatchAccept(items, accept) {
|
|
32
|
+
if (!accept)
|
|
33
|
+
return true;
|
|
34
|
+
const types = acceptList(accept);
|
|
35
|
+
return Array.from(items).every((item) => {
|
|
36
|
+
if (item.kind !== 'file')
|
|
37
|
+
return false;
|
|
38
|
+
return types.some((type) => {
|
|
39
|
+
if (type.endsWith('/*'))
|
|
40
|
+
return item.type.startsWith(type.replace('/*', '/'));
|
|
41
|
+
if (type.startsWith('.'))
|
|
42
|
+
return true;
|
|
43
|
+
return item.type === type;
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
// ── Validation & partitioning ────────────────────────────────────────────────
|
|
48
|
+
/** Validate one file against the constraints and the existing list (duplicates). */
|
|
49
|
+
export function validateIntakeFile(file, existing, constraints, messages) {
|
|
50
|
+
const errors = [];
|
|
51
|
+
const { accept, maxFileSize = Infinity, minFileSize = 0, validate } = constraints;
|
|
52
|
+
if (accept && !matchesAccept(file, accept)) {
|
|
53
|
+
errors.push({
|
|
54
|
+
code: 'FILE_INVALID_TYPE',
|
|
55
|
+
message: messages.invalidType(file.type || 'unknown')
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
if (file.size > maxFileSize) {
|
|
59
|
+
errors.push({
|
|
60
|
+
code: 'FILE_TOO_LARGE',
|
|
61
|
+
message: messages.tooLarge(formatFileSize(maxFileSize))
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
if (file.size < minFileSize) {
|
|
65
|
+
errors.push({
|
|
66
|
+
code: 'FILE_TOO_SMALL',
|
|
67
|
+
message: messages.tooSmall(formatFileSize(minFileSize))
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
if (existing.some((f) => f.file.name === file.name && f.file.size === file.size)) {
|
|
71
|
+
errors.push({ code: 'FILE_EXISTS', message: messages.exists() });
|
|
72
|
+
}
|
|
73
|
+
if (validate) {
|
|
74
|
+
const custom = validate(file);
|
|
75
|
+
if (custom)
|
|
76
|
+
errors.push(...custom);
|
|
77
|
+
}
|
|
78
|
+
return errors;
|
|
79
|
+
}
|
|
80
|
+
let idCounter = 0;
|
|
81
|
+
/**
|
|
82
|
+
* Split incoming files into accepted entries (id + pending status + image
|
|
83
|
+
* preview object-URL) and rejections. Files beyond the remaining `maxFiles`
|
|
84
|
+
* budget are rejected with `TOO_MANY_FILES` before any validation runs.
|
|
85
|
+
* The caller owns the returned entries — including revoking their previews
|
|
86
|
+
* (`revokeIntakePreviews`) when they leave the list.
|
|
87
|
+
*/
|
|
88
|
+
export function partitionIntake(incoming, existing, constraints, messages, idPrefix = 'file') {
|
|
89
|
+
const accepted = [];
|
|
90
|
+
const rejected = [];
|
|
91
|
+
const maxFiles = constraints.maxFiles ?? Infinity;
|
|
92
|
+
const remaining = maxFiles - existing.length;
|
|
93
|
+
const toProcess = incoming.slice(0, Math.max(0, remaining));
|
|
94
|
+
const excess = incoming.slice(Math.max(0, remaining));
|
|
95
|
+
for (const file of excess) {
|
|
96
|
+
rejected.push({
|
|
97
|
+
file,
|
|
98
|
+
errors: [{ code: 'TOO_MANY_FILES', message: messages.tooMany(maxFiles) }]
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
for (const file of toProcess) {
|
|
102
|
+
const errors = validateIntakeFile(file, existing, constraints, messages);
|
|
103
|
+
if (errors.length > 0) {
|
|
104
|
+
rejected.push({ file, errors });
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
accepted.push(createIntakeEntry(file, idPrefix));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return { accepted, rejected };
|
|
111
|
+
}
|
|
112
|
+
/** Wrap a (pre-validated) file as a pending entry with id and image preview. */
|
|
113
|
+
export function createIntakeEntry(file, idPrefix = 'file') {
|
|
114
|
+
return {
|
|
115
|
+
id: `${idPrefix}-${Date.now()}-${++idCounter}`,
|
|
116
|
+
file,
|
|
117
|
+
status: 'pending',
|
|
118
|
+
errors: [],
|
|
119
|
+
preview: isImageFile(file) ? URL.createObjectURL(file) : undefined
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
/** Revoke the preview object-URLs of the given entries (removal/teardown). */
|
|
123
|
+
export function revokeIntakePreviews(entries) {
|
|
124
|
+
for (const entry of entries) {
|
|
125
|
+
if (entry.preview)
|
|
126
|
+
URL.revokeObjectURL(entry.preview);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// ── Helpers ──────────────────────────────────────────────────────────────────
|
|
130
|
+
/** Human-readable file size (`1.5 MB`). Empty string for non-finite values. */
|
|
131
|
+
export function formatFileSize(bytes) {
|
|
132
|
+
if (bytes === 0)
|
|
133
|
+
return '0 B';
|
|
134
|
+
if (!Number.isFinite(bytes))
|
|
135
|
+
return '';
|
|
136
|
+
const k = 1024;
|
|
137
|
+
const sizes = ['B', 'KB', 'MB', 'GB'];
|
|
138
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
139
|
+
return `${parseFloat((bytes / k ** i).toFixed(1))} ${sizes[i]}`;
|
|
140
|
+
}
|
|
141
|
+
/** Is this file an image (drives preview object-URL creation)? */
|
|
142
|
+
export function isImageFile(file) {
|
|
143
|
+
return file.type.startsWith('image/');
|
|
144
|
+
}
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export * from './date.js';
|
|
2
2
|
export * from './draggable.js';
|
|
3
3
|
export * from './figma-token-export.js';
|
|
4
|
+
export { createIntakeEntry, dragItemsMatchAccept, type FileIntakeConstraints, type FileIntakeEntry, type FileIntakeError, type FileIntakeErrorCode, type FileIntakeMessages, type FileIntakeRejection, type FileIntakeStatus, formatFileSize, isImageFile, matchesAccept, partitionIntake, revokeIntakePreviews, validateIntakeFile } from './file-intake.js';
|
|
4
5
|
export { arrow, autoUpdate, type ComputePositionReturn, computePosition, flip, type Middleware, offset, type Placement, type Strategy, shift, size } from './floating.js';
|
|
5
6
|
export { createBrowserNavigationSource, createLocalStorageAdapter, GuideController, type GuideControllerOptions, type GuideDirection, type GuideEndEvent, type GuideNavigationSource, type GuideOverlayStackLike, type GuideStep, type GuideStepEvent, type GuideStorageAdapter, type GuideTopicMeta, type GuideTour } from './guide.svelte.js';
|
|
6
7
|
export * from './id.js';
|
package/dist/utils/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export * from './date.js';
|
|
2
2
|
export * from './draggable.js';
|
|
3
3
|
export * from './figma-token-export.js';
|
|
4
|
+
export { createIntakeEntry, dragItemsMatchAccept, formatFileSize, isImageFile, matchesAccept, partitionIntake, revokeIntakePreviews, validateIntakeFile } from './file-intake.js';
|
|
4
5
|
export { arrow, autoUpdate, computePosition, flip, offset, shift, size } from './floating.js';
|
|
5
6
|
export { createBrowserNavigationSource, createLocalStorageAdapter, GuideController } from './guide.svelte.js';
|
|
6
7
|
export * from './id.js';
|
package/dist/utils/variants.js
CHANGED
|
@@ -623,6 +623,20 @@ function resolveClassValue(value) {
|
|
|
623
623
|
* time layer (ValidSlotVariants, VariantPropsMap) catches the same class of
|
|
624
624
|
* mistakes for literal configs; this covers JS consumers and values built
|
|
625
625
|
* from imported constants.
|
|
626
|
+
*
|
|
627
|
+
* Error codes (prod builds throw the bare code to keep message bytes out of
|
|
628
|
+
* consumer bundles; reproduce in dev for the full message. Codes are stable —
|
|
629
|
+
* never renumber, append only):
|
|
630
|
+
* - tv:E1 — `base` and `slots` are mutually exclusive
|
|
631
|
+
* - tv:E2 — plain class value routes to 'base', but no 'base' slot is declared
|
|
632
|
+
* - tv:E3 — class leaf is not a string / nested array of strings
|
|
633
|
+
* - tv:E4 — slot map given, but this tv() declares no slots
|
|
634
|
+
* - tv:E5 — value targets an undeclared slot name
|
|
635
|
+
* - tv:E6 — value is neither class string, array nor slot map
|
|
636
|
+
* - tv:E7 — compoundVariants references an unknown variant axis
|
|
637
|
+
* - tv:E8 — compoundVariants matches a value the axis does not declare
|
|
638
|
+
* - tv:E9 — defaultVariants references an unknown variant axis
|
|
639
|
+
* - tv:E10 — defaultVariants value is not declared on its axis
|
|
626
640
|
*/
|
|
627
641
|
function validateTvConfig(config) {
|
|
628
642
|
const { base, slots, variants = {}, compoundVariants = [], defaultVariants = {} } = config;
|
|
@@ -630,11 +644,15 @@ function validateTvConfig(config) {
|
|
|
630
644
|
if (slotNames && base != null) {
|
|
631
645
|
// Fail loud instead of the historical silent drop (base only ever
|
|
632
646
|
// reached a slot literally named 'base').
|
|
633
|
-
throw new Error(
|
|
647
|
+
throw new Error(import.meta.env?.DEV
|
|
648
|
+
? 'tv(): `base` and `slots` are mutually exclusive — declare the primary slot as `slots.base` instead.'
|
|
649
|
+
: 'tv:E1');
|
|
634
650
|
}
|
|
635
651
|
const requireBaseSlot = (context) => {
|
|
636
652
|
if (slotNames && !slotNames.includes('base')) {
|
|
637
|
-
throw new Error(
|
|
653
|
+
throw new Error(import.meta.env?.DEV
|
|
654
|
+
? `tv(): ${context} is a plain class value, which routes to the 'base' slot — but no slot named 'base' is declared.`
|
|
655
|
+
: 'tv:E2');
|
|
638
656
|
}
|
|
639
657
|
};
|
|
640
658
|
// Leaf values must bottom out in class strings (nested arrays allowed,
|
|
@@ -652,7 +670,9 @@ function validateTvConfig(config) {
|
|
|
652
670
|
}
|
|
653
671
|
return;
|
|
654
672
|
}
|
|
655
|
-
throw new Error(
|
|
673
|
+
throw new Error(import.meta.env?.DEV
|
|
674
|
+
? `tv(): ${context} must be a class string (or nested array of strings), got ${typeof value}.`
|
|
675
|
+
: 'tv:E3');
|
|
656
676
|
};
|
|
657
677
|
const checkSlotKeys = (value, context) => {
|
|
658
678
|
if (value == null)
|
|
@@ -665,17 +685,23 @@ function validateTvConfig(config) {
|
|
|
665
685
|
}
|
|
666
686
|
if (typeof value === 'object') {
|
|
667
687
|
if (!slotNames) {
|
|
668
|
-
throw new Error(
|
|
688
|
+
throw new Error(import.meta.env?.DEV
|
|
689
|
+
? `tv(): ${context} is a slot map, but this tv() declares no slots — use a plain class string/array.`
|
|
690
|
+
: 'tv:E4');
|
|
669
691
|
}
|
|
670
692
|
for (const key of Object.keys(value)) {
|
|
671
693
|
if (!slotNames.includes(key)) {
|
|
672
|
-
throw new Error(
|
|
694
|
+
throw new Error(import.meta.env?.DEV
|
|
695
|
+
? `tv(): ${context} targets unknown slot '${key}' (declared slots: ${slotNames.join(', ')}).`
|
|
696
|
+
: 'tv:E5');
|
|
673
697
|
}
|
|
674
698
|
checkClassLeaf(value[key], `${context}.${key}`);
|
|
675
699
|
}
|
|
676
700
|
return;
|
|
677
701
|
}
|
|
678
|
-
throw new Error(
|
|
702
|
+
throw new Error(import.meta.env?.DEV
|
|
703
|
+
? `tv(): ${context} must be a class string, array or slot map, got ${typeof value}.`
|
|
704
|
+
: 'tv:E6');
|
|
679
705
|
};
|
|
680
706
|
for (const [axis, values] of Object.entries(variants)) {
|
|
681
707
|
for (const [valueName, value] of Object.entries(values)) {
|
|
@@ -688,7 +714,9 @@ function validateTvConfig(config) {
|
|
|
688
714
|
continue;
|
|
689
715
|
const axis = variants[key];
|
|
690
716
|
if (axis == null) {
|
|
691
|
-
throw new Error(
|
|
717
|
+
throw new Error(import.meta.env?.DEV
|
|
718
|
+
? `tv(): compoundVariants[${i}] references unknown variant axis '${key}'.`
|
|
719
|
+
: 'tv:E7');
|
|
692
720
|
}
|
|
693
721
|
const constraint = cv[key];
|
|
694
722
|
const values = Array.isArray(constraint) ? constraint : [constraint];
|
|
@@ -703,7 +731,9 @@ function validateTvConfig(config) {
|
|
|
703
731
|
if ((normalized === 'true' || normalized === 'false') && booleanAxis)
|
|
704
732
|
continue;
|
|
705
733
|
if (normalized == null || !(normalized in axis)) {
|
|
706
|
-
throw new Error(
|
|
734
|
+
throw new Error(import.meta.env?.DEV
|
|
735
|
+
? `tv(): compoundVariants[${i}] matches '${key}: ${String(v)}', but axis '${key}' declares no such value (values: ${Object.keys(axis).join(', ')}).`
|
|
736
|
+
: 'tv:E8');
|
|
707
737
|
}
|
|
708
738
|
}
|
|
709
739
|
}
|
|
@@ -712,14 +742,18 @@ function validateTvConfig(config) {
|
|
|
712
742
|
for (const [key, value] of Object.entries(defaultVariants)) {
|
|
713
743
|
const axis = variants[key];
|
|
714
744
|
if (axis == null) {
|
|
715
|
-
throw new Error(
|
|
745
|
+
throw new Error(import.meta.env?.DEV
|
|
746
|
+
? `tv(): defaultVariants references unknown variant axis '${key}'.`
|
|
747
|
+
: 'tv:E9');
|
|
716
748
|
}
|
|
717
749
|
const normalized = falsyToString(value);
|
|
718
750
|
const booleanAxis = 'true' in axis || 'false' in axis;
|
|
719
751
|
if ((normalized === 'true' || normalized === 'false') && booleanAxis)
|
|
720
752
|
continue;
|
|
721
753
|
if (normalized == null || !(normalized in axis)) {
|
|
722
|
-
throw new Error(
|
|
754
|
+
throw new Error(import.meta.env?.DEV
|
|
755
|
+
? `tv(): defaultVariants.${key} = '${String(value)}' is not a declared value of axis '${key}' (values: ${Object.keys(axis).join(', ')}).`
|
|
756
|
+
: 'tv:E10');
|
|
723
757
|
}
|
|
724
758
|
}
|
|
725
759
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@urbicon-ui/blocks",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.36.0",
|
|
4
4
|
"description": "Svelte 5 UI component library with Tailwind CSS 4, OKLCH design tokens and zero runtime dependencies",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -79,9 +79,7 @@
|
|
|
79
79
|
},
|
|
80
80
|
"sideEffects": [
|
|
81
81
|
"./src/**/*.css",
|
|
82
|
-
"./dist/**/*.css"
|
|
83
|
-
"./dist/i18n/index.js",
|
|
84
|
-
"./dist/i18n/index.d.ts"
|
|
82
|
+
"./dist/**/*.css"
|
|
85
83
|
],
|
|
86
84
|
"peerDependencies": {
|
|
87
85
|
"svelte": "^5.56.4",
|
|
@@ -95,8 +93,8 @@
|
|
|
95
93
|
"@sveltejs/package": "^2.5.8",
|
|
96
94
|
"@sveltejs/vite-plugin-svelte": "^7.0.0",
|
|
97
95
|
"@tailwindcss/vite": "^4.3.1",
|
|
98
|
-
"@urbicon-ui/i18n": "6.
|
|
99
|
-
"@urbicon-ui/shared-types": "6.
|
|
96
|
+
"@urbicon-ui/i18n": "6.36.0",
|
|
97
|
+
"@urbicon-ui/shared-types": "6.36.0",
|
|
100
98
|
"prettier": "^3.8.4",
|
|
101
99
|
"prettier-plugin-svelte": "^4.1.1",
|
|
102
100
|
"prettier-plugin-tailwindcss": "^0.8.0",
|