picasso-skill 1.6.0 → 2.0.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.
@@ -0,0 +1,227 @@
1
+ # Tables and Forms Reference
2
+
3
+ ## Table of Contents
4
+ 1. Sortable Tables
5
+ 2. Responsive Tables
6
+ 3. Inline Editing
7
+ 4. Multi-Select Patterns
8
+ 5. Form Validation
9
+ 6. Multi-Step Forms
10
+ 7. Complex Inputs
11
+ 8. Common Mistakes
12
+
13
+ ---
14
+
15
+ ## 1. Sortable Tables
16
+
17
+ ```html
18
+ <table>
19
+ <thead>
20
+ <tr>
21
+ <th aria-sort="ascending">
22
+ <button>Name <span aria-hidden="true">↑</span></button>
23
+ </th>
24
+ <th aria-sort="none">
25
+ <button>Date <span aria-hidden="true">↕</span></button>
26
+ </th>
27
+ </tr>
28
+ </thead>
29
+ </table>
30
+ ```
31
+
32
+ - Use `aria-sort` on `<th>`: `ascending`, `descending`, or `none`.
33
+ - Sort icon: `↑` ascending, `↓` descending, `↕` unsorted. Use `aria-hidden="true"` on the icon.
34
+ - Sortable headers must be `<button>` inside `<th>`, not clickable `<th>`.
35
+ - Default sort: most recent first for dates, alphabetical for names.
36
+
37
+ ---
38
+
39
+ ## 2. Responsive Tables
40
+
41
+ **Option A: Horizontal scroll** (preferred for data tables)
42
+
43
+ ```css
44
+ .table-container {
45
+ overflow-x: auto;
46
+ -webkit-overflow-scrolling: touch;
47
+ border: 1px solid var(--border);
48
+ border-radius: 8px;
49
+ }
50
+
51
+ /* Fade edge to hint scrollability */
52
+ .table-container::after {
53
+ content: '';
54
+ position: absolute;
55
+ right: 0;
56
+ top: 0;
57
+ bottom: 0;
58
+ width: 40px;
59
+ background: linear-gradient(to left, var(--surface-1), transparent);
60
+ pointer-events: none;
61
+ }
62
+ ```
63
+
64
+ **Option B: Stacked cards** (for simple tables on mobile)
65
+
66
+ ```css
67
+ @media (max-width: 640px) {
68
+ table, thead, tbody, th, td, tr { display: block; }
69
+ thead { display: none; }
70
+ td { padding: 8px 16px; text-align: right; }
71
+ td::before {
72
+ content: attr(data-label);
73
+ float: left;
74
+ font-weight: 600;
75
+ color: var(--text-secondary);
76
+ }
77
+ }
78
+ ```
79
+
80
+ ---
81
+
82
+ ## 3. Inline Editing
83
+
84
+ Click to edit pattern: display text, click reveals input, blur/Enter saves.
85
+
86
+ ```jsx
87
+ function EditableCell({ value, onSave }) {
88
+ const [editing, setEditing] = useState(false);
89
+ const [draft, setDraft] = useState(value);
90
+
91
+ if (!editing) return (
92
+ <span onClick={() => setEditing(true)} className="cursor-text hover:bg-surface-2 px-2 py-1 rounded">
93
+ {value}
94
+ </span>
95
+ );
96
+
97
+ return (
98
+ <input
99
+ value={draft}
100
+ onChange={e => setDraft(e.target.value)}
101
+ onBlur={() => { onSave(draft); setEditing(false); }}
102
+ onKeyDown={e => { if (e.key === 'Enter') { onSave(draft); setEditing(false); } if (e.key === 'Escape') setEditing(false); }}
103
+ autoFocus
104
+ className="input-base w-full"
105
+ />
106
+ );
107
+ }
108
+ ```
109
+
110
+ Show a subtle pencil icon on row hover. Use `opacity-0 group-hover:opacity-100` pattern.
111
+
112
+ ---
113
+
114
+ ## 4. Multi-Select Patterns
115
+
116
+ - **Checkbox column**: leftmost column, always visible.
117
+ - **Shift-click range select**: select from last checked to current.
118
+ - **Select all**: checkbox in header, toggles all visible (filtered) rows.
119
+ - **Bulk action bar**: appears when 1+ rows selected. Shows count + actions.
120
+
121
+ ```jsx
122
+ <div className={`fixed bottom-4 left-1/2 -translate-x-1/2 bg-surface-2 rounded-xl px-4 py-2
123
+ flex items-center gap-4 shadow-lg border border-border transition-transform
124
+ ${selectedCount > 0 ? 'translate-y-0' : 'translate-y-[200%]'}`}>
125
+ <span className="text-sm font-medium">{selectedCount} selected</span>
126
+ <button className="btn-ghost text-sm">Export</button>
127
+ <button className="btn-ghost text-sm text-red">Delete</button>
128
+ </div>
129
+ ```
130
+
131
+ ---
132
+
133
+ ## 5. Form Validation
134
+
135
+ **When to validate:**
136
+
137
+ | Trigger | Use For |
138
+ |---|---|
139
+ | On blur | Email format, required fields, min/max length |
140
+ | On submit | All fields, server-side checks |
141
+ | Real-time (on change) | Password strength, username availability |
142
+ | Never on keystroke | Don't interrupt typing. Wait for blur or 500ms debounce. |
143
+
144
+ ```jsx
145
+ <div className="space-y-1.5">
146
+ <label htmlFor="email" className="text-sm font-medium">Email</label>
147
+ <input
148
+ id="email"
149
+ type="email"
150
+ aria-invalid={error ? "true" : undefined}
151
+ aria-describedby={error ? "email-error" : undefined}
152
+ className={`input-base ${error ? 'border-red' : ''}`}
153
+ />
154
+ {error && (
155
+ <p id="email-error" role="alert" className="text-xs text-red flex items-center gap-1">
156
+ <svg className="w-3.5 h-3.5" aria-hidden="true">...</svg>
157
+ {error}
158
+ </p>
159
+ )}
160
+ </div>
161
+ ```
162
+
163
+ Error messages: specific and helpful. "Enter a valid email" not "Invalid input."
164
+
165
+ ---
166
+
167
+ ## 6. Multi-Step Forms
168
+
169
+ Show a progress indicator. Allow back navigation. Validate per step, not all at once.
170
+
171
+ ```jsx
172
+ <div className="flex items-center gap-2 mb-8">
173
+ {steps.map((step, i) => (
174
+ <Fragment key={i}>
175
+ <div className={`flex items-center justify-center h-8 w-8 rounded-full text-sm font-bold
176
+ ${i < currentStep ? 'bg-accent text-white' :
177
+ i === currentStep ? 'border-2 border-accent text-accent' :
178
+ 'border border-border text-muted'}`}>
179
+ {i < currentStep ? '✓' : i + 1}
180
+ </div>
181
+ {i < steps.length - 1 && (
182
+ <div className={`flex-1 h-0.5 ${i < currentStep ? 'bg-accent' : 'bg-border'}`} />
183
+ )}
184
+ </Fragment>
185
+ ))}
186
+ </div>
187
+ ```
188
+
189
+ Rules:
190
+ - Save progress per step (don't lose data on back).
191
+ - Validate step before advancing (disable Next if invalid).
192
+ - Show step count: "Step 2 of 4".
193
+ - Allow clicking completed steps to go back.
194
+ - Final step: show summary before submit.
195
+
196
+ ---
197
+
198
+ ## 7. Complex Inputs
199
+
200
+ **Date pickers:** Use native `<input type="date">` first. Custom picker only if design requires it. Always allow manual text entry as fallback.
201
+
202
+ **File upload:** Show progress, preview (for images), allow removal.
203
+
204
+ ```jsx
205
+ <label className="flex flex-col items-center gap-2 p-8 border-2 border-dashed border-border
206
+ rounded-xl cursor-pointer hover:border-accent hover:bg-accent/5 transition-colors">
207
+ <svg>...</svg>
208
+ <span className="text-sm text-secondary">Drop files or click to upload</span>
209
+ <input type="file" className="hidden" onChange={handleUpload} />
210
+ </label>
211
+ ```
212
+
213
+ **Address autocomplete:** Use Google Places API or similar. Show suggestions in a dropdown. Parse into structured fields (street, city, state, zip).
214
+
215
+ ---
216
+
217
+ ## 8. Common Mistakes
218
+
219
+ - **Sortable `<th>` without `<button>`.** Clicking a `<th>` isn't keyboard accessible.
220
+ - **No `aria-sort` on sortable columns.** Screen readers can't announce sort state.
221
+ - **Validating on every keystroke.** Annoying. Use blur or 500ms debounce.
222
+ - **Error messages without `role="alert"`.** Screen readers won't announce them.
223
+ - **Multi-step form losing data on back.** Save each step's state.
224
+ - **No horizontal scroll hint on tables.** Users don't know content is hidden. Add fade gradient.
225
+ - **Custom date picker without text input fallback.** Some users prefer typing dates.
226
+ - **Select all selecting ALL rows, not just filtered.** Only select what's visible.
227
+ - **Labels as placeholder text.** Labels must be visible above the input, always.