@webx-ui/module-catalog 0.2.0 → 0.4.0

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.
@@ -2,7 +2,9 @@ import { BulkActionInfo } from './types';
2
2
  /**
3
3
  * What a bulk action asks for before it runs — a category, a label — and the last word before it
4
4
  * does: how many products it is about to touch. The fields are drawn from what the server said
5
- * about the action, so a satellite's action gets its dialog without this file knowing it.
5
+ * about the action, so a satellite's action gets its dialog without this file knowing it: a
6
+ * param with a `source` is a choice out of that reference book (a label, a brand), and one that is
7
+ * not required says what choosing nothing does — for `set-brand`, take the brand off.
6
8
  */
7
9
  type __VLS_Props = {
8
10
  action: BulkActionInfo;
@@ -0,0 +1,6 @@
1
+ import { ColumnValue } from './types';
2
+ type __VLS_Props = {
3
+ value: ColumnValue | undefined;
4
+ };
5
+ declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
6
+ export default _default;
@@ -1,2 +1,16 @@
1
- declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, HTMLDivElement>;
1
+ type __VLS_Props = {
2
+ /** Videos on this site (`webx-catalog.fields.video`); the server's screen patch says. */
3
+ video?: boolean;
4
+ /** What a video file may be, checked before a byte of it is sent. */
5
+ videoTypes?: string[];
6
+ /** How large, in bytes. */
7
+ videoMaxBytes?: number;
8
+ };
9
+ declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
10
+ video: boolean;
11
+ videoTypes: string[];
12
+ videoMaxBytes: number;
13
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {
14
+ picker: HTMLInputElement;
15
+ }, HTMLDivElement>;
2
16
  export default _default;
@@ -0,0 +1,26 @@
1
+ type __VLS_Props = {
2
+ options?: Array<{
3
+ label: string;
4
+ value: string;
5
+ }>;
6
+ disabled?: boolean;
7
+ ariaLabel?: string;
8
+ };
9
+ type __VLS_PublicProps = {
10
+ modelValue?: string | null;
11
+ } & __VLS_Props;
12
+ declare const _default: import('vue').DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
13
+ "update:modelValue": (value: string | null) => any;
14
+ }, string, import('vue').PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
15
+ "onUpdate:modelValue"?: ((value: string | null) => any) | undefined;
16
+ }>, {
17
+ disabled: boolean;
18
+ ariaLabel: string;
19
+ options: Array<{
20
+ label: string;
21
+ value: string;
22
+ }>;
23
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {
24
+ root: HTMLDivElement;
25
+ }, HTMLDivElement>;
26
+ export default _default;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * A video by its address, onto a picture of the gallery: a YouTube link, or a direct link to an
3
+ * MP4 or WebM file the server then downloads in its queue (§5 of the video spec).
4
+ */
5
+ type __VLS_Props = {
6
+ product: number;
7
+ image: number;
8
+ };
9
+ declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {
10
+ field: HTMLDivElement;
11
+ }, any>;
12
+ export default _default;
@@ -0,0 +1,11 @@
1
+ import { GalleryVideo, VideoJob } from './galleryVideo';
2
+ /**
3
+ * One video on its way into the gallery: what it is doing, and the bar while the file goes up —
4
+ * the share, the speed and the time left, with pause and cancel beside it.
5
+ */
6
+ type __VLS_Props = {
7
+ job: VideoJob;
8
+ video: GalleryVideo;
9
+ };
10
+ declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLDivElement>;
11
+ export default _default;
package/dist/api.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { AdminContext } from '@webx-ui/module-admin';
2
2
  import { Paginated } from '@webx-ui/core';
3
3
  import { ScreenModel } from '@webx-ui/schema';
4
- import { BulkActionInfo, BulkRun, BulkSelection, CategoryDetail, CategoryNode, CategoryRow, DeletedCategory, DeletedKind, DeletedProduct, FacetRegistryAnswer, ProductDetail, ProductImage, ProductQuery, ProductRow, ProductsPage } from './types';
4
+ import { BulkActionInfo, BulkRun, BulkSelection, CategoryDetail, CategoryNode, CategoryRow, DeletedCategory, DeletedKind, DeletedProduct, FacetRegistryAnswer, ProductDetail, ProductImage, ProductQuery, QueuedVideo, ProductRow, ProductsPage } from './types';
5
5
  export interface CatalogApi {
6
6
  products(query?: ProductQuery): Promise<ProductsPage>;
7
7
  product(id: number): Promise<ProductDetail>;
@@ -15,6 +15,20 @@ export interface CatalogApi {
15
15
  /** The whole gallery in its order, with every picture's words (§11.2). */
16
16
  saveImages(id: number, images: Pick<ProductImage, 'id' | 'alt' | 'title'>[]): Promise<ProductImage[]>;
17
17
  removeImage(id: number, image: number): Promise<void>;
18
+ /**
19
+ * An address the server fetches: a picture or a YouTube video comes back as the new row, a
20
+ * direct link to a video file as `QueuedVideo` — the row appears once the queue has it.
21
+ */
22
+ fetchImage(id: number, url: string): Promise<ProductImage | QueuedVideo>;
23
+ /** A finished chunked upload (`upload` is its id) or an address, onto a picture of the gallery. */
24
+ attachVideo(id: number, image: number, source: {
25
+ upload: string;
26
+ duration?: number | null;
27
+ } | {
28
+ url: string;
29
+ }): Promise<ProductImage | QueuedVideo>;
30
+ /** The file, if it is one, is deleted at once. */
31
+ detachVideo(id: number, image: number): Promise<ProductImage>;
18
32
  categories(): Promise<CategoryNode[]>;
19
33
  category(id: number): Promise<CategoryDetail>;
20
34
  createCategory(values: ScreenModel, parent: number | null): Promise<CategoryDetail>;
@@ -0,0 +1,32 @@
1
+ import { AdminModule, CategoriesOptions, Messages } from '@webx-ui/module-admin';
2
+ /**
3
+ * A reference book of the catalogue — labels, stock statuses, brands — as the satellite that owns
4
+ * it describes it (§4 of the dictionaries spec). Everything else is the same for each.
5
+ */
6
+ export interface DictionaryOptions {
7
+ /** The module the server registers: `catalog-labels`. */
8
+ id: string;
9
+ /** Its path under the catalogue's, and under the catalogue's API: `labels`. */
10
+ slug: string;
11
+ /** The described screen of one record: `catalog.label-form`. */
12
+ screen: string;
13
+ /** The facet of the products list that picks a record's products: `label`. */
14
+ facet: string;
15
+ /** The satellite's dictionary: `webx-catalog-labels`. */
16
+ namespace: string;
17
+ /** The group of it the list's words are in: `label`. */
18
+ group: string;
19
+ /** Its English, under the server's until the server's arrives. */
20
+ messages: Record<string, Messages>;
21
+ /** Where the catalogue lives in the panel — `catalog({ path })`'s. */
22
+ catalog?: string;
23
+ }
24
+ /**
25
+ * The panel's shared category screens for one reference book: the list with its order dragged
26
+ * and the number of products on each row, and the page of one record, which is the satellite's
27
+ * described screen. Rights are the catalogue's (decision 8), and "Show its products" is the list
28
+ * of products narrowed by the satellite's own facet.
29
+ */
30
+ export declare function dictionaryOptions(options: DictionaryOptions): CategoriesOptions;
31
+ /** A reference book as a section of the panel: one entry, two routes. */
32
+ export declare function dictionarySection(options: DictionaryOptions): AdminModule;
package/dist/editor.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { InjectionKey, Ref } from 'vue';
2
+ import { GalleryVideo } from './galleryVideo';
2
3
  import { CategoryRow, ProductImage, ProductRow } from './types';
3
4
  /**
4
5
  * What the product editor knows and the nodes of `catalog.product-form` do not.
@@ -14,6 +15,12 @@ export interface ProductEditorContext {
14
15
  images: Ref<ProductImage[]>;
15
16
  /** Closed for writing: no permission, or a save in flight. */
16
17
  locked: Ref<boolean>;
18
+ /**
19
+ * Video files on their way into the gallery. Kept up here rather than in the gallery field, whose
20
+ * tab is taken down when another is opened — and an upload with it. The field makes its own
21
+ * when an editor leaves it out.
22
+ */
23
+ video?: GalleryVideo;
17
24
  }
18
25
  export declare const productEditorKey: InjectionKey<ProductEditorContext>;
19
26
  export declare function provideProductEditor(editor: ProductEditorContext): void;
@@ -0,0 +1,67 @@
1
+ import { ComputedRef, Ref } from 'vue';
2
+ import { AdminContext, ChunkedUpload, UnfinishedUpload } from '@webx-ui/module-admin';
3
+ import { ProductImage } from './types';
4
+ import { ProbeOptions } from './video';
5
+ /**
6
+ * Video files going into the gallery (§7 of the video spec): the frame, the picture, the file a
7
+ * piece at a time, and the request that puts the two together.
8
+ *
9
+ * Kept by the product editor rather than by the gallery field. The field lives on a tab, and a tab
10
+ * nobody is looking at is taken down — with the chunked upload inside it, which pauses when its
11
+ * scope dies. Up here the upload carries on while the rest of the form is being filled in.
12
+ *
13
+ * One file at a time, as there is one chunked upload: several at once share one connection
14
+ * anyway, and one bar that moves says more than three that crawl.
15
+ */
16
+ export declare const VIDEO_PURPOSE = "catalog.video";
17
+ export type VideoJobStage = 'waiting' | 'poster' | 'uploading' | 'attaching' | 'failed';
18
+ export interface VideoJob {
19
+ key: number;
20
+ file: File;
21
+ /** The product it goes to, as it was when the file was chosen. */
22
+ product: number;
23
+ /** The picture it goes onto; `null` until the frame has been uploaded as one. */
24
+ image: number | null;
25
+ /** The job made that picture itself — a cancel takes it away again. */
26
+ created: boolean;
27
+ /** The frame, until the picture is on the server and the row shows its own. */
28
+ poster: string | null;
29
+ duration: number | null;
30
+ stage: VideoJobStage;
31
+ /** Why it stopped, in words; only in `failed`. */
32
+ error: string | null;
33
+ /** The browser could not open the file, so there is no frame to make a picture of. */
34
+ unreadable: boolean;
35
+ }
36
+ /** An upload this browser left unfinished for this product, with the picture it was for. */
37
+ export interface UnfinishedVideo extends UnfinishedUpload {
38
+ image: number | null;
39
+ }
40
+ export interface GalleryVideo {
41
+ readonly jobs: Readonly<Ref<readonly VideoJob[]>>;
42
+ /** The one upload that moves — its state, progress, speed and time left. */
43
+ readonly upload: ChunkedUpload;
44
+ /** Something is on its way to the server; leaving now loses the rest of it. */
45
+ readonly busy: ComputedRef<boolean>;
46
+ /** What a reload interrupted on this product, to be continued by choosing the file again. */
47
+ readonly unfinished: ComputedRef<UnfinishedVideo[]>;
48
+ /** Onto `image`, or a new row made of its own frame when there is none. */
49
+ add(file: File, image?: number | null): void;
50
+ pause(): void;
51
+ resume(): void;
52
+ /** Try a failed one again: a file the server has part of continues from there. */
53
+ retry(job: VideoJob): void;
54
+ cancel(job: VideoJob): Promise<void>;
55
+ /** Take a failed one off the list. */
56
+ dismiss(job: VideoJob): void;
57
+ /** Stop offering to continue an upload. */
58
+ forget(entry: UnfinishedVideo): void;
59
+ }
60
+ export interface GalleryVideoOptions {
61
+ product: Ref<number | null>;
62
+ images: Ref<ProductImage[]>;
63
+ admin?: AdminContext;
64
+ storage?: Storage | null;
65
+ probe?: ProbeOptions;
66
+ }
67
+ export declare function createGalleryVideo(options: GalleryVideoOptions): GalleryVideo;
package/dist/index.d.ts CHANGED
@@ -1,7 +1,11 @@
1
1
  export { catalog, type CatalogOptions } from './module';
2
2
  export { createCatalogApi, productSearch, CATALOG_API, type CatalogApi } from './api';
3
3
  export { catalogMessages } from './messages';
4
+ export { dictionaryOptions, dictionarySection, type DictionaryOptions } from './dictionaries';
5
+ export { FACET_PREFIX } from './filters';
6
+ export { TONES, toneBadge, type Tone } from './tones';
4
7
  export { provideProductEditor, productEditorKey, useProductEditor, provideCatalogCategoryEditor, categoryEditorKey, useCatalogCategoryEditor, type ProductEditorContext, type CategoryEditorContext, } from './editor';
8
+ export { createGalleryVideo, VIDEO_PURPOSE, type GalleryVideo, type GalleryVideoOptions, type UnfinishedVideo, type VideoJob, type VideoJobStage, } from './galleryVideo';
5
9
  export { useCategoryTree, useFacetRegistry, type CategoryTree, type FacetRegistry } from './store';
6
10
  export { default as WxCatalogProductsPage } from './ProductsPage';
7
11
  export { default as WxCatalogProductEditor } from './ProductEditorPage';
@@ -13,4 +17,6 @@ export { default as WxCatalogDeletedPage } from './DeletedPage';
13
17
  export { default as WxCatalogCategoryField } from './CategoryField';
14
18
  export { default as WxCatalogFacetsField } from './FacetsField';
15
19
  export { default as WxCatalogGallery } from './GalleryField';
16
- export type { CategoryDetail, CategoryNode, CategoryRef, CategoryRow, DeletedCategory, DeletedKind, DeletedProduct, FacetChoice, FacetInfo, FacetKind, FacetSetting, ProductColumnInfo, ProductDetail, ProductImage, ProductQuery, ProductRow, ProductSort, ProductState, ProductsPage, SkuHolder, } from './types';
20
+ export { default as WxCatalogToneField } from './ToneField';
21
+ export { default as WxCatalogColumnValue } from './ColumnValue';
22
+ export type { CategoryDetail, CategoryNode, CategoryRef, CategoryRow, ColumnRecord, ColumnValue, DeletedCategory, DeletedKind, DeletedProduct, FacetChoice, FacetInfo, FacetKind, FacetSetting, ProductColumnInfo, ProductDetail, ProductImage, ProductQuery, ProductVideo, QueuedVideo, ProductRow, ProductSort, ProductState, ProductsPage, SkuHolder, } from './types';