@classic-homes/theme-svelte 0.1.54 → 0.1.55

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.
@@ -0,0 +1,45 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { render, screen } from '@testing-library/svelte';
3
+ import FileUpload from '../lib/components/FileUpload.svelte';
4
+ describe('FileUpload accepted-types label', () => {
5
+ it('derives a friendly label from MIME types instead of showing raw values', () => {
6
+ render(FileUpload, {
7
+ props: {
8
+ label: 'Upload files',
9
+ acceptedTypes: [
10
+ 'image/jpeg',
11
+ 'image/png',
12
+ 'application/pdf',
13
+ 'video/mp4',
14
+ 'video/quicktime',
15
+ ],
16
+ },
17
+ });
18
+ expect(screen.getByText(/Images, PDF, Videos \(max/)).toBeInTheDocument();
19
+ // Raw MIME types should not be shown
20
+ expect(screen.queryByText(/image\/jpeg/)).not.toBeInTheDocument();
21
+ });
22
+ it('uses the default accepted types (Images, PDF) when none are provided', () => {
23
+ render(FileUpload, { props: { label: 'Upload files' } });
24
+ expect(screen.getByText(/^Images, PDF \(max/)).toBeInTheDocument();
25
+ });
26
+ it('respects an explicit typesLabel override', () => {
27
+ render(FileUpload, {
28
+ props: {
29
+ label: 'Upload files',
30
+ acceptedTypes: ['image/png', 'video/mp4'],
31
+ typesLabel: 'Photos and clips',
32
+ },
33
+ });
34
+ expect(screen.getByText(/^Photos and clips \(max/)).toBeInTheDocument();
35
+ });
36
+ it('falls back to the uppercased subtype for unmapped types', () => {
37
+ render(FileUpload, {
38
+ props: {
39
+ label: 'Upload files',
40
+ acceptedTypes: ['application/zip'],
41
+ },
42
+ });
43
+ expect(screen.getByText(/^ZIP \(max/)).toBeInTheDocument();
44
+ });
45
+ });
@@ -38,6 +38,12 @@
38
38
  label?: string;
39
39
  /** Hint text shown below the drop zone */
40
40
  hint?: string;
41
+ /**
42
+ * Human-friendly label for the accepted file types shown in the drop zone.
43
+ * When omitted, a readable label is derived from `acceptedTypes`
44
+ * (e.g. "Images, PDF, Videos") instead of showing raw MIME types.
45
+ */
46
+ typesLabel?: string;
41
47
  /** Additional classes */
42
48
  class?: string;
43
49
  }
@@ -56,6 +62,7 @@
56
62
  onUpload,
57
63
  label,
58
64
  hint,
65
+ typesLabel,
59
66
  class: className,
60
67
  }: Props = $props();
61
68
 
@@ -68,6 +75,33 @@
68
75
 
69
76
  const displayError = $derived(externalError || internalError);
70
77
 
78
+ /**
79
+ * Readable label for the accepted types shown in the drop zone.
80
+ * Uses the explicit `typesLabel` when provided, otherwise groups the
81
+ * accepted MIME types into friendly names (Images, PDF, Videos, ...).
82
+ */
83
+ const acceptedTypesLabel = $derived.by(() => {
84
+ if (typesLabel) return typesLabel;
85
+
86
+ const groups: string[] = [];
87
+ const add = (name: string) => {
88
+ if (!groups.includes(name)) groups.push(name);
89
+ };
90
+
91
+ for (const type of acceptedTypes) {
92
+ if (type.startsWith('image/')) add('Images');
93
+ else if (type === 'application/pdf') add('PDF');
94
+ else if (type.startsWith('video/')) add('Videos');
95
+ else if (type.startsWith('audio/')) add('Audio');
96
+ else {
97
+ const subtype = type.split('/')[1];
98
+ add(subtype ? subtype.toUpperCase() : type);
99
+ }
100
+ }
101
+
102
+ return groups.join(', ');
103
+ });
104
+
71
105
  // Helper to generate unique ID
72
106
  function generateId(): string {
73
107
  return `file-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
@@ -337,7 +371,7 @@
337
371
  <span class="font-medium text-foreground">Click to upload</span> or drag and drop
338
372
  </p>
339
373
  <p class="mt-1 text-xs text-muted-foreground">
340
- {acceptedTypes.join(', ')} (max {formatSize(maxSizeBytes)})
374
+ {acceptedTypesLabel} (max {formatSize(maxSizeBytes)})
341
375
  </p>
342
376
 
343
377
  <!-- Hidden file input -->
@@ -34,6 +34,12 @@ interface Props {
34
34
  label?: string;
35
35
  /** Hint text shown below the drop zone */
36
36
  hint?: string;
37
+ /**
38
+ * Human-friendly label for the accepted file types shown in the drop zone.
39
+ * When omitted, a readable label is derived from `acceptedTypes`
40
+ * (e.g. "Images, PDF, Videos") instead of showing raw MIME types.
41
+ */
42
+ typesLabel?: string;
37
43
  /** Additional classes */
38
44
  class?: string;
39
45
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@classic-homes/theme-svelte",
3
- "version": "0.1.54",
3
+ "version": "0.1.55",
4
4
  "description": "Svelte components for the Classic theme system",
5
5
  "type": "module",
6
6
  "svelte": "./dist/lib/index.js",