@isi-ui7/corporate-themes 0.1.1 → 0.2.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 ADDED
@@ -0,0 +1,146 @@
1
+ # @isi-ui7/corporate-themes
2
+
3
+ Sistem tema korporat berbasis Carbon Design System — branding per institusi bank dengan token warna, logo, dan variant Carbon (white/g10/g90/g100).
4
+
5
+ ## Fitur
6
+
7
+ - `ThemeProvider`: inject tema korporat ke seluruh aplikasi
8
+ - `CorporateTheme`: apply CSS class tema ke subtree tertentu
9
+ - `GlobalCorporateTheme`: inject CSS variables global ke `<html>`
10
+ - `ThemeSwitcher`: komponen UI untuk ganti variant (white/g10/g90/g100)
11
+ - `useTheme()`: akses tema aktif dan variant dari komponen manapun
12
+ - `useThemeTokens()`: akses token warna aktif (brandColors, buttonPrimary, dll.)
13
+ - `useBrandColors()`, `useThemeVariant()`, `useCorporateFeatures()`: hooks spesifik
14
+ - Multiple tema tersedia: `bca-syariah`, `bni-syariah`, dst. (via `corporateThemes`)
15
+
16
+ ## Instalasi
17
+
18
+ ```bash
19
+ pnpm add @isi-ui7/corporate-themes react react-dom
20
+ ```
21
+
22
+ ## Penggunaan
23
+
24
+ ### Setup di app root
25
+
26
+ ```tsx
27
+ // app/layout.tsx
28
+ import { ThemeProvider } from "@isi-ui7/corporate-themes";
29
+
30
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
31
+ return (
32
+ <html>
33
+ <body>
34
+ <ThemeProvider corporateId="bca-syariah" variant="g90">
35
+ {children}
36
+ </ThemeProvider>
37
+ </body>
38
+ </html>
39
+ );
40
+ }
41
+ ```
42
+
43
+ ### Akses tema dari komponen
44
+
45
+ ```tsx
46
+ "use client";
47
+ import { useTheme, useThemeTokens } from "@isi-ui7/corporate-themes";
48
+
49
+ export function BrandedHeader() {
50
+ const { theme, variant } = useTheme();
51
+ const tokens = useThemeTokens();
52
+
53
+ return (
54
+ <header style={{ background: tokens.headerBackground }}>
55
+ <img src={tokens.logoUrl.light} alt={theme.displayName} />
56
+ <span>{theme.displayName} — {variant}</span>
57
+ </header>
58
+ );
59
+ }
60
+ ```
61
+
62
+ ### Ganti variant di runtime
63
+
64
+ ```tsx
65
+ "use client";
66
+ import { useTheme, ThemeSwitcher } from "@isi-ui7/corporate-themes";
67
+
68
+ export function Toolbar() {
69
+ const { variant, setVariant } = useTheme();
70
+ return <ThemeSwitcher current={variant} onChange={setVariant} />;
71
+ }
72
+ ```
73
+
74
+ ### Apply tema ke subtree saja
75
+
76
+ ```tsx
77
+ import { CorporateTheme } from "@isi-ui7/corporate-themes";
78
+
79
+ <CorporateTheme corporateId="bni-syariah" variant="white">
80
+ <SidebarContent />
81
+ </CorporateTheme>
82
+ ```
83
+
84
+ ## Props
85
+
86
+ ### `ThemeProvider`
87
+
88
+ | Nama | Tipe | Wajib | Deskripsi |
89
+ | --- | --- | --- | --- |
90
+ | `corporateId` | `string` | tidak | ID tema korporat (contoh: `"bca-syariah"`). Default: tema pertama |
91
+ | `variant` | `CarbonThemeVariant` | tidak | Variant Carbon awal. Default: tema `defaultVariant` |
92
+ | `children` | `ReactNode` | ya | Konten aplikasi |
93
+
94
+ ### `CorporateTheme`
95
+
96
+ | Nama | Tipe | Wajib | Deskripsi |
97
+ | --- | --- | --- | --- |
98
+ | `corporateId` | `string` | tidak | ID tema korporat untuk subtree ini |
99
+ | `variant` | `CarbonThemeVariant` | tidak | Variant untuk subtree ini |
100
+ | `children` | `ReactNode` | ya | Subtree yang di-themed |
101
+
102
+ ### `CarbonThemeVariant`
103
+
104
+ `"white" | "g10" | "g90" | "g100"`
105
+
106
+ ## `useTheme()` — returns `ThemeContextValue`
107
+
108
+ | Property | Tipe | Deskripsi |
109
+ | --- | --- | --- |
110
+ | `theme` | `CorporateTheme` | Data tema aktif (id, name, displayName, tokens, supportedVariants) |
111
+ | `variant` | `CarbonThemeVariant` | Variant Carbon aktif |
112
+ | `corporateId` | `string` | ID tema aktif |
113
+ | `setVariant` | `(v) => void` | Ganti variant di runtime |
114
+
115
+ ## `useThemeTokens()` — returns `ThemeTokens`
116
+
117
+ | Token | Tipe | Deskripsi |
118
+ | --- | --- | --- |
119
+ | `brandColors` | `BrandColors` | Palet warna merek (primary, secondary, accent, dll.) |
120
+ | `logoUrl` | `{ light, dark }` | URL logo untuk mode terang/gelap |
121
+ | `headerBackground` | `string` | Warna background header |
122
+ | `buttonPrimary` | `string` | Warna tombol primary |
123
+ | `linkPrimary` | `string` | Warna link primary |
124
+ | `focus` | `string` | Warna focus ring |
125
+ | ... | | Lihat `ThemeTokens` di `types.ts` |
126
+
127
+ ## A11y
128
+
129
+ - CSS variables diinjeksi ke level `<html>` atau subtree — kompatibel dengan Carbon focus management
130
+ - Contrast ratio mengikuti standar WCAG 2.1 AA (tanggungjawab konfigurasi token per tema)
131
+
132
+ ## Scripts
133
+
134
+ ```bash
135
+ pnpm build # Build ke dist/
136
+ pnpm lint # ESLint
137
+ pnpm test # Vitest
138
+ pnpm typecheck # TypeScript check
139
+ ```
140
+
141
+ ## Catatan
142
+
143
+ - Peer deps: React/ReactDOM `^18 || ^19`
144
+ - Tidak ada dependensi Carbon langsung — token diimplementasi sebagai CSS custom properties
145
+ - `ThemeProvider` menggunakan React Context — wrap di level layout tertinggi
146
+ - `corporateThemes` (dari `import { corporateThemes }`) adalah daftar semua tema yang tersedia
@@ -0,0 +1 @@
1
+ export declare function useDensity(): "compact" | "normal";
package/dist/index.d.ts CHANGED
@@ -8,3 +8,4 @@ export { useThemeTokens } from './hooks/useThemeTokens';
8
8
  export { useBrandColors } from './hooks/useBrandColors';
