featuredrop 1.1.0 → 1.3.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 +547 -4
- package/dist/admin.cjs +212 -0
- package/dist/admin.cjs.map +1 -0
- package/dist/admin.d.cts +176 -0
- package/dist/admin.d.ts +176 -0
- package/dist/admin.js +207 -0
- package/dist/admin.js.map +1 -0
- package/dist/angular.cjs +296 -0
- package/dist/angular.cjs.map +1 -0
- package/dist/angular.d.cts +233 -0
- package/dist/angular.d.ts +233 -0
- package/dist/angular.js +293 -0
- package/dist/angular.js.map +1 -0
- package/dist/bridges.cjs +401 -0
- package/dist/bridges.cjs.map +1 -0
- package/dist/bridges.d.cts +194 -0
- package/dist/bridges.d.ts +194 -0
- package/dist/bridges.js +394 -0
- package/dist/bridges.js.map +1 -0
- package/dist/ci.cjs +328 -0
- package/dist/ci.cjs.map +1 -0
- package/dist/ci.d.cts +176 -0
- package/dist/ci.d.ts +176 -0
- package/dist/ci.js +324 -0
- package/dist/ci.js.map +1 -0
- package/dist/featuredrop.cjs +1377 -0
- package/dist/featuredrop.cjs.map +1 -0
- package/dist/flags.cjs +51 -0
- package/dist/flags.cjs.map +1 -0
- package/dist/flags.d.cts +48 -0
- package/dist/flags.d.ts +48 -0
- package/dist/flags.js +47 -0
- package/dist/flags.js.map +1 -0
- package/dist/index.cjs +4734 -70
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1516 -9
- package/dist/index.d.ts +1516 -9
- package/dist/index.js +4660 -71
- package/dist/index.js.map +1 -1
- package/dist/preact.cjs +7790 -0
- package/dist/preact.cjs.map +1 -0
- package/dist/preact.d.cts +1213 -0
- package/dist/preact.d.ts +1213 -0
- package/dist/preact.js +7760 -0
- package/dist/preact.js.map +1 -0
- package/dist/react.cjs +6678 -159
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +852 -112
- package/dist/react.d.ts +852 -112
- package/dist/react.js +6657 -156
- package/dist/react.js.map +1 -1
- package/dist/schema.cjs +292 -0
- package/dist/schema.cjs.map +1 -0
- package/dist/schema.d.cts +345 -0
- package/dist/schema.d.ts +345 -0
- package/dist/schema.js +286 -0
- package/dist/schema.js.map +1 -0
- package/dist/solid.cjs +383 -0
- package/dist/solid.cjs.map +1 -0
- package/dist/solid.d.cts +246 -0
- package/dist/solid.d.ts +246 -0
- package/dist/solid.js +376 -0
- package/dist/solid.js.map +1 -0
- package/dist/svelte.cjs +339 -0
- package/dist/svelte.cjs.map +1 -0
- package/dist/svelte.js +334 -0
- package/dist/svelte.js.map +1 -0
- package/dist/testing.cjs +1543 -0
- package/dist/testing.cjs.map +1 -0
- package/dist/testing.d.cts +361 -0
- package/dist/testing.d.ts +361 -0
- package/dist/testing.js +1536 -0
- package/dist/testing.js.map +1 -0
- package/dist/vue.cjs +1094 -0
- package/dist/vue.cjs.map +1 -0
- package/dist/vue.js +1082 -0
- package/dist/vue.js.map +1 -0
- package/dist/web-components.cjs +493 -0
- package/dist/web-components.cjs.map +1 -0
- package/dist/web-components.d.cts +215 -0
- package/dist/web-components.d.ts +215 -0
- package/dist/web-components.js +487 -0
- package/dist/web-components.js.map +1 -0
- package/package.json +184 -3
package/dist/admin.cjs
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var react = require('react');
|
|
5
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
6
|
+
|
|
7
|
+
// src/admin/index.tsx
|
|
8
|
+
var panelStyles = {
|
|
9
|
+
border: "1px solid #e5e7eb",
|
|
10
|
+
borderRadius: "10px",
|
|
11
|
+
padding: "12px",
|
|
12
|
+
background: "#ffffff"
|
|
13
|
+
};
|
|
14
|
+
var headingStyles = {
|
|
15
|
+
margin: "0 0 8px",
|
|
16
|
+
fontSize: "15px",
|
|
17
|
+
fontWeight: 700
|
|
18
|
+
};
|
|
19
|
+
function ManifestEditor({
|
|
20
|
+
features,
|
|
21
|
+
onSave,
|
|
22
|
+
readOnly = false,
|
|
23
|
+
children
|
|
24
|
+
}) {
|
|
25
|
+
const [draft, setDraft] = react.useState(() => JSON.stringify(features, null, 2));
|
|
26
|
+
const [status, setStatus] = react.useState("idle");
|
|
27
|
+
const [error, setError] = react.useState("");
|
|
28
|
+
const parsed = react.useMemo(() => {
|
|
29
|
+
try {
|
|
30
|
+
const next = JSON.parse(draft);
|
|
31
|
+
if (!Array.isArray(next)) throw new Error("Manifest must be an array");
|
|
32
|
+
return next;
|
|
33
|
+
} catch {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
}, [draft]);
|
|
37
|
+
const save = async () => {
|
|
38
|
+
if (readOnly || !parsed) return;
|
|
39
|
+
setStatus("saving");
|
|
40
|
+
setError("");
|
|
41
|
+
try {
|
|
42
|
+
await onSave(parsed);
|
|
43
|
+
setStatus("saved");
|
|
44
|
+
} catch (cause) {
|
|
45
|
+
setStatus("error");
|
|
46
|
+
setError(cause instanceof Error ? cause.message : "Failed to save manifest");
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
if (children) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
|
|
50
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("section", { "data-featuredrop-admin-manifest-editor": true, style: panelStyles, children: [
|
|
51
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { style: headingStyles, children: "Manifest Editor" }),
|
|
52
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
53
|
+
"textarea",
|
|
54
|
+
{
|
|
55
|
+
"aria-label": "Manifest JSON",
|
|
56
|
+
value: draft,
|
|
57
|
+
onChange: (event) => setDraft(event.target.value),
|
|
58
|
+
readOnly,
|
|
59
|
+
style: {
|
|
60
|
+
width: "100%",
|
|
61
|
+
minHeight: "180px",
|
|
62
|
+
fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
|
|
63
|
+
fontSize: "12px",
|
|
64
|
+
lineHeight: 1.45,
|
|
65
|
+
border: "1px solid #d1d5db",
|
|
66
|
+
borderRadius: "8px",
|
|
67
|
+
padding: "10px"
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
),
|
|
71
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px", marginTop: "8px" }, children: [
|
|
72
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: save, disabled: readOnly || !parsed, children: "Save" }),
|
|
73
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { "aria-live": "polite", children: status }),
|
|
74
|
+
!parsed && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "#dc2626" }, children: "Invalid JSON" }),
|
|
75
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "#dc2626" }, children: error })
|
|
76
|
+
] })
|
|
77
|
+
] });
|
|
78
|
+
}
|
|
79
|
+
function ScheduleCalendar({ features, onSchedule }) {
|
|
80
|
+
const [values, setValues] = react.useState({});
|
|
81
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("section", { "data-featuredrop-admin-schedule-calendar": true, style: panelStyles, children: [
|
|
82
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { style: headingStyles, children: "Schedule Calendar" }),
|
|
83
|
+
/* @__PURE__ */ jsxRuntime.jsx("ul", { style: { margin: 0, padding: 0, listStyle: "none", display: "grid", gap: "10px" }, children: features.map((feature) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
84
|
+
"li",
|
|
85
|
+
{
|
|
86
|
+
style: {
|
|
87
|
+
border: "1px solid #e5e7eb",
|
|
88
|
+
borderRadius: "8px",
|
|
89
|
+
padding: "10px",
|
|
90
|
+
display: "grid",
|
|
91
|
+
gap: "6px"
|
|
92
|
+
},
|
|
93
|
+
children: [
|
|
94
|
+
/* @__PURE__ */ jsxRuntime.jsx("strong", { children: feature.label }),
|
|
95
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { style: { display: "grid", gap: "4px" }, children: [
|
|
96
|
+
"Publish at",
|
|
97
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
98
|
+
"input",
|
|
99
|
+
{
|
|
100
|
+
type: "datetime-local",
|
|
101
|
+
value: values[feature.id] ?? "",
|
|
102
|
+
onChange: (event) => {
|
|
103
|
+
const value = event.target.value;
|
|
104
|
+
setValues((previous) => ({ ...previous, [feature.id]: value }));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
)
|
|
108
|
+
] }),
|
|
109
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
110
|
+
"button",
|
|
111
|
+
{
|
|
112
|
+
type: "button",
|
|
113
|
+
onClick: () => {
|
|
114
|
+
const value = values[feature.id];
|
|
115
|
+
if (!value) return;
|
|
116
|
+
void onSchedule(feature.id, new Date(value).toISOString());
|
|
117
|
+
},
|
|
118
|
+
children: "Schedule"
|
|
119
|
+
}
|
|
120
|
+
)
|
|
121
|
+
]
|
|
122
|
+
},
|
|
123
|
+
feature.id
|
|
124
|
+
)) })
|
|
125
|
+
] });
|
|
126
|
+
}
|
|
127
|
+
function PreviewPanel({ feature, components = ["badge", "changelog"] }) {
|
|
128
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("section", { "data-featuredrop-admin-preview-panel": true, style: panelStyles, children: [
|
|
129
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { style: headingStyles, children: "Preview Panel" }),
|
|
130
|
+
!feature ? /* @__PURE__ */ jsxRuntime.jsx("p", { style: { margin: 0, color: "#6b7280" }, children: "Select a feature to preview." }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
131
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { style: { margin: "0 0 6px", fontWeight: 600 }, children: feature.label }),
|
|
132
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { style: { margin: "0 0 8px", color: "#6b7280" }, children: feature.description ?? "No description" }),
|
|
133
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: "6px" }, children: components.map((component) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
134
|
+
"span",
|
|
135
|
+
{
|
|
136
|
+
style: {
|
|
137
|
+
border: "1px solid #d1d5db",
|
|
138
|
+
borderRadius: "999px",
|
|
139
|
+
padding: "2px 8px",
|
|
140
|
+
fontSize: "12px"
|
|
141
|
+
},
|
|
142
|
+
children: component
|
|
143
|
+
},
|
|
144
|
+
component
|
|
145
|
+
)) })
|
|
146
|
+
] })
|
|
147
|
+
] });
|
|
148
|
+
}
|
|
149
|
+
function toggle(list, value) {
|
|
150
|
+
const items = new Set(list ?? []);
|
|
151
|
+
if (items.has(value)) items.delete(value);
|
|
152
|
+
else items.add(value);
|
|
153
|
+
return Array.from(items);
|
|
154
|
+
}
|
|
155
|
+
function AudienceBuilder({
|
|
156
|
+
segments = [],
|
|
157
|
+
roles = [],
|
|
158
|
+
regions = [],
|
|
159
|
+
value,
|
|
160
|
+
onChange,
|
|
161
|
+
onSave
|
|
162
|
+
}) {
|
|
163
|
+
const [audience, setAudience] = react.useState({
|
|
164
|
+
plan: value?.plan ?? [],
|
|
165
|
+
role: value?.role ?? [],
|
|
166
|
+
region: value?.region ?? []
|
|
167
|
+
});
|
|
168
|
+
const updateAudience = (next) => {
|
|
169
|
+
setAudience(next);
|
|
170
|
+
onChange?.(next);
|
|
171
|
+
};
|
|
172
|
+
const section = (title, values, selected, onToggle) => /* @__PURE__ */ jsxRuntime.jsxs("fieldset", { style: { border: "none", margin: 0, padding: 0 }, children: [
|
|
173
|
+
/* @__PURE__ */ jsxRuntime.jsx("legend", { style: { fontWeight: 600, marginBottom: "4px" }, children: title }),
|
|
174
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: "8px" }, children: values.map((item) => /* @__PURE__ */ jsxRuntime.jsxs("label", { style: { display: "inline-flex", alignItems: "center", gap: "6px" }, children: [
|
|
175
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
176
|
+
"input",
|
|
177
|
+
{
|
|
178
|
+
type: "checkbox",
|
|
179
|
+
checked: Boolean(selected?.includes(item)),
|
|
180
|
+
onChange: () => onToggle(item)
|
|
181
|
+
}
|
|
182
|
+
),
|
|
183
|
+
item
|
|
184
|
+
] }, item)) })
|
|
185
|
+
] });
|
|
186
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("section", { "data-featuredrop-admin-audience-builder": true, style: panelStyles, children: [
|
|
187
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { style: headingStyles, children: "Audience Builder" }),
|
|
188
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "grid", gap: "10px" }, children: [
|
|
189
|
+
section("Plans", segments, audience.plan, (item) => updateAudience({ ...audience, plan: toggle(audience.plan, item) })),
|
|
190
|
+
section("Roles", roles, audience.role, (item) => updateAudience({ ...audience, role: toggle(audience.role, item) })),
|
|
191
|
+
section("Regions", regions, audience.region, (item) => updateAudience({ ...audience, region: toggle(audience.region, item) }))
|
|
192
|
+
] }),
|
|
193
|
+
onSave && /* @__PURE__ */ jsxRuntime.jsx(
|
|
194
|
+
"button",
|
|
195
|
+
{
|
|
196
|
+
type: "button",
|
|
197
|
+
style: { marginTop: "10px" },
|
|
198
|
+
onClick: () => {
|
|
199
|
+
void onSave(audience);
|
|
200
|
+
},
|
|
201
|
+
children: "Save audience"
|
|
202
|
+
}
|
|
203
|
+
)
|
|
204
|
+
] });
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
exports.AudienceBuilder = AudienceBuilder;
|
|
208
|
+
exports.ManifestEditor = ManifestEditor;
|
|
209
|
+
exports.PreviewPanel = PreviewPanel;
|
|
210
|
+
exports.ScheduleCalendar = ScheduleCalendar;
|
|
211
|
+
//# sourceMappingURL=admin.cjs.map
|
|
212
|
+
//# sourceMappingURL=admin.cjs.map
|
|
@@ -0,0 +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"]}
|
package/dist/admin.d.cts
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
/** Entry type label — determines default icon/color in UI */
|
|
5
|
+
type FeatureType = "feature" | "improvement" | "fix" | "breaking";
|
|
6
|
+
/** Priority level for announcements */
|
|
7
|
+
type FeaturePriority = "critical" | "normal" | "low";
|
|
8
|
+
/** Call-to-action for a feature entry */
|
|
9
|
+
interface FeatureCTA {
|
|
10
|
+
/** Button/link label */
|
|
11
|
+
label: string;
|
|
12
|
+
/** URL to navigate to */
|
|
13
|
+
url: string;
|
|
14
|
+
}
|
|
15
|
+
/** Variant-level overrides for A/B announcement testing */
|
|
16
|
+
interface FeatureVariant {
|
|
17
|
+
/** Optional variant-specific label override */
|
|
18
|
+
label?: string;
|
|
19
|
+
/** Optional variant-specific description override */
|
|
20
|
+
description?: string;
|
|
21
|
+
/** Optional variant-specific image override */
|
|
22
|
+
image?: string;
|
|
23
|
+
/** Optional variant-specific CTA override */
|
|
24
|
+
cta?: FeatureCTA;
|
|
25
|
+
/** Optional variant-specific metadata overrides */
|
|
26
|
+
meta?: Record<string, unknown>;
|
|
27
|
+
}
|
|
28
|
+
/** Audience targeting rule — determines which user segments see a feature */
|
|
29
|
+
interface AudienceRule {
|
|
30
|
+
/** Plans that should see this feature (e.g. ["pro", "enterprise"]) */
|
|
31
|
+
plan?: string[];
|
|
32
|
+
/** Roles that should see this feature (e.g. ["admin", "editor"]) */
|
|
33
|
+
role?: string[];
|
|
34
|
+
/** Regions that should see this feature (e.g. ["us", "eu"]) */
|
|
35
|
+
region?: string[];
|
|
36
|
+
/** Arbitrary key-value pairs for custom matching logic */
|
|
37
|
+
custom?: Record<string, unknown>;
|
|
38
|
+
}
|
|
39
|
+
/** Dependency gates for progressive feature discovery */
|
|
40
|
+
interface FeatureDependencies {
|
|
41
|
+
/** Features the user must have seen before this one can surface */
|
|
42
|
+
seen?: string[];
|
|
43
|
+
/** Features the user must have clicked before this one can surface */
|
|
44
|
+
clicked?: string[];
|
|
45
|
+
/** Features the user must have dismissed before this one can surface */
|
|
46
|
+
dismissed?: string[];
|
|
47
|
+
}
|
|
48
|
+
/** Runtime context used by trigger evaluation */
|
|
49
|
+
interface TriggerContext {
|
|
50
|
+
/** Current app route/path */
|
|
51
|
+
path?: string;
|
|
52
|
+
/** Named events observed in this session */
|
|
53
|
+
events?: ReadonlySet<string>;
|
|
54
|
+
/** Named milestone flags reached in this session */
|
|
55
|
+
milestones?: ReadonlySet<string>;
|
|
56
|
+
/** Usage counters keyed by event/pattern name */
|
|
57
|
+
usage?: Record<string, number>;
|
|
58
|
+
/** Session elapsed time in milliseconds */
|
|
59
|
+
elapsedMs?: number;
|
|
60
|
+
/** Scroll completion percentage (0-100) */
|
|
61
|
+
scrollPercent?: number;
|
|
62
|
+
/** Optional additional trigger context */
|
|
63
|
+
metadata?: Record<string, unknown>;
|
|
64
|
+
}
|
|
65
|
+
type FeatureTrigger = {
|
|
66
|
+
type: "page";
|
|
67
|
+
match: string | RegExp;
|
|
68
|
+
} | {
|
|
69
|
+
type: "usage";
|
|
70
|
+
event: string;
|
|
71
|
+
minActions?: number;
|
|
72
|
+
} | {
|
|
73
|
+
type: "time";
|
|
74
|
+
minSeconds: number;
|
|
75
|
+
} | {
|
|
76
|
+
type: "milestone";
|
|
77
|
+
event: string;
|
|
78
|
+
} | {
|
|
79
|
+
type: "frustration";
|
|
80
|
+
pattern: string;
|
|
81
|
+
threshold?: number;
|
|
82
|
+
} | {
|
|
83
|
+
type: "scroll";
|
|
84
|
+
minPercent?: number;
|
|
85
|
+
} | {
|
|
86
|
+
type: "custom";
|
|
87
|
+
evaluate: (context: TriggerContext) => boolean;
|
|
88
|
+
};
|
|
89
|
+
/** A single feature entry in the manifest */
|
|
90
|
+
interface FeatureEntry {
|
|
91
|
+
/** Unique identifier for the feature */
|
|
92
|
+
id: string;
|
|
93
|
+
/** Human-readable label (e.g. "Decision Journal") */
|
|
94
|
+
label: string;
|
|
95
|
+
/** Optional longer description (supports markdown in UI components) */
|
|
96
|
+
description?: string;
|
|
97
|
+
/**
|
|
98
|
+
* Semantic version targeting.
|
|
99
|
+
* If provided as an object, requires `appVersion` to be supplied to the provider/helpers.
|
|
100
|
+
* - introduced: earliest app version that includes this feature
|
|
101
|
+
* - showNewUntil: stop showing "new" once appVersion reaches this
|
|
102
|
+
* - deprecatedAt: hide feature for app versions at or above this (optional safety)
|
|
103
|
+
* - showIn: range string, e.g. ">=2.5.0 <3.0.0"
|
|
104
|
+
*/
|
|
105
|
+
version?: string | {
|
|
106
|
+
introduced?: string;
|
|
107
|
+
showNewUntil?: string;
|
|
108
|
+
deprecatedAt?: string;
|
|
109
|
+
showIn?: string;
|
|
110
|
+
};
|
|
111
|
+
/** ISO date when this feature was released */
|
|
112
|
+
releasedAt: string;
|
|
113
|
+
/** ISO date after which the "new" badge should stop showing */
|
|
114
|
+
showNewUntil: string;
|
|
115
|
+
/** Optional key to match navigation items (e.g. "/journal", "settings") */
|
|
116
|
+
sidebarKey?: string;
|
|
117
|
+
/** Optional grouping category (e.g. "ai", "billing", "core") */
|
|
118
|
+
category?: string;
|
|
119
|
+
/** Optional product scope (`"*"`, `"askverdict"`, etc.) for multi-product manifests */
|
|
120
|
+
product?: string;
|
|
121
|
+
/** Optional URL to link to (e.g. docs page, changelog entry) */
|
|
122
|
+
url?: string;
|
|
123
|
+
/** Optional feature flag key; requires a flag bridge to evaluate */
|
|
124
|
+
flagKey?: string;
|
|
125
|
+
/** Entry type — determines default icon/color in UI components */
|
|
126
|
+
type?: FeatureType;
|
|
127
|
+
/** Priority level — critical entries get special treatment in UI */
|
|
128
|
+
priority?: FeaturePriority;
|
|
129
|
+
/** Optional image/screenshot URL */
|
|
130
|
+
image?: string;
|
|
131
|
+
/** Optional call-to-action button */
|
|
132
|
+
cta?: FeatureCTA;
|
|
133
|
+
/** ISO date — entry is hidden until this date (scheduled publishing) */
|
|
134
|
+
publishAt?: string;
|
|
135
|
+
/** Optional arbitrary metadata */
|
|
136
|
+
meta?: Record<string, unknown>;
|
|
137
|
+
/** A/B variants keyed by variant name (e.g. control, treatment_a) */
|
|
138
|
+
variants?: Record<string, FeatureVariant>;
|
|
139
|
+
/** Percentage split per variant (same order as variants object keys) */
|
|
140
|
+
variantSplit?: number[];
|
|
141
|
+
/** Audience targeting — if set, only matching users see this feature */
|
|
142
|
+
audience?: AudienceRule;
|
|
143
|
+
/** Dependency requirements (progressive disclosure sequencing) */
|
|
144
|
+
dependsOn?: FeatureDependencies;
|
|
145
|
+
/** Contextual trigger rule */
|
|
146
|
+
trigger?: FeatureTrigger;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
interface ManifestEditorProps {
|
|
150
|
+
features: readonly FeatureEntry[];
|
|
151
|
+
onSave: (updated: FeatureEntry[]) => Promise<void> | void;
|
|
152
|
+
readOnly?: boolean;
|
|
153
|
+
children?: ReactNode;
|
|
154
|
+
}
|
|
155
|
+
declare function ManifestEditor({ features, onSave, readOnly, children, }: ManifestEditorProps): react_jsx_runtime.JSX.Element;
|
|
156
|
+
interface ScheduleCalendarProps {
|
|
157
|
+
features: readonly FeatureEntry[];
|
|
158
|
+
onSchedule: (featureId: string, publishAt: string) => Promise<void> | void;
|
|
159
|
+
}
|
|
160
|
+
declare function ScheduleCalendar({ features, onSchedule }: ScheduleCalendarProps): react_jsx_runtime.JSX.Element;
|
|
161
|
+
interface PreviewPanelProps {
|
|
162
|
+
feature?: FeatureEntry | null;
|
|
163
|
+
components?: Array<"badge" | "changelog" | "spotlight" | "banner" | "toast">;
|
|
164
|
+
}
|
|
165
|
+
declare function PreviewPanel({ feature, components }: PreviewPanelProps): react_jsx_runtime.JSX.Element;
|
|
166
|
+
interface AudienceBuilderProps {
|
|
167
|
+
segments?: string[];
|
|
168
|
+
roles?: string[];
|
|
169
|
+
regions?: string[];
|
|
170
|
+
value?: AudienceRule;
|
|
171
|
+
onChange?: (audience: AudienceRule) => void;
|
|
172
|
+
onSave?: (audience: AudienceRule) => Promise<void> | void;
|
|
173
|
+
}
|
|
174
|
+
declare function AudienceBuilder({ segments, roles, regions, value, onChange, onSave, }: AudienceBuilderProps): react_jsx_runtime.JSX.Element;
|
|
175
|
+
|
|
176
|
+
export { AudienceBuilder, type AudienceBuilderProps, ManifestEditor, type ManifestEditorProps, PreviewPanel, type PreviewPanelProps, ScheduleCalendar, type ScheduleCalendarProps };
|
package/dist/admin.d.ts
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
/** Entry type label — determines default icon/color in UI */
|
|
5
|
+
type FeatureType = "feature" | "improvement" | "fix" | "breaking";
|
|
6
|
+
/** Priority level for announcements */
|
|
7
|
+
type FeaturePriority = "critical" | "normal" | "low";
|
|
8
|
+
/** Call-to-action for a feature entry */
|
|
9
|
+
interface FeatureCTA {
|
|
10
|
+
/** Button/link label */
|
|
11
|
+
label: string;
|
|
12
|
+
/** URL to navigate to */
|
|
13
|
+
url: string;
|
|
14
|
+
}
|
|
15
|
+
/** Variant-level overrides for A/B announcement testing */
|
|
16
|
+
interface FeatureVariant {
|
|
17
|
+
/** Optional variant-specific label override */
|
|
18
|
+
label?: string;
|
|
19
|
+
/** Optional variant-specific description override */
|
|
20
|
+
description?: string;
|
|
21
|
+
/** Optional variant-specific image override */
|
|
22
|
+
image?: string;
|
|
23
|
+
/** Optional variant-specific CTA override */
|
|
24
|
+
cta?: FeatureCTA;
|
|
25
|
+
/** Optional variant-specific metadata overrides */
|
|
26
|
+
meta?: Record<string, unknown>;
|
|
27
|
+
}
|
|
28
|
+
/** Audience targeting rule — determines which user segments see a feature */
|
|
29
|
+
interface AudienceRule {
|
|
30
|
+
/** Plans that should see this feature (e.g. ["pro", "enterprise"]) */
|
|
31
|
+
plan?: string[];
|
|
32
|
+
/** Roles that should see this feature (e.g. ["admin", "editor"]) */
|
|
33
|
+
role?: string[];
|
|
34
|
+
/** Regions that should see this feature (e.g. ["us", "eu"]) */
|
|
35
|
+
region?: string[];
|
|
36
|
+
/** Arbitrary key-value pairs for custom matching logic */
|
|
37
|
+
custom?: Record<string, unknown>;
|
|
38
|
+
}
|
|
39
|
+
/** Dependency gates for progressive feature discovery */
|
|
40
|
+
interface FeatureDependencies {
|
|
41
|
+
/** Features the user must have seen before this one can surface */
|
|
42
|
+
seen?: string[];
|
|
43
|
+
/** Features the user must have clicked before this one can surface */
|
|
44
|
+
clicked?: string[];
|
|
45
|
+
/** Features the user must have dismissed before this one can surface */
|
|
46
|
+
dismissed?: string[];
|
|
47
|
+
}
|
|
48
|
+
/** Runtime context used by trigger evaluation */
|
|
49
|
+
interface TriggerContext {
|
|
50
|
+
/** Current app route/path */
|
|
51
|
+
path?: string;
|
|
52
|
+
/** Named events observed in this session */
|
|
53
|
+
events?: ReadonlySet<string>;
|
|
54
|
+
/** Named milestone flags reached in this session */
|
|
55
|
+
milestones?: ReadonlySet<string>;
|
|
56
|
+
/** Usage counters keyed by event/pattern name */
|
|
57
|
+
usage?: Record<string, number>;
|
|
58
|
+
/** Session elapsed time in milliseconds */
|
|
59
|
+
elapsedMs?: number;
|
|
60
|
+
/** Scroll completion percentage (0-100) */
|
|
61
|
+
scrollPercent?: number;
|
|
62
|
+
/** Optional additional trigger context */
|
|
63
|
+
metadata?: Record<string, unknown>;
|
|
64
|
+
}
|
|
65
|
+
type FeatureTrigger = {
|
|
66
|
+
type: "page";
|
|
67
|
+
match: string | RegExp;
|
|
68
|
+
} | {
|
|
69
|
+
type: "usage";
|
|
70
|
+
event: string;
|
|
71
|
+
minActions?: number;
|
|
72
|
+
} | {
|
|
73
|
+
type: "time";
|
|
74
|
+
minSeconds: number;
|
|
75
|
+
} | {
|
|
76
|
+
type: "milestone";
|
|
77
|
+
event: string;
|
|
78
|
+
} | {
|
|
79
|
+
type: "frustration";
|
|
80
|
+
pattern: string;
|
|
81
|
+
threshold?: number;
|
|
82
|
+
} | {
|
|
83
|
+
type: "scroll";
|
|
84
|
+
minPercent?: number;
|
|
85
|
+
} | {
|
|
86
|
+
type: "custom";
|
|
87
|
+
evaluate: (context: TriggerContext) => boolean;
|
|
88
|
+
};
|
|
89
|
+
/** A single feature entry in the manifest */
|
|
90
|
+
interface FeatureEntry {
|
|
91
|
+
/** Unique identifier for the feature */
|
|
92
|
+
id: string;
|
|
93
|
+
/** Human-readable label (e.g. "Decision Journal") */
|
|
94
|
+
label: string;
|
|
95
|
+
/** Optional longer description (supports markdown in UI components) */
|
|
96
|
+
description?: string;
|
|
97
|
+
/**
|
|
98
|
+
* Semantic version targeting.
|
|
99
|
+
* If provided as an object, requires `appVersion` to be supplied to the provider/helpers.
|
|
100
|
+
* - introduced: earliest app version that includes this feature
|
|
101
|
+
* - showNewUntil: stop showing "new" once appVersion reaches this
|
|
102
|
+
* - deprecatedAt: hide feature for app versions at or above this (optional safety)
|
|
103
|
+
* - showIn: range string, e.g. ">=2.5.0 <3.0.0"
|
|
104
|
+
*/
|
|
105
|
+
version?: string | {
|
|
106
|
+
introduced?: string;
|
|
107
|
+
showNewUntil?: string;
|
|
108
|
+
deprecatedAt?: string;
|
|
109
|
+
showIn?: string;
|
|
110
|
+
};
|
|
111
|
+
/** ISO date when this feature was released */
|
|
112
|
+
releasedAt: string;
|
|
113
|
+
/** ISO date after which the "new" badge should stop showing */
|
|
114
|
+
showNewUntil: string;
|
|
115
|
+
/** Optional key to match navigation items (e.g. "/journal", "settings") */
|
|
116
|
+
sidebarKey?: string;
|
|
117
|
+
/** Optional grouping category (e.g. "ai", "billing", "core") */
|
|
118
|
+
category?: string;
|
|
119
|
+
/** Optional product scope (`"*"`, `"askverdict"`, etc.) for multi-product manifests */
|
|
120
|
+
product?: string;
|
|
121
|
+
/** Optional URL to link to (e.g. docs page, changelog entry) */
|
|
122
|
+
url?: string;
|
|
123
|
+
/** Optional feature flag key; requires a flag bridge to evaluate */
|
|
124
|
+
flagKey?: string;
|
|
125
|
+
/** Entry type — determines default icon/color in UI components */
|
|
126
|
+
type?: FeatureType;
|
|
127
|
+
/** Priority level — critical entries get special treatment in UI */
|
|
128
|
+
priority?: FeaturePriority;
|
|
129
|
+
/** Optional image/screenshot URL */
|
|
130
|
+
image?: string;
|
|
131
|
+
/** Optional call-to-action button */
|
|
132
|
+
cta?: FeatureCTA;
|
|
133
|
+
/** ISO date — entry is hidden until this date (scheduled publishing) */
|
|
134
|
+
publishAt?: string;
|
|
135
|
+
/** Optional arbitrary metadata */
|
|
136
|
+
meta?: Record<string, unknown>;
|
|
137
|
+
/** A/B variants keyed by variant name (e.g. control, treatment_a) */
|
|
138
|
+
variants?: Record<string, FeatureVariant>;
|
|
139
|
+
/** Percentage split per variant (same order as variants object keys) */
|
|
140
|
+
variantSplit?: number[];
|
|
141
|
+
/** Audience targeting — if set, only matching users see this feature */
|
|
142
|
+
audience?: AudienceRule;
|
|
143
|
+
/** Dependency requirements (progressive disclosure sequencing) */
|
|
144
|
+
dependsOn?: FeatureDependencies;
|
|
145
|
+
/** Contextual trigger rule */
|
|
146
|
+
trigger?: FeatureTrigger;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
interface ManifestEditorProps {
|
|
150
|
+
features: readonly FeatureEntry[];
|
|
151
|
+
onSave: (updated: FeatureEntry[]) => Promise<void> | void;
|
|
152
|
+
readOnly?: boolean;
|
|
153
|
+
children?: ReactNode;
|
|
154
|
+
}
|
|
155
|
+
declare function ManifestEditor({ features, onSave, readOnly, children, }: ManifestEditorProps): react_jsx_runtime.JSX.Element;
|
|
156
|
+
interface ScheduleCalendarProps {
|
|
157
|
+
features: readonly FeatureEntry[];
|
|
158
|
+
onSchedule: (featureId: string, publishAt: string) => Promise<void> | void;
|
|
159
|
+
}
|
|
160
|
+
declare function ScheduleCalendar({ features, onSchedule }: ScheduleCalendarProps): react_jsx_runtime.JSX.Element;
|
|
161
|
+
interface PreviewPanelProps {
|
|
162
|
+
feature?: FeatureEntry | null;
|
|
163
|
+
components?: Array<"badge" | "changelog" | "spotlight" | "banner" | "toast">;
|
|
164
|
+
}
|
|
165
|
+
declare function PreviewPanel({ feature, components }: PreviewPanelProps): react_jsx_runtime.JSX.Element;
|
|
166
|
+
interface AudienceBuilderProps {
|
|
167
|
+
segments?: string[];
|
|
168
|
+
roles?: string[];
|
|
169
|
+
regions?: string[];
|
|
170
|
+
value?: AudienceRule;
|
|
171
|
+
onChange?: (audience: AudienceRule) => void;
|
|
172
|
+
onSave?: (audience: AudienceRule) => Promise<void> | void;
|
|
173
|
+
}
|
|
174
|
+
declare function AudienceBuilder({ segments, roles, regions, value, onChange, onSave, }: AudienceBuilderProps): react_jsx_runtime.JSX.Element;
|
|
175
|
+
|
|
176
|
+
export { AudienceBuilder, type AudienceBuilderProps, ManifestEditor, type ManifestEditorProps, PreviewPanel, type PreviewPanelProps, ScheduleCalendar, type ScheduleCalendarProps };
|