You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/src/uix/morfo/components/file-upload.ts

290 lines
6.9 KiB

import type { Morfo } from '../types';
import { v } from '../types';
export const fileUploadMorfo = {
name: 'FileUpload',
kebab: 'file-upload',
scope: ['soma', 'sema', 'eidos'],
expression: 'pack',
apg: 'https://www.w3.org/WAI/ARIA/apg/patterns/button/',
texts: {
label: '#?components.file-upload.label|File Upload',
dropzone: '#?components.file-upload.dropzone|Upload files',
trigger: '#?components.file-upload.trigger|Select files',
list: '#?components.file-upload.list|Selected files',
remove: '#?components.file-upload.remove|Remove file'
},
events: [
{
name: 'contact-trigger-picker',
semantic: {
family: 'contact',
verb: 'trigger',
target: v.partRef('trigger'),
sequence: 'coincident'
}
},
{
name: 'commit-set-add',
semantic: {
family: 'commit',
verb: 'set',
target: v.partRef('provider'),
intent: 'affirm',
sequence: 'post'
}
},
{
// Persistence: book §6.2 — signal.risk = untilFix. A rejected
// file (too big, wrong type, too many) must keep its warning
// visible until the user removes the offending file or chooses
// a valid one. Provider clears via `runtime.clearTarget(provider)`
// when the file list becomes valid.
name: 'signal-warn-reject',
semantic: {
family: 'signal',
verb: 'warn',
target: v.partRef('provider'),
intent: 'risk',
sequence: 'post',
persistence: 'untilFix'
},
// Book §9.2: signal.warn + risk ⇒ persistentTrace +
// reducedMotionFallback='text'. Caller passes the rejection
// reason as `message` so the live region announces e.g.
// "File too large — choose under 5MB."
a11ySemantic: {
requiresPersistentTrace: true,
reducedMotionFallback: 'text'
}
},
{
name: 'commit-remove',
semantic: {
family: 'commit',
verb: 'remove',
target: v.partRef('item'),
intent: 'neutral',
sequence: 'post'
}
},
{
name: 'commit-reset',
semantic: {
family: 'commit',
verb: 'reset',
target: v.partRef('provider'),
intent: 'neutral',
sequence: 'post'
}
}
],
parts: [
{
name: 'Provider',
kebab: 'provider',
archetype: 'provider',
kind: 'public',
defaultElement: 'div',
optional: false,
data: [
{ attr: 'data-disabled', severity: 'optional' },
{ attr: 'data-invalid', severity: 'optional' },
{ attr: 'data-required', severity: 'optional' },
{ attr: 'data-empty', severity: 'optional' }
],
aria: []
},
{
name: 'Label',
kebab: 'label',
archetype: 'label',
kind: 'public',
defaultElement: 'label',
optional: true,
data: [{ attr: 'data-disabled', severity: 'optional' }],
aria: []
},
{
name: 'Dropzone',
kebab: 'dropzone',
kind: 'public',
defaultElement: 'div',
role: 'button',
optional: true,
data: [
{ attr: 'data-disabled', severity: 'optional' },
{ attr: 'data-dragging', severity: 'optional' }
],
aria: [
{
attr: 'aria-label',
value: v.translationRef('#?components.file-upload.dropzone|Upload files'),
severity: 'recommended'
},
// Provider emitted `boolToStr(disabled)` (always "true"/"false"), so
// `propRef` + `ariaBoolean` lets renderProps() emit the same string.
{
attr: 'aria-disabled',
value: v.propRef('disabled'),
severity: 'optional',
ariaBoolean: true
}
],
keyboard: [
{ key: 'Enter', action: 'open-file-picker' },
{ key: ' ', action: 'open-file-picker' }
]
},
{
name: 'Trigger',
kebab: 'trigger',
archetype: 'trigger',
kind: 'public',
defaultElement: 'button',
role: 'button',
optional: true,
data: [{ attr: 'data-disabled', severity: 'optional' }],
aria: [
{ attr: 'type', value: v.literal('button') },
{
attr: 'aria-label',
value: v.translationRef('#?components.file-upload.trigger|Select files'),
severity: 'recommended'
},
// Provider emitted `boolToStr(disabled)` (always "true"/"false"), so
// `propRef` + `ariaBoolean` lets renderProps() emit the same string.
{
attr: 'aria-disabled',
value: v.propRef('disabled'),
severity: 'optional',
ariaBoolean: true
}
]
},
{
name: 'HiddenInput',
kebab: 'hidden-input',
archetype: 'input',
kind: 'public',
defaultElement: 'input',
optional: true,
data: [],
aria: [{ attr: 'aria-hidden', value: v.literal('true') }]
},
{
name: 'FileList',
kebab: 'file-list',
archetype: 'group',
kind: 'public',
defaultElement: 'ul',
role: 'list',
optional: true,
data: [],
aria: [
{
attr: 'aria-label',
value: v.translationRef('#?components.file-upload.list|Selected files'),
severity: 'recommended'
}
]
},
{
name: 'Item',
kebab: 'item',
archetype: 'item',
kind: 'public',
defaultElement: 'li',
role: 'listitem',
optional: true,
data: [
{ attr: 'data-file-name' },
{ attr: 'data-file-type', severity: 'optional' }
],
aria: []
},
{
name: 'ItemName',
kebab: 'item-name',
archetype: 'description',
kind: 'public',
defaultElement: 'span',
optional: true,
data: [],
aria: []
},
{
name: 'ItemSize',
kebab: 'item-size',
archetype: 'description',
kind: 'public',
defaultElement: 'span',
optional: true,
data: [],
aria: []
},
{
name: 'ItemPreview',
kebab: 'item-preview',
archetype: 'preview',
kind: 'public',
defaultElement: 'div',
optional: true,
data: [{ attr: 'data-type', severity: 'optional' }],
aria: [{ attr: 'aria-label', value: v.propRef('fileName'), severity: 'recommended' }]
},
{
name: 'ItemRemove',
kebab: 'item-remove',
archetype: 'action',
kind: 'public',
defaultElement: 'button',
role: 'button',
optional: true,
data: [{ attr: 'data-disabled', severity: 'optional' }],
aria: [
{ attr: 'type', value: v.literal('button') },
{
attr: 'aria-label',
value: v.translationRef('#?components.file-upload.remove|Remove file'),
severity: 'recommended'
}
]
},
{
name: 'ItemProgress',
kebab: 'item-progress',
archetype: 'indicator',
kind: 'public',
defaultElement: 'div',
role: 'progressbar',
optional: true,
data: [{ attr: 'data-value' }],
aria: [
{ attr: 'aria-valuenow', value: v.propRef('percent') },
{ attr: 'aria-valuemin', value: v.literal('0') },
{ attr: 'aria-valuemax', value: v.literal('100') },
{ attr: 'aria-label', value: v.propRef('fileName'), severity: 'recommended' }
]
},
{
name: 'ClearTrigger',
kebab: 'clear-trigger',
archetype: 'action',
kind: 'public',
defaultElement: 'button',
role: 'button',
optional: true,
data: [{ attr: 'data-disabled', severity: 'optional' }],
aria: [
{ attr: 'type', value: v.literal('button') },
{
attr: 'aria-label',
value: v.commonRef('buttons.clear', 'Clear all'),
severity: 'recommended'
}
]
}
]
} as const satisfies Morfo;

Powered by TurnKey Linux.