@mohasinac/appkit 3.4.5 → 3.4.6

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.
@@ -115,7 +115,7 @@ function CarouselCardRenderer({ card, isMobile, push, }) {
115
115
  gridRow: String(gridPos.gridRow),
116
116
  gridColumn: String(gridPos.gridColumn),
117
117
  minHeight: isMobile ? 100 : 140,
118
- }, children: [_jsx(CardBackground, { bg: card.background }), !card.isButtonOnly && (_jsxs(_Fragment, { children: [_jsx(Scrim, { direction: "bottom-up", intensity: "strong", className: POSITION_FILL }), _jsxs(Stack, { justify: "end", className: `${POSITION_FILL} md:p-[1.5rem] ${textAlignClass}`, padding: "xs", children: [card.content?.eyebrow && (_jsx(Text, { color: "inverse", shadow: "sm", className: "text-[10px] !/70 mb-0.5 tracking-wider", mdSize: "xs", transform: "uppercase", children: card.content.eyebrow })), card.content?.subtitle && (_jsx(Text, { color: "inverse", shadow: "sm", className: "hidden md:block !/90 mb-0.5 md:mb-2", mdSize: "sm", size: "xs", children: card.content.subtitle })), card.content?.title && (_jsx(Heading, { level: 2, className: `text-[11px] mb-0.5 md:mb-3`, truncate: 2, weight: "bold", shadow: "md", mdSize: "2xl", lgSize: "3xl", style: { color: card.content.textColor ?? "white" }, children: card.content.title })), card.content?.description && (_jsx(Text, { color: "inverse", shadow: "sm", className: `text-[10px] md:text-[0.875rem] !/80 mb-1 md:mb-4`, truncate: true, children: card.content.description })), (card.buttons?.length ?? 0) > 0 && (_jsx(Row, { wrap: true, gap: "xs", className: "md:gap-[0.5rem]", children: (card.buttons ?? []).map((btn, i) => {
118
+ }, children: [_jsx(CardBackground, { bg: card.background }), !card.isButtonOnly && (_jsxs(_Fragment, { children: [_jsx(Scrim, { direction: "bottom-up", intensity: "strong", className: POSITION_FILL }), _jsxs(Stack, { justify: "end", className: `${POSITION_FILL} md:p-[1.5rem] ${textAlignClass}`, padding: "xs", children: [card.content?.eyebrow && (_jsx(Text, { color: "inverse", shadow: "sm", className: "text-[10px] !/70 mb-0.5 tracking-wider", mdSize: "xs", transform: "uppercase", children: card.content.eyebrow })), card.content?.subtitle && (_jsx(Text, { color: "inverse", shadow: "sm", className: "hidden md:block !/90 mb-0.5 md:mb-2", mdSize: "sm", size: "xs", children: card.content.subtitle })), card.content?.title && (_jsx(Heading, { level: 2, className: `text-[11px] mb-0.5 md:mb-3`, truncate: 2, weight: "bold", shadow: "md", mdSize: "2xl", lgSize: "3xl", style: { color: card.content.textColor ?? "white" }, children: card.content.title })), card.content?.description && (_jsx(Text, { color: "inverse", shadow: "sm", className: `text-[10px] md:text-[0.875rem] !/80 mb-1 md:mb-4`, truncate: true, children: card.content.description })), (card.buttons?.length ?? 0) > 0 && (_jsx(Row, { wrap: true, gap: "xs", className: "md:gap-[var(--appkit-space-2)]", children: (card.buttons ?? []).map((btn, i) => {
119
119
  const variant = btn.variant === "link" || btn.variant === "ghost"
120
120
  ? "ghost"
121
121
  : btn.variant;
@@ -184,7 +184,7 @@ export function HeroCarousel({ initialSlides, push } = {}) {
184
184
  return (_jsxs(Section, { ref: sectionRef, className: `relative w-full ${heightClass} overflow-hidden`, "aria-roledescription": "carousel", "aria-label": "Hero carousel", onKeyDown: handleKeyDown, onMouseEnter: () => setIsPaused(true), onMouseLeave: () => setIsPaused(false), onFocus: () => setIsPaused(true), onBlur: () => setIsPaused(false), tabIndex: 0, children: [_jsx(Div, { "aria-live": "polite", "aria-atomic": "true", className: "sr-only", children: `Slide ${currentSlide + 1} of ${slides.length}` }), _jsx(Div, { className: POSITION_FILL, children: _jsx(Div, { layout: "flex", ref: slidesRef, onScroll: handleSlidesScroll, className: "h-full overflow-x-auto scroll-smooth snap-x snap-mandatory [scrollbar-width:none] [&::-webkit-scrollbar]:hidden", style: { gap: 0 }, children: slides.map((slide, slideIndex) => {
185
185
  const slideHeightClass = getSlideHeightClass(slide.settings?.height);
186
186
  const hasCards = slide.cards && slide.cards.length > 0;
187
- return (_jsxs(Div, { className: `snap-start flex-none w-full relative self-stretch bg-neutral-900 ${slideHeightClass}`, children: [_jsx(Div, { className: POSITION_FILL, children: _jsx(SlideBackground, { bg: slide.background, legacy: slide.media, mobileLegacy: slide.mobileMedia, isMobile: isMobile, priority: slideIndex === 0 }) }), slide.overlay && (_jsxs(Div, { className: `${POSITION_FILL} ${FLEX_CENTER} [flex-direction:column] text-center md:px-[4rem] lg:px-[8rem]`, padding: "x-lg", children: [slide.overlay.subtitle && (_jsx(Text, { color: "inverse", shadow: "sm", className: "stagger-1 !/80 mb-1 md:mb-2 tracking-widest", mdSize: "sm", size: "xs", transform: "uppercase", children: slide.overlay.subtitle })), slide.overlay.title && (_jsx(Heading, { color: "inverse", level: 1, className: "stagger-2 font-display ! mb-2 md:mb-4", size: "4xl", shadow: "2xl", mdSize: "6xl", lgSize: "8xl", children: slide.overlay.title })), slide.overlay.description && (_jsx(Text, { color: "inverse", shadow: "sm", className: "stagger-3 !/90 mb-4 md:mb-8 max-w-2xl mx-auto", mdSize: "lg", lgSize: "xl", size: "sm", children: slide.overlay.description })), slide.overlay.button && (_jsx(Div, { className: "stagger-4", children: _jsx(Button, { variant: slide.overlay.button.variant, size: "sm", onClick: makeButtonClickHandler(slide.overlay.button.link, slide.overlay.button.openInNewTab, push), children: slide.overlay.button.text }) }))] })), hasCards && (_jsx(Div, { className: `${POSITION_FILL} grid gap-[0.5rem] md:gap-[1rem] md:p-[2rem]`, padding: "md", style: {
187
+ return (_jsxs(Div, { className: `snap-start flex-none w-full relative self-stretch bg-neutral-900 ${slideHeightClass}`, children: [_jsx(Div, { className: POSITION_FILL, children: _jsx(SlideBackground, { bg: slide.background, legacy: slide.media, mobileLegacy: slide.mobileMedia, isMobile: isMobile, priority: slideIndex === 0 }) }), slide.overlay && (_jsxs(Div, { className: `${POSITION_FILL} ${FLEX_CENTER} [flex-direction:column] text-center md:px-[4rem] lg:px-[8rem]`, padding: "x-lg", children: [slide.overlay.subtitle && (_jsx(Text, { color: "inverse", shadow: "sm", className: "stagger-1 !/80 mb-1 md:mb-2 tracking-widest", mdSize: "sm", size: "xs", transform: "uppercase", children: slide.overlay.subtitle })), slide.overlay.title && (_jsx(Heading, { color: "inverse", level: 1, className: "stagger-2 font-display ! mb-2 md:mb-4", size: "4xl", shadow: "2xl", mdSize: "6xl", lgSize: "8xl", children: slide.overlay.title })), slide.overlay.description && (_jsx(Text, { color: "inverse", shadow: "sm", className: "stagger-3 !/90 mb-4 md:mb-8 max-w-2xl mx-auto", mdSize: "lg", lgSize: "xl", size: "sm", children: slide.overlay.description })), slide.overlay.button && (_jsx(Div, { className: "stagger-4", children: _jsx(Button, { variant: slide.overlay.button.variant, size: "sm", onClick: makeButtonClickHandler(slide.overlay.button.link, slide.overlay.button.openInNewTab, push), children: slide.overlay.button.text }) }))] })), hasCards && (_jsx(Div, { className: `${POSITION_FILL} grid gap-[var(--appkit-space-2)] md:gap-[var(--appkit-space-4)] md:p-[var(--appkit-space-8)]`, padding: "md", style: {
188
188
  gridTemplateRows: "repeat(2, 1fr)",
189
189
  gridTemplateColumns: isMobile ? "1fr" : "repeat(3, 1fr)",
190
190
  alignContent: "center",
@@ -18,12 +18,6 @@ import CameraCapture from "./CameraCapture";
18
18
  import { extractVideoPosterFrame, posterBlobAsFile } from "./video-poster";
19
19
  import { inferMediaTypeFromMime } from "../types/index";
20
20
  import { normalizeError } from "../../../errors/normalize";
21
- const __P = {
22
- p3: "p-3",
23
- };
24
- const __O = {
25
- hidden: "overflow-hidden",
26
- };
27
21
  const CLS_PDF_BADGE = "flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-error-surface text-error dark:bg-error-surface dark:text-error";
28
22
  const CLS_PDF_NAME = "text-sm font-medium text-info underline break-all dark:text-info";
29
23
  const CLS_PDF_LINK = "text-sm underline break-all text-info dark:text-info";
@@ -85,7 +79,7 @@ function ExternalUrlTabPanel({ extInput, setExtInput, extError, setExtError, onA
85
79
  return (_jsxs(Stack, { gap: "sm", children: [_jsxs(Row, { gap: "sm", children: [_jsx("input", { type: "url", value: extInput, onChange: (e) => { setExtInput(e.target.value); setExtError(""); }, placeholder: "https://example.com/image.jpg", className: "appkit-input flex-1" }), _jsx(Button, { type: "button", variant: "primary", size: "sm", onClick: onApply, children: "Apply" })] }), extError && _jsx(Alert, { variant: "error", children: extError }), _jsx(Text, { size: "xs", variant: "secondary", children: "External URLs are stored as-is and are not watermarked." })] }));
86
80
  }
87
81
  function MediaPreviewPanel({ value, label, disabled, enableTrim, enableThumbnail, onEditVideo, onRemove, tUpload, tMediaEditor, }) {
88
- return (_jsxs(Div, { className: `${__P.p3}`, rounded: "lg", surface: "muted", border: "default", children: [isVideo(value) ? (_jsxs(Stack, { gap: "sm", children: [_jsx(Div, { className: `relative aspect-video ${__O.hidden}`, rounded: "lg", children: _jsx(MediaVideo, { src: value, alt: label, controls: true, objectFit: "contain" }) }), _jsx(Text, { size: "xs", variant: "secondary", children: "Video uploaded successfully. Large videos may take longer to process." })] })) : isImage(value) ? (_jsx(Div, { className: `relative aspect-video ${__O.hidden}`, rounded: "lg", children: _jsx(MediaImage, { src: value, alt: label, size: "card", objectFit: "contain" }) })) : isPdf(value) ? (_jsxs(Stack, { gap: "sm", children: [_jsx(Div, { className: `relative w-full ${__O.hidden}`, rounded: "lg", border: "default", style: { height: 280 }, children: _jsx("iframe", { src: value, title: filenameFromUrl(value), className: "w-full h-full border-0" }) }), _jsxs(Row, { gap: "md", align: "center", children: [_jsx(Div, { "aria-hidden": true, className: CLS_PDF_BADGE, children: _jsx(Span, { size: "xs", weight: "bold", children: "PDF" }) }), _jsx(Anchor, { href: value, className: CLS_PDF_NAME, children: filenameFromUrl(value) })] })] })) : (_jsx(Anchor, { href: value, className: CLS_PDF_LINK, children: filenameFromUrl(value) })), !disabled && (_jsxs(Row, { wrap: true, gap: "sm", className: "mt-2", children: [isVideo(value) && (enableTrim || enableThumbnail) && (_jsx(Button, { type: "button", onClick: () => onEditVideo(value), variant: "secondary", size: "sm", children: tMediaEditor("editVideo") })), _jsx(Button, { type: "button", onClick: onRemove, variant: "danger", size: "sm", children: tUpload("remove") })] }))] }));
82
+ return (_jsxs(Div, { padding: "sm", rounded: "lg", surface: "muted", border: "default", children: [isVideo(value) ? (_jsxs(Stack, { gap: "sm", children: [_jsx(Div, { className: "relative aspect-video", overflow: "hidden", rounded: "lg", children: _jsx(MediaVideo, { src: value, alt: label, controls: true, objectFit: "contain" }) }), _jsx(Text, { size: "xs", variant: "secondary", children: "Video uploaded successfully. Large videos may take longer to process." })] })) : isImage(value) ? (_jsx(Div, { className: "relative aspect-video", overflow: "hidden", rounded: "lg", children: _jsx(MediaImage, { src: value, alt: label, size: "card", objectFit: "contain" }) })) : isPdf(value) ? (_jsxs(Stack, { gap: "sm", children: [_jsx(Div, { className: "relative w-full", overflow: "hidden", rounded: "lg", border: "default", style: { height: 280 }, children: _jsx("iframe", { src: value, title: filenameFromUrl(value), className: "w-full h-full border-0" }) }), _jsxs(Row, { gap: "md", align: "center", children: [_jsx(Div, { "aria-hidden": true, className: CLS_PDF_BADGE, children: _jsx(Span, { size: "xs", weight: "bold", children: "PDF" }) }), _jsx(Anchor, { href: value, className: CLS_PDF_NAME, children: filenameFromUrl(value) })] })] })) : (_jsx(Anchor, { href: value, className: CLS_PDF_LINK, children: filenameFromUrl(value) })), !disabled && (_jsxs(Row, { wrap: true, gap: "sm", className: "mt-2", children: [isVideo(value) && (enableTrim || enableThumbnail) && (_jsx(Button, { type: "button", onClick: () => onEditVideo(value), variant: "secondary", size: "sm", children: tMediaEditor("editVideo") })), _jsx(Button, { type: "button", onClick: onRemove, variant: "danger", size: "sm", children: tUpload("remove") })] }))] }));
89
83
  }
90
84
  export function MediaUploadField({ label, value, onChange, onChangeField, onUpload,
91
85
  // SB-UNI-Z5 2026-05-13 — `kind` derives accept/maxSizeMB when not set
@@ -20,6 +20,30 @@ const MODE_OPTIONS = [
20
20
  { label: "Light", value: "light" },
21
21
  { label: "Dark", value: "dark" },
22
22
  ];
23
+ /** Groups `REQUIRED_THEME_TOKENS` into labeled subsections so the editor doesn't read as one undifferentiated grid of ~68 inputs. */
24
+ const TOKEN_GROUPS = [
25
+ { label: "Primary", keys: REQUIRED_THEME_TOKENS.filter((k) => k.startsWith("appkit-color-primary")) },
26
+ { label: "Secondary", keys: REQUIRED_THEME_TOKENS.filter((k) => k.startsWith("appkit-color-secondary")) },
27
+ {
28
+ label: "Surface & border",
29
+ keys: REQUIRED_THEME_TOKENS.filter((k) => ["appkit-color-bg", "appkit-color-surface", "appkit-color-surface-elevated", "appkit-color-surface-input", "appkit-color-border", "appkit-color-border-subtle"].includes(k)),
30
+ },
31
+ {
32
+ label: "Text",
33
+ keys: REQUIRED_THEME_TOKENS.filter((k) => k.startsWith("appkit-color-text")),
34
+ },
35
+ {
36
+ label: "Status",
37
+ keys: REQUIRED_THEME_TOKENS.filter((k) => ["appkit-color-success", "appkit-color-success-surface", "appkit-color-warning", "appkit-color-warning-surface", "appkit-color-error", "appkit-color-error-surface", "appkit-color-info", "appkit-color-info-surface"].includes(k)),
38
+ },
39
+ {
40
+ label: "Focus & glow",
41
+ keys: REQUIRED_THEME_TOKENS.filter((k) => k === "appkit-color-focus-ring" || k.startsWith("appkit-shadow-glow")),
42
+ },
43
+ { label: "Fonts", keys: REQUIRED_THEME_TOKENS.filter((k) => k.startsWith("appkit-font-")) },
44
+ { label: "Spacing scale", keys: REQUIRED_THEME_TOKENS.filter((k) => k.startsWith("appkit-space-")) },
45
+ { label: "Font-size scale", keys: REQUIRED_THEME_TOKENS.filter((k) => k.startsWith("appkit-text-")) },
46
+ ];
23
47
  function isBuiltInId(id) {
24
48
  return BUILT_IN_THEMES.some((t) => t.id === id);
25
49
  }
@@ -70,7 +94,7 @@ function ThemeEditor({ draft, readOnly, onChange, onSave, onCancel, }) {
70
94
  gradients: { ...draft.gradients, [key]: value },
71
95
  });
72
96
  }, [draft, onChange]);
73
- return (_jsx(Section, { padding: "md", surface: "card", border: "default", rounded: "lg", children: _jsxs(Stack, { gap: "md", children: [_jsxs(Row, { align: "end", justify: "between", gap: "md", wrap: true, children: [_jsxs(Stack, { gap: "sm", children: [_jsx(Input, { label: "Name", value: draft.name, onChange: (event) => onChange({ ...draft, name: event.target.value }), disabled: readOnly }), _jsx(Input, { label: "Id (slug)", value: draft.id, onChange: (event) => onChange({ ...draft, id: slugify(event.target.value) }), disabled: readOnly || draft.builtIn === true })] }), _jsx(Select, { label: "Mode", options: MODE_OPTIONS, value: draft.mode, onValueChange: (next) => onChange({ ...draft, mode: next }), disabled: readOnly })] }), _jsxs(Stack, { gap: "sm", children: [_jsx(Text, { size: "sm", weight: "semibold", children: "CSS variable tokens" }), _jsxs(Text, { size: "xs", color: "muted", children: ["Each key is written as ", _jsx("code", { children: "--key" }), " on ", _jsx("code", { children: "<html>" }), " ", "when this theme is active. Empty values fall back to the active mode\u2019s built-in theme."] }), _jsx(Grid, { cols: 2, gap: "sm", children: REQUIRED_THEME_TOKENS.map((key) => (_jsx(Input, { label: key, value: draft.tokens[key] ?? "", onChange: (event) => updateToken(key, event.target.value), disabled: readOnly, placeholder: "inherits from built-in" }, key))) })] }), _jsxs(Stack, { gap: "sm", children: [_jsx(Text, { size: "sm", weight: "semibold", children: "Gradients" }), _jsxs(Text, { size: "xs", color: "muted", children: ["Each gradient is a complete CSS expression \u2014 vary direction, stops, opacity, and easing per theme. Tokens flow through", " ", _jsxs("code", { children: ["--appkit-gradient-", "<key>"] }), "."] }), _jsx(Stack, { gap: "sm", children: REQUIRED_GRADIENT_KEYS.map((key) => (_jsx(Textarea, { label: key, rows: 2, value: draft.gradients[key] ?? "", onChange: (event) => updateGradient(key, event.target.value), disabled: readOnly, placeholder: "linear-gradient(...)" }, key))) })] }), _jsxs(Row, { gap: "sm", justify: "end", children: [_jsx(Button, { variant: "ghost", onClick: onCancel, children: "Cancel" }), !readOnly ? (_jsx(Button, { variant: "primary", onClick: onSave, children: "Save theme" })) : null] })] }) }));
97
+ return (_jsx(Section, { padding: "md", surface: "card", border: "default", rounded: "lg", children: _jsxs(Stack, { gap: "md", children: [_jsxs(Row, { align: "end", justify: "between", gap: "md", wrap: true, children: [_jsxs(Stack, { gap: "sm", children: [_jsx(Input, { label: "Name", value: draft.name, onChange: (event) => onChange({ ...draft, name: event.target.value }), disabled: readOnly }), _jsx(Input, { label: "Id (slug)", value: draft.id, onChange: (event) => onChange({ ...draft, id: slugify(event.target.value) }), disabled: readOnly || draft.builtIn === true })] }), _jsx(Select, { label: "Mode", options: MODE_OPTIONS, value: draft.mode, onValueChange: (next) => onChange({ ...draft, mode: next }), disabled: readOnly })] }), _jsxs(Stack, { gap: "sm", children: [_jsx(Text, { size: "sm", weight: "semibold", children: "CSS variable tokens" }), _jsxs(Text, { size: "xs", color: "muted", children: ["Each key is written as ", _jsx("code", { children: "--key" }), " on ", _jsx("code", { children: "<html>" }), " ", "when this theme is active. Empty values fall back to the active mode\u2019s built-in theme."] }), TOKEN_GROUPS.map((group) => (_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", weight: "semibold", color: "muted", children: group.label }), _jsx(Grid, { cols: 2, gap: "sm", children: group.keys.map((key) => (_jsx(Input, { label: key, value: draft.tokens[key] ?? "", onChange: (event) => updateToken(key, event.target.value), disabled: readOnly, placeholder: "inherits from built-in" }, key))) })] }, group.label)))] }), _jsxs(Stack, { gap: "sm", children: [_jsx(Text, { size: "sm", weight: "semibold", children: "Gradients" }), _jsxs(Text, { size: "xs", color: "muted", children: ["Each gradient is a complete CSS expression \u2014 vary direction, stops, opacity, and easing per theme. Tokens flow through", " ", _jsxs("code", { children: ["--appkit-gradient-", "<key>"] }), "."] }), _jsx(Stack, { gap: "sm", children: REQUIRED_GRADIENT_KEYS.map((key) => (_jsx(Textarea, { label: key, rows: 2, value: draft.gradients[key] ?? "", onChange: (event) => updateGradient(key, event.target.value), disabled: readOnly, placeholder: "linear-gradient(...)" }, key))) })] }), _jsxs(Row, { gap: "sm", justify: "end", children: [_jsx(Button, { variant: "ghost", onClick: onCancel, children: "Cancel" }), !readOnly ? (_jsx(Button, { variant: "primary", onClick: onSave, children: "Save theme" })) : null] })] }) }));
74
98
  }
75
99
  export function ThemeManagerView({ value, onChange, previewOrigin = "/", }) {
76
100
  const [editingId, setEditingId] = useState(null);