@godxjp/ui 18.14.0 → 18.15.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/components/data-display/data-table.js +6 -2
- package/dist/components/data-entry/upload.d.ts +1 -1
- package/dist/components/data-entry/upload.js +18 -4
- package/dist/components/layout/split-pane.d.ts +7 -1
- package/dist/props/components/data-entry.prop.d.ts +9 -0
- package/dist/props/vocabulary/data.prop.d.ts +12 -0
- package/dist/styles/form-layout.css +10 -0
- package/dist/styles/layout.css +11 -0
- package/dist/styles/table-layout.css +38 -0
- package/package.json +2 -2
|
@@ -511,8 +511,12 @@ DataTable.Content = function DataTableContent() {
|
|
|
511
511
|
style: columnWidth(col.width).style,
|
|
512
512
|
className: cn(
|
|
513
513
|
columnWidth(col.width).className,
|
|
514
|
-
|
|
515
|
-
|
|
514
|
+
// `headerAlign` when the heading differs from the rows,
|
|
515
|
+
// `align` otherwise. A table wanting centred headings
|
|
516
|
+
// over start-aligned text could not say so before, and
|
|
517
|
+
// consumers reached for `[&_th_button]:justify-center`.
|
|
518
|
+
(col.headerAlign ?? col.align) === "right" && "text-end",
|
|
519
|
+
(col.headerAlign ?? col.align) === "center" && "text-center",
|
|
516
520
|
col.hiddenOnMobile && "hidden md:table-cell",
|
|
517
521
|
isSortable && "select-none",
|
|
518
522
|
col.pin === "end" && "ui-data-table-pin-end"
|
|
@@ -4,4 +4,4 @@ export type { UploadProp, UploadProp as UploadProps, UploadFileItemProp, UploadV
|
|
|
4
4
|
export type { UploadFileItem, UploadVariant, UploadCommitAction } from "./upload-types.js";
|
|
5
5
|
export { collectUploadCommitActions, createUploadItem } from "./upload-types.js";
|
|
6
6
|
export { useUploadDraft } from "./use-upload-draft.js";
|
|
7
|
-
export declare function Upload({ variant, value, defaultValue, onValueChange, accept: acceptProp, multiple: multipleProp, maxCount: maxCountProp, maxSizeBytes, disabled, removable, onUpload, id, className, children, ...ariaProps }: UploadProp): React.JSX.Element;
|
|
7
|
+
export declare function Upload({ variant, triggerSize, value, defaultValue, onValueChange, accept: acceptProp, multiple: multipleProp, maxCount: maxCountProp, maxSizeBytes, disabled, removable, onUpload, id, className, children, ...ariaProps }: UploadProp): React.JSX.Element;
|
|
@@ -75,6 +75,7 @@ async function runUpload(file, item, onUpload, setItems) {
|
|
|
75
75
|
}
|
|
76
76
|
function Upload({
|
|
77
77
|
variant = "dropzone",
|
|
78
|
+
triggerSize,
|
|
78
79
|
value,
|
|
79
80
|
defaultValue,
|
|
80
81
|
onValueChange,
|
|
@@ -212,13 +213,26 @@ function Upload({
|
|
|
212
213
|
] });
|
|
213
214
|
}
|
|
214
215
|
if (variant === "button") {
|
|
216
|
+
const iconOnly = typeof triggerSize === "string" && triggerSize.startsWith("icon");
|
|
217
|
+
const label = children ?? t("dataEntry.upload.buttonLabel");
|
|
215
218
|
return /* @__PURE__ */ jsxs("div", { className: cn("ui-stack-sm", className), children: [
|
|
216
219
|
hiddenInput,
|
|
217
220
|
liveRegion,
|
|
218
|
-
/* @__PURE__ */ jsxs(
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
221
|
+
/* @__PURE__ */ jsxs(
|
|
222
|
+
Button,
|
|
223
|
+
{
|
|
224
|
+
type: "button",
|
|
225
|
+
variant: "outline",
|
|
226
|
+
size: triggerSize,
|
|
227
|
+
disabled,
|
|
228
|
+
onClick: openPicker,
|
|
229
|
+
"aria-label": iconOnly ? typeof label === "string" ? label : void 0 : void 0,
|
|
230
|
+
children: [
|
|
231
|
+
/* @__PURE__ */ jsx(UploadIcon, { className: iconOnly ? "size-4" : "me-2 size-4", "aria-hidden": "true" }),
|
|
232
|
+
iconOnly ? null : label
|
|
233
|
+
]
|
|
234
|
+
}
|
|
235
|
+
),
|
|
222
236
|
items.length > 0 && /* @__PURE__ */ jsx(UploadFileList, { items, onRemove: removable ? removeItem : void 0 })
|
|
223
237
|
] });
|
|
224
238
|
}
|
|
@@ -2,7 +2,13 @@ import type { ReactNode } from "react";
|
|
|
2
2
|
export type SplitPaneProps = {
|
|
3
3
|
children: ReactNode;
|
|
4
4
|
aside: ReactNode;
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* How wide the rail is once the pane is wide enough to split: `sm` 20rem,
|
|
7
|
+
* `md` 22rem, `lg` 30rem. `lg` is for rails that carry a panel rather than a
|
|
8
|
+
* list — a metadata table, a recently-updated feed — and it holds off
|
|
9
|
+
* splitting until 64rem so the main column stays the wider of the two.
|
|
10
|
+
*/
|
|
11
|
+
asideWidth?: "sm" | "md" | "lg";
|
|
6
12
|
/** Accessible complementary landmark name; required when multiple panes share a document. */
|
|
7
13
|
asideLabel?: string;
|
|
8
14
|
};
|
|
@@ -520,6 +520,15 @@ export type UploadProp = FieldA11yProps & {
|
|
|
520
520
|
}>;
|
|
521
521
|
/** Injected by FormField (or set directly) — applied to the native `<input type="file">`. */
|
|
522
522
|
id?: IdProp;
|
|
523
|
+
/**
|
|
524
|
+
* `variant="button"` only — the size of the visible trigger, forwarded to
|
|
525
|
+
* Button. An icon size renders the trigger icon-only and moves the label to
|
|
526
|
+
* `aria-label`, which is what a toolbar wants: a 32px square beside the other
|
|
527
|
+
* icon buttons rather than a 147px labelled one that outweighs them.
|
|
528
|
+
*
|
|
529
|
+
* @see Button — same size scale
|
|
530
|
+
*/
|
|
531
|
+
triggerSize?: "default" | "md" | "xs" | "sm" | "lg" | "icon" | "icon-xs" | "icon-sm" | "icon-lg";
|
|
523
532
|
className?: ClassNameProp;
|
|
524
533
|
children?: React.ReactNode;
|
|
525
534
|
};
|
|
@@ -34,6 +34,18 @@ export type ColumnDefProp<T> = {
|
|
|
34
34
|
*/
|
|
35
35
|
width?: string;
|
|
36
36
|
align?: ColumnAlignProp;
|
|
37
|
+
/**
|
|
38
|
+
* Alignment of the header cell, when it differs from the body.
|
|
39
|
+
*
|
|
40
|
+
* Defaults to `align`, which is the usual case. It exists because a table
|
|
41
|
+
* can want centred headings over start-aligned text — a long subject reads
|
|
42
|
+
* from the left while its column heading sits over the column — and `align`
|
|
43
|
+
* alone cannot say that: setting it to `center` centres the rows too.
|
|
44
|
+
*
|
|
45
|
+
* Consumers were reaching for `[&_th_button]:justify-center` to get there,
|
|
46
|
+
* which is a hand-tuned override of a layout the table owns.
|
|
47
|
+
*/
|
|
48
|
+
headerAlign?: ColumnAlignProp;
|
|
37
49
|
hiddenOnMobile?: boolean;
|
|
38
50
|
/**
|
|
39
51
|
* List this column in DataTable.ViewOptions (the column show/hide "set view"
|
|
@@ -33,6 +33,16 @@
|
|
|
33
33
|
margin-block-start: var(--form-field-row-gap);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
/* …except when the fields are ResponsiveGrid ITEMS (Form columns={n}): there the grid's own
|
|
37
|
+
* `gap` owns the rhythm, and a per-item margin double-spaces every row AND breaks column
|
|
38
|
+
* alignment — the FIRST field has no preceding sibling so no margin, while its row-mate does,
|
|
39
|
+
* shifting row 1's columns 11px apart and inflating every grid track by the margin. Fields
|
|
40
|
+
* merely NESTED somewhere inside a grid cell (a stacked pair in one cell) are not direct
|
|
41
|
+
* children, keep the margin, and are unaffected. */
|
|
42
|
+
.ui-responsive-grid > .ui-form-field + .ui-form-field {
|
|
43
|
+
margin-block-start: 0;
|
|
44
|
+
}
|
|
45
|
+
|
|
36
46
|
/* Vertical (default + collapsed state): label stacked above the control column, LEFT-aligned.
|
|
37
47
|
* Gap = the shared --field-label-gap so FormField matches Descriptions and every label-above stack. */
|
|
38
48
|
.ui-form-field {
|
package/dist/styles/layout.css
CHANGED
|
@@ -384,6 +384,17 @@
|
|
|
384
384
|
}
|
|
385
385
|
}
|
|
386
386
|
|
|
387
|
+
/* `lg` splits later than the other two ON PURPOSE. A rail is only useful when
|
|
388
|
+
* the column it sits beside still reads as the main one, and at the 48rem
|
|
389
|
+
* threshold a 30rem rail would leave 16.5rem of main — narrower than the rail
|
|
390
|
+
* itself, which inverts the whole point. 64rem leaves the main column 33.5rem,
|
|
391
|
+
* about twice the rail, so the page still reads main-plus-rail. */
|
|
392
|
+
@container split-pane (min-width: 64rem) {
|
|
393
|
+
.ui-split-pane[data-aside-width="lg"] {
|
|
394
|
+
grid-template-columns: minmax(0, 1fr) 30rem;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
387
398
|
.ui-split-pane-main,
|
|
388
399
|
.ui-split-pane-aside {
|
|
389
400
|
min-width: 0;
|
|
@@ -169,6 +169,44 @@
|
|
|
169
169
|
gap: var(--space-inline-xs);
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
+
/* A centred header centres its LABEL, not its button.
|
|
173
|
+
*
|
|
174
|
+
* The sort chevron lives inside the label, so centring the button alone
|
|
175
|
+
* leaves the words half an icon to the left of the column they name —
|
|
176
|
+
* measured at 8px on a 12px icon, which is enough to read as a mistake in a
|
|
177
|
+
* row of headings.
|
|
178
|
+
*
|
|
179
|
+
* The fix is symmetry, not a counterweight. Reserving the chevron's width on
|
|
180
|
+
* BOTH sides and taking the chevron itself out of flow means the words are
|
|
181
|
+
* centred by construction — the label's own box is centred in the cell, and
|
|
182
|
+
* nothing inside it can shift them. A counterweight sitting in flow as a
|
|
183
|
+
* flex sibling was the first attempt and it holds only while there is room
|
|
184
|
+
* to spare: flex items shrink, so on a column narrow enough to squeeze them
|
|
185
|
+
* the balance collapses and the label slides back off centre. Measured at
|
|
186
|
+
* 8px on a 56px column, 0px on the wide ones — a bug that only appears in
|
|
187
|
+
* the narrow case is worse than one that appears everywhere.
|
|
188
|
+
*
|
|
189
|
+
* Only when the column asked to be centred: a start-aligned header wants the
|
|
190
|
+
* icon to follow the text with nothing before it. */
|
|
191
|
+
:is(th, td).text-center > .ui-data-table-sort-button > .ui-data-table-sort-label {
|
|
192
|
+
position: relative;
|
|
193
|
+
/* The icon's width plus the gap it would have sat behind — the space the
|
|
194
|
+
* chevron occupied when it was in flow, now reserved on each side. */
|
|
195
|
+
padding-inline: calc(0.75rem + var(--space-inline-xs));
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/* Out of flow, in the inline-end reservation its own padding just made.
|
|
199
|
+
* Logical inset, so RTL puts it on the other side with the padding. */
|
|
200
|
+
:is(th, td).text-center
|
|
201
|
+
> .ui-data-table-sort-button
|
|
202
|
+
> .ui-data-table-sort-label
|
|
203
|
+
> :not(:first-child) {
|
|
204
|
+
position: absolute;
|
|
205
|
+
inset-inline-end: 0;
|
|
206
|
+
top: 50%;
|
|
207
|
+
transform: translateY(-50%);
|
|
208
|
+
}
|
|
209
|
+
|
|
172
210
|
.ui-data-table-scroll {
|
|
173
211
|
position: relative;
|
|
174
212
|
overflow-x: auto;
|