@politiet/sheriff-web-components 2.13.0 → 2.14.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 (139) hide show
  1. package/custom-elements.json +3996 -1344
  2. package/dist/controllers/index.d.ts +3 -0
  3. package/dist/controllers/index.d.ts.map +1 -0
  4. package/dist/controllers/index.js +3 -0
  5. package/dist/controllers/index.js.map +1 -0
  6. package/dist/controllers/sds-drag-drop-controller.d.ts +25 -0
  7. package/dist/controllers/sds-drag-drop-controller.d.ts.map +1 -0
  8. package/dist/controllers/sds-drag-drop-controller.js +52 -0
  9. package/dist/controllers/sds-drag-drop-controller.js.map +1 -0
  10. package/dist/controllers/sds-file-preview-controller.d.ts +38 -0
  11. package/dist/controllers/sds-file-preview-controller.d.ts.map +1 -0
  12. package/dist/controllers/sds-file-preview-controller.js +90 -0
  13. package/dist/controllers/sds-file-preview-controller.js.map +1 -0
  14. package/dist/frameworks/preact.d.ts +14 -1
  15. package/dist/frameworks/preact.d.ts.map +1 -1
  16. package/dist/frameworks/react.d.ts +30 -1
  17. package/dist/frameworks/react.d.ts.map +1 -1
  18. package/dist/frameworks/solidjs.d.ts +4 -0
  19. package/dist/frameworks/solidjs.d.ts.map +1 -1
  20. package/dist/frameworks/svelte.d.ts +4 -0
  21. package/dist/frameworks/svelte.d.ts.map +1 -1
  22. package/dist/frameworks/vue.d.ts +24 -1
  23. package/dist/frameworks/vue.d.ts.map +1 -1
  24. package/dist/index.d.ts +8 -0
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +4 -0
  27. package/dist/index.js.map +1 -1
  28. package/dist/mixins/sds-dialog-target-mixin.d.ts.map +1 -1
  29. package/dist/mixins/sds-dialog-target-mixin.js +10 -0
  30. package/dist/mixins/sds-dialog-target-mixin.js.map +1 -1
  31. package/dist/react-wrappers/SDSDialogWrapper.d.ts +1 -0
  32. package/dist/react-wrappers/SDSDialogWrapper.d.ts.map +1 -1
  33. package/dist/react-wrappers/SDSDialogWrapper.js +1 -0
  34. package/dist/react-wrappers/SDSDialogWrapper.js.map +1 -1
  35. package/dist/react-wrappers/SDSFileUploadFileListWrapper.d.ts +3 -0
  36. package/dist/react-wrappers/SDSFileUploadFileListWrapper.d.ts.map +1 -0
  37. package/dist/react-wrappers/SDSFileUploadFileListWrapper.js +10 -0
  38. package/dist/react-wrappers/SDSFileUploadFileListWrapper.js.map +1 -0
  39. package/dist/react-wrappers/SDSFileUploadItemWrapper.d.ts +6 -0
  40. package/dist/react-wrappers/SDSFileUploadItemWrapper.d.ts.map +1 -0
  41. package/dist/react-wrappers/SDSFileUploadItemWrapper.js +12 -0
  42. package/dist/react-wrappers/SDSFileUploadItemWrapper.js.map +1 -0
  43. package/dist/react-wrappers/SDSFileUploadWrapper.d.ts +12 -0
  44. package/dist/react-wrappers/SDSFileUploadWrapper.d.ts.map +1 -0
  45. package/dist/react-wrappers/SDSFileUploadWrapper.js +18 -0
  46. package/dist/react-wrappers/SDSFileUploadWrapper.js.map +1 -0
  47. package/dist/react-wrappers/SDSSearchWrapper.d.ts +15 -0
  48. package/dist/react-wrappers/SDSSearchWrapper.d.ts.map +1 -0
  49. package/dist/react-wrappers/SDSSearchWrapper.js +19 -0
  50. package/dist/react-wrappers/SDSSearchWrapper.js.map +1 -0
  51. package/dist/react-wrappers/index.d.ts +4 -0
  52. package/dist/react-wrappers/index.d.ts.map +1 -1
  53. package/dist/react-wrappers/index.js +4 -0
  54. package/dist/react-wrappers/index.js.map +1 -1
  55. package/dist/sds-button/sds-button.component.d.ts +0 -1
  56. package/dist/sds-button/sds-button.component.d.ts.map +1 -1
  57. package/dist/sds-button/sds-button.component.js +10 -16
  58. package/dist/sds-button/sds-button.component.js.map +1 -1
  59. package/dist/sds-button/sds-button.styles.d.ts.map +1 -1
  60. package/dist/sds-button/sds-button.styles.js +7 -2
  61. package/dist/sds-button/sds-button.styles.js.map +1 -1
  62. package/dist/sds-dialog/sds-dialog.component.d.ts.map +1 -1
  63. package/dist/sds-dialog/sds-dialog.component.js +11 -1
  64. package/dist/sds-dialog/sds-dialog.component.js.map +1 -1
  65. package/dist/sds-file-upload/sds-file-upload.d.ts +102 -0
  66. package/dist/sds-file-upload/sds-file-upload.d.ts.map +1 -0
  67. package/dist/sds-file-upload/sds-file-upload.js +384 -0
  68. package/dist/sds-file-upload/sds-file-upload.js.map +1 -0
  69. package/dist/sds-file-upload/sds-file-upload.styles.d.ts +2 -0
  70. package/dist/sds-file-upload/sds-file-upload.styles.d.ts.map +1 -0
  71. package/dist/sds-file-upload/sds-file-upload.styles.js +234 -0
  72. package/dist/sds-file-upload/sds-file-upload.styles.js.map +1 -0
  73. package/dist/sds-file-upload-file-list/sds-file-upload-file-list.d.ts +14 -0
  74. package/dist/sds-file-upload-file-list/sds-file-upload-file-list.d.ts.map +1 -0
  75. package/dist/sds-file-upload-file-list/sds-file-upload-file-list.js +26 -0
  76. package/dist/sds-file-upload-file-list/sds-file-upload-file-list.js.map +1 -0
  77. package/dist/sds-file-upload-file-list/sds-file-upload-file-list.styles.d.ts +2 -0
  78. package/dist/sds-file-upload-file-list/sds-file-upload-file-list.styles.d.ts.map +1 -0
  79. package/dist/sds-file-upload-file-list/sds-file-upload-file-list.styles.js +19 -0
  80. package/dist/sds-file-upload-file-list/sds-file-upload-file-list.styles.js.map +1 -0
  81. package/dist/sds-file-upload-item/assets/u-progress.js +2 -0
  82. package/dist/sds-file-upload-item/sds-file-upload-item.d.ts +62 -0
  83. package/dist/sds-file-upload-item/sds-file-upload-item.d.ts.map +1 -0
  84. package/dist/sds-file-upload-item/sds-file-upload-item.js +205 -0
  85. package/dist/sds-file-upload-item/sds-file-upload-item.js.map +1 -0
  86. package/dist/sds-file-upload-item/sds-file-upload-item.styles.d.ts +2 -0
  87. package/dist/sds-file-upload-item/sds-file-upload-item.styles.d.ts.map +1 -0
  88. package/dist/sds-file-upload-item/sds-file-upload-item.styles.js +227 -0
  89. package/dist/sds-file-upload-item/sds-file-upload-item.styles.js.map +1 -0
  90. package/dist/sds-radio/sds-radio.d.ts +53 -1
  91. package/dist/sds-radio/sds-radio.d.ts.map +1 -1
  92. package/dist/sds-radio/sds-radio.js +218 -41
  93. package/dist/sds-radio/sds-radio.js.map +1 -1
  94. package/dist/sds-radio/sds-radio.styles.js +36 -36
  95. package/dist/sds-radio/sds-radio.styles.js.map +1 -1
  96. package/dist/sds-radio-group/sds-radio-group.d.ts +4 -2
  97. package/dist/sds-radio-group/sds-radio-group.d.ts.map +1 -1
  98. package/dist/sds-radio-group/sds-radio-group.js +10 -3
  99. package/dist/sds-radio-group/sds-radio-group.js.map +1 -1
  100. package/dist/sds-search/sds-search.component.d.ts +128 -0
  101. package/dist/sds-search/sds-search.component.d.ts.map +1 -0
  102. package/dist/sds-search/sds-search.component.js +345 -0
  103. package/dist/sds-search/sds-search.component.js.map +1 -0
  104. package/dist/sds-search/sds-search.d.ts +13 -0
  105. package/dist/sds-search/sds-search.d.ts.map +1 -0
  106. package/dist/sds-search/sds-search.js +18 -0
  107. package/dist/sds-search/sds-search.js.map +1 -0
  108. package/dist/sds-search/sds-search.styles.d.ts +2 -0
  109. package/dist/sds-search/sds-search.styles.d.ts.map +1 -0
  110. package/dist/sds-search/sds-search.styles.js +74 -0
  111. package/dist/sds-search/sds-search.styles.js.map +1 -0
  112. package/dist/sds-textfield/sds-textfield.component.d.ts +4 -1
  113. package/dist/sds-textfield/sds-textfield.component.d.ts.map +1 -1
  114. package/dist/sds-textfield/sds-textfield.component.js +20 -5
  115. package/dist/sds-textfield/sds-textfield.component.js.map +1 -1
  116. package/dist/sds-textfield/sds-textfield.styles.d.ts.map +1 -1
  117. package/dist/sds-textfield/sds-textfield.styles.js +11 -0
  118. package/dist/sds-textfield/sds-textfield.styles.js.map +1 -1
  119. package/dist/sheriff-web-components.js +1104 -375
  120. package/dist/skill/SKILL.md +136 -42
  121. package/dist/skill/references/components.md +332 -35
  122. package/dist/skill/references/react-wrappers.md +41 -9
  123. package/dist/utils/file-validation.d.ts +31 -0
  124. package/dist/utils/file-validation.d.ts.map +1 -0
  125. package/dist/utils/file-validation.js +57 -0
  126. package/dist/utils/file-validation.js.map +1 -0
  127. package/dist/utils/format-bytes.d.ts +6 -0
  128. package/dist/utils/format-bytes.d.ts.map +1 -0
  129. package/dist/utils/format-bytes.js +13 -0
  130. package/dist/utils/format-bytes.js.map +1 -0
  131. package/dist/utils/video-thumbnail.d.ts +8 -0
  132. package/dist/utils/video-thumbnail.d.ts.map +1 -0
  133. package/dist/utils/video-thumbnail.js +77 -0
  134. package/dist/utils/video-thumbnail.js.map +1 -0
  135. package/dist/version.d.ts +1 -1
  136. package/dist/version.js +1 -1
  137. package/dist/version.js.map +1 -1
  138. package/package.json +24 -4
  139. package/web-types.json +3452 -1048
