@jbpark/ui-kit 6.2.0 → 7.1.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.
package/dist/Tag.d.mts CHANGED
@@ -6,18 +6,19 @@ type NativeSpanProps = React$1.ComponentProps<'span'> & {
6
6
  };
7
7
  interface Props extends Omit<NativeSpanProps, 'variant' | 'color'> {
8
8
  /**
9
- * Fill style, aligned with `Button`'s vocabulary. `'default'` is a
10
- * **deprecated alias** for `'filled'` — it still renders identically, but
11
- * prefer `'filled'` going forward (#320).
12
- *
13
- * @remarks `'default'` will be removed in a future major.
9
+ * Fill style, aligned with `Button`'s vocabulary (#320). The pre-7.0
10
+ * `'default'` spelling was removed — use `'filled'`, which renders
11
+ * identically.
14
12
  */
15
- variant?: 'filled' | 'outlined' | 'default';
13
+ variant?: 'filled' | 'outlined';
16
14
  /**
17
- * Colour, sharing `Button`'s preset palette. The named states
18
- * (`primary`/`success`/`warning`/`danger`) keep their semantic look; the
19
- * shared presets (`blue`, `red`, `gold`, …) are backed by the same
20
- * `data-color` system as `Button` (#320).
15
+ * Colour. Every value — the semantic states (`primary`/`success`/`warning`/
16
+ * `danger`) as well as the palette shared with `Button` (`blue`, `red`,
17
+ * `gold`, …) — resolves through the same `data-color` + `--tag-*` system
18
+ * (#320), so any of them can be re-themed the same way.
19
+ *
20
+ * `success`/`warning` have no `Button` counterpart on purpose: a Tag marks
21
+ * state, which is why antd's Tag also carries them while its Button does not.
21
22
  */
22
23
  color?: 'default' | 'primary' | 'success' | 'warning' | 'danger' | PresetColor;
23
24
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Tag.d.mts","names":[],"sources":["../src/components/atoms/tag.tsx"],"mappings":";;;KAYK,kBAAkB,QAAM;EAC3B;;UAGe,cAAc,KAAK;;;;;;;;EAQlC;;;;;;;EAOA,mEAC6D;;cAgDzD,QAAO,WAAA,SAAA,OAAA,SAAA,aAAA,SAOV,UAAK,QAAA,IAAA"}
1
+ {"version":3,"file":"Tag.d.mts","names":[],"sources":["../src/components/atoms/tag.tsx"],"mappings":";;;KAYK,kBAAkB,QAAM;EAC3B;;UAGe,cAAc,KAAK;;;;;;EAMlC;;;;;;;;;;EAUA,mEAC6D;;cA+BzD,QAAO,WAAA,SAAA,OAAA,SAAA,aAAA,SAOV,UAAK,QAAA,IAAA"}
package/dist/Tag.mjs CHANGED
@@ -2,39 +2,23 @@
2
2
  import { cn } from "./utils.mjs";
3
3
  import { useConfig } from "./providers/config/context.mjs";
4
4
  import { INTERACTIVE_CHASSIS } from "./lib/chassis.mjs";
5
- import { isPresetColor } from "./lib/colors.mjs";
6
5
  import "react";
7
6
  import { Slot } from "@radix-ui/react-slot";
8
7
  import { jsx } from "react/jsx-runtime";
9
8
  //#region src/components/atoms/tag.tsx
10
9
  const TAG_BASE = cn(INTERACTIVE_CHASSIS, "border w-fit whitespace-nowrap overflow-hidden", "text-xs font-medium gap-1 transition-[color,box-shadow]", "[&>svg]:size-3 [&>svg]:pointer-events-none", "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground");
11
- const fillColorClasses = {
12
- default: "border-transparent bg-muted text-muted-foreground",
13
- primary: "border-transparent bg-primary/10 text-primary",
14
- success: "border-transparent bg-green-500/10 text-green-600 dark:text-green-400",
15
- warning: "border-transparent bg-yellow-500/10 text-yellow-600 dark:text-yellow-400",
16
- danger: "border-transparent bg-destructive/10 text-destructive"
17
- };
18
- const outlinedColorClasses = {
19
- default: "border-border text-foreground",
20
- primary: "border-primary text-primary",
21
- success: "border-green-500 text-green-600 dark:text-green-400",
22
- warning: "border-yellow-500 text-yellow-600 dark:text-yellow-400",
23
- danger: "border-destructive text-destructive"
24
- };
25
- const presetFillClasses = cn("border-transparent", "bg-[color-mix(in_oklch,var(--tag-bg),transparent_90%)]", "text-(--tag-bg)");
26
- const presetOutlinedClasses = cn("border-(--tag-bg) text-(--tag-bg)");
10
+ const fillClasses = cn("border-transparent bg-(--tag-tint) text-(--tag-fg)");
11
+ const outlinedClasses = cn("border-(--tag-bg) text-(--tag-fg)");
27
12
  const Tag = ({ className, variant, color, asChild = false, children, ...props }) => {
28
13
  const { defaultProps } = useConfig();
29
14
  const tagDefaults = defaultProps?.tag;
30
15
  const resolvedVariant = variant ?? tagDefaults?.variant ?? "filled";
31
16
  const resolvedColor = color ?? tagDefaults?.color ?? "default";
32
- const isOutlined = resolvedVariant === "outlined";
33
- const preset = isPresetColor(resolvedColor);
34
17
  return /* @__PURE__ */ jsx(asChild ? Slot : "span", {
35
18
  "data-slot": "badge",
36
- "data-color": preset ? resolvedColor : void 0,
37
- className: cn(TAG_BASE, "rounded-full px-2.5 py-1", "text-xs font-medium", preset ? isOutlined ? presetOutlinedClasses : presetFillClasses : isOutlined ? outlinedColorClasses[resolvedColor] : fillColorClasses[resolvedColor], className),
19
+ "data-color": resolvedColor,
20
+ "data-variant": resolvedVariant,
21
+ className: cn(TAG_BASE, "rounded-full px-2.5 py-1", "text-xs font-medium", resolvedVariant === "outlined" ? outlinedClasses : fillClasses, className),
38
22
  ...props,
39
23
  children
40
24
  });
package/dist/Tag.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"Tag.mjs","names":[],"sources":["../src/components/atoms/tag.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\n\nimport { Slot } from '@radix-ui/react-slot';\n\nimport { useConfig } from '@repo/ui/providers';\nimport { cn } from '@repo/ui/utils';\n\nimport { INTERACTIVE_CHASSIS } from '../../lib/chassis';\nimport { type PresetColor, isPresetColor } from '../../lib/colors';\n\ntype NativeSpanProps = React.ComponentProps<'span'> & {\n asChild?: boolean;\n};\n\nexport interface Props extends Omit<NativeSpanProps, 'variant' | 'color'> {\n /**\n * Fill style, aligned with `Button`'s vocabulary. `'default'` is a\n * **deprecated alias** for `'filled'` — it still renders identically, but\n * prefer `'filled'` going forward (#320).\n *\n * @remarks `'default'` will be removed in a future major.\n */\n variant?: 'filled' | 'outlined' | 'default';\n /**\n * Colour, sharing `Button`'s preset palette. The named states\n * (`primary`/`success`/`warning`/`danger`) keep their semantic look; the\n * shared presets (`blue`, `red`, `gold`, …) are backed by the same\n * `data-color` system as `Button` (#320).\n */\n color?:\n 'default' | 'primary' | 'success' | 'warning' | 'danger' | PresetColor;\n}\n\n// Base absorbed from core/badge's cva base + its `outline` variant, which Tag\n// always rendered as (#278 ③ / #294 Phase 4). The shared focus/aria/centering\n// set lives in INTERACTIVE_CHASSIS; a Tag adds badge geometry and its svg\n// sizing but — unlike Button — no `disabled:*` (a Tag is not disableable). The\n// rounded/padding leftovers are overridden by the atom classes below exactly as\n// before, so the rendered output is unchanged (verified against a pre-refactor\n// render matrix).\nconst TAG_BASE = cn(\n INTERACTIVE_CHASSIS,\n 'border w-fit whitespace-nowrap overflow-hidden',\n 'text-xs font-medium gap-1 transition-[color,box-shadow]',\n '[&>svg]:size-3 [&>svg]:pointer-events-none',\n 'text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground',\n);\n\nconst fillColorClasses: Record<string, string> = {\n default: 'border-transparent bg-muted text-muted-foreground',\n primary: 'border-transparent bg-primary/10 text-primary',\n success:\n 'border-transparent bg-green-500/10 text-green-600 dark:text-green-400',\n warning:\n 'border-transparent bg-yellow-500/10 text-yellow-600 dark:text-yellow-400',\n danger: 'border-transparent bg-destructive/10 text-destructive',\n};\n\nconst outlinedColorClasses: Record<string, string> = {\n default: 'border-border text-foreground',\n primary: 'border-primary text-primary',\n success: 'border-green-500 text-green-600 dark:text-green-400',\n warning: 'border-yellow-500 text-yellow-600 dark:text-yellow-400',\n danger: 'border-destructive text-destructive',\n};\n\n// Preset colours resolve their hue from the shared `--tag-bg` custom property\n// (globals.css, keyed on `data-color`) rather than a per-colour Tailwind class,\n// so `Tag` and `Button` stay in lock-step. Fill uses a 10% tint behind the\n// full-strength hue; outlined borders and texts it directly.\nconst presetFillClasses = cn(\n 'border-transparent',\n 'bg-[color-mix(in_oklch,var(--tag-bg),transparent_90%)]',\n 'text-(--tag-bg)',\n);\n\nconst presetOutlinedClasses = cn('border-(--tag-bg) text-(--tag-bg)');\n\nconst Tag = ({\n className,\n variant,\n color,\n asChild = false,\n children,\n ...props\n}: Props) => {\n const { defaultProps } = useConfig();\n const tagDefaults = defaultProps?.tag as\n Partial<Pick<Props, 'variant' | 'color'>> | undefined;\n // An explicit prop wins over a `Config` default, which wins over the built-in\n // — the same resolution order `Button` uses.\n const resolvedVariant = variant ?? tagDefaults?.variant ?? 'filled';\n const resolvedColor = color ?? tagDefaults?.color ?? 'default';\n // `'default'` is the pre-#320 spelling of `'filled'`; fold it in so the alias\n // renders identically.\n const isOutlined = resolvedVariant === 'outlined';\n const preset = isPresetColor(resolvedColor);\n const Comp = asChild ? Slot : 'span';\n\n return (\n <Comp\n data-slot=\"badge\"\n // Only preset colours drive the `--tag-*` system; the named states keep\n // their bespoke classes, so existing usage renders byte-identical.\n data-color={preset ? resolvedColor : undefined}\n className={cn(\n TAG_BASE,\n 'rounded-full px-2.5 py-1',\n 'text-xs font-medium',\n preset\n ? isOutlined\n ? presetOutlinedClasses\n : presetFillClasses\n : isOutlined\n ? outlinedColorClasses[resolvedColor]\n : fillColorClasses[resolvedColor],\n className,\n //\n )}\n {...props}\n >\n {children}\n </Comp>\n );\n};\n\nexport default Tag;\n"],"mappings":";;;;;;;;;AA0CA,MAAM,WAAW,GACf,qBACA,kDACA,2DACA,8CACA,wEACF;AAEA,MAAM,mBAA2C;CAC/C,SAAS;CACT,SAAS;CACT,SACE;CACF,SACE;CACF,QAAQ;AACV;AAEA,MAAM,uBAA+C;CACnD,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;AACV;AAMA,MAAM,oBAAoB,GACxB,sBACA,0DACA,iBACF;AAEA,MAAM,wBAAwB,GAAG,mCAAmC;AAEpE,MAAM,OAAO,EACX,WACA,SACA,OACA,UAAU,OACV,UACA,GAAG,YACQ;CACX,MAAM,EAAE,iBAAiB,UAAU;CACnC,MAAM,cAAc,cAAc;CAIlC,MAAM,kBAAkB,WAAW,aAAa,WAAW;CAC3D,MAAM,gBAAgB,SAAS,aAAa,SAAS;CAGrD,MAAM,aAAa,oBAAoB;CACvC,MAAM,SAAS,cAAc,aAAa;CAG1C,OACE,oBAHW,UAAU,OAAO,QAG5B;EACE,aAAU;EAGV,cAAY,SAAS,gBAAgB,KAAA;EACrC,WAAW,GACT,UACA,4BACA,uBACA,SACI,aACE,wBACA,oBACF,aACE,qBAAqB,iBACrB,iBAAiB,gBACvB,SAEF;EACA,GAAI;EAEH;CACG,CAAA;AAEV"}
1
+ {"version":3,"file":"Tag.mjs","names":[],"sources":["../src/components/atoms/tag.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\n\nimport { Slot } from '@radix-ui/react-slot';\n\nimport { useConfig } from '@repo/ui/providers';\nimport { cn } from '@repo/ui/utils';\n\nimport { INTERACTIVE_CHASSIS } from '../../lib/chassis';\nimport { type PresetColor } from '../../lib/colors';\n\ntype NativeSpanProps = React.ComponentProps<'span'> & {\n asChild?: boolean;\n};\n\nexport interface Props extends Omit<NativeSpanProps, 'variant' | 'color'> {\n /**\n * Fill style, aligned with `Button`'s vocabulary (#320). The pre-7.0\n * `'default'` spelling was removed — use `'filled'`, which renders\n * identically.\n */\n variant?: 'filled' | 'outlined';\n /**\n * Colour. Every value — the semantic states (`primary`/`success`/`warning`/\n * `danger`) as well as the palette shared with `Button` (`blue`, `red`,\n * `gold`, …) — resolves through the same `data-color` + `--tag-*` system\n * (#320), so any of them can be re-themed the same way.\n *\n * `success`/`warning` have no `Button` counterpart on purpose: a Tag marks\n * state, which is why antd's Tag also carries them while its Button does not.\n */\n color?:\n 'default' | 'primary' | 'success' | 'warning' | 'danger' | PresetColor;\n}\n\n// Base absorbed from core/badge's cva base + its `outline` variant, which Tag\n// always rendered as (#278 ③ / #294 Phase 4). The shared focus/aria/centering\n// set lives in INTERACTIVE_CHASSIS; a Tag adds badge geometry and its svg\n// sizing but — unlike Button — no `disabled:*` (a Tag is not disableable). The\n// rounded/padding leftovers are overridden by the atom classes below exactly as\n// before, so the rendered output is unchanged (verified against a pre-refactor\n// render matrix).\nconst TAG_BASE = cn(\n INTERACTIVE_CHASSIS,\n 'border w-fit whitespace-nowrap overflow-hidden',\n 'text-xs font-medium gap-1 transition-[color,box-shadow]',\n '[&>svg]:size-3 [&>svg]:pointer-events-none',\n 'text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground',\n);\n\n// Every colour — semantic states and shared presets alike — resolves from the\n// `--tag-*` custom properties that `globals.css` sets per `data-color` (#320).\n// Before 7.0 only the presets took this path while the states carried bespoke\n// Tailwind classes, which meant `[data-color]` hooks and `--tag-*` overrides\n// worked on some colours but silently not on others.\n//\n// --tag-bg the hue; the border in `outlined`\n// --tag-fg text colour (defaults to --tag-bg)\n// --tag-tint the fill behind `filled` (defaults to a 10% --tag-bg wash)\nconst fillClasses = cn('border-transparent bg-(--tag-tint) text-(--tag-fg)');\n\nconst outlinedClasses = cn('border-(--tag-bg) text-(--tag-fg)');\n\nconst Tag = ({\n className,\n variant,\n color,\n asChild = false,\n children,\n ...props\n}: Props) => {\n const { defaultProps } = useConfig();\n const tagDefaults = defaultProps?.tag as\n Partial<Pick<Props, 'variant' | 'color'>> | undefined;\n // An explicit prop wins over a `Config` default, which wins over the built-in\n // — the same resolution order `Button` uses.\n const resolvedVariant = variant ?? tagDefaults?.variant ?? 'filled';\n const resolvedColor = color ?? tagDefaults?.color ?? 'default';\n const isOutlined = resolvedVariant === 'outlined';\n const Comp = asChild ? Slot : 'span';\n\n return (\n <Comp\n data-slot=\"badge\"\n // Emitted for every colour, not just the presets, so consumers can hook\n // `[data-color]` / `[data-variant]` uniformly. `data-variant` is what\n // lets `globals.css` give `default` a different text colour when\n // outlined without reintroducing a second class path here.\n data-color={resolvedColor}\n data-variant={resolvedVariant}\n className={cn(\n TAG_BASE,\n 'rounded-full px-2.5 py-1',\n 'text-xs font-medium',\n isOutlined ? outlinedClasses : fillClasses,\n className,\n //\n )}\n {...props}\n >\n {children}\n </Comp>\n );\n};\n\nexport default Tag;\n"],"mappings":";;;;;;;;AA2CA,MAAM,WAAW,GACf,qBACA,kDACA,2DACA,8CACA,wEACF;AAWA,MAAM,cAAc,GAAG,oDAAoD;AAE3E,MAAM,kBAAkB,GAAG,mCAAmC;AAE9D,MAAM,OAAO,EACX,WACA,SACA,OACA,UAAU,OACV,UACA,GAAG,YACQ;CACX,MAAM,EAAE,iBAAiB,UAAU;CACnC,MAAM,cAAc,cAAc;CAIlC,MAAM,kBAAkB,WAAW,aAAa,WAAW;CAC3D,MAAM,gBAAgB,SAAS,aAAa,SAAS;CAIrD,OACE,oBAHW,UAAU,OAAO,QAG5B;EACE,aAAU;EAKV,cAAY;EACZ,gBAAc;EACd,WAAW,GACT,UACA,4BACA,uBAfa,oBAAoB,aAgBpB,kBAAkB,aAC/B,SAEF;EACA,GAAI;EAEH;CACG,CAAA;AAEV"}
@@ -9,9 +9,11 @@ import Input from "./input/index.mjs";
9
9
  import Popover from "./popover.mjs";
10
10
  import Progress from "./progress.mjs";
11
11
  import Radio from "./radio/index.mjs";
12
+ import RichTextEditor from "./rich-text-editor/rich-text-editor.mjs";
13
+ import "./rich-text-editor/index.mjs";
12
14
  import Select from "./select.mjs";
13
15
  import Skeleton from "./skeleton/index.mjs";
14
16
  import Slider from "./slider/slider.mjs";
15
17
  import Spin from "./spin.mjs";
16
18
  import Switch from "./switch.mjs";
17
- export { Button, Checkbox, ColorPicker, DatePicker, FloatButton, Input, Popover, Progress, Radio, Select, Skeleton, Slider, Spin, Switch, Tag, Typography };
19
+ export { Button, Checkbox, ColorPicker, DatePicker, FloatButton, Input, Popover, Progress, Radio, RichTextEditor, Select, Skeleton, Slider, Spin, Switch, Tag, Typography };
@@ -0,0 +1,7 @@
1
+ import { cn } from "../../../utils.mjs";
2
+ //#region src/components/atoms/rich-text-editor/content-classes.ts
3
+ const RICH_TEXT_CONTENT_CLASSES = cn("[&_.tiptap]:outline-none", "[&_.tiptap>*:first-child]:mt-0", "[&_.tiptap_h1]:mt-6", "[&_.tiptap_h1]:mb-2", "[&_.tiptap_h1]:text-2xl", "[&_.tiptap_h1]:font-bold", "[&_.tiptap_h2]:mt-5", "[&_.tiptap_h2]:mb-2", "[&_.tiptap_h2]:text-xl", "[&_.tiptap_h2]:font-bold", "[&_.tiptap_h3]:mt-4", "[&_.tiptap_h3]:mb-2", "[&_.tiptap_h3]:text-lg", "[&_.tiptap_h3]:font-semibold", "[&_.tiptap_h4]:mt-3", "[&_.tiptap_h4]:mb-1", "[&_.tiptap_h4]:text-base", "[&_.tiptap_h4]:font-semibold", "[&_.tiptap_ul]:my-2", "[&_.tiptap_ul]:list-disc", "[&_.tiptap_ul]:pl-5", "[&_.tiptap_ol]:my-2", "[&_.tiptap_ol]:list-decimal", "[&_.tiptap_ol]:pl-5", "[&_.tiptap_li]:my-1", "[&_.tiptap_blockquote]:my-2", "[&_.tiptap_blockquote]:border-l-2", "[&_.tiptap_blockquote]:border-gray-300", "[&_.tiptap_blockquote]:pl-3", "[&_.tiptap_blockquote]:text-gray-600", "[&_.tiptap_blockquote]:italic", "[&_.tiptap_pre]:overflow-x-auto", "[&_.tiptap_pre]:my-2", "[&_.tiptap_pre]:rounded", "[&_.tiptap_pre]:bg-gray-900", "[&_.tiptap_pre]:p-3", "[&_.tiptap_pre]:font-mono", "[&_.tiptap_pre]:text-sm", "[&_.tiptap_pre]:text-gray-100", "[&_.tiptap_pre_code]:bg-transparent", "[&_.tiptap_pre_code]:p-0", "[&_.tiptap_pre_code]:text-inherit", "[&_.tiptap_code]:rounded", "[&_.tiptap_code]:bg-gray-100", "[&_.tiptap_code]:px-1", "[&_.tiptap_code]:py-0.5", "[&_.tiptap_code]:font-mono", "[&_.tiptap_code]:text-[0.85em]", "[&_.tiptap_hr]:my-4", "[&_.tiptap_hr]:border-gray-200", "[&_.tiptap_a]:text-blue-600", "[&_.tiptap_a]:underline", "[&_.tiptap_a]:underline-offset-2", "[&_.tiptap_p.is-editor-empty:first-child::before]:pointer-events-none", "[&_.tiptap_p.is-editor-empty:first-child::before]:float-left", "[&_.tiptap_p.is-editor-empty:first-child::before]:h-0", "[&_.tiptap_p.is-editor-empty:first-child::before]:text-gray-400", "[&_.tiptap_p.is-editor-empty:first-child::before]:content-[attr(data-placeholder)]");
4
+ //#endregion
5
+ export { RICH_TEXT_CONTENT_CLASSES };
6
+
7
+ //# sourceMappingURL=content-classes.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-classes.mjs","names":[],"sources":["../../../../src/components/atoms/rich-text-editor/content-classes.ts"],"sourcesContent":["import { cn } from '@repo/ui/utils';\n\n// The package ships no global Tailwind preflight (see src/globals.css), and a\n// host that runs its own preflight (most do) resets bare h1-h6/ul/ol/blockquote\n// to look like plain text. Since the toolbar can now produce all of these\n// nodes, they need their own scoped typography here or toggling them would be\n// visibly a no-op. Selectors are written out per Tailwind utility (not built\n// via string interpolation) because v4 only extracts class candidates that\n// appear as literal strings in source (see popover.tsx's arrow-class comment).\nexport const RICH_TEXT_CONTENT_CLASSES = cn(\n '[&_.tiptap]:outline-none',\n // Every block element (p/h1/ul/blockquote/...) carries its own UA top\n // margin — without this, the first one stacks on top of the box's own\n // py-2, doubling the padding visually.\n '[&_.tiptap>*:first-child]:mt-0',\n\n '[&_.tiptap_h1]:mt-6',\n '[&_.tiptap_h1]:mb-2',\n '[&_.tiptap_h1]:text-2xl',\n '[&_.tiptap_h1]:font-bold',\n '[&_.tiptap_h2]:mt-5',\n '[&_.tiptap_h2]:mb-2',\n '[&_.tiptap_h2]:text-xl',\n '[&_.tiptap_h2]:font-bold',\n '[&_.tiptap_h3]:mt-4',\n '[&_.tiptap_h3]:mb-2',\n '[&_.tiptap_h3]:text-lg',\n '[&_.tiptap_h3]:font-semibold',\n '[&_.tiptap_h4]:mt-3',\n '[&_.tiptap_h4]:mb-1',\n '[&_.tiptap_h4]:text-base',\n '[&_.tiptap_h4]:font-semibold',\n\n '[&_.tiptap_ul]:my-2',\n '[&_.tiptap_ul]:list-disc',\n '[&_.tiptap_ul]:pl-5',\n '[&_.tiptap_ol]:my-2',\n '[&_.tiptap_ol]:list-decimal',\n '[&_.tiptap_ol]:pl-5',\n '[&_.tiptap_li]:my-1',\n\n '[&_.tiptap_blockquote]:my-2',\n '[&_.tiptap_blockquote]:border-l-2',\n '[&_.tiptap_blockquote]:border-gray-300',\n '[&_.tiptap_blockquote]:pl-3',\n '[&_.tiptap_blockquote]:text-gray-600',\n '[&_.tiptap_blockquote]:italic',\n\n // A long unwrapped code line would otherwise blow out the box width.\n '[&_.tiptap_pre]:overflow-x-auto',\n '[&_.tiptap_pre]:my-2',\n '[&_.tiptap_pre]:rounded',\n '[&_.tiptap_pre]:bg-gray-900',\n '[&_.tiptap_pre]:p-3',\n '[&_.tiptap_pre]:font-mono',\n '[&_.tiptap_pre]:text-sm',\n '[&_.tiptap_pre]:text-gray-100',\n // Reset the inline `code` treatment below when it's nested inside `pre`,\n // so a code block doesn't get a second (redundant) chip background.\n '[&_.tiptap_pre_code]:bg-transparent',\n '[&_.tiptap_pre_code]:p-0',\n '[&_.tiptap_pre_code]:text-inherit',\n '[&_.tiptap_code]:rounded',\n '[&_.tiptap_code]:bg-gray-100',\n '[&_.tiptap_code]:px-1',\n '[&_.tiptap_code]:py-0.5',\n '[&_.tiptap_code]:font-mono',\n '[&_.tiptap_code]:text-[0.85em]',\n\n '[&_.tiptap_hr]:my-4',\n '[&_.tiptap_hr]:border-gray-200',\n\n '[&_.tiptap_a]:text-blue-600',\n '[&_.tiptap_a]:underline',\n '[&_.tiptap_a]:underline-offset-2',\n\n '[&_.tiptap_p.is-editor-empty:first-child::before]:pointer-events-none',\n '[&_.tiptap_p.is-editor-empty:first-child::before]:float-left',\n '[&_.tiptap_p.is-editor-empty:first-child::before]:h-0',\n '[&_.tiptap_p.is-editor-empty:first-child::before]:text-gray-400',\n '[&_.tiptap_p.is-editor-empty:first-child::before]:content-[attr(data-placeholder)]',\n);\n"],"mappings":";;AASA,MAAa,4BAA4B,GACvC,4BAIA,kCAEA,uBACA,uBACA,2BACA,4BACA,uBACA,uBACA,0BACA,4BACA,uBACA,uBACA,0BACA,gCACA,uBACA,uBACA,4BACA,gCAEA,uBACA,4BACA,uBACA,uBACA,+BACA,uBACA,uBAEA,+BACA,qCACA,0CACA,+BACA,wCACA,iCAGA,mCACA,wBACA,2BACA,+BACA,uBACA,6BACA,2BACA,iCAGA,uCACA,4BACA,qCACA,4BACA,gCACA,yBACA,2BACA,8BACA,kCAEA,uBACA,kCAEA,+BACA,2BACA,oCAEA,yEACA,gEACA,yDACA,mEACA,oFACF"}
@@ -0,0 +1,3 @@
1
+ import { ToolbarItem, ToolbarPreset } from "./types.mjs";
2
+ import RichTextEditor, { Props } from "./rich-text-editor.mjs";
3
+ export { RichTextEditor as default };
@@ -0,0 +1,24 @@
1
+ import { ToolbarItem, ToolbarPreset } from "./types.mjs";
2
+ //#region src/components/atoms/rich-text-editor/rich-text-editor.d.ts
3
+ interface Props {
4
+ value?: string;
5
+ placeholder?: string;
6
+ className?: string;
7
+ classNames?: {
8
+ toolbar?: string;
9
+ content?: string;
10
+ };
11
+ /**
12
+ * `true` shows every built-in preset; an array shows only the listed
13
+ * presets, in the given order. Omitted or `false` renders no toolbar,
14
+ * matching the original (toolbar-less) output.
15
+ */
16
+ toolbar?: boolean | ToolbarPreset[];
17
+ /** Extra buttons appended after the built-in presets. */
18
+ toolbarItems?: ToolbarItem[];
19
+ onChange?: (value: string) => void;
20
+ }
21
+ declare const RichTextEditor: ({ value, placeholder, className, classNames, toolbar, toolbarItems, onChange }: Props) => import("react").JSX.Element;
22
+ //#endregion
23
+ export { Props, RichTextEditor as default };
24
+ //# sourceMappingURL=rich-text-editor.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rich-text-editor.d.mts","names":[],"sources":["../../../../src/components/atoms/rich-text-editor/rich-text-editor.tsx"],"mappings":";;UAgBiB;EACf;EACA;EACA;EACA;IACE;IACA;;;;;;;EAOF,oBAAoB;;EAEpB,eAAe;EACf,YAAY;;cAGR,mBAAkB,OAAA,aAAA,WAAA,YAAA,SAAA,cAAA,YAQrB,0BAAK,IAAA"}
@@ -0,0 +1,55 @@
1
+ "use client";
2
+ import { cn } from "../../../utils.mjs";
3
+ import { RICH_TEXT_CONTENT_CLASSES } from "./content-classes.mjs";
4
+ import { DEFAULT_TOOLBAR_PRESETS } from "./toolbar-presets.mjs";
5
+ import Toolbar from "./toolbar.mjs";
6
+ import { useEffect } from "react";
7
+ import { jsx, jsxs } from "react/jsx-runtime";
8
+ import Placeholder from "@tiptap/extension-placeholder";
9
+ import { TextStyleKit } from "@tiptap/extension-text-style";
10
+ import { EditorContent, useEditor } from "@tiptap/react";
11
+ import StarterKit from "@tiptap/starter-kit";
12
+ //#region src/components/atoms/rich-text-editor/rich-text-editor.tsx
13
+ const RichTextEditor = ({ value = "", placeholder = "Enter text...", className, classNames, toolbar = false, toolbarItems, onChange }) => {
14
+ const presets = toolbar === true ? DEFAULT_TOOLBAR_PRESETS : toolbar || [];
15
+ const showToolbar = presets.length > 0 || (toolbarItems?.length ?? 0) > 0;
16
+ const editor = useEditor({
17
+ immediatelyRender: false,
18
+ extensions: [
19
+ StarterKit,
20
+ Placeholder.configure({ placeholder }),
21
+ TextStyleKit.configure({
22
+ fontFamily: false,
23
+ lineHeight: false,
24
+ backgroundColor: false
25
+ })
26
+ ],
27
+ content: value,
28
+ onBlur: ({ editor: e }) => {
29
+ onChange?.(e.getHTML());
30
+ },
31
+ shouldRerenderOnTransaction: showToolbar
32
+ });
33
+ useEffect(() => {
34
+ if (!editor) return;
35
+ if (editor.getHTML() !== value) editor.commands.setContent(value, { emitUpdate: false });
36
+ }, [value, editor]);
37
+ return /* @__PURE__ */ jsxs("div", {
38
+ "data-slot": "rich-text-editor",
39
+ className: cn("rounded border border-gray-200 bg-white text-sm text-gray-800", className),
40
+ children: [showToolbar && editor && /* @__PURE__ */ jsx(Toolbar, {
41
+ editor,
42
+ presets,
43
+ items: toolbarItems,
44
+ className: classNames?.toolbar
45
+ }), /* @__PURE__ */ jsx("div", {
46
+ "data-slot": "rich-text-editor-content",
47
+ className: cn("min-h-20 px-3 py-2", RICH_TEXT_CONTENT_CLASSES, classNames?.content),
48
+ children: /* @__PURE__ */ jsx(EditorContent, { editor })
49
+ })]
50
+ });
51
+ };
52
+ //#endregion
53
+ export { RichTextEditor as default };
54
+
55
+ //# sourceMappingURL=rich-text-editor.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rich-text-editor.mjs","names":[],"sources":["../../../../src/components/atoms/rich-text-editor/rich-text-editor.tsx"],"sourcesContent":["'use client';\n\nimport { useEffect } from 'react';\n\nimport Placeholder from '@tiptap/extension-placeholder';\nimport { TextStyleKit } from '@tiptap/extension-text-style';\nimport { EditorContent, useEditor } from '@tiptap/react';\nimport StarterKit from '@tiptap/starter-kit';\n\nimport { cn } from '@repo/ui/utils';\n\nimport { RICH_TEXT_CONTENT_CLASSES } from './content-classes';\nimport Toolbar from './toolbar';\nimport { DEFAULT_TOOLBAR_PRESETS } from './toolbar-presets';\nimport type { ToolbarItem, ToolbarPreset } from './types';\n\nexport interface Props {\n value?: string;\n placeholder?: string;\n className?: string;\n classNames?: {\n toolbar?: string;\n content?: string;\n };\n /**\n * `true` shows every built-in preset; an array shows only the listed\n * presets, in the given order. Omitted or `false` renders no toolbar,\n * matching the original (toolbar-less) output.\n */\n toolbar?: boolean | ToolbarPreset[];\n /** Extra buttons appended after the built-in presets. */\n toolbarItems?: ToolbarItem[];\n onChange?: (value: string) => void;\n}\n\nconst RichTextEditor = ({\n value = '',\n placeholder = 'Enter text...',\n className,\n classNames,\n toolbar = false,\n toolbarItems,\n onChange,\n}: Props) => {\n const presets = toolbar === true ? DEFAULT_TOOLBAR_PRESETS : toolbar || [];\n const showToolbar = presets.length > 0 || (toolbarItems?.length ?? 0) > 0;\n\n const editor = useEditor({\n // SSR renders every exported component without effects running, so the\n // editor must not touch the DOM during that first pass — deferring\n // creation to mount keeps `renderToStaticMarkup` from throwing.\n immediatelyRender: false,\n extensions: [\n StarterKit,\n Placeholder.configure({ placeholder }),\n TextStyleKit.configure({\n fontFamily: false,\n lineHeight: false,\n backgroundColor: false,\n }),\n ],\n content: value,\n onBlur: ({ editor: e }) => {\n onChange?.(e.getHTML());\n },\n // @tiptap/react v3 only re-renders on selection/transaction changes when\n // explicitly opted in — the toolbar's isActive()/getAttributes() reads\n // need that to reflect the caret position live.\n shouldRerenderOnTransaction: showToolbar,\n });\n\n useEffect(() => {\n if (!editor) {\n return;\n }\n\n const current = editor.getHTML();\n\n if (current !== value) {\n editor.commands.setContent(value, { emitUpdate: false });\n }\n }, [value, editor]);\n\n return (\n <div\n data-slot=\"rich-text-editor\"\n className={cn(\n 'rounded border border-gray-200 bg-white text-sm text-gray-800',\n className,\n //\n )}\n >\n {showToolbar && editor && (\n <Toolbar\n editor={editor}\n presets={presets}\n items={toolbarItems}\n className={classNames?.toolbar}\n />\n )}\n <div\n data-slot=\"rich-text-editor-content\"\n className={cn(\n 'min-h-20 px-3 py-2',\n RICH_TEXT_CONTENT_CLASSES,\n classNames?.content,\n //\n )}\n >\n <EditorContent editor={editor} />\n </div>\n </div>\n );\n};\n\nexport default RichTextEditor;\n"],"mappings":";;;;;;;;;;;;AAmCA,MAAM,kBAAkB,EACtB,QAAQ,IACR,cAAc,iBACd,WACA,YACA,UAAU,OACV,cACA,eACW;CACX,MAAM,UAAU,YAAY,OAAO,0BAA0B,WAAW,CAAC;CACzE,MAAM,cAAc,QAAQ,SAAS,MAAM,cAAc,UAAU,KAAK;CAExE,MAAM,SAAS,UAAU;EAIvB,mBAAmB;EACnB,YAAY;GACV;GACA,YAAY,UAAU,EAAE,YAAY,CAAC;GACrC,aAAa,UAAU;IACrB,YAAY;IACZ,YAAY;IACZ,iBAAiB;GACnB,CAAC;EACH;EACA,SAAS;EACT,SAAS,EAAE,QAAQ,QAAQ;GACzB,WAAW,EAAE,QAAQ,CAAC;EACxB;EAIA,6BAA6B;CAC/B,CAAC;CAED,gBAAgB;EACd,IAAI,CAAC,QACH;EAKF,IAFgB,OAAO,QAEb,MAAM,OACd,OAAO,SAAS,WAAW,OAAO,EAAE,YAAY,MAAM,CAAC;CAE3D,GAAG,CAAC,OAAO,MAAM,CAAC;CAElB,OACE,qBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,iEACA,SAEF;EANF,UAAA,CAQG,eAAe,UACd,oBAAC,SAAD;GACU;GACC;GACT,OAAO;GACP,WAAW,YAAY;EACxB,CAAA,GAEH,oBAAC,OAAD;GACE,aAAU;GACV,WAAW,GACT,sBACA,2BACA,YAAY,OAEd;GAEA,UAAA,oBAAC,eAAD,EAAuB,OAAS,CAAA;EAC7B,CAAA,CACF;;AAET"}
@@ -0,0 +1,16 @@
1
+ import { cn } from "../../../utils.mjs";
2
+ import Button from "../../../Button.mjs";
3
+ import { jsx } from "react/jsx-runtime";
4
+ //#region src/components/atoms/rich-text-editor/toolbar-button.tsx
5
+ const ToolbarButton = ({ active, className, ...props }) => /* @__PURE__ */ jsx(Button, {
6
+ ...props,
7
+ type: "text",
8
+ size: "small",
9
+ shape: "default",
10
+ "aria-pressed": active,
11
+ className: cn(active && "bg-accent", className)
12
+ });
13
+ //#endregion
14
+ export { ToolbarButton as default };
15
+
16
+ //# sourceMappingURL=toolbar-button.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolbar-button.mjs","names":[],"sources":["../../../../src/components/atoms/rich-text-editor/toolbar-button.tsx"],"sourcesContent":["import { cn } from '@repo/ui/utils';\n\nimport Button, { type Props as ButtonProps } from '../button';\n\nexport interface ToolbarButtonProps extends Omit<\n ButtonProps,\n 'type' | 'shape' | 'size'\n> {\n active?: boolean;\n}\n\nconst ToolbarButton = ({ active, className, ...props }: ToolbarButtonProps) => (\n <Button\n // Spread first: when this button sits inside a `Popover` trigger\n // (`asChild`), Radix injects its own native `type=\"button\"` onto us for\n // form-submit safety — that's a different `type` than Button's own\n // antd-style color/variant switch, and if it landed after these three,\n // it would silently override `type=\"text\"` and fall through to the\n // `outlined` variant's border.\n {...props}\n type=\"text\"\n size=\"small\"\n shape=\"default\"\n aria-pressed={active}\n className={cn(active && 'bg-accent', className)}\n />\n);\n\nexport default ToolbarButton;\n"],"mappings":";;;;AAWA,MAAM,iBAAiB,EAAE,QAAQ,WAAW,GAAG,YAC7C,oBAAC,QAAD;CAOE,GAAI;CACJ,MAAK;CACL,MAAK;CACL,OAAM;CACN,gBAAc;CACd,WAAW,GAAG,UAAU,aAAa,SAAS;AAC/C,CAAA"}
@@ -0,0 +1,209 @@
1
+ "use client";
2
+ import Button from "../../../Button.mjs";
3
+ import Popover from "../popover.mjs";
4
+ import ColorPicker from "../color-picker.mjs";
5
+ import Input from "../input/index.mjs";
6
+ import ToolbarButton from "./toolbar-button.mjs";
7
+ import Select from "../select.mjs";
8
+ import { useState } from "react";
9
+ import { Bold, Code, Code2, Italic, Link, List, ListOrdered, Minus, Quote, Redo2, Strikethrough, Underline, Undo2 } from "lucide-react";
10
+ import { jsx, jsxs } from "react/jsx-runtime";
11
+ //#region src/components/atoms/rich-text-editor/toolbar-presets.tsx
12
+ const FONT_SIZE_OPTIONS = [
13
+ {
14
+ label: "12",
15
+ value: "12px"
16
+ },
17
+ {
18
+ label: "14",
19
+ value: "14px"
20
+ },
21
+ {
22
+ label: "16",
23
+ value: "16px"
24
+ },
25
+ {
26
+ label: "18",
27
+ value: "18px"
28
+ },
29
+ {
30
+ label: "24",
31
+ value: "24px"
32
+ },
33
+ {
34
+ label: "32",
35
+ value: "32px"
36
+ }
37
+ ];
38
+ const HEADING_LEVELS = [
39
+ 1,
40
+ 2,
41
+ 3,
42
+ 4
43
+ ];
44
+ const HEADING_OPTIONS = [{
45
+ label: "Paragraph",
46
+ value: "paragraph"
47
+ }, ...HEADING_LEVELS.map((level) => ({
48
+ label: `Heading ${level}`,
49
+ value: String(level)
50
+ }))];
51
+ const LinkControl = ({ editor }) => {
52
+ const [open, setOpen] = useState(false);
53
+ const [href, setHref] = useState("");
54
+ const apply = () => {
55
+ const next = href.trim();
56
+ if (next) editor.chain().focus().extendMarkRange("link").setLink({ href: next }).run();
57
+ else editor.chain().focus().unsetLink().run();
58
+ setOpen(false);
59
+ };
60
+ return /* @__PURE__ */ jsx(Popover, {
61
+ placement: "bottom",
62
+ open,
63
+ onOpenChange: (next) => {
64
+ if (next) setHref(editor.getAttributes("link").href ?? "");
65
+ setOpen(next);
66
+ },
67
+ content: /* @__PURE__ */ jsxs("div", {
68
+ className: "flex items-center gap-2",
69
+ children: [/* @__PURE__ */ jsx(Input, {
70
+ value: href,
71
+ placeholder: "https://",
72
+ className: "w-48",
73
+ onChange: (e) => setHref(e.target.value),
74
+ onKeyDown: (e) => {
75
+ if (e.key === "Enter") {
76
+ e.preventDefault();
77
+ apply();
78
+ }
79
+ }
80
+ }), /* @__PURE__ */ jsx(Button, {
81
+ size: "small",
82
+ onClick: apply,
83
+ children: "Apply"
84
+ })]
85
+ }),
86
+ children: /* @__PURE__ */ jsx(ToolbarButton, {
87
+ icon: /* @__PURE__ */ jsx(Link, {}),
88
+ "aria-label": "Link",
89
+ active: editor.isActive("link")
90
+ })
91
+ });
92
+ };
93
+ const TOOLBAR_PRESET_RENDERERS = {
94
+ undo: (editor) => /* @__PURE__ */ jsx(ToolbarButton, {
95
+ icon: /* @__PURE__ */ jsx(Undo2, {}),
96
+ "aria-label": "Undo",
97
+ disabled: !editor.can().undo(),
98
+ onClick: () => editor.chain().focus().undo().run()
99
+ }, "undo"),
100
+ redo: (editor) => /* @__PURE__ */ jsx(ToolbarButton, {
101
+ icon: /* @__PURE__ */ jsx(Redo2, {}),
102
+ "aria-label": "Redo",
103
+ disabled: !editor.can().redo(),
104
+ onClick: () => editor.chain().focus().redo().run()
105
+ }, "redo"),
106
+ heading: (editor) => {
107
+ const activeLevel = HEADING_LEVELS.find((level) => editor.isActive("heading", { level }));
108
+ return /* @__PURE__ */ jsx(Select, {
109
+ className: "h-6 w-28",
110
+ placeholder: "Style",
111
+ options: HEADING_OPTIONS,
112
+ value: activeLevel ? String(activeLevel) : "paragraph",
113
+ onChange: (value) => value === "paragraph" ? editor.chain().setParagraph().run() : editor.chain().setHeading({ level: Number(value) }).run()
114
+ }, "heading");
115
+ },
116
+ bold: (editor) => /* @__PURE__ */ jsx(ToolbarButton, {
117
+ icon: /* @__PURE__ */ jsx(Bold, {}),
118
+ "aria-label": "Bold",
119
+ active: editor.isActive("bold"),
120
+ onClick: () => editor.chain().focus().toggleBold().run()
121
+ }, "bold"),
122
+ italic: (editor) => /* @__PURE__ */ jsx(ToolbarButton, {
123
+ icon: /* @__PURE__ */ jsx(Italic, {}),
124
+ "aria-label": "Italic",
125
+ active: editor.isActive("italic"),
126
+ onClick: () => editor.chain().focus().toggleItalic().run()
127
+ }, "italic"),
128
+ underline: (editor) => /* @__PURE__ */ jsx(ToolbarButton, {
129
+ icon: /* @__PURE__ */ jsx(Underline, {}),
130
+ "aria-label": "Underline",
131
+ active: editor.isActive("underline"),
132
+ onClick: () => editor.chain().focus().toggleUnderline().run()
133
+ }, "underline"),
134
+ strike: (editor) => /* @__PURE__ */ jsx(ToolbarButton, {
135
+ icon: /* @__PURE__ */ jsx(Strikethrough, {}),
136
+ "aria-label": "Strikethrough",
137
+ active: editor.isActive("strike"),
138
+ onClick: () => editor.chain().focus().toggleStrike().run()
139
+ }, "strike"),
140
+ code: (editor) => /* @__PURE__ */ jsx(ToolbarButton, {
141
+ icon: /* @__PURE__ */ jsx(Code, {}),
142
+ "aria-label": "Inline code",
143
+ active: editor.isActive("code"),
144
+ onClick: () => editor.chain().focus().toggleCode().run()
145
+ }, "code"),
146
+ bulletList: (editor) => /* @__PURE__ */ jsx(ToolbarButton, {
147
+ icon: /* @__PURE__ */ jsx(List, {}),
148
+ "aria-label": "Bullet list",
149
+ active: editor.isActive("bulletList"),
150
+ onClick: () => editor.chain().focus().toggleBulletList().run()
151
+ }, "bulletList"),
152
+ orderedList: (editor) => /* @__PURE__ */ jsx(ToolbarButton, {
153
+ icon: /* @__PURE__ */ jsx(ListOrdered, {}),
154
+ "aria-label": "Ordered list",
155
+ active: editor.isActive("orderedList"),
156
+ onClick: () => editor.chain().focus().toggleOrderedList().run()
157
+ }, "orderedList"),
158
+ blockquote: (editor) => /* @__PURE__ */ jsx(ToolbarButton, {
159
+ icon: /* @__PURE__ */ jsx(Quote, {}),
160
+ "aria-label": "Blockquote",
161
+ active: editor.isActive("blockquote"),
162
+ onClick: () => editor.chain().focus().toggleBlockquote().run()
163
+ }, "blockquote"),
164
+ codeBlock: (editor) => /* @__PURE__ */ jsx(ToolbarButton, {
165
+ icon: /* @__PURE__ */ jsx(Code2, {}),
166
+ "aria-label": "Code block",
167
+ active: editor.isActive("codeBlock"),
168
+ onClick: () => editor.chain().focus().toggleCodeBlock().run()
169
+ }, "codeBlock"),
170
+ horizontalRule: (editor) => /* @__PURE__ */ jsx(ToolbarButton, {
171
+ icon: /* @__PURE__ */ jsx(Minus, {}),
172
+ "aria-label": "Horizontal rule",
173
+ onClick: () => editor.chain().focus().setHorizontalRule().run()
174
+ }, "horizontalRule"),
175
+ link: (editor) => /* @__PURE__ */ jsx(LinkControl, { editor }, "link"),
176
+ fontSize: (editor) => /* @__PURE__ */ jsx(Select, {
177
+ className: "h-6 w-20",
178
+ placeholder: "Size",
179
+ options: FONT_SIZE_OPTIONS,
180
+ value: editor.getAttributes("textStyle").fontSize ?? void 0,
181
+ onChange: (value) => editor.chain().setFontSize(value).run()
182
+ }, "fontSize"),
183
+ color: (editor) => /* @__PURE__ */ jsx(ColorPicker, {
184
+ value: editor.getAttributes("textStyle").color || "#000000",
185
+ onChange: (value) => editor.chain().setColor(value).run()
186
+ }, "color")
187
+ };
188
+ const DEFAULT_TOOLBAR_PRESETS = [
189
+ "undo",
190
+ "redo",
191
+ "heading",
192
+ "bold",
193
+ "italic",
194
+ "underline",
195
+ "strike",
196
+ "code",
197
+ "bulletList",
198
+ "orderedList",
199
+ "blockquote",
200
+ "codeBlock",
201
+ "horizontalRule",
202
+ "link",
203
+ "fontSize",
204
+ "color"
205
+ ];
206
+ //#endregion
207
+ export { DEFAULT_TOOLBAR_PRESETS, TOOLBAR_PRESET_RENDERERS };
208
+
209
+ //# sourceMappingURL=toolbar-presets.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolbar-presets.mjs","names":["LinkIcon"],"sources":["../../../../src/components/atoms/rich-text-editor/toolbar-presets.tsx"],"sourcesContent":["'use client';\n\nimport { type ReactNode, useState } from 'react';\n\nimport type { Editor } from '@tiptap/core';\nimport {\n Bold,\n Code,\n Code2,\n Italic,\n Link as LinkIcon,\n List,\n ListOrdered,\n Minus,\n Quote,\n Redo2,\n Strikethrough,\n Underline,\n Undo2,\n} from 'lucide-react';\n\nimport Button from '../button';\nimport ColorPicker from '../color-picker';\nimport Input from '../input';\nimport Popover from '../popover';\nimport Select from '../select';\nimport ToolbarButton from './toolbar-button';\nimport type { ToolbarPreset } from './types';\n\nconst FONT_SIZE_OPTIONS = [\n { label: '12', value: '12px' },\n { label: '14', value: '14px' },\n { label: '16', value: '16px' },\n { label: '18', value: '18px' },\n { label: '24', value: '24px' },\n { label: '32', value: '32px' },\n];\n\nconst HEADING_LEVELS = [1, 2, 3, 4] as const;\n\nconst HEADING_OPTIONS = [\n { label: 'Paragraph', value: 'paragraph' },\n ...HEADING_LEVELS.map(level => ({\n label: `Heading ${level}`,\n value: String(level),\n })),\n];\n\n// Owns its own open/href state, so it has to be a real component (not a\n// plain render function like the other presets) for the hooks below to be\n// valid.\nconst LinkControl = ({ editor }: { editor: Editor }) => {\n const [open, setOpen] = useState(false);\n const [href, setHref] = useState('');\n\n const apply = () => {\n const next = href.trim();\n\n if (next) {\n editor\n .chain()\n .focus()\n .extendMarkRange('link')\n .setLink({ href: next })\n .run();\n } else {\n editor.chain().focus().unsetLink().run();\n }\n setOpen(false);\n };\n\n return (\n <Popover\n placement=\"bottom\"\n open={open}\n onOpenChange={next => {\n if (next) {\n setHref(editor.getAttributes('link').href ?? '');\n }\n setOpen(next);\n }}\n content={\n <div className=\"flex items-center gap-2\">\n <Input\n value={href}\n placeholder=\"https://\"\n className=\"w-48\"\n onChange={e => setHref(e.target.value)}\n onKeyDown={e => {\n if (e.key === 'Enter') {\n e.preventDefault();\n apply();\n }\n }}\n />\n <Button size=\"small\" onClick={apply}>\n Apply\n </Button>\n </div>\n }\n >\n <ToolbarButton\n icon={<LinkIcon />}\n aria-label=\"Link\"\n active={editor.isActive('link')}\n />\n </Popover>\n );\n};\n\nexport const TOOLBAR_PRESET_RENDERERS: Record<\n ToolbarPreset,\n (editor: Editor) => ReactNode\n> = {\n undo: editor => (\n <ToolbarButton\n key=\"undo\"\n icon={<Undo2 />}\n aria-label=\"Undo\"\n disabled={!editor.can().undo()}\n onClick={() => editor.chain().focus().undo().run()}\n />\n ),\n redo: editor => (\n <ToolbarButton\n key=\"redo\"\n icon={<Redo2 />}\n aria-label=\"Redo\"\n disabled={!editor.can().redo()}\n onClick={() => editor.chain().focus().redo().run()}\n />\n ),\n heading: editor => {\n const activeLevel = HEADING_LEVELS.find(level =>\n editor.isActive('heading', { level }),\n );\n\n return (\n <Select\n key=\"heading\"\n className=\"h-6 w-28\"\n placeholder=\"Style\"\n options={HEADING_OPTIONS}\n value={activeLevel ? String(activeLevel) : 'paragraph'}\n // No `.focus()` here — the Select is still open when this fires,\n // and refocusing the editor mid-selection dismisses it early (same\n // class of bug as the color picker below).\n onChange={value =>\n value === 'paragraph'\n ? editor.chain().setParagraph().run()\n : editor\n .chain()\n .setHeading({ level: Number(value) as 1 | 2 | 3 | 4 })\n .run()\n }\n />\n );\n },\n bold: editor => (\n <ToolbarButton\n key=\"bold\"\n icon={<Bold />}\n aria-label=\"Bold\"\n active={editor.isActive('bold')}\n onClick={() => editor.chain().focus().toggleBold().run()}\n />\n ),\n italic: editor => (\n <ToolbarButton\n key=\"italic\"\n icon={<Italic />}\n aria-label=\"Italic\"\n active={editor.isActive('italic')}\n onClick={() => editor.chain().focus().toggleItalic().run()}\n />\n ),\n underline: editor => (\n <ToolbarButton\n key=\"underline\"\n icon={<Underline />}\n aria-label=\"Underline\"\n active={editor.isActive('underline')}\n onClick={() => editor.chain().focus().toggleUnderline().run()}\n />\n ),\n strike: editor => (\n <ToolbarButton\n key=\"strike\"\n icon={<Strikethrough />}\n aria-label=\"Strikethrough\"\n active={editor.isActive('strike')}\n onClick={() => editor.chain().focus().toggleStrike().run()}\n />\n ),\n code: editor => (\n <ToolbarButton\n key=\"code\"\n icon={<Code />}\n aria-label=\"Inline code\"\n active={editor.isActive('code')}\n onClick={() => editor.chain().focus().toggleCode().run()}\n />\n ),\n bulletList: editor => (\n <ToolbarButton\n key=\"bulletList\"\n icon={<List />}\n aria-label=\"Bullet list\"\n active={editor.isActive('bulletList')}\n onClick={() => editor.chain().focus().toggleBulletList().run()}\n />\n ),\n orderedList: editor => (\n <ToolbarButton\n key=\"orderedList\"\n icon={<ListOrdered />}\n aria-label=\"Ordered list\"\n active={editor.isActive('orderedList')}\n onClick={() => editor.chain().focus().toggleOrderedList().run()}\n />\n ),\n blockquote: editor => (\n <ToolbarButton\n key=\"blockquote\"\n icon={<Quote />}\n aria-label=\"Blockquote\"\n active={editor.isActive('blockquote')}\n onClick={() => editor.chain().focus().toggleBlockquote().run()}\n />\n ),\n codeBlock: editor => (\n <ToolbarButton\n key=\"codeBlock\"\n icon={<Code2 />}\n aria-label=\"Code block\"\n active={editor.isActive('codeBlock')}\n onClick={() => editor.chain().focus().toggleCodeBlock().run()}\n />\n ),\n horizontalRule: editor => (\n <ToolbarButton\n key=\"horizontalRule\"\n icon={<Minus />}\n aria-label=\"Horizontal rule\"\n onClick={() => editor.chain().focus().setHorizontalRule().run()}\n />\n ),\n link: editor => <LinkControl key=\"link\" editor={editor} />,\n fontSize: editor => (\n <Select\n key=\"fontSize\"\n className=\"h-6 w-20\"\n placeholder=\"Size\"\n options={FONT_SIZE_OPTIONS}\n value={editor.getAttributes('textStyle').fontSize ?? undefined}\n // No `.focus()` — see the `heading` preset above.\n onChange={value => editor.chain().setFontSize(value).run()}\n />\n ),\n color: editor => (\n <ColorPicker\n key=\"color\"\n value={editor.getAttributes('textStyle').color || '#000000'}\n // No `.focus()`: react-colorful fires `onChange` continuously while\n // dragging, and refocusing the editor on every tick moves DOM focus\n // out from under the still-open popover, which Radix reads as an\n // outside interaction and dismisses immediately (ui-kit reported\n // symptom: \"picker closes as soon as you try to change the color\").\n // The mark still applies to the stored selection without it.\n onChange={value => editor.chain().setColor(value).run()}\n />\n ),\n};\n\nexport const DEFAULT_TOOLBAR_PRESETS: ToolbarPreset[] = [\n 'undo',\n 'redo',\n 'heading',\n 'bold',\n 'italic',\n 'underline',\n 'strike',\n 'code',\n 'bulletList',\n 'orderedList',\n 'blockquote',\n 'codeBlock',\n 'horizontalRule',\n 'link',\n 'fontSize',\n 'color',\n];\n"],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import { cn } from "../../../utils.mjs";
2
+ import ToolbarButton from "./toolbar-button.mjs";
3
+ import { TOOLBAR_PRESET_RENDERERS } from "./toolbar-presets.mjs";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ //#region src/components/atoms/rich-text-editor/toolbar.tsx
6
+ const Toolbar = ({ editor, presets, items, className }) => {
7
+ return /* @__PURE__ */ jsxs("div", {
8
+ "data-slot": "rich-text-editor-toolbar",
9
+ className: cn("flex flex-wrap items-center gap-1 border-b border-gray-200 px-2 py-1", className),
10
+ children: [presets.map((preset) => TOOLBAR_PRESET_RENDERERS[preset](editor)), items?.map((item) => /* @__PURE__ */ jsx(ToolbarButton, {
11
+ icon: item.icon,
12
+ "aria-label": item.label,
13
+ active: item.isActive?.(editor),
14
+ onClick: () => item.onClick(editor)
15
+ }, item.key))]
16
+ });
17
+ };
18
+ //#endregion
19
+ export { Toolbar as default };
20
+
21
+ //# sourceMappingURL=toolbar.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolbar.mjs","names":[],"sources":["../../../../src/components/atoms/rich-text-editor/toolbar.tsx"],"sourcesContent":["import type { Editor } from '@tiptap/core';\n\nimport { cn } from '@repo/ui/utils';\n\nimport ToolbarButton from './toolbar-button';\nimport { TOOLBAR_PRESET_RENDERERS } from './toolbar-presets';\nimport type { ToolbarItem, ToolbarPreset } from './types';\n\nexport interface ToolbarProps {\n editor: Editor;\n presets: ToolbarPreset[];\n items?: ToolbarItem[];\n className?: string;\n}\n\nconst Toolbar = ({ editor, presets, items, className }: ToolbarProps) => {\n return (\n <div\n data-slot=\"rich-text-editor-toolbar\"\n className={cn(\n 'flex flex-wrap items-center gap-1 border-b border-gray-200 px-2 py-1',\n className,\n //\n )}\n >\n {presets.map(preset => TOOLBAR_PRESET_RENDERERS[preset](editor))}\n {items?.map(item => (\n <ToolbarButton\n key={item.key}\n icon={item.icon}\n aria-label={item.label}\n active={item.isActive?.(editor)}\n onClick={() => item.onClick(editor)}\n />\n ))}\n </div>\n );\n};\n\nexport default Toolbar;\n"],"mappings":";;;;;AAeA,MAAM,WAAW,EAAE,QAAQ,SAAS,OAAO,gBAA8B;CACvE,OACE,qBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,wEACA,SAEF;EANF,UAAA,CAQG,QAAQ,KAAI,WAAU,yBAAyB,OAAO,CAAC,MAAM,CAAC,GAC9D,OAAO,KAAI,SACV,oBAAC,eAAD;GAEE,MAAM,KAAK;GACX,cAAY,KAAK;GACjB,QAAQ,KAAK,WAAW,MAAM;GAC9B,eAAe,KAAK,QAAQ,MAAM;EACnC,GALM,KAAK,GAKX,CACF,CACE;;AAET"}
@@ -0,0 +1,14 @@
1
+ import { ReactNode } from "react";
2
+ import { Editor } from "@tiptap/core";
3
+ //#region src/components/atoms/rich-text-editor/types.d.ts
4
+ type ToolbarPreset = 'undo' | 'redo' | 'heading' | 'bold' | 'italic' | 'underline' | 'strike' | 'code' | 'bulletList' | 'orderedList' | 'blockquote' | 'codeBlock' | 'horizontalRule' | 'link' | 'fontSize' | 'color';
5
+ interface ToolbarItem {
6
+ key: string;
7
+ icon: ReactNode;
8
+ label?: string;
9
+ isActive?: (editor: Editor) => boolean;
10
+ onClick: (editor: Editor) => void;
11
+ }
12
+ //#endregion
13
+ export { ToolbarItem, ToolbarPreset };
14
+ //# sourceMappingURL=types.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.mts","names":[],"sources":["../../../../src/components/atoms/rich-text-editor/types.ts"],"mappings":";;;KAIY;UAkBK;EACf;EACA,MAAM;EACN;EACA,YAAY,QAAQ;EACpB,UAAU,QAAQ"}
package/dist/index.d.mts CHANGED
@@ -20,6 +20,7 @@ import Input from "./components/atoms/input/index.mjs";
20
20
  import Popover from "./components/atoms/popover.mjs";
21
21
  import Progress from "./components/atoms/progress.mjs";
22
22
  import Radio from "./components/atoms/radio/index.mjs";
23
+ import RichTextEditor from "./components/atoms/rich-text-editor/rich-text-editor.mjs";
23
24
  import Select from "./components/atoms/select.mjs";
24
25
  import Skeleton from "./components/atoms/skeleton/index.mjs";
25
26
  import Slider from "./components/atoms/slider/slider.mjs";
@@ -52,4 +53,4 @@ import { ComponentSize, DefaultProps, Locale, ThemeConfig, ThemeToken } from "./
52
53
  import { DEFAULT_LOCALE, useConfig } from "./providers/config/context.mjs";
53
54
  import Config, { Props as Props$3 } from "./providers/config/config.mjs";
54
55
  import { ConfigSnapshotProvider, getRootConfigValue } from "./providers/config/registry.mjs";
55
- export { Button, Card, type Props as CardProps, Checkbox, Col, type Props$1 as ColProps, Collapse, type Props$2 as CollapseProps, ColorPicker, type ComponentSize, Config, type Props$3 as ConfigProps, ConfigSnapshotProvider, Container, type Props$4 as ContainerProps, type Props$5 as ContentProps, DEFAULT_LOCALE, DatePicker, type DefaultProps, Drawer, type Props$6 as DrawerProps, Dropdown, type Props$7 as DropdownProps, Empty, type Props$8 as EmptyProps, FloatButton, type Props$9 as FooterProps, type Props$10 as HeaderProps, Input, Layout, type Props$11 as LayoutProps, List, type Props$12 as ListProps, type Locale, Marquees, type Props$13 as MarqueesProps, Menu, type Props$14 as MenuProps, Modal, type Props$15 as ModalProps, PageHeader, type Props$16 as PageHeaderProps, Popover, Progress, Radio, Result, type Props$17 as ResultProps, Reveals, type Props$18 as RevealsProps, Row, type Props$19 as RowProps, Select, type Props$20 as SiderProps, Skeleton, Slider, Space, type Props$21 as SpaceProps, Spin, Splitter, type Props$22 as SplitterProps, Swiper, type Props$23 as SwiperProps, Switch, Tag, type ThemeConfig, type ThemeToken, Toast, type StaticProps as ToastOptions, Typography, Upload, type UploadFile, type Props$24 as UploadProps, getRootConfigValue, useConfig };
56
+ export { Button, Card, type Props as CardProps, Checkbox, Col, type Props$1 as ColProps, Collapse, type Props$2 as CollapseProps, ColorPicker, type ComponentSize, Config, type Props$3 as ConfigProps, ConfigSnapshotProvider, Container, type Props$4 as ContainerProps, type Props$5 as ContentProps, DEFAULT_LOCALE, DatePicker, type DefaultProps, Drawer, type Props$6 as DrawerProps, Dropdown, type Props$7 as DropdownProps, Empty, type Props$8 as EmptyProps, FloatButton, type Props$9 as FooterProps, type Props$10 as HeaderProps, Input, Layout, type Props$11 as LayoutProps, List, type Props$12 as ListProps, type Locale, Marquees, type Props$13 as MarqueesProps, Menu, type Props$14 as MenuProps, Modal, type Props$15 as ModalProps, PageHeader, type Props$16 as PageHeaderProps, Popover, Progress, Radio, Result, type Props$17 as ResultProps, Reveals, type Props$18 as RevealsProps, RichTextEditor, Row, type Props$19 as RowProps, Select, type Props$20 as SiderProps, Skeleton, Slider, Space, type Props$21 as SpaceProps, Spin, Splitter, type Props$22 as SplitterProps, Swiper, type Props$23 as SwiperProps, Switch, Tag, type ThemeConfig, type ThemeToken, Toast, type StaticProps as ToastOptions, Typography, Upload, type UploadFile, type Props$24 as UploadProps, getRootConfigValue, useConfig };
package/dist/index.mjs CHANGED
@@ -13,6 +13,7 @@ import Input from "./components/atoms/input/index.mjs";
13
13
  import Progress from "./components/atoms/progress.mjs";
14
14
  import Radio from "./components/atoms/radio/index.mjs";
15
15
  import Select from "./components/atoms/select.mjs";
16
+ import RichTextEditor from "./components/atoms/rich-text-editor/rich-text-editor.mjs";
16
17
  import Skeleton from "./components/atoms/skeleton/index.mjs";
17
18
  import slider_default from "./components/atoms/slider/index.mjs";
18
19
  import Spin from "./components/atoms/spin.mjs";
@@ -39,4 +40,4 @@ import Result from "./components/templates/result.mjs";
39
40
  import PageHeader from "./components/templates/page-header.mjs";
40
41
  import Row from "./components/templates/grid/row.mjs";
41
42
  import Col from "./components/templates/grid/col.mjs";
42
- export { Button, Card, Checkbox, Col, Collapse, ColorPicker, Config, ConfigSnapshotProvider, Container, DEFAULT_LOCALE, DatePicker, Drawer, Dropdown, Empty, FloatButton, Input, Layout, List, Marquees, Menu, Modal, PageHeader, Popover, Progress, Radio, Result, Reveals, Row, Select, Skeleton, slider_default as Slider, Space, Spin, Splitter, Swiper, Switch, Tag, Toast, Typography, Upload, getRootConfigValue, useConfig };
43
+ export { Button, Card, Checkbox, Col, Collapse, ColorPicker, Config, ConfigSnapshotProvider, Container, DEFAULT_LOCALE, DatePicker, Drawer, Dropdown, Empty, FloatButton, Input, Layout, List, Marquees, Menu, Modal, PageHeader, Popover, Progress, Radio, Result, Reveals, RichTextEditor, Row, Select, Skeleton, slider_default as Slider, Space, Spin, Splitter, Swiper, Switch, Tag, Toast, Typography, Upload, getRootConfigValue, useConfig };
package/dist/style.css CHANGED
@@ -6,12 +6,16 @@
6
6
  --font-mono: var(--font-geist-mono);
7
7
  --color-red-400: oklch(70.4% .191 22.216);
8
8
  --color-yellow-400: oklch(85.2% .199 91.936);
9
- --color-yellow-500: oklch(79.5% .184 86.047);
10
- --color-yellow-600: oklch(68.1% .162 75.834);
11
9
  --color-green-400: oklch(79.2% .209 151.711);
12
- --color-green-500: oklch(72.3% .219 149.579);
13
- --color-green-600: oklch(62.7% .194 149.214);
14
10
  --color-blue-400: oklch(70.7% .165 254.624);
11
+ --color-blue-600: oklch(54.6% .245 262.881);
12
+ --color-gray-100: oklch(96.7% .003 264.542);
13
+ --color-gray-200: oklch(92.8% .006 264.531);
14
+ --color-gray-300: oklch(87.2% .01 258.338);
15
+ --color-gray-400: oklch(70.7% .022 261.325);
16
+ --color-gray-600: oklch(44.6% .03 256.802);
17
+ --color-gray-800: oklch(27.8% .033 256.848);
18
+ --color-gray-900: oklch(21% .034 264.665);
15
19
  --color-black: #000;
16
20
  --color-white: #fff;
17
21
  --spacing: .25rem;
@@ -149,6 +153,41 @@
149
153
  [data-slot="button"][data-color="gold"] {
150
154
  --btn-bg: #f59e0b;
151
155
  }
156
+ [data-slot="badge"][data-color] {
157
+ --tag-fg: var(--tag-bg);
158
+ --tag-tint: var(--tag-bg);
159
+ @supports (color: color-mix(in lab, red, red)) {
160
+ --tag-tint: color-mix(in oklab, var(--tag-bg), transparent 90%);
161
+ }
162
+ }
163
+ [data-slot="badge"][data-color="default"] {
164
+ --tag-bg: var(--border);
165
+ --tag-tint: var(--muted);
166
+ --tag-fg: var(--muted-foreground);
167
+ }
168
+ [data-slot="badge"][data-color="default"][data-variant="outlined"] {
169
+ --tag-fg: var(--foreground);
170
+ }
171
+ [data-slot="badge"][data-color="primary"] {
172
+ --tag-bg: var(--primary);
173
+ }
174
+ [data-slot="badge"][data-color="danger"] {
175
+ --tag-bg: var(--destructive);
176
+ }
177
+ [data-slot="badge"][data-color="success"] {
178
+ --tag-bg: oklch(72.3% .219 149.579);
179
+ --tag-fg: oklch(62.7% .194 149.214);
180
+ }
181
+ [data-slot="badge"][data-color="warning"] {
182
+ --tag-bg: oklch(79.5% .184 86.047);
183
+ --tag-fg: oklch(68.1% .162 75.834);
184
+ }
185
+ :is(.dark, [data-theme="dark"]) [data-slot="badge"][data-color="success"] {
186
+ --tag-fg: oklch(79.2% .209 151.711);
187
+ }
188
+ :is(.dark, [data-theme="dark"]) [data-slot="badge"][data-color="warning"] {
189
+ --tag-fg: oklch(85.2% .199 91.936);
190
+ }
152
191
  [data-slot="badge"][data-color="blue"] {
153
192
  --tag-bg: #3b82f6;
154
193
  }
@@ -598,6 +637,9 @@
598
637
  .min-h-16 {
599
638
  min-height: calc(var(--spacing) * 16);
600
639
  }
640
+ .min-h-20 {
641
+ min-height: calc(var(--spacing) * 20);
642
+ }
601
643
  .min-h-screen {
602
644
  min-height: 100vh;
603
645
  }
@@ -622,9 +664,15 @@
622
664
  .w-15 {
623
665
  width: calc(var(--spacing) * 15);
624
666
  }
667
+ .w-20 {
668
+ width: calc(var(--spacing) * 20);
669
+ }
625
670
  .w-25 {
626
671
  width: calc(var(--spacing) * 25);
627
672
  }
673
+ .w-28 {
674
+ width: calc(var(--spacing) * 28);
675
+ }
628
676
  .w-48 {
629
677
  width: calc(var(--spacing) * 48);
630
678
  }
@@ -1096,11 +1144,8 @@
1096
1144
  .border-current {
1097
1145
  border-color: currentcolor;
1098
1146
  }
1099
- .border-destructive {
1100
- border-color: var(--destructive);
1101
- }
1102
- .border-green-500 {
1103
- border-color: var(--color-green-500);
1147
+ .border-gray-200 {
1148
+ border-color: var(--color-gray-200);
1104
1149
  }
1105
1150
  .border-input {
1106
1151
  border-color: var(--input);
@@ -1111,17 +1156,11 @@
1111
1156
  .border-transparent {
1112
1157
  border-color: transparent;
1113
1158
  }
1114
- .border-yellow-500 {
1115
- border-color: var(--color-yellow-500);
1116
- }
1117
1159
  .bg-\(--btn-bg\) {
1118
1160
  background-color: var(--btn-bg);
1119
1161
  }
1120
- .bg-\[color-mix\(in_oklch\,var\(--tag-bg\)\,transparent_90\%\)\] {
1121
- background-color: var(--tag-bg);
1122
- @supports (color: color-mix(in lab, red, red)) {
1123
- background-color: color-mix(in oklch,var(--tag-bg),transparent 90%);
1124
- }
1162
+ .bg-\(--tag-tint\) {
1163
+ background-color: var(--tag-tint);
1125
1164
  }
1126
1165
  .bg-accent {
1127
1166
  background-color: var(--accent);
@@ -1156,18 +1195,6 @@
1156
1195
  .bg-destructive {
1157
1196
  background-color: var(--destructive);
1158
1197
  }
1159
- .bg-destructive\/10 {
1160
- background-color: var(--destructive);
1161
- @supports (color: color-mix(in lab, red, red)) {
1162
- background-color: color-mix(in oklab, var(--destructive) 10%, transparent);
1163
- }
1164
- }
1165
- .bg-green-500\/10 {
1166
- background-color: color-mix(in srgb, oklch(72.3% .219 149.579) 10%, transparent);
1167
- @supports (color: color-mix(in lab, red, red)) {
1168
- background-color: color-mix(in oklab, var(--color-green-500) 10%, transparent);
1169
- }
1170
- }
1171
1198
  .bg-inherit {
1172
1199
  background-color: inherit;
1173
1200
  }
@@ -1183,12 +1210,6 @@
1183
1210
  .bg-primary {
1184
1211
  background-color: var(--primary);
1185
1212
  }
1186
- .bg-primary\/10 {
1187
- background-color: var(--primary);
1188
- @supports (color: color-mix(in lab, red, red)) {
1189
- background-color: color-mix(in oklab, var(--primary) 10%, transparent);
1190
- }
1191
- }
1192
1213
  .bg-primary\/20 {
1193
1214
  background-color: var(--primary);
1194
1215
  @supports (color: color-mix(in lab, red, red)) {
@@ -1201,11 +1222,8 @@
1201
1222
  .bg-transparent {
1202
1223
  background-color: transparent;
1203
1224
  }
1204
- .bg-yellow-500\/10 {
1205
- background-color: color-mix(in srgb, oklch(79.5% .184 86.047) 10%, transparent);
1206
- @supports (color: color-mix(in lab, red, red)) {
1207
- background-color: color-mix(in oklab, var(--color-yellow-500) 10%, transparent);
1208
- }
1225
+ .bg-white {
1226
+ background-color: var(--color-white);
1209
1227
  }
1210
1228
  .fill-primary {
1211
1229
  fill: var(--primary);
@@ -1415,8 +1433,8 @@
1415
1433
  .text-\(--btn-fg\) {
1416
1434
  color: var(--btn-fg);
1417
1435
  }
1418
- .text-\(--tag-bg\) {
1419
- color: var(--tag-bg);
1436
+ .text-\(--tag-fg\) {
1437
+ color: var(--tag-fg);
1420
1438
  }
1421
1439
  .text-accent-foreground {
1422
1440
  color: var(--accent-foreground);
@@ -1436,12 +1454,12 @@
1436
1454
  .text-foreground {
1437
1455
  color: var(--foreground);
1438
1456
  }
1457
+ .text-gray-800 {
1458
+ color: var(--color-gray-800);
1459
+ }
1439
1460
  .text-green-400 {
1440
1461
  color: var(--color-green-400);
1441
1462
  }
1442
- .text-green-600 {
1443
- color: var(--color-green-600);
1444
- }
1445
1463
  .text-muted-foreground {
1446
1464
  color: var(--muted-foreground);
1447
1465
  }
@@ -1466,12 +1484,12 @@
1466
1484
  .text-yellow-400 {
1467
1485
  color: var(--color-yellow-400);
1468
1486
  }
1469
- .text-yellow-600 {
1470
- color: var(--color-yellow-600);
1471
- }
1472
1487
  .lowercase {
1473
1488
  text-transform: lowercase;
1474
1489
  }
1490
+ .italic {
1491
+ font-style: italic;
1492
+ }
1475
1493
  .underline {
1476
1494
  text-decoration-line: underline;
1477
1495
  }
@@ -1545,6 +1563,10 @@
1545
1563
  outline-style: var(--tw-outline-style);
1546
1564
  outline-width: 1px;
1547
1565
  }
1566
+ .blur {
1567
+ --tw-blur: blur(8px);
1568
+ filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
1569
+ }
1548
1570
  .filter {
1549
1571
  filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
1550
1572
  }
@@ -2604,12 +2626,6 @@
2604
2626
  background-color: color-mix(in oklab, var(--input) 30%, transparent);
2605
2627
  }
2606
2628
  }
2607
- .dark\:text-green-400:is(.dark *, [data-theme="dark"] *) {
2608
- color: var(--color-green-400);
2609
- }
2610
- .dark\:text-yellow-400:is(.dark *, [data-theme="dark"] *) {
2611
- color: var(--color-yellow-400);
2612
- }
2613
2629
  @media (hover: hover) {
2614
2630
  .dark\:hover\:bg-accent\/50:is(.dark *, [data-theme="dark"] *):hover {
2615
2631
  background-color: var(--accent);
@@ -2661,6 +2677,192 @@
2661
2677
  background-color: color-mix(in oklab, var(--input) 80%, transparent);
2662
2678
  }
2663
2679
  }
2680
+ .\[\&_\.tiptap\]\:outline-none .tiptap {
2681
+ --tw-outline-style: none;
2682
+ outline-style: none;
2683
+ }
2684
+ .\[\&_\.tiptap_a\]\:text-blue-600 .tiptap a {
2685
+ color: var(--color-blue-600);
2686
+ }
2687
+ .\[\&_\.tiptap_a\]\:underline .tiptap a {
2688
+ text-decoration-line: underline;
2689
+ }
2690
+ .\[\&_\.tiptap_a\]\:underline-offset-2 .tiptap a {
2691
+ text-underline-offset: 2px;
2692
+ }
2693
+ .\[\&_\.tiptap_blockquote\]\:my-2 .tiptap blockquote {
2694
+ margin-block: calc(var(--spacing) * 2);
2695
+ }
2696
+ .\[\&_\.tiptap_blockquote\]\:border-l-2 .tiptap blockquote {
2697
+ border-left-style: var(--tw-border-style);
2698
+ border-left-width: 2px;
2699
+ }
2700
+ .\[\&_\.tiptap_blockquote\]\:border-gray-300 .tiptap blockquote {
2701
+ border-color: var(--color-gray-300);
2702
+ }
2703
+ .\[\&_\.tiptap_blockquote\]\:pl-3 .tiptap blockquote {
2704
+ padding-left: calc(var(--spacing) * 3);
2705
+ }
2706
+ .\[\&_\.tiptap_blockquote\]\:text-gray-600 .tiptap blockquote {
2707
+ color: var(--color-gray-600);
2708
+ }
2709
+ .\[\&_\.tiptap_blockquote\]\:italic .tiptap blockquote {
2710
+ font-style: italic;
2711
+ }
2712
+ .\[\&_\.tiptap_code\]\:rounded .tiptap code {
2713
+ border-radius: .25rem;
2714
+ }
2715
+ .\[\&_\.tiptap_code\]\:bg-gray-100 .tiptap code {
2716
+ background-color: var(--color-gray-100);
2717
+ }
2718
+ .\[\&_\.tiptap_code\]\:px-1 .tiptap code {
2719
+ padding-inline: var(--spacing);
2720
+ }
2721
+ .\[\&_\.tiptap_code\]\:py-0\.5 .tiptap code {
2722
+ padding-block: calc(var(--spacing) * 0.5);
2723
+ }
2724
+ .\[\&_\.tiptap_code\]\:font-mono .tiptap code {
2725
+ font-family: var(--font-geist-mono);
2726
+ }
2727
+ .\[\&_\.tiptap_code\]\:text-\[0\.85em\] .tiptap code {
2728
+ font-size: 0.85em;
2729
+ }
2730
+ .\[\&_\.tiptap_h1\]\:mt-6 .tiptap h1 {
2731
+ margin-top: calc(var(--spacing) * 6);
2732
+ }
2733
+ .\[\&_\.tiptap_h1\]\:mb-2 .tiptap h1 {
2734
+ margin-bottom: calc(var(--spacing) * 2);
2735
+ }
2736
+ .\[\&_\.tiptap_h1\]\:text-2xl .tiptap h1 {
2737
+ font-size: var(--text-2xl);
2738
+ line-height: var(--tw-leading, var(--text-2xl--line-height));
2739
+ }
2740
+ .\[\&_\.tiptap_h1\]\:font-bold .tiptap h1 {
2741
+ --tw-font-weight: var(--font-weight-bold);
2742
+ font-weight: var(--font-weight-bold);
2743
+ }
2744
+ .\[\&_\.tiptap_h2\]\:mt-5 .tiptap h2 {
2745
+ margin-top: calc(var(--spacing) * 5);
2746
+ }
2747
+ .\[\&_\.tiptap_h2\]\:mb-2 .tiptap h2 {
2748
+ margin-bottom: calc(var(--spacing) * 2);
2749
+ }
2750
+ .\[\&_\.tiptap_h2\]\:text-xl .tiptap h2 {
2751
+ font-size: var(--text-xl);
2752
+ line-height: var(--tw-leading, var(--text-xl--line-height));
2753
+ }
2754
+ .\[\&_\.tiptap_h2\]\:font-bold .tiptap h2 {
2755
+ --tw-font-weight: var(--font-weight-bold);
2756
+ font-weight: var(--font-weight-bold);
2757
+ }
2758
+ .\[\&_\.tiptap_h3\]\:mt-4 .tiptap h3 {
2759
+ margin-top: calc(var(--spacing) * 4);
2760
+ }
2761
+ .\[\&_\.tiptap_h3\]\:mb-2 .tiptap h3 {
2762
+ margin-bottom: calc(var(--spacing) * 2);
2763
+ }
2764
+ .\[\&_\.tiptap_h3\]\:text-lg .tiptap h3 {
2765
+ font-size: var(--text-lg);
2766
+ line-height: var(--tw-leading, var(--text-lg--line-height));
2767
+ }
2768
+ .\[\&_\.tiptap_h3\]\:font-semibold .tiptap h3 {
2769
+ --tw-font-weight: var(--font-weight-semibold);
2770
+ font-weight: var(--font-weight-semibold);
2771
+ }
2772
+ .\[\&_\.tiptap_h4\]\:mt-3 .tiptap h4 {
2773
+ margin-top: calc(var(--spacing) * 3);
2774
+ }
2775
+ .\[\&_\.tiptap_h4\]\:mb-1 .tiptap h4 {
2776
+ margin-bottom: var(--spacing);
2777
+ }
2778
+ .\[\&_\.tiptap_h4\]\:text-base .tiptap h4 {
2779
+ font-size: var(--text-base);
2780
+ line-height: var(--tw-leading, var(--text-base--line-height));
2781
+ }
2782
+ .\[\&_\.tiptap_h4\]\:font-semibold .tiptap h4 {
2783
+ --tw-font-weight: var(--font-weight-semibold);
2784
+ font-weight: var(--font-weight-semibold);
2785
+ }
2786
+ .\[\&_\.tiptap_hr\]\:my-4 .tiptap hr {
2787
+ margin-block: calc(var(--spacing) * 4);
2788
+ }
2789
+ .\[\&_\.tiptap_hr\]\:border-gray-200 .tiptap hr {
2790
+ border-color: var(--color-gray-200);
2791
+ }
2792
+ .\[\&_\.tiptap_li\]\:my-1 .tiptap li {
2793
+ margin-block: var(--spacing);
2794
+ }
2795
+ .\[\&_\.tiptap_ol\]\:my-2 .tiptap ol {
2796
+ margin-block: calc(var(--spacing) * 2);
2797
+ }
2798
+ .\[\&_\.tiptap_ol\]\:list-decimal .tiptap ol {
2799
+ list-style-type: decimal;
2800
+ }
2801
+ .\[\&_\.tiptap_ol\]\:pl-5 .tiptap ol {
2802
+ padding-left: calc(var(--spacing) * 5);
2803
+ }
2804
+ .\[\&_\.tiptap_p\.is-editor-empty\:first-child\:\:before\]\:pointer-events-none .tiptap p.is-editor-empty:first-child::before {
2805
+ pointer-events: none;
2806
+ }
2807
+ .\[\&_\.tiptap_p\.is-editor-empty\:first-child\:\:before\]\:float-left .tiptap p.is-editor-empty:first-child::before {
2808
+ float: left;
2809
+ }
2810
+ .\[\&_\.tiptap_p\.is-editor-empty\:first-child\:\:before\]\:h-0 .tiptap p.is-editor-empty:first-child::before {
2811
+ height: 0px;
2812
+ }
2813
+ .\[\&_\.tiptap_p\.is-editor-empty\:first-child\:\:before\]\:text-gray-400 .tiptap p.is-editor-empty:first-child::before {
2814
+ color: var(--color-gray-400);
2815
+ }
2816
+ .\[\&_\.tiptap_p\.is-editor-empty\:first-child\:\:before\]\:content-\[attr\(data-placeholder\)\] .tiptap p.is-editor-empty:first-child::before {
2817
+ --tw-content: attr(data-placeholder);
2818
+ content: var(--tw-content);
2819
+ }
2820
+ .\[\&_\.tiptap_pre\]\:my-2 .tiptap pre {
2821
+ margin-block: calc(var(--spacing) * 2);
2822
+ }
2823
+ .\[\&_\.tiptap_pre\]\:overflow-x-auto .tiptap pre {
2824
+ overflow-x: auto;
2825
+ }
2826
+ .\[\&_\.tiptap_pre\]\:rounded .tiptap pre {
2827
+ border-radius: .25rem;
2828
+ }
2829
+ .\[\&_\.tiptap_pre\]\:bg-gray-900 .tiptap pre {
2830
+ background-color: var(--color-gray-900);
2831
+ }
2832
+ .\[\&_\.tiptap_pre\]\:p-3 .tiptap pre {
2833
+ padding: calc(var(--spacing) * 3);
2834
+ }
2835
+ .\[\&_\.tiptap_pre\]\:font-mono .tiptap pre {
2836
+ font-family: var(--font-geist-mono);
2837
+ }
2838
+ .\[\&_\.tiptap_pre\]\:text-sm .tiptap pre {
2839
+ font-size: var(--text-sm);
2840
+ line-height: var(--tw-leading, var(--text-sm--line-height));
2841
+ }
2842
+ .\[\&_\.tiptap_pre\]\:text-gray-100 .tiptap pre {
2843
+ color: var(--color-gray-100);
2844
+ }
2845
+ .\[\&_\.tiptap_pre_code\]\:bg-transparent .tiptap pre code {
2846
+ background-color: transparent;
2847
+ }
2848
+ .\[\&_\.tiptap_pre_code\]\:p-0 .tiptap pre code {
2849
+ padding: 0px;
2850
+ }
2851
+ .\[\&_\.tiptap_pre_code\]\:text-inherit .tiptap pre code {
2852
+ color: inherit;
2853
+ }
2854
+ .\[\&_\.tiptap_ul\]\:my-2 .tiptap ul {
2855
+ margin-block: calc(var(--spacing) * 2);
2856
+ }
2857
+ .\[\&_\.tiptap_ul\]\:list-disc .tiptap ul {
2858
+ list-style-type: disc;
2859
+ }
2860
+ .\[\&_\.tiptap_ul\]\:pl-5 .tiptap ul {
2861
+ padding-left: calc(var(--spacing) * 5);
2862
+ }
2863
+ .\[\&_\.tiptap\>\*\:first-child\]\:mt-0 .tiptap > :first-child {
2864
+ margin-top: 0px;
2865
+ }
2664
2866
  .\[\&_svg\]\:pointer-events-none svg {
2665
2867
  pointer-events: none;
2666
2868
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jbpark/ui-kit",
3
- "version": "6.2.0",
3
+ "version": "7.1.0",
4
4
  "description": "Modern React UI component library built with TypeScript, Tailwind CSS, and Radix UI. Featuring atoms, molecules, organisms and layout templates for building beautiful interfaces.",
5
5
  "keywords": [
6
6
  "react",
@@ -143,6 +143,11 @@
143
143
  "@radix-ui/react-slider": "^1.4.7",
144
144
  "@radix-ui/react-slot": "^1.3.3",
145
145
  "@radix-ui/react-switch": "^1.3.7",
146
+ "@tiptap/core": "^3.30.1",
147
+ "@tiptap/extension-placeholder": "^3.30.1",
148
+ "@tiptap/extension-text-style": "^3.30.1",
149
+ "@tiptap/react": "^3.30.1",
150
+ "@tiptap/starter-kit": "^3.30.1",
146
151
  "class-variance-authority": "^0.7.1",
147
152
  "clsx": "^2.1.1",
148
153
  "date-fns": "^4.4.0",
@@ -1,28 +0,0 @@
1
- //#region src/lib/colors.ts
2
- /**
3
- * The shared preset colour palette. `Button` and `Tag` both express these via
4
- * the `--btn-*` / `--tag-*` custom-property systems in `globals.css` (keyed off
5
- * `data-color`), so the same word means the same hue on either component
6
- * (#320). Keep this list in sync with the `[data-color='…']` rules there.
7
- */
8
- const PRESET_COLORS = [
9
- "blue",
10
- "purple",
11
- "cyan",
12
- "green",
13
- "magenta",
14
- "pink",
15
- "red",
16
- "orange",
17
- "yellow",
18
- "volcano",
19
- "geekblue",
20
- "lime",
21
- "gold"
22
- ];
23
- /** Runtime membership test — true when `color` is one of the shared presets. */
24
- const isPresetColor = (color) => PRESET_COLORS.includes(color);
25
- //#endregion
26
- export { PRESET_COLORS, isPresetColor };
27
-
28
- //# sourceMappingURL=colors.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"colors.mjs","names":[],"sources":["../../src/lib/colors.ts"],"sourcesContent":["/**\n * The shared preset colour palette. `Button` and `Tag` both express these via\n * the `--btn-*` / `--tag-*` custom-property systems in `globals.css` (keyed off\n * `data-color`), so the same word means the same hue on either component\n * (#320). Keep this list in sync with the `[data-color='…']` rules there.\n */\nexport const PRESET_COLORS = [\n 'blue',\n 'purple',\n 'cyan',\n 'green',\n 'magenta',\n 'pink',\n 'red',\n 'orange',\n 'yellow',\n 'volcano',\n 'geekblue',\n 'lime',\n 'gold',\n] as const;\n\nexport type PresetColor = (typeof PRESET_COLORS)[number];\n\n/** Runtime membership test — true when `color` is one of the shared presets. */\nexport const isPresetColor = (color: string): color is PresetColor =>\n (PRESET_COLORS as readonly string[]).includes(color);\n"],"mappings":";;;;;;;AAMA,MAAa,gBAAgB;CAC3B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;AAKA,MAAa,iBAAiB,UAC3B,cAAoC,SAAS,KAAK"}