@rogieking/figui3 11.1.5 → 11.2.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.
@@ -2,9 +2,11 @@
2
2
  name: fig-editor
3
3
  description: >-
4
4
  Guides FigUI3 editor bundle (`fig-editor.js` / `fig-editor.css`): fig-select,
5
- fig-select-options, fig-select-option, fig-fill-picker, and fig-interpolation-swatch,
5
+ fig-select-options, fig-select-option, fig-fill-picker, fig-palette-editor,
6
+ fig-reorder, and fig-interpolation-swatch,
6
7
  including React JSX usage. Use when building custom selects, grouped option lists,
7
- sticky separators, ghost selects, fill picker dialogs, or interpolation swatches.
8
+ sticky separators, ghost selects, fill picker dialogs, reorderable lists, or
9
+ interpolation swatches.
8
10
  Requires fig.js.
9
11
  user-invocable: false
10
12
  ---
@@ -25,7 +27,7 @@ import "@rogieking/figui3/fig-editor.css";
25
27
  import "@rogieking/figui3/fig-editor.js";
26
28
  ```
27
29
 
28
- `fig-editor.js` imports `fig.js` and `fig-lab.js`. Still import `fig-editor.css`. Import `fig-lab.css` if lab visuals are needed.
30
+ `fig-editor.js` imports `fig.js`. Still import `fig-editor.css`.
29
31
 
30
32
  Registered tags:
31
33
 
@@ -35,6 +37,8 @@ Registered tags:
35
37
  | `fig-select-options` | Scrollable panel (`slot="panel"`), overflow chevrons |
36
38
  | `fig-select-option` | Option (`value`, `label`, `selected`, `disabled`, `subtle`) |
37
39
  | `fig-fill-picker` | Full fill editor dialog (solid, gradient, image, video, webcam, custom modes) |
40
+ | `fig-palette-editor` | Ordered palette editor |
41
+ | `fig-reorder` | Pointer- and keyboard-reorderable direct-child list |
38
42
  | `fig-interpolation-swatch` | Gradient interpolation preview swatch |
39
43
 
40
44
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  React contract: [../figui3/react.md](../figui3/react.md). Attrs: [reference.md](reference.md).
4
4
 
5
- Install `fig-editor.css` + `fig-editor.js` (pulls in `fig.js` and `fig-lab.js`). Still import `fig-editor.css`. Import `fig-lab.css` if lab visuals are needed.
5
+ Install `fig-editor.css` + `fig-editor.js` (pulls in `fig.js`). Still import `fig-editor.css`.
6
6
 
7
7
  ## `fig-select`
8
8
 
@@ -66,6 +66,57 @@ Data-driven (no authored options):
66
66
  - Attrs: `value` (falls back to trimmed `textContent`), `label` (closed-trigger text when content is rich), `selected`, `disabled`, `subtle` (secondary hover/focus fill)
67
67
  - `role="option"`, `aria-selected`, `aria-disabled`
68
68
 
69
+ ## `fig-palette-editor`
70
+
71
+ Reusable ordered palette editor used by `fig-input-palette edit="picker"`.
72
+
73
+ ```tsx
74
+ <fig-palette-editor
75
+ value='["#94BD00","#83AD00","#1A632A","#003905"]'
76
+ onInput={onInput}
77
+ onChange={onChange}
78
+ />
79
+ ```
80
+
81
+ - Attrs: `value`, `min`, `max`, `fixed`, `disabled`
82
+ - `max` is unbounded when omitted.
83
+ - Events: `input` / `change` with the normalized ordered color array in `detail`
84
+ - Uses `fig-reorder` for pointer and keyboard reordering.
85
+
86
+ ## `fig-reorder`
87
+
88
+ ```tsx
89
+ <fig-reorder axis="vertical" handle=".drag">
90
+ {items.map((item) => (
91
+ <div key={item.id} className="row">
92
+ <button className="drag" type="button" aria-label="Reorder" />
93
+ {item.label}
94
+ </div>
95
+ ))}
96
+ </fig-reorder>
97
+ ```
98
+
99
+ Listen for `reorder` on a ref (`onReorder` is not a React-mapped event):
100
+
101
+ ```tsx
102
+ useEffect(() => {
103
+ const el = ref.current;
104
+ if (!el) return;
105
+ const handler = (event: Event) => {
106
+ const { oldIndex, newIndex, item } = (event as CustomEvent).detail;
107
+ onReorder({ oldIndex, newIndex, item });
108
+ };
109
+ el.addEventListener("reorder", handler);
110
+ return () => el.removeEventListener("reorder", handler);
111
+ }, [onReorder]);
112
+ ```
113
+
114
+ - `display: contents`. Reorders direct children.
115
+ - Attrs: `axis` (`vertical` | `horizontal`), `handle`, `items`, `indicator` (`default` | `ring`), `disabled`.
116
+ - `items` limits which direct children reorder; `refresh()` forces a re-sync.
117
+ - Event `reorder`: `{ oldIndex, newIndex, item }`.
118
+ - With fewer than two matching items, list semantics remain but drag and keyboard affordances stay inactive.
119
+
69
120
  ## `fig-fill-picker`
70
121
 
71
122
  Full fill editor. Core `fig-input-color` / `fig-input-fill` auto-open it when this tag is registered.
@@ -35,6 +35,24 @@ Position: omit to overlay the selected option on the trigger. Set to place the m
35
35
 
36
36
  Events: `input`, `change`, `optionhover`, `optionfocus`.
37
37
 
38
+ ## Reorder
39
+
40
+ `fig-reorder` observes `axis`, `handle`, `items`, `indicator`, and `disabled`.
41
+
42
+ - `items`: selector for reorderable direct children; non-matching children remain in place.
43
+ - `indicator`: `default` or `ring`.
44
+ - `refresh()`: force child/selector synchronization.
45
+ - Event `reorder`: `{ oldIndex, newIndex, item }`; indices count matching items.
46
+ - Nested drag controls are ignored unless an explicit `handle` is configured.
47
+
48
+ ## Palette editor
49
+
50
+ `fig-palette-editor` observes `value`, `min`, `max`, `fixed`, and `disabled`. An omitted `max` allows unlimited colors.
51
+
52
+ - `value`: JSON array of hex strings or `{ color, alpha }` objects, or comma-separated hex
53
+ - `value` property and `input` / `change` event `detail`: normalized ordered `{ color, alpha }[]`
54
+ - Rows are direct `fig-reorder` items and support pointer or keyboard reordering.
55
+
38
56
  ## Fill picker modes
39
57
 
40
58
  Built-in: `solid`, `gradient`, `image`, `video`, `webcam`.
@@ -2,7 +2,7 @@
2
2
  name: fig-lab
3
3
  description: >-
4
4
  Guides FigUI3 experimental Lab components: fig-canvas-control,
5
- fig-input-audio, fig-input-wheel, fig-reorder, and AI composer components,
5
+ fig-input-audio, fig-input-wheel, and AI composer components,
6
6
  including React JSX usage. APIs are unstable.
7
7
  user-invocable: false
8
8
  ---
@@ -22,4 +22,4 @@ import "@rogieking/figui3/fig-lab.css";
22
22
  import "@rogieking/figui3/fig-lab.js";
23
23
  ```
