Skip to content

Commit a781546

Browse files
gjulivangjulivan
authored andcommitted
chore: updated version of rich text with tiptap
1 parent a3d8c93 commit a781546

31 files changed

Lines changed: 1924 additions & 132 deletions
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
schema: spec-driven
2+
created: 2026-06-05
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
## Context
2+
3+
The rich text editor uses TipTap, which already supports column widths via the `colwidth` attribute on table cells. TipTap's base `TableCell` extension includes this attribute, and the `TableBackgroundColor` extension reads it to generate `<colgroup>` elements for column sizing.
4+
5+
Currently:
6+
7+
- `colwidth` is an array of pixel values (e.g., `[150]` for single column, `[100, 150, 200]` for colspan)
8+
- TipTap has a `resizable: true` option that should enable drag-to-resize, but the custom `TableBackgroundColorNodeView` doesn't implement resize handles
9+
- Users can click column borders, which sets a width, but cannot drag to adjust
10+
- No UI control exists to set exact pixel widths
11+
12+
The existing cell configuration dropdown already has sections for background color, border color/style/width using a `ConfigurationSection` pattern.
13+
14+
## Goals / Non-Goals
15+
16+
**Goals:**
17+
18+
- Add a number input control to the cell configuration dropdown for setting column width
19+
- Support exact pixel values (25-1000px range)
20+
- Provide clear button to reset to auto width
21+
- Handle colspan cells by setting only the first column width
22+
- Follow existing configuration dropdown patterns and styling
23+
- Validate input and clamp to acceptable ranges
24+
25+
**Non-Goals:**
26+
27+
- Implementing drag-to-resize handles (would require significant NodeView work)
28+
- Supporting percentage or other CSS units (only pixels for now)
29+
- Setting widths for all columns in a colspan cell (only first column)
30+
- Syncing widths across all rows (only first row widths apply per TipTap's design)
31+
- Adding column width presets dropdown (keep it simple with number input only)
32+
33+
## Decisions
34+
35+
### Decision 1: Use number input type (not dropdown with presets)
36+
37+
**Rationale:** User requested "exact pixel values" in requirements. A number input provides precision without limiting users to preset sizes.
38+
39+
**Alternatives considered:**
40+
41+
- Dropdown with presets (Small/Medium/Large): Too restrictive, doesn't meet "exact values" requirement
42+
- Hybrid (input + preset buttons): Over-engineered for initial implementation
43+
- Text input: Number input provides better UX with built-in increment/decrement and validation
44+
45+
**Implementation:** Add new `"numberInput"` type to `ConfigurationSection` interface alongside existing `"colorPicker"` and `"dropdown"` types.
46+
47+
---
48+
49+
### Decision 2: Set only first column width for colspan cells
50+
51+
**Rationale:**
52+
53+
- User explicitly requested "set only first column" in requirements
54+
- Simplifies implementation and UX (no need for multi-column width editor)
55+
- Matches TipTap's array-based `colwidth` structure where `colwidth[0]` is the first column
56+
57+
**Alternatives considered:**
58+
59+
- Set all spanned columns to same width: Could surprise users if they had different widths set
60+
- Show per-column width array editor: Complex UI for edge case (most cells don't have colspan)
61+
- Disable control for colspan cells: Too restrictive
62+
63+
**Implementation:** `onChange` handler creates `colwidth` array with single value: `[width]`
64+
65+
---
66+
67+
### Decision 3: Use setCellAttribute command (not custom command)
68+
69+
**Rationale:**
70+
71+
- `setCellAttribute("colwidth", value)` should work because `colwidth` is in TipTap's base TableCell
72+
- Other cell properties (backgroundColor, borderColor, etc.) use `setCellAttribute` successfully
73+
- No need to define custom commands in extensions
74+
75+
**Alternatives considered:**
76+
77+
- Custom `setCellWidth` command in `TableCellBackgroundColor`: Unnecessary abstraction
78+
- Modify `TableCellBackgroundColor.addAttributes()` to re-declare colwidth: Already inherits via `...this.parent?.()`
79+
80+
**Implementation:** Direct call to `editor.chain().focus().setCellAttribute("colwidth", [width]).run()`
81+
82+
---
83+
84+
### Decision 4: Render clear button conditionally (when value exists)
85+
86+
**Rationale:**
87+
88+
- Provides explicit way to reset to auto width (null)
89+
- Visual indicator that a custom width is set
90+
- Follows common UI pattern (seen in search inputs, etc.)
91+
92+
**Alternatives considered:**
93+
94+
- Always show clear button: Clutters UI when empty
95+
- Use empty string to mean auto: Less explicit, could be confusing
96+
- Add separate "Auto" button: Redundant with clear functionality
97+
98+
**Implementation:** Render `×` button only when `currentValue !== null`
99+
100+
---
101+
102+
### Decision 5: Store null for auto width (not empty array or zero)
103+
104+
**Rationale:**
105+
106+
- TipTap treats `colwidth: null` as auto-sizing behavior
107+
- Consistent with how TipTap's base extensions work
108+
- `colwidth: []` or `colwidth: [0]` could cause layout issues
109+
110+
**Implementation:** When user clears input, call `setCellAttribute("colwidth", null)`
111+
112+
## Risks / Trade-offs
113+
114+
### Risk: Parent attribute inheritance might not work
115+
116+
If `TableCellBackgroundColor` doesn't properly inherit `colwidth` from base `TableCell`, `setCellAttribute` calls will fail silently.
117+
118+
**Mitigation:** The extension already uses `...this.parent?.()` in `addAttributes()`, which should preserve `colwidth`. If issues arise, explicitly re-declare `colwidth` in the extension's attributes.
119+
120+
---
121+
122+
### Risk: First-row-only behavior might confuse users
123+
124+
TipTap only uses `colwidth` from the first row of the table to generate `<colgroup>`. Setting widths on other rows has no effect.
125+
126+
**Mitigation:** Could add tooltip or helper text: "Note: Only first row column widths apply." For initial implementation, leave as-is since it matches TipTap's inherent behavior.
127+
128+
---
129+
130+
### Risk: Custom NodeView might interfere with colwidth updates
131+
132+
The `TableBackgroundColorNodeView` manually generates `<colgroup>` in `updateColgroup()`. If it's not reactive to `colwidth` changes, widths might not update visually.
133+
134+
**Mitigation:** The NodeView's `update()` method already calls `updateColgroup()` on node changes, so it should react to `colwidth` updates. Test thoroughly during implementation.
135+
136+
---
137+
138+
### Trade-off: No drag-to-resize (only manual input)
139+
140+
Users lose the convenience of dragging column borders to resize.
141+
142+
**Mitigation:** The number input provides precision that drag handles lack. If drag-to-resize is needed later, it would require integrating ProseMirror's `columnResizing` plugin into the custom NodeView (~200 lines of code). For now, manual input meets the stated requirements.
143+
144+
---
145+
146+
### Trade-off: Pixel-only units (no percentages)
147+
148+
Users cannot set responsive column widths using percentages.
149+
150+
**Mitigation:** Percentage support would require custom rendering logic (TipTap's `colwidth` is pixel-only). Tables in rich text editors typically use fixed layouts. Can be added later if users request it.
151+
152+
## Migration Plan
153+
154+
No migration needed. This is a purely additive feature:
155+
156+
- Existing tables without `colwidth` continue to work (auto width)
157+
- Existing tables with `colwidth` set (via TipTap's base functionality) display correctly
158+
- No data model changes or breaking API changes
159+
160+
Deployment:
161+
162+
1. Merge code changes
163+
2. Run build
164+
3. Deploy widget to Mendix project
165+
4. Feature is immediately available in cell configuration dropdown
166+
167+
Rollback:
168+
169+
- If issues arise, remove the new configuration section from `createCellConfigurationSections()`
170+
- No data corruption risk (colwidth attribute is standard TipTap)
171+
172+
## Open Questions
173+
174+
1. **Should we show the actual rendered column width vs. the set value?**
175+
- The set `colwidth` might differ from actual rendered width due to table layout constraints
176+
- For initial implementation: Show the set value only (simpler)
177+
- Can add "measured width" tooltip later if needed
178+
179+
2. **Should we prevent setting widths on non-first-row cells?**
180+
- Pro: Avoids confusion about why widths don't apply
181+
- Con: Restricts user control, might not match mental model
182+
- Decision: Allow setting on any cell (simpler), rely on TipTap's first-row behavior
183+
184+
3. **Should we add keyboard shortcuts for common widths?**
185+
- Out of scope for initial implementation
186+
- Can be added later if users request it
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
## Why
2+
3+
Users need precise control over table column widths in the rich text editor. Currently, while TipTap supports column widths via the `colwidth` attribute, there's no UI control to set them. Users can only click column borders which sets widths without drag-to-resize capability, making it difficult to achieve desired layouts.
4+
5+
## What Changes
6+
7+
- Add a "Column Width" number input control to the cell configuration dropdown
8+
- Support setting exact pixel widths (25-1000px range)
9+
- Provide "Clear" button to reset to auto width
10+
- Handle colspan cells by setting only the first column width
11+
- Integrate with existing `setCellAttribute` command for `colwidth` attribute
12+
13+
## Capabilities
14+
15+
### New Capabilities
16+
17+
- `table-column-width-control`: UI control in cell configuration dropdown allowing users to set precise column widths in pixels, with validation, auto width support, and colspan handling
18+
19+
### Modified Capabilities
20+
21+
<!-- No existing spec requirements are changing - this is a new UI feature using existing TipTap colwidth infrastructure -->
22+
23+
## Impact
24+
25+
**Affected Files:**
26+
27+
- `src/components/toolbars/components/ConfigurationDropdown.tsx` - Add number input type support
28+
- `src/components/toolbars/components/ConfigurationDropdown.scss` - Add number input styling
29+
- `src/components/toolbars/ToolbarConfig.ts` - Update ConfigurationSection type definition
30+
- `src/components/toolbars/helpers/configurationHelpers.ts` - Add column width section
31+
32+
**User Impact:**
33+
34+
- Positive: Users gain precise control over table column widths via familiar number input UI
35+
- No breaking changes: Feature is additive, existing tables continue to work
36+
37+
**Technical Impact:**
38+
39+
- Uses existing TipTap `colwidth` attribute mechanism (no changes to data model)
40+
- No impact on existing table resize behavior (custom NodeView remains unchanged)
41+
- Follows established configuration dropdown patterns
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
## ADDED Requirements
2+
3+
### Requirement: Column width input control
4+
5+
The cell configuration dropdown SHALL include a number input control labeled "Column Width" that allows users to set the column width in pixels.
6+
7+
#### Scenario: Opening cell configuration shows current width
8+
9+
- **WHEN** user selects a table cell and opens the cell configuration dropdown
10+
- **THEN** the "Column Width" input displays the current column width value if set, or shows empty with "Auto" placeholder if width is auto
11+
12+
#### Scenario: Setting a valid column width
13+
14+
- **WHEN** user enters a numeric value between 25 and 1000 in the "Column Width" input
15+
- **THEN** the column width is set to that exact pixel value and the column resizes accordingly
16+
17+
#### Scenario: Clearing column width for auto sizing
18+
19+
- **WHEN** user clicks the clear button or deletes the value from the "Column Width" input
20+
- **THEN** the column width is reset to auto (null) and the column resizes to fit content
21+
22+
### Requirement: Column width validation
23+
24+
The system SHALL validate column width input to ensure values are within acceptable ranges.
25+
26+
#### Scenario: Entering value below minimum
27+
28+
- **WHEN** user enters a value less than 25 pixels
29+
- **THEN** the system clamps the value to 25 pixels
30+
31+
#### Scenario: Entering value above maximum
32+
33+
- **WHEN** user enters a value greater than 1000 pixels
34+
- **THEN** the system clamps the value to 1000 pixels
35+
36+
#### Scenario: Entering invalid input
37+
38+
- **WHEN** user enters non-numeric text
39+
- **THEN** the system ignores the input and retains the previous value
40+
41+
### Requirement: Colspan cell width handling
42+
43+
The system SHALL set only the first column width when the selected cell has a colspan greater than 1.
44+
45+
#### Scenario: Setting width on colspan cell
46+
47+
- **WHEN** user sets column width on a cell with colspan=3 that currently has colwidth=[100, 150, 200]
48+
- **THEN** the system sets colwidth=[new_value] affecting only the first spanned column
49+
50+
#### Scenario: Reading width from colspan cell
51+
52+
- **WHEN** user opens cell configuration for a cell with colspan=3 and colwidth=[100, 150, 200]
53+
- **THEN** the "Column Width" input displays 100 (the first column's width)
54+
55+
### Requirement: Number input UI component
56+
57+
The configuration dropdown SHALL support a "numberInput" type with number-specific controls.
58+
59+
#### Scenario: Number input with unit label
60+
61+
- **WHEN** a configuration section has type "numberInput" with unit "px"
62+
- **THEN** the UI renders a number input field with "px" unit label beside it
63+
64+
#### Scenario: Number input with clear button
65+
66+
- **WHEN** a configuration section has type "numberInput" and the field has a value
67+
- **THEN** the UI displays a clear button (×) that resets the field to empty when clicked
68+
69+
#### Scenario: Number input with placeholder
70+
71+
- **WHEN** a configuration section has type "numberInput" with placeholder "Auto"
72+
- **THEN** the empty input field shows "Auto" as placeholder text
73+
74+
### Requirement: Column width persistence
75+
76+
The system SHALL persist column width values in the document's colwidth attribute.
77+
78+
#### Scenario: Width persists after save and reload
79+
80+
- **WHEN** user sets a column width to 150 pixels, saves the document, and reloads the page
81+
- **THEN** the column width remains 150 pixels and is displayed correctly in the cell configuration
82+
83+
#### Scenario: Width persists across editing sessions
84+
85+
- **WHEN** user sets column widths on multiple columns and closes the editor
86+
- **THEN** reopening the document displays all columns at their configured widths
87+
88+
### Requirement: Visual feedback
89+
90+
The system SHALL provide clear visual feedback when column width changes.
91+
92+
#### Scenario: Immediate column resize on input
93+
94+
- **WHEN** user changes the column width value in the input field
95+
- **THEN** the table column resizes immediately without requiring additional confirmation
96+
97+
#### Scenario: Clear button visibility
98+
99+
- **WHEN** the column width input has a value
100+
- **THEN** the clear button is visible
101+
- **WHEN** the column width input is empty
102+
- **THEN** the clear button is hidden
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
## 1. Type Definition Updates
2+
3+
- [x] 1.1 Update `ConfigurationSection` interface in `src/components/toolbars/ToolbarConfig.ts` to add `"numberInput"` to type union
4+
- [x] 1.2 Add optional fields to `ConfigurationSection` interface: `min?: number`, `max?: number`, `step?: number`, `placeholder?: string`, `unit?: string`
5+
- [x] 1.3 Update `ConfigurationSection` interface in `src/components/toolbars/components/ConfigurationDropdown.tsx` to match the updated type definition
6+
- [x] 1.4 Update `getCurrentValue` return type to allow `string | number | null` instead of just `string | null`
7+
8+
## 2. UI Component Implementation
9+
10+
- [x] 2.1 Add number input rendering case in `ConfigurationDropdown.tsx` after the dropdown case (around line 73)
11+
- [x] 2.2 Create wrapper div with className `configuration-number-input` containing the input, unit label, and clear button
12+
- [x] 2.3 Implement number input with type="number", min/max/step/placeholder props from section config
13+
- [x] 2.4 Implement conditional unit label display using `configuration-unit` className when `section.unit` exists
14+
- [x] 2.5 Implement conditional clear button (×) with `configuration-clear-button` className, shown only when `currentValue !== null`
15+
- [x] 2.6 Wire up onChange handler to call `section.onChange(e.target.value)` on input change
16+
- [x] 2.7 Wire up clear button onClick handler to call `section.onChange("")` to reset to auto width
17+
18+
## 3. Styling
19+
20+
- [x] 3.1 Add `.configuration-number-input` styles in `ConfigurationDropdown.scss` with flex layout and 4px gap
21+
- [x] 3.2 Add `.configuration-input` styles matching `.configuration-select` with padding, borders, transitions, and focus states
22+
- [x] 3.3 Add number input specific styles to hide spinner arrows (`::-webkit-inner-spin-button`, `::-webkit-outer-spin-button`, `-moz-appearance: textfield`)
23+
- [x] 3.4 Add `.configuration-input::placeholder` styles with gray color and italic font
24+
- [x] 3.5 Add `.configuration-unit` styles with 12px font size, gray color, and nowrap
25+
- [x] 3.6 Add `.configuration-clear-button` styles with padding, borders, hover/active states matching the design
26+
27+
## 4. Cell Configuration Logic
28+
29+
- [x] 4.1 Add new configuration section object in `createCellConfigurationSections()` function in `src/components/toolbars/helpers/configurationHelpers.ts` after `cellBorderWidth`
30+
- [x] 4.2 Set section id to `"cellWidth"`, label to `"Column Width"`, type to `"numberInput"`
31+
- [x] 4.3 Set min to 25, max to 1000, step to 1, placeholder to "Auto", unit to "px"
32+
- [x] 4.4 Implement `getCurrentValue` function that calls `getCellAttributes(editor)`, extracts `colwidth` array, and returns `colwidth[0]` or null
33+
- [x] 4.5 Implement `onChange` function that parses input value, validates it, clamps to min/max range, and calls `setCellAttribute("colwidth", [value])` or `setCellAttribute("colwidth", null)` for empty input
34+
- [x] 4.6 Handle edge case where input is empty string by calling `setCellAttribute("colwidth", null)` to reset to auto width
35+
- [x] 4.7 Handle colspan cells by creating colwidth array with single value `[clampedValue]` regardless of colspan
36+
37+
## 5. Testing & Verification
38+
39+
- [x] 5.1 Test setting column width to valid value (e.g., 150px) and verify column resizes
40+
- [x] 5.2 Test clearing column width via clear button and verify column auto-sizes
41+
- [x] 5.3 Test entering value below minimum (e.g., 10) and verify it clamps to 25
42+
- [x] 5.4 Test entering value above maximum (e.g., 2000) and verify it clamps to 1000
43+
- [x] 5.5 Test entering invalid input (e.g., "abc") and verify it's ignored
44+
- [x] 5.6 Test with colspan cell (colspan=3) and verify only first column width is set
45+
- [x] 5.7 Test that width persists after save/reload of document
46+
- [x] 5.8 Test that clear button visibility toggles correctly (hidden when empty, shown when value exists)
47+
- [x] 5.9 Test that placeholder "Auto" displays when input is empty
48+
- [x] 5.10 Test keyboard navigation and accessibility of number input control
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
schema: spec-driven
2+
created: 2026-06-11
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# code-view-highlighting
2+
3+
Add syntax highlighting to code view mode using react-simple-code-editor and highlight.js

0 commit comments

Comments
 (0)