@kolkrabbi/kol-component 0.30.0 → 0.31.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kolkrabbi/kol-component",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.31.0",
|
|
4
4
|
"description": "KOL design-system components — atoms through organisms, emitting canonical kol-* classes. Pairs with @kolkrabbi/kol-theme for styling.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"@floating-ui/react": "^0.27.19",
|
|
25
25
|
"embla-carousel-react": "^8.6.0",
|
|
26
26
|
"react-syntax-highlighter": "^16.1.1",
|
|
27
|
-
"@kolkrabbi/kol-icons": "0.
|
|
27
|
+
"@kolkrabbi/kol-icons": "0.12.0"
|
|
28
28
|
},
|
|
29
29
|
"peerDependencies": {
|
|
30
30
|
"framer-motion": "^12.0.0",
|
|
@@ -128,11 +128,32 @@ export default function FieldRow({
|
|
|
128
128
|
placeholder,
|
|
129
129
|
disabled = false,
|
|
130
130
|
}) {
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
131
|
+
const dash = <span className="kol-helper-10 text-meta">—</span>
|
|
132
|
+
/* Empty MEDIA is a framed + slot, empty FILE is a Choose-file control —
|
|
133
|
+
* the reference panel's grammar (user frames 2026-08-09), not a bare
|
|
134
|
+
* icon button. */
|
|
135
|
+
const mediaEmpty = onPick ? (
|
|
136
|
+
<button
|
|
137
|
+
type="button"
|
|
138
|
+
aria-label={label}
|
|
139
|
+
disabled={disabled}
|
|
140
|
+
onClick={onPick}
|
|
141
|
+
className="flex h-14 w-20 cursor-pointer items-center justify-center rounded border border-fg-16 bg-fg-02 text-body transition-colors duration-150 hover:text-emphasis"
|
|
142
|
+
>
|
|
143
|
+
<Icon name="plus" size={14} />
|
|
144
|
+
</button>
|
|
145
|
+
) : dash
|
|
146
|
+
const fileEmpty = onPick ? (
|
|
147
|
+
<button
|
|
148
|
+
type="button"
|
|
149
|
+
aria-label={label}
|
|
150
|
+
disabled={disabled}
|
|
151
|
+
onClick={onPick}
|
|
152
|
+
className="kol-control kol-control--filled kol-control-sm kol-mono-12 w-full cursor-pointer text-left text-meta"
|
|
153
|
+
>
|
|
154
|
+
Choose file…
|
|
155
|
+
</button>
|
|
156
|
+
) : dash
|
|
136
157
|
|
|
137
158
|
let control = null
|
|
138
159
|
if (type === 'text') {
|
|
@@ -168,7 +189,7 @@ export default function FieldRow({
|
|
|
168
189
|
/>
|
|
169
190
|
)}
|
|
170
191
|
</span>
|
|
171
|
-
) :
|
|
192
|
+
) : mediaEmpty
|
|
172
193
|
} else if (type === 'file') {
|
|
173
194
|
control = value ? (
|
|
174
195
|
/* kol-tag--data: a filename renders VERBATIM — the chip uppercase is
|
|
@@ -176,7 +197,7 @@ export default function FieldRow({
|
|
|
176
197
|
<Tag variant="secondary" size="sm" hash={false} className="kol-tag--data" onRemove={onChange ? () => onChange(null) : undefined}>
|
|
177
198
|
{value.name ?? value}
|
|
178
199
|
</Tag>
|
|
179
|
-
) :
|
|
200
|
+
) : fileEmpty
|
|
180
201
|
}
|
|
181
202
|
|
|
182
203
|
return (
|
|
@@ -147,17 +147,19 @@ export default function RecordManager({
|
|
|
147
147
|
return {
|
|
148
148
|
...col,
|
|
149
149
|
render: (row) => (
|
|
150
|
-
|
|
150
|
+
/* the open affordance is the reference's BOXED toggle-overlay
|
|
151
|
+
* button, pinned at the cell's end — not an inline icon riding
|
|
152
|
+
* the text (user frames 2026-08-09). Hover-revealed per row. */
|
|
153
|
+
<span className="flex items-center justify-between gap-2 min-w-0 max-w-full">
|
|
151
154
|
<span className="truncate text-emphasis">{col.render ? col.render(row) : row[col.accessor]}</span>
|
|
152
|
-
<
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
iconSize={12}
|
|
157
|
-
aria-label={typeof col.header === 'string' ? col.header : 'Open'}
|
|
158
|
-
className="shrink-0 opacity-0 group-hover:opacity-100 focus-visible:opacity-100"
|
|
155
|
+
<button
|
|
156
|
+
type="button"
|
|
157
|
+
aria-label="Toggle overlay"
|
|
158
|
+
className="shrink-0 inline-flex cursor-pointer rounded-sm border border-fg-16 bg-transparent p-1 text-body opacity-0 transition-opacity duration-150 group-hover:opacity-100 focus-visible:opacity-100 hover:text-emphasis"
|
|
159
159
|
onClick={() => openRecord(row)}
|
|
160
|
-
|
|
160
|
+
>
|
|
161
|
+
<Icon name="toggle-overlay" size={14} />
|
|
162
|
+
</button>
|
|
161
163
|
</span>
|
|
162
164
|
),
|
|
163
165
|
}
|
|
@@ -202,55 +204,52 @@ export default function RecordManager({
|
|
|
202
204
|
return col
|
|
203
205
|
})
|
|
204
206
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
const i = rows.indexOf(row)
|
|
213
|
-
return (
|
|
214
|
-
/* REST-VISIBLE (2026-08-09 — "Im looking for this handle"): the
|
|
215
|
-
* reference draws the grip dim at rest; hover-only hid the whole
|
|
216
|
-
* reorder affordance. */
|
|
217
|
-
<button
|
|
218
|
-
type="button"
|
|
219
|
-
aria-label={reorderLabel(i + 1)}
|
|
220
|
-
className="cursor-grab touch-none bg-transparent border-0 p-0 text-meta hover:text-emphasis"
|
|
221
|
-
onPointerDown={(e) => startDrag(e, i)}
|
|
222
|
-
>
|
|
223
|
-
<Icon name="drag-handle" size={14} />
|
|
224
|
-
</button>
|
|
225
|
-
)
|
|
226
|
-
},
|
|
227
|
-
})
|
|
228
|
-
}
|
|
229
|
-
prefix.push({
|
|
230
|
-
accessor: '__select',
|
|
207
|
+
/* ONE LEADING FIELD (reference row anatomy, user frames 2026-08-09:
|
|
208
|
+
* "reorder and the toggle is the same field — look at the sizes"): the
|
|
209
|
+
* grip and the row checkbox share a single cell at matched sizes. The
|
|
210
|
+
* grip is rest-visible, dim; the header keeps only the select-all box,
|
|
211
|
+
* with the grip column held as space so the checkboxes align. */
|
|
212
|
+
const prefix = [{
|
|
213
|
+
accessor: '__lead',
|
|
231
214
|
header: (
|
|
232
|
-
<
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
215
|
+
<span className="inline-flex items-center gap-2">
|
|
216
|
+
{onReorder && <span className="w-4" aria-hidden="true" />}
|
|
217
|
+
<ToggleCheckbox
|
|
218
|
+
checked={rows.length > 0 && selected.size === rows.length}
|
|
219
|
+
onChange={() =>
|
|
220
|
+
updateSelection(selected.size === rows.length ? new Set() : new Set(rows.map(rowId)))
|
|
221
|
+
}
|
|
222
|
+
/>
|
|
223
|
+
</span>
|
|
238
224
|
),
|
|
239
|
-
className: 'kol-table-cell-text w-
|
|
225
|
+
className: 'kol-table-cell-text w-14',
|
|
240
226
|
render: (row) => {
|
|
241
|
-
const
|
|
227
|
+
const i = rows.indexOf(row)
|
|
228
|
+
const id = rowId(row, i)
|
|
242
229
|
return (
|
|
243
|
-
<
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
230
|
+
<span className="inline-flex items-center gap-2">
|
|
231
|
+
{onReorder && (
|
|
232
|
+
<button
|
|
233
|
+
type="button"
|
|
234
|
+
aria-label={reorderLabel(i + 1)}
|
|
235
|
+
className="inline-flex w-4 cursor-grab touch-none justify-center border-0 bg-transparent p-0 text-meta hover:text-emphasis"
|
|
236
|
+
onPointerDown={(e) => startDrag(e, i)}
|
|
237
|
+
>
|
|
238
|
+
<Icon name="drag-handle" size={16} />
|
|
239
|
+
</button>
|
|
240
|
+
)}
|
|
241
|
+
<ToggleCheckbox
|
|
242
|
+
checked={selected.has(id)}
|
|
243
|
+
onChange={() => {
|
|
244
|
+
const next = new Set(selected)
|
|
245
|
+
next.has(id) ? next.delete(id) : next.add(id)
|
|
246
|
+
updateSelection(next)
|
|
247
|
+
}}
|
|
248
|
+
/>
|
|
249
|
+
</span>
|
|
251
250
|
)
|
|
252
251
|
},
|
|
253
|
-
}
|
|
252
|
+
}]
|
|
254
253
|
return [...prefix, ...resolved]
|
|
255
254
|
}, [columns, rows, selected, onReorder, drag]) // eslint-disable-line react-hooks/exhaustive-deps
|
|
256
255
|
|