24
24
 
25
- Use Lab for audio and wheel inputs, canvas handles, reorder behavior, and AI composition surfaces. Keep Lab out of `fig.js`.
25
+ Use Lab for audio and wheel inputs, canvas handles, and AI composition surfaces. Keep Lab out of `fig.js`.
@@ -54,38 +54,6 @@ Handlers below assume `onInput` / `onChange` from the React contract.
54
54
 
55
55
  - Methods: `focus()`, `spinTo(value)`, `beginScrub()`, `updateScrub()`, `endScrub()`.
56
56
 
57
- ### `fig-reorder`
58
-
59
- ```tsx
60
- <fig-reorder axis="vertical" handle=".drag">
61
- {items.map((item) => (
62
- <div key={item.id} className="row">
63
- <button className="drag" type="button" aria-label="Reorder" />
64
- {item.label}
65
- </div>
66
- ))}
67
- </fig-reorder>
68
- ```
69
-
70
- Listen for `reorder` on a ref (`onReorder` is not a React-mapped event):
71
-
72
- ```tsx
73
- useEffect(() => {
74
- const el = ref.current;
75
- if (!el) return;
76
- const handler = (event: Event) => {
77
- const { oldIndex, newIndex, item } = (event as CustomEvent).detail;
78
- onReorder({ oldIndex, newIndex, item });
79
- };
80
- el.addEventListener("reorder", handler);
81
- return () => el.removeEventListener("reorder", handler);
82
- }, [onReorder]);
83
- ```
84
-
85
- - `display: contents`. Reorders **direct children**. `axis` `vertical` | `horizontal`. `items` selector limits which children reorder (e.g. `items=".row"` to skip headers); `indicator="default|ring"` controls the drop indicator style; `refresh()` re-syncs. Omit `handle` to drag whole rows; set it when rows contain sliders/handles.
86
- - With fewer than two matching items, children keep `role="listitem"` but drag cursors, handles, focus, and move labels stay inactive until another item is added.
87
- - Event `reorder`: `{ oldIndex, newIndex, item }` (indices among matching items). Nested drag is ignored for sliders, handles, and canvas controls.
88
-
89
57
  ## AI composer
