@shoplix-ai/block-kit 4.6.0 → 5.16.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.
Files changed (115) hide show
  1. package/README.md +116 -10
  2. package/dist/account-links.d.ts +96 -0
  3. package/dist/account-links.d.ts.map +1 -0
  4. package/dist/account-links.js +121 -0
  5. package/dist/account-links.js.map +1 -0
  6. package/dist/address-list.d.ts +58 -0
  7. package/dist/address-list.d.ts.map +1 -0
  8. package/dist/address-list.js +57 -0
  9. package/dist/address-list.js.map +1 -0
  10. package/dist/buy-box.d.ts +8 -0
  11. package/dist/buy-box.d.ts.map +1 -1
  12. package/dist/buy-box.js +8 -0
  13. package/dist/buy-box.js.map +1 -1
  14. package/dist/capabilities.d.ts +12 -2
  15. package/dist/capabilities.d.ts.map +1 -1
  16. package/dist/capabilities.js.map +1 -1
  17. package/dist/category-grid.d.ts +92 -0
  18. package/dist/category-grid.d.ts.map +1 -0
  19. package/dist/category-grid.js +123 -0
  20. package/dist/category-grid.js.map +1 -0
  21. package/dist/color-choice.d.ts +4 -0
  22. package/dist/color-choice.d.ts.map +1 -0
  23. package/dist/color-choice.js +11 -0
  24. package/dist/color-choice.js.map +1 -0
  25. package/dist/content-direction.d.ts +10 -0
  26. package/dist/content-direction.d.ts.map +1 -0
  27. package/dist/content-direction.js +20 -0
  28. package/dist/content-direction.js.map +1 -0
  29. package/dist/contract.d.ts +20 -14
  30. package/dist/contract.d.ts.map +1 -1
  31. package/dist/contract.js +3 -2
  32. package/dist/contract.js.map +1 -1
  33. package/dist/description.d.ts +60 -0
  34. package/dist/description.d.ts.map +1 -0
  35. package/dist/description.js +332 -0
  36. package/dist/description.js.map +1 -0
  37. package/dist/hero-banner.d.ts +10 -1
  38. package/dist/hero-banner.d.ts.map +1 -1
  39. package/dist/hero-banner.js +17 -0
  40. package/dist/hero-banner.js.map +1 -1
  41. package/dist/index.d.ts +32 -11
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +19 -8
  44. package/dist/index.js.map +1 -1
  45. package/dist/listing-filters.d.ts +114 -0
  46. package/dist/listing-filters.d.ts.map +1 -0
  47. package/dist/listing-filters.js +195 -0
  48. package/dist/listing-filters.js.map +1 -0
  49. package/dist/listing-toolbar.d.ts +117 -0
  50. package/dist/listing-toolbar.d.ts.map +1 -0
  51. package/dist/listing-toolbar.js +130 -0
  52. package/dist/listing-toolbar.js.map +1 -0
  53. package/dist/money.d.ts +7 -0
  54. package/dist/money.d.ts.map +1 -1
  55. package/dist/money.js +15 -0
  56. package/dist/money.js.map +1 -1
  57. package/dist/navigation.d.ts +10 -2
  58. package/dist/navigation.d.ts.map +1 -1
  59. package/dist/orders.d.ts +162 -0
  60. package/dist/orders.d.ts.map +1 -0
  61. package/dist/orders.js +302 -0
  62. package/dist/orders.js.map +1 -0
  63. package/dist/product-card.d.ts +4 -0
  64. package/dist/product-card.d.ts.map +1 -1
  65. package/dist/product-card.js +4 -0
  66. package/dist/product-card.js.map +1 -1
  67. package/dist/product-gallery.d.ts +3 -0
  68. package/dist/product-gallery.d.ts.map +1 -1
  69. package/dist/product-gallery.js +3 -0
  70. package/dist/product-gallery.js.map +1 -1
  71. package/dist/product-specs.d.ts +33 -2
  72. package/dist/product-specs.d.ts.map +1 -1
  73. package/dist/product-specs.js +51 -2
  74. package/dist/product-specs.js.map +1 -1
  75. package/dist/product-summary.d.ts +12 -1
  76. package/dist/product-summary.d.ts.map +1 -1
  77. package/dist/product-summary.js +29 -0
  78. package/dist/product-summary.js.map +1 -1
  79. package/dist/profile-header.d.ts +30 -0
  80. package/dist/profile-header.d.ts.map +1 -0
  81. package/dist/profile-header.js +36 -0
  82. package/dist/profile-header.js.map +1 -0
  83. package/dist/promo-banner.d.ts +11 -1
  84. package/dist/promo-banner.d.ts.map +1 -1
  85. package/dist/promo-banner.js +24 -0
  86. package/dist/promo-banner.js.map +1 -1
  87. package/dist/section-header.d.ts +5 -1
  88. package/dist/section-header.d.ts.map +1 -1
  89. package/dist/section-header.js +5 -1
  90. package/dist/section-header.js.map +1 -1
  91. package/dist/sign-in.d.ts +28 -0
  92. package/dist/sign-in.d.ts.map +1 -0
  93. package/dist/sign-in.js +27 -0
  94. package/dist/sign-in.js.map +1 -0
  95. package/dist/store-header.d.ts +49 -6
  96. package/dist/store-header.d.ts.map +1 -1
  97. package/dist/store-header.js +59 -5
  98. package/dist/store-header.js.map +1 -1
  99. package/dist/variant-choice.d.ts +14 -0
  100. package/dist/variant-choice.d.ts.map +1 -1
  101. package/dist/variant-choice.js +36 -0
  102. package/dist/variant-choice.js.map +1 -1
  103. package/dist/variant-rows.d.ts +33 -0
  104. package/dist/variant-rows.d.ts.map +1 -0
  105. package/dist/variant-rows.js +52 -0
  106. package/dist/variant-rows.js.map +1 -0
  107. package/dist/version.d.ts +2 -2
  108. package/dist/version.d.ts.map +1 -1
  109. package/dist/version.js +2 -2
  110. package/dist/version.js.map +1 -1
  111. package/dist/words.d.ts +185 -0
  112. package/dist/words.d.ts.map +1 -1
  113. package/dist/words.js +530 -4
  114. package/dist/words.js.map +1 -1
  115. package/package.json +2 -2
