@stack-spot/citric-react 0.15.4 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"Card.d.ts","sourceRoot":"","sources":["../../src/components/Card.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAI1C,MAAM,WAAW,aAAc,SAAQ,eAAe;IACpD;;;;OAIG;IACH,GAAG,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,SAAS,GAAG,SAAS,CAAC;IACpE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,cAAc,CAAC,KAAK,IAAI,CAAC;IAC5D;;;;OAIG;IACH,IAAI,CAAC,EAAE,KAAK,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,CAAC;IACxD;;;;OAIG;IACH,OAAO,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;CACjC;AAED,MAAM,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,KAAK,CAAC,GAAG,aAAa,CAAA;AAE1E,eAAO,MAAM,IAAI,mEAAoF,SAAS,4CAS5G,CAAA"}
1
+ {"version":3,"file":"Card.d.ts","sourceRoot":"","sources":["../../src/components/Card.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAI1C,MAAM,WAAW,aAAc,SAAQ,eAAe;IACpD;;;;OAIG;IACH,GAAG,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,SAAS,GAAG,SAAS,CAAC;IACpE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,cAAc,CAAC,KAAK,IAAI,CAAC;IAC5D;;;;OAIG;IACH,IAAI,CAAC,EAAE,KAAK,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,CAAC;IACxD;;;;OAIG;IACH,OAAO,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;CACjC;AAED,MAAM,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,KAAK,CAAC,GAAG,aAAa,CAAA;AAE1E,eAAO,MAAM,IAAI,mEAAoF,SAAS,4CAU5G,CAAA"}
@@ -2,5 +2,5 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { listToClass } from '@stack-spot/portal-theme';
3
3
  import { withRef } from '../utils/react.js';
4
4
  import { CitricComponent } from './CitricComponent.js';
5
- export const Card = withRef(({ tag = 'div', onClick, size, bgLevel, className, children, ...props }) => (_jsx(CitricComponent, { tag: tag, component: "card", className: listToClass([onClick && 'clickable', size, bgLevel && `bg-${bgLevel}`, className]), ...props, children: children })));
5
+ export const Card = withRef(({ tag = 'div', onClick, size, bgLevel, className, children, ...props }) => (_jsx(CitricComponent, { tag: tag, component: "card", onClick: onClick, className: listToClass([onClick && 'clickable', size, bgLevel && `bg-${bgLevel}`, className]), ...props, children: children })));
6
6
  //# sourceMappingURL=Card.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Card.js","sourceRoot":"","sources":["../../src/components/Card.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AAEtD,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AA0BnD,MAAM,CAAC,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,EAAE,GAAG,GAAG,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAa,EAAE,EAAE,CAAC,CACjH,KAAC,eAAe,IACd,GAAG,EAAE,GAAG,EACR,SAAS,EAAC,MAAM,EAChB,SAAS,EAAE,WAAW,CAAC,CAAC,OAAO,IAAI,WAAW,EAAE,IAAI,EAAE,OAAO,IAAI,MAAM,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC,KACzF,KAAK,YAER,QAAQ,GACO,CACnB,CAAC,CAAA"}
1
+ {"version":3,"file":"Card.js","sourceRoot":"","sources":["../../src/components/Card.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AAEtD,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AA0BnD,MAAM,CAAC,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,EAAE,GAAG,GAAG,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAa,EAAE,EAAE,CAAC,CACjH,KAAC,eAAe,IACd,GAAG,EAAE,GAAG,EACR,SAAS,EAAC,MAAM,EAChB,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,WAAW,CAAC,CAAC,OAAO,IAAI,WAAW,EAAE,IAAI,EAAE,OAAO,IAAI,MAAM,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC,KACzF,KAAK,YAER,QAAQ,GACO,CACnB,CAAC,CAAA"}
@@ -0,0 +1,8 @@
1
+ import { WithStyleShortcuts } from '../types.js';
2
+ export interface BaseImageWithFallbackProps extends Pick<WithStyleShortcuts, 'w' | 'h' | 'radius' | 'bg'> {
3
+ fallback: React.ReactNode;
4
+ showLoading?: boolean;
5
+ }
6
+ export type ImageWithFallbackProps = JSX.IntrinsicElements['img'] & BaseImageWithFallbackProps;
7
+ export declare const ImageWithFallback: ({ onLoad, onError, className, style: ogStyle, fallback, showLoading, w, h, radius, bg, ...props }: ImageWithFallbackProps) => import("react/jsx-runtime").JSX.Element;
8
+ //# sourceMappingURL=ImageWithFallback.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ImageWithFallback.d.ts","sourceRoot":"","sources":["../../src/components/ImageWithFallback.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAA;AAI7C,MAAM,WAAW,0BAA2B,SAAQ,IAAI,CAAC,kBAAkB,EAAE,GAAG,GAAG,GAAG,GAAG,QAAQ,GAAG,IAAI,CAAC;IACvG,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,MAAM,sBAAsB,GAAG,GAAG,CAAC,iBAAiB,CAAC,KAAK,CAAC,GAAG,0BAA0B,CAAA;AAE9F,eAAO,MAAM,iBAAiB,GAC5B,mGAA0G,sBAAsB,4CAgCjI,CAAA"}
@@ -0,0 +1,27 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { listToClass } from '@stack-spot/portal-theme';
3
+ import { useEffect, useMemo, useState } from 'react';
4
+ import { getStyleFromProps } from '../utils/css.js';
5
+ import { Skeleton } from './Skeleton.js';
6
+ export const ImageWithFallback = ({ onLoad, onError, className, style: ogStyle, fallback, showLoading = true, w, h, radius, bg, ...props }) => {
7
+ const [state, setState] = useState(props.src ? 'loading' : 'error');
8
+ const isLoading = state === 'loading' && showLoading;
9
+ const style = useMemo(() => ({ ...getStyleFromProps({ w, h, radius, bg }), ...ogStyle }), [ogStyle, w, h, radius, bg]);
10
+ function handleLoad(e) {
11
+ if (state === 'loading')
12
+ setState('ready');
13
+ onLoad?.(e);
14
+ }
15
+ function handleError(e) {
16
+ setState('error');
17
+ onError?.(e);
18
+ }
19
+ useEffect(() => {
20
+ if (state !== 'loading')
21
+ setState(props.src ? 'loading' : 'error');
22
+ }, [props.src]);
23
+ if (state === 'error')
24
+ return _jsx("div", { className: listToClass([className, 'center']), style: style, children: fallback });
25
+ return _jsxs(_Fragment, { children: [isLoading && _jsx(Skeleton, { className: className, style: style }), _jsx("img", { onLoad: handleLoad, onError: handleError, style: { ...style, ...(isLoading ? { pointerEvents: 'none', position: 'absolute', opacity: 0 } : {}) }, "aria-hidden": isLoading, className: className, ...props })] });
26
+ };
27
+ //# sourceMappingURL=ImageWithFallback.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ImageWithFallback.js","sourceRoot":"","sources":["../../src/components/ImageWithFallback.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AACtD,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAEpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AASrC,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,GAAG,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,KAAK,EAA0B,EAChI,EAAE;IACF,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAgC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAA;IAClG,MAAM,SAAS,GAAG,KAAK,KAAK,SAAS,IAAI,WAAW,CAAA;IACpD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,GAAG,iBAAiB,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,OAAO,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,CAAA;IAEtH,SAAS,UAAU,CAAC,CAAgD;QAClE,IAAI,KAAK,KAAK,SAAS;YAAE,QAAQ,CAAC,OAAO,CAAC,CAAA;QAC1C,MAAM,EAAE,CAAC,CAAC,CAAC,CAAA;IACb,CAAC;IAED,SAAS,WAAW,CAAC,CAAgD;QACnE,QAAQ,CAAC,OAAO,CAAC,CAAA;QACjB,OAAO,EAAE,CAAC,CAAC,CAAC,CAAA;IACd,CAAC;IAED,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,KAAK,KAAK,SAAS;YAAE,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAA;IACpE,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAA;IAEf,IAAI,KAAK,KAAK,OAAO;QAAE,OAAO,cAAK,SAAS,EAAE,WAAW,CAAC,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,YAAG,QAAQ,GAAO,CAAA;IAChH,OAAO,8BACJ,SAAS,IAAI,KAAC,QAAQ,IAAC,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,GAAI,EAC9D,cACE,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,WAAW,EACpB,KAAK,EAAE,EAAE,GAAG,KAAK,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,iBACzF,SAAS,EACtB,SAAS,EAAE,SAAS,KAChB,KAAK,GACT,IACD,CAAA;AACL,CAAC,CAAA"}
@@ -32,15 +32,75 @@ export type CenterProps<T extends keyof HTMLTag> = HTMLTag[T] & BaseLayoutProps<
32
32
  export type RowProps<T extends keyof HTMLTag> = HTMLTag[T] & BaseRowProps<T>;
33
33
  export type ColumnProps<T extends keyof HTMLTag> = HTMLTag[T] & BaseColumnProps<T>;
34
34
  declare function _Center<T extends keyof HTMLTag = 'div'>({ tag, className, ...props }: CenterProps<T>): import("react").ReactElement<{
35
- style: Partial<import("react").CSSProperties>;
35
+ bg?: import("@stack-spot/portal-theme").ColorKey;
36
+ fg?: import("@stack-spot/portal-theme").ColorKey;
37
+ border?: import("@stack-spot/portal-theme").ColorKey;
38
+ radius?: import("@stack-spot/portal-theme").RadiusKey;
39
+ m?: import("@stack-spot/portal-theme").SpacingKey | import("@stack-spot/portal-theme").SpacingKey[] | string;
40
+ mt?: import("@stack-spot/portal-theme").SpacingKey | string;
41
+ mb?: import("@stack-spot/portal-theme").SpacingKey | string;
42
+ ml?: import("@stack-spot/portal-theme").SpacingKey | string;
43
+ mr?: import("@stack-spot/portal-theme").SpacingKey | string;
44
+ p?: import("@stack-spot/portal-theme").SpacingKey | import("@stack-spot/portal-theme").SpacingKey[] | string;
45
+ pt?: import("@stack-spot/portal-theme").SpacingKey | string;
46
+ pb?: import("@stack-spot/portal-theme").SpacingKey | string;
47
+ pl?: import("@stack-spot/portal-theme").SpacingKey | string;
48
+ pr?: import("@stack-spot/portal-theme").SpacingKey | string;
49
+ w?: string | number;
50
+ h?: string | number;
51
+ flex?: React.CSSProperties["flex"];
52
+ justifyContent?: React.CSSProperties["justifyContent"];
53
+ alignItems?: React.CSSProperties["alignItems"];
54
+ gap?: React.CSSProperties["gap"];
55
+ style: any;
36
56
  className: string;
37
57
  }, string | import("react").JSXElementConstructor<any>>;
38
58
  declare function _Row<T extends keyof HTMLTag = 'div'>({ tag, className, center, ...props }: RowProps<T>): import("react").ReactElement<{
39
- style: Partial<import("react").CSSProperties>;
59
+ bg?: import("@stack-spot/portal-theme").ColorKey;
60
+ fg?: import("@stack-spot/portal-theme").ColorKey;
61
+ border?: import("@stack-spot/portal-theme").ColorKey;
62
+ radius?: import("@stack-spot/portal-theme").RadiusKey;
63
+ m?: import("@stack-spot/portal-theme").SpacingKey | import("@stack-spot/portal-theme").SpacingKey[] | string;
64
+ mt?: import("@stack-spot/portal-theme").SpacingKey | string;
65
+ mb?: import("@stack-spot/portal-theme").SpacingKey | string;
66
+ ml?: import("@stack-spot/portal-theme").SpacingKey | string;
67
+ mr?: import("@stack-spot/portal-theme").SpacingKey | string;
68
+ p?: import("@stack-spot/portal-theme").SpacingKey | import("@stack-spot/portal-theme").SpacingKey[] | string;
69
+ pt?: import("@stack-spot/portal-theme").SpacingKey | string;
70
+ pb?: import("@stack-spot/portal-theme").SpacingKey | string;
71
+ pl?: import("@stack-spot/portal-theme").SpacingKey | string;
72
+ pr?: import("@stack-spot/portal-theme").SpacingKey | string;
73
+ w?: string | number;
74
+ h?: string | number;
75
+ flex?: React.CSSProperties["flex"];
76
+ justifyContent?: React.CSSProperties["justifyContent"];
77
+ alignItems?: React.CSSProperties["alignItems"];
78
+ gap?: React.CSSProperties["gap"];
79
+ style: any;
40
80
  className: string;
41
81
  }, string | import("react").JSXElementConstructor<any>>;
42
82
  declare function _Column<T extends keyof HTMLTag = 'div'>({ tag, className, center, ...props }: ColumnProps<T>): import("react").ReactElement<{
43
- style: Partial<import("react").CSSProperties>;
83
+ bg?: import("@stack-spot/portal-theme").ColorKey;
84
+ fg?: import("@stack-spot/portal-theme").ColorKey;
85
+ border?: import("@stack-spot/portal-theme").ColorKey;
86
+ radius?: import("@stack-spot/portal-theme").RadiusKey;
87
+ m?: import("@stack-spot/portal-theme").SpacingKey | import("@stack-spot/portal-theme").SpacingKey[] | string;
88
+ mt?: import("@stack-spot/portal-theme").SpacingKey | string;
89
+ mb?: import("@stack-spot/portal-theme").SpacingKey | string;
90
+ ml?: import("@stack-spot/portal-theme").SpacingKey | string;
91
+ mr?: import("@stack-spot/portal-theme").SpacingKey | string;
92
+ p?: import("@stack-spot/portal-theme").SpacingKey | import("@stack-spot/portal-theme").SpacingKey[] | string;
93
+ pt?: import("@stack-spot/portal-theme").SpacingKey | string;
94
+ pb?: import("@stack-spot/portal-theme").SpacingKey | string;
95
+ pl?: import("@stack-spot/portal-theme").SpacingKey | string;
96
+ pr?: import("@stack-spot/portal-theme").SpacingKey | string;
97
+ w?: string | number;
98
+ h?: string | number;
99
+ flex?: React.CSSProperties["flex"];
100
+ justifyContent?: React.CSSProperties["justifyContent"];
101
+ alignItems?: React.CSSProperties["alignItems"];
102
+ gap?: React.CSSProperties["gap"];
103
+ style: any;
44
104
  className: string;
45
105
  }, string | import("react").JSXElementConstructor<any>>;
46
106
  export declare const Center: typeof _Center;
@@ -1 +1 @@
1
- {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../src/components/layout.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAA;AAItD,eAAO,MAAM,MAAM;;;;CAIlB,CAAA;AAED,MAAM,WAAW,eAAe,CAAC,CAAC,SAAS,MAAM,OAAO,CAAE,SAAQ,kBAAkB;IAClF;;;;OAIG;IACH,GAAG,CAAC,EAAE,CAAC,CAAC;CACT;AAED,MAAM,WAAW,YAAY,CAAC,CAAC,SAAS,MAAM,OAAO,CAAE,SAAQ,eAAe,CAAC,CAAC,CAAC;IAC/E;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,eAAe,CAAC,CAAC,SAAS,MAAM,OAAO,CAAE,SAAQ,eAAe,CAAC,CAAC,CAAC;IAClF;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,MAAM,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAA;AAClF,MAAM,MAAM,QAAQ,CAAC,CAAC,SAAS,MAAM,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,CAAA;AAC5E,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,MAAM,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAA;AAElF,iBAAS,OAAO,CAAC,CAAC,SAAS,MAAM,OAAO,GAAG,KAAK,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,WAAW,CAAC,CAAC,CAAC;;;wDAE7F;AAED,iBAAS,IAAI,CAAC,CAAC,SAAS,MAAM,OAAO,GAAG,KAAK,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAC;;;wDAE/F;AAED,iBAAS,OAAO,CAAC,CAAC,SAAS,MAAM,OAAO,GAAG,KAAK,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE,EAAE,WAAW,CAAC,CAAC,CAAC;;;wDAErG;AAED,eAAO,MAAM,MAAM,gBAAmB,CAAA;AACtC,eAAO,MAAM,GAAG,aAAgB,CAAA;AAChC,eAAO,MAAM,MAAM,gBAAmB,CAAA"}
1
+ {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../src/components/layout.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAA;AAItD,eAAO,MAAM,MAAM;;;;CAIlB,CAAA;AAED,MAAM,WAAW,eAAe,CAAC,CAAC,SAAS,MAAM,OAAO,CAAE,SAAQ,kBAAkB;IAClF;;;;OAIG;IACH,GAAG,CAAC,EAAE,CAAC,CAAC;CACT;AAED,MAAM,WAAW,YAAY,CAAC,CAAC,SAAS,MAAM,OAAO,CAAE,SAAQ,eAAe,CAAC,CAAC,CAAC;IAC/E;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,eAAe,CAAC,CAAC,SAAS,MAAM,OAAO,CAAE,SAAQ,eAAe,CAAC,CAAC,CAAC;IAClF;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,MAAM,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAA;AAClF,MAAM,MAAM,QAAQ,CAAC,CAAC,SAAS,MAAM,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,CAAA;AAC5E,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,MAAM,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAA;AAElF,iBAAS,OAAO,CAAC,CAAC,SAAS,MAAM,OAAO,GAAG,KAAK,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,WAAW,CAAC,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;wDAE7F;AAED,iBAAS,IAAI,CAAC,CAAC,SAAS,MAAM,OAAO,GAAG,KAAK,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;wDAE/F;AAED,iBAAS,OAAO,CAAC,CAAC,SAAS,MAAM,OAAO,GAAG,KAAK,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE,EAAE,WAAW,CAAC,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;wDAErG;AAED,eAAO,MAAM,MAAM,gBAAmB,CAAA;AACtC,eAAO,MAAM,GAAG,aAAgB,CAAA;AAChC,eAAO,MAAM,MAAM,gBAAmB,CAAA"}
package/dist/index.d.ts CHANGED
@@ -21,6 +21,7 @@ export * from './components/Form.js';
21
21
  export * from './components/FormGroup.js';
22
22
  export * from './components/IconBox.js';
23
23
  export * from './components/ImageBox.js';
24
+ export * from './components/ImageWithFallback.js';
24
25
  export * from './components/Input.js';
25
26
  export * from './components/layout.js';
26
27
  export * from './components/Link.js';
@@ -49,5 +50,7 @@ export * from './components/Textarea.js';
49
50
  export * from './components/Tooltip.js';
50
51
  export * from './context/CitricProvider.js';
51
52
  export type { CitricController } from './types.js';
53
+ export * from './utils/checkbox.js';
54
+ export * from './utils/radio.js';
52
55
  export * from './utils/ValueController.js';
53
56
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAA;AACtC,cAAc,oBAAoB,CAAA;AAClC,cAAc,2BAA2B,CAAA;AACzC,cAAc,qBAAqB,CAAA;AACnC,cAAc,0BAA0B,CAAA;AACxC,cAAc,oBAAoB,CAAA;AAClC,cAAc,yBAAyB,CAAA;AACvC,cAAc,yBAAyB,CAAA;AACvC,cAAc,qBAAqB,CAAA;AACnC,cAAc,mBAAmB,CAAA;AACjC,cAAc,uBAAuB,CAAA;AACrC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,qBAAqB,CAAA;AACnC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,sBAAsB,CAAA;AACpC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,+BAA+B,CAAA;AAC7C,cAAc,uBAAuB,CAAA;AACrC,cAAc,yBAAyB,CAAA;AACvC,cAAc,mBAAmB,CAAA;AACjC,cAAc,wBAAwB,CAAA;AACtC,cAAc,sBAAsB,CAAA;AACpC,cAAc,uBAAuB,CAAA;AACrC,cAAc,oBAAoB,CAAA;AAClC,cAAc,qBAAqB,CAAA;AACnC,cAAc,mBAAmB,CAAA;AACjC,cAAc,0BAA0B,CAAA;AACxC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,sBAAsB,CAAA;AACpC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,yBAAyB,CAAA;AACvC,cAAc,0BAA0B,CAAA;AACxC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,yBAAyB,CAAA;AACvC,cAAc,qBAAqB,CAAA;AACnC,cAAc,qBAAqB,CAAA;AACnC,cAAc,wBAAwB,CAAA;AACtC,cAAc,uBAAuB,CAAA;AACrC,cAAc,qBAAqB,CAAA;AACnC,cAAc,yBAAyB,CAAA;AACvC,cAAc,sBAAsB,CAAA;AACpC,cAAc,qBAAqB,CAAA;AACnC,cAAc,oBAAoB,CAAA;AAClC,cAAc,mBAAmB,CAAA;AACjC,cAAc,iCAAiC,CAAA;AAC/C,cAAc,yBAAyB,CAAA;AACvC,cAAc,mBAAmB,CAAA;AACjC,cAAc,uBAAuB,CAAA;AACrC,cAAc,sBAAsB,CAAA;AACpC,cAAc,0BAA0B,CAAA;AACxC,YAAY,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAC/C,cAAc,yBAAyB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAA;AACtC,cAAc,oBAAoB,CAAA;AAClC,cAAc,2BAA2B,CAAA;AACzC,cAAc,qBAAqB,CAAA;AACnC,cAAc,0BAA0B,CAAA;AACxC,cAAc,oBAAoB,CAAA;AAClC,cAAc,yBAAyB,CAAA;AACvC,cAAc,yBAAyB,CAAA;AACvC,cAAc,qBAAqB,CAAA;AACnC,cAAc,mBAAmB,CAAA;AACjC,cAAc,uBAAuB,CAAA;AACrC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,qBAAqB,CAAA;AACnC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,sBAAsB,CAAA;AACpC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,+BAA+B,CAAA;AAC7C,cAAc,uBAAuB,CAAA;AACrC,cAAc,yBAAyB,CAAA;AACvC,cAAc,mBAAmB,CAAA;AACjC,cAAc,wBAAwB,CAAA;AACtC,cAAc,sBAAsB,CAAA;AACpC,cAAc,uBAAuB,CAAA;AACrC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,oBAAoB,CAAA;AAClC,cAAc,qBAAqB,CAAA;AACnC,cAAc,mBAAmB,CAAA;AACjC,cAAc,0BAA0B,CAAA;AACxC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,sBAAsB,CAAA;AACpC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,yBAAyB,CAAA;AACvC,cAAc,0BAA0B,CAAA;AACxC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,yBAAyB,CAAA;AACvC,cAAc,qBAAqB,CAAA;AACnC,cAAc,qBAAqB,CAAA;AACnC,cAAc,wBAAwB,CAAA;AACtC,cAAc,uBAAuB,CAAA;AACrC,cAAc,qBAAqB,CAAA;AACnC,cAAc,yBAAyB,CAAA;AACvC,cAAc,sBAAsB,CAAA;AACpC,cAAc,qBAAqB,CAAA;AACnC,cAAc,oBAAoB,CAAA;AAClC,cAAc,mBAAmB,CAAA;AACjC,cAAc,iCAAiC,CAAA;AAC/C,cAAc,yBAAyB,CAAA;AACvC,cAAc,mBAAmB,CAAA;AACjC,cAAc,uBAAuB,CAAA;AACrC,cAAc,sBAAsB,CAAA;AACpC,cAAc,0BAA0B,CAAA;AACxC,YAAY,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAC/C,cAAc,kBAAkB,CAAA;AAChC,cAAc,eAAe,CAAA;AAC7B,cAAc,yBAAyB,CAAA"}
package/dist/index.js CHANGED
@@ -21,6 +21,7 @@ export * from './components/Form.js';
21
21
  export * from './components/FormGroup.js';
22
22
  export * from './components/IconBox.js';
23
23
  export * from './components/ImageBox.js';
24
+ export * from './components/ImageWithFallback.js';
24
25
  export * from './components/Input.js';
25
26
  export * from './components/layout.js';
26
27
  export * from './components/Link.js';
@@ -48,5 +49,7 @@ export * from './components/Text.js';
48
49
  export * from './components/Textarea.js';
49
50
  export * from './components/Tooltip.js';
50
51
  export * from './context/CitricProvider.js';
52
+ export * from './utils/checkbox.js';
53
+ export * from './utils/radio.js';
51
54
  export * from './utils/ValueController.js';
52
55
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAA;AACtC,cAAc,oBAAoB,CAAA;AAClC,cAAc,2BAA2B,CAAA;AACzC,cAAc,qBAAqB,CAAA;AACnC,cAAc,0BAA0B,CAAA;AACxC,cAAc,oBAAoB,CAAA;AAClC,cAAc,yBAAyB,CAAA;AACvC,cAAc,yBAAyB,CAAA;AACvC,cAAc,qBAAqB,CAAA;AACnC,cAAc,mBAAmB,CAAA;AACjC,cAAc,uBAAuB,CAAA;AACrC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,qBAAqB,CAAA;AACnC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,sBAAsB,CAAA;AACpC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,+BAA+B,CAAA;AAC7C,cAAc,uBAAuB,CAAA;AACrC,cAAc,yBAAyB,CAAA;AACvC,cAAc,mBAAmB,CAAA;AACjC,cAAc,wBAAwB,CAAA;AACtC,cAAc,sBAAsB,CAAA;AACpC,cAAc,uBAAuB,CAAA;AACrC,cAAc,oBAAoB,CAAA;AAClC,cAAc,qBAAqB,CAAA;AACnC,cAAc,mBAAmB,CAAA;AACjC,cAAc,0BAA0B,CAAA;AACxC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,sBAAsB,CAAA;AACpC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,yBAAyB,CAAA;AACvC,cAAc,0BAA0B,CAAA;AACxC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,yBAAyB,CAAA;AACvC,cAAc,qBAAqB,CAAA;AACnC,cAAc,qBAAqB,CAAA;AACnC,cAAc,wBAAwB,CAAA;AACtC,cAAc,uBAAuB,CAAA;AACrC,cAAc,qBAAqB,CAAA;AACnC,cAAc,yBAAyB,CAAA;AACvC,cAAc,sBAAsB,CAAA;AACpC,cAAc,qBAAqB,CAAA;AACnC,cAAc,oBAAoB,CAAA;AAClC,cAAc,mBAAmB,CAAA;AACjC,cAAc,iCAAiC,CAAA;AAC/C,cAAc,yBAAyB,CAAA;AACvC,cAAc,mBAAmB,CAAA;AACjC,cAAc,uBAAuB,CAAA;AACrC,cAAc,sBAAsB,CAAA;AACpC,cAAc,0BAA0B,CAAA;AAExC,cAAc,yBAAyB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAA;AACtC,cAAc,oBAAoB,CAAA;AAClC,cAAc,2BAA2B,CAAA;AACzC,cAAc,qBAAqB,CAAA;AACnC,cAAc,0BAA0B,CAAA;AACxC,cAAc,oBAAoB,CAAA;AAClC,cAAc,yBAAyB,CAAA;AACvC,cAAc,yBAAyB,CAAA;AACvC,cAAc,qBAAqB,CAAA;AACnC,cAAc,mBAAmB,CAAA;AACjC,cAAc,uBAAuB,CAAA;AACrC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,qBAAqB,CAAA;AACnC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,sBAAsB,CAAA;AACpC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,+BAA+B,CAAA;AAC7C,cAAc,uBAAuB,CAAA;AACrC,cAAc,yBAAyB,CAAA;AACvC,cAAc,mBAAmB,CAAA;AACjC,cAAc,wBAAwB,CAAA;AACtC,cAAc,sBAAsB,CAAA;AACpC,cAAc,uBAAuB,CAAA;AACrC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,oBAAoB,CAAA;AAClC,cAAc,qBAAqB,CAAA;AACnC,cAAc,mBAAmB,CAAA;AACjC,cAAc,0BAA0B,CAAA;AACxC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,sBAAsB,CAAA;AACpC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,yBAAyB,CAAA;AACvC,cAAc,0BAA0B,CAAA;AACxC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,yBAAyB,CAAA;AACvC,cAAc,qBAAqB,CAAA;AACnC,cAAc,qBAAqB,CAAA;AACnC,cAAc,wBAAwB,CAAA;AACtC,cAAc,uBAAuB,CAAA;AACrC,cAAc,qBAAqB,CAAA;AACnC,cAAc,yBAAyB,CAAA;AACvC,cAAc,sBAAsB,CAAA;AACpC,cAAc,qBAAqB,CAAA;AACnC,cAAc,oBAAoB,CAAA;AAClC,cAAc,mBAAmB,CAAA;AACjC,cAAc,iCAAiC,CAAA;AAC/C,cAAc,yBAAyB,CAAA;AACvC,cAAc,mBAAmB,CAAA;AACjC,cAAc,uBAAuB,CAAA;AACrC,cAAc,sBAAsB,CAAA;AACpC,cAAc,0BAA0B,CAAA;AAExC,cAAc,kBAAkB,CAAA;AAChC,cAAc,eAAe,CAAA;AAC7B,cAAc,yBAAyB,CAAA"}
@@ -0,0 +1,75 @@
1
+ export interface CheckboxGroupHookParams<T, F = string> {
2
+ /**
3
+ * The initial value for the checkbox group.
4
+ *
5
+ * @default []
6
+ */
7
+ initialValue?: T[];
8
+ /**
9
+ * A function to apply a filter to an option. Must return true if the option respects the filter and false otherwise.
10
+ * @param filter the current filter.
11
+ * @param option the current option.
12
+ * @returns true if the option should pass the filter, false if the option should be discarded.
13
+ */
14
+ applyFilter?: (filter: F, option: T) => boolean;
15
+ /**
16
+ * The full set of options for the checkbox group.
17
+ */
18
+ options: T[];
19
+ /**
20
+ * A function that produces a unique id for an option.
21
+ * @param option the current option.
22
+ * @returns a unique key.
23
+ */
24
+ renderKey: (option: T) => string | number | undefined;
25
+ }
26
+ /**
27
+ * Use this hook to easily implement filtering and selection controls for a checkbox group.
28
+ * @param params the parameters to create the controls.
29
+ * @returns the checkbox controls.
30
+ */
31
+ export declare function useCheckboxGroupControls<T, F = string>(params: CheckboxGroupHookParams<T, F>): {
32
+ /**
33
+ * Selects all the options currently visible.
34
+ */
35
+ selectAll: () => void;
36
+ /**
37
+ * Removes all options from the selection.
38
+ */
39
+ removeSelection: () => void;
40
+ /**
41
+ * The current filter applied.
42
+ */
43
+ filter: F | undefined;
44
+ /**
45
+ * Apply a new filter.
46
+ */
47
+ setFilter: import("react").Dispatch<import("react").SetStateAction<F | undefined>>;
48
+ /**
49
+ * The options that should be passed to the checkbox group.
50
+ */
51
+ options: T[];
52
+ /**
53
+ * The value that should be passed to the checkbox group.
54
+ */
55
+ value: T[];
56
+ /**
57
+ * Changes the current value, should be passed to the property `onChange` of the checkbox group.
58
+ */
59
+ setValue: import("react").Dispatch<import("react").SetStateAction<T[]>>;
60
+ /**
61
+ * A function to render a unique key for an option. Should be passed to the property `renderKey` of the checkbox group.
62
+ */
63
+ renderKey: (option: T) => string | number | undefined;
64
+ /**
65
+ * A function that returns true if the option is filtered out, but checked.
66
+ * @param option the option to check.
67
+ * @returns true if the option was filtered out, but is checked; false otherwise.
68
+ */
69
+ isUnfilteredButChecked: (o: T) => boolean;
70
+ /**
71
+ * True if all options showing are selected, false otherwise.
72
+ */
73
+ isAllSelected: boolean;
74
+ };
75
+ //# sourceMappingURL=checkbox.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checkbox.d.ts","sourceRoot":"","sources":["../../src/utils/checkbox.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,uBAAuB,CAAC,CAAC,EAAE,CAAC,GAAG,MAAM;IACpD;;;;OAIG;IACH,YAAY,CAAC,EAAE,CAAC,EAAE,CAAC;IACnB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC;IAChD;;OAEG;IACH,OAAO,EAAE,CAAC,EAAE,CAAC;IACb;;;;OAIG;IACH,SAAS,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;CACvD;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,MAAM,EAAE,uBAAuB,CAAC,CAAC,EAAE,CAAC,CAAC;IA+BzF;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;8BArEqB,MAAM,GAAG,MAAM,GAAG,SAAS;IAuEnD;;;;OAIG;gCAhDmF,CAAC;IAkDvF;;OAEG;;EAGN"}
@@ -0,0 +1,81 @@
1
+ import { useCallback, useMemo, useState } from 'react';
2
+ import { defaultRenderKey } from './options.js';
3
+ /**
4
+ * Use this hook to easily implement filtering and selection controls for a checkbox group.
5
+ * @param params the parameters to create the controls.
6
+ * @returns the checkbox controls.
7
+ */
8
+ export function useCheckboxGroupControls(params) {
9
+ const [value, setValue] = useState(params.initialValue ?? []);
10
+ const [filter, setFilter] = useState();
11
+ const renderKey = params.renderKey ?? defaultRenderKey;
12
+ const { options, isUnfilteredButChecked } = useMemo(() => {
13
+ if (!params.applyFilter || !filter)
14
+ return { options: params.options, isUnfilteredButChecked: () => false };
15
+ const filtered = [];
16
+ const unfilteredButChecked = [];
17
+ const map = new Map();
18
+ const valueKeys = value.map(o => renderKey(o));
19
+ for (const o of params.options) {
20
+ const key = renderKey(o);
21
+ if (params.applyFilter(filter, o))
22
+ filtered.push(o);
23
+ else if (valueKeys.includes(key)) {
24
+ unfilteredButChecked.push(o);
25
+ map.set(key, true);
26
+ }
27
+ }
28
+ return { options: [...unfilteredButChecked, ...filtered], isUnfilteredButChecked: (o) => map.has(renderKey(o)) };
29
+ }, [params.options, filter]);
30
+ const selectAll = useCallback(() => {
31
+ setValue([...options]);
32
+ }, [options]);
33
+ const removeSelection = useCallback(() => {
34
+ setValue([]);
35
+ }, []);
36
+ return {
37
+ /**
38
+ * Selects all the options currently visible.
39
+ */
40
+ selectAll,
41
+ /**
42
+ * Removes all options from the selection.
43
+ */
44
+ removeSelection,
45
+ /**
46
+ * The current filter applied.
47
+ */
48
+ filter,
49
+ /**
50
+ * Apply a new filter.
51
+ */
52
+ setFilter: setFilter,
53
+ /**
54
+ * The options that should be passed to the checkbox group.
55
+ */
56
+ options,
57
+ /**
58
+ * The value that should be passed to the checkbox group.
59
+ */
60
+ value,
61
+ /**
62
+ * Changes the current value, should be passed to the property `onChange` of the checkbox group.
63
+ */
64
+ setValue,
65
+ /**
66
+ * A function to render a unique key for an option. Should be passed to the property `renderKey` of the checkbox group.
67
+ */
68
+ renderKey,
69
+ /**
70
+ * A function that returns true if the option is filtered out, but checked.
71
+ * @param option the option to check.
72
+ * @returns true if the option was filtered out, but is checked; false otherwise.
73
+ */
74
+ isUnfilteredButChecked,
75
+ /**
76
+ * True if all options showing are selected, false otherwise.
77
+ */
78
+ isAllSelected: value.length === options.length,
79
+ };
80
+ }
81
+ //# sourceMappingURL=checkbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checkbox.js","sourceRoot":"","sources":["../../src/utils/checkbox.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAA;AA4B5C;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CAAgB,MAAqC;IAC3F,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,YAAY,IAAI,EAAE,CAAC,CAAA;IAC7D,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,EAAiB,CAAA;IACrD,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,IAAI,gBAAgB,CAAA;IAEtD,MAAM,EAAE,OAAO,EAAE,sBAAsB,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE;QACvD,IAAI,CAAC,MAAM,CAAC,WAAW,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,sBAAsB,EAAE,GAAG,EAAE,CAAC,KAAK,EAAE,CAAA;QAC3G,MAAM,QAAQ,GAAQ,EAAE,CAAA;QACxB,MAAM,oBAAoB,GAAQ,EAAE,CAAA;QACpC,MAAM,GAAG,GAAG,IAAI,GAAG,EAAwC,CAAA;QAC3D,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAA;QAC9C,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YAC/B,MAAM,GAAG,GAAG,SAAS,CAAC,CAAC,CAAC,CAAA;YACxB,IAAI,MAAM,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC;gBAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;iBAC9C,IAAI,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;gBACjC,oBAAoB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;gBAC5B,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;YACpB,CAAC;QACH,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,CAAC,GAAG,oBAAoB,EAAE,GAAG,QAAQ,CAAC,EAAE,sBAAsB,EAAE,CAAC,CAAI,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;IACrH,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAA;IAE5B,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE;QACjC,QAAQ,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAA;IACxB,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAA;IAEb,MAAM,eAAe,GAAG,WAAW,CAAC,GAAG,EAAE;QACvC,QAAQ,CAAC,EAAE,CAAC,CAAA;IACd,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,OAAO;QACL;;WAEG;QACH,SAAS;QACT;;WAEG;QACH,eAAe;QACf;;WAEG;QACH,MAAM;QACN;;WAEG;QACH,SAAS,EAAE,SAAS;QACpB;;WAEG;QACH,OAAO;QACP;;WAEG;QACH,KAAK;QACL;;WAEG;QACH,QAAQ;QACR;;WAEG;QACH,SAAS;QACT;;;;WAIG;QACH,sBAAsB;QACtB;;WAEG;QACH,aAAa,EAAE,KAAK,CAAC,MAAM,KAAK,OAAO,CAAC,MAAM;KAC/C,CAAA;AACH,CAAC"}
@@ -1,12 +1,34 @@
1
1
  import { ColorKey } from '@stack-spot/portal-theme';
2
+ import { SpacingKey } from '@stack-spot/portal-theme/dist/definition.js';
2
3
  import { TextAppearance, WithStyleShortcuts } from '../types.js';
3
4
  export declare function colorNameToColorVariable(name: ColorKey): string;
4
5
  export declare function applyColor(style: React.CSSProperties | undefined, color: ColorKey | undefined): import("react").CSSProperties | undefined;
5
6
  export declare function textAppearanceToClass(appearance: TextAppearance): string;
6
7
  export declare function applyTextAppearance(className: string | undefined, appearance: TextAppearance | undefined): string;
7
8
  export declare function applyCSSVariable(style: React.CSSProperties | undefined, name: string, value: any): import("react").CSSProperties | undefined;
8
- export declare function applyStyles({ bg, fg, border, radius, justifyContent, alignItems, flex, gap, m, mt, mb, ml, mr, p, pt, pb, pl, pr, w, h, style, ...props }: WithStyleShortcuts & Record<string, any>): {
9
- style: Partial<import("react").CSSProperties>;
9
+ export declare function getStyleFromProps({ bg, fg, border, radius, justifyContent, alignItems, flex, gap, m, mt, mb, ml, mr, p, pt, pb, pl, pr, w, h, }: WithStyleShortcuts): React.CSSProperties;
10
+ export declare function applyStyles({ style, ...props }: WithStyleShortcuts & Record<string, any>): {
11
+ bg?: ColorKey;
12
+ fg?: ColorKey;
13
+ border?: ColorKey;
14
+ radius?: import("@stack-spot/portal-theme").RadiusKey;
15
+ m?: SpacingKey | SpacingKey[] | string;
16
+ mt?: SpacingKey | string;
17
+ mb?: SpacingKey | string;
18
+ ml?: SpacingKey | string;
19
+ mr?: SpacingKey | string;
20
+ p?: SpacingKey | SpacingKey[] | string;
21
+ pt?: SpacingKey | string;
22
+ pb?: SpacingKey | string;
23
+ pl?: SpacingKey | string;
24
+ pr?: SpacingKey | string;
25
+ w?: string | number;
26
+ h?: string | number;
27
+ flex?: React.CSSProperties["flex"];
28
+ justifyContent?: React.CSSProperties["justifyContent"];
29
+ alignItems?: React.CSSProperties["alignItems"];
30
+ gap?: React.CSSProperties["gap"];
31
+ style: any;
10
32
  };
11
33
  export declare function styleObjectToCssString(styleObject?: React.CSSProperties): string;
12
34
  //# sourceMappingURL=css.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"css.d.ts","sourceRoot":"","sources":["../../src/utils/css.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAsB,MAAM,0BAA0B,CAAA;AAGvE,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAA;AAE7D,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAE/D;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC,aAAa,GAAG,SAAS,EAAE,KAAK,EAAE,QAAQ,GAAG,SAAS,6CAE7F;AAED,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,cAAc,GAAG,MAAM,CAExE;AAED,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,UAAU,EAAE,cAAc,GAAG,SAAS,UAExG;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,KAAK,CAAC,aAAa,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,6CAGhG;AAQD,wBAAgB,WAAW,CACzB,EACE,EAAE,EACF,EAAE,EACF,MAAM,EACN,MAAM,EACN,cAAc,EACd,UAAU,EACV,IAAI,EACJ,GAAG,EACH,CAAC,EACD,EAAE,EACF,EAAE,EACF,EAAE,EACF,EAAE,EACF,CAAC,EACD,EAAE,EACF,EAAE,EACF,EAAE,EACF,EAAE,EACF,CAAC,EACD,CAAC,EACD,KAAK,EACL,GAAG,KAAK,EACT,EAAE,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;;EA8B5C;AAGD,wBAAgB,sBAAsB,CAAC,WAAW,GAAE,KAAK,CAAC,aAAkB,UAgB3E"}
1
+ {"version":3,"file":"css.d.ts","sourceRoot":"","sources":["../../src/utils/css.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAsB,MAAM,0BAA0B,CAAA;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,0CAA0C,CAAA;AAErE,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAA;AAE7D,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAE/D;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC,aAAa,GAAG,SAAS,EAAE,KAAK,EAAE,QAAQ,GAAG,SAAS,6CAE7F;AAED,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,cAAc,GAAG,MAAM,CAExE;AAED,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,UAAU,EAAE,cAAc,GAAG,SAAS,UAExG;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,KAAK,CAAC,aAAa,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,6CAGhG;AAQD,wBAAgB,iBAAiB,CAAC,EAChC,EAAE,EACF,EAAE,EACF,MAAM,EACN,MAAM,EACN,cAAc,EACd,UAAU,EACV,IAAI,EACJ,GAAG,EACH,CAAC,EACD,EAAE,EACF,EAAE,EACF,EAAE,EACF,EAAE,EACF,CAAC,EACD,EAAE,EACF,EAAE,EACF,EAAE,EACF,EAAE,EACF,CAAC,EACD,CAAC,GACF,EAAE,kBAAkB,GAAG,KAAK,CAAC,aAAa,CA4B1C;AAED,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE,EAAE,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;EAGxF;AAGD,wBAAgB,sBAAsB,CAAC,WAAW,GAAE,KAAK,CAAC,aAAkB,UAgB3E"}
package/dist/utils/css.js CHANGED
@@ -24,7 +24,7 @@ function spacingToStyle(spacing) {
24
24
  return theme.spacing[spacing];
25
25
  return spacing?.map(s => theme.spacing[s]).join(' ');
26
26
  }
27
- export function applyStyles({ bg, fg, border, radius, justifyContent, alignItems, flex, gap, m, mt, mb, ml, mr, p, pt, pb, pl, pr, w, h, style, ...props }) {
27
+ export function getStyleFromProps({ bg, fg, border, radius, justifyContent, alignItems, flex, gap, m, mt, mb, ml, mr, p, pt, pb, pl, pr, w, h, }) {
28
28
  const [bgColor, bgLevel] = bg?.split('.') ?? [];
29
29
  const [fgColor, fgLevel] = fg?.split('.') ?? [];
30
30
  const [borderColor, borderLevel] = border?.split('.') ?? [];
@@ -50,23 +50,26 @@ export function applyStyles({ bg, fg, border, radius, justifyContent, alignItems
50
50
  paddingRight: spacingToStyle(pr),
51
51
  width: w,
52
52
  height: h,
53
- ...style,
54
53
  };
55
- return { style: omitBy(newStyle, v => v === undefined), ...props };
54
+ return omitBy(newStyle, v => v === undefined);
55
+ }
56
+ export function applyStyles({ style, ...props }) {
57
+ const newStyle = getStyleFromProps(props);
58
+ return { style: { ...newStyle, ...style }, ...props };
56
59
  }
57
60
  // AI generated
58
61
  export function styleObjectToCssString(styleObject = {}) {
59
62
  return Object.entries(styleObject)
60
63
  .map(([property, value]) => {
61
64
  // Convert camelCase to kebab-case
62
- const cssProperty = property.replace(/([A-Z])/g, "-$1").toLowerCase();
65
+ const cssProperty = property.replace(/([A-Z])/g, '-$1').toLowerCase();
63
66
  // Append 'px' to numeric values for common dimension properties
64
- const cssValue = typeof value === "number" &&
67
+ const cssValue = typeof value === 'number' &&
65
68
  !['zIndex', 'opacity', 'fontWeight'].includes(property)
66
69
  ? `${value}px`
67
70
  : value;
68
71
  return `${cssProperty}: ${cssValue}`;
69
72
  })
70
- .join("; ");
73
+ .join('; ');
71
74
  }
72
75
  //# sourceMappingURL=css.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"css.js","sourceRoot":"","sources":["../../src/utils/css.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"css.js","sourceRoot":"","sources":["../../src/utils/css.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ export interface RadioGroupHookParams<T, F = string> {
2
+ /**
3
+ * The initial value for the radio group.
4
+ */
5
+ initialValue?: T;
6
+ /**
7
+ * A function to apply a filter to an option. Must return true if the option respects the filter and false otherwise.
8
+ * @param filter the current filter.
9
+ * @param option the current option.
10
+ * @returns true if the option should pass the filter, false if the option should be discarded.
11
+ */
12
+ applyFilter?: (filter: F, option: T) => boolean;
13
+ /**
14
+ * The full set of options for the radio group.
15
+ */
16
+ options: T[];
17
+ /**
18
+ * A function that produces a unique id for an option.
19
+ * @param option the current option.
20
+ * @returns a unique key.
21
+ */
22
+ renderKey: (option: T) => string | number | undefined;
23
+ }
24
+ /**
25
+ * Use this hook to easily implement filtering for a radio group.
26
+ * @param params the parameters to create the controls.
27
+ * @returns the checkbox controls.
28
+ */
29
+ export declare function useRadioGroupControls<T, F = string>(params: RadioGroupHookParams<T, F>): {
30
+ /**
31
+ * The current filter applied.
32
+ */
33
+ filter: F | undefined;
34
+ /**
35
+ * Apply a new filter.
36
+ */
37
+ setFilter: import("react").Dispatch<import("react").SetStateAction<F | undefined>>;
38
+ /**
39
+ * The options that should be passed to the radio group.
40
+ */
41
+ options: T[];
42
+ /**
43
+ * The value that should be passed to the radio group.
44
+ */
45
+ value: T | undefined;
46
+ /**
47
+ * Changes the current value, should be passed to the property `onChange` of the radio group.
48
+ */
49
+ setValue: import("react").Dispatch<import("react").SetStateAction<T | undefined>>;
50
+ /**
51
+ * A function to render a unique key for an option. Should be passed to the property `renderKey` of the radio group.
52
+ */
53
+ renderKey: (option: T) => string | number | undefined;
54
+ /**
55
+ * A function that returns true if the option is filtered out, but checked.
56
+ * @param option the option to check.
57
+ * @returns true if the option was filtered out, but is checked; false otherwise.
58
+ */
59
+ isUnfilteredButChecked: (o: T) => boolean | undefined;
60
+ };
61
+ //# sourceMappingURL=radio.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"radio.d.ts","sourceRoot":"","sources":["../../src/utils/radio.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,oBAAoB,CAAC,CAAC,EAAE,CAAC,GAAG,MAAM;IACjD;;OAEG;IACH,YAAY,CAAC,EAAE,CAAC,CAAC;IACjB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC;IAChD;;OAEG;IACH,OAAO,EAAE,CAAC,EAAE,CAAC;IACb;;;;OAIG;IACH,SAAS,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;CACvD;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,MAAM,EAAE,oBAAoB,CAAC,CAAC,EAAE,CAAC,CAAC;IAiBnF;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;8BA/CqB,MAAM,GAAG,MAAM,GAAG,SAAS;IAiDnD;;;;OAIG;gCAjC2B,CAAC;EAoClC"}
@@ -0,0 +1,56 @@
1
+ import { useMemo, useState } from 'react';
2
+ import { defaultRenderKey } from './options.js';
3
+ /**
4
+ * Use this hook to easily implement filtering for a radio group.
5
+ * @param params the parameters to create the controls.
6
+ * @returns the checkbox controls.
7
+ */
8
+ export function useRadioGroupControls(params) {
9
+ const [value, setValue] = useState(params.initialValue);
10
+ const [filter, setFilter] = useState();
11
+ const renderKey = params.renderKey ?? defaultRenderKey;
12
+ const { options, isUnfilteredButChecked } = useMemo(() => {
13
+ if (!params.applyFilter || !filter)
14
+ return { options: params.options, isUnfilteredButChecked: () => false };
15
+ const valueKey = value ? renderKey(value) : undefined;
16
+ const isValueFilteredOut = value && !params.applyFilter?.(filter, value);
17
+ const filtered = params.options.filter(o => params.applyFilter?.(filter, o));
18
+ return {
19
+ options: isValueFilteredOut ? [value, ...filtered] : filtered,
20
+ isUnfilteredButChecked: (o) => isValueFilteredOut && renderKey(o) === valueKey,
21
+ };
22
+ }, [params.options, filter]);
23
+ return {
24
+ /**
25
+ * The current filter applied.
26
+ */
27
+ filter,
28
+ /**
29
+ * Apply a new filter.
30
+ */
31
+ setFilter: setFilter,
32
+ /**
33
+ * The options that should be passed to the radio group.
34
+ */
35
+ options,
36
+ /**
37
+ * The value that should be passed to the radio group.
38
+ */
39
+ value,
40
+ /**
41
+ * Changes the current value, should be passed to the property `onChange` of the radio group.
42
+ */
43
+ setValue,
44
+ /**
45
+ * A function to render a unique key for an option. Should be passed to the property `renderKey` of the radio group.
46
+ */
47
+ renderKey,
48
+ /**
49
+ * A function that returns true if the option is filtered out, but checked.
50
+ * @param option the option to check.
51
+ * @returns true if the option was filtered out, but is checked; false otherwise.
52
+ */
53
+ isUnfilteredButChecked,
54
+ };
55
+ }
56
+ //# sourceMappingURL=radio.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"radio.js","sourceRoot":"","sources":["../../src/utils/radio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AACzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAA;AA0B5C;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAgB,MAAkC;IACrF,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,YAAY,CAAC,CAAA;IACvD,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,EAAiB,CAAA;IACrD,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,IAAI,gBAAgB,CAAA;IAEtD,MAAM,EAAE,OAAO,EAAE,sBAAsB,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE;QACvD,IAAI,CAAC,MAAM,CAAC,WAAW,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,sBAAsB,EAAE,GAAG,EAAE,CAAC,KAAK,EAAE,CAAA;QAC3G,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;QACrD,MAAM,kBAAkB,GAAG,KAAK,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;QACxE,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAA;QAC5E,OAAO;YACL,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ;YAC7D,sBAAsB,EAAE,CAAC,CAAI,EAAE,EAAE,CAAC,kBAAkB,IAAI,SAAS,CAAC,CAAC,CAAC,KAAK,QAAQ;SAClF,CAAA;IACH,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAA;IAE5B,OAAO;QACL;;WAEG;QACH,MAAM;QACN;;WAEG;QACH,SAAS,EAAE,SAAS;QACpB;;WAEG;QACH,OAAO;QACP;;WAEG;QACH,KAAK;QACL;;WAEG;QACH,QAAQ;QACR;;WAEG;QACH,SAAS;QACT;;;;WAIG;QACH,sBAAsB;KACvB,CAAA;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stack-spot/citric-react",
3
- "version": "0.15.4",
3
+ "version": "0.17.0",
4
4
  "author": "StackSpot",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
@@ -31,6 +31,7 @@ export const Card = withRef(({ tag = 'div', onClick, size, bgLevel, className, c
31
31
  <CitricComponent
32
32
  tag={tag}
33
33
  component="card"
34
+ onClick={onClick}
34
35
  className={listToClass([onClick && 'clickable', size, bgLevel && `bg-${bgLevel}`, className])}
35
36
  {...props}
36
37
  >
@@ -0,0 +1,47 @@
1
+ import { listToClass } from '@stack-spot/portal-theme'
2
+ import { useEffect, useMemo, useState } from 'react'
3
+ import { WithStyleShortcuts } from '../types'
4
+ import { getStyleFromProps } from '../utils/css'
5
+ import { Skeleton } from './Skeleton'
6
+
7
+ export interface BaseImageWithFallbackProps extends Pick<WithStyleShortcuts, 'w' | 'h' | 'radius' | 'bg'> {
8
+ fallback: React.ReactNode,
9
+ showLoading?: boolean,
10
+ }
11
+
12
+ export type ImageWithFallbackProps = JSX.IntrinsicElements['img'] & BaseImageWithFallbackProps
13
+
14
+ export const ImageWithFallback = (
15
+ { onLoad, onError, className, style: ogStyle, fallback, showLoading = true, w, h, radius, bg, ...props }: ImageWithFallbackProps,
16
+ ) => {
17
+ const [state, setState] = useState<'loading' | 'ready' | 'error'>(props.src ? 'loading' : 'error')
18
+ const isLoading = state === 'loading' && showLoading
19
+ const style = useMemo(() => ({ ...getStyleFromProps({ w, h, radius, bg }), ...ogStyle }), [ogStyle, w, h, radius, bg])
20
+
21
+ function handleLoad(e: React.SyntheticEvent<HTMLImageElement, Event>) {
22
+ if (state === 'loading') setState('ready')
23
+ onLoad?.(e)
24
+ }
25
+
26
+ function handleError(e: React.SyntheticEvent<HTMLImageElement, Event>) {
27
+ setState('error')
28
+ onError?.(e)
29
+ }
30
+
31
+ useEffect(() => {
32
+ if (state !== 'loading') setState(props.src ? 'loading' : 'error')
33
+ }, [props.src])
34
+
35
+ if (state === 'error') return <div className={listToClass([className, 'center'])} style={style}>{fallback}</div>
36
+ return <>
37
+ {isLoading && <Skeleton className={className} style={style} />}
38
+ <img
39
+ onLoad={handleLoad}
40
+ onError={handleError}
41
+ style={{ ...style, ...(isLoading ? { pointerEvents: 'none', position: 'absolute', opacity: 0 } : {}) }}
42
+ aria-hidden={isLoading}
43
+ className={className}
44
+ {...props}
45
+ />
46
+ </>
47
+ }
package/src/index.ts CHANGED
@@ -21,6 +21,7 @@ export * from './components/Form'
21
21
  export * from './components/FormGroup'
22
22
  export * from './components/IconBox'
23
23
  export * from './components/ImageBox'
24
+ export * from './components/ImageWithFallback'
24
25
  export * from './components/Input'
25
26
  export * from './components/layout'
26
27
  export * from './components/Link'
@@ -49,4 +50,7 @@ export * from './components/Textarea'
49
50
  export * from './components/Tooltip'
50
51
  export * from './context/CitricProvider'
51
52
  export type { CitricController } from './types'
53
+ export * from './utils/checkbox'
54
+ export * from './utils/radio'
52
55
  export * from './utils/ValueController'
56
+
@@ -0,0 +1,109 @@
1
+ import { useCallback, useMemo, useState } from 'react'
2
+ import { defaultRenderKey } from './options'
3
+
4
+ export interface CheckboxGroupHookParams<T, F = string> {
5
+ /**
6
+ * The initial value for the checkbox group.
7
+ *
8
+ * @default []
9
+ */
10
+ initialValue?: T[],
11
+ /**
12
+ * A function to apply a filter to an option. Must return true if the option respects the filter and false otherwise.
13
+ * @param filter the current filter.
14
+ * @param option the current option.
15
+ * @returns true if the option should pass the filter, false if the option should be discarded.
16
+ */
17
+ applyFilter?: (filter: F, option: T) => boolean,
18
+ /**
19
+ * The full set of options for the checkbox group.
20
+ */
21
+ options: T[],
22
+ /**
23
+ * A function that produces a unique id for an option.
24
+ * @param option the current option.
25
+ * @returns a unique key.
26
+ */
27
+ renderKey: (option: T) => string | number | undefined,
28
+ }
29
+
30
+ /**
31
+ * Use this hook to easily implement filtering and selection controls for a checkbox group.
32
+ * @param params the parameters to create the controls.
33
+ * @returns the checkbox controls.
34
+ */
35
+ export function useCheckboxGroupControls<T, F = string>(params: CheckboxGroupHookParams<T, F>) {
36
+ const [value, setValue] = useState(params.initialValue ?? [])
37
+ const [filter, setFilter] = useState<F | undefined>()
38
+ const renderKey = params.renderKey ?? defaultRenderKey
39
+
40
+ const { options, isUnfilteredButChecked } = useMemo(() => {
41
+ if (!params.applyFilter || !filter) return { options: params.options, isUnfilteredButChecked: () => false }
42
+ const filtered: T[] = []
43
+ const unfilteredButChecked: T[] = []
44
+ const map = new Map<number | string | undefined, boolean>()
45
+ const valueKeys = value.map(o => renderKey(o))
46
+ for (const o of params.options) {
47
+ const key = renderKey(o)
48
+ if (params.applyFilter(filter, o)) filtered.push(o)
49
+ else if (valueKeys.includes(key)) {
50
+ unfilteredButChecked.push(o)
51
+ map.set(key, true)
52
+ }
53
+ }
54
+ return { options: [...unfilteredButChecked, ...filtered], isUnfilteredButChecked: (o: T) => map.has(renderKey(o)) }
55
+ }, [params.options, filter])
56
+
57
+ const selectAll = useCallback(() => {
58
+ setValue([...options])
59
+ }, [options])
60
+
61
+ const removeSelection = useCallback(() => {
62
+ setValue([])
63
+ }, [])
64
+
65
+ return {
66
+ /**
67
+ * Selects all the options currently visible.
68
+ */
69
+ selectAll,
70
+ /**
71
+ * Removes all options from the selection.
72
+ */
73
+ removeSelection,
74
+ /**
75
+ * The current filter applied.
76
+ */
77
+ filter,
78
+ /**
79
+ * Apply a new filter.
80
+ */
81
+ setFilter: setFilter,
82
+ /**
83
+ * The options that should be passed to the checkbox group.
84
+ */
85
+ options,
86
+ /**
87
+ * The value that should be passed to the checkbox group.
88
+ */
89
+ value,
90
+ /**
91
+ * Changes the current value, should be passed to the property `onChange` of the checkbox group.
92
+ */
93
+ setValue,
94
+ /**
95
+ * A function to render a unique key for an option. Should be passed to the property `renderKey` of the checkbox group.
96
+ */
97
+ renderKey,
98
+ /**
99
+ * A function that returns true if the option is filtered out, but checked.
100
+ * @param option the option to check.
101
+ * @returns true if the option was filtered out, but is checked; false otherwise.
102
+ */
103
+ isUnfilteredButChecked,
104
+ /**
105
+ * True if all options showing are selected, false otherwise.
106
+ */
107
+ isAllSelected: value.length === options.length,
108
+ }
109
+ }
package/src/utils/css.ts CHANGED
@@ -30,37 +30,33 @@ function spacingToStyle(spacing: SpacingKey | SpacingKey[] | string | undefined)
30
30
  return spacing?.map(s => theme.spacing[s]).join(' ')
31
31
  }
32
32
 
33
- export function applyStyles(
34
- {
35
- bg,
36
- fg,
37
- border,
38
- radius,
39
- justifyContent,
40
- alignItems,
41
- flex,
42
- gap,
43
- m,
44
- mt,
45
- mb,
46
- ml,
47
- mr,
48
- p,
49
- pt,
50
- pb,
51
- pl,
52
- pr,
53
- w,
54
- h,
55
- style,
56
- ...props
57
- }: WithStyleShortcuts & Record<string, any>,
58
- ) {
33
+ export function getStyleFromProps({
34
+ bg,
35
+ fg,
36
+ border,
37
+ radius,
38
+ justifyContent,
39
+ alignItems,
40
+ flex,
41
+ gap,
42
+ m,
43
+ mt,
44
+ mb,
45
+ ml,
46
+ mr,
47
+ p,
48
+ pt,
49
+ pb,
50
+ pl,
51
+ pr,
52
+ w,
53
+ h,
54
+ }: WithStyleShortcuts): React.CSSProperties {
59
55
  const [bgColor, bgLevel] = bg?.split('.') ?? []
60
56
  const [fgColor, fgLevel] = fg?.split('.') ?? []
61
57
  const [borderColor, borderLevel] = border?.split('.') ?? []
62
58
  const borderColorVar = (theme.color as any)[borderColor]?.[borderLevel]
63
- const newStyle: React.CSSProperties = {
59
+ const newStyle: React.CSSProperties = {
64
60
  backgroundColor: (theme.color as any)[bgColor]?.[bgLevel],
65
61
  color: (theme.color as any)[fgColor]?.[fgLevel],
66
62
  border: borderColorVar ? `1px solid ${borderColorVar}` : undefined,
@@ -81,9 +77,13 @@ export function applyStyles(
81
77
  paddingRight: spacingToStyle(pr),
82
78
  width: w,
83
79
  height: h,
84
- ...style,
85
80
  }
86
- return { style: omitBy(newStyle, v => v === undefined), ...props }
81
+ return omitBy(newStyle, v => v === undefined)
82
+ }
83
+
84
+ export function applyStyles({ style, ...props }: WithStyleShortcuts & Record<string, any>) {
85
+ const newStyle = getStyleFromProps(props)
86
+ return { style: { ...newStyle, ...style }, ...props }
87
87
  }
88
88
 
89
89
  // AI generated
@@ -91,16 +91,16 @@ export function styleObjectToCssString(styleObject: React.CSSProperties = {}) {
91
91
  return Object.entries(styleObject)
92
92
  .map(([property, value]) => {
93
93
  // Convert camelCase to kebab-case
94
- const cssProperty = property.replace(/([A-Z])/g, "-$1").toLowerCase()
94
+ const cssProperty = property.replace(/([A-Z])/g, '-$1').toLowerCase()
95
95
 
96
96
  // Append 'px' to numeric values for common dimension properties
97
97
  const cssValue =
98
- typeof value === "number" &&
98
+ typeof value === 'number' &&
99
99
  !['zIndex', 'opacity', 'fontWeight'].includes(property)
100
100
  ? `${value}px`
101
101
  : value
102
102
 
103
103
  return `${cssProperty}: ${cssValue}`
104
104
  })
105
- .join("; ")
105
+ .join('; ')
106
106
  }
@@ -0,0 +1,81 @@
1
+ import { useMemo, useState } from 'react'
2
+ import { defaultRenderKey } from './options'
3
+
4
+ export interface RadioGroupHookParams<T, F = string> {
5
+ /**
6
+ * The initial value for the radio group.
7
+ */
8
+ initialValue?: T,
9
+ /**
10
+ * A function to apply a filter to an option. Must return true if the option respects the filter and false otherwise.
11
+ * @param filter the current filter.
12
+ * @param option the current option.
13
+ * @returns true if the option should pass the filter, false if the option should be discarded.
14
+ */
15
+ applyFilter?: (filter: F, option: T) => boolean,
16
+ /**
17
+ * The full set of options for the radio group.
18
+ */
19
+ options: T[],
20
+ /**
21
+ * A function that produces a unique id for an option.
22
+ * @param option the current option.
23
+ * @returns a unique key.
24
+ */
25
+ renderKey: (option: T) => string | number | undefined,
26
+ }
27
+
28
+ /**
29
+ * Use this hook to easily implement filtering for a radio group.
30
+ * @param params the parameters to create the controls.
31
+ * @returns the checkbox controls.
32
+ */
33
+ export function useRadioGroupControls<T, F = string>(params: RadioGroupHookParams<T, F>) {
34
+ const [value, setValue] = useState(params.initialValue)
35
+ const [filter, setFilter] = useState<F | undefined>()
36
+ const renderKey = params.renderKey ?? defaultRenderKey
37
+
38
+ const { options, isUnfilteredButChecked } = useMemo(() => {
39
+ if (!params.applyFilter || !filter) return { options: params.options, isUnfilteredButChecked: () => false }
40
+ const valueKey = value ? renderKey(value) : undefined
41
+ const isValueFilteredOut = value && !params.applyFilter?.(filter, value)
42
+ const filtered = params.options.filter(o => params.applyFilter?.(filter, o))
43
+ return {
44
+ options: isValueFilteredOut ? [value, ...filtered] : filtered,
45
+ isUnfilteredButChecked: (o: T) => isValueFilteredOut && renderKey(o) === valueKey,
46
+ }
47
+ }, [params.options, filter])
48
+
49
+ return {
50
+ /**
51
+ * The current filter applied.
52
+ */
53
+ filter,
54
+ /**
55
+ * Apply a new filter.
56
+ */
57
+ setFilter: setFilter,
58
+ /**
59
+ * The options that should be passed to the radio group.
60
+ */
61
+ options,
62
+ /**
63
+ * The value that should be passed to the radio group.
64
+ */
65
+ value,
66
+ /**
67
+ * Changes the current value, should be passed to the property `onChange` of the radio group.
68
+ */
69
+ setValue,
70
+ /**
71
+ * A function to render a unique key for an option. Should be passed to the property `renderKey` of the radio group.
72
+ */
73
+ renderKey,
74
+ /**
75
+ * A function that returns true if the option is filtered out, but checked.
76
+ * @param option the option to check.
77
+ * @returns true if the option was filtered out, but is checked; false otherwise.
78
+ */
79
+ isUnfilteredButChecked,
80
+ }
81
+ }