@mohasinac/appkit 3.5.3 → 3.5.4
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.
- package/dist/features/seller/components/CategoryInlineSelect.d.ts +1 -1
- package/dist/features/seller/components/CategoryInlineSelect.js +1 -1
- package/dist/react/hooks/useBulkSelection.js +12 -3
- package/dist/react/hooks/useGesture.js +48 -4
- package/dist/react/hooks/useLongPress.d.ts +1 -0
- package/dist/react/hooks/useLongPress.js +5 -0
- package/dist/react/hooks/usePullToRefresh.js +12 -1
- package/dist/react/hooks/useRealtimeEvent.js +18 -1
- package/dist/react/hooks/useSwipe.js +14 -0
- package/dist/styles.css +1 -1
- package/dist/tailwind-utilities.css +1 -1
- package/dist/ui/components/BaseListingCard.d.ts +2 -1
- package/dist/ui/components/BaseListingCard.js +4 -5
- package/dist/ui/components/Button.js +52 -22
- package/dist/ui/components/DateInput.js +1 -0
- package/dist/ui/components/DynamicBgDiv.js +8 -6
- package/dist/ui/components/FormField.js +1 -1
- package/dist/ui/components/HorizontalScroller.js +17 -6
- package/dist/ui/components/Iframe.d.ts +8 -1
- package/dist/ui/components/Layout.d.ts +4 -4
- package/dist/ui/components/Layout.js +8 -8
- package/dist/ui/components/Motion.js +4 -1
- package/dist/ui/components/OtpInput.js +1 -1
- package/dist/ui/components/PaginatedSelect.js +29 -3
- package/dist/ui/components/Pagination.js +10 -5
- package/dist/ui/components/RichTextEditor.js +64 -3
- package/dist/ui/components/Select.js +1 -0
- package/dist/ui/components/Semantic.d.ts +10 -10
- package/dist/ui/components/Semantic.js +25 -25
- package/dist/ui/components/SideDrawer.js +13 -11
- package/dist/ui/components/SideModal.js +9 -7
- package/dist/ui/components/SlottedListingView.d.ts +13 -2
- package/dist/ui/components/StickyToolbar.js +9 -5
- package/dist/ui/components/TagInput.js +15 -2
- package/dist/ui/components/Textarea.js +1 -0
- package/dist/ui/components/Toggle.js +8 -1
- package/dist/ui/components/UnsavedChangesModal.js +12 -1
- package/dist/ui/forms/ColorPickerField.js +7 -0
- package/dist/ui/forms/FieldCheckbox.js +1 -1
- package/dist/utils/id-generators.d.ts +7 -4
- package/dist/utils/id-generators.js +53 -31
- package/dist/utils/number.formatter.js +19 -6
- package/dist/utils/string.formatter.js +4 -1
- package/package.json +1 -1
|
@@ -21,7 +21,8 @@ export interface BaseListingCardRootProps {
|
|
|
21
21
|
onTouchEnd?: () => void;
|
|
22
22
|
}
|
|
23
23
|
export interface BaseListingCardHeroProps {
|
|
24
|
-
aspect
|
|
24
|
+
/** Aspect ratio for the hero image — only these two produce a real CSS rule (Tailwind's static scanner can't see a dynamically-interpolated `aspect-[${var}]`). Defaults to `"4/3"`. */
|
|
25
|
+
aspect?: "square" | "4/3";
|
|
25
26
|
variant?: "grid" | "list";
|
|
26
27
|
className?: string;
|
|
27
28
|
children?: ReactNode;
|
|
@@ -25,11 +25,10 @@ function BaseListingCardHero({ aspect, variant = "grid", className = "", childre
|
|
|
25
25
|
.filter(Boolean)
|
|
26
26
|
.join(" "), onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, children: children }));
|
|
27
27
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
: `aspect-[${aspect}]`;
|
|
28
|
+
// Literal, statically-scannable class names only — never interpolate an
|
|
29
|
+
// arbitrary value into `aspect-[...]`, Tailwind's JIT scanner can't see it
|
|
30
|
+
// and the rule silently never makes it into the compiled CSS.
|
|
31
|
+
const aspectClass = aspect === "square" ? "aspect-square" : "aspect-[4/3]";
|
|
33
32
|
return (_jsx("div", { className: [
|
|
34
33
|
"relative overflow-hidden bg-[var(--appkit-color-surface)] flex-shrink-0",
|
|
35
34
|
aspectClass,
|
|
@@ -116,6 +116,16 @@ const ACTION_KIND_VARIANT = {
|
|
|
116
116
|
};
|
|
117
117
|
export function Button({ variant, size = "md", className = "", isLoading = false, disabled, children, gap, textSize, paddingX, paddingY, weight, textColor, border, rounded, shadow, justify, asChild = false, action, ...props }) {
|
|
118
118
|
const [confirmOpen, setConfirmOpen] = useState(false);
|
|
119
|
+
// React 17+ no longer pools SyntheticEvents, so it's safe to hold onto the
|
|
120
|
+
// original triggering event across the confirmation dialog's async gap and
|
|
121
|
+
// forward it to the consumer's onClick once confirmed — not the confirm
|
|
122
|
+
// button's own click event (a different DOM element, with none of the
|
|
123
|
+
// data-* attributes the caller may have put on the real trigger). Per the
|
|
124
|
+
// DOM/React event spec, `currentTarget` itself is reset to null once the
|
|
125
|
+
// original event's own synchronous dispatch finishes, so it's captured
|
|
126
|
+
// separately here and restored onto the stored event before forwarding.
|
|
127
|
+
const pendingEventRef = React.useRef(null);
|
|
128
|
+
const pendingTargetRef = React.useRef(null);
|
|
119
129
|
// Resolve defaults from action registry
|
|
120
130
|
const resolvedVariant = variant ?? (action ? (ACTION_KIND_VARIANT[action.kind] ?? "primary") : "primary");
|
|
121
131
|
const resolvedChildren = children ?? (action ? action.label : undefined);
|
|
@@ -159,37 +169,57 @@ export function Button({ variant, size = "md", className = "", isLoading = false
|
|
|
159
169
|
}
|
|
160
170
|
if (action?.confirmation) {
|
|
161
171
|
event.preventDefault();
|
|
172
|
+
pendingEventRef.current = event;
|
|
173
|
+
pendingTargetRef.current = event.currentTarget;
|
|
162
174
|
setConfirmOpen(true);
|
|
163
175
|
return;
|
|
164
176
|
}
|
|
165
177
|
wrapAsync(userOnClick)(event);
|
|
166
178
|
}, [disabled, isLoading, action, userOnClick, wrapAsync]);
|
|
167
|
-
const handleConfirm = useCallback((
|
|
179
|
+
const handleConfirm = useCallback(() => {
|
|
168
180
|
setConfirmOpen(false);
|
|
169
|
-
|
|
181
|
+
const originalEvent = pendingEventRef.current;
|
|
182
|
+
const originalTarget = pendingTargetRef.current;
|
|
183
|
+
pendingEventRef.current = null;
|
|
184
|
+
pendingTargetRef.current = null;
|
|
185
|
+
if (originalEvent) {
|
|
186
|
+
originalEvent.currentTarget = originalTarget;
|
|
187
|
+
wrapAsync(userOnClick)(originalEvent);
|
|
188
|
+
}
|
|
170
189
|
}, [userOnClick, wrapAsync]);
|
|
171
|
-
if (asChild && React.isValidElement(resolvedChildren)) {
|
|
172
|
-
const child = resolvedChildren;
|
|
173
|
-
return React.cloneElement(child, {
|
|
174
|
-
...props,
|
|
175
|
-
className: twMerge(String(child.props.className ?? ""), classes),
|
|
176
|
-
...(disabled ? { "aria-disabled": true } : {}),
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
190
|
const confirmDef = action?.confirmation;
|
|
180
191
|
const confirmVariant = confirmDef?.confirmKind
|
|
181
192
|
? (ACTION_KIND_VARIANT[confirmDef.confirmKind] ?? "primary")
|
|
182
193
|
: "primary";
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
194
|
+
// Built once and rendered alongside EITHER the asChild clone or the plain
|
|
195
|
+
// <button> below — this must never live inside an early return for only
|
|
196
|
+
// one of those two branches, or the other branch can never open a
|
|
197
|
+
// confirmation dialog at all (this was the actual asChild bug: the early
|
|
198
|
+
// return happened before this JSX was ever reached).
|
|
199
|
+
const confirmPortal = confirmOpen && confirmDef && typeof document !== "undefined" && createPortal(_jsx("div", { role: "dialog", "aria-modal": "true", "aria-labelledby": "appkit-action-confirm-title", style: {
|
|
200
|
+
position: "fixed", inset: 0, zIndex: "var(--appkit-z-confirm, 1000)",
|
|
201
|
+
display: "flex", alignItems: "center", justifyContent: "center",
|
|
202
|
+
background: "rgba(0,0,0,0.45)", backdropFilter: "blur(2px)",
|
|
203
|
+
}, onClick: (e) => { if (e.target === e.currentTarget)
|
|
204
|
+
setConfirmOpen(false); }, children: _jsxs("div", { style: {
|
|
205
|
+
background: "var(--appkit-color-surface)",
|
|
206
|
+
borderRadius: "var(--appkit-radius-lg, 12px)",
|
|
207
|
+
padding: "1.5rem",
|
|
208
|
+
maxWidth: "380px", width: "calc(100% - 2rem)",
|
|
209
|
+
boxShadow: "var(--appkit-shadow-lg, 0 20px 60px rgba(0,0,0,0.2))",
|
|
210
|
+
}, children: [_jsx("p", { id: "appkit-action-confirm-title", style: { fontWeight: 600, marginBottom: "0.5rem", fontSize: "1rem" }, children: confirmDef.title }), _jsx("p", { style: { fontSize: "0.875rem", color: "var(--appkit-color-text-muted)", marginBottom: "1.25rem" }, children: confirmDef.body }), _jsxs("div", { style: { display: "flex", gap: "0.5rem", justifyContent: "flex-end" }, children: [_jsx(Button, { variant: "ghost", size: "sm", onClick: () => setConfirmOpen(false), children: confirmDef.cancelLabel ?? "Cancel" }), _jsx(Button, { variant: confirmVariant, size: "sm", onClick: handleConfirm, children: confirmDef.confirmLabel })] })] }) }), document.body);
|
|
211
|
+
if (asChild && React.isValidElement(resolvedChildren)) {
|
|
212
|
+
const child = resolvedChildren;
|
|
213
|
+
// Never spread the caller's raw onClick here — it must go through
|
|
214
|
+
// handleClick so a configured action.confirmation dialog still gates
|
|
215
|
+
// the click even when rendering as a cloned child (e.g. next/link).
|
|
216
|
+
const { onClick: _rawOnClick, ...restProps } = props;
|
|
217
|
+
return (_jsxs(_Fragment, { children: [React.cloneElement(child, {
|
|
218
|
+
...restProps,
|
|
219
|
+
className: twMerge(String(child.props.className ?? ""), classes),
|
|
220
|
+
...(disabled ? { "aria-disabled": true } : {}),
|
|
221
|
+
onClick: handleClick,
|
|
222
|
+
}), confirmPortal] }));
|
|
223
|
+
}
|
|
224
|
+
return (_jsxs(_Fragment, { children: [_jsxs("button", { className: classes, disabled: disabled || isLoading, "aria-busy": isLoading || undefined, ...props, "aria-label": resolvedAriaLabel, onClick: handleClick, children: [isLoading && (_jsx(Loader2, { className: "appkit-button__spinner", "aria-hidden": "true" })), isLoading ? (_jsx("span", { className: "appkit-button__content appkit-button__content--loading", children: resolvedChildren })) : (_jsx("span", { className: "appkit-button__content", children: resolvedChildren }))] }), confirmPortal] }));
|
|
195
225
|
}
|
|
@@ -7,12 +7,14 @@ export function DynamicBgDiv({ color, background, textColor, className = "", chi
|
|
|
7
7
|
const el = ref.current;
|
|
8
8
|
if (!el)
|
|
9
9
|
return;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
// Explicitly clear every property this component owns before
|
|
11
|
+
// (re-)applying — otherwise a value set on a previous render (e.g. a
|
|
12
|
+
// `background` gradient) stays in the inline style forever once that
|
|
13
|
+
// prop becomes undefined, even though a sibling prop like `color` is
|
|
14
|
+
// now supposed to take over.
|
|
15
|
+
el.style.background = background ?? "";
|
|
16
|
+
el.style.backgroundColor = !background && color ? color : "";
|
|
17
|
+
el.style.color = textColor ?? "";
|
|
16
18
|
}, [background, color, textColor]);
|
|
17
19
|
return (_jsx("div", { ref: ref, className: className, "aria-hidden": ariaHidden, children: children }));
|
|
18
20
|
}
|
|
@@ -17,7 +17,7 @@ export function FormField({ label, name, card = false, type = "text", value = ""
|
|
|
17
17
|
const errorId = `${inputId}-error`;
|
|
18
18
|
const describedBy = showError ? errorId : undefined;
|
|
19
19
|
if (type === "image" && onUpload) {
|
|
20
|
-
return (_jsxs("div", { className: card ? CARD_CLASS : BASE_CLASS, "data-section": "formfield-div-505", children: [_jsx(ImageUpload, { currentImage: value || undefined, onUpload: onUpload, onChange: (url) => onChange?.(url), label: label ? `${label}${required ? " *" : ""}` : undefined, helperText: hint ?? helpText, captureSource: captureSource ?? "file-only", accept: accept, maxSizeMB: maxSizeMB }), showError ? (_jsx(Text, { id: errorId, size: "sm", variant: "error", className: "appkit-form-field__error", role: "alert", children: error })) : null] }));
|
|
20
|
+
return (_jsxs("div", { className: card ? CARD_CLASS : BASE_CLASS, "data-section": "formfield-div-505", children: [_jsx("div", { "aria-disabled": disabled || undefined, className: disabled ? "pointer-events-none opacity-60" : undefined, children: _jsx(ImageUpload, { currentImage: value || undefined, onUpload: onUpload, onChange: (url) => onChange?.(url), label: label ? `${label}${required ? " *" : ""}` : undefined, helperText: hint ?? helpText, captureSource: captureSource ?? "file-only", accept: accept, maxSizeMB: maxSizeMB }) }), showError ? (_jsx(Text, { id: errorId, size: "sm", variant: "error", className: "appkit-form-field__error", role: "alert", children: error })) : null] }));
|
|
21
21
|
}
|
|
22
22
|
if (type === "media" && onUpload) {
|
|
23
23
|
return (_jsxs("div", { className: card ? CARD_CLASS : BASE_CLASS, "data-section": "formfield-div-506", children: [_jsx(MediaUploadField, { label: `${label || name}${required ? " *" : ""}`, value: value, onChange: (url) => onChange?.(url), onUpload: onUpload, disabled: disabled, helperText: hint ?? helpText, captureSource: captureSource ?? "file-only", captureMode: captureMode ?? "both", accept: accept, maxSizeMB: maxSizeMB }), showError ? (_jsx(Text, { id: errorId, size: "sm", variant: "error", className: "appkit-form-field__error", role: "alert", children: error })) : null] }));
|
|
@@ -194,23 +194,34 @@ export function HorizontalScroller({ children, className = "", gap = 16, snapToI
|
|
|
194
194
|
return () => clearInterval(autoScrollTimer.current);
|
|
195
195
|
}, [autoScroll, isPaused, autoScrollInterval, containerRef]);
|
|
196
196
|
useEffect(() => {
|
|
197
|
-
if (!perView)
|
|
197
|
+
if (!perView && !loop)
|
|
198
198
|
return;
|
|
199
199
|
const el = containerRef.current;
|
|
200
200
|
if (!el)
|
|
201
201
|
return;
|
|
202
202
|
const observer = new ResizeObserver(([entry]) => {
|
|
203
203
|
const w = entry.contentRect.width;
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
204
|
+
if (perView) {
|
|
205
|
+
const count = resolvePerView(perView, w);
|
|
206
|
+
if (count > 0) {
|
|
207
|
+
setColCount(count);
|
|
208
|
+
setItemWidth((w - (count - 1) * gap) / count);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
// loop is true but no perView hint was given: items render at their
|
|
213
|
+
// natural width, so measure a real rendered item to get the scroll
|
|
214
|
+
// stride the clone-buffer offset / edge teleporter need — without
|
|
215
|
+
// this, itemWidth never resolves and loop mode never initializes.
|
|
216
|
+
const item = el.querySelector(".appkit-hscroller__item");
|
|
217
|
+
if (item)
|
|
218
|
+
setItemWidth(item.getBoundingClientRect().width);
|
|
208
219
|
}
|
|
209
220
|
updateExtents();
|
|
210
221
|
});
|
|
211
222
|
observer.observe(el);
|
|
212
223
|
return () => observer.disconnect();
|
|
213
|
-
}, [perView, gap, containerRef, updateExtents]);
|
|
224
|
+
}, [perView, loop, gap, containerRef, updateExtents]);
|
|
214
225
|
// Recompute extents when content size changes (itemWidth resolved, items count changes).
|
|
215
226
|
useEffect(() => {
|
|
216
227
|
updateExtents();
|
|
@@ -15,7 +15,14 @@ export interface IframeProps extends Omit<IframeHTMLAttributes<HTMLIFrameElement
|
|
|
15
15
|
aspect?: IframeAspect;
|
|
16
16
|
/** Rounded corners preset. Default `"lg"`. */
|
|
17
17
|
rounded?: IframeRounded;
|
|
18
|
-
/**
|
|
18
|
+
/**
|
|
19
|
+
* Sandbox attribute. Default is `"allow-same-origin allow-scripts
|
|
20
|
+
* allow-popups allow-forms"` — permissive enough for trusted third-party
|
|
21
|
+
* embeds (payment checkout panels, YouTube). Combining `allow-same-origin`
|
|
22
|
+
* with `allow-scripts` lets same-origin framed content remove its own
|
|
23
|
+
* sandbox restrictions, so pass a tighter override for any `src` that
|
|
24
|
+
* isn't a fully-trusted origin.
|
|
25
|
+
*/
|
|
19
26
|
sandbox?: string;
|
|
20
27
|
}
|
|
21
28
|
export declare function Iframe({ src, title, aspect, rounded, sandbox, loading, ...rest }: IframeProps): import("react").JSX.Element;
|
|
@@ -184,7 +184,7 @@ export interface ContainerProps extends React.HTMLAttributes<HTMLElement>, Surfa
|
|
|
184
184
|
as?: React.ElementType;
|
|
185
185
|
children?: React.ReactNode;
|
|
186
186
|
}
|
|
187
|
-
export declare function Container({ size, as, surface, padding, rounded, border, shadow, className, children, ...props }: ContainerProps): React.JSX.Element;
|
|
187
|
+
export declare function Container({ size, as, surface, padding, paddingX, paddingY, rounded, roundedTop, roundedBottom, border, shadow, overflow, className, children, ...props }: ContainerProps): React.JSX.Element;
|
|
188
188
|
/**
|
|
189
189
|
* Vertical flex column. Use instead of `<div className="flex flex-col gap-4" data-section="layout-div-535">`.
|
|
190
190
|
*
|
|
@@ -245,7 +245,7 @@ export interface StackProps extends React.HTMLAttributes<HTMLElement>, SurfacePr
|
|
|
245
245
|
as?: React.ElementType;
|
|
246
246
|
children?: React.ReactNode;
|
|
247
247
|
}
|
|
248
|
-
export declare function Stack({ gap, centered, align, justify, textSize, textWeight, color, divide, direction, wrap, smAlign, as, surface, padding, paddingX, paddingY, rounded, border, shadow, className, children, ...props }: StackProps): React.JSX.Element;
|
|
248
|
+
export declare function Stack({ gap, centered, align, justify, textSize, textWeight, color, divide, direction, wrap, smAlign, as, surface, padding, paddingX, paddingY, rounded, roundedTop, roundedBottom, border, shadow, overflow, className, children, ...props }: StackProps): React.JSX.Element;
|
|
249
249
|
/**
|
|
250
250
|
* Horizontal flex row. Use instead of `<div className="flex items-center gap-3" data-section="layout-div-536">`.
|
|
251
251
|
*
|
|
@@ -315,7 +315,7 @@ declare const TEXT_COLOR_MAP: {
|
|
|
315
315
|
readonly info: "appkit-color--info";
|
|
316
316
|
};
|
|
317
317
|
type TextColorKey = keyof typeof TEXT_COLOR_MAP;
|
|
318
|
-
export declare function Row({ gap, centered, align, justify, textSize, textWeight, color, wrap, oddEven, divide, as, surface, padding, paddingX, paddingY, rounded, border, shadow, className, children, ...props }: RowProps): React.JSX.Element;
|
|
318
|
+
export declare function Row({ gap, centered, align, justify, textSize, textWeight, color, wrap, oddEven, divide, as, surface, padding, paddingX, paddingY, rounded, roundedTop, roundedBottom, border, shadow, overflow, className, children, ...props }: RowProps): React.JSX.Element;
|
|
319
319
|
/**
|
|
320
320
|
* Responsive CSS grid. Use instead of `<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4" data-section="layout-div-537">`.
|
|
321
321
|
*
|
|
@@ -355,5 +355,5 @@ export interface GridProps extends React.HTMLAttributes<HTMLElement>, SurfacePro
|
|
|
355
355
|
as?: React.ElementType;
|
|
356
356
|
children?: React.ReactNode;
|
|
357
357
|
}
|
|
358
|
-
export declare function Grid({ cols, gap, align, justify, as, surface, padding, rounded, border, shadow, className, children, ...props }: GridProps): React.JSX.Element;
|
|
358
|
+
export declare function Grid({ cols, gap, align, justify, as, surface, padding, paddingX, paddingY, rounded, roundedTop, roundedBottom, border, shadow, overflow, className, children, ...props }: GridProps): React.JSX.Element;
|
|
359
359
|
export {};
|
|
@@ -154,9 +154,9 @@ const JUSTIFY_MAP = {
|
|
|
154
154
|
around: "appkit-justify--around",
|
|
155
155
|
evenly: "appkit-justify--evenly",
|
|
156
156
|
};
|
|
157
|
-
export function Container({ size = "2xl", as, surface, padding, rounded, border, shadow, className = "", children, ...props }) {
|
|
157
|
+
export function Container({ size = "2xl", as, surface, padding, paddingX, paddingY, rounded, roundedTop, roundedBottom, border, shadow, overflow, className = "", children, ...props }) {
|
|
158
158
|
const Tag = (as ?? "div");
|
|
159
|
-
return (_jsx(Tag, { className: ["appkit-container", CONTAINER_MAP[size], buildSurfaceClasses({ surface, padding, rounded, border, shadow }), className]
|
|
159
|
+
return (_jsx(Tag, { className: ["appkit-container", CONTAINER_MAP[size], buildSurfaceClasses({ surface, padding, paddingX, paddingY, rounded, roundedTop, roundedBottom, border, shadow, overflow }), className]
|
|
160
160
|
.filter(Boolean)
|
|
161
161
|
.join(" "), ...props, children: children }));
|
|
162
162
|
}
|
|
@@ -178,7 +178,7 @@ function resolveDivideClass(divide, axis) {
|
|
|
178
178
|
const base = `appkit-${axis}--divide`;
|
|
179
179
|
return divide === "subtle" ? `${base}-subtle` : base;
|
|
180
180
|
}
|
|
181
|
-
export function Stack({ gap = "md", centered = false, align = "stretch", justify = "start", textSize, textWeight, color, divide, direction, wrap = false, smAlign, as, surface, padding, paddingX, paddingY, rounded, border, shadow, className = "", children, ...props }) {
|
|
181
|
+
export function Stack({ gap = "md", centered = false, align = "stretch", justify = "start", textSize, textWeight, color, divide, direction, wrap = false, smAlign, as, surface, padding, paddingX, paddingY, rounded, roundedTop, roundedBottom, border, shadow, overflow, className = "", children, ...props }) {
|
|
182
182
|
const Tag = (as ?? "div");
|
|
183
183
|
const classes = [
|
|
184
184
|
"appkit-stack",
|
|
@@ -193,7 +193,7 @@ export function Stack({ gap = "md", centered = false, align = "stretch", justify
|
|
|
193
193
|
wrap ? "flex-wrap" : "",
|
|
194
194
|
smAlign ? STACK_SM_ALIGN_MAP[smAlign] : "",
|
|
195
195
|
resolveDivideClass(divide, "stack"),
|
|
196
|
-
buildSurfaceClasses({ surface, padding, paddingX, paddingY, rounded, border, shadow }),
|
|
196
|
+
buildSurfaceClasses({ surface, padding, paddingX, paddingY, rounded, roundedTop, roundedBottom, border, shadow, overflow }),
|
|
197
197
|
className,
|
|
198
198
|
]
|
|
199
199
|
.filter(Boolean)
|
|
@@ -231,7 +231,7 @@ const ROW_ODD_EVEN_MAP = {
|
|
|
231
231
|
none: "",
|
|
232
232
|
zebra: "even:bg-[var(--appkit-color-surface-input)] dark:even:bg-[var(--appkit-color-bg)]",
|
|
233
233
|
};
|
|
234
|
-
export function Row({ gap = "md", centered = false, align = "center", justify = "start", textSize, textWeight, color, wrap = false, oddEven, divide, as, surface, padding, paddingX, paddingY, rounded, border, shadow, className = "", children, ...props }) {
|
|
234
|
+
export function Row({ gap = "md", centered = false, align = "center", justify = "start", textSize, textWeight, color, wrap = false, oddEven, divide, as, surface, padding, paddingX, paddingY, rounded, roundedTop, roundedBottom, border, shadow, overflow, className = "", children, ...props }) {
|
|
235
235
|
const Tag = (as ?? "div");
|
|
236
236
|
const classes = [
|
|
237
237
|
"appkit-row",
|
|
@@ -244,14 +244,14 @@ export function Row({ gap = "md", centered = false, align = "center", justify =
|
|
|
244
244
|
textWeight ? TEXT_WEIGHT_MAP[textWeight] : "",
|
|
245
245
|
color ? TEXT_COLOR_MAP[color] : "",
|
|
246
246
|
resolveDivideClass(divide, "row"),
|
|
247
|
-
buildSurfaceClasses({ surface, padding, paddingX, paddingY, rounded, border, shadow }),
|
|
247
|
+
buildSurfaceClasses({ surface, padding, paddingX, paddingY, rounded, roundedTop, roundedBottom, border, shadow, overflow }),
|
|
248
248
|
className,
|
|
249
249
|
]
|
|
250
250
|
.filter(Boolean)
|
|
251
251
|
.join(" ");
|
|
252
252
|
return (_jsx(Tag, { className: classes, ...props, children: children }));
|
|
253
253
|
}
|
|
254
|
-
export function Grid({ cols, gap = "md", align, justify, as, surface, padding, rounded, border, shadow, className = "", children, ...props }) {
|
|
254
|
+
export function Grid({ cols, gap = "md", align, justify, as, surface, padding, paddingX, paddingY, rounded, roundedTop, roundedBottom, border, shadow, overflow, className = "", children, ...props }) {
|
|
255
255
|
const Tag = (as ?? "div");
|
|
256
256
|
const baseClass = cols !== undefined ? GRID_MAP[cols] : "appkit-grid";
|
|
257
257
|
const classes = [
|
|
@@ -259,7 +259,7 @@ export function Grid({ cols, gap = "md", align, justify, as, surface, padding, r
|
|
|
259
259
|
GAP_MAP[gap],
|
|
260
260
|
align ? ITEMS_MAP[align] : "",
|
|
261
261
|
justify ? JUSTIFY_MAP[justify] : "",
|
|
262
|
-
buildSurfaceClasses({ surface, padding, rounded, border, shadow }),
|
|
262
|
+
buildSurfaceClasses({ surface, padding, paddingX, paddingY, rounded, roundedTop, roundedBottom, border, shadow, overflow }),
|
|
263
263
|
className,
|
|
264
264
|
]
|
|
265
265
|
.filter(Boolean)
|
|
@@ -108,7 +108,10 @@ export function AnimatedRow({ delay = 0, children, className, ...props }) {
|
|
|
108
108
|
}
|
|
109
109
|
export function Draggable({ axis, constraints, dragElastic = 0.1, children, ...props }) {
|
|
110
110
|
const reduced = useReducedMotion();
|
|
111
|
-
|
|
111
|
+
// `axis` defaults to unrestricted (true) when omitted, but an explicit
|
|
112
|
+
// `axis={false}` must actually disable dragging — `axis || true` always
|
|
113
|
+
// collapsed a falsy axis back to `true`, making `axis={false}` a no-op.
|
|
114
|
+
const drag = reduced ? false : (axis ?? true);
|
|
112
115
|
return (_jsx(motion.div, { drag: drag, dragConstraints: constraints, dragElastic: dragElastic, ...props, children: children }));
|
|
113
116
|
}
|
|
114
117
|
export function Swipeable({ onSwipeLeft, onSwipeRight, threshold = 50, children, ...props }) {
|
|
@@ -47,7 +47,7 @@ export function OtpInput({ length = 6, value, onChange, label, error, helperText
|
|
|
47
47
|
const lastFilled = Math.min(sanitized.length, length - 1);
|
|
48
48
|
focusAt(lastFilled);
|
|
49
49
|
}
|
|
50
|
-
return (_jsxs("div", { className: "w-full", children: [label && (_jsx(Label, { htmlFor: `${inputId}-0`, className: "appkit-form-field__label mb-2", children: label })), _jsx("div", { className: "flex gap-2", role: "group", "aria-labelledby": label ? `${inputId}-label` : undefined, children: digits.map((digit, i) => (_jsx("input", { ref: (el) => { inputsRef.current[i] = el; }, id: i === 0 ? `${inputId}-0` : undefined, type: "text", inputMode: inputMode, maxLength: 1, value: digit, disabled: disabled, autoFocus: autoFocus && i === 0, autoComplete: "one-time-code", "aria-label": `Digit ${i + 1} of ${length}`, className: [
|
|
50
|
+
return (_jsxs("div", { className: "w-full", children: [label && (_jsx(Label, { id: `${inputId}-label`, htmlFor: `${inputId}-0`, className: "appkit-form-field__label mb-2", children: label })), _jsx("div", { className: "flex gap-2", role: "group", "aria-labelledby": label ? `${inputId}-label` : undefined, children: digits.map((digit, i) => (_jsx("input", { ref: (el) => { inputsRef.current[i] = el; }, id: i === 0 ? `${inputId}-0` : undefined, type: "text", inputMode: inputMode, maxLength: 1, value: digit, disabled: disabled, autoFocus: autoFocus && i === 0, autoComplete: "one-time-code", "aria-label": `Digit ${i + 1} of ${length}`, className: [
|
|
51
51
|
"appkit-input",
|
|
52
52
|
"appkit-otp-input",
|
|
53
53
|
error ? "appkit-input--error" : "",
|
|
@@ -64,15 +64,26 @@ export function PaginatedSelect(props) {
|
|
|
64
64
|
const [drawerOpen, setDrawerOpen] = useState(false);
|
|
65
65
|
const containerRef = useRef(null);
|
|
66
66
|
const labelMap = useRef(new Map());
|
|
67
|
+
// Monotonic counter guarding against out-of-order async responses: a
|
|
68
|
+
// slower earlier request (e.g. for an already-abandoned search query)
|
|
69
|
+
// must never overwrite state after a faster, more recent request resolved.
|
|
70
|
+
const requestIdRef = useRef(0);
|
|
71
|
+
const wasOpenRef = useRef(false);
|
|
67
72
|
const hasCreate = Boolean(createLabel && (renderCreateForm ?? (createFields && onCreateSubmit)));
|
|
68
73
|
const resolvedOptions = options ?? asyncOptions;
|
|
69
74
|
resolvedOptions.forEach((o) => labelMap.current.set(o.value, o.label));
|
|
70
75
|
const load = useCallback(async (search, nextPage, reset = false) => {
|
|
71
76
|
if (!loadOptions)
|
|
72
77
|
return;
|
|
78
|
+
const requestId = ++requestIdRef.current;
|
|
73
79
|
setLoading(true);
|
|
74
80
|
try {
|
|
75
81
|
const response = await loadOptions(search, nextPage);
|
|
82
|
+
// A newer request (new search, or the dropdown reopened) was issued
|
|
83
|
+
// while this one was in flight — its response is stale, discard it
|
|
84
|
+
// rather than clobbering state a more recent request already set.
|
|
85
|
+
if (requestId !== requestIdRef.current)
|
|
86
|
+
return;
|
|
76
87
|
setAsyncOptions((prev) => {
|
|
77
88
|
const merged = reset ? response.items : [...prev, ...response.items];
|
|
78
89
|
merged.forEach((o) => labelMap.current.set(o.value, o.label));
|
|
@@ -82,13 +93,28 @@ export function PaginatedSelect(props) {
|
|
|
82
93
|
setHasMore(response.hasMore);
|
|
83
94
|
}
|
|
84
95
|
finally {
|
|
85
|
-
|
|
96
|
+
if (requestId === requestIdRef.current)
|
|
97
|
+
setLoading(false);
|
|
86
98
|
}
|
|
87
99
|
}, [loadOptions]);
|
|
88
100
|
useEffect(() => {
|
|
89
|
-
if (!open || !loadOptions)
|
|
101
|
+
if (!open || !loadOptions) {
|
|
102
|
+
wasOpenRef.current = false;
|
|
90
103
|
return;
|
|
91
|
-
|
|
104
|
+
}
|
|
105
|
+
// Load immediately the moment the dropdown opens; debounce subsequent
|
|
106
|
+
// reloads triggered by the user typing so every keystroke doesn't fire
|
|
107
|
+
// a new request.
|
|
108
|
+
const isFreshOpen = !wasOpenRef.current;
|
|
109
|
+
wasOpenRef.current = true;
|
|
110
|
+
if (isFreshOpen) {
|
|
111
|
+
void load(query, 1, true);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const timer = setTimeout(() => {
|
|
115
|
+
void load(query, 1, true);
|
|
116
|
+
}, 300);
|
|
117
|
+
return () => clearTimeout(timer);
|
|
92
118
|
}, [open, query, load, loadOptions]);
|
|
93
119
|
useEffect(() => {
|
|
94
120
|
if (!open || !containerRef.current)
|
|
@@ -6,12 +6,17 @@ function getPageNumbers(currentPage, totalPages, maxVisible) {
|
|
|
6
6
|
return Array.from({ length: totalPages }, (_, i) => i + 1);
|
|
7
7
|
}
|
|
8
8
|
const pages = [];
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
// Split unevenly (floor/ceil) around (maxVisible - 1) rather than using a
|
|
10
|
+
// single halved value on both sides — `Math.floor(maxVisible / 2)` on
|
|
11
|
+
// both sides produces a window of `2*halfVisible + 1`, which is one page
|
|
12
|
+
// too many whenever maxVisible is even.
|
|
13
|
+
const before = Math.floor((maxVisible - 1) / 2);
|
|
14
|
+
const after = Math.ceil((maxVisible - 1) / 2);
|
|
15
|
+
let startPage = Math.max(1, currentPage - before);
|
|
16
|
+
let endPage = Math.min(totalPages, currentPage + after);
|
|
17
|
+
if (currentPage <= before)
|
|
13
18
|
endPage = maxVisible;
|
|
14
|
-
if (currentPage >= totalPages -
|
|
19
|
+
if (currentPage >= totalPages - after)
|
|
15
20
|
startPage = totalPages - maxVisible + 1;
|
|
16
21
|
if (startPage > 1) {
|
|
17
22
|
pages.push(1);
|
|
@@ -1,12 +1,69 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useEffect, useMemo, useRef } from "react";
|
|
4
|
+
// Matches exactly what this editor's own toolbar (bold/italic/underline/
|
|
5
|
+
// lists/link/clear-formatting) and typing can legitimately produce.
|
|
6
|
+
// Anything else — <script>, <img onerror=...>, <iframe>, <svg>, <style>,
|
|
7
|
+
// <form>, event-handler attributes — can only have arrived via paste, and is
|
|
8
|
+
// dropped entirely rather than risk it either executing live in the editor
|
|
9
|
+
// or being persisted and re-rendered elsewhere as stored XSS.
|
|
10
|
+
const ALLOWED_TAGS = new Set([
|
|
11
|
+
"B", "STRONG", "I", "EM", "U", "S", "STRIKE",
|
|
12
|
+
"UL", "OL", "LI", "A", "BR", "DIV", "SPAN", "P",
|
|
13
|
+
]);
|
|
14
|
+
function isSafeHref(href) {
|
|
15
|
+
const trimmed = href.trim();
|
|
16
|
+
// Same rule as string.formatter.ts's applyMark: allow http(s)/mailto, a
|
|
17
|
+
// single leading "/" (same-site relative path, NOT "//host" protocol-
|
|
18
|
+
// relative), or "#" — reject everything else including javascript:.
|
|
19
|
+
return /^(https?:\/\/|mailto:|\/(?!\/)|#)/i.test(trimmed);
|
|
20
|
+
}
|
|
21
|
+
function sanitizeRichTextHtml(html) {
|
|
22
|
+
if (typeof document === "undefined" || !html)
|
|
23
|
+
return "";
|
|
24
|
+
const template = document.createElement("template");
|
|
25
|
+
template.innerHTML = html;
|
|
26
|
+
const walk = (root) => {
|
|
27
|
+
Array.from(root.childNodes).forEach((child) => {
|
|
28
|
+
if (child.nodeType === Node.ELEMENT_NODE) {
|
|
29
|
+
const el = child;
|
|
30
|
+
if (!ALLOWED_TAGS.has(el.tagName)) {
|
|
31
|
+
root.removeChild(el);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
Array.from(el.attributes).forEach((attr) => {
|
|
35
|
+
if (el.tagName === "A" && attr.name.toLowerCase() === "href") {
|
|
36
|
+
if (!isSafeHref(attr.value))
|
|
37
|
+
el.setAttribute("href", "#");
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
el.removeAttribute(attr.name);
|
|
41
|
+
});
|
|
42
|
+
walk(el);
|
|
43
|
+
}
|
|
44
|
+
else if (child.nodeType !== Node.TEXT_NODE) {
|
|
45
|
+
root.removeChild(child);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
walk(template.content);
|
|
50
|
+
return template.innerHTML;
|
|
51
|
+
}
|
|
4
52
|
export function RichTextEditor({ value, onChange, disabled = false, className = "", minHeightClassName = "min-h-[180px]", placeholder = "Write formatted content...", }) {
|
|
5
53
|
const editorRef = useRef(null);
|
|
6
54
|
const emitChange = () => {
|
|
7
55
|
if (!editorRef.current)
|
|
8
56
|
return;
|
|
9
|
-
|
|
57
|
+
const raw = editorRef.current.innerHTML;
|
|
58
|
+
const sanitized = sanitizeRichTextHtml(raw);
|
|
59
|
+
// Only touch the live DOM (which would reset caret position) when
|
|
60
|
+
// sanitization actually changed something — a no-op for every normal
|
|
61
|
+
// keystroke/toolbar action, since those only ever produce allowlisted
|
|
62
|
+
// markup; only a malicious paste triggers this branch.
|
|
63
|
+
if (sanitized !== raw) {
|
|
64
|
+
editorRef.current.innerHTML = sanitized;
|
|
65
|
+
}
|
|
66
|
+
onChange(sanitized);
|
|
10
67
|
};
|
|
11
68
|
const exec = (command, commandValue) => {
|
|
12
69
|
if (disabled || typeof document === "undefined")
|
|
@@ -51,8 +108,12 @@ export function RichTextEditor({ value, onChange, disabled = false, className =
|
|
|
51
108
|
const editor = editorRef.current;
|
|
52
109
|
if (!editor)
|
|
53
110
|
return;
|
|
54
|
-
|
|
55
|
-
|
|
111
|
+
// Sanitize on every incoming `value` too — this is the stored-XSS path:
|
|
112
|
+
// previously-saved content (e.g. loaded from Firestore) must not be
|
|
113
|
+
// trusted just because it was already persisted.
|
|
114
|
+
const safeValue = sanitizeRichTextHtml(value);
|
|
115
|
+
if (editor.innerHTML !== safeValue) {
|
|
116
|
+
editor.innerHTML = safeValue;
|
|
56
117
|
}
|
|
57
118
|
}, [value]);
|
|
58
119
|
return (_jsxs("div", { className: `appkit-rich-text-editor rounded-lg border border-zinc-200 bg-[var(--appkit-color-surface)] border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] ${className}`, "data-section": "richtexteditor-div-582", children: [_jsx("div", { className: "appkit-rich-text-editor__toolbar flex flex-wrap gap-1 border-b border-zinc-200 p-2 border-[var(--appkit-color-border)]", "data-section": "richtexteditor-div-583", children: toolbarActions.map((action) => (_jsx("button", { type: "button", title: action.title, onClick: action.run, disabled: disabled, className: "appkit-rich-text-editor__btn rounded px-2 py-1 text-xs font-medium text-zinc-700 transition hover:bg-zinc-50 disabled:cursor-not-allowed disabled:opacity-50 text-[var(--appkit-color-text-muted)] hover:bg-[var(--appkit-color-surface-elevated)]", children: action.label }, action.title))) }), _jsx("div", { ref: editorRef, role: "textbox", "aria-label": "Rich text editor", contentEditable: !disabled, suppressContentEditableWarning: true, "data-placeholder": placeholder, onInput: emitChange, onBlur: emitChange, className: `prose prose-sm max-w-none p-3 focus:outline-none dark:prose-invert ${minHeightClassName} ${disabled ? "cursor-not-allowed opacity-70" : ""}` })] }));
|
|
@@ -87,7 +87,7 @@ export interface ArticleProps extends React.HTMLAttributes<HTMLElement>, Surface
|
|
|
87
87
|
color?: SemanticColor;
|
|
88
88
|
children?: React.ReactNode;
|
|
89
89
|
}
|
|
90
|
-
export declare function Article({ className, surface, padding, rounded, border, shadow, color, children, ...props }: ArticleProps): React.JSX.Element;
|
|
90
|
+
export declare function Article({ className, surface, padding, paddingX, paddingY, rounded, roundedTop, roundedBottom, border, shadow, overflow, color, children, ...props }: ArticleProps): React.JSX.Element;
|
|
91
91
|
/**
|
|
92
92
|
* Semantic `<main>` element.
|
|
93
93
|
* Wraps the primary content of the document. Should appear only once per page.
|
|
@@ -96,7 +96,7 @@ export interface MainProps extends React.HTMLAttributes<HTMLElement>, SurfacePro
|
|
|
96
96
|
color?: SemanticColor;
|
|
97
97
|
children: React.ReactNode;
|
|
98
98
|
}
|
|
99
|
-
export declare function Main({ className, surface, padding, paddingX, paddingY, rounded, border, shadow, color, children, ...props }: MainProps): React.JSX.Element;
|
|
99
|
+
export declare function Main({ className, surface, padding, paddingX, paddingY, rounded, roundedTop, roundedBottom, border, shadow, overflow, color, children, ...props }: MainProps): React.JSX.Element;
|
|
100
100
|
/**
|
|
101
101
|
* Semantic `<aside>` element.
|
|
102
102
|
* Use for supplementary content tangentially related to the main content:
|
|
@@ -134,7 +134,7 @@ export interface NavProps extends React.HTMLAttributes<HTMLElement>, SurfaceProp
|
|
|
134
134
|
textSize?: "xs" | "sm" | "base" | "lg";
|
|
135
135
|
children: React.ReactNode;
|
|
136
136
|
}
|
|
137
|
-
export declare function Nav({ surface, padding, rounded, border, shadow, spacing, gap, layout, color, textSize, className, children, ...props }: NavProps): React.JSX.Element;
|
|
137
|
+
export declare function Nav({ surface, padding, paddingX, paddingY, rounded, roundedTop, roundedBottom, border, shadow, overflow, spacing, gap, layout, color, textSize, className, children, ...props }: NavProps): React.JSX.Element;
|
|
138
138
|
/**
|
|
139
139
|
* Semantic `<header>` element for block-level component headers.
|
|
140
140
|
* Use inside `Section`, `Article`, or card bodies — NOT as the page-level header.
|
|
@@ -151,7 +151,7 @@ export declare function Nav({ surface, padding, rounded, border, shadow, spacing
|
|
|
151
151
|
export interface BlockHeaderProps extends React.HTMLAttributes<HTMLElement>, SurfaceProps {
|
|
152
152
|
children: React.ReactNode;
|
|
153
153
|
}
|
|
154
|
-
export declare function BlockHeader({ className, surface, padding, rounded, border, shadow, children, ...props }: BlockHeaderProps): React.JSX.Element;
|
|
154
|
+
export declare function BlockHeader({ className, surface, padding, paddingX, paddingY, rounded, roundedTop, roundedBottom, border, shadow, overflow, children, ...props }: BlockHeaderProps): React.JSX.Element;
|
|
155
155
|
/**
|
|
156
156
|
* Semantic `<footer>` element for block-level component footers.
|
|
157
157
|
* Use inside `Section`, `Article`, or card bodies — NOT as the page-level footer.
|
|
@@ -159,7 +159,7 @@ export declare function BlockHeader({ className, surface, padding, rounded, bord
|
|
|
159
159
|
export interface BlockFooterProps extends React.HTMLAttributes<HTMLElement>, SurfaceProps {
|
|
160
160
|
children: React.ReactNode;
|
|
161
161
|
}
|
|
162
|
-
export declare function BlockFooter({ className, surface, padding, rounded, border, shadow, children, ...props }: BlockFooterProps): React.JSX.Element;
|
|
162
|
+
export declare function BlockFooter({ className, surface, padding, paddingX, paddingY, rounded, roundedTop, roundedBottom, border, shadow, overflow, children, ...props }: BlockFooterProps): React.JSX.Element;
|
|
163
163
|
/**
|
|
164
164
|
* Semantic `<ul>` (unordered list) element.
|
|
165
165
|
*
|
|
@@ -266,7 +266,7 @@ export interface TableProps extends Omit<React.TableHTMLAttributes<HTMLTableElem
|
|
|
266
266
|
stickyHeader?: boolean;
|
|
267
267
|
children: React.ReactNode;
|
|
268
268
|
}
|
|
269
|
-
export declare function Table({ variant, size, stickyHeader, className, surface, padding, rounded, border, shadow, children, ...props }: TableProps): React.JSX.Element;
|
|
269
|
+
export declare function Table({ variant, size, stickyHeader, className, surface, padding, paddingX, paddingY, rounded, roundedTop, roundedBottom, border, shadow, overflow, children, ...props }: TableProps): React.JSX.Element;
|
|
270
270
|
type TheadSurface = "none" | "default" | "muted" | "subtle";
|
|
271
271
|
export interface TheadProps extends React.HTMLAttributes<HTMLTableSectionElement> {
|
|
272
272
|
/** Background tone for the header row. */
|
|
@@ -347,16 +347,16 @@ export declare function Code({ color, weight, size, padding, rounded, surface, c
|
|
|
347
347
|
export interface PreProps extends React.HTMLAttributes<HTMLPreElement>, SurfaceProps {
|
|
348
348
|
children: React.ReactNode;
|
|
349
349
|
}
|
|
350
|
-
export declare function Pre({ className, surface, padding, rounded, border, shadow, children, ...props }: PreProps): React.JSX.Element;
|
|
350
|
+
export declare function Pre({ className, surface, padding, paddingX, paddingY, rounded, roundedTop, roundedBottom, border, shadow, overflow, children, ...props }: PreProps): React.JSX.Element;
|
|
351
351
|
export interface BlockquoteProps extends React.BlockquoteHTMLAttributes<HTMLQuoteElement>, SurfaceProps {
|
|
352
352
|
color?: "default" | "primary" | "info" | "warning";
|
|
353
353
|
children: React.ReactNode;
|
|
354
354
|
}
|
|
355
|
-
export declare function Blockquote({ color, className, surface, padding, paddingX, paddingY, rounded, border, shadow, children, ...props }: BlockquoteProps): React.JSX.Element;
|
|
355
|
+
export declare function Blockquote({ color, className, surface, padding, paddingX, paddingY, rounded, roundedTop, roundedBottom, border, shadow, overflow, children, ...props }: BlockquoteProps): React.JSX.Element;
|
|
356
356
|
export interface FigureProps extends React.HTMLAttributes<HTMLElement>, SurfaceProps {
|
|
357
357
|
children: React.ReactNode;
|
|
358
358
|
}
|
|
359
|
-
export declare function Figure({ className, surface, padding, rounded, border, shadow, children, ...props }: FigureProps): React.JSX.Element;
|
|
359
|
+
export declare function Figure({ className, surface, padding, paddingX, paddingY, rounded, roundedTop, roundedBottom, border, shadow, overflow, children, ...props }: FigureProps): React.JSX.Element;
|
|
360
360
|
export interface FigcaptionProps extends React.HTMLAttributes<HTMLElement> {
|
|
361
361
|
children: React.ReactNode;
|
|
362
362
|
}
|
|
@@ -372,7 +372,7 @@ export interface DlProps extends React.HTMLAttributes<HTMLDListElement>, Surface
|
|
|
372
372
|
divide?: boolean | "default" | "subtle";
|
|
373
373
|
children: React.ReactNode;
|
|
374
374
|
}
|
|
375
|
-
export declare function Dl({ variant, divide, className, surface, padding, rounded, border, shadow, children, ...props }: DlProps): React.JSX.Element;
|
|
375
|
+
export declare function Dl({ variant, divide, className, surface, padding, paddingX, paddingY, rounded, roundedTop, roundedBottom, border, shadow, overflow, children, ...props }: DlProps): React.JSX.Element;
|
|
376
376
|
type DtDdColor = "default" | "primary" | "muted" | "faint";
|
|
377
377
|
type DtDdWeight = "normal" | "medium" | "semibold" | "bold";
|
|
378
378
|
export interface DtProps extends React.HTMLAttributes<HTMLElement> {
|