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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,5 @@ yarn-error.log*

# typescript
*.tsbuildinfo
next-env.d.ts
next-env.d.ts
.env*.local
1 change: 1 addition & 0 deletions next-env.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
/// <reference path="./.next/types/routes.d.ts" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/pages/api-reference/config/typescript for more information.
1 change: 1 addition & 0 deletions next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const nextConfig = {
// react-icons related bug https://linear.app/uniform/issue/UNI-1373/need-to-set-esmexternals-to-use-the-mesh-sdk-with-nextjs
esmExternals: false,
},
devIndicators: false,
};

export default nextConfig;
3,824 changes: 2,011 additions & 1,813 deletions package-lock.json

Large diffs are not rendered by default.

21 changes: 11 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@uniformdev/design-extensions",
"version": "20.36.1",
"version": "20.51.0",
"private": true,
"engines": {
"yarn": "please-use-npm",
Expand All @@ -19,15 +19,16 @@
"remove-propertyEditor": "tsx scripts/remove-property-editors.ts createAIEdit/afterAIEdit dex-color-palette-parameter dex-space-control-parameter dex-slider-control-parameter dex-segmented-control-parameter dex-token-selector-parameter"
},
"dependencies": {
"@uniformdev/canvas": "^20.36.1",
"@uniformdev/cli": "^20.36.1",
"@uniformdev/design-system": "^20.36.1",
"@uniformdev/mesh-edgehancer-sdk": "^20.36.1",
"@uniformdev/mesh-sdk-react": "^20.36.1",
"@uiw/react-color-sketch": "^2.9.6",
"@uniformdev/canvas": "^20.51.0",
"@uniformdev/cli": "^20.51.0",
"@uniformdev/design-system": "^20.51.0",
"@uniformdev/mesh-edgehancer-sdk": "^20.51.0",
"@uniformdev/mesh-sdk-react": "^20.51.0",
"@vercel/kv": "^2.0.0",
"classnames": "^2.5.1",
"color": "^4.2.3",
"next": "^15.1.11",
"next": "^15.5.12",
"react": "^18.2.0",
"react-colorful": "^5.6.1",
"react-dom": "^18.2.0",
Expand All @@ -53,7 +54,7 @@
"postcss": "^8.5.1",
"prettier": "3.5.1",
"tailwindcss": "^3.4.17",
"typescript": "^5.7.3",
"tsx": "^4.19.1"
"tsx": "^4.19.1",
"typescript": "^5.7.3"
}
}
}
41 changes: 41 additions & 0 deletions src/components/atoms/CustomHexConfigToggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React, { ChangeEvent, FC, useCallback } from 'react';
import { InputToggle } from '@uniformdev/design-system';
import { SetLocationValueDispatch } from '@uniformdev/mesh-sdk-react';

type CustomHexConfigToggleType = {
allowCustomHex?: MeshType.MeshDesignExtensionsParametersConfig['allowCustomHex'];
setCustomHexConfig: SetLocationValueDispatch<
Pick<MeshType.MeshDesignExtensionsParametersConfig, 'allowCustomHex'> | undefined,
Pick<MeshType.MeshDesignExtensionsParametersConfig, 'allowCustomHex'>
>;
};

const CustomHexConfigToggle: FC<CustomHexConfigToggleType> = ({ allowCustomHex, setCustomHexConfig }) => {
const handleToggle = useCallback(
(e: ChangeEvent<HTMLInputElement>) => {
const { checked } = e.target;
setCustomHexConfig(previousValue => {
if (checked) {
return { newValue: { ...previousValue, allowCustomHex: checked } };
} else {
const { allowCustomHex: _, ...restValues } = previousValue || {};
return { newValue: restValues };
}
});
},
[setCustomHexConfig]
);

return (
<InputToggle
label="Allow custom hex value"
caption="Allow users to specify a custom hex color value as an override."
name="allowCustomHex"
type="checkbox"
checked={Boolean(allowCustomHex)}
onChange={handleToggle}
/>
);
};

export default CustomHexConfigToggle;
56 changes: 52 additions & 4 deletions src/components/parameters/ColorPaletteParam.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import React, { FC, useCallback, useMemo, ChangeEvent } from 'react';
import React, { FC, useCallback, useMemo, useState, ChangeEvent } from 'react';
import classNames from 'classnames';
import { Callout } from '@uniformdev/design-system';
import { Button, Callout } from '@uniformdev/design-system';
import { SetLocationValueDispatch } from '@uniformdev/mesh-sdk-react';
import WithStylesVariables from '@/components/WithStylesVariables';
import { ALLOW_COLOR_GROUP } from '@/constants';
import { getGroupFromKey } from '@/utils';
import Sketch from '@uiw/react-color-sketch';

const CUSTOM_HEX_PREFIX = 'custom:';