90
58
 
91
59
  Layout shells. Wire behavior yourself. Children are React nodes.
@@ -53,20 +53,6 @@ Parent must be `position: relative` (or similar) so the control can fill it. Wra
53
53
 
54
54
  Types: `point`, `color`, `point-radius`, `point-radius-angle`, `point-point`.
55
55
 
56
- ## `fig-reorder`
57
-
58
- Observed: `axis`, `handle`, `items`, `indicator`, `disabled`.
59
-
60
- `items`: CSS selector for which direct children are reorderable (default: all). Non-matching children stay in place and get `role="none"` unless they have a role. Class/attribute changes on children re-sync automatically; call `refresh()` to force it.
61
-
62
- `indicator`: Drop indicator style, either `default` or `ring`.
63
-
64
- With fewer than two matching items, matching children retain `role="listitem"` but remain non-draggable and receive no generated focus or move label.
65
-
66
- Event `reorder`: `{ oldIndex, newIndex, item }`. Indices count matching items, not DOM positions.
67
-
68
- Nested drag is ignored for sliders, handles, and canvas controls so inner gestures still work. If a row is still stolen, set `handle` to a drag-affordance selector.
69
-
70
56
  ## AI shells
71
57
 
72
58
  `fig-ai-prompt`, `fig-ai-context`, `fig-chat-message` are empty custom elements (presentation CSS only).
@@ -27,10 +27,10 @@ import "@rogieking/figui3/fig.js";
27
27
  | Bundle | CSS + JS | Components |
28
28
  |---|---|---|
29
29
  | **Core** (this skill) | `fig.css` + `fig.js` | All `fig-*` in [components.md](components.md) |
30
- | **Editor** | `fig-editor.css` + `fig-editor.js` | `fig-select*`, `fig-fill-picker`, `fig-interpolation-swatch` |
30
+ | **Editor** | `fig-editor.css` + `fig-editor.js` | `fig-select*`, `fig-fill-picker`, `fig-palette-editor`, `fig-reorder`, `fig-interpolation-swatch` |
31
31
  | **Layer** | `fig-layer.css` + `fig-layer.js` | `fig-layer` |
32
32
 
33
- `fig-editor.js` also imports `fig.js` and `fig-lab.js`. Lab CSS is still separate. `fig-layer` is **not** registered by `fig-editor.js`. Toast is core; layer is `fig-layer.js`.
33
+ `fig-editor.js` also imports `fig.js`. Lab remains a separate JS/CSS bundle. `fig-layer` is **not** registered by `fig-editor.js`. Toast is core; layer is `fig-layer.js`.
34
34
 
35
35
  ## Principles
36
36
 