@@ -3,10 +3,12 @@
3
3
  React 18 does not natively support web component events. Use these wrappers instead of bare web components.
4
4
  Import components from `@politiet/sheriff-web-components/react-wrappers`.
5
5
 
6
- React 19+ supports custom elements natively — may use web components directly without wrappers.
6
+ React 19+ supports custom elements natively and may use web components directly without wrappers. For typed custom elements without wrappers, reference `@politiet/sheriff-web-components/framework/react`.
7
7
 
8
8
  ## Available Wrappers
9
9
 
10
+ All 33 components have a wrapper:
11
+
10
12
  ```tsx
11
13
  import {
12
14
  SDSAlertWrapper,
@@ -16,13 +18,23 @@ import {
16
18
  SDSCheckboxGroupWrapper,
17
19
  SDSChipWrapper,
18
20
  SDSDetailsWrapper,
21
+ SDSDetailsGroupWrapper,
19
22
  SDSDialogWrapper,
23
+ SDSEnvironmentBannerWrapper,
24
+ SDSFileUploadWrapper,
25
+ SDSFileUploadItemWrapper,
26
+ SDSFileUploadFileListWrapper,
20
27
  SDSHeadingWrapper,
21
28
  SDSIconWrapper,
29
+ SDSInternalHeaderWrapper,
22
30
  SDSLoaderWrapper,
23
31
  SDSNotificationWrapper,
32
+ SDSPopoverWrapper,
33
+ SDSProcessWrapper,
34
+ SDSProcessStepWrapper,
24
35
  SDSRadioWrapper,
25
36
  SDSRadioGroupWrapper,
37
+ SDSSearchWrapper,
26
38
  SDSSelectWrapper,
27
39
  SDSStepperWrapper,
28
40
  SDSStepperStepWrapper,
@@ -31,6 +43,7 @@ import {
31
43
  SDSTextWrapper,
32
44
  SDSTextAreaWrapper,
33
45
  SDSTextFieldWrapper,
46
+ SDSTooltipWrapper,
34
47
  } from '@politiet/sheriff-web-components/react-wrappers';
35
48
  ```
