Skip to content

fix(bricks): natural-sort palette so -50 lands before -500 + reBEMer design refinements - #129

Merged
jackgranatowski merged 2 commits into
mainfrom
fix/natural-sort-color-palette
May 27, 2026
Merged

fix(bricks): natural-sort palette so -50 lands before -500 + reBEMer design refinements#129
jackgranatowski merged 2 commits into
mainfrom
fix/natural-sort-color-palette

Conversation

@kiro-agent

@kiro-agent kiro-agent Bot commented May 27, 2026

Copy link
Copy Markdown

This pull request was created by @kiro-agent on behalf of @jackgranatowski 👻

Comment with /kiro fix to address specific feedback or /kiro all to address everything.
Learn about Kiro autonomous agent


What

Two related changes from this design-review pass:

1. Bug fix: Bricks color palette ordering

Shades were rendering in lexicographic order, so primary-50 landed between primary-400 and primary-500 instead of right after the base color. Same issue affected alpha shades (a5 after a40) and any other numeric-suffix token (space-2 after space-10, etc.).

Fix: every CSS-name sort now uses SORT_NATURAL | SORT_FLAG_CASE so numeric suffixes order intuitively.

Five sites in three files:

  • integrations/bricks/includes/class-css-parser.php (variables, class names)
  • integrations/bricks/includes/class-inventory.php (sanitize_inventory, two in get_variables_by_category)
  • scripts/gen-bricks-inventory.js (generator + regenerated output for a clean diff)

The PHP sort is what feeds Bricks' Color Manager, so that alone fixes the user-visible bug. The JS generator is updated in lockstep so the committed fallback inventory.json reads in the same order — purely cosmetic, since sanitize_inventory() always re-sorts on read.

Before / After (primary shades):

- primary, primary-100, primary-200, primary-300, primary-400, primary-50, primary-500, ...
+ primary, primary-50, primary-100, primary-200, primary-300, primary-400, primary-500, ...

2. Design refinements added to docs/rebemer.md

