@nsaa/core 0.1.0-alpha.2 → 0.1.0-alpha.4

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.
Files changed (72) hide show
  1. package/LICENSE +1 -1
  2. package/NOTICE +27 -0
  3. package/README.md +30 -8
  4. package/dist/_virtual/_rolldown/runtime.js +13 -0
  5. package/dist/alert/alert.d.ts +30 -5
  6. package/dist/alert/alert.js +201 -15
  7. package/dist/alert/index.d.ts +2 -2
  8. package/dist/alert-dialog/alert-dialog.js +13 -7
  9. package/dist/badge/badge.d.ts +2 -2
  10. package/dist/badge/badge.js +1 -1
  11. package/dist/button/button.d.ts +2 -2
  12. package/dist/button/button.js +1 -1
  13. package/dist/dialog/dialog.js +13 -7
  14. package/dist/empty/empty.d.ts +1 -1
  15. package/dist/empty/empty.js +2 -2
  16. package/dist/index.d.ts +4 -3
  17. package/dist/index.js +3 -2
  18. package/dist/input-group/input-group.d.ts +1 -1
  19. package/dist/input-otp/input-otp.js +1 -1
  20. package/dist/lib/opener.js +29 -0
  21. package/dist/sound/lazy-uisfx.d.ts +20 -0
  22. package/dist/sound/lazy-uisfx.js +68 -0
  23. package/dist/sound/sound-map.d.ts +2 -0
  24. package/dist/sound/sound-map.js +5 -1
  25. package/dist/sound/uisfx.d.ts +5 -1
  26. package/dist/sources/accordion.css +3 -0
  27. package/dist/sources/alert-dialog.css +26 -0
  28. package/dist/sources/alert.css +28 -0
  29. package/dist/sources/avatar.css +3 -0
  30. package/dist/sources/badge.css +3 -0
  31. package/dist/sources/button.css +24 -0
  32. package/dist/sources/calendar.css +25 -0
  33. package/dist/sources/card.css +3 -0
  34. package/dist/sources/checkbox.css +6 -0
  35. package/dist/sources/collapsible.css +2 -0
  36. package/dist/sources/combobox.css +28 -0
  37. package/dist/sources/command.css +30 -0
  38. package/dist/sources/context-menu.css +6 -0
  39. package/dist/sources/dialog.css +26 -0
  40. package/dist/sources/drawer.css +6 -0
  41. package/dist/sources/dropdown-menu.css +6 -0
  42. package/dist/sources/empty.css +3 -0
  43. package/dist/sources/field.css +5 -0
  44. package/dist/sources/input-group.css +27 -0
  45. package/dist/sources/input-otp.css +8 -0
  46. package/dist/sources/input.css +3 -0
  47. package/dist/sources/kbd.css +3 -0
  48. package/dist/sources/label.css +3 -0
  49. package/dist/sources/loaders-text.css +8 -0
  50. package/dist/sources/loaders.css +40 -0
  51. package/dist/sources/native-select.css +3 -0
  52. package/dist/sources/pagination.css +25 -0
  53. package/dist/sources/popover.css +3 -0
  54. package/dist/sources/radio-group.css +6 -0
  55. package/dist/sources/select.css +6 -0
  56. package/dist/sources/separator.css +3 -0
  57. package/dist/sources/skeleton.css +3 -0
  58. package/dist/sources/slider.css +6 -0
  59. package/dist/sources/spinner.css +20 -0
  60. package/dist/sources/switch.css +6 -0
  61. package/dist/sources/table.css +3 -0
  62. package/dist/sources/tabs.css +3 -0
  63. package/dist/sources/textarea.css +3 -0
  64. package/dist/sources/toast.css +25 -0
  65. package/dist/sources/toggle-group.css +32 -0
  66. package/dist/sources/toolbar.css +34 -0
  67. package/dist/sources/tooltip.css +3 -0
  68. package/dist/toolbar/toolbar.js +1 -1
  69. package/package.json +10 -4
  70. package/src/feel.css +80 -1
  71. package/src/styles-base.css +142 -0
  72. package/src/styles.css +3 -133
