@zoiq.io/dev-kit 0.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/dist/index.mjs ADDED
@@ -0,0 +1,362 @@
1
+ import { createContext, useState, useCallback, useEffect, useContext } from 'react';
2
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
+ import { clsx } from 'clsx';
4
+ import { twMerge } from 'tailwind-merge';
5
+
6
+ // src/context/ZOIQProvider.tsx
7
+
8
+ // src/api/client.ts
9
+ async function fetchProjectConfig(projectKey, apiBaseUrl) {
10
+ const base = apiBaseUrl ?? (typeof window !== "undefined" ? window.location.origin : "");
11
+ const url = `${base.replace(/\/$/, "")}/api/zoiq/project/${encodeURIComponent(projectKey)}`;
12
+ const res = await fetch(url);
13
+ if (!res.ok) {
14
+ throw new Error(`Failed to fetch project config: ${res.status} ${res.statusText}`);
15
+ }
16
+ const data = await res.json();
17
+ return data;
18
+ }
19
+ async function fetchSectionFlags(projectKey, apiBaseUrl) {
20
+ const base = apiBaseUrl ?? (typeof window !== "undefined" ? window.location.origin : "");
21
+ const url = `${base.replace(/\/$/, "")}/api/zoiq/project/${encodeURIComponent(projectKey)}/sections`;
22
+ const res = await fetch(url);
23
+ if (!res.ok) {
24
+ throw new Error(`Failed to fetch section flags: ${res.status} ${res.statusText}`);
25
+ }
26
+ return res.json();
27
+ }
28
+ async function fetchEntityData(projectKey, entity, options, apiBaseUrl) {
29
+ const base = apiBaseUrl ?? (typeof window !== "undefined" ? window.location.origin : "");
30
+ const params = new URLSearchParams();
31
+ if (options.id) params.set("id", options.id);
32
+ if (options.query) {
33
+ Object.entries(options.query).forEach(([k, v]) => params.set(k, v));
34
+ }
35
+ const qs = params.toString();
36
+ const url = `${base.replace(/\/$/, "")}/api/zoiq/project/${encodeURIComponent(projectKey)}/data/${encodeURIComponent(entity)}${qs ? `?${qs}` : ""}`;
37
+ const res = await fetch(url);
38
+ if (!res.ok) {
39
+ throw new Error(`Failed to fetch entity ${entity}: ${res.status} ${res.statusText}`);
40
+ }
41
+ const data = await res.json();
42
+ return data;
43
+ }
44
+
45
+ // src/theme/applyTheme.ts
46
+ var STYLE_GUIDE_TO_CSS_VAR = {
47
+ background: "--background",
48
+ foreground: "--foreground",
49
+ primary: "--primary",
50
+ secondary: "--secondary",
51
+ card: "--card",
52
+ cardForeground: "--card-foreground",
53
+ popover: "--popover",
54
+ popoverForeground: "--popover-foreground",
55
+ muted: "--muted",
56
+ mutedForeground: "--muted-foreground",
57
+ accent: "--accent",
58
+ accentForeground: "--accent-foreground",
59
+ destructive: "--destructive",
60
+ destructiveForeground: "--destructive-foreground",
61
+ border: "--border",
62
+ input: "--input",
63
+ ring: "--ring",
64
+ sidebar: "--sidebar",
65
+ sidebarForeground: "--sidebar-foreground",
66
+ sidebarPrimary: "--sidebar-primary",
67
+ sidebarPrimaryForeground: "--sidebar-primary-foreground",
68
+ sidebarAccent: "--sidebar-accent",
69
+ sidebarAccentForeground: "--sidebar-accent-foreground",
70
+ sidebarBorder: "--sidebar-border",
71
+ radius: "--radius"
72
+ };
73
+ function applyTheme(settings) {
74
+ if (typeof document === "undefined") return;
75
+ const root = document.documentElement;
76
+ if (settings.styleGuide && typeof settings.styleGuide === "object") {
77
+ for (const [key, value] of Object.entries(settings.styleGuide)) {
78
+ if (value == null || value === "") continue;
79
+ const cssVar = STYLE_GUIDE_TO_CSS_VAR[key] ?? `--${key}`;
80
+ root.style.setProperty(cssVar, value);
81
+ }
82
+ }
83
+ if (settings.definedColors?.length) {
84
+ for (const color of settings.definedColors) {
85
+ if (!color?.name || !color?.value) continue;
86
+ const varName = `--color-${color.name.replace(/\s+/g, "-").toLowerCase()}`;
87
+ root.style.setProperty(varName, color.value);
88
+ }
89
+ }
90
+ if (settings.clientDefinedColors?.length) {
91
+ for (const item of settings.clientDefinedColors) {
92
+ const value = item?.definedColor?.value;
93
+ const name = item?.name;
94
+ if (!name || !value) continue;
95
+ const varName = `--${name.replace(/\s+/g, "-").toLowerCase()}`;
96
+ root.style.setProperty(varName, value);
97
+ }
98
+ }
99
+ const branding = settings.branding;
100
+ if (branding?.primaryFont?.link || branding?.secondaryFont?.link || branding?.tertiaryFont?.link) {
101
+ const fontLinks = [];
102
+ if (branding.primaryFont?.link) fontLinks.push(`<link rel="stylesheet" href="${branding.primaryFont.link}" />`);
103
+ if (branding.secondaryFont?.link) fontLinks.push(`<link rel="stylesheet" href="${branding.secondaryFont.link}" />`);
104
+ if (branding.tertiaryFont?.link) fontLinks.push(`<link rel="stylesheet" href="${branding.tertiaryFont.link}" />`);
105
+ if (fontLinks.length > 0) {
106
+ const id = "zoiq-fonts";
107
+ let el = document.getElementById(id);
108
+ if (!el) {
109
+ el = document.createElement("div");
110
+ el.id = id;
111
+ el.innerHTML = fontLinks.join("");
112
+ document.head.append(...el.children);
113
+ el.remove();
114
+ }
115
+ }
116
+ }
117
+ }
118
+ var ZOIQContext = createContext(null);
119
+ function ZOIQProvider({
120
+ projectKey,
121
+ apiBaseUrl,
122
+ fetchProjectConfig: customFetch,
123
+ children
124
+ }) {
125
+ const [settings, setSettings] = useState(null);
126
+ const [loading, setLoading] = useState(true);
127
+ const [error, setError] = useState(null);
128
+ const fetchAndApply = useCallback(async () => {
129
+ if (!projectKey) {
130
+ setLoading(false);
131
+ return;
132
+ }
133
+ setLoading(true);
134
+ setError(null);
135
+ try {
136
+ const data = customFetch ? await customFetch(projectKey) : await fetchProjectConfig(projectKey, apiBaseUrl);
137
+ setSettings(data ?? null);
138
+ if (data) {
139
+ applyTheme(data);
140
+ }
141
+ } catch (err) {
142
+ setError(err instanceof Error ? err : new Error(String(err)));
143
+ setSettings(null);
144
+ } finally {
145
+ setLoading(false);
146
+ }
147
+ }, [projectKey, apiBaseUrl, customFetch]);
148
+ useEffect(() => {
149
+ fetchAndApply();
150
+ }, [fetchAndApply]);
151
+ const value = {
152
+ projectKey,
153
+ apiBaseUrl,
154
+ settings,
155
+ loading,
156
+ error,
157
+ refetch: fetchAndApply
158
+ };
159
+ return /* @__PURE__ */ jsx(ZOIQContext.Provider, { value, children });
160
+ }
161
+ function useZOIQContext() {
162
+ return useContext(ZOIQContext);
163
+ }
164
+
165
+ // src/hooks/useProjectSettings.ts
166
+ function useProjectSettings() {
167
+ const ctx = useZOIQContext();
168
+ if (!ctx) {
169
+ return {
170
+ data: null,
171
+ loading: false,
172
+ error: new Error("useProjectSettings must be used within ZOIQProvider"),
173
+ refetch: async () => {
174
+ }
175
+ };
176
+ }
177
+ return {
178
+ data: ctx.settings,
179
+ loading: ctx.loading,
180
+ error: ctx.error,
181
+ refetch: ctx.refetch
182
+ };
183
+ }
184
+ function useSectionFlags() {
185
+ const ctx = useZOIQContext();
186
+ const [enabledIds, setEnabledIds] = useState(/* @__PURE__ */ new Set());
187
+ const [disabledIds, setDisabledIds] = useState(/* @__PURE__ */ new Set());
188
+ const [loading, setLoading] = useState(true);
189
+ const [error, setError] = useState(null);
190
+ const fetch2 = useCallback(async () => {
191
+ if (!ctx?.projectKey) {
192
+ setLoading(false);
193
+ return;
194
+ }
195
+ setLoading(true);
196
+ setError(null);
197
+ try {
198
+ const data = await fetchSectionFlags(ctx.projectKey, ctx.apiBaseUrl);
199
+ setEnabledIds(new Set(data.enabledIds ?? []));
200
+ setDisabledIds(new Set(data.disabledIds ?? []));
201
+ } catch (err) {
202
+ setError(err instanceof Error ? err : new Error(String(err)));
203
+ setEnabledIds(/* @__PURE__ */ new Set());
204
+ setDisabledIds(/* @__PURE__ */ new Set());
205
+ } finally {
206
+ setLoading(false);
207
+ }
208
+ }, [ctx?.projectKey, ctx?.apiBaseUrl]);
209
+ useEffect(() => {
210
+ fetch2();
211
+ }, [fetch2]);
212
+ if (!ctx) {
213
+ return {
214
+ enabledIds: /* @__PURE__ */ new Set(),
215
+ disabledIds: /* @__PURE__ */ new Set(),
216
+ loading: false,
217
+ error: new Error("useSectionFlags must be used within ZOIQProvider"),
218
+ refetch: async () => {
219
+ }
220
+ };
221
+ }
222
+ return { enabledIds, disabledIds, loading, error, refetch: fetch2 };
223
+ }
224
+ function useZOIQApi(entity, options = {}) {
225
+ const ctx = useZOIQContext();
226
+ const [data, setData] = useState(null);
227
+ const [loading, setLoading] = useState(true);
228
+ const [error, setError] = useState(null);
229
+ const fetch2 = useCallback(async () => {
230
+ if (!ctx?.projectKey) {
231
+ setLoading(false);
232
+ return;
233
+ }
234
+ setLoading(true);
235
+ setError(null);
236
+ try {
237
+ const result = await fetchEntityData(
238
+ ctx.projectKey,
239
+ entity,
240
+ { id: options.id, query: options.query },
241
+ ctx.apiBaseUrl
242
+ );
243
+ setData(result);
244
+ } catch (err) {
245
+ setError(err instanceof Error ? err : new Error(String(err)));
246
+ setData(null);
247
+ } finally {
248
+ setLoading(false);
249
+ }
250
+ }, [ctx?.projectKey, entity, options.id, JSON.stringify(options.query)]);
251
+ useEffect(() => {
252
+ fetch2();
253
+ }, [fetch2]);
254
+ if (!ctx) {
255
+ return {
256
+ data: null,
257
+ loading: false,
258
+ error: new Error("useZOIQApi must be used within ZOIQProvider"),
259
+ refetch: async () => {
260
+ }
261
+ };
262
+ }
263
+ return { data, loading, error, refetch: fetch2 };
264
+ }
265
+ function cn(...inputs) {
266
+ return twMerge(clsx(inputs));
267
+ }
268
+ var Text = ({
269
+ children,
270
+ className,
271
+ as: As = "span",
272
+ ...props
273
+ }) => {
274
+ return /* @__PURE__ */ jsx(As, { className: cn("text-[var(--text-primary,#111)]", className), ...props, children });
275
+ };
276
+ var Title = ({ children, className }) => {
277
+ return /* @__PURE__ */ jsx(
278
+ "h1",
279
+ {
280
+ className: cn(
281
+ "text-2xl md:text-3xl mb-0 font-semibold text-pretty text-[var(--text-primary,#111)]",
282
+ className
283
+ ),
284
+ children
285
+ }
286
+ );
287
+ };
288
+ var Subtitle = ({ children, className }) => {
289
+ return /* @__PURE__ */ jsx(Text, { as: "div", className: cn("text-sm md:text-base text-[var(--text-secondary,#666)]", className), children });
290
+ };
291
+ var ScrollButton = ({ className, threshold = 200 }) => {
292
+ const [isVisible, setIsVisible] = useState(false);
293
+ useEffect(() => {
294
+ const onScroll = () => setIsVisible(typeof window !== "undefined" ? window.scrollY > threshold : false);
295
+ window.addEventListener("scroll", onScroll, { passive: true });
296
+ onScroll();
297
+ return () => window.removeEventListener("scroll", onScroll);
298
+ }, [threshold]);
299
+ return /* @__PURE__ */ jsx("div", { className: cn("fixed bottom-10 right-10 z-50 hidden md:block", className), children: /* @__PURE__ */ jsx(
300
+ "button",
301
+ {
302
+ type: "button",
303
+ className: cn(
304
+ "rounded-full p-2 cursor-pointer shadow-lg transition-all duration-300",
305
+ "bg-[var(--primary,hsl(220,70%,50%))] text-[var(--primary-foreground,#fff)]",
306
+ isVisible ? "opacity-100" : "opacity-0 pointer-events-none"
307
+ ),
308
+ onClick: () => window.scrollTo({ top: 0, behavior: "smooth" }),
309
+ "aria-label": "Scroll to top",
310
+ children: /* @__PURE__ */ jsx("span", { className: "inline-block w-6 h-6", "aria-hidden": true, children: "\u2191" })
311
+ }
312
+ ) });
313
+ };
314
+ var ToggleTheme = ({ className, onToggle, theme, children }) => {
315
+ return /* @__PURE__ */ jsx("button", { type: "button", onClick: onToggle, className: cn(className), "aria-label": `Toggle theme (current: ${theme ?? "unknown"})`, children: children ?? "Theme" });
316
+ };
317
+ var Section = ({ children, className }) => {
318
+ return /* @__PURE__ */ jsx("section", { className: cn("max-w-7xl mx-auto w-full px-8 md:px-0 pt-12 md:pt-24 pb-12 md:pb-24", className), children });
319
+ };
320
+
321
+ // src/components/molecules/ToastContainer.tsx
322
+ var ToastContainer = () => {
323
+ return null;
324
+ };
325
+ var Page = ({ children, className, fullWidth }) => {
326
+ return /* @__PURE__ */ jsx("div", { className: cn("w-full flex-1 flex flex-col min-h-screen", className), children: /* @__PURE__ */ jsx("main", { className: cn("w-full flex-1 flex flex-col", fullWidth ? "px-0" : "px-4 md:px-8"), children }) });
327
+ };
328
+ var Header = ({ children, className, left, right }) => {
329
+ return /* @__PURE__ */ jsx(
330
+ "header",
331
+ {
332
+ className: cn(
333
+ "w-full h-14 sticky top-0 z-50 border-b border-[var(--border,transparent)]",
334
+ "bg-[var(--sidebar,var(--background))]",
335
+ className
336
+ ),
337
+ children: /* @__PURE__ */ jsxs("nav", { className: "flex h-full w-full items-center justify-between gap-4 px-4 md:px-6", "aria-label": "Main", children: [
338
+ left != null ? /* @__PURE__ */ jsx("div", { className: "flex items-center gap-3", children: left }) : null,
339
+ children,
340
+ right != null ? /* @__PURE__ */ jsx("div", { className: "flex items-center gap-3", children: right }) : null
341
+ ] })
342
+ }
343
+ );
344
+ };
345
+ var Footer = ({ children, className }) => {
346
+ return /* @__PURE__ */ jsx("footer", { className: cn("w-full border-t border-[var(--border,transparent)] py-6 px-4 md:px-8", className), children });
347
+ };
348
+ var SecondarySidebar = ({ items, className, isActive, renderLink }) => {
349
+ return /* @__PURE__ */ jsx("div", { className: cn("px-4", className), children: /* @__PURE__ */ jsx("ul", { className: "flex p-1 rounded-lg bg-[var(--accent,#f4f4f5)] border border-[var(--border,#e4e4e7)] w-full justify-between gap-4", children: items.map((item) => {
350
+ const active = isActive?.(item) ?? false;
351
+ const content = /* @__PURE__ */ jsxs(Fragment, { children: [
352
+ item.icon,
353
+ /* @__PURE__ */ jsx("span", { children: item.label })
354
+ ] });
355
+ const child = renderLink ? renderLink(item, content) : /* @__PURE__ */ jsx("a", { href: item.href, className: cn("flex items-center justify-center gap-2 text-center h-8 w-full rounded-md text-sm font-medium transition-colors", active ? "bg-[var(--sidebar-accent,var(--accent))] text-[var(--foreground)]" : "text-[var(--muted-foreground,#71717a)]"), children: content });
356
+ return /* @__PURE__ */ jsx("li", { className: "w-full", children: child }, item.href);
357
+ }) }) });
358
+ };
359
+
360
+ export { Footer, Header, Page, ScrollButton, SecondarySidebar, Section, Subtitle, Text, Title, ToastContainer, ToggleTheme, ZOIQProvider, useProjectSettings, useSectionFlags, useZOIQApi, useZOIQContext };
361
+ //# sourceMappingURL=index.mjs.map
362
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/api/client.ts","../src/theme/applyTheme.ts","../src/context/ZOIQProvider.tsx","../src/hooks/useProjectSettings.ts","../src/hooks/useSectionFlags.ts","../src/hooks/useZOIQApi.ts","../src/utils/cn.ts","../src/components/atoms/Text.tsx","../src/components/atoms/Title.tsx","../src/components/atoms/Subtitle.tsx","../src/components/atoms/ScrollButton.tsx","../src/components/atoms/ToggleTheme.tsx","../src/components/molecules/Section.tsx","../src/components/molecules/ToastContainer.tsx","../src/components/layout/Page.tsx","../src/components/layout/Header.tsx","../src/components/layout/Footer.tsx","../src/components/layout/SecondarySidebar.tsx"],"names":["useState","fetch","useCallback","useEffect","jsx","jsxs"],"mappings":"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","file":"index.mjs","sourcesContent":["import type { ProjectSettings } from '../context/types'\n\n/**\n * Default fetch for project config. Calls GET {apiBaseUrl}/project/{projectKey}\n * and expects JSON matching ProjectSettings.\n */\nexport async function fetchProjectConfig(\n projectKey: string,\n apiBaseUrl?: string\n): Promise<ProjectSettings | null> {\n const base = apiBaseUrl ?? (typeof window !== 'undefined' ? window.location.origin : '')\n const url = `${base.replace(/\\/$/, '')}/api/zoiq/project/${encodeURIComponent(projectKey)}`\n const res = await fetch(url)\n if (!res.ok) {\n throw new Error(`Failed to fetch project config: ${res.status} ${res.statusText}`)\n }\n const data = (await res.json()) as ProjectSettings\n return data\n}\n\n/**\n * Fetch section flags for the project. Calls GET {apiBaseUrl}/project/{projectKey}/sections\n */\nexport async function fetchSectionFlags(\n projectKey: string,\n apiBaseUrl?: string\n): Promise<{ enabledIds: string[]; disabledIds: string[] }> {\n const base = apiBaseUrl ?? (typeof window !== 'undefined' ? window.location.origin : '')\n const url = `${base.replace(/\\/$/, '')}/api/zoiq/project/${encodeURIComponent(projectKey)}/sections`\n const res = await fetch(url)\n if (!res.ok) {\n throw new Error(`Failed to fetch section flags: ${res.status} ${res.statusText}`)\n }\n return res.json() as Promise<{ enabledIds: string[]; disabledIds: string[] }>\n}\n\n/**\n * Fetch entity data for the project. Calls GET {apiBaseUrl}/project/{projectKey}/data/{entity}?id=...\n */\nexport async function fetchEntityData<T>(\n projectKey: string,\n entity: string,\n options: { id?: string; query?: Record<string, string> },\n apiBaseUrl?: string\n): Promise<T | null> {\n const base = apiBaseUrl ?? (typeof window !== 'undefined' ? window.location.origin : '')\n const params = new URLSearchParams()\n if (options.id) params.set('id', options.id)\n if (options.query) {\n Object.entries(options.query).forEach(([k, v]) => params.set(k, v))\n }\n const qs = params.toString()\n const url = `${base.replace(/\\/$/, '')}/api/zoiq/project/${encodeURIComponent(projectKey)}/data/${encodeURIComponent(entity)}${qs ? `?${qs}` : ''}`\n const res = await fetch(url)\n if (!res.ok) {\n throw new Error(`Failed to fetch entity ${entity}: ${res.status} ${res.statusText}`)\n }\n const data = (await res.json()) as T\n return data\n}\n","import type { ProjectSettings } from '../context/types'\n\n/**\n * Maps styleGuide keys to CSS variable names (e.g. for :root or a wrapper).\n * Aligns with portal globals.css tokens.\n */\nconst STYLE_GUIDE_TO_CSS_VAR: Record<string, string> = {\n background: '--background',\n foreground: '--foreground',\n primary: '--primary',\n secondary: '--secondary',\n card: '--card',\n cardForeground: '--card-foreground',\n popover: '--popover',\n popoverForeground: '--popover-foreground',\n muted: '--muted',\n mutedForeground: '--muted-foreground',\n accent: '--accent',\n accentForeground: '--accent-foreground',\n destructive: '--destructive',\n destructiveForeground: '--destructive-foreground',\n border: '--border',\n input: '--input',\n ring: '--ring',\n sidebar: '--sidebar',\n sidebarForeground: '--sidebar-foreground',\n sidebarPrimary: '--sidebar-primary',\n sidebarPrimaryForeground: '--sidebar-primary-foreground',\n sidebarAccent: '--sidebar-accent',\n sidebarAccentForeground: '--sidebar-accent-foreground',\n sidebarBorder: '--sidebar-border',\n radius: '--radius',\n}\n\n/**\n * Injects theme from ProjectSettings into document: CSS variables and optional font links.\n */\nexport function applyTheme(settings: ProjectSettings): void {\n if (typeof document === 'undefined') return\n\n const root = document.documentElement\n\n if (settings.styleGuide && typeof settings.styleGuide === 'object') {\n for (const [key, value] of Object.entries(settings.styleGuide)) {\n if (value == null || value === '') continue\n const cssVar = STYLE_GUIDE_TO_CSS_VAR[key] ?? `--${key}`\n root.style.setProperty(cssVar, value)\n }\n }\n\n if (settings.definedColors?.length) {\n for (const color of settings.definedColors) {\n if (!color?.name || !color?.value) continue\n const varName = `--color-${color.name.replace(/\\s+/g, '-').toLowerCase()}`\n root.style.setProperty(varName, color.value)\n }\n }\n\n if (settings.clientDefinedColors?.length) {\n for (const item of settings.clientDefinedColors) {\n const value = item?.definedColor?.value\n const name = item?.name\n if (!name || !value) continue\n const varName = `--${name.replace(/\\s+/g, '-').toLowerCase()}`\n root.style.setProperty(varName, value)\n }\n }\n\n const branding = settings.branding\n if (branding?.primaryFont?.link || branding?.secondaryFont?.link || branding?.tertiaryFont?.link) {\n const fontLinks: string[] = []\n if (branding.primaryFont?.link) fontLinks.push(`<link rel=\"stylesheet\" href=\"${branding.primaryFont.link}\" />`)\n if (branding.secondaryFont?.link) fontLinks.push(`<link rel=\"stylesheet\" href=\"${branding.secondaryFont.link}\" />`)\n if (branding.tertiaryFont?.link) fontLinks.push(`<link rel=\"stylesheet\" href=\"${branding.tertiaryFont.link}\" />`)\n if (fontLinks.length > 0) {\n const id = 'zoiq-fonts'\n let el = document.getElementById(id)\n if (!el) {\n el = document.createElement('div')\n el.id = id\n el.innerHTML = fontLinks.join('')\n document.head.append(...el.children)\n el.remove()\n }\n }\n }\n}\n","'use client'\n\nimport React, { createContext, useCallback, useContext, useEffect, useState } from 'react'\nimport type { ProjectSettings } from './types'\nimport { fetchProjectConfig } from '../api/client'\nimport { applyTheme } from '../theme/applyTheme'\n\nexport interface ZOIQProviderProps {\n /** Project key (e.g. project ID or public API key) to fetch theme and config */\n projectKey: string\n /** Base URL for the project config API (e.g. https://your-portal.com/api/zoiq) */\n apiBaseUrl?: string\n /** Optional custom fetcher; if provided, apiBaseUrl is ignored for config fetch */\n fetchProjectConfig?: (key: string) => Promise<ProjectSettings | null>\n children: React.ReactNode\n}\n\ninterface ZOIQContextValue {\n projectKey: string\n apiBaseUrl?: string\n settings: ProjectSettings | null\n loading: boolean\n error: Error | null\n refetch: () => Promise<void>\n}\n\nconst ZOIQContext = createContext<ZOIQContextValue | null>(null)\n\nexport function ZOIQProvider({\n projectKey,\n apiBaseUrl,\n fetchProjectConfig: customFetch,\n children,\n}: ZOIQProviderProps) {\n const [settings, setSettings] = useState<ProjectSettings | null>(null)\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState<Error | null>(null)\n\n const fetchAndApply = useCallback(async () => {\n if (!projectKey) {\n setLoading(false)\n return\n }\n setLoading(true)\n setError(null)\n try {\n const data = customFetch\n ? await customFetch(projectKey)\n : await fetchProjectConfig(projectKey, apiBaseUrl)\n setSettings(data ?? null)\n if (data) {\n applyTheme(data)\n }\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)))\n setSettings(null)\n } finally {\n setLoading(false)\n }\n }, [projectKey, apiBaseUrl, customFetch])\n\n useEffect(() => {\n fetchAndApply()\n }, [fetchAndApply])\n\n const value: ZOIQContextValue = {\n projectKey,\n apiBaseUrl,\n settings,\n loading,\n error,\n refetch: fetchAndApply,\n }\n\n return <ZOIQContext.Provider value={value}>{children}</ZOIQContext.Provider>\n}\n\nexport function useZOIQContext(): ZOIQContextValue | null {\n return useContext(ZOIQContext)\n}\n","'use client'\n\nimport { useZOIQContext } from '../context/ZOIQProvider'\n\nexport interface UseProjectSettingsResult {\n data: import('../context/types').ProjectSettings | null\n loading: boolean\n error: Error | null\n refetch: () => Promise<void>\n}\n\n/**\n * Returns the full project theme/settings for the current project key.\n * Must be used within ZOIQProvider. Data is the same that the provider used to apply theme.\n */\nexport function useProjectSettings(): UseProjectSettingsResult {\n const ctx = useZOIQContext()\n if (!ctx) {\n return {\n data: null,\n loading: false,\n error: new Error('useProjectSettings must be used within ZOIQProvider'),\n refetch: async () => {},\n }\n }\n return {\n data: ctx.settings,\n loading: ctx.loading,\n error: ctx.error,\n refetch: ctx.refetch,\n }\n}\n","'use client'\n\nimport { useCallback, useContext, useEffect, useState } from 'react'\nimport { useZOIQContext } from '../context/ZOIQProvider'\nimport { fetchSectionFlags } from '../api/client'\n\nexport interface UseSectionFlagsResult {\n enabledIds: Set<string>\n disabledIds: Set<string>\n loading: boolean\n error: Error | null\n refetch: () => Promise<void>\n}\n\n/**\n * Returns which section IDs are enabled or disabled for the current project.\n * Must be used within ZOIQProvider. Uses the same apiBaseUrl as the provider.\n */\nexport function useSectionFlags(): UseSectionFlagsResult {\n const ctx = useZOIQContext()\n const [enabledIds, setEnabledIds] = useState<Set<string>>(new Set())\n const [disabledIds, setDisabledIds] = useState<Set<string>>(new Set())\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState<Error | null>(null)\n\n const fetch = useCallback(async () => {\n if (!ctx?.projectKey) {\n setLoading(false)\n return\n }\n setLoading(true)\n setError(null)\n try {\n const data = await fetchSectionFlags(ctx.projectKey, ctx.apiBaseUrl)\n setEnabledIds(new Set(data.enabledIds ?? []))\n setDisabledIds(new Set(data.disabledIds ?? []))\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)))\n setEnabledIds(new Set())\n setDisabledIds(new Set())\n } finally {\n setLoading(false)\n }\n }, [ctx?.projectKey, ctx?.apiBaseUrl])\n\n useEffect(() => {\n fetch()\n }, [fetch])\n\n if (!ctx) {\n return {\n enabledIds: new Set(),\n disabledIds: new Set(),\n loading: false,\n error: new Error('useSectionFlags must be used within ZOIQProvider'),\n refetch: async () => {},\n }\n }\n\n return { enabledIds, disabledIds, loading, error, refetch: fetch }\n}\n","'use client'\n\nimport { useCallback, useContext, useEffect, useState } from 'react'\nimport { useZOIQContext } from '../context/ZOIQProvider'\nimport { fetchEntityData } from '../api/client'\n\nexport interface UseZOIQApiOptions {\n id?: string\n query?: Record<string, string>\n}\n\nexport interface UseZOIQApiResult<T> {\n data: T | null\n loading: boolean\n error: Error | null\n refetch: () => Promise<void>\n}\n\n/**\n * Fetches custom entity data for the current project.\n * Must be used within ZOIQProvider.\n */\nexport function useZOIQApi<T = unknown>(\n entity: string,\n options: UseZOIQApiOptions = {}\n): UseZOIQApiResult<T> {\n const ctx = useZOIQContext()\n const [data, setData] = useState<T | null>(null)\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState<Error | null>(null)\n\n const fetch = useCallback(async () => {\n if (!ctx?.projectKey) {\n setLoading(false)\n return\n }\n setLoading(true)\n setError(null)\n try {\n const result = await fetchEntityData<T>(\n ctx.projectKey,\n entity,\n { id: options.id, query: options.query },\n ctx.apiBaseUrl\n )\n setData(result)\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)))\n setData(null)\n } finally {\n setLoading(false)\n }\n }, [ctx?.projectKey, entity, options.id, JSON.stringify(options.query)])\n\n useEffect(() => {\n fetch()\n }, [fetch])\n\n if (!ctx) {\n return {\n data: null,\n loading: false,\n error: new Error('useZOIQApi must be used within ZOIQProvider'),\n refetch: async () => {},\n }\n }\n\n return { data, loading, error, refetch: fetch }\n}\n","import { type ClassValue, clsx } from 'clsx'\nimport { twMerge } from 'tailwind-merge'\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n","'use client'\n\nimport React from 'react'\nimport { cn } from '../../utils/cn'\n\nexport interface TextProps extends React.HTMLAttributes<HTMLElement> {\n children?: React.ReactNode\n className?: string\n as?: 'span' | 'p' | 'div'\n}\n\nexport const Text = ({\n children,\n className,\n as: As = 'span',\n ...props\n}: TextProps) => {\n return (\n <As className={cn('text-[var(--text-primary,#111)]', className)} {...props}>\n {children}\n </As>\n )\n}\n\nexport default Text\n","'use client'\n\nimport React from 'react'\nimport { cn } from '../../utils/cn'\n\nexport interface TitleProps {\n children?: React.ReactNode\n className?: string\n}\n\nexport const Title = ({ children, className }: TitleProps) => {\n return (\n <h1\n className={cn(\n 'text-2xl md:text-3xl mb-0 font-semibold text-pretty text-[var(--text-primary,#111)]',\n className\n )}\n >\n {children}\n </h1>\n )\n}\n\nexport default Title\n","'use client'\n\nimport React from 'react'\nimport { Text } from './Text'\nimport { cn } from '../../utils/cn'\n\nexport interface SubtitleProps {\n children?: React.ReactNode\n className?: string\n}\n\nexport const Subtitle = ({ children, className }: SubtitleProps) => {\n return (\n <Text as=\"div\" className={cn('text-sm md:text-base text-[var(--text-secondary,#666)]', className)}>\n {children}\n </Text>\n )\n}\n\nexport default Subtitle\n","'use client'\n\nimport React, { useState, useEffect } from 'react'\nimport { cn } from '../../utils/cn'\n\nexport interface ScrollButtonProps {\n className?: string\n /** Scroll Y threshold above which the button is shown (default 200) */\n threshold?: number\n}\n\nexport const ScrollButton = ({ className, threshold = 200 }: ScrollButtonProps) => {\n const [isVisible, setIsVisible] = useState(false)\n\n useEffect(() => {\n const onScroll = () => setIsVisible(typeof window !== 'undefined' ? window.scrollY > threshold : false)\n window.addEventListener('scroll', onScroll, { passive: true })\n onScroll()\n return () => window.removeEventListener('scroll', onScroll)\n }, [threshold])\n\n return (\n <div className={cn('fixed bottom-10 right-10 z-50 hidden md:block', className)}>\n <button\n type=\"button\"\n className={cn(\n 'rounded-full p-2 cursor-pointer shadow-lg transition-all duration-300',\n 'bg-[var(--primary,hsl(220,70%,50%))] text-[var(--primary-foreground,#fff)]',\n isVisible ? 'opacity-100' : 'opacity-0 pointer-events-none'\n )}\n onClick={() => window.scrollTo({ top: 0, behavior: 'smooth' })}\n aria-label=\"Scroll to top\"\n >\n <span className=\"inline-block w-6 h-6\" aria-hidden>\n ↑\n </span>\n </button>\n </div>\n )\n}\n\nexport default ScrollButton\n","'use client'\n\nimport React from 'react'\nimport { cn } from '../../utils/cn'\n\nexport interface ToggleThemeProps {\n className?: string\n /** Callback when user requests theme toggle; host app controls actual theme state */\n onToggle?: () => void\n /** Optional current theme name for rendering (e.g. \"light\" | \"dark\") */\n theme?: string\n /** Content to show (e.g. icon). If not provided, shows \"Theme\" */\n children?: React.ReactNode\n}\n\nexport const ToggleTheme = ({ className, onToggle, theme, children }: ToggleThemeProps) => {\n return (\n <button type=\"button\" onClick={onToggle} className={cn(className)} aria-label={`Toggle theme (current: ${theme ?? 'unknown'})`}>\n {children ?? 'Theme'}\n </button>\n )\n}\n\nexport default ToggleTheme\n","'use client'\n\nimport React from 'react'\nimport { cn } from '../../utils/cn'\n\nexport interface SectionProps {\n children?: React.ReactNode\n className?: string\n}\n\nexport const Section = ({ children, className }: SectionProps) => {\n return (\n <section className={cn('max-w-7xl mx-auto w-full px-8 md:px-0 pt-12 md:pt-24 pb-12 md:pb-24', className)}>\n {children}\n </section>\n )\n}\n\nexport default Section\n","'use client'\n\nimport React from 'react'\n\n/**\n * Placeholder for toast container. Host app should render Toaster from \"sonner\" (or similar)\n * inside the app; ZOIQ does not bundle a toast library.\n */\nexport const ToastContainer = () => {\n return null\n}\n\nexport default ToastContainer\n","'use client'\n\nimport React from 'react'\nimport { cn } from '../../utils/cn'\n\nexport interface PageProps {\n children?: React.ReactNode\n className?: string\n /** Optional full-width layout (no horizontal padding) */\n fullWidth?: boolean\n}\n\nexport const Page = ({ children, className, fullWidth }: PageProps) => {\n return (\n <div className={cn('w-full flex-1 flex flex-col min-h-screen', className)}>\n <main className={cn('w-full flex-1 flex flex-col', fullWidth ? 'px-0' : 'px-4 md:px-8')}>\n {children}\n </main>\n </div>\n )\n}\n\nexport default Page\n","'use client'\n\nimport React from 'react'\nimport { cn } from '../../utils/cn'\n\nexport interface HeaderProps {\n children?: React.ReactNode\n className?: string\n /** Optional left slot (e.g. logo, nav) */\n left?: React.ReactNode\n /** Optional right slot (e.g. user menu, theme toggle) */\n right?: React.ReactNode\n}\n\nexport const Header = ({ children, className, left, right }: HeaderProps) => {\n return (\n <header\n className={cn(\n 'w-full h-14 sticky top-0 z-50 border-b border-[var(--border,transparent)]',\n 'bg-[var(--sidebar,var(--background))]',\n className\n )}\n >\n <nav className=\"flex h-full w-full items-center justify-between gap-4 px-4 md:px-6\" aria-label=\"Main\">\n {left != null ? <div className=\"flex items-center gap-3\">{left}</div> : null}\n {children}\n {right != null ? <div className=\"flex items-center gap-3\">{right}</div> : null}\n </nav>\n </header>\n )\n}\n\nexport default Header\n","'use client'\n\nimport React from 'react'\nimport { cn } from '../../utils/cn'\n\nexport interface FooterProps {\n children?: React.ReactNode\n className?: string\n}\n\nexport const Footer = ({ children, className }: FooterProps) => {\n return (\n <footer className={cn('w-full border-t border-[var(--border,transparent)] py-6 px-4 md:px-8', className)}>\n {children}\n </footer>\n )\n}\n\nexport default Footer\n","'use client'\n\nimport React from 'react'\nimport { cn } from '../../utils/cn'\n\nexport interface SecondarySidebarItem {\n label: string\n href: string\n icon?: React.ReactNode\n}\n\nexport interface SecondarySidebarProps {\n items: SecondarySidebarItem[]\n className?: string\n /** Optional: return true if item is active (e.g. from pathname) */\n isActive?: (item: SecondarySidebarItem) => boolean\n /** Optional: custom link renderer (e.g. Next.js Link). Default: <a> */\n renderLink?: (item: SecondarySidebarItem, children: React.ReactNode) => React.ReactNode\n}\n\nexport const SecondarySidebar = ({ items, className, isActive, renderLink }: SecondarySidebarProps) => {\n return (\n <div className={cn('px-4', className)}>\n <ul className=\"flex p-1 rounded-lg bg-[var(--accent,#f4f4f5)] border border-[var(--border,#e4e4e7)] w-full justify-between gap-4\">\n {items.map((item) => {\n const active = isActive?.(item) ?? false\n const content = (\n <>\n {item.icon}\n <span>{item.label}</span>\n </>\n )\n const child = renderLink ? (\n renderLink(item, content)\n ) : (\n <a href={item.href} className={cn('flex items-center justify-center gap-2 text-center h-8 w-full rounded-md text-sm font-medium transition-colors', active ? 'bg-[var(--sidebar-accent,var(--accent))] text-[var(--foreground)]' : 'text-[var(--muted-foreground,#71717a)]')}>\n {content}\n </a>\n )\n return (\n <li key={item.href} className=\"w-full\">\n {child}\n </li>\n )\n })}\n </ul>\n </div>\n )\n}\n\nexport default SecondarySidebar\n"]}
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@zoiq.io/dev-kit",
3
+ "version": "0.1.0",
4
+ "private": false,
5
+ "description": "ZOIQ - React component library and framework with project-key-driven theme, hooks, and UI primitives",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.mjs",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.mjs",
13
+ "require": "./dist/index.js"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "README.md"
19
+ ],
20
+ "scripts": {
21
+ "build": "tsup",
22
+ "dev": "tsup --watch"
23
+ },
24
+ "peerDependencies": {
25
+ "react": ">=18.0.0",
26
+ "react-dom": ">=18.0.0"
27
+ },
28
+ "dependencies": {
29
+ "clsx": "^2.1.1",
30
+ "tailwind-merge": "^3.2.0"
31
+ },
32
+ "devDependencies": {
33
+ "@types/react": "^19.0.0",
34
+ "@types/react-dom": "^19.0.0",
35
+ "react": "^19.0.0",
36
+ "react-dom": "^19.0.0",
37
+ "tsup": "^8.3.5",
38
+ "typescript": "^5.0.0"
39
+ },
40
+ "publishConfig": {
41
+ "access": "public"
42
+ },
43
+ "keywords": [
44
+ "react",
45
+ "component-library",
46
+ "theme",
47
+ "zoiq"
48
+ ]
49
+ }