@@ -0,0 +1,114 @@
1
+ import { type ListingFilterDisplay, type ListingFilterKind, type ListingFilterValueDisplay, type ListingToolbarBlock, type LocaleCode } from '@shoplix-ai/sdui-schema';
2
+ type ListingToolbarSettings = ListingToolbarBlock['props'];
3
+ interface RowBase {
4
+ readonly filterId: string;
5
+ readonly kind?: ListingFilterKind;
6
+ readonly label: string;
7
+ }
8
+ /**
9
+ * One row of the filter sheet, in the shape the shopper answers it with: a
10
+ * switch for a filter Shopify answers with a yes, the stock for one, with the
11
+ * line under its words; the values of a list, each with its count and its
12
+ * swatch or picture; or a price range between the bounds Shopify offers.
13
+ */
14
+ export type ListingFilterRow = (RowBase & {
15
+ readonly shape: 'switch';
16
+ readonly hint?: string;
17
+ readonly value: ListingFilterValueDisplay;
18
+ }) | (RowBase & {
19
+ readonly shape: 'list';
20
+ readonly values: readonly ListingFilterValueDisplay[];
21
+ }) | (RowBase & {
22
+ readonly shape: 'range';
23
+ readonly min: number;
24
+ readonly max: number;
25
+ });
26
+ /** Whether the merchant's words for a kind title its filter: every kind but those that may hold several. */
27
+ export declare function listingFilterWordsApply(kind: ListingFilterKind): boolean;
28
+ /**
29
+ * The rows of the filter sheet out of the filters Shopify offers the
30
+ * collection, in the merchant's order (`listingFiltersOf`), each titled in the
31
+ * merchant's words where they wrote some the buyer reads and Shopify's
32
+ * otherwise. The stock is a switch that says "In stock only" over "Hide
33
+ * products that are sold out" from the catalog, or the merchant's words and
34
+ * line, and turns on Shopify's own in stock value.
35
+ */
36
+ export declare function listingFilterRows(settings: ListingToolbarSettings, filters: readonly ListingFilterDisplay[], language: LocaleCode, defaultLanguage: LocaleCode): readonly ListingFilterRow[];
37
+ /**
38
+ * A filter the shopper turned on: the filter and the value it is, the product
39
+ * filter that goes to Shopify for it, and the words of the chip that names it
40
+ * under the toolbar. The chip keeps its words, so a filter stays named while
41
+ * the listing reads again.
42
+ */
43
+ export interface ActiveListingFilter {
44
+ readonly filterId: string;
45
+ readonly valueId: string;
46
+ readonly input: string;
47
+ readonly label: string;
48
+ }
49
+ /** One filter on, as one key: two of them are the same filter where their keys are. */
50
+ export declare function activeFilterKey(filter: Pick<ActiveListingFilter, 'filterId' | 'valueId'>): string;
51
+ /**
52
+ * Whether a toolbar offers its filters, on the phone and on the canvas alike:
53
+ * the merchant left the button on, the listing reads a collection, and Shopify
54
+ * offers a filter the sheet would draw, has not answered yet, or the shopper
55
+ * has a filter on.
56
+ */
57
+ export declare function listingFilterShown(settings: ListingToolbarSettings, listing: {
58
+ readonly filterable: boolean;
59
+ readonly filters: readonly ListingFilterDisplay[] | undefined;
60
+ readonly active: number;
61
+ }, language: LocaleCode, defaultLanguage: LocaleCode): boolean;
62
+ /** A switch or a value of a list turned on: Shopify's own input for the value, and the switch's words or the value's. */
63
+ export declare function activeFilterOf(row: Extract<ListingFilterRow, {
64
+ shape: 'switch' | 'list';
65
+ }>, value: ListingFilterValueDisplay): ActiveListingFilter;
66
+ /** The id a price range the shopper gave holds in place of a value's, Shopify offering one range and no values to pick. */
67
+ export declare const PRICE_RANGE_VALUE = "range";
68
+ /**
69
+ * A price the shopper typed, read as a number whatever keyboard wrote it: the
70
+ * digits the Arabic and the Persian keyboards write read as the ones Shopify
71
+ * takes, the Arabic decimal mark as the point, and the thousands marks dropped.
72
+ * Where a point and a comma both stand, the last is the decimal mark; a lone
73
+ * comma before three digits groups the thousands, so "1,000" is a thousand and
74
+ * "49,90" forty-nine and ninety; a lone point is the decimal mark. Nothing
75
+ * typed, or something that is no price, is no bound.
76
+ */
77
+ export declare function typedPrice(typed: string): number | undefined;
78
+ /**
79
+ * A price range the shopper gave, as Shopify's price filter, the one filter
80
+ * whose input the app writes, since Shopify offers a range's bounds and no
81
+ * value to pick: the bounds they typed, low first. Its chip names the filter
82
+ * and both ends, a missing end being Shopify's own bound. No bound typed is no
83
+ * filter.
84
+ */
85
+ export declare function activePriceFilter(row: Extract<ListingFilterRow, {
86
+ shape: 'range';
87
+ }>, low: number | undefined, high: number | undefined): ActiveListingFilter | undefined;
88
+ /** The bounds of a price range the shopper gave, read back off its filter, to stand in the sheet's fields again. */
89
+ export declare function priceBoundsOf(active: ActiveListingFilter): {
90
+ readonly min?: number;
91
+ readonly max?: number;
92
+ };
93
+ /** Every word of the filter button, the sheet and the chips. */
94
+ export interface ListingFilterWords {
95
+ readonly button: string;
96
+ readonly title: string;
97
+ readonly apply: string;
98
+ readonly clear: string;
99
+ readonly clearAll: string;
100
+ readonly remove: string;
101
+ readonly none: string;
102
+ readonly min: string;
103
+ readonly max: string;
104
+ /** How a screen reader names the button with this many filters on. */
105
+ on(count: number): string;
106
+ }
107
+ /**
108
+ * The words of the filters: the merchant's for the button, the sheet's title,
109
+ * its two buttons and "clear all" where they wrote some the buyer reads, and
110
+ * the catalog's `listing.filter*` otherwise.
111
+ */
112
+ export declare function listingFilterWords(settings: ListingToolbarSettings, language: LocaleCode, defaultLanguage: LocaleCode): ListingFilterWords;
113
+ export {};
114
+ //# sourceMappingURL=listing-filters.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listing-filters.d.ts","sourceRoot":"","sources":["../src/listing-filters.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,195 @@
1
+ import { LISTING_TOOLBAR_DEFAULTS, listingFiltersOf, } from '@shoplix-ai/sdui-schema';
2
+ import { readable } from './locale.js';
3
+ import { platformWords } from './words.js';
4
+ function wordOf(text, language, defaultLanguage) {
5
+ return text === undefined ? undefined : readable(text, language, defaultLanguage);
6
+ }
7
+ /**
8
+ * The kinds that may hold several filters of Shopify's, a size and a colour
9
+ * for one: each is titled in the words the merchant gave it in Search &
10
+ * Discovery, since one word of theirs could not name both.
11
+ */
12
+ const SEVERAL_FILTER_KINDS = new Set([
13
+ 'variant_option',
14
+ 'metafield',
15
+ ]);
16
+ /** Whether the merchant's words for a kind title its filter: every kind but those that may hold several. */
17
+ export function listingFilterWordsApply(kind) {
18
+ return !SEVERAL_FILTER_KINDS.has(kind);
19
+ }
20
+ /**
21
+ * The rows of the filter sheet out of the filters Shopify offers the
22
+ * collection, in the merchant's order (`listingFiltersOf`), each titled in the
23
+ * merchant's words where they wrote some the buyer reads and Shopify's
24
+ * otherwise. The stock is a switch that says "In stock only" over "Hide
25
+ * products that are sold out" from the catalog, or the merchant's words and
26
+ * line, and turns on Shopify's own in stock value.
27
+ */
28
+ export function listingFilterRows(settings, filters, language, defaultLanguage) {
29
+ const words = platformWords(language, defaultLanguage);
30
+ return listingFiltersOf(settings, filters).flatMap(({ filter, choice }) => {
31
+ const worded = filter.kind !== undefined && listingFilterWordsApply(filter.kind);
32
+ const own = worded ? wordOf(choice?.label, language, defaultLanguage) : undefined;
33
+ const stock = filter.kind === 'availability';
34
+ const base = {
35
+ filterId: filter.id,
36
+ ...(filter.kind === undefined ? {} : { kind: filter.kind }),
37
+ };
38
+ const yes = filter.values.find((value) => value.id === filter.yes);
39
+ if (yes !== undefined) {
40
+ const hint = stock
41
+ ? (wordOf(choice?.hint, language, defaultLanguage) ??
42
+ words.own('listing.filter_in_stock_hint'))
43
+ : undefined;
44
+ return [
45
+ {
46
+ ...base,
47
+ shape: 'switch',
48
+ label: own ?? (stock ? words.own('listing.filter_in_stock') : filter.label),
49
+ ...(hint === undefined ? {} : { hint }),
50
+ value: yes,
51
+ },
52
+ ];
53
+ }
54
+ if (filter.shape === 'price_range') {
55
+ if (filter.range === undefined)
56
+ return [];
57
+ return [
58
+ {
59
+ ...base,
60
+ shape: 'range',
61
+ label: own ?? filter.label,
62
+ min: filter.range.min,
63
+ max: filter.range.max,
64
+ },
65
+ ];
66
+ }
67
+ if (filter.values.length === 0)
68
+ return [];
69
+ return [{ ...base, shape: 'list', label: own ?? filter.label, values: filter.values }];
70
+ });
71
+ }
72
+ /** One filter on, as one key: two of them are the same filter where their keys are. */
73
+ export function activeFilterKey(filter) {
74
+ return `${filter.filterId}:${filter.valueId}`;
75
+ }
76
+ /**
77
+ * Whether a toolbar offers its filters, on the phone and on the canvas alike:
78
+ * the merchant left the button on, the listing reads a collection, and Shopify
79
+ * offers a filter the sheet would draw, has not answered yet, or the shopper
80
+ * has a filter on.
81
+ */
82
+ export function listingFilterShown(settings, listing, language, defaultLanguage) {
83
+ if (!(settings.filter ?? LISTING_TOOLBAR_DEFAULTS.filter) || !listing.filterable)
84
+ return false;
85
+ if (listing.filters === undefined || listing.active > 0)
86
+ return true;
87
+ return listingFilterRows(settings, listing.filters, language, defaultLanguage).length > 0;
88
+ }
89
+ /** A switch or a value of a list turned on: Shopify's own input for the value, and the switch's words or the value's. */
90
+ export function activeFilterOf(row, value) {
91
+ return {
92
+ filterId: row.filterId,
93
+ valueId: value.id,
94
+ input: value.input,
95
+ label: row.shape === 'switch' ? row.label : value.label,
96
+ };
97
+ }
98
+ /** The id a price range the shopper gave holds in place of a value's, Shopify offering one range and no values to pick. */
99
+ export const PRICE_RANGE_VALUE = 'range';
100
+ const DIGIT_SETS = ['٠١٢٣٤٥٦٧٨٩', '۰۱۲۳۴۵۶۷۸۹'];
101
+ /**
102
+ * A price the shopper typed, read as a number whatever keyboard wrote it: the
103
+ * digits the Arabic and the Persian keyboards write read as the ones Shopify
104
+ * takes, the Arabic decimal mark as the point, and the thousands marks dropped.
105
+ * Where a point and a comma both stand, the last is the decimal mark; a lone
106
+ * comma before three digits groups the thousands, so "1,000" is a thousand and
107
+ * "49,90" forty-nine and ninety; a lone point is the decimal mark. Nothing
108
+ * typed, or something that is no price, is no bound.
109
+ */
110
+ export function typedPrice(typed) {
111
+ let text = typed
112
+ .trim()
113
+ .replace(/[\s٬']/g, '')
114
+ .replace(/٫/g, '.');
115
+ for (const set of DIGIT_SETS) {
116
+ text = text.replace(/[٠-٩۰-۹]/g, (digit) => {
117
+ const at = set.indexOf(digit);
118
+ return at === -1 ? digit : String(at);
119
+ });
120
+ }
121
+ const marks = [...text.matchAll(/[.,]/g)].map((match) => match.index);
122
+ const last = marks[marks.length - 1];
123
+ let decimal;
124
+ if (last !== undefined && new Set(marks.map((at) => text[at])).size === 2)
125
+ decimal = last;
126
+ else if (last !== undefined && marks.length === 1) {
127
+ decimal = text[last] === '.' || text.length - last - 1 !== 3 ? last : undefined;
128
+ }
129
+ const whole = decimal === undefined ? text : text.slice(0, decimal);
130
+ const fraction = decimal === undefined ? undefined : text.slice(decimal + 1);
131
+ const groups = whole.split(/[.,]/);
132
+ if (groups.slice(1).some((group) => group.length !== 3))
133
+ return undefined;
134
+ const latin = groups.join('') + (fraction === undefined ? '' : `.${fraction}`);
135
+ if (!/^\d+(\.\d+)?$/.test(latin))
136
+ return undefined;
137
+ const amount = Number(latin);
138
+ return Number.isFinite(amount) ? amount : undefined;
139
+ }
140
+ function priceWord(amount) {
141
+ return String(Math.round(amount * 100) / 100);
142
+ }
143
+ /**
144
+ * A price range the shopper gave, as Shopify's price filter, the one filter
145
+ * whose input the app writes, since Shopify offers a range's bounds and no
146
+ * value to pick: the bounds they typed, low first. Its chip names the filter
147
+ * and both ends, a missing end being Shopify's own bound. No bound typed is no
148
+ * filter.
149
+ */
150
+ export function activePriceFilter(row, low, high) {
151
+ if (low === undefined && high === undefined)
152
+ return undefined;
153
+ const [min, max] = low !== undefined && high !== undefined && low > high ? [high, low] : [low, high];
154
+ const price = { ...(min === undefined ? {} : { min }), ...(max === undefined ? {} : { max }) };
155
+ return {
156
+ filterId: row.filterId,
157
+ valueId: PRICE_RANGE_VALUE,
158
+ input: JSON.stringify({ price }),
159
+ label: `${row.label}: ${priceWord(min ?? row.min)} – ${priceWord(max ?? row.max)}`,
160
+ };
161
+ }
162
+ /** The bounds of a price range the shopper gave, read back off its filter, to stand in the sheet's fields again. */
163
+ export function priceBoundsOf(active) {
164
+ try {
165
+ const price = JSON.parse(active.input).price;
166
+ return {
167
+ ...(typeof price?.min === 'number' ? { min: price.min } : {}),
168
+ ...(typeof price?.max === 'number' ? { max: price.max } : {}),
169
+ };
170
+ }
171
+ catch {
172
+ return {};
173
+ }
174
+ }
175
+ /**
176
+ * The words of the filters: the merchant's for the button, the sheet's title,
177
+ * its two buttons and "clear all" where they wrote some the buyer reads, and
178
+ * the catalog's `listing.filter*` otherwise.
179
+ */
180
+ export function listingFilterWords(settings, language, defaultLanguage) {
181
+ const words = platformWords(language, defaultLanguage);
182
+ return {
183
+ button: words.merchantOr(settings.filterButton, 'listing.filter'),
184
+ title: words.merchantOr(settings.filterTitle, 'listing.filter_title'),
185
+ apply: words.merchantOr(settings.filterApply, 'listing.filter_apply'),
186
+ clear: words.merchantOr(settings.filterClear, 'listing.filter_clear'),
187
+ clearAll: words.merchantOr(settings.filterClearAll, 'listing.filter_clear_all'),
188
+ remove: words.own('listing.filter_remove'),
189
+ none: words.own('listing.filter_none'),
190
+ min: words.own('listing.filter_min'),
191
+ max: words.own('listing.filter_max'),
192
+ on: (count) => words.own('listing.filter_on').replace('{count}', String(count)),
193
+ };
194
+ }
195
+ //# sourceMappingURL=listing-filters.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listing-filters.js","sourceRoot":"","sources":["../src/listing-filters.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,EACxB,gBAAgB,GAOjB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAyB3C,SAAS,MAAM,CACb,IAA+B,EAC/B,QAAoB,EACpB,eAA2B;IAE3B,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,eAAe,CAAC,CAAC;AACpF,CAAC;AAED;;;;GAIG;AACH,MAAM,oBAAoB,GAAmC,IAAI,GAAG,CAAC;IACnE,gBAAgB;IAChB,WAAW;CACZ,CAAC,CAAC;AAEH,4GAA4G;AAC5G,MAAM,UAAU,uBAAuB,CAAC,IAAuB;IAC7D,OAAO,CAAC,oBAAoB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AACzC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAC/B,QAAgC,EAChC,OAAwC,EACxC,QAAoB,EACpB,eAA2B;IAE3B,MAAM,KAAK,GAAG,aAAa,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;IACvD,OAAO,gBAAgB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAsB,EAAE;QAC5F,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,KAAK,SAAS,IAAI,uBAAuB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACjF,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAClF,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,KAAK,cAAc,CAAC;QAC7C,MAAM,IAAI,GAAG;YACX,QAAQ,EAAE,MAAM,CAAC,EAAE;YACnB,GAAG,CAAC,MAAM,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;SAC5D,CAAC;QACF,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,MAAM,CAAC,GAAG,CAAC,CAAC;QACnE,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YACtB,MAAM,IAAI,GAAG,KAAK;gBAChB,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,eAAe,CAAC;oBAChD,KAAK,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;gBAC5C,CAAC,CAAC,SAAS,CAAC;YACd,OAAO;gBACL;oBACE,GAAG,IAAI;oBACP,KAAK,EAAE,QAAQ;oBACf,KAAK,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;oBAC3E,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;oBACvC,KAAK,EAAE,GAAG;iBACX;aACF,CAAC;QACJ,CAAC;QACD,IAAI,MAAM,CAAC,KAAK,KAAK,aAAa,EAAE,CAAC;YACnC,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS;gBAAE,OAAO,EAAE,CAAC;YAC1C,OAAO;gBACL;oBACE,GAAG,IAAI;oBACP,KAAK,EAAE,OAAO;oBACd,KAAK,EAAE,GAAG,IAAI,MAAM,CAAC,KAAK;oBAC1B,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG;oBACrB,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG;iBACtB;aACF,CAAC;QACJ,CAAC;QACD,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QAC1C,OAAO,CAAC,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IACzF,CAAC,CAAC,CAAC;AACL,CAAC;AAeD,uFAAuF;AACvF,MAAM,UAAU,eAAe,CAAC,MAAyD;IACvF,OAAO,GAAG,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;AAChD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAChC,QAAgC,EAChC,OAIC,EACD,QAAoB,EACpB,eAA2B;IAE3B,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,IAAI,wBAAwB,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU;QAAE,OAAO,KAAK,CAAC;IAC/F,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACrE,OAAO,iBAAiB,CAAC,QAAQ,EAAE,OAAO,CAAC,OAAO,EAAE,QAAQ,EAAE,eAAe,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;AAC5F,CAAC;AAED,yHAAyH;AACzH,MAAM,UAAU,cAAc,CAC5B,GAA4D,EAC5D,KAAgC;IAEhC,OAAO;QACL,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,OAAO,EAAE,KAAK,CAAC,EAAE;QACjB,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,KAAK,EAAE,GAAG,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK;KACxD,CAAC;AACJ,CAAC;AAED,2HAA2H;AAC3H,MAAM,CAAC,MAAM,iBAAiB,GAAG,OAAO,CAAC;AAEzC,MAAM,UAAU,GAAG,CAAC,YAAY,EAAE,YAAY,CAAU,CAAC;AAEzD;;;;;;;;GAQG;AACH,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,IAAI,IAAI,GAAG,KAAK;SACb,IAAI,EAAE;SACN,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACtB,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;QAC7B,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,KAAK,EAAE,EAAE;YACzC,MAAM,EAAE,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YAC9B,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC;IACL,CAAC;IACD,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACtE,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACrC,IAAI,OAA2B,CAAC;IAChC,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,GAAG,IAAI,CAAC;SACrF,IAAI,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClD,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI,IAAI,CAAC,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;IAClF,CAAC;IACD,MAAM,KAAK,GAAG,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IACpE,MAAM,QAAQ,GAAG,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;IAC7E,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACnC,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IAC1E,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,QAAQ,EAAE,CAAC,CAAC;IAC/E,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IACnD,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC7B,OAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;AACtD,CAAC;AAED,SAAS,SAAS,CAAC,MAAc;IAC/B,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC;AAChD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAC/B,GAAkD,EAClD,GAAuB,EACvB,IAAwB;IAExB,IAAI,GAAG,KAAK,SAAS,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC9D,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,GACd,GAAG,KAAK,SAAS,IAAI,IAAI,KAAK,SAAS,IAAI,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACpF,MAAM,KAAK,GAAG,EAAE,GAAG,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;IAC/F,OAAO;QACL,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,OAAO,EAAE,iBAAiB;QAC1B,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,CAAC;QAChC,KAAK,EAAE,GAAG,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,MAAM,SAAS,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,EAAE;KACnF,CAAC;AACJ,CAAC;AAED,oHAAoH;AACpH,MAAM,UAAU,aAAa,CAAC,MAA2B;IAIvD,IAAI,CAAC;QACH,MAAM,KAAK,GAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAkD,CAAC,KAAK,CAAC;QAC/F,OAAO;YACL,GAAG,CAAC,OAAO,KAAK,EAAE,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC7D,GAAG,CAAC,OAAO,KAAK,EAAE,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC9D,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAiBD;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAChC,QAAgC,EAChC,QAAoB,EACpB,eAA2B;IAE3B,MAAM,KAAK,GAAG,aAAa,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;IACvD,OAAO;QACL,MAAM,EAAE,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,YAAY,EAAE,gBAAgB,CAAC;QACjE,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,WAAW,EAAE,sBAAsB,CAAC;QACrE,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,WAAW,EAAE,sBAAsB,CAAC;QACrE,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,WAAW,EAAE,sBAAsB,CAAC;QACrE,QAAQ,EAAE,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,cAAc,EAAE,0BAA0B,CAAC;QAC/E,MAAM,EAAE,KAAK,CAAC,GAAG,CAAC,uBAAuB,CAAC;QAC1C,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,qBAAqB,CAAC;QACtC,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC,oBAAoB,CAAC;QACpC,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC,oBAAoB,CAAC;QACpC,EAAE,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;KAChF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,117 @@
1
+ import { type ListingSortKey, type ListingToolbarBlock, type LocaleCode, type ThemeStyle } from '@shoplix-ai/sdui-schema';
2
+ type ListingToolbarSettings = ListingToolbarBlock['props'];
3
+ /** The parts of the listing toolbar, each with the theme role it draws unless a component token names another. */
4
+ declare const LISTING_TOOLBAR_ROLES: {
5
+ readonly count: "text";
6
+ readonly count_word: "muted";
7
+ readonly bar: "elevated";
8
+ readonly bar_stroke: "border";
9
+ readonly bar_ink: "text";
10
+ readonly track: "sunken";
11
+ readonly cell: "elevated";
12
+ readonly cell_ink: "text";
13
+ readonly cell_idle: "subtle";
14
+ readonly divider: "border";
15
+ readonly badge: "accent";
16
+ readonly chip: "sunken";
17
+ readonly chip_stroke: "border";
18
+ readonly chip_ink: "text";
19
+ readonly chip_remove: "subtle";
20
+ readonly clear_all: "accent";
21
+ };
22
+ export type ListingToolbarPart = keyof typeof LISTING_TOOLBAR_ROLES;
23
+ /** The toolbar's colours, and the ink that reads on the badge and on a chip's remove button. */
24
+ export type ListingToolbarColors = Readonly<Record<ListingToolbarPart | 'badge_ink' | 'chip_remove_ink', string>>;
25
+ /**
26
+ * Every colour the listing toolbar draws: the count and its word, the bar
27
+ * that opens the sorts and the filters with its stroke, its words and the line
28
+ * between its halves, the badge that counts the filters on, the switch's track
29
+ * with the cell of the layout on show and the idle one, and the chips under the
30
+ * bar with their stroke, words and remove button, and "clear all". A role the
31
+ * merchant chose for the bar, its stroke, its words, the track, the badge or
32
+ * the chips wins; every other part is its role with `listing_toolbar.<part>`
33
+ * over it, and the badge and the remove button write in whichever ink reads on
34
+ * them. The phone and its web twin read this one table.
35
+ */
36
+ export declare function listingToolbarColors(theme: ThemeStyle, settings?: Pick<ListingToolbarSettings, 'surface' | 'stroke' | 'ink' | 'track' | 'badge' | 'chipSurface' | 'chipStroke' | 'chipInk'>): ListingToolbarColors;
37
+ /** Every measure of the toolbar, and which of its parts it draws. */
38
+ export interface ListingToolbarLook {
39
+ readonly count: boolean;
40
+ readonly layoutSwitch: boolean;
41
+ readonly sort: boolean;
42
+ readonly filter: boolean;
43
+ readonly chips: boolean;
44
+ readonly height: number;
45
+ readonly radius: number;
46
+ readonly countSize: number;
47
+ readonly wordSize: number;
48
+ readonly labelSize: number;
49
+ readonly iconSize: number;
50
+ readonly switchCell: {
51
+ readonly width: number;
52
+ readonly height: number;
53
+ readonly radius: number;
54
+ };
55
+ readonly switchPad: number;
56
+ readonly badge: {
57
+ readonly size: number;
58
+ readonly text: number;
59
+ };
60
+ readonly chip: {
61
+ readonly height: number;
62
+ readonly radius: number;
63
+ readonly text: number;
64
+ readonly remove: number;
65
+ readonly gap: number;
66
+ };
67
+ }
68
+ /**
69
+ * The toolbar as the mot design measures it: the count at 15 over a word at
70
+ * 13, the switch's two 34 by 30 cells on a track padded by 3, the bar at the
71
+ * merchant's height and corner with its words at 12.5 beside a 16 point
72
+ * glyph, the badge an 18 point circle with its number at 10.5, and each chip
73
+ * 32 tall at the merchant's corner with its words at 12.5 and an 18 point
74
+ * remove button, 8 apart. The merchant switches each part off and sets the bar.
75
+ */
76
+ export declare function listingToolbarLook(settings: ListingToolbarSettings): ListingToolbarLook;
77
+ /** How many products a listing holds so far: the number, with a plus while more pages exist, and the word after it. */
78
+ export interface ListingCount {
79
+ readonly number: string;
80
+ readonly word: string;
81
+ }
82
+ /**
83
+ * The count a listing shows: the products it has loaded, "24+" while Shopify
84
+ * names a next page, and the full number once the last page is in. The
85
+ * Storefront gives a collection no total, so the app never claims one.
86
+ */
87
+ export declare function listingCount(count: number, more: boolean, language: LocaleCode, defaultLanguage: LocaleCode): ListingCount;
88
+ /** One sort the sheet offers, in the words the shopper reads. */
89
+ export interface ListingSortRow {
90
+ readonly key: ListingSortKey;
91
+ readonly label: string;
92
+ }
93
+ /**
94
+ * The words of one sort: the merchant's own where they wrote some in a
95
+ * language the buyer reads, and the catalog's otherwise, so a sort the
96
+ * Binding opens in that the toolbar does not list is still named.
97
+ */
98
+ export declare function listingSortLabel(settings: ListingToolbarSettings, key: ListingSortKey, language: LocaleCode, defaultLanguage: LocaleCode): string;
99
+ /** The sorts the sheet offers, in the merchant's order and words. */
100
+ export declare function listingSortRows(settings: ListingToolbarSettings, language: LocaleCode, defaultLanguage: LocaleCode): readonly ListingSortRow[];
101
+ /**
102
+ * The row a product takes in a list, as mot-mobile draws it: the picture
103
+ * square at 104 beside the title in two lines and the price, and the add
104
+ * button, a 40 point square on the theme's corner, at the reading end, inside
105
+ * a card padded by 10 with 12 between its parts.
106
+ */
107
+ export declare const PRODUCT_ROW_LOOK: {
108
+ readonly picture: 104;
109
+ readonly padding: 10;
110
+ readonly gap: 12;
111
+ readonly button: 40;
112
+ readonly titleSize: 13.5;
113
+ readonly titleLines: 2;
114
+ readonly priceSize: 17;
115
+ };
116
+ export {};
117
+ //# sourceMappingURL=listing-toolbar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listing-toolbar.d.ts","sourceRoot":"","sources":["../src/listing-toolbar.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,130 @@
1
+ import { LISTING_TOOLBAR_DEFAULTS, listingSortsOf, } from '@shoplix-ai/sdui-schema';
2
+ import { readable } from './locale.js';
3
+ import { partColors } from './part-colors.js';
4
+ import { readableInk } from './readable.js';
5
+ import { countedWord, platformWords } from './words.js';
6
+ /** The parts of the listing toolbar, each with the theme role it draws unless a component token names another. */
7
+ const LISTING_TOOLBAR_ROLES = {
8
+ count: 'text',
9
+ count_word: 'muted',
10
+ bar: 'elevated',
11
+ bar_stroke: 'border',
12
+ bar_ink: 'text',
13
+ track: 'sunken',
14
+ cell: 'elevated',
15
+ cell_ink: 'text',
16
+ cell_idle: 'subtle',
17
+ divider: 'border',
18
+ badge: 'accent',
19
+ chip: 'sunken',
20
+ chip_stroke: 'border',
21
+ chip_ink: 'text',
22
+ chip_remove: 'subtle',
23
+ clear_all: 'accent',
24
+ };
25
+ /**
26
+ * Every colour the listing toolbar draws: the count and its word, the bar
27
+ * that opens the sorts and the filters with its stroke, its words and the line
28
+ * between its halves, the badge that counts the filters on, the switch's track
29
+ * with the cell of the layout on show and the idle one, and the chips under the
30
+ * bar with their stroke, words and remove button, and "clear all". A role the
31
+ * merchant chose for the bar, its stroke, its words, the track, the badge or
32
+ * the chips wins; every other part is its role with `listing_toolbar.<part>`
33
+ * over it, and the badge and the remove button write in whichever ink reads on
34
+ * them. The phone and its web twin read this one table.
35
+ */
36
+ export function listingToolbarColors(theme, settings = {}) {
37
+ const table = partColors(theme, 'listing_toolbar', LISTING_TOOLBAR_ROLES);
38
+ const chosen = (role, fallback) => role === undefined ? fallback : theme.colors[role];
39
+ const badge = chosen(settings.badge, table.badge);
40
+ return {
41
+ ...table,
42
+ bar: chosen(settings.surface, table.bar),
43
+ bar_stroke: chosen(settings.stroke, table.bar_stroke),
44
+ bar_ink: chosen(settings.ink, table.bar_ink),
45
+ track: chosen(settings.track, table.track),
46
+ badge,
47
+ badge_ink: readableInk(badge),
48
+ chip: chosen(settings.chipSurface, table.chip),
49
+ chip_stroke: chosen(settings.chipStroke, table.chip_stroke),
50
+ chip_ink: chosen(settings.chipInk, table.chip_ink),
51
+ chip_remove_ink: readableInk(table.chip_remove),
52
+ };
53
+ }
54
+ /**
55
+ * The toolbar as the mot design measures it: the count at 15 over a word at
56
+ * 13, the switch's two 34 by 30 cells on a track padded by 3, the bar at the
57
+ * merchant's height and corner with its words at 12.5 beside a 16 point
58
+ * glyph, the badge an 18 point circle with its number at 10.5, and each chip
59
+ * 32 tall at the merchant's corner with its words at 12.5 and an 18 point
60
+ * remove button, 8 apart. The merchant switches each part off and sets the bar.
61
+ */
62
+ export function listingToolbarLook(settings) {
63
+ return {
64
+ count: settings.count ?? LISTING_TOOLBAR_DEFAULTS.count,
65
+ layoutSwitch: settings.layoutSwitch ?? LISTING_TOOLBAR_DEFAULTS.layoutSwitch,
66
+ sort: settings.sort ?? LISTING_TOOLBAR_DEFAULTS.sort,
67
+ filter: settings.filter ?? LISTING_TOOLBAR_DEFAULTS.filter,
68
+ chips: settings.chips ?? LISTING_TOOLBAR_DEFAULTS.chips,
69
+ height: settings.height ?? LISTING_TOOLBAR_DEFAULTS.height,
70
+ radius: settings.radius ?? LISTING_TOOLBAR_DEFAULTS.radius,
71
+ countSize: 15,
72
+ wordSize: 13,
73
+ labelSize: 12.5,
74
+ iconSize: 16,
75
+ switchCell: { width: 34, height: 30, radius: 6 },
76
+ switchPad: 3,
77
+ badge: { size: 18, text: 10.5 },
78
+ chip: {
79
+ height: 32,
80
+ radius: settings.chipRadius ?? LISTING_TOOLBAR_DEFAULTS.chipRadius,
81
+ text: 12.5,
82
+ remove: 18,
83
+ gap: 8,
84
+ },
85
+ };
86
+ }
87
+ /**
88
+ * The count a listing shows: the products it has loaded, "24+" while Shopify
89
+ * names a next page, and the full number once the last page is in. The
90
+ * Storefront gives a collection no total, so the app never claims one.
91
+ */
92
+ export function listingCount(count, more, language, defaultLanguage) {
93
+ return {
94
+ number: more ? `${count}+` : String(count),
95
+ word: countedWord('listing.products', count, language, defaultLanguage),
96
+ };
97
+ }
98
+ /**
99
+ * The words of one sort: the merchant's own where they wrote some in a
100
+ * language the buyer reads, and the catalog's otherwise, so a sort the
101
+ * Binding opens in that the toolbar does not list is still named.
102
+ */
103
+ export function listingSortLabel(settings, key, language, defaultLanguage) {
104
+ const own = listingSortsOf(settings).find((choice) => choice.key === key)?.label;
105
+ const written = own === undefined ? undefined : readable(own, language, defaultLanguage);
106
+ return written ?? platformWords(language, defaultLanguage).own(`listing.sort.${key}`);
107
+ }
108
+ /** The sorts the sheet offers, in the merchant's order and words. */
109
+ export function listingSortRows(settings, language, defaultLanguage) {
110
+ return listingSortsOf(settings).map(({ key }) => ({
111
+ key,
112
+ label: listingSortLabel(settings, key, language, defaultLanguage),
113
+ }));
114
+ }
115
+ /**
116
+ * The row a product takes in a list, as mot-mobile draws it: the picture
117
+ * square at 104 beside the title in two lines and the price, and the add
118
+ * button, a 40 point square on the theme's corner, at the reading end, inside
119
+ * a card padded by 10 with 12 between its parts.
120
+ */
121
+ export const PRODUCT_ROW_LOOK = {
122
+ picture: 104,
123
+ padding: 10,
124
+ gap: 12,
125
+ button: 40,
126
+ titleSize: 13.5,
127
+ titleLines: 2,
128
+ priceSize: 17,
129
+ };
130
+ //# sourceMappingURL=listing-toolbar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listing-toolbar.js","sourceRoot":"","sources":["../src/listing-toolbar.ts"],"names":[],"mappings":"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"}
package/dist/money.d.ts CHANGED
@@ -32,6 +32,13 @@ export declare function moneyText(money: DisplayMoney, language: string, style?:
32
32
  * where the saving does not round to a percent worth drawing.
33
33
  */
34
34
  export declare function discountPercent(price: DisplayMoney, compareAt: DisplayMoney | undefined): number | null;
35
+ /**
36
+ * The struck price a product draws beside its own: the compare-at in the style
37
+ * the theme chose, where Shopify sent one in the same currency above the price,
38
+ * and none otherwise. A compare-at that carries no amount is drawn as Shopify
39
+ * wrote it.
40
+ */
41
+ export declare function compareAtParts(price: DisplayMoney, compareAt: DisplayMoney | undefined, language: string, style?: MoneyStyle): MoneyParts | null;
35
42
  /**
36
43
  * A figure a block worked out for itself, written the way every other price on
37
44
  * the screen is written: through the same style, from a decimal amount, never
@@ -1 +1 @@
1
- {"version":3,"file":"money.d.ts","sourceRoot":"","sources":["../src/money.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,YAAY,EAEjB,KAAK,UAAU,EAChB,MAAM,yBAAyB,CAAC;AAajC;;;GAGG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,GAAG,MAAM,EACvB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,GACf,MAAM,GAAG,IAAI,CAYf;AAoDD,qFAAqF;AACrF,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,8EAA8E;AAC9E,wBAAgB,WAAW,CAAC,KAAK,EAAE,YAAY,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAI1E;AAyCD;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE,YAAY,EACnB,QAAQ,EAAE,MAAM,EAChB,KAAK,GAAE,UAAgC,GACtC,UAAU,CAQZ;AAED,2DAA2D;AAC3D,wBAAgB,SAAS,CACvB,KAAK,EAAE,YAAY,EACnB,QAAQ,EAAE,MAAM,EAChB,KAAK,GAAE,UAAgC,GACtC,MAAM,CAGR;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,YAAY,EACnB,SAAS,EAAE,YAAY,GAAG,SAAS,GAClC,MAAM,GAAG,IAAI,CAOf;AAKD;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,EAChB,KAAK,GAAE,UAAgC,GACtC,UAAU,CAWZ;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,EAChB,KAAK,GAAE,UAAgC,GACtC,UAAU,CAGZ"}
1
+ {"version":3,"file":"money.d.ts","sourceRoot":"","sources":["../src/money.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,YAAY,EAEjB,KAAK,UAAU,EAChB,MAAM,yBAAyB,CAAC;AAajC;;;GAGG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,GAAG,MAAM,EACvB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,GACf,MAAM,GAAG,IAAI,CAYf;AAoDD,qFAAqF;AACrF,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,8EAA8E;AAC9E,wBAAgB,WAAW,CAAC,KAAK,EAAE,YAAY,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAI1E;AAyCD;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE,YAAY,EACnB,QAAQ,EAAE,MAAM,EAChB,KAAK,GAAE,UAAgC,GACtC,UAAU,CAQZ;AAED,2DAA2D;AAC3D,wBAAgB,SAAS,CACvB,KAAK,EAAE,YAAY,EACnB,QAAQ,EAAE,MAAM,EAChB,KAAK,GAAE,UAAgC,GACtC,MAAM,CAGR;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,YAAY,EACnB,SAAS,EAAE,YAAY,GAAG,SAAS,GAClC,MAAM,GAAG,IAAI,CAOf;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,YAAY,EACnB,SAAS,EAAE,YAAY,GAAG,SAAS,EACnC,QAAQ,EAAE,MAAM,EAChB,KAAK,GAAE,UAAgC,GACtC,UAAU,GAAG,IAAI,CAMnB;AAKD;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,EAChB,KAAK,GAAE,UAAgC,GACtC,UAAU,CAWZ;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,EAChB,KAAK,GAAE,UAAgC,GACtC,UAAU,CAGZ"}
package/dist/money.js CHANGED
@@ -154,6 +154,21 @@ export function discountPercent(price, compareAt) {
154
154
  const percent = Math.round((1 - now / was) * 100);
155
155
  return percent === 0 ? null : percent;
156
156
  }
157
+ /**
158
+ * The struck price a product draws beside its own: the compare-at in the style
159
+ * the theme chose, where Shopify sent one in the same currency above the price,
160
+ * and none otherwise. A compare-at that carries no amount is drawn as Shopify
161
+ * wrote it.
162
+ */
163
+ export function compareAtParts(price, compareAt, language, style = DEFAULT_MONEY_STYLE) {
164
+ if (compareAt === undefined || compareAt.currencyCode !== price.currencyCode)
165
+ return null;
166
+ const now = moneyAmount(price);
167
+ const was = moneyAmount(compareAt);
168
+ if (now !== null && was !== null && was <= now)
169
+ return null;
170
+ return moneyParts(compareAt, language, style);
171
+ }
157
172
  /** Past every currency's own places, so the style rounds the derived amount rather than this line. */
158
173
  const DERIVED_PLACES = 6;
159
174
  /**