@andreyfedkovich/cozy-ui 0.4.0 → 0.5.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 CHANGED
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## Unreleased
4
+
5
+ - **fix:** Published `styles.css` now includes Tailwind utilities and design tokens used by `Calendar` and other `src/components/ui` primitives. Consumers only need `import "@andreyfedkovich/cozy-ui/styles.css"` — Tailwind in the host app is not required.
6
+ - **build:** `build:lib` runs `@tailwindcss/cli` on `src/lib/tailwind.css` and merges output with SCSS module CSS.
7
+
3
8
  ## 0.2.1
4
9
 
5
10
  - **fix:** Published `dist-lib/index.d.ts` is now the real rolled-up declaration bundle (no broken stub pointing at `../dist/lib/index`). `vite-plugin-dts` writes types to the same `outDir` as the library build (`dist-lib`).
package/README.md CHANGED
@@ -31,7 +31,7 @@ npm i @andreyfedkovich/cozy-ui
31
31
  - [Design tokens](#design-tokens)
32
32
  - [Component API](#component-api)
33
33
  - [Layout & content](#layout--content) — `BaseBlock`, `Card`, `CollapsableBlock`, `Collapse`, `Carousel`, `EmptyComponent`, `Spinner`
34
- - [Inputs & forms](#inputs--forms) — `Button`, `RadioGroupButton`, `Select`, `DialogSelect`, `TreeDialogSelect`, `InputCaption`, `Label`
34
+ - [Inputs & forms](#inputs--forms) — `Button`, `RadioGroupButton`, `Input`, `Calendar`, `Checkbox`, `Select`, `DialogSelect`, `TreeDialogSelect`, `InputCaption`, `Label`
35
35
  - [Navigation](#navigation) — `Tabs`, `TabsRounded`, `Stepper`
36
36
  - [Overlays](#overlays) — `Popover`, `TooltipDark`, `TooltipLight`
37
37
  - [Utility](#utility) — `Tag`, `CopyTextTrigger`
@@ -86,6 +86,19 @@ import "@andreyfedkovich/cozy-ui/styles.css";
86
86
 
87
87
  Sizing uses CSS `rem` against the browser’s default root font size (commonly **16px**). You **do not** need to set `html { font-size: … }` for components to match the library demo.
88
88
 
89
+ ### Tailwind-powered components
90
+
91
+ Most Cozy UI styles come from SCSS modules bundled into `styles.css`. Components built on shadcn use Tailwind class names in JS; those utilities are **prebuilt into the same** `@andreyfedkovich/cozy-ui/styles.css` when the package is published. You do **not** need Tailwind CSS in your application.
92
+
93
+ If your app already uses Tailwind v4 and you prefer to generate utilities yourself, you may add `@source` pointing at the library bundle — optional, not required.
94
+
95
+ ### Adding a new Tailwind-based component (library authors)
96
+
97
+ 1. Primitive in `src/components/ui/<name>.tsx` (Tailwind + Radix as needed).
98
+ 2. Public API in `src/lib/components/<Name>/` (field label, errors, value; SCSS optional for the trigger shell).
99
+ 3. Ensure paths are covered by `@source` in `src/lib/tailwind.css` (`../lib/**/*`, `../components/ui/**/*`).
100
+ 4. Run `npm run build:lib` before publish; verify `dist-lib/styles.css` includes the new classes.
101
+
89
102
  ---
90
103
 
91
104
  ## Quick start
@@ -312,6 +325,123 @@ const [view, setView] = useState<"grid" | "list">("grid");
312
325
  />;
313
326
  ```
314
327
 
328
+ #### `Input`
329
+
330
+ Accessible text field with optional label and validation message for product forms.
331
+
332
+ | Prop | Type | Default | Description |
333
+ | ---------------- | --------------------------------------- | ------- | ------------------------------------ |
334
+ | `label` | `ReactNode` | — | Field label above the input. |
335
+ | `tooltipContent` | `ReactNode` | — | Help tooltip on the «?» icon next to the label. |
336
+ | `tooltipPopperClassName` | `string` | — | Extra class for the tooltip popper. |
337
+ | `error` | `string \| null` | — | Validation message under the input. |
338
+ | `disabled` | `boolean` | `false` | Disabled state. |
339
+ | `className` | `string` | — | Wrapper class. |
340
+ | `inputClassName` | `string` | — | Native `<input>` class. |
341
+ | `...rest` | `InputHTMLAttributes<HTMLInputElement>` | — | All native input props. |
342
+
343
+ ```tsx
344
+ import { Input } from "@andreyfedkovich/cozy-ui";
345
+ import { useState } from "react";
346
+
347
+ const [email, setEmail] = useState("");
348
+
349
+ <Input
350
+ label="Email"
351
+ placeholder="you@company.com"
352
+ value={email}
353
+ onChange={(e) => setEmail(e.target.value)}
354
+ />;
355
+
356
+ <Input
357
+ label="Password"
358
+ type="password"
359
+ error="Minimum 8 characters."
360
+ />;
361
+ ```
362
+
363
+ #### `Calendar`
364
+
365
+ Date picker field for forms. Value is stored as `yyyy-MM-dd` (or `null`); the trigger shows `dd.MM.yyyy`. Includes helpers for parsing and serializing local calendar days.
366
+
367
+ **Styling:** import `@andreyfedkovich/cozy-ui/styles.css` once (same as other components). Calendar popover and day grid use Tailwind utilities that are included in that file — no extra CSS or Tailwind config in your project.
368
+
369
+ | Prop | Type | Default | Description |
370
+ | ------------------------- | --------------------------------- | ------- | -------------------------------------------------------- |
371
+ | `label` | `string` | — | Field label. |
372
+ | `required` | `boolean` | `false` | Appends ` *` to the label. |
373
+ | `value` | `string \| null` | — | Selected date as `yyyy-MM-dd`. |
374
+ | `onChange` | `(value: string \| null) => void` | — | Called when the user picks or clears a date. |
375
+ | `minDate` | `Date` | — | Earliest selectable day (inclusive, local calendar). |
376
+ | `error` | `string \| null` | — | Validation message under the field. |
377
+ | `disabled` | `boolean` | `false` | Disables the trigger. |
378
+ | `tooltipContent` | `ReactNode` | — | Help tooltip on the «i» icon next to the label. |
379
+ | `tooltipPopperClassName` | `string` | — | Extra class for the tooltip popper. |
380
+ | `className` | `string` | — | Wrapper class. |
381
+
382
+ Exported utilities: `startOfLocalDay`, `todayLocalDay`, `toYmdString`, `parseYmdToLocalDay`.
383
+
384
+ ```tsx
385
+ import {
386
+ Calendar,
387
+ todayLocalDay,
388
+ } from "@andreyfedkovich/cozy-ui";
389
+ import { useState } from "react";
390
+
391
+ const [startDate, setStartDate] = useState<string | null>(null);
392
+
393
+ <Calendar
394
+ label="Дата начала"
395
+ required
396
+ value={startDate}
397
+ onChange={setStartDate}
398
+ minDate={todayLocalDay()}
399
+ />;
400
+
401
+ <Calendar
402
+ label="Дедлайн"
403
+ value={startDate}
404
+ onChange={setStartDate}
405
+ error="Укажите дату."
406
+ tooltipContent="Дата должна быть не раньше сегодня."
407
+ />;
408
+ ```
409
+
410
+ #### `Checkbox`
411
+
412
+ Accessible checkbox with a custom premium box, optional inline label, and validation message.
413
+
414
+ | Prop | Type | Default | Description |
415
+ | ------------------- | -------------------------------------------- | ------- | ---------------------------------------- |
416
+ | `label` | `ReactNode` | — | Label text to the right of the checkbox. |
417
+ | `error` | `string \| null` | — | Validation message under the control. |
418
+ | `disabled` | `boolean` | `false` | Disabled state. |
419
+ | `className` | `string` | — | Wrapper class. |
420
+ | `checkboxClassName` | `string` | — | Class on the visual checkbox box. |
421
+ | `...rest` | `Omit<InputHTMLAttributes<HTMLInputElement>, "type">` | — | All native checkbox props (`checked`, `onChange`, `name`, etc.). |
422
+
423
+ ```tsx
424
+ import { Checkbox } from "@andreyfedkovich/cozy-ui";
425
+ import { useState } from "react";
426
+
427
+ const [agreed, setAgreed] = useState(false);
428
+
429
+ <Checkbox
430
+ label="Согласен с условиями обработки данных"
431
+ checked={agreed}
432
+ onChange={(e) => setAgreed(e.target.checked)}
433
+ />;
434
+
435
+ <Checkbox label="Уведомления по email" defaultChecked disabled />;
436
+
437
+ <Checkbox
438
+ label="Обязательное согласие"
439
+ checked={agreed}
440
+ onChange={(e) => setAgreed(e.target.checked)}
441
+ error={agreed ? null : "Необходимо принять условия."}
442
+ />;
443
+ ```
444
+
315
445
  #### `Select`
316
446
 
317
447
  Powerful, virtualized-friendly select with `single` and `multiple` modes, search, custom rendering, and table layout.
@@ -327,7 +457,9 @@ Powerful, virtualized-friendly select with `single` and `multiple` modes, search
327
457
  | `columns` | `SelectColumn[]` | — | Required when `template="table"`. |
328
458
  | `isLoading` | `boolean` | `false` | Show loading state in dropdown. |
329
459
  | `error` | `string \| null` | — | Validation message. |
330
- | `label` | `ReactNode` | — | Field label. |
460
+ | `label` | `ReactNode` | — | Field label. |
461
+ | `tooltipContent` | `ReactNode` | — | Help tooltip on the «?» icon next to the label. |
462
+ | `tooltipPopperClassName` | `string` | — | Extra class for the tooltip popper. |
331
463
 
332
464
  ```tsx
333
465
  import { Select, type CustomOption } from "@andreyfedkovich/cozy-ui";
@@ -354,6 +486,12 @@ const [value, setValue] = useState<CustomOption<unknown, string> | null>(null);
354
486
 
355
487
  Dialog-based picker for large datasets — search + paginated loading + multi-select.
356
488
 
489
+ | Prop | Type | Description |
490
+ | ------------------------ | ----------- | ----------------------------------------------- |
491
+ | `label` | `ReactNode` | Field label above the trigger. |
492
+ | `tooltipContent` | `ReactNode` | Help tooltip on the «?» icon next to the label. |
493
+ | `tooltipPopperClassName` | `string` | Extra class for the tooltip popper. |
494
+
357
495
  ```tsx
358
496
  import { DialogSelect } from "@andreyfedkovich/cozy-ui";
359
497
 
@@ -373,6 +511,12 @@ import { DialogSelect } from "@andreyfedkovich/cozy-ui";
373
511
 
374
512
  Hierarchical picker with lazy-loaded branches and search.
375
513
 
514
+ | Prop | Type | Description |
515
+ | ------------------------ | ----------- | ----------------------------------------------- |
516
+ | `label` | `ReactNode` | Field label above the trigger. |
517
+ | `tooltipContent` | `ReactNode` | Help tooltip on the «?» icon next to the label. |
518
+ | `tooltipPopperClassName` | `string` | Extra class for the tooltip popper. |
519
+
376
520
  ```tsx
377
521
  import { TreeDialogSelect } from "@andreyfedkovich/cozy-ui";
378
522
 
@@ -720,7 +864,7 @@ For per-component overrides, every component accepts a `className` prop and uses
720
864
  ```bash
721
865
  bun install
722
866
  bun run dev # demo playground at http://localhost:5173
723
- bun run build:lib # produce dist/ (ESM + CJS + .d.ts + styles.css)
867
+ bun run build:lib # dist-lib/ (ESM + CJS + .d.ts + styles.css with SCSS + Tailwind)
724
868
  bun run lint
725
869
  bun run format
726
870
  ```
@@ -751,4 +895,4 @@ PRs are welcome. Please:
751
895
 
752
896
  ## License
753
897
 
754
- MIT © Andrey Fedkovich
898
+ MIT © Andrey Fedkovich
@@ -25,6 +25,7 @@ import { default as FileReloadIcon } from './fileReload.svg?react';
25
25
  import { default as FileSync } from './fileSync.svg?react';
26
26
  import { default as FilterIcon } from './filter.svg?react';
27
27
  import { default as FolderEditIcon } from './folderEdit.svg?react';
28
+ import { ForwardRefExoticComponent } from 'react';
28
29
  import { default as GraduateIcon } from './graduate.svg?react';
29
30
  import { default as GridIcon } from './grid.svg?react';
30
31
  import { default as HeartIcon } from './heart.svg?react';
@@ -33,6 +34,7 @@ import { default as HistoryBlue } from './historyBlue.svg?react';
33
34
  import { default as HomeIcon } from './home.svg?react';
34
35
  import { HTMLAttributes } from 'react';
35
36
  import { default as InfoIcon } from './info.svg?react';
37
+ import { InputHTMLAttributes } from 'react';
36
38
  import { default as IslandIcon } from './island.svg?react';
37
39
  import { JSX } from 'react/jsx-runtime';
38
40
  import { default as ListIcon } from './list.svg?react';
@@ -48,6 +50,7 @@ import { default as ProfileSearchIcon } from './profileSearch.svg?react';
48
50
  import { PropsWithChildren } from 'react';
49
51
  import * as React_2 from 'react';
50
52
  import { ReactNode } from 'react';
53
+ import { RefAttributes } from 'react';
51
54
  import { RefObject } from 'react';
52
55
  import { default as ReloadIcon } from './reload.svg?react';
53
56
  import { default as SchoolIcon } from './school.svg?react';
@@ -131,6 +134,23 @@ declare type ButtonSize = "small" | "medium" | "large";
131
134
 
132
135
  declare type ButtonVariant = "default" | "primary" | "secondary" | "text" | "link" | "danger";
133
136
 
137
+ export declare const Calendar: ({ label, required, value, onChange, minDate, error, disabled, tooltipContent, tooltipPopperClassName, className, }: CalendarProps) => JSX.Element;
138
+
139
+ export declare interface CalendarProps {
140
+ label: string;
141
+ required?: boolean;
142
+ value?: string | null;
143
+ onChange: (value: string | null) => void;
144
+ /** Нижняя граница выбора (включительно), локальный календарный день */
145
+ minDate?: Date;
146
+ error?: string | null;
147
+ disabled?: boolean;
148
+ /** Подсказка по наведению на иконку «?» справа от подписи */
149
+ tooltipContent?: ReactNode;
150
+ tooltipPopperClassName?: string;
151
+ className?: string;
152
+ }
153
+
134
154
  export { CameraIcon }
135
155
 
136
156
  export { CancelIcon }
@@ -178,6 +198,14 @@ export { ChartIcon }
178
198
 
179
199
  export { ChatIcon }
180
200
 
201
+ export declare const Checkbox: ForwardRefExoticComponent<CheckboxProps & RefAttributes<HTMLInputElement>>;
202
+
203
+ export declare interface CheckboxProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "type"> {
204
+ label?: ReactNode;
205
+ error?: string | null;
206
+ checkboxClassName?: string;
207
+ }
208
+
181
209
  export { CheckGreen }
182
210
 
183
211
  export { ClockFilledIcon }
@@ -367,6 +395,9 @@ declare type CustomSelectProps<T, S> = {
367
395
  onClear?: () => void;
368
396
  icon?: ReactNode;
369
397
  label?: ReactNode;
398
+ /** Подсказка по наведению на иконку «?» справа от подписи */
399
+ tooltipContent?: ReactNode;
400
+ tooltipPopperClassName?: string;
370
401
  onSearch?: (value: string) => void;
371
402
  isLoading?: boolean;
372
403
  disabled?: boolean;
@@ -440,7 +471,7 @@ export declare interface DetailViewProps {
440
471
  id?: string;
441
472
  }
442
473
 
443
- export declare const DialogSelect: <T, S extends string | number>({ value, placeholder, loadOptions, onChange, onClear, columns, label, title, searchPlaceholder, selectButtonText, closeButtonText, manualButtonText, onManualAdd, pageSize, debounceMs, disabled, error, className, inputClassName, selectedOptionRender, }: DialogSelectProps<T, S>) => JSX.Element;
474
+ export declare const DialogSelect: <T, S extends string | number>({ value, placeholder, loadOptions, onChange, onClear, columns, label, tooltipContent, tooltipPopperClassName, title, searchPlaceholder, selectButtonText, closeButtonText, manualButtonText, onManualAdd, pageSize, debounceMs, disabled, error, className, inputClassName, selectedOptionRender, }: DialogSelectProps<T, S>) => JSX.Element;
444
475
 
445
476
  export declare type DialogSelectColumn<T, S extends string | number> = {
446
477
  key: string;
@@ -457,6 +488,9 @@ export declare interface DialogSelectProps<T, S extends string | number> {
457
488
  onClear?: () => void;
458
489
  columns?: DialogSelectColumn<T, S>[];
459
490
  label?: ReactNode;
491
+ /** Подсказка по наведению на иконку «?» справа от подписи */
492
+ tooltipContent?: ReactNode;
493
+ tooltipPopperClassName?: string;
460
494
  title?: ReactNode;
461
495
  searchPlaceholder?: string;
462
496
  selectButtonText?: string;
@@ -532,6 +566,8 @@ export { HomeIcon }
532
566
 
533
567
  export { InfoIcon }
534
568
 
569
+ export declare const Input: ForwardRefExoticComponent<InputProps & RefAttributes<HTMLInputElement>>;
570
+
535
571
  export declare const InputCaption: React_2.FC<PropsWithChildren<InputCaptionProps>>;
536
572
 
537
573
  declare interface InputCaptionProps {
@@ -544,6 +580,15 @@ declare interface InputCaptionProps {
544
580
 
545
581
  export declare type InputCaptionVariant = "neutral" | "error" | "success";
546
582
 
583
+ export declare interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
584
+ label?: ReactNode;
585
+ error?: string | null;
586
+ inputClassName?: string;
587
+ /** Подсказка по наведению на иконку «?» справа от подписи */
588
+ tooltipContent?: ReactNode;
589
+ tooltipPopperClassName?: string;
590
+ }
591
+
547
592
  export { IslandIcon }
548
593
 
549
594
  export declare const Label: ({ htmlFor, children, className }: LabelProps) => JSX.Element;
@@ -595,6 +640,8 @@ declare type ModeProps<T, S> = {
595
640
 
596
641
  export { NotebookIcon }
597
642
 
643
+ export declare const parseYmdToLocalDay: (value: string | null | undefined) => Date | undefined;
644
+
598
645
  export { PhoneIcon }
599
646
 
600
647
  export { PlaneIcon }
@@ -697,7 +744,7 @@ declare interface SectionComponentProps extends Omit<DetailSection, "fields"> {
697
744
  children?: ReactNode;
698
745
  }
699
746
 
700
- export declare const Select: <T, S extends string | number>({ options, value, mode, placeholder, onChange, dropdownRender, optionRender, selectedOptionRender, dropdownIcon, tagRender, dropDownClassName, optionClassName, inputClassName, deleteIconClassName, onDelete, onClear, label, onSearch, searchClassName, searchPlaceholder, isLoading, disabled, onClose, portalTarget, error, fixedHeight, template, columns, total, }: CustomSelectProps<T, S>) => JSX.Element;
747
+ export declare const Select: <T, S extends string | number>({ options, value, mode, placeholder, onChange, dropdownRender, optionRender, selectedOptionRender, dropdownIcon, tagRender, dropDownClassName, optionClassName, inputClassName, deleteIconClassName, onDelete, onClear, label, tooltipContent, tooltipPopperClassName, onSearch, searchClassName, searchPlaceholder, isLoading, disabled, onClose, portalTarget, error, fixedHeight, template, columns, total, }: CustomSelectProps<T, S>) => JSX.Element;
701
748
 
702
749
  export declare type SelectColumn<T, S> = {
703
750
  key: string;
@@ -712,6 +759,8 @@ export declare const Spinner: React_2.FC<Props>;
712
759
 
713
760
  declare type SpinnerSize = "big" | "small" | "extraSmall" | "medium" | "large";
714
761
 
762
+ export declare const startOfLocalDay: (d: Date) => Date;
763
+
715
764
  export declare const Stepper: default_2.FC<StepperProps>;
716
765
 
717
766
  export declare type StepperItem = {
@@ -782,6 +831,8 @@ export { TaskListIcon }
782
831
 
783
832
  export { TimesheetIcon }
784
833
 
834
+ export declare const todayLocalDay: () => Date;
835
+
785
836
  export declare const TooltipDark: MemoExoticComponent<({ title, content, open: openProp, defaultOpen, trigger, mouseEnterDelay, mouseLeaveDelay, onOpenChange, placement, arrow, children, overlayClassName, getPopupContainer, }: TooltipProps) => JSX.Element>;
786
837
 
787
838
  export declare const TooltipLight: FC<TooltipLightProps>;
@@ -825,7 +876,10 @@ declare type TooltipTarget = string | HTMLElement | RefObject<HTMLElement | null
825
876
 
826
877
  export declare type TooltipTrigger = "hover" | "click";
827
878
 
828
- export declare const TreeDialogSelect: <T, S extends string | number>({ value, placeholder, loadChildren: loadChildrenProp, loadNodes, searchNodes, onChange, onClear, label, title, searchPlaceholder, selectButtonText, closeButtonText, confirmButtonText, debounceMs, disabled, error, className, inputClassName, selectedOptionRender, nodeRender, leafConfirmOnly, }: TreeDialogSelectProps<T, S>) => JSX.Element;
879
+ /** `yyyy-MM-dd` for API / form state */
880
+ export declare const toYmdString: (d: Date) => string;
881
+
882
+ export declare const TreeDialogSelect: <T, S extends string | number>({ value, placeholder, loadChildren: loadChildrenProp, loadNodes, searchNodes, onChange, onClear, label, tooltipContent, tooltipPopperClassName, title, searchPlaceholder, selectButtonText, closeButtonText, confirmButtonText, debounceMs, disabled, error, className, inputClassName, selectedOptionRender, nodeRender, leafConfirmOnly, }: TreeDialogSelectProps<T, S>) => JSX.Element;
829
883
 
830
884
  /** Pass either {@link loadNodes} or {@link loadChildren} (deprecated alias). */
831
885
  export declare type TreeDialogSelectProps<T, S extends string | number> = TreeDialogSelectShared<T, S> & ({
@@ -843,6 +897,9 @@ declare interface TreeDialogSelectShared<T, S extends string | number> {
843
897
  onChange?: (node: TreeNode<T, S>) => void;
844
898
  onClear?: () => void;
845
899
  label?: ReactNode;
900
+ /** Подсказка по наведению на иконку «?» справа от подписи */
901
+ tooltipContent?: ReactNode;
902
+ tooltipPopperClassName?: string;
846
903
  title?: ReactNode;
847
904
  searchPlaceholder?: string;
848
905
  selectButtonText?: string;