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
12 changes: 12 additions & 0 deletions compat/jsx-runtime.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export {
Fragment,
jsx,
jsxs,
jsxDEV,
jsxTemplate,
jsxAttr,
jsxEscape
} from 'preact/jsx-runtime';
import { CompatJSX } from './src/jsx';

export { CompatJSX as JSX };
121 changes: 121 additions & 0 deletions compat/src/dom.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import { Signalish } from '../../src/dom';

/**
* React-compatible SVG attributes available only in preact/compat.
* These camelCase attribute names are converted to their standard
* equivalents at runtime by preact/compat.
*/
export interface CompatSVGAttributes {
alignmentBaseline?: Signalish<
| 'auto'
| 'baseline'
| 'before-edge'
| 'text-before-edge'
| 'middle'
| 'central'
| 'after-edge'
| 'text-after-edge'
| 'ideographic'
| 'alphabetic'
| 'hanging'
| 'mathematical'
| 'inherit'
| undefined
>;
allowReorder?: Signalish<'no' | 'yes' | undefined>;
/** @deprecated See https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/arabic-form */
arabicForm?: Signalish<
'initial' | 'medial' | 'terminal' | 'isolated' | undefined
>;
baselineShift?: Signalish<number | string | undefined>;
capHeight?: Signalish<number | string | undefined>;
clipPath?: Signalish<string | undefined>;
clipRule?: Signalish<number | string | undefined>;
colorInterpolation?: Signalish<number | string | undefined>;
colorInterpolationFilters?: Signalish<
'auto' | 'sRGB' | 'linearRGB' | 'inherit' | undefined
>;
colorProfile?: Signalish<number | string | undefined>;
colorRendering?: Signalish<number | string | undefined>;
contentScriptType?: Signalish<number | string | undefined>;
contentStyleType?: Signalish<number | string | undefined>;
dominantBaseline?: Signalish<number | string | undefined>;
enableBackground?: Signalish<number | string | undefined>;
fillOpacity?: Signalish<number | string | undefined>;
fillRule?: Signalish<'nonzero' | 'evenodd' | 'inherit' | undefined>;
floodColor?: Signalish<number | string | undefined>;
floodOpacity?: Signalish<number | string | undefined>;
fontFamily?: Signalish<string | undefined>;
fontSize?: Signalish<number | string | undefined>;
fontSizeAdjust?: Signalish<number | string | undefined>;
fontStretch?: Signalish<number | string | undefined>;
fontStyle?: Signalish<number | string | undefined>;
fontVariant?: Signalish<number | string | undefined>;
fontWeight?: Signalish<number | string | undefined>;
glyphName?: Signalish<number | string | undefined>;
glyphOrientationHorizontal?: Signalish<number | string | undefined>;
glyphOrientationVertical?: Signalish<number | string | undefined>;
horizAdvX?: Signalish<number | string | undefined>;
horizOriginX?: Signalish<number | string | undefined>;
hrefLang?: Signalish<string | undefined>;
imageRendering?: Signalish<number | string | undefined>;
letterSpacing?: Signalish<number | string | undefined>;
lightingColor?: Signalish<number | string | undefined>;
markerEnd?: Signalish<string | undefined>;
markerMid?: Signalish<string | undefined>;
markerStart?: Signalish<string | undefined>;
overlinePosition?: Signalish<number | string | undefined>;
overlineThickness?: Signalish<number | string | undefined>;
paintOrder?: Signalish<number | string | undefined>;
panose1?: Signalish<number | string | undefined>;
pointerEvents?: Signalish<number | string | undefined>;
renderingIntent?: Signalish<number | string | undefined>;
repeatCount?: Signalish<number | string | undefined>;
repeatDur?: Signalish<number | string | undefined>;
shapeRendering?: Signalish<number | string | undefined>;
stopColor?: Signalish<string | undefined>;
stopOpacity?: Signalish<number | string | undefined>;
strikethroughPosition?: Signalish<number | string | undefined>;
strikethroughThickness?: Signalish<number | string | undefined>;
strokeDasharray?: Signalish<string | number | undefined>;
strokeDashoffset?: Signalish<string | number | undefined>;
strokeLinecap?: Signalish<
'butt' | 'round' | 'square' | 'inherit' | undefined
>;
strokeLinejoin?: Signalish<
'miter' | 'round' | 'bevel' | 'inherit' | undefined
>;
strokeMiterlimit?: Signalish<string | number | undefined>;
strokeOpacity?: Signalish<number | string | undefined>;
strokeWidth?: Signalish<number | string | undefined>;
textAnchor?: Signalish<string | undefined>;
textDecoration?: Signalish<number | string | undefined>;
textRendering?: Signalish<number | string | undefined>;
transformOrigin?: Signalish<string | undefined>;
underlinePosition?: Signalish<number | string | undefined>;
underlineThickness?: Signalish<number | string | undefined>;
unicodeBidi?: Signalish<number | string | undefined>;
unicodeRange?: Signalish<number | string | undefined>;
unitsPerEm?: Signalish<number | string | undefined>;
vAlphabetic?: Signalish<number | string | undefined>;
vectorEffect?: Signalish<number | string | undefined>;
vertAdvY?: Signalish<number | string | undefined>;
vertOriginX?: Signalish<number | string | undefined>;
vertOriginY?: Signalish<number | string | undefined>;
vHanging?: Signalish<number | string | undefined>;
vIdeographic?: Signalish<number | string | undefined>;
vMathematical?: Signalish<number | string | undefined>;
wordSpacing?: Signalish<number | string | undefined>;
writingMode?: Signalish<number | string | undefined>;
xHeight?: Signalish<number | string | undefined>;
xlinkActuate?: Signalish<string | undefined>;
xlinkArcrole?: Signalish<string | undefined>;
xlinkHref?: Signalish<string | undefined>;
xlinkRole?: Signalish<string | undefined>;
xlinkShow?: Signalish<string | undefined>;
xlinkTitle?: Signalish<string | undefined>;
xlinkType?: Signalish<string | undefined>;
xmlBase?: Signalish<string | undefined>;
xmlLang?: Signalish<string | undefined>;
xmlSpace?: Signalish<string | undefined>;
}
25 changes: 17 additions & 8 deletions compat/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import * as _hooks from '../../hooks';
import * as preact1 from 'preact';
import { JSXInternal } from '../../src/jsx';
import * as _Suspense from './suspense';
import { CompatSVGAttributes } from './dom';
import { CompatJSX } from './jsx';