@@ -0,0 +1,6 @@
1
+ /* @nsaa/core: Tailwind sources for radio-group (generated). */
2
+ @source "../lib/cn.js";
3
+ @source "../radio-group/radio-group.js";
4
+ @source "../sound/sound-map.js";
5
+ @source "../sound/sound.js";
6
+ @source "../tokens/dist/motion.js";
@@ -0,0 +1,6 @@
1
+ /* @nsaa/core: Tailwind sources for select (generated). */
2
+ @source "../lib/cn.js";
3
+ @source "../select/select.js";
4
+ @source "../sound/sound-map.js";
5
+ @source "../sound/sound.js";
6
+ @source "../tokens/dist/motion.js";
@@ -0,0 +1,3 @@
1
+ /* @nsaa/core: Tailwind sources for separator (generated). */
2
+ @source "../lib/cn.js";
3
+ @source "../separator/separator.js";
@@ -0,0 +1,3 @@
1
+ /* @nsaa/core: Tailwind sources for skeleton (generated). */
2
+ @source "../lib/cn.js";
3
+ @source "../skeleton/skeleton.js";
@@ -0,0 +1,6 @@
1
+ /* @nsaa/core: Tailwind sources for slider (generated). */
2
+ @source "../lib/cn.js";
3
+ @source "../slider/slider.js";
4
+ @source "../sound/sound-map.js";
5
+ @source "../sound/sound.js";
6
+ @source "../tokens/dist/motion.js";
@@ -0,0 +1,20 @@
1
+ /* @nsaa/core: Tailwind sources for spinner (generated). */
2
+ @source "../lib/cn.js";
3
+ @source "../loaders/arc.js";
4
+ @source "../loaders/bouncing-dots.js";
5
+ @source "../loaders/cap.js";
6
+ @source "../loaders/circular-dots.js";
7
+ @source "../loaders/classic.js";
8
+ @source "../loaders/easing.js";
9
+ @source "../loaders/fade.js";
10
+ @source "../loaders/frame.js";
11
+ @source "../loaders/motion.js";
12
+ @source "../loaders/orbit.js";
13
+ @source "../loaders/pulse.js";
14
+ @source "../loaders/ring.js";
15
+ @source "../loaders/wave.js";
16
+ @source "../sound/sound.js";
17
+ @source "../spinner/loader-provider.js";
18
+ @source "../spinner/registry.js";
19
+ @source "../spinner/spinner.js";
20
+ @source "../tokens/dist/motion.js";
@@ -0,0 +1,6 @@
1
+ /* @nsaa/core: Tailwind sources for switch (generated). */
2
+ @source "../lib/cn.js";
3
+ @source "../sound/sound-map.js";
4
+ @source "../sound/sound.js";
5
+ @source "../switch/switch.js";
6
+ @source "../tokens/dist/motion.js";
@@ -0,0 +1,3 @@
1
+ /* @nsaa/core: Tailwind sources for table (generated). */
2
+ @source "../lib/cn.js";
3
+ @source "../table/table.js";
@@ -0,0 +1,3 @@
1
+ /* @nsaa/core: Tailwind sources for tabs (generated). */
2
+ @source "../lib/cn.js";
3
+ @source "../tabs/tabs.js";
@@ -0,0 +1,3 @@
1
+ /* @nsaa/core: Tailwind sources for textarea (generated). */
2
+ @source "../lib/cn.js";
3
+ @source "../textarea/textarea.js";
@@ -0,0 +1,25 @@
1
+ /* @nsaa/core: Tailwind sources for toast (generated). */
2
+ @source "../button/button.js";
3
+ @source "../lib/cn.js";
4
+ @source "../lib/control-defaults.js";
5
+ @source "../lib/use-press.js";
6
+ @source "../loaders/arc.js";
7
+ @source "../loaders/bouncing-dots.js";
8
+ @source "../loaders/cap.js";
9
+ @source "../loaders/circular-dots.js";
10
+ @source "../loaders/classic.js";
11
+ @source "../loaders/easing.js";
12
+ @source "../loaders/fade.js";
13
+ @source "../loaders/frame.js";
14
+ @source "../loaders/motion.js";
15
+ @source "../loaders/orbit.js";
16
+ @source "../loaders/pulse.js";
17
+ @source "../loaders/ring.js";
18
+ @source "../loaders/wave.js";
19
+ @source "../sound/sound-map.js";
20
+ @source "../sound/sound.js";
21
+ @source "../spinner/loader-provider.js";
22
+ @source "../spinner/registry.js";
23
+ @source "../spinner/spinner.js";
24
+ @source "../toast/toast.js";
25
+ @source "../tokens/dist/motion.js";
@@ -0,0 +1,32 @@
1
+ /* @nsaa/core: Tailwind sources for toggle-group (generated). */
2
+ @source "../button/button.js";
3
+ @source "../dropdown-menu/dropdown-menu.js";
4
+ @source "../kbd/kbd.js";
5
+ @source "../lib/cn.js";
6
+ @source "../lib/control-defaults.js";
7
+ @source "../lib/shortcut.js";
8
+ @source "../lib/tv.js";
9
+ @source "../lib/use-press.js";
10
+ @source "../loaders/arc.js";
11
+ @source "../loaders/bouncing-dots.js";
12
+ @source "../loaders/cap.js";
13
+ @source "../loaders/circular-dots.js";
14
+ @source "../loaders/classic.js";
15
+ @source "../loaders/easing.js";
16
+ @source "../loaders/fade.js";
17
+ @source "../loaders/frame.js";
18
+ @source "../loaders/motion.js";
19
+ @source "../loaders/orbit.js";
20
+ @source "../loaders/pulse.js";
21
+ @source "../loaders/ring.js";
22
+ @source "../loaders/wave.js";
23
+ @source "../sound/sound-map.js";
24
+ @source "../sound/sound.js";
25
+ @source "../spinner/loader-provider.js";
26
+ @source "../spinner/registry.js";
27
+ @source "../spinner/spinner.js";
28
+ @source "../toggle-group/toggle-group.js";
29
+ @source "../tokens/dist/motion.js";
30
+ @source "../toolbar/overflow.js";
31
+ @source "../toolbar/toolbar-item.js";
32
+ @source "../tooltip/tooltip.js";
@@ -0,0 +1,34 @@
1
+ /* @nsaa/core: Tailwind sources for toolbar (generated). */
2
+ @source "../button/button.js";
3
+ @source "../dropdown-menu/dropdown-menu.js";
4
+ @source "../input/input.js";
5
+ @source "../kbd/kbd.js";
6
+ @source "../lib/cn.js";
7
+ @source "../lib/control-defaults.js";
8
+ @source "../lib/merge-refs.js";
9
+ @source "../lib/shortcut.js";
10
+ @source "../lib/tv.js";
11
+ @source "../lib/use-press.js";
12
+ @source "../loaders/arc.js";
13
+ @source "../loaders/bouncing-dots.js";
14
+ @source "../loaders/cap.js";
15
+ @source "../loaders/circular-dots.js";
16
+ @source "../loaders/classic.js";
17
+ @source "../loaders/easing.js";
18
+ @source "../loaders/fade.js";
19
+ @source "../loaders/frame.js";
20
+ @source "../loaders/motion.js";
21
+ @source "../loaders/orbit.js";
22
+ @source "../loaders/pulse.js";
23
+ @source "../loaders/ring.js";
24
+ @source "../loaders/wave.js";
25
+ @source "../sound/sound-map.js";
26
+ @source "../sound/sound.js";
27
+ @source "../spinner/loader-provider.js";
28
+ @source "../spinner/registry.js";
29
+ @source "../spinner/spinner.js";
30
+ @source "../tokens/dist/motion.js";
31
+ @source "../toolbar/overflow.js";
32
+ @source "../toolbar/toolbar-item.js";
33
+ @source "../toolbar/toolbar.js";
34
+ @source "../tooltip/tooltip.js";
@@ -0,0 +1,3 @@
1
+ /* @nsaa/core: Tailwind sources for tooltip (generated). */
2
+ @source "../lib/cn.js";
3
+ @source "../tooltip/tooltip.js";
@@ -2,6 +2,7 @@
2
2
  import { cn } from "../lib/cn.js";
