@timmbr/ui 1.18.0 → 1.19.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.
Files changed (39) hide show
  1. package/dist/components/Calendar/Calendar.helpers.js +1 -1
  2. package/dist/components/Calendar/Calendar.js +1 -1
  3. package/dist/components/DataTable/DataTable.d.ts.map +1 -1
  4. package/dist/components/DataTable/DataTable.js +16 -4
  5. package/dist/components/DatePicker/DatePicker.helpers.js +1 -2
  6. package/dist/components/Rating/Rating.d.ts +1 -1
  7. package/dist/components/Rating/Rating.d.ts.map +1 -1
  8. package/dist/components/Rating/Rating.js +11 -2
  9. package/dist/components/Rating/Rating.types.d.ts +5 -0
  10. package/dist/components/Rating/Rating.types.d.ts.map +1 -1
  11. package/dist/components/RatingDistribution/RatingDistribution.d.ts +8 -0
  12. package/dist/components/RatingDistribution/RatingDistribution.d.ts.map +1 -0
  13. package/dist/components/RatingDistribution/RatingDistribution.js +70 -0
  14. package/dist/components/RatingDistribution/RatingDistribution.types.d.ts +21 -0
  15. package/dist/components/RatingDistribution/RatingDistribution.types.d.ts.map +1 -0
  16. package/dist/components/RatingDistribution/index.d.ts +3 -0
  17. package/dist/components/RatingDistribution/index.d.ts.map +1 -0
  18. package/dist/components/RatingInput/RatingInput.d.ts +8 -0
  19. package/dist/components/RatingInput/RatingInput.d.ts.map +1 -0
  20. package/dist/components/RatingInput/RatingInput.js +95 -0
  21. package/dist/components/RatingInput/RatingInput.styles.d.ts +6 -0
  22. package/dist/components/RatingInput/RatingInput.styles.d.ts.map +1 -0
  23. package/dist/components/RatingInput/RatingInput.styles.js +13 -0
  24. package/dist/components/RatingInput/RatingInput.types.d.ts +18 -0
  25. package/dist/components/RatingInput/RatingInput.types.d.ts.map +1 -0
  26. package/dist/components/RatingInput/index.d.ts +4 -0
  27. package/dist/components/RatingInput/index.d.ts.map +1 -0
  28. package/dist/components/RichTextEditor/RichTextEditor.d.ts +1 -1
  29. package/dist/components/RichTextEditor/RichTextEditor.d.ts.map +1 -1
  30. package/dist/components/RichTextEditor/RichTextEditor.js +2 -0
  31. package/dist/components/RichTextEditor/RichTextEditor.types.d.ts +2 -0
  32. package/dist/components/RichTextEditor/RichTextEditor.types.d.ts.map +1 -1
  33. package/dist/components/RichTextEditor/subcomponents/RteToolbar.d.ts +2 -1
  34. package/dist/components/RichTextEditor/subcomponents/RteToolbar.d.ts.map +1 -1
  35. package/dist/components/RichTextEditor/subcomponents/RteToolbar.js +60 -2
  36. package/dist/index.d.ts +2 -0
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +3 -0
  39. package/package.json +4 -4
@@ -1,7 +1,7 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
+ import { getDefaultClassNames } from '@daypicker/react';
2
3
  import { cn } from '@timmbr/utils';
3
4
  import { ChevronLeft, ChevronDown, ChevronRight } from '@timmbr/icons';
4
- import { getDefaultClassNames } from '../../node_modules/.pnpm/react-day-picker@10.0.2_@types_react@19.3.0_react@19.3.0/node_modules/react-day-picker/dist/esm/helpers/getDefaultClassNames.js';
5
5
 
6
6
  const selectedDayButton = "[&_button]:bg-primary [&_button]:text-primary-foreground [&_button]:hover:bg-primary [&_button]:hover:text-primary-foreground";
7
7
  const baseDayButton = "inline-flex h-full w-full items-center justify-center rounded-[2px] text-body-3 font-medium text-inherit transition-colors duration-150 hover:bg-grey-100 hover:text-foreground dark:hover:bg-grey-800 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-1";
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from 'react/jsx-runtime';
3
3
  import * as React from 'react';
4
+ import { DayPicker } from '@daypicker/react';
4
5
  import { cn } from '@timmbr/utils';
5
6
  import { ChevronDown } from '@timmbr/icons';
6
7
  import { resolveMotion } from '../../types/motion.js';
