Skip to content

Commit 7a9f163

Browse files
marcelfolaronclaude
andcommitted
feat(components): add no-op forms.textarea + migrate 10 plain textareas
Third primitive after button (#3531) and text-input (#3558). A no-op textarea component plus migration of the 10 plain <textarea> tags to it. Component body is <textarea {{ $attributes }}>{{ $slot }}</textarea> — attributes pass through and the field value is the slot (inner content), preserved exactly (textareas are whitespace-sensitive). No variant arm: plain textareas carry no distinct style class. DEFERRED (left RAW) — the 19 Tiptap rich-text editor textareas. JS upgrades exactly textarea.tiptapSimple / textarea.tiptapComplex (app/.../core/tiptap/index.js) plus the Wiki .wiki-editor-textarea; routing those through the component would break the editors. Migrated 10 plain textareas across 6 files (Help projectDefinitionStep x3, Ideas/Wiki newMilestone, Timesheets add/edit + Tickets timesheet description, Widgets myToDos x2). Verified: full diff is pure <textarea> <-> <x-global::forms.textarea> tag swaps (14 ins / 14 del symmetric), view:cache + Pint clean, static audit = 0 plain missed, 19 editors deferred. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 0042d0c commit 7a9f163

9 files changed

Lines changed: 70 additions & 16 deletions

File tree

app/Domain/Help/Templates/projectDefinitionStep.blade.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@
77
<p>{!! __('text.structured_project_thinking') !!}</p>
88
<br />
99
<label><strong>{{ __('label.what_are_you_trying_to_accomplish') }}</strong></label>
10-
<textarea id="accomplish" name="accomplish" value="" placeholder="" rows="3" style="width:99%; overflow-x: hidden;"></textarea>
10+
<x-global::forms.textarea id="accomplish" name="accomplish" value="" placeholder="" rows="3" style="width:99%; overflow-x: hidden;"></x-global::forms.textarea>
1111
<br />
1212
<label><strong>{{ __('label.how_does_the_world_look_like') }}</strong></label>
13-
<textarea id="wordlview" name="worldview" value="" placeholder="" rows="3" style="width:99%; overflow-x: hidden;"></textarea>
13+
<x-global::forms.textarea id="wordlview" name="worldview" value="" placeholder="" rows="3" style="width:99%; overflow-x: hidden;"></x-global::forms.textarea>
1414
<br />
1515
<label><strong>{{ __('label.why_is_this_important') }}</strong></label>
16-
<textarea id="whyImportant" name="whyImportant" value="" placeholder="" rows="3" style="width:99%; overflow-x: hidden;"></textarea>
16+
<x-global::forms.textarea id="whyImportant" name="whyImportant" value="" placeholder="" rows="3" style="width:99%; overflow-x: hidden;"></x-global::forms.textarea>
1717

1818
</div>
1919
<div class="col-md-4">

app/Domain/Ideas/Templates/ideaDialog.blade.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ class="fa fa-link"></span> {!! __('headlines.linked_milestone') !!} <i class="fa
7474
</div>
7575
<div class="row" id="newMilestone" style="display:none;">
7676
<div class="col-md-12">
77-
<textarea name="newMilestone"></textarea><br/>
77+
<x-global::forms.textarea name="newMilestone"></x-global::forms.textarea><br/>
7878
<input type="hidden" name="type" value="milestone"/>
7979
<input type="hidden" name="leancanvasitemid" value="{{ $id }} "/>
8080
<x-global::forms.button tag="input" inputType="button" :labelText="__('buttons.save')" onclick="jQuery('#primaryCanvasSubmitButton').click()"

app/Domain/Tickets/Templates/submodules/timesheet.blade.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
</span>
3636
<label for="description">{!! __('label.description') !!}</label>
3737
<span class="field">
38-
<textarea rows="5" cols="50" id="description" name="description">{{ $values['description'] }}</textarea><br />
38+
<x-global::forms.textarea rows="5" cols="50" id="description" name="description">{{ $values['description'] }}</x-global::forms.textarea><br />
3939
</span>
4040
<input type="hidden" name="saveTimes" value="1" />
4141
<input type="submit" value="{{ __('buttons.save') }}" name="saveTimes" class="button" />

app/Domain/Timesheets/Templates/addTime.blade.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,9 @@
105105
<label for="hours">{!! __('HOURS') !!}</label> <x-global::forms.text-input
106106
id="hours" name="hours"
107107
value="{{ $values['hours'] }}" size="7" /> <br/>
108-
<label for="description">{!! __('DESCRIPTION') !!}</label> <textarea
108+
<label for="description">{!! __('DESCRIPTION') !!}</label> <x-global::forms.textarea
109109
rows="5" cols="50" id="description"
110-
name="description">{{ $values['description'] }}</textarea><br/>
110+
name="description">{{ $values['description'] }}</x-global::forms.textarea><br/>
111111
<br/>
112112
<br/>
113113
<label for="invoicedEmpl">{!! __('INVOICED') !!}</label> <input

app/Domain/Timesheets/Templates/editTime.blade.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,8 @@ function filterProjectsByClient() {
124124
<label for="hours">{!! __('label.hours') !!}</label> <x-global::forms.text-input
125125
id="hours" name="hours"
126126
value="{{ $values['hours'] }}" size="7" /> <br />
127-
<label for="description">{!! __('label.description') !!}</label> <textarea
128-
rows="5" cols="50" id="description" name="description">{{ $values['description'] }}</textarea><br />
127+
<label for="description">{!! __('label.description') !!}</label> <x-global::forms.textarea
128+
rows="5" cols="50" id="description" name="description">{{ $values['description'] }}</x-global::forms.textarea><br />
129129

130130

131131

app/Domain/Widgets/Templates/partials/myToDos.blade.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -196,8 +196,8 @@ class='active'
196196
value=""/>
197197
<input type="hidden" name="dateToFinish"
198198
value="{{ date('Y-m-d', strtotime('next friday'))}}"/>
199-
<textarea name="description" class="description-input" style="display:none;"
200-
placeholder="{{ __('input.placeholders.description') }}"></textarea>
199+
<x-global::forms.textarea name="description" class="description-input" style="display:none;"
200+
placeholder="{{ __('input.placeholders.description') }}"></x-global::forms.textarea>
201201
</div>
202202
<div>
203203
<x-global::forms.button tag="input" inputType="submit" :labelText="__('buttons.save')" name="create"
@@ -281,8 +281,8 @@ class='active'
281281
@endphp
282282
<input type="hidden" name="dateToFinish"
283283
value="{{ $dueDate }}"/>
284-
<textarea name="description" class="description-input" style="display:none;"
285-
placeholder="{{ __('input.placeholders.description') }}"></textarea>
284+
<x-global::forms.textarea name="description" class="description-input" style="display:none;"
285+
placeholder="{{ __('input.placeholders.description') }}"></x-global::forms.textarea>
286286
</div>
287287
<div>
288288
<x-global::forms.button tag="input" inputType="submit" :labelText="__('buttons.save')" name="create"

app/Domain/Wiki/Templates/articleDialog.blade.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ function createTree($id, $parentId, &$wikiHeadlines, &$wikiHL, $indent)
8888
</div>
8989
<div class="row" id="newMilestone" style="display:none;">
9090
<div class="col-md-12">
91-
<textarea name="newMilestone"></textarea><br />
91+
<x-global::forms.textarea name="newMilestone"></x-global::forms.textarea><br />
9292
<input type="hidden" name="type" value="milestone" />
9393
<input type="hidden" name="leancanvasitemid" value="{{ $id }} " />
9494
<x-global::forms.button tag="input" inputType="button" :labelText="__('buttons.save')" onclick="jQuery('#primaryArticleSubmitButton').click()" contentRole="primary" />

app/Views/Templates/components/COMPONENTS.md

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,8 @@ Status: ⬜ todo · 🟡 in progress · ✅ no-op done (on master) · 🎨 desig
8686
| Component | Tag | Cat | Status | Ref | Notes |
8787
|---|---|---|---|---|---|
8888
| button | `forms.button` | forms || refactor/table-component | merged #3531: no-op migration + 3-tier role model |
89-
| text-input | `forms.text-input` | forms | 🟡 | refactor/table-component | PR #3558: thin no-op; **146 call-sites / 56 files migrated**; **defer JS-coupled** (datepickers/tags/inline-edit/color/sorter/hourCell) + legacy `<?php echo ?>`-in-attr |
90-
| textarea | `forms.textarea` | forms | | selectsComponentUpdates | |
89+
| text-input | `forms.text-input` | forms | | refactor/table-component | merged #3558: no-op; 146 call-sites / 56 files; variants `headline`/`large`/`small` (dropped `form`/`legacy` as CSS-redundant); HTML-native `type` prop; **defer JS-coupled** (datepickers/tags/inline-edit/color/sorter/hourCell) + legacy `<?php echo ?>`-in-attr |
90+
| textarea | `forms.textarea` | forms | 🟡 | selectsComponentUpdates | thin no-op (attrs + inner-content slot); 10 plain migrated / 6 files; **defer Tiptap editors** (`.tiptapSimple`/`.tiptapComplex`/`.wiki-editor-textarea`) |
9191
| select (native) | `forms.select` | forms || refactor/table-component | native no-op first; JS-enhanced later |
9292
| form-field | `forms.field-row` | forms || refactor/table-component | label-row + caption + validation wrapper |
9393
| card (content-box) | `elements.card` | elements || ui-components | **replaces `.maincontentinner`** (167 sites) |
@@ -304,3 +304,14 @@ Only visually-distinct treatments earn a variant. Verdicts:
304304
canonical one being .secretInput) but its call-sites are the deferred async-save fields, so it's a planned
305305
variant; `legacy`(.input) = REDUNDANT (no `.input` CSS rule exists anywhere). **Dropped `variant="legacy"`**
306306
(1 call-site, TwoFA/edit → bare; removed the arm). Component now exposes only `headline`/`large`/`small`.
307+
- _textarea_: thin no-op `forms.textarea` (off master, post-#3558 merge; worktree `.claude/worktrees/textarea`).
308+
Body is `<textarea {{ $attributes }}>{{ $slot }}</textarea>` — attributes pass through, the field value is
309+
the slot (inner content) preserved EXACTLY (textareas are whitespace-sensitive). **10 plain textareas
310+
migrated across 6 files** (Help projectDefinitionStep ×3, Ideas/Wiki newMilestone, Timesheets add/edit +
311+
Tickets timesheet description, Widgets myToDos description-input ×2). **19 Tiptap editor textareas left
312+
RAW** — JS upgrades exactly `textarea.tiptapSimple` / `textarea.tiptapComplex` (core/tiptap/index.js) plus
313+
the Wiki `.wiki-editor-textarea`; never route those through the component. No `variant` arm (plain
314+
textareas carry no distinct style class; the only textarea classes are editor-coupled). Verified: full diff
315+
is pure `<textarea>``<x-global::forms.textarea>` tag swaps (14 ins / 14 del symmetric), view:cache + Pint
316+
clean, static audit = 0 plain missed / 19 editors deferred. (No live render: the dev server serves the main
317+
checkout, not this worktree branch; the swap is a by-construction no-op like text-input's proven mechanism.)
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
@props([
2+
// NO-OP textarea: renders a plain <textarea> with today's attributes + inner content.
3+
// There is NO `variant` arm: the only textarea style-classes in the app (.tiptapSimple /
4+
// .tiptapComplex / .wiki-editor-textarea) are JS rich-text EDITOR mounts — never route those
5+
// through this component (see do-not-touch below). Plain textareas carry no distinct style
6+
// class, so attribute + content passthrough is the whole no-op surface.
7+
8+
// --- design-system IDL: declared for the durable contract (shared with forms.text-input),
9+
// intentionally NOT rendered in no-op mode (a label/validation wrapper would change
10+
// today's markup). Activated in the design phase's field-row layout. ---
11+
'contentRole' => '', // reserved
12+
'state' => '', // info | warning | danger | success (validation) — reserved
13+
'scale' => '', // xs | s | m | l | xl — reserved
14+
'labelPosition' => 'top', // reserved
15+
'labelText' => '', // reserved
16+
'caption' => '', // reserved
17+
'validationText' => '', // reserved
18+
'validationState' => '', // reserved
19+
])
20+
21+
{{--
22+
forms.textarea — NO-OP textarea.
23+
24+
Renders a plain <textarea> with the SAME attributes the app uses today; every attribute
25+
(name, id, rows, cols, placeholder, style, class, data-*, hx-*, required, …) passes through
26+
via $attributes, and the field's value is the slot (inner content), preserved EXACTLY.
27+
28+
⚠️ DO NOT route rich-text EDITOR textareas through this component — JS upgrades them to Tiptap
29+
and they will break. Keep these RAW:
30+
• Tiptap: class="tiptapSimple" / class="tiptapComplex" (JS scans `textarea.tiptapSimple` /
31+
`textarea.tiptapComplex` and mounts an editor — public/assets/js/app/core/tiptap/index.js)
32+
• Wiki editor: class="wiki-editor-textarea" (id="wikiArticleContent")
33+
• any textarea with an inline on* handler or a data-*editor* attribute.
34+
35+
⚠️ Whitespace matters: a textarea's value IS its inner content. Keep the slot tight —
36+
<x-global::forms.textarea …>{{ $value }}</x-global::forms.textarea> — never add newlines/indent
37+
around the value, or you change the field's content.
38+
39+
Migration:
40+
<textarea name="x"></textarea> -> <x-global::forms.textarea name="x"></x-global::forms.textarea>
41+
<textarea name="x">{{ $v }}</textarea> -> <x-global::forms.textarea name="x">{{ $v }}</x-global::forms.textarea>
42+
--}}
43+
<textarea {{ $attributes }}>{{ $slot }}</textarea>

0 commit comments

Comments
 (0)