@icomponents/react 0.1.0 → 0.1.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@icomponents/react",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Кит компонентов для веба: shadcn по форме на Base UI, оболочка, темизация, контракт testid",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
@@ -122,7 +122,7 @@
122
122
  },
123
123
  "dependencies": {
124
124
  "@base-ui/react": "^1.6.0",
125
- "@icomponents/tokens": "workspace:*",
125
+ "@icomponents/tokens": "^0.1.2",
126
126
  "@radix-ui/react-icons": "^1.3.2",
127
127
  "class-variance-authority": "^0.7.1",
128
128
  "clsx": "^2.1.1",
@@ -147,7 +147,7 @@
147
147
  },
148
148
  "devDependencies": {
149
149
  "@happy-dom/global-registrator": "^20.10.6",
150
- "@icomponents/typescript-config": "workspace:*",
150
+ "@icomponents/typescript-config": "0.0.0",
151
151
  "@tanstack/react-router": "^1.170.18",
152
152
  "@tanstack/react-table": "^8.21.3",
153
153
  "@testing-library/dom": "^10.4.1",
@@ -25,7 +25,7 @@ export function PasswordInput({ className, disabled, ref, ...props }: PasswordIn
25
25
  size="icon"
26
26
  variant="ghost"
27
27
  disabled={disabled}
28
- className="absolute inset-e-1 top-1/2 h-6 w-6 -translate-y-1/2 rounded-md text-muted-foreground"
28
+ className="absolute end-1 top-1/2 h-6 w-6 -translate-y-1/2 rounded-md text-muted-foreground"
29
29
  onClick={() => setShowPassword((prev) => !prev)}
30
30
  >
31
31
  {showPassword ? <Eye size={18} /> : <EyeOff size={18} />}
@@ -26,11 +26,11 @@ export function Search({
26
26
  >
27
27
  <SearchIcon
28
28
  aria-hidden="true"
29
- className="absolute inset-s-1.5 top-1/2 -translate-y-1/2"
29
+ className="absolute start-1.5 top-1/2 -translate-y-1/2"
30
30
  size={16}
31
31
  />
32
32
  <span className="ms-4">{label}</span>
33
- <kbd className="pointer-events-none absolute inset-e-[0.3rem] top-[0.3rem] hidden h-5 items-center gap-1 rounded border bg-muted px-1.5 font-mono text-[10px] font-medium opacity-100 select-none group-hover:bg-accent sm:flex">
33
+ <kbd className="pointer-events-none absolute end-[0.3rem] top-[0.3rem] hidden h-5 items-center gap-1 rounded border bg-muted px-1.5 font-mono text-[10px] font-medium opacity-100 select-none group-hover:bg-accent sm:flex">
34
34
  <span className="text-xs">⌘</span>K
35
35
  </kbd>
36
36
  </Button>
@@ -1,7 +1,7 @@
1
1
  export function SkipToMain() {
2
2
  return (
3
3
  <a
4
- className={`fixed inset-s-44 z-999 -translate-y-52 bg-primary px-4 py-2 text-sm font-medium whitespace-nowrap text-primary-foreground opacity-95 shadow-sm transition hover:bg-primary/90 focus:translate-y-3 focus:transform focus-visible:ring-1 focus-visible:ring-ring`}
4
+ className={`fixed start-44 z-999 -translate-y-52 bg-primary px-4 py-2 text-sm font-medium whitespace-nowrap text-primary-foreground opacity-95 shadow-sm transition hover:bg-primary/90 focus:translate-y-3 focus:transform focus-visible:ring-1 focus-visible:ring-ring`}
5
5
  href="#content"
6
6
  >
7
7
  Skip to Main
@@ -61,7 +61,7 @@ function DialogContent({
61
61
  {showCloseButton && (
62
62
  <DialogPrimitive.Close
63
63
  data-slot="dialog-close"
64
- className="absolute inset-e-4 top-4 rounded-xs opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none data-open:bg-accent data-open:text-muted-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
64
+ className="absolute end-4 top-4 rounded-xs opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none data-open:bg-accent data-open:text-muted-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
65
65
  >
66
66
  <XIcon />
67
67
  <span className="sr-only">Close</span>
@@ -97,7 +97,7 @@ function DropdownMenuCheckboxItem({
97
97
  checked={checked}
98
98
  {...props}
99
99
  >
100
- <span className="pointer-events-none absolute inset-s-2 flex size-3.5 items-center justify-center">
100
+ <span className="pointer-events-none absolute start-2 flex size-3.5 items-center justify-center">
101
101
  <DropdownMenuPrimitive.CheckboxItemIndicator>
102
102
  <CheckIcon className="size-4" />
103
103
  </DropdownMenuPrimitive.CheckboxItemIndicator>
@@ -127,7 +127,7 @@ function DropdownMenuRadioItem({
127
127
  )}
128
128
  {...props}
129
129
  >
130
- <span className="pointer-events-none absolute inset-s-2 flex size-3.5 items-center justify-center">
130
+ <span className="pointer-events-none absolute start-2 flex size-3.5 items-center justify-center">
131
131
  <DropdownMenuPrimitive.RadioItemIndicator>
132
132
  <CircleIcon className="size-2 fill-current" />
133
133
  </DropdownMenuPrimitive.RadioItemIndicator>
@@ -143,7 +143,7 @@ function SelectItem({
143
143
  )}
144
144
  {...props}
145
145
  >
146
- <span className="absolute inset-e-2 flex size-3.5 items-center justify-center">
146
+ <span className="absolute end-2 flex size-3.5 items-center justify-center">
147
147
  <SelectPrimitive.ItemIndicator>
148
148
  <CheckIcon className="size-4" />
149
149
  </SelectPrimitive.ItemIndicator>
@@ -52,9 +52,9 @@ function SheetContent({
52
52
  className={cn(
53
53
  "fixed z-50 flex flex-col gap-4 bg-background shadow-lg transition ease-in-out data-closed:animate-out data-closed:duration-300 data-open:animate-in data-open:duration-500",
54
54
  side === "right" &&
55
- "inset-y-0 inset-e-0 h-full w-3/4 border-s data-closed:slide-out-to-end data-open:slide-in-from-end sm:max-w-sm",
55
+ "inset-y-0 end-0 h-full w-3/4 border-s data-closed:slide-out-to-end data-open:slide-in-from-end sm:max-w-sm",
56
56
  side === "left" &&
57
- "inset-y-0 inset-s-0 h-full w-3/4 border-e data-closed:slide-out-to-start data-open:slide-in-from-start sm:max-w-sm",
57
+ "inset-y-0 start-0 h-full w-3/4 border-e data-closed:slide-out-to-start data-open:slide-in-from-start sm:max-w-sm",
58
58
  side === "top" &&
59
59
  "inset-x-0 top-0 h-auto border-b data-closed:slide-out-to-top data-open:slide-in-from-top",
60
60
  side === "bottom" &&
@@ -64,7 +64,7 @@ function SheetContent({
64
64
  {...props}
65
65
  >
66
66
  {children}
67
- <SheetPrimitive.Close className="absolute inset-e-4 top-4 rounded-xs opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none data-open:bg-secondary">
67
+ <SheetPrimitive.Close className="absolute end-4 top-4 rounded-xs opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none data-open:bg-secondary">
68
68
  <XIcon className="size-4" />
69
69
  <span className="sr-only">Close</span>
70
70
  </SheetPrimitive.Close>
@@ -227,8 +227,8 @@ function Sidebar({
227
227
  className={cn(
228
228
  "fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[inset-inline,width] duration-200 ease-linear md:flex",
229
229
  side === "left"
230
- ? "inset-s-0 group-data-[collapsible=offcanvas]:-inset-s-[calc(var(--sidebar-width))]"
231
- : "inset-e-0 group-data-[collapsible=offcanvas]:-inset-e-[calc(var(--sidebar-width))]",
230
+ ? "start-0 group-data-[collapsible=offcanvas]:-start-[calc(var(--sidebar-width))]"
231
+ : "end-0 group-data-[collapsible=offcanvas]:-end-[calc(var(--sidebar-width))]",
232
232
  // Adjust the padding for floating and inset variants.
233
233
  variant === "floating" || variant === "inset"
234
234
  ? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]"
@@ -283,12 +283,12 @@ function SidebarRail({ className, ...props }: React.ComponentProps<"button">) {
283
283
  onClick={toggleSidebar}
284
284
  title="Toggle Sidebar"
285
285
  className={cn(
286
- "absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear group-data-[side=left]:-inset-e-4 group-data-[side=right]:inset-s-0 after:absolute after:inset-y-0 after:inset-s-1/2 after:w-0.5 hover:after:bg-sidebar-border sm:flex",
286
+ "absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear group-data-[side=left]:-end-4 group-data-[side=right]:start-0 after:absolute after:inset-y-0 after:start-1/2 after:w-0.5 hover:after:bg-sidebar-border sm:flex",
287
287
  "in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize",
288
288
  "[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize",
289
289
  "group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:start-full hover:group-data-[collapsible=offcanvas]:bg-sidebar",
290
- "[[data-side=left][data-collapsible=offcanvas]_&]:-inset-e-2",
291
- "[[data-side=right][data-collapsible=offcanvas]_&]:-inset-s-2",
290
+ "[[data-side=left][data-collapsible=offcanvas]_&]:-end-2",
291
+ "[[data-side=right][data-collapsible=offcanvas]_&]:-start-2",
292
292
 
293
293
  // RTL support
294
294
  "rtl:translate-x-1/2",
@@ -428,7 +428,7 @@ function SidebarGroupAction({
428
428
  "data-slot": "sidebar-group-action",
429
429
  "data-sidebar": "group-action",
430
430
  className: cn(
431
- "absolute inset-e-3 top-3.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground ring-sidebar-ring outline-hidden transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
431
+ "absolute end-3 top-3.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground ring-sidebar-ring outline-hidden transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
432
432
  // Increases the hit area of the button on mobile.
433
433
  "after:absolute after:-inset-2 md:after:hidden",
434
434
  "group-data-[collapsible=icon]:hidden",
@@ -553,7 +553,7 @@ function SidebarMenuAction({
553
553
  "data-slot": "sidebar-menu-action",
554
554
  "data-sidebar": "menu-action",
555
555
  className: cn(
556
- "absolute inset-e-1 top-1.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground ring-sidebar-ring outline-hidden transition-transform peer-hover/menu-button:text-sidebar-accent-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
556
+ "absolute end-1 top-1.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground ring-sidebar-ring outline-hidden transition-transform peer-hover/menu-button:text-sidebar-accent-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
557
557
  // Increases the hit area of the button on mobile.
558
558
  "after:absolute after:-inset-2 md:after:hidden",
559
559
  "peer-data-[size=sm]/menu-button:top-1",
@@ -574,7 +574,7 @@ function SidebarMenuBadge({ className, ...props }: React.ComponentProps<"div">)
574
574
  data-slot="sidebar-menu-badge"
575
575
  data-sidebar="menu-badge"
576
576
  className={cn(
577
- "pointer-events-none absolute inset-e-1 flex h-5 min-w-5 items-center justify-center rounded-md px-1 text-xs font-medium text-sidebar-foreground tabular-nums select-none",
577
+ "pointer-events-none absolute end-1 flex h-5 min-w-5 items-center justify-center rounded-md px-1 text-xs font-medium text-sidebar-foreground tabular-nums select-none",
578
578
  "peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[active=true]/menu-button:text-sidebar-accent-foreground",
579
579
  "peer-data-[size=sm]/menu-button:top-1",
580
580
  "peer-data-[size=default]/menu-button:top-1.5",
@@ -0,0 +1,30 @@
1
+ import { describe, expect, it } from "bun:test";
2
+
3
+ import { Glob } from "bun";
4
+
5
+ // Модули собирают CSS через bun-plugin-tailwind со встроенным Tailwind 4.1: утилит 4.2+ там нет,
6
+ // класс молча не генерируется (Sheet side="right" уезжал влево). Логические отступы — только start-/end-.
7
+ const TAILWIND_42_ONLY = /\binset-(?:s|e|bs|be)-/;
8
+
9
+ const SRC = new URL(".", import.meta.url).pathname;
10
+ const SELF = new URL(import.meta.url).pathname;
11
+
12
+ describe("исходники кита: только утилиты Tailwind 4.1", () => {
13
+ it("нет inset-s-/inset-e-/inset-bs-/inset-be- (вместо них start-/end-/top-/bottom-)", async () => {
14
+ const files = await Array.fromAsync(
15
+ new Glob("**/*.{ts,tsx}").scan({ cwd: SRC, absolute: true })
16
+ );
17
+ expect(files.some((f) => f.endsWith("components/ui/sheet.tsx"))).toBe(true);
18
+
19
+ const violations: string[] = [];
20
+ for (const file of files) {
21
+ if (file === SELF) continue;
22
+ const lines = (await Bun.file(file).text()).split("\n");
23
+ lines.forEach((line, i) => {
24
+ const m = line.match(TAILWIND_42_ONLY);
25
+ if (m) violations.push(`${file.slice(SRC.length)}:${i + 1}: ${m[0]}`);
26
+ });
27
+ }
28
+ expect(violations).toEqual([]);
29
+ });
30
+ });