@nadicodeai/ui 1.1.0 → 1.1.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.
@@ -1 +1 @@
1
- {"version":3,"file":"chart-time-series.d.ts","sourceRoot":"","sources":["../../src/components/chart-time-series.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAY/B,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,kCAAkC,CAAC;AAgH1C,KAAK,gBAAgB,GAAG;IACtB,2EAA2E;IAC3E,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,KAAK,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;AAEvD,KAAK,eAAe,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,UAAU,CAAC,GAAG;IACxE,IAAI,EAAE,SAAS,eAAe,EAAE,CAAC;IACjC,wDAAwD;IACxD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACpC,2DAA2D;IAC3D,cAAc,EAAE,cAAc,CAAC;IAC/B,wEAAwE;IACxE,KAAK,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IAC3C;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAsJF,iBAAS,cAAc,CAAC,EACtB,IAAI,EACJ,IAAI,EACJ,MAAM,EACN,cAAc,EACd,KAAK,EACL,MAAiB,EACjB,cAA8B,EAC9B,UAAU,EACV,UAAoB,EACpB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,eAAe,qBAyDjB;AAED,iBAAS,cAAc,CAAC,EACtB,IAAI,EACJ,IAAI,EACJ,MAAM,EACN,cAAc,EACd,KAAK,EACL,MAAiB,EACjB,cAA8B,EAC9B,UAAU,EACV,UAAoB,EACpB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,eAAe,qBA6EjB;AAED,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,CAAC;AAC1C,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,gBAAgB,EAAE,CAAC"}
1
+ {"version":3,"file":"chart-time-series.d.ts","sourceRoot":"","sources":["../../src/components/chart-time-series.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAY/B,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,kCAAkC,CAAC;AAiH1C,KAAK,gBAAgB,GAAG;IACtB,2EAA2E;IAC3E,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,KAAK,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;AAEvD,KAAK,eAAe,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,UAAU,CAAC,GAAG;IACxE,IAAI,EAAE,SAAS,eAAe,EAAE,CAAC;IACjC,wDAAwD;IACxD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACpC,2DAA2D;IAC3D,cAAc,EAAE,cAAc,CAAC;IAC/B,wEAAwE;IACxE,KAAK,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IAC3C;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAsJF,iBAAS,cAAc,CAAC,EACtB,IAAI,EACJ,IAAI,EACJ,MAAM,EACN,cAAc,EACd,KAAK,EACL,MAAiB,EACjB,cAA8B,EAC9B,UAAU,EACV,UAAoB,EACpB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,eAAe,qBAyDjB;AAED,iBAAS,cAAc,CAAC,EACtB,IAAI,EACJ,IAAI,EACJ,MAAM,EACN,cAAc,EACd,KAAK,EACL,MAAiB,EACjB,cAA8B,EAC9B,UAAU,EACV,UAAoB,EACpB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,eAAe,qBA6EjB;AAED,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,CAAC;AAC1C,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,gBAAgB,EAAE,CAAC"}
@@ -34,16 +34,17 @@ import { CHART_ENTITY_OTHER_COLOR, entityColor, } from "./chart-entity-colors.js
34
34
  * never shows, which would leave the `accessibilityLayer` keyboard path with
35
35
  * no visible focus — and that utility also beats the global base-layer focus
36
36
  * outline. chart.tsx is untouched, so we restore the canonical treatment
37
- * through the `className` we pass to our own `ChartContainer` instances: these
38
- * `:focus-visible` overrides sit on a distinct arbitrary-variant selector (a
37
+ * through the `className` we pass to our own `ChartContainer` instances: this
38
+ * `:focus-visible` override sits on a distinct arbitrary-variant selector (a
39
39
  * different tailwind-merge group AND modifier, so `cn()` keeps both) with
40
40
  * higher CSS specificity, re-enabling the offset ink outline only while the
41
- * svg is keyboard-focused.
41
+ * svg is keyboard-focused. `nc-focus-outline` writes `outline-style: solid`
42
+ * outright, which is what gets past `outline-hidden` — that utility parks
43
+ * `none` in the `--tw-outline-style` variable every Tailwind outline utility
44
+ * reads, so a plain `focus-visible:outline` restates a suppression.
42
45
  */
43
- const CHART_SURFACE_FOCUS_CLASS = "[&_.recharts-surface:focus-visible]:outline " +
44
- "[&_.recharts-surface:focus-visible]:outline-[length:var(--outline-width-focus)] " +
45
- "[&_.recharts-surface:focus-visible]:outline-ring " +
46
- "[&_.recharts-surface:focus-visible]:outline-offset-[var(--outline-offset-focus)]";
46
+ const CHART_SURFACE_FOCUS_CLASS = "[&_.recharts-surface:focus-visible]:nc-focus-outline " +
47
+ "[&_.recharts-surface:focus-visible]:outline-ring";
47
48
  /**
48
49
  * The x ticks land at ONE constant stride across the range, and the stride is
49
50
  * the smallest one whose labels still clear each other at the width the chart
@@ -44,7 +44,7 @@ function ComboboxSeparator({ className, ...props }) {
44
44
  return (_jsx(ComboboxPrimitive.Separator, { "data-slot": "combobox-separator", className: cn("-mx-1 my-1 h-px bg-border", className), ...props }));
45
45
  }
46
46
  function ComboboxChips({ className, ...props }) {
47
- return (_jsx(ComboboxPrimitive.Chips, { "data-slot": "combobox-chips", className: cn("flex min-h-touch-target flex-wrap items-center gap-1 rounded-md border border-input bg-background bg-clip-padding px-control-padding-inline py-1 text-sm transition-colors focus-within:outline focus-within:outline-[length:var(--outline-width-focus)] focus-within:outline-offset-[var(--outline-offset-focus)] focus-within:outline-ring has-aria-invalid:border-destructive has-aria-invalid:outline has-aria-invalid:outline-[length:var(--outline-width-focus)] has-aria-invalid:outline-offset-[var(--outline-offset-focus)] has-aria-invalid:outline-destructive has-data-[slot=combobox-chip]:px-1 [@media(hover:hover)_and_(pointer:fine)]:min-h-control-height", className), ...props }));
47
+ return (_jsx(ComboboxPrimitive.Chips, { "data-slot": "combobox-chips", className: cn("flex min-h-touch-target flex-wrap items-center gap-1 rounded-md border border-input bg-background bg-clip-padding px-control-padding-inline py-1 text-sm transition-colors focus-within:nc-focus-outline focus-within:outline-ring has-aria-invalid:border-destructive has-aria-invalid:nc-focus-outline has-aria-invalid:outline-destructive has-data-[slot=combobox-chip]:px-1 [@media(hover:hover)_and_(pointer:fine)]:min-h-control-height", className), ...props }));
48
48
  }
49
49
  function ComboboxChip({ className, children, showRemove = true, ...props }) {
50
50
  return (_jsxs(ComboboxPrimitive.Chip, { "data-slot": "combobox-chip", className: cn("flex h-[calc(--spacing(5.25))] w-fit items-center justify-center gap-1 rounded-md bg-muted px-1.5 text-xs font-medium whitespace-nowrap text-foreground has-disabled:pointer-events-none has-disabled:cursor-not-allowed has-disabled:opacity-50 has-data-[slot=combobox-chip-remove]:pr-0", className), ...props, children: [children, showRemove && (_jsx(ComboboxPrimitive.ChipRemove, { render: _jsx(Button, { variant: "ghost", size: "icon-xs" }), className: "-ml-1 opacity-50 hover:opacity-100", "data-slot": "combobox-chip-remove", children: _jsx(XIcon, { className: "pointer-events-none" }) }))] }));
@@ -6,7 +6,7 @@ import { Button } from "./button.js";
6
6
  import { Input } from "./input.js";
7
7
  import { Textarea } from "./textarea.js";
8
8
  function InputGroup({ className, ...props }) {
9
- return (_jsx("div", { "data-slot": "input-group", role: "group", className: cn("group/input-group relative flex h-control-height min-h-touch-target w-full min-w-0 items-center rounded-md border border-input bg-background transition-colors outline-none in-data-[slot=combobox-content]:focus-within:border-inherit has-disabled:bg-input/50 has-disabled:opacity-50 not-in-data-[slot=combobox-content]:has-[[data-slot=input-group-control]:focus-visible]:outline has-[[data-slot=input-group-control]:focus-visible]:outline-[length:var(--outline-width-focus)] has-[[data-slot=input-group-control]:focus-visible]:outline-offset-[var(--outline-offset-focus)] has-[[data-slot=input-group-control]:focus-visible]:outline-ring has-[[data-slot][aria-invalid=true]]:border-destructive has-[[data-slot][aria-invalid=true]]:outline has-[[data-slot][aria-invalid=true]]:outline-[length:var(--outline-width-focus)] has-[[data-slot][aria-invalid=true]]:outline-offset-[var(--outline-offset-focus)] has-[[data-slot][aria-invalid=true]]:outline-destructive has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>textarea]:h-auto has-[>[data-align=block-end]]:[&>input]:pt-3 has-[>[data-align=block-start]]:[&>input]:pb-3 has-[>[data-align=inline-end]]:[&>input]:pr-1.5 has-[>[data-align=inline-start]]:[&>input]:pl-1.5 [@media(hover:hover)_and_(pointer:fine)]:min-h-0", className), ...props }));
9
+ return (_jsx("div", { "data-slot": "input-group", role: "group", className: cn("group/input-group relative flex h-control-height min-h-touch-target w-full min-w-0 items-center rounded-md border border-input bg-background transition-colors outline-none in-data-[slot=combobox-content]:focus-within:border-inherit has-disabled:bg-input/50 has-disabled:opacity-50 not-in-data-[slot=combobox-content]:has-[[data-slot=input-group-control]:focus-visible]:nc-focus-outline has-[[data-slot=input-group-control]:focus-visible]:outline-ring has-[[data-slot][aria-invalid=true]]:border-destructive has-[[data-slot][aria-invalid=true]]:nc-focus-outline has-[[data-slot][aria-invalid=true]]:outline-destructive has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>textarea]:h-auto has-[>[data-align=block-end]]:[&>input]:pt-3 has-[>[data-align=block-start]]:[&>input]:pb-3 has-[>[data-align=inline-end]]:[&>input]:pr-1.5 has-[>[data-align=inline-start]]:[&>input]:pl-1.5 [@media(hover:hover)_and_(pointer:fine)]:min-h-0", className), ...props }));
10
10
  }
11
11
  const inputGroupAddonVariants = cva("flex h-auto cursor-text items-center justify-center gap-2 py-1.5 text-sm font-medium text-muted-foreground select-none group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-4", {
12
12
  variants: {
@@ -16,12 +16,12 @@ function InputOTP({ className, containerClassName, ...props }) {
16
16
  suppressHydrationWarning: true }));
17
17
  }
18
18
  function InputOTPGroup({ className, ...props }) {
19
- return (_jsx("div", { "data-slot": "input-otp-group", className: cn("flex items-center rounded-md has-aria-invalid:border-destructive has-aria-invalid:outline has-aria-invalid:outline-[length:var(--outline-width-focus)] has-aria-invalid:outline-offset-[var(--outline-offset-focus)] has-aria-invalid:outline-destructive", className), ...props }));
19
+ return (_jsx("div", { "data-slot": "input-otp-group", className: cn("flex items-center rounded-md has-aria-invalid:border-destructive has-aria-invalid:nc-focus-outline has-aria-invalid:outline-destructive", className), ...props }));
20
20
  }
21
21
  function InputOTPSlot({ index, className, ...props }) {
22
22
  const inputOTPContext = React.useContext(OTPInputContext);
23
23
  const { char, hasFakeCaret, isActive } = inputOTPContext?.slots[index] ?? {};
24
- return (_jsxs("div", { "data-slot": "input-otp-slot", "data-active": isActive, className: cn("relative flex size-control-height min-h-touch-target min-w-touch-target items-center justify-center border-y border-r border-input bg-background text-sm transition-[border-color,color,opacity] duration-[var(--nc-duration-confirm)] ease-[var(--nc-ease-out-strong)] motion-reduce:transition-none outline-none first:rounded-l-md first:border-l last:rounded-r-md aria-invalid:border-destructive data-[active=true]:z-10 data-[active=true]:outline data-[active=true]:outline-[length:var(--outline-width-focus)] data-[active=true]:outline-offset-[var(--outline-offset-focus)] data-[active=true]:outline-ring data-[active=true]:aria-invalid:border-destructive data-[active=true]:aria-invalid:outline-destructive [@media(hover:hover)_and_(pointer:fine)]:min-h-0 [@media(hover:hover)_and_(pointer:fine)]:min-w-0", className), ...props, children: [char, hasFakeCaret && (_jsx("div", { className: "pointer-events-none absolute inset-0 flex items-center justify-center", children: _jsx("div", { className: "h-4 w-px bg-foreground motion-safe:animate-caret-blink motion-safe:duration-[var(--nc-duration-typing)]" }) }))] }));
24
+ return (_jsxs("div", { "data-slot": "input-otp-slot", "data-active": isActive, className: cn("relative flex size-control-height min-h-touch-target min-w-touch-target items-center justify-center border-y border-r border-input bg-background text-sm transition-[border-color,color,opacity] duration-[var(--nc-duration-confirm)] ease-[var(--nc-ease-out-strong)] motion-reduce:transition-none outline-none first:rounded-l-md first:border-l last:rounded-r-md aria-invalid:border-destructive data-[active=true]:z-10 data-[active=true]:nc-focus-outline data-[active=true]:outline-ring data-[active=true]:aria-invalid:border-destructive data-[active=true]:aria-invalid:outline-destructive [@media(hover:hover)_and_(pointer:fine)]:min-h-0 [@media(hover:hover)_and_(pointer:fine)]:min-w-0", className), ...props, children: [char, hasFakeCaret && (_jsx("div", { className: "pointer-events-none absolute inset-0 flex items-center justify-center", children: _jsx("div", { className: "h-4 w-px bg-foreground motion-safe:animate-caret-blink motion-safe:duration-[var(--nc-duration-typing)]" }) }))] }));
25
25
  }
26
26
  function InputOTPSeparator({ ...props }) {
27
27
  return (_jsx("div", { "data-slot": "input-otp-separator", className: "flex items-center [&_svg:not([class*='size-'])]:size-4", role: "separator", ...props, children: _jsx(MinusIcon, {}) }));
@@ -7,6 +7,6 @@ function Slider({ className, defaultValue, value, min = 0, max = 100, ...props }
7
7
  : Array.isArray(defaultValue)
8
8
  ? defaultValue
9
9
  : [min, max];
10
- return (_jsx(SliderPrimitive.Root, { className: cn("data-horizontal:w-full data-vertical:h-full", className), "data-slot": "slider", defaultValue: defaultValue, value: value, min: min, max: max, thumbAlignment: "edge", ...props, children: _jsxs(SliderPrimitive.Control, { className: "relative flex w-full touch-none items-center select-none data-disabled:opacity-50 data-vertical:h-full data-vertical:min-h-40 data-vertical:w-auto data-vertical:flex-col", children: [_jsx(SliderPrimitive.Track, { "data-slot": "slider-track", className: "relative grow overflow-hidden rounded-full bg-muted select-none data-horizontal:h-1 data-horizontal:w-full data-vertical:h-full data-vertical:w-1", children: _jsx(SliderPrimitive.Indicator, { "data-slot": "slider-range", className: "bg-primary select-none data-horizontal:h-full data-vertical:w-full" }) }), Array.from({ length: _values.length }, (_, index) => (_jsx(SliderPrimitive.Thumb, { "data-slot": "slider-thumb", className: "relative block size-3 shrink-0 rounded-full border border-input bg-background transition-colors select-none after:absolute after:top-1/2 after:left-1/2 after:size-touch-target after:-translate-x-1/2 after:-translate-y-1/2 hover:outline hover:outline-[length:var(--outline-width-focus)] hover:outline-offset-[var(--outline-offset-focus)] active:outline active:outline-[length:var(--outline-width-focus)] active:outline-offset-[var(--outline-offset-focus)] disabled:pointer-events-none disabled:opacity-50 [@media(hover:hover)_and_(pointer:fine)]:after:hidden" }, index)))] }) }));
10
+ return (_jsx(SliderPrimitive.Root, { className: cn("data-horizontal:w-full data-vertical:h-full", className), "data-slot": "slider", defaultValue: defaultValue, value: value, min: min, max: max, thumbAlignment: "edge", ...props, children: _jsxs(SliderPrimitive.Control, { className: "relative flex w-full touch-none items-center select-none data-disabled:opacity-50 data-vertical:h-full data-vertical:min-h-40 data-vertical:w-auto data-vertical:flex-col", children: [_jsx(SliderPrimitive.Track, { "data-slot": "slider-track", className: "relative grow overflow-hidden rounded-full bg-muted select-none data-horizontal:h-1 data-horizontal:w-full data-vertical:h-full data-vertical:w-1", children: _jsx(SliderPrimitive.Indicator, { "data-slot": "slider-range", className: "bg-primary select-none data-horizontal:h-full data-vertical:w-full" }) }), Array.from({ length: _values.length }, (_, index) => (_jsx(SliderPrimitive.Thumb, { "data-slot": "slider-thumb", className: "relative block size-3 shrink-0 rounded-full border border-input bg-background transition-colors select-none after:absolute after:top-1/2 after:left-1/2 after:size-touch-target after:-translate-x-1/2 after:-translate-y-1/2 hover:nc-focus-outline active:nc-focus-outline disabled:pointer-events-none disabled:opacity-50 [@media(hover:hover)_and_(pointer:fine)]:after:hidden" }, index)))] }) }));
11
11
  }
12
12
  export { Slider };
@@ -10,15 +10,16 @@ import { classUtilities } from "./jsx-class-utility.js";
10
10
  * the canonical outline".
11
11
  *
12
12
  * A focus-variant utility may only suppress the outline (outline-none,
13
- * outline-hidden), restate the canonical treatment on a proxy target (the
14
- * outline style/width/offset tokens plus the ring-role colors, as input-group
15
- * does when the group carries the indicator for its inner control), or move
16
- * non-paint properties (z-index, colors of the element itself, …).
13
+ * outline-hidden), restate the canonical treatment on a proxy target through
14
+ * the one shared `nc-focus-outline` utility plus a ring-role color (as
15
+ * input-group does when the group carries the indicator for its inner
16
+ * control), or move non-paint properties (z-index, colors of the element
17
+ * itself, …). Restating the style, width, and offset as separate utilities is
18
+ * a fork of that owner, so the raw outline width belongs to nobody.
17
19
  */
18
20
  const RING_BASE = /^-?ring(?:-|$)/;
19
- const ALLOWED_OUTLINE_BASE = new Set(["outline", "outline-none", "outline-hidden"]);
21
+ const ALLOWED_OUTLINE_BASE = new Set(["nc-focus-outline", "outline-none", "outline-hidden"]);
20
22
  const ALLOWED_OUTLINE_COLOR = /^outline-(?:ring|sidebar-ring)$/;
21
- const OUTLINE_TOKEN_LENGTH = /^outline-\[length:var\(--outline-width-focus\)\]$/;
22
23
  const OUTLINE_OFFSET = /^-?outline-offset-/;
23
24
 
24
25
  function baseOf(utility) {
@@ -39,15 +40,9 @@ function repaintedFocus(utility) {
39
40
  if (base === utility) return undefined;
40
41
  if (RING_BASE.test(base)) return "boxShadowFocus";
41
42
  if (base.startsWith("[outline")) return "customFocusOutline";
43
+ if (ALLOWED_OUTLINE_BASE.has(base)) return undefined;
42
44
  if (!base.startsWith("outline")) return undefined;
43
- if (
44
- ALLOWED_OUTLINE_BASE.has(base) ||
45
- ALLOWED_OUTLINE_COLOR.test(base) ||
46
- OUTLINE_TOKEN_LENGTH.test(base) ||
47
- OUTLINE_OFFSET.test(base)
48
- ) {
49
- return undefined;
50
- }
45
+ if (ALLOWED_OUTLINE_COLOR.test(base) || OUTLINE_OFFSET.test(base)) return undefined;
51
46
  return "customFocusOutline";
52
47
  }
53
48
 
@@ -63,7 +58,7 @@ export const noRepaintedFocus = {
63
58
  boxShadowFocus:
64
59
  "Focus never paints a box-shadow: the base layer draws the offset outline. Drop {{utility}}.",
65
60
  customFocusOutline:
66
- "{{utility}} repaints focus with its own width or hue. The base layer owns the focus outline; a proxy target restates only the canonical tokens.",
61
+ "{{utility}} repaints focus with its own width or hue. The base layer owns the focus outline; a proxy target takes nc-focus-outline plus a ring-role color.",
67
62
  },
68
63
  },
69
64
  create(context) {
@@ -92,6 +92,22 @@
92
92
  }
93
93
  }
94
94
 
95
+ /*
96
+ * The proxy focus outline: the one restatement of the canonical treatment
97
+ * above, for an element that carries the indicator on another element's
98
+ * behalf (the input group around its control, the OTP slot for the hidden
99
+ * input, the chart wrapper for its svg, the slider thumb). The call site adds
100
+ * the hue with outline-ring or outline-destructive and nothing else.
101
+ * Declared as a utility so variant prefixes can gate it, and so the style is
102
+ * literally `solid` rather than Tailwind's `--tw-outline-style`, which any
103
+ * outline-none or outline-hidden on the same element sets to `none` for good.
104
+ */
105
+ @utility nc-focus-outline {
106
+ outline-style: solid;
107
+ outline-width: var(--outline-width-focus);
108
+ outline-offset: var(--outline-offset-focus);
109
+ }
110
+
95
111
  @layer components {
96
112
  .nc-toast {
97
113
  border: 0 !important;
package/docs/contract.md CHANGED
@@ -39,7 +39,12 @@ with a box-shadow ring, a raw width, or its own hue
39
39
  (`nadicodeai/no-repainted-focus` enforces this). A component may only
40
40
  suppress the outline where a proxy target carries it (`InputGroup` shows the
41
41
  indicator for its inner control; the OTP active slot for its hidden input) or
42
- where a highlight ground replaces it (menu and command items).
42
+ where a highlight ground replaces it (menu and command items). The proxy
43
+ target draws it with `nc-focus-outline`, the one utility that carries the
44
+ outline's style, width, and offset, plus a ring-role color utility. Nothing
45
+ restates those three as separate utilities: an `outline-none` or
46
+ `outline-hidden` on the same element leaves Tailwind's own outline utilities
47
+ painting nothing.
43
48
 
44
49
  `nc-glass` is the one glass material, and glass is floating chrome: menu,
45
50
  popover, select, combobox, and navigation-menu popups, the command palette,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nadicodeai/ui",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -63,7 +63,7 @@
63
63
  "@assistant-ui/react": "0.15.1",
64
64
  "@assistant-ui/react-markdown": "0.14.8",
65
65
  "@base-ui/react": "^1.6.0",
66
- "@nadicodeai/design-system": "1.1.0",
66
+ "@nadicodeai/design-system": "1.1.1",
67
67
  "@paper-design/shaders": "0.0.78",
68
68
  "class-variance-authority": "^0.7.1",
69
69
  "clsx": "^2.1.1",