@forgedevstack/ink 1.0.1 → 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 +25 -0
- package/README.md +78 -122
- package/dist/components/InkEditor/InkEditor.cjs +1 -1
- package/dist/components/InkEditor/InkEditor.d.ts.map +1 -1
- package/dist/components/InkEditor/InkEditor.js +495 -156
- package/dist/components/InkEditor/components/AiPanel/AiPanel.cjs +1 -0
- package/dist/components/InkEditor/components/AiPanel/AiPanel.d.ts +11 -0
- package/dist/components/InkEditor/components/AiPanel/AiPanel.d.ts.map +1 -0
- package/dist/components/InkEditor/components/AiPanel/AiPanel.js +178 -0
- package/dist/components/InkEditor/components/AiPanel/index.d.ts +3 -0
- package/dist/components/InkEditor/components/AiPanel/index.d.ts.map +1 -0
- package/dist/components/InkEditor/components/BlockHandles/BlockHandles.cjs +1 -0
- package/dist/components/InkEditor/components/BlockHandles/BlockHandles.d.ts +9 -0
- package/dist/components/InkEditor/components/BlockHandles/BlockHandles.d.ts.map +1 -0
- package/dist/components/InkEditor/components/BlockHandles/BlockHandles.js +12 -0
- package/dist/components/InkEditor/components/BlockHandles/index.d.ts +3 -0
- package/dist/components/InkEditor/components/BlockHandles/index.d.ts.map +1 -0
- package/dist/components/InkEditor/components/CommentsPanel/CommentsPanel.cjs +1 -0
- package/dist/components/InkEditor/components/CommentsPanel/CommentsPanel.d.ts +11 -0
- package/dist/components/InkEditor/components/CommentsPanel/CommentsPanel.d.ts.map +1 -0
- package/dist/components/InkEditor/components/CommentsPanel/CommentsPanel.js +61 -0
- package/dist/components/InkEditor/components/CommentsPanel/index.d.ts +3 -0
- package/dist/components/InkEditor/components/CommentsPanel/index.d.ts.map +1 -0
- package/dist/components/InkEditor/components/SlashMenu/SlashMenu.cjs +1 -0
- package/dist/components/InkEditor/components/SlashMenu/SlashMenu.d.ts +10 -0
- package/dist/components/InkEditor/components/SlashMenu/SlashMenu.d.ts.map +1 -0
- package/dist/components/InkEditor/components/SlashMenu/SlashMenu.js +20 -0
- package/dist/components/InkEditor/components/SlashMenu/index.d.ts +3 -0
- package/dist/components/InkEditor/components/SlashMenu/index.d.ts.map +1 -0
- package/dist/components/InkEditor/components/TrackChangesBar/TrackChangesBar.cjs +1 -0
- package/dist/components/InkEditor/components/TrackChangesBar/TrackChangesBar.d.ts +11 -0
- package/dist/components/InkEditor/components/TrackChangesBar/TrackChangesBar.d.ts.map +1 -0
- package/dist/components/InkEditor/components/TrackChangesBar/TrackChangesBar.js +27 -0
- package/dist/components/InkEditor/components/TrackChangesBar/index.d.ts +3 -0
- package/dist/components/InkEditor/components/TrackChangesBar/index.d.ts.map +1 -0
- package/dist/components/InkEditor/components/index.d.ts +5 -0
- package/dist/components/InkEditor/components/index.d.ts.map +1 -1
- package/dist/constants/aiModels.const.cjs +1 -0
- package/dist/constants/aiModels.const.d.ts +5 -0
- package/dist/constants/aiModels.const.d.ts.map +1 -0
- package/dist/constants/aiModels.const.js +31 -0
- package/dist/constants/defaults.const.cjs +1 -1
- package/dist/constants/defaults.const.d.ts +32 -1
- package/dist/constants/defaults.const.d.ts.map +1 -1
- package/dist/constants/defaults.const.js +124 -20
- package/dist/constants/index.d.ts +1 -0
- package/dist/constants/index.d.ts.map +1 -1
- package/dist/constants/numbers.const.cjs +1 -1
- package/dist/constants/numbers.const.d.ts +13 -0
- package/dist/constants/numbers.const.d.ts.map +1 -1
- package/dist/constants/numbers.const.js +13 -3
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +32 -13
- package/dist/plugins/ai/aiPlugin.cjs +1 -1
- package/dist/plugins/ai/aiPlugin.d.ts.map +1 -1
- package/dist/plugins/ai/aiPlugin.js +40 -18
- package/dist/plugins/ai/demoProvider.cjs +1 -0
- package/dist/plugins/ai/demoProvider.d.ts +3 -0
- package/dist/plugins/ai/demoProvider.d.ts.map +1 -0
- package/dist/plugins/ai/demoProvider.js +130 -0
- package/dist/plugins/ai/index.cjs +1 -1
- package/dist/plugins/ai/index.d.ts +4 -1
- package/dist/plugins/ai/index.d.ts.map +1 -1
- package/dist/plugins/ai/index.js +15 -3
- package/dist/plugins/ai/stubs.cjs +1 -0
- package/dist/plugins/ai/stubs.d.ts +7 -0
- package/dist/plugins/ai/stubs.d.ts.map +1 -0
- package/dist/plugins/ai/stubs.js +23 -0
- package/dist/styles.css +464 -19
- package/dist/types/ai.types.d.ts +111 -2
- package/dist/types/ai.types.d.ts.map +1 -1
- package/dist/types/comments.types.d.ts +17 -0
- package/dist/types/comments.types.d.ts.map +1 -0
- package/dist/types/features.types.d.ts +5 -0
- package/dist/types/features.types.d.ts.map +1 -0
- package/dist/types/index.d.ts +5 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/ink.types.d.ts +26 -1
- package/dist/types/ink.types.d.ts.map +1 -1
- package/dist/types/trackChanges.types.d.ts +12 -0
- package/dist/types/trackChanges.types.d.ts.map +1 -0
- package/dist/utils/blocks.utils.cjs +1 -0
- package/dist/utils/blocks.utils.d.ts +4 -0
- package/dist/utils/blocks.utils.d.ts.map +1 -0
- package/dist/utils/blocks.utils.js +41 -0
- package/dist/utils/comments.utils.cjs +1 -0
- package/dist/utils/comments.utils.d.ts +5 -0
- package/dist/utils/comments.utils.d.ts.map +1 -0
- package/dist/utils/comments.utils.js +32 -0
- package/dist/utils/history.utils.cjs +1 -0
- package/dist/utils/history.utils.d.ts +13 -0
- package/dist/utils/history.utils.d.ts.map +1 -0
- package/dist/utils/history.utils.js +29 -0
- package/dist/utils/id.utils.cjs +1 -0
- package/dist/utils/id.utils.d.ts +2 -0
- package/dist/utils/id.utils.d.ts.map +1 -0
- package/dist/utils/id.utils.js +4 -0
- package/dist/utils/index.d.ts +7 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/slash.utils.cjs +1 -0
- package/dist/utils/slash.utils.d.ts +4 -0
- package/dist/utils/slash.utils.d.ts.map +1 -0
- package/dist/utils/slash.utils.js +13 -0
- package/dist/utils/table.utils.cjs +1 -0
- package/dist/utils/table.utils.d.ts +2 -0
- package/dist/utils/table.utils.d.ts.map +1 -0
- package/dist/utils/table.utils.js +13 -0
- package/dist/utils/trackChanges.utils.cjs +1 -0
- package/dist/utils/trackChanges.utils.d.ts +7 -0
- package/dist/utils/trackChanges.utils.d.ts.map +1 -0
- package/dist/utils/trackChanges.utils.js +34 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.1.0 — 2026-08-01
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- CKEditor-inspired editor shell: soft light card, rounded toolbar, `variant="classic" | "document"`
|
|
7
|
+
- Structure blocks with hover/focus outline and block handles (move up/down MVP)
|
|
8
|
+
- Toolbar: table insert, undo/redo, track changes, comments, AI toggles
|
|
9
|
+
- Tables: insert N×M HTML tables with basic editable cells
|
|
10
|
+
- Track changes MVP: `<ins class="Ink-tc-insert">` / `<del class="Ink-tc-delete">`, Accept/Reject strip, `trackChanges` / `onTrackChangesChange`
|
|
11
|
+
- Comments MVP: highlight selection → threaded Comments archive sidebar, `comments` / `onCommentsChange`, `showCommentsPanel`
|
|
12
|
+
- Slash-command MVP: `/` → heading, list, table, AI
|
|
13
|
+
- Features flag object: `features={{ table, trackChanges, comments, ai, blocks, slash, history, typoAutoFix }}`
|
|
14
|
+
- Ink AI suite (`@forgedevstack/ink/plugins/ai`):
|
|
15
|
+
- Capabilities: `chat`, `rewrite`, `summarize`, `expand`, `tone`, `translate`, `review`, `quickAction`, `suggestDiff`
|
|
16
|
+
- Side panel UI via `ai={{ enabled, placement, openOnInit, uiTheme, ... }}`
|
|
17
|
+
- Multi-turn chat history, Quick Actions, Review, Translate, diff preview → apply
|
|
18
|
+
- Provider registry: `inkAi.registerProvider({ id, models, run })`
|
|
19
|
+
- Built-in `demo` provider (deterministic local suggestions, no API keys)
|
|
20
|
+
- Model catalog constants (Claude / Gemini / GPT ids — catalog only; BYO LLM)
|
|
21
|
+
- Architecture stubs: cost control, moderation, permissions, external knowledge, quality eval, fallback chains
|
|
22
|
+
- Exports: `INK_COLLAB_TOOLBAR`, `INK_AI_MODEL_CATALOG`, `buildTableHtml`, comment/track helpers
|
|
23
|
+
|
|
24
|
+
### Docs
|
|
25
|
+
- Feature matrix: CK-inspired capabilities → Ink status (Shipped MVP / Stub / Planned)
|
|
26
|
+
- Honesty framing: CKEditor-inspired architecture with local demo providers; bring your own LLM. No SOC2/enterprise hosting claims.
|
|
27
|
+
|
|
3
28
|
## 1.0.1 — 2026-08-01
|
|
4
29
|
|
|
5
30
|
### Added
|
package/README.md
CHANGED
|
@@ -3,14 +3,15 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/@forgedevstack/ink)
|
|
4
4
|
[](./LICENSE)
|
|
5
5
|
|
|
6
|
-
**ForgeStack rich text editor** for React.
|
|
6
|
+
**ForgeStack rich text editor** for React. CKEditor-inspired shell with tables, track changes, comments, block handles, slash commands, and pluggable Ink AI (bring your own LLM + local demo provider).
|
|
7
7
|
|
|
8
8
|
<p align="center">
|
|
9
9
|
<img src="./assets/ink-logo.png" alt="Ink logo" width="120" />
|
|
10
10
|
</p>
|
|
11
11
|
|
|
12
|
-
> **Domain:** [inkforgejs.com](https://inkforgejs.com) — docs +
|
|
13
|
-
> **Inspired by
|
|
12
|
+
> **Domain:** [inkforgejs.com](https://inkforgejs.com) — docs + demos.
|
|
13
|
+
> **Inspired by CKEditor 5** demos / AI features pages and earlier Quill-like portal aesthetics — not a fork. Ink is a contenteditable React component with ForgeStack integrations.
|
|
14
|
+
> **Honesty:** Local demo AI providers only. No hosted enterprise LLM, SOC2, or on-prem claims. Connect Claude / Gemini / GPT (or custom) via `inkAi.registerProvider`.
|
|
14
15
|
|
|
15
16
|
## Install
|
|
16
17
|
|
|
@@ -29,7 +30,10 @@ export function App() {
|
|
|
29
30
|
<InkEditor
|
|
30
31
|
value={value}
|
|
31
32
|
onChange={setValue}
|
|
32
|
-
|
|
33
|
+
variant="classic"
|
|
34
|
+
features={{ table: true, trackChanges: true, comments: true, ai: true, blocks: true, slash: true }}
|
|
35
|
+
ai={{ enabled: true, placement: 'sidebar', openOnInit: true }}
|
|
36
|
+
showCommentsPanel
|
|
33
37
|
typoAutoFix
|
|
34
38
|
/>
|
|
35
39
|
);
|
|
@@ -41,151 +45,103 @@ export function App() {
|
|
|
41
45
|
| | |
|
|
42
46
|
|---|---|
|
|
43
47
|
| Docs portal | [ink-portal](https://github.com/yaghobieh/ink-portal) · [inkforgejs.com](https://inkforgejs.com) |
|
|
44
|
-
|
|
|
48
|
+
| Demos hub | `/demos` |
|
|
49
|
+
| Ink AI | `/ai` |
|
|
50
|
+
| Live playground | `/playground` |
|
|
45
51
|
| npm | https://www.npmjs.com/package/@forgedevstack/ink |
|
|
46
52
|
| Repo | https://github.com/yaghobieh/ink |
|
|
47
53
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
54
|
+
## Feature matrix (CK-inspired → Ink 1.1.0)
|
|
55
|
+
|
|
56
|
+
| Capability | Status |
|
|
57
|
+
|---|---|
|
|
58
|
+
| Classic / document editor shell | **Shipped MVP** |
|
|
59
|
+
| Headings, lists, links, images, colors | **Shipped MVP** |
|
|
60
|
+
| Tables (insert N×M) | **Shipped MVP** |
|
|
61
|
+
| Undo / redo | **Shipped MVP** |
|
|
62
|
+
| Block handles (move up/down) | **Shipped MVP** (full DnD Planned) |
|
|
63
|
+
| Slash commands | **Shipped MVP** |
|
|
64
|
+
| Track changes + Accept/Reject | **Shipped MVP** |
|
|
65
|
+
| Comments archive sidebar | **Shipped MVP** |
|
|
66
|
+
| AI chat + history | **Shipped MVP** (demo provider) |
|
|
67
|
+
| AI Quick Actions / Review / Translate | **Shipped MVP** (demo) |
|
|
68
|
+
| AI diff preview → apply | **Shipped MVP** |
|
|
69
|
+
| Provider registry + model catalog | **Shipped MVP** (catalog constants; BYO run) |
|
|
70
|
+
| Cost control / moderation / permissions / RAG hooks | **Stub** (typed interfaces + no-ops) |
|
|
71
|
+
| Quality eval suite / MCP hosting | **Stub / Planned** |
|
|
72
|
+
| Real-time multiplayer CRDT | **Planned** |
|
|
51
73
|
|
|
52
74
|
## Props (`InkEditorProps`)
|
|
53
75
|
|
|
54
76
|
| Prop | Type | Default | Description |
|
|
55
77
|
|------|------|---------|-------------|
|
|
56
|
-
| `value`
|
|
57
|
-
| `
|
|
58
|
-
| `
|
|
59
|
-
| `
|
|
60
|
-
| `
|
|
61
|
-
| `
|
|
62
|
-
| `
|
|
63
|
-
| `
|
|
64
|
-
| `
|
|
65
|
-
| `
|
|
66
|
-
| `
|
|
67
|
-
| `
|
|
68
|
-
| `
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
Also accepts standard `div` HTML attributes except `onChange`.
|
|
72
|
-
|
|
73
|
-
## Toolbar options (`ToolbarOption`)
|
|
74
|
-
|
|
75
|
-
```
|
|
76
|
-
bold | italic | underline | strikethrough
|
|
77
|
-
heading1 | heading2 | heading3 | heading4 | heading5 | heading6
|
|
78
|
-
paragraph | headingDropdown
|
|
79
|
-
bulletList | orderedList | blockquote | code
|
|
80
|
-
link | image | textColor | highlightColor
|
|
81
|
-
alignLeft | alignCenter | alignRight | alignJustify
|
|
82
|
-
indent | outdent | clearFormat | divider
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
Presets exported from the package:
|
|
78
|
+
| `value` / `defaultValue` / `onChange` | HTML string | — | Controlled content |
|
|
79
|
+
| `variant` | `'classic' \| 'document'` | `'classic'` | Shell layout |
|
|
80
|
+
| `features` | `InkFeaturesConfig` | all on | Module toggles |
|
|
81
|
+
| `toolbar` | `ToolbarOption[]` | `INK_DEFAULT_TOOLBAR` | Toolbar controls |
|
|
82
|
+
| `trackChanges` / `onTrackChangesChange` | `InkTrackChange[]` | — | Parallel TC model |
|
|
83
|
+
| `trackChangesEnabled` | `boolean` | `false` | Wrap inserts/deletes |
|
|
84
|
+
| `comments` / `onCommentsChange` | `InkCommentThread[]` | — | Comment threads |
|
|
85
|
+
| `showCommentsPanel` | `boolean` | `false` | Comments archive |
|
|
86
|
+
| `ai` | `InkAiConfig` | — | AI panel config |
|
|
87
|
+
| `slashCommands` | `boolean` | from features | `/` menu |
|
|
88
|
+
| `tableRows` / `tableCols` | `number` | `3` | Default table size |
|
|
89
|
+
| `author` | `string` | `'You'` | TC / comment author |
|
|
90
|
+
| `typoAutoFix` | `boolean` | `true` | Blur typo MVP |
|
|
91
|
+
|
|
92
|
+
## Toolbar options
|
|
86
93
|
|
|
87
|
-
- `INK_DEFAULT_TOOLBAR` — full editing set
|
|
88
|
-
- `INK_SIMPLE_TOOLBAR` — bold / italic / underline + lists
|
|
89
|
-
|
|
90
|
-
```tsx
|
|
91
|
-
import { InkEditor, INK_SIMPLE_TOOLBAR } from '@forgedevstack/ink';
|
|
92
|
-
|
|
93
|
-
<InkEditor toolbar={INK_SIMPLE_TOOLBAR} />
|
|
94
94
|
```
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
| Variable | Role |
|
|
101
|
-
|----------|------|
|
|
102
|
-
| `--ink-border` | Borders |
|
|
103
|
-
| `--ink-bg` | Editor background |
|
|
104
|
-
| `--ink-toolbar` | Toolbar background |
|
|
105
|
-
| `--ink-text` | Body text |
|
|
106
|
-
| `--ink-muted` | Placeholder / footer |
|
|
107
|
-
| `--ink-accent` | Active / accent |
|
|
108
|
-
| `--ink-accent-soft` | Active button soft fill |
|
|
109
|
-
|
|
110
|
-
Theme helper classes (wrap the editor or add to the root):
|
|
111
|
-
|
|
112
|
-
| Class | Look |
|
|
113
|
-
|-------|------|
|
|
114
|
-
| `.ink-theme-snow` | Clean Quill-like paper toolbar |
|
|
115
|
-
| `.ink-theme-bubble` | Soft floating card |
|
|
116
|
-
| `.ink-theme-dark` | Dark zinc surfaces |
|
|
117
|
-
| `.ink-theme-minimal` | Flat, dashed toolbar edge |
|
|
118
|
-
|
|
119
|
-
```tsx
|
|
120
|
-
<div className="ink-theme-snow">
|
|
121
|
-
<InkEditor value={html} onChange={setHtml} />
|
|
122
|
-
</div>
|
|
95
|
+
headingDropdown | bold | italic | underline | strikethrough
|
|
96
|
+
textColor | highlightColor | bulletList | orderedList
|
|
97
|
+
link | image | table | undo | redo
|
|
98
|
+
trackChanges | comments | ai | clearFormat | divider
|
|
99
|
+
+ align* | indent | outdent | blockquote | code | heading1–6
|
|
123
100
|
```
|
|
124
101
|
|
|
125
|
-
|
|
102
|
+
Presets: `INK_DEFAULT_TOOLBAR`, `INK_SIMPLE_TOOLBAR`, `INK_COLLAB_TOOLBAR`.
|
|
126
103
|
|
|
127
|
-
|
|
128
|
-
- **Image paste** — `allowImagePaste`
|
|
129
|
-
- **Char count** — `showCharCount` / `charCountMax`
|
|
130
|
-
- **Read only** — `readOnly`
|
|
104
|
+
## Ink AI
|
|
131
105
|
|
|
132
106
|
```ts
|
|
133
|
-
import {
|
|
134
|
-
|
|
135
|
-
const { html, fixedCount } = applyTypoAutoFix(rawHtml);
|
|
136
|
-
```
|
|
107
|
+
import { inkAi, INK_AI_MODEL_CATALOG } from '@forgedevstack/ink/plugins/ai';
|
|
137
108
|
|
|
138
|
-
|
|
109
|
+
// Demo provider is registered by default (no API keys).
|
|
110
|
+
await inkAi.runProvider('demo', {
|
|
111
|
+
capability: 'rewrite',
|
|
112
|
+
html: '<p>Hello</p>',
|
|
113
|
+
selectionHtml: '<p>Hello</p>',
|
|
114
|
+
});
|
|
139
115
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
async run({ html }) {
|
|
148
|
-
return { html };
|
|
116
|
+
inkAi.registerProvider({
|
|
117
|
+
id: 'my-openai',
|
|
118
|
+
name: 'My OpenAI',
|
|
119
|
+
models: INK_AI_MODEL_CATALOG.filter((m) => m.provider === 'openai'),
|
|
120
|
+
async run(request) {
|
|
121
|
+
// Call your backend / SDK — Ink does not host models.
|
|
122
|
+
return { html: request.html, text: '…' };
|
|
149
123
|
},
|
|
150
124
|
});
|
|
151
125
|
```
|
|
152
126
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
## Angular
|
|
156
|
-
|
|
157
|
-
```ts
|
|
158
|
-
import { createInkAngularUsage, documentInkAngularAdapter } from '@forgedevstack/ink/angular';
|
|
159
|
-
|
|
160
|
-
console.log(documentInkAngularAdapter());
|
|
161
|
-
console.log(createInkAngularUsage());
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
Mount `InkEditor` via your preferred React↔Angular bridge. A dedicated Angular component lands in 1.x.
|
|
127
|
+
Panel placement: `sidebar` | `drawer` | `floating`. Theme via `ai.uiTheme` / CSS vars `--ink-ai-*`.
|
|
165
128
|
|
|
166
|
-
|
|
129
|
+
Architecture stubs (MVP interfaces): cost-control cache/rate-limit, moderation, permissions, external knowledge, quality eval, fallback chains — see `@forgedevstack/ink/plugins/ai` exports `createNoop*`.
|
|
167
130
|
|
|
168
|
-
|
|
131
|
+
## CSS variables & themes
|
|
169
132
|
|
|
170
|
-
|
|
133
|
+
| Variable | Role |
|
|
134
|
+
|----------|------|
|
|
135
|
+
| `--ink-border` / `--ink-bg` / `--ink-toolbar` | Surfaces |
|
|
136
|
+
| `--ink-text` / `--ink-muted` / `--ink-accent` | Type + accent (teal) |
|
|
137
|
+
| `--ink-shadow` / `--ink-radius` | Card chrome |
|
|
138
|
+
| `--ink-ai-accent` / `--ink-ai-surface` / `--ink-ai-border` | AI panel |
|
|
171
139
|
|
|
172
|
-
|
|
173
|
-
|---|---|---|
|
|
174
|
-
| Core | Delta document model + Parchment | HTML string + contenteditable |
|
|
175
|
-
| Framework | Framework-agnostic | React-first (ForgeStack) |
|
|
176
|
-
| Themes | Snow / Bubble built-in | CSS variables + `ink-theme-*` classes |
|
|
177
|
-
| Typo / AI | Ecosystem plugins | Built-in typo MVP + AI register stub |
|
|
178
|
-
| License / lineage | Quill open source | Independent MIT package — **inspired by**, not a fork |
|
|
140
|
+
Themes: `.ink-theme-snow` · `.ink-theme-bubble` · `.ink-theme-dark` · `.ink-theme-minimal`
|
|
179
141
|
|
|
180
|
-
##
|
|
142
|
+
## Angular / WordPress
|
|
181
143
|
|
|
182
|
-
|
|
183
|
-
- Toolbar: bold / italic / underline / strike, headings, text + highlight colors, lists, links, image insert/paste
|
|
184
|
-
- **Typo auto-fix MVP** — bundled dictionary + heuristics
|
|
185
|
-
- **Theme classes** — snow / bubble / dark / minimal
|
|
186
|
-
- **AI agent stub** — `@forgedevstack/ink/plugins/ai`
|
|
187
|
-
- **Angular** — `@forgedevstack/ink/angular` helpers
|
|
188
|
-
- **WordPress** — `wordpress/ink-editor` stub
|
|
144
|
+
See `@forgedevstack/ink/angular` and [`wordpress/README.md`](./wordpress/README.md).
|
|
189
145
|
|
|
190
146
|
## License
|
|
191
147
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s=require("react/jsx-runtime"),f=require("react"),T=require("../../constants/numbers.const.cjs"),u=require("../../constants/defaults.const.cjs"),ee=require("../../utils/cn.utils.cjs"),te=require("../../utils/typo.utils.cjs"),i=require("./helpers/format.utils.cjs"),I=require("./components/ToolbarButton/ToolbarButton.cjs"),re=require("./components/ToolbarDropdown/ToolbarDropdown.cjs"),O=require("./components/ToolbarColorPicker/ToolbarColorPicker.cjs"),b={bold:"B",italic:"I",underline:"U",strikethrough:"S",bulletList:"•",orderedList:"1.",link:"🔗",image:"🖼",clearFormat:"⌫",alignLeft:"⫷",alignCenter:"☰",alignRight:"⫸",alignJustify:"≡",indent:"→",outdent:"←",blockquote:"“",code:"</>"},ne=v=>{const{value:h,defaultValue:_="",onChange:g,placeholder:x=u.INK_PLACEHOLDER_DEFAULT,disabled:n=!1,readOnly:o=!1,minHeight:m=T.INK_MIN_HEIGHT,maxHeight:C,toolbar:y=u.INK_DEFAULT_TOOLBAR,className:E="",testId:S,allowImagePaste:A=!0,showCharCount:L=!1,charCountMax:N,typoAutoFix:B=!0,...F}=v,r=f.useRef(null),[D,U]=f.useState(new Set),[K,k]=f.useState("p"),[j,R]=f.useState(0),[q,w]=f.useState(T.INK_DEFAULT_TEXT_COLOR),[M,P]=f.useState(T.INK_DEFAULT_HIGHLIGHT_COLOR);f.useEffect(()=>{!r.current||h===void 0||r.current.innerHTML!==h&&(r.current.innerHTML=h)},[h]),f.useEffect(()=>{!r.current||h||!_||(r.current.innerHTML=_)},[]);const H=e=>{var t;g==null||g(e),L&&r.current&&R(((t=r.current.textContent)==null?void 0:t.length)??0)},p=()=>{U(i.getActiveFormats());const e=i.queryCommandValue("formatBlock");e&&k(e.toLowerCase().replace(/[<>]/g,""))},d=()=>{r.current&&(H(r.current.innerHTML),p())},V=()=>{if(!r.current||!B||n||o)return;const e=r.current.innerHTML,t=te.applyTypoAutoFix(e);t.html!==e&&(r.current.innerHTML=t.html,H(t.html))},G=e=>{var c;if(n||o)return;(c=r.current)==null||c.focus();const t=u.INK_BUTTON_CONFIG[e];t&&(t.value?i.execCommand(t.command,t.value):i.execCommand(t.command),d())},$=e=>{var t;n||o||((t=r.current)==null||t.focus(),i.execCommand("formatBlock",e),k(e),d())},W=()=>{var t;if(n||o)return;const e=window.prompt("Enter URL:","https://");e&&((t=r.current)==null||t.focus(),i.insertLink(e),d())},J=async()=>{if(n||o)return;const e=document.createElement("input");e.type="file",e.accept="image/*",e.onchange=async()=>{var a,l;const t=(a=e.files)==null?void 0:a[0];if(!t)return;const c=await i.fileToDataUrl(t);(l=r.current)==null||l.focus(),i.insertImage(c,t.name),d()},e.click()},X=async e=>{var c;if(!A||n||o)return;const t=(c=e.clipboardData)==null?void 0:c.items;if(t)for(const a of Array.from(t)){if(!a.type.startsWith("image/"))continue;e.preventDefault();const l=a.getAsFile();if(!l)continue;const Z=await i.fileToDataUrl(l);i.insertImage(Z),d()}},z=(e,t)=>{if(e==="divider")return s.jsx("span",{className:u.INK_CLASS_DIVIDER},`divider-${t}`);if(e==="headingDropdown")return s.jsx(re.ToolbarDropdown,{title:"Heading",options:u.INK_HEADING_OPTIONS,value:K||"p",disabled:n||o,onChange:$},"heading");if(e==="textColor")return s.jsx(O.ToolbarColorPicker,{title:"Text color",type:"text",value:q,disabled:n||o,onChange:a=>{var l;(l=r.current)==null||l.focus(),i.setTextColor(a),w(a),d()}},"textColor");if(e==="highlightColor")return s.jsx(O.ToolbarColorPicker,{title:"Highlight color",type:"highlight",value:M,disabled:n||o,onChange:a=>{var l;(l=r.current)==null||l.focus(),i.setHighlightColor(a),P(a),d()}},"highlightColor");if(e==="link")return s.jsx(I.ToolbarButton,{icon:b.link,title:"Insert link",disabled:n||o,onClick:W},"link");if(e==="image")return s.jsx(I.ToolbarButton,{icon:b.image,title:"Insert image",disabled:n||o,onClick:()=>{J()}},"image");const c=u.INK_BUTTON_CONFIG[e];return c?s.jsx(I.ToolbarButton,{icon:b[e]??e.slice(0,1).toUpperCase(),title:c.title,active:D.has(e),disabled:n||o,onClick:()=>G(e)},e):null},Q=typeof m=="number"?`${m}px`:m,Y=typeof C=="number"?`${C}px`:C;return s.jsxs("div",{className:ee.cn(u.INK_CLASS_ROOT,E),"data-testid":S,"data-disabled":n||void 0,...F,children:[s.jsx("div",{className:u.INK_CLASS_TOOLBAR,role:"toolbar","aria-label":"Ink formatting toolbar",children:y.map(z)}),s.jsx("div",{ref:r,className:u.INK_CLASS_CONTENT,contentEditable:!n&&!o,role:"textbox","aria-multiline":"true","aria-placeholder":x,"data-placeholder":x,suppressContentEditableWarning:!0,style:{minHeight:Q,maxHeight:Y},onInput:d,onBlur:V,onKeyUp:p,onMouseUp:p,onPaste:e=>{X(e)}}),L?s.jsxs("div",{className:u.INK_CLASS_FOOTER,children:[j,N?` / ${N}`:""]}):null]})};exports.InkEditor=ne;
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s=require("react/jsx-runtime"),a=require("react"),J=require("../../constants/numbers.const.cjs"),d=require("../../constants/defaults.const.cjs"),ht=require("../../utils/cn.utils.cjs"),Ct=require("../../utils/typo.utils.cjs"),be=require("../../utils/id.utils.cjs"),gt=require("../../utils/table.utils.cjs"),D=require("../../utils/blocks.utils.cjs"),I=require("../../utils/trackChanges.utils.cjs"),Q=require("../../utils/comments.utils.cjs"),Ie=require("../../utils/history.utils.cjs"),Se=require("../../utils/slash.utils.cjs"),l=require("./helpers/format.utils.cjs"),p=require("./components/ToolbarButton/ToolbarButton.cjs"),pt=require("./components/ToolbarDropdown/ToolbarDropdown.cjs"),xe=require("./components/ToolbarColorPicker/ToolbarColorPicker.cjs"),kt=require("./components/CommentsPanel/CommentsPanel.cjs"),Tt=require("./components/AiPanel/AiPanel.cjs"),bt=require("./components/BlockHandles/BlockHandles.cjs"),It=require("./components/SlashMenu/SlashMenu.cjs"),St=require("./components/TrackChangesBar/TrackChangesBar.cjs"),k={bold:"B",italic:"I",underline:"U",strikethrough:"S",bulletList:"•",orderedList:"1.",link:"🔗",image:"🖼",table:"▦",undo:"↶",redo:"↷",trackChanges:"±",comments:"💬",ai:"✦",clearFormat:"⌫",alignLeft:"⫷",alignCenter:"☰",alignRight:"⫸",alignJustify:"≡",indent:"→",outdent:"←",blockquote:"“",code:"</>"},Y=()=>{const H=window.getSelection();if(!H||H.rangeCount===0)return"";const g=H.getRangeAt(0),S=document.createElement("div");return S.appendChild(g.cloneContents()),S.innerHTML},xt=H=>{var ke;const{value:g,defaultValue:S="",onChange:M,placeholder:Z=d.INK_PLACEHOLDER_DEFAULT,disabled:c=!1,readOnly:i=!1,minHeight:K=J.INK_MIN_HEIGHT,maxHeight:U,toolbar:Le=d.INK_DEFAULT_TOOLBAR,className:_e="",testId:He,allowImagePaste:Ae=!0,showCharCount:ee=!1,charCountMax:te,typoAutoFix:we=!0,variant:Ee=d.INK_DEFAULT_VARIANT,features:Ne,author:x=d.INK_DEFAULT_AUTHOR,trackChanges:A,onTrackChangesChange:q,trackChangesEnabled:y,onTrackChangesEnabledChange:P,comments:w,onCommentsChange:F,showCommentsPanel:E,onShowCommentsPanelChange:V,ai:h,slashCommands:Be,tableRows:ve=d.INK_TABLE_DEFAULT_ROWS,tableCols:ye=d.INK_TABLE_DEFAULT_COLS,...Re}=H,m={...d.INK_DEFAULT_FEATURES,...Ne},o=a.useRef(null),R=a.useRef(new Ie.InkHistoryStack(g??S)),[Oe,je]=a.useState(new Set),[De,ne]=a.useState("p"),[Me,Ke]=a.useState(0),[Ue,qe]=a.useState(J.INK_DEFAULT_TEXT_COLOR),[Pe,Fe]=a.useState(J.INK_DEFAULT_HIGHLIGHT_COLOR),[L,oe]=a.useState(y??!1),[Ve,re]=a.useState(A??[]),[Ge,se]=a.useState(w??[]),[$e,ce]=a.useState(E??!1),[ae,G]=a.useState(!!(h!=null&&h.enabled&&h.openOnInit)),[le,We]=a.useState(""),[Xe,ze]=a.useState(0),[Je,ie]=a.useState(!1),[Qe,O]=a.useState([]),[ue,Ye]=a.useState({top:0,left:0}),T=A??Ve,N=w??Ge,$=E??$e,de=Be??m.slash;a.useEffect(()=>{y!==void 0&&oe(y)},[y]),a.useEffect(()=>{A&&re(A)},[A]),a.useEffect(()=>{w&&se(w)},[w]),a.useEffect(()=>{E!==void 0&&ce(E)},[E]),a.useEffect(()=>{!o.current||g===void 0||o.current.innerHTML!==g&&(o.current.innerHTML=g)},[g]),a.useEffect(()=>{!o.current||g||!S||(o.current.innerHTML=S,R.current=new Ie.InkHistoryStack(S))},[]);const W=e=>{var t;R.current.push(e),M==null||M(e),ee&&o.current&&Ke(((t=o.current.textContent)==null?void 0:t.length)??0)},_=e=>{o.current&&(o.current.innerHTML=e,W(e))},B=e=>{re(e),q==null||q(e)},X=e=>{se(e),F==null||F(e)},z=e=>{ce(e),V==null||V(e)},Ze=e=>{oe(e),P==null||P(e)},j=()=>{je(l.getActiveFormats());const e=l.queryCommandValue("formatBlock");if(e&&ne(e.toLowerCase().replace(/[<>]/g,"")),We(Y()),!o.current||!m.blocks)return;const t=window.getSelection(),n=(t==null?void 0:t.anchorNode)??null,r=D.getBlockElement(n,o.current);if(D.markActiveBlock(o.current,r),r){const u=o.current.getBoundingClientRect(),C=r.getBoundingClientRect();ze(C.top-u.top+o.current.scrollTop),ie(!0)}else ie(!1)},f=()=>{var t,n,r;if(!o.current)return;let e=o.current.innerHTML;if(L&&m.trackChanges){const u=window.getSelection();if(u&&!u.isCollapsed){const C=Y();if(C){const b=I.createTrackChange("delete",C,x);B([...T,b]),et(b.id),e=o.current.innerHTML}}}if(W(e),j(),de&&o.current){const u=((n=(t=window.getSelection())==null?void 0:t.anchorNode)==null?void 0:n.textContent)??"",C=Se.extractSlashQuery(u);if(C!==null){O(Se.filterSlashCommands(C));const b=(r=window.getSelection())==null?void 0:r.getRangeAt(0);if(b&&o.current){const v=b.getBoundingClientRect(),Te=o.current.getBoundingClientRect();Ye({top:v.bottom-Te.top+8,left:v.left-Te.left})}}else O([])}},et=e=>{const t=window.getSelection();if(!t||t.rangeCount===0)return;const n=Y();n&&l.insertHTML(I.wrapDeleteHtml(n,e))},tt=()=>{if(!o.current||!we||!m.typoAutoFix||c||i)return;const e=o.current.innerHTML,t=Ct.applyTypoAutoFix(e);t.html!==e&&(o.current.innerHTML=t.html,W(t.html))},nt=e=>{var n;if(c||i)return;(n=o.current)==null||n.focus();const t=d.INK_BUTTON_CONFIG[e];t&&(t.value?l.execCommand(t.command,t.value):l.execCommand(t.command),f())},ot=e=>{var t;c||i||((t=o.current)==null||t.focus(),l.execCommand("formatBlock",e),ne(e),f())},rt=()=>{var t;if(c||i)return;const e=window.prompt("Enter URL:","https://");e&&((t=o.current)==null||t.focus(),l.insertLink(e),f())},st=async()=>{if(c||i)return;const e=document.createElement("input");e.type="file",e.accept="image/*",e.onchange=async()=>{var r,u;const t=(r=e.files)==null?void 0:r[0];if(!t)return;const n=await l.fileToDataUrl(t);(u=o.current)==null||u.focus(),l.insertImage(n,t.name),f()},e.click()},me=()=>{var t;if(c||i||!m.table)return;(t=o.current)==null||t.focus();const e=gt.buildTableHtml(ve,ye);if(L&&m.trackChanges){const n=I.createTrackChange("insert",e,x);B([...T,n]),l.insertHTML(I.wrapInsertHtml(e,n.id))}else l.insertHTML(e);f()},fe=()=>{const e=R.current.undo();if(e===null||!o.current){l.execCommand("undo"),f();return}_(e)},he=()=>{const e=R.current.redo();if(e===null||!o.current){l.execCommand("redo"),f();return}_(e)},ct=()=>{var u;if(c||i||!m.comments)return;const e=window.prompt("Comment:");if(!(e!=null&&e.trim()))return;const t=be.createInkId("hl");if((u=o.current)==null||u.focus(),!Q.wrapSelectionAsComment(t))return;const r=Q.createCommentThread(x,e.trim(),t);X([r,...N]),z(!0),f()},Ce=e=>{if(!o.current)return;const t=I.acceptTrackChangeInHtml(o.current.innerHTML,e);_(t),B(T.map(n=>n.id===e?{...n,accepted:!0}:n))},ge=e=>{if(!o.current)return;const t=I.rejectTrackChangeInHtml(o.current.innerHTML,e);_(t),B(T.map(n=>n.id===e?{...n,rejected:!0}:n))},at=async e=>{var n;if(!Ae||c||i)return;const t=(n=e.clipboardData)==null?void 0:n.items;if(t)for(const r of Array.from(t)){if(!r.type.startsWith("image/"))continue;e.preventDefault();const u=r.getAsFile();if(!u)continue;const C=await l.fileToDataUrl(u);if(L&&m.trackChanges){const b=`<img src="${C}" alt="" style="max-width:100%;height:auto;" />`,v=I.createTrackChange("insert",b,x);B([...T,v]),l.insertHTML(I.wrapInsertHtml(b,v.id))}else l.insertImage(C);f()}},lt=e=>{e.key==="Escape"&&O([]),(e.metaKey||e.ctrlKey)&&e.key==="z"&&(e.preventDefault(),e.shiftKey?he():fe())},it=e=>{var n,r;(n=o.current)==null||n.focus();const t=window.getSelection();if((r=t==null?void 0:t.anchorNode)!=null&&r.textContent){const C=t.anchorNode.textContent.replace(/(?:^|\s)\/[^\s]*$/," ");t.anchorNode.nodeType===Node.TEXT_NODE&&(t.anchorNode.textContent=C)}switch(O([]),e.insert){case"heading1":l.execCommand("formatBlock","h1");break;case"heading2":l.execCommand("formatBlock","h2");break;case"bulletList":l.execCommand("insertUnorderedList");break;case"orderedList":l.execCommand("insertOrderedList");break;case"table":me();return;case"ai":G(!0);break}f()},pe=e=>{if(!o.current)return;const t=window.getSelection(),n=D.getBlockElement((t==null?void 0:t.anchorNode)??null,o.current);n&&D.moveBlock(n,e)&&(f(),j())},ut=(e,t)=>{if(e==="divider")return s.jsx("span",{className:d.INK_CLASS_DIVIDER},`divider-${t}`);if(e==="headingDropdown")return s.jsx(pt.ToolbarDropdown,{title:"Heading",options:d.INK_HEADING_OPTIONS,value:De||"p",disabled:c||i,onChange:ot},"heading");if(e==="textColor")return s.jsx(xe.ToolbarColorPicker,{title:"Text color",type:"text",value:Ue,disabled:c||i,onChange:r=>{var u;(u=o.current)==null||u.focus(),l.setTextColor(r),qe(r),f()}},"textColor");if(e==="highlightColor")return s.jsx(xe.ToolbarColorPicker,{title:"Highlight color",type:"highlight",value:Pe,disabled:c||i,onChange:r=>{var u;(u=o.current)==null||u.focus(),l.setHighlightColor(r),Fe(r),f()}},"highlightColor");if(e==="link")return s.jsx(p.ToolbarButton,{icon:k.link,title:"Insert link",disabled:c||i,onClick:rt},"link");if(e==="image")return s.jsx(p.ToolbarButton,{icon:k.image,title:"Insert image",disabled:c||i,onClick:()=>{st()}},"image");if(e==="table")return m.table?s.jsx(p.ToolbarButton,{icon:k.table,title:"Insert table",disabled:c||i,onClick:me},"table"):null;if(e==="undo")return s.jsx(p.ToolbarButton,{icon:k.undo,title:"Undo",disabled:c||i,onClick:fe},"undo");if(e==="redo")return s.jsx(p.ToolbarButton,{icon:k.redo,title:"Redo",disabled:c||i,onClick:he},"redo");if(e==="trackChanges")return m.trackChanges?s.jsx(p.ToolbarButton,{icon:k.trackChanges,title:"Track changes",active:L,disabled:c||i,onClick:()=>Ze(!L)},"trackChanges"):null;if(e==="comments")return m.comments?s.jsx(p.ToolbarButton,{icon:k.comments,title:"Comments",active:$,disabled:c||i,onClick:()=>{$?z(!1):ct()}},"comments"):null;if(e==="ai")return!m.ai||!(h!=null&&h.enabled)?null:s.jsx(p.ToolbarButton,{icon:k.ai,title:"Ink AI",active:ae,disabled:c||i,onClick:()=>G(r=>!r)},"ai");const n=d.INK_BUTTON_CONFIG[e];return n?s.jsx(p.ToolbarButton,{icon:k[e]??e.slice(0,1).toUpperCase(),title:n.title,active:Oe.has(e),disabled:c||i,onClick:()=>nt(e)},e):null},dt=typeof K=="number"?`${K}px`:K,mt=typeof U=="number"?`${U}px`:U,ft=!!(h!=null&&h.enabled&&ae);return s.jsxs("div",{className:ht.cn(d.INK_CLASS_ROOT,_e),"data-testid":He,"data-disabled":c||void 0,"data-variant":Ee,...Re,children:[s.jsx("div",{className:d.INK_CLASS_TOOLBAR,role:"toolbar","aria-label":"Ink formatting toolbar",children:Le.map(ut)}),L&&m.trackChanges?s.jsx(St.TrackChangesBar,{changes:T,onAccept:Ce,onReject:ge,onAcceptAll:()=>T.forEach(e=>Ce(e.id)),onRejectAll:()=>T.forEach(e=>ge(e.id))}):null,s.jsxs("div",{className:d.INK_CLASS_SHELL,children:[s.jsxs("div",{className:d.INK_CLASS_BODY,children:[m.blocks?s.jsx(bt.BlockHandles,{visible:Je&&!c&&!i,top:Xe,onMoveUp:()=>pe("up"),onMoveDown:()=>pe("down")}):null,s.jsx("div",{ref:o,className:d.INK_CLASS_CONTENT,contentEditable:!c&&!i,role:"textbox","aria-multiline":"true","aria-placeholder":Z,"data-placeholder":Z,suppressContentEditableWarning:!0,style:{minHeight:dt,maxHeight:mt},onInput:f,onBlur:tt,onKeyUp:j,onKeyDown:lt,onMouseUp:j,onPaste:e=>{at(e)}}),de?s.jsx(It.SlashMenu,{items:Qe,top:ue.top,left:ue.left,onSelect:it}):null]}),$&&m.comments?s.jsx(kt.CommentsPanel,{comments:N,author:x,onClose:()=>z(!1),onResolve:e=>{const t=N.find(n=>n.id===e);X(N.map(n=>n.id===e?{...n,resolved:!0}:n)),t&&o.current&&_(Q.removeCommentMark(o.current.innerHTML,t.highlightId))},onAddReply:(e,t)=>{X(N.map(n=>n.id===e?{...n,replies:[...n.replies,{id:be.createInkId("reply"),author:x,body:t,timestamp:Date.now()}]}:n))}}):null,ft&&h?s.jsx(Tt.AiPanel,{config:h,documentHtml:((ke=o.current)==null?void 0:ke.innerHTML)??g??"",selectionHtml:le,onClose:()=>G(!1),onApplyHtml:e=>{var t;if((t=o.current)==null||t.focus(),le)l.insertHTML(e);else{_(e);return}f()}}):null]}),ee?s.jsxs("div",{className:d.INK_CLASS_FOOTER,children:[Me,te?` / ${te}`:""]}):null]})};exports.InkEditor=xt;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InkEditor.d.ts","sourceRoot":"","sources":["../../../src/components/InkEditor/InkEditor.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"InkEditor.d.ts","sourceRoot":"","sources":["../../../src/components/InkEditor/InkEditor.tsx"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,EAAE,EAIR,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EAEV,cAAc,EAIf,MAAM,aAAa,CAAC;AAmGrB,eAAO,MAAM,SAAS,EAAE,EAAE,CAAC,cAAc,CAyqBxC,CAAC"}
|