36
49
 
@@ -54,13 +67,32 @@ function MyForm() {
54
67
  }
55
68
  ```
56
69
 
57
- ## Event Mapping Examples
70
+ ## Event Mapping
71
+
72
+ Handler names follow React idioms and **drop the `sds-` prefix** — the DOM event `sds-remove` becomes `onRemove`, not `onSdsRemove`.
73
+
74
+ | Wrapper | React prop | DOM event |
75
+ | ------------------------------------------------- | -------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
76
+ | `SDSAlertWrapper`, `SDSNotificationWrapper` | `onRemove` | `sds-remove` |
77
+ | `SDSButtonWrapper` | `onClick`, `onSubmit`, `onReset` | `click`, `submit`, `reset` |
78
+ | `SDSCheckboxWrapper`, `SDSRadioWrapper` | `onChange`, `onFocus`, `onBlur` | `change`, `focus`, `blur` |
79
+ | `SDSCheckboxGroupWrapper`, `SDSRadioGroupWrapper` | `onUpdate`, `onChange` | `sds-update`, `change` |
80
+ | `SDSChipWrapper` | `onChange`, `onRemove` | `change`, `sds-remove` |
81
+ | `SDSDetailsWrapper`, `SDSTooltipWrapper` | `onToggle` | `toggle` |
82
+ | `SDSFileUploadWrapper` | `onInput`, `onChange`, `onCancel`, `onFocus`, `onBlur`, `onReject`, `onPreviewReady` | `input`, `change`, `cancel`, `focus`, `blur`, `sds-reject`, `sds-preview-ready` |
83
+ | `SDSFileUploadItemWrapper` | `onRemove` | `sds-remove` |
84
+ | `SDSPopoverWrapper` | `onToggle` | `toggle` (native `ToggleEvent`) |
85
+ | `SDSDialogWrapper` | `onClose`, `onCancel` | `close`, `cancel` |
86
+ | `SDSSearchWrapper` | `onSearch`, `onInput`, `onChange`, `onSelect`, `onFocus`, `onBlur`, `onKeyDown`, `onInvalid` | `search` (detail `{ value }`), `input`, **`input`**, `select`, `focus`, `blur`, `keydown`, `invalid` |
87
+ | `SDSSelectWrapper`, `SDSSwitchWrapper` | `onChange`, `onFocus`, `onBlur` | `change`, `focus`, `blur` |
88
+ | `SDSStepperWrapper` | `onChange` | `change` (detail `{ index }`) |
89
+ | `SDSTextFieldWrapper` | `onInput`, `onChange`, `onSelect`, `onFocus`, `onBlur`, `onKeyDown` | `input`, **`input`**, `select`, `focus`, `blur`, `keydown` |
90
+ | `SDSTextAreaWrapper` | `onInput`, `onChange`, `onSelect`, `onFocus`, `onBlur` | `input`, **`input`**, `select`, `focus`, `blur` |
91
+
92
+ Wrappers with no event mappings (presentational only): `SDSCardWrapper`, `SDSDetailsGroupWrapper`, `SDSEnvironmentBannerWrapper`, `SDSFileUploadFileListWrapper`, `SDSHeadingWrapper`, `SDSIconWrapper`, `SDSInternalHeaderWrapper`, `SDSLoaderWrapper`, `SDSProcessWrapper`, `SDSProcessStepWrapper`, `SDSStepperStepWrapper`, `SDSTagWrapper`, `SDSTextWrapper`.
58
93
 
59
- More React-y event handling in that names follow React naming/idioms:
94
+ ## Gotchas
60
95
 
61
- - `SDSButtonWrapper`: `onClick` → `click`, `onSubmit` → `submit`, `onReset` → `reset`
62
- - `SDSTextFieldWrapper`: `onInput` → `input`, `onSelect` → `select`, `onFocus` → `focus`, `onBlur` → `blur`, `onKeydown` → `keydown`
63
- - `SDSAlertWrapper`: `onSdsRemove` → `sds-remove`
64
- - `SDSDetailsWrapper`: `onSdsToggle` → `sds-toggle`
65
- - `SDSDialogWrapper`: `onClose` → `close`
66
- - `SDSCheckboxGroupWrapper` / `SDSRadioGroupWrapper`: `onSdsUpdate` → `sds-update`
96
+ - On `SDSTextFieldWrapper`, `SDSTextAreaWrapper` and `SDSSearchWrapper`, **`onChange` is wired to the `input` event**, so it fires on every keystroke like React's own `onChange` — not on blur like the native DOM `change` event. Use `onBlur` if you need commit-on-blur semantics.
97
+ - `onKeyDown` (capital D) is the correct casing on `SDSTextFieldWrapper` and `SDSSearchWrapper`; there is no `onKeydown`.
98
+ - Wrappers forward all other props straight through as attributes, so kebab-case component attributes (`help-text`, `error-message`, `removable-label`, `app-name`) keep their kebab-case names in JSX.
@@ -0,0 +1,31 @@
1
+ export interface SDSRejectedFile {
2
+ file: File;
3
+ reason: string;
4
+ errorCode: 'type-mismatch' | 'too-large';
5
+ }
6
+ export interface PartitionFilesOptions {
7
+ accept?: string;
8
+ maxSizeInBytes?: number;
9
+ multiple?: boolean;
10
+ }
11
+ /**
12
+ * Mirrors the native file input's `accept` matching: a token is either an extension (`.pdf`),
13
+ * a MIME wildcard (`image/*`) or an exact MIME type. Matches if any token matches.
14
+ */
15
+ export declare function matchesAccept(file: File, accept?: string): boolean;
16
+ /**
17
+ * Splits an incoming selection into files that pass validation and files that don't, with a reason.
18
+ * Like the native file input, every selection replaces the current one. Duplicates within the
19
+ * selection (same name, size and last modified) are silently dropped rather than rejected. In
20
+ * single-file mode only the first incoming file is considered.
21
+ */
22
+ export declare function partitionFiles(incoming: File[], options: PartitionFilesOptions): {
23
+ accepted: File[];
24
+ rejected: SDSRejectedFile[];
25
+ };
26
+ /**
27
+ * Identity check for files that survives the copies browsers hand out across separate
28
+ * `change`/`drop` events, where reference equality no longer holds.
29
+ */
30
+ export declare function isSameFile(a: File, b: File): boolean;
31
+ //# sourceMappingURL=file-validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-validation.d.ts","sourceRoot":"","sources":["../../src/utils/file-validation.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,eAAe;IAC/B,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,eAAe,GAAG,WAAW,CAAC;CACzC;AAED,MAAM,WAAW,qBAAqB;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAgBlE;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,qBAAqB,GAAG;IAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAAC,QAAQ,EAAE,eAAe,EAAE,CAAA;CAAE,CAoBlI;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,GAAG,OAAO,CAEpD"}
@@ -0,0 +1,57 @@
1
+ import { formatBytes } from './format-bytes';
2
+ /**
3
+ * Mirrors the native file input's `accept` matching: a token is either an extension (`.pdf`),
4
+ * a MIME wildcard (`image/*`) or an exact MIME type. Matches if any token matches.
5
+ */
6
+ export function matchesAccept(file, accept) {
7
+ if (!accept)
8
+ return true;
9
+ const tokens = accept
10
+ .split(',')
11
+ .map((token) => token.trim().toLowerCase())
12
+ .filter(Boolean);
13
+ if (tokens.length === 0)
14
+ return true;
15
+ const fileName = file.name.toLowerCase();
16
+ const mimeType = file.type.toLowerCase();
17
+ return tokens.some((token) => {
18
+ if (token.startsWith('.'))
19
+ return fileName.endsWith(token);
20
+ if (token.endsWith('/*'))
21
+ return mimeType.startsWith(token.slice(0, -1));
22
+ return mimeType === token;
23
+ });
24
+ }
25
+ /**
26
+ * Splits an incoming selection into files that pass validation and files that don't, with a reason.
27
+ * Like the native file input, every selection replaces the current one. Duplicates within the
28
+ * selection (same name, size and last modified) are silently dropped rather than rejected. In
29
+ * single-file mode only the first incoming file is considered.
30
+ */
31
+ export function partitionFiles(incoming, options) {
32
+ const { accept, maxSizeInBytes, multiple = false } = options;
33
+ const accepted = [];
34
+ const rejected = [];
35
+ const candidates = multiple ? incoming : incoming.slice(0, 1);
36
+ for (const file of candidates) {
37
+ if (!matchesAccept(file, accept)) {
38
+ rejected.push({ file, reason: 'Filtypen støttes ikke.', errorCode: 'type-mismatch' });
39
+ continue;
40
+ }
41
+ if (maxSizeInBytes && file.size > maxSizeInBytes) {
42
+ rejected.push({ file, reason: `Filen er for stor. Maks ${formatBytes(maxSizeInBytes)}.`, errorCode: 'too-large' });
43
+ continue;
44
+ }
45
+ if (!accepted.some((candidate) => isSameFile(candidate, file)))
46
+ accepted.push(file);
47
+ }
48
+ return { accepted, rejected };
49
+ }
50
+ /**
51
+ * Identity check for files that survives the copies browsers hand out across separate
52
+ * `change`/`drop` events, where reference equality no longer holds.
53
+ */
54
+ export function isSameFile(a, b) {
55
+ return a === b || (a.name === b.name && a.size === b.size && a.lastModified === b.lastModified);
56
+ }
57
+ //# sourceMappingURL=file-validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-validation.js","sourceRoot":"","sources":["../../src/utils/file-validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAc7C;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,IAAU,EAAE,MAAe;IACxD,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACzB,MAAM,MAAM,GAAG,MAAM;SACnB,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;SAC1C,MAAM,CAAC,OAAO,CAAC,CAAC;IAClB,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAErC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;IACzC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;IAEzC,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE;QAC5B,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,OAAO,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC3D,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,OAAO,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACzE,OAAO,QAAQ,KAAK,KAAK,CAAC;IAC3B,CAAC,CAAC,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,QAAgB,EAAE,OAA8B;IAC9E,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,QAAQ,GAAG,KAAK,EAAE,GAAG,OAAO,CAAC;IAE7D,MAAM,QAAQ,GAAW,EAAE,CAAC;IAC5B,MAAM,QAAQ,GAAsB,EAAE,CAAC;IACvC,MAAM,UAAU,GAAG,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAE9D,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC/B,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC;YAClC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,wBAAwB,EAAE,SAAS,EAAE,eAAe,EAAE,CAAC,CAAC;YACtF,SAAS;QACV,CAAC;QACD,IAAI,cAAc,IAAI,IAAI,CAAC,IAAI,GAAG,cAAc,EAAE,CAAC;YAClD,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,2BAA2B,WAAW,CAAC,cAAc,CAAC,GAAG,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,CAAC;YACnH,SAAS;QACV,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,UAAU,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;YAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACrF,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;AAC/B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,CAAO,EAAE,CAAO;IAC1C,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,YAAY,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC;AACjG,CAAC","sourcesContent":["import { formatBytes } from './format-bytes';\n\nexport interface SDSRejectedFile {\n\tfile: File;\n\treason: string;\n\terrorCode: 'type-mismatch' | 'too-large';\n}\n\nexport interface PartitionFilesOptions {\n\taccept?: string;\n\tmaxSizeInBytes?: number;\n\tmultiple?: boolean;\n}\n\n/**\n * Mirrors the native file input's `accept` matching: a token is either an extension (`.pdf`),\n * a MIME wildcard (`image/*`) or an exact MIME type. Matches if any token matches.\n */\nexport function matchesAccept(file: File, accept?: string): boolean {\n\tif (!accept) return true;\n\tconst tokens = accept\n\t\t.split(',')\n\t\t.map((token) => token.trim().toLowerCase())\n\t\t.filter(Boolean);\n\tif (tokens.length === 0) return true;\n\n\tconst fileName = file.name.toLowerCase();\n\tconst mimeType = file.type.toLowerCase();\n\n\treturn tokens.some((token) => {\n\t\tif (token.startsWith('.')) return fileName.endsWith(token);\n\t\tif (token.endsWith('/*')) return mimeType.startsWith(token.slice(0, -1));\n\t\treturn mimeType === token;\n\t});\n}\n\n/**\n * Splits an incoming selection into files that pass validation and files that don't, with a reason.\n * Like the native file input, every selection replaces the current one. Duplicates within the\n * selection (same name, size and last modified) are silently dropped rather than rejected. In\n * single-file mode only the first incoming file is considered.\n */\nexport function partitionFiles(incoming: File[], options: PartitionFilesOptions): { accepted: File[]; rejected: SDSRejectedFile[] } {\n\tconst { accept, maxSizeInBytes, multiple = false } = options;\n\n\tconst accepted: File[] = [];\n\tconst rejected: SDSRejectedFile[] = [];\n\tconst candidates = multiple ? incoming : incoming.slice(0, 1);\n\n\tfor (const file of candidates) {\n\t\tif (!matchesAccept(file, accept)) {\n\t\t\trejected.push({ file, reason: 'Filtypen støttes ikke.', errorCode: 'type-mismatch' });\n\t\t\tcontinue;\n\t\t}\n\t\tif (maxSizeInBytes && file.size > maxSizeInBytes) {\n\t\t\trejected.push({ file, reason: `Filen er for stor. Maks ${formatBytes(maxSizeInBytes)}.`, errorCode: 'too-large' });\n\t\t\tcontinue;\n\t\t}\n\t\tif (!accepted.some((candidate) => isSameFile(candidate, file))) accepted.push(file);\n\t}\n\n\treturn { accepted, rejected };\n}\n\n/**\n * Identity check for files that survives the copies browsers hand out across separate\n * `change`/`drop` events, where reference equality no longer holds.\n */\nexport function isSameFile(a: File, b: File): boolean {\n\treturn a === b || (a.name === b.name && a.size === b.size && a.lastModified === b.lastModified);\n}\n"]}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Formats a byte count as a human-readable string using Norwegian formatting
3
+ * (comma decimal separator), e.g. `7400` → `7,2 kB`.
4
+ */
5
+ export declare function formatBytes(bytes: number): string;
6
+ //# sourceMappingURL=format-bytes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format-bytes.d.ts","sourceRoot":"","sources":["../../src/utils/format-bytes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMjD"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Formats a byte count as a human-readable string using Norwegian formatting
3
+ * (comma decimal separator), e.g. `7400` → `7,2 kB`.
4
+ */
5
+ export function formatBytes(bytes) {
6
+ if (bytes === 0)
7
+ return '0 B';
8
+ const units = ['B', 'kB', 'MB', 'GB'];
9
+ const exponent = Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), units.length - 1);
10
+ const value = bytes / 1024 ** exponent;
11
+ return `${value.toFixed(exponent === 0 ? 0 : 1).replace('.', ',')} ${units[exponent]}`;
12
+ }
13
+ //# sourceMappingURL=format-bytes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format-bytes.js","sourceRoot":"","sources":["../../src/utils/format-bytes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa;IACxC,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC9B,MAAM,KAAK,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IACtC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC1F,MAAM,KAAK,GAAG,KAAK,GAAG,IAAI,IAAI,QAAQ,CAAC;IACvC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;AACxF,CAAC","sourcesContent":["/**\n * Formats a byte count as a human-readable string using Norwegian formatting\n * (comma decimal separator), e.g. `7400` → `7,2 kB`.\n */\nexport function formatBytes(bytes: number): string {\n\tif (bytes === 0) return '0 B';\n\tconst units = ['B', 'kB', 'MB', 'GB'];\n\tconst exponent = Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), units.length - 1);\n\tconst value = bytes / 1024 ** exponent;\n\treturn `${value.toFixed(exponent === 0 ? 0 : 1).replace('.', ',')} ${units[exponent]}`;\n}\n"]}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Generates a square-agnostic still-frame thumbnail for a video file and returns an object URL
3
+ * for the encoded image blob (WebP where supported, otherwise JPEG). The caller owns the URL and
4
+ * must revoke it with `URL.revokeObjectURL` when done. Rejects if the video can't be decoded in
5
+ * time, so callers can fall back to a file icon.
6
+ */
7
+ export declare function generateVideoThumbnail(file: File): Promise<string>;
8
+ //# sourceMappingURL=video-thumbnail.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"video-thumbnail.d.ts","sourceRoot":"","sources":["../../src/utils/video-thumbnail.ts"],"names":[],"mappings":"AAcA;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CA0ElE"}
@@ -0,0 +1,77 @@
1
+ const THUMBNAIL_TIMEOUT_MS = 5000;
2
+ const THUMBNAIL_QUALITY = 0.75;
3
+ let webpSupported;
4
+ function supportsWebpEncoding() {
5
+ if (webpSupported === undefined) {
6
+ const canvas = document.createElement('canvas');
7
+ canvas.width = canvas.height = 1;
8
+ webpSupported = canvas.toDataURL('image/webp').startsWith('data:image/webp');
9
+ }
10
+ return webpSupported;
11
+ }
12
+ /**
13
+ * Generates a square-agnostic still-frame thumbnail for a video file and returns an object URL
14
+ * for the encoded image blob (WebP where supported, otherwise JPEG). The caller owns the URL and
15
+ * must revoke it with `URL.revokeObjectURL` when done. Rejects if the video can't be decoded in
16
+ * time, so callers can fall back to a file icon.
17
+ */
18
+ export function generateVideoThumbnail(file) {
19
+ return new Promise((resolve, reject) => {
20
+ const source = URL.createObjectURL(file);
21
+ const video = document.createElement('video');
22
+ let settled = false;
23
+ const cleanup = () => {
24
+ clearTimeout(timer);
25
+ video.removeAttribute('src');
26
+ video.load();
27
+ URL.revokeObjectURL(source);
28
+ };
29
+ const fail = (error) => {
30
+ if (settled)
31
+ return;
32
+ settled = true;
33
+ cleanup();
34
+ reject(error instanceof Error ? error : new Error(String(error)));
35
+ };
36
+ const succeed = (url) => {
37
+ if (settled) {
38
+ URL.revokeObjectURL(url);
39
+ return;
40
+ }
41
+ settled = true;
42
+ cleanup();
43
+ resolve(url);
44
+ };
45
+ const timer = setTimeout(() => fail(new Error('Video thumbnail generation timed out')), THUMBNAIL_TIMEOUT_MS);
46
+ video.muted = true;
47
+ video.playsInline = true;
48
+ video.preload = 'auto';
49
+ video.addEventListener('error', () => fail(new Error('Video could not be decoded')));
50
+ video.addEventListener('loadeddata', () => {
51
+ // Seek slightly past the start to avoid capturing a black leading frame.
52
+ video.currentTime = Math.min(0.1, (video.duration || 0) / 2);
53
+ }, { once: true });
54
+ video.addEventListener('seeked', () => {
55
+ try {
56
+ const width = video.videoWidth;
57
+ const height = video.videoHeight;
58
+ if (!width || !height)
59
+ throw new Error('Video has no dimensions');
60
+ const canvas = document.createElement('canvas');
61
+ canvas.width = width;
62
+ canvas.height = height;
63
+ const context = canvas.getContext('2d');
64
+ if (!context)
65
+ throw new Error('Canvas 2D context unavailable');
66
+ context.drawImage(video, 0, 0, width, height);
67
+ const type = supportsWebpEncoding() ? 'image/webp' : 'image/jpeg';
68
+ canvas.toBlob((blob) => (blob ? succeed(URL.createObjectURL(blob)) : fail(new Error('Canvas toBlob returned null'))), type, THUMBNAIL_QUALITY);
69
+ }
70
+ catch (error) {
71
+ fail(error);
72
+ }
73
+ }, { once: true });
74
+ video.src = source;
75
+ });
76
+ }
77
+ //# sourceMappingURL=video-thumbnail.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"video-thumbnail.js","sourceRoot":"","sources":["../../src/utils/video-thumbnail.ts"],"names":[],"mappings":"AAAA,MAAM,oBAAoB,GAAG,IAAI,CAAC;AAClC,MAAM,iBAAiB,GAAG,IAAI,CAAC;AAE/B,IAAI,aAAkC,CAAC;AAEvC,SAAS,oBAAoB;IAC5B,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QAChD,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;QACjC,aAAa,GAAG,MAAM,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC;IAC9E,CAAC;IACD,OAAO,aAAa,CAAC;AACtB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CAAC,IAAU;IAChD,OAAO,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC9C,MAAM,MAAM,GAAG,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;QACzC,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;QAC9C,IAAI,OAAO,GAAG,KAAK,CAAC;QAEpB,MAAM,OAAO,GAAG,GAAG,EAAE;YACpB,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,KAAK,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;YAC7B,KAAK,CAAC,IAAI,EAAE,CAAC;YACb,GAAG,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;QAC7B,CAAC,CAAC;QACF,MAAM,IAAI,GAAG,CAAC,KAAc,EAAE,EAAE;YAC/B,IAAI,OAAO;gBAAE,OAAO;YACpB,OAAO,GAAG,IAAI,CAAC;YACf,OAAO,EAAE,CAAC;YACV,MAAM,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACnE,CAAC,CAAC;QACF,MAAM,OAAO,GAAG,CAAC,GAAW,EAAE,EAAE;YAC/B,IAAI,OAAO,EAAE,CAAC;gBACb,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;gBACzB,OAAO;YACR,CAAC;YACD,OAAO,GAAG,IAAI,CAAC;YACf,OAAO,EAAE,CAAC;YACV,OAAO,CAAC,GAAG,CAAC,CAAC;QACd,CAAC,CAAC;QAEF,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC,EAAE,oBAAoB,CAAC,CAAC;QAE9G,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC;QACnB,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC;QACzB,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC;QACvB,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC,CAAC,CAAC;QAErF,KAAK,CAAC,gBAAgB,CACrB,YAAY,EACZ,GAAG,EAAE;YACJ,yEAAyE;YACzE,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAC9D,CAAC,EACD,EAAE,IAAI,EAAE,IAAI,EAAE,CACd,CAAC;QAEF,KAAK,CAAC,gBAAgB,CACrB,QAAQ,EACR,GAAG,EAAE;YACJ,IAAI,CAAC;gBACJ,MAAM,KAAK,GAAG,KAAK,CAAC,UAAU,CAAC;gBAC/B,MAAM,MAAM,GAAG,KAAK,CAAC,WAAW,CAAC;gBACjC,IAAI,CAAC,KAAK,IAAI,CAAC,MAAM;oBAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;gBAElE,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;gBAChD,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;gBACrB,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;gBACvB,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;gBACxC,IAAI,CAAC,OAAO;oBAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;gBAC/D,OAAO,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;gBAE9C,MAAM,IAAI,GAAG,oBAAoB,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC;gBAClE,MAAM,CAAC,MAAM,CACZ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC,CAAC,EACtG,IAAI,EACJ,iBAAiB,CACjB,CAAC;YACH,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAChB,IAAI,CAAC,KAAK,CAAC,CAAC;YACb,CAAC;QACF,CAAC,EACD,EAAE,IAAI,EAAE,IAAI,EAAE,CACd,CAAC;QAEF,KAAK,CAAC,GAAG,GAAG,MAAM,CAAC;IACpB,CAAC,CAAC,CAAC;AACJ,CAAC","sourcesContent":["const THUMBNAIL_TIMEOUT_MS = 5000;\nconst THUMBNAIL_QUALITY = 0.75;\n\nlet webpSupported: boolean | undefined;\n\nfunction supportsWebpEncoding(): boolean {\n\tif (webpSupported === undefined) {\n\t\tconst canvas = document.createElement('canvas');\n\t\tcanvas.width = canvas.height = 1;\n\t\twebpSupported = canvas.toDataURL('image/webp').startsWith('data:image/webp');\n\t}\n\treturn webpSupported;\n}\n\n/**\n * Generates a square-agnostic still-frame thumbnail for a video file and returns an object URL\n * for the encoded image blob (WebP where supported, otherwise JPEG). The caller owns the URL and\n * must revoke it with `URL.revokeObjectURL` when done. Rejects if the video can't be decoded in\n * time, so callers can fall back to a file icon.\n */\nexport function generateVideoThumbnail(file: File): Promise<string> {\n\treturn new Promise<string>((resolve, reject) => {\n\t\tconst source = URL.createObjectURL(file);\n\t\tconst video = document.createElement('video');\n\t\tlet settled = false;\n\n\t\tconst cleanup = () => {\n\t\t\tclearTimeout(timer);\n\t\t\tvideo.removeAttribute('src');\n\t\t\tvideo.load();\n\t\t\tURL.revokeObjectURL(source);\n\t\t};\n\t\tconst fail = (error: unknown) => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tcleanup();\n\t\t\treject(error instanceof Error ? error : new Error(String(error)));\n\t\t};\n\t\tconst succeed = (url: string) => {\n\t\t\tif (settled) {\n\t\t\t\tURL.revokeObjectURL(url);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsettled = true;\n\t\t\tcleanup();\n\t\t\tresolve(url);\n\t\t};\n\n\t\tconst timer = setTimeout(() => fail(new Error('Video thumbnail generation timed out')), THUMBNAIL_TIMEOUT_MS);\n\n\t\tvideo.muted = true;\n\t\tvideo.playsInline = true;\n\t\tvideo.preload = 'auto';\n\t\tvideo.addEventListener('error', () => fail(new Error('Video could not be decoded')));\n\n\t\tvideo.addEventListener(\n\t\t\t'loadeddata',\n\t\t\t() => {\n\t\t\t\t// Seek slightly past the start to avoid capturing a black leading frame.\n\t\t\t\tvideo.currentTime = Math.min(0.1, (video.duration || 0) / 2);\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\n\t\tvideo.addEventListener(\n\t\t\t'seeked',\n\t\t\t() => {\n\t\t\t\ttry {\n\t\t\t\t\tconst width = video.videoWidth;\n\t\t\t\t\tconst height = video.videoHeight;\n\t\t\t\t\tif (!width || !height) throw new Error('Video has no dimensions');\n\n\t\t\t\t\tconst canvas = document.createElement('canvas');\n\t\t\t\t\tcanvas.width = width;\n\t\t\t\t\tcanvas.height = height;\n\t\t\t\t\tconst context = canvas.getContext('2d');\n\t\t\t\t\tif (!context) throw new Error('Canvas 2D context unavailable');\n\t\t\t\t\tcontext.drawImage(video, 0, 0, width, height);\n\n\t\t\t\t\tconst type = supportsWebpEncoding() ? 'image/webp' : 'image/jpeg';\n\t\t\t\t\tcanvas.toBlob(\n\t\t\t\t\t\t(blob) => (blob ? succeed(URL.createObjectURL(blob)) : fail(new Error('Canvas toBlob returned null'))),\n\t\t\t\t\t\ttype,\n\t\t\t\t\t\tTHUMBNAIL_QUALITY,\n\t\t\t\t\t);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tfail(error);\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\n\t\tvideo.src = source;\n\t});\n}\n"]}
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const SDS_VERSION = "2.13.0";
1
+ export declare const SDS_VERSION = "2.14.0";
2
2
  //# sourceMappingURL=version.d.ts.map
