@oslokommune/punkt-elements
Version:
Komponentbiblioteket til Punkt, et designsystem laget av Oslo Origo
214 lines (202 loc) • 7.21 kB
text/typescript
import { html } from 'lit'
import type { TFileComment, TQueueItemOperation, TQueueOperationContext } from './fileupload-types'
const COMMENTS_ATTRIBUTE = 'comments'
const formatTimestamp = (iso: string): string => {
const date = new Date(iso)
if (Number.isNaN(date.getTime())) return iso
const day = String(date.getDate()).padStart(2, '0')
const month = String(date.getMonth() + 1).padStart(2, '0')
const year = date.getFullYear()
const hours = String(date.getHours()).padStart(2, '0')
const minutes = String(date.getMinutes()).padStart(2, '0')
return `${day}.${month}.${year} kl. ${hours}:${minutes}`
}
const handleRenameKeydown = (event: KeyboardEvent, save: () => void, cancel: () => void) => {
if (event.key === 'Enter') {
event.preventDefault()
event.stopPropagation()
save()
}
if (event.key === 'Escape') {
event.preventDefault()
event.stopPropagation()
cancel()
}
}
const handleCommentTextareaKeydown = (event: KeyboardEvent, save: () => void, cancel: () => void) => {
if (event.key === 'Escape') {
event.preventDefault()
event.stopPropagation()
cancel()
}
if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') {
event.preventDefault()
event.stopPropagation()
save()
}
}
export const createRemoveOperation = (removeFile: (fileId: string) => void): TQueueItemOperation => ({
id: 'remove',
title: 'Slett',
ariaLabel: 'Slett fil',
onClick: ({ file }) => removeFile(file.fileId),
})
export const createRenameOperation = (): TQueueItemOperation => ({
id: 'rename',
title: 'Rediger',
ariaLabel: 'Rediger filnavn',
renderInlineUI: (context: TQueueOperationContext) => {
const currentName =
context.getAttribute<string>('targetFilename') ||
context.file.attributes?.targetFilename ||
context.file.file?.name ||
''
const inputId = `pkt-fileupload-rename-${context.file.fileId}`
const save = () => {
const input = document.getElementById(inputId) as HTMLInputElement | null
const nextName = input?.value?.trim()
if (nextName) {
context.setAttribute('targetFilename', nextName)
}
context.close()
}
return html`
<label for=${inputId} class="pkt-sr-only">Endre filnavn</label>
<input
id=${inputId}
type="text"
class="pkt-fileupload__queue-display__item__rename-input"
?disabled=${context.disabled}
.value=${currentName}
@keydown=${(event: KeyboardEvent) => handleRenameKeydown(event, save, context.close)}
/>
<button
type="button"
class="pkt-btn pkt-btn--secondary pkt-btn--small"
?disabled=${context.disabled}
@click=${save}
>
Lagre
</button>
<button
type="button"
class="pkt-btn pkt-btn--tertiary pkt-btn--small"
?disabled=${context.disabled}
@click=${context.close}
>
Avbryt
</button>
`
},
renderHidden: (context: TQueueOperationContext) => {
const targetFilename =
context.getAttribute<string>('targetFilename') ||
context.file.attributes?.targetFilename ||
context.file.file?.name ||
''
return html`<input
type="hidden"
name=${`${context.inputName}-targetFilename`}
value=${targetFilename}
/>`
},
})
export const createCommentOperation = (): TQueueItemOperation => ({
id: 'comment',
title: (file) => {
const comments = (file.attributes?.[COMMENTS_ATTRIBUTE] as TFileComment[] | undefined) ?? []
return comments.length > 0 ? '' : 'Legg til kommentar'
},
ariaLabel: 'Legg til kommentar',
renderExtendedUI: (context: TQueueOperationContext) => {
const comments = context.getAttribute<TFileComment[]>(COMMENTS_ATTRIBUTE) ?? []
const existingComment = comments[0]
const textareaId = `pkt-fileupload-comment-${context.file.fileId}`
const save = () => {
const textarea = document.getElementById(textareaId) as HTMLTextAreaElement | null
const text = textarea?.value?.trim()
if (text) {
context.setAttribute(COMMENTS_ATTRIBUTE, [{ text, timestamp: new Date().toISOString() } satisfies TFileComment])
}
context.close()
}
return html`
<label for=${textareaId} class="pkt-fileupload__queue-display__item__comment-label">
${existingComment ? 'Rediger kommentar' : 'Legg til kommentar'}
</label>
<textarea
id=${textareaId}
class="pkt-fileupload__queue-display__item__comment-input"
?disabled=${context.disabled}
.value=${existingComment?.text ?? ''}
rows="2"
placeholder="Skriv inn kommentar"
@keydown=${(event: KeyboardEvent) => handleCommentTextareaKeydown(event, save, context.close)}
></textarea>
<button
type="button"
class="pkt-btn pkt-btn--secondary pkt-btn--small"
?disabled=${context.disabled}
@click=${save}
>
${existingComment ? 'Lagre kommentar' : 'Legg til kommentar'}
</button>
<button
type="button"
class="pkt-btn pkt-btn--tertiary pkt-btn--small"
?disabled=${context.disabled}
@click=${context.close}
>
Avbryt
</button>
`
},
renderContent: (context: TQueueOperationContext) => {
if (context.isActive) return null
const comments = context.getAttribute<TFileComment[]>(COMMENTS_ATTRIBUTE) ?? []
if (comments.length === 0) return null
const comment = comments[0]
return html`
<div class="pkt-fileupload__queue-display__item__comments">
<div class="pkt-fileupload__queue-display__item__comment">
<div class="pkt-fileupload__queue-display__item__comment__content">
<span class="pkt-fileupload__queue-display__item__comment__text" aria-label="Kommentar tekst">
${comment.text}
</span>
<time class="pkt-fileupload__queue-display__item__comment__time">
${formatTimestamp(comment.timestamp)}
</time>
</div>
<div class="pkt-fileupload__queue-display__item__comment__actions">
<button
type="button"
class="pkt-fileupload__queue-display__item__comment__action"
aria-label="Rediger kommentar"
?disabled=${context.disabled}
@click=${context.activate}
>
<pkt-icon name="edit"></pkt-icon>
</button>
<button
type="button"
class="pkt-fileupload__queue-display__item__comment__action"
aria-label="Slett kommentar"
?disabled=${context.disabled}
@click=${() => context.setAttribute(COMMENTS_ATTRIBUTE, undefined)}
>
<pkt-icon name="trash-can"></pkt-icon>
</button>
</div>
</div>
</div>
`
},
renderHidden: (context: TQueueOperationContext) => {
const comments = context.getAttribute<TFileComment[]>(COMMENTS_ATTRIBUTE)
return html`<input
type="hidden"
name=${`${context.inputName}-comments`}
value=${comments ? JSON.stringify(comments) : ''}
/>`
},
})