9
9
  export { useThemeVariant } from './hooks/useThemeVariant';
10
10
  export { useCorporateFeatures } from './hooks/useCorporateFeatures';
11
+ export { useDensity } from './hooks/useDensity';
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { jsx as i, jsxs as k } from "react/jsx-runtime";
2
- import { useMemo as b, useState as h, useEffect as g, createContext as f, useContext as A } from "react";
2
+ import { useMemo as h, useState as b, useEffect as g, createContext as f, useContext as A } from "react";
3
3
  const E = {
4
4
  brandColors: {
5
5
  primary: "#0F62FE",
@@ -166,11 +166,11 @@ const E = {
166
166
  headerBackground: "#0F62FE",
167
167
  sidebarBackground: "#1192E8",
168
168
  navigationBackground: "#F4F7FF"
169
- }, u = [
169
+ }, m = [
170
170
  {
171
171
  id: "carbon-default",
172
172
  name: "carbon-default",
173
- displayName: "Carbon Default",
173
+ displayName: "ISI",
174
174
  tokens: E,
175
175
  supportedVariants: ["white", "g10", "g90", "g100"],
176
176
  defaultVariant: "g10"
@@ -209,58 +209,58 @@ const E = {
209
209
  }
210
210
  ], F = f(null);
211
211
  function p(e) {
212
- const a = u.find((t) => t.id === "carbon-default") ?? u.find((t) => t.id === "ihsan") ?? u[0];
213
- return e ? u.find((t) => t.id === e) ?? a : a;
212
+ const t = m.find((a) => a.id === "carbon-default") ?? m.find((a) => a.id === "ihsan") ?? m[0];
213
+ return e ? m.find((a) => a.id === e) ?? t : t;
214
214
  }
215
- function S({ corporateId: e, variant: a, children: t }) {
216
- const r = b(() => p(e), [e]), [c, m] = h(
217
- a ?? r.defaultVariant
215
+ function S({ corporateId: e, variant: t, children: a }) {
216
+ const r = h(() => p(e), [e]), [d, v] = b(
217
+ t ?? r.defaultVariant
218
218
  );
219
219
  g(() => {
220
- a && r.supportedVariants.includes(a) && m(a);
221
- }, [a, r]), g(() => {
220
+ t && r.supportedVariants.includes(t) && v(t);
221
+ }, [t, r]), g(() => {
222
222
  if (typeof document > "u") return;
223
- const l = document.documentElement, o = document.body;
224
- u.flatMap(
223
+ const u = document.documentElement, o = document.body;
224
+ m.flatMap(
225
225
  (s) => s.supportedVariants.map((C) => `platform-theme-${s.id}-${C}`)
226
226
  ).forEach((s) => {
227
- l.classList.remove(s), o.classList.remove(s);
227
+ u.classList.remove(s), o.classList.remove(s);
228
228
  });
229
- const n = `platform-theme-${r.id}-${c}`;
230
- return l.classList.add(n), o.classList.add(n), () => {
231
- l.classList.remove(n), o.classList.remove(n);
229
+ const n = `platform-theme-${r.id}-${d}`;
230
+ return u.classList.add(n), o.classList.add(n), () => {
231
+ u.classList.remove(n), o.classList.remove(n);
232
232
  };
233
- }, [r, c]);
234
- const d = {
233
+ }, [r, d]);
234
+ const l = {
235
235
  theme: r,
236
- variant: c,
236
+ variant: d,
237
237
  corporateId: r.id,
238
- setVariant: m
238
+ setVariant: v
239
239
  };
240
- return /* @__PURE__ */ i(F.Provider, { value: d, children: t });
240
+ return /* @__PURE__ */ i(F.Provider, { value: l, children: a });
241
241
  }
242
- function v() {
242
+ function c() {
243
243
  const e = A(F);
244
244
  if (!e)
245
245
  throw new Error("useTheme must be used inside ThemeProvider");
246
246
  return e;
247
247
  }
248
- function V({ corporateId: e, variant: a, children: t }) {
249
- return /* @__PURE__ */ i(S, { corporateId: e, variant: a, children: t });
248
+ function V({ corporateId: e, variant: t, children: a }) {
249
+ return /* @__PURE__ */ i(S, { corporateId: e, variant: t, children: a });
250
250
  }
251
251
  function j({
252
252
  as: e,
253
- className: a,
254
- corporateId: t,
253
+ className: t,
254
+ corporateId: a,
255
255
  variant: r,
256
- children: c,
257
- ...m
256
+ children: d,
257
+ ...v
258
258
  }) {
259
- const d = v(), l = e ?? "div", o = b(
260
- () => t ? p(t) : d.theme,
261
- [t, d.theme]
262
- ), [y, n] = h(
263
- r ?? d.variant ?? o.defaultVariant
259
+ const l = c(), u = e ?? "div", o = h(
260
+ () => a ? p(a) : l.theme,
261
+ [a, l.theme]
262
+ ), [y, n] = b(
263
+ r ?? l.variant ?? o.defaultVariant
264
264
  );
265
265
  g(() => {
266
266
  r && o.supportedVariants.includes(r) ? n(r) : r || n(o.defaultVariant);
@@ -270,55 +270,60 @@ function j({
270
270
  variant: y,
271
271
  corporateId: o.id,
272
272
  setVariant: n
273
- }, C = [a, `platform-theme-${o.id}-${y}`].filter(Boolean).join(" ");
274
- return /* @__PURE__ */ i(F.Provider, { value: s, children: /* @__PURE__ */ i(l, { className: C, ...m, children: c }) });
273
+ }, C = [t, `platform-theme-${o.id}-${y}`].filter(Boolean).join(" ");
274
+ return /* @__PURE__ */ i(F.Provider, { value: s, children: /* @__PURE__ */ i(u, { className: C, ...v, children: d }) });
275
275
  }
276
- function N({ corporateId: e, variant: a, children: t }) {
277
- return /* @__PURE__ */ i(V, { corporateId: e, variant: a, children: t });
276
+ function N({ corporateId: e, variant: t, children: a }) {
277
+ return /* @__PURE__ */ i(V, { corporateId: e, variant: t, children: a });
278
278
  }
279
279
  const T = ["white", "g10", "g90", "g100"];
280
280
  function U() {
281
- const { variant: e, setVariant: a, theme: t } = v();
281
+ const { variant: e, setVariant: t, theme: a } = c();
282
282
  return /* @__PURE__ */ k("div", { style: { display: "inline-flex", gap: "0.5rem", alignItems: "center" }, children: [
283
- /* @__PURE__ */ i("span", { style: { fontSize: "0.85rem" }, children: t.displayName }),
283
+ /* @__PURE__ */ i("span", { style: { fontSize: "0.85rem" }, children: a.displayName }),
284
284
  /* @__PURE__ */ i(
285
285
  "select",
286
286
  {
287
287
  value: e,
288
- onChange: (r) => a(r.target.value),
288
+ onChange: (r) => t(r.target.value),
289
289
  children: T.map((r) => /* @__PURE__ */ i("option", { value: r, children: r.toUpperCase() }, r))
290
290
  }
291
291
  )
292
292
  ] });
293
293
  }
294
- function w() {
295
- const { theme: e } = v();
294
+ function I() {
295
+ const { theme: e } = c();
296
296
  return e.tokens;
297
297
  }
298
298
  function L() {
299
- return w().brandColors;
299
+ return I().brandColors;
300
300
  }
301
301
  function $() {
302
- const { variant: e, setVariant: a } = v();
303
- return { variant: e, setVariant: a };
302
+ const { variant: e, setVariant: t } = c();
303
+ return { variant: e, setVariant: t };
304
304
  }
305
305
  function M() {
306
- const { theme: e } = v();
306
+ const { theme: e } = c();
307
307
  return {
308
308
  logo: e.tokens.logoUrl,
309
309
  brandColors: e.tokens.brandColors
310
310
  };
311
311
  }
312
+ function z() {
313
+ const { theme: e } = c();
314
+ return e.tokens.density ?? "compact";
315
+ }
312
316
  export {
313
317
  j as CorporateTheme,
314
318
  N as GlobalCorporateTheme,
315
319
  S as ThemeContextProvider,
316
320
  V as ThemeProvider,
317
321
  U as ThemeSwitcher,
318
- u as corporateThemes,
322
+ m as corporateThemes,
319
323
  L as useBrandColors,
320
324
  M as useCorporateFeatures,
321
- v as useTheme,
322
- w as useThemeTokens,
325
+ z as useDensity,
326
+ c as useTheme,
327
+ I as useThemeTokens,
323
328
  $ as useThemeVariant
324
329
  };