tamga-ui 0.5.4 → 0.5.5

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/CHANGELOG.md CHANGED
@@ -5,6 +5,31 @@ Versions follow [semver](https://semver.org/). Through `0.x`, breaking changes m
5
5
 
6
6
  > 🇹🇷 Türkçe için [tamga.org.tr/tr](https://tamga.org.tr/tr).
7
7
 
8
+ ## 0.5.5
9
+
10
+ > A page title finds its size, a shell can be driven by state instead of addresses, and the
11
+ > current rail row stands on the brand.
12
+
13
+ ### Added
14
+
15
+ - **`AppShell` entries can carry an action instead of an address.** `NavEntry.href` was required and
16
+ the active row was found by comparing paths, which is right for a web panel and wrong for a
17
+ desktop app, where a screen is state and there is no URL. An entry may now give `onSelect`, and
18
+ `activePath` is then matched against its `key`. One of the two is required; nothing changes for an
19
+ entry that has a path.
20
+
21
+ - **`AppShell.mainClassName`** — a state class on the content surface, for something the shell
22
+ cannot know: a window-wide drop target marking its edge, say. Layout stays the kit's; without it
23
+ a product had to draw the whole shell by hand to reach that one edge.
24
+
25
+ ### Changed
26
+
27
+ - **A page title is 24px, not 40px.** `PageBand` drew its heading at `--text-display-lg`, which is
28
+ the reference design's own size for a marketing-width page. In a dense panel — a table under the
29
+ title, a filter bar above it — it took the room the data needed and read as a banner rather than a
30
+ heading. The scale now reads 16 section · 18 dialog · 24 page · 30 KPI, and the two token comments
31
+ that still called 18px "page titles" and 30px "KPI numbers only" were corrected with it.
32
+
8
33
  ## 0.5.4
9
34
 
10
35
  > An empty filter drawer no longer advertises itself, and a tile's icon reads as a glyph.
@@ -78,7 +78,7 @@ export function CellActions({ className, children, align = "end", ...props
78
78
  * Doküman: /docs/page-band
79
79
  */
80
80
  export function PageBand({ eyebrow, title, subtitle, actions, className, ...rest }) {
81
- return (_jsxs("div", { ...dataProps(rest), className: cn("flex flex-wrap items-end gap-4", className), children: [_jsxs("div", { className: "min-w-0 flex-1 basis-65", children: [eyebrow ? (_jsx("p", { className: "mb-1.5 text-small font-semibold text-ink-faint", children: eyebrow })) : null, _jsx("h1", { className: "flex flex-wrap items-center gap-x-3 gap-y-1.5 font-display text-display-lg leading-tight font-extrabold text-ink", children: title }), subtitle ? _jsx("p", { className: "mt-1.5 text-body text-ink-soft", children: subtitle }) : null] }), actions ? _jsx("div", { className: "ml-auto flex flex-wrap items-center gap-2", children: actions }) : null] }));
81
+ return (_jsxs("div", { ...dataProps(rest), className: cn("flex flex-wrap items-end gap-4", className), children: [_jsxs("div", { className: "min-w-0 flex-1 basis-65", children: [eyebrow ? (_jsx("p", { className: "mb-1.5 text-small font-semibold text-ink-faint", children: eyebrow })) : null, _jsx("h1", { className: "flex flex-wrap items-center gap-x-3 gap-y-1.5 font-display text-display-sm leading-tight font-extrabold text-ink", children: title }), subtitle ? _jsx("p", { className: "mt-1.5 text-body text-ink-soft", children: subtitle }) : null] }), actions ? _jsx("div", { className: "ml-auto flex flex-wrap items-center gap-2", children: actions }) : null] }));
82
82
  }
83
83
  /**
84
84
  * Gezinen bağlantı. `Button variant="link"` DEĞİL: o bir `<button>`, yani orta
package/dist/fonts.css CHANGED
@@ -1,4 +1,4 @@
1
- /*! tamga-ui 0.5.4 · MIT · https://tamga.org.tr */
1
+ /*! tamga-ui 0.5.5 · MIT · https://tamga.org.tr */
2
2
  @font-face {
3
3
  font-family: "Red Hat Display";
4
4
  font-style: normal;
package/dist/kit.css CHANGED
@@ -1,4 +1,4 @@
1
- /*! tamga-ui 0.5.4 · MIT · https://tamga.org.tr */
1
+ /*! tamga-ui 0.5.5 · MIT · https://tamga.org.tr */
2
2
  :root {
3
3
 
4
4
  --overlay-gap: 8px;
@@ -440,9 +440,9 @@
440
440
 
441
441
  .tamga-rail-link[data-active="true"] {
442
442
  background: var(--color-shell);
443
- border-color: var(--color-edge-strong);
443
+ border-color: var(--color-accent-shadow);
444
444
  transform: translate(-1px, -1px);
445
- box-shadow: 3px 3px 0 var(--color-edge-strong);
445
+ box-shadow: 3px 3px 0 var(--color-accent-shadow);
446
446
  }
447
447
 
448
448
  .tamga-rail-link[data-active="true"] svg {
@@ -451,7 +451,7 @@
451
451
 
452
452
  .tamga-rail-link[data-active="true"]:active {
453
453
  transform: translate(2px, 2px);
454
- box-shadow: 0 0 0 var(--color-edge-strong);
454
+ box-shadow: 0 0 0 var(--color-accent-shadow);
455
455
  }
456
456
 
457
457
  .tamga-btn:not(:disabled):active,
@@ -8,8 +8,23 @@ import { type LinkComponent } from "./shared.js";
8
8
  * yönlendiriciyi tanımaz. Gerekçe: docs/adr/0004-sablon-katmani.md
9
9
  */
10
10
  export type NavEntry = {
11
+ /**
12
+ * The entry's identity. With `onSelect` it is also what `activePath` is compared against.
13
+ * TR: Girişin kimliği. `onSelect` ile birlikte `activePath`in karşılaştırıldığı değer de bu.
14
+ */
11
15
  key: string;
12
- href: string;
16
+ /**
17
+ * Where the entry goes. A desktop app has no addresses: it gives `onSelect` instead, and one of
18
+ * the two is required.
19
+ * TR: Girişin gittiği yer. Masaüstü uygulamasının adresi yok; onun yerine `onSelect` veriyor ve
20
+ * ikisinden biri zorunlu.
21
+ */
22
+ href?: string;
23
+ /**
24
+ * Runs instead of navigating. For a shell whose screens are state, not addresses.
25
+ * TR: Gezinmenin yerine koşuyor · ekranları adres değil durum olan bir kabuk için.
26
+ */
27
+ onSelect?: () => void;
13
28
  /** The translated label. In the tooltip on a narrow rail, on the row itself on a wide one. TR: Çevrilmiş etiket. Dar rayda ipucunda, geniş rayda satırın kendisinde. */
14
29
  label: string;
15
30
  icon: ComponentProps<typeof Icon>["icon"];
@@ -56,6 +71,13 @@ export type AppShellProps = {
56
71
  topbar?: ReactNode;
57
72
  /** A control at the foot of the rail: an expand/collapse button, say. TR: Rayın dibine giren kontrol: genişlet/daralt düğmesi gibi. */
58
73
  railFooter?: ReactNode;
74
+ /**
75
+ * A state class on the content surface, for something the shell cannot know: a window-wide drop
76
+ * target marking its edge, say. Layout stays the kit's.
77
+ * TR: İçerik yüzeyine binen durum sınıfı · kabuğun bilemeyeceği bir şey için: pencere genelinde
78
+ * bir bırakma hedefinin kenarını işaretlemesi gibi. Düzen kitte kalıyor.
79
+ */
80
+ mainClassName?: string;
59
81
  linkComponent?: LinkComponent;
60
82
  labels: {
61
83
  home: string;
@@ -63,5 +85,5 @@ export type AppShellProps = {
63
85
  };
64
86
  children: ReactNode;
65
87
  };
66
- export declare function AppShell({ brand, nav, activePath, rail, topbar, railFooter, linkComponent: Link, labels, children, }: AppShellProps): import("react").JSX.Element;
88
+ export declare function AppShell({ brand, nav, activePath, rail, topbar, railFooter, mainClassName, linkComponent: Link, labels, children, }: AppShellProps): import("react").JSX.Element;
67
89
  //# sourceMappingURL=app-shell.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"app-shell.d.ts","sourceRoot":"","sources":["../../src/patterns/app-shell.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvD,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAE7C,OAAO,EAAa,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5D;;;;;GAKG;AAEH,MAAM,MAAM,QAAQ,GAAG;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,wKAAwK;IACxK,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,cAAc,CAAC,OAAO,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC;IAC1C;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,wJAAwJ;IACxJ,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,GAAG,EAAE,SAAS,QAAQ,EAAE,CAAC;IACzB,mGAAmG;IACnG,UAAU,EAAE,MAAM,CAAC;IACnB;;;;;;;;;;;OAWG;IACH,IAAI,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IACzB;;;;OAIG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,uIAAuI;IACvI,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C,QAAQ,EAAE,SAAS,CAAC;CACrB,CAAC;AAEF,wBAAgB,QAAQ,CAAC,EACvB,KAAK,EACL,GAAG,EACH,UAAU,EACV,IAAe,EACf,MAAM,EACN,UAAU,EACV,aAAa,EAAE,IAAgB,EAC/B,MAAM,EACN,QAAQ,GACT,EAAE,aAAa,+BAmHf"}
1
+ {"version":3,"file":"app-shell.d.ts","sourceRoot":"","sources":["../../src/patterns/app-shell.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvD,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAG7C,OAAO,EAAa,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5D;;;;;GAKG;AAEH,MAAM,MAAM,QAAQ,GAAG;IACrB;;;OAGG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;OAKG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,wKAAwK;IACxK,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,cAAc,CAAC,OAAO,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC;IAC1C;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,wJAAwJ;IACxJ,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,GAAG,EAAE,SAAS,QAAQ,EAAE,CAAC;IACzB,mGAAmG;IACnG,UAAU,EAAE,MAAM,CAAC;IACnB;;;;;;;;;;;OAWG;IACH,IAAI,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IACzB;;;;OAIG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,uIAAuI;IACvI,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C,QAAQ,EAAE,SAAS,CAAC;CACrB,CAAC;AAEF,wBAAgB,QAAQ,CAAC,EACvB,KAAK,EACL,GAAG,EACH,UAAU,EACV,IAAe,EACf,MAAM,EACN,UAAU,EACV,aAAa,EACb,aAAa,EAAE,IAAgB,EAC/B,MAAM,EACN,QAAQ,GACT,EAAE,aAAa,+BAsHf"}
@@ -3,16 +3,18 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
3
3
  import { Fragment } from "react";
4
4
  import { Icon } from "../components/icon.js";
5
5
  import { RailLink } from "../components/rail-link.js";
6
+ import { cn } from "../lib/cn.js";
6
7
  import { PlainLink } from "./shared.js";
7
- export function AppShell({ brand, nav, activePath, rail = "narrow", topbar, railFooter, linkComponent: Link = PlainLink, labels, children, }) {
8
+ export function AppShell({ brand, nav, activePath, rail = "narrow", topbar, railFooter, mainClassName, linkComponent: Link = PlainLink, labels, children, }) {
8
9
  /* Bir giriş kendi alt ağacına sahip, ve EN UZUN EŞLEŞEN KAZANIR: kökün `/`
9
10
  olmadığı bir panelde kök giriş altındaki her rotayı yutuyordu.
10
11
  Gerekçe: docs/gerekce/08-blok-ve-sablon.md */
11
12
  const kapsiyor = (href) => activePath === href || activePath.startsWith(`${href}/`);
12
- const enOzel = nav.reduce((kazanan, entry) => kapsiyor(entry.href) && (kazanan === null || entry.href.length > kazanan.length)
13
+ const enOzel = nav.reduce((kazanan, entry) => entry.href && kapsiyor(entry.href) && (kazanan === null || entry.href.length > kazanan.length)
13
14
  ? entry.href
14
15
  : kazanan, null);
15
- const isCurrent = (href) => href === enOzel;
16
+ /* ADRESİ OLMAYAN GİRİŞ ANAHTARIYLA EŞLEŞİYOR: masaüstü kabuğunda ekran bir durum, yol değil. */
17
+ const isCurrent = (entry) => entry.href ? entry.href === enOzel : entry.key === activePath;
16
18
  const wide = rail === "wide";
17
- return (_jsxs("div", { className: "flex h-dvh w-full overflow-hidden bg-rail text-ink-soft", children: [_jsxs("aside", { className: `flex shrink-0 flex-col gap-2 bg-rail py-4 ${wide ? "w-60 px-3" : "w-20 items-center px-1"}`, "data-rail": rail, children: [brand ? (_jsxs(_Fragment, { children: [_jsx("span", { "aria-label": labels.home, className: `mb-2 flex h-10 shrink-0 items-center text-ink ${wide ? "px-2" : "w-10 justify-center"}`, children: brand }), _jsx("span", { className: `h-0 w-6 border-t border-line ${wide ? "ml-2" : ""}` })] })) : null, _jsx("nav", { "aria-label": labels.primaryNav, className: `tamga-rail-scroll flex w-full flex-1 flex-col gap-2 py-1 ${wide ? "" : "items-center"}`, children: nav.map((entry, i) => (_jsxs(Fragment, { children: [wide && entry.section && entry.section !== nav[i - 1]?.section ? (_jsx("p", { className: `px-2.5 text-caption font-bold uppercase tracking-label text-ink-faint ${i > 0 ? "mt-5 pb-1.5" : "pb-1.5"}`, children: entry.section })) : null, _jsx(RailLink, { href: entry.href, label: entry.label, active: isCurrent(entry.href), showLabel: wide, linkComponent: Link, "data-nav": entry.key, children: _jsx(Icon, { icon: entry.icon, size: "md", weight: isCurrent(entry.href) ? "fill" : "regular" }) })] }, entry.key))) }), railFooter ? _jsx("div", { className: "shrink-0", children: railFooter }) : null] }), _jsxs("div", { className: "flex min-w-0 flex-1 flex-col", children: [_jsx("header", { className: "tamga-gutter flex items-center gap-4 bg-band py-4", children: topbar }), _jsx("div", { className: "min-h-0 flex-1 overflow-hidden pr-4 pb-4", children: _jsx("main", { className: "tamga-surface tamga-app-main relative h-full min-h-0 overflow-y-auto", children: children }) })] })] }));
19
+ return (_jsxs("div", { className: "flex h-dvh w-full overflow-hidden bg-rail text-ink-soft", children: [_jsxs("aside", { className: `flex shrink-0 flex-col gap-2 bg-rail py-4 ${wide ? "w-60 px-3" : "w-20 items-center px-1"}`, "data-rail": rail, children: [brand ? (_jsxs(_Fragment, { children: [_jsx("span", { "aria-label": labels.home, className: `mb-2 flex h-10 shrink-0 items-center text-ink ${wide ? "px-2" : "w-10 justify-center"}`, children: brand }), _jsx("span", { className: `h-0 w-6 border-t border-line ${wide ? "ml-2" : ""}` })] })) : null, _jsx("nav", { "aria-label": labels.primaryNav, className: `tamga-rail-scroll flex w-full flex-1 flex-col gap-2 py-1 ${wide ? "" : "items-center"}`, children: nav.map((entry, i) => (_jsxs(Fragment, { children: [wide && entry.section && entry.section !== nav[i - 1]?.section ? (_jsx("p", { className: `px-2.5 text-caption font-bold uppercase tracking-label text-ink-faint ${i > 0 ? "mt-5 pb-1.5" : "pb-1.5"}`, children: entry.section })) : null, _jsx(RailLink, { href: entry.href, onClick: entry.onSelect, label: entry.label, active: isCurrent(entry), showLabel: wide, linkComponent: Link, "data-nav": entry.key, children: _jsx(Icon, { icon: entry.icon, size: "md", weight: isCurrent(entry) ? "fill" : "regular" }) })] }, entry.key))) }), railFooter ? _jsx("div", { className: "shrink-0", children: railFooter }) : null] }), _jsxs("div", { className: "flex min-w-0 flex-1 flex-col", children: [_jsx("header", { className: "tamga-gutter flex items-center gap-4 bg-band py-4", children: topbar }), _jsx("div", { className: "min-h-0 flex-1 overflow-hidden pr-4 pb-4", children: _jsx("main", { className: cn("tamga-surface tamga-app-main relative h-full min-h-0 overflow-y-auto", mainClassName), children: children }) })] })] }));
18
20
  }
package/dist/styles.css CHANGED
@@ -1,4 +1,4 @@
1
- /*! tamga-ui 0.5.4 · MIT · https://tamga.org.tr */
1
+ /*! tamga-ui 0.5.5 · MIT · https://tamga.org.tr */
2
2
  @import "./fonts.css";
3
3
  @import "./theme.css";
4
4
  @import "./kit.css";
package/dist/theme.css CHANGED
@@ -1,4 +1,4 @@
1
- /*! tamga-ui 0.5.4 · MIT · https://tamga.org.tr */
1
+ /*! tamga-ui 0.5.5 · MIT · https://tamga.org.tr */
2
2
  @custom-variant dark (&:is(.dark *));
3
3
 
4
4
  @theme static {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tamga-ui",
3
- "version": "0.5.4",
3
+ "version": "0.5.5",
4
4
  "description": "Mant\u0131ksal's shared interface library: tokens, physics and components.",
5
5
  "license": "MIT",
6
6
  "type": "module",