@urbicon-ui/blocks 6.35.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.
Files changed (99) hide show
  1. package/dist/components/Chat/Chat/Chat.svelte +53 -0
  2. package/dist/components/Chat/Chat/Chat.svelte.d.ts +4 -0
  3. package/dist/components/Chat/Chat/chat.variants.d.ts +20 -0
  4. package/dist/components/Chat/Chat/chat.variants.js +15 -0
  5. package/dist/components/Chat/Chat/index.d.ts +47 -0
  6. package/dist/components/Chat/Chat/index.js +2 -0
  7. package/dist/components/Chat/ChatMessage/ChatMessage.svelte +342 -0
  8. package/dist/components/Chat/ChatMessage/ChatMessage.svelte.d.ts +4 -0
  9. package/dist/components/Chat/ChatMessage/chat-message.variants.d.ts +138 -0
  10. package/dist/components/Chat/ChatMessage/chat-message.variants.js +118 -0
  11. package/dist/components/Chat/ChatMessage/index.d.ts +102 -0
  12. package/dist/components/Chat/ChatMessage/index.js +2 -0
  13. package/dist/components/Chat/ChatMessageList/ChatMessageList.svelte +301 -0
  14. package/dist/components/Chat/ChatMessageList/ChatMessageList.svelte.d.ts +6 -0
  15. package/dist/components/Chat/ChatMessageList/chat-message-list.variants.d.ts +23 -0
  16. package/dist/components/Chat/ChatMessageList/chat-message-list.variants.js +32 -0
  17. package/dist/components/Chat/ChatMessageList/chat-scroll.d.ts +45 -0
  18. package/dist/components/Chat/ChatMessageList/chat-scroll.js +52 -0
  19. package/dist/components/Chat/ChatMessageList/index.d.ts +93 -0
  20. package/dist/components/Chat/ChatMessageList/index.js +3 -0
  21. package/dist/components/Chat/CitationChip/CitationChip.svelte +107 -0
  22. package/dist/components/Chat/CitationChip/CitationChip.svelte.d.ts +4 -0
  23. package/dist/components/Chat/CitationChip/citation-chip.variants.d.ts +40 -0
  24. package/dist/components/Chat/CitationChip/citation-chip.variants.js +42 -0
  25. package/dist/components/Chat/CitationChip/index.d.ts +69 -0
  26. package/dist/components/Chat/CitationChip/index.js +2 -0
  27. package/dist/components/Chat/CodeBlock/CodeBlock.svelte +120 -0
  28. package/dist/components/Chat/CodeBlock/CodeBlock.svelte.d.ts +4 -0
  29. package/dist/components/Chat/CodeBlock/code-block.variants.d.ts +40 -0
  30. package/dist/components/Chat/CodeBlock/code-block.variants.js +51 -0
  31. package/dist/components/Chat/CodeBlock/index.d.ts +55 -0
  32. package/dist/components/Chat/CodeBlock/index.js +2 -0
  33. package/dist/components/Chat/PromptInput/PromptInput.svelte +432 -0
  34. package/dist/components/Chat/PromptInput/PromptInput.svelte.d.ts +4 -0
  35. package/dist/components/Chat/PromptInput/index.d.ts +165 -0
  36. package/dist/components/Chat/PromptInput/index.js +2 -0
  37. package/dist/components/Chat/PromptInput/prompt-input.variants.d.ts +90 -0
  38. package/dist/components/Chat/PromptInput/prompt-input.variants.js +102 -0
  39. package/dist/components/Chat/ReasoningDisclosure/ReasoningDisclosure.svelte +107 -0
  40. package/dist/components/Chat/ReasoningDisclosure/ReasoningDisclosure.svelte.d.ts +4 -0
  41. package/dist/components/Chat/ReasoningDisclosure/index.d.ts +85 -0
  42. package/dist/components/Chat/ReasoningDisclosure/index.js +2 -0
  43. package/dist/components/Chat/ReasoningDisclosure/reasoning-disclosure.variants.d.ts +20 -0
  44. package/dist/components/Chat/ReasoningDisclosure/reasoning-disclosure.variants.js +31 -0
  45. package/dist/components/Chat/StreamingMarkdown/MdBlock.svelte +99 -0
  46. package/dist/components/Chat/StreamingMarkdown/MdBlock.svelte.d.ts +9 -0
  47. package/dist/components/Chat/StreamingMarkdown/MdInline.svelte +82 -0
  48. package/dist/components/Chat/StreamingMarkdown/MdInline.svelte.d.ts +9 -0
  49. package/dist/components/Chat/StreamingMarkdown/StreamingMarkdown.svelte +118 -0
  50. package/dist/components/Chat/StreamingMarkdown/StreamingMarkdown.svelte.d.ts +4 -0
  51. package/dist/components/Chat/StreamingMarkdown/index.d.ts +86 -0
  52. package/dist/components/Chat/StreamingMarkdown/index.js +2 -0
  53. package/dist/components/Chat/StreamingMarkdown/md-context.d.ts +58 -0
  54. package/dist/components/Chat/StreamingMarkdown/md-context.js +1 -0
  55. package/dist/components/Chat/StreamingMarkdown/streaming-markdown.variants.d.ts +145 -0
  56. package/dist/components/Chat/StreamingMarkdown/streaming-markdown.variants.js +73 -0
  57. package/dist/components/Chat/ToolCallCard/ToolCallCard.svelte +174 -0
  58. package/dist/components/Chat/ToolCallCard/ToolCallCard.svelte.d.ts +4 -0
  59. package/dist/components/Chat/ToolCallCard/index.d.ts +84 -0
  60. package/dist/components/Chat/ToolCallCard/index.js +2 -0
  61. package/dist/components/Chat/ToolCallCard/tool-call-card.variants.d.ts +38 -0
  62. package/dist/components/Chat/ToolCallCard/tool-call-card.variants.js +38 -0
  63. package/dist/components/Chat/chat.types.d.ts +82 -0
  64. package/dist/components/Chat/chat.types.js +7 -0
  65. package/dist/components/Chat/index.d.ts +22 -0
  66. package/dist/components/Chat/index.js +14 -0
  67. package/dist/components/Chat/markdown/blocks.d.ts +54 -0
  68. package/dist/components/Chat/markdown/blocks.js +462 -0
  69. package/dist/components/Chat/markdown/inline.d.ts +31 -0
  70. package/dist/components/Chat/markdown/inline.js +446 -0
  71. package/dist/components/Chat/markdown/repair.d.ts +23 -0
  72. package/dist/components/Chat/markdown/repair.js +337 -0
  73. package/dist/components/Chat/markdown/streaming-harness.d.ts +23 -0
  74. package/dist/components/Chat/markdown/streaming-harness.js +62 -0
  75. package/dist/components/Chat/markdown/types.d.ts +139 -0
  76. package/dist/components/Chat/markdown/types.js +13 -0
  77. package/dist/components/Chat/markdown/url-policy.d.ts +33 -0
  78. package/dist/components/Chat/markdown/url-policy.js +109 -0
  79. package/dist/components/FileUpload/FileUpload.svelte +35 -123
  80. package/dist/components/FileUpload/FileUpload.svelte.d.ts +1 -1
  81. package/dist/components/FileUpload/index.d.ts +2 -28
  82. package/dist/components/index.d.ts +1 -0
  83. package/dist/components/index.js +1 -0
  84. package/dist/primitives/Collapsible/Collapsible.svelte +5 -0
  85. package/dist/primitives/SplitPane/SplitPane.svelte +293 -0
  86. package/dist/primitives/SplitPane/SplitPane.svelte.d.ts +4 -0
  87. package/dist/primitives/SplitPane/index.d.ts +88 -0
  88. package/dist/primitives/SplitPane/index.js +2 -0
  89. package/dist/primitives/SplitPane/split-pane.utils.d.ts +73 -0
  90. package/dist/primitives/SplitPane/split-pane.utils.js +94 -0
  91. package/dist/primitives/SplitPane/split-pane.variants.d.ts +40 -0
  92. package/dist/primitives/SplitPane/split-pane.variants.js +56 -0
  93. package/dist/primitives/index.d.ts +2 -0
  94. package/dist/primitives/index.js +1 -0
  95. package/dist/utils/file-intake.d.ts +78 -0
  96. package/dist/utils/file-intake.js +144 -0
  97. package/dist/utils/index.d.ts +1 -0
  98. package/dist/utils/index.js +1 -0
  99. package/package.json +3 -3
@@ -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
+ }
@@ -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';
@@ -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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@urbicon-ui/blocks",
3
- "version": "6.35.0",
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": {
@@ -93,8 +93,8 @@
93
93
  "@sveltejs/package": "^2.5.8",
94
94
  "@sveltejs/vite-plugin-svelte": "^7.0.0",
95
95
  "@tailwindcss/vite": "^4.3.1",
96
- "@urbicon-ui/i18n": "6.35.0",
97
- "@urbicon-ui/shared-types": "6.35.0",
96
+ "@urbicon-ui/i18n": "6.36.0",
97
+ "@urbicon-ui/shared-types": "6.36.0",
98
98
  "prettier": "^3.8.4",
99
99
  "prettier-plugin-svelte": "^4.1.1",
100
100
  "prettier-plugin-tailwindcss": "^0.8.0",