@mohasinac/appkit 4.52.2 → 4.52.4

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.
@@ -0,0 +1,82 @@
1
+ /*
2
+ * WHY: Authored six-part procedures for the design-ux/feature-badge-picker page.
3
+ * WHAT: 5 case(s), keyed by full checklist id.
4
+ *
5
+ * @tag domain:tester
6
+ * @tag layer:seed
7
+ * @tag pattern:none
8
+ * @tag access:server-only
9
+ * @tag consumers:seed-data/authored/index.ts
10
+ * @tag sideEffects:none
11
+ */
12
+ export const authored = {
13
+ "checklist-design-ux-feature-badge-picker-features-are-searchable": {
14
+ roles: ["seller"],
15
+ startPage: "/store/products",
16
+ steps: [
17
+ "Sign in as the seller who owns the store and open /store/products.",
18
+ "Open any product for editing.",
19
+ "Scroll to the 'Feature badges' section of the form.",
20
+ "Open the control and type a few letters of a badge name.",
21
+ ],
22
+ expectedBehaviour: "Anything over five options is a searchable picker in this codebase. The control loads the platform badges eligible for this listing type plus the store's own, and filters them client-side as you type.",
23
+ expectedUiState: "'Feature badges' is a SINGLE control that opens a searchable list with a text input — not a two-column grid of bordered checkbox tiles, which is what it was. Typing narrows the visible options, and selected badges appear as removable chips on the control.",
24
+ endResult: "Closing and reopening the picker preserves the current selection. Nothing is saved until the product form itself is saved.",
25
+ },
26
+ "checklist-design-ux-feature-badge-picker-features-search-matches-description": {
27
+ roles: ["seller"],
28
+ startPage: "/store/products",
29
+ steps: [
30
+ "With the badge picker open, note a badge whose description contains a word that is NOT in its label — 'Sealed' is described as 'Factory wrap intact and never opened'.",
31
+ "Type that description-only word into the picker's search box, e.g. 'factory'.",
32
+ ],
33
+ inputs: { "picker search": "factory" },
34
+ expectedBehaviour: "Each option's description is folded into its label text specifically so it remains searchable after the conversion. In the old grid the description was visible on every tile, so it was findable by eye; in a filtered list it would be unreachable unless it is part of what is matched.",
35
+ expectedUiState: "The badge whose DESCRIPTION contains the typed word is listed, even though its name does not contain it. Searching a word in neither the label nor any description shows the no-results message instead.",
36
+ endResult: "Clearing the search box restores the full list. No selection has changed.",
37
+ },
38
+ "checklist-design-ux-feature-badge-picker-features-scope-is-visible": {
39
+ roles: ["seller"],
40
+ startPage: "/store/products",
41
+ steps: [
42
+ "Open the badge picker on a product belonging to a store that has at least one custom badge of its own.",
43
+ "Read the full text of several options in the list.",
44
+ "Select one platform badge and one store badge, then close the picker and read the two chips.",
45
+ ],
46
+ expectedBehaviour: "The grid separated the two scopes under 'Platform features' and 'Store custom features' headings. A flat searchable list has no headings, so the scope is carried in each option's own text — which also means it survives into the selected chip, where the grid's headings never reached.",
47
+ expectedUiState: "Every option ends with '(platform)' or '(your store)'. The two selected chips each still show which scope they came from. An option with no scope marker at all is a regression.",
48
+ endResult: "The distinction persists after saving and reopening the product — it is derived from the badge's own scope, not from selection order.",
49
+ },
50
+ "checklist-design-ux-feature-badge-picker-features-respects-the-cap": {
51
+ roles: ["seller"],
52
+ startPage: "/store/products",
53
+ steps: [
54
+ "Open the badge picker and read the 'Selected: N of 24' line above it.",
55
+ "Select badges one at a time until N reaches the stated maximum.",
56
+ "Try to select one more badge.",
57
+ ],
58
+ expectedBehaviour: "The ceiling is applied to the incoming selection rather than by disabling unticked rows, because a multi-select has no per-row disabled state. Selections beyond the cap are refused, keeping the earliest ones — so the badge that fails is the one just clicked, which is what a user expects.",
59
+ expectedUiState: "The counter stops at the maximum and does not go above it. Attempting to add one more does not increase the count and does not silently replace an existing selection. The counter line always matches the number of chips shown.",
60
+ expectedData: { "selected badge count": "never exceeds the stated maximum" },
61
+ endResult: "Saving the product stores at most the maximum number of badges. Reopening the product shows the same set.",
62
+ },
63
+ "checklist-design-ux-feature-badge-picker-features-inline-create": {
64
+ roles: ["seller"],
65
+ startPage: "/store/products",
66
+ steps: [
67
+ "Open the badge picker on one of your own products.",
68
+ "Choose 'Create a badge for my store'.",
69
+ "Enter a label such as 'QA inline badge' and leave the icon as its default.",
70
+ "Submit the create form.",
71
+ "Close the picker, reload the page, and reopen the picker.",
72
+ ],
73
+ inputs: { "Badge label": "QA inline badge", Icon: "star" },
74
+ expectedBehaviour: "Creating posts to the store-scope features route, which sets the owning store server-side rather than trusting the request body, and scopes the new badge to the listing type being edited. The picker's option list is refetched afterwards so the badge becomes a real option rather than a chip with nothing behind it.",
75
+ expectedUiState: "The create drawer closes on success and the new badge appears immediately as a SELECTED chip. Reopening the picker lists it among the options, marked '(your store)'. After a full page reload it is still listed and still selected on the product.",
76
+ expectedData: {
77
+ "new badge scope": "store",
78
+ "new badge owner": "the signed-in seller's store",
79
+ },
80
+ endResult: "The badge persists as a store-scope feature and is available on that store's other products too. Remove it from the store's feature settings afterwards so it does not accumulate.",
81
+ },
82
+ };
@@ -0,0 +1,2 @@
1
+ import type { AuthoredCase } from "./_types";
2
+ export declare const authored: Record<string, AuthoredCase>;
@@ -0,0 +1,88 @@
1
+ /*
2
+ * WHY: Authored six-part procedures for the design-ux/nav-reachability page.
3
+ * WHAT: 6 case(s), keyed by full checklist id.
4
+ *
5
+ * @tag domain:tester
6
+ * @tag layer:seed
7
+ * @tag pattern:none
8
+ * @tag access:server-only
9
+ * @tag consumers:seed-data/authored/index.ts
10
+ * @tag sideEffects:none
11
+ */
12
+ export const authored = {
13
+ "checklist-design-ux-nav-reachability-main-nav-first-items-reachable": {
14
+ roles: ["guest"],
15
+ startPage: "/products",
16
+ steps: [
17
+ "Set the browser window to roughly 1024 pixels wide.",
18
+ "Open /products and look at the horizontal navigation strip under the header.",
19
+ "Read the FIRST item at the left edge of the strip.",
20
+ "Scroll the strip to the right as far as it goes and read the LAST item.",
21
+ ],
22
+ expectedBehaviour: "The strip centres its items while they fit and falls back to starting at the left edge as soon as they would overflow, so nothing is ever pushed past the leading edge where scrolling cannot reach it.",
23
+ expectedUiState: "'Home' is the first item visible at the left edge of the strip, followed by 'Products'. Scrolling right reaches 'About Us' at the far end. The prior symptom was the strip opening mid-list with 'Home' and 'Products' already cut off past the left edge and no way to bring them back.",
24
+ endResult: "Nothing persists. Reloading at the same width shows 'Home' first again — the strip is not remembering a scroll position, it genuinely starts at the beginning.",
25
+ },
26
+ "checklist-design-ux-nav-reachability-main-nav-left-chevron-works": {
27
+ roles: ["guest"],
28
+ startPage: "/products",
29
+ steps: [
30
+ "At roughly 1024 pixels wide, scroll the navigation strip to the right (drag it, or use the right chevron).",
31
+ "Look at the left end of the strip for a left-pointing chevron.",
32
+ "Click the left chevron.",
33
+ ],
34
+ expectedBehaviour: "The left chevron is shown when the strip has been scrolled away from its start. That condition could never be true while the centring pinned the scroll position at 0, so the control existed and never appeared.",
35
+ expectedUiState: "After scrolling right, a left chevron is visible at the left end of the strip. Clicking it scrolls the strip back towards the start, and continuing to click eventually brings 'Home' into view and the chevron disappears again.",
36
+ endResult: "The strip can be scrolled to either end and back as many times as wanted. No state is saved.",
37
+ },
38
+ "checklist-design-ux-nav-reachability-header-hamburger-reachable-at-320": {
39
+ roles: ["guest"],
40
+ startPage: "/products",
41
+ steps: [
42
+ "Set the browser window to 320 pixels wide, or choose an iPhone SE device profile.",
43
+ "Look at the right-hand end of the top header row.",
44
+ "Tap the hamburger (menu) control.",
45
+ ],
46
+ expectedBehaviour: "The header row must fit inside the viewport at the narrowest supported width. The app shell clips horizontal overflow rather than scrolling it, so anything past the edge is unreachable — not merely out of sight.",
47
+ expectedUiState: "The hamburger is FULLY visible at the end of the header row, not half-cut and not missing, and tapping it opens the menu. The theme toggle immediately before it is also whole. The prior symptom was the hamburger sitting entirely beyond the right edge and the theme toggle sliced in half.",
48
+ endResult: "The menu opens and closes normally. Nothing persists.",
49
+ },
50
+ "checklist-design-ux-nav-reachability-header-demotes-optional-controls": {
51
+ roles: ["guest"],
52
+ startPage: "/products",
53
+ steps: [
54
+ "At 320 pixels wide, read every icon in the top header row.",
55
+ "Widen the window past about 640 pixels.",
56
+ "Read the header row again.",
57
+ "At 320 pixels again, open the hamburger menu and look for the deals and tour entries.",
58
+ ],
59
+ expectedBehaviour: "Room for the hamburger is made by demoting the two most discretionary controls at the narrowest width, rather than by letting the most important one fall off the end. Neither is removed from the product — only from the header row at that width.",
60
+ expectedUiState: "At 320px the 'Today's Deals' and product-tour icons are NOT in the header. Above ~640px both are back. At 320px their destinations are still reachable from the menu, so nothing has become unavailable.",
61
+ endResult: "Purely responsive; no state is written. Resizing back and forth shows them disappear and reappear at the same point each time.",
62
+ },
63
+ "checklist-design-ux-nav-reachability-no-horizontal-page-scroll": {
64
+ roles: ["guest"],
65
+ startPage: "/",
66
+ steps: [
67
+ "Set the browser window to 320 pixels wide.",
68
+ "Visit each of: /, /products, any product detail page, /categories, /cart.",
69
+ "On each page, try to drag the page sideways and look for a horizontal scrollbar at the bottom of the window.",
70
+ ],
71
+ expectedBehaviour: "No layout should be wider than the viewport at the narrowest supported width. A sideways-scrolling page is the clearest single symptom of a broken responsive layout.",
72
+ expectedUiState: "On all five pages the content does not move horizontally and no horizontal scrollbar appears. Report the page and the element if any one of them scrolls — this case is per-page, so a single failure is still a finding even if the other four pass.",
73
+ endResult: "Nothing persists. This is a pure layout check at one width.",
74
+ },
75
+ "checklist-design-ux-nav-reachability-lightbox-thumbnails-reachable": {
76
+ roles: ["guest"],
77
+ startPage: "/products",
78
+ steps: [
79
+ "Open a product that has several images — the Beyblade X UX-03 WizardRod and the video-demo fixtures all carry multiple.",
80
+ "Click the main product image to open the lightbox.",
81
+ "Look at the thumbnail strip below the enlarged image.",
82
+ "Scroll the strip to both ends.",
83
+ ],
84
+ expectedBehaviour: "The thumbnail strip is a horizontal scroller and had the same centring defect as the navbar, so with enough images its first thumbnails were off the leading edge with no scroll position that could reach them.",
85
+ expectedUiState: "The strip begins at the FIRST image, and every thumbnail can be reached by scrolling. No thumbnail is stranded past the left edge. Clicking any thumbnail switches the enlarged image to it.",
86
+ endResult: "Closing the lightbox returns to the product page with no change. Reopening starts the strip at the first image again.",
87
+ },
88
+ };
@@ -87,6 +87,9 @@ import { authored as a_cta_layout__editor_action_bar } from "./cta-layout__edito
87
87
  import { authored as a_cta_layout__product_bottom_bar } from "./cta-layout__product-bottom-bar.js";
