From 034356366c323cf4b46db0a07f73db13ee615f7c Mon Sep 17 00:00:00 2001 From: Martin Rizzo Date: Fri, 19 Jun 2026 14:40:25 -0300 Subject: [PATCH] feat: Allow custom endpoint configuration for Palette and Style selectors The commit introduces the ability to manually configure the data endpoints for both `PaletteSelector` and `StyleSelector` widgets. Previously, the full endpoint URL was automatically calculated based on a specified version; now, a complete custom URL can be provided. While the automated versioning system remains the default behavior, this change provides significantly greater configurability by allowing these widgets to load data from any source. --- js/custom_widgets/style_gallery_button.js | 5 +- js/custom_widgets/ui_palettes.js | 95 ++++++++--------- js/custom_widgets/ui_styles.js | 100 +++++++++--------- js/style_category_selector.js | 3 +- nodes/custom_widgets.py | 121 +++++++++++++++------- 5 files changed, 180 insertions(+), 144 deletions(-) diff --git a/js/custom_widgets/style_gallery_button.js b/js/custom_widgets/style_gallery_button.js index 0502389..d0c9f65 100644 --- a/js/custom_widgets/style_gallery_button.js +++ b/js/custom_widgets/style_gallery_button.js @@ -53,7 +53,6 @@ function addStyleGalleryButton(node, name, data) { label : `🖼️ ${buttonTitle} ...`, serialize: true, options : { - version : "1.0.0", dialog_title: dialogTitle, prev_index : prevIndex, ...options @@ -74,10 +73,10 @@ function addStyleGalleryButton(node, name, data) { // } const options = button.options; const prevWidget = button.node.widgets[options.prev_index]; - const version = options.version || "1.0"; + const endpoint = options.endpoint || ""; const dialog_options = options.dialog || {}; - const styleDialog = requireVisualStyleGalleryDialog(version); + const styleDialog = requireVisualStyleGalleryDialog(endpoint); const currentStyle = prevWidget.value?.replace(/^"|"$/g, ''); styleDialog.launch( dialog_options, currentStyle, (selectedStyle) => { diff --git a/js/custom_widgets/ui_palettes.js b/js/custom_widgets/ui_palettes.js index df68265..f8bee88 100644 --- a/js/custom_widgets/ui_palettes.js +++ b/js/custom_widgets/ui_palettes.js @@ -21,17 +21,17 @@ import { api } from "../../../scripts/api.js"; import { GalleryDialog, GalleryDialogDelegate } from "./gallery_dialog.js"; import { GalleryWidget, GalleryWidgetDelegate } from "./gallery_widget.js"; -// Cache of promises to avoid duplicate requests for the same color palette version. -const _fetchPalettesCache = new Map(); +// Cache of promises to avoid duplicate requests for the same endpoint. +const _fetchesByEndpoint = new Map(); -// Registry of dialogs for each color palette version. -const _dialogRegistry = new Map(); +// Registry of dialogs for each color-palete database endpoint. +const _dialogsByEndpoint = new Map(); //#==========================================================================# //# FETCH COLOR PALETTES # -//# FIRST generation of UI fetched the items directly using this function # -//# and loaded them into a native ComfyUI combo-box. Currently, the function # +//# The FIRST generation of UI fetched items directly using this function # +//# and loaded them into a native ComfyUI combobox. Currently, this function # //# is internally invoked from GALLERY DIALOG and the GALLERY WIDGET. # /** @@ -40,9 +40,9 @@ const _dialogRegistry = new Map(); * Note: The implementation looks a bit complex because of the caching system. * It uses an immediately-invoked function (IIFE) to cache the ongoing promise * right away, ensuring we don't trigger duplicate network requests for the - * same version. + * same endpoint URL. * - * @param {string} version - The version of the color palettes to fetch. + * @param {string} endpoint - The full endpoint URL to fetch the palettes from. * @returns {Promise>} * Resolves to the array of formatted color palettes. * Each element in the array is an object with the following properties: @@ -53,37 +53,32 @@ const _dialogRegistry = new Map(); * - colors : Array of color objects, each containing a name and a hex code (Array<{name: string, hex: string}>) * @example * // Using async/await - * const palettes = await fetchColorPaletteArray('1.0.0'); + * const palettes = await fetchColorPaletteArray('/zi_power/palettes/by_version?v=1.0'); * console.log(`Loaded ${palettes.length} palettes.`); * @example * // Using promises (.then) - * fetchColorPaletteArray('1.0.0').then(palettes => { + * fetchColorPaletteArray('/zi_power/styles/by_version?v=1.0').then(palettes => { * console.log(`Loaded ${palettes.length} palettes.`); * }); */ -async function fetchColorPaletteArray(version) +async function fetchColorPaletteArray(endpoint) { - if( typeof version !== 'string' || !version.trim() ) { - console.error(`Invalid version parameter: "${version}". Expected a non-empty string.`); + if( typeof endpoint !== 'string' || !endpoint.trim() ) { + console.error(`Invalid endpoint parameter: "${endpoint}". Expected a non-empty string.`); return []; } - // normalize version string to "x.y.z" format - const parts = version.split('.'); - while( parts.length < 3 ) { parts.push('0'); } - version = parts.join('.'); - - // if the version already exists in cache, - // either the ongoing promise or resolved result + // if the endpoint already exists in the "fetch cache" + // (either the ongoing promise or resolved result), // RETURN IT! - if( _fetchPalettesCache.has(version) ) { - return _fetchPalettesCache.get(version); + if( _fetchesByEndpoint.has(endpoint) ) { + return _fetchesByEndpoint.get(endpoint); } // encapsulate the fetch process in a promise const fetchPromise = (async () => { try { - // fetch the palettes for the given version - const response = await api.fetchApi(`/zi_power/palettes/by_version?v=${encodeURIComponent(version)}`); + // fetch the palettes for the given endpoint + const response = await api.fetchApi(endpoint); if( !response.ok ) { throw new Error(`HTTP ${response.status}`); } // validate that the response is an actual array @@ -111,30 +106,30 @@ async function fetchColorPaletteArray(version) }); } catch (error) { - // if failed, delete the cache for this version to allow future retries - console.error(`Failed to fetch palettes for version ${version}: ${error.message}`); - _fetchPalettesCache.delete(version); + // if failed, delete the cache for this endpoint to allow future retries + console.error(`Failed to fetch palettes from "${endpoint}": ${error.message}`); + _fetchesByEndpoint.delete(endpoint); return []; } })(); // store the promise in cache for future use - _fetchPalettesCache.set(version, fetchPromise); + _fetchesByEndpoint.set(endpoint, fetchPromise); return fetchPromise; } //#=========================================================================# //# PALETTE GALLERY DIALOG # -//# SECOND generation of UI added a button within the node that launched a # +//# The SECOND generation of UI added a node button that launched a # //# GALLERY DIALOG, which in turn modified a native combo-box in ComfyUI. # //# # class PaletteGalleryDialogDelegate extends GalleryDialogDelegate { - constructor(version) { + constructor(endpoint) { super(); - this._version = version; //< the version of the palettes to fetch + this.endpoint = endpoint; } /** @@ -149,7 +144,7 @@ class PaletteGalleryDialogDelegate extends GalleryDialogDelegate { * - thumbnail : URL for the item's thumbnail image (string) */ async fetchItemArray() { - return fetchColorPaletteArray(this._version); + return fetchColorPaletteArray(this.endpoint); } /** @@ -184,42 +179,42 @@ class PaletteGalleryDialogDelegate extends GalleryDialogDelegate { } /** - * Returns a palette selection dialog containing the specified palette database version - * @param {string} version - Version of the palette database to show (e.g., "1.0") + * Returns a palette selection dialog containing the palettes loaded from the specified endpoint. + * @param {string} endpoint - The full endpoint URL to fetch the palettes from. * @returns {GalleryDialog} - * The gallery dialog instance for the specified version + * The gallery dialog instance for the specified endpoint * @example - * const paletteDialog = requireColorPaletteGalleryDialog("1.2"); + * const paletteDialog = requireColorPaletteGalleryDialog("/api/palettes/v1/list"); * const currentPalette = "Volcano"; * paletteDialog.launch({}, currentPalette, (selectedPalette) => { * console.log("Selected Palette: " + selectedPalette); * }); */ -function requireColorPaletteGalleryDialog(version) { +function requireColorPaletteGalleryDialog(endpoint) { - // check if a dialog is already registered for the specified version - const dialog = _dialogRegistry.get(version); + // check if a dialog is already registered for the specified endpoint + const dialog = _dialogsByEndpoint.get(endpoint); if( dialog ) { return dialog; } - // if no dialog exists for this version, create a new one - const newDelegate = new PaletteGalleryDialogDelegate(version); + // if no dialog exists for this endpoint, create a new one + const newDelegate = new PaletteGalleryDialogDelegate(endpoint); const newDialog = new GalleryDialog(newDelegate); - _dialogRegistry.set(version, newDialog); + _dialogsByEndpoint.set(endpoint, newDialog); return newDialog; } //#=========================================================================# //# PALETTE GALLERY WIDGET # -//# THIRD generation of UI uses GALLERY WIDGET to launch the GALLERY DIALOG,# -//# these gallery widgets are customized by 'delegate' objects. # +//# The THIRD generation of UI uses a "GALLERY WIDGET" to launch a # +//# "GALLERY DIALOG", both of them customized by 'delegate' objects. # //# # class PaletteWidgetDelegate extends GalleryWidgetDelegate { - constructor(version) { + constructor(endpoint) { super(); - this.version = version; //< the version of the palettes to fetch + this.endpoint = endpoint; } /** @@ -234,7 +229,7 @@ class PaletteWidgetDelegate extends GalleryWidgetDelegate { * - thumbnail : URL for the item's thumbnail image (string) */ async fetchItemArray() { - return fetchColorPaletteArray(this.version); + return fetchColorPaletteArray(this.endpoint); } getItemText(item) { @@ -276,12 +271,12 @@ class PaletteWidgetDelegate extends GalleryWidgetDelegate { function addColorPaletteGalleryWidget(node, name, data) { const type = data[0]; const options = data[1] || {}; - const version = options.version || '1.0'; + const endpoint = options.endpoint || ""; const dialog_options = options.dialog || {}; - let widget = new GalleryWidget(type, node, name, options, new PaletteWidgetDelegate(version), (widget) => + let widget = new GalleryWidget(type, node, name, options, new PaletteWidgetDelegate(endpoint), (widget) => { // launch dialog and update widget value - const paletteDialog = requireColorPaletteGalleryDialog(version); + const paletteDialog = requireColorPaletteGalleryDialog(endpoint); const currentPalette = widget.value; paletteDialog.launch( dialog_options, currentPalette, (selectedPalette) => { widget.forceUpdate( selectedPalette ); diff --git a/js/custom_widgets/ui_styles.js b/js/custom_widgets/ui_styles.js index 20198f6..469f9fb 100644 --- a/js/custom_widgets/ui_styles.js +++ b/js/custom_widgets/ui_styles.js @@ -21,17 +21,17 @@ import { api } from "../../../scripts/api.js"; import { GalleryDialog, GalleryDialogDelegate } from "./gallery_dialog.js"; import { GalleryWidget, GalleryWidgetDelegate } from "./gallery_widget.js"; -// Cache of promises to avoid duplicate requests for the same visual style version. -const _fetchStylesCache = new Map(); +// Cache of promises to avoid duplicate requests for the same endpoint. +const _fetchesByEndpoint = new Map(); -// Registry of dialogs for each visual style version. -const _dialogsByVersion = new Map(); +// Registry of dialogs for each visual-style database endpoint. +const _dialogsByEndpoint = new Map(); //#==========================================================================# //# FETCH VISUAL STYLES # -//# FIRST generation of UI fetched the items directly using this function # -//# and loaded them into a native ComfyUI combo-box. Currently, the function # +//# The FIRST generation of UI fetched items directly using this function # +//# and loaded them into a native ComfyUI combobox. Currently, this function # //# is internally invoked from GALLERY DIALOG and the GALLERY WIDGET. # /** @@ -40,9 +40,9 @@ const _dialogsByVersion = new Map(); * Note: The implementation looks a bit complex because of the caching system. * It uses an immediately-invoked function (IIFE) to cache the ongoing promise * right away, ensuring we don't trigger duplicate network requests for the - * same version. + * same endpoint URL. * - * @param {string} version - The version of the styles to fetch. + * @param {string} endpoint - The full endpoint URL to fetch the styles from. * @returns {Promise>} * Resolves to the array of formatted styles. * Each element in the array is an object with the following properties: @@ -55,39 +55,33 @@ const _dialogsByVersion = new Map(); * * @example * // Using async/await - * const styles = await fetchVisualStyleArray('1.0.0'); + * const styles = await fetchVisualStyleArray('/zi_power/styles/by_version?v=1.0'); * console.log(`Loaded ${styles.length} styles.`); - * * @example * // Using promises (.then) - * fetchVisualStyleArray('1.0.0').then(styles => { + * fetchVisualStyleArray('/zi_power/styles/by_version?v=1.0').then(styles => { * console.log(`Loaded ${styles.length} styles.`); * }); */ -async function fetchVisualStyleArray(version) +async function fetchVisualStyleArray(endpoint) { - if (typeof version !== 'string' || !version.trim()) { - console.error(`Invalid version parameter: "${version}". Expected a non-empty string.`); + if( typeof endpoint !== 'string' || !endpoint.trim() ) { + console.error(`Invalid endpoint parameter: "${endpoint}". Expected a non-empty string.`); return []; } - // normalize version string to "x.y.z" format - const parts = version.split('.'); - while( parts.length < 3 ) { parts.push('0'); } - version = parts.join('.'); - - // if the version already exists in cache, - // either the ongoing promise or resolved result + // if the endpoint already exists in the "fetch cache" + // (either the ongoing promise or resolved result), // RETURN IT! - if( _fetchStylesCache.has(version) ) { - return _fetchStylesCache.get(version); + if( _fetchesByEndpoint.has(endpoint) ) { + return _fetchesByEndpoint.get(endpoint); } // encapsulate the fetch process in a promise const fetchPromise = (async () => { try { - // fetch the styles for the given version - const response = await api.fetchApi(`/zi_power/styles/by_version?v=${encodeURIComponent(version)}`); + // fetch the styles from the given endpoint + const response = await api.fetchApi(endpoint); if( !response.ok ) { throw new Error(`HTTP ${response.status}`); } // validate that the response is an actual array @@ -103,35 +97,35 @@ async function fetchVisualStyleArray(version) category : style[1] || "Uncategorized", description: style[2] || "", tags : style[3] || "", - thumbnail : thumbFileName ? `${THUMBNAIL_BASE_URL}?file=${thumbFileName}` : "" + thumbnail : thumbFileName ? `${THUMBNAIL_BASE_URL}?file=${thumbFileName}` : "" }; }); } catch (error) { - // if failed, delete the cache for this version to allow future retries - console.error(`Failed to fetch styles for version ${version}: ${error.message}`); - _fetchStylesCache.delete(version); + // if failed, delete the cache for this endpoint to allow future retries + console.error(`Failed to fetch styles from "${endpoint}": ${error.message}`); + _fetchesByEndpoint.delete(endpoint); return []; } })(); // store the promise in cache for future use - _fetchStylesCache.set(version, fetchPromise); + _fetchesByEndpoint.set(endpoint, fetchPromise); return fetchPromise; } //#=========================================================================# //# STYLE GALLERY DIALOG # -//# SECOND generation of UI added a button within the node that launched a # +//# The SECOND generation of UI added a node button that launched a # //# GALLERY DIALOG, which in turn modified a native combo-box in ComfyUI. # //# # class StyleDialogDelegate extends GalleryDialogDelegate { - constructor(version) { + constructor(endpoint) { super(); - this._version = version; //< the version of the styles to fetch + this.endpoint = endpoint; } /** @@ -146,7 +140,7 @@ class StyleDialogDelegate extends GalleryDialogDelegate { * - thumbnail : URL for the item's thumbnail image (string) */ async fetchItemArray() { - return fetchVisualStyleArray(this._version); + return fetchVisualStyleArray(this.endpoint); } /** @@ -170,46 +164,46 @@ class StyleDialogDelegate extends GalleryDialogDelegate { } /** - * Returns a style selection dialog containing the specified style database version. - * @param {string} version - Version of the style database to show (e.g., "1.0") + * Returns a style selection dialog containing the styles loaded from the specified endpoint. + * @param {string} endpoint - The full endpoint URL to fetch the styles from. * @returns {GalleryDialog} - * The gallery dialog instance for the specified version + * The gallery dialog instance for the specified endpoint * @example - * const styleDialog = requireVisualStyleGalleryDialog("1.2"); + * const styleDialog = requireVisualStyleGalleryDialog("/api/styles/v1/list"); * const currentStyle = "Anime"; * styleDialog.launch( {}, currentStyle, (selectedStyle) => { * console.log("Selected Style: " + selectedStyle); * }); */ -function requireVisualStyleGalleryDialog(version) { +function requireVisualStyleGalleryDialog(endpoint) { - // check if a dialog is already registered for the specified version - const dialog = _dialogsByVersion.get(version); + // check if a dialog is already registered for the specified endpoint + const dialog = _dialogsByEndpoint.get(endpoint); if( dialog ) { return dialog; } - // If no dialog exists for this version, create a new one - const newDelegate = new StyleDialogDelegate(version); + // If no dialog exists for this endpoint, create a new one + const newDelegate = new StyleDialogDelegate(endpoint); const newDialog = new GalleryDialog(newDelegate); - _dialogsByVersion.set(version, newDialog); + _dialogsByEndpoint.set(endpoint, newDialog); return newDialog; } //#=========================================================================# //# STYLE GALLERY WIDGET # -//# THIRD generation of UI uses GALLERY WIDGET to launch the GALLERY DIALOG,# -//# these gallery widgets are customized by 'delegate' objects. # +//# The THIRD generation of UI uses a "GALLERY WIDGET" to launch a # +//# "GALLERY DIALOG", both of them customized by 'delegate' objects. # //# # class StyleWidgetDelegate extends GalleryWidgetDelegate { - constructor(version) { + constructor(endpoint) { super(); - this.version = version; //< the version of the styles to fetch + this.endpoint = endpoint; } async fetchItemArray() { - return fetchVisualStyleArray(this.version); + return fetchVisualStyleArray(this.endpoint); } getItemText(item, value, options) { @@ -270,12 +264,14 @@ class StyleWidgetDelegate extends GalleryWidgetDelegate { function addVisualStyleGalleryWidget(node, name, data) { const type = data[0]; const options = data[1] || {}; - const version = options.version || '1.0'; + const endpoint = options.endpoint || ""; + const images_url = "/zi_power/styles/samples?file=${name}&cb=${cachebuster}"; + const thumbs_url = "/zi_power/styles/samples?file=${name}&cb=${cachebuster}"; const dialog_options = options.dialog || {}; - let widget = new GalleryWidget(type, node, name, options, new StyleWidgetDelegate(version), (widget) => + let widget = new GalleryWidget(type, node, name, options, new StyleWidgetDelegate(endpoint), (widget) => { // launch dialog and update widget value - const styleDialog = requireVisualStyleGalleryDialog(version); + const styleDialog = requireVisualStyleGalleryDialog(endpoint); const currentStyle = widget.value; styleDialog.launch( dialog_options, currentStyle, (selectedStyle) => { widget.forceUpdate( selectedStyle ); diff --git a/js/style_category_selector.js b/js/style_category_selector.js index bed25b2..7963146 100644 --- a/js/style_category_selector.js +++ b/js/style_category_selector.js @@ -41,8 +41,7 @@ function init(self, categoryWidget, styleWidget) { self.selectedByCategory = {}; // performs an asynchronous request to the server to get styles (version 0.9) - console.log("##>> fetching visual styles"); - fetchVisualStyleArray("0.9").then( styles => { + fetchVisualStyleArray("/zi_power/styles/by_version?v=0.9").then( styles => { let stylesByCategory = {}; for( let i=0 ; i str: + return f"/zi_power/styles/by_version?v={version}" + +def _get_palettes_endpoint(version: str) -> str: + return f"/zi_power/palettes/by_version?v={version}" + #========================= PALETTE SELECTOR WIDGET =========================# @@ -31,6 +37,7 @@ class PaletteSelector: def __init__(self, id : str, *, version : str | None = None, + endpoint : str | None = None, height : int | None = None, dialog_title : str | None = None, dialog_icon : str | None = None, @@ -43,22 +50,26 @@ class PaletteSelector:
A color palette selector widget. Args: - id (str): A unique identifier for the input component. - version (str): The version of the palette database to load (e.g., "1.0"). - height (int): The height of the widget in pixels. - dialog_title (str): The title of the dialog window displayed for palette selection. - dialog_icon (str): The icon to display as a prefix of the dialog title. - * For PrimeIcons : Use "pi.[icon name]" e.g., "pi.pi-image"; (see https://primevue.org/icons/#list) - * For Pictogrammers: Use "mdi.[icon name]" e.g., "mdi.mdi-image"; (see https://pictogrammers.com/library/mdi) - * An empty string removes the icon from the title - dialog_size (str): The size of the dialog window. Supported values: "small" or "default". - dialog_view_mode (str): The view mode for the dialog window. Supported values: "grid" or "list". - If provided, the user cannot change the view mode. - allow_variants (bool): If True, the widget treats "//" as a separator in palette names. - The left part is considered the primary name, and the right part - is considered its variation. - tooltip (str): A tooltip description for the widget. + id (str): A unique identifier for the input component. + version (str): The version of the palette database to load (e.g., "1.0"). + endpoint (str): The endpoint to use for loading the palette database. + (if specified then `version` will not be taken into account.) + height (int): The height of the widget in pixels. + dialog_title (str): The title of the dialog window displayed for palette selection. + dialog_icon (str): The icon to display as a prefix of the dialog title. + * For PrimeIcons : Use "pi.[icon name]" e.g., "pi.pi-image"; (see https://primevue.org/icons/#list) + * For Pictogrammers: Use "mdi.[icon name]" e.g., "mdi.mdi-image"; (see https://pictogrammers.com/library/mdi) + * An empty string removes the icon from the title + dialog_size (str): The size of the dialog window. Supported values: "small" or "default". + dialog_view_mode (str): The view mode for the dialog window. Supported values: "grid" or "list". + If provided, the user cannot change the view mode. + allow_variants (bool): If True, the widget treats "//" as a separator in palette names. + The left part is considered the primary name, and the right part + is considered its variation. + tooltip (str): A tooltip description for the widget. """ + if not version and not endpoint: + raise ValueError("Either version or endpoint must be specified.") if not dialog_title: dialog_title = "Select Palette" @@ -67,8 +78,13 @@ class PaletteSelector: } if version is not None: - extra_dict["version"] = version - extra_dict["dialog"]["version"] = version + default_endpoint = _get_palettes_endpoint(version) + extra_dict["endpoint"] = default_endpoint + extra_dict["dialog"]["endpoint"] = default_endpoint + + if endpoint is not None: + extra_dict["endpoint"] = endpoint + extra_dict["dialog"]["endpoint"] = endpoint if height is not None: extra_dict["height"] = height @@ -113,30 +129,35 @@ class StyleSelector: def __init__(self, id : str, *, version : str | None = None, + endpoint : str | None = None, height : int | None = None, dialog_title : str | None = None, dialog_icon : str | None = None, dialog_size : str | None = None, dialog_view_mode: str | None = None, - allow_variants: bool | None = None, + allow_variants : bool | None = None, tooltip : str | None = None, ): """
A visual style selector widget. Args: - id (str): A unique identifier for the input component. - version (str): The version of the style database to load (e.g., "1.0"). - height (int): The height of the widget in pixels. - dialog_title (str): The title of the dialog window displayed for style selection. - dialog_size (str): The size of the dialog window. Supported values: "small" or "default". - dialog_view_mode (str): The view mode for the dialog window. Supported values: "grid" or "list". - If provided, the user cannot change the view mode. - allow_variants (bool): If True, the widget treats "//" as a separator in style names. - The left part is considered the primary name, and the right part - is considered its variation. - tooltip (str): A tooltip description for the widget. + id (str): A unique identifier for the input component. + version (str): The version of the style database to load (e.g., "1.0"). + endpoint (str): The endpoint to use for loading the style database. + (if specified then `version` will not be taken into account.) + height (int): The height of the widget in pixels. + dialog_title (str): The title of the dialog window displayed for style selection. + dialog_size (str): The size of the dialog window. Supported values: "small" or "default". + dialog_view_mode (str): The view mode for the dialog window. Supported values: "grid" or "list". + (if provided, the user cannot change the view mode.) + allow_variants (bool): If True, the widget treats "//" as a separator in style names. + The left part is considered the primary name, and the right part + is considered its variation. + tooltip (str): A tooltip description for the widget. """ + if not version and not endpoint: + raise ValueError("Either version or endpoint must be specified.") if not dialog_title: dialog_title = "Select Style" @@ -145,8 +166,13 @@ class StyleSelector: } if version is not None: - extra_dict["version"] = version - extra_dict["dialog"]["version"] = version + default_endpoint = _get_styles_endpoint(version) + extra_dict["endpoint"] = default_endpoint + extra_dict["dialog"]["endpoint"] = default_endpoint + + if endpoint is not None: + extra_dict["endpoint"] = endpoint + extra_dict["dialog"]["endpoint"] = endpoint if height is not None: extra_dict["height"] = height @@ -247,11 +273,12 @@ class StyleGalleryButton: def __init__(self, id : str, version : str | None = None, + endpoint : str | None = None, dialog_title : str | None = None, dialog_icon : str | None = None, dialog_size : str | None = None, dialog_view_mode: str | None = None, - allow_variants: bool | None = None, + allow_variants : bool | None = None, tooltip : str | None = None, ): """ @@ -262,18 +289,38 @@ class StyleGalleryButton: Args: id (str): A unique identifier for the input component. - version (str, optional): The version of the visual styles to display in the - style gallery. This parameter can be used for backwards - compatibility with older versions of the styles. If not - provided, the latest version will be used. + version (str): The version of the style database to load (e.g., "1.0"). + endpoint (str): The endpoint to use for loading the style database. + (if specified then `version` will not be taken into account.) + dialog_title (str): The title of the dialog window displayed for style selection. + dialog_icon (str): The icon to display as a prefix of the dialog title. + * For PrimeIcons : Use "pi.[icon name]" e.g., "pi.pi-image"; (see https://primevue.org/icons/#list) + * For Pictogrammers: Use "mdi.[icon name]" e.g., "mdi.mdi-image"; (see https://pictogrammers.com/library/mdi) + * An empty string removes the icon from the title + dialog_size (str): The size of the dialog window. Supported values: "small" or "default". + dialog_view_mode (str): The view mode for the dialog window. Supported values: "grid" or "list". + (if provided, the user cannot change the view mode.) + allow_variants (bool): If True, the widget treats "//" as a separator in style names. + The left part is considered the primary name, and the right part + is considered its variation. + tooltip (str): A tooltip description for the widget. """ + if not version and not endpoint: + raise ValueError("Either version or endpoint must be specified.") + extra_dict: dict[str,Any] = { "title": "Select Style", "dialog": {}, } if version is not None: - extra_dict["version"] = version + version_endpoint = _get_styles_endpoint(version) + extra_dict["endpoint"] = version_endpoint + extra_dict["dialog"]["endpoint"] = version_endpoint + + if endpoint is not None: + extra_dict["endpoint"] = endpoint + extra_dict["dialog"]["endpoint"] = endpoint if dialog_title is not None: extra_dict["title"] = dialog_title