@theseam/ui-common 1.0.2-beta.59 → 1.0.2-beta.63
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/fesm2022/theseam-ui-common-file-input.mjs +537 -0
- package/fesm2022/theseam-ui-common-file-input.mjs.map +1 -0
- package/fesm2022/theseam-ui-common-signature-input.mjs +179 -66
- package/fesm2022/theseam-ui-common-signature-input.mjs.map +1 -1
- package/file-input/index.d.ts +190 -0
- package/file-input/package.json +3 -0
- package/package.json +5 -1
- package/signature-input/index.d.ts +71 -17
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theseam-ui-common-file-input.mjs","sources":["../../../projects/ui-common/file-input/file-item.utils.ts","../../../projects/ui-common/file-input/file-input-validation.ts","../../../projects/ui-common/file-input/file-drop-zone.directive.ts","../../../projects/ui-common/file-input/file-input.component.ts","../../../projects/ui-common/file-input/file-input.component.html","../../../projects/ui-common/file-input/file-tile.component.ts","../../../projects/ui-common/file-input/file-tile.component.html","../../../projects/ui-common/file-input/file-field.component.ts","../../../projects/ui-common/file-input/file-field.component.html","../../../projects/ui-common/file-input/theseam-ui-common-file-input.ts"],"sourcesContent":["import {\n faFile,\n faFileExcel,\n faFileImage,\n faFilePdf,\n faFileWord,\n} from '@fortawesome/free-solid-svg-icons'\n\nimport { SeamIcon } from '@theseam/ui-common/icon'\n\nimport { SeamFileItem } from './file-item.models'\n\nexport function seamFileItemFromFile(file: File, id?: string): SeamFileItem {\n return {\n name: file.name,\n size: file.size,\n type: file.type,\n source: { kind: 'file', file },\n id,\n }\n}\n\nexport interface SeamFileItemFromUrlOptions {\n name?: string\n type?: string\n size?: number\n id?: string\n thumbnailUrl?: string\n}\n\nexport function seamFileItemFromUrl(\n url: string,\n opts: SeamFileItemFromUrlOptions = {},\n): SeamFileItem {\n return {\n name: opts.name ?? _basenameFromUrl(url) ?? url,\n size: opts.size,\n type: opts.type,\n source: { kind: 'url', url },\n id: opts.id,\n thumbnailUrl: opts.thumbnailUrl,\n }\n}\n\nfunction _basenameFromUrl(url: string): string | null {\n // Strip query string and fragment before pulling the final path segment.\n const hashIdx = url.indexOf('#')\n const noHash = hashIdx >= 0 ? url.slice(0, hashIdx) : url\n const queryIdx = noHash.indexOf('?')\n const path = queryIdx >= 0 ? noHash.slice(0, queryIdx) : noHash\n\n // Find the last path segment (after the last /)\n const lastSlash = path.lastIndexOf('/')\n if (lastSlash < 0) return null\n\n const basename = path.slice(lastSlash + 1)\n\n // If there's an actual filename after the last slash, decode and return it\n if (basename) {\n try {\n return decodeURIComponent(basename)\n } catch {\n return basename\n }\n }\n\n // No basename (e.g., trailing slash or just protocol/domain), return null\n return null\n}\n\n/**\n * Extracts native `File` objects from items whose source is `file`. Items\n * backed by a URL or a Blob are ignored. Useful for submit-side mapping\n * when the consumer only cares about newly-uploaded blobs.\n */\nexport function seamFilesFromItems(items: SeamFileItem[]): File[] {\n const files: File[] = []\n for (const item of items) {\n if (item.source.kind === 'file') {\n files.push(item.source.file)\n }\n }\n return files\n}\n\nconst WORD_MIMES = new Set<string>([\n 'application/msword',\n 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n])\n\nconst EXCEL_MIMES = new Set<string>([\n 'application/vnd.ms-excel',\n 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n 'text/csv',\n])\n\n/**\n * Maps a MIME type to a built-in SeamIcon. Returns a generic file icon for\n * unknown, empty, or missing types. Returns SeamIcon (not IconDefinition) so\n * the icon set can change later without a breaking signature change.\n */\nexport function iconForMime(type: string | undefined): SeamIcon {\n if (!type) return faFile\n if (type === 'application/pdf') return faFilePdf\n if (type.startsWith('image/')) return faFileImage\n if (WORD_MIMES.has(type)) return faFileWord\n if (EXCEL_MIMES.has(type)) return faFileExcel\n return faFile\n}\n","import { SeamFileRejection, SeamFileRejectionReason } from './file-item.models'\n\nexport interface FileValidationOptions {\n accept: string\n maxSize: number | null\n maxFiles: number | null\n}\n\nexport interface FileValidationResult {\n accepted: File[]\n rejected: SeamFileRejection[]\n}\n\n/**\n * Validates a batch of files against accept / maxSize / maxFiles.\n *\n * `accept` is parsed as the standard comma-separated list: `.ext`, `mime/*`,\n * or `mime/subtype`. Matching against `file.type` is case-insensitive; when\n * `file.type` is empty, extension tokens (`.csv`) are tried against the file\n * name. Each rejected file accumulates ALL applicable reasons rather than\n * short-circuiting, so consumers can display comprehensive errors.\n *\n * `maxFiles` caps the total accepted count; files past the cap are rejected\n * with reason `'count'` in arrival order.\n */\nexport function validateFiles(\n files: File[],\n opts: FileValidationOptions,\n): FileValidationResult {\n const acceptTokens = _parseAccept(opts.accept)\n const accepted: File[] = []\n const rejected: SeamFileRejection[] = []\n\n for (const file of files) {\n const reasons: SeamFileRejectionReason[] = []\n\n if (acceptTokens.length > 0 && !_matchesAccept(file, acceptTokens)) {\n reasons.push('type')\n }\n\n if (opts.maxSize !== null && file.size > opts.maxSize) {\n reasons.push('size')\n }\n\n if (reasons.length > 0) {\n rejected.push({ file, reasons })\n continue\n }\n\n if (opts.maxFiles !== null && accepted.length >= opts.maxFiles) {\n rejected.push({ file, reasons: ['count'] })\n continue\n }\n\n accepted.push(file)\n }\n\n return { accepted, rejected }\n}\n\nfunction _parseAccept(accept: string): string[] {\n return accept\n .split(',')\n .map((t) => t.trim().toLowerCase())\n .filter((t) => t.length > 0)\n}\n\nfunction _matchesAccept(file: File, tokens: string[]): boolean {\n const mime = file.type.toLowerCase()\n const name = file.name.toLowerCase()\n\n for (const token of tokens) {\n if (token.startsWith('.')) {\n if (name.endsWith(token)) return true\n continue\n }\n if (!mime) continue\n if (token.endsWith('/*')) {\n const prefix = token.slice(0, -1) // keep the slash\n if (mime.startsWith(prefix)) return true\n continue\n }\n if (token === mime) return true\n }\n return false\n}\n","import {\n booleanAttribute,\n computed,\n Directive,\n input,\n output,\n signal,\n} from '@angular/core'\n\nimport { SeamFileRejection } from './file-item.models'\nimport { validateFiles } from './file-input-validation'\n\n@Directive({\n selector: '[seamFileDropZone]',\n host: {\n '[class.seam-file-drop-zone--over]': '_isOver()',\n '(dragenter)': '_onDragEnter($event)',\n '(dragover)': '_onDragOver($event)',\n '(dragleave)': '_onDragLeave($event)',\n '(drop)': '_onDrop($event)',\n },\n})\nexport class TheSeamFileDropZoneDirective {\n readonly accept = input<string>('')\n readonly maxSize = input<number | null>(null)\n readonly maxFiles = input<number | null>(null)\n readonly disabled = input(false, { transform: booleanAttribute })\n\n readonly seamFileDrop = output<File[]>()\n readonly seamFileDropRejected = output<SeamFileRejection[]>()\n\n /** Counter-based dragenter/leave tracking to avoid child-element flicker. */\n private readonly _dragDepth = signal(0)\n\n protected readonly _isOver = computed(\n () => !this.disabled() && this._dragDepth() > 0,\n )\n\n protected _onDragEnter(event: DragEvent): void {\n if (this.disabled()) return\n event.preventDefault()\n this._dragDepth.update((n) => n + 1)\n }\n\n protected _onDragOver(event: DragEvent): void {\n if (this.disabled()) return\n // preventDefault is required for the drop event to fire.\n event.preventDefault()\n }\n\n protected _onDragLeave(event: DragEvent): void {\n if (this.disabled()) return\n this._dragDepth.update((n) => Math.max(0, n - 1))\n }\n\n protected _onDrop(event: DragEvent): void {\n if (this.disabled()) return\n event.preventDefault()\n this._dragDepth.set(0)\n\n const files = event.dataTransfer ? Array.from(event.dataTransfer.files) : []\n if (files.length === 0) return\n\n const { accepted, rejected } = validateFiles(files, {\n accept: this.accept(),\n maxSize: this.maxSize(),\n maxFiles: this.maxFiles(),\n })\n\n this.seamFileDrop.emit(accepted)\n if (rejected.length > 0) this.seamFileDropRejected.emit(rejected)\n }\n}\n","import {\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n ElementRef,\n input,\n output,\n signal,\n viewChild,\n} from '@angular/core'\n\nimport { faUpload } from '@fortawesome/free-solid-svg-icons'\n\nimport { TheSeamIconModule } from '@theseam/ui-common/icon'\n\nimport { TheSeamFileDropZoneDirective } from './file-drop-zone.directive'\nimport { validateFiles } from './file-input-validation'\nimport { SeamFileRejection, SeamFileRejectionReason } from './file-item.models'\n\n@Component({\n selector: 'seam-file-input',\n templateUrl: './file-input.component.html',\n styleUrls: ['./file-input.component.scss'],\n imports: [TheSeamFileDropZoneDirective, TheSeamIconModule],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class TheSeamFileInputComponent {\n readonly multiple = input(false, { transform: booleanAttribute })\n readonly accept = input<string>('')\n readonly maxSize = input<number | null>(null)\n readonly maxFiles = input<number | null>(null)\n readonly disabled = input(false, { transform: booleanAttribute })\n readonly hideErrors = input(false, { transform: booleanAttribute })\n readonly promptText = input<string>('Choose a file')\n readonly promptSuffix = input<string>('or drag it here')\n\n readonly filesAdded = output<File[]>()\n readonly rejected = output<SeamFileRejection[]>()\n\n protected readonly _faUpload = faUpload\n protected readonly _lastRejections = signal<SeamFileRejection[]>([])\n protected readonly _effectiveMaxFiles = computed(() => {\n const explicit = this.maxFiles()\n if (!this.multiple()) {\n return explicit !== null ? Math.min(explicit, 1) : 1\n }\n return explicit\n })\n protected readonly _errorMessage = computed(() =>\n _formatErrors(\n this._lastRejections(),\n this.maxSize(),\n this._effectiveMaxFiles(),\n ),\n )\n\n private readonly _nativeInput =\n viewChild.required<ElementRef<HTMLInputElement>>('native')\n\n _openPicker(): void {\n if (this.disabled()) return\n this._nativeInput().nativeElement.click()\n }\n\n protected _onFilesDropped(files: File[]): void {\n this._lastRejections.set([])\n if (files.length > 0) this.filesAdded.emit(files)\n }\n\n protected _onRejected(rejections: SeamFileRejection[]): void {\n this._lastRejections.set(rejections)\n this.rejected.emit(rejections)\n }\n\n protected _onNativeChange(event: Event): void {\n const nativeInput = event.target as HTMLInputElement\n const files = nativeInput.files ? Array.from(nativeInput.files) : []\n // Clear the value so the same file can be re-selected next time.\n nativeInput.value = ''\n\n if (files.length === 0) return\n\n const { accepted, rejected } = validateFiles(files, {\n accept: this.accept(),\n maxSize: this.maxSize(),\n maxFiles: this._effectiveMaxFiles(),\n })\n\n if (rejected.length > 0) {\n this._lastRejections.set(rejected)\n this.rejected.emit(rejected)\n } else {\n this._lastRejections.set([])\n }\n\n if (accepted.length > 0) this.filesAdded.emit(accepted)\n }\n}\n\nfunction _formatErrors(\n rejections: SeamFileRejection[],\n maxSize: number | null,\n maxFiles: number | null,\n): string | null {\n if (rejections.length === 0) return null\n const firstReason: SeamFileRejectionReason = rejections[0].reasons[0]\n switch (firstReason) {\n case 'type':\n return 'File type not accepted.'\n case 'size': {\n const mb = maxSize !== null ? (maxSize / (1024 * 1024)).toFixed(1) : null\n return mb\n ? `File exceeds the maximum size (${mb} MB).`\n : 'File exceeds the maximum size.'\n }\n case 'count':\n return maxFiles !== null\n ? `Only ${maxFiles} file(s) can be added.`\n : 'Too many files selected.'\n default:\n return 'File could not be accepted.'\n }\n}\n","<div\n class=\"seam-file-input__zone\"\n seamFileDropZone\n [accept]=\"accept()\"\n [maxSize]=\"maxSize()\"\n [maxFiles]=\"_effectiveMaxFiles()\"\n [disabled]=\"disabled()\"\n (seamFileDrop)=\"_onFilesDropped($event)\"\n (seamFileDropRejected)=\"_onRejected($event)\"\n role=\"button\"\n [attr.tabindex]=\"disabled() ? -1 : 0\"\n (click)=\"_openPicker()\"\n (keydown.enter)=\"_openPicker(); $event.preventDefault()\"\n (keydown.space)=\"_openPicker(); $event.preventDefault()\"\n>\n <span class=\"seam-file-input__icon\">\n <seam-icon [icon]=\"_faUpload\"></seam-icon>\n </span>\n <p class=\"seam-file-input__prompt\">\n <strong>{{ promptText() }}</strong> {{ promptSuffix() }}\n </p>\n</div>\n\n<input\n #native\n type=\"file\"\n hidden\n [multiple]=\"multiple()\"\n [attr.accept]=\"accept() || null\"\n (change)=\"_onNativeChange($event)\"\n/>\n\n@if (!hideErrors() && _errorMessage(); as msg) {\n <p class=\"seam-file-input__errors\">{{ msg }}</p>\n}\n","import {\n AfterViewInit,\n booleanAttribute,\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n Component,\n computed,\n effect,\n inject,\n input,\n output,\n signal,\n} from '@angular/core'\n\nimport { faTimes } from '@fortawesome/free-solid-svg-icons'\n\nimport { NgTemplateOutlet } from '@angular/common'\n\nimport { TheSeamIconModule } from '@theseam/ui-common/icon'\n\nimport { iconForMime } from './file-item.utils'\nimport { SeamFileItem, SeamFileTileVariant } from './file-item.models'\n\n@Component({\n selector: 'seam-file-tile',\n templateUrl: './file-tile.component.html',\n styleUrls: ['./file-tile.component.scss'],\n imports: [TheSeamIconModule, NgTemplateOutlet],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class TheSeamFileTileComponent implements AfterViewInit {\n private readonly _cdr = inject(ChangeDetectorRef)\n readonly item = input.required<SeamFileItem>()\n readonly variant = input<SeamFileTileVariant>('row')\n readonly showName = input(true, { transform: booleanAttribute })\n readonly showMeta = input(true, { transform: booleanAttribute })\n readonly removable = input(true, { transform: booleanAttribute })\n readonly disabled = input(false, { transform: booleanAttribute })\n\n readonly remove = output<SeamFileItem>()\n readonly itemClick = output<SeamFileItem>()\n\n protected readonly _faTimes = faTimes\n\n protected readonly _mimeIcon = computed(() => iconForMime(this.item().type))\n protected readonly _metaLine = computed(() => _formatMeta(this.item()))\n protected readonly _showRemoveBtn = computed(\n () => this.removable() && !this.disabled(),\n )\n\n /** True when itemClick is observed AND the tile is not disabled. */\n protected readonly _isInteractive = computed(\n () => this._clickObserved() && !this.disabled(),\n )\n\n /**\n * Thumbnail URL for image items. Tracked across item changes so object\n * URLs are revoked when the item changes or the component is destroyed.\n */\n private _ownedObjectUrl: string | null = null\n private _pendingObjectUrl: string | null = null\n\n protected readonly _thumbUrl = computed(() => {\n const item = this.item()\n\n if (item.thumbnailUrl) return item.thumbnailUrl\n\n const isImage = _isImageMime(item.type)\n\n if (\n (item.source.kind === 'file' || item.source.kind === 'blob') &&\n isImage\n ) {\n const blob =\n item.source.kind === 'file' ? item.source.file : item.source.blob\n const url = URL.createObjectURL(blob)\n this._pendingObjectUrl = url\n return url\n }\n\n if (item.source.kind === 'url' && _looksLikeImage(item)) {\n return item.source.url\n }\n\n return null\n })\n\n /**\n * True once we detect that a consumer has wired (itemClick).\n * Detected in ngAfterViewInit — by that point the parent's template binding\n * has called subscribe() on the OutputEmitterRef, populating its internal\n * `listeners` array (Option A: access via internal field on Angular 20's\n * OutputEmitterRef). If the internal shape is absent, conservatively stays\n * false (opt-out default — no unwanted role=button on inert tiles).\n */\n protected readonly _clickObserved = signal(false)\n\n constructor() {\n // When _thumbUrl changes, revoke the previous owned URL (if any).\n effect(() => {\n // Read the signal so this effect re-runs when the thumbnail changes.\n this._thumbUrl()\n const previous = this._ownedObjectUrl\n this._ownedObjectUrl = this._pendingObjectUrl\n this._pendingObjectUrl = null\n if (previous && previous !== this._ownedObjectUrl) {\n URL.revokeObjectURL(previous)\n }\n })\n // Destroy cleanup: revoke the last owned URL.\n effect((onCleanup) => {\n onCleanup(() => {\n if (this._ownedObjectUrl) {\n URL.revokeObjectURL(this._ownedObjectUrl)\n this._ownedObjectUrl = null\n }\n })\n })\n }\n\n ngAfterViewInit(): void {\n // Detect whether (itemClick) is bound by checking the OutputEmitterRef's\n // internal listeners array. By ngAfterViewInit, the parent's template\n // bindings (including event bindings via subscribe()) have already been\n // applied during the parent's change-detection pass.\n //\n // Option A: access (this.itemClick as any).listeners which is the internal\n // array in Angular 20's OutputEmitterRef (null initially, an array once\n // subscribed). If the internal shape changes, we conservatively keep false.\n const ref = this.itemClick as unknown as { listeners?: unknown[] | null }\n const observed =\n ref.listeners !== undefined ? (ref.listeners?.length ?? 0) > 0 : false\n if (observed) {\n this._clickObserved.set(true)\n this._cdr.markForCheck()\n }\n }\n\n protected _onRemove(event: MouseEvent): void {\n event.stopPropagation()\n this.remove.emit(this.item())\n }\n\n protected _onBodyClick(): void {\n if (!this._clickObserved() || this.disabled()) return\n this.itemClick.emit(this.item())\n }\n\n protected _onBodyKey(event: KeyboardEvent): void {\n if (!this._clickObserved() || this.disabled()) return\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n this.itemClick.emit(this.item())\n }\n }\n}\n\nfunction _formatMeta(item: SeamFileItem): string {\n const parts: string[] = []\n if (item.size !== undefined) parts.push(_formatBytes(item.size))\n if (item.type) parts.push(item.type)\n return parts.join(' · ')\n}\n\nfunction _formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`\n}\n\nfunction _isImageMime(type: string | undefined): boolean {\n return !!type && type.toLowerCase().startsWith('image/')\n}\n\nconst IMAGE_EXT = /\\.(png|jpe?g|gif|webp|bmp|svg)(\\?|$)/i\n\nfunction _looksLikeImage(item: SeamFileItem): boolean {\n if (_isImageMime(item.type)) return true\n if (item.source.kind === 'url' && IMAGE_EXT.test(item.source.url)) return true\n return false\n}\n","<div\n class=\"seam-file-tile\"\n [class.seam-file-tile--row]=\"variant() === 'row'\"\n [class.seam-file-tile--preview]=\"variant() === 'preview'\"\n [class.seam-file-tile--clickable]=\"_isInteractive()\"\n>\n @if (variant() === 'row') {\n @if (_isInteractive()) {\n <div\n class=\"seam-file-tile__clickable-body\"\n role=\"button\"\n tabindex=\"0\"\n (click)=\"_onBodyClick()\"\n (keydown)=\"_onBodyKey($event)\"\n >\n <ng-container *ngTemplateOutlet=\"rowContent\"></ng-container>\n </div>\n } @else {\n <ng-container *ngTemplateOutlet=\"rowContent\"></ng-container>\n }\n\n @if (_showRemoveBtn()) {\n <button\n type=\"button\"\n class=\"seam-file-tile__remove\"\n (click)=\"_onRemove($event)\"\n title=\"Remove file\"\n >\n <seam-icon [icon]=\"_faTimes\"></seam-icon>\n </button>\n }\n } @else {\n @if (_showRemoveBtn()) {\n <button\n type=\"button\"\n class=\"seam-file-tile__remove seam-file-tile__remove--overlay\"\n (click)=\"_onRemove($event)\"\n title=\"Remove file\"\n >\n <seam-icon [icon]=\"_faTimes\"></seam-icon>\n </button>\n }\n @if (_isInteractive()) {\n <div\n class=\"seam-file-tile__clickable-body\"\n role=\"button\"\n tabindex=\"0\"\n (click)=\"_onBodyClick()\"\n (keydown)=\"_onBodyKey($event)\"\n >\n <ng-container *ngTemplateOutlet=\"previewContent\"></ng-container>\n </div>\n } @else {\n <ng-container *ngTemplateOutlet=\"previewContent\"></ng-container>\n }\n }\n</div>\n\n<ng-template #rowContent>\n <span\n class=\"seam-file-tile__visual\"\n [class.seam-file-tile__visual--image]=\"!!_thumbUrl()\"\n >\n @if (_thumbUrl(); as url) {\n <img class=\"seam-file-tile__thumb\" [src]=\"url\" [alt]=\"item().name\" />\n } @else {\n <seam-icon [icon]=\"_mimeIcon()\"></seam-icon>\n }\n </span>\n <div class=\"seam-file-tile__body\">\n <div class=\"seam-file-tile__name\" [attr.title]=\"item().name\">\n {{ item().name }}\n </div>\n @if (showMeta() && _metaLine(); as meta) {\n <div class=\"seam-file-tile__meta\">{{ meta }}</div>\n }\n </div>\n</ng-template>\n\n<ng-template #previewContent>\n <span class=\"seam-file-tile__preview-media\">\n @if (_thumbUrl(); as url) {\n <img class=\"seam-file-tile__thumb\" [src]=\"url\" [alt]=\"item().name\" />\n } @else {\n <span class=\"seam-file-tile__visual\">\n <seam-icon [icon]=\"_mimeIcon()\"></seam-icon>\n </span>\n }\n </span>\n @if (showName()) {\n <div class=\"seam-file-tile__preview-name\" [attr.title]=\"item().name\">\n {{ item().name }}\n </div>\n }\n</ng-template>\n","import {\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n forwardRef,\n input,\n output,\n signal,\n} from '@angular/core'\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'\n\nimport { TheSeamFileInputComponent } from './file-input.component'\nimport { TheSeamFileTileComponent } from './file-tile.component'\nimport { SeamFileItem, SeamFileRejection } from './file-item.models'\nimport { seamFileItemFromFile } from './file-item.utils'\n\n@Component({\n selector: 'seam-file-field',\n templateUrl: './file-field.component.html',\n styleUrls: ['./file-field.component.scss'],\n imports: [TheSeamFileInputComponent, TheSeamFileTileComponent],\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => TheSeamFileFieldComponent),\n multi: true,\n },\n ],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class TheSeamFileFieldComponent implements ControlValueAccessor {\n readonly multiple = input(false, { transform: booleanAttribute })\n readonly accept = input<string>('')\n readonly maxSize = input<number | null>(null)\n readonly maxFiles = input<number | null>(null)\n readonly disabled = input(false, { transform: booleanAttribute })\n readonly previewMode = input(false, { transform: booleanAttribute })\n readonly showTileName = input(true, { transform: booleanAttribute })\n readonly promptText = input<string>('Choose a file')\n readonly promptSuffix = input<string>('or drag it here')\n readonly replaceText = input<string>('choose a different file')\n readonly hideErrors = input(false, { transform: booleanAttribute })\n\n readonly rejected = output<SeamFileRejection[]>()\n\n protected readonly _items = signal<SeamFileItem[]>([])\n protected readonly _cvaDisabled = signal(false)\n\n protected readonly _effectiveDisabled = computed(\n () => this.disabled() || this._cvaDisabled(),\n )\n\n protected readonly _hasFile = computed(\n () => !this.multiple() && this._items().length > 0,\n )\n\n protected readonly _remainingMaxFiles = computed(() => {\n const max = this.maxFiles()\n if (!this.multiple()) {\n // Single-mode: cap at 1 always. If explicit lower, honor.\n return max !== null ? Math.min(max, 1) : 1\n }\n if (max === null) return null\n return Math.max(0, max - this._items().length)\n })\n\n protected readonly _tileVariant = computed(() =>\n this.previewMode() ? 'preview' : 'row',\n )\n\n private _onChange: (value: SeamFileItem[]) => void = () => undefined\n private _onTouched: () => void = () => undefined\n\n writeValue(value: SeamFileItem[] | null): void {\n this._items.set(value ?? [])\n }\n\n registerOnChange(fn: (value: SeamFileItem[]) => void): void {\n this._onChange = fn\n }\n\n registerOnTouched(fn: () => void): void {\n this._onTouched = fn\n }\n\n setDisabledState(isDisabled: boolean): void {\n this._cvaDisabled.set(isDisabled)\n }\n\n protected _onFilesAdded(files: File[]): void {\n if (files.length === 0) return\n const added = files.map((f) => seamFileItemFromFile(f))\n if (!this.multiple()) {\n this._items.set(added.slice(0, 1))\n } else {\n const remaining = this._remainingMaxFiles()\n const toAdd = remaining !== null ? added.slice(0, remaining) : added\n if (toAdd.length === 0) return\n this._items.update((prev) => [...prev, ...toAdd])\n }\n this._emit()\n }\n\n protected _onRejected(rejections: SeamFileRejection[]): void {\n this.rejected.emit(rejections)\n }\n\n protected _onTileRemove(item: SeamFileItem): void {\n this._items.update((prev) => prev.filter((i) => i !== item))\n this._emit()\n }\n\n private _emit(): void {\n this._onChange(this._items())\n this._onTouched()\n }\n}\n","@if (_hasFile()) {\n <seam-file-tile\n [item]=\"_items()[0]\"\n [variant]=\"_tileVariant()\"\n [showName]=\"showTileName()\"\n [disabled]=\"_effectiveDisabled()\"\n (remove)=\"_onTileRemove($event)\"\n ></seam-file-tile>\n <button\n type=\"button\"\n class=\"seam-file-field__replace\"\n [disabled]=\"_effectiveDisabled()\"\n (click)=\"inputComponentWhenFilled._openPicker()\"\n >\n or <strong>{{ replaceText() }}</strong>\n </button>\n <!-- Hidden mounted input so the replace button has a picker to delegate to. -->\n <seam-file-input\n #inputComponentWhenFilled\n hidden\n [multiple]=\"multiple()\"\n [accept]=\"accept()\"\n [maxSize]=\"maxSize()\"\n [maxFiles]=\"_remainingMaxFiles()\"\n [disabled]=\"_effectiveDisabled()\"\n [hideErrors]=\"true\"\n (filesAdded)=\"_onFilesAdded($event)\"\n (rejected)=\"_onRejected($event)\"\n ></seam-file-input>\n} @else {\n <seam-file-input\n #inputComponent\n [multiple]=\"multiple()\"\n [accept]=\"accept()\"\n [maxSize]=\"maxSize()\"\n [maxFiles]=\"_remainingMaxFiles()\"\n [disabled]=\"_effectiveDisabled()\"\n [hideErrors]=\"hideErrors()\"\n [promptText]=\"promptText()\"\n [promptSuffix]=\"promptSuffix()\"\n (filesAdded)=\"_onFilesAdded($event)\"\n (rejected)=\"_onRejected($event)\"\n ></seam-file-input>\n\n @if (multiple() && _items().length > 0) {\n <div\n class=\"seam-file-field__tiles\"\n [class.seam-file-field__tiles--preview]=\"previewMode()\"\n >\n @for (item of _items(); track item.id ?? item.name) {\n <seam-file-tile\n [item]=\"item\"\n [variant]=\"_tileVariant()\"\n [showName]=\"showTileName()\"\n [disabled]=\"_effectiveDisabled()\"\n (remove)=\"_onTileRemove($event)\"\n ></seam-file-tile>\n }\n </div>\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { InjectionToken, inject, DestroyRef, computed, signal, ChangeDetectionStrategy, Component, input, output,
|
|
3
|
-
import * as i1$
|
|
2
|
+
import { InjectionToken, inject, DestroyRef, computed, signal, viewChild, ChangeDetectionStrategy, Component, input, output, afterNextRender, effect, isDevMode, ElementRef, EventEmitter, HostListener, Output, Input, Directive } from '@angular/core';
|
|
3
|
+
import * as i1$1 from '@angular/cdk/a11y';
|
|
4
4
|
import { A11yModule } from '@angular/cdk/a11y';
|
|
5
5
|
import { toSignal, takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';
|
|
6
6
|
import * as i2 from '@angular/forms';
|
|
@@ -8,22 +8,21 @@ import { FormControl, NG_VALUE_ACCESSOR, ReactiveFormsModule, FormGroup } from '
|
|
|
8
8
|
import { of, from, map, switchMap as switchMap$1, combineLatest } from 'rxjs';
|
|
9
9
|
import { faSignature, faUpload, faKeyboard } from '@fortawesome/free-solid-svg-icons';
|
|
10
10
|
import * as i3 from '@theseam/ui-common/buttons';
|
|
11
|
-
import { TheSeamButtonsModule } from '@theseam/ui-common/buttons';
|
|
11
|
+
import { TheSeamButtonsModule, TheSeamButtonComponent, TheSeamAnchorButtonComponent } from '@theseam/ui-common/buttons';
|
|
12
12
|
import * as i4 from '@theseam/ui-common/icon';
|
|
13
13
|
import { TheSeamIconModule } from '@theseam/ui-common/icon';
|
|
14
14
|
import { TheSeamLayoutService } from '@theseam/ui-common/layout';
|
|
15
|
-
import { ModalRef } from '@theseam/ui-common/modal';
|
|
15
|
+
import { ModalRef, Modal } from '@theseam/ui-common/modal';
|
|
16
16
|
import { TheSeamAutoFocusDirective, TheSeamDisableControlDirective } from '@theseam/ui-common/shared';
|
|
17
17
|
import { readFileAsDataUrlAsync, observeControlValue, observeControlValid } from '@theseam/ui-common/utils';
|
|
18
|
-
import { switchMap, debounceTime } from 'rxjs/operators';
|
|
19
|
-
import
|
|
20
|
-
import
|
|
21
|
-
import * as i1$1 from '@almothafar/angular-signature-pad';
|
|
18
|
+
import { switchMap, debounceTime, take } from 'rxjs/operators';
|
|
19
|
+
import { TheSeamFileDropZoneDirective } from '@theseam/ui-common/file-input';
|
|
20
|
+
import * as i1 from '@almothafar/angular-signature-pad';
|
|
22
21
|
import { AngularSignaturePadModule } from '@almothafar/angular-signature-pad';
|
|
23
22
|
import { TheSeamFontLoaderService } from '@theseam/ui-common/services';
|
|
24
23
|
import * as i2$1 from '@theseam/ui-common/form-field';
|
|
25
24
|
import { TheSeamFormFieldModule } from '@theseam/ui-common/form-field';
|
|
26
|
-
import { ComponentHarness } from '@angular/cdk/testing';
|
|
25
|
+
import { ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';
|
|
27
26
|
|
|
28
27
|
const THESEAM_SIGNATURE_INPUT_CONTAINER = new InjectionToken('THESEAM_SIGNATURE_INPUT_CONTAINER');
|
|
29
28
|
|
|
@@ -41,12 +40,6 @@ class TheSeamSignatureInputImgComponent {
|
|
|
41
40
|
optional: true,
|
|
42
41
|
});
|
|
43
42
|
_destroyRef = inject(DestroyRef);
|
|
44
|
-
/**
|
|
45
|
-
* The File is only needed for validation at selection time. Once it's been
|
|
46
|
-
* converted to a data URL and stored in the form value, we don't need the
|
|
47
|
-
* File again — so there's no point trying to round-trip it through
|
|
48
|
-
* writeValue / form state. The preview renders off the current form value.
|
|
49
|
-
*/
|
|
50
43
|
_fileControl = new FormControl(null, {
|
|
51
44
|
validators: [maxFileSizeValidator],
|
|
52
45
|
});
|
|
@@ -54,24 +47,18 @@ class TheSeamSignatureInputImgComponent {
|
|
|
54
47
|
initialValue: this._fileControl.status,
|
|
55
48
|
});
|
|
56
49
|
_sizeError = computed(() => {
|
|
57
|
-
// Touch the status signal so this re-runs on validity changes.
|
|
58
50
|
this._fileStatus();
|
|
59
51
|
return this._fileControl.getError('maxFileSize')
|
|
60
52
|
? 'File size has exceeded 2MB.'
|
|
61
53
|
: null;
|
|
62
54
|
}, ...(ngDevMode ? [{ debugName: "_sizeError" }] : []));
|
|
63
|
-
/**
|
|
64
|
-
* Single source of truth for both the form value and the preview image.
|
|
65
|
-
* External writes (writeValue) and successful uploads both funnel through
|
|
66
|
-
* here, so switching tabs and coming back always shows the last committed
|
|
67
|
-
* signature.
|
|
68
|
-
*/
|
|
69
55
|
_value = signal(null, ...(ngDevMode ? [{ debugName: "_value" }] : []));
|
|
70
56
|
_previewDataUrl = computed(() => this._value(), ...(ngDevMode ? [{ debugName: "_previewDataUrl" }] : []));
|
|
71
57
|
_previewBackgroundImage = computed(() => {
|
|
72
58
|
const url = this._value();
|
|
73
59
|
return url ? `url("${url}")` : null;
|
|
74
60
|
}, ...(ngDevMode ? [{ debugName: "_previewBackgroundImage" }] : []));
|
|
61
|
+
_nativeInput = viewChild.required('filesInput');
|
|
75
62
|
_onChange = () => undefined;
|
|
76
63
|
_onTouched = () => undefined;
|
|
77
64
|
constructor() {
|
|
@@ -79,8 +66,6 @@ class TheSeamSignatureInputImgComponent {
|
|
|
79
66
|
this._container.registerInputItem('img', this);
|
|
80
67
|
this._destroyRef.onDestroy(() => this._container?.unregisterInputItem('img', this));
|
|
81
68
|
}
|
|
82
|
-
// Valid file uploads convert to a data URL and become both the preview
|
|
83
|
-
// and the form value. Invalid (too large) files clear both.
|
|
84
69
|
this._fileControl.valueChanges
|
|
85
70
|
.pipe(switchMap(() => {
|
|
86
71
|
const file = this._fileControl.value;
|
|
@@ -109,44 +94,21 @@ class TheSeamSignatureInputImgComponent {
|
|
|
109
94
|
this._fileControl.enable();
|
|
110
95
|
}
|
|
111
96
|
clear() {
|
|
112
|
-
// valueChanges subscription propagates this to `_value` (null) and to the
|
|
113
|
-
// form value.
|
|
114
97
|
this._fileControl.setValue(null);
|
|
115
98
|
}
|
|
116
99
|
openFileBrowse() {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
};
|
|
128
|
-
const onFileChange = (event) => {
|
|
129
|
-
const input = event.target;
|
|
130
|
-
if (input.files && input.files.length > 0) {
|
|
131
|
-
this._fileControl.setValue(input.files[0]);
|
|
132
|
-
}
|
|
133
|
-
cleanup();
|
|
134
|
-
};
|
|
135
|
-
fileInput.addEventListener('change', onFileChange);
|
|
136
|
-
// Detect file browser canceled without making a selection.
|
|
137
|
-
const onFocusReturned = () => cleanup();
|
|
138
|
-
document.body.addEventListener('focus', onFocusReturned);
|
|
139
|
-
window.addEventListener('focus', onFocusReturned);
|
|
140
|
-
fileInput.click();
|
|
141
|
-
}
|
|
142
|
-
_onFileDropped(files) {
|
|
143
|
-
for (const droppedFile of files) {
|
|
144
|
-
if (droppedFile.fileEntry.isFile) {
|
|
145
|
-
const fileEntry = droppedFile.fileEntry;
|
|
146
|
-
fileEntry.file((file) => this._fileControl.setValue(file));
|
|
147
|
-
break;
|
|
148
|
-
}
|
|
100
|
+
this._nativeInput().nativeElement.click();
|
|
101
|
+
}
|
|
102
|
+
_onFilesDropped(files) {
|
|
103
|
+
if (files.length > 0)
|
|
104
|
+
this._fileControl.setValue(files[0]);
|
|
105
|
+
}
|
|
106
|
+
_onNativeChange(event) {
|
|
107
|
+
const input = event.target;
|
|
108
|
+
if (input.files && input.files.length > 0) {
|
|
109
|
+
this._fileControl.setValue(input.files[0]);
|
|
149
110
|
}
|
|
111
|
+
input.value = '';
|
|
150
112
|
}
|
|
151
113
|
_setValue(value) {
|
|
152
114
|
this._value.set(value);
|
|
@@ -160,18 +122,18 @@ class TheSeamSignatureInputImgComponent {
|
|
|
160
122
|
useExisting: TheSeamSignatureInputImgComponent,
|
|
161
123
|
multi: true,
|
|
162
124
|
},
|
|
163
|
-
], ngImport: i0, template: "<div class=\"seam-signature-input-img\">\n <div class=\"seam-signature-input-img__upload-container\">\n <div class=\"seam-signature-input-img__header h-100\">\n <div\n class=\"seam-signature-input-img__upload-box h-100\"\n [class.has-preview]=\"!!_previewDataUrl()\"\n [style.background-image]=\"_previewBackgroundImage()\"\n tabindex=\"0\"\n (
|
|
125
|
+
], viewQueries: [{ propertyName: "_nativeInput", first: true, predicate: ["filesInput"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"seam-signature-input-img\">\n <div class=\"seam-signature-input-img__upload-container\">\n <div class=\"seam-signature-input-img__header h-100\">\n <div\n class=\"seam-signature-input-img__upload-box h-100\"\n [class.has-preview]=\"!!_previewDataUrl()\"\n [style.background-image]=\"_previewBackgroundImage()\"\n tabindex=\"0\"\n seamFileDropZone\n accept=\"image/*\"\n (seamFileDrop)=\"_onFilesDropped($event)\"\n (click)=\"openFileBrowse()\"\n (keydown.enter)=\"openFileBrowse()\"\n >\n @if (!_previewDataUrl()) {\n <div class=\"seam-signature-input-img__drop-prompt\">\n <strong>Choose a file</strong> or drag it here\n </div>\n }\n </div>\n\n @if (_sizeError(); as err) {\n <div class=\"seam-signature-input-img__size-error\">{{ err }}</div>\n }\n </div>\n </div>\n\n <input\n #filesInput\n type=\"file\"\n hidden\n accept=\"image/*\"\n (change)=\"_onNativeChange($event)\"\n />\n</div>\n", styles: [":host{display:block}.seam-signature-input-img{border-bottom:1px solid black}.seam-signature-input-img__header{font-weight:500}.seam-signature-input-img__upload-container{height:174px;position:relative}.seam-signature-input-img__upload-box{position:relative;text-align:center;cursor:pointer;background-repeat:no-repeat;background-position:center;background-size:contain}.seam-signature-input-img__upload-box.has-preview{background-color:#fff}.seam-signature-input-img__size-error{color:var(--bs-danger, #dc3545)}\n"], dependencies: [{ kind: "directive", type: TheSeamFileDropZoneDirective, selector: "[seamFileDropZone]", inputs: ["accept", "maxSize", "maxFiles", "disabled"], outputs: ["seamFileDrop", "seamFileDropRejected"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
164
126
|
}
|
|
165
127
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TheSeamSignatureInputImgComponent, decorators: [{
|
|
166
128
|
type: Component,
|
|
167
|
-
args: [{ selector: 'seam-signature-input-img', imports: [
|
|
129
|
+
args: [{ selector: 'seam-signature-input-img', imports: [TheSeamFileDropZoneDirective], providers: [
|
|
168
130
|
{
|
|
169
131
|
provide: NG_VALUE_ACCESSOR,
|
|
170
132
|
useExisting: TheSeamSignatureInputImgComponent,
|
|
171
133
|
multi: true,
|
|
172
134
|
},
|
|
173
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"seam-signature-input-img\">\n <div class=\"seam-signature-input-img__upload-container\">\n <div class=\"seam-signature-input-img__header h-100\">\n <div\n class=\"seam-signature-input-img__upload-box h-100\"\n [class.has-preview]=\"!!_previewDataUrl()\"\n [style.background-image]=\"_previewBackgroundImage()\"\n tabindex=\"0\"\n (
|
|
174
|
-
}], ctorParameters: () => [] });
|
|
135
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"seam-signature-input-img\">\n <div class=\"seam-signature-input-img__upload-container\">\n <div class=\"seam-signature-input-img__header h-100\">\n <div\n class=\"seam-signature-input-img__upload-box h-100\"\n [class.has-preview]=\"!!_previewDataUrl()\"\n [style.background-image]=\"_previewBackgroundImage()\"\n tabindex=\"0\"\n seamFileDropZone\n accept=\"image/*\"\n (seamFileDrop)=\"_onFilesDropped($event)\"\n (click)=\"openFileBrowse()\"\n (keydown.enter)=\"openFileBrowse()\"\n >\n @if (!_previewDataUrl()) {\n <div class=\"seam-signature-input-img__drop-prompt\">\n <strong>Choose a file</strong> or drag it here\n </div>\n }\n </div>\n\n @if (_sizeError(); as err) {\n <div class=\"seam-signature-input-img__size-error\">{{ err }}</div>\n }\n </div>\n </div>\n\n <input\n #filesInput\n type=\"file\"\n hidden\n accept=\"image/*\"\n (change)=\"_onNativeChange($event)\"\n />\n</div>\n", styles: [":host{display:block}.seam-signature-input-img{border-bottom:1px solid black}.seam-signature-input-img__header{font-weight:500}.seam-signature-input-img__upload-container{height:174px;position:relative}.seam-signature-input-img__upload-box{position:relative;text-align:center;cursor:pointer;background-repeat:no-repeat;background-position:center;background-size:contain}.seam-signature-input-img__upload-box.has-preview{background-color:#fff}.seam-signature-input-img__size-error{color:var(--bs-danger, #dc3545)}\n"] }]
|
|
136
|
+
}], ctorParameters: () => [], propDecorators: { _nativeInput: [{ type: i0.ViewChild, args: ['filesInput', { isSignal: true }] }] } });
|
|
175
137
|
|
|
176
138
|
const DEFAULT_OPTIONS = {
|
|
177
139
|
canvasWidth: 500,
|
|
@@ -271,7 +233,7 @@ class TheSeamSignatureInputPenComponent {
|
|
|
271
233
|
useExisting: TheSeamSignatureInputPenComponent,
|
|
272
234
|
multi: true,
|
|
273
235
|
},
|
|
274
|
-
], viewQueries: [{ propertyName: "_signaturePad", first: true, predicate: ["sigPad"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n class=\"seam-signature-input-pen__canvas-wrap\"\n [style.width.px]=\"_canvasWidth()\"\n [style.height.px]=\"_canvasHeight()\"\n>\n <signature-pad\n #sigPad\n [options]=\"options()\"\n (drawStart)=\"_drawStart($event)\"\n (drawEnd)=\"_drawComplete($event)\"\n ></signature-pad>\n</div>\n", styles: [":host{display:block;overflow:hidden;position:relative}.seam-signature-input-pen__canvas-wrap{border-bottom:1px solid black}signature-pad{background:none!important}signature-pad ::ng-deep .signature-pad-canvas{border:none!important}\n"], dependencies: [{ kind: "ngmodule", type: AngularSignaturePadModule }, { kind: "component", type: i1
|
|
236
|
+
], viewQueries: [{ propertyName: "_signaturePad", first: true, predicate: ["sigPad"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n class=\"seam-signature-input-pen__canvas-wrap\"\n [style.width.px]=\"_canvasWidth()\"\n [style.height.px]=\"_canvasHeight()\"\n>\n <signature-pad\n #sigPad\n [options]=\"options()\"\n (drawStart)=\"_drawStart($event)\"\n (drawEnd)=\"_drawComplete($event)\"\n ></signature-pad>\n</div>\n", styles: [":host{display:block;overflow:hidden;position:relative}.seam-signature-input-pen__canvas-wrap{border-bottom:1px solid black}signature-pad{background:none!important}signature-pad ::ng-deep .signature-pad-canvas{border:none!important}\n"], dependencies: [{ kind: "ngmodule", type: AngularSignaturePadModule }, { kind: "component", type: i1.SignaturePadComponent, selector: "signature-pad", inputs: ["options"], outputs: ["drawStart", "drawBeforeUpdate", "drawAfterUpdate", "drawEnd"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
275
237
|
}
|
|
276
238
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TheSeamSignatureInputPenComponent, decorators: [{
|
|
277
239
|
type: Component,
|
|
@@ -583,7 +545,7 @@ class TheSeamSignatureInputPanelComponent {
|
|
|
583
545
|
provide: THESEAM_SIGNATURE_INPUT_CONTAINER,
|
|
584
546
|
useExisting: TheSeamSignatureInputPanelComponent,
|
|
585
547
|
},
|
|
586
|
-
], ngImport: i0, template: "<div class=\"seam-signature-input-panel\">\n <div class=\"seam-signature-input-panel__content\" cdkTrapFocus>\n <div class=\"seam-signature-input-panel__options pb-2 mb-1\">\n <button\n seamButton\n theme=\"primary\"\n [class.btn-sm]=\"_isSm()\"\n class=\"text-nowrap mr-1\"\n [class.active]=\"_activeType() === 'pen'\"\n (click)=\"showType('pen')\"\n >\n <seam-icon [icon]=\"_faSignature\" size=\"sm\"></seam-icon> Draw\n </button>\n <button\n seamButton\n theme=\"primary\"\n [class.btn-sm]=\"_isSm()\"\n class=\"text-nowrap mx-1\"\n [class.active]=\"_activeType() === 'text'\"\n (click)=\"showType('text')\"\n >\n <seam-icon [icon]=\"_faKeyboard\" size=\"sm\"></seam-icon> Type\n </button>\n <button\n seamButton\n theme=\"primary\"\n [class.btn-sm]=\"_isSm()\"\n class=\"text-nowrap ml-1\"\n [class.active]=\"_activeType() === 'img'\"\n (click)=\"showType('img')\"\n >\n <seam-icon [icon]=\"_faUpload\" size=\"sm\"></seam-icon> Upload\n </button>\n </div>\n\n <form [formGroup]=\"_form\">\n @switch (_activeType()) {\n @case ('pen') {\n <seam-signature-input-pen\n formControlName=\"pen\"\n ></seam-signature-input-pen>\n }\n @case ('text') {\n <seam-signature-input-text\n formControlName=\"text\"\n ></seam-signature-input-text>\n }\n @case ('img') {\n <seam-signature-input-img\n formControlName=\"img\"\n ></seam-signature-input-img>\n }\n }\n </form>\n\n <div class=\"seam-signature-input-panel__footer mt-1\">\n <div>\n @if (_resetType() === 'delete') {\n <button\n seamButton\n theme=\"danger\"\n [class.btn-sm]=\"_isSm()\"\n [disabled]=\"_valueEmpty()\"\n (click)=\"_onClearBtnClick($event)\"\n >\n Delete\n </button>\n } @else {\n <button\n seamButton\n theme=\"lightgray\"\n [class.btn-sm]=\"_isSm()\"\n [disabled]=\"_valueEmpty()\"\n (click)=\"_onClearBtnClick($event)\"\n >\n Clear\n </button>\n }\n </div>\n <div>\n <button\n seamButton\n theme=\"lightgray\"\n [class.btn-sm]=\"_isSm()\"\n seamAutoFocus\n (click)=\"_onCancelBtnClick($event)\"\n >\n Cancel\n </button>\n <button\n seamButton\n theme=\"primary\"\n [class.btn-sm]=\"_isSm()\"\n [disabled]=\"!_canSubmit()\"\n (click)=\"_onSubmitBtnClick($event)\"\n >\n Apply Signature\n </button>\n </div>\n </div>\n </div>\n</div>\n", styles: [":host{display:block}.seam-signature-input-panel{background-color:#fff;border-radius:4px}.seam-signature-input-panel__options{padding:8px 8px 0;border-bottom:1px solid black;display:flex;flex-direction:row;justify-content:flex-end}.seam-signature-input-panel__footer{padding:0 8px 8px;display:flex;flex-direction:row;justify-content:space-between;margin-top:2px}.seam-signature-input-panel__footer>div>*:not(:last-child){margin-right:6px}.seam-signature-input-panel__footer button{height:36px;margin-top:6px}\n"], dependencies: [{ kind: "ngmodule", type: A11yModule }, { kind: "directive", type: i1$
|
|
548
|
+
], ngImport: i0, template: "<div class=\"seam-signature-input-panel\">\n <div class=\"seam-signature-input-panel__content\" cdkTrapFocus>\n <div class=\"seam-signature-input-panel__options pb-2 mb-1\">\n <button\n seamButton\n theme=\"primary\"\n [class.btn-sm]=\"_isSm()\"\n class=\"text-nowrap mr-1\"\n [class.active]=\"_activeType() === 'pen'\"\n (click)=\"showType('pen')\"\n >\n <seam-icon [icon]=\"_faSignature\" size=\"sm\"></seam-icon> Draw\n </button>\n <button\n seamButton\n theme=\"primary\"\n [class.btn-sm]=\"_isSm()\"\n class=\"text-nowrap mx-1\"\n [class.active]=\"_activeType() === 'text'\"\n (click)=\"showType('text')\"\n >\n <seam-icon [icon]=\"_faKeyboard\" size=\"sm\"></seam-icon> Type\n </button>\n <button\n seamButton\n theme=\"primary\"\n [class.btn-sm]=\"_isSm()\"\n class=\"text-nowrap ml-1\"\n [class.active]=\"_activeType() === 'img'\"\n (click)=\"showType('img')\"\n >\n <seam-icon [icon]=\"_faUpload\" size=\"sm\"></seam-icon> Upload\n </button>\n </div>\n\n <form [formGroup]=\"_form\">\n @switch (_activeType()) {\n @case ('pen') {\n <seam-signature-input-pen\n formControlName=\"pen\"\n ></seam-signature-input-pen>\n }\n @case ('text') {\n <seam-signature-input-text\n formControlName=\"text\"\n ></seam-signature-input-text>\n }\n @case ('img') {\n <seam-signature-input-img\n formControlName=\"img\"\n ></seam-signature-input-img>\n }\n }\n </form>\n\n <div class=\"seam-signature-input-panel__footer mt-1\">\n <div>\n @if (_resetType() === 'delete') {\n <button\n seamButton\n theme=\"danger\"\n [class.btn-sm]=\"_isSm()\"\n [disabled]=\"_valueEmpty()\"\n (click)=\"_onClearBtnClick($event)\"\n >\n Delete\n </button>\n } @else {\n <button\n seamButton\n theme=\"lightgray\"\n [class.btn-sm]=\"_isSm()\"\n [disabled]=\"_valueEmpty()\"\n (click)=\"_onClearBtnClick($event)\"\n >\n Clear\n </button>\n }\n </div>\n <div>\n <button\n seamButton\n theme=\"lightgray\"\n [class.btn-sm]=\"_isSm()\"\n seamAutoFocus\n (click)=\"_onCancelBtnClick($event)\"\n >\n Cancel\n </button>\n <button\n seamButton\n theme=\"primary\"\n [class.btn-sm]=\"_isSm()\"\n [disabled]=\"!_canSubmit()\"\n (click)=\"_onSubmitBtnClick($event)\"\n >\n Apply Signature\n </button>\n </div>\n </div>\n </div>\n</div>\n", styles: [":host{display:block}.seam-signature-input-panel{background-color:#fff;border-radius:4px}.seam-signature-input-panel__options{padding:8px 8px 0;border-bottom:1px solid black;display:flex;flex-direction:row;justify-content:flex-end}.seam-signature-input-panel__footer{padding:0 8px 8px;display:flex;flex-direction:row;justify-content:space-between;margin-top:2px}.seam-signature-input-panel__footer>div>*:not(:last-child){margin-right:6px}.seam-signature-input-panel__footer button{height:36px;margin-top:6px}\n"], dependencies: [{ kind: "ngmodule", type: A11yModule }, { kind: "directive", type: i1$1.CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: TheSeamButtonsModule }, { kind: "component", type: i3.TheSeamButtonComponent, selector: "button[seamButton]", inputs: ["disabled", "theme", "size", "type"], exportAs: ["seamButton"] }, { kind: "ngmodule", type: TheSeamIconModule }, { kind: "component", type: i4.IconComponent, selector: "seam-icon", inputs: ["grayscaleOnDisable", "disabled", "iconClass", "icon", "size", "showDefaultOnError", "defaultIcon", "iconType"] }, { kind: "directive", type: TheSeamAutoFocusDirective, selector: "[seamAutoFocus]", inputs: ["seamAutoFocus"], exportAs: ["seamAutoFocus"] }, { kind: "component", type: TheSeamSignatureInputPenComponent, selector: "seam-signature-input-pen", inputs: ["options"], outputs: ["beginDrawing", "endDrawing"] }, { kind: "component", type: TheSeamSignatureInputTextComponent, selector: "seam-signature-input-text" }, { kind: "component", type: TheSeamSignatureInputImgComponent, selector: "seam-signature-input-img" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
587
549
|
}
|
|
588
550
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TheSeamSignatureInputPanelComponent, decorators: [{
|
|
589
551
|
type: Component,
|
|
@@ -610,9 +572,144 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
|
|
|
610
572
|
}, template: "<div class=\"seam-signature-input-panel\">\n <div class=\"seam-signature-input-panel__content\" cdkTrapFocus>\n <div class=\"seam-signature-input-panel__options pb-2 mb-1\">\n <button\n seamButton\n theme=\"primary\"\n [class.btn-sm]=\"_isSm()\"\n class=\"text-nowrap mr-1\"\n [class.active]=\"_activeType() === 'pen'\"\n (click)=\"showType('pen')\"\n >\n <seam-icon [icon]=\"_faSignature\" size=\"sm\"></seam-icon> Draw\n </button>\n <button\n seamButton\n theme=\"primary\"\n [class.btn-sm]=\"_isSm()\"\n class=\"text-nowrap mx-1\"\n [class.active]=\"_activeType() === 'text'\"\n (click)=\"showType('text')\"\n >\n <seam-icon [icon]=\"_faKeyboard\" size=\"sm\"></seam-icon> Type\n </button>\n <button\n seamButton\n theme=\"primary\"\n [class.btn-sm]=\"_isSm()\"\n class=\"text-nowrap ml-1\"\n [class.active]=\"_activeType() === 'img'\"\n (click)=\"showType('img')\"\n >\n <seam-icon [icon]=\"_faUpload\" size=\"sm\"></seam-icon> Upload\n </button>\n </div>\n\n <form [formGroup]=\"_form\">\n @switch (_activeType()) {\n @case ('pen') {\n <seam-signature-input-pen\n formControlName=\"pen\"\n ></seam-signature-input-pen>\n }\n @case ('text') {\n <seam-signature-input-text\n formControlName=\"text\"\n ></seam-signature-input-text>\n }\n @case ('img') {\n <seam-signature-input-img\n formControlName=\"img\"\n ></seam-signature-input-img>\n }\n }\n </form>\n\n <div class=\"seam-signature-input-panel__footer mt-1\">\n <div>\n @if (_resetType() === 'delete') {\n <button\n seamButton\n theme=\"danger\"\n [class.btn-sm]=\"_isSm()\"\n [disabled]=\"_valueEmpty()\"\n (click)=\"_onClearBtnClick($event)\"\n >\n Delete\n </button>\n } @else {\n <button\n seamButton\n theme=\"lightgray\"\n [class.btn-sm]=\"_isSm()\"\n [disabled]=\"_valueEmpty()\"\n (click)=\"_onClearBtnClick($event)\"\n >\n Clear\n </button>\n }\n </div>\n <div>\n <button\n seamButton\n theme=\"lightgray\"\n [class.btn-sm]=\"_isSm()\"\n seamAutoFocus\n (click)=\"_onCancelBtnClick($event)\"\n >\n Cancel\n </button>\n <button\n seamButton\n theme=\"primary\"\n [class.btn-sm]=\"_isSm()\"\n [disabled]=\"!_canSubmit()\"\n (click)=\"_onSubmitBtnClick($event)\"\n >\n Apply Signature\n </button>\n </div>\n </div>\n </div>\n</div>\n", styles: [":host{display:block}.seam-signature-input-panel{background-color:#fff;border-radius:4px}.seam-signature-input-panel__options{padding:8px 8px 0;border-bottom:1px solid black;display:flex;flex-direction:row;justify-content:flex-end}.seam-signature-input-panel__footer{padding:0 8px 8px;display:flex;flex-direction:row;justify-content:space-between;margin-top:2px}.seam-signature-input-panel__footer>div>*:not(:last-child){margin-right:6px}.seam-signature-input-panel__footer button{height:36px;margin-top:6px}\n"] }]
|
|
611
573
|
}], propDecorators: { result: [{ type: i0.Output, args: ["result"] }] } });
|
|
612
574
|
|
|
575
|
+
/**
|
|
576
|
+
* Opens the signature input panel in a modal when the host button/anchor is
|
|
577
|
+
* clicked, and writes the submitted data URL back through its bound form
|
|
578
|
+
* control. Implements `ControlValueAccessor` so it works with any of the form
|
|
579
|
+
* binding styles (`formControl`, `formControlName`, `ngModel`).
|
|
580
|
+
*
|
|
581
|
+
* Usage:
|
|
582
|
+
*
|
|
583
|
+
* ```html
|
|
584
|
+
* <button seamButton theme="primary" seamSignatureInput formControlName="signature">
|
|
585
|
+
* Sign
|
|
586
|
+
* </button>
|
|
587
|
+
* ```
|
|
588
|
+
*
|
|
589
|
+
* The selector-name input accepts a partial `ModalConfig` for cases that need
|
|
590
|
+
* to tweak the modal (e.g. `disableClose`):
|
|
591
|
+
*
|
|
592
|
+
* ```html
|
|
593
|
+
* <button
|
|
594
|
+
* seamButton
|
|
595
|
+
* [seamSignatureInput]="{ disableClose: true }"
|
|
596
|
+
* formControlName="signature"
|
|
597
|
+
* >Sign</button>
|
|
598
|
+
* ```
|
|
599
|
+
*/
|
|
600
|
+
class TheSeamSignatureInputButtonDirective {
|
|
601
|
+
_modal = inject(Modal);
|
|
602
|
+
_elementRef = inject(ElementRef);
|
|
603
|
+
// When the same host element also carries `seamButton`/`a[seamButton]`,
|
|
604
|
+
// delegate disabled state to its `disabled` input so its host binding remains
|
|
605
|
+
// the single source of truth for the `disabled` attribute — avoids a
|
|
606
|
+
// tug-of-war between this directive and the button directive's CD.
|
|
607
|
+
_seamButton = inject(TheSeamButtonComponent, {
|
|
608
|
+
optional: true,
|
|
609
|
+
self: true,
|
|
610
|
+
});
|
|
611
|
+
_seamAnchor = inject(TheSeamAnchorButtonComponent, {
|
|
612
|
+
optional: true,
|
|
613
|
+
self: true,
|
|
614
|
+
});
|
|
615
|
+
/**
|
|
616
|
+
* Partial `ModalConfig` passthrough. Most consumers leave this unset; the
|
|
617
|
+
* signature panel's styles assume the default modal size.
|
|
618
|
+
*/
|
|
619
|
+
modalConfig;
|
|
620
|
+
/** Emits the submitted data URL when the user applies a signature. */
|
|
621
|
+
signed = new EventEmitter();
|
|
622
|
+
/** Emits when the user dismisses the panel without submitting. */
|
|
623
|
+
canceled = new EventEmitter();
|
|
624
|
+
_value = null;
|
|
625
|
+
_disabled = false;
|
|
626
|
+
_onChange = () => undefined;
|
|
627
|
+
_onTouched = () => undefined;
|
|
628
|
+
writeValue(value) {
|
|
629
|
+
this._value = value;
|
|
630
|
+
}
|
|
631
|
+
registerOnChange(fn) {
|
|
632
|
+
this._onChange = fn;
|
|
633
|
+
}
|
|
634
|
+
registerOnTouched(fn) {
|
|
635
|
+
this._onTouched = fn;
|
|
636
|
+
}
|
|
637
|
+
setDisabledState(isDisabled) {
|
|
638
|
+
this._disabled = isDisabled;
|
|
639
|
+
if (this._seamButton) {
|
|
640
|
+
this._seamButton.disabled = isDisabled;
|
|
641
|
+
}
|
|
642
|
+
else if (this._seamAnchor) {
|
|
643
|
+
this._seamAnchor.disabled = isDisabled;
|
|
644
|
+
}
|
|
645
|
+
else {
|
|
646
|
+
const el = this._elementRef.nativeElement;
|
|
647
|
+
if (isDisabled) {
|
|
648
|
+
el.setAttribute('disabled', '');
|
|
649
|
+
}
|
|
650
|
+
else {
|
|
651
|
+
el.removeAttribute('disabled');
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
/** @ignore */
|
|
656
|
+
_onClick() {
|
|
657
|
+
if (this._disabled) {
|
|
658
|
+
return;
|
|
659
|
+
}
|
|
660
|
+
const ref = this._modal.openFromComponent(TheSeamSignatureInputPanelComponent, this.modalConfig ?? undefined);
|
|
661
|
+
ref
|
|
662
|
+
.afterClosed()
|
|
663
|
+
.pipe(take(1))
|
|
664
|
+
.subscribe((result) => {
|
|
665
|
+
this._onTouched();
|
|
666
|
+
if (result?.type === 'submit') {
|
|
667
|
+
this._value = result.value;
|
|
668
|
+
this._onChange(result.value);
|
|
669
|
+
this.signed.emit(result.value);
|
|
670
|
+
}
|
|
671
|
+
else {
|
|
672
|
+
this.canceled.emit();
|
|
673
|
+
}
|
|
674
|
+
});
|
|
675
|
+
}
|
|
676
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TheSeamSignatureInputButtonDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
677
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.15", type: TheSeamSignatureInputButtonDirective, isStandalone: true, selector: "button[seamSignatureInput], a[seamSignatureInput]", inputs: { modalConfig: ["seamSignatureInput", "modalConfig"] }, outputs: { signed: "signed", canceled: "canceled" }, host: { listeners: { "click": "_onClick()" } }, providers: [
|
|
678
|
+
{
|
|
679
|
+
provide: NG_VALUE_ACCESSOR,
|
|
680
|
+
useExisting: TheSeamSignatureInputButtonDirective,
|
|
681
|
+
multi: true,
|
|
682
|
+
},
|
|
683
|
+
], exportAs: ["seamSignatureInput"], ngImport: i0 });
|
|
684
|
+
}
|
|
685
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TheSeamSignatureInputButtonDirective, decorators: [{
|
|
686
|
+
type: Directive,
|
|
687
|
+
args: [{
|
|
688
|
+
selector: 'button[seamSignatureInput], a[seamSignatureInput]',
|
|
689
|
+
exportAs: 'seamSignatureInput',
|
|
690
|
+
providers: [
|
|
691
|
+
{
|
|
692
|
+
provide: NG_VALUE_ACCESSOR,
|
|
693
|
+
useExisting: TheSeamSignatureInputButtonDirective,
|
|
694
|
+
multi: true,
|
|
695
|
+
},
|
|
696
|
+
],
|
|
697
|
+
}]
|
|
698
|
+
}], propDecorators: { modalConfig: [{
|
|
699
|
+
type: Input,
|
|
700
|
+
args: ['seamSignatureInput']
|
|
701
|
+
}], signed: [{
|
|
702
|
+
type: Output
|
|
703
|
+
}], canceled: [{
|
|
704
|
+
type: Output
|
|
705
|
+
}], _onClick: [{
|
|
706
|
+
type: HostListener,
|
|
707
|
+
args: ['click']
|
|
708
|
+
}] } });
|
|
709
|
+
|
|
613
710
|
class TheSeamSignatureInputImgHarness extends ComponentHarness {
|
|
614
711
|
static hostSelector = 'seam-signature-input-img';
|
|
615
|
-
_fileDrop = this.locatorFor('
|
|
712
|
+
_fileDrop = this.locatorFor('.seam-signature-input-img__upload-box');
|
|
616
713
|
_sizeError = this.locatorForOptional('.seam-signature-input-img__size-error');
|
|
617
714
|
_preview = this.locatorForOptional('.seam-signature-input-img__preview');
|
|
618
715
|
async getSizeError() {
|
|
@@ -735,9 +832,25 @@ class TheSeamSignatureInputPanelHarness extends ComponentHarness {
|
|
|
735
832
|
}
|
|
736
833
|
}
|
|
737
834
|
|
|
835
|
+
class TheSeamSignatureInputButtonHarness extends ComponentHarness {
|
|
836
|
+
static hostSelector = 'button[seamSignatureInput], a[seamSignatureInput]';
|
|
837
|
+
static with(options = {}) {
|
|
838
|
+
return new HarnessPredicate(TheSeamSignatureInputButtonHarness, options).addOption('text', options.text, (harness, text) => HarnessPredicate.stringMatches(harness.getText(), text));
|
|
839
|
+
}
|
|
840
|
+
async getText() {
|
|
841
|
+
return (await this.host()).text();
|
|
842
|
+
}
|
|
843
|
+
async isDisabled() {
|
|
844
|
+
return (await this.host()).getAttribute('disabled').then((v) => v !== null);
|
|
845
|
+
}
|
|
846
|
+
async click() {
|
|
847
|
+
await (await this.host()).click();
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
|
|
738
851
|
/**
|
|
739
852
|
* Generated bundle index. Do not edit.
|
|
740
853
|
*/
|
|
741
854
|
|
|
742
|
-
export { THESEAM_SIGNATURE_INPUT_CONTAINER, TheSeamSignatureInputImgComponent, TheSeamSignatureInputImgHarness, TheSeamSignatureInputPanelComponent, TheSeamSignatureInputPanelHarness, TheSeamSignatureInputPenComponent, TheSeamSignatureInputPenHarness, TheSeamSignatureInputTextComponent, TheSeamSignatureInputTextHarness };
|
|
855
|
+
export { THESEAM_SIGNATURE_INPUT_CONTAINER, TheSeamSignatureInputButtonDirective, TheSeamSignatureInputButtonHarness, TheSeamSignatureInputImgComponent, TheSeamSignatureInputImgHarness, TheSeamSignatureInputPanelComponent, TheSeamSignatureInputPanelHarness, TheSeamSignatureInputPenComponent, TheSeamSignatureInputPenHarness, TheSeamSignatureInputTextComponent, TheSeamSignatureInputTextHarness };
|
|
743
856
|
//# sourceMappingURL=theseam-ui-common-signature-input.mjs.map
|