@explorer02/cfm-survey-sdk 0.2.1 → 0.2.3
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/dist/cli/index.js +18 -18
- package/dist/cli/index.mjs +14 -14
- package/dist/index.d.mts +465 -580
- package/dist/index.d.ts +465 -580
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +6 -4
- package/postinstall.js +96 -69
- package/templates/AGENT.md +18 -8
- package/templates/docs/00-integration/analytics-events-catalog.md +54 -0
- package/templates/docs/00-integration/answer-logic-and-navigation.md +50 -0
- package/templates/docs/00-integration/aws-deploy.md +281 -0
- package/templates/docs/00-integration/client-integration-guide.md +351 -0
- package/templates/docs/00-integration/component-checklist.md +55 -22
- package/templates/docs/00-integration/constraints.md +49 -4
- package/templates/docs/00-integration/custom-field-logic-and-navigation.md +174 -0
- package/templates/docs/00-integration/display-logic-and-navigation.md +64 -0
- package/templates/docs/00-integration/end-page-logic.md +64 -0
- package/templates/docs/00-integration/file-upload-aws.md +116 -0
- package/templates/docs/00-integration/logic-fields-catalog.md +105 -0
- package/templates/docs/00-integration/partial-save-and-recovery.md +98 -0
- package/templates/docs/00-integration/placeholders-and-tokens.md +116 -0
- package/templates/docs/00-integration/progress.md +61 -0
- package/templates/docs/00-integration/question-display-variants.md +65 -0
- package/templates/docs/00-integration/question-numbering.md +51 -0
- package/templates/docs/00-integration/question-type-sdk-matrix.md +244 -0
- package/templates/docs/00-integration/setup.md +84 -0
- package/templates/docs/00-integration/skip-logic-and-navigation.md +80 -0
- package/templates/docs/00-integration/survey-lifecycle-analytics.md +94 -0
- package/templates/docs/00-integration/useSurveySDK.md +151 -23
- package/templates/docs/01-components/01-survey-page.md +76 -54
- package/templates/docs/01-components/02-question.md +61 -58
- package/templates/docs/01-components/03-rating-scale.md +11 -1
- package/templates/docs/01-components/04-star-rating-scale.md +45 -0
- package/templates/docs/01-components/05-csat-matrix-scale.md +20 -11
- package/templates/docs/01-components/06-likert-matrix-scale.md +14 -4
- package/templates/docs/01-components/07-slider-matrix-scale.md +11 -2
- package/templates/docs/01-components/08-file-upload-scale.md +23 -51
- package/templates/docs/01-components/09-custom-slider-track.md +2 -2
- package/templates/docs/01-components/11-progress-bar.md +10 -4
- package/templates/docs/01-components/13-matrix-dropdown.md +29 -32
- package/templates/docs/01-components/14-intro-page.md +34 -0
- package/templates/docs/01-components/15-end-page.md +31 -0
- package/templates/docs/01-components/16-paused-page.md +27 -0
- package/templates/docs/01-components/17-heatmap-scale.md +75 -0
- package/templates/docs/01-components/18-rank-order-scale.md +93 -0
- package/templates/docs/01-components/README.md +42 -36
- package/templates/docs/02-reference/config-field-index.md +141 -139
- package/templates/docs/02-reference/exports.md +149 -0
- package/templates/docs/02-reference/question-types/01-rating.md +31 -32
- package/templates/docs/02-reference/question-types/04-csat.md +51 -42
- package/templates/docs/02-reference/question-types/05-rating-scale.md +16 -11
- package/templates/docs/02-reference/question-types/06-slider.md +2 -2
- package/templates/docs/02-reference/question-types/07-matrix-cfm.md +44 -30
- package/templates/docs/02-reference/question-types/08-matrix-csat.md +4 -26
- package/templates/docs/02-reference/question-types/09-matrix-rating.md +29 -13
- package/templates/docs/02-reference/question-types/10-slider-matrix.md +15 -4
- package/templates/docs/02-reference/question-types/11-file-upload.md +43 -17
- package/templates/docs/02-reference/question-types/12-heatmap.md +59 -0
- package/templates/docs/02-reference/question-types/13-rank-order.md +101 -0
- package/templates/docs/02-reference/question-types/README.md +96 -47
- package/templates/docs/02-reference/routing-table.md +33 -18
- package/templates/docs/02-reference/value-derivation.md +63 -0
- package/templates/docs/03-ui-specs/00-question-shell.md +19 -88
- package/templates/docs/03-ui-specs/01-rating.md +18 -52
- package/templates/docs/03-ui-specs/02-radio.md +80 -37
- package/templates/docs/03-ui-specs/03-text.md +2 -2
- package/templates/docs/03-ui-specs/04-csat.md +68 -33
- package/templates/docs/03-ui-specs/05-rating-scale.md +21 -18
- package/templates/docs/03-ui-specs/06-slider.md +3 -1
- package/templates/docs/03-ui-specs/07-matrix-cfm.md +44 -25
- package/templates/docs/03-ui-specs/08-matrix-csat-rating.md +19 -43
- package/templates/docs/03-ui-specs/09-slider-matrix.md +18 -1
- package/templates/docs/03-ui-specs/10-file-upload.md +42 -21
- package/templates/docs/03-ui-specs/11-text-and-media.md +29 -29
- package/templates/docs/03-ui-specs/12-survey-chrome.md +58 -14
- package/templates/docs/03-ui-specs/13-heatmap.md +80 -0
- package/templates/docs/03-ui-specs/14-rank-order.md +128 -0
- package/templates/docs/03-ui-specs/README.md +16 -14
- package/templates/docs/03-ui-specs/shared/custom-slider-track.md +28 -35
- package/templates/docs/03-ui-specs/shared/matrix-dropdown.md +5 -0
- package/templates/docs/MANIFEST.json +476 -69
- package/templates/docs/index.md +82 -30
- package/templates/docs/templates/CustomSliderTrack.tsx +144 -0
- package/templates/docs/templates/MatrixDropdown.tsx +216 -0
- package/templates/docs/templates/Question.tsx +221 -154
- package/templates/docs/templates/RankOrderScale.tsx +353 -0
- package/templates/docs/templates/deploy-to-aws.sh +114 -0
- package/templates/docs/templates/heatmapCoords.ts +58 -0
- package/templates/docs/templates/implementation_plan.md +126 -67
- package/templates/docs/templates/survey-inventory.schema.json +77 -0
- package/templates/docs/templates/surveyUiIcons.tsx +52 -0
- package/templates/docs/templates/verify-agent-build.sh +85 -0
- package/templates/docs/01-components/04-csat-scale.md +0 -40
- package/templates/docs/02-question-types/01-rating.md +0 -44
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# Rank Order UI Spec (`RANK_ORDER`)
|
|
2
|
+
|
|
3
|
+
> **Reference:** `02-reference/question-types/13-rank-order.md`
|
|
4
|
+
> **Blueprint:** `01-components/18-rank-order-scale.md`
|
|
5
|
+
> **Portable template:** copy [`templates/RankOrderScale.tsx`](../templates/RankOrderScale.tsx)
|
|
6
|
+
|
|
7
|
+
## Config gate
|
|
8
|
+
|
|
9
|
+
| Field | Values | UI branch |
|
|
10
|
+
|-------|--------|-----------|
|
|
11
|
+
| `interactionMode` | `'dropdown'` | Rank `<select>` per row |
|
|
12
|
+
| `interactionMode` | `'dragAndDrop'` | `@dnd-kit` sortable list |
|
|
13
|
+
| `optionDisplay` | `textOnly` / `imageOnly` / `textAndImage` | Option content layout |
|
|
14
|
+
| `requireRankAll` | boolean | Validation (SDK) |
|
|
15
|
+
| `shuffleOptions` | boolean | **SDK shuffles at fetch** — render `question.options` as-is; do not re-shuffle client-side |
|
|
16
|
+
|
|
17
|
+
## Dependencies
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @dnd-kit/core @dnd-kit/sortable @dnd-kit/utilities
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Next.js: template includes `'use client'`. Optional in `Question.tsx`:
|
|
24
|
+
|
|
25
|
+
```tsx
|
|
26
|
+
const RankOrderScale = dynamic(() => import('./RankOrderScale').then(m => ({ default: m.RankOrderScale })), {
|
|
27
|
+
ssr: false,
|
|
28
|
+
loading: () => <p>Loading rank order…</p>,
|
|
29
|
+
});
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## SDK wiring
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
import {
|
|
36
|
+
getVisibleRankOrderOptionsForAnswers,
|
|
37
|
+
normalizeRankOrderAnswers,
|
|
38
|
+
assignRankWithoutDuplicates,
|
|
39
|
+
buildRankOrderFromOrderedOptionIds,
|
|
40
|
+
getOrderedOptionIdsFromRanks,
|
|
41
|
+
} from '@explorer02/cfm-survey-sdk';
|
|
42
|
+
|
|
43
|
+
// Question.tsx — filter options + normalize answer
|
|
44
|
+
const rankOrderQuestion = {
|
|
45
|
+
...question,
|
|
46
|
+
options: getVisibleRankOrderOptionsForAnswers(question, allAnswers, allQuestions, customFieldValues),
|
|
47
|
+
};
|
|
48
|
+
<RankOrderScale
|
|
49
|
+
question={rankOrderQuestion}
|
|
50
|
+
selectedValue={normalizeRankOrderAnswers(selectedValue)}
|
|
51
|
+
onSelect={onSelect}
|
|
52
|
+
/>
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Answer shape: `RankOrderAnswers` = `Record<optionId, rank>` (1-based).
|
|
56
|
+
|
|
57
|
+
## Interaction modes
|
|
58
|
+
|
|
59
|
+
### Dropdown (`interactionMode: 'dropdown'`)
|
|
60
|
+
|
|
61
|
+
| Element | Behavior |
|
|
62
|
+
|---------|----------|
|
|
63
|
+
| Rank select | `-` (unassigned) or `1..N` per option row |
|
|
64
|
+
| Duplicate ranks | `assignRankWithoutDuplicates` clears rank R from other options |
|
|
65
|
+
| Layout | Rank select left, option content right |
|
|
66
|
+
|
|
67
|
+
### Drag and drop (`interactionMode: 'dragAndDrop'`)
|
|
68
|
+
|
|
69
|
+
| Element | Behavior |
|
|
70
|
+
|---------|----------|
|
|
71
|
+
| Drag handle | Six-dot grip; `PointerSensor` + `KeyboardSensor` |
|
|
72
|
+
| Rank badge | Circular badge showing 1-based position |
|
|
73
|
+
| Reorder | List order → `buildRankOrderFromOrderedOptionIds(orderedIds)` |
|
|
74
|
+
| Up/Down | Keyboard fallback; disabled on first/last |
|
|
75
|
+
|
|
76
|
+
## Implementation Recipe — dnd-kit
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
const sensors = useSensors(
|
|
80
|
+
useSensor(PointerSensor),
|
|
81
|
+
useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates })
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const handleDragEnd = (event: DragEndEvent) => {
|
|
85
|
+
const { active, over } = event;
|
|
86
|
+
if (!over || active.id === over.id) return;
|
|
87
|
+
const oldIndex = orderedOptionIds.indexOf(String(active.id));
|
|
88
|
+
const newIndex = orderedOptionIds.indexOf(String(over.id));
|
|
89
|
+
if (oldIndex === -1 || newIndex === -1) return;
|
|
90
|
+
onSelect(buildRankOrderFromOrderedOptionIds(arrayMove(orderedOptionIds, oldIndex, newIndex)));
|
|
91
|
+
};
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Wrap list in `<DndContext collisionDetection={closestCenter}>` + `<SortableContext strategy={verticalListSortingStrategy}>`.
|
|
95
|
+
|
|
96
|
+
Copy full implementation from [`templates/RankOrderScale.tsx`](../templates/RankOrderScale.tsx).
|
|
97
|
+
|
|
98
|
+
## Option display
|
|
99
|
+
|
|
100
|
+
| `optionDisplay` | Render |
|
|
101
|
+
|-----------------|--------|
|
|
102
|
+
| `textOnly` | Label via `dangerouslySetInnerHTML` |
|
|
103
|
+
| `imageOnly` | Square thumbnail; prefer `option.imageUrl` over `previewImageUrl` |
|
|
104
|
+
| `textAndImage` | Thumbnail + label side by side |
|
|
105
|
+
|
|
106
|
+
## Validation UX
|
|
107
|
+
|
|
108
|
+
- Required + `requireRankAll`: every visible option unique rank 1..N
|
|
109
|
+
- Required + not `requireRankAll`: at least one visible option ranked
|
|
110
|
+
- Show `validationError` from question shell
|
|
111
|
+
|
|
112
|
+
## Styling
|
|
113
|
+
|
|
114
|
+
- Border `#e5e5e5`, optional `#e20074` when ranked
|
|
115
|
+
- Rank badge: `#fdf2f8` bg, `#e20074` text
|
|
116
|
+
|
|
117
|
+
## Logic
|
|
118
|
+
|
|
119
|
+
RANK_ORDER operators (ranked as/above/below) — see [`logic-fields-catalog.md`](../00-integration/logic-fields-catalog.md).
|
|
120
|
+
|
|
121
|
+
## Agent checklist
|
|
122
|
+
|
|
123
|
+
- [ ] Copied `templates/RankOrderScale.tsx` (or equivalent dnd-kit + dropdown)
|
|
124
|
+
- [ ] `@dnd-kit/*` in package.json when survey has RANK_ORDER
|
|
125
|
+
- [ ] `getVisibleRankOrderOptionsForAnswers` + `normalizeRankOrderAnswers`
|
|
126
|
+
- [ ] `option.imageUrl` before `previewImageUrl`
|
|
127
|
+
- [ ] No client-side re-shuffle when `shuffleOptions` is true
|
|
128
|
+
- [ ] No stub placeholder text
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# UI Specifications — Reference Implementation Guide
|
|
2
2
|
|
|
3
|
-
> **For npm installs:** implement from these specs + [`templates/Question.tsx`](../templates/Question.tsx).
|
|
4
|
-
> **For monorepo devs:**
|
|
3
|
+
> **For npm installs:** implement from these specs + [`templates/Question.tsx`](../templates/Question.tsx).
|
|
4
|
+
> **For monorepo devs:** Reference client at `apps/client/src/components/` aligns with SDK types — trust `03-ui-specs/`, `templates/Question.tsx`, and exported types.
|
|
5
5
|
> Read the spec for **each question type present** in the fetched survey before writing React code.
|
|
6
6
|
|
|
7
7
|
## How to Read a UI Spec
|
|
@@ -38,24 +38,26 @@ Each file in this folder follows the same structure:
|
|
|
38
38
|
| Spec file | Reference component | `question.type` |
|
|
39
39
|
|-----------|---------------------|-----------------|
|
|
40
40
|
| [00-question-shell.md](00-question-shell.md) | `Question.tsx` | All (wrapper) |
|
|
41
|
-
| [01-rating.md](01-rating.md) | `RatingScale.tsx` | `
|
|
42
|
-
| [02-radio.md](02-radio.md) | `Question.tsx` inline | `
|
|
43
|
-
| [03-text.md](03-text.md) | `Question.tsx` inline | `
|
|
44
|
-
| [04-csat.md](04-csat.md) | `
|
|
45
|
-
| [05-rating-scale.md](05-rating-scale.md) |
|
|
46
|
-
| [06-slider.md](06-slider.md) |
|
|
47
|
-
| [07-matrix-cfm.md](07-matrix-cfm.md) | `LikertMatrixScale.tsx` | `
|
|
48
|
-
| [08-matrix-csat-rating.md](08-matrix-csat-rating.md) | `CsatMatrixScale.tsx` |
|
|
41
|
+
| [01-rating.md](01-rating.md) | `RatingScale.tsx` | `NPS_SCALE` |
|
|
42
|
+
| [02-radio.md](02-radio.md) | `Question.tsx` inline | `MCQ` |
|
|
43
|
+
| [03-text.md](03-text.md) | `Question.tsx` inline | `TEXTFIELD` |
|
|
44
|
+
| [04-csat.md](04-csat.md) | `CsatMatrixScale.tsx` | `CSAT_MATRIX` |
|
|
45
|
+
| [05-rating-scale.md](05-rating-scale.md) | `RatingScale.tsx` | `star_rating` |
|
|
46
|
+
| [06-slider.md](06-slider.md) | `CustomSliderTrack.tsx` | `slider` |
|
|
47
|
+
| [07-matrix-cfm.md](07-matrix-cfm.md) | `LikertMatrixScale.tsx` | `cfm_matrix` |
|
|
48
|
+
| [08-matrix-csat-rating.md](08-matrix-csat-rating.md) | `CsatMatrixScale.tsx` | `rating_matrix` |
|
|
49
49
|
| [09-slider-matrix.md](09-slider-matrix.md) | `SliderMatrixScale.tsx` | `slider_matrix` |
|
|
50
50
|
| [10-file-upload.md](10-file-upload.md) | `FileUploadScale.tsx` | `file_upload` |
|
|
51
|
-
| [11-text-and-media.md](11-text-and-media.md) | `Question.tsx` inline | `
|
|
51
|
+
| [11-text-and-media.md](11-text-and-media.md) | `Question.tsx` inline | `TEXT_AND_MEDIA` |
|
|
52
|
+
| [13-heatmap.md](13-heatmap.md) | `HeatmapScale.tsx` | `HEATMAP` |
|
|
53
|
+
| [14-rank-order.md](14-rank-order.md) | `RankOrderScale.tsx` | `RANK_ORDER` |
|
|
52
54
|
| [12-survey-chrome.md](12-survey-chrome.md) | `SurveyPage.tsx` + chrome | Shell |
|
|
53
55
|
| [shared/custom-slider-track.md](shared/custom-slider-track.md) | `CustomSliderTrack.tsx` | Primitive |
|
|
54
56
|
| [shared/matrix-dropdown.md](shared/matrix-dropdown.md) | `MatrixDropdown.tsx` | Primitive |
|
|
55
57
|
|
|
56
58
|
## NPS Traffic-Light Colors
|
|
57
59
|
|
|
58
|
-
Use
|
|
60
|
+
Use accent colors from SDK options — never invent colors for NPS:
|
|
59
61
|
|
|
60
62
|
| Value | Hex |
|
|
61
63
|
|-------|-----|
|
|
@@ -73,8 +75,8 @@ Use `option.color` from SDK — never invent colors:
|
|
|
73
75
|
|
|
74
76
|
## When to Read
|
|
75
77
|
|
|
76
|
-
After Phase 3 in [`index.md`](../index.md), for each question in
|
|
78
|
+
After Phase 3 in [`index.md`](../index.md), for each question in the fetched survey:
|
|
77
79
|
|
|
78
80
|
1. Read [`02-reference/question-types/`](../02-reference/question-types/) for data shape
|
|
79
|
-
2. Read matching spec from this folder (see [`MANIFEST.json`](../MANIFEST.json) `
|
|
81
|
+
2. Read matching spec from this folder (see [`MANIFEST.json`](../MANIFEST.json) `questionTypes.{type}.uiSpec`)
|
|
80
82
|
3. Cross-check [`config-field-index.md`](../02-reference/config-field-index.md)
|
|
@@ -1,52 +1,45 @@
|
|
|
1
1
|
# UI Spec: Custom Slider Track (shared primitive)
|
|
2
2
|
|
|
3
|
-
> **
|
|
4
|
-
> **Used by:** `SliderMatrixScale
|
|
3
|
+
> **Portable template:** copy [`templates/CustomSliderTrack.tsx`](../templates/CustomSliderTrack.tsx) + [`templates/surveyUiIcons.tsx`](../templates/surveyUiIcons.tsx)
|
|
4
|
+
> **Used by:** `SliderMatrixScale`, `CsatMatrixScale` (graphics), matrix `displayStyle: graphics`
|
|
5
|
+
|
|
6
|
+
## Scale column labels (Day 19 — CRITICAL)
|
|
7
|
+
|
|
8
|
+
Matrix rows must pass **`tickLabels` from `scaleColumns[].label`** (filtered to visible columns):
|
|
9
|
+
|
|
10
|
+
```typescript
|
|
11
|
+
const tickLabels = visibleScaleColumns.map(col => col.label);
|
|
12
|
+
<CustomSliderTrack tickLabels={tickLabels} ticks={tickLabels.length} ... />
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Tooltip shows stripped HTML from `tickLabels[tickIndex]`; without labels, tooltips fall back to numeric value only.
|
|
5
16
|
|
|
6
17
|
## Layer Architecture
|
|
7
18
|
|
|
8
19
|
```
|
|
9
|
-
1. Gray inactive track (#e5e7eb, 4px
|
|
10
|
-
2. Magenta fill bar (
|
|
11
|
-
3. Tick marks
|
|
12
|
-
4. Invisible <input type="range"> overlay
|
|
13
|
-
5.
|
|
14
|
-
6. Tooltip
|
|
20
|
+
1. Gray inactive track (#e5e7eb, 4px)
|
|
21
|
+
2. Magenta fill bar (percentage%, #e20074 or #9ca3af if disabled)
|
|
22
|
+
3. Tick marks at column positions
|
|
23
|
+
4. Invisible <input type="range"> overlay
|
|
24
|
+
5. Thumb: circle OR emoji (sliderType === 'graphics')
|
|
25
|
+
6. Tooltip on hover/drag (#1f2937)
|
|
15
26
|
```
|
|
16
27
|
|
|
17
28
|
## Props
|
|
18
29
|
|
|
19
30
|
| Prop | Role |
|
|
20
31
|
|------|------|
|
|
21
|
-
| `min`, `max`, `htmlStep` | Range
|
|
32
|
+
| `min`, `max`, `htmlStep` | Range bounds |
|
|
22
33
|
| `value` | Current position |
|
|
23
|
-
| `disabled` | Gray theme, opacity 0.5
|
|
24
|
-
| `
|
|
25
|
-
| `
|
|
26
|
-
|
|
|
27
|
-
| `
|
|
28
|
-
| `reverseScaleOrder` | Flip emoji index calculation |
|
|
29
|
-
|
|
30
|
-
## Interactive States
|
|
31
|
-
|
|
32
|
-
| State | Thumb | Tooltip |
|
|
33
|
-
|-------|-------|---------|
|
|
34
|
-
| Default | White circle, 2.5px magenta border | Hidden |
|
|
35
|
-
| Hover/drag | Pink glow ring `rgba(226,0,116,0.2)` | Dark bubble with `Math.round(value)` |
|
|
36
|
-
| Disabled | Gray border, opacity 0.5 | Hidden |
|
|
37
|
-
| Graphics | Emoji at percentage position | Same tooltip |
|
|
38
|
-
|
|
39
|
-
## Emoji Index Formula
|
|
40
|
-
|
|
41
|
-
```typescript
|
|
42
|
-
const idx = Math.round(((value - min) / (max - min)) * ((ticks || 10) - 1));
|
|
43
|
-
const displayIdx = reverseScaleOrder ? (ticks || 10) - 1 - idx : idx;
|
|
44
|
-
getEmojiForIndex(displayIdx, ticks || 10)
|
|
45
|
-
```
|
|
34
|
+
| `disabled` | Gray theme, opacity 0.5 |
|
|
35
|
+
| `sliderType: 'graphics'` | Emoji thumb via `surveyUiIcons.getEmojiForIndex` |
|
|
36
|
+
| `ticks` | Discrete tick count |
|
|
37
|
+
| **`tickLabels`** | **Column labels for tooltip + graphics index** |
|
|
38
|
+
| `reverseScaleOrder` | Flip emoji index |
|
|
46
39
|
|
|
47
40
|
## Agent Checklist
|
|
48
41
|
|
|
49
|
-
- [ ]
|
|
42
|
+
- [ ] Copy portable template or match layer stack
|
|
43
|
+
- [ ] Always pass `tickLabels` from matrix `scaleColumns` when available
|
|
50
44
|
- [ ] Tooltip on hover AND drag
|
|
51
|
-
- [ ] Graphics
|
|
52
|
-
- [ ] Transition disabled while dragging
|
|
45
|
+
- [ ] Graphics emoji thumb with `reverseScaleOrder` support
|
|
@@ -30,6 +30,11 @@ if (val === null) {
|
|
|
30
30
|
// When null selected, non-null options disabled
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
+
## Props
|
|
34
|
+
|
|
35
|
+
- `options: ScaleColumn[]` — matrix scale columns (`id`, `label`)
|
|
36
|
+
- `value` / `onChange` — stored values use `matrixColumnStoredValue(col)` → column **`id`**
|
|
37
|
+
|
|
33
38
|
## Agent Checklist
|
|
34
39
|
|
|
35
40
|
- [ ] Click-outside closes panel
|