3
3
  import { ControlDefaultsContext, useControlDefaults } from "../lib/control-defaults.js";
4
4
  import { buttonVariants } from "../button/button.js";
5
+ import { mergeRefs } from "../lib/merge-refs.js";
5
6
  import { Input } from "../input/input.js";
6
7
  import { DropdownMenuCheckboxItem, DropdownMenuItem, DropdownMenuShortcut } from "../dropdown-menu/dropdown-menu.js";
7
8
  import { tv } from "../lib/tv.js";
@@ -9,7 +10,6 @@ import { ariaShortcut, formatShortcut } from "../lib/shortcut.js";
9
10
  import { TooltipProvider } from "../tooltip/tooltip.js";
10
11
  import { ToolbarItem } from "./toolbar-item.js";
11
12
  import { OverflowContext, OverflowMore, OverflowStore, useOverflowUnit } from "./overflow.js";
12
- import { mergeRefs } from "../lib/merge-refs.js";
13
13
  import { jsx, jsxs } from "react/jsx-runtime";
14
14
  import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
15
15
  import { Toolbar } from "@base-ui/react/toolbar";
package/package.json CHANGED
@@ -1,17 +1,21 @@
1
1
  {
2
2
  "name": "@nsaa/core",
3
- "version": "0.1.0-alpha.2",
3
+ "version": "0.1.0-alpha.4",
4
4
  "description": "Nsaa core components: accessible, token-driven, animated to the Nsaa feel spec.",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "sideEffects": [
8
8
  "**/*.css",
9
+ "./dist/index.js",
10
+ "./src/index.ts",
9
11
  "./dist/lib/track-input-modality.js",
12
+ "./src/lib/track-input-modality.ts",
10
13
  "./dist/spinner/spinner.js"
11
14
  ],
12
15
  "files": [
13
16
  "dist",
14
17
  "src/styles.css",
18
+ "src/styles-base.css",
15
19
  "src/feel.css",
16
20
  "README.md",
17
21
  "LICENSE",
@@ -34,7 +38,9 @@
34
38
  "types": "./dist/sound-uisfx.d.ts",
35
39
  "import": "./dist/sound-uisfx.js"
36
40
  },
37
- "./styles.css": "./src/styles.css"
41
+ "./styles.css": "./src/styles.css",
42
+ "./styles-base.css": "./src/styles-base.css",
43
+ "./sources/*": "./dist/sources/*"
38
44
  },
