featuredrop 1.3.0 → 2.1.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.
- package/README.md +287 -760
- package/dist/adapters.cjs +1757 -0
- package/dist/adapters.cjs.map +1 -0
- package/dist/adapters.d.cts +744 -0
- package/dist/adapters.d.ts +744 -0
- package/dist/adapters.js +1745 -0
- package/dist/adapters.js.map +1 -0
- package/dist/admin.cjs +148 -32
- package/dist/admin.cjs.map +1 -1
- package/dist/admin.d.cts +14 -3
- package/dist/admin.d.ts +14 -3
- package/dist/admin.js +148 -32
- package/dist/admin.js.map +1 -1
- package/dist/bridges.cjs +134 -15
- package/dist/bridges.cjs.map +1 -1
- package/dist/bridges.d.cts +12 -5
- package/dist/bridges.d.ts +12 -5
- package/dist/bridges.js +114 -15
- package/dist/bridges.js.map +1 -1
- package/dist/ci.cjs +34 -0
- package/dist/ci.cjs.map +1 -1
- package/dist/ci.d.cts +5 -1
- package/dist/ci.d.ts +5 -1
- package/dist/ci.js +34 -1
- package/dist/ci.js.map +1 -1
- package/dist/cms.cjs +835 -0
- package/dist/cms.cjs.map +1 -0
- package/dist/cms.d.cts +236 -0
- package/dist/cms.d.ts +236 -0
- package/dist/cms.js +829 -0
- package/dist/cms.js.map +1 -0
- package/dist/featuredrop.cjs +23 -2
- package/dist/featuredrop.cjs.map +1 -1
- package/dist/flags.cjs +27 -7
- package/dist/flags.cjs.map +1 -1
- package/dist/flags.d.cts +14 -0
- package/dist/flags.d.ts +14 -0
- package/dist/flags.js +27 -7
- package/dist/flags.js.map +1 -1
- package/dist/index.cjs +52 -4460
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1340
- package/dist/index.d.ts +1 -1340
- package/dist/index.js +53 -4387
- package/dist/index.js.map +1 -1
- package/dist/markdown.cjs +257 -0
- package/dist/markdown.cjs.map +1 -0
- package/dist/markdown.d.cts +9 -0
- package/dist/markdown.d.ts +9 -0
- package/dist/markdown.js +234 -0
- package/dist/markdown.js.map +1 -0
- package/dist/preact.cjs +37 -12
- package/dist/preact.cjs.map +1 -1
- package/dist/preact.js +17 -12
- package/dist/preact.js.map +1 -1
- package/dist/react.cjs +37 -12
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +17 -12
- package/dist/react.js.map +1 -1
- package/dist/renderer.cjs +503 -0
- package/dist/renderer.cjs.map +1 -0
- package/dist/renderer.d.cts +250 -0
- package/dist/renderer.d.ts +250 -0
- package/dist/renderer.js +501 -0
- package/dist/renderer.js.map +1 -0
- package/dist/rss.cjs +291 -0
- package/dist/rss.cjs.map +1 -0
- package/dist/rss.d.cts +158 -0
- package/dist/rss.d.ts +158 -0
- package/dist/rss.js +268 -0
- package/dist/rss.js.map +1 -0
- package/dist/vue.cjs +23 -2
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.js +3 -2
- package/dist/vue.js.map +1 -1
- package/package.json +72 -6
package/dist/admin.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/admin/index.tsx"],"names":["useState","useMemo","jsx","Fragment","jsxs"],"mappings":"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","file":"admin.cjs","sourcesContent":["import { useMemo, useState, type CSSProperties, type ReactNode } from \"react\";\nimport type { AudienceRule, FeatureEntry } from \"../types\";\n\nconst panelStyles: CSSProperties = {\n border: \"1px solid #e5e7eb\",\n borderRadius: \"10px\",\n padding: \"12px\",\n background: \"#ffffff\",\n};\n\nconst headingStyles: CSSProperties = {\n margin: \"0 0 8px\",\n fontSize: \"15px\",\n fontWeight: 700,\n};\n\nexport interface ManifestEditorProps {\n features: readonly FeatureEntry[];\n onSave: (updated: FeatureEntry[]) => Promise<void> | void;\n readOnly?: boolean;\n children?: ReactNode;\n}\n\nexport function ManifestEditor({\n features,\n onSave,\n readOnly = false,\n children,\n}: ManifestEditorProps) {\n const [draft, setDraft] = useState(() => JSON.stringify(features, null, 2));\n const [status, setStatus] = useState<string>(\"idle\");\n const [error, setError] = useState<string>(\"\");\n\n const parsed = useMemo(() => {\n try {\n const next = JSON.parse(draft) as unknown;\n if (!Array.isArray(next)) throw new Error(\"Manifest must be an array\");\n return next as FeatureEntry[];\n } catch {\n return null;\n }\n }, [draft]);\n\n const save = async () => {\n if (readOnly || !parsed) return;\n setStatus(\"saving\");\n setError(\"\");\n try {\n await onSave(parsed);\n setStatus(\"saved\");\n } catch (cause) {\n setStatus(\"error\");\n setError(cause instanceof Error ? cause.message : \"Failed to save manifest\");\n }\n };\n\n if (children) return <>{children}</>;\n\n return (\n <section data-featuredrop-admin-manifest-editor style={panelStyles}>\n <p style={headingStyles}>Manifest Editor</p>\n <textarea\n aria-label=\"Manifest JSON\"\n value={draft}\n onChange={(event) => setDraft(event.target.value)}\n readOnly={readOnly}\n style={{\n width: \"100%\",\n minHeight: \"180px\",\n fontFamily: \"ui-monospace, SFMono-Regular, Menlo, monospace\",\n fontSize: \"12px\",\n lineHeight: 1.45,\n border: \"1px solid #d1d5db\",\n borderRadius: \"8px\",\n padding: \"10px\",\n }}\n />\n <div style={{ display: \"flex\", alignItems: \"center\", gap: \"8px\", marginTop: \"8px\" }}>\n <button type=\"button\" onClick={save} disabled={readOnly || !parsed}>\n Save\n </button>\n <span aria-live=\"polite\">{status}</span>\n {!parsed && <span style={{ color: \"#dc2626\" }}>Invalid JSON</span>}\n {error && <span style={{ color: \"#dc2626\" }}>{error}</span>}\n </div>\n </section>\n );\n}\n\nexport interface ScheduleCalendarProps {\n features: readonly FeatureEntry[];\n onSchedule: (featureId: string, publishAt: string) => Promise<void> | void;\n}\n\nexport function ScheduleCalendar({ features, onSchedule }: ScheduleCalendarProps) {\n const [values, setValues] = useState<Record<string, string>>({});\n\n return (\n <section data-featuredrop-admin-schedule-calendar style={panelStyles}>\n <p style={headingStyles}>Schedule Calendar</p>\n <ul style={{ margin: 0, padding: 0, listStyle: \"none\", display: \"grid\", gap: \"10px\" }}>\n {features.map((feature) => (\n <li\n key={feature.id}\n style={{\n border: \"1px solid #e5e7eb\",\n borderRadius: \"8px\",\n padding: \"10px\",\n display: \"grid\",\n gap: \"6px\",\n }}\n >\n <strong>{feature.label}</strong>\n <label style={{ display: \"grid\", gap: \"4px\" }}>\n Publish at\n <input\n type=\"datetime-local\"\n value={values[feature.id] ?? \"\"}\n onChange={(event) => {\n const value = event.target.value;\n setValues((previous) => ({ ...previous, [feature.id]: value }));\n }}\n />\n </label>\n <button\n type=\"button\"\n onClick={() => {\n const value = values[feature.id];\n if (!value) return;\n void onSchedule(feature.id, new Date(value).toISOString());\n }}\n >\n Schedule\n </button>\n </li>\n ))}\n </ul>\n </section>\n );\n}\n\nexport interface PreviewPanelProps {\n feature?: FeatureEntry | null;\n components?: Array<\"badge\" | \"changelog\" | \"spotlight\" | \"banner\" | \"toast\">;\n}\n\nexport function PreviewPanel({ feature, components = [\"badge\", \"changelog\"] }: PreviewPanelProps) {\n return (\n <section data-featuredrop-admin-preview-panel style={panelStyles}>\n <p style={headingStyles}>Preview Panel</p>\n {!feature ? (\n <p style={{ margin: 0, color: \"#6b7280\" }}>Select a feature to preview.</p>\n ) : (\n <>\n <p style={{ margin: \"0 0 6px\", fontWeight: 600 }}>{feature.label}</p>\n <p style={{ margin: \"0 0 8px\", color: \"#6b7280\" }}>{feature.description ?? \"No description\"}</p>\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: \"6px\" }}>\n {components.map((component) => (\n <span\n key={component}\n style={{\n border: \"1px solid #d1d5db\",\n borderRadius: \"999px\",\n padding: \"2px 8px\",\n fontSize: \"12px\",\n }}\n >\n {component}\n </span>\n ))}\n </div>\n </>\n )}\n </section>\n );\n}\n\nexport interface AudienceBuilderProps {\n segments?: string[];\n roles?: string[];\n regions?: string[];\n value?: AudienceRule;\n onChange?: (audience: AudienceRule) => void;\n onSave?: (audience: AudienceRule) => Promise<void> | void;\n}\n\nfunction toggle(list: string[] | undefined, value: string): string[] {\n const items = new Set(list ?? []);\n if (items.has(value)) items.delete(value);\n else items.add(value);\n return Array.from(items);\n}\n\nexport function AudienceBuilder({\n segments = [],\n roles = [],\n regions = [],\n value,\n onChange,\n onSave,\n}: AudienceBuilderProps) {\n const [audience, setAudience] = useState<AudienceRule>({\n plan: value?.plan ?? [],\n role: value?.role ?? [],\n region: value?.region ?? [],\n });\n\n const updateAudience = (next: AudienceRule) => {\n setAudience(next);\n onChange?.(next);\n };\n\n const section = (\n title: string,\n values: string[],\n selected: string[] | undefined,\n onToggle: (value: string) => void,\n ) => (\n <fieldset style={{ border: \"none\", margin: 0, padding: 0 }}>\n <legend style={{ fontWeight: 600, marginBottom: \"4px\" }}>{title}</legend>\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: \"8px\" }}>\n {values.map((item) => (\n <label key={item} style={{ display: \"inline-flex\", alignItems: \"center\", gap: \"6px\" }}>\n <input\n type=\"checkbox\"\n checked={Boolean(selected?.includes(item))}\n onChange={() => onToggle(item)}\n />\n {item}\n </label>\n ))}\n </div>\n </fieldset>\n );\n\n return (\n <section data-featuredrop-admin-audience-builder style={panelStyles}>\n <p style={headingStyles}>Audience Builder</p>\n <div style={{ display: \"grid\", gap: \"10px\" }}>\n {section(\"Plans\", segments, audience.plan, (item) =>\n updateAudience({ ...audience, plan: toggle(audience.plan, item) }))}\n {section(\"Roles\", roles, audience.role, (item) =>\n updateAudience({ ...audience, role: toggle(audience.role, item) }))}\n {section(\"Regions\", regions, audience.region, (item) =>\n updateAudience({ ...audience, region: toggle(audience.region, item) }))}\n </div>\n {onSave && (\n <button\n type=\"button\"\n style={{ marginTop: \"10px\" }}\n onClick={() => {\n void onSave(audience);\n }}\n >\n Save audience\n </button>\n )}\n </section>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/admin/index.tsx"],"names":["useState","useMemo","jsx","Fragment","jsxs"],"mappings":"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","file":"admin.cjs","sourcesContent":["import { useMemo, useState, type CSSProperties, type ReactNode } from \"react\";\nimport type { AudienceRule, FeatureEntry } from \"../types\";\n\nconst panelStyles: CSSProperties = {\n border: \"1px solid #e5e7eb\",\n borderRadius: \"10px\",\n padding: \"12px\",\n background: \"#ffffff\",\n};\n\nconst headingStyles: CSSProperties = {\n margin: \"0 0 8px\",\n fontSize: \"15px\",\n fontWeight: 700,\n};\n\nexport interface ManifestEditorProps {\n features: readonly FeatureEntry[];\n onSave: (updated: FeatureEntry[]) => Promise<void> | void;\n schema?: {\n parse?: (value: unknown) => unknown;\n safeParse?: (value: unknown) => { success: boolean; data?: unknown; error?: unknown };\n };\n readOnly?: boolean;\n children?: ReactNode;\n}\n\ninterface DraftParseResult {\n parsed: FeatureEntry[] | null;\n error: string;\n}\n\nfunction toErrorMessage(error: unknown): string {\n if (error instanceof Error && error.message) return error.message;\n if (typeof error === \"string\" && error.trim()) return error.trim();\n return \"Invalid manifest data\";\n}\n\nfunction parseDraft(\n draft: string,\n schema: ManifestEditorProps[\"schema\"] | undefined,\n): DraftParseResult {\n try {\n const raw = JSON.parse(draft) as unknown;\n if (!Array.isArray(raw)) {\n return {\n parsed: null,\n error: \"Manifest must be an array\",\n };\n }\n\n if (!schema) {\n return {\n parsed: raw as FeatureEntry[],\n error: \"\",\n };\n }\n\n if (typeof schema.safeParse === \"function\") {\n const result = schema.safeParse(raw);\n if (!result.success) {\n return {\n parsed: null,\n error: toErrorMessage(result.error),\n };\n }\n if (!Array.isArray(result.data)) {\n return {\n parsed: null,\n error: \"Schema output must be an array\",\n };\n }\n return {\n parsed: result.data as FeatureEntry[],\n error: \"\",\n };\n }\n\n if (typeof schema.parse === \"function\") {\n const parsed = schema.parse(raw);\n if (!Array.isArray(parsed)) {\n return {\n parsed: null,\n error: \"Schema output must be an array\",\n };\n }\n return {\n parsed: parsed as FeatureEntry[],\n error: \"\",\n };\n }\n\n return {\n parsed: raw as FeatureEntry[],\n error: \"\",\n };\n } catch (error: unknown) {\n return {\n parsed: null,\n error: toErrorMessage(error),\n };\n }\n}\n\nexport function ManifestEditor({\n features,\n onSave,\n schema,\n readOnly = false,\n children,\n}: ManifestEditorProps) {\n const [draft, setDraft] = useState(() => JSON.stringify(features, null, 2));\n const [status, setStatus] = useState<string>(\"idle\");\n const [error, setError] = useState<string>(\"\");\n\n const parsedResult = useMemo(() => parseDraft(draft, schema), [draft, schema]);\n const parsed = parsedResult.parsed;\n\n const save = async () => {\n if (readOnly || !parsed) return;\n setStatus(\"saving\");\n setError(\"\");\n try {\n await onSave(parsed);\n setStatus(\"saved\");\n } catch (cause) {\n setStatus(\"error\");\n setError(cause instanceof Error ? cause.message : \"Failed to save manifest\");\n }\n };\n\n if (children) return <>{children}</>;\n\n return (\n <section data-featuredrop-admin-manifest-editor style={panelStyles}>\n <p style={headingStyles}>Manifest Editor</p>\n <textarea\n aria-label=\"Manifest JSON\"\n value={draft}\n onChange={(event) => setDraft(event.target.value)}\n readOnly={readOnly}\n style={{\n width: \"100%\",\n minHeight: \"180px\",\n fontFamily: \"ui-monospace, SFMono-Regular, Menlo, monospace\",\n fontSize: \"12px\",\n lineHeight: 1.45,\n border: \"1px solid #d1d5db\",\n borderRadius: \"8px\",\n padding: \"10px\",\n }}\n />\n <div style={{ display: \"flex\", alignItems: \"center\", gap: \"8px\", marginTop: \"8px\" }}>\n <button type=\"button\" onClick={save} disabled={readOnly || !parsed}>\n Save\n </button>\n <span aria-live=\"polite\">{status}</span>\n {!parsed && <span style={{ color: \"#dc2626\" }}>{parsedResult.error || \"Invalid JSON\"}</span>}\n {error && <span style={{ color: \"#dc2626\" }}>{error}</span>}\n </div>\n </section>\n );\n}\n\nexport interface ScheduleCalendarProps {\n features: readonly FeatureEntry[];\n onSchedule: (featureId: string, publishAt: string) => Promise<void> | void;\n onExpire?: (featureId: string, expiresAt: string) => Promise<void> | void;\n minDate?: string;\n}\n\nfunction toDateTimeInputMin(value: string | undefined): string | undefined {\n if (!value) return undefined;\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) return undefined;\n return date.toISOString().slice(0, 16);\n}\n\nexport function ScheduleCalendar({\n features,\n onSchedule,\n onExpire,\n minDate,\n}: ScheduleCalendarProps) {\n const [values, setValues] = useState<Record<string, string>>({});\n const [expireValues, setExpireValues] = useState<Record<string, string>>({});\n const minDateInput = toDateTimeInputMin(minDate);\n\n return (\n <section data-featuredrop-admin-schedule-calendar style={panelStyles}>\n <p style={headingStyles}>Schedule Calendar</p>\n <ul style={{ margin: 0, padding: 0, listStyle: \"none\", display: \"grid\", gap: \"10px\" }}>\n {features.map((feature) => (\n <li\n key={feature.id}\n style={{\n border: \"1px solid #e5e7eb\",\n borderRadius: \"8px\",\n padding: \"10px\",\n display: \"grid\",\n gap: \"6px\",\n }}\n >\n <strong>{feature.label}</strong>\n <label style={{ display: \"grid\", gap: \"4px\" }}>\n Publish at\n <input\n type=\"datetime-local\"\n value={values[feature.id] ?? \"\"}\n min={minDateInput}\n onChange={(event) => {\n const value = event.target.value;\n setValues((previous) => ({ ...previous, [feature.id]: value }));\n }}\n />\n </label>\n {onExpire && (\n <label style={{ display: \"grid\", gap: \"4px\" }}>\n Expire at\n <input\n type=\"datetime-local\"\n value={expireValues[feature.id] ?? \"\"}\n min={minDateInput}\n onChange={(event) => {\n const value = event.target.value;\n setExpireValues((previous) => ({ ...previous, [feature.id]: value }));\n }}\n />\n </label>\n )}\n <button\n type=\"button\"\n onClick={() => {\n const value = values[feature.id];\n if (!value) return;\n void onSchedule(feature.id, new Date(value).toISOString());\n }}\n >\n Schedule\n </button>\n {onExpire && (\n <button\n type=\"button\"\n onClick={() => {\n const value = expireValues[feature.id];\n if (!value) return;\n void onExpire(feature.id, new Date(value).toISOString());\n }}\n >\n Set expiry\n </button>\n )}\n </li>\n ))}\n </ul>\n </section>\n );\n}\n\nexport interface PreviewPanelProps {\n feature?: FeatureEntry | null;\n components?: Array<\"badge\" | \"changelog\" | \"spotlight\" | \"banner\" | \"toast\">;\n theme?: \"light\" | \"dark\";\n}\n\nexport function PreviewPanel({\n feature,\n components = [\"badge\", \"changelog\"],\n theme = \"light\",\n}: PreviewPanelProps) {\n const dark = theme === \"dark\";\n return (\n <section\n data-featuredrop-admin-preview-panel\n data-featuredrop-theme={theme}\n style={{\n ...panelStyles,\n background: dark ? \"#111827\" : \"#ffffff\",\n borderColor: dark ? \"#374151\" : \"#e5e7eb\",\n color: dark ? \"#f9fafb\" : \"#111827\",\n }}\n >\n <p style={headingStyles}>Preview Panel</p>\n {!feature ? (\n <p style={{ margin: 0, color: dark ? \"#9ca3af\" : \"#6b7280\" }}>Select a feature to preview.</p>\n ) : (\n <>\n <p style={{ margin: \"0 0 6px\", fontWeight: 600 }}>{feature.label}</p>\n <p style={{ margin: \"0 0 8px\", color: dark ? \"#9ca3af\" : \"#6b7280\" }}>\n {feature.description ?? \"No description\"}\n </p>\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: \"6px\" }}>\n {components.map((component) => (\n <span\n key={component}\n style={{\n border: dark ? \"1px solid #4b5563\" : \"1px solid #d1d5db\",\n borderRadius: \"999px\",\n padding: \"2px 8px\",\n fontSize: \"12px\",\n }}\n >\n {component}\n </span>\n ))}\n </div>\n </>\n )}\n </section>\n );\n}\n\nexport interface AudienceBuilderProps {\n segments?: string[];\n roles?: string[];\n regions?: string[];\n value?: AudienceRule;\n onChange?: (audience: AudienceRule) => void;\n onSave?: (audience: AudienceRule) => Promise<void> | void;\n}\n\nfunction toggle(list: string[] | undefined, value: string): string[] {\n const items = new Set(list ?? []);\n if (items.has(value)) items.delete(value);\n else items.add(value);\n return Array.from(items);\n}\n\nexport function AudienceBuilder({\n segments = [],\n roles = [],\n regions = [],\n value,\n onChange,\n onSave,\n}: AudienceBuilderProps) {\n const [audience, setAudience] = useState<AudienceRule>({\n plan: value?.plan ?? [],\n role: value?.role ?? [],\n region: value?.region ?? [],\n });\n\n const updateAudience = (next: AudienceRule) => {\n setAudience(next);\n onChange?.(next);\n };\n\n const section = (\n title: string,\n values: string[],\n selected: string[] | undefined,\n onToggle: (value: string) => void,\n ) => (\n <fieldset style={{ border: \"none\", margin: 0, padding: 0 }}>\n <legend style={{ fontWeight: 600, marginBottom: \"4px\" }}>{title}</legend>\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: \"8px\" }}>\n {values.map((item) => (\n <label key={item} style={{ display: \"inline-flex\", alignItems: \"center\", gap: \"6px\" }}>\n <input\n type=\"checkbox\"\n checked={Boolean(selected?.includes(item))}\n onChange={() => onToggle(item)}\n />\n {item}\n </label>\n ))}\n </div>\n </fieldset>\n );\n\n return (\n <section data-featuredrop-admin-audience-builder style={panelStyles}>\n <p style={headingStyles}>Audience Builder</p>\n <div style={{ display: \"grid\", gap: \"10px\" }}>\n {section(\"Plans\", segments, audience.plan, (item) =>\n updateAudience({ ...audience, plan: toggle(audience.plan, item) }))}\n {section(\"Roles\", roles, audience.role, (item) =>\n updateAudience({ ...audience, role: toggle(audience.role, item) }))}\n {section(\"Regions\", regions, audience.region, (item) =>\n updateAudience({ ...audience, region: toggle(audience.region, item) }))}\n </div>\n {onSave && (\n <button\n type=\"button\"\n style={{ marginTop: \"10px\" }}\n onClick={() => {\n void onSave(audience);\n }}\n >\n Save audience\n </button>\n )}\n </section>\n );\n}\n"]}
|
package/dist/admin.d.cts
CHANGED
|
@@ -149,20 +149,31 @@ interface FeatureEntry {
|
|
|
149
149
|
interface ManifestEditorProps {
|
|
150
150
|
features: readonly FeatureEntry[];
|
|
151
151
|
onSave: (updated: FeatureEntry[]) => Promise<void> | void;
|
|
152
|
+
schema?: {
|
|
153
|
+
parse?: (value: unknown) => unknown;
|
|
154
|
+
safeParse?: (value: unknown) => {
|
|
155
|
+
success: boolean;
|
|
156
|
+
data?: unknown;
|
|
157
|
+
error?: unknown;
|
|
158
|
+
};
|
|
159
|
+
};
|
|
152
160
|
readOnly?: boolean;
|
|
153
161
|
children?: ReactNode;
|
|
154
162
|
}
|
|
155
|
-
declare function ManifestEditor({ features, onSave, readOnly, children, }: ManifestEditorProps): react_jsx_runtime.JSX.Element;
|
|
163
|
+
declare function ManifestEditor({ features, onSave, schema, readOnly, children, }: ManifestEditorProps): react_jsx_runtime.JSX.Element;
|
|
156
164
|
interface ScheduleCalendarProps {
|
|
157
165
|
features: readonly FeatureEntry[];
|
|
158
166
|
onSchedule: (featureId: string, publishAt: string) => Promise<void> | void;
|
|
167
|
+
onExpire?: (featureId: string, expiresAt: string) => Promise<void> | void;
|
|
168
|
+
minDate?: string;
|
|
159
169
|
}
|
|
160
|
-
declare function ScheduleCalendar({ features, onSchedule }: ScheduleCalendarProps): react_jsx_runtime.JSX.Element;
|
|
170
|
+
declare function ScheduleCalendar({ features, onSchedule, onExpire, minDate, }: ScheduleCalendarProps): react_jsx_runtime.JSX.Element;
|
|
161
171
|
interface PreviewPanelProps {
|
|
162
172
|
feature?: FeatureEntry | null;
|
|
163
173
|
components?: Array<"badge" | "changelog" | "spotlight" | "banner" | "toast">;
|
|
174
|
+
theme?: "light" | "dark";
|
|
164
175
|
}
|
|
165
|
-
declare function PreviewPanel({ feature, components }: PreviewPanelProps): react_jsx_runtime.JSX.Element;
|
|
176
|
+
declare function PreviewPanel({ feature, components, theme, }: PreviewPanelProps): react_jsx_runtime.JSX.Element;
|
|
166
177
|
interface AudienceBuilderProps {
|
|
167
178
|
segments?: string[];
|
|
168
179
|
roles?: string[];
|
package/dist/admin.d.ts
CHANGED
|
@@ -149,20 +149,31 @@ interface FeatureEntry {
|
|
|
149
149
|
interface ManifestEditorProps {
|
|
150
150
|
features: readonly FeatureEntry[];
|
|
151
151
|
onSave: (updated: FeatureEntry[]) => Promise<void> | void;
|
|
152
|
+
schema?: {
|
|
153
|
+
parse?: (value: unknown) => unknown;
|
|
154
|
+
safeParse?: (value: unknown) => {
|
|
155
|
+
success: boolean;
|
|
156
|
+
data?: unknown;
|
|
157
|
+
error?: unknown;
|
|
158
|
+
};
|
|
159
|
+
};
|
|
152
160
|
readOnly?: boolean;
|
|
153
161
|
children?: ReactNode;
|
|
154
162
|
}
|
|
155
|
-
declare function ManifestEditor({ features, onSave, readOnly, children, }: ManifestEditorProps): react_jsx_runtime.JSX.Element;
|
|
163
|
+
declare function ManifestEditor({ features, onSave, schema, readOnly, children, }: ManifestEditorProps): react_jsx_runtime.JSX.Element;
|
|
156
164
|
interface ScheduleCalendarProps {
|
|
157
165
|
features: readonly FeatureEntry[];
|
|
158
166
|
onSchedule: (featureId: string, publishAt: string) => Promise<void> | void;
|
|
167
|
+
onExpire?: (featureId: string, expiresAt: string) => Promise<void> | void;
|
|
168
|
+
minDate?: string;
|
|
159
169
|
}
|
|
160
|
-
declare function ScheduleCalendar({ features, onSchedule }: ScheduleCalendarProps): react_jsx_runtime.JSX.Element;
|
|
170
|
+
declare function ScheduleCalendar({ features, onSchedule, onExpire, minDate, }: ScheduleCalendarProps): react_jsx_runtime.JSX.Element;
|
|
161
171
|
interface PreviewPanelProps {
|
|
162
172
|
feature?: FeatureEntry | null;
|
|
163
173
|
components?: Array<"badge" | "changelog" | "spotlight" | "banner" | "toast">;
|
|
174
|
+
theme?: "light" | "dark";
|
|
164
175
|
}
|
|
165
|
-
declare function PreviewPanel({ feature, components }: PreviewPanelProps): react_jsx_runtime.JSX.Element;
|
|
176
|
+
declare function PreviewPanel({ feature, components, theme, }: PreviewPanelProps): react_jsx_runtime.JSX.Element;
|
|
166
177
|
interface AudienceBuilderProps {
|
|
167
178
|
segments?: string[];
|
|
168
179
|
roles?: string[];
|
package/dist/admin.js
CHANGED
|
@@ -14,24 +14,81 @@ var headingStyles = {
|
|
|
14
14
|
fontSize: "15px",
|
|
15
15
|
fontWeight: 700
|
|
16
16
|
};
|
|
17
|
+
function toErrorMessage(error) {
|
|
18
|
+
if (error instanceof Error && error.message) return error.message;
|
|
19
|
+
if (typeof error === "string" && error.trim()) return error.trim();
|
|
20
|
+
return "Invalid manifest data";
|
|
21
|
+
}
|
|
22
|
+
function parseDraft(draft, schema) {
|
|
23
|
+
try {
|
|
24
|
+
const raw = JSON.parse(draft);
|
|
25
|
+
if (!Array.isArray(raw)) {
|
|
26
|
+
return {
|
|
27
|
+
parsed: null,
|
|
28
|
+
error: "Manifest must be an array"
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
if (!schema) {
|
|
32
|
+
return {
|
|
33
|
+
parsed: raw,
|
|
34
|
+
error: ""
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
if (typeof schema.safeParse === "function") {
|
|
38
|
+
const result = schema.safeParse(raw);
|
|
39
|
+
if (!result.success) {
|
|
40
|
+
return {
|
|
41
|
+
parsed: null,
|
|
42
|
+
error: toErrorMessage(result.error)
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
if (!Array.isArray(result.data)) {
|
|
46
|
+
return {
|
|
47
|
+
parsed: null,
|
|
48
|
+
error: "Schema output must be an array"
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
parsed: result.data,
|
|
53
|
+
error: ""
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
if (typeof schema.parse === "function") {
|
|
57
|
+
const parsed = schema.parse(raw);
|
|
58
|
+
if (!Array.isArray(parsed)) {
|
|
59
|
+
return {
|
|
60
|
+
parsed: null,
|
|
61
|
+
error: "Schema output must be an array"
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
parsed,
|
|
66
|
+
error: ""
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
parsed: raw,
|
|
71
|
+
error: ""
|
|
72
|
+
};
|
|
73
|
+
} catch (error) {
|
|
74
|
+
return {
|
|
75
|
+
parsed: null,
|
|
76
|
+
error: toErrorMessage(error)
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
}
|
|
17
80
|
function ManifestEditor({
|
|
18
81
|
features,
|
|
19
82
|
onSave,
|
|
83
|
+
schema,
|
|
20
84
|
readOnly = false,
|
|
21
85
|
children
|
|
22
86
|
}) {
|
|
23
87
|
const [draft, setDraft] = useState(() => JSON.stringify(features, null, 2));
|
|
24
88
|
const [status, setStatus] = useState("idle");
|
|
25
89
|
const [error, setError] = useState("");
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
const next = JSON.parse(draft);
|
|
29
|
-
if (!Array.isArray(next)) throw new Error("Manifest must be an array");
|
|
30
|
-
return next;
|
|
31
|
-
} catch {
|
|
32
|
-
return null;
|
|
33
|
-
}
|
|
34
|
-
}, [draft]);
|
|
90
|
+
const parsedResult = useMemo(() => parseDraft(draft, schema), [draft, schema]);
|
|
91
|
+
const parsed = parsedResult.parsed;
|
|
35
92
|
const save = async () => {
|
|
36
93
|
if (readOnly || !parsed) return;
|
|
37
94
|
setStatus("saving");
|
|
@@ -69,13 +126,26 @@ function ManifestEditor({
|
|
|
69
126
|
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px", marginTop: "8px" }, children: [
|
|
70
127
|
/* @__PURE__ */ jsx("button", { type: "button", onClick: save, disabled: readOnly || !parsed, children: "Save" }),
|
|
71
128
|
/* @__PURE__ */ jsx("span", { "aria-live": "polite", children: status }),
|
|
72
|
-
!parsed && /* @__PURE__ */ jsx("span", { style: { color: "#dc2626" }, children: "Invalid JSON" }),
|
|
129
|
+
!parsed && /* @__PURE__ */ jsx("span", { style: { color: "#dc2626" }, children: parsedResult.error || "Invalid JSON" }),
|
|
73
130
|
error && /* @__PURE__ */ jsx("span", { style: { color: "#dc2626" }, children: error })
|
|
74
131
|
] })
|
|
75
132
|
] });
|
|
76
133
|
}
|
|
77
|
-
function
|
|
134
|
+
function toDateTimeInputMin(value) {
|
|
135
|
+
if (!value) return void 0;
|
|
136
|
+
const date = new Date(value);
|
|
137
|
+
if (Number.isNaN(date.getTime())) return void 0;
|
|
138
|
+
return date.toISOString().slice(0, 16);
|
|
139
|
+
}
|
|
140
|
+
function ScheduleCalendar({
|
|
141
|
+
features,
|
|
142
|
+
onSchedule,
|
|
143
|
+
onExpire,
|
|
144
|
+
minDate
|
|
145
|
+
}) {
|
|
78
146
|
const [values, setValues] = useState({});
|
|
147
|
+
const [expireValues, setExpireValues] = useState({});
|
|
148
|
+
const minDateInput = toDateTimeInputMin(minDate);
|
|
79
149
|
return /* @__PURE__ */ jsxs("section", { "data-featuredrop-admin-schedule-calendar": true, style: panelStyles, children: [
|
|
80
150
|
/* @__PURE__ */ jsx("p", { style: headingStyles, children: "Schedule Calendar" }),
|
|
81
151
|
/* @__PURE__ */ jsx("ul", { style: { margin: 0, padding: 0, listStyle: "none", display: "grid", gap: "10px" }, children: features.map((feature) => /* @__PURE__ */ jsxs(
|
|
@@ -97,6 +167,7 @@ function ScheduleCalendar({ features, onSchedule }) {
|
|
|
97
167
|
{
|
|
98
168
|
type: "datetime-local",
|
|
99
169
|
value: values[feature.id] ?? "",
|
|
170
|
+
min: minDateInput,
|
|
100
171
|
onChange: (event) => {
|
|
101
172
|
const value = event.target.value;
|
|
102
173
|
setValues((previous) => ({ ...previous, [feature.id]: value }));
|
|
@@ -104,6 +175,21 @@ function ScheduleCalendar({ features, onSchedule }) {
|
|
|
104
175
|
}
|
|
105
176
|
)
|
|
106
177
|
] }),
|
|
178
|
+
onExpire && /* @__PURE__ */ jsxs("label", { style: { display: "grid", gap: "4px" }, children: [
|
|
179
|
+
"Expire at",
|
|
180
|
+
/* @__PURE__ */ jsx(
|
|
181
|
+
"input",
|
|
182
|
+
{
|
|
183
|
+
type: "datetime-local",
|
|
184
|
+
value: expireValues[feature.id] ?? "",
|
|
185
|
+
min: minDateInput,
|
|
186
|
+
onChange: (event) => {
|
|
187
|
+
const value = event.target.value;
|
|
188
|
+
setExpireValues((previous) => ({ ...previous, [feature.id]: value }));
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
)
|
|
192
|
+
] }),
|
|
107
193
|
/* @__PURE__ */ jsx(
|
|
108
194
|
"button",
|
|
109
195
|
{
|
|
@@ -115,6 +201,18 @@ function ScheduleCalendar({ features, onSchedule }) {
|
|
|
115
201
|
},
|
|
116
202
|
children: "Schedule"
|
|
117
203
|
}
|
|
204
|
+
),
|
|
205
|
+
onExpire && /* @__PURE__ */ jsx(
|
|
206
|
+
"button",
|
|
207
|
+
{
|
|
208
|
+
type: "button",
|
|
209
|
+
onClick: () => {
|
|
210
|
+
const value = expireValues[feature.id];
|
|
211
|
+
if (!value) return;
|
|
212
|
+
void onExpire(feature.id, new Date(value).toISOString());
|
|
213
|
+
},
|
|
214
|
+
children: "Set expiry"
|
|
215
|
+
}
|
|
118
216
|
)
|
|
119
217
|
]
|
|
120
218
|
},
|
|
@@ -122,27 +220,45 @@ function ScheduleCalendar({ features, onSchedule }) {
|
|
|
122
220
|
)) })
|
|
123
221
|
] });
|
|
124
222
|
}
|
|
125
|
-
function PreviewPanel({
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
223
|
+
function PreviewPanel({
|
|
224
|
+
feature,
|
|
225
|
+
components = ["badge", "changelog"],
|
|
226
|
+
theme = "light"
|
|
227
|
+
}) {
|
|
228
|
+
const dark = theme === "dark";
|
|
229
|
+
return /* @__PURE__ */ jsxs(
|
|
230
|
+
"section",
|
|
231
|
+
{
|
|
232
|
+
"data-featuredrop-admin-preview-panel": true,
|
|
233
|
+
"data-featuredrop-theme": theme,
|
|
234
|
+
style: {
|
|
235
|
+
...panelStyles,
|
|
236
|
+
background: dark ? "#111827" : "#ffffff",
|
|
237
|
+
borderColor: dark ? "#374151" : "#e5e7eb",
|
|
238
|
+
color: dark ? "#f9fafb" : "#111827"
|
|
239
|
+
},
|
|
240
|
+
children: [
|
|
241
|
+
/* @__PURE__ */ jsx("p", { style: headingStyles, children: "Preview Panel" }),
|
|
242
|
+
!feature ? /* @__PURE__ */ jsx("p", { style: { margin: 0, color: dark ? "#9ca3af" : "#6b7280" }, children: "Select a feature to preview." }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
243
|
+
/* @__PURE__ */ jsx("p", { style: { margin: "0 0 6px", fontWeight: 600 }, children: feature.label }),
|
|
244
|
+
/* @__PURE__ */ jsx("p", { style: { margin: "0 0 8px", color: dark ? "#9ca3af" : "#6b7280" }, children: feature.description ?? "No description" }),
|
|
245
|
+
/* @__PURE__ */ jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: "6px" }, children: components.map((component) => /* @__PURE__ */ jsx(
|
|
246
|
+
"span",
|
|
247
|
+
{
|
|
248
|
+
style: {
|
|
249
|
+
border: dark ? "1px solid #4b5563" : "1px solid #d1d5db",
|
|
250
|
+
borderRadius: "999px",
|
|
251
|
+
padding: "2px 8px",
|
|
252
|
+
fontSize: "12px"
|
|
253
|
+
},
|
|
254
|
+
children: component
|
|
255
|
+
},
|
|
256
|
+
component
|
|
257
|
+
)) })
|
|
258
|
+
] })
|
|
259
|
+
]
|
|
260
|
+
}
|
|
261
|
+
);
|
|
146
262
|
}
|
|
147
263
|
function toggle(list, value) {
|
|
148
264
|
const items = new Set(list ?? []);
|
package/dist/admin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/admin/index.tsx"],"names":[],"mappings":"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","file":"admin.js","sourcesContent":["import { useMemo, useState, type CSSProperties, type ReactNode } from \"react\";\nimport type { AudienceRule, FeatureEntry } from \"../types\";\n\nconst panelStyles: CSSProperties = {\n border: \"1px solid #e5e7eb\",\n borderRadius: \"10px\",\n padding: \"12px\",\n background: \"#ffffff\",\n};\n\nconst headingStyles: CSSProperties = {\n margin: \"0 0 8px\",\n fontSize: \"15px\",\n fontWeight: 700,\n};\n\nexport interface ManifestEditorProps {\n features: readonly FeatureEntry[];\n onSave: (updated: FeatureEntry[]) => Promise<void> | void;\n readOnly?: boolean;\n children?: ReactNode;\n}\n\nexport function ManifestEditor({\n features,\n onSave,\n readOnly = false,\n children,\n}: ManifestEditorProps) {\n const [draft, setDraft] = useState(() => JSON.stringify(features, null, 2));\n const [status, setStatus] = useState<string>(\"idle\");\n const [error, setError] = useState<string>(\"\");\n\n const parsed = useMemo(() => {\n try {\n const next = JSON.parse(draft) as unknown;\n if (!Array.isArray(next)) throw new Error(\"Manifest must be an array\");\n return next as FeatureEntry[];\n } catch {\n return null;\n }\n }, [draft]);\n\n const save = async () => {\n if (readOnly || !parsed) return;\n setStatus(\"saving\");\n setError(\"\");\n try {\n await onSave(parsed);\n setStatus(\"saved\");\n } catch (cause) {\n setStatus(\"error\");\n setError(cause instanceof Error ? cause.message : \"Failed to save manifest\");\n }\n };\n\n if (children) return <>{children}</>;\n\n return (\n <section data-featuredrop-admin-manifest-editor style={panelStyles}>\n <p style={headingStyles}>Manifest Editor</p>\n <textarea\n aria-label=\"Manifest JSON\"\n value={draft}\n onChange={(event) => setDraft(event.target.value)}\n readOnly={readOnly}\n style={{\n width: \"100%\",\n minHeight: \"180px\",\n fontFamily: \"ui-monospace, SFMono-Regular, Menlo, monospace\",\n fontSize: \"12px\",\n lineHeight: 1.45,\n border: \"1px solid #d1d5db\",\n borderRadius: \"8px\",\n padding: \"10px\",\n }}\n />\n <div style={{ display: \"flex\", alignItems: \"center\", gap: \"8px\", marginTop: \"8px\" }}>\n <button type=\"button\" onClick={save} disabled={readOnly || !parsed}>\n Save\n </button>\n <span aria-live=\"polite\">{status}</span>\n {!parsed && <span style={{ color: \"#dc2626\" }}>Invalid JSON</span>}\n {error && <span style={{ color: \"#dc2626\" }}>{error}</span>}\n </div>\n </section>\n );\n}\n\nexport interface ScheduleCalendarProps {\n features: readonly FeatureEntry[];\n onSchedule: (featureId: string, publishAt: string) => Promise<void> | void;\n}\n\nexport function ScheduleCalendar({ features, onSchedule }: ScheduleCalendarProps) {\n const [values, setValues] = useState<Record<string, string>>({});\n\n return (\n <section data-featuredrop-admin-schedule-calendar style={panelStyles}>\n <p style={headingStyles}>Schedule Calendar</p>\n <ul style={{ margin: 0, padding: 0, listStyle: \"none\", display: \"grid\", gap: \"10px\" }}>\n {features.map((feature) => (\n <li\n key={feature.id}\n style={{\n border: \"1px solid #e5e7eb\",\n borderRadius: \"8px\",\n padding: \"10px\",\n display: \"grid\",\n gap: \"6px\",\n }}\n >\n <strong>{feature.label}</strong>\n <label style={{ display: \"grid\", gap: \"4px\" }}>\n Publish at\n <input\n type=\"datetime-local\"\n value={values[feature.id] ?? \"\"}\n onChange={(event) => {\n const value = event.target.value;\n setValues((previous) => ({ ...previous, [feature.id]: value }));\n }}\n />\n </label>\n <button\n type=\"button\"\n onClick={() => {\n const value = values[feature.id];\n if (!value) return;\n void onSchedule(feature.id, new Date(value).toISOString());\n }}\n >\n Schedule\n </button>\n </li>\n ))}\n </ul>\n </section>\n );\n}\n\nexport interface PreviewPanelProps {\n feature?: FeatureEntry | null;\n components?: Array<\"badge\" | \"changelog\" | \"spotlight\" | \"banner\" | \"toast\">;\n}\n\nexport function PreviewPanel({ feature, components = [\"badge\", \"changelog\"] }: PreviewPanelProps) {\n return (\n <section data-featuredrop-admin-preview-panel style={panelStyles}>\n <p style={headingStyles}>Preview Panel</p>\n {!feature ? (\n <p style={{ margin: 0, color: \"#6b7280\" }}>Select a feature to preview.</p>\n ) : (\n <>\n <p style={{ margin: \"0 0 6px\", fontWeight: 600 }}>{feature.label}</p>\n <p style={{ margin: \"0 0 8px\", color: \"#6b7280\" }}>{feature.description ?? \"No description\"}</p>\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: \"6px\" }}>\n {components.map((component) => (\n <span\n key={component}\n style={{\n border: \"1px solid #d1d5db\",\n borderRadius: \"999px\",\n padding: \"2px 8px\",\n fontSize: \"12px\",\n }}\n >\n {component}\n </span>\n ))}\n </div>\n </>\n )}\n </section>\n );\n}\n\nexport interface AudienceBuilderProps {\n segments?: string[];\n roles?: string[];\n regions?: string[];\n value?: AudienceRule;\n onChange?: (audience: AudienceRule) => void;\n onSave?: (audience: AudienceRule) => Promise<void> | void;\n}\n\nfunction toggle(list: string[] | undefined, value: string): string[] {\n const items = new Set(list ?? []);\n if (items.has(value)) items.delete(value);\n else items.add(value);\n return Array.from(items);\n}\n\nexport function AudienceBuilder({\n segments = [],\n roles = [],\n regions = [],\n value,\n onChange,\n onSave,\n}: AudienceBuilderProps) {\n const [audience, setAudience] = useState<AudienceRule>({\n plan: value?.plan ?? [],\n role: value?.role ?? [],\n region: value?.region ?? [],\n });\n\n const updateAudience = (next: AudienceRule) => {\n setAudience(next);\n onChange?.(next);\n };\n\n const section = (\n title: string,\n values: string[],\n selected: string[] | undefined,\n onToggle: (value: string) => void,\n ) => (\n <fieldset style={{ border: \"none\", margin: 0, padding: 0 }}>\n <legend style={{ fontWeight: 600, marginBottom: \"4px\" }}>{title}</legend>\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: \"8px\" }}>\n {values.map((item) => (\n <label key={item} style={{ display: \"inline-flex\", alignItems: \"center\", gap: \"6px\" }}>\n <input\n type=\"checkbox\"\n checked={Boolean(selected?.includes(item))}\n onChange={() => onToggle(item)}\n />\n {item}\n </label>\n ))}\n </div>\n </fieldset>\n );\n\n return (\n <section data-featuredrop-admin-audience-builder style={panelStyles}>\n <p style={headingStyles}>Audience Builder</p>\n <div style={{ display: \"grid\", gap: \"10px\" }}>\n {section(\"Plans\", segments, audience.plan, (item) =>\n updateAudience({ ...audience, plan: toggle(audience.plan, item) }))}\n {section(\"Roles\", roles, audience.role, (item) =>\n updateAudience({ ...audience, role: toggle(audience.role, item) }))}\n {section(\"Regions\", regions, audience.region, (item) =>\n updateAudience({ ...audience, region: toggle(audience.region, item) }))}\n </div>\n {onSave && (\n <button\n type=\"button\"\n style={{ marginTop: \"10px\" }}\n onClick={() => {\n void onSave(audience);\n }}\n >\n Save audience\n </button>\n )}\n </section>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/admin/index.tsx"],"names":[],"mappings":"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","file":"admin.js","sourcesContent":["import { useMemo, useState, type CSSProperties, type ReactNode } from \"react\";\nimport type { AudienceRule, FeatureEntry } from \"../types\";\n\nconst panelStyles: CSSProperties = {\n border: \"1px solid #e5e7eb\",\n borderRadius: \"10px\",\n padding: \"12px\",\n background: \"#ffffff\",\n};\n\nconst headingStyles: CSSProperties = {\n margin: \"0 0 8px\",\n fontSize: \"15px\",\n fontWeight: 700,\n};\n\nexport interface ManifestEditorProps {\n features: readonly FeatureEntry[];\n onSave: (updated: FeatureEntry[]) => Promise<void> | void;\n schema?: {\n parse?: (value: unknown) => unknown;\n safeParse?: (value: unknown) => { success: boolean; data?: unknown; error?: unknown };\n };\n readOnly?: boolean;\n children?: ReactNode;\n}\n\ninterface DraftParseResult {\n parsed: FeatureEntry[] | null;\n error: string;\n}\n\nfunction toErrorMessage(error: unknown): string {\n if (error instanceof Error && error.message) return error.message;\n if (typeof error === \"string\" && error.trim()) return error.trim();\n return \"Invalid manifest data\";\n}\n\nfunction parseDraft(\n draft: string,\n schema: ManifestEditorProps[\"schema\"] | undefined,\n): DraftParseResult {\n try {\n const raw = JSON.parse(draft) as unknown;\n if (!Array.isArray(raw)) {\n return {\n parsed: null,\n error: \"Manifest must be an array\",\n };\n }\n\n if (!schema) {\n return {\n parsed: raw as FeatureEntry[],\n error: \"\",\n };\n }\n\n if (typeof schema.safeParse === \"function\") {\n const result = schema.safeParse(raw);\n if (!result.success) {\n return {\n parsed: null,\n error: toErrorMessage(result.error),\n };\n }\n if (!Array.isArray(result.data)) {\n return {\n parsed: null,\n error: \"Schema output must be an array\",\n };\n }\n return {\n parsed: result.data as FeatureEntry[],\n error: \"\",\n };\n }\n\n if (typeof schema.parse === \"function\") {\n const parsed = schema.parse(raw);\n if (!Array.isArray(parsed)) {\n return {\n parsed: null,\n error: \"Schema output must be an array\",\n };\n }\n return {\n parsed: parsed as FeatureEntry[],\n error: \"\",\n };\n }\n\n return {\n parsed: raw as FeatureEntry[],\n error: \"\",\n };\n } catch (error: unknown) {\n return {\n parsed: null,\n error: toErrorMessage(error),\n };\n }\n}\n\nexport function ManifestEditor({\n features,\n onSave,\n schema,\n readOnly = false,\n children,\n}: ManifestEditorProps) {\n const [draft, setDraft] = useState(() => JSON.stringify(features, null, 2));\n const [status, setStatus] = useState<string>(\"idle\");\n const [error, setError] = useState<string>(\"\");\n\n const parsedResult = useMemo(() => parseDraft(draft, schema), [draft, schema]);\n const parsed = parsedResult.parsed;\n\n const save = async () => {\n if (readOnly || !parsed) return;\n setStatus(\"saving\");\n setError(\"\");\n try {\n await onSave(parsed);\n setStatus(\"saved\");\n } catch (cause) {\n setStatus(\"error\");\n setError(cause instanceof Error ? cause.message : \"Failed to save manifest\");\n }\n };\n\n if (children) return <>{children}</>;\n\n return (\n <section data-featuredrop-admin-manifest-editor style={panelStyles}>\n <p style={headingStyles}>Manifest Editor</p>\n <textarea\n aria-label=\"Manifest JSON\"\n value={draft}\n onChange={(event) => setDraft(event.target.value)}\n readOnly={readOnly}\n style={{\n width: \"100%\",\n minHeight: \"180px\",\n fontFamily: \"ui-monospace, SFMono-Regular, Menlo, monospace\",\n fontSize: \"12px\",\n lineHeight: 1.45,\n border: \"1px solid #d1d5db\",\n borderRadius: \"8px\",\n padding: \"10px\",\n }}\n />\n <div style={{ display: \"flex\", alignItems: \"center\", gap: \"8px\", marginTop: \"8px\" }}>\n <button type=\"button\" onClick={save} disabled={readOnly || !parsed}>\n Save\n </button>\n <span aria-live=\"polite\">{status}</span>\n {!parsed && <span style={{ color: \"#dc2626\" }}>{parsedResult.error || \"Invalid JSON\"}</span>}\n {error && <span style={{ color: \"#dc2626\" }}>{error}</span>}\n </div>\n </section>\n );\n}\n\nexport interface ScheduleCalendarProps {\n features: readonly FeatureEntry[];\n onSchedule: (featureId: string, publishAt: string) => Promise<void> | void;\n onExpire?: (featureId: string, expiresAt: string) => Promise<void> | void;\n minDate?: string;\n}\n\nfunction toDateTimeInputMin(value: string | undefined): string | undefined {\n if (!value) return undefined;\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) return undefined;\n return date.toISOString().slice(0, 16);\n}\n\nexport function ScheduleCalendar({\n features,\n onSchedule,\n onExpire,\n minDate,\n}: ScheduleCalendarProps) {\n const [values, setValues] = useState<Record<string, string>>({});\n const [expireValues, setExpireValues] = useState<Record<string, string>>({});\n const minDateInput = toDateTimeInputMin(minDate);\n\n return (\n <section data-featuredrop-admin-schedule-calendar style={panelStyles}>\n <p style={headingStyles}>Schedule Calendar</p>\n <ul style={{ margin: 0, padding: 0, listStyle: \"none\", display: \"grid\", gap: \"10px\" }}>\n {features.map((feature) => (\n <li\n key={feature.id}\n style={{\n border: \"1px solid #e5e7eb\",\n borderRadius: \"8px\",\n padding: \"10px\",\n display: \"grid\",\n gap: \"6px\",\n }}\n >\n <strong>{feature.label}</strong>\n <label style={{ display: \"grid\", gap: \"4px\" }}>\n Publish at\n <input\n type=\"datetime-local\"\n value={values[feature.id] ?? \"\"}\n min={minDateInput}\n onChange={(event) => {\n const value = event.target.value;\n setValues((previous) => ({ ...previous, [feature.id]: value }));\n }}\n />\n </label>\n {onExpire && (\n <label style={{ display: \"grid\", gap: \"4px\" }}>\n Expire at\n <input\n type=\"datetime-local\"\n value={expireValues[feature.id] ?? \"\"}\n min={minDateInput}\n onChange={(event) => {\n const value = event.target.value;\n setExpireValues((previous) => ({ ...previous, [feature.id]: value }));\n }}\n />\n </label>\n )}\n <button\n type=\"button\"\n onClick={() => {\n const value = values[feature.id];\n if (!value) return;\n void onSchedule(feature.id, new Date(value).toISOString());\n }}\n >\n Schedule\n </button>\n {onExpire && (\n <button\n type=\"button\"\n onClick={() => {\n const value = expireValues[feature.id];\n if (!value) return;\n void onExpire(feature.id, new Date(value).toISOString());\n }}\n >\n Set expiry\n </button>\n )}\n </li>\n ))}\n </ul>\n </section>\n );\n}\n\nexport interface PreviewPanelProps {\n feature?: FeatureEntry | null;\n components?: Array<\"badge\" | \"changelog\" | \"spotlight\" | \"banner\" | \"toast\">;\n theme?: \"light\" | \"dark\";\n}\n\nexport function PreviewPanel({\n feature,\n components = [\"badge\", \"changelog\"],\n theme = \"light\",\n}: PreviewPanelProps) {\n const dark = theme === \"dark\";\n return (\n <section\n data-featuredrop-admin-preview-panel\n data-featuredrop-theme={theme}\n style={{\n ...panelStyles,\n background: dark ? \"#111827\" : \"#ffffff\",\n borderColor: dark ? \"#374151\" : \"#e5e7eb\",\n color: dark ? \"#f9fafb\" : \"#111827\",\n }}\n >\n <p style={headingStyles}>Preview Panel</p>\n {!feature ? (\n <p style={{ margin: 0, color: dark ? \"#9ca3af\" : \"#6b7280\" }}>Select a feature to preview.</p>\n ) : (\n <>\n <p style={{ margin: \"0 0 6px\", fontWeight: 600 }}>{feature.label}</p>\n <p style={{ margin: \"0 0 8px\", color: dark ? \"#9ca3af\" : \"#6b7280\" }}>\n {feature.description ?? \"No description\"}\n </p>\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: \"6px\" }}>\n {components.map((component) => (\n <span\n key={component}\n style={{\n border: dark ? \"1px solid #4b5563\" : \"1px solid #d1d5db\",\n borderRadius: \"999px\",\n padding: \"2px 8px\",\n fontSize: \"12px\",\n }}\n >\n {component}\n </span>\n ))}\n </div>\n </>\n )}\n </section>\n );\n}\n\nexport interface AudienceBuilderProps {\n segments?: string[];\n roles?: string[];\n regions?: string[];\n value?: AudienceRule;\n onChange?: (audience: AudienceRule) => void;\n onSave?: (audience: AudienceRule) => Promise<void> | void;\n}\n\nfunction toggle(list: string[] | undefined, value: string): string[] {\n const items = new Set(list ?? []);\n if (items.has(value)) items.delete(value);\n else items.add(value);\n return Array.from(items);\n}\n\nexport function AudienceBuilder({\n segments = [],\n roles = [],\n regions = [],\n value,\n onChange,\n onSave,\n}: AudienceBuilderProps) {\n const [audience, setAudience] = useState<AudienceRule>({\n plan: value?.plan ?? [],\n role: value?.role ?? [],\n region: value?.region ?? [],\n });\n\n const updateAudience = (next: AudienceRule) => {\n setAudience(next);\n onChange?.(next);\n };\n\n const section = (\n title: string,\n values: string[],\n selected: string[] | undefined,\n onToggle: (value: string) => void,\n ) => (\n <fieldset style={{ border: \"none\", margin: 0, padding: 0 }}>\n <legend style={{ fontWeight: 600, marginBottom: \"4px\" }}>{title}</legend>\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: \"8px\" }}>\n {values.map((item) => (\n <label key={item} style={{ display: \"inline-flex\", alignItems: \"center\", gap: \"6px\" }}>\n <input\n type=\"checkbox\"\n checked={Boolean(selected?.includes(item))}\n onChange={() => onToggle(item)}\n />\n {item}\n </label>\n ))}\n </div>\n </fieldset>\n );\n\n return (\n <section data-featuredrop-admin-audience-builder style={panelStyles}>\n <p style={headingStyles}>Audience Builder</p>\n <div style={{ display: \"grid\", gap: \"10px\" }}>\n {section(\"Plans\", segments, audience.plan, (item) =>\n updateAudience({ ...audience, plan: toggle(audience.plan, item) }))}\n {section(\"Roles\", roles, audience.role, (item) =>\n updateAudience({ ...audience, role: toggle(audience.role, item) }))}\n {section(\"Regions\", regions, audience.region, (item) =>\n updateAudience({ ...audience, region: toggle(audience.region, item) }))}\n </div>\n {onSave && (\n <button\n type=\"button\"\n style={{ marginTop: \"10px\" }}\n onClick={() => {\n void onSave(audience);\n }}\n >\n Save audience\n </button>\n )}\n </section>\n );\n}\n"]}
|