declare namespace preact {
export interface FunctionComponent<P = {}> {
Expand Down Expand Up @@ -102,9 +104,10 @@ declare namespace preact {
// export default React;
export = React;
export as namespace React;

declare namespace React {
// Export JSX
export import JSX = JSXInternal;
// Export JSX with React-compatible camelCase SVG attributes
export import JSX = CompatJSX;

// Hooks
export import CreateHandle = _hooks.CreateHandle;
Expand Down Expand Up @@ -175,14 +178,12 @@ declare namespace React {
export import DetailedHTMLProps = preact1.DetailedHTMLProps;
export import CSSProperties = preact1.CSSProperties;

// Compat SVG attributes include React-compatible camelCase properties
// that are not available in core Preact
export interface SVGProps<T extends EventTarget>
extends preact1.SVGAttributes<T>,
preact1.ClassAttributes<T> {}

interface SVGAttributes<T extends EventTarget = SVGElement>
extends preact1.SVGAttributes<T> {}

interface ReactSVG extends JSXInternal.IntrinsicSVGElements {}
preact1.ClassAttributes<T>,
CompatSVGAttributes {}

export import AriaAttributes = preact1.AriaAttributes;

Expand Down Expand Up @@ -432,3 +433,11 @@ declare namespace React {
): void;
export const unstable_now: () => number;
}

// Augment global JSX namespace when preact/compat is imported
declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace JSX {
interface IntrinsicElements extends CompatJSX.IntrinsicElements {}
}
}
109 changes: 109 additions & 0 deletions compat/src/jsx.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import * as preact from 'preact';
import { JSXInternal } from '../../src/jsx';
import { CompatSVGAttributes } from './dom';

type Defaultize<Props, Defaults> =
// Distribute over unions
Props extends any // Make any properties included in Default optional
? Partial<Pick<Props, Extract<keyof Props, keyof Defaults>>> & // Include the remaining properties from Props
Pick<Props, Exclude<keyof Props, keyof Defaults>>
: never;

// Compat SVGAttributes includes React-compatible camelCase properties
interface SVGAttributes<T extends EventTarget = SVGElement>
extends preact.SVGAttributes<T>,
CompatSVGAttributes {}

// Compat IntrinsicSVGElements uses SVGAttributes with camelCase properties
interface CompatIntrinsicSVGElements {
svg: SVGAttributes<SVGSVGElement>;
animate: SVGAttributes<SVGAnimateElement>;
circle: SVGAttributes<SVGCircleElement>;
animateMotion: SVGAttributes<SVGAnimateMotionElement>;
animateTransform: SVGAttributes<SVGAnimateTransformElement>;
clipPath: SVGAttributes<SVGClipPathElement>;
defs: SVGAttributes<SVGDefsElement>;
desc: SVGAttributes<SVGDescElement>;
ellipse: SVGAttributes<SVGEllipseElement>;
feBlend: SVGAttributes<SVGFEBlendElement>;
feColorMatrix: SVGAttributes<SVGFEColorMatrixElement>;
feComponentTransfer: SVGAttributes<SVGFEComponentTransferElement>;
feComposite: SVGAttributes<SVGFECompositeElement>;
feConvolveMatrix: SVGAttributes<SVGFEConvolveMatrixElement>;
feDiffuseLighting: SVGAttributes<SVGFEDiffuseLightingElement>;
feDisplacementMap: SVGAttributes<SVGFEDisplacementMapElement>;
feDistantLight: SVGAttributes<SVGFEDistantLightElement>;
feDropShadow: SVGAttributes<SVGFEDropShadowElement>;
feFlood: SVGAttributes<SVGFEFloodElement>;
feFuncA: SVGAttributes<SVGFEFuncAElement>;
feFuncB: SVGAttributes<SVGFEFuncBElement>;
feFuncG: SVGAttributes<SVGFEFuncGElement>;
feFuncR: SVGAttributes<SVGFEFuncRElement>;
feGaussianBlur: SVGAttributes<SVGFEGaussianBlurElement>;
feImage: SVGAttributes<SVGFEImageElement>;
feMerge: SVGAttributes<SVGFEMergeElement>;
feMergeNode: SVGAttributes<SVGFEMergeNodeElement>;
feMorphology: SVGAttributes<SVGFEMorphologyElement>;
feOffset: SVGAttributes<SVGFEOffsetElement>;
fePointLight: SVGAttributes<SVGFEPointLightElement>;
feSpecularLighting: SVGAttributes<SVGFESpecularLightingElement>;
feSpotLight: SVGAttributes<SVGFESpotLightElement>;
feTile: SVGAttributes<SVGFETileElement>;
feTurbulence: SVGAttributes<SVGFETurbulenceElement>;
filter: SVGAttributes<SVGFilterElement>;
foreignObject: SVGAttributes<SVGForeignObjectElement>;
g: SVGAttributes<SVGGElement>;
image: SVGAttributes<SVGImageElement>;
line: SVGAttributes<SVGLineElement>;
linearGradient: SVGAttributes<SVGLinearGradientElement>;
marker: SVGAttributes<SVGMarkerElement>;
mask: SVGAttributes<SVGMaskElement>;
metadata: SVGAttributes<SVGMetadataElement>;
mpath: SVGAttributes<SVGMPathElement>;
path: SVGAttributes<SVGPathElement>;
pattern: SVGAttributes<SVGPatternElement>;
polygon: SVGAttributes<SVGPolygonElement>;
polyline: SVGAttributes<SVGPolylineElement>;
radialGradient: SVGAttributes<SVGRadialGradientElement>;
rect: SVGAttributes<SVGRectElement>;
set: SVGAttributes<SVGSetElement>;
stop: SVGAttributes<SVGStopElement>;
switch: SVGAttributes<SVGSwitchElement>;
symbol: SVGAttributes<SVGSymbolElement>;
text: SVGAttributes<SVGTextElement>;
textPath: SVGAttributes<SVGTextPathElement>;
tspan: SVGAttributes<SVGTSpanElement>;
use: SVGAttributes<SVGUseElement>;
view: SVGAttributes<SVGViewElement>;
}

export namespace CompatJSX {
export type LibraryManagedAttributes<Component, Props> = Component extends {
defaultProps: infer Defaults;
}
? Defaultize<Props, Defaults>
: Props;

export type IntrinsicAttributes = JSXInternal.IntrinsicAttributes;

export type ElementType<P = any> = JSXInternal.ElementType<P>;

export type Element = JSXInternal.Element;

export type ElementClass = JSXInternal.ElementClass;

export type ElementAttributesProperty = JSXInternal.ElementAttributesProperty;

export type ElementChildrenAttribute = JSXInternal.ElementChildrenAttribute;

export interface IntrinsicSVGElements extends CompatIntrinsicSVGElements {}

export type IntrinsicMathMLElements = JSXInternal.IntrinsicMathMLElements;

export type IntrinsicHTMLElements = JSXInternal.IntrinsicHTMLElements;

export interface IntrinsicElements
extends IntrinsicSVGElements,
IntrinsicMathMLElements,
IntrinsicHTMLElements {}
}
24 changes: 24 additions & 0 deletions compat/test/ts/dom-attributes.test-d.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/* eslint-disable no-unused-vars */
import React from '../../src';

// SVG camelCase attributes should be available in preact/compat
// These are React-compatible and converted to kebab-case at runtime
const svgCasingTest = (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48">
<circle fill="blue" strokeWidth="2" cx="24" cy="24" r="20" />
</svg>
);

// Standard kebab-case SVG attributes should also work
const svgKebabCaseTest = (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48">
<circle fill="blue" stroke-width="2" cx="24" cy="24" r="20" />
</svg>
);

// More camelCase SVG attributes that should work in compat
const fillOpacityTest = <rect fillOpacity="0.5" />;
const stopColorTest = <stop stopColor="red" />;
const fontFamilyTest = <text fontFamily="Arial" />;
const strokeDasharrayTest = <path strokeDasharray="5,5" />;
const textAnchorTest = <text textAnchor="middle" />;
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,12 @@
"default": "./compat/server.browser.js"
},
"./compat/jsx-runtime": {
"types": "./jsx-runtime/src/index.d.ts",
"types": "./compat/jsx-runtime.d.ts",
"import": "./compat/jsx-runtime.mjs",
"require": "./compat/jsx-runtime.js"
},
"./compat/jsx-dev-runtime": {
"types": "./jsx-runtime/src/index.d.ts",
"types": "./compat/jsx-runtime.d.ts",
"import": "./compat/jsx-dev-runtime.mjs",
"require": "./compat/jsx-dev-runtime.js"
},
Expand Down
Loading