@kolkrabbi/kol-component 0.204.0 → 0.205.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/molecules/AlignmentGrid.jsx +50 -34
- package/src/utilities/Popover.jsx +10 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kolkrabbi/kol-component",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.205.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",
|
|
@@ -1,27 +1,28 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Icon } from '@kolkrabbi/kol-icons'
|
|
2
|
+
import SegmentedToggle from '../atoms/SegmentedToggle.jsx'
|
|
3
|
+
import { glyphSize } from '../hooks/glyphLadders.js'
|
|
2
4
|
|
|
3
5
|
/**
|
|
4
|
-
* AlignmentGrid —
|
|
5
|
-
* vertical start/center/end, each a quiet icon Button that emits an
|
|
6
|
-
* `(axis, mode)` alignment intent. Driven off a static config array (the
|
|
7
|
-
* default 6, overridable via `items`). Presentation only — the consumer wires
|
|
8
|
-
* `onAlign` to whatever "align these" means in its context (align a box to the
|
|
9
|
-
* canvas bounds, align a multi-selection's common bbox, …).
|
|
6
|
+
* AlignmentGrid — the align control: TWO three-way strips, X and Y.
|
|
10
7
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
8
|
+
* Rebuilt on `SegmentedToggle` 2026-09-03 (`editor-chrome-review`, the user's
|
|
9
|
+
* own pass over the running editor: *"alignment isnt using segmentedtoggle?"*).
|
|
10
|
+
* It was six bare quiet icon Buttons in one `grid-cols-6` — six loose controls
|
|
11
|
+
* where the thing itself is two three-way choices, which is what a segmented
|
|
12
|
+
* strip is for. The shape had been ruled on `editor-set-is-behind-its-source`
|
|
13
|
+
* and the PRESS TREATMENT was the open question; his reaction answered it.
|
|
16
14
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
15
|
+
* MOMENTARY, NOT A SELECTION. `value={null}` puts the strip in its stateless
|
|
16
|
+
* mode: no cell is ever lit, because "align left" is an action you fire, not a
|
|
17
|
+
* state the object is in — the object's alignment is not a property this reads
|
|
18
|
+
* back. The press is the cell's own `:active`, drawn in the theme
|
|
19
|
+
* (`.kol-seg-cell:active`), which is why no `tone` or `pressed` prop was minted
|
|
20
|
+
* for it: `tone` is the GROUND axis and says nothing about a momentary press.
|
|
22
21
|
*
|
|
23
|
-
* @param {(axis:'h'|'v', mode:'start'|'center'|'end') => void} onAlign
|
|
24
|
-
* @param {Array} items
|
|
22
|
+
* @param {(axis:'h'|'v', mode:'start'|'center'|'end') => void} onAlign - Fired on press
|
|
23
|
+
* @param {Array} items - `[{ axis, mode, icon, title }]` cells (default the standard 6, three per axis)
|
|
24
|
+
* @param {'xs'|'sm'|'md'|'lg'} size - The strips' rung (default 'sm')
|
|
25
|
+
* @param {string} className - Extra classes on the wrapper
|
|
25
26
|
*/
|
|
26
27
|
const ALIGN_BUTTONS = [
|
|
27
28
|
{ axis: 'h', mode: 'start', icon: 'align-horizontal-left', title: 'Align left' },
|
|
@@ -32,22 +33,37 @@ const ALIGN_BUTTONS = [
|
|
|
32
33
|
{ axis: 'v', mode: 'end', icon: 'align-vertical-bottom', title: 'Align bottom' },
|
|
33
34
|
]
|
|
34
35
|
|
|
35
|
-
export default function AlignmentGrid({ onAlign, items = ALIGN_BUTTONS }) {
|
|
36
|
+
export default function AlignmentGrid({ onAlign, items = ALIGN_BUTTONS, size = 'sm', className = '' }) {
|
|
37
|
+
const strip = (axis) => items.filter((b) => b.axis === axis)
|
|
38
|
+
|
|
36
39
|
return (
|
|
37
|
-
<div className=
|
|
38
|
-
{
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
40
|
+
<div className={`kol-alignment-grid flex flex-col gap-1 ${className}`.trim()}>
|
|
41
|
+
{['h', 'v'].map((axis) => {
|
|
42
|
+
const cells = strip(axis)
|
|
43
|
+
if (!cells.length) return null
|
|
44
|
+
return (
|
|
45
|
+
<SegmentedToggle
|
|
46
|
+
key={axis}
|
|
47
|
+
variant="filled"
|
|
48
|
+
size={size}
|
|
49
|
+
/* stateless: never lit, the press IS the feedback */
|
|
50
|
+
value={null}
|
|
51
|
+
ariaLabel={axis === 'h' ? 'Align horizontally' : 'Align vertically'}
|
|
52
|
+
/* the cell's `label` takes a NODE, so the glyph needs no new prop
|
|
53
|
+
* on SegmentedToggle — and the glyph size comes from the ADJACENT
|
|
54
|
+
* ladder, never a number typed here */
|
|
55
|
+
options={cells.map((b) => ({
|
|
56
|
+
value: `${b.axis}-${b.mode}`,
|
|
57
|
+
label: <Icon name={b.icon} size={glyphSize(size)} />,
|
|
58
|
+
ariaLabel: b.title,
|
|
59
|
+
}))}
|
|
60
|
+
onChange={(v) => {
|
|
61
|
+
const cell = cells.find((b) => `${b.axis}-${b.mode}` === v)
|
|
62
|
+
if (cell) onAlign?.(cell.axis, cell.mode)
|
|
63
|
+
}}
|
|
64
|
+
/>
|
|
65
|
+
)
|
|
66
|
+
})}
|
|
51
67
|
</div>
|
|
52
68
|
)
|
|
53
69
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useState } from 'react'
|
|
2
|
+
import { toneClass } from './tone.js'
|
|
2
3
|
import {
|
|
3
4
|
useFloating,
|
|
4
5
|
autoUpdate,
|
|
@@ -189,6 +190,14 @@ export function PopoverPanel({
|
|
|
189
190
|
panel = true,
|
|
190
191
|
modal = false,
|
|
191
192
|
focus = true,
|
|
193
|
+
/* THE FLOATING SURFACE'S GROUND (editor-chrome-review, kol-fxr 2026-09-03 —
|
|
194
|
+
* the user on the Editor / Labs / Randomiser list: *"can we change it border
|
|
195
|
+
* oq-04 and background as tone prop?"*). The panel painted
|
|
196
|
+
* `surface-secondary` unconditionally, which in dark is LIGHTER than the bar
|
|
197
|
+
* it drops from, so the layering read inverted. Unset it still does exactly
|
|
198
|
+
* that, so nothing existing moves; a tone paints that tone's ground instead,
|
|
199
|
+
* through the same `toneClass` every other control uses. */
|
|
200
|
+
tone,
|
|
192
201
|
className = '',
|
|
193
202
|
style: extraStyle,
|
|
194
203
|
}) {
|
|
@@ -199,7 +208,7 @@ export function PopoverPanel({
|
|
|
199
208
|
* carries the stacking guarantee — floats must top overlay chrome
|
|
200
209
|
* (.kol-overlay z-100), or a dropdown inside a FullscreenOverlay renders
|
|
201
210
|
* under the sheet and its options can't be clicked. */
|
|
202
|
-
const cls = ['kol-popover-float', panel && 'kol-popover', className].filter(Boolean).join(' ')
|
|
211
|
+
const cls = ['kol-popover-float', panel && 'kol-popover', tone && toneClass(tone), className].filter(Boolean).join(' ')
|
|
203
212
|
|
|
204
213
|
/* `data-editor-keep-selection` mirrors the marker on the EditorShell
|
|
205
214
|
* root. Popovers render via FloatingPortal (mounted on <body>, outside
|