88
88
  import { authored as a_design_ux__back_to_top_button } from "./design-ux__back-to-top-button.js";
89
89
  import { authored as a_design_ux__rich_text_readability } from "./design-ux__rich-text-readability.js";
90
+ import { authored as a_design_ux__action_bar_placement } from "./design-ux__action-bar-placement.js";
91
+ import { authored as a_design_ux__nav_reachability } from "./design-ux__nav-reachability.js";
92
+ import { authored as a_design_ux__feature_badge_picker } from "./design-ux__feature-badge-picker.js";
90
93
  import { authored as a_design_ux__dashboard_layout } from "./design-ux__dashboard-layout.js";
91
94
  import { authored as a_design_ux__footer_theme } from "./design-ux__footer-theme.js";
92
95
  import { authored as a_design_ux__form_validation_errors } from "./design-ux__form-validation-errors.js";
@@ -210,6 +213,9 @@ export const AUTHORED_CASES = {
210
213
  ...a_cta_layout__product_bottom_bar,
211
214
  ...a_design_ux__back_to_top_button,
212
215
  ...a_design_ux__rich_text_readability,
216
+ ...a_design_ux__action_bar_placement,
217
+ ...a_design_ux__nav_reachability,
218
+ ...a_design_ux__feature_badge_picker,
213
219
  ...a_design_ux__dashboard_layout,
214
220
  ...a_design_ux__footer_theme,
215
221
  ...a_design_ux__form_validation_errors,
@@ -3892,6 +3892,129 @@ const rawTesterChecklistItems = [
3892
3892
  },
3893
3893
  ],
