bsky-richtext-react 1.0.2 → 1.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/CHANGELOG.md +24 -0
- package/README.md +8 -79
- package/dist/index.cjs +19 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -4
- package/dist/index.d.ts +8 -4
- package/dist/index.js +19 -26
- package/dist/index.js.map +1 -1
- package/package.json +4 -6
- package/dist/styles.css +0 -106
- package/dist/styles.css.map +0 -1
- package/dist/styles.d.cts +0 -2
- package/dist/styles.d.ts +0 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
## [1.1.0] — 2026-02-17
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- **Default classNames now use Tailwind CSS utility classes** instead of the previous BEM-style class names (`bsky-editor`, `bsky-richtext`, etc.). All components have sensible out-of-the-box appearance as long as Tailwind is configured in the consumer's project — no extra setup needed.
|
|
15
|
+
- `defaultDisplayClassNames` — mentions, links, and tags are styled `text-blue-500 hover:underline`.
|
|
16
|
+
- `defaultEditorClassNames` — editor root is `block w-full relative`; mention chips and autolinks are `inline text-blue-500`.
|
|
17
|
+
- `defaultSuggestionClassNames` — dropdown has full visual defaults: `bg-white rounded-lg shadow-lg border`, hover states, avatar layout, truncated text columns.
|
|
18
|
+
- **`styles.css` removed from the published package.** The `bsky-richtext-react/styles.css` sub-export and the `./dist/styles.css` artefact no longer exist. Remove any `import 'bsky-richtext-react/styles.css'` from your app.
|
|
19
|
+
- **`sideEffects` set to `false`** — the package no longer has CSS side effects, enabling full tree-shaking.
|
|
20
|
+
- **Tailwind added as a `devDependency`** — used exclusively in Storybook for development/testing. Not bundled in or required by consumers.
|
|
21
|
+
- The `classNames` prop API and `generateClassNames()` are unchanged — all existing override patterns continue to work.
|
|
22
|
+
|
|
23
|
+
### Migration
|
|
24
|
+
|
|
25
|
+
```diff
|
|
26
|
+
- import 'bsky-richtext-react/styles.css'
|
|
27
|
+
import { RichTextEditor } from 'bsky-richtext-react'
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
If you were targeting the old BEM class names in your own CSS, replace them with the `classNames` prop or `generateClassNames()` to apply your own classes directly.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
10
34
|
## [1.0.2] — 2026-02-17
|
|
11
35
|
|
|
12
36
|
### Fixed
|
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
- **`<RichTextDisplay>`** — Render AT Protocol richtext records (`text` + `facets`) as interactive HTML. Handles @mentions, links, and #hashtags with fully customisable renderers and URL resolvers.
|
|
15
15
|
- **`<RichTextEditor>`** — TipTap-based editor with real-time @mention autocomplete (powered by the **Bluesky public API** by default — no auth required), stateless URL decoration, undo/redo, and an imperative ref API.
|
|
16
16
|
- **`generateClassNames()`** — Deep-merge utility for the `classNames` prop system. Pass an array of partial classNames objects and get one merged result, optionally using your own `cn()` / `clsx` / `tailwind-merge` utility.
|
|
17
|
-
- **
|
|
17
|
+
- **Tailwind defaults, fully overridable** — Default classNames use Tailwind utility classes out of the box. Override any part via the `classNames` prop — no stylesheet import needed.
|
|
18
18
|
- **Fully typed** — TypeScript-first with complete type definitions for all AT Protocol facet types.
|
|
19
19
|
- **Tree-shakeable** — ESM + CJS dual build via `tsup`.
|
|
20
20
|
|
|
@@ -47,7 +47,6 @@ bun add react react-dom
|
|
|
47
47
|
|
|
48
48
|
```tsx
|
|
49
49
|
import { RichTextDisplay } from 'bsky-richtext-react'
|
|
50
|
-
import 'bsky-richtext-react/styles.css'
|
|
51
50
|
|
|
52
51
|
// Pass raw fields from an app.bsky.feed.post record
|
|
53
52
|
export function Post({ post }) {
|
|
@@ -59,7 +58,6 @@ export function Post({ post }) {
|
|
|
59
58
|
|
|
60
59
|
```tsx
|
|
61
60
|
import { RichTextEditor } from 'bsky-richtext-react'
|
|
62
|
-
import 'bsky-richtext-react/styles.css'
|
|
63
61
|
|
|
64
62
|
export function Composer() {
|
|
65
63
|
return (
|
|
@@ -81,84 +79,13 @@ export function Composer() {
|
|
|
81
79
|
|
|
82
80
|
## Styling
|
|
83
81
|
|
|
84
|
-
|
|
82
|
+
The library ships **no CSS file**. All default styles are Tailwind utility classes applied through the `classNames` prop system. As long as Tailwind is configured in your project, components look good with zero extra setup.
|
|
85
83
|
|
|
86
|
-
|
|
87
|
-
import 'bsky-richtext-react/styles.css'
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
This only sets `display`, `word-break`, `box-sizing`, and flex layout rules. **No colours, fonts, or borders are applied.** You control all visual styling.
|
|
91
|
-
|
|
92
|
-
### 2. Target the default class names
|
|
93
|
-
|
|
94
|
-
Every element rendered by the components carries a predictable CSS class that you can target directly:
|
|
95
|
-
|
|
96
|
-
#### `<RichTextDisplay>`
|
|
97
|
-
|
|
98
|
-
| Class | Element |
|
|
99
|
-
|-------|---------|
|
|
100
|
-
| `.bsky-richtext` | Root `<span>` |
|
|
101
|
-
| `.bsky-mention` | @mention `<a>` |
|
|
102
|
-
| `.bsky-link` | Link `<a>` |
|
|
103
|
-
| `.bsky-tag` | #hashtag `<a>` |
|
|
104
|
-
|
|
105
|
-
#### `<RichTextEditor>`
|
|
106
|
-
|
|
107
|
-
| Class | Element |
|
|
108
|
-
|-------|---------|
|
|
109
|
-
| `.bsky-editor` | Root wrapper `<div>` |
|
|
110
|
-
| `.bsky-editor-content` | ProseMirror wrapper |
|
|
111
|
-
| `.bsky-editor-mention` | Mention chip inside editor |
|
|
112
|
-
| `.autolink` | URL decoration span inside editor |
|
|
113
|
-
|
|
114
|
-
#### `<MentionSuggestionList>` (dropdown)
|
|
115
|
-
|
|
116
|
-
| Class | Element |
|
|
117
|
-
|-------|---------|
|
|
118
|
-
| `.bsky-suggestions` | Outer container |
|
|
119
|
-
| `.bsky-suggestion-item` | Each suggestion row (`<button>`) |
|
|
120
|
-
| `.bsky-suggestion-item-selected` | Currently highlighted row |
|
|
121
|
-
| `.bsky-suggestion-avatar` | Avatar wrapper |
|
|
122
|
-
| `.bsky-suggestion-avatar-img` | `<img>` element |
|
|
123
|
-
| `.bsky-suggestion-avatar-placeholder` | Initial-letter fallback |
|
|
124
|
-
| `.bsky-suggestion-text` | Text column (name + handle) |
|
|
125
|
-
| `.bsky-suggestion-name` | Display name |
|
|
126
|
-
| `.bsky-suggestion-handle` | `@handle` |
|
|
127
|
-
| `.bsky-suggestion-empty` | "No results" message |
|
|
128
|
-
|
|
129
|
-
```css
|
|
130
|
-
/* Example: style the editor */
|
|
131
|
-
.bsky-editor .ProseMirror {
|
|
132
|
-
padding: 12px 16px;
|
|
133
|
-
border: 1px solid #e1e4e8;
|
|
134
|
-
border-radius: 8px;
|
|
135
|
-
font-size: 16px;
|
|
136
|
-
line-height: 1.5;
|
|
137
|
-
min-height: 120px;
|
|
138
|
-
}
|
|
84
|
+
### 1. Defaults — Tailwind utility classes
|
|
139
85
|
|
|
140
|
-
|
|
141
|
-
.bsky-mention {
|
|
142
|
-
color: #0085ff;
|
|
143
|
-
font-weight: 600;
|
|
144
|
-
text-decoration: none;
|
|
145
|
-
}
|
|
146
|
-
.bsky-mention:hover { text-decoration: underline; }
|
|
147
|
-
|
|
148
|
-
/* Example: style the suggestion dropdown */
|
|
149
|
-
.bsky-suggestions {
|
|
150
|
-
background: #fff;
|
|
151
|
-
border: 1px solid #e1e4e8;
|
|
152
|
-
border-radius: 8px;
|
|
153
|
-
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
|
|
154
|
-
min-width: 240px;
|
|
155
|
-
padding: 4px;
|
|
156
|
-
}
|
|
157
|
-
.bsky-suggestion-item { padding: 8px 10px; border-radius: 6px; }
|
|
158
|
-
.bsky-suggestion-item-selected { background: #f0f4ff; }
|
|
159
|
-
```
|
|
86
|
+
Every component has a set of default Tailwind classes applied out of the box (see `defaultEditorClassNames`, `defaultDisplayClassNames`, `defaultSuggestionClassNames`). No stylesheet import is required.
|
|
160
87
|
|
|
161
|
-
###
|
|
88
|
+
### 2. Use `generateClassNames()` for targeted overrides
|
|
162
89
|
|
|
163
90
|
The `classNames` prop on each component accepts a nested object. Use `generateClassNames()` to cleanly layer your classes on top of the defaults without rewriting them from scratch:
|
|
164
91
|
|
|
@@ -205,7 +132,9 @@ Pass a plain object to skip the defaults entirely:
|
|
|
205
132
|
<RichTextDisplay classNames={{ root: 'my-text', mention: 'my-mention' }} />
|
|
206
133
|
```
|
|
207
134
|
|
|
208
|
-
###
|
|
135
|
+
### 3. Using `tailwind-merge` to deduplicate classes
|
|
136
|
+
|
|
137
|
+
When layering your own Tailwind classes on top of the defaults, use `tailwind-merge` as the `cn` argument to avoid conflicting class duplication:
|
|
209
138
|
|
|
210
139
|
```tsx
|
|
211
140
|
import { twMerge } from 'tailwind-merge'
|
package/dist/index.cjs
CHANGED
|
@@ -35,29 +35,28 @@ function isTagFeature(feature) {
|
|
|
35
35
|
|
|
36
36
|
// src/defaults/classNames.ts
|
|
37
37
|
var defaultDisplayClassNames = {
|
|
38
|
-
root: "
|
|
39
|
-
mention: "
|
|
40
|
-
link: "
|
|
41
|
-
tag: "
|
|
38
|
+
root: "inline break-words",
|
|
39
|
+
mention: "inline text-blue-500 hover:underline cursor-pointer",
|
|
40
|
+
link: "inline text-blue-500 hover:underline",
|
|
41
|
+
tag: "inline text-blue-500 hover:underline cursor-pointer"
|
|
42
42
|
};
|
|
43
43
|
var defaultSuggestionClassNames = {
|
|
44
|
-
root: "
|
|
45
|
-
item: "
|
|
46
|
-
itemSelected: "
|
|
47
|
-
avatar: "
|
|
48
|
-
avatarImg: "
|
|
49
|
-
avatarPlaceholder: "
|
|
50
|
-
text: "
|
|
51
|
-
name: "
|
|
52
|
-
handle: "
|
|
53
|
-
empty: "
|
|
44
|
+
root: "flex flex-col max-h-80 overflow-y-auto bg-white rounded-lg shadow-lg border border-gray-200 min-w-60",
|
|
45
|
+
item: "flex items-center gap-3 w-full px-3 py-2 text-left cursor-pointer border-none bg-transparent hover:bg-gray-100 select-none",
|
|
46
|
+
itemSelected: "bg-gray-100",
|
|
47
|
+
avatar: "flex-shrink-0 w-10 h-10 rounded-full overflow-hidden bg-gray-200 flex items-center justify-center",
|
|
48
|
+
avatarImg: "block w-full h-full object-cover",
|
|
49
|
+
avatarPlaceholder: "flex items-center justify-center w-full h-full text-gray-500 font-medium text-sm",
|
|
50
|
+
text: "flex flex-col flex-1 min-w-0 overflow-hidden",
|
|
51
|
+
name: "block truncate font-medium text-gray-900 text-sm",
|
|
52
|
+
handle: "block truncate text-xs text-gray-500",
|
|
53
|
+
empty: "block px-3 py-2 text-sm text-gray-500"
|
|
54
54
|
};
|
|
55
55
|
var defaultEditorClassNames = {
|
|
56
|
-
root: "
|
|
57
|
-
content: "
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
link: "autolink",
|
|
56
|
+
root: "block w-full relative",
|
|
57
|
+
content: "block w-full",
|
|
58
|
+
mention: "inline text-blue-500",
|
|
59
|
+
link: "inline text-blue-500",
|
|
61
60
|
suggestion: defaultSuggestionClassNames
|
|
62
61
|
};
|
|
63
62
|
|
|
@@ -372,13 +371,7 @@ function createDebouncedSearch(delayMs = 300) {
|
|
|
372
371
|
});
|
|
373
372
|
};
|
|
374
373
|
}
|
|
375
|
-
var MentionSuggestionList = react.forwardRef(function MentionSuggestionListImpl({
|
|
376
|
-
items,
|
|
377
|
-
command,
|
|
378
|
-
showAvatars = true,
|
|
379
|
-
noResultsText = "No results",
|
|
380
|
-
classNames: classNamesProp
|
|
381
|
-
}, ref) {
|
|
374
|
+
var MentionSuggestionList = react.forwardRef(function MentionSuggestionListImpl({ items, command, showAvatars = true, noResultsText = "No results", classNames: classNamesProp }, ref) {
|
|
382
375
|
const [selectedIndex, setSelectedIndex] = react.useState(0);
|
|
383
376
|
const cn = react.useMemo(
|
|
384
377
|
() => generateClassNames([defaultSuggestionClassNames, classNamesProp]),
|