From 58366a1217794f1d9d984dc05f03d636a3e9bf4b Mon Sep 17 00:00:00 2001 From: chrisnojima Date: Fri, 29 May 2026 14:30:02 -0400 Subject: [PATCH 1/7] =?UTF-8?q?migrate=20CB/CB2=20=E2=86=92=20CB3:=20profi?= =?UTF-8?q?le?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plans/clickablebox3.md | 14 ++++++------ shared/profile/add-to-team.tsx | 4 ++-- shared/profile/edit-avatar/index.tsx | 11 ++++++---- shared/profile/generic/proofs-list.tsx | 11 +++++----- shared/profile/user/actions/index.tsx | 12 +++++------ shared/profile/user/friend.tsx | 15 ++++++------- shared/profile/user/index.tsx | 30 +++++++++++++------------- shared/profile/user/teams/index.tsx | 14 ++++++------ shared/profile/user/teams/team-row.tsx | 24 ++++++++++----------- 9 files changed, 65 insertions(+), 70 deletions(-) diff --git a/plans/clickablebox3.md b/plans/clickablebox3.md index 04ee699989ff..69f9509d1e8d 100644 --- a/plans/clickablebox3.md +++ b/plans/clickablebox3.md @@ -38,13 +38,13 @@ Use `migrate-clickable-box` skill for each chunk. Run `yarn lint && yarn tsc` an - [x] `shared/devices/` (6 total) ### Round 1 — small -- [ ] `shared/git/` (3) -- [ ] `shared/incoming-share/` (2) -- [ ] `shared/signup/` (2) -- [ ] `shared/provision/` (4) -- [ ] `shared/people/` (2) -- [ ] `shared/settings/` (4) -- [ ] `shared/profile/` (10) +- [x] `shared/git/` (3) +- [x] `shared/incoming-share/` (2) +- [x] `shared/signup/` (2) +- [x] `shared/provision/` (4) +- [x] `shared/people/` (2) +- [x] `shared/settings/` (4) +- [x] `shared/profile/` (10) ### Round 2 — medium - [ ] `shared/tracker/` (4) diff --git a/shared/profile/add-to-team.tsx b/shared/profile/add-to-team.tsx index 0448b9516d1c..207d5d2888a0 100644 --- a/shared/profile/add-to-team.tsx +++ b/shared/profile/add-to-team.tsx @@ -341,7 +341,7 @@ type RowProps = { const TeamRow = (props: RowProps) => { return ( - props.onCheck(!props.checked) : undefined}> + props.onCheck(!props.checked) : undefined}> @@ -372,7 +372,7 @@ const TeamRow = (props: RowProps) => { {!isMobile && } - + ) } diff --git a/shared/profile/edit-avatar/index.tsx b/shared/profile/edit-avatar/index.tsx index 71c6f733bb02..47e7f1b99850 100644 --- a/shared/profile/edit-avatar/index.tsx +++ b/shared/profile/edit-avatar/index.tsx @@ -159,7 +159,8 @@ const DesktopEditAvatar = (_p: Props) => { {' '} for one. - { type="iconfont-camera" /> )} - + {loading === 'loaded' ? Click to select. Scroll to zoom. : null} @@ -311,12 +312,14 @@ const NativeAvatarUploadWrapper = (p: Props) => { const renderImageZoomer = () => { if (type === 'team' && !selectedImage) { return ( - - + ) } return selectedImage ? ( diff --git a/shared/profile/generic/proofs-list.tsx b/shared/profile/generic/proofs-list.tsx index 3a4986f101a8..4ca32f5db9c5 100644 --- a/shared/profile/generic/proofs-list.tsx +++ b/shared/profile/generic/proofs-list.tsx @@ -620,7 +620,10 @@ const ProviderPicker = ({ renderItem={(_: unknown, provider: Provider) => ( - onSelect(provider.key)} style={styles.containerBox} @@ -647,7 +650,7 @@ const ProviderPicker = ({ style={styles.iconArrow} type="iconfont-arrow-right" /> - + )} /> @@ -1314,11 +1317,7 @@ const styles = Kb.Styles.styleSheetCreate( }, }), containerBox: { - alignItems: 'center', - display: 'flex', - flexDirection: 'row', height: isMobile ? 56 : 48, - justifyContent: 'flex-start', }, description: {...rightColumnStyle}, error: { diff --git a/shared/profile/user/actions/index.tsx b/shared/profile/user/actions/index.tsx index 22c7c9af3c6b..b7b37964f035 100644 --- a/shared/profile/user/actions/index.tsx +++ b/shared/profile/user/actions/index.tsx @@ -208,14 +208,12 @@ const DropdownButton = (p: DropdownProps) => { const {showPopup, popup, popupAnchor} = Kb.usePopup2(makePopup) return ( - - - - - - + + + + {popup} - + ) } diff --git a/shared/profile/user/friend.tsx b/shared/profile/user/friend.tsx index d4366fc0cd78..72844c74b2cf 100644 --- a/shared/profile/user/friend.tsx +++ b/shared/profile/user/friend.tsx @@ -25,12 +25,12 @@ const Container = (ownProps: OwnProps) => { : followsYou ? ('icon-follow-me-21' as const) : ('icon-following-21' as const) return ( - - + {!!followIconType && } @@ -45,8 +45,7 @@ const Container = (ownProps: OwnProps) => { {fullname} - - + ) } diff --git a/shared/profile/user/index.tsx b/shared/profile/user/index.tsx index d70bc05c2d7a..8c0914460892 100644 --- a/shared/profile/user/index.tsx +++ b/shared/profile/user/index.tsx @@ -227,24 +227,24 @@ const Tabs = (p: TabsProps) => { const onClickFollowing = () => p.onSelectTab('following') const onClickFollowers = () => p.onSelectTab('followers') const tab = (tab: Tab) => ( - - - - {tab === 'following' - ? `Following${!p.loadingFollowing ? ` (${p.numFollowing || 0})` : ''}` - : `Followers${!p.loadingFollowers ? ` (${p.numFollowers || 0})` : ''}`} - - {((tab === 'following' && p.loadingFollowing) || p.loadingFollowers) && ( - - )} - - + + {tab === 'following' + ? `Following${!p.loadingFollowing ? ` (${p.numFollowing || 0})` : ''}` + : `Followers${!p.loadingFollowers ? ` (${p.numFollowers || 0})` : ''}`} + + {((tab === 'following' && p.loadingFollowing) || p.loadingFollowers) && ( + + )} + ) return ( diff --git a/shared/profile/user/teams/index.tsx b/shared/profile/user/teams/index.tsx index bc5b8bdb9a05..46ad3d7ffc7d 100644 --- a/shared/profile/user/teams/index.tsx +++ b/shared/profile/user/teams/index.tsx @@ -73,14 +73,12 @@ const TeamShowcase = (props: TeamShowcaseProps) => { const ShowcaseTeamsOffer = (p: {onEdit: () => void}) => ( - - - - - {"Feature the teams you're in"} - - - + + + + {"Feature the teams you're in"} + + ) diff --git a/shared/profile/user/teams/team-row.tsx b/shared/profile/user/teams/team-row.tsx index 4751ff7217a1..4f6a1152cdb6 100644 --- a/shared/profile/user/teams/team-row.tsx +++ b/shared/profile/user/teams/team-row.tsx @@ -12,19 +12,17 @@ type Props = { } const TeamRow = ({isOpen, loading = false, name, onClick, popup, popupAnchor}: Props) => ( - - - <> - {popup} - - - - {name} - - {typeof isOpen === 'boolean' && } - {loading && } - - + + <> + {popup} + + + + {name} + + {typeof isOpen === 'boolean' && } + {loading && } + ) const styles = Kb.Styles.styleSheetCreate(() => ({ From 0f2f1e454084da182631dc2671942bbfa8c8dc41 Mon Sep 17 00:00:00 2001 From: chrisnojima Date: Fri, 29 May 2026 14:38:42 -0400 Subject: [PATCH 2/7] =?UTF-8?q?migrate=20CB/CB2=20=E2=86=92=20CB3:=20track?= =?UTF-8?q?er,=20menubar,=20app,=20router-v2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plans/clickablebox3.md | 10 +-- shared/app/global-errors.tsx | 4 +- shared/app/runtime-stats.tsx | 10 +-- shared/menubar/index.desktop.tsx | 105 +++++++++++----------- shared/router-v2/header/index.desktop.tsx | 34 +++---- shared/router-v2/tab-bar.desktop.tsx | 101 ++++++++++----------- shared/tracker/assertion.tsx | 45 +++++----- 7 files changed, 155 insertions(+), 154 deletions(-) diff --git a/plans/clickablebox3.md b/plans/clickablebox3.md index 69f9509d1e8d..0fcef11e62f4 100644 --- a/plans/clickablebox3.md +++ b/plans/clickablebox3.md @@ -24,7 +24,7 @@ ## ✅ Done: ClickableBox3 implemented and devices/ migrated Committed in `3ac6c14b82`. Key points for future reference: -- `ClickableBox3Props = Box2Props & {onClick?, onLongPress?, hitSlop?}` — `direction` required +- `ClickableBox3Props = Box2Props & {onClick?, onLongPress?, hitSlop?}` — `direction` required; desktop mouse events (`onMouseDown/Up/Leave/Move/Over/Enter`, `onContextMenu`) are in `Box2Props` and passed through to the `
` - `box2ClassNames()` extracted from Box2 and shared; `box2SharedProps` exported from `box.tsx` - `devices/` pilot complete: 3 CB2 usages → CB3, inner Box2 wrappers eliminated, `mobileAddHeader` style simplified @@ -47,10 +47,10 @@ Use `migrate-clickable-box` skill for each chunk. Run `yarn lint && yarn tsc` an - [x] `shared/profile/` (10) ### Round 2 — medium -- [ ] `shared/tracker/` (4) -- [ ] `shared/menubar/` (3) -- [ ] `shared/app/` (4) -- [ ] `shared/router-v2/` (9) +- [x] `shared/tracker/` (4) +- [x] `shared/menubar/` (3) +- [x] `shared/app/` (4) +- [x] `shared/router-v2/` (9) - [ ] `shared/teams/` (25+) - [ ] `shared/team-building/` (9+) diff --git a/shared/app/global-errors.tsx b/shared/app/global-errors.tsx index d5cfc7e672ae..d1257d310d98 100644 --- a/shared/app/global-errors.tsx +++ b/shared/app/global-errors.tsx @@ -213,7 +213,7 @@ const GlobalError = () => { } return ( - + {summary} @@ -239,7 +239,7 @@ const GlobalError = () => { {details} - + ) } diff --git a/shared/app/runtime-stats.tsx b/shared/app/runtime-stats.tsx index bad8651248a6..4214b75d8e5c 100644 --- a/shared/app/runtime-stats.tsx +++ b/shared/app/runtime-stats.tsx @@ -226,8 +226,7 @@ const RuntimeStatsDesktop = ({stats}: Props) => { return ( <> - setMoreLogs(m => !m)}> - + setMoreLogs(m => !m)} direction="vertical" style={styles.container} gap="xxtiny" fullWidth={true}> {!moreLogs && stats.processStats?.map((stat, i) => { return ( @@ -303,8 +302,7 @@ const RuntimeStatsDesktop = ({stats}: Props) => { )*/} - - + ) @@ -333,9 +331,9 @@ const RuntimeStatsMobile = ({stats}: Props) => { style={showLogs ? styles.modalLogStats : styles.modalLogStatsHidden} gap="xtiny" > - setShowLogs(s => !s)}> + setShowLogs(s => !s)} direction="vertical"> - + {processStat && ( diff --git a/shared/menubar/index.desktop.tsx b/shared/menubar/index.desktop.tsx index 7c9640febddb..3d70402e3829 100644 --- a/shared/menubar/index.desktop.tsx +++ b/shared/menubar/index.desktop.tsx @@ -118,53 +118,55 @@ const ChatRow = (p: {conv: Conversation; httpSrvAddress: string; httpSrvToken: s const timestamp = conv.timestamp ? TimestampUtil.formatTimeForConversationList(conv.timestamp) : '' return ( - R.remoteDispatch(RemoteGen.createOpenChatFromWidget({conversationIDKey: conv.conversationIDKey}))} - style={styles.chatRow} + direction="horizontal" + fullWidth={true} + alignItems="center" + gap="tiny" + style={styles.chatRowInner} > - - - - - - - {isTeam && conv.channelname ? `${name}#${conv.channelname}` : name} - - {conv.hasBadge && } - - {!!timestamp && ( - - {timestamp} - - )} + + + + + + {isTeam && conv.channelname ? `${name}#${conv.channelname}` : name} + + {conv.hasBadge && } - {!!conv.snippetDecorated && ( + {!!timestamp && ( - {conv.snippetDecorated} + {timestamp} )} + {!!conv.snippetDecorated && ( + + {conv.snippetDecorated} + + )} - + ) } @@ -191,17 +193,22 @@ const ChatPreview = (p: {conversationsToSend: ReadonlyArray; convL // Inline file updates (replaces FilesContainer + files.desktop.tsx with store-connected components) const FileUpdate = (p: {path: T.FS.Path; uploading: boolean; onClick: () => void}) => ( - - - - {p.uploading && ( - - - - )} - - - + + + {p.uploading && ( + + + + )} + + ) const defaultNumFileOptionsShown = 3 @@ -642,11 +649,6 @@ const styles = Kb.Styles.styleSheetCreate(() => ({ backgroundColor: Kb.Styles.globalColors.white, color: Kb.Styles.globalColors.black, }, - chatRow: Kb.Styles.platformStyles({ - isElectron: { - ...Kb.Styles.desktopStyles.clickable, - }, - }), chatRowInner: Kb.Styles.padding(Kb.Styles.globalMargins.xtiny, Kb.Styles.globalMargins.xsmall), chatRowName: {flexShrink: 1}, @@ -655,7 +657,6 @@ const styles = Kb.Styles.styleSheetCreate(() => ({ chatSnippet: {color: Kb.Styles.globalColors.black_50}, chatSnippetUnread: {color: Kb.Styles.globalColors.black}, chatTimestamp: {color: Kb.Styles.globalColors.black_50, flexShrink: 0, marginLeft: Kb.Styles.globalMargins.tiny}, - fileFullWidth: {width: '100%'}, fileIcon: { flexShrink: 0, ...Kb.Styles.size(16), diff --git a/shared/router-v2/header/index.desktop.tsx b/shared/router-v2/header/index.desktop.tsx index 6275f6242fa6..86461e439e7c 100644 --- a/shared/router-v2/header/index.desktop.tsx +++ b/shared/router-v2/header/index.desktop.tsx @@ -79,17 +79,19 @@ const SystemButtons = ({isMaximized}: {isMaximized: boolean}) => { } return ( - - - + { style={styles.appIcon} type={isMaximized ? 'iconfont-app-un-maximize' : 'iconfont-app-maximize'} /> - - + - + ) } @@ -192,21 +195,20 @@ function DesktopHeader(p: Props) { > {/* TODO have headerLeft be the back button */} {headerLeft !== null && ( - - - - - + + )} { const menuHeader = ( - + { } /> - + { return ( <> - - - + + <> + + Hi {username}! + + - <> - - Hi {username}! - - - - - + + {popup} ) @@ -267,37 +266,33 @@ function Tab(props: TabProps) { } return ( - - - - - - {tab === Tabs.fsTab && } - - - {label} - - + + + + {tab === Tabs.fsTab && } - + + {label} + + + ) } diff --git a/shared/tracker/assertion.tsx b/shared/tracker/assertion.tsx index af8ed8898903..dd09f151610e 100644 --- a/shared/tracker/assertion.tsx +++ b/shared/tracker/assertion.tsx @@ -222,24 +222,29 @@ const Container = (ownProps: OwnProps) => { )} - - - - {items ? ( - <> - - {popup} - - ) : ( - - )} - - + + + {items ? ( + <> + + {popup} + + ) : ( + + )} + {!!metas.length && ( @@ -482,9 +487,9 @@ const AssertionSiteIcon = (p: SIProps) => { child = {child} } return ( - + {child} - + ) } From b8cc973d2cc9127ebe5dac3ffc7657362bb6022a Mon Sep 17 00:00:00 2001 From: chrisnojima Date: Fri, 29 May 2026 15:02:00 -0400 Subject: [PATCH 3/7] clean up iconContainer: remove redundant clickable/flexBoxColumn, fold in icon size --- shared/router-v2/header/index.desktop.tsx | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/shared/router-v2/header/index.desktop.tsx b/shared/router-v2/header/index.desktop.tsx index 86461e439e7c..8083ba381b8c 100644 --- a/shared/router-v2/header/index.desktop.tsx +++ b/shared/router-v2/header/index.desktop.tsx @@ -200,7 +200,7 @@ function DesktopHeader(p: Props) { hover_background_color_black_10: !!back, })} onClick={pop} - style={Kb.Styles.collapseStyles([iconContainerStyle, styles.icon])} + style={iconContainerStyle} direction="vertical" > Date: Fri, 29 May 2026 15:17:27 -0400 Subject: [PATCH 4/7] update skill --- skill/migrate-clickable-box/SKILL.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/skill/migrate-clickable-box/SKILL.md b/skill/migrate-clickable-box/SKILL.md index f473702a08ce..94e51c79236c 100644 --- a/skill/migrate-clickable-box/SKILL.md +++ b/skill/migrate-clickable-box/SKILL.md @@ -11,7 +11,9 @@ See `plans/clickablebox3.md` for the full migration plan, directory checklist, a `ClickableBox3` = `ClickableBox2` + all `Box2` layout props (direction optional). On desktop it renders a `
` with the Box2 CSS class system plus `clickable-box2` cursor. On mobile it uses `Pressable` + `box2SharedProps` for layout. -Type: `Box2Props & {onClick?, onLongPress?, onMouseOver?, hitSlop?}` — **`direction` is required.** +Type: `Box2Props & {onClick?, onLongPress?, hitSlop?}` — **`direction` is required.** + +`Box2Props` includes desktop mouse events: `onMouseDown`, `onMouseUp`, `onMouseLeave`, `onMouseMove`, `onMouseOver`, `onMouseEnter`, `onContextMenu`. CB3 passes all of these through to the desktop `
`. They are **not** forwarded on mobile (Pressable doesn't support them). `direction` is always required. For Pattern B swaps (plain clickable wrapper, no layout needed), pass the direction that matches how children are stacked — usually `"vertical"` for a single child or vertically-stacked children. @@ -110,11 +112,12 @@ These CB1 props have no CB3 equivalent: - `hoverColor`, `underlayColor` → add `hover_background_color_*` CSS className to CB3 instead - `feedback={false}` → drop (Pressable doesn't have this) - `activeOpacity` → drop -- `onMouseEnter` / `onMouseLeave` → rare; use a wrapper div if truly needed - `onPressIn` / `onPressOut` → not in CB3; leave as CB1 and note it - `tooltip` → wrap with `` outside CB3 - `onLongPress={(e) => ...}` → remove the `e` param (CB3 signature is `() => void`) +Note: `onMouseDown`, `onMouseUp`, `onMouseLeave`, `onMouseMove`, `onMouseOver`, `onMouseEnter` are **fully supported** in CB3 via `Box2Props` — these are NOT Pattern D cases. + ## Step 3: Present Changes Before Touching Anything For each usage show: file, line, pattern (A/B/C/D), proposed change. From 01b879abe79b81c8f13d24f5f4ad4237baab02e1 Mon Sep 17 00:00:00 2001 From: chrisnojima Date: Fri, 29 May 2026 16:12:21 -0400 Subject: [PATCH 5/7] add onMouseEnter to Box2Props and forward it in ClickableBox3 desktop --- shared/common-adapters/box.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/shared/common-adapters/box.tsx b/shared/common-adapters/box.tsx index fc9171f51534..d377163dc69a 100644 --- a/shared/common-adapters/box.tsx +++ b/shared/common-adapters/box.tsx @@ -24,6 +24,7 @@ export type Box2Props = { onDrop?: (syntheticDragEvent: React.DragEvent) => void onLayout?: (evt: LayoutEvent) => void onMouseDown?: (syntheticEvent: React.MouseEvent) => void + onMouseEnter?: (syntheticEvent: React.MouseEvent) => void onMouseMove?: (syntheticEvent: React.MouseEvent) => void onMouseLeave?: (syntheticEvent: React.MouseEvent) => void onMouseUp?: (syntheticEvent: React.MouseEvent) => void @@ -318,7 +319,7 @@ export const ClickableBox3 = (p: ClickableBox3Props & {ref?: React.Ref Date: Fri, 29 May 2026 16:14:25 -0400 Subject: [PATCH 6/7] fix lint: suppress consistent-type-imports for expo-camera require cast --- shared/provision/code-page/qr-scan/scanner.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/shared/provision/code-page/qr-scan/scanner.tsx b/shared/provision/code-page/qr-scan/scanner.tsx index 55a2ad9d524a..8de1aee64108 100644 --- a/shared/provision/code-page/qr-scan/scanner.tsx +++ b/shared/provision/code-page/qr-scan/scanner.tsx @@ -9,6 +9,7 @@ type Props = { const QRScannerMobile = (p: Props): React.ReactElement | null => { // eslint-disable-next-line @typescript-eslint/no-var-requires + // eslint-disable-next-line @typescript-eslint/consistent-type-imports const {CameraView, useCameraPermissions} = require('expo-camera') as typeof import('expo-camera') const [scanned, setScanned] = React.useState(false) const [permission, requestPermission] = useCameraPermissions() From 1307e4136e3988398cae9710ecb5a0a5da62ad27 Mon Sep 17 00:00:00 2001 From: chrisnojima Date: Fri, 29 May 2026 16:14:56 -0400 Subject: [PATCH 7/7] skill --- skill/migrate-clickable-box/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skill/migrate-clickable-box/SKILL.md b/skill/migrate-clickable-box/SKILL.md index 94e51c79236c..3a340d9ad9e0 100644 --- a/skill/migrate-clickable-box/SKILL.md +++ b/skill/migrate-clickable-box/SKILL.md @@ -136,7 +136,7 @@ From `shared/`: ``` yarn lint && yarn tsc ``` -Fix errors before reporting done. +**Both must pass with zero errors before reporting done.** Fix any failures — including lint errors in files we touched or that were broken in a prior session. Do not skip lint or treat failures as pre-existing without verifying via `git stash`. ## Step 6: Update Checklist