@useinsider/guido 3.0.0-beta.7a5aecd → 3.0.0-beta.7d3a300

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.
Files changed (50) hide show
  1. package/dist/components/organisms/onboarding/GenericOnboarding.vue.js +1 -1
  2. package/dist/components/organisms/onboarding/GenericOnboarding.vue2.js +1 -1
  3. package/dist/components/organisms/onboarding/TextBlockOnboarding.vue.js +1 -1
  4. package/dist/components/organisms/onboarding/TextBlockOnboarding.vue2.js +2 -2
  5. package/dist/config/compiler/unsubscribeCompilerRules.js +14 -14
  6. package/dist/config/compiler/utils/recommendationCompilerUtils.js +29 -18
  7. package/dist/config/i18n/en/tooltips.json.js +2 -1
  8. package/dist/extensions/Blocks/Recommendation/block.js +4 -1
  9. package/dist/extensions/Blocks/Recommendation/constants/blockIds.js +1 -1
  10. package/dist/extensions/Blocks/Recommendation/constants/controlIds.js +1 -1
  11. package/dist/extensions/Blocks/Recommendation/constants/selectors.js +15 -12
  12. package/dist/extensions/Blocks/Recommendation/controls/cardComposition/index.js +693 -144
  13. package/dist/extensions/Blocks/Recommendation/controls/customAttribute/index.js +78 -0
  14. package/dist/extensions/Blocks/Recommendation/controls/layout/index.js +27 -24
  15. package/dist/extensions/Blocks/Recommendation/controls/main/utils.js +96 -88
  16. package/dist/extensions/Blocks/Recommendation/controls/spacing/index.js +83 -81
  17. package/dist/extensions/Blocks/Recommendation/extension.js +18 -16
  18. package/dist/extensions/Blocks/Recommendation/recommendation.css.js +126 -2
  19. package/dist/extensions/Blocks/Recommendation/settingsPanel.js +124 -106
  20. package/dist/extensions/Blocks/Recommendation/store/recommendation.js +8 -7
  21. package/dist/extensions/Blocks/Recommendation/templates/grid/elementRenderer.js +63 -34
  22. package/dist/extensions/Blocks/Recommendation/templates/grid/template.js +30 -33
  23. package/dist/extensions/Blocks/Recommendation/templates/index.js +8 -8
  24. package/dist/extensions/Blocks/Recommendation/templates/list/elementRenderer.js +28 -13
  25. package/dist/extensions/Blocks/Recommendation/templates/list/template.js +25 -44
  26. package/dist/extensions/Blocks/Recommendation/templates/utils.js +62 -38
  27. package/dist/extensions/Blocks/Recommendation/utils/tagName.js +6 -6
  28. package/dist/extensions/Blocks/Unsubscribe/settingsPanel.js +16 -17
  29. package/dist/guido.css +1 -1
  30. package/dist/node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js +324 -218
  31. package/dist/package.json.js +1 -1
  32. package/dist/src/extensions/Blocks/Recommendation/block.d.ts +1 -0
  33. package/dist/src/extensions/Blocks/Recommendation/constants/blockIds.d.ts +2 -1
  34. package/dist/src/extensions/Blocks/Recommendation/constants/controlIds.d.ts +8 -1
  35. package/dist/src/extensions/Blocks/Recommendation/constants/index.d.ts +1 -1
  36. package/dist/src/extensions/Blocks/Recommendation/constants/selectors.d.ts +10 -0
  37. package/dist/src/extensions/Blocks/Recommendation/controls/cardComposition/index.d.ts +134 -44
  38. package/dist/src/extensions/Blocks/Recommendation/controls/customAttribute/index.d.ts +105 -0
  39. package/dist/src/extensions/Blocks/Recommendation/controls/index.d.ts +1 -0
  40. package/dist/src/extensions/Blocks/Recommendation/controls/main/utils.d.ts +2 -0
  41. package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +1 -0
  42. package/dist/src/extensions/Blocks/Recommendation/templates/grid/elementRenderer.d.ts +1 -1
  43. package/dist/src/extensions/Blocks/Recommendation/templates/list/elementRenderer.d.ts +1 -1
  44. package/dist/src/extensions/Blocks/Recommendation/templates/list/template.d.ts +10 -4
  45. package/dist/src/extensions/Blocks/Recommendation/templates/utils.d.ts +37 -2
  46. package/dist/src/extensions/Blocks/Recommendation/utils/tagName.d.ts +3 -3
  47. package/dist/static/styles/components/button.css.js +13 -7
  48. package/dist/static/styles/components/narrow-panel.css.js +52 -0
  49. package/dist/static/styles/variables.css.js +3 -0
  50. package/package.json +3 -3
