@usefidel/design-system 0.3.0 → 0.5.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/dist/fidel.manifest.json +2 -2
- package/dist/index.cjs +113 -53
- package/dist/index.css +32 -1
- package/dist/index.d.cts +47 -9
- package/dist/index.d.ts +47 -9
- package/dist/index.js +114 -54
- package/package.json +1 -1
package/dist/fidel.manifest.json
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -128,69 +128,129 @@ function DiffSection({
|
|
|
128
128
|
mismatchCount,
|
|
129
129
|
elements,
|
|
130
130
|
defaultExpanded = false,
|
|
131
|
+
headerless = false,
|
|
132
|
+
onElementToggle,
|
|
133
|
+
onElementHover,
|
|
131
134
|
className,
|
|
132
135
|
...rest
|
|
133
136
|
}) {
|
|
134
137
|
const [expanded, setExpanded] = (0, import_react2.useState)(defaultExpanded);
|
|
138
|
+
const open = headerless || expanded;
|
|
135
139
|
const count = mismatchCount ?? elements.reduce((sum, el) => sum + el.properties.length, 0);
|
|
136
|
-
const classes = [
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
140
|
+
const classes = [
|
|
141
|
+
"fds-diff-section",
|
|
142
|
+
headerless && "fds-diff-section--flat",
|
|
143
|
+
className
|
|
144
|
+
].filter(Boolean).join(" ");
|
|
145
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
146
|
+
"div",
|
|
147
|
+
{
|
|
148
|
+
className: classes,
|
|
149
|
+
"data-expanded": open ? "true" : void 0,
|
|
150
|
+
"data-flat": headerless ? "true" : void 0,
|
|
151
|
+
...rest,
|
|
152
|
+
children: [
|
|
153
|
+
!headerless && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
154
|
+
"button",
|
|
155
|
+
{
|
|
156
|
+
type: "button",
|
|
157
|
+
className: "fds-diff-section__header",
|
|
158
|
+
"aria-expanded": expanded,
|
|
159
|
+
onClick: () => setExpanded((v) => !v),
|
|
160
|
+
children: [
|
|
161
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "fds-diff-section__head-left", children: [
|
|
162
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Chevron2, { open: expanded }),
|
|
163
|
+
number != null && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "fds-diff-section__number", children: number }),
|
|
164
|
+
name != null && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "fds-diff-section__name", children: name })
|
|
165
|
+
] }),
|
|
166
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "fds-diff-section__count", children: plural(count, "mismatch", "mismatches") })
|
|
167
|
+
]
|
|
168
|
+
}
|
|
169
|
+
),
|
|
170
|
+
open && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "fds-diff-section__body", children: elements.map((el, ei) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
171
|
+
ElementRow,
|
|
172
|
+
{
|
|
173
|
+
element: el,
|
|
174
|
+
index: ei,
|
|
175
|
+
onToggle: onElementToggle,
|
|
176
|
+
onHover: onElementHover
|
|
177
|
+
},
|
|
178
|
+
`${el.name}-${ei}`
|
|
179
|
+
)) })
|
|
180
|
+
]
|
|
181
|
+
}
|
|
182
|
+
);
|
|
170
183
|
}
|
|
171
|
-
function
|
|
172
|
-
|
|
173
|
-
|
|
184
|
+
function ElementRow({
|
|
185
|
+
element,
|
|
186
|
+
index,
|
|
187
|
+
onToggle,
|
|
188
|
+
onHover
|
|
189
|
+
}) {
|
|
190
|
+
const hasDetail = element.detail != null;
|
|
191
|
+
const isControlled = element.open !== void 0;
|
|
192
|
+
const [internalOpen, setInternalOpen] = (0, import_react2.useState)(element.defaultOpen ?? false);
|
|
193
|
+
const open = isControlled ? !!element.open : internalOpen;
|
|
194
|
+
const toggle = () => {
|
|
195
|
+
const next = !open;
|
|
196
|
+
if (!isControlled) setInternalOpen(next);
|
|
197
|
+
onToggle?.(index, next);
|
|
198
|
+
};
|
|
199
|
+
const lines = /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
200
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "fds-diff-section__element-head-inner", children: [
|
|
201
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "fds-diff-section__element-name", children: element.name }),
|
|
202
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "fds-diff-section__element-count", children: plural(element.properties.length, "property", "properties") }),
|
|
203
|
+
hasDetail && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Chevron2, { open, className: "fds-diff-section__element-caret" })
|
|
204
|
+
] }),
|
|
205
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "fds-diff-section__lines", children: element.properties.map((line, li) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "fds-diff-section__line", children: [
|
|
206
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "fds-diff-section__prop", children: line.property }),
|
|
207
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "fds-diff-section__delta", children: [
|
|
208
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "fds-diff-section__live", children: line.live }),
|
|
209
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Arrow, {}),
|
|
210
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "fds-diff-section__design", children: line.design })
|
|
211
|
+
] })
|
|
212
|
+
] }, `${line.property}-${li}`)) })
|
|
213
|
+
] });
|
|
214
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
215
|
+
"div",
|
|
174
216
|
{
|
|
175
|
-
className:
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
}
|
|
190
|
-
|
|
217
|
+
className: "fds-diff-section__element",
|
|
218
|
+
"data-open": hasDetail && open ? "true" : void 0,
|
|
219
|
+
onMouseEnter: onHover ? () => onHover(index, true) : void 0,
|
|
220
|
+
onMouseLeave: onHover ? () => onHover(index, false) : void 0,
|
|
221
|
+
children: [
|
|
222
|
+
hasDetail ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
223
|
+
"button",
|
|
224
|
+
{
|
|
225
|
+
type: "button",
|
|
226
|
+
className: "fds-diff-section__element-head fds-diff-section__element-head--button",
|
|
227
|
+
"aria-expanded": open,
|
|
228
|
+
onClick: toggle,
|
|
229
|
+
children: lines
|
|
230
|
+
}
|
|
231
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "fds-diff-section__element-head", children: lines }),
|
|
232
|
+
hasDetail && open && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "fds-diff-section__detail", children: element.detail })
|
|
233
|
+
]
|
|
191
234
|
}
|
|
192
235
|
);
|
|
193
236
|
}
|
|
237
|
+
function Chevron2({ open, className }) {
|
|
238
|
+
const classes = [
|
|
239
|
+
"fds-diff-section__chevron",
|
|
240
|
+
open && "fds-diff-section__chevron--open",
|
|
241
|
+
className
|
|
242
|
+
].filter(Boolean).join(" ");
|
|
243
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", "aria-hidden": "true", className: classes, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
244
|
+
"path",
|
|
245
|
+
{
|
|
246
|
+
d: "M4.5 3 8 6l-3.5 3",
|
|
247
|
+
stroke: "currentColor",
|
|
248
|
+
strokeWidth: "1.3",
|
|
249
|
+
strokeLinecap: "round",
|
|
250
|
+
strokeLinejoin: "round"
|
|
251
|
+
}
|
|
252
|
+
) });
|
|
253
|
+
}
|
|
194
254
|
function Arrow() {
|
|
195
255
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
196
256
|
"svg",
|
package/dist/index.css
CHANGED
|
@@ -310,14 +310,45 @@
|
|
|
310
310
|
.fds-diff-section__element {
|
|
311
311
|
display: flex;
|
|
312
312
|
flex-direction: column;
|
|
313
|
+
}
|
|
314
|
+
.fds-diff-section__element-head {
|
|
315
|
+
display: flex;
|
|
316
|
+
flex-direction: column;
|
|
313
317
|
gap: 14px;
|
|
318
|
+
width: 100%;
|
|
314
319
|
padding: 6px var(--spacing-5) 6px var(--spacing-6);
|
|
315
320
|
}
|
|
316
|
-
.fds-diff-section__element-head {
|
|
321
|
+
.fds-diff-section__element-head--button {
|
|
322
|
+
border: 0;
|
|
323
|
+
background: none;
|
|
324
|
+
font: inherit;
|
|
325
|
+
color: inherit;
|
|
326
|
+
text-align: left;
|
|
327
|
+
cursor: pointer;
|
|
328
|
+
transition: background var(--duration-quick, 150ms) ease;
|
|
329
|
+
}
|
|
330
|
+
.fds-diff-section__element-head--button:hover {
|
|
331
|
+
background: var(--color-surface-hover);
|
|
332
|
+
}
|
|
333
|
+
.fds-diff-section__element-head-inner {
|
|
317
334
|
display: flex;
|
|
318
335
|
align-items: center;
|
|
319
336
|
gap: var(--spacing-2);
|
|
320
337
|
}
|
|
338
|
+
.fds-diff-section__element-caret {
|
|
339
|
+
margin-left: auto;
|
|
340
|
+
flex-shrink: 0;
|
|
341
|
+
color: var(--color-text-muted);
|
|
342
|
+
}
|
|
343
|
+
.fds-diff-section__detail {
|
|
344
|
+
padding: 0 var(--spacing-5) var(--spacing-3) var(--spacing-6);
|
|
345
|
+
}
|
|
346
|
+
.fds-diff-section--flat .fds-diff-section__body {
|
|
347
|
+
gap: 0;
|
|
348
|
+
}
|
|
349
|
+
.fds-diff-section--flat .fds-diff-section__element + .fds-diff-section__element {
|
|
350
|
+
border-top: 1px solid var(--color-border-light);
|
|
351
|
+
}
|
|
321
352
|
.fds-diff-section__element-name {
|
|
322
353
|
font-weight: var(--font-weight-medium);
|
|
323
354
|
font-size: 14px;
|
package/dist/index.d.cts
CHANGED
|
@@ -74,12 +74,29 @@ interface DiffElement {
|
|
|
74
74
|
name: string;
|
|
75
75
|
/** Property mismatches for this element. */
|
|
76
76
|
properties: DiffPropertyLine[];
|
|
77
|
+
/**
|
|
78
|
+
* Optional drill-down content. When provided, the element row becomes a
|
|
79
|
+
* toggle: clicking it reveals this node beneath the property deltas. Use it
|
|
80
|
+
* to host a richer detail view (copy actions, triage, verdicts) while the
|
|
81
|
+
* mono deltas stay as the at-a-glance summary. Presentational — the caller
|
|
82
|
+
* owns whatever lives inside.
|
|
83
|
+
*/
|
|
84
|
+
detail?: ReactNode;
|
|
85
|
+
/** When the element has `detail`, render it open on first paint (uncontrolled). @default false */
|
|
86
|
+
defaultOpen?: boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Controlled open state. When defined, the row is controlled: the component
|
|
89
|
+
* renders this value and never keeps its own expand state — the caller owns
|
|
90
|
+
* it via `onElementToggle` (so drawer selection can drive, e.g., a matching
|
|
91
|
+
* screenshot highlight). Leave undefined for uncontrolled (`defaultOpen`).
|
|
92
|
+
*/
|
|
93
|
+
open?: boolean;
|
|
77
94
|
}
|
|
78
95
|
interface DiffSectionProps extends HTMLAttributes<HTMLDivElement> {
|
|
79
|
-
/** Ordinal shown before the name, e.g. "01".
|
|
80
|
-
number
|
|
81
|
-
/** Section name, e.g. "Nav". */
|
|
82
|
-
name
|
|
96
|
+
/** Ordinal shown before the name, e.g. "01". Omitted in `headerless` mode. */
|
|
97
|
+
number?: string;
|
|
98
|
+
/** Section name, e.g. "Nav". Omitted in `headerless` mode. */
|
|
99
|
+
name?: string;
|
|
83
100
|
/**
|
|
84
101
|
* Count shown on the right of the header. Defaults to the total number of
|
|
85
102
|
* property lines across all elements.
|
|
@@ -87,17 +104,38 @@ interface DiffSectionProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
87
104
|
mismatchCount?: number;
|
|
88
105
|
/** Elements in this section, each with its own property mismatches. */
|
|
89
106
|
elements: DiffElement[];
|
|
90
|
-
/** Render expanded on first paint. @default false */
|
|
107
|
+
/** Render expanded on first paint. Ignored in `headerless` mode. @default false */
|
|
91
108
|
defaultExpanded?: boolean;
|
|
109
|
+
/**
|
|
110
|
+
* Drop the numbered, collapsible section header and render the element list
|
|
111
|
+
* directly — a flat drawer with no section grouping. `number`/`name`/
|
|
112
|
+
* `mismatchCount` are ignored. @default false
|
|
113
|
+
*/
|
|
114
|
+
headerless?: boolean;
|
|
115
|
+
/**
|
|
116
|
+
* Called when an element with `detail` is toggled. `index` is the element's
|
|
117
|
+
* position in `elements`. Pair with `DiffElement.open` to control expansion
|
|
118
|
+
* from the parent (e.g. to sync a screenshot highlight with drawer selection).
|
|
119
|
+
*/
|
|
120
|
+
onElementToggle?: (index: number, open: boolean) => void;
|
|
121
|
+
/** Called when the pointer enters (`true`) or leaves (`false`) an element row. */
|
|
122
|
+
onElementHover?: (index: number, hovering: boolean) => void;
|
|
92
123
|
}
|
|
93
124
|
/**
|
|
94
|
-
* Fidel design-system DiffSection —
|
|
95
|
-
*
|
|
96
|
-
*
|
|
125
|
+
* Fidel design-system DiffSection — the mismatch drawer's section.
|
|
126
|
+
*
|
|
127
|
+
* Two shapes:
|
|
128
|
+
* - Grouped (default): a numbered, collapsible header (`01 Nav · 2
|
|
129
|
+
* mismatches`) over its elements.
|
|
130
|
+
* - `headerless`: just the element list, for a flat drawer with no section
|
|
131
|
+
* grouping.
|
|
132
|
+
*
|
|
133
|
+
* Each element lists its property deltas as `live → design` mono rows, and may
|
|
134
|
+
* carry a `detail` node that expands beneath the deltas as a drill-down.
|
|
97
135
|
*
|
|
98
136
|
* Presentational only — no diff taxonomy. Framing is Live → Design (founder
|
|
99
137
|
* decision 2026-04-24): each delta reads `live → design`.
|
|
100
138
|
*/
|
|
101
|
-
declare function DiffSection({ number, name, mismatchCount, elements, defaultExpanded, className, ...rest }: DiffSectionProps): react.JSX.Element;
|
|
139
|
+
declare function DiffSection({ number, name, mismatchCount, elements, defaultExpanded, headerless, onElementToggle, onElementHover, className, ...rest }: DiffSectionProps): react.JSX.Element;
|
|
102
140
|
|
|
103
141
|
export { Button, type ButtonProps, type ButtonSize, type ButtonVariant, type DiffElement, type DiffPropertyLine, DiffSection, type DiffSectionProps, MismatchCard, type MismatchCardProps, type MismatchProperty };
|
package/dist/index.d.ts
CHANGED
|
@@ -74,12 +74,29 @@ interface DiffElement {
|
|
|
74
74
|
name: string;
|
|
75
75
|
/** Property mismatches for this element. */
|
|
76
76
|
properties: DiffPropertyLine[];
|
|
77
|
+
/**
|
|
78
|
+
* Optional drill-down content. When provided, the element row becomes a
|
|
79
|
+
* toggle: clicking it reveals this node beneath the property deltas. Use it
|
|
80
|
+
* to host a richer detail view (copy actions, triage, verdicts) while the
|
|
81
|
+
* mono deltas stay as the at-a-glance summary. Presentational — the caller
|
|
82
|
+
* owns whatever lives inside.
|
|
83
|
+
*/
|
|
84
|
+
detail?: ReactNode;
|
|
85
|
+
/** When the element has `detail`, render it open on first paint (uncontrolled). @default false */
|
|
86
|
+
defaultOpen?: boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Controlled open state. When defined, the row is controlled: the component
|
|
89
|
+
* renders this value and never keeps its own expand state — the caller owns
|
|
90
|
+
* it via `onElementToggle` (so drawer selection can drive, e.g., a matching
|
|
91
|
+
* screenshot highlight). Leave undefined for uncontrolled (`defaultOpen`).
|
|
92
|
+
*/
|
|
93
|
+
open?: boolean;
|
|
77
94
|
}
|
|
78
95
|
interface DiffSectionProps extends HTMLAttributes<HTMLDivElement> {
|
|
79
|
-
/** Ordinal shown before the name, e.g. "01".
|
|
80
|
-
number
|
|
81
|
-
/** Section name, e.g. "Nav". */
|
|
82
|
-
name
|
|
96
|
+
/** Ordinal shown before the name, e.g. "01". Omitted in `headerless` mode. */
|
|
97
|
+
number?: string;
|
|
98
|
+
/** Section name, e.g. "Nav". Omitted in `headerless` mode. */
|
|
99
|
+
name?: string;
|
|
83
100
|
/**
|
|
84
101
|
* Count shown on the right of the header. Defaults to the total number of
|
|
85
102
|
* property lines across all elements.
|
|
@@ -87,17 +104,38 @@ interface DiffSectionProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
87
104
|
mismatchCount?: number;
|
|
88
105
|
/** Elements in this section, each with its own property mismatches. */
|
|
89
106
|
elements: DiffElement[];
|
|
90
|
-
/** Render expanded on first paint. @default false */
|
|
107
|
+
/** Render expanded on first paint. Ignored in `headerless` mode. @default false */
|
|
91
108
|
defaultExpanded?: boolean;
|
|
109
|
+
/**
|
|
110
|
+
* Drop the numbered, collapsible section header and render the element list
|
|
111
|
+
* directly — a flat drawer with no section grouping. `number`/`name`/
|
|
112
|
+
* `mismatchCount` are ignored. @default false
|
|
113
|
+
*/
|
|
114
|
+
headerless?: boolean;
|
|
115
|
+
/**
|
|
116
|
+
* Called when an element with `detail` is toggled. `index` is the element's
|
|
117
|
+
* position in `elements`. Pair with `DiffElement.open` to control expansion
|
|
118
|
+
* from the parent (e.g. to sync a screenshot highlight with drawer selection).
|
|
119
|
+
*/
|
|
120
|
+
onElementToggle?: (index: number, open: boolean) => void;
|
|
121
|
+
/** Called when the pointer enters (`true`) or leaves (`false`) an element row. */
|
|
122
|
+
onElementHover?: (index: number, hovering: boolean) => void;
|
|
92
123
|
}
|
|
93
124
|
/**
|
|
94
|
-
* Fidel design-system DiffSection —
|
|
95
|
-
*
|
|
96
|
-
*
|
|
125
|
+
* Fidel design-system DiffSection — the mismatch drawer's section.
|
|
126
|
+
*
|
|
127
|
+
* Two shapes:
|
|
128
|
+
* - Grouped (default): a numbered, collapsible header (`01 Nav · 2
|
|
129
|
+
* mismatches`) over its elements.
|
|
130
|
+
* - `headerless`: just the element list, for a flat drawer with no section
|
|
131
|
+
* grouping.
|
|
132
|
+
*
|
|
133
|
+
* Each element lists its property deltas as `live → design` mono rows, and may
|
|
134
|
+
* carry a `detail` node that expands beneath the deltas as a drill-down.
|
|
97
135
|
*
|
|
98
136
|
* Presentational only — no diff taxonomy. Framing is Live → Design (founder
|
|
99
137
|
* decision 2026-04-24): each delta reads `live → design`.
|
|
100
138
|
*/
|
|
101
|
-
declare function DiffSection({ number, name, mismatchCount, elements, defaultExpanded, className, ...rest }: DiffSectionProps): react.JSX.Element;
|
|
139
|
+
declare function DiffSection({ number, name, mismatchCount, elements, defaultExpanded, headerless, onElementToggle, onElementHover, className, ...rest }: DiffSectionProps): react.JSX.Element;
|
|
102
140
|
|
|
103
141
|
export { Button, type ButtonProps, type ButtonSize, type ButtonVariant, type DiffElement, type DiffPropertyLine, DiffSection, type DiffSectionProps, MismatchCard, type MismatchCardProps, type MismatchProperty };
|
package/dist/index.js
CHANGED
|
@@ -90,7 +90,7 @@ function Chevron({ direction }) {
|
|
|
90
90
|
|
|
91
91
|
// src/components/DiffSection/DiffSection.tsx
|
|
92
92
|
import { useState as useState2 } from "react";
|
|
93
|
-
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
93
|
+
import { Fragment, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
94
94
|
function plural(n, one, many) {
|
|
95
95
|
return `${n} ${n === 1 ? one : many}`;
|
|
96
96
|
}
|
|
@@ -100,69 +100,129 @@ function DiffSection({
|
|
|
100
100
|
mismatchCount,
|
|
101
101
|
elements,
|
|
102
102
|
defaultExpanded = false,
|
|
103
|
+
headerless = false,
|
|
104
|
+
onElementToggle,
|
|
105
|
+
onElementHover,
|
|
103
106
|
className,
|
|
104
107
|
...rest
|
|
105
108
|
}) {
|
|
106
109
|
const [expanded, setExpanded] = useState2(defaultExpanded);
|
|
110
|
+
const open = headerless || expanded;
|
|
107
111
|
const count = mismatchCount ?? elements.reduce((sum, el) => sum + el.properties.length, 0);
|
|
108
|
-
const classes = [
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
112
|
+
const classes = [
|
|
113
|
+
"fds-diff-section",
|
|
114
|
+
headerless && "fds-diff-section--flat",
|
|
115
|
+
className
|
|
116
|
+
].filter(Boolean).join(" ");
|
|
117
|
+
return /* @__PURE__ */ jsxs3(
|
|
118
|
+
"div",
|
|
119
|
+
{
|
|
120
|
+
className: classes,
|
|
121
|
+
"data-expanded": open ? "true" : void 0,
|
|
122
|
+
"data-flat": headerless ? "true" : void 0,
|
|
123
|
+
...rest,
|
|
124
|
+
children: [
|
|
125
|
+
!headerless && /* @__PURE__ */ jsxs3(
|
|
126
|
+
"button",
|
|
127
|
+
{
|
|
128
|
+
type: "button",
|
|
129
|
+
className: "fds-diff-section__header",
|
|
130
|
+
"aria-expanded": expanded,
|
|
131
|
+
onClick: () => setExpanded((v) => !v),
|
|
132
|
+
children: [
|
|
133
|
+
/* @__PURE__ */ jsxs3("span", { className: "fds-diff-section__head-left", children: [
|
|
134
|
+
/* @__PURE__ */ jsx3(Chevron2, { open: expanded }),
|
|
135
|
+
number != null && /* @__PURE__ */ jsx3("span", { className: "fds-diff-section__number", children: number }),
|
|
136
|
+
name != null && /* @__PURE__ */ jsx3("span", { className: "fds-diff-section__name", children: name })
|
|
137
|
+
] }),
|
|
138
|
+
/* @__PURE__ */ jsx3("span", { className: "fds-diff-section__count", children: plural(count, "mismatch", "mismatches") })
|
|
139
|
+
]
|
|
140
|
+
}
|
|
141
|
+
),
|
|
142
|
+
open && /* @__PURE__ */ jsx3("div", { className: "fds-diff-section__body", children: elements.map((el, ei) => /* @__PURE__ */ jsx3(
|
|
143
|
+
ElementRow,
|
|
144
|
+
{
|
|
145
|
+
element: el,
|
|
146
|
+
index: ei,
|
|
147
|
+
onToggle: onElementToggle,
|
|
148
|
+
onHover: onElementHover
|
|
149
|
+
},
|
|
150
|
+
`${el.name}-${ei}`
|
|
151
|
+
)) })
|
|
152
|
+
]
|
|
153
|
+
}
|
|
154
|
+
);
|
|
142
155
|
}
|
|
143
|
-
function
|
|
144
|
-
|
|
145
|
-
|
|
156
|
+
function ElementRow({
|
|
157
|
+
element,
|
|
158
|
+
index,
|
|
159
|
+
onToggle,
|
|
160
|
+
onHover
|
|
161
|
+
}) {
|
|
162
|
+
const hasDetail = element.detail != null;
|
|
163
|
+
const isControlled = element.open !== void 0;
|
|
164
|
+
const [internalOpen, setInternalOpen] = useState2(element.defaultOpen ?? false);
|
|
165
|
+
const open = isControlled ? !!element.open : internalOpen;
|
|
166
|
+
const toggle = () => {
|
|
167
|
+
const next = !open;
|
|
168
|
+
if (!isControlled) setInternalOpen(next);
|
|
169
|
+
onToggle?.(index, next);
|
|
170
|
+
};
|
|
171
|
+
const lines = /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
172
|
+
/* @__PURE__ */ jsxs3("div", { className: "fds-diff-section__element-head-inner", children: [
|
|
173
|
+
/* @__PURE__ */ jsx3("span", { className: "fds-diff-section__element-name", children: element.name }),
|
|
174
|
+
/* @__PURE__ */ jsx3("span", { className: "fds-diff-section__element-count", children: plural(element.properties.length, "property", "properties") }),
|
|
175
|
+
hasDetail && /* @__PURE__ */ jsx3(Chevron2, { open, className: "fds-diff-section__element-caret" })
|
|
176
|
+
] }),
|
|
177
|
+
/* @__PURE__ */ jsx3("div", { className: "fds-diff-section__lines", children: element.properties.map((line, li) => /* @__PURE__ */ jsxs3("div", { className: "fds-diff-section__line", children: [
|
|
178
|
+
/* @__PURE__ */ jsx3("span", { className: "fds-diff-section__prop", children: line.property }),
|
|
179
|
+
/* @__PURE__ */ jsxs3("span", { className: "fds-diff-section__delta", children: [
|
|
180
|
+
/* @__PURE__ */ jsx3("span", { className: "fds-diff-section__live", children: line.live }),
|
|
181
|
+
/* @__PURE__ */ jsx3(Arrow, {}),
|
|
182
|
+
/* @__PURE__ */ jsx3("span", { className: "fds-diff-section__design", children: line.design })
|
|
183
|
+
] })
|
|
184
|
+
] }, `${line.property}-${li}`)) })
|
|
185
|
+
] });
|
|
186
|
+
return /* @__PURE__ */ jsxs3(
|
|
187
|
+
"div",
|
|
146
188
|
{
|
|
147
|
-
className:
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
}
|
|
162
|
-
|
|
189
|
+
className: "fds-diff-section__element",
|
|
190
|
+
"data-open": hasDetail && open ? "true" : void 0,
|
|
191
|
+
onMouseEnter: onHover ? () => onHover(index, true) : void 0,
|
|
192
|
+
onMouseLeave: onHover ? () => onHover(index, false) : void 0,
|
|
193
|
+
children: [
|
|
194
|
+
hasDetail ? /* @__PURE__ */ jsx3(
|
|
195
|
+
"button",
|
|
196
|
+
{
|
|
197
|
+
type: "button",
|
|
198
|
+
className: "fds-diff-section__element-head fds-diff-section__element-head--button",
|
|
199
|
+
"aria-expanded": open,
|
|
200
|
+
onClick: toggle,
|
|
201
|
+
children: lines
|
|
202
|
+
}
|
|
203
|
+
) : /* @__PURE__ */ jsx3("div", { className: "fds-diff-section__element-head", children: lines }),
|
|
204
|
+
hasDetail && open && /* @__PURE__ */ jsx3("div", { className: "fds-diff-section__detail", children: element.detail })
|
|
205
|
+
]
|
|
163
206
|
}
|
|
164
207
|
);
|
|
165
208
|
}
|
|
209
|
+
function Chevron2({ open, className }) {
|
|
210
|
+
const classes = [
|
|
211
|
+
"fds-diff-section__chevron",
|
|
212
|
+
open && "fds-diff-section__chevron--open",
|
|
213
|
+
className
|
|
214
|
+
].filter(Boolean).join(" ");
|
|
215
|
+
return /* @__PURE__ */ jsx3("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", "aria-hidden": "true", className: classes, children: /* @__PURE__ */ jsx3(
|
|
216
|
+
"path",
|
|
217
|
+
{
|
|
218
|
+
d: "M4.5 3 8 6l-3.5 3",
|
|
219
|
+
stroke: "currentColor",
|
|
220
|
+
strokeWidth: "1.3",
|
|
221
|
+
strokeLinecap: "round",
|
|
222
|
+
strokeLinejoin: "round"
|
|
223
|
+
}
|
|
224
|
+
) });
|
|
225
|
+
}
|
|
166
226
|
function Arrow() {
|
|
167
227
|
return /* @__PURE__ */ jsx3(
|
|
168
228
|
"svg",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@usefidel/design-system",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Fidel brand design tokens + React component library — DTCG token source of truth, generated per-surface CSS + Tailwind-v4 parser-compatibility output, and on-brand React components (Button, MismatchCard, DiffSection).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|