@@ -263,7 +263,23 @@ Handlers below assume `onInput` / `onChange` / `onClick` from [react.md](react.m
263
263
  />
264
264
  ```
265
265
 
266
- - Attrs: `value`, `fixed`, `open`, `disabled`
266
+ - Attrs: `value`, `edit` (`true` | `false` | `picker`), `fixed`, `open`, `disabled`, `min`, `max`
267
+ - `edit="true"` keeps the inline expandable editor, `edit="false"` renders a compact preview, and `edit="picker"` opens `fig-palette-editor` from the editor bundle.
268
+
269
+ ### `fig-palette-editor`
270
+
271
+ ```tsx
272
+ <fig-palette-editor
273
+ value='["#0D99FF","#14AE5C"]'
274
+ onInput={onInput}
275
+ onChange={onChange}
276
+ />
277
+ ```
278
+
279
+ - Editor-bundle component for reusable palette editing with drag and keyboard reordering.
280
+ - Attrs: `value`, `fixed`, `disabled`, `min`, `max`
281
+ - `max` is unbounded when omitted.
282
+ - Events: `input` / `change` with the normalized ordered color array in `detail`
267
283
 
268
284
  ### `fig-input-gradient`
269
285
 
@@ -80,6 +80,7 @@ type FigTag =
80
80
  | "fig-input-gradient"
81
81
  | "fig-input-number"
82
82
  | "fig-input-palette"
83
+ | "fig-palette-editor"
83
84
  | "fig-input-text"
84
85
  | "fig-input-wheel"
85
86
  | "fig-interpolation-swatch"
package/CHANGELOG.md CHANGED
@@ -2,6 +2,31 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [11.2.0]
6
+
7
+ ### Added
8
+
9
+ - Added the reusable `fig-palette-editor` with color editing, add/remove controls, and pointer or keyboard reordering.
10
+ - Added palette editor and reorder examples, controls, typings, tests, and documentation.
11
+
12
+ ### Changed
13
+
14
+ - Added inline, preview, and popup picker modes to `fig-input-palette`.
15
+ - Moved `fig-reorder` from the Lab bundle to the Editor bundle and expanded its item, handle, indicator, and accessibility behavior.
16
+ - Updated labelless `fig-field` layouts to support flexible groups of controls.
17
+ - Refined palette and gradient editor structure and spacing with standard fields, headers, and stacks.
18
+
19
+ ### Fixed
20
+
21
+ - Kept reorder indicators visible inside popovers, modal dialogs, and fullscreen elements.
22
+ - Allowed color tips to inherit the active light or dark theme.
23
+
24
+ ## [11.1.6]
25
+
26
+ ### Fixed
27
+
28
+ - Corrected labeled separator alignment and padding in `fig-select`.
29
+
5
30
  ## [11.1.5]
6
31
 
7
32
  ### Fixed
package/README.md CHANGED
@@ -112,6 +112,8 @@ Minimal example:
112
112
  | [Color Tip](#color-tip) | `<fig-color-tip>` | Compact color tip with picker |
113
113
  | [Color Input](#color-input) | `<fig-input-color>` | Color picker with hex/alpha |
114
114
  | [Input Palette](#input-palette) | `<fig-input-palette>` | Editable multi-color palette |
115
+ | [Palette Editor](#palette-editor) | `<fig-palette-editor>` | Reusable reorderable palette editor |
116
+ | [Reorder](#reorder) | `<fig-reorder>` | Pointer- and keyboard-reorderable list |
115
117
  | [Gradient Input](#gradient-input) | `<fig-input-gradient>` | Gradient editor with stops |
116
118
  | [Fill Input](#fill-input) | `<fig-input-fill>` | Solid, gradient, image, video fill |
117
119
  | [Fill Picker](#fill-picker) | `<fig-fill-picker>` | Full fill picker dialog |
@@ -622,6 +624,7 @@ An editable palette of solid colors, each rendered as a `<fig-input-color>` swat
622
624
  | `max` | number | `8` | Maximum (add button hidden at max) |
623
625
  | `open` | boolean | `false` | Expanded rows with text inputs per color |
624
626
  | `fixed` | boolean | `false` | Lock palette length — no add or remove (`fixed` or `fixed="true"`) |
627
+ | `edit` | `"true"` \| `"false"` \| `"picker"` | `"true"` | Inline editor, compact preview, or popup palette editor |
625
628
 
626
629
  **Events:**
627
630
 
@@ -632,10 +635,36 @@ An editable palette of solid colors, each rendered as a `<fig-input-color>` swat
632
635
 
633
636
  ```html
634
637
  <fig-input-palette value='["#FF0000","#00FF00","#0000FF"]'></fig-input-palette>
635
- <fig-input-palette value='[{"color":"#FF0000","alpha":0.5},{"color":"#00FF00","alpha":1}]' open></fig-input-palette>
638
+ <fig-input-palette edit="false" value='["#FF0000","#00FF00","#0000FF"]'></fig-input-palette>
639
+ <fig-input-palette edit="picker" value='[{"color":"#FF0000","alpha":0.5},{"color":"#00FF00","alpha":1}]'></fig-input-palette>
636
640
  ```
637
641
 
638
- The collapsed palette is a single tab stop. Enter or Space expands it, and focus styling uses the shared focus outline tokens on the visible swatch row.
642
+ The editable palette is a single tab stop. Enter or Space expands inline mode or opens picker mode. `edit="false"` renders only the compact preview. Picker mode requires `fig-editor.js`.
643
+
644
+ #### Palette Editor
645
+
646
+ `<fig-palette-editor>`
647
+
648
+ A reusable editor-bundle component for ordered color arrays. It uses `<fig-reorder>` for pointer and keyboard reordering and emits normalized color arrays from `input` and `change`. It supports `value`, `min`, `max`, `fixed`, and `disabled`; omit `max` for an unlimited number of colors.
649
+
650
+ ```html
651
+ <fig-palette-editor value='["#94BD00","#83AD00","#1A632A","#003905"]'></fig-palette-editor>
652
+ ```
653
+
654
+ #### Reorder
655
+
656
+ `<fig-reorder>`
657
+
658
+ An editor-bundle wrapper for reordering direct children with pointer or keyboard controls. Use `handle` for rows containing interactive controls, and `items` to limit which direct children participate.
659
+
660
+ ```html
661
+ <fig-reorder axis="vertical" handle=".drag-handle">
662
+ <div><button class="drag-handle" aria-label="Reorder">Move</button>First</div>
663
+ <div><button class="drag-handle" aria-label="Reorder">Move</button>Second</div>
664
+ </fig-reorder>
665
+ ```
666
+
667
+ Attributes: `axis`, `handle`, `items`, `indicator`, and `disabled`. The bubbling `reorder` event includes `{ oldIndex, newIndex, item }`.
639
668
 
640
669
  ---
641
670
 
package/components.css CHANGED
@@ -4682,7 +4682,15 @@ fig-input-palette {
4682
4682
  outline: var(--figma-focus-outline);
4683
4683
  outline-offset: var(--figma-focus-outline-offset);
4684
4684
  }
4685
- &[open]:not([open="false"]):not([edit="false"]) {
4685
+ &:is([edit="false"], [edit="picker"]) {
4686
+ grid-template-columns: minmax(0, 1fr);
4687
+ gap: 0;
4688
+
4689
+ > .palette-colors-inline {
4690
+ grid-column: 1 / -1;
4691
+ }
4692
+ }
4693
+ &[open]:not([open="false"]):not([edit="false"]):not([edit="picker"]) {
4686
4694
  grid-template-areas:
4687
4695
  "inline button"
4688
4696
  "expanded expanded";
@@ -4853,24 +4861,19 @@ fig-field {
4853
4861
  transform: rotate(0deg);
4854
4862
  }
4855
4863
 
4856
- /* labelless fields can have a few inputs */
4864
+ /* Labelless fields support any number of controls between the side padding. */
4857
4865
  &:not([direction="vertical"]):not(:has(> label)) {
4858
- grid-template-columns:
4859
- var(--fig-field-left-padding) minmax(0, var(--fig-field-label-ratio))
4860
- var(--spacer-2)
4861
- minmax(0, var(--fig-field-input-ratio)) var(--fig-field-right-padding);
4862
- grid-template-areas: "chevron input1 gap input2 pad";
4863
-
4864
- & > *:first-child {
4865
- grid-area: input1;
4866
- }
4866
+ display: flex;
4867
+ gap: var(--fig-field-gap);
4868
+ padding-inline: var(--fig-field-left-padding) var(--fig-field-right-padding);
4867
4869
 
4868
- & > *:last-child {
4869
- grid-area: input2;
4870
+ &:has(fig-button[icon]:not([icon="false"])[variant="ghost"]) {
4871
+ padding-inline: var(--fig-field-left-padding) calc(var(--fig-field-right-padding) * 0.5);
4870
4872
  }
4871
4873
 
4872
- & > *:only-child {
4873
- grid-column: input1 / -2;
4874
+ & > *:not(fig-button):not(.fig-field-chevron) {
4875
+ flex: 1 1 0;
4876
+ min-width: 0;
4874
4877
  }
4875
4878
  }
4876
4879
 
@@ -7033,7 +7036,6 @@ fig-color-tip {
7033
7036
  overflow: visible;
7034
7037
  position: relative;
7035
7038
  color: var(--figma-color-text);
7036
- color-scheme: light only;
7037
7039
  width: var(--size);
7038
7040
  height: var(--size);
7039
7041
  aspect-ratio: 1 / 1;
@@ -7294,6 +7296,7 @@ fig-select-options > :is(fig-separator, fig-menu-separator):has(> label):first-c
7294
7296
  fig-select-options > [data-fig-select-nav="start"] + :is(fig-separator, fig-menu-separator):has(> label) {
7295
7297
  --fig-separator-color: transparent;
7296
7298
  --fig-separator-margin-block: 0;
7299
+ --fig-separator-padding-inline: 0 var(--spacer-3,0.75rem);
7297
7300
  }
7298
7301
 
7299
7302
  fig-menu > [slot="trigger"] + :is(fig-separator, fig-menu-separator):has(> label) {