├── packages
├── console-ui
│ ├── select
│ │ └── index.ts
│ ├── toast
│ │ └── index.ts
│ ├── label-chip
│ │ └── index.ts
│ ├── checkbox
│ │ └── index.tsx
│ ├── README.md
│ ├── package.json
│ ├── index.ts
│ ├── divider
│ │ └── index.tsx
│ ├── form-field
│ │ └── index.ts
│ ├── LICENSE
│ ├── text-form-field
│ │ └── index.tsx
│ ├── text-field
│ │ └── index.tsx
│ └── button
│ │ └── index.tsx
├── editor-ui-breadcrumb
│ ├── index.ts
│ └── package.json
├── editor-ui-search
│ ├── index.ts
│ └── package.json
├── editor-ui
│ ├── lib
│ │ ├── layouts
│ │ │ └── README.md
│ │ ├── index.ts
│ │ ├── other
│ │ │ └── button
│ │ │ │ ├── index.tsx
│ │ │ │ └── button.stories.tsx
│ │ ├── dashboard
│ │ │ ├── guide
│ │ │ │ ├── index.tsx
│ │ │ │ └── guide.stories.tsx
│ │ │ ├── dashboard.tsx
│ │ │ ├── dashboard-cell
│ │ │ │ ├── index.tsx
│ │ │ │ └── dashbaord-cell.stories.tsx
│ │ │ └── dashboard.stories.tsx
│ │ ├── header
│ │ │ ├── menu
│ │ │ │ ├── index.tsx
│ │ │ │ └── menu.stories.tsx
│ │ │ ├── search-button
│ │ │ │ ├── index.tsx
│ │ │ │ └── search-button.stories.tsx
│ │ │ └── navigation-button
│ │ │ │ ├── index.tsx
│ │ │ │ └── navigation-button.stories.tsx
│ │ └── combined
│ │ │ └── property-layer
│ │ │ ├── only-text-field
│ │ │ ├── only-text-field.stories.mdx
│ │ │ └── index.tsx
│ │ │ ├── only-two-text-field
│ │ │ ├── only-text-field.stories.mdx
│ │ │ └── index.tsx
│ │ │ ├── text-field-n-toggle
│ │ │ ├── text-field-n-toggle.stories.mdx
│ │ │ └── index.tsx
│ │ │ ├── only-toggle
│ │ │ ├── index.tsx
│ │ │ └── only-toggle.stories.mdx
│ │ │ ├── text-filed-n-selector
│ │ │ ├── text-filed-n-selector.stories.mdx
│ │ │ └── index.tsx
│ │ │ └── text-field-n-silder
│ │ │ ├── text-field-n-silder.stories.mdx
│ │ │ └── index.tsx
│ ├── index.ts
│ └── package.json
├── README.md
├── editor-ui-button
│ ├── scaffolds
│ │ ├── text-button.tsx
│ │ ├── square-icon-button.tsx
│ │ ├── index.ts
│ │ ├── loading-button.tsx
│ │ └── default-button.tsx
│ ├── index.ts
│ ├── loading-indicator
│ │ ├── helpers
│ │ │ ├── index.ts
│ │ │ ├── colors.ts
│ │ │ ├── prop-types.ts
│ │ │ └── unit-converter.ts
│ │ ├── interfaces.ts
│ │ └── default-loading-indicator.tsx
│ └── package.json
├── editor-ui-property
│ ├── layout
│ │ ├── property-list.tsx
│ │ ├── property-input-cell.tsx
│ │ ├── index.ts
│ │ ├── dnd-item
│ │ │ └── index.tsx
│ │ └── dnd-wrapper
│ │ │ └── index.tsx
│ ├── readme.md
│ ├── tsconfig.json
│ ├── property-cell
│ │ ├── index.ts
│ │ ├── property-cell.stories.tsx
│ │ └── property-cell.tsx
│ ├── property-line
│ │ ├── index.ts
│ │ └── property-line.tsx
│ ├── property-group
│ │ ├── index.ts
│ │ ├── property-group.tsx
│ │ └── property-group.stories.tsx
│ ├── property-lines
│ │ ├── index.ts
│ │ ├── property-lines.tsx
│ │ └── property-lines.stories.tsx
│ ├── property-input-toggle-group
│ │ ├── index.ts
│ │ └── property-input-toggle-group.tsx
│ ├── property-input-color
│ │ ├── index.ts
│ │ └── property-input-color.tsx
│ ├── property-input-json
│ │ ├── index.ts
│ │ ├── readme.md
│ │ └── property-input-json.tsx
│ ├── property-group-header
│ │ ├── index.ts
│ │ ├── property-group-header.stories.tsx
│ │ └── property-group-header.tsx
│ ├── property-input-select
│ │ ├── index.ts
│ │ └── property-input-select.tsx
│ ├── property-input-slider
│ │ ├── index.ts
│ │ └── property-input-slider.tsx
│ ├── property-input-checkbox
│ │ ├── index.ts
│ │ └── property-input-checkbox.tsx
│ ├── theme-one
│ │ ├── index.ts
│ │ ├── light.ts
│ │ └── dark.ts
│ ├── property-input
│ │ ├── index.ts
│ │ ├── property-input.stories.tsx
│ │ └── property-input.tsx
│ ├── theme
│ │ ├── index.ts
│ │ ├── use-theme.ts
│ │ ├── styled.ts
│ │ ├── editor-ui-property-theme-provider.tsx
│ │ └── theme.ts
│ ├── .storybook
│ │ ├── main.js
│ │ └── preview.js
│ ├── css
│ │ └── index.ts
│ ├── index.ts
│ └── package.json
├── editor-ui-hierarchy
│ ├── hierarchy-layer-item
│ │ ├── index.ts
│ │ └── props.ts
│ ├── hierarchy-page-item
│ │ ├── index.ts
│ │ └── props.ts
│ ├── hierarchy-segment
│ │ ├── index.ts
│ │ └── hierarchy-segment.tsx
│ ├── hierarchy-segment-label
│ │ ├── index.ts
│ │ ├── hierarchy-segment-label.tsx
│ │ └── hierarchy-segment-label-scaffold.tsx
│ ├── index.ts
│ ├── package.json
│ ├── hierachy.stories.mdx
│ ├── hierachy.tsx
│ ├── item
│ │ ├── item.stories.mdx
│ │ └── index.tsx
│ └── tree-view.tsx
├── editor-ui-multiplayer
│ ├── multiplayer-cursor
│ │ └── index.ts
│ ├── multiplayer-avatar
│ │ ├── index.ts
│ │ └── multiplayer-avatar.tsx
│ ├── multiplayer-avatar-group
│ │ ├── index.ts
│ │ └── multiplayer-avatar-group.tsx
│ ├── index.ts
│ └── package.json
├── editor-ui-panel
│ ├── README.md
│ └── package.json
├── editor-ui-tooltip
│ ├── index.ts
│ ├── tooltip
│ │ ├── index.ts
│ │ └── tooltip.tsx
│ └── package.json
├── editor-ui-menu
│ ├── index.ts
│ ├── _internal
│ │ ├── index.ts
│ │ └── menu.tsx
│ ├── README.md
│ └── package.json
├── editor-ui-sortable
│ ├── index.ts
│ ├── README.md
│ ├── package.json
│ ├── LICENSE
│ └── sortable.tsx
├── editor-ui-workspace
│ ├── index.ts
│ ├── package.json
│ └── layouts
│ │ ├── index.ts
│ │ ├── workspace-layout
│ │ └── index.tsx
│ │ └── home-scaffold
│ │ └── index.tsx
├── editor-ui-shortcut
│ ├── README.md
│ ├── package.json
│ └── CONTRIBUTING.md
├── editor-ui-alert-dialog
│ ├── index.ts
│ ├── package.json
│ └── alert-dialog.tsx
├── editor-ui-color-picker
│ ├── index.ts
│ ├── color-picker.tsx
│ └── package.json
├── editor-ui-context-menu
│ ├── index.tsx
│ ├── context-menu
│ │ ├── index.ts
│ │ ├── context-menu-separator.tsx
│ │ ├── context-menu-root.tsx
│ │ └── context-menu-item.tsx
│ └── package.json
├── editor-ui-dropdown-menu
│ ├── index.ts
│ ├── package.json
│ └── dropdown-menu.tsx
├── editor-ui-desktop-titlebar
│ ├── index.ts
│ ├── README.md
│ ├── package.json
│ └── bar-drag-area.tsx
├── editor-ui-scroll-area
│ ├── index.ts
│ ├── README.md
│ ├── package.json
│ ├── LICENSE
│ └── scroll-area.tsx
├── editor-ui-hooks
│ ├── index.ts
│ ├── package.json
│ ├── use-window-size.ts
│ └── use-hover.ts
├── editor-ui-spacer
│ ├── index.ts
│ ├── package.json
│ └── spacer.ts
├── editor-ui-listview
│ ├── index.ts
│ ├── README.md
│ ├── package.json
│ └── LICENSE
├── editor-ui-toolbar
│ └── package.json
├── editor-ui-utils
│ ├── index.ts
│ ├── package.json
│ ├── with-separator.ts
│ └── merge-event-handlers.ts
├── editor-ui-dialog
│ ├── index.ts
│ ├── dialog-control.ts
│ ├── package.json
│ ├── README.md
│ ├── dialog-context-provider.tsx
│ └── dialog.tsx
├── editor-ui-foundation
│ └── package.json
├── editor-ui-icons
│ ├── package.json
│ ├── icons.stories.mdx
│ ├── index.tsx
│ └── icons.tsx
└── editor-ui-theme
│ ├── media-query.ts
│ ├── package.json
│ ├── index.ts
│ ├── dark.ts
│ ├── theme-provider.tsx
│ └── light.ts
├── branding
└── cover.png
├── .prettierrc
├── examples
└── README.md
├── .storybook
├── preview.js
└── main.js
├── tsconfig.json
├── CONTRIBUTING.md
├── .github
└── workflows
│ └── chromatic.yml
├── LICENSE
├── package.json
├── README.md
└── .gitignore
/packages/console-ui/select/index.ts:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/console-ui/toast/index.ts:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/editor-ui-breadcrumb/index.ts:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/editor-ui-search/index.ts:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/console-ui/label-chip/index.ts:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/editor-ui/lib/layouts/README.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/README.md:
--------------------------------------------------------------------------------
1 | # `@editor-ui` pacakges
2 |
--------------------------------------------------------------------------------
/packages/editor-ui-button/scaffolds/text-button.tsx:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/layout/property-list.tsx:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/editor-ui-button/scaffolds/square-icon-button.tsx:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/editor-ui-hierarchy/hierarchy-layer-item/index.ts:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/editor-ui-hierarchy/hierarchy-page-item/index.ts:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/editor-ui-multiplayer/multiplayer-cursor/index.ts:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/layout/property-input-cell.tsx:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/editor-ui/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./lib";
2 |
--------------------------------------------------------------------------------
/packages/editor-ui-button/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./scaffolds"
--------------------------------------------------------------------------------
/packages/editor-ui-panel/README.md:
--------------------------------------------------------------------------------
1 | # `@editor-ui/panel`
2 |
--------------------------------------------------------------------------------
/packages/editor-ui-tooltip/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./tooltip"
--------------------------------------------------------------------------------
/packages/editor-ui-menu/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./_internal";
2 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/readme.md:
--------------------------------------------------------------------------------
1 | # `@editor-ui/property`
2 |
--------------------------------------------------------------------------------
/packages/editor-ui-sortable/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./sortable";
2 |
--------------------------------------------------------------------------------
/packages/editor-ui-tooltip/tooltip/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./tooltip"
--------------------------------------------------------------------------------
/packages/editor-ui-workspace/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./layouts";
2 |
--------------------------------------------------------------------------------
/packages/console-ui/checkbox/index.tsx:
--------------------------------------------------------------------------------
1 | export function Checkbox() {}
2 |
--------------------------------------------------------------------------------
/packages/editor-ui-menu/_internal/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./menu";
2 |
--------------------------------------------------------------------------------
/packages/editor-ui-shortcut/README.md:
--------------------------------------------------------------------------------
1 | # Keymaps & Shortcut utility
2 |
--------------------------------------------------------------------------------
/packages/editor-ui-alert-dialog/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./alert-dialog";
2 |
--------------------------------------------------------------------------------
/packages/editor-ui-color-picker/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./color-picker";
2 |
--------------------------------------------------------------------------------
/packages/editor-ui-context-menu/index.tsx:
--------------------------------------------------------------------------------
1 | export * from "./context-menu";
2 |
--------------------------------------------------------------------------------
/packages/editor-ui-dropdown-menu/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./dropdown-menu";
2 |
--------------------------------------------------------------------------------
/packages/editor-ui-desktop-titlebar/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./bar-drag-area";
2 |
--------------------------------------------------------------------------------
/branding/cover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gridaco/editor-ui/HEAD/branding/cover.png
--------------------------------------------------------------------------------
/packages/editor-ui-property/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json"
3 | }
4 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "useTabs": false,
3 | "trailingComma": "es5",
4 | "semi": true
5 | }
--------------------------------------------------------------------------------
/packages/editor-ui-hierarchy/hierarchy-layer-item/props.ts:
--------------------------------------------------------------------------------
1 | export interface LayerItemProps {}
2 |
--------------------------------------------------------------------------------
/packages/editor-ui-hierarchy/hierarchy-segment/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./hierarchy-segment";
2 |
--------------------------------------------------------------------------------
/packages/editor-ui-scroll-area/index.ts:
--------------------------------------------------------------------------------
1 | export { default as default } from "./scroll-area";
2 |
--------------------------------------------------------------------------------
/packages/editor-ui-desktop-titlebar/README.md:
--------------------------------------------------------------------------------
1 | # Titlebar for frameless electron application (macOS)
2 |
--------------------------------------------------------------------------------
/packages/editor-ui-multiplayer/multiplayer-avatar/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./multiplayer-avatar";
2 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/property-cell/index.ts:
--------------------------------------------------------------------------------
1 | export { PropertyCell } from "./property-cell";
2 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/property-line/index.ts:
--------------------------------------------------------------------------------
1 | export { PropertyLine } from "./property-line";
2 |
--------------------------------------------------------------------------------
/packages/editor-ui-hooks/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./use-hover";
2 | export * from "./use-window-size";
3 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/property-group/index.ts:
--------------------------------------------------------------------------------
1 | export { PropertyGroup } from "./property-group";
2 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/property-lines/index.ts:
--------------------------------------------------------------------------------
1 | export { PropertyLines } from "./property-lines";
2 |
--------------------------------------------------------------------------------
/packages/editor-ui-spacer/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./spacer";
2 | export * as Spacer from "./spacer";
3 |
--------------------------------------------------------------------------------
/packages/editor-ui-listview/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./listview";
2 | export * as ListView from "./listview";
3 |
--------------------------------------------------------------------------------
/packages/editor-ui-multiplayer/multiplayer-avatar-group/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./multiplayer-avatar-group";
2 |
--------------------------------------------------------------------------------
/packages/editor-ui-search/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@editor-ui/search",
3 | "version": "0.0.0"
4 | }
--------------------------------------------------------------------------------
/packages/editor-ui-shortcut/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@editor-ui/shortcut",
3 | "version": "0.0.0"
4 | }
--------------------------------------------------------------------------------
/packages/editor-ui-toolbar/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@editor-ui/toolbar",
3 | "version": "0.0.0"
4 | }
--------------------------------------------------------------------------------
/packages/editor-ui-breadcrumb/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@editor-ui/breadcrumb",
3 | "version": "0.0.0"
4 | }
--------------------------------------------------------------------------------
/packages/editor-ui-property/property-input-toggle-group/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./property-input-toggle-group";
2 |
--------------------------------------------------------------------------------
/packages/editor-ui-utils/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./with-separator";
2 | export * from "./merge-event-handlers";
3 |
--------------------------------------------------------------------------------
/packages/editor-ui-workspace/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@editor-ui/workspace",
3 | "version": "0.0.0"
4 | }
--------------------------------------------------------------------------------
/packages/editor-ui-button/scaffolds/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./default-button";
2 | export * from "./loading-button";
3 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/property-input-color/index.ts:
--------------------------------------------------------------------------------
1 | export { PropertyColorInput } from "./property-input-color";
2 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/property-input-json/index.ts:
--------------------------------------------------------------------------------
1 | export { PropertyJsonInput } from "./property-input-json";
2 |
--------------------------------------------------------------------------------
/packages/editor-ui-workspace/layouts/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./home-scaffold";
2 | export * from "./workspace-layout";
3 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/property-group-header/index.ts:
--------------------------------------------------------------------------------
1 | export { PropertyGroupHeader } from "./property-group-header";
2 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/property-input-select/index.ts:
--------------------------------------------------------------------------------
1 | export { PropertySelectInput } from "./property-input-select";
2 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/property-input-slider/index.ts:
--------------------------------------------------------------------------------
1 | export { PropertySliderInput } from "./property-input-slider";
2 |
--------------------------------------------------------------------------------
/packages/editor-ui-multiplayer/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./multiplayer-avatar";
2 | export * from "./multiplayer-avatar-group";
3 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/property-input-checkbox/index.ts:
--------------------------------------------------------------------------------
1 | export { PropertyCheckboxInput } from "./property-input-checkbox";
2 |
--------------------------------------------------------------------------------
/packages/console-ui/README.md:
--------------------------------------------------------------------------------
1 | # @editor-ui/console
2 | Reflect UI Package for Console web applications Powering General Grida UIs.
3 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/theme-one/index.ts:
--------------------------------------------------------------------------------
1 | export { default as light } from "./light";
2 | export { default as dark } from "./dark";
3 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/property-input-json/readme.md:
--------------------------------------------------------------------------------
1 | ## References
2 |
3 | - react-json-editor-ajrm
4 | - react-json-view
5 | - react-json-tree
6 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/property-input/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./property-input";
2 | export type { PropertyInputProps } from "./property-input";
3 |
--------------------------------------------------------------------------------
/packages/editor-ui-button/loading-indicator/helpers/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./prop-types";
2 | export * from "./colors";
3 | export * from "./unit-converter";
4 |
--------------------------------------------------------------------------------
/packages/editor-ui-hierarchy/hierarchy-segment-label/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./hierarchy-segment-label";
2 | export * from "./hierarchy-segment-label-scaffold";
3 |
--------------------------------------------------------------------------------
/packages/editor-ui-hierarchy/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./tree-view";
2 | export * as TreeView from "./tree-view";
3 | export * from "./hierachy";
4 | // export * from "./item";
5 |
--------------------------------------------------------------------------------
/packages/editor-ui-context-menu/context-menu/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./context-menu-item";
2 | export * from "./context-menu-root";
3 | export * from "./context-menu-separator";
4 |
--------------------------------------------------------------------------------
/packages/editor-ui-panel/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@editor-ui/panel",
3 | "version": "0.0.0",
4 | "dependencies": {
5 | "@editor-ui/foundation": "workspace:^"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/packages/editor-ui-dialog/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./dialog";
2 | export { ModalContextProvider } from "./dialog-context-provider";
3 | export { showDialog, create } from "./dialog-control";
4 |
--------------------------------------------------------------------------------
/packages/editor-ui-foundation/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@editor-ui/foundation",
3 | "version": "0.0.0",
4 | "dependencies": {
5 | "@editor-ui/theme": "workspace:*"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/layout/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./dnd-item";
2 | export * from "./dnd-wrapper";
3 | // export * from "./property-input-cell";
4 | // export * from "./property-list";
5 |
--------------------------------------------------------------------------------
/packages/editor-ui-shortcut/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ## Technical References
2 |
3 | > This are the official projects we reference to build this package.
4 |
5 | - react-hotkeys-hook
6 | - monaco-editor
7 |
--------------------------------------------------------------------------------
/packages/editor-ui-desktop-titlebar/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@editor-ui/desktop-titlebar",
3 | "version": "0.0.0",
4 | "dependencies": {
5 | "@editor-ui/foundation": "workspace:^"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/packages/editor-ui-multiplayer/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@editor-ui/multiplayer",
3 | "version": "0.0.0",
4 | "dependencies": {
5 | "@radix-ui/react-avatar": "^0.0.14"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/property-input-json/property-input-json.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | /**
4 | * @deprecated not ready yet
5 | */
6 | export function PropertyJsonInput() {
7 | return <>>;
8 | }
9 |
--------------------------------------------------------------------------------
/packages/console-ui/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@editor-ui/console",
3 | "version": "0.0.0",
4 | "dependencies": {
5 | "@radix-ui/react-toast": "^1.0.0",
6 | "install": "^0.13.0",
7 | "npm": "^8.18.0"
8 | }
9 | }
--------------------------------------------------------------------------------
/packages/editor-ui-property/theme/index.ts:
--------------------------------------------------------------------------------
1 | export { EditorPropertyThemeProvider } from "./editor-ui-property-theme-provider";
2 | export type { EditorPropertyTheme } from "./theme";
3 | export { useTheme } from "./use-theme";
4 |
--------------------------------------------------------------------------------
/examples/README.md:
--------------------------------------------------------------------------------
1 | # Examples
2 |
3 | ## simple
4 |
5 | ## usage in production
6 |
7 | - [bridged](https://github.com/bridgedxyz/bridged)
8 |
9 | ## realwork copy example
10 |
11 | - vscode
12 | - notion
13 | - sketch
14 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/theme/use-theme.ts:
--------------------------------------------------------------------------------
1 | import { useTheme as _useTheme } from "@emotion/react";
2 | import { EditorPropertyTheme } from "./theme";
3 |
4 | export const useTheme: () => EditorPropertyTheme = _useTheme as any;
5 |
--------------------------------------------------------------------------------
/packages/editor-ui/lib/index.ts:
--------------------------------------------------------------------------------
1 | export * from "@editor-ui/hierarchy";
2 | export * as hooks from "@editor-ui/hooks";
3 | export * from "@editor-ui/button";
4 | export * from "@editor-ui/spacer";
5 | export * from "@editor-ui/utils";
6 |
--------------------------------------------------------------------------------
/.storybook/preview.js:
--------------------------------------------------------------------------------
1 |
2 | export const parameters = {
3 | actions: { argTypesRegex: "^on[A-Z].*" },
4 | controls: {
5 | matchers: {
6 | color: /(background|color)$/i,
7 | date: /Date$/,
8 | },
9 | },
10 | }
--------------------------------------------------------------------------------
/packages/editor-ui-dialog/dialog-control.ts:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { create as _create } from "react-modal-promise";
3 | //
4 | export function showDialog(d) {
5 | _create(d)();
6 | }
7 | export const create = _create;
8 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": false,
4 | "module": "esnext",
5 | "target": "ES2017",
6 | "jsx": "react",
7 | "moduleResolution": "node",
8 | "esModuleInterop": true
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/packages/editor-ui-sortable/README.md:
--------------------------------------------------------------------------------
1 | # Sortable
2 |
3 | ## Disclaimer
4 |
5 | > This package was originally copied from [here](https://github.com/noya-app/noya/blob/main/packages/noya-designsystem/src/components/Sortable.tsx) under MIT License @2021.9
6 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to Reflect Editor UI
2 |
3 | ## Read reflect-ui contribution guideline first
4 |
5 | WIP
6 |
7 | ## General React Coding conventions
8 |
9 | https://github.com/bridgedxyz/.github/blob/main/contributing/react.md
10 |
--------------------------------------------------------------------------------
/packages/editor-ui-dropdown-menu/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@editor-ui/dropdown-menu",
3 | "version": "0.0.0",
4 | "private": false,
5 | "dependencies": {
6 | "@radix-ui/react-dropdown-menu": "^2.0.6",
7 | "@stitches/react": "^1.2.8"
8 | }
9 | }
--------------------------------------------------------------------------------
/packages/editor-ui/lib/other/button/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styled from '@emotion/styled';
3 |
4 | function Button() {
5 | return (
6 |
7 |
8 |
9 | )
10 | }
11 |
12 | export default Button
13 |
--------------------------------------------------------------------------------
/packages/editor-ui-dialog/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@editor-ui/dialog",
3 | "version": "0.0.0",
4 | "main": "index.ts",
5 | "dependencies": {
6 | "@radix-ui/react-dialog": "^0.0.19",
7 | "react-modal-promise": "^0.7.6"
8 | }
9 | }
--------------------------------------------------------------------------------
/packages/editor-ui-scroll-area/README.md:
--------------------------------------------------------------------------------
1 | # Scroll Area
2 |
3 | ## Disclaimer
4 |
5 | > This package was originally copied from [here](https://github.com/noya-app/noya/blob/main/packages/noya-designsystem/src/components/ScrollArea.tsx) under MIT License @2021.9
6 |
--------------------------------------------------------------------------------
/packages/editor-ui-menu/README.md:
--------------------------------------------------------------------------------
1 | # `@editor-ui/menu`
2 |
3 | ## References
4 |
5 | - https://developer.apple.com/design/human-interface-guidelines/macos/menus/menu-anatomy/
6 | - https://developer.apple.com/design/human-interface-guidelines/macos/menus/menu-bar-menus/
7 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/theme/styled.ts:
--------------------------------------------------------------------------------
1 | import styled from "@emotion/styled";
2 | import { EditorPropertyTheme } from "./theme";
3 |
4 | declare module "@emotion/react" {
5 | export interface Theme extends EditorPropertyTheme {}
6 | }
7 |
8 | export default styled;
9 |
--------------------------------------------------------------------------------
/packages/editor-ui-color-picker/color-picker.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { RgbaColorPicker } from "react-colorful";
3 |
4 | export function ColorPicker(
5 | props: React.ComponentProps
6 | ) {
7 | return ;
8 | }
9 |
--------------------------------------------------------------------------------
/packages/editor-ui/lib/dashboard/guide/index.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import styled from '@emotion/styled';
3 |
4 | export interface DashboardGuideProps {}
5 |
6 | function DashboardGuide(props: DashboardGuideProps) {
7 | return
;
8 | }
9 |
10 | export default DashboardGuide;
11 |
--------------------------------------------------------------------------------
/packages/editor-ui-hierarchy/hierarchy-page-item/props.ts:
--------------------------------------------------------------------------------
1 | export interface SinglePageItemProps {
2 | icon: string;
3 | name: string;
4 | expanded: boolean;
5 | depth: number;
6 | }
7 |
8 | export interface PageItemTreeProps extends SinglePageItemProps {
9 | children?: PageItemTreeProps[];
10 | }
11 |
--------------------------------------------------------------------------------
/packages/editor-ui-dialog/README.md:
--------------------------------------------------------------------------------
1 | # `@editor-ui/doalog` _(modal)_
2 |
3 | ```sh
4 | yarn add @editor-ui/dialog
5 | ```
6 |
7 | ## Usage
8 |
9 | ```tsx
10 | import { showModal } from "@editor-ui/dialog";
11 |
12 | showModal(<>Hi>).then((d) => {
13 | // do something with modal result
14 | });
15 | ```
16 |
--------------------------------------------------------------------------------
/packages/console-ui/index.ts:
--------------------------------------------------------------------------------
1 | export { TextFormField } from "./text-form-field";
2 | export { TextField } from "./text-field";
3 | export { Button } from "./button";
4 | export { Divider } from "./divider";
5 | export {
6 | FormFieldBase,
7 | FormFieldLabel,
8 | FormFieldAssisiveText,
9 | } from "./form-field";
10 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/.storybook/main.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | stories: ["../**/*.stories.mdx", "../**/*.stories.@(js|jsx|ts|tsx)"],
3 | addons: [
4 | "@storybook/addon-links",
5 | "@storybook/addon-essentials",
6 | "@storybook/addon-interactions",
7 | ],
8 | framework: "@storybook/react",
9 | };
10 |
--------------------------------------------------------------------------------
/packages/editor-ui/lib/dashboard/dashboard.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styled from '@emotion/styled';
3 | export interface DashBoardProps {
4 |
5 | }
6 |
7 | function DashBoard(props: DashBoardProps) {
8 | return (
9 |
10 |
11 |
12 | )
13 | }
14 |
15 | export default DashBoard
16 |
--------------------------------------------------------------------------------
/packages/editor-ui/lib/header/menu/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styled from '@emotion/styled';
3 |
4 | export interface HeaderMenuProps {
5 |
6 | }
7 |
8 | function HeaderMenu(props : HeaderMenuProps) {
9 | return (
10 |
11 |
12 |
13 | )
14 | }
15 |
16 | export default HeaderMenu
17 |
--------------------------------------------------------------------------------
/packages/editor-ui-spacer/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@editor-ui/spacer",
3 | "version": "0.0.0",
4 | "dependencies": {
5 | "@editor-ui/foundation": "workspace:^"
6 | },
7 | "devDependencies": {
8 | "@emotion/styled": "^11.11.0"
9 | },
10 | "peerDependencies": {
11 | "@emotion/styled": "^11.11.0"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/packages/editor-ui/lib/dashboard/dashboard-cell/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styled from '@emotion/styled';
3 |
4 | export interface DashboardCellProps {
5 |
6 | }
7 |
8 | function DashboardCell(props : DashboardCellProps) {
9 | return (
10 |
11 |
12 |
13 | )
14 | }
15 |
16 | export default DashboardCell
17 |
--------------------------------------------------------------------------------
/packages/editor-ui-dialog/dialog-context-provider.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ModalContainer from "react-modal-promise";
3 |
4 | export function ModalContextProvider(props: {
5 | children: React.ReactNode | React.ReactNode[];
6 | }) {
7 | return (
8 | <>
9 |
10 | {props.children}
11 | >
12 | );
13 | }
14 |
--------------------------------------------------------------------------------
/packages/editor-ui-menu/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@editor-ui/menu",
3 | "version": "0.0.0",
4 | "dependencies": {
5 | "@editor-ui/foundation": "workspace:^",
6 | "@editor-ui/theme": "workspace:^"
7 | },
8 | "devDependencies": {
9 | "@emotion/css": "^11.11.2"
10 | },
11 | "peerDependencies": {
12 | "@emotion/css": "^11.11.2"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/packages/editor-ui-listview/README.md:
--------------------------------------------------------------------------------
1 | # List view with dnd & sortable
2 |
3 | ## LICENSE - MIT
4 |
5 | This package was initially copy & pasted from noya design system.
6 |
7 | ## Disclaimer
8 |
9 | > This package was originally copied from [here](https://github.com/noya-app/noya/blob/main/packages/noya-designsystem/src/components/ListView.tsx) under MIT License @2021.9
10 |
--------------------------------------------------------------------------------
/packages/editor-ui/lib/header/search-button/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styled from '@emotion/styled';
3 |
4 | export interface HeaderSearchButtonProps {
5 |
6 | }
7 |
8 | function HeaderSearchButton(props : HeaderSearchButtonProps) {
9 | return (
10 |
11 |
12 |
13 | )
14 | }
15 |
16 | export default HeaderSearchButton
17 |
--------------------------------------------------------------------------------
/packages/console-ui/divider/index.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import styled from "@emotion/styled";
3 |
4 | export function Divider({
5 | width,
6 | }: {
7 | width?: React.CSSProperties["width"] | "full";
8 | }) {
9 | return ;
10 | }
11 |
12 | const Line = styled.hr`
13 | border: none;
14 | border-top: solid 1px rgba(0, 0, 0, 0.15);
15 | width: 100%;
16 | `;
17 |
--------------------------------------------------------------------------------
/packages/editor-ui-color-picker/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@editor-ui/color-picker",
3 | "version": "0.0.0",
4 | "dependencies": {
5 | "react-colorful": "^5.6.1"
6 | },
7 | "devDependencies": {
8 | "@types/react": "18.2.58",
9 | "react": "^18.2.0"
10 | },
11 | "peerDependencies": {
12 | "@types/react": "18.2.58",
13 | "react": "^18.2.0"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/packages/editor-ui-hierarchy/hierarchy-segment-label/hierarchy-segment-label.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import styled from "@emotion/styled";
3 | export function HierarchySegmentLabel(props: {
4 | name: string;
5 | expandToggle: JSX.Element;
6 | actions: JSX.Element[];
7 | }) {
8 | return {props.name} ;
9 | }
10 |
11 | const Wrapper = styled.div``;
12 |
--------------------------------------------------------------------------------
/packages/editor-ui-context-menu/context-menu/context-menu-separator.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import styled from "@emotion/styled";
3 | import { SEPARATOR_ITEM, styles } from "@editor-ui/menu";
4 | import { Separator as _Separator } from "@radix-ui/react-context-menu";
5 |
6 | export { SEPARATOR_ITEM };
7 |
8 | export const ContextMenuSeparator = styled(_Separator)(styles.separatorStyle);
9 |
--------------------------------------------------------------------------------
/packages/editor-ui-hooks/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@editor-ui/hooks",
3 | "version": "0.0.0",
4 | "description": "React hooks fro editor-ui on for react",
5 | "devDependencies": {
6 | "@types/react": "18.2.58",
7 | "react": "^18.2.0"
8 | },
9 | "peerDependencies": {
10 | "@types/react": "18.2.58",
11 | "react": "^18.2.0"
12 | }
13 | }
--------------------------------------------------------------------------------
/packages/editor-ui/lib/header/navigation-button/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styled from '@emotion/styled';
3 |
4 | export interface HeadernavigationButtonProps {
5 |
6 | }
7 |
8 | function HeaderNavigationButton(props : HeadernavigationButtonProps) {
9 | return (
10 |
11 |
12 |
13 | )
14 | }
15 |
16 | export default HeaderNavigationButton
17 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/property-group/property-group.tsx:
--------------------------------------------------------------------------------
1 | import styled from "@emotion/styled";
2 | import React from "react";
3 |
4 | export function PropertyGroup({ children }: React.PropsWithChildren<{}>) {
5 | return {children} ;
6 | }
7 |
8 | const PropertyGroupContainer = styled.div`
9 | display: flex;
10 | flex-direction: column;
11 | `;
12 |
--------------------------------------------------------------------------------
/packages/editor-ui/lib/other/button/button.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Story, Meta } from "@storybook/react";
3 |
4 | import Button from "./";
5 |
6 | export default {
7 | title: "Other/Button",
8 | component: Button,
9 | } as Meta;
10 |
11 | const Template: Story = (args) => ;
12 |
13 | export const Basic = Template.bind({});
14 | Basic.args = {};
15 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/property-group-header/property-group-header.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { PropertyGroupHeader } from "./property-group-header";
3 |
4 | export default {
5 | title: "property-group-header",
6 | component: PropertyGroupHeader,
7 | };
8 |
9 | export const Primary = () => (
10 |
11 | Layout
12 |
13 | );
14 |
--------------------------------------------------------------------------------
/packages/editor-ui-alert-dialog/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@editor-ui/alert-dialog",
3 | "version": "0.0.0",
4 | "dependencies": {
5 | "@radix-ui/react-alert-dialog": "^1.0.5",
6 | "@stitches/react": "^1.2.8"
7 | },
8 | "devDependencies": {
9 | "@radix-ui/react-dialog": "^1.0.5",
10 | "@types/react": "18.2.58"
11 | },
12 | "peerDependencies": {
13 | "@radix-ui/react-dialog": "^1.0.5"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/packages/editor-ui-hierarchy/hierarchy-segment-label/hierarchy-segment-label-scaffold.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { HierarchySegmentLabel } from "./hierarchy-segment-label";
3 | import styled from "@emotion/styled";
4 | export function HierarchySegmentLabelScaffold(props: {
5 | name: string;
6 | toggle?: boolean;
7 | initialExpanded: boolean;
8 | }) {
9 | return ;
10 | }
11 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/theme-one/light.ts:
--------------------------------------------------------------------------------
1 | import type { EditorPropertyTheme } from "../theme";
2 |
3 | const light: EditorPropertyTheme = {
4 | input: {
5 | bg: "#F8F8F8",
6 | prefix: "#B6B6B6",
7 | suffix: "#B6B6B6",
8 | value: "black",
9 | value_disabled: "#B6B6B6",
10 | border: {
11 | focus: "#B6B6B6",
12 | },
13 | },
14 | foreground: "black",
15 | };
16 |
17 | export default light;
18 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/theme/editor-ui-property-theme-provider.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { ThemeProvider } from "@emotion/react";
3 | import type { EditorPropertyTheme } from "./theme";
4 |
5 | export function EditorPropertyThemeProvider({
6 | theme,
7 | children,
8 | }: React.PropsWithChildren<{
9 | theme: EditorPropertyTheme;
10 | }>) {
11 | return {children} ;
12 | }
13 |
--------------------------------------------------------------------------------
/packages/editor-ui/lib/header/menu/menu.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Story, Meta } from "@storybook/react";
3 |
4 | import HeaderMenu, { HeaderMenuProps } from "./";
5 |
6 | export default {
7 | title: "Header/Dashboard",
8 | component: HeaderMenu,
9 | } as Meta;
10 |
11 | const Template: Story = (args) => ;
12 |
13 | export const Basic = Template.bind({});
14 | Basic.args = {};
15 |
--------------------------------------------------------------------------------
/.storybook/main.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | stories: [
3 | "../packages/**/*.stories.mdx",
4 | "../packages/**/*.stories.@(js|jsx|ts|tsx)",
5 | ],
6 | addons: [
7 | "@storybook/preset-create-react-app",
8 | "@storybook/addon-actions",
9 | "@storybook/addon-links",
10 | "@storybook/addon-essentials",
11 | "@storybook/preset-create-react-app",
12 | "@storybook/addon-a11y",
13 | "@storybook/addon-docs",
14 | ],
15 | };
16 |
--------------------------------------------------------------------------------
/packages/editor-ui-utils/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@editor-ui/utils",
3 | "version": "0.0.0",
4 | "dependencies": {
5 | "@radix-ui/primitive": "^1.0.1",
6 | "react-use-gesture": "^9.1.3"
7 | },
8 | "devDependencies": {
9 | "@types/react": "18.2.58",
10 | "react": "^18.2.0"
11 | },
12 | "peerDependencies": {
13 | "@types/react": "18.2.58",
14 | "react": "^18.2.0"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/packages/editor-ui/lib/dashboard/dashboard.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Story, Meta } from "@storybook/react";
3 |
4 | import Dashboard, { DashBoardProps } from "./dashboard";
5 |
6 | export default {
7 | title: "Dashboard/Dashboard",
8 | component: Dashboard,
9 | } as Meta;
10 |
11 | const Template: Story = (args) => ;
12 |
13 | export const Basic = Template.bind({});
14 | Basic.args = {};
15 |
--------------------------------------------------------------------------------
/packages/editor-ui-icons/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@editor-ui/icons",
3 | "version": "0.0.0",
4 | "dependencies": {
5 | "@editor-ui/foundation": "workspace:^"
6 | },
7 | "devDependencies": {
8 | "@emotion/styled": "^11.11.0",
9 | "@types/react": "18.2.58",
10 | "react": "^18.2.0"
11 | },
12 | "peerDependencies": {
13 | "@emotion/styled": "^11.11.0",
14 | "@types/react": "18.2.58",
15 | "react": "^18.2.0"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/theme/theme.ts:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | type Background = React.CSSProperties["background"];
4 | type Color = React.CSSProperties["color"];
5 |
6 | export interface EditorPropertyTheme {
7 | input: {
8 | bg: Background;
9 | prefix: Color;
10 | suffix: Color;
11 | value: Color;
12 | value_disabled: Color;
13 | border: {
14 | focus: Color;
15 | };
16 | };
17 | foreground: Color;
18 | }
19 |
--------------------------------------------------------------------------------
/packages/editor-ui-theme/media-query.ts:
--------------------------------------------------------------------------------
1 | export const size = {
2 | medium: "800px",
3 | large: "1280px",
4 | xlarge: "1550px",
5 | xxlarge: "1680px",
6 | };
7 |
8 | export const mediaQuery = {
9 | small: `@media (max-width: ${size.medium})`,
10 | medium: `@media (max-width: ${size.large}) and (min-width: ${size.medium})`,
11 | large: `@media (max-width: ${size.xlarge}) and (min-width: ${size.large})`,
12 | xlarge: `@media (min-width: ${size.xlarge})`,
13 | };
14 |
--------------------------------------------------------------------------------
/packages/editor-ui/lib/dashboard/guide/guide.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Story, Meta } from "@storybook/react";
3 |
4 | import DashboardGuide, { DashboardGuideProps } from "./";
5 |
6 | export default {
7 | title: "Dashboard/Guide",
8 | component: DashboardGuide,
9 | } as Meta;
10 |
11 | const Template: Story = (args) => ;
12 |
13 | export const Basic = Template.bind({});
14 | Basic.args = {};
15 |
--------------------------------------------------------------------------------
/packages/editor-ui/lib/dashboard/dashboard-cell/dashbaord-cell.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Story, Meta } from "@storybook/react";
3 |
4 | import DashboardCell, { DashboardCellProps } from "./";
5 |
6 | export default {
7 | title: "Dashboard/Cell",
8 | component: DashboardCell,
9 | } as Meta;
10 |
11 | const Template: Story = (args) => ;
12 |
13 | export const Basic = Template.bind({});
14 | Basic.args = {};
15 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/property-cell/property-cell.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { PropertyCell } from "./property-cell";
3 |
4 | export default {
5 | title: "property-cell",
6 | component: PropertyCell,
7 | };
8 |
9 | export const Primary = () => (
10 |
15 | Content
16 |
17 | );
18 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/theme-one/dark.ts:
--------------------------------------------------------------------------------
1 | import type { EditorPropertyTheme } from "../theme";
2 |
3 | const dark: EditorPropertyTheme = {
4 | input: {
5 | bg: "rgba(0, 0, 0, 0.2",
6 | prefix: "rgba(255, 255, 255, 0.5)",
7 | suffix: "rgba(255, 255, 255, 0.5)",
8 | value: "white",
9 | value_disabled: "rgba(255, 255, 255, 0.5)",
10 | border: {
11 | focus: "rgba(255, 255, 255, 0.5)",
12 | },
13 | },
14 | foreground: "white",
15 | };
16 |
17 | export default dark;
18 |
--------------------------------------------------------------------------------
/packages/editor-ui/lib/header/search-button/search-button.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Story, Meta } from "@storybook/react";
3 |
4 | import HeaderSearchButton, { HeaderSearchButtonProps } from "./";
5 |
6 | export default {
7 | title: "Header/Navigation-Button",
8 | component: HeaderSearchButton,
9 | } as Meta;
10 |
11 | const Template: Story = (args) => ;
12 |
13 | export const Basic = Template.bind({});
14 | Basic.args = {};
15 |
--------------------------------------------------------------------------------
/packages/editor-ui-tooltip/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@editor-ui/tooltip",
3 | "version": "0.0.0",
4 | "dependencies": {
5 | "@editor-ui/foundation": "workspace:^",
6 | "@editor-ui/theme": "workspace:^",
7 | "@radix-ui/react-slot": "^0.0.11",
8 | "@radix-ui/react-tooltip": "^0.0.19"
9 | },
10 | "devDependencies": {
11 | "@types/react": "18.2.58",
12 | "react": "^18.2.0"
13 | },
14 | "peerDependencies": {
15 | "@types/react": "18.2.58",
16 | "react": "^18.2.0"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/packages/editor-ui/lib/header/navigation-button/navigation-button.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Story, Meta } from "@storybook/react";
3 |
4 | import HeaderNavigationButton, { HeadernavigationButtonProps } from "./";
5 |
6 | export default {
7 | title: "Header/Navigation-Button",
8 | component: HeaderNavigationButton,
9 | } as Meta;
10 |
11 | const Template: Story = (args) => ;
12 |
13 | export const Basic = Template.bind({});
14 | Basic.args = {};
15 |
--------------------------------------------------------------------------------
/packages/editor-ui-theme/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@editor-ui/theme",
3 | "version": "0.0.0",
4 | "peerDependencies": {
5 | "@emotion/core": "^11.0.0",
6 | "@emotion/css": "^11.1.3",
7 | "@emotion/react": "^11.1.5",
8 | "@emotion/styled": "^11.1.5",
9 | "@types/react": "18.2.58",
10 | "react": "^18.2.0"
11 | },
12 | "dependencies": {
13 | "immer": "^9.0.3"
14 | },
15 | "devDependencies": {
16 | "@types/react": "18.2.58",
17 | "react": "^18.2.0"
18 | }
19 | }
--------------------------------------------------------------------------------
/packages/editor-ui-scroll-area/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@editor-ui/scroll-area",
3 | "description": "Scroll area component abstraction",
4 | "authors": "Grida.co",
5 | "version": "0.0.0",
6 | "dependencies": {
7 | "@editor-ui/theme": "workspace:^",
8 | "@radix-ui/react-scroll-area": "^0.0.16"
9 | },
10 | "devDependencies": {
11 | "@types/react": "18.2.58",
12 | "react": "^18.2.0"
13 | },
14 | "peerDependencies": {
15 | "@types/react": "18.2.58",
16 | "react": "^18.2.0"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/css/index.ts:
--------------------------------------------------------------------------------
1 | import { css } from "@emotion/react";
2 |
3 | export const input_type_number_disable_browser_default_appearence = css`
4 | /* Disabling up and down arrows for number inputs */
5 | &[type="number"] {
6 | -moz-appearance: textfield; /* Firefox */
7 | appearance: textfield; /* Chrome, Safari, Edge, and Opera */
8 | }
9 |
10 | /* Hide the spin button in Chrome, Safari, Edge, and Opera */
11 | &::-webkit-outer-spin-button,
12 | &::-webkit-inner-spin-button {
13 | -webkit-appearance: none;
14 | margin: 0;
15 | }
16 | `;
17 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/property-lines/property-lines.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import styled from "@emotion/styled";
3 |
4 | export function PropertyLines({
5 | children,
6 | padding = 16,
7 | }: React.PropsWithChildren<{ padding?: React.CSSProperties["padding"] }>) {
8 | return (
9 |
14 | {children}
15 |
16 | );
17 | }
18 |
19 | const PropertyLinesContainer = styled.div`
20 | display: flex;
21 | flex-direction: column;
22 | gap: 8px;
23 | `;
24 |
--------------------------------------------------------------------------------
/packages/editor-ui-theme/index.ts:
--------------------------------------------------------------------------------
1 | import { light } from "./light";
2 | import { dark } from "./dark";
3 | import styled, { CreateStyled } from "@emotion/styled";
4 | export * from "./theme-provider";
5 |
6 | export const theme = {
7 | dark: dark,
8 | light: light,
9 | };
10 |
11 | type _Theme = typeof light;
12 | export type Theme = _Theme;
13 |
14 | declare module "@emotion/react" {
15 | export interface Theme extends _Theme {}
16 | }
17 |
18 | //@ts-ignore - below line sometimes throw "Type error: Type 'CreateStyled' is not generic." even if it is generic typed
19 | export default styled as CreateStyled<_Theme>;
20 |
--------------------------------------------------------------------------------
/packages/editor-ui-button/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@editor-ui/button",
3 | "version": "0.0.0",
4 | "devDependencies": {
5 | "@emotion/react": "^11.11.3",
6 | "@emotion/styled": "^11.11.0",
7 | "@types/react": "18.2.58",
8 | "react": "^18.2.0"
9 | },
10 | "peerDependencies": {
11 | "@emotion/react": "^11.11.3",
12 | "@emotion/styled": "^11.11.0",
13 | "@types/react": "18.2.58",
14 | "react": "^18.2.0"
15 | },
16 | "dependencies": {
17 | "@editor-ui/theme": "workspace:^",
18 | "@editor-ui/tooltip": "workspace:^"
19 | }
20 | }
--------------------------------------------------------------------------------
/packages/editor-ui-hierarchy/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@editor-ui/hierarchy",
3 | "version": "0.0.0",
4 | "dependencies": {
5 | "@editor-ui/foundation": "workspace:^",
6 | "@editor-ui/icons": "workspace:^",
7 | "@editor-ui/listview": "workspace:^",
8 | "@editor-ui/spacer": "workspace:^",
9 | "@radix-ui/react-icons": "^1.0.3"
10 | },
11 | "devDependencies": {
12 | "@emotion/styled": "^11.11.0",
13 | "@types/react": "18.2.58",
14 | "react": "^18.2.0"
15 | },
16 | "peerDependencies": {
17 | "@emotion/styled": "^11.11.0",
18 | "@types/react": "18.2.58",
19 | "react": "^18.2.0"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/packages/editor-ui-context-menu/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@editor-ui/context-menu",
3 | "version": "0.0.0",
4 | "dependencies": {
5 | "@editor-ui/foundation": "workspace:^",
6 | "@editor-ui/menu": "workspace:^",
7 | "@editor-ui/spacer": "workspace:^",
8 | "@radix-ui/react-context-menu": "^0.1.1",
9 | "@radix-ui/react-icons": "^1.0.3"
10 | },
11 | "devDependencies": {
12 | "@emotion/styled": "^11.11.0",
13 | "@types/react": "18.2.58",
14 | "react": "^18.2.0"
15 | },
16 | "peerDependencies": {
17 | "@emotion/styled": "^11.11.0",
18 | "@types/react": "18.2.58",
19 | "react": "^18.2.0"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./property-cell";
2 | export * from "./property-group";
3 | export * from "./property-group-header";
4 | export * from "./property-input";
5 | export * from "./property-input-checkbox";
6 | export * from "./property-input-slider";
7 | export * from "./property-input-color";
8 | export * from "./property-input-select";
9 | export * from "./property-input-toggle-group";
10 | export * from "./property-line";
11 | export * from "./property-lines";
12 | export * from "./layout";
13 |
14 | export { EditorPropertyThemeProvider } from "./theme";
15 | export type { EditorPropertyTheme } from "./theme";
16 | export * as one from "./theme-one";
17 |
--------------------------------------------------------------------------------
/packages/editor-ui-sortable/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@editor-ui/sortable",
3 | "version": "0.0.0",
4 | "dependencies": {
5 | "@dnd-kit/core": "^3.1.1",
6 | "@dnd-kit/modifiers": "^3.0.0",
7 | "@dnd-kit/sortable": "^4.0.0",
8 | "@dnd-kit/utilities": "^2.0.0",
9 | "@editor-ui/foundation": "workspace:^"
10 | },
11 | "devDependencies": {
12 | "@types/react": "18.2.58",
13 | "@types/react-dom": "^18.0.8",
14 | "react": "^18.2.0",
15 | "react-dom": "^18.2.0"
16 | },
17 | "peerDependencies": {
18 | "@types/react": "18.2.58",
19 | "@types/react-dom": "^18.0.8",
20 | "react": "^18.2.0",
21 | "react-dom": "^18.2.0"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/layout/dnd-item/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { useMemo } from 'react';
2 | import { useSortable } from "@dnd-kit/sortable";
3 | import { CSS } from '@dnd-kit/utilities';
4 |
5 | interface ItemProps {
6 | id: string;
7 | children: (props: any) => JSX.Element;
8 | }
9 |
10 | export function DnDItem({ id, children }: ItemProps) {
11 | const sortable = useSortable({ id });
12 |
13 | const { attributes, listeners, setNodeRef, transform, transition } = sortable;
14 |
15 | const style = useMemo(
16 | () => ({
17 | transform: CSS.Transform.toString(transform),
18 | transition,
19 | }),
20 | [transform, transition],
21 | );
22 |
23 | return children({ ref: setNodeRef, style, ...attributes, ...listeners });
24 | }
--------------------------------------------------------------------------------
/packages/editor-ui-property/property-input/property-input.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { PropertyInput } from "./property-input";
3 |
4 | export default {
5 | title: "property-input",
6 | component: PropertyInput,
7 | };
8 |
9 | export const WithPrefix = () => (
10 |
11 | );
12 |
13 | export const WithSuffix = () => (
14 |
15 | );
16 |
17 | export const TypeNumber = () => (
18 |
19 | );
20 |
21 | export const WithReadonly = () => (
22 |
28 | );
29 |
--------------------------------------------------------------------------------
/packages/editor-ui-icons/icons.stories.mdx:
--------------------------------------------------------------------------------
1 | import { Meta, Story, Canvas } from "@storybook/addon-docs/blocks";
2 |
3 | import Icon from "./";
4 | import icons from "./icons";
5 |
6 |
7 |
8 | # Icon
9 |
10 | `Icon` Component
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | # Icon List
21 |
22 |
23 |
24 |
25 | {Object.keys(icons).map((i) => (
26 |
27 | ))}
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/packages/editor-ui/lib/combined/property-layer/only-text-field/only-text-field.stories.mdx:
--------------------------------------------------------------------------------
1 | import { Meta, Story, Canvas } from "@storybook/addon-docs/blocks";
2 |
3 | import OnlyTextField from "./";
4 |
5 |
6 |
7 | # OnlyTextField
8 |
9 | `OnlyTextField` combined component
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | # Example - Fill
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/property-lines/property-lines.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { PropertyInput } from "../property-input";
3 | import { PropertyLine } from "../property-line/property-line";
4 | import { PropertyLines } from "./property-lines";
5 |
6 | export default {
7 | title: "property-lines",
8 | component: PropertyLines,
9 | };
10 |
11 | export const Primary = () => (
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | );
23 |
--------------------------------------------------------------------------------
/packages/editor-ui/lib/combined/property-layer/only-two-text-field/only-text-field.stories.mdx:
--------------------------------------------------------------------------------
1 | import { Meta, Story, Canvas } from "@storybook/addon-docs/blocks";
2 |
3 | import OnlyTwoTextField from "./";
4 |
5 |
6 |
7 | # OnlyTwoTextField
8 |
9 | `OnlyTwoTextField` combined component
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | # Example - Postion
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/packages/editor-ui/lib/combined/property-layer/text-field-n-toggle/text-field-n-toggle.stories.mdx:
--------------------------------------------------------------------------------
1 | import { Meta, Story, Canvas } from "@storybook/addon-docs/blocks";
2 |
3 | import TextFieldnToggle from "./";
4 |
5 |
6 |
7 | # TextFieldnToggle
8 |
9 | `TextFieldnToggle` combined component
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | # Example - Radius
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/packages/editor-ui/lib/combined/property-layer/only-toggle/index.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import styled from "@emotion/styled";
3 | import Toggle from "../../../property/input/toggle";
4 |
5 | function OnlyToggle(props: {
6 | label: string;
7 | leftItem: React.ReactNode;
8 | rightItem: React.ReactNode;
9 | }) {
10 | const { label, leftItem, rightItem } = props;
11 |
12 | return (
13 |
14 | {label}
15 |
16 |
17 | );
18 | }
19 |
20 | export default OnlyToggle;
21 |
22 | const Wrapper = styled.div`
23 | display: flex;
24 | align-items: center;
25 | justify-content: space-between;
26 | width: 210px;
27 |
28 | label {
29 | font-size: 12px;
30 | color: #fff;
31 | }
32 |
33 | .postion {
34 | margin: 0px 4px;
35 | }
36 | `;
37 |
--------------------------------------------------------------------------------
/packages/editor-ui-utils/with-separator.ts:
--------------------------------------------------------------------------------
1 | import { Children, cloneElement, isValidElement, ReactNode } from "react";
2 |
3 | function createKey(key: string | number) {
4 | return `s-${key}`;
5 | }
6 |
7 | export function withSeparatorElements(
8 | elements: ReactNode,
9 | separator: ReactNode | (() => ReactNode)
10 | ) {
11 | const childrenArray = Children.toArray(elements);
12 |
13 | for (let i = childrenArray.length - 1; i > 0; i--) {
14 | let sep =
15 | typeof separator === "function"
16 | ? separator()
17 | : isValidElement(separator)
18 | ? cloneElement(separator, { key: createKey(i) })
19 | : separator;
20 |
21 | if (isValidElement(sep) && sep.key == null) {
22 | sep = cloneElement(sep, { key: createKey(i) });
23 | }
24 |
25 | childrenArray.splice(i, 0, sep as any);
26 | }
27 |
28 | return childrenArray;
29 | }
30 |
--------------------------------------------------------------------------------
/packages/console-ui/form-field/index.ts:
--------------------------------------------------------------------------------
1 | import styled from "@emotion/styled";
2 |
3 | export const FormFieldLabel = styled.span`
4 | opacity: 0.9;
5 | text-overflow: ellipsis;
6 | font-size: 12px;
7 | font-family: Inter, sans-serif;
8 | font-weight: 400;
9 | text-align: left;
10 | align-self: stretch;
11 | flex-shrink: 0;
12 | `;
13 |
14 | export const FormFieldBase = styled.div`
15 | display: flex;
16 | justify-content: flex-start;
17 | flex-direction: column;
18 | align-items: flex-start;
19 | gap: 8px;
20 | align-self: stretch;
21 | box-sizing: border-box;
22 | flex-shrink: 0;
23 | `;
24 |
25 | export const FormFieldAssisiveText = styled.span`
26 | opacity: 0.6;
27 | text-overflow: ellipsis;
28 | font-size: 12px;
29 | font-family: Inter, sans-serif;
30 | font-weight: 400;
31 | text-align: left;
32 | align-self: stretch;
33 | flex-shrink: 0;
34 | `;
35 |
--------------------------------------------------------------------------------
/packages/editor-ui-button/loading-indicator/interfaces.ts:
--------------------------------------------------------------------------------
1 | import { SerializedStyles } from "@emotion/react";
2 |
3 | export interface LengthObject {
4 | value: number;
5 | unit: string;
6 | }
7 |
8 | export interface CommonProps {
9 | color?: string;
10 | loading?: boolean;
11 | css?: string | SerializedStyles;
12 | speedMultiplier?: number;
13 | }
14 |
15 | export type LengthType = number | string;
16 |
17 | export interface LoaderHeightWidthProps extends CommonProps {
18 | height?: LengthType;
19 | width?: LengthType;
20 | }
21 |
22 | export interface LoaderSizeProps extends CommonProps {
23 | size?: LengthType;
24 | }
25 |
26 | export interface LoaderSizeMarginProps extends LoaderSizeProps {
27 | margin?: LengthType;
28 | }
29 |
30 | export interface LoaderHeightWidthRadiusProps extends LoaderHeightWidthProps {
31 | margin?: LengthType;
32 | radius?: LengthType;
33 | }
34 |
--------------------------------------------------------------------------------
/packages/editor-ui-desktop-titlebar/bar-drag-area.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import styled from "@editor-ui/theme";
3 |
4 | interface Props {
5 | controlDoubleClick: (e?) => void;
6 | children?: JSX.Element | JSX.Element[] | undefined;
7 | enabled?: boolean;
8 | }
9 |
10 | export function BarDragArea(props: Props) {
11 | const enabled = props.enabled === undefined ? true : props.enabled;
12 | return (
13 | <>
14 | {enabled && (
15 |
16 | {props.children}
17 |
18 | )}
19 | >
20 | );
21 | }
22 |
23 | const Wrapper = styled.div(({ theme }) => ({
24 | /** https://www.electronjs.org/docs/api/frameless-window#draggable-region - this is also present on side nav bar*/
25 | WebkitAppRegion: "drag",
26 | width: "100%",
27 | height: theme.sizes.desktopControlWindowBar.height,
28 | }));
29 |
--------------------------------------------------------------------------------
/packages/editor-ui-spacer/spacer.ts:
--------------------------------------------------------------------------------
1 | import styled from "@emotion/styled";
2 |
3 | interface Props {
4 | size?: number;
5 | }
6 |
7 | /* ----------------------------------------------------------------------------
8 | * Vertical
9 | * ------------------------------------------------------------------------- */
10 |
11 | const SpacerVertical = styled.span(({ size }) => ({
12 | display: "block",
13 | ...(size === undefined ? { flex: 1 } : { minHeight: size }),
14 | }));
15 |
16 | /* ----------------------------------------------------------------------------
17 | * Horizontal
18 | * ------------------------------------------------------------------------- */
19 |
20 | const SpacerHorizontal = styled.span(({ size }) => ({
21 | display: "block",
22 | ...(size === undefined ? { flex: 1 } : { minWidth: size }),
23 | }));
24 |
25 | export const Vertical = SpacerVertical;
26 | export const Horizontal = SpacerHorizontal;
27 |
--------------------------------------------------------------------------------
/packages/editor-ui/lib/combined/property-layer/only-text-field/index.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import styled from "@emotion/styled";
3 | import TextField from "../../../property/input/text-field";
4 | import Icon from "../../../icons";
5 |
6 | function OnlyTextField(props: { label: string }) {
7 | const { label } = props;
8 |
9 | return (
10 |
11 | {label}
12 |
13 | }
17 | />
18 |
19 |
20 | );
21 | }
22 |
23 | export default OnlyTextField;
24 |
25 | const Wrapper = styled.div`
26 | display: flex;
27 | align-items: center;
28 | justify-content: space-between;
29 | width: 210px;
30 |
31 | label {
32 | font-size: 12px;
33 | color: #fff;
34 | }
35 |
36 | .postion {
37 | margin: 0px 4px;
38 | }
39 | `;
40 |
--------------------------------------------------------------------------------
/packages/editor-ui-hierarchy/hierarchy-segment/hierarchy-segment.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import styled from "@emotion/styled";
3 | export function HierarchySegment(props: {
4 | children: JSX.Element | JSX.Element[];
5 | }) {
6 | const label = undefined;
7 | const body = undefined;
8 | return (
9 |
10 | {label}
11 | {body}
12 |
13 | );
14 | }
15 |
16 | const RootWrapper = styled.div``;
17 | const LabelWrapper = styled.div``;
18 | const BodyWrapper = styled.div``;
19 |
20 | function HierarchySegmentSlot_Label(props: { children: JSX.Element }) {
21 | return <>{props.children}>;
22 | }
23 |
24 | function HierarchySegmentSlot_Body(props: { children: JSX.Element }) {
25 | return <>{props.children}>;
26 | }
27 |
28 | export const HierarchySegmentSlots = {
29 | Label: HierarchySegmentSlot_Label,
30 | Body: HierarchySegmentSlot_Body,
31 | };
32 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/property-line/property-line.tsx:
--------------------------------------------------------------------------------
1 | import styled from "@emotion/styled";
2 | import React from "react";
3 | export function PropertyLine({
4 | label,
5 | children,
6 | onClick,
7 | gap = 8,
8 | }: React.PropsWithChildren<{
9 | label?: string;
10 | gap?: number;
11 | onClick?: (e) => void;
12 | }>) {
13 | return (
14 |
15 | {label && {label} }
16 |
21 | {children}
22 |
23 |
24 | );
25 | }
26 |
27 | const Line = styled.div`
28 | display: flex;
29 | flex-direction: row;
30 | align-items: center;
31 | `;
32 |
33 | const Items = styled.div`
34 | display: flex;
35 | flex: 7;
36 | `;
37 |
38 | const Label = styled.label`
39 | max-width: 80px;
40 | flex: 2;
41 | margin-right: 16px;
42 | font-family: Inter, sans-serif;
43 | font-size: 11px;
44 | color: #999;
45 | `;
46 |
--------------------------------------------------------------------------------
/.github/workflows/chromatic.yml:
--------------------------------------------------------------------------------
1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
3 |
4 | name: chromatic-deploy
5 |
6 | on:
7 | push:
8 | branches: [main]
9 | pull_request:
10 | branches: [main]
11 |
12 | jobs:
13 | build:
14 | runs-on: ubuntu-latest
15 |
16 | steps:
17 | - uses: actions/checkout@v2
18 | - name: Install dependencies
19 | run: yarn
20 | # 👇 Adds Chromatic as a step in the workflow
21 | - name: Publish to Chromatic
22 | uses: chromaui/action@v1
23 | # Chromatic GitHub Action options
24 | with:
25 | token: ${{ secrets.GITHUB_TOKEN }}
26 | # 👇 Chromatic projectToken, refer to the manage page to obtain it.
27 | projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
28 |
--------------------------------------------------------------------------------
/packages/editor-ui-listview/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@editor-ui/listview",
3 | "version": "0.0.0",
4 | "dependencies": {
5 | "@editor-ui/context-menu": "workspace:^",
6 | "@editor-ui/foundation": "workspace:^",
7 | "@editor-ui/hooks": "workspace:^",
8 | "@editor-ui/scroll-area": "workspace:^",
9 | "@editor-ui/sortable": "workspace:^",
10 | "@editor-ui/spacer": "workspace:^",
11 | "@editor-ui/theme": "workspace:^",
12 | "@editor-ui/utils": "workspace:^",
13 | "@radix-ui/react-compose-refs": "^1.0.1",
14 | "@reflect-ui/uiutils": "0.1.2-2",
15 | "react-virtualized": "^9.22.3",
16 | "react-window": "^1.8.6"
17 | },
18 | "peerDependencies": {
19 | "@emotion/styled": "^11.11.0",
20 | "@types/react": "18.2.58",
21 | "react": "^18.2.0"
22 | },
23 | "devDependencies": {
24 | "@emotion/styled": "^11.11.0",
25 | "@types/react": "18.2.58",
26 | "@types/react-virtualized": "^9.21.13",
27 | "@types/react-window": "^1.8.5",
28 | "react": "^18.2.0"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/packages/editor-ui-theme/dark.ts:
--------------------------------------------------------------------------------
1 | // import produce from "immer";
2 | import * as lightTheme from "./light";
3 |
4 | export const colors = (colors) => {
5 | colors.primary = "rgb(81, 78, 253)";
6 | colors.text = "rgb(248,248,250)";
7 | colors.textMuted = "rgb(180,180,180)";
8 | colors.textDisabled = "rgb(100,100,100)";
9 | colors.inputBackground = "rgb(50,50,52)";
10 | colors.divider = "rgba(255,255,255,0.1)";
11 | colors.dividerStrong = "rgba(0,0,0,1)";
12 | colors.canvas.background = "rgb(19,20,21)";
13 | colors.sidebar.background = "rgba(40,40,40,0.85)";
14 | colors.popover.background = "rgb(40,40,40)";
15 | colors.listView.raisedBackground = "rgba(255,255,255,0.1)";
16 | colors.slider.background = "#BBB";
17 | colors.mask = "rgb(102,187,106)";
18 | return colors;
19 | };
20 |
21 | export const textStyles = lightTheme.textStyles;
22 | export const fonts = lightTheme.fonts;
23 | export const sizes = lightTheme.sizes;
24 |
25 | export const dark = {
26 | colors: colors({ ...lightTheme.colors }),
27 | fonts: fonts,
28 | textStyles: textStyles,
29 | sizes: sizes,
30 | };
31 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/property-cell/property-cell.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import styled from "@emotion/styled";
3 |
4 | export function PropertyCell({
5 | background,
6 | border,
7 | outline,
8 | children,
9 | height,
10 | minWidth,
11 | onClick,
12 | }: React.PropsWithChildren<{
13 | background?: React.CSSProperties["background"];
14 | border?: React.CSSProperties["border"];
15 | outline?: React.CSSProperties["outline"];
16 | height?: React.CSSProperties["height"];
17 | minWidth?: React.CSSProperties["minWidth"];
18 | onClick?: React.MouseEventHandler;
19 | }>) {
20 | return (
21 |
31 | {children}
32 |
33 | );
34 | }
35 |
36 | const PropertyCellContainer = styled.div`
37 | display: flex;
38 | align-items: center;
39 | justify-content: center;
40 | width: 100%;
41 | height: 100%;
42 | border-radius: 4px;
43 | `;
44 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/property-group/property-group.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { PropertyGroupHeader } from "../property-group-header";
3 | import { PropertyInput } from "../property-input";
4 | import { PropertyLine } from "../property-line/property-line";
5 | import { PropertyLines } from "../property-lines";
6 | import { PropertyGroup } from "./property-group";
7 |
8 | export default {
9 | title: "property-group",
10 | component: PropertyGroup,
11 | };
12 |
13 | export const Primary = () => (
14 |
15 |
16 | Layout
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | );
30 |
--------------------------------------------------------------------------------
/packages/editor-ui/lib/combined/property-layer/text-filed-n-selector/text-filed-n-selector.stories.mdx:
--------------------------------------------------------------------------------
1 | import { Meta, Story, Canvas } from "@storybook/addon-docs/blocks";
2 |
3 | import TextFieldnSelector from "./";
4 |
5 |
6 |
7 | # TextFieldnSelector
8 |
9 | `TextFieldnSelector` combined component
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | # Example - Width
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | # Example - Height
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Bridged
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@editor-ui/property",
3 | "version": "0.0.0",
4 | "scripts": {
5 | "storybook": "start-storybook -p 6006",
6 | "build-storybook": "build-storybook"
7 | },
8 | "dependencies": {
9 | "@dnd-kit/core": "^6.1.0",
10 | "@dnd-kit/modifiers": "^7.0.0",
11 | "@dnd-kit/sortable": "^8.0.0",
12 | "@dnd-kit/utilities": "^3.2.2",
13 | "@editor-ui/foundation": "workspace:^",
14 | "@radix-ui/react-checkbox": "^1.0.4",
15 | "@radix-ui/react-icons": "^1.0.3",
16 | "@radix-ui/react-select": "^1.2.0",
17 | "@radix-ui/react-slider": "^0.0.11",
18 | "@radix-ui/react-toggle-group": "^1.0.4"
19 | },
20 | "peerDependencies": {
21 | "@emotion/react": "^11.10.5",
22 | "@emotion/styled": "^11.10.5",
23 | "@types/react": "18.2.58",
24 | "react": "^18.2.0"
25 | },
26 | "devDependencies": {
27 | "@emotion/react": "^11.10.5",
28 | "@emotion/styled": "^11.10.5",
29 | "@types/react": "18.2.58",
30 | "autoprefixer": "^10.0.1",
31 | "postcss": "^8",
32 | "react": "^18.2.0",
33 | "tailwindcss": "^3.3.0"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/packages/editor-ui/lib/combined/property-layer/text-field-n-silder/text-field-n-silder.stories.mdx:
--------------------------------------------------------------------------------
1 | import { Meta, Story, Canvas } from "@storybook/addon-docs/blocks";
2 |
3 | import TextFieldnSilder from "./";
4 |
5 |
6 |
7 | # TextFieldnSilder
8 |
9 | `TextFieldnSilder` combined component
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | # Example - Rotation
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | # Example - Opacity
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/packages/editor-ui/lib/combined/property-layer/only-toggle/only-toggle.stories.mdx:
--------------------------------------------------------------------------------
1 | import { Meta, Story, Canvas } from "@storybook/addon-docs/blocks";
2 |
3 | import OnlyToggle from "./";
4 |
5 |
6 |
7 | # OnlyToggle
8 |
9 | `OnlyToggle` combined component
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | # Example - Visible
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | # Example - Overflow
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/packages/console-ui/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Refelct
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/editor-ui/lib/combined/property-layer/text-field-n-silder/index.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import styled from "@emotion/styled";
3 | import TextField from "../../../property/input/text-field";
4 | import Silder from "../../../property/input/silder";
5 |
6 | function TextFieldnSilder(props: { label: string }) {
7 | const { label } = props;
8 | return (
9 |
10 | {label}
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | );
21 | }
22 |
23 | export default TextFieldnSilder;
24 |
25 | const Wrapper = styled.div`
26 | display: flex;
27 | align-items: center;
28 | justify-content: space-between;
29 | width: 210px;
30 |
31 | label {
32 | font-size: 12px;
33 | color: #fff;
34 | }
35 |
36 | .editor-area {
37 | display: flex;
38 | align-items: center;
39 | }
40 |
41 | .postion,
42 | .silder {
43 | margin: 0px 4px;
44 | }
45 | `;
46 |
--------------------------------------------------------------------------------
/packages/editor-ui/lib/combined/property-layer/text-filed-n-selector/index.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import styled from "@emotion/styled";
3 | import TextField from "../../../property/input/text-field";
4 | import Selector from "../../../property/input/selector";
5 |
6 | function TextFieldnSelector(props: { label: string }) {
7 | const { label } = props;
8 |
9 | return (
10 |
11 | {label}
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | );
22 | }
23 |
24 | export default TextFieldnSelector;
25 |
26 | const Wrapper = styled.div`
27 | display: flex;
28 | align-items: center;
29 | justify-content: space-between;
30 | width: 210px;
31 |
32 | label {
33 | font-size: 12px;
34 | color: #fff;
35 | }
36 |
37 | .editor-area {
38 | display: flex;
39 | align-items: center;
40 | }
41 |
42 | .postion,
43 | .selector {
44 | margin: 0px 4px;
45 | }
46 | `;
47 |
--------------------------------------------------------------------------------
/packages/editor-ui-workspace/layouts/workspace-layout/index.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import styled from "@emotion/styled";
3 | function Layout() {
4 | return (
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | );
17 | }
18 |
19 | const RootWrapperLayout = styled.div`
20 | display: flex;
21 | flex-direction: row;
22 | `;
23 | const Workspace = styled.div`
24 | display: flex;
25 | flex-direction: row;
26 | `;
27 | const SideNavigation = styled.div`
28 | display: flex;
29 | flex-direction: column;
30 | align-items: start;
31 | `;
32 | const Rectangle1 = styled.em`
33 | color: red;
34 | `;
35 | const TopBarAndAreaFrame = styled.div`
36 | display: flex;
37 | flex-direction: column;
38 | align-items: start;
39 | `;
40 | const TopBar = styled.em`
41 | color: red;
42 | `;
43 | const ContentArea = styled.em`
44 | color: red;
45 | `;
46 | export default Layout;
47 |
--------------------------------------------------------------------------------
/packages/editor-ui-button/loading-indicator/helpers/colors.ts:
--------------------------------------------------------------------------------
1 | enum BasicColors {
2 | maroon = "#800000",
3 | red = "#FF0000",
4 | orange = "#FFA500",
5 | yellow = "#FFFF00",
6 | olive = "#808000",
7 | green = "#008000",
8 | purple = "#800080",
9 | fuchsia = "#FF00FF",
10 | lime = "#00FF00",
11 | teal = "#008080",
12 | aqua = "#00FFFF",
13 | blue = "#0000FF",
14 | navy = "#000080",
15 | black = "#000000",
16 | gray = "#808080",
17 | silver = "#C0C0C0",
18 | white = "#FFFFFF",
19 | }
20 |
21 | export const calculateRgba = (color: string, opacity: number): string => {
22 | if (Object.keys(BasicColors).includes(color)) {
23 | color = BasicColors[color as keyof typeof BasicColors];
24 | }
25 |
26 | if (color[0] === "#") {
27 | color = color.slice(1);
28 | }
29 |
30 | if (color.length === 3) {
31 | let res = "";
32 | color.split("").forEach((c: string) => {
33 | res += c;
34 | res += c;
35 | });
36 | color = res;
37 | }
38 |
39 | const rgbValues: string = (color.match(/.{2}/g) || [])
40 | .map((hex: string) => parseInt(hex, 16))
41 | .join(", ");
42 |
43 | return `rgba(${rgbValues}, ${opacity})`;
44 | };
45 |
--------------------------------------------------------------------------------
/packages/editor-ui-listview/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Grida
4 | Copyright (c) 2020 Noya
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 |
--------------------------------------------------------------------------------
/packages/editor-ui-sortable/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Grida
4 | Copyright (c) 2020 Noya
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 |
--------------------------------------------------------------------------------
/packages/editor-ui-scroll-area/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Grida
4 | Copyright (c) 2020 Noya
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 |
--------------------------------------------------------------------------------
/packages/editor-ui-tooltip/tooltip/tooltip.tsx:
--------------------------------------------------------------------------------
1 | import React, { memo, ReactNode } from "react";
2 | import * as TooltipPrimitive from "@radix-ui/react-tooltip";
3 | import { Slot } from "@radix-ui/react-slot";
4 | import styled from "@editor-ui/theme";
5 |
6 | const Content = styled(TooltipPrimitive.Content)(({ theme }) => ({
7 | ...theme.textStyles.small,
8 | color: theme.colors.text,
9 | borderRadius: 3,
10 | padding: `${theme.sizes.spacing.small}px ${theme.sizes.spacing.medium}px`,
11 | backgroundColor: theme.colors.popover.background,
12 | boxShadow: "0 2px 4px rgba(0,0,0,0.2), 0 0 12px rgba(0,0,0,0.1)",
13 | border: `1px solid ${theme.colors.dividerStrong}`,
14 | }));
15 |
16 | interface Props {
17 | children: ReactNode;
18 | content: ReactNode;
19 | }
20 |
21 | export const Tooltip = memo(function Tooltip({ children, content }: Props) {
22 | return (
23 | // @ts-ignore
24 |
25 | {children}
26 |
27 | {content}
28 | {/* */}
29 |
30 |
31 | );
32 | });
33 |
--------------------------------------------------------------------------------
/packages/console-ui/text-form-field/index.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import styled from "@emotion/styled";
3 | import { TextField } from "../text-field";
4 | import {
5 | FormFieldLabel,
6 | FormFieldBase,
7 | FormFieldAssisiveText,
8 | } from "../form-field";
9 |
10 | export function TextFormField({
11 | label,
12 | helpText,
13 | readonly,
14 | ...rest
15 | }: {
16 | onEnter?: (value: string) => void;
17 | onChange?: (value: string) => void;
18 | readonly?: boolean;
19 | label?: string;
20 | value?: string;
21 | helpText?: string;
22 | placeholder?: string;
23 | autoFocus?: boolean;
24 | }) {
25 | return (
26 |
27 |
28 | {label && {label} }
29 |
30 | {helpText && {helpText} }
31 |
32 |
33 | );
34 | }
35 |
36 | const Wrap = styled.div`
37 | user-select: none;
38 | display: flex;
39 | justify-content: flex-start;
40 | flex-direction: column;
41 | align-items: flex-start;
42 | align-self: stretch;
43 | box-sizing: border-box;
44 | flex-shrink: 0;
45 | `;
46 |
--------------------------------------------------------------------------------
/packages/editor-ui-multiplayer/multiplayer-avatar-group/multiplayer-avatar-group.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import styled from "@emotion/styled";
3 |
4 | interface MultiplayerAvatarGroupProps {
5 | spacing?: number;
6 | children?: JSX.Element[];
7 | }
8 |
9 | export function MultiplayerAvatarGroup(props: MultiplayerAvatarGroupProps) {
10 | if (props.spacing !== undefined) {
11 | const _spacingtype = spacingtype(props.spacing);
12 | // todo
13 | }
14 |
15 | return (
16 | <_Root>
17 | {props.children?.map((c, i) => {
18 | return (
19 |
20 | {c}
21 |
22 | );
23 | })}
24 |
25 | );
26 | }
27 |
28 | const _Root = styled.div`
29 | display: flex;
30 | flex-direction: row;
31 | `;
32 |
33 | const Positioned = styled.div<{
34 | spacing: number;
35 | index?: number;
36 | }>`
37 | position: relative;
38 | margin-left: ${(p) => p.spacing + "px"};
39 | `;
40 |
41 | function spacingtype(spacing: number): "-" | "none" | "+" {
42 | if (spacing > 0) {
43 | return "+";
44 | } else if (spacing < 0) {
45 | return "-";
46 | } else {
47 | return "none";
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/.storybook/preview.js:
--------------------------------------------------------------------------------
1 | import { useMemo } from "react";
2 | import { EditorPropertyThemeProvider } from "../theme";
3 | import * as themes from "../theme-one";
4 |
5 | export const parameters = {
6 | actions: { argTypesRegex: "^on[A-Z].*" },
7 | controls: {
8 | matchers: {
9 | color: /(background|color)$/i,
10 | date: /Date$/,
11 | },
12 | },
13 | };
14 |
15 | export const withTheme = (Story, context) => {
16 | const { theme: themeKey } = context.globals;
17 | const theme = useMemo(() => themes[themeKey] || themes["light"], [themeKey]);
18 |
19 | return (
20 |
21 |
22 |
23 | );
24 | };
25 |
26 | export const decorators = [withTheme];
27 |
28 | export const globalTypes = {
29 | theme: {
30 | name: "Theme",
31 | title: "Theme",
32 | description: "Theme for your components",
33 | defaultValue: "light",
34 | toolbar: {
35 | icon: "paintbrush",
36 | dynamicTitle: true,
37 | items: [
38 | { value: "light", left: "☀️", title: "Light mode" },
39 | { value: "dark", left: "🌙", title: "Dark mode" },
40 | ],
41 | },
42 | },
43 | };
44 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@reflect-ui/editor-ui",
3 | "version": "0.0.1",
4 | "description": "All you need to create professional editor workspace ui",
5 | "main": "lib",
6 | "repository": "https://github.com/reflect-ui/reflect-editor-ui",
7 | "homepage": "https://reflect-ui.com",
8 | "author": "reflect-ui authors",
9 | "license": "MIT",
10 | "private": true,
11 | "workspaces": [
12 | "packages/*"
13 | ],
14 | "devDependencies": {
15 | "@babel/core": "^7.20.2",
16 | "@storybook/addon-actions": "^6.5.13",
17 | "@storybook/addon-essentials": "^6.5.13",
18 | "@storybook/addon-interactions": "^6.5.13",
19 | "@storybook/addon-links": "^6.5.13",
20 | "@storybook/builder-webpack4": "^6.5.13",
21 | "@storybook/manager-webpack4": "^6.5.13",
22 | "@storybook/react": "^6.5.13",
23 | "@storybook/testing-library": "^0.0.13",
24 | "babel-loader": "^8.3.0",
25 | "chromatic": "^5.7.1",
26 | "typescript": "^4.1.5"
27 | },
28 | "scripts": {
29 | "storybook": "start-storybook -p 6006",
30 | "build-storybook": "build-storybook",
31 | "chromatic": "chromatic --exit-zero-on-changes"
32 | }
33 | }
--------------------------------------------------------------------------------
/packages/editor-ui-property/property-input-toggle-group/property-input-toggle-group.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import * as ToggleGroup from "@radix-ui/react-toggle-group";
3 |
4 | export function PropertyInputToggleGroup({
5 | ariaLabel,
6 | defaultValue,
7 | value,
8 | options,
9 | onValueChange,
10 | }: {
11 | ariaLabel?: string;
12 | defaultValue?: string;
13 | value?: string;
14 | options?: {
15 | value: string;
16 | ariaLabel?: string;
17 | icon: React.ReactNode;
18 | }[];
19 | onValueChange?: (value: string) => void;
20 | }) {
21 | return (
22 |
30 | {options?.map((option) => {
31 | return (
32 |
38 | {option.icon}
39 |
40 | );
41 | })}
42 |
43 | );
44 | }
45 |
--------------------------------------------------------------------------------
/packages/editor-ui-hierarchy/hierachy.stories.mdx:
--------------------------------------------------------------------------------
1 | import { Meta, Story, Canvas } from "@storybook/addon-docs/blocks";
2 |
3 | import Hierachy, { dummyData } from "./hierachy";
4 | import Icon from "../icons";
5 |
6 |
7 |
8 | # Hierachy
9 |
10 | `Hierachy` component that **wraps HierachyItem** to make it into Sturcts.
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | ## Expand Hierachy Item
21 |
22 | **Item1 has been expanded.**
23 |
24 | For expanded items, it automatically becomes selected Item.
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | ### How to Expand?
35 |
36 | Click indicator icon, Icon look like this
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/packages/editor-ui-hooks/use-window-size.ts:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from "react";
2 |
3 | const win = typeof window === "undefined" ? null : window;
4 |
5 | interface UseWindowSizeOptions {
6 | initialWidth?: number;
7 | initialHeight?: number;
8 | }
9 |
10 | /**
11 | * react hooks: use window size
12 | * reference: https://github.com/jaredLunde/react-hook/blob/master/packages/window-size/src/index.tsx
13 | * @returns
14 | */
15 | export function useWindowSize(
16 | option?: UseWindowSizeOptions
17 | ): { width: number; height: number } {
18 | const [windowSize, setWindowSize] = useState({
19 | width: win?.innerWidth ?? option?.initialWidth ?? 0,
20 | height: win?.innerHeight ?? option?.initialWidth ?? 0,
21 | });
22 |
23 | useEffect(() => {
24 | function handleResize() {
25 | setWindowSize({
26 | width: win?.innerWidth,
27 | height: win?.innerHeight,
28 | });
29 | }
30 |
31 | win?.addEventListener("resize", handleResize);
32 | win?.addEventListener("orientationchange", handleResize);
33 |
34 | handleResize();
35 |
36 | return () => {
37 | win?.removeEventListener("resize", handleResize);
38 | win?.removeEventListener("orientationchange", handleResize);
39 | };
40 | }, []);
41 |
42 | return windowSize;
43 | }
44 |
--------------------------------------------------------------------------------
/packages/editor-ui-utils/merge-event-handlers.ts:
--------------------------------------------------------------------------------
1 | ///
2 | /// copied from https://github.com/noya-app/noya/blob/main/packages/noya-designsystem/src/hooks/mergeEventHandlers.ts
3 | /// under MIT License
4 | ///
5 |
6 | import { useGesture } from "react-use-gesture";
7 | import { composeEventHandlers } from "@radix-ui/primitive";
8 |
9 | const unique = (array: T[]) => [...new Set(array)];
10 |
11 | function composeAllEventHandlers(...handlers: ((e: E) => void)[]) {
12 | const [first, ...rest] = handlers;
13 |
14 | return rest.reduce(
15 | (result, handler) => composeEventHandlers(result, handler),
16 | first
17 | );
18 | }
19 |
20 | type ReactEventHandlers = ReturnType>;
21 | type EventName = keyof ReactEventHandlers;
22 |
23 | export function mergeEventHandlers(
24 | ...handlerMaps: ReactEventHandlers[]
25 | ): ReactEventHandlers {
26 | const eventNames = unique(handlerMaps.map(Object.keys).flat() as EventName[]);
27 |
28 | return Object.fromEntries(
29 | eventNames.map((eventName) => {
30 | const handlers = handlerMaps.flatMap((handlerMap) => {
31 | const value = handlerMap[eventName];
32 | return value ? [value] : [];
33 | });
34 |
35 | return [eventName, composeAllEventHandlers(...handlers)];
36 | })
37 | );
38 | }
39 |
--------------------------------------------------------------------------------
/packages/editor-ui-button/loading-indicator/helpers/prop-types.ts:
--------------------------------------------------------------------------------
1 | import {
2 | LoaderHeightWidthProps,
3 | LoaderSizeProps,
4 | LoaderSizeMarginProps,
5 | LoaderHeightWidthRadiusProps,
6 | CommonProps,
7 | } from "../interfaces";
8 |
9 | /*
10 | * DefaultProps object for different loaders
11 | */
12 | const commonValues: Required = {
13 | loading: true,
14 | color: "#000000",
15 | css: "",
16 | speedMultiplier: 1,
17 | };
18 |
19 | export function sizeDefaults(sizeValue: number): Required {
20 | return Object.assign({}, commonValues, { size: sizeValue });
21 | }
22 |
23 | export function sizeMarginDefaults(
24 | sizeValue: number
25 | ): Required {
26 | return Object.assign({}, sizeDefaults(sizeValue), {
27 | margin: 2,
28 | });
29 | }
30 |
31 | export function heightWidthDefaults(
32 | height: number,
33 | width: number
34 | ): Required {
35 | return Object.assign({}, commonValues, {
36 | height,
37 | width,
38 | });
39 | }
40 |
41 | export function heightWidthRadiusDefaults(
42 | height: number,
43 | width: number,
44 | radius = 2
45 | ): Required {
46 | return Object.assign({}, heightWidthDefaults(height, width), {
47 | radius,
48 | margin: 2,
49 | });
50 | }
51 |
--------------------------------------------------------------------------------
/packages/editor-ui/lib/combined/property-layer/text-field-n-toggle/index.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import styled from "@emotion/styled";
3 | import TextField from "../../../property/input/text-field";
4 | import Toggle from "../../../property/input/toggle";
5 | import Icon from "../../../icons";
6 |
7 | function TextFieldnToggle(props: { label: string }) {
8 | const { label } = props;
9 | return (
10 |
11 | {label}
12 |
13 |
14 |
15 |
16 |
17 | }
20 | rightItem={ }
21 | />
22 |
23 |
24 |
25 | );
26 | }
27 |
28 | export default TextFieldnToggle;
29 |
30 | const Wrapper = styled.div`
31 | display: flex;
32 | align-items: center;
33 | justify-content: space-between;
34 | width: 210px;
35 |
36 | label {
37 | font-size: 12px;
38 | color: #fff;
39 | }
40 |
41 | .editor-area {
42 | display: flex;
43 | align-items: center;
44 | }
45 |
46 | .postion,
47 | .toggle {
48 | margin: 0px 4px;
49 | }
50 | `;
51 |
--------------------------------------------------------------------------------
/packages/editor-ui/lib/combined/property-layer/only-two-text-field/index.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import styled from "@emotion/styled";
3 | import TextField from "../../../property/input/text-field";
4 | import Icon from "../../../icons";
5 |
6 | function OnlyTwoTextField(props: { label: string }) {
7 | const { label } = props;
8 |
9 | return (
10 |
11 | {label}
12 |
13 |
14 | }
18 | />
19 |
20 |
21 | }
25 | />
26 |
27 |
28 |
29 | );
30 | }
31 |
32 | export default OnlyTwoTextField;
33 |
34 | const Wrapper = styled.div`
35 | display: flex;
36 | align-items: center;
37 | justify-content: space-between;
38 | width: 210px;
39 |
40 | label {
41 | font-size: 12px;
42 | color: #fff;
43 | }
44 |
45 | .editor-area {
46 | display: flex;
47 | align-items: center;
48 | }
49 |
50 | .postion {
51 | margin: 0px 4px;
52 | }
53 | `;
54 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/property-input-slider/property-input-slider.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import * as Slider from "@radix-ui/react-slider";
3 |
4 | export function PropertySliderInput({
5 | stopPropagation,
6 | value,
7 | min,
8 | max,
9 | step,
10 | onValueChange,
11 | }: {
12 | stopPropagation?: boolean;
13 | value?: number[];
14 | min?: number;
15 | max?: number;
16 | step?: number;
17 | orientation?: "horizontal" | "vertical";
18 | onValueChange?: (value: number[]) => void;
19 | }) {
20 | return (
21 | {
30 | event.stopPropagation();
31 | }
32 | : undefined
33 | }
34 | onValueChange={onValueChange}
35 | >
36 |
37 |
38 |
39 |
40 |
41 | );
42 | }
43 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/property-input-checkbox/property-input-checkbox.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import styled from "@emotion/styled";
3 | import * as Checkbox from "@radix-ui/react-checkbox";
4 | import { CheckIcon } from "@radix-ui/react-icons";
5 |
6 | interface CheckboxProps {
7 | value?: boolean;
8 | onChange?: (checked: boolean) => void;
9 | }
10 |
11 | export function PropertyCheckboxInput({
12 | value: checked,
13 | onChange,
14 | }: CheckboxProps) {
15 | const [value, setValue] = React.useState(checked);
16 |
17 | const onvalue = (value: boolean) => {
18 | setValue(value);
19 | onChange?.(value);
20 | };
21 |
22 | return (
23 |
28 |
29 |
30 |
31 |
32 | );
33 | }
34 |
35 | const CheckboxRoot = styled(Checkbox.Root)`
36 | button {
37 | all: unset;
38 | }
39 |
40 | background-color: white;
41 | width: 14px;
42 | height: 14px;
43 | border-radius: 4px;
44 | display: flex;
45 | align-items: center;
46 | justify-content: center;
47 |
48 | /* */
49 | .indicator {
50 | /* */
51 | .icon {
52 | color: black;
53 | width: 12px;
54 | height: 12px;
55 | }
56 | }
57 | `;
58 |
--------------------------------------------------------------------------------
/packages/editor-ui-icons/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { CSSProperties } from "react";
2 | import styled from "@emotion/styled";
3 | import icons, { IconList } from "./icons";
4 |
5 | interface IconStyledProps {
6 | width?: number;
7 | height?: number;
8 | fill?: CSSProperties["fill"]
9 | }
10 |
11 | export interface IconProps
12 | extends React.DetailedHTMLProps<
13 | React.HTMLAttributes,
14 | HTMLDivElement
15 | > {
16 | name: keyof IconList;
17 | width?: number;
18 | height?: number;
19 | iconColor?: CSSProperties["fill"]
20 | }
21 |
22 | function Icon(props: IconProps) {
23 | const { name, width, height, iconColor, ...divProps } = props;
24 |
25 | return (
26 |
32 |
36 | {icons[name].svg}
37 |
38 |
39 | );
40 | }
41 |
42 | export default Icon;
43 |
44 | const ResponsiveBox = styled.div`
45 | display: inline-flex;
46 | align-items: center;
47 | justify-content: center;
48 | width: ${(p) => p.width}px;
49 | height: ${(p) => p.height}px;
50 |
51 | svg {
52 | * {
53 | fill: ${p => p.fill};
54 | }
55 | }
56 | `;
57 |
--------------------------------------------------------------------------------
/packages/editor-ui-multiplayer/multiplayer-avatar/multiplayer-avatar.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import * as Avatar from "@radix-ui/react-avatar";
3 | import styled from "@emotion/styled";
4 |
5 | interface Props {
6 | id: string;
7 | /**
8 | * e.g. - "https://picsum.photos/id/1005/400/400"
9 | */
10 | image: string;
11 | /**
12 | * character display - not a full name, but a fraction of it.
13 | */
14 | chars: string;
15 | online: boolean;
16 | onClick: (id: string) => void;
17 | }
18 |
19 | export function MultiplayerAvatar(props: Props) {
20 | return (
21 |
22 |
23 | {props.chars}
24 |
25 | );
26 | }
27 |
28 | const StyledAvatar = styled(Avatar.Root)`
29 | display: inline-flex;
30 | align-items: center;
31 | justify-content: center;
32 | vertical-align: middle;
33 | overflow: hidden;
34 | user-select: none;
35 | width: 24px;
36 | height: 24px;
37 | border-radius: 12px;
38 |
39 | opacity: 100%;
40 | filter: drop-shadow(0px 1px 4px rgba(0, 0, 0, 0.15));
41 | `;
42 |
43 | const StyledImage = styled(Avatar.Image)`
44 | width: 100%;
45 | height: 100%;
46 | object-fit: cover;
47 | `;
48 |
49 | const StyledFallback = styled(Avatar.Fallback)`
50 | width: 100%;
51 | height: 100%;
52 | display: flex;
53 | align-items: center;
54 | justify-content: center;
55 | background-color: #717171;
56 | `;
57 |
--------------------------------------------------------------------------------
/packages/editor-ui-dialog/dialog.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import * as DialogPrimitive from "@radix-ui/react-dialog";
3 | import styled from "@emotion/styled";
4 |
5 | const StyledOverlay = styled(DialogPrimitive.Overlay)`
6 | background-color: rgba(0, 0, 0, 0.2);
7 | position: fixed;
8 | top: 0;
9 | right: 0;
10 | bottom: 0;
11 | left: 0;
12 | `;
13 |
14 | const StyledContent = styled(DialogPrimitive.Content)`
15 | position: fixed;
16 | top: 50%;
17 | left: 50%;
18 | box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.12);
19 | transform: translate(-50%, -50%);
20 | min-width: 200px;
21 | max-width: fit-content;
22 | max-height: 85vh;
23 | padding: 20px;
24 | margin-top: -5vh;
25 | background-color: white;
26 | border-radius: 4px;
27 |
28 | &:focus {
29 | outline: "none";
30 | }
31 | `;
32 |
33 | export function Dialog({ children, ...props }) {
34 | return (
35 | // @ts-ignore
36 |
37 |
38 |
39 | {children}
40 |
41 | );
42 | }
43 |
44 | export const DialogContent = React.forwardRef(
45 | // @ts-ignore
46 | ({ children, ...props }, forwardedRef) => (
47 |
52 | {children}
53 |
54 | )
55 | );
56 |
57 | export const DialogTrigger = DialogPrimitive.Trigger;
58 | export const DialogClose = DialogPrimitive.Close;
59 |
--------------------------------------------------------------------------------
/packages/editor-ui/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@editor-ui/editor",
3 | "version": "0.0.0",
4 | "description": "full package of editor ui packages",
5 | "dependencies": {
6 | "@dnd-kit/core": "^2.1.2",
7 | "@dnd-kit/modifiers": "^1.0.5",
8 | "@dnd-kit/sortable": "^2.0.1",
9 | "@dnd-kit/utilities": "^1.0.3",
10 | "@editor-ui/button": "workspace:^",
11 | "@editor-ui/foundation": "workspace:^",
12 | "@editor-ui/hierarchy": "workspace:^",
13 | "@editor-ui/hooks": "workspace:^",
14 | "@editor-ui/multiplayer": "workspace:^",
15 | "@editor-ui/spacer": "workspace:^",
16 | "@editor-ui/utils": "workspace:^",
17 | "@radix-ui/react-dropdown-menu": "^0.1.6",
18 | "@radix-ui/react-icons": "^1.0.3",
19 | "@radix-ui/react-progress": "^0.0.13",
20 | "@radix-ui/react-slider": "^0.0.11",
21 | "@radix-ui/react-tooltip": "^0.0.18",
22 | "@stitches/react": "^1.2.8",
23 | "emotion-icons": "^3.7.0"
24 | },
25 | "peerDependencies": {
26 | "@emotion/core": "^11.0.0",
27 | "@emotion/react": "^11.1.5",
28 | "@emotion/styled": "^11.1.5",
29 | "react": "^17.0.1 || ^18.2.0",
30 | "react-dom": "^17.0.1 || ^18.2.0"
31 | },
32 | "peerDependenciesMeta": {
33 | "@types/react": {
34 | "optional": true
35 | },
36 | "@emotion/react": {
37 | "optional": true
38 | },
39 | "@emotion/styled": {
40 | "optional": true
41 | }
42 | },
43 | "publishConfig": {
44 | "access": "public"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/packages/editor-ui-workspace/layouts/home-scaffold/index.tsx:
--------------------------------------------------------------------------------
1 | import styled from "@emotion/styled";
2 | import React from "react";
3 |
4 | export function HomeScaffold(props: {
5 | children: JSX.Element;
6 | navigation: JSX.Element;
7 | topBar: JSX.Element;
8 | controlDoubleClick: () => void;
9 | }) {
10 | return (
11 |
12 | {props.navigation}
13 |
14 | {props.topBar}
15 | {props.children}
16 |
17 |
18 | );
19 | }
20 |
21 | const NAV_WIDTH = "200px";
22 |
23 | const Root = styled.div`
24 | height: 100vh;
25 | width: 100vw;
26 | display: flex;
27 | flex-direction: row;
28 | overflow: auto;
29 | `;
30 |
31 | const ContentAndTopBarFrame = styled.div`
32 | flex: none;
33 | order: 1;
34 | align-self: stretch;
35 | flex-grow: 1;
36 | margin: 0px 0px;
37 |
38 | /* flex root */
39 | display: flex;
40 | flex-direction: column;
41 | `;
42 |
43 | const NavigationWrapper = styled.div`
44 | height: 100%;
45 | width: ${NAV_WIDTH};
46 | z-index: 1; /* Stay on top */
47 | top: 0; /* Stay at the top */
48 | left: 0;
49 | background-color: #f6f6f6;
50 | overflow-x: auto; /* Disable horizontal scroll */
51 | `;
52 |
53 | const BodyWrapper = styled.div`
54 | /* child of flex */
55 | flex: 1;
56 |
57 | overflow-x: hidden;
58 | overflow-y: scroll;
59 | max-height: 100%;
60 | max-width: 100%;
61 | `;
62 |
--------------------------------------------------------------------------------
/packages/editor-ui-button/loading-indicator/default-loading-indicator.tsx:
--------------------------------------------------------------------------------
1 | /** @jsxRuntime classic */
2 | /** @jsx jsx */
3 | import React from "react";
4 | import { keyframes, css, jsx, SerializedStyles } from "@emotion/react";
5 | import { sizeMarginDefaults } from "./helpers";
6 | import { LoaderSizeMarginProps } from "./interfaces";
7 | import { cssValue } from "./helpers";
8 |
9 | const sync = keyframes`
10 | 33% {transform: translateY(10px)}
11 | 66% {transform: translateY(-10px)}
12 | 100% {transform: translateY(0)}
13 | `;
14 |
15 | class Loader extends React.PureComponent> {
16 | public static defaultProps = sizeMarginDefaults(15);
17 |
18 | public style = (i: number): SerializedStyles => {
19 | const { color, size, margin, speedMultiplier } = this.props;
20 |
21 | return css`
22 | background-color: ${color};
23 | width: ${cssValue(size)};
24 | height: ${cssValue(size)};
25 | margin: ${cssValue(margin)};
26 | border-radius: 100%;
27 | display: inline-block;
28 | animation: ${sync} ${0.6 / speedMultiplier}s ${i * 0.07}s infinite
29 | ease-in-out;
30 | animation-fill-mode: both;
31 | `;
32 | };
33 |
34 | public render(): JSX.Element | null {
35 | const { loading, css } = this.props;
36 |
37 | return loading ? (
38 |
39 |
40 |
41 |
42 |
43 | ) : null;
44 | }
45 | }
46 |
47 | export default Loader;
48 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/property-group-header/property-group-header.tsx:
--------------------------------------------------------------------------------
1 | import React, { forwardRef } from "react";
2 | import styled from "@emotion/styled";
3 |
4 | export const PropertyGroupHeader = forwardRef(function (
5 | {
6 | padding = 16,
7 | children,
8 | dividers,
9 | as,
10 | asButton,
11 | onClick,
12 | ...props
13 | }: React.PropsWithChildren<{
14 | padding?: React.CSSProperties["padding"];
15 | dividers?: boolean;
16 | as?: React.ElementType;
17 | asButton?: boolean;
18 | onClick?: () => void;
19 | }>,
20 | ref: React.Ref
21 | ) {
22 | return (
23 |
35 | {children}
36 | {/* {} */}
37 |
38 | );
39 | });
40 |
41 | const Container = styled.header`
42 | display: flex;
43 | flex-direction: row;
44 | align-items: center;
45 | justify-content: space-between;
46 |
47 | h1,
48 | h2,
49 | h3,
50 | h4,
51 | h5,
52 | h6 {
53 | cursor: default;
54 | font-family: Inter, sans-serif;
55 | font-size: 12px;
56 | font-weight: 600;
57 | margin: 0;
58 | color: ${(p) =>
59 | /* @ts-ignore */
60 | p.theme.foreground};
61 | }
62 | `;
63 |
--------------------------------------------------------------------------------
/packages/console-ui/text-field/index.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import styled from "@emotion/styled";
3 |
4 | export function TextField({
5 | value,
6 | placeholder,
7 | readonly,
8 | onChange,
9 | onEnter,
10 | autoFocus
11 | }: {
12 | onChange?: (value: string) => void;
13 | onEnter?: (value: string) => void;
14 | readonly?: boolean;
15 | value?: string;
16 | placeholder?: string;
17 | autoFocus?: boolean;
18 | }) {
19 | return (
20 |
21 | {
25 | onChange?.(e.target.value);
26 | }}
27 | onKeyDown={(e) => {
28 | if (e.key === "Enter") {
29 | // @ts-ignore
30 | onEnter?.(e.target.value);
31 | }
32 | }}
33 | value={value}
34 | placeholder={placeholder}
35 | />
36 |
37 | );
38 | }
39 |
40 | const Wrap = styled.div`
41 | display: flex;
42 | justify-content: flex-start;
43 | flex-direction: row;
44 | align-items: flex-start;
45 | align-self: stretch;
46 | box-sizing: border-box;
47 | flex-shrink: 0;
48 | `;
49 |
50 | const BaseTextField = styled.input`
51 | display: flex;
52 | justify-content: flex-start;
53 | flex-direction: row;
54 | align-items: flex-start;
55 | border: solid 1px rgba(0, 0, 0, 0.1);
56 | background: rgba(255, 255, 255, 0.08);
57 | border-radius: 4px;
58 | width: 100%;
59 | box-sizing: border-box;
60 | padding: 10px;
61 | font-weight: normal;
62 | font-size: 14px;
63 |
64 | ::placeholder {
65 | opacity: 0.3;
66 | }
67 | `;
68 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/layout/dnd-wrapper/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { useCallback } from "react";
2 | import {
3 | DndContext,
4 | useSensor,
5 | useSensors,
6 | PointerSensor,
7 | closestCenter,
8 | DragEndEvent,
9 | } from "@dnd-kit/core";
10 | import {
11 | restrictToFirstScrollableAncestor,
12 | restrictToVerticalAxis,
13 | } from "@dnd-kit/modifiers";
14 | import {
15 | SortableContext,
16 | verticalListSortingStrategy,
17 | } from "@dnd-kit/sortable";
18 |
19 | interface DnDWrapperProps {
20 | keys: string[];
21 | children: React.ReactNode;
22 | onMoveItem?: (si: number, di: number) => void;
23 | }
24 |
25 | function DnDWrapper(props: DnDWrapperProps) {
26 | const { keys, children, onMoveItem } = props;
27 | const sensors = useSensors(useSensor(PointerSensor));
28 |
29 | const dragEnd = useCallback(
30 | (event: DragEndEvent) => {
31 | const { active, over } = event;
32 |
33 | if (over && active.id !== over.id) {
34 | const oldIndex = keys.indexOf(active.id as string);
35 | const newIndex = keys.indexOf(over.id as string);
36 |
37 | onMoveItem?.(oldIndex, newIndex);
38 | }
39 | },
40 | [keys, onMoveItem]
41 | );
42 |
43 | return (
44 |
50 |
51 | {children}
52 |
53 |
54 | );
55 | }
56 |
57 | export default DnDWrapper;
58 |
--------------------------------------------------------------------------------
/packages/editor-ui-menu/_internal/menu.tsx:
--------------------------------------------------------------------------------
1 | import { CSSObject } from "@emotion/css";
2 | import { Theme } from "@editor-ui/theme";
3 |
4 | export const SEPARATOR_ITEM = "separator";
5 |
6 | export type RegularMenuItem = {
7 | value: T;
8 | title: string;
9 | checked?: boolean;
10 | };
11 |
12 | export type MenuItem =
13 | | typeof SEPARATOR_ITEM
14 | | RegularMenuItem;
15 |
16 | export const styles = {
17 | separatorStyle: ({ theme }: { theme: Theme }): CSSObject => ({
18 | height: "1px",
19 | backgroundColor: theme.colors.divider,
20 | margin: "4px 8px",
21 | }),
22 |
23 | itemStyle: ({
24 | theme,
25 | disabled,
26 | }: {
27 | theme: Theme;
28 | disabled?: boolean;
29 | }): CSSObject => ({
30 | ...(theme.textStyles.small as any),
31 | fontWeight: 500,
32 | fontSize: "0.8rem",
33 | flex: "0 0 auto",
34 | userSelect: "none",
35 | cursor: "pointer",
36 | borderRadius: "3px",
37 | padding: "4px 8px",
38 | ...(disabled && {
39 | color: theme.colors.textDisabled,
40 | }),
41 | "&:focus": {
42 | outline: "none",
43 | color: "white",
44 | backgroundColor: theme.colors.primary,
45 | },
46 | display: "flex",
47 | alignItems: "center",
48 | }),
49 |
50 | contentStyle: ({ theme }: { theme: Theme }): CSSObject => ({
51 | borderRadius: 4,
52 | backgroundColor: theme.colors.popover.background,
53 | color: theme.colors.text,
54 | boxShadow: "0 2px 4px rgba(0,0,0,0.2), 0 0 12px rgba(0,0,0,0.1)",
55 | padding: "4px",
56 | border: `1px solid ${theme.colors.divider}`,
57 | }),
58 | };
59 |
--------------------------------------------------------------------------------
/packages/editor-ui-theme/theme-provider.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | // =========== issue: https://github.com/storybookjs/storybook/issues/10231
4 | import { ThemeProvider as _ThemeProvider, useTheme } from "@emotion/react";
5 | // import { ThemeProvider as _ThemeProvider, useTheme } from "emotion-theming";
6 | // ===========
7 | import styled from "@emotion/styled";
8 |
9 | import { light } from "./light";
10 | import { dark } from "./dark";
11 |
12 | /**
13 | * if both light and dark is checked, it follows system theme, otherwise fallbacks to light.
14 | * @param props
15 | * @returns
16 | */
17 | export function EditorThemeProvider(props: {
18 | children: JSX.Element[] | JSX.Element;
19 | light?: boolean;
20 | dark?: boolean;
21 | theme?: "light" | "dark";
22 | debug?: boolean;
23 | }) {
24 | /**
25 | * 1. use theme props
26 | * 2. use light props
27 | * 3. use dark props
28 | * 4. otherwise, fallback to light
29 | */
30 | const themename =
31 | props?.theme ??
32 | (props.light && "light") ??
33 | (props.dark && "dark") ??
34 | "light";
35 |
36 | const themedata =
37 | typeof themename == "boolean"
38 | ? themename
39 | ? light
40 | : dark
41 | : themename == "light"
42 | ? light
43 | : dark;
44 |
45 | return (
46 | <_ThemeProvider theme={themedata}>
47 | {props.debug && }
48 | {props.children}
49 |
50 | );
51 | }
52 |
53 | function ThemeDebugger() {
54 | const theme = useTheme();
55 | console.log("theme", theme);
56 | return {JSON.stringify(theme)};
57 | }
58 |
59 | export { useTheme };
60 | export { styled };
61 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # Reflect Editor UI
4 |
5 | > React UI Framework for creating productivity applications. - officially supported by [reflect-ui](https://reflect-ui.com)
6 |
7 |
8 |
9 | ## Installation
10 |
11 | ```shell
12 | yarn add @reflect-ui/editor-ui
13 | ```
14 |
15 |
16 |
17 | ## Usage
18 |
19 | ```tsx
20 | import { PropertyCell, PropertyItem, PropertyLabel } from "@reflect-ui/editor-ui"
21 |
22 |
23 | function PropertyList(){
24 | return (
25 |
26 | Rotation
27 |
28 |
29 |
30 |
31 | );
32 | }
33 | ```
34 |
35 | ## Design
36 | Reflect Editor UI's Original design file is opened and available [here][design_file_source]
37 |
38 |
39 | ## Contributing
40 |
41 | - **join chromatic** with this [link](https://www.chromatic.com/builds?appId=606833a032dc6f0021869fe0) you'll get instant access to reflect-editor-ui chromatic
42 | - **read contributing.md** [here](./CONTRIBUTING.md)
43 | - **check out the design file** [here][design_file_source]
44 |
45 |
46 |
47 |
48 |
49 | ## Used by
50 |
51 | - [nothing.app](https://nothing.app) - [github](https://github.com/bridgedxyz/nothing)
52 |
53 | - [surf.codes](https://surf.codes/) - [github](https://github.com/surfcodes/surf)
54 |
55 | - [Bridged](http://bridged.xyz/) - [github](https://github.com/bridgedxyz/bridged)
56 |
57 | - [designto.codes](http://designto.codes/) - [github](https://github.com/bridgedxyz/design-to-code)
58 |
59 |
60 | [design_file_source]: https://www.figma.com/file/g7ly2MT4hQfoGr7sAvw5FO/editor-ui?node-id=133%3A5909
61 |
--------------------------------------------------------------------------------
/packages/editor-ui-context-menu/context-menu/context-menu-root.tsx:
--------------------------------------------------------------------------------
1 | import React, { memo, ReactNode } from "react";
2 | import styled from "@emotion/styled";
3 | import * as ContextMenu from "@radix-ui/react-context-menu";
4 | import { SEPARATOR_ITEM, MenuItem, styles } from "@editor-ui/menu";
5 |
6 | import { ContextMenuItem } from "./context-menu-item";
7 | import { ContextMenuSeparator } from "./context-menu-separator";
8 |
9 | /* ----------------------------------------------------------------------------
10 | * Root
11 | * ------------------------------------------------------------------------- */
12 |
13 | const RootElement = styled(ContextMenu.Content)(styles.contentStyle);
14 |
15 | interface Props {
16 | children: ReactNode;
17 | items: Array> | ReadonlyArray>;
18 | onSelect?: (value: T) => void;
19 | }
20 |
21 | export const ContextMenuRoot = memo(function ContextMenuRoot({
22 | items,
23 | children,
24 | onSelect,
25 | }: Props) {
26 | const hasCheckedItem = items.some(
27 | (item) => item !== SEPARATOR_ITEM && item.checked
28 | );
29 |
30 | return (
31 |
32 | {/* @ts-ignore */}
33 | {children}
34 | {/* @ts-ignore */}
35 |
36 | {items.map((item, index) =>
37 | item === SEPARATOR_ITEM ? (
38 | // @ts-ignore
39 |
40 | ) : (
41 | onSelect?.(item.value)}
46 | >
47 | {item.title}
48 |
49 | )
50 | )}
51 |
52 |
53 | );
54 | });
55 |
--------------------------------------------------------------------------------
/packages/editor-ui-hierarchy/hierachy.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import styled from "@emotion/styled";
3 |
4 | import { HierachyItem } from "./item";
5 |
6 | type GraphicsLayerType = "layout" | "text" | "icon" | "image" | string;
7 | export interface HierarchyData {
8 | id?: string;
9 | title: string;
10 | type?: GraphicsLayerType;
11 | children?: HierarchyData[];
12 | }
13 |
14 | export interface HierachyProps {
15 | /** @inetrnal Expand HierachyItem Function */
16 | onExpand?: () => void;
17 | /** Selected HierachyItem Function */
18 | onSelect: (id: string) => void;
19 | /** HitachyItem Margin Level */
20 | level?: number;
21 | /** Scene Structs */
22 | data: HierarchyData[];
23 | /** Current Selected Id */
24 | selectId: string;
25 | }
26 |
27 | export function Hierachy(props: HierachyProps) {
28 | const [isExpaned, setIsExpaned] = useState(false);
29 | const { level, data: structs, onSelect, selectId } = props;
30 |
31 | return (
32 |
33 | {structs.map((i, ix) => (
34 |
35 | setIsExpaned(!isExpaned)}
41 | onSelect={() => onSelect(i.id)}
42 | />
43 | {i.children && isExpaned && (
44 | setIsExpaned(!isExpaned)}
49 | onSelect={onSelect}
50 | />
51 | )}
52 |
53 | ))}
54 |
55 | );
56 | }
57 |
58 | Hierachy.defaultProps = {
59 | level: 0,
60 | structs: [],
61 | expandIds: [],
62 | };
63 |
64 | const Wrapper = styled.div`
65 | max-width: 230px;
66 | width: 100%;
67 | `;
68 |
--------------------------------------------------------------------------------
/packages/editor-ui-button/loading-indicator/helpers/unit-converter.ts:
--------------------------------------------------------------------------------
1 | import { LengthObject } from "../interfaces";
2 |
3 | const cssUnit: { [unit: string]: boolean } = {
4 | cm: true,
5 | mm: true,
6 | in: true,
7 | px: true,
8 | pt: true,
9 | pc: true,
10 | em: true,
11 | ex: true,
12 | ch: true,
13 | rem: true,
14 | vw: true,
15 | vh: true,
16 | vmin: true,
17 | vmax: true,
18 | "%": true,
19 | };
20 |
21 | /**
22 | * If size is a number, append px to the value as default unit.
23 | * If size is a string, validate against list of valid units.
24 | * If unit is valid, return size as is.
25 | * If unit is invalid, console warn issue, replace with px as the unit.
26 | *
27 | * @param {(number | string)} size
28 | * @return {LengthObject} LengthObject
29 | */
30 | export function parseLengthAndUnit(size: number | string): LengthObject {
31 | if (typeof size === "number") {
32 | return {
33 | value: size,
34 | unit: "px",
35 | };
36 | }
37 | let value: number;
38 | const valueString: string = (size.match(/^[0-9.]*/) || "").toString();
39 | if (valueString.includes(".")) {
40 | value = parseFloat(valueString);
41 | } else {
42 | value = parseInt(valueString, 10);
43 | }
44 |
45 | const unit: string = (size.match(/[^0-9]*$/) || "").toString();
46 |
47 | if (cssUnit[unit]) {
48 | return {
49 | value,
50 | unit,
51 | };
52 | }
53 |
54 | console.warn(
55 | `React Spinners: ${size} is not a valid css value. Defaulting to ${value}px.`
56 | );
57 |
58 | return {
59 | value,
60 | unit: "px",
61 | };
62 | }
63 |
64 | /**
65 | * Take value as an input and return valid css value
66 | *
67 | * @param {(number | string)} value
68 | * @return {string} valid css value
69 | */
70 | export function cssValue(value: number | string): string {
71 | const lengthWithunit: LengthObject = parseLengthAndUnit(value);
72 |
73 | return `${lengthWithunit.value}${lengthWithunit.unit}`;
74 | }
75 |
--------------------------------------------------------------------------------
/packages/editor-ui-context-menu/context-menu/context-menu-item.tsx:
--------------------------------------------------------------------------------
1 | import React, { memo, ReactNode } from "react";
2 | import styled from "@emotion/styled";
3 | import { CheckIcon } from "@radix-ui/react-icons";
4 | import { Spacer } from "@editor-ui/spacer";
5 | import {
6 | Item,
7 | CheckboxItem,
8 | ItemIndicator,
9 | } from "@radix-ui/react-context-menu";
10 | import { MenuItem, styles } from "@editor-ui/menu";
11 | export type { MenuItem };
12 |
13 | /* ----------------------------------------------------------------------------
14 | * Item
15 | * ------------------------------------------------------------------------- */
16 |
17 | const ItemElement = styled(Item)(styles.itemStyle);
18 |
19 | const CheckboxItemElement = styled(CheckboxItem)(styles.itemStyle);
20 |
21 | interface ContextMenuItemProps {
22 | children: ReactNode;
23 | onSelect: () => void;
24 | checked: boolean;
25 | indented: boolean;
26 | }
27 |
28 | const CHECKBOX_WIDTH = 15;
29 | const CHECKBOX_RIGHT_INSET = 3;
30 |
31 | const StyledItemIndicator = styled(ItemIndicator)({
32 | display: "flex",
33 | alignItems: "center",
34 | left: `-${CHECKBOX_WIDTH / 2}px`,
35 | position: "relative",
36 | marginRight: `-${CHECKBOX_RIGHT_INSET}px`,
37 | });
38 |
39 | export const ContextMenuItem = memo(function ContextMenuItem({
40 | indented,
41 | checked,
42 | children,
43 | onSelect,
44 | }: ContextMenuItemProps) {
45 | if (checked) {
46 | return (
47 | // @ts-ignore
48 |
53 |
54 |
55 |
56 | {children}
57 |
58 | );
59 | } else {
60 | return (
61 | // @ts-ignore
62 |
63 | {indented && (
64 |
65 | )}
66 | {children}
67 |
68 | );
69 | }
70 | });
71 |
--------------------------------------------------------------------------------
/packages/console-ui/button/index.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import styled from "@emotion/styled";
3 | import { CSSProperties } from "@emotion/serialize";
4 |
5 | const textcolormap = {
6 | white: "black",
7 | black: "white",
8 | red: "white",
9 | } as const;
10 |
11 | const bgcolormap = {
12 | white: "white",
13 | black: "black",
14 | red: "red",
15 | };
16 |
17 | export const Button = React.forwardRef(function Button({
18 | onClick,
19 | color = "black",
20 | width = "auto",
21 | height = "auto",
22 | children,
23 | disabled,
24 | }: {
25 | onClick?: (e?: React.MouseEvent) => void;
26 | color?: "white" | "black" | "red";
27 | disabled?: boolean;
28 | width?: React.CSSProperties["width"];
29 | height?: React.CSSProperties["height"];
30 | } & React.PropsWithChildren, forwaredRef: React.Ref) {
31 | return (
32 |
43 | {children}
44 |
45 | );
46 | })
47 |
48 | const ButtonBase = styled.button<{
49 | textColor: CSSProperties["color"];
50 | backgroundColor: CSSProperties["color"];
51 | }>`
52 | user-select: none;
53 | cursor: pointer;
54 | border: none;
55 | outline: none;
56 | border-radius: 2px;
57 | align-self: stretch;
58 | background-color: ${(props) => props.backgroundColor};
59 | box-sizing: border-box;
60 | padding: 6px 16px;
61 |
62 | :disabled {
63 | cursor: not-allowed;
64 | opacity: 0.4;
65 | }
66 | :enabled {
67 | :hover {
68 | opacity: 0.8;
69 | }
70 | :active {
71 | opacity: 0.9;
72 | }
73 | }
74 |
75 | :focus {
76 | outline: 1px solid blue;
77 | }
78 |
79 | color: ${(props) => props.textColor};
80 | text-overflow: ellipsis;
81 | font-size: 14px;
82 | font-family: Inter, sans-serif;
83 | font-weight: 500;
84 | `;
85 |
--------------------------------------------------------------------------------
/packages/editor-ui-scroll-area/scroll-area.tsx:
--------------------------------------------------------------------------------
1 | import * as RadixScrollArea from "@radix-ui/react-scroll-area";
2 | import { ReactNode, useCallback, useState } from "react";
3 | import styled from "@editor-ui/theme";
4 |
5 | const SCROLLBAR_SIZE = 10;
6 |
7 | const StyledScrollArea = styled(RadixScrollArea.Root)({
8 | width: "100%",
9 | height: "100%",
10 | });
11 |
12 | const StyledViewport = styled(RadixScrollArea.Viewport)({
13 | width: "100%",
14 | height: "100%",
15 | // Override the `display: table` in the child, since this allows
16 | // elements to expand beyond the width of the viewport.
17 | "& > div": {
18 | display: "block !important",
19 | },
20 | });
21 |
22 | const StyledScrollbar = styled(RadixScrollArea.Scrollbar)({
23 | display: "flex",
24 | padding: "3px",
25 | '&[data-orientation="vertical"]': {
26 | width: SCROLLBAR_SIZE,
27 | },
28 | });
29 |
30 | const StyledThumb = styled(RadixScrollArea.Thumb)(({ theme }) => ({
31 | flex: 1,
32 | borderRadius: SCROLLBAR_SIZE,
33 | backgroundColor: theme.colors.scrollbar,
34 | }));
35 |
36 | const Container = styled.div({
37 | flex: "1 1 0px",
38 | minHeight: 0,
39 | });
40 |
41 | interface Props {
42 | children?: ReactNode | ((scrollElementRef: HTMLDivElement) => ReactNode);
43 | }
44 |
45 | export default function ScrollArea({ children }: Props) {
46 | const [
47 | scrollElementRef,
48 | setScrollElementRef,
49 | ] = useState(null);
50 |
51 | return (
52 |
53 |
54 | setScrollElementRef(ref), [])}
56 | >
57 | {typeof children === "function"
58 | ? scrollElementRef
59 | ? children(scrollElementRef)
60 | : null
61 | : children}
62 |
63 |
64 |
65 |
66 |
67 |
68 | );
69 | }
70 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | lerna-debug.log*
8 |
9 | # Diagnostic reports (https://nodejs.org/api/report.html)
10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
11 |
12 | # Runtime data
13 | pids
14 | *.pid
15 | *.seed
16 | *.pid.lock
17 |
18 | # Directory for instrumented libs generated by jscoverage/JSCover
19 | lib-cov
20 |
21 | # Coverage directory used by tools like istanbul
22 | coverage
23 | *.lcov
24 |
25 | # nyc test coverage
26 | .nyc_output
27 |
28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
29 | .grunt
30 |
31 | # Bower dependency directory (https://bower.io/)
32 | bower_components
33 |
34 | # node-waf configuration
35 | .lock-wscript
36 |
37 | # Compiled binary addons (https://nodejs.org/api/addons.html)
38 | build/Release
39 |
40 | # Dependency directories
41 | node_modules/
42 | jspm_packages/
43 |
44 | # TypeScript v1 declaration files
45 | typings/
46 |
47 | # TypeScript cache
48 | *.tsbuildinfo
49 |
50 | # Optional npm cache directory
51 | .npm
52 |
53 | # Optional eslint cache
54 | .eslintcache
55 |
56 | # Microbundle cache
57 | .rpt2_cache/
58 | .rts2_cache_cjs/
59 | .rts2_cache_es/
60 | .rts2_cache_umd/
61 |
62 | # Optional REPL history
63 | .node_repl_history
64 |
65 | # Output of 'npm pack'
66 | *.tgz
67 |
68 | # Yarn Integrity file
69 | .yarn-integrity
70 |
71 | # dotenv environment variables file
72 | .env
73 | .env.test
74 |
75 | # parcel-bundler cache (https://parceljs.org/)
76 | .cache
77 |
78 | # Next.js build output
79 | .next
80 |
81 | # Nuxt.js build / generate output
82 | .nuxt
83 | dist
84 |
85 | # Gatsby files
86 | .cache/
87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js
88 | # https://nextjs.org/blog/next-9-1#public-directory-support
89 | # public
90 |
91 | # vuepress build output
92 | .vuepress/dist
93 |
94 | # Serverless directories
95 | .serverless/
96 |
97 | # FuseBox cache
98 | .fusebox/
99 |
100 | # DynamoDB Local files
101 | .dynamodb/
102 |
103 | # TernJS port file
104 | .tern-port
105 | .DS_Store
106 |
--------------------------------------------------------------------------------
/packages/editor-ui-button/scaffolds/loading-button.tsx:
--------------------------------------------------------------------------------
1 | import React, { ReactChild, useRef, useState, useEffect } from "react";
2 | import Loading from "../loading-indicator/default-loading-indicator";
3 | import styled from "@emotion/styled";
4 |
5 | interface LoadingButtonProps {
6 | children: ReactChild;
7 | loading?: boolean;
8 | disabled?: boolean;
9 | onClick?: (e) => void;
10 | }
11 |
12 | export function LoadingButton(props: LoadingButtonProps) {
13 | const { loading, disabled, onClick } = props;
14 | const [width, setWidth] = React.useState(0);
15 | const [height, setHeight] = React.useState(0);
16 | const [showLoader, setShowLoader] = useState(false);
17 | const ref = useRef(null);
18 |
19 | useEffect(() => {
20 | // set w/h
21 | if (ref.current && ref.current.getBoundingClientRect().width) {
22 | setWidth(ref.current.getBoundingClientRect().width);
23 | }
24 | if (ref.current && ref.current.getBoundingClientRect().height) {
25 | setHeight(ref.current.getBoundingClientRect().height);
26 | }
27 |
28 | //
29 | if (loading) {
30 | setShowLoader(true);
31 | }
32 |
33 | // Show loader a bits longer to avoid loading flash
34 | if (!loading && showLoader) {
35 | const timeout = setTimeout(() => {
36 | setShowLoader(false);
37 | }, 400);
38 |
39 | return () => {
40 | clearTimeout(timeout);
41 | };
42 | }
43 | }, [loading, showLoader]);
44 |
45 | return (
46 |
53 | {showLoader ? (
54 |
55 | ) : (
56 | props.children
57 | )}
58 |
59 | );
60 | }
61 |
62 | const Button = styled.button<{
63 | widht: number;
64 | height: number;
65 | }>`
66 | width: ${(p) => (p.widht ? p.widht + "px" : undefined)};
67 | height: ${(p) => (p.height ? p.height + "px" : undefined)};
68 | min-height: 24px;
69 | height: 100%;
70 | border: none;
71 | background: black;
72 | color: white;
73 | padding: 16px 20px;
74 | border-radius: 4px;
75 | font-size: large;
76 | `;
77 |
--------------------------------------------------------------------------------
/packages/editor-ui-hierarchy/item/item.stories.mdx:
--------------------------------------------------------------------------------
1 | import { Meta, Story, Canvas } from "@storybook/addon-docs/blocks";
2 |
3 | import HirachyItem from "./";
4 |
5 |
6 |
7 | # Hirachy Item
8 |
9 | `Hirachy Item` Component is for representing a **single structure**
10 |
11 |
12 |
13 |
14 |
21 |
22 |
23 |
24 |
25 | ## Select Item & UnSelect Item
26 |
27 | **Select Item** : Background color changes when users perform events such as click.
28 |
29 | **UnSelect Item** : Changes to Select Item when an unselected item, mouse-hover event, or click event occurs
30 |
31 |
32 |
33 |
52 |
53 |
54 |
55 | ## Item Level Variant (0 ~ 3)
56 |
57 | **Struct's Deps** are called **levels**
58 |
59 | Margin formula for level :
60 |
61 | ```js
62 | const levelMargin = 14;
63 | const defaultMargin = 25;
64 |
65 | return level * levelMargin + defaultMargin;
66 | ```
67 |
68 |
69 |
70 |
71 | {Array(4)
72 | .fill(null)
73 | .map((_, ix) => (
74 |
75 |
83 |
84 | ))}
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/packages/editor-ui-hierarchy/tree-view.tsx:
--------------------------------------------------------------------------------
1 | import React, {
2 | //@ts-ignore
3 | ForwardedRef,
4 | forwardRef,
5 | memo,
6 | ReactNode,
7 | useCallback,
8 | useContext,
9 | } from "react";
10 | import { ChevronDownIcon, ChevronRightIcon } from "@radix-ui/react-icons";
11 | import styled from "@emotion/styled";
12 | import { ListView } from "@editor-ui/listview";
13 | import { ListViewRowProps } from "@editor-ui/listview";
14 | import * as Spacer from "@editor-ui/spacer";
15 |
16 | /* ----------------------------------------------------------------------------
17 | * Row
18 | * ------------------------------------------------------------------------- */
19 |
20 | type TreeRowBaseProps = {
21 | icon?: ReactNode;
22 | depth: number;
23 | expanded?: boolean;
24 | onClickChevron?: () => void;
25 | };
26 |
27 | const ChevronContainer = styled.span({
28 | display: "flex",
29 | alignItems: "center",
30 | });
31 |
32 | export type TreeRowProps<
33 | MenuItemType extends string
34 | > = ListViewRowProps & TreeRowBaseProps;
35 |
36 | const TreeRow = forwardRef(function TreeRow(
37 | {
38 | depth,
39 | icon,
40 | expanded,
41 | onClickChevron,
42 | children,
43 | ...rest
44 | }: TreeRowProps,
45 | forwardedRef: ForwardedRef
46 | ) {
47 | const { expandable } = useContext(ListView.ListRowContext);
48 |
49 | const handleClickChevron = useCallback(
50 | (event) => {
51 | event.stopPropagation();
52 | onClickChevron?.();
53 | },
54 | [onClickChevron]
55 | );
56 |
57 | return (
58 |
59 |
60 | {expandable && (
61 | <>
62 | {expanded === undefined ? (
63 |
64 | ) : (
65 |
66 | {expanded ? : }
67 |
68 | )}
69 |
70 | >
71 | )}
72 | {icon && (
73 | <>
74 | {icon}
75 |
76 | >
77 | )}
78 | {children}
79 |
80 | );
81 | });
82 |
83 | /* ----------------------------------------------------------------------------
84 | * Root
85 | * ------------------------------------------------------------------------- */
86 |
87 | export const Root = ListView.Root;
88 | export const RowTitle = ListView.RowTitle;
89 | export const Row = memo(TreeRow);
90 | export type TreeViewClickInfo = ListView.ListViewClickInfo;
91 |
--------------------------------------------------------------------------------
/packages/editor-ui-alert-dialog/alert-dialog.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { styled, keyframes } from "@stitches/react";
3 | import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
4 | import type { DialogContentProps } from "@radix-ui/react-dialog";
5 |
6 | const overlayShow = keyframes({
7 | "0%": { opacity: 0 },
8 | "100%": { opacity: 1 },
9 | });
10 |
11 | const contentShow = keyframes({
12 | "0%": { opacity: 0, transform: "translate(-50%, -48%) scale(.96)" },
13 | "100%": { opacity: 1, transform: "translate(-50%, -50%) scale(1)" },
14 | });
15 |
16 | const StyledOverlay = styled(AlertDialogPrimitive.Overlay, {
17 | backgroundColor: "rgba(0, 0, 0, 0.1)",
18 | position: "fixed",
19 | zIndex: 9999,
20 | inset: 0,
21 | "@media (prefers-reduced-motion: no-preference)": {
22 | animation: `${overlayShow} 150ms cubic-bezier(0.16, 1, 0.3, 1) forwards`,
23 | },
24 | });
25 |
26 | const StyledContent = styled(AlertDialogPrimitive.Content, {
27 | backgroundColor: "white",
28 | zIndex: 99999,
29 | borderRadius: 6,
30 | boxShadow:
31 | "hsl(206 22% 7% / 35%) 0px 10px 38px -10px, hsl(206 22% 7% / 20%) 0px 10px 20px -15px",
32 | position: "fixed",
33 | top: "50%",
34 | left: "50%",
35 | transform: "translate(-50%, -50%)",
36 | width: "90vw",
37 | maxWidth: "500px",
38 | maxHeight: "85vh",
39 | padding: 25,
40 | "@media (prefers-reduced-motion: no-preference)": {
41 | animation: `${contentShow} 150ms cubic-bezier(0.16, 1, 0.3, 1) forwards`,
42 | },
43 | "&:focus": { outline: "none" },
44 | });
45 |
46 | function Content({
47 | children,
48 | ...props
49 | }: React.PropsWithChildren) {
50 | return (
51 |
52 |
53 | {children}
54 |
55 | );
56 | }
57 |
58 | const StyledTitle = styled(AlertDialogPrimitive.Title, {
59 | margin: 0,
60 | color: "rgba(0, 0, 0, 0.95)",
61 | fontSize: 17,
62 | fontWeight: 500,
63 | });
64 |
65 | const StyledDescription = styled(AlertDialogPrimitive.Description, {
66 | marginBottom: 20,
67 | color: `rgba(0, 0, 0, 0.5)`,
68 | fontSize: 15,
69 | lineHeight: 1.5,
70 | });
71 |
72 | // Exports
73 | export const AlertDialog = AlertDialogPrimitive.Root;
74 | export const AlertDialogTrigger = AlertDialogPrimitive.Trigger;
75 | export const AlertDialogContent = Content;
76 | export const AlertDialogTitle = StyledTitle;
77 | export const AlertDialogDescription = StyledDescription;
78 | export const AlertDialogAction = AlertDialogPrimitive.Action;
79 | export const AlertDialogCancel = AlertDialogPrimitive.Cancel;
80 | export const AlertDialogOverlay = StyledOverlay;
81 | export { AlertDialogPrimitive };
82 |
--------------------------------------------------------------------------------
/packages/editor-ui-button/scaffolds/default-button.tsx:
--------------------------------------------------------------------------------
1 | import React, { ForwardedRef, forwardRef, memo, ReactNode } from "react";
2 | // import styled from "@emotion/styled";
3 | import { Tooltip } from "@editor-ui/tooltip";
4 | import styled from "@editor-ui/theme";
5 |
6 | type ButtonVariant = "normal" | "thin";
7 |
8 | /* ----------------------------------------------------------------------------
9 | * Element
10 | * ------------------------------------------------------------------------- */
11 |
12 | const ButtonElement = styled.button<{
13 | active: boolean;
14 | disabled: boolean;
15 | variant: ButtonVariant;
16 | }>(({ theme, active, disabled, variant }) => ({
17 | ...theme.textStyles.small,
18 | flex: "0 0 auto",
19 | position: "relative",
20 | border: "0",
21 | outline: "none",
22 | minWidth: variant === "thin" ? undefined : "31px",
23 | textAlign: "left",
24 | borderRadius: "4px",
25 | paddingTop: "4px",
26 | paddingRight: variant === "thin" ? "1px" : "6px",
27 | paddingBottom: variant === "thin" ? "0px" : "4px",
28 | paddingLeft: variant === "thin" ? "1px" : "6px",
29 | background: active ? theme.colors.primary : theme.colors.inputBackground,
30 | color: active ? "white" : theme.colors.text,
31 | opacity: disabled ? 0.25 : 1,
32 | "&:focus": {
33 | boxShadow: `0 0 0 1px ${theme.colors.sidebar.background}, 0 0 0 3px ${theme.colors.primary}`,
34 | },
35 | display: "flex",
36 | alignItems: "center",
37 | justifyContent: "center",
38 |
39 | "& *": {
40 | pointerEvents: "none",
41 | },
42 | }));
43 |
44 | /* ----------------------------------------------------------------------------
45 | * Content
46 | * ------------------------------------------------------------------------- */
47 |
48 | const ButtonContent = styled.span(({ theme }) => ({
49 | // Line height of small text - maybe figure out better way to ensure
50 | // icons don't have a smaller height
51 | minHeight: "19px",
52 | display: "flex",
53 | alignItems: "center",
54 | }));
55 |
56 | /* ----------------------------------------------------------------------------
57 | * Root
58 | * ------------------------------------------------------------------------- */
59 |
60 | interface ButtonRootProps {
61 | id: string;
62 | children: ReactNode;
63 | active?: boolean;
64 | disabled?: boolean;
65 | variant?: ButtonVariant;
66 | tooltip?: ReactNode;
67 | onClick?: () => void;
68 | }
69 |
70 | export const Button = memo(
71 | forwardRef(function Button(
72 | {
73 | id,
74 | tooltip,
75 | active = false,
76 | disabled = false,
77 | variant = "normal",
78 | onClick,
79 | children,
80 | }: ButtonRootProps,
81 | forwardedRef: ForwardedRef
82 | ) {
83 | const buttonElement = (
84 |
92 | {children}
93 |
94 | );
95 |
96 | return tooltip ? (
97 | {buttonElement}
98 | ) : (
99 | buttonElement
100 | );
101 | })
102 | );
103 |
--------------------------------------------------------------------------------
/packages/editor-ui-hierarchy/item/index.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import styled from "@emotion/styled";
3 | import { HierarchyData } from "../hierachy";
4 | import Icon from "@editor-ui/icons";
5 |
6 | interface HirachyItemStyledProps {
7 | ml?: number;
8 | selected?: boolean;
9 | expanded?: boolean;
10 | }
11 |
12 | export interface HirachyItemProps {
13 | /** */
14 | onSelect?: () => void;
15 | /** If child exists, the function used to expand */
16 | onExpand?: () => void;
17 | /** A single Struct for visualization */
18 | data: HierarchyData;
19 | /** user selects an item or not item `click, mouse-hover` */
20 | selected?: boolean;
21 | /** margin level of item `14 + level + defaultMargin` */
22 | level: number;
23 | /** */
24 | expanded?: boolean;
25 | /** */
26 | children?: React.ReactNode;
27 | }
28 |
29 | function returnTypeIcon(type: HierarchyData["type"]) {
30 | switch (type) {
31 | case "icon":
32 | return ;
33 | case "layout":
34 | return ;
35 | case "image":
36 | return ;
37 | case "text":
38 | return ;
39 | }
40 | }
41 |
42 | export function HierachyItem(props: HirachyItemProps) {
43 | const {
44 | onExpand,
45 | onSelect,
46 | level,
47 | selected,
48 | expanded,
49 | data: { title, children: child, type },
50 | children,
51 | ...rest
52 | } = props;
53 | return (
54 |
55 |
56 | {expanded != null && (
57 |
58 | )}
59 |
60 |
61 | {returnTypeIcon(type)}
62 | {title}
63 |
64 | {children}
65 |
66 | );
67 | }
68 |
69 | HierachyItem.defaultProps = {
70 | isSelect: false,
71 | level: 0,
72 | };
73 |
74 | const Wrapper = styled.div`
75 | position: relative;
76 | background-color: ${(p) => p.selected && `#514EFD`};
77 | padding-left: ${(p) => p.ml}px;
78 | height: 30px;
79 | margin-right: 9px;
80 | margin: 3px 0px;
81 | border-radius: 6px;
82 | cursor: pointer;
83 | transition: all 0.2s ease;
84 | display: flex;
85 | align-items: center;
86 | justify-content: space-between;
87 |
88 | .indicator {
89 | display: flex;
90 | align-items: center;
91 | padding: 4px;
92 | }
93 |
94 | .label {
95 | display: flex;
96 | align-items: center;
97 | height: 100%;
98 | width: 80%;
99 |
100 | span {
101 | margin-left: 4px;
102 | color: ${(p) => (p.selected ? `#fff` : `#000`)};
103 | font-size: 12px;
104 | }
105 | }
106 |
107 | &:hover {
108 | background-color: #514efd;
109 |
110 | span {
111 | color: #fff;
112 | }
113 | }
114 | `;
115 |
116 | const CustomIcon = styled(Icon)`
117 | transition: all 0.3s ease;
118 | ${(p) =>
119 | p.expanded &&
120 | `
121 | transform : rotate(90deg);
122 |
123 | svg {
124 | path {
125 | fill: #000;
126 | }
127 | }
128 | `}
129 | `;
130 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/property-input-color/property-input-color.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import styled from "../theme/styled";
3 | import { useTheme } from "../theme";
4 | import { PropertyCell } from "../property-cell";
5 |
6 | interface ColorInputProps {
7 | autofocus?: boolean;
8 | placeholder?: string;
9 | type?: "color";
10 | value?: string | number;
11 | readonly?: boolean;
12 | disabled?: boolean;
13 |
14 | onChange?: (value: string) => void;
15 | onClick?: () => void;
16 | }
17 |
18 | export function PropertyColorInput({
19 | autofocus = false,
20 | placeholder,
21 | value: initial = "",
22 | readonly,
23 | disabled,
24 | onChange,
25 | onClick,
26 | }: ColorInputProps) {
27 | const [value, setValue] = React.useState(initial);
28 | const [focused, setFocused] = React.useState(false);
29 | const theme = useTheme();
30 | const inputRef = React.useRef(null);
31 |
32 | const onfocus = () => {
33 | setFocused(true);
34 | };
35 |
36 | const onfocuscapture = () => {
37 | // select all text on focus
38 | inputRef.current?.select();
39 | };
40 |
41 | const onblur = () => {
42 | setFocused(false);
43 | };
44 |
45 | const onvalue = (value: string) => {
46 | setValue(value);
47 | onChange?.(value);
48 | };
49 |
50 | return (
51 |
58 | onvalue(e.target.value)}
67 | style={{
68 | margin: 0,
69 | }}
70 | />
71 | onvalue(e.target.value)}
82 | placeholder={placeholder}
83 | style={{
84 | margin: 0,
85 | }}
86 | />
87 |
88 | );
89 | }
90 |
91 | const ColorPickerInput = styled.input`
92 | height: 100%;
93 | border: none;
94 | outline: none;
95 | background: transparent;
96 | color: ${(props) =>
97 | /* @ts-ignore */
98 | props.theme.input.value};
99 | font-size: 11px;
100 | font-weight: 500;
101 | padding: 0;
102 | `;
103 |
104 | const ColorTextInput = styled.input`
105 | width: 100%;
106 | height: 100%;
107 | border: none;
108 | outline: none;
109 | background: transparent;
110 | color: ${(props) =>
111 | /* @ts-ignore */
112 | props.theme.input.value};
113 | font-size: 11px;
114 | font-weight: 500;
115 | padding: 0;
116 |
117 | &:disabled {
118 | color: ${(props) =>
119 | /* @ts-ignore */
120 | props.theme.input.value_disabled};
121 | }
122 |
123 | ::placeholder {
124 | color: #999;
125 | }
126 | `;
127 |
--------------------------------------------------------------------------------
/packages/editor-ui-theme/light.ts:
--------------------------------------------------------------------------------
1 | import { mediaQuery } from "./media-query";
2 | import { CSSObject } from "@emotion/css";
3 |
4 | export const colors = {
5 | text: "rgb(85, 85, 85)",
6 | textMuted: "rgb(166, 166, 166)",
7 | textDisabled: "rgb(166, 166, 166)",
8 | textDecorativeLight: "rgb(168, 185, 212)",
9 | textLink: "rgb(58, 108, 234)",
10 | textLinkFocused: "rgb(35, 82, 124)",
11 | divider: "rgba(0, 0, 0, 0.07)",
12 | dividerStrong: "rgba(0, 0, 0, 0.09)",
13 | primary: "#DADADA",
14 | primaryLight: "##F7F7F7",
15 | primaryDark: "#A6A6A6",
16 | neutralBackground: "rgb(222,223,232)",
17 | inputBackground: "rgb(240, 240, 242)",
18 | codeBackground: "rgb(250, 250, 250)",
19 | selectedBackground: "rgb(242, 245, 250)",
20 | activeBackground: "rgba(0,0,0,0.1)",
21 | dragOutline: "#A6A6A6",
22 | banner: {
23 | top: "rgb(222, 229, 255)",
24 | bottom: "rgba(252, 252, 254, 1)",
25 | },
26 | title: {
27 | get left() {
28 | return colors.primary;
29 | },
30 | right: "#b9a2ff",
31 | // right: '#93d8ff'
32 | },
33 | button: {
34 | primaryText: "white",
35 | secondaryText: "white",
36 | get primaryBackground() {
37 | return colors.primary;
38 | },
39 | secondaryBackground: "rgb(160, 160, 160)",
40 | },
41 | listView: {
42 | raisedBackground: "rgba(255,255,255,0.8)",
43 | },
44 | canvas: {
45 | background: "rgb(249,249,249)",
46 | dragHandleStroke: "rgba(180,180,180,0.5)",
47 | },
48 | sidebar: {
49 | background: "rgba(252,252,252,0.85)",
50 | },
51 | popover: {
52 | background: "rgb(252,252,252)",
53 | },
54 | slider: {
55 | background: "white",
56 | border: "#BBB",
57 | },
58 | icon: "rgb(139, 139, 139)",
59 | iconSelected: "rgb(220, 220, 220)",
60 | mask: "rgb(12,193,67)",
61 | };
62 |
63 | export const fonts = {
64 | normal: "'Helvetica Neue', Helvetica, Arial, sans-serif",
65 | monospace: "Menlo, Monaco, Consolas, 'Courier New', monospace",
66 | };
67 |
68 | // The last one, 0.85, I just eyeballed
69 | const typeScale = [3.052, 2.441, 1.953, 1.563, 1.25, 1, 0.85]; // Major third
70 |
71 | export const textStyles = {
72 | title: {
73 | fontFamily: fonts.normal,
74 | fontSize: `${typeScale[0]}rem`,
75 | fontWeight: "bold",
76 | lineHeight: "1.4",
77 | [mediaQuery.small]: {
78 | fontSize: "36px",
79 | },
80 | } as CSSObject,
81 | subtitle: {
82 | fontFamily: fonts.normal,
83 | fontSize: `${typeScale[3]}rem`,
84 | fontWeight: 500,
85 | lineHeight: "1.75",
86 | [mediaQuery.small]: {
87 | fontSize: "18px",
88 | },
89 | } as CSSObject,
90 | heading1: {
91 | fontFamily: fonts.normal,
92 | fontSize: `${typeScale[2]}rem`,
93 | fontWeight: 500,
94 | lineHeight: "1.75",
95 | } as CSSObject,
96 | heading2: {
97 | fontFamily: fonts.normal,
98 | fontSize: `${typeScale[3]}rem`,
99 | fontWeight: 500,
100 | lineHeight: "1.75",
101 | } as CSSObject,
102 | heading3: {
103 | fontFamily: fonts.normal,
104 | fontSize: `${typeScale[4]}rem`,
105 | fontWeight: 500,
106 | lineHeight: "1.75",
107 | } as CSSObject,
108 | body: {
109 | fontFamily: fonts.normal,
110 | fontSize: `${typeScale[5]}rem`,
111 | fontWeight: 400,
112 | lineHeight: "1.75",
113 | } as CSSObject,
114 | small: {
115 | fontFamily: fonts.normal,
116 | fontSize: `${typeScale[6]}rem`,
117 | fontWeight: 400,
118 | lineHeight: "1.4",
119 | } as CSSObject,
120 | code: {
121 | fontFamily: fonts.monospace,
122 | fontSize: "90%",
123 | lineHeight: "1.5",
124 | } as CSSObject,
125 | };
126 |
127 | export const sizes = {
128 | sidebarWidth: 260,
129 | // draggable area on frameless mac app
130 | desktopControlWindowBar: {
131 | height: 46,
132 | },
133 | toolbar: {
134 | height: 46,
135 | itemSeparator: 8,
136 | },
137 | spacing: {
138 | nano: 2,
139 | micro: 4,
140 | small: 8,
141 | medium: 16,
142 | large: 32,
143 | xlarge: 64,
144 | xxlarge: 128,
145 | },
146 | };
147 |
148 | export const light = {
149 | colors: colors,
150 | fonts: fonts,
151 | textStyles: textStyles,
152 | sizes: sizes,
153 | };
154 |
--------------------------------------------------------------------------------
/packages/editor-ui-dropdown-menu/dropdown-menu.tsx:
--------------------------------------------------------------------------------
1 | import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
2 | import { styled, keyframes } from "@stitches/react";
3 |
4 | const slideUpAndFade = keyframes({
5 | "0%": { opacity: 0, transform: "translateY(2px)" },
6 | "100%": { opacity: 1, transform: "translateY(0)" },
7 | });
8 |
9 | const slideRightAndFade = keyframes({
10 | "0%": { opacity: 0, transform: "translateX(-2px)" },
11 | "100%": { opacity: 1, transform: "translateX(0)" },
12 | });
13 |
14 | const slideDownAndFade = keyframes({
15 | "0%": { opacity: 0, transform: "translateY(-2px)" },
16 | "100%": { opacity: 1, transform: "translateY(0)" },
17 | });
18 |
19 | const slideLeftAndFade = keyframes({
20 | "0%": { opacity: 0, transform: "translateX(2px)" },
21 | "100%": { opacity: 1, transform: "translateX(0)" },
22 | });
23 |
24 | const StyledContent = styled(DropdownMenuPrimitive.Content, {
25 | minWidth: 220,
26 | backgroundColor: "white",
27 | borderRadius: 6,
28 | padding: 5,
29 | boxShadow:
30 | "0px 10px 38px -10px rgba(22, 23, 24, 0.35), 0px 10px 20px -15px rgba(22, 23, 24, 0.2)",
31 | "@media (prefers-reduced-motion: no-preference)": {
32 | animationDuration: "400ms",
33 | animationTimingFunction: "cubic-bezier(0.16, 1, 0.3, 1)",
34 | animationFillMode: "forwards",
35 | willChange: "transform, opacity",
36 | '&[data-state="open"]': {
37 | '&[data-side="top"]': { animationName: slideDownAndFade },
38 | '&[data-side="right"]': { animationName: slideLeftAndFade },
39 | '&[data-side="bottom"]': { animationName: slideUpAndFade },
40 | '&[data-side="left"]': { animationName: slideRightAndFade },
41 | },
42 | },
43 | });
44 |
45 | const itemStyles = {
46 | all: "unset",
47 | fontSize: 13,
48 | lineHeight: 1,
49 | // color: violet.violet11,
50 | borderRadius: 3,
51 | display: "flex",
52 | gap: 4,
53 | alignItems: "center",
54 | height: 25,
55 | padding: "0 5px",
56 | position: "relative",
57 | paddingLeft: 8,
58 | userSelect: "none",
59 |
60 | "&[data-disabled]": {
61 | // color: mauve.mauve8,
62 | opacity: 0.5,
63 | pointerEvents: "none",
64 | },
65 |
66 | "&:focus": {
67 | backgroundColor: `rgba(0, 0, 0, 0.1)`,
68 | // color: violet.violet1,
69 | },
70 | };
71 |
72 | const StyledItem = styled(DropdownMenuPrimitive.Item, { ...itemStyles });
73 | const StyledCheckboxItem = styled(DropdownMenuPrimitive.CheckboxItem, {
74 | ...itemStyles,
75 | });
76 | const StyledRadioItem = styled(DropdownMenuPrimitive.RadioItem, {
77 | ...itemStyles,
78 | });
79 | const StyledTriggerItem = styled(DropdownMenuPrimitive.SubTrigger, {
80 | '&[data-state="open"]': {
81 | // backgroundColor: violet.violet4,
82 | // color: violet.violet11,
83 | },
84 | ...itemStyles,
85 | });
86 |
87 | const StyledLabel = styled(DropdownMenuPrimitive.Label, {
88 | paddingLeft: 25,
89 | fontSize: 12,
90 | lineHeight: "25px",
91 | // color: mauve.mauve11,
92 | });
93 |
94 | const StyledSeparator = styled(DropdownMenuPrimitive.Separator, {
95 | height: 1,
96 | backgroundColor: "rgba(0, 0, 0, 0.2)",
97 | margin: 5,
98 | });
99 |
100 | const StyledItemIndicator = styled(DropdownMenuPrimitive.ItemIndicator, {
101 | position: "absolute",
102 | left: 0,
103 | width: 25,
104 | display: "inline-flex",
105 | alignItems: "center",
106 | justifyContent: "center",
107 | });
108 |
109 | const StyledArrow = styled(DropdownMenuPrimitive.Arrow, {
110 | fill: "white",
111 | });
112 |
113 | // Exports
114 | export const DropdownMenu = DropdownMenuPrimitive.Root;
115 | export const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
116 | export const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
117 | export const DropdownMenuContent = StyledContent;
118 | export const DropdownMenuItem = StyledItem;
119 | export const DropdownMenuCheckboxItem = StyledCheckboxItem;
120 | export const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
121 | export const DropdownMenuRadioItem = StyledRadioItem;
122 | export const DropdownMenuItemIndicator = StyledItemIndicator;
123 | export const DropdownMenuTriggerItem = StyledTriggerItem;
124 | export const DropdownMenuLabel = StyledLabel;
125 | export const DropdownMenuSeparator = StyledSeparator;
126 | export const DropdownMenuArrow = StyledArrow;
127 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/property-input-select/property-input-select.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import styled from "@emotion/styled";
3 | import * as Select from "@radix-ui/react-select";
4 | import {
5 | CheckIcon,
6 | ChevronDownIcon,
7 | ChevronUpIcon,
8 | } from "@radix-ui/react-icons";
9 | import { css } from "@emotion/react";
10 |
11 | type OptionsInput = Array<{ label: string; value: string }> | Array;
12 |
13 | interface SelectInputProps {
14 | autofocus?: boolean;
15 | value?: string;
16 | placeholder?: string;
17 | options?: OptionsInput;
18 |
19 | readonly?: boolean;
20 | disabled?: boolean;
21 |
22 | onChange?: (value: string) => void;
23 | onClick?: () => void;
24 |
25 | // aria
26 | ariaLabel?: string;
27 | }
28 |
29 | export function PropertySelectInput({
30 | autofocus = false,
31 | placeholder,
32 | options: _options = [],
33 | readonly,
34 | disabled,
35 | value: initial,
36 | ariaLabel,
37 | onChange,
38 | }: SelectInputProps) {
39 | const [value, setValue] = React.useState(initial);
40 | const options = React.useMemo(
41 | () =>
42 | _options.map((o) => {
43 | if (typeof o === "string") {
44 | return {
45 | label: o,
46 | value: o,
47 | };
48 | }
49 | return o;
50 | }),
51 | [_options]
52 | );
53 |
54 | return (
55 | {
57 | setValue(v);
58 | onChange?.(v);
59 | }}
60 | value={value}
61 | disabled={disabled}
62 | >
63 |
68 |
69 |
70 |
71 |
72 |
73 |
78 |
79 |
80 |
81 |
82 |
83 | {options.map(({ value, label }) => (
84 |
85 | {label}
86 |
87 | ))}
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 | );
96 | }
97 |
98 | const SelectItem = React.forwardRef(
99 | (
100 | { children, ...props }: React.PropsWithChildren,
101 | forwardedRef: React.Ref
102 | ) => {
103 | return (
104 |
105 | {children}
106 |
107 |
108 |
109 |
110 | );
111 | }
112 | );
113 |
114 | const StyledSelectItem = styled(Select.Item)`
115 | font-family: sans-serif;
116 | font-size: 11px;
117 | line-height: 1;
118 | color: #1a1a1a;
119 | border-radius: 3px;
120 | display: flex;
121 | align-items: center;
122 | height: 25px;
123 | padding: 0 35px 0 25px;
124 | position: relative;
125 | user-select: none;
126 |
127 | &[data-disabled] {
128 | color: rgba(0, 0, 0, 0.2);
129 | pointer-events: none;
130 | }
131 | &[data-highlighted] {
132 | outline: none;
133 | background-color: rgba(0, 0, 0, 0.1);
134 | color: var(--violet1);
135 | }
136 |
137 | .indicator {
138 | position: absolute;
139 | left: 0;
140 | width: 25px;
141 | display: inline-flex;
142 | align-items: center;
143 | justify-content: center;
144 | }
145 |
146 | /* */
147 | `;
148 |
149 | const StyledTrigger = styled(Select.Trigger)`
150 | all: unset;
151 | font-family: sans-serif;
152 | display: inline-flex;
153 | align-items: center;
154 | justify-content: center;
155 | border-radius: 4px;
156 | padding: 0 8px;
157 | font-size: 11px;
158 | line-height: 1;
159 | height: 24px;
160 | gap: 4px;
161 | background-color: white;
162 | color: #1a1a1a;
163 | box-shadow: 0 2px 2px rgba(22, 23, 24, 0.1);
164 |
165 | &:hover {
166 | background-color: #f2f2f2;
167 | }
168 |
169 | &:focus {
170 | box-shadow: 0 0 0 1px black;
171 | }
172 |
173 | &[data-placeholder] {
174 | color: #3c3c3c;
175 | }
176 |
177 | .icon {
178 | color: #1a1a1a;
179 | }
180 | `;
181 |
182 | const SelectScrollButton = css`
183 | display: flex;
184 | align-items: center;
185 | justify-content: center;
186 | height: 25px;
187 | background-color: white;
188 | color: #1a1a1a;
189 | cursor: default;
190 | `;
191 |
192 | const SelectScrollUpButton = styled(Select.ScrollUpButton)`
193 | ${SelectScrollButton}
194 | `;
195 |
196 | const SelectScrollDownButton = styled(Select.ScrollDownButton)`
197 | ${SelectScrollButton}
198 | `;
199 |
200 | const SelectContent = styled(Select.Content)`
201 | overflow: hidden;
202 | background-color: white;
203 | border-radius: 6px;
204 | box-shadow: 0px 10px 38px -10px rgba(22, 23, 24, 0.35),
205 | 0px 10px 20px -15px rgba(22, 23, 24, 0.2);
206 | `;
207 |
--------------------------------------------------------------------------------
/packages/editor-ui-property/property-input/property-input.tsx:
--------------------------------------------------------------------------------
1 | import styled from "../theme/styled";
2 | import React, { useEffect } from "react";
3 |
4 | import { PropertyCell } from "../property-cell";
5 | import { useTheme } from "../theme";
6 | import { input_type_number_disable_browser_default_appearence } from "../css";
7 | import { css } from "@emotion/react";
8 |
9 | type PropertyInputType = "number" | "text" | "select";
10 |
11 | export type PropertyInputProps = PlainInputProps;
12 |
13 | interface PlainInputProps {
14 | autofocus?: boolean;
15 | prefix?: React.ReactNode;
16 | suffix?: React.ReactNode;
17 | placeholder?: string;
18 | type?: PropertyInputType;
19 | value?: string | number;
20 | min?: number;
21 | max?: number;
22 | readonly?: boolean;
23 | disabled?: boolean;
24 | stopPropagation?: boolean;
25 |
26 | /**
27 | * The pattern attribute specifies a regular expression the form control's value should match. If a non-null value doesn't conform to the constraints set by the pattern value, the ValidityState object's read-only patternMismatch property will be true.
28 | */
29 | pattern?: string;
30 | onChange?: (value: string) => void;
31 | onClick?: () => void;
32 | }
33 |
34 | export function PropertyInput({
35 | autofocus = false,
36 | prefix,
37 | suffix,
38 | placeholder,
39 | type = "text",
40 | value: initial = "",
41 | min,
42 | max,
43 | readonly,
44 | disabled,
45 | pattern,
46 | stopPropagation,
47 | onChange,
48 | onClick,
49 | }: PropertyInputProps) {
50 | const [focused, setFocused] = React.useState(false);
51 | const [value, setValue] = React.useState(initial);
52 | const theme = useTheme();
53 | const inputRef = React.useRef(null);
54 |
55 | useEffect(() => {
56 | setValue(initial);
57 | }, [initial]);
58 |
59 | const onclick = (e) => {
60 | if (inputRef.current) {
61 | inputRef.current.focus();
62 | }
63 | onClick?.();
64 | e.stopPropagation();
65 | };
66 |
67 | const onvalue = (value: string) => {
68 | setValue(value);
69 | onChange?.(value);
70 | };
71 |
72 | const onfocus = () => {
73 | setFocused(true);
74 | };
75 |
76 | const onfocuscapture = () => {
77 | // select all text on focus
78 | inputRef.current?.select();
79 | };
80 |
81 | const onblur = () => {
82 | setFocused(false);
83 | };
84 |
85 | const onkeydown = (e: React.KeyboardEvent) => {
86 | if (e.key === "Enter" || e.key === "Escape") {
87 | inputRef.current?.blur();
88 | }
89 |
90 | if (readonly) {
91 | return;
92 | }
93 |
94 | // up or down key ally
95 | if (type === "number" && (e.key === "ArrowUp" || e.key === "ArrowDown")) {
96 | e.preventDefault(); // this is required to prevent number's default behavior
97 | // if shift key is pressed, increase or decrease by 10
98 | // if ctrl / cmd key is pressed, increase or decrease by 0.1
99 | // if both shift and ctrl / cmd key is pressed, increase or decrease by 100
100 | const step = e.shiftKey
101 | ? e.ctrlKey || e.metaKey
102 | ? 100
103 | : 10
104 | : e.ctrlKey || e.metaKey
105 | ? 0.1
106 | : 1;
107 |
108 | const value = Number(inputRef.current?.value);
109 | const newValue = e.key === "ArrowUp" ? value + step : value - step;
110 | onvalue("" + newValue);
111 | }
112 |
113 | if (stopPropagation) {
114 | e.stopPropagation();
115 | }
116 | };
117 |
118 | return (
119 |
126 | {prefix && {prefix} }
127 | onvalue(e.target.value)}
139 | placeholder={placeholder}
140 | pattern={pattern}
141 | min={min}
142 | max={max}
143 | style={{
144 | margin: 0,
145 | marginLeft: !prefix ? 8 : 0,
146 | marginRight: !suffix ? 8 : 0,
147 | }}
148 | />
149 | {suffix && {suffix} }
150 |
151 | );
152 | }
153 |
154 | export function PropertyNumericInput({
155 | onChange,
156 | ...props
157 | }: Omit, "type" | "onChange"> & {
158 | onChange?: (value: number) => void;
159 | }) {
160 | return (
161 | {
165 | const val = Number(txt);
166 | if (isNaN(val)) {
167 | return;
168 | }
169 | onChange?.(val);
170 | }}
171 | />
172 | );
173 | }
174 |
175 | const PlainInput = styled.input`
176 | width: 100%;
177 | height: 100%;
178 | border: none;
179 | outline: none;
180 | background: transparent;
181 | color: ${(props) =>
182 | /* @ts-ignore */
183 | props.theme.input.value};
184 | font-size: 11px;
185 | font-weight: 500;
186 | padding: 0;
187 |
188 | &:disabled {
189 | color: ${(props) =>
190 | // @ts-ignore
191 | props.theme.input.value_disabled};
192 | }
193 |
194 | ::placeholder {
195 | color: #999;
196 | }
197 |
198 | ${input_type_number_disable_browser_default_appearence}
199 | `;
200 |
201 | const _fix = css`
202 | cursor: default;
203 | flex-shrink: 0;
204 | display: flex;
205 | align-items: center;
206 | justify-content: center;
207 | font-family: Inter, sans-serif;
208 | font-size: 9px;
209 | height: 24px;
210 | width: 24px;
211 | `;
212 |
213 | const Prefix = styled.span`
214 | ${_fix}
215 | color: ${(props) =>
216 | // @ts-ignore
217 | props.theme.input.prefix};
218 | `;
219 |
220 | const Suffix = styled.span`
221 | ${_fix}
222 | color: ${(props) =>
223 | // @ts-ignore
224 | props.theme.input.suffix};
225 | `;
226 |
--------------------------------------------------------------------------------
/packages/editor-ui-hooks/use-hover.ts:
--------------------------------------------------------------------------------
1 | // From: https://github.com/radix-ui/primitives/blob/main/packages/react/scroll-area/src/useHover.ts
2 | // MIT License
3 |
4 | // This code is a fork of `react-aria`'s `useHover` hook. The code in this file are based on code
5 | // from both `react-aria` and `react-interactions`. Original licensing for each project can be found
6 | // in the the root directories of each respective repository.
7 | //
8 | // @see https://github.com/adobe/react-spectrum/tree/452d1cb6a49f9f493757737edaf2b64014108de6/packages/%40react-aria
9 | // @see https://github.com/facebook/react/tree/cc7c1aece46a6b69b41958d731e0fd27c94bfc6c/packages/react-interactions
10 |
11 | import * as React from "react";
12 |
13 | export interface HoverEvent {
14 | /** The type of hover event being fired. */
15 | type: "hoverstart" | "hoverend";
16 | /** The pointer type that triggered the hover event. */
17 | pointerType: "mouse" | "pen";
18 | /** The target element of the hover event. */
19 | target: HTMLElement;
20 | }
21 |
22 | export interface HoverEvents {
23 | /** Handler that is called when a hover interaction starts. */
24 | onHoverStart?(e: HoverEvent): void;
25 | /** Handler that is called when a hover interaction ends. */
26 | onHoverEnd?(e: HoverEvent): void;
27 | /** Handler that is called when the hover state changes. */
28 | onHoverChange?(isHovering: boolean): void;
29 | }
30 |
31 | export interface HoverProps extends HoverEvents {
32 | /** Whether the hover events should be disabled. */
33 | isDisabled?: boolean;
34 | }
35 |
36 | interface HoverResult {
37 | /** Props to spread on the target element. */
38 | hoverProps: React.HTMLAttributes;
39 | isHovered: boolean;
40 | }
41 |
42 | // iOS fires onPointerEnter twice: once with pointerType="touch" and again with pointerType="mouse".
43 | // We want to ignore these emulated events so they do not trigger hover behavior.
44 | // See https://bugs.webkit.org/show_bug.cgi?id=214609.
45 | let globalIgnoreEmulatedMouseEvents = false;
46 | let hoverCount = 0;
47 |
48 | function setGlobalIgnoreEmulatedMouseEvents() {
49 | globalIgnoreEmulatedMouseEvents = true;
50 |
51 | // Clear globalIgnoreEmulatedMouseEvents after a short timeout. iOS fires onPointerEnter with
52 | // pointerType="mouse" immediately after onPointerUp and before onFocus. On other devices that
53 | // don't have this quirk, we don't want to ignore a mouse hover sometime in the distant future
54 | // because a user previously touched the element.
55 | setTimeout(function clearGlobalIgnoreEmulatedMouseEvents() {
56 | globalIgnoreEmulatedMouseEvents = false;
57 | }, 50);
58 | }
59 |
60 | function handleGlobalPointerEvent(event: PointerEvent) {
61 | if (event.pointerType === "touch") {
62 | setGlobalIgnoreEmulatedMouseEvents();
63 | }
64 | }
65 |
66 | function setupGlobalTouchEvents() {
67 | if (typeof document === "undefined") {
68 | return;
69 | }
70 |
71 | document.addEventListener("pointerup", handleGlobalPointerEvent);
72 |
73 | hoverCount++;
74 | return function teardownGlobalTouchEvents() {
75 | hoverCount--;
76 | if (hoverCount > 0) {
77 | return;
78 | }
79 | document.removeEventListener("pointerup", handleGlobalPointerEvent);
80 | };
81 | }
82 |
83 | /**
84 | * Handles pointer hover interactions for an element. Normalizes behavior
85 | * across browsers and platforms, and ignores emulated mouse events on touch devices.
86 | */
87 | export function useHover(props: HoverProps = {}): HoverResult {
88 | const { onHoverStart, onHoverChange, onHoverEnd, isDisabled } = props;
89 |
90 | const [isHovered, setHovered] = React.useState(false);
91 | const state = React.useRef({
92 | isHovered: false,
93 | ignoreEmulatedMouseEvents: false,
94 | }).current;
95 |
96 | React.useEffect(setupGlobalTouchEvents, []);
97 |
98 | const hoverProps = React.useMemo(
99 | function getHoverProps() {
100 | function triggerHoverStart(
101 | event:
102 | | PointerEvent
103 | | React.PointerEvent
104 | | MouseEvent
105 | | React.MouseEvent,
106 | pointerType: "mouse" | "pen" | "touch"
107 | ) {
108 | if (isDisabled || pointerType === "touch" || state.isHovered) {
109 | return;
110 | }
111 |
112 | state.isHovered = true;
113 | const target = event.target as HTMLElement;
114 |
115 | if (onHoverStart) {
116 | onHoverStart({
117 | type: "hoverstart",
118 | target,
119 | pointerType,
120 | });
121 | }
122 |
123 | if (onHoverChange) {
124 | onHoverChange(true);
125 | }
126 |
127 | setHovered(true);
128 | }
129 |
130 | function triggerHoverEnd(
131 | event:
132 | | PointerEvent
133 | | React.PointerEvent
134 | | MouseEvent
135 | | React.MouseEvent,
136 | pointerType: "mouse" | "pen" | "touch"
137 | ) {
138 | if (isDisabled || pointerType === "touch" || !state.isHovered) {
139 | return;
140 | }
141 |
142 | state.isHovered = false;
143 | const target = event.target as HTMLElement;
144 |
145 | if (onHoverEnd) {
146 | onHoverEnd({
147 | type: "hoverend",
148 | target,
149 | pointerType,
150 | });
151 | }
152 |
153 | if (onHoverChange) {
154 | onHoverChange(false);
155 | }
156 |
157 | setHovered(false);
158 | }
159 |
160 | const hoverProps: React.HTMLAttributes = {
161 | onPointerEnter(event: React.PointerEvent) {
162 | if (
163 | globalIgnoreEmulatedMouseEvents &&
164 | event.pointerType === "mouse"
165 | ) {
166 | return;
167 | }
168 | triggerHoverStart(event, event.pointerType);
169 | },
170 | onPointerLeave(event: React.PointerEvent) {
171 | triggerHoverEnd(event, event.pointerType);
172 | },
173 | };
174 |
175 | return hoverProps;
176 | },
177 | [isDisabled, state, onHoverStart, onHoverChange, onHoverEnd]
178 | );
179 |
180 | return {
181 | hoverProps,
182 | isHovered,
183 | };
184 | }
185 |
--------------------------------------------------------------------------------
/packages/editor-ui-sortable/sortable.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | closestCenter,
3 | DndContext,
4 | DragEndEvent,
5 | DragMoveEvent,
6 | DragOverlay,
7 | DragStartEvent,
8 | PointerSensor,
9 | Translate,
10 | useSensor,
11 | useSensors,
12 | } from "@dnd-kit/core";
13 | import {
14 | SortableContext,
15 | useSortable,
16 | verticalListSortingStrategy,
17 | } from "@dnd-kit/sortable";
18 | import React, {
19 | createContext,
20 | memo,
21 | ReactNode,
22 | Ref,
23 | useCallback,
24 | useContext,
25 | useMemo,
26 | useRef,
27 | useState,
28 | } from "react";
29 | import { createPortal } from "react-dom";
30 |
31 | export type RelativeDropPosition = "above" | "below" | "inside";
32 |
33 | export type DropValidator = (
34 | sourceId: string,
35 | destinationId: string,
36 | position: RelativeDropPosition
37 | ) => boolean;
38 |
39 | const defaultAcceptsDrop: DropValidator = (
40 | sourceId,
41 | destinationId,
42 | position
43 | ) => {
44 | return position !== "inside" && sourceId !== destinationId;
45 | };
46 |
47 | const SortableItemContext = createContext<{
48 | position: Translate;
49 | acceptsDrop: DropValidator;
50 | setActivatorEvent: (event: PointerEvent) => void;
51 | }>({
52 | position: { x: 0, y: 0 },
53 | acceptsDrop: defaultAcceptsDrop,
54 | setActivatorEvent: () => {},
55 | });
56 |
57 | function validateDropIndicator(
58 | acceptsDrop: DropValidator,
59 | activeId: string,
60 | overId: string,
61 | offsetTop: number,
62 | elementTop: number,
63 | elementHeight: number
64 | ): RelativeDropPosition | undefined {
65 | const acceptsDropInside = acceptsDrop(activeId, overId, "inside");
66 |
67 | // If we're in the center of the element, prefer dropping inside
68 | if (
69 | offsetTop >= elementTop + elementHeight / 3 &&
70 | offsetTop <= elementTop + (elementHeight * 2) / 3 &&
71 | acceptsDropInside
72 | )
73 | return "inside";
74 |
75 | // Are we over the top or bottom half of the element?
76 | const indicator =
77 | offsetTop < elementTop + elementHeight / 2 ? "above" : "below";
78 |
79 | // Drop above or below if possible, falling back to inside
80 | return acceptsDrop(activeId, overId, indicator)
81 | ? indicator
82 | : acceptsDropInside
83 | ? "inside"
84 | : undefined;
85 | }
86 |
87 | /* ----------------------------------------------------------------------------
88 | * Item
89 | * ------------------------------------------------------------------------- */
90 |
91 | type UseSortableReturnType = ReturnType;
92 |
93 | interface ItemProps {
94 | id: string;
95 | disabled?: boolean;
96 | children: (
97 | props: {
98 | ref: Ref;
99 | relativeDropPosition?: RelativeDropPosition;
100 | [key: string]: any;
101 | } & UseSortableReturnType["attributes"]
102 | ) => JSX.Element;
103 | }
104 |
105 | function SortableItem({
106 | id,
107 | disabled,
108 | children,
109 | }: ItemProps) {
110 | const { position, acceptsDrop, setActivatorEvent } =
111 | useContext(SortableItemContext);
112 | const sortable = useSortable({ id, disabled });
113 |
114 | const {
115 | active,
116 | activatorEvent,
117 | attributes,
118 | listeners,
119 | setNodeRef,
120 | isDragging,
121 | index,
122 | overIndex,
123 | over,
124 | } = sortable;
125 |
126 | if (activatorEvent) {
127 | setActivatorEvent(activatorEvent as PointerEvent);
128 | }
129 |
130 | const eventY = (activatorEvent as PointerEvent | null)?.clientY ?? 0;
131 | const offsetTop = eventY + position.y;
132 |
133 | const ref = useCallback((node: T) => setNodeRef(node), [setNodeRef]);
134 |
135 | return children({
136 | ref,
137 | ...attributes,
138 | ...listeners,
139 | relativeDropPosition:
140 | index === overIndex && !isDragging && active && over
141 | ? validateDropIndicator(
142 | acceptsDrop,
143 | active.id,
144 | over.id,
145 | offsetTop,
146 | over.rect.offsetTop,
147 | over.rect.height
148 | )
149 | : undefined,
150 | });
151 | }
152 |
153 | /* ----------------------------------------------------------------------------
154 | * Root
155 | * ------------------------------------------------------------------------- */
156 |
157 | interface RootProps {
158 | keys: string[];
159 | children: ReactNode;
160 | renderOverlay?: (index: number) => ReactNode;
161 | onMoveItem?: (
162 | sourceIndex: number,
163 | destinationIndex: number,
164 | position: RelativeDropPosition
165 | ) => void;
166 | acceptsDrop?: DropValidator;
167 | }
168 |
169 | function SortableRoot({
170 | keys,
171 | children,
172 | onMoveItem,
173 | renderOverlay,
174 | acceptsDrop = defaultAcceptsDrop,
175 | }: RootProps) {
176 | const [_document, set_document] = React.useState(null);
177 | React.useEffect(() => {
178 | set_document(document);
179 | }, []);
180 |
181 | const sensors = useSensors(
182 | useSensor(PointerSensor, {
183 | activationConstraint: {
184 | distance: 4,
185 | },
186 | })
187 | );
188 |
189 | const [activeIndex, setActiveIndex] = useState();
190 | const activatorEvent = useRef(null);
191 |
192 | const setActivatorEvent = useCallback((event: PointerEvent) => {
193 | activatorEvent.current = event;
194 | }, []);
195 |
196 | const [position, setPosition] = useState({ x: 0, y: 0 });
197 |
198 | const handleDragStart = useCallback(
199 | (event: DragStartEvent) => {
200 | setActiveIndex(keys.indexOf(event.active.id));
201 | },
202 | [keys]
203 | );
204 |
205 | const handleDragMove = useCallback((event: DragMoveEvent) => {
206 | setPosition({ ...event.delta });
207 | }, []);
208 |
209 | const handleDragEnd = useCallback(
210 | (event: DragEndEvent) => {
211 | const { active, over } = event;
212 |
213 | setActiveIndex(undefined);
214 |
215 | if (over && active.id !== over.id) {
216 | const oldIndex = keys.indexOf(active.id);
217 | const newIndex = keys.indexOf(over.id);
218 |
219 | const eventY = activatorEvent.current?.clientY ?? 0;
220 | const offsetTop = eventY + position.y;
221 |
222 | const indicator = validateDropIndicator(
223 | acceptsDrop,
224 | active.id,
225 | over.id,
226 | offsetTop,
227 | over.rect.offsetTop,
228 | over.rect.height
229 | );
230 |
231 | if (!indicator) return;
232 |
233 | onMoveItem?.(oldIndex, newIndex, indicator);
234 | }
235 | },
236 | [acceptsDrop, keys, onMoveItem, position.y]
237 | );
238 |
239 | return (
240 | ({
243 | acceptsDrop,
244 | position,
245 | setActivatorEvent,
246 | }),
247 | [acceptsDrop, position, setActivatorEvent]
248 | )}
249 | >
250 | {/* @ts-ignore */}
251 |
258 |
259 | {children}
260 |
261 | {renderOverlay &&
262 | _document &&
263 | createPortal(
264 |
265 | {activeIndex !== undefined && renderOverlay(activeIndex)}
266 | ,
267 | _document.body
268 | )}
269 |
270 |
271 | );
272 | }
273 |
274 | export const Item = memo(SortableItem);
275 | export const Root = memo(SortableRoot);
276 |
--------------------------------------------------------------------------------
/packages/editor-ui-icons/icons.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | interface IconListProps {
4 | width: number;
5 | height: number;
6 | svg: JSX.Element;
7 | }
8 |
9 | export interface IconList {
10 | indicator: IconListProps;
11 | hirachyLayout: IconListProps;
12 | hirachyText: IconListProps;
13 | hirachyImage: IconListProps;
14 | pipette: IconListProps;
15 | headerInsert: IconListProps;
16 | headerScreen: IconListProps;
17 | headerFrame: IconListProps;
18 | headerText: IconListProps;
19 | headerScroll: IconListProps;
20 | headerPage: IconListProps;
21 | headerComponent: IconListProps;
22 | headerVariables: IconListProps;
23 | headerHandoff: IconListProps;
24 | headerZoom: IconListProps;
25 | xPostion: IconListProps;
26 | yPostion: IconListProps;
27 | close: IconListProps;
28 | allBoundary: IconListProps;
29 | cornerBoundary: IconListProps;
30 | }
31 |
32 | const icons: IconList = {
33 | indicator: {
34 | width: 12,
35 | height: 12,
36 | svg: ,
37 | },
38 | hirachyLayout: {
39 | width: 12,
40 | height: 12,
41 | svg: (
42 |
48 | ),
49 | },
50 | hirachyText: {
51 | width: 12,
52 | height: 12,
53 | svg: (
54 |
60 | ),
61 | },
62 | hirachyImage: {
63 | width: 12,
64 | height: 12,
65 | svg: (
66 |
70 | ),
71 | },
72 | pipette: {
73 | width: 16,
74 | height: 16,
75 | svg: (
76 |
80 | ),
81 | },
82 | headerComponent: {
83 | width: 24,
84 | height: 24,
85 | svg: (
86 |
92 | ),
93 | },
94 | headerFrame: {
95 | width: 24,
96 | height: 24,
97 | svg: ,
98 | },
99 | headerHandoff: {
100 | width: 24,
101 | height: 24,
102 | svg: (
103 |
109 | ),
110 | },
111 | headerInsert: {
112 | width: 24,
113 | height: 24,
114 | svg: ,
115 | },
116 | headerPage: {
117 | width: 24,
118 | height: 24,
119 | svg: (
120 | <>
121 |
122 |
126 | >
127 | ),
128 | },
129 | headerScreen: {
130 | width: 24,
131 | height: 24,
132 | svg: (
133 | <>
134 |
135 |
139 | >
140 | ),
141 | },
142 | headerScroll: {
143 | width: 24,
144 | height: 24,
145 | svg: (
146 | <>
147 |
148 |
152 |
156 | >
157 | ),
158 | },
159 | headerText: {
160 | width: 24,
161 | height: 24,
162 | svg: (
163 |
169 | ),
170 | },
171 | headerVariables: {
172 | width: 24,
173 | height: 24,
174 | svg: (
175 |
181 | ),
182 | },
183 | headerZoom: {
184 | width: 24,
185 | height: 24,
186 | svg: (
187 |
191 | ),
192 | },
193 | xPostion: {
194 | width: 16,
195 | height: 16,
196 | svg: (
197 |
201 | ),
202 | },
203 | yPostion: {
204 | width: 16,
205 | height: 16,
206 | svg: (
207 |
211 | ),
212 | },
213 | close: {
214 | width: 16,
215 | height: 16,
216 | svg: (
217 |
221 | ),
222 | },
223 | allBoundary: {
224 | width: 17,
225 | height: 17,
226 | svg: (
227 |
231 | ),
232 | },
233 | cornerBoundary: {
234 | width: 17,
235 | height: 17,
236 | svg: (
237 |
241 | ),
242 | },
243 | };
244 |
245 | export default icons;
246 |
--------------------------------------------------------------------------------