package/dist/version.js CHANGED
@@ -1,3 +1,3 @@
1
1
  // Auto-generated by generate-version.cjs — do not edit manually
2
- export const SDS_VERSION = '2.13.0';
2
+ export const SDS_VERSION = '2.14.0';
3
3
  //# sourceMappingURL=version.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,MAAM,CAAC,MAAM,WAAW,GAAG,QAAQ,CAAC","sourcesContent":["// Auto-generated by generate-version.cjs — do not edit manually\nexport const SDS_VERSION = '2.13.0';\n"]}
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,MAAM,CAAC,MAAM,WAAW,GAAG,QAAQ,CAAC","sourcesContent":["// Auto-generated by generate-version.cjs — do not edit manually\nexport const SDS_VERSION = '2.14.0';\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@politiet/sheriff-web-components",
3
- "version": "2.13.0",
3
+ "version": "2.14.0",
4
4
  "description": "Sheriff Design System Web Components Library",
5
5
  "author": "Politiets IT-enhet",
6
6
  "license": "ISC",
@@ -19,6 +19,7 @@
19
19
  "./dist/index.js",
20
20
  "./dist/sds-*/sds-*.js",
21
21
  "./dist/shared/**/positioning.js",
22
+ "./dist/sds-file-upload-item/assets/u-progress.js",
22
23
  "./dist/sheriff-web-components.js"
