Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/remove-style-feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"react-grab": minor
"grab": minor
"@react-grab/cli": minor
---

Remove the Style action and panel, including its keyboard shortcuts, inline previews, CSS property controls, design-token handling, and edit-related action context and renderer types. Simplify the toolbar to its Copy control while keeping Comment available through the context menu and action menu.
5 changes: 1 addition & 4 deletions apps/e2e-app-vite-upstream/src/error-boundary.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import { Component, useState } from "react";

export class FixtureErrorBoundary extends Component<
FixtureErrorBoundaryProps,
FixtureErrorBoundaryState
> {
class FixtureErrorBoundary extends Component<FixtureErrorBoundaryProps, FixtureErrorBoundaryState> {
state: FixtureErrorBoundaryState = { didError: false };

static getDerivedStateFromError = (): FixtureErrorBoundaryState => ({ didError: true });
Expand Down
8 changes: 0 additions & 8 deletions apps/e2e-app-vite/src/index.css
Original file line number Diff line number Diff line change
@@ -1,9 +1 @@
@import "tailwindcss";

/* Library-agnostic design tokens used by the design-token prompt e2e test.
Definition-only (never referenced), so they add no visual change. */
:root {
--rg-test-space-4: 16px;
--rg-test-space-6: 24px;
--rg-test-brand: #123456;
}
2 changes: 1 addition & 1 deletion apps/e2e-app-vite/src/pierre-diff-fixture.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export default SmallInput
`,
};

export const PierreDiff = () => (
const PierreDiff = () => (
<MultiFileDiff
oldFile={OLD_FILE}
newFile={NEW_FILE}
Expand Down
7 changes: 7 additions & 0 deletions apps/e2e-react-grab-development-aliases.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { fileURLToPath } from "node:url";

const REACT_GRAB_DEVELOPMENT_CORE_PATH = fileURLToPath(
new URL("./e2e-react-grab-development/dist/core/index.js", import.meta.url),
);

export const REACT_GRAB_DEVELOPMENT_ALIASES = {
"react-grab/core": REACT_GRAB_DEVELOPMENT_CORE_PATH,
"react-grab/primitives": "@react-grab/e2e-development/primitives",
"react-grab": "@react-grab/e2e-development",
};
1 change: 0 additions & 1 deletion apps/openstory/stories/renderer.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,6 @@ const Scene = (props: SceneProps) => {
actions={createMenuActions(Boolean(props.filePath))}
onInputChange={noop}
onInputSubmit={noop}
onToggleExpand={noop}
onConfirmDismiss={noop}
onToggleActive={noop}
onToolbarStateChange={noop}
Expand Down
29 changes: 22 additions & 7 deletions apps/web-extension/src/content/react-grab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ const turndownService = new TurndownService();
let extensionApi: ReactGrabAPI | null = null;
let lastToolbarState: ToolbarState | null = null;
let isApplyingExternalState = false;
let hasHydratedInitialState = false;
let stateChangeUnsubscribe: (() => void) | null = null;

const handleToolbarStateFromApi = (toolbarState: ToolbarState | null): void => {
if (isApplyingExternalState) return;
if (isApplyingExternalState || !hasHydratedInitialState) return;
if (!toolbarState) return;
if (
lastToolbarState &&
Expand All @@ -39,6 +40,18 @@ const handleToolbarStateFromApi = (toolbarState: ToolbarState | null): void => {
window.postMessage({ type: "__REACT_GRAB_TOOLBAR_STATE_SAVE__", state: toolbarState }, "*");
};

const applyExternalToolbarState = (api: ReactGrabAPI, toolbarState: ToolbarState): void => {
isApplyingExternalState = true;
try {
api.setToolbarState(toolbarState);
} finally {
isApplyingExternalState = false;
}

const appliedToolbarState = api.getToolbarState();
handleToolbarStateFromApi(appliedToolbarState);
};

const subscribeToStateChanges = (api: ReactGrabAPI): void => {
if (stateChangeUnsubscribe) {
stateChangeUnsubscribe();
Expand Down Expand Up @@ -125,9 +138,7 @@ const handleToolbarStateChange = async (state: ToolbarState): Promise<void> => {
await initializeReactGrab();
const api = getActiveApi();
if (api) {
isApplyingExternalState = true;
api.setToolbarState(state);
isApplyingExternalState = false;
applyExternalToolbarState(api, state);
}
};

Expand Down Expand Up @@ -186,17 +197,21 @@ const queryInitialState = (): Promise<InitialState> => {

const startup = async (): Promise<void> => {
const initialState = await queryInitialState();
lastToolbarState = initialState.toolbarState;
const api = await initializeReactGrab();

if (api) {
if (initialState.toolbarState) {
isApplyingExternalState = true;
api.setToolbarState(initialState.toolbarState);
isApplyingExternalState = false;
applyExternalToolbarState(api, initialState.toolbarState);
} else if (!initialState.enabled) {
api.setEnabled(false);
}
}

// Core normalizes persisted action IDs in a microtask after plugin registration.
await Promise.resolve();
hasHydratedInitialState = true;
handleToolbarStateFromApi(api?.getToolbarState() ?? null);
};

if (document.readyState === "loading") {
Expand Down
2 changes: 1 addition & 1 deletion apps/website/components/ui/badge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,4 @@ function Badge({
);
}

export { Badge, badgeVariants };
export { Badge };
2 changes: 1 addition & 1 deletion apps/website/components/ui/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,4 @@ function Button({
);
}

export { Button, buttonVariants };
export { Button };
25 changes: 1 addition & 24 deletions apps/website/components/ui/card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,33 +56,10 @@ function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
);
}

function CardAction({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-action"
className={cn("col-start-2 row-span-2 row-start-1 self-start justify-self-end", className)}
{...props}
/>
);
}

function CardContent({ className, ...props }: React.ComponentProps<"div">) {
return (
<div data-slot="card-content" className={cn("px-(--card-spacing)", className)} {...props} />
);
}

function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-footer"
className={cn(
"flex items-center rounded-b-xl border-t bg-muted/50 p-(--card-spacing)",
className,
)}
{...props}
/>
);
}

export { Card, CardHeader, CardFooter, CardTitle, CardAction, CardDescription, CardContent };
export { Card, CardHeader, CardTitle, CardDescription, CardContent };
7 changes: 0 additions & 7 deletions apps/website/components/ui/dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,6 @@ function DialogPortal({ ...props }: React.ComponentProps<typeof DialogPrimitive.
return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />;
}

function DialogClose({ ...props }: React.ComponentProps<typeof DialogPrimitive.Close>) {
return <DialogPrimitive.Close data-slot="dialog-close" {...props} />;
}

function DialogOverlay({
className,
...props
Expand Down Expand Up @@ -135,13 +131,10 @@ function DialogDescription({

export {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogOverlay,
DialogPortal,
DialogTitle,
DialogTrigger,
};
147 changes: 0 additions & 147 deletions apps/website/components/ui/dropdown-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,11 @@ import * as React from "react";
import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui";

import { cn } from "@/lib/utils";
import { CheckIcon, ChevronRightIcon } from "lucide-react";

function DropdownMenu({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {
return <DropdownMenuPrimitive.Root data-slot="dropdown-menu" {...props} />;
}

function DropdownMenuPortal({
...props
}: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {
return <DropdownMenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />;
}

function DropdownMenuTrigger({
...props
}: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {
Expand Down Expand Up @@ -44,10 +37,6 @@ function DropdownMenuContent({
);
}

function DropdownMenuGroup({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {
return <DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />;
}

function DropdownMenuItem({
className,
inset,
Expand All @@ -71,76 +60,6 @@ function DropdownMenuItem({
);
}

function DropdownMenuCheckboxItem({
className,
children,
checked,
inset,
...props
}: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem> & {
inset?: boolean;
}) {
return (
<DropdownMenuPrimitive.CheckboxItem
data-slot="dropdown-menu-checkbox-item"
data-inset={inset}
className={cn(
"relative flex cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-inset:pl-7 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className,
)}
checked={checked}
{...props}
>
<span
className="pointer-events-none absolute right-2 flex items-center justify-center"
data-slot="dropdown-menu-checkbox-item-indicator"
>
<DropdownMenuPrimitive.ItemIndicator>
<CheckIcon />
</DropdownMenuPrimitive.ItemIndicator>
</span>
{children}
</DropdownMenuPrimitive.CheckboxItem>
);
}

function DropdownMenuRadioGroup({
...props
}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {
return <DropdownMenuPrimitive.RadioGroup data-slot="dropdown-menu-radio-group" {...props} />;
}

function DropdownMenuRadioItem({
className,
children,
inset,
...props
}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem> & {
inset?: boolean;
}) {
return (
<DropdownMenuPrimitive.RadioItem
data-slot="dropdown-menu-radio-item"
data-inset={inset}
className={cn(
"relative flex cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-inset:pl-7 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className,
)}
{...props}
>
<span
className="pointer-events-none absolute right-2 flex items-center justify-center"
data-slot="dropdown-menu-radio-item-indicator"
>
<DropdownMenuPrimitive.ItemIndicator>
<CheckIcon />
</DropdownMenuPrimitive.ItemIndicator>
</span>
{children}
</DropdownMenuPrimitive.RadioItem>
);
}

function DropdownMenuLabel({
className,
inset,
Expand Down Expand Up @@ -174,77 +93,11 @@ function DropdownMenuSeparator({
);
}

function DropdownMenuShortcut({ className, ...props }: React.ComponentProps<"span">) {
return (
<span
data-slot="dropdown-menu-shortcut"
className={cn(
"ml-auto text-xs tracking-widest text-muted-foreground group-focus/dropdown-menu-item:text-accent-foreground",
className,
)}
{...props}
/>
);
}

function DropdownMenuSub({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {
return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />;
}

function DropdownMenuSubTrigger({
className,
inset,
children,
...props
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {
inset?: boolean;
}) {
return (
<DropdownMenuPrimitive.SubTrigger
data-slot="dropdown-menu-sub-trigger"
data-inset={inset}
className={cn(
"flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:pl-7 data-open:bg-accent data-open:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className,
)}
{...props}
>
{children}
<ChevronRightIcon className="ml-auto" />
</DropdownMenuPrimitive.SubTrigger>
);
}

function DropdownMenuSubContent({
className,
...props
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {
return (
<DropdownMenuPrimitive.SubContent
data-slot="dropdown-menu-sub-content"
className={cn(
"z-50 min-w-[96px] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-lg bg-popover p-1 text-popover-foreground shadow-lg ring-1 ring-foreground/10 duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
className,
)}
{...props}
/>
);
}

export {
DropdownMenu,
DropdownMenuPortal,
DropdownMenuTrigger,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuLabel,
DropdownMenuItem,
DropdownMenuCheckboxItem,
DropdownMenuRadioGroup,
DropdownMenuRadioItem,
DropdownMenuSeparator,
DropdownMenuShortcut,
DropdownMenuSub,
DropdownMenuSubTrigger,
DropdownMenuSubContent,
};
Loading
Loading