v1 design extensions approved in the design-review thread (Auto-BEM parity gaps + one v1.1 candidate):

  • Goal _⚠️ Potential issue_ | _🟠 Major_ | _🏗️ Heavy lift_ #9: element-aware row pre-fills, sibling auto-numbering, per-row skip toggle (without breaking apply atomicity)
  • §6.2: skip-toggle column documented in the panel sketch
  • §6.3: migrate-mode preview chip strip
  • §7.1 / 7.2: new lib/element-types.js module + tests
  • §9: Operation gains skip and suggestedFrom fields
  • §9.2: sibling auto-numbering rule (plan-local, excludes skipped, never overrides user-typed names)
  • §9.3: element-type pre-fill + provenance tracking
  • §11.3: nameCollisions entries gain recommendedAction hint (attach / rename / replace) for a one-click "use existing" affordance
  • §20: unused-class read-only report added to v1.1 candidates (Goal Add light theme support and theme application layer #6 stands — never deletes)

Tested

  • php -l clean on both modified PHP files
  • tests/token-api.spec.js still green (independent JS-side sort, snapshot unaffected)
  • Live PHP parser path verified against dist/slashed.optimal.css — primary shades emerge in primary, -50, -100, …, -500, -600, …, -950, -a5, -a10, -a20, … order
  • inventory.json regenerated and diffed: only the expected shade reorderings, no other tokens moved
  • The browser-spec failures observed locally are unrelated (require npx playwright install); they test computed CSS values, not name ordering

Out of scope

  • The JS-side tests/token-api.spec.js and its snapshot were intentionally not changed. That contract is about the set of tokens, not the order — switching it to natural sort would force a noisy snapshot churn for no behavior change.

Summary by CodeRabbit

  • Documentation

    • Updated reBEMer design documentation with expanded v1 behavior details, including i18n/a11y considerations, element-aware naming suggestions, and migration mode UI preview.
  • Chores

    • Improved ordering of design tokens and CSS classes using natural sort (numeric-aware, case-insensitive) for more intuitive presentation across the system.

Review Change Stack

The Bricks color palette dropdown was rendering shades in lexicographic
order, so users saw primary-100, primary-200, ..., primary-50, primary-500,
primary-600 — with -50 stranded between -400 and -500 instead of right
after the base color. Same issue affected alpha shades (a5 after a40)
and any other numeric-suffix token (space-2 after space-10 etc.).

Switch every CSS-name sort to SORT_NATURAL | SORT_FLAG_CASE so numeric
suffixes order intuitively. Five sites in three files:

  - includes/class-css-parser.php (variables, class names)
  - includes/class-inventory.php  (sanitize_inventory, two in
                                   get_variables_by_category)
  - scripts/gen-bricks-inventory.js (generator, regenerated output)

The PHP sort is what feeds Bricks' Color Manager, so this is the only
required change for the user-visible bug. The JS generator is updated
in lockstep so the committed fallback inventory.json reads in the same
order — a cosmetic improvement (sanitize_inventory always re-sorts on
read).

The token-api snapshot test is unaffected: it does its own JS-side
[...names].sort() of declared tokens and compares against the locked
snapshot. Lex-sort there is fine — that contract is about the *set*
of tokens, not the order.

Also extends docs/rebemer.md with the v1 design refinements approved
in design review:

  - Goal #9: element-aware row pre-fills, sibling auto-numbering,
    per-row skip toggle (without breaking apply atomicity)
  - §6.2: skip-toggle column documented in the panel sketch
  - §6.3: migrate-mode preview chip strip
  - §7.1/7.2: new lib/element-types.js module + tests
  - §9: Operation gains skip and suggestedFrom fields
  - §9.2: sibling auto-numbering rule (plan-local, excludes skipped)
  - §9.3: element-type pre-fill + provenance tracking
  - §11.3: nameCollisions entries gain recommendedAction hint
    (attach / rename / replace) for one-click 'use existing'
  - §20: unused-class read-only report added to v1.1 candidates

Co-authored-by: Jack Granatowski <contact@codeslash.net>
@jackgranatowski

Copy link
Copy Markdown
Contributor

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 27, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented May 27, 2026

Copy link
Copy Markdown

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8249ced3-8769-4f53-a025-9f57b12eeca7

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR introduces reBEMer v1 design refinements covering skip/include UI semantics and element-aware naming, plus standardizes Bricks inventory token and class ordering to natural-case sorting across the generation pipeline and output JSON.

Changes

reBEMer v1 Design Document

Layer / File(s) Summary
UI Design and Skip/Include Semantics
docs/rebemer.md
Goals expanded to include i18n/a11y and element-aware pre-filling; structure panel layout updated to show per-row include/skip toggles with preview area; skip toggle semantics define that skipped rows remain visible but produce no mutations and are excluded from preflight counting and auto-numbering collision tracking.
Migrate-mode Preview Behavior
docs/rebemer.md
Migrate-mode preview chips display which element-settings keys will be migrated, with hover tooltips showing allowlist/denylist surfacing and visual indicators for blocked settings.
Architecture: element-types Module Design
docs/rebemer.md
New pure module element-types.js maps Bricks element types to BEM element labels with PHP-filterable mapping; module structure documented in editor-app layout; unit test module element-types.test.js added.
Plan Model Extensions and buildPlan Logic
docs/rebemer.md
Plan.Operation extended with skip field (non-mutating recorded rows) and suggestedFrom provenance tags; buildPlan behaviors detailed for sibling auto-numbering (with skip exclusions and collision handling), element-type pre-fill using element-types.suggestElementName, and provenance-based UI rendering of suggestions.
Preflight API Contract and Future Extensions
docs/rebemer.md
REST preflight nameCollisions response strengthened with recommendedAction field (attach, rename, replace) marked as advisory; proposed open-question candidate for read-only GET /rebemer/unused endpoint reporting unused global classes with reference-count sharing and capability checks.

Natural-case Sorting Standardization for Bricks Inventory

Layer / File(s) Summary
Natural Sort Implementation in Parser, Inventory, and Generator
integrations/bricks/includes/class-css-parser.php, integrations/bricks/includes/class-inventory.php, scripts/gen-bricks-inventory.js
Slashed_Bricks_CSS_Parser extraction methods now apply SORT_NATURAL | SORT_FLAG_CASE to de-duplicated variables and class names; Slashed_Bricks_Inventory normalization and category grouping similarly apply natural, case-insensitive sorting; gen-bricks-inventory.js introduces naturalCompare helper implementing numeric-aware ordering and applies it to token and class extraction output.
Generated Inventory Data Reordering
integrations/bricks/data/inventory.json
Color token entries across six color groups and opacity variables reordered to natural-sort order (numeric suffixes like -50, -100, -950 grouped in expected sequence); sf_classes entries reordered with sf-cover__center positioned earlier per natural sorting.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • codeslash-dev/SLASHED#81: Both PRs modify the Bricks inventory generation pipeline (class-css-parser.php, class-inventory.php, gen-bricks-inventory.js) to change sorting behavior within the same extraction and sanitization logic.
  • codeslash-dev/SLASHED#83: Main PR's natural-case sorting updates to Slashed_Bricks_CSS_Parser, Slashed_Bricks_Inventory, and gen-bricks-inventory.js build on the inventory-driven architecture introduced in PR #83.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main changes: a bug fix for natural-sort palette ordering and reBEMer design refinements. It is concise, specific, and clearly summarizes the primary changes across the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/natural-sort-color-palette

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
scripts/gen-bricks-inventory.js (1)

49-49: ⚡ Quick win

Pin the comparator locale/collator for deterministic generated inventory ordering.

localeCompare with an undefined locale relies on the runtime/host default locale, which can vary across environments and lead to diff churn; use a single explicit Intl.Collator and reuse its .compare.

Proposed diff
-const naturalCompare = (a, b) => a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' });
+const naturalCompare = new Intl.Collator('en', {
+  numeric: true,
+  sensitivity: 'base',
+}).compare;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/gen-bricks-inventory.js` at line 49, The comparator naturalCompare
currently calls a.localeCompare with an undefined locale which makes ordering
platform-dependent; replace it by instantiating a single explicit Intl.Collator
(e.g., new Intl.Collator('en', { numeric: true, sensitivity: 'base' })) and
reuse its .compare method for naturalCompare so the generated inventory ordering
is deterministic; ensure the collator is created once (module scope) and that
naturalCompare references collator.compare.
docs/rebemer.md (1)

176-176: ⚡ Quick win

Simplify redundant phrasing.

The phrase "lifted up into" is redundant. Consider "lifted into" or "moved into" for clearer, more concise documentation.

📝 Suggested simplification
-chip strip listing the element-settings keys (and a hover tooltip with
-their values) that will be lifted up into the new class. Drawn from
+chip strip listing the element-settings keys (and a hover tooltip with
+their values) that will be lifted into the new class. Drawn from
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/rebemer.md` at line 176, Replace the redundant phrase "lifted up into"
(found in the docs line containing "their values) that will be lifted up into
the new class. Drawn from") with a concise alternative such as "lifted into" or
"moved into"; update the sentence to read e.g. "that will be moved into the new
class" and ensure surrounding punctuation and capitalization remain correct.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/rebemer.md`:
- Around line 179-180: The phrase "on the allowlist denylist" in docs/rebemer.md
(near the §12 reference "Bricks introducing a new style key") is ambiguous;
update that sentence to use a single clear term — replace "on the allowlist
denylist" with "on the denylist" (or "not on the allowlist" if the intent is
absence from the allowlist) so it unambiguously conveys blocked settings; find
the sentence containing that phrase and make the replacement to match the
surrounding discussion of surfacing blocked settings.

---

Nitpick comments:
In `@docs/rebemer.md`:
- Line 176: Replace the redundant phrase "lifted up into" (found in the docs
line containing "their values) that will be lifted up into the new class. Drawn
from") with a concise alternative such as "lifted into" or "moved into"; update
the sentence to read e.g. "that will be moved into the new class" and ensure
surrounding punctuation and capitalization remain correct.

In `@scripts/gen-bricks-inventory.js`:
- Line 49: The comparator naturalCompare currently calls a.localeCompare with an
undefined locale which makes ordering platform-dependent; replace it by
instantiating a single explicit Intl.Collator (e.g., new Intl.Collator('en', {
numeric: true, sensitivity: 'base' })) and reuse its .compare method for
naturalCompare so the generated inventory ordering is deterministic; ensure the
collator is created once (module scope) and that naturalCompare references
collator.compare.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ed6a7dde-57cd-45b3-b67c-072dc90ed427

📥 Commits

Reviewing files that changed from the base of the PR and between f0d07bb and f19f848.

📒 Files selected for processing (5)
  • docs/rebemer.md
  • integrations/bricks/data/inventory.json
  • integrations/bricks/includes/class-css-parser.php
  • integrations/bricks/includes/class-inventory.php
  • scripts/gen-bricks-inventory.js

Comment thread docs/rebemer.md Outdated
Comment on lines +179 to +180
when a setting *would* be migrated but is on the allowlist denylist
(see §12 threat-model entry "Bricks introducing a new style key").

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Clarify "allowlist denylist" phrasing.

The phrase "on the allowlist denylist" is confusing — a key cannot be on both simultaneously. Based on the context (surfacing blocked settings), this should likely read "on the denylist" or "not on the allowlist."

📝 Suggested fix
-when a setting *would* be migrated but is on the allowlist denylist
+when a setting *would* be migrated but is on the denylist

Or, if the intent is to describe absence from the allowlist:

-when a setting *would* be migrated but is on the allowlist denylist
+when a setting *would* be migrated but is not on the allowlist
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
when a setting *would* be migrated but is on the allowlist denylist
(see §12 threat-model entry "Bricks introducing a new style key").
when a setting *would* be migrated but is on the denylist
(see §12 threat-model entry "Bricks introducing a new style key").
Suggested change
when a setting *would* be migrated but is on the allowlist denylist
(see §12 threat-model entry "Bricks introducing a new style key").
when a setting *would* be migrated but is not on the allowlist
(see §12 threat-model entry "Bricks introducing a new style key").
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/rebemer.md` around lines 179 - 180, The phrase "on the allowlist
denylist" in docs/rebemer.md (near the §12 reference "Bricks introducing a new
style key") is ambiguous; update that sentence to use a single clear term —
replace "on the allowlist denylist" with "on the denylist" (or "not on the
allowlist" if the intent is absence from the allowlist) so it unambiguously
conveys blocked settings; find the sentence containing that phrase and make the
replacement to match the surrounding discussion of surfacing blocked settings.

@jackgranatowski

Copy link
Copy Markdown
Contributor

/kiro all

CodeRabbit correctly flagged the contradictory 'on the allowlist
denylist' wording — a key can't be on both simultaneously. The intent
is to surface settings that are NOT on the allowlist (i.e. unknown
keys that reBEMer refuses to migrate). Updated to 'not on the
allowlist' for clarity.
@jackgranatowski
jackgranatowski merged commit 692ea16 into main May 27, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants