@akinon/pz-theme 2.0.88-rc.0 → 2.0.89-beta.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.
package/CHANGELOG.md
CHANGED
|
@@ -1,38 +1,20 @@
|
|
|
1
1
|
# @akinon/pz-theme
|
|
2
2
|
|
|
3
|
-
## 2.0.
|
|
4
|
-
|
|
5
|
-
### Patch Changes
|
|
6
|
-
|
|
7
|
-
- Updated dependencies [
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
- Updated dependencies [bfafa3f49]
|
|
19
|
-
- Updated dependencies [57d7eb305]
|
|
20
|
-
- Updated dependencies [d99a6a7d5]
|
|
21
|
-
- Updated dependencies [9db81a714]
|
|
22
|
-
- Updated dependencies [591e345e1]
|
|
23
|
-
- Updated dependencies [4de5303c5]
|
|
24
|
-
- Updated dependencies [95b139dc1]
|
|
25
|
-
- Updated dependencies [1d00f2d06]
|
|
26
|
-
- Updated dependencies [4ac7b2a1e]
|
|
27
|
-
- Updated dependencies [e9598c71d]
|
|
28
|
-
- Updated dependencies [4998a9631]
|
|
29
|
-
- Updated dependencies [804d2bd6c]
|
|
30
|
-
- Updated dependencies [3909d3224]
|
|
31
|
-
- Updated dependencies [6a3d8a631]
|
|
32
|
-
- Updated dependencies [e18836b20]
|
|
33
|
-
- Updated dependencies [b1111d7b]
|
|
34
|
-
- @akinon/next@2.0.88-rc.0
|
|
35
|
-
- @akinon/theme-contract@2.0.88-rc.0
|
|
3
|
+
## 2.0.89-beta.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [cbbbfd757]
|
|
8
|
+
- @akinon/next@2.0.89-beta.0
|
|
9
|
+
- @akinon/theme-contract@2.0.89-beta.0
|
|
10
|
+
|
|
11
|
+
## 2.0.88
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- c871a38a: ZERO-4903: Add a brand search-term transform hook to the search box Merchandiser synonym/typo tables are brand data
|
|
16
|
+
- @akinon/next@2.0.88
|
|
17
|
+
- @akinon/theme-contract@2.0.88
|
|
36
18
|
|
|
37
19
|
## 2.0.87
|
|
38
20
|
|
package/package.json
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akinon/pz-theme",
|
|
3
3
|
"description": "Theme package for Project Zero Next — ThemePlaceholder system and theme editor infrastructure",
|
|
4
|
-
"version": "2.0.
|
|
4
|
+
"version": "2.0.89-beta.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "src/index.ts",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"test": "jest"
|
|
9
9
|
},
|
|
10
10
|
"peerDependencies": {
|
|
11
|
-
"@akinon/next": "2.0.
|
|
11
|
+
"@akinon/next": "2.0.89-beta.0",
|
|
12
12
|
"react": "^18.0.0 || ^19.0.0",
|
|
13
13
|
"react-dom": "^18.0.0 || ^19.0.0"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@akinon/theme-contract": "2.0.
|
|
16
|
+
"@akinon/theme-contract": "2.0.89-beta.0",
|
|
17
17
|
"clsx": "2.1.1",
|
|
18
18
|
"lottie-web": "^5.13.0",
|
|
19
19
|
"tailwind-merge": "^2.5.4",
|
|
20
20
|
"zod": "4.4.1"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
|
-
"@akinon/next": "2.0.
|
|
23
|
+
"@akinon/next": "2.0.89-beta.0",
|
|
24
24
|
"@testing-library/jest-dom": "5.16.4",
|
|
25
25
|
"@testing-library/react": "16.3.2",
|
|
26
26
|
"@testing-library/user-event": "14.1.1",
|
|
@@ -4,6 +4,7 @@ import React, { useRef, useState } from 'react';
|
|
|
4
4
|
import { useRouter } from 'next/navigation';
|
|
5
5
|
import { getResponsiveValue, partAttrs, resolveForceOpen } from '../utils';
|
|
6
6
|
import { emitCommerceEvent } from '../utils/analytics';
|
|
7
|
+
import { applySearchTermTransform } from '../utils/search-transform';
|
|
7
8
|
import { useOverlay } from '../hooks/use-overlay';
|
|
8
9
|
import ThemeBlock from '../theme-block';
|
|
9
10
|
import { BlockRendererProps } from './block-renderer-registry';
|
|
@@ -183,7 +184,9 @@ const SearchBoxBlock = ({
|
|
|
183
184
|
|
|
184
185
|
const submit = (event: React.FormEvent) => {
|
|
185
186
|
event.preventDefault();
|
|
186
|
-
|
|
187
|
+
// The brand's synonym/typo transform (ZERO-4903) rewrites the query the
|
|
188
|
+
// way the merchandiser's table says before anything runs or reports it.
|
|
189
|
+
const value = applySearchTermTransform(term.trim());
|
|
187
190
|
if (!value || isDesigner) return;
|
|
188
191
|
emitCommerceEvent('search', { searchTerm: value });
|
|
189
192
|
const separator = searchUrl.includes('?') ? '&' : '?';
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__resetSearchTermTransformForTests,
|
|
3
|
+
applySearchTermTransform,
|
|
4
|
+
registerSearchTermTransform
|
|
5
|
+
} from '../search-transform';
|
|
6
|
+
|
|
7
|
+
describe('search term transform registry (ZERO-4903)', () => {
|
|
8
|
+
afterEach(() => __resetSearchTermTransformForTests());
|
|
9
|
+
|
|
10
|
+
it('is the identity when no brand registered', () => {
|
|
11
|
+
expect(applySearchTermTransform('spka')).toBe('spka');
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('runs the registered transform and can unregister it', () => {
|
|
15
|
+
const detach = registerSearchTermTransform((text) =>
|
|
16
|
+
text.replace('spka', 'şapka')
|
|
17
|
+
);
|
|
18
|
+
expect(applySearchTermTransform('spka')).toBe('şapka');
|
|
19
|
+
|
|
20
|
+
detach();
|
|
21
|
+
expect(applySearchTermTransform('spka')).toBe('spka');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('falls back to the input when the transform throws or empties', () => {
|
|
25
|
+
registerSearchTermTransform(() => {
|
|
26
|
+
throw new Error('brand bug');
|
|
27
|
+
});
|
|
28
|
+
expect(applySearchTermTransform('polo')).toBe('polo');
|
|
29
|
+
|
|
30
|
+
__resetSearchTermTransformForTests();
|
|
31
|
+
registerSearchTermTransform(() => '');
|
|
32
|
+
expect(applySearchTermTransform('polo')).toBe('polo');
|
|
33
|
+
});
|
|
34
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Brand hook for search-term rewriting (ZERO-4903).
|
|
3
|
+
*
|
|
4
|
+
* Merchandisers maintain synonym/typo tables ("spka" → "şapka") that the
|
|
5
|
+
* query must pass through BEFORE it is searched — but the table's source and
|
|
6
|
+
* matching rules are brand decisions, so the composed search box never learns
|
|
7
|
+
* them. A brand registers one transform from its own code (the same ownership
|
|
8
|
+
* pattern as the analytics bridge), and the search-box block runs every
|
|
9
|
+
* submitted query through it. No registration means identity: stores without
|
|
10
|
+
* a table keep exactly today's behavior.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
type SearchTermTransform = (text: string) => string;
|
|
14
|
+
|
|
15
|
+
let transform: SearchTermTransform | null = null;
|
|
16
|
+
|
|
17
|
+
/** Register the brand's transform. Returns an unregister function. */
|
|
18
|
+
export const registerSearchTermTransform = (
|
|
19
|
+
fn: SearchTermTransform
|
|
20
|
+
): (() => void) => {
|
|
21
|
+
transform = fn;
|
|
22
|
+
return () => {
|
|
23
|
+
if (transform === fn) transform = null;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/** The query the search should run — the input itself when no brand hooked in
|
|
28
|
+
* or the transform throws (a brand bug must never break search). */
|
|
29
|
+
export const applySearchTermTransform = (text: string): string => {
|
|
30
|
+
if (!transform) return text;
|
|
31
|
+
try {
|
|
32
|
+
const result = transform(text);
|
|
33
|
+
return typeof result === 'string' && result.length > 0 ? result : text;
|
|
34
|
+
} catch {
|
|
35
|
+
return text;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/** Test-only: reset the registry between cases. */
|
|
40
|
+
export const __resetSearchTermTransformForTests = (): void => {
|
|
41
|
+
transform = null;
|
|
42
|
+
};
|