3894
3894
  },
3895
+ {
3896
+ pageKey: "nav-reachability",
3897
+ pageLabel: "Navigation — Every Item Reachable at Every Width",
3898
+ href: "/products",
3899
+ cases: [
3900
+ {
3901
+ key: "main-nav-first-items-reachable",
3902
+ label: "At a ~1024px window the main navbar still reaches 'Home' and 'Products' — they are not cut off past the left edge",
3903
+ description: "Fixed 2026-10-15. BEFORE: the nav strip was a horizontal scroller centred with `justify-center`. When flex content overflows a centred container the overflow splits across BOTH ends, and the leading half cannot be scrolled to because scrollLeft stops at 0. Measured at 1024px: 14 items needing 1245px in a 990px strip put 'Home' at x=-238 and 'Products' at x=-148, with scrollLeft already 0 — permanently unreachable. AFTER: set the window to roughly 1024px wide and look at the navbar. 'Home' must be the first visible item at the left edge. Scroll the strip right and confirm 'About Us' is reachable too.",
3904
+ href: "/products",
3905
+ },
3906
+ {
3907
+ key: "main-nav-left-chevron-works",
3908
+ label: "After scrolling the navbar right, the left chevron appears and scrolls it back to 'Home'",
3909
+ description: "The chevron existed before the fix but could never appear: it is shown when scrollLeft > 0, and scrollLeft was pinned at 0 by the centring — so the control built for exactly this problem was disabled by the problem. Scroll the nav strip to the right, confirm a left chevron appears, click it, and confirm the strip scrolls back and 'Home' becomes visible.",
3910
+ href: "/products",
3911
+ },
3912
+ {
3913
+ key: "header-hamburger-reachable-at-320",
3914
+ label: "At a 320px-wide window the hamburger (Open menu) is fully visible and tappable in the header",
3915
+ description: "Fixed 2026-10-15. BEFORE: the header action row ran 64px past a 320px viewport and the app shell clips horizontal overflow, so the excess was not scrollable — it was gone. 'Open menu' sat entirely off-screen and the theme toggle was sliced in half. AFTER: narrow the window to 320px (or use an iPhone SE profile). The hamburger must be fully visible at the end of the header row and must open the menu when tapped. The theme toggle beside it must also be whole, not clipped.",
3916
+ href: "/products",
3917
+ },
3918
+ {
3919
+ key: "header-demotes-optional-controls",
3920
+ label: "At 320px the 'Today's Deals' and product-tour icons are hidden from the header, and both reappear on a wider screen",
3921
+ description: "This is how the hamburger was given room — the two most discretionary controls step aside at the narrowest width rather than the most important one falling off. At 320px confirm neither icon is in the header. Widen past ~640px and confirm both come back. Neither is lost at 320px: both remain reachable from the menu the hamburger opens.",
3922
+ href: "/products",
3923
+ },
3924
+ {
3925
+ key: "no-horizontal-page-scroll",
3926
+ label: "No page scrolls sideways at 320px — the whole layout fits the viewport width",
3927
+ description: "A horizontal scrollbar on a phone is the single clearest sign of a broken responsive layout. At 320px, visit the homepage, /products, a product detail page, /categories and /cart. On each, try to drag the page sideways: nothing should move, and no horizontal scrollbar should appear at the bottom of the window.",
3928
+ href: "/",
3929
+ },
3930
+ {
3931
+ key: "lightbox-thumbnails-reachable",
3932
+ label: "In the image lightbox, the FIRST thumbnail is reachable when a gallery has many images",
3933
+ description: "Same defect as the navbar, same fix — the thumbnail strip was a centred flex scroller, so with enough images the leading thumbnails were off the left edge with no way to scroll to them. Open a product with several images, click the main image to open the lightbox, and confirm the thumbnail strip starts at its first image and that every thumbnail can be reached by scrolling the strip.",
3934
+ href: "/products",
3935
+ },
3936
+ ],
3937
+ },
3938
+ {
3939
+ pageKey: "action-bar-placement",
3940
+ pageLabel: "Action Bar & Back-to-Top — Desktop vs Mobile",
3941
+ href: "/products",
3942
+ cases: [
3943
+ {
3944
+ key: "back-to-top-dismiss-visible",
3945
+ label: "The small ✕ beside the back-to-top button actually shows a ✕ — not an empty outlined pill",
3946
+ description: "Fixed 2026-10-15. BEFORE: the dismiss control was a `<Button size=\"sm\">` forced to 24px wide, but that size carries 12px of padding on each side — so the content box was exactly 0px and the ✕ glyph shrank to nothing. The button was there and clickable; the icon was invisible. AFTER: scroll any long page past ~400px. Two round controls appear in the corner: a large one with an up-chevron, and a small one with a clearly visible ✕. Clicking the ✕ hides both until you navigate to another page.",
3947
+ href: "/products",
3948
+ },
3949
+ {
3950
+ key: "action-bar-top-on-desktop",
3951
+ label: "ON DESKTOP (window wider than ~1024px): the page action bar sits directly UNDER the header, not welded to the bottom of the window",
3952
+ description: "Changed 2026-10-15. BEFORE: the same full-width bar was pinned to the bottom edge on every screen size — a mobile pattern on a desktop window, where it reads as a browser download bar and sits as far from the content as possible. AFTER: maximise the window and open a product detail page (or any admin list and tick a row to enter bulk mode). The bar must appear immediately below the site header, full width, with its shadow falling DOWNWARD onto the page.",
3953
+ href: "/products",
3954
+ },
3955
+ {
3956
+ key: "action-bar-bottom-on-mobile",
3957
+ label: "ON MOBILE (narrow window): the same action bar is still at the BOTTOM, stacked directly above the bottom tab bar",
3958
+ description: "The other half of the change, and the real regression risk — the two layouts share one component. Narrow the browser to phone width (or use device emulation) on the same page. The bar must be at the bottom, immediately above the bottom navigation, with its shadow falling UPWARD. Resize the window slowly across the ~1024px line both ways: the bar must move cleanly between the two positions and never appear in both places or in neither.",
3959
+ href: "/products",
3960
+ },
3961
+ {
3962
+ key: "action-bar-no-content-overlap",
3963
+ label: "ON DESKTOP: the top action bar never covers the first rows of page content, and leaves no empty gap when it is absent",
3964
+ description: "The bar is fixed, so the page reserves space for it. Two checks. (1) With the bar showing, the first heading/row of content must be fully readable, not hidden behind it. (2) On a page with NO action bar, there must be no blank band under the header — the reservation collapses to zero when nothing is published.",
3965
+ href: "/products",
3966
+ },
3967
+ {
3968
+ key: "action-bar-panels-open-into-screen",
3969
+ label: "Expandable panels on the action bar open INTO the screen — downward on desktop, upward on mobile",
3970
+ description: "On desktop, open an admin list, tick two rows to enter bulk mode, then open the action-type picker: it must expand DOWNWARD over the page. Repeat at phone width: it must expand UPWARD. A panel that opens off-screen is unusable, and the direction has to follow whichever edge the bar is attached to.",
3971
+ href: "/admin/products",
3972
+ },
3973
+ {
3974
+ key: "back-to-top-clears-the-bar",
3975
+ label: "The back-to-top button never overlaps the action bar or the bottom tab bar at any window width",
3976
+ description: "On mobile the button floats above whatever is stacked at the bottom edge; on desktop the bar is at the top so the button should sit lower. Scroll a long page at phone width with an action bar showing — the button must sit clear above it. Widen to desktop: the button must move down as the bottom tier empties, with no overlap at any point during the resize.",
3977
+ href: "/products",
3978
+ },
3979
+ ],
3980
+ },
3981
+ {
3982
+ pageKey: "feature-badge-picker",
3983
+ pageLabel: "Feature Badges — Searchable Picker",
3984
+ href: "/store/products",
3985
+ cases: [
3986
+ {
3987
+ key: "features-are-searchable",
3988
+ label: "The product form's Feature badges control is a SEARCHABLE dropdown, not a long grid of checkboxes",
3989
+ description: "Changed 2026-10-15. BEFORE: every eligible badge rendered as a bordered checkbox tile in a two-column grid — a wall a seller had to read end-to-end, which grew every time an admin added a badge. AFTER: as a seller, open any product for editing and find 'Feature badges'. It must be a single control that opens a searchable list. Type part of a badge name and confirm the list narrows.",
3990
+ href: "/store/products",
3991
+ },
3992
+ {
3993
+ key: "features-search-matches-description",
3994
+ label: "Searching the badge picker matches a badge's DESCRIPTION, not only its name",
3995
+ description: "The description is folded into each option so it stays searchable. Open the picker and type a word that appears only in a badge's description (e.g. 'factory', which is in Sealed's description but not its label). That badge must still appear in the filtered list.",
3996
+ href: "/store/products",
3997
+ },
3998
+ {
3999
+ key: "features-scope-is-visible",
4000
+ label: "Each badge option says whether it is a platform badge or one of your own store's",
4001
+ description: "The old grid showed two separate headings. A flat searchable list has none, so the scope rides in the option text — every option must end with '(platform)' or '(your store)', and the selected chips must keep that distinction too.",
4002
+ href: "/store/products",
4003
+ },
4004
+ {
4005
+ key: "features-respects-the-cap",
4006
+ label: "Selecting more than the allowed number of badges is prevented, and an over-limit product loads without blocking save",
4007
+ description: "Select badges until you hit the stated limit ('Selected: N of 24'), then try to select one more — the selection must not exceed the cap. This replaced a mechanism that disabled every unticked checkbox at the limit, so confirm the control still communicates that you are full rather than silently ignoring clicks.",
4008
+ href: "/store/products",
4009
+ },
4010
+ {
4011
+ key: "features-inline-create",
4012
+ label: "A seller can create a NEW store badge from inside the picker, and it is immediately selectable",
4013
+ description: "Added 2026-10-15. As a seller, open the badge picker and use 'Create a badge for my store'. Fill in a label and icon and submit. The drawer must close, the new badge must appear as a selected chip, and reopening the picker must list it as a real option marked '(your store)' — not a one-off chip that disappears on reload. Reload the page and confirm it persisted.",
4014
+ href: "/store/products",
4015
+ },
4016
+ ],
4017
+ },
3895
4018
  {
3896
4019
  pageKey: "rich-text-readability",
3897
4020
  pageLabel: "Admin-Authored Rich Text — Readability in Both Themes",