23
24
  ],
24
25
  "exports": {
@@ -97,6 +98,18 @@
97
98
  "import": "./dist/sds-environment-banner/sds-environment-banner.js",
98
99
  "default": "./dist/sds-environment-banner/sds-environment-banner.js"
99
100
  },
101
+ "./sds-file-upload": {
102
+ "types": "./dist/sds-file-upload/sds-file-upload.d.ts",
103
+ "import": "./dist/sds-file-upload/sds-file-upload.js"
104
+ },
105
+ "./sds-file-upload-item": {
106
+ "types": "./dist/sds-file-upload-item/sds-file-upload-item.d.ts",
107
+ "import": "./dist/sds-file-upload-item/sds-file-upload-item.js"
108
+ },
109
+ "./sds-file-upload-file-list": {
110
+ "types": "./dist/sds-file-upload-file-list/sds-file-upload-file-list.d.ts",
111
+ "import": "./dist/sds-file-upload-file-list/sds-file-upload-file-list.js"
112
+ },
100
113
  "./sds-heading": {
101
114
  "types": "./dist/sds-heading/sds-heading.d.ts",
102
115
  "import": "./dist/sds-heading/sds-heading.js",
@@ -152,6 +165,11 @@
152
165
  "import": "./dist/sds-radio-group/sds-radio-group.js",
153
166
  "default": "./dist/sds-radio-group/sds-radio-group.js"
154
167
  },