type ColorPaletteParamProps = {
value?: string;
Expand All @@ -13,6 +16,7 @@ type ColorPaletteParamProps = {
colors: NonNullable<Type.KVStorage['colors']>;
selectedGroup?: string;
allowColors?: string[];
allowCustomHex?: boolean;
};

const ColorPaletteParam: FC<ColorPaletteParamProps> = ({
Expand All @@ -22,7 +26,12 @@ const ColorPaletteParam: FC<ColorPaletteParamProps> = ({
colors = [],
selectedGroup,
allowColors,
allowCustomHex,
}) => {
const isCustomHexValue = value?.startsWith(CUSTOM_HEX_PREFIX) ?? false;
const customHexColor = isCustomHexValue && value ? value.slice(CUSTOM_HEX_PREFIX.length) : undefined;
const [showPicker, setShowPicker] = useState(false);

const availableItems = useMemo(() => {
if (allowColors?.length) {
return colors.filter(({ colorKey }) => allowColors.includes(colorKey));
Expand All @@ -35,12 +44,27 @@ const ColorPaletteParam: FC<ColorPaletteParamProps> = ({
const handleSelection = useCallback(
(event: ChangeEvent<HTMLInputElement>) => {
const selected = event.currentTarget.value;
setShowPicker(false);
setValue(prev => ({ newValue: prev === selected ? null : selected }));
},
[setValue]
);

const handleClear = useCallback(() => setValue(() => ({ newValue: null })), [setValue]);
const handlePickerChange = useCallback(
(color: { hex: string }) => {
setValue(() => ({ newValue: `${CUSTOM_HEX_PREFIX}${color.hex}` }));
},
Comment on lines +53 to +56

Copilot AI Mar 9, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

handlePickerChange persists custom colors as a custom:#RRGGBB string. However, the property-editor JSON schema for color palette values currently uses z.enum(availableColorKeys), which will reject any custom: values. Please update the schema/handler to allow a custom:-prefixed hex value when allowCustomHex is enabled (e.g., a union of the enum and a hex-regex string), otherwise this new feature will break validation/AI edit output for color palette params.

Copilot uses AI. Check for mistakes.
[setValue]
);

const handleCustomSquareClick = useCallback(() => {
setShowPicker(prev => !prev);
}, []);

const handleClear = useCallback(() => {
setShowPicker(false);
setValue(() => ({ newValue: null }));
}, [setValue]);

if (!colors.length) {
return (
Expand Down Expand Up @@ -97,9 +121,33 @@ const ColorPaletteParam: FC<ColorPaletteParamProps> = ({
</label>
);
})}
{allowCustomHex && (
<button
type="button"
onClick={handleCustomSquareClick}
className={classNames(
'relative size-8 rounded-sm border cursor-pointer',
'hover:outline hover:outline-2 hover:outline-accent-dark-hover',
'flex items-center justify-center',
isCustomHexValue ? 'outline outline-2 outline-accent-dark border-white' : 'border-dashed border-gray-400'
)}
style={customHexColor ? { backgroundColor: customHexColor } : undefined}
title="Custom hex color"
>
{!customHexColor && <span className="text-sm font-bold text-gray-400">?</span>}
</button>
Comment thread
alexshyba marked this conversation as resolved.
)}
</div>
{allowCustomHex && showPicker && (
<div className="mt-2 flex flex-col items-start gap-1.5">
<Sketch color={customHexColor || '#000000'} onChange={handlePickerChange} />
<Button buttonType="secondary" size="sm" onClick={() => setShowPicker(false)}>
Accept
</Button>
Comment on lines +143 to +146

Copilot AI Mar 9, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "Accept" button currently only closes the picker, but the value is already being written on every Sketch onChange. This is misleading UX and makes it impossible to cancel accidental changes. Consider either renaming the button to "Close/Done" or staging the picked color in local state and only calling setValue when the user clicks "Accept".

Copilot uses AI. Check for mistakes.
</div>
)}
<div className="mt-2 flex items-center justify-between">
<span className="h-6 truncate">{value}</span>
<span className="h-6 truncate">{isCustomHexValue ? customHexColor : value}</span>
<button
// eslint-disable-next-line tailwindcss/no-custom-classname
className="text-action-destructive-default disabled:text-gray-400"
Expand Down
2 changes: 2 additions & 0 deletions src/pages/config/color-palette.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { FC, useCallback, useEffect, useMemo } from 'react';
import { LoadingOverlay, InputSelect } from '@uniformdev/design-system';
import { useMeshLocation } from '@uniformdev/mesh-sdk-react';
import CustomHexConfigToggle from '@/components/atoms/CustomHexConfigToggle';
import RequiredConfigToggle from '@/components/atoms/RequiredConfigToggle';
import ViewPortConfigToggle from '@/components/atoms/ViewPortConfigToggle';
import { ClearParameterValue } from '@/components/ClearParameterValue';
Expand Down Expand Up @@ -118,6 +119,7 @@ const DesignExtensionsParametersConfig: FC = () => {
)}
<ViewPortConfigToggle withViewPort={config?.withViewPort} setViewPortConfig={setConfig} changeDefaultValue />
<RequiredConfigToggle required={config?.required} setRequiredConfig={setConfig} />
<CustomHexConfigToggle allowCustomHex={config?.allowCustomHex} setCustomHexConfig={setConfig} />
<ColorConfigItemSection
filteredColors={filteredColors}
allowColors={allowColors}
Expand Down
2 changes: 2 additions & 0 deletions src/pages/editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const DesignExtensionsParametersEditor: FC = () => {
const {
required = false,
withViewPort = false,
allowCustomHex = false,
allowColors = [],
selectedTokenType,
allowTokens = [],
Expand Down Expand Up @@ -71,6 +72,7 @@ const DesignExtensionsParametersEditor: FC = () => {
selectedGroup={selectedGroup}
setValue={setValue as SetLocationValueDispatch<string | null, string | null>}
allowColors={allowColors}
allowCustomHex={allowCustomHex}
/>
</ReadOnlyContainer>
);
Expand Down
1 change: 1 addition & 0 deletions src/types/MeshType.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ declare namespace MeshType {
withViewPort?: boolean;
selectedGroup?: string;
selectedTokenType?: string;
allowCustomHex?: boolean;
allowColors?: string[];
allowDimensions?: string[];
allowTokens?: string[];
Expand Down