@@ -1,4 +1,4 @@
1
- const o = { stripo: { version: "2.54.0" } }, s = {
1
+ const o = { stripo: { version: "2.59.0" } }, s = {
2
2
  guido: o
3
3
  };
4
4
  export {
@@ -22,6 +22,7 @@ export declare class RecommendationBlock extends Block {
22
22
  getName(): string;
23
23
  getDescription(): string;
24
24
  getSettingsPanelTitleHtml(): string;
25
+ allowInnerBlocksDND(): boolean;
25
26
  /**
26
27
  * Returns the template HTML for a new recommendation block.
27
28
  * Generates a unique recommendation ID and embeds the instance class
@@ -9,5 +9,6 @@ export declare enum RecommendationBlockId {
9
9
  OLD_PRICE = "recommendation-block-old-price",
10
10
  OMNIBUS_PRICE = "recommendation-block-omnibus-price",
11
11
  OMNIBUS_DISCOUNT = "recommendation-block-omnibus-discount",
12
- IMAGE = "recommendation-block-image"
12
+ IMAGE = "recommendation-block-image",
13
+ CUSTOM_ATTRIBUTE = "recommendation-block-custom-attribute"
13
14
  }
@@ -55,5 +55,12 @@ export declare enum RecommendationControlId {
55
55
  OMNIBUS_DISCOUNT_TEXT_BEFORE = "recommendation-block-omnibus-discount-text-before-control",
56
56
  OMNIBUS_DISCOUNT_TEXT_AFTER = "recommendation-block-omnibus-discount-text-after-control",
57
57
  IMAGE_SIZE = "recommendation-block-image-size-control",
58
- IMAGE_MARGINS = "recommendation-block-image-margins-control"
58
+ IMAGE_MARGINS = "recommendation-block-image-margins-control",
59
+ CUSTOM_ATTR_ALIGN = "recommendation-block-custom-attr-align-control",
60
+ CUSTOM_ATTR_BACKGROUND = "recommendation-block-custom-attr-background-control",
61
+ CUSTOM_ATTR_COLOR = "recommendation-block-custom-attr-color-control",
62
+ CUSTOM_ATTR_FONT_FAMILY = "recommendation-block-custom-attr-font-family-control",
63
+ CUSTOM_ATTR_PADDINGS = "recommendation-block-custom-attr-paddings-control",
64
+ CUSTOM_ATTR_SIZE = "recommendation-block-custom-attr-size-control",
65
+ CUSTOM_ATTR_STYLE = "recommendation-block-custom-attr-style-control"
59
66
  }
@@ -8,6 +8,6 @@
8
8
  */
9
9
  export { RecommendationBlockId } from './blockIds';
10
10
  export { RecommendationControlId } from './controlIds';
11
- export { BLOCK_ROOT_SELECTOR, CONTAINER_SELECTOR, DESKTOP_CONTAINER_SELECTOR, MOBILE_CONTAINER_SELECTOR, MOBILE_ROW_SELECTOR, CURRENCY_ATTR, ATTR_PRODUCT_IMAGE, ATTR_PRODUCT_NAME, ATTR_PRODUCT_PRICE, ATTR_PRODUCT_OLD_PRICE, ATTR_PRODUCT_OMNIBUS_PRICE, ATTR_PRODUCT_OMNIBUS_DISCOUNT, ATTR_PRODUCT_BUTTON, } from './selectors';
11
+ export { BLOCK_ROOT_SELECTOR, CONTAINER_SELECTOR, DESKTOP_CONTAINER_SELECTOR, MOBILE_CONTAINER_SELECTOR, MOBILE_ROW_SELECTOR, CURRENCY_ATTR, ATTR_PRODUCT_IMAGE, ATTR_PRODUCT_NAME, ATTR_PRODUCT_PRICE, ATTR_PRODUCT_OLD_PRICE, ATTR_PRODUCT_OMNIBUS_PRICE, ATTR_PRODUCT_OMNIBUS_DISCOUNT, ATTR_PRODUCT_BUTTON, ATTR_CUSTOM_PREFIX, ATTR_DATA_CUSTOM_ATTRIBUTES, ATTR_PRODUCT_ATTR, } from './selectors';
12
12
  export { LAYOUT_VALUES, LAYOUT_OPTIONS, DEFAULT_PRODUCTS_PER_ROW, DEFAULT_CARDS_IN_ROW, DEFAULT_MOBILE_CARDS_IN_ROW, MAX_PRODUCT_COUNT, MIN_PRODUCT_COUNT, MAX_PRODUCTS_PER_ROW, MIN_PRODUCTS_PER_ROW, MAX_MOBILE_PRODUCTS_PER_ROW, MIN_MOBILE_PRODUCTS_PER_ROW, DEFAULT_COLUMN_SPACING, DEFAULT_ROW_SPACING, DEFAULT_MOBILE_COLUMN_SPACING, DEFAULT_MOBILE_ROW_SPACING, MIN_SPACING, MAX_SPACING, SPACING_STEP, } from './layout';
13
13
  export { DEFAULT_NODE_CONFIG, DEFAULT_CURRENCY, DEFAULT_COMPOSITION, DEFAULT_VISIBILITY, CURRENT_CONFIG_VERSION, EXCLUDED_ALGORITHM_IDS, } from './defaultConfig';
@@ -40,3 +40,13 @@ export declare const ATTR_PRODUCT_OLD_PRICE = "productOldPrice";
40
40
  export declare const ATTR_PRODUCT_OMNIBUS_PRICE = "productOmnibusPrice";
41
41
  export declare const ATTR_PRODUCT_OMNIBUS_DISCOUNT = "productOmnibusDiscount";
42
42
  export declare const ATTR_PRODUCT_BUTTON = "productButton";
43
+ /**
44
+ * Custom attribute constants
45
+ * Used for dynamically added product attributes in Card Composition
46
+ */
47
+ /** Prefix for custom attribute keys in composition arrays (e.g., "customAttr:rating_star") */
48
+ export declare const ATTR_CUSTOM_PREFIX = "customAttr:";
49
+ /** HTML data attribute storing JSON array of added custom attribute names */
50
+ export declare const ATTR_DATA_CUSTOM_ATTRIBUTES = "data-custom-attributes";
51
+ /** HTML attribute on <td> elements identifying the product attribute for compiler template variable generation */
52
+ export declare const ATTR_PRODUCT_ATTR = "product-attr";
@@ -4,92 +4,182 @@ export declare const COMPOSITION_CONTROL_BLOCK_ID = "ui-elements-recommendation-
4
4
  export interface CardCompositionItem {
5
5
  key: string;
6
6
  label: string;
7
- visible: boolean;
8
7
  }
9
8
  export declare class RecommendationCardCompositionControl extends CommonControl {
10
9
  private store;
11
- private unsubscribeOrientation;
10
+ private unsubscribeStore;
11
+ private eventController;
12
+ /**
13
+ * Guard flag: when true, onTemplateNodeUpdated skips _initializeComposition.
14
+ * Used during _onReorder to prevent multiple intermediate rebuilds.
15
+ */
16
+ private reorderInProgress;
12
17
  getId(): string;
13
18
  getTemplate(): string;
14
19
  onRender(): void;
15
20
  onTemplateNodeUpdated(node: ImmutableHtmlNode): void;
21
+ onDestroy(): void;
22
+ private _initializeComposition;
23
+ private _registerValueChangeListeners;
24
+ private _readCompositionFromNode;
25
+ private _readCustomAttributesFromNode;
26
+ private _readVisibilityFromRows;
27
+ private _getDefaultVisibilities;
28
+ private _extractVisibilityFromRows;
29
+ private _parseVisibilityValue;
30
+ private _mergeWithDefaults;
31
+ private _buildVisibilityValues;
16
32
  /**
17
- * Creates the HTML content for an orderable item with label and toggle
33
+ * Renders orderable items into the composition list.
34
+ * Returns `true` if a full DOM rebuild occurred, `false` if existing
35
+ * elements were reordered in-place (preserving UE-SELECT state).
18
36
  */
19
- private _createItemContent;
37
+ private _renderOrderableItems;
20
38
  /**
21
- * Registers event listeners for composition and visibility changes
39
+ * Attempts to reorder existing orderable-item elements to match the composition order.
40
+ * If the list already contains the same set of items (possibly in a different order),
41
+ * performs a lightweight DOM reorder instead of a full innerHTML rebuild.
42
+ * Returns true if reorder was performed, false if a full rebuild is needed.
22
43
  */
23
- private _registerValueChangeListeners;
44
+ private _tryReorderInPlace;
45
+ private _createBuiltInItemHtml;
46
+ private _createCustomItemHtml;
24
47
  /**
25
- * Initializes composition order and visibility state from the current node
48
+ * Builds select options from the store's filterList.
49
+ * Falls back to a single option for the currently selected attribute.
26
50
  */
27
- private _initializeComposition;
51
+ private _getSelectOptions;
28
52
  /**
29
- * Reads composition order from node's data-card-composition attribute
30
- * Falls back to default order if attribute is not present
53
+ * Initializes custom attribute selects: sets their options and current value.
54
+ * Selects are pre-allocated in getTemplate() and moved into items by
55
+ * _moveSelectsIntoItems — this method only updates their data.
31
56
  */
32
- private _readCompositionFromNode;
57
+ private _initializeCustomSelects;
33
58
  /**
34
- * Builds visibility values object from the visibility map
59
+ * Moves UE-SWITCHER elements from the hidden toggle store into orderable items.
60
+ * Stripo initializes toggles at template parse time; moving the DOM node preserves bindings.
35
61
  */
36
- private _buildVisibilityValues;
62
+ private _moveTogglesIntoItems;
37
63
  /**
38
- * Read visibility state from individual row elements' data-visibility attributes
39
- * This ensures toggles reflect the actual DOM state
64
+ * Moves pre-allocated UE-SELECT elements from the hidden custom-select-store
65
+ * into orderable item slots. Same pattern as _moveTogglesIntoItems.
40
66
  */
41
- private _readVisibilityFromRows;
67
+ private _moveSelectsIntoItems;
42
68
  /**
43
- * Returns default visibility values for all items
69
+ * Rescues UE-SWITCHER elements from orderable items back to the hidden toggle store.
70
+ * Must be called before re-rendering the list with innerHTML to prevent toggle destruction.
71
+ * Without this, onTemplateNodeUpdated → _renderOrderableItems → innerHTML would destroy
72
+ * previously-moved toggles, making them permanently lost.
44
73
  */
45
- private _getDefaultVisibilities;
74
+ private _rescueTogglesToStore;
46
75
  /**
47
- * Extracts visibility values from DOM nodes
76
+ * Rescues UE-SELECT elements from orderable items back to the hidden custom-select-store.
77
+ * Same rescue pattern as _rescueTogglesToStore — prevents innerHTML from destroying them.
48
78
  */
49
- private _extractVisibilityFromRows;
79
+ private _rescueSelectsToStore;
50
80
  /**
51
- * Parses visibility value from string to boolean
52
- * Accepts "1", "true" as true, everything else as false
81
+ * Moves pre-allocated UE-BUTTON delete elements from the hidden custom-delete-store
82
+ * into orderable item slots. Same pattern as _moveSelectsIntoItems.
53
83
  */
54
- private _parseVisibilityValue;
84
+ private _moveDeleteButtonsIntoItems;
55
85
  /**
56
- * Merges extracted visibilities with default values for missing keys
86
+ * Rescues UE-BUTTON delete elements from orderable items back to the hidden custom-delete-store.
87
+ * Same rescue pattern as _rescueSelectsToStore — prevents innerHTML from destroying them.
57
88
  */
58
- private _mergeWithDefaults;
89
+ private _rescueDeleteButtonsToStore;
59
90
  /**
60
- * Apply the reordered composition to the block's HTML structure
61
- * Updates the data-card-composition attribute and reorders product attributes
62
- * Note: Reordering is only applied for grid layout
91
+ * Moves pre-allocated reorder icon UE-BUTTON elements from the hidden reorder-icon-store
92
+ * into orderable item drag-handle slots. Same pattern as _moveDeleteButtonsIntoItems.
63
93
  */
64
- private _applyCompositionToBlock;
94
+ private _moveReorderIconsIntoItems;
65
95
  /**
66
- * Reorders attribute rows within each product card based on composition order
67
- * Targets the tbody inside each product-attribute-cell to preserve card structure
96
+ * Rescues reorder icon UE-BUTTON elements from orderable items back to the hidden reorder-icon-store.
97
+ * Same rescue pattern as _rescueDeleteButtonsToStore prevents innerHTML from destroying them.
68
98
  */
69
- private _reorderProductAttributes;
99
+ private _rescueReorderIconsToStore;
100
+ private _setupEventListeners;
101
+ private _setupDragAndDrop;
102
+ private _setupDeleteHandler;
103
+ private _onAddAttribute;
70
104
  /**
71
- * Builds HTML string with attributes ordered according to composition
105
+ * Removes a single custom attribute by its index in the customAttrs array.
106
+ * Index-based to correctly handle duplicate attributes.
72
107
  */
73
- private _buildCompositionHtml;
108
+ private _onDeleteCustomAttribute;
109
+ /**
110
+ * Handles changing a custom attribute's selection via its inline _GuSelect.
111
+ * Uses the customIndex to target only the specific instance, supporting duplicates.
112
+ */
113
+ private _onCustomAttributeChanged;
114
+ private _onReorder;
115
+ private _injectCustomAttributeHtml;
116
+ private _injectGridAttributeRow;
117
+ private _injectListAttributeRow;
118
+ /**
119
+ * Removes a custom attribute by rebuilding product card content without it.
120
+ * The composition parameter should already have the deleted key removed.
121
+ */
122
+ private _removeCustomAttributeHtml;
123
+ /**
124
+ * Atomically updates both composition and custom-attributes in a single apply()
125
+ * so that onTemplateNodeUpdated fires only once with fully consistent state.
126
+ * Two separate apply() calls would cause an intermediate onTemplateNodeUpdated
127
+ * where composition is updated but customAttributes still has the old order,
128
+ * producing a flicker on the custom attribute dropdowns.
129
+ */
130
+ private _updateBothAttributes;
131
+ /**
132
+ * Reorders attribute rows within each product card based on composition order.
133
+ * Only used for grid layout (list layout has fixed 3-column structure).
134
+ */
135
+ private _reorderProductAttributes;
74
136
  /**
75
- * Apply visibility changes to the block's HTML structure
76
- * Updates display style and data-visibility attribute for all matching elements
77
- * - <tr> elements: use display: none / table-row
78
- * - <td> elements: use display: none / table-cell
137
+ * Builds HTML string with attributes ordered according to composition.
138
+ * Queries existing rows from the container by data-attribute-type.
79
139
  */
140
+ private _buildCompositionHtml;
80
141
  private _applyVisibilityToBlock;
81
142
  /**
82
- * Gets the current layout orientation from store or DOM
143
+ * Finds the composition array index for the Nth custom attribute (0-based).
144
+ * Scans left-to-right, counting only entries with the custom prefix.
145
+ * The customIndex maps 1:1 with the customAttrs array order.
83
146
  */
147
+ private _findNthCustomKeyIndex;
84
148
  private _getCurrentLayout;
85
149
  /**
86
- * Updates orderable state based on layout orientation
87
- * Adds/removes disabled class to hide drag icons for list layout
150
+ * Extracts background color properties from existing card elements.
151
+ * Checks both `.product-card-segment` (where applyCardBackgroundColor sets bg for grid)
152
+ * and `.product-card-wrapper` (where CardBackgroundColorControl sets bg).
153
+ * Used when injecting new attribute cells to match the card's current background.
154
+ */
155
+ private _extractSegmentBgFromCard;
156
+ private _getControlContainer;
157
+ /**
158
+ * Adds/removes orderable-disabled class based on layout orientation.
159
+ * List layout hides drag handles via CSS and disables draggable attribute
160
+ * to prevent native browser drag-and-drop from working without the handle.
88
161
  */
89
162
  private _updateOrderableState;
90
163
  /**
91
- * Subscribe to store orientation changes
92
- * Updates orderable state when layout changes via the layout control
164
+ * Disables the "Add Attribute" button when the custom attribute limit is reached
165
+ * or when all available filters have already been added (no unused attributes left).
166
+ */
167
+ private _updateAddButtonState;
168
+ /**
169
+ * Subscribes to store changes for orientation and filterList updates.
170
+ * When filterList changes (e.g. after async fetch), re-renders dropdowns with new options.
171
+ */
172
+ private _subscribeToStoreChanges;
173
+ /**
174
+ * Looks up the display name for an attribute from the store's filterList.
175
+ * Falls back to Title Case conversion of the snake_case attribute name.
176
+ */
177
+ private _getDisplayNameForAttribute;
178
+ /**
179
+ * Resolves the display content for a custom attribute cell.
180
+ * Uses the real product value from the store when available, falls back to displayName.
93
181
  */
94
- private _subscribeToOrientationChanges;
182
+ private _resolveAttributeContent;
183
+ private _getGridCellHtml;
184
+ private _getListRowHtml;
95
185
  }
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Custom Attribute Element Controls
3
+ *
4
+ * Controls for styling custom product attribute elements in recommendation cards.
5
+ *
6
+ * Unlike built-in elements (Name, Price, etc.) where all instances share a single
7
+ * block ID and should be styled uniformly, custom attributes are conceptually
8
+ * different elements (e.g., "brand" vs "rating_star") that need independent styling.
9
+ *
10
+ * Each custom attribute element carries a unique `product-attr` HTML attribute
11
+ * (e.g., `product-attr="product_attribute.brand"`). The controls below use this
12
+ * attribute to scope style changes to only the same attribute type across all
13
+ * product cards — changing "brand" color won't affect "rating_star" color.
14
+ */
15
+ import { ImmutableHtmlNode } from '@stripoinc/ui-editor-extensions';
16
+ /**
17
+ * Grouped Custom Attribute Controls
18
+ * Use this object for cleaner imports in extension.ts
19
+ */
20
+ export declare const CustomAttributeControls: {
21
+ readonly align: {
22
+ new (): {
23
+ getId(): string;
24
+ getTargetNodes(root: ImmutableHtmlNode): ImmutableHtmlNode[];
25
+ getParentControlId(): string;
26
+ api: import("@stripoinc/ui-editor-extensions").ControlApi;
27
+ getLabels(): import("@stripoinc/ui-editor-extensions").ControlLabels | undefined;
28
+ getModificationDescription(): import("@stripoinc/ui-editor-extensions").ModificationDescription | undefined;
29
+ getAdditionalModifications(_root: ImmutableHtmlNode): import("@stripoinc/ui-editor-extensions").TemplateModifier<import("@stripoinc/ui-editor-extensions").HtmlNodeModifier, import("@stripoinc/ui-editor-extensions").CssNodeModifier> | undefined;
30
+ isVisible(_node: ImmutableHtmlNode): boolean;
31
+ };
32
+ };
33
+ readonly color: {
34
+ new (): {
35
+ getId(): string;
36
+ getTargetNodes(root: ImmutableHtmlNode): ImmutableHtmlNode[];
37
+ getParentControlId(): string;
38
+ api: import("@stripoinc/ui-editor-extensions").ControlApi;
39
+ getLabels(): import("@stripoinc/ui-editor-extensions").ControlLabels | undefined;
40
+ getModificationDescription(): import("@stripoinc/ui-editor-extensions").ModificationDescription | undefined;
41
+ getAdditionalModifications(_root: ImmutableHtmlNode): import("@stripoinc/ui-editor-extensions").TemplateModifier<import("@stripoinc/ui-editor-extensions").HtmlNodeModifier, import("@stripoinc/ui-editor-extensions").CssNodeModifier> | undefined;
42
+ isVisible(_node: ImmutableHtmlNode): boolean;
43
+ };
44
+ };
45
+ readonly size: {
46
+ new (): {
47
+ getId(): string;
48
+ getTargetNodes(root: ImmutableHtmlNode): ImmutableHtmlNode[];
49
+ getParentControlId(): string;
50
+ api: import("@stripoinc/ui-editor-extensions").ControlApi;
51
+ getLabels(): import("@stripoinc/ui-editor-extensions").ControlLabels | undefined;
52
+ getModificationDescription(): import("@stripoinc/ui-editor-extensions").ModificationDescription | undefined;
53
+ getAdditionalModifications(_root: ImmutableHtmlNode): import("@stripoinc/ui-editor-extensions").TemplateModifier<import("@stripoinc/ui-editor-extensions").HtmlNodeModifier, import("@stripoinc/ui-editor-extensions").CssNodeModifier> | undefined;
54
+ isVisible(_node: ImmutableHtmlNode): boolean;
55
+ };
56
+ };
57
+ readonly style: {
58
+ new (): {
59
+ getId(): string;
60
+ getTargetNodes(root: ImmutableHtmlNode): ImmutableHtmlNode[];
61
+ getParentControlId(): string;
62
+ api: import("@stripoinc/ui-editor-extensions").ControlApi;
63
+ getLabels(): import("@stripoinc/ui-editor-extensions").ControlLabels | undefined;
64
+ getModificationDescription(): import("@stripoinc/ui-editor-extensions").ModificationDescription | undefined;
65
+ getAdditionalModifications(_root: ImmutableHtmlNode): import("@stripoinc/ui-editor-extensions").TemplateModifier<import("@stripoinc/ui-editor-extensions").HtmlNodeModifier, import("@stripoinc/ui-editor-extensions").CssNodeModifier> | undefined;
66
+ isVisible(_node: ImmutableHtmlNode): boolean;
67
+ };
68
+ };
69
+ readonly fontFamily: {
70
+ new (): {
71
+ getId(): string;
72
+ getTargetNodes(root: ImmutableHtmlNode): ImmutableHtmlNode[];
73
+ getParentControlId(): string;
74
+ api: import("@stripoinc/ui-editor-extensions").ControlApi;
75
+ getLabels(): import("@stripoinc/ui-editor-extensions").ControlLabels | undefined;
76
+ getModificationDescription(): import("@stripoinc/ui-editor-extensions").ModificationDescription | undefined;
77
+ getAdditionalModifications(_root: ImmutableHtmlNode): import("@stripoinc/ui-editor-extensions").TemplateModifier<import("@stripoinc/ui-editor-extensions").HtmlNodeModifier, import("@stripoinc/ui-editor-extensions").CssNodeModifier> | undefined;
78
+ isVisible(_node: ImmutableHtmlNode): boolean;
79
+ };
80
+ };
81
+ readonly background: {
82
+ new (): {
83
+ getId(): string;
84
+ getTargetNodes(root: ImmutableHtmlNode): ImmutableHtmlNode[];
85
+ getParentControlId(): string;
86
+ api: import("@stripoinc/ui-editor-extensions").ControlApi;
87
+ getLabels(): import("@stripoinc/ui-editor-extensions").ControlLabels | undefined;
88
+ getModificationDescription(): import("@stripoinc/ui-editor-extensions").ModificationDescription | undefined;
89
+ getAdditionalModifications(_root: ImmutableHtmlNode): import("@stripoinc/ui-editor-extensions").TemplateModifier<import("@stripoinc/ui-editor-extensions").HtmlNodeModifier, import("@stripoinc/ui-editor-extensions").CssNodeModifier> | undefined;
90
+ isVisible(_node: ImmutableHtmlNode): boolean;
91
+ };
92
+ };
93
+ readonly paddings: {
94
+ new (): {
95
+ getId(): string;
96
+ getTargetNodes(root: ImmutableHtmlNode): ImmutableHtmlNode[];
97
+ getParentControlId(): string;
98
+ api: import("@stripoinc/ui-editor-extensions").ControlApi;
99
+ getLabels(): import("@stripoinc/ui-editor-extensions").ControlLabels | undefined;
100
+ getModificationDescription(): import("@stripoinc/ui-editor-extensions").ModificationDescription | undefined;
101
+ getAdditionalModifications(_root: ImmutableHtmlNode): import("@stripoinc/ui-editor-extensions").TemplateModifier<import("@stripoinc/ui-editor-extensions").HtmlNodeModifier, import("@stripoinc/ui-editor-extensions").CssNodeModifier> | undefined;
102
+ isVisible(_node: ImmutableHtmlNode): boolean;
103
+ };
104
+ };
105
+ };
@@ -18,6 +18,7 @@ export { OmnibusPriceControls } from './omnibusPrice';
18
18
  export { OmnibusDiscountControls } from './omnibusDiscount';
19
19
  export { ButtonControls } from './button';
20
20
  export { ImageControls } from './image';
21
+ export { CustomAttributeControls } from './customAttribute';
21
22
  export { SpacingControl, SPACING_CONTROL_ID } from './spacing';
22
23
  export { CardBackgroundColorControl, CARD_BACKGROUND_COLOR_CONTROL_ID } from './cardBackground';
23
24
  export { LayoutControl, LAYOUT_CONTROL_ID } from './layout';
@@ -56,6 +56,8 @@ export interface RegenerateProductRowsOptions {
56
56
  products?: RecommendationProduct[];
57
57
  /** Optional: pass layout directly to avoid stale DOM reads after setAttribute */
58
58
  layout?: Orientation;
59
+ /** Optional: pass composition directly to avoid stale DOM reads after setAttribute */
60
+ composition?: string[];
59
61
  }
60
62
  /**
61
63
  * Regenerates only the mobile product container rows.
@@ -22,6 +22,7 @@ interface PerBlockConfigs {
22
22
  textTrimming: boolean;
23
23
  unresponsive: boolean;
24
24
  size: string;
25
+ customAttributes: string[];
25
26
  }
26
27
  interface PerBlockState {
27
28
  recommendationConfigs: PerBlockConfigs;
@@ -1,4 +1,4 @@
1
- import type { ElementRenderer } from '../utils';
1
+ import { type ElementRenderer } from '../utils';
2
2
  /**
3
3
  * Grid element renderer
4
4
  * Each element returns a `<td>` containing a nested table structure:
@@ -1,4 +1,4 @@
1
- import type { ElementRenderer } from '../utils';
1
+ import { type ElementRenderer } from '../utils';
2
2
  /**
3
3
  * List element renderer
4
4
  * - Image and Button return `<td>` cells for the 3-column layout
@@ -1,18 +1,24 @@
1
1
  import type { RecommendationProduct } from '@@/Types/recommendation';
2
2
  /**
3
3
  * Generates a list product card with 3-column layout
4
- * Uses listElementRenderer to render Image, Info content, and Button
4
+ * Uses buildElementRenderer to render Image, Info content, and Button
5
5
  * Layout: [Image (120px)] [Info table (flexible)] [Button (100px)]
6
+ *
7
+ * The info cell rows are built dynamically from the composition array,
8
+ * supporting both built-in attributes and custom product attributes.
9
+ * Image and Button are always separate columns (not in the info cell).
6
10
  * @param product - The product data
11
+ * @param composition - Array defining order of card elements
7
12
  * @returns HTML string for a single product card row
8
13
  */
9
- export declare function getListProductCard(product: RecommendationProduct): string;
14
+ export declare function getListProductCard(product: RecommendationProduct, composition?: string[]): string;
10
15
  /**
11
16
  * Prepares list product rows
12
17
  * Each product is a full-width row with 3-column layout
13
18
  * @param products - Array of products to display
19
+ * @param composition - Array defining order of card elements
14
20
  * @returns HTML string for product rows
15
21
  */
16
- export declare function prepareProductRows(products: RecommendationProduct[]): string;
22
+ export declare function prepareProductRows(products: RecommendationProduct[], composition?: string[]): string;
17
23
  export declare function getDefaultTemplate(): string;
18
- export declare function generateBlockTemplate(products: RecommendationProduct[], title?: string): string;
24
+ export declare function generateBlockTemplate(products: RecommendationProduct[], title?: string, composition?: string[]): string;
@@ -1,5 +1,35 @@
1
1
  import type { RecommendationProduct } from '@@/Types/recommendation';
2
2
  import { ATTR_PRODUCT_IMAGE, ATTR_PRODUCT_NAME, ATTR_PRODUCT_PRICE, ATTR_PRODUCT_OLD_PRICE, ATTR_PRODUCT_OMNIBUS_PRICE, ATTR_PRODUCT_OMNIBUS_DISCOUNT, ATTR_PRODUCT_BUTTON } from '../constants';
3
+ /**
4
+ * Converts a snake_case attribute name to Title Case display name.
5
+ * e.g., "rating_star" → "Rating Star"
6
+ */
7
+ export declare function toDisplayName(attrName: string): string;
8
+ /**
9
+ * Callback that generates the cell HTML for a custom product attribute.
10
+ * Layout-specific: grid returns `<td>…`, list returns `<tr><td>…</td></tr>`.
11
+ */
12
+ export type CustomCellHtmlGetter = (attrName: string, content: string) => string;
13
+ /**
14
+ * Symbol key for embedding custom attribute HTML in an ElementRenderer.
15
+ * Grid and list renderers store their custom-attribute cell template under this key
16
+ * so that `buildElementRenderer` can read it without a separate callback parameter.
17
+ *
18
+ * Using a Symbol avoids conflicts with the string index signature — call sites that
19
+ * access `renderer[stringKey]` always get `(product) => string` without type narrowing.
20
+ */
21
+ export declare const CUSTOM_CELL_HTML: unique symbol;
22
+ /**
23
+ * Extends a base element renderer with custom attribute entries from the composition.
24
+ * Each `customAttr:<name>` key in the composition gets a renderer closure that calls
25
+ * the layout-specific custom cell HTML getter stored in `baseRenderer[CUSTOM_CELL_HTML]`.
26
+ *
27
+ * This ensures that custom attribute renderers live inside the ElementRenderer object
28
+ * alongside built-in ones, so template code can use a uniform lookup for all attributes.
29
+ * @param baseRenderer - The built-in element renderer (grid or list), must include a [CUSTOM_CELL_HTML] entry
30
+ * @param composition - Array of attribute keys including `customAttr:*` entries
31
+ */
32
+ export declare function buildElementRenderer(baseRenderer: ElementRenderer, composition: string[]): ElementRenderer;
3
33
  export type Orientation = 'list' | 'grid';
4
34
  /**
5
35
  * Options for prepareProductRows unified function
@@ -13,8 +43,11 @@ export interface PrepareProductRowsOptions {
13
43
  composition?: string[];
14
44
  }
15
45
  /**
16
- * Element renderer interface for product card elements
17
- * Keys are ATTR_PRODUCT_* constants for consistent naming
46
+ * Element renderer interface for product card elements.
47
+ * Keys are ATTR_PRODUCT_* constants for built-in elements.
48
+ * The index signature allows dynamic custom attribute keys (e.g., "customAttr:rating_star").
49
+ * The Symbol-keyed [CUSTOM_CELL_HTML] entry stores the layout-specific HTML template
50
+ * for custom attributes — used by `buildElementRenderer` to create custom entries.
18
51
  */
19
52
  export interface ElementRenderer {
20
53
  [ATTR_PRODUCT_IMAGE]: (product: RecommendationProduct) => string;
@@ -24,6 +57,8 @@ export interface ElementRenderer {
24
57
  [ATTR_PRODUCT_OMNIBUS_PRICE]: (product: RecommendationProduct) => string;
25
58
  [ATTR_PRODUCT_OMNIBUS_DISCOUNT]: (product: RecommendationProduct) => string;
26
59
  [ATTR_PRODUCT_BUTTON]: (product: RecommendationProduct) => string;
60
+ [CUSTOM_CELL_HTML]?: CustomCellHtmlGetter;
61
+ [key: string]: (product: RecommendationProduct) => string;
27
62
  }
28
63
  /**
29
64
  * Product card getter function type
@@ -15,7 +15,7 @@ export interface NodeWithGetStyle {
15
15
  }
16
16
  /** Interface for nodes with parent method */
17
17
  export interface NodeWithParent {
18
- parent: () => ImmutableHtmlNode | null;
18
+ parent: () => ImmutableHtmlNode | undefined;
19
19
  }
20
20
  /**
21
21
  * Type guard to check if a node has getStyle method
@@ -38,13 +38,13 @@ export declare function isTdNode(node: unknown): node is ImmutableHtmlNode & Nod
38
38
  * @param property - The CSS property name
39
39
  * @returns The style value or null if not accessible
40
40
  */
41
- export declare function safeGetStyle(node: ImmutableHtmlNode | null, property: string): string | null | undefined;
41
+ export declare function safeGetStyle(node: ImmutableHtmlNode | null | undefined, property: string): string | null | undefined;
42
42
  /**
43
43
  * Safely retrieves the parent element of a node
44
44
  * @param node - The node to get the parent from
45
45
  * @returns The parent node or null if not accessible
46
46
  */
47
- export declare function safeGetParent(node: ImmutableHtmlNode | null): ImmutableHtmlNode | null;
47
+ export declare function safeGetParent(node: ImmutableHtmlNode | null | undefined): ImmutableHtmlNode | null;
48
48
  /**
49
49
  * Safely retrieves the tag name from a node.
50
50
  * Handles both standard DOM tagName property and Stripo's getTagName() method.
@@ -99,18 +99,12 @@ ue-check-button.checked:not(.flat-white) input:checked + label .icon-button {
99
99
  color: var(--guido-color-primary-500);
100
100
  }
101
101
 
102
- ue-select.full-width .button {
103
- border: none !important;
104
- background-color: var(--guido-color-neutral-200) !important;
105
- color: var(--guido-color-neutral-800) !important;
106
- }
107
-
108
102
  ue-select.full-width .button .icon-button {
109
103
  color: var(--guido-color-gray-600) !important;
110
104
  }
111
105
 
112
106
  ue-select.full-width .button:hover:not(:disabled,.disabled) {
113
- background-color: var(--guido-color-neutral-100) !important;
107
+ background-color: var(--guido-color-gray-0) !important;
114
108
  }
115
109
 
116
110
  ue-color {
@@ -130,6 +124,18 @@ ue-select-text-input .select-text-input-toggle .button {
130
124
  justify-content: center;
131
125
  background-color: transparent !important;
132
126
  }
127
+
128
+ .control-shadow-wrapper,
129
+ ue-button:not(.no-shadow,.flat-white),
130
+ ue-toggle:not(.no-shadow,.flat-white),
131
+ :is(ue-popover-toggler,ue-toggle-icon-picker,ue-emoji-toggle),
132
+ .button-group,
133
+ ue-counter:not(.no-shadow),
134
+ :is(ue-select,ue-mergetags,ue-font-family-select):not(.no-shadow),
135
+ ue-check-button:not(.no-shadow,.flat-white) {
136
+ background: none;
137
+ padding: 0;
138
+ }
133
139
  `;
134
140
  export {
135
141
  o as default