mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2026-09-09 18:03:21 +00:00
AAE-43707 Add storybook stories for pdf viewer family
Adds Storybook coverage for pdf-viewer, pdf-viewer-thumb and pdf-viewer-thumbnails. The thumbnail stories use lightweight mocks that emulate the pdf.js PDFViewer page descriptor surface so the panels can be rendered in isolation.
This commit is contained in:
+119
@@ -0,0 +1,119 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { applicationConfig, Meta, StoryObj, moduleMetadata } from '@storybook/angular';
|
||||
import { PdfThumbComponent } from './pdf-viewer-thumb.component';
|
||||
import { provideStoryCore } from '../../../stories/core-story.providers';
|
||||
|
||||
const buildMockPage = (id: number, color: string) => ({
|
||||
id,
|
||||
getWidth: () => 91,
|
||||
getHeight: () => 114,
|
||||
getPage: () =>
|
||||
Promise.resolve({
|
||||
getViewport: ({ scale }: { scale: number }) => ({ width: 91 * scale, height: 114 * scale }),
|
||||
render: ({ canvasContext, viewport }: { canvasContext: CanvasRenderingContext2D; viewport: { width: number; height: number } }) => {
|
||||
canvasContext.fillStyle = color;
|
||||
canvasContext.fillRect(0, 0, viewport.width, viewport.height);
|
||||
canvasContext.fillStyle = '#333';
|
||||
canvasContext.font = '14px sans-serif';
|
||||
canvasContext.fillText(`Page ${id}`, 16, 24);
|
||||
return { promise: Promise.resolve() };
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
const EMPTY_PAGE = {
|
||||
id: 0,
|
||||
getWidth: () => 91,
|
||||
getHeight: () => 114,
|
||||
getPage: () => new Promise(() => undefined)
|
||||
};
|
||||
|
||||
type PdfThumbStoryArgs = PdfThumbComponent & {
|
||||
selected?: boolean;
|
||||
};
|
||||
|
||||
const meta: Meta<PdfThumbStoryArgs> = {
|
||||
component: PdfThumbComponent,
|
||||
title: 'Core/Viewer/PDF Viewer Thumb',
|
||||
decorators: [
|
||||
moduleMetadata({
|
||||
imports: [PdfThumbComponent]
|
||||
}),
|
||||
applicationConfig({
|
||||
providers: [...provideStoryCore()]
|
||||
})
|
||||
],
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
component: `Single thumbnail tile rendered for a page in the PDF Viewer thumbnails panel. Renders a small canvas preview from the supplied \`page\` descriptor.`
|
||||
}
|
||||
}
|
||||
},
|
||||
argTypes: {
|
||||
page: {
|
||||
control: false,
|
||||
description: 'Page descriptor providing `getPage()`, `getWidth()` and `getHeight()` used to render the thumbnail.',
|
||||
table: { type: { summary: 'PdfThumbnailPage' } }
|
||||
},
|
||||
selected: {
|
||||
control: 'boolean',
|
||||
description: 'Visual flag toggled by the parent thumbnails list when the page is the active one.',
|
||||
table: { category: 'Storybook Helpers' }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<PdfThumbStoryArgs>;
|
||||
|
||||
export const Empty: Story = {
|
||||
args: {
|
||||
page: EMPTY_PAGE,
|
||||
selected: false
|
||||
},
|
||||
render: (args) => ({
|
||||
props: args,
|
||||
template: `<adf-pdf-thumb [page]="page" style="display:inline-block; padding:8px;" />`
|
||||
})
|
||||
};
|
||||
|
||||
export const Populated: Story = {
|
||||
args: {
|
||||
page: buildMockPage(1, '#e3f2fd'),
|
||||
selected: false
|
||||
},
|
||||
render: (args) => ({
|
||||
props: args,
|
||||
template: `<adf-pdf-thumb [page]="page" style="display:inline-block; padding:8px;" />`
|
||||
})
|
||||
};
|
||||
|
||||
export const Selected: Story = {
|
||||
args: {
|
||||
page: buildMockPage(2, '#bbdefb'),
|
||||
selected: true
|
||||
},
|
||||
render: (args) => ({
|
||||
props: args,
|
||||
template: `<div [style.outline]="selected ? '2px solid #1976d2' : 'none'" style="display:inline-block; padding:8px;">
|
||||
<adf-pdf-thumb [page]="page" />
|
||||
</div>`
|
||||
})
|
||||
};
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { applicationConfig, Meta, StoryObj, moduleMetadata } from '@storybook/angular';
|
||||
import { PdfThumbListComponent } from './pdf-viewer-thumbnails.component';
|
||||
import { provideStoryCore } from '../../../stories/core-story.providers';
|
||||
|
||||
const buildPdfViewerMock = (totalPages: number) => {
|
||||
const pageHandlers: Array<(event: { pageNumber: number }) => void> = [];
|
||||
|
||||
const buildMockPage = (id: number) => ({
|
||||
id,
|
||||
width: 91,
|
||||
height: 114
|
||||
});
|
||||
|
||||
const buildPageProxy = (id: number) => ({
|
||||
getViewport: ({ scale }: { scale: number }) => ({ width: 91 * scale, height: 114 * scale }),
|
||||
render: ({ canvasContext, viewport }: { canvasContext: CanvasRenderingContext2D; viewport: { width: number; height: number } }) => {
|
||||
canvasContext.fillStyle = id % 2 ? '#e3f2fd' : '#f3e5f5';
|
||||
canvasContext.fillRect(0, 0, viewport.width, viewport.height);
|
||||
canvasContext.fillStyle = '#333';
|
||||
canvasContext.font = '12px sans-serif';
|
||||
canvasContext.fillText(`Page ${id}`, 12, 20);
|
||||
return { promise: Promise.resolve() };
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
currentPageNumber: 1,
|
||||
pagesCount: totalPages,
|
||||
_pages: Array.from({ length: totalPages }, (_, i) => buildMockPage(i + 1)),
|
||||
pdfDocument: {
|
||||
getPage: (id: number) => Promise.resolve(buildPageProxy(id))
|
||||
},
|
||||
eventBus: {
|
||||
on: (event: string, handler: (e: { pageNumber: number }) => void) => {
|
||||
if (event === 'pagechanging') {
|
||||
pageHandlers.push(handler);
|
||||
}
|
||||
},
|
||||
off: () => undefined
|
||||
}
|
||||
} as any;
|
||||
};
|
||||
|
||||
type PdfThumbnailsStoryArgs = PdfThumbListComponent & {
|
||||
pageCount?: number;
|
||||
};
|
||||
|
||||
const meta: Meta<PdfThumbnailsStoryArgs> = {
|
||||
component: PdfThumbListComponent,
|
||||
title: 'Core/Viewer/PDF Viewer Thumbnails',
|
||||
decorators: [
|
||||
moduleMetadata({
|
||||
imports: [PdfThumbListComponent]
|
||||
}),
|
||||
applicationConfig({
|
||||
providers: [...provideStoryCore()]
|
||||
})
|
||||
],
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
component: `Side panel listing thumbnails for every page of the PDF currently rendered by the \`adf-pdf-viewer\`. Stories use a lightweight mock of the underlying \`PDFViewer\`.`
|
||||
}
|
||||
}
|
||||
},
|
||||
argTypes: {
|
||||
pdfViewer: {
|
||||
control: false,
|
||||
description: 'Reference to the underlying pdf.js `PDFViewer` instance. Required input.',
|
||||
table: { type: { summary: 'PDFViewer' } }
|
||||
},
|
||||
pageCount: {
|
||||
control: { type: 'number', min: 0, max: 50 },
|
||||
description: 'Number of pages used to build the mock `PDFViewer`.',
|
||||
table: { category: 'Storybook Helpers' }
|
||||
},
|
||||
close: {
|
||||
action: 'close',
|
||||
description: 'Emitted when the user requests to close the thumbnails panel (e.g. via Escape).',
|
||||
table: { type: { summary: 'EventEmitter <void>' }, category: 'Actions' }
|
||||
}
|
||||
},
|
||||
args: {
|
||||
pageCount: 5
|
||||
},
|
||||
render: (args) => ({
|
||||
props: {
|
||||
...args,
|
||||
pdfViewer: buildPdfViewerMock(args.pageCount ?? 0)
|
||||
},
|
||||
template: `<div style="height:480px; width:140px; border:1px solid #ddd; overflow:hidden;">
|
||||
<adf-pdf-thumbnails [pdfViewer]="pdfViewer" (close)="close($event)" style="display:block; height:100%;" />
|
||||
</div>`
|
||||
})
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<PdfThumbnailsStoryArgs>;
|
||||
|
||||
export const Empty: Story = {
|
||||
args: { pageCount: 0 }
|
||||
};
|
||||
|
||||
export const Populated: Story = {
|
||||
args: { pageCount: 8 }
|
||||
};
|
||||
|
||||
export const Selected: Story = {
|
||||
args: { pageCount: 4 }
|
||||
};
|
||||
@@ -0,0 +1,142 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { applicationConfig, Meta, StoryObj, moduleMetadata } from '@storybook/angular';
|
||||
import { PdfViewerComponent } from './pdf-viewer.component';
|
||||
import { provideStoryCore } from '../../../stories/core-story.providers';
|
||||
|
||||
const SAMPLE_PDF_URL = 'https://mozilla.github.io/pdf.js/web/compressed.tracemonkey-pldi-09.pdf';
|
||||
|
||||
const meta: Meta<PdfViewerComponent> = {
|
||||
component: PdfViewerComponent,
|
||||
title: 'Core/Viewer/PDF Viewer',
|
||||
decorators: [
|
||||
moduleMetadata({
|
||||
imports: [PdfViewerComponent]
|
||||
}),
|
||||
applicationConfig({
|
||||
providers: [...provideStoryCore()]
|
||||
})
|
||||
],
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
component: `Renders PDF documents using \`pdfjs-dist\`. Stories require the pdf.js worker assets to be served by Storybook; see the Viewer documentation for details.`
|
||||
}
|
||||
}
|
||||
},
|
||||
argTypes: {
|
||||
urlFile: {
|
||||
control: 'text',
|
||||
description: 'External URL of the PDF file to load.',
|
||||
table: { type: { summary: 'string' } }
|
||||
},
|
||||
blobFile: {
|
||||
control: false,
|
||||
description: 'In-memory Blob containing the PDF binary content.',
|
||||
table: { type: { summary: 'Blob' } }
|
||||
},
|
||||
fileName: {
|
||||
control: 'text',
|
||||
description: 'Optional file name displayed by the toolbar.',
|
||||
table: { type: { summary: 'string' } }
|
||||
},
|
||||
showToolbar: {
|
||||
control: 'boolean',
|
||||
description: 'Whether to show the PDF viewer toolbar (page navigation, zoom, ...).',
|
||||
table: { type: { summary: 'boolean' }, defaultValue: { summary: 'true' } }
|
||||
},
|
||||
allowThumbnails: {
|
||||
control: 'boolean',
|
||||
description: 'Whether the thumbnails side panel can be opened.',
|
||||
table: { type: { summary: 'boolean' }, defaultValue: { summary: 'false' } }
|
||||
},
|
||||
cacheType: {
|
||||
control: 'text',
|
||||
description: 'Optional `Cache-Control` header value used when loading via URL.',
|
||||
table: { type: { summary: 'string' } }
|
||||
},
|
||||
rendered: {
|
||||
action: 'rendered',
|
||||
description: 'Emitted after a page is rendered.',
|
||||
table: { type: { summary: 'EventEmitter <void>' }, category: 'Actions' }
|
||||
},
|
||||
error: {
|
||||
action: 'error',
|
||||
description: 'Emitted when the PDF fails to load.',
|
||||
table: { type: { summary: 'EventEmitter <void>' }, category: 'Actions' }
|
||||
},
|
||||
close: {
|
||||
action: 'close',
|
||||
description: 'Emitted when the password dialog is dismissed without supplying a password.',
|
||||
table: { type: { summary: 'EventEmitter <void>' }, category: 'Actions' }
|
||||
},
|
||||
pagesLoaded: {
|
||||
action: 'pagesLoaded',
|
||||
description: 'Emitted when all pages of the document finish loading.',
|
||||
table: { type: { summary: 'EventEmitter <void>' }, category: 'Actions' }
|
||||
}
|
||||
},
|
||||
args: {
|
||||
urlFile: SAMPLE_PDF_URL,
|
||||
fileName: 'sample.pdf',
|
||||
showToolbar: true,
|
||||
allowThumbnails: false
|
||||
},
|
||||
render: (args) => ({
|
||||
props: args,
|
||||
template: `<div style="height:600px; border:1px solid #ddd;">
|
||||
<adf-pdf-viewer
|
||||
[urlFile]="urlFile"
|
||||
[fileName]="fileName"
|
||||
[showToolbar]="showToolbar"
|
||||
[allowThumbnails]="allowThumbnails"
|
||||
[cacheType]="cacheType"
|
||||
(rendered)="rendered($event)"
|
||||
(error)="error($event)"
|
||||
(close)="close($event)"
|
||||
(pagesLoaded)="pagesLoaded($event)" />
|
||||
</div>`
|
||||
})
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<PdfViewerComponent>;
|
||||
|
||||
export const WithSamplePdf: Story = {
|
||||
args: {
|
||||
urlFile: SAMPLE_PDF_URL,
|
||||
showToolbar: true,
|
||||
allowThumbnails: false
|
||||
}
|
||||
};
|
||||
|
||||
export const WithThumbnailsEnabled: Story = {
|
||||
args: {
|
||||
urlFile: SAMPLE_PDF_URL,
|
||||
showToolbar: true,
|
||||
allowThumbnails: true
|
||||
}
|
||||
};
|
||||
|
||||
export const ToolbarHidden: Story = {
|
||||
args: {
|
||||
urlFile: SAMPLE_PDF_URL,
|
||||
showToolbar: false,
|
||||
allowThumbnails: false
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user