168
+ "./sds-search": {
169
+ "types": "./dist/sds-search/sds-search.d.ts",
170
+ "import": "./dist/sds-search/sds-search.js",
171
+ "default": "./dist/sds-search/sds-search.js"
172
+ },
155
173
  "./sds-select": {
156
174
  "types": "./dist/sds-select/sds-select.d.ts",
157
175
  "import": "./dist/sds-select/sds-select.js",
@@ -204,10 +222,11 @@
204
222
  "test:watch": "vitest",
205
223
  "tidy-frameworks": "node ../../../scripts/delete-filetypes-from-folder.js --folder ./dist/frameworks --filetypes js,js.map",
206
224
  "build:component-version": "node generate-version.cjs",
207
- "build": "npm run build:shared && npm run build:popover && npm run build:tooltip && npm run build:component-version && tsc && npm run tidy-frameworks && npm run build:metadata && npm run build:skill",
225
+ "build": "npm run build:shared && npm run build:popover && npm run build:tooltip && npm run build:u-progress && npm run build:component-version && tsc && npm run tidy-frameworks && npm run build:metadata && npm run build:skill",
208
226
  "build:shared": "rollup -c ./src/shared/assets/rollup.config.js",
209
227
  "build:tooltip": "rollup -c ./src/sds-tooltip/assets/rollup.config.js",
210
228
  "build:popover": "rollup -c src/sds-popover/assets/rollup.config.js",
229
+ "build:u-progress": "rollup -c ./src/sds-file-upload-item/assets/rollup.config.js",
211
230
  "build:web-types": "wca-webtypes analyze \"src/sds-*/**/*.ts\" --format webtypes --visibility public --outFile \"web-types.json\"",
212
231
  "build:cem": "cem analyze --config custom-elements-manifest.config.mjs --outdir .",
213
232
  "build:metadata": "npm run build:web-types && npm run build:cem",
@@ -221,7 +240,7 @@
221
240
  "@politiet/sheriff-icons": "^2.1.1"
222
241
  },
223
242
  "peerDependencies": {
224
- "@politiet/sheriff-css-framework": "^2.6.1",
243
+ "@politiet/sheriff-css-framework": "^2.6.2",
225
244
  "typescript": ">=3.8.0"
226
245
  },
227
246
  "peerDependenciesMeta": {
@@ -236,12 +255,13 @@
236
255
  "@digdir/designsystemet-web": "^1.12.1",
237
256
  "@rollup/plugin-node-resolve": "^16.0.3",
238
257
  "@rollup/plugin-terser": "^1.0.0",
258
+ "@u-elements/u-progress": "^1.0.1",
239
259
  "lit-web-types": "^0.1.5",
240
260
  "preact": "^10.26.1",
241
261
  "rollup": "^4.59.0",
242
262
  "solid-js": "^1.9.4",
243
263
  "ts-lit-plugin": "^2.0.2",
244
- "vitest": "^3.2.4",
264
+ "vitest": "^4.1.11",
245
265
  "vue": "^3.5.13",
246
266
  "web-component-analyzer-webtypes": "^2.0.12"
247
267
  },