@@ -8,7 +9,6 @@ import { resolveCaptionDefaults, buildCalendarClassNames, buildCalendarComponent
8
9
  import { calendarRootVariants } from './Calendar.styles.js';
9
10
  import { CalendarYearPicker, CalendarMonthPicker } from './subcomponents/CalendarMonthYearPickers.js';
10
11
  import { useGlobalAnimation } from '../../providers/AnimationProvider.js';
11
- import { DayPicker } from '../../node_modules/.pnpm/react-day-picker@10.0.2_@types_react@19.3.0_react@19.3.0/node_modules/react-day-picker/dist/esm/DayPicker.js';
12
12
 
13
13
  function startOfMonth(date) {
14
14
  return new Date(date.getFullYear(), date.getMonth(), 1);
@@ -1 +1 @@
1
- {"version":3,"file":"DataTable.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/DataTable.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAIL,UAAU,EAGV,KAAK,SAAS,EACf,MAAM,uBAAuB,CAAC;AAc/B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,EAAE,EACjD,IAAI,EACJ,OAAO,EACP,OAAO,EACP,eAAe,EACf,YAAY,EACZ,oBAAoB,EACpB,SAAS,EACT,kBAAkB,EAClB,QAAQ,EACR,OAAO,EACP,IAAI,EACJ,YAAkC,EAClC,SAAiB,EACjB,QAAQ,EACR,UAAU,EACV,YAAmB,EACnB,mBAA0B,EAC1B,MAAM,EAAE,UAAU,GACnB,EAAE,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,qBA+L/B;yBAlNe,SAAS;;;AAsNzB,OAAO,EAAE,UAAU,EAAE,CAAC;AACtB,YAAY,EAAE,SAAS,EAAE,CAAC"}
1
+ {"version":3,"file":"DataTable.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/DataTable.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAIL,UAAU,EAGV,KAAK,SAAS,EACf,MAAM,uBAAuB,CAAC;AAc/B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,EAAE,EACjD,IAAI,EACJ,OAAO,EACP,OAAO,EACP,eAAe,EACf,YAAY,EACZ,oBAAoB,EACpB,SAAS,EACT,kBAAkB,EAClB,QAAQ,EACR,OAAO,EACP,IAAI,EACJ,YAAkC,EAClC,SAAiB,EACjB,QAAQ,EACR,UAAU,EACV,YAAmB,EACnB,mBAA0B,EAC1B,MAAM,EAAE,UAAU,GACnB,EAAE,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,qBAgN/B;yBAnOe,SAAS;;;AAuOzB,OAAO,EAAE,UAAU,EAAE,CAAC;AACtB,YAAY,EAAE,SAAS,EAAE,CAAC"}
@@ -128,6 +128,18 @@ function DataTable({
128
128
  ) }) : table.getRowModel().rows.length > 0 ? table.getRowModel().rows.map((row, index) => {
129
129
  const isSelected = row.getIsSelected();
130
130
  const cells = row.getVisibleCells().map((cell) => /* @__PURE__ */ jsx(TableCell, { children: flexRender(cell.column.columnDef.cell, cell.getContext()) }, cell.id));
131
+ const rowInteraction = onRowClick ? {
132
+ tabIndex: 0,
133
+ onClick: () => onRowClick(row),
134
+ onKeyDown: (event) => {
135
+ if (event.target !== event.currentTarget) return;
136
+ if (event.key === "Enter" || event.key === " ") {
137
+ event.preventDefault();
138
+ onRowClick(row);
139
+ }
140
+ }
141
+ } : {};
142
+ const rowFocusClass = onRowClick && "cursor-pointer focus-visible:outline-none focus-visible:bg-grey-50 focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring dark:focus-visible:bg-grey-900";
131
143
  if (shouldAnimate) {
132
144
  return /* @__PURE__ */ jsx(
133
145
  motion.tr,
@@ -142,9 +154,9 @@ function DataTable({
142
154
  },
143
155
  className: cn(
144
156
  "border-b border-grey-200 dark:border-grey-800 transition-colors data-[state=selected]:bg-primary/5 hover:bg-grey-50/80 dark:hover:bg-grey-900/60",
145
- onRowClick && "cursor-pointer"
157
+ rowFocusClass
146
158
  ),
147
- onClick: () => onRowClick?.(row),
159
+ ...rowInteraction,
148
160
  children: cells
149
161
  },
150
162
  row.id
@@ -154,8 +166,8 @@ function DataTable({
154
166
  TableRow,
155
167
  {
156
168
  "data-state": isSelected ? "selected" : void 0,
157
- className: cn(onRowClick && "cursor-pointer"),
158
- onClick: () => onRowClick?.(row),
169
+ className: cn(rowFocusClass),
170
+ ...rowInteraction,
159
171
  children: cells
160
172
  },
161
173
  row.id
@@ -1,5 +1,4 @@
1
- import { isValid } from '../../node_modules/.pnpm/date-fns@4.4.0/node_modules/date-fns/isValid.js';
2
- import { format } from '../../node_modules/.pnpm/date-fns@4.4.0/node_modules/date-fns/format.js';
1
+ import { isValid, format } from 'date-fns';
3
2
 
4
3
  const defaultDateFormat = "PPP";
5
4
  function formatDateValue(date, dateFormat = defaultDateFormat) {
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
2
  import type { RatingProps } from './Rating.types';
3
- /** Read-only average rating: "4.5 ★ (817)". */
3
+ /** Read-only average rating: "4.5 ★ (817)", or a row of stars with `display="stars"`. */
4
4
  export declare const Rating: React.ForwardRefExoticComponent<RatingProps & React.RefAttributes<HTMLDivElement>>;
5
5
  //# sourceMappingURL=Rating.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Rating.d.ts","sourceRoot":"","sources":["../../../src/components/Rating/Rating.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD,+CAA+C;AAC/C,eAAO,MAAM,MAAM,oFA4BlB,CAAC"}
1
+ {"version":3,"file":"Rating.d.ts","sourceRoot":"","sources":["../../../src/components/Rating/Rating.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAuBlD,yFAAyF;AACzF,eAAO,MAAM,MAAM,oFAqClB,CAAC"}
@@ -4,8 +4,17 @@ import { cn } from '@timmbr/utils';
4
4
  import { Star } from '@timmbr/icons';
5
5
  import { ratingVariants } from './Rating.styles.js';
6
6
 
7
+ function StarRow({ value, max }) {
8
+ return /* @__PURE__ */ jsx("span", { className: "inline-flex items-center gap-0.5", children: Array.from({ length: max }, (_, i) => {
9
+ const fill = Math.max(0, Math.min(1, value - i));
10
+ return /* @__PURE__ */ jsxs("span", { className: "relative inline-flex", children: [
11
+ /* @__PURE__ */ jsx(Star, { className: "fill-grey-200 text-grey-200 dark:fill-grey-700 dark:text-grey-700" }),
12
+ fill > 0 && /* @__PURE__ */ jsx("span", { className: "absolute inset-0 overflow-hidden", style: { width: `${fill * 100}%` }, children: /* @__PURE__ */ jsx(Star, { className: "fill-warning text-warning" }) })
13
+ ] }, i);
14
+ }) });
15
+ }
7
16
  const Rating = React.forwardRef(
8
- ({ value, max = 5, count, locale = "en-IN", label, size, className, ...props }, ref) => {
17
+ ({ value, max = 5, count, locale = "en-IN", label, size, display = "compact", className, ...props }, ref) => {
9
18
  const shown = new Intl.NumberFormat(locale, { maximumFractionDigits: 1 }).format(value);
10
19
  const counted = count !== void 0 ? new Intl.NumberFormat(locale).format(count) : void 0;
11
20
  const accessibleName = label ?? `Rated ${shown} out of ${max}${counted !== void 0 ? ` from ${counted} ratings` : ""}`;
@@ -19,7 +28,7 @@ const Rating = React.forwardRef(
19
28
  className: cn(ratingVariants({ size }), className),
20
29
  ...props,
21
30
  children: [
22
- /* @__PURE__ */ jsxs("span", { "aria-hidden": "true", className: "inline-flex items-center gap-0.5", children: [
31
+ display === "stars" ? /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "inline-flex", children: /* @__PURE__ */ jsx(StarRow, { value, max }) }) : /* @__PURE__ */ jsxs("span", { "aria-hidden": "true", className: "inline-flex items-center gap-0.5", children: [
23
32
  /* @__PURE__ */ jsx("span", { className: "font-medium", children: shown }),
24
33
  /* @__PURE__ */ jsx(Star, { className: "fill-warning text-warning" })
25
34
  ] }),
@@ -7,6 +7,11 @@ export interface RatingProps extends Omit<React.HTMLAttributes<HTMLDivElement>,
7
7
  max?: number;
8
8
  /** Number of ratings or reviews, shown as "(817)". */
9
9
  count?: number;
10
+ /**
11
+ * `compact` shows the number and one star ("4.5 ★"); `stars` shows a row of
12
+ * `max` stars filled to the value, as on a review card.
13
+ */
14
+ display?: 'compact' | 'stars';
10
15
  /** BCP 47 locale for the numbers (default `en-IN`). */
11
16
  locale?: string;
12
17
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"Rating.types.d.ts","sourceRoot":"","sources":["../../../src/components/Rating/Rating.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AACpC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD,MAAM,WAAW,WAAY,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC,EAAE,cAAc;IACzG,gCAAgC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uDAAuD;IACvD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB"}
1
+ {"version":3,"file":"Rating.types.d.ts","sourceRoot":"","sources":["../../../src/components/Rating/Rating.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AACpC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD,MAAM,WAAW,WAAY,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC,EAAE,cAAc;IACzG,gCAAgC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,OAAO,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;IAC9B,uDAAuD;IACvD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB"}
@@ -0,0 +1,8 @@
1
+ import * as React from 'react';
2
+ import type { RatingDistributionProps } from './RatingDistribution.types';
3
+ /**
4
+ * Star histogram. With `onValueChange`, each bar doubles as a single-select
5
+ * filter: shoppers expect to click a bar to read only those reviews.
6
+ */
7
+ export declare const RatingDistribution: React.ForwardRefExoticComponent<RatingDistributionProps & React.RefAttributes<HTMLDivElement>>;
8
+ //# sourceMappingURL=RatingDistribution.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RatingDistribution.d.ts","sourceRoot":"","sources":["../../../src/components/RatingDistribution/RatingDistribution.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,KAAK,EAAE,uBAAuB,EAAyB,MAAM,4BAA4B,CAAC;AAKjG;;;GAGG;AACH,eAAO,MAAM,kBAAkB,gGA6E9B,CAAC"}
@@ -0,0 +1,70 @@
1
+ "use client";
2
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
+ import * as React from 'react';
4
+ import { cn } from '@timmbr/utils';
5
+ import { Star } from '@timmbr/icons';
6
+
7
+ const defaultRowLabel = (row, percent) => `${row.stars} star${row.stars === 1 ? "" : "s"}, ${row.count} review${row.count === 1 ? "" : "s"} (${percent}%)`;
8
+ const RatingDistribution = React.forwardRef(
9
+ ({ rows, value, onValueChange, locale = "en-IN", getRowLabel = defaultRowLabel, className, ...props }, ref) => {
10
+ const total = rows.reduce((sum, row) => sum + row.count, 0);
11
+ const sorted = [...rows].sort((a, b) => b.stars - a.stars);
12
+ const number = new Intl.NumberFormat(locale);
13
+ const interactive = onValueChange !== void 0;
14
+ return /* @__PURE__ */ jsx(
15
+ "div",
16
+ {
17
+ ref,
18
+ role: interactive ? "group" : "list",
19
+ "data-slot": "rating-distribution",
20
+ className: cn("flex flex-col gap-1 font-sans", className),
21
+ ...props,
22
+ children: sorted.map((row) => {
23
+ const percent = total > 0 ? Math.round(row.count / total * 100) : 0;
24
+ const selected = value === row.stars;
25
+ const content = /* @__PURE__ */ jsxs(Fragment, { children: [
26
+ /* @__PURE__ */ jsxs("span", { className: "inline-flex w-8 shrink-0 items-center gap-0.5 text-body-3 font-medium text-foreground", children: [
27
+ row.stars,
28
+ /* @__PURE__ */ jsx(Star, { className: "size-3 fill-warning text-warning" })
29
+ ] }),
30
+ /* @__PURE__ */ jsx("span", { className: "relative h-2 flex-1 overflow-hidden rounded-full bg-grey-200 dark:bg-grey-800", children: /* @__PURE__ */ jsx(
31
+ "span",
32
+ {
33
+ className: cn(
34
+ "absolute inset-y-0 left-0 rounded-full transition-[width] duration-500",
35
+ selected || value == null ? "bg-warning" : "bg-warning/40"
36
+ ),
37
+ style: { width: `${percent}%` }
38
+ }
39
+ ) }),
40
+ /* @__PURE__ */ jsx("span", { className: "w-12 shrink-0 text-right text-body-3 tabular-nums text-muted-foreground", children: number.format(row.count) })
41
+ ] });
42
+ const rowClass = "flex w-full items-center gap-3 rounded-md px-2 py-1.5 text-left";
43
+ if (!interactive) {
44
+ return /* @__PURE__ */ jsx("div", { role: "listitem", "aria-label": getRowLabel(row, percent), className: rowClass, children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "contents", children: content }) }, row.stars);
45
+ }
46
+ return /* @__PURE__ */ jsx(
47
+ "button",
48
+ {
49
+ type: "button",
50
+ "aria-pressed": selected,
51
+ "aria-label": getRowLabel(row, percent),
52
+ disabled: row.count === 0 && !selected,
53
+ onClick: () => onValueChange(selected ? null : row.stars),
54
+ className: cn(
55
+ rowClass,
56
+ "transition-colors hover:bg-grey-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:bg-transparent dark:hover:bg-grey-900",
57
+ selected && "bg-warning/10 hover:bg-warning/15"
58
+ ),
59
+ children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "contents", children: content })
60
+ },
61
+ row.stars
62
+ );
63
+ })
64
+ }
65
+ );
66
+ }
67
+ );
68
+ RatingDistribution.displayName = "RatingDistribution";
69
+
70
+ export { RatingDistribution };
@@ -0,0 +1,21 @@
1
+ import type * as React from 'react';
2
+ export interface RatingDistributionRow {
3
+ stars: number;
4
+ count: number;
5
+ }
6
+ export interface RatingDistributionProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'> {
7
+ /** One row per star level, in any order; shown highest first. */
8
+ rows: readonly RatingDistributionRow[];
9
+ /** Star level currently used as a filter, if any. */
10
+ value?: number | null;
11
+ /**
12
+ * Makes each row a toggle button: clicking selects that level, clicking the
13
+ * selected row clears it (null). Without it the rows are static.
14
+ */
15
+ onValueChange?: (stars: number | null) => void;
16
+ /** BCP 47 locale for counts and percentages (default `en-IN`). */
17
+ locale?: string;
18
+ /** Accessible name for one row. Default: "5 stars, 120 reviews (64%)". */
19
+ getRowLabel?: (row: RatingDistributionRow, percent: number) => string;
20
+ }
21
+ //# sourceMappingURL=RatingDistribution.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RatingDistribution.types.d.ts","sourceRoot":"","sources":["../../../src/components/RatingDistribution/RatingDistribution.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AAEpC,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,uBACf,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC;IAC9D,iEAAiE;IACjE,IAAI,EAAE,SAAS,qBAAqB,EAAE,CAAC;IACvC,qDAAqD;IACrD,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAC/C,kEAAkE;IAClE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0EAA0E;IAC1E,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,qBAAqB,EAAE,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;CACvE"}
@@ -0,0 +1,3 @@
1
+ export * from './RatingDistribution';
2
+ export * from './RatingDistribution.types';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/RatingDistribution/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,4BAA4B,CAAC"}
@@ -0,0 +1,8 @@
1
+ import * as React from 'react';
2
+ import type { RatingInputProps } from './RatingInput.types';
3
+ /**
4
+ * Star picker built as a radio group: one tab stop, arrow keys move and select,
5
+ * Home/End jump to the ends. Hover previews the value before it is chosen.
6
+ */
7
+ export declare const RatingInput: React.ForwardRefExoticComponent<RatingInputProps & React.RefAttributes<HTMLDivElement>>;
8
+ //# sourceMappingURL=RatingInput.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RatingInput.d.ts","sourceRoot":"","sources":["../../../src/components/RatingInput/RatingInput.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAE5D;;;GAGG;AACH,eAAO,MAAM,WAAW,yFAqFvB,CAAC"}
@@ -0,0 +1,95 @@
1
+ "use client";
2
+ import { jsxs, jsx } from 'react/jsx-runtime';
3
+ import * as React from 'react';
4
+ import { cn } from '@timmbr/utils';
5
+ import { Star } from '@timmbr/icons';
6
+ import { ratingInputVariants } from './RatingInput.styles.js';
7
+
8
+ const RatingInput = React.forwardRef(
9
+ ({ value, onChange, max = 5, labels, disabled, invalid, size, className, ...props }, ref) => {
10
+ const [hovered, setHovered] = React.useState(0);
11
+ const buttons = React.useRef([]);
12
+ const shown = hovered || value;
13
+ const labelFor = (star) => labels?.[star - 1] ?? `${star} star${star === 1 ? "" : "s"}`;
14
+ const select = (star) => {
15
+ const next = Math.min(max, Math.max(1, star));
16
+ onChange(next);
17
+ buttons.current[next - 1]?.focus();
18
+ };
19
+ const onKeyDown = (event, star) => {
20
+ const moves = {
21
+ ArrowRight: star + 1,
22
+ ArrowUp: star + 1,
23
+ ArrowLeft: star - 1,
24
+ ArrowDown: star - 1,
25
+ Home: 1,
26
+ End: max
27
+ };
28
+ if (!(event.key in moves)) return;
29
+ event.preventDefault();
30
+ select(moves[event.key]);
31
+ };
32
+ return /* @__PURE__ */ jsxs(
33
+ "div",
34
+ {
35
+ ref,
36
+ role: "radiogroup",
37
+ "aria-invalid": invalid || void 0,
38
+ "aria-disabled": disabled || void 0,
39
+ "data-slot": "rating-input",
40
+ className: cn(ratingInputVariants({ size }), className),
41
+ ...props,
42
+ children: [
43
+ /* @__PURE__ */ jsx("span", { className: "inline-flex", onMouseLeave: () => setHovered(0), children: Array.from({ length: max }, (_, i) => {
44
+ const star = i + 1;
45
+ const checked = star === value;
46
+ const focusable = value ? checked : star === 1;
47
+ return /* @__PURE__ */ jsx(
48
+ "button",
49
+ {
50
+ ref: (el) => {
51
+ buttons.current[i] = el;
52
+ },
53
+ type: "button",
54
+ role: "radio",
55
+ "aria-checked": checked,
56
+ "aria-label": labelFor(star),
57
+ tabIndex: focusable ? 0 : -1,
58
+ disabled,
59
+ onClick: () => select(star),
60
+ onKeyDown: (event) => onKeyDown(event, star),
61
+ onMouseEnter: () => !disabled && setHovered(star),
62
+ className: "rounded-md p-0.5 text-grey-300 transition-transform focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 enabled:hover:scale-110 disabled:cursor-not-allowed disabled:opacity-50",
63
+ children: /* @__PURE__ */ jsx(
64
+ Star,
65
+ {
66
+ "aria-hidden": "true",
67
+ className: cn(
68
+ "transition-colors",
69
+ star <= shown ? "fill-warning text-warning" : "fill-transparent"
70
+ )
71
+ }
72
+ )
73
+ },
74
+ star
75
+ );
76
+ }) }),
77
+ labels && /* @__PURE__ */ jsx(
78
+ "span",
79
+ {
80
+ "aria-hidden": "true",
81
+ className: cn(
82
+ "min-w-[6rem] text-body-2 font-medium",
83
+ shown ? "text-foreground" : "text-muted-foreground"
84
+ ),
85
+ children: shown ? labelFor(shown) : " "
86
+ }
87
+ )
88
+ ]
89
+ }
90
+ );
91
+ }
92
+ );
93
+ RatingInput.displayName = "RatingInput";
94
+
95
+ export { RatingInput };
@@ -0,0 +1,6 @@
1
+ import { type VariantProps } from 'class-variance-authority';
2
+ export declare const ratingInputVariants: (props?: ({
3
+ size?: "md" | "lg" | null | undefined;
4
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
5
+ export type RatingInputVariants = VariantProps<typeof ratingInputVariants>;
6
+ //# sourceMappingURL=RatingInput.styles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RatingInput.styles.d.ts","sourceRoot":"","sources":["../../../src/components/RatingInput/RatingInput.styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAElE,eAAO,MAAM,mBAAmB;;8EAQ9B,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,YAAY,CAAC,OAAO,mBAAmB,CAAC,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { cva } from 'class-variance-authority';
2
+
3
+ const ratingInputVariants = cva("inline-flex items-center font-sans", {
4
+ variants: {
5
+ size: {
6
+ md: "gap-3 [&_svg]:size-6",
7
+ lg: "gap-4 [&_svg]:size-8"
8
+ }
9
+ },
10
+ defaultVariants: { size: "lg" }
11
+ });
12
+
13
+ export { ratingInputVariants };
@@ -0,0 +1,18 @@
1
+ import type * as React from 'react';
2
+ import type { RatingInputVariants } from './RatingInput.styles';
3
+ export interface RatingInputProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange' | 'defaultValue'>, RatingInputVariants {
4
+ /** Selected rating; 0 means nothing chosen yet. */
5
+ value: number;
6
+ onChange: (value: number) => void;
7
+ /** Highest selectable rating (default 5). */
8
+ max?: number;
9
+ /**
10
+ * Word for each value, lowest first (e.g. ["Poor", …, "Excellent"]). Shown
11
+ * next to the stars and used as each star's accessible name.
12
+ */
13
+ labels?: readonly string[];
14
+ disabled?: boolean;
15
+ /** Marks the group invalid for assistive tech (pair with a visible error). */
16
+ invalid?: boolean;
17
+ }
18
+ //# sourceMappingURL=RatingInput.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RatingInput.types.d.ts","sourceRoot":"","sources":["../../../src/components/RatingInput/RatingInput.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AACpC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAEhE,MAAM,WAAW,gBACf,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,GAAG,cAAc,CAAC,EAC7E,mBAAmB;IACrB,mDAAmD;IACnD,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,6CAA6C;IAC7C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,8EAA8E;IAC9E,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB"}
@@ -0,0 +1,4 @@
1
+ export * from './RatingInput';
2
+ export * from './RatingInput.types';
3
+ export * from './RatingInput.styles';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/RatingInput/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC"}
@@ -1,4 +1,4 @@
1
1
  import * as React from 'react';
2
2
  import type { RichTextEditorProps } from './RichTextEditor.types';
3
- export declare function RichTextEditor({ value, defaultValue, onChange, onChangeJson, onFocus, onBlur, placeholder, maxCharacters, showCharacterCount, showWordCount, toolbar, toolbarClassName, disabled, readOnly, className, editorClassName, style, id, motion: motionProp, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledby, 'aria-describedby': ariaDescribedby, }: RichTextEditorProps): React.JSX.Element;
3
+ export declare function RichTextEditor({ value, defaultValue, onChange, onChangeJson, onFocus, onBlur, placeholder, maxCharacters, showCharacterCount, showWordCount, toolbar, toolbarPreset, toolbarClassName, disabled, readOnly, className, editorClassName, style, id, motion: motionProp, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledby, 'aria-describedby': ariaDescribedby, }: RichTextEditorProps): React.JSX.Element;
4
4
  //# sourceMappingURL=RichTextEditor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"RichTextEditor.d.ts","sourceRoot":"","sources":["../../../src/components/RichTextEditor/RichTextEditor.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAW/B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAElE,wBAAgB,cAAc,CAAC,EAC7B,KAAK,EACL,YAAY,EACZ,QAAQ,EACR,YAAY,EACZ,OAAO,EACP,MAAM,EACN,WAAW,EACX,aAAa,EACb,kBAA0B,EAC1B,aAAqB,EACrB,OAAc,EACd,gBAAgB,EAChB,QAAgB,EAChB,QAAgB,EAChB,SAAS,EACT,eAAe,EACf,KAAK,EACL,EAAE,EACF,MAAM,EAAE,UAAU,EAClB,YAAY,EAAE,SAAS,EACvB,iBAAiB,EAAE,cAAc,EACjC,kBAAkB,EAAE,eAAe,GACpC,EAAE,mBAAmB,qBAoIrB"}
1
+ {"version":3,"file":"RichTextEditor.d.ts","sourceRoot":"","sources":["../../../src/components/RichTextEditor/RichTextEditor.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAW/B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAElE,wBAAgB,cAAc,CAAC,EAC7B,KAAK,EACL,YAAY,EACZ,QAAQ,EACR,YAAY,EACZ,OAAO,EACP,MAAM,EACN,WAAW,EACX,aAAa,EACb,kBAA0B,EAC1B,aAAqB,EACrB,OAAc,EACd,aAAsB,EACtB,gBAAgB,EAChB,QAAgB,EAChB,QAAgB,EAChB,SAAS,EACT,eAAe,EACf,KAAK,EACL,EAAE,EACF,MAAM,EAAE,UAAU,EAClB,YAAY,EAAE,SAAS,EACvB,iBAAiB,EAAE,cAAc,EACjC,kBAAkB,EAAE,eAAe,GACpC,EAAE,mBAAmB,qBAqIrB"}
@@ -23,6 +23,7 @@ function RichTextEditor({
23
23
  showCharacterCount = false,
24
24
  showWordCount = false,
25
25
  toolbar = true,
26
+ toolbarPreset = "full",
26
27
  toolbarClassName,
27
28
  disabled = false,
28
29
  readOnly = false,
@@ -117,6 +118,7 @@ function RichTextEditor({
117
118
  toolbar && /* @__PURE__ */ jsx(
118
119
  RteToolbar,
119
120
  {
121
+ preset: toolbarPreset,
120
122
  className: cn(
121
123
  shouldAnimate && mounted ? "animate-in fade-in duration-150" : void 0,
122
124
  toolbarClassName
@@ -21,6 +21,8 @@ export interface RichTextEditorProps extends MotionProps {
21
21
  showWordCount?: boolean;
22
22
  /** Show the toolbar — default true */
23
23
  toolbar?: boolean;
24
+ /** `basic` keeps bold, italic, and lists only. */
25
+ toolbarPreset?: 'full' | 'basic';
24
26
  toolbarClassName?: string;
25
27
  disabled?: boolean;
26
28
  readOnly?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"RichTextEditor.types.d.ts","sourceRoot":"","sources":["../../../src/components/RichTextEditor/RichTextEditor.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AACpC,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,MAAM,WAAW,mBAAoB,SAAQ,WAAW;IACtD,mCAAmC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uCAAuC;IACvC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,iEAAiE;IACjE,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,IAAI,CAAC;IAC3C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uEAAuE;IACvE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kCAAkC;IAClC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,oCAAoC;IACpC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,sCAAsC;IACtC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,oBAAoB;IACnC,gCAAgC;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B;AAED,MAAM,WAAW,wBAAwB;IACvC,4CAA4C;IAC5C,OAAO,EAAE,WAAW,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,aAAa,EAAE,OAAO,CAAC;IACvB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,qBAAqB;IACpC,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC;IACtB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,mDAAmD;IACnD,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,MAAM,WAAW,iBAAiB;IAChC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB"}
1
+ {"version":3,"file":"RichTextEditor.types.d.ts","sourceRoot":"","sources":["../../../src/components/RichTextEditor/RichTextEditor.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AACpC,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,MAAM,WAAW,mBAAoB,SAAQ,WAAW;IACtD,mCAAmC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uCAAuC;IACvC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,iEAAiE;IACjE,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,IAAI,CAAC;IAC3C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uEAAuE;IACvE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kCAAkC;IAClC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,oCAAoC;IACpC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,sCAAsC;IACtC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,kDAAkD;IAClD,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACjC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,oBAAoB;IACnC,gCAAgC;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B;AAED,MAAM,WAAW,wBAAwB;IACvC,4CAA4C;IAC5C,OAAO,EAAE,WAAW,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,aAAa,EAAE,OAAO,CAAC;IACvB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,qBAAqB;IACpC,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC;IACtB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,mDAAmD;IACnD,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,MAAM,WAAW,iBAAiB;IAChC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB"}
@@ -1,7 +1,8 @@
1
1
  import * as React from 'react';
2
2
  interface RteToolbarProps {
3
3
  className?: string;
4
+ preset?: 'full' | 'basic';
4
5
  }
5
- export declare function RteToolbar({ className }: RteToolbarProps): React.JSX.Element | null;
6
+ export declare function RteToolbar({ className, preset }: RteToolbarProps): React.JSX.Element | null;
6
7
  export {};
7
8
  //# sourceMappingURL=RteToolbar.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"RteToolbar.d.ts","sourceRoot":"","sources":["../../../../src/components/RichTextEditor/subcomponents/RteToolbar.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AA+B/B,UAAU,eAAe;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAoBD,wBAAgB,UAAU,CAAC,EAAE,SAAS,EAAE,EAAE,eAAe,4BAwKxD"}
1
+ {"version":3,"file":"RteToolbar.d.ts","sourceRoot":"","sources":["../../../../src/components/RichTextEditor/subcomponents/RteToolbar.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AA+B/B,UAAU,eAAe;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CAC3B;AAoBD,wBAAgB,UAAU,CAAC,EAAE,SAAS,EAAE,MAAe,EAAE,EAAE,eAAe,4BAqNzE"}
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { jsxs, jsx } from 'react/jsx-runtime';
3
3
  import { cn } from '@timmbr/utils';
4
- import { Undo2, Redo2, Pilcrow, Heading2, Heading3, Bold, Italic, Underline, Strikethrough, List, ListOrdered, Quote, AlignLeft, AlignCenter, AlignRight, AlignJustify, Minus, RemoveFormatting } from '@timmbr/icons';
4
+ import { Bold, Italic, List, ListOrdered, Undo2, Redo2, Pilcrow, Heading2, Heading3, Underline, Strikethrough, Quote, AlignLeft, AlignCenter, AlignRight, AlignJustify, Minus, RemoveFormatting } from '@timmbr/icons';
5
5
  import { useRteContext } from '../RichTextEditor.context.js';
6
6
  import { toolbarVariants } from '../RichTextEditor.styles.js';
7
7
  import { RteToolbarButton } from './RteToolbarButton.js';
@@ -23,10 +23,68 @@ function handleToolbarKeyDown(e) {
23
23
  const next = e.key === "ArrowRight" ? focusable[(idx + 1) % len] : e.key === "ArrowLeft" ? focusable[(idx - 1 + len) % len] : e.key === "Home" ? focusable[0] : focusable[len - 1];
24
24
  next?.focus();
25
25
  }
26
- function RteToolbar({ className }) {
26
+ function RteToolbar({ className, preset = "full" }) {
27
27
  const { editor, disabled, readOnly } = useRteContext();
28
28
  if (!editor) return null;
29
29
  const isDisabled = disabled || readOnly;
30
+ if (preset === "basic") {
31
+ return /* @__PURE__ */ jsxs(
32
+ "div",
33
+ {
34
+ "data-slot": "rte-toolbar",
35
+ role: "toolbar",
36
+ "aria-label": "Text formatting",
37
+ onKeyDown: handleToolbarKeyDown,
38
+ className: cn(toolbarVariants(), className),
39
+ children: [
40
+ /* @__PURE__ */ jsxs(RteToolbarGroup, { showLeadingDivider: false, children: [
41
+ /* @__PURE__ */ jsx(
42
+ RteToolbarButton,
43
+ {
44
+ label: "Bold",
45
+ icon: /* @__PURE__ */ jsx(Bold, { size: ICON_SIZE }),
46
+ onClick: () => editor.chain().focus().toggleBold().run(),
47
+ isActive: editor.isActive("bold"),
48
+ disabled: isDisabled
49
+ }
50
+ ),
51
+ /* @__PURE__ */ jsx(
52
+ RteToolbarButton,
53
+ {
54
+ label: "Italic",
55
+ icon: /* @__PURE__ */ jsx(Italic, { size: ICON_SIZE }),
56
+ onClick: () => editor.chain().focus().toggleItalic().run(),
57
+ isActive: editor.isActive("italic"),
58
+ disabled: isDisabled
59
+ }
60
+ )
61
+ ] }),
62
+ /* @__PURE__ */ jsxs(RteToolbarGroup, { children: [
63
+ /* @__PURE__ */ jsx(
64
+ RteToolbarButton,
65
+ {
66
+ label: "Bullet list",
67
+ icon: /* @__PURE__ */ jsx(List, { size: ICON_SIZE }),
68
+ onClick: () => editor.chain().focus().toggleBulletList().run(),
69
+ isActive: editor.isActive("bulletList"),
70
+ disabled: isDisabled
71
+ }
72
+ ),
73
+ /* @__PURE__ */ jsx(
74
+ RteToolbarButton,
75
+ {
76
+ label: "Ordered list",
77
+ icon: /* @__PURE__ */ jsx(ListOrdered, { size: ICON_SIZE }),
78
+ onClick: () => editor.chain().focus().toggleOrderedList().run(),
79
+ isActive: editor.isActive("orderedList"),
80
+ disabled: isDisabled
81
+ }
82
+ )
83
+ ] })
84
+ ]
85
+ }
86
+ );
87
+ }
30
88
  return /* @__PURE__ */ jsxs(
31
89
  "div",
32
90
  {
package/dist/index.d.ts CHANGED
@@ -78,6 +78,8 @@ export * from './components/Stepper';
78
78
  export * from './components/MediaCard';
79
79
  export * from './components/Price';
80
80
  export * from './components/Rating';
81
+ export * from './components/RatingInput';
82
+ export * from './components/RatingDistribution';
81
83
  export * from './components/IconTile';
82
84
  export * from './components/VisuallyHidden';
83
85
  export * from './components/Fieldset';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,gBAAgB,CAAC;AAC/B,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG3D,cAAc,aAAa,CAAC;AAG5B,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AAGnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,0BAA0B,CAAC;AACzC,cAAc,0BAA0B,CAAC;AACzC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC;AACvC,cAAc,kCAAkC,CAAC;AACjD,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,6BAA6B,CAAC;AAG5C,cAAc,0BAA0B,CAAC;AACzC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,wBAAwB,CAAC;AACvC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AAGvC,cAAc,qBAAqB,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AACvC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAGlC,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AAGxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,0BAA0B,CAAC;AACzC,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,yBAAyB,CAAC;AACxC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,4BAA4B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,gBAAgB,CAAC;AAC/B,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG3D,cAAc,aAAa,CAAC;AAG5B,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AAGnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,0BAA0B,CAAC;AACzC,cAAc,0BAA0B,CAAC;AACzC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC;AACvC,cAAc,kCAAkC,CAAC;AACjD,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,6BAA6B,CAAC;AAG5C,cAAc,0BAA0B,CAAC;AACzC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,wBAAwB,CAAC;AACvC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AAGvC,cAAc,qBAAqB,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AACvC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAGlC,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AAGxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,0BAA0B,CAAC;AACzC,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,yBAAyB,CAAC;AACxC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,0BAA0B,CAAC;AACzC,cAAc,iCAAiC,CAAC;AAChD,cAAc,uBAAuB,CAAC;AACtC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,4BAA4B,CAAC"}
package/dist/index.js CHANGED
@@ -92,6 +92,8 @@ export { Radio, RadioGroup, RadioItem } from './components/Radio/Radio.js';
92
92
  export { RadioCard } from './components/RadioCard/RadioCard.js';
93
93
  export { RangeSlider } from './components/RangeSlider/RangeSlider.js';
94
94
  export { Rating } from './components/Rating/Rating.js';
95
+ export { RatingDistribution } from './components/RatingDistribution/RatingDistribution.js';
96
+ export { RatingInput } from './components/RatingInput/RatingInput.js';
95
97
  export { RichTextContent } from './components/RichTextEditor/RichTextContent.js';
96
98
  export { RichTextEditor } from './components/RichTextEditor/RichTextEditor.js';
97
99
  export { RichTextJsonContent } from './components/RichTextEditor/RichTextJsonContent.js';
@@ -194,6 +196,7 @@ export { quantityStepperButtonVariants, quantityStepperValueVariants, quantitySt
194
196
  export { radioCardDotClass, radioCardMarkerClass, radioCardVariants } from './components/RadioCard/RadioCard.styles.js';
195
197
  export { radioIndicatorVariants, radioItemVariants } from './components/Radio/Radio.styles.js';
196
198
  export { rangeSliderRangeVariants, rangeSliderRootVariants, rangeSliderThumbVariants, rangeSliderTrackVariants } from './components/RangeSlider/RangeSlider.styles.js';
199
+ export { ratingInputVariants } from './components/RatingInput/RatingInput.styles.js';
197
200
  export { ratingVariants } from './components/Rating/Rating.styles.js';
198
201
  export { scrollRailChevronVariants, scrollRailVariants, scrollRailWrapperVariants } from './components/ScrollRail/ScrollRail.styles.js';
199
202
  export { selectContentVariants, selectItemVariants, selectTriggerVariants } from './components/Select/Select.styles.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@timmbr/ui",
3
- "version": "1.18.0",
3
+ "version": "1.19.0",
4
4
  "description": "High-performance, Next.js App Router-compatible UI design system components for Timmbr",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -54,10 +54,10 @@
54
54
  "date-fns": "^4.4.0",
55
55
  "input-otp": "^1.5.0",
56
56
  "@timmbr/theme": "1.3.0",
57
- "@timmbr/motion": "1.2.6",
58
- "@timmbr/utils": "1.6.0",
59
57
  "@timmbr/hooks": "1.3.0",
60
- "@timmbr/icons": "1.7.0"
58
+ "@timmbr/icons": "1.8.0",
59
+ "@timmbr/utils": "1.6.0",
60
+ "@timmbr/motion": "1.2.6"
61
61
  },
62
62
  "peerDependencies": {
63
63
  "next": ">=13.0.0 || >=14.0.0 || >=15.0.0 || >=16.0.0",