react-cosmos-ui
Advanced tools
Comparing version 6.0.0-canary.0f73dbd.0 to 6.0.0-canary.10c9ae9.0
@@ -8,3 +8,3 @@ import React from 'react'; | ||
}; | ||
export declare function BaseSvg({ children, ...attrs }: Props): JSX.Element; | ||
export declare function BaseSvg({ children, ...attrs }: Props): React.JSX.Element; | ||
export {}; |
@@ -10,3 +10,3 @@ import React from 'react'; | ||
}; | ||
export declare function Button32({ icon, label, title, disabled, selected, onClick, }: Props): JSX.Element; | ||
export declare function Button32({ icon, label, title, disabled, selected, onClick, }: Props): React.JSX.Element; | ||
export {}; |
@@ -10,3 +10,3 @@ import React from 'react'; | ||
}; | ||
export declare function Button8({ icon, label, title, disabled, selected, onClick, }: Props): JSX.Element; | ||
export declare function Button8({ icon, label, title, disabled, selected, onClick, }: Props): React.JSX.Element; | ||
export {}; |
@@ -9,3 +9,3 @@ import React from 'react'; | ||
}; | ||
export declare function IconButton32({ icon, title, disabled, selected, onClick, }: Props): JSX.Element; | ||
export declare function IconButton32({ icon, title, disabled, selected, onClick, }: Props): React.JSX.Element; | ||
export {}; |
@@ -9,3 +9,3 @@ import React from 'react'; | ||
}; | ||
export declare function IconButton8({ icon, title, disabled, selected, onClick, }: Props): JSX.Element; | ||
export declare function IconButton8({ icon, title, disabled, selected, onClick, }: Props): React.JSX.Element; | ||
export {}; |
@@ -17,3 +17,6 @@ import styled from 'styled-components'; | ||
outline: none; | ||
transition: background ${quick}s, color ${quick}s, opacity ${quick}s; | ||
transition: | ||
background ${quick}s, | ||
color ${quick}s, | ||
opacity ${quick}s; | ||
@@ -20,0 +23,0 @@ :hover { |
@@ -0,7 +1,11 @@ | ||
import React from 'react'; | ||
import { SvgChildren } from './BaseSvg.js'; | ||
type IconProps = { | ||
children: SvgChildren; | ||
export type IconProps = { | ||
size?: number | string; | ||
strokeWidth?: number; | ||
}; | ||
export declare function Icon({ children, size }: IconProps): JSX.Element; | ||
type Props = IconProps & { | ||
children: SvgChildren; | ||
}; | ||
export declare function Icon({ children, size, strokeWidth }: Props): React.JSX.Element; | ||
export {}; |
import React from 'react'; | ||
import { BaseSvg } from './BaseSvg.js'; | ||
export function Icon({ children, size = '100%' }) { | ||
return (React.createElement(BaseSvg, { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }, children)); | ||
export function Icon({ children, size = '100%', strokeWidth = 1.5 }) { | ||
return (React.createElement(BaseSvg, { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: strokeWidth, strokeLinecap: "round", strokeLinejoin: "round" }, children)); | ||
} |
@@ -1,33 +0,31 @@ | ||
type Props = { | ||
size?: number; | ||
}; | ||
export declare const ChevronLeftIcon: () => JSX.Element; | ||
export declare const ChevronRightIcon: () => JSX.Element; | ||
export declare const ChevronDownIcon: () => JSX.Element; | ||
export declare const FolderIcon: () => JSX.Element; | ||
export declare const XIcon: () => JSX.Element; | ||
export declare const XCircleIcon: () => JSX.Element; | ||
export declare const MaximizeIcon: () => JSX.Element; | ||
export declare const SmartphoneIcon: () => JSX.Element; | ||
export declare const Minimize2Icon: () => JSX.Element; | ||
export declare const RefreshCwIcon: () => JSX.Element; | ||
export declare const RefreshCcwIcon: (props: Props) => JSX.Element; | ||
export declare const HomeIcon: () => JSX.Element; | ||
export declare const CastIcon: () => JSX.Element; | ||
export declare const EditIcon: () => JSX.Element; | ||
export declare const CheckCircleIcon: () => JSX.Element; | ||
export declare const AlertCircleIcon: () => JSX.Element; | ||
export declare const InfoIcon: () => JSX.Element; | ||
export declare const LoaderIcon: () => JSX.Element; | ||
export declare const SlidersIcon: () => JSX.Element; | ||
export declare const CopyIcon: () => JSX.Element; | ||
export declare const RotateCcwIcon: () => JSX.Element; | ||
export declare const FileIcon: () => JSX.Element; | ||
export declare const SearchIcon: () => JSX.Element; | ||
export declare const MenuIcon: () => JSX.Element; | ||
export declare const ExternalIcon: () => JSX.Element; | ||
export declare const HelpCircleIcon: () => JSX.Element; | ||
export declare const MinusSquareIcon: () => JSX.Element; | ||
export declare const PlusSquareIcon: () => JSX.Element; | ||
export declare const StarIcon: () => JSX.Element; | ||
export {}; | ||
import React from 'react'; | ||
import { IconProps } from '../Icon.js'; | ||
export declare const ChevronLeftIcon: () => React.JSX.Element; | ||
export declare const ChevronRightIcon: () => React.JSX.Element; | ||
export declare const ChevronDownIcon: () => React.JSX.Element; | ||
export declare const FolderIcon: () => React.JSX.Element; | ||
export declare const XIcon: () => React.JSX.Element; | ||
export declare const XCircleIcon: () => React.JSX.Element; | ||
export declare const MaximizeIcon: () => React.JSX.Element; | ||
export declare const SmartphoneIcon: () => React.JSX.Element; | ||
export declare const Minimize2Icon: () => React.JSX.Element; | ||
export declare const RefreshCwIcon: () => React.JSX.Element; | ||
export declare const RefreshCcwIcon: (props: IconProps) => React.JSX.Element; | ||
export declare const HomeIcon: () => React.JSX.Element; | ||
export declare const CastIcon: () => React.JSX.Element; | ||
export declare const EditIcon: () => React.JSX.Element; | ||
export declare const CheckCircleIcon: (props: IconProps) => React.JSX.Element; | ||
export declare const AlertCircleIcon: () => React.JSX.Element; | ||
export declare const InfoIcon: () => React.JSX.Element; | ||
export declare const LoaderIcon: () => React.JSX.Element; | ||
export declare const SlidersIcon: () => React.JSX.Element; | ||
export declare const CopyIcon: () => React.JSX.Element; | ||
export declare const RotateCcwIcon: () => React.JSX.Element; | ||
export declare const FileIcon: () => React.JSX.Element; | ||
export declare const SearchIcon: () => React.JSX.Element; | ||
export declare const MenuIcon: () => React.JSX.Element; | ||
export declare const ExternalIcon: () => React.JSX.Element; | ||
export declare const HelpCircleIcon: () => React.JSX.Element; | ||
export declare const MinusSquareIcon: () => React.JSX.Element; | ||
export declare const PlusSquareIcon: () => React.JSX.Element; | ||
export declare const StarIcon: () => React.JSX.Element; |
@@ -45,3 +45,3 @@ import React from 'react'; | ||
React.createElement("polygon", { points: "18 2 22 6 12 16 8 16 8 12 18 2" }))); | ||
export const CheckCircleIcon = () => (React.createElement(Icon, null, | ||
export const CheckCircleIcon = (props) => (React.createElement(Icon, { ...props }, | ||
React.createElement("path", { d: "M22 11.08V12a10 10 0 1 1-5.93-9.14" }), | ||
@@ -48,0 +48,0 @@ React.createElement("polyline", { points: "22 4 12 14.01 9 11.01" }))); |
@@ -0,1 +1,2 @@ | ||
import React from 'react'; | ||
import { SvgChildren } from './BaseSvg.js'; | ||
@@ -7,3 +8,3 @@ type Props = { | ||
}; | ||
export declare function Illustration({ children, viewBox, size }: Props): JSX.Element; | ||
export declare function Illustration({ children, viewBox, size }: Props): React.JSX.Element; | ||
export {}; |
@@ -0,3 +1,4 @@ | ||
import React from 'react'; | ||
export declare const ArtificialIntelligenceIllustration: ({ title, }: { | ||
title: string; | ||
}) => JSX.Element; | ||
}) => React.JSX.Element; |
@@ -0,3 +1,4 @@ | ||
import React from 'react'; | ||
export declare const AstronautIllustration: ({ title }: { | ||
title: string; | ||
}) => JSX.Element; | ||
}) => React.JSX.Element; |
@@ -0,3 +1,4 @@ | ||
import React from 'react'; | ||
export declare const BlankCanvasIllustration: ({ title }: { | ||
title: string; | ||
}) => JSX.Element; | ||
}) => React.JSX.Element; |
@@ -0,1 +1,2 @@ | ||
import React from 'react'; | ||
export type NumberInputStyles = { | ||
@@ -14,3 +15,3 @@ focusedColor: string; | ||
}; | ||
export declare function NumberInput({ id, value, minValue, maxValue, styles, onChange, }: Props): JSX.Element; | ||
export declare function NumberInput({ id, value, minValue, maxValue, styles, onChange, }: Props): React.JSX.Element; | ||
export {}; |
@@ -0,1 +1,2 @@ | ||
import React from 'react'; | ||
type BaseOption = { | ||
@@ -15,3 +16,3 @@ value: string; | ||
}; | ||
export declare function Select<Option extends BaseOption>({ id, testId, options, value, color, height, padding, onChange, }: Props<Option>): JSX.Element; | ||
export declare function Select<Option extends BaseOption>({ id, testId, options, value, color, height, padding, onChange, }: Props<Option>): React.JSX.Element; | ||
export {}; |
@@ -0,1 +1,2 @@ | ||
import React from 'react'; | ||
type Props = { | ||
@@ -8,3 +9,3 @@ value: string; | ||
}; | ||
export declare function KeyBox({ value, bgColor, textColor, size, fontSize, }: Props): JSX.Element; | ||
export declare function KeyBox({ value, bgColor, textColor, size, fontSize, }: Props): React.JSX.Element; | ||
export {}; |
@@ -0,1 +1,2 @@ | ||
import React from 'react'; | ||
export declare const SidePanelContainer: import("styled-components").StyledComponent<"div", any, {}, never>; | ||
@@ -7,5 +8,5 @@ export declare const SidePanelHeader: import("styled-components").StyledComponent<"div", any, {}, never>; | ||
}; | ||
export declare function SidePanelTitle({ label, componentName }: TitleProps): JSX.Element; | ||
export declare function SidePanelTitle({ label, componentName }: TitleProps): React.JSX.Element; | ||
export declare const SidePanelActions: import("styled-components").StyledComponent<"div", any, {}, never>; | ||
export declare const SidePanelBody: import("styled-components").StyledComponent<"div", any, {}, never>; | ||
export {}; |
@@ -23,3 +23,3 @@ import React from 'react'; | ||
React.createElement(TitleLabel, null, label), | ||
typeof componentName === 'string' && (React.createElement(ComponentName, null, componentName ? componentName : React.createElement("em", null, "Unnamed"))))); | ||
typeof componentName === 'string' && (React.createElement(ComponentName, null, componentName ? componentName : `(anonymous)`)))); | ||
} | ||
@@ -26,0 +26,0 @@ export const SidePanelActions = styled.div ` |
@@ -0,1 +1,2 @@ | ||
import React from 'react'; | ||
type Props = { | ||
@@ -6,3 +7,3 @@ width: number; | ||
}; | ||
export declare function Space(props: Props): JSX.Element; | ||
export declare function Space(props: Props): React.JSX.Element; | ||
export {}; |
@@ -1,2 +0,2 @@ | ||
import { ReactNode } from 'react'; | ||
import React, { ReactNode } from 'react'; | ||
import { TreeNode } from 'react-cosmos-core'; | ||
@@ -18,3 +18,3 @@ import { TreeExpansion } from '../shared/treeExpansion.js'; | ||
}; | ||
export declare function TreeView<Item>({ node, name, parents, expansion, setExpansion, renderNode, }: Props<Item>): JSX.Element; | ||
export declare function TreeView<Item>({ node, name, parents, expansion, setExpansion, renderNode, }: Props<Item>): React.JSX.Element; | ||
export {}; |
@@ -0,1 +1,2 @@ | ||
import React from 'react'; | ||
import { FixtureStateValues } from 'react-cosmos-core'; | ||
@@ -8,3 +9,3 @@ import { TreeExpansion } from '../../shared/treeExpansion.js'; | ||
}; | ||
export declare function ExpandCollapseValues({ values, expansion, setExpansion, }: Props): JSX.Element | null; | ||
export declare function ExpandCollapseValues({ values, expansion, setExpansion, }: Props): React.JSX.Element | null; | ||
export {}; |
@@ -1,4 +0,4 @@ | ||
export { stringifyElementId, stringifyFixtureId } from './shared.js'; | ||
export { ValueInputTree } from './ValueInputTree.js'; | ||
export { stringifyElementId } from './shared.js'; | ||
export { hasFsValues, sortFsValueGroups } from './valueGroups.js'; | ||
export { ValueInputTree } from './ValueInputTree.js'; | ||
export { FixtureExpansion, FixtureExpansionGroup, getFixtureExpansion, OnElementExpansionChange, updateElementExpansion, } from './valueTreeExpansion.js'; | ||
export { FixtureExpansion, FixtureExpansionGroup, OnElementExpansionChange, getFixtureExpansion, updateElementExpansion, } from './valueTreeExpansion.js'; |
@@ -1,4 +0,4 @@ | ||
export { stringifyElementId, stringifyFixtureId } from './shared.js'; | ||
export { ValueInputTree } from './ValueInputTree.js'; | ||
export { stringifyElementId } from './shared.js'; | ||
export { hasFsValues, sortFsValueGroups } from './valueGroups.js'; | ||
export { ValueInputTree } from './ValueInputTree.js'; | ||
export { getFixtureExpansion, updateElementExpansion, } from './valueTreeExpansion.js'; |
@@ -1,5 +0,6 @@ | ||
import { FixtureElementId, FixtureId, FixtureStatePrimitiveValue, FixtureStateUnserializableValue, TreeNode } from 'react-cosmos-core'; | ||
import { FixtureElementId, FixtureStatePrimitiveValue, FixtureStateUnserializableValue, TreeNode } from 'react-cosmos-core'; | ||
export type LeafValue = FixtureStatePrimitiveValue | FixtureStateUnserializableValue; | ||
export type ValueNodeData = { | ||
type: 'collection'; | ||
isArray: boolean; | ||
} | { | ||
@@ -15,3 +16,2 @@ type: 'item'; | ||
export declare function stringifyElementId(elementId: FixtureElementId): string; | ||
export declare function stringifyFixtureId(fixtureId: FixtureId): string; | ||
export {}; |
@@ -9,8 +9,4 @@ import styled from 'styled-components'; | ||
} | ||
export function stringifyFixtureId(fixtureId) { | ||
const { path, name } = fixtureId; | ||
return name ? `${path}-${name}` : path; | ||
} | ||
function getLeftPadding(depth) { | ||
return depth * 12; | ||
} |
@@ -0,1 +1,2 @@ | ||
import React from 'react'; | ||
type Props = { | ||
@@ -7,3 +8,3 @@ id: string; | ||
}; | ||
export declare function BooleanValueInput({ id, name, data, onChange }: Props): JSX.Element; | ||
export declare function BooleanValueInput({ id, name, data, onChange }: Props): React.JSX.Element; | ||
export {}; |
@@ -0,5 +1,6 @@ | ||
import React from 'react'; | ||
type Props = { | ||
name: string; | ||
}; | ||
export declare function NullValueInput({ name }: Props): JSX.Element; | ||
export declare function NullValueInput({ name }: Props): React.JSX.Element; | ||
export {}; |
@@ -0,1 +1,2 @@ | ||
import React from 'react'; | ||
type Props = { | ||
@@ -7,3 +8,3 @@ id: string; | ||
}; | ||
export declare function NumberValueInput({ id, name, data, onChange }: Props): JSX.Element; | ||
export declare function NumberValueInput({ id, name, data, onChange }: Props): React.JSX.Element; | ||
export {}; |
@@ -0,1 +1,2 @@ | ||
import React from 'react'; | ||
type Props = { | ||
@@ -7,3 +8,3 @@ id: string; | ||
}; | ||
export declare function StringValueInput({ id, name, data, onChange }: Props): JSX.Element; | ||
export declare function StringValueInput({ id, name, data, onChange }: Props): React.JSX.Element; | ||
export {}; |
@@ -1,2 +0,2 @@ | ||
import React from 'react'; | ||
import React, { useEffect, useState } from 'react'; | ||
import { useFocus } from '../../../hooks/useFocus.js'; | ||
@@ -8,5 +8,19 @@ import { blue, grey248, grey8 } from '../../../style/colors.js'; | ||
const { focused, onFocus, onBlur } = useFocus(); | ||
const onInputChange = React.useCallback((e) => onChange(e.currentTarget.value), [onChange]); | ||
// The data state is duplicated locally to solve the jumping cursor bug | ||
// that occurs in controlled React inputs that don't immediately re-render | ||
// with the new input value on change (because they await for the parent to | ||
// propagate the changed value back down). | ||
// https://github.com/facebook/react/issues/955 | ||
// https://github.com/react-cosmos/react-cosmos/issues/1372 | ||
const [localData, setLocalData] = useState(data); | ||
useEffect(() => { | ||
if (!focused) | ||
setLocalData(data); | ||
}, [data, focused]); | ||
const onInputChange = React.useCallback((e) => { | ||
setLocalData(e.currentTarget.value); | ||
onChange(e.currentTarget.value); | ||
}, [onChange]); | ||
// Mirror textarea behavior and add an extra row after user adds a new line | ||
const mirrorText = focused ? data.replace(/\n$/, `\n `) : data; | ||
const mirrorText = focused ? localData.replace(/\n$/, `\n `) : localData; | ||
return (React.createElement(React.Fragment, null, | ||
@@ -17,4 +31,4 @@ React.createElement(Label, { title: name, htmlFor: id }, name), | ||
React.createElement(TextContainer, null, | ||
React.createElement(TextMirror, { minWidth: 64, focused: focused }, data.length > 0 || focused ? mirrorText : React.createElement("em", null, "empty")), | ||
React.createElement(TextField, { rows: 1, id: id, value: data, focused: focused, color: grey248, onChange: onInputChange, onFocus: onFocus, onBlur: onBlur })))))); | ||
React.createElement(TextMirror, { minWidth: 64, focused: focused }, localData.length > 0 || focused ? mirrorText : React.createElement("em", null, "empty")), | ||
React.createElement(TextField, { rows: 1, id: id, value: localData, focused: focused, color: grey248, onChange: onInputChange, onFocus: onFocus, onBlur: onBlur })))))); | ||
} |
@@ -0,5 +1,6 @@ | ||
import React from 'react'; | ||
type Props = { | ||
name: string; | ||
}; | ||
export declare function UndefinedValueInput({ name }: Props): JSX.Element; | ||
export declare function UndefinedValueInput({ name }: Props): React.JSX.Element; | ||
export {}; |
@@ -0,1 +1,2 @@ | ||
import React from 'react'; | ||
type Props = { | ||
@@ -5,3 +6,3 @@ name: string; | ||
}; | ||
export declare function UnserializableValueInput({ name, data }: Props): JSX.Element; | ||
export declare function UnserializableValueInput({ name, data }: Props): React.JSX.Element; | ||
export {}; |
@@ -0,1 +1,2 @@ | ||
import React from 'react'; | ||
import { PrimitiveData } from 'react-cosmos-core'; | ||
@@ -10,3 +11,3 @@ import { LeafValue } from '../shared.js'; | ||
}; | ||
export declare function ValueInput({ value, name, id, indentLevel, onChange }: Props): JSX.Element; | ||
export declare function ValueInput({ value, name, id, indentLevel, onChange }: Props): React.JSX.Element; | ||
export {}; |
@@ -7,6 +7,6 @@ import React from 'react'; | ||
import { NumberValueInput } from './NumberValueInput.js'; | ||
import { ValueInputContainer } from './shared.js'; | ||
import { StringValueInput } from './StringValueInput.js'; | ||
import { UndefinedValueInput } from './UndefinedValueInput.js'; | ||
import { UnserializableValueInput } from './UnserializableValueInput.js'; | ||
import { ValueInputContainer } from './shared.js'; | ||
export function ValueInput({ value, name, id, indentLevel, onChange }) { | ||
@@ -13,0 +13,0 @@ return (React.createElement(ValueInputSlot, { slotProps: { id, name, value, indentLevel, onChange } }, |
@@ -0,4 +1,6 @@ | ||
import React from 'react'; | ||
type Props = { | ||
name: string; | ||
childNames: string[]; | ||
childrenText: string; | ||
disabled: boolean; | ||
expanded: boolean; | ||
@@ -8,3 +10,3 @@ indentLevel: number; | ||
}; | ||
export declare function ValueInputDir({ name, childNames, expanded, indentLevel, onToggle, }: Props): JSX.Element; | ||
export declare function ValueInputDir({ name, childrenText, disabled, expanded, indentLevel, onToggle, }: Props): React.JSX.Element; | ||
export {}; |
@@ -6,4 +6,3 @@ import React from 'react'; | ||
import { ValueTreeItem } from './shared.js'; | ||
export function ValueInputDir({ name, childNames, expanded, indentLevel, onToggle, }) { | ||
const disabled = childNames.length === 0; | ||
export function ValueInputDir({ name, childrenText, disabled, expanded, indentLevel, onToggle, }) { | ||
return (React.createElement(ValueTreeItem, { indentLevel: indentLevel }, | ||
@@ -16,7 +15,4 @@ React.createElement(ButtonContainer, null, | ||
React.createElement(DirName, { disabled: disabled }, name), | ||
React.createElement(ChildrenInfo, null, getChildInfo(childNames)))))))); | ||
React.createElement(ChildrenInfo, null, childrenText))))))); | ||
} | ||
function getChildInfo(childNames) { | ||
return childNames.length > 0 ? `{ ${childNames.join(', ')} }` : `{}`; | ||
} | ||
const ButtonContainer = styled.div ` | ||
@@ -23,0 +19,0 @@ padding: 2px 0; |
@@ -14,5 +14,12 @@ import { clone, setWith } from 'lodash-es'; | ||
const { data, children } = node; | ||
if (data.type === 'item') | ||
if (data.type === 'item') { | ||
return (React.createElement(ValueInput, { value: data.value, name: name, id: getInputId(id, parents, name), indentLevel: parents.length, onChange: newData => onValueChange(setValueAtPath(values, { type: 'primitive', data: newData }, getValuePath(name, parents))) })); | ||
return (children && (React.createElement(ValueInputDir, { name: name, childNames: Object.keys(children), expanded: expanded, indentLevel: parents.length, onToggle: onToggle }))); | ||
} | ||
if (children) { | ||
const childKeys = Object.keys(children); | ||
return (React.createElement(ValueInputDir, { name: name, childrenText: getChildrenText(childKeys, data.isArray), disabled: childKeys.length === 0, expanded: expanded, indentLevel: parents.length, onToggle: onToggle })); | ||
} | ||
else { | ||
return null; | ||
} | ||
} }))); | ||
@@ -30,2 +37,10 @@ }); | ||
} | ||
function getChildrenText(childKeys, isArray) { | ||
if (childKeys.length > 0) { | ||
return isArray ? `[ ${childKeys.length} ]` : `{ ${childKeys.join(', ')} }`; | ||
} | ||
else { | ||
return isArray ? `[]` : `{}`; | ||
} | ||
} | ||
const Container = styled.div ` | ||
@@ -32,0 +47,0 @@ background: ${grey32}; |
import { FixtureStateValues } from 'react-cosmos-core'; | ||
import { ValueNode } from './shared.js'; | ||
export declare function createValueTree(values: FixtureStateValues): ValueNode; | ||
export declare function createValueTree(values: FixtureStateValues, isArray?: boolean): ValueNode; |
@@ -1,2 +0,2 @@ | ||
export function createValueTree(values) { | ||
export function createValueTree(values, isArray = false) { | ||
const children = {}; | ||
@@ -6,3 +6,3 @@ Object.keys(values).forEach(key => { | ||
if (value.type === 'object') { | ||
children[key] = createValueTree(value.values); | ||
children[key] = createValueTree(value.values, false); | ||
} | ||
@@ -14,9 +14,14 @@ else if (value.type === 'array') { | ||
}); | ||
children[key] = createValueTree(objValues); | ||
children[key] = createValueTree(objValues, true); | ||
} | ||
else { | ||
children[key] = { data: { type: 'item', value } }; | ||
children[key] = { | ||
data: { type: 'item', value }, | ||
}; | ||
} | ||
}); | ||
return { data: { type: 'collection' }, children }; | ||
return { | ||
data: { type: 'collection', isArray }, | ||
children, | ||
}; | ||
} |
import { clone, setWith } from 'lodash-es'; | ||
import { stringifyElementId, stringifyFixtureId } from './shared.js'; | ||
import { stringifyFixtureId, } from 'react-cosmos-core'; | ||
import { stringifyElementId } from './shared.js'; | ||
const DEFAULT_EXPANSION = {}; | ||
@@ -4,0 +5,0 @@ export function getFixtureExpansion(groupExpansion, fixtureId) { |
import React from 'react'; | ||
declare const _default: ({ children }: { | ||
children: React.ReactNode; | ||
}) => JSX.Element; | ||
}) => React.JSX.Element; | ||
export default _default; |
import { loadPlugins } from 'react-plugin'; | ||
import './plugins/pluginEntry.js'; | ||
import { DEFAULT_PLUGIN_CONFIG } from './shared/defaultPluginConfig.js'; | ||
const rendererConfig = { | ||
...DEFAULT_PLUGIN_CONFIG, | ||
core: { | ||
projectId: 'testProjectId', | ||
fixturesDir: '__fixtures__', | ||
fixtureFileSuffix: 'fixture', | ||
devServerOn: true, | ||
}, | ||
rendererCore: { | ||
fixtures: {}, | ||
rendererUrl: '/renderer.html', | ||
}, | ||
}; | ||
// This file is required to run globally with side effects for the "inception" | ||
// fixture to work. | ||
loadPlugins({ | ||
config: { | ||
...DEFAULT_PLUGIN_CONFIG, | ||
core: { | ||
projectId: 'testProjectId', | ||
fixturesDir: '__fixtures__', | ||
fixtureFileSuffix: 'fixture', | ||
devServerOn: true, | ||
webRendererUrl: '/_renderer.html', | ||
}, | ||
}, | ||
config: rendererConfig, | ||
}); |
@@ -6,3 +6,2 @@ export * from './components/buttons/index.js'; | ||
export * from './plugins/ClassStatePanel/spec.js'; | ||
export * from './plugins/ContentOverlay/spec.js'; | ||
export * from './plugins/ControlPanel/spec.js'; | ||
@@ -37,2 +36,1 @@ export * from './plugins/ControlSelect/spec.js'; | ||
export * from './style/vars.js'; | ||
export * from './testHelpers/pluginMocks.js'; |
@@ -6,3 +6,2 @@ export * from './components/buttons/index.js'; | ||
export * from './plugins/ClassStatePanel/spec.js'; | ||
export * from './plugins/ContentOverlay/spec.js'; | ||
export * from './plugins/ControlPanel/spec.js'; | ||
@@ -37,2 +36,1 @@ export * from './plugins/ControlSelect/spec.js'; | ||
export * from './style/vars.js'; | ||
export * from './testHelpers/pluginMocks.js'; |
@@ -16,4 +16,2 @@ import React from 'react'; | ||
const { loadPlugins, Slot } = ReactPlugin; | ||
const config = { ...DEFAULT_PLUGIN_CONFIG, ...playgroundConfig }; | ||
loadPlugins({ config }); | ||
// We can make plugin loading unblocking if react-plugin exports the | ||
@@ -25,2 +23,4 @@ // reloadPlugins method. | ||
})); | ||
const config = { ...DEFAULT_PLUGIN_CONFIG, ...playgroundConfig }; | ||
loadPlugins({ config }); | ||
const root = ReactDom.createRoot(document.getElementById('root')); | ||
@@ -33,7 +33,18 @@ root.render(React.createElement(React.Fragment, null, | ||
console.log(`[Cosmos] Loading plugin script at ${scriptPath}`); | ||
// Handle both absolute (dev server) and relative paths (static export) | ||
// Paths are absolute with the dev server, and relative with static | ||
// exports. Why aren't they always relative? Because in dev mode | ||
// the plugins could be loaded from folders outside the project rootDir, | ||
// for example when using a monorepo. In that case relative paths would | ||
// have to contain "../" segments, which are not allowed in URLs, and | ||
// for this reason we pass full paths when using the dev server. | ||
const normalizedPath = scriptPath.startsWith('/') | ||
? scriptPath | ||
: `/${scriptPath}`; | ||
await import(/* webpackIgnore: true */ `./_plugin${normalizedPath}`); | ||
try { | ||
await import(/* webpackIgnore: true */ `./_plugin${normalizedPath}`); | ||
} | ||
catch (err) { | ||
console.log(`[Cosmos] Failed to load plugin script ${scriptPath}`); | ||
console.log(err); | ||
} | ||
} |
import { CosmosPluginConfig } from 'react-cosmos-core'; | ||
import { CoreSpec } from './plugins/Core/spec.js'; | ||
import { RendererCoreSpec } from './plugins/RendererCore/spec.js'; | ||
export type PlaygroundConfig = { | ||
core: CoreSpec['config']; | ||
rendererCore: RendererCoreSpec['config']; | ||
[pluginName: string]: {}; | ||
@@ -6,0 +8,0 @@ }; |
@@ -1,10 +0,12 @@ | ||
import { FixtureState, FixtureStateClassState, StateUpdater } from 'react-cosmos-core'; | ||
import React from 'react'; | ||
import { ClassStateFixtureStateItem } from 'react-cosmos-core'; | ||
import { FixtureExpansion, OnElementExpansionChange } from '../../../components/ValueInputTree/index.js'; | ||
import { SetClassStateFixtureState } from '../shared.js'; | ||
type Props = { | ||
fsClassState: FixtureStateClassState; | ||
classStateFsItem: ClassStateFixtureStateItem; | ||
fixtureExpansion: FixtureExpansion; | ||
onFixtureStateChange: (stateUpdater: StateUpdater<FixtureState>) => void; | ||
onFixtureStateChange: SetClassStateFixtureState; | ||
onElementExpansionChange: OnElementExpansionChange; | ||
}; | ||
export declare function ComponentClassState({ fsClassState, fixtureExpansion, onFixtureStateChange, onElementExpansionChange, }: Props): JSX.Element; | ||
export declare function ComponentClassState({ classStateFsItem, fixtureExpansion, onFixtureStateChange, onElementExpansionChange, }: Props): React.JSX.Element; | ||
export {}; |
import { isEqual } from 'lodash-es'; | ||
import React, { useCallback } from 'react'; | ||
import { updateFixtureStateClassState, } from 'react-cosmos-core'; | ||
import { updateClassStateFixtureStateItem, } from 'react-cosmos-core'; | ||
import { SidePanelActions, SidePanelBody, SidePanelContainer, SidePanelHeader, SidePanelTitle, } from '../../../components/SidePanel.js'; | ||
import { ExpandCollapseValues } from '../../../components/ValueInputTree/ExpandCollapseValues.js'; | ||
import { ValueInputTree, stringifyElementId, } from '../../../components/ValueInputTree/index.js'; | ||
import { IconButton32 } from '../../../components/buttons/index.js'; | ||
import { RotateCcwIcon } from '../../../components/icons/index.js'; | ||
import { SidePanelActions, SidePanelBody, SidePanelContainer, SidePanelHeader, SidePanelTitle, } from '../../../components/SidePanel.js'; | ||
import { ExpandCollapseValues } from '../../../components/ValueInputTree/ExpandCollapseValues.js'; | ||
import { stringifyElementId, ValueInputTree, } from '../../../components/ValueInputTree/index.js'; | ||
import { createClassStateFsUpdater } from './shared.js'; | ||
export function ComponentClassState({ fsClassState, fixtureExpansion, onFixtureStateChange, onElementExpansionChange, }) { | ||
const { componentName, elementId, values } = fsClassState; | ||
import { classStateFsItemUpdater } from './shared.js'; | ||
export function ComponentClassState({ classStateFsItem, fixtureExpansion, onFixtureStateChange, onElementExpansionChange, }) { | ||
const { componentName, elementId, values } = classStateFsItem; | ||
const [initialValues] = React.useState(() => values); | ||
const handleValuesReset = React.useCallback(() => onFixtureStateChange(createClassStateFsUpdater(elementId, prevFs => updateFixtureStateClassState({ | ||
fixtureState: prevFs, | ||
const handleValuesReset = React.useCallback(() => onFixtureStateChange(classStateFsItemUpdater(elementId, prevFs => updateClassStateFixtureStateItem({ | ||
classStateFs: prevFs, | ||
elementId, | ||
@@ -19,4 +19,4 @@ values: initialValues, | ||
const handleValueChange = React.useCallback((newValues) => { | ||
onFixtureStateChange(createClassStateFsUpdater(elementId, prevFs => updateFixtureStateClassState({ | ||
fixtureState: prevFs, | ||
onFixtureStateChange(classStateFsItemUpdater(elementId, prevFs => updateClassStateFixtureStateItem({ | ||
classStateFs: prevFs, | ||
elementId, | ||
@@ -23,0 +23,0 @@ values: newValues, |
import React from 'react'; | ||
import { FixtureState, StateUpdater } from 'react-cosmos-core'; | ||
import { ClassStateFixtureState } from 'react-cosmos-core'; | ||
import { FixtureExpansion, OnElementExpansionChange } from '../../../components/ValueInputTree/index.js'; | ||
import { SetClassStateFixtureState } from '../shared.js'; | ||
type Props = { | ||
fixtureState: FixtureState; | ||
fixtureState: ClassStateFixtureState | undefined; | ||
fixtureExpansion: FixtureExpansion; | ||
onFixtureStateChange: (stateUpdater: StateUpdater<FixtureState>) => void; | ||
onFixtureStateChange: SetClassStateFixtureState; | ||
onElementExpansionChange: OnElementExpansionChange; | ||
@@ -9,0 +10,0 @@ }; |
@@ -5,10 +5,10 @@ import React from 'react'; | ||
export const ClassStatePanel = React.memo(function ClassStatePanel({ fixtureState, fixtureExpansion, onFixtureStateChange, onElementExpansionChange, }) { | ||
if (!fixtureState.classState) { | ||
if (!fixtureState) { | ||
return null; | ||
} | ||
const classStateWithValues = fixtureState.classState.filter(hasFsValues); | ||
return (React.createElement(React.Fragment, null, sortFsValueGroups(classStateWithValues).map(fsClassState => { | ||
const strElementId = stringifyElementId(fsClassState.elementId); | ||
return (React.createElement(ComponentClassState, { key: strElementId, fsClassState: fsClassState, fixtureExpansion: fixtureExpansion, onFixtureStateChange: onFixtureStateChange, onElementExpansionChange: onElementExpansionChange })); | ||
const classStateWithValues = fixtureState.filter(hasFsValues); | ||
return (React.createElement(React.Fragment, null, sortFsValueGroups(classStateWithValues).map(fsItem => { | ||
const strElementId = stringifyElementId(fsItem.elementId); | ||
return (React.createElement(ComponentClassState, { key: strElementId, classStateFsItem: fsItem, fixtureExpansion: fixtureExpansion, onFixtureStateChange: onFixtureStateChange, onElementExpansionChange: onElementExpansionChange })); | ||
}))); | ||
}); |
@@ -1,2 +0,2 @@ | ||
import { FixtureElementId, FixtureState, FixtureStateClassState, StateUpdater } from 'react-cosmos-core'; | ||
export declare function createClassStateFsUpdater(elementId: FixtureElementId, cb: (prevFs: FixtureState) => FixtureStateClassState[]): StateUpdater<FixtureState>; | ||
import { ClassStateFixtureState, FixtureElementId, FixtureStateUpdater } from 'react-cosmos-core'; | ||
export declare function classStateFsItemUpdater(elementId: FixtureElementId, cb: FixtureStateUpdater<ClassStateFixtureState>): FixtureStateUpdater<ClassStateFixtureState>; |
@@ -1,16 +0,13 @@ | ||
import { findFixtureStateClassState, } from 'react-cosmos-core'; | ||
import { findClassStateFixtureStateItem, } from 'react-cosmos-core'; | ||
import { stringifyElementId } from '../../../components/ValueInputTree/index.js'; | ||
export function createClassStateFsUpdater(elementId, cb) { | ||
export function classStateFsItemUpdater(elementId, cb) { | ||
return prevFs => { | ||
const fsClassState = findFixtureStateClassState(prevFs, elementId); | ||
if (!fsClassState) { | ||
const fsItem = findClassStateFixtureStateItem(prevFs, elementId); | ||
if (!fsItem) { | ||
const elId = stringifyElementId(elementId); | ||
console.warn(`Trying to update missing element with ID: ${elId}`); | ||
return prevFs; | ||
return prevFs ?? []; | ||
} | ||
return { | ||
...prevFs, | ||
classState: cb(prevFs), | ||
}; | ||
return cb(prevFs); | ||
}; | ||
} |
@@ -1,6 +0,6 @@ | ||
import React from 'react'; | ||
import React, { useCallback } from 'react'; | ||
import { createPlugin } from 'react-plugin'; | ||
import { getFixtureExpansion, updateElementExpansion, } from '../../components/ValueInputTree/index.js'; | ||
import { ClassStatePanel } from './ClassStatePanel/index.js'; | ||
import { CLASS_STATE_TREE_EXPANSION_STORAGE_KEY } from './shared.js'; | ||
import { CLASS_STATE_TREE_EXPANSION_STORAGE_KEY, } from './shared.js'; | ||
const { namedPlug, register } = createPlugin({ | ||
@@ -10,4 +10,6 @@ name: 'classStatePanel', | ||
namedPlug('sidePanelRow', 'classState', ({ pluginContext, slotProps }) => { | ||
const { fixtureId, fixtureState, onFixtureStateChange } = slotProps; | ||
const { fixtureId, getFixtureState, setFixtureState } = slotProps; | ||
const { fixtureExpansion, onElementExpansionChange } = useFixtureExpansion(pluginContext, fixtureId); | ||
const fixtureState = getFixtureState('classState'); | ||
const onFixtureStateChange = useCallback(update => setFixtureState('classState', update), [setFixtureState]); | ||
return (React.createElement(ClassStatePanel, { fixtureState: fixtureState, fixtureExpansion: fixtureExpansion, onFixtureStateChange: onFixtureStateChange, onElementExpansionChange: onElementExpansionChange })); | ||
@@ -14,0 +16,0 @@ }); |
@@ -0,1 +1,3 @@ | ||
import { ClassStateFixtureState, FixtureStateUpdater } from 'react-cosmos-core'; | ||
export type SetClassStateFixtureState = (updater: FixtureStateUpdater<ClassStateFixtureState>) => void; | ||
export declare const CLASS_STATE_TREE_EXPANSION_STORAGE_KEY = "classStateTreeExpansion"; |
@@ -1,8 +0,10 @@ | ||
import { FixtureState, StateUpdater } from 'react-cosmos-core'; | ||
import React from 'react'; | ||
import { ControlsFixtureState } from 'react-cosmos-core'; | ||
import { SetControlsFixtureState } from './shared.js'; | ||
type Props = { | ||
fixtureState: FixtureState; | ||
fixtureState: ControlsFixtureState | undefined; | ||
controlActionOrder: string[]; | ||
onFixtureStateChange: (stateUpdater: StateUpdater<FixtureState>) => void; | ||
onFixtureStateChange: SetControlsFixtureState; | ||
}; | ||
export declare function ControlPanel({ fixtureState, controlActionOrder, onFixtureStateChange, }: Props): JSX.Element | null; | ||
export declare function ControlPanel({ fixtureState, controlActionOrder, onFixtureStateChange, }: Props): React.JSX.Element | null; | ||
export {}; |
import { isEqual } from 'lodash-es'; | ||
import React from 'react'; | ||
import { SidePanelActions, SidePanelBody, SidePanelContainer, SidePanelHeader, SidePanelTitle, } from '../../components/SidePanel.js'; | ||
import { IconButton32 } from '../../components/buttons/index.js'; | ||
import { RotateCcwIcon } from '../../components/icons/index.js'; | ||
import { SidePanelActions, SidePanelBody, SidePanelContainer, SidePanelHeader, SidePanelTitle, } from '../../components/SidePanel.js'; | ||
import { ControlActionSlot } from '../../slots/ControlActionSlot.js'; | ||
@@ -10,3 +10,3 @@ import { ControlSlot } from '../../slots/ControlSlot.js'; | ||
const handleControlsReset = React.useCallback(() => onFixtureStateChange(resetControls), [onFixtureStateChange]); | ||
const controls = fixtureState.controls || {}; | ||
const controls = fixtureState ?? {}; | ||
if (Object.keys(controls).length === 0) | ||
@@ -30,7 +30,7 @@ return null; | ||
function resetControls(fixtureState) { | ||
const controls = fixtureState.controls ? { ...fixtureState.controls } : {}; | ||
const controls = fixtureState ? { ...fixtureState } : {}; | ||
Object.keys(controls).forEach(controlName => { | ||
controls[controlName] = resetControl(controls[controlName]); | ||
}); | ||
return { ...fixtureState, controls }; | ||
return controls; | ||
} | ||
@@ -37,0 +37,0 @@ function resetControl(control) { |
@@ -1,2 +0,2 @@ | ||
import React from 'react'; | ||
import React, { useCallback } from 'react'; | ||
import { createPlugin } from 'react-plugin'; | ||
@@ -12,3 +12,5 @@ import { ControlPanel } from './ControlPanel.js'; | ||
const { controlActionOrder } = pluginContext.getConfig(); | ||
const { fixtureState, onFixtureStateChange } = slotProps; | ||
const { getFixtureState, setFixtureState } = slotProps; | ||
const fixtureState = getFixtureState('controls'); | ||
const onFixtureStateChange = useCallback(update => setFixtureState('controls', update), [setFixtureState]); | ||
return (React.createElement(ControlPanel, { fixtureState: fixtureState, controlActionOrder: controlActionOrder, onFixtureStateChange: onFixtureStateChange })); | ||
@@ -15,0 +17,0 @@ }); |
@@ -10,8 +10,5 @@ import React, { useCallback } from 'react'; | ||
const handleChange = useCallback((selectName, updatedControl) => { | ||
onFixtureStateChange(fixtureState => ({ | ||
...fixtureState, | ||
controls: { | ||
...fixtureState.controls, | ||
[selectName]: updatedControl, | ||
}, | ||
onFixtureStateChange(prevFs => ({ | ||
...prevFs, | ||
[selectName]: updatedControl, | ||
})); | ||
@@ -18,0 +15,0 @@ }, [onFixtureStateChange]); |
@@ -1,8 +0,9 @@ | ||
import { FixtureStateSelectControl } from 'react-cosmos-core'; | ||
import React from 'react'; | ||
import { SelectControlFixtureState } from 'react-cosmos-core'; | ||
type Props = { | ||
name: string; | ||
control: FixtureStateSelectControl; | ||
onChange: (name: string, select: FixtureStateSelectControl) => unknown; | ||
control: SelectControlFixtureState; | ||
onChange: (name: string, select: SelectControlFixtureState) => unknown; | ||
}; | ||
export declare function SelectValueInput({ name, control, onChange }: Props): JSX.Element; | ||
export declare function SelectValueInput({ name, control, onChange }: Props): React.JSX.Element; | ||
export {}; |
import React from 'react'; | ||
import { Label, ValueDataContainer, ValueInputContainer, } from '../../components/ValueInputTree/ValueInput/shared.js'; | ||
import { Select } from '../../components/inputs/Select.js'; | ||
import { Label, ValueDataContainer, ValueInputContainer, } from '../../components/ValueInputTree/ValueInput/shared.js'; | ||
import { lightBlue } from '../../style/colors.js'; | ||
@@ -5,0 +5,0 @@ export function SelectValueInput({ name, control, onChange }) { |
@@ -14,3 +14,2 @@ import { omit } from 'lodash-es'; | ||
devServerOn: false, | ||
webRendererUrl: null, | ||
}, | ||
@@ -23,3 +22,2 @@ methods: { | ||
isDevServerOn, | ||
getWebRendererUrl, | ||
}, | ||
@@ -68,4 +66,1 @@ }); | ||
} | ||
function getWebRendererUrl({ getConfig }) { | ||
return getConfig().webRendererUrl; | ||
} |
@@ -9,3 +9,2 @@ export type Commands = Record<string, () => unknown>; | ||
devServerOn: boolean; | ||
webRendererUrl: null | string; | ||
}; | ||
@@ -24,4 +23,3 @@ state: { | ||
isDevServerOn(): boolean; | ||
getWebRendererUrl(): null | string; | ||
}; | ||
}; |
@@ -0,1 +1,2 @@ | ||
import React from 'react'; | ||
type Props = { | ||
@@ -5,3 +6,3 @@ selected: boolean; | ||
}; | ||
export declare function BookmarkFixtureButton({ selected, onClick }: Props): JSX.Element; | ||
export declare function BookmarkFixtureButton({ selected, onClick }: Props): React.JSX.Element; | ||
export {}; |
@@ -1,10 +0,10 @@ | ||
import { FixtureId, FlatFixtureTree } from 'react-cosmos-core'; | ||
import React from 'react'; | ||
import { FixtureId, FlatFixtureTree, FlatFixtureTreeItem } from 'react-cosmos-core'; | ||
type Props = { | ||
fixtureItems: FlatFixtureTree; | ||
bookmarks: FixtureId[]; | ||
bookmarks: FlatFixtureTree; | ||
selectedFixtureId: FixtureId | null; | ||
onFixtureSelect: (fixtureId: FixtureId) => void; | ||
onBookmarkDelete: (fixtureId: FixtureId) => void; | ||
onBookmarkDelete: (fixtureItem: FlatFixtureTreeItem) => void; | ||
}; | ||
export declare function FixtureBookmarks({ fixtureItems, bookmarks, selectedFixtureId, onFixtureSelect, onBookmarkDelete, }: Props): JSX.Element | null; | ||
export declare function FixtureBookmarks({ bookmarks, selectedFixtureId, onFixtureSelect, onBookmarkDelete, }: Props): React.JSX.Element | null; | ||
export {}; |
@@ -1,12 +0,12 @@ | ||
import { isEqual } from 'lodash-es'; | ||
import { isEqual, sortBy } from 'lodash-es'; | ||
import React from 'react'; | ||
import { stringifyFixtureId, } from 'react-cosmos-core'; | ||
import styled from 'styled-components'; | ||
import { XIcon } from '../../components/icons/index.js'; | ||
import { stringifyFixtureId } from '../../components/ValueInputTree/index.js'; | ||
import { createRelativePlaygroundUrl } from '../../shared/url.js'; | ||
import { blue, grey128, grey224, grey24, grey248, grey32, grey8, selectedColors, white10, } from '../../style/colors.js'; | ||
import { quick } from '../../style/vars.js'; | ||
export function FixtureBookmarks({ fixtureItems, bookmarks, selectedFixtureId, onFixtureSelect, onBookmarkDelete, }) { | ||
const bookmarkedItems = fixtureItems.filter(item => bookmarks.some(b => isEqual(b, item.fixtureId))); | ||
if (!bookmarkedItems.length) | ||
export function FixtureBookmarks({ bookmarks, selectedFixtureId, onFixtureSelect, onBookmarkDelete, }) { | ||
const sortedBookmarks = useSortedBookmarks(bookmarks); | ||
if (!sortedBookmarks.length) | ||
return null; | ||
@@ -16,3 +16,3 @@ return (React.createElement(Container, null, | ||
React.createElement(HeaderTitle, null, "Bookmarks")), | ||
bookmarkedItems.map(fixtureItem => { | ||
sortedBookmarks.map(fixtureItem => { | ||
const { fixtureId } = fixtureItem; | ||
@@ -32,3 +32,3 @@ const itemKey = stringifyFixtureId(fixtureId); | ||
React.createElement(FixtureLink, { href: createRelativePlaygroundUrl({ fixtureId }), selected: selected, onClick: handleClick }, getFixtureName(fixtureItem)), | ||
React.createElement(DeleteButton, { onClick: () => onBookmarkDelete(fixtureId) }, | ||
React.createElement(DeleteButton, { onClick: () => onBookmarkDelete(fixtureItem) }, | ||
React.createElement(DeleteIconContainer, null, | ||
@@ -38,2 +38,5 @@ React.createElement(XIcon, null))))); | ||
} | ||
function useSortedBookmarks(bookmarks) { | ||
return React.useMemo(() => sortBy(bookmarks, b => b.fixtureId.path, b => b.fixtureId.name), [bookmarks]); | ||
} | ||
function openAnchorInNewTab(anchorEl) { | ||
@@ -40,0 +43,0 @@ // Allow users to cmd+click to open fixtures in new tab |
import { isEqual } from 'lodash-es'; | ||
import React from 'react'; | ||
import { createFixtureTree, flattenFixtureTree, } from 'react-cosmos-core'; | ||
import { createPlugin } from 'react-plugin'; | ||
@@ -11,9 +10,9 @@ import { BookmarkFixtureButton } from './BookmarkFixtureButton.js'; | ||
namedPlug('fixtureAction', 'bookmarkFixture', ({ pluginContext, slotProps }) => { | ||
const { fixtureId } = slotProps; | ||
const { fixtureItem } = slotProps; | ||
const { getBookmarks, setBookmarks } = getStorageApi(pluginContext); | ||
const bookmarks = getBookmarks(); | ||
const selected = bookmarks.some(b => isEqual(b, fixtureId)); | ||
const selected = bookmarks.some(b => isEqual(b, fixtureItem)); | ||
return (React.createElement(BookmarkFixtureButton, { selected: selected, onClick: () => setBookmarks(selected | ||
? bookmarks.filter(b => !isEqual(b, fixtureId)) | ||
: [...bookmarks, fixtureId]) })); | ||
? bookmarks.filter(b => !isEqual(b, fixtureItem)) | ||
: [...bookmarks, fixtureItem]) })); | ||
}); | ||
@@ -24,4 +23,3 @@ namedPlug('navRow', 'fixtureBookmarks', ({ pluginContext }) => { | ||
const bookmarks = getBookmarks(); | ||
const fixtureItems = useFixtureItems(pluginContext); | ||
return (React.createElement(FixtureBookmarks, { fixtureItems: fixtureItems, bookmarks: bookmarks, selectedFixtureId: router.getSelectedFixtureId(), onFixtureSelect: router.selectFixture, onBookmarkDelete: fixtureId => setBookmarks(bookmarks.filter(b => !isEqual(b, fixtureId))) })); | ||
return (React.createElement(FixtureBookmarks, { bookmarks: bookmarks, selectedFixtureId: router.getSelectedFixtureId(), onFixtureSelect: router.selectFixture, onBookmarkDelete: fixtureItem => setBookmarks(bookmarks.filter(b => !isEqual(b, fixtureItem))) })); | ||
}); | ||
@@ -34,16 +32,8 @@ export { register }; | ||
function getBookmarks() { | ||
return storage.getItem('fixtureBookmarks') || []; | ||
return storage.getItem('fixtureBookmarks.1') || []; | ||
} | ||
function setBookmarks(bookmarks) { | ||
storage.setItem('fixtureBookmarks', bookmarks); | ||
storage.setItem('fixtureBookmarks.1', bookmarks); | ||
} | ||
return { getBookmarks, setBookmarks }; | ||
} | ||
function useFixtureItems(pluginContext) { | ||
const { getMethodsOf } = pluginContext; | ||
const core = getMethodsOf('core'); | ||
const { fixturesDir, fixtureFileSuffix } = core.getFixtureFileVars(); | ||
const rendererCore = getMethodsOf('rendererCore'); | ||
const fixtures = rendererCore.getFixtures(); | ||
return React.useMemo(() => flattenFixtureTree(createFixtureTree({ fixturesDir, fixtureFileSuffix, fixtures })), [fixtureFileSuffix, fixtures, fixturesDir]); | ||
} |
@@ -0,7 +1,8 @@ | ||
import React from 'react'; | ||
type Props = { | ||
validFixtureSelected: boolean; | ||
fixtureSelected: boolean; | ||
onOpen: () => unknown; | ||
onCloseNav: () => unknown; | ||
}; | ||
export declare function FixtureSearchHeader({ validFixtureSelected, onOpen, onCloseNav, }: Props): JSX.Element; | ||
export declare function FixtureSearchHeader({ fixtureSelected, onOpen, onCloseNav, }: Props): React.JSX.Element; | ||
export {}; |
import React from 'react'; | ||
import styled from 'styled-components'; | ||
import { KeyBox } from '../../components/KeyBox.js'; | ||
import { IconButton32 } from '../../components/buttons/index.js'; | ||
import { ChevronLeftIcon, SearchIcon } from '../../components/icons/index.js'; | ||
import { KeyBox } from '../../components/KeyBox.js'; | ||
import { blue, grey160, grey32, white10 } from '../../style/colors.js'; | ||
export function FixtureSearchHeader({ validFixtureSelected, onOpen, onCloseNav, }) { | ||
export function FixtureSearchHeader({ fixtureSelected, onOpen, onCloseNav, }) { | ||
return (React.createElement(Container, null, | ||
@@ -16,3 +16,3 @@ React.createElement(SearchButton, { onClick: onOpen }, | ||
React.createElement(NavButtonContainer, null, | ||
React.createElement(IconButton32, { icon: React.createElement(ChevronLeftIcon, null), title: "Hide fixture list", disabled: !validFixtureSelected, selected: false, onClick: onCloseNav })))); | ||
React.createElement(IconButton32, { icon: React.createElement(ChevronLeftIcon, null), title: "Hide fixture list", disabled: !fixtureSelected, selected: false, onClick: onCloseNav })))); | ||
} | ||
@@ -19,0 +19,0 @@ const Container = styled.div ` |
@@ -0,1 +1,2 @@ | ||
import React from 'react'; | ||
import { FixtureId, FixtureList } from 'react-cosmos-core'; | ||
@@ -12,3 +13,3 @@ type Props = { | ||
}; | ||
export declare function FixtureSearchOverlay({ searchText, fixturesDir, fixtureFileSuffix, fixtures, selectedFixtureId, onSetSearchText, onClose, onSelect, }: Props): JSX.Element; | ||
export declare function FixtureSearchOverlay({ searchText, fixturesDir, fixtureFileSuffix, fixtures, selectedFixtureId, onSetSearchText, onClose, onSelect, }: Props): React.JSX.Element; | ||
export {}; |
import { filter } from 'fuzzaldrin-plus'; | ||
import { isEqual } from 'lodash-es'; | ||
import React, { useCallback, useEffect, useMemo, useRef, useState, } from 'react'; | ||
import { createFixtureTree, flattenFixtureTree, KEY_DOWN, KEY_ENTER, KEY_ESC, KEY_FWD_SLASH, KEY_TAB, KEY_UP, } from 'react-cosmos-core'; | ||
import { KEY_DOWN, KEY_ENTER, KEY_ESC, KEY_FWD_SLASH, KEY_TAB, KEY_UP, createFixtureTree, flattenFixtureTree, } from 'react-cosmos-core'; | ||
import styled from 'styled-components'; | ||
@@ -179,3 +179,3 @@ import { HelpCircleIcon, SearchIcon } from '../../components/icons/index.js'; | ||
React.createElement(ResultsContainer, null, | ||
matchingFixturePaths.map(cleanFixturePath => (React.createElement(FixtureSearchResult, { key: cleanFixturePath, cleanFixturePath: cleanFixturePath, fixtureItem: fixtureItems[cleanFixturePath], active: cleanFixturePath === activeFixturePath, onSelect: onSelect }))), | ||
matchingFixturePaths.map(cleanFixturePath => fixtureItems[cleanFixturePath] && (React.createElement(FixtureSearchResult, { key: cleanFixturePath, cleanFixturePath: cleanFixturePath, fixtureItem: fixtureItems[cleanFixturePath], active: cleanFixturePath === activeFixturePath, onSelect: onSelect }))), | ||
matchingFixturePaths.length === 0 && (React.createElement(NoResults, null, "No results"))))))); | ||
@@ -234,4 +234,6 @@ } | ||
background: ${grey248}; | ||
box-shadow: rgba(15, 15, 15, 0.05) 0px 0px 0px 1px, | ||
rgba(15, 15, 15, 0.1) 0px 5px 10px, rgba(15, 15, 15, 0.2) 0px 15px 40px; | ||
box-shadow: | ||
rgba(15, 15, 15, 0.05) 0px 0px 0px 1px, | ||
rgba(15, 15, 15, 0.1) 0px 5px 10px, | ||
rgba(15, 15, 15, 0.2) 0px 15px 40px; | ||
display: flex; | ||
@@ -282,3 +284,5 @@ flex-direction: column; | ||
cursor: pointer; | ||
transition: background ${quick}s, color ${quick}s; | ||
transition: | ||
background ${quick}s, | ||
color ${quick}s; | ||
@@ -293,3 +297,5 @@ :hover { | ||
opacity: ${props => (props.visible ? 1 : 0)}; | ||
transition: height ${quick}s, opacity ${quick}s; | ||
transition: | ||
height ${quick}s, | ||
opacity ${quick}s; | ||
user-select: none; | ||
@@ -296,0 +302,0 @@ `; |
@@ -0,1 +1,2 @@ | ||
import React from 'react'; | ||
import { FixtureId, FlatFixtureTreeItem } from 'react-cosmos-core'; | ||
@@ -8,3 +9,3 @@ type Props = { | ||
}; | ||
export declare function FixtureSearchResult({ active, cleanFixturePath, fixtureItem, onSelect, }: Props): JSX.Element; | ||
export declare function FixtureSearchResult({ active, cleanFixturePath, fixtureItem, onSelect, }: Props): React.JSX.Element; | ||
export {}; |
@@ -1,1 +0,2 @@ | ||
export declare function FixtureSearchShortcuts(): JSX.Element; | ||
import React from 'react'; | ||
export declare function FixtureSearchShortcuts(): React.JSX.Element; |
@@ -21,2 +21,3 @@ import React from 'react'; | ||
const { getMethodsOf } = pluginContext; | ||
const router = getMethodsOf('router'); | ||
const rendererCore = getMethodsOf('rendererCore'); | ||
@@ -30,3 +31,3 @@ const fixtures = rendererCore.getFixtures(); | ||
} | ||
return (React.createElement(FixtureSearchHeader, { validFixtureSelected: rendererCore.isValidFixtureSelected(), onOpen: onOpen, onCloseNav: onCloseNav })); | ||
return (React.createElement(FixtureSearchHeader, { fixtureSelected: router.getSelectedFixtureId() !== null, onOpen: onOpen, onCloseNav: onCloseNav })); | ||
}); | ||
@@ -33,0 +34,0 @@ namedPlug('global', 'fixtureSearch', ({ pluginContext }) => { |
@@ -0,1 +1,2 @@ | ||
import React from 'react'; | ||
type Props = { | ||
@@ -5,5 +6,5 @@ fixturesDir: string; | ||
}; | ||
export declare function BlankState({ fixturesDir, fixtureFileSuffix }: Props): JSX.Element; | ||
export declare function BlankState({ fixturesDir, fixtureFileSuffix }: Props): React.JSX.Element; | ||
export declare const IconContainer: import("styled-components").StyledComponent<"div", any, {}, never>; | ||
export declare const NoWrap: import("styled-components").StyledComponent<"span", any, {}, never>; | ||
export {}; |
import React from 'react'; | ||
import { DelayRender } from 'react-cosmos-core'; | ||
import styled from 'styled-components'; | ||
@@ -6,26 +7,24 @@ import { FileIcon } from '../../components/icons/index.js'; | ||
export function BlankState({ fixturesDir, fixtureFileSuffix }) { | ||
return (React.createElement(Container, { "data-testid": "nav-blank-state" }, | ||
React.createElement(IconContainer, null, | ||
React.createElement(FileIcon, null)), | ||
React.createElement(Title, null, | ||
"No component ", | ||
React.createElement(NoWrap, null, "fixtures found")), | ||
React.createElement(Description, null, | ||
React.createElement("ol", null, | ||
React.createElement("li", null, | ||
"Place fixture files under ", | ||
React.createElement("code", null, fixturesDir), | ||
" dirs or add the", | ||
' ', | ||
React.createElement("code", null, | ||
".", | ||
fixtureFileSuffix), | ||
" suffix to", | ||
' ', | ||
React.createElement(NoWrap, null, "their name")), | ||
React.createElement("li", null, | ||
"Default exports from your fixtures (any React element or component)", | ||
' ', | ||
"will ", | ||
React.createElement(NoWrap, null, "appear here")))))); | ||
return (React.createElement(DelayRender, { delay: 500 }, | ||
React.createElement(Container, { "data-testid": "nav-blank-state" }, | ||
React.createElement(IconContainer, null, | ||
React.createElement(FileIcon, null)), | ||
React.createElement(Title, null, | ||
"No component ", | ||
React.createElement(NoWrap, null, "fixtures found")), | ||
React.createElement(Description, null, | ||
React.createElement("ol", null, | ||
React.createElement("li", null, | ||
"Place fixture files under ", | ||
React.createElement("code", null, fixturesDir), | ||
" dirs or add the ", | ||
React.createElement("code", null, | ||
".", | ||
fixtureFileSuffix), | ||
" suffix to", | ||
' ', | ||
React.createElement(NoWrap, null, "their name")), | ||
React.createElement("li", null, | ||
"Default exports from your fixtures (any React element or component) will ", | ||
React.createElement(NoWrap, null, "appear here"))))))); | ||
} | ||
@@ -32,0 +31,0 @@ const Container = styled.div ` |
@@ -1,6 +0,6 @@ | ||
import { RefObject } from 'react'; | ||
import React, { RefObject } from 'react'; | ||
import { FixtureId } from 'react-cosmos-core'; | ||
type Props = { | ||
name: string; | ||
fixtureId: FixtureId; | ||
fixturePath: string; | ||
indentLevel: number; | ||
@@ -11,3 +11,3 @@ selected: boolean; | ||
}; | ||
export declare function FixtureButton({ name, fixtureId, indentLevel, selected, selectedRef, onSelect, }: Props): JSX.Element; | ||
export declare function FixtureButton({ name, fixturePath, indentLevel, selected, selectedRef, onSelect, }: Props): React.JSX.Element; | ||
export {}; |
@@ -6,4 +6,4 @@ import React from 'react'; | ||
import { FixtureTreeItem } from './FixtureTreeItem.js'; | ||
export function FixtureButton({ name, fixtureId, indentLevel, selected, selectedRef, onSelect, }) { | ||
return (React.createElement(FixtureLink, { fixtureId: fixtureId, onSelect: onSelect }, | ||
export function FixtureButton({ name, fixturePath, indentLevel, selected, selectedRef, onSelect, }) { | ||
return (React.createElement(FixtureLink, { fixtureId: { path: fixturePath }, onSelect: onSelect }, | ||
React.createElement(FixtureTreeItem, { ref: selected ? selectedRef : undefined, indentLevel: indentLevel, selected: selected }, | ||
@@ -10,0 +10,0 @@ React.createElement(Name, null, name)))); |
@@ -0,1 +1,2 @@ | ||
import React from 'react'; | ||
type Props = { | ||
@@ -8,3 +9,3 @@ name: string; | ||
}; | ||
export declare function FixtureDir({ name, expanded, indentLevel, selected, onToggle, }: Props): JSX.Element; | ||
export declare function FixtureDir({ name, expanded, indentLevel, selected, onToggle, }: Props): React.JSX.Element; | ||
export {}; |
@@ -1,2 +0,2 @@ | ||
import { ReactNode } from 'react'; | ||
import React, { ReactNode } from 'react'; | ||
import { FixtureId } from 'react-cosmos-core'; | ||
@@ -8,3 +8,3 @@ type Props = { | ||
}; | ||
export declare function FixtureLink({ children, fixtureId, onSelect }: Props): JSX.Element; | ||
export declare function FixtureLink({ children, fixtureId, onSelect }: Props): React.JSX.Element; | ||
export {}; |
@@ -1,6 +0,5 @@ | ||
import { isEqual } from 'lodash-es'; | ||
import React from 'react'; | ||
import styled from 'styled-components'; | ||
import { TreeView } from '../../../components/TreeView.js'; | ||
import { nodeContainsFixtureId, recordContainsFixtureId, } from '../../../shared/fixtureTree.js'; | ||
import { fixtureTreeNodeContainsFixtureId } from '../../../shared/fixtureTree.js'; | ||
import { grey32 } from '../../../style/colors.js'; | ||
@@ -15,9 +14,8 @@ import { FixtureButton } from './FixtureButton.js'; | ||
if (data.type === 'fixture') { | ||
const selected = isEqual(selectedFixtureId, data.fixtureId); | ||
return (React.createElement(FixtureButton, { name: name, fixtureId: data.fixtureId, indentLevel: parents.length, selected: selected, selectedRef: selectedRef, onSelect: onSelect })); | ||
const selected = selectedFixtureId?.path === data.path; | ||
return (React.createElement(FixtureButton, { name: name, fixturePath: data.path, indentLevel: parents.length, selected: selected, selectedRef: selectedRef, onSelect: onSelect })); | ||
} | ||
if (data.type === 'multiFixture') { | ||
const selected = selectedFixtureId !== null && | ||
recordContainsFixtureId(data.fixtureIds, selectedFixtureId); | ||
return (React.createElement(MultiFixtureButton, { name: name, fixtureIds: data.fixtureIds, indentLevel: parents.length, selected: selected, selectedFixtureId: selectedFixtureId, selectedRef: selectedRef, onSelect: onSelect })); | ||
const selected = selectedFixtureId?.path === data.path; | ||
return (React.createElement(MultiFixtureButton, { name: name, fixturePath: data.path, fixtureNames: data.names, indentLevel: parents.length, selected: selected, selectedFixtureId: selectedFixtureId, selectedRef: selectedRef, onSelect: onSelect })); | ||
} | ||
@@ -28,3 +26,3 @@ if (!children) | ||
selectedFixtureId !== null && | ||
nodeContainsFixtureId(node, selectedFixtureId); | ||
fixtureTreeNodeContainsFixtureId(node, selectedFixtureId); | ||
return (React.createElement(FixtureDir, { name: name, indentLevel: parents.length, expanded: expanded, selected: selected, onToggle: onToggle })); | ||
@@ -31,0 +29,0 @@ } }))); |
@@ -1,6 +0,7 @@ | ||
import { RefObject } from 'react'; | ||
import React, { RefObject } from 'react'; | ||
import { FixtureId } from 'react-cosmos-core'; | ||
type Props = { | ||
name: string; | ||
fixtureIds: Record<string, FixtureId>; | ||
fixturePath: string; | ||
fixtureNames: string[]; | ||
indentLevel: number; | ||
@@ -12,3 +13,3 @@ selected: boolean; | ||
}; | ||
export declare function MultiFixtureButton({ name, fixtureIds, indentLevel, selected, selectedFixtureId, selectedRef, onSelect, }: Props): JSX.Element | null; | ||
export declare function MultiFixtureButton({ name, fixturePath, fixtureNames, indentLevel, selected, selectedFixtureId, selectedRef, onSelect, }: Props): React.JSX.Element; | ||
export {}; |
@@ -1,2 +0,1 @@ | ||
import { isEqual } from 'lodash-es'; | ||
import React from 'react'; | ||
@@ -8,12 +7,13 @@ import styled from 'styled-components'; | ||
import { MultiFixtureChildButton } from './MultiFixtureChildButton.js'; | ||
export function MultiFixtureButton({ name, fixtureIds, indentLevel, selected, selectedFixtureId, selectedRef, onSelect, }) { | ||
const fixtureNames = Object.keys(fixtureIds); | ||
const firstFixtureId = fixtureIds[fixtureNames[0]]; | ||
if (!firstFixtureId) | ||
return null; | ||
if (!selected) | ||
return (React.createElement(FixtureLink, { fixtureId: firstFixtureId, onSelect: onSelect }, | ||
export function MultiFixtureButton({ name, fixturePath, fixtureNames, indentLevel, selected, selectedFixtureId, selectedRef, onSelect, }) { | ||
if (!selected) { | ||
const [firstFixtureName] = fixtureNames; | ||
const fixtureId = firstFixtureName | ||
? { path: fixturePath, name: firstFixtureName } | ||
: { path: fixturePath }; | ||
return (React.createElement(FixtureLink, { fixtureId: fixtureId, onSelect: onSelect }, | ||
React.createElement(FixtureTreeItem, { indentLevel: indentLevel, selected: false }, | ||
React.createElement(Name, null, name), | ||
React.createElement(Count, null, fixtureNames.length)))); | ||
} | ||
return (React.createElement(React.Fragment, null, | ||
@@ -23,5 +23,10 @@ React.createElement(FixtureTreeItem, { indentLevel: indentLevel, selected: true }, | ||
React.createElement(Count, null, fixtureNames.length)), | ||
fixtureNames.map(fixtureName => { | ||
const fixtureId = fixtureIds[fixtureName]; | ||
const childSelected = isEqual(fixtureId, selectedFixtureId); | ||
fixtureNames.map((fixtureName, index) => { | ||
const fixtureId = { path: fixturePath, name: fixtureName }; | ||
// Select first child when only the path of a multi fixture is selected | ||
const childSelected = selectedFixtureId !== null && | ||
selectedFixtureId.path === fixturePath && | ||
(selectedFixtureId.name === undefined | ||
? index === 0 | ||
: fixtureName === selectedFixtureId.name); | ||
return (React.createElement(MultiFixtureChildButton, { key: fixtureName, name: fixtureName, fixtureId: fixtureId, indentLevel: indentLevel + 1, selected: childSelected, selectedRef: selectedRef, onSelect: onSelect })); | ||
@@ -28,0 +33,0 @@ }), |
@@ -1,2 +0,2 @@ | ||
import { RefObject } from 'react'; | ||
import React, { RefObject } from 'react'; | ||
import { FixtureId } from 'react-cosmos-core'; | ||
@@ -11,3 +11,3 @@ type Props = { | ||
}; | ||
export declare function MultiFixtureChildButton({ name, fixtureId, indentLevel, selected, selectedRef, onSelect, }: Props): JSX.Element; | ||
export declare function MultiFixtureChildButton({ name, fixtureId, indentLevel, selected, selectedRef, onSelect, }: Props): React.JSX.Element; | ||
export {}; |
@@ -0,1 +1,2 @@ | ||
import React from 'react'; | ||
import { FixtureId, FixtureList } from 'react-cosmos-core'; | ||
@@ -7,3 +8,2 @@ import { TreeExpansion } from '../../shared/treeExpansion.js'; | ||
selectedFixtureId: null | FixtureId; | ||
rendererConnected: boolean; | ||
fixtures: FixtureList; | ||
@@ -14,3 +14,3 @@ expansion: TreeExpansion; | ||
}; | ||
export declare function FixtureTreeContainer({ fixturesDir, fixtureFileSuffix, selectedFixtureId, rendererConnected, fixtures, expansion, selectFixture, setExpansion, }: Props): JSX.Element; | ||
export declare function FixtureTreeContainer({ fixturesDir, fixtureFileSuffix, selectedFixtureId, fixtures, expansion, selectFixture, setExpansion, }: Props): React.JSX.Element; | ||
export {}; |
@@ -9,7 +9,5 @@ import React, { useMemo } from 'react'; | ||
import { useScrollToSelected } from './useScrollToSelected.js'; | ||
export function FixtureTreeContainer({ fixturesDir, fixtureFileSuffix, selectedFixtureId, rendererConnected, fixtures, expansion, selectFixture, setExpansion, }) { | ||
export function FixtureTreeContainer({ fixturesDir, fixtureFileSuffix, selectedFixtureId, fixtures, expansion, selectFixture, setExpansion, }) { | ||
const rootNode = useMemo(() => createFixtureTree({ fixtures, fixturesDir, fixtureFileSuffix }), [fixtures, fixturesDir, fixtureFileSuffix]); | ||
const { containerRef, selectedRef } = useScrollToSelected(selectedFixtureId); | ||
if (!rendererConnected) | ||
return React.createElement(TreeContainer, null); | ||
if (Object.keys(fixtures).length === 0) { | ||
@@ -16,0 +14,0 @@ return (React.createElement(TreeContainer, null, |
@@ -0,1 +1,2 @@ | ||
import React from 'react'; | ||
import { FixtureList } from 'react-cosmos-core'; | ||
@@ -10,3 +11,3 @@ import { TreeExpansion } from '../../shared/treeExpansion.js'; | ||
}; | ||
export declare function FixtureTreeHeader({ fixturesDir, fixtureFileSuffix, fixtures, expansion, setExpansion, }: Props): JSX.Element; | ||
export declare function FixtureTreeHeader({ fixturesDir, fixtureFileSuffix, fixtures, expansion, setExpansion, }: Props): React.JSX.Element; | ||
export {}; |
@@ -21,3 +21,3 @@ import React, { useCallback } from 'react'; | ||
const setExpansionMemo = useCallback((newExpansion) => setTreeExpansion(storage, newExpansion), [storage]); | ||
return (React.createElement(FixtureTreeContainer, { fixturesDir: fixturesDir, fixtureFileSuffix: fixtureFileSuffix, selectedFixtureId: router.getSelectedFixtureId(), rendererConnected: rendererCore.isRendererConnected(), fixtures: rendererCore.getFixtures(), expansion: expansion, selectFixture: router.selectFixture, setExpansion: setExpansionMemo })); | ||
return (React.createElement(FixtureTreeContainer, { fixturesDir: fixturesDir, fixtureFileSuffix: fixtureFileSuffix, selectedFixtureId: router.getSelectedFixtureId(), fixtures: rendererCore.getFixtures(), expansion: expansion, selectFixture: router.selectFixture, setExpansion: setExpansionMemo })); | ||
}); | ||
@@ -24,0 +24,0 @@ export { register }; |
import { createFixtureTree, } from 'react-cosmos-core'; | ||
import { nodeContainsFixtureId } from '../../shared/fixtureTree.js'; | ||
import { fixtureTreeNodeContainsFixtureId } from '../../shared/fixtureTree.js'; | ||
import { getTreeExpansion, setTreeExpansion, } from './shared.js'; | ||
@@ -35,3 +35,3 @@ export function revealFixture(context, fixtureId) { | ||
if (childNode.data.type !== 'fileDir') { | ||
if (nodeContainsFixtureId(childNode, fixtureId)) | ||
if (fixtureTreeNodeContainsFixtureId(childNode, fixtureId)) | ||
return parents; | ||
@@ -38,0 +38,0 @@ } |
@@ -6,3 +6,3 @@ import { PluginContext } from 'react-plugin'; | ||
export type FixtureTreeContext = PluginContext<FixtureTreeSpec>; | ||
export declare function getTreeExpansion({ getItem }: StorageSpec['methods']): TreeExpansion; | ||
export declare function getTreeExpansion({ getItem }: StorageSpec['methods']): {}; | ||
export declare function setTreeExpansion({ setItem }: StorageSpec['methods'], treeExpansion: TreeExpansion): void; |
@@ -0,5 +1,6 @@ | ||
import React from 'react'; | ||
type Props = { | ||
onClick: () => void; | ||
}; | ||
export declare function FullScreenButton({ onClick }: Props): JSX.Element; | ||
export declare function FullScreenButton({ onClick }: Props): React.JSX.Element; | ||
export {}; |
import React from 'react'; | ||
import { createRendererUrl } from 'react-cosmos-core'; | ||
import { createPlugin } from 'react-plugin'; | ||
import { stringifyRendererUrlQuery } from 'react-cosmos-core'; | ||
import { FullScreenButton } from './FullScreenButton.js'; | ||
@@ -12,7 +12,13 @@ const { namedPlug, register } = createPlugin({ | ||
const core = getMethodsOf('core'); | ||
const rendererUrl = core.getWebRendererUrl(); | ||
const rendererCore = getMethodsOf('rendererCore'); | ||
const rendererUrl = rendererCore.getRendererUrl(); | ||
const onSelect = React.useCallback(() => { | ||
const query = stringifyRendererUrlQuery({ _fixtureId: fixtureId }); | ||
const fixtureUrl = `${rendererUrl}?${query}`; | ||
window.open(fixtureUrl, '_blank'); | ||
if (rendererUrl) { | ||
const fixtureUrl = createRendererUrl(rendererUrl, fixtureId, true); | ||
// noopener is required to prevent reuse of sessionStorage from the | ||
// Playground window, thus making sure the remote renderer will generate | ||
// a different rendererId from the iframe renderer. | ||
// https://stackoverflow.com/a/73821739 | ||
window.open(fixtureUrl, '_blank', 'noopener=true'); | ||
} | ||
}, [fixtureId, rendererUrl]); | ||
@@ -19,0 +25,0 @@ React.useEffect(() => { |
@@ -9,3 +9,3 @@ import { rendererSocketMessage, } from 'react-cosmos-core'; | ||
} | ||
socket = new WebSocket(location.origin.replace(/^https?:/, 'ws:')); | ||
socket = new WebSocket(location.origin.replace(/^https:/, 'wss:').replace(/^http:/, 'ws:')); | ||
socket.addEventListener('open', () => { | ||
@@ -12,0 +12,0 @@ if (socket && pendingMessages.length > 0) { |
@@ -0,1 +1,2 @@ | ||
import React from 'react'; | ||
import { NotificationItem } from './spec.js'; | ||
@@ -5,3 +6,3 @@ type Props = { | ||
}; | ||
export declare function Notifications({ notifications }: Props): JSX.Element; | ||
export declare function Notifications({ notifications }: Props): React.JSX.Element; | ||
export {}; |
import './BuildNotifications/index.js'; | ||
import './ClassStatePanel/index.js'; | ||
import './ContentOverlay/index.js'; | ||
import './ControlPanel/index.js'; | ||
@@ -5,0 +4,0 @@ import './ControlSelect/index.js'; |
import { enablePlugin } from 'react-plugin'; | ||
import './BuildNotifications/index.js'; | ||
import './ClassStatePanel/index.js'; | ||
import './ContentOverlay/index.js'; | ||
import './ControlPanel/index.js'; | ||
@@ -6,0 +5,0 @@ import './ControlSelect/index.js'; |
@@ -0,1 +1,2 @@ | ||
import React from 'react'; | ||
export type SimplePlugin = { | ||
@@ -9,3 +10,3 @@ name: string; | ||
}; | ||
export declare function PluginList({ plugins, enable }: Props): JSX.Element; | ||
export declare function PluginList({ plugins, enable }: Props): React.JSX.Element; | ||
export {}; |
@@ -1,3 +0,4 @@ | ||
export declare function BlankState(): JSX.Element; | ||
import React from 'react'; | ||
export declare function BlankState(): React.JSX.Element; | ||
export declare const IconContainer: import("styled-components").StyledComponent<"div", any, {}, never>; | ||
export declare const NoWrap: import("styled-components").StyledComponent<"span", any, {}, never>; |
import React from 'react'; | ||
import { DelayRender } from 'react-cosmos-core'; | ||
import styled from 'styled-components'; | ||
@@ -6,14 +7,15 @@ import { SlidersIcon } from '../../components/icons/index.js'; | ||
export function BlankState() { | ||
return (React.createElement(Container, null, | ||
React.createElement(IconContainer, null, | ||
React.createElement(SlidersIcon, null)), | ||
React.createElement(Title, null, | ||
"No visible props in ", | ||
React.createElement(NoWrap, null, "selected fixture")), | ||
React.createElement(Description, null, | ||
"Props of exported JSX ", | ||
React.createElement(NoWrap, null, "elements from"), | ||
" your fixtures", | ||
' ', | ||
React.createElement(NoWrap, null, "will appear here.")))); | ||
return (React.createElement(DelayRender, { delay: 500 }, | ||
React.createElement(Container, null, | ||
React.createElement(IconContainer, null, | ||
React.createElement(SlidersIcon, null)), | ||
React.createElement(Title, null, | ||
"No visible props in ", | ||
React.createElement(NoWrap, null, "selected fixture")), | ||
React.createElement(Description, null, | ||
"Props of exported JSX ", | ||
React.createElement(NoWrap, null, "elements from"), | ||
" your fixtures", | ||
' ', | ||
React.createElement(NoWrap, null, "will appear here."))))); | ||
} | ||
@@ -20,0 +22,0 @@ const Container = styled.div ` |
@@ -1,2 +0,2 @@ | ||
import React from 'react'; | ||
import React, { useCallback } from 'react'; | ||
import { createPlugin } from 'react-plugin'; | ||
@@ -6,3 +6,3 @@ import { getFixtureExpansion, hasFsValues, updateElementExpansion, } from '../../components/ValueInputTree/index.js'; | ||
import { PropsPanel } from './PropsPanel/index.js'; | ||
import { PROPS_TREE_EXPANSION_STORAGE_KEY } from './shared.js'; | ||
import { PROPS_TREE_EXPANSION_STORAGE_KEY, } from './shared.js'; | ||
const { namedPlug, register } = createPlugin({ | ||
@@ -12,4 +12,6 @@ name: 'propsPanel', | ||
namedPlug('sidePanelRow', 'props', ({ pluginContext, slotProps }) => { | ||
const { fixtureId, fixtureState, onFixtureStateChange } = slotProps; | ||
const { fixtureId, getFixtureState, setFixtureState } = slotProps; | ||
const { fixtureExpansion, onElementExpansionChange } = useFixtureExpansion(pluginContext, fixtureId); | ||
const fixtureState = getFixtureState('props'); | ||
const onFixtureStateChange = useCallback(change => setFixtureState('props', change), [setFixtureState]); | ||
return (React.createElement(PropsPanel, { fixtureState: fixtureState, fixtureExpansion: fixtureExpansion, onFixtureStateChange: onFixtureStateChange, onElementExpansionChange: onElementExpansionChange })); | ||
@@ -22,4 +24,4 @@ }); | ||
namedPlug('sidePanelRow', 'blankState', ({ slotProps }) => { | ||
const { fixtureState } = slotProps; | ||
return shouldShowBlankState(fixtureState) ? React.createElement(BlankState, null) : null; | ||
const { getFixtureState } = slotProps; | ||
return shouldShowBlankState(getFixtureState) ? React.createElement(BlankState, null) : null; | ||
}); | ||
@@ -44,13 +46,13 @@ export { register }; | ||
} | ||
function shouldShowBlankState(fixtureState) { | ||
// Don't show blank state until props (empty or not) have been read | ||
if (!fixtureState.props) | ||
return false; | ||
const hasProps = fixtureState.props.some(hasFsValues); | ||
function shouldShowBlankState(getFixtureState) { | ||
const props = getFixtureState('props'); | ||
const hasProps = props && props.some(hasFsValues); | ||
if (hasProps) | ||
return false; | ||
const hasClassState = fixtureState.classState && fixtureState.classState.some(hasFsValues); | ||
const classState = getFixtureState('classState'); | ||
const hasClassState = classState && classState.some(hasFsValues); | ||
if (hasClassState) | ||
return false; | ||
const hasControls = fixtureState.controls && Object.keys(fixtureState.controls).length > 0; | ||
const controls = getFixtureState('controls'); | ||
const hasControls = controls && Object.keys(controls).length > 0; | ||
if (hasControls) | ||
@@ -57,0 +59,0 @@ return false; |
@@ -1,10 +0,12 @@ | ||
import { FixtureState, FixtureStateProps, StateUpdater } from 'react-cosmos-core'; | ||
import React from 'react'; | ||
import { PropsFixtureStateItem } from 'react-cosmos-core'; | ||
import { FixtureExpansion, OnElementExpansionChange } from '../../../components/ValueInputTree/index.js'; | ||
import { SetPropsFixtureState } from '../shared.js'; | ||
type Props = { | ||
fsProps: FixtureStateProps; | ||
propsFsItem: PropsFixtureStateItem; | ||
fixtureExpansion: FixtureExpansion; | ||
onFixtureStateChange: (stateUpdater: StateUpdater<FixtureState>) => void; | ||
onFixtureStateChange: SetPropsFixtureState; | ||
onElementExpansionChange: OnElementExpansionChange; | ||
}; | ||
export declare function ComponentProps({ fsProps, fixtureExpansion, onFixtureStateChange, onElementExpansionChange, }: Props): JSX.Element; | ||
export declare function ComponentProps({ propsFsItem, fixtureExpansion, onFixtureStateChange, onElementExpansionChange, }: Props): React.JSX.Element; | ||
export {}; |
import { isEqual } from 'lodash-es'; | ||
import React, { useCallback } from 'react'; | ||
import { resetFixtureStateProps, updateFixtureStateProps, } from 'react-cosmos-core'; | ||
import { resetPropsFixtureStateItem, updatePropsFixtureStateItem, } from 'react-cosmos-core'; | ||
import { SidePanelActions, SidePanelBody, SidePanelContainer, SidePanelHeader, SidePanelTitle, } from '../../../components/SidePanel.js'; | ||
import { ExpandCollapseValues } from '../../../components/ValueInputTree/ExpandCollapseValues.js'; | ||
import { ValueInputTree, stringifyElementId, } from '../../../components/ValueInputTree/index.js'; | ||
import { IconButton32 } from '../../../components/buttons/index.js'; | ||
import { CopyIcon, RotateCcwIcon } from '../../../components/icons/index.js'; | ||
import { SidePanelActions, SidePanelBody, SidePanelContainer, SidePanelHeader, SidePanelTitle, } from '../../../components/SidePanel.js'; | ||
import { ExpandCollapseValues } from '../../../components/ValueInputTree/ExpandCollapseValues.js'; | ||
import { stringifyElementId, ValueInputTree, } from '../../../components/ValueInputTree/index.js'; | ||
import { createPropsFsUpdater } from './shared.js'; | ||
export function ComponentProps({ fsProps, fixtureExpansion, onFixtureStateChange, onElementExpansionChange, }) { | ||
const { componentName, elementId, values } = fsProps; | ||
import { propsFsItemUpdater } from './shared.js'; | ||
export function ComponentProps({ propsFsItem, fixtureExpansion, onFixtureStateChange, onElementExpansionChange, }) { | ||
const { componentName, elementId, values } = propsFsItem; | ||
const [reset, setReset] = React.useState(true); | ||
const handleResetToggle = React.useCallback(() => setReset(!reset), [reset]); | ||
const [initialValues] = React.useState(() => values); | ||
const handleValuesReset = React.useCallback(() => onFixtureStateChange(createPropsFsUpdater(elementId, prevFs => resetFixtureStateProps({ | ||
fixtureState: prevFs, | ||
const handleValuesReset = React.useCallback(() => onFixtureStateChange(propsFsItemUpdater(elementId, prevFs => resetPropsFixtureStateItem({ | ||
propsFs: prevFs, | ||
elementId, | ||
@@ -21,5 +21,7 @@ values: initialValues, | ||
const handleValueChange = React.useCallback((newValues) => { | ||
const changeFn = reset ? resetFixtureStateProps : updateFixtureStateProps; | ||
onFixtureStateChange(createPropsFsUpdater(elementId, prevFs => changeFn({ | ||
fixtureState: prevFs, | ||
const changeFn = reset | ||
? resetPropsFixtureStateItem | ||
: updatePropsFixtureStateItem; | ||
onFixtureStateChange(propsFsItemUpdater(elementId, prevFs => changeFn({ | ||
propsFs: prevFs, | ||
elementId, | ||
@@ -26,0 +28,0 @@ values: newValues, |
import React from 'react'; | ||
import { FixtureState, StateUpdater } from 'react-cosmos-core'; | ||
import { PropsFixtureState } from 'react-cosmos-core'; | ||
import { FixtureExpansion, OnElementExpansionChange } from '../../../components/ValueInputTree/index.js'; | ||
import { SetPropsFixtureState } from '../shared.js'; | ||
type Props = { | ||
fixtureState: FixtureState; | ||
fixtureState: PropsFixtureState | undefined; | ||
fixtureExpansion: FixtureExpansion; | ||
onFixtureStateChange: (stateUpdater: StateUpdater<FixtureState>) => void; | ||
onFixtureStateChange: SetPropsFixtureState; | ||
onElementExpansionChange: OnElementExpansionChange; | ||
@@ -9,0 +10,0 @@ }; |
@@ -5,10 +5,10 @@ import React from 'react'; | ||
export const PropsPanel = React.memo(function PropsPanel({ fixtureState, fixtureExpansion, onFixtureStateChange, onElementExpansionChange, }) { | ||
if (!fixtureState.props) { | ||
if (!fixtureState) { | ||
return null; | ||
} | ||
const propsWithValues = fixtureState.props.filter(hasFsValues); | ||
return (React.createElement(React.Fragment, null, sortFsValueGroups(propsWithValues).map(fsProps => { | ||
const strElementId = stringifyElementId(fsProps.elementId); | ||
return (React.createElement(ComponentProps, { key: strElementId, fsProps: fsProps, fixtureExpansion: fixtureExpansion, onFixtureStateChange: onFixtureStateChange, onElementExpansionChange: onElementExpansionChange })); | ||
const propsWithValues = fixtureState.filter(hasFsValues); | ||
return (React.createElement(React.Fragment, null, sortFsValueGroups(propsWithValues).map(fsItem => { | ||
const strElementId = stringifyElementId(fsItem.elementId); | ||
return (React.createElement(ComponentProps, { key: strElementId, propsFsItem: fsItem, fixtureExpansion: fixtureExpansion, onFixtureStateChange: onFixtureStateChange, onElementExpansionChange: onElementExpansionChange })); | ||
}))); | ||
}); |
@@ -1,2 +0,2 @@ | ||
import { FixtureElementId, FixtureState, FixtureStateProps, StateUpdater } from 'react-cosmos-core'; | ||
export declare function createPropsFsUpdater(elementId: FixtureElementId, cb: (prevFs: FixtureState) => FixtureStateProps[]): StateUpdater<FixtureState>; | ||
import { FixtureElementId, FixtureStateUpdater, PropsFixtureState } from 'react-cosmos-core'; | ||
export declare function propsFsItemUpdater(elementId: FixtureElementId, cb: FixtureStateUpdater<PropsFixtureState>): FixtureStateUpdater<PropsFixtureState>; |
@@ -1,16 +0,13 @@ | ||
import { findFixtureStateProps, } from 'react-cosmos-core'; | ||
import { findPropsFixtureStateItem, } from 'react-cosmos-core'; | ||
import { stringifyElementId } from '../../../components/ValueInputTree/index.js'; | ||
export function createPropsFsUpdater(elementId, cb) { | ||
export function propsFsItemUpdater(elementId, cb) { | ||
return prevFs => { | ||
const fsProps = findFixtureStateProps(prevFs, elementId); | ||
if (!fsProps) { | ||
const fsItem = findPropsFixtureStateItem(prevFs, elementId); | ||
if (!fsItem) { | ||
const elId = stringifyElementId(elementId); | ||
console.warn(`Trying to update missing element with ID: ${elId}`); | ||
return prevFs; | ||
return prevFs ?? []; | ||
} | ||
return { | ||
...prevFs, | ||
props: cb(prevFs), | ||
}; | ||
return cb(prevFs); | ||
}; | ||
} |
@@ -0,1 +1,3 @@ | ||
import { FixtureStateUpdater, PropsFixtureState } from 'react-cosmos-core'; | ||
export type SetPropsFixtureState = (updater: FixtureStateUpdater<PropsFixtureState>) => void; | ||
export declare const PROPS_TREE_EXPANSION_STORAGE_KEY = "propsTreeExpansion"; |
@@ -27,4 +27,5 @@ import React from 'react'; | ||
const core = getMethodsOf('core'); | ||
const rendererCore = getMethodsOf('rendererCore'); | ||
const notifications = getMethodsOf('notifications'); | ||
return (React.createElement(RemoteButton, { devServerOn: core.isDevServerOn(), webRendererUrl: core.getWebRendererUrl(), pushNotification: notifications.pushTimedNotification })); | ||
return (React.createElement(RemoteButton, { devServerOn: core.isDevServerOn(), rendererUrl: rendererCore.getRendererUrl(), pushNotification: notifications.pushTimedNotification })); | ||
}); | ||
@@ -31,0 +32,0 @@ export { register }; |
@@ -0,8 +1,9 @@ | ||
import React from 'react'; | ||
import { NotificationItem } from '../../Notifications/spec.js'; | ||
type Props = { | ||
devServerOn: boolean; | ||
webRendererUrl: null | string; | ||
rendererUrl: null | string; | ||
pushNotification: (notification: NotificationItem) => unknown; | ||
}; | ||
export declare function RemoteButton({ devServerOn, webRendererUrl, pushNotification, }: Props): JSX.Element | null; | ||
export declare function RemoteButton({ devServerOn, rendererUrl, pushNotification, }: Props): React.JSX.Element | null; | ||
export {}; |
import React from 'react'; | ||
import { createRendererUrl } from 'react-cosmos-core'; | ||
import { IconButton32 } from '../../../components/buttons/index.js'; | ||
import { CastIcon } from '../../../components/icons/index.js'; | ||
import { copyToClipboard } from './copyToClipboard.js'; | ||
export function RemoteButton({ devServerOn, webRendererUrl, pushNotification, }) { | ||
if (!devServerOn || !webRendererUrl) { | ||
export function RemoteButton({ devServerOn, rendererUrl, pushNotification, }) { | ||
if (!devServerOn || !rendererUrl) { | ||
return null; | ||
} | ||
return (React.createElement(IconButton32, { icon: React.createElement(CastIcon, null), title: "Copy remote renderer URL", onClick: () => copyRendererUrlToClipboard(webRendererUrl) })); | ||
return (React.createElement(IconButton32, { icon: React.createElement(CastIcon, null), title: "Copy remote renderer URL", onClick: () => copyRendererUrlToClipboard(createRendererUrl(rendererUrl)) })); | ||
async function copyRendererUrlToClipboard(url) { | ||
@@ -36,3 +37,3 @@ const fullUrl = getFullUrl(url); | ||
return rendererUrl; | ||
return `${location.origin}${rendererUrl}`; | ||
return new URL(rendererUrl, location.origin).toString(); | ||
} |
@@ -0,8 +1,16 @@ | ||
import { fixtureStateByName } from 'react-cosmos-core'; | ||
import { createPlugin } from 'react-plugin'; | ||
import { isValidFixtureSelected } from './isValidFixtureSelected.js'; | ||
import { onRouterFixtureChange } from './onRouterFixtureChange.js'; | ||
import { onRouterFixtureReselect } from './onRouterFixtureReselect.js'; | ||
import { onRouterFixtureSelect } from './onRouterFixtureSelect.js'; | ||
import { onRouterFixtureUnselect } from './onRouterFixtureUnselect.js'; | ||
import { receiveResponse } from './receiveResponse/index.js'; | ||
import { reloadRenderer } from './reloadRenderer.js'; | ||
import { setFixtureState } from './setFixtureState.js'; | ||
const { on, register } = createPlugin({ | ||
import { setGlobalFixtureState } from './setGlobalFixtureState.js'; | ||
const { on, register, onLoad } = createPlugin({ | ||
name: 'rendererCore', | ||
defaultConfig: { | ||
fixtures: {}, | ||
rendererUrl: null, | ||
}, | ||
initialState: { | ||
@@ -13,19 +21,34 @@ connectedRendererIds: [], | ||
fixtureState: {}, | ||
globalFixtureState: {}, | ||
}, | ||
methods: { | ||
getRendererUrl, | ||
getConnectedRendererIds, | ||
getPrimaryRendererId, | ||
getFixtures, | ||
getFixtureState, | ||
isRendererConnected, | ||
isValidFixtureSelected, | ||
setFixtureState, | ||
reloadRenderer, | ||
selectPrimaryRenderer, | ||
receiveResponse, | ||
getAllFixtureState, | ||
getFixtureState, | ||
setFixtureState, | ||
setGlobalFixtureState, | ||
}, | ||
}); | ||
on('router', { fixtureChange: onRouterFixtureChange }); | ||
onLoad(({ getConfig, setState }) => { | ||
const { fixtures } = getConfig(); | ||
setState(prevState => ({ ...prevState, fixtures })); | ||
}); | ||
on('router', { | ||
fixtureSelect: onRouterFixtureSelect, | ||
fixtureReselect: onRouterFixtureReselect, | ||
fixtureUnselect: onRouterFixtureUnselect, | ||
}); | ||
export { register }; | ||
if (process.env.NODE_ENV !== 'test') | ||
register(); | ||
function getRendererUrl({ getConfig }) { | ||
return getConfig().rendererUrl; | ||
} | ||
function getConnectedRendererIds({ getState }) { | ||
@@ -40,5 +63,8 @@ return getState().connectedRendererIds; | ||
} | ||
function getFixtureState({ getState }) { | ||
function getAllFixtureState({ getState }) { | ||
return getState().fixtureState; | ||
} | ||
function getFixtureState({ getState }, name) { | ||
return fixtureStateByName(getState().fixtureState, name); | ||
} | ||
function isRendererConnected({ getState }) { | ||
@@ -45,0 +71,0 @@ return getState().connectedRendererIds.length > 0; |
@@ -8,2 +8,6 @@ import { isEqual } from 'lodash-es'; | ||
const { primaryRendererId, fixtureState: prevFixtureState } = context.getState(); | ||
// Discard updates from secondary renderers | ||
if (rendererId !== primaryRendererId) { | ||
return; | ||
} | ||
if (!isEqual(fixtureId, selectedFixtureId)) { | ||
@@ -14,6 +18,2 @@ console.warn('[Renderer] fixtureStateChange response ignored ' + | ||
} | ||
// Discard updates from secondary renderers | ||
if (rendererId !== primaryRendererId) { | ||
return; | ||
} | ||
if (isEqual(fixtureState, prevFixtureState)) { | ||
@@ -20,0 +20,0 @@ return; |
@@ -1,5 +0,6 @@ | ||
import { postSelectFixtureRequest } from '../shared/postRequest.js'; | ||
import { getSelectedFixtureId } from '../shared/router.js'; | ||
import { isEqual } from 'lodash-es'; | ||
import { postSelectFixtureRequest, postSetFixtureStateRequest, } from '../shared/postRequest.js'; | ||
export function receiveRendererReadyResponse(context, { payload }) { | ||
const { rendererId, fixtures, initialFixtureId } = payload; | ||
const { rendererId } = payload; | ||
const { connectedRendererIds: prevRendererIds, globalFixtureState } = context.getState(); | ||
context.setState(stateUpdater, afterStateChanged); | ||
@@ -9,3 +10,2 @@ function stateUpdater(prevState) { | ||
const primaryRendererId = prevState.primaryRendererId || rendererId; | ||
const isPrimaryRenderer = rendererId === primaryRendererId; | ||
const { connectedRendererIds, fixtureState } = prevState; | ||
@@ -16,25 +16,24 @@ return { | ||
primaryRendererId, | ||
fixtures, | ||
fixtureState: isPrimaryRenderer ? {} : fixtureState, | ||
fixtureState: rendererId === primaryRendererId ? globalFixtureState : fixtureState, | ||
}; | ||
} | ||
function afterStateChanged() { | ||
if (initialFixtureId) | ||
selectInitialFixture(context, initialFixtureId); | ||
else | ||
selectFixtureFromUrlParams(context, rendererId); | ||
notifyRendererConnection(context, rendererId); | ||
const router = context.getMethodsOf('router'); | ||
const rendererFixtureId = payload.selectedFixtureId; | ||
const routerFixtureId = router.getSelectedFixtureId(); | ||
if (routerFixtureId && !isEqual(routerFixtureId, rendererFixtureId)) { | ||
const { fixtureState } = context.getState(); | ||
postSelectFixtureRequest(context, rendererId, routerFixtureId, fixtureState); | ||
} | ||
else if (rendererFixtureId) { | ||
if (Object.keys(globalFixtureState).length > 0) { | ||
postSetFixtureStateRequest(context, rendererId, rendererFixtureId, globalFixtureState); | ||
} | ||
} | ||
// Notify about connected renderers that weren't connected before | ||
if (!prevRendererIds.includes(rendererId)) { | ||
notifyRendererConnection(context, rendererId); | ||
} | ||
} | ||
} | ||
function selectInitialFixture({ getMethodsOf }, fixtureId) { | ||
const router = getMethodsOf('router'); | ||
router.selectFixture(fixtureId); | ||
} | ||
function selectFixtureFromUrlParams(context, rendererId) { | ||
const fixtureId = getSelectedFixtureId(context); | ||
if (fixtureId) { | ||
const { fixtureState } = context.getState(); | ||
postSelectFixtureRequest(context, rendererId, fixtureId, fixtureState); | ||
} | ||
} | ||
function notifyRendererConnection({ getMethodsOf }, rendererId) { | ||
@@ -41,0 +40,0 @@ const notifications = getMethodsOf('notifications'); |
@@ -1,3 +0,3 @@ | ||
import { FixtureState, StateUpdater } from 'react-cosmos-core'; | ||
import { FixtureStateChange } from 'react-cosmos-core'; | ||
import { RendererCoreContext } from './shared/index.js'; | ||
export declare function setFixtureState(context: RendererCoreContext, stateUpdater: StateUpdater<FixtureState>): void; | ||
export declare function setFixtureState(context: RendererCoreContext, name: string, change: FixtureStateChange<unknown>): void; |
@@ -0,4 +1,5 @@ | ||
import { updateFixtureState, } from 'react-cosmos-core'; | ||
import { postSetFixtureStateRequest } from './shared/postRequest.js'; | ||
import { getSelectedFixtureId } from './shared/router.js'; | ||
export function setFixtureState(context, stateUpdater) { | ||
export function setFixtureState(context, name, change) { | ||
const fixtureId = getSelectedFixtureId(context); | ||
@@ -9,9 +10,9 @@ if (!fixtureId) { | ||
} | ||
context.setState(change, () => { | ||
context.setState(stateUpdater, () => { | ||
postRendererRequest(fixtureId); | ||
}); | ||
function change(prevState) { | ||
function stateUpdater(prevState) { | ||
return { | ||
...prevState, | ||
fixtureState: stateUpdater(prevState.fixtureState), | ||
fixtureState: updateFixtureState(prevState.fixtureState, name, change), | ||
}; | ||
@@ -18,0 +19,0 @@ } |
import { FixtureId, FixtureState, RendererId } from 'react-cosmos-core'; | ||
import { RendererCoreContext } from '../shared/index.js'; | ||
import { RendererCoreContext } from './index.js'; | ||
export declare function postReloadRendererRequest(context: RendererCoreContext, rendererId: RendererId): void; | ||
export declare function postSelectFixtureRequest(context: RendererCoreContext, rendererId: RendererId, fixtureId: FixtureId, fixtureState: FixtureState): void; | ||
export declare function postUnselectFixtureRequest(context: RendererCoreContext, rendererId: RendererId): void; | ||
export declare function postSetFixtureStateRequest(context: RendererCoreContext, rendererId: RendererId, fixtureId: FixtureId, fixtureState: FixtureState): void; |
@@ -0,1 +1,9 @@ | ||
export function postReloadRendererRequest(context, rendererId) { | ||
postRendererRequest(context, { | ||
type: 'reloadRenderer', | ||
payload: { | ||
rendererId, | ||
}, | ||
}); | ||
} | ||
export function postSelectFixtureRequest(context, rendererId, fixtureId, fixtureState) { | ||
@@ -2,0 +10,0 @@ postRendererRequest(context, { |
@@ -1,4 +0,10 @@ | ||
import { FixtureList, FixtureState, MessageType, RendererId, StateUpdater } from 'react-cosmos-core'; | ||
import { FixtureList, FixtureState, FixtureStateChange, MessageType, RendererId } from 'react-cosmos-core'; | ||
export type GetFixtureState = <T>(name: string) => T | undefined; | ||
export type SetFixtureStateByName = <T>(name: string, change: FixtureStateChange<T>) => void; | ||
export type RendererCoreSpec = { | ||
name: 'rendererCore'; | ||
config: { | ||
fixtures: FixtureList; | ||
rendererUrl: null | string; | ||
}; | ||
state: { | ||
@@ -9,13 +15,17 @@ connectedRendererIds: RendererId[]; | ||
fixtureState: FixtureState; | ||
globalFixtureState: FixtureState; | ||
}; | ||
methods: { | ||
getRendererUrl(): null | string; | ||
getConnectedRendererIds(): RendererId[]; | ||
getPrimaryRendererId(): null | RendererId; | ||
getFixtures(): FixtureList; | ||
getFixtureState(): FixtureState; | ||
isRendererConnected(): boolean; | ||
isValidFixtureSelected(): boolean; | ||
setFixtureState(stateUpdater: StateUpdater<FixtureState>): void; | ||
reloadRenderer(): void; | ||
selectPrimaryRenderer(primaryRendererId: RendererId): void; | ||
receiveResponse(msg: MessageType): void; | ||
getAllFixtureState(): FixtureState; | ||
getFixtureState: GetFixtureState; | ||
setFixtureState: SetFixtureStateByName; | ||
setGlobalFixtureState<T>(name: string, state: T): void; | ||
}; | ||
@@ -22,0 +32,0 @@ events: { |
@@ -37,3 +37,3 @@ const notificationId = 'renderer-location-change'; | ||
title: 'Renderer iframe location changed', | ||
info: `Reload or select another fixture to reset your preview.`, | ||
info: `Select a fixture to reset your preview.`, | ||
}); | ||
@@ -63,7 +63,8 @@ } | ||
const { href } = iframeWindow.location; | ||
const locationWithoutHash = href.split('#')[0]; | ||
return (locationWithoutHash !== iframeSrc && | ||
// Some static servers strip .html extensions automatically | ||
// https://github.com/zeit/serve-handler/tree/ce35fcd4e1c67356348f4735eed88fb084af9b43#cleanurls-booleanarray | ||
locationWithoutHash !== iframeSrc.replace(/\.html$/, '')); | ||
return ( | ||
// Don't register a location change when renderer searchParams change | ||
!href.startsWith( | ||
// Some static servers strip .html extensions automatically | ||
// https://github.com/zeit/serve-handler/tree/ce35fcd4e1c67356348f4735eed88fb084af9b43#cleanurls-booleanarray | ||
iframeSrc.replace(/\.html$/, ''))); | ||
} | ||
@@ -70,0 +71,0 @@ catch (err) { |
@@ -32,4 +32,13 @@ export function handleWindowMessages(context) { | ||
} | ||
function updateRuntimeStatus({ getState, setState }, response) { | ||
function updateRuntimeStatus({ getState, setState, getMethodsOf }, response) { | ||
const { runtimeStatus } = getState(); | ||
if (response.type === 'rendererError') { | ||
const notifications = getMethodsOf('notifications'); | ||
notifications.pushTimedNotification({ | ||
id: 'renderer-error', | ||
type: 'error', | ||
title: 'Renderer error', | ||
info: 'Check the browser console for details.', | ||
}); | ||
} | ||
// Errors are not of interest anymore after renderer connectivity has been | ||
@@ -36,0 +45,0 @@ // established. Errors that occur after renderer is connected are likely |
import React from 'react'; | ||
import { createPlugin } from 'react-plugin'; | ||
import { checkRendererStatus } from './checkRendererStatus.js'; | ||
import { RendererPreview } from './RendererPreview.js'; | ||
import { createRendererRequestHandler } from './handleRendererRequests.js'; | ||
import { handleWindowMessages } from './handleWindowMessages.js'; | ||
import { RendererPreview } from './RendererPreview.js'; | ||
const { postRendererRequest, setIframeRef } = createRendererRequestHandler(); | ||
@@ -11,7 +10,5 @@ const { onLoad, on, plug, register } = createPlugin({ | ||
initialState: { | ||
urlStatus: 'unknown', | ||
runtimeStatus: 'pending', | ||
}, | ||
methods: { | ||
getUrlStatus, | ||
getRuntimeStatus, | ||
@@ -28,6 +25,3 @@ }, | ||
} | ||
return [ | ||
checkRendererStatus(context, rendererUrl), | ||
handleWindowMessages(context), | ||
]; | ||
return [handleWindowMessages(context)]; | ||
}); | ||
@@ -38,3 +32,3 @@ plug('rendererPreview', ({ pluginContext }) => { | ||
} | ||
return (React.createElement(RendererPreview, { rendererUrl: getRendererUrl(pluginContext), onIframeRef: handleIframeRef })); | ||
return (React.createElement(RendererPreview, { rendererUrl: getRendererUrl(pluginContext), rendererConnected: getRendererConnected(pluginContext), runtimeStatus: pluginContext.getState().runtimeStatus, onIframeRef: handleIframeRef })); | ||
}); | ||
@@ -44,5 +38,2 @@ export { register }; | ||
register(); | ||
function getUrlStatus({ getState }) { | ||
return getState().urlStatus; | ||
} | ||
function getRuntimeStatus({ getState }) { | ||
@@ -52,3 +43,6 @@ return getState().runtimeStatus; | ||
function getRendererUrl({ getMethodsOf }) { | ||
return getMethodsOf('core').getWebRendererUrl(); | ||
return getMethodsOf('rendererCore').getRendererUrl(); | ||
} | ||
function getRendererConnected({ getMethodsOf }) { | ||
return getMethodsOf('rendererCore').isRendererConnected(); | ||
} |
import React from 'react'; | ||
import { RuntimeStatus } from './spec.js'; | ||
export type OnIframeRef = (elRef: null | HTMLIFrameElement) => void; | ||
type Props = { | ||
rendererUrl: null | string; | ||
rendererConnected: boolean; | ||
runtimeStatus: RuntimeStatus; | ||
onIframeRef: OnIframeRef; | ||
@@ -6,0 +9,0 @@ }; |
import React from 'react'; | ||
import { createRendererUrl } from 'react-cosmos-core'; | ||
import { Slot } from 'react-plugin'; | ||
import styled from 'styled-components'; | ||
export const RendererPreview = React.memo(function RendererPreview({ rendererUrl, onIframeRef, }) { | ||
import { RemoteRendererOverlay } from './RendererOverlay/RemoteRendererOverlay.js'; | ||
import { RendererOverlay } from './RendererOverlay/RendererOverlay.js'; | ||
export const RendererPreview = React.memo(function RendererPreview({ rendererUrl, rendererConnected, runtimeStatus, onIframeRef, }) { | ||
if (!rendererUrl) { | ||
return null; | ||
// This code path is used when Cosmos is in React Native mode | ||
return (React.createElement(Container, null, | ||
React.createElement(RemoteRendererOverlay, { rendererConnected: rendererConnected }))); | ||
} | ||
return (React.createElement(Slot, { name: "rendererPreviewOuter" }, | ||
React.createElement(Container, null, | ||
React.createElement(Iframe, { "data-testid": "previewIframe", ref: onIframeRef, src: rendererUrl, frameBorder: 0, allow: "clipboard-write *" })))); | ||
React.createElement(Iframe, { "data-testid": "previewIframe", ref: onIframeRef, src: createRendererUrl(rendererUrl), frameBorder: 0, allow: "clipboard-write *; fullscreen *;" }), | ||
React.createElement(RendererOverlay, { runtimeStatus: runtimeStatus })))); | ||
}); | ||
const Container = styled.div ` | ||
position: relative; | ||
width: 100%; | ||
@@ -14,0 +21,0 @@ height: 100%; |
import { PluginContext } from 'react-plugin'; | ||
import { RendererPreviewSpec } from './spec.js'; | ||
export type UrlStatus = 'unknown' | 'ok' | 'error'; | ||
export type RuntimeStatus = 'pending' | 'connected' | 'error'; | ||
export type State = { | ||
urlStatus: UrlStatus; | ||
runtimeStatus: RuntimeStatus; | ||
}; | ||
export type RendererPreviewContext = PluginContext<RendererPreviewSpec>; |
@@ -1,2 +0,1 @@ | ||
export type UrlStatus = 'unknown' | 'ok' | 'error'; | ||
export type RuntimeStatus = 'pending' | 'connected' | 'error'; | ||
@@ -6,9 +5,7 @@ export type RendererPreviewSpec = { | ||
state: { | ||
urlStatus: UrlStatus; | ||
runtimeStatus: RuntimeStatus; | ||
}; | ||
methods: { | ||
getUrlStatus(): UrlStatus; | ||
getRuntimeStatus(): RuntimeStatus; | ||
}; | ||
}; |
import React from 'react'; | ||
import { createPlugin } from 'react-plugin'; | ||
import { ResponsivePreview } from './ResponsivePreview/ResponsivePreview.js'; | ||
import { ToggleButton } from './ToggleButton/index.js'; | ||
import { DEFAULT_DEVICES, DEFAULT_VIEWPORT_STATE, VIEWPORT_STORAGE_KEY, } from './shared.js'; | ||
import { ToggleButton } from './ToggleButton/index.js'; | ||
const { plug, namedPlug, register } = createPlugin({ | ||
@@ -13,16 +13,15 @@ name: 'responsivePreview', | ||
plug('rendererPreviewOuter', ({ children, pluginContext }) => { | ||
const { getConfig, getMethodsOf } = pluginContext; | ||
const { getConfig } = pluginContext; | ||
const { devices } = getConfig(); | ||
const rendererCore = getMethodsOf('rendererCore'); | ||
const { enabled, viewport, scaled } = getViewportState(pluginContext); | ||
const onViewportChange = useViewportChange(pluginContext); | ||
const onScaledChange = useScaledChange(pluginContext); | ||
return (React.createElement(ResponsivePreview, { devices: devices, enabled: enabled, viewport: viewport, scaled: scaled, validFixtureSelected: rendererCore.isValidFixtureSelected(), setViewport: onViewportChange, setScaled: onScaledChange }, children)); | ||
return (React.createElement(ResponsivePreview, { devices: devices, enabled: enabled, viewport: viewport, scaled: scaled, setViewport: onViewportChange, setScaled: onScaledChange }, children)); | ||
}); | ||
namedPlug('rendererAction', 'responsivePreview', ({ pluginContext }) => { | ||
const { getMethodsOf } = pluginContext; | ||
const core = getMethodsOf('core'); | ||
const rendererCore = getMethodsOf('rendererCore'); | ||
const viewportState = getViewportState(pluginContext); | ||
const { enabled, viewport } = viewportState; | ||
if (!core.getWebRendererUrl()) | ||
if (!rendererCore.getRendererUrl()) | ||
return null; | ||
@@ -32,7 +31,7 @@ return (React.createElement(ToggleButton, { selected: enabled, onToggle: () => { | ||
setViewportState(pluginContext, { ...viewportState, enabled: false }); | ||
setFixtureStateViewport(pluginContext, null); | ||
setViewportFixtureState(pluginContext, null); | ||
} | ||
else { | ||
setViewportState(pluginContext, { ...viewportState, enabled: true }); | ||
setFixtureStateViewport(pluginContext, viewport); | ||
setViewportFixtureState(pluginContext, viewport); | ||
} | ||
@@ -46,8 +45,6 @@ } })); | ||
const viewportState = getViewportState(context); | ||
return React.useCallback((viewportChange) => { | ||
const viewport = typeof viewportChange === 'function' | ||
? viewportChange(viewportState.viewport) | ||
: viewportChange; | ||
return React.useCallback((change) => { | ||
const viewport = typeof change === 'function' ? change(viewportState.viewport) : change; | ||
setViewportState(context, { ...viewportState, enabled: true, viewport }); | ||
setFixtureStateViewport(context, viewport); | ||
setViewportFixtureState(context, viewport); | ||
}, [context, viewportState]); | ||
@@ -65,5 +62,5 @@ } | ||
const rendererCore = getMethodsOf('rendererCore'); | ||
const fixtureState = rendererCore.getFixtureState(); | ||
return fixtureState.viewport | ||
? { ...viewportState, enabled: true, viewport: fixtureState.viewport } | ||
const viewport = rendererCore.getFixtureState('viewport'); | ||
return viewport | ||
? { ...viewportState, enabled: true, viewport } | ||
: viewportState; | ||
@@ -76,9 +73,6 @@ } | ||
} | ||
function setFixtureStateViewport(context, viewport) { | ||
function setViewportFixtureState(context, viewport) { | ||
const { getMethodsOf } = context; | ||
const rendererCore = getMethodsOf('rendererCore'); | ||
rendererCore.setFixtureState(fixtureState => ({ | ||
...fixtureState, | ||
viewport, | ||
})); | ||
rendererCore.setFixtureState('viewport', viewport); | ||
} |
@@ -1,3 +0,4 @@ | ||
import { Dispatch, ReactNode, SetStateAction } from 'react'; | ||
import { ResponsiveDevice, ResponsiveViewport } from '../spec.js'; | ||
import React, { Dispatch, ReactNode, SetStateAction } from 'react'; | ||
import { Viewport } from 'react-cosmos-core'; | ||
import { ResponsiveDevice } from '../spec.js'; | ||
type Props = { | ||
@@ -7,9 +8,8 @@ children?: ReactNode; | ||
enabled: boolean; | ||
viewport: ResponsiveViewport; | ||
viewport: Viewport; | ||
scaled: boolean; | ||
validFixtureSelected: boolean; | ||
setViewport: Dispatch<SetStateAction<ResponsiveViewport>>; | ||
setViewport: Dispatch<SetStateAction<Viewport>>; | ||
setScaled: (scaled: boolean) => unknown; | ||
}; | ||
export declare function ResponsivePreview({ children, devices, enabled, viewport, scaled, validFixtureSelected, setViewport, setScaled, }: Props): JSX.Element; | ||
export declare function ResponsivePreview({ children, devices, enabled, viewport, scaled, setViewport, setScaled, }: Props): React.JSX.Element; | ||
export {}; |
@@ -6,5 +6,5 @@ import { isEqual } from 'lodash-es'; | ||
import { grey64, grey8 } from '../../../style/colors.js'; | ||
import { Header } from './Header.js'; | ||
import { ResponsiveHeader } from './ResponsiveHeader.js'; | ||
import { getStyles, getViewportScaleFactor, responsivePreviewBorderWidth, responsivePreviewPadding, stretchStyle, } from './style.js'; | ||
export function ResponsivePreview({ children, devices, enabled, viewport, scaled, validFixtureSelected, setViewport, setScaled, }) { | ||
export function ResponsivePreview({ children, devices, enabled, viewport, scaled, setViewport, setScaled, }) { | ||
const [container, setContainer] = useState(null); | ||
@@ -57,3 +57,3 @@ const onWidthChange = useCallback((width) => setViewport(prevViewport => ({ ...prevViewport, width })), [setViewport]); | ||
// component instances are preserved and the transition is seamless. | ||
if (!validFixtureSelected || !enabled || !container) { | ||
if (!enabled || !container) { | ||
return (React.createElement(Container, null, | ||
@@ -68,3 +68,3 @@ React.createElement("div", { key: "preview", ref: handleContainerRef, style: stretchStyle }, | ||
return (React.createElement(Container, null, | ||
React.createElement(Header, { devices: devices, selectedViewport: viewport, scaleFactor: scaleFactor, scaled: scaled, selectViewport: setViewport, toggleScale: () => setScaled(!scaled) }), | ||
React.createElement(ResponsiveHeader, { devices: devices, selectedViewport: viewport, scaleFactor: scaleFactor, scaled: scaled, selectViewport: setViewport, toggleScale: () => setScaled(!scaled) }), | ||
React.createElement("div", { key: "preview", ref: handleContainerRef, style: maskContainerStyle }, | ||
@@ -71,0 +71,0 @@ React.createElement("div", { style: padContainerStyle }, |
@@ -1,2 +0,2 @@ | ||
import { ResponsiveViewport } from '../spec.js'; | ||
import { Viewport } from 'react-cosmos-core'; | ||
export declare const responsivePreviewPadding: { | ||
@@ -14,4 +14,4 @@ top: number; | ||
export declare function getStyles({ container, viewport, scaled, }: { | ||
container: ResponsiveViewport; | ||
viewport: ResponsiveViewport; | ||
container: Viewport; | ||
viewport: Viewport; | ||
scaled: boolean; | ||
@@ -46,2 +46,2 @@ }): { | ||
}; | ||
export declare function getViewportScaleFactor(viewport: ResponsiveViewport, container: ResponsiveViewport): number; | ||
export declare function getViewportScaleFactor(viewport: Viewport, container: Viewport): number; |
@@ -1,14 +0,11 @@ | ||
import { FixtureState } from 'react-cosmos-core'; | ||
import { Viewport } from 'react-cosmos-core'; | ||
import { PluginContext } from 'react-plugin'; | ||
import { StorageSpec } from '../Storage/spec.js'; | ||
import { ResponsivePreviewSpec, ResponsiveViewport } from './spec.js'; | ||
import { ResponsivePreviewSpec } from './spec.js'; | ||
export type ResponsivePreviewContext = PluginContext<ResponsivePreviewSpec>; | ||
export type StorageMethods = StorageSpec['methods']; | ||
export type FixtureStateWithViewport = FixtureState & { | ||
viewport?: ResponsiveViewport; | ||
}; | ||
export type ViewportState = { | ||
enabled: boolean; | ||
scaled: boolean; | ||
viewport: ResponsiveViewport; | ||
viewport: Viewport; | ||
}; | ||
@@ -15,0 +12,0 @@ export declare const DEFAULT_DEVICES: { |
export const DEFAULT_DEVICES = [ | ||
{ label: 'iPhone 5/SE', width: 320, height: 568 }, | ||
{ label: 'iPhone 6/7/8', width: 375, height: 667 }, | ||
{ label: 'iPhone 6/7/8 Plus', width: 414, height: 736 }, | ||
{ label: 'iPhone X', width: 375, height: 812 }, | ||
{ label: 'iPad', width: 768, height: 1024 }, | ||
{ label: 'iPad Pro', width: 1024, height: 1366 }, | ||
{ label: 'iPhone SE', width: 375, height: 667 }, | ||
{ label: 'iPhone 12/13/14', width: 390, height: 844 }, | ||
{ label: 'iPhone 14 Pro', width: 393, height: 852 }, | ||
{ label: 'iPhone 14 Plus', width: 428, height: 926 }, | ||
{ label: 'iPhone 14 Pro Max', width: 430, height: 932 }, | ||
{ label: 'iPad mini', width: 744, height: 1133 }, | ||
{ label: 'iPad', width: 820, height: 1180 }, | ||
{ label: 'iPad Pro 11"', width: 834, height: 1194 }, | ||
{ label: 'iPad Pro 12.9"', width: 1024, height: 1366 }, | ||
{ label: 'Small laptop', width: 1280, height: 720 }, | ||
{ label: 'Laptop', width: 1366, height: 768 }, | ||
{ label: 'Large laptop', width: 1600, height: 900 }, | ||
{ label: 'Full HD', width: 1920, height: 1080 }, | ||
{ label: 'Quad HD', width: 2560, height: 1440 }, | ||
{ label: 'Large laptop', width: 1536, height: 864 }, | ||
{ label: '1080p', width: 1920, height: 1080 }, | ||
{ label: '1440p', width: 2560, height: 1440 }, | ||
]; | ||
@@ -18,3 +21,3 @@ export const VIEWPORT_STORAGE_KEY = 'responsiveViewportState'; | ||
scaled: true, | ||
viewport: { width: 320, height: 568 }, | ||
viewport: { width: 375, height: 667 }, | ||
}; |
@@ -1,6 +0,3 @@ | ||
export type ResponsiveViewport = { | ||
width: number; | ||
height: number; | ||
}; | ||
export type ResponsiveDevice = ResponsiveViewport & { | ||
import { Viewport } from 'react-cosmos-core'; | ||
export type ResponsiveDevice = Viewport & { | ||
label: string; | ||
@@ -7,0 +4,0 @@ }; |
@@ -0,1 +1,2 @@ | ||
import React from 'react'; | ||
type Props = { | ||
@@ -5,3 +6,3 @@ selected: boolean; | ||
}; | ||
export declare function ToggleButton({ selected, onToggle }: Props): JSX.Element; | ||
export declare function ToggleButton({ selected, onToggle }: Props): React.JSX.Element; | ||
export {}; |
@@ -1,9 +0,7 @@ | ||
import { FixtureId } from 'react-cosmos-core'; | ||
import React from 'react'; | ||
type Props = { | ||
selectedFixtureId: FixtureId | null; | ||
rendererConnected: boolean; | ||
validFixtureSelected: boolean; | ||
globalActionOrder: string[]; | ||
}; | ||
export declare function GlobalHeader({ selectedFixtureId, rendererConnected, validFixtureSelected, globalActionOrder, }: Props): JSX.Element; | ||
export declare function GlobalHeader({ rendererConnected, globalActionOrder }: Props): React.JSX.Element; | ||
export {}; |
import React from 'react'; | ||
import { ArraySlot } from 'react-plugin'; | ||
import styled from 'styled-components'; | ||
import { grey176, grey32, white10 } from '../../style/colors.js'; | ||
export function GlobalHeader({ selectedFixtureId, rendererConnected, validFixtureSelected, globalActionOrder, }) { | ||
function getMessage() { | ||
if (!rendererConnected) { | ||
return React.createElement(Message, null, "Waiting for renderer..."); | ||
} | ||
if (!selectedFixtureId) { | ||
return React.createElement(Message, null, "No fixture selected"); | ||
} | ||
if (!validFixtureSelected) { | ||
return React.createElement(Message, null, "Fixture not found"); | ||
} | ||
return null; | ||
} | ||
import { grey32, white10 } from '../../style/colors.js'; | ||
export function GlobalHeader({ rendererConnected, globalActionOrder }) { | ||
return (React.createElement(Container, null, | ||
React.createElement(Left, null), | ||
getMessage(), | ||
React.createElement(Right, null, rendererConnected && (React.createElement(ArraySlot, { name: "globalAction", plugOrder: globalActionOrder }))))); | ||
@@ -52,9 +39,1 @@ } | ||
`; | ||
const Message = styled.div ` | ||
padding: 4px; | ||
color: ${grey176}; | ||
line-height: 24px; | ||
white-space: nowrap; | ||
text-overflow: ellipsis; | ||
overflow: hidden; | ||
`; |
import React from 'react'; | ||
import { createFixtureTree, flattenFixtureTree } from 'react-cosmos-core'; | ||
import { createPlugin } from 'react-plugin'; | ||
import { useWelcomeDismiss } from './HomeOverlay/welcomeDismiss.js'; | ||
import { Root } from './Root.js'; | ||
import { isNavOpen, openNav } from './navOpen.js'; | ||
@@ -8,3 +10,2 @@ import { getNavWidthApi } from './navWidth.js'; | ||
import { getPanelWidthApi } from './panelWidth.js'; | ||
import { Root } from './Root.js'; | ||
const { onLoad, plug, register } = createPlugin({ | ||
@@ -45,10 +46,10 @@ name: 'root', | ||
const onTogglePanel = useOpenPanel(pluginContext); | ||
const welcomeDismiss = useWelcomeDismiss(pluginContext); | ||
const { storageCacheReady } = getState(); | ||
if (!storageCacheReady) { | ||
return (React.createElement(Root, { storageCacheReady: false, fixtureItems: [], selectedFixtureId: null, rendererConnected: false, validFixtureSelected: false, fixtureState: {}, navOpen: false, panelOpen: false, navWidth: 0, panelWidth: 0, sidePanelRowOrder: [], globalActionOrder: [], globalOrder: [], navRowOrder: [], fixtureActionOrder: [], rendererActionOrder: [], onToggleNav: () => { }, onTogglePanel: () => { }, onFixtureSelect: () => { }, onFixtureClose: () => { }, onFixtureStateChange: () => { }, setNavWidth: () => { }, setPanelWidth: () => { } })); | ||
} | ||
if (!storageCacheReady) | ||
return null; | ||
const { navWidth, setNavWidth } = getNavWidthApi(pluginContext); | ||
const { panelWidth, setPanelWidth } = getPanelWidthApi(pluginContext); | ||
const { sidePanelRowOrder, globalActionOrder, globalOrder, navRowOrder, fixtureActionOrder, rendererActionOrder, } = getConfig(); | ||
return (React.createElement(Root, { storageCacheReady: true, fixtureItems: fixtureItems, selectedFixtureId: router.getSelectedFixtureId(), rendererConnected: rendererCore.isRendererConnected(), validFixtureSelected: rendererCore.isValidFixtureSelected(), fixtureState: rendererCore.getFixtureState(), navOpen: isNavOpen(pluginContext), panelOpen: isPanelOpen(pluginContext), navWidth: navWidth, panelWidth: panelWidth, sidePanelRowOrder: sidePanelRowOrder, globalActionOrder: globalActionOrder, globalOrder: globalOrder, navRowOrder: navRowOrder, fixtureActionOrder: fixtureActionOrder, rendererActionOrder: rendererActionOrder, onToggleNav: onToggleNav, onTogglePanel: onTogglePanel, onFixtureSelect: router.selectFixture, onFixtureClose: router.unselectFixture, onFixtureStateChange: rendererCore.setFixtureState, setNavWidth: setNavWidth, setPanelWidth: setPanelWidth })); | ||
return (React.createElement(Root, { fixtureItems: fixtureItems, selectedFixtureId: router.getSelectedFixtureId(), rendererConnected: rendererCore.isRendererConnected(), getFixtureState: rendererCore.getFixtureState, setFixtureState: rendererCore.setFixtureState, navOpen: isNavOpen(pluginContext), panelOpen: isPanelOpen(pluginContext), navWidth: navWidth, panelWidth: panelWidth, sidePanelRowOrder: sidePanelRowOrder, globalActionOrder: globalActionOrder, globalOrder: globalOrder, navRowOrder: navRowOrder, fixtureActionOrder: fixtureActionOrder, rendererActionOrder: rendererActionOrder, onToggleNav: onToggleNav, onTogglePanel: onTogglePanel, onReloadRenderer: rendererCore.reloadRenderer, onCloseFixture: router.unselectFixture, setNavWidth: setNavWidth, setPanelWidth: setPanelWidth, welcomeDismissed: welcomeDismiss.isWelcomeDismissed(), onDismissWelcome: welcomeDismiss.onDismissWelcome, onShowWelcome: welcomeDismiss.onShowWelcome })); | ||
}); | ||
@@ -55,0 +56,0 @@ export { register }; |
export const NAV_OPEN_STORAGE_KEY = 'navOpen'; | ||
const NAV_OPEN_DEFAULT = true; | ||
const NAV_OPEN_DEFAULT = window.innerWidth >= 640; | ||
export function isNavOpen(context) { | ||
@@ -4,0 +4,0 @@ const storage = context.getMethodsOf('storage'); |
export const PANEL_OPEN_STORAGE_KEY = 'sidePanelOpen'; | ||
const PANEL_OPEN_DEFAULT = true; | ||
const PANEL_OPEN_DEFAULT = window.innerWidth >= 960; | ||
export function isPanelOpen(context) { | ||
const { getMethodsOf } = context; | ||
const rendererCore = getMethodsOf('rendererCore'); | ||
if (!rendererCore.isValidFixtureSelected()) { | ||
return false; | ||
} | ||
const storage = context.getMethodsOf('storage'); | ||
@@ -10,0 +5,0 @@ const open = storage.getItem(PANEL_OPEN_STORAGE_KEY); |
@@ -12,3 +12,3 @@ import React from 'react'; | ||
onTogglePanel: () => unknown; | ||
onFixtureSelect: (fixtureId: FixtureId) => unknown; | ||
onReloadRenderer: () => unknown; | ||
onClose: () => unknown; | ||
@@ -15,0 +15,0 @@ }; |
@@ -9,6 +9,5 @@ import { isEqual } from 'lodash-es'; | ||
import { grey176, grey32, white10 } from '../../style/colors.js'; | ||
export const RendererHeader = React.memo(function RendererHeader({ fixtureItems, fixtureId, navOpen, panelOpen, fixtureActionOrder, rendererActionOrder, onOpenNav, onTogglePanel, onFixtureSelect, onClose, }) { | ||
export const RendererHeader = React.memo(function RendererHeader({ fixtureItems, fixtureId, navOpen, panelOpen, fixtureActionOrder, rendererActionOrder, onOpenNav, onTogglePanel, onReloadRenderer, onClose, }) { | ||
const fixtureItem = findFixtureItemById(fixtureItems, fixtureId); | ||
const slotProps = React.useMemo(() => ({ fixtureId }), [fixtureId]); | ||
const onReload = React.useCallback(() => onFixtureSelect(fixtureId), [fixtureId, onFixtureSelect]); | ||
return (React.createElement(Container, null, | ||
@@ -20,4 +19,4 @@ React.createElement(Left, null, | ||
React.createElement(IconButton32, { icon: React.createElement(XCircleIcon, null), title: "Close fixture", onClick: onClose }), | ||
React.createElement(IconButton32, { icon: React.createElement(RotateCcwIcon, null), title: "Reload fixture", onClick: onReload }), | ||
React.createElement(FixtureActionSlot, { slotProps: slotProps, plugOrder: fixtureActionOrder })), | ||
React.createElement(IconButton32, { icon: React.createElement(RotateCcwIcon, null), title: "Reload fixture", onClick: onReloadRenderer }), | ||
fixtureItem && (React.createElement(FixtureActionSlotContainer, { fixtureActionOrder: fixtureActionOrder, fixtureItem: fixtureItem }))), | ||
fixtureItem && React.createElement(FixtureName, null, getFixtureName(fixtureItem)), | ||
@@ -28,4 +27,13 @@ React.createElement(Right, null, | ||
}); | ||
function FixtureActionSlotContainer({ fixtureActionOrder, fixtureItem, }) { | ||
const slotProps = React.useMemo(() => ({ fixtureItem }), [fixtureItem]); | ||
return (React.createElement(FixtureActionSlot, { slotProps: slotProps, plugOrder: fixtureActionOrder })); | ||
} | ||
function findFixtureItemById(fixtureItems, fixtureId) { | ||
return fixtureItems.find(fixtureItem => isEqual(fixtureItem.fixtureId, fixtureId)); | ||
if (fixtureId.name) { | ||
return fixtureItems.find(fixtureItem => isEqual(fixtureItem.fixtureId, fixtureId)); | ||
} | ||
// When a multi fixture is selected by path only, the first of its named | ||
// fixtures will be selected. | ||
return fixtureItems.find(fixtureItem => fixtureItem.fixtureId.path === fixtureId.path); | ||
} | ||
@@ -32,0 +40,0 @@ function getFixtureName({ name, fileName }) { |
@@ -1,9 +0,10 @@ | ||
import { FixtureId, FixtureState, FlatFixtureTreeItem, StateUpdater } from 'react-cosmos-core'; | ||
import React from 'react'; | ||
import { FixtureId, FlatFixtureTreeItem } from 'react-cosmos-core'; | ||
import { GetFixtureState, SetFixtureStateByName } from '../RendererCore/spec.js'; | ||
type Props = { | ||
storageCacheReady: boolean; | ||
fixtureItems: FlatFixtureTreeItem[]; | ||
selectedFixtureId: FixtureId | null; | ||
rendererConnected: boolean; | ||
validFixtureSelected: boolean; | ||
fixtureState: FixtureState; | ||
getFixtureState: GetFixtureState; | ||
setFixtureState: SetFixtureStateByName; | ||
navOpen: boolean; | ||
@@ -21,9 +22,11 @@ panelOpen: boolean; | ||
onTogglePanel: () => unknown; | ||
onFixtureSelect: (fixtureId: FixtureId) => unknown; | ||
onFixtureClose: () => unknown; | ||
onFixtureStateChange: (stateUpdater: StateUpdater<FixtureState>) => void; | ||
onReloadRenderer: () => unknown; | ||
onCloseFixture: () => unknown; | ||
setNavWidth: (width: number) => unknown; | ||
setPanelWidth: (width: number) => unknown; | ||
welcomeDismissed: boolean; | ||
onDismissWelcome: () => unknown; | ||
onShowWelcome: () => unknown; | ||
}; | ||
export declare function Root({ storageCacheReady, fixtureItems, selectedFixtureId, rendererConnected, validFixtureSelected, fixtureState, navOpen, panelOpen, navWidth, panelWidth, sidePanelRowOrder, globalActionOrder, globalOrder, navRowOrder, fixtureActionOrder, rendererActionOrder, onToggleNav, onTogglePanel, onFixtureSelect, onFixtureClose, onFixtureStateChange, setNavWidth, setPanelWidth, }: Props): JSX.Element; | ||
export declare function Root({ fixtureItems, selectedFixtureId, rendererConnected, getFixtureState, setFixtureState, navOpen, panelOpen, navWidth, panelWidth, sidePanelRowOrder, globalActionOrder, globalOrder, navRowOrder, fixtureActionOrder, rendererActionOrder, onToggleNav, onTogglePanel, onReloadRenderer, onCloseFixture, setNavWidth, setPanelWidth, welcomeDismissed, onDismissWelcome, onShowWelcome, }: Props): React.JSX.Element; | ||
export {}; |
@@ -8,5 +8,6 @@ import React from 'react'; | ||
import { GlobalHeader } from './GlobalHeader.js'; | ||
import { HomeOverlay } from './HomeOverlay/HomeOverlay.js'; | ||
import { RendererHeader } from './RendererHeader.js'; | ||
import { SidePanel } from './SidePanel.js'; | ||
export function Root({ storageCacheReady, fixtureItems, selectedFixtureId, rendererConnected, validFixtureSelected, fixtureState, navOpen, panelOpen, navWidth, panelWidth, sidePanelRowOrder, globalActionOrder, globalOrder, navRowOrder, fixtureActionOrder, rendererActionOrder, onToggleNav, onTogglePanel, onFixtureSelect, onFixtureClose, onFixtureStateChange, setNavWidth, setPanelWidth, }) { | ||
export function Root({ fixtureItems, selectedFixtureId, rendererConnected, getFixtureState, setFixtureState, navOpen, panelOpen, navWidth, panelWidth, sidePanelRowOrder, globalActionOrder, globalOrder, navRowOrder, fixtureActionOrder, rendererActionOrder, onToggleNav, onTogglePanel, onReloadRenderer, onCloseFixture, setNavWidth, setPanelWidth, welcomeDismissed, onDismissWelcome, onShowWelcome, }) { | ||
const navDrag = useDrag({ | ||
@@ -21,6 +22,3 @@ value: navWidth, | ||
}); | ||
if (!storageCacheReady) { | ||
return React.createElement(Container, null); | ||
} | ||
const showNav = rendererConnected && (navOpen || !validFixtureSelected); | ||
const showNav = navOpen || !selectedFixtureId; | ||
const dragging = navDrag.dragging || panelDrag.dragging; | ||
@@ -30,17 +28,18 @@ // z-indexes are set here on purpose to show the layer hierarchy at a glance | ||
showNav && (React.createElement(Draggable, { style: { width: navWidth, zIndex: 2 } }, | ||
React.createElement(Nav, null, rendererConnected && (React.createElement(NavRowSlot, { slotProps: { onCloseNav: onToggleNav }, plugOrder: navRowOrder }))), | ||
React.createElement(Nav, null, | ||
React.createElement(NavRowSlot, { slotProps: { onCloseNav: onToggleNav }, plugOrder: navRowOrder })), | ||
navDrag.dragging && React.createElement(DragOverlay, null), | ||
React.createElement(NavDragHandle, { ref: navDrag.dragElRef }))), | ||
React.createElement(MainContainer, { key: "main", style: { zIndex: 1 } }, | ||
!validFixtureSelected && (React.createElement(GlobalHeader, { selectedFixtureId: selectedFixtureId, rendererConnected: rendererConnected, validFixtureSelected: validFixtureSelected, globalActionOrder: globalActionOrder })), | ||
!selectedFixtureId && (React.createElement(GlobalHeader, { rendererConnected: rendererConnected, globalActionOrder: globalActionOrder })), | ||
React.createElement(RendererContainer, { key: "rendererContainer" }, | ||
selectedFixtureId && validFixtureSelected && (React.createElement(RendererHeader, { fixtureItems: fixtureItems, fixtureId: selectedFixtureId, navOpen: navOpen, panelOpen: panelOpen, fixtureActionOrder: fixtureActionOrder, rendererActionOrder: rendererActionOrder, onOpenNav: onToggleNav, onTogglePanel: onTogglePanel, onFixtureSelect: onFixtureSelect, onClose: onFixtureClose })), | ||
selectedFixtureId && (React.createElement(RendererHeader, { fixtureItems: fixtureItems, fixtureId: selectedFixtureId, navOpen: navOpen, panelOpen: panelOpen, fixtureActionOrder: fixtureActionOrder, rendererActionOrder: rendererActionOrder, onOpenNav: onToggleNav, onTogglePanel: onTogglePanel, onReloadRenderer: onReloadRenderer, onClose: onCloseFixture })), | ||
React.createElement(RendererBody, { key: "rendererBody" }, | ||
React.createElement(Slot, { name: "rendererPreview" }), | ||
dragging && React.createElement(DragOverlay, null), | ||
panelOpen && selectedFixtureId && (React.createElement(ControlPanelContainer, { style: { width: panelWidth, zIndex: 3 } }, | ||
React.createElement(SidePanel, { fixtureId: selectedFixtureId, fixtureState: fixtureState, sidePanelRowOrder: sidePanelRowOrder, onFixtureStateChange: onFixtureStateChange }), | ||
selectedFixtureId && panelOpen && (React.createElement(ControlPanelContainer, { style: { width: panelWidth, zIndex: 3 } }, | ||
React.createElement(SidePanel, { fixtureId: selectedFixtureId, getFixtureState: getFixtureState, setFixtureState: setFixtureState, sidePanelRowOrder: sidePanelRowOrder }), | ||
panelDrag.dragging && React.createElement(DragOverlay, null), | ||
React.createElement(PanelDragHandle, { ref: panelDrag.dragElRef })))), | ||
React.createElement(Slot, { name: "contentOverlay" }))), | ||
!selectedFixtureId && (React.createElement(HomeOverlay, { welcomeDismissed: welcomeDismissed, onDismissWelcome: onDismissWelcome, onShowWelcome: onShowWelcome })))), | ||
React.createElement("div", { style: { zIndex: 4 } }, | ||
@@ -47,0 +46,0 @@ React.createElement(ArraySlot, { name: "global", plugOrder: globalOrder })))); |
import React from 'react'; | ||
import { FixtureId, FixtureState, StateUpdater } from 'react-cosmos-core'; | ||
import { FixtureId } from 'react-cosmos-core'; | ||
import { GetFixtureState, SetFixtureStateByName } from '../RendererCore/spec.js'; | ||
type Props = { | ||
fixtureId: FixtureId; | ||
fixtureState: FixtureState; | ||
onFixtureStateChange: (stateUpdater: StateUpdater<FixtureState>) => void; | ||
getFixtureState: GetFixtureState; | ||
setFixtureState: SetFixtureStateByName; | ||
sidePanelRowOrder: string[]; | ||
@@ -8,0 +9,0 @@ }; |
@@ -5,4 +5,4 @@ import React from 'react'; | ||
import { grey32 } from '../../style/colors.js'; | ||
export const SidePanel = React.memo(function SidePanel({ fixtureId, fixtureState, onFixtureStateChange, sidePanelRowOrder, }) { | ||
const slotProps = React.useMemo(() => ({ fixtureId, fixtureState, onFixtureStateChange }), [fixtureId, fixtureState, onFixtureStateChange]); | ||
export const SidePanel = React.memo(function SidePanel({ fixtureId, getFixtureState, setFixtureState, sidePanelRowOrder, }) { | ||
const slotProps = React.useMemo(() => ({ fixtureId, getFixtureState, setFixtureState }), [fixtureId, getFixtureState, setFixtureState]); | ||
return (React.createElement(Container, null, | ||
@@ -9,0 +9,0 @@ React.createElement(Content, null, |
@@ -0,1 +1,2 @@ | ||
import React from 'react'; | ||
type Props = { | ||
@@ -6,3 +7,3 @@ disabled?: boolean; | ||
}; | ||
export declare function ToggleNavButton({ disabled, selected, onToggle }: Props): JSX.Element; | ||
export declare function ToggleNavButton({ disabled, selected, onToggle }: Props): React.JSX.Element; | ||
export {}; |
@@ -6,2 +6,5 @@ import { isEqual } from 'lodash-es'; | ||
name: 'router', | ||
defaultConfig: { | ||
initialFixtureId: null, | ||
}, | ||
initialState: { | ||
@@ -17,4 +20,8 @@ urlParams: {}, | ||
onLoad(context => { | ||
const { setState } = context; | ||
const { getConfig, setState } = context; | ||
setState({ urlParams: getUrlParams() }); | ||
const { initialFixtureId } = getConfig(); | ||
if (initialFixtureId) { | ||
selectFixture(context, initialFixtureId); | ||
} | ||
return subscribeToLocationChanges((urlParams) => { | ||
@@ -25,3 +32,3 @@ const { fixtureId } = context.getState().urlParams; | ||
if (fixtureChanged) { | ||
emitFixtureChangeEvent(context); | ||
emitFixtureChangeEvent(context, true); | ||
} | ||
@@ -47,14 +54,26 @@ }); | ||
const urlParamsEqual = isEqual(nextUrlParams, urlParams); | ||
context.setState({ urlParams: nextUrlParams }, () => { | ||
// Setting identical url params is considered a "reset" request | ||
if (fixtureChanged || urlParamsEqual) { | ||
emitFixtureChangeEvent(context); | ||
} | ||
if (!urlParamsEqual) { | ||
if (urlParamsEqual) { | ||
// Setting identical URL params can be considered a "reset" request, but | ||
// this will only re-render the fixture if the renderer implements an | ||
// auto-incrementing render key in its state | ||
emitFixtureChangeEvent(context, false); | ||
} | ||
else { | ||
context.setState({ urlParams: nextUrlParams }, () => { | ||
pushUrlParams(context.getState().urlParams); | ||
} | ||
}); | ||
emitFixtureChangeEvent(context, fixtureChanged); | ||
}); | ||
} | ||
} | ||
function emitFixtureChangeEvent(context) { | ||
context.emit('fixtureChange', getSelectedFixtureId(context)); | ||
function emitFixtureChangeEvent(context, fixtureChanged) { | ||
const fixtureId = getSelectedFixtureId(context); | ||
if (!fixtureId) { | ||
context.emit('fixtureUnselect'); | ||
} | ||
else if (fixtureChanged) { | ||
context.emit('fixtureSelect', fixtureId); | ||
} | ||
else { | ||
context.emit('fixtureReselect', fixtureId); | ||
} | ||
} |
@@ -1,6 +0,9 @@ | ||
import { FixtureId, PlaygroundUrlParams } from 'react-cosmos-core'; | ||
import { FixtureId, PlaygroundParams } from 'react-cosmos-core'; | ||
export type RouterSpec = { | ||
name: 'router'; | ||
config: { | ||
initialFixtureId: null | FixtureId; | ||
}; | ||
state: { | ||
urlParams: PlaygroundUrlParams; | ||
urlParams: PlaygroundParams; | ||
}; | ||
@@ -13,4 +16,6 @@ methods: { | ||
events: { | ||
fixtureChange(fixtureId: null | FixtureId): void; | ||
fixtureSelect(fixtureId: FixtureId): void; | ||
fixtureReselect(fixtureId: FixtureId): void; | ||
fixtureUnselect(): void; | ||
}; | ||
}; |
@@ -16,8 +16,5 @@ import React, { useCallback, useMemo } from 'react'; | ||
...fixtureState, | ||
controls: { | ||
...fixtureState.controls, | ||
[controlName]: { | ||
...control, | ||
currentValue: updatedValues[controlName], | ||
}, | ||
[controlName]: { | ||
...control, | ||
currentValue: updatedValues[controlName], | ||
}, | ||
@@ -24,0 +21,0 @@ })); |
@@ -5,4 +5,4 @@ import { PluginContext } from 'react-plugin'; | ||
export declare function useTreeExpansionStorage(pluginContext: PluginContext<StandardControlSpec>): { | ||
expansion: TreeExpansion; | ||
expansion: {}; | ||
setExpansion: (newTreeExpansion: TreeExpansion) => void; | ||
}; |
import { FixtureId, FixtureTreeNode } from 'react-cosmos-core'; | ||
export declare function recordContainsFixtureId(fixtureIds: Record<string, FixtureId>, fixtureId: FixtureId): boolean; | ||
export declare function nodeContainsFixtureId({ data, children }: FixtureTreeNode, fixtureId: FixtureId): boolean; | ||
export declare function fixtureTreeNodeContainsFixtureId({ data, children }: FixtureTreeNode, fixtureId: FixtureId): boolean; |
@@ -1,12 +0,7 @@ | ||
import { isEqual } from 'lodash-es'; | ||
export function recordContainsFixtureId(fixtureIds, fixtureId) { | ||
return Object.keys(fixtureIds).some(fixtureName => isEqual(fixtureIds[fixtureName], fixtureId)); | ||
} | ||
export function nodeContainsFixtureId({ data, children }, fixtureId) { | ||
if (data.type === 'fixture') | ||
return isEqual(data.fixtureId, fixtureId); | ||
if (data.type === 'multiFixture') | ||
return recordContainsFixtureId(data.fixtureIds, fixtureId); | ||
export function fixtureTreeNodeContainsFixtureId({ data, children }, fixtureId) { | ||
if (data.type === 'fixture' || data.type === 'multiFixture') { | ||
return data.path === fixtureId.path; | ||
} | ||
return (children !== undefined && | ||
Object.keys(children).some(childName => nodeContainsFixtureId(children[childName], fixtureId))); | ||
Object.keys(children).some(childName => fixtureTreeNodeContainsFixtureId(children[childName], fixtureId))); | ||
} |
@@ -1,5 +0,6 @@ | ||
import { PlaygroundUrlParams } from 'react-cosmos-core'; | ||
export declare function getUrlParams(): PlaygroundUrlParams; | ||
export declare function pushUrlParams(urlParams: PlaygroundUrlParams): void; | ||
export declare function subscribeToLocationChanges(userHandler: (urlParams: PlaygroundUrlParams) => unknown): () => void; | ||
export declare function createRelativePlaygroundUrl(urlParams: PlaygroundUrlParams): string; | ||
import { PlaygroundParams } from 'react-cosmos-core'; | ||
export declare function getUrlParams(): PlaygroundParams; | ||
export declare function pushUrlParams(urlParams: PlaygroundParams): void; | ||
export declare function subscribeToLocationChanges(userHandler: (urlParams: PlaygroundParams) => unknown): () => void; | ||
export declare function createRelativePlaygroundUrl(urlParams: PlaygroundParams): string; | ||
export declare function createRelativeUrlWithQuery(query: string): string; |
@@ -1,7 +0,7 @@ | ||
import { parsePlaygroundUrlQuery, stringifyPlaygroundUrlQuery, } from 'react-cosmos-core'; | ||
import { buildPlaygroundQueryString, parsePlaygroundQueryString, } from 'react-cosmos-core'; | ||
export function getUrlParams() { | ||
return parsePlaygroundUrlQuery(location.search); | ||
return parsePlaygroundQueryString(location.search); | ||
} | ||
export function pushUrlParams(urlParams) { | ||
const query = stringifyPlaygroundUrlQuery(urlParams); | ||
const query = buildPlaygroundQueryString(urlParams); | ||
// Refresh page completely when pushState isn't supported | ||
@@ -25,10 +25,10 @@ if (!history.pushState) { | ||
export function createRelativePlaygroundUrl(urlParams) { | ||
const query = stringifyPlaygroundUrlQuery(urlParams); | ||
const query = buildPlaygroundQueryString(urlParams); | ||
return createRelativeUrlWithQuery(query); | ||
} | ||
function createRelativeUrlWithQuery(query) { | ||
export function createRelativeUrlWithQuery(query) { | ||
// NOTE: "./" is used to return to the home URL. Passing an empty string | ||
// doesn't do anything. And passing "/" doesn't work if Cosmos is not hosted | ||
// at root (sub)domain level. | ||
return query.length > 0 ? `?${query}` : './'; | ||
return query || './'; | ||
} |
@@ -1,4 +0,5 @@ | ||
import { FixtureStateControls } from 'react-cosmos-core'; | ||
import React from 'react'; | ||
import { ControlsFixtureState } from 'react-cosmos-core'; | ||
export type ControlActionSlotProps = { | ||
controls: FixtureStateControls; | ||
controls: ControlsFixtureState; | ||
}; | ||
@@ -9,3 +10,3 @@ type Props = { | ||
}; | ||
export declare function ControlActionSlot({ slotProps, plugOrder }: Props): JSX.Element; | ||
export declare function ControlActionSlot({ slotProps, plugOrder }: Props): React.JSX.Element; | ||
export {}; |
@@ -1,6 +0,7 @@ | ||
import { FixtureState, FixtureStateControl, StateUpdater } from 'react-cosmos-core'; | ||
export type ControlSlotProps<TControl extends FixtureStateControl> = { | ||
import React from 'react'; | ||
import { ControlFixtureState, ControlsFixtureState, FixtureStateUpdater } from 'react-cosmos-core'; | ||
export type ControlSlotProps<TControl extends ControlFixtureState> = { | ||
controlName: string; | ||
control: TControl; | ||
onFixtureStateChange: (stateUpdater: StateUpdater<FixtureState>) => void; | ||
onFixtureStateChange: (updater: FixtureStateUpdater<ControlsFixtureState>) => void; | ||
}; | ||
@@ -10,3 +11,3 @@ type Props = { | ||
}; | ||
export declare function ControlSlot({ slotProps }: Props): JSX.Element; | ||
export declare function ControlSlot({ slotProps }: Props): React.JSX.Element; | ||
export {}; |
@@ -1,4 +0,5 @@ | ||
import { FixtureId } from 'react-cosmos-core'; | ||
import React from 'react'; | ||
import { FlatFixtureTreeItem } from 'react-cosmos-core'; | ||
export type FixtureActionSlotProps = { | ||
fixtureId: FixtureId; | ||
fixtureItem: FlatFixtureTreeItem; | ||
}; | ||
@@ -9,3 +10,3 @@ type Props = { | ||
}; | ||
export declare function FixtureActionSlot({ slotProps, plugOrder }: Props): JSX.Element; | ||
export declare function FixtureActionSlot({ slotProps, plugOrder }: Props): React.JSX.Element; | ||
export {}; |
@@ -0,1 +1,2 @@ | ||
import React from 'react'; | ||
export type NavRowSlotProps = { | ||
@@ -8,3 +9,3 @@ onCloseNav: () => unknown; | ||
}; | ||
export declare function NavRowSlot({ slotProps, plugOrder }: Props): JSX.Element; | ||
export declare function NavRowSlot({ slotProps, plugOrder }: Props): React.JSX.Element; | ||
export {}; |
@@ -0,1 +1,2 @@ | ||
import React from 'react'; | ||
import { FixtureId } from 'react-cosmos-core'; | ||
@@ -9,3 +10,3 @@ export type RendererActionSlotProps = { | ||
}; | ||
export declare function RendererActionSlot({ slotProps, plugOrder }: Props): JSX.Element; | ||
export declare function RendererActionSlot({ slotProps, plugOrder }: Props): React.JSX.Element; | ||
export {}; |
@@ -1,6 +0,8 @@ | ||
import { FixtureId, FixtureState, StateUpdater } from 'react-cosmos-core'; | ||
import React from 'react'; | ||
import { FixtureId } from 'react-cosmos-core'; | ||
import { GetFixtureState, SetFixtureStateByName } from '../plugins/RendererCore/spec.js'; | ||
export type SidePanelRowSlotProps = { | ||
fixtureId: FixtureId; | ||
fixtureState: FixtureState; | ||
onFixtureStateChange: (stateUpdater: StateUpdater<FixtureState>) => void; | ||
getFixtureState: GetFixtureState; | ||
setFixtureState: SetFixtureStateByName; | ||
}; | ||
@@ -11,3 +13,3 @@ type Props = { | ||
}; | ||
export declare function SidePanelRowSlot({ slotProps, plugOrder }: Props): JSX.Element; | ||
export declare function SidePanelRowSlot({ slotProps, plugOrder }: Props): React.JSX.Element; | ||
export {}; |
@@ -1,2 +0,2 @@ | ||
import { ReactNode } from 'react'; | ||
import React, { ReactNode } from 'react'; | ||
import { FixtureStatePrimitiveValue, FixtureStateUnserializableValue, PrimitiveData } from 'react-cosmos-core'; | ||
@@ -15,3 +15,3 @@ type LeafValue = FixtureStatePrimitiveValue | FixtureStateUnserializableValue; | ||
}; | ||
export declare function ValueInputSlot({ children, slotProps }: Props): JSX.Element; | ||
export declare function ValueInputSlot({ children, slotProps }: Props): React.JSX.Element; | ||
export {}; |
@@ -33,14 +33,16 @@ /// <reference types="jest" /> | ||
isDevServerOn(): boolean; | ||
getWebRendererUrl(): string | null; | ||
}; | ||
export declare function getRendererCoreMethods(): { | ||
getRendererUrl(): string | null; | ||
getConnectedRendererIds(): string[]; | ||
getPrimaryRendererId(): string | null; | ||
getFixtures(): import("react-cosmos-core").FixtureList; | ||
getFixtureState(): import("react-cosmos-core").FixtureState; | ||
isRendererConnected(): boolean; | ||
isValidFixtureSelected(): boolean; | ||
setFixtureState(stateUpdater: import("react-cosmos-core").StateUpdater<import("react-cosmos-core").FixtureState>): void; | ||
reloadRenderer(): void; | ||
selectPrimaryRenderer(primaryRendererId: string): void; | ||
receiveResponse(msg: import("react-cosmos-core").MessageType): void; | ||
getAllFixtureState(): import("react-cosmos-core").FixtureState; | ||
getFixtureState: import("../plugins/RendererCore/spec.js").GetFixtureState; | ||
setFixtureState: import("../plugins/RendererCore/spec.js").SetFixtureStateByName; | ||
setGlobalFixtureState<T>(name: string, state: T): void; | ||
}; | ||
@@ -53,3 +55,2 @@ export declare function getNotificationsMethods(): { | ||
export declare function getRendererPreviewMethods(): { | ||
getUrlStatus(): import("../plugins/RendererPreview/spec.js").UrlStatus; | ||
getRuntimeStatus(): import("../plugins/RendererPreview/spec.js").RuntimeStatus; | ||
@@ -76,3 +77,2 @@ }; | ||
isDevServerOn: jest.Mock<any, any, any> | ((context: import("react-plugin").PluginContext<CoreSpec>) => boolean); | ||
getWebRendererUrl: jest.Mock<any, any, any> | ((context: import("react-plugin").PluginContext<CoreSpec>) => string | null); | ||
}; | ||
@@ -83,15 +83,18 @@ export declare function mockMessageHandler(methods?: MethodsOf<MessageHandlerSpec>): { | ||
export declare function mockRendererCore(methods?: MethodsOf<RendererCoreSpec>): { | ||
getRendererUrl: jest.Mock<any, any, any> | ((context: import("react-plugin").PluginContext<RendererCoreSpec>) => string | null); | ||
getConnectedRendererIds: jest.Mock<any, any, any> | ((context: import("react-plugin").PluginContext<RendererCoreSpec>) => string[]); | ||
getPrimaryRendererId: jest.Mock<any, any, any> | ((context: import("react-plugin").PluginContext<RendererCoreSpec>) => string | null); | ||
getFixtures: jest.Mock<any, any, any> | ((context: import("react-plugin").PluginContext<RendererCoreSpec>) => import("react-cosmos-core").FixtureList); | ||
getFixtureState: jest.Mock<any, any, any> | ((context: import("react-plugin").PluginContext<RendererCoreSpec>) => import("react-cosmos-core").FixtureState); | ||
isRendererConnected: jest.Mock<any, any, any> | ((context: import("react-plugin").PluginContext<RendererCoreSpec>) => boolean); | ||
isValidFixtureSelected: jest.Mock<any, any, any> | ((context: import("react-plugin").PluginContext<RendererCoreSpec>) => boolean); | ||
setFixtureState: jest.Mock<any, any, any> | ((context: import("react-plugin").PluginContext<RendererCoreSpec>, stateUpdater: import("react-cosmos-core").StateUpdater<import("react-cosmos-core").FixtureState>) => void); | ||
reloadRenderer: jest.Mock<any, any, any> | ((context: import("react-plugin").PluginContext<RendererCoreSpec>) => void); | ||
selectPrimaryRenderer: jest.Mock<any, any, any> | ((context: import("react-plugin").PluginContext<RendererCoreSpec>, primaryRendererId: string) => void); | ||
receiveResponse: jest.Mock<any, any, any> | ((context: import("react-plugin").PluginContext<RendererCoreSpec>, msg: import("react-cosmos-core").MessageType) => void); | ||
getAllFixtureState: jest.Mock<any, any, any> | ((context: import("react-plugin").PluginContext<RendererCoreSpec>) => import("react-cosmos-core").FixtureState); | ||
getFixtureState: jest.Mock<any, any, any> | ((context: import("react-plugin").PluginContext<RendererCoreSpec>, name: string) => unknown); | ||
setFixtureState: jest.Mock<any, any, any> | ((context: import("react-plugin").PluginContext<RendererCoreSpec>, name: string, change: unknown) => void); | ||
setGlobalFixtureState: jest.Mock<any, any, any> | ((context: import("react-plugin").PluginContext<RendererCoreSpec>, name: string, state: unknown) => void); | ||
}; | ||
export declare function mockRendererPreview(methods?: MethodsOf<RendererPreviewSpec>): { | ||
getUrlStatus: jest.Mock<any, any, any> | ((context: import("react-plugin").PluginContext<RendererPreviewSpec>) => import("../plugins/RendererPreview/spec.js").UrlStatus); | ||
getRuntimeStatus: jest.Mock<any, any, any> | ((context: import("react-plugin").PluginContext<RendererPreviewSpec>) => import("../plugins/RendererPreview/spec.js").RuntimeStatus); | ||
getUrlStatus: jest.Mock<any, any, any>; | ||
}; | ||
@@ -110,3 +113,5 @@ export declare function mockNotifications(methods?: MethodsOf<NotificationsSpec>): { | ||
export declare function onRouter(events?: EventsOf<RouterSpec>): { | ||
fixtureChange: jest.Mock<any, any, any> | import("ui-plugin/dist/types/PluginContextHandlers.js").PluginEventHandler<any, [fixtureId: import("react-cosmos-core").FixtureId | null]>; | ||
fixtureSelect: jest.Mock<any, any, any> | import("ui-plugin/dist/types/PluginContextHandlers.js").PluginEventHandler<any, [fixtureId: import("react-cosmos-core").FixtureId]>; | ||
fixtureReselect: jest.Mock<any, any, any> | import("ui-plugin/dist/types/PluginContextHandlers.js").PluginEventHandler<any, [fixtureId: import("react-cosmos-core").FixtureId]>; | ||
fixtureUnselect: jest.Mock<any, any, any> | import("ui-plugin/dist/types/PluginContextHandlers.js").PluginEventHandler<any, []>; | ||
}; | ||
@@ -113,0 +118,0 @@ export declare function onMessageHandler(events?: EventsOf<MessageHandlerSpec>): { |
@@ -57,3 +57,2 @@ import { getPluginContext, } from 'react-plugin'; | ||
isDevServerOn: jest.fn(), | ||
getWebRendererUrl: jest.fn(), | ||
...methods, | ||
@@ -74,11 +73,14 @@ }; | ||
const allMethods = { | ||
getRendererUrl: jest.fn(), | ||
getConnectedRendererIds: jest.fn(), | ||
getPrimaryRendererId: jest.fn(), | ||
getFixtures: jest.fn(), | ||
getFixtureState: jest.fn(), | ||
isRendererConnected: jest.fn(), | ||
isValidFixtureSelected: jest.fn(), | ||
setFixtureState: jest.fn(), | ||
reloadRenderer: jest.fn(), | ||
selectPrimaryRenderer: jest.fn(), | ||
receiveResponse: jest.fn(), | ||
getAllFixtureState: jest.fn(), | ||
getFixtureState: jest.fn(), | ||
setFixtureState: jest.fn(), | ||
setGlobalFixtureState: jest.fn(), | ||
...methods, | ||
@@ -118,3 +120,5 @@ }; | ||
const allEvents = { | ||
fixtureChange: jest.fn(), | ||
fixtureSelect: jest.fn(), | ||
fixtureReselect: jest.fn(), | ||
fixtureUnselect: jest.fn(), | ||
...events, | ||
@@ -121,0 +125,0 @@ }; |
{ | ||
"name": "react-cosmos-ui", | ||
"version": "6.0.0-canary.0f73dbd.0+0f73dbd", | ||
"version": "6.0.0-canary.10c9ae9.0+10c9ae9", | ||
"description": "React Cosmos UI", | ||
@@ -17,12 +17,12 @@ "repository": "https://github.com/react-cosmos/react-cosmos/tree/main/packages/react-cosmos-ui", | ||
"dependencies": { | ||
"lodash-es": "^4.17.21", | ||
"react-cosmos-core": "^6.0.0-canary.0f73dbd.0+0f73dbd" | ||
"lodash-es": "4.17.21", | ||
"react-cosmos-core": "6.0.0-canary.10c9ae9.0+10c9ae9" | ||
}, | ||
"devDependencies": { | ||
"fuzzaldrin-plus": "^0.6.0", | ||
"localforage": "^1.10.0", | ||
"react-plugin": "^3.0.0-alpha.4", | ||
"styled-components": "^5.3.8" | ||
"fuzzaldrin-plus": "0.6.0", | ||
"localforage": "1.10.0", | ||
"react-plugin": "3.0.0-alpha.4", | ||
"styled-components": "5.3.11" | ||
}, | ||
"gitHead": "0f73dbdeff46d2ddf4d85da71fdb41ea4df7322e" | ||
"gitHead": "10c9ae9ecc9886484f3a495f713fedef4cbfd8f6" | ||
} |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
389
10425
27
3
2898810
- Removedjs-base64@3.7.7(transitive)
- Removedreact-cosmos-core@6.2.0(transitive)
- Removedreact-is@18.3.1(transitive)
Updatedlodash-es@4.17.21