@politiet/sheriff-web-components 2.13.1 → 2.14.1
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/custom-elements.json +3942 -1450
- package/dist/controllers/index.d.ts +3 -0
- package/dist/controllers/index.d.ts.map +1 -0
- package/dist/controllers/index.js +3 -0
- package/dist/controllers/index.js.map +1 -0
- package/dist/controllers/sds-drag-drop-controller.d.ts +25 -0
- package/dist/controllers/sds-drag-drop-controller.d.ts.map +1 -0
- package/dist/controllers/sds-drag-drop-controller.js +52 -0
- package/dist/controllers/sds-drag-drop-controller.js.map +1 -0
- package/dist/controllers/sds-file-preview-controller.d.ts +38 -0
- package/dist/controllers/sds-file-preview-controller.d.ts.map +1 -0
- package/dist/controllers/sds-file-preview-controller.js +90 -0
- package/dist/controllers/sds-file-preview-controller.js.map +1 -0
- package/dist/frameworks/preact.d.ts +15 -1
- package/dist/frameworks/preact.d.ts.map +1 -1
- package/dist/frameworks/react.d.ts +33 -1
- package/dist/frameworks/react.d.ts.map +1 -1
- package/dist/frameworks/solidjs.d.ts +4 -0
- package/dist/frameworks/solidjs.d.ts.map +1 -1
- package/dist/frameworks/svelte.d.ts +4 -0
- package/dist/frameworks/svelte.d.ts.map +1 -1
- package/dist/frameworks/vue.d.ts +24 -1
- package/dist/frameworks/vue.d.ts.map +1 -1
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/react-wrappers/SDSDialogWrapper.d.ts +1 -0
- package/dist/react-wrappers/SDSDialogWrapper.d.ts.map +1 -1
- package/dist/react-wrappers/SDSDialogWrapper.js +1 -0
- package/dist/react-wrappers/SDSDialogWrapper.js.map +1 -1
- package/dist/react-wrappers/SDSFileUploadFileListWrapper.d.ts +3 -0
- package/dist/react-wrappers/SDSFileUploadFileListWrapper.d.ts.map +1 -0
- package/dist/react-wrappers/SDSFileUploadFileListWrapper.js +10 -0
- package/dist/react-wrappers/SDSFileUploadFileListWrapper.js.map +1 -0
- package/dist/react-wrappers/SDSFileUploadItemWrapper.d.ts +6 -0
- package/dist/react-wrappers/SDSFileUploadItemWrapper.d.ts.map +1 -0
- package/dist/react-wrappers/SDSFileUploadItemWrapper.js +12 -0
- package/dist/react-wrappers/SDSFileUploadItemWrapper.js.map +1 -0
- package/dist/react-wrappers/SDSFileUploadWrapper.d.ts +12 -0
- package/dist/react-wrappers/SDSFileUploadWrapper.d.ts.map +1 -0
- package/dist/react-wrappers/SDSFileUploadWrapper.js +18 -0
- package/dist/react-wrappers/SDSFileUploadWrapper.js.map +1 -0
- package/dist/react-wrappers/SDSSearchWrapper.d.ts +15 -0
- package/dist/react-wrappers/SDSSearchWrapper.d.ts.map +1 -0
- package/dist/react-wrappers/SDSSearchWrapper.js +19 -0
- package/dist/react-wrappers/SDSSearchWrapper.js.map +1 -0
- package/dist/react-wrappers/SDSStepperStepWrapper.d.ts +4 -1
- package/dist/react-wrappers/SDSStepperStepWrapper.d.ts.map +1 -1
- package/dist/react-wrappers/SDSStepperStepWrapper.js +3 -1
- package/dist/react-wrappers/SDSStepperStepWrapper.js.map +1 -1
- package/dist/react-wrappers/index.d.ts +4 -0
- package/dist/react-wrappers/index.d.ts.map +1 -1
- package/dist/react-wrappers/index.js +4 -0
- package/dist/react-wrappers/index.js.map +1 -1
- package/dist/sds-alert/sds-alert.styles.js +1 -1
- package/dist/sds-alert/sds-alert.styles.js.map +1 -1
- package/dist/sds-button/sds-button.component.d.ts +0 -1
- package/dist/sds-button/sds-button.component.d.ts.map +1 -1
- package/dist/sds-button/sds-button.component.js +10 -16
- package/dist/sds-button/sds-button.component.js.map +1 -1
- package/dist/sds-checkbox/sds-checkbox.styles.d.ts.map +1 -1
- package/dist/sds-checkbox/sds-checkbox.styles.js +6 -0
- package/dist/sds-checkbox/sds-checkbox.styles.js.map +1 -1
- package/dist/sds-dialog/sds-dialog.component.d.ts.map +1 -1
- package/dist/sds-dialog/sds-dialog.component.js +11 -1
- package/dist/sds-dialog/sds-dialog.component.js.map +1 -1
- package/dist/sds-file-upload/sds-file-upload.d.ts +102 -0
- package/dist/sds-file-upload/sds-file-upload.d.ts.map +1 -0
- package/dist/sds-file-upload/sds-file-upload.js +384 -0
- package/dist/sds-file-upload/sds-file-upload.js.map +1 -0
- package/dist/sds-file-upload/sds-file-upload.styles.d.ts +2 -0
- package/dist/sds-file-upload/sds-file-upload.styles.d.ts.map +1 -0
- package/dist/sds-file-upload/sds-file-upload.styles.js +234 -0
- package/dist/sds-file-upload/sds-file-upload.styles.js.map +1 -0
- package/dist/sds-file-upload-file-list/sds-file-upload-file-list.d.ts +14 -0
- package/dist/sds-file-upload-file-list/sds-file-upload-file-list.d.ts.map +1 -0
- package/dist/sds-file-upload-file-list/sds-file-upload-file-list.js +26 -0
- package/dist/sds-file-upload-file-list/sds-file-upload-file-list.js.map +1 -0
- package/dist/sds-file-upload-file-list/sds-file-upload-file-list.styles.d.ts +2 -0
- package/dist/sds-file-upload-file-list/sds-file-upload-file-list.styles.d.ts.map +1 -0
- package/dist/sds-file-upload-file-list/sds-file-upload-file-list.styles.js +19 -0
- package/dist/sds-file-upload-file-list/sds-file-upload-file-list.styles.js.map +1 -0
- package/dist/sds-file-upload-item/assets/u-progress.js +2 -0
- package/dist/sds-file-upload-item/sds-file-upload-item.d.ts +62 -0
- package/dist/sds-file-upload-item/sds-file-upload-item.d.ts.map +1 -0
- package/dist/sds-file-upload-item/sds-file-upload-item.js +205 -0
- package/dist/sds-file-upload-item/sds-file-upload-item.js.map +1 -0
- package/dist/sds-file-upload-item/sds-file-upload-item.styles.d.ts +2 -0
- package/dist/sds-file-upload-item/sds-file-upload-item.styles.d.ts.map +1 -0
- package/dist/sds-file-upload-item/sds-file-upload-item.styles.js +227 -0
- package/dist/sds-file-upload-item/sds-file-upload-item.styles.js.map +1 -0
- package/dist/sds-icon/sds-icon.system.js +7 -7
- package/dist/sds-icon/sds-icon.system.js.map +1 -1
- package/dist/sds-internal-header/sds-internal-header.component.js +1 -1
- package/dist/sds-internal-header/sds-internal-header.component.js.map +1 -1
- package/dist/sds-internal-header/sds-internal-header.styles.js +1 -1
- package/dist/sds-internal-header/sds-internal-header.styles.js.map +1 -1
- package/dist/sds-notification/sds-notification.styles.js +1 -1
- package/dist/sds-notification/sds-notification.styles.js.map +1 -1
- package/dist/sds-popover/assets/popover-styles.d.ts.map +1 -1
- package/dist/sds-popover/assets/popover-styles.js +1 -1
- package/dist/sds-popover/assets/popover-styles.js.map +1 -1
- package/dist/sds-radio/sds-radio.styles.d.ts.map +1 -1
- package/dist/sds-radio/sds-radio.styles.js +6 -1
- package/dist/sds-radio/sds-radio.styles.js.map +1 -1
- package/dist/sds-search/sds-search.component.d.ts +128 -0
- package/dist/sds-search/sds-search.component.d.ts.map +1 -0
- package/dist/sds-search/sds-search.component.js +345 -0
- package/dist/sds-search/sds-search.component.js.map +1 -0
- package/dist/sds-search/sds-search.d.ts +13 -0
- package/dist/sds-search/sds-search.d.ts.map +1 -0
- package/dist/sds-search/sds-search.js +18 -0
- package/dist/sds-search/sds-search.js.map +1 -0
- package/dist/sds-search/sds-search.styles.d.ts +2 -0
- package/dist/sds-search/sds-search.styles.d.ts.map +1 -0
- package/dist/sds-search/sds-search.styles.js +74 -0
- package/dist/sds-search/sds-search.styles.js.map +1 -0
- package/dist/sds-stepper-step/sds-stepper-step.d.ts +3 -0
- package/dist/sds-stepper-step/sds-stepper-step.d.ts.map +1 -1
- package/dist/sds-stepper-step/sds-stepper-step.js +4 -3
- package/dist/sds-stepper-step/sds-stepper-step.js.map +1 -1
- package/dist/sds-stepper-step/sds-stepper-step.styles.js +3 -3
- package/dist/sds-stepper-step/sds-stepper-step.styles.js.map +1 -1
- package/dist/sds-textfield/sds-textfield.component.d.ts +4 -1
- package/dist/sds-textfield/sds-textfield.component.d.ts.map +1 -1
- package/dist/sds-textfield/sds-textfield.component.js +20 -5
- package/dist/sds-textfield/sds-textfield.component.js.map +1 -1
- package/dist/sds-textfield/sds-textfield.styles.d.ts.map +1 -1
- package/dist/sds-textfield/sds-textfield.styles.js +11 -0
- package/dist/sds-textfield/sds-textfield.styles.js.map +1 -1
- package/dist/sds-tooltip/assets/tooltip-styles.d.ts.map +1 -1
- package/dist/sds-tooltip/assets/tooltip-styles.js +1 -1
- package/dist/sds-tooltip/assets/tooltip-styles.js.map +1 -1
- package/dist/sds-tooltip/sds-tooltip.d.ts.map +1 -1
- package/dist/sds-tooltip/sds-tooltip.js +1 -1
- package/dist/sds-tooltip/sds-tooltip.js.map +1 -1
- package/dist/shared/assets/positioning.js +1 -1
- package/dist/sheriff-web-components.js +1103 -371
- package/dist/skill/SKILL.md +61 -50
- package/dist/skill/references/components.md +91 -3
- package/dist/skill/references/react-wrappers.md +28 -19
- package/dist/utils/file-validation.d.ts +31 -0
- package/dist/utils/file-validation.d.ts.map +1 -0
- package/dist/utils/file-validation.js +57 -0
- package/dist/utils/file-validation.js.map +1 -0
- package/dist/utils/format-bytes.d.ts +6 -0
- package/dist/utils/format-bytes.d.ts.map +1 -0
- package/dist/utils/format-bytes.js +13 -0
- package/dist/utils/format-bytes.js.map +1 -0
- package/dist/utils/video-thumbnail.d.ts +8 -0
- package/dist/utils/video-thumbnail.d.ts.map +1 -0
- package/dist/utils/video-thumbnail.js +77 -0
- package/dist/utils/video-thumbnail.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +27 -7
- package/web-types.json +3437 -1120
package/dist/skill/SKILL.md
CHANGED
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
name: sheriff-web-components
|
|
3
3
|
description: >
|
|
4
4
|
Assists developers using @politiet/sheriff-web-components made of Lit-based custom
|
|
5
|
-
elements with the sds-* prefix. Covers all
|
|
5
|
+
elements with the sds-* prefix. Covers all 33 components (alert, button, card,
|
|
6
6
|
checkbox, checkbox-group, chip, details, details-group, dialog,
|
|
7
|
-
environment-banner,
|
|
8
|
-
|
|
7
|
+
environment-banner, file-upload, file-upload-item, file-upload-file-list,
|
|
8
|
+
heading, icon, internal-header, loader, notification,
|
|
9
|
+
popover, process, process-step, radio, radio-group, search, select, stepper,
|
|
9
10
|
stepper-step, switch, tag, text, textarea, textfield, tooltip), React
|
|
10
11
|
wrappers, framework type definitions, form-associated elements, slots,
|
|
11
12
|
events, and data-palette theming. Use when the user references sds-*
|
|
@@ -19,11 +20,11 @@ description: >
|
|
|
19
20
|
|
|
20
21
|
When looking up component details not covered here, read the source directly:
|
|
21
22
|
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
23
|
+
- Most components: `packages/sheriff/web-components/src/sds-{name}/sds-{name}.ts`
|
|
24
|
+
- Exception components (alert, button, dialog, environment-banner, heading, icon, internal-header, select, text, textfield): `packages/sheriff/web-components/src/sds-{name}/sds-{name}.component.ts`
|
|
25
|
+
- Styles and CSS custom properties: `packages/sheriff/web-components/src/sds-{name}/sds-{name}.styles.ts`
|
|
26
|
+
- Usage examples: `packages/sheriff/web-components/src/sds-{name}/sds-{name}.stories.ts`
|
|
27
|
+
- Documentation: `packages/sheriff/web-components/src/sds-{name}/sds-{name}.mdx`, `variables.mdx` (CSS variables), `guidelines.mdx` (design guidance)
|
|
27
28
|
|
|
28
29
|
Inside an installed package the same files live under `node_modules/@politiet/sheriff-web-components/dist/sds-{name}/`.
|
|
29
30
|
|
|
@@ -78,37 +79,41 @@ Every component has its own subpath export matching its tag name (`./sds-alert`
|
|
|
78
79
|
|
|
79
80
|
All components use the `sds-` prefix. Sizes are `"lg"` | `"md"` | `"sm"`, default `"md"` — **except `sds-button`, which defaults to `"lg"`**. `sds-heading` and `sds-text` use the wider `"xl" | "lg" | "md" | "sm" | "xs"` scale.
|
|
80
81
|
|
|
81
|
-
| Component
|
|
82
|
-
|
|
|
83
|
-
| `sds-alert`
|
|
84
|
-
| `sds-button`
|
|
85
|
-
| `sds-card`
|
|
86
|
-
| `sds-checkbox`
|
|
87
|
-
| `sds-checkbox-group`
|
|
88
|
-
| `sds-chip`
|
|
89
|
-
| `sds-details`
|
|
90
|
-
| `sds-details-group`
|
|
91
|
-
| `sds-dialog`
|
|
92
|
-
| `sds-environment-banner`
|
|
93
|
-
| `sds-
|
|
94
|
-
| `sds-
|
|
95
|
-
| `sds-
|
|
96
|
-
| `sds-
|
|
97
|
-
| `sds-
|
|
98
|
-
| `sds-
|
|
99
|
-
| `sds-
|
|
100
|
-
| `sds-
|
|
101
|
-
| `sds-
|
|
102
|
-
| `sds-
|
|
103
|
-
| `sds-
|
|
104
|
-
| `sds-
|
|
105
|
-
| `sds-
|
|
106
|
-
| `sds-
|
|
107
|
-
| `sds-
|
|
108
|
-
| `sds-
|
|
109
|
-
| `sds-
|
|
110
|
-
| `sds-
|
|
111
|
-
| `sds-
|
|
82
|
+
| Component | Description | Key Props |
|
|
83
|
+
| --------------------------- | -------------------------------------------- | ------------------------------------------------------------------------------------------------ |
|
|
84
|
+
| `sds-alert` | Contextual alert banner | `variant`, `size`, `removable-label`, `data-palette` |
|
|
85
|
+
| `sds-button` | Button or link-as-button | `variant`, `size`, `type`, `disabled`, `loading`, `icon`, `inverted`, `label`, `href`, `command` |
|
|
86
|
+
| `sds-card` | Content container; link card when `link` set | `link` |
|
|
87
|
+
| `sds-checkbox` | Single checkbox | `label`, `name`, `value`, `checked`, `error`, `help-text` |
|
|
88
|
+
| `sds-checkbox-group` | Grouped checkboxes with legend | `legend`, `error-message`, `help-text` |
|
|
89
|
+
| `sds-chip` | Selectable or removable chip/pill | `variant`, `checked`, `name`, `value`, `size` |
|
|
90
|
+
| `sds-details` | Expandable accordion | `open`, `standalone`, `name` (exclusive group) |
|
|
91
|
+
| `sds-details-group` | Wraps `sds-details` into one accordion group | `outlined`, `name` (makes the group exclusive) |
|
|
92
|
+
| `sds-dialog` | Modal/dialog wrapping native `<dialog>` | `open`, `modal`, `closedby`, `close-button-label` |
|
|
93
|
+
| `sds-environment-banner` | Environment/build strip for internal apps | `env`, `build` |
|
|
94
|
+
| `sds-file-upload` | File picker with drag and drop (beta) | `name`, `accept`, `multiple`, `max-size-in-bytes`, `error-message`, `hide-file-list` |
|
|
95
|
+
| `sds-file-upload-item` | One file row with remove button and progress | `file`, `size-in-bytes`, `uploaded-percent`, `error-message`, `for` |
|
|
96
|
+
| `sds-file-upload-file-list` | List container for `sds-file-upload-item` | — |
|
|
97
|
+
| `sds-heading` | Semantic heading | `level`, `size` |
|
|
98
|
+
| `sds-icon` | Dynamic SVG icon | `name`, `size`, `label`, `color` |
|
|
99
|
+
| `sds-internal-header` | App header for internal (non-public) apps | `app-name`, `home-href` |
|
|
100
|
+
| `sds-loader` | Loading spinner | `size`, `contrast` |
|
|
101
|
+
| `sds-notification` | **Deprecated** — use `sds-alert` | `variant`, `removable-label` |
|
|
102
|
+
| `sds-popover` | Anchored popover built on the Popover API | `placement`, `autoplacement`, `overscroll` |
|
|
103
|
+
| `sds-process` | Timeline / process list | `heading-level` |
|
|
104
|
+
| `sds-process-step` | Individual step in a process | `heading`, `timestamp` |
|
|
105
|
+
| `sds-radio` | Single radio button | `label`, `name`, `value`, `checked`, `hide-label` |
|
|
106
|
+
| `sds-radio-group` | Grouped radios with legend | `legend`, `direction`, `error-message` |
|
|
107
|
+
| `sds-search` | Search field with search button | `label`, `hide-label`, `name`, `button-variant` |
|
|
108
|
+
| `sds-select` | Dropdown select | `label`, `name`, `default-value`, `error-message` |
|
|
109
|
+
| `sds-stepper` | Step indicator for multi-step flows | `orientation` |
|
|
110
|
+
| `sds-stepper-step` | Individual step in a stepper | `complete`, `interactive`, `active` |
|
|
111
|
+
| `sds-switch` | Toggle switch | `label`, `name`, `checked`, `reverse`, `hide-label` |
|
|
112
|
+
| `sds-tag` | Non-interactive label/badge | `size`, `data-palette` |
|
|
113
|
+
| `sds-text` | Text container with typography | `size`, `strong`, `subtle`, `tall` |
|
|
114
|
+
| `sds-textarea` | Multi-line text input | `label`, `name`, `counter`, `autosize`, `error-message` |
|
|
115
|
+
| `sds-textfield` | Single-line text input | `label`, `hide-label`, `name`, `type`, `error-message` |
|
|
116
|
+
| `sds-tooltip` | Hover/focus tooltip anchored to a trigger | `id` (required), `placement` |
|
|
112
117
|
|
|
113
118
|
For full component API (all props, slots, events, code examples), see `references/components.md`.
|
|
114
119
|
|
|
@@ -116,15 +121,15 @@ For full component API (all props, slots, events, code examples), see `reference
|
|
|
116
121
|
|
|
117
122
|
`data-palette` works on **every** component and is inherited from any ancestor container, with three exceptions:
|
|
118
123
|
|
|
119
|
-
-
|
|
120
|
-
-
|
|
121
|
-
-
|
|
124
|
+
- `sds-alert`: `data-palette` is a typed component property, so it must be set **on the alert itself** (it does not inherit from a container). Accepted values are only `info` | `success` | `attention` | `danger`; it also selects the alert's status icon.
|
|
125
|
+
- `sds-tooltip` and `sds-environment-banner`: fixed colors, palette has no effect. The environment banner colors itself from `env`.
|
|
126
|
+
- `sds-loader`: the palette variant is designed for a loader sitting **on** a palette-colored surface. Add `contrast` to flip it back for a plain background.
|
|
122
127
|
|
|
123
128
|
`sds-tag` additionally accepts `data-palette="danger-action"` (deep red), which is not a general framework palette.
|
|
124
129
|
|
|
125
130
|
## Form-Associated Components
|
|
126
131
|
|
|
127
|
-
`sds-button`, `sds-checkbox`, `sds-chip`, `sds-radio`, `sds-select`, `sds-switch`, `sds-textarea`, and `sds-textfield` are form-associated: they participate in `<form>` submission, validation, and reset without extra wiring. Set both `name` and `value` for the value to be submitted. `sds-switch` submits `"on"` / `"off"`.
|
|
132
|
+
`sds-button`, `sds-checkbox`, `sds-chip`, `sds-file-upload`, `sds-radio`, `sds-search`, `sds-select`, `sds-switch`, `sds-textarea`, and `sds-textfield` are form-associated: they participate in `<form>` submission, validation, and reset without extra wiring. Set both `name` and `value` for the value to be submitted. `sds-switch` submits `"on"` / `"off"`. `sds-file-upload` only needs `name` and submits the selected files, and it has no `readonly`.
|
|
128
133
|
|
|
129
134
|
Shared props from the form-control mixin: `name`, `disabled`, `readonly`. In a `sds-checkbox-group` / `sds-radio-group`, setting `disabled` or `readonly` on the group propagates to children unless the child sets it explicitly.
|
|
130
135
|
|
|
@@ -140,6 +145,8 @@ Shared props from the form-control mixin: `name`, `disabled`, `readonly`. In a `
|
|
|
140
145
|
|
|
141
146
|
The attribute is the default slot content, so use one or the other — not both.
|
|
142
147
|
|
|
148
|
+
`sds-file-upload` has **only** the `label` slot, no `label` attribute.
|
|
149
|
+
|
|
143
150
|
## React Wrappers
|
|
144
151
|
|
|
145
152
|
React versions before v19 do not natively handle web component events. Use the provided wrappers from `@politiet/sheriff-web-components/react-wrappers`:
|
|
@@ -159,7 +166,10 @@ function MyForm() {
|
|
|
159
166
|
}
|
|
160
167
|
```
|
|
161
168
|
|
|
162
|
-
React 19+ supports custom elements natively
|
|
169
|
+
React 19+ supports custom elements natively and can use web components directly without wrappers.
|
|
170
|
+
Event props on raw elements must match the event name exactly: `onclose`, `oncancel`, `ontoggle`, `onclick` (lowercase).
|
|
171
|
+
React treats camelCase `onClose`/`onCancel`/`onToggle` as its own synthetic events and never fires them on custom elements.
|
|
172
|
+
hey are only typed for backwards compatibility and marked deprecated.
|
|
163
173
|
|
|
164
174
|
For the full list of available wrappers and event mappings, see `references/react-wrappers.md`.
|
|
165
175
|
|
|
@@ -250,9 +260,10 @@ Put the accessible name on the button via `label` (it becomes `aria-label` on th
|
|
|
250
260
|
|
|
251
261
|
## Error Handling
|
|
252
262
|
|
|
253
|
-
-
|
|
254
|
-
-
|
|
255
|
-
-
|
|
256
|
-
-
|
|
257
|
-
-
|
|
258
|
-
-
|
|
263
|
+
- **Component does not render or render weird**: Verify the CSS framework is imported. This is needed for CSS custom properties.
|
|
264
|
+
- **Events do not fire in React (pre-v19)**: Confirm React wrappers are used instead of web components.
|
|
265
|
+
- **`onClose`/`onToggle` never fires in React 19**: On raw `sds-*` elements use lowercase `onclose`/`ontoggle`/`oncancel`, or use the wrapper, where camelCase is correct. The same applies to `click` on `sds-stepper-step`: use `onclick` on the raw element, `onClick` on `SDSStepperStepWrapper`.
|
|
266
|
+
- **Event listener never fires**: Check the exact event name in `references/components.md`. `sds-details`/`sds-popover`/`sds-tooltip` dispatch `toggle` (not `sds-toggle`) and `sds-dialog` dispatches `close` (not `sds-close`, which is deprecated).
|
|
267
|
+
- **Icons do not load**: Check the icon name format (`{name}-{source}-{variant}`) and network access to jsDelivr CDN. If in secure/isolated network, use Artifactory. If needed, see `@politiet/sheriff-icons` for icon skill.
|
|
268
|
+
- **Form values not submitted**: Ensure the component has both `name` and `value` attributes set.
|
|
269
|
+
- **`data-palette` seems ignored**: On `sds-alert` it must be set on the element itself, and only `info`/`success`/`attention`/`danger` are valid. `sds-tooltip` and `sds-environment-banner` do not support palettes.
|
|
@@ -278,7 +278,7 @@ Modal/dialog wrapping native `<dialog>`.
|
|
|
278
278
|
|
|
279
279
|
**Props:** `open`, `modal`, `closedby` (`"none"` | `"closerequest"` | `"any"`, default `"closerequest"`), `close-button-label` (default `"Lukk dialogvindu"`, empty string hides the built-in close button)
|
|
280
280
|
**Slots:** `header`, default (body), `footer`
|
|
281
|
-
**Events:** `close
|
|
281
|
+
**Events:** `close`, `cancel` (fires before the dialog closes via ESC, outside click or `requestClose()`; call `preventDefault()` to keep it open). `sds-close` still fires but is **deprecated** — listening for it logs a console warning and it is removed in the next major.
|
|
282
282
|
**Methods:** `show()`, `showModal()` (also sets `modal`), `close()`, `requestClose()`
|
|
283
283
|
**Notes:**
|
|
284
284
|
|
|
@@ -286,6 +286,7 @@ Modal/dialog wrapping native `<dialog>`.
|
|
|
286
286
|
- `command="show-modal"` requires `commandfor="{dialog id}"` and wires `aria-haspopup`/`aria-expanded`/`aria-controls` on the trigger.
|
|
287
287
|
- `closedby="any"` includes a Safari polyfill for outside clicks.
|
|
288
288
|
- An element in the default slot carrying `autofocus` receives focus once the open animation ends.
|
|
289
|
+
- `close` bubbles, so a listener on an outer dialog also receives it from a nested dialog. Check `event.target === event.currentTarget` when nesting. `cancel` does not bubble, matching the native event.
|
|
289
290
|
|
|
290
291
|
---
|
|
291
292
|
|
|
@@ -303,6 +304,68 @@ Thin strip identifying the running environment and build, for internal apps. Sou
|
|
|
303
304
|
|
|
304
305
|
---
|
|
305
306
|
|
|
307
|
+
## sds-file-upload
|
|
308
|
+
|
|
309
|
+
File picker with drag and drop and a built-in list of selected files. Form-associated. **Beta** — larger API changes may still happen.
|
|
310
|
+
|
|
311
|
+
```html
|
|
312
|
+
<sds-file-upload name="attachments" multiple accept=".pdf,image/*" max-size-in-bytes="10485760" file-limitation-text="PDF eller bilde, maks 10 MB">
|
|
313
|
+
<span slot="label">Vedlegg</span>
|
|
314
|
+
</sds-file-upload>
|
|
315
|
+
|
|
316
|
+
<sds-file-upload name="cv" variant="compact" size="sm" required>
|
|
317
|
+
<span slot="label">CV</span>
|
|
318
|
+
</sds-file-upload>
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
**Props:** `name`, `label`, `accept` (same syntax as native: extensions, `image/*`, exact MIME types), `multiple`, `required`, `disabled`, `max-size-in-bytes`, `help-text`, `error-message`, `file-limitation-text`, `hide-file-list`, `variant` (`"default"` | `"compact"`), `size`
|
|
322
|
+
**Slots:** `label` (alternative to the `label` attribute, wins if both are set). Without a label, the input is named "Velg fil" / "Velg filer".
|
|
323
|
+
**Events:**
|
|
324
|
+
|
|
325
|
+
- `input`, `change` — the accepted selection changed (picked, dropped, removed or cleared). `input` fires right before `change`.
|
|
326
|
+
- `cancel` — the user closed the file picker without choosing anything. Not cancelable.
|
|
327
|
+
- `focus`, `blur`
|
|
328
|
+
- `sds-reject` — detail `{ rejected: { file, reason, errorCode }[] }`, `errorCode` is `"type-mismatch"` | `"too-large"`. `reason` is a Norwegian message.
|
|
329
|
+
- `sds-preview-ready` — detail `{ file, url }`, fired when an image or video thumbnail is ready.
|
|
330
|
+
|
|
331
|
+
**Properties and methods:** `files` (`File[]`, read-only), `rejectedFiles` (`{ file, reason, errorCode }[]`, read-only), `value` (`C:\fakepath\…` of the first file; only `""` may be assigned, which clears, other values throw), `removeFile(file)`, `clear()`, `dismissRejected(file)`, `getPreviewUrl(file)`, `focus()`, `blur()`, `checkValidity()`, `reportValidity()`, `setCustomValidity(message)`
|
|
332
|
+
**Notes:**
|
|
333
|
+
|
|
334
|
+
- Behaves like `<input type="file">`: a single-file selection always replaces the previous one, even if the new file is rejected. The same goes for `multiple`: every new selection replaces the previous files. Duplicates within a selection (same name, size and last modified) are dropped.
|
|
335
|
+
- Submits every accepted file under `name` as `FormData`, or an empty `File` when nothing is selected, like native. There is no `value` attribute to set, and no `readonly`.
|
|
336
|
+
- Constraint errors (`required`) use the native validation bubble. `setCustomValidity(message)` sets `error-message`.
|
|
337
|
+
- Don't call `URL.revokeObjectURL` on URLs from `getPreviewUrl()` or `sds-preview-ready` — the component cleans them up.
|
|
338
|
+
- Rejected files show in the built-in list with "Feil ved opplasting" and the `reason` as the error message.
|
|
339
|
+
|
|
340
|
+
### sds-file-upload-item
|
|
341
|
+
|
|
342
|
+
One file row: icon or thumbnail, name, size, a remove button and optional upload progress. Used by the built-in list, and for building your own list.
|
|
343
|
+
|
|
344
|
+
**Props:** `file` (file name), `size-in-bytes`, `error-message`, `preview` (image URL), `uploaded-percent` (shows a progress bar while set), `uploaded-size-in-bytes`, `disabled`, `for` (`id` of the owning `sds-file-upload`)
|
|
345
|
+
**Slots:** `actions-end` (extra buttons, placed before the remove button)
|
|
346
|
+
**Events:** `sds-remove` (cancelable) — fired when the remove button is pressed.
|
|
347
|
+
**Note:** Without `for`, listen for `sds-remove` and call `removeFile(file)` (or `dismissRejected(file)` for an item with `error-message`) on the upload yourself. With `for`, the item does that and removes itself from the DOM; `preventDefault()` on `sds-remove` cancels both. `disabled` doesn't reach buttons in `actions-end`, so disable those yourself, and include the file name in their labels (`label="Last ned rapport.pdf"`).
|
|
348
|
+
|
|
349
|
+
### sds-file-upload-file-list
|
|
350
|
+
|
|
351
|
+
List container (`role="list"`) for `sds-file-upload-item` children. No props or events.
|
|
352
|
+
|
|
353
|
+
**Slots:** default (`sds-file-upload-item` children)
|
|
354
|
+
|
|
355
|
+
Custom file list — set `hide-file-list` on the upload and render the items yourself, for example to show upload progress:
|
|
356
|
+
|
|
357
|
+
```html
|
|
358
|
+
<sds-file-upload id="docs" name="docs" multiple hide-file-list>
|
|
359
|
+
<span slot="label">Dokumenter</span>
|
|
360
|
+
</sds-file-upload>
|
|
361
|
+
|
|
362
|
+
<sds-file-upload-file-list>
|
|
363
|
+
<sds-file-upload-item for="docs" file="rapport.pdf" size-in-bytes="482133" uploaded-percent="40"></sds-file-upload-item>
|
|
364
|
+
</sds-file-upload-file-list>
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
306
369
|
## sds-heading
|
|
307
370
|
|
|
308
371
|
Semantic heading. Source: `sds-heading.component.ts`.
|
|
@@ -512,6 +575,28 @@ Groups radio buttons with shared legend and validation.
|
|
|
512
575
|
|
|
513
576
|
---
|
|
514
577
|
|
|
578
|
+
## sds-search
|
|
579
|
+
|
|
580
|
+
Search field: an `sds-textfield` (`type="search"`) and an icon button, shoulder to shoulder.
|
|
581
|
+
|
|
582
|
+
```html
|
|
583
|
+
<search aria-label="Registersøk">
|
|
584
|
+
<form action="/sok">
|
|
585
|
+
<sds-search label="Søk i registeret" hide-label name="q"></sds-search>
|
|
586
|
+
</form>
|
|
587
|
+
</search>
|
|
588
|
+
|
|
589
|
+
<sds-search label="Søk" button-variant="secondary"></sds-search>
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
**Props:** `label`, `hide-label`, `name`, `value`, `placeholder`, `disabled`, `readonly`, `error-message`, `help-text`, `size`, `button-label` (default `"Søk"`), `button-variant`, `required`, `minlength`, `maxlength`, `pattern`, `autocomplete` (forwarded to the inner input)
|
|
593
|
+
**Slots:** `label` (rich label content, takes precedence over the `label` prop), `button` (replaces the default icon button; the slotted control owns its own click, `disabled` and form submission)
|
|
594
|
+
**Events:** `search` (detail `{ value }`, cancelable), `input`, `change`, `select`, `keydown` (cancelling Enter prevents `search`), `focus`, `blur`, `invalid`. `focus`/`blur` fire when focus enters or leaves the component as a whole, not when it moves between the field and the button.
|
|
595
|
+
**Methods:** `focus()`, `blur()`, `select()`, `setSelectionRange()`, `selectionStart`/`selectionEnd`, `checkValidity()`, `reportValidity()`, `setCustomValidity()`, plus `validity`, `validationMessage`, `willValidate`.
|
|
596
|
+
**Note:** Clicking the button or pressing Enter validates the field (unless the form has `novalidate`), emits `search` if it is valid, then submits the surrounding form unless `search` was cancelled with `preventDefault()`. Always set `label`; use `hide-label` to hide it visually. The placeholder is not an accessible name. In React/Preact JSX without the wrapper, the listener must be lowercase: `onsearch`.
|
|
597
|
+
|
|
598
|
+
---
|
|
599
|
+
|
|
515
600
|
## sds-select
|
|
516
601
|
|
|
517
602
|
Dropdown select using native `<option>`/`<optgroup>` elements.
|
|
@@ -574,7 +659,10 @@ Step indicator for multi-step flows. Contains `sds-stepper-step` children. Gets
|
|
|
574
659
|
|
|
575
660
|
**Props:** `complete`, `interactive` (clickable), `active` (current step)
|
|
576
661
|
**Slots:** default (label text)
|
|
662
|
+
**Events:** `click` (native `MouseEvent`)
|
|
577
663
|
**Note:** Step numbers are generated automatically from the child order.
|
|
664
|
+
**Note:** `click` fires on every step, interactive or not, and also when an `interactive` step is activated with Enter or Space. Inside an `sds-stepper` the stepper's `change` fires first, so the step is already active by the time `click` arrives. The event bubbles, so a listener on `sds-stepper` sees it with `target` set to the clicked `sds-stepper-step`.
|
|
665
|
+
**React/Preact:** On a raw `<sds-stepper-step>` write the listener lowercase, `onclick`. CamelCase `onClick` is React's own synthetic event and is typed as deprecated. With `SDSStepperStepWrapper` the prop is `onClick`.
|
|
578
666
|
|
|
579
667
|
---
|
|
580
668
|
|
|
@@ -665,7 +753,7 @@ Single-line text input.
|
|
|
665
753
|
<sds-textfield label="ID" name="id" value="12345" readonly></sds-textfield>
|
|
666
754
|
```
|
|
667
755
|
|
|
668
|
-
**Props:** `label`, `name`, `value`, `type` (HTML input types), `placeholder`, `disabled`, `readonly`, `required`, `autocomplete`, `pattern`, `minlength`, `maxlength`, `min`, `max`, `help-text`, `error-message`, `size`
|
|
756
|
+
**Props:** `label`, `hide-label`, `name`, `value`, `type` (HTML input types), `placeholder`, `disabled`, `readonly`, `required`, `autocomplete`, `pattern`, `minlength`, `maxlength`, `min`, `max`, `help-text`, `error-message`, `size`
|
|
669
757
|
**Slots:** `after` (e.g., icon), `label` (alternative to the `label` attribute)
|
|
670
758
|
**Events:** `input`, `change`, `select`, `focus`, `blur`, `keydown`
|
|
671
759
|
**Note:** When both `error-message` and `help-text` are set, `aria-describedby` lists the error first, then the help text. `readonly` renders a lock icon next to the label.
|
|
@@ -689,5 +777,5 @@ Hover/focus tooltip. The tooltip is a sibling of its trigger, and the trigger po
|
|
|
689
777
|
|
|
690
778
|
**Props:** `id` (**required** — the value the trigger's `aria-describedby` references), `placement` (`"top"` | `"bottom"` | `"left"` | `"right"`, each also with `-start` / `-end`, or `"none"`; default `"top"`)
|
|
691
779
|
**Slots:** default (tooltip text — keep it to plain text)
|
|
692
|
-
**Events:** `toggle` (detail: the trigger element that opened it)
|
|
780
|
+
**Events:** `toggle` (detail: the trigger element that opened it). The native popover `ToggleEvent` also fires on the host.
|
|
693
781
|
**Notes:** Sets `role="tooltip"` and `popover="manual"` on itself. Multiple triggers may reference the same tooltip. Give the trigger and tooltip a `position: relative` wrapper. `data-palette` has no effect — tooltip colours are fixed.
|
|
@@ -7,7 +7,7 @@ React 19+ supports custom elements natively and may use web components directly
|
|
|
7
7
|
|
|
8
8
|
## Available Wrappers
|
|
9
9
|
|
|
10
|
-
All
|
|
10
|
+
All 33 components have a wrapper:
|
|
11
11
|
|
|
12
12
|
```tsx
|
|
13
13
|
import {
|
|
@@ -21,6 +21,9 @@ import {
|
|
|
21
21
|
SDSDetailsGroupWrapper,
|
|
22
22
|
SDSDialogWrapper,
|
|
23
23
|
SDSEnvironmentBannerWrapper,
|
|
24
|
+
SDSFileUploadWrapper,
|
|
25
|
+
SDSFileUploadItemWrapper,
|
|
26
|
+
SDSFileUploadFileListWrapper,
|
|
24
27
|
SDSHeadingWrapper,
|
|
25
28
|
SDSIconWrapper,
|
|
26
29
|
SDSInternalHeaderWrapper,
|
|
@@ -31,6 +34,7 @@ import {
|
|
|
31
34
|
SDSProcessStepWrapper,
|
|
32
35
|
SDSRadioWrapper,
|
|
33
36
|
SDSRadioGroupWrapper,
|
|
37
|
+
SDSSearchWrapper,
|
|
34
38
|
SDSSelectWrapper,
|
|
35
39
|
SDSStepperWrapper,
|
|
36
40
|
SDSStepperStepWrapper,
|
|
@@ -67,25 +71,30 @@ function MyForm() {
|
|
|
67
71
|
|
|
68
72
|
Handler names follow React idioms and **drop the `sds-` prefix** — the DOM event `sds-remove` becomes `onRemove`, not `onSdsRemove`.
|
|
69
73
|
|
|
70
|
-
| Wrapper | React prop
|
|
71
|
-
| ------------------------------------------------- |
|
|
72
|
-
| `SDSAlertWrapper`, `SDSNotificationWrapper` | `onRemove`
|
|
73
|
-
| `SDSButtonWrapper` | `onClick`, `onSubmit`, `onReset`
|
|
74
|
-
| `SDSCheckboxWrapper`, `SDSRadioWrapper` | `onChange`, `onFocus`, `onBlur`
|
|
75
|
-
| `SDSCheckboxGroupWrapper`, `SDSRadioGroupWrapper` | `onUpdate`, `onChange`
|
|
76
|
-
| `SDSChipWrapper` | `onChange`, `onRemove`
|
|
77
|
-
| `SDSDetailsWrapper`, `SDSTooltipWrapper` | `onToggle`
|
|
78
|
-
| `
|
|
79
|
-
| `
|
|
80
|
-
| `
|
|
81
|
-
| `
|
|
82
|
-
| `
|
|
83
|
-
| `
|
|
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
|
+
| `SDSStepperStepWrapper` | `onClick` | `click` (native `MouseEvent`) |
|
|
90
|
+
| `SDSTextFieldWrapper` | `onInput`, `onChange`, `onSelect`, `onFocus`, `onBlur`, `onKeyDown` | `input`, **`input`**, `select`, `focus`, `blur`, `keydown` |
|
|
91
|
+
| `SDSTextAreaWrapper` | `onInput`, `onChange`, `onSelect`, `onFocus`, `onBlur` | `input`, **`input`**, `select`, `focus`, `blur` |
|
|
84
92
|
|
|
85
|
-
Wrappers with no event mappings (presentational only): `SDSCardWrapper`, `SDSDetailsGroupWrapper`, `SDSEnvironmentBannerWrapper`, `SDSHeadingWrapper`, `SDSIconWrapper`, `SDSInternalHeaderWrapper`, `SDSLoaderWrapper`, `SDSProcessWrapper`, `SDSProcessStepWrapper`, `
|
|
93
|
+
Wrappers with no event mappings (presentational only): `SDSCardWrapper`, `SDSDetailsGroupWrapper`, `SDSEnvironmentBannerWrapper`, `SDSFileUploadFileListWrapper`, `SDSHeadingWrapper`, `SDSIconWrapper`, `SDSInternalHeaderWrapper`, `SDSLoaderWrapper`, `SDSProcessWrapper`, `SDSProcessStepWrapper`, `SDSTagWrapper`, `SDSTextWrapper`.
|
|
86
94
|
|
|
87
95
|
## Gotchas
|
|
88
96
|
|
|
89
|
-
-
|
|
90
|
-
-
|
|
91
|
-
-
|
|
97
|
+
- 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.
|
|
98
|
+
- `onKeyDown` (capital D) is the correct casing on `SDSTextFieldWrapper` and `SDSSearchWrapper`; there is no `onKeydown`.
|
|
99
|
+
- `SDSStepperStepWrapper` maps `onClick` to the step's native `click`. On a raw `<sds-stepper-step>` write it lowercase as `onclick`; camelCase `onClick` there is React's own synthetic event and is typed as deprecated.
|
|
100
|
+
- 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 @@
|
|
|
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"}
|