@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 +146 -0
- package/dist/hooks/useDensity.d.ts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +54 -49
- package/dist/style.css +1 -1
- package/dist/types.d.ts +2 -0
- package/package.json +2 -2
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
|
|
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
|
-
},
|
|
169
|
+
}, m = [
|
|
170
170
|
{
|
|
171
171
|
id: "carbon-default",
|
|
172
172
|
name: "carbon-default",
|
|
173
|
-
displayName: "
|
|
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
|
|
213
|
-
return e ?
|
|
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:
|
|
216
|
-
const r =
|
|
217
|
-
|
|
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
|
-
|
|
221
|
-
}, [
|
|
220
|
+
t && r.supportedVariants.includes(t) && v(t);
|
|
221
|
+
}, [t, r]), g(() => {
|
|
222
222
|
if (typeof document > "u") return;
|
|
223
|
-
const
|
|
224
|
-
|
|
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
|
-
|
|
227
|
+
u.classList.remove(s), o.classList.remove(s);
|
|
228
228
|
});
|
|
229
|
-
const n = `platform-theme-${r.id}-${
|
|
230
|
-
return
|
|
231
|
-
|
|
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,
|
|
234
|
-
const
|
|
233
|
+
}, [r, d]);
|
|
234
|
+
const l = {
|
|
235
235
|
theme: r,
|
|
236
|
-
variant:
|
|
236
|
+
variant: d,
|
|
237
237
|
corporateId: r.id,
|
|
238
|
-
setVariant:
|
|
238
|
+
setVariant: v
|
|
239
239
|
};
|
|
240
|
-
return /* @__PURE__ */ i(F.Provider, { value:
|
|
240
|
+
return /* @__PURE__ */ i(F.Provider, { value: l, children: a });
|
|
241
241
|
}
|
|
242
|
-
function
|
|
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:
|
|
249
|
-
return /* @__PURE__ */ i(S, { corporateId: e, variant:
|
|
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:
|
|
254
|
-
corporateId:
|
|
253
|
+
className: t,
|
|
254
|
+
corporateId: a,
|
|
255
255
|
variant: r,
|
|
256
|
-
children:
|
|
257
|
-
...
|
|
256
|
+
children: d,
|
|
257
|
+
...v
|
|
258
258
|
}) {
|
|
259
|
-
const
|
|
260
|
-
() =>
|
|
261
|
-
[
|
|
262
|
-
), [y, n] =
|
|
263
|
-
r ??
|
|
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 = [
|
|
274
|
-
return /* @__PURE__ */ i(F.Provider, { value: s, children: /* @__PURE__ */ i(
|
|
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:
|
|
277
|
-
return /* @__PURE__ */ i(V, { corporateId: e, variant:
|
|
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:
|
|
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:
|
|
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) =>
|
|
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
|
|
295
|
-
const { theme: e } =
|
|
294
|
+
function I() {
|
|
295
|
+
const { theme: e } = c();
|
|
296
296
|
return e.tokens;
|
|
297
297
|
}
|
|
298
298
|
function L() {
|
|
299
|
-
return
|
|
299
|
+
return I().brandColors;
|
|
300
300
|
}
|
|
301
301
|
function $() {
|
|
302
|
-
const { variant: e, setVariant:
|
|
303
|
-
return { variant: e, setVariant:
|
|
302
|
+
const { variant: e, setVariant: t } = c();
|
|
303
|
+
return { variant: e, setVariant: t };
|
|
304
304
|
}
|
|
305
305
|
function M() {
|
|
306
|
-
const { theme: e } =
|
|
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
|
-
|
|
322
|
+
m as corporateThemes,
|
|
319
323
|
L as useBrandColors,
|
|
320
324
|
M as useCorporateFeatures,
|
|
321
|
-
|
|
322
|
-
|
|
325
|
+
z as useDensity,
|
|
326
|
+
c as useTheme,
|
|
327
|
+
I as useThemeTokens,
|
|
323
328
|
$ as useThemeVariant
|
|
324
329
|
};
|