@arbor-education/design-system.components 0.13.0 → 0.13.1
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/.agent-memory/blanche-designspert/MEMORY.md +189 -0
- package/.agent-memory/dorothy-fact-checker/MEMORY.md +228 -0
- package/.agent-memory/dorothy-fact-checker/numberinput_component.md +53 -0
- package/.agent-memory/dorothy-fact-checker/progress_component.md +36 -0
- package/.agent-memory/rose-storybookspert/MEMORY.md +105 -0
- package/.agent-memory/sophia-componentspert/MEMORY.md +34 -0
- package/{.claude/agent-memory → .agent-memory}/sophia-componentspert/components.md +170 -17
- package/{.claude → .gather}/agents/blanche-designspert.md +7 -2
- package/{.claude → .gather}/agents/dorothy-fact-checker.md +7 -2
- package/{.claude → .gather}/agents/rose-storybookspert.md +80 -11
- package/{.claude → .gather}/agents/sophia-componentspert.md +9 -4
- package/.gather/gather.yaml +9 -0
- package/{CLAUDE.md → .gather/instructions/project-overview.md} +42 -9
- package/{.claude → .gather}/skills/analyze-design/README.md +5 -0
- package/{.claude → .gather}/skills/analyze-design/SKILL.md +1 -1
- package/.gather/skills/analyze-design/meta.md +4 -0
- package/{.claude → .gather}/skills/create-page/README.md +5 -0
- package/{.claude → .gather}/skills/create-page/design-analysis-template.md +5 -0
- package/.gather/skills/create-page/meta.md +4 -0
- package/{.claude → .gather}/skills/create-page/page-template.scss +5 -0
- package/{.claude → .gather}/skills/create-page/page-template.tsx +5 -0
- package/{.claude → .gather}/skills/map-legacy/README.md +5 -0
- package/.gather/skills/map-legacy/meta.md +4 -0
- package/{.claude → .gather}/skills/migrate-page/README.md +5 -0
- package/.gather/skills/migrate-page/meta.md +4 -0
- package/.gather/skills/write-stories/README.md +157 -0
- package/.gather/skills/write-stories/SKILL.md +841 -0
- package/.gather/skills/write-stories/meta.md +4 -0
- package/.ralph/storybook-upgrade/knowledge.md +308 -0
- package/.ralph/storybook-upgrade/prd.json +777 -0
- package/.ralph/storybook-upgrade/progress.md +342 -0
- package/.storybook/DocsTemplate.tsx +122 -0
- package/.storybook/preview.ts +40 -0
- package/.stylelintignore +2 -0
- package/CHANGELOG.md +6 -0
- package/{.claude/component-library.md → component-library.md} +27 -10
- package/dist/components/badge/Badge.stories.d.ts +85 -6
- package/dist/components/badge/Badge.stories.d.ts.map +1 -1
- package/dist/components/badge/Badge.stories.js +626 -27
- package/dist/components/badge/Badge.stories.js.map +1 -1
- package/dist/components/banner/Banner.stories.d.ts +129 -63
- package/dist/components/banner/Banner.stories.d.ts.map +1 -1
- package/dist/components/banner/Banner.stories.js +855 -39
- package/dist/components/banner/Banner.stories.js.map +1 -1
- package/dist/components/button/Button.stories.d.ts +148 -8
- package/dist/components/button/Button.stories.d.ts.map +1 -1
- package/dist/components/button/Button.stories.js +1089 -80
- package/dist/components/button/Button.stories.js.map +1 -1
- package/dist/components/dot/Dot.stories.d.ts +46 -11
- package/dist/components/dot/Dot.stories.d.ts.map +1 -1
- package/dist/components/dot/Dot.stories.js +504 -15
- package/dist/components/dot/Dot.stories.js.map +1 -1
- package/dist/components/dropdown/Dropdown.stories.d.ts +89 -14
- package/dist/components/dropdown/Dropdown.stories.d.ts.map +1 -1
- package/dist/components/dropdown/Dropdown.stories.js +769 -17
- package/dist/components/dropdown/Dropdown.stories.js.map +1 -1
- package/dist/components/formField/FormField.stories.d.ts +95 -35
- package/dist/components/formField/FormField.stories.d.ts.map +1 -1
- package/dist/components/formField/FormField.stories.js +1174 -69
- package/dist/components/formField/FormField.stories.js.map +1 -1
- package/dist/components/formField/inputs/checkbox/CheckboxInput.stories.d.ts +96 -9
- package/dist/components/formField/inputs/checkbox/CheckboxInput.stories.d.ts.map +1 -1
- package/dist/components/formField/inputs/checkbox/CheckboxInput.stories.js +717 -10
- package/dist/components/formField/inputs/checkbox/CheckboxInput.stories.js.map +1 -1
- package/dist/components/formField/inputs/number/NumberInput.stories.d.ts +149 -11
- package/dist/components/formField/inputs/number/NumberInput.stories.d.ts.map +1 -1
- package/dist/components/formField/inputs/number/NumberInput.stories.js +624 -10
- package/dist/components/formField/inputs/number/NumberInput.stories.js.map +1 -1
- package/dist/components/formField/inputs/radio/RadioButtonInput.stories.d.ts +74 -1
- package/dist/components/formField/inputs/radio/RadioButtonInput.stories.d.ts.map +1 -1
- package/dist/components/formField/inputs/radio/RadioButtonInput.stories.js +673 -44
- package/dist/components/formField/inputs/radio/RadioButtonInput.stories.js.map +1 -1
- package/dist/components/formField/inputs/text/TextInput.stories.d.ts +119 -1
- package/dist/components/formField/inputs/text/TextInput.stories.d.ts.map +1 -1
- package/dist/components/formField/inputs/text/TextInput.stories.js +549 -10
- package/dist/components/formField/inputs/text/TextInput.stories.js.map +1 -1
- package/dist/components/formField/inputs/textArea/TextArea.stories.d.ts +129 -4
- package/dist/components/formField/inputs/textArea/TextArea.stories.d.ts.map +1 -1
- package/dist/components/formField/inputs/textArea/TextArea.stories.js +577 -3
- package/dist/components/formField/inputs/textArea/TextArea.stories.js.map +1 -1
- package/dist/components/heading/Heading.stories.d.ts +449 -50
- package/dist/components/heading/Heading.stories.d.ts.map +1 -1
- package/dist/components/heading/Heading.stories.js +536 -60
- package/dist/components/heading/Heading.stories.js.map +1 -1
- package/dist/components/icon/Icon.stories.d.ts +81 -10
- package/dist/components/icon/Icon.stories.d.ts.map +1 -1
- package/dist/components/icon/Icon.stories.js +979 -8
- package/dist/components/icon/Icon.stories.js.map +1 -1
- package/dist/components/pill/Pill.stories.d.ts +71 -19
- package/dist/components/pill/Pill.stories.d.ts.map +1 -1
- package/dist/components/pill/Pill.stories.js +573 -14
- package/dist/components/pill/Pill.stories.js.map +1 -1
- package/dist/components/progress/Progress.stories.d.ts +75 -298
- package/dist/components/progress/Progress.stories.d.ts.map +1 -1
- package/dist/components/progress/Progress.stories.js +449 -52
- package/dist/components/progress/Progress.stories.js.map +1 -1
- package/dist/components/separator/Separator.stories.d.ts +58 -5
- package/dist/components/separator/Separator.stories.d.ts.map +1 -1
- package/dist/components/separator/Separator.stories.js +443 -4
- package/dist/components/separator/Separator.stories.js.map +1 -1
- package/dist/components/tag/Tag.stories.d.ts +116 -5
- package/dist/components/tag/Tag.stories.d.ts.map +1 -1
- package/dist/components/tag/Tag.stories.js +581 -28
- package/dist/components/tag/Tag.stories.js.map +1 -1
- package/dist/index.css +8 -1
- package/dist/index.css.map +1 -1
- package/eslint.config.mts +5 -1
- package/package.json +3 -3
- package/src/components/badge/Badge.stories.tsx +869 -42
- package/src/components/banner/Banner.stories.tsx +1081 -63
- package/src/components/button/Button.stories.tsx +1394 -99
- package/src/components/dot/Dot.stories.tsx +723 -32
- package/src/components/dropdown/Dropdown.stories.tsx +1174 -35
- package/src/components/formField/FormField.stories.tsx +1522 -105
- package/src/components/formField/inputs/checkbox/CheckboxInput.stories.tsx +1020 -15
- package/src/components/formField/inputs/number/NumberInput.stories.tsx +908 -15
- package/src/components/formField/inputs/radio/RadioButtonInput.stories.tsx +932 -51
- package/src/components/formField/inputs/text/TextInput.stories.tsx +773 -13
- package/src/components/formField/inputs/textArea/TextArea.stories.tsx +756 -8
- package/src/components/heading/Heading.stories.tsx +752 -120
- package/src/components/icon/Icon.stories.tsx +1446 -12
- package/src/components/pill/Pill.stories.tsx +867 -21
- package/src/components/progress/Progress.stories.tsx +625 -58
- package/src/components/separator/Separator.stories.tsx +730 -8
- package/src/components/separator/separator.scss +12 -3
- package/src/components/tag/Tag.stories.tsx +755 -53
- package/.claude/agent-memory/blanche-designspert/MEMORY.md +0 -64
- package/.claude/agent-memory/dorothy-fact-checker/MEMORY.md +0 -129
- package/.claude/agent-memory/rose-storybookspert/MEMORY.md +0 -29
- package/.claude/agent-memory/sophia-componentspert/MEMORY.md +0 -14
- package/.claude/design-assessment-daily-attendance-2026-04-10.md +0 -566
- package/.claude/figma-assessment-7154-58899.md +0 -404
- package/.claude/figma-assessment-UKQfcxnT4rlHHNuiumt4o1-11086-97537.md +0 -392
- package/.claude/figma-assessment-UKQfcxnT4rlHHNuiumt4o1-551-41974.md +0 -474
- package/.claude/figma-assessment-UKQfcxnT4rlHHNuiumt4o1-551-43094.md +0 -462
- package/.claude/figma-assessment-fcFK4CGzkz2fVyY3koX8ZE-7154-59061.md +0 -440
- package/.claude/migration-report-custom-report-writer-2026-02-19.md +0 -591
- /package/{.claude/agent-memory → .agent-memory}/blanche-designspert/token-review-patterns.md +0 -0
- /package/{.claude/agent-memory → .agent-memory}/rose-storybookspert/patterns.md +0 -0
- /package/{.claude → .gather}/skills/create-page/SKILL.md +0 -0
- /package/{.claude → .gather}/skills/map-legacy/SKILL.md +0 -0
- /package/{.claude → .gather}/skills/migrate-page/SKILL.md +0 -0
|
@@ -1,591 +0,0 @@
|
|
|
1
|
-
# Legacy Migration Report
|
|
2
|
-
## Page: Custom Report Writer — All Reports
|
|
3
|
-
**Mapped by:** Sophia Petrillo, Componentspert
|
|
4
|
-
**Verified by:** Dorothy Zbornak, QA Expert
|
|
5
|
-
**Date:** 2026-02-19
|
|
6
|
-
**Screenshot:** `/var/folders/02/6tfvyr9x5t5dlmv4nvpmwy3r0000gp/T/TemporaryItems/NSIRD_screencaptureui_6PJdtv/Screenshot 2026-02-19 at 15.37.35.png`
|
|
7
|
-
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
## TL;DR
|
|
11
|
-
|
|
12
|
-
This page has 21 distinct legacy UI elements. 14 of them have direct Arbor equivalents — a strong result for a complex page. The big wins are the table toolbar (BulkActionsDropdown, HideColumnsDropdown, SearchBar are all built in — you don't write a single line for those) and the data table itself (AG Grid via `Table`). The main gaps are the application shell (top nav, side navs — these are not library problems, they're app-level concerns) and the missing `Breadcrumbs` and `Banner`/`Alert` components, which are worth raising as library tickets.
|
|
13
|
-
|
|
14
|
-
**Migration readiness: 14/21 elements have direct Arbor equivalents**
|
|
15
|
-
|
|
16
|
-
---
|
|
17
|
-
|
|
18
|
-
## Migration Map
|
|
19
|
-
|
|
20
|
-
| # | Legacy Element | Where | Arbor Component | Complexity | Status |
|
|
21
|
-
|---|---|---|---|---|---|
|
|
22
|
-
| 1 | Top navigation bar | App shell | — | 🔴 High | ❌ No equivalent |
|
|
23
|
-
| 2 | Left side nav — icon variant | App shell | — | 🔴 High | ❌ No equivalent |
|
|
24
|
-
| 3 | Left side nav — text variant | App shell | — | 🔴 High | ❌ No equivalent |
|
|
25
|
-
| 4 | Breadcrumbs | Below top nav | — (compose manually) | 🟡 Medium | ❌ No equivalent |
|
|
26
|
-
| 5 | Page heading | Page header | `Heading` | 🟢 Low | ✅ Mappable |
|
|
27
|
-
| 6 | "Create New Report" button | Page header | `Button` variant="primary" | 🟢 Low | ✅ Mappable |
|
|
28
|
-
| 7 | Warning/alert banner | Below header | — (compose manually) | 🟡 Medium | ❌ No equivalent |
|
|
29
|
-
| 8 | Filter status indicator | Above tabs | `Table.RowCountInfo` + `Button` | 🟡 Medium | ✅ Mappable (with caveats) |
|
|
30
|
-
| 9 | Tab bar (Active/Archived/Expired) | Above table | `Tabs` + `Tabs.Item` | 🟢 Low | ✅ Mappable |
|
|
31
|
-
| 10 | Download split/dropdown button | Table toolbar | `Button` + `Dropdown` | 🟡 Medium | ✅ Mappable (not true split) |
|
|
32
|
-
| 11 | "Schedule" toolbar button | Table toolbar | `Button` variant="secondary" | 🟢 Low | ✅ Mappable |
|
|
33
|
-
| 12 | Bulk action dropdown | Table toolbar | `Table.BulkActionsDropdown` | 🟢 Low | ✅ Mappable |
|
|
34
|
-
| 13 | Hide columns dropdown | Table toolbar | `Table.HideColumnsDropdown` | 🟢 Low | ✅ Mappable |
|
|
35
|
-
| 14 | Table search input | Table toolbar | Built into `Table` (hasSearch=true) | 🟢 Low | ✅ Mappable |
|
|
36
|
-
| 15 | Icon-only toolbar buttons | Table toolbar | `Button` icon-only + `TooltipWrapper` | 🟢 Low | ✅ Mappable |
|
|
37
|
-
| 16 | Data table | Main content | `Table` (AG Grid Enterprise) | 🔴 High | ✅ Mappable (migration work) |
|
|
38
|
-
| 17 | Row checkboxes | Table | AG Grid ColDef | 🟢 Low | ✅ Mappable |
|
|
39
|
-
| 18 | Link text in table cells | Table — Title col | Custom `cellRenderer` | 🟡 Medium | ✅ Mappable |
|
|
40
|
-
| 19 | Type indicator (icon + text) | Table — Type col | Custom `cellRenderer` with `Icon` | 🟡 Medium | ✅ Mappable |
|
|
41
|
-
| 20 | Sortable column headers | Table | AG Grid ColDef `sortable: true` | 🟢 Low | ✅ Mappable |
|
|
42
|
-
| 21 | Overflow menu per row | Table — last col | `Dropdown` + `Button` in `cellRenderer` | 🟡 Medium | ✅ Mappable |
|
|
43
|
-
|
|
44
|
-
---
|
|
45
|
-
|
|
46
|
-
## Element-by-Element Breakdown
|
|
47
|
-
|
|
48
|
-
Before we start: picture it — Sicily, 1952. My father needed to move from the old stone farmhouse to the new one in town. Every piece of furniture had to be mapped — "does the old bed fit in the new room? Does the old table go in the corner?" He didn't just grab random things and hope they fit. He measured. He thought. He used his head. That is what we are going to do here, you and I, right now. Not one guess in this report. Dorothy read every source file.
|
|
49
|
-
|
|
50
|
-
---
|
|
51
|
-
|
|
52
|
-
### 1–3. Top Navigation Bar / Left Icon Nav / Left Text Nav
|
|
53
|
-
|
|
54
|
-
Let me be clear about something before anything else: **items 1, 2, and 3 are application shell components.** This library builds UI primitives for page content, not full application navigation frames. You are on your own for those three, or you are building them custom.
|
|
55
|
-
|
|
56
|
-
**Top navigation bar:**
|
|
57
|
-
The `Icon` component exists for the individual icons inside it, and `Button` works for the "Ask Arbor" button — there is even a custom icon for it at `src/components/icon/customIcons/AskArbor.tsx`, the icon name is `'ask-arbor'`. So:
|
|
58
|
-
|
|
59
|
-
```tsx
|
|
60
|
-
<Button variant="secondary" iconLeftName="ask-arbor">Ask Arbor</Button>
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
The dropdown menus in the nav can each be a `Dropdown` + `Dropdown.Trigger` + `Dropdown.Content` + `Dropdown.Item`. But the dark container shell itself? That is yours to build.
|
|
64
|
-
|
|
65
|
-
**Left icon nav rail:**
|
|
66
|
-
Individual icon items can be composed like this — and always wrap them in a `TooltipWrapper`, I am not negotiating on this:
|
|
67
|
-
|
|
68
|
-
```tsx
|
|
69
|
-
<TooltipWrapper tooltipContent="Home">
|
|
70
|
-
<Button variant="tertiary" iconLeftName="house" iconLeftScreenReaderText="Home" />
|
|
71
|
-
</TooltipWrapper>
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
Available icons: `'house'` (Home), `'star'` (Favourites), `'bell'` (Notifications), `'circle-help'` (Help), `'log-out'` (Sign Out).
|
|
75
|
-
|
|
76
|
-
**Left text nav:**
|
|
77
|
-
The `Section` component is for page sections with white card backgrounds. **Do not try to use it as a nav sidebar.** I have seen people try. It ends badly. Individual link items can use `Button variant="text-link"`, and `Separator` can divide sections. But the sidebar container with active state highlighting? Custom build.
|
|
78
|
-
|
|
79
|
-
**Recommendation:** Build dedicated `TopNav`, `SideNavIcons`, and `SideNavText` components at app level, using Arbor's `Button`, `Dropdown`, `Icon`, `TooltipWrapper`, and `Separator` primitives inside them.
|
|
80
|
-
|
|
81
|
-
_(Dorothy verified: confirmed — no navigation shell components exist in the library)_
|
|
82
|
-
|
|
83
|
-
---
|
|
84
|
-
|
|
85
|
-
### 4. Breadcrumbs
|
|
86
|
-
|
|
87
|
-
No `Breadcrumbs` component exists in the library. But this one you can compose in twenty minutes. The key rule is: **the current page item should NOT be a link** — mark it with `aria-current="page"`. This is standard accessibility practice, not optional.
|
|
88
|
-
|
|
89
|
-
```tsx
|
|
90
|
-
<nav aria-label="Breadcrumb">
|
|
91
|
-
<ol className="ds-custom-report-writer__breadcrumbs">
|
|
92
|
-
<li>
|
|
93
|
-
<Button variant="text-link" onClick={() => navigate('/school')}>School</Button>
|
|
94
|
-
</li>
|
|
95
|
-
<li aria-hidden="true">
|
|
96
|
-
<Icon name="chevron-right" size={14} />
|
|
97
|
-
</li>
|
|
98
|
-
<li aria-current="page">Custom Report Writer</li>
|
|
99
|
-
</ol>
|
|
100
|
-
</nav>
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
**Feature gaps:** No built-in truncation, no library-standard styling. If breadcrumbs appear on more than this page, raise a library ticket for a `Breadcrumbs` component — it is worth standardising.
|
|
104
|
-
|
|
105
|
-
_(Dorothy verified: confirmed — no Breadcrumbs component in src/index.ts)_
|
|
106
|
-
|
|
107
|
-
---
|
|
108
|
-
|
|
109
|
-
### 5. Page Heading — "Custom Report Writer - All Reports"
|
|
110
|
-
|
|
111
|
-
**Arbor replacement:** `Heading` (`src/components/heading/Heading.tsx`)
|
|
112
|
-
**Migration complexity:** 🟢 Low
|
|
113
|
-
|
|
114
|
-
Direct swap. The `level` prop defaults to 1 if you don't specify it.
|
|
115
|
-
|
|
116
|
-
```tsx
|
|
117
|
-
<Heading level={1}>Custom Report Writer - All Reports</Heading>
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
If the heading needs right-side content (like the "Create New Report" button beside it), use `Heading.InnerContainer`:
|
|
121
|
-
|
|
122
|
-
```tsx
|
|
123
|
-
<Heading level={1}>
|
|
124
|
-
<Heading.InnerContainer>Custom Report Writer - All Reports</Heading.InnerContainer>
|
|
125
|
-
<Heading.InnerContainer>
|
|
126
|
-
<Button variant="primary" onClick={onCreateNewReport}>Create New Report</Button>
|
|
127
|
-
</Heading.InnerContainer>
|
|
128
|
-
</Heading>
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
_(Dorothy verified: confirmed — `Heading` exists, exported from `src/index.ts`, `Heading.InnerContainer` pattern confirmed in source)_
|
|
132
|
-
|
|
133
|
-
---
|
|
134
|
-
|
|
135
|
-
### 6. "Create New Report" Primary CTA Button
|
|
136
|
-
|
|
137
|
-
**Arbor replacement:** `Button` variant="primary" (`src/components/button/Button.tsx`)
|
|
138
|
-
**Migration complexity:** 🟢 Low
|
|
139
|
-
|
|
140
|
-
```tsx
|
|
141
|
-
<Button variant="primary" onClick={onCreateNewReport}>
|
|
142
|
-
Create New Report
|
|
143
|
-
</Button>
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
**Important:** Do NOT pass `type="submit"` — the `type` prop is intentionally Omitted from `ButtonProps` (`Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'type' | 'onClick'>`). If you need an icon, use `iconLeftName` — e.g. `iconLeftName="plus"`.
|
|
147
|
-
|
|
148
|
-
_(Dorothy verified: confirmed — `type` is indeed Omitted from ButtonProps. `variant="primary"` confirmed. `iconLeftName` confirmed.)_
|
|
149
|
-
|
|
150
|
-
---
|
|
151
|
-
|
|
152
|
-
### 7. Warning/Alert Banner — "Expired Reports"
|
|
153
|
-
|
|
154
|
-
There is no dedicated `Alert`, `Banner`, or `Notification` component in this library. This is a genuine gap worth raising as a ticket — warning/info/success/error contextual page banners are universally needed.
|
|
155
|
-
|
|
156
|
-
For now, compose it:
|
|
157
|
-
|
|
158
|
-
```tsx
|
|
159
|
-
<aside className="ds-custom-report-writer__warning-banner" role="alert">
|
|
160
|
-
<Icon name="triangle-alert" size={20} screenReaderText="Warning" />
|
|
161
|
-
<div className="ds-custom-report-writer__warning-banner-content">
|
|
162
|
-
<strong>Expired Reports</strong>
|
|
163
|
-
<p>Your description text here.</p>
|
|
164
|
-
</div>
|
|
165
|
-
<Button variant="secondary" size="S" onClick={onFixExpiredFilters}>
|
|
166
|
-
Fix Expired Filters
|
|
167
|
-
</Button>
|
|
168
|
-
</aside>
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
**SCSS using design tokens:**
|
|
172
|
-
```scss
|
|
173
|
-
.ds-custom-report-writer__warning-banner {
|
|
174
|
-
display: flex;
|
|
175
|
-
align-items: center;
|
|
176
|
-
gap: var(--spacing-medium);
|
|
177
|
-
padding: var(--spacing-medium);
|
|
178
|
-
background: var(--color-warning-050);
|
|
179
|
-
border: 1px solid var(--color-warning-300);
|
|
180
|
-
border-radius: var(--border-radius-small);
|
|
181
|
-
}
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
**Feature gaps:** No dismiss behaviour, no standardised variant system. Raise a `Banner` ticket.
|
|
185
|
-
|
|
186
|
-
_(Dorothy verified: confirmed — no Alert/Banner component exists in the library)_
|
|
187
|
-
|
|
188
|
-
---
|
|
189
|
-
|
|
190
|
-
### 8. Filter Status Indicator — "Showing all results" + "Change" link
|
|
191
|
-
|
|
192
|
-
**Arbor replacement:** `Table.RowCountInfo` + `Icon` + `Button` variant="text-link"
|
|
193
|
-
**Migration complexity:** 🟡 Medium
|
|
194
|
-
|
|
195
|
-
`Table.RowCountInfo` reads from `GridApiContext` and renders "Showing N results" or "Showing N of M results" automatically. **It can only live inside a `Table`** — it uses `GridApiContext` internally, so you cannot use it standalone outside a Table. Place it in `headerContent` or `footerContent`.
|
|
196
|
-
|
|
197
|
-
```tsx
|
|
198
|
-
<Table
|
|
199
|
-
rowData={reports}
|
|
200
|
-
columnDefs={columnDefs}
|
|
201
|
-
headerContent={
|
|
202
|
-
<div className="ds-custom-report-writer__filter-status">
|
|
203
|
-
<Icon name="funnel" size={16} />
|
|
204
|
-
<Table.RowCountInfo />
|
|
205
|
-
<Button variant="text-link" onClick={onChangeFilters}>Change</Button>
|
|
206
|
-
</div>
|
|
207
|
-
}
|
|
208
|
-
/>
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
**For server-side filtering:** Pass a `totalRows` prop to `Table.RowCountInfo` to supply the external row count. "Showing all results" vs "Showing filtered results" label is not auto-generated in server-side mode — manage that text yourself.
|
|
212
|
-
|
|
213
|
-
_(Dorothy verified: confirmed — `Table.RowCountInfo` exists, uses GridApiContext, `totalRows` prop confirmed in RowCountInfo source)_
|
|
214
|
-
|
|
215
|
-
---
|
|
216
|
-
|
|
217
|
-
### 9. Tab Bar — Active / Archived / Expired
|
|
218
|
-
|
|
219
|
-
**Arbor replacement:** `Tabs` + `Tabs.Item`
|
|
220
|
-
**Migration complexity:** 🟢 Low
|
|
221
|
-
|
|
222
|
-
Picture it: Sicily, 1948. We had three buckets — one for bread, one for olives, one for wine. You knew exactly which bucket was "active" because it had a cloth on it. That is all tabs are. Controlled active state, mutually exclusive. This is a direct swap.
|
|
223
|
-
|
|
224
|
-
`Tabs` is **controlled** — you must manage which tab is active in parent state yourself. `Tabs.Item` renders semantic `<li role="presentation">` → `<button role="tab" aria-selected={active}>`. Fully accessible out of the box.
|
|
225
|
-
|
|
226
|
-
```tsx
|
|
227
|
-
const [activeTab, setActiveTab] = useState<'active' | 'archived' | 'expired'>('active');
|
|
228
|
-
|
|
229
|
-
<Tabs>
|
|
230
|
-
<Tabs.Item
|
|
231
|
-
active={activeTab === 'active'}
|
|
232
|
-
tabElementProps={{ onClick: () => setActiveTab('active') }}
|
|
233
|
-
>
|
|
234
|
-
Active
|
|
235
|
-
</Tabs.Item>
|
|
236
|
-
<Tabs.Item
|
|
237
|
-
active={activeTab === 'archived'}
|
|
238
|
-
tabElementProps={{ onClick: () => setActiveTab('archived') }}
|
|
239
|
-
>
|
|
240
|
-
Archived
|
|
241
|
-
</Tabs.Item>
|
|
242
|
-
<Tabs.Item
|
|
243
|
-
active={activeTab === 'expired'}
|
|
244
|
-
tabElementProps={{ onClick: () => setActiveTab('expired') }}
|
|
245
|
-
>
|
|
246
|
-
Expired
|
|
247
|
-
</Tabs.Item>
|
|
248
|
-
</Tabs>
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
**Link mode:** If any of these tabs navigate to different URLs rather than switching panels in-place, pass `tabElement='link'` and use `tabElementProps` with anchor attributes (`href`, etc.) instead of an `onClick`.
|
|
252
|
-
|
|
253
|
-
_(Dorothy verified: confirmed — `Tabs` and `TabsItem` exist, `active` prop confirmed, `tabElementProps` confirmed, `tabElement='link'` confirmed, accessible HTML structure confirmed)_
|
|
254
|
-
|
|
255
|
-
---
|
|
256
|
-
|
|
257
|
-
### 10. Download Split/Dropdown Button
|
|
258
|
-
|
|
259
|
-
**Arbor replacement:** `Button` variant="dropdown" + `Dropdown`
|
|
260
|
-
**Migration complexity:** 🟡 Medium
|
|
261
|
-
|
|
262
|
-
`Dropdown.Trigger` uses Radix UI's `asChild` — it must receive a single `React.ReactElement` child. The `download` icon (`name="download"`) is available if you want it.
|
|
263
|
-
|
|
264
|
-
```tsx
|
|
265
|
-
<Dropdown>
|
|
266
|
-
<Dropdown.Trigger>
|
|
267
|
-
<Button variant="dropdown" iconLeftName="download">
|
|
268
|
-
Download
|
|
269
|
-
</Button>
|
|
270
|
-
</Dropdown.Trigger>
|
|
271
|
-
<Dropdown.Content>
|
|
272
|
-
<Dropdown.Item onSelect={onDownloadCsv}>Download as CSV</Dropdown.Item>
|
|
273
|
-
<Dropdown.Item onSelect={onDownloadPdf}>Download as PDF</Dropdown.Item>
|
|
274
|
-
</Dropdown.Content>
|
|
275
|
-
</Dropdown>
|
|
276
|
-
```
|
|
277
|
-
|
|
278
|
-
**Feature gap — true split button:** A real split button has TWO separate click targets: one that fires the primary action immediately, one that opens the dropdown. The Arbor pattern is a single dropdown trigger — the whole button opens the dropdown. If "Download" must fire immediately on click AND also offer format choices, you need a custom split button with two buttons side by side. This does not exist in the library — worth raising as a ticket if it appears in multiple places.
|
|
279
|
-
|
|
280
|
-
_(Dorothy verified: confirmed — `Dropdown.Trigger`, `Dropdown.Content`, `Dropdown.Item` with `onSelect` all confirmed. `asChild` Radix pattern confirmed.)_
|
|
281
|
-
|
|
282
|
-
---
|
|
283
|
-
|
|
284
|
-
### 11. "Schedule" Toolbar Button
|
|
285
|
-
|
|
286
|
-
**Arbor replacement:** `Button` variant="secondary"
|
|
287
|
-
**Migration complexity:** 🟢 Low
|
|
288
|
-
|
|
289
|
-
```tsx
|
|
290
|
-
<Button variant="secondary" size="S" onClick={onSchedule}>Schedule</Button>
|
|
291
|
-
```
|
|
292
|
-
|
|
293
|
-
_(Dorothy verified: confirmed)_
|
|
294
|
-
|
|
295
|
-
---
|
|
296
|
-
|
|
297
|
-
### 12. Bulk Action Dropdown
|
|
298
|
-
|
|
299
|
-
**Arbor replacement:** `Table.BulkActionsDropdown` (`src/components/table/BulkActionsDropdown.tsx`)
|
|
300
|
-
**Migration complexity:** 🟢 Low
|
|
301
|
-
|
|
302
|
-
This is exactly what `Table.BulkActionsDropdown` exists for. It reads selected rows from `GridApiContext` and calls your callbacks with the grid API.
|
|
303
|
-
|
|
304
|
-
**One thing to know:** it renders "Actions (N)" where N is the number of ACTION OPTIONS defined, **not** the number of selected rows. If you need "Actions (2 selected)", manage that label yourself with a custom `Dropdown`.
|
|
305
|
-
|
|
306
|
-
```tsx
|
|
307
|
-
<Table
|
|
308
|
-
rowData={reports}
|
|
309
|
-
columnDefs={columnDefs}
|
|
310
|
-
headerContent={
|
|
311
|
-
<Table.BulkActionsDropdown
|
|
312
|
-
actions={[
|
|
313
|
-
{ displayName: 'Archive', callback: (api) => archiveSelected(api?.getSelectedRows()) },
|
|
314
|
-
{ displayName: 'Delete', callback: (api) => deleteSelected(api?.getSelectedRows()), disabled: !canDelete },
|
|
315
|
-
]}
|
|
316
|
-
/>
|
|
317
|
-
}
|
|
318
|
-
/>
|
|
319
|
-
```
|
|
320
|
-
|
|
321
|
-
**MUST be used inside a `Table`** — it uses `GridApiContext` internally.
|
|
322
|
-
|
|
323
|
-
_(Dorothy verified: confirmed — `actions` prop shape confirmed as `{ displayName: string, callback: (api: GridApi | null) => void, disabled?: boolean }[]`. GridApiContext dependency confirmed.)_
|
|
324
|
-
|
|
325
|
-
---
|
|
326
|
-
|
|
327
|
-
### 13. Hide Columns Dropdown
|
|
328
|
-
|
|
329
|
-
**Arbor replacement:** `Table.HideColumnsDropdown` (`src/components/table/HideColumnsDropdown.tsx`)
|
|
330
|
-
**Migration complexity:** 🟢 Low
|
|
331
|
-
|
|
332
|
-
Auto-reads column list from `GridApiContext`, shows a multi-select dropdown, toggles column visibility via the AG Grid API. Zero custom code needed for the standard case.
|
|
333
|
-
|
|
334
|
-
```tsx
|
|
335
|
-
<Table
|
|
336
|
-
headerContent={
|
|
337
|
-
<div style={{ display: 'flex', gap: 'var(--spacing-small)' }}>
|
|
338
|
-
<Table.BulkActionsDropdown actions={bulkActions} />
|
|
339
|
-
<Table.HideColumnsDropdown />
|
|
340
|
-
</div>
|
|
341
|
-
}
|
|
342
|
-
/>
|
|
343
|
-
```
|
|
344
|
-
|
|
345
|
-
Optional props: `columns` (manual column list instead of reading from grid), `onSelectionChanged` (callback on visibility change), `overrideColumnHiding` (suppress automatic AG Grid visibility calls if you want to manage it yourself).
|
|
346
|
-
|
|
347
|
-
_(Dorothy verified: confirmed — all three optional props confirmed in HideColumnsDropdown source)_
|
|
348
|
-
|
|
349
|
-
---
|
|
350
|
-
|
|
351
|
-
### 14. Table Search Input
|
|
352
|
-
|
|
353
|
-
**Arbor replacement:** Built into `Table` — `hasSearch` defaults to `true`
|
|
354
|
-
**Migration complexity:** 🟢 Low
|
|
355
|
-
|
|
356
|
-
The `SearchBar` only renders inside `TableHeader`, which only renders when `headerContent` is provided. **If your legacy table has a search bar but no other toolbar elements, pass `headerContent={<></>}` (an empty fragment)** to ensure `TableHeader` renders and the `SearchBar` appears. This is the thing that trips people up.
|
|
357
|
-
|
|
358
|
-
```tsx
|
|
359
|
-
// Empty fragment triggers the TableHeader and SearchBar
|
|
360
|
-
<Table rowData={reports} columnDefs={columnDefs} headerContent={<></>} />
|
|
361
|
-
```
|
|
362
|
-
|
|
363
|
-
To suppress search: `hasSearch={false}`.
|
|
364
|
-
|
|
365
|
-
For server-side filtering: pass `hasSearch={false}` on the Table and use the `SearchBar` component directly (it IS exported from `src/index.ts`) with your own debounced server call.
|
|
366
|
-
|
|
367
|
-
_(Dorothy verified: confirmed — `hasSearch` prop confirmed, `SearchBar` confirmed exported from `src/index.ts`, `TableHeader`/`SearchBar` render logic confirmed)_
|
|
368
|
-
|
|
369
|
-
---
|
|
370
|
-
|
|
371
|
-
### 15. Icon-Only Toolbar Buttons (export, settings, help, fullscreen)
|
|
372
|
-
|
|
373
|
-
**Arbor replacement:** `Button` (no children, `iconLeftName` set) + `TooltipWrapper`
|
|
374
|
-
**Migration complexity:** 🟢 Low
|
|
375
|
-
|
|
376
|
-
`Button` auto-detects icon-only mode when children is absent and an icon prop is provided. Always wrap in `TooltipWrapper` — icon-only buttons without tooltips are an accessibility problem, not a style choice.
|
|
377
|
-
|
|
378
|
-
`TooltipWrapper` takes a `tooltipContent` prop.
|
|
379
|
-
|
|
380
|
-
```tsx
|
|
381
|
-
<TooltipWrapper tooltipContent="Settings">
|
|
382
|
-
<Button
|
|
383
|
-
variant="tertiary"
|
|
384
|
-
size="S"
|
|
385
|
-
iconLeftName="settings"
|
|
386
|
-
iconLeftScreenReaderText="Settings"
|
|
387
|
-
/>
|
|
388
|
-
</TooltipWrapper>
|
|
389
|
-
```
|
|
390
|
-
|
|
391
|
-
Available icons for these toolbar actions:
|
|
392
|
-
| Legacy action | Arbor icon name |
|
|
393
|
-
|---|---|
|
|
394
|
-
| Export | `'upload'` or `'download'` |
|
|
395
|
-
| Settings | `'settings'` |
|
|
396
|
-
| Help | `'circle-help'` |
|
|
397
|
-
| Fullscreen/expand | `'expand'` |
|
|
398
|
-
|
|
399
|
-
_(Dorothy verified: confirmed — `tooltipContent` prop on TooltipWrapper confirmed. Icon names verified against the icon set.)_
|
|
400
|
-
|
|
401
|
-
---
|
|
402
|
-
|
|
403
|
-
### 16. Data Table
|
|
404
|
-
|
|
405
|
-
**Arbor replacement:** `Table` (`src/components/table/Table.tsx`) — AG Grid Enterprise wrapper
|
|
406
|
-
**Migration complexity:** 🔴 High
|
|
407
|
-
|
|
408
|
-
The `Table` is fully capable of everything this legacy table does. The HIGH rating is about the migration work — going from a hand-rolled HTML table to AG Grid's data model requires rewriting your data layer to produce flat row objects. The component itself is not the problem.
|
|
409
|
-
|
|
410
|
-
**Two critical rules before you start:**
|
|
411
|
-
|
|
412
|
-
1. **Do NOT call `setAgGridLicenseKey()`** — `Table` handles it at module load time. Call it yourself and you will get double-registration warnings.
|
|
413
|
-
2. **Do NOT manually spread `DSDefaultColDef`** — `Table` merges it automatically via `{ ...DSDefaultColDef, ...defaultColDef }`. If you spread it yourself you will get duplicate configuration.
|
|
414
|
-
|
|
415
|
-
**Full column definitions for this page:**
|
|
416
|
-
|
|
417
|
-
```tsx
|
|
418
|
-
const typeIconMap: Record<string, string> = {
|
|
419
|
-
Student: 'user',
|
|
420
|
-
Group: 'users-round',
|
|
421
|
-
School: 'house',
|
|
422
|
-
};
|
|
423
|
-
|
|
424
|
-
const columnDefs: ColDef[] = [
|
|
425
|
-
{
|
|
426
|
-
checkboxSelection: true,
|
|
427
|
-
headerCheckboxSelection: true,
|
|
428
|
-
width: 48,
|
|
429
|
-
suppressSizeToFit: true,
|
|
430
|
-
},
|
|
431
|
-
{
|
|
432
|
-
field: 'title',
|
|
433
|
-
headerName: 'Title',
|
|
434
|
-
sortable: true,
|
|
435
|
-
flex: 2,
|
|
436
|
-
cellRenderer: (params: { value: string; data: ReportRow }) => (
|
|
437
|
-
<Button variant="text-link" size="S" onClick={() => onOpenReport(params.data.id)}>
|
|
438
|
-
{params.value}
|
|
439
|
-
</Button>
|
|
440
|
-
),
|
|
441
|
-
},
|
|
442
|
-
{
|
|
443
|
-
field: 'type',
|
|
444
|
-
headerName: 'Type',
|
|
445
|
-
sortable: true,
|
|
446
|
-
flex: 1,
|
|
447
|
-
cellRenderer: (params: { value: string }) => (
|
|
448
|
-
<span style={{ display: 'flex', alignItems: 'center', gap: '0.5rem' }}>
|
|
449
|
-
<Icon name={typeIconMap[params.value] ?? 'file'} size={16} />
|
|
450
|
-
{params.value}
|
|
451
|
-
</span>
|
|
452
|
-
),
|
|
453
|
-
},
|
|
454
|
-
{ field: 'createdBy', headerName: 'Created By', sortable: true, flex: 1 },
|
|
455
|
-
{ field: 'context', headerName: 'Context', sortable: true, flex: 1 },
|
|
456
|
-
{ field: 'createdDate', headerName: 'Created Date', sortable: true, sort: 'asc', flex: 1 },
|
|
457
|
-
{ field: 'modifiedDate', headerName: 'Modified Date', sortable: true, flex: 1 },
|
|
458
|
-
{ field: 'accessedDate', headerName: 'Accessed Date', sortable: true, flex: 1 },
|
|
459
|
-
{
|
|
460
|
-
headerName: '',
|
|
461
|
-
width: 48,
|
|
462
|
-
suppressSizeToFit: true,
|
|
463
|
-
cellRenderer: (params: { data: ReportRow }) => (
|
|
464
|
-
<Dropdown>
|
|
465
|
-
<Dropdown.Trigger>
|
|
466
|
-
<Button
|
|
467
|
-
variant="tertiary"
|
|
468
|
-
size="S"
|
|
469
|
-
iconLeftName="ellipsis-vertical"
|
|
470
|
-
iconLeftScreenReaderText="Row actions"
|
|
471
|
-
/>
|
|
472
|
-
</Dropdown.Trigger>
|
|
473
|
-
<Dropdown.Content>
|
|
474
|
-
<Dropdown.Item onSelect={() => onDuplicate(params.data)}>Duplicate</Dropdown.Item>
|
|
475
|
-
<Dropdown.Item onSelect={() => onEdit(params.data)}>Edit</Dropdown.Item>
|
|
476
|
-
</Dropdown.Content>
|
|
477
|
-
</Dropdown>
|
|
478
|
-
),
|
|
479
|
-
},
|
|
480
|
-
];
|
|
481
|
-
```
|
|
482
|
-
|
|
483
|
-
**z-index note for the overflow menu:** If the `Dropdown` inside a row cell clips within the grid container, use `PopupParentContext`:
|
|
484
|
-
|
|
485
|
-
```tsx
|
|
486
|
-
const containerRef = useRef<HTMLDivElement>(null);
|
|
487
|
-
|
|
488
|
-
<div ref={containerRef}>
|
|
489
|
-
<PopupParentContext.Provider value={containerRef}>
|
|
490
|
-
<Table rowData={reports} columnDefs={columnDefs} ... />
|
|
491
|
-
</PopupParentContext.Provider>
|
|
492
|
-
</div>
|
|
493
|
-
```
|
|
494
|
-
|
|
495
|
-
**On the three-dot icon:** `'ellipsis-vertical'` maps to Lucide's `EllipsisVertical`. `'3-dot'` also maps to `EllipsisVertical` — they are the same component registered under two names. Either works; use `'ellipsis-vertical'` for consistency with what the rest of Arbor uses.
|
|
496
|
-
|
|
497
|
-
_(Dorothy verified: confirmed — `checkboxSelection`, `headerCheckboxSelection`, `sortable`, `sort`, `flex`, `suppressSizeToFit` all valid AG Grid ColDef props. DSDefaultColDef auto-merge confirmed in Table source. License key auto-init confirmed. `'ellipsis-vertical'` icon name confirmed.)_
|
|
498
|
-
|
|
499
|
-
---
|
|
500
|
-
|
|
501
|
-
## Elements With No Arbor Equivalent
|
|
502
|
-
|
|
503
|
-
These require either a custom build at app level or a new library component:
|
|
504
|
-
|
|
505
|
-
| Legacy Element | Why Nothing Fits | Suggested Approach | Priority |
|
|
506
|
-
|---|---|---|---|
|
|
507
|
-
| Top navigation bar | App shell — not a page-content concern | Custom `TopNav` using `Button`, `Dropdown`, `Icon` primitives | High (shared across all pages) |
|
|
508
|
-
| Left icon nav | App shell — icon rail | Custom `SideNavIcons` using `Button` + `TooltipWrapper` | High (shared across all pages) |
|
|
509
|
-
| Left text nav | App shell — hierarchical sidebar | Custom `SideNavText` using `Button` text-link + `Separator` | High (shared across all pages) |
|
|
510
|
-
| Breadcrumbs | Not yet built as a library component | Compose from `<nav><ol>`, `Button text-link`, `Icon chevron-right` | Medium — raise a `Breadcrumbs` ticket |
|
|
511
|
-
| Warning/alert banner | No `Alert` or `Banner` component | Compose from `Icon` + `Button` + custom SCSS for now | High — raise a `Banner` ticket |
|
|
512
|
-
|
|
513
|
-
---
|
|
514
|
-
|
|
515
|
-
## Component Library Tickets to Raise
|
|
516
|
-
|
|
517
|
-
| Component | Why | Appears On | Priority |
|
|
518
|
-
|---|---|---|---|
|
|
519
|
-
| `Alert` / `Banner` | Amber/green/red/blue contextual page banners | Every page with warnings, success messages, notices | **High** |
|
|
520
|
-
| `Breadcrumbs` | Navigation path indicator | Every page deeper than top-level | **Medium** |
|
|
521
|
-
| True `SplitButton` | Primary action + dropdown alternatives in one control | Download buttons, action buttons with sub-options | **Low** |
|
|
522
|
-
| `dsLinkCellRenderer` | Named AG Grid cell renderer for navigable links | Any table with clickable row names | **Low** |
|
|
523
|
-
|
|
524
|
-
---
|
|
525
|
-
|
|
526
|
-
## Migration Complexity Summary
|
|
527
|
-
|
|
528
|
-
| Complexity | Count | Elements |
|
|
529
|
-
|---|---|---|
|
|
530
|
-
| 🟢 Low | 10 | Page heading, Create New Report button, Tab bar, Schedule button, Bulk action dropdown, Hide columns dropdown, Table search, Icon toolbar buttons, Row checkboxes, Sortable column headers |
|
|
531
|
-
| 🟡 Medium | 7 | Breadcrumbs, Warning banner, Filter status indicator, Download dropdown button, Link cells, Type indicator cells, Overflow menu per row |
|
|
532
|
-
| 🔴 High | 4 | Top nav bar, Left icon nav, Left text nav, Data table (data model migration) |
|
|
533
|
-
| ❌ No equivalent | 5 | Top nav, Left icon nav, Left text nav, Breadcrumbs, Warning banner |
|
|
534
|
-
|
|
535
|
-
---
|
|
536
|
-
|
|
537
|
-
## Recommended Migration Order
|
|
538
|
-
|
|
539
|
-
Sophia's take: "Start where you get quick wins and build muscle memory with the Arbor API before you touch the big things. The table migration is the real work — do it last, when your team already knows how Button, Tabs, and Section feel."
|
|
540
|
-
|
|
541
|
-
1. **Start with Low complexity** — these are all direct swaps, no surprises:
|
|
542
|
-
1. `Heading` for the page title
|
|
543
|
-
2. `Button variant="primary"` for "Create New Report"
|
|
544
|
-
3. `Button variant="secondary"` for "Schedule", "Duplicate", "Edit"
|
|
545
|
-
4. `Tabs` + `Tabs.Item` for Active/Archived/Expired
|
|
546
|
-
5. `Button` icon-only + `TooltipWrapper` for the icon toolbar buttons
|
|
547
|
-
|
|
548
|
-
2. **Then Medium complexity** — same purpose, different API:
|
|
549
|
-
6. Compose the filter status bar (`Table.RowCountInfo` + `Button text-link`)
|
|
550
|
-
7. Build the Download dropdown (`Button variant="dropdown"` + `Dropdown`)
|
|
551
|
-
8. Compose Breadcrumbs manually (`<nav><ol>` pattern)
|
|
552
|
-
9. Compose Warning banner (`Icon` + `Button` + custom SCSS)
|
|
553
|
-
|
|
554
|
-
3. **The main event — data table migration:**
|
|
555
|
-
10. Define `columnDefs` mapping all 8 data columns + checkbox column + overflow column
|
|
556
|
-
11. Wire `rowData` from existing data layer
|
|
557
|
-
12. Add `Table.BulkActionsDropdown` + `Table.HideColumnsDropdown` to `headerContent`
|
|
558
|
-
13. Built-in search auto-appears when `headerContent` is set (hasSearch defaults to true)
|
|
559
|
-
|
|
560
|
-
4. **App shell (coordinate separately):**
|
|
561
|
-
- TopNav, SideNavIcons, SideNavText — these are shared across ALL pages; treat them as a separate project with the shell team, not part of a single page migration
|
|
562
|
-
|
|
563
|
-
---
|
|
564
|
-
|
|
565
|
-
## What This Migration Will NOT Change
|
|
566
|
-
|
|
567
|
-
Things that stay the same regardless of component swap:
|
|
568
|
-
- Business logic (filtering, sorting, scheduling reports)
|
|
569
|
-
- Data fetching (API calls to load and paginate reports)
|
|
570
|
-
- Routing (navigating to individual report pages)
|
|
571
|
-
- State management patterns (tab state, selected row state, filter state)
|
|
572
|
-
- Auth and permission checks
|
|
573
|
-
|
|
574
|
-
---
|
|
575
|
-
|
|
576
|
-
## Appendix: Files Dorothy Verified
|
|
577
|
-
|
|
578
|
-
Every claim in this report is grounded in actual source code. Dorothy read all of the following:
|
|
579
|
-
|
|
580
|
-
- `src/index.ts`
|
|
581
|
-
- `src/components/heading/Heading.tsx`
|
|
582
|
-
- `src/components/button/Button.tsx`
|
|
583
|
-
- `src/components/tabs/Tabs.tsx`
|
|
584
|
-
- `src/components/tabs/TabsItem.tsx`
|
|
585
|
-
- `src/components/table/Table.tsx`
|
|
586
|
-
- `src/components/table/BulkActionsDropdown.tsx`
|
|
587
|
-
- `src/components/table/HideColumnsDropdown.tsx`
|
|
588
|
-
- `src/components/table/TableHeader.tsx`
|
|
589
|
-
- `src/components/table/pagination/RowCountInfo.tsx`
|
|
590
|
-
- `src/components/dropdown/Dropdown.tsx`
|
|
591
|
-
- `src/components/tooltip/TooltipWrapper.tsx`
|
/package/{.claude/agent-memory → .agent-memory}/blanche-designspert/token-review-patterns.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|