diff --git a/docs/docs/apps.md b/docs/docs/apps.md
index fd8facf..d7c74b4 100644
--- a/docs/docs/apps.md
+++ b/docs/docs/apps.md
@@ -19,6 +19,39 @@ There are 5 apps by default that come with RadixOS:
| Settings | `settings` | System customization and formatting | Tab-id |
| Image Viewer | `image` | Can open images | data:image or SVG |
+### Configuration
+
+You can configure some apps by passing a second argument to `setupApps`:
+
+```tsx
+const apps = setupApps([], {
+ terminalPlugins: [],
+ defaultAppsOnDesktop: ["terminal", "explorer"],
+});
+```
+
+### Terminal plugins
+
+You can pass extra matchers as plugins to the terminal application. This allows you to respond to commands and push output back to the terminal.
+
+```tsx
+const terminalPluginOpen: TerminalPlugin = {
+ matcher: (command) => command === "open",
+ exec: (pushOutput, command, args) => {
+ // do some stuff, then
+ pushOutput(
+
+ Opening "{args.join(" ")}"
+
+ );
+ },
+};
+
+const apps = setupApps([], {
+ terminalPlugins: [terminalPluginOpen],
+});
+```
+
## Creating your own applications
You can create apps by using `createApp`:
@@ -80,6 +113,14 @@ const { launch } = useAppLauncher();
launch("some-app", { ...settings });
```
+### Set default focus element
+
+To configure which element should be focused when the title-bar is clicked, or when the app is initially opened, you can set the following attribute on the HTML element: `data-returnfocus="true"`. Example:
+
+```tsx
+
+```
+
## Application Hooks
The app components are mounted inside `RadixOS`, which gives them access to a few hooks to control the operating system.
diff --git a/docs/docs/index.md b/docs/docs/index.md
index 4c8a1eb..5d9b97b 100644
--- a/docs/docs/index.md
+++ b/docs/docs/index.md
@@ -4,20 +4,25 @@ sidebar_position: 1
# Radix OS
-Radix OS is a operating system simulated on the web, with a modular file system that can be swapped out with any async source, able to run your own custom built applications. Designed to be flexible and easily extendable so it can fit your needs.
+Radix OS is an operating system simulated on the web, with a modular file system that can be swapped out with any async source, able to run your own custom built applications. Designed to be flexible and easily extendable so it can fit your needs.
[](https://imp-dance.github.io/radix-os/)
+:::tip So what it, really?
+
+A React component, coupled with a few helper functions and hooks - published to NPM. Together, this package lets you create an OS-like environment, and inject custom applications of your own.
+:::
+
## Features
- Window management
- Modular file system
- Customizable UI
- App launcher
-- Keyboard shortcuts
-- Context menus
- System UI components
-- Drag 'n drop file upload
+- Drag 'n drop user interface
+- Set of default applications
+ - Explorer, terminal, code, image viewer + more.
## Getting started
@@ -41,24 +46,24 @@ We also recommend that you install `@radix-ui/react-icons` if you plan on extend
```tsx title="lib/radix-os.ts"
import {
- fsZustandIntegration,
+ createZustandFsIntegration,
setupApps,
createUseAppLauncher
} from "radix-os;
export const applications = setupApps();
export const useAppLauncher = createUseAppLauncher(applications);
+export const fs = createZustandFsIntegration();
```
```tsx title="App.tsx"
import '@radix-ui/themes/styles.css';
import {
RadixOS,
- fsZustandIntegration
} from "radix-os;
-import { applications } from "./lib/radix-os";
+import { applications, fs } from "./lib/radix-os";
export default function App(){
- return
+ return
}
```
diff --git a/package.json b/package.json
index 91c987e..7fc8155 100644
--- a/package.json
+++ b/package.json
@@ -12,7 +12,7 @@
"dependencies": {
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/themes": "^3.1.4",
- "radix-os": "^0.2.0",
+ "radix-os": "^0.2.1",
"radix-ui": "^1.0.1",
"react": "^18.3.1",
"react-confetti": "^6.1.0",
diff --git a/packages/radix-os/package.json b/packages/radix-os/package.json
index ef0075f..00bcd5f 100644
--- a/packages/radix-os/package.json
+++ b/packages/radix-os/package.json
@@ -1,6 +1,6 @@
{
"name": "radix-os",
- "version": "0.2.0",
+ "version": "0.2.1",
"description": "A simulated operating system built with React and Radix UI",
"main": "dist/index.js",
"module": "dist/index.mjs",
diff --git a/packages/radix-os/src/components/Desktop/Desktop.tsx b/packages/radix-os/src/components/Desktop/Desktop.tsx
index df67909..349dda9 100644
--- a/packages/radix-os/src/components/Desktop/Desktop.tsx
+++ b/packages/radix-os/src/components/Desktop/Desktop.tsx
@@ -20,7 +20,10 @@ import {
useState,
} from "react";
import { DesktopShortcut } from "../../services/applications/desktop-shortcuts";
-import { useUntypedAppContext } from "../../services/applications/launcher";
+import {
+ UseAppLauncherReturn,
+ useUntypedAppContext,
+} from "../../services/applications/launcher";
import { useSettingsStore } from "../../stores/settings";
import { RadixOsApp } from "../../stores/window";
import { throttle } from "../../utils";
@@ -64,9 +67,11 @@ export function Desktop(props: {
icon: app.defaultWindowSettings?.icon ?? ,
title: app.appName,
id: app.appId,
- onClick: () => {
+ onClick: (() => {
launch(app.appId);
- },
+ }) as (
+ appLauncher: UseAppLauncherReturn
+ ) => void,
position: {
x: gridPad,
y: i > 0 ? gridSize * i + gridPad : gridPad,
@@ -248,9 +253,10 @@ function Application(props: {
icon: ReactNode;
title: string;
id: string;
- onClick: () => void;
+ onClick: (appLauncher: UseAppLauncherReturn) => void;
position: { x: number; y: number };
}) {
+ const appLauncher = useUntypedAppContext();
const [mousePosition, setMousePosition] = useState<{
x: number;
y: number;
@@ -294,7 +300,7 @@ function Application(props: {
style={style}
{...draggable.attributes}
{...draggable.listeners}
- onClick={props.onClick}
+ onClick={() => props.onClick(appLauncher)}
>
{props.icon}
diff --git a/packages/radix-os/src/components/WindowDragManager/WindowDragManager.tsx b/packages/radix-os/src/components/WindowDragManager/WindowDragManager.tsx
index a971591..c9f44dc 100644
--- a/packages/radix-os/src/components/WindowDragManager/WindowDragManager.tsx
+++ b/packages/radix-os/src/components/WindowDragManager/WindowDragManager.tsx
@@ -1,6 +1,7 @@
import {
DndContext,
MouseSensor,
+ pointerWithin,
useSensor,
} from "@dnd-kit/core";
import { ReactNode } from "react";
@@ -24,6 +25,7 @@ export function WindowDragManager(props: {
{
setIsDragging(false);
const window = windows.find(
diff --git a/packages/radix-os/src/components/apps/Settings/Settings.tsx b/packages/radix-os/src/components/apps/Settings/Settings.tsx
index badae0e..536e2cf 100644
--- a/packages/radix-os/src/components/apps/Settings/Settings.tsx
+++ b/packages/radix-os/src/components/apps/Settings/Settings.tsx
@@ -242,7 +242,6 @@ function StorageTab() {
-
+
+ Used space:{" "}
+ {getByteSize(localStorage.getItem(FS_LS_KEY) ?? "")}
+
);
}
+
+function getByteSize(s: string) {
+ return formatBytes(new Blob([s]).size);
+}
+
+function formatBytes(bytes: number, decimals = 2) {
+ if (!+bytes) return "0 Bytes";
+
+ const k = 1024;
+ const dm = decimals < 0 ? 0 : decimals;
+ const sizes = [
+ "Bytes",
+ "KiB",
+ "MiB",
+ "GiB",
+ "TiB",
+ "PiB",
+ "EiB",
+ "ZiB",
+ "YiB",
+ ];
+
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
+
+ return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${
+ sizes[i]
+ }`;
+}
diff --git a/packages/radix-os/src/components/apps/Terminal/Terminal.tsx b/packages/radix-os/src/components/apps/Terminal/Terminal.tsx
index baaf3b4..84d3ce4 100644
--- a/packages/radix-os/src/components/apps/Terminal/Terminal.tsx
+++ b/packages/radix-os/src/components/apps/Terminal/Terminal.tsx
@@ -8,6 +8,7 @@ import {
TextField,
} from "@radix-ui/themes";
import React, {
+ ComponentProps,
ReactNode,
useLayoutEffect,
useRef,
@@ -29,9 +30,37 @@ import { FsFolder } from "../../../stores/fs";
import { RadixOsAppComponent } from "../../../stores/window";
import { Command, helpText } from "./constants";
import { parseFs } from "./modules/fs";
-import { joinQuotedArgs } from "./utils";
+import { parseOpen } from "./modules/open";
+import { extractFlags, joinQuotedArgs } from "./utils";
-export const Terminal: RadixOsAppComponent = (props) => {
+export type TerminalPlugin = {
+ matcher: (command: string, args: string[]) => boolean;
+ exec: (
+ pushOutput: (...output: ReactNode[]) => void,
+ command: string,
+ args: string[]
+ ) => void;
+ /** Continue checking for other commands after exec, even if command is matched */
+ passThrough?: boolean;
+};
+
+function findLeafString(node: ReactNode): string {
+ if (typeof node === "string") return node;
+ if (typeof node === "number") return node.toString();
+ if (Array.isArray(node))
+ return node.map(findLeafString).join("");
+ if (node === null || node === undefined) return "";
+ if (typeof node === "object" && "props" in node) {
+ return findLeafString(node.props.children);
+ }
+ return "";
+}
+
+export const Terminal = (
+ props: ComponentProps & {
+ plugins?: TerminalPlugin[];
+ }
+) => {
const { openFile } = useUntypedAppContext();
const currentCommandIndex = useRef(0);
const prevCommands = useRef([]);
@@ -50,6 +79,11 @@ export const Terminal: RadixOsAppComponent = (props) => {
]);
function pushOutput(...output: ReactNode[]) {
+ /*const asText = output
+ .map((e) => findLeafString(e))
+ .join("\n")
+ .trim(); */
+
setOutput((prev) => [...prev, ...output]);
}
@@ -85,8 +119,27 @@ export const Terminal: RadixOsAppComponent = (props) => {
const parts = input.split(" ");
const [command, ...args_] = parts;
const args = joinQuotedArgs(args_);
+ const flags = extractFlags(args);
+ const plugins = props.plugins ?? [];
+ for (const plugin of plugins) {
+ if (plugin.matcher(command, args)) {
+ plugin.exec(pushOutput, command, args);
+ if (!plugin.passThrough) return;
+ }
+ }
if (command === "") return pushOutput(<>>);
switch (command) {
+ case "open": {
+ return parseOpen({
+ tree,
+ args,
+ cd: path.current.join("/"),
+ flags,
+ openFile,
+ pushOutput,
+ });
+ break;
+ }
case "echo": {
pushOutput(
{
updateFile: (path, file) =>
updateFile.mutateAsync({ path, file }),
tree: tree as FsFolder,
- openFile,
});
}
case "cd": {
diff --git a/packages/radix-os/src/components/apps/Terminal/constants.tsx b/packages/radix-os/src/components/apps/Terminal/constants.tsx
index ac67b8d..b575509 100644
--- a/packages/radix-os/src/components/apps/Terminal/constants.tsx
+++ b/packages/radix-os/src/components/apps/Terminal/constants.tsx
@@ -33,11 +33,22 @@ mkdir [name] - Create a new directory
ls - List files in current directory
cd [path] - Change directory
mv [path1] [path2] - Move file/folder from [path1] to [path2]
+open [path] - Open a file
+open --help - Show help for opening files
fs [path] -R [name] - Rename a file or folder
-fs [path] -O [launcher?] - Open a file
fs [path] -L [launcher] - Set a file's default launcher
fs [path] --ll - List a file's available launchers
fs [path] --ex [launcher] - Make file executable in given launcher
Relative paths are supported. Use quotes for paths with spaces.`;
+
+export const openHelpText = `Available flags for command "open":
+--help - Show this help message
+-l [launcher] - Open file with specific launcher
+-x [number] - Horizontal position of window
+-y [number] - Vertical position of window
+-w [number] - Width of window
+-h [number] - Height of window
+-r [true/false] - Resizable
+-s [true/false] - Scrollable`;
diff --git a/packages/radix-os/src/components/apps/Terminal/modules/fs.tsx b/packages/radix-os/src/components/apps/Terminal/modules/fs.tsx
index 9b6f476..45a9a66 100644
--- a/packages/radix-os/src/components/apps/Terminal/modules/fs.tsx
+++ b/packages/radix-os/src/components/apps/Terminal/modules/fs.tsx
@@ -1,6 +1,5 @@
import { Code } from "@radix-ui/themes";
import { ReactNode } from "react";
-import { useUntypedAppContext } from "../../../../services/applications/launcher";
import {
findNodeByPath,
isFile,
@@ -20,13 +19,11 @@ export function parseFs({
currentPath,
updateFile,
tree,
- openFile,
}: {
pushOutput: (...output: ReactNode[]) => void;
args: string[];
currentPath: string;
tree: FsFolder;
- openFile: ReturnType["openFile"];
updateFile: (
path: string,
file: Partial
@@ -71,7 +68,8 @@ export function parseFs({
updateFile(path, { name });
};
switch (flag) {
- case "-R": {
+ case "-R":
+ case "-r": {
const name = quotableRestArgs(restArgs);
if (!name) {
pushOutput(
@@ -94,32 +92,8 @@ export function parseFs({
);
}
- case "-O": {
- const launcher = restArgs[0];
- if (!isFile(node)) {
- return pushOutput(
-
- Not a file
-
- );
- }
- const validLaunchers = node.launcher;
- if (
- launcher &&
- !validLaunchers.includes(launcher as "code")
- ) {
- return pushOutput(
-
- Invalid launcher
-
- );
- }
- openFile({ file: node, path }, { launcher });
- return pushOutput(
-
- );
- }
- case "-L": {
+ case "-L":
+ case "-l": {
const launcher = restArgs[0];
if (!launcher) {
return pushOutput(
@@ -148,7 +122,8 @@ export function parseFs({
);
}
- case "--ll": {
+ case "--ll":
+ case "--LL": {
const node = findNodeByPath(path, tree);
if (!node) {
return pushOutput();
@@ -176,7 +151,8 @@ export function parseFs({
);
break;
}
- case "--ex": {
+ case "--ex":
+ case "--EX": {
const node = findNodeByPath(path, tree);
if (!node) {
return pushOutput();
diff --git a/packages/radix-os/src/components/apps/Terminal/modules/open.tsx b/packages/radix-os/src/components/apps/Terminal/modules/open.tsx
new file mode 100644
index 0000000..dd2d0ff
--- /dev/null
+++ b/packages/radix-os/src/components/apps/Terminal/modules/open.tsx
@@ -0,0 +1,71 @@
+import { Code } from "@radix-ui/themes";
+import { ReactNode } from "react";
+import { UseAppLauncherReturn } from "../../../../services/applications/launcher";
+import {
+ findNodeByPath,
+ isFile,
+ parseRelativePath,
+} from "../../../../services/fs/tree-helpers";
+import { FsNode } from "../../../../stores/fs";
+import { Command, openHelpText } from "../constants";
+
+export function parseOpen(opts: {
+ flags: Record;
+ args: string[];
+ pushOutput: (...output: ReactNode[]) => void;
+ openFile: UseAppLauncherReturn["openFile"];
+ cd: string;
+ tree: FsNode;
+}) {
+ const { flags, pushOutput, openFile, cd, args, tree } = opts;
+ if (flags && "help" in flags) {
+ return pushOutput(
+
+
+ {openHelpText}
+
+
+ );
+ }
+ const filePath = parseRelativePath(cd, args[0]);
+ const file = findNodeByPath(filePath, tree);
+ if (!isFile(file)) {
+ return pushOutput(
+
+ Not a file
+
+ );
+ }
+ let launcher = file.launcher[0];
+ if (flags.l && file.launcher.includes(flags.l)) {
+ launcher = flags.l;
+ }
+ openFile(
+ { file, path: filePath },
+ {
+ launcher,
+ x: flags.x ? parseInt(flags.x) : undefined,
+ y: flags.y ? parseInt(flags.y) : undefined,
+ initialWidth: flags.w ? parseInt(flags.w) : undefined,
+ initialHeight: flags.h ? parseInt(flags.h) : undefined,
+ resizeable:
+ flags.r === "true"
+ ? true
+ : flags.r === "false"
+ ? false
+ : undefined,
+ scrollable:
+ flags.s === "true"
+ ? true
+ : flags.s === "false"
+ ? false
+ : undefined,
+ }
+ );
+ return pushOutput(
+ ,
+
+ );
+}
diff --git a/packages/radix-os/src/components/apps/Terminal/utils.ts b/packages/radix-os/src/components/apps/Terminal/utils.ts
index 41f13e2..990d02b 100644
--- a/packages/radix-os/src/components/apps/Terminal/utils.ts
+++ b/packages/radix-os/src/components/apps/Terminal/utils.ts
@@ -52,3 +52,21 @@ export function joinQuotedArgs(args: string[]) {
});
return nextArgs;
}
+
+export function extractFlags(args: string[]) {
+ const flagRecord: Record = {};
+
+ args.forEach((arg, index) => {
+ if (arg.startsWith("--")) {
+ const flag = arg.slice(2);
+ const value = args[index + 1];
+ flagRecord[flag] = value;
+ } else if (arg.startsWith("-")) {
+ const flags = arg.slice(1);
+ const value = args[index + 1];
+ flagRecord[flags] = value;
+ }
+ });
+
+ return flagRecord;
+}
diff --git a/packages/radix-os/src/services/applications/desktop-shortcuts.ts b/packages/radix-os/src/services/applications/desktop-shortcuts.ts
index f08c78e..1179252 100644
--- a/packages/radix-os/src/services/applications/desktop-shortcuts.ts
+++ b/packages/radix-os/src/services/applications/desktop-shortcuts.ts
@@ -1,9 +1,10 @@
import { ReactNode } from "react";
+import { UseAppLauncherReturn } from "./launcher";
export type DesktopShortcut = {
icon: ReactNode;
label: string;
- onClick: () => void;
+ onClick: (appLauncher: UseAppLauncherReturn) => void;
};
export const setupDesktopShortcuts = (
...shortcuts: Array
diff --git a/packages/radix-os/src/services/applications/setupApps.ts b/packages/radix-os/src/services/applications/setupApps.ts
deleted file mode 100644
index 9c451af..0000000
--- a/packages/radix-os/src/services/applications/setupApps.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-import { defaultApps } from "../../defaultApps";
-import {
- RadixOsApp,
- RadixOsAppComponent,
-} from "../../stores/window";
-
-export type RadixAppList =
- readonly RadixOsApp[];
-
-export type DefaultApps =
- | "explorer"
- | "terminal"
- | "web"
- | "settings"
- | "code";
-
-export const createApp = (
- arg: RadixOsAppComponent
-): RadixOsAppComponent => arg;
-
-export const setupApps = <
- TProvided extends string,
- TActual extends string = string extends TProvided
- ? DefaultApps
- : TProvided | DefaultApps
->(
- apps: RadixAppList,
- options?: {
- defaultAppsOnDesktop?: DefaultApps[];
- }
-): RadixAppList => {
- const applications = Object.values(
- [
- ...defaultApps.map((app) => ({
- ...app,
- addToDesktop: options?.defaultAppsOnDesktop
- ? options.defaultAppsOnDesktop.includes(
- app.appId as "explorer"
- )
- : app.addToDesktop,
- })),
- ...(apps ?? []),
- ].reduce((acc, item) => {
- acc[item.appId] = item as RadixAppList[number];
- return acc;
- }, {} as Record[number]>)
- ) as unknown as RadixAppList;
-
- return applications;
-};
diff --git a/packages/radix-os/src/services/applications/setupApps.tsx b/packages/radix-os/src/services/applications/setupApps.tsx
new file mode 100644
index 0000000..98da9b7
--- /dev/null
+++ b/packages/radix-os/src/services/applications/setupApps.tsx
@@ -0,0 +1,86 @@
+import { ComponentProps } from "react";
+import {
+ Terminal,
+ TerminalPlugin,
+} from "../../components/apps/Terminal/Terminal";
+import { defaultApps } from "../../defaultApps";
+import {
+ RadixOsApp,
+ RadixOsAppComponent,
+} from "../../stores/window";
+
+export type RadixAppList =
+ readonly RadixOsApp[];
+
+export type DefaultApps =
+ | "explorer"
+ | "terminal"
+ | "web"
+ | "settings"
+ | "code";
+
+export type SetupAppsOptions = {
+ defaultAppsOnDesktop?: DefaultApps[];
+ terminalPlugins?: TerminalPlugin[];
+};
+
+export const createApp = (
+ arg: RadixOsAppComponent
+): RadixOsAppComponent => arg;
+
+/** Injects relevant props to default apps based on options */
+function defaultAppMapper(
+ application: (typeof defaultApps)[number],
+ options?: SetupAppsOptions
+) {
+ let component = application.component;
+ switch (application.appId) {
+ case "terminal":
+ if (options?.terminalPlugins) {
+ component = (props: ComponentProps) => {
+ return (
+
+ );
+ };
+ }
+ break;
+ default:
+ break;
+ }
+ return {
+ ...application,
+ addToDesktop: options?.defaultAppsOnDesktop
+ ? options.defaultAppsOnDesktop.includes(
+ application.appId as "explorer"
+ )
+ : application.addToDesktop,
+ component,
+ };
+}
+
+export const setupApps = <
+ TProvided extends string,
+ TActual extends string = string extends TProvided
+ ? DefaultApps
+ : TProvided | DefaultApps
+>(
+ apps: RadixAppList,
+ options?: SetupAppsOptions
+): RadixAppList => {
+ const applications = Object.values(
+ [
+ ...defaultApps.map((app) =>
+ defaultAppMapper(app, options)
+ ),
+ ...(apps ?? []),
+ ].reduce((acc, item) => {
+ acc[item.appId] = item as RadixAppList[number];
+ return acc;
+ }, {} as Record[number]>)
+ ) as unknown as RadixAppList;
+
+ return applications;
+};
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 33b6cd4..aa3a42c 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -15,8 +15,8 @@ importers:
specifier: ^3.1.4
version: 3.1.4(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
radix-os:
- specifier: ^0.2.0
- version: 0.2.0(@types/react-dom@18.3.0)(@types/react@18.3.9)(monaco-editor@0.52.0)
+ specifier: ^0.2.1
+ version: 0.2.1(@types/react-dom@18.3.0)(@types/react@18.3.9)(monaco-editor@0.52.0)
radix-ui:
specifier: ^1.0.1
version: 1.0.1(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -2040,8 +2040,8 @@ packages:
queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
- radix-os@0.2.0:
- resolution: {integrity: sha512-8GaLbRAABp3ZuVBtMFCCnud2PHcnD0Udt1Sy+09frCX5rHksib6svDXyTyqGPBWKlObm/kqJ0J0M+gaUxwmngQ==}
+ radix-os@0.2.1:
+ resolution: {integrity: sha512-CXa6YZIagQQu4eP7HPnj1sikofGZ2Tz5eoCXHVYFSPR5xlkK6s2UYx9D3JlwIrtOt93FW899E/U5ix3eu6sMWw==}
radix-ui@1.0.1:
resolution: {integrity: sha512-qfGibbqtbOlxP3b+1JjbLUc8Q7+e9DL8gFycLtkBkoAQyUkKuHAEBfFUcyG5MaQHjqRuML+YLtt/R1/dUYQafQ==}
@@ -4381,7 +4381,7 @@ snapshots:
queue-microtask@1.2.3: {}
- radix-os@0.2.0(@types/react-dom@18.3.0)(@types/react@18.3.9)(monaco-editor@0.52.0):
+ radix-os@0.2.1(@types/react-dom@18.3.0)(@types/react@18.3.9)(monaco-editor@0.52.0):
dependencies:
'@dnd-kit/core': 6.1.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@dnd-kit/modifiers': 7.0.0(@dnd-kit/core@6.1.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)
diff --git a/src/applications/ExampleApp.tsx b/src/applications/ExampleApp.tsx
index a73c321..eb7c032 100644
--- a/src/applications/ExampleApp.tsx
+++ b/src/applications/ExampleApp.tsx
@@ -9,7 +9,7 @@ export const ExampleApp = createApp((_props) => {
direction="column"
gap="3"
p="3"
- style={{ textAlign: "center" }}
+ style={{ textAlign: "center", userSelect: "none" }}
>
You can create custom apps