tamga-ui 0.4.0 → 0.4.1
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 +34 -1
- package/dist/components/radio-group.d.ts +8 -2
- package/dist/components/radio-group.d.ts.map +1 -1
- package/dist/components/radio-group.js +2 -2
- package/dist/kit.css +1 -1
- package/dist/patterns/app-shell.d.ts +15 -0
- package/dist/patterns/app-shell.d.ts.map +1 -1
- package/dist/patterns/app-shell.js +2 -1
- package/dist/styles.css +1 -1
- package/dist/theme.css +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,7 +5,40 @@ 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.4.
|
|
8
|
+
## 0.4.1
|
|
9
|
+
|
|
10
|
+
Two gaps that products had been paying for, both found by a gate that asks a product not to
|
|
11
|
+
hand-write a kit class. Each one had pushed a caller off the component entirely.
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **An accessibility invariant suite.** Twenty-three renders, three invariants: every interactive
|
|
16
|
+
element has an accessible name, no `aria-hidden` subtree hides something focusable, and role pairs
|
|
17
|
+
are complete (`radio` inside `radiogroup`, `tab` inside `tablist`, `option` inside `listbox`).
|
|
18
|
+
|
|
19
|
+
This is not an axe sweep and does not claim to be. The previous sweep ran over a consuming
|
|
20
|
+
product's stories and disappeared with them, which was the wrong home for it: a promise the
|
|
21
|
+
library makes has to be measured in the library. What is not covered is written at the top of the
|
|
22
|
+
file — contrast (a separate gate already measures it), focus order, live-region behaviour, and any
|
|
23
|
+
component the suite does not render.
|
|
24
|
+
|
|
25
|
+
- **`RadioGroup` options carry their own attributes.** Anything beyond `value` and `label` lands on
|
|
26
|
+
that option's button. The sibling components for picking one of several things had carried
|
|
27
|
+
per-option hooks since 0.3.1 and 0.4.0; this one had not, so a caller who needed to point at a
|
|
28
|
+
single choice left the component behind and hand-wrote the class, which meant leaving the role and
|
|
29
|
+
the keyboard behind with it. The kit's own attributes are written after the caller's, so a hook
|
|
30
|
+
cannot overwrite `aria-checked`.
|
|
31
|
+
|
|
32
|
+
- **`AppShell` draws section headings.** `NavEntry` takes an optional `section`; the rail groups
|
|
33
|
+
consecutive entries by it and draws a heading when the group changes. Wide rails only: in a 40px
|
|
34
|
+
box a heading does not read, and there grouping is carried by spacing.
|
|
35
|
+
|
|
36
|
+
A panel whose menu is split into seven named groups could not express that, so it drew its own
|
|
37
|
+
rail and left behind everything the template brings. The field is flat rather than a nested list
|
|
38
|
+
of groups, for two reasons: nesting would have been a breaking change, and a nested shape makes an
|
|
39
|
+
empty group possible. Here a heading exists only if an entry has one.
|
|
40
|
+
|
|
41
|
+
|
|
9
42
|
|
|
10
43
|
**A step now has an identity of its own.** `Steps` took a plain `readonly string[]`, so a step was
|
|
11
44
|
nothing but its translated label. Two consequences followed, and both were silent.
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
export declare function RadioGroup<T extends string>({ options, value, onChange, label, look, disabled, className, ...rest }: {
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* The choices. Anything beyond `value` and `label` lands on that option's button, so a choice can
|
|
5
|
+
* carry the hook a test or a style needs. TR: Seçenekler. `value` ve `label` dışındaki her şey o
|
|
6
|
+
* seçeneğin düğmesine iniyor, yani bir seçenek testin ya da stilin ihtiyaç duyduğu kancayı
|
|
7
|
+
* taşıyabiliyor.
|
|
8
|
+
*/
|
|
9
|
+
options: readonly ({
|
|
4
10
|
value: T;
|
|
5
11
|
label: ReactNode;
|
|
6
|
-
}[];
|
|
12
|
+
} & Record<string, unknown>)[];
|
|
7
13
|
value: T;
|
|
8
14
|
onChange?: (next: T) => void;
|
|
9
15
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"radio-group.d.ts","sourceRoot":"","sources":["../../src/components/radio-group.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAWvC,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,EAAE,EAC3C,OAAO,EACP,KAAK,EACL,QAAQ,EACR,KAAK,EACL,IAAa,EACb,QAAgB,EAChB,SAAS,EACT,GAAG,IAAI,EACR,EAAE;IACD,OAAO,EAAE,SAAS;QAAE,KAAK,EAAE,CAAC,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"radio-group.d.ts","sourceRoot":"","sources":["../../src/components/radio-group.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAWvC,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,EAAE,EAC3C,OAAO,EACP,KAAK,EACL,QAAQ,EACR,KAAK,EACL,IAAa,EACb,QAAgB,EAChB,SAAS,EACT,GAAG,IAAI,EACR,EAAE;IACD;;;;;OAKG;IACH,OAAO,EAAE,SAAS,CAAC;QAAE,KAAK,EAAE,CAAC,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC;IAC/E,KAAK,EAAE,CAAC,CAAC;IACT,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC;IAC7B;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;;;;;;;;;OAWG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IAChC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,CAAC,CAAC,EAAE,QAAQ,MAAM,EAAE,GAAG,OAAO,CAAC;CAChC,+BAmDA"}
|
|
@@ -10,7 +10,7 @@ import { OFF } from "./control-base.js";
|
|
|
10
10
|
* olmadan ekran okuyucu "üç ayrı düğme" duyurur, "üç seçenekten biri" değil.
|
|
11
11
|
* ---------------------------------------------------------------- */
|
|
12
12
|
export function RadioGroup({ options, value, onChange, label, look = "list", disabled = false, className, ...rest }) {
|
|
13
|
-
return (_jsx("div", { ...dataProps(rest), role: "radiogroup", "aria-label": label, "data-look": look, className: cn(look === "list" ? "flex flex-col gap-2" : "flex flex-wrap gap-2", look === "card" && "sm:grid sm:grid-cols-3", className), children: options.map((
|
|
13
|
+
return (_jsx("div", { ...dataProps(rest), role: "radiogroup", "aria-label": label, "data-look": look, className: cn(look === "list" ? "flex flex-col gap-2" : "flex flex-wrap gap-2", look === "card" && "sm:grid sm:grid-cols-3", className), children: options.map(({ value: v, label: etiket, ...rest }) => (_jsxs("button", { type: "button", ...rest, role: "radio", "aria-checked": value === v, "aria-disabled": disabled || undefined, onClick: () => !disabled && onChange?.(v),
|
|
14
14
|
/* ÜSTTEN HİZALI VE TAM GENİŞLİK, ve ikisi de iki satırlık bir
|
|
15
15
|
seçenek yüzünden değişti.
|
|
16
16
|
`items-center` tek satırlık etiketlerde doğru duruyordu; altına
|
|
@@ -20,5 +20,5 @@ export function RadioGroup({ options, value, onChange, label, look = "list", dis
|
|
|
20
20
|
erkenden sarıyor ve seçenekler farklı genişliklerde tırtıklı bir
|
|
21
21
|
sütun oluşturuyordu. Tam genişlik hepsini aynı sol kenara ve aynı
|
|
22
22
|
sarma noktasına oturtuyor. */
|
|
23
|
-
className: cn("text-body", look === "list" && "flex w-full items-start gap-2 text-left", look === "chip" && "tamga-choice-chip", look === "card" && "tamga-choice-card"), style: disabled ? OFF : undefined, children: [_jsx("span", { className: cn("tamga-radio", look !== "chip" && "tamga-choice-mark"), "data-checked": value ===
|
|
23
|
+
className: cn("text-body", look === "list" && "flex w-full items-start gap-2 text-left", look === "chip" && "tamga-choice-chip", look === "card" && "tamga-choice-card"), style: disabled ? OFF : undefined, children: [_jsx("span", { className: cn("tamga-radio", look !== "chip" && "tamga-choice-mark"), "data-checked": value === v }), _jsx("span", { className: "min-w-0 flex-1", children: etiket })] }, v))) }));
|
|
24
24
|
}
|
package/dist/kit.css
CHANGED
|
@@ -13,6 +13,21 @@ export type NavEntry = {
|
|
|
13
13
|
/** 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
14
|
label: string;
|
|
15
15
|
icon: ComponentProps<typeof Icon>["icon"];
|
|
16
|
+
/**
|
|
17
|
+
* The group this entry belongs to, already translated. TR: Bu girişin ait olduğu grup, çevrilmiş
|
|
18
|
+
* hâliyle.
|
|
19
|
+
*
|
|
20
|
+
* Ray, ardışık girişleri bu ada göre kümeliyor ve grup değiştiğinde bir başlık çiziyor. Verilmezse
|
|
21
|
+
* giriş başlıksız kalıyor; hiçbiri vermezse ray tek bir liste olarak çiziliyor, yani eski davranış.
|
|
22
|
+
*
|
|
23
|
+
* ALAN DÜZ, VERİ İÇ İÇE DEĞİL. `nav` bir gruplar dizisi olsaydı bu kırıcı bir değişiklik olurdu,
|
|
24
|
+
* ve boş bir grup kurmak mümkün hâle gelirdi. Düz listede o iki sorun da yok: grup başlığı
|
|
25
|
+
* verinin bir alanı, ve başlık ancak bir girişi varsa görünüyor.
|
|
26
|
+
*
|
|
27
|
+
* YALNIZ GENİŞ RAYDA ÇİZİLİYOR. Dar rayda 40 piksellik bir kutuda başlık okunmuyor; orada
|
|
28
|
+
* gruplama boşlukla anlatılıyor.
|
|
29
|
+
*/
|
|
30
|
+
section?: string;
|
|
16
31
|
};
|
|
17
32
|
export type AppShellProps = {
|
|
18
33
|
/** The brand mark at the top of the rail; the caller supplies its own link. TR: Rayın tepesindeki marka işareti; kendi bağlantısını çağıran veriyor. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-shell.d.ts","sourceRoot":"","sources":["../../src/patterns/app-shell.tsx"],"names":[],"mappings":"
|
|
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,+BAiFf"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Fragment } from "react";
|
|
3
4
|
import { Icon } from "../components/icon.js";
|
|
4
5
|
import { RailLink } from "../components/rail-link.js";
|
|
5
6
|
import { PlainLink } from "./shared.js";
|
|
@@ -9,5 +10,5 @@ export function AppShell({ brand, nav, activePath, rail = "narrow", topbar, rail
|
|
|
9
10
|
altındaki her rotayı yutar. */
|
|
10
11
|
const isCurrent = (href) => href === "/" ? activePath === href : activePath === href || activePath.startsWith(`${href}/`);
|
|
11
12
|
const wide = rail === "wide";
|
|
12
|
-
return (_jsxs("div", { className: "flex h-dvh w-full overflow-hidden bg-shell text-ink-soft", children: [_jsxs("aside", { className: `flex shrink-0 flex-col gap-2 bg-shell 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) => (_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: "base" }) }, 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 py-4", children: topbar }), _jsx("div", { className: "min-h-0 flex-1 overflow-hidden pr-4 pb-4", children: _jsx("main", { className: "tamga-surface h-full min-h-0 overflow-y-auto", children: children }) })] })] }));
|
|
13
|
+
return (_jsxs("div", { className: "flex h-dvh w-full overflow-hidden bg-shell text-ink-soft", children: [_jsxs("aside", { className: `flex shrink-0 flex-col gap-2 bg-shell 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-micro font-semibold uppercase tracking-wide text-ink-faint ${i > 0 ? "mt-4 pb-1" : "pb-1"}`, 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: "base" }) })] }, 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 py-4", children: topbar }), _jsx("div", { className: "min-h-0 flex-1 overflow-hidden pr-4 pb-4", children: _jsx("main", { className: "tamga-surface h-full min-h-0 overflow-y-auto", children: children }) })] })] }));
|
|
13
14
|
}
|
package/dist/styles.css
CHANGED
package/dist/theme.css
CHANGED