@godxjp/ui 16.6.0 → 16.7.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.
@@ -2,7 +2,12 @@ import * as React from "react";
2
2
  import { type VariantProps } from "class-variance-authority";
3
3
  import type { ShapeProp, ToneProp } from "../../props/vocabulary";
4
4
  export type BadgeVariant = "default" | "secondary" | "outline" | "dashed";
5
- export type BadgeTone = ToneProp;
5
+ /**
6
+ * Badge tones extend the shared status `ToneProp` with a brand `primary` tone — a SOFT brand pill
7
+ * (tinted fill + brand text), the dashboard "role pill" pattern. The status tones stay status-only;
8
+ * for a SOLID brand fill use `variant="default"`.
9
+ */
10
+ export type BadgeTone = ToneProp | "primary";
6
11
  declare const badgeVariants: (props?: ({
7
12
  variant?: "default" | "outline" | "dashed" | "secondary" | null | undefined;
8
13
  shape?: "default" | "pill" | "sharp" | null | undefined;
@@ -17,6 +17,7 @@ import {
17
17
  toneInfoClass,
18
18
  toneMutedClass,
19
19
  toneNeutralClass,
20
+ tonePrimaryClass,
20
21
  toneSuccessClass,
21
22
  toneWarningClass
22
23
  } from "../../lib/control-styles";
@@ -65,6 +66,7 @@ const badgeVariants = cva(
65
66
  );
66
67
  const badgeToneClass = {
67
68
  default: void 0,
69
+ primary: cn("border-transparent", tonePrimaryClass),
68
70
  success: cn("border-transparent", toneSuccessClass),
69
71
  warning: cn("border-transparent", toneWarningClass),
70
72
  destructive: cn("border-transparent", toneDestructiveClass),
@@ -4,6 +4,12 @@ export type InputProps = React.InputHTMLAttributes<HTMLInputElement> & {
4
4
  allowClear?: boolean;
5
5
  /** Called after the field is cleared via the inline ✕. */
6
6
  onClear?: () => void;
7
+ /**
8
+ * A leading affordance pinned inside the start of the field — e.g. a mail or
9
+ * search icon (the common auth/search pattern). Decorative by default; the
10
+ * input keeps the keyboard focus. Pairs with `trailingIcon`/`allowClear`.
11
+ */
12
+ leadingIcon?: React.ReactNode;
7
13
  /**
8
14
  * A trailing affordance pinned inside the field — e.g. a calendar / clock popover
9
15
  * trigger button. ONE trailing icon shows at a time: when `allowClear` and the field
@@ -16,6 +22,12 @@ export declare const Input: React.ForwardRefExoticComponent<React.InputHTMLAttri
16
22
  allowClear?: boolean;
17
23
  /** Called after the field is cleared via the inline ✕. */
18
24
  onClear?: () => void;
25
+ /**
26
+ * A leading affordance pinned inside the start of the field — e.g. a mail or
27
+ * search icon (the common auth/search pattern). Decorative by default; the
28
+ * input keeps the keyboard focus. Pairs with `trailingIcon`/`allowClear`.
29
+ */
30
+ leadingIcon?: React.ReactNode;
19
31
  /**
20
32
  * A trailing affordance pinned inside the field — e.g. a calendar / clock popover
21
33
  * trigger button. ONE trailing icon shows at a time: when `allowClear` and the field
@@ -18,6 +18,7 @@ const Input = React.forwardRef(
18
18
  type,
19
19
  allowClear = false,
20
20
  onClear,
21
+ leadingIcon,
21
22
  trailingIcon,
22
23
  value,
23
24
  defaultValue,
@@ -58,7 +59,7 @@ const Input = React.forwardRef(
58
59
  setHasText(false);
59
60
  onClear?.();
60
61
  };
61
- if (!allowClear && trailingIcon == null) {
62
+ if (!allowClear && trailingIcon == null && leadingIcon == null) {
62
63
  return /* @__PURE__ */ jsx(
63
64
  "input",
64
65
  {
@@ -86,6 +87,15 @@ const Input = React.forwardRef(
86
87
  }
87
88
  ) : trailingIcon;
88
89
  return /* @__PURE__ */ jsxs("span", { "data-slot": "input-affix-wrapper", className: "relative inline-flex w-full items-center", children: [
90
+ leadingIcon != null ? /* @__PURE__ */ jsx(
91
+ "span",
92
+ {
93
+ "data-slot": "input-leading",
94
+ "aria-hidden": "true",
95
+ className: "text-muted-foreground pointer-events-none absolute inset-y-0 start-2 inline-flex items-center",
96
+ children: leadingIcon
97
+ }
98
+ ) : null,
89
99
  /* @__PURE__ */ jsx(
90
100
  "input",
91
101
  {
@@ -95,7 +105,12 @@ const Input = React.forwardRef(
95
105
  value,
96
106
  defaultValue,
97
107
  onChange: handleChange,
98
- className: cn(inputBaseClass, (showClear || trailingIcon != null) && "pe-9", className),
108
+ className: cn(
109
+ inputBaseClass,
110
+ leadingIcon != null && "ps-9",
111
+ (showClear || trailingIcon != null) && "pe-9",
112
+ className
113
+ ),
99
114
  ...props
100
115
  }
101
116
  ),
@@ -27,4 +27,5 @@ export declare const Heading: React.ForwardRefExoticComponent<Omit<React.HTMLAtt
27
27
  tone?: import("../../props").TextToneProp;
28
28
  align?: import("../../props").TextAlignProp;
29
29
  truncate?: boolean;
30
+ weight?: import("../../props").FontWeightProp;
30
31
  } & React.RefAttributes<HTMLHeadingElement>>;
@@ -28,12 +28,13 @@ const Text = React.forwardRef(
28
28
  );
29
29
  Text.displayName = "Text";
30
30
  const Heading = React.forwardRef(
31
- ({ level = 2, as, tone = "default", align, truncate, className, ...props }, ref) => React.createElement(as ?? `h${level}`, {
31
+ ({ level = 2, as, tone = "default", align, truncate, weight = "medium", className, ...props }, ref) => React.createElement(as ?? `h${level}`, {
32
32
  ref,
33
33
  "data-slot": "heading",
34
34
  "data-level": level,
35
35
  "data-tone": tone,
36
36
  "data-align": align,
37
+ "data-weight": weight,
37
38
  "data-truncate": truncate ? "" : void 0,
38
39
  className: cn("ui-heading", className),
39
40
  ...props
@@ -23,6 +23,11 @@ export declare const tableCellPaddingClass = "py-[length:var(--table-cell-paddin
23
23
  export declare const toneSuccessClass = "border-success/30 bg-success/10 text-success-strong";
24
24
  export declare const toneWarningClass = "border-warning/30 bg-warning/10 text-warning-strong";
25
25
  export declare const toneInfoClass = "border-info/30 bg-info/10 text-info-strong";
26
+ /** Soft BRAND pill — a tinted primary tone (border/fill keep the brand role; the TEXT uses the
27
+ * AA-strong brand colour `text-primary-strong`, darker than the fill, so a small brand label clears
28
+ * WCAG AA on the soft tint — `text-primary` alone is only 4.04:1 in light). For a SOLID brand fill
29
+ * use the Badge `default` variant instead. */
30
+ export declare const tonePrimaryClass = "border-primary/30 bg-primary/10 text-primary-strong";
26
31
  export declare const toneDestructiveClass = "border-destructive/30 bg-destructive/10 text-error-strong";
27
32
  export declare const toneMutedClass = "border-border bg-muted text-muted-foreground";
28
33
  export declare const toneNeutralClass = "border-border bg-muted text-muted-foreground";
@@ -11,6 +11,7 @@ const tableCellPaddingClass = "py-[length:var(--table-cell-padding-y)]";
11
11
  const toneSuccessClass = "border-success/30 bg-success/10 text-success-strong";
12
12
  const toneWarningClass = "border-warning/30 bg-warning/10 text-warning-strong";
13
13
  const toneInfoClass = "border-info/30 bg-info/10 text-info-strong";
14
+ const tonePrimaryClass = "border-primary/30 bg-primary/10 text-primary-strong";
14
15
  const toneDestructiveClass = "border-destructive/30 bg-destructive/10 text-error-strong";
15
16
  const toneMutedClass = "border-border bg-muted text-muted-foreground";
16
17
  const toneNeutralClass = "border-border bg-muted text-muted-foreground";
@@ -29,6 +30,7 @@ export {
29
30
  toneInfoClass,
30
31
  toneMutedClass,
31
32
  toneNeutralClass,
33
+ tonePrimaryClass,
32
34
  toneSuccessClass,
33
35
  toneWarningClass
34
36
  };
@@ -23,7 +23,8 @@ export type DescriptionsItemProp = {
23
23
  /** @see Badge */
24
24
  export type BadgeProp = {
25
25
  variant?: "default" | "secondary" | "outline";
26
- tone?: ToneProp;
26
+ /** Status tones plus a brand `primary` tone (soft brand pill); solid brand = `variant="default"`. */
27
+ tone?: ToneProp | "primary";
27
28
  status?: string;
28
29
  icon?: React.ComponentType<{
29
30
  className?: string;
@@ -15,6 +15,10 @@ export type InputProp = React.InputHTMLAttributes<HTMLInputElement> & {
15
15
  allowClear?: boolean;
16
16
  /** Called after the field is cleared via the inline ✕. */
17
17
  onClear?: () => void;
18
+ /** A leading affordance pinned inside the start of the field (e.g. a mail/lock icon). */
19
+ leadingIcon?: React.ReactNode;
20
+ /** A trailing affordance pinned inside the end of the field (replaced by the clear ✕ when `allowClear` + value). */
21
+ trailingIcon?: React.ReactNode;
18
22
  };
19
23
  /** @see Textarea */
20
24
  export type TextareaProp = React.TextareaHTMLAttributes<HTMLTextAreaElement> & {
@@ -28,6 +28,8 @@ export type HeadingProp = Omit<React.HTMLAttributes<HTMLHeadingElement>, "color"
28
28
  tone?: TextToneProp;
29
29
  align?: TextAlignProp;
30
30
  truncate?: boolean;
31
+ /** Weight (system canon: 400 · 500 · 700). Default `medium` — set `bold` for an emphasised title. */
32
+ weight?: FontWeightProp;
31
33
  };
32
34
  /** @see Button */
33
35
  export type ButtonProp = React.ButtonHTMLAttributes<HTMLButtonElement> & {
@@ -42,7 +42,7 @@
42
42
  @source inline("rounded-{xs,xl,2xl}");
43
43
  @source inline("text-2xs");
44
44
  @source inline("text-{3xl,4xl,5xl}");
45
- @source inline("text-{success,warning,info,error}-strong");
45
+ @source inline("text-{primary,success,warning,info,error}-strong");
46
46
  /* `.js` matters: the published package ships only compiled JS under dist (no
47
47
  * .tsx sources), and this file is copied verbatim into dist/styles — without
48
48
  * it Tailwind finds no component classes in consumers (unstyled popovers and
@@ -103,6 +103,7 @@
103
103
  --color-attention-foreground: hsl(var(--attention-foreground));
104
104
  /* AA-strong status TEXT colours (text-{success,warning,info,error}-strong) — darker than the
105
105
  * fills so small coloured labels clear WCAG AA on white; flip light on the dark theme. */
106
+ --color-primary-strong: hsl(var(--text-primary));
106
107
  --color-success-strong: hsl(var(--text-success));
107
108
  --color-warning-strong: hsl(var(--text-warning));
108
109
  --color-info-strong: hsl(var(--text-info));
@@ -23,6 +23,16 @@
23
23
  overflow: hidden;
24
24
  }
25
25
 
26
+ /* Decorative brand SPOTLIGHT backdrop — the token-driven radial halo behind a hero / auth card,
27
+ * replacing a hand-authored `radial-gradient(... hsl(var(--primary)/.18) ...)`. Apply to an
28
+ * `aria-hidden` layer (e.g. an absolutely-positioned full-bleed div behind the card). All geometry
29
+ * and tint come from the `--brand-glow*` tokens, so a theme retints/repositions it with no markup
30
+ * change. `pointer-events:none` keeps the backdrop from stealing clicks from the card above it. */
31
+ .ui-brand-glow {
32
+ background-image: var(--brand-glow);
33
+ pointer-events: none;
34
+ }
35
+
26
36
  .ui-flex,
27
37
  .ui-stack-xs {
28
38
  display: flex;
@@ -33,14 +33,19 @@
33
33
  font-size: var(--font-size-2xl);
34
34
  }
35
35
 
36
- /* Weight — the dxs-kintai canon (400 body · 500 heading/label · 700 emphasis). No 600. */
37
- [data-slot="text"][data-weight="regular"] {
36
+ /* Weight — the dxs-kintai canon (400 body · 500 heading/label · 700 emphasis). No 600.
37
+ * Shared by text + heading; the two-attribute heading selectors outrank the base heading
38
+ * rule below, so `<Heading weight="bold">` renders a semantic, emphasised title. */
39
+ [data-slot="text"][data-weight="regular"],
40
+ [data-slot="heading"][data-weight="regular"] {
38
41
  font-weight: var(--font-weight-normal);
39
42
  }
40
- [data-slot="text"][data-weight="medium"] {
43
+ [data-slot="text"][data-weight="medium"],
44
+ [data-slot="heading"][data-weight="medium"] {
41
45
  font-weight: var(--font-weight-medium);
42
46
  }
43
- [data-slot="text"][data-weight="bold"] {
47
+ [data-slot="text"][data-weight="bold"],
48
+ [data-slot="heading"][data-weight="bold"] {
44
49
  font-weight: var(--font-weight-bold);
45
50
  }
46
51
 
@@ -40,6 +40,7 @@
40
40
  /* Status TEXT colours — darker than the fill roles so small coloured text (a StatCard delta, an
41
41
  * outline status badge label) clears WCAG AA 4.5:1 on white. The fill roles (--success/--warning/
42
42
  * --info) stay the brighter wa-iro for badges/bars; only TEXT reads these via text-*-strong. */
43
+ --text-primary: 204 100% 30%; /* deep brand blue — AA brand text on the soft primary tint */
43
44
  --text-success: 152 84% 22%; /* deep 若竹 — AA green text on white */
44
45
  --text-warning: 36 100% 28%; /* dark 山吹 amber — yellow can never pass as text */
45
46
  --text-info: 221 70% 38%; /* deep 群青 — AA blue text on white */
@@ -107,6 +108,21 @@
107
108
  * — the CTA then carries a brand glow with no component change. */
108
109
  --shadow-glow: 0 0 0 0 transparent;
109
110
 
111
+ /* Brand SPOTLIGHT — a decorative radial brand halo for hero / auth backdrops (the `.ui-brand-glow`
112
+ * utility paints this as a background-image on an aria-hidden layer). Every knob is a token, so a
113
+ * service retints (`--brand-glow-color`), softens (`--brand-glow-alpha`), resizes
114
+ * (`--brand-glow-size`) or repositions (`--brand-glow-position`) the halo with no markup change;
115
+ * override the whole `--brand-glow` for a bespoke gradient. Default: a soft primary glow up top. */
116
+ --brand-glow-color: var(--primary);
117
+ --brand-glow-alpha: 0.18;
118
+ --brand-glow-size: 60% 50%;
119
+ --brand-glow-position: 50% 0%;
120
+ --brand-glow: radial-gradient(
121
+ ellipse var(--brand-glow-size) at var(--brand-glow-position),
122
+ hsl(var(--brand-glow-color) / var(--brand-glow-alpha)),
123
+ transparent 70%
124
+ );
125
+
110
126
  /* FOCUS RING — the two global knobs for the keyboard-focus affordance (WCAG 2.4.7 / 2.4.11).
111
127
  * `--focus-ring-color` is the themeable hue (HSL components, defaults to --ring) and
112
128
  * `--focus-ring-width` the standard thickness; override either ONCE — even scoped under a
@@ -345,6 +361,7 @@
345
361
  --text-link: 204 90% 66%;
346
362
  --text-brand: 204 90% 66%;
347
363
  /* Status text on the dark spine reads LIGHT (AA on dark surfaces). */
364
+ --text-primary: 204 90% 64%; /* lifted brand blue — AA on the dark primary tint */
348
365
  --text-success: 146 55% 64%;
349
366
  --text-warning: 44 95% 62%;
350
367
  --text-info: 221 70% 72%;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@godxjp/ui",
3
- "version": "16.6.0",
3
+ "version": "16.7.0",
4
4
  "type": "module",
5
5
  "packageManager": "pnpm@10.29.1",
6
6
  "sideEffects": false,