39
45
  "dependencies": {
40
46
  "@base-ui/react": "^1.9.0",
@@ -47,7 +53,7 @@
47
53
  "tailwind-merge": "^3.7.0",
48
54
  "tailwind-variants": "^3.3.1",
49
55
  "uisfx": "0.4.0",
50
- "@nsaa/tokens": "^0.1.0-alpha.2"
56
+ "@nsaa/tokens": "^0.1.0-alpha.4"
51
57
  },
52
58
  "devDependencies": {
53
59
  "@testing-library/jest-dom": "^7.0.1",
@@ -78,7 +84,7 @@
78
84
  "access": "public"
79
85
  },
80
86
  "scripts": {
81
- "build": "tsdown",
87
+ "build": "tsdown && node ../../scripts/core-sources.mjs",
82
88
  "dev": "tsdown --watch",
83
89
  "typecheck": "tsc --noEmit",
84
90
  "test": "vitest run",
package/src/feel.css CHANGED
@@ -19,6 +19,69 @@
19
19
  * own unlayered CSS still wins.
20
20
  */
21
21
 
22
+ /* ------------------------------------------------------------------ coarse-pointer hit areas (#144)
23
+ DESIGN.md: 44 px targets on coarse pointers. An invisible ::before, centred, at least 44 × 44 and
24
+ never smaller than the control; layout is unchanged. ::before because base-nova already uses
25
+ ::after (Tabs' line indicator, the Checkbox / Radio / Switch / Slider thumb hit expanders).
26
+ Tailwind's components layer, below utilities: the `position: relative` here never overrides a
27
+ control's own `absolute` (the Dialog close) or a Toolbar / Toggle Group override.
28
+ Inputs are replaced elements and take no pseudo-element, so on a coarse pointer they grow to
29
+ 44 px tall instead; an Input Group grows as a whole. */
30
+ @layer components {
31
+ @media (pointer: coarse) {
32
+ :is(
33
+ .group\/button,
34
+ [data-slot="select-trigger"],
35
+ [data-slot="checkbox"],
36
+ [data-slot="radio-group-item"],
37
+ [data-slot="switch"],
38
+ [data-slot="slider-thumb"],
39
+ [data-slot="tabs-trigger"]
40
+ ) {
41
+ position: relative;
42
+
43
+ &::before {
44
+ content: "";
45
+ position: absolute;
46
+ top: 50%;
47
+ left: 50%;
48
+ width: 100%;
49
+ height: 100%;
50
+ min-width: calc(var(--spacing) * 11);
51
+ min-height: calc(var(--spacing) * 11);
52
+ translate: -50% -50%;
53
+ }
54
+ }
55
+
56
+ /* Alert links (#148): 44 px tall, their own width (the AlertLinks gap keeps them apart);
57
+ ::after, as ::before draws the separator. */
58
+ [data-slot="alert-link"]::after {
59
+ content: "";
60
+ position: absolute;
61
+ inset-inline: 0;
62
+ top: 50%;
63
+ height: calc(var(--spacing) * 11);
64
+ translate: 0 -50%;
65
+ }
66
+
67
+ :is([data-slot="input"], [data-slot="input-group"]) {
68
+ min-height: calc(var(--spacing) * 11);
69
+ }
70
+
71
+ /* Neighbours closer than 44 px would share a hit area. Pagination links sit 2 px apart, so
72
+ along the row they keep their own width. Calendar days tile the grid edge to edge (every
73
+ point is some day's), so a day's hit area is its cell; the month arrows keep 44 px.
74
+ Toolbar and Toggle Group do the same along their axis (#75). */
75
+ [data-slot="pagination-content"] .group\/button::before {
76
+ min-width: 0;
77
+ }
78
+ [data-slot="calendar"] button[data-day]::before {
79
+ min-width: 0;
80
+ min-height: 0;
81
+ }
82
+ }
83
+ }
84
+
22
85
  @layer nsaa-feel {
23
86
  :root {
24
87
  --nsaa-time-scale: 1;
@@ -409,6 +472,13 @@
409
472
  }
410
473
  }
411
474
 
475
+ /* Dismiss (#148): opacity only, duration.fast, then it unmounts. No height animation (not a
476
+ named layout exception); instant under reduced motion and after keyboard input. */
477
+ [data-slot="alert"][data-ending-style] {
478
+ opacity: 0;
479
+ transition-duration: calc(var(--nsaa-duration-fast) * var(--nsaa-time-scale));
480
+ }
481
+
412
482
  /* ---------------------------------------------------------------- Avatar, Skeleton, Spinner
413
483
  A loaded image fades in 150; Skeleton keeps its pulse; Spinner turns at duration.spin. */
414
484
  /* SkeletonContent: what replaces a Skeleton fades in the same way (#128). */
@@ -658,6 +728,10 @@
658
728
  }
659
729
  }
660
730
 
731
+ & [data-slot="alert"][data-ending-style] {
732
+ transition-duration: 0s;
733
+ }
734
+
661
735
  & :is([data-slot="skeleton"], [data-loader="lucide"]) {
662
736
  animation: none;
663
737
  }
@@ -822,6 +896,10 @@
822
896
  }
823
897
  }
824
898
 
899
+ & [data-slot="alert"][data-ending-style] {
900
+ transition-duration: 0s;
901
+ }
902
+
825
903
  & :is([data-slot="skeleton"], [data-loader="lucide"]) {
826
904
  animation: none;
827
905
  }
@@ -881,7 +959,8 @@
881
959
  [data-slot="drawer-overlay"],
882
960
  [data-slot="accordion-content"],
883
961
  [data-slot="collapsible-content"],
884
- [data-slot="skeleton-content"]
962
+ [data-slot="skeleton-content"],
963
+ [data-slot="alert"][data-ending-style]
885
964
  ) {
886
965
  transition-duration: 0s;
887
966
  }
@@ -0,0 +1,142 @@
1
+ /*
2
+ * @nsaa/core styles without Tailwind sources (#144): tokens, the feel layer and the variants.
3
+ * For the smallest CSS, import this plus one sources file per component you use:
4
+ * @import "tailwindcss";
5
+ * @import "@nsaa/core/styles-base.css";
6
+ * @import "@nsaa/core/sources/button.css";
7
+ * @import "@nsaa/core/sources/dialog.css";
8
+ * `styles.css` is this file plus every component's sources.
9
+ */
10
+ @import "@nsaa/tokens/css";
11
+
12
+ /* The feel layer (#108): motion for the base-nova components, keyed to data-slot. */
13
+ @import "./feel.css";
14
+
15
+ /* `dark:` follows the mode axis (`.dark` or `data-mode="dark"` on an ancestor), not the OS, so the
16
+ shadcn classes (#84) switch with the rest of the tokens. The nearest mode wins (#120): a light
17
+ panel inside a dark page is light, and a dark panel inside that light panel is dark again. */
18
+ @custom-variant dark (
19
+ &:where(
20
+ .dark,
21
+ [data-mode="dark"],
22
+ :is(.dark, [data-mode="dark"]) *:not([data-mode="light"], [data-mode="light"] *),
23
+ [data-mode="light"] [data-mode="dark"] *
24
+ )
25
+ );
26
+
27
+ /* shadcn's base layer (apps/v4 globals.css, `* { @apply border-border }`): a bare `border` class takes
28
+ the border token, not currentColor. Dialog's footer and the Drawer's edge rely on it (#84). */
29
+ @layer base {
30
+ *,
31
+ ::after,
32
+ ::before {
33
+ border-color: var(--border);
34
+ }
35
+ }
36
+
37
+ /* shadcn's orientation variants (shadcn/tailwind.css, which the shadcn CLI imports for its users).
38
+ Base UI sets `data-orientation`, not `data-horizontal`; Tabs, Separator and Field use these (#84).
39
+ shadcn's other data-* variants match Base UI's attributes as Tailwind's defaults already. */
40
+ @custom-variant data-horizontal {
41
+ &:where([data-orientation="horizontal"]) {
42
+ @slot;
43
+ }
44
+ }
45
+
46
+ @custom-variant data-vertical {
47
+ &:where([data-orientation="vertical"]) {
48
+ @slot;
49
+ }
50
+ }
51
+
52
+ /* shadcn's `data-selected` (same file): only `data-selected="true"`. cmdk writes "true" / "false", so
53
+ Tailwind's default (attribute present) would highlight every Command item (#84). */
54
+ @custom-variant data-selected {
55
+ &:where([data-selected="true"]) {
56
+ @slot;
57
+ }
58
+ }
59
+
60
+ /* shadcn style hooks: `cn-rtl-flip` marks icons the shadcn CLI mirrors for right-to-left (the submenu
61
+ chevrons); `cn-input-otp` and two `cn-calendar-*` classes are styled by base-nova's style sheet, not
62
+ by the item's classes. */
63
+ @layer components {
64
+ .cn-rtl-flip:where(:dir(rtl)) {
65
+ rotate: 180deg;
66
+ }
67
+
68
+ /* Input OTP's root: shadcn's style-nova.css gives `cn-input-otp` a `gap-2` between the groups. */
69
+ .cn-input-otp {
70
+ gap: calc(var(--spacing) * 2);
71
+ }
72
+
73
+ /* Calendar with captionLayout="dropdown" (#136): style-nova.css draws the month and year
74
+ dropdowns' border and focus ring, and pads the caption label; the item's classes don't. */
75
+ .cn-calendar-dropdown-root {
76
+ border: 1px solid var(--input);
77
+
78
+ &:has(:focus) {
79
+ border-color: var(--ring);
80
+ box-shadow: 0 0 0 3px color-mix(in oklab, var(--ring) 50%, transparent);
81
+ }
82
+ }
83
+
84
+ .cn-calendar-caption-label {
85
+ height: calc(var(--spacing) * 6);
86
+ padding-right: calc(var(--spacing) * 1);
87
+ padding-left: calc(var(--spacing) * 1.5);
88
+ }
89
+ }
90
+
91
+ /* Hover only where hovering is real (fine pointers), never on disabled, busy or read-only controls. */
92
+ @custom-variant hover-fine {
93
+ @media (hover: hover) and (pointer: fine) {
94
+ &:hover:not([data-disabled], [data-loading], [data-readonly]) {
95
+ @slot;
96
+ }
97
+ }
98
+ }
99
+
100
+ /* Pressed look, never on disabled or busy controls. */
101
+ @custom-variant pressed {
102
+ &:active:not([data-disabled], [data-loading]) {
103
+ @slot;
104
+ }
105
+ }
106
+
107
+ /* shadcn's `no-scrollbar` (apps/v4 globals.css), used by the Combobox list (#84). `cn-menu-target`
108
+ and `cn-menu-translucent` on Select and Combobox popups are inert markers the shadcn CLI keeps for
109
+ its optional translucent-menu setting; nothing styles them by default, so neither do we. */
110
+ @utility no-scrollbar {
111
+ -ms-overflow-style: none;
112
+ scrollbar-width: none;
113
+
114
+ &::-webkit-scrollbar {
115
+ display: none;
116
+ }
117
+ }
118
+
119
+ /* Input OTP's fake caret (`animate-caret-blink`, #84). shadcn's apps/v4 globals.css defines it; the
120
+ base-nova registry item doesn't ship it, so core does (and the `input-otp` registry item adds it).
121
+ One blink is `duration.caret` (1.25 s, as shadcn's; #125). Under reduced motion the caret stays solid. */
122
+ @theme {
123
+ --animate-caret-blink: caret-blink var(--nsaa-duration-caret) ease-out infinite;
124
+
125
+ @keyframes caret-blink {
126
+ 0%,
127
+ 70%,
128
+ 100% {
129
+ opacity: 1;
130
+ }
131
+ 20%,
132
+ 50% {
133
+ opacity: 0;
134
+ }
135
+ }
136
+ }
137
+
138
+ @media (prefers-reduced-motion: reduce) {
139
+ .animate-caret-blink {
140
+ animation: none;
141
+ }
142
+ }
package/src/styles.css CHANGED
@@ -3,139 +3,9 @@
3
3
  * @import "tailwindcss";
4
4
  * @import "@nsaa/core/styles.css";
5
5
  */
6
- @import "@nsaa/tokens/css";
7
6
 
8
- /* The feel layer (#108): motion for the base-nova components, keyed to data-slot. */
9
- @import "./feel.css";
7
+ @import "./styles-base.css";
10
8
 
11
- /* Let Tailwind see the class names used by the built components. */
9
+ /* Let Tailwind see the class names used by every built component. For less CSS, import
10
+ styles-base.css and the sources of the components you use instead (see that file). */
12
11
  @source "../dist";
13
-
14
- /* `dark:` follows the mode axis (`.dark` or `data-mode="dark"` on an ancestor), not the OS, so the
15
- shadcn classes (#84) switch with the rest of the tokens. The nearest mode wins (#120): a light
16
- panel inside a dark page is light, and a dark panel inside that light panel is dark again. */
17
- @custom-variant dark (
18
- &:where(
19
- .dark,
20
- [data-mode="dark"],
21
- :is(.dark, [data-mode="dark"]) *:not([data-mode="light"], [data-mode="light"] *),
22
- [data-mode="light"] [data-mode="dark"] *
23
- )
24
- );
25
-
26
- /* shadcn's base layer (apps/v4 globals.css, `* { @apply border-border }`): a bare `border` class takes
27
- the border token, not currentColor. Dialog's footer and the Drawer's edge rely on it (#84). */
28
- @layer base {
29
- *,
30
- ::after,
31
- ::before {
32
- border-color: var(--border);
33
- }
34
- }
35
-
36
- /* shadcn's orientation variants (shadcn/tailwind.css, which the shadcn CLI imports for its users).
37
- Base UI sets `data-orientation`, not `data-horizontal`; Tabs, Separator and Field use these (#84).
38
- shadcn's other data-* variants match Base UI's attributes as Tailwind's defaults already. */
39
- @custom-variant data-horizontal {
40
- &:where([data-orientation="horizontal"]) {
41
- @slot;
42
- }
43
- }
44
-
45
- @custom-variant data-vertical {
46
- &:where([data-orientation="vertical"]) {
47
- @slot;
48
- }
49
- }
50
-
51
- /* shadcn's `data-selected` (same file): only `data-selected="true"`. cmdk writes "true" / "false", so
52
- Tailwind's default (attribute present) would highlight every Command item (#84). */
53
- @custom-variant data-selected {
54
- &:where([data-selected="true"]) {
55
- @slot;
56
- }
57
- }
58
-
59
- /* shadcn style hooks: `cn-rtl-flip` marks icons the shadcn CLI mirrors for right-to-left (the submenu
60
- chevrons); `cn-input-otp` and two `cn-calendar-*` classes are styled by base-nova's style sheet, not
61
- by the item's classes. */
62
- @layer components {
63
- .cn-rtl-flip:where(:dir(rtl)) {
64
- rotate: 180deg;
65
- }
66
-
67
- /* Input OTP's root: shadcn's style-nova.css gives `cn-input-otp` a `gap-2` between the groups. */
68
- .cn-input-otp {
69
- gap: calc(var(--spacing) * 2);
70
- }
71
-
72
- /* Calendar with captionLayout="dropdown" (#136): style-nova.css draws the month and year
73
- dropdowns' border and focus ring, and pads the caption label; the item's classes don't. */
74
- .cn-calendar-dropdown-root {
75
- border: 1px solid var(--input);
76
-
77
- &:has(:focus) {
78
- border-color: var(--ring);
79
- box-shadow: 0 0 0 3px color-mix(in oklab, var(--ring) 50%, transparent);
80
- }
81
- }
82
-
83
- .cn-calendar-caption-label {
84
- height: calc(var(--spacing) * 6);
85
- padding-right: calc(var(--spacing) * 1);
86
- padding-left: calc(var(--spacing) * 1.5);
87
- }
88
- }
89
-
90
- /* Hover only where hovering is real (fine pointers), never on disabled, busy or read-only controls. */
91
- @custom-variant hover-fine {
92
- @media (hover: hover) and (pointer: fine) {
93
- &:hover:not([data-disabled], [data-loading], [data-readonly]) {
94
- @slot;
95
- }
96
- }
97
- }
98
-
99
- /* Pressed look, never on disabled or busy controls. */
100
- @custom-variant pressed {
101
- &:active:not([data-disabled], [data-loading]) {
102
- @slot;
103
- }
104
- }
105
-
106
- /* shadcn's `no-scrollbar` (apps/v4 globals.css), used by the Combobox list (#84). `cn-menu-target`
107
- and `cn-menu-translucent` on Select and Combobox popups are inert markers the shadcn CLI keeps for
108
- its optional translucent-menu setting; nothing styles them by default, so neither do we. */
109
- @utility no-scrollbar {
110
- -ms-overflow-style: none;
111
- scrollbar-width: none;
112
-
113
- &::-webkit-scrollbar {
114
- display: none;
115
- }
116
- }
117
-
118
- /* Input OTP's fake caret (`animate-caret-blink`, #84). shadcn's apps/v4 globals.css defines it; the
119
- base-nova registry item doesn't ship it, so core does (and the `input-otp` registry item adds it).
120
- One blink is `duration.caret` (1.25 s, as shadcn's; #125). Under reduced motion the caret stays solid. */
121
- @theme {
122
- --animate-caret-blink: caret-blink var(--nsaa-duration-caret) ease-out infinite;
123
-
124
- @keyframes caret-blink {
125
- 0%,
126
- 70%,
127
- 100% {
128
- opacity: 1;
129
- }
130
- 20%,
131
- 50% {
132
- opacity: 0;
133
- }
134
- }
135
- }
136
-
137
- @media (prefers-reduced-motion: reduce) {
138
- .animate-caret-blink {
139
- animation: none;
140
- }
141
- }