@kolkrabbi/kol-component 0.176.0 → 0.178.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 +1 -1
- package/src/atoms/Button.jsx +1 -1
- package/src/index.js +1 -0
- package/src/molecules/ContentCard.jsx +11 -1
- package/src/molecules/ContentRow.jsx +6 -0
- package/src/molecules/ContentText.jsx +10 -0
- package/src/organisms/ContentFilters.jsx +2 -1
- package/src/organisms/MediaLibraryPages.jsx +2 -8
- package/src/utilities/formatSize.js +14 -0
- package/src/utilities/tone.js +9 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kolkrabbi/kol-component",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.178.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",
|
package/src/atoms/Button.jsx
CHANGED
|
@@ -18,7 +18,7 @@ import { glyphSize } from '../hooks/glyphLadders.js'
|
|
|
18
18
|
* @param {string} props.iconRight - Icon name to display on the right
|
|
19
19
|
* @param {string} props.iconLeftHover - Icon to show on hover (left position)
|
|
20
20
|
* @param {string} props.iconRightHover - Icon to show on hover (right position)
|
|
21
|
-
* @param {'primary'|'secondary'|'outline'|'ghost'|'grey'|'sunken'} props.tone - the ground (tone-is-the-ground-axis, 2026-09-03) — wins over `variant` on the same element; unset = inherit the wrapper's. `sunken` = the control set's dark well + fg-96 ink (ControlToneSunken); `inverse` aliased
|
|
21
|
+
* @param {'primary'|'secondary'|'inverted'|'outline'|'ghost'|'grey'|'sunken'} props.tone - the ground (`secondary` = the page surface, `inverted` = the text colour as fill — what `variant="secondary"` paints) (tone-is-the-ground-axis, 2026-09-03) — wins over `variant` on the same element; unset = inherit the wrapper's. `sunken` = the control set's dark well + fg-96 ink (ControlToneSunken); `inverse` aliased
|
|
22
22
|
* @param {string} props.iconOnly - Icon name for icon-only button
|
|
23
23
|
* @param {string} props.iconOnlyHover - Icon to show on hover (icon-only)
|
|
24
24
|
* @param {boolean} props.animateIcon - Disable default hover states to focus on icon animation
|
package/src/index.js
CHANGED
|
@@ -159,6 +159,7 @@ export { nearestRatio, RATIOS } from './utilities/ratios.js'
|
|
|
159
159
|
* useDragResize wear ONE implementation (OneGrabGestureBothRails, 2026-08-30) */
|
|
160
160
|
export { default as useGrabEdge } from './hooks/useGrabEdge.js'
|
|
161
161
|
export { default as markdownToHtml, inlineToHtml } from './utilities/markdownToHtml.js'
|
|
162
|
+
export { default as formatSize } from './utilities/formatSize.js'
|
|
162
163
|
export { default as RecordManager } from './organisms/RecordManager.jsx'
|
|
163
164
|
export { default as SpectrumGrid } from './organisms/SpectrumGrid.jsx'
|
|
164
165
|
export { default as Table } from './organisms/Table.jsx'
|
|
@@ -30,6 +30,7 @@ import ContentText from './ContentText.jsx'
|
|
|
30
30
|
* the A4 question is open (06-content-card-system.md §4). */
|
|
31
31
|
const RATIOS = {
|
|
32
32
|
file: '1 / 1',
|
|
33
|
+
slide: '16 / 9', /* a deck is a 1920×1080 stage (slide-variant-and-shelf-preset, 2026-09-03) */
|
|
33
34
|
catalog: '1 / 1.41421',
|
|
34
35
|
article: '16 / 9',
|
|
35
36
|
showcase: '3 / 4',
|
|
@@ -43,6 +44,11 @@ const BOX = {
|
|
|
43
44
|
* like I've said that before" — the ListingCardThumbBorder ruling): the selected
|
|
44
45
|
* state reads from the checked ToggleCheckbox, not a fg-64 border */
|
|
45
46
|
file: { layout: 'stack', border: null, bg: 'var(--kol-fg-02)', pad: 'var(--kol-pad-card-sm)' },
|
|
47
|
+
/* SLIDE (slide-variant-and-shelf-preset, kol-client-olina 2026-09-03; user: "they are genuinely
|
|
48
|
+
* different with 16:9 layout and those exposed properties"): file's stack — cover on top, the
|
|
49
|
+
* plate below — on the PAGE'S surface, rest and hover (olina's /slide-deck, read off the render).
|
|
50
|
+
* The plate is not a tone (user: "no just controls"); it is this kind's colour. */
|
|
51
|
+
slide: { layout: 'stack', border: null, bg: 'var(--kol-surface-primary)', pad: 'var(--kol-pad-card-sm)' },
|
|
46
52
|
/* THE FRAME READS BACKWARDS (CatalogCardFrameAndZoom, kol-website 2026-08-28 — user, on a 212-tile
|
|
47
53
|
* grid: no frame at rest; the old rest value is the hover): a wall of fg-04 frames is a grid of boxes,
|
|
48
54
|
* louder than what they hold. Rest `transparent` (the 1px stays, so the hover step never relayouts),
|
|
@@ -88,6 +94,7 @@ const BOX = {
|
|
|
88
94
|
* has no surface of its own to step, so it dims its title instead. */
|
|
89
95
|
const HOVER = {
|
|
90
96
|
file: 'var(--kol-oq-04)',
|
|
97
|
+
slide: 'var(--kol-surface-primary)', /* the plate holds its colour on hover; the drawer control is the affordance */
|
|
91
98
|
catalog: 'var(--kol-surface-tertiary)',
|
|
92
99
|
/* article and work take NO surface hover, and that is a decision not a gap:
|
|
93
100
|
* article has no surface of its own (its media frame, when on, steps its
|
|
@@ -132,7 +139,10 @@ const MEDIA = {
|
|
|
132
139
|
*
|
|
133
140
|
* `layout` is the discriminator inside `showcase` because `reveal` was already
|
|
134
141
|
* taken by the consumer's overlay NODE. Its values are the box vocabulary the
|
|
135
|
-
* component already spoke: drawer (default) · canvas.
|
|
142
|
+
* component already spoke: drawer (default) · canvas.
|
|
143
|
+
*
|
|
144
|
+
* A FIFTH KIND, `slide` (2026-09-03, user-ruled: a deck is genuinely a different
|
|
145
|
+
* thing from a file — a 16:9 stage carrying a date, a size and a slide count). */
|
|
136
146
|
const ALIAS = { default: 'file', print: 'catalog', work: 'showcase', typeface: 'showcaseCanvas' }
|
|
137
147
|
const LAYOUT_KEY = { canvas: 'showcaseCanvas', drawer: 'showcase' }
|
|
138
148
|
|
|
@@ -47,6 +47,12 @@ const BOX = {
|
|
|
47
47
|
* full-width grey band under it is heavier than the line itself. Scoped to
|
|
48
48
|
* `default`: catalog and print still carry the same `oq-04`, unruled. */
|
|
49
49
|
file: { thumb: 48, ratio: '1 / 1', pad: `${S2} 0`, gap: S3, align: 'items-center', divider: true },
|
|
50
|
+
/* SLIDE (slide-variant-and-shelf-preset, 2026-09-03): file's row with the thumb FILLING the
|
|
51
|
+
* rung's height and taking its width from 16:9 — 48 tall, 85 wide, the whole frame — not
|
|
52
|
+
* the 48 square, which cropped a deck to a sliver (read off olina's /slide-deck). `minH` 64
|
|
53
|
+
* = the 48 thumb plus the row's 8px pads; a fill thumb reads its height off the row's
|
|
54
|
+
* rung, and without one it fell to the 96 fallback (80 × 142, measured on the showcase). */
|
|
55
|
+
slide: { thumb: 'fill', ratio: '16 / 9', pad: `${S2} 0`, gap: S3, align: 'items-center', divider: true, minH: 64 },
|
|
50
56
|
/* catalog/print rows render AT 36px — the shipped GridCard list row is a
|
|
51
57
|
* fixed 36 and the Y padding was what pushed it past that. X padding stays;
|
|
52
58
|
* `minH` is now the whole height budget and the row centres inside it. */
|
|
@@ -57,6 +57,13 @@ const RAMP = {
|
|
|
57
57
|
card: { title: 'kol-sans-heading-04 text-emphasis truncate', date: 'kol-mono-12 text-meta', size: 'kol-mono-12 text-meta' },
|
|
58
58
|
row: { title: 'kol-sans-heading-05 text-emphasis truncate', date: 'kol-mono-12 text-meta', size: 'kol-mono-12 text-meta' },
|
|
59
59
|
},
|
|
60
|
+
/* SLIDE — a deck (slide-variant-and-shelf-preset, kol-client-olina 2026-09-03;
|
|
61
|
+
* user: "they are genuinely different with 16:9 layout and those exposed
|
|
62
|
+
* properties"). file's voices plus a `meta` line — the slide count. */
|
|
63
|
+
slide: {
|
|
64
|
+
card: { title: 'kol-sans-heading-04 text-emphasis truncate', date: 'kol-mono-12 text-meta', size: 'kol-mono-12 text-meta', meta: 'kol-mono-12 text-meta' },
|
|
65
|
+
row: { title: 'kol-sans-heading-05 text-emphasis truncate', date: 'kol-mono-12 text-meta', size: 'kol-mono-12 text-meta', meta: 'kol-mono-12 text-meta' },
|
|
66
|
+
},
|
|
60
67
|
catalog: {
|
|
61
68
|
/* detail truncates (ShellHomeSystem, 2026-08-27): a wrapping blurb set three
|
|
62
69
|
* cards' plates at three heights and misaligned the media */
|
|
@@ -138,6 +145,8 @@ const RAMP = {
|
|
|
138
145
|
* read off the shipped components and the live pages they render on. */
|
|
139
146
|
const ORDER = {
|
|
140
147
|
file: { card: ['title', ['group', 'date', 'size']], row: ['title', ['group', 'date', 'size']] },
|
|
148
|
+
/* slide: title, then date · size · slide count on one baseline (read off olina's /slide-deck) */
|
|
149
|
+
slide: { card: ['title', ['group', 'date', 'size', 'meta']], row: ['title', ['group', 'date', 'size', 'meta']] },
|
|
141
150
|
catalog: { card: ['title', 'detail'], row: [['between', 'title', 'detail']] },
|
|
142
151
|
/* title + body are ONE block in BOTH forms — a `stack`, so they sit on the
|
|
143
152
|
* tight 4px internal gap while tags, kicker and the meta group keep the
|
|
@@ -190,6 +199,7 @@ const STACK = {
|
|
|
190
199
|
|
|
191
200
|
const GAPS = {
|
|
192
201
|
file: { card: 'var(--kol-spacing-3)', row: 'var(--kol-spacing-2)' },
|
|
202
|
+
slide: { card: 'var(--kol-spacing-3)', row: 'var(--kol-spacing-2)' },
|
|
193
203
|
catalog: { card: 'var(--kol-spacing-1)', row: 'var(--kol-spacing-2)' },
|
|
194
204
|
article: { card: 'var(--kol-spacing-3)', row: 'var(--kol-spacing-3)', hero: 'var(--kol-spacing-3)' },
|
|
195
205
|
showcase: { card: 'var(--kol-spacing-2)', row: 'var(--kol-spacing-4)' },
|
|
@@ -265,7 +265,8 @@ const ContentFilters = ({
|
|
|
265
265
|
/* THE LAW (user ruling 2026-08-27, said "for the 10th time" — ContentFiltersFirstGroupHugs,
|
|
266
266
|
* its WIDTH overruled the same day — ContentFiltersFirstGroupFixedWidth, kol-monitor: "nope
|
|
267
267
|
* not hug, fix a size … if columns, maybe just use one?"): THE FIRST FILTER GROUP IS ONE
|
|
268
|
-
* CATALOG COLUMN WIDE — `.kol-filters-first` (kol-theme):
|
|
268
|
+
* CATALOG COLUMN WIDE — `.kol-filters-first` (kol-theme): one track of the catalog grid AT THE
|
|
269
|
+
* COUNT IT RENDERS (theme ≥0.137.0 — was `(100cqw − 120px) / 6`, true only at six tracks), the `1fr`
|
|
269
270
|
* of the catalog's `repeat(6, 1fr)` gap 24, measured on the header row as a container so
|
|
270
271
|
* the count/strip beside the groups never narrows it. It sits over the first card; EVERY
|
|
271
272
|
* GROUP AFTER IT FLOWS across the rest of the row, starting over the second. By POSITION,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useEffect, useMemo, useRef, useState } from 'react'
|
|
2
|
+
import formatSize from '../utilities/formatSize.js'
|
|
2
3
|
import { Icon } from '@kolkrabbi/kol-icons'
|
|
3
4
|
import Button from '../atoms/Button.jsx'
|
|
4
5
|
import Divider from '../atoms/Divider.jsx'
|
|
@@ -87,14 +88,7 @@ const SORT_OPTIONS = [
|
|
|
87
88
|
{ value: 'kind', label: 'Kind' },
|
|
88
89
|
]
|
|
89
90
|
|
|
90
|
-
/* bytes → weight
|
|
91
|
-
function formatSize(bytes) {
|
|
92
|
-
if (bytes == null) return ''
|
|
93
|
-
if (bytes < 1024) return `${bytes} B`
|
|
94
|
-
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`
|
|
95
|
-
if (bytes < 1024 * 1024 * 1024) return `${(bytes / 1024 / 1024).toFixed(1)} MB`
|
|
96
|
-
return `${(bytes / 1024 / 1024 / 1024).toFixed(2)} GB`
|
|
97
|
-
}
|
|
91
|
+
/* bytes → weight: `utilities/formatSize` since 0.178.0 — one copy, exported */
|
|
98
92
|
const formatDate = (iso) => (iso ? new Date(iso).toISOString().slice(0, 10) : '')
|
|
99
93
|
const isImage = (ct) => !!ct && ct.startsWith('image/')
|
|
100
94
|
const isVideo = (ct) => !!ct && ct.startsWith('video/')
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* formatSize — bytes → the weight a file reads as in the media admin
|
|
3
|
+
* (`1.2 MB`). Lived inside MediaLibraryPages; exported since 0.178.0
|
|
4
|
+
* (slide-variant-and-shelf-preset, 2026-09-03) because kol-shell's shelf preset
|
|
5
|
+
* and olina's deck page were restating it byte for byte. Duplicated from the
|
|
6
|
+
* media client on purpose (§3: the UI never imports the client).
|
|
7
|
+
*/
|
|
8
|
+
export default function formatSize(bytes) {
|
|
9
|
+
if (bytes == null) return ''
|
|
10
|
+
if (bytes < 1024) return `${bytes} B`
|
|
11
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`
|
|
12
|
+
if (bytes < 1024 * 1024 * 1024) return `${(bytes / 1024 / 1024).toFixed(1)} MB`
|
|
13
|
+
return `${(bytes / 1024 / 1024 / 1024).toFixed(2)} GB`
|
|
14
|
+
}
|
package/src/utilities/tone.js
CHANGED
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
* toneClass — the control set's TONE, six values (tone-is-the-ground-axis,
|
|
3
3
|
* kol-client-olina 2026-09-03; the six-tone list is the user's).
|
|
4
4
|
*
|
|
5
|
-
* primary · secondary · outline · ghost · grey · sunken
|
|
5
|
+
* primary · secondary · inverted · outline · ghost · grey · sunken
|
|
6
|
+
*
|
|
7
|
+
* `secondary` paints the PAGE SURFACE and `inverted` the text colour as fill
|
|
8
|
+
* (tone-secondary-is-inverse, 2026-09-03; user: "that tone should be called
|
|
9
|
+
* secondary. What is currently secondary should be called inverted") — 0.134.0
|
|
10
|
+
* had lifted `secondary` from Button's variant, which was already an inverse.
|
|
6
11
|
*
|
|
7
12
|
* A tone is a ground-and-ink bundle — `--kol-tone-*` custom properties in
|
|
8
13
|
* kol-theme (kol-components-molecules.css, TONE) that every control paints
|
|
@@ -13,9 +18,10 @@
|
|
|
13
18
|
*
|
|
14
19
|
* `inverse` is `sunken`'s alias (0.117.0's name — ControlToneSunken,
|
|
15
20
|
* kol-website 2026-08-28; user ruling: the control does not invert anything,
|
|
16
|
-
* it sits BELOW the plane it is on)
|
|
21
|
+
* it sits BELOW the plane it is on) — NOT `inverted`; one kol-website call
|
|
22
|
+
* still passes it, and it drops when that moves.
|
|
17
23
|
*/
|
|
18
|
-
export const TONES = ['primary', 'secondary', 'outline', 'ghost', 'grey', 'sunken']
|
|
24
|
+
export const TONES = ['primary', 'secondary', 'inverted', 'outline', 'ghost', 'grey', 'sunken']
|
|
19
25
|
|
|
20
26
|
export const toneClass = (tone) =>
|
|
21
27
|
tone === 'inverse' ? 'kol-tone-sunken' : TONES.includes(tone) ? `